From 680344945f84364fbbcbe4d4a353a52d4a724653 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Wed, 16 Jul 2008 21:36:19 +0000 Subject: update to latest 2geom (rev1497) (bzr r6332) --- src/2geom/basic-intersection.cpp | 97 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 95 insertions(+), 2 deletions(-) (limited to 'src/2geom/basic-intersection.cpp') diff --git a/src/2geom/basic-intersection.cpp b/src/2geom/basic-intersection.cpp index 5375e5b58..48b990445 100644 --- a/src/2geom/basic-intersection.cpp +++ b/src/2geom/basic-intersection.cpp @@ -1,5 +1,8 @@ #include <2geom/basic-intersection.h> #include <2geom/exception.h> +#include +#include + unsigned intersect_steps = 0; @@ -12,6 +15,7 @@ public: OldBezier() { } void split(double t, OldBezier &a, OldBezier &b) const; + Point operator()(double t) const; ~OldBezier() {} @@ -152,7 +156,28 @@ void OldBezier::split(double t, OldBezier &left, OldBezier &right) const { right.p[j] = Vtemp[sz-1-j][j]; } - +/* + * split the curve at the midpoint, returning an array with the two parts + * Temporary storage is minimized by using part of the storage for the result + * to hold an intermediate value until it is no longer needed. + */ +Point OldBezier::operator()(double t) const { + const unsigned sz = p.size(); + Geom::Point Vtemp[sz][sz]; + + /* Copy control points */ + std::copy(p.begin(), p.end(), Vtemp[0]); + + /* Triangle computation */ + for (unsigned i = 1; i < sz; i++) { + for (unsigned j = 0; j < sz - i; j++) { + Vtemp[i][j] = lerp(t, Vtemp[i-1][j], Vtemp[i-1][j+1]); + } + } + return Vtemp[sz-1][0]; +} + + /* * Test the bounding boxes of two OldBezier curves for interference. * Several observations: @@ -324,7 +349,7 @@ double Lmax(Point p) { } unsigned wangs_theorem(OldBezier a) { - return 12; // seems a good approximation! + return 6; // seems a good approximation! double la1 = Lmax( ( a.p[2] - a.p[1] ) - (a.p[1] - a.p[0]) ); double la2 = Lmax( ( a.p[3] - a.p[2] ) - (a.p[2] - a.p[1]) ); double l0 = std::max(la1, la2); @@ -337,6 +362,71 @@ unsigned wangs_theorem(OldBezier a) { return ra; } +struct rparams +{ + OldBezier &A; + OldBezier &B; +}; + +static int +intersect_polish_f (const gsl_vector * x, void *params, + gsl_vector * f) +{ + const double x0 = gsl_vector_get (x, 0); + const double x1 = gsl_vector_get (x, 1); + + Geom::Point dx = ((struct rparams *) params)->A(x0) - + ((struct rparams *) params)->B(x1); + + gsl_vector_set (f, 0, dx[0]); + gsl_vector_set (f, 1, dx[1]); + + return GSL_SUCCESS; +} + +static void intersect_polish_root (OldBezier &A, double &s, + OldBezier &B, double &t) { + const gsl_multiroot_fsolver_type *T; + gsl_multiroot_fsolver *sol; + + int status; + size_t iter = 0; + + const size_t n = 2; + struct rparams p = {A, B}; + gsl_multiroot_function f = {&intersect_polish_f, n, &p}; + + double x_init[2] = {s, t}; + gsl_vector *x = gsl_vector_alloc (n); + + gsl_vector_set (x, 0, x_init[0]); + gsl_vector_set (x, 1, x_init[1]); + + T = gsl_multiroot_fsolver_hybrids; + sol = gsl_multiroot_fsolver_alloc (T, 2); + gsl_multiroot_fsolver_set (sol, &f, x); + + do + { + iter++; + status = gsl_multiroot_fsolver_iterate (sol); + + if (status) /* check if solver is stuck */ + break; + + status = + gsl_multiroot_test_residual (sol->f, 1e-12); + } + while (status == GSL_CONTINUE && iter < 1000); + + s = gsl_vector_get (sol->x, 0); + t = gsl_vector_get (sol->x, 1); + + gsl_multiroot_fsolver_free (sol); + gsl_vector_free (x); +} + + std::vector > find_intersections( OldBezier a, OldBezier b) { std::vector > parameters; @@ -346,6 +436,9 @@ std::vector > find_intersections( OldBezier a, OldBezi b, 0., 1., wangs_theorem(b), parameters); } + for(unsigned i = 0; i < parameters.size(); i++) + intersect_polish_root(a, parameters[i].first, + b, parameters[i].second); std::sort(parameters.begin(), parameters.end()); return parameters; } -- cgit v1.2.3