1
#include <2geom/basic-intersection.h>
2
#include <2geom/sbasis-to-bezier.h>
3
#include <2geom/exception.h>
6
#include <gsl/gsl_vector.h>
7
#include <gsl/gsl_multiroots.h>
13
//#ifdef USE_RECURSIVE_INTERSECTOR
15
// void find_intersections(std::vector<std::pair<double, double> > &xs,
16
// D2<SBasis> const & A,
17
// D2<SBasis> const & B) {
18
// vector<Point> BezA, BezB;
19
// sbasis_to_bezier(BezA, A);
20
// sbasis_to_bezier(BezB, B);
24
// find_intersections_bezier_recursive(xs, BezA, BezB);
26
// void find_intersections(std::vector< std::pair<double, double> > & xs,
27
// std::vector<Point> const& A,
28
// std::vector<Point> const& B,
30
// find_intersections_bezier_recursive(xs, A, B, precision);
35
namespace detail{ namespace bezier_clipping {
36
void portion (std::vector<Point> & B, Interval const& I);
39
void find_intersections(std::vector<std::pair<double, double> > &xs,
41
D2<SBasis> const & B) {
42
vector<Point> BezA, BezB;
43
sbasis_to_bezier(BezA, A);
44
sbasis_to_bezier(BezB, B);
48
find_intersections_bezier_clipping(xs, BezA, BezB);
50
void find_intersections(std::vector< std::pair<double, double> > & xs,
51
std::vector<Point> const& A,
52
std::vector<Point> const& B,
54
find_intersections_bezier_clipping(xs, A, B, precision);
60
* split the curve at the midpoint, returning an array with the two parts
61
* Temporary storage is minimized by using part of the storage for the result
62
* to hold an intermediate value until it is no longer needed.
64
void split(vector<Point> const &p, double t,
65
vector<Point> &left, vector<Point> &right) {
66
const unsigned sz = p.size();
67
Geom::Point Vtemp[sz][sz];
69
/* Copy control points */
70
std::copy(p.begin(), p.end(), Vtemp[0]);
72
/* Triangle computation */
73
for (unsigned i = 1; i < sz; i++) {
74
for (unsigned j = 0; j < sz - i; j++) {
75
Vtemp[i][j] = lerp(t, Vtemp[i-1][j], Vtemp[i-1][j+1]);
81
for (unsigned j = 0; j < sz; j++)
82
left[j] = Vtemp[j][0];
83
for (unsigned j = 0; j < sz; j++)
84
right[j] = Vtemp[sz-1-j][j];
89
find_self_intersections(std::vector<std::pair<double, double> > &xs,
90
D2<SBasis> const & A) {
91
vector<double> dr = roots(derivative(A[X]));
93
vector<double> dyr = roots(derivative(A[Y]));
94
dr.insert(dr.begin(), dyr.begin(), dyr.end());
98
// We want to be sure that we have no empty segments
99
sort(dr.begin(), dr.end());
100
vector<double>::iterator new_end = unique(dr.begin(), dr.end());
101
dr.resize( new_end - dr.begin() );
103
vector<vector<Point> > pieces;
105
vector<Point> in, l, r;
106
sbasis_to_bezier(in, A);
107
for(unsigned i = 0; i < dr.size()-1; i++) {
108
split(in, (dr[i+1]-dr[i]) / (1 - dr[i]), l, r);
114
for(unsigned i = 0; i < dr.size()-1; i++) {
115
for(unsigned j = i+1; j < dr.size()-1; j++) {
116
std::vector<std::pair<double, double> > section;
118
find_intersections( section, pieces[i], pieces[j]);
119
for(unsigned k = 0; k < section.size(); k++) {
120
double l = section[k].first;
121
double r = section[k].second;
122
// XXX: This condition will prune out false positives, but it might create some false negatives. Todo: Confirm it is correct.
124
//if((l == 1) && (r == 0))
125
if( ( l > 1-1e-4 ) && (r < 1e-4) )//FIXME: what precision should be used here???
127
xs.push_back(std::make_pair((1-l)*dr[i] + l*dr[i+1],
128
(1-r)*dr[j] + r*dr[j+1]));
133
// Because i is in order, xs should be roughly already in order?
134
//sort(xs.begin(), xs.end());
135
//unique(xs.begin(), xs.end());
139
#include <gsl/gsl_multiroots.h>
148
intersect_polish_f (const gsl_vector * x, void *params,
151
const double x0 = gsl_vector_get (x, 0);
152
const double x1 = gsl_vector_get (x, 1);
154
Geom::Point dx = ((struct rparams *) params)->A(x0) -
155
((struct rparams *) params)->B(x1);
157
gsl_vector_set (f, 0, dx[0]);
158
gsl_vector_set (f, 1, dx[1]);
169
static double EpsilonBy(double value, int eps)
178
static void intersect_polish_root (D2<SBasis> const &A, double &s,
179
D2<SBasis> const &B, double &t) {
181
const gsl_multiroot_fsolver_type *T;
182
gsl_multiroot_fsolver *sol;
187
std::vector<Point> as, bs;
188
as = A.valueAndDerivatives(s, 2);
189
bs = B.valueAndDerivatives(t, 2);
190
Point F = as[0] - bs[0];
191
double best = dot(F, F);
193
for(int i = 0; i < 4; i++) {
199
|dA(s)[0] -dB(t)[0]| (X1 - X0) = A(s) - B(t)
203
// We're using the standard transformation matricies, which is numerically rather poor. Much better to solve the equation using elimination.
205
Matrix jack(as[1][0], as[1][1],
206
-bs[1][0], -bs[1][1],
208
Point soln = (F)*jack.inverse();
209
double ns = s - soln[0];
210
double nt = t - soln[1];
212
as = A.valueAndDerivatives(ns, 2);
213
bs = B.valueAndDerivatives(nt, 2);
215
double trial = dot(F, F);
216
if (trial > best*0.1) {// we have standards, you know
217
// At this point we could do a line search
227
struct rparams p = {A, B};
228
gsl_multiroot_function f = {&intersect_polish_f, n, &p};
230
double x_init[2] = {s, t};
231
gsl_vector *x = gsl_vector_alloc (n);
233
gsl_vector_set (x, 0, x_init[0]);
234
gsl_vector_set (x, 1, x_init[1]);
236
T = gsl_multiroot_fsolver_hybrids;
237
sol = gsl_multiroot_fsolver_alloc (T, 2);
238
gsl_multiroot_fsolver_set (sol, &f, x);
243
status = gsl_multiroot_fsolver_iterate (sol);
245
if (status) /* check if solver is stuck */
249
gsl_multiroot_test_residual (sol->f, 1e-12);
251
while (status == GSL_CONTINUE && iter < 1000);
253
s = gsl_vector_get (sol->x, 0);
254
t = gsl_vector_get (sol->x, 1);
256
gsl_multiroot_fsolver_free (sol);
261
// This code does a neighbourhood search for minor improvements.
262
double best_v = L1(A(s) - B(t));
263
//std::cout << "------\n" << best_v << std::endl;
267
double trial_v = best_v;
268
for(int nsi = -1; nsi < 2; nsi++) {
269
for(int nti = -1; nti < 2; nti++) {
270
Point n(EpsilonBy(best[0], nsi),
271
EpsilonBy(best[1], nti));
272
double c = L1(A(n[0]) - B(n[1]));
273
//std::cout << c << "; ";
281
//std::cout << "\n" << s << " -> " << s - best[0] << std::endl;
282
//std::cout << t << " -> " << t - best[1] << std::endl;
283
//std::cout << best_v << std::endl;
296
void polish_intersections(std::vector<std::pair<double, double> > &xs,
297
D2<SBasis> const &A, D2<SBasis> const &B)
299
for(unsigned i = 0; i < xs.size(); i++)
300
intersect_polish_root(A, xs[i].first,
306
* Compute the Hausdorf distance from A to B only.
311
/** Compute the value of a bezier
312
Todo: find a good palce for this.
314
// suggested by Sederberg.
315
Point OldBezier::operator()(double t) const {
317
double u, bc, tn, tmp;
320
for(int dim = 0; dim < 2; dim++) {
328
tmp = (tmp + tn*bc*p[i][dim])*u;
330
r[dim] = (tmp + tn*t*p[n][dim]);
337
* Compute the Hausdorf distance from A to B only.
339
double hausdorfl(D2<SBasis>& A, D2<SBasis> const& B,
341
double *a_t, double* b_t) {
342
std::vector< std::pair<double, double> > xs;
343
std::vector<Point> Az, Bz;
344
sbasis_to_bezier (Az, A);
345
sbasis_to_bezier (Bz, B);
346
find_collinear_normal(xs, Az, Bz, m_precision);
347
double h_dist = 0, h_a_t = 0, h_b_t = 0;
350
double t = Geom::nearest_point(Ax, B);
351
dist = Geom::distance(Ax, B(t));
358
t = Geom::nearest_point(Ax, B);
359
dist = Geom::distance(Ax, B(t));
365
for (size_t i = 0; i < xs.size(); ++i)
367
Point At = A(xs[i].first);
368
Point Bu = B(xs[i].second);
369
double distAtBu = Geom::distance(At, Bu);
370
t = Geom::nearest_point(At, B);
371
dist = Geom::distance(At, B(t));
372
//FIXME: we might miss it due to floating point precision...
373
if (dist >= distAtBu-.1 && distAtBu > h_dist) {
375
h_b_t = xs[i].second;
380
if(a_t) *a_t = h_a_t;
381
if(b_t) *b_t = h_b_t;
387
* Compute the symmetric Hausdorf distance.
389
double hausdorf(D2<SBasis>& A, D2<SBasis> const& B,
391
double *a_t, double* b_t) {
392
double h_dist = hausdorfl(A, B, m_precision, a_t, b_t);
396
double t = Geom::nearest_point(Bx, A);
397
dist = Geom::distance(Bx, A(t));
404
t = Geom::nearest_point(Bx, A);
405
dist = Geom::distance(Bx, A(t));
419
c-file-style:"stroustrup"
420
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
425
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :