Code

update to latest 2geom (rev1497)
authorjohanengelen <johanengelen@users.sourceforge.net>
Wed, 16 Jul 2008 21:36:19 +0000 (21:36 +0000)
committerjohanengelen <johanengelen@users.sourceforge.net>
Wed, 16 Jul 2008 21:36:19 +0000 (21:36 +0000)
40 files changed:
src/2geom/CMakeLists.txt
src/2geom/Makefile_insert
src/2geom/basic-intersection.cpp
src/2geom/choose.h
src/2geom/circle.cpp [new file with mode: 0644]
src/2geom/circle.h [new file with mode: 0644]
src/2geom/coord.h
src/2geom/curve.h
src/2geom/curves.h
src/2geom/ellipse.cpp
src/2geom/ellipse.h
src/2geom/forward.h
src/2geom/interval.h
src/2geom/numeric/fitting-model.h
src/2geom/path-intersection.cpp
src/2geom/path.cpp
src/2geom/path.h
src/2geom/pathvector.cpp
src/2geom/pathvector.h
src/2geom/poly-dk-solve.cpp
src/2geom/poly-dk-solve.h
src/2geom/poly-laguerre-solve.cpp
src/2geom/poly-laguerre-solve.h
src/2geom/poly.cpp
src/2geom/poly.h
src/2geom/rect.h
src/2geom/sbasis-roots.cpp
src/2geom/shape.cpp
src/2geom/svg-elliptical-arc.cpp
src/2geom/svg-elliptical-arc.h
src/2geom/svg-path-parser.cpp
src/2geom/svg-path-parser.h
src/2geom/svg-path.cpp
src/2geom/svg-path.h
src/2geom/transforms.h
src/display/inkscape-cairo.cpp
src/display/nr-arena-shape.cpp
src/livarot/PathCutting.cpp
src/live_effects/lpe-offset.cpp
src/svg/svg-path.cpp

index 8c22cb15a6cb6be62d06a49b42cd29aa94df227c..e94c5c673443bd3e3d74dc9bf3de240ed15cb057 100644 (file)
@@ -1,6 +1,7 @@
 SET(2geom_SRC
 basic-intersection.cpp
 bezier-utils.cpp
+circle.cpp
 circle-circle.cpp
 conjugate_gradient.cpp
 convex-cover.cpp
index 84b9f740117499eaf82beff713fa3a0e07704d98..d03799dd7ff75c1e3e9f533e41ed688f00a96424 100644 (file)
@@ -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      \
index 5375e5b58296c80009e83701c25bf009c9a5bb53..48b990445ed3c0296378237811ed247750aade2b 100644 (file)
@@ -1,5 +1,8 @@
 #include <2geom/basic-intersection.h>
 #include <2geom/exception.h>
+#include <gsl/gsl_vector.h>
+#include <gsl/gsl_multiroots.h>
+     
 
 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<std::pair<double, double> > find_intersections( OldBezier a, OldBezier b)
 {
     std::vector<std::pair<double, double> > parameters;
@@ -346,6 +436,9 @@ std::vector<std::pair<double, double> > 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;
 }
index bfd66e8a9091b233452a9917c7a89dc3dd8b2101..141a23f370faee171e1e952c6a45e08445eed6ba 100644 (file)
@@ -30,6 +30,7 @@
 
 #ifndef _CHOOSE_H
 #define _CHOOSE_H
+#include <vector>
 
 // 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 (file)
index 0000000..c3cea0a
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Circle Curve
+ *
+ * Authors:
+ *      Marco Cecchetti <mrcekets at gmail.com>
+ *
+ * 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<Point> 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<NL::LFMCircle> 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 (file)
index 0000000..2f81e27
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Circle Curve
+ *
+ * Authors:
+ *      Marco Cecchetti <mrcekets at gmail.com>
+ *
+ * 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<Point> 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<Point> 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 :
index e9abfc927d84a8d8c5ab06865b8dec14a96cfd31..b2c2a4766f5bbba23c50d4b56d78dc8148707f24 100644 (file)
@@ -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; }
index 8eaf73fcf4d733e52bf31fef697783203b435cb1..6ab05b750ecd5808139ad9aad942252b3b776310 100644 (file)
@@ -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++) {
index 3bf7d9b598f37b4384793604a5815c70e8960805..b0b16df3ddc45d12e91f43f1ee9ff3cedcdf1c9b 100644 (file)
@@ -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>
 
 
index 20ac0bb2bc358e54c745571b61a4fcea06384164..2690a091bfafab64276f10328a0e12981c82604c 100644 (file)
@@ -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<double> 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<double> 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<Point> 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<double> 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
 
index a10f9ced090bdb5c2a97d9e5329c44948fd9a3c1..1f0dfce632792c8e5854fd095e95773a3a0aa118 100644 (file)
@@ -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<double> implicit_form_coefficients() const;
+
+    Ellipse transformed(Matrix const& m) const;
+
   private:
     Point m_centre, m_ray;
     double m_angle;
index 52fd3525e324280439ad5589b55b35d38b8cdb7a..9bd5dedbe7cdc18468a6b16792fde5e832399794 100644 (file)
@@ -43,6 +43,7 @@ typedef BezierCurve<2> QuadraticBezier;
 typedef BezierCurve<1> LineSegment;
 typedef BezierCurve<3> CubicBezier;
 class EllipticalArc;
+class SVGEllipticalArc;
 
 class HLineSegment;
 class VLineSegment;
index f042294ff605f1f276ac0ad40d1b74e043faf617..9887c044ffaa0dd8bc754aab9b2b9c394698a657 100644 (file)
 
 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 {
index cc31133727079f7fb2eb2c140d9f7a73df88d169..de8f24760aa91e8bad823aefd440fe5204038f90 100644 (file)
@@ -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<Point, double, InstanceType>
+{
+  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<Circle>
+{
+  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<double, double, SBasis>
index 635996e515fde2ff8c12e732959db78d27c777dc..2612aa12507a4a8ce21fd3384398ce6bbb76dabc 100644 (file)
@@ -4,6 +4,8 @@
 
 //for path_direction:
 #include <2geom/sbasis-geometric.h>
+#include <gsl/gsl_vector.h>
+#include <gsl/gsl_multiroots.h>
 
 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;
index 2e5b789d5936252895e72c07ac37c308232589b5..d39b3ca9235f16b546a564a88b6a1187e448689a 100644 (file)
 
 #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<typename iter>
 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<Curve>((*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<double> 
 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> 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<Curve>(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<Curve>(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<Curve>(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();
     }
index 1e9aa1d42cbd805c2daf94340beb84d239869b49..f391c9c249cd933ba27401d7eef61c9bbbbf0d32 100644 (file)
 #define SEEN_GEOM_PATH_H
 
 
+#include <boost/shared_ptr.hpp>
 #include <2geom/curves.h>
 
 #include <iterator>
+#include <algorithm>
 
 
 namespace Geom
 {
 
-// Conditional expression for types. If true, first, if false, second.
-template<bool _Cond, typename _Iftrue, typename _Iffalse>
-  struct __conditional_type
-  { typedef _Iftrue __type; };
+class Path;
 
-template<typename _Iftrue, typename _Iffalse>
-  struct __conditional_type<false, _Iftrue, _Iffalse>
-  { typedef _Iffalse __type; };
+namespace PathInternal {
 
+typedef std::vector<boost::shared_ptr<Curve const> > Sequence;
 
-template <typename IteratorImpl>
-class BaseIterator
-: public std::iterator<std::forward_iterator_tag, Curve const>
-{
-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<Curve *> Sequence;
-  BaseIterator (  typename __conditional_type<
-                    (std::__are_same<IteratorImpl, Sequence::const_iterator >::__value),  // check if this instantiation is of const_iterator type
-                    const BaseIterator< Sequence::iterator >,     // if true:  accept iterator in const_iterator instantiation
-                    const BaseIterator<IteratorImpl> > ::__type   // if false: default to standard copy constructor
-                  & __other)
-    : impl_(__other.impl_) { }
-  friend class BaseIterator< Sequence::const_iterator >;
-
+template <typename C, typename P>
+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<Curve const> get_ref() const {
+    return path->get_ref_at_index(index);
   }
 
-  BaseIterator operator++(int) {
-    BaseIterator old=*this;
+  C &operator++() {
+    ++index;
+    return static_cast<C &>(*this);
+  }
+  C operator++(int) {
+    C old(static_cast<C &>(*this));
     ++(*this);
     return old;
   }
 
-  BaseIterator &operator--() {
-    --impl_;
-    return *this;
+  C &operator--() {
+    --index;
+    return static_cast<C &>(*this);
   }
-
-  BaseIterator operator--(int) {
-    BaseIterator old=*this;
+  C operator--(int) {
+    C old(static_cast<C &>(*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 <typename Iterator>
-class DuplicatingIterator
-: public std::iterator<std::input_iterator_tag, Curve *>
-{
+class ConstIterator : public BaseIterator<ConstIterator, Path const> {
 public:
-  DuplicatingIterator() {}
-  DuplicatingIterator(Iterator const &iter) : impl_(iter) {}
+  typedef BaseIterator<ConstIterator, Path const> 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<Iterator, Path> {
+public:
+  typedef BaseIterator<Iterator, Path> Base;
+
+  Iterator() : Base() {}
+  // default copy, default assign
+
+  operator ConstIterator const &() const {
+    return reinterpret_cast<ConstIterator const &>(*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<ClosingSegment>(curves_.back())
  */
 class Path {
-private:
-  typedef std::vector<Curve *> Sequence;
-
 public:
-  typedef BaseIterator<Sequence::iterator> iterator;
-  typedef BaseIterator<Sequence::const_iterator> 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<Sequence>(new Sequence(1, boost::shared_ptr<Curve>()))),
+    final_(new ClosingSegment(p, p)),
+    closed_(false)
   {
-    curves_.push_back(final_);
-    insert(begin(), other.begin(), other.end());
+    get_curves().back() = boost::shared_ptr<Curve>(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<Sequence>(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<Curve>(final_));
   }
 
-  template <typename Impl>
-  Path(BaseIterator<Impl> first, BaseIterator<Impl> 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<Curve const> 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<Curve>((*iter)->reverse());
     }
+    std::reverse(ret.get_curves().begin(), ret.get_curves().end()-1);
+    ret.final_ = static_cast<ClosingSegment *>(ret.final_->reverse());
+    ret.get_curves().back() = boost::shared_ptr<Curve>(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>(curve.duplicate()));
+    if (stitching) stitch(seq_pos, seq_pos, source);
+    do_update(seq_pos, seq_pos, source.begin(), source.end());
   }
 
-  template <typename Impl>
-  void insert(iterator pos, BaseIterator<Impl> first, BaseIterator<Impl> 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<Impl>(first.impl_),
-                    DuplicatingIterator<Impl>(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>(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 <typename Impl>
-  void replace(iterator replaced,
-               BaseIterator<Impl> first, BaseIterator<Impl> 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>(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<Impl>(first.impl_),
-                    DuplicatingIterator<Impl>(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 <typename Impl>
-  void replace(iterator first_replaced, iterator last_replaced,
-               BaseIterator<Impl> first, BaseIterator<Impl> 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<Curve> 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<Curve> 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<SBasis> 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 <typename CurveType, typename A>
   void appendNew(A a) {
+    unshare();
     do_append(new CurveType(finalPoint(), a));
   }
 
   template <typename CurveType, typename A, typename B>
   void appendNew(A a, B b) {
+    unshare();
     do_append(new CurveType(finalPoint(), a, b));
   }
 
   template <typename CurveType, typename A, typename B, typename C>
   void appendNew(A a, B b, C c) {
+    unshare();
     do_append(new CurveType(finalPoint(), a, b, c));
   }
 
   template <typename CurveType, typename A, typename B, typename C,
                                 typename D>
   void appendNew(A a, B b, C c, D d) {
+    unshare();
     do_append(new CurveType(finalPoint(), a, b, c, d));
   }
 
   template <typename CurveType, typename A, typename B, typename C,
                                 typename D, typename E>
   void appendNew(A a, B b, C c, D d, E e) {
+    unshare();
     do_append(new CurveType(finalPoint(), a, b, c, d, e));
   }
 
   template <typename CurveType, typename A, typename B, typename C,
                                 typename D, typename E, typename F>
   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<Sequence>(new Sequence(*curves_));
+    }
+    if (!get_curves().back().unique()) {
+      final_ = static_cast<ClosingSegment *>(final_->duplicate());
+      get_curves().back() = boost::shared_ptr<Curve>(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<Sequence> curves_;
   ClosingSegment *final_;
   bool closed_;
-  
 };  // end class Path
 
 inline static Piecewise<D2<SBasis> > paths_to_pw(std::vector<Path> paths) {
@@ -734,7 +687,6 @@ inline void swap<Geom::Path>(Geom::Path &a, Geom::Path &b)
 
 }  // end namespace std
 
-
 #endif // SEEN_GEOM_PATH_H
 
 
index 9befc1f170688edfee205f5ddd12bf70b459e3ee..1e0a20003c61b6e9f9893695e6a261f0d1bc7ce4 100644 (file)
@@ -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;
index 17f6b62127e2afe976a225e89b843982766ece63..14d1efdfa3dfbba92e04d0a7626b068cd314dd13 100644 (file)
 #include <2geom/forward.h>
 #include <2geom/path.h>
 #include <2geom/rect.h>
+#include <2geom/transforms.h>
 
 namespace Geom {
 
 typedef std::vector<Geom::Path> 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);
 
index 2787c4478bb7f3918100f2d2ff821d181a12dd09..a328b316ce6ba37381a4745ea6a2387068770f79 100644 (file)
@@ -3,6 +3,8 @@
 
 /*** implementation of the Durand-Kerner method.  seems buggy*/
 
+namespace Geom {
+
 std::complex<double> evalu(Poly const & p, std::complex<double> x) {
     std::complex<double> result = 0;
     std::complex<double> xx = 1;
@@ -51,6 +53,7 @@ std::vector<std::complex<double> > DK(Poly const & ply, const double tol) {
     return roots;
 }
 
+} // namespace Geom
 
 /*
   Local Variables:
index dadd1211094ffd32bb7594c51464aac138d341bd..463f854c137f80509b09ecdbd4cf416c106c6745 100644 (file)
@@ -1,9 +1,18 @@
+#ifndef LIB2GEOM_SEEN_POLY_DK_SOLVE_H
+#define LIB2GEOM_SEEN_POLY_DK_SOLVE_H
+
 #include <2geom/poly.h>
 #include <complex>
 
+namespace Geom {
+
 std::vector<std::complex<double> > 
 DK(Poly const & ply, const double tol=1e-10);
 
+} // namespace Geom
+
+#endif // LIB2GEOM_SEEN_POLY_DK_SOLVE_H
+
 /*
   Local Variables:
   mode:c++
index bd2ddf305235e358b96aa221a2611ae48420d3a7..5b59690b742aec0ef565959b2813472086831ea9 100644 (file)
@@ -1,6 +1,9 @@
 #include <2geom/poly-laguerre-solve.h>
 #include <iterator>
 
+
+namespace Geom {
+
 typedef std::complex<double> 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++
index 6f7cb0aee86b0b3ff9dd0156e7998477a1baba51..6836aa49d4c97c44d7cb89e9b334cc09e4ba4aa5 100644 (file)
@@ -1,6 +1,11 @@
+#ifndef LIB2GEOM_SEEN_POLY_LAGUERRE_SOLVE_H
+#define LIB2GEOM_SEEN_POLY_LAGUERRE_SOLVE_H
+
 #include <2geom/poly.h>
 #include <complex>
 
+namespace Geom {
+
 std::vector<std::complex<double> > 
 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++
index 1b9b0e568e98dfd17b2720ca9a68e0b550b1ca4d..d8b379557f154b812dd151dd62d3a50df3ac73e3 100644 (file)
@@ -1,5 +1,12 @@
 #include <2geom/poly.h>
 
+#define HAVE_GSL
+#ifdef HAVE_GSL
+#include <gsl/gsl_poly.h>
+#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 <gsl/gsl_poly.h>
-#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:
index 2d7b79bfef9d04d1dd2f226d6ad64b8b1c7db891..152626698c574b0847475348c463509e422400dc 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef SEEN_POLY_H
-#define SEEN_POLY_H
+#ifndef LIB2GEOM_SEEN_POLY_H
+#define LIB2GEOM_SEEN_POLY_H
 #include <assert.h>
 #include <vector>
 #include <iostream>
@@ -7,22 +7,24 @@
 #include <complex>
 #include <2geom/utils.h>
 
+namespace Geom {
+
 class Poly : public std::vector<double>{
 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 <typename T>
     T eval(T x) const {
         T r = 0;
@@ -116,17 +116,17 @@ public:
         }
         return r;
     }
-    
+
     template <typename T>
     T operator()(T t) const { return (T)eval(t);}
-    
+
     void normalize();
-    
+
     void monicify();
     Poly() {}
     Poly(const Poly& p) : std::vector<double>(p) {}
     Poly(const double a) {push_back(a);}
-    
+
 public:
     template <class T, class U>
     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
index 27a475cf3476d93da06fd4ec52c3824289d4578c..a136e91a8f01e8883a7fadd24c08cc65a320dee9 100644 (file)
@@ -55,6 +55,10 @@ class D2<Interval> {
   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<Interval>() { f[X] = f[Y] = Interval(0, 0); }
     
     D2<Interval>(Interval const &a, Interval const &b) {
index 30f5fb22fdbfd7e853ea1fa39faeb143207a957a..861baf76d7637815ccff468811f5b17e656eff37 100644 (file)
@@ -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];
index 936dfaf70fdb10ba6656dd66e342b2f57cc07a23..814c6c68c08f0ef036cf4ad989a99a17c9e92fd7 100644 (file)
@@ -432,7 +432,7 @@ std::vector<Path> inner_sanitize(std::vector<Path> 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";
index 047ae1431585462dbc7c1984577dc741174c09c2..cdf60bc9fdc1d6a8180272056c4ab6e11b843002 100644 (file)
@@ -915,10 +915,32 @@ D2<SBasis> 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() )
index f129e5a65c96193cd00f0fa8a91b431c621b954a..7d5087c48961b2f8485e84ba7b3f595c27b0da9f 100644 (file)
@@ -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<Point> 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:
index 2a0ee9b1f5222a4784192e503f61fec654ce1bb1..bb452ec3336dcfc5e13d7ca7970a2af340a7949d 100644 (file)
@@ -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 ) {
index d24d255517d094c6a4b83f5e00d1f1b9ab198242..60d8a078b62b2375357c2dc555208cfeff34e4b5 100644 (file)
@@ -44,12 +44,13 @@ namespace Geom {
 void parse_svg_path(char const *str, SVGPathSink &sink) throw(SVGPathParseError);
 
 inline std::vector<Path> parse_svg_path(char const *str) throw(SVGPathParseError) {
-    /*PathBuilder b;
-    parse_svg_path(str, b);
-    return b.peek();*/
-    std::vector<Path> subpaths;
-    std::back_insert_iterator<std::vector<Path> > iter(subpaths);
-    SVGPathGenerator<std::back_insert_iterator<std::vector<Path> > > generator(iter);
+    typedef std::vector<Path> Subpaths;
+    typedef std::back_insert_iterator<Subpaths> Inserter;
+    
+    Subpaths subpaths;
+    Inserter iter(subpaths);
+    SVGPathGenerator<Inserter> generator(iter);
+
     parse_svg_path(str, generator);
     return subpaths;
 }
index c178b92da43900ffc86f5d906521006ca1573c62..bed04d3ffcfd1144dfcb6ac5a17290e6ad957844 100644 (file)
@@ -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<LineSegment>(*iter, sink) ||
         output_as<CubicBezier>(*iter, sink) ||
         output_as<QuadraticBezier>(*iter, sink) ||
-        output_as<EllipticalArc>(*iter, sink) ||
+        output_as<SVGEllipticalArc>(*iter, sink) ||
         output_as<Curve>(*iter, sink);
     }
 
index 1ae4b054cba2bb821b248ce163d951b4db056990..666a249af6906ad2b10b69bd987336b6d9426993 100644 (file)
@@ -65,15 +65,15 @@ public:
         _in_path = true;
     }
 //TODO: what if _in_path = false?
-    
+
     void hlineTo(Coord v) {
        _path.template appendNew<HLineSegment>(Point(v, _path.finalPoint()[Y]));
     }
-    
+
     void vlineTo(Coord v) {
        _path.template appendNew<VLineSegment>(Point(_path.finalPoint()[X], v));
     }
-    
+
     void lineTo(Point p) {
         _path.template appendNew<LineSegment>(p);
     }
@@ -89,7 +89,7 @@ public:
     void arcTo(double rx, double ry, double angle,
                bool large_arc, bool sweep, Point p)
     {
-        _path.template appendNew<EllipticalArc>(rx, ry, angle,
+        _path.template appendNew<SVGEllipticalArc>(rx, ry, angle,
                                                  large_arc, sweep, p);
     }
 
index ca0a81ac7d5d53122b0892506408a04b7b88cae1..898b095b593751fdc4fbac209e81ea9f94ba5ae5 100644 (file)
@@ -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);
index 907f4c3ef41379730bb19d53016fbb95c82745ff..f2892491aec05811f1b0b0efeddd8d4d97fd013a 100644 (file)
@@ -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<Geom::EllipticalArc *>(c)) {
+//    else if(Geom::SVGEllipticalArc const *svg_elliptical_arc = dynamic_cast<Geom::SVGEllipticalArc *>(c)) {
 //        //TODO: get at the innards and spit them out to cairo
 //    }
     else {
index 23bf70be5eb597e34a8cd58d67f61d4e71b5568e..26b4ea67e5a693a4fa76fc41e6305f16044881dd 100644 (file)
@@ -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 <display/canvas-arena.h>
 #include <display/nr-arena.h>
 #include <display/nr-arena-shape.h>
 #include <typeinfo>
 #include <cairo.h>
 
+#include <glib.h>
+#include "svg/svg.h"
+#include <fenv.h>
+
 //int  showRuns=0;
 void nr_pixblock_render_shape_mask_or(NRPixBlock &m,Shape* theS);
 
index da5ca4145e7a0547312135c5c2e7f236b4fc478c..7146d91f9786f44ef1423dbe8afa257f6836af54 100644 (file)
@@ -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<Geom::EllipticalArc const *>(&c)) {
+    else if(Geom::SVGEllipticalArc const *svg_elliptical_arc = dynamic_cast<Geom::SVGEllipticalArc const *>(&c)) {
         ArcTo( from_2geom(svg_elliptical_arc->finalPoint()),
                svg_elliptical_arc->ray(0), svg_elliptical_arc->ray(1),
                svg_elliptical_arc->rotation_angle(),
index 2916b9fa2ecb5b438e5b530f20f3c5222105cda7..0d45fee2ac138e6638ee1a1be06623556ff0eb3c 100644 (file)
@@ -49,7 +49,7 @@ static void append_half_circle(Geom::Piecewise<Geom::D2<Geom::SBasis> > &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<D2<SBasis> > cap_pwd2(cap.toSBasis());
     pwd2.continuousConcat(cap_pwd2);
 }
index a57b9248cc49dbbd9a9e1c331e478dd3f8c1ce88..ade351402ee45ae501ff684b18b804ceee7c42ac 100644 (file)
@@ -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<Geom::EllipticalArc const *>(c)) {
+    else if(Geom::SVGEllipticalArc const *svg_elliptical_arc = dynamic_cast<Geom::SVGEllipticalArc const *>(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(),