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>
40 //////////////////////////////////////////////////////////////////////////////
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
++)
61 const B2DPolygon
aCompare(rCandidate
.getB2DPolygon(b
));
63 if(tools::isInside(aCompare
, aCandidate
, true))
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
);
77 aRetval
.setB2DPolygon(a
, aFlipped
);
84 B2DPolyPolygon
correctOutmostPolygon(const B2DPolyPolygon
& rCandidate
)
86 const sal_uInt32
nCount(rCandidate
.count());
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
++)
99 const B2DPolygon
aCompare(rCandidate
.getB2DPolygon(b
));
101 if(tools::isInside(aCompare
, aCandidate
, true))
110 B2DPolyPolygon
aRetval(rCandidate
);
114 // exchange polygon a and polygon 0L
115 aRetval
.setB2DPolygon(0L, aCandidate
);
116 aRetval
.setB2DPolygon(a
, rCandidate
.getB2DPolygon(0L));
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
));
145 aRetval
.append(aCandidate
);
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
));
174 aRetval
.append(aCandidate
);
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
));
203 aRetval
.append(aCandidate
);
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
);
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
));
238 return (nInsideCount
% 2L);
242 B2DRange
getRangeWithControlPoints(const B2DPolyPolygon
& rCandidate
)
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
));
256 B2DRange
getRange(const B2DPolyPolygon
& rCandidate
)
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
));
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
));
289 pLineTarget
? &aLineTarget
: 0,
290 pGapTarget
? &aGapTarget
: 0,
295 pLineTarget
->append(aLineTarget
);
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
))
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
));
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
));
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
;
364 const double fNewDistance(getSmallestDistancePointToPolygon(aCandidate
, rTestPoint
, nNewEdgeIndex
, fNewCut
));
366 if(DBL_MAX
== fRetval
|| fNewDistance
< fRetval
)
368 fRetval
= fNewDistance
;
370 rEdgeIndex
= nNewEdgeIndex
;
373 if(fTools::equal(fRetval
, fZero
))
375 // already found zero distance, cannot get better. Ensure numerical zero value and end loop.
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
));
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
));
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
));
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
));
452 B2DPolyPolygon
growInNormalDirection(const B2DPolyPolygon
& rCandidate
, double fValue
)
456 B2DPolyPolygon aRetval
;
458 for(sal_uInt32
a(0L); a
< rCandidate
.count(); a
++)
460 aRetval
.append(growInNormalDirection(rCandidate
.getB2DPolygon(a
), fValue
));
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
));
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
));
500 bool isRectangle( const B2DPolyPolygon
& rPoly
)
502 // exclude some cheap cases first
503 if( rPoly
.count() != 1 )
506 return isRectangle( rPoly
.getB2DPolygon(0) );
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
)));
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
));
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())
551 for(sal_uInt32
a(0); a
< nPolygonCount
; a
++)
553 const B2DPolygon
aCandidate(rCandidateA
.getB2DPolygon(a
));
555 if(!equal(aCandidate
, rCandidateB
.getB2DPolygon(a
), rfSmallValue
))
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
)));
581 } // end of namespace tools
582 } // end of namespace basegfx
584 //////////////////////////////////////////////////////////////////////////////