diff --git a/src/display/curve.cpp b/src/display/curve.cpp
index eb86773f91dbdf76b5bced293e25063e71377274..c229ec28a533ebc5b9b2ff28c7a4b366d50bead3 100644 (file)
--- a/src/display/curve.cpp
+++ b/src/display/curve.cpp
#define __CURVE_C__
/** \file
- * Routines for SPCurve and for NArtBpath arrays in general.
+ * Routines for SPCurve and for NArtBpath arrays / Geom::PathVector in general.
*/
/*
- * Author:
+ * Authors:
* Lauris Kaplinski <lauris@kaplinski.com>
+ * Johan Engelen
*
* Copyright (C) 2000 Lauris Kaplinski
* Copyright (C) 2000-2001 Ximian, Inc.
#include <2geom/sbasis-geometric.h>
#include <2geom/sbasis-to-bezier.h>
#include "svg/svg.h"
+#include <2geom/point.h>
static unsigned sp_bpath_length(NArtBpath const bpath[]);
static bool sp_bpath_closed(NArtBpath const bpath[]);
-#define NO_CHECKS
-
-static void debug_out( char const * text, Geom::PathVector const & pathv) {
-#ifndef NO_CHECKS
- char * str = sp_svg_write_path(pathv);
- g_message("%s : %s", text, str);
- g_free(str);
-#endif
-}
-static void debug_out( char const * text, NArtBpath const * bpath) {
-#ifndef NO_CHECKS
- char * str = sp_svg_write_path(bpath);
- g_message("%s : %s", text, str);
- g_free(str);
-#endif
-}
-void SPCurve::debug_check( char const * text, SPCurve const * curve) {
-#ifndef NO_CHECKS
- char * pathv_str = sp_svg_write_path(curve->_pathv);
- char * bpath_str = sp_svg_write_path(curve->_bpath);
- if ( strcmp(pathv_str, bpath_str) ) {
- g_message("%s : unequal paths", text);
- g_message("bpath : %s", bpath_str);
- g_message("pathv : %s", pathv_str);
- }
- g_free(pathv_str);
- g_free(bpath_str);
-#endif
-}
-void SPCurve::debug_check( char const * text, bool a) {
-#ifndef NO_CHECKS
- if ( !a ) {
- g_message("%s : bool fail", text);
- }
-#endif
-}
-
/* Constructors */
/**
_bpath->code = NR_END;
_pathv.clear();
-
- debug_check("SPCurve::SPCurve(guint length)", this);
}
SPCurve::SPCurve(Geom::PathVector const& pathv)
break;
_substart = i;
_closed = sp_bpath_closed(_bpath);
-
- debug_check("SPCurve::SPCurve(Geom::PathVector const& pathv)", this);
}
// * 2GEOMproof
curve->_pathv = BPath_to_2GeomPath(curve->_bpath);
- debug_check("SPCurve::new_from_foreign_bpath", curve);
-
return curve;
}
SPCurve *curve = SPCurve::new_from_foreign_bpath(bpath);
g_free(bpath);
- debug_check("SPCurve::new_from_bpath", curve);
-
return curve;
}
// * 2GEOMproof
SPCurve *
-SPCurve::new_from_rect(NR::Maybe<NR::Rect> const &rect)
+SPCurve::new_from_rect(Geom::Rect const &rect)
{
- g_return_val_if_fail(rect, NULL);
-
SPCurve *c = new SPCurve();
- NR::Point p = rect->corner(0);
+ NR::Point p = rect.corner(0);
c->moveto(p);
for (int i=3; i>=0; i--) {
- c->lineto(rect->corner(i));
+ c->lineto(rect.corner(i));
}
c->closepath_current();
- debug_check("SPCurve::new_from_rect", c);
-
return c;
}
/* Methods */
void
-SPCurve::set_pathv(Geom::PathVector const & new_pathv)
+SPCurve::set_pathvector(Geom::PathVector const & new_pathv)
{
_pathv = new_pathv;
break;
_substart = i;
_closed = sp_bpath_closed(_bpath);
-
- debug_check("SPCurve::set_pathv", this);
}
/**
return _end;
}
+/*
+ * Returns the number of segments of all paths summed
+ */
+guint
+SPCurve::get_segment_count() const
+{
+ guint nr = 0;
+ for(Geom::PathVector::const_iterator it = _pathv.begin(); it != _pathv.end(); ++it) {
+ nr += (*it).size();
+
+ if (it->closed()) nr += 1;
+ }
+ return nr;
+}
+
/**
* Increase _refcount of curve.
*
* \todo should this be shared with other refcounting code?
- * 2GEOMproof
*/
SPCurve *
SPCurve::ref()
{
- g_return_val_if_fail(this != NULL, NULL);
-
_refcount += 1;
return this;
* Decrease refcount of curve, with possible destruction.
*
* \todo should this be shared with other refcounting code?
- * 2GEOMproof
*/
SPCurve *
SPCurve::unref()
{
- g_return_val_if_fail(this != NULL, NULL);
-
_refcount -= 1;
if (_refcount < 1) {
SPCurve *
SPCurve::copy() const
{
- g_return_val_if_fail(this != NULL, NULL);
-
return SPCurve::new_from_foreign_bpath(_bpath);
}
SPCurve *
SPCurve::concat(GSList const *list)
{
- g_return_val_if_fail(list != NULL, NULL);
-
gint length = 0;
for (GSList const *l = list; l != NULL; l = l->next) {
new_curve->_pathv.insert( new_curve->_pathv.end(), c->get_pathvector().begin(), c->get_pathvector().end() );
}
- debug_check("SPCurve::concat", new_curve);
-
return new_curve;
}
GSList *
SPCurve::split() const
{
- g_return_val_if_fail(this != NULL, NULL);
-
guint p = 0;
GSList *l = NULL;
}
}
-/**
- * Transform all paths in curve using matrix.
- * 2GEOMified, can be deleted when completely 2geom
- */
+
void
SPCurve::transform(NR::Matrix const &m)
{
- tmpl_curve_transform<NR::Matrix>(this, m);
-
transform(to_2geom(m));
+};
- debug_check("SPCurve::transform", this);
-}
-
+
/**
* Transform all paths in curve using matrix.
*/
void
SPCurve::transform(Geom::Matrix const &m)
{
- _pathv = _pathv * m;
-}
-
-/**
- * Transform all paths in curve using NR::translate.
- * 2GEOMified, can be deleted when completely 2geom
- */
-void
-SPCurve::transform(NR::translate const &m)
-{
- tmpl_curve_transform<NR::translate>(this, m);
-
- transform(to_2geom(m));
+ tmpl_curve_transform<NR::Matrix>(this, from_2geom(m));
- debug_check("SPCurve::transform translate", this);
+ _pathv = _pathv * m;
}
/**
void
SPCurve::reset()
{
- g_return_if_fail(this != NULL);
-
_bpath->code = NR_END;
_end = 0;
_substart = 0;
_closed = false;
_pathv.clear();
-
- debug_check("SPCurve::reset", this);
}
/* Several consecutive movetos are ALLOWED */
void
SPCurve::moveto(NR::Point const &p)
{
- g_return_if_fail(this != NULL);
g_return_if_fail(!_moving);
_substart = _end;
_movePos = p;
_pathv.push_back( Geom::Path() ); // for some reason Geom::Path(p) does not work...
_pathv.back().start(to_2geom(p));
-
- // the output is not the same. This is because SPCurve *incorrectly* coaslesces multiple moveto's into one for NArtBpath.
-// debug_check("SPCurve::moveto", this);
}
/**
void
SPCurve::lineto(gdouble x, gdouble y)
{
- g_return_if_fail(this != NULL);
g_return_if_fail(_hascpt);
if (_moving) {
_end++;
_pathv.back().appendNew<Geom::LineSegment>( Geom::Point(x,y) );
}
-
- debug_check("SPCurve::lineto", this);
}
/**
void
SPCurve::curveto(gdouble x0, gdouble y0, gdouble x1, gdouble y1, gdouble x2, gdouble y2)
{
- g_return_if_fail(this != NULL);
g_return_if_fail(_hascpt);
g_return_if_fail(!_moving);
@@ -705,8 +627,6 @@ SPCurve::curveto(gdouble x0, gdouble y0, gdouble x1, gdouble y1, gdouble x2, gdo
if (_pathv.empty()) g_message("leeg");
else _pathv.back().appendNew<Geom::CubicBezier>( Geom::Point(x0,y0), Geom::Point(x1,y1), Geom::Point(x2,y2) );
}
-
- debug_check("SPCurve::curveto", this);
}
/**
@@ -716,7 +636,6 @@ SPCurve::curveto(gdouble x0, gdouble y0, gdouble x1, gdouble y1, gdouble x2, gdo
void
SPCurve::closepath()
{
- g_return_if_fail(this != NULL);
g_return_if_fail(_hascpt);
g_return_if_fail(!_posSet);
g_return_if_fail(!_moving);
}
_hascpt = false;
-
- debug_check("SPCurve::closepath", this);
}
/** Like SPCurve::closepath() but sets the end point of the current
command to the subpath start point instead of adding a new lineto.
Used for freehand drawing when the user draws back to the start point.
+
+ 2GEOMified
**/
void
SPCurve::closepath_current()
{
- g_return_if_fail(this != NULL);
g_return_if_fail(_hascpt);
g_return_if_fail(!_posSet);
g_return_if_fail(!_closed);
_hascpt = false;
_moving = false;
-
- debug_check("SPCurve::closepath_current", this);
}
/**
- * True if no paths are in curve.
+ * True if no paths are in curve. If it only contains a path with only a moveto, the path is considered NON-empty
*/
bool
SPCurve::is_empty() const
{
- g_return_val_if_fail(this != NULL, TRUE);
-
- bool empty = _pathv.empty(); /* || _pathv.front().empty(); */
- debug_check("SPCurve::is_empty", (_bpath->code == NR_END) == empty );
+ bool empty = _pathv.empty();
- return (_bpath->code == NR_END);
+ return empty;
}
/**
break;
}
}
- debug_check("SPCurve::is_closed", (closed) == (_closed) );
- return _closed;
+ return closed;
}
/**
NArtBpath const *
SPCurve::last_bpath() const
{
- g_return_val_if_fail(this != NULL, NULL);
-
if (_end == 0) {
return NULL;
}
}
/**
- * Return first subpath or NULL.
+ * Return last pathsegment (possibly the closing path segment) of the last path in PathVector or NULL.
+ * If the last path is empty (contains only a moveto), the function returns NULL
*/
-NArtBpath const *
-SPCurve::first_bpath() const
+Geom::Curve const *
+SPCurve::last_segment() const
{
- g_return_val_if_fail(this != NULL, NULL);
+ if (is_empty()) {
+ return NULL;
+ }
+ if (_pathv.back().empty()) {
+ return NULL;
+ }
- if (_end == 0) {
+ return &_pathv.back().back_default();
+}
+
+/**
+ * Return last path in PathVector or NULL.
+ */
+Geom::Path const *
+SPCurve::last_path() const
+{
+ if (is_empty()) {
return NULL;
}
- return _bpath;
+ return &_pathv.back();
+}
+
+/**
+ * Return first pathsegment in PathVector or NULL.
+ * equal in functionality to SPCurve::first_bpath()
+ */
+Geom::Curve const *
+SPCurve::first_segment() const
+{
+ if (is_empty()) {
+ return NULL;
+ }
+ if (_pathv.front().empty()) {
+ return NULL;
+ }
+
+ return &_pathv.front().front();
+}
+
+/**
+ * Return first path in PathVector or NULL.
+ */
+Geom::Path const *
+SPCurve::first_path() const
+{
+ if (is_empty()) {
+ return NULL;
+ }
+
+ return &_pathv.front();
}
/**
NR::Point
SPCurve::first_point() const
{
- NArtBpath const * bpath = first_bpath();
- g_return_val_if_fail(bpath != NULL, NR::Point(0, 0));
if (is_empty())
return NR::Point(0, 0);
- debug_check("SPCurve::first_point", bpath->c(3) == _pathv.front().initialPoint() );
-
- return bpath->c(3);
- // return from_2geom( _pathv.front().initialPoint() );
+ return from_2geom( _pathv.front().initialPoint() );
}
/**
* 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
+ * 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)
*/
NR::Point
SPCurve::second_point() const
{
- g_return_val_if_fail(this != NULL, NR::Point(0, 0));
-
- if (_end < 1) {
- return _movePos;
+ if (is_empty()) {
+ return NR::Point(0,0);
}
-
- NArtBpath *bpath = NULL;
- if (_end < 2) {
- bpath = _bpath;
- } else {
- bpath = _bpath + 1;
+ 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();
+ } else {
+ return _pathv[0].initialPoint();
+ }
}
- g_return_val_if_fail(bpath != NULL, NR::Point(0, 0));
-
- debug_check("SPCurve::second_point", bpath->c(3) == _pathv.front()[0].finalPoint() );
-
- return bpath->c(3);
+ else
+ return _pathv.front()[0].finalPoint();
}
/**
NR::Point
SPCurve::penultimate_point() const
{
- g_return_val_if_fail(this != NULL, NR::Point(0, 0));
-
if (_end < 2) {
return _movePos;
}
NArtBpath *const bpath = _bpath + _end - 2;
g_return_val_if_fail(bpath != NULL, NR::Point(0, 0));
-
- Geom::Point p(NR_HUGE, NR_HUGE);
- Geom::Curve const& back = _pathv.back().back();
- if (_pathv.back().closed()) {
- p = back.finalPoint();
- } else {
- p = back.initialPoint();
- }
- debug_check("SPCurve::penultimate_point", bpath->c(3) == p );
- return bpath->c(3);
+
+ Geom::Curve const& back = _pathv.back().back_default();
+ Geom::Point p = back.initialPoint();
+ return from_2geom(p);
}
/**
* 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) ?
+ * If the last path is only a moveto, then return that point.
*/
NR::Point
SPCurve::last_point() const
{
- NArtBpath const * bpath = last_bpath();
- g_return_val_if_fail(bpath != NULL, NR::Point(0, 0));
if (is_empty())
return NR::Point(0, 0);
- debug_check("SPCurve::last_point", bpath->c(3) == _pathv.back().finalPoint() );
- return bpath->c(3);
- // return from_2geom( _pathv.back().finalPoint() );
+ return from_2geom( _pathv.back().finalPoint() );
}
inline static bool
}
new_curve->_pathv = Geom::reverse_paths_and_order(_pathv);
-
- debug_check("SPCurve::create_reverse", new_curve);
}
/**
SPCurve::append(SPCurve const *curve2,
bool use_lineto)
{
- g_return_if_fail(this != NULL);
g_return_if_fail(curve2 != NULL);
if (curve2->is_empty())
case NR_MOVETO_OPEN:
if (use_lineto && _hascpt) {
lineto(bp->x3, bp->y3);
- use_lineto = FALSE;
+ use_lineto = false;
} else {
- if (closed) closepath();
+ if (closed && _hascpt) closepath();
moveto(bp->x3, bp->y3);
}
closed = false;
lineto(bp->x3, bp->y3);
use_lineto = FALSE;
} else {
- if (closed) closepath();
+ if (closed && _hascpt) closepath();
moveto(bp->x3, bp->y3);
}
closed = true;
closepath();
}
- debug_check("SPCurve::append", this);
-
/* 2GEOM code when code above is removed:
if (use_lineto) {
Geom::PathVector::const_iterator it = curve2->_pathv.begin();
/**
* Append \a c1 to \a this with possible fusing of close endpoints.
+ * 2GEOMproof. Needs to be recoded when NArtBpath is no longer there. Right now, it applies the same changes to bpath and pathv depending on bpath
*/
SPCurve *
SPCurve::append_continuous(SPCurve const *c1, gdouble tolerance)
{
- g_return_val_if_fail(this != NULL, NULL);
g_return_val_if_fail(c1 != NULL, NULL);
g_return_val_if_fail(!_closed, NULL);
g_return_val_if_fail(!c1->_closed, NULL);
return this;
}
- debug_check("SPCurve::append_continuous 11", this);
-
NArtBpath const *be = last_bpath();
if (be) {
- NArtBpath const *bs = c1->first_bpath();
+ NArtBpath const *bs = c1->get_bpath();
if ( bs
&& ( fabs( bs->x3 - be->x3 ) <= tolerance )
&& ( fabs( bs->y3 - be->y3 ) <= tolerance ) )
append(c1, TRUE);
}
- debug_check("SPCurve::append_continuous", this);
-
return this;
}
/**
* Remove last segment of curve.
* (Only used once in /src/pen-context.cpp)
+ * 2GEOMified
*/
void
SPCurve::backspace()
{
- g_return_if_fail(this != NULL);
-
if ( is_empty() )
return;
_pathv.back().erase_last();
_pathv.back().close(false);
}
-
- debug_check("SPCurve::backspace", this);
}
/* Private methods */
@@ -1357,7 +1286,7 @@ sp_curve_nonzero_distance_including_space(SPCurve const *const curve, double seg
}
/**
- *
+ * 2GEOMified
*/
void
SPCurve::stretch_endpoints(NR::Point const &new_p0, NR::Point const &new_p1)
Geom::Piecewise<Geom::D2<Geom::SBasis> > offsetpath = Geom::sectionize( Geom::D2<Geom::Piecewise<Geom::SBasis> >(offsetx, offsety) );
pwd2 += offsetpath;
_pathv = Geom::path_from_piecewise( pwd2, 0.001 );
-
- debug_check("SPCurve::stretch_endpoints", this);
}
/**
_pathv.front().setInitial(to_2geom(new_p0));
_pathv.front().setFinal(to_2geom(new_p1));
-
- debug_check("SPCurve::move_endpoints", this);
}
/**
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
}
- debug_check("SPCurve::nodes_in_path", r == (gint)nr);
-
return r;
}
/**
* Adds p to the last point (and last handle if present) of the last path
+ * 2GEOMified
*/
void
SPCurve::last_point_additive_move(Geom::Point const & p)
newcube.setPoint(2, newcube[2] + p);
_pathv.back().replace( --_pathv.back().end(), newcube );
}
-
- debug_check("SPCurve::last_point_additive_move", this);
}
/*