1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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>
43 //////////////////////////////////////////////////////////////////////////////
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
++)
64 const B2DPolygon
aCompare(rCandidate
.getB2DPolygon(b
));
66 if(tools::isInside(aCompare
, aCandidate
, true))
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
);
80 aRetval
.setB2DPolygon(a
, aFlipped
);
87 B2DPolyPolygon
correctOutmostPolygon(const B2DPolyPolygon
& rCandidate
)
89 const sal_uInt32
nCount(rCandidate
.count());
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
++)
102 const B2DPolygon
aCompare(rCandidate
.getB2DPolygon(b
));
104 if(tools::isInside(aCompare
, aCandidate
, true))
113 B2DPolyPolygon
aRetval(rCandidate
);
117 // exchange polygon a and polygon 0L
118 aRetval
.setB2DPolygon(0L, aCandidate
);
119 aRetval
.setB2DPolygon(a
, rCandidate
.getB2DPolygon(0L));
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
));
148 aRetval
.append(aCandidate
);
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
));
177 aRetval
.append(aCandidate
);
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
));
206 aRetval
.append(aCandidate
);
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
);
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
));
241 return (nInsideCount
% 2L);
245 B2DRange
getRangeWithControlPoints(const B2DPolyPolygon
& rCandidate
)
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
));
259 B2DRange
getRange(const B2DPolyPolygon
& rCandidate
)
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
));
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
));
292 pLineTarget
? &aLineTarget
: 0,
293 pGapTarget
? &aGapTarget
: 0,
298 pLineTarget
->append(aLineTarget
);
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
))
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
));
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
));
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
;
367 const double fNewDistance(getSmallestDistancePointToPolygon(aCandidate
, rTestPoint
, nNewEdgeIndex
, fNewCut
));
369 if(DBL_MAX
== fRetval
|| fNewDistance
< fRetval
)
371 fRetval
= fNewDistance
;
373 rEdgeIndex
= nNewEdgeIndex
;
376 if(fTools::equal(fRetval
, fZero
))
378 // already found zero distance, cannot get better. Ensure numerical zero value and end loop.
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
));
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
));
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
));
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
));
455 B2DPolyPolygon
growInNormalDirection(const B2DPolyPolygon
& rCandidate
, double fValue
)
459 B2DPolyPolygon aRetval
;
461 for(sal_uInt32
a(0L); a
< rCandidate
.count(); a
++)
463 aRetval
.append(growInNormalDirection(rCandidate
.getB2DPolygon(a
), fValue
));
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
));
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
));
503 bool isRectangle( const B2DPolyPolygon
& rPoly
)
505 // exclude some cheap cases first
506 if( rPoly
.count() != 1 )
509 return isRectangle( rPoly
.getB2DPolygon(0) );
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
)));
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
));
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())
554 for(sal_uInt32
a(0); a
< nPolygonCount
; a
++)
556 const B2DPolygon
aCandidate(rCandidateA
.getB2DPolygon(a
));
558 if(!equal(aCandidate
, rCandidateB
.getB2DPolygon(a
), rfSmallValue
))
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
)));
584 } // end of namespace tools
585 } // end of namespace basegfx
587 //////////////////////////////////////////////////////////////////////////////