diff options
| author | Johan B. C. Engelen <jbc.engelen@swissonline.ch> | 2008-06-06 01:43:35 +0000 |
|---|---|---|
| committer | johanengelen <johanengelen@users.sourceforge.net> | 2008-06-06 01:43:35 +0000 |
| commit | 8a38c52bce619b07117cdd87a183eb05fb51e28e (patch) | |
| tree | 39b9f2af1ce9df43884a3b33ca2445097fe8f5a5 /src/display | |
| parent | oops. sys/wait.h not on win32 (diff) | |
| download | inkscape-8a38c52bce619b07117cdd87a183eb05fb51e28e.tar.gz inkscape-8a38c52bce619b07117cdd87a183eb05fb51e28e.zip | |
merge gsoc2008_johan_path2geom into trunk
(bzr r5823)
Diffstat (limited to 'src/display')
| -rw-r--r-- | src/display/bezier-utils.cpp | 16 | ||||
| -rw-r--r-- | src/display/canvas-bpath.cpp | 4 | ||||
| -rw-r--r-- | src/display/curve.cpp | 573 | ||||
| -rw-r--r-- | src/display/curve.h | 105 | ||||
| -rw-r--r-- | src/display/nr-arena-shape.cpp | 2 | ||||
| -rw-r--r-- | src/display/nr-filter-composite.cpp | 2 | ||||
| -rw-r--r-- | src/display/nr-filter-gaussian.cpp | 4 |
7 files changed, 541 insertions, 165 deletions
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 <libnr/n-art-bpath.h> #include <libnr/nr-point-matrix-ops.h> #include <libnr/nr-translate-ops.h> +#include <libnr/n-art-bpath-2geom.h> +#include <libnr/nr-convert2geom.h> #include <cstring> #include <string> +#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<NR::Rect> const &rect) { @@ -114,9 +201,12 @@ SPCurve::new_from_rect(NR::Maybe<NR::Rect> 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<class M> 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<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)); + + 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,19 +546,32 @@ 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. + */ +void 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<Geom::LineSegment const *>( &(*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,77 +610,43 @@ 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::LineSegment>( 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::LineSegment>( 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. + */ +void SPCurve::curveto(NR::Point const &p0, NR::Point const &p1, NR::Point const &p2) { using NR::X; @@ -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::CubicBezier>( 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::CubicBezier>( 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<Geom::LineSegment const *>(&_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<Geom::LineSegment const *>(&_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<Geom::LineSegment>( (*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<Geom::D2<Geom::SBasis> > pwd2 = _pathv.front().toPwSb(); + Geom::Piecewise<Geom::SBasis> 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<Geom::SBasis> offsetx = (arclength*-1.+1)*A[0] + arclength*B[0]; + Geom::Piecewise<Geom::SBasis> offsety = (arclength*-1.+1)*A[1] + arclength*B[1]; + 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); } +/** + * 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<Geom::CubicBezier const *>(&_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 <glib/gtypes.h> #include <glib/gslist.h> +#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<NR::Rect> 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<class M> 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; } |
