From: johanengelen Date: Fri, 6 Jun 2008 01:43:35 +0000 (+0000) Subject: merge gsoc2008_johan_path2geom into trunk X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=dda97aeba7480d08320ebceecae13b8531db1b81;p=inkscape.git merge gsoc2008_johan_path2geom into trunk --- diff --git a/src/display/bezier-utils.cpp b/src/display/bezier-utils.cpp index 7957ef56c..b01e31b14 100644 --- a/src/display/bezier-utils.cpp +++ b/src/display/bezier-utils.cpp @@ -148,8 +148,8 @@ copy_without_nans_or_adjacent_duplicates(NR::Point const src[], unsigned src_len if ( si == src_len ) { return 0; } - if (!isNaN(src[si][NR::X]) && - !isNaN(src[si][NR::Y])) { + if (!IS_NAN(src[si][NR::X]) && + !IS_NAN(src[si][NR::Y])) { dest[0] = NR::Point(src[si]); ++si; break; @@ -160,8 +160,8 @@ copy_without_nans_or_adjacent_duplicates(NR::Point const src[], unsigned src_len for (; si < src_len; ++si) { NR::Point const src_pt = NR::Point(src[si]); if ( src_pt != dest[di] - && !isNaN(src_pt[NR::X]) - && !isNaN(src_pt[NR::Y])) { + && !IS_NAN(src_pt[NR::X]) + && !IS_NAN(src_pt[NR::Y])) { dest[++di] = src_pt; } } @@ -201,7 +201,7 @@ sp_bezier_fit_cubic_full(NR::Point bezier[], int split_points[], double const dist = ( L2( data[len - 1] - data[0] ) / 3.0 ); - if (isNaN(dist)) { + if (IS_NAN(dist)) { /* Numerical problem, fall back to straight line segment. */ bezier[1] = bezier[0]; bezier[2] = bezier[3]; @@ -604,7 +604,7 @@ NewtonRaphsonRootFind(BezierCurve const Q, NR::Point const &P, gdouble const u) } } - if (!isFinite(improved_u)) { + if (!IS_FINITE(improved_u)) { improved_u = u; } else if ( improved_u < 0.0 ) { improved_u = 0.0; @@ -835,7 +835,7 @@ chord_length_parameterize(NR::Point const d[], gdouble u[], unsigned const len) /* Then scale to [0.0 .. 1.0]. */ gdouble tot_len = u[len - 1]; g_return_if_fail( tot_len != 0 ); - if (isFinite(tot_len)) { + if (IS_FINITE(tot_len)) { for (unsigned i = 1; i < len; ++i) { u[i] /= tot_len; } @@ -849,7 +849,7 @@ chord_length_parameterize(NR::Point const d[], gdouble u[], unsigned const len) /** \todo * It's been reported that u[len - 1] can differ from 1.0 on some * systems (amd64), despite it having been calculated as x / x where x - * is isFinite and non-zero. + * is IS_FINITE and non-zero. */ if (u[len - 1] != 1) { double const diff = u[len - 1] - 1; diff --git a/src/display/canvas-bpath.cpp b/src/display/canvas-bpath.cpp index a3327308c..3c46a9049 100644 --- a/src/display/canvas-bpath.cpp +++ b/src/display/canvas-bpath.cpp @@ -142,7 +142,7 @@ sp_canvas_bpath_update (SPCanvasItem *item, NR::Matrix const &affine, unsigned i Path* thePath=new Path; thePath->LoadArtBPath(SP_CURVE_BPATH(cbp->curve), affine, true); thePath->Convert(0.25); - if ((cbp->fill_rgba & 0xff) && (cbp->curve->_end > 2)) { + if ((cbp->fill_rgba & 0xff) && (cbp->curve->get_length() > 2)) { Shape* theShape=new Shape; thePath->Fill(theShape,0); if ( cbp->fill_shp == NULL ) cbp->fill_shp=new Shape; @@ -165,7 +165,7 @@ sp_canvas_bpath_update (SPCanvasItem *item, NR::Matrix const &affine, unsigned i } } } - if ((cbp->stroke_rgba & 0xff) && (cbp->curve->_end > 1)) { + if ((cbp->stroke_rgba & 0xff) && (cbp->curve->get_length() > 1)) { JoinType join=join_straight; // Shape* theShape=new Shape; ButtType butt=butt_straight; diff --git a/src/display/curve.cpp b/src/display/curve.cpp index 966a35f5b..eb86773f9 100644 --- a/src/display/curve.cpp +++ b/src/display/curve.cpp @@ -25,29 +25,74 @@ #include #include #include +#include +#include #include #include +#include <2geom/pathvector.h> +#include <2geom/sbasis-geometric.h> +#include <2geom/sbasis-to-bezier.h> +#include "svg/svg.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 */ /** * The returned curve's state is as if SPCurve::reset has just been called on it. * \param length Initial number of NArtBpath elements allocated for bpath (including NR_END * element). + * 2GEOMproof */ SPCurve::SPCurve(guint length) - : _end(0), + : _refcount(1), + _bpath(NULL), + _pathv(), + _end(0), _length(length), _substart(0), _hascpt(false), _posSet(false), _moving(false), - _closed(false), - _refcount(1), - _bpath(NULL) + _closed(false) { if (length <= 0) { g_error("SPCurve::SPCurve called with invalid length parameter"); @@ -56,8 +101,41 @@ SPCurve::SPCurve(guint length) _bpath = g_new(NArtBpath, length); _bpath->code = NR_END; + + _pathv.clear(); + + debug_check("SPCurve::SPCurve(guint length)", this); } +SPCurve::SPCurve(Geom::PathVector const& pathv) + : _refcount(1), + _bpath(NULL), + _pathv(pathv), + _end(0), + _length(0), + _substart(0), + _hascpt(false), + _posSet(false), + _moving(false), + _closed(false) +{ + // temporary code to convert to _bpath as well: + _bpath = BPath_from_2GeomPath(_pathv); + unsigned const len = sp_bpath_length(_bpath); + _length = len; + _end = _length - 1; + gint i = _end; + for (; i > 0; i--) + if ((_bpath[i].code == NR_MOVETO) || + (_bpath[i].code == NR_MOVETO_OPEN)) + break; + _substart = i; + _closed = sp_bpath_closed(_bpath); + + debug_check("SPCurve::SPCurve(Geom::PathVector const& pathv)", this); +} + +// * 2GEOMproof SPCurve * SPCurve::new_from_foreign_bpath(NArtBpath const *bpath) { @@ -81,6 +159,10 @@ SPCurve::new_from_foreign_bpath(NArtBpath const *bpath) curve->_substart = i; curve->_closed = sp_bpath_closed(new_bpath); + curve->_pathv = BPath_to_2GeomPath(curve->_bpath); + + debug_check("SPCurve::new_from_foreign_bpath", curve); + return curve; } @@ -88,6 +170,7 @@ SPCurve::new_from_foreign_bpath(NArtBpath const *bpath) * Convert NArtBpath object to SPCurve object. * * \return new SPCurve, or NULL if the curve was not created for some reason. + * 2GEOMproof */ SPCurve * SPCurve::new_from_bpath(NArtBpath *bpath) @@ -96,9 +179,13 @@ SPCurve::new_from_bpath(NArtBpath *bpath) 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 const &rect) { @@ -114,9 +201,12 @@ SPCurve::new_from_rect(NR::Maybe const &rect) } c->closepath_current(); + debug_check("SPCurve::new_from_rect", c); + return c; } +// * 2GEOMproof SPCurve::~SPCurve() { if (_bpath) { @@ -127,19 +217,33 @@ SPCurve::~SPCurve() /* Methods */ -/** - * Frees old path and sets new path - * This does not copy the bpath, so the new_bpath should not be deleted by caller - */ void -SPCurve::set_bpath(NArtBpath * new_bpath) +SPCurve::set_pathv(Geom::PathVector const & new_pathv) { - if (new_bpath && new_bpath != _bpath) { // FIXME, add function to SPCurve to change bpath? or a copy function? - if (_bpath) { - g_free(_bpath); //delete old bpath - } - _bpath = new_bpath; + _pathv = new_pathv; + + _hascpt = false; + _posSet = false; + _moving = false; + + // temporary code to convert to _bpath as well: + if (_bpath) { + g_free(_bpath); + _bpath = NULL; } + _bpath = BPath_from_2GeomPath(_pathv); + unsigned const len = sp_bpath_length(_bpath); + _length = len; + _end = _length - 1; + gint i = _end; + for (; i > 0; i--) + if ((_bpath[i].code == NR_MOVETO) || + (_bpath[i].code == NR_MOVETO_OPEN)) + break; + _substart = i; + _closed = sp_bpath_closed(_bpath); + + debug_check("SPCurve::set_pathv", this); } /** @@ -150,18 +254,30 @@ SPCurve::get_bpath() const { return _bpath; }; -/* -NArtBpath * -SPCurve::get_bpath() + +Geom::PathVector const & +SPCurve::get_pathvector() const { - return _bpath; -}; -*/ + return _pathv; +} + +/** + *Returns index in bpath[] of NR_END element. + * remove for 2geom + */ +guint +SPCurve::get_length() const +{ +// g_message("SPCurve::get_length must be removed"); + + return _end; +} /** * Increase _refcount of curve. * * \todo should this be shared with other refcounting code? + * 2GEOMproof */ SPCurve * SPCurve::ref() @@ -177,6 +293,7 @@ SPCurve::ref() * Decrease refcount of curve, with possible destruction. * * \todo should this be shared with other refcounting code? + * 2GEOMproof */ SPCurve * SPCurve::unref() @@ -186,10 +303,6 @@ SPCurve::unref() _refcount -= 1; if (_refcount < 1) { - if (_bpath) { - g_free(_bpath); - _bpath = NULL; - } delete this; } @@ -198,6 +311,8 @@ SPCurve::unref() /** * Add space for more paths in curve. + * This function has no meaning for 2geom representation, other than maybe for optimization issues (enlargening the vector for what is to come) + * 2GEOMproof */ void SPCurve::ensure_space(guint space) @@ -218,6 +333,7 @@ SPCurve::ensure_space(guint space) /** * Create new curve from its own bpath array. + * 2GEOMproof */ SPCurve * SPCurve::copy() const @@ -229,6 +345,7 @@ SPCurve::copy() const /** * Return new curve that is the concatenation of all curves in list. + * 2GEOMified */ SPCurve * SPCurve::concat(GSList const *list) @@ -264,11 +381,19 @@ SPCurve::concat(GSList const *list) new_curve->_substart = i; + for (GSList const *l = list; l != NULL; l = l->next) { + SPCurve *c = (SPCurve *) l->data; + 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; } /** * Returns a list of new curves corresponding to the subpaths in \a curve. + * 2geomified */ GSList * SPCurve::split() const @@ -278,6 +403,7 @@ SPCurve::split() const guint p = 0; GSList *l = NULL; + gint pathnr = 0; while (p < _end) { gint i = 1; while ((_bpath[p + i].code == NR_LINETO) || @@ -290,8 +416,10 @@ SPCurve::split() const new_curve->_substart = 0; new_curve->_closed = (new_curve->_bpath->code == NR_MOVETO); new_curve->_hascpt = (new_curve->_bpath->code == NR_MOVETO_OPEN); + new_curve->_pathv = Geom::PathVector(1, _pathv[pathnr]); l = g_slist_prepend(l, new_curve); p += i; + pathnr++; } return l; @@ -302,7 +430,7 @@ SPCurve::split() const */ template static void -tmpl_curve_transform(SPCurve *const curve, M const &m) +tmpl_curve_transform(SPCurve * curve, M const &m) { g_return_if_fail(curve != NULL); @@ -329,24 +457,44 @@ tmpl_curve_transform(SPCurve *const curve, M const &m) /** * Transform all paths in curve using matrix. + * 2GEOMified, can be deleted when completely 2geom */ void SPCurve::transform(NR::Matrix const &m) { tmpl_curve_transform(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(this, m); + + transform(to_2geom(m)); + + debug_check("SPCurve::transform translate", this); } /** * Set curve to empty curve. + * 2GEOMified */ void SPCurve::reset() @@ -360,6 +508,10 @@ SPCurve::reset() _posSet = false; _moving = false; _closed = false; + + _pathv.clear(); + + debug_check("SPCurve::reset", this); } /* Several consecutive movetos are ALLOWED */ @@ -372,9 +524,17 @@ SPCurve::moveto(gdouble x, gdouble y) { moveto(NR::Point(x, y)); } - +/** + * Calls SPCurve::moveto() with point made of given coordinates. + */ +void +SPCurve::moveto(Geom::Point const &p) +{ + moveto(from_2geom(p)); +} /** * Perform a moveto to a point, thus starting a new subpath. + * 2GEOMified */ void SPCurve::moveto(NR::Point const &p) @@ -386,8 +546,21 @@ SPCurve::moveto(NR::Point const &p) _hascpt = true; _posSet = true; _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); } +/** + * Calls SPCurve::lineto() with a point's coordinates. + */ +void +SPCurve::lineto(Geom::Point const &p) +{ + lineto(p[Geom::X], p[Geom::Y]); +} /** * Calls SPCurve::lineto() with a point's coordinates. */ @@ -396,9 +569,9 @@ SPCurve::lineto(NR::Point const &p) { lineto(p[NR::X], p[NR::Y]); } - /** * Adds a line to the current subpath. + * 2GEOMified */ void SPCurve::lineto(gdouble x, gdouble y) @@ -415,10 +588,14 @@ SPCurve::lineto(gdouble x, gdouble y) bp->x3 = x; bp->y3 = y; _moving = false; - return; - } - if (_posSet) { + Geom::Path::iterator it = _pathv.back().end(); + if ( Geom::LineSegment const *last_line_segment = dynamic_cast( &(*it) )) { + Geom::LineSegment new_seg( *last_line_segment ); + new_seg.setFinal( Geom::Point(x,y) ); + _pathv.back().replace(it, new_seg); + } + } else if (_posSet) { /* start a new segment */ ensure_space(2); NArtBpath *bp = _bpath + _end; @@ -433,73 +610,39 @@ SPCurve::lineto(gdouble x, gdouble y) _end += 2; _posSet = false; _closed = false; - return; - } - - /* add line */ - - g_return_if_fail(_end > 1); - ensure_space(1); - NArtBpath *bp = _bpath + _end; - bp->code = NR_LINETO; - bp->x3 = x; - bp->y3 = y; - bp++; - bp->code = NR_END; - _end++; -} -/// Unused -void -SPCurve::lineto_moving(gdouble x, gdouble y) -{ - g_return_if_fail(this != NULL); - g_return_if_fail(_hascpt); - - if (_moving) { - /* change endpoint */ - g_return_if_fail(!_posSet); - g_return_if_fail(_end > 1); - NArtBpath *bp = _bpath + _end - 1; - g_return_if_fail(bp->code == NR_LINETO); - bp->x3 = x; - bp->y3 = y; + _pathv.back().appendNew( Geom::Point(x,y) ); return; - } + } else { + /* add line */ - if (_posSet) { - /* start a new segment */ - ensure_space(2); + g_return_if_fail(_end > 1); + ensure_space(1); NArtBpath *bp = _bpath + _end; - bp->code = NR_MOVETO_OPEN; - bp->setC(3, _movePos); - bp++; bp->code = NR_LINETO; bp->x3 = x; bp->y3 = y; bp++; bp->code = NR_END; - _end += 2; - _posSet = false; - _moving = true; - _closed = false; - return; + _end++; + _pathv.back().appendNew( Geom::Point(x,y) ); } - /* add line */ - - g_return_if_fail(_end > 1); - ensure_space(1); - NArtBpath *bp = _bpath + _end; - bp->code = NR_LINETO; - bp->x3 = x; - bp->y3 = y; - bp++; - bp->code = NR_END; - _end++; - _moving = true; + debug_check("SPCurve::lineto", this); } +/** + * Calls SPCurve::curveto() with coordinates of three points. + */ +void +SPCurve::curveto(Geom::Point const &p0, 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] ); +} /** * Calls SPCurve::curveto() with coordinates of three points. */ @@ -512,9 +655,9 @@ SPCurve::curveto(NR::Point const &p0, NR::Point const &p1, NR::Point const &p2) p1[X], p1[Y], p2[X], p2[Y] ); } - /** * Adds a bezier segment to the current subpath. + * 2GEOMified */ void SPCurve::curveto(gdouble x0, gdouble y0, gdouble x1, gdouble y1, gdouble x2, gdouble y2) @@ -542,28 +685,33 @@ SPCurve::curveto(gdouble x0, gdouble y0, gdouble x1, gdouble y1, gdouble x2, gdo _end += 2; _posSet = false; _closed = false; - return; + _pathv.back().appendNew( Geom::Point(x0,y0), Geom::Point(x1,y1), Geom::Point(x2,y2) ); + } else { + /* add curve */ + + g_return_if_fail(_end > 1); + ensure_space(1); + NArtBpath *bp = _bpath + _end; + bp->code = NR_CURVETO; + bp->x1 = x0; + bp->y1 = y0; + bp->x2 = x1; + bp->y2 = y1; + bp->x3 = x2; + bp->y3 = y2; + bp++; + bp->code = NR_END; + _end++; + if (_pathv.empty()) g_message("leeg"); + else _pathv.back().appendNew( Geom::Point(x0,y0), Geom::Point(x1,y1), Geom::Point(x2,y2) ); } - /* add curve */ - - g_return_if_fail(_end > 1); - ensure_space(1); - NArtBpath *bp = _bpath + _end; - bp->code = NR_CURVETO; - bp->x1 = x0; - bp->y1 = y0; - bp->x2 = x1; - bp->y2 = y1; - bp->x3 = x2; - bp->y3 = y2; - bp++; - bp->code = NR_END; - _end++; + debug_check("SPCurve::curveto", this); } /** * Close current subpath by possibly adding a line between start and end. + * 2GEOMified */ void SPCurve::closepath() @@ -587,8 +735,23 @@ SPCurve::closepath() bs->code = NR_MOVETO; } + // Inkscape always manually adds the closing line segment to SPCurve with a lineto. + // This lineto is removed in the writing function for NArtBpath, + // so when path is closed and the last segment is a lineto, the closing line segment must really be removed first! + // TODO: fix behavior in Inkscape! + if ( /*Geom::LineSegment const *line_segment = */ dynamic_cast(&_pathv.back().back())) { + _pathv.back().erase_last(); + } + _pathv.back().close(true); _closed = true; + for (Geom::PathVector::const_iterator it = _pathv.begin(); it != _pathv.end(); it++) { + if ( ! it->closed() ) { + _closed = false; + break; + } + } + for (NArtBpath const *bp = _bpath; bp->code != NR_END; bp++) { /** \todo * effic: Maintain a count of NR_MOVETO_OPEN's (e.g. instead of @@ -601,6 +764,8 @@ SPCurve::closepath() } _hascpt = false; + + debug_check("SPCurve::closepath", this); } /** Like SPCurve::closepath() but sets the end point of the current @@ -627,8 +792,23 @@ SPCurve::closepath_current() bs->code = NR_MOVETO; } + // Inkscape always manually adds the closing line segment to SPCurve with a lineto. + // This lineto is removed in the writing function for NArtBpath, + // so when path is closed and the last segment is a lineto, the closing line segment must really be removed first! + // TODO: fix behavior in Inkscape! + if ( /*Geom::LineSegment const *line_segment = */ dynamic_cast(&_pathv.back().back())) { + _pathv.back().erase_last(); + } + _pathv.back().close(true); _closed = true; + for (Geom::PathVector::const_iterator it = _pathv.begin(); it != _pathv.end(); it++) { + if ( ! it->closed() ) { + _closed = false; + break; + } + } + for (NArtBpath const *bp = _bpath; bp->code != NR_END; bp++) { /** \todo * effic: Maintain a count of NR_MOVETO_OPEN's (e.g. instead of @@ -642,6 +822,8 @@ SPCurve::closepath_current() _hascpt = false; _moving = false; + + debug_check("SPCurve::closepath_current", this); } /** @@ -652,6 +834,9 @@ 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 ); + return (_bpath->code == NR_END); } @@ -661,13 +846,22 @@ SPCurve::is_empty() const bool SPCurve::is_closed() const { + bool closed = true; + for (Geom::PathVector::const_iterator it = _pathv.begin(); it != _pathv.end(); it++) { + if ( ! it->closed() ) { + closed = false; + break; + } + } + debug_check("SPCurve::is_closed", (closed) == (_closed) ); + return _closed; } /** * Return last subpath or NULL. */ -NArtBpath * +NArtBpath const * SPCurve::last_bpath() const { g_return_val_if_fail(this != NULL, NULL); @@ -682,7 +876,7 @@ SPCurve::last_bpath() const /** * Return first subpath or NULL. */ -NArtBpath * +NArtBpath const * SPCurve::first_bpath() const { g_return_val_if_fail(this != NULL, NULL); @@ -695,14 +889,20 @@ SPCurve::first_bpath() const } /** - * Return first point of first subpath or (0,0). + * 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) ? */ NR::Point SPCurve::first_point() const { - NArtBpath *const bpath = first_bpath(); + 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() ); } /** @@ -724,6 +924,9 @@ SPCurve::second_point() const bpath = _bpath + 1; } 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); } @@ -741,18 +944,33 @@ SPCurve::penultimate_point() const 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); } /** - * Return last point of last subpath or (0,0). + * 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) ? */ NR::Point SPCurve::last_point() const { - NArtBpath *const bpath = last_bpath(); + 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() ); } inline static bool @@ -765,6 +983,8 @@ is_moveto(NRPathcode const c) * Returns a *new* \a curve but drawn in the opposite direction. * Should result in the same shape, but * with all its markers drawn facing the other direction. + * Reverses the order of subpaths as well + * 2GEOMified **/ SPCurve * SPCurve::create_reverse() const @@ -806,10 +1026,17 @@ SPCurve::create_reverse() const g_assert_not_reached(); } } + + new_curve->_pathv = Geom::reverse_paths_and_order(_pathv); + + debug_check("SPCurve::create_reverse", new_curve); } /** - * Append \a curve2 to \a curve. + * Append \a curve2 to \a this. + * If \a use_lineto is false, simply add all paths in \a curve2 to \a this; + * if \a use_lineto is true, combine \a this's last path and \a curve2's first path and add the rest of the paths in \a curve2 to \a this. + * 2GEOMified */ void SPCurve::append(SPCurve const *curve2, @@ -818,6 +1045,8 @@ SPCurve::append(SPCurve const *curve2, g_return_if_fail(this != NULL); g_return_if_fail(curve2 != NULL); + if (curve2->is_empty()) + return; if (curve2->_end < 1) return; @@ -865,6 +1094,29 @@ SPCurve::append(SPCurve const *curve2, if (closed) { closepath(); } + + debug_check("SPCurve::append", this); + + /* 2GEOM code when code above is removed: + if (use_lineto) { + Geom::PathVector::const_iterator it = curve2->_pathv.begin(); + if ( ! _pathv.empty() ) { + Geom::Path & lastpath = _pathv.back(); + lastpath.appendNew( (*it).initialPoint() ); + lastpath.append( (*it) ); + } else { + _pathv.push_back( (*it) ); + } + + for (it++; it != curve2->_pathv.end(); it++) { + _pathv.push_back( (*it) ); + } + } else { + for (Geom::PathVector::const_iterator it = curve2->_pathv.begin(); it != curve2->_pathv.end(); it++) { + _pathv.push_back( (*it) ); + } + } + */ } /** @@ -882,7 +1134,9 @@ SPCurve::append_continuous(SPCurve const *c1, gdouble tolerance) return this; } - NArtBpath *be = last_bpath(); + debug_check("SPCurve::append_continuous 11", this); + + NArtBpath const *be = last_bpath(); if (be) { NArtBpath const *bs = c1->first_bpath(); if ( bs @@ -923,17 +1177,23 @@ SPCurve::append_continuous(SPCurve const *c1, gdouble 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) */ void SPCurve::backspace() { g_return_if_fail(this != NULL); + if ( is_empty() ) + return; + if (_end > 0) { _end -= 1; if (_end > 0) { @@ -950,6 +1210,13 @@ SPCurve::backspace() } _bpath[_end].code = NR_END; } + + if ( !_pathv.back().empty() ) { + _pathv.back().erase_last(); + _pathv.back().close(false); + } + + debug_check("SPCurve::backspace", this); } /* Private methods */ @@ -1089,6 +1356,9 @@ sp_curve_nonzero_distance_including_space(SPCurve const *const curve, double seg } } +/** + * + */ void SPCurve::stretch_endpoints(NR::Point const &new_p0, NR::Point const &new_p1) { @@ -1130,8 +1400,29 @@ SPCurve::stretch_endpoints(NR::Point const &new_p0, NR::Point const &new_p1) /* Explicit set for better numerical properties. */ _bpath[nSegs].setC(3, new_p1); delete [] seg2len; + + Geom::Piecewise > pwd2 = _pathv.front().toPwSb(); + Geom::Piecewise arclength = Geom::arcLengthSb(pwd2); + if ( arclength.lastValue() <= 0 ) { + g_error("SPCurve::stretch_endpoints - arclength <= 0"); + throw; + } + arclength *= 1./arclength.lastValue(); + Geom::Point const A( to_2geom(offset0) ); + Geom::Point const B( to_2geom(offset1) ); + Geom::Piecewise offsetx = (arclength*-1.+1)*A[0] + arclength*B[0]; + Geom::Piecewise offsety = (arclength*-1.+1)*A[1] + arclength*B[1]; + Geom::Piecewise > offsetpath = Geom::sectionize( Geom::D2 >(offsetx, offsety) ); + pwd2 += offsetpath; + _pathv = Geom::path_from_piecewise( pwd2, 0.001 ); + + debug_check("SPCurve::stretch_endpoints", this); } +/** + * sets start of first path to new_p0, and end of first path to new_p1 + * 2GEOMified + */ void SPCurve::move_endpoints(NR::Point const &new_p0, NR::Point const &new_p1) { @@ -1143,8 +1434,72 @@ SPCurve::move_endpoints(NR::Point const &new_p0, NR::Point const &new_p1) _bpath->setC(3, new_p0); _bpath[nSegs].setC(3, new_p1); + + _pathv.front().setInitial(to_2geom(new_p0)); + _pathv.front().setFinal(to_2geom(new_p1)); + + debug_check("SPCurve::move_endpoints", this); +} + +/** + * returns the number of nodes in a path, used for statusbar text when selecting an spcurve. + * 2GEOMified + */ +guint +SPCurve::nodes_in_path() const +{ + gint r = _end; + gint i = _length - 1; + if (i > r) i = r; // sometimes after switching from node editor length is wrong, e.g. f6 - draw - f2 - tab - f1, this fixes it + for (; i >= 0; i --) + if (_bpath[i].code == NR_MOVETO) + r --; + + guint nr = 0; + for(Geom::PathVector::const_iterator it = _pathv.begin(); it != _pathv.end(); ++it) { + 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 + } + + 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 + */ +void +SPCurve::last_point_additive_move(Geom::Point const & p) +{ + if (is_empty()) { + return; + } + if (_end == 0) { + return; + } + NArtBpath * path = _bpath + _end - 1; + + if (path->code == NR_CURVETO) { + path->x2 += p[Geom::X]; + path->y2 += p[Geom::Y]; + } + path->x3 += p[Geom::X]; + path->y3 += p[Geom::Y]; + + _pathv.back().setFinal( _pathv.back().finalPoint() + p ); + + // Move handle as well when the last segment is a cubic bezier segment: + // TODO: what to do for quadratic beziers? + if ( Geom::CubicBezier const *lastcube = dynamic_cast(&_pathv.back().back()) ) { + Geom::CubicBezier newcube( *lastcube ); + newcube.setPoint(2, newcube[2] + p); + _pathv.back().replace( --_pathv.back().end(), newcube ); + } + + debug_check("SPCurve::last_point_additive_move", this); +} /* Local Variables: diff --git a/src/display/curve.h b/src/display/curve.h index 5cd8bb12c..4e94578ed 100644 --- a/src/display/curve.h +++ b/src/display/curve.h @@ -18,58 +18,33 @@ #include #include +#include <2geom/forward.h> +#include <2geom/point.h> + #include "libnr/nr-forward.h" #include "libnr/nr-rect.h" #define SP_CURVE_LENSTEP 32 -/// Wrapper around NArtBpath. +struct SPObject; + +/// Wrapper around Geom::PathVector. class SPCurve { public: /* Constructors */ SPCurve(guint length = SP_CURVE_LENSTEP); + SPCurve(Geom::PathVector const& pathv); static SPCurve * new_from_bpath(NArtBpath *bpath); static SPCurve * new_from_foreign_bpath(NArtBpath const *bpath); static SPCurve * new_from_rect(NR::Maybe const &rect); virtual ~SPCurve(); - void set_bpath(NArtBpath * new_bpath); + void set_pathv(Geom::PathVector const & new_pathv); NArtBpath const * get_bpath() const; + Geom::PathVector const & get_pathvector() const; - /// Index in bpath[] of NR_END element. - guint _end; - - /// Allocated size (i.e., capacity) of bpath[] array. Not to be confused - /// with the SP_CURVE_LENGTH macro, which returns the logical length of - /// the path (i.e., index of NR_END). - guint _length; - - /// Index in bpath[] of the start (i.e., moveto element) of the last - /// subpath in this path. - guint _substart; - - /// Previous moveto position. - /// \note This is used for coalescing moveto's, whereas if we're to - /// conform to the SVG spec then we mustn't coalesce movetos if we have - /// midpoint markers. Ref: - /// http://www.w3.org/TR/SVG11/implnote.html#PathElementImplementationNotes - /// (first subitem of the item about zero-length path segments) - NR::Point _movePos; - - /// True iff current point is defined. Initially false for a new curve; - /// becomes true after moveto; becomes false on closepath. Curveto, - /// lineto etc. require hascpt; hascpt remains true after lineto/curveto. - bool _hascpt : 1; - - /// True iff previous was moveto. - bool _posSet : 1; - - /// True iff bpath end is moving. - bool _moving : 1; - - /// True iff all subpaths are closed. - bool _closed : 1; + guint get_length() const; SPCurve * ref(); SPCurve * unref(); @@ -77,18 +52,22 @@ public: SPCurve * copy() const; GSList * split() const; + void transform(Geom::Matrix const &m); void transform(NR::Matrix const &); void transform(NR::translate const &); void stretch_endpoints(NR::Point const &, NR::Point const &); void move_endpoints(NR::Point const &, NR::Point const &); + void last_point_additive_move(Geom::Point const & p); void reset(); + void moveto(Geom::Point const &p); void moveto(NR::Point const &p); void moveto(gdouble x, gdouble y); + void lineto(Geom::Point const &p); void lineto(NR::Point const &p); void lineto(gdouble x, gdouble y); - void lineto_moving(gdouble x, gdouble y); + void curveto(Geom::Point const &p0, Geom::Point const &p1, Geom::Point const &p2); void curveto(NR::Point const &p0, NR::Point const &p1, NR::Point const &p2); void curveto(gdouble x0, gdouble y0, gdouble x1, gdouble y1, gdouble x2, gdouble y2); void closepath(); @@ -98,12 +77,13 @@ public: bool is_empty() const; bool is_closed() const; - NArtBpath * last_bpath() const; - NArtBpath * first_bpath() const; + NArtBpath const * last_bpath() const; + NArtBpath const * first_bpath() const; NR::Point first_point() const; NR::Point last_point() const; NR::Point second_point() const; NR::Point penultimate_point() const; + guint nodes_in_path() const; void append(SPCurve const *curve2, bool use_lineto); SPCurve * create_reverse() const; @@ -117,20 +97,61 @@ protected: gint _refcount; NArtBpath *_bpath; + Geom::PathVector _pathv; + + /// Index in bpath[] of NR_END element. + guint _end; + + /// Allocated size (i.e., capacity) of bpath[] array. Not to be confused + /// with the SP_CURVE_LENGTH macro, which returns the logical length of + /// the path (i.e., index of NR_END). + guint _length; + + /// Index in bpath[] of the start (i.e., moveto element) of the last + /// subpath in this path. + guint _substart; + + /// Previous moveto position. + /// \note This is used for coalescing moveto's, whereas if we're to + /// conform to the SVG spec then we mustn't coalesce movetos if we have + /// midpoint markers. Ref: + /// http://www.w3.org/TR/SVG11/implnote.html#PathElementImplementationNotes + /// (first subitem of the item about zero-length path segments) + NR::Point _movePos; + + /// True iff current point is defined. Initially false for a new curve; + /// becomes true after moveto; becomes false on closepath. Curveto, + /// lineto etc. require hascpt; hascpt remains true after lineto/curveto. + bool _hascpt : 1; + + /// True iff previous was moveto. + bool _posSet : 1; + + /// True iff bpath end is moving. + bool _moving : 1; + + /// True iff all subpaths are closed. + bool _closed : 1; private: // Don't implement these: SPCurve(const SPCurve&); SPCurve& operator=(const SPCurve&); +//friends: friend double sp_curve_distance_including_space(SPCurve const *const curve, double seg2len[]); friend double sp_curve_nonzero_distance_including_space(SPCurve const *const curve, double seg2len[]); template friend void tmpl_curve_transform(SPCurve *const curve, M const &m); + // this function is the only one who needs read access to _movePos and _posSet + friend void sp_polygon_set(SPObject *object, unsigned int key, const gchar *value); + + static void debug_check( char const * text, SPCurve const * curve); + static void debug_check( char const * text, bool a); }; -#define SP_CURVE_LENGTH(c) (((SPCurve const *)(c))->_end) -#define SP_CURVE_BPATH(c) ((c)->get_bpath()) -#define SP_CURVE_SEGMENT(c,i) ((c)->get_bpath() + (i)) +#define SP_CURVE_LENGTH(c) (((SPCurve const *)(c))->get_length()) +#define SP_CURVE_BPATH(c) (((SPCurve const *)(c))->get_bpath()) +#define SP_CURVE_SEGMENT(c,i) (((SPCurve const *)(c))->get_bpath() + (i)) #endif /* !SEEN_DISPLAY_CURVE_H */ @@ -143,4 +164,4 @@ private: fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/display/nr-arena-shape.cpp b/src/display/nr-arena-shape.cpp index 0ff7132e1..0cd0de2bb 100644 --- a/src/display/nr-arena-shape.cpp +++ b/src/display/nr-arena-shape.cpp @@ -432,7 +432,7 @@ void nr_arena_shape_update_fill(NRArenaShape *shape, NRGC *gc, NRRectL *area, bool force_shape) { if ((shape->_fill.paint.type() != NRArenaShape::Paint::NONE || force_shape) && - ((shape->curve->_end > 2) || (SP_CURVE_BPATH(shape->curve)[1].code == NR_CURVETO)) ) { + ((shape->curve->get_length() > 2) || (SP_CURVE_BPATH(shape->curve)[1].code == NR_CURVETO)) ) { if (TRUE || !shape->fill_shp) { NR::Matrix cached_to_new = NR::identity(); int isometry = 0; diff --git a/src/display/nr-filter-composite.cpp b/src/display/nr-filter-composite.cpp index 8670f61b2..02a195bb0 100644 --- a/src/display/nr-filter-composite.cpp +++ b/src/display/nr-filter-composite.cpp @@ -207,7 +207,7 @@ void FilterComposite::set_operator(FeCompositeOperator op) { } void FilterComposite::set_arithmetic(double k1, double k2, double k3, double k4) { - if (!isFinite(k1) || !isFinite(k2) || !isFinite(k3) || !isFinite(k4)) { + if (!IS_FINITE(k1) || !IS_FINITE(k2) || !IS_FINITE(k3) || !IS_FINITE(k4)) { g_warning("Non-finite parameter for feComposite arithmetic operator"); return; } diff --git a/src/display/nr-filter-gaussian.cpp b/src/display/nr-filter-gaussian.cpp index 5ef430394..311333247 100644 --- a/src/display/nr-filter-gaussian.cpp +++ b/src/display/nr-filter-gaussian.cpp @@ -792,14 +792,14 @@ FilterTraits FilterGaussian::get_input_traits() { void FilterGaussian::set_deviation(double deviation) { - if(isFinite(deviation) && deviation >= 0) { + if(IS_FINITE(deviation) && deviation >= 0) { _deviation_x = _deviation_y = deviation; } } void FilterGaussian::set_deviation(double x, double y) { - if(isFinite(x) && x >= 0 && isFinite(y) && y >= 0) { + if(IS_FINITE(x) && x >= 0 && IS_FINITE(y) && y >= 0) { _deviation_x = x; _deviation_y = y; } diff --git a/src/draw-context.cpp b/src/draw-context.cpp index 6e919d81d..33c3898a7 100644 --- a/src/draw-context.cpp +++ b/src/draw-context.cpp @@ -312,9 +312,9 @@ spdc_attach_selection(SPDrawContext *dc, Inkscape::Selection */*sel*/) for (GSList *l = dc->white_curves; l != NULL; l = l->next) { SPCurve *c; c = (SPCurve*)l->data; - g_return_if_fail( c->_end > 1 ); + g_return_if_fail( c->get_length() > 1 ); if ( SP_CURVE_BPATH(c)->code == NR_MOVETO_OPEN ) { - NArtBpath *s, *e; + NArtBpath const *s, *e; SPDrawAnchor *a; s = c->first_bpath(); e = c->last_bpath(); diff --git a/src/dyna-draw-context.cpp b/src/dyna-draw-context.cpp index 7f3c41c2e..c6140d17d 100644 --- a/src/dyna-draw-context.cpp +++ b/src/dyna-draw-context.cpp @@ -704,7 +704,7 @@ sp_dyna_draw_context_root_handler(SPEventContext *event_context, // so _gradually_ let go attraction to prevent jerks target = (dc->hatch_spacing * speed + hatch_dist * (SPEED_NORMAL - speed))/SPEED_NORMAL; } - if (!isNaN(dot) && dot < -0.5) {// flip + if (!IS_NAN(dot) && dot < -0.5) {// flip target = -target; } @@ -775,7 +775,7 @@ sp_dyna_draw_context_root_handler(SPEventContext *event_context, } else { // Not drawing but spacing set: gray, center snapped, fixed radius NR::Point c = (nearest + dc->hatch_spacing * hatch_unit_vector) * motion_to_curve.inverse(); - if (!isNaN(c[NR::X]) && !isNaN(c[NR::Y])) { + if (!IS_NAN(c[NR::X]) && !IS_NAN(c[NR::Y])) { NR::Matrix const sm (NR::scale(dc->hatch_spacing, dc->hatch_spacing) * NR::translate(c)); sp_canvas_item_affine_absolute(dc->hatch_area, sm); sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(dc->hatch_area), 0x7f7f7fff, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); @@ -989,7 +989,7 @@ set_to_accumulated(SPDynaDrawContext *dc, bool unionize) item->transform = SP_ITEM(desktop->currentRoot())->getRelativeTransform(desktop->currentLayer()); item->updateRepr(); } - abp = nr_artpath_affine(dc->accumulated->first_bpath(), sp_desktop_dt2root_affine(desktop)); + abp = nr_artpath_affine(dc->accumulated->get_bpath(), sp_desktop_dt2root_affine(desktop)); str = sp_svg_write_path(abp); g_assert( str != NULL ); g_free(abp); @@ -1053,22 +1053,22 @@ accumulate_calligraphic(SPDynaDrawContext *dc) dc->accumulated->reset(); /* Is this required ?? */ SPCurve *rev_cal2 = dc->cal2->create_reverse(); - g_assert(dc->cal1->_end > 1); - g_assert(rev_cal2->_end > 1); + g_assert(dc->cal1->get_length() > 1); + g_assert(rev_cal2->get_length() > 1); g_assert(SP_CURVE_SEGMENT(dc->cal1, 0)->code == NR_MOVETO_OPEN); g_assert(SP_CURVE_SEGMENT(rev_cal2, 0)->code == NR_MOVETO_OPEN); g_assert(SP_CURVE_SEGMENT(dc->cal1, 1)->code == NR_CURVETO); g_assert(SP_CURVE_SEGMENT(rev_cal2, 1)->code == NR_CURVETO); - g_assert(SP_CURVE_SEGMENT(dc->cal1, dc->cal1->_end-1)->code == NR_CURVETO); - g_assert(SP_CURVE_SEGMENT(rev_cal2, rev_cal2->_end-1)->code == NR_CURVETO); + g_assert(SP_CURVE_SEGMENT(dc->cal1, dc->cal1->get_length()-1)->code == NR_CURVETO); + g_assert(SP_CURVE_SEGMENT(rev_cal2, rev_cal2->get_length()-1)->code == NR_CURVETO); dc->accumulated->append(dc->cal1, FALSE); - add_cap(dc->accumulated, SP_CURVE_SEGMENT(dc->cal1, dc->cal1->_end-1)->c(2), SP_CURVE_SEGMENT(dc->cal1, dc->cal1->_end-1)->c(3), SP_CURVE_SEGMENT(rev_cal2, 0)->c(3), SP_CURVE_SEGMENT(rev_cal2, 1)->c(1), dc->cap_rounding); + add_cap(dc->accumulated, SP_CURVE_SEGMENT(dc->cal1, dc->cal1->get_length()-1)->c(2), SP_CURVE_SEGMENT(dc->cal1, dc->cal1->get_length()-1)->c(3), SP_CURVE_SEGMENT(rev_cal2, 0)->c(3), SP_CURVE_SEGMENT(rev_cal2, 1)->c(1), dc->cap_rounding); dc->accumulated->append(rev_cal2, TRUE); - add_cap(dc->accumulated, SP_CURVE_SEGMENT(rev_cal2, rev_cal2->_end-1)->c(2), SP_CURVE_SEGMENT(rev_cal2, rev_cal2->_end-1)->c(3), SP_CURVE_SEGMENT(dc->cal1, 0)->c(3), SP_CURVE_SEGMENT(dc->cal1, 1)->c(1), dc->cap_rounding); + add_cap(dc->accumulated, SP_CURVE_SEGMENT(rev_cal2, rev_cal2->get_length()-1)->c(2), SP_CURVE_SEGMENT(rev_cal2, rev_cal2->get_length()-1)->c(3), SP_CURVE_SEGMENT(dc->cal1, 0)->c(3), SP_CURVE_SEGMENT(dc->cal1, 1)->c(1), dc->cap_rounding); dc->accumulated->closepath(); @@ -1107,7 +1107,7 @@ fit_and_split(SPDynaDrawContext *dc, gboolean release) #endif /* Current calligraphic */ - if ( dc->cal1->_end == 0 || dc->cal2->_end == 0 ) { + if ( dc->cal1->get_length() == 0 || dc->cal2->get_length() == 0 ) { /* dc->npoints > 0 */ /* g_print("calligraphics(1|2) reset\n"); */ dc->cal1->reset(); diff --git a/src/eraser-context.cpp b/src/eraser-context.cpp index 88496b065..36cfb0d15 100644 --- a/src/eraser-context.cpp +++ b/src/eraser-context.cpp @@ -736,7 +736,7 @@ set_to_accumulated(SPEraserContext *dc) item->transform = SP_ITEM(desktop->currentRoot())->getRelativeTransform(desktop->currentLayer()); item->updateRepr(); } - abp = nr_artpath_affine(dc->accumulated->first_bpath(), sp_desktop_dt2root_affine(desktop)); + abp = nr_artpath_affine(dc->accumulated->get_bpath(), sp_desktop_dt2root_affine(desktop)); str = sp_svg_write_path(abp); g_assert( str != NULL ); g_free(abp); @@ -879,22 +879,22 @@ accumulate_eraser(SPEraserContext *dc) dc->accumulated->reset(); /* Is this required ?? */ SPCurve *rev_cal2 = dc->cal2->create_reverse(); - g_assert(dc->cal1->_end > 1); - g_assert(rev_cal2->_end > 1); + g_assert(dc->cal1->get_length() > 1); + g_assert(rev_cal2->get_length() > 1); g_assert(SP_CURVE_SEGMENT(dc->cal1, 0)->code == NR_MOVETO_OPEN); g_assert(SP_CURVE_SEGMENT(rev_cal2, 0)->code == NR_MOVETO_OPEN); g_assert(SP_CURVE_SEGMENT(dc->cal1, 1)->code == NR_CURVETO); g_assert(SP_CURVE_SEGMENT(rev_cal2, 1)->code == NR_CURVETO); - g_assert(SP_CURVE_SEGMENT(dc->cal1, dc->cal1->_end-1)->code == NR_CURVETO); - g_assert(SP_CURVE_SEGMENT(rev_cal2, rev_cal2->_end-1)->code == NR_CURVETO); + g_assert(SP_CURVE_SEGMENT(dc->cal1, dc->cal1->get_length()-1)->code == NR_CURVETO); + g_assert(SP_CURVE_SEGMENT(rev_cal2, rev_cal2->get_length()-1)->code == NR_CURVETO); dc->accumulated->append(dc->cal1, FALSE); - add_cap(dc->accumulated, SP_CURVE_SEGMENT(dc->cal1, dc->cal1->_end-1)->c(2), SP_CURVE_SEGMENT(dc->cal1, dc->cal1->_end-1)->c(3), SP_CURVE_SEGMENT(rev_cal2, 0)->c(3), SP_CURVE_SEGMENT(rev_cal2, 1)->c(1), dc->cap_rounding); + add_cap(dc->accumulated, SP_CURVE_SEGMENT(dc->cal1, dc->cal1->get_length()-1)->c(2), SP_CURVE_SEGMENT(dc->cal1, dc->cal1->get_length()-1)->c(3), SP_CURVE_SEGMENT(rev_cal2, 0)->c(3), SP_CURVE_SEGMENT(rev_cal2, 1)->c(1), dc->cap_rounding); dc->accumulated->append(rev_cal2, TRUE); - add_cap(dc->accumulated, SP_CURVE_SEGMENT(rev_cal2, rev_cal2->_end-1)->c(2), SP_CURVE_SEGMENT(rev_cal2, rev_cal2->_end-1)->c(3), SP_CURVE_SEGMENT(dc->cal1, 0)->c(3), SP_CURVE_SEGMENT(dc->cal1, 1)->c(1), dc->cap_rounding); + add_cap(dc->accumulated, SP_CURVE_SEGMENT(rev_cal2, rev_cal2->get_length()-1)->c(2), SP_CURVE_SEGMENT(rev_cal2, rev_cal2->get_length()-1)->c(3), SP_CURVE_SEGMENT(dc->cal1, 0)->c(3), SP_CURVE_SEGMENT(dc->cal1, 1)->c(1), dc->cap_rounding); dc->accumulated->closepath(); @@ -933,7 +933,7 @@ fit_and_split(SPEraserContext *dc, gboolean release) #endif /* Current eraser */ - if ( dc->cal1->_end == 0 || dc->cal2->_end == 0 ) { + if ( dc->cal1->get_length() == 0 || dc->cal2->get_length() == 0 ) { /* dc->npoints > 0 */ /* g_print("erasers(1|2) reset\n"); */ dc->cal1->reset(); diff --git a/src/isnan.h b/src/isnan.h index 608f9bb56..57c221fce 100644 --- a/src/isnan.h +++ b/src/isnan.h @@ -27,17 +27,17 @@ */ #if defined(__isnan) -# define isNaN(_a) (__isnan(_a)) +# define IS_NAN(_a) (__isnan(_a)) #elif defined(__APPLE__) && __GNUC__ == 3 -# define isNaN(_a) (__isnan(_a)) /* MacOSX/Darwin definition < 10.4 */ +# define IS_NAN(_a) (__isnan(_a)) /* MacOSX/Darwin definition < 10.4 */ #elif defined(WIN32) || defined(_isnan) -# define isNaN(_a) (_isnan(_a)) /* Win32 definition */ +# define IS_NAN(_a) (_isnan(_a)) /* Win32 definition */ #elif defined(isnan) || defined(__FreeBSD__) || defined(__osf__) -# define isNaN(_a) (isnan(_a)) /* GNU definition */ +# define IS_NAN(_a) (isnan(_a)) /* GNU definition */ #elif defined (SOLARIS_2_8) && __GNUC__ == 3 && __GNUC_MINOR__ == 2 -# define isNaN(_a) (isnan(_a)) /* GNU definition */ +# define IS_NAN(_a) (isnan(_a)) /* GNU definition */ #else -# define isNaN(_a) (std::isnan(_a)) +# define IS_NAN(_a) (std::isnan(_a)) #endif /* If the above doesn't work, then try (a != a). * Also, please report a bug as per http://www.inkscape.org/report_bugs.php, @@ -46,22 +46,22 @@ #if defined(__isfinite) -# define isFinite(_a) (__isfinite(_a)) +# define IS_FINITE(_a) (__isfinite(_a)) #elif defined(__APPLE__) && __GNUC__ == 3 -# define isFinite(_a) (__isfinite(_a)) /* MacOSX/Darwin definition < 10.4 */ +# define IS_FINITE(_a) (__isfinite(_a)) /* MacOSX/Darwin definition < 10.4 */ #elif defined(__sgi) -# define isFinite(_a) (_isfinite(_a)) +# define IS_FINITE(_a) (_isfinite(_a)) #elif defined(isfinite) -# define isFinite(_a) (isfinite(_a)) +# define IS_FINITE(_a) (isfinite(_a)) #elif defined(__osf__) -# define isFinite(_a) (finite(_a) && !isNaN(_a)) +# define IS_FINITE(_a) (finite(_a) && !IS_NAN(_a)) #elif defined (SOLARIS_2_8) && __GNUC__ == 3 && __GNUC_MINOR__ == 2 #include -#define isFinite(_a) (finite(_a) && !isNaN(_a)) +#define IS_FINITE(_a) (finite(_a) && !IS_NAN(_a)) #else -# define isFinite(_a) (std::isfinite(_a)) +# define IS_FINITE(_a) (std::isfinite(_a)) #endif -/* If the above doesn't work, then try (finite(_a) && !isNaN(_a)) or (!isNaN((_a) - (_a))). +/* If the above doesn't work, then try (finite(_a) && !IS_NAN(_a)) or (!IS_NAN((_a) - (_a))). * Also, please report a bug as per http://www.inkscape.org/report_bugs.php, * giving information about what platform and compiler version you're using. */ diff --git a/src/libcola/cola.cpp b/src/libcola/cola.cpp index afad49eb2..2119ea981 100644 --- a/src/libcola/cola.cpp +++ b/src/libcola/cola.cpp @@ -132,7 +132,7 @@ void ConstrainedMajorizationLayout::majlayout( } b[i] += degree * coords[i]; } - assert(!isNaN(b[i])); + assert(!IS_NAN(b[i])); } if(constrainedLayout) { setupDummyVars(); diff --git a/src/libcola/gradient_projection.cpp b/src/libcola/gradient_projection.cpp index 94844ca88..237cb94af 100644 --- a/src/libcola/gradient_projection.cpp +++ b/src/libcola/gradient_projection.cpp @@ -50,7 +50,7 @@ unsigned GradientProjection::solve(double * b) { solver = setupVPSC(); //cerr << "in gradient projection: n=" << n << endl; for (i=0;idesiredPosition=place[i]; } @@ -98,7 +98,7 @@ unsigned GradientProjection::solve(double * b) { // move to new unconstrained position for (i=0; idesiredPosition=place[i]; } diff --git a/src/libnr/in-svg-plane-test.cpp b/src/libnr/in-svg-plane-test.cpp index f5620c32b..138812655 100644 --- a/src/libnr/in-svg-plane-test.cpp +++ b/src/libnr/in-svg-plane-test.cpp @@ -19,8 +19,8 @@ int main(int argc, char *argv[]) NR::Point const small_n3_4(-3.0 * small, 4.0 * small); NR::Point const part_nan(3., nan); - assert(isNaN(nan)); - assert(!isNaN(small)); + assert(IS_NAN(nan)); + assert(!IS_NAN(small)); UTEST_TEST("in_svg_plane") { UTEST_ASSERT(in_svg_plane(p3n4)); diff --git a/src/libnr/in-svg-plane-test.h b/src/libnr/in-svg-plane-test.h index 6cd29bd6a..ced9f978c 100644 --- a/src/libnr/in-svg-plane-test.h +++ b/src/libnr/in-svg-plane-test.h @@ -21,8 +21,8 @@ public: small_n3_4( -3.0 * small, 4.0 * small ), part_nan( 3., nan ) { - setupValid &= isNaN(nan); - setupValid &= !isNaN(small); + setupValid &= IS_NAN(nan); + setupValid &= !IS_NAN(small); } virtual ~InSvgPlaneTest() {} diff --git a/src/libnr/n-art-bpath-2geom.cpp b/src/libnr/n-art-bpath-2geom.cpp index 89ac85b2b..e9dd9f5a6 100644 --- a/src/libnr/n-art-bpath-2geom.cpp +++ b/src/libnr/n-art-bpath-2geom.cpp @@ -3,91 +3,18 @@ /** \file * Contains functions to convert from NArtBpath to 2geom's Path * - * Copyright (C) Johan Engelen 2007 + * Copyright (C) Johan Engelen 2007-2008 * * Released under GNU GPL, read the file 'COPYING' for more information */ - #include "libnr/n-art-bpath-2geom.h" + #include "svg/svg.h" #include #include <2geom/path.h> #include <2geom/svg-path.h> #include <2geom/svg-path-parser.h> -#include <2geom/sbasis-to-bezier.h> - -//########################################################## - -#include -#include -#include -#include - -static void curve_to_svgd(std::ostream & f, Geom::Curve const* c) { - if(Geom::LineSegment const *line_segment = dynamic_cast(c)) { - f << boost::format("L %g,%g ") % (*line_segment)[1][0] % (*line_segment)[1][1]; - } - else if(Geom::QuadraticBezier const *quadratic_bezier = dynamic_cast(c)) { - f << boost::format("Q %g,%g %g,%g ") % (*quadratic_bezier)[1][0] % (*quadratic_bezier)[1][0] - % (*quadratic_bezier)[2][0] % (*quadratic_bezier)[2][1]; - } - else if(Geom::CubicBezier const *cubic_bezier = dynamic_cast(c)) { - f << boost::format("C %g,%g %g,%g %g,%g ") - % (*cubic_bezier)[1][0] % (*cubic_bezier)[1][1] - % (*cubic_bezier)[2][0] % (*cubic_bezier)[2][1] - % (*cubic_bezier)[3][0] % (*cubic_bezier)[3][1]; - } -// else if(Geom::SVGEllipticalArc const *svg_elliptical_arc = dynamic_cast(c)) { -// //get at the innards and spit them out as svgd -// } - else { - //this case handles sbasis as well as all other curve types - Geom::Path sbasis_path = Geom::path_from_sbasis(c->toSBasis(), 0.1); - - //recurse to convert the new path resulting from the sbasis to svgd - for(Geom::Path::iterator iter = sbasis_path.begin(); iter != sbasis_path.end(); ++iter) { - curve_to_svgd(f, &(*iter)); - } - } -} - -static void write_svgd(std::ostream & f, Geom::Path const &p) { - if(f == NULL) { - f << "ERRRRRRORRRRR"; - return; - } - - f << boost::format("M %g,%g ") % p.initialPoint()[0] % p.initialPoint()[1]; - - for(Geom::Path::const_iterator iter(p.begin()), end(p.end()); iter != end; ++iter) { - curve_to_svgd(f, &(*iter)); - } - if(p.closed()) - f << "Z "; -} - -static void write_svgd(std::ostream & f, std::vector const &p) { - std::vector::const_iterator it(p.begin()); - for(; it != p.end(); it++) { - write_svgd(f, *it); - } -} - -std::vector -SVGD_to_2GeomPath (char const *svgd) -{ - std::vector pathv; - - try { - pathv = Geom::parse_svg_path(svgd); - } - catch (std::runtime_error e) { - g_warning("SVGPathParseError: %s", e.what()); - } - - return pathv; -} std::vector @@ -99,26 +26,15 @@ BPath_to_2GeomPath(NArtBpath const * bpath) g_warning("BPath_to_2GeomPath - empty path returned"); return pathv; } - pathv = SVGD_to_2GeomPath(svgpath); + pathv = sp_svg_read_pathv(svgpath); g_free(svgpath); return pathv; } -char * -SVGD_from_2GeomPath(std::vector const & path) -{ - std::ostringstream ss; - write_svgd(ss, path); - ss.flush(); - std::string str = ss.str(); - char * svgd = g_strdup(str.c_str()); - return svgd; -} - NArtBpath * BPath_from_2GeomPath(std::vector const & path) { - char * svgd = SVGD_from_2GeomPath(path); + char * svgd = sp_svg_write_path(path); NArtBpath *bpath = sp_svg_read_path(svgd); g_free(svgd); return bpath; diff --git a/src/libnr/n-art-bpath-2geom.h b/src/libnr/n-art-bpath-2geom.h index 21995656b..bf1592e28 100644 --- a/src/libnr/n-art-bpath-2geom.h +++ b/src/libnr/n-art-bpath-2geom.h @@ -13,9 +13,7 @@ #include <2geom/path.h> #include -std::vector SVGD_to_2GeomPath (char const *svgd); std::vector BPath_to_2GeomPath (NArtBpath const *bpath); -char * SVGD_from_2GeomPath(std::vector const & path); NArtBpath * BPath_from_2GeomPath (std::vector const & path); diff --git a/src/libnr/nr-convert2geom.h b/src/libnr/nr-convert2geom.h index 7741e7782..5e6021569 100644 --- a/src/libnr/nr-convert2geom.h +++ b/src/libnr/nr-convert2geom.h @@ -9,16 +9,36 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include <2geom/matrix.h> #include -#include <2geom/d2.h> #include +#include +#include <2geom/matrix.h> +#include <2geom/d2.h> +#include <2geom/transforms.h> +#include <2geom/point.h> + +inline Geom::Point to_2geom(NR::Point const & _pt) { + return Geom::Point(_pt[0], _pt[1]); +} + +inline NR::Point from_2geom(Geom::Point const & _pt) { + return NR::Point(_pt[0], _pt[1]); +} inline Geom::Matrix to_2geom(NR::Matrix const & mat) { Geom::Matrix mat2geom(mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]); return mat2geom; } +inline NR::Matrix from_2geom(Geom::Matrix const & mat) { + NR::Matrix mat2geom(mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]); + return mat2geom; +} + +inline Geom::Translate to_2geom(NR::translate const & mat) { + return Geom::Translate( mat.offset[0], mat.offset[1] ); +} + inline NR::Rect from_2geom(Geom::Rect const & rect2geom) { NR::Rect rect(rect2geom.min(), rect2geom.max()); return rect; diff --git a/src/libnr/nr-point-fns-test.cpp b/src/libnr/nr-point-fns-test.cpp index 11181436b..00a704b59 100644 --- a/src/libnr/nr-point-fns-test.cpp +++ b/src/libnr/nr-point-fns-test.cpp @@ -24,8 +24,8 @@ int main(int argc, char *argv[]) Point const part_nan(3., nan); Point const inf_left(-inf, 5.0); - assert(isNaN(nan)); - assert(!isNaN(small)); + assert(IS_NAN(nan)); + assert(!IS_NAN(small)); UTEST_TEST("L1") { UTEST_ASSERT( NR::L1(p0) == 0.0 ); @@ -33,7 +33,7 @@ int main(int argc, char *argv[]) UTEST_ASSERT( NR::L1(small_left) == small ); UTEST_ASSERT( NR::L1(inf_left) == inf ); UTEST_ASSERT( NR::L1(small_n3_4) == 7.0 * small ); - UTEST_ASSERT(isNaN(NR::L1(part_nan))); + UTEST_ASSERT(IS_NAN(NR::L1(part_nan))); } UTEST_TEST("L2") { @@ -42,7 +42,7 @@ int main(int argc, char *argv[]) UTEST_ASSERT( NR::L2(small_left) == small ); UTEST_ASSERT( NR::L2(inf_left) == inf ); UTEST_ASSERT( NR::L2(small_n3_4) == 5.0 * small ); - UTEST_ASSERT(isNaN(NR::L2(part_nan))); + UTEST_ASSERT(IS_NAN(NR::L2(part_nan))); } UTEST_TEST("LInfty") { @@ -51,7 +51,7 @@ int main(int argc, char *argv[]) UTEST_ASSERT( NR::LInfty(small_left) == small ); UTEST_ASSERT( NR::LInfty(inf_left) == inf ); UTEST_ASSERT( NR::LInfty(small_n3_4) == 4.0 * small ); - UTEST_ASSERT(isNaN(NR::LInfty(part_nan))); + UTEST_ASSERT(IS_NAN(NR::LInfty(part_nan))); } UTEST_TEST("is_zero") { diff --git a/src/libnr/nr-point-fns-test.h b/src/libnr/nr-point-fns-test.h index 509d9d2fa..a94ef1b73 100644 --- a/src/libnr/nr-point-fns-test.h +++ b/src/libnr/nr-point-fns-test.h @@ -26,11 +26,11 @@ public: part_nan( 3., nan ), inf_left( -inf, 5.0 ) { - TS_ASSERT( isNaN(nan) ); - TS_ASSERT( !isNaN(small) ); + TS_ASSERT( IS_NAN(nan) ); + TS_ASSERT( !IS_NAN(small) ); - setupValid &= isNaN(nan); - setupValid &= !isNaN(small); + setupValid &= IS_NAN(nan); + setupValid &= !IS_NAN(small); } virtual ~NrPointFnsTest() {} @@ -65,7 +65,7 @@ public: TS_ASSERT_EQUALS( NR::L1(small_left), small ); TS_ASSERT_EQUALS( NR::L1(inf_left), inf ); TS_ASSERT_EQUALS( NR::L1(small_n3_4), 7.0 * small ); - TS_ASSERT(isNaN(NR::L1(part_nan))); + TS_ASSERT(IS_NAN(NR::L1(part_nan))); } void testL2(void) @@ -75,7 +75,7 @@ public: TS_ASSERT_EQUALS( NR::L2(small_left), small ); TS_ASSERT_EQUALS( NR::L2(inf_left), inf ); TS_ASSERT_EQUALS( NR::L2(small_n3_4), 5.0 * small ); - TS_ASSERT( isNaN(NR::L2(part_nan)) ); + TS_ASSERT( IS_NAN(NR::L2(part_nan)) ); } void testLInfty(void) @@ -85,7 +85,7 @@ public: TS_ASSERT_EQUALS( NR::LInfty(small_left), small ); TS_ASSERT_EQUALS( NR::LInfty(inf_left), inf ); TS_ASSERT_EQUALS( NR::LInfty(small_n3_4), 4.0 * small ); - TS_ASSERT( isNaN(NR::LInfty(part_nan)) ); + TS_ASSERT( IS_NAN(NR::LInfty(part_nan)) ); } void testIsZero(void) diff --git a/src/libnr/nr-point-fns.cpp b/src/libnr/nr-point-fns.cpp index a7b128bdb..f73f71e3b 100644 --- a/src/libnr/nr-point-fns.cpp +++ b/src/libnr/nr-point-fns.cpp @@ -7,7 +7,7 @@ using NR::Point; NR::Coord NR::LInfty(Point const &p) { NR::Coord const a(fabs(p[0])); NR::Coord const b(fabs(p[1])); - return ( a < b || isNaN(b) + return ( a < b || IS_NAN(b) ? b : a ); } diff --git a/src/libnr/nr-types.cpp b/src/libnr/nr-types.cpp index 98054a551..a4e16d127 100644 --- a/src/libnr/nr-types.cpp +++ b/src/libnr/nr-types.cpp @@ -18,7 +18,7 @@ void NR::Point::normalize() { double len = hypot(_pt[0], _pt[1]); g_return_if_fail(len != 0); - g_return_if_fail(!isNaN(len)); + g_return_if_fail(!IS_NAN(len)); static double const inf = 1e400; if(len != inf) { *this /= len; diff --git a/src/libvpsc/generate-constraints.cpp b/src/libvpsc/generate-constraints.cpp index 3574a2743..f3bc65eed 100644 --- a/src/libvpsc/generate-constraints.cpp +++ b/src/libvpsc/generate-constraints.cpp @@ -79,8 +79,8 @@ bool CmpNodePos::operator() (const Node* u, const Node* v) const { if (v->pos < u->pos) { return false; } - if (isNaN(u->pos) != isNaN(v->pos)) { - return isNaN(u->pos); + if (IS_NAN(u->pos) != IS_NAN(v->pos)) { + return IS_NAN(u->pos); } return u < v; @@ -153,9 +153,9 @@ int compare_events(const void *a, const void *b) { return 1; } else if(ea->pos < eb->pos) { return -1; - } else if(isNaN(ea->pos) != isNaN(ea->pos)) { + } else if(IS_NAN(ea->pos) != IS_NAN(ea->pos)) { /* See comment in CmpNodePos. */ - return ( isNaN(ea->pos) + return ( IS_NAN(ea->pos) ? -1 : 1 ); } diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 765d0a59b..0749e4e93 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -221,40 +221,22 @@ Effect::doBeforeEffect (SPLPEItem */*lpeitem*/) void Effect::doEffect (SPCurve * curve) { - NArtBpath *new_bpath = doEffect_nartbpath(curve->get_bpath()); + NArtBpath const *bpath_in = curve->get_bpath(); - curve->set_bpath(new_bpath); -} + std::vector result_pathv; -NArtBpath * -Effect::doEffect_nartbpath (NArtBpath const * path_in) -{ try { - std::vector orig_pathv = BPath_to_2GeomPath(path_in); - - std::vector result_pathv = doEffect_path(orig_pathv); + std::vector orig_pathv = BPath_to_2GeomPath(bpath_in); - NArtBpath *new_bpath = BPath_from_2GeomPath(result_pathv); - - return new_bpath; + result_pathv = doEffect_path(orig_pathv); } catch (std::exception & e) { g_warning("Exception during LPE %s execution. \n %s", getName().c_str(), e.what()); SP_ACTIVE_DESKTOP->messageStack()->flash( Inkscape::WARNING_MESSAGE, _("An exception occurred during execution of the Path Effect.") ); - - NArtBpath *path_out; - - unsigned ret = 0; - while ( path_in[ret].code != NR_END ) { - ++ret; - } - unsigned len = ++ret; - - path_out = g_new(NArtBpath, len); - memcpy(path_out, path_in, len * sizeof(NArtBpath)); - return path_out; } + + curve->set_pathv(result_pathv); } std::vector diff --git a/src/live_effects/effect.h b/src/live_effects/effect.h index c04f248e3..a8cb525b8 100644 --- a/src/live_effects/effect.h +++ b/src/live_effects/effect.h @@ -125,8 +125,6 @@ protected: // the order in which they appear is the order in which they are // called by this base class. (i.e. doEffect(SPCurve * curve) defaults to calling // doEffect(std::vector ) - virtual NArtBpath * - doEffect_nartbpath (NArtBpath const * path_in) __attribute__ ((deprecated)); virtual std::vector doEffect_path (std::vector const & path_in); virtual Geom::Piecewise > diff --git a/src/live_effects/lpe-curvestitch.cpp b/src/live_effects/lpe-curvestitch.cpp index 9cf9f2f26..814a381af 100644 --- a/src/live_effects/lpe-curvestitch.cpp +++ b/src/live_effects/lpe-curvestitch.cpp @@ -17,7 +17,7 @@ #include "sp-item.h" #include "sp-path.h" -#include "libnr/n-art-bpath-2geom.h" +#include "svg/svg.h" #include "xml/repr.h" #include <2geom/path.h> @@ -158,7 +158,7 @@ LPECurveStitch::resetDefaults(SPItem * item) // calculate bounding box: (isn't there a simpler way?) Piecewise > pwd2; - std::vector temppath = SVGD_to_2GeomPath( SP_OBJECT_REPR(item)->attribute("inkscape:original-d")); + std::vector temppath = sp_svg_read_pathv( SP_OBJECT_REPR(item)->attribute("inkscape:original-d")); for (unsigned int i=0; i < temppath.size(); i++) { pwd2.concat( temppath[i].toPwSb() ); } diff --git a/src/live_effects/lpe-knot.h b/src/live_effects/lpe-knot.h index 521c2d7c9..a68888105 100644 --- a/src/live_effects/lpe-knot.h +++ b/src/live_effects/lpe-knot.h @@ -27,7 +27,6 @@ public: // Choose to implement one of the doEffect functions. You can delete or comment out the others. // virtual void doEffect (SPCurve * curve); -// virtual NArtBpath * doEffect_nartbpath (NArtBpath * path_in); virtual std::vector doEffect_path (std::vector const & input_path); // virtual Geom::Piecewise > doEffect_pwd2 (Geom::Piecewise > & pwd2_in); diff --git a/src/live_effects/lpe-test-doEffect-stack.cpp b/src/live_effects/lpe-test-doEffect-stack.cpp index f3fb346fe..3b578b2c6 100644 --- a/src/live_effects/lpe-test-doEffect-stack.cpp +++ b/src/live_effects/lpe-test-doEffect-stack.cpp @@ -45,31 +45,10 @@ LPEdoEffectStackTest::doEffect (SPCurve * curve) } } -NArtBpath * -LPEdoEffectStackTest::doEffect_nartbpath (NArtBpath const * path_in) -{ - if (step >= 2) { - return Effect::doEffect_nartbpath(path_in); - } else { - // return here - NArtBpath *path_out; - - unsigned ret = 0; - while ( path_in[ret].code != NR_END ) { - ++ret; - } - unsigned len = ++ret; - - path_out = g_new(NArtBpath, len); - memcpy(path_out, path_in, len * sizeof(NArtBpath)); - return path_out; - } -} - std::vector LPEdoEffectStackTest::doEffect_path (std::vector const & path_in) { - if (step >= 3) { + if (step >= 2) { return Effect::doEffect_path(path_in); } else { // return here diff --git a/src/live_effects/lpe-test-doEffect-stack.h b/src/live_effects/lpe-test-doEffect-stack.h index cf2d480b1..7c22a3b37 100644 --- a/src/live_effects/lpe-test-doEffect-stack.h +++ b/src/live_effects/lpe-test-doEffect-stack.h @@ -26,7 +26,6 @@ public: virtual ~LPEdoEffectStackTest(); virtual void doEffect (SPCurve * curve); - virtual NArtBpath * doEffect_nartbpath (NArtBpath const * path_in); virtual std::vector doEffect_path (std::vector const & path_in); virtual Geom::Piecewise > doEffect_pwd2 (Geom::Piecewise > const & pwd2_in); diff --git a/src/live_effects/lpe-vonkoch.cpp b/src/live_effects/lpe-vonkoch.cpp index ee09221ed..114dd7263 100644 --- a/src/live_effects/lpe-vonkoch.cpp +++ b/src/live_effects/lpe-vonkoch.cpp @@ -159,7 +159,7 @@ LPEVonKoch::resetDefaults(SPItem * item) // set the bend path to run horizontally in the middle of the bounding box of the original path Piecewise > pwd2; - std::vector temppath = SVGD_to_2GeomPath( SP_OBJECT_REPR(item)->attribute("inkscape:original-d")); + std::vector temppath = sp_svg_read_pathv( SP_OBJECT_REPR(item)->attribute("inkscape:original-d")); for (unsigned int i=0; i < temppath.size(); i++) { pwd2.concat( temppath[i].toPwSb() ); } diff --git a/src/live_effects/parameter/parameter.h b/src/live_effects/parameter/parameter.h index d3afec3af..511ce46a2 100644 --- a/src/live_effects/parameter/parameter.h +++ b/src/live_effects/parameter/parameter.h @@ -10,8 +10,7 @@ */ #include -#include <2geom/point.h> -#include <2geom/path.h> +#include <2geom/forward.h> struct SPDesktop; struct SPItem; diff --git a/src/live_effects/parameter/path.cpp b/src/live_effects/parameter/path.cpp index 376e61bee..759e9f788 100644 --- a/src/live_effects/parameter/path.cpp +++ b/src/live_effects/parameter/path.cpp @@ -113,10 +113,10 @@ PathParam::param_readSVGValue(const gchar * strvalue) } catch (Inkscape::BadURIException &e) { g_warning("%s", e.what()); ref.detach(); - _pathvector = SVGD_to_2GeomPath(defvalue); + _pathvector = sp_svg_read_pathv(defvalue); } } else { - _pathvector = SVGD_to_2GeomPath(strvalue); + _pathvector = sp_svg_read_pathv(strvalue); } signal_path_changed.emit(); @@ -132,7 +132,7 @@ PathParam::param_getSVGValue() const if (href) { return href; } else { - gchar * svgd = SVGD_from_2GeomPath( _pathvector ); + gchar * svgd = sp_svg_write_path( _pathvector ); return svgd; } } @@ -233,7 +233,7 @@ PathParam::param_set_and_write_new_value (Geom::Piecewise { remove_link(); _pathvector = Geom::path_from_piecewise(newpath, LPE_CONVERSION_TOLERANCE); - gchar * svgd = SVGD_from_2GeomPath( _pathvector ); + gchar * svgd = sp_svg_write_path( _pathvector ); param_write_to_repr(svgd); g_free(svgd); // force value upon pwd2 and don't recalculate. @@ -248,7 +248,7 @@ PathParam::param_set_and_write_new_value (std::vector const & newpat _pathvector = newpath; must_recalculate_pwd2 = true; - gchar * svgd = SVGD_from_2GeomPath( _pathvector ); + gchar * svgd = sp_svg_write_path( _pathvector ); param_write_to_repr(svgd); g_free(svgd); } @@ -324,7 +324,7 @@ PathParam::linked_modified(SPObject *linked_obj, guint /*flags*/) if (curve == NULL) { // curve invalid, set default value - _pathvector = SVGD_to_2GeomPath(defvalue); + _pathvector = sp_svg_read_pathv(defvalue); } else { _pathvector = BPath_to_2GeomPath(SP_CURVE_BPATH(curve)); curve->unref(); diff --git a/src/nodepath.cpp b/src/nodepath.cpp index e827f9fb0..249721cfa 100644 --- a/src/nodepath.cpp +++ b/src/nodepath.cpp @@ -95,7 +95,7 @@ static GMemChunk *nodechunk = NULL; /* Creation from object */ -static NArtBpath *subpath_from_bpath(Inkscape::NodePath::Path *np, NArtBpath *b, gchar const *t); +static NArtBpath const * subpath_from_bpath(Inkscape::NodePath::Path *np, NArtBpath const *b, gchar const *t); static gchar *parse_nodetypes(gchar const *types, gint length); /* Object updating */ @@ -181,8 +181,8 @@ Inkscape::NodePath::Path *sp_nodepath_new(SPDesktop *desktop, SPObject *object, if (curve == NULL) return NULL; - NArtBpath *bpath = curve->first_bpath(); - gint length = curve->_end; + NArtBpath const *bpath = curve->get_bpath(); + gint length = curve->get_length(); if (length == 0) { curve->unref(); return NULL; // prevent crash for one-node paths @@ -250,7 +250,7 @@ Inkscape::NodePath::Path *sp_nodepath_new(SPDesktop *desktop, SPObject *object, gchar *typestr = parse_nodetypes(nodetypes, length); // create the subpath(s) from the bpath - NArtBpath *b = bpath; + NArtBpath const *b = bpath; while (b->code != NR_END) { b = subpath_from_bpath(np, b, typestr + (b - bpath)); } @@ -444,7 +444,7 @@ static void sp_nodepath_cleanup(Inkscape::NodePath::Path *nodepath) * \param t The node type. * \todo Fixme: t should be a proper type, rather than gchar */ -static NArtBpath *subpath_from_bpath(Inkscape::NodePath::Path *np, NArtBpath *b, gchar const *t) +static NArtBpath const * subpath_from_bpath(Inkscape::NodePath::Path *np, NArtBpath const *b, gchar const *t) { NR::Point ppos, pos, npos; diff --git a/src/path-chemistry.cpp b/src/path-chemistry.cpp index 996ae3fd5..05ea6c130 100644 --- a/src/path-chemistry.cpp +++ b/src/path-chemistry.cpp @@ -435,7 +435,7 @@ sp_selected_item_to_curved_repr(SPItem *item, guint32 /*text_grouping_policy*/) // Prevent empty paths from being added to the document // otherwise we end up with zomby markup in the SVG file - if(curve->_end <= 0) + if(curve->get_length() <= 0) { curve->unref(); return NULL; diff --git a/src/pen-context.cpp b/src/pen-context.cpp index 8d7ac0819..7dc489540 100644 --- a/src/pen-context.cpp +++ b/src/pen-context.cpp @@ -806,7 +806,7 @@ pen_redraw_all (SPPenContext *const pc) sp_canvas_item_hide (pc->cl1); } - NArtBpath *const bpath = pc->green_curve->last_bpath(); + NArtBpath const * bpath = pc->green_curve->last_bpath(); if (bpath) { if (bpath->code == NR_CURVETO && NR::Point(bpath->x2, bpath->y2) != pc->p[0]) { SP_CTRL(pc->c0)->moveto(NR::Point(bpath->x2, bpath->y2)); @@ -827,14 +827,9 @@ pen_lastpoint_move (SPPenContext *const pc, gdouble x, gdouble y) return; // green - NArtBpath *const bpath = pc->green_curve->last_bpath(); + NArtBpath const * bpath = pc->green_curve->last_bpath(); if (bpath) { - if (bpath->code == NR_CURVETO) { - bpath->x2 += x; - bpath->y2 += y; - } - bpath->x3 += x; - bpath->y3 += y; + pc->green_curve->last_point_additive_move( Geom::Point(x,y) ); } else { // start anchor too if (pc->green_anchor) { @@ -861,7 +856,7 @@ pen_lastpoint_tocurve (SPPenContext *const pc) return; // red - NArtBpath *const bpath = pc->green_curve->last_bpath(); + NArtBpath const * bpath = pc->green_curve->last_bpath(); if (bpath && bpath->code == NR_CURVETO) { pc->p[1] = pc->p[0] + (NR::Point(bpath->x3, bpath->y3) - NR::Point(bpath->x2, bpath->y2)); } else { diff --git a/src/sp-ellipse.cpp b/src/sp-ellipse.cpp index e25be12af..e7a42ab7f 100644 --- a/src/sp-ellipse.cpp +++ b/src/sp-ellipse.cpp @@ -167,7 +167,7 @@ sp_genericellipse_update_patheffect(SPLPEItem *lpeitem, bool write) if (write) { Inkscape::XML::Node *repr = SP_OBJECT_REPR(shape); if ( shape->curve != NULL ) { - NArtBpath *abp = shape->curve->first_bpath(); + NArtBpath const *abp = shape->curve->get_bpath(); if (abp) { gchar *str = sp_svg_write_path(abp); repr->setAttribute("d", str); diff --git a/src/sp-item-group.cpp b/src/sp-item-group.cpp index 20efd8fe7..347f50491 100644 --- a/src/sp-item-group.cpp +++ b/src/sp-item-group.cpp @@ -853,7 +853,7 @@ sp_group_perform_patheffect(SPGroup *group, SPGroup *topgroup) Inkscape::XML::Node *repr = SP_OBJECT_REPR(subitem); - NArtBpath *abp = c->first_bpath(); + NArtBpath const *abp = c->first_bpath(); if (abp) { gchar *str = sp_svg_write_path(abp); repr->setAttribute("d", str); diff --git a/src/sp-namedview.cpp b/src/sp-namedview.cpp index 3f52232cb..9851e146a 100644 --- a/src/sp-namedview.cpp +++ b/src/sp-namedview.cpp @@ -766,9 +766,9 @@ void sp_namedview_window_from_document(SPDesktop *desktop) } // restore zoom and view - if (nv->zoom != 0 && nv->zoom != HUGE_VAL && !isNaN(nv->zoom) - && nv->cx != HUGE_VAL && !isNaN(nv->cx) - && nv->cy != HUGE_VAL && !isNaN(nv->cy)) { + if (nv->zoom != 0 && nv->zoom != HUGE_VAL && !IS_NAN(nv->zoom) + && nv->cx != HUGE_VAL && !IS_NAN(nv->cx) + && nv->cy != HUGE_VAL && !IS_NAN(nv->cy)) { desktop->zoom_absolute(nv->cx, nv->cy, nv->zoom); } else if (sp_desktop_document(desktop)) { // document without saved zoom, zoom to its page desktop->zoom_page(); diff --git a/src/sp-path.cpp b/src/sp-path.cpp index 511e1efc5..81d05ebef 100644 --- a/src/sp-path.cpp +++ b/src/sp-path.cpp @@ -122,14 +122,9 @@ gint sp_nodes_in_path(SPPath *path) { SPCurve *curve = SP_SHAPE(path)->curve; - if (!curve) return 0; - gint r = curve->_end; - gint i = curve->_length - 1; - if (i > r) i = r; // sometimes after switching from node editor length is wrong, e.g. f6 - draw - f2 - tab - f1, this fixes it - for (; i >= 0; i --) - if (SP_CURVE_BPATH(curve)[i].code == NR_MOVETO) - r --; - return r; + if (!curve) + return 0; + return curve->nodes_in_path(); } static gchar * @@ -313,7 +308,7 @@ sp_path_write(SPObject *object, Inkscape::XML::Node *repr, guint flags) } if ( shape->curve != NULL ) { - NArtBpath *abp = shape->curve->first_bpath(); + NArtBpath const * abp = shape->curve->get_bpath(); if (abp) { gchar *str = sp_svg_write_path(abp); repr->setAttribute("d", str); @@ -327,7 +322,7 @@ sp_path_write(SPObject *object, Inkscape::XML::Node *repr, guint flags) SPPath *path = (SPPath *) object; if ( path->original_curve != NULL ) { - NArtBpath *abp = path->original_curve->first_bpath(); + NArtBpath const * abp = path->original_curve->get_bpath(); if (abp) { gchar *str = sp_svg_write_path(abp); repr->setAttribute("inkscape:original-d", str); @@ -419,7 +414,7 @@ sp_path_update_patheffect(SPLPEItem *lpeitem, bool write) // could also do SP_OBJECT(shape)->updateRepr(); but only the d attribute needs updating. Inkscape::XML::Node *repr = SP_OBJECT_REPR(shape); if ( shape->curve != NULL ) { - NArtBpath *abp = shape->curve->first_bpath(); + NArtBpath const *abp = shape->curve->get_bpath(); if (abp) { gchar *str = sp_svg_write_path(abp); repr->setAttribute("d", str); diff --git a/src/sp-polygon.cpp b/src/sp-polygon.cpp index 6012e065d..d90f829b9 100644 --- a/src/sp-polygon.cpp +++ b/src/sp-polygon.cpp @@ -28,7 +28,6 @@ static void sp_polygon_init(SPPolygon *polygon); static void sp_polygon_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); static Inkscape::XML::Node *sp_polygon_write(SPObject *object, Inkscape::XML::Node *repr, guint flags); -static void sp_polygon_set(SPObject *object, unsigned int key, const gchar *value); static gchar *sp_polygon_description(SPItem *item); @@ -128,7 +127,7 @@ static Inkscape::XML::Node *sp_polygon_write(SPObject *object, Inkscape::XML::No } /* We can safely write points here, because all subclasses require it too (Lauris) */ - NArtBpath *abp = shape->curve->first_bpath(); + NArtBpath const * abp = shape->curve->get_bpath(); gchar *str = sp_svg_write_polygon(abp); repr->setAttribute("points", str); g_free(str); @@ -162,7 +161,7 @@ static gboolean polygon_get_value(gchar const **p, gdouble *v) } -static void sp_polygon_set(SPObject *object, unsigned int key, const gchar *value) +void sp_polygon_set(SPObject *object, unsigned int key, const gchar *value) { SPPolygon *polygon = SP_POLYGON(object); diff --git a/src/sp-polygon.h b/src/sp-polygon.h index 0da720fc2..3ea91be76 100644 --- a/src/sp-polygon.h +++ b/src/sp-polygon.h @@ -30,4 +30,7 @@ struct SPPolygonClass { GType sp_polygon_get_type (void); +// made 'public' so that SPCurve can set it as friend: +void sp_polygon_set(SPObject *object, unsigned int key, const gchar *value); + #endif diff --git a/src/sp-shape.cpp b/src/sp-shape.cpp index 991381bda..99e4ed485 100644 --- a/src/sp-shape.cpp +++ b/src/sp-shape.cpp @@ -546,8 +546,8 @@ NR::Matrix sp_shape_marker_get_transform(SPShape const *shape, NArtBpath const *bp) { g_return_val_if_fail(( is_moveto(SP_CURVE_BPATH(shape->curve)[0].code) - && ( 0 < shape->curve->_end ) - && ( SP_CURVE_BPATH(shape->curve)[shape->curve->_end].code == NR_END ) ), + && ( 0 < shape->curve->get_length() ) + && ( SP_CURVE_BPATH(shape->curve)[shape->curve->get_length()].code == NR_END ) ), NR::Matrix(NR::translate(bp->c(3)))); double const angle1 = incoming_tangent(bp); double const angle2 = outgoing_tangent(bp); diff --git a/src/sp-spiral.cpp b/src/sp-spiral.cpp index 60f2bbc92..7351ff61f 100644 --- a/src/sp-spiral.cpp +++ b/src/sp-spiral.cpp @@ -308,7 +308,7 @@ sp_spiral_update_patheffect(SPLPEItem *lpeitem, bool write) if (write) { Inkscape::XML::Node *repr = SP_OBJECT_REPR(shape); if ( shape->curve != NULL ) { - NArtBpath *abp = shape->curve->first_bpath(); + NArtBpath const * abp = shape->curve->get_bpath(); if (abp) { gchar *str = sp_svg_write_path(abp); repr->setAttribute("d", str); diff --git a/src/sp-star.cpp b/src/sp-star.cpp index 4c5f9623b..6543a9866 100644 --- a/src/sp-star.cpp +++ b/src/sp-star.cpp @@ -285,7 +285,7 @@ sp_star_update_patheffect(SPLPEItem *lpeitem, bool write) if (write) { Inkscape::XML::Node *repr = SP_OBJECT_REPR(shape); if ( shape->curve != NULL ) { - NArtBpath *abp = shape->curve->first_bpath(); + NArtBpath const * abp = shape->curve->get_bpath(); if (abp) { gchar *str = sp_svg_write_path(abp); repr->setAttribute("d", str); diff --git a/src/style.cpp b/src/style.cpp index fd6b17892..a67b86167 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -1672,7 +1672,7 @@ sp_style_merge_length_prop_from_dying_parent(LengthT &child, LengthT const &pare * fixme: Have separate ex ratio parameter. * Get x height from libnrtype or pango. */ - if (!isFinite(child.value)) { + if (!IS_FINITE(child.value)) { child.value = child.computed; child.unit = SP_CSS_UNIT_NONE; } diff --git a/src/svg/svg-path.cpp b/src/svg/svg-path.cpp index bd0d4a4f5..d610b9212 100644 --- a/src/svg/svg-path.cpp +++ b/src/svg/svg-path.cpp @@ -38,6 +38,11 @@ #include "gnome-canvas-bpath-util.h" #include "svg/path-string.h" +#include <2geom/pathvector.h> +#include <2geom/path.h> +#include <2geom/sbasis-to-bezier.h> +#include <2geom/svg-path.h> +#include <2geom/svg-path-parser.h> /* This module parses an SVG path element into an RsvgBpathDef. @@ -668,6 +673,21 @@ NArtBpath *sp_svg_read_path(gchar const *str) return bpath; } +Geom::PathVector sp_svg_read_pathv(char const * str) +{ + std::vector pathv; + + // TODO: enable this exception catching. don't catch now to better see when things go wrong +// try { + pathv = Geom::parse_svg_path(str); +// } +// catch (std::runtime_error e) { +// g_warning("SVGPathParseError: %s", e.what()); +// } + + return pathv; +} + gchar *sp_svg_write_path(NArtBpath const *bpath) { bool closed=false; @@ -710,6 +730,53 @@ gchar *sp_svg_write_path(NArtBpath const *bpath) return g_strdup(str.c_str()); } +static void sp_svg_write_curve(Inkscape::SVG::PathString & str, Geom::Curve const * c) { + if(Geom::LineSegment const *line_segment = dynamic_cast(c)) { + str.lineTo( (*line_segment)[1][0], (*line_segment)[1][1] ); + } + else if(Geom::QuadraticBezier const *quadratic_bezier = dynamic_cast(c)) { + str.quadTo( (*quadratic_bezier)[1][0], (*quadratic_bezier)[1][0], + (*quadratic_bezier)[2][0], (*quadratic_bezier)[2][1] ); + } + else if(Geom::CubicBezier const *cubic_bezier = dynamic_cast(c)) { + str.curveTo( (*cubic_bezier)[1][0], (*cubic_bezier)[1][1], + (*cubic_bezier)[2][0], (*cubic_bezier)[2][1], + (*cubic_bezier)[3][0], (*cubic_bezier)[3][1] ); + } + else if(Geom::EllipticalArc const *svg_elliptical_arc = dynamic_cast(c)) { + str.arcTo( svg_elliptical_arc->ray(0), svg_elliptical_arc->ray(1), + svg_elliptical_arc->rotation_angle(), + svg_elliptical_arc->large_arc_flag(), svg_elliptical_arc->sweep_flag(), + svg_elliptical_arc->finalPoint() ); + } else { + //this case handles sbasis as well as all other curve types + Geom::Path sbasis_path = Geom::path_from_sbasis(c->toSBasis(), 0.1); + + //recurse to convert the new path resulting from the sbasis to svgd + for(Geom::Path::iterator iter = sbasis_path.begin(); iter != sbasis_path.end(); ++iter) { + sp_svg_write_curve(str, &(*iter)); + } + } +} + +gchar * sp_svg_write_path(Geom::PathVector const &p) { + Inkscape::SVG::PathString str; + + for(Geom::PathVector::const_iterator pit = p.begin(); pit != p.end(); pit++) { + str.moveTo( pit->initialPoint()[0], pit->initialPoint()[1] ); + + for(Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); cit++) { + sp_svg_write_curve(str, &(*cit)); + } + + if (pit->closed()) { + str.closePath(); + } + } + + return g_strdup(str.c_str()); +} + /* Local Variables: mode:c++ diff --git a/src/svg/svg.h b/src/svg/svg.h index 4b2dea994..0e5b4d5d5 100644 --- a/src/svg/svg.h +++ b/src/svg/svg.h @@ -18,6 +18,7 @@ #include "svg/svg-length.h" #include "libnr/nr-forward.h" +#include <2geom/forward.h> /* Generic */ @@ -63,8 +64,9 @@ double sp_svg_read_percentage (const char * str, double def); /* NB! As paths can be long, we use here dynamic string */ NArtBpath * sp_svg_read_path (const char * str); -char * sp_svg_write_path (const NArtBpath * bpath); - +Geom::PathVector sp_svg_read_pathv (char const * str); +gchar * sp_svg_write_path (const NArtBpath * bpath); +gchar * sp_svg_write_path (Geom::PathVector const &p); #endif diff --git a/src/ui/clipboard.cpp b/src/ui/clipboard.cpp index 2d38f5ccd..227d57a96 100644 --- a/src/ui/clipboard.cpp +++ b/src/ui/clipboard.cpp @@ -222,7 +222,7 @@ void ClipboardManagerImpl::copy() void ClipboardManagerImpl::copyPathParameter(Inkscape::LivePathEffect::PathParam *pp) { if ( pp == NULL ) return; - gchar *svgd = SVGD_from_2GeomPath( pp->get_pathvector() ); + gchar *svgd = sp_svg_write_path( pp->get_pathvector() ); if ( svgd == NULL || *svgd == '\0' ) return; _discardInternalClipboard();