Updated core
[LibreOffice.git] / basegfx / source / polygon / b2dpolypolygontools.cxx
blob8a5337bfe4b1199f70b604bd3d58d399e90e9cfd
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <basegfx/polygon/b2dpolypolygontools.hxx>
21 #include <osl/diagnose.h>
22 #include <basegfx/polygon/b2dpolypolygon.hxx>
23 #include <basegfx/polygon/b2dpolygon.hxx>
24 #include <basegfx/polygon/b2dpolygontools.hxx>
25 #include <basegfx/numeric/ftools.hxx>
26 #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
28 #include <numeric>
30 //////////////////////////////////////////////////////////////////////////////
32 namespace basegfx
34 namespace tools
36 B2DPolyPolygon correctOrientations(const B2DPolyPolygon& rCandidate)
38 B2DPolyPolygon aRetval(rCandidate);
39 const sal_uInt32 nCount(aRetval.count());
41 for(sal_uInt32 a(0L); a < nCount; a++)
43 const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
44 const B2VectorOrientation aOrientation(tools::getOrientation(aCandidate));
45 sal_uInt32 nDepth(0L);
47 for(sal_uInt32 b(0L); b < nCount; b++)
49 if(b != a)
51 const B2DPolygon aCompare(rCandidate.getB2DPolygon(b));
53 if(tools::isInside(aCompare, aCandidate, true))
55 nDepth++;
60 const bool bShallBeHole(1L == (nDepth & 0x00000001));
61 const bool bIsHole(ORIENTATION_NEGATIVE == aOrientation);
63 if(bShallBeHole != bIsHole && ORIENTATION_NEUTRAL != aOrientation)
65 B2DPolygon aFlipped(aCandidate);
66 aFlipped.flip();
67 aRetval.setB2DPolygon(a, aFlipped);
71 return aRetval;
74 B2DPolyPolygon correctOutmostPolygon(const B2DPolyPolygon& rCandidate)
76 const sal_uInt32 nCount(rCandidate.count());
78 if(nCount > 1L)
80 for(sal_uInt32 a(0L); a < nCount; a++)
82 const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
83 sal_uInt32 nDepth(0L);
85 for(sal_uInt32 b(0L); b < nCount; b++)
87 if(b != a)
89 const B2DPolygon aCompare(rCandidate.getB2DPolygon(b));
91 if(tools::isInside(aCompare, aCandidate, true))
93 nDepth++;
98 if(!nDepth)
100 B2DPolyPolygon aRetval(rCandidate);
102 if(a != 0L)
104 // exchange polygon a and polygon 0L
105 aRetval.setB2DPolygon(0L, aCandidate);
106 aRetval.setB2DPolygon(a, rCandidate.getB2DPolygon(0L));
109 // exit
110 return aRetval;
115 return rCandidate;
118 B2DPolyPolygon adaptiveSubdivideByDistance(const B2DPolyPolygon& rCandidate, double fDistanceBound)
120 if(rCandidate.areControlPointsUsed())
122 const sal_uInt32 nPolygonCount(rCandidate.count());
123 B2DPolyPolygon aRetval;
125 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
127 const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
129 if(aCandidate.areControlPointsUsed())
131 aRetval.append(tools::adaptiveSubdivideByDistance(aCandidate, fDistanceBound));
133 else
135 aRetval.append(aCandidate);
139 return aRetval;
141 else
143 return rCandidate;
147 B2DPolyPolygon adaptiveSubdivideByAngle(const B2DPolyPolygon& rCandidate, double fAngleBound)
149 if(rCandidate.areControlPointsUsed())
151 const sal_uInt32 nPolygonCount(rCandidate.count());
152 B2DPolyPolygon aRetval;
154 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
156 const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
158 if(aCandidate.areControlPointsUsed())
160 aRetval.append(tools::adaptiveSubdivideByAngle(aCandidate, fAngleBound));
162 else
164 aRetval.append(aCandidate);
168 return aRetval;
170 else
172 return rCandidate;
176 B2DPolyPolygon adaptiveSubdivideByCount(const B2DPolyPolygon& rCandidate, sal_uInt32 nCount)
178 if(rCandidate.areControlPointsUsed())
180 const sal_uInt32 nPolygonCount(rCandidate.count());
181 B2DPolyPolygon aRetval;
183 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
185 const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
187 if(aCandidate.areControlPointsUsed())
189 aRetval.append(tools::adaptiveSubdivideByCount(aCandidate, nCount));
191 else
193 aRetval.append(aCandidate);
197 return aRetval;
199 else
201 return rCandidate;
205 bool isInside(const B2DPolyPolygon& rCandidate, const B2DPoint& rPoint, bool bWithBorder)
207 const sal_uInt32 nPolygonCount(rCandidate.count());
209 if(1L == nPolygonCount)
211 return isInside(rCandidate.getB2DPolygon(0L), rPoint, bWithBorder);
213 else
215 sal_Int32 nInsideCount(0L);
217 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
219 const B2DPolygon aPolygon(rCandidate.getB2DPolygon(a));
220 const bool bInside(isInside(aPolygon, rPoint, bWithBorder));
222 if(bInside)
224 nInsideCount++;
228 return (nInsideCount % 2L);
232 B2DRange getRange(const B2DPolyPolygon& rCandidate)
234 B2DRange aRetval;
235 const sal_uInt32 nPolygonCount(rCandidate.count());
237 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
239 B2DPolygon aCandidate = rCandidate.getB2DPolygon(a);
240 aRetval.expand(tools::getRange(aCandidate));
243 return aRetval;
246 void applyLineDashing(const B2DPolyPolygon& rCandidate, const ::std::vector<double>& rDotDashArray, B2DPolyPolygon* pLineTarget, B2DPolyPolygon* pGapTarget, double fFullDashDotLen)
248 if(0.0 == fFullDashDotLen && rDotDashArray.size())
250 // calculate fFullDashDotLen from rDotDashArray
251 fFullDashDotLen = ::std::accumulate(rDotDashArray.begin(), rDotDashArray.end(), 0.0);
254 if(rCandidate.count() && fFullDashDotLen > 0.0)
256 B2DPolyPolygon aLineTarget, aGapTarget;
258 for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
260 const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
262 applyLineDashing(
263 aCandidate,
264 rDotDashArray,
265 pLineTarget ? &aLineTarget : 0,
266 pGapTarget ? &aGapTarget : 0,
267 fFullDashDotLen);
269 if(pLineTarget)
271 pLineTarget->append(aLineTarget);
274 if(pGapTarget)
276 pGapTarget->append(aGapTarget);
282 bool isInEpsilonRange(const B2DPolyPolygon& rCandidate, const B2DPoint& rTestPosition, double fDistance)
284 const sal_uInt32 nPolygonCount(rCandidate.count());
286 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
288 B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
290 if(isInEpsilonRange(aCandidate, rTestPosition, fDistance))
292 return true;
296 return false;
299 B3DPolyPolygon createB3DPolyPolygonFromB2DPolyPolygon(const B2DPolyPolygon& rCandidate, double fZCoordinate)
301 const sal_uInt32 nPolygonCount(rCandidate.count());
302 B3DPolyPolygon aRetval;
304 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
306 B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
308 aRetval.append(createB3DPolygonFromB2DPolygon(aCandidate, fZCoordinate));
311 return aRetval;
314 B2DPolyPolygon createB2DPolyPolygonFromB3DPolyPolygon(const B3DPolyPolygon& rCandidate, const B3DHomMatrix& rMat)
316 const sal_uInt32 nPolygonCount(rCandidate.count());
317 B2DPolyPolygon aRetval;
319 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
321 B3DPolygon aCandidate(rCandidate.getB3DPolygon(a));
323 aRetval.append(createB2DPolygonFromB3DPolygon(aCandidate, rMat));
326 return aRetval;
329 double getSmallestDistancePointToPolyPolygon(const B2DPolyPolygon& rCandidate, const B2DPoint& rTestPoint, sal_uInt32& rPolygonIndex, sal_uInt32& rEdgeIndex, double& rCut)
331 double fRetval(DBL_MAX);
332 const double fZero(0.0);
333 const sal_uInt32 nPolygonCount(rCandidate.count());
335 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
337 const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
338 sal_uInt32 nNewEdgeIndex;
339 double fNewCut;
340 const double fNewDistance(getSmallestDistancePointToPolygon(aCandidate, rTestPoint, nNewEdgeIndex, fNewCut));
342 if(DBL_MAX == fRetval || fNewDistance < fRetval)
344 fRetval = fNewDistance;
345 rPolygonIndex = a;
346 rEdgeIndex = nNewEdgeIndex;
347 rCut = fNewCut;
349 if(fTools::equal(fRetval, fZero))
351 // already found zero distance, cannot get better. Ensure numerical zero value and end loop.
352 fRetval = 0.0;
353 break;
358 return fRetval;
361 B2DPolyPolygon distort(const B2DPolyPolygon& rCandidate, const B2DRange& rOriginal, const B2DPoint& rTopLeft, const B2DPoint& rTopRight, const B2DPoint& rBottomLeft, const B2DPoint& rBottomRight)
363 const sal_uInt32 nPolygonCount(rCandidate.count());
364 B2DPolyPolygon aRetval;
366 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
368 const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
370 aRetval.append(distort(aCandidate, rOriginal, rTopLeft, rTopRight, rBottomLeft, rBottomRight));
373 return aRetval;
376 B2DPolyPolygon expandToCurve(const B2DPolyPolygon& rCandidate)
378 const sal_uInt32 nPolygonCount(rCandidate.count());
379 B2DPolyPolygon aRetval;
381 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
383 const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
385 aRetval.append(expandToCurve(aCandidate));
388 return aRetval;
391 B2DPolyPolygon growInNormalDirection(const B2DPolyPolygon& rCandidate, double fValue)
393 if(0.0 != fValue)
395 B2DPolyPolygon aRetval;
397 for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
399 aRetval.append(growInNormalDirection(rCandidate.getB2DPolygon(a), fValue));
402 return aRetval;
404 else
406 return rCandidate;
410 void correctGrowShrinkPolygonPair(SAL_UNUSED_PARAMETER B2DPolyPolygon& /*rOriginal*/, SAL_UNUSED_PARAMETER B2DPolyPolygon& /*rGrown*/)
412 //TODO!
415 B2DPolyPolygon reSegmentPolyPolygon(const B2DPolyPolygon& rCandidate, sal_uInt32 nSegments)
417 B2DPolyPolygon aRetval;
419 for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
421 aRetval.append(reSegmentPolygon(rCandidate.getB2DPolygon(a), nSegments));
424 return aRetval;
427 B2DPolyPolygon interpolate(const B2DPolyPolygon& rOld1, const B2DPolyPolygon& rOld2, double t)
429 OSL_ENSURE(rOld1.count() == rOld2.count(), "B2DPolyPolygon interpolate: Different geometry (!)");
430 B2DPolyPolygon aRetval;
432 for(sal_uInt32 a(0L); a < rOld1.count(); a++)
434 aRetval.append(interpolate(rOld1.getB2DPolygon(a), rOld2.getB2DPolygon(a), t));
437 return aRetval;
440 bool isRectangle( const B2DPolyPolygon& rPoly )
442 // exclude some cheap cases first
443 if( rPoly.count() != 1 )
444 return false;
446 return isRectangle( rPoly.getB2DPolygon(0) );
449 // #i76891#
450 B2DPolyPolygon simplifyCurveSegments(const B2DPolyPolygon& rCandidate)
452 if(rCandidate.areControlPointsUsed())
454 B2DPolyPolygon aRetval;
456 for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
458 aRetval.append(simplifyCurveSegments(rCandidate.getB2DPolygon(a)));
461 return aRetval;
463 else
465 return rCandidate;
469 B2DPolyPolygon snapPointsOfHorizontalOrVerticalEdges(const B2DPolyPolygon& rCandidate)
471 B2DPolyPolygon aRetval;
473 for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
475 aRetval.append(snapPointsOfHorizontalOrVerticalEdges(rCandidate.getB2DPolygon(a)));
478 return aRetval;
481 } // end of namespace tools
482 } // end of namespace basegfx
484 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */