1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
30 //////////////////////////////////////////////////////////////////////////////
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
++)
51 const B2DPolygon
aCompare(rCandidate
.getB2DPolygon(b
));
53 if(tools::isInside(aCompare
, aCandidate
, true))
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
);
67 aRetval
.setB2DPolygon(a
, aFlipped
);
74 B2DPolyPolygon
correctOutmostPolygon(const B2DPolyPolygon
& rCandidate
)
76 const sal_uInt32
nCount(rCandidate
.count());
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
++)
89 const B2DPolygon
aCompare(rCandidate
.getB2DPolygon(b
));
91 if(tools::isInside(aCompare
, aCandidate
, true))
100 B2DPolyPolygon
aRetval(rCandidate
);
104 // exchange polygon a and polygon 0L
105 aRetval
.setB2DPolygon(0L, aCandidate
);
106 aRetval
.setB2DPolygon(a
, rCandidate
.getB2DPolygon(0L));
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
));
135 aRetval
.append(aCandidate
);
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
));
164 aRetval
.append(aCandidate
);
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
));
193 aRetval
.append(aCandidate
);
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
);
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
));
228 return (nInsideCount
% 2L);
232 B2DRange
getRange(const B2DPolyPolygon
& rCandidate
)
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
));
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
));
265 pLineTarget
? &aLineTarget
: 0,
266 pGapTarget
? &aGapTarget
: 0,
271 pLineTarget
->append(aLineTarget
);
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
))
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
));
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
));
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
;
340 const double fNewDistance(getSmallestDistancePointToPolygon(aCandidate
, rTestPoint
, nNewEdgeIndex
, fNewCut
));
342 if(DBL_MAX
== fRetval
|| fNewDistance
< fRetval
)
344 fRetval
= fNewDistance
;
346 rEdgeIndex
= nNewEdgeIndex
;
349 if(fTools::equal(fRetval
, fZero
))
351 // already found zero distance, cannot get better. Ensure numerical zero value and end loop.
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
));
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
));
391 B2DPolyPolygon
growInNormalDirection(const B2DPolyPolygon
& rCandidate
, double fValue
)
395 B2DPolyPolygon aRetval
;
397 for(sal_uInt32
a(0L); a
< rCandidate
.count(); a
++)
399 aRetval
.append(growInNormalDirection(rCandidate
.getB2DPolygon(a
), fValue
));
410 void correctGrowShrinkPolygonPair(SAL_UNUSED_PARAMETER B2DPolyPolygon
& /*rOriginal*/, SAL_UNUSED_PARAMETER B2DPolyPolygon
& /*rGrown*/)
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
));
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
));
440 bool isRectangle( const B2DPolyPolygon
& rPoly
)
442 // exclude some cheap cases first
443 if( rPoly
.count() != 1 )
446 return isRectangle( rPoly
.getB2DPolygon(0) );
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
)));
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
)));
481 } // end of namespace tools
482 } // end of namespace basegfx
484 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */