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