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