diff --git a/src/display/curve.cpp b/src/display/curve.cpp
index 075f7df9e5a36cbd4970c7ed7315164e841334e0..1b54c981c25c8277917bc8477283972d549e2485 100644 (file)
--- a/src/display/curve.cpp
+++ b/src/display/curve.cpp
Geom::Point p = rect.corner(0);
c->moveto(p);
- for (int i=3; i>=0; i--) {
+ for (int i=3; i>=1; i--) {
c->lineto(rect.corner(i));
}
- c->closepath_current();
+ c->closepath();
return c;
}
}
/**
* Perform a moveto to a point, thus starting a new subpath.
+ * Point p must be finite.
*/
void
SPCurve::moveto(Geom::Point const &p)
}
/**
- * Calls SPCurve::lineto() with a point's coordinates.
+ * Adds a line to the current subpath.
+ * Point p must be finite.
*/
void
SPCurve::lineto(Geom::Point const &p)
{
- lineto(p[Geom::X], p[Geom::Y]);
+ if (_pathv.empty()) g_message("SPCurve::lineto - path is empty!");
+ else _pathv.back().appendNew<Geom::LineSegment>( p );
}
/**
- * Adds a line to the current subpath.
+ * Calls SPCurve::lineto( Geom::Point(x,y) )
*/
void
SPCurve::lineto(gdouble x, gdouble y)
{
- if (_pathv.empty()) g_message("leeg");
- else _pathv.back().appendNew<Geom::LineSegment>( Geom::Point(x,y) );
+ lineto(Geom::Point(x,y));
}
/**
- * Calls SPCurve::curveto() with coordinates of three points.
+ * Adds a quadratic bezier segment to the current subpath.
+ * All points must be finite.
*/
void
-SPCurve::curveto(Geom::Point const &p0, Geom::Point const &p1, Geom::Point const &p2)
+SPCurve::quadto(Geom::Point const &p1, Geom::Point const &p2)
{
- using Geom::X;
- using Geom::Y;
- curveto( p0[X], p0[Y],
- p1[X], p1[Y],
- p2[X], p2[Y] );
+ if (_pathv.empty()) g_message("SPCurve::quadto - path is empty!");
+ else _pathv.back().appendNew<Geom::QuadraticBezier>( p1, p2);
+}
+/**
+ * Calls SPCurve::quadto( Geom::Point(x1,y1), Geom::Point(x2,y2) )
+ * All coordinates must be finite.
+ */
+void
+SPCurve::quadto(gdouble x1, gdouble y1, gdouble x2, gdouble y2)
+{
+ quadto( Geom::Point(x1,y1), Geom::Point(x2,y2) );
}
+
/**
* Adds a bezier segment to the current subpath.
+ * All points must be finite.
+ */
+void
+SPCurve::curveto(Geom::Point const &p0, Geom::Point const &p1, Geom::Point const &p2)
+{
+ if (_pathv.empty()) g_message("SPCurve::curveto - path is empty!");
+ else _pathv.back().appendNew<Geom::CubicBezier>( p0, p1, p2 );
+}
+/**
+ * Calls SPCurve::curveto( Geom::Point(x0,y0), Geom::Point(x1,y1), Geom::Point(x2,y2) )
+ * All coordinates must be finite.
*/
void
SPCurve::curveto(gdouble x0, gdouble y0, gdouble x1, gdouble y1, gdouble x2, gdouble y2)
{
- if (_pathv.empty()) g_message("leeg");
- else _pathv.back().appendNew<Geom::CubicBezier>( Geom::Point(x0,y0), Geom::Point(x1,y1), Geom::Point(x2,y2) );
+ curveto( Geom::Point(x0,y0), Geom::Point(x1,y1), Geom::Point(x2,y2) );
}
/**
void
SPCurve::closepath_current()
{
- _pathv.back().setFinal(_pathv.back().initialPoint());
+ if (_pathv.back().size() > 0 && dynamic_cast<Geom::LineSegment const *>(&_pathv.back().back_open())) {
+ _pathv.back().erase_last();
+ } else {
+ _pathv.back().setFinal(_pathv.back().initialPoint());
+ }
_pathv.back().close(true);
}
}
/**
- * Return first point of first subpath or (0,0). TODO: shouldn't this be (NR_HUGE, NR_HUGE) to be able to tell it apart from normal (0,0) ?
+ * Return first point of first subpath or nothing when the path is empty.
*/
-Geom::Point
+boost::optional<Geom::Point>
SPCurve::first_point() const
{
- if (is_empty())
- return Geom::Point(0, 0);
+ boost::optional<Geom::Point> retval;
- return _pathv.front().initialPoint();
+ if (!is_empty()) {
+ retval = _pathv.front().initialPoint();
+ }
+
+ return retval;
}
/**
* Return the second point of first subpath or _movePos if curve too short.
- * If the pathvector is empty, this returns (0,0). If the first path is only a moveto, this method
+ * If the pathvector is empty, this returns nothing. If the first path is only a moveto, this method
* returns the first point of the second path, if it exists. If there is no 2nd path, it returns the
* first point of the first path.
- *
- * FIXME: for empty paths shouldn't this return (NR_HUGE,NR_HUGE)
*/
-Geom::Point
+boost::optional<Geom::Point>
SPCurve::second_point() const
{
- if (is_empty()) {
- return Geom::Point(0,0);
- }
- else if (_pathv.front().empty()) {
- // first path is only a moveto
- // check if there is second path
- if (_pathv.size() > 1) {
- return _pathv[1].initialPoint();
+ boost::optional<Geom::Point> retval;
+ if (!is_empty()) {
+ if (_pathv.front().empty()) {
+ // first path is only a moveto
+ // check if there is second path
+ if (_pathv.size() > 1) {
+ retval = _pathv[1].initialPoint();
+ } else {
+ retval = _pathv[0].initialPoint();
+ }
} else {
- return _pathv[0].initialPoint();
+ retval = _pathv.front()[0].finalPoint();
}
}
- else
- return _pathv.front()[0].finalPoint();
+
+ return retval;
}
/**
- * TODO: fix comment: Return the second-last point of last subpath or _movePos if curve too short.
+ * Return the second-last point of last subpath or first point when that last subpath has only a moveto.
*/
-Geom::Point
+boost::optional<Geom::Point>
SPCurve::penultimate_point() const
{
- Geom::Curve const& back = _pathv.back().back_default();
- return back.initialPoint();
+ boost::optional<Geom::Point> retval;
+ if (!is_empty()) {
+ Geom::Path const &lastpath = _pathv.back();
+ if (!lastpath.empty()) {
+ Geom::Curve const &back = lastpath.back_default();
+ retval = back.initialPoint();
+ } else {
+ retval = lastpath.initialPoint();
+ }
+ }
+
+ return retval;
}
/**
- * Return last point of last subpath or (0,0). TODO: shouldn't this be (NR_HUGE, NR_HUGE) to be able to tell it apart from normal (0,0) ?
+ * Return last point of last subpath or nothing when the curve is empty.
* If the last path is only a moveto, then return that point.
*/
-Geom::Point
+boost::optional<Geom::Point>
SPCurve::last_point() const
{
- if (is_empty())
- return Geom::Point(0, 0);
+ boost::optional<Geom::Point> retval;
- return _pathv.back().finalPoint();
+ if (!is_empty()) {
+ retval = _pathv.back().finalPoint();
+ }
+
+ return retval;
}
/**
return this;
}
- if ( (fabs(this->last_point()[X] - c1->first_point()[X]) <= tolerance)
- && (fabs(this->last_point()[Y] - c1->first_point()[Y]) <= tolerance) )
+ if ( (fabs((*this->last_point())[X] - (*c1->first_point())[X]) <= tolerance)
+ && (fabs((*this->last_point())[Y] - (*c1->first_point())[Y]) <= tolerance) )
{
// c1's first subpath can be appended to this curve's last subpath
Geom::PathVector::const_iterator path_it = c1->_pathv.begin();
}
} else {
- append(c1, false);
+ append(c1, true);
}
return this;
/**
* TODO: add comments about what this method does and what assumptions are made and requirements are put on SPCurve
+ (2:08:18 AM) Johan: basically, i convert the path to pw<d2>
+(2:08:27 AM) Johan: then i calculate an offset path
+(2:08:29 AM) Johan: to move the knots
+(2:08:36 AM) Johan: then i add it
+(2:08:40 AM) Johan: then convert back to path
+If I remember correctly, this moves the firstpoint to new_p0, and the lastpoint to new_p1, and moves all nodes in between according to their arclength (interpolates the movement amount)
*/
void
SPCurve::stretch_endpoints(Geom::Point const &new_p0, Geom::Point const &new_p1)
@@ -541,8 +587,8 @@ SPCurve::stretch_endpoints(Geom::Point const &new_p0, Geom::Point const &new_p1)
return;
}
- Geom::Point const offset0( new_p0 - first_point() );
- Geom::Point const offset1( new_p1 - last_point() );
+ Geom::Point const offset0( new_p0 - *first_point() );
+ Geom::Point const offset1( new_p1 - *last_point() );
Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2 = _pathv.front().toPwSb();
Geom::Piecewise<Geom::SBasis> arclength = Geom::arcLengthSb(pwd2);
/**
* returns the number of nodes in a path, used for statusbar text when selecting an spcurve.
+ * Sum of nodes in all the paths. When a path is closed, and its closing line segment is of zero-length,
+ * this function will not count the closing knot double (so basically ignores the closing line segment when it has zero length)
*/
guint
SPCurve::nodes_in_path() const
nr += (*it).size();
nr++; // count last node (this works also for closed paths because although they don't have a 'last node', they do have an extra segment
+
+ // do not count closing knot double for zero-length closing line segments
+ // however, if the path is only a moveto, and is closed, do not subtract 1 (otherwise the result will be zero nodes)
+ if ( it->closed()
+ && ((*it).size() != 0) )
+ {
+ Geom::Curve const &c = it->back_closed();
+ if (are_near(c.initialPoint(), c.finalPoint())) {
+ nr--;
+ }
+ }
}
return nr;