summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: e4c0ec9)
raw | patch | inline | side by side (parent: e4c0ec9)
author | johanengelen <johanengelen@users.sourceforge.net> | |
Wed, 16 Jul 2008 21:36:19 +0000 (21:36 +0000) | ||
committer | johanengelen <johanengelen@users.sourceforge.net> | |
Wed, 16 Jul 2008 21:36:19 +0000 (21:36 +0000) |
40 files changed:
index 8c22cb15a6cb6be62d06a49b42cd29aa94df227c..e94c5c673443bd3e3d74dc9bf3de240ed15cb057 100644 (file)
--- a/src/2geom/CMakeLists.txt
+++ b/src/2geom/CMakeLists.txt
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)
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)
#include <2geom/basic-intersection.h>
#include <2geom/exception.h>
+#include <gsl/gsl_vector.h>
+#include <gsl/gsl_multiroots.h>
+
unsigned intersect_steps = 0;
OldBezier() {
}
void split(double t, OldBezier &a, OldBezier &b) const;
+ Point operator()(double t) const;
~OldBezier() {}
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:
}
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);
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;
}
diff --git a/src/2geom/choose.h b/src/2geom/choose.h
index bfd66e8a9091b233452a9917c7a89dc3dd8b2101..141a23f370faee171e1e952c6a45e08445eed6ba 100644 (file)
--- a/src/2geom/choose.h
+++ b/src/2geom/choose.h
#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
--- /dev/null
+++ b/src/2geom/circle.cpp
@@ -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
--- /dev/null
+++ b/src/2geom/circle.h
@@ -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 :
diff --git a/src/2geom/coord.h b/src/2geom/coord.h
index e9abfc927d84a8d8c5ab06865b8dec14a96cfd31..b2c2a4766f5bbba23c50d4b56d78dc8148707f24 100644 (file)
--- a/src/2geom/coord.h
+++ b/src/2geom/coord.h
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 8eaf73fcf4d733e52bf31fef697783203b435cb1..6ab05b750ecd5808139ad9aad942252b3b776310 100644 (file)
--- a/src/2geom/curve.h
+++ b/src/2geom/curve.h
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;
/* 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 3bf7d9b598f37b4384793604a5815c70e8960805..b0b16df3ddc45d12e91f43f1ee9ff3cedcdf1c9b 100644 (file)
--- a/src/2geom/curves.h
+++ b/src/2geom/curves.h
#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 20ac0bb2bc358e54c745571b61a4fcea06384164..2690a091bfafab64276f10328a0e12981c82604c 100644 (file)
--- a/src/2geom/ellipse.cpp
+++ b/src/2geom/ellipse.cpp
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
}
+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();
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
diff --git a/src/2geom/ellipse.h b/src/2geom/ellipse.h
index a10f9ced090bdb5c2a97d9e5329c44948fd9a3c1..1f0dfce632792c8e5854fd095e95773a3a0aa118 100644 (file)
--- a/src/2geom/ellipse.h
+++ b/src/2geom/ellipse.h
#include <2geom/point.h>
#include <2geom/exception.h>
-
+#include <2geom/matrix.h>
namespace Geom
{
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;
diff --git a/src/2geom/forward.h b/src/2geom/forward.h
index 52fd3525e324280439ad5589b55b35d38b8cdb7a..9bd5dedbe7cdc18468a6b16792fde5e832399794 100644 (file)
--- a/src/2geom/forward.h
+++ b/src/2geom/forward.h
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 f042294ff605f1f276ac0ad40d1b74e043faf617..9887c044ffaa0dd8bc754aab9b2b9c394698a657 100644 (file)
--- a/src/2geom/interval.h
+++ b/src/2geom/interval.h
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;
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)
#include <2geom/bezier-curve.h>
#include <2geom/poly.h>
#include <2geom/ellipse.h>
+#include <2geom/circle.h>
#include <2geom/utils.h>
};
+// 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)
//for path_direction:
#include <2geom/sbasis-geometric.h>
+#include <gsl/gsl_vector.h>
+#include <gsl/gsl_multiroots.h>
namespace Geom {
}
}
+
+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.
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
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 2e5b789d5936252895e72c07ac37c308232589b5..d39b3ca9235f16b546a564a88b6a1187e448689a 100644 (file)
--- a/src/2geom/path.cpp
+++ b/src/2geom/path.cpp
#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;
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;
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
{
{
// 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));
}
}
}
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 1e9aa1d42cbd805c2daf94340beb84d239869b49..f391c9c249cd933ba27401d7eef61c9bbbbf0d32 100644 (file)
--- a/src/2geom/path.h
+++ b/src/2geom/path.h
#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"
* 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;
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 {
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; }
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
{
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) {
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));
}
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));
}
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));
}
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));
}
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);
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) {
} // end namespace std
-
#endif // SEEN_GEOM_PATH_H
index 9befc1f170688edfee205f5ddd12bf70b459e3ee..1e0a20003c61b6e9f9893695e6a261f0d1bc7ce4 100644 (file)
--- a/src/2geom/pathvector.cpp
+++ b/src/2geom/pathvector.cpp
// 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
**/
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;
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 17f6b62127e2afe976a225e89b843982766ece63..14d1efdfa3dfbba92e04d0a7626b068cd314dd13 100644 (file)
--- a/src/2geom/pathvector.h
+++ b/src/2geom/pathvector.h
#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)
/*** 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;
return roots;
}
+} // namespace Geom
/*
Local Variables:
index dadd1211094ffd32bb7594c51464aac138d341bd..463f854c137f80509b09ecdbd4cf416c106c6745 100644 (file)
+#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)
#include <2geom/poly-laguerre-solve.h>
#include <iterator>
+
+namespace Geom {
+
typedef std::complex<double> cdouble;
cdouble laguerre_internal_complex(Poly const & p,
return result;
}
+} // namespace Geom
+
/*
Local Variables:
mode:c++
index 6f7cb0aee86b0b3ff9dd0156e7998477a1baba51..6836aa49d4c97c44d7cb89e9b334cc09e4ba4aa5 100644 (file)
+#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);
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 1b9b0e568e98dfd17b2720ca9a68e0b550b1ca4d..d8b379557f154b812dd151dd62d3a50df3ac73e3 100644 (file)
--- a/src/2geom/poly.cpp
+++ b/src/2geom/poly.cpp
#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);
}
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);
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;
assert(1);
}*/
+} //namespace Geom
/*
Local Variables:
diff --git a/src/2geom/poly.h b/src/2geom/poly.h
index 2d7b79bfef9d04d1dd2f226d6ad64b8b1c7db891..152626698c574b0847475348c463509e422400dc 100644 (file)
--- a/src/2geom/poly.h
+++ b/src/2geom/poly.h
-#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>
#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]);
}
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]);
}
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];
}
Poly result;
const unsigned out_size = size();
result.reserve(out_size);
-
+
for(unsigned i = 0; i < out_size; i++) {
result.push_back((*this)[i]);
}
Poly operator-() const {
Poly result;
result.resize(size());
-
+
for(unsigned i = 0; i < size(); i++) {
result[i] = -(*this)[i];
}
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;
}
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 {
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:
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 27a475cf3476d93da06fd4ec52c3824289d4578c..a136e91a8f01e8883a7fadd24c08cc65a320dee9 100644 (file)
--- a/src/2geom/rect.h
+++ b/src/2geom/rect.h
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)
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 936dfaf70fdb10ba6656dd66e342b2f57cc07a23..814c6c68c08f0ef036cf4ad989a99a17c9e92fd7 100644 (file)
--- a/src/2geom/shape.cpp
+++ b/src/2geom/shape.cpp
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)
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)
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;
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)
-#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
*
};
-#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,
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)
_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;
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);
}
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();
}
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();
}
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();
}
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();
}
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"
}
}
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)
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;
}
diff --git a/src/2geom/svg-path.cpp b/src/2geom/svg-path.cpp
index c178b92da43900ffc86f5d906521006ca1573c62..bed04d3ffcfd1144dfcb6ac5a17290e6ad957844 100644 (file)
--- a/src/2geom/svg-path.cpp
+++ b/src/2geom/svg-path.cpp
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() );
}
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);
}
diff --git a/src/2geom/svg-path.h b/src/2geom/svg-path.h
index 1ae4b054cba2bb821b248ce163d951b4db056990..666a249af6906ad2b10b69bd987336b6d9426993 100644 (file)
--- a/src/2geom/svg-path.h
+++ b/src/2geom/svg-path.h
_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);
}
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);
}
diff --git a/src/2geom/transforms.h b/src/2geom/transforms.h
index ca0a81ac7d5d53122b0892506408a04b7b88cae1..898b095b593751fdc4fbac209e81ea9f94ba5ae5 100644 (file)
--- a/src/2geom/transforms.h
+++ b/src/2geom/transforms.h
**/
class Rotate {
private:
- Rotate();
+ Rotate() {}
Point vec;
public:
explicit Rotate(Coord theta) : vec(std::cos(theta), std::sin(theta)) {}
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)
* 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)
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)
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);
}
diff --git a/src/svg/svg-path.cpp b/src/svg/svg-path.cpp
index a57b9248cc49dbbd9a9e1c331e478dd3f8c1ce88..ade351402ee45ae501ff684b18b804ceee7c42ac 100644 (file)
--- 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<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(),