From 1f37e9d97c3bb8cf02b2cc80af8dcfc9aba7c7b4 Mon Sep 17 00:00:00 2001 From: johanengelen Date: Wed, 16 Jul 2008 21:36:19 +0000 Subject: [PATCH] update to latest 2geom (rev1497) --- src/2geom/CMakeLists.txt | 1 + src/2geom/Makefile_insert | 2 + src/2geom/basic-intersection.cpp | 97 +++++- src/2geom/choose.h | 1 + src/2geom/circle.cpp | 115 +++++++ src/2geom/circle.h | 127 +++++++ src/2geom/coord.h | 1 + src/2geom/curve.h | 9 +- src/2geom/curves.h | 2 +- src/2geom/ellipse.cpp | 77 ++++- src/2geom/ellipse.h | 6 +- src/2geom/forward.h | 1 + src/2geom/interval.h | 16 +- src/2geom/numeric/fitting-model.h | 36 ++ src/2geom/path-intersection.cpp | 87 ++++- src/2geom/path.cpp | 103 +++--- src/2geom/path.h | 552 ++++++++++++++---------------- src/2geom/pathvector.cpp | 11 +- src/2geom/pathvector.h | 44 ++- src/2geom/poly-dk-solve.cpp | 3 + src/2geom/poly-dk-solve.h | 9 + src/2geom/poly-laguerre-solve.cpp | 5 + src/2geom/poly-laguerre-solve.h | 9 + src/2geom/poly.cpp | 13 +- src/2geom/poly.h | 48 +-- src/2geom/rect.h | 4 + src/2geom/sbasis-roots.cpp | 4 +- src/2geom/shape.cpp | 2 +- src/2geom/svg-elliptical-arc.cpp | 22 ++ src/2geom/svg-elliptical-arc.h | 15 +- src/2geom/svg-path-parser.cpp | 48 +-- src/2geom/svg-path-parser.h | 13 +- src/2geom/svg-path.cpp | 8 +- src/2geom/svg-path.h | 8 +- src/2geom/transforms.h | 8 +- src/display/inkscape-cairo.cpp | 2 +- src/display/nr-arena-shape.cpp | 8 +- src/livarot/PathCutting.cpp | 2 +- src/live_effects/lpe-offset.cpp | 2 +- src/svg/svg-path.cpp | 2 +- 40 files changed, 1057 insertions(+), 466 deletions(-) create mode 100644 src/2geom/circle.cpp create mode 100644 src/2geom/circle.h diff --git a/src/2geom/CMakeLists.txt b/src/2geom/CMakeLists.txt index 8c22cb15a..e94c5c673 100644 --- a/src/2geom/CMakeLists.txt +++ b/src/2geom/CMakeLists.txt @@ -1,6 +1,7 @@ SET(2geom_SRC basic-intersection.cpp bezier-utils.cpp +circle.cpp circle-circle.cpp conjugate_gradient.cpp convex-cover.cpp diff --git a/src/2geom/Makefile_insert b/src/2geom/Makefile_insert index 84b9f7401..d03799dd7 100644 --- a/src/2geom/Makefile_insert +++ b/src/2geom/Makefile_insert @@ -9,6 +9,8 @@ 2geom/basic-intersection.cpp \ 2geom/bezier-utils.cpp \ 2geom/circle-circle.cpp \ + 2geom/circle.cpp \ + 2geom/circle.h \ 2geom/conjugate_gradient.cpp \ 2geom/convex-cover.cpp \ 2geom/crossing.cpp \ diff --git a/src/2geom/basic-intersection.cpp b/src/2geom/basic-intersection.cpp index 5375e5b58..48b990445 100644 --- a/src/2geom/basic-intersection.cpp +++ b/src/2geom/basic-intersection.cpp @@ -1,5 +1,8 @@ #include <2geom/basic-intersection.h> #include <2geom/exception.h> +#include +#include + unsigned intersect_steps = 0; @@ -12,6 +15,7 @@ public: OldBezier() { } void split(double t, OldBezier &a, OldBezier &b) const; + Point operator()(double t) const; ~OldBezier() {} @@ -152,7 +156,28 @@ void OldBezier::split(double t, OldBezier &left, OldBezier &right) const { right.p[j] = Vtemp[sz-1-j][j]; } - +/* + * split the curve at the midpoint, returning an array with the two parts + * Temporary storage is minimized by using part of the storage for the result + * to hold an intermediate value until it is no longer needed. + */ +Point OldBezier::operator()(double t) const { + const unsigned sz = p.size(); + Geom::Point Vtemp[sz][sz]; + + /* Copy control points */ + std::copy(p.begin(), p.end(), Vtemp[0]); + + /* Triangle computation */ + for (unsigned i = 1; i < sz; i++) { + for (unsigned j = 0; j < sz - i; j++) { + Vtemp[i][j] = lerp(t, Vtemp[i-1][j], Vtemp[i-1][j+1]); + } + } + return Vtemp[sz-1][0]; +} + + /* * Test the bounding boxes of two OldBezier curves for interference. * Several observations: @@ -324,7 +349,7 @@ double Lmax(Point p) { } unsigned wangs_theorem(OldBezier a) { - return 12; // seems a good approximation! + return 6; // seems a good approximation! double la1 = Lmax( ( a.p[2] - a.p[1] ) - (a.p[1] - a.p[0]) ); double la2 = Lmax( ( a.p[3] - a.p[2] ) - (a.p[2] - a.p[1]) ); double l0 = std::max(la1, la2); @@ -337,6 +362,71 @@ unsigned wangs_theorem(OldBezier a) { return ra; } +struct rparams +{ + OldBezier &A; + OldBezier &B; +}; + +static int +intersect_polish_f (const gsl_vector * x, void *params, + gsl_vector * f) +{ + const double x0 = gsl_vector_get (x, 0); + const double x1 = gsl_vector_get (x, 1); + + Geom::Point dx = ((struct rparams *) params)->A(x0) - + ((struct rparams *) params)->B(x1); + + gsl_vector_set (f, 0, dx[0]); + gsl_vector_set (f, 1, dx[1]); + + return GSL_SUCCESS; +} + +static void intersect_polish_root (OldBezier &A, double &s, + OldBezier &B, double &t) { + const gsl_multiroot_fsolver_type *T; + gsl_multiroot_fsolver *sol; + + int status; + size_t iter = 0; + + const size_t n = 2; + struct rparams p = {A, B}; + gsl_multiroot_function f = {&intersect_polish_f, n, &p}; + + double x_init[2] = {s, t}; + gsl_vector *x = gsl_vector_alloc (n); + + gsl_vector_set (x, 0, x_init[0]); + gsl_vector_set (x, 1, x_init[1]); + + T = gsl_multiroot_fsolver_hybrids; + sol = gsl_multiroot_fsolver_alloc (T, 2); + gsl_multiroot_fsolver_set (sol, &f, x); + + do + { + iter++; + status = gsl_multiroot_fsolver_iterate (sol); + + if (status) /* check if solver is stuck */ + break; + + status = + gsl_multiroot_test_residual (sol->f, 1e-12); + } + while (status == GSL_CONTINUE && iter < 1000); + + s = gsl_vector_get (sol->x, 0); + t = gsl_vector_get (sol->x, 1); + + gsl_multiroot_fsolver_free (sol); + gsl_vector_free (x); +} + + std::vector > find_intersections( OldBezier a, OldBezier b) { std::vector > parameters; @@ -346,6 +436,9 @@ std::vector > find_intersections( OldBezier a, OldBezi b, 0., 1., wangs_theorem(b), parameters); } + for(unsigned i = 0; i < parameters.size(); i++) + intersect_polish_root(a, parameters[i].first, + b, parameters[i].second); std::sort(parameters.begin(), parameters.end()); return parameters; } diff --git a/src/2geom/choose.h b/src/2geom/choose.h index bfd66e8a9..141a23f37 100644 --- a/src/2geom/choose.h +++ b/src/2geom/choose.h @@ -30,6 +30,7 @@ #ifndef _CHOOSE_H #define _CHOOSE_H +#include // XXX: Can we keep only the left terms easily? // this would more than halve the array diff --git a/src/2geom/circle.cpp b/src/2geom/circle.cpp new file mode 100644 index 000000000..c3cea0ae7 --- /dev/null +++ b/src/2geom/circle.cpp @@ -0,0 +1,115 @@ +/* + * Circle Curve + * + * Authors: + * Marco Cecchetti + * + * Copyright 2008 authors + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + */ + + +#include <2geom/circle.h> +#include <2geom/ellipse.h> +#include <2geom/svg-elliptical-arc.h> +#include <2geom/numeric/fitting-tool.h> +#include <2geom/numeric/fitting-model.h> + + + +namespace Geom +{ + +void Circle::set(double A, double B, double C, double D) +{ + if (A == 0) + { + THROW_RANGEERROR("square term coefficient == 0"); + } + + //std::cerr << "B = " << B << " C = " << C << " D = " << D << std::endl; + + double b = B / A; + double c = C / A; + double d = D / A; + + m_centre[X] = -b/2; + m_centre[Y] = -c/2; + double r2 = m_centre[X] * m_centre[X] + m_centre[Y] * m_centre[Y] - d; + + if (r2 < 0) + { + THROW_RANGEERROR("ray^2 < 0"); + } + + m_ray = std::sqrt(r2); +} + + +void Circle::set(std::vector const& points) +{ + size_t sz = points.size(); + if (sz < 3) + { + THROW_RANGEERROR("fitting error: too few points passed"); + } + NL::LFMCircle model; + NL::least_squeares_fitter fitter(model, sz); + + for (size_t i = 0; i < sz; ++i) + { + fitter.append(points[i]); + } + fitter.update(); + + NL::Vector z(sz, 0.0); + model.instance(*this, fitter.result(z)); +} + + +SVGEllipticalArc +Circle::arc(Point const& initial, Point const& inner, Point const& final, + bool _svg_compliant) +{ + Ellipse e(center(X), center(Y), ray(), ray(), 0); + return e.arc(initial, inner, final, _svg_compliant); +} + + +} // end namespace Geom + + + + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/2geom/circle.h b/src/2geom/circle.h new file mode 100644 index 000000000..2f81e27bc --- /dev/null +++ b/src/2geom/circle.h @@ -0,0 +1,127 @@ +/* + * Circle Curve + * + * Authors: + * Marco Cecchetti + * + * Copyright 2008 authors + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + */ + + +#ifndef _2GEOM_CIRCLE_H_ +#define _2GEOM_CIRCLE_H_ + + +#include <2geom/point.h> +#include <2geom/exception.h> + + +namespace Geom +{ + +class SVGEllipticalArc; + +class Circle +{ + public: + Circle() + {} + + Circle(double cx, double cy, double r) + : m_centre(cx, cy), m_ray(r) + { + } + + Circle(double A, double B, double C, double D) + { + set(A, B, C, D); + } + + Circle(std::vector const& points) + { + set(points); + } + + void set(double cx, double cy, double r) + { + m_centre[X] = cx; + m_centre[Y] = cy; + m_ray = r; + } + + + // build a circle by its implicit equation: + // Ax^2 + Ay^2 + Bx + Cy + D = 0 + void set(double A, double B, double C, double D); + + // build up the best fitting circle wrt the passed points + // prerequisite: at least 3 points must be passed + void set(std::vector const& points); + + SVGEllipticalArc + arc(Point const& initial, Point const& inner, Point const& final, + bool _svg_compliant = true); + + Point center() const + { + return m_centre; + } + + Coord center(Dim2 d) const + { + return m_centre[d]; + } + + Coord ray() const + { + return m_ray; + } + + + private: + Point m_centre; + Coord m_ray; + Coord m_angle; +}; + + +} // end namespace Geom + + + +#endif // _2GEOM_CIRCLE_H_ + + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/2geom/coord.h b/src/2geom/coord.h index e9abfc927..b2c2a4766 100644 --- a/src/2geom/coord.h +++ b/src/2geom/coord.h @@ -45,6 +45,7 @@ namespace Geom { typedef double Coord; const Coord EPSILON = 1e-5; //1e-18; +const Coord COORD_HUGE = 1e18; //IMPL: NearConcept inline bool are_near(Coord a, Coord b, double eps=EPSILON) { return fabs(a-b) <= eps; } diff --git a/src/2geom/curve.h b/src/2geom/curve.h index 8eaf73fcf..6ab05b750 100644 --- a/src/2geom/curve.h +++ b/src/2geom/curve.h @@ -67,6 +67,8 @@ public: virtual Point initialPoint() const = 0; virtual Point finalPoint() const = 0; + /* isDegenerate returns true if the curve has "zero length". + * For a bezier curve this means for example that all handles are at the same point */ virtual bool isDegenerate() const = 0; virtual Curve *duplicate() const = 0; @@ -122,7 +124,12 @@ public: /* unitTangentAt returns the unit vector tangent to the curve at position t * (in the direction of increasing t). The method uses l'Hopital's rule when the derivative * is (0,0), parameter n determines the maximum nr of iterations (for when higher derivatives are also (0,0) ). - * Point(0,0) is returned if no non-zero derivative could be found. */ + * Point(0,0) is returned if no non-zero derivative could be found. + * Note that unitTangentAt(1) will probably not give the desired result. Probably one should do: + * Curve * c_reverse = c.reverse(); + * Point tangent = - c_reverse->unitTangentAt(0); + * delete c_reverse; + */ virtual Point unitTangentAt(Coord t, unsigned n = 3) const { for (unsigned deriv_n = 1; deriv_n <= n; deriv_n++) { diff --git a/src/2geom/curves.h b/src/2geom/curves.h index 3bf7d9b59..b0b16df3d 100644 --- a/src/2geom/curves.h +++ b/src/2geom/curves.h @@ -42,7 +42,7 @@ #include <2geom/sbasis-curve.h> #include <2geom/bezier-curve.h> #include <2geom/hvlinesegment.h> -#include <2geom/elliptical-arc.h> +//#include <2geom/elliptical-arc.h> #include <2geom/svg-elliptical-arc.h> diff --git a/src/2geom/ellipse.cpp b/src/2geom/ellipse.cpp index 20ac0bb2b..2690a091b 100644 --- a/src/2geom/ellipse.cpp +++ b/src/2geom/ellipse.cpp @@ -56,7 +56,7 @@ void Ellipse::set(double A, double B, double C, double D, double E, double F) double num = A * sqr(m_centre[X]) + B * m_centre[X] * m_centre[Y] + C * sqr(m_centre[Y]) - - A * F; + - F; //evaluate ellipse rotation angle @@ -120,6 +120,35 @@ void Ellipse::set(double A, double B, double C, double D, double E, double F) } +std::vector Ellipse::implicit_form_coefficients() const +{ + if (ray(X) == 0 || ray(Y) == 0) + { + THROW_LOGICALERROR("a degenerate ellipse doesn't own an implicit form"); + } + + std::vector coeff(6); + double cosrot = std::cos(rot_angle()); + double sinrot = std::sin(rot_angle()); + double cos2 = cosrot * cosrot; + double sin2 = sinrot * sinrot; + double cossin = cosrot * sinrot; + double invrx2 = 1 / (ray(X) * ray(X)); + double invry2 = 1 / (ray(Y) * ray(Y)); + + coeff[0] = invrx2 * cos2 + invry2 * sin2; + coeff[1] = 2 * (invrx2 - invry2) * cossin; + coeff[2] = invrx2 * sin2 + invry2 * cos2; + coeff[3] = -(2 * coeff[0] * center(X) + coeff[1] * center(Y)); + coeff[4] = -(2 * coeff[2] * center(Y) + coeff[1] * center(X)); + coeff[5] = coeff[0] * center(X) * center(X) + + coeff[1] * center(X) * center(Y) + + coeff[2] * center(Y) * center(Y) + - 1; + return coeff; +} + + void Ellipse::set(std::vector const& points) { size_t sz = points.size(); @@ -188,6 +217,52 @@ Ellipse::arc(Point const& initial, Point const& inner, Point const& final, return ea; } +Ellipse Ellipse::transformed(Matrix const& m) const +{ + double cosrot = std::cos(rot_angle()); + double sinrot = std::sin(rot_angle()); + Matrix A( ray(X) * cosrot, ray(X) * sinrot, + -ray(Y) * sinrot, ray(Y) * cosrot, + 0, 0 ); + Point new_center = center() * m; + Matrix M = m.without_translation(); + Matrix AM = A * M; + if ( are_near(AM.det(), 0) ) + { + double angle; + if (AM[0] != 0) + { + angle = std::atan2(AM[2], AM[0]); + } + else if (AM[1] != 0) + { + angle = std::atan2(AM[3], AM[1]); + } + else + { + angle = M_PI/2; + } + Point V(std::cos(angle), std::sin(angle)); + V *= AM; + double rx = L2(V); + angle = atan2(V); + return Ellipse(new_center[X], new_center[Y], rx, 0, angle); + } + + std::vector coeff = implicit_form_coefficients(); + Matrix Q( coeff[0], coeff[1]/2, + coeff[1]/2, coeff[2], + 0, 0 ); + + Matrix invm = M.inverse(); + Q = invm * Q ; + std::swap( invm[1], invm[2] ); + Q *= invm; + Ellipse e(Q[0], 2*Q[1], Q[3], 0, 0, -1); + e.m_centre = new_center; + + return e; +} } // end namespace Geom diff --git a/src/2geom/ellipse.h b/src/2geom/ellipse.h index a10f9ced0..1f0dfce63 100644 --- a/src/2geom/ellipse.h +++ b/src/2geom/ellipse.h @@ -37,7 +37,7 @@ #include <2geom/point.h> #include <2geom/exception.h> - +#include <2geom/matrix.h> namespace Geom { @@ -108,6 +108,10 @@ class Ellipse return m_angle; } + std::vector implicit_form_coefficients() const; + + Ellipse transformed(Matrix const& m) const; + private: Point m_centre, m_ray; double m_angle; diff --git a/src/2geom/forward.h b/src/2geom/forward.h index 52fd3525e..9bd5dedbe 100644 --- a/src/2geom/forward.h +++ b/src/2geom/forward.h @@ -43,6 +43,7 @@ typedef BezierCurve<2> QuadraticBezier; typedef BezierCurve<1> LineSegment; typedef BezierCurve<3> CubicBezier; class EllipticalArc; +class SVGEllipticalArc; class HLineSegment; class VLineSegment; diff --git a/src/2geom/interval.h b/src/2geom/interval.h index f042294ff..9887c044f 100644 --- a/src/2geom/interval.h +++ b/src/2geom/interval.h @@ -43,15 +43,21 @@ namespace Geom { -// +/* Although an Interval where _b[0] > _b[1] is considered empty, for proper functioning of other methods, + * a proper empty Interval is [+COORD_HUGE, -COORD_HUGE]. Then, expandTo(p) will set the interval to [p,p]. + */ class Interval { private: - Coord _b[2]; // this should always hold: _b[0] <= _b[1], otherwise the interval is empty. + Coord _b[2]; public: - //TODO: I just know this'll pop up somewhere, starting off someone's interval at 0... I can't see how to avoid this. - explicit Interval() { _b[0] = _b[1] = 0; } + // The default constructor creates an empty interval, that ranges from +COORD_HUGE to -COORD_HUGE. + // Doing an expandTo(p) on this empty interval will correctly set the whole interval to [p,p]. + explicit Interval() { _b[0] = +COORD_HUGE; _b[1] = -COORD_HUGE; } explicit Interval(Coord u) { _b[0] = _b[1] = u; } + /* When creating an Interval using the constructor specifying the exact range, the created interval + * will be [u,v] when u<=v ; and will be [v,u] when v < u !!! + */ Interval(Coord u, Coord v) { if(u < v) { _b[0] = u; _b[1] = v; @@ -71,7 +77,7 @@ public: inline Coord extent() const { return _b[1] - _b[0]; } inline Coord middle() const { return (_b[1] + _b[0]) * 0.5; } - inline bool isEmpty() const { return _b[0] >= _b[1]; } + inline bool isEmpty() const { return _b[0] > _b[1]; } inline bool contains(Coord val) const { return _b[0] <= val && val <= _b[1]; } bool contains(const Interval & val) const { return _b[0] <= val._b[0] && val._b[1] <= _b[1]; } bool intersects(const Interval & val) const { diff --git a/src/2geom/numeric/fitting-model.h b/src/2geom/numeric/fitting-model.h index cc3113372..de8f24760 100644 --- a/src/2geom/numeric/fitting-model.h +++ b/src/2geom/numeric/fitting-model.h @@ -41,6 +41,7 @@ #include <2geom/bezier-curve.h> #include <2geom/poly.h> #include <2geom/ellipse.h> +#include <2geom/circle.h> #include <2geom/utils.h> @@ -239,6 +240,41 @@ class LFMEllipse }; +// incomplete model, it can be inherited to make up different kinds of +// instance type; the raw data is a vector of coefficients of the equation +// of a circle curve +template< typename InstanceType > +class LFMCircleEquation + : public LinearFittingModelWithFixedTerms +{ + public: + void feed( VectorView & coeff, double & fixed_term, Point const& p ) const + { + coeff[0] = p[X]; + coeff[1] = p[Y]; + coeff[2] = 1; + fixed_term = p[X] * p[X] + p[Y] * p[Y]; + } + + size_t size() const + { + return 3; + } +}; + + +// this model generates Ellipse curves +class LFMCircle + : public LFMCircleEquation +{ + public: + void instance(Circle & c, ConstVectorView const& coeff) const + { + c.set(1, coeff[0], coeff[1], coeff[2]); + } +}; + + // this model generates SBasis objects class LFMSBasis : public LinearFittingModel diff --git a/src/2geom/path-intersection.cpp b/src/2geom/path-intersection.cpp index 635996e51..2612aa125 100644 --- a/src/2geom/path-intersection.cpp +++ b/src/2geom/path-intersection.cpp @@ -4,6 +4,8 @@ //for path_direction: #include <2geom/sbasis-geometric.h> +#include +#include namespace Geom { @@ -171,6 +173,88 @@ linear_intersect(Point A0, Point A1, Point B0, Point B1, } } + +typedef union dbl_64{ + long long i64; + double d64; +}; + +static double EpsilonOf(double value) +{ + dbl_64 s; + s.d64 = value; + if(s.i64 == 0) + { + s.i64++; + return s.d64 - value; + } + else if(s.i64-- < 0) + return s.d64 - value; + else + return value - s.d64; +} + +struct rparams { + Curve const &A; + Curve const &B; +}; + +static int +intersect_polish_f (const gsl_vector * x, void *params, + gsl_vector * f) +{ + const double x0 = gsl_vector_get (x, 0); + const double x1 = gsl_vector_get (x, 1); + + Geom::Point dx = ((struct rparams *) params)->A(x0) - + ((struct rparams *) params)->B(x1); + + gsl_vector_set (f, 0, dx[0]); + gsl_vector_set (f, 1, dx[1]); + + return GSL_SUCCESS; +} + +static void +intersect_polish_root (Curve const &A, double &s, + Curve const &B, double &t) { + int status; + size_t iter = 0; + + const size_t n = 2; + struct rparams p = {A, B}; + gsl_multiroot_function f = {&intersect_polish_f, n, &p}; + + double x_init[2] = {s, t}; + gsl_vector *x = gsl_vector_alloc (n); + + gsl_vector_set (x, 0, x_init[0]); + gsl_vector_set (x, 1, x_init[1]); + + const gsl_multiroot_fsolver_type *T = gsl_multiroot_fsolver_hybrids; + gsl_multiroot_fsolver *sol = gsl_multiroot_fsolver_alloc (T, 2); + gsl_multiroot_fsolver_set (sol, &f, x); + + do + { + iter++; + status = gsl_multiroot_fsolver_iterate (sol); + + if (status) /* check if solver is stuck */ + break; + + status = + gsl_multiroot_test_residual (sol->f, 1e-12); + } + while (status == GSL_CONTINUE && iter < 1000); + + s = gsl_vector_get (sol->x, 0); + t = gsl_vector_get (sol->x, 1); + + gsl_multiroot_fsolver_free (sol); + gsl_vector_free (x); +} + /* This uses the local bounds functions of curves to generically intersect two. * It passes in the curves, time intervals, and keeps track of depth, while * returning the results through the Crossings parameter. @@ -196,6 +280,8 @@ void pair_intersect(Curve const & A, double Al, double Ah, tA, tB, c)) { tA = tA * (Ah - Al) + Al; tB = tB * (Bh - Bl) + Bl; + intersect_polish_root(A, tA, + B, tB); if(depth % 2) ret.push_back(Crossing(tB, tA, c < 0)); else @@ -212,7 +298,6 @@ void pair_intersect(Curve const & A, double Al, double Ah, A, Al, Ah, ret, depth+1); } - // A simple wrapper around pair_intersect Crossings SimpleCrosser::crossings(Curve const &a, Curve const &b) { Crossings ret; diff --git a/src/2geom/path.cpp b/src/2geom/path.cpp index 2e5b789d5..d39b3ca92 100644 --- a/src/2geom/path.cpp +++ b/src/2geom/path.cpp @@ -36,18 +36,11 @@ #include <2geom/path.h> +using namespace Geom::PathInternal; namespace Geom { -void Path::swap(Path &other) { - std::swap(curves_, other.curves_); - std::swap(closed_, other.closed_); - std::swap(*final_, *other.final_); - curves_[curves_.size()-1] = final_; - other.curves_[other.curves_.size()-1] = other.final_; -} - Rect Path::boundsFast() const { Rect bounds; if (empty()) return bounds; @@ -74,33 +67,6 @@ Rect Path::boundsExact() const { return bounds; } -/* -Rect Path::boundsFast() -{ - Rect bound; - if (empty()) return bound; - - bound = begin()->boundsFast(); - for (iterator it = ++begin(); it != end(); ++it) - { - bound.unionWith(it->boundsFast()); - } - return bound; -} - -Rect Path::boundsExact() -{ - Rect bound; - if (empty()) return bound; - - bound = begin()->boundsExact(); - for (iterator it = ++begin(); it != end(); ++it) - { - bound.unionWith(it->boundsExact()); - } - return bound; - }*/ - template iter inc(iter const &x, unsigned n) { iter ret = x; @@ -109,6 +75,29 @@ iter inc(iter const &x, unsigned n) { return ret; } +Path &Path::operator*=(Matrix const &m) { + unshare(); + Sequence::iterator last = get_curves().end() - 1; + Sequence::iterator it; + Point prev; + for (it = get_curves().begin() ; it != last ; ++it) { + *it = boost::shared_ptr((*it)->transformed(m)); + if ( it != get_curves().begin() && (*it)->initialPoint() != prev ) { + THROW_CONTINUITYERROR(); + } + prev = (*it)->finalPoint(); + } + for ( int i = 0 ; i < 2 ; ++i ) { + final_->setPoint(i, (*final_)[i] * m); + } + if (get_curves().size() > 1) { + if ( front().initialPoint() != initialPoint() || back().finalPoint() != finalPoint() ) { + THROW_CONTINUITYERROR(); + } + } + return *this; +} + std::vector Path::allNearestPoints(Point const& _point, double from, double to) const { @@ -311,57 +300,57 @@ void Path::do_update(Sequence::iterator first_replaced, { // note: modifies the contents of [first,last) check_continuity(first_replaced, last_replaced, first, last); - delete_range(first_replaced, last_replaced); if ( ( last - first ) == ( last_replaced - first_replaced ) ) { std::copy(first, last, first_replaced); } else { // this approach depends on std::vector's behavior WRT iterator stability - curves_.erase(first_replaced, last_replaced); - curves_.insert(first_replaced, first, last); + get_curves().erase(first_replaced, last_replaced); + get_curves().insert(first_replaced, first, last); } - if ( curves_.front() != final_ ) { + if ( get_curves().front().get() != final_ ) { final_->setPoint(0, back().finalPoint()); final_->setPoint(1, front().initialPoint()); } } -void Path::do_append(Curve *curve) { - if ( curves_.front() == final_ ) { +void Path::do_append(Curve *c) { + boost::shared_ptr curve(c); + if ( get_curves().front().get() == final_ ) { final_->setPoint(1, curve->initialPoint()); } else { if (curve->initialPoint() != finalPoint()) { THROW_CONTINUITYERROR(); } } - curves_.insert(curves_.end()-1, curve); + get_curves().insert(get_curves().end()-1, curve); final_->setPoint(0, curve->finalPoint()); } -void Path::delete_range(Sequence::iterator first, Sequence::iterator last) { - for ( Sequence::iterator iter=first ; iter != last ; ++iter ) { - delete *iter; - } -} - void Path::stitch(Sequence::iterator first_replaced, Sequence::iterator last_replaced, Sequence &source) { if (!source.empty()) { - if ( first_replaced != curves_.begin() ) { + if ( first_replaced != get_curves().begin() ) { if ( (*first_replaced)->initialPoint() != source.front()->initialPoint() ) { - source.insert(source.begin(), new StitchSegment((*first_replaced)->initialPoint(), source.front()->initialPoint())); + Curve *stitch = new StitchSegment((*first_replaced)->initialPoint(), + source.front()->initialPoint()); + source.insert(source.begin(), boost::shared_ptr(stitch)); } } - if ( last_replaced != (curves_.end()-1) ) { + if ( last_replaced != (get_curves().end()-1) ) { if ( (*last_replaced)->finalPoint() != source.back()->finalPoint() ) { - source.insert(source.end(), new StitchSegment(source.back()->finalPoint(), (*last_replaced)->finalPoint())); + Curve *stitch = new StitchSegment(source.back()->finalPoint(), + (*last_replaced)->finalPoint()); + source.insert(source.end(), boost::shared_ptr(stitch)); } } - } else if ( first_replaced != last_replaced && first_replaced != curves_.begin() && last_replaced != curves_.end()-1) { + } else if ( first_replaced != last_replaced && first_replaced != get_curves().begin() && last_replaced != get_curves().end()-1) { if ( (*first_replaced)->initialPoint() != (*(last_replaced-1))->finalPoint() ) { - source.insert(source.begin(), new StitchSegment((*(last_replaced-1))->finalPoint(), (*first_replaced)->initialPoint())); + Curve *stitch = new StitchSegment((*(last_replaced-1))->finalPoint(), + (*first_replaced)->initialPoint()); + source.insert(source.begin(), boost::shared_ptr(stitch)); } } } @@ -372,17 +361,17 @@ void Path::check_continuity(Sequence::iterator first_replaced, Sequence::iterator last) { if ( first != last ) { - if ( first_replaced != curves_.begin() ) { + if ( first_replaced != get_curves().begin() ) { if ( (*first_replaced)->initialPoint() != (*first)->initialPoint() ) { THROW_CONTINUITYERROR(); } } - if ( last_replaced != (curves_.end()-1) ) { + if ( last_replaced != (get_curves().end()-1) ) { if ( (*(last_replaced-1))->finalPoint() != (*(last-1))->finalPoint() ) { THROW_CONTINUITYERROR(); } } - } else if ( first_replaced != last_replaced && first_replaced != curves_.begin() && last_replaced != curves_.end()-1) { + } else if ( first_replaced != last_replaced && first_replaced != get_curves().begin() && last_replaced != get_curves().end()-1) { if ( (*first_replaced)->initialPoint() != (*(last_replaced-1))->finalPoint() ) { THROW_CONTINUITYERROR(); } diff --git a/src/2geom/path.h b/src/2geom/path.h index 1e9aa1d42..f391c9c24 100644 --- a/src/2geom/path.h +++ b/src/2geom/path.h @@ -38,118 +38,100 @@ #define SEEN_GEOM_PATH_H +#include #include <2geom/curves.h> #include +#include namespace Geom { -// Conditional expression for types. If true, first, if false, second. -template - struct __conditional_type - { typedef _Iftrue __type; }; +class Path; -template - struct __conditional_type - { typedef _Iffalse __type; }; +namespace PathInternal { +typedef std::vector > Sequence; -template -class BaseIterator -: public std::iterator -{ -public: - BaseIterator() {} - - // default construct - // default copy - - // Allow Sequence::iterator to Sequence::const_iterator conversion - // unfortunately I do not know how to imitate the way __normal_iterator - // does it, because I don't see a way to get the typename of the container - // IteratorImpl is pointing at... - typedef std::vector Sequence; - BaseIterator ( typename __conditional_type< - (std::__are_same::__value), // check if this instantiation is of const_iterator type - const BaseIterator< Sequence::iterator >, // if true: accept iterator in const_iterator instantiation - const BaseIterator > ::__type // if false: default to standard copy constructor - & __other) - : impl_(__other.impl_) { } - friend class BaseIterator< Sequence::const_iterator >; - +template +class BaseIterator { +protected: + BaseIterator() : path(NULL), index(0) {} + BaseIterator(P *p, unsigned i) : path(p), index(i) {} + // default copy, default assign +public: bool operator==(BaseIterator const &other) { - return other.impl_ == impl_; + return path == other.path && index == other.index; } bool operator!=(BaseIterator const &other) { - return other.impl_ != impl_; + return path != other.path || index != other.index; } - Curve const &operator*() const { return **impl_; } - Curve const *operator->() const { return *impl_; } - - BaseIterator &operator++() { - ++impl_; - return *this; + Curve const &operator*() const { return (*path)[index]; } + Curve const *operator->() const { return &(*path)[index]; } + boost::shared_ptr get_ref() const { + return path->get_ref_at_index(index); } - BaseIterator operator++(int) { - BaseIterator old=*this; + C &operator++() { + ++index; + return static_cast(*this); + } + C operator++(int) { + C old(static_cast(*this)); ++(*this); return old; } - BaseIterator &operator--() { - --impl_; - return *this; + C &operator--() { + --index; + return static_cast(*this); } - - BaseIterator operator--(int) { - BaseIterator old=*this; + C operator--(int) { + C old(static_cast(*this)); --(*this); return old; } private: - BaseIterator(IteratorImpl const &pos) : impl_(pos) {} + P *path; + unsigned index; - IteratorImpl impl_; - friend class Path; + friend class ::Geom::Path; }; -template -class DuplicatingIterator -: public std::iterator -{ +class ConstIterator : public BaseIterator { public: - DuplicatingIterator() {} - DuplicatingIterator(Iterator const &iter) : impl_(iter) {} + typedef BaseIterator Base; - bool operator==(DuplicatingIterator const &other) { - return other.impl_ == impl_; - } - bool operator!=(DuplicatingIterator const &other) { - return other.impl_ != impl_; - } + ConstIterator() : Base() {} + // default copy, default assign - Curve *operator*() const { return (*impl_)->duplicate(); } +private: + ConstIterator(Path const &p, unsigned i) : Base(&p, i) {} + friend class ::Geom::Path; +}; - DuplicatingIterator &operator++() { - ++impl_; - return *this; - } - DuplicatingIterator operator++(int) { - DuplicatingIterator old=*this; - ++(*this); - return old; +class Iterator : public BaseIterator { +public: + typedef BaseIterator Base; + + Iterator() : Base() {} + // default copy, default assign + + operator ConstIterator const &() const { + return reinterpret_cast(*this); } private: - Iterator impl_; + Iterator(Path &p, unsigned i) : Base(&p, i) {} + friend class ::Geom::Path; }; +} + /* * Open and closed paths: all paths, whether open or closed, store a final * segment which connects the initial and final endpoints of the "real" @@ -159,19 +141,21 @@ private: * Conversely, the range [begin(), end_closed()) always contains the "extra" * closing segment. * - * The only difference between a closed and an open path is whether end() - * returns end_closed() or end_open(). The idea behind this is to let - * any path be stroked using [begin(), end_default()), and filled using - * [begin(), end_closed()), without requiring a separate "filled" version + * The only difference between a closed and an open path is whether + * end_default() returns end_closed() or end_open(). The idea behind this + * is to let any path be stroked using [begin(), end_default()), and filled + * using [begin(), end_closed()), without requiring a separate "filled" version * of the path to use for filling. + * + * \invariant : curves_ always contains at least one segment. The last segment + * is always of type ClosingSegment. All constructors take care of this. + (curves_.size() > 0) && dynamic_cast(curves_.back()) */ class Path { -private: - typedef std::vector Sequence; - public: - typedef BaseIterator iterator; - typedef BaseIterator const_iterator; + typedef PathInternal::Sequence Sequence; + typedef PathInternal::Iterator iterator; + typedef PathInternal::ConstIterator const_iterator; typedef Sequence::size_type size_type; typedef Sequence::difference_type difference_type; @@ -180,6 +164,7 @@ public: ClosingSegment() : LineSegment() {} ClosingSegment(Point const &p1, Point const &p2) : LineSegment(p1, p2) {} virtual Curve *duplicate() const { return new ClosingSegment(*this); } + virtual Curve *reverse() const { return new ClosingSegment((*this)[1], (*this)[0]); } }; enum Stitching { @@ -192,74 +177,77 @@ public: StitchSegment() : LineSegment() {} StitchSegment(Point const &p1, Point const &p2) : LineSegment(p1, p2) {} virtual Curve *duplicate() const { return new StitchSegment(*this); } + virtual Curve *reverse() const { return new StitchSegment((*this)[1], (*this)[0]); } }; - Path() - : final_(new ClosingSegment()), closed_(false) - { - curves_.push_back(final_); - } + // Path(Path const &other) - use default copy constructor - Path(Path const &other) - : final_(new ClosingSegment()), closed_(other.closed_) + explicit Path(Point p=Point()) + : curves_(boost::shared_ptr(new Sequence(1, boost::shared_ptr()))), + final_(new ClosingSegment(p, p)), + closed_(false) { - curves_.push_back(final_); - insert(begin(), other.begin(), other.end()); + get_curves().back() = boost::shared_ptr(final_); } - explicit Path(Point p) - : final_(new ClosingSegment(p, p)), closed_(false) + Path(const_iterator const &first, + const_iterator const &last, + bool closed=false) + : curves_(boost::shared_ptr(new Sequence(seq_iter(first), + seq_iter(last)))), + closed_(closed) { - curves_.push_back(final_); + if (!get_curves().empty()) { + final_ = new ClosingSegment(get_curves().back()->finalPoint(), + get_curves().front()->initialPoint()); + } else { + final_ = new ClosingSegment(); + } + get_curves().push_back(boost::shared_ptr(final_)); } - template - Path(BaseIterator first, BaseIterator last, bool closed=false) - : closed_(closed), final_(new ClosingSegment()) - { - curves_.push_back(final_); - insert(begin(), first, last); - } + virtual ~Path() {} + + // Path &operator=(Path const &other) - use default assignment operator - virtual ~Path() { - delete_range(curves_.begin(), curves_.end()-1); - delete final_; + void swap(Path &other) { + std::swap(other.curves_, curves_); + std::swap(other.final_, final_); + std::swap(other.closed_, closed_); } - Path &operator=(Path const &other) { - clear(); - insert(begin(), other.begin(), other.end()); - close(other.closed_); - return *this; + Curve const &operator[](unsigned i) const { return *get_curves()[i]; } + Curve const &at_index(unsigned i) const { return *get_curves()[i]; } + boost::shared_ptr get_ref_at_index(unsigned i) { + return get_curves()[i]; } - void swap(Path &other); - - Curve const &operator[](unsigned i) const { return *curves_[i]; } - - Curve const &front() const { return *curves_[0]; } - Curve const &back() const { return *curves_[curves_.size()-2]; } - Curve const &back_open() const { return *curves_[curves_.size()-2]; } - Curve const &back_closed() const { return *curves_[curves_.size()-1]; } + Curve const &front() const { return *get_curves()[0]; } + Curve const &back() const { return back_open(); } + Curve const &back_open() const { + if (empty()) { THROW_RANGEERROR("Path contains not enough segments"); } + return *get_curves()[get_curves().size()-2]; + } + Curve const &back_closed() const { return *get_curves()[get_curves().size()-1]; } Curve const &back_default() const { return ( closed_ ? back_closed() : back_open() ); } - const_iterator begin() const { return curves_.begin(); } - const_iterator end() const { return curves_.end()-1; } - iterator begin() { return curves_.begin(); } - iterator end() { return curves_.end()-1; } + const_iterator begin() const { return const_iterator(*this, 0); } + const_iterator end() const { return const_iterator(*this, size()); } + iterator begin() { return iterator(*this, 0); } + iterator end() { return iterator(*this, size()); } - const_iterator end_open() const { return curves_.end()-1; } - const_iterator end_closed() const { return curves_.end(); } + const_iterator end_open() const { return const_iterator(*this, size()); } + const_iterator end_closed() const { return const_iterator(*this, size()+1); } const_iterator end_default() const { return ( closed_ ? end_closed() : end_open() ); } - size_type size() const { return curves_.size()-1; } - size_type max_size() const { return curves_.max_size()-1; } + size_type size() const { return get_curves().size()-1; } + size_type max_size() const { return get_curves().max_size()-1; } - bool empty() const { return curves_.size() == 1; } + bool empty() const { return get_curves().size() == 1; } bool closed() const { return closed_; } void close(bool closed=true) { closed_ = closed; } @@ -286,66 +274,22 @@ public: return ret; } - bool operator==(Path const &m) const { - if (size() != m.size() || closed() != m.closed()) - return false; - const_iterator it2 = m.curves_.begin(); - for(const_iterator it = curves_.begin(); it != curves_.end(); ++it) { - const Curve& a = (*it); - const Curve& b = (*it2); - if(!(a == b)) - return false; - ++it2; - } - return true; - } - - /* - Path operator*=(Matrix) - This is not possible without at least partly regenerating the curves of - the path, because a path can consist of many types of curves, - e.g. a HLineSegment. - Such a segment cannot be transformed and stay a HLineSegment in general - (take for example rotations). - This means that these curves of the path have to be replaced with - LineSegments: new Curves. - So an implementation of this method should check the curve's type to see - whether operator*= is doable for that curve type, ... - */ + bool operator==(Path const &other) const { + if (this == &other) return true; + if (closed_ != other.closed_) return false; + return get_curves() == other.get_curves(); + } + bool operator!=(Path const &other) const { + return !( *this == other ); + } + Path operator*(Matrix const &m) const { - Path ret; - ret.curves_.reserve(curves_.size()); - for(const_iterator it = begin(); it != end(); ++it) { - Curve *curve = it->transformed(m); - ret.do_append(curve); - } - ret.close(closed_); + Path ret(*this); + ret *= m; return ret; } - /* - // this should be even quickier but it works at low level - Path operator*(Matrix const &m) const - { - Path result; - size_t sz = curves_.size() - 1; - if (sz == 0) return result; - result.curves_.resize(curves_.size()); - result.curves_.back() = result.final_; - result.curves_[0] = (curves_[0])->transformed(m); - for (size_t i = 1; i < sz; ++i) - { - result.curves_[i] = (curves_[i])->transformed(m); - if ( result.curves_[i]->initialPoint() != result.curves_[i-1]->finalPoint() ) { - THROW_CONTINUITYERROR(); - } - } - result.final_->setInitial( (result.curves_[sz])->finalPoint() ); - result.final_->setFinal( (result.curves_[0])->initialPoint() ); - result.closed_ = closed_; - return result; - } - */ + Path &operator*=(Matrix const &m); Point pointAt(double t) const { @@ -433,137 +377,130 @@ public: Path portion(Interval i) const { return portion(i.min(), i.max()); } Path reverse() const { - Path ret; - ret.close(closed_); - for(int i = size() - (closed_ ? 0 : 1); i >= 0; i--) { - Curve *temp = (*this)[i].reverse(); - ret.append(*temp); - // delete since append makes a copy - delete temp; + Path ret(*this); + ret.unshare(); + for ( Sequence::iterator iter = ret.get_curves().begin() ; + iter != ret.get_curves().end()-1 ; ++iter ) + { + *iter = boost::shared_ptr((*iter)->reverse()); } + std::reverse(ret.get_curves().begin(), ret.get_curves().end()-1); + ret.final_ = static_cast(ret.final_->reverse()); + ret.get_curves().back() = boost::shared_ptr(ret.final_); return ret; } - void insert(iterator pos, Curve const &curve, Stitching stitching=NO_STITCHING) { - Sequence source(1, curve.duplicate()); - try { - if (stitching) stitch(pos.impl_, pos.impl_, source); - do_update(pos.impl_, pos.impl_, source.begin(), source.end()); - } catch (...) { - delete_range(source.begin(), source.end()); - throw; - } + void insert(iterator const &pos, + Curve const &curve, Stitching stitching=NO_STITCHING) + { + unshare(); + Sequence::iterator seq_pos(seq_iter(pos)); + Sequence source(1, boost::shared_ptr(curve.duplicate())); + if (stitching) stitch(seq_pos, seq_pos, source); + do_update(seq_pos, seq_pos, source.begin(), source.end()); } - template - void insert(iterator pos, BaseIterator first, BaseIterator last, Stitching stitching=NO_STITCHING) + void insert(iterator const &pos, + const_iterator const &first, + const_iterator const &last, + Stitching stitching=NO_STITCHING) { - Sequence source(DuplicatingIterator(first.impl_), - DuplicatingIterator(last.impl_)); - try { - if (stitching) stitch(pos.impl_, pos.impl_, source); - do_update(pos.impl_, pos.impl_, source.begin(), source.end()); - } catch (...) { - delete_range(source.begin(), source.end()); - throw; - } + unshare(); + Sequence::iterator seq_pos(seq_iter(pos)); + Sequence source(seq_iter(first), seq_iter(last)); + if (stitching) stitch(seq_pos, seq_pos, source); + do_update(seq_pos, seq_pos, source.begin(), source.end()); } void clear() { - do_update(curves_.begin(), curves_.end()-1, - curves_.begin(), curves_.begin()); + unshare(); + do_update(get_curves().begin(), get_curves().end()-1, + get_curves().begin(), get_curves().begin()); } - void erase(iterator pos, Stitching stitching=NO_STITCHING) { + void erase(iterator const &pos, Stitching stitching=NO_STITCHING) { + unshare(); + Sequence::iterator seq_pos(seq_iter(pos)); if (stitching) { Sequence stitched; - stitch(pos.impl_, pos.impl_+1, stitched); - try { - do_update(pos.impl_, pos.impl_+1, stitched.begin(), stitched.end()); - } catch (...) { - delete_range(stitched.begin(), stitched.end()); - throw; - } + stitch(seq_pos, seq_pos+1, stitched); + do_update(seq_pos, seq_pos+1, stitched.begin(), stitched.end()); } else { - do_update(pos.impl_, pos.impl_+1, curves_.begin(), curves_.begin()); + do_update(seq_pos, seq_pos+1, get_curves().begin(), get_curves().begin()); } } - void erase(iterator first, iterator last, Stitching stitching=NO_STITCHING) { + void erase(iterator const &first, + iterator const &last, + Stitching stitching=NO_STITCHING) + { + unshare(); + Sequence::iterator seq_first=seq_iter(first); + Sequence::iterator seq_last=seq_iter(last); if (stitching) { Sequence stitched; - stitch(first.impl_, last.impl_, stitched); - try { - do_update(first.impl_, last.impl_, stitched.begin(), stitched.end()); - } catch (...) { - delete_range(stitched.begin(), stitched.end()); - throw; - } + stitch(seq_first, seq_last, stitched); + do_update(seq_first, seq_last, stitched.begin(), stitched.end()); } else { - do_update(first.impl_, last.impl_, curves_.begin(), curves_.begin()); + do_update(seq_first, seq_last, + get_curves().begin(), get_curves().begin()); } } // erase last segment of path void erase_last() { - erase(curves_.end()-2); + erase(iterator(*this, size()-1)); } - void replace(iterator replaced, Curve const &curve, Stitching stitching=NO_STITCHING) { - Sequence source(1, curve.duplicate()); - try { - if (stitching) stitch(replaced.impl_, replaced.impl_+1, source); - do_update(replaced.impl_, replaced.impl_+1, source.begin(), source.end()); - } catch (...) { - delete_range(source.begin(), source.end()); - throw; - } + void replace(iterator const &replaced, + Curve const &curve, + Stitching stitching=NO_STITCHING) + { + unshare(); + Sequence::iterator seq_replaced(seq_iter(replaced)); + Sequence source(1, boost::shared_ptr(curve.duplicate())); + if (stitching) stitch(seq_replaced, seq_replaced+1, source); + do_update(seq_replaced, seq_replaced+1, source.begin(), source.end()); } - void replace(iterator first_replaced, iterator last_replaced, + void replace(iterator const &first_replaced, + iterator const &last_replaced, Curve const &curve, Stitching stitching=NO_STITCHING) { - Sequence source(1, curve.duplicate()); - try { - if (stitching) stitch(first_replaced.impl_, last_replaced.impl_, source); - do_update(first_replaced.impl_, last_replaced.impl_, - source.begin(), source.end()); - } catch (...) { - delete_range(source.begin(), source.end()); - throw; - } - } - - template - void replace(iterator replaced, - BaseIterator first, BaseIterator last, + unshare(); + Sequence::iterator seq_first_replaced(seq_iter(first_replaced)); + Sequence::iterator seq_last_replaced(seq_iter(last_replaced)); + Sequence source(1, boost::shared_ptr(curve.duplicate())); + if (stitching) stitch(seq_first_replaced, seq_last_replaced, source); + do_update(seq_first_replaced, seq_last_replaced, + source.begin(), source.end()); + } + + void replace(iterator const &replaced, + const_iterator const &first, + const_iterator const &last, Stitching stitching=NO_STITCHING) { - Sequence source(DuplicatingIterator(first.impl_), - DuplicatingIterator(last.impl_)); - try { - if (stitching) stitch(replaced.impl_, replaced.impl_+1, source); - do_update(replaced.impl_, replaced.impl_+1, source.begin(), source.end()); - } catch (...) { - delete_range(source.begin(), source.end()); - throw; - } + unshare(); + Sequence::iterator seq_replaced(seq_iter(replaced)); + Sequence source(seq_iter(first), seq_iter(last)); + if (stitching) stitch(seq_replaced, seq_replaced+1, source); + do_update(seq_replaced, seq_replaced+1, source.begin(), source.end()); } - template - void replace(iterator first_replaced, iterator last_replaced, - BaseIterator first, BaseIterator last, + void replace(iterator const &first_replaced, + iterator const &last_replaced, + const_iterator const &first, + const_iterator const &last, Stitching stitching=NO_STITCHING) { - Sequence source(first.impl_, last.impl_); - try { - if (stitching) stitch(first_replaced.impl_, last_replaced.impl_, source); - do_update(first_replaced.impl_, last_replaced.impl_, - source.begin(), source.end()); - } catch (...) { - delete_range(source.begin(), source.end()); - throw; - } + unshare(); + Sequence::iterator seq_first_replaced(seq_iter(first_replaced)); + Sequence::iterator seq_last_replaced(seq_iter(last_replaced)); + Sequence source(seq_iter(first), seq_iter(last)); + if (stitching) stitch(seq_first_replaced, seq_last_replaced, source); + do_update(seq_first_replaced, seq_last_replaced, + source.begin(), source.end()); } void start(Point p) { @@ -578,44 +515,32 @@ public: void setInitial(Point const& p) { if ( empty() ) return; - Curve* head = front().duplicate(); + unshare(); + boost::shared_ptr head(front().duplicate()); head->setInitial(p); - Sequence::iterator replaced = curves_.begin(); + Sequence::iterator replaced = get_curves().begin(); Sequence source(1, head); - try - { - do_update(replaced, replaced + 1, source.begin(), source.end()); - } - catch (...) - { - delete_range(source.begin(), source.end()); - throw; - } + do_update(replaced, replaced + 1, source.begin(), source.end()); } void setFinal(Point const& p) { if ( empty() ) return; - Curve* tail = back().duplicate(); + unshare(); + boost::shared_ptr tail(back().duplicate()); tail->setFinal(p); - Sequence::iterator replaced = curves_.end() - 2; + Sequence::iterator replaced = get_curves().end() - 2; Sequence source(1, tail); - try - { - do_update(replaced, replaced + 1, source.begin(), source.end()); - } - catch (...) - { - delete_range(source.begin(), source.end()); - throw; - } + do_update(replaced, replaced + 1, source.begin(), source.end()); } void append(Curve const &curve, Stitching stitching=NO_STITCHING) { + unshare(); if (stitching) stitchTo(curve.initialPoint()); do_append(curve.duplicate()); } void append(D2 const &curve, Stitching stitching=NO_STITCHING) { + unshare(); if (stitching) stitchTo(Point(curve[X][0][0], curve[Y][0][0])); do_append(new SBasisCurve(curve)); } @@ -625,40 +550,47 @@ public: void stitchTo(Point const &p) { if (!empty() && finalPoint() != p) { + unshare(); do_append(new StitchSegment(finalPoint(), p)); } } template void appendNew(A a) { + unshare(); do_append(new CurveType(finalPoint(), a)); } template void appendNew(A a, B b) { + unshare(); do_append(new CurveType(finalPoint(), a, b)); } template void appendNew(A a, B b, C c) { + unshare(); do_append(new CurveType(finalPoint(), a, b, c)); } template void appendNew(A a, B b, C c, D d) { + unshare(); do_append(new CurveType(finalPoint(), a, b, c, d)); } template void appendNew(A a, B b, C c, D d, E e) { + unshare(); do_append(new CurveType(finalPoint(), a, b, c, d, e)); } template void appendNew(A a, B b, C c, D d, E e, F f) { + unshare(); do_append(new CurveType(finalPoint(), a, b, c, d, e, f)); } @@ -666,6 +598,7 @@ public: typename D, typename E, typename F, typename G> void appendNew(A a, B b, C c, D d, E e, F f, G g) { + unshare(); do_append(new CurveType(finalPoint(), a, b, c, d, e, f, g)); } @@ -673,6 +606,7 @@ public: typename D, typename E, typename F, typename G, typename H> void appendNew(A a, B b, C c, D d, E e, F f, G g, H h) { + unshare(); do_append(new CurveType(finalPoint(), a, b, c, d, e, f, g, h)); } @@ -680,10 +614,31 @@ public: typename D, typename E, typename F, typename G, typename H, typename I> void appendNew(A a, B b, C c, D d, E e, F f, G g, H h, I i) { + unshare(); do_append(new CurveType(finalPoint(), a, b, c, d, e, f, g, h, i)); } private: + static Sequence::iterator seq_iter(iterator const &iter) { + return iter.path->get_curves().begin() + iter.index; + } + static Sequence::const_iterator seq_iter(const_iterator const &iter) { + return iter.path->get_curves().begin() + iter.index; + } + + Sequence &get_curves() { return *curves_; } + Sequence const &get_curves() const { return *curves_; } + + void unshare() { + if (!curves_.unique()) { + curves_ = boost::shared_ptr(new Sequence(*curves_)); + } + if (!get_curves().back().unique()) { + final_ = static_cast(final_->duplicate()); + get_curves().back() = boost::shared_ptr(final_); + } + } + void stitch(Sequence::iterator first_replaced, Sequence::iterator last_replaced, Sequence &sequence); @@ -693,19 +648,17 @@ private: Sequence::iterator first, Sequence::iterator last); + // n.b. takes ownership of curve object void do_append(Curve *curve); - static void delete_range(Sequence::iterator first, Sequence::iterator last); - void check_continuity(Sequence::iterator first_replaced, Sequence::iterator last_replaced, Sequence::iterator first, Sequence::iterator last); - Sequence curves_; + boost::shared_ptr curves_; ClosingSegment *final_; bool closed_; - }; // end class Path inline static Piecewise > paths_to_pw(std::vector paths) { @@ -734,7 +687,6 @@ inline void swap(Geom::Path &a, Geom::Path &b) } // end namespace std - #endif // SEEN_GEOM_PATH_H diff --git a/src/2geom/pathvector.cpp b/src/2geom/pathvector.cpp index 9befc1f17..1e0a20003 100644 --- a/src/2geom/pathvector.cpp +++ b/src/2geom/pathvector.cpp @@ -44,15 +44,6 @@ namespace Geom { // TODO: see which of these functions can be inlined for optimization -PathVector operator* (PathVector const & path_in, Matrix const &m) -{ - PathVector path_out; - for(PathVector::const_iterator it = path_in.begin(); it != path_in.end(); ++it) { - path_out.push_back( (*it) * m ); - } - return path_out; -} - /** * Reverses all Paths and the order of paths in the vector as well **/ @@ -65,6 +56,7 @@ PathVector reverse_paths_and_order (PathVector const & path_in) return path_out; } +// FIXME: this function does not work for empty paths, because Rect cannot be initialized empty yet. check rect.h Rect bounds_fast( PathVector const& pv ) { typedef PathVector::const_iterator const_iterator; @@ -80,6 +72,7 @@ Rect bounds_fast( PathVector const& pv ) return bound; } +// FIXME: this function does not work for empty paths, because Rect cannot be initialized empty yet. check rect.h Rect bounds_exact( PathVector const& pv ) { typedef PathVector::const_iterator const_iterator; diff --git a/src/2geom/pathvector.h b/src/2geom/pathvector.h index 17f6b6212..14d1efdfa 100644 --- a/src/2geom/pathvector.h +++ b/src/2geom/pathvector.h @@ -38,13 +38,55 @@ #include <2geom/forward.h> #include <2geom/path.h> #include <2geom/rect.h> +#include <2geom/transforms.h> namespace Geom { typedef std::vector PathVector; +/* general path transformation: */ +inline +void operator*= (PathVector & path_in, Matrix const &m) { + for(PathVector::iterator it = path_in.begin(); it != path_in.end(); ++it) { + (*it) *= m; + } +} +inline +PathVector operator*(PathVector const & path_in, Matrix const &m) { + PathVector ret(path_in); + ret *= m; + return ret; +} + +/* specific path transformations: Translation: + * This makes it possible to make optimized implementations for Translate transforms */ +inline +void operator*= (PathVector & path_in, Translate const &m) { + for(PathVector::iterator it = path_in.begin(); it != path_in.end(); ++it) { + (*it) *= m; + } +} +inline +PathVector operator*(PathVector const & path_in, Translate const &m) { + PathVector ret(path_in); + ret *= m; + return ret; +} + +/* user friendly approach to Translate transforms: just add an offset Point to the whole path */ +inline +void operator+=(PathVector &path_in, Point const &p) { + for(PathVector::iterator it = path_in.begin(); it != path_in.end(); ++it) { + (*it) *= Translate(p); + } +} +inline +PathVector operator+(PathVector const &path_in, Point const &p) { + PathVector ret(path_in); + ret *= Translate(p); + return ret; +} -PathVector operator* (PathVector const & path_in, Matrix const &m); PathVector reverse_paths_and_order (PathVector const & path_in); diff --git a/src/2geom/poly-dk-solve.cpp b/src/2geom/poly-dk-solve.cpp index 2787c4478..a328b316c 100644 --- a/src/2geom/poly-dk-solve.cpp +++ b/src/2geom/poly-dk-solve.cpp @@ -3,6 +3,8 @@ /*** implementation of the Durand-Kerner method. seems buggy*/ +namespace Geom { + std::complex evalu(Poly const & p, std::complex x) { std::complex result = 0; std::complex xx = 1; @@ -51,6 +53,7 @@ std::vector > DK(Poly const & ply, const double tol) { return roots; } +} // namespace Geom /* Local Variables: diff --git a/src/2geom/poly-dk-solve.h b/src/2geom/poly-dk-solve.h index dadd12110..463f854c1 100644 --- a/src/2geom/poly-dk-solve.h +++ b/src/2geom/poly-dk-solve.h @@ -1,9 +1,18 @@ +#ifndef LIB2GEOM_SEEN_POLY_DK_SOLVE_H +#define LIB2GEOM_SEEN_POLY_DK_SOLVE_H + #include <2geom/poly.h> #include +namespace Geom { + std::vector > DK(Poly const & ply, const double tol=1e-10); +} // namespace Geom + +#endif // LIB2GEOM_SEEN_POLY_DK_SOLVE_H + /* Local Variables: mode:c++ diff --git a/src/2geom/poly-laguerre-solve.cpp b/src/2geom/poly-laguerre-solve.cpp index bd2ddf305..5b59690b7 100644 --- a/src/2geom/poly-laguerre-solve.cpp +++ b/src/2geom/poly-laguerre-solve.cpp @@ -1,6 +1,9 @@ #include <2geom/poly-laguerre-solve.h> #include + +namespace Geom { + typedef std::complex cdouble; cdouble laguerre_internal_complex(Poly const & p, @@ -140,6 +143,8 @@ laguerre_real_interval(Poly const & /*ply*/, return result; } +} // namespace Geom + /* Local Variables: mode:c++ diff --git a/src/2geom/poly-laguerre-solve.h b/src/2geom/poly-laguerre-solve.h index 6f7cb0aee..6836aa49d 100644 --- a/src/2geom/poly-laguerre-solve.h +++ b/src/2geom/poly-laguerre-solve.h @@ -1,6 +1,11 @@ +#ifndef LIB2GEOM_SEEN_POLY_LAGUERRE_SOLVE_H +#define LIB2GEOM_SEEN_POLY_LAGUERRE_SOLVE_H + #include <2geom/poly.h> #include +namespace Geom { + std::vector > laguerre(Poly ply, const double tol=1e-10); @@ -9,6 +14,10 @@ laguerre_real_interval(Poly ply, const double lo, const double hi, const double tol=1e-10); +} // namespace Geom + +#endif // LIB2GEOM_SEEN_POLY_LAGUERRE_SOLVE_H + /* Local Variables: mode:c++ diff --git a/src/2geom/poly.cpp b/src/2geom/poly.cpp index 1b9b0e568..d8b379557 100644 --- a/src/2geom/poly.cpp +++ b/src/2geom/poly.cpp @@ -1,5 +1,12 @@ #include <2geom/poly.h> +#define HAVE_GSL +#ifdef HAVE_GSL +#include +#endif + +namespace Geom { + Poly Poly::operator*(const Poly& p) const { Poly result; result.resize(degree() + p.degree()+1); @@ -11,10 +18,6 @@ Poly Poly::operator*(const Poly& p) const { } return result; } -#define HAVE_GSL -#ifdef HAVE_GSL -#include -#endif /*double Poly::eval(double x) const { return gsl_poly_eval(&coeff[0], size(), x); @@ -151,6 +154,7 @@ Poly divide(Poly const &a, Poly const &b, Poly &r) { c.resize(k, 0.); for(unsigned i = k; i >= l; i--) { + //assert(i >= 0); double ci = r.back()/b.back(); c[i-l] += ci; Poly bb = ci*b; @@ -184,6 +188,7 @@ Poly gcd(Poly const &a, Poly const &b, const double /*tol*/) { assert(1); }*/ +} //namespace Geom /* Local Variables: diff --git a/src/2geom/poly.h b/src/2geom/poly.h index 2d7b79bfe..152626698 100644 --- a/src/2geom/poly.h +++ b/src/2geom/poly.h @@ -1,5 +1,5 @@ -#ifndef SEEN_POLY_H -#define SEEN_POLY_H +#ifndef LIB2GEOM_SEEN_POLY_H +#define LIB2GEOM_SEEN_POLY_H #include #include #include @@ -7,22 +7,24 @@ #include #include <2geom/utils.h> +namespace Geom { + class Poly : public std::vector{ public: // coeff; // sum x^i*coeff[i] - + //unsigned size() const { return coeff.size();} unsigned degree() const { return size()-1;} //double operator[](const int i) const { return (*this)[i];} //double& operator[](const int i) { return (*this)[i];} - + Poly operator+(const Poly& p) const { Poly result; const unsigned out_size = std::max(size(), p.size()); const unsigned min_size = std::min(size(), p.size()); //result.reserve(out_size); - + for(unsigned i = 0; i < min_size; i++) { result.push_back((*this)[i] + p[i]); } @@ -38,7 +40,7 @@ public: const unsigned out_size = std::max(size(), p.size()); const unsigned min_size = std::min(size(), p.size()); result.reserve(out_size); - + for(unsigned i = 0; i < min_size; i++) { result.push_back((*this)[i] - p[i]); } @@ -53,7 +55,7 @@ public: const unsigned out_size = std::max(size(), p.size()); const unsigned min_size = std::min(size(), p.size()); resize(out_size); - + for(unsigned i = 0; i < min_size; i++) { (*this)[i] -= p[i]; } @@ -65,7 +67,7 @@ public: Poly result; const unsigned out_size = size(); result.reserve(out_size); - + for(unsigned i = 0; i < out_size; i++) { result.push_back((*this)[i]); } @@ -75,7 +77,7 @@ public: Poly operator-() const { Poly result; result.resize(size()); - + for(unsigned i = 0; i < size(); i++) { result[i] = -(*this)[i]; } @@ -85,29 +87,27 @@ public: Poly result; const unsigned out_size = size(); result.reserve(out_size); - + for(unsigned i = 0; i < out_size; i++) { result.push_back((*this)[i]*p); } assert(result.size() == out_size); return result; } - - /** Equivalent to multiply by x^terms. */ + // equivalent to multiply by x^terms, negative terms are disallowed Poly shifted(unsigned const terms) const { Poly result; size_type const out_size = size() + terms; result.reserve(out_size); - result.resize(terms, 0.0); - result.insert(result.end(), this->begin(), this->end()); + result.resize(terms, 0.0); + result.insert(result.end(), this->begin(), this->end()); assert(result.size() == out_size); return result; } - Poly operator*(const Poly& p) const; - + template T eval(T x) const { T r = 0; @@ -116,17 +116,17 @@ public: } return r; } - + template T operator()(T t) const { return (T)eval(t);} - + void normalize(); - + void monicify(); Poly() {} Poly(const Poly& p) : std::vector(p) {} Poly(const double a) {push_back(a);} - + public: template void val_and_deriv(T x, U &pd) const { @@ -147,7 +147,7 @@ public: pd[i] *= cnst; } } - + static Poly linear(double ax, double b) { Poly p; p.push_back(b); @@ -191,12 +191,15 @@ inline std::ostream &operator<< (std::ostream &out_file, const Poly &in_poly) { out_file << " + "; } else out_file << in_poly[i]; - + } } return out_file; } +} // namespace Geom + +#endif //LIB2GEOM_SEEN_POLY_H /* Local Variables: @@ -208,4 +211,3 @@ inline std::ostream &operator<< (std::ostream &out_file, const Poly &in_poly) { End: */ // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : -#endif diff --git a/src/2geom/rect.h b/src/2geom/rect.h index 27a475cf3..a136e91a8 100644 --- a/src/2geom/rect.h +++ b/src/2geom/rect.h @@ -55,6 +55,10 @@ class D2 { private: Interval f[2]; public: + /* The default constructor creates a rect that contains the point (0,0). Isn't it better to have it be empty? + * i.e. f[X] = f[Y] = Interval(); . Don't use Interval(+COORD_HUGE, -COORD_HUGE) !! because the arguments + * will be interchanged to Interval(-COORD_HUGE, +COORD_HUGE)!! + */ D2() { f[X] = f[Y] = Interval(0, 0); } D2(Interval const &a, Interval const &b) { diff --git a/src/2geom/sbasis-roots.cpp b/src/2geom/sbasis-roots.cpp index 30f5fb22f..861baf76d 100644 --- a/src/2geom/sbasis-roots.cpp +++ b/src/2geom/sbasis-roots.cpp @@ -62,8 +62,10 @@ Interval bounds_exact(SBasis const &a) { return result; } +// I have no idea how this works, some clever bounding argument by jfb. Interval bounds_fast(const SBasis &sb, int order) { - Interval res; + Interval res(0,0); // an empty sbasis is 0. + for(int j = sb.size()-1; j>=order; j--) { double a=sb[j][0]; double b=sb[j][1]; diff --git a/src/2geom/shape.cpp b/src/2geom/shape.cpp index 936dfaf70..814c6c68c 100644 --- a/src/2geom/shape.cpp +++ b/src/2geom/shape.cpp @@ -432,7 +432,7 @@ std::vector inner_sanitize(std::vector const & ps) { std::cout << "r" << ix << "[" << from.getTime(ix) << ", " << to.getTime(ix) << "]\n"; Path p = ps[ix].portion(from.getTime(ix), to.getTime(ix)).reverse(); for(unsigned i = 0; i < p.size(); i++) - res.append(p[i]); + res.append(p[i], Path::STITCH_DISCONTINUOUS); } else { // forwards std::cout << "f" << ix << "[" << from.getTime(ix) << ", " << to.getTime(ix) << "]\n"; diff --git a/src/2geom/svg-elliptical-arc.cpp b/src/2geom/svg-elliptical-arc.cpp index 047ae1431..cdf60bc9f 100644 --- a/src/2geom/svg-elliptical-arc.cpp +++ b/src/2geom/svg-elliptical-arc.cpp @@ -915,10 +915,32 @@ D2 SVGEllipticalArc::toSBasis() const SBasis arc_y = ray(Y) * sin(param,4); arc[0] = arc_x * cos_rot_angle - arc_y * sin_rot_angle + Linear(center(X),center(X)); arc[1] = arc_x * sin_rot_angle + arc_y * cos_rot_angle + Linear(center(Y),center(Y)); + + // ensure that endpoints remain exact + for ( int d = 0 ; d < 2 ; d++ ) { + arc[d][0][0] = initialPoint()[d]; + arc[d][0][1] = finalPoint()[d]; + } + return arc; } +Curve* SVGEllipticalArc::transformed(Matrix const& m) const +{ + // return SBasisCurve(toSBasis()).transformed(m); + + Ellipse e(center(X), center(Y), ray(X), ray(Y), rotation_angle()); + Ellipse et = e.transformed(m); + Point inner_point = pointAt(0.5); + SVGEllipticalArc ea = et.arc( initialPoint() * m, + inner_point * m, + finalPoint() * m, + is_svg_compliant() ); + return ea.duplicate(); +} + + Coord SVGEllipticalArc::map_to_02PI(Coord t) const { if ( sweep_flag() ) diff --git a/src/2geom/svg-elliptical-arc.h b/src/2geom/svg-elliptical-arc.h index f129e5a65..7d5087c48 100644 --- a/src/2geom/svg-elliptical-arc.h +++ b/src/2geom/svg-elliptical-arc.h @@ -219,11 +219,7 @@ class SVGEllipticalArc : public Curve Curve *derivative() const; - // TODO: native implementation of the following methods - Curve *transformed(Matrix const &m) const - { - return SBasisCurve(toSBasis()).transformed(m); - } + Curve *transformed(Matrix const &m) const; std::vector pointAndDerivatives(Coord t, unsigned int n) const; @@ -388,14 +384,9 @@ class make_elliptical_arc return svg_compliant; } - void svg_compliant_on() - { - svg_compliant = true; - } - - void svg_compliant_off() + void svg_compliant_flag(bool _svg_compliant) { - svg_compliant = false; + svg_compliant = _svg_compliant; } private: diff --git a/src/2geom/svg-path-parser.cpp b/src/2geom/svg-path-parser.cpp index 2a0ee9b1f..bb452ec33 100644 --- a/src/2geom/svg-path-parser.cpp +++ b/src/2geom/svg-path-parser.cpp @@ -1,4 +1,4 @@ -#line 1 "/home/mental/trees/lib2geom/src/2geom/svg-path-parser.rl" +#line 1 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" /* * parse SVG path specifications * @@ -138,7 +138,7 @@ private: }; -#line 142 "/home/mental/trees/lib2geom/src/2geom/svg-path-parser.cpp" +#line 142 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.cpp" static const char _svg_path_actions[] = { 0, 1, 0, 1, 1, 1, 2, 1, 3, 1, 4, 1, 5, 1, 15, 1, @@ -1143,7 +1143,7 @@ static const int svg_path_first_final = 270; static const int svg_path_en_main = 1; -#line 142 "/home/mental/trees/lib2geom/src/2geom/svg-path-parser.rl" +#line 142 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" void Parser::parse(char const *str) @@ -1156,12 +1156,12 @@ throw(SVGPathParseError) _reset(); -#line 1160 "/home/mental/trees/lib2geom/src/2geom/svg-path-parser.cpp" +#line 1160 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.cpp" { cs = svg_path_start; } -#line 1165 "/home/mental/trees/lib2geom/src/2geom/svg-path-parser.cpp" +#line 1165 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.cpp" { int _klen; unsigned int _trans; @@ -1234,13 +1234,13 @@ _match: switch ( *_acts++ ) { case 0: -#line 154 "/home/mental/trees/lib2geom/src/2geom/svg-path-parser.rl" +#line 154 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" { start = p; } break; case 1: -#line 158 "/home/mental/trees/lib2geom/src/2geom/svg-path-parser.rl" +#line 158 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" { char const *end=p; std::string buf(start, end); @@ -1249,55 +1249,55 @@ _match: } break; case 2: -#line 165 "/home/mental/trees/lib2geom/src/2geom/svg-path-parser.rl" +#line 165 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" { _push(1.0); } break; case 3: -#line 169 "/home/mental/trees/lib2geom/src/2geom/svg-path-parser.rl" +#line 169 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" { _push(0.0); } break; case 4: -#line 173 "/home/mental/trees/lib2geom/src/2geom/svg-path-parser.rl" +#line 173 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" { _absolute = true; } break; case 5: -#line 177 "/home/mental/trees/lib2geom/src/2geom/svg-path-parser.rl" +#line 177 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" { _absolute = false; } break; case 6: -#line 181 "/home/mental/trees/lib2geom/src/2geom/svg-path-parser.rl" +#line 181 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" { _moveTo(_pop_point()); } break; case 7: -#line 185 "/home/mental/trees/lib2geom/src/2geom/svg-path-parser.rl" +#line 185 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" { _lineTo(_pop_point()); } break; case 8: -#line 189 "/home/mental/trees/lib2geom/src/2geom/svg-path-parser.rl" +#line 189 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" { _hlineTo(Point(_pop_coord(X), _current[Y])); } break; case 9: -#line 193 "/home/mental/trees/lib2geom/src/2geom/svg-path-parser.rl" +#line 193 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" { _vlineTo(Point(_current[X], _pop_coord(Y))); } break; case 10: -#line 197 "/home/mental/trees/lib2geom/src/2geom/svg-path-parser.rl" +#line 197 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" { Point p = _pop_point(); Point c1 = _pop_point(); @@ -1306,7 +1306,7 @@ _match: } break; case 11: -#line 204 "/home/mental/trees/lib2geom/src/2geom/svg-path-parser.rl" +#line 204 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" { Point p = _pop_point(); Point c1 = _pop_point(); @@ -1314,7 +1314,7 @@ _match: } break; case 12: -#line 210 "/home/mental/trees/lib2geom/src/2geom/svg-path-parser.rl" +#line 210 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" { Point p = _pop_point(); Point c = _pop_point(); @@ -1322,14 +1322,14 @@ _match: } break; case 13: -#line 216 "/home/mental/trees/lib2geom/src/2geom/svg-path-parser.rl" +#line 216 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" { Point p = _pop_point(); _quadTo(_quad_tangent, p); } break; case 14: -#line 221 "/home/mental/trees/lib2geom/src/2geom/svg-path-parser.rl" +#line 221 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" { Point point = _pop_point(); bool sweep = _pop_flag(); @@ -1342,16 +1342,16 @@ _match: } break; case 15: -#line 232 "/home/mental/trees/lib2geom/src/2geom/svg-path-parser.rl" +#line 232 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" { _closePath(); } break; case 16: -#line 368 "/home/mental/trees/lib2geom/src/2geom/svg-path-parser.rl" +#line 368 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" {goto _out;} break; -#line 1355 "/home/mental/trees/lib2geom/src/2geom/svg-path-parser.cpp" +#line 1355 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.cpp" } } @@ -1362,7 +1362,7 @@ _again: goto _resume; _out: {} } -#line 378 "/home/mental/trees/lib2geom/src/2geom/svg-path-parser.rl" +#line 378 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" if ( cs < svg_path_first_final ) { diff --git a/src/2geom/svg-path-parser.h b/src/2geom/svg-path-parser.h index d24d25551..60d8a078b 100644 --- a/src/2geom/svg-path-parser.h +++ b/src/2geom/svg-path-parser.h @@ -44,12 +44,13 @@ namespace Geom { void parse_svg_path(char const *str, SVGPathSink &sink) throw(SVGPathParseError); inline std::vector parse_svg_path(char const *str) throw(SVGPathParseError) { - /*PathBuilder b; - parse_svg_path(str, b); - return b.peek();*/ - std::vector subpaths; - std::back_insert_iterator > iter(subpaths); - SVGPathGenerator > > generator(iter); + typedef std::vector Subpaths; + typedef std::back_insert_iterator Inserter; + + Subpaths subpaths; + Inserter iter(subpaths); + SVGPathGenerator generator(iter); + parse_svg_path(str, generator); return subpaths; } diff --git a/src/2geom/svg-path.cpp b/src/2geom/svg-path.cpp index c178b92da..bed04d3ff 100644 --- a/src/2geom/svg-path.cpp +++ b/src/2geom/svg-path.cpp @@ -59,9 +59,9 @@ void output(QuadraticBezier const &curve, SVGPathSink &sink) { sink.quadTo(curve[1], curve[2]); } -void output(EllipticalArc const &curve, SVGPathSink &sink) { - sink.arcTo( curve.ray(X), curve.ray(Y), curve.rotation_angle(), - curve.large_arc_flag(), curve.sweep_flag(), +void output(SVGEllipticalArc const &curve, SVGPathSink &sink) { + sink.arcTo( curve.ray(X), curve.ray(Y), curve.rotation_angle(), + curve.large_arc_flag(), curve.sweep_flag(), curve.finalPoint() ); } @@ -86,7 +86,7 @@ void output_svg_path(Path &path, SVGPathSink &sink) { output_as(*iter, sink) || output_as(*iter, sink) || output_as(*iter, sink) || - output_as(*iter, sink) || + output_as(*iter, sink) || output_as(*iter, sink); } diff --git a/src/2geom/svg-path.h b/src/2geom/svg-path.h index 1ae4b054c..666a249af 100644 --- a/src/2geom/svg-path.h +++ b/src/2geom/svg-path.h @@ -65,15 +65,15 @@ public: _in_path = true; } //TODO: what if _in_path = false? - + void hlineTo(Coord v) { _path.template appendNew(Point(v, _path.finalPoint()[Y])); } - + void vlineTo(Coord v) { _path.template appendNew(Point(_path.finalPoint()[X], v)); } - + void lineTo(Point p) { _path.template appendNew(p); } @@ -89,7 +89,7 @@ public: void arcTo(double rx, double ry, double angle, bool large_arc, bool sweep, Point p) { - _path.template appendNew(rx, ry, angle, + _path.template appendNew(rx, ry, angle, large_arc, sweep, p); } diff --git a/src/2geom/transforms.h b/src/2geom/transforms.h index ca0a81ac7..898b095b5 100644 --- a/src/2geom/transforms.h +++ b/src/2geom/transforms.h @@ -76,7 +76,7 @@ inline Point operator*(Point const &p, Scale const &s) { return Point(p[X] * s[X **/ class Rotate { private: - Rotate(); + Rotate() {} Point vec; public: explicit Rotate(Coord theta) : vec(std::cos(theta), std::sin(theta)) {} @@ -89,7 +89,11 @@ class Rotate { inline bool operator==(Rotate const &o) const { return vec == o.vec; } inline bool operator!=(Rotate const &o) const { return vec != o.vec; } - Rotate inverse() const { return Rotate( Point(vec[X], -vec[Y]) ); } + inline Rotate inverse() const { + Rotate r; + r.vec = Point(vec[X], -vec[Y]); + return r; + } static Rotate from_degrees(Coord deg) { Coord rad = (deg / 180.0) * M_PI; return Rotate(rad); diff --git a/src/display/inkscape-cairo.cpp b/src/display/inkscape-cairo.cpp index 907f4c3ef..f2892491a 100644 --- a/src/display/inkscape-cairo.cpp +++ b/src/display/inkscape-cairo.cpp @@ -218,7 +218,7 @@ feed_curve_to_cairo(cairo_t *cr, Geom::Curve const &c, Geom::Matrix const & tran } } } -// else if(Geom::EllipticalArc const *svg_elliptical_arc = dynamic_cast(c)) { +// else if(Geom::SVGEllipticalArc const *svg_elliptical_arc = dynamic_cast(c)) { // //TODO: get at the innards and spit them out to cairo // } else { diff --git a/src/display/nr-arena-shape.cpp b/src/display/nr-arena-shape.cpp index 23bf70be5..26b4ea67e 100644 --- a/src/display/nr-arena-shape.cpp +++ b/src/display/nr-arena-shape.cpp @@ -12,8 +12,8 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ - - +#include <2geom/svg-path.h> +#include <2geom/svg-path-parser.h> #include #include #include @@ -40,6 +40,10 @@ #include #include +#include +#include "svg/svg.h" +#include + //int showRuns=0; void nr_pixblock_render_shape_mask_or(NRPixBlock &m,Shape* theS); diff --git a/src/livarot/PathCutting.cpp b/src/livarot/PathCutting.cpp index da5ca4145..7146d91f9 100644 --- a/src/livarot/PathCutting.cpp +++ b/src/livarot/PathCutting.cpp @@ -395,7 +395,7 @@ void Path::AddCurve(Geom::Curve const &c) Geom::Point tme = 3 * ((*cubic_bezier)[3] - (*cubic_bezier)[2]); CubicTo (from_2geom(tmp), from_2geom(tms), from_2geom(tme)); } - else if(Geom::EllipticalArc const *svg_elliptical_arc = dynamic_cast(&c)) { + else if(Geom::SVGEllipticalArc const *svg_elliptical_arc = dynamic_cast(&c)) { ArcTo( from_2geom(svg_elliptical_arc->finalPoint()), svg_elliptical_arc->ray(0), svg_elliptical_arc->ray(1), svg_elliptical_arc->rotation_angle(), diff --git a/src/live_effects/lpe-offset.cpp b/src/live_effects/lpe-offset.cpp index 2916b9fa2..0d45fee2a 100644 --- a/src/live_effects/lpe-offset.cpp +++ b/src/live_effects/lpe-offset.cpp @@ -49,7 +49,7 @@ static void append_half_circle(Geom::Piecewise > &pwd2, using namespace Geom; double r = L2(dir); - EllipticalArc cap(center + dir, r, r, angle_between(Point(1,0), dir), false, false, center - dir); + SVGEllipticalArc cap(center + dir, r, r, angle_between(Point(1,0), dir), false, false, center - dir); Piecewise > cap_pwd2(cap.toSBasis()); pwd2.continuousConcat(cap_pwd2); } diff --git a/src/svg/svg-path.cpp b/src/svg/svg-path.cpp index a57b9248c..ade351402 100644 --- a/src/svg/svg-path.cpp +++ b/src/svg/svg-path.cpp @@ -757,7 +757,7 @@ static void sp_svg_write_curve(Inkscape::SVG::PathString & str, Geom::Curve cons (*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)) { + else if(Geom::SVGEllipticalArc 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(), -- 2.30.2