Coverage Report

Created: 2025-12-08 09:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/basegfx/source/polygon/b2dpolygoncutandtouch.cxx
Line
Count
Source
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/b2dpolygoncutandtouch.hxx>
21
#include <osl/diagnose.h>
22
#include <sal/log.hxx>
23
#include <basegfx/numeric/ftools.hxx>
24
#include <basegfx/point/b2dpoint.hxx>
25
#include <basegfx/vector/b2dvector.hxx>
26
#include <basegfx/vector/b2enums.hxx>
27
#include <basegfx/range/b2drange.hxx>
28
#include <basegfx/polygon/b2dpolygon.hxx>
29
#include <basegfx/polygon/b2dpolypolygon.hxx>
30
#include <basegfx/polygon/b2dpolygontools.hxx>
31
#include <basegfx/curve/b2dcubicbezier.hxx>
32
33
#include <vector>
34
#include <algorithm>
35
#include <memory>
36
37
0
#define SUBDIVIDE_FOR_CUT_TEST_COUNT        (50)
38
39
namespace basegfx
40
{
41
    namespace
42
    {
43
44
        class temporaryPoint
45
        {
46
            B2DPoint                            maPoint;        // the new point
47
            sal_uInt32                          mnIndex;        // index after which to insert
48
            double                              mfCut;          // parametric cut description [0.0 .. 1.0]
49
50
        public:
51
            temporaryPoint(const B2DPoint& rNewPoint, sal_uInt32 nIndex, double fCut)
52
12.0M
            :   maPoint(rNewPoint),
53
12.0M
                mnIndex(nIndex),
54
12.0M
                mfCut(fCut)
55
12.0M
            {
56
12.0M
            }
57
58
            bool operator<(const temporaryPoint& rComp) const
59
31.7M
            {
60
31.7M
                if(mnIndex == rComp.mnIndex)
61
11.4M
                {
62
11.4M
                    return (mfCut < rComp.mfCut);
63
11.4M
                }
64
65
20.3M
                return (mnIndex < rComp.mnIndex);
66
31.7M
            }
67
68
2.69M
            const B2DPoint& getPoint() const { return maPoint; }
69
4.10M
            sal_uInt32 getIndex() const { return mnIndex; }
70
0
            double getCut() const { return mfCut; }
71
        };
72
73
        typedef std::vector< temporaryPoint > temporaryPointVector;
74
75
        class temporaryPolygonData
76
        {
77
            B2DPolygon                              maPolygon;
78
            B2DRange                                maRange;
79
            temporaryPointVector                    maPoints;
80
81
        public:
82
426k
            const B2DPolygon& getPolygon() const { return maPolygon; }
83
31.8k
            void setPolygon(const B2DPolygon& rNew) { maPolygon = rNew; maRange = maPolygon.getB2DRange(); }
84
6.06M
            const B2DRange& getRange() const { return maRange; }
85
291k
            temporaryPointVector& getTemporaryPointVector() { return maPoints; }
86
        };
87
88
        B2DPolygon mergeTemporaryPointsAndPolygon(const B2DPolygon& rCandidate, temporaryPointVector& rTempPoints)
89
490k
        {
90
            // #i76891# mergeTemporaryPointsAndPolygon redesigned to be able to correctly handle
91
            // single edges with/without control points
92
            // #i101491# added counter for non-changing element count
93
490k
            const sal_uInt32 nTempPointCount(rTempPoints.size());
94
95
490k
            if(nTempPointCount)
96
5.71k
            {
97
5.71k
                B2DPolygon aRetval;
98
5.71k
                const sal_uInt32 nCount(rCandidate.count());
99
100
5.71k
                if(nCount)
101
5.71k
                {
102
                    // sort temp points to assure increasing fCut values and increasing indices
103
5.71k
                    std::sort(rTempPoints.begin(), rTempPoints.end());
104
105
                    // prepare loop
106
5.71k
                    B2DCubicBezier aEdge;
107
5.71k
                    sal_uInt32 nNewInd(0);
108
109
                    // add start point
110
5.71k
                    aRetval.append(rCandidate.getB2DPoint(0));
111
112
1.61M
                    for(sal_uInt32 a(0); a < nCount; a++)
113
1.61M
                    {
114
                        // get edge
115
1.61M
                        rCandidate.getBezierSegment(a, aEdge);
116
117
1.61M
                        if(aEdge.isBezier())
118
0
                        {
119
                            // control vectors involved for this edge
120
0
                            double fLeftStart(0.0);
121
122
                            // now add all points targeted to be at this index
123
0
                            while (nNewInd < nTempPointCount && rTempPoints[nNewInd].getIndex() == a && fLeftStart < 1.0)
124
0
                            {
125
0
                                const temporaryPoint& rTempPoint = rTempPoints[nNewInd++];
126
127
                                // split curve segment. Splits need to come sorted and need to be < 1.0. Also,
128
                                // since original segment is consumed from left to right, the cut values need
129
                                // to be scaled to the remaining part
130
0
                                B2DCubicBezier aLeftPart;
131
0
                                const double fRelativeSplitPoint((rTempPoint.getCut() - fLeftStart) / (1.0 - fLeftStart));
132
0
                                aEdge.split(fRelativeSplitPoint, &aLeftPart, &aEdge);
133
0
                                fLeftStart = rTempPoint.getCut();
134
135
                                // add left bow
136
0
                                aRetval.appendBezierSegment(aLeftPart.getControlPointA(), aLeftPart.getControlPointB(), rTempPoint.getPoint());
137
0
                            }
138
139
                            // add remaining bow
140
0
                            aRetval.appendBezierSegment(aEdge.getControlPointA(), aEdge.getControlPointB(), aEdge.getEndPoint());
141
0
                        }
142
1.61M
                        else
143
1.61M
                        {
144
                            // add all points targeted to be at this index
145
4.30M
                            while(nNewInd < nTempPointCount && rTempPoints[nNewInd].getIndex() == a)
146
2.69M
                            {
147
2.69M
                                const temporaryPoint& rTempPoint = rTempPoints[nNewInd++];
148
2.69M
                                const B2DPoint& aNewPoint(rTempPoint.getPoint());
149
150
                                // do not add points double
151
2.69M
                                if(!aRetval.getB2DPoint(aRetval.count() - 1).equal(aNewPoint))
152
817k
                                {
153
817k
                                    aRetval.append(aNewPoint);
154
817k
                                }
155
2.69M
                            }
156
157
                            // add edge end point
158
1.61M
                            aRetval.append(aEdge.getEndPoint());
159
1.61M
                        }
160
1.61M
                    }
161
5.71k
                }
162
163
5.71k
                if(rCandidate.isClosed())
164
4.25k
                {
165
                    // set closed flag and correct last point (which is added double now).
166
4.25k
                    utils::closeWithGeometryChange(aRetval);
167
4.25k
                }
168
169
5.71k
                return aRetval;
170
5.71k
            }
171
484k
            else
172
484k
            {
173
484k
                return rCandidate;
174
484k
            }
175
490k
        }
176
177
        void adaptAndTransferCutsWithBezierSegment(
178
            const temporaryPointVector& rPointVector, const B2DPolygon& rPolygon,
179
            sal_uInt32 nInd, temporaryPointVector& rTempPoints)
180
0
        {
181
            // assuming that the subdivision to create rPolygon used equidistant pieces
182
            // (as in adaptiveSubdivideByCount) it is now possible to calculate back the
183
            // cut positions in the polygon to relative cut positions on the original bezier
184
            // segment.
185
0
            const sal_uInt32 nEdgeCount(rPolygon.count() ? rPolygon.count() - 1 : 0);
186
187
0
            if(!rPointVector.empty() && nEdgeCount)
188
0
            {
189
0
                for( const auto& rTempPoint : rPointVector )
190
0
                {
191
0
                    const double fCutPosInPolygon(static_cast<double>(rTempPoint.getIndex()) + rTempPoint.getCut());
192
0
                    const double fRelativeCutPos(fCutPosInPolygon / static_cast<double>(nEdgeCount));
193
0
                    rTempPoints.emplace_back(rTempPoint.getPoint(), nInd, fRelativeCutPos);
194
0
                }
195
0
            }
196
0
        }
197
198
    } // end of anonymous namespace
199
} // end of namespace basegfx
200
201
namespace basegfx
202
{
203
    namespace
204
    {
205
206
        // predefines for calls to this methods before method implementation
207
208
        void findCuts(const B2DPolygon& rCandidate, temporaryPointVector& rTempPoints, size_t* pPointLimit = nullptr);
209
        void findTouches(const B2DPolygon& rEdgePolygon, const B2DPolygon& rPointPolygon, temporaryPointVector& rTempPoints);
210
        void findCuts(const B2DPolygon& rCandidateA, const B2DPolygon& rCandidateB, temporaryPointVector& rTempPointsA, temporaryPointVector& rTempPointsB);
211
212
        void findEdgeCutsTwoEdges(
213
            const B2DPoint& rCurrA, const B2DPoint& rNextA,
214
            const B2DPoint& rCurrB, const B2DPoint& rNextB,
215
            sal_uInt32 nIndA, sal_uInt32 nIndB,
216
            temporaryPointVector& rTempPointsA, temporaryPointVector& rTempPointsB)
217
13.4M
        {
218
            // no null length edges
219
13.4M
            if(rCurrA.equal(rNextA) || rCurrB.equal(rNextB))
220
3.12M
                return;
221
222
            // no common start/end points, this can be no cuts
223
10.3M
            if(rCurrB.equal(rCurrA) || rCurrB.equal(rNextA) || rNextB.equal(rCurrA) || rNextB.equal(rNextA))
224
7.25M
                return;
225
226
3.09M
            const B2DVector aVecA(rNextA - rCurrA);
227
3.09M
            const B2DVector aVecB(rNextB - rCurrB);
228
3.09M
            double fCut(aVecA.cross(aVecB));
229
230
3.09M
            if(fTools::equalZero(fCut))
231
560k
                return;
232
233
2.53M
            const double fZero(0.0);
234
2.53M
            const double fOne(1.0);
235
2.53M
            fCut = (aVecB.getY() * (rCurrB.getX() - rCurrA.getX()) + aVecB.getX() * (rCurrA.getY() - rCurrB.getY())) / fCut;
236
237
2.53M
            if (!fTools::betweenOrEqualEither(fCut, fZero, fOne))
238
891k
                return;
239
240
            // it's a candidate, but also need to test parameter value of cut on line 2
241
1.64M
            double fCut2;
242
243
            // choose the more precise version
244
1.64M
            if(fabs(aVecB.getX()) > fabs(aVecB.getY()))
245
1.12M
            {
246
1.12M
                fCut2 = (rCurrA.getX() + (fCut * aVecA.getX()) - rCurrB.getX()) / aVecB.getX();
247
1.12M
            }
248
519k
            else
249
519k
            {
250
519k
                fCut2 = (rCurrA.getY() + (fCut * aVecA.getY()) - rCurrB.getY()) / aVecB.getY();
251
519k
            }
252
253
1.64M
            if (fTools::betweenOrEqualEither(fCut2, fZero, fOne))
254
816k
            {
255
                // cut is in range, add point. Two edges can have only one cut, but
256
                // add a cut point to each list. The lists may be the same for
257
                // self intersections.
258
816k
                const B2DPoint aCutPoint(interpolate(rCurrA, rNextA, fCut));
259
816k
                rTempPointsA.emplace_back(aCutPoint, nIndA, fCut);
260
816k
                rTempPointsB.emplace_back(aCutPoint, nIndB, fCut2);
261
816k
            }
262
1.64M
        }
263
264
        void findCutsAndTouchesAndCommonForBezier(const B2DPolygon& rCandidateA, const B2DPolygon& rCandidateB, temporaryPointVector& rTempPointsA, temporaryPointVector& rTempPointsB)
265
0
        {
266
            // #i76891#
267
            // This new method is necessary since in findEdgeCutsBezierAndEdge and in findEdgeCutsTwoBeziers
268
            // it is not sufficient to use findCuts() recursively. This will indeed find the cuts between the
269
            // segments of the two temporarily adaptive subdivided bezier segments, but not the touches or
270
            // equal points of them.
271
            // It would be possible to find the touches using findTouches(), but at last with common points
272
            // the adding of cut points (temporary points) would fail. But for these temporarily adaptive
273
            // subdivided bezier segments, common points may be not very likely, but the bug shows that it
274
            // happens.
275
            // Touch points are a little bit more likely than common points. All in all it is best to use
276
            // a specialized method here which can profit from knowing that it is working on a special
277
            // family of B2DPolygons: no curve segments included and not closed.
278
0
            OSL_ENSURE(!rCandidateA.areControlPointsUsed() && !rCandidateB.areControlPointsUsed(), "findCutsAndTouchesAndCommonForBezier only works with subdivided polygons (!)");
279
0
            OSL_ENSURE(!rCandidateA.isClosed() && !rCandidateB.isClosed(), "findCutsAndTouchesAndCommonForBezier only works with opened polygons (!)");
280
0
            const sal_uInt32 nPointCountA(rCandidateA.count());
281
0
            const sal_uInt32 nPointCountB(rCandidateB.count());
282
283
0
            if(nPointCountA <= 1 || nPointCountB <= 1)
284
0
                return;
285
286
0
            const sal_uInt32 nEdgeCountA(nPointCountA - 1);
287
0
            const sal_uInt32 nEdgeCountB(nPointCountB - 1);
288
0
            B2DPoint aCurrA(rCandidateA.getB2DPoint(0));
289
290
0
            for(sal_uInt32 a(0); a < nEdgeCountA; a++)
291
0
            {
292
0
                const B2DPoint aNextA(rCandidateA.getB2DPoint(a + 1));
293
0
                const B2DRange aRangeA(aCurrA, aNextA);
294
0
                B2DPoint aCurrB(rCandidateB.getB2DPoint(0));
295
296
0
                for(sal_uInt32 b(0); b < nEdgeCountB; b++)
297
0
                {
298
0
                    const B2DPoint aNextB(rCandidateB.getB2DPoint(b + 1));
299
0
                    const B2DRange aRangeB(aCurrB, aNextB);
300
301
0
                    if(aRangeA.overlaps(aRangeB))
302
0
                    {
303
                        // no null length edges
304
0
                        if(!(aCurrA.equal(aNextA) || aCurrB.equal(aNextB)))
305
0
                        {
306
0
                            const B2DVector aVecA(aNextA - aCurrA);
307
0
                            const B2DVector aVecB(aNextB - aCurrB);
308
0
                            double fCutA(aVecA.cross(aVecB));
309
310
0
                            if(!fTools::equalZero(fCutA))
311
0
                            {
312
0
                                const double fZero(0.0);
313
0
                                const double fOne(1.0);
314
0
                                fCutA = (aVecB.getY() * (aCurrB.getX() - aCurrA.getX()) + aVecB.getX() * (aCurrA.getY() - aCurrB.getY())) / fCutA;
315
316
                                // use range [0.0 .. 1.0[, thus in the loop, all direct aCurrA cuts will be registered
317
                                // as 0.0 cut. The 1.0 cut will be registered in the next loop step
318
0
                                if(fTools::moreOrEqual(fCutA, fZero) && fTools::less(fCutA, fOne))
319
0
                                {
320
                                    // it's a candidate, but also need to test parameter value of cut on line 2
321
0
                                    double fCutB;
322
323
                                    // choose the more precise version
324
0
                                    if(fabs(aVecB.getX()) > fabs(aVecB.getY()))
325
0
                                    {
326
0
                                        fCutB = (aCurrA.getX() + (fCutA * aVecA.getX()) - aCurrB.getX()) / aVecB.getX();
327
0
                                    }
328
0
                                    else
329
0
                                    {
330
0
                                        fCutB = (aCurrA.getY() + (fCutA * aVecA.getY()) - aCurrB.getY()) / aVecB.getY();
331
0
                                    }
332
333
                                    // use range [0.0 .. 1.0[, thus in the loop, all direct aCurrA cuts will be registered
334
                                    // as 0.0 cut. The 1.0 cut will be registered in the next loop step
335
0
                                    if(fTools::moreOrEqual(fCutB, fZero) && fTools::less(fCutB, fOne))
336
0
                                    {
337
                                        // cut is in both ranges. Add points for A and B
338
                                        // #i111715# use fTools::equal instead of fTools::equalZero for better accuracy
339
0
                                        if(fTools::equal(fCutA, fZero))
340
0
                                        {
341
                                            // ignore for start point in first edge; this is handled
342
                                            // by outer methods and would just produce a double point
343
0
                                            if(a)
344
0
                                            {
345
0
                                                rTempPointsA.emplace_back(aCurrA, a, 0.0);
346
0
                                            }
347
0
                                        }
348
0
                                        else
349
0
                                        {
350
0
                                            const B2DPoint aCutPoint(interpolate(aCurrA, aNextA, fCutA));
351
0
                                            rTempPointsA.emplace_back(aCutPoint, a, fCutA);
352
0
                                        }
353
354
                                        // #i111715# use fTools::equal instead of fTools::equalZero for better accuracy
355
0
                                        if(fTools::equal(fCutB, fZero))
356
0
                                        {
357
                                            // ignore for start point in first edge; this is handled
358
                                            // by outer methods and would just produce a double point
359
0
                                            if(b)
360
0
                                            {
361
0
                                                rTempPointsB.emplace_back(aCurrB, b, 0.0);
362
0
                                            }
363
0
                                        }
364
0
                                        else
365
0
                                        {
366
0
                                            const B2DPoint aCutPoint(interpolate(aCurrB, aNextB, fCutB));
367
0
                                            rTempPointsB.emplace_back(aCutPoint, b, fCutB);
368
0
                                        }
369
0
                                    }
370
0
                                }
371
0
                            }
372
0
                        }
373
0
                    }
374
375
                    // prepare next step
376
0
                    aCurrB = aNextB;
377
0
                }
378
379
                // prepare next step
380
0
                aCurrA = aNextA;
381
0
            }
382
0
        }
383
384
        void findEdgeCutsBezierAndEdge(
385
            const B2DCubicBezier& rCubicA,
386
            const B2DPoint& rCurrB, const B2DPoint& rNextB,
387
            sal_uInt32 nIndA, sal_uInt32 nIndB,
388
            temporaryPointVector& rTempPointsA, temporaryPointVector& rTempPointsB)
389
0
        {
390
            // find all cuts between given bezier segment and edge. Add an entry to the tempPoints
391
            // for each common point with the cut value describing the relative position on given
392
            // bezier segment and edge.
393
0
            B2DPolygon aTempPolygonA;
394
0
            B2DPolygon aTempPolygonEdge;
395
0
            temporaryPointVector aTempPointVectorA;
396
0
            temporaryPointVector aTempPointVectorEdge;
397
398
            // create subdivided polygons and find cuts between them
399
            // Keep adaptiveSubdivideByCount due to needed quality
400
0
            aTempPolygonA.reserve(SUBDIVIDE_FOR_CUT_TEST_COUNT + 8);
401
0
            aTempPolygonA.append(rCubicA.getStartPoint());
402
0
            rCubicA.adaptiveSubdivideByCount(aTempPolygonA, SUBDIVIDE_FOR_CUT_TEST_COUNT);
403
0
            aTempPolygonEdge.append(rCurrB);
404
0
            aTempPolygonEdge.append(rNextB);
405
406
            // #i76891# using findCuts recursively is not sufficient here
407
0
            findCutsAndTouchesAndCommonForBezier(aTempPolygonA, aTempPolygonEdge, aTempPointVectorA, aTempPointVectorEdge);
408
409
0
            if(!aTempPointVectorA.empty())
410
0
            {
411
                // adapt tempVector entries to segment
412
0
                adaptAndTransferCutsWithBezierSegment(aTempPointVectorA, aTempPolygonA, nIndA, rTempPointsA);
413
0
            }
414
415
            // append remapped tempVector entries for edge to tempPoints for edge
416
0
            for(const temporaryPoint & rTempPoint : aTempPointVectorEdge)
417
0
            {
418
0
                rTempPointsB.emplace_back(rTempPoint.getPoint(), nIndB, rTempPoint.getCut());
419
0
            }
420
0
        }
421
422
        void findEdgeCutsTwoBeziers(
423
            const B2DCubicBezier& rCubicA,
424
            const B2DCubicBezier& rCubicB,
425
            sal_uInt32 nIndA, sal_uInt32 nIndB,
426
            temporaryPointVector& rTempPointsA, temporaryPointVector& rTempPointsB)
427
0
        {
428
            // find all cuts between the two given bezier segments. Add an entry to the tempPoints
429
            // for each common point with the cut value describing the relative position on given
430
            // bezier segments.
431
0
            B2DPolygon aTempPolygonA;
432
0
            B2DPolygon aTempPolygonB;
433
0
            temporaryPointVector aTempPointVectorA;
434
0
            temporaryPointVector aTempPointVectorB;
435
436
            // create subdivided polygons and find cuts between them
437
            // Keep adaptiveSubdivideByCount due to needed quality
438
0
            aTempPolygonA.reserve(SUBDIVIDE_FOR_CUT_TEST_COUNT + 8);
439
0
            aTempPolygonA.append(rCubicA.getStartPoint());
440
0
            rCubicA.adaptiveSubdivideByCount(aTempPolygonA, SUBDIVIDE_FOR_CUT_TEST_COUNT);
441
0
            aTempPolygonB.reserve(SUBDIVIDE_FOR_CUT_TEST_COUNT + 8);
442
0
            aTempPolygonB.append(rCubicB.getStartPoint());
443
0
            rCubicB.adaptiveSubdivideByCount(aTempPolygonB, SUBDIVIDE_FOR_CUT_TEST_COUNT);
444
445
            // #i76891# using findCuts recursively is not sufficient here
446
0
            findCutsAndTouchesAndCommonForBezier(aTempPolygonA, aTempPolygonB, aTempPointVectorA, aTempPointVectorB);
447
448
0
            if(!aTempPointVectorA.empty())
449
0
            {
450
                // adapt tempVector entries to segment
451
0
                adaptAndTransferCutsWithBezierSegment(aTempPointVectorA, aTempPolygonA, nIndA, rTempPointsA);
452
0
            }
453
454
0
            if(!aTempPointVectorB.empty())
455
0
            {
456
                // adapt tempVector entries to segment
457
0
                adaptAndTransferCutsWithBezierSegment(aTempPointVectorB, aTempPolygonB, nIndB, rTempPointsB);
458
0
            }
459
0
        }
460
461
        void findEdgeCutsOneBezier(
462
            const B2DCubicBezier& rCubicA,
463
            sal_uInt32 nInd, temporaryPointVector& rTempPoints)
464
0
        {
465
            // avoid expensive part of this method if possible
466
            // TODO: use hasAnyExtremum() method instead when it becomes available
467
0
            double fDummy;
468
0
            const bool bHasAnyExtremum = rCubicA.getMinimumExtremumPosition( fDummy );
469
0
            if( !bHasAnyExtremum )
470
0
                return;
471
472
            // find all self-intersections on the given bezier segment. Add an entry to the tempPoints
473
            // for each self intersection point with the cut value describing the relative position on given
474
            // bezier segment.
475
0
            B2DPolygon aTempPolygon;
476
0
            temporaryPointVector aTempPointVector;
477
478
            // create subdivided polygon and find cuts on it
479
            // Keep adaptiveSubdivideByCount due to needed quality
480
0
            aTempPolygon.reserve(SUBDIVIDE_FOR_CUT_TEST_COUNT + 8);
481
0
            aTempPolygon.append(rCubicA.getStartPoint());
482
0
            rCubicA.adaptiveSubdivideByCount(aTempPolygon, SUBDIVIDE_FOR_CUT_TEST_COUNT);
483
0
            findCuts(aTempPolygon, aTempPointVector);
484
485
0
            if(!aTempPointVector.empty())
486
0
            {
487
                // adapt tempVector entries to segment
488
0
                adaptAndTransferCutsWithBezierSegment(aTempPointVector, aTempPolygon, nInd, rTempPoints);
489
0
            }
490
0
        }
491
492
        void findCuts(const B2DPolygon& rCandidate, temporaryPointVector& rTempPoints, size_t* pPointLimit)
493
477k
        {
494
            // find out if there are edges with intersections (self-cuts). If yes, add
495
            // entries to rTempPoints accordingly
496
477k
            const sal_uInt32 nPointCount(rCandidate.count());
497
498
477k
            if(!nPointCount)
499
0
                return;
500
501
477k
            const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1);
502
503
477k
            if(!nEdgeCount)
504
2
                return;
505
506
477k
            const bool bCurvesInvolved(rCandidate.areControlPointsUsed());
507
508
477k
            if(bCurvesInvolved)
509
0
            {
510
0
                B2DCubicBezier aCubicA;
511
0
                B2DCubicBezier aCubicB;
512
513
0
                for(sal_uInt32 a(0); a < nEdgeCount - 1; a++)
514
0
                {
515
0
                    rCandidate.getBezierSegment(a, aCubicA);
516
0
                    aCubicA.testAndSolveTrivialBezier();
517
0
                    const bool bEdgeAIsCurve(aCubicA.isBezier());
518
0
                    const B2DRange aRangeA(aCubicA.getRange());
519
520
0
                    if(bEdgeAIsCurve)
521
0
                    {
522
                        // curved segments may have self-intersections, do not forget those (!)
523
0
                        findEdgeCutsOneBezier(aCubicA, a, rTempPoints);
524
0
                    }
525
526
0
                    for(sal_uInt32 b(a + 1); b < nEdgeCount; b++)
527
0
                    {
528
0
                        rCandidate.getBezierSegment(b, aCubicB);
529
0
                        aCubicB.testAndSolveTrivialBezier();
530
0
                        const B2DRange aRangeB(aCubicB.getRange());
531
532
                        // only overlapping segments need to be tested
533
                        // consecutive segments touch of course
534
0
                        bool bOverlap = false;
535
0
                        if( b > a+1)
536
0
                            bOverlap = aRangeA.overlaps(aRangeB);
537
0
                        else
538
0
                            bOverlap = aRangeA.overlapsMore(aRangeB);
539
0
                        if( bOverlap)
540
0
                        {
541
0
                            const bool bEdgeBIsCurve(aCubicB.isBezier());
542
0
                            if(bEdgeAIsCurve && bEdgeBIsCurve)
543
0
                            {
544
                                // test for bezier-bezier cuts
545
0
                                findEdgeCutsTwoBeziers(aCubicA, aCubicB, a, b, rTempPoints, rTempPoints);
546
0
                            }
547
0
                            else if(bEdgeAIsCurve)
548
0
                            {
549
                                // test for bezier-edge cuts
550
0
                                findEdgeCutsBezierAndEdge(aCubicA, aCubicB.getStartPoint(), aCubicB.getEndPoint(), a, b, rTempPoints, rTempPoints);
551
0
                            }
552
0
                            else if(bEdgeBIsCurve)
553
0
                            {
554
                                // test for bezier-edge cuts
555
0
                                findEdgeCutsBezierAndEdge(aCubicB, aCubicA.getStartPoint(), aCubicA.getEndPoint(), b, a, rTempPoints, rTempPoints);
556
0
                            }
557
0
                            else
558
0
                            {
559
                                // test for simple edge-edge cuts
560
0
                                findEdgeCutsTwoEdges(aCubicA.getStartPoint(), aCubicA.getEndPoint(), aCubicB.getStartPoint(), aCubicB.getEndPoint(),
561
0
                                    a, b, rTempPoints, rTempPoints);
562
0
                            }
563
0
                        }
564
0
                    }
565
0
                }
566
0
            }
567
477k
            else
568
477k
            {
569
477k
                B2DPoint aCurrA(rCandidate.getB2DPoint(0));
570
571
2.64M
                for(sal_uInt32 a(0); a < nEdgeCount - 1; a++)
572
2.16M
                {
573
2.16M
                    const B2DPoint aNextA(rCandidate.getB2DPoint(a + 1 == nPointCount ? 0 : a + 1));
574
2.16M
                    const B2DRange aRangeA(aCurrA, aNextA);
575
2.16M
                    B2DPoint aCurrB(rCandidate.getB2DPoint(a + 1));
576
577
159M
                    for(sal_uInt32 b(a + 1); b < nEdgeCount; b++)
578
158M
                    {
579
158M
                        const B2DPoint aNextB(rCandidate.getB2DPoint(b + 1 == nPointCount ? 0 : b + 1));
580
158M
                        const B2DRange aRangeB(aCurrB, aNextB);
581
582
                        // consecutive segments touch of course
583
158M
                        bool bOverlap = false;
584
158M
                        if( b > a+1)
585
155M
                            bOverlap = aRangeA.overlaps(aRangeB);
586
2.16M
                        else
587
2.16M
                            bOverlap = aRangeA.overlapsMore(aRangeB);
588
158M
                        if( bOverlap)
589
11.2M
                        {
590
11.2M
                            findEdgeCutsTwoEdges(aCurrA, aNextA, aCurrB, aNextB, a, b, rTempPoints, rTempPoints);
591
11.2M
                        }
592
593
158M
                        if (pPointLimit && rTempPoints.size() > *pPointLimit)
594
214k
                            break;
595
596
                        // prepare next step
597
157M
                        aCurrB = aNextB;
598
157M
                    }
599
600
                    // prepare next step
601
2.16M
                    aCurrA = aNextA;
602
2.16M
                }
603
477k
            }
604
605
477k
            if (pPointLimit)
606
31.9k
            {
607
31.9k
                if (rTempPoints.size() > *pPointLimit)
608
334
                    *pPointLimit = 0;
609
31.5k
                else
610
31.5k
                    *pPointLimit -= rTempPoints.size();
611
31.9k
            }
612
477k
        }
613
614
    } // end of anonymous namespace
615
} // end of namespace basegfx
616
617
namespace basegfx
618
{
619
    namespace
620
    {
621
622
        void findTouchesOnEdge(
623
            const B2DPoint& rCurr, const B2DPoint& rNext, const B2DPolygon& rPointPolygon,
624
            sal_uInt32 nInd, temporaryPointVector& rTempPoints)
625
30.3M
        {
626
            // find out if points from rPointPolygon are positioned on given edge. If Yes, add
627
            // points there to represent touches (which may be enter or leave nodes later).
628
30.3M
            const sal_uInt32 nPointCount(rPointPolygon.count());
629
630
30.3M
            if(!nPointCount)
631
0
                return;
632
633
30.3M
            const B2DRange aRange(rCurr, rNext);
634
30.3M
            const B2DVector aEdgeVector(rNext - rCurr);
635
30.3M
            bool bTestUsingX(fabs(aEdgeVector.getX()) > fabs(aEdgeVector.getY()));
636
637
1.35G
            for(sal_uInt32 a(0); a < nPointCount; a++)
638
1.32G
            {
639
1.32G
                const B2DPoint aTestPoint(rPointPolygon.getB2DPoint(a));
640
641
1.32G
                if(aRange.isInside(aTestPoint))
642
108M
                {
643
108M
                    if(!aTestPoint.equal(rCurr) && !aTestPoint.equal(rNext))
644
32.4M
                    {
645
32.4M
                        const B2DVector aTestVector(aTestPoint - rCurr);
646
647
32.4M
                        if(areParallel(aEdgeVector, aTestVector))
648
10.4M
                        {
649
10.4M
                            const double fCut(bTestUsingX
650
10.4M
                                ? aTestVector.getX() / aEdgeVector.getX()
651
10.4M
                                : aTestVector.getY() / aEdgeVector.getY());
652
10.4M
                            const double fZero(0.0);
653
10.4M
                            const double fOne(1.0);
654
655
10.4M
                            if(fTools::more(fCut, fZero) && fTools::less(fCut, fOne))
656
10.4M
                            {
657
10.4M
                                rTempPoints.emplace_back(aTestPoint, nInd, fCut);
658
10.4M
                            }
659
10.4M
                        }
660
32.4M
                    }
661
108M
                }
662
1.32G
            }
663
30.3M
        }
664
665
        void findTouchesOnCurve(
666
            const B2DCubicBezier& rCubicA, const B2DPolygon& rPointPolygon,
667
            sal_uInt32 nInd, temporaryPointVector& rTempPoints)
668
0
        {
669
            // find all points from rPointPolygon which touch the given bezier segment. Add an entry
670
            // for each touch to the given pointVector. The cut for that entry is the relative position on
671
            // the given bezier segment.
672
0
            B2DPolygon aTempPolygon;
673
0
            temporaryPointVector aTempPointVector;
674
675
            // create subdivided polygon and find cuts on it
676
            // Keep adaptiveSubdivideByCount due to needed quality
677
0
            aTempPolygon.reserve(SUBDIVIDE_FOR_CUT_TEST_COUNT + 8);
678
0
            aTempPolygon.append(rCubicA.getStartPoint());
679
0
            rCubicA.adaptiveSubdivideByCount(aTempPolygon, SUBDIVIDE_FOR_CUT_TEST_COUNT);
680
0
            findTouches(aTempPolygon, rPointPolygon, aTempPointVector);
681
682
0
            if(!aTempPointVector.empty())
683
0
            {
684
                // adapt tempVector entries to segment
685
0
                adaptAndTransferCutsWithBezierSegment(aTempPointVector, aTempPolygon, nInd, rTempPoints);
686
0
            }
687
0
        }
688
689
        void findTouches(const B2DPolygon& rEdgePolygon, const B2DPolygon& rPointPolygon, temporaryPointVector& rTempPoints)
690
612k
        {
691
            // find out if points from rPointPolygon touch edges from rEdgePolygon. If yes,
692
            // add entries to rTempPoints
693
612k
            const sal_uInt32 nPointCount(rPointPolygon.count());
694
612k
            const sal_uInt32 nEdgePointCount(rEdgePolygon.count());
695
696
612k
            if(!(nPointCount && nEdgePointCount))
697
0
                return;
698
699
612k
            const sal_uInt32 nEdgeCount(rEdgePolygon.isClosed() ? nEdgePointCount : nEdgePointCount - 1);
700
612k
            B2DPoint aCurr(rEdgePolygon.getB2DPoint(0));
701
702
31.2M
            for(sal_uInt32 a(0); a < nEdgeCount; a++)
703
30.5M
            {
704
30.5M
                const sal_uInt32 nNextIndex((a + 1) % nEdgePointCount);
705
30.5M
                const B2DPoint aNext(rEdgePolygon.getB2DPoint(nNextIndex));
706
707
30.5M
                if(!aCurr.equal(aNext))
708
30.3M
                {
709
30.3M
                    bool bHandleAsSimpleEdge(true);
710
711
30.3M
                    if(rEdgePolygon.areControlPointsUsed())
712
0
                    {
713
0
                        const B2DPoint aNextControlPoint(rEdgePolygon.getNextControlPoint(a));
714
0
                        const B2DPoint aPrevControlPoint(rEdgePolygon.getPrevControlPoint(nNextIndex));
715
0
                        const bool bEdgeIsCurve(!aNextControlPoint.equal(aCurr) || !aPrevControlPoint.equal(aNext));
716
717
0
                        if(bEdgeIsCurve)
718
0
                        {
719
0
                            bHandleAsSimpleEdge = false;
720
0
                            const B2DCubicBezier aCubicA(aCurr, aNextControlPoint, aPrevControlPoint, aNext);
721
0
                            findTouchesOnCurve(aCubicA, rPointPolygon, a, rTempPoints);
722
0
                        }
723
0
                    }
724
725
30.3M
                    if(bHandleAsSimpleEdge)
726
30.3M
                    {
727
30.3M
                        findTouchesOnEdge(aCurr, aNext, rPointPolygon, a, rTempPoints);
728
30.3M
                    }
729
30.3M
                }
730
731
                // next step
732
30.5M
                aCurr = aNext;
733
30.5M
            }
734
612k
        }
735
736
    } // end of anonymous namespace
737
} // end of namespace basegfx
738
739
namespace basegfx
740
{
741
    namespace
742
    {
743
744
        void findCuts(const B2DPolygon& rCandidateA, const B2DPolygon& rCandidateB, temporaryPointVector& rTempPointsA, temporaryPointVector& rTempPointsB)
745
67.5k
        {
746
            // find out if edges from both polygons cut. If so, add entries to rTempPoints which
747
            // should be added to the polygons accordingly
748
67.5k
            const sal_uInt32 nPointCountA(rCandidateA.count());
749
67.5k
            const sal_uInt32 nPointCountB(rCandidateB.count());
750
751
67.5k
            if(!(nPointCountA && nPointCountB))
752
0
                return;
753
754
67.5k
            const sal_uInt32 nEdgeCountA(rCandidateA.isClosed() ? nPointCountA : nPointCountA - 1);
755
67.5k
            const sal_uInt32 nEdgeCountB(rCandidateB.isClosed() ? nPointCountB : nPointCountB - 1);
756
757
67.5k
            if(!(nEdgeCountA && nEdgeCountB))
758
2
                return;
759
760
67.5k
            const bool bCurvesInvolved(rCandidateA.areControlPointsUsed() || rCandidateB.areControlPointsUsed());
761
762
67.5k
            if(bCurvesInvolved)
763
0
            {
764
0
                B2DCubicBezier aCubicA;
765
0
                B2DCubicBezier aCubicB;
766
767
0
                for(sal_uInt32 a(0); a < nEdgeCountA; a++)
768
0
                {
769
0
                    rCandidateA.getBezierSegment(a, aCubicA);
770
0
                    aCubicA.testAndSolveTrivialBezier();
771
0
                    const bool bEdgeAIsCurve(aCubicA.isBezier());
772
0
                    const B2DRange aRangeA(aCubicA.getRange());
773
774
0
                    for(sal_uInt32 b(0); b < nEdgeCountB; b++)
775
0
                    {
776
0
                        rCandidateB.getBezierSegment(b, aCubicB);
777
0
                        aCubicB.testAndSolveTrivialBezier();
778
0
                        const B2DRange aRangeB(aCubicB.getRange());
779
780
                        // consecutive segments touch of course
781
0
                        bool bOverlap = false;
782
0
                        if( b > a+1)
783
0
                            bOverlap = aRangeA.overlaps(aRangeB);
784
0
                        else
785
0
                            bOverlap = aRangeA.overlapsMore(aRangeB);
786
0
                        if( bOverlap)
787
0
                        {
788
0
                            const bool bEdgeBIsCurve(aCubicB.isBezier());
789
0
                            if(bEdgeAIsCurve && bEdgeBIsCurve)
790
0
                            {
791
                                // test for bezier-bezier cuts
792
0
                                findEdgeCutsTwoBeziers(aCubicA, aCubicB, a, b, rTempPointsA, rTempPointsB);
793
0
                            }
794
0
                            else if(bEdgeAIsCurve)
795
0
                            {
796
                                // test for bezier-edge cuts
797
0
                                findEdgeCutsBezierAndEdge(aCubicA, aCubicB.getStartPoint(), aCubicB.getEndPoint(), a, b, rTempPointsA, rTempPointsB);
798
0
                            }
799
0
                            else if(bEdgeBIsCurve)
800
0
                            {
801
                                // test for bezier-edge cuts
802
0
                                findEdgeCutsBezierAndEdge(aCubicB, aCubicA.getStartPoint(), aCubicA.getEndPoint(), b, a, rTempPointsB, rTempPointsA);
803
0
                            }
804
0
                            else
805
0
                            {
806
                                // test for simple edge-edge cuts
807
0
                                findEdgeCutsTwoEdges(aCubicA.getStartPoint(), aCubicA.getEndPoint(), aCubicB.getStartPoint(), aCubicB.getEndPoint(),
808
0
                                    a, b, rTempPointsA, rTempPointsB);
809
0
                            }
810
0
                        }
811
0
                    }
812
0
                }
813
0
            }
814
67.5k
            else
815
67.5k
            {
816
67.5k
                B2DPoint aCurrA(rCandidateA.getB2DPoint(0));
817
818
26.3M
                for(sal_uInt32 a(0); a < nEdgeCountA; a++)
819
26.2M
                {
820
26.2M
                    const B2DPoint aNextA(rCandidateA.getB2DPoint(a + 1 == nPointCountA ? 0 : a + 1));
821
26.2M
                    const B2DRange aRangeA(aCurrA, aNextA);
822
26.2M
                    B2DPoint aCurrB(rCandidateB.getB2DPoint(0));
823
824
357M
                    for(sal_uInt32 b(0); b < nEdgeCountB; b++)
825
331M
                    {
826
331M
                        const B2DPoint aNextB(rCandidateB.getB2DPoint(b + 1 == nPointCountB ? 0 : b + 1));
827
331M
                        const B2DRange aRangeB(aCurrB, aNextB);
828
829
                        // consecutive segments touch of course
830
331M
                        bool bOverlap = false;
831
331M
                        if( b > a+1)
832
66.9M
                            bOverlap = aRangeA.overlaps(aRangeB);
833
264M
                        else
834
264M
                            bOverlap = aRangeA.overlapsMore(aRangeB);
835
331M
                        if( bOverlap)
836
2.18M
                        {
837
                            // test for simple edge-edge cuts
838
2.18M
                            findEdgeCutsTwoEdges(aCurrA, aNextA, aCurrB, aNextB, a, b, rTempPointsA, rTempPointsB);
839
2.18M
                        }
840
841
                        // prepare next step
842
331M
                        aCurrB = aNextB;
843
331M
                    }
844
845
                    // prepare next step
846
26.2M
                    aCurrA = aNextA;
847
26.2M
                }
848
67.5k
            }
849
67.5k
        }
850
851
    } // end of anonymous namespace
852
} // end of namespace basegfx
853
854
namespace basegfx::utils
855
{
856
857
        B2DPolygon addPointsAtCutsAndTouches(const B2DPolygon& rCandidate, size_t* pPointLimit)
858
477k
        {
859
477k
            if(rCandidate.count())
860
477k
            {
861
477k
                temporaryPointVector aTempPoints;
862
863
477k
                findTouches(rCandidate, rCandidate, aTempPoints);
864
477k
                findCuts(rCandidate, aTempPoints, pPointLimit);
865
477k
                if (pPointLimit && !*pPointLimit)
866
10.3k
                {
867
10.3k
                    SAL_WARN("basegfx", "addPointsAtCutsAndTouches hit point limit");
868
10.3k
                    return rCandidate;
869
10.3k
                }
870
871
467k
                return mergeTemporaryPointsAndPolygon(rCandidate, aTempPoints);
872
477k
            }
873
0
            else
874
0
            {
875
0
                return rCandidate;
876
0
            }
877
477k
        }
878
879
        B2DPolyPolygon addPointsAtCutsAndTouches(const B2DPolyPolygon& rCandidate, size_t* pPointLimit)
880
446k
        {
881
446k
            const sal_uInt32 nCount(rCandidate.count());
882
883
446k
            if(nCount)
884
446k
            {
885
446k
                B2DPolyPolygon aRetval;
886
887
446k
                if(nCount == 1)
888
445k
                {
889
                    // remove self intersections
890
445k
                    aRetval.append(addPointsAtCutsAndTouches(rCandidate.getB2DPolygon(0), pPointLimit));
891
445k
                }
892
932
                else
893
932
                {
894
                    // first solve self cuts and self touches for all contained single polygons
895
932
                    std::unique_ptr<temporaryPolygonData[]> pTempData(new temporaryPolygonData[nCount]);
896
932
                    sal_uInt32 a, b;
897
898
32.7k
                    for(a = 0; a < nCount; a++)
899
31.8k
                    {
900
                        // use polygons with solved self intersections
901
31.8k
                        pTempData[a].setPolygon(addPointsAtCutsAndTouches(rCandidate.getB2DPolygon(a), pPointLimit));
902
31.8k
                    }
903
904
932
                    if (pPointLimit && !*pPointLimit)
905
139
                    {
906
139
                        SAL_WARN("basegfx", "addPointsAtCutsAndTouches hit point limit");
907
139
                        return rCandidate;
908
139
                    }
909
910
                    // now cuts and touches between the polygons
911
21.9k
                    for(a = 0; a < nCount; a++)
912
21.1k
                    {
913
2.06M
                        for(b = 0; b < nCount; b++)
914
2.04M
                        {
915
2.04M
                            if(a != b)
916
2.02M
                            {
917
                                // look for touches, compare each edge polygon to all other points
918
2.02M
                                if(pTempData[a].getRange().overlaps(pTempData[b].getRange()))
919
135k
                                {
920
135k
                                    findTouches(pTempData[a].getPolygon(), pTempData[b].getPolygon(), pTempData[a].getTemporaryPointVector());
921
135k
                                }
922
2.02M
                            }
923
924
2.04M
                            if(a < b)
925
1.01M
                            {
926
                                // look for cuts, compare each edge polygon to following ones
927
1.01M
                                if(pTempData[a].getRange().overlaps(pTempData[b].getRange()))
928
67.5k
                                {
929
67.5k
                                    findCuts(pTempData[a].getPolygon(), pTempData[b].getPolygon(), pTempData[a].getTemporaryPointVector(), pTempData[b].getTemporaryPointVector());
930
67.5k
                                }
931
1.01M
                            }
932
2.04M
                        }
933
21.1k
                    }
934
935
                    // consolidate the result
936
21.9k
                    for(a = 0; a < nCount; a++)
937
21.1k
                    {
938
21.1k
                        aRetval.append(mergeTemporaryPointsAndPolygon(pTempData[a].getPolygon(), pTempData[a].getTemporaryPointVector()));
939
21.1k
                    }
940
793
                }
941
942
446k
                return aRetval;
943
446k
            }
944
0
            else
945
0
            {
946
0
                return rCandidate;
947
0
            }
948
446k
        }
949
950
        B2DPolygon addPointsAtCuts(const B2DPolygon& rCandidate, const B2DPoint& rStart, const B2DPoint& rEnd)
951
1.76k
        {
952
1.76k
            const sal_uInt32 nCount(rCandidate.count());
953
954
1.76k
            if(nCount && !rStart.equal(rEnd))
955
1.76k
            {
956
1.76k
                const B2DRange aPolygonRange(rCandidate.getB2DRange());
957
1.76k
                const B2DRange aEdgeRange(rStart, rEnd);
958
959
1.76k
                if(aPolygonRange.overlaps(aEdgeRange))
960
1.76k
                {
961
1.76k
                    const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nCount : nCount - 1);
962
1.76k
                    temporaryPointVector aTempPoints;
963
1.76k
                    temporaryPointVector aUnusedTempPoints;
964
1.76k
                    B2DCubicBezier aCubic;
965
966
153k
                    for(sal_uInt32 a(0); a < nEdgeCount; a++)
967
151k
                    {
968
151k
                        rCandidate.getBezierSegment(a, aCubic);
969
151k
                        B2DRange aCubicRange(aCubic.getStartPoint(), aCubic.getEndPoint());
970
971
151k
                        if(aCubic.isBezier())
972
0
                        {
973
0
                            aCubicRange.expand(aCubic.getControlPointA());
974
0
                            aCubicRange.expand(aCubic.getControlPointB());
975
976
0
                            if(aCubicRange.overlaps(aEdgeRange))
977
0
                            {
978
0
                                findEdgeCutsBezierAndEdge(aCubic, rStart, rEnd, a, 0, aTempPoints, aUnusedTempPoints);
979
0
                            }
980
0
                        }
981
151k
                        else
982
151k
                        {
983
151k
                            if(aCubicRange.overlaps(aEdgeRange))
984
42.8k
                            {
985
42.8k
                                findEdgeCutsTwoEdges(aCubic.getStartPoint(), aCubic.getEndPoint(), rStart, rEnd, a, 0, aTempPoints, aUnusedTempPoints);
986
42.8k
                            }
987
151k
                        }
988
151k
                    }
989
990
1.76k
                    return mergeTemporaryPointsAndPolygon(rCandidate, aTempPoints);
991
1.76k
                }
992
1.76k
            }
993
994
0
            return rCandidate;
995
1.76k
        }
996
997
        B2DPolygon addPointsAtCuts(const B2DPolygon& rCandidate, const B2DPolyPolygon& rPolyMask)
998
0
        {
999
0
            const sal_uInt32 nCountA(rCandidate.count());
1000
0
            const sal_uInt32 nCountM(rPolyMask.count());
1001
1002
0
            if(nCountA && nCountM)
1003
0
            {
1004
0
                const B2DRange aRangeA(rCandidate.getB2DRange());
1005
0
                const B2DRange aRangeM(rPolyMask.getB2DRange());
1006
1007
0
                if(aRangeA.overlaps(aRangeM))
1008
0
                {
1009
0
                    const sal_uInt32 nEdgeCountA(rCandidate.isClosed() ? nCountA : nCountA - 1);
1010
0
                    temporaryPointVector aTempPointsA;
1011
0
                    temporaryPointVector aUnusedTempPointsB;
1012
1013
0
                    for(sal_uInt32 m(0); m < nCountM; m++)
1014
0
                    {
1015
0
                        const B2DPolygon& aMask(rPolyMask.getB2DPolygon(m));
1016
0
                        const sal_uInt32 nCountB(aMask.count());
1017
1018
0
                        if(nCountB)
1019
0
                        {
1020
0
                            B2DCubicBezier aCubicA;
1021
0
                            B2DCubicBezier aCubicB;
1022
1023
0
                            for(sal_uInt32 a(0); a < nEdgeCountA; a++)
1024
0
                            {
1025
0
                                rCandidate.getBezierSegment(a, aCubicA);
1026
0
                                const bool bCubicAIsCurve(aCubicA.isBezier());
1027
0
                                B2DRange aCubicRangeA(aCubicA.getStartPoint(), aCubicA.getEndPoint());
1028
1029
0
                                if(bCubicAIsCurve)
1030
0
                                {
1031
0
                                    aCubicRangeA.expand(aCubicA.getControlPointA());
1032
0
                                    aCubicRangeA.expand(aCubicA.getControlPointB());
1033
0
                                }
1034
1035
0
                                for(sal_uInt32 b(0); b < nCountB; b++)
1036
0
                                {
1037
0
                                    aMask.getBezierSegment(b, aCubicB);
1038
0
                                    const bool bCubicBIsCurve(aCubicB.isBezier());
1039
0
                                    B2DRange aCubicRangeB(aCubicB.getStartPoint(), aCubicB.getEndPoint());
1040
1041
0
                                    if(bCubicBIsCurve)
1042
0
                                    {
1043
0
                                        aCubicRangeB.expand(aCubicB.getControlPointA());
1044
0
                                        aCubicRangeB.expand(aCubicB.getControlPointB());
1045
0
                                    }
1046
1047
0
                                    if(aCubicRangeA.overlaps(aCubicRangeB))
1048
0
                                    {
1049
0
                                        if(bCubicAIsCurve && bCubicBIsCurve)
1050
0
                                        {
1051
0
                                            findEdgeCutsTwoBeziers(aCubicA, aCubicB, a, b, aTempPointsA, aUnusedTempPointsB);
1052
0
                                        }
1053
0
                                        else if(bCubicAIsCurve)
1054
0
                                        {
1055
0
                                            findEdgeCutsBezierAndEdge(aCubicA, aCubicB.getStartPoint(), aCubicB.getEndPoint(), a, b, aTempPointsA, aUnusedTempPointsB);
1056
0
                                        }
1057
0
                                        else if(bCubicBIsCurve)
1058
0
                                        {
1059
0
                                            findEdgeCutsBezierAndEdge(aCubicB, aCubicA.getStartPoint(), aCubicA.getEndPoint(), b, a, aUnusedTempPointsB, aTempPointsA);
1060
0
                                        }
1061
0
                                        else
1062
0
                                        {
1063
0
                                            findEdgeCutsTwoEdges(aCubicA.getStartPoint(), aCubicA.getEndPoint(), aCubicB.getStartPoint(), aCubicB.getEndPoint(), a, b, aTempPointsA, aUnusedTempPointsB);
1064
0
                                        }
1065
0
                                    }
1066
0
                                }
1067
0
                            }
1068
0
                        }
1069
0
                    }
1070
1071
0
                    return mergeTemporaryPointsAndPolygon(rCandidate, aTempPointsA);
1072
0
                }
1073
0
            }
1074
1075
0
            return rCandidate;
1076
0
        }
1077
1078
} // end of namespace
1079
1080
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */