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 <osl/diagnose.h> 31*cdf0e10cSrcweir #include <basegfx/polygon/b3dpolygontools.hxx> 32*cdf0e10cSrcweir #include <basegfx/polygon/b3dpolygon.hxx> 33*cdf0e10cSrcweir #include <basegfx/numeric/ftools.hxx> 34*cdf0e10cSrcweir #include <basegfx/range/b3drange.hxx> 35*cdf0e10cSrcweir #include <basegfx/point/b2dpoint.hxx> 36*cdf0e10cSrcweir #include <basegfx/matrix/b3dhommatrix.hxx> 37*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygon.hxx> 38*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygontools.hxx> 39*cdf0e10cSrcweir #include <basegfx/tuple/b3ituple.hxx> 40*cdf0e10cSrcweir #include <numeric> 41*cdf0e10cSrcweir 42*cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 43*cdf0e10cSrcweir 44*cdf0e10cSrcweir namespace basegfx 45*cdf0e10cSrcweir { 46*cdf0e10cSrcweir namespace tools 47*cdf0e10cSrcweir { 48*cdf0e10cSrcweir // B3DPolygon tools 49*cdf0e10cSrcweir void checkClosed(B3DPolygon& rCandidate) 50*cdf0e10cSrcweir { 51*cdf0e10cSrcweir while(rCandidate.count() > 1L 52*cdf0e10cSrcweir && rCandidate.getB3DPoint(0L).equal(rCandidate.getB3DPoint(rCandidate.count() - 1L))) 53*cdf0e10cSrcweir { 54*cdf0e10cSrcweir rCandidate.setClosed(true); 55*cdf0e10cSrcweir rCandidate.remove(rCandidate.count() - 1L); 56*cdf0e10cSrcweir } 57*cdf0e10cSrcweir } 58*cdf0e10cSrcweir 59*cdf0e10cSrcweir // Get successor and predecessor indices. Returning the same index means there 60*cdf0e10cSrcweir // is none. Same for successor. 61*cdf0e10cSrcweir sal_uInt32 getIndexOfPredecessor(sal_uInt32 nIndex, const B3DPolygon& rCandidate) 62*cdf0e10cSrcweir { 63*cdf0e10cSrcweir OSL_ENSURE(nIndex < rCandidate.count(), "getIndexOfPredecessor: Access to polygon out of range (!)"); 64*cdf0e10cSrcweir 65*cdf0e10cSrcweir if(nIndex) 66*cdf0e10cSrcweir { 67*cdf0e10cSrcweir return nIndex - 1L; 68*cdf0e10cSrcweir } 69*cdf0e10cSrcweir else if(rCandidate.count()) 70*cdf0e10cSrcweir { 71*cdf0e10cSrcweir return rCandidate.count() - 1L; 72*cdf0e10cSrcweir } 73*cdf0e10cSrcweir else 74*cdf0e10cSrcweir { 75*cdf0e10cSrcweir return nIndex; 76*cdf0e10cSrcweir } 77*cdf0e10cSrcweir } 78*cdf0e10cSrcweir 79*cdf0e10cSrcweir sal_uInt32 getIndexOfSuccessor(sal_uInt32 nIndex, const B3DPolygon& rCandidate) 80*cdf0e10cSrcweir { 81*cdf0e10cSrcweir OSL_ENSURE(nIndex < rCandidate.count(), "getIndexOfPredecessor: Access to polygon out of range (!)"); 82*cdf0e10cSrcweir 83*cdf0e10cSrcweir if(nIndex + 1L < rCandidate.count()) 84*cdf0e10cSrcweir { 85*cdf0e10cSrcweir return nIndex + 1L; 86*cdf0e10cSrcweir } 87*cdf0e10cSrcweir else 88*cdf0e10cSrcweir { 89*cdf0e10cSrcweir return 0L; 90*cdf0e10cSrcweir } 91*cdf0e10cSrcweir } 92*cdf0e10cSrcweir 93*cdf0e10cSrcweir B3DRange getRange(const B3DPolygon& rCandidate) 94*cdf0e10cSrcweir { 95*cdf0e10cSrcweir B3DRange aRetval; 96*cdf0e10cSrcweir const sal_uInt32 nPointCount(rCandidate.count()); 97*cdf0e10cSrcweir 98*cdf0e10cSrcweir for(sal_uInt32 a(0L); a < nPointCount; a++) 99*cdf0e10cSrcweir { 100*cdf0e10cSrcweir const B3DPoint aTestPoint(rCandidate.getB3DPoint(a)); 101*cdf0e10cSrcweir aRetval.expand(aTestPoint); 102*cdf0e10cSrcweir } 103*cdf0e10cSrcweir 104*cdf0e10cSrcweir return aRetval; 105*cdf0e10cSrcweir } 106*cdf0e10cSrcweir 107*cdf0e10cSrcweir B3DVector getNormal(const B3DPolygon& rCandidate) 108*cdf0e10cSrcweir { 109*cdf0e10cSrcweir return rCandidate.getNormal(); 110*cdf0e10cSrcweir } 111*cdf0e10cSrcweir 112*cdf0e10cSrcweir B3DVector getPositiveOrientedNormal(const B3DPolygon& rCandidate) 113*cdf0e10cSrcweir { 114*cdf0e10cSrcweir B3DVector aRetval(rCandidate.getNormal()); 115*cdf0e10cSrcweir 116*cdf0e10cSrcweir if(ORIENTATION_NEGATIVE == getOrientation(rCandidate)) 117*cdf0e10cSrcweir { 118*cdf0e10cSrcweir aRetval = -aRetval; 119*cdf0e10cSrcweir } 120*cdf0e10cSrcweir 121*cdf0e10cSrcweir return aRetval; 122*cdf0e10cSrcweir } 123*cdf0e10cSrcweir 124*cdf0e10cSrcweir B2VectorOrientation getOrientation(const B3DPolygon& rCandidate) 125*cdf0e10cSrcweir { 126*cdf0e10cSrcweir B2VectorOrientation eRetval(ORIENTATION_NEUTRAL); 127*cdf0e10cSrcweir 128*cdf0e10cSrcweir if(rCandidate.count() > 2L) 129*cdf0e10cSrcweir { 130*cdf0e10cSrcweir const double fSignedArea(getSignedArea(rCandidate)); 131*cdf0e10cSrcweir 132*cdf0e10cSrcweir if(fSignedArea > 0.0) 133*cdf0e10cSrcweir { 134*cdf0e10cSrcweir eRetval = ORIENTATION_POSITIVE; 135*cdf0e10cSrcweir } 136*cdf0e10cSrcweir else if(fSignedArea < 0.0) 137*cdf0e10cSrcweir { 138*cdf0e10cSrcweir eRetval = ORIENTATION_NEGATIVE; 139*cdf0e10cSrcweir } 140*cdf0e10cSrcweir } 141*cdf0e10cSrcweir 142*cdf0e10cSrcweir return eRetval; 143*cdf0e10cSrcweir } 144*cdf0e10cSrcweir 145*cdf0e10cSrcweir double getSignedArea(const B3DPolygon& rCandidate) 146*cdf0e10cSrcweir { 147*cdf0e10cSrcweir double fRetval(0.0); 148*cdf0e10cSrcweir const sal_uInt32 nPointCount(rCandidate.count()); 149*cdf0e10cSrcweir 150*cdf0e10cSrcweir if(nPointCount > 2) 151*cdf0e10cSrcweir { 152*cdf0e10cSrcweir const B3DVector aAbsNormal(absolute(getNormal(rCandidate))); 153*cdf0e10cSrcweir sal_uInt16 nCase(3); // default: ignore z 154*cdf0e10cSrcweir 155*cdf0e10cSrcweir if(aAbsNormal.getX() > aAbsNormal.getY()) 156*cdf0e10cSrcweir { 157*cdf0e10cSrcweir if(aAbsNormal.getX() > aAbsNormal.getZ()) 158*cdf0e10cSrcweir { 159*cdf0e10cSrcweir nCase = 1; // ignore x 160*cdf0e10cSrcweir } 161*cdf0e10cSrcweir } 162*cdf0e10cSrcweir else if(aAbsNormal.getY() > aAbsNormal.getZ()) 163*cdf0e10cSrcweir { 164*cdf0e10cSrcweir nCase = 2; // ignore y 165*cdf0e10cSrcweir } 166*cdf0e10cSrcweir 167*cdf0e10cSrcweir B3DPoint aPreviousPoint(rCandidate.getB3DPoint(nPointCount - 1L)); 168*cdf0e10cSrcweir 169*cdf0e10cSrcweir for(sal_uInt32 a(0L); a < nPointCount; a++) 170*cdf0e10cSrcweir { 171*cdf0e10cSrcweir const B3DPoint aCurrentPoint(rCandidate.getB3DPoint(a)); 172*cdf0e10cSrcweir 173*cdf0e10cSrcweir switch(nCase) 174*cdf0e10cSrcweir { 175*cdf0e10cSrcweir case 1: // ignore x 176*cdf0e10cSrcweir fRetval += aPreviousPoint.getZ() * aCurrentPoint.getY(); 177*cdf0e10cSrcweir fRetval -= aPreviousPoint.getY() * aCurrentPoint.getZ(); 178*cdf0e10cSrcweir break; 179*cdf0e10cSrcweir case 2: // ignore y 180*cdf0e10cSrcweir fRetval += aPreviousPoint.getX() * aCurrentPoint.getZ(); 181*cdf0e10cSrcweir fRetval -= aPreviousPoint.getZ() * aCurrentPoint.getX(); 182*cdf0e10cSrcweir break; 183*cdf0e10cSrcweir case 3: // ignore z 184*cdf0e10cSrcweir fRetval += aPreviousPoint.getX() * aCurrentPoint.getY(); 185*cdf0e10cSrcweir fRetval -= aPreviousPoint.getY() * aCurrentPoint.getX(); 186*cdf0e10cSrcweir break; 187*cdf0e10cSrcweir } 188*cdf0e10cSrcweir 189*cdf0e10cSrcweir // prepare next step 190*cdf0e10cSrcweir aPreviousPoint = aCurrentPoint; 191*cdf0e10cSrcweir } 192*cdf0e10cSrcweir 193*cdf0e10cSrcweir switch(nCase) 194*cdf0e10cSrcweir { 195*cdf0e10cSrcweir case 1: // ignore x 196*cdf0e10cSrcweir fRetval /= 2.0 * aAbsNormal.getX(); 197*cdf0e10cSrcweir break; 198*cdf0e10cSrcweir case 2: // ignore y 199*cdf0e10cSrcweir fRetval /= 2.0 * aAbsNormal.getY(); 200*cdf0e10cSrcweir break; 201*cdf0e10cSrcweir case 3: // ignore z 202*cdf0e10cSrcweir fRetval /= 2.0 * aAbsNormal.getZ(); 203*cdf0e10cSrcweir break; 204*cdf0e10cSrcweir } 205*cdf0e10cSrcweir } 206*cdf0e10cSrcweir 207*cdf0e10cSrcweir return fRetval; 208*cdf0e10cSrcweir } 209*cdf0e10cSrcweir 210*cdf0e10cSrcweir double getArea(const B3DPolygon& rCandidate) 211*cdf0e10cSrcweir { 212*cdf0e10cSrcweir double fRetval(0.0); 213*cdf0e10cSrcweir 214*cdf0e10cSrcweir if(rCandidate.count() > 2) 215*cdf0e10cSrcweir { 216*cdf0e10cSrcweir fRetval = getSignedArea(rCandidate); 217*cdf0e10cSrcweir const double fZero(0.0); 218*cdf0e10cSrcweir 219*cdf0e10cSrcweir if(fTools::less(fRetval, fZero)) 220*cdf0e10cSrcweir { 221*cdf0e10cSrcweir fRetval = -fRetval; 222*cdf0e10cSrcweir } 223*cdf0e10cSrcweir } 224*cdf0e10cSrcweir 225*cdf0e10cSrcweir return fRetval; 226*cdf0e10cSrcweir } 227*cdf0e10cSrcweir 228*cdf0e10cSrcweir double getEdgeLength(const B3DPolygon& rCandidate, sal_uInt32 nIndex) 229*cdf0e10cSrcweir { 230*cdf0e10cSrcweir OSL_ENSURE(nIndex < rCandidate.count(), "getEdgeLength: Access to polygon out of range (!)"); 231*cdf0e10cSrcweir double fRetval(0.0); 232*cdf0e10cSrcweir const sal_uInt32 nPointCount(rCandidate.count()); 233*cdf0e10cSrcweir 234*cdf0e10cSrcweir if(nIndex < nPointCount) 235*cdf0e10cSrcweir { 236*cdf0e10cSrcweir if(rCandidate.isClosed() || ((nIndex + 1L) != nPointCount)) 237*cdf0e10cSrcweir { 238*cdf0e10cSrcweir const sal_uInt32 nNextIndex(getIndexOfSuccessor(nIndex, rCandidate)); 239*cdf0e10cSrcweir const B3DPoint aCurrentPoint(rCandidate.getB3DPoint(nIndex)); 240*cdf0e10cSrcweir const B3DPoint aNextPoint(rCandidate.getB3DPoint(nNextIndex)); 241*cdf0e10cSrcweir const B3DVector aVector(aNextPoint - aCurrentPoint); 242*cdf0e10cSrcweir fRetval = aVector.getLength(); 243*cdf0e10cSrcweir } 244*cdf0e10cSrcweir } 245*cdf0e10cSrcweir 246*cdf0e10cSrcweir return fRetval; 247*cdf0e10cSrcweir } 248*cdf0e10cSrcweir 249*cdf0e10cSrcweir double getLength(const B3DPolygon& rCandidate) 250*cdf0e10cSrcweir { 251*cdf0e10cSrcweir double fRetval(0.0); 252*cdf0e10cSrcweir const sal_uInt32 nPointCount(rCandidate.count()); 253*cdf0e10cSrcweir 254*cdf0e10cSrcweir if(nPointCount > 1L) 255*cdf0e10cSrcweir { 256*cdf0e10cSrcweir const sal_uInt32 nLoopCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1L); 257*cdf0e10cSrcweir 258*cdf0e10cSrcweir for(sal_uInt32 a(0L); a < nLoopCount; a++) 259*cdf0e10cSrcweir { 260*cdf0e10cSrcweir const sal_uInt32 nNextIndex(getIndexOfSuccessor(a, rCandidate)); 261*cdf0e10cSrcweir const B3DPoint aCurrentPoint(rCandidate.getB3DPoint(a)); 262*cdf0e10cSrcweir const B3DPoint aNextPoint(rCandidate.getB3DPoint(nNextIndex)); 263*cdf0e10cSrcweir const B3DVector aVector(aNextPoint - aCurrentPoint); 264*cdf0e10cSrcweir fRetval += aVector.getLength(); 265*cdf0e10cSrcweir } 266*cdf0e10cSrcweir } 267*cdf0e10cSrcweir 268*cdf0e10cSrcweir return fRetval; 269*cdf0e10cSrcweir } 270*cdf0e10cSrcweir 271*cdf0e10cSrcweir B3DPoint getPositionAbsolute(const B3DPolygon& rCandidate, double fDistance, double fLength) 272*cdf0e10cSrcweir { 273*cdf0e10cSrcweir B3DPoint aRetval; 274*cdf0e10cSrcweir const sal_uInt32 nPointCount(rCandidate.count()); 275*cdf0e10cSrcweir 276*cdf0e10cSrcweir if(nPointCount > 1L) 277*cdf0e10cSrcweir { 278*cdf0e10cSrcweir sal_uInt32 nIndex(0L); 279*cdf0e10cSrcweir bool bIndexDone(false); 280*cdf0e10cSrcweir const double fZero(0.0); 281*cdf0e10cSrcweir double fEdgeLength(fZero); 282*cdf0e10cSrcweir 283*cdf0e10cSrcweir // get length if not given 284*cdf0e10cSrcweir if(fTools::equalZero(fLength)) 285*cdf0e10cSrcweir { 286*cdf0e10cSrcweir fLength = getLength(rCandidate); 287*cdf0e10cSrcweir } 288*cdf0e10cSrcweir 289*cdf0e10cSrcweir // handle fDistance < 0.0 290*cdf0e10cSrcweir if(fTools::less(fDistance, fZero)) 291*cdf0e10cSrcweir { 292*cdf0e10cSrcweir if(rCandidate.isClosed()) 293*cdf0e10cSrcweir { 294*cdf0e10cSrcweir // if fDistance < 0.0 increment with multiple of fLength 295*cdf0e10cSrcweir sal_uInt32 nCount(sal_uInt32(-fDistance / fLength)); 296*cdf0e10cSrcweir fDistance += double(nCount + 1L) * fLength; 297*cdf0e10cSrcweir } 298*cdf0e10cSrcweir else 299*cdf0e10cSrcweir { 300*cdf0e10cSrcweir // crop to polygon start 301*cdf0e10cSrcweir fDistance = fZero; 302*cdf0e10cSrcweir bIndexDone = true; 303*cdf0e10cSrcweir } 304*cdf0e10cSrcweir } 305*cdf0e10cSrcweir 306*cdf0e10cSrcweir // handle fDistance >= fLength 307*cdf0e10cSrcweir if(fTools::moreOrEqual(fDistance, fLength)) 308*cdf0e10cSrcweir { 309*cdf0e10cSrcweir if(rCandidate.isClosed()) 310*cdf0e10cSrcweir { 311*cdf0e10cSrcweir // if fDistance >= fLength decrement with multiple of fLength 312*cdf0e10cSrcweir sal_uInt32 nCount(sal_uInt32(fDistance / fLength)); 313*cdf0e10cSrcweir fDistance -= (double)(nCount) * fLength; 314*cdf0e10cSrcweir } 315*cdf0e10cSrcweir else 316*cdf0e10cSrcweir { 317*cdf0e10cSrcweir // crop to polygon end 318*cdf0e10cSrcweir fDistance = fZero; 319*cdf0e10cSrcweir nIndex = nPointCount - 1L; 320*cdf0e10cSrcweir bIndexDone = true; 321*cdf0e10cSrcweir } 322*cdf0e10cSrcweir } 323*cdf0e10cSrcweir 324*cdf0e10cSrcweir // look for correct index. fDistance is now [0.0 .. fLength[ 325*cdf0e10cSrcweir if(!bIndexDone) 326*cdf0e10cSrcweir { 327*cdf0e10cSrcweir do 328*cdf0e10cSrcweir { 329*cdf0e10cSrcweir // get length of next edge 330*cdf0e10cSrcweir fEdgeLength = getEdgeLength(rCandidate, nIndex); 331*cdf0e10cSrcweir 332*cdf0e10cSrcweir if(fTools::moreOrEqual(fDistance, fEdgeLength)) 333*cdf0e10cSrcweir { 334*cdf0e10cSrcweir // go to next edge 335*cdf0e10cSrcweir fDistance -= fEdgeLength; 336*cdf0e10cSrcweir nIndex++; 337*cdf0e10cSrcweir } 338*cdf0e10cSrcweir else 339*cdf0e10cSrcweir { 340*cdf0e10cSrcweir // it's on this edge, stop 341*cdf0e10cSrcweir bIndexDone = true; 342*cdf0e10cSrcweir } 343*cdf0e10cSrcweir } while (!bIndexDone); 344*cdf0e10cSrcweir } 345*cdf0e10cSrcweir 346*cdf0e10cSrcweir // get the point using nIndex 347*cdf0e10cSrcweir aRetval = rCandidate.getB3DPoint(nIndex); 348*cdf0e10cSrcweir 349*cdf0e10cSrcweir // if fDistance != 0.0, move that length on the edge. The edge 350*cdf0e10cSrcweir // length is in fEdgeLength. 351*cdf0e10cSrcweir if(!fTools::equalZero(fDistance)) 352*cdf0e10cSrcweir { 353*cdf0e10cSrcweir sal_uInt32 nNextIndex(getIndexOfSuccessor(nIndex, rCandidate)); 354*cdf0e10cSrcweir const B3DPoint aNextPoint(rCandidate.getB3DPoint(nNextIndex)); 355*cdf0e10cSrcweir double fRelative(fZero); 356*cdf0e10cSrcweir 357*cdf0e10cSrcweir if(!fTools::equalZero(fEdgeLength)) 358*cdf0e10cSrcweir { 359*cdf0e10cSrcweir fRelative = fDistance / fEdgeLength; 360*cdf0e10cSrcweir } 361*cdf0e10cSrcweir 362*cdf0e10cSrcweir // add calculated average value to the return value 363*cdf0e10cSrcweir aRetval += interpolate(aRetval, aNextPoint, fRelative); 364*cdf0e10cSrcweir } 365*cdf0e10cSrcweir } 366*cdf0e10cSrcweir 367*cdf0e10cSrcweir return aRetval; 368*cdf0e10cSrcweir } 369*cdf0e10cSrcweir 370*cdf0e10cSrcweir B3DPoint getPositionRelative(const B3DPolygon& rCandidate, double fDistance, double fLength) 371*cdf0e10cSrcweir { 372*cdf0e10cSrcweir // get length if not given 373*cdf0e10cSrcweir if(fTools::equalZero(fLength)) 374*cdf0e10cSrcweir { 375*cdf0e10cSrcweir fLength = getLength(rCandidate); 376*cdf0e10cSrcweir } 377*cdf0e10cSrcweir 378*cdf0e10cSrcweir // multiply fDistance with real length to get absolute position and 379*cdf0e10cSrcweir // use getPositionAbsolute 380*cdf0e10cSrcweir return getPositionAbsolute(rCandidate, fDistance * fLength, fLength); 381*cdf0e10cSrcweir } 382*cdf0e10cSrcweir 383*cdf0e10cSrcweir void applyLineDashing(const B3DPolygon& rCandidate, const ::std::vector<double>& rDotDashArray, B3DPolyPolygon* pLineTarget, B3DPolyPolygon* pGapTarget, double fDotDashLength) 384*cdf0e10cSrcweir { 385*cdf0e10cSrcweir const sal_uInt32 nPointCount(rCandidate.count()); 386*cdf0e10cSrcweir const sal_uInt32 nDotDashCount(rDotDashArray.size()); 387*cdf0e10cSrcweir 388*cdf0e10cSrcweir if(fTools::lessOrEqual(fDotDashLength, 0.0)) 389*cdf0e10cSrcweir { 390*cdf0e10cSrcweir fDotDashLength = ::std::accumulate(rDotDashArray.begin(), rDotDashArray.end(), 0.0); 391*cdf0e10cSrcweir } 392*cdf0e10cSrcweir 393*cdf0e10cSrcweir if(fTools::more(fDotDashLength, 0.0) && (pLineTarget || pGapTarget) && nPointCount) 394*cdf0e10cSrcweir { 395*cdf0e10cSrcweir // clear targets 396*cdf0e10cSrcweir if(pLineTarget) 397*cdf0e10cSrcweir { 398*cdf0e10cSrcweir pLineTarget->clear(); 399*cdf0e10cSrcweir } 400*cdf0e10cSrcweir 401*cdf0e10cSrcweir if(pGapTarget) 402*cdf0e10cSrcweir { 403*cdf0e10cSrcweir pGapTarget->clear(); 404*cdf0e10cSrcweir } 405*cdf0e10cSrcweir 406*cdf0e10cSrcweir // prepare current edge's start 407*cdf0e10cSrcweir B3DPoint aCurrentPoint(rCandidate.getB3DPoint(0)); 408*cdf0e10cSrcweir const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1); 409*cdf0e10cSrcweir 410*cdf0e10cSrcweir // prepare DotDashArray iteration and the line/gap switching bool 411*cdf0e10cSrcweir sal_uInt32 nDotDashIndex(0); 412*cdf0e10cSrcweir bool bIsLine(true); 413*cdf0e10cSrcweir double fDotDashMovingLength(rDotDashArray[0]); 414*cdf0e10cSrcweir B3DPolygon aSnippet; 415*cdf0e10cSrcweir 416*cdf0e10cSrcweir // iterate over all edges 417*cdf0e10cSrcweir for(sal_uInt32 a(0); a < nEdgeCount; a++) 418*cdf0e10cSrcweir { 419*cdf0e10cSrcweir // update current edge 420*cdf0e10cSrcweir double fLastDotDashMovingLength(0.0); 421*cdf0e10cSrcweir const sal_uInt32 nNextIndex((a + 1) % nPointCount); 422*cdf0e10cSrcweir const B3DPoint aNextPoint(rCandidate.getB3DPoint(nNextIndex)); 423*cdf0e10cSrcweir const double fEdgeLength(B3DVector(aNextPoint - aCurrentPoint).getLength()); 424*cdf0e10cSrcweir 425*cdf0e10cSrcweir while(fTools::less(fDotDashMovingLength, fEdgeLength)) 426*cdf0e10cSrcweir { 427*cdf0e10cSrcweir // new split is inside edge, create and append snippet [fLastDotDashMovingLength, fDotDashMovingLength] 428*cdf0e10cSrcweir const bool bHandleLine(bIsLine && pLineTarget); 429*cdf0e10cSrcweir const bool bHandleGap(!bIsLine && pGapTarget); 430*cdf0e10cSrcweir 431*cdf0e10cSrcweir if(bHandleLine || bHandleGap) 432*cdf0e10cSrcweir { 433*cdf0e10cSrcweir if(!aSnippet.count()) 434*cdf0e10cSrcweir { 435*cdf0e10cSrcweir aSnippet.append(interpolate(aCurrentPoint, aNextPoint, fLastDotDashMovingLength / fEdgeLength)); 436*cdf0e10cSrcweir } 437*cdf0e10cSrcweir 438*cdf0e10cSrcweir aSnippet.append(interpolate(aCurrentPoint, aNextPoint, fDotDashMovingLength / fEdgeLength)); 439*cdf0e10cSrcweir 440*cdf0e10cSrcweir if(bHandleLine) 441*cdf0e10cSrcweir { 442*cdf0e10cSrcweir pLineTarget->append(aSnippet); 443*cdf0e10cSrcweir } 444*cdf0e10cSrcweir else 445*cdf0e10cSrcweir { 446*cdf0e10cSrcweir pGapTarget->append(aSnippet); 447*cdf0e10cSrcweir } 448*cdf0e10cSrcweir 449*cdf0e10cSrcweir aSnippet.clear(); 450*cdf0e10cSrcweir } 451*cdf0e10cSrcweir 452*cdf0e10cSrcweir // prepare next DotDashArray step and flip line/gap flag 453*cdf0e10cSrcweir fLastDotDashMovingLength = fDotDashMovingLength; 454*cdf0e10cSrcweir fDotDashMovingLength += rDotDashArray[(++nDotDashIndex) % nDotDashCount]; 455*cdf0e10cSrcweir bIsLine = !bIsLine; 456*cdf0e10cSrcweir } 457*cdf0e10cSrcweir 458*cdf0e10cSrcweir // append snippet [fLastDotDashMovingLength, fEdgeLength] 459*cdf0e10cSrcweir const bool bHandleLine(bIsLine && pLineTarget); 460*cdf0e10cSrcweir const bool bHandleGap(!bIsLine && pGapTarget); 461*cdf0e10cSrcweir 462*cdf0e10cSrcweir if(bHandleLine || bHandleGap) 463*cdf0e10cSrcweir { 464*cdf0e10cSrcweir if(!aSnippet.count()) 465*cdf0e10cSrcweir { 466*cdf0e10cSrcweir aSnippet.append(interpolate(aCurrentPoint, aNextPoint, fLastDotDashMovingLength / fEdgeLength)); 467*cdf0e10cSrcweir } 468*cdf0e10cSrcweir 469*cdf0e10cSrcweir aSnippet.append(aNextPoint); 470*cdf0e10cSrcweir } 471*cdf0e10cSrcweir 472*cdf0e10cSrcweir // prepare move to next edge 473*cdf0e10cSrcweir fDotDashMovingLength -= fEdgeLength; 474*cdf0e10cSrcweir 475*cdf0e10cSrcweir // prepare next edge step (end point gets new start point) 476*cdf0e10cSrcweir aCurrentPoint = aNextPoint; 477*cdf0e10cSrcweir } 478*cdf0e10cSrcweir 479*cdf0e10cSrcweir // append last intermediate results (if exists) 480*cdf0e10cSrcweir if(aSnippet.count()) 481*cdf0e10cSrcweir { 482*cdf0e10cSrcweir if(bIsLine && pLineTarget) 483*cdf0e10cSrcweir { 484*cdf0e10cSrcweir pLineTarget->append(aSnippet); 485*cdf0e10cSrcweir } 486*cdf0e10cSrcweir else if(!bIsLine && pGapTarget) 487*cdf0e10cSrcweir { 488*cdf0e10cSrcweir pGapTarget->append(aSnippet); 489*cdf0e10cSrcweir } 490*cdf0e10cSrcweir } 491*cdf0e10cSrcweir 492*cdf0e10cSrcweir // check if start and end polygon may be merged 493*cdf0e10cSrcweir if(pLineTarget) 494*cdf0e10cSrcweir { 495*cdf0e10cSrcweir const sal_uInt32 nCount(pLineTarget->count()); 496*cdf0e10cSrcweir 497*cdf0e10cSrcweir if(nCount > 1) 498*cdf0e10cSrcweir { 499*cdf0e10cSrcweir // these polygons were created above, there exists none with less than two points, 500*cdf0e10cSrcweir // thus dircet point access below is allowed 501*cdf0e10cSrcweir const B3DPolygon aFirst(pLineTarget->getB3DPolygon(0)); 502*cdf0e10cSrcweir B3DPolygon aLast(pLineTarget->getB3DPolygon(nCount - 1)); 503*cdf0e10cSrcweir 504*cdf0e10cSrcweir if(aFirst.getB3DPoint(0).equal(aLast.getB3DPoint(aLast.count() - 1))) 505*cdf0e10cSrcweir { 506*cdf0e10cSrcweir // start of first and end of last are the same -> merge them 507*cdf0e10cSrcweir aLast.append(aFirst); 508*cdf0e10cSrcweir aLast.removeDoublePoints(); 509*cdf0e10cSrcweir pLineTarget->setB3DPolygon(0, aLast); 510*cdf0e10cSrcweir pLineTarget->remove(nCount - 1); 511*cdf0e10cSrcweir } 512*cdf0e10cSrcweir } 513*cdf0e10cSrcweir } 514*cdf0e10cSrcweir 515*cdf0e10cSrcweir if(pGapTarget) 516*cdf0e10cSrcweir { 517*cdf0e10cSrcweir const sal_uInt32 nCount(pGapTarget->count()); 518*cdf0e10cSrcweir 519*cdf0e10cSrcweir if(nCount > 1) 520*cdf0e10cSrcweir { 521*cdf0e10cSrcweir // these polygons were created above, there exists none with less than two points, 522*cdf0e10cSrcweir // thus dircet point access below is allowed 523*cdf0e10cSrcweir const B3DPolygon aFirst(pGapTarget->getB3DPolygon(0)); 524*cdf0e10cSrcweir B3DPolygon aLast(pGapTarget->getB3DPolygon(nCount - 1)); 525*cdf0e10cSrcweir 526*cdf0e10cSrcweir if(aFirst.getB3DPoint(0).equal(aLast.getB3DPoint(aLast.count() - 1))) 527*cdf0e10cSrcweir { 528*cdf0e10cSrcweir // start of first and end of last are the same -> merge them 529*cdf0e10cSrcweir aLast.append(aFirst); 530*cdf0e10cSrcweir aLast.removeDoublePoints(); 531*cdf0e10cSrcweir pGapTarget->setB3DPolygon(0, aLast); 532*cdf0e10cSrcweir pGapTarget->remove(nCount - 1); 533*cdf0e10cSrcweir } 534*cdf0e10cSrcweir } 535*cdf0e10cSrcweir } 536*cdf0e10cSrcweir } 537*cdf0e10cSrcweir else 538*cdf0e10cSrcweir { 539*cdf0e10cSrcweir // parameters make no sense, just add source to targets 540*cdf0e10cSrcweir if(pLineTarget) 541*cdf0e10cSrcweir { 542*cdf0e10cSrcweir pLineTarget->append(rCandidate); 543*cdf0e10cSrcweir } 544*cdf0e10cSrcweir 545*cdf0e10cSrcweir if(pGapTarget) 546*cdf0e10cSrcweir { 547*cdf0e10cSrcweir pGapTarget->append(rCandidate); 548*cdf0e10cSrcweir } 549*cdf0e10cSrcweir } 550*cdf0e10cSrcweir } 551*cdf0e10cSrcweir 552*cdf0e10cSrcweir B3DPolygon applyDefaultNormalsSphere( const B3DPolygon& rCandidate, const B3DPoint& rCenter) 553*cdf0e10cSrcweir { 554*cdf0e10cSrcweir B3DPolygon aRetval(rCandidate); 555*cdf0e10cSrcweir 556*cdf0e10cSrcweir for(sal_uInt32 a(0L); a < aRetval.count(); a++) 557*cdf0e10cSrcweir { 558*cdf0e10cSrcweir B3DVector aVector(aRetval.getB3DPoint(a) - rCenter); 559*cdf0e10cSrcweir aVector.normalize(); 560*cdf0e10cSrcweir aRetval.setNormal(a, aVector); 561*cdf0e10cSrcweir } 562*cdf0e10cSrcweir 563*cdf0e10cSrcweir return aRetval; 564*cdf0e10cSrcweir } 565*cdf0e10cSrcweir 566*cdf0e10cSrcweir B3DPolygon invertNormals( const B3DPolygon& rCandidate) 567*cdf0e10cSrcweir { 568*cdf0e10cSrcweir B3DPolygon aRetval(rCandidate); 569*cdf0e10cSrcweir 570*cdf0e10cSrcweir if(aRetval.areNormalsUsed()) 571*cdf0e10cSrcweir { 572*cdf0e10cSrcweir for(sal_uInt32 a(0L); a < aRetval.count(); a++) 573*cdf0e10cSrcweir { 574*cdf0e10cSrcweir aRetval.setNormal(a, -aRetval.getNormal(a)); 575*cdf0e10cSrcweir } 576*cdf0e10cSrcweir } 577*cdf0e10cSrcweir 578*cdf0e10cSrcweir return aRetval; 579*cdf0e10cSrcweir } 580*cdf0e10cSrcweir 581*cdf0e10cSrcweir B3DPolygon applyDefaultTextureCoordinatesParallel( const B3DPolygon& rCandidate, const B3DRange& rRange, bool bChangeX, bool bChangeY) 582*cdf0e10cSrcweir { 583*cdf0e10cSrcweir B3DPolygon aRetval(rCandidate); 584*cdf0e10cSrcweir 585*cdf0e10cSrcweir if(bChangeX || bChangeY) 586*cdf0e10cSrcweir { 587*cdf0e10cSrcweir // create projection of standard texture coordinates in (X, Y) onto 588*cdf0e10cSrcweir // the 3d coordinates straight 589*cdf0e10cSrcweir const double fWidth(rRange.getWidth()); 590*cdf0e10cSrcweir const double fHeight(rRange.getHeight()); 591*cdf0e10cSrcweir const bool bWidthSet(!fTools::equalZero(fWidth)); 592*cdf0e10cSrcweir const bool bHeightSet(!fTools::equalZero(fHeight)); 593*cdf0e10cSrcweir const double fOne(1.0); 594*cdf0e10cSrcweir 595*cdf0e10cSrcweir for(sal_uInt32 a(0L); a < aRetval.count(); a++) 596*cdf0e10cSrcweir { 597*cdf0e10cSrcweir const B3DPoint aPoint(aRetval.getB3DPoint(a)); 598*cdf0e10cSrcweir B2DPoint aTextureCoordinate(aRetval.getTextureCoordinate(a)); 599*cdf0e10cSrcweir 600*cdf0e10cSrcweir if(bChangeX) 601*cdf0e10cSrcweir { 602*cdf0e10cSrcweir if(bWidthSet) 603*cdf0e10cSrcweir { 604*cdf0e10cSrcweir aTextureCoordinate.setX((aPoint.getX() - rRange.getMinX()) / fWidth); 605*cdf0e10cSrcweir } 606*cdf0e10cSrcweir else 607*cdf0e10cSrcweir { 608*cdf0e10cSrcweir aTextureCoordinate.setX(0.0); 609*cdf0e10cSrcweir } 610*cdf0e10cSrcweir } 611*cdf0e10cSrcweir 612*cdf0e10cSrcweir if(bChangeY) 613*cdf0e10cSrcweir { 614*cdf0e10cSrcweir if(bHeightSet) 615*cdf0e10cSrcweir { 616*cdf0e10cSrcweir aTextureCoordinate.setY(fOne - ((aPoint.getY() - rRange.getMinY()) / fHeight)); 617*cdf0e10cSrcweir } 618*cdf0e10cSrcweir else 619*cdf0e10cSrcweir { 620*cdf0e10cSrcweir aTextureCoordinate.setY(fOne); 621*cdf0e10cSrcweir } 622*cdf0e10cSrcweir } 623*cdf0e10cSrcweir 624*cdf0e10cSrcweir aRetval.setTextureCoordinate(a, aTextureCoordinate); 625*cdf0e10cSrcweir } 626*cdf0e10cSrcweir } 627*cdf0e10cSrcweir 628*cdf0e10cSrcweir return aRetval; 629*cdf0e10cSrcweir } 630*cdf0e10cSrcweir 631*cdf0e10cSrcweir B3DPolygon applyDefaultTextureCoordinatesSphere( const B3DPolygon& rCandidate, const B3DPoint& rCenter, bool bChangeX, bool bChangeY) 632*cdf0e10cSrcweir { 633*cdf0e10cSrcweir B3DPolygon aRetval(rCandidate); 634*cdf0e10cSrcweir 635*cdf0e10cSrcweir if(bChangeX || bChangeY) 636*cdf0e10cSrcweir { 637*cdf0e10cSrcweir // create texture coordinates using sphere projection to cartesian coordinates, 638*cdf0e10cSrcweir // use object's center as base 639*cdf0e10cSrcweir const double fOne(1.0); 640*cdf0e10cSrcweir const sal_uInt32 nPointCount(aRetval.count()); 641*cdf0e10cSrcweir bool bPolarPoints(false); 642*cdf0e10cSrcweir sal_uInt32 a; 643*cdf0e10cSrcweir 644*cdf0e10cSrcweir // create center cartesian coordinates to have a possibility to decide if on boundary 645*cdf0e10cSrcweir // transitions which value to choose 646*cdf0e10cSrcweir const B3DRange aPlaneRange(getRange(rCandidate)); 647*cdf0e10cSrcweir const B3DPoint aPlaneCenter(aPlaneRange.getCenter() - rCenter); 648*cdf0e10cSrcweir const double fXCenter(fOne - ((atan2(aPlaneCenter.getZ(), aPlaneCenter.getX()) + F_PI) / F_2PI)); 649*cdf0e10cSrcweir 650*cdf0e10cSrcweir for(a = 0L; a < nPointCount; a++) 651*cdf0e10cSrcweir { 652*cdf0e10cSrcweir const B3DVector aVector(aRetval.getB3DPoint(a) - rCenter); 653*cdf0e10cSrcweir const double fY(fOne - ((atan2(aVector.getY(), aVector.getXZLength()) + F_PI2) / F_PI)); 654*cdf0e10cSrcweir B2DPoint aTexCoor(aRetval.getTextureCoordinate(a)); 655*cdf0e10cSrcweir 656*cdf0e10cSrcweir if(fTools::equalZero(fY)) 657*cdf0e10cSrcweir { 658*cdf0e10cSrcweir // point is a north polar point, no useful X-coordinate can be created. 659*cdf0e10cSrcweir if(bChangeY) 660*cdf0e10cSrcweir { 661*cdf0e10cSrcweir aTexCoor.setY(0.0); 662*cdf0e10cSrcweir 663*cdf0e10cSrcweir if(bChangeX) 664*cdf0e10cSrcweir { 665*cdf0e10cSrcweir bPolarPoints = true; 666*cdf0e10cSrcweir } 667*cdf0e10cSrcweir } 668*cdf0e10cSrcweir } 669*cdf0e10cSrcweir else if(fTools::equal(fY, fOne)) 670*cdf0e10cSrcweir { 671*cdf0e10cSrcweir // point is a south polar point, no useful X-coordinate can be created. Set 672*cdf0e10cSrcweir // Y-coordinte, though 673*cdf0e10cSrcweir if(bChangeY) 674*cdf0e10cSrcweir { 675*cdf0e10cSrcweir aTexCoor.setY(fOne); 676*cdf0e10cSrcweir 677*cdf0e10cSrcweir if(bChangeX) 678*cdf0e10cSrcweir { 679*cdf0e10cSrcweir bPolarPoints = true; 680*cdf0e10cSrcweir } 681*cdf0e10cSrcweir } 682*cdf0e10cSrcweir } 683*cdf0e10cSrcweir else 684*cdf0e10cSrcweir { 685*cdf0e10cSrcweir double fX(fOne - ((atan2(aVector.getZ(), aVector.getX()) + F_PI) / F_2PI)); 686*cdf0e10cSrcweir 687*cdf0e10cSrcweir // correct cartesinan point coordiante dependent from center value 688*cdf0e10cSrcweir if(fX > fXCenter + 0.5) 689*cdf0e10cSrcweir { 690*cdf0e10cSrcweir fX -= fOne; 691*cdf0e10cSrcweir } 692*cdf0e10cSrcweir else if(fX < fXCenter - 0.5) 693*cdf0e10cSrcweir { 694*cdf0e10cSrcweir fX += fOne; 695*cdf0e10cSrcweir } 696*cdf0e10cSrcweir 697*cdf0e10cSrcweir if(bChangeX) 698*cdf0e10cSrcweir { 699*cdf0e10cSrcweir aTexCoor.setX(fX); 700*cdf0e10cSrcweir } 701*cdf0e10cSrcweir 702*cdf0e10cSrcweir if(bChangeY) 703*cdf0e10cSrcweir { 704*cdf0e10cSrcweir aTexCoor.setY(fY); 705*cdf0e10cSrcweir } 706*cdf0e10cSrcweir } 707*cdf0e10cSrcweir 708*cdf0e10cSrcweir aRetval.setTextureCoordinate(a, aTexCoor); 709*cdf0e10cSrcweir } 710*cdf0e10cSrcweir 711*cdf0e10cSrcweir if(bPolarPoints) 712*cdf0e10cSrcweir { 713*cdf0e10cSrcweir // correct X-texture coordinates if polar points are contained. Those 714*cdf0e10cSrcweir // coordinates cannot be correct, so use prev or next X-coordinate 715*cdf0e10cSrcweir for(a = 0L; a < nPointCount; a++) 716*cdf0e10cSrcweir { 717*cdf0e10cSrcweir B2DPoint aTexCoor(aRetval.getTextureCoordinate(a)); 718*cdf0e10cSrcweir 719*cdf0e10cSrcweir if(fTools::equalZero(aTexCoor.getY()) || fTools::equal(aTexCoor.getY(), fOne)) 720*cdf0e10cSrcweir { 721*cdf0e10cSrcweir // get prev, next TexCoor and test for pole 722*cdf0e10cSrcweir const B2DPoint aPrevTexCoor(aRetval.getTextureCoordinate(a ? a - 1L : nPointCount - 1L)); 723*cdf0e10cSrcweir const B2DPoint aNextTexCoor(aRetval.getTextureCoordinate((a + 1L) % nPointCount)); 724*cdf0e10cSrcweir const bool bPrevPole(fTools::equalZero(aPrevTexCoor.getY()) || fTools::equal(aPrevTexCoor.getY(), fOne)); 725*cdf0e10cSrcweir const bool bNextPole(fTools::equalZero(aNextTexCoor.getY()) || fTools::equal(aNextTexCoor.getY(), fOne)); 726*cdf0e10cSrcweir 727*cdf0e10cSrcweir if(!bPrevPole && !bNextPole) 728*cdf0e10cSrcweir { 729*cdf0e10cSrcweir // both no poles, mix them 730*cdf0e10cSrcweir aTexCoor.setX((aPrevTexCoor.getX() + aNextTexCoor.getX()) / 2.0); 731*cdf0e10cSrcweir } 732*cdf0e10cSrcweir else if(!bNextPole) 733*cdf0e10cSrcweir { 734*cdf0e10cSrcweir // copy next 735*cdf0e10cSrcweir aTexCoor.setX(aNextTexCoor.getX()); 736*cdf0e10cSrcweir } 737*cdf0e10cSrcweir else 738*cdf0e10cSrcweir { 739*cdf0e10cSrcweir // copy prev, even if it's a pole, hopefully it is already corrected 740*cdf0e10cSrcweir aTexCoor.setX(aPrevTexCoor.getX()); 741*cdf0e10cSrcweir } 742*cdf0e10cSrcweir 743*cdf0e10cSrcweir aRetval.setTextureCoordinate(a, aTexCoor); 744*cdf0e10cSrcweir } 745*cdf0e10cSrcweir } 746*cdf0e10cSrcweir } 747*cdf0e10cSrcweir } 748*cdf0e10cSrcweir 749*cdf0e10cSrcweir return aRetval; 750*cdf0e10cSrcweir } 751*cdf0e10cSrcweir 752*cdf0e10cSrcweir bool isInEpsilonRange(const B3DPoint& rEdgeStart, const B3DPoint& rEdgeEnd, const B3DPoint& rTestPosition, double fDistance) 753*cdf0e10cSrcweir { 754*cdf0e10cSrcweir // build edge vector 755*cdf0e10cSrcweir const B3DVector aEdge(rEdgeEnd - rEdgeStart); 756*cdf0e10cSrcweir bool bDoDistanceTestStart(false); 757*cdf0e10cSrcweir bool bDoDistanceTestEnd(false); 758*cdf0e10cSrcweir 759*cdf0e10cSrcweir if(aEdge.equalZero()) 760*cdf0e10cSrcweir { 761*cdf0e10cSrcweir // no edge, just a point. Do one of the distance tests. 762*cdf0e10cSrcweir bDoDistanceTestStart = true; 763*cdf0e10cSrcweir } 764*cdf0e10cSrcweir else 765*cdf0e10cSrcweir { 766*cdf0e10cSrcweir // calculate fCut in aEdge 767*cdf0e10cSrcweir const B3DVector aTestEdge(rTestPosition - rEdgeStart); 768*cdf0e10cSrcweir const double fScalarTestEdge(aEdge.scalar(aTestEdge)); 769*cdf0e10cSrcweir const double fScalarStartEdge(aEdge.scalar(rEdgeStart)); 770*cdf0e10cSrcweir const double fScalarEdge(aEdge.scalar(aEdge)); 771*cdf0e10cSrcweir const double fCut((fScalarTestEdge - fScalarStartEdge) / fScalarEdge); 772*cdf0e10cSrcweir const double fZero(0.0); 773*cdf0e10cSrcweir const double fOne(1.0); 774*cdf0e10cSrcweir 775*cdf0e10cSrcweir if(fTools::less(fCut, fZero)) 776*cdf0e10cSrcweir { 777*cdf0e10cSrcweir // left of rEdgeStart 778*cdf0e10cSrcweir bDoDistanceTestStart = true; 779*cdf0e10cSrcweir } 780*cdf0e10cSrcweir else if(fTools::more(fCut, fOne)) 781*cdf0e10cSrcweir { 782*cdf0e10cSrcweir // right of rEdgeEnd 783*cdf0e10cSrcweir bDoDistanceTestEnd = true; 784*cdf0e10cSrcweir } 785*cdf0e10cSrcweir else 786*cdf0e10cSrcweir { 787*cdf0e10cSrcweir // inside line [0.0 .. 1.0] 788*cdf0e10cSrcweir const B3DPoint aCutPoint(interpolate(rEdgeStart, rEdgeEnd, fCut)); 789*cdf0e10cSrcweir const B3DVector aDelta(rTestPosition - aCutPoint); 790*cdf0e10cSrcweir const double fDistanceSquare(aDelta.scalar(aDelta)); 791*cdf0e10cSrcweir 792*cdf0e10cSrcweir if(fDistanceSquare <= fDistance * fDistance * fDistance) 793*cdf0e10cSrcweir { 794*cdf0e10cSrcweir return true; 795*cdf0e10cSrcweir } 796*cdf0e10cSrcweir else 797*cdf0e10cSrcweir { 798*cdf0e10cSrcweir return false; 799*cdf0e10cSrcweir } 800*cdf0e10cSrcweir } 801*cdf0e10cSrcweir } 802*cdf0e10cSrcweir 803*cdf0e10cSrcweir if(bDoDistanceTestStart) 804*cdf0e10cSrcweir { 805*cdf0e10cSrcweir const B3DVector aDelta(rTestPosition - rEdgeStart); 806*cdf0e10cSrcweir const double fDistanceSquare(aDelta.scalar(aDelta)); 807*cdf0e10cSrcweir 808*cdf0e10cSrcweir if(fDistanceSquare <= fDistance * fDistance * fDistance) 809*cdf0e10cSrcweir { 810*cdf0e10cSrcweir return true; 811*cdf0e10cSrcweir } 812*cdf0e10cSrcweir } 813*cdf0e10cSrcweir else if(bDoDistanceTestEnd) 814*cdf0e10cSrcweir { 815*cdf0e10cSrcweir const B3DVector aDelta(rTestPosition - rEdgeEnd); 816*cdf0e10cSrcweir const double fDistanceSquare(aDelta.scalar(aDelta)); 817*cdf0e10cSrcweir 818*cdf0e10cSrcweir if(fDistanceSquare <= fDistance * fDistance * fDistance) 819*cdf0e10cSrcweir { 820*cdf0e10cSrcweir return true; 821*cdf0e10cSrcweir } 822*cdf0e10cSrcweir } 823*cdf0e10cSrcweir 824*cdf0e10cSrcweir return false; 825*cdf0e10cSrcweir } 826*cdf0e10cSrcweir 827*cdf0e10cSrcweir bool isInEpsilonRange(const B3DPolygon& rCandidate, const B3DPoint& rTestPosition, double fDistance) 828*cdf0e10cSrcweir { 829*cdf0e10cSrcweir const sal_uInt32 nPointCount(rCandidate.count()); 830*cdf0e10cSrcweir 831*cdf0e10cSrcweir if(nPointCount) 832*cdf0e10cSrcweir { 833*cdf0e10cSrcweir const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1L); 834*cdf0e10cSrcweir B3DPoint aCurrent(rCandidate.getB3DPoint(0)); 835*cdf0e10cSrcweir 836*cdf0e10cSrcweir if(nEdgeCount) 837*cdf0e10cSrcweir { 838*cdf0e10cSrcweir // edges 839*cdf0e10cSrcweir for(sal_uInt32 a(0); a < nEdgeCount; a++) 840*cdf0e10cSrcweir { 841*cdf0e10cSrcweir const sal_uInt32 nNextIndex((a + 1) % nPointCount); 842*cdf0e10cSrcweir const B3DPoint aNext(rCandidate.getB3DPoint(nNextIndex)); 843*cdf0e10cSrcweir 844*cdf0e10cSrcweir if(isInEpsilonRange(aCurrent, aNext, rTestPosition, fDistance)) 845*cdf0e10cSrcweir { 846*cdf0e10cSrcweir return true; 847*cdf0e10cSrcweir } 848*cdf0e10cSrcweir 849*cdf0e10cSrcweir // prepare next step 850*cdf0e10cSrcweir aCurrent = aNext; 851*cdf0e10cSrcweir } 852*cdf0e10cSrcweir } 853*cdf0e10cSrcweir else 854*cdf0e10cSrcweir { 855*cdf0e10cSrcweir // no edges, but points -> not closed. Check single point. Just 856*cdf0e10cSrcweir // use isInEpsilonRange with twice the same point, it handles those well 857*cdf0e10cSrcweir if(isInEpsilonRange(aCurrent, aCurrent, rTestPosition, fDistance)) 858*cdf0e10cSrcweir { 859*cdf0e10cSrcweir return true; 860*cdf0e10cSrcweir } 861*cdf0e10cSrcweir } 862*cdf0e10cSrcweir } 863*cdf0e10cSrcweir 864*cdf0e10cSrcweir return false; 865*cdf0e10cSrcweir } 866*cdf0e10cSrcweir 867*cdf0e10cSrcweir bool isInside(const B3DPolygon& rCandidate, const B3DPoint& rPoint, bool bWithBorder) 868*cdf0e10cSrcweir { 869*cdf0e10cSrcweir if(bWithBorder && isPointOnPolygon(rCandidate, rPoint, true)) 870*cdf0e10cSrcweir { 871*cdf0e10cSrcweir return true; 872*cdf0e10cSrcweir } 873*cdf0e10cSrcweir else 874*cdf0e10cSrcweir { 875*cdf0e10cSrcweir bool bRetval(false); 876*cdf0e10cSrcweir const B3DVector aPlaneNormal(rCandidate.getNormal()); 877*cdf0e10cSrcweir 878*cdf0e10cSrcweir if(!aPlaneNormal.equalZero()) 879*cdf0e10cSrcweir { 880*cdf0e10cSrcweir const sal_uInt32 nPointCount(rCandidate.count()); 881*cdf0e10cSrcweir 882*cdf0e10cSrcweir if(nPointCount) 883*cdf0e10cSrcweir { 884*cdf0e10cSrcweir B3DPoint aCurrentPoint(rCandidate.getB3DPoint(nPointCount - 1)); 885*cdf0e10cSrcweir const double fAbsX(fabs(aPlaneNormal.getX())); 886*cdf0e10cSrcweir const double fAbsY(fabs(aPlaneNormal.getY())); 887*cdf0e10cSrcweir const double fAbsZ(fabs(aPlaneNormal.getZ())); 888*cdf0e10cSrcweir 889*cdf0e10cSrcweir if(fAbsX > fAbsY && fAbsX > fAbsZ) 890*cdf0e10cSrcweir { 891*cdf0e10cSrcweir // normal points mostly in X-Direction, use YZ-Polygon projection for check 892*cdf0e10cSrcweir // x -> y, y -> z 893*cdf0e10cSrcweir for(sal_uInt32 a(0); a < nPointCount; a++) 894*cdf0e10cSrcweir { 895*cdf0e10cSrcweir const B3DPoint aPreviousPoint(aCurrentPoint); 896*cdf0e10cSrcweir aCurrentPoint = rCandidate.getB3DPoint(a); 897*cdf0e10cSrcweir 898*cdf0e10cSrcweir // cross-over in Z? 899*cdf0e10cSrcweir const bool bCompZA(fTools::more(aPreviousPoint.getZ(), rPoint.getZ())); 900*cdf0e10cSrcweir const bool bCompZB(fTools::more(aCurrentPoint.getZ(), rPoint.getZ())); 901*cdf0e10cSrcweir 902*cdf0e10cSrcweir if(bCompZA != bCompZB) 903*cdf0e10cSrcweir { 904*cdf0e10cSrcweir // cross-over in Y? 905*cdf0e10cSrcweir const bool bCompYA(fTools::more(aPreviousPoint.getY(), rPoint.getY())); 906*cdf0e10cSrcweir const bool bCompYB(fTools::more(aCurrentPoint.getY(), rPoint.getY())); 907*cdf0e10cSrcweir 908*cdf0e10cSrcweir if(bCompYA == bCompYB) 909*cdf0e10cSrcweir { 910*cdf0e10cSrcweir if(bCompYA) 911*cdf0e10cSrcweir { 912*cdf0e10cSrcweir bRetval = !bRetval; 913*cdf0e10cSrcweir } 914*cdf0e10cSrcweir } 915*cdf0e10cSrcweir else 916*cdf0e10cSrcweir { 917*cdf0e10cSrcweir const double fCompare( 918*cdf0e10cSrcweir aCurrentPoint.getY() - (aCurrentPoint.getZ() - rPoint.getZ()) * 919*cdf0e10cSrcweir (aPreviousPoint.getY() - aCurrentPoint.getY()) / 920*cdf0e10cSrcweir (aPreviousPoint.getZ() - aCurrentPoint.getZ())); 921*cdf0e10cSrcweir 922*cdf0e10cSrcweir if(fTools::more(fCompare, rPoint.getY())) 923*cdf0e10cSrcweir { 924*cdf0e10cSrcweir bRetval = !bRetval; 925*cdf0e10cSrcweir } 926*cdf0e10cSrcweir } 927*cdf0e10cSrcweir } 928*cdf0e10cSrcweir } 929*cdf0e10cSrcweir } 930*cdf0e10cSrcweir else if(fAbsY > fAbsX && fAbsY > fAbsZ) 931*cdf0e10cSrcweir { 932*cdf0e10cSrcweir // normal points mostly in Y-Direction, use XZ-Polygon projection for check 933*cdf0e10cSrcweir // x -> x, y -> z 934*cdf0e10cSrcweir for(sal_uInt32 a(0); a < nPointCount; a++) 935*cdf0e10cSrcweir { 936*cdf0e10cSrcweir const B3DPoint aPreviousPoint(aCurrentPoint); 937*cdf0e10cSrcweir aCurrentPoint = rCandidate.getB3DPoint(a); 938*cdf0e10cSrcweir 939*cdf0e10cSrcweir // cross-over in Z? 940*cdf0e10cSrcweir const bool bCompZA(fTools::more(aPreviousPoint.getZ(), rPoint.getZ())); 941*cdf0e10cSrcweir const bool bCompZB(fTools::more(aCurrentPoint.getZ(), rPoint.getZ())); 942*cdf0e10cSrcweir 943*cdf0e10cSrcweir if(bCompZA != bCompZB) 944*cdf0e10cSrcweir { 945*cdf0e10cSrcweir // cross-over in X? 946*cdf0e10cSrcweir const bool bCompXA(fTools::more(aPreviousPoint.getX(), rPoint.getX())); 947*cdf0e10cSrcweir const bool bCompXB(fTools::more(aCurrentPoint.getX(), rPoint.getX())); 948*cdf0e10cSrcweir 949*cdf0e10cSrcweir if(bCompXA == bCompXB) 950*cdf0e10cSrcweir { 951*cdf0e10cSrcweir if(bCompXA) 952*cdf0e10cSrcweir { 953*cdf0e10cSrcweir bRetval = !bRetval; 954*cdf0e10cSrcweir } 955*cdf0e10cSrcweir } 956*cdf0e10cSrcweir else 957*cdf0e10cSrcweir { 958*cdf0e10cSrcweir const double fCompare( 959*cdf0e10cSrcweir aCurrentPoint.getX() - (aCurrentPoint.getZ() - rPoint.getZ()) * 960*cdf0e10cSrcweir (aPreviousPoint.getX() - aCurrentPoint.getX()) / 961*cdf0e10cSrcweir (aPreviousPoint.getZ() - aCurrentPoint.getZ())); 962*cdf0e10cSrcweir 963*cdf0e10cSrcweir if(fTools::more(fCompare, rPoint.getX())) 964*cdf0e10cSrcweir { 965*cdf0e10cSrcweir bRetval = !bRetval; 966*cdf0e10cSrcweir } 967*cdf0e10cSrcweir } 968*cdf0e10cSrcweir } 969*cdf0e10cSrcweir } 970*cdf0e10cSrcweir } 971*cdf0e10cSrcweir else 972*cdf0e10cSrcweir { 973*cdf0e10cSrcweir // normal points mostly in Z-Direction, use XY-Polygon projection for check 974*cdf0e10cSrcweir // x -> x, y -> y 975*cdf0e10cSrcweir for(sal_uInt32 a(0); a < nPointCount; a++) 976*cdf0e10cSrcweir { 977*cdf0e10cSrcweir const B3DPoint aPreviousPoint(aCurrentPoint); 978*cdf0e10cSrcweir aCurrentPoint = rCandidate.getB3DPoint(a); 979*cdf0e10cSrcweir 980*cdf0e10cSrcweir // cross-over in Y? 981*cdf0e10cSrcweir const bool bCompYA(fTools::more(aPreviousPoint.getY(), rPoint.getY())); 982*cdf0e10cSrcweir const bool bCompYB(fTools::more(aCurrentPoint.getY(), rPoint.getY())); 983*cdf0e10cSrcweir 984*cdf0e10cSrcweir if(bCompYA != bCompYB) 985*cdf0e10cSrcweir { 986*cdf0e10cSrcweir // cross-over in X? 987*cdf0e10cSrcweir const bool bCompXA(fTools::more(aPreviousPoint.getX(), rPoint.getX())); 988*cdf0e10cSrcweir const bool bCompXB(fTools::more(aCurrentPoint.getX(), rPoint.getX())); 989*cdf0e10cSrcweir 990*cdf0e10cSrcweir if(bCompXA == bCompXB) 991*cdf0e10cSrcweir { 992*cdf0e10cSrcweir if(bCompXA) 993*cdf0e10cSrcweir { 994*cdf0e10cSrcweir bRetval = !bRetval; 995*cdf0e10cSrcweir } 996*cdf0e10cSrcweir } 997*cdf0e10cSrcweir else 998*cdf0e10cSrcweir { 999*cdf0e10cSrcweir const double fCompare( 1000*cdf0e10cSrcweir aCurrentPoint.getX() - (aCurrentPoint.getY() - rPoint.getY()) * 1001*cdf0e10cSrcweir (aPreviousPoint.getX() - aCurrentPoint.getX()) / 1002*cdf0e10cSrcweir (aPreviousPoint.getY() - aCurrentPoint.getY())); 1003*cdf0e10cSrcweir 1004*cdf0e10cSrcweir if(fTools::more(fCompare, rPoint.getX())) 1005*cdf0e10cSrcweir { 1006*cdf0e10cSrcweir bRetval = !bRetval; 1007*cdf0e10cSrcweir } 1008*cdf0e10cSrcweir } 1009*cdf0e10cSrcweir } 1010*cdf0e10cSrcweir } 1011*cdf0e10cSrcweir } 1012*cdf0e10cSrcweir } 1013*cdf0e10cSrcweir } 1014*cdf0e10cSrcweir 1015*cdf0e10cSrcweir return bRetval; 1016*cdf0e10cSrcweir } 1017*cdf0e10cSrcweir } 1018*cdf0e10cSrcweir 1019*cdf0e10cSrcweir bool isInside(const B3DPolygon& rCandidate, const B3DPolygon& rPolygon, bool bWithBorder) 1020*cdf0e10cSrcweir { 1021*cdf0e10cSrcweir const sal_uInt32 nPointCount(rPolygon.count()); 1022*cdf0e10cSrcweir 1023*cdf0e10cSrcweir for(sal_uInt32 a(0L); a < nPointCount; a++) 1024*cdf0e10cSrcweir { 1025*cdf0e10cSrcweir const B3DPoint aTestPoint(rPolygon.getB3DPoint(a)); 1026*cdf0e10cSrcweir 1027*cdf0e10cSrcweir if(!isInside(rCandidate, aTestPoint, bWithBorder)) 1028*cdf0e10cSrcweir { 1029*cdf0e10cSrcweir return false; 1030*cdf0e10cSrcweir } 1031*cdf0e10cSrcweir } 1032*cdf0e10cSrcweir 1033*cdf0e10cSrcweir return true; 1034*cdf0e10cSrcweir } 1035*cdf0e10cSrcweir 1036*cdf0e10cSrcweir bool isPointOnLine(const B3DPoint& rStart, const B3DPoint& rEnd, const B3DPoint& rCandidate, bool bWithPoints) 1037*cdf0e10cSrcweir { 1038*cdf0e10cSrcweir if(rCandidate.equal(rStart) || rCandidate.equal(rEnd)) 1039*cdf0e10cSrcweir { 1040*cdf0e10cSrcweir // candidate is in epsilon around start or end -> inside 1041*cdf0e10cSrcweir return bWithPoints; 1042*cdf0e10cSrcweir } 1043*cdf0e10cSrcweir else if(rStart.equal(rEnd)) 1044*cdf0e10cSrcweir { 1045*cdf0e10cSrcweir // start and end are equal, but candidate is outside their epsilon -> outside 1046*cdf0e10cSrcweir return false; 1047*cdf0e10cSrcweir } 1048*cdf0e10cSrcweir else 1049*cdf0e10cSrcweir { 1050*cdf0e10cSrcweir const B3DVector aEdgeVector(rEnd - rStart); 1051*cdf0e10cSrcweir const B3DVector aTestVector(rCandidate - rStart); 1052*cdf0e10cSrcweir 1053*cdf0e10cSrcweir if(areParallel(aEdgeVector, aTestVector)) 1054*cdf0e10cSrcweir { 1055*cdf0e10cSrcweir const double fZero(0.0); 1056*cdf0e10cSrcweir const double fOne(1.0); 1057*cdf0e10cSrcweir double fParamTestOnCurr(0.0); 1058*cdf0e10cSrcweir 1059*cdf0e10cSrcweir if(aEdgeVector.getX() > aEdgeVector.getY()) 1060*cdf0e10cSrcweir { 1061*cdf0e10cSrcweir if(aEdgeVector.getX() > aEdgeVector.getZ()) 1062*cdf0e10cSrcweir { 1063*cdf0e10cSrcweir // X is biggest 1064*cdf0e10cSrcweir fParamTestOnCurr = aTestVector.getX() / aEdgeVector.getX(); 1065*cdf0e10cSrcweir } 1066*cdf0e10cSrcweir else 1067*cdf0e10cSrcweir { 1068*cdf0e10cSrcweir // Z is biggest 1069*cdf0e10cSrcweir fParamTestOnCurr = aTestVector.getZ() / aEdgeVector.getZ(); 1070*cdf0e10cSrcweir } 1071*cdf0e10cSrcweir } 1072*cdf0e10cSrcweir else 1073*cdf0e10cSrcweir { 1074*cdf0e10cSrcweir if(aEdgeVector.getY() > aEdgeVector.getZ()) 1075*cdf0e10cSrcweir { 1076*cdf0e10cSrcweir // Y is biggest 1077*cdf0e10cSrcweir fParamTestOnCurr = aTestVector.getY() / aEdgeVector.getY(); 1078*cdf0e10cSrcweir } 1079*cdf0e10cSrcweir else 1080*cdf0e10cSrcweir { 1081*cdf0e10cSrcweir // Z is biggest 1082*cdf0e10cSrcweir fParamTestOnCurr = aTestVector.getZ() / aEdgeVector.getZ(); 1083*cdf0e10cSrcweir } 1084*cdf0e10cSrcweir } 1085*cdf0e10cSrcweir 1086*cdf0e10cSrcweir if(fTools::more(fParamTestOnCurr, fZero) && fTools::less(fParamTestOnCurr, fOne)) 1087*cdf0e10cSrcweir { 1088*cdf0e10cSrcweir return true; 1089*cdf0e10cSrcweir } 1090*cdf0e10cSrcweir } 1091*cdf0e10cSrcweir 1092*cdf0e10cSrcweir return false; 1093*cdf0e10cSrcweir } 1094*cdf0e10cSrcweir } 1095*cdf0e10cSrcweir 1096*cdf0e10cSrcweir bool isPointOnPolygon(const B3DPolygon& rCandidate, const B3DPoint& rPoint, bool bWithPoints) 1097*cdf0e10cSrcweir { 1098*cdf0e10cSrcweir const sal_uInt32 nPointCount(rCandidate.count()); 1099*cdf0e10cSrcweir 1100*cdf0e10cSrcweir if(nPointCount > 1L) 1101*cdf0e10cSrcweir { 1102*cdf0e10cSrcweir const sal_uInt32 nLoopCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1L); 1103*cdf0e10cSrcweir B3DPoint aCurrentPoint(rCandidate.getB3DPoint(0)); 1104*cdf0e10cSrcweir 1105*cdf0e10cSrcweir for(sal_uInt32 a(0); a < nLoopCount; a++) 1106*cdf0e10cSrcweir { 1107*cdf0e10cSrcweir const B3DPoint aNextPoint(rCandidate.getB3DPoint((a + 1) % nPointCount)); 1108*cdf0e10cSrcweir 1109*cdf0e10cSrcweir if(isPointOnLine(aCurrentPoint, aNextPoint, rPoint, bWithPoints)) 1110*cdf0e10cSrcweir { 1111*cdf0e10cSrcweir return true; 1112*cdf0e10cSrcweir } 1113*cdf0e10cSrcweir 1114*cdf0e10cSrcweir aCurrentPoint = aNextPoint; 1115*cdf0e10cSrcweir } 1116*cdf0e10cSrcweir } 1117*cdf0e10cSrcweir else if(nPointCount && bWithPoints) 1118*cdf0e10cSrcweir { 1119*cdf0e10cSrcweir return rPoint.equal(rCandidate.getB3DPoint(0)); 1120*cdf0e10cSrcweir } 1121*cdf0e10cSrcweir 1122*cdf0e10cSrcweir return false; 1123*cdf0e10cSrcweir } 1124*cdf0e10cSrcweir 1125*cdf0e10cSrcweir bool getCutBetweenLineAndPlane(const B3DVector& rPlaneNormal, const B3DPoint& rPlanePoint, const B3DPoint& rEdgeStart, const B3DPoint& rEdgeEnd, double& fCut) 1126*cdf0e10cSrcweir { 1127*cdf0e10cSrcweir if(!rPlaneNormal.equalZero() && !rEdgeStart.equal(rEdgeEnd)) 1128*cdf0e10cSrcweir { 1129*cdf0e10cSrcweir const B3DVector aTestEdge(rEdgeEnd - rEdgeStart); 1130*cdf0e10cSrcweir const double fScalarEdge(rPlaneNormal.scalar(aTestEdge)); 1131*cdf0e10cSrcweir 1132*cdf0e10cSrcweir if(!fTools::equalZero(fScalarEdge)) 1133*cdf0e10cSrcweir { 1134*cdf0e10cSrcweir const B3DVector aCompareEdge(rPlanePoint - rEdgeStart); 1135*cdf0e10cSrcweir const double fScalarCompare(rPlaneNormal.scalar(aCompareEdge)); 1136*cdf0e10cSrcweir 1137*cdf0e10cSrcweir fCut = fScalarCompare / fScalarEdge; 1138*cdf0e10cSrcweir return true; 1139*cdf0e10cSrcweir } 1140*cdf0e10cSrcweir } 1141*cdf0e10cSrcweir 1142*cdf0e10cSrcweir return false; 1143*cdf0e10cSrcweir } 1144*cdf0e10cSrcweir 1145*cdf0e10cSrcweir bool getCutBetweenLineAndPolygon(const B3DPolygon& rCandidate, const B3DPoint& rEdgeStart, const B3DPoint& rEdgeEnd, double& fCut) 1146*cdf0e10cSrcweir { 1147*cdf0e10cSrcweir const sal_uInt32 nPointCount(rCandidate.count()); 1148*cdf0e10cSrcweir 1149*cdf0e10cSrcweir if(nPointCount > 2 && !rEdgeStart.equal(rEdgeEnd)) 1150*cdf0e10cSrcweir { 1151*cdf0e10cSrcweir const B3DVector aPlaneNormal(rCandidate.getNormal()); 1152*cdf0e10cSrcweir 1153*cdf0e10cSrcweir if(!aPlaneNormal.equalZero()) 1154*cdf0e10cSrcweir { 1155*cdf0e10cSrcweir const B3DPoint aPointOnPlane(rCandidate.getB3DPoint(0)); 1156*cdf0e10cSrcweir 1157*cdf0e10cSrcweir return getCutBetweenLineAndPlane(aPlaneNormal, aPointOnPlane, rEdgeStart, rEdgeEnd, fCut); 1158*cdf0e10cSrcweir } 1159*cdf0e10cSrcweir } 1160*cdf0e10cSrcweir 1161*cdf0e10cSrcweir return false; 1162*cdf0e10cSrcweir } 1163*cdf0e10cSrcweir 1164*cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////// 1165*cdf0e10cSrcweir // comparators with tolerance for 3D Polygons 1166*cdf0e10cSrcweir 1167*cdf0e10cSrcweir bool equal(const B3DPolygon& rCandidateA, const B3DPolygon& rCandidateB, const double& rfSmallValue) 1168*cdf0e10cSrcweir { 1169*cdf0e10cSrcweir const sal_uInt32 nPointCount(rCandidateA.count()); 1170*cdf0e10cSrcweir 1171*cdf0e10cSrcweir if(nPointCount != rCandidateB.count()) 1172*cdf0e10cSrcweir return false; 1173*cdf0e10cSrcweir 1174*cdf0e10cSrcweir const bool bClosed(rCandidateA.isClosed()); 1175*cdf0e10cSrcweir 1176*cdf0e10cSrcweir if(bClosed != rCandidateB.isClosed()) 1177*cdf0e10cSrcweir return false; 1178*cdf0e10cSrcweir 1179*cdf0e10cSrcweir for(sal_uInt32 a(0); a < nPointCount; a++) 1180*cdf0e10cSrcweir { 1181*cdf0e10cSrcweir const B3DPoint aPoint(rCandidateA.getB3DPoint(a)); 1182*cdf0e10cSrcweir 1183*cdf0e10cSrcweir if(!aPoint.equal(rCandidateB.getB3DPoint(a), rfSmallValue)) 1184*cdf0e10cSrcweir return false; 1185*cdf0e10cSrcweir } 1186*cdf0e10cSrcweir 1187*cdf0e10cSrcweir return true; 1188*cdf0e10cSrcweir } 1189*cdf0e10cSrcweir 1190*cdf0e10cSrcweir bool equal(const B3DPolygon& rCandidateA, const B3DPolygon& rCandidateB) 1191*cdf0e10cSrcweir { 1192*cdf0e10cSrcweir const double fSmallValue(fTools::getSmallValue()); 1193*cdf0e10cSrcweir 1194*cdf0e10cSrcweir return equal(rCandidateA, rCandidateB, fSmallValue); 1195*cdf0e10cSrcweir } 1196*cdf0e10cSrcweir 1197*cdf0e10cSrcweir // snap points of horizontal or vertical edges to discrete values 1198*cdf0e10cSrcweir B3DPolygon snapPointsOfHorizontalOrVerticalEdges(const B3DPolygon& rCandidate) 1199*cdf0e10cSrcweir { 1200*cdf0e10cSrcweir const sal_uInt32 nPointCount(rCandidate.count()); 1201*cdf0e10cSrcweir 1202*cdf0e10cSrcweir if(nPointCount > 1) 1203*cdf0e10cSrcweir { 1204*cdf0e10cSrcweir // Start by copying the source polygon to get a writeable copy. The closed state is 1205*cdf0e10cSrcweir // copied by aRetval's initialisation, too, so no need to copy it in this method 1206*cdf0e10cSrcweir B3DPolygon aRetval(rCandidate); 1207*cdf0e10cSrcweir 1208*cdf0e10cSrcweir // prepare geometry data. Get rounded from original 1209*cdf0e10cSrcweir B3ITuple aPrevTuple(basegfx::fround(rCandidate.getB3DPoint(nPointCount - 1))); 1210*cdf0e10cSrcweir B3DPoint aCurrPoint(rCandidate.getB3DPoint(0)); 1211*cdf0e10cSrcweir B3ITuple aCurrTuple(basegfx::fround(aCurrPoint)); 1212*cdf0e10cSrcweir 1213*cdf0e10cSrcweir // loop over all points. This will also snap the implicit closing edge 1214*cdf0e10cSrcweir // even when not closed, but that's no problem here 1215*cdf0e10cSrcweir for(sal_uInt32 a(0); a < nPointCount; a++) 1216*cdf0e10cSrcweir { 1217*cdf0e10cSrcweir // get next point. Get rounded from original 1218*cdf0e10cSrcweir const bool bLastRun(a + 1 == nPointCount); 1219*cdf0e10cSrcweir const sal_uInt32 nNextIndex(bLastRun ? 0 : a + 1); 1220*cdf0e10cSrcweir const B3DPoint aNextPoint(rCandidate.getB3DPoint(nNextIndex)); 1221*cdf0e10cSrcweir const B3ITuple aNextTuple(basegfx::fround(aNextPoint)); 1222*cdf0e10cSrcweir 1223*cdf0e10cSrcweir // get the states 1224*cdf0e10cSrcweir const bool bPrevVertical(aPrevTuple.getX() == aCurrTuple.getX()); 1225*cdf0e10cSrcweir const bool bNextVertical(aNextTuple.getX() == aCurrTuple.getX()); 1226*cdf0e10cSrcweir const bool bPrevHorizontal(aPrevTuple.getY() == aCurrTuple.getY()); 1227*cdf0e10cSrcweir const bool bNextHorizontal(aNextTuple.getY() == aCurrTuple.getY()); 1228*cdf0e10cSrcweir const bool bSnapX(bPrevVertical || bNextVertical); 1229*cdf0e10cSrcweir const bool bSnapY(bPrevHorizontal || bNextHorizontal); 1230*cdf0e10cSrcweir 1231*cdf0e10cSrcweir if(bSnapX || bSnapY) 1232*cdf0e10cSrcweir { 1233*cdf0e10cSrcweir const B3DPoint aSnappedPoint( 1234*cdf0e10cSrcweir bSnapX ? aCurrTuple.getX() : aCurrPoint.getX(), 1235*cdf0e10cSrcweir bSnapY ? aCurrTuple.getY() : aCurrPoint.getY(), 1236*cdf0e10cSrcweir aCurrPoint.getZ()); 1237*cdf0e10cSrcweir 1238*cdf0e10cSrcweir aRetval.setB3DPoint(a, aSnappedPoint); 1239*cdf0e10cSrcweir } 1240*cdf0e10cSrcweir 1241*cdf0e10cSrcweir // prepare next point 1242*cdf0e10cSrcweir if(!bLastRun) 1243*cdf0e10cSrcweir { 1244*cdf0e10cSrcweir aPrevTuple = aCurrTuple; 1245*cdf0e10cSrcweir aCurrPoint = aNextPoint; 1246*cdf0e10cSrcweir aCurrTuple = aNextTuple; 1247*cdf0e10cSrcweir } 1248*cdf0e10cSrcweir } 1249*cdf0e10cSrcweir 1250*cdf0e10cSrcweir return aRetval; 1251*cdf0e10cSrcweir } 1252*cdf0e10cSrcweir else 1253*cdf0e10cSrcweir { 1254*cdf0e10cSrcweir return rCandidate; 1255*cdf0e10cSrcweir } 1256*cdf0e10cSrcweir } 1257*cdf0e10cSrcweir 1258*cdf0e10cSrcweir } // end of namespace tools 1259*cdf0e10cSrcweir } // end of namespace basegfx 1260*cdf0e10cSrcweir 1261*cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 1262*cdf0e10cSrcweir 1263*cdf0e10cSrcweir // eof 1264