xref: /AOO41X/main/basegfx/source/workbench/bezierclip.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1*cdf0e10cSrcweir /*************************************************************************
2*cdf0e10cSrcweir  *
3*cdf0e10cSrcweir  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4*cdf0e10cSrcweir  *
5*cdf0e10cSrcweir  * Copyright 2000, 2010 Oracle and/or its affiliates.
6*cdf0e10cSrcweir  *
7*cdf0e10cSrcweir  * OpenOffice.org - a multi-platform office productivity suite
8*cdf0e10cSrcweir  *
9*cdf0e10cSrcweir  * This file is part of OpenOffice.org.
10*cdf0e10cSrcweir  *
11*cdf0e10cSrcweir  * OpenOffice.org is free software: you can redistribute it and/or modify
12*cdf0e10cSrcweir  * it under the terms of the GNU Lesser General Public License version 3
13*cdf0e10cSrcweir  * only, as published by the Free Software Foundation.
14*cdf0e10cSrcweir  *
15*cdf0e10cSrcweir  * OpenOffice.org is distributed in the hope that it will be useful,
16*cdf0e10cSrcweir  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*cdf0e10cSrcweir  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*cdf0e10cSrcweir  * GNU Lesser General Public License version 3 for more details
19*cdf0e10cSrcweir  * (a copy is included in the LICENSE file that accompanied this code).
20*cdf0e10cSrcweir  *
21*cdf0e10cSrcweir  * You should have received a copy of the GNU Lesser General Public License
22*cdf0e10cSrcweir  * version 3 along with OpenOffice.org.  If not, see
23*cdf0e10cSrcweir  * <http://www.openoffice.org/license.html>
24*cdf0e10cSrcweir  * for a copy of the LGPLv3 License.
25*cdf0e10cSrcweir  *
26*cdf0e10cSrcweir  ************************************************************************/
27*cdf0e10cSrcweir 
28*cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
29*cdf0e10cSrcweir #include "precompiled_basegfx.hxx"
30*cdf0e10cSrcweir 
31*cdf0e10cSrcweir #include <algorithm>
32*cdf0e10cSrcweir #include <iterator>
33*cdf0e10cSrcweir #include <vector>
34*cdf0e10cSrcweir #include <utility>
35*cdf0e10cSrcweir 
36*cdf0e10cSrcweir #include <math.h>
37*cdf0e10cSrcweir 
38*cdf0e10cSrcweir #include "bezierclip.hxx"
39*cdf0e10cSrcweir #include "gauss.hxx"
40*cdf0e10cSrcweir 
41*cdf0e10cSrcweir 
42*cdf0e10cSrcweir 
43*cdf0e10cSrcweir // what to test
44*cdf0e10cSrcweir #define WITH_ASSERTIONS
45*cdf0e10cSrcweir //#define WITH_CONVEXHULL_TEST
46*cdf0e10cSrcweir //#define WITH_MULTISUBDIVIDE_TEST
47*cdf0e10cSrcweir //#define WITH_FATLINE_TEST
48*cdf0e10cSrcweir //#define WITH_CALCFOCUS_TEST
49*cdf0e10cSrcweir //#define WITH_SAFEPARAMBASE_TEST
50*cdf0e10cSrcweir //#define WITH_SAFEPARAMS_TEST
51*cdf0e10cSrcweir //#define WITH_SAFEPARAM_DETAILED_TEST
52*cdf0e10cSrcweir //#define WITH_SAFEFOCUSPARAM_CALCFOCUS
53*cdf0e10cSrcweir //#define WITH_SAFEFOCUSPARAM_TEST
54*cdf0e10cSrcweir //#define WITH_SAFEFOCUSPARAM_DETAILED_TEST
55*cdf0e10cSrcweir #define WITH_BEZIERCLIP_TEST
56*cdf0e10cSrcweir 
57*cdf0e10cSrcweir 
58*cdf0e10cSrcweir 
59*cdf0e10cSrcweir // -----------------------------------------------------------------------------
60*cdf0e10cSrcweir 
61*cdf0e10cSrcweir /* Implementation of the so-called 'Fat-Line Bezier Clipping Algorithm' by Sederberg et al.
62*cdf0e10cSrcweir  *
63*cdf0e10cSrcweir  * Actual reference is: T. W. Sederberg and T Nishita: Curve
64*cdf0e10cSrcweir  * intersection using Bezier clipping. In Computer Aided Design, 22
65*cdf0e10cSrcweir  * (9), 1990, pp. 538--549
66*cdf0e10cSrcweir  */
67*cdf0e10cSrcweir 
68*cdf0e10cSrcweir // -----------------------------------------------------------------------------
69*cdf0e10cSrcweir 
70*cdf0e10cSrcweir /* Misc helper
71*cdf0e10cSrcweir  * ===========
72*cdf0e10cSrcweir  */
73*cdf0e10cSrcweir int fallFac( int n, int k )
74*cdf0e10cSrcweir {
75*cdf0e10cSrcweir #ifdef WITH_ASSERTIONS
76*cdf0e10cSrcweir     assert(n>=k); // "For factorials, n must be greater or equal k"
77*cdf0e10cSrcweir     assert(n>=0); // "For factorials, n must be positive"
78*cdf0e10cSrcweir     assert(k>=0); // "For factorials, k must be positive"
79*cdf0e10cSrcweir #endif
80*cdf0e10cSrcweir 
81*cdf0e10cSrcweir     int res( 1 );
82*cdf0e10cSrcweir 
83*cdf0e10cSrcweir     while( k-- && n ) res *= n--;
84*cdf0e10cSrcweir 
85*cdf0e10cSrcweir     return res;
86*cdf0e10cSrcweir }
87*cdf0e10cSrcweir 
88*cdf0e10cSrcweir // -----------------------------------------------------------------------------
89*cdf0e10cSrcweir 
90*cdf0e10cSrcweir int fac( int n )
91*cdf0e10cSrcweir {
92*cdf0e10cSrcweir     return fallFac(n, n);
93*cdf0e10cSrcweir }
94*cdf0e10cSrcweir 
95*cdf0e10cSrcweir // -----------------------------------------------------------------------------
96*cdf0e10cSrcweir 
97*cdf0e10cSrcweir /* Bezier fat line clipping part
98*cdf0e10cSrcweir  * =============================
99*cdf0e10cSrcweir  */
100*cdf0e10cSrcweir 
101*cdf0e10cSrcweir // -----------------------------------------------------------------------------
102*cdf0e10cSrcweir 
103*cdf0e10cSrcweir void Impl_calcFatLine( FatLine& line, const Bezier& c )
104*cdf0e10cSrcweir {
105*cdf0e10cSrcweir     // Prepare normalized implicit line
106*cdf0e10cSrcweir     // ================================
107*cdf0e10cSrcweir 
108*cdf0e10cSrcweir     // calculate vector orthogonal to p1-p4:
109*cdf0e10cSrcweir     line.a = -(c.p0.y - c.p3.y);
110*cdf0e10cSrcweir     line.b = (c.p0.x - c.p3.x);
111*cdf0e10cSrcweir 
112*cdf0e10cSrcweir     // normalize
113*cdf0e10cSrcweir     const double len( sqrt( line.a*line.a + line.b*line.b ) );
114*cdf0e10cSrcweir     if( !tolZero(len) )
115*cdf0e10cSrcweir     {
116*cdf0e10cSrcweir         line.a /= len;
117*cdf0e10cSrcweir         line.b /= len;
118*cdf0e10cSrcweir     }
119*cdf0e10cSrcweir 
120*cdf0e10cSrcweir     line.c = -(line.a*c.p0.x + line.b*c.p0.y);
121*cdf0e10cSrcweir 
122*cdf0e10cSrcweir 
123*cdf0e10cSrcweir     // Determine bounding fat line from it
124*cdf0e10cSrcweir     // ===================================
125*cdf0e10cSrcweir 
126*cdf0e10cSrcweir     // calc control point distances
127*cdf0e10cSrcweir     const double dP2( calcLineDistance(line.a, line.b, line.c, c.p1.x, c.p1.y ) );
128*cdf0e10cSrcweir     const double dP3( calcLineDistance(line.a, line.b, line.c, c.p2.x, c.p2.y ) );
129*cdf0e10cSrcweir 
130*cdf0e10cSrcweir     // calc approximate bounding lines to curve (tight bounds are
131*cdf0e10cSrcweir     // possible here, but more expensive to calculate and thus not
132*cdf0e10cSrcweir     // worth the overhead)
133*cdf0e10cSrcweir     if( dP2 * dP3 > 0.0 )
134*cdf0e10cSrcweir     {
135*cdf0e10cSrcweir         line.dMin = 3.0/4.0 * ::std::min(0.0, ::std::min(dP2, dP3));
136*cdf0e10cSrcweir         line.dMax = 3.0/4.0 * ::std::max(0.0, ::std::max(dP2, dP3));
137*cdf0e10cSrcweir     }
138*cdf0e10cSrcweir     else
139*cdf0e10cSrcweir     {
140*cdf0e10cSrcweir         line.dMin = 4.0/9.0 * ::std::min(0.0, ::std::min(dP2, dP3));
141*cdf0e10cSrcweir         line.dMax = 4.0/9.0 * ::std::max(0.0, ::std::max(dP2, dP3));
142*cdf0e10cSrcweir     }
143*cdf0e10cSrcweir }
144*cdf0e10cSrcweir 
145*cdf0e10cSrcweir void Impl_calcBounds( Point2D& 			leftTop,
146*cdf0e10cSrcweir                       Point2D& 			rightBottom,
147*cdf0e10cSrcweir                       const Bezier& 	c1 			)
148*cdf0e10cSrcweir {
149*cdf0e10cSrcweir     leftTop.x = ::std::min( c1.p0.x, ::std::min( c1.p1.x, ::std::min( c1.p2.x, c1.p3.x ) ) );
150*cdf0e10cSrcweir     leftTop.y = ::std::min( c1.p0.y, ::std::min( c1.p1.y, ::std::min( c1.p2.y, c1.p3.y ) ) );
151*cdf0e10cSrcweir     rightBottom.x = ::std::max( c1.p0.x, ::std::max( c1.p1.x, ::std::max( c1.p2.x, c1.p3.x ) ) );
152*cdf0e10cSrcweir     rightBottom.y = ::std::max( c1.p0.y, ::std::max( c1.p1.y, ::std::max( c1.p2.y, c1.p3.y ) ) );
153*cdf0e10cSrcweir }
154*cdf0e10cSrcweir 
155*cdf0e10cSrcweir bool Impl_doBBoxIntersect( const Bezier& c1,
156*cdf0e10cSrcweir                            const Bezier& c2 )
157*cdf0e10cSrcweir {
158*cdf0e10cSrcweir     // calc rectangular boxes from c1 and c2
159*cdf0e10cSrcweir     Point2D lt1;
160*cdf0e10cSrcweir     Point2D rb1;
161*cdf0e10cSrcweir     Point2D lt2;
162*cdf0e10cSrcweir     Point2D rb2;
163*cdf0e10cSrcweir 
164*cdf0e10cSrcweir     Impl_calcBounds( lt1, rb1, c1 );
165*cdf0e10cSrcweir     Impl_calcBounds( lt2, rb2, c2 );
166*cdf0e10cSrcweir 
167*cdf0e10cSrcweir     if( ::std::min(rb1.x, rb2.x) < ::std::max(lt1.x, lt2.x) ||
168*cdf0e10cSrcweir         ::std::min(rb1.y, rb2.y) < ::std::max(lt1.y, lt2.y) )
169*cdf0e10cSrcweir     {
170*cdf0e10cSrcweir         return false;
171*cdf0e10cSrcweir     }
172*cdf0e10cSrcweir     else
173*cdf0e10cSrcweir     {
174*cdf0e10cSrcweir         return true;
175*cdf0e10cSrcweir     }
176*cdf0e10cSrcweir }
177*cdf0e10cSrcweir 
178*cdf0e10cSrcweir /* calculates two t's for the given bernstein control polygon: the first is
179*cdf0e10cSrcweir  * the intersection of the min value line with the convex hull from
180*cdf0e10cSrcweir  * the left, the second is the intersection of the max value line with
181*cdf0e10cSrcweir  * the convex hull from the right.
182*cdf0e10cSrcweir  */
183*cdf0e10cSrcweir bool Impl_calcSafeParams( double& 			t1,
184*cdf0e10cSrcweir                           double& 			t2,
185*cdf0e10cSrcweir                           const Polygon2D&	rPoly,
186*cdf0e10cSrcweir                           double			lowerYBound,
187*cdf0e10cSrcweir                           double			upperYBound )
188*cdf0e10cSrcweir {
189*cdf0e10cSrcweir     // need the convex hull of the control polygon, as this is
190*cdf0e10cSrcweir     // guaranteed to completely bound the curve
191*cdf0e10cSrcweir     Polygon2D convHull( convexHull(rPoly) );
192*cdf0e10cSrcweir 
193*cdf0e10cSrcweir     // init min and max buffers
194*cdf0e10cSrcweir     t1 = 0.0 ;
195*cdf0e10cSrcweir     double currLowerT( 1.0 );
196*cdf0e10cSrcweir 
197*cdf0e10cSrcweir     t2 = 1.0;
198*cdf0e10cSrcweir     double currHigherT( 0.0 );
199*cdf0e10cSrcweir 
200*cdf0e10cSrcweir     if( convHull.size() <= 1 )
201*cdf0e10cSrcweir         return false; // only one point? Then we're done with clipping
202*cdf0e10cSrcweir 
203*cdf0e10cSrcweir     /* now, clip against lower and higher bounds */
204*cdf0e10cSrcweir     Point2D p0;
205*cdf0e10cSrcweir     Point2D p1;
206*cdf0e10cSrcweir 
207*cdf0e10cSrcweir     bool bIntersection( false );
208*cdf0e10cSrcweir 
209*cdf0e10cSrcweir     for( Polygon2D::size_type i=0; i<convHull.size(); ++i )
210*cdf0e10cSrcweir     {
211*cdf0e10cSrcweir         // have to check against convHull.size() segments, as the
212*cdf0e10cSrcweir         // convex hull is, by definition, closed. Thus, for the
213*cdf0e10cSrcweir         // last point, we take the first point as partner.
214*cdf0e10cSrcweir         if( i+1 == convHull.size() )
215*cdf0e10cSrcweir         {
216*cdf0e10cSrcweir             // close the polygon
217*cdf0e10cSrcweir             p0 = convHull[i];
218*cdf0e10cSrcweir             p1 = convHull[0];
219*cdf0e10cSrcweir         }
220*cdf0e10cSrcweir         else
221*cdf0e10cSrcweir         {
222*cdf0e10cSrcweir             p0 = convHull[i];
223*cdf0e10cSrcweir             p1 = convHull[i+1];
224*cdf0e10cSrcweir         }
225*cdf0e10cSrcweir 
226*cdf0e10cSrcweir         // is the segment in question within or crossing the
227*cdf0e10cSrcweir         // horizontal band spanned by lowerYBound and upperYBound? If
228*cdf0e10cSrcweir         // not, we've got no intersection. If yes, we maybe don't have
229*cdf0e10cSrcweir         // an intersection, but we've got to update the permissible
230*cdf0e10cSrcweir         // range, nevertheless. This is because inside lying segments
231*cdf0e10cSrcweir         // leads to full range forbidden.
232*cdf0e10cSrcweir         if( (tolLessEqual(p0.y, upperYBound) || tolLessEqual(p1.y, upperYBound)) &&
233*cdf0e10cSrcweir             (tolGreaterEqual(p0.y, lowerYBound) || tolGreaterEqual(p1.y, lowerYBound)) )
234*cdf0e10cSrcweir         {
235*cdf0e10cSrcweir             // calc intersection of convex hull segment with
236*cdf0e10cSrcweir             // one of the horizontal bounds lines
237*cdf0e10cSrcweir             const double r_x( p1.x - p0.x );
238*cdf0e10cSrcweir             const double r_y( p1.y - p0.y );
239*cdf0e10cSrcweir 
240*cdf0e10cSrcweir             if( tolZero(r_y) )
241*cdf0e10cSrcweir             {
242*cdf0e10cSrcweir                 // r_y is virtually zero, thus we've got a horizontal
243*cdf0e10cSrcweir                 // line. Now check whether we maybe coincide with lower or
244*cdf0e10cSrcweir                 // upper horizonal bound line.
245*cdf0e10cSrcweir                 if( tolEqual(p0.y, lowerYBound) ||
246*cdf0e10cSrcweir                     tolEqual(p0.y, upperYBound) )
247*cdf0e10cSrcweir                 {
248*cdf0e10cSrcweir                     // yes, simulate intersection then
249*cdf0e10cSrcweir                     currLowerT = ::std::min(currLowerT, ::std::min(p0.x, p1.x));
250*cdf0e10cSrcweir                     currHigherT = ::std::max(currHigherT, ::std::max(p0.x, p1.x));
251*cdf0e10cSrcweir                 }
252*cdf0e10cSrcweir             }
253*cdf0e10cSrcweir             else
254*cdf0e10cSrcweir             {
255*cdf0e10cSrcweir                 // check against lower and higher bounds
256*cdf0e10cSrcweir                 // =====================================
257*cdf0e10cSrcweir 
258*cdf0e10cSrcweir                 // calc intersection with horizontal dMin line
259*cdf0e10cSrcweir                 const double currTLow( (lowerYBound - p0.y) * r_x / r_y + p0.x );
260*cdf0e10cSrcweir 
261*cdf0e10cSrcweir                 // calc intersection with horizontal dMax line
262*cdf0e10cSrcweir                 const double currTHigh( (upperYBound - p0.y) * r_x / r_y + p0.x );
263*cdf0e10cSrcweir 
264*cdf0e10cSrcweir                 currLowerT = ::std::min(currLowerT, ::std::min(currTLow, currTHigh));
265*cdf0e10cSrcweir                 currHigherT = ::std::max(currHigherT, ::std::max(currTLow, currTHigh));
266*cdf0e10cSrcweir             }
267*cdf0e10cSrcweir 
268*cdf0e10cSrcweir             // set flag that at least one segment is contained or
269*cdf0e10cSrcweir             // intersects given horizontal band.
270*cdf0e10cSrcweir             bIntersection = true;
271*cdf0e10cSrcweir         }
272*cdf0e10cSrcweir     }
273*cdf0e10cSrcweir 
274*cdf0e10cSrcweir #ifndef WITH_SAFEPARAMBASE_TEST
275*cdf0e10cSrcweir     // limit intersections found to permissible t parameter range
276*cdf0e10cSrcweir     t1 = ::std::max(0.0, currLowerT);
277*cdf0e10cSrcweir     t2 = ::std::min(1.0, currHigherT);
278*cdf0e10cSrcweir #endif
279*cdf0e10cSrcweir 
280*cdf0e10cSrcweir     return bIntersection;
281*cdf0e10cSrcweir }
282*cdf0e10cSrcweir 
283*cdf0e10cSrcweir 
284*cdf0e10cSrcweir /* calculates two t's for the given bernstein polynomial: the first is
285*cdf0e10cSrcweir  * the intersection of the min value line with the convex hull from
286*cdf0e10cSrcweir  * the left, the second is the intersection of the max value line with
287*cdf0e10cSrcweir  * the convex hull from the right.
288*cdf0e10cSrcweir  *
289*cdf0e10cSrcweir  * The polynomial coefficients c0 to c3 given to this method
290*cdf0e10cSrcweir  * must correspond to t values of 0, 1/3, 2/3 and 1, respectively.
291*cdf0e10cSrcweir  */
292*cdf0e10cSrcweir bool Impl_calcSafeParams_clip( double& 			t1,
293*cdf0e10cSrcweir                                double& 			t2,
294*cdf0e10cSrcweir                                const FatLine& 	bounds,
295*cdf0e10cSrcweir                                double  			c0,
296*cdf0e10cSrcweir                                double  			c1,
297*cdf0e10cSrcweir                                double  			c2,
298*cdf0e10cSrcweir                                double  			c3 )
299*cdf0e10cSrcweir {
300*cdf0e10cSrcweir     /* first of all, determine convex hull of c0-c3 */
301*cdf0e10cSrcweir     Polygon2D poly(4);
302*cdf0e10cSrcweir     poly[0] = Point2D(0, 		c0);
303*cdf0e10cSrcweir     poly[1] = Point2D(1.0/3.0, 	c1);
304*cdf0e10cSrcweir     poly[2] = Point2D(2.0/3.0, 	c2);
305*cdf0e10cSrcweir     poly[3] = Point2D(1, 		c3);
306*cdf0e10cSrcweir 
307*cdf0e10cSrcweir #ifndef WITH_SAFEPARAM_DETAILED_TEST
308*cdf0e10cSrcweir 
309*cdf0e10cSrcweir     return Impl_calcSafeParams( t1, t2, poly, bounds.dMin, bounds.dMax );
310*cdf0e10cSrcweir 
311*cdf0e10cSrcweir #else
312*cdf0e10cSrcweir     bool bRet( Impl_calcSafeParams( t1, t2, poly, bounds.dMin, bounds.dMax ) );
313*cdf0e10cSrcweir 
314*cdf0e10cSrcweir     Polygon2D convHull( convexHull( poly ) );
315*cdf0e10cSrcweir 
316*cdf0e10cSrcweir     cout << "# convex hull testing" << endl
317*cdf0e10cSrcweir          << "plot [t=0:1] ";
318*cdf0e10cSrcweir     cout << " bez("
319*cdf0e10cSrcweir          << poly[0].x << ","
320*cdf0e10cSrcweir          << poly[1].x << ","
321*cdf0e10cSrcweir          << poly[2].x << ","
322*cdf0e10cSrcweir          << poly[3].x << ",t),bez("
323*cdf0e10cSrcweir          << poly[0].y << ","
324*cdf0e10cSrcweir          << poly[1].y << ","
325*cdf0e10cSrcweir          << poly[2].y << ","
326*cdf0e10cSrcweir          << poly[3].y << ",t), "
327*cdf0e10cSrcweir          << "t, " << bounds.dMin << ", "
328*cdf0e10cSrcweir          << "t, " << bounds.dMax << ", "
329*cdf0e10cSrcweir          << t1 << ", t, "
330*cdf0e10cSrcweir          << t2 << ", t, "
331*cdf0e10cSrcweir          << "'-' using ($1):($2) title \"control polygon\" with lp, "
332*cdf0e10cSrcweir          << "'-' using ($1):($2) title \"convex hull\" with lp" << endl;
333*cdf0e10cSrcweir 
334*cdf0e10cSrcweir     unsigned int k;
335*cdf0e10cSrcweir     for( k=0; k<poly.size(); ++k )
336*cdf0e10cSrcweir     {
337*cdf0e10cSrcweir         cout << poly[k].x << " " << poly[k].y << endl;
338*cdf0e10cSrcweir     }
339*cdf0e10cSrcweir     cout << poly[0].x << " " << poly[0].y << endl;
340*cdf0e10cSrcweir     cout << "e" << endl;
341*cdf0e10cSrcweir 
342*cdf0e10cSrcweir     for( k=0; k<convHull.size(); ++k )
343*cdf0e10cSrcweir     {
344*cdf0e10cSrcweir         cout << convHull[k].x << " " << convHull[k].y << endl;
345*cdf0e10cSrcweir     }
346*cdf0e10cSrcweir     cout << convHull[0].x << " " << convHull[0].y << endl;
347*cdf0e10cSrcweir     cout << "e" << endl;
348*cdf0e10cSrcweir 
349*cdf0e10cSrcweir     return bRet;
350*cdf0e10cSrcweir #endif
351*cdf0e10cSrcweir }
352*cdf0e10cSrcweir 
353*cdf0e10cSrcweir // -----------------------------------------------------------------------------
354*cdf0e10cSrcweir 
355*cdf0e10cSrcweir void Impl_deCasteljauAt( Bezier& 		part1,
356*cdf0e10cSrcweir 						 Bezier& 		part2,
357*cdf0e10cSrcweir 						 const Bezier& 	input,
358*cdf0e10cSrcweir 						 double			t		 )
359*cdf0e10cSrcweir {
360*cdf0e10cSrcweir 	// deCasteljau bezier arc, scheme is:
361*cdf0e10cSrcweir 	//
362*cdf0e10cSrcweir 	// First row is    C_0^n,C_1^n,...,C_n^n
363*cdf0e10cSrcweir 	// Second row is         P_1^n,...,P_n^n
364*cdf0e10cSrcweir 	// etc.
365*cdf0e10cSrcweir 	// with P_k^r = (1 - x_s)P_{k-1}^{r-1} + x_s P_k{r-1}
366*cdf0e10cSrcweir 	//
367*cdf0e10cSrcweir 	// this results in:
368*cdf0e10cSrcweir 	//
369*cdf0e10cSrcweir 	// P1  P2  P3  P4
370*cdf0e10cSrcweir 	// L1  P2  P3  R4
371*cdf0e10cSrcweir     //     L2  H   R3
372*cdf0e10cSrcweir     //         L3  R2
373*cdf0e10cSrcweir     //             L4/R1
374*cdf0e10cSrcweir     if( tolZero(t) )
375*cdf0e10cSrcweir     {
376*cdf0e10cSrcweir         // t is zero -> part2 is input curve, part1 is empty (input.p0, that is)
377*cdf0e10cSrcweir         part1.p0.x = part1.p1.x = part1.p2.x = part1.p3.x = input.p0.x;
378*cdf0e10cSrcweir         part1.p0.y = part1.p1.y = part1.p2.y = part1.p3.y = input.p0.y;
379*cdf0e10cSrcweir         part2 = input;
380*cdf0e10cSrcweir     }
381*cdf0e10cSrcweir     else if( tolEqual(t, 1.0) )
382*cdf0e10cSrcweir     {
383*cdf0e10cSrcweir         // t is one -> part1 is input curve, part2 is empty (input.p3, that is)
384*cdf0e10cSrcweir         part1 = input;
385*cdf0e10cSrcweir         part2.p0.x = part2.p1.x = part2.p2.x = part2.p3.x = input.p3.x;
386*cdf0e10cSrcweir         part2.p0.y = part2.p1.y = part2.p2.y = part2.p3.y = input.p3.y;
387*cdf0e10cSrcweir     }
388*cdf0e10cSrcweir     else
389*cdf0e10cSrcweir     {
390*cdf0e10cSrcweir         part1.p0.x = input.p0.x; 		   	 						part1.p0.y = input.p0.y;
391*cdf0e10cSrcweir         part1.p1.x = (1.0 - t)*part1.p0.x + t*input.p1.x; 			part1.p1.y = (1.0 - t)*part1.p0.y + t*input.p1.y;
392*cdf0e10cSrcweir         const double Hx ( (1.0 - t)*input.p1.x + t*input.p2.x ), 	Hy ( (1.0 - t)*input.p1.y + t*input.p2.y );
393*cdf0e10cSrcweir         part1.p2.x = (1.0 - t)*part1.p1.x + t*Hx;   				part1.p2.y = (1.0 - t)*part1.p1.y + t*Hy;
394*cdf0e10cSrcweir         part2.p3.x = input.p3.x; 		   	        				part2.p3.y = input.p3.y;
395*cdf0e10cSrcweir         part2.p2.x = (1.0 - t)*input.p2.x + t*input.p3.x;  			part2.p2.y = (1.0 - t)*input.p2.y + t*input.p3.y;
396*cdf0e10cSrcweir         part2.p1.x = (1.0 - t)*Hx + t*part2.p2.x;   				part2.p1.y = (1.0 - t)*Hy + t*part2.p2.y;
397*cdf0e10cSrcweir         part2.p0.x = (1.0 - t)*part1.p2.x + t*part2.p1.x;  			part2.p0.y = (1.0 - t)*part1.p2.y + t*part2.p1.y;
398*cdf0e10cSrcweir         part1.p3.x = part2.p0.x; 		            				part1.p3.y = part2.p0.y;
399*cdf0e10cSrcweir     }
400*cdf0e10cSrcweir }
401*cdf0e10cSrcweir 
402*cdf0e10cSrcweir // -----------------------------------------------------------------------------
403*cdf0e10cSrcweir 
404*cdf0e10cSrcweir void printCurvesWithSafeRange( const Bezier& c1, const Bezier& c2, double t1_c1, double t2_c1,
405*cdf0e10cSrcweir                                const Bezier& c2_part, const FatLine& bounds_c2 )
406*cdf0e10cSrcweir {
407*cdf0e10cSrcweir     static int offset = 0;
408*cdf0e10cSrcweir 
409*cdf0e10cSrcweir     cout << "# safe param range testing" << endl
410*cdf0e10cSrcweir          << "plot [t=0.0:1.0] ";
411*cdf0e10cSrcweir 
412*cdf0e10cSrcweir     // clip safe ranges off c1
413*cdf0e10cSrcweir     Bezier c1_part1;
414*cdf0e10cSrcweir     Bezier c1_part2;
415*cdf0e10cSrcweir     Bezier c1_part3;
416*cdf0e10cSrcweir 
417*cdf0e10cSrcweir     // subdivide at t1_c1
418*cdf0e10cSrcweir     Impl_deCasteljauAt( c1_part1, c1_part2, c1, t1_c1 );
419*cdf0e10cSrcweir     // subdivide at t2_c1
420*cdf0e10cSrcweir     Impl_deCasteljauAt( c1_part1, c1_part3, c1_part2, t2_c1 );
421*cdf0e10cSrcweir 
422*cdf0e10cSrcweir     // output remaining segment (c1_part1)
423*cdf0e10cSrcweir 
424*cdf0e10cSrcweir     cout << "bez("
425*cdf0e10cSrcweir          << c1.p0.x+offset << ","
426*cdf0e10cSrcweir          << c1.p1.x+offset << ","
427*cdf0e10cSrcweir          << c1.p2.x+offset << ","
428*cdf0e10cSrcweir          << c1.p3.x+offset << ",t),bez("
429*cdf0e10cSrcweir          << c1.p0.y << ","
430*cdf0e10cSrcweir          << c1.p1.y << ","
431*cdf0e10cSrcweir          << c1.p2.y << ","
432*cdf0e10cSrcweir          << c1.p3.y << ",t), bez("
433*cdf0e10cSrcweir          << c2.p0.x+offset << ","
434*cdf0e10cSrcweir          << c2.p1.x+offset << ","
435*cdf0e10cSrcweir          << c2.p2.x+offset << ","
436*cdf0e10cSrcweir          << c2.p3.x+offset << ",t),bez("
437*cdf0e10cSrcweir          << c2.p0.y << ","
438*cdf0e10cSrcweir          << c2.p1.y << ","
439*cdf0e10cSrcweir          << c2.p2.y << ","
440*cdf0e10cSrcweir          << c2.p3.y << ",t), "
441*cdf0e10cSrcweir #if 1
442*cdf0e10cSrcweir          << "bez("
443*cdf0e10cSrcweir          << c1_part1.p0.x+offset << ","
444*cdf0e10cSrcweir          << c1_part1.p1.x+offset << ","
445*cdf0e10cSrcweir          << c1_part1.p2.x+offset << ","
446*cdf0e10cSrcweir          << c1_part1.p3.x+offset << ",t),bez("
447*cdf0e10cSrcweir          << c1_part1.p0.y << ","
448*cdf0e10cSrcweir          << c1_part1.p1.y << ","
449*cdf0e10cSrcweir          << c1_part1.p2.y << ","
450*cdf0e10cSrcweir          << c1_part1.p3.y << ",t), "
451*cdf0e10cSrcweir #endif
452*cdf0e10cSrcweir #if 1
453*cdf0e10cSrcweir          << "bez("
454*cdf0e10cSrcweir          << c2_part.p0.x+offset << ","
455*cdf0e10cSrcweir          << c2_part.p1.x+offset << ","
456*cdf0e10cSrcweir          << c2_part.p2.x+offset << ","
457*cdf0e10cSrcweir          << c2_part.p3.x+offset << ",t),bez("
458*cdf0e10cSrcweir          << c2_part.p0.y << ","
459*cdf0e10cSrcweir          << c2_part.p1.y << ","
460*cdf0e10cSrcweir          << c2_part.p2.y << ","
461*cdf0e10cSrcweir          << c2_part.p3.y << ",t), "
462*cdf0e10cSrcweir #endif
463*cdf0e10cSrcweir          << "linex("
464*cdf0e10cSrcweir          << bounds_c2.a << ","
465*cdf0e10cSrcweir          << bounds_c2.b << ","
466*cdf0e10cSrcweir          << bounds_c2.c << ",t)+" << offset << ", liney("
467*cdf0e10cSrcweir          << bounds_c2.a << ","
468*cdf0e10cSrcweir          << bounds_c2.b << ","
469*cdf0e10cSrcweir          << bounds_c2.c << ",t) title \"fat line (center)\", linex("
470*cdf0e10cSrcweir          << bounds_c2.a << ","
471*cdf0e10cSrcweir          << bounds_c2.b << ","
472*cdf0e10cSrcweir          << bounds_c2.c-bounds_c2.dMin << ",t)+" << offset << ", liney("
473*cdf0e10cSrcweir          << bounds_c2.a << ","
474*cdf0e10cSrcweir          << bounds_c2.b << ","
475*cdf0e10cSrcweir          << bounds_c2.c-bounds_c2.dMin << ",t) title \"fat line (min) \", linex("
476*cdf0e10cSrcweir          << bounds_c2.a << ","
477*cdf0e10cSrcweir          << bounds_c2.b << ","
478*cdf0e10cSrcweir          << bounds_c2.c-bounds_c2.dMax << ",t)+" << offset << ", liney("
479*cdf0e10cSrcweir          << bounds_c2.a << ","
480*cdf0e10cSrcweir          << bounds_c2.b << ","
481*cdf0e10cSrcweir          << bounds_c2.c-bounds_c2.dMax << ",t) title \"fat line (max) \"" << endl;
482*cdf0e10cSrcweir 
483*cdf0e10cSrcweir     offset += 1;
484*cdf0e10cSrcweir }
485*cdf0e10cSrcweir 
486*cdf0e10cSrcweir // -----------------------------------------------------------------------------
487*cdf0e10cSrcweir 
488*cdf0e10cSrcweir void printResultWithFinalCurves( const Bezier& c1, const Bezier& c1_part,
489*cdf0e10cSrcweir                                  const Bezier& c2, const Bezier& c2_part,
490*cdf0e10cSrcweir                                  double t1_c1, double t2_c1 )
491*cdf0e10cSrcweir {
492*cdf0e10cSrcweir     static int offset = 0;
493*cdf0e10cSrcweir 
494*cdf0e10cSrcweir     cout << "# final result" << endl
495*cdf0e10cSrcweir          << "plot [t=0.0:1.0] ";
496*cdf0e10cSrcweir 
497*cdf0e10cSrcweir     cout << "bez("
498*cdf0e10cSrcweir          << c1.p0.x+offset << ","
499*cdf0e10cSrcweir          << c1.p1.x+offset << ","
500*cdf0e10cSrcweir          << c1.p2.x+offset << ","
501*cdf0e10cSrcweir          << c1.p3.x+offset << ",t),bez("
502*cdf0e10cSrcweir          << c1.p0.y << ","
503*cdf0e10cSrcweir          << c1.p1.y << ","
504*cdf0e10cSrcweir          << c1.p2.y << ","
505*cdf0e10cSrcweir          << c1.p3.y << ",t), bez("
506*cdf0e10cSrcweir          << c1_part.p0.x+offset << ","
507*cdf0e10cSrcweir          << c1_part.p1.x+offset << ","
508*cdf0e10cSrcweir          << c1_part.p2.x+offset << ","
509*cdf0e10cSrcweir          << c1_part.p3.x+offset << ",t),bez("
510*cdf0e10cSrcweir          << c1_part.p0.y << ","
511*cdf0e10cSrcweir          << c1_part.p1.y << ","
512*cdf0e10cSrcweir          << c1_part.p2.y << ","
513*cdf0e10cSrcweir          << c1_part.p3.y << ",t), "
514*cdf0e10cSrcweir          << " pointmarkx(bez("
515*cdf0e10cSrcweir          << c1.p0.x+offset << ","
516*cdf0e10cSrcweir          << c1.p1.x+offset << ","
517*cdf0e10cSrcweir          << c1.p2.x+offset << ","
518*cdf0e10cSrcweir          << c1.p3.x+offset << ","
519*cdf0e10cSrcweir          << t1_c1 << "),t), "
520*cdf0e10cSrcweir          << " pointmarky(bez("
521*cdf0e10cSrcweir          << c1.p0.y << ","
522*cdf0e10cSrcweir          << c1.p1.y << ","
523*cdf0e10cSrcweir          << c1.p2.y << ","
524*cdf0e10cSrcweir          << c1.p3.y << ","
525*cdf0e10cSrcweir          << t1_c1 << "),t), "
526*cdf0e10cSrcweir          << " pointmarkx(bez("
527*cdf0e10cSrcweir          << c1.p0.x+offset << ","
528*cdf0e10cSrcweir          << c1.p1.x+offset << ","
529*cdf0e10cSrcweir          << c1.p2.x+offset << ","
530*cdf0e10cSrcweir          << c1.p3.x+offset << ","
531*cdf0e10cSrcweir          << t2_c1 << "),t), "
532*cdf0e10cSrcweir          << " pointmarky(bez("
533*cdf0e10cSrcweir          << c1.p0.y << ","
534*cdf0e10cSrcweir          << c1.p1.y << ","
535*cdf0e10cSrcweir          << c1.p2.y << ","
536*cdf0e10cSrcweir          << c1.p3.y << ","
537*cdf0e10cSrcweir          << t2_c1 << "),t), "
538*cdf0e10cSrcweir 
539*cdf0e10cSrcweir          << "bez("
540*cdf0e10cSrcweir          << c2.p0.x+offset << ","
541*cdf0e10cSrcweir          << c2.p1.x+offset << ","
542*cdf0e10cSrcweir          << c2.p2.x+offset << ","
543*cdf0e10cSrcweir          << c2.p3.x+offset << ",t),bez("
544*cdf0e10cSrcweir          << c2.p0.y << ","
545*cdf0e10cSrcweir          << c2.p1.y << ","
546*cdf0e10cSrcweir          << c2.p2.y << ","
547*cdf0e10cSrcweir          << c2.p3.y << ",t), "
548*cdf0e10cSrcweir          << "bez("
549*cdf0e10cSrcweir          << c2_part.p0.x+offset << ","
550*cdf0e10cSrcweir          << c2_part.p1.x+offset << ","
551*cdf0e10cSrcweir          << c2_part.p2.x+offset << ","
552*cdf0e10cSrcweir          << c2_part.p3.x+offset << ",t),bez("
553*cdf0e10cSrcweir          << c2_part.p0.y << ","
554*cdf0e10cSrcweir          << c2_part.p1.y << ","
555*cdf0e10cSrcweir          << c2_part.p2.y << ","
556*cdf0e10cSrcweir          << c2_part.p3.y << ",t)" << endl;
557*cdf0e10cSrcweir 
558*cdf0e10cSrcweir     offset += 1;
559*cdf0e10cSrcweir }
560*cdf0e10cSrcweir 
561*cdf0e10cSrcweir // -----------------------------------------------------------------------------
562*cdf0e10cSrcweir 
563*cdf0e10cSrcweir /** determine parameter ranges [0,t1) and (t2,1] on c1, where c1 is guaranteed to lie outside c2.
564*cdf0e10cSrcweir   	Returns false, if the two curves don't even intersect.
565*cdf0e10cSrcweir 
566*cdf0e10cSrcweir     @param t1
567*cdf0e10cSrcweir     Range [0,t1) on c1 is guaranteed to lie outside c2
568*cdf0e10cSrcweir 
569*cdf0e10cSrcweir     @param t2
570*cdf0e10cSrcweir     Range (t2,1] on c1 is guaranteed to lie outside c2
571*cdf0e10cSrcweir 
572*cdf0e10cSrcweir     @param c1_orig
573*cdf0e10cSrcweir     Original curve c1
574*cdf0e10cSrcweir 
575*cdf0e10cSrcweir     @param c1_part
576*cdf0e10cSrcweir     Subdivided current part of c1
577*cdf0e10cSrcweir 
578*cdf0e10cSrcweir     @param c2_orig
579*cdf0e10cSrcweir     Original curve c2
580*cdf0e10cSrcweir 
581*cdf0e10cSrcweir     @param c2_part
582*cdf0e10cSrcweir     Subdivided current part of c2
583*cdf0e10cSrcweir  */
584*cdf0e10cSrcweir bool Impl_calcClipRange( double& 		t1,
585*cdf0e10cSrcweir                          double& 		t2,
586*cdf0e10cSrcweir                          const Bezier& 	c1_orig,
587*cdf0e10cSrcweir                          const Bezier& 	c1_part,
588*cdf0e10cSrcweir                          const Bezier& 	c2_orig,
589*cdf0e10cSrcweir                          const Bezier& 	c2_part )
590*cdf0e10cSrcweir {
591*cdf0e10cSrcweir 	// TODO: Maybe also check fat line orthogonal to P0P3, having P0
592*cdf0e10cSrcweir 	//       and P3 as the extremal points
593*cdf0e10cSrcweir 
594*cdf0e10cSrcweir     if( Impl_doBBoxIntersect(c1_part, c2_part) )
595*cdf0e10cSrcweir     {
596*cdf0e10cSrcweir         // Calculate fat lines around c1
597*cdf0e10cSrcweir         FatLine	bounds_c2;
598*cdf0e10cSrcweir 
599*cdf0e10cSrcweir         // must use the subdivided version of c2, since the fat line
600*cdf0e10cSrcweir         // algorithm works implicitely with the convex hull bounding
601*cdf0e10cSrcweir         // box.
602*cdf0e10cSrcweir         Impl_calcFatLine(bounds_c2, c2_part);
603*cdf0e10cSrcweir 
604*cdf0e10cSrcweir         // determine clip positions on c2. Can use original c1 (which
605*cdf0e10cSrcweir         // is necessary anyway, to get the t's on the original curve),
606*cdf0e10cSrcweir         // since the distance calculations work directly in the
607*cdf0e10cSrcweir         // Bernstein polynom parameter domain.
608*cdf0e10cSrcweir         if( Impl_calcSafeParams_clip( t1, t2, bounds_c2,
609*cdf0e10cSrcweir                                       calcLineDistance( bounds_c2.a,
610*cdf0e10cSrcweir                                                         bounds_c2.b,
611*cdf0e10cSrcweir                                                         bounds_c2.c,
612*cdf0e10cSrcweir                                                         c1_orig.p0.x,
613*cdf0e10cSrcweir                                                         c1_orig.p0.y	),
614*cdf0e10cSrcweir                                       calcLineDistance( bounds_c2.a,
615*cdf0e10cSrcweir                                                         bounds_c2.b,
616*cdf0e10cSrcweir                                                         bounds_c2.c,
617*cdf0e10cSrcweir                                                         c1_orig.p1.x,
618*cdf0e10cSrcweir                                                         c1_orig.p1.y	),
619*cdf0e10cSrcweir                                       calcLineDistance( bounds_c2.a,
620*cdf0e10cSrcweir                                                         bounds_c2.b,
621*cdf0e10cSrcweir                                                         bounds_c2.c,
622*cdf0e10cSrcweir                                                         c1_orig.p2.x,
623*cdf0e10cSrcweir                                                         c1_orig.p2.y	),
624*cdf0e10cSrcweir                                       calcLineDistance( bounds_c2.a,
625*cdf0e10cSrcweir                                                         bounds_c2.b,
626*cdf0e10cSrcweir                                                         bounds_c2.c,
627*cdf0e10cSrcweir                                                         c1_orig.p3.x,
628*cdf0e10cSrcweir                                                         c1_orig.p3.y	) ) )
629*cdf0e10cSrcweir         {
630*cdf0e10cSrcweir             //printCurvesWithSafeRange(c1_orig, c2_orig, t1, t2, c2_part, bounds_c2);
631*cdf0e10cSrcweir 
632*cdf0e10cSrcweir             // they do intersect
633*cdf0e10cSrcweir             return true;
634*cdf0e10cSrcweir         }
635*cdf0e10cSrcweir     }
636*cdf0e10cSrcweir 
637*cdf0e10cSrcweir     // they don't intersect: nothing to do
638*cdf0e10cSrcweir     return false;
639*cdf0e10cSrcweir }
640*cdf0e10cSrcweir 
641*cdf0e10cSrcweir // -----------------------------------------------------------------------------
642*cdf0e10cSrcweir 
643*cdf0e10cSrcweir /* Tangent intersection part
644*cdf0e10cSrcweir  * =========================
645*cdf0e10cSrcweir  */
646*cdf0e10cSrcweir 
647*cdf0e10cSrcweir // -----------------------------------------------------------------------------
648*cdf0e10cSrcweir 
649*cdf0e10cSrcweir void Impl_calcFocus( Bezier& res, const Bezier& c )
650*cdf0e10cSrcweir {
651*cdf0e10cSrcweir     // arbitrary small value, for now
652*cdf0e10cSrcweir     // TODO: find meaningful value
653*cdf0e10cSrcweir     const double minPivotValue( 1.0e-20 );
654*cdf0e10cSrcweir 
655*cdf0e10cSrcweir     Point2D::value_type fMatrix[6];
656*cdf0e10cSrcweir     Point2D::value_type fRes[2];
657*cdf0e10cSrcweir 
658*cdf0e10cSrcweir     // calc new curve from hodograph, c and linear blend
659*cdf0e10cSrcweir 
660*cdf0e10cSrcweir     // Coefficients for derivative of c are (C_i=n(C_{i+1} - C_i)):
661*cdf0e10cSrcweir     //
662*cdf0e10cSrcweir     // 3(P1 - P0), 3(P2 - P1), 3(P3 - P2) (bezier curve of degree 2)
663*cdf0e10cSrcweir     //
664*cdf0e10cSrcweir     // The hodograph is then (bezier curve of 2nd degree is P0(1-t)^2 + 2P1(1-t)t + P2t^2):
665*cdf0e10cSrcweir     //
666*cdf0e10cSrcweir     // 3(P1 - P0)(1-t)^2 + 6(P2 - P1)(1-t)t + 3(P3 - P2)t^2
667*cdf0e10cSrcweir     //
668*cdf0e10cSrcweir     // rotate by 90 degrees: x=-y, y=x and you get the normal vector function N(t):
669*cdf0e10cSrcweir     //
670*cdf0e10cSrcweir     // x(t) = -(3(P1.y - P0.y)(1-t)^2 + 6(P2.y - P1.y)(1-t)t + 3(P3.y - P2.y)t^2)
671*cdf0e10cSrcweir     // y(t) =   3(P1.x - P0.x)(1-t)^2 + 6(P2.x - P1.x)(1-t)t + 3(P3.x - P2.x)t^2
672*cdf0e10cSrcweir     //
673*cdf0e10cSrcweir     // Now, the focus curve is defined to be F(t)=P(t) + c(t)N(t),
674*cdf0e10cSrcweir     // where P(t) is the original curve, and c(t)=c0(1-t) + c1 t
675*cdf0e10cSrcweir     //
676*cdf0e10cSrcweir     // This results in the following expression for F(t):
677*cdf0e10cSrcweir     //
678*cdf0e10cSrcweir     // x(t) =  P0.x (1-t)^3 + 3 P1.x (1-t)^2t + 3 P2.x (1.t)t^2 + P3.x t^3 -
679*cdf0e10cSrcweir     //			(c0(1-t) + c1 t)(3(P1.y - P0.y)(1-t)^2 + 6(P2.y - P1.y)(1-t)t + 3(P3.y - P2.y)t^2)
680*cdf0e10cSrcweir     //
681*cdf0e10cSrcweir     // y(t) =  P0.y (1-t)^3 + 3 P1.y (1-t)^2t + 3 P2.y (1.t)t^2 + P3.y t^3 +
682*cdf0e10cSrcweir     //			(c0(1-t) + c1 t)(3(P1.x - P0.x)(1-t)^2 + 6(P2.x - P1.x)(1-t)t + 3(P3.x - P2.x)t^2)
683*cdf0e10cSrcweir     //
684*cdf0e10cSrcweir     // As a heuristic, we set F(0)=F(1) (thus, the curve is closed and _tends_ to be small):
685*cdf0e10cSrcweir     //
686*cdf0e10cSrcweir     // For F(0), the following results:
687*cdf0e10cSrcweir     //
688*cdf0e10cSrcweir     // x(0) = P0.x - c0 3(P1.y - P0.y)
689*cdf0e10cSrcweir     // y(0) = P0.y + c0 3(P1.x - P0.x)
690*cdf0e10cSrcweir     //
691*cdf0e10cSrcweir     // For F(1), the following results:
692*cdf0e10cSrcweir     //
693*cdf0e10cSrcweir     // x(1) = P3.x - c1 3(P3.y - P2.y)
694*cdf0e10cSrcweir     // y(1) = P3.y + c1 3(P3.x - P2.x)
695*cdf0e10cSrcweir     //
696*cdf0e10cSrcweir     // Reorder, collect and substitute into F(0)=F(1):
697*cdf0e10cSrcweir     //
698*cdf0e10cSrcweir     // P0.x - c0 3(P1.y - P0.y) = P3.x - c1 3(P3.y - P2.y)
699*cdf0e10cSrcweir     // P0.y + c0 3(P1.x - P0.x) = P3.y + c1 3(P3.x - P2.x)
700*cdf0e10cSrcweir     //
701*cdf0e10cSrcweir     // which yields
702*cdf0e10cSrcweir     //
703*cdf0e10cSrcweir     // (P0.y - P1.y)c0 + (P3.y - P2.y)c1 = (P3.x - P0.x)/3
704*cdf0e10cSrcweir     // (P1.x - P0.x)c0 + (P2.x - P3.x)c1 = (P3.y - P0.y)/3
705*cdf0e10cSrcweir     //
706*cdf0e10cSrcweir 
707*cdf0e10cSrcweir     // so, this is what we calculate here (determine c0 and c1):
708*cdf0e10cSrcweir     fMatrix[0] = c.p1.x - c.p0.x;
709*cdf0e10cSrcweir     fMatrix[1] = c.p2.x - c.p3.x;
710*cdf0e10cSrcweir     fMatrix[2] = (c.p3.y - c.p0.y)/3.0;
711*cdf0e10cSrcweir     fMatrix[3] = c.p0.y - c.p1.y;
712*cdf0e10cSrcweir     fMatrix[4] = c.p3.y - c.p2.y;
713*cdf0e10cSrcweir     fMatrix[5] = (c.p3.x - c.p0.x)/3.0;
714*cdf0e10cSrcweir 
715*cdf0e10cSrcweir     // TODO: determine meaningful value for
716*cdf0e10cSrcweir     if( !solve(fMatrix, 2, 3, fRes, minPivotValue) )
717*cdf0e10cSrcweir     {
718*cdf0e10cSrcweir         // TODO: generate meaningful values here
719*cdf0e10cSrcweir         // singular or nearly singular system -- use arbitrary
720*cdf0e10cSrcweir         // values for res
721*cdf0e10cSrcweir         fRes[0] = 0.0;
722*cdf0e10cSrcweir         fRes[1] = 1.0;
723*cdf0e10cSrcweir 
724*cdf0e10cSrcweir         cerr << "Matrix singular!" << endl;
725*cdf0e10cSrcweir     }
726*cdf0e10cSrcweir 
727*cdf0e10cSrcweir     // now, the reordered and per-coefficient collected focus curve is
728*cdf0e10cSrcweir     // the following third degree bezier curve F(t):
729*cdf0e10cSrcweir     //
730*cdf0e10cSrcweir     // x(t) =  P0.x (1-t)^3 + 3 P1.x (1-t)^2t + 3 P2.x (1.t)t^2 + P3.x t^3 -
731*cdf0e10cSrcweir     //			(c0(1-t) + c1 t)(3(P1.y - P0.y)(1-t)^2 + 6(P2.y - P1.y)(1-t)t + 3(P3.y - P2.y)t^2)
732*cdf0e10cSrcweir     //      =  P0.x (1-t)^3 + 3 P1.x (1-t)^2t + 3 P2.x (1.t)t^2 + P3.x t^3 -
733*cdf0e10cSrcweir     //		   (3c0P1.y(1-t)^3 - 3c0P0.y(1-t)^3 + 6c0P2.y(1-t)^2t - 6c0P1.y(1-t)^2t +
734*cdf0e10cSrcweir     //		    3c0P3.y(1-t)t^2 - 3c0P2.y(1-t)t^2 +
735*cdf0e10cSrcweir     //		    3c1P1.y(1-t)^2t - 3c1P0.y(1-t)^2t + 6c1P2.y(1-t)t^2 - 6c1P1.y(1-t)t^2 +
736*cdf0e10cSrcweir     //		    3c1P3.yt^3 - 3c1P2.yt^3)
737*cdf0e10cSrcweir     //		=  (P0.x - 3 c0 P1.y + 3 c0 P0.y)(1-t)^3 +
738*cdf0e10cSrcweir     //		   3(P1.x - c1 P1.y + c1 P0.y - 2 c0 P2.y + 2 c0 P1.y)(1-t)^2t +
739*cdf0e10cSrcweir     //		   3(P2.x - 2 c1 P2.y + 2 c1 P1.y - c0 P3.y + c0 P2.y)(1-t)t^2 +
740*cdf0e10cSrcweir     //		   (P3.x - 3 c1 P3.y + 3 c1 P2.y)t^3
741*cdf0e10cSrcweir     //		=  (P0.x - 3 c0(P1.y - P0.y))(1-t)^3 +
742*cdf0e10cSrcweir     //		   3(P1.x - c1(P1.y - P0.y) - 2c0(P2.y - P1.y))(1-t)^2t +
743*cdf0e10cSrcweir     //		   3(P2.x - 2 c1(P2.y - P1.y) - c0(P3.y - P2.y))(1-t)t^2 +
744*cdf0e10cSrcweir     //		   (P3.x - 3 c1(P3.y - P2.y))t^3
745*cdf0e10cSrcweir     //
746*cdf0e10cSrcweir     // y(t) =  P0.y (1-t)^3 + 3 P1.y (1-t)^2t + 3 P2.y (1-t)t^2 + P3.y t^3 +
747*cdf0e10cSrcweir     //			(c0(1-t) + c1 t)(3(P1.x - P0.x)(1-t)^2 + 6(P2.x - P1.x)(1-t)t + 3(P3.x - P2.x)t^2)
748*cdf0e10cSrcweir     //		=  P0.y (1-t)^3 + 3 P1.y (1-t)^2t + 3 P2.y (1-t)t^2 + P3.y t^3 +
749*cdf0e10cSrcweir     //		   3c0(P1.x - P0.x)(1-t)^3 + 6c0(P2.x - P1.x)(1-t)^2t + 3c0(P3.x - P2.x)(1-t)t^2 +
750*cdf0e10cSrcweir     //		   3c1(P1.x - P0.x)(1-t)^2t + 6c1(P2.x - P1.x)(1-t)t^2 + 3c1(P3.x - P2.x)t^3
751*cdf0e10cSrcweir     //		=  (P0.y + 3 c0 (P1.x - P0.x))(1-t)^3 +
752*cdf0e10cSrcweir     //		   3(P1.y + 2 c0 (P2.x - P1.x) + c1 (P1.x - P0.x))(1-t)^2t +
753*cdf0e10cSrcweir     //		   3(P2.y + c0 (P3.x - P2.x) + 2 c1 (P2.x - P1.x))(1-t)t^2 +
754*cdf0e10cSrcweir     //		   (P3.y + 3 c1 (P3.x - P2.x))t^3
755*cdf0e10cSrcweir     //
756*cdf0e10cSrcweir     // Therefore, the coefficients F0 to F3 of the focus curve are:
757*cdf0e10cSrcweir     //
758*cdf0e10cSrcweir     // F0.x = (P0.x - 3 c0(P1.y - P0.y))					F0.y = (P0.y + 3 c0 (P1.x - P0.x))
759*cdf0e10cSrcweir     // F1.x = (P1.x - c1(P1.y - P0.y) - 2c0(P2.y - P1.y))	F1.y = (P1.y + 2 c0 (P2.x - P1.x) + c1 (P1.x - P0.x))
760*cdf0e10cSrcweir     // F2.x = (P2.x - 2 c1(P2.y - P1.y) - c0(P3.y - P2.y))	F2.y = (P2.y + c0 (P3.x - P2.x) + 2 c1 (P2.x - P1.x))
761*cdf0e10cSrcweir     // F3.x = (P3.x - 3 c1(P3.y - P2.y))					F3.y = (P3.y + 3 c1 (P3.x - P2.x))
762*cdf0e10cSrcweir     //
763*cdf0e10cSrcweir     res.p0.x = c.p0.x - 3*fRes[0]*(c.p1.y - c.p0.y);
764*cdf0e10cSrcweir     res.p1.x = c.p1.x - fRes[1]*(c.p1.y - c.p0.y) - 2*fRes[0]*(c.p2.y - c.p1.y);
765*cdf0e10cSrcweir     res.p2.x = c.p2.x - 2*fRes[1]*(c.p2.y - c.p1.y) - fRes[0]*(c.p3.y - c.p2.y);
766*cdf0e10cSrcweir     res.p3.x = c.p3.x - 3*fRes[1]*(c.p3.y - c.p2.y);
767*cdf0e10cSrcweir 
768*cdf0e10cSrcweir     res.p0.y = c.p0.y + 3*fRes[0]*(c.p1.x - c.p0.x);
769*cdf0e10cSrcweir     res.p1.y = c.p1.y + 2*fRes[0]*(c.p2.x - c.p1.x) + fRes[1]*(c.p1.x - c.p0.x);
770*cdf0e10cSrcweir     res.p2.y = c.p2.y + fRes[0]*(c.p3.x - c.p2.x) + 2*fRes[1]*(c.p2.x - c.p1.x);
771*cdf0e10cSrcweir     res.p3.y = c.p3.y + 3*fRes[1]*(c.p3.x - c.p2.x);
772*cdf0e10cSrcweir }
773*cdf0e10cSrcweir 
774*cdf0e10cSrcweir // -----------------------------------------------------------------------------
775*cdf0e10cSrcweir 
776*cdf0e10cSrcweir bool Impl_calcSafeParams_focus( double& 		t1,
777*cdf0e10cSrcweir                                 double& 		t2,
778*cdf0e10cSrcweir                                 const Bezier& 	curve,
779*cdf0e10cSrcweir                                 const Bezier& 	focus )
780*cdf0e10cSrcweir {
781*cdf0e10cSrcweir     // now, we want to determine which normals of the original curve
782*cdf0e10cSrcweir     // P(t) intersect with the focus curve F(t). The condition for
783*cdf0e10cSrcweir     // this statement is P'(t)(P(t) - F) = 0, i.e. hodograph P'(t) and
784*cdf0e10cSrcweir     // line through P(t) and F are perpendicular.
785*cdf0e10cSrcweir     // If you expand this equation, you end up with something like
786*cdf0e10cSrcweir     //
787*cdf0e10cSrcweir     // (\sum_{i=0}^n (P_i - F)B_i^n(t))^T (\sum_{j=0}^{n-1} n(P_{j+1} - P_j)B_j^{n-1}(t))
788*cdf0e10cSrcweir     //
789*cdf0e10cSrcweir     // Multiplying that out (as the scalar product is linear, we can
790*cdf0e10cSrcweir     // extract some terms) yields:
791*cdf0e10cSrcweir     //
792*cdf0e10cSrcweir     // (P_i - F)^T n(P_{j+1} - P_j) B_i^n(t)B_j^{n-1}(t) + ...
793*cdf0e10cSrcweir     //
794*cdf0e10cSrcweir     // If we combine the B_i^n(t)B_j^{n-1}(t) product, we arrive at a
795*cdf0e10cSrcweir     // Bernstein polynomial of degree 2n-1, as
796*cdf0e10cSrcweir     //
797*cdf0e10cSrcweir     // \binom{n}{i}(1-t)^{n-i}t^i) \binom{n-1}{j}(1-t)^{n-1-j}t^j) =
798*cdf0e10cSrcweir     // \binom{n}{i}\binom{n-1}{j}(1-t)^{2n-1-i-j}t^{i+j}
799*cdf0e10cSrcweir     //
800*cdf0e10cSrcweir     // Thus, with the defining equation for a 2n-1 degree Bernstein
801*cdf0e10cSrcweir     // polynomial
802*cdf0e10cSrcweir     //
803*cdf0e10cSrcweir     // \sum_{i=0}^{2n-1} d_i B_i^{2n-1}(t)
804*cdf0e10cSrcweir     //
805*cdf0e10cSrcweir     // the d_i are calculated as follows:
806*cdf0e10cSrcweir     //
807*cdf0e10cSrcweir     // d_i = \sum_{j+k=i, j\in\{0,...,n\}, k\in\{0,...,n-1\}} \frac{\binom{n}{j}\binom{n-1}{k}}{\binom{2n-1}{i}} n (P_{k+1} - P_k)^T(P_j - F)
808*cdf0e10cSrcweir     //
809*cdf0e10cSrcweir     //
810*cdf0e10cSrcweir     // Okay, but F is now not a single point, but itself a curve
811*cdf0e10cSrcweir     // F(u). Thus, for every value of u, we get a different 2n-1
812*cdf0e10cSrcweir     // bezier curve from the above equation. Therefore, we have a
813*cdf0e10cSrcweir     // tensor product bezier patch, with the following defining
814*cdf0e10cSrcweir     // equation:
815*cdf0e10cSrcweir     //
816*cdf0e10cSrcweir     // d(t,u) = \sum_{i=0}^{2n-1} \sum_{j=0}^m B_i^{2n-1}(t) B_j^{m}(u) d_{ij}, where
817*cdf0e10cSrcweir     // d_{ij} = \sum_{k+l=i, l\in\{0,...,n\}, k\in\{0,...,n-1\}} \frac{\binom{n}{l}\binom{n-1}{k}}{\binom{2n-1}{i}} n (P_{k+1} - P_k)^T(P_l - F_j)
818*cdf0e10cSrcweir     //
819*cdf0e10cSrcweir     // as above, only that now F is one of the focus' control points.
820*cdf0e10cSrcweir     //
821*cdf0e10cSrcweir     // Note the difference in the binomial coefficients to the
822*cdf0e10cSrcweir     // reference paper, these formulas most probably contained a typo.
823*cdf0e10cSrcweir     //
824*cdf0e10cSrcweir     // To determine, where D(t,u) is _not_ zero (these are the parts
825*cdf0e10cSrcweir     // of the curve that don't share normals with the focus and can
826*cdf0e10cSrcweir     // thus be safely clipped away), we project D(u,t) onto the
827*cdf0e10cSrcweir     // (d(t,u), t) plane, determine the convex hull there and proceed
828*cdf0e10cSrcweir     // as for the curve intersection part (projection is orthogonal to
829*cdf0e10cSrcweir     // u axis, thus simply throw away u coordinate).
830*cdf0e10cSrcweir     //
831*cdf0e10cSrcweir     // \fallfac are so-called falling factorials (see Concrete
832*cdf0e10cSrcweir     // Mathematics, p. 47 for a definition).
833*cdf0e10cSrcweir     //
834*cdf0e10cSrcweir 
835*cdf0e10cSrcweir     // now, for tensor product bezier curves, the convex hull property
836*cdf0e10cSrcweir     // holds, too. Thus, we simply project the control points (t_{ij},
837*cdf0e10cSrcweir     // u_{ij}, d_{ij}) onto the (t,d) plane and calculate the
838*cdf0e10cSrcweir     // intersections of the convex hull with the t axis, as for the
839*cdf0e10cSrcweir     // bezier clipping case.
840*cdf0e10cSrcweir 
841*cdf0e10cSrcweir     //
842*cdf0e10cSrcweir     // calc polygon of control points (t_{ij}, d_{ij}):
843*cdf0e10cSrcweir     //
844*cdf0e10cSrcweir     const int n( 3 ); // cubic bezier curves, as a matter of fact
845*cdf0e10cSrcweir     const int i_card( 2*n );
846*cdf0e10cSrcweir     const int j_card( n + 1 );
847*cdf0e10cSrcweir     const int k_max( n-1 );
848*cdf0e10cSrcweir     Polygon2D controlPolygon( i_card*j_card ); // vector of (t_{ij}, d_{ij}) in row-major order
849*cdf0e10cSrcweir 
850*cdf0e10cSrcweir     int i, j, k, l; // variable notation from formulas above and Sederberg article
851*cdf0e10cSrcweir     Point2D::value_type d;
852*cdf0e10cSrcweir     for( i=0; i<i_card; ++i )
853*cdf0e10cSrcweir     {
854*cdf0e10cSrcweir         for( j=0; j<j_card; ++j )
855*cdf0e10cSrcweir         {
856*cdf0e10cSrcweir             // calc single d_{ij} sum:
857*cdf0e10cSrcweir             for( d=0.0, k=::std::max(0,i-n); k<=k_max && k<=i; ++k )
858*cdf0e10cSrcweir             {
859*cdf0e10cSrcweir                 l = i - k; // invariant: k + l = i
860*cdf0e10cSrcweir                 assert(k>=0 && k<=n-1); // k \in {0,...,n-1}
861*cdf0e10cSrcweir                 assert(l>=0 && l<=n);   // l \in {0,...,n}
862*cdf0e10cSrcweir 
863*cdf0e10cSrcweir                 // TODO: find, document and assert proper limits for n and int's max_val.
864*cdf0e10cSrcweir                 // This becomes important should anybody wants to use
865*cdf0e10cSrcweir                 // this code for higher-than-cubic beziers
866*cdf0e10cSrcweir                 d += static_cast<double>(fallFac(n,l)*fallFac(n-1,k)*fac(i)) /
867*cdf0e10cSrcweir                     static_cast<double>(fac(l)*fac(k) * fallFac(2*n-1,i)) * n *
868*cdf0e10cSrcweir                     ( (curve[k+1].x - curve[k].x)*(curve[l].x - focus[j].x) +	// dot product here
869*cdf0e10cSrcweir                       (curve[k+1].y - curve[k].y)*(curve[l].y - focus[j].y) );
870*cdf0e10cSrcweir             }
871*cdf0e10cSrcweir 
872*cdf0e10cSrcweir             // Note that the t_{ij} values are evenly spaced on the
873*cdf0e10cSrcweir             // [0,1] interval, thus t_{ij}=i/(2n-1)
874*cdf0e10cSrcweir             controlPolygon[ i*j_card + j ] = Point2D( i/(2.0*n-1.0), d );
875*cdf0e10cSrcweir         }
876*cdf0e10cSrcweir     }
877*cdf0e10cSrcweir 
878*cdf0e10cSrcweir #ifndef WITH_SAFEFOCUSPARAM_DETAILED_TEST
879*cdf0e10cSrcweir 
880*cdf0e10cSrcweir     // calc safe parameter range, to determine [0,t1] and [t2,1] where
881*cdf0e10cSrcweir     // no zero crossing is guaranteed.
882*cdf0e10cSrcweir     return Impl_calcSafeParams( t1, t2, controlPolygon, 0.0, 0.0 );
883*cdf0e10cSrcweir 
884*cdf0e10cSrcweir #else
885*cdf0e10cSrcweir     bool bRet( Impl_calcSafeParams( t1, t2, controlPolygon, 0.0, 0.0 ) );
886*cdf0e10cSrcweir 
887*cdf0e10cSrcweir     Polygon2D convHull( convexHull( controlPolygon ) );
888*cdf0e10cSrcweir 
889*cdf0e10cSrcweir     cout << "# convex hull testing (focus)" << endl
890*cdf0e10cSrcweir          << "plot [t=0:1] ";
891*cdf0e10cSrcweir     cout << "'-' using ($1):($2) title \"control polygon\" with lp, "
892*cdf0e10cSrcweir          << "'-' using ($1):($2) title \"convex hull\" with lp" << endl;
893*cdf0e10cSrcweir 
894*cdf0e10cSrcweir     unsigned int count;
895*cdf0e10cSrcweir     for( count=0; count<controlPolygon.size(); ++count )
896*cdf0e10cSrcweir     {
897*cdf0e10cSrcweir         cout << controlPolygon[count].x << " " << controlPolygon[count].y << endl;
898*cdf0e10cSrcweir     }
899*cdf0e10cSrcweir     cout << controlPolygon[0].x << " " << controlPolygon[0].y << endl;
900*cdf0e10cSrcweir     cout << "e" << endl;
901*cdf0e10cSrcweir 
902*cdf0e10cSrcweir     for( count=0; count<convHull.size(); ++count )
903*cdf0e10cSrcweir     {
904*cdf0e10cSrcweir         cout << convHull[count].x << " " << convHull[count].y << endl;
905*cdf0e10cSrcweir     }
906*cdf0e10cSrcweir     cout << convHull[0].x << " " << convHull[0].y << endl;
907*cdf0e10cSrcweir     cout << "e" << endl;
908*cdf0e10cSrcweir 
909*cdf0e10cSrcweir     return bRet;
910*cdf0e10cSrcweir #endif
911*cdf0e10cSrcweir }
912*cdf0e10cSrcweir 
913*cdf0e10cSrcweir // -----------------------------------------------------------------------------
914*cdf0e10cSrcweir 
915*cdf0e10cSrcweir /** Calc all values t_i on c1, for which safeRanges functor does not
916*cdf0e10cSrcweir     give a safe range on c1 and c2.
917*cdf0e10cSrcweir 
918*cdf0e10cSrcweir 	This method is the workhorse of the bezier clipping. Because c1
919*cdf0e10cSrcweir 	and c2 must be alternatingly tested against each other (first
920*cdf0e10cSrcweir 	determine safe parameter interval on c1 with regard to c2, then
921*cdf0e10cSrcweir 	the other way around), we call this method recursively with c1 and
922*cdf0e10cSrcweir 	c2 swapped.
923*cdf0e10cSrcweir 
924*cdf0e10cSrcweir 	@param result
925*cdf0e10cSrcweir     Output iterator where the final t values are added to. If curves
926*cdf0e10cSrcweir     don't intersect, nothing is added.
927*cdf0e10cSrcweir 
928*cdf0e10cSrcweir     @param delta
929*cdf0e10cSrcweir     Maximal allowed distance to true critical point (measured in the
930*cdf0e10cSrcweir     original curve's coordinate system)
931*cdf0e10cSrcweir 
932*cdf0e10cSrcweir     @param safeRangeFunctor
933*cdf0e10cSrcweir     Functor object, that must provide the following operator():
934*cdf0e10cSrcweir     bool safeRangeFunctor( double& t1,
935*cdf0e10cSrcweir     					   double& t2,
936*cdf0e10cSrcweir                            const Bezier& c1_orig,
937*cdf0e10cSrcweir                            const Bezier& c1_part,
938*cdf0e10cSrcweir                            const Bezier& c2_orig,
939*cdf0e10cSrcweir                            const Bezier& c2_part );
940*cdf0e10cSrcweir     This functor must calculate the safe ranges [0,t1] and [t2,1] on
941*cdf0e10cSrcweir     c1_orig, where c1_orig is 'safe' from c2_part. If the whole
942*cdf0e10cSrcweir     c1_orig is safe, false must be returned, true otherwise.
943*cdf0e10cSrcweir  */
944*cdf0e10cSrcweir template <class Functor> void Impl_applySafeRanges_rec( ::std::back_insert_iterator< ::std::vector< ::std::pair<double, double> > >&	result,
945*cdf0e10cSrcweir                                                         double 																			delta,
946*cdf0e10cSrcweir                                                         const Functor& 																	safeRangeFunctor,
947*cdf0e10cSrcweir                                                         int																				recursionLevel,
948*cdf0e10cSrcweir                                                         const Bezier& 																	c1_orig,
949*cdf0e10cSrcweir                                                         const Bezier& 																	c1_part,
950*cdf0e10cSrcweir                                                         double																			last_t1_c1,
951*cdf0e10cSrcweir                                                         double																			last_t2_c1,
952*cdf0e10cSrcweir                                                         const Bezier& 																	c2_orig,
953*cdf0e10cSrcweir                                                         const Bezier& 																	c2_part,
954*cdf0e10cSrcweir                                                         double																			last_t1_c2,
955*cdf0e10cSrcweir                                                         double																			last_t2_c2  )
956*cdf0e10cSrcweir {
957*cdf0e10cSrcweir     // check end condition
958*cdf0e10cSrcweir     // ===================
959*cdf0e10cSrcweir 
960*cdf0e10cSrcweir 	// TODO: tidy up recursion handling. maybe put everything in a
961*cdf0e10cSrcweir 	// struct and swap that here at method entry
962*cdf0e10cSrcweir 
963*cdf0e10cSrcweir     // TODO: Implement limit on recursion depth. Should that limit be
964*cdf0e10cSrcweir     // reached, chances are that we're on a higher-order tangency. For
965*cdf0e10cSrcweir     // this case, AW proposed to take the middle of the current
966*cdf0e10cSrcweir     // interval, and to correct both curve's tangents at that new
967*cdf0e10cSrcweir     // endpoint to be equal. That virtually generates a first-order
968*cdf0e10cSrcweir     // tangency, and justifies to return a single intersection
969*cdf0e10cSrcweir     // point. Otherwise, inside/outside test might fail here.
970*cdf0e10cSrcweir 
971*cdf0e10cSrcweir     for( int i=0; i<recursionLevel; ++i ) cerr << " ";
972*cdf0e10cSrcweir     if( recursionLevel % 2 )
973*cdf0e10cSrcweir     {
974*cdf0e10cSrcweir         cerr << "level: " << recursionLevel
975*cdf0e10cSrcweir              << " t: "
976*cdf0e10cSrcweir              << last_t1_c2 + (last_t2_c2 - last_t1_c2)/2.0
977*cdf0e10cSrcweir              << ", c1: " << last_t1_c2 << " " << last_t2_c2
978*cdf0e10cSrcweir              << ", c2: " << last_t1_c1 << " " << last_t2_c1
979*cdf0e10cSrcweir              << endl;
980*cdf0e10cSrcweir     }
981*cdf0e10cSrcweir     else
982*cdf0e10cSrcweir     {
983*cdf0e10cSrcweir         cerr << "level: " << recursionLevel
984*cdf0e10cSrcweir              << " t: "
985*cdf0e10cSrcweir              << last_t1_c1 + (last_t2_c1 - last_t1_c1)/2.0
986*cdf0e10cSrcweir              << ", c1: " << last_t1_c1 << " " << last_t2_c1
987*cdf0e10cSrcweir              << ", c2: " << last_t1_c2 << " " << last_t2_c2
988*cdf0e10cSrcweir              << endl;
989*cdf0e10cSrcweir     }
990*cdf0e10cSrcweir 
991*cdf0e10cSrcweir     // refine solution
992*cdf0e10cSrcweir     // ===============
993*cdf0e10cSrcweir 
994*cdf0e10cSrcweir     double t1_c1, t2_c1;
995*cdf0e10cSrcweir 
996*cdf0e10cSrcweir     // Note: we first perform the clipping and only test for precision
997*cdf0e10cSrcweir     // sufficiency afterwards, since we want to exploit the fact that
998*cdf0e10cSrcweir     // Impl_calcClipRange returns false if the curves don't
999*cdf0e10cSrcweir     // intersect. We would have to check that separately for the end
1000*cdf0e10cSrcweir     // condition, otherwise.
1001*cdf0e10cSrcweir 
1002*cdf0e10cSrcweir     // determine safe range on c1_orig
1003*cdf0e10cSrcweir     if( safeRangeFunctor( t1_c1, t2_c1, c1_orig, c1_part, c2_orig, c2_part ) )
1004*cdf0e10cSrcweir     {
1005*cdf0e10cSrcweir         // now, t1 and t2 are calculated on the original curve
1006*cdf0e10cSrcweir         // (but against a fat line calculated from the subdivided
1007*cdf0e10cSrcweir         // c2, namely c2_part). If the [t1,t2] range is outside
1008*cdf0e10cSrcweir         // our current [last_t1,last_t2] range, we're done in this
1009*cdf0e10cSrcweir         // branch - the curves no longer intersect.
1010*cdf0e10cSrcweir         if( tolLessEqual(t1_c1, last_t2_c1) && tolGreaterEqual(t2_c1, last_t1_c1) )
1011*cdf0e10cSrcweir         {
1012*cdf0e10cSrcweir             // As noted above, t1 and t2 are calculated on the
1013*cdf0e10cSrcweir             // original curve, but against a fat line
1014*cdf0e10cSrcweir             // calculated from the subdivided c2, namely
1015*cdf0e10cSrcweir             // c2_part. Our domain to work on is
1016*cdf0e10cSrcweir             // [last_t1,last_t2], on the other hand, so values
1017*cdf0e10cSrcweir             // of [t1,t2] outside that range are irrelevant
1018*cdf0e10cSrcweir             // here. Clip range appropriately.
1019*cdf0e10cSrcweir             t1_c1 = ::std::max(t1_c1, last_t1_c1);
1020*cdf0e10cSrcweir             t2_c1 = ::std::min(t2_c1, last_t2_c1);
1021*cdf0e10cSrcweir 
1022*cdf0e10cSrcweir             // TODO: respect delta
1023*cdf0e10cSrcweir             // for now, end condition is just a fixed threshold on the t's
1024*cdf0e10cSrcweir 
1025*cdf0e10cSrcweir             // check end condition
1026*cdf0e10cSrcweir             // ===================
1027*cdf0e10cSrcweir 
1028*cdf0e10cSrcweir #if 1
1029*cdf0e10cSrcweir             if( fabs(last_t2_c1 - last_t1_c1) < 0.0001 &&
1030*cdf0e10cSrcweir                 fabs(last_t2_c2 - last_t1_c2) < 0.0001	)
1031*cdf0e10cSrcweir #else
1032*cdf0e10cSrcweir             if( fabs(last_t2_c1 - last_t1_c1) < 0.01 &&
1033*cdf0e10cSrcweir                 fabs(last_t2_c2 - last_t1_c2) < 0.01	)
1034*cdf0e10cSrcweir #endif
1035*cdf0e10cSrcweir             {
1036*cdf0e10cSrcweir                 // done. Add to result
1037*cdf0e10cSrcweir                 if( recursionLevel % 2 )
1038*cdf0e10cSrcweir                 {
1039*cdf0e10cSrcweir                     // uneven level: have to swap the t's, since curves are swapped, too
1040*cdf0e10cSrcweir                     *result++ = ::std::make_pair( last_t1_c2 + (last_t2_c2 - last_t1_c2)/2.0,
1041*cdf0e10cSrcweir                                                   last_t1_c1 + (last_t2_c1 - last_t1_c1)/2.0 );
1042*cdf0e10cSrcweir                 }
1043*cdf0e10cSrcweir                 else
1044*cdf0e10cSrcweir                 {
1045*cdf0e10cSrcweir                     *result++ = ::std::make_pair( last_t1_c1 + (last_t2_c1 - last_t1_c1)/2.0,
1046*cdf0e10cSrcweir                                                   last_t1_c2 + (last_t2_c2 - last_t1_c2)/2.0 );
1047*cdf0e10cSrcweir                 }
1048*cdf0e10cSrcweir 
1049*cdf0e10cSrcweir #if 0
1050*cdf0e10cSrcweir                 //printResultWithFinalCurves( c1_orig, c1_part, c2_orig, c2_part, last_t1_c1, last_t2_c1 );
1051*cdf0e10cSrcweir                 printResultWithFinalCurves( c1_orig, c1_part, c2_orig, c2_part, t1_c1, t2_c1 );
1052*cdf0e10cSrcweir #else
1053*cdf0e10cSrcweir                 // calc focus curve of c2
1054*cdf0e10cSrcweir                 Bezier focus;
1055*cdf0e10cSrcweir                 Impl_calcFocus(focus, c2_part); // need to use subdivided c2
1056*cdf0e10cSrcweir 
1057*cdf0e10cSrcweir                 safeRangeFunctor( t1_c1, t2_c1, c1_orig, c1_part, c2_orig, c2_part );
1058*cdf0e10cSrcweir 
1059*cdf0e10cSrcweir                 //printResultWithFinalCurves( c1_orig, c1_part, c2_orig, focus, t1_c1, t2_c1 );
1060*cdf0e10cSrcweir                 printResultWithFinalCurves( c1_orig, c1_part, c2_orig, focus, last_t1_c1, last_t2_c1 );
1061*cdf0e10cSrcweir #endif
1062*cdf0e10cSrcweir             }
1063*cdf0e10cSrcweir             else
1064*cdf0e10cSrcweir             {
1065*cdf0e10cSrcweir                 // heuristic: if parameter range is not reduced by at least
1066*cdf0e10cSrcweir                 // 20%, subdivide longest curve, and clip shortest against
1067*cdf0e10cSrcweir                 // both parts of longest
1068*cdf0e10cSrcweir //                if( (last_t2_c1 - last_t1_c1 - t2_c1 + t1_c1) / (last_t2_c1 - last_t1_c1) < 0.2 )
1069*cdf0e10cSrcweir                 if( false )
1070*cdf0e10cSrcweir                 {
1071*cdf0e10cSrcweir                     // subdivide and descend
1072*cdf0e10cSrcweir                     // =====================
1073*cdf0e10cSrcweir 
1074*cdf0e10cSrcweir                     Bezier part1;
1075*cdf0e10cSrcweir                     Bezier part2;
1076*cdf0e10cSrcweir 
1077*cdf0e10cSrcweir                     double intervalMiddle;
1078*cdf0e10cSrcweir 
1079*cdf0e10cSrcweir                     if( last_t2_c1 - last_t1_c1 > last_t2_c2 - last_t1_c2 )
1080*cdf0e10cSrcweir                     {
1081*cdf0e10cSrcweir                         // subdivide c1
1082*cdf0e10cSrcweir                         // ============
1083*cdf0e10cSrcweir 
1084*cdf0e10cSrcweir                         intervalMiddle = last_t1_c1 + (last_t2_c1 - last_t1_c1)/2.0;
1085*cdf0e10cSrcweir 
1086*cdf0e10cSrcweir                         // subdivide at the middle of the interval (as
1087*cdf0e10cSrcweir                         // we're not subdividing on the original
1088*cdf0e10cSrcweir                         // curve, this simply amounts to subdivision
1089*cdf0e10cSrcweir                         // at 0.5)
1090*cdf0e10cSrcweir                         Impl_deCasteljauAt( part1, part2, c1_part, 0.5 );
1091*cdf0e10cSrcweir 
1092*cdf0e10cSrcweir                         // and descend recursively with swapped curves
1093*cdf0e10cSrcweir                         Impl_applySafeRanges_rec( result, delta, safeRangeFunctor, recursionLevel+1,
1094*cdf0e10cSrcweir                                                   c2_orig, c2_part, last_t1_c2, last_t2_c2,
1095*cdf0e10cSrcweir                                                   c1_orig, part1, last_t1_c1, intervalMiddle );
1096*cdf0e10cSrcweir 
1097*cdf0e10cSrcweir                         Impl_applySafeRanges_rec( result, delta, safeRangeFunctor, recursionLevel+1,
1098*cdf0e10cSrcweir                                                   c2_orig, c2_part, last_t1_c2, last_t2_c2,
1099*cdf0e10cSrcweir                                                   c1_orig, part2, intervalMiddle, last_t2_c1 );
1100*cdf0e10cSrcweir                     }
1101*cdf0e10cSrcweir                     else
1102*cdf0e10cSrcweir                     {
1103*cdf0e10cSrcweir                         // subdivide c2
1104*cdf0e10cSrcweir                         // ============
1105*cdf0e10cSrcweir 
1106*cdf0e10cSrcweir                         intervalMiddle = last_t1_c2 + (last_t2_c2 - last_t1_c2)/2.0;
1107*cdf0e10cSrcweir 
1108*cdf0e10cSrcweir                         // subdivide at the middle of the interval (as
1109*cdf0e10cSrcweir                         // we're not subdividing on the original
1110*cdf0e10cSrcweir                         // curve, this simply amounts to subdivision
1111*cdf0e10cSrcweir                         // at 0.5)
1112*cdf0e10cSrcweir                         Impl_deCasteljauAt( part1, part2, c2_part, 0.5 );
1113*cdf0e10cSrcweir 
1114*cdf0e10cSrcweir                         // and descend recursively with swapped curves
1115*cdf0e10cSrcweir                         Impl_applySafeRanges_rec( result, delta, safeRangeFunctor, recursionLevel+1,
1116*cdf0e10cSrcweir                                                   c2_orig, part1, last_t1_c2, intervalMiddle,
1117*cdf0e10cSrcweir                                                   c1_orig, c1_part, last_t1_c1, last_t2_c1 );
1118*cdf0e10cSrcweir 
1119*cdf0e10cSrcweir                         Impl_applySafeRanges_rec( result, delta, safeRangeFunctor, recursionLevel+1,
1120*cdf0e10cSrcweir                                                   c2_orig, part2, intervalMiddle, last_t2_c2,
1121*cdf0e10cSrcweir                                                   c1_orig, c1_part, last_t1_c1, last_t2_c1 );
1122*cdf0e10cSrcweir                     }
1123*cdf0e10cSrcweir                 }
1124*cdf0e10cSrcweir                 else
1125*cdf0e10cSrcweir                 {
1126*cdf0e10cSrcweir                     // apply calculated clip
1127*cdf0e10cSrcweir                     // =====================
1128*cdf0e10cSrcweir 
1129*cdf0e10cSrcweir                     // clip safe ranges off c1_orig
1130*cdf0e10cSrcweir                     Bezier c1_part1;
1131*cdf0e10cSrcweir                     Bezier c1_part2;
1132*cdf0e10cSrcweir                     Bezier c1_part3;
1133*cdf0e10cSrcweir 
1134*cdf0e10cSrcweir                     // subdivide at t1_c1
1135*cdf0e10cSrcweir                     Impl_deCasteljauAt( c1_part1, c1_part2, c1_orig, t1_c1 );
1136*cdf0e10cSrcweir 
1137*cdf0e10cSrcweir                     // subdivide at t2_c1. As we're working on
1138*cdf0e10cSrcweir                     // c1_part2 now, we have to adapt t2_c1 since
1139*cdf0e10cSrcweir                     // we're no longer in the original parameter
1140*cdf0e10cSrcweir                     // interval. This is based on the following
1141*cdf0e10cSrcweir                     // assumption: t2_new = (t2-t1)/(1-t1), which
1142*cdf0e10cSrcweir                     // relates the t2 value into the new parameter
1143*cdf0e10cSrcweir                     // range [0,1] of c1_part2.
1144*cdf0e10cSrcweir                     Impl_deCasteljauAt( c1_part1, c1_part3, c1_part2, (t2_c1-t1_c1)/(1.0-t1_c1) );
1145*cdf0e10cSrcweir 
1146*cdf0e10cSrcweir                     // descend with swapped curves and c1_part1 as the
1147*cdf0e10cSrcweir                     // remaining (middle) segment
1148*cdf0e10cSrcweir                     Impl_applySafeRanges_rec( result, delta, safeRangeFunctor, recursionLevel+1,
1149*cdf0e10cSrcweir                                               c2_orig, c2_part, last_t1_c2, last_t2_c2,
1150*cdf0e10cSrcweir                                               c1_orig, c1_part1, t1_c1, t2_c1 );
1151*cdf0e10cSrcweir                 }
1152*cdf0e10cSrcweir             }
1153*cdf0e10cSrcweir         }
1154*cdf0e10cSrcweir     }
1155*cdf0e10cSrcweir }
1156*cdf0e10cSrcweir 
1157*cdf0e10cSrcweir // -----------------------------------------------------------------------------
1158*cdf0e10cSrcweir 
1159*cdf0e10cSrcweir struct ClipBezierFunctor
1160*cdf0e10cSrcweir {
1161*cdf0e10cSrcweir     bool operator()( double& t1_c1,
1162*cdf0e10cSrcweir                      double& t2_c1,
1163*cdf0e10cSrcweir                      const Bezier& c1_orig,
1164*cdf0e10cSrcweir                      const Bezier& c1_part,
1165*cdf0e10cSrcweir                      const Bezier& c2_orig,
1166*cdf0e10cSrcweir                      const Bezier& c2_part ) const
1167*cdf0e10cSrcweir     {
1168*cdf0e10cSrcweir         return Impl_calcClipRange( t1_c1, t2_c1, c1_orig, c1_part, c2_orig, c2_part );
1169*cdf0e10cSrcweir     }
1170*cdf0e10cSrcweir };
1171*cdf0e10cSrcweir 
1172*cdf0e10cSrcweir // -----------------------------------------------------------------------------
1173*cdf0e10cSrcweir 
1174*cdf0e10cSrcweir struct BezierTangencyFunctor
1175*cdf0e10cSrcweir {
1176*cdf0e10cSrcweir     bool operator()( double& t1_c1,
1177*cdf0e10cSrcweir                      double& t2_c1,
1178*cdf0e10cSrcweir                      const Bezier& c1_orig,
1179*cdf0e10cSrcweir                      const Bezier& c1_part,
1180*cdf0e10cSrcweir                      const Bezier& c2_orig,
1181*cdf0e10cSrcweir                      const Bezier& c2_part ) const
1182*cdf0e10cSrcweir     {
1183*cdf0e10cSrcweir         // calc focus curve of c2
1184*cdf0e10cSrcweir         Bezier focus;
1185*cdf0e10cSrcweir         Impl_calcFocus(focus, c2_part); // need to use subdivided c2
1186*cdf0e10cSrcweir                                         // here, as the whole curve is
1187*cdf0e10cSrcweir                                         // used for focus calculation
1188*cdf0e10cSrcweir 
1189*cdf0e10cSrcweir         // determine safe range on c1_orig
1190*cdf0e10cSrcweir         bool bRet( Impl_calcSafeParams_focus( t1_c1, t2_c1,
1191*cdf0e10cSrcweir                                               c1_orig, // use orig curve here, need t's on original curve
1192*cdf0e10cSrcweir                                               focus ) );
1193*cdf0e10cSrcweir 
1194*cdf0e10cSrcweir         cerr << "range: " << t2_c1 - t1_c1 << ", ret: " << bRet << endl;
1195*cdf0e10cSrcweir 
1196*cdf0e10cSrcweir         return bRet;
1197*cdf0e10cSrcweir     }
1198*cdf0e10cSrcweir };
1199*cdf0e10cSrcweir 
1200*cdf0e10cSrcweir // -----------------------------------------------------------------------------
1201*cdf0e10cSrcweir 
1202*cdf0e10cSrcweir /** Perform a bezier clip (curve against curve)
1203*cdf0e10cSrcweir 
1204*cdf0e10cSrcweir 	@param result
1205*cdf0e10cSrcweir     Output iterator where the final t values are added to. This
1206*cdf0e10cSrcweir     iterator will remain empty, if there are no intersections.
1207*cdf0e10cSrcweir 
1208*cdf0e10cSrcweir     @param delta
1209*cdf0e10cSrcweir     Maximal allowed distance to true intersection (measured in the
1210*cdf0e10cSrcweir     original curve's coordinate system)
1211*cdf0e10cSrcweir  */
1212*cdf0e10cSrcweir void clipBezier( ::std::back_insert_iterator< ::std::vector< ::std::pair<double, double> > >&	result,
1213*cdf0e10cSrcweir                  double 																		delta,
1214*cdf0e10cSrcweir                  const Bezier& 																	c1,
1215*cdf0e10cSrcweir                  const Bezier& 																	c2		  )
1216*cdf0e10cSrcweir {
1217*cdf0e10cSrcweir #if 0
1218*cdf0e10cSrcweir     // first of all, determine list of collinear normals. Collinear
1219*cdf0e10cSrcweir     // normals typically separate two intersections, thus, subdivide
1220*cdf0e10cSrcweir     // at all collinear normal's t values beforehand. This will cater
1221*cdf0e10cSrcweir     // for tangent intersections, where two or more intersections are
1222*cdf0e10cSrcweir     // infinitesimally close together.
1223*cdf0e10cSrcweir 
1224*cdf0e10cSrcweir     // TODO: evaluate effects of higher-than-second-order
1225*cdf0e10cSrcweir     // tangencies. Sederberg et al. state that collinear normal
1226*cdf0e10cSrcweir     // algorithm then degrades quickly.
1227*cdf0e10cSrcweir 
1228*cdf0e10cSrcweir     ::std::vector< ::std::pair<double,double> > results;
1229*cdf0e10cSrcweir     ::std::back_insert_iterator< ::std::vector< ::std::pair<double, double> > > ii(results);
1230*cdf0e10cSrcweir 
1231*cdf0e10cSrcweir     Impl_calcCollinearNormals( ii, delta, 0, c1, c1, 0.0, 1.0, c2, c2, 0.0, 1.0 );
1232*cdf0e10cSrcweir 
1233*cdf0e10cSrcweir     // As Sederberg's collinear normal theorem is only sufficient, not
1234*cdf0e10cSrcweir     // necessary for two intersections left and right, we've to test
1235*cdf0e10cSrcweir     // all segments generated by the collinear normal algorithm
1236*cdf0e10cSrcweir     // against each other. In other words, if the two curves are both
1237*cdf0e10cSrcweir     // divided in a left and a right part, the collinear normal
1238*cdf0e10cSrcweir     // theorem does _not_ state that the left part of curve 1 does not
1239*cdf0e10cSrcweir     // e.g. intersect with the right part of curve 2.
1240*cdf0e10cSrcweir 
1241*cdf0e10cSrcweir     // divide c1 and c2 at collinear normal intersection points
1242*cdf0e10cSrcweir     ::std::vector< Bezier > c1_segments( results.size()+1 );
1243*cdf0e10cSrcweir     ::std::vector< Bezier > c2_segments( results.size()+1 );
1244*cdf0e10cSrcweir     Bezier c1_remainder( c1 );
1245*cdf0e10cSrcweir     Bezier c2_remainder( c2 );
1246*cdf0e10cSrcweir     unsigned int i;
1247*cdf0e10cSrcweir     for( i=0; i<results.size(); ++i )
1248*cdf0e10cSrcweir     {
1249*cdf0e10cSrcweir         Bezier c1_part2;
1250*cdf0e10cSrcweir         Impl_deCasteljauAt( c1_segments[i], c1_part2, c1_remainder, results[i].first );
1251*cdf0e10cSrcweir         c1_remainder = c1_part2;
1252*cdf0e10cSrcweir 
1253*cdf0e10cSrcweir         Bezier c2_part2;
1254*cdf0e10cSrcweir         Impl_deCasteljauAt( c2_segments[i], c2_part2, c2_remainder, results[i].second );
1255*cdf0e10cSrcweir         c2_remainder = c2_part2;
1256*cdf0e10cSrcweir     }
1257*cdf0e10cSrcweir     c1_segments[i] = c1_remainder;
1258*cdf0e10cSrcweir     c2_segments[i] = c2_remainder;
1259*cdf0e10cSrcweir 
1260*cdf0e10cSrcweir     // now, c1/c2_segments contain all segments, then
1261*cdf0e10cSrcweir     // clip every resulting segment against every other
1262*cdf0e10cSrcweir     unsigned int c1_curr, c2_curr;
1263*cdf0e10cSrcweir     for( c1_curr=0; c1_curr<c1_segments.size(); ++c1_curr )
1264*cdf0e10cSrcweir     {
1265*cdf0e10cSrcweir         for( c2_curr=0; c2_curr<c2_segments.size(); ++c2_curr )
1266*cdf0e10cSrcweir         {
1267*cdf0e10cSrcweir             if( c1_curr != c2_curr )
1268*cdf0e10cSrcweir             {
1269*cdf0e10cSrcweir                 Impl_clipBezier_rec(result, delta, 0,
1270*cdf0e10cSrcweir                                     c1_segments[c1_curr], c1_segments[c1_curr],
1271*cdf0e10cSrcweir                                     0.0, 1.0,
1272*cdf0e10cSrcweir                                     c2_segments[c2_curr], c2_segments[c2_curr],
1273*cdf0e10cSrcweir                                     0.0, 1.0);
1274*cdf0e10cSrcweir             }
1275*cdf0e10cSrcweir         }
1276*cdf0e10cSrcweir     }
1277*cdf0e10cSrcweir #else
1278*cdf0e10cSrcweir     Impl_applySafeRanges_rec( result, delta, BezierTangencyFunctor(), 0, c1, c1, 0.0, 1.0, c2, c2, 0.0, 1.0 );
1279*cdf0e10cSrcweir     //Impl_applySafeRanges_rec( result, delta, ClipBezierFunctor(), 0, c1, c1, 0.0, 1.0, c2, c2, 0.0, 1.0 );
1280*cdf0e10cSrcweir #endif
1281*cdf0e10cSrcweir     // that's it, boys'n'girls!
1282*cdf0e10cSrcweir }
1283*cdf0e10cSrcweir 
1284*cdf0e10cSrcweir int main(int argc, const char *argv[])
1285*cdf0e10cSrcweir {
1286*cdf0e10cSrcweir     double curr_Offset( 0 );
1287*cdf0e10cSrcweir     unsigned int i,j,k;
1288*cdf0e10cSrcweir 
1289*cdf0e10cSrcweir     Bezier someCurves[] =
1290*cdf0e10cSrcweir         {
1291*cdf0e10cSrcweir //            {Point2D(0.0,0.0),Point2D(0.0,1.0),Point2D(1.0,1.0),Point2D(1.0,0.0)},
1292*cdf0e10cSrcweir //            {Point2D(0.0,0.0),Point2D(0.0,1.0),Point2D(1.0,1.0),Point2D(1.0,0.5)},
1293*cdf0e10cSrcweir //            {Point2D(1.0,0.0),Point2D(0.0,0.0),Point2D(0.0,1.0),Point2D(1.0,1.0)}
1294*cdf0e10cSrcweir //            {Point2D(0.25+1,0.5),Point2D(0.25+1,0.708333),Point2D(0.423611+1,0.916667),Point2D(0.770833+1,0.980324)},
1295*cdf0e10cSrcweir //            {Point2D(0.0+1,0.0),Point2D(0.0+1,1.0),Point2D(1.0+1,1.0),Point2D(1.0+1,0.5)}
1296*cdf0e10cSrcweir 
1297*cdf0e10cSrcweir // tangency1
1298*cdf0e10cSrcweir //            {Point2D(0.627124+1,0.828427),Point2D(0.763048+1,0.828507),Point2D(0.885547+1,0.77312),Point2D(0.950692+1,0.67325)},
1299*cdf0e10cSrcweir //            {Point2D(0.0,1.0),Point2D(0.1,1.0),Point2D(0.4,1.0),Point2D(0.5,1.0)}
1300*cdf0e10cSrcweir 
1301*cdf0e10cSrcweir //            {Point2D(0.0,0.0),Point2D(0.0,1.0),Point2D(1.0,1.0),Point2D(1.0,0.5)},
1302*cdf0e10cSrcweir //            {Point2D(0.60114,0.933091),Point2D(0.69461,0.969419),Point2D(0.80676,0.992976),Point2D(0.93756,0.998663)}
1303*cdf0e10cSrcweir //            {Point2D(1.0,0.0),Point2D(0.0,0.0),Point2D(0.0,1.0),Point2D(1.0,1.0)},
1304*cdf0e10cSrcweir //            {Point2D(0.62712,0.828427),Point2D(0.76305,0.828507),Point2D(0.88555,0.77312),Point2D(0.95069,0.67325)}
1305*cdf0e10cSrcweir 
1306*cdf0e10cSrcweir // clipping1
1307*cdf0e10cSrcweir //            {Point2D(0.0,0.0),Point2D(0.0,3.5),Point2D(1.0,-2.5),Point2D(1.0,1.0)},
1308*cdf0e10cSrcweir //            {Point2D(0.0,1.0),Point2D(3.5,1.0),Point2D(-2.5,0.0),Point2D(1.0,0.0)}
1309*cdf0e10cSrcweir 
1310*cdf0e10cSrcweir // tangency2
1311*cdf0e10cSrcweir //            {Point2D(0.0,1.0),Point2D(3.5,1.0),Point2D(-2.5,0.0),Point2D(1.0,0.0)},
1312*cdf0e10cSrcweir //            {Point2D(15.3621,0.00986464),Point2D(15.3683,0.0109389),Point2D(15.3682,0.0109315),Point2D(15.3621,0.00986464)}
1313*cdf0e10cSrcweir 
1314*cdf0e10cSrcweir // tangency3
1315*cdf0e10cSrcweir //            {Point2D(1.0,0.0),Point2D(0.0,0.0),Point2D(0.0,1.0),Point2D(1.0,1.0)},
1316*cdf0e10cSrcweir //            {Point2D(-0.5,0.0),Point2D(0.5,0.0),Point2D(0.5,1.0),Point2D(-0.5,1.0)}
1317*cdf0e10cSrcweir 
1318*cdf0e10cSrcweir // tangency4
1319*cdf0e10cSrcweir //            {Point2D(-0.5,0.0),Point2D(0.5,0.0),Point2D(0.5,1.0),Point2D(-0.5,1.0)},
1320*cdf0e10cSrcweir //            {Point2D(0.26,0.4),Point2D(0.25,0.5),Point2D(0.25,0.5),Point2D(0.26,0.6)}
1321*cdf0e10cSrcweir 
1322*cdf0e10cSrcweir // tangency5
1323*cdf0e10cSrcweir //            {Point2D(0.0,0.0),Point2D(0.0,3.5),Point2D(1.0,-2.5),Point2D(1.0,1.0)},
1324*cdf0e10cSrcweir //            {Point2D(15.3621,0.00986464),Point2D(15.3683,0.0109389),Point2D(15.3682,0.0109315),Point2D(15.3621,0.00986464)}
1325*cdf0e10cSrcweir 
1326*cdf0e10cSrcweir // tangency6
1327*cdf0e10cSrcweir //            {Point2D(0.0,0.0),Point2D(0.0,3.5),Point2D(1.0,-2.5),Point2D(1.0,1.0)},
1328*cdf0e10cSrcweir //            {Point2D(15.3621,10.00986464),Point2D(15.3683,10.0109389),Point2D(15.3682,10.0109315),Point2D(15.3621,10.00986464)}
1329*cdf0e10cSrcweir 
1330*cdf0e10cSrcweir // tangency7
1331*cdf0e10cSrcweir //            {Point2D(2.505,0.0),Point2D(2.505+4.915,4.300),Point2D(2.505+3.213,10.019),Point2D(2.505-2.505,10.255)},
1332*cdf0e10cSrcweir //            {Point2D(15.3621,10.00986464),Point2D(15.3683,10.0109389),Point2D(15.3682,10.0109315),Point2D(15.3621,10.00986464)}
1333*cdf0e10cSrcweir 
1334*cdf0e10cSrcweir // tangency Sederberg example
1335*cdf0e10cSrcweir             {Point2D(2.505,0.0),Point2D(2.505+4.915,4.300),Point2D(2.505+3.213,10.019),Point2D(2.505-2.505,10.255)},
1336*cdf0e10cSrcweir             {Point2D(5.33+9.311,0.0),Point2D(5.33+9.311-13.279,4.205),Point2D(5.33+9.311-10.681,9.119),Point2D(5.33+9.311-2.603,10.254)}
1337*cdf0e10cSrcweir 
1338*cdf0e10cSrcweir // clipping2
1339*cdf0e10cSrcweir //            {Point2D(-0.5,0.0),Point2D(0.5,0.0),Point2D(0.5,1.0),Point2D(-0.5,1.0)},
1340*cdf0e10cSrcweir //            {Point2D(0.2575,0.4),Point2D(0.2475,0.5),Point2D(0.2475,0.5),Point2D(0.2575,0.6)}
1341*cdf0e10cSrcweir 
1342*cdf0e10cSrcweir //            {Point2D(0.0,0.1),Point2D(0.2,3.5),Point2D(1.0,-2.5),Point2D(1.1,1.2)},
1343*cdf0e10cSrcweir //            {Point2D(0.0,1.0),Point2D(3.5,0.9),Point2D(-2.5,0.1),Point2D(1.1,0.2)}
1344*cdf0e10cSrcweir //            {Point2D(0.0,0.1),Point2D(0.2,3.0),Point2D(1.0,-2.0),Point2D(1.1,1.2)},
1345*cdf0e10cSrcweir //            {Point2D(0.627124+1,0.828427),Point2D(0.763048+1,0.828507),Point2D(0.885547+1,0.77312),Point2D(0.950692+1,0.67325)}
1346*cdf0e10cSrcweir //            {Point2D(0.0,1.0),Point2D(3.0,0.9),Point2D(-2.0,0.1),Point2D(1.1,0.2)}
1347*cdf0e10cSrcweir //            {Point2D(0.0,4.0),Point2D(0.1,5.0),Point2D(0.9,5.0),Point2D(1.0,4.0)},
1348*cdf0e10cSrcweir //            {Point2D(0.0,0.0),Point2D(0.1,0.5),Point2D(0.9,0.5),Point2D(1.0,0.0)},
1349*cdf0e10cSrcweir //            {Point2D(0.0,0.1),Point2D(0.1,1.5),Point2D(0.9,1.5),Point2D(1.0,0.1)},
1350*cdf0e10cSrcweir //            {Point2D(0.0,-4.0),Point2D(0.1,-5.0),Point2D(0.9,-5.0),Point2D(1.0,-4.0)}
1351*cdf0e10cSrcweir         };
1352*cdf0e10cSrcweir 
1353*cdf0e10cSrcweir     // output gnuplot setup
1354*cdf0e10cSrcweir     cout << "#!/usr/bin/gnuplot -persist" << endl
1355*cdf0e10cSrcweir          << "#" << endl
1356*cdf0e10cSrcweir          << "# automatically generated by bezierclip, don't change!" << endl
1357*cdf0e10cSrcweir          << "#" << endl
1358*cdf0e10cSrcweir          << "set parametric" << endl
1359*cdf0e10cSrcweir          << "bez(p,q,r,s,t) = p*(1-t)**3+q*3*(1-t)**2*t+r*3*(1-t)*t**2+s*t**3" << endl
1360*cdf0e10cSrcweir          << "bezd(p,q,r,s,t) = 3*(q-p)*(1-t)**2+6*(r-q)*(1-t)*t+3*(s-r)*t**2" << endl
1361*cdf0e10cSrcweir          << "pointmarkx(c,t) = c-0.03*t" << endl
1362*cdf0e10cSrcweir          << "pointmarky(c,t) = c+0.03*t" << endl
1363*cdf0e10cSrcweir          << "linex(a,b,c,t) = a*-c + t*-b" << endl
1364*cdf0e10cSrcweir          << "liney(a,b,c,t) = b*-c + t*a" << endl << endl
1365*cdf0e10cSrcweir          << "# end of setup" << endl << endl;
1366*cdf0e10cSrcweir 
1367*cdf0e10cSrcweir #ifdef WITH_CONVEXHULL_TEST
1368*cdf0e10cSrcweir     // test convex hull algorithm
1369*cdf0e10cSrcweir     const double convHull_xOffset( curr_Offset );
1370*cdf0e10cSrcweir     curr_Offset += 20;
1371*cdf0e10cSrcweir     cout << "# convex hull testing" << endl
1372*cdf0e10cSrcweir          << "plot [t=0:1] ";
1373*cdf0e10cSrcweir     for( i=0; i<sizeof(someCurves)/sizeof(Bezier); ++i )
1374*cdf0e10cSrcweir     {
1375*cdf0e10cSrcweir         Polygon2D aTestPoly(4);
1376*cdf0e10cSrcweir         aTestPoly[0] = someCurves[i].p0;
1377*cdf0e10cSrcweir         aTestPoly[1] = someCurves[i].p1;
1378*cdf0e10cSrcweir         aTestPoly[2] = someCurves[i].p2;
1379*cdf0e10cSrcweir         aTestPoly[3] = someCurves[i].p3;
1380*cdf0e10cSrcweir 
1381*cdf0e10cSrcweir         aTestPoly[0].x += convHull_xOffset;
1382*cdf0e10cSrcweir         aTestPoly[1].x += convHull_xOffset;
1383*cdf0e10cSrcweir         aTestPoly[2].x += convHull_xOffset;
1384*cdf0e10cSrcweir         aTestPoly[3].x += convHull_xOffset;
1385*cdf0e10cSrcweir 
1386*cdf0e10cSrcweir         cout << " bez("
1387*cdf0e10cSrcweir              << aTestPoly[0].x << ","
1388*cdf0e10cSrcweir              << aTestPoly[1].x << ","
1389*cdf0e10cSrcweir              << aTestPoly[2].x << ","
1390*cdf0e10cSrcweir              << aTestPoly[3].x << ",t),bez("
1391*cdf0e10cSrcweir              << aTestPoly[0].y << ","
1392*cdf0e10cSrcweir              << aTestPoly[1].y << ","
1393*cdf0e10cSrcweir              << aTestPoly[2].y << ","
1394*cdf0e10cSrcweir              << aTestPoly[3].y << ",t), '-' using ($1):($2) title \"convex hull " << i << "\" with lp";
1395*cdf0e10cSrcweir 
1396*cdf0e10cSrcweir         if( i+1<sizeof(someCurves)/sizeof(Bezier) )
1397*cdf0e10cSrcweir             cout << ",\\" << endl;
1398*cdf0e10cSrcweir         else
1399*cdf0e10cSrcweir             cout << endl;
1400*cdf0e10cSrcweir     }
1401*cdf0e10cSrcweir     for( i=0; i<sizeof(someCurves)/sizeof(Bezier); ++i )
1402*cdf0e10cSrcweir     {
1403*cdf0e10cSrcweir         Polygon2D aTestPoly(4);
1404*cdf0e10cSrcweir         aTestPoly[0] = someCurves[i].p0;
1405*cdf0e10cSrcweir         aTestPoly[1] = someCurves[i].p1;
1406*cdf0e10cSrcweir         aTestPoly[2] = someCurves[i].p2;
1407*cdf0e10cSrcweir         aTestPoly[3] = someCurves[i].p3;
1408*cdf0e10cSrcweir 
1409*cdf0e10cSrcweir         aTestPoly[0].x += convHull_xOffset;
1410*cdf0e10cSrcweir         aTestPoly[1].x += convHull_xOffset;
1411*cdf0e10cSrcweir         aTestPoly[2].x += convHull_xOffset;
1412*cdf0e10cSrcweir         aTestPoly[3].x += convHull_xOffset;
1413*cdf0e10cSrcweir 
1414*cdf0e10cSrcweir         Polygon2D convHull( convexHull(aTestPoly) );
1415*cdf0e10cSrcweir 
1416*cdf0e10cSrcweir         for( k=0; k<convHull.size(); ++k )
1417*cdf0e10cSrcweir         {
1418*cdf0e10cSrcweir             cout << convHull[k].x << " " << convHull[k].y << endl;
1419*cdf0e10cSrcweir         }
1420*cdf0e10cSrcweir         cout << convHull[0].x << " " << convHull[0].y << endl;
1421*cdf0e10cSrcweir         cout << "e" << endl;
1422*cdf0e10cSrcweir     }
1423*cdf0e10cSrcweir #endif
1424*cdf0e10cSrcweir 
1425*cdf0e10cSrcweir #ifdef WITH_MULTISUBDIVIDE_TEST
1426*cdf0e10cSrcweir     // test convex hull algorithm
1427*cdf0e10cSrcweir     const double multiSubdivide_xOffset( curr_Offset );
1428*cdf0e10cSrcweir     curr_Offset += 20;
1429*cdf0e10cSrcweir     cout << "# multi subdivide testing" << endl
1430*cdf0e10cSrcweir          << "plot [t=0:1] ";
1431*cdf0e10cSrcweir     for( i=0; i<sizeof(someCurves)/sizeof(Bezier); ++i )
1432*cdf0e10cSrcweir     {
1433*cdf0e10cSrcweir         Bezier c( someCurves[i] );
1434*cdf0e10cSrcweir         Bezier c1_part1;
1435*cdf0e10cSrcweir         Bezier c1_part2;
1436*cdf0e10cSrcweir         Bezier c1_part3;
1437*cdf0e10cSrcweir 
1438*cdf0e10cSrcweir         c.p0.x += multiSubdivide_xOffset;
1439*cdf0e10cSrcweir         c.p1.x += multiSubdivide_xOffset;
1440*cdf0e10cSrcweir         c.p2.x += multiSubdivide_xOffset;
1441*cdf0e10cSrcweir         c.p3.x += multiSubdivide_xOffset;
1442*cdf0e10cSrcweir 
1443*cdf0e10cSrcweir         const double t1( 0.1+i/(3.0*sizeof(someCurves)/sizeof(Bezier)) );
1444*cdf0e10cSrcweir         const double t2( 0.9-i/(3.0*sizeof(someCurves)/sizeof(Bezier)) );
1445*cdf0e10cSrcweir 
1446*cdf0e10cSrcweir         // subdivide at t1
1447*cdf0e10cSrcweir         Impl_deCasteljauAt( c1_part1, c1_part2, c, t1 );
1448*cdf0e10cSrcweir 
1449*cdf0e10cSrcweir         // subdivide at t2_c1. As we're working on
1450*cdf0e10cSrcweir         // c1_part2 now, we have to adapt t2_c1 since
1451*cdf0e10cSrcweir         // we're no longer in the original parameter
1452*cdf0e10cSrcweir         // interval. This is based on the following
1453*cdf0e10cSrcweir         // assumption: t2_new = (t2-t1)/(1-t1), which
1454*cdf0e10cSrcweir         // relates the t2 value into the new parameter
1455*cdf0e10cSrcweir         // range [0,1] of c1_part2.
1456*cdf0e10cSrcweir         Impl_deCasteljauAt( c1_part1, c1_part3, c1_part2, (t2-t1)/(1.0-t1) );
1457*cdf0e10cSrcweir 
1458*cdf0e10cSrcweir         // subdivide at t2
1459*cdf0e10cSrcweir         Impl_deCasteljauAt( c1_part3, c1_part2, c, t2 );
1460*cdf0e10cSrcweir 
1461*cdf0e10cSrcweir         cout << " bez("
1462*cdf0e10cSrcweir              << c1_part1.p0.x << ","
1463*cdf0e10cSrcweir              << c1_part1.p1.x << ","
1464*cdf0e10cSrcweir              << c1_part1.p2.x << ","
1465*cdf0e10cSrcweir              << c1_part1.p3.x << ",t), bez("
1466*cdf0e10cSrcweir              << c1_part1.p0.y+0.01 << ","
1467*cdf0e10cSrcweir              << c1_part1.p1.y+0.01 << ","
1468*cdf0e10cSrcweir              << c1_part1.p2.y+0.01 << ","
1469*cdf0e10cSrcweir              << c1_part1.p3.y+0.01 << ",t) title \"middle " << i << "\", "
1470*cdf0e10cSrcweir              << " bez("
1471*cdf0e10cSrcweir              << c1_part2.p0.x << ","
1472*cdf0e10cSrcweir              << c1_part2.p1.x << ","
1473*cdf0e10cSrcweir              << c1_part2.p2.x << ","
1474*cdf0e10cSrcweir              << c1_part2.p3.x << ",t), bez("
1475*cdf0e10cSrcweir              << c1_part2.p0.y << ","
1476*cdf0e10cSrcweir              << c1_part2.p1.y << ","
1477*cdf0e10cSrcweir              << c1_part2.p2.y << ","
1478*cdf0e10cSrcweir              << c1_part2.p3.y << ",t) title \"right " << i << "\", "
1479*cdf0e10cSrcweir              << " bez("
1480*cdf0e10cSrcweir              << c1_part3.p0.x << ","
1481*cdf0e10cSrcweir              << c1_part3.p1.x << ","
1482*cdf0e10cSrcweir              << c1_part3.p2.x << ","
1483*cdf0e10cSrcweir              << c1_part3.p3.x << ",t), bez("
1484*cdf0e10cSrcweir              << c1_part3.p0.y << ","
1485*cdf0e10cSrcweir              << c1_part3.p1.y << ","
1486*cdf0e10cSrcweir              << c1_part3.p2.y << ","
1487*cdf0e10cSrcweir              << c1_part3.p3.y << ",t) title \"left " << i << "\"";
1488*cdf0e10cSrcweir 
1489*cdf0e10cSrcweir 
1490*cdf0e10cSrcweir         if( i+1<sizeof(someCurves)/sizeof(Bezier) )
1491*cdf0e10cSrcweir             cout << ",\\" << endl;
1492*cdf0e10cSrcweir         else
1493*cdf0e10cSrcweir             cout << endl;
1494*cdf0e10cSrcweir     }
1495*cdf0e10cSrcweir #endif
1496*cdf0e10cSrcweir 
1497*cdf0e10cSrcweir #ifdef WITH_FATLINE_TEST
1498*cdf0e10cSrcweir     // test fatline algorithm
1499*cdf0e10cSrcweir     const double fatLine_xOffset( curr_Offset );
1500*cdf0e10cSrcweir     curr_Offset += 20;
1501*cdf0e10cSrcweir     cout << "# fat line testing" << endl
1502*cdf0e10cSrcweir          << "plot [t=0:1] ";
1503*cdf0e10cSrcweir     for( i=0; i<sizeof(someCurves)/sizeof(Bezier); ++i )
1504*cdf0e10cSrcweir     {
1505*cdf0e10cSrcweir         Bezier c( someCurves[i] );
1506*cdf0e10cSrcweir 
1507*cdf0e10cSrcweir         c.p0.x += fatLine_xOffset;
1508*cdf0e10cSrcweir         c.p1.x += fatLine_xOffset;
1509*cdf0e10cSrcweir         c.p2.x += fatLine_xOffset;
1510*cdf0e10cSrcweir         c.p3.x += fatLine_xOffset;
1511*cdf0e10cSrcweir 
1512*cdf0e10cSrcweir         FatLine line;
1513*cdf0e10cSrcweir 
1514*cdf0e10cSrcweir         Impl_calcFatLine(line, c);
1515*cdf0e10cSrcweir 
1516*cdf0e10cSrcweir         cout << " bez("
1517*cdf0e10cSrcweir              << c.p0.x << ","
1518*cdf0e10cSrcweir              << c.p1.x << ","
1519*cdf0e10cSrcweir              << c.p2.x << ","
1520*cdf0e10cSrcweir              << c.p3.x << ",t), bez("
1521*cdf0e10cSrcweir              << c.p0.y << ","
1522*cdf0e10cSrcweir              << c.p1.y << ","
1523*cdf0e10cSrcweir              << c.p2.y << ","
1524*cdf0e10cSrcweir              << c.p3.y << ",t) title \"bezier " << i << "\", linex("
1525*cdf0e10cSrcweir              << line.a << ","
1526*cdf0e10cSrcweir              << line.b << ","
1527*cdf0e10cSrcweir              << line.c << ",t), liney("
1528*cdf0e10cSrcweir              << line.a << ","
1529*cdf0e10cSrcweir              << line.b << ","
1530*cdf0e10cSrcweir              << line.c << ",t) title \"fat line (center) on " << i << "\", linex("
1531*cdf0e10cSrcweir              << line.a << ","
1532*cdf0e10cSrcweir              << line.b << ","
1533*cdf0e10cSrcweir              << line.c-line.dMin << ",t), liney("
1534*cdf0e10cSrcweir              << line.a << ","
1535*cdf0e10cSrcweir              << line.b << ","
1536*cdf0e10cSrcweir              << line.c-line.dMin << ",t) title \"fat line (min) on " << i << "\", linex("
1537*cdf0e10cSrcweir              << line.a << ","
1538*cdf0e10cSrcweir              << line.b << ","
1539*cdf0e10cSrcweir              << line.c-line.dMax << ",t), liney("
1540*cdf0e10cSrcweir              << line.a << ","
1541*cdf0e10cSrcweir              << line.b << ","
1542*cdf0e10cSrcweir              << line.c-line.dMax << ",t) title \"fat line (max) on " << i << "\"";
1543*cdf0e10cSrcweir 
1544*cdf0e10cSrcweir         if( i+1<sizeof(someCurves)/sizeof(Bezier) )
1545*cdf0e10cSrcweir             cout << ",\\" << endl;
1546*cdf0e10cSrcweir         else
1547*cdf0e10cSrcweir             cout << endl;
1548*cdf0e10cSrcweir     }
1549*cdf0e10cSrcweir #endif
1550*cdf0e10cSrcweir 
1551*cdf0e10cSrcweir #ifdef WITH_CALCFOCUS_TEST
1552*cdf0e10cSrcweir     // test focus curve algorithm
1553*cdf0e10cSrcweir     const double focus_xOffset( curr_Offset );
1554*cdf0e10cSrcweir     curr_Offset += 20;
1555*cdf0e10cSrcweir     cout << "# focus line testing" << endl
1556*cdf0e10cSrcweir          << "plot [t=0:1] ";
1557*cdf0e10cSrcweir     for( i=0; i<sizeof(someCurves)/sizeof(Bezier); ++i )
1558*cdf0e10cSrcweir     {
1559*cdf0e10cSrcweir         Bezier c( someCurves[i] );
1560*cdf0e10cSrcweir 
1561*cdf0e10cSrcweir         c.p0.x += focus_xOffset;
1562*cdf0e10cSrcweir         c.p1.x += focus_xOffset;
1563*cdf0e10cSrcweir         c.p2.x += focus_xOffset;
1564*cdf0e10cSrcweir         c.p3.x += focus_xOffset;
1565*cdf0e10cSrcweir 
1566*cdf0e10cSrcweir         // calc focus curve
1567*cdf0e10cSrcweir         Bezier focus;
1568*cdf0e10cSrcweir         Impl_calcFocus(focus, c);
1569*cdf0e10cSrcweir 
1570*cdf0e10cSrcweir         cout << " bez("
1571*cdf0e10cSrcweir              << c.p0.x << ","
1572*cdf0e10cSrcweir              << c.p1.x << ","
1573*cdf0e10cSrcweir              << c.p2.x << ","
1574*cdf0e10cSrcweir              << c.p3.x << ",t), bez("
1575*cdf0e10cSrcweir              << c.p0.y << ","
1576*cdf0e10cSrcweir              << c.p1.y << ","
1577*cdf0e10cSrcweir              << c.p2.y << ","
1578*cdf0e10cSrcweir              << c.p3.y << ",t) title \"bezier " << i << "\", bez("
1579*cdf0e10cSrcweir              << focus.p0.x << ","
1580*cdf0e10cSrcweir              << focus.p1.x << ","
1581*cdf0e10cSrcweir              << focus.p2.x << ","
1582*cdf0e10cSrcweir              << focus.p3.x << ",t), bez("
1583*cdf0e10cSrcweir              << focus.p0.y << ","
1584*cdf0e10cSrcweir              << focus.p1.y << ","
1585*cdf0e10cSrcweir              << focus.p2.y << ","
1586*cdf0e10cSrcweir              << focus.p3.y << ",t) title \"focus " << i << "\"";
1587*cdf0e10cSrcweir 
1588*cdf0e10cSrcweir 
1589*cdf0e10cSrcweir         if( i+1<sizeof(someCurves)/sizeof(Bezier) )
1590*cdf0e10cSrcweir             cout << ",\\" << endl;
1591*cdf0e10cSrcweir         else
1592*cdf0e10cSrcweir             cout << endl;
1593*cdf0e10cSrcweir     }
1594*cdf0e10cSrcweir #endif
1595*cdf0e10cSrcweir 
1596*cdf0e10cSrcweir #ifdef WITH_SAFEPARAMBASE_TEST
1597*cdf0e10cSrcweir     // test safe params base method
1598*cdf0e10cSrcweir     double safeParamsBase_xOffset( curr_Offset );
1599*cdf0e10cSrcweir     cout << "# safe param base method testing" << endl
1600*cdf0e10cSrcweir          << "plot [t=0:1] ";
1601*cdf0e10cSrcweir     for( i=0; i<sizeof(someCurves)/sizeof(Bezier); ++i )
1602*cdf0e10cSrcweir     {
1603*cdf0e10cSrcweir         Bezier c( someCurves[i] );
1604*cdf0e10cSrcweir 
1605*cdf0e10cSrcweir         c.p0.x += safeParamsBase_xOffset;
1606*cdf0e10cSrcweir         c.p1.x += safeParamsBase_xOffset;
1607*cdf0e10cSrcweir         c.p2.x += safeParamsBase_xOffset;
1608*cdf0e10cSrcweir         c.p3.x += safeParamsBase_xOffset;
1609*cdf0e10cSrcweir 
1610*cdf0e10cSrcweir         Polygon2D poly(4);
1611*cdf0e10cSrcweir         poly[0] = c.p0;
1612*cdf0e10cSrcweir         poly[1] = c.p1;
1613*cdf0e10cSrcweir         poly[2] = c.p2;
1614*cdf0e10cSrcweir         poly[3] = c.p3;
1615*cdf0e10cSrcweir 
1616*cdf0e10cSrcweir         double t1, t2;
1617*cdf0e10cSrcweir 
1618*cdf0e10cSrcweir         bool bRet( Impl_calcSafeParams( t1, t2, poly, 0, 1 ) );
1619*cdf0e10cSrcweir 
1620*cdf0e10cSrcweir         Polygon2D convHull( convexHull( poly ) );
1621*cdf0e10cSrcweir 
1622*cdf0e10cSrcweir         cout << " bez("
1623*cdf0e10cSrcweir              << poly[0].x << ","
1624*cdf0e10cSrcweir              << poly[1].x << ","
1625*cdf0e10cSrcweir              << poly[2].x << ","
1626*cdf0e10cSrcweir              << poly[3].x << ",t),bez("
1627*cdf0e10cSrcweir              << poly[0].y << ","
1628*cdf0e10cSrcweir              << poly[1].y << ","
1629*cdf0e10cSrcweir              << poly[2].y << ","
1630*cdf0e10cSrcweir              << poly[3].y << ",t), "
1631*cdf0e10cSrcweir              << "t+" << safeParamsBase_xOffset << ", 0, "
1632*cdf0e10cSrcweir              << "t+" << safeParamsBase_xOffset << ", 1, ";
1633*cdf0e10cSrcweir         if( bRet )
1634*cdf0e10cSrcweir         {
1635*cdf0e10cSrcweir             cout << t1+safeParamsBase_xOffset << ", t, "
1636*cdf0e10cSrcweir                  << t2+safeParamsBase_xOffset << ", t, ";
1637*cdf0e10cSrcweir         }
1638*cdf0e10cSrcweir         cout << "'-' using ($1):($2) title \"control polygon\" with lp, "
1639*cdf0e10cSrcweir              << "'-' using ($1):($2) title \"convex hull\" with lp";
1640*cdf0e10cSrcweir 
1641*cdf0e10cSrcweir         if( i+1<sizeof(someCurves)/sizeof(Bezier) )
1642*cdf0e10cSrcweir             cout << ",\\" << endl;
1643*cdf0e10cSrcweir         else
1644*cdf0e10cSrcweir             cout << endl;
1645*cdf0e10cSrcweir 
1646*cdf0e10cSrcweir         safeParamsBase_xOffset += 2;
1647*cdf0e10cSrcweir     }
1648*cdf0e10cSrcweir 
1649*cdf0e10cSrcweir     safeParamsBase_xOffset = curr_Offset;
1650*cdf0e10cSrcweir     for( i=0; i<sizeof(someCurves)/sizeof(Bezier); ++i )
1651*cdf0e10cSrcweir     {
1652*cdf0e10cSrcweir         Bezier c( someCurves[i] );
1653*cdf0e10cSrcweir 
1654*cdf0e10cSrcweir         c.p0.x += safeParamsBase_xOffset;
1655*cdf0e10cSrcweir         c.p1.x += safeParamsBase_xOffset;
1656*cdf0e10cSrcweir         c.p2.x += safeParamsBase_xOffset;
1657*cdf0e10cSrcweir         c.p3.x += safeParamsBase_xOffset;
1658*cdf0e10cSrcweir 
1659*cdf0e10cSrcweir         Polygon2D poly(4);
1660*cdf0e10cSrcweir         poly[0] = c.p0;
1661*cdf0e10cSrcweir         poly[1] = c.p1;
1662*cdf0e10cSrcweir         poly[2] = c.p2;
1663*cdf0e10cSrcweir         poly[3] = c.p3;
1664*cdf0e10cSrcweir 
1665*cdf0e10cSrcweir         double t1, t2;
1666*cdf0e10cSrcweir 
1667*cdf0e10cSrcweir         Impl_calcSafeParams( t1, t2, poly, 0, 1 );
1668*cdf0e10cSrcweir 
1669*cdf0e10cSrcweir         Polygon2D convHull( convexHull( poly ) );
1670*cdf0e10cSrcweir 
1671*cdf0e10cSrcweir         unsigned int k;
1672*cdf0e10cSrcweir         for( k=0; k<poly.size(); ++k )
1673*cdf0e10cSrcweir         {
1674*cdf0e10cSrcweir             cout << poly[k].x << " " << poly[k].y << endl;
1675*cdf0e10cSrcweir         }
1676*cdf0e10cSrcweir         cout << poly[0].x << " " << poly[0].y << endl;
1677*cdf0e10cSrcweir         cout << "e" << endl;
1678*cdf0e10cSrcweir 
1679*cdf0e10cSrcweir         for( k=0; k<convHull.size(); ++k )
1680*cdf0e10cSrcweir         {
1681*cdf0e10cSrcweir             cout << convHull[k].x << " " << convHull[k].y << endl;
1682*cdf0e10cSrcweir         }
1683*cdf0e10cSrcweir         cout << convHull[0].x << " " << convHull[0].y << endl;
1684*cdf0e10cSrcweir         cout << "e" << endl;
1685*cdf0e10cSrcweir 
1686*cdf0e10cSrcweir         safeParamsBase_xOffset += 2;
1687*cdf0e10cSrcweir     }
1688*cdf0e10cSrcweir     curr_Offset += 20;
1689*cdf0e10cSrcweir #endif
1690*cdf0e10cSrcweir 
1691*cdf0e10cSrcweir #ifdef WITH_SAFEPARAMS_TEST
1692*cdf0e10cSrcweir     // test safe parameter range algorithm
1693*cdf0e10cSrcweir     const double safeParams_xOffset( curr_Offset );
1694*cdf0e10cSrcweir     curr_Offset += 20;
1695*cdf0e10cSrcweir     cout << "# safe param range testing" << endl
1696*cdf0e10cSrcweir          << "plot [t=0.0:1.0] ";
1697*cdf0e10cSrcweir     for( i=0; i<sizeof(someCurves)/sizeof(Bezier); ++i )
1698*cdf0e10cSrcweir     {
1699*cdf0e10cSrcweir         for( j=i+1; j<sizeof(someCurves)/sizeof(Bezier); ++j )
1700*cdf0e10cSrcweir         {
1701*cdf0e10cSrcweir             Bezier c1( someCurves[i] );
1702*cdf0e10cSrcweir             Bezier c2( someCurves[j] );
1703*cdf0e10cSrcweir 
1704*cdf0e10cSrcweir             c1.p0.x += safeParams_xOffset;
1705*cdf0e10cSrcweir             c1.p1.x += safeParams_xOffset;
1706*cdf0e10cSrcweir             c1.p2.x += safeParams_xOffset;
1707*cdf0e10cSrcweir             c1.p3.x += safeParams_xOffset;
1708*cdf0e10cSrcweir             c2.p0.x += safeParams_xOffset;
1709*cdf0e10cSrcweir             c2.p1.x += safeParams_xOffset;
1710*cdf0e10cSrcweir             c2.p2.x += safeParams_xOffset;
1711*cdf0e10cSrcweir             c2.p3.x += safeParams_xOffset;
1712*cdf0e10cSrcweir 
1713*cdf0e10cSrcweir             double t1, t2;
1714*cdf0e10cSrcweir 
1715*cdf0e10cSrcweir             if( Impl_calcClipRange(t1, t2, c1, c1, c2, c2) )
1716*cdf0e10cSrcweir             {
1717*cdf0e10cSrcweir                 // clip safe ranges off c1
1718*cdf0e10cSrcweir                 Bezier c1_part1;
1719*cdf0e10cSrcweir                 Bezier c1_part2;
1720*cdf0e10cSrcweir                 Bezier c1_part3;
1721*cdf0e10cSrcweir 
1722*cdf0e10cSrcweir 				// subdivide at t1_c1
1723*cdf0e10cSrcweir                 Impl_deCasteljauAt( c1_part1, c1_part2, c1, t1 );
1724*cdf0e10cSrcweir 				// subdivide at t2_c1
1725*cdf0e10cSrcweir                 Impl_deCasteljauAt( c1_part1, c1_part3, c1_part2, (t2-t1)/(1.0-t1) );
1726*cdf0e10cSrcweir 
1727*cdf0e10cSrcweir 				// output remaining segment (c1_part1)
1728*cdf0e10cSrcweir 
1729*cdf0e10cSrcweir                 cout << " bez("
1730*cdf0e10cSrcweir                      << c1.p0.x << ","
1731*cdf0e10cSrcweir                      << c1.p1.x << ","
1732*cdf0e10cSrcweir                      << c1.p2.x << ","
1733*cdf0e10cSrcweir                      << c1.p3.x << ",t),bez("
1734*cdf0e10cSrcweir                      << c1.p0.y << ","
1735*cdf0e10cSrcweir                      << c1.p1.y << ","
1736*cdf0e10cSrcweir                      << c1.p2.y << ","
1737*cdf0e10cSrcweir                      << c1.p3.y << ",t), bez("
1738*cdf0e10cSrcweir                      << c2.p0.x << ","
1739*cdf0e10cSrcweir                      << c2.p1.x << ","
1740*cdf0e10cSrcweir                      << c2.p2.x << ","
1741*cdf0e10cSrcweir                      << c2.p3.x << ",t),bez("
1742*cdf0e10cSrcweir                      << c2.p0.y << ","
1743*cdf0e10cSrcweir                      << c2.p1.y << ","
1744*cdf0e10cSrcweir                      << c2.p2.y << ","
1745*cdf0e10cSrcweir                      << c2.p3.y << ",t), bez("
1746*cdf0e10cSrcweir                      << c1_part1.p0.x << ","
1747*cdf0e10cSrcweir                      << c1_part1.p1.x << ","
1748*cdf0e10cSrcweir                      << c1_part1.p2.x << ","
1749*cdf0e10cSrcweir                      << c1_part1.p3.x << ",t),bez("
1750*cdf0e10cSrcweir                      << c1_part1.p0.y << ","
1751*cdf0e10cSrcweir                      << c1_part1.p1.y << ","
1752*cdf0e10cSrcweir                      << c1_part1.p2.y << ","
1753*cdf0e10cSrcweir                      << c1_part1.p3.y << ",t)";
1754*cdf0e10cSrcweir 
1755*cdf0e10cSrcweir                 if( i+2<sizeof(someCurves)/sizeof(Bezier) )
1756*cdf0e10cSrcweir                     cout << ",\\" << endl;
1757*cdf0e10cSrcweir                 else
1758*cdf0e10cSrcweir                     cout << endl;
1759*cdf0e10cSrcweir             }
1760*cdf0e10cSrcweir         }
1761*cdf0e10cSrcweir     }
1762*cdf0e10cSrcweir #endif
1763*cdf0e10cSrcweir 
1764*cdf0e10cSrcweir #ifdef WITH_SAFEPARAM_DETAILED_TEST
1765*cdf0e10cSrcweir     // test safe parameter range algorithm
1766*cdf0e10cSrcweir     const double safeParams2_xOffset( curr_Offset );
1767*cdf0e10cSrcweir     curr_Offset += 20;
1768*cdf0e10cSrcweir     if( sizeof(someCurves)/sizeof(Bezier) > 1 )
1769*cdf0e10cSrcweir     {
1770*cdf0e10cSrcweir         Bezier c1( someCurves[0] );
1771*cdf0e10cSrcweir         Bezier c2( someCurves[1] );
1772*cdf0e10cSrcweir 
1773*cdf0e10cSrcweir         c1.p0.x += safeParams2_xOffset;
1774*cdf0e10cSrcweir         c1.p1.x += safeParams2_xOffset;
1775*cdf0e10cSrcweir         c1.p2.x += safeParams2_xOffset;
1776*cdf0e10cSrcweir         c1.p3.x += safeParams2_xOffset;
1777*cdf0e10cSrcweir         c2.p0.x += safeParams2_xOffset;
1778*cdf0e10cSrcweir         c2.p1.x += safeParams2_xOffset;
1779*cdf0e10cSrcweir         c2.p2.x += safeParams2_xOffset;
1780*cdf0e10cSrcweir         c2.p3.x += safeParams2_xOffset;
1781*cdf0e10cSrcweir 
1782*cdf0e10cSrcweir         double t1, t2;
1783*cdf0e10cSrcweir 
1784*cdf0e10cSrcweir         // output happens here
1785*cdf0e10cSrcweir         Impl_calcClipRange(t1, t2, c1, c1, c2, c2);
1786*cdf0e10cSrcweir     }
1787*cdf0e10cSrcweir #endif
1788*cdf0e10cSrcweir 
1789*cdf0e10cSrcweir #ifdef WITH_SAFEFOCUSPARAM_TEST
1790*cdf0e10cSrcweir     // test safe parameter range from focus algorithm
1791*cdf0e10cSrcweir     const double safeParamsFocus_xOffset( curr_Offset );
1792*cdf0e10cSrcweir     curr_Offset += 20;
1793*cdf0e10cSrcweir     cout << "# safe param range from focus testing" << endl
1794*cdf0e10cSrcweir          << "plot [t=0.0:1.0] ";
1795*cdf0e10cSrcweir     for( i=0; i<sizeof(someCurves)/sizeof(Bezier); ++i )
1796*cdf0e10cSrcweir     {
1797*cdf0e10cSrcweir         for( j=i+1; j<sizeof(someCurves)/sizeof(Bezier); ++j )
1798*cdf0e10cSrcweir         {
1799*cdf0e10cSrcweir             Bezier c1( someCurves[i] );
1800*cdf0e10cSrcweir             Bezier c2( someCurves[j] );
1801*cdf0e10cSrcweir 
1802*cdf0e10cSrcweir             c1.p0.x += safeParamsFocus_xOffset;
1803*cdf0e10cSrcweir             c1.p1.x += safeParamsFocus_xOffset;
1804*cdf0e10cSrcweir             c1.p2.x += safeParamsFocus_xOffset;
1805*cdf0e10cSrcweir             c1.p3.x += safeParamsFocus_xOffset;
1806*cdf0e10cSrcweir             c2.p0.x += safeParamsFocus_xOffset;
1807*cdf0e10cSrcweir             c2.p1.x += safeParamsFocus_xOffset;
1808*cdf0e10cSrcweir             c2.p2.x += safeParamsFocus_xOffset;
1809*cdf0e10cSrcweir             c2.p3.x += safeParamsFocus_xOffset;
1810*cdf0e10cSrcweir 
1811*cdf0e10cSrcweir             double t1, t2;
1812*cdf0e10cSrcweir 
1813*cdf0e10cSrcweir             Bezier focus;
1814*cdf0e10cSrcweir #ifdef WITH_SAFEFOCUSPARAM_CALCFOCUS
1815*cdf0e10cSrcweir #if 0
1816*cdf0e10cSrcweir             {
1817*cdf0e10cSrcweir                 // clip safe ranges off c1_orig
1818*cdf0e10cSrcweir                 Bezier c1_part1;
1819*cdf0e10cSrcweir                 Bezier c1_part2;
1820*cdf0e10cSrcweir                 Bezier c1_part3;
1821*cdf0e10cSrcweir 
1822*cdf0e10cSrcweir                 // subdivide at t1_c1
1823*cdf0e10cSrcweir                 Impl_deCasteljauAt( c1_part1, c1_part2, c2, 0.30204 );
1824*cdf0e10cSrcweir 
1825*cdf0e10cSrcweir                 // subdivide at t2_c1. As we're working on
1826*cdf0e10cSrcweir                 // c1_part2 now, we have to adapt t2_c1 since
1827*cdf0e10cSrcweir                 // we're no longer in the original parameter
1828*cdf0e10cSrcweir                 // interval. This is based on the following
1829*cdf0e10cSrcweir                 // assumption: t2_new = (t2-t1)/(1-t1), which
1830*cdf0e10cSrcweir                 // relates the t2 value into the new parameter
1831*cdf0e10cSrcweir                 // range [0,1] of c1_part2.
1832*cdf0e10cSrcweir                 Impl_deCasteljauAt( c1_part1, c1_part3, c1_part2, (0.57151-0.30204)/(1.0-0.30204) );
1833*cdf0e10cSrcweir 
1834*cdf0e10cSrcweir                 c2 = c1_part1;
1835*cdf0e10cSrcweir                 Impl_calcFocus( focus, c2 );
1836*cdf0e10cSrcweir             }
1837*cdf0e10cSrcweir #else
1838*cdf0e10cSrcweir             Impl_calcFocus( focus, c2 );
1839*cdf0e10cSrcweir #endif
1840*cdf0e10cSrcweir #else
1841*cdf0e10cSrcweir             focus = c2;
1842*cdf0e10cSrcweir #endif
1843*cdf0e10cSrcweir             // determine safe range on c1
1844*cdf0e10cSrcweir             bool bRet( Impl_calcSafeParams_focus( t1, t2,
1845*cdf0e10cSrcweir                                                   c1, focus ) );
1846*cdf0e10cSrcweir 
1847*cdf0e10cSrcweir             cerr << "t1: " << t1 << ", t2: " << t2 << endl;
1848*cdf0e10cSrcweir 
1849*cdf0e10cSrcweir             // clip safe ranges off c1
1850*cdf0e10cSrcweir             Bezier c1_part1;
1851*cdf0e10cSrcweir             Bezier c1_part2;
1852*cdf0e10cSrcweir             Bezier c1_part3;
1853*cdf0e10cSrcweir 
1854*cdf0e10cSrcweir             // subdivide at t1_c1
1855*cdf0e10cSrcweir             Impl_deCasteljauAt( c1_part1, c1_part2, c1, t1 );
1856*cdf0e10cSrcweir             // subdivide at t2_c1
1857*cdf0e10cSrcweir             Impl_deCasteljauAt( c1_part1, c1_part3, c1_part2, (t2-t1)/(1.0-t1) );
1858*cdf0e10cSrcweir 
1859*cdf0e10cSrcweir             // output remaining segment (c1_part1)
1860*cdf0e10cSrcweir 
1861*cdf0e10cSrcweir             cout << " bez("
1862*cdf0e10cSrcweir                  << c1.p0.x << ","
1863*cdf0e10cSrcweir                  << c1.p1.x << ","
1864*cdf0e10cSrcweir                  << c1.p2.x << ","
1865*cdf0e10cSrcweir                  << c1.p3.x << ",t),bez("
1866*cdf0e10cSrcweir                  << c1.p0.y << ","
1867*cdf0e10cSrcweir                  << c1.p1.y << ","
1868*cdf0e10cSrcweir                  << c1.p2.y << ","
1869*cdf0e10cSrcweir                  << c1.p3.y << ",t) title \"c1\", "
1870*cdf0e10cSrcweir #ifdef WITH_SAFEFOCUSPARAM_CALCFOCUS
1871*cdf0e10cSrcweir                  << "bez("
1872*cdf0e10cSrcweir                  << c2.p0.x << ","
1873*cdf0e10cSrcweir                  << c2.p1.x << ","
1874*cdf0e10cSrcweir                  << c2.p2.x << ","
1875*cdf0e10cSrcweir                  << c2.p3.x << ",t),bez("
1876*cdf0e10cSrcweir                  << c2.p0.y << ","
1877*cdf0e10cSrcweir                  << c2.p1.y << ","
1878*cdf0e10cSrcweir                  << c2.p2.y << ","
1879*cdf0e10cSrcweir                  << c2.p3.y << ",t) title \"c2\", "
1880*cdf0e10cSrcweir                  << "bez("
1881*cdf0e10cSrcweir                  << focus.p0.x << ","
1882*cdf0e10cSrcweir                  << focus.p1.x << ","
1883*cdf0e10cSrcweir                  << focus.p2.x << ","
1884*cdf0e10cSrcweir                  << focus.p3.x << ",t),bez("
1885*cdf0e10cSrcweir                  << focus.p0.y << ","
1886*cdf0e10cSrcweir                  << focus.p1.y << ","
1887*cdf0e10cSrcweir                  << focus.p2.y << ","
1888*cdf0e10cSrcweir                  << focus.p3.y << ",t) title \"focus\"";
1889*cdf0e10cSrcweir #else
1890*cdf0e10cSrcweir                  << "bez("
1891*cdf0e10cSrcweir                  << c2.p0.x << ","
1892*cdf0e10cSrcweir                  << c2.p1.x << ","
1893*cdf0e10cSrcweir                  << c2.p2.x << ","
1894*cdf0e10cSrcweir                  << c2.p3.x << ",t),bez("
1895*cdf0e10cSrcweir                  << c2.p0.y << ","
1896*cdf0e10cSrcweir                  << c2.p1.y << ","
1897*cdf0e10cSrcweir                  << c2.p2.y << ","
1898*cdf0e10cSrcweir                  << c2.p3.y << ",t) title \"focus\"";
1899*cdf0e10cSrcweir #endif
1900*cdf0e10cSrcweir             if( bRet )
1901*cdf0e10cSrcweir             {
1902*cdf0e10cSrcweir                 cout << ", bez("
1903*cdf0e10cSrcweir                      << c1_part1.p0.x << ","
1904*cdf0e10cSrcweir                      << c1_part1.p1.x << ","
1905*cdf0e10cSrcweir                      << c1_part1.p2.x << ","
1906*cdf0e10cSrcweir                      << c1_part1.p3.x << ",t),bez("
1907*cdf0e10cSrcweir                      << c1_part1.p0.y+0.01 << ","
1908*cdf0e10cSrcweir                      << c1_part1.p1.y+0.01 << ","
1909*cdf0e10cSrcweir                      << c1_part1.p2.y+0.01 << ","
1910*cdf0e10cSrcweir                      << c1_part1.p3.y+0.01 << ",t) title \"part\"";
1911*cdf0e10cSrcweir             }
1912*cdf0e10cSrcweir 
1913*cdf0e10cSrcweir             if( i+2<sizeof(someCurves)/sizeof(Bezier) )
1914*cdf0e10cSrcweir                 cout << ",\\" << endl;
1915*cdf0e10cSrcweir             else
1916*cdf0e10cSrcweir                 cout << endl;
1917*cdf0e10cSrcweir         }
1918*cdf0e10cSrcweir     }
1919*cdf0e10cSrcweir #endif
1920*cdf0e10cSrcweir 
1921*cdf0e10cSrcweir #ifdef WITH_SAFEFOCUSPARAM_DETAILED_TEST
1922*cdf0e10cSrcweir     // test safe parameter range algorithm
1923*cdf0e10cSrcweir     const double safeParams3_xOffset( curr_Offset );
1924*cdf0e10cSrcweir     curr_Offset += 20;
1925*cdf0e10cSrcweir     if( sizeof(someCurves)/sizeof(Bezier) > 1 )
1926*cdf0e10cSrcweir     {
1927*cdf0e10cSrcweir         Bezier c1( someCurves[0] );
1928*cdf0e10cSrcweir         Bezier c2( someCurves[1] );
1929*cdf0e10cSrcweir 
1930*cdf0e10cSrcweir         c1.p0.x += safeParams3_xOffset;
1931*cdf0e10cSrcweir         c1.p1.x += safeParams3_xOffset;
1932*cdf0e10cSrcweir         c1.p2.x += safeParams3_xOffset;
1933*cdf0e10cSrcweir         c1.p3.x += safeParams3_xOffset;
1934*cdf0e10cSrcweir         c2.p0.x += safeParams3_xOffset;
1935*cdf0e10cSrcweir         c2.p1.x += safeParams3_xOffset;
1936*cdf0e10cSrcweir         c2.p2.x += safeParams3_xOffset;
1937*cdf0e10cSrcweir         c2.p3.x += safeParams3_xOffset;
1938*cdf0e10cSrcweir 
1939*cdf0e10cSrcweir         double t1, t2;
1940*cdf0e10cSrcweir 
1941*cdf0e10cSrcweir         Bezier focus;
1942*cdf0e10cSrcweir #ifdef WITH_SAFEFOCUSPARAM_CALCFOCUS
1943*cdf0e10cSrcweir         Impl_calcFocus( focus, c2 );
1944*cdf0e10cSrcweir #else
1945*cdf0e10cSrcweir         focus = c2;
1946*cdf0e10cSrcweir #endif
1947*cdf0e10cSrcweir 
1948*cdf0e10cSrcweir         // determine safe range on c1, output happens here
1949*cdf0e10cSrcweir         Impl_calcSafeParams_focus( t1, t2,
1950*cdf0e10cSrcweir                                    c1, focus );
1951*cdf0e10cSrcweir     }
1952*cdf0e10cSrcweir #endif
1953*cdf0e10cSrcweir 
1954*cdf0e10cSrcweir #ifdef WITH_BEZIERCLIP_TEST
1955*cdf0e10cSrcweir     ::std::vector< ::std::pair<double, double> > 								result;
1956*cdf0e10cSrcweir     ::std::back_insert_iterator< ::std::vector< ::std::pair<double, double> > > ii(result);
1957*cdf0e10cSrcweir 
1958*cdf0e10cSrcweir     // test full bezier clipping
1959*cdf0e10cSrcweir     const double bezierClip_xOffset( curr_Offset );
1960*cdf0e10cSrcweir     curr_Offset += 20;
1961*cdf0e10cSrcweir     cout << endl << endl << "# bezier clip testing" << endl
1962*cdf0e10cSrcweir          << "plot [t=0:1] ";
1963*cdf0e10cSrcweir     for( i=0; i<sizeof(someCurves)/sizeof(Bezier); ++i )
1964*cdf0e10cSrcweir     {
1965*cdf0e10cSrcweir         for( j=i+1; j<sizeof(someCurves)/sizeof(Bezier); ++j )
1966*cdf0e10cSrcweir         {
1967*cdf0e10cSrcweir             Bezier c1( someCurves[i] );
1968*cdf0e10cSrcweir             Bezier c2( someCurves[j] );
1969*cdf0e10cSrcweir 
1970*cdf0e10cSrcweir             c1.p0.x += bezierClip_xOffset;
1971*cdf0e10cSrcweir             c1.p1.x += bezierClip_xOffset;
1972*cdf0e10cSrcweir             c1.p2.x += bezierClip_xOffset;
1973*cdf0e10cSrcweir             c1.p3.x += bezierClip_xOffset;
1974*cdf0e10cSrcweir             c2.p0.x += bezierClip_xOffset;
1975*cdf0e10cSrcweir             c2.p1.x += bezierClip_xOffset;
1976*cdf0e10cSrcweir             c2.p2.x += bezierClip_xOffset;
1977*cdf0e10cSrcweir             c2.p3.x += bezierClip_xOffset;
1978*cdf0e10cSrcweir 
1979*cdf0e10cSrcweir             cout << " bez("
1980*cdf0e10cSrcweir                  << c1.p0.x << ","
1981*cdf0e10cSrcweir                  << c1.p1.x << ","
1982*cdf0e10cSrcweir                  << c1.p2.x << ","
1983*cdf0e10cSrcweir                  << c1.p3.x << ",t),bez("
1984*cdf0e10cSrcweir                  << c1.p0.y << ","
1985*cdf0e10cSrcweir                  << c1.p1.y << ","
1986*cdf0e10cSrcweir                  << c1.p2.y << ","
1987*cdf0e10cSrcweir                  << c1.p3.y << ",t), bez("
1988*cdf0e10cSrcweir                  << c2.p0.x << ","
1989*cdf0e10cSrcweir                  << c2.p1.x << ","
1990*cdf0e10cSrcweir                  << c2.p2.x << ","
1991*cdf0e10cSrcweir                  << c2.p3.x << ",t),bez("
1992*cdf0e10cSrcweir                  << c2.p0.y << ","
1993*cdf0e10cSrcweir                  << c2.p1.y << ","
1994*cdf0e10cSrcweir                  << c2.p2.y << ","
1995*cdf0e10cSrcweir                  << c2.p3.y << ",t), '-' using (bez("
1996*cdf0e10cSrcweir                  << c1.p0.x << ","
1997*cdf0e10cSrcweir                  << c1.p1.x << ","
1998*cdf0e10cSrcweir                  << c1.p2.x << ","
1999*cdf0e10cSrcweir                  << c1.p3.x
2000*cdf0e10cSrcweir                  << ",$1)):(bez("
2001*cdf0e10cSrcweir                  << c1.p0.y << ","
2002*cdf0e10cSrcweir                  << c1.p1.y << ","
2003*cdf0e10cSrcweir                  << c1.p2.y << ","
2004*cdf0e10cSrcweir                  << c1.p3.y << ",$1)) title \"bezier " << i << " clipped against " << j << " (t on " << i << ")\", "
2005*cdf0e10cSrcweir                  << " '-' using (bez("
2006*cdf0e10cSrcweir                  << c2.p0.x << ","
2007*cdf0e10cSrcweir                  << c2.p1.x << ","
2008*cdf0e10cSrcweir                  << c2.p2.x << ","
2009*cdf0e10cSrcweir                  << c2.p3.x
2010*cdf0e10cSrcweir                  << ",$1)):(bez("
2011*cdf0e10cSrcweir                  << c2.p0.y << ","
2012*cdf0e10cSrcweir                  << c2.p1.y << ","
2013*cdf0e10cSrcweir                  << c2.p2.y << ","
2014*cdf0e10cSrcweir                  << c2.p3.y << ",$1)) title \"bezier " << i << " clipped against " << j << " (t on " << j << ")\"";
2015*cdf0e10cSrcweir 
2016*cdf0e10cSrcweir             if( i+2<sizeof(someCurves)/sizeof(Bezier) )
2017*cdf0e10cSrcweir                 cout << ",\\" << endl;
2018*cdf0e10cSrcweir             else
2019*cdf0e10cSrcweir                 cout << endl;
2020*cdf0e10cSrcweir         }
2021*cdf0e10cSrcweir     }
2022*cdf0e10cSrcweir     for( i=0; i<sizeof(someCurves)/sizeof(Bezier); ++i )
2023*cdf0e10cSrcweir     {
2024*cdf0e10cSrcweir         for( j=i+1; j<sizeof(someCurves)/sizeof(Bezier); ++j )
2025*cdf0e10cSrcweir         {
2026*cdf0e10cSrcweir             result.clear();
2027*cdf0e10cSrcweir             Bezier c1( someCurves[i] );
2028*cdf0e10cSrcweir             Bezier c2( someCurves[j] );
2029*cdf0e10cSrcweir 
2030*cdf0e10cSrcweir             c1.p0.x += bezierClip_xOffset;
2031*cdf0e10cSrcweir             c1.p1.x += bezierClip_xOffset;
2032*cdf0e10cSrcweir             c1.p2.x += bezierClip_xOffset;
2033*cdf0e10cSrcweir             c1.p3.x += bezierClip_xOffset;
2034*cdf0e10cSrcweir             c2.p0.x += bezierClip_xOffset;
2035*cdf0e10cSrcweir             c2.p1.x += bezierClip_xOffset;
2036*cdf0e10cSrcweir             c2.p2.x += bezierClip_xOffset;
2037*cdf0e10cSrcweir             c2.p3.x += bezierClip_xOffset;
2038*cdf0e10cSrcweir 
2039*cdf0e10cSrcweir             clipBezier( ii, 0.00001, c1, c2 );
2040*cdf0e10cSrcweir 
2041*cdf0e10cSrcweir             for( k=0; k<result.size(); ++k )
2042*cdf0e10cSrcweir             {
2043*cdf0e10cSrcweir                 cout << result[k].first << endl;
2044*cdf0e10cSrcweir             }
2045*cdf0e10cSrcweir             cout << "e" << endl;
2046*cdf0e10cSrcweir 
2047*cdf0e10cSrcweir             for( k=0; k<result.size(); ++k )
2048*cdf0e10cSrcweir             {
2049*cdf0e10cSrcweir                 cout << result[k].second << endl;
2050*cdf0e10cSrcweir             }
2051*cdf0e10cSrcweir             cout << "e" << endl;
2052*cdf0e10cSrcweir         }
2053*cdf0e10cSrcweir     }
2054*cdf0e10cSrcweir #endif
2055*cdf0e10cSrcweir 
2056*cdf0e10cSrcweir     return 0;
2057*cdf0e10cSrcweir }
2058