LibreOffice Module basegfx (master) 1
b2dpolygon.cxx
Go to the documentation of this file.
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 <sal/config.h>
21
29#include <memory>
30#include <vector>
31
32namespace
33{
34
35class CoordinateDataArray2D
36{
37private:
38 std::vector<basegfx::B2DPoint> maVector;
39
40public:
41 explicit CoordinateDataArray2D(sal_uInt32 nCount)
42 : maVector(nCount)
43 {
44 }
45
46 CoordinateDataArray2D(const CoordinateDataArray2D& rOriginal, sal_uInt32 nIndex, sal_uInt32 nCount)
47 : maVector(rOriginal.maVector.begin() + nIndex, rOriginal.maVector.begin() + (nIndex + nCount))
48 {
49 }
50
51 sal_uInt32 count() const
52 {
53 return maVector.size();
54 }
55
56 bool operator==(const CoordinateDataArray2D& rCandidate) const
57 {
58 return (maVector == rCandidate.maVector);
59 }
60
61 const basegfx::B2DPoint& getCoordinate(sal_uInt32 nIndex) const
62 {
63 assert(nIndex < maVector.size());
64 return maVector[nIndex];
65 }
66
67 void setCoordinate(sal_uInt32 nIndex, const basegfx::B2DPoint& rValue)
68 {
69 assert(nIndex < maVector.size());
70 maVector[nIndex] = rValue;
71 }
72
73 void reserve(sal_uInt32 nCount)
74 {
75 maVector.reserve(nCount);
76 }
77
78 void append(const basegfx::B2DPoint& rValue)
79 {
80 maVector.push_back(rValue);
81 }
82
83 void insert(sal_uInt32 nIndex, const basegfx::B2DPoint& rValue, sal_uInt32 nCount)
84 {
85 assert(nCount > 0);
86 assert(nIndex <= maVector.size());
87 // add nCount copies of rValue
88 maVector.insert(maVector.begin() + nIndex, nCount, rValue);
89 }
90
91 void insert(sal_uInt32 nIndex, const CoordinateDataArray2D& rSource)
92 {
93 assert(rSource.maVector.size() > 0);
94 assert(nIndex <= maVector.size());
95 // insert data
96 auto aIndex = maVector.begin();
97 aIndex += nIndex;
98 auto aStart = rSource.maVector.cbegin();
99 auto aEnd = rSource.maVector.cend();
100 maVector.insert(aIndex, aStart, aEnd);
101 }
102
103 void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
104 {
105 assert(nCount > 0);
106 assert(nIndex + nCount <= maVector.size());
107 // remove point data
108 const auto aStart = maVector.begin() + nIndex;
109 const auto aEnd = aStart + nCount;
110 maVector.erase(aStart, aEnd);
111 }
112
113 void flip(bool bIsClosed)
114 {
115 assert(maVector.size() > 1);
116
117 // to keep the same point at index 0, just flip all points except the
118 // first one when closed
119 const sal_uInt32 nHalfSize(bIsClosed ? (maVector.size() - 1) >> 1 : maVector.size() >> 1);
120 auto aStart = bIsClosed ? maVector.begin() + 1 : maVector.begin();
121 auto aEnd = maVector.end() - 1;
122
123 for(sal_uInt32 a(0); a < nHalfSize; a++)
124 {
125 std::swap(*aStart, *aEnd);
126 ++aStart;
127 --aEnd;
128 }
129 }
130
131 void removeDoublePointsAtBeginEnd()
132 {
133 // remove from end as long as there are at least two points
134 // and begin/end are equal
135 while((maVector.size() > 1) && (maVector[0] == maVector[maVector.size() - 1]))
136 {
137 maVector.pop_back();
138 }
139 }
140
141 void removeDoublePointsWholeTrack()
142 {
143 sal_uInt32 nIndex(0);
144
145 // test as long as there are at least two points and as long as the index
146 // is smaller or equal second last point
147 while((maVector.size() > 1) && (nIndex <= maVector.size() - 2))
148 {
149 if(maVector[nIndex] == maVector[nIndex + 1])
150 {
151 // if next is same as index, delete next
152 maVector.erase(maVector.begin() + (nIndex + 1));
153 }
154 else
155 {
156 // if different, step forward
157 nIndex++;
158 }
159 }
160 }
161
162 void transform(const basegfx::B2DHomMatrix& rMatrix)
163 {
164 for (auto& point : maVector)
165 {
166 point *= rMatrix;
167 }
168 }
169};
170
171class ControlVectorPair2D
172{
173 basegfx::B2DVector maPrevVector;
174 basegfx::B2DVector maNextVector;
175
176public:
177 explicit ControlVectorPair2D() {}
178
179 const basegfx::B2DVector& getPrevVector() const
180 {
181 return maPrevVector;
182 }
183
184 void setPrevVector(const basegfx::B2DVector& rValue)
185 {
186 if(rValue != maPrevVector)
187 maPrevVector = rValue;
188 }
189
190 const basegfx::B2DVector& getNextVector() const
191 {
192 return maNextVector;
193 }
194
195 void setNextVector(const basegfx::B2DVector& rValue)
196 {
197 if(rValue != maNextVector)
198 maNextVector = rValue;
199 }
200
201 bool operator==(const ControlVectorPair2D& rData) const
202 {
203 return (maPrevVector == rData.getPrevVector() && maNextVector == rData.getNextVector());
204 }
205
206 void flip()
207 {
208 std::swap(maPrevVector, maNextVector);
209 }
210};
211
212class ControlVectorArray2D
213{
214 typedef std::vector< ControlVectorPair2D > ControlVectorPair2DVector;
215
216 ControlVectorPair2DVector maVector;
217 sal_uInt32 mnUsedVectors;
218
219public:
220 explicit ControlVectorArray2D(sal_uInt32 nCount)
221 : maVector(nCount),
222 mnUsedVectors(0)
223 {}
224
225 ControlVectorArray2D(const ControlVectorArray2D& rOriginal, sal_uInt32 nIndex, sal_uInt32 nCount)
226 : mnUsedVectors(0)
227 {
228 assert(nIndex + nCount <= rOriginal.maVector.size());
229 auto aStart(rOriginal.maVector.begin() + nIndex);
230 auto aEnd(aStart + nCount);
231 maVector.reserve(nCount);
232
233 for(; aStart != aEnd; ++aStart)
234 {
235 if(!aStart->getPrevVector().equalZero())
236 mnUsedVectors++;
237
238 if(!aStart->getNextVector().equalZero())
239 mnUsedVectors++;
240
241 maVector.push_back(*aStart);
242 }
243 }
244
245 bool operator==(const ControlVectorArray2D& rCandidate) const
246 {
247 return (maVector == rCandidate.maVector);
248 }
249
250 bool isUsed() const
251 {
252 return (mnUsedVectors != 0);
253 }
254
255 const basegfx::B2DVector& getPrevVector(sal_uInt32 nIndex) const
256 {
257 assert(nIndex < maVector.size());
258 return maVector[nIndex].getPrevVector();
259 }
260
261 void setPrevVector(sal_uInt32 nIndex, const basegfx::B2DVector& rValue)
262 {
263 bool bWasUsed(mnUsedVectors && !maVector[nIndex].getPrevVector().equalZero());
264 bool bIsUsed(!rValue.equalZero());
265
266 if(bWasUsed)
267 {
268 if(bIsUsed)
269 {
270 maVector[nIndex].setPrevVector(rValue);
271 }
272 else
273 {
274 maVector[nIndex].setPrevVector(basegfx::B2DVector::getEmptyVector());
275 mnUsedVectors--;
276 }
277 }
278 else
279 {
280 if(bIsUsed)
281 {
282 maVector[nIndex].setPrevVector(rValue);
283 mnUsedVectors++;
284 }
285 }
286 }
287
288 const basegfx::B2DVector& getNextVector(sal_uInt32 nIndex) const
289 {
290 assert(nIndex < maVector.size());
291 return maVector[nIndex].getNextVector();
292 }
293
294 void setNextVector(sal_uInt32 nIndex, const basegfx::B2DVector& rValue)
295 {
296 bool bWasUsed(mnUsedVectors && !maVector[nIndex].getNextVector().equalZero());
297 bool bIsUsed(!rValue.equalZero());
298
299 if(bWasUsed)
300 {
301 if(bIsUsed)
302 {
303 maVector[nIndex].setNextVector(rValue);
304 }
305 else
306 {
307 maVector[nIndex].setNextVector(basegfx::B2DVector::getEmptyVector());
308 mnUsedVectors--;
309 }
310 }
311 else
312 {
313 if(bIsUsed)
314 {
315 maVector[nIndex].setNextVector(rValue);
316 mnUsedVectors++;
317 }
318 }
319 }
320
321 void append(const ControlVectorPair2D& rValue)
322 {
323 maVector.push_back(rValue);
324
325 if(!rValue.getPrevVector().equalZero())
326 mnUsedVectors += 1;
327
328 if(!rValue.getNextVector().equalZero())
329 mnUsedVectors += 1;
330 }
331
332 void insert(sal_uInt32 nIndex, const ControlVectorPair2D& rValue, sal_uInt32 nCount)
333 {
334 assert(nCount > 0);
335 assert(nIndex <= maVector.size());
336
337 // add nCount copies of rValue
338 maVector.insert(maVector.begin() + nIndex, nCount, rValue);
339
340 if(!rValue.getPrevVector().equalZero())
341 mnUsedVectors += nCount;
342
343 if(!rValue.getNextVector().equalZero())
344 mnUsedVectors += nCount;
345 }
346
347 void insert(sal_uInt32 nIndex, const ControlVectorArray2D& rSource)
348 {
349 assert(rSource.maVector.size() > 0);
350 assert(nIndex <= maVector.size());
351
352 // insert data
353 ControlVectorPair2DVector::iterator aIndex(maVector.begin() + nIndex);
354 ControlVectorPair2DVector::const_iterator aStart(rSource.maVector.begin());
355 ControlVectorPair2DVector::const_iterator aEnd(rSource.maVector.end());
356 maVector.insert(aIndex, aStart, aEnd);
357
358 for(; aStart != aEnd; ++aStart)
359 {
360 if(!aStart->getPrevVector().equalZero())
361 mnUsedVectors++;
362
363 if(!aStart->getNextVector().equalZero())
364 mnUsedVectors++;
365 }
366 }
367
368 void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
369 {
370 assert(nCount > 0);
371 assert(nIndex + nCount <= maVector.size());
372
373 const ControlVectorPair2DVector::iterator aDeleteStart(maVector.begin() + nIndex);
374 const ControlVectorPair2DVector::iterator aDeleteEnd(aDeleteStart + nCount);
375 ControlVectorPair2DVector::const_iterator aStart(aDeleteStart);
376
377 for(; mnUsedVectors && aStart != aDeleteEnd; ++aStart)
378 {
379 if(!aStart->getPrevVector().equalZero())
380 mnUsedVectors--;
381
382 if(mnUsedVectors && !aStart->getNextVector().equalZero())
383 mnUsedVectors--;
384 }
385
386 // remove point data
387 maVector.erase(aDeleteStart, aDeleteEnd);
388 }
389
390 void flip(bool bIsClosed)
391 {
392 assert(maVector.size() > 1);
393
394 // to keep the same point at index 0, just flip all points except the
395 // first one when closed
396 const sal_uInt32 nHalfSize(bIsClosed ? (maVector.size() - 1) >> 1 : maVector.size() >> 1);
397 ControlVectorPair2DVector::iterator aStart(bIsClosed ? maVector.begin() + 1 : maVector.begin());
398 ControlVectorPair2DVector::iterator aEnd(maVector.end() - 1);
399
400 for(sal_uInt32 a(0); a < nHalfSize; a++)
401 {
402 // swap Prev and Next
403 aStart->flip();
404 aEnd->flip();
405
406 // swap entries
407 std::swap(*aStart, *aEnd);
408
409 ++aStart;
410 --aEnd;
411 }
412
413 if(aStart == aEnd)
414 {
415 // swap Prev and Next at middle element (if exists)
416 aStart->flip();
417 }
418
419 if(bIsClosed)
420 {
421 // swap Prev and Next at start element
422 maVector.begin()->flip();
423 }
424 }
425};
426
427class ImplBufferedData : public basegfx::SystemDependentDataHolder
428{
429private:
430 // Possibility to hold the last subdivision
431 mutable std::optional< basegfx::B2DPolygon > mpDefaultSubdivision;
432
433 // Possibility to hold the last B2DRange calculation
434 mutable std::optional< basegfx::B2DRange > moB2DRange;
435
436public:
437 ImplBufferedData()
438 {
439 }
440
441 const basegfx::B2DPolygon& getDefaultAdaptiveSubdivision(const basegfx::B2DPolygon& rSource) const
442 {
443 if(!mpDefaultSubdivision)
444 {
445 mpDefaultSubdivision = basegfx::utils::adaptiveSubdivideByAngle(rSource);
446 }
447
448 return *mpDefaultSubdivision;
449 }
450
451 const basegfx::B2DRange& getB2DRange(const basegfx::B2DPolygon& rSource) const
452 {
453 if(!moB2DRange)
454 {
455 basegfx::B2DRange aNewRange;
456 const sal_uInt32 nPointCount(rSource.count());
457
458 if(nPointCount)
459 {
460 for(sal_uInt32 a(0); a < nPointCount; a++)
461 {
462 aNewRange.expand(rSource.getB2DPoint(a));
463 }
464
465 if(rSource.areControlPointsUsed())
466 {
467 const sal_uInt32 nEdgeCount(rSource.isClosed() ? nPointCount : nPointCount - 1);
468
469 if(nEdgeCount)
470 {
472 aEdge.setStartPoint(rSource.getB2DPoint(0));
473
474 for(sal_uInt32 b(0); b < nEdgeCount; b++)
475 {
476 const sal_uInt32 nNextIndex((b + 1) % nPointCount);
477 aEdge.setControlPointA(rSource.getNextControlPoint(b));
478 aEdge.setControlPointB(rSource.getPrevControlPoint(nNextIndex));
479 aEdge.setEndPoint(rSource.getB2DPoint(nNextIndex));
480
481 if(aEdge.isBezier())
482 {
483 const basegfx::B2DRange aBezierRangeWithControlPoints(aEdge.getRange());
484
485 if(!aNewRange.isInside(aBezierRangeWithControlPoints))
486 {
487 // the range with control points of the current edge is not completely
488 // inside the current range without control points. Expand current range by
489 // subdividing the bezier segment.
490 // Ideal here is a subdivision at the extreme values, so use
491 // getAllExtremumPositions to get all extremas in one run
492 std::vector< double > aExtremas;
493
494 aExtremas.reserve(4);
495 aEdge.getAllExtremumPositions(aExtremas);
496
497 const sal_uInt32 nExtremaCount(aExtremas.size());
498
499 for(sal_uInt32 c(0); c < nExtremaCount; c++)
500 {
501 aNewRange.expand(aEdge.interpolatePoint(aExtremas[c]));
502 }
503 }
504 }
505
506 // prepare next edge
507 aEdge.setStartPoint(aEdge.getEndPoint());
508 }
509 }
510 }
511 }
512
513 moB2DRange = aNewRange;
514 }
515
516 return *moB2DRange;
517 }
518};
519
520}
521
523{
524private:
525 // The point vector. This vector exists always and defines the
526 // count of members.
527 CoordinateDataArray2D maPoints;
528
529 // The control point vectors. This vectors are created on demand
530 // and may be zero.
531 std::optional< ControlVectorArray2D > moControlVector;
532
533 // buffered data for e.g. default subdivision and range
534 // we do not want to 'modify' the ImplB2DPolygon,
535 // but add buffered data that is valid for all referencing instances
536 mutable std::unique_ptr<ImplBufferedData> mpBufferedData;
537
538 // flag which decides if this polygon is opened or closed
540
541public:
543 {
544 if(!moControlVector || !moControlVector->isUsed())
545 {
546 return rSource;
547 }
548
549 if(!mpBufferedData)
550 {
551 mpBufferedData.reset(new ImplBufferedData);
552 }
553
554 return mpBufferedData->getDefaultAdaptiveSubdivision(rSource);
555 }
556
558 {
559 if(!mpBufferedData)
560 {
561 mpBufferedData.reset(new ImplBufferedData);
562 }
563
564 return mpBufferedData->getB2DRange(rSource);
565 }
566
568 : maPoints(0),
569 mbIsClosed(false)
570 {}
571
572 ImplB2DPolygon(const ImplB2DPolygon& rToBeCopied)
573 : maPoints(rToBeCopied.maPoints),
574 mbIsClosed(rToBeCopied.mbIsClosed)
575 {
576 // complete initialization using copy
577 if(rToBeCopied.moControlVector && rToBeCopied.moControlVector->isUsed())
578 {
579 moControlVector.emplace( *rToBeCopied.moControlVector );
580 }
581 }
582
583 ImplB2DPolygon(const ImplB2DPolygon& rToBeCopied, sal_uInt32 nIndex, sal_uInt32 nCount)
584 : maPoints(rToBeCopied.maPoints, nIndex, nCount),
585 mbIsClosed(rToBeCopied.mbIsClosed)
586 {
587 // complete initialization using partly copy
588 if(rToBeCopied.moControlVector && rToBeCopied.moControlVector->isUsed())
589 {
590 moControlVector.emplace( *rToBeCopied.moControlVector, nIndex, nCount );
591
592 if(!moControlVector->isUsed())
593 moControlVector.reset();
594 }
595 }
596
598 {
599 if (this != &rOther)
600 {
601 moControlVector.reset();
602 mpBufferedData.reset();
603 maPoints = rOther.maPoints;
604 mbIsClosed = rOther.mbIsClosed;
605 if (rOther.moControlVector && rOther.moControlVector->isUsed())
606 {
607 moControlVector.emplace( *rOther.moControlVector );
608
609 if(!moControlVector->isUsed())
610 moControlVector.reset();
611 }
612 }
613 return *this;
614 }
615
616 sal_uInt32 count() const
617 {
618 return maPoints.count();
619 }
620
621 bool isClosed() const
622 {
623 return mbIsClosed;
624 }
625
626 void setClosed(bool bNew)
627 {
628 if(bNew != mbIsClosed)
629 {
630 mpBufferedData.reset();
631 mbIsClosed = bNew;
632 }
633 }
634
635 bool operator==(const ImplB2DPolygon& rCandidate) const
636 {
637 if(mbIsClosed != rCandidate.mbIsClosed)
638 return false;
639 if(!(maPoints == rCandidate.maPoints))
640 return false;
641 bool bControlVectorsAreEqual(true);
642
644 {
645 if(rCandidate.moControlVector)
646 {
647 bControlVectorsAreEqual = ((*moControlVector) == (*rCandidate.moControlVector));
648 }
649 else
650 {
651 // candidate has no control vector, so it's assumed all unused.
652 bControlVectorsAreEqual = !moControlVector->isUsed();
653 }
654 }
655 else
656 {
657 if(rCandidate.moControlVector)
658 {
659 // we have no control vector, so it's assumed all unused.
660 bControlVectorsAreEqual = !rCandidate.moControlVector->isUsed();
661 }
662 }
663
664 return bControlVectorsAreEqual;
665 }
666
667 const basegfx::B2DPoint& getPoint(sal_uInt32 nIndex) const
668 {
669 return maPoints.getCoordinate(nIndex);
670 }
671
672 void setPoint(sal_uInt32 nIndex, const basegfx::B2DPoint& rValue)
673 {
674 mpBufferedData.reset();
675 maPoints.setCoordinate(nIndex, rValue);
676 }
677
678 void reserve(sal_uInt32 nCount)
679 {
680 maPoints.reserve(nCount);
681 }
682
683 void append(const basegfx::B2DPoint& rPoint)
684 {
685 mpBufferedData.reset(); // TODO: is this needed?
686 const auto aCoordinate = rPoint;
687 maPoints.append(aCoordinate);
688
690 {
691 const ControlVectorPair2D aVectorPair;
692 moControlVector->append(aVectorPair);
693 }
694 }
695
696 void insert(sal_uInt32 nIndex, const basegfx::B2DPoint& rPoint, sal_uInt32 nCount)
697 {
698 assert(nCount > 0);
699 mpBufferedData.reset();
700 auto aCoordinate = rPoint;
701 maPoints.insert(nIndex, aCoordinate, nCount);
702
704 {
705 ControlVectorPair2D aVectorPair;
706 moControlVector->insert(nIndex, aVectorPair, nCount);
707 }
708 }
709
710 void append(const basegfx::B2DPoint& rPoint, sal_uInt32 nCount)
711 {
712 insert(count(), rPoint, nCount);
713 }
714
715 const basegfx::B2DVector& getPrevControlVector(sal_uInt32 nIndex) const
716 {
718 {
719 return moControlVector->getPrevVector(nIndex);
720 }
721 else
722 {
724 }
725 }
726
727 void setPrevControlVector(sal_uInt32 nIndex, const basegfx::B2DVector& rValue)
728 {
729 if(!moControlVector)
730 {
731 if(!rValue.equalZero())
732 {
733 mpBufferedData.reset();
734 moControlVector.emplace(maPoints.count());
735 moControlVector->setPrevVector(nIndex, rValue);
736 }
737 }
738 else
739 {
740 mpBufferedData.reset();
741 moControlVector->setPrevVector(nIndex, rValue);
742
743 if(!moControlVector->isUsed())
744 moControlVector.reset();
745 }
746 }
747
748 const basegfx::B2DVector& getNextControlVector(sal_uInt32 nIndex) const
749 {
751 {
752 return moControlVector->getNextVector(nIndex);
753 }
754 else
755 {
757 }
758 }
759
760 void setNextControlVector(sal_uInt32 nIndex, const basegfx::B2DVector& rValue)
761 {
762 if(!moControlVector)
763 {
764 if(!rValue.equalZero())
765 {
766 mpBufferedData.reset();
767 moControlVector.emplace(maPoints.count());
768 moControlVector->setNextVector(nIndex, rValue);
769 }
770 }
771 else
772 {
773 mpBufferedData.reset();
774 moControlVector->setNextVector(nIndex, rValue);
775
776 if(!moControlVector->isUsed())
777 moControlVector.reset();
778 }
779 }
780
782 {
783 return (moControlVector && moControlVector->isUsed());
784 }
785
787 {
788 mpBufferedData.reset();
789 moControlVector.reset();
790 }
791
792 void setControlVectors(sal_uInt32 nIndex, const basegfx::B2DVector& rPrev, const basegfx::B2DVector& rNext)
793 {
796 }
797
798 void appendBezierSegment(const basegfx::B2DVector& rNext, const basegfx::B2DVector& rPrev, const basegfx::B2DPoint& rPoint)
799 {
800 mpBufferedData.reset();
801 const sal_uInt32 nCount(maPoints.count());
802
803 if(nCount)
804 {
805 setNextControlVector(nCount - 1, rNext);
806 }
807
808 insert(nCount, rPoint, 1);
810 }
811
812 void append(const ImplB2DPolygon& rSource)
813 {
814 assert(rSource.maPoints.count() > 0);
815 const sal_uInt32 nIndex = count();
816
817 mpBufferedData.reset();
818
819 maPoints.insert(nIndex, rSource.maPoints);
820
821 if(rSource.moControlVector)
822 {
823 if (!moControlVector)
824 moControlVector.emplace(nIndex);
825 moControlVector->insert(nIndex, *rSource.moControlVector);
826
827 if(!moControlVector->isUsed())
828 moControlVector.reset();
829 }
830 else if(moControlVector)
831 {
832 ControlVectorPair2D aVectorPair;
833 moControlVector->insert(nIndex, aVectorPair, rSource.count());
834 }
835 }
836
837 void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
838 {
839 assert(nCount > 0);
840 mpBufferedData.reset();
841 maPoints.remove(nIndex, nCount);
842
844 {
845 moControlVector->remove(nIndex, nCount);
846
847 if(!moControlVector->isUsed())
848 moControlVector.reset();
849 }
850 }
851
852 void flip()
853 {
854 assert(maPoints.count() > 1);
855
856 mpBufferedData.reset();
857
858 // flip points
859 maPoints.flip(mbIsClosed);
860
862 {
863 // flip control vector
865 }
866 }
867
868 bool hasDoublePoints() const
869 {
870 if(mbIsClosed)
871 {
872 // check for same start and end point
873 const sal_uInt32 nIndex(maPoints.count() - 1);
874
875 if(maPoints.getCoordinate(0) == maPoints.getCoordinate(nIndex))
876 {
878 {
879 if(moControlVector->getNextVector(nIndex).equalZero() && moControlVector->getPrevVector(0).equalZero())
880 {
881 return true;
882 }
883 }
884 else
885 {
886 return true;
887 }
888 }
889 }
890
891 // test for range
892 for(sal_uInt32 a(0); a < maPoints.count() - 1; a++)
893 {
894 if(maPoints.getCoordinate(a) == maPoints.getCoordinate(a + 1))
895 {
897 {
898 if(moControlVector->getNextVector(a).equalZero() && moControlVector->getPrevVector(a + 1).equalZero())
899 {
900 return true;
901 }
902 }
903 else
904 {
905 return true;
906 }
907 }
908 }
909
910 return false;
911 }
912
914 {
915 // Only remove DoublePoints at Begin and End when poly is closed
916 if(!mbIsClosed)
917 return;
918
919 mpBufferedData.reset();
920
922 {
923 bool bRemove;
924
925 do
926 {
927 bRemove = false;
928
929 if(maPoints.count() > 1)
930 {
931 const sal_uInt32 nIndex(maPoints.count() - 1);
932
933 if(maPoints.getCoordinate(0) == maPoints.getCoordinate(nIndex))
934 {
936 {
937 if(moControlVector->getNextVector(nIndex).equalZero() && moControlVector->getPrevVector(0).equalZero())
938 {
939 bRemove = true;
940 }
941 }
942 else
943 {
944 bRemove = true;
945 }
946 }
947 }
948
949 if(bRemove)
950 {
951 const sal_uInt32 nIndex(maPoints.count() - 1);
952
953 if(moControlVector && !moControlVector->getPrevVector(nIndex).equalZero())
954 {
955 moControlVector->setPrevVector(0, moControlVector->getPrevVector(nIndex));
956 }
957
958 remove(nIndex, 1);
959 }
960 }
961 while(bRemove);
962 }
963 else
964 {
965 maPoints.removeDoublePointsAtBeginEnd();
966 }
967 }
968
970 {
971 mpBufferedData.reset();
972
974 {
975 sal_uInt32 nIndex(0);
976
977 // test as long as there are at least two points and as long as the index
978 // is smaller or equal second last point
979 while((maPoints.count() > 1) && (nIndex <= maPoints.count() - 2))
980 {
981 bool bRemove(maPoints.getCoordinate(nIndex) == maPoints.getCoordinate(nIndex + 1));
982
983 if(bRemove && moControlVector)
984 {
985 if(!moControlVector->getNextVector(nIndex).equalZero() || !moControlVector->getPrevVector(nIndex + 1).equalZero())
986 {
987 bRemove = false;
988 }
989 }
990
991 if(bRemove)
992 {
993 if(moControlVector && !moControlVector->getPrevVector(nIndex).equalZero())
994 {
995 moControlVector->setPrevVector(nIndex + 1, moControlVector->getPrevVector(nIndex));
996 }
997
998 // if next is same as index and the control vectors are unused, delete index
999 remove(nIndex, 1);
1000 }
1001 else
1002 {
1003 // if different, step forward
1004 nIndex++;
1005 }
1006 }
1007 }
1008 else
1009 {
1010 maPoints.removeDoublePointsWholeTrack();
1011 }
1012 }
1013
1015 {
1016 mpBufferedData.reset();
1017
1018 if(moControlVector)
1019 {
1020 for(sal_uInt32 a(0); a < maPoints.count(); a++)
1021 {
1022 basegfx::B2DPoint aCandidate = maPoints.getCoordinate(a);
1023
1024 if(moControlVector->isUsed())
1025 {
1026 const basegfx::B2DVector& rPrevVector(moControlVector->getPrevVector(a));
1027 const basegfx::B2DVector& rNextVector(moControlVector->getNextVector(a));
1028
1029 if(!rPrevVector.equalZero())
1030 {
1031 basegfx::B2DVector aPrevVector(rMatrix * rPrevVector);
1032 moControlVector->setPrevVector(a, aPrevVector);
1033 }
1034
1035 if(!rNextVector.equalZero())
1036 {
1037 basegfx::B2DVector aNextVector(rMatrix * rNextVector);
1038 moControlVector->setNextVector(a, aNextVector);
1039 }
1040 }
1041
1042 aCandidate *= rMatrix;
1043 maPoints.setCoordinate(a, aCandidate);
1044 }
1045
1046 if(!moControlVector->isUsed())
1047 moControlVector.reset();
1048 }
1049 else
1050 {
1051 maPoints.transform(rMatrix);
1052 }
1053 }
1054
1056 {
1057 if(!mpBufferedData)
1058 {
1059 mpBufferedData.reset(new ImplBufferedData);
1060 }
1061
1062 mpBufferedData->addOrReplaceSystemDependentData(rData);
1063 }
1064
1066 {
1067 if(mpBufferedData)
1068 {
1069 return mpBufferedData->getSystemDependentData(hash_code);
1070 }
1071
1073 }
1074};
1075
1076namespace basegfx
1077{
1079
1081 : mpPolygon(DEFAULT) {}
1082
1083 B2DPolygon::B2DPolygon(std::initializer_list<basegfx::B2DPoint> aPoints)
1084 {
1085 for (const basegfx::B2DPoint& rPoint : aPoints)
1086 {
1087 append(rPoint);
1088 }
1089 }
1090
1091 B2DPolygon::B2DPolygon(const B2DPolygon&) = default;
1092
1094
1095 B2DPolygon::B2DPolygon(const B2DPolygon& rPolygon, sal_uInt32 nIndex, sal_uInt32 nCount)
1096 : mpPolygon(ImplB2DPolygon(*rPolygon.mpPolygon, nIndex, nCount))
1097 {
1098 }
1099
1100 B2DPolygon::~B2DPolygon() = default;
1101
1102 B2DPolygon& B2DPolygon::operator=(const B2DPolygon&) = default;
1103
1105
1107 {
1109 }
1110
1111 bool B2DPolygon::operator==(const B2DPolygon& rPolygon) const
1112 {
1113 if(mpPolygon.same_object(rPolygon.mpPolygon))
1114 return true;
1115
1116 return ((*mpPolygon) == (*rPolygon.mpPolygon));
1117 }
1118
1119 bool B2DPolygon::operator!=(const B2DPolygon& rPolygon) const
1120 {
1121 return !(*this == rPolygon);
1122 }
1123
1124 sal_uInt32 B2DPolygon::count() const
1125 {
1126 return mpPolygon->count();
1127 }
1128
1129 B2DPoint const & B2DPolygon::getB2DPoint(sal_uInt32 nIndex) const
1130 {
1131 return mpPolygon->getPoint(nIndex);
1132 }
1133
1134 void B2DPolygon::setB2DPoint(sal_uInt32 nIndex, const B2DPoint& rValue)
1135 {
1136 if(getB2DPoint(nIndex) != rValue)
1137 {
1138 mpPolygon->setPoint(nIndex, rValue);
1139 }
1140 }
1141
1142 void B2DPolygon::reserve(sal_uInt32 nCount)
1143 {
1144 mpPolygon->reserve(nCount);
1145 }
1146
1147 void B2DPolygon::insert(sal_uInt32 nIndex, const B2DPoint& rPoint, sal_uInt32 nCount)
1148 {
1149 if(nCount)
1150 {
1151 mpPolygon->insert(nIndex, rPoint, nCount);
1152 }
1153 }
1154
1155 void B2DPolygon::append(const B2DPoint& rPoint, sal_uInt32 nCount)
1156 {
1157 if(nCount)
1158 {
1159 mpPolygon->append(rPoint, nCount);
1160 }
1161 }
1162
1163 void B2DPolygon::append(const B2DPoint& rPoint)
1164 {
1165 mpPolygon->append(rPoint);
1166 }
1167
1169 {
1170 return mpPolygon->getPrevControlVector(nIndex);
1171 }
1172
1174 {
1175 return mpPolygon->getNextControlVector(nIndex);
1176 }
1177
1179 {
1181 {
1183 }
1184 else
1185 {
1186 return getB2DPoint(nIndex);
1187 }
1188 }
1189
1191 {
1193 {
1195 }
1196 else
1197 {
1198 return getB2DPoint(nIndex);
1199 }
1200 }
1201
1202 void B2DPolygon::setPrevControlPoint(sal_uInt32 nIndex, const B2DPoint& rValue)
1203 {
1204 const basegfx::B2DVector aNewVector(rValue - getB2DPoint(nIndex));
1205
1206 if(getPrevControlVector(nIndex) != aNewVector)
1207 {
1208 mpPolygon->setPrevControlVector(nIndex, aNewVector);
1209 }
1210 }
1211
1212 void B2DPolygon::setNextControlPoint(sal_uInt32 nIndex, const B2DPoint& rValue)
1213 {
1214 const basegfx::B2DVector aNewVector(rValue - getB2DPoint(nIndex));
1215
1216 if(getNextControlVector(nIndex) != aNewVector)
1217 {
1218 mpPolygon->setNextControlVector(nIndex, aNewVector);
1219 }
1220 }
1221
1222 void B2DPolygon::setControlPoints(sal_uInt32 nIndex, const basegfx::B2DPoint& rPrev, const basegfx::B2DPoint& rNext)
1223 {
1224 const B2DPoint aPoint(getB2DPoint(nIndex));
1225 const basegfx::B2DVector aNewPrev(rPrev - aPoint);
1226 const basegfx::B2DVector aNewNext(rNext - aPoint);
1227
1228 if(getPrevControlVector(nIndex) != aNewPrev || getNextControlVector(nIndex) != aNewNext)
1229 {
1230 mpPolygon->setControlVectors(nIndex, aNewPrev, aNewNext);
1231 }
1232 }
1233
1235 {
1237 {
1238 mpPolygon->setPrevControlVector(nIndex, B2DVector::getEmptyVector());
1239 }
1240 }
1241
1243 {
1245 {
1246 mpPolygon->setNextControlVector(nIndex, B2DVector::getEmptyVector());
1247 }
1248 }
1249
1251 {
1253 {
1254 mpPolygon->resetControlVectors();
1255 }
1256 }
1257
1259 const B2DPoint& rNextControlPoint,
1260 const B2DPoint& rPrevControlPoint,
1261 const B2DPoint& rPoint)
1262 {
1263 const B2DVector aNewNextVector(count() ? B2DVector(rNextControlPoint - getB2DPoint(count() - 1)) : B2DVector::getEmptyVector());
1264 const B2DVector aNewPrevVector(rPrevControlPoint - rPoint);
1265
1266 if(aNewNextVector.equalZero() && aNewPrevVector.equalZero())
1267 {
1268 mpPolygon->append(rPoint);
1269 }
1270 else
1271 {
1272 mpPolygon->appendBezierSegment(aNewNextVector, aNewPrevVector, rPoint);
1273 }
1274 }
1275
1276 void B2DPolygon::appendQuadraticBezierSegment(const B2DPoint& rControlPoint, const B2DPoint& rPoint)
1277 {
1278 if (count() == 0)
1279 {
1280 mpPolygon->append(rPoint);
1281 const double nX((rControlPoint.getX() * 2.0 + rPoint.getX()) / 3.0);
1282 const double nY((rControlPoint.getY() * 2.0 + rPoint.getY()) / 3.0);
1283 setPrevControlPoint(0, B2DPoint(nX, nY));
1284 }
1285 else
1286 {
1287 const B2DPoint aPreviousPoint(getB2DPoint(count() - 1));
1288
1289 const double nX1((rControlPoint.getX() * 2.0 + aPreviousPoint.getX()) / 3.0);
1290 const double nY1((rControlPoint.getY() * 2.0 + aPreviousPoint.getY()) / 3.0);
1291 const double nX2((rControlPoint.getX() * 2.0 + rPoint.getX()) / 3.0);
1292 const double nY2((rControlPoint.getY() * 2.0 + rPoint.getY()) / 3.0);
1293
1294 appendBezierSegment(B2DPoint(nX1, nY1), B2DPoint(nX2, nY2), rPoint);
1295 }
1296 }
1297
1299 {
1300 return mpPolygon->areControlPointsUsed();
1301 }
1302
1303 bool B2DPolygon::isPrevControlPointUsed(sal_uInt32 nIndex) const
1304 {
1306 }
1307
1308 bool B2DPolygon::isNextControlPointUsed(sal_uInt32 nIndex) const
1309 {
1311 }
1312
1314 {
1316 {
1317 const B2DVector& rPrev(getPrevControlVector(nIndex));
1318 const B2DVector& rNext(getNextControlVector(nIndex));
1319
1320 return getContinuity(rPrev, rNext);
1321 }
1322 else
1323 {
1325 }
1326 }
1327
1328 void B2DPolygon::getBezierSegment(sal_uInt32 nIndex, B2DCubicBezier& rTarget) const
1329 {
1330 const bool bNextIndexValidWithoutClose(nIndex + 1 < count());
1331
1332 if(bNextIndexValidWithoutClose || isClosed())
1333 {
1334 const sal_uInt32 nNextIndex(bNextIndexValidWithoutClose ? nIndex + 1 : 0);
1335 rTarget.setStartPoint(getB2DPoint(nIndex));
1336 rTarget.setEndPoint(getB2DPoint(nNextIndex));
1337
1339 {
1340 rTarget.setControlPointA(rTarget.getStartPoint() + getNextControlVector(nIndex));
1341 rTarget.setControlPointB(rTarget.getEndPoint() + getPrevControlVector(nNextIndex));
1342 }
1343 else
1344 {
1345 // no bezier, reset control points at rTarget
1346 rTarget.setControlPointA(rTarget.getStartPoint());
1347 rTarget.setControlPointB(rTarget.getEndPoint());
1348 }
1349 }
1350 else
1351 {
1352 // no valid edge at all, reset rTarget to current point
1353 const B2DPoint aPoint(getB2DPoint(nIndex));
1354 rTarget.setStartPoint(aPoint);
1355 rTarget.setEndPoint(aPoint);
1356 rTarget.setControlPointA(aPoint);
1357 rTarget.setControlPointB(aPoint);
1358 }
1359 }
1360
1362 {
1363 return mpPolygon->getDefaultAdaptiveSubdivision(*this);
1364 }
1365
1367 {
1368 return mpPolygon->getB2DRange(*this);
1369 }
1370
1371 void B2DPolygon::append(const B2DPolygon& rPoly, sal_uInt32 nIndex, sal_uInt32 nCount)
1372 {
1373 assert(nIndex + nCount <= rPoly.count());
1374
1375 if(!nCount)
1376 {
1377 nCount = rPoly.count() - nIndex;
1378 if (!nCount)
1379 return;
1380 }
1381
1382 if(nIndex == 0 && nCount == rPoly.count())
1383 {
1384 mpPolygon->append(*rPoly.mpPolygon);
1385 }
1386 else
1387 {
1388 mpPolygon->append(ImplB2DPolygon(*rPoly.mpPolygon, nIndex, nCount));
1389 }
1390 }
1391
1392 void B2DPolygon::remove(sal_uInt32 nIndex, sal_uInt32 nCount)
1393 {
1394 if(nCount)
1395 {
1396 mpPolygon->remove(nIndex, nCount);
1397 }
1398 }
1399
1401 {
1403 }
1404
1406 {
1407 return mpPolygon->isClosed();
1408 }
1409
1411 {
1412 if(isClosed() != bNew)
1413 {
1414 mpPolygon->setClosed(bNew);
1415 }
1416 }
1417
1419 {
1420 if(count() > 1)
1421 {
1422 mpPolygon->flip();
1423 }
1424 }
1425
1427 {
1428 return (count() > 1 && mpPolygon->hasDoublePoints());
1429 }
1430
1432 {
1433 if(hasDoublePoints())
1434 {
1435 mpPolygon->removeDoublePointsAtBeginEnd();
1436 mpPolygon->removeDoublePointsWholeTrack();
1437 }
1438 }
1439
1441 {
1442 if(count() && !rMatrix.isIdentity())
1443 {
1444 mpPolygon->transform(rMatrix);
1445 }
1446 }
1447
1449 {
1450 mpPolygon->addOrReplaceSystemDependentData(rData);
1451 }
1452
1454 {
1455 return mpPolygon->getSystemDependentData(hash_code);
1456 }
1457
1458} // end of namespace basegfx
1459
1460/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void setPoint(sal_uInt32 nIndex, const basegfx::B2DPoint &rValue)
Definition: b2dpolygon.cxx:672
ImplB2DPolygon & operator=(const ImplB2DPolygon &rOther)
Definition: b2dpolygon.cxx:597
void removeDoublePointsWholeTrack()
Definition: b2dpolygon.cxx:969
void setNextControlVector(sal_uInt32 nIndex, const basegfx::B2DVector &rValue)
Definition: b2dpolygon.cxx:760
void append(const basegfx::B2DPoint &rPoint)
Definition: b2dpolygon.cxx:683
const basegfx::B2DPoint & getPoint(sal_uInt32 nIndex) const
Definition: b2dpolygon.cxx:667
basegfx::SystemDependentData_SharedPtr getSystemDependentData(size_t hash_code) const
void addOrReplaceSystemDependentData(basegfx::SystemDependentData_SharedPtr &rData) const
void append(const ImplB2DPolygon &rSource)
Definition: b2dpolygon.cxx:812
void setControlVectors(sal_uInt32 nIndex, const basegfx::B2DVector &rPrev, const basegfx::B2DVector &rNext)
Definition: b2dpolygon.cxx:792
std::optional< ControlVectorArray2D > moControlVector
Definition: b2dpolygon.cxx:531
void removeDoublePointsAtBeginEnd()
Definition: b2dpolygon.cxx:913
void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
Definition: b2dpolygon.cxx:837
const basegfx::B2DRange & getB2DRange(const basegfx::B2DPolygon &rSource) const
Definition: b2dpolygon.cxx:557
bool operator==(const ImplB2DPolygon &rCandidate) const
Definition: b2dpolygon.cxx:635
const basegfx::B2DVector & getPrevControlVector(sal_uInt32 nIndex) const
Definition: b2dpolygon.cxx:715
void reserve(sal_uInt32 nCount)
Definition: b2dpolygon.cxx:678
bool areControlPointsUsed() const
Definition: b2dpolygon.cxx:781
bool isClosed() const
Definition: b2dpolygon.cxx:621
void appendBezierSegment(const basegfx::B2DVector &rNext, const basegfx::B2DVector &rPrev, const basegfx::B2DPoint &rPoint)
Definition: b2dpolygon.cxx:798
void resetControlVectors()
Definition: b2dpolygon.cxx:786
void setClosed(bool bNew)
Definition: b2dpolygon.cxx:626
void append(const basegfx::B2DPoint &rPoint, sal_uInt32 nCount)
Definition: b2dpolygon.cxx:710
ImplB2DPolygon(const ImplB2DPolygon &rToBeCopied)
Definition: b2dpolygon.cxx:572
void setPrevControlVector(sal_uInt32 nIndex, const basegfx::B2DVector &rValue)
Definition: b2dpolygon.cxx:727
ImplB2DPolygon(const ImplB2DPolygon &rToBeCopied, sal_uInt32 nIndex, sal_uInt32 nCount)
Definition: b2dpolygon.cxx:583
void insert(sal_uInt32 nIndex, const basegfx::B2DPoint &rPoint, sal_uInt32 nCount)
Definition: b2dpolygon.cxx:696
std::unique_ptr< ImplBufferedData > mpBufferedData
Definition: b2dpolygon.cxx:536
sal_uInt32 count() const
Definition: b2dpolygon.cxx:616
CoordinateDataArray2D maPoints
Definition: b2dpolygon.cxx:527
const basegfx::B2DPolygon & getDefaultAdaptiveSubdivision(const basegfx::B2DPolygon &rSource) const
Definition: b2dpolygon.cxx:542
const basegfx::B2DVector & getNextControlVector(sal_uInt32 nIndex) const
Definition: b2dpolygon.cxx:748
void transform(const basegfx::B2DHomMatrix &rMatrix)
bool hasDoublePoints() const
Definition: b2dpolygon.cxx:868
void setStartPoint(const B2DPoint &rValue)
SAL_DLLPRIVATE void getAllExtremumPositions(::std::vector< double > &rResults) const
Get all extremum pos of this segment.
void setControlPointA(const B2DPoint &rValue)
void setEndPoint(const B2DPoint &rValue)
B2DRange getRange() const
void setControlPointB(const B2DPoint &rValue)
B2DPoint interpolatePoint(double t) const
const B2DPoint & getEndPoint() const
bool isIdentity() const
Base Point class with two double values.
Definition: b2dpoint.hxx:42
bool isPrevControlPointUsed(sal_uInt32 nIndex) const
const basegfx::B2DVector & getNextControlVector(sal_uInt32 nIndex) const
void setB2DPoint(sal_uInt32 nIndex, const basegfx::B2DPoint &rValue)
bool isNextControlPointUsed(sal_uInt32 nIndex) const
SystemDependentData_SharedPtr getSystemDependantDataInternal(size_t hash_code) const
B2DPolygon & operator=(const B2DPolygon &rPolygon)
assignment operator
void addOrReplaceSystemDependentDataInternal(SystemDependentData_SharedPtr &rData) const
void clear()
clear all points
void insert(sal_uInt32 nIndex, const basegfx::B2DPoint &rPoint, sal_uInt32 nCount=1)
Coordinate insert/append.
bool operator!=(const B2DPolygon &rPolygon) const
void resetNextControlPoint(sal_uInt32 nIndex)
void appendQuadraticBezierSegment(const basegfx::B2DPoint &rQuadControlPoint, const basegfx::B2DPoint &rPoint)
This is a shortcut to append a quadratic bezier segment.
void setPrevControlPoint(sal_uInt32 nIndex, const basegfx::B2DPoint &rValue)
bool operator==(const B2DPolygon &rPolygon) const
compare operators
bool isClosed() const
closed state interface
basegfx::B2DPoint const & getB2DPoint(sal_uInt32 nIndex) const
Coordinate interface.
void transform(const basegfx::B2DHomMatrix &rMatrix)
apply transformation given in matrix form
void getBezierSegment(sal_uInt32 nIndex, B2DCubicBezier &rTarget) const
bezier segment access
B2DPolygon()
diverse constructors
void setNextControlPoint(sal_uInt32 nIndex, const basegfx::B2DPoint &rValue)
basegfx::B2DPoint getPrevControlPoint(sal_uInt32 nIndex) const
Basic ControlPoint interface.
bool hasDoublePoints() const
test if Polygon has double points
void setControlPoints(sal_uInt32 nIndex, const basegfx::B2DPoint &rPrev, const basegfx::B2DPoint &rNext)
bool areControlPointsUsed() const
ControlPoint checks.
B2VectorContinuity getContinuityInPoint(sal_uInt32 nIndex) const
void append(const basegfx::B2DPoint &rPoint, sal_uInt32 nCount)
void reserve(sal_uInt32 nCount)
B2DRange const & getB2DRange() const
Get the B2DRange (Rectangle dimensions) of this B2DPolygon.
void removeDoublePoints()
remove double points, at the begin/end and follow-ups, too
sal_uInt32 count() const
member count
const basegfx::B2DVector & getPrevControlVector(sal_uInt32 nIndex) const
void setClosed(bool bNew)
void makeUnique()
unshare this polygon with all internally shared instances
B2DPolygon const & getDefaultAdaptiveSubdivision() const
Default adaptive subdivision access.
void resetPrevControlPoint(sal_uInt32 nIndex)
ControlPoint resets.
void remove(sal_uInt32 nIndex, sal_uInt32 nCount=1)
remove points
basegfx::B2DPoint getNextControlPoint(sal_uInt32 nIndex) const
void flip()
flip polygon direction
void appendBezierSegment(const basegfx::B2DPoint &rNextControlPoint, const basegfx::B2DPoint &rPrevControlPoint, const basegfx::B2DPoint &rPoint)
Bezier segment append with control points. The current last polygon point is implicitly taken as star...
A two-dimensional interval over doubles.
Definition: b2drange.hxx:54
Base Point class with two double values.
Definition: b2dvector.hxx:40
static const B2DVector & getEmptyVector()
Definition: b2dvector.cxx:74
void expand(const Tuple2D< TYPE > &rTuple)
add point to the set, expanding as necessary
Definition: Range2D.hxx:142
bool isInside(const Tuple2D< TYPE > &rTuple) const
yields true if given point is contained in set
Definition: Range2D.hxx:118
bool equalZero() const
Definition: Tuple2D.hxx:95
TYPE getX() const
Get X-Coordinate of 2D Tuple.
Definition: Tuple2D.hxx:63
TYPE getY() const
Get Y-Coordinate of 2D Tuple.
Definition: Tuple2D.hxx:66
bool same_object(const cow_wrapper &rOther) const
value_type & make_unique()
int nCount
std::deque< AttacherIndex_Impl > aIndex
FilterGroup & rTarget
sal_Int32 nIndex
uno_Any a
def point()
bool equalZero(const T &rfVal)
Compare against small value.
Definition: ftools.hxx:156
B2DPolygon adaptiveSubdivideByAngle(const B2DPolygon &rCandidate, double fAngleBound)
B2VectorContinuity
Descriptor for the mathematical continuity of two 2D Vectors.
Definition: b2enums.hxx:41
std::shared_ptr< SystemDependentData > SystemDependentData_SharedPtr
Definition: b2dpolygon.hxx:41
B2VectorContinuity getContinuity(const B2DVector &rBackVector, const B2DVector &rForwardVector)
Test continuity between given vectors.
Definition: b2dvector.cxx:161
static o3tl::cow_wrapper< ImplB2DPolygon > DEFAULT
OUStringBuffer & remove(OUStringBuffer &rIn, sal_Unicode c)
enumrange< T >::Iterator begin(enumrange< T >)
bool operator==(const XclFontData &rLeft, const XclFontData &rRight)