1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 // MARKER(update_precomp.py): autogen include statement, do not remove
23 #include "precompiled_basegfx.hxx"
24 
25 #include <basegfx/polygon/b2dpolypolygontools.hxx>
26 #include <osl/diagnose.h>
27 #include <basegfx/polygon/b2dpolypolygon.hxx>
28 #include <basegfx/polygon/b2dpolygon.hxx>
29 #include <basegfx/polygon/b2dpolygontools.hxx>
30 #include <basegfx/numeric/ftools.hxx>
31 #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
32 #include <numeric>
33 
34 //////////////////////////////////////////////////////////////////////////////
35 
36 namespace basegfx
37 {
38 	namespace tools
39 	{
correctOrientations(const B2DPolyPolygon & rCandidate)40 		B2DPolyPolygon correctOrientations(const B2DPolyPolygon& rCandidate)
41 		{
42 			B2DPolyPolygon aRetval(rCandidate);
43 			const sal_uInt32 nCount(aRetval.count());
44 
45 			for(sal_uInt32 a(0L); a < nCount; a++)
46 			{
47 				const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
48 				const B2VectorOrientation aOrientation(tools::getOrientation(aCandidate));
49 				sal_uInt32 nDepth(0L);
50 
51 				for(sal_uInt32 b(0L); b < nCount; b++)
52 				{
53 					if(b != a)
54 					{
55 						const B2DPolygon aCompare(rCandidate.getB2DPolygon(b));
56 
57 						if(tools::isInside(aCompare, aCandidate, true))
58 						{
59 							nDepth++;
60 						}
61 					}
62 				}
63 
64 				const bool bShallBeHole(1L == (nDepth & 0x00000001));
65 				const bool bIsHole(ORIENTATION_NEGATIVE == aOrientation);
66 
67 				if(bShallBeHole != bIsHole && ORIENTATION_NEUTRAL != aOrientation)
68 				{
69 					B2DPolygon aFlipped(aCandidate);
70 					aFlipped.flip();
71 					aRetval.setB2DPolygon(a, aFlipped);
72 				}
73 			}
74 
75 			return aRetval;
76 		}
77 
correctOutmostPolygon(const B2DPolyPolygon & rCandidate)78 		B2DPolyPolygon correctOutmostPolygon(const B2DPolyPolygon& rCandidate)
79 		{
80 			const sal_uInt32 nCount(rCandidate.count());
81 
82 			if(nCount > 1L)
83 			{
84 				for(sal_uInt32 a(0L); a < nCount; a++)
85 				{
86 					const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
87 					sal_uInt32 nDepth(0L);
88 
89 					for(sal_uInt32 b(0L); b < nCount; b++)
90 					{
91 						if(b != a)
92 						{
93 							const B2DPolygon aCompare(rCandidate.getB2DPolygon(b));
94 
95 							if(tools::isInside(aCompare, aCandidate, true))
96 							{
97 								nDepth++;
98 							}
99 						}
100 					}
101 
102 					if(!nDepth)
103 					{
104 						B2DPolyPolygon aRetval(rCandidate);
105 
106 						if(a != 0L)
107 						{
108 							// exchange polygon a and polygon 0L
109 							aRetval.setB2DPolygon(0L, aCandidate);
110 							aRetval.setB2DPolygon(a, rCandidate.getB2DPolygon(0L));
111 						}
112 
113 						// exit
114 						return aRetval;
115 					}
116 				}
117 			}
118 
119 			return rCandidate;
120 		}
121 
adaptiveSubdivideByDistance(const B2DPolyPolygon & rCandidate,double fDistanceBound)122 		B2DPolyPolygon adaptiveSubdivideByDistance(const B2DPolyPolygon& rCandidate, double fDistanceBound)
123 		{
124 			if(rCandidate.areControlPointsUsed())
125 			{
126 				const sal_uInt32 nPolygonCount(rCandidate.count());
127 				B2DPolyPolygon aRetval;
128 
129 				for(sal_uInt32 a(0L); a < nPolygonCount; a++)
130 				{
131 					const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
132 
133 					if(aCandidate.areControlPointsUsed())
134 					{
135 						aRetval.append(tools::adaptiveSubdivideByDistance(aCandidate, fDistanceBound));
136 					}
137 					else
138 					{
139 						aRetval.append(aCandidate);
140 					}
141 				}
142 
143 				return aRetval;
144 			}
145 			else
146 			{
147 				return rCandidate;
148 			}
149 		}
150 
adaptiveSubdivideByAngle(const B2DPolyPolygon & rCandidate,double fAngleBound)151 		B2DPolyPolygon adaptiveSubdivideByAngle(const B2DPolyPolygon& rCandidate, double fAngleBound)
152 		{
153 			if(rCandidate.areControlPointsUsed())
154 			{
155 				const sal_uInt32 nPolygonCount(rCandidate.count());
156 				B2DPolyPolygon aRetval;
157 
158 				for(sal_uInt32 a(0L); a < nPolygonCount; a++)
159 				{
160 					const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
161 
162 					if(aCandidate.areControlPointsUsed())
163 					{
164 						aRetval.append(tools::adaptiveSubdivideByAngle(aCandidate, fAngleBound));
165 					}
166 					else
167 					{
168 						aRetval.append(aCandidate);
169 					}
170 				}
171 
172 				return aRetval;
173 			}
174 			else
175 			{
176 				return rCandidate;
177 			}
178 		}
179 
adaptiveSubdivideByCount(const B2DPolyPolygon & rCandidate,sal_uInt32 nCount)180 		B2DPolyPolygon adaptiveSubdivideByCount(const B2DPolyPolygon& rCandidate, sal_uInt32 nCount)
181 		{
182 			if(rCandidate.areControlPointsUsed())
183 			{
184 				const sal_uInt32 nPolygonCount(rCandidate.count());
185 				B2DPolyPolygon aRetval;
186 
187 				for(sal_uInt32 a(0L); a < nPolygonCount; a++)
188 				{
189 					const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
190 
191 					if(aCandidate.areControlPointsUsed())
192 					{
193 						aRetval.append(tools::adaptiveSubdivideByCount(aCandidate, nCount));
194 					}
195 					else
196 					{
197 						aRetval.append(aCandidate);
198 					}
199 				}
200 
201 				return aRetval;
202 			}
203 			else
204 			{
205 				return rCandidate;
206 			}
207 		}
208 
isInside(const B2DPolyPolygon & rCandidate,const B2DPoint & rPoint,bool bWithBorder)209 		bool isInside(const B2DPolyPolygon& rCandidate, const B2DPoint& rPoint, bool bWithBorder)
210 		{
211 			const sal_uInt32 nPolygonCount(rCandidate.count());
212 
213 			if(1L == nPolygonCount)
214 			{
215 				return isInside(rCandidate.getB2DPolygon(0L), rPoint, bWithBorder);
216 			}
217 			else
218 			{
219 				sal_Int32 nInsideCount(0L);
220 
221 				for(sal_uInt32 a(0L); a < nPolygonCount; a++)
222 				{
223 					const B2DPolygon aPolygon(rCandidate.getB2DPolygon(a));
224 					const bool bInside(isInside(aPolygon, rPoint, bWithBorder));
225 
226 					if(bInside)
227 					{
228 						nInsideCount++;
229 					}
230 				}
231 
232 				return (nInsideCount % 2L);
233 			}
234 		}
235 
getRangeWithControlPoints(const B2DPolyPolygon & rCandidate)236 		B2DRange getRangeWithControlPoints(const B2DPolyPolygon& rCandidate)
237 		{
238 			B2DRange aRetval;
239 			const sal_uInt32 nPolygonCount(rCandidate.count());
240 
241 			for(sal_uInt32 a(0L); a < nPolygonCount; a++)
242 			{
243 				B2DPolygon aCandidate = rCandidate.getB2DPolygon(a);
244 				aRetval.expand(tools::getRangeWithControlPoints(aCandidate));
245 			}
246 
247 			return aRetval;
248 		}
249 
getRange(const B2DPolyPolygon & rCandidate)250 		B2DRange getRange(const B2DPolyPolygon& rCandidate)
251 		{
252 			B2DRange aRetval;
253 			const sal_uInt32 nPolygonCount(rCandidate.count());
254 
255 			for(sal_uInt32 a(0L); a < nPolygonCount; a++)
256 			{
257 				B2DPolygon aCandidate = rCandidate.getB2DPolygon(a);
258 				aRetval.expand(tools::getRange(aCandidate));
259 			}
260 
261 			return aRetval;
262 		}
263 
getSignedArea(const B2DPolyPolygon & rCandidate)264 		double getSignedArea(const B2DPolyPolygon& rCandidate)
265 		{
266 			double fRetval(0.0);
267 			const sal_uInt32 nPolygonCount(rCandidate.count());
268 
269 			for(sal_uInt32 a(0L); a < nPolygonCount; a++)
270 			{
271 				const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
272 
273                 fRetval += tools::getSignedArea(aCandidate);
274 			}
275 
276 			return fRetval;
277 		}
278 
getArea(const B2DPolyPolygon & rCandidate)279 		double getArea(const B2DPolyPolygon& rCandidate)
280 		{
281 			return fabs(getSignedArea(rCandidate));
282 		}
283 
applyLineDashing(const B2DPolyPolygon & rCandidate,const::std::vector<double> & rDotDashArray,B2DPolyPolygon * pLineTarget,B2DPolyPolygon * pGapTarget,double fFullDashDotLen)284         void applyLineDashing(const B2DPolyPolygon& rCandidate, const ::std::vector<double>& rDotDashArray, B2DPolyPolygon* pLineTarget, B2DPolyPolygon* pGapTarget, double fFullDashDotLen)
285 		{
286 			if(0.0 == fFullDashDotLen && rDotDashArray.size())
287 			{
288 				// calculate fFullDashDotLen from rDotDashArray
289 				fFullDashDotLen = ::std::accumulate(rDotDashArray.begin(), rDotDashArray.end(), 0.0);
290 			}
291 
292 			if(rCandidate.count() && fFullDashDotLen > 0.0)
293 			{
294 				B2DPolyPolygon aLineTarget, aGapTarget;
295 
296 				for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
297 				{
298 					const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
299 
300 					applyLineDashing(
301 						aCandidate,
302 						rDotDashArray,
303 						pLineTarget ? &aLineTarget : 0,
304 						pGapTarget ? &aGapTarget : 0,
305 						fFullDashDotLen);
306 
307 					if(pLineTarget)
308 					{
309 						pLineTarget->append(aLineTarget);
310 					}
311 
312 					if(pGapTarget)
313 					{
314 						pGapTarget->append(aGapTarget);
315 					}
316 				}
317 			}
318 		}
319 
isInEpsilonRange(const B2DPolyPolygon & rCandidate,const B2DPoint & rTestPosition,double fDistance)320 		bool isInEpsilonRange(const B2DPolyPolygon& rCandidate, const B2DPoint& rTestPosition, double fDistance)
321 		{
322 			const sal_uInt32 nPolygonCount(rCandidate.count());
323 
324 			for(sal_uInt32 a(0L); a < nPolygonCount; a++)
325 			{
326 				B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
327 
328 				if(isInEpsilonRange(aCandidate, rTestPosition, fDistance))
329 				{
330 					return true;
331 				}
332 			}
333 
334 			return false;
335 		}
336 
createB3DPolyPolygonFromB2DPolyPolygon(const B2DPolyPolygon & rCandidate,double fZCoordinate)337 		B3DPolyPolygon createB3DPolyPolygonFromB2DPolyPolygon(const B2DPolyPolygon& rCandidate, double fZCoordinate)
338 		{
339 			const sal_uInt32 nPolygonCount(rCandidate.count());
340 			B3DPolyPolygon aRetval;
341 
342 			for(sal_uInt32 a(0L); a < nPolygonCount; a++)
343 			{
344 				B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
345 
346 				aRetval.append(createB3DPolygonFromB2DPolygon(aCandidate, fZCoordinate));
347 			}
348 
349 			return aRetval;
350 		}
351 
createB2DPolyPolygonFromB3DPolyPolygon(const B3DPolyPolygon & rCandidate,const B3DHomMatrix & rMat)352 		B2DPolyPolygon createB2DPolyPolygonFromB3DPolyPolygon(const B3DPolyPolygon& rCandidate, const B3DHomMatrix& rMat)
353 		{
354 			const sal_uInt32 nPolygonCount(rCandidate.count());
355 			B2DPolyPolygon aRetval;
356 
357 			for(sal_uInt32 a(0L); a < nPolygonCount; a++)
358 			{
359 				B3DPolygon aCandidate(rCandidate.getB3DPolygon(a));
360 
361 				aRetval.append(createB2DPolygonFromB3DPolygon(aCandidate, rMat));
362 			}
363 
364 			return aRetval;
365 		}
366 
getSmallestDistancePointToPolyPolygon(const B2DPolyPolygon & rCandidate,const B2DPoint & rTestPoint,sal_uInt32 & rPolygonIndex,sal_uInt32 & rEdgeIndex,double & rCut)367 		double getSmallestDistancePointToPolyPolygon(const B2DPolyPolygon& rCandidate, const B2DPoint& rTestPoint, sal_uInt32& rPolygonIndex, sal_uInt32& rEdgeIndex, double& rCut)
368 		{
369 			double fRetval(DBL_MAX);
370 			const double fZero(0.0);
371 			const sal_uInt32 nPolygonCount(rCandidate.count());
372 
373 			for(sal_uInt32 a(0L); a < nPolygonCount; a++)
374 			{
375 				const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
376 				sal_uInt32 nNewEdgeIndex;
377 				double fNewCut;
378 				const double fNewDistance(getSmallestDistancePointToPolygon(aCandidate, rTestPoint, nNewEdgeIndex, fNewCut));
379 
380 				if(DBL_MAX == fRetval || fNewDistance < fRetval)
381 				{
382 					fRetval = fNewDistance;
383 					rPolygonIndex = a;
384 					rEdgeIndex = nNewEdgeIndex;
385 					rCut = fNewCut;
386 
387 					if(fTools::equal(fRetval, fZero))
388 					{
389 						// already found zero distance, cannot get better. Ensure numerical zero value and end loop.
390 						fRetval = 0.0;
391 						break;
392 					}
393 				}
394 			}
395 
396 			return fRetval;
397 		}
398 
distort(const B2DPolyPolygon & rCandidate,const B2DRange & rOriginal,const B2DPoint & rTopLeft,const B2DPoint & rTopRight,const B2DPoint & rBottomLeft,const B2DPoint & rBottomRight)399 		B2DPolyPolygon distort(const B2DPolyPolygon& rCandidate, const B2DRange& rOriginal, const B2DPoint& rTopLeft, const B2DPoint& rTopRight, const B2DPoint& rBottomLeft, const B2DPoint& rBottomRight)
400 		{
401 			const sal_uInt32 nPolygonCount(rCandidate.count());
402 			B2DPolyPolygon aRetval;
403 
404 			for(sal_uInt32 a(0L); a < nPolygonCount; a++)
405 			{
406 				const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
407 
408 				aRetval.append(distort(aCandidate, rOriginal, rTopLeft, rTopRight, rBottomLeft, rBottomRight));
409 			}
410 
411 			return aRetval;
412 		}
413 
rotateAroundPoint(const B2DPolyPolygon & rCandidate,const B2DPoint & rCenter,double fAngle)414 		B2DPolyPolygon rotateAroundPoint(const B2DPolyPolygon& rCandidate, const B2DPoint& rCenter, double fAngle)
415 		{
416 			const sal_uInt32 nPolygonCount(rCandidate.count());
417 			B2DPolyPolygon aRetval;
418 
419 			for(sal_uInt32 a(0L); a < nPolygonCount; a++)
420 			{
421 				const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
422 
423 				aRetval.append(rotateAroundPoint(aCandidate, rCenter, fAngle));
424 			}
425 
426 			return aRetval;
427 		}
428 
expandToCurve(const B2DPolyPolygon & rCandidate)429 		B2DPolyPolygon expandToCurve(const B2DPolyPolygon& rCandidate)
430 		{
431 			const sal_uInt32 nPolygonCount(rCandidate.count());
432 			B2DPolyPolygon aRetval;
433 
434 			for(sal_uInt32 a(0L); a < nPolygonCount; a++)
435 			{
436 				const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
437 
438 				aRetval.append(expandToCurve(aCandidate));
439 			}
440 
441 			return aRetval;
442 		}
443 
setContinuity(const B2DPolyPolygon & rCandidate,B2VectorContinuity eContinuity)444 		B2DPolyPolygon setContinuity(const B2DPolyPolygon& rCandidate, B2VectorContinuity eContinuity)
445 		{
446 			if(rCandidate.areControlPointsUsed())
447 			{
448 				const sal_uInt32 nPolygonCount(rCandidate.count());
449 				B2DPolyPolygon aRetval;
450 
451 				for(sal_uInt32 a(0L); a < nPolygonCount; a++)
452 				{
453 					const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
454 
455 					aRetval.append(setContinuity(aCandidate, eContinuity));
456 				}
457 
458 				return aRetval;
459 			}
460 			else
461 			{
462 				return rCandidate;
463 			}
464 		}
465 
growInNormalDirection(const B2DPolyPolygon & rCandidate,double fValue)466 		B2DPolyPolygon growInNormalDirection(const B2DPolyPolygon& rCandidate, double fValue)
467 		{
468 			if(0.0 != fValue)
469 			{
470 				B2DPolyPolygon aRetval;
471 
472 				for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
473 				{
474 					aRetval.append(growInNormalDirection(rCandidate.getB2DPolygon(a), fValue));
475 				}
476 
477 				return aRetval;
478 			}
479 			else
480 			{
481 				return rCandidate;
482 			}
483 		}
484 
correctGrowShrinkPolygonPair(B2DPolyPolygon &,B2DPolyPolygon &)485 		void correctGrowShrinkPolygonPair(B2DPolyPolygon& /*rOriginal*/, B2DPolyPolygon& /*rGrown*/)
486 		{
487 		}
488 
reSegmentPolyPolygon(const B2DPolyPolygon & rCandidate,sal_uInt32 nSegments)489 		B2DPolyPolygon reSegmentPolyPolygon(const B2DPolyPolygon& rCandidate, sal_uInt32 nSegments)
490 		{
491 			B2DPolyPolygon aRetval;
492 
493 			for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
494 			{
495 				aRetval.append(reSegmentPolygon(rCandidate.getB2DPolygon(a), nSegments));
496 			}
497 
498 			return aRetval;
499 		}
500 
interpolate(const B2DPolyPolygon & rOld1,const B2DPolyPolygon & rOld2,double t)501 		B2DPolyPolygon interpolate(const B2DPolyPolygon& rOld1, const B2DPolyPolygon& rOld2, double t)
502 		{
503 			OSL_ENSURE(rOld1.count() == rOld2.count(), "B2DPolyPolygon interpolate: Different geometry (!)");
504 			B2DPolyPolygon aRetval;
505 
506 			for(sal_uInt32 a(0L); a < rOld1.count(); a++)
507 			{
508 				aRetval.append(interpolate(rOld1.getB2DPolygon(a), rOld2.getB2DPolygon(a), t));
509 			}
510 
511 			return aRetval;
512 		}
513 
isRectangle(const B2DPolyPolygon & rPoly)514         bool isRectangle( const B2DPolyPolygon& rPoly )
515         {
516             // exclude some cheap cases first
517             if( rPoly.count() != 1 )
518                 return false;
519 
520             return isRectangle( rPoly.getB2DPolygon(0) );
521         }
522 
523 		// #i76891#
simplifyCurveSegments(const B2DPolyPolygon & rCandidate)524 		B2DPolyPolygon simplifyCurveSegments(const B2DPolyPolygon& rCandidate)
525 		{
526 			if(rCandidate.areControlPointsUsed())
527 			{
528 				B2DPolyPolygon aRetval;
529 
530 				for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
531 				{
532 					aRetval.append(simplifyCurveSegments(rCandidate.getB2DPolygon(a)));
533 				}
534 
535 				return aRetval;
536 			}
537 			else
538 			{
539 				return rCandidate;
540 			}
541 		}
542 
reSegmentPolyPolygonEdges(const B2DPolyPolygon & rCandidate,sal_uInt32 nSubEdges,bool bHandleCurvedEdges,bool bHandleStraightEdges)543 		B2DPolyPolygon reSegmentPolyPolygonEdges(const B2DPolyPolygon& rCandidate, sal_uInt32 nSubEdges, bool bHandleCurvedEdges, bool bHandleStraightEdges)
544         {
545 			B2DPolyPolygon aRetval;
546 
547 			for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
548 			{
549 				aRetval.append(reSegmentPolygonEdges(rCandidate.getB2DPolygon(a), nSubEdges, bHandleCurvedEdges, bHandleStraightEdges));
550 			}
551 
552 			return aRetval;
553         }
554 
555         //////////////////////////////////////////////////////////////////////
556 		// comparators with tolerance for 2D PolyPolygons
557 
equal(const B2DPolyPolygon & rCandidateA,const B2DPolyPolygon & rCandidateB,const double & rfSmallValue)558 		bool equal(const B2DPolyPolygon& rCandidateA, const B2DPolyPolygon& rCandidateB, const double& rfSmallValue)
559 		{
560 			const sal_uInt32 nPolygonCount(rCandidateA.count());
561 
562 			if(nPolygonCount != rCandidateB.count())
563 				return false;
564 
565 			for(sal_uInt32 a(0); a < nPolygonCount; a++)
566 			{
567 				const B2DPolygon aCandidate(rCandidateA.getB2DPolygon(a));
568 
569 				if(!equal(aCandidate, rCandidateB.getB2DPolygon(a), rfSmallValue))
570 					return false;
571 			}
572 
573 			return true;
574 		}
575 
equal(const B2DPolyPolygon & rCandidateA,const B2DPolyPolygon & rCandidateB)576 		bool equal(const B2DPolyPolygon& rCandidateA, const B2DPolyPolygon& rCandidateB)
577 		{
578 			const double fSmallValue(fTools::getSmallValue());
579 
580 			return equal(rCandidateA, rCandidateB, fSmallValue);
581 		}
582 
snapPointsOfHorizontalOrVerticalEdges(const B2DPolyPolygon & rCandidate)583 		B2DPolyPolygon snapPointsOfHorizontalOrVerticalEdges(const B2DPolyPolygon& rCandidate)
584 		{
585 			B2DPolyPolygon aRetval;
586 
587 			for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
588 			{
589 				aRetval.append(snapPointsOfHorizontalOrVerticalEdges(rCandidate.getB2DPolygon(a)));
590 			}
591 
592 			return aRetval;
593 		}
594 
containsOnlyHorizontalAndVerticalEdges(const B2DPolyPolygon & rCandidate)595         bool containsOnlyHorizontalAndVerticalEdges(const B2DPolyPolygon& rCandidate)
596         {
597             if(rCandidate.areControlPointsUsed())
598             {
599                 return false;
600             }
601 
602             for(sal_uInt32 a(0); a < rCandidate.count(); a++)
603             {
604                 if(!containsOnlyHorizontalAndVerticalEdges(rCandidate.getB2DPolygon(a)))
605                 {
606                     return false;
607                 }
608             }
609 
610             return true;
611         }
612 
613         //////////////////////////////////////////////////////////////////////////////
614         // converters for com::sun::star::drawing::PointSequence
615 
UnoPointSequenceSequenceToB2DPolyPolygon(const com::sun::star::drawing::PointSequenceSequence & rPointSequenceSequenceSource,bool bCheckClosed)616         B2DPolyPolygon UnoPointSequenceSequenceToB2DPolyPolygon(
617             const com::sun::star::drawing::PointSequenceSequence& rPointSequenceSequenceSource,
618             bool bCheckClosed)
619         {
620             B2DPolyPolygon aRetval;
621             const com::sun::star::drawing::PointSequence* pPointSequence = rPointSequenceSequenceSource.getConstArray();
622             const com::sun::star::drawing::PointSequence* pPointSeqEnd = pPointSequence + rPointSequenceSequenceSource.getLength();
623 
624             for(;pPointSequence != pPointSeqEnd; pPointSequence++)
625             {
626                 const B2DPolygon aNewPolygon = UnoPointSequenceToB2DPolygon(*pPointSequence, bCheckClosed);
627                 aRetval.append(aNewPolygon);
628             }
629 
630             return aRetval;
631         }
632 
B2DPolyPolygonToUnoPointSequenceSequence(const B2DPolyPolygon & rPolyPolygon,com::sun::star::drawing::PointSequenceSequence & rPointSequenceSequenceRetval)633         void B2DPolyPolygonToUnoPointSequenceSequence(
634             const B2DPolyPolygon& rPolyPolygon,
635             com::sun::star::drawing::PointSequenceSequence& rPointSequenceSequenceRetval)
636         {
637             const sal_uInt32 nCount(rPolyPolygon.count());
638 
639             if(nCount)
640             {
641                 rPointSequenceSequenceRetval.realloc(nCount);
642                 com::sun::star::drawing::PointSequence* pPointSequence = rPointSequenceSequenceRetval.getArray();
643 
644                 for(sal_uInt32 a(0); a < nCount; a++)
645                 {
646                     const B2DPolygon aPolygon(rPolyPolygon.getB2DPolygon(a));
647 
648                     B2DPolygonToUnoPointSequence(aPolygon, *pPointSequence);
649                     pPointSequence++;
650                 }
651             }
652             else
653             {
654                 rPointSequenceSequenceRetval.realloc(0);
655             }
656         }
657 
658         //////////////////////////////////////////////////////////////////////////////
659         // converters for com::sun::star::drawing::PolyPolygonBezierCoords (curved polygons)
660 
UnoPolyPolygonBezierCoordsToB2DPolyPolygon(const com::sun::star::drawing::PolyPolygonBezierCoords & rPolyPolygonBezierCoordsSource,bool bCheckClosed)661         B2DPolyPolygon UnoPolyPolygonBezierCoordsToB2DPolyPolygon(
662             const com::sun::star::drawing::PolyPolygonBezierCoords& rPolyPolygonBezierCoordsSource,
663             bool bCheckClosed)
664         {
665             B2DPolyPolygon aRetval;
666             const sal_uInt32 nSequenceCount((sal_uInt32)rPolyPolygonBezierCoordsSource.Coordinates.getLength());
667 
668             if(nSequenceCount)
669             {
670                 OSL_ENSURE(nSequenceCount == (sal_uInt32)rPolyPolygonBezierCoordsSource.Flags.getLength(),
671                     "UnoPolyPolygonBezierCoordsToB2DPolyPolygon: unequal number of Points and Flags (!)");
672                 const com::sun::star::drawing::PointSequence* pPointSequence = rPolyPolygonBezierCoordsSource.Coordinates.getConstArray();
673                 const com::sun::star::drawing::FlagSequence* pFlagSequence = rPolyPolygonBezierCoordsSource.Flags.getConstArray();
674 
675                 for(sal_uInt32 a(0); a < nSequenceCount; a++)
676                 {
677                     const B2DPolygon aNewPolygon(UnoPolygonBezierCoordsToB2DPolygon(
678                         *pPointSequence,
679                         *pFlagSequence,
680                         bCheckClosed));
681 
682                     pPointSequence++;
683                     pFlagSequence++;
684                     aRetval.append(aNewPolygon);
685                 }
686             }
687 
688             return aRetval;
689         }
690 
B2DPolyPolygonToUnoPolyPolygonBezierCoords(const B2DPolyPolygon & rPolyPolygon,com::sun::star::drawing::PolyPolygonBezierCoords & rPolyPolygonBezierCoordsRetval)691         void B2DPolyPolygonToUnoPolyPolygonBezierCoords(
692             const B2DPolyPolygon& rPolyPolygon,
693             com::sun::star::drawing::PolyPolygonBezierCoords& rPolyPolygonBezierCoordsRetval)
694         {
695             const sal_uInt32 nCount(rPolyPolygon.count());
696 
697             if(nCount)
698             {
699                 // prepare return value memory
700                 rPolyPolygonBezierCoordsRetval.Coordinates.realloc((sal_Int32)nCount);
701                 rPolyPolygonBezierCoordsRetval.Flags.realloc((sal_Int32)nCount);
702 
703                 // get pointers to arrays
704                 com::sun::star::drawing::PointSequence* pPointSequence = rPolyPolygonBezierCoordsRetval.Coordinates.getArray();
705                 com::sun::star::drawing::FlagSequence*  pFlagSequence = rPolyPolygonBezierCoordsRetval.Flags.getArray();
706 
707                 for(sal_uInt32 a(0); a < nCount; a++)
708                 {
709                     const B2DPolygon aSource(rPolyPolygon.getB2DPolygon(a));
710 
711                     B2DPolygonToUnoPolygonBezierCoords(
712                         aSource,
713                         *pPointSequence,
714                         *pFlagSequence);
715                     pPointSequence++;
716                     pFlagSequence++;
717                 }
718             }
719             else
720             {
721                 rPolyPolygonBezierCoordsRetval.Coordinates.realloc(0);
722                 rPolyPolygonBezierCoordsRetval.Flags.realloc(0);
723             }
724         }
725 
726     } // end of namespace tools
727 } // end of namespace basegfx
728 
729 //////////////////////////////////////////////////////////////////////////////
730 // eof
731