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 #include <basegfx/polygon/b2dpolygoncutandtouch.hxx> 31*cdf0e10cSrcweir #include <osl/diagnose.h> 32*cdf0e10cSrcweir #include <basegfx/numeric/ftools.hxx> 33*cdf0e10cSrcweir #include <basegfx/point/b2dpoint.hxx> 34*cdf0e10cSrcweir #include <basegfx/vector/b2dvector.hxx> 35*cdf0e10cSrcweir #include <basegfx/range/b2drange.hxx> 36*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygontools.hxx> 37*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygontools.hxx> 38*cdf0e10cSrcweir #include <basegfx/curve/b2dcubicbezier.hxx> 39*cdf0e10cSrcweir 40*cdf0e10cSrcweir #include <vector> 41*cdf0e10cSrcweir #include <algorithm> 42*cdf0e10cSrcweir 43*cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 44*cdf0e10cSrcweir // defines 45*cdf0e10cSrcweir 46*cdf0e10cSrcweir #define SUBDIVIDE_FOR_CUT_TEST_COUNT (50) 47*cdf0e10cSrcweir 48*cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 49*cdf0e10cSrcweir 50*cdf0e10cSrcweir namespace basegfx 51*cdf0e10cSrcweir { 52*cdf0e10cSrcweir namespace 53*cdf0e10cSrcweir { 54*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////// 55*cdf0e10cSrcweir 56*cdf0e10cSrcweir class temporaryPoint 57*cdf0e10cSrcweir { 58*cdf0e10cSrcweir B2DPoint maPoint; // the new point 59*cdf0e10cSrcweir sal_uInt32 mnIndex; // index after which to insert 60*cdf0e10cSrcweir double mfCut; // parametric cut description [0.0 .. 1.0] 61*cdf0e10cSrcweir 62*cdf0e10cSrcweir public: 63*cdf0e10cSrcweir temporaryPoint(const B2DPoint& rNewPoint, sal_uInt32 nIndex, double fCut) 64*cdf0e10cSrcweir : maPoint(rNewPoint), 65*cdf0e10cSrcweir mnIndex(nIndex), 66*cdf0e10cSrcweir mfCut(fCut) 67*cdf0e10cSrcweir { 68*cdf0e10cSrcweir } 69*cdf0e10cSrcweir 70*cdf0e10cSrcweir bool operator<(const temporaryPoint& rComp) const 71*cdf0e10cSrcweir { 72*cdf0e10cSrcweir if(mnIndex == rComp.mnIndex) 73*cdf0e10cSrcweir { 74*cdf0e10cSrcweir return (mfCut < rComp.mfCut); 75*cdf0e10cSrcweir } 76*cdf0e10cSrcweir 77*cdf0e10cSrcweir return (mnIndex < rComp.mnIndex); 78*cdf0e10cSrcweir } 79*cdf0e10cSrcweir 80*cdf0e10cSrcweir const B2DPoint& getPoint() const { return maPoint; } 81*cdf0e10cSrcweir sal_uInt32 getIndex() const { return mnIndex; } 82*cdf0e10cSrcweir double getCut() const { return mfCut; } 83*cdf0e10cSrcweir }; 84*cdf0e10cSrcweir 85*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////// 86*cdf0e10cSrcweir 87*cdf0e10cSrcweir typedef ::std::vector< temporaryPoint > temporaryPointVector; 88*cdf0e10cSrcweir 89*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////// 90*cdf0e10cSrcweir 91*cdf0e10cSrcweir class temporaryPolygonData 92*cdf0e10cSrcweir { 93*cdf0e10cSrcweir B2DPolygon maPolygon; 94*cdf0e10cSrcweir B2DRange maRange; 95*cdf0e10cSrcweir temporaryPointVector maPoints; 96*cdf0e10cSrcweir 97*cdf0e10cSrcweir public: 98*cdf0e10cSrcweir const B2DPolygon& getPolygon() const { return maPolygon; } 99*cdf0e10cSrcweir void setPolygon(const B2DPolygon& rNew) { maPolygon = rNew; maRange = tools::getRange(maPolygon); } 100*cdf0e10cSrcweir const B2DRange& getRange() const { return maRange; } 101*cdf0e10cSrcweir temporaryPointVector& getTemporaryPointVector() { return maPoints; } 102*cdf0e10cSrcweir }; 103*cdf0e10cSrcweir 104*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////// 105*cdf0e10cSrcweir 106*cdf0e10cSrcweir B2DPolygon mergeTemporaryPointsAndPolygon(const B2DPolygon& rCandidate, temporaryPointVector& rTempPoints) 107*cdf0e10cSrcweir { 108*cdf0e10cSrcweir // #i76891# mergeTemporaryPointsAndPolygon redesigned to be able to correctly handle 109*cdf0e10cSrcweir // single edges with/without control points 110*cdf0e10cSrcweir // #i101491# added counter for non-changing element count 111*cdf0e10cSrcweir const sal_uInt32 nTempPointCount(rTempPoints.size()); 112*cdf0e10cSrcweir 113*cdf0e10cSrcweir if(nTempPointCount) 114*cdf0e10cSrcweir { 115*cdf0e10cSrcweir B2DPolygon aRetval; 116*cdf0e10cSrcweir const sal_uInt32 nCount(rCandidate.count()); 117*cdf0e10cSrcweir 118*cdf0e10cSrcweir if(nCount) 119*cdf0e10cSrcweir { 120*cdf0e10cSrcweir // sort temp points to assure increasing fCut values and increasing indices 121*cdf0e10cSrcweir ::std::sort(rTempPoints.begin(), rTempPoints.end()); 122*cdf0e10cSrcweir 123*cdf0e10cSrcweir // prepare loop 124*cdf0e10cSrcweir B2DCubicBezier aEdge; 125*cdf0e10cSrcweir sal_uInt32 nNewInd(0L); 126*cdf0e10cSrcweir 127*cdf0e10cSrcweir // add start point 128*cdf0e10cSrcweir aRetval.append(rCandidate.getB2DPoint(0)); 129*cdf0e10cSrcweir 130*cdf0e10cSrcweir for(sal_uInt32 a(0L); a < nCount; a++) 131*cdf0e10cSrcweir { 132*cdf0e10cSrcweir // get edge 133*cdf0e10cSrcweir rCandidate.getBezierSegment(a, aEdge); 134*cdf0e10cSrcweir 135*cdf0e10cSrcweir if(aEdge.isBezier()) 136*cdf0e10cSrcweir { 137*cdf0e10cSrcweir // control vectors involved for this edge 138*cdf0e10cSrcweir double fLeftStart(0.0); 139*cdf0e10cSrcweir 140*cdf0e10cSrcweir // now add all points targeted to be at this index 141*cdf0e10cSrcweir while(nNewInd < nTempPointCount && rTempPoints[nNewInd].getIndex() == a) 142*cdf0e10cSrcweir { 143*cdf0e10cSrcweir const temporaryPoint& rTempPoint = rTempPoints[nNewInd++]; 144*cdf0e10cSrcweir 145*cdf0e10cSrcweir // split curve segment. Splits need to come sorted and need to be < 1.0. Also, 146*cdf0e10cSrcweir // since original segment is consumed from left to right, the cut values need 147*cdf0e10cSrcweir // to be scaled to the remaining part 148*cdf0e10cSrcweir B2DCubicBezier aLeftPart; 149*cdf0e10cSrcweir const double fRelativeSplitPoint((rTempPoint.getCut() - fLeftStart) / (1.0 - fLeftStart)); 150*cdf0e10cSrcweir aEdge.split(fRelativeSplitPoint, &aLeftPart, &aEdge); 151*cdf0e10cSrcweir fLeftStart = rTempPoint.getCut(); 152*cdf0e10cSrcweir 153*cdf0e10cSrcweir // add left bow 154*cdf0e10cSrcweir aRetval.appendBezierSegment(aLeftPart.getControlPointA(), aLeftPart.getControlPointB(), rTempPoint.getPoint()); 155*cdf0e10cSrcweir } 156*cdf0e10cSrcweir 157*cdf0e10cSrcweir // add remaining bow 158*cdf0e10cSrcweir aRetval.appendBezierSegment(aEdge.getControlPointA(), aEdge.getControlPointB(), aEdge.getEndPoint()); 159*cdf0e10cSrcweir } 160*cdf0e10cSrcweir else 161*cdf0e10cSrcweir { 162*cdf0e10cSrcweir // add all points targeted to be at this index 163*cdf0e10cSrcweir while(nNewInd < nTempPointCount && rTempPoints[nNewInd].getIndex() == a) 164*cdf0e10cSrcweir { 165*cdf0e10cSrcweir const temporaryPoint& rTempPoint = rTempPoints[nNewInd++]; 166*cdf0e10cSrcweir const B2DPoint aNewPoint(rTempPoint.getPoint()); 167*cdf0e10cSrcweir 168*cdf0e10cSrcweir // do not add points double 169*cdf0e10cSrcweir if(!aRetval.getB2DPoint(aRetval.count() - 1L).equal(aNewPoint)) 170*cdf0e10cSrcweir { 171*cdf0e10cSrcweir aRetval.append(aNewPoint); 172*cdf0e10cSrcweir } 173*cdf0e10cSrcweir } 174*cdf0e10cSrcweir 175*cdf0e10cSrcweir // add edge end point 176*cdf0e10cSrcweir aRetval.append(aEdge.getEndPoint()); 177*cdf0e10cSrcweir } 178*cdf0e10cSrcweir } 179*cdf0e10cSrcweir } 180*cdf0e10cSrcweir 181*cdf0e10cSrcweir if(rCandidate.isClosed()) 182*cdf0e10cSrcweir { 183*cdf0e10cSrcweir // set closed flag and correct last point (which is added double now). 184*cdf0e10cSrcweir tools::closeWithGeometryChange(aRetval); 185*cdf0e10cSrcweir } 186*cdf0e10cSrcweir 187*cdf0e10cSrcweir return aRetval; 188*cdf0e10cSrcweir } 189*cdf0e10cSrcweir else 190*cdf0e10cSrcweir { 191*cdf0e10cSrcweir return rCandidate; 192*cdf0e10cSrcweir } 193*cdf0e10cSrcweir } 194*cdf0e10cSrcweir 195*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////// 196*cdf0e10cSrcweir 197*cdf0e10cSrcweir void adaptAndTransferCutsWithBezierSegment( 198*cdf0e10cSrcweir const temporaryPointVector& rPointVector, const B2DPolygon& rPolygon, 199*cdf0e10cSrcweir sal_uInt32 nInd, temporaryPointVector& rTempPoints) 200*cdf0e10cSrcweir { 201*cdf0e10cSrcweir // assuming that the subdivision to create rPolygon used aequidistant pieces 202*cdf0e10cSrcweir // (as in adaptiveSubdivideByCount) it is now possible to calculate back the 203*cdf0e10cSrcweir // cut positions in the polygon to relative cut positions on the original bezier 204*cdf0e10cSrcweir // segment. 205*cdf0e10cSrcweir const sal_uInt32 nTempPointCount(rPointVector.size()); 206*cdf0e10cSrcweir const sal_uInt32 nEdgeCount(rPolygon.count() ? rPolygon.count() - 1L : 0L); 207*cdf0e10cSrcweir 208*cdf0e10cSrcweir if(nTempPointCount && nEdgeCount) 209*cdf0e10cSrcweir { 210*cdf0e10cSrcweir for(sal_uInt32 a(0L); a < nTempPointCount; a++) 211*cdf0e10cSrcweir { 212*cdf0e10cSrcweir const temporaryPoint& rTempPoint = rPointVector[a]; 213*cdf0e10cSrcweir const double fCutPosInPolygon((double)rTempPoint.getIndex() + rTempPoint.getCut()); 214*cdf0e10cSrcweir const double fRelativeCutPos(fCutPosInPolygon / (double)nEdgeCount); 215*cdf0e10cSrcweir rTempPoints.push_back(temporaryPoint(rTempPoint.getPoint(), nInd, fRelativeCutPos)); 216*cdf0e10cSrcweir } 217*cdf0e10cSrcweir } 218*cdf0e10cSrcweir } 219*cdf0e10cSrcweir 220*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////// 221*cdf0e10cSrcweir 222*cdf0e10cSrcweir } // end of anonymous namespace 223*cdf0e10cSrcweir } // end of namespace basegfx 224*cdf0e10cSrcweir 225*cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 226*cdf0e10cSrcweir 227*cdf0e10cSrcweir namespace basegfx 228*cdf0e10cSrcweir { 229*cdf0e10cSrcweir namespace 230*cdf0e10cSrcweir { 231*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////// 232*cdf0e10cSrcweir // predefines for calls to this methods before method implementation 233*cdf0e10cSrcweir 234*cdf0e10cSrcweir void findCuts(const B2DPolygon& rCandidate, temporaryPointVector& rTempPoints); 235*cdf0e10cSrcweir void findTouches(const B2DPolygon& rEdgePolygon, const B2DPolygon& rPointPolygon, temporaryPointVector& rTempPoints); 236*cdf0e10cSrcweir void findCuts(const B2DPolygon& rCandidateA, const B2DPolygon& rCandidateB, temporaryPointVector& rTempPointsA, temporaryPointVector& rTempPointsB); 237*cdf0e10cSrcweir 238*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////// 239*cdf0e10cSrcweir 240*cdf0e10cSrcweir void findEdgeCutsTwoEdges( 241*cdf0e10cSrcweir const B2DPoint& rCurrA, const B2DPoint& rNextA, 242*cdf0e10cSrcweir const B2DPoint& rCurrB, const B2DPoint& rNextB, 243*cdf0e10cSrcweir sal_uInt32 nIndA, sal_uInt32 nIndB, 244*cdf0e10cSrcweir temporaryPointVector& rTempPointsA, temporaryPointVector& rTempPointsB) 245*cdf0e10cSrcweir { 246*cdf0e10cSrcweir // no null length edges 247*cdf0e10cSrcweir if(!(rCurrA.equal(rNextA) || rCurrB.equal(rNextB))) 248*cdf0e10cSrcweir { 249*cdf0e10cSrcweir // no common start/end points, this can be no cuts 250*cdf0e10cSrcweir if(!(rCurrB.equal(rCurrA) || rCurrB.equal(rNextA) || rNextB.equal(rCurrA) || rNextB.equal(rNextA))) 251*cdf0e10cSrcweir { 252*cdf0e10cSrcweir const B2DVector aVecA(rNextA - rCurrA); 253*cdf0e10cSrcweir const B2DVector aVecB(rNextB - rCurrB); 254*cdf0e10cSrcweir double fCut(aVecA.cross(aVecB)); 255*cdf0e10cSrcweir 256*cdf0e10cSrcweir if(!fTools::equalZero(fCut)) 257*cdf0e10cSrcweir { 258*cdf0e10cSrcweir const double fZero(0.0); 259*cdf0e10cSrcweir const double fOne(1.0); 260*cdf0e10cSrcweir fCut = (aVecB.getY() * (rCurrB.getX() - rCurrA.getX()) + aVecB.getX() * (rCurrA.getY() - rCurrB.getY())) / fCut; 261*cdf0e10cSrcweir 262*cdf0e10cSrcweir if(fTools::more(fCut, fZero) && fTools::less(fCut, fOne)) 263*cdf0e10cSrcweir { 264*cdf0e10cSrcweir // it's a candidate, but also need to test parameter value of cut on line 2 265*cdf0e10cSrcweir double fCut2; 266*cdf0e10cSrcweir 267*cdf0e10cSrcweir // choose the more precise version 268*cdf0e10cSrcweir if(fabs(aVecB.getX()) > fabs(aVecB.getY())) 269*cdf0e10cSrcweir { 270*cdf0e10cSrcweir fCut2 = (rCurrA.getX() + (fCut * aVecA.getX()) - rCurrB.getX()) / aVecB.getX(); 271*cdf0e10cSrcweir } 272*cdf0e10cSrcweir else 273*cdf0e10cSrcweir { 274*cdf0e10cSrcweir fCut2 = (rCurrA.getY() + (fCut * aVecA.getY()) - rCurrB.getY()) / aVecB.getY(); 275*cdf0e10cSrcweir } 276*cdf0e10cSrcweir 277*cdf0e10cSrcweir if(fTools::more(fCut2, fZero) && fTools::less(fCut2, fOne)) 278*cdf0e10cSrcweir { 279*cdf0e10cSrcweir // cut is in range, add point. Two edges can have only one cut, but 280*cdf0e10cSrcweir // add a cut point to each list. The lists may be the same for 281*cdf0e10cSrcweir // self intersections. 282*cdf0e10cSrcweir const B2DPoint aCutPoint(interpolate(rCurrA, rNextA, fCut)); 283*cdf0e10cSrcweir rTempPointsA.push_back(temporaryPoint(aCutPoint, nIndA, fCut)); 284*cdf0e10cSrcweir rTempPointsB.push_back(temporaryPoint(aCutPoint, nIndB, fCut2)); 285*cdf0e10cSrcweir } 286*cdf0e10cSrcweir } 287*cdf0e10cSrcweir } 288*cdf0e10cSrcweir } 289*cdf0e10cSrcweir } 290*cdf0e10cSrcweir } 291*cdf0e10cSrcweir 292*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////// 293*cdf0e10cSrcweir 294*cdf0e10cSrcweir void findCutsAndTouchesAndCommonForBezier(const B2DPolygon& rCandidateA, const B2DPolygon& rCandidateB, temporaryPointVector& rTempPointsA, temporaryPointVector& rTempPointsB) 295*cdf0e10cSrcweir { 296*cdf0e10cSrcweir // #i76891# 297*cdf0e10cSrcweir // This new method is necessary since in findEdgeCutsBezierAndEdge and in findEdgeCutsTwoBeziers 298*cdf0e10cSrcweir // it is not sufficient to use findCuts() recursively. This will indeed find the cuts between the 299*cdf0e10cSrcweir // segments of the two temporarily adaptive subdivided bezier segments, but not the touches or 300*cdf0e10cSrcweir // equal points of them. 301*cdf0e10cSrcweir // It would be possible to find the toches using findTouches(), but at last with commpn points 302*cdf0e10cSrcweir // the adding of cut points (temporary points) would fail. But for these temporarily adaptive 303*cdf0e10cSrcweir // subdivided bezier segments, common points may be not very likely, but the bug shows that it 304*cdf0e10cSrcweir // happens. 305*cdf0e10cSrcweir // Touch points are a little bit more likely than common points. All in all it is best to use 306*cdf0e10cSrcweir // a specialized method here which can profit from knowing that it is working on a special 307*cdf0e10cSrcweir // family of B2DPolygons: no curve segments included and not closed. 308*cdf0e10cSrcweir OSL_ENSURE(!rCandidateA.areControlPointsUsed() && !rCandidateB.areControlPointsUsed(), "findCutsAndTouchesAndCommonForBezier only works with subdivided polygons (!)"); 309*cdf0e10cSrcweir OSL_ENSURE(!rCandidateA.isClosed() && !rCandidateB.isClosed(), "findCutsAndTouchesAndCommonForBezier only works with opened polygons (!)"); 310*cdf0e10cSrcweir const sal_uInt32 nPointCountA(rCandidateA.count()); 311*cdf0e10cSrcweir const sal_uInt32 nPointCountB(rCandidateB.count()); 312*cdf0e10cSrcweir 313*cdf0e10cSrcweir if(nPointCountA > 1 && nPointCountB > 1) 314*cdf0e10cSrcweir { 315*cdf0e10cSrcweir const sal_uInt32 nEdgeCountA(nPointCountA - 1); 316*cdf0e10cSrcweir const sal_uInt32 nEdgeCountB(nPointCountB - 1); 317*cdf0e10cSrcweir B2DPoint aCurrA(rCandidateA.getB2DPoint(0L)); 318*cdf0e10cSrcweir 319*cdf0e10cSrcweir for(sal_uInt32 a(0L); a < nEdgeCountA; a++) 320*cdf0e10cSrcweir { 321*cdf0e10cSrcweir const B2DPoint aNextA(rCandidateA.getB2DPoint(a + 1L)); 322*cdf0e10cSrcweir const B2DRange aRangeA(aCurrA, aNextA); 323*cdf0e10cSrcweir B2DPoint aCurrB(rCandidateB.getB2DPoint(0L)); 324*cdf0e10cSrcweir 325*cdf0e10cSrcweir for(sal_uInt32 b(0L); b < nEdgeCountB; b++) 326*cdf0e10cSrcweir { 327*cdf0e10cSrcweir const B2DPoint aNextB(rCandidateB.getB2DPoint(b + 1L)); 328*cdf0e10cSrcweir const B2DRange aRangeB(aCurrB, aNextB); 329*cdf0e10cSrcweir 330*cdf0e10cSrcweir if(aRangeA.overlaps(aRangeB)) 331*cdf0e10cSrcweir { 332*cdf0e10cSrcweir // no null length edges 333*cdf0e10cSrcweir if(!(aCurrA.equal(aNextA) || aCurrB.equal(aNextB))) 334*cdf0e10cSrcweir { 335*cdf0e10cSrcweir const B2DVector aVecA(aNextA - aCurrA); 336*cdf0e10cSrcweir const B2DVector aVecB(aNextB - aCurrB); 337*cdf0e10cSrcweir double fCutA(aVecA.cross(aVecB)); 338*cdf0e10cSrcweir 339*cdf0e10cSrcweir if(!fTools::equalZero(fCutA)) 340*cdf0e10cSrcweir { 341*cdf0e10cSrcweir const double fZero(0.0); 342*cdf0e10cSrcweir const double fOne(1.0); 343*cdf0e10cSrcweir fCutA = (aVecB.getY() * (aCurrB.getX() - aCurrA.getX()) + aVecB.getX() * (aCurrA.getY() - aCurrB.getY())) / fCutA; 344*cdf0e10cSrcweir 345*cdf0e10cSrcweir // use range [0.0 .. 1.0[, thus in the loop, all direct aCurrA cuts will be registered 346*cdf0e10cSrcweir // as 0.0 cut. The 1.0 cut will be registered in the next loop step 347*cdf0e10cSrcweir if(fTools::moreOrEqual(fCutA, fZero) && fTools::less(fCutA, fOne)) 348*cdf0e10cSrcweir { 349*cdf0e10cSrcweir // it's a candidate, but also need to test parameter value of cut on line 2 350*cdf0e10cSrcweir double fCutB; 351*cdf0e10cSrcweir 352*cdf0e10cSrcweir // choose the more precise version 353*cdf0e10cSrcweir if(fabs(aVecB.getX()) > fabs(aVecB.getY())) 354*cdf0e10cSrcweir { 355*cdf0e10cSrcweir fCutB = (aCurrA.getX() + (fCutA * aVecA.getX()) - aCurrB.getX()) / aVecB.getX(); 356*cdf0e10cSrcweir } 357*cdf0e10cSrcweir else 358*cdf0e10cSrcweir { 359*cdf0e10cSrcweir fCutB = (aCurrA.getY() + (fCutA * aVecA.getY()) - aCurrB.getY()) / aVecB.getY(); 360*cdf0e10cSrcweir } 361*cdf0e10cSrcweir 362*cdf0e10cSrcweir // use range [0.0 .. 1.0[, thus in the loop, all direct aCurrA cuts will be registered 363*cdf0e10cSrcweir // as 0.0 cut. The 1.0 cut will be registered in the next loop step 364*cdf0e10cSrcweir if(fTools::moreOrEqual(fCutB, fZero) && fTools::less(fCutB, fOne)) 365*cdf0e10cSrcweir { 366*cdf0e10cSrcweir // cut is in both ranges. Add points for A and B 367*cdf0e10cSrcweir // #i111715# use fTools::equal instead of fTools::equalZero for better accuracy 368*cdf0e10cSrcweir if(fTools::equal(fCutA, fZero)) 369*cdf0e10cSrcweir { 370*cdf0e10cSrcweir // ignore for start point in first edge; this is handled 371*cdf0e10cSrcweir // by outer methods and would just produce a double point 372*cdf0e10cSrcweir if(a) 373*cdf0e10cSrcweir { 374*cdf0e10cSrcweir rTempPointsA.push_back(temporaryPoint(aCurrA, a, 0.0)); 375*cdf0e10cSrcweir } 376*cdf0e10cSrcweir } 377*cdf0e10cSrcweir else 378*cdf0e10cSrcweir { 379*cdf0e10cSrcweir const B2DPoint aCutPoint(interpolate(aCurrA, aNextA, fCutA)); 380*cdf0e10cSrcweir rTempPointsA.push_back(temporaryPoint(aCutPoint, a, fCutA)); 381*cdf0e10cSrcweir } 382*cdf0e10cSrcweir 383*cdf0e10cSrcweir // #i111715# use fTools::equal instead of fTools::equalZero for better accuracy 384*cdf0e10cSrcweir if(fTools::equal(fCutB, fZero)) 385*cdf0e10cSrcweir { 386*cdf0e10cSrcweir // ignore for start point in first edge; this is handled 387*cdf0e10cSrcweir // by outer methods and would just produce a double point 388*cdf0e10cSrcweir if(b) 389*cdf0e10cSrcweir { 390*cdf0e10cSrcweir rTempPointsB.push_back(temporaryPoint(aCurrB, b, 0.0)); 391*cdf0e10cSrcweir } 392*cdf0e10cSrcweir } 393*cdf0e10cSrcweir else 394*cdf0e10cSrcweir { 395*cdf0e10cSrcweir const B2DPoint aCutPoint(interpolate(aCurrB, aNextB, fCutB)); 396*cdf0e10cSrcweir rTempPointsB.push_back(temporaryPoint(aCutPoint, b, fCutB)); 397*cdf0e10cSrcweir } 398*cdf0e10cSrcweir } 399*cdf0e10cSrcweir } 400*cdf0e10cSrcweir } 401*cdf0e10cSrcweir } 402*cdf0e10cSrcweir } 403*cdf0e10cSrcweir 404*cdf0e10cSrcweir // prepare next step 405*cdf0e10cSrcweir aCurrB = aNextB; 406*cdf0e10cSrcweir } 407*cdf0e10cSrcweir 408*cdf0e10cSrcweir // prepare next step 409*cdf0e10cSrcweir aCurrA = aNextA; 410*cdf0e10cSrcweir } 411*cdf0e10cSrcweir } 412*cdf0e10cSrcweir } 413*cdf0e10cSrcweir 414*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////// 415*cdf0e10cSrcweir 416*cdf0e10cSrcweir void findEdgeCutsBezierAndEdge( 417*cdf0e10cSrcweir const B2DCubicBezier& rCubicA, 418*cdf0e10cSrcweir const B2DPoint& rCurrB, const B2DPoint& rNextB, 419*cdf0e10cSrcweir sal_uInt32 nIndA, sal_uInt32 nIndB, 420*cdf0e10cSrcweir temporaryPointVector& rTempPointsA, temporaryPointVector& rTempPointsB) 421*cdf0e10cSrcweir { 422*cdf0e10cSrcweir // find all cuts between given bezier segment and edge. Add an entry to the tempPoints 423*cdf0e10cSrcweir // for each common point with the cut value describing the relative position on given 424*cdf0e10cSrcweir // bezier segment and edge. 425*cdf0e10cSrcweir B2DPolygon aTempPolygonA; 426*cdf0e10cSrcweir B2DPolygon aTempPolygonEdge; 427*cdf0e10cSrcweir temporaryPointVector aTempPointVectorA; 428*cdf0e10cSrcweir temporaryPointVector aTempPointVectorEdge; 429*cdf0e10cSrcweir 430*cdf0e10cSrcweir // create subdivided polygons and find cuts between them 431*cdf0e10cSrcweir // Keep adaptiveSubdivideByCount due to needed quality 432*cdf0e10cSrcweir aTempPolygonA.reserve(SUBDIVIDE_FOR_CUT_TEST_COUNT + 8); 433*cdf0e10cSrcweir aTempPolygonA.append(rCubicA.getStartPoint()); 434*cdf0e10cSrcweir rCubicA.adaptiveSubdivideByCount(aTempPolygonA, SUBDIVIDE_FOR_CUT_TEST_COUNT); 435*cdf0e10cSrcweir aTempPolygonEdge.append(rCurrB); 436*cdf0e10cSrcweir aTempPolygonEdge.append(rNextB); 437*cdf0e10cSrcweir 438*cdf0e10cSrcweir // #i76891# using findCuts recursively is not sufficient here 439*cdf0e10cSrcweir findCutsAndTouchesAndCommonForBezier(aTempPolygonA, aTempPolygonEdge, aTempPointVectorA, aTempPointVectorEdge); 440*cdf0e10cSrcweir 441*cdf0e10cSrcweir if(aTempPointVectorA.size()) 442*cdf0e10cSrcweir { 443*cdf0e10cSrcweir // adapt tempVector entries to segment 444*cdf0e10cSrcweir adaptAndTransferCutsWithBezierSegment(aTempPointVectorA, aTempPolygonA, nIndA, rTempPointsA); 445*cdf0e10cSrcweir } 446*cdf0e10cSrcweir 447*cdf0e10cSrcweir // append remapped tempVector entries for edge to tempPoints for edge 448*cdf0e10cSrcweir for(sal_uInt32 a(0L); a < aTempPointVectorEdge.size(); a++) 449*cdf0e10cSrcweir { 450*cdf0e10cSrcweir const temporaryPoint& rTempPoint = aTempPointVectorEdge[a]; 451*cdf0e10cSrcweir rTempPointsB.push_back(temporaryPoint(rTempPoint.getPoint(), nIndB, rTempPoint.getCut())); 452*cdf0e10cSrcweir } 453*cdf0e10cSrcweir } 454*cdf0e10cSrcweir 455*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////// 456*cdf0e10cSrcweir 457*cdf0e10cSrcweir void findEdgeCutsTwoBeziers( 458*cdf0e10cSrcweir const B2DCubicBezier& rCubicA, 459*cdf0e10cSrcweir const B2DCubicBezier& rCubicB, 460*cdf0e10cSrcweir sal_uInt32 nIndA, sal_uInt32 nIndB, 461*cdf0e10cSrcweir temporaryPointVector& rTempPointsA, temporaryPointVector& rTempPointsB) 462*cdf0e10cSrcweir { 463*cdf0e10cSrcweir // find all cuts between the two given bezier segments. Add an entry to the tempPoints 464*cdf0e10cSrcweir // for each common point with the cut value describing the relative position on given 465*cdf0e10cSrcweir // bezier segments. 466*cdf0e10cSrcweir B2DPolygon aTempPolygonA; 467*cdf0e10cSrcweir B2DPolygon aTempPolygonB; 468*cdf0e10cSrcweir temporaryPointVector aTempPointVectorA; 469*cdf0e10cSrcweir temporaryPointVector aTempPointVectorB; 470*cdf0e10cSrcweir 471*cdf0e10cSrcweir // create subdivided polygons and find cuts between them 472*cdf0e10cSrcweir // Keep adaptiveSubdivideByCount due to needed quality 473*cdf0e10cSrcweir aTempPolygonA.reserve(SUBDIVIDE_FOR_CUT_TEST_COUNT + 8); 474*cdf0e10cSrcweir aTempPolygonA.append(rCubicA.getStartPoint()); 475*cdf0e10cSrcweir rCubicA.adaptiveSubdivideByCount(aTempPolygonA, SUBDIVIDE_FOR_CUT_TEST_COUNT); 476*cdf0e10cSrcweir aTempPolygonB.reserve(SUBDIVIDE_FOR_CUT_TEST_COUNT + 8); 477*cdf0e10cSrcweir aTempPolygonB.append(rCubicB.getStartPoint()); 478*cdf0e10cSrcweir rCubicB.adaptiveSubdivideByCount(aTempPolygonB, SUBDIVIDE_FOR_CUT_TEST_COUNT); 479*cdf0e10cSrcweir 480*cdf0e10cSrcweir // #i76891# using findCuts recursively is not sufficient here 481*cdf0e10cSrcweir findCutsAndTouchesAndCommonForBezier(aTempPolygonA, aTempPolygonB, aTempPointVectorA, aTempPointVectorB); 482*cdf0e10cSrcweir 483*cdf0e10cSrcweir if(aTempPointVectorA.size()) 484*cdf0e10cSrcweir { 485*cdf0e10cSrcweir // adapt tempVector entries to segment 486*cdf0e10cSrcweir adaptAndTransferCutsWithBezierSegment(aTempPointVectorA, aTempPolygonA, nIndA, rTempPointsA); 487*cdf0e10cSrcweir } 488*cdf0e10cSrcweir 489*cdf0e10cSrcweir if(aTempPointVectorB.size()) 490*cdf0e10cSrcweir { 491*cdf0e10cSrcweir // adapt tempVector entries to segment 492*cdf0e10cSrcweir adaptAndTransferCutsWithBezierSegment(aTempPointVectorB, aTempPolygonB, nIndB, rTempPointsB); 493*cdf0e10cSrcweir } 494*cdf0e10cSrcweir } 495*cdf0e10cSrcweir 496*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////// 497*cdf0e10cSrcweir 498*cdf0e10cSrcweir void findEdgeCutsOneBezier( 499*cdf0e10cSrcweir const B2DCubicBezier& rCubicA, 500*cdf0e10cSrcweir sal_uInt32 nInd, temporaryPointVector& rTempPoints) 501*cdf0e10cSrcweir { 502*cdf0e10cSrcweir // avoid expensive part of this method if possible 503*cdf0e10cSrcweir // TODO: use hasAnyExtremum() method instead when it becomes available 504*cdf0e10cSrcweir double fDummy; 505*cdf0e10cSrcweir const bool bHasAnyExtremum = rCubicA.getMinimumExtremumPosition( fDummy ); 506*cdf0e10cSrcweir if( !bHasAnyExtremum ) 507*cdf0e10cSrcweir return; 508*cdf0e10cSrcweir 509*cdf0e10cSrcweir // find all self-intersections on the given bezier segment. Add an entry to the tempPoints 510*cdf0e10cSrcweir // for each self intersection point with the cut value describing the relative position on given 511*cdf0e10cSrcweir // bezier segment. 512*cdf0e10cSrcweir B2DPolygon aTempPolygon; 513*cdf0e10cSrcweir temporaryPointVector aTempPointVector; 514*cdf0e10cSrcweir 515*cdf0e10cSrcweir // create subdivided polygon and find cuts on it 516*cdf0e10cSrcweir // Keep adaptiveSubdivideByCount due to needed quality 517*cdf0e10cSrcweir aTempPolygon.reserve(SUBDIVIDE_FOR_CUT_TEST_COUNT + 8); 518*cdf0e10cSrcweir aTempPolygon.append(rCubicA.getStartPoint()); 519*cdf0e10cSrcweir rCubicA.adaptiveSubdivideByCount(aTempPolygon, SUBDIVIDE_FOR_CUT_TEST_COUNT); 520*cdf0e10cSrcweir findCuts(aTempPolygon, aTempPointVector); 521*cdf0e10cSrcweir 522*cdf0e10cSrcweir if(aTempPointVector.size()) 523*cdf0e10cSrcweir { 524*cdf0e10cSrcweir // adapt tempVector entries to segment 525*cdf0e10cSrcweir adaptAndTransferCutsWithBezierSegment(aTempPointVector, aTempPolygon, nInd, rTempPoints); 526*cdf0e10cSrcweir } 527*cdf0e10cSrcweir } 528*cdf0e10cSrcweir 529*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////// 530*cdf0e10cSrcweir 531*cdf0e10cSrcweir void findCuts(const B2DPolygon& rCandidate, temporaryPointVector& rTempPoints) 532*cdf0e10cSrcweir { 533*cdf0e10cSrcweir // find out if there are edges with intersections (self-cuts). If yes, add 534*cdf0e10cSrcweir // entries to rTempPoints accordingly 535*cdf0e10cSrcweir const sal_uInt32 nPointCount(rCandidate.count()); 536*cdf0e10cSrcweir 537*cdf0e10cSrcweir if(nPointCount) 538*cdf0e10cSrcweir { 539*cdf0e10cSrcweir const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1L); 540*cdf0e10cSrcweir 541*cdf0e10cSrcweir if(nEdgeCount) 542*cdf0e10cSrcweir { 543*cdf0e10cSrcweir const bool bCurvesInvolved(rCandidate.areControlPointsUsed()); 544*cdf0e10cSrcweir 545*cdf0e10cSrcweir if(bCurvesInvolved) 546*cdf0e10cSrcweir { 547*cdf0e10cSrcweir B2DCubicBezier aCubicA; 548*cdf0e10cSrcweir B2DCubicBezier aCubicB; 549*cdf0e10cSrcweir 550*cdf0e10cSrcweir for(sal_uInt32 a(0L); a < nEdgeCount - 1L; a++) 551*cdf0e10cSrcweir { 552*cdf0e10cSrcweir rCandidate.getBezierSegment(a, aCubicA); 553*cdf0e10cSrcweir aCubicA.testAndSolveTrivialBezier(); 554*cdf0e10cSrcweir const bool bEdgeAIsCurve(aCubicA.isBezier()); 555*cdf0e10cSrcweir const B2DRange aRangeA(aCubicA.getRange()); 556*cdf0e10cSrcweir 557*cdf0e10cSrcweir if(bEdgeAIsCurve) 558*cdf0e10cSrcweir { 559*cdf0e10cSrcweir // curved segments may have self-intersections, do not forget those (!) 560*cdf0e10cSrcweir findEdgeCutsOneBezier(aCubicA, a, rTempPoints); 561*cdf0e10cSrcweir } 562*cdf0e10cSrcweir 563*cdf0e10cSrcweir for(sal_uInt32 b(a + 1L); b < nEdgeCount; b++) 564*cdf0e10cSrcweir { 565*cdf0e10cSrcweir rCandidate.getBezierSegment(b, aCubicB); 566*cdf0e10cSrcweir aCubicB.testAndSolveTrivialBezier(); 567*cdf0e10cSrcweir const bool bEdgeBIsCurve(aCubicB.isBezier()); 568*cdf0e10cSrcweir const B2DRange aRangeB(aCubicB.getRange()); 569*cdf0e10cSrcweir 570*cdf0e10cSrcweir // only overlapping segments need to be tested 571*cdf0e10cSrcweir // consecutive segments touch of course 572*cdf0e10cSrcweir bool bOverlap = false; 573*cdf0e10cSrcweir if( b > a+1) 574*cdf0e10cSrcweir bOverlap = aRangeA.overlaps(aRangeB); 575*cdf0e10cSrcweir else 576*cdf0e10cSrcweir bOverlap = aRangeA.overlapsMore(aRangeB); 577*cdf0e10cSrcweir if( bOverlap) 578*cdf0e10cSrcweir { 579*cdf0e10cSrcweir if(bEdgeAIsCurve && bEdgeBIsCurve) 580*cdf0e10cSrcweir { 581*cdf0e10cSrcweir // test for bezier-bezier cuts 582*cdf0e10cSrcweir findEdgeCutsTwoBeziers(aCubicA, aCubicB, a, b, rTempPoints, rTempPoints); 583*cdf0e10cSrcweir } 584*cdf0e10cSrcweir else if(bEdgeAIsCurve) 585*cdf0e10cSrcweir { 586*cdf0e10cSrcweir // test for bezier-edge cuts 587*cdf0e10cSrcweir findEdgeCutsBezierAndEdge(aCubicA, aCubicB.getStartPoint(), aCubicB.getEndPoint(), a, b, rTempPoints, rTempPoints); 588*cdf0e10cSrcweir } 589*cdf0e10cSrcweir else if(bEdgeBIsCurve) 590*cdf0e10cSrcweir { 591*cdf0e10cSrcweir // test for bezier-edge cuts 592*cdf0e10cSrcweir findEdgeCutsBezierAndEdge(aCubicB, aCubicA.getStartPoint(), aCubicA.getEndPoint(), b, a, rTempPoints, rTempPoints); 593*cdf0e10cSrcweir } 594*cdf0e10cSrcweir else 595*cdf0e10cSrcweir { 596*cdf0e10cSrcweir // test for simple edge-edge cuts 597*cdf0e10cSrcweir findEdgeCutsTwoEdges(aCubicA.getStartPoint(), aCubicA.getEndPoint(), aCubicB.getStartPoint(), aCubicB.getEndPoint(), 598*cdf0e10cSrcweir a, b, rTempPoints, rTempPoints); 599*cdf0e10cSrcweir } 600*cdf0e10cSrcweir } 601*cdf0e10cSrcweir } 602*cdf0e10cSrcweir } 603*cdf0e10cSrcweir } 604*cdf0e10cSrcweir else 605*cdf0e10cSrcweir { 606*cdf0e10cSrcweir B2DPoint aCurrA(rCandidate.getB2DPoint(0L)); 607*cdf0e10cSrcweir 608*cdf0e10cSrcweir for(sal_uInt32 a(0L); a < nEdgeCount - 1L; a++) 609*cdf0e10cSrcweir { 610*cdf0e10cSrcweir const B2DPoint aNextA(rCandidate.getB2DPoint(a + 1L == nPointCount ? 0L : a + 1L)); 611*cdf0e10cSrcweir const B2DRange aRangeA(aCurrA, aNextA); 612*cdf0e10cSrcweir B2DPoint aCurrB(rCandidate.getB2DPoint(a + 1L)); 613*cdf0e10cSrcweir 614*cdf0e10cSrcweir for(sal_uInt32 b(a + 1L); b < nEdgeCount; b++) 615*cdf0e10cSrcweir { 616*cdf0e10cSrcweir const B2DPoint aNextB(rCandidate.getB2DPoint(b + 1L == nPointCount ? 0L : b + 1L)); 617*cdf0e10cSrcweir const B2DRange aRangeB(aCurrB, aNextB); 618*cdf0e10cSrcweir 619*cdf0e10cSrcweir // consecutive segments touch of course 620*cdf0e10cSrcweir bool bOverlap = false; 621*cdf0e10cSrcweir if( b > a+1) 622*cdf0e10cSrcweir bOverlap = aRangeA.overlaps(aRangeB); 623*cdf0e10cSrcweir else 624*cdf0e10cSrcweir bOverlap = aRangeA.overlapsMore(aRangeB); 625*cdf0e10cSrcweir if( bOverlap) 626*cdf0e10cSrcweir { 627*cdf0e10cSrcweir findEdgeCutsTwoEdges(aCurrA, aNextA, aCurrB, aNextB, a, b, rTempPoints, rTempPoints); 628*cdf0e10cSrcweir } 629*cdf0e10cSrcweir 630*cdf0e10cSrcweir // prepare next step 631*cdf0e10cSrcweir aCurrB = aNextB; 632*cdf0e10cSrcweir } 633*cdf0e10cSrcweir 634*cdf0e10cSrcweir // prepare next step 635*cdf0e10cSrcweir aCurrA = aNextA; 636*cdf0e10cSrcweir } 637*cdf0e10cSrcweir } 638*cdf0e10cSrcweir } 639*cdf0e10cSrcweir } 640*cdf0e10cSrcweir } 641*cdf0e10cSrcweir 642*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////// 643*cdf0e10cSrcweir 644*cdf0e10cSrcweir } // end of anonymous namespace 645*cdf0e10cSrcweir } // end of namespace basegfx 646*cdf0e10cSrcweir 647*cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 648*cdf0e10cSrcweir 649*cdf0e10cSrcweir namespace basegfx 650*cdf0e10cSrcweir { 651*cdf0e10cSrcweir namespace 652*cdf0e10cSrcweir { 653*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////// 654*cdf0e10cSrcweir 655*cdf0e10cSrcweir void findTouchesOnEdge( 656*cdf0e10cSrcweir const B2DPoint& rCurr, const B2DPoint& rNext, const B2DPolygon& rPointPolygon, 657*cdf0e10cSrcweir sal_uInt32 nInd, temporaryPointVector& rTempPoints) 658*cdf0e10cSrcweir { 659*cdf0e10cSrcweir // find out if points from rPointPolygon are positioned on given edge. If Yes, add 660*cdf0e10cSrcweir // points there to represent touches (which may be enter or leave nodes later). 661*cdf0e10cSrcweir const sal_uInt32 nPointCount(rPointPolygon.count()); 662*cdf0e10cSrcweir 663*cdf0e10cSrcweir if(nPointCount) 664*cdf0e10cSrcweir { 665*cdf0e10cSrcweir const B2DRange aRange(rCurr, rNext); 666*cdf0e10cSrcweir const B2DVector aEdgeVector(rNext - rCurr); 667*cdf0e10cSrcweir B2DVector aNormalizedEdgeVector(aEdgeVector); 668*cdf0e10cSrcweir aNormalizedEdgeVector.normalize(); 669*cdf0e10cSrcweir bool bTestUsingX(fabs(aEdgeVector.getX()) > fabs(aEdgeVector.getY())); 670*cdf0e10cSrcweir 671*cdf0e10cSrcweir for(sal_uInt32 a(0L); a < nPointCount; a++) 672*cdf0e10cSrcweir { 673*cdf0e10cSrcweir const B2DPoint aTestPoint(rPointPolygon.getB2DPoint(a)); 674*cdf0e10cSrcweir 675*cdf0e10cSrcweir if(aRange.isInside(aTestPoint)) 676*cdf0e10cSrcweir { 677*cdf0e10cSrcweir if(!aTestPoint.equal(rCurr) && !aTestPoint.equal(rNext)) 678*cdf0e10cSrcweir { 679*cdf0e10cSrcweir const B2DVector aTestVector(aTestPoint - rCurr); 680*cdf0e10cSrcweir 681*cdf0e10cSrcweir if(areParallel(aNormalizedEdgeVector, aTestVector)) 682*cdf0e10cSrcweir { 683*cdf0e10cSrcweir const double fCut((bTestUsingX) 684*cdf0e10cSrcweir ? aTestVector.getX() / aEdgeVector.getX() 685*cdf0e10cSrcweir : aTestVector.getY() / aEdgeVector.getY()); 686*cdf0e10cSrcweir const double fZero(0.0); 687*cdf0e10cSrcweir const double fOne(1.0); 688*cdf0e10cSrcweir 689*cdf0e10cSrcweir if(fTools::more(fCut, fZero) && fTools::less(fCut, fOne)) 690*cdf0e10cSrcweir { 691*cdf0e10cSrcweir rTempPoints.push_back(temporaryPoint(aTestPoint, nInd, fCut)); 692*cdf0e10cSrcweir } 693*cdf0e10cSrcweir } 694*cdf0e10cSrcweir } 695*cdf0e10cSrcweir } 696*cdf0e10cSrcweir } 697*cdf0e10cSrcweir } 698*cdf0e10cSrcweir } 699*cdf0e10cSrcweir 700*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////// 701*cdf0e10cSrcweir 702*cdf0e10cSrcweir void findTouchesOnCurve( 703*cdf0e10cSrcweir const B2DCubicBezier& rCubicA, const B2DPolygon& rPointPolygon, 704*cdf0e10cSrcweir sal_uInt32 nInd, temporaryPointVector& rTempPoints) 705*cdf0e10cSrcweir { 706*cdf0e10cSrcweir // find all points from rPointPolygon which touch the given bezier segment. Add an entry 707*cdf0e10cSrcweir // for each touch to the given pointVector. The cut for that entry is the relative position on 708*cdf0e10cSrcweir // the given bezier segment. 709*cdf0e10cSrcweir B2DPolygon aTempPolygon; 710*cdf0e10cSrcweir temporaryPointVector aTempPointVector; 711*cdf0e10cSrcweir 712*cdf0e10cSrcweir // create subdivided polygon and find cuts on it 713*cdf0e10cSrcweir // Keep adaptiveSubdivideByCount due to needed quality 714*cdf0e10cSrcweir aTempPolygon.reserve(SUBDIVIDE_FOR_CUT_TEST_COUNT + 8); 715*cdf0e10cSrcweir aTempPolygon.append(rCubicA.getStartPoint()); 716*cdf0e10cSrcweir rCubicA.adaptiveSubdivideByCount(aTempPolygon, SUBDIVIDE_FOR_CUT_TEST_COUNT); 717*cdf0e10cSrcweir findTouches(aTempPolygon, rPointPolygon, aTempPointVector); 718*cdf0e10cSrcweir 719*cdf0e10cSrcweir if(aTempPointVector.size()) 720*cdf0e10cSrcweir { 721*cdf0e10cSrcweir // adapt tempVector entries to segment 722*cdf0e10cSrcweir adaptAndTransferCutsWithBezierSegment(aTempPointVector, aTempPolygon, nInd, rTempPoints); 723*cdf0e10cSrcweir } 724*cdf0e10cSrcweir } 725*cdf0e10cSrcweir 726*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////// 727*cdf0e10cSrcweir 728*cdf0e10cSrcweir void findTouches(const B2DPolygon& rEdgePolygon, const B2DPolygon& rPointPolygon, temporaryPointVector& rTempPoints) 729*cdf0e10cSrcweir { 730*cdf0e10cSrcweir // find out if points from rPointPolygon touch edges from rEdgePolygon. If yes, 731*cdf0e10cSrcweir // add entries to rTempPoints 732*cdf0e10cSrcweir const sal_uInt32 nPointCount(rPointPolygon.count()); 733*cdf0e10cSrcweir const sal_uInt32 nEdgePointCount(rEdgePolygon.count()); 734*cdf0e10cSrcweir 735*cdf0e10cSrcweir if(nPointCount && nEdgePointCount) 736*cdf0e10cSrcweir { 737*cdf0e10cSrcweir const sal_uInt32 nEdgeCount(rEdgePolygon.isClosed() ? nEdgePointCount : nEdgePointCount - 1L); 738*cdf0e10cSrcweir B2DPoint aCurr(rEdgePolygon.getB2DPoint(0)); 739*cdf0e10cSrcweir 740*cdf0e10cSrcweir for(sal_uInt32 a(0L); a < nEdgeCount; a++) 741*cdf0e10cSrcweir { 742*cdf0e10cSrcweir const sal_uInt32 nNextIndex((a + 1) % nEdgePointCount); 743*cdf0e10cSrcweir const B2DPoint aNext(rEdgePolygon.getB2DPoint(nNextIndex)); 744*cdf0e10cSrcweir 745*cdf0e10cSrcweir if(!aCurr.equal(aNext)) 746*cdf0e10cSrcweir { 747*cdf0e10cSrcweir bool bHandleAsSimpleEdge(true); 748*cdf0e10cSrcweir 749*cdf0e10cSrcweir if(rEdgePolygon.areControlPointsUsed()) 750*cdf0e10cSrcweir { 751*cdf0e10cSrcweir const B2DPoint aNextControlPoint(rEdgePolygon.getNextControlPoint(a)); 752*cdf0e10cSrcweir const B2DPoint aPrevControlPoint(rEdgePolygon.getPrevControlPoint(nNextIndex)); 753*cdf0e10cSrcweir const bool bEdgeIsCurve(!aNextControlPoint.equal(aCurr) || !aPrevControlPoint.equal(aNext)); 754*cdf0e10cSrcweir 755*cdf0e10cSrcweir if(bEdgeIsCurve) 756*cdf0e10cSrcweir { 757*cdf0e10cSrcweir bHandleAsSimpleEdge = false; 758*cdf0e10cSrcweir const B2DCubicBezier aCubicA(aCurr, aNextControlPoint, aPrevControlPoint, aNext); 759*cdf0e10cSrcweir findTouchesOnCurve(aCubicA, rPointPolygon, a, rTempPoints); 760*cdf0e10cSrcweir } 761*cdf0e10cSrcweir } 762*cdf0e10cSrcweir 763*cdf0e10cSrcweir if(bHandleAsSimpleEdge) 764*cdf0e10cSrcweir { 765*cdf0e10cSrcweir findTouchesOnEdge(aCurr, aNext, rPointPolygon, a, rTempPoints); 766*cdf0e10cSrcweir } 767*cdf0e10cSrcweir } 768*cdf0e10cSrcweir 769*cdf0e10cSrcweir // next step 770*cdf0e10cSrcweir aCurr = aNext; 771*cdf0e10cSrcweir } 772*cdf0e10cSrcweir } 773*cdf0e10cSrcweir } 774*cdf0e10cSrcweir 775*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////// 776*cdf0e10cSrcweir 777*cdf0e10cSrcweir } // end of anonymous namespace 778*cdf0e10cSrcweir } // end of namespace basegfx 779*cdf0e10cSrcweir 780*cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 781*cdf0e10cSrcweir 782*cdf0e10cSrcweir namespace basegfx 783*cdf0e10cSrcweir { 784*cdf0e10cSrcweir namespace 785*cdf0e10cSrcweir { 786*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////// 787*cdf0e10cSrcweir 788*cdf0e10cSrcweir void findCuts(const B2DPolygon& rCandidateA, const B2DPolygon& rCandidateB, temporaryPointVector& rTempPointsA, temporaryPointVector& rTempPointsB) 789*cdf0e10cSrcweir { 790*cdf0e10cSrcweir // find out if edges from both polygons cut. If so, add entries to rTempPoints which 791*cdf0e10cSrcweir // should be added to the polygons accordingly 792*cdf0e10cSrcweir const sal_uInt32 nPointCountA(rCandidateA.count()); 793*cdf0e10cSrcweir const sal_uInt32 nPointCountB(rCandidateB.count()); 794*cdf0e10cSrcweir 795*cdf0e10cSrcweir if(nPointCountA && nPointCountB) 796*cdf0e10cSrcweir { 797*cdf0e10cSrcweir const sal_uInt32 nEdgeCountA(rCandidateA.isClosed() ? nPointCountA : nPointCountA - 1L); 798*cdf0e10cSrcweir const sal_uInt32 nEdgeCountB(rCandidateB.isClosed() ? nPointCountB : nPointCountB - 1L); 799*cdf0e10cSrcweir 800*cdf0e10cSrcweir if(nEdgeCountA && nEdgeCountB) 801*cdf0e10cSrcweir { 802*cdf0e10cSrcweir const bool bCurvesInvolved(rCandidateA.areControlPointsUsed() || rCandidateB.areControlPointsUsed()); 803*cdf0e10cSrcweir 804*cdf0e10cSrcweir if(bCurvesInvolved) 805*cdf0e10cSrcweir { 806*cdf0e10cSrcweir B2DCubicBezier aCubicA; 807*cdf0e10cSrcweir B2DCubicBezier aCubicB; 808*cdf0e10cSrcweir 809*cdf0e10cSrcweir for(sal_uInt32 a(0L); a < nEdgeCountA; a++) 810*cdf0e10cSrcweir { 811*cdf0e10cSrcweir rCandidateA.getBezierSegment(a, aCubicA); 812*cdf0e10cSrcweir aCubicA.testAndSolveTrivialBezier(); 813*cdf0e10cSrcweir const bool bEdgeAIsCurve(aCubicA.isBezier()); 814*cdf0e10cSrcweir const B2DRange aRangeA(aCubicA.getRange()); 815*cdf0e10cSrcweir 816*cdf0e10cSrcweir for(sal_uInt32 b(0L); b < nEdgeCountB; b++) 817*cdf0e10cSrcweir { 818*cdf0e10cSrcweir rCandidateB.getBezierSegment(b, aCubicB); 819*cdf0e10cSrcweir aCubicB.testAndSolveTrivialBezier(); 820*cdf0e10cSrcweir const bool bEdgeBIsCurve(aCubicB.isBezier()); 821*cdf0e10cSrcweir const B2DRange aRangeB(aCubicB.getRange()); 822*cdf0e10cSrcweir 823*cdf0e10cSrcweir // consecutive segments touch of course 824*cdf0e10cSrcweir bool bOverlap = false; 825*cdf0e10cSrcweir if( b > a+1) 826*cdf0e10cSrcweir bOverlap = aRangeA.overlaps(aRangeB); 827*cdf0e10cSrcweir else 828*cdf0e10cSrcweir bOverlap = aRangeA.overlapsMore(aRangeB); 829*cdf0e10cSrcweir if( bOverlap) 830*cdf0e10cSrcweir { 831*cdf0e10cSrcweir if(bEdgeAIsCurve && bEdgeBIsCurve) 832*cdf0e10cSrcweir { 833*cdf0e10cSrcweir // test for bezier-bezier cuts 834*cdf0e10cSrcweir findEdgeCutsTwoBeziers(aCubicA, aCubicB, a, b, rTempPointsA, rTempPointsB); 835*cdf0e10cSrcweir } 836*cdf0e10cSrcweir else if(bEdgeAIsCurve) 837*cdf0e10cSrcweir { 838*cdf0e10cSrcweir // test for bezier-edge cuts 839*cdf0e10cSrcweir findEdgeCutsBezierAndEdge(aCubicA, aCubicB.getStartPoint(), aCubicB.getEndPoint(), a, b, rTempPointsA, rTempPointsB); 840*cdf0e10cSrcweir } 841*cdf0e10cSrcweir else if(bEdgeBIsCurve) 842*cdf0e10cSrcweir { 843*cdf0e10cSrcweir // test for bezier-edge cuts 844*cdf0e10cSrcweir findEdgeCutsBezierAndEdge(aCubicB, aCubicA.getStartPoint(), aCubicA.getEndPoint(), b, a, rTempPointsB, rTempPointsA); 845*cdf0e10cSrcweir } 846*cdf0e10cSrcweir else 847*cdf0e10cSrcweir { 848*cdf0e10cSrcweir // test for simple edge-edge cuts 849*cdf0e10cSrcweir findEdgeCutsTwoEdges(aCubicA.getStartPoint(), aCubicA.getEndPoint(), aCubicB.getStartPoint(), aCubicB.getEndPoint(), 850*cdf0e10cSrcweir a, b, rTempPointsA, rTempPointsB); 851*cdf0e10cSrcweir } 852*cdf0e10cSrcweir } 853*cdf0e10cSrcweir } 854*cdf0e10cSrcweir } 855*cdf0e10cSrcweir } 856*cdf0e10cSrcweir else 857*cdf0e10cSrcweir { 858*cdf0e10cSrcweir B2DPoint aCurrA(rCandidateA.getB2DPoint(0L)); 859*cdf0e10cSrcweir 860*cdf0e10cSrcweir for(sal_uInt32 a(0L); a < nEdgeCountA; a++) 861*cdf0e10cSrcweir { 862*cdf0e10cSrcweir const B2DPoint aNextA(rCandidateA.getB2DPoint(a + 1L == nPointCountA ? 0L : a + 1L)); 863*cdf0e10cSrcweir const B2DRange aRangeA(aCurrA, aNextA); 864*cdf0e10cSrcweir B2DPoint aCurrB(rCandidateB.getB2DPoint(0L)); 865*cdf0e10cSrcweir 866*cdf0e10cSrcweir for(sal_uInt32 b(0L); b < nEdgeCountB; b++) 867*cdf0e10cSrcweir { 868*cdf0e10cSrcweir const B2DPoint aNextB(rCandidateB.getB2DPoint(b + 1L == nPointCountB ? 0L : b + 1L)); 869*cdf0e10cSrcweir const B2DRange aRangeB(aCurrB, aNextB); 870*cdf0e10cSrcweir 871*cdf0e10cSrcweir // consecutive segments touch of course 872*cdf0e10cSrcweir bool bOverlap = false; 873*cdf0e10cSrcweir if( b > a+1) 874*cdf0e10cSrcweir bOverlap = aRangeA.overlaps(aRangeB); 875*cdf0e10cSrcweir else 876*cdf0e10cSrcweir bOverlap = aRangeA.overlapsMore(aRangeB); 877*cdf0e10cSrcweir if( bOverlap) 878*cdf0e10cSrcweir { 879*cdf0e10cSrcweir // test for simple edge-edge cuts 880*cdf0e10cSrcweir findEdgeCutsTwoEdges(aCurrA, aNextA, aCurrB, aNextB, a, b, rTempPointsA, rTempPointsB); 881*cdf0e10cSrcweir } 882*cdf0e10cSrcweir 883*cdf0e10cSrcweir // prepare next step 884*cdf0e10cSrcweir aCurrB = aNextB; 885*cdf0e10cSrcweir } 886*cdf0e10cSrcweir 887*cdf0e10cSrcweir // prepare next step 888*cdf0e10cSrcweir aCurrA = aNextA; 889*cdf0e10cSrcweir } 890*cdf0e10cSrcweir } 891*cdf0e10cSrcweir } 892*cdf0e10cSrcweir } 893*cdf0e10cSrcweir } 894*cdf0e10cSrcweir 895*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////// 896*cdf0e10cSrcweir 897*cdf0e10cSrcweir } // end of anonymous namespace 898*cdf0e10cSrcweir } // end of namespace basegfx 899*cdf0e10cSrcweir 900*cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 901*cdf0e10cSrcweir 902*cdf0e10cSrcweir namespace basegfx 903*cdf0e10cSrcweir { 904*cdf0e10cSrcweir namespace tools 905*cdf0e10cSrcweir { 906*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////// 907*cdf0e10cSrcweir 908*cdf0e10cSrcweir B2DPolygon addPointsAtCutsAndTouches(const B2DPolygon& rCandidate) 909*cdf0e10cSrcweir { 910*cdf0e10cSrcweir if(rCandidate.count()) 911*cdf0e10cSrcweir { 912*cdf0e10cSrcweir temporaryPointVector aTempPoints; 913*cdf0e10cSrcweir 914*cdf0e10cSrcweir findTouches(rCandidate, rCandidate, aTempPoints); 915*cdf0e10cSrcweir findCuts(rCandidate, aTempPoints); 916*cdf0e10cSrcweir 917*cdf0e10cSrcweir return mergeTemporaryPointsAndPolygon(rCandidate, aTempPoints); 918*cdf0e10cSrcweir } 919*cdf0e10cSrcweir else 920*cdf0e10cSrcweir { 921*cdf0e10cSrcweir return rCandidate; 922*cdf0e10cSrcweir } 923*cdf0e10cSrcweir } 924*cdf0e10cSrcweir 925*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////// 926*cdf0e10cSrcweir 927*cdf0e10cSrcweir B2DPolyPolygon addPointsAtCutsAndTouches(const B2DPolyPolygon& rCandidate, bool bSelfIntersections) 928*cdf0e10cSrcweir { 929*cdf0e10cSrcweir const sal_uInt32 nCount(rCandidate.count()); 930*cdf0e10cSrcweir 931*cdf0e10cSrcweir if(nCount) 932*cdf0e10cSrcweir { 933*cdf0e10cSrcweir B2DPolyPolygon aRetval; 934*cdf0e10cSrcweir 935*cdf0e10cSrcweir if(1L == nCount) 936*cdf0e10cSrcweir { 937*cdf0e10cSrcweir if(bSelfIntersections) 938*cdf0e10cSrcweir { 939*cdf0e10cSrcweir // remove self intersections 940*cdf0e10cSrcweir aRetval.append(addPointsAtCutsAndTouches(rCandidate.getB2DPolygon(0L))); 941*cdf0e10cSrcweir } 942*cdf0e10cSrcweir else 943*cdf0e10cSrcweir { 944*cdf0e10cSrcweir // copy source 945*cdf0e10cSrcweir aRetval = rCandidate; 946*cdf0e10cSrcweir } 947*cdf0e10cSrcweir } 948*cdf0e10cSrcweir else 949*cdf0e10cSrcweir { 950*cdf0e10cSrcweir // first solve self cuts and self touches for all contained single polygons 951*cdf0e10cSrcweir temporaryPolygonData *pTempData = new temporaryPolygonData[nCount]; 952*cdf0e10cSrcweir sal_uInt32 a, b; 953*cdf0e10cSrcweir 954*cdf0e10cSrcweir for(a = 0L; a < nCount; a++) 955*cdf0e10cSrcweir { 956*cdf0e10cSrcweir if(bSelfIntersections) 957*cdf0e10cSrcweir { 958*cdf0e10cSrcweir // use polygons with solved self intersections 959*cdf0e10cSrcweir pTempData[a].setPolygon(addPointsAtCutsAndTouches(rCandidate.getB2DPolygon(a))); 960*cdf0e10cSrcweir } 961*cdf0e10cSrcweir else 962*cdf0e10cSrcweir { 963*cdf0e10cSrcweir // copy given polygons 964*cdf0e10cSrcweir pTempData[a].setPolygon(rCandidate.getB2DPolygon(a)); 965*cdf0e10cSrcweir } 966*cdf0e10cSrcweir } 967*cdf0e10cSrcweir 968*cdf0e10cSrcweir // now cuts and touches between the polygons 969*cdf0e10cSrcweir for(a = 0L; a < nCount; a++) 970*cdf0e10cSrcweir { 971*cdf0e10cSrcweir for(b = 0L; b < nCount; b++) 972*cdf0e10cSrcweir { 973*cdf0e10cSrcweir if(a != b) 974*cdf0e10cSrcweir { 975*cdf0e10cSrcweir // look for touches, compare each edge polygon to all other points 976*cdf0e10cSrcweir if(pTempData[a].getRange().overlaps(pTempData[b].getRange())) 977*cdf0e10cSrcweir { 978*cdf0e10cSrcweir findTouches(pTempData[a].getPolygon(), pTempData[b].getPolygon(), pTempData[a].getTemporaryPointVector()); 979*cdf0e10cSrcweir } 980*cdf0e10cSrcweir } 981*cdf0e10cSrcweir 982*cdf0e10cSrcweir if(a < b) 983*cdf0e10cSrcweir { 984*cdf0e10cSrcweir // look for cuts, compare each edge polygon to following ones 985*cdf0e10cSrcweir if(pTempData[a].getRange().overlaps(pTempData[b].getRange())) 986*cdf0e10cSrcweir { 987*cdf0e10cSrcweir findCuts(pTempData[a].getPolygon(), pTempData[b].getPolygon(), pTempData[a].getTemporaryPointVector(), pTempData[b].getTemporaryPointVector()); 988*cdf0e10cSrcweir } 989*cdf0e10cSrcweir } 990*cdf0e10cSrcweir } 991*cdf0e10cSrcweir } 992*cdf0e10cSrcweir 993*cdf0e10cSrcweir // consolidate the result 994*cdf0e10cSrcweir for(a = 0L; a < nCount; a++) 995*cdf0e10cSrcweir { 996*cdf0e10cSrcweir aRetval.append(mergeTemporaryPointsAndPolygon(pTempData[a].getPolygon(), pTempData[a].getTemporaryPointVector())); 997*cdf0e10cSrcweir } 998*cdf0e10cSrcweir 999*cdf0e10cSrcweir delete[] pTempData; 1000*cdf0e10cSrcweir } 1001*cdf0e10cSrcweir 1002*cdf0e10cSrcweir return aRetval; 1003*cdf0e10cSrcweir } 1004*cdf0e10cSrcweir else 1005*cdf0e10cSrcweir { 1006*cdf0e10cSrcweir return rCandidate; 1007*cdf0e10cSrcweir } 1008*cdf0e10cSrcweir } 1009*cdf0e10cSrcweir 1010*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////// 1011*cdf0e10cSrcweir 1012*cdf0e10cSrcweir B2DPolygon addPointsAtCutsAndTouches(const B2DPolyPolygon& rMask, const B2DPolygon& rCandidate) 1013*cdf0e10cSrcweir { 1014*cdf0e10cSrcweir if(rCandidate.count()) 1015*cdf0e10cSrcweir { 1016*cdf0e10cSrcweir temporaryPointVector aTempPoints; 1017*cdf0e10cSrcweir temporaryPointVector aTempPointsUnused; 1018*cdf0e10cSrcweir 1019*cdf0e10cSrcweir for(sal_uInt32 a(0L); a < rMask.count(); a++) 1020*cdf0e10cSrcweir { 1021*cdf0e10cSrcweir const B2DPolygon aPartMask(rMask.getB2DPolygon(a)); 1022*cdf0e10cSrcweir 1023*cdf0e10cSrcweir findTouches(rCandidate, aPartMask, aTempPoints); 1024*cdf0e10cSrcweir findCuts(rCandidate, aPartMask, aTempPoints, aTempPointsUnused); 1025*cdf0e10cSrcweir } 1026*cdf0e10cSrcweir 1027*cdf0e10cSrcweir return mergeTemporaryPointsAndPolygon(rCandidate, aTempPoints); 1028*cdf0e10cSrcweir } 1029*cdf0e10cSrcweir else 1030*cdf0e10cSrcweir { 1031*cdf0e10cSrcweir return rCandidate; 1032*cdf0e10cSrcweir } 1033*cdf0e10cSrcweir } 1034*cdf0e10cSrcweir 1035*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////// 1036*cdf0e10cSrcweir 1037*cdf0e10cSrcweir B2DPolyPolygon addPointsAtCutsAndTouches(const B2DPolyPolygon& rMask, const B2DPolyPolygon& rCandidate) 1038*cdf0e10cSrcweir { 1039*cdf0e10cSrcweir B2DPolyPolygon aRetval; 1040*cdf0e10cSrcweir 1041*cdf0e10cSrcweir for(sal_uInt32 a(0L); a < rCandidate.count(); a++) 1042*cdf0e10cSrcweir { 1043*cdf0e10cSrcweir aRetval.append(addPointsAtCutsAndTouches(rMask, rCandidate.getB2DPolygon(a))); 1044*cdf0e10cSrcweir } 1045*cdf0e10cSrcweir 1046*cdf0e10cSrcweir return aRetval; 1047*cdf0e10cSrcweir } 1048*cdf0e10cSrcweir 1049*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////// 1050*cdf0e10cSrcweir 1051*cdf0e10cSrcweir B2DPolygon addPointsAtCuts(const B2DPolygon& rCandidate, const B2DPoint& rStart, const B2DPoint& rEnd) 1052*cdf0e10cSrcweir { 1053*cdf0e10cSrcweir const sal_uInt32 nCount(rCandidate.count()); 1054*cdf0e10cSrcweir 1055*cdf0e10cSrcweir if(nCount && !rStart.equal(rEnd)) 1056*cdf0e10cSrcweir { 1057*cdf0e10cSrcweir const B2DRange aPolygonRange(rCandidate.getB2DRange()); 1058*cdf0e10cSrcweir const B2DRange aEdgeRange(rStart, rEnd); 1059*cdf0e10cSrcweir 1060*cdf0e10cSrcweir if(aPolygonRange.overlaps(aEdgeRange)) 1061*cdf0e10cSrcweir { 1062*cdf0e10cSrcweir const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nCount : nCount - 1); 1063*cdf0e10cSrcweir temporaryPointVector aTempPoints; 1064*cdf0e10cSrcweir temporaryPointVector aUnusedTempPoints; 1065*cdf0e10cSrcweir B2DCubicBezier aCubic; 1066*cdf0e10cSrcweir 1067*cdf0e10cSrcweir for(sal_uInt32 a(0); a < nEdgeCount; a++) 1068*cdf0e10cSrcweir { 1069*cdf0e10cSrcweir rCandidate.getBezierSegment(a, aCubic); 1070*cdf0e10cSrcweir B2DRange aCubicRange(aCubic.getStartPoint(), aCubic.getEndPoint()); 1071*cdf0e10cSrcweir 1072*cdf0e10cSrcweir if(aCubic.isBezier()) 1073*cdf0e10cSrcweir { 1074*cdf0e10cSrcweir aCubicRange.expand(aCubic.getControlPointA()); 1075*cdf0e10cSrcweir aCubicRange.expand(aCubic.getControlPointB()); 1076*cdf0e10cSrcweir 1077*cdf0e10cSrcweir if(aCubicRange.overlaps(aEdgeRange)) 1078*cdf0e10cSrcweir { 1079*cdf0e10cSrcweir findEdgeCutsBezierAndEdge(aCubic, rStart, rEnd, a, 0, aTempPoints, aUnusedTempPoints); 1080*cdf0e10cSrcweir } 1081*cdf0e10cSrcweir } 1082*cdf0e10cSrcweir else 1083*cdf0e10cSrcweir { 1084*cdf0e10cSrcweir if(aCubicRange.overlaps(aEdgeRange)) 1085*cdf0e10cSrcweir { 1086*cdf0e10cSrcweir findEdgeCutsTwoEdges(aCubic.getStartPoint(), aCubic.getEndPoint(), rStart, rEnd, a, 0, aTempPoints, aUnusedTempPoints); 1087*cdf0e10cSrcweir } 1088*cdf0e10cSrcweir } 1089*cdf0e10cSrcweir } 1090*cdf0e10cSrcweir 1091*cdf0e10cSrcweir return mergeTemporaryPointsAndPolygon(rCandidate, aTempPoints); 1092*cdf0e10cSrcweir } 1093*cdf0e10cSrcweir } 1094*cdf0e10cSrcweir 1095*cdf0e10cSrcweir return rCandidate; 1096*cdf0e10cSrcweir } 1097*cdf0e10cSrcweir 1098*cdf0e10cSrcweir B2DPolyPolygon addPointsAtCuts(const B2DPolyPolygon& rCandidate, const B2DPoint& rStart, const B2DPoint& rEnd) 1099*cdf0e10cSrcweir { 1100*cdf0e10cSrcweir B2DPolyPolygon aRetval; 1101*cdf0e10cSrcweir 1102*cdf0e10cSrcweir for(sal_uInt32 a(0); a < rCandidate.count(); a++) 1103*cdf0e10cSrcweir { 1104*cdf0e10cSrcweir aRetval.append(addPointsAtCuts(rCandidate.getB2DPolygon(a), rStart, rEnd)); 1105*cdf0e10cSrcweir } 1106*cdf0e10cSrcweir 1107*cdf0e10cSrcweir return aRetval; 1108*cdf0e10cSrcweir } 1109*cdf0e10cSrcweir 1110*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////// 1111*cdf0e10cSrcweir 1112*cdf0e10cSrcweir B2DPolygon addPointsAtCuts(const B2DPolygon& rCandidate, const B2DPolyPolygon& rPolyMask) 1113*cdf0e10cSrcweir { 1114*cdf0e10cSrcweir const sal_uInt32 nCountA(rCandidate.count()); 1115*cdf0e10cSrcweir const sal_uInt32 nCountM(rPolyMask.count()); 1116*cdf0e10cSrcweir 1117*cdf0e10cSrcweir if(nCountA && nCountM) 1118*cdf0e10cSrcweir { 1119*cdf0e10cSrcweir const B2DRange aRangeA(rCandidate.getB2DRange()); 1120*cdf0e10cSrcweir const B2DRange aRangeM(rPolyMask.getB2DRange()); 1121*cdf0e10cSrcweir 1122*cdf0e10cSrcweir if(aRangeA.overlaps(aRangeM)) 1123*cdf0e10cSrcweir { 1124*cdf0e10cSrcweir const sal_uInt32 nEdgeCountA(rCandidate.isClosed() ? nCountA : nCountA - 1); 1125*cdf0e10cSrcweir temporaryPointVector aTempPointsA; 1126*cdf0e10cSrcweir temporaryPointVector aUnusedTempPointsB; 1127*cdf0e10cSrcweir 1128*cdf0e10cSrcweir for(sal_uInt32 m(0); m < nCountM; m++) 1129*cdf0e10cSrcweir { 1130*cdf0e10cSrcweir const B2DPolygon aMask(rPolyMask.getB2DPolygon(m)); 1131*cdf0e10cSrcweir const sal_uInt32 nCountB(aMask.count()); 1132*cdf0e10cSrcweir 1133*cdf0e10cSrcweir if(nCountB) 1134*cdf0e10cSrcweir { 1135*cdf0e10cSrcweir B2DCubicBezier aCubicA; 1136*cdf0e10cSrcweir B2DCubicBezier aCubicB; 1137*cdf0e10cSrcweir 1138*cdf0e10cSrcweir for(sal_uInt32 a(0); a < nEdgeCountA; a++) 1139*cdf0e10cSrcweir { 1140*cdf0e10cSrcweir rCandidate.getBezierSegment(a, aCubicA); 1141*cdf0e10cSrcweir const bool bCubicAIsCurve(aCubicA.isBezier()); 1142*cdf0e10cSrcweir B2DRange aCubicRangeA(aCubicA.getStartPoint(), aCubicA.getEndPoint()); 1143*cdf0e10cSrcweir 1144*cdf0e10cSrcweir if(bCubicAIsCurve) 1145*cdf0e10cSrcweir { 1146*cdf0e10cSrcweir aCubicRangeA.expand(aCubicA.getControlPointA()); 1147*cdf0e10cSrcweir aCubicRangeA.expand(aCubicA.getControlPointB()); 1148*cdf0e10cSrcweir } 1149*cdf0e10cSrcweir 1150*cdf0e10cSrcweir for(sal_uInt32 b(0); b < nCountB; b++) 1151*cdf0e10cSrcweir { 1152*cdf0e10cSrcweir aMask.getBezierSegment(b, aCubicB); 1153*cdf0e10cSrcweir const bool bCubicBIsCurve(aCubicB.isBezier()); 1154*cdf0e10cSrcweir B2DRange aCubicRangeB(aCubicB.getStartPoint(), aCubicB.getEndPoint()); 1155*cdf0e10cSrcweir 1156*cdf0e10cSrcweir if(bCubicBIsCurve) 1157*cdf0e10cSrcweir { 1158*cdf0e10cSrcweir aCubicRangeB.expand(aCubicB.getControlPointA()); 1159*cdf0e10cSrcweir aCubicRangeB.expand(aCubicB.getControlPointB()); 1160*cdf0e10cSrcweir } 1161*cdf0e10cSrcweir 1162*cdf0e10cSrcweir if(aCubicRangeA.overlaps(aCubicRangeB)) 1163*cdf0e10cSrcweir { 1164*cdf0e10cSrcweir if(bCubicAIsCurve && bCubicBIsCurve) 1165*cdf0e10cSrcweir { 1166*cdf0e10cSrcweir findEdgeCutsTwoBeziers(aCubicA, aCubicB, a, b, aTempPointsA, aUnusedTempPointsB); 1167*cdf0e10cSrcweir } 1168*cdf0e10cSrcweir else if(bCubicAIsCurve) 1169*cdf0e10cSrcweir { 1170*cdf0e10cSrcweir findEdgeCutsBezierAndEdge(aCubicA, aCubicB.getStartPoint(), aCubicB.getEndPoint(), a, b, aTempPointsA, aUnusedTempPointsB); 1171*cdf0e10cSrcweir } 1172*cdf0e10cSrcweir else if(bCubicBIsCurve) 1173*cdf0e10cSrcweir { 1174*cdf0e10cSrcweir findEdgeCutsBezierAndEdge(aCubicB, aCubicA.getStartPoint(), aCubicA.getEndPoint(), b, a, aUnusedTempPointsB, aTempPointsA); 1175*cdf0e10cSrcweir } 1176*cdf0e10cSrcweir else 1177*cdf0e10cSrcweir { 1178*cdf0e10cSrcweir findEdgeCutsTwoEdges(aCubicA.getStartPoint(), aCubicA.getEndPoint(), aCubicB.getStartPoint(), aCubicB.getEndPoint(), a, b, aTempPointsA, aUnusedTempPointsB); 1179*cdf0e10cSrcweir } 1180*cdf0e10cSrcweir } 1181*cdf0e10cSrcweir } 1182*cdf0e10cSrcweir } 1183*cdf0e10cSrcweir } 1184*cdf0e10cSrcweir } 1185*cdf0e10cSrcweir 1186*cdf0e10cSrcweir return mergeTemporaryPointsAndPolygon(rCandidate, aTempPointsA); 1187*cdf0e10cSrcweir } 1188*cdf0e10cSrcweir } 1189*cdf0e10cSrcweir 1190*cdf0e10cSrcweir return rCandidate; 1191*cdf0e10cSrcweir } 1192*cdf0e10cSrcweir 1193*cdf0e10cSrcweir B2DPolyPolygon addPointsAtCuts(const B2DPolyPolygon& rCandidate, const B2DPolyPolygon& rMask) 1194*cdf0e10cSrcweir { 1195*cdf0e10cSrcweir B2DPolyPolygon aRetval; 1196*cdf0e10cSrcweir 1197*cdf0e10cSrcweir for(sal_uInt32 a(0); a < rCandidate.count(); a++) 1198*cdf0e10cSrcweir { 1199*cdf0e10cSrcweir aRetval.append(addPointsAtCuts(rCandidate.getB2DPolygon(a), rMask)); 1200*cdf0e10cSrcweir } 1201*cdf0e10cSrcweir 1202*cdf0e10cSrcweir return aRetval; 1203*cdf0e10cSrcweir } 1204*cdf0e10cSrcweir 1205*cdf0e10cSrcweir B2DPolygon addPointsAtCuts(const B2DPolygon& rCandidate) 1206*cdf0e10cSrcweir { 1207*cdf0e10cSrcweir if(rCandidate.count()) 1208*cdf0e10cSrcweir { 1209*cdf0e10cSrcweir temporaryPointVector aTempPoints; 1210*cdf0e10cSrcweir 1211*cdf0e10cSrcweir findCuts(rCandidate, aTempPoints); 1212*cdf0e10cSrcweir 1213*cdf0e10cSrcweir return mergeTemporaryPointsAndPolygon(rCandidate, aTempPoints); 1214*cdf0e10cSrcweir } 1215*cdf0e10cSrcweir else 1216*cdf0e10cSrcweir { 1217*cdf0e10cSrcweir return rCandidate; 1218*cdf0e10cSrcweir } 1219*cdf0e10cSrcweir } 1220*cdf0e10cSrcweir 1221*cdf0e10cSrcweir B2DPolyPolygon addPointsAtCuts(const B2DPolyPolygon& rCandidate, bool bSelfIntersections) 1222*cdf0e10cSrcweir { 1223*cdf0e10cSrcweir const sal_uInt32 nCount(rCandidate.count()); 1224*cdf0e10cSrcweir 1225*cdf0e10cSrcweir if(nCount) 1226*cdf0e10cSrcweir { 1227*cdf0e10cSrcweir B2DPolyPolygon aRetval; 1228*cdf0e10cSrcweir 1229*cdf0e10cSrcweir if(1 == nCount) 1230*cdf0e10cSrcweir { 1231*cdf0e10cSrcweir if(bSelfIntersections) 1232*cdf0e10cSrcweir { 1233*cdf0e10cSrcweir // remove self intersections 1234*cdf0e10cSrcweir aRetval.append(addPointsAtCuts(rCandidate.getB2DPolygon(0))); 1235*cdf0e10cSrcweir } 1236*cdf0e10cSrcweir else 1237*cdf0e10cSrcweir { 1238*cdf0e10cSrcweir // copy source 1239*cdf0e10cSrcweir aRetval = rCandidate; 1240*cdf0e10cSrcweir } 1241*cdf0e10cSrcweir } 1242*cdf0e10cSrcweir else 1243*cdf0e10cSrcweir { 1244*cdf0e10cSrcweir // first solve self cuts for all contained single polygons 1245*cdf0e10cSrcweir temporaryPolygonData *pTempData = new temporaryPolygonData[nCount]; 1246*cdf0e10cSrcweir sal_uInt32 a, b; 1247*cdf0e10cSrcweir 1248*cdf0e10cSrcweir for(a = 0; a < nCount; a++) 1249*cdf0e10cSrcweir { 1250*cdf0e10cSrcweir if(bSelfIntersections) 1251*cdf0e10cSrcweir { 1252*cdf0e10cSrcweir // use polygons with solved self intersections 1253*cdf0e10cSrcweir pTempData[a].setPolygon(addPointsAtCuts(rCandidate.getB2DPolygon(a))); 1254*cdf0e10cSrcweir } 1255*cdf0e10cSrcweir else 1256*cdf0e10cSrcweir { 1257*cdf0e10cSrcweir // copy given polygons 1258*cdf0e10cSrcweir pTempData[a].setPolygon(rCandidate.getB2DPolygon(a)); 1259*cdf0e10cSrcweir } 1260*cdf0e10cSrcweir } 1261*cdf0e10cSrcweir 1262*cdf0e10cSrcweir // now cuts and touches between the polygons 1263*cdf0e10cSrcweir for(a = 0; a < nCount; a++) 1264*cdf0e10cSrcweir { 1265*cdf0e10cSrcweir for(b = 0; b < nCount; b++) 1266*cdf0e10cSrcweir { 1267*cdf0e10cSrcweir if(a < b) 1268*cdf0e10cSrcweir { 1269*cdf0e10cSrcweir // look for cuts, compare each edge polygon to following ones 1270*cdf0e10cSrcweir if(pTempData[a].getRange().overlaps(pTempData[b].getRange())) 1271*cdf0e10cSrcweir { 1272*cdf0e10cSrcweir findCuts(pTempData[a].getPolygon(), pTempData[b].getPolygon(), pTempData[a].getTemporaryPointVector(), pTempData[b].getTemporaryPointVector()); 1273*cdf0e10cSrcweir } 1274*cdf0e10cSrcweir } 1275*cdf0e10cSrcweir } 1276*cdf0e10cSrcweir } 1277*cdf0e10cSrcweir 1278*cdf0e10cSrcweir // consolidate the result 1279*cdf0e10cSrcweir for(a = 0L; a < nCount; a++) 1280*cdf0e10cSrcweir { 1281*cdf0e10cSrcweir aRetval.append(mergeTemporaryPointsAndPolygon(pTempData[a].getPolygon(), pTempData[a].getTemporaryPointVector())); 1282*cdf0e10cSrcweir } 1283*cdf0e10cSrcweir 1284*cdf0e10cSrcweir delete[] pTempData; 1285*cdf0e10cSrcweir } 1286*cdf0e10cSrcweir 1287*cdf0e10cSrcweir return aRetval; 1288*cdf0e10cSrcweir } 1289*cdf0e10cSrcweir else 1290*cdf0e10cSrcweir { 1291*cdf0e10cSrcweir return rCandidate; 1292*cdf0e10cSrcweir } 1293*cdf0e10cSrcweir } 1294*cdf0e10cSrcweir 1295*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////// 1296*cdf0e10cSrcweir 1297*cdf0e10cSrcweir } // end of namespace tools 1298*cdf0e10cSrcweir } // end of namespace basegfx 1299*cdf0e10cSrcweir 1300*cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 1301*cdf0e10cSrcweir // eof 1302