1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <basegfx/polygon/b2dpolypolygontools.hxx>
21 #include <osl/diagnose.h>
22 #include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
23 #include <basegfx/polygon/b2dpolypolygon.hxx>
24 #include <basegfx/polygon/b2dpolygon.hxx>
25 #include <basegfx/polygon/b2dpolygontools.hxx>
26 #include <basegfx/numeric/ftools.hxx>
27 #include <rtl/math.hxx>
28 
29 #include <algorithm>
30 #include <numeric>
31 
32 namespace basegfx::utils
33 {
correctOrientations(const B2DPolyPolygon & rCandidate)34         B2DPolyPolygon correctOrientations(const B2DPolyPolygon& rCandidate)
35         {
36             B2DPolyPolygon aRetval(rCandidate);
37             const sal_uInt32 nCount(aRetval.count());
38 
39             for(sal_uInt32 a(0); a < nCount; a++)
40             {
41                 const B2DPolygon& aCandidate(rCandidate.getB2DPolygon(a));
42                 const B2VectorOrientation aOrientation(utils::getOrientation(aCandidate));
43                 sal_uInt32 nDepth(0);
44 
45                 for(sal_uInt32 b(0); b < nCount; b++)
46                 {
47                     if(b != a)
48                     {
49                         const B2DPolygon& aCompare(rCandidate.getB2DPolygon(b));
50 
51                         if(utils::isInside(aCompare, aCandidate, true))
52                         {
53                             nDepth++;
54                         }
55                     }
56                 }
57 
58                 const bool bShallBeHole((nDepth & 0x00000001) == 1);
59                 const bool bIsHole(aOrientation == B2VectorOrientation::Negative);
60 
61                 if(bShallBeHole != bIsHole && aOrientation != B2VectorOrientation::Neutral)
62                 {
63                     B2DPolygon aFlipped(aCandidate);
64                     aFlipped.flip();
65                     aRetval.setB2DPolygon(a, aFlipped);
66                 }
67             }
68 
69             return aRetval;
70         }
71 
correctOutmostPolygon(const B2DPolyPolygon & rCandidate)72         B2DPolyPolygon correctOutmostPolygon(const B2DPolyPolygon& rCandidate)
73         {
74             const sal_uInt32 nCount(rCandidate.count());
75 
76             if(nCount > 1)
77             {
78                 for(sal_uInt32 a(0); a < nCount; a++)
79                 {
80                     const B2DPolygon& aCandidate(rCandidate.getB2DPolygon(a));
81                     sal_uInt32 nDepth(0);
82 
83                     for(sal_uInt32 b(0); b < nCount; b++)
84                     {
85                         if(b != a)
86                         {
87                             const B2DPolygon& aCompare(rCandidate.getB2DPolygon(b));
88 
89                             if(utils::isInside(aCompare, aCandidate, true))
90                             {
91                                 nDepth++;
92                             }
93                         }
94                     }
95 
96                     if(!nDepth)
97                     {
98                         B2DPolyPolygon aRetval(rCandidate);
99 
100                         if(a != 0)
101                         {
102                             // exchange polygon a and polygon 0
103                             aRetval.setB2DPolygon(0, aCandidate);
104                             aRetval.setB2DPolygon(a, rCandidate.getB2DPolygon(0));
105                         }
106 
107                         // exit
108                         return aRetval;
109                     }
110                 }
111             }
112 
113             return rCandidate;
114         }
115 
adaptiveSubdivideByDistance(const B2DPolyPolygon & rCandidate,double fDistanceBound)116         B2DPolyPolygon adaptiveSubdivideByDistance(const B2DPolyPolygon& rCandidate, double fDistanceBound)
117         {
118             if(rCandidate.areControlPointsUsed())
119             {
120                 B2DPolyPolygon aRetval;
121 
122                 for(auto const& rPolygon : rCandidate)
123                 {
124                     if(rPolygon.areControlPointsUsed())
125                     {
126                         aRetval.append(utils::adaptiveSubdivideByDistance(rPolygon, fDistanceBound));
127                     }
128                     else
129                     {
130                         aRetval.append(rPolygon);
131                     }
132                 }
133 
134                 return aRetval;
135             }
136             else
137             {
138                 return rCandidate;
139             }
140         }
141 
adaptiveSubdivideByAngle(const B2DPolyPolygon & rCandidate,double fAngleBound)142         B2DPolyPolygon adaptiveSubdivideByAngle(const B2DPolyPolygon& rCandidate, double fAngleBound)
143         {
144             if(rCandidate.areControlPointsUsed())
145             {
146                 B2DPolyPolygon aRetval;
147 
148                 for(auto const& rPolygon : rCandidate)
149                 {
150                     if(rPolygon.areControlPointsUsed())
151                     {
152                         aRetval.append(utils::adaptiveSubdivideByAngle(rPolygon, fAngleBound));
153                     }
154                     else
155                     {
156                         aRetval.append(rPolygon);
157                     }
158                 }
159 
160                 return aRetval;
161             }
162             else
163             {
164                 return rCandidate;
165             }
166         }
167 
isInside(const B2DPolyPolygon & rCandidate,const B2DPoint & rPoint,bool bWithBorder)168         bool isInside(const B2DPolyPolygon& rCandidate, const B2DPoint& rPoint, bool bWithBorder)
169         {
170             if(rCandidate.count() == 1)
171             {
172                 return isInside(rCandidate.getB2DPolygon(0), rPoint, bWithBorder);
173             }
174             else
175             {
176                 sal_Int32 nInsideCount = std::count_if(rCandidate.begin(), rCandidate.end(), [rPoint, bWithBorder](B2DPolygon polygon){ return isInside(polygon, rPoint, bWithBorder); });
177 
178                 return (nInsideCount % 2);
179             }
180         }
181 
getRange(const B2DPolyPolygon & rCandidate)182         B2DRange getRange(const B2DPolyPolygon& rCandidate)
183         {
184             B2DRange aRetval;
185 
186             for(auto const& rPolygon : rCandidate)
187             {
188                 aRetval.expand(utils::getRange(rPolygon));
189             }
190 
191             return aRetval;
192         }
193 
getSignedArea(const B2DPolyPolygon & rCandidate)194         double getSignedArea(const B2DPolyPolygon& rCandidate)
195         {
196             double fRetval(0.0);
197 
198             for(auto const& rPolygon : rCandidate)
199             {
200                 fRetval += utils::getSignedArea(rPolygon);
201             }
202 
203             return fRetval;
204         }
205 
getArea(const B2DPolyPolygon & rCandidate)206         double getArea(const B2DPolyPolygon& rCandidate)
207         {
208             return fabs(getSignedArea(rCandidate));
209         }
210 
applyLineDashing(const B2DPolyPolygon & rCandidate,const std::vector<double> & rDotDashArray,B2DPolyPolygon * pLineTarget,double fFullDashDotLen)211         void applyLineDashing(const B2DPolyPolygon& rCandidate, const std::vector<double>& rDotDashArray, B2DPolyPolygon* pLineTarget, double fFullDashDotLen)
212         {
213             if(fFullDashDotLen == 0.0 && !rDotDashArray.empty())
214             {
215                 // calculate fFullDashDotLen from rDotDashArray
216                 fFullDashDotLen = std::accumulate(rDotDashArray.begin(), rDotDashArray.end(), 0.0);
217             }
218 
219             if(!(rCandidate.count() && fFullDashDotLen > 0.0))
220                 return;
221 
222             B2DPolyPolygon aLineTarget;
223 
224             for(auto const& rPolygon : rCandidate)
225             {
226                 applyLineDashing(
227                     rPolygon,
228                     rDotDashArray,
229                     pLineTarget ? &aLineTarget : nullptr,
230                     nullptr,
231                     fFullDashDotLen);
232 
233                 if(pLineTarget)
234                 {
235                     pLineTarget->append(aLineTarget);
236                 }
237             }
238         }
239 
isInEpsilonRange(const B2DPolyPolygon & rCandidate,const B2DPoint & rTestPosition,double fDistance)240         bool isInEpsilonRange(const B2DPolyPolygon& rCandidate, const B2DPoint& rTestPosition, double fDistance)
241         {
242             for(auto const& rPolygon : rCandidate)
243             {
244                 if(isInEpsilonRange(rPolygon, rTestPosition, fDistance))
245                 {
246                     return true;
247                 }
248             }
249 
250             return false;
251         }
252 
createB3DPolyPolygonFromB2DPolyPolygon(const B2DPolyPolygon & rCandidate,double fZCoordinate)253         B3DPolyPolygon createB3DPolyPolygonFromB2DPolyPolygon(const B2DPolyPolygon& rCandidate, double fZCoordinate)
254         {
255             B3DPolyPolygon aRetval;
256 
257             for(auto const& rPolygon : rCandidate)
258             {
259                 aRetval.append(createB3DPolygonFromB2DPolygon(rPolygon, fZCoordinate));
260             }
261 
262             return aRetval;
263         }
264 
createB2DPolyPolygonFromB3DPolyPolygon(const B3DPolyPolygon & rCandidate,const B3DHomMatrix & rMat)265         B2DPolyPolygon createB2DPolyPolygonFromB3DPolyPolygon(const B3DPolyPolygon& rCandidate, const B3DHomMatrix& rMat)
266         {
267             B2DPolyPolygon aRetval;
268 
269             for(auto const& rPolygon : rCandidate)
270             {
271                 aRetval.append(createB2DPolygonFromB3DPolygon(rPolygon, rMat));
272             }
273 
274             return aRetval;
275         }
276 
getSmallestDistancePointToPolyPolygon(const B2DPolyPolygon & rCandidate,const B2DPoint & rTestPoint,sal_uInt32 & rPolygonIndex,sal_uInt32 & rEdgeIndex,double & rCut)277         double getSmallestDistancePointToPolyPolygon(const B2DPolyPolygon& rCandidate, const B2DPoint& rTestPoint, sal_uInt32& rPolygonIndex, sal_uInt32& rEdgeIndex, double& rCut)
278         {
279             double fRetval(DBL_MAX);
280             const double fZero(0.0);
281             const sal_uInt32 nPolygonCount(rCandidate.count());
282 
283             for(sal_uInt32 a(0); a < nPolygonCount; a++)
284             {
285                 const B2DPolygon& aCandidate(rCandidate.getB2DPolygon(a));
286                 sal_uInt32 nNewEdgeIndex;
287                 double fNewCut(0.0);
288                 const double fNewDistance(getSmallestDistancePointToPolygon(aCandidate, rTestPoint, nNewEdgeIndex, fNewCut));
289 
290                 if(fRetval == DBL_MAX || fNewDistance < fRetval)
291                 {
292                     fRetval = fNewDistance;
293                     rPolygonIndex = a;
294                     rEdgeIndex = nNewEdgeIndex;
295                     rCut = fNewCut;
296 
297                     if(fTools::equal(fRetval, fZero))
298                     {
299                         // already found zero distance, cannot get better. Ensure numerical zero value and end loop.
300                         fRetval = 0.0;
301                         break;
302                     }
303                 }
304             }
305 
306             return fRetval;
307         }
308 
distort(const B2DPolyPolygon & rCandidate,const B2DRange & rOriginal,const B2DPoint & rTopLeft,const B2DPoint & rTopRight,const B2DPoint & rBottomLeft,const B2DPoint & rBottomRight)309         B2DPolyPolygon distort(const B2DPolyPolygon& rCandidate, const B2DRange& rOriginal, const B2DPoint& rTopLeft, const B2DPoint& rTopRight, const B2DPoint& rBottomLeft, const B2DPoint& rBottomRight)
310         {
311             B2DPolyPolygon aRetval;
312 
313             for(auto const& rPolygon : rCandidate)
314             {
315                 aRetval.append(distort(rPolygon, rOriginal, rTopLeft, rTopRight, rBottomLeft, rBottomRight));
316             }
317 
318             return aRetval;
319         }
320 
expandToCurve(const B2DPolyPolygon & rCandidate)321         B2DPolyPolygon expandToCurve(const B2DPolyPolygon& rCandidate)
322         {
323             B2DPolyPolygon aRetval;
324 
325             for(auto const& rPolygon : rCandidate)
326             {
327                 aRetval.append(expandToCurve(rPolygon));
328             }
329 
330             return aRetval;
331         }
332 
growInNormalDirection(const B2DPolyPolygon & rCandidate,double fValue)333         B2DPolyPolygon growInNormalDirection(const B2DPolyPolygon& rCandidate, double fValue)
334         {
335             if(fValue != 0.0)
336             {
337                 B2DPolyPolygon aRetval;
338 
339                 for(auto const& rPolygon : rCandidate)
340                 {
341                     aRetval.append(growInNormalDirection(rPolygon, fValue));
342                 }
343 
344                 return aRetval;
345             }
346             else
347             {
348                 return rCandidate;
349             }
350         }
351 
reSegmentPolyPolygon(const B2DPolyPolygon & rCandidate,sal_uInt32 nSegments)352         B2DPolyPolygon reSegmentPolyPolygon(const B2DPolyPolygon& rCandidate, sal_uInt32 nSegments)
353         {
354             B2DPolyPolygon aRetval;
355 
356             for(auto const& rPolygon : rCandidate)
357             {
358                 aRetval.append(reSegmentPolygon(rPolygon, nSegments));
359             }
360 
361             return aRetval;
362         }
363 
interpolate(const B2DPolyPolygon & rOld1,const B2DPolyPolygon & rOld2,double t)364         B2DPolyPolygon interpolate(const B2DPolyPolygon& rOld1, const B2DPolyPolygon& rOld2, double t)
365         {
366             OSL_ENSURE(rOld1.count() == rOld2.count(), "B2DPolyPolygon interpolate: Different geometry (!)");
367             B2DPolyPolygon aRetval;
368 
369             for(sal_uInt32 a(0); a < rOld1.count(); a++)
370             {
371                 aRetval.append(interpolate(rOld1.getB2DPolygon(a), rOld2.getB2DPolygon(a), t));
372             }
373 
374             return aRetval;
375         }
376 
isRectangle(const B2DPolyPolygon & rPoly)377         bool isRectangle( const B2DPolyPolygon& rPoly )
378         {
379             // exclude some cheap cases first
380             if( rPoly.count() != 1 )
381                 return false;
382 
383             return isRectangle( rPoly.getB2DPolygon(0) );
384         }
385 
386         // #i76891#
simplifyCurveSegments(const B2DPolyPolygon & rCandidate)387         B2DPolyPolygon simplifyCurveSegments(const B2DPolyPolygon& rCandidate)
388         {
389             if(rCandidate.areControlPointsUsed())
390             {
391                 B2DPolyPolygon aRetval;
392 
393                 for(auto const& rPolygon : rCandidate)
394                 {
395                     aRetval.append(simplifyCurveSegments(rPolygon));
396                 }
397 
398                 return aRetval;
399             }
400             else
401             {
402                 return rCandidate;
403             }
404         }
405 
snapPointsOfHorizontalOrVerticalEdges(const B2DPolyPolygon & rCandidate)406         B2DPolyPolygon snapPointsOfHorizontalOrVerticalEdges(const B2DPolyPolygon& rCandidate)
407         {
408             B2DPolyPolygon aRetval;
409 
410             for(auto const& rPolygon : rCandidate)
411             {
412                 aRetval.append(snapPointsOfHorizontalOrVerticalEdges(rPolygon));
413             }
414 
415             return aRetval;
416         }
417 
createSevenSegmentPolyPolygon(char nNumber,bool bLitSegments)418         B2DPolyPolygon createSevenSegmentPolyPolygon(char nNumber, bool bLitSegments)
419         {
420             // config here
421             // {
422             const double fTotalSize=1.0;
423             const double fPosMiddleSegment=0.6;
424             const double fSegmentEndChopHoriz=0.08;
425             const double fSegmentEndChopVert =0.04;
426             // }
427             // config here
428 
429             const double fLeft=0.0;
430             const double fRight=fTotalSize;
431             const double fTop=0.0;
432             const double fMiddle=fPosMiddleSegment;
433             const double fBottom=fTotalSize;
434 
435             // from 0 to 5: pair of segment corner coordinates
436 
437             // segment corner indices are these:
438 
439             //   0 - 1
440             //   |   |
441             //   2 - 3
442             //   |   |
443             //   4 - 5
444 
445             static const double corners[] =
446             {
447                 fLeft,  fTop,
448                 fRight, fTop,
449                 fLeft,  fMiddle,
450                 fRight, fMiddle,
451                 fLeft,  fBottom,
452                 fRight, fBottom
453             };
454 
455             // from 0 to 9: which segments are 'lit' for this number?
456 
457             // array denotes graph edges to traverse, with -1 means
458             // stop (the vertices are the corner indices from above):
459             //     0
460             //     -
461             // 1 |   | 2
462             //     - 3
463             // 4 |   | 5
464             //     -
465             //     6
466 
467             static const int numbers[] =
468             {
469                 1, 1, 1, 0, 1, 1, 1, // 0
470                 0, 0, 1, 0, 0, 1, 0, // 1
471                 1, 0, 1, 1, 1, 0, 1, // 2
472                 1, 0, 1, 1, 0, 1, 1, // 3
473                 0, 1, 1, 1, 0, 1, 0, // 4
474                 1, 1, 0, 1, 0, 1, 1, // 5
475                 1, 1, 0, 1, 1, 1, 1, // 6
476                 1, 0, 1, 0, 0, 1, 0, // 1
477                 1, 1, 1, 1, 1, 1, 1, // 8
478                 1, 1, 1, 1, 0, 1, 1, // 9
479                 0, 0, 0, 1, 0, 0, 0, // '-'
480                 1, 1, 0, 1, 1, 0, 1, // 'E'
481             };
482 
483             // maps segment index to two corner ids:
484             static const int index2corner[] =
485             {
486                 0, 2,  // 0
487                 0, 4,  // 1
488                 2, 6,  // 2
489                 4, 6,  // 3
490                 4, 8,  // 4
491                 6, 10, // 5
492                 8, 10, // 6
493             };
494 
495             B2DPolyPolygon aRes;
496             if( nNumber == '-' )
497             {
498                 nNumber = 10;
499             }
500             else if( nNumber == 'E' )
501             {
502                 nNumber = 11;
503             }
504             else if( nNumber == '.' )
505             {
506                 if( bLitSegments )
507                     aRes.append(createPolygonFromCircle(B2DPoint(fTotalSize/2, fTotalSize),
508                                                         fSegmentEndChopHoriz));
509                 return aRes;
510             }
511             else
512             {
513                 nNumber=std::clamp<sal_uInt32>(nNumber,'0','9') - '0';
514             }
515 
516             B2DPolygon aCurrSegment;
517             const size_t sliceSize=SAL_N_ELEMENTS(numbers)/12;
518             const int* pCurrSegment=numbers + nNumber*sliceSize;
519             for( size_t i=0; i<sliceSize; i++, pCurrSegment++)
520             {
521                 if( !(*pCurrSegment ^ int(bLitSegments)) )
522                 {
523                     const size_t j=2*i;
524                     aCurrSegment.clear();
525                     B2DPoint start(corners[index2corner[j]],
526                                    corners[index2corner[j]+1]  );
527                     B2DPoint end  (corners[index2corner[j+1]],
528                                    corners[index2corner[j+1]+1]);
529 
530                     if( rtl::math::approxEqual(start.getX(), end.getX()) )
531                     {
532                         start.setY(start.getY()+fSegmentEndChopVert);
533                         end.setY(end.getY()-fSegmentEndChopVert);
534                     }
535                     else
536                     {
537                         start.setX(start.getX()+fSegmentEndChopHoriz);
538                         end.setX(end.getX()-fSegmentEndChopHoriz);
539                     }
540 
541                     aCurrSegment.append(start);
542                     aCurrSegment.append(end);
543                 }
544                 aRes.append(aCurrSegment);
545             }
546 
547             return aRes;
548         }
549 
550         // converters for css::drawing::PointSequence
551 
UnoPointSequenceSequenceToB2DPolyPolygon(const css::drawing::PointSequenceSequence & rPointSequenceSequenceSource)552         B2DPolyPolygon UnoPointSequenceSequenceToB2DPolyPolygon(
553             const css::drawing::PointSequenceSequence& rPointSequenceSequenceSource)
554         {
555             B2DPolyPolygon aRetval;
556             const css::drawing::PointSequence* pPointSequence = rPointSequenceSequenceSource.getConstArray();
557             const css::drawing::PointSequence* pPointSeqEnd = pPointSequence + rPointSequenceSequenceSource.getLength();
558 
559             for(;pPointSequence != pPointSeqEnd; pPointSequence++)
560             {
561                 const B2DPolygon aNewPolygon = UnoPointSequenceToB2DPolygon(*pPointSequence);
562                 aRetval.append(aNewPolygon);
563             }
564 
565             return aRetval;
566         }
567 
B2DPolyPolygonToUnoPointSequenceSequence(const B2DPolyPolygon & rPolyPolygon,css::drawing::PointSequenceSequence & rPointSequenceSequenceRetval)568         void B2DPolyPolygonToUnoPointSequenceSequence(
569             const B2DPolyPolygon& rPolyPolygon,
570             css::drawing::PointSequenceSequence& rPointSequenceSequenceRetval)
571         {
572             const sal_uInt32 nCount(rPolyPolygon.count());
573 
574             if(nCount)
575             {
576                 rPointSequenceSequenceRetval.realloc(nCount);
577                 css::drawing::PointSequence* pPointSequence = rPointSequenceSequenceRetval.getArray();
578 
579                 for(auto const& rPolygon : rPolyPolygon)
580                 {
581                     B2DPolygonToUnoPointSequence(rPolygon, *pPointSequence);
582                     pPointSequence++;
583                 }
584             }
585             else
586             {
587                 rPointSequenceSequenceRetval.realloc(0);
588             }
589         }
590 
591         // converters for css::drawing::PolyPolygonBezierCoords (curved polygons)
592 
UnoPolyPolygonBezierCoordsToB2DPolyPolygon(const css::drawing::PolyPolygonBezierCoords & rPolyPolygonBezierCoordsSource)593         B2DPolyPolygon UnoPolyPolygonBezierCoordsToB2DPolyPolygon(
594             const css::drawing::PolyPolygonBezierCoords& rPolyPolygonBezierCoordsSource)
595         {
596             B2DPolyPolygon aRetval;
597             const sal_uInt32 nSequenceCount(static_cast<sal_uInt32>(rPolyPolygonBezierCoordsSource.Coordinates.getLength()));
598 
599             if(nSequenceCount)
600             {
601                 OSL_ENSURE(nSequenceCount == static_cast<sal_uInt32>(rPolyPolygonBezierCoordsSource.Flags.getLength()),
602                     "UnoPolyPolygonBezierCoordsToB2DPolyPolygon: unequal number of Points and Flags (!)");
603                 const css::drawing::PointSequence* pPointSequence = rPolyPolygonBezierCoordsSource.Coordinates.getConstArray();
604                 const css::drawing::FlagSequence* pFlagSequence = rPolyPolygonBezierCoordsSource.Flags.getConstArray();
605 
606                 for(sal_uInt32 a(0); a < nSequenceCount; a++)
607                 {
608                     const B2DPolygon aNewPolygon(UnoPolygonBezierCoordsToB2DPolygon(
609                         *pPointSequence,
610                         *pFlagSequence));
611 
612                     pPointSequence++;
613                     pFlagSequence++;
614                     aRetval.append(aNewPolygon);
615                 }
616             }
617 
618             return aRetval;
619         }
620 
B2DPolyPolygonToUnoPolyPolygonBezierCoords(const B2DPolyPolygon & rPolyPolygon,css::drawing::PolyPolygonBezierCoords & rPolyPolygonBezierCoordsRetval)621         void B2DPolyPolygonToUnoPolyPolygonBezierCoords(
622             const B2DPolyPolygon& rPolyPolygon,
623             css::drawing::PolyPolygonBezierCoords& rPolyPolygonBezierCoordsRetval)
624         {
625             const sal_uInt32 nCount(rPolyPolygon.count());
626 
627             if(nCount)
628             {
629                 // prepare return value memory
630                 rPolyPolygonBezierCoordsRetval.Coordinates.realloc(static_cast<sal_Int32>(nCount));
631                 rPolyPolygonBezierCoordsRetval.Flags.realloc(static_cast<sal_Int32>(nCount));
632 
633                 // get pointers to arrays
634                 css::drawing::PointSequence* pPointSequence = rPolyPolygonBezierCoordsRetval.Coordinates.getArray();
635                 css::drawing::FlagSequence*  pFlagSequence = rPolyPolygonBezierCoordsRetval.Flags.getArray();
636 
637                 for(auto const& rSource : rPolyPolygon)
638                 {
639                     B2DPolygonToUnoPolygonBezierCoords(
640                         rSource,
641                         *pPointSequence,
642                         *pFlagSequence);
643                     pPointSequence++;
644                     pFlagSequence++;
645                 }
646             }
647             else
648             {
649                 rPolyPolygonBezierCoordsRetval.Coordinates.realloc(0);
650                 rPolyPolygonBezierCoordsRetval.Flags.realloc(0);
651             }
652         }
653 
654 } // end of namespace
655 
656 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
657