merge the formfield patch from ooo-build
[ooovba.git] / basegfx / source / polygon / b2dpolypolygontools.cxx
blobbf2525a718806b857b582b8c585553752c3c6a56
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: b2dpolypolygontools.cxx,v $
10 * $Revision: 1.19.4.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_basegfx.hxx"
33 #include <basegfx/polygon/b2dpolypolygontools.hxx>
34 #include <osl/diagnose.h>
35 #include <basegfx/polygon/b2dpolypolygon.hxx>
36 #include <basegfx/polygon/b2dpolygon.hxx>
37 #include <basegfx/polygon/b2dpolygontools.hxx>
38 #include <basegfx/numeric/ftools.hxx>
39 #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
41 #include <numeric>
43 //////////////////////////////////////////////////////////////////////////////
45 namespace basegfx
47 namespace tools
49 B2DPolyPolygon correctOrientations(const B2DPolyPolygon& rCandidate)
51 B2DPolyPolygon aRetval(rCandidate);
52 const sal_uInt32 nCount(aRetval.count());
54 for(sal_uInt32 a(0L); a < nCount; a++)
56 const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
57 const B2VectorOrientation aOrientation(tools::getOrientation(aCandidate));
58 sal_uInt32 nDepth(0L);
60 for(sal_uInt32 b(0L); b < nCount; b++)
62 if(b != a)
64 const B2DPolygon aCompare(rCandidate.getB2DPolygon(b));
66 if(tools::isInside(aCompare, aCandidate, true))
68 nDepth++;
73 const bool bShallBeHole(1L == (nDepth & 0x00000001));
74 const bool bIsHole(ORIENTATION_NEGATIVE == aOrientation);
76 if(bShallBeHole != bIsHole && ORIENTATION_NEUTRAL != aOrientation)
78 B2DPolygon aFlipped(aCandidate);
79 aFlipped.flip();
80 aRetval.setB2DPolygon(a, aFlipped);
84 return aRetval;
87 B2DPolyPolygon correctOutmostPolygon(const B2DPolyPolygon& rCandidate)
89 const sal_uInt32 nCount(rCandidate.count());
91 if(nCount > 1L)
93 for(sal_uInt32 a(0L); a < nCount; a++)
95 const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
96 sal_uInt32 nDepth(0L);
98 for(sal_uInt32 b(0L); b < nCount; b++)
100 if(b != a)
102 const B2DPolygon aCompare(rCandidate.getB2DPolygon(b));
104 if(tools::isInside(aCompare, aCandidate, true))
106 nDepth++;
111 if(!nDepth)
113 B2DPolyPolygon aRetval(rCandidate);
115 if(a != 0L)
117 // exchange polygon a and polygon 0L
118 aRetval.setB2DPolygon(0L, aCandidate);
119 aRetval.setB2DPolygon(a, rCandidate.getB2DPolygon(0L));
122 // exit
123 return aRetval;
128 return rCandidate;
131 B2DPolyPolygon adaptiveSubdivideByDistance(const B2DPolyPolygon& rCandidate, double fDistanceBound)
133 if(rCandidate.areControlPointsUsed())
135 const sal_uInt32 nPolygonCount(rCandidate.count());
136 B2DPolyPolygon aRetval;
138 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
140 const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
142 if(aCandidate.areControlPointsUsed())
144 aRetval.append(tools::adaptiveSubdivideByDistance(aCandidate, fDistanceBound));
146 else
148 aRetval.append(aCandidate);
152 return aRetval;
154 else
156 return rCandidate;
160 B2DPolyPolygon adaptiveSubdivideByAngle(const B2DPolyPolygon& rCandidate, double fAngleBound)
162 if(rCandidate.areControlPointsUsed())
164 const sal_uInt32 nPolygonCount(rCandidate.count());
165 B2DPolyPolygon aRetval;
167 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
169 const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
171 if(aCandidate.areControlPointsUsed())
173 aRetval.append(tools::adaptiveSubdivideByAngle(aCandidate, fAngleBound));
175 else
177 aRetval.append(aCandidate);
181 return aRetval;
183 else
185 return rCandidate;
189 B2DPolyPolygon adaptiveSubdivideByCount(const B2DPolyPolygon& rCandidate, sal_uInt32 nCount)
191 if(rCandidate.areControlPointsUsed())
193 const sal_uInt32 nPolygonCount(rCandidate.count());
194 B2DPolyPolygon aRetval;
196 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
198 const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
200 if(aCandidate.areControlPointsUsed())
202 aRetval.append(tools::adaptiveSubdivideByCount(aCandidate, nCount));
204 else
206 aRetval.append(aCandidate);
210 return aRetval;
212 else
214 return rCandidate;
218 bool isInside(const B2DPolyPolygon& rCandidate, const B2DPoint& rPoint, bool bWithBorder)
220 const sal_uInt32 nPolygonCount(rCandidate.count());
222 if(1L == nPolygonCount)
224 return isInside(rCandidate.getB2DPolygon(0L), rPoint, bWithBorder);
226 else
228 sal_Int32 nInsideCount(0L);
230 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
232 const B2DPolygon aPolygon(rCandidate.getB2DPolygon(a));
233 const bool bInside(isInside(aPolygon, rPoint, bWithBorder));
235 if(bInside)
237 nInsideCount++;
241 return (nInsideCount % 2L);
245 B2DRange getRangeWithControlPoints(const B2DPolyPolygon& rCandidate)
247 B2DRange aRetval;
248 const sal_uInt32 nPolygonCount(rCandidate.count());
250 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
252 B2DPolygon aCandidate = rCandidate.getB2DPolygon(a);
253 aRetval.expand(tools::getRangeWithControlPoints(aCandidate));
256 return aRetval;
259 B2DRange getRange(const B2DPolyPolygon& rCandidate)
261 B2DRange aRetval;
262 const sal_uInt32 nPolygonCount(rCandidate.count());
264 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
266 B2DPolygon aCandidate = rCandidate.getB2DPolygon(a);
267 aRetval.expand(tools::getRange(aCandidate));
270 return aRetval;
273 void applyLineDashing(const B2DPolyPolygon& rCandidate, const ::std::vector<double>& rDotDashArray, B2DPolyPolygon* pLineTarget, B2DPolyPolygon* pGapTarget, double fFullDashDotLen)
275 if(0.0 == fFullDashDotLen && rDotDashArray.size())
277 // calculate fFullDashDotLen from rDotDashArray
278 fFullDashDotLen = ::std::accumulate(rDotDashArray.begin(), rDotDashArray.end(), 0.0);
281 if(rCandidate.count() && fFullDashDotLen > 0.0)
283 B2DPolyPolygon aLineTarget, aGapTarget;
285 for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
287 const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
289 applyLineDashing(
290 aCandidate,
291 rDotDashArray,
292 pLineTarget ? &aLineTarget : 0,
293 pGapTarget ? &aGapTarget : 0,
294 fFullDashDotLen);
296 if(pLineTarget)
298 pLineTarget->append(aLineTarget);
301 if(pGapTarget)
303 pGapTarget->append(aGapTarget);
309 bool isInEpsilonRange(const B2DPolyPolygon& rCandidate, const B2DPoint& rTestPosition, double fDistance)
311 const sal_uInt32 nPolygonCount(rCandidate.count());
313 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
315 B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
317 if(isInEpsilonRange(aCandidate, rTestPosition, fDistance))
319 return true;
323 return false;
326 B3DPolyPolygon createB3DPolyPolygonFromB2DPolyPolygon(const B2DPolyPolygon& rCandidate, double fZCoordinate)
328 const sal_uInt32 nPolygonCount(rCandidate.count());
329 B3DPolyPolygon aRetval;
331 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
333 B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
335 aRetval.append(createB3DPolygonFromB2DPolygon(aCandidate, fZCoordinate));
338 return aRetval;
341 B2DPolyPolygon createB2DPolyPolygonFromB3DPolyPolygon(const B3DPolyPolygon& rCandidate, const B3DHomMatrix& rMat)
343 const sal_uInt32 nPolygonCount(rCandidate.count());
344 B2DPolyPolygon aRetval;
346 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
348 B3DPolygon aCandidate(rCandidate.getB3DPolygon(a));
350 aRetval.append(createB2DPolygonFromB3DPolygon(aCandidate, rMat));
353 return aRetval;
356 double getSmallestDistancePointToPolyPolygon(const B2DPolyPolygon& rCandidate, const B2DPoint& rTestPoint, sal_uInt32& rPolygonIndex, sal_uInt32& rEdgeIndex, double& rCut)
358 double fRetval(DBL_MAX);
359 const double fZero(0.0);
360 const sal_uInt32 nPolygonCount(rCandidate.count());
362 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
364 const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
365 sal_uInt32 nNewEdgeIndex;
366 double fNewCut;
367 const double fNewDistance(getSmallestDistancePointToPolygon(aCandidate, rTestPoint, nNewEdgeIndex, fNewCut));
369 if(DBL_MAX == fRetval || fNewDistance < fRetval)
371 fRetval = fNewDistance;
372 rPolygonIndex = a;
373 rEdgeIndex = nNewEdgeIndex;
374 rCut = fNewCut;
376 if(fTools::equal(fRetval, fZero))
378 // already found zero distance, cannot get better. Ensure numerical zero value and end loop.
379 fRetval = 0.0;
380 break;
385 return fRetval;
388 B2DPolyPolygon distort(const B2DPolyPolygon& rCandidate, const B2DRange& rOriginal, const B2DPoint& rTopLeft, const B2DPoint& rTopRight, const B2DPoint& rBottomLeft, const B2DPoint& rBottomRight)
390 const sal_uInt32 nPolygonCount(rCandidate.count());
391 B2DPolyPolygon aRetval;
393 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
395 const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
397 aRetval.append(distort(aCandidate, rOriginal, rTopLeft, rTopRight, rBottomLeft, rBottomRight));
400 return aRetval;
403 B2DPolyPolygon rotateAroundPoint(const B2DPolyPolygon& rCandidate, const B2DPoint& rCenter, double fAngle)
405 const sal_uInt32 nPolygonCount(rCandidate.count());
406 B2DPolyPolygon aRetval;
408 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
410 const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
412 aRetval.append(rotateAroundPoint(aCandidate, rCenter, fAngle));
415 return aRetval;
418 B2DPolyPolygon expandToCurve(const B2DPolyPolygon& rCandidate)
420 const sal_uInt32 nPolygonCount(rCandidate.count());
421 B2DPolyPolygon aRetval;
423 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
425 const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
427 aRetval.append(expandToCurve(aCandidate));
430 return aRetval;
433 B2DPolyPolygon setContinuity(const B2DPolyPolygon& rCandidate, B2VectorContinuity eContinuity)
435 if(rCandidate.areControlPointsUsed())
437 const sal_uInt32 nPolygonCount(rCandidate.count());
438 B2DPolyPolygon aRetval;
440 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
442 const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
444 aRetval.append(setContinuity(aCandidate, eContinuity));
447 return aRetval;
449 else
451 return rCandidate;
455 B2DPolyPolygon growInNormalDirection(const B2DPolyPolygon& rCandidate, double fValue)
457 if(0.0 != fValue)
459 B2DPolyPolygon aRetval;
461 for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
463 aRetval.append(growInNormalDirection(rCandidate.getB2DPolygon(a), fValue));
466 return aRetval;
468 else
470 return rCandidate;
474 void correctGrowShrinkPolygonPair(B2DPolyPolygon& /*rOriginal*/, B2DPolyPolygon& /*rGrown*/)
478 B2DPolyPolygon reSegmentPolyPolygon(const B2DPolyPolygon& rCandidate, sal_uInt32 nSegments)
480 B2DPolyPolygon aRetval;
482 for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
484 aRetval.append(reSegmentPolygon(rCandidate.getB2DPolygon(a), nSegments));
487 return aRetval;
490 B2DPolyPolygon interpolate(const B2DPolyPolygon& rOld1, const B2DPolyPolygon& rOld2, double t)
492 OSL_ENSURE(rOld1.count() == rOld2.count(), "B2DPolyPolygon interpolate: Different geometry (!)");
493 B2DPolyPolygon aRetval;
495 for(sal_uInt32 a(0L); a < rOld1.count(); a++)
497 aRetval.append(interpolate(rOld1.getB2DPolygon(a), rOld2.getB2DPolygon(a), t));
500 return aRetval;
503 bool isRectangle( const B2DPolyPolygon& rPoly )
505 // exclude some cheap cases first
506 if( rPoly.count() != 1 )
507 return false;
509 return isRectangle( rPoly.getB2DPolygon(0) );
512 // #i76891#
513 B2DPolyPolygon simplifyCurveSegments(const B2DPolyPolygon& rCandidate)
515 if(rCandidate.areControlPointsUsed())
517 B2DPolyPolygon aRetval;
519 for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
521 aRetval.append(simplifyCurveSegments(rCandidate.getB2DPolygon(a)));
524 return aRetval;
526 else
528 return rCandidate;
532 B2DPolyPolygon reSegmentPolyPolygonEdges(const B2DPolyPolygon& rCandidate, sal_uInt32 nSubEdges, bool bHandleCurvedEdges, bool bHandleStraightEdges)
534 B2DPolyPolygon aRetval;
536 for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
538 aRetval.append(reSegmentPolygonEdges(rCandidate.getB2DPolygon(a), nSubEdges, bHandleCurvedEdges, bHandleStraightEdges));
541 return aRetval;
544 //////////////////////////////////////////////////////////////////////
545 // comparators with tolerance for 2D PolyPolygons
547 bool equal(const B2DPolyPolygon& rCandidateA, const B2DPolyPolygon& rCandidateB, const double& rfSmallValue)
549 const sal_uInt32 nPolygonCount(rCandidateA.count());
551 if(nPolygonCount != rCandidateB.count())
552 return false;
554 for(sal_uInt32 a(0); a < nPolygonCount; a++)
556 const B2DPolygon aCandidate(rCandidateA.getB2DPolygon(a));
558 if(!equal(aCandidate, rCandidateB.getB2DPolygon(a), rfSmallValue))
559 return false;
562 return true;
565 bool equal(const B2DPolyPolygon& rCandidateA, const B2DPolyPolygon& rCandidateB)
567 const double fSmallValue(fTools::getSmallValue());
569 return equal(rCandidateA, rCandidateB, fSmallValue);
572 B2DPolyPolygon snapPointsOfHorizontalOrVerticalEdges(const B2DPolyPolygon& rCandidate)
574 B2DPolyPolygon aRetval;
576 for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
578 aRetval.append(snapPointsOfHorizontalOrVerticalEdges(rCandidate.getB2DPolygon(a)));
581 return aRetval;
584 } // end of namespace tools
585 } // end of namespace basegfx
587 //////////////////////////////////////////////////////////////////////////////
588 // eof