merged tag ooo/OOO330_m14
[LibreOffice.git] / basegfx / source / polygon / b2dpolypolygontools.cxx
blobdcfa34f93c02c40758f4a88af743dd13f35bca94
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_basegfx.hxx"
30 #include <basegfx/polygon/b2dpolypolygontools.hxx>
31 #include <osl/diagnose.h>
32 #include <basegfx/polygon/b2dpolypolygon.hxx>
33 #include <basegfx/polygon/b2dpolygon.hxx>
34 #include <basegfx/polygon/b2dpolygontools.hxx>
35 #include <basegfx/numeric/ftools.hxx>
36 #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
38 #include <numeric>
40 //////////////////////////////////////////////////////////////////////////////
42 namespace basegfx
44 namespace tools
46 B2DPolyPolygon correctOrientations(const B2DPolyPolygon& rCandidate)
48 B2DPolyPolygon aRetval(rCandidate);
49 const sal_uInt32 nCount(aRetval.count());
51 for(sal_uInt32 a(0L); a < nCount; a++)
53 const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
54 const B2VectorOrientation aOrientation(tools::getOrientation(aCandidate));
55 sal_uInt32 nDepth(0L);
57 for(sal_uInt32 b(0L); b < nCount; b++)
59 if(b != a)
61 const B2DPolygon aCompare(rCandidate.getB2DPolygon(b));
63 if(tools::isInside(aCompare, aCandidate, true))
65 nDepth++;
70 const bool bShallBeHole(1L == (nDepth & 0x00000001));
71 const bool bIsHole(ORIENTATION_NEGATIVE == aOrientation);
73 if(bShallBeHole != bIsHole && ORIENTATION_NEUTRAL != aOrientation)
75 B2DPolygon aFlipped(aCandidate);
76 aFlipped.flip();
77 aRetval.setB2DPolygon(a, aFlipped);
81 return aRetval;
84 B2DPolyPolygon correctOutmostPolygon(const B2DPolyPolygon& rCandidate)
86 const sal_uInt32 nCount(rCandidate.count());
88 if(nCount > 1L)
90 for(sal_uInt32 a(0L); a < nCount; a++)
92 const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
93 sal_uInt32 nDepth(0L);
95 for(sal_uInt32 b(0L); b < nCount; b++)
97 if(b != a)
99 const B2DPolygon aCompare(rCandidate.getB2DPolygon(b));
101 if(tools::isInside(aCompare, aCandidate, true))
103 nDepth++;
108 if(!nDepth)
110 B2DPolyPolygon aRetval(rCandidate);
112 if(a != 0L)
114 // exchange polygon a and polygon 0L
115 aRetval.setB2DPolygon(0L, aCandidate);
116 aRetval.setB2DPolygon(a, rCandidate.getB2DPolygon(0L));
119 // exit
120 return aRetval;
125 return rCandidate;
128 B2DPolyPolygon adaptiveSubdivideByDistance(const B2DPolyPolygon& rCandidate, double fDistanceBound)
130 if(rCandidate.areControlPointsUsed())
132 const sal_uInt32 nPolygonCount(rCandidate.count());
133 B2DPolyPolygon aRetval;
135 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
137 const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
139 if(aCandidate.areControlPointsUsed())
141 aRetval.append(tools::adaptiveSubdivideByDistance(aCandidate, fDistanceBound));
143 else
145 aRetval.append(aCandidate);
149 return aRetval;
151 else
153 return rCandidate;
157 B2DPolyPolygon adaptiveSubdivideByAngle(const B2DPolyPolygon& rCandidate, double fAngleBound)
159 if(rCandidate.areControlPointsUsed())
161 const sal_uInt32 nPolygonCount(rCandidate.count());
162 B2DPolyPolygon aRetval;
164 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
166 const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
168 if(aCandidate.areControlPointsUsed())
170 aRetval.append(tools::adaptiveSubdivideByAngle(aCandidate, fAngleBound));
172 else
174 aRetval.append(aCandidate);
178 return aRetval;
180 else
182 return rCandidate;
186 B2DPolyPolygon adaptiveSubdivideByCount(const B2DPolyPolygon& rCandidate, sal_uInt32 nCount)
188 if(rCandidate.areControlPointsUsed())
190 const sal_uInt32 nPolygonCount(rCandidate.count());
191 B2DPolyPolygon aRetval;
193 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
195 const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
197 if(aCandidate.areControlPointsUsed())
199 aRetval.append(tools::adaptiveSubdivideByCount(aCandidate, nCount));
201 else
203 aRetval.append(aCandidate);
207 return aRetval;
209 else
211 return rCandidate;
215 bool isInside(const B2DPolyPolygon& rCandidate, const B2DPoint& rPoint, bool bWithBorder)
217 const sal_uInt32 nPolygonCount(rCandidate.count());
219 if(1L == nPolygonCount)
221 return isInside(rCandidate.getB2DPolygon(0L), rPoint, bWithBorder);
223 else
225 sal_Int32 nInsideCount(0L);
227 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
229 const B2DPolygon aPolygon(rCandidate.getB2DPolygon(a));
230 const bool bInside(isInside(aPolygon, rPoint, bWithBorder));
232 if(bInside)
234 nInsideCount++;
238 return (nInsideCount % 2L);
242 B2DRange getRangeWithControlPoints(const B2DPolyPolygon& rCandidate)
244 B2DRange aRetval;
245 const sal_uInt32 nPolygonCount(rCandidate.count());
247 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
249 B2DPolygon aCandidate = rCandidate.getB2DPolygon(a);
250 aRetval.expand(tools::getRangeWithControlPoints(aCandidate));
253 return aRetval;
256 B2DRange getRange(const B2DPolyPolygon& rCandidate)
258 B2DRange aRetval;
259 const sal_uInt32 nPolygonCount(rCandidate.count());
261 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
263 B2DPolygon aCandidate = rCandidate.getB2DPolygon(a);
264 aRetval.expand(tools::getRange(aCandidate));
267 return aRetval;
270 void applyLineDashing(const B2DPolyPolygon& rCandidate, const ::std::vector<double>& rDotDashArray, B2DPolyPolygon* pLineTarget, B2DPolyPolygon* pGapTarget, double fFullDashDotLen)
272 if(0.0 == fFullDashDotLen && rDotDashArray.size())
274 // calculate fFullDashDotLen from rDotDashArray
275 fFullDashDotLen = ::std::accumulate(rDotDashArray.begin(), rDotDashArray.end(), 0.0);
278 if(rCandidate.count() && fFullDashDotLen > 0.0)
280 B2DPolyPolygon aLineTarget, aGapTarget;
282 for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
284 const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
286 applyLineDashing(
287 aCandidate,
288 rDotDashArray,
289 pLineTarget ? &aLineTarget : 0,
290 pGapTarget ? &aGapTarget : 0,
291 fFullDashDotLen);
293 if(pLineTarget)
295 pLineTarget->append(aLineTarget);
298 if(pGapTarget)
300 pGapTarget->append(aGapTarget);
306 bool isInEpsilonRange(const B2DPolyPolygon& rCandidate, const B2DPoint& rTestPosition, double fDistance)
308 const sal_uInt32 nPolygonCount(rCandidate.count());
310 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
312 B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
314 if(isInEpsilonRange(aCandidate, rTestPosition, fDistance))
316 return true;
320 return false;
323 B3DPolyPolygon createB3DPolyPolygonFromB2DPolyPolygon(const B2DPolyPolygon& rCandidate, double fZCoordinate)
325 const sal_uInt32 nPolygonCount(rCandidate.count());
326 B3DPolyPolygon aRetval;
328 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
330 B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
332 aRetval.append(createB3DPolygonFromB2DPolygon(aCandidate, fZCoordinate));
335 return aRetval;
338 B2DPolyPolygon createB2DPolyPolygonFromB3DPolyPolygon(const B3DPolyPolygon& rCandidate, const B3DHomMatrix& rMat)
340 const sal_uInt32 nPolygonCount(rCandidate.count());
341 B2DPolyPolygon aRetval;
343 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
345 B3DPolygon aCandidate(rCandidate.getB3DPolygon(a));
347 aRetval.append(createB2DPolygonFromB3DPolygon(aCandidate, rMat));
350 return aRetval;
353 double getSmallestDistancePointToPolyPolygon(const B2DPolyPolygon& rCandidate, const B2DPoint& rTestPoint, sal_uInt32& rPolygonIndex, sal_uInt32& rEdgeIndex, double& rCut)
355 double fRetval(DBL_MAX);
356 const double fZero(0.0);
357 const sal_uInt32 nPolygonCount(rCandidate.count());
359 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
361 const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
362 sal_uInt32 nNewEdgeIndex;
363 double fNewCut;
364 const double fNewDistance(getSmallestDistancePointToPolygon(aCandidate, rTestPoint, nNewEdgeIndex, fNewCut));
366 if(DBL_MAX == fRetval || fNewDistance < fRetval)
368 fRetval = fNewDistance;
369 rPolygonIndex = a;
370 rEdgeIndex = nNewEdgeIndex;
371 rCut = fNewCut;
373 if(fTools::equal(fRetval, fZero))
375 // already found zero distance, cannot get better. Ensure numerical zero value and end loop.
376 fRetval = 0.0;
377 break;
382 return fRetval;
385 B2DPolyPolygon distort(const B2DPolyPolygon& rCandidate, const B2DRange& rOriginal, const B2DPoint& rTopLeft, const B2DPoint& rTopRight, const B2DPoint& rBottomLeft, const B2DPoint& rBottomRight)
387 const sal_uInt32 nPolygonCount(rCandidate.count());
388 B2DPolyPolygon aRetval;
390 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
392 const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
394 aRetval.append(distort(aCandidate, rOriginal, rTopLeft, rTopRight, rBottomLeft, rBottomRight));
397 return aRetval;
400 B2DPolyPolygon rotateAroundPoint(const B2DPolyPolygon& rCandidate, const B2DPoint& rCenter, double fAngle)
402 const sal_uInt32 nPolygonCount(rCandidate.count());
403 B2DPolyPolygon aRetval;
405 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
407 const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
409 aRetval.append(rotateAroundPoint(aCandidate, rCenter, fAngle));
412 return aRetval;
415 B2DPolyPolygon expandToCurve(const B2DPolyPolygon& rCandidate)
417 const sal_uInt32 nPolygonCount(rCandidate.count());
418 B2DPolyPolygon aRetval;
420 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
422 const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
424 aRetval.append(expandToCurve(aCandidate));
427 return aRetval;
430 B2DPolyPolygon setContinuity(const B2DPolyPolygon& rCandidate, B2VectorContinuity eContinuity)
432 if(rCandidate.areControlPointsUsed())
434 const sal_uInt32 nPolygonCount(rCandidate.count());
435 B2DPolyPolygon aRetval;
437 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
439 const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
441 aRetval.append(setContinuity(aCandidate, eContinuity));
444 return aRetval;
446 else
448 return rCandidate;
452 B2DPolyPolygon growInNormalDirection(const B2DPolyPolygon& rCandidate, double fValue)
454 if(0.0 != fValue)
456 B2DPolyPolygon aRetval;
458 for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
460 aRetval.append(growInNormalDirection(rCandidate.getB2DPolygon(a), fValue));
463 return aRetval;
465 else
467 return rCandidate;
471 void correctGrowShrinkPolygonPair(B2DPolyPolygon& /*rOriginal*/, B2DPolyPolygon& /*rGrown*/)
475 B2DPolyPolygon reSegmentPolyPolygon(const B2DPolyPolygon& rCandidate, sal_uInt32 nSegments)
477 B2DPolyPolygon aRetval;
479 for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
481 aRetval.append(reSegmentPolygon(rCandidate.getB2DPolygon(a), nSegments));
484 return aRetval;
487 B2DPolyPolygon interpolate(const B2DPolyPolygon& rOld1, const B2DPolyPolygon& rOld2, double t)
489 OSL_ENSURE(rOld1.count() == rOld2.count(), "B2DPolyPolygon interpolate: Different geometry (!)");
490 B2DPolyPolygon aRetval;
492 for(sal_uInt32 a(0L); a < rOld1.count(); a++)
494 aRetval.append(interpolate(rOld1.getB2DPolygon(a), rOld2.getB2DPolygon(a), t));
497 return aRetval;
500 bool isRectangle( const B2DPolyPolygon& rPoly )
502 // exclude some cheap cases first
503 if( rPoly.count() != 1 )
504 return false;
506 return isRectangle( rPoly.getB2DPolygon(0) );
509 // #i76891#
510 B2DPolyPolygon simplifyCurveSegments(const B2DPolyPolygon& rCandidate)
512 if(rCandidate.areControlPointsUsed())
514 B2DPolyPolygon aRetval;
516 for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
518 aRetval.append(simplifyCurveSegments(rCandidate.getB2DPolygon(a)));
521 return aRetval;
523 else
525 return rCandidate;
529 B2DPolyPolygon reSegmentPolyPolygonEdges(const B2DPolyPolygon& rCandidate, sal_uInt32 nSubEdges, bool bHandleCurvedEdges, bool bHandleStraightEdges)
531 B2DPolyPolygon aRetval;
533 for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
535 aRetval.append(reSegmentPolygonEdges(rCandidate.getB2DPolygon(a), nSubEdges, bHandleCurvedEdges, bHandleStraightEdges));
538 return aRetval;
541 //////////////////////////////////////////////////////////////////////
542 // comparators with tolerance for 2D PolyPolygons
544 bool equal(const B2DPolyPolygon& rCandidateA, const B2DPolyPolygon& rCandidateB, const double& rfSmallValue)
546 const sal_uInt32 nPolygonCount(rCandidateA.count());
548 if(nPolygonCount != rCandidateB.count())
549 return false;
551 for(sal_uInt32 a(0); a < nPolygonCount; a++)
553 const B2DPolygon aCandidate(rCandidateA.getB2DPolygon(a));
555 if(!equal(aCandidate, rCandidateB.getB2DPolygon(a), rfSmallValue))
556 return false;
559 return true;
562 bool equal(const B2DPolyPolygon& rCandidateA, const B2DPolyPolygon& rCandidateB)
564 const double fSmallValue(fTools::getSmallValue());
566 return equal(rCandidateA, rCandidateB, fSmallValue);
569 B2DPolyPolygon snapPointsOfHorizontalOrVerticalEdges(const B2DPolyPolygon& rCandidate)
571 B2DPolyPolygon aRetval;
573 for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
575 aRetval.append(snapPointsOfHorizontalOrVerticalEdges(rCandidate.getB2DPolygon(a)));
578 return aRetval;
581 } // end of namespace tools
582 } // end of namespace basegfx
584 //////////////////////////////////////////////////////////////////////////////
585 // eof