Coverage Report

Created: 2025-11-16 09:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/basegfx/source/polygon/b3dpolygon.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 <osl/diagnose.h>
21
#include <basegfx/polygon/b3dpolygon.hxx>
22
#include <basegfx/point/b3dpoint.hxx>
23
#include <basegfx/matrix/b3dhommatrix.hxx>
24
#include <basegfx/point/b2dpoint.hxx>
25
#include <basegfx/color/bcolor.hxx>
26
#include <basegfx/matrix/b2dhommatrix.hxx>
27
#include <cassert>
28
#include <memory>
29
#include <utility>
30
#include <vector>
31
#include <algorithm>
32
33
namespace {
34
35
class CoordinateData3D
36
{
37
    basegfx::B3DPoint                               maPoint;
38
39
public:
40
    CoordinateData3D()
41
0
    {
42
0
    }
43
44
    explicit CoordinateData3D(const basegfx::B3DPoint& rData)
45
19.2k
    :   maPoint(rData)
46
19.2k
    {
47
19.2k
    }
48
49
    const basegfx::B3DPoint& getCoordinate() const
50
19.2k
    {
51
19.2k
        return maPoint;
52
19.2k
    }
53
54
    void setCoordinate(const basegfx::B3DPoint& rValue)
55
0
    {
56
0
        if(rValue != maPoint)
57
0
            maPoint = rValue;
58
0
    }
59
60
    bool operator==(const CoordinateData3D& rData) const
61
0
    {
62
0
        return (maPoint == rData.getCoordinate());
63
0
    }
64
65
    void transform(const basegfx::B3DHomMatrix& rMatrix)
66
19.2k
    {
67
19.2k
        maPoint *= rMatrix;
68
19.2k
    }
69
};
70
71
class CoordinateDataArray3D
72
{
73
    typedef std::vector< CoordinateData3D > CoordinateData3DVector;
74
75
    CoordinateData3DVector                          maVector;
76
77
public:
78
    explicit CoordinateDataArray3D(sal_uInt32 nCount)
79
1
    :   maVector(nCount)
80
1
    {
81
1
    }
82
83
    CoordinateDataArray3D(const CoordinateDataArray3D& rOriginal, sal_uInt32 nIndex, sal_uInt32 nCount)
84
0
    :   maVector(rOriginal.maVector.begin() + nIndex, rOriginal.maVector.begin() + (nIndex + nCount))
85
0
    {
86
0
    }
87
88
    ::basegfx::B3DVector getNormal() const
89
0
    {
90
0
        ::basegfx::B3DVector aRetval;
91
0
        const sal_uInt32 nPointCount(maVector.size());
92
93
0
        if(nPointCount > 2)
94
0
        {
95
0
            sal_uInt32 nISmallest(0);
96
0
            sal_uInt32 a(0);
97
0
            const basegfx::B3DPoint* pSmallest(&maVector[0].getCoordinate());
98
0
            const basegfx::B3DPoint* pNext(nullptr);
99
0
            const basegfx::B3DPoint* pPrev(nullptr);
100
101
            // To guarantee a correctly oriented point, choose an outmost one
102
            // which then cannot be concave
103
0
            for(a = 1; a < nPointCount; a++)
104
0
            {
105
0
                const basegfx::B3DPoint& rCandidate = maVector[a].getCoordinate();
106
107
0
                if((rCandidate.getX() < pSmallest->getX())
108
0
                    || (rCandidate.getX() == pSmallest->getX() && rCandidate.getY() < pSmallest->getY())
109
0
                    || (rCandidate.getX() == pSmallest->getX() && rCandidate.getY() == pSmallest->getY() && rCandidate.getZ() < pSmallest->getZ()))
110
0
                {
111
0
                    nISmallest = a;
112
0
                    pSmallest = &rCandidate;
113
0
                }
114
0
            }
115
116
            // look for a next point different from minimal one
117
0
            for(a = (nISmallest + 1) % nPointCount; a != nISmallest; a = (a + 1) % nPointCount)
118
0
            {
119
0
                const basegfx::B3DPoint& rCandidate = maVector[a].getCoordinate();
120
121
0
                if(!rCandidate.equal(*pSmallest))
122
0
                {
123
0
                    pNext = &rCandidate;
124
0
                    break;
125
0
                }
126
0
            }
127
128
            // look for a previous point different from minimal one
129
0
            for(a = (nISmallest + nPointCount - 1) % nPointCount; a != nISmallest; a = (a + nPointCount - 1) % nPointCount)
130
0
            {
131
0
                const basegfx::B3DPoint& rCandidate = maVector[a].getCoordinate();
132
133
0
                if(!rCandidate.equal(*pSmallest))
134
0
                {
135
0
                    pPrev = &rCandidate;
136
0
                    break;
137
0
                }
138
0
            }
139
140
            // we always have a minimal point. If we also have a different next and previous,
141
            // we can calculate the normal
142
0
            if(pNext && pPrev)
143
0
            {
144
0
                const basegfx::B3DVector aPrev(*pPrev - *pSmallest);
145
0
                const basegfx::B3DVector aNext(*pNext - *pSmallest);
146
147
0
                aRetval = cross(aPrev, aNext);
148
0
                aRetval.normalize();
149
0
            }
150
0
        }
151
152
0
        return aRetval;
153
0
    }
154
155
    sal_uInt32 count() const
156
21.6k
    {
157
21.6k
        return maVector.size();
158
21.6k
    }
159
160
    bool operator==(const CoordinateDataArray3D& rCandidate) const
161
0
    {
162
0
        return (maVector == rCandidate.maVector);
163
0
    }
164
165
    const basegfx::B3DPoint& getCoordinate(sal_uInt32 nIndex) const
166
19.2k
    {
167
19.2k
        return maVector[nIndex].getCoordinate();
168
19.2k
    }
169
170
    void setCoordinate(sal_uInt32 nIndex, const basegfx::B3DPoint& rValue)
171
0
    {
172
0
        maVector[nIndex].setCoordinate(rValue);
173
0
    }
174
175
    void insert(sal_uInt32 nIndex, const CoordinateData3D& rValue, sal_uInt32 nCount)
176
19.2k
    {
177
19.2k
        if(nCount)
178
19.2k
        {
179
            // add nCount copies of rValue
180
19.2k
            CoordinateData3DVector::iterator aIndex(maVector.begin());
181
19.2k
            aIndex += nIndex;
182
19.2k
            maVector.insert(aIndex, nCount, rValue);
183
19.2k
        }
184
19.2k
    }
185
186
    void insert(sal_uInt32 nIndex, const CoordinateDataArray3D& rSource)
187
0
    {
188
0
        const sal_uInt32 nCount(rSource.maVector.size());
189
190
0
        if(nCount)
191
0
        {
192
            // insert data
193
0
            CoordinateData3DVector::iterator aIndex(maVector.begin());
194
0
            aIndex += nIndex;
195
0
            CoordinateData3DVector::const_iterator aStart(rSource.maVector.begin());
196
0
            CoordinateData3DVector::const_iterator aEnd(rSource.maVector.end());
197
0
            maVector.insert(aIndex, aStart, aEnd);
198
0
        }
199
0
    }
200
201
    void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
202
0
    {
203
0
        if(nCount)
204
0
        {
205
            // remove point data
206
0
            CoordinateData3DVector::iterator aStart(maVector.begin());
207
0
            aStart += nIndex;
208
0
            const CoordinateData3DVector::iterator aEnd(aStart + nCount);
209
0
            maVector.erase(aStart, aEnd);
210
0
        }
211
0
    }
212
213
    void flip()
214
0
    {
215
0
        if(maVector.size() <= 1)
216
0
            return;
217
218
0
        const sal_uInt32 nHalfSize(maVector.size() >> 1);
219
0
        CoordinateData3DVector::iterator aStart(maVector.begin());
220
0
        CoordinateData3DVector::iterator aEnd(maVector.end() - 1);
221
222
0
        for(sal_uInt32 a(0); a < nHalfSize; a++)
223
0
        {
224
0
            std::swap(*aStart, *aEnd);
225
0
            ++aStart;
226
0
            --aEnd;
227
0
        }
228
0
    }
229
230
    void transform(const ::basegfx::B3DHomMatrix& rMatrix)
231
2.40k
    {
232
2.40k
        for (auto & elem : maVector)
233
19.2k
        {
234
19.2k
            elem.transform(rMatrix);
235
19.2k
        }
236
2.40k
    }
237
};
238
239
class BColorArray
240
{
241
    typedef std::vector< ::basegfx::BColor > BColorDataVector;
242
243
    BColorDataVector                                    maVector;
244
    sal_uInt32                                          mnUsedEntries;
245
246
public:
247
    explicit BColorArray(sal_uInt32 nCount)
248
0
    :   maVector(nCount),
249
0
        mnUsedEntries(0)
250
0
    {
251
0
    }
252
253
    BColorArray(const BColorArray& rOriginal, sal_uInt32 nIndex, sal_uInt32 nCount)
254
0
    :   mnUsedEntries(0)
255
0
    {
256
0
        BColorDataVector::const_iterator aStart(rOriginal.maVector.begin());
257
0
        aStart += nIndex;
258
0
        BColorDataVector::const_iterator aEnd(aStart);
259
0
        assert(nCount <= rOriginal.maVector.size());
260
0
        aEnd += nCount;
261
0
        maVector.reserve(nCount);
262
263
0
        for(; aStart != aEnd; ++aStart)
264
0
        {
265
0
            if(!aStart->equalZero())
266
0
                mnUsedEntries++;
267
268
0
            maVector.push_back(*aStart);
269
0
        }
270
0
    }
271
272
    bool operator==(const BColorArray& rCandidate) const
273
0
    {
274
0
        return (maVector == rCandidate.maVector);
275
0
    }
276
277
    bool isUsed() const
278
0
    {
279
0
        return (mnUsedEntries != 0);
280
0
    }
281
282
    const ::basegfx::BColor& getBColor(sal_uInt32 nIndex) const
283
0
    {
284
0
        return maVector[nIndex];
285
0
    }
286
287
    void setBColor(sal_uInt32 nIndex, const ::basegfx::BColor& rValue)
288
0
    {
289
0
        bool bWasUsed(mnUsedEntries && !maVector[nIndex].equalZero());
290
0
        bool bIsUsed(!rValue.equalZero());
291
292
0
        if(bWasUsed)
293
0
        {
294
0
            if(bIsUsed)
295
0
            {
296
0
                maVector[nIndex] = rValue;
297
0
            }
298
0
            else
299
0
            {
300
0
                maVector[nIndex] = ::basegfx::BColor::getEmptyBColor();
301
0
                mnUsedEntries--;
302
0
            }
303
0
        }
304
0
        else
305
0
        {
306
0
            if(bIsUsed)
307
0
            {
308
0
                maVector[nIndex] = rValue;
309
0
                mnUsedEntries++;
310
0
            }
311
0
        }
312
0
    }
313
314
    void insert(sal_uInt32 nIndex, const ::basegfx::BColor& rValue, sal_uInt32 nCount)
315
0
    {
316
0
        if(nCount)
317
0
        {
318
            // add nCount copies of rValue
319
0
            BColorDataVector::iterator aIndex(maVector.begin());
320
0
            aIndex += nIndex;
321
0
            maVector.insert(aIndex, nCount, rValue);
322
323
0
            if(!rValue.equalZero())
324
0
                mnUsedEntries += nCount;
325
0
        }
326
0
    }
327
328
    void insert(sal_uInt32 nIndex, const BColorArray& rSource)
329
0
    {
330
0
        const sal_uInt32 nCount(rSource.maVector.size());
331
332
0
        if(nCount)
333
0
        {
334
            // insert data
335
0
            BColorDataVector::iterator aIndex(maVector.begin());
336
0
            aIndex += nIndex;
337
0
            BColorDataVector::const_iterator aStart(rSource.maVector.begin());
338
0
            BColorDataVector::const_iterator aEnd(rSource.maVector.end());
339
0
            maVector.insert(aIndex, aStart, aEnd);
340
341
0
            mnUsedEntries += std::count_if(aStart, aEnd,
342
0
                [](BColorDataVector::const_reference rData) { return !rData.equalZero(); });
343
0
        }
344
0
    }
345
346
    void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
347
0
    {
348
0
        if(nCount)
349
0
        {
350
0
            const BColorDataVector::iterator aDeleteStart(maVector.begin() + nIndex);
351
0
            const BColorDataVector::iterator aDeleteEnd(aDeleteStart + nCount);
352
353
0
            auto nDeleteUsed = std::count_if(aDeleteStart, aDeleteEnd,
354
0
                [](BColorDataVector::const_reference rData) { return !rData.equalZero(); });
355
0
            mnUsedEntries -= std::min(mnUsedEntries, static_cast<sal_uInt32>(nDeleteUsed));
356
357
            // remove point data
358
0
            maVector.erase(aDeleteStart, aDeleteEnd);
359
0
        }
360
0
    }
361
362
    void flip()
363
0
    {
364
0
        if(maVector.size() <= 1)
365
0
            return;
366
367
0
        const sal_uInt32 nHalfSize(maVector.size() >> 1);
368
0
        BColorDataVector::iterator aStart(maVector.begin());
369
0
        BColorDataVector::iterator aEnd(maVector.end() - 1);
370
371
0
        for(sal_uInt32 a(0); a < nHalfSize; a++)
372
0
        {
373
0
            std::swap(*aStart, *aEnd);
374
0
            ++aStart;
375
0
            --aEnd;
376
0
        }
377
0
    }
378
};
379
380
class NormalsArray3D
381
{
382
    typedef std::vector< ::basegfx::B3DVector > NormalsData3DVector;
383
384
    NormalsData3DVector                                 maVector;
385
    sal_uInt32                                          mnUsedEntries;
386
387
public:
388
    explicit NormalsArray3D(sal_uInt32 nCount)
389
0
    :   maVector(nCount),
390
0
        mnUsedEntries(0)
391
0
    {
392
0
    }
393
394
    NormalsArray3D(const NormalsArray3D& rOriginal, sal_uInt32 nIndex, sal_uInt32 nCount)
395
0
    :   mnUsedEntries(0)
396
0
    {
397
0
        NormalsData3DVector::const_iterator aStart(rOriginal.maVector.begin());
398
0
        aStart += nIndex;
399
0
        NormalsData3DVector::const_iterator aEnd(aStart);
400
0
        aEnd += nCount;
401
0
        maVector.reserve(nCount);
402
403
0
        for(; aStart != aEnd; ++aStart)
404
0
        {
405
0
            if(!aStart->equalZero())
406
0
                mnUsedEntries++;
407
408
0
            maVector.push_back(*aStart);
409
0
        }
410
0
    }
411
412
    bool operator==(const NormalsArray3D& rCandidate) const
413
0
    {
414
0
        return (maVector == rCandidate.maVector);
415
0
    }
416
417
    bool isUsed() const
418
0
    {
419
0
        return (mnUsedEntries != 0);
420
0
    }
421
422
    const ::basegfx::B3DVector& getNormal(sal_uInt32 nIndex) const
423
0
    {
424
0
        return maVector[nIndex];
425
0
    }
426
427
    void setNormal(sal_uInt32 nIndex, const ::basegfx::B3DVector& rValue)
428
0
    {
429
0
        bool bWasUsed(mnUsedEntries && !maVector[nIndex].equalZero());
430
0
        bool bIsUsed(!rValue.equalZero());
431
432
0
        if(bWasUsed)
433
0
        {
434
0
            if(bIsUsed)
435
0
            {
436
0
                maVector[nIndex] = rValue;
437
0
            }
438
0
            else
439
0
            {
440
0
                maVector[nIndex] = ::basegfx::B3DVector::getEmptyVector();
441
0
                mnUsedEntries--;
442
0
            }
443
0
        }
444
0
        else
445
0
        {
446
0
            if(bIsUsed)
447
0
            {
448
0
                maVector[nIndex] = rValue;
449
0
                mnUsedEntries++;
450
0
            }
451
0
        }
452
0
    }
453
454
    void insert(sal_uInt32 nIndex, const ::basegfx::B3DVector& rValue, sal_uInt32 nCount)
455
0
    {
456
0
        if(nCount)
457
0
        {
458
            // add nCount copies of rValue
459
0
            NormalsData3DVector::iterator aIndex(maVector.begin());
460
0
            aIndex += nIndex;
461
0
            maVector.insert(aIndex, nCount, rValue);
462
463
0
            if(!rValue.equalZero())
464
0
                mnUsedEntries += nCount;
465
0
        }
466
0
    }
467
468
    void insert(sal_uInt32 nIndex, const NormalsArray3D& rSource)
469
0
    {
470
0
        const sal_uInt32 nCount(rSource.maVector.size());
471
472
0
        if(nCount)
473
0
        {
474
            // insert data
475
0
            NormalsData3DVector::iterator aIndex(maVector.begin());
476
0
            aIndex += nIndex;
477
0
            NormalsData3DVector::const_iterator aStart(rSource.maVector.begin());
478
0
            NormalsData3DVector::const_iterator aEnd(rSource.maVector.end());
479
0
            maVector.insert(aIndex, aStart, aEnd);
480
481
0
            mnUsedEntries += std::count_if(aStart, aEnd,
482
0
                [](NormalsData3DVector::const_reference rData) { return !rData.equalZero(); });
483
0
        }
484
0
    }
485
486
    void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
487
0
    {
488
0
        if(nCount)
489
0
        {
490
0
            const NormalsData3DVector::iterator aDeleteStart(maVector.begin() + nIndex);
491
0
            const NormalsData3DVector::iterator aDeleteEnd(aDeleteStart + nCount);
492
493
0
            auto nDeleteUsed = std::count_if(aDeleteStart, aDeleteEnd,
494
0
                [](NormalsData3DVector::const_reference rData) { return !rData.equalZero(); });
495
0
            mnUsedEntries -= std::min(mnUsedEntries, static_cast<sal_uInt32>(nDeleteUsed));
496
497
            // remove point data
498
0
            maVector.erase(aDeleteStart, aDeleteEnd);
499
0
        }
500
0
    }
501
502
    void flip()
503
0
    {
504
0
        if(maVector.size() <= 1)
505
0
            return;
506
507
0
        const sal_uInt32 nHalfSize(maVector.size() >> 1);
508
0
        NormalsData3DVector::iterator aStart(maVector.begin());
509
0
        NormalsData3DVector::iterator aEnd(maVector.end() - 1);
510
511
0
        for(sal_uInt32 a(0); a < nHalfSize; a++)
512
0
        {
513
0
            std::swap(*aStart, *aEnd);
514
0
            ++aStart;
515
0
            --aEnd;
516
0
        }
517
0
    }
518
519
    void transform(const basegfx::B3DHomMatrix& rMatrix)
520
0
    {
521
0
        for (auto & elem : maVector)
522
0
        {
523
0
            elem *= rMatrix;
524
0
        }
525
0
    }
526
};
527
528
class TextureCoordinate2D
529
{
530
    typedef std::vector< ::basegfx::B2DPoint > TextureData2DVector;
531
532
    TextureData2DVector                                 maVector;
533
    sal_uInt32                                          mnUsedEntries;
534
535
public:
536
    explicit TextureCoordinate2D(sal_uInt32 nCount)
537
0
    :   maVector(nCount),
538
0
        mnUsedEntries(0)
539
0
    {
540
0
    }
541
542
    TextureCoordinate2D(const TextureCoordinate2D& rOriginal, sal_uInt32 nIndex, sal_uInt32 nCount)
543
0
    :   mnUsedEntries(0)
544
0
    {
545
0
        TextureData2DVector::const_iterator aStart(rOriginal.maVector.begin());
546
0
        aStart += nIndex;
547
0
        TextureData2DVector::const_iterator aEnd(aStart);
548
0
        aEnd += nCount;
549
0
        maVector.reserve(nCount);
550
551
0
        for(; aStart != aEnd; ++aStart)
552
0
        {
553
0
            if(!aStart->equalZero())
554
0
                mnUsedEntries++;
555
556
0
            maVector.push_back(*aStart);
557
0
        }
558
0
    }
559
560
    bool operator==(const TextureCoordinate2D& rCandidate) const
561
0
    {
562
0
        return (maVector == rCandidate.maVector);
563
0
    }
564
565
    bool isUsed() const
566
0
    {
567
0
        return (mnUsedEntries != 0);
568
0
    }
569
570
    const ::basegfx::B2DPoint& getTextureCoordinate(sal_uInt32 nIndex) const
571
0
    {
572
0
        return maVector[nIndex];
573
0
    }
574
575
    void setTextureCoordinate(sal_uInt32 nIndex, const ::basegfx::B2DPoint& rValue)
576
0
    {
577
0
        bool bWasUsed(mnUsedEntries && !maVector[nIndex].equalZero());
578
0
        bool bIsUsed(!rValue.equalZero());
579
580
0
        if(bWasUsed)
581
0
        {
582
0
            if(bIsUsed)
583
0
            {
584
0
                maVector[nIndex] = rValue;
585
0
            }
586
0
            else
587
0
            {
588
0
                maVector[nIndex] = ::basegfx::B2DPoint::getEmptyPoint();
589
0
                mnUsedEntries--;
590
0
            }
591
0
        }
592
0
        else
593
0
        {
594
0
            if(bIsUsed)
595
0
            {
596
0
                maVector[nIndex] = rValue;
597
0
                mnUsedEntries++;
598
0
            }
599
0
        }
600
0
    }
601
602
    void insert(sal_uInt32 nIndex, const ::basegfx::B2DPoint& rValue, sal_uInt32 nCount)
603
0
    {
604
0
        if(nCount)
605
0
        {
606
            // add nCount copies of rValue
607
0
            TextureData2DVector::iterator aIndex(maVector.begin());
608
0
            aIndex += nIndex;
609
0
            maVector.insert(aIndex, nCount, rValue);
610
611
0
            if(!rValue.equalZero())
612
0
                mnUsedEntries += nCount;
613
0
        }
614
0
    }
615
616
    void insert(sal_uInt32 nIndex, const TextureCoordinate2D& rSource)
617
0
    {
618
0
        const sal_uInt32 nCount(rSource.maVector.size());
619
620
0
        if(nCount)
621
0
        {
622
            // insert data
623
0
            TextureData2DVector::iterator aIndex(maVector.begin());
624
0
            aIndex += nIndex;
625
0
            TextureData2DVector::const_iterator aStart(rSource.maVector.begin());
626
0
            TextureData2DVector::const_iterator aEnd(rSource.maVector.end());
627
0
            maVector.insert(aIndex, aStart, aEnd);
628
629
0
            mnUsedEntries += std::count_if(aStart, aEnd,
630
0
                [](TextureData2DVector::const_reference rData) { return !rData.equalZero(); });
631
0
        }
632
0
    }
633
634
    void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
635
0
    {
636
0
        if(nCount)
637
0
        {
638
0
            const TextureData2DVector::iterator aDeleteStart(maVector.begin() + nIndex);
639
0
            const TextureData2DVector::iterator aDeleteEnd(aDeleteStart + nCount);
640
641
0
            auto nDeleteUsed = std::count_if(aDeleteStart, aDeleteEnd,
642
0
                [](TextureData2DVector::const_reference rData) { return !rData.equalZero(); });
643
0
            mnUsedEntries -= std::min(mnUsedEntries, static_cast<sal_uInt32>(nDeleteUsed));
644
645
            // remove point data
646
0
            maVector.erase(aDeleteStart, aDeleteEnd);
647
0
        }
648
0
    }
649
650
    void flip()
651
0
    {
652
0
        if(maVector.size() <= 1)
653
0
            return;
654
655
0
        const sal_uInt32 nHalfSize(maVector.size() >> 1);
656
0
        TextureData2DVector::iterator aStart(maVector.begin());
657
0
        TextureData2DVector::iterator aEnd(maVector.end() - 1);
658
659
0
        for(sal_uInt32 a(0); a < nHalfSize; a++)
660
0
        {
661
0
            std::swap(*aStart, *aEnd);
662
0
            ++aStart;
663
0
            --aEnd;
664
0
        }
665
0
    }
666
667
    void transform(const ::basegfx::B2DHomMatrix& rMatrix)
668
0
    {
669
0
        for (auto & elem : maVector)
670
0
        {
671
0
            elem *= rMatrix;
672
0
        }
673
0
    }
674
};
675
676
}
677
678
class ImplB3DPolygon
679
{
680
    // The point vector. This vector exists always and defines the
681
    // count of members.
682
    CoordinateDataArray3D                           maPoints;
683
684
    // The BColor vector. This vectors are created on demand
685
    // and may be zero.
686
    std::unique_ptr<BColorArray>                    mpBColors;
687
688
    // The Normals vector. This vectors are created on demand
689
    // and may be zero.
690
    std::unique_ptr<NormalsArray3D>                 mpNormals;
691
692
    // The TextureCoordinates vector. This vectors are created on demand
693
    // and may be zero.
694
    std::unique_ptr<TextureCoordinate2D>            mpTextureCoordinates;
695
696
    // flag which decides if this polygon is opened or closed
697
    bool                                            mbIsClosed : 1;
698
699
public:
700
    // This constructor is only used from the static identity polygon, thus
701
    // the RefCount is set to 1 to never 'delete' this static incarnation.
702
    ImplB3DPolygon()
703
1
    :   maPoints(0),
704
1
        mbIsClosed(false)
705
1
    {
706
        // complete initialization with defaults
707
1
    }
708
709
    ImplB3DPolygon(const ImplB3DPolygon& rToBeCopied)
710
2.40k
    :   maPoints(rToBeCopied.maPoints),
711
2.40k
        mbIsClosed(rToBeCopied.mbIsClosed)
712
2.40k
    {
713
        // complete initialization using copy
714
2.40k
        if(rToBeCopied.mpBColors && rToBeCopied.mpBColors->isUsed())
715
0
        {
716
0
            mpBColors.reset( new BColorArray(*rToBeCopied.mpBColors) );
717
0
        }
718
719
2.40k
        if(rToBeCopied.mpNormals && rToBeCopied.mpNormals->isUsed())
720
0
        {
721
0
            mpNormals.reset( new NormalsArray3D(*rToBeCopied.mpNormals) );
722
0
        }
723
724
2.40k
        if(rToBeCopied.mpTextureCoordinates && rToBeCopied.mpTextureCoordinates->isUsed())
725
0
        {
726
0
            mpTextureCoordinates.reset( new TextureCoordinate2D(*rToBeCopied.mpTextureCoordinates) );
727
0
        }
728
2.40k
    }
729
730
    ImplB3DPolygon(const ImplB3DPolygon& rToBeCopied, sal_uInt32 nIndex, sal_uInt32 nCount)
731
0
    :   maPoints(rToBeCopied.maPoints, nIndex, nCount),
732
0
        mbIsClosed(rToBeCopied.mbIsClosed)
733
0
    {
734
        // complete initialization using partly copy
735
0
        if(rToBeCopied.mpBColors && rToBeCopied.mpBColors->isUsed())
736
0
        {
737
0
            mpBColors.reset( new BColorArray(*rToBeCopied.mpBColors, nIndex, nCount) );
738
739
0
            if(!mpBColors->isUsed())
740
0
            {
741
0
                mpBColors.reset();
742
0
            }
743
0
        }
744
745
0
        if(rToBeCopied.mpNormals && rToBeCopied.mpNormals->isUsed())
746
0
        {
747
0
            mpNormals.reset( new NormalsArray3D(*rToBeCopied.mpNormals, nIndex, nCount) );
748
749
0
            if(!mpNormals->isUsed())
750
0
            {
751
0
                mpNormals.reset();
752
0
            }
753
0
        }
754
755
0
        if(rToBeCopied.mpTextureCoordinates && rToBeCopied.mpTextureCoordinates->isUsed())
756
0
        {
757
0
            mpTextureCoordinates.reset( new TextureCoordinate2D(*rToBeCopied.mpTextureCoordinates, nIndex, nCount) );
758
759
0
            if(!mpTextureCoordinates->isUsed())
760
0
            {
761
0
                mpTextureCoordinates.reset();
762
0
            }
763
0
        }
764
0
    }
765
766
    sal_uInt32 count() const
767
21.6k
    {
768
21.6k
        return maPoints.count();
769
21.6k
    }
770
771
    bool isClosed() const
772
0
    {
773
0
        return mbIsClosed;
774
0
    }
775
776
    void setClosed(bool bNew)
777
0
    {
778
0
        if(bNew != mbIsClosed)
779
0
        {
780
0
            mbIsClosed = bNew;
781
0
        }
782
0
    }
783
784
    bool impBColorsAreEqual(const ImplB3DPolygon& rCandidate) const
785
0
    {
786
0
        bool bBColorsAreEqual(true);
787
788
0
        if(mpBColors)
789
0
        {
790
0
            if(rCandidate.mpBColors)
791
0
            {
792
0
                bBColorsAreEqual = (*mpBColors == *rCandidate.mpBColors);
793
0
            }
794
0
            else
795
0
            {
796
                // candidate has no BColors, so it's assumed all unused.
797
0
                bBColorsAreEqual = !mpBColors->isUsed();
798
0
            }
799
0
        }
800
0
        else
801
0
        {
802
0
            if(rCandidate.mpBColors)
803
0
            {
804
                // we have no TextureCoordinates, so it's assumed all unused.
805
0
                bBColorsAreEqual = !rCandidate.mpBColors->isUsed();
806
0
            }
807
0
        }
808
809
0
        return bBColorsAreEqual;
810
0
    }
811
812
    bool impNormalsAreEqual(const ImplB3DPolygon& rCandidate) const
813
0
    {
814
0
        bool bNormalsAreEqual(true);
815
816
0
        if(mpNormals)
817
0
        {
818
0
            if(rCandidate.mpNormals)
819
0
            {
820
0
                bNormalsAreEqual = (*mpNormals == *rCandidate.mpNormals);
821
0
            }
822
0
            else
823
0
            {
824
                // candidate has no normals, so it's assumed all unused.
825
0
                bNormalsAreEqual = !mpNormals->isUsed();
826
0
            }
827
0
        }
828
0
        else
829
0
        {
830
0
            if(rCandidate.mpNormals)
831
0
            {
832
                // we have no normals, so it's assumed all unused.
833
0
                bNormalsAreEqual = !rCandidate.mpNormals->isUsed();
834
0
            }
835
0
        }
836
837
0
        return bNormalsAreEqual;
838
0
    }
839
840
    bool impTextureCoordinatesAreEqual(const ImplB3DPolygon& rCandidate) const
841
0
    {
842
0
        bool bTextureCoordinatesAreEqual(true);
843
844
0
        if(mpTextureCoordinates)
845
0
        {
846
0
            if(rCandidate.mpTextureCoordinates)
847
0
            {
848
0
                bTextureCoordinatesAreEqual = (*mpTextureCoordinates == *rCandidate.mpTextureCoordinates);
849
0
            }
850
0
            else
851
0
            {
852
                // candidate has no TextureCoordinates, so it's assumed all unused.
853
0
                bTextureCoordinatesAreEqual = !mpTextureCoordinates->isUsed();
854
0
            }
855
0
        }
856
0
        else
857
0
        {
858
0
            if(rCandidate.mpTextureCoordinates)
859
0
            {
860
                // we have no TextureCoordinates, so it's assumed all unused.
861
0
                bTextureCoordinatesAreEqual = !rCandidate.mpTextureCoordinates->isUsed();
862
0
            }
863
0
        }
864
865
0
        return bTextureCoordinatesAreEqual;
866
0
    }
867
868
    bool operator==(const ImplB3DPolygon& rCandidate) const
869
0
    {
870
0
        if(mbIsClosed == rCandidate.mbIsClosed)
871
0
        {
872
0
            if(maPoints == rCandidate.maPoints)
873
0
            {
874
0
                if(impBColorsAreEqual(rCandidate))
875
0
                {
876
0
                    if(impNormalsAreEqual(rCandidate))
877
0
                    {
878
0
                        if(impTextureCoordinatesAreEqual(rCandidate))
879
0
                        {
880
0
                            return true;
881
0
                        }
882
0
                    }
883
0
                }
884
0
            }
885
0
        }
886
887
0
        return false;
888
0
    }
889
890
    const ::basegfx::B3DPoint& getPoint(sal_uInt32 nIndex) const
891
19.2k
    {
892
19.2k
        return maPoints.getCoordinate(nIndex);
893
19.2k
    }
894
895
    void setPoint(sal_uInt32 nIndex, const ::basegfx::B3DPoint& rValue)
896
0
    {
897
0
        maPoints.setCoordinate(nIndex, rValue);
898
0
    }
899
900
    void insert(sal_uInt32 nIndex, const ::basegfx::B3DPoint& rPoint, sal_uInt32 nCount)
901
19.2k
    {
902
19.2k
        if(!nCount)
903
0
            return;
904
905
19.2k
        CoordinateData3D aCoordinate(rPoint);
906
19.2k
        maPoints.insert(nIndex, aCoordinate, nCount);
907
908
19.2k
        if(mpBColors)
909
0
        {
910
0
            mpBColors->insert(nIndex, ::basegfx::BColor::getEmptyBColor(), nCount);
911
0
        }
912
913
19.2k
        if(mpNormals)
914
0
        {
915
0
            mpNormals->insert(nIndex, ::basegfx::B3DVector::getEmptyVector(), nCount);
916
0
        }
917
918
19.2k
        if(mpTextureCoordinates)
919
0
        {
920
0
            mpTextureCoordinates->insert(nIndex, ::basegfx::B2DPoint::getEmptyPoint(), nCount);
921
0
        }
922
19.2k
    }
923
924
    const ::basegfx::BColor& getBColor(sal_uInt32 nIndex) const
925
0
    {
926
0
        if(mpBColors)
927
0
        {
928
0
            return mpBColors->getBColor(nIndex);
929
0
        }
930
0
        else
931
0
        {
932
0
            return ::basegfx::BColor::getEmptyBColor();
933
0
        }
934
0
    }
935
936
    void setBColor(sal_uInt32 nIndex, const ::basegfx::BColor& rValue)
937
0
    {
938
0
        if(!mpBColors)
939
0
        {
940
0
            if(!rValue.equalZero())
941
0
            {
942
0
                mpBColors.reset( new BColorArray(maPoints.count()) );
943
0
                mpBColors->setBColor(nIndex, rValue);
944
0
            }
945
0
        }
946
0
        else
947
0
        {
948
0
            mpBColors->setBColor(nIndex, rValue);
949
950
0
            if(!mpBColors->isUsed())
951
0
            {
952
0
                mpBColors.reset();
953
0
            }
954
0
        }
955
0
    }
956
957
    bool areBColorsUsed() const
958
0
    {
959
0
        return (mpBColors && mpBColors->isUsed());
960
0
    }
961
962
    void clearBColors()
963
0
    {
964
0
        mpBColors.reset();
965
0
    }
966
967
    ::basegfx::B3DVector getNormal() const
968
0
    {
969
0
        return maPoints.getNormal();
970
0
    }
971
972
    const ::basegfx::B3DVector& getNormal(sal_uInt32 nIndex) const
973
0
    {
974
0
        if(mpNormals)
975
0
        {
976
0
            return mpNormals->getNormal(nIndex);
977
0
        }
978
0
        else
979
0
        {
980
0
            return ::basegfx::B3DVector::getEmptyVector();
981
0
        }
982
0
    }
983
984
    void setNormal(sal_uInt32 nIndex, const ::basegfx::B3DVector& rValue)
985
0
    {
986
0
        if(!mpNormals)
987
0
        {
988
0
            if(!rValue.equalZero())
989
0
            {
990
0
                mpNormals.reset( new NormalsArray3D(maPoints.count()) );
991
0
                mpNormals->setNormal(nIndex, rValue);
992
0
            }
993
0
        }
994
0
        else
995
0
        {
996
0
            mpNormals->setNormal(nIndex, rValue);
997
998
0
            if(!mpNormals->isUsed())
999
0
            {
1000
0
                mpNormals.reset();
1001
0
            }
1002
0
        }
1003
0
    }
1004
1005
    void transformNormals(const ::basegfx::B3DHomMatrix& rMatrix)
1006
0
    {
1007
0
        if(mpNormals)
1008
0
        {
1009
0
            mpNormals->transform(rMatrix);
1010
0
        }
1011
0
    }
1012
1013
    bool areNormalsUsed() const
1014
0
    {
1015
0
        return (mpNormals && mpNormals->isUsed());
1016
0
    }
1017
1018
    void clearNormals()
1019
0
    {
1020
0
        mpNormals.reset();
1021
0
    }
1022
1023
    const ::basegfx::B2DPoint& getTextureCoordinate(sal_uInt32 nIndex) const
1024
0
    {
1025
0
        if(mpTextureCoordinates)
1026
0
        {
1027
0
            return mpTextureCoordinates->getTextureCoordinate(nIndex);
1028
0
        }
1029
0
        else
1030
0
        {
1031
0
            return ::basegfx::B2DPoint::getEmptyPoint();
1032
0
        }
1033
0
    }
1034
1035
    void setTextureCoordinate(sal_uInt32 nIndex, const ::basegfx::B2DPoint& rValue)
1036
0
    {
1037
0
        if(!mpTextureCoordinates)
1038
0
        {
1039
0
            if(!rValue.equalZero())
1040
0
            {
1041
0
                mpTextureCoordinates.reset( new TextureCoordinate2D(maPoints.count()) );
1042
0
                mpTextureCoordinates->setTextureCoordinate(nIndex, rValue);
1043
0
            }
1044
0
        }
1045
0
        else
1046
0
        {
1047
0
            mpTextureCoordinates->setTextureCoordinate(nIndex, rValue);
1048
1049
0
            if(!mpTextureCoordinates->isUsed())
1050
0
            {
1051
0
                mpTextureCoordinates.reset();
1052
0
            }
1053
0
        }
1054
0
    }
1055
1056
    bool areTextureCoordinatesUsed() const
1057
0
    {
1058
0
        return (mpTextureCoordinates && mpTextureCoordinates->isUsed());
1059
0
    }
1060
1061
    void clearTextureCoordinates()
1062
0
    {
1063
0
        mpTextureCoordinates.reset();
1064
0
    }
1065
1066
    void transformTextureCoordinates(const ::basegfx::B2DHomMatrix& rMatrix)
1067
0
    {
1068
0
        if(mpTextureCoordinates)
1069
0
        {
1070
0
            mpTextureCoordinates->transform(rMatrix);
1071
0
        }
1072
0
    }
1073
1074
    void insert(sal_uInt32 nIndex, const ImplB3DPolygon& rSource)
1075
0
    {
1076
0
        const sal_uInt32 nCount(rSource.maPoints.count());
1077
1078
0
        if(!nCount)
1079
0
            return;
1080
1081
0
        maPoints.insert(nIndex, rSource.maPoints);
1082
1083
0
        if(rSource.mpBColors && rSource.mpBColors->isUsed())
1084
0
        {
1085
0
            if(!mpBColors)
1086
0
            {
1087
0
                mpBColors.reset( new BColorArray(maPoints.count()) );
1088
0
            }
1089
1090
0
            mpBColors->insert(nIndex, *rSource.mpBColors);
1091
0
        }
1092
0
        else
1093
0
        {
1094
0
            if(mpBColors)
1095
0
            {
1096
0
                mpBColors->insert(nIndex, ::basegfx::BColor::getEmptyBColor(), nCount);
1097
0
            }
1098
0
        }
1099
1100
0
        if(rSource.mpNormals && rSource.mpNormals->isUsed())
1101
0
        {
1102
0
            if(!mpNormals)
1103
0
            {
1104
0
                mpNormals.reset( new NormalsArray3D(maPoints.count()) );
1105
0
            }
1106
1107
0
            mpNormals->insert(nIndex, *rSource.mpNormals);
1108
0
        }
1109
0
        else
1110
0
        {
1111
0
            if(mpNormals)
1112
0
            {
1113
0
                mpNormals->insert(nIndex, ::basegfx::B3DVector::getEmptyVector(), nCount);
1114
0
            }
1115
0
        }
1116
1117
0
        if(rSource.mpTextureCoordinates && rSource.mpTextureCoordinates->isUsed())
1118
0
        {
1119
0
            if(!mpTextureCoordinates)
1120
0
            {
1121
0
                mpTextureCoordinates.reset( new TextureCoordinate2D(maPoints.count()) );
1122
0
            }
1123
1124
0
            mpTextureCoordinates->insert(nIndex, *rSource.mpTextureCoordinates);
1125
0
        }
1126
0
        else
1127
0
        {
1128
0
            if(mpTextureCoordinates)
1129
0
            {
1130
0
                mpTextureCoordinates->insert(nIndex, ::basegfx::B2DPoint::getEmptyPoint(), nCount);
1131
0
            }
1132
0
        }
1133
0
    }
1134
1135
    void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
1136
0
    {
1137
0
        if(!nCount)
1138
0
            return;
1139
1140
0
        maPoints.remove(nIndex, nCount);
1141
1142
0
        if(mpBColors)
1143
0
        {
1144
0
            mpBColors->remove(nIndex, nCount);
1145
1146
0
            if(!mpBColors->isUsed())
1147
0
            {
1148
0
                mpBColors.reset();
1149
0
            }
1150
0
        }
1151
1152
0
        if(mpNormals)
1153
0
        {
1154
0
            mpNormals->remove(nIndex, nCount);
1155
1156
0
            if(!mpNormals->isUsed())
1157
0
            {
1158
0
                mpNormals.reset();
1159
0
            }
1160
0
        }
1161
1162
0
        if(mpTextureCoordinates)
1163
0
        {
1164
0
            mpTextureCoordinates->remove(nIndex, nCount);
1165
1166
0
            if(!mpTextureCoordinates->isUsed())
1167
0
            {
1168
0
                mpTextureCoordinates.reset();
1169
0
            }
1170
0
        }
1171
0
    }
1172
1173
    void flip()
1174
0
    {
1175
0
        if(maPoints.count() <= 1)
1176
0
            return;
1177
1178
0
        maPoints.flip();
1179
1180
0
        if(mpBColors)
1181
0
        {
1182
0
            mpBColors->flip();
1183
0
        }
1184
1185
0
        if(mpNormals)
1186
0
        {
1187
0
            mpNormals->flip();
1188
0
        }
1189
1190
0
        if(mpTextureCoordinates)
1191
0
        {
1192
0
            mpTextureCoordinates->flip();
1193
0
        }
1194
0
    }
1195
1196
    bool hasDoublePoints() const
1197
0
    {
1198
0
        if(mbIsClosed)
1199
0
        {
1200
            // check for same start and end point
1201
0
            const sal_uInt32 nIndex(maPoints.count() - 1);
1202
1203
0
            if(maPoints.getCoordinate(0) == maPoints.getCoordinate(nIndex))
1204
0
            {
1205
0
                const bool bBColorEqual(!mpBColors || (mpBColors->getBColor(0) == mpBColors->getBColor(nIndex)));
1206
1207
0
                if(bBColorEqual)
1208
0
                {
1209
0
                    const bool bNormalsEqual(!mpNormals || (mpNormals->getNormal(0) == mpNormals->getNormal(nIndex)));
1210
1211
0
                    if(bNormalsEqual)
1212
0
                    {
1213
0
                        const bool bTextureCoordinatesEqual(!mpTextureCoordinates || (mpTextureCoordinates->getTextureCoordinate(0) == mpTextureCoordinates->getTextureCoordinate(nIndex)));
1214
1215
0
                        if(bTextureCoordinatesEqual)
1216
0
                        {
1217
0
                            return true;
1218
0
                        }
1219
0
                    }
1220
0
                }
1221
0
            }
1222
0
        }
1223
1224
        // test for range
1225
0
        for(sal_uInt32 a(0); a < maPoints.count() - 1; a++)
1226
0
        {
1227
0
            if(maPoints.getCoordinate(a) == maPoints.getCoordinate(a + 1))
1228
0
            {
1229
0
                const bool bBColorEqual(!mpBColors || (mpBColors->getBColor(a) == mpBColors->getBColor(a + 1)));
1230
1231
0
                if(bBColorEqual)
1232
0
                {
1233
0
                    const bool bNormalsEqual(!mpNormals || (mpNormals->getNormal(a) == mpNormals->getNormal(a + 1)));
1234
1235
0
                    if(bNormalsEqual)
1236
0
                    {
1237
0
                        const bool bTextureCoordinatesEqual(!mpTextureCoordinates || (mpTextureCoordinates->getTextureCoordinate(a) == mpTextureCoordinates->getTextureCoordinate(a + 1)));
1238
1239
0
                        if(bTextureCoordinatesEqual)
1240
0
                        {
1241
0
                            return true;
1242
0
                        }
1243
0
                    }
1244
0
                }
1245
0
            }
1246
0
        }
1247
1248
0
        return false;
1249
0
    }
1250
1251
    void removeDoublePointsAtBeginEnd()
1252
0
    {
1253
        // Only remove DoublePoints at Begin and End when poly is closed
1254
0
        if(!mbIsClosed)
1255
0
            return;
1256
1257
0
        bool bRemove;
1258
1259
0
        do
1260
0
        {
1261
0
            bRemove = false;
1262
1263
0
            if(maPoints.count() > 1)
1264
0
            {
1265
0
                const sal_uInt32 nIndex(maPoints.count() - 1);
1266
0
                bRemove = (maPoints.getCoordinate(0) == maPoints.getCoordinate(nIndex));
1267
1268
0
                if(bRemove && mpBColors && mpBColors->getBColor(0) != mpBColors->getBColor(nIndex))
1269
0
                {
1270
0
                    bRemove = false;
1271
0
                }
1272
1273
0
                if(bRemove && mpNormals && mpNormals->getNormal(0) != mpNormals->getNormal(nIndex))
1274
0
                {
1275
0
                    bRemove = false;
1276
0
                }
1277
1278
0
                if(bRemove && mpTextureCoordinates && mpTextureCoordinates->getTextureCoordinate(0) != mpTextureCoordinates->getTextureCoordinate(nIndex))
1279
0
                {
1280
0
                    bRemove = false;
1281
0
                }
1282
0
            }
1283
1284
0
            if(bRemove)
1285
0
            {
1286
0
                const sal_uInt32 nIndex(maPoints.count() - 1);
1287
0
                remove(nIndex, 1);
1288
0
            }
1289
0
        } while(bRemove);
1290
0
    }
1291
1292
    void removeDoublePointsWholeTrack()
1293
0
    {
1294
0
        sal_uInt32 nIndex(0);
1295
1296
        // test as long as there are at least two points and as long as the index
1297
        // is smaller or equal second last point
1298
0
        while((maPoints.count() > 1) && (nIndex <= maPoints.count() - 2))
1299
0
        {
1300
0
            const sal_uInt32 nNextIndex(nIndex + 1);
1301
0
            bool bRemove(maPoints.getCoordinate(nIndex) == maPoints.getCoordinate(nNextIndex));
1302
1303
0
            if(bRemove && mpBColors && mpBColors->getBColor(nIndex) != mpBColors->getBColor(nNextIndex))
1304
0
            {
1305
0
                bRemove = false;
1306
0
            }
1307
1308
0
            if(bRemove && mpNormals && mpNormals->getNormal(nIndex) != mpNormals->getNormal(nNextIndex))
1309
0
            {
1310
0
                bRemove = false;
1311
0
            }
1312
1313
0
            if(bRemove && mpTextureCoordinates && mpTextureCoordinates->getTextureCoordinate(nIndex) != mpTextureCoordinates->getTextureCoordinate(nNextIndex))
1314
0
            {
1315
0
                bRemove = false;
1316
0
            }
1317
1318
0
            if(bRemove)
1319
0
            {
1320
                // if next is same as index and the control vectors are unused, delete index
1321
0
                remove(nIndex, 1);
1322
0
            }
1323
0
            else
1324
0
            {
1325
                // if different, step forward
1326
0
                nIndex++;
1327
0
            }
1328
0
        }
1329
0
    }
1330
1331
    void transform(const ::basegfx::B3DHomMatrix& rMatrix)
1332
2.40k
    {
1333
2.40k
        maPoints.transform(rMatrix);
1334
2.40k
    }
1335
};
1336
1337
namespace basegfx
1338
{
1339
    namespace {
1340
1341
2.40k
    B3DPolygon::ImplType const & getDefaultPolygon() {
1342
2.40k
        static B3DPolygon::ImplType const singleton;
1343
2.40k
        return singleton;
1344
2.40k
    }
1345
1346
    }
1347
1348
    B3DPolygon::B3DPolygon() :
1349
2.40k
        mpPolygon(getDefaultPolygon())
1350
2.40k
    {
1351
2.40k
    }
1352
1353
0
    B3DPolygon::B3DPolygon(const B3DPolygon&) = default;
1354
1355
0
    B3DPolygon::B3DPolygon(B3DPolygon&&) = default;
1356
1357
2.40k
    B3DPolygon::~B3DPolygon() = default;
1358
1359
0
    B3DPolygon& B3DPolygon::operator=(const B3DPolygon&) = default;
1360
1361
0
    B3DPolygon& B3DPolygon::operator=(B3DPolygon&&) = default;
1362
1363
    bool B3DPolygon::operator==(const B3DPolygon& rPolygon) const
1364
0
    {
1365
0
        if(mpPolygon.same_object(rPolygon.mpPolygon))
1366
0
            return true;
1367
1368
0
        return (*mpPolygon == *rPolygon.mpPolygon);
1369
0
    }
1370
1371
    sal_uInt32 B3DPolygon::count() const
1372
0
    {
1373
0
        return mpPolygon->count();
1374
0
    }
1375
1376
    basegfx::B3DPoint const & B3DPolygon::getB3DPoint(sal_uInt32 nIndex) const
1377
19.2k
    {
1378
19.2k
        OSL_ENSURE(nIndex < mpPolygon->count(), "B3DPolygon access outside range (!)");
1379
1380
19.2k
        return mpPolygon->getPoint(nIndex);
1381
19.2k
    }
1382
1383
    void B3DPolygon::setB3DPoint(sal_uInt32 nIndex, const basegfx::B3DPoint& rValue)
1384
0
    {
1385
0
        OSL_ENSURE(nIndex < std::as_const(mpPolygon)->count(), "B3DPolygon access outside range (!)");
1386
1387
0
        if(getB3DPoint(nIndex) != rValue)
1388
0
            mpPolygon->setPoint(nIndex, rValue);
1389
0
    }
1390
1391
    BColor const & B3DPolygon::getBColor(sal_uInt32 nIndex) const
1392
0
    {
1393
0
        OSL_ENSURE(nIndex < mpPolygon->count(), "B3DPolygon access outside range (!)");
1394
1395
0
        return mpPolygon->getBColor(nIndex);
1396
0
    }
1397
1398
    void B3DPolygon::setBColor(sal_uInt32 nIndex, const BColor& rValue)
1399
0
    {
1400
0
        OSL_ENSURE(nIndex < std::as_const(mpPolygon)->count(), "B3DPolygon access outside range (!)");
1401
1402
0
        if(std::as_const(mpPolygon)->getBColor(nIndex) != rValue)
1403
0
            mpPolygon->setBColor(nIndex, rValue);
1404
0
    }
1405
1406
    bool B3DPolygon::areBColorsUsed() const
1407
0
    {
1408
0
        return mpPolygon->areBColorsUsed();
1409
0
    }
1410
1411
    void B3DPolygon::clearBColors()
1412
0
    {
1413
0
        if(std::as_const(mpPolygon)->areBColorsUsed())
1414
0
            mpPolygon->clearBColors();
1415
0
    }
1416
1417
    B3DVector B3DPolygon::getNormal() const
1418
0
    {
1419
0
        return mpPolygon->getNormal();
1420
0
    }
1421
1422
    B3DVector const & B3DPolygon::getNormal(sal_uInt32 nIndex) const
1423
0
    {
1424
0
        OSL_ENSURE(nIndex < mpPolygon->count(), "B3DPolygon access outside range (!)");
1425
1426
0
        return mpPolygon->getNormal(nIndex);
1427
0
    }
1428
1429
    void B3DPolygon::setNormal(sal_uInt32 nIndex, const B3DVector& rValue)
1430
0
    {
1431
0
        OSL_ENSURE(nIndex < std::as_const(mpPolygon)->count(), "B3DPolygon access outside range (!)");
1432
1433
0
        if(std::as_const(mpPolygon)->getNormal(nIndex) != rValue)
1434
0
            mpPolygon->setNormal(nIndex, rValue);
1435
0
    }
1436
1437
    void B3DPolygon::transformNormals(const B3DHomMatrix& rMatrix)
1438
0
    {
1439
0
        if(std::as_const(mpPolygon)->areNormalsUsed() && !rMatrix.isIdentity())
1440
0
            mpPolygon->transformNormals(rMatrix);
1441
0
    }
1442
1443
    bool B3DPolygon::areNormalsUsed() const
1444
0
    {
1445
0
        return mpPolygon->areNormalsUsed();
1446
0
    }
1447
1448
    void B3DPolygon::clearNormals()
1449
0
    {
1450
0
        if(std::as_const(mpPolygon)->areNormalsUsed())
1451
0
            mpPolygon->clearNormals();
1452
0
    }
1453
1454
    B2DPoint const & B3DPolygon::getTextureCoordinate(sal_uInt32 nIndex) const
1455
0
    {
1456
0
        OSL_ENSURE(nIndex < mpPolygon->count(), "B3DPolygon access outside range (!)");
1457
1458
0
        return mpPolygon->getTextureCoordinate(nIndex);
1459
0
    }
1460
1461
    void B3DPolygon::setTextureCoordinate(sal_uInt32 nIndex, const B2DPoint& rValue)
1462
0
    {
1463
0
        OSL_ENSURE(nIndex < std::as_const(mpPolygon)->count(), "B3DPolygon access outside range (!)");
1464
1465
0
        if(std::as_const(mpPolygon)->getTextureCoordinate(nIndex) != rValue)
1466
0
            mpPolygon->setTextureCoordinate(nIndex, rValue);
1467
0
    }
1468
1469
    void B3DPolygon::transformTextureCoordinates(const B2DHomMatrix& rMatrix)
1470
0
    {
1471
0
        if(std::as_const(mpPolygon)->areTextureCoordinatesUsed() && !rMatrix.isIdentity())
1472
0
            mpPolygon->transformTextureCoordinates(rMatrix);
1473
0
    }
1474
1475
    bool B3DPolygon::areTextureCoordinatesUsed() const
1476
0
    {
1477
0
        return mpPolygon->areTextureCoordinatesUsed();
1478
0
    }
1479
1480
    void B3DPolygon::clearTextureCoordinates()
1481
0
    {
1482
0
        if(std::as_const(mpPolygon)->areTextureCoordinatesUsed())
1483
0
            mpPolygon->clearTextureCoordinates();
1484
0
    }
1485
1486
    void B3DPolygon::append(const basegfx::B3DPoint& rPoint, sal_uInt32 nCount)
1487
19.2k
    {
1488
19.2k
        if(nCount)
1489
19.2k
            mpPolygon->insert(std::as_const(mpPolygon)->count(), rPoint, nCount);
1490
19.2k
    }
1491
1492
    void B3DPolygon::append(const B3DPolygon& rPoly, sal_uInt32 nIndex, sal_uInt32 nCount)
1493
0
    {
1494
0
        if(!rPoly.count())
1495
0
            return;
1496
1497
0
        if(!nCount)
1498
0
        {
1499
0
            nCount = rPoly.count();
1500
0
        }
1501
1502
0
        if(nIndex == 0 && nCount == rPoly.count())
1503
0
        {
1504
0
            mpPolygon->insert(std::as_const(mpPolygon)->count(), *rPoly.mpPolygon);
1505
0
        }
1506
0
        else
1507
0
        {
1508
0
            OSL_ENSURE(nIndex + nCount <= rPoly.mpPolygon->count(), "B3DPolygon Append outside range (!)");
1509
0
            ImplB3DPolygon aTempPoly(*rPoly.mpPolygon, nIndex, nCount);
1510
0
            mpPolygon->insert(std::as_const(mpPolygon)->count(), aTempPoly);
1511
0
        }
1512
0
    }
1513
1514
    void B3DPolygon::remove(sal_uInt32 nIndex, sal_uInt32 nCount)
1515
0
    {
1516
0
        OSL_ENSURE(nIndex + nCount <= std::as_const(mpPolygon)->count(), "B3DPolygon Remove outside range (!)");
1517
1518
0
        if(nCount)
1519
0
            mpPolygon->remove(nIndex, nCount);
1520
0
    }
1521
1522
    void B3DPolygon::clear()
1523
0
    {
1524
0
        mpPolygon = getDefaultPolygon();
1525
0
    }
1526
1527
    bool B3DPolygon::isClosed() const
1528
0
    {
1529
0
        return mpPolygon->isClosed();
1530
0
    }
1531
1532
    void B3DPolygon::setClosed(bool bNew)
1533
0
    {
1534
0
        if(isClosed() != bNew)
1535
0
            mpPolygon->setClosed(bNew);
1536
0
    }
1537
1538
    void B3DPolygon::flip()
1539
0
    {
1540
0
        if(count() > 1)
1541
0
            mpPolygon->flip();
1542
0
    }
1543
1544
    bool B3DPolygon::hasDoublePoints() const
1545
0
    {
1546
0
        return (mpPolygon->count() > 1 && mpPolygon->hasDoublePoints());
1547
0
    }
1548
1549
    void B3DPolygon::removeDoublePoints()
1550
0
    {
1551
0
        if(hasDoublePoints())
1552
0
        {
1553
0
            mpPolygon->removeDoublePointsAtBeginEnd();
1554
0
            mpPolygon->removeDoublePointsWholeTrack();
1555
0
        }
1556
0
    }
1557
1558
    void B3DPolygon::transform(const basegfx::B3DHomMatrix& rMatrix)
1559
2.40k
    {
1560
2.40k
        if(std::as_const(mpPolygon)->count() && !rMatrix.isIdentity())
1561
2.40k
        {
1562
2.40k
            mpPolygon->transform(rMatrix);
1563
2.40k
        }
1564
2.40k
    }
1565
} // end of namespace basegfx
1566
1567
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */