Coverage Report

Created: 2026-08-14 10:22

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
300k
#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
10.6M
            :   maPoint(rNewPoint),
53
10.6M
                mnIndex(nIndex),
54
10.6M
                mfCut(fCut)
55
10.6M
            {
56
10.6M
            }
57
58
            bool operator<(const temporaryPoint& rComp) const
59
52.0M
            {
60
52.0M
                if(mnIndex == rComp.mnIndex)
61
17.9M
                {
62
17.9M
                    return (mfCut < rComp.mfCut);
63
17.9M
                }
64
65
34.1M
                return (mnIndex < rComp.mnIndex);
66
52.0M
            }
67
68
3.98M
            const B2DPoint& getPoint() const { return maPoint; }
69
5.24M
            sal_uInt32 getIndex() const { return mnIndex; }
70
4.33k
            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
244k
            const B2DPolygon& getPolygon() const { return maPolygon; }
83
14.8k
            void setPolygon(const B2DPolygon& rNew) { maPolygon = rNew; maRange = maPolygon.getB2DRange(); }
84
1.24M
            const B2DRange& getRange() const { return maRange; }
85
167k
            temporaryPointVector& getTemporaryPointVector() { return maPoints; }
86
        };
87
88
        B2DPolygon mergeTemporaryPointsAndPolygon(const B2DPolygon& rCandidate, temporaryPointVector& rTempPoints)
89
416k
        {
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
416k
            const sal_uInt32 nTempPointCount(rTempPoints.size());
94
95
416k
            if(nTempPointCount)
96
9.82k
            {
97
9.82k
                B2DPolygon aRetval;
98
9.82k
                const sal_uInt32 nCount(rCandidate.count());
99
100
9.82k
                if(nCount)
101
9.82k
                {
102
                    // sort temp points to assure increasing fCut values and increasing indices
103
9.82k
                    std::sort(rTempPoints.begin(), rTempPoints.end());
104
105
                    // prepare loop
106
9.82k
                    B2DCubicBezier aEdge;
107
9.82k
                    sal_uInt32 nNewInd(0);
108
109
                    // add start point
110
9.82k
                    aRetval.append(rCandidate.getB2DPoint(0));
111
112
1.31M
                    for(sal_uInt32 a(0); a < nCount; a++)
113
1.30M
                    {
114
                        // get edge
115
1.30M
                        rCandidate.getBezierSegment(a, aEdge);
116
117
1.30M
                        if(aEdge.isBezier())
118
977
                        {
119
                            // control vectors involved for this edge
120
977
                            double fLeftStart(0.0);
121
122
                            // now add all points targeted to be at this index
123
2.34k
                            while (nNewInd < nTempPointCount && rTempPoints[nNewInd].getIndex() == a && fLeftStart < 1.0)
124
1.37k
                            {
125
1.37k
                                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
1.37k
                                B2DCubicBezier aLeftPart;
131
1.37k
                                const double fRelativeSplitPoint((rTempPoint.getCut() - fLeftStart) / (1.0 - fLeftStart));
132
1.37k
                                aEdge.split(fRelativeSplitPoint, &aLeftPart, &aEdge);
133
1.37k
                                fLeftStart = rTempPoint.getCut();
134
135
                                // add left bow
136
1.37k
                                aRetval.appendBezierSegment(aLeftPart.getControlPointA(), aLeftPart.getControlPointB(), rTempPoint.getPoint());
137
1.37k
                            }
138
139
                            // add remaining bow
140
977
                            aRetval.appendBezierSegment(aEdge.getControlPointA(), aEdge.getControlPointB(), aEdge.getEndPoint());
141
977
                        }
142
1.30M
                        else
143
1.30M
                        {
144
                            // add all points targeted to be at this index
145
5.28M
                            while(nNewInd < nTempPointCount && rTempPoints[nNewInd].getIndex() == a)
146
3.98M
                            {
147
3.98M
                                const temporaryPoint& rTempPoint = rTempPoints[nNewInd++];
148
3.98M
                                const B2DPoint& aNewPoint(rTempPoint.getPoint());
149
150
                                // do not add points double
151
3.98M
                                if(!aRetval.getB2DPoint(aRetval.count() - 1).equal(aNewPoint))
152
1.31M
                                {
153
1.31M
                                    aRetval.append(aNewPoint);
154
1.31M
                                }
155
3.98M
                            }
156
157
                            // add edge end point
158
1.30M
                            aRetval.append(aEdge.getEndPoint());
159
1.30M
                        }
160
1.30M
                    }
161
9.82k
                }
162
163
9.82k
                if(rCandidate.isClosed())
164
6.37k
                {
165
                    // set closed flag and correct last point (which is added double now).
166
6.37k
                    utils::closeWithGeometryChange(aRetval);
167
6.37k
                }
168
169
9.82k
                return aRetval;
170
9.82k
            }
171
406k
            else
172
406k
            {
173
406k
                return rCandidate;
174
406k
            }
175
416k
        }
176
177
        void adaptAndTransferCutsWithBezierSegment(
178
            const temporaryPointVector& rPointVector, const B2DPolygon& rPolygon,
179
            sal_uInt32 nInd, temporaryPointVector& rTempPoints)
180
718
        {
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
718
            const sal_uInt32 nEdgeCount(rPolygon.count() ? rPolygon.count() - 1 : 0);
186
187
718
            if(!rPointVector.empty() && nEdgeCount)
188
718
            {
189
718
                for( const auto& rTempPoint : rPointVector )
190
1.36k
                {
191
1.36k
                    const double fCutPosInPolygon(static_cast<double>(rTempPoint.getIndex()) + rTempPoint.getCut());
192
1.36k
                    const double fRelativeCutPos(fCutPosInPolygon / static_cast<double>(nEdgeCount));
193
1.36k
                    rTempPoints.emplace_back(rTempPoint.getPoint(), nInd, fRelativeCutPos);
194
1.36k
                }
195
718
            }
196
718
        }
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
9.52M
        {
218
            // no null length edges
219
9.52M
            if(rCurrA.equal(rNextA) || rCurrB.equal(rNextB))
220
2.17M
                return;
221
222
            // no common start/end points, this can be no cuts
223
7.35M
            if(rCurrB.equal(rCurrA) || rCurrB.equal(rNextA) || rNextB.equal(rCurrA) || rNextB.equal(rNextA))
224
2.81M
                return;
225
226
4.53M
            const B2DVector aVecA(rNextA - rCurrA);
227
4.53M
            const B2DVector aVecB(rNextB - rCurrB);
228
4.53M
            double fCut(aVecA.cross(aVecB));
229
230
4.53M
            if(fTools::equalZero(fCut))
231
506k
                return;
232
233
4.02M
            const double fZero(0.0);
234
4.02M
            const double fOne(1.0);
235
4.02M
            fCut = (aVecB.getY() * (rCurrB.getX() - rCurrA.getX()) + aVecB.getX() * (rCurrA.getY() - rCurrB.getY())) / fCut;
236
237
4.02M
            if (!fTools::betweenOrEqualEither(fCut, fZero, fOne))
238
1.83M
                return;
239
240
            // it's a candidate, but also need to test parameter value of cut on line 2
241
2.19M
            double fCut2;
242
243
            // choose the more precise version
244
2.19M
            if(fabs(aVecB.getX()) > fabs(aVecB.getY()))
245
1.10M
            {
246
1.10M
                fCut2 = (rCurrA.getX() + (fCut * aVecA.getX()) - rCurrB.getX()) / aVecB.getX();
247
1.10M
            }
248
1.08M
            else
249
1.08M
            {
250
1.08M
                fCut2 = (rCurrA.getY() + (fCut * aVecA.getY()) - rCurrB.getY()) / aVecB.getY();
251
1.08M
            }
252
253
2.19M
            if (fTools::betweenOrEqualEither(fCut2, fZero, fOne))
254
1.32M
            {
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
1.32M
                const B2DPoint aCutPoint(interpolate(rCurrA, rNextA, fCut));
259
1.32M
                rTempPointsA.emplace_back(aCutPoint, nIndA, fCut);
260
1.32M
                rTempPointsB.emplace_back(aCutPoint, nIndB, fCut2);
261
1.32M
            }
262
2.19M
        }
263
264
        void findCutsAndTouchesAndCommonForBezier(const B2DPolygon& rCandidateA, const B2DPolygon& rCandidateB, temporaryPointVector& rTempPointsA, temporaryPointVector& rTempPointsB)
265
84.1k
        {
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
84.1k
            OSL_ENSURE(!rCandidateA.areControlPointsUsed() && !rCandidateB.areControlPointsUsed(), "findCutsAndTouchesAndCommonForBezier only works with subdivided polygons (!)");
279
84.1k
            OSL_ENSURE(!rCandidateA.isClosed() && !rCandidateB.isClosed(), "findCutsAndTouchesAndCommonForBezier only works with opened polygons (!)");
280
84.1k
            const sal_uInt32 nPointCountA(rCandidateA.count());
281
84.1k
            const sal_uInt32 nPointCountB(rCandidateB.count());
282
283
84.1k
            if(nPointCountA <= 1 || nPointCountB <= 1)
284
0
                return;
285
286
84.1k
            const sal_uInt32 nEdgeCountA(nPointCountA - 1);
287
84.1k
            const sal_uInt32 nEdgeCountB(nPointCountB - 1);
288
84.1k
            B2DPoint aCurrA(rCandidateA.getB2DPoint(0));
289
290
4.37M
            for(sal_uInt32 a(0); a < nEdgeCountA; a++)
291
4.29M
            {
292
4.29M
                const B2DPoint aNextA(rCandidateA.getB2DPoint(a + 1));
293
4.29M
                const B2DRange aRangeA(aCurrA, aNextA);
294
4.29M
                B2DPoint aCurrB(rCandidateB.getB2DPoint(0));
295
296
63.9M
                for(sal_uInt32 b(0); b < nEdgeCountB; b++)
297
59.6M
                {
298
59.6M
                    const B2DPoint aNextB(rCandidateB.getB2DPoint(b + 1));
299
59.6M
                    const B2DRange aRangeB(aCurrB, aNextB);
300
301
59.6M
                    if(aRangeA.overlaps(aRangeB))
302
1.24M
                    {
303
                        // no null length edges
304
1.24M
                        if(!(aCurrA.equal(aNextA) || aCurrB.equal(aNextB)))
305
1.20M
                        {
306
1.20M
                            const B2DVector aVecA(aNextA - aCurrA);
307
1.20M
                            const B2DVector aVecB(aNextB - aCurrB);
308
1.20M
                            double fCutA(aVecA.cross(aVecB));
309
310
1.20M
                            if(!fTools::equalZero(fCutA))
311
1.08M
                            {
312
1.08M
                                const double fZero(0.0);
313
1.08M
                                const double fOne(1.0);
314
1.08M
                                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
1.08M
                                if(fTools::moreOrEqual(fCutA, fZero) && fTools::less(fCutA, fOne))
319
63.4k
                                {
320
                                    // it's a candidate, but also need to test parameter value of cut on line 2
321
63.4k
                                    double fCutB;
322
323
                                    // choose the more precise version
324
63.4k
                                    if(fabs(aVecB.getX()) > fabs(aVecB.getY()))
325
62.8k
                                    {
326
62.8k
                                        fCutB = (aCurrA.getX() + (fCutA * aVecA.getX()) - aCurrB.getX()) / aVecB.getX();
327
62.8k
                                    }
328
596
                                    else
329
596
                                    {
330
596
                                        fCutB = (aCurrA.getY() + (fCutA * aVecA.getY()) - aCurrB.getY()) / aVecB.getY();
331
596
                                    }
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
63.4k
                                    if(fTools::moreOrEqual(fCutB, fZero) && fTools::less(fCutB, fOne))
336
501
                                    {
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
501
                                        if(fTools::equal(fCutA, fZero))
340
110
                                        {
341
                                            // ignore for start point in first edge; this is handled
342
                                            // by outer methods and would just produce a double point
343
110
                                            if(a)
344
29
                                            {
345
29
                                                rTempPointsA.emplace_back(aCurrA, a, 0.0);
346
29
                                            }
347
110
                                        }
348
391
                                        else
349
391
                                        {
350
391
                                            const B2DPoint aCutPoint(interpolate(aCurrA, aNextA, fCutA));
351
391
                                            rTempPointsA.emplace_back(aCutPoint, a, fCutA);
352
391
                                        }
353
354
                                        // #i111715# use fTools::equal instead of fTools::equalZero for better accuracy
355
501
                                        if(fTools::equal(fCutB, fZero))
356
94
                                        {
357
                                            // ignore for start point in first edge; this is handled
358
                                            // by outer methods and would just produce a double point
359
94
                                            if(b)
360
5
                                            {
361
5
                                                rTempPointsB.emplace_back(aCurrB, b, 0.0);
362
5
                                            }
363
94
                                        }
364
407
                                        else
365
407
                                        {
366
407
                                            const B2DPoint aCutPoint(interpolate(aCurrB, aNextB, fCutB));
367
407
                                            rTempPointsB.emplace_back(aCutPoint, b, fCutB);
368
407
                                        }
369
501
                                    }
370
63.4k
                                }
371
1.08M
                            }
372
1.20M
                        }
373
1.24M
                    }
374
375
                    // prepare next step
376
59.6M
                    aCurrB = aNextB;
377
59.6M
                }
378
379
                // prepare next step
380
4.29M
                aCurrA = aNextA;
381
4.29M
            }
382
84.1k
        }
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
62.4k
        {
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
62.4k
            B2DPolygon aTempPolygonA;
394
62.4k
            B2DPolygon aTempPolygonEdge;
395
62.4k
            temporaryPointVector aTempPointVectorA;
396
62.4k
            temporaryPointVector aTempPointVectorEdge;
397
398
            // create subdivided polygons and find cuts between them
399
            // Keep adaptiveSubdivideByCount due to needed quality
400
62.4k
            aTempPolygonA.reserve(SUBDIVIDE_FOR_CUT_TEST_COUNT + 8);
401
62.4k
            aTempPolygonA.append(rCubicA.getStartPoint());
402
62.4k
            rCubicA.adaptiveSubdivideByCount(aTempPolygonA, SUBDIVIDE_FOR_CUT_TEST_COUNT);
403
62.4k
            aTempPolygonEdge.append(rCurrB);
404
62.4k
            aTempPolygonEdge.append(rNextB);
405
406
            // #i76891# using findCuts recursively is not sufficient here
407
62.4k
            findCutsAndTouchesAndCommonForBezier(aTempPolygonA, aTempPolygonEdge, aTempPointVectorA, aTempPointVectorEdge);
408
409
62.4k
            if(!aTempPointVectorA.empty())
410
74
            {
411
                // adapt tempVector entries to segment
412
74
                adaptAndTransferCutsWithBezierSegment(aTempPointVectorA, aTempPolygonA, nIndA, rTempPointsA);
413
74
            }
414
415
            // append remapped tempVector entries for edge to tempPoints for edge
416
62.4k
            for(const temporaryPoint & rTempPoint : aTempPointVectorEdge)
417
221
            {
418
221
                rTempPointsB.emplace_back(rTempPoint.getPoint(), nIndB, rTempPoint.getCut());
419
221
            }
420
62.4k
        }
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
21.7k
        {
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
21.7k
            B2DPolygon aTempPolygonA;
432
21.7k
            B2DPolygon aTempPolygonB;
433
21.7k
            temporaryPointVector aTempPointVectorA;
434
21.7k
            temporaryPointVector aTempPointVectorB;
435
436
            // create subdivided polygons and find cuts between them
437
            // Keep adaptiveSubdivideByCount due to needed quality
438
21.7k
            aTempPolygonA.reserve(SUBDIVIDE_FOR_CUT_TEST_COUNT + 8);
439
21.7k
            aTempPolygonA.append(rCubicA.getStartPoint());
440
21.7k
            rCubicA.adaptiveSubdivideByCount(aTempPolygonA, SUBDIVIDE_FOR_CUT_TEST_COUNT);
441
21.7k
            aTempPolygonB.reserve(SUBDIVIDE_FOR_CUT_TEST_COUNT + 8);
442
21.7k
            aTempPolygonB.append(rCubicB.getStartPoint());
443
21.7k
            rCubicB.adaptiveSubdivideByCount(aTempPolygonB, SUBDIVIDE_FOR_CUT_TEST_COUNT);
444
445
            // #i76891# using findCuts recursively is not sufficient here
446
21.7k
            findCutsAndTouchesAndCommonForBezier(aTempPolygonA, aTempPolygonB, aTempPointVectorA, aTempPointVectorB);
447
448
21.7k
            if(!aTempPointVectorA.empty())
449
138
            {
450
                // adapt tempVector entries to segment
451
138
                adaptAndTransferCutsWithBezierSegment(aTempPointVectorA, aTempPolygonA, nIndA, rTempPointsA);
452
138
            }
453
454
21.7k
            if(!aTempPointVectorB.empty())
455
128
            {
456
                // adapt tempVector entries to segment
457
128
                adaptAndTransferCutsWithBezierSegment(aTempPointVectorB, aTempPolygonB, nIndB, rTempPointsB);
458
128
            }
459
21.7k
        }
460
461
        void findEdgeCutsOneBezier(
462
            const B2DCubicBezier& rCubicA,
463
            sal_uInt32 nInd, temporaryPointVector& rTempPoints)
464
1.33k
        {
465
            // avoid expensive part of this method if possible
466
            // TODO: use hasAnyExtremum() method instead when it becomes available
467
1.33k
            double fDummy;
468
1.33k
            const bool bHasAnyExtremum = rCubicA.getMinimumExtremumPosition( fDummy );
469
1.33k
            if( !bHasAnyExtremum )
470
615
                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
724
            B2DPolygon aTempPolygon;
476
724
            temporaryPointVector aTempPointVector;
477
478
            // create subdivided polygon and find cuts on it
479
            // Keep adaptiveSubdivideByCount due to needed quality
480
724
            aTempPolygon.reserve(SUBDIVIDE_FOR_CUT_TEST_COUNT + 8);
481
724
            aTempPolygon.append(rCubicA.getStartPoint());
482
724
            rCubicA.adaptiveSubdivideByCount(aTempPolygon, SUBDIVIDE_FOR_CUT_TEST_COUNT);
483
724
            findCuts(aTempPolygon, aTempPointVector);
484
485
724
            if(!aTempPointVector.empty())
486
9
            {
487
                // adapt tempVector entries to segment
488
9
                adaptAndTransferCutsWithBezierSegment(aTempPointVector, aTempPolygon, nInd, rTempPoints);
489
9
            }
490
724
        }
491
492
        void findCuts(const B2DPolygon& rCandidate, temporaryPointVector& rTempPoints, size_t* pPointLimit)
493
397k
        {
494
            // find out if there are edges with intersections (self-cuts). If yes, add
495
            // entries to rTempPoints accordingly
496
397k
            const sal_uInt32 nPointCount(rCandidate.count());
497
498
397k
            if(!nPointCount)
499
0
                return;
500
501
397k
            const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1);
502
503
397k
            if(!nEdgeCount)
504
227
                return;
505
506
397k
            const bool bCurvesInvolved(rCandidate.areControlPointsUsed());
507
508
397k
            if(bCurvesInvolved)
509
1.03k
            {
510
1.03k
                B2DCubicBezier aCubicA;
511
1.03k
                B2DCubicBezier aCubicB;
512
513
5.27k
                for(sal_uInt32 a(0); a < nEdgeCount - 1; a++)
514
4.23k
                {
515
4.23k
                    rCandidate.getBezierSegment(a, aCubicA);
516
4.23k
                    aCubicA.testAndSolveTrivialBezier();
517
4.23k
                    const bool bEdgeAIsCurve(aCubicA.isBezier());
518
4.23k
                    const B2DRange aRangeA(aCubicA.getRange());
519
520
4.23k
                    if(bEdgeAIsCurve)
521
1.33k
                    {
522
                        // curved segments may have self-intersections, do not forget those (!)
523
1.33k
                        findEdgeCutsOneBezier(aCubicA, a, rTempPoints);
524
1.33k
                    }
525
526
27.6k
                    for(sal_uInt32 b(a + 1); b < nEdgeCount; b++)
527
23.3k
                    {
528
23.3k
                        rCandidate.getBezierSegment(b, aCubicB);
529
23.3k
                        aCubicB.testAndSolveTrivialBezier();
530
23.3k
                        const B2DRange aRangeB(aCubicB.getRange());
531
532
                        // only overlapping segments need to be tested
533
                        // consecutive segments touch of course
534
23.3k
                        bool bOverlap = false;
535
23.3k
                        if( b > a+1)
536
19.1k
                            bOverlap = aRangeA.overlaps(aRangeB);
537
4.23k
                        else
538
4.23k
                            bOverlap = aRangeA.overlapsMore(aRangeB);
539
23.3k
                        if( bOverlap)
540
3.96k
                        {
541
3.96k
                            const bool bEdgeBIsCurve(aCubicB.isBezier());
542
3.96k
                            if(bEdgeAIsCurve && bEdgeBIsCurve)
543
1.19k
                            {
544
                                // test for bezier-bezier cuts
545
1.19k
                                findEdgeCutsTwoBeziers(aCubicA, aCubicB, a, b, rTempPoints, rTempPoints);
546
1.19k
                            }
547
2.77k
                            else if(bEdgeAIsCurve)
548
309
                            {
549
                                // test for bezier-edge cuts
550
309
                                findEdgeCutsBezierAndEdge(aCubicA, aCubicB.getStartPoint(), aCubicB.getEndPoint(), a, b, rTempPoints, rTempPoints);
551
309
                            }
552
2.46k
                            else if(bEdgeBIsCurve)
553
979
                            {
554
                                // test for bezier-edge cuts
555
979
                                findEdgeCutsBezierAndEdge(aCubicB, aCubicA.getStartPoint(), aCubicA.getEndPoint(), b, a, rTempPoints, rTempPoints);
556
979
                            }
557
1.48k
                            else
558
1.48k
                            {
559
                                // test for simple edge-edge cuts
560
1.48k
                                findEdgeCutsTwoEdges(aCubicA.getStartPoint(), aCubicA.getEndPoint(), aCubicB.getStartPoint(), aCubicB.getEndPoint(),
561
1.48k
                                    a, b, rTempPoints, rTempPoints);
562
1.48k
                            }
563
3.96k
                        }
564
23.3k
                    }
565
4.23k
                }
566
1.03k
            }
567
396k
            else
568
396k
            {
569
396k
                B2DPoint aCurrA(rCandidate.getB2DPoint(0));
570
571
1.90M
                for(sal_uInt32 a(0); a < nEdgeCount - 1; a++)
572
1.50M
                {
573
1.50M
                    const B2DPoint aNextA(rCandidate.getB2DPoint(a + 1 == nPointCount ? 0 : a + 1));
574
1.50M
                    const B2DRange aRangeA(aCurrA, aNextA);
575
1.50M
                    B2DPoint aCurrB(rCandidate.getB2DPoint(a + 1));
576
577
41.6M
                    for(sal_uInt32 b(a + 1); b < nEdgeCount; b++)
578
40.1M
                    {
579
40.1M
                        const B2DPoint aNextB(rCandidate.getB2DPoint(b + 1 == nPointCount ? 0 : b + 1));
580
40.1M
                        const B2DRange aRangeB(aCurrB, aNextB);
581
582
                        // consecutive segments touch of course
583
40.1M
                        bool bOverlap = false;
584
40.1M
                        if( b > a+1)
585
38.6M
                            bOverlap = aRangeA.overlaps(aRangeB);
586
1.50M
                        else
587
1.50M
                            bOverlap = aRangeA.overlapsMore(aRangeB);
588
40.1M
                        if( bOverlap)
589
6.68M
                        {
590
6.68M
                            findEdgeCutsTwoEdges(aCurrA, aNextA, aCurrB, aNextB, a, b, rTempPoints, rTempPoints);
591
6.68M
                        }
592
593
40.1M
                        if (pPointLimit && rTempPoints.size() > *pPointLimit)
594
58.7k
                            break;
595
596
                        // prepare next step
597
40.1M
                        aCurrB = aNextB;
598
40.1M
                    }
599
600
                    // prepare next step
601
1.50M
                    aCurrA = aNextA;
602
1.50M
                }
603
396k
            }
604
605
397k
            if (pPointLimit)
606
1.74k
            {
607
1.74k
                if (rTempPoints.size() > *pPointLimit)
608
38
                    *pPointLimit = 0;
609
1.70k
                else
610
1.70k
                    *pPointLimit -= rTempPoints.size();
611
1.74k
            }
612
397k
        }
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
7.68M
        {
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
7.68M
            const sal_uInt32 nPointCount(rPointPolygon.count());
629
630
7.68M
            if(!nPointCount)
631
0
                return;
632
633
7.68M
            const B2DRange aRange(rCurr, rNext);
634
7.68M
            const B2DVector aEdgeVector(rNext - rCurr);
635
7.68M
            bool bTestUsingX(fabs(aEdgeVector.getX()) > fabs(aEdgeVector.getY()));
636
637
502M
            for(sal_uInt32 a(0); a < nPointCount; a++)
638
494M
            {
639
494M
                const B2DPoint aTestPoint(rPointPolygon.getB2DPoint(a));
640
641
494M
                if(aRange.isInside(aTestPoint))
642
85.5M
                {
643
85.5M
                    if(!aTestPoint.equal(rCurr) && !aTestPoint.equal(rNext))
644
18.3M
                    {
645
18.3M
                        const B2DVector aTestVector(aTestPoint - rCurr);
646
647
18.3M
                        if(areParallel(aEdgeVector, aTestVector))
648
8.04M
                        {
649
8.04M
                            const double fCut(bTestUsingX
650
8.04M
                                ? aTestVector.getX() / aEdgeVector.getX()
651
8.04M
                                : aTestVector.getY() / aEdgeVector.getY());
652
8.04M
                            const double fZero(0.0);
653
8.04M
                            const double fOne(1.0);
654
655
8.04M
                            if(fTools::more(fCut, fZero) && fTools::less(fCut, fOne))
656
8.03M
                            {
657
8.03M
                                rTempPoints.emplace_back(aTestPoint, nInd, fCut);
658
8.03M
                            }
659
8.04M
                        }
660
18.3M
                    }
661
85.5M
                }
662
494M
            }
663
7.68M
        }
664
665
        void findTouchesOnCurve(
666
            const B2DCubicBezier& rCubicA, const B2DPolygon& rPointPolygon,
667
            sal_uInt32 nInd, temporaryPointVector& rTempPoints)
668
43.6k
        {
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
43.6k
            B2DPolygon aTempPolygon;
673
43.6k
            temporaryPointVector aTempPointVector;
674
675
            // create subdivided polygon and find cuts on it
676
            // Keep adaptiveSubdivideByCount due to needed quality
677
43.6k
            aTempPolygon.reserve(SUBDIVIDE_FOR_CUT_TEST_COUNT + 8);
678
43.6k
            aTempPolygon.append(rCubicA.getStartPoint());
679
43.6k
            rCubicA.adaptiveSubdivideByCount(aTempPolygon, SUBDIVIDE_FOR_CUT_TEST_COUNT);
680
43.6k
            findTouches(aTempPolygon, rPointPolygon, aTempPointVector);
681
682
43.6k
            if(!aTempPointVector.empty())
683
369
            {
684
                // adapt tempVector entries to segment
685
369
                adaptAndTransferCutsWithBezierSegment(aTempPointVector, aTempPolygon, nInd, rTempPoints);
686
369
            }
687
43.6k
        }
688
689
        void findTouches(const B2DPolygon& rEdgePolygon, const B2DPolygon& rPointPolygon, temporaryPointVector& rTempPoints)
690
516k
        {
691
            // find out if points from rPointPolygon touch edges from rEdgePolygon. If yes,
692
            // add entries to rTempPoints
693
516k
            const sal_uInt32 nPointCount(rPointPolygon.count());
694
516k
            const sal_uInt32 nEdgePointCount(rEdgePolygon.count());
695
696
516k
            if(!(nPointCount && nEdgePointCount))
697
0
                return;
698
699
516k
            const sal_uInt32 nEdgeCount(rEdgePolygon.isClosed() ? nEdgePointCount : nEdgePointCount - 1);
700
516k
            B2DPoint aCurr(rEdgePolygon.getB2DPoint(0));
701
702
8.55M
            for(sal_uInt32 a(0); a < nEdgeCount; a++)
703
8.03M
            {
704
8.03M
                const sal_uInt32 nNextIndex((a + 1) % nEdgePointCount);
705
8.03M
                const B2DPoint aNext(rEdgePolygon.getB2DPoint(nNextIndex));
706
707
8.03M
                if(!aCurr.equal(aNext))
708
7.73M
                {
709
7.73M
                    bool bHandleAsSimpleEdge(true);
710
711
7.73M
                    if(rEdgePolygon.areControlPointsUsed())
712
44.5k
                    {
713
44.5k
                        const B2DPoint aNextControlPoint(rEdgePolygon.getNextControlPoint(a));
714
44.5k
                        const B2DPoint aPrevControlPoint(rEdgePolygon.getPrevControlPoint(nNextIndex));
715
44.5k
                        const bool bEdgeIsCurve(!aNextControlPoint.equal(aCurr) || !aPrevControlPoint.equal(aNext));
716
717
44.5k
                        if(bEdgeIsCurve)
718
43.6k
                        {
719
43.6k
                            bHandleAsSimpleEdge = false;
720
43.6k
                            const B2DCubicBezier aCubicA(aCurr, aNextControlPoint, aPrevControlPoint, aNext);
721
43.6k
                            findTouchesOnCurve(aCubicA, rPointPolygon, a, rTempPoints);
722
43.6k
                        }
723
44.5k
                    }
724
725
7.73M
                    if(bHandleAsSimpleEdge)
726
7.68M
                    {
727
7.68M
                        findTouchesOnEdge(aCurr, aNext, rPointPolygon, a, rTempPoints);
728
7.68M
                    }
729
7.73M
                }
730
731
                // next step
732
8.03M
                aCurr = aNext;
733
8.03M
            }
734
516k
        }
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
38.2k
        {
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
38.2k
            const sal_uInt32 nPointCountA(rCandidateA.count());
749
38.2k
            const sal_uInt32 nPointCountB(rCandidateB.count());
750
751
38.2k
            if(!(nPointCountA && nPointCountB))
752
0
                return;
753
754
38.2k
            const sal_uInt32 nEdgeCountA(rCandidateA.isClosed() ? nPointCountA : nPointCountA - 1);
755
38.2k
            const sal_uInt32 nEdgeCountB(rCandidateB.isClosed() ? nPointCountB : nPointCountB - 1);
756
757
38.2k
            if(!(nEdgeCountA && nEdgeCountB))
758
54
                return;
759
760
38.2k
            const bool bCurvesInvolved(rCandidateA.areControlPointsUsed() || rCandidateB.areControlPointsUsed());
761
762
38.2k
            if(bCurvesInvolved)
763
20.3k
            {
764
20.3k
                B2DCubicBezier aCubicA;
765
20.3k
                B2DCubicBezier aCubicB;
766
767
142k
                for(sal_uInt32 a(0); a < nEdgeCountA; a++)
768
122k
                {
769
122k
                    rCandidateA.getBezierSegment(a, aCubicA);
770
122k
                    aCubicA.testAndSolveTrivialBezier();
771
122k
                    const bool bEdgeAIsCurve(aCubicA.isBezier());
772
122k
                    const B2DRange aRangeA(aCubicA.getRange());
773
774
857k
                    for(sal_uInt32 b(0); b < nEdgeCountB; b++)
775
735k
                    {
776
735k
                        rCandidateB.getBezierSegment(b, aCubicB);
777
735k
                        aCubicB.testAndSolveTrivialBezier();
778
735k
                        const B2DRange aRangeB(aCubicB.getRange());
779
780
                        // consecutive segments touch of course
781
735k
                        bool bOverlap = false;
782
735k
                        if( b > a+1)
783
204k
                            bOverlap = aRangeA.overlaps(aRangeB);
784
530k
                        else
785
530k
                            bOverlap = aRangeA.overlapsMore(aRangeB);
786
735k
                        if( bOverlap)
787
142k
                        {
788
142k
                            const bool bEdgeBIsCurve(aCubicB.isBezier());
789
142k
                            if(bEdgeAIsCurve && bEdgeBIsCurve)
790
20.5k
                            {
791
                                // test for bezier-bezier cuts
792
20.5k
                                findEdgeCutsTwoBeziers(aCubicA, aCubicB, a, b, rTempPointsA, rTempPointsB);
793
20.5k
                            }
794
122k
                            else if(bEdgeAIsCurve)
795
409
                            {
796
                                // test for bezier-edge cuts
797
409
                                findEdgeCutsBezierAndEdge(aCubicA, aCubicB.getStartPoint(), aCubicB.getEndPoint(), a, b, rTempPointsA, rTempPointsB);
798
409
                            }
799
121k
                            else if(bEdgeBIsCurve)
800
60.7k
                            {
801
                                // test for bezier-edge cuts
802
60.7k
                                findEdgeCutsBezierAndEdge(aCubicB, aCubicA.getStartPoint(), aCubicA.getEndPoint(), b, a, rTempPointsB, rTempPointsA);
803
60.7k
                            }
804
61.1k
                            else
805
61.1k
                            {
806
                                // test for simple edge-edge cuts
807
61.1k
                                findEdgeCutsTwoEdges(aCubicA.getStartPoint(), aCubicA.getEndPoint(), aCubicB.getStartPoint(), aCubicB.getEndPoint(),
808
61.1k
                                    a, b, rTempPointsA, rTempPointsB);
809
61.1k
                            }
810
142k
                        }
811
735k
                    }
812
122k
                }
813
20.3k
            }
814
17.9k
            else
815
17.9k
            {
816
17.9k
                B2DPoint aCurrA(rCandidateA.getB2DPoint(0));
817
818
3.11M
                for(sal_uInt32 a(0); a < nEdgeCountA; a++)
819
3.09M
                {
820
3.09M
                    const B2DPoint aNextA(rCandidateA.getB2DPoint(a + 1 == nPointCountA ? 0 : a + 1));
821
3.09M
                    const B2DRange aRangeA(aCurrA, aNextA);
822
3.09M
                    B2DPoint aCurrB(rCandidateB.getB2DPoint(0));
823
824
154M
                    for(sal_uInt32 b(0); b < nEdgeCountB; b++)
825
150M
                    {
826
150M
                        const B2DPoint aNextB(rCandidateB.getB2DPoint(b + 1 == nPointCountB ? 0 : b + 1));
827
150M
                        const B2DRange aRangeB(aCurrB, aNextB);
828
829
                        // consecutive segments touch of course
830
150M
                        bool bOverlap = false;
831
150M
                        if( b > a+1)
832
58.2M
                            bOverlap = aRangeA.overlaps(aRangeB);
833
92.7M
                        else
834
92.7M
                            bOverlap = aRangeA.overlapsMore(aRangeB);
835
150M
                        if( bOverlap)
836
2.75M
                        {
837
                            // test for simple edge-edge cuts
838
2.75M
                            findEdgeCutsTwoEdges(aCurrA, aNextA, aCurrB, aNextB, a, b, rTempPointsA, rTempPointsB);
839
2.75M
                        }
840
841
                        // prepare next step
842
150M
                        aCurrB = aNextB;
843
150M
                    }
844
845
                    // prepare next step
846
3.09M
                    aCurrA = aNextA;
847
3.09M
                }
848
17.9k
            }
849
38.2k
        }
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
397k
        {
859
397k
            if(rCandidate.count())
860
396k
            {
861
396k
                temporaryPointVector aTempPoints;
862
863
396k
                findTouches(rCandidate, rCandidate, aTempPoints);
864
396k
                findCuts(rCandidate, aTempPoints, pPointLimit);
865
396k
                if (pPointLimit && !*pPointLimit)
866
433
                {
867
433
                    SAL_WARN("basegfx", "addPointsAtCutsAndTouches hit point limit");
868
433
                    return rCandidate;
869
433
                }
870
871
396k
                return mergeTemporaryPointsAndPolygon(rCandidate, aTempPoints);
872
396k
            }
873
895
            else
874
895
            {
875
895
                return rCandidate;
876
895
            }
877
397k
        }
878
879
        B2DPolyPolygon addPointsAtCutsAndTouches(const B2DPolyPolygon& rCandidate, size_t* pPointLimit)
880
383k
        {
881
383k
            const sal_uInt32 nCount(rCandidate.count());
882
883
383k
            if(nCount)
884
383k
            {
885
383k
                B2DPolyPolygon aRetval;
886
887
383k
                if(nCount == 1)
888
381k
                {
889
                    // remove self intersections
890
381k
                    aRetval.append(addPointsAtCutsAndTouches(rCandidate.getB2DPolygon(0), pPointLimit));
891
381k
                }
892
2.35k
                else
893
2.35k
                {
894
                    // first solve self cuts and self touches for all contained single polygons
895
2.35k
                    std::unique_ptr<temporaryPolygonData[]> pTempData(new temporaryPolygonData[nCount]);
896
2.35k
                    sal_uInt32 a, b;
897
898
17.2k
                    for(a = 0; a < nCount; a++)
899
14.8k
                    {
900
                        // use polygons with solved self intersections
901
14.8k
                        pTempData[a].setPolygon(addPointsAtCutsAndTouches(rCandidate.getB2DPolygon(a), pPointLimit));
902
14.8k
                    }
903
904
2.35k
                    if (pPointLimit && !*pPointLimit)
905
13
                    {
906
13
                        SAL_WARN("basegfx", "addPointsAtCutsAndTouches hit point limit");
907
13
                        return rCandidate;
908
13
                    }
909
910
                    // now cuts and touches between the polygons
911
16.7k
                    for(a = 0; a < nCount; a++)
912
14.4k
                    {
913
444k
                        for(b = 0; b < nCount; b++)
914
430k
                        {
915
430k
                            if(a != b)
916
415k
                            {
917
                                // look for touches, compare each edge polygon to all other points
918
415k
                                if(pTempData[a].getRange().overlaps(pTempData[b].getRange()))
919
76.5k
                                {
920
76.5k
                                    findTouches(pTempData[a].getPolygon(), pTempData[b].getPolygon(), pTempData[a].getTemporaryPointVector());
921
76.5k
                                }
922
415k
                            }
923
924
430k
                            if(a < b)
925
207k
                            {
926
                                // look for cuts, compare each edge polygon to following ones
927
207k
                                if(pTempData[a].getRange().overlaps(pTempData[b].getRange()))
928
38.2k
                                {
929
38.2k
                                    findCuts(pTempData[a].getPolygon(), pTempData[b].getPolygon(), pTempData[a].getTemporaryPointVector(), pTempData[b].getTemporaryPointVector());
930
38.2k
                                }
931
207k
                            }
932
430k
                        }
933
14.4k
                    }
934
935
                    // consolidate the result
936
16.7k
                    for(a = 0; a < nCount; a++)
937
14.4k
                    {
938
14.4k
                        aRetval.append(mergeTemporaryPointsAndPolygon(pTempData[a].getPolygon(), pTempData[a].getTemporaryPointVector()));
939
14.4k
                    }
940
2.34k
                }
941
942
383k
                return aRetval;
943
383k
            }
944
0
            else
945
0
            {
946
0
                return rCandidate;
947
0
            }
948
383k
        }
949
950
        B2DPolygon addPointsAtCuts(const B2DPolygon& rCandidate, const B2DPoint& rStart, const B2DPoint& rEnd)
951
5.44k
        {
952
5.44k
            const sal_uInt32 nCount(rCandidate.count());
953
954
5.44k
            if(nCount && !rStart.equal(rEnd))
955
5.44k
            {
956
5.44k
                const B2DRange aPolygonRange(rCandidate.getB2DRange());
957
5.44k
                const B2DRange aEdgeRange(rStart, rEnd);
958
959
5.44k
                if(aPolygonRange.overlaps(aEdgeRange))
960
5.44k
                {
961
5.44k
                    const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nCount : nCount - 1);
962
5.44k
                    temporaryPointVector aTempPoints;
963
5.44k
                    temporaryPointVector aUnusedTempPoints;
964
5.44k
                    B2DCubicBezier aCubic;
965
966
99.5k
                    for(sal_uInt32 a(0); a < nEdgeCount; a++)
967
94.0k
                    {
968
94.0k
                        rCandidate.getBezierSegment(a, aCubic);
969
94.0k
                        B2DRange aCubicRange(aCubic.getStartPoint(), aCubic.getEndPoint());
970
971
94.0k
                        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
94.0k
                        else
982
94.0k
                        {
983
94.0k
                            if(aCubicRange.overlaps(aEdgeRange))
984
31.7k
                            {
985
31.7k
                                findEdgeCutsTwoEdges(aCubic.getStartPoint(), aCubic.getEndPoint(), rStart, rEnd, a, 0, aTempPoints, aUnusedTempPoints);
986
31.7k
                            }
987
94.0k
                        }
988
94.0k
                    }
989
990
5.44k
                    return mergeTemporaryPointsAndPolygon(rCandidate, aTempPoints);
991
5.44k
                }
992
5.44k
            }
993
994
0
            return rCandidate;
995
5.44k
        }
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: */