tdf#130857 qt weld: Support mail merge "Server Auth" dialog
[LibreOffice.git] / basegfx / source / polygon / b3dpolygon.cxx
blobf17f974e2fb7e3bad3f8cd69418fca047867b725
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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>
33 namespace {
35 class CoordinateData3D
37 basegfx::B3DPoint maPoint;
39 public:
40 CoordinateData3D()
44 explicit CoordinateData3D(const basegfx::B3DPoint& rData)
45 : maPoint(rData)
49 const basegfx::B3DPoint& getCoordinate() const
51 return maPoint;
54 void setCoordinate(const basegfx::B3DPoint& rValue)
56 if(rValue != maPoint)
57 maPoint = rValue;
60 bool operator==(const CoordinateData3D& rData) const
62 return (maPoint == rData.getCoordinate());
65 void transform(const basegfx::B3DHomMatrix& rMatrix)
67 maPoint *= rMatrix;
71 class CoordinateDataArray3D
73 typedef std::vector< CoordinateData3D > CoordinateData3DVector;
75 CoordinateData3DVector maVector;
77 public:
78 explicit CoordinateDataArray3D(sal_uInt32 nCount)
79 : maVector(nCount)
83 CoordinateDataArray3D(const CoordinateDataArray3D& rOriginal, sal_uInt32 nIndex, sal_uInt32 nCount)
84 : maVector(rOriginal.maVector.begin() + nIndex, rOriginal.maVector.begin() + (nIndex + nCount))
88 ::basegfx::B3DVector getNormal() const
90 ::basegfx::B3DVector aRetval;
91 const sal_uInt32 nPointCount(maVector.size());
93 if(nPointCount > 2)
95 sal_uInt32 nISmallest(0);
96 sal_uInt32 a(0);
97 const basegfx::B3DPoint* pSmallest(&maVector[0].getCoordinate());
98 const basegfx::B3DPoint* pNext(nullptr);
99 const basegfx::B3DPoint* pPrev(nullptr);
101 // To guarantee a correctly oriented point, choose an outmost one
102 // which then cannot be concave
103 for(a = 1; a < nPointCount; a++)
105 const basegfx::B3DPoint& rCandidate = maVector[a].getCoordinate();
107 if((rCandidate.getX() < pSmallest->getX())
108 || (rCandidate.getX() == pSmallest->getX() && rCandidate.getY() < pSmallest->getY())
109 || (rCandidate.getX() == pSmallest->getX() && rCandidate.getY() == pSmallest->getY() && rCandidate.getZ() < pSmallest->getZ()))
111 nISmallest = a;
112 pSmallest = &rCandidate;
116 // look for a next point different from minimal one
117 for(a = (nISmallest + 1) % nPointCount; a != nISmallest; a = (a + 1) % nPointCount)
119 const basegfx::B3DPoint& rCandidate = maVector[a].getCoordinate();
121 if(!rCandidate.equal(*pSmallest))
123 pNext = &rCandidate;
124 break;
128 // look for a previous point different from minimal one
129 for(a = (nISmallest + nPointCount - 1) % nPointCount; a != nISmallest; a = (a + nPointCount - 1) % nPointCount)
131 const basegfx::B3DPoint& rCandidate = maVector[a].getCoordinate();
133 if(!rCandidate.equal(*pSmallest))
135 pPrev = &rCandidate;
136 break;
140 // we always have a minimal point. If we also have a different next and previous,
141 // we can calculate the normal
142 if(pNext && pPrev)
144 const basegfx::B3DVector aPrev(*pPrev - *pSmallest);
145 const basegfx::B3DVector aNext(*pNext - *pSmallest);
147 aRetval = cross(aPrev, aNext);
148 aRetval.normalize();
152 return aRetval;
155 sal_uInt32 count() const
157 return maVector.size();
160 bool operator==(const CoordinateDataArray3D& rCandidate) const
162 return (maVector == rCandidate.maVector);
165 const basegfx::B3DPoint& getCoordinate(sal_uInt32 nIndex) const
167 return maVector[nIndex].getCoordinate();
170 void setCoordinate(sal_uInt32 nIndex, const basegfx::B3DPoint& rValue)
172 maVector[nIndex].setCoordinate(rValue);
175 void insert(sal_uInt32 nIndex, const CoordinateData3D& rValue, sal_uInt32 nCount)
177 if(nCount)
179 // add nCount copies of rValue
180 CoordinateData3DVector::iterator aIndex(maVector.begin());
181 aIndex += nIndex;
182 maVector.insert(aIndex, nCount, rValue);
186 void insert(sal_uInt32 nIndex, const CoordinateDataArray3D& rSource)
188 const sal_uInt32 nCount(rSource.maVector.size());
190 if(nCount)
192 // insert data
193 CoordinateData3DVector::iterator aIndex(maVector.begin());
194 aIndex += nIndex;
195 CoordinateData3DVector::const_iterator aStart(rSource.maVector.begin());
196 CoordinateData3DVector::const_iterator aEnd(rSource.maVector.end());
197 maVector.insert(aIndex, aStart, aEnd);
201 void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
203 if(nCount)
205 // remove point data
206 CoordinateData3DVector::iterator aStart(maVector.begin());
207 aStart += nIndex;
208 const CoordinateData3DVector::iterator aEnd(aStart + nCount);
209 maVector.erase(aStart, aEnd);
213 void flip()
215 if(maVector.size() <= 1)
216 return;
218 const sal_uInt32 nHalfSize(maVector.size() >> 1);
219 CoordinateData3DVector::iterator aStart(maVector.begin());
220 CoordinateData3DVector::iterator aEnd(maVector.end() - 1);
222 for(sal_uInt32 a(0); a < nHalfSize; a++)
224 std::swap(*aStart, *aEnd);
225 ++aStart;
226 --aEnd;
230 void transform(const ::basegfx::B3DHomMatrix& rMatrix)
232 for (auto & elem : maVector)
234 elem.transform(rMatrix);
239 class BColorArray
241 typedef std::vector< ::basegfx::BColor > BColorDataVector;
243 BColorDataVector maVector;
244 sal_uInt32 mnUsedEntries;
246 public:
247 explicit BColorArray(sal_uInt32 nCount)
248 : maVector(nCount),
249 mnUsedEntries(0)
253 BColorArray(const BColorArray& rOriginal, sal_uInt32 nIndex, sal_uInt32 nCount)
254 : mnUsedEntries(0)
256 BColorDataVector::const_iterator aStart(rOriginal.maVector.begin());
257 aStart += nIndex;
258 BColorDataVector::const_iterator aEnd(aStart);
259 assert(nCount <= rOriginal.maVector.size());
260 aEnd += nCount;
261 maVector.reserve(nCount);
263 for(; aStart != aEnd; ++aStart)
265 if(!aStart->equalZero())
266 mnUsedEntries++;
268 maVector.push_back(*aStart);
272 bool operator==(const BColorArray& rCandidate) const
274 return (maVector == rCandidate.maVector);
277 bool isUsed() const
279 return (mnUsedEntries != 0);
282 const ::basegfx::BColor& getBColor(sal_uInt32 nIndex) const
284 return maVector[nIndex];
287 void setBColor(sal_uInt32 nIndex, const ::basegfx::BColor& rValue)
289 bool bWasUsed(mnUsedEntries && !maVector[nIndex].equalZero());
290 bool bIsUsed(!rValue.equalZero());
292 if(bWasUsed)
294 if(bIsUsed)
296 maVector[nIndex] = rValue;
298 else
300 maVector[nIndex] = ::basegfx::BColor::getEmptyBColor();
301 mnUsedEntries--;
304 else
306 if(bIsUsed)
308 maVector[nIndex] = rValue;
309 mnUsedEntries++;
314 void insert(sal_uInt32 nIndex, const ::basegfx::BColor& rValue, sal_uInt32 nCount)
316 if(nCount)
318 // add nCount copies of rValue
319 BColorDataVector::iterator aIndex(maVector.begin());
320 aIndex += nIndex;
321 maVector.insert(aIndex, nCount, rValue);
323 if(!rValue.equalZero())
324 mnUsedEntries += nCount;
328 void insert(sal_uInt32 nIndex, const BColorArray& rSource)
330 const sal_uInt32 nCount(rSource.maVector.size());
332 if(nCount)
334 // insert data
335 BColorDataVector::iterator aIndex(maVector.begin());
336 aIndex += nIndex;
337 BColorDataVector::const_iterator aStart(rSource.maVector.begin());
338 BColorDataVector::const_iterator aEnd(rSource.maVector.end());
339 maVector.insert(aIndex, aStart, aEnd);
341 mnUsedEntries += std::count_if(aStart, aEnd,
342 [](BColorDataVector::const_reference rData) { return !rData.equalZero(); });
346 void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
348 if(nCount)
350 const BColorDataVector::iterator aDeleteStart(maVector.begin() + nIndex);
351 const BColorDataVector::iterator aDeleteEnd(aDeleteStart + nCount);
353 auto nDeleteUsed = std::count_if(aDeleteStart, aDeleteEnd,
354 [](BColorDataVector::const_reference rData) { return !rData.equalZero(); });
355 mnUsedEntries -= std::min(mnUsedEntries, static_cast<sal_uInt32>(nDeleteUsed));
357 // remove point data
358 maVector.erase(aDeleteStart, aDeleteEnd);
362 void flip()
364 if(maVector.size() <= 1)
365 return;
367 const sal_uInt32 nHalfSize(maVector.size() >> 1);
368 BColorDataVector::iterator aStart(maVector.begin());
369 BColorDataVector::iterator aEnd(maVector.end() - 1);
371 for(sal_uInt32 a(0); a < nHalfSize; a++)
373 std::swap(*aStart, *aEnd);
374 ++aStart;
375 --aEnd;
380 class NormalsArray3D
382 typedef std::vector< ::basegfx::B3DVector > NormalsData3DVector;
384 NormalsData3DVector maVector;
385 sal_uInt32 mnUsedEntries;
387 public:
388 explicit NormalsArray3D(sal_uInt32 nCount)
389 : maVector(nCount),
390 mnUsedEntries(0)
394 NormalsArray3D(const NormalsArray3D& rOriginal, sal_uInt32 nIndex, sal_uInt32 nCount)
395 : mnUsedEntries(0)
397 NormalsData3DVector::const_iterator aStart(rOriginal.maVector.begin());
398 aStart += nIndex;
399 NormalsData3DVector::const_iterator aEnd(aStart);
400 aEnd += nCount;
401 maVector.reserve(nCount);
403 for(; aStart != aEnd; ++aStart)
405 if(!aStart->equalZero())
406 mnUsedEntries++;
408 maVector.push_back(*aStart);
412 bool operator==(const NormalsArray3D& rCandidate) const
414 return (maVector == rCandidate.maVector);
417 bool isUsed() const
419 return (mnUsedEntries != 0);
422 const ::basegfx::B3DVector& getNormal(sal_uInt32 nIndex) const
424 return maVector[nIndex];
427 void setNormal(sal_uInt32 nIndex, const ::basegfx::B3DVector& rValue)
429 bool bWasUsed(mnUsedEntries && !maVector[nIndex].equalZero());
430 bool bIsUsed(!rValue.equalZero());
432 if(bWasUsed)
434 if(bIsUsed)
436 maVector[nIndex] = rValue;
438 else
440 maVector[nIndex] = ::basegfx::B3DVector::getEmptyVector();
441 mnUsedEntries--;
444 else
446 if(bIsUsed)
448 maVector[nIndex] = rValue;
449 mnUsedEntries++;
454 void insert(sal_uInt32 nIndex, const ::basegfx::B3DVector& rValue, sal_uInt32 nCount)
456 if(nCount)
458 // add nCount copies of rValue
459 NormalsData3DVector::iterator aIndex(maVector.begin());
460 aIndex += nIndex;
461 maVector.insert(aIndex, nCount, rValue);
463 if(!rValue.equalZero())
464 mnUsedEntries += nCount;
468 void insert(sal_uInt32 nIndex, const NormalsArray3D& rSource)
470 const sal_uInt32 nCount(rSource.maVector.size());
472 if(nCount)
474 // insert data
475 NormalsData3DVector::iterator aIndex(maVector.begin());
476 aIndex += nIndex;
477 NormalsData3DVector::const_iterator aStart(rSource.maVector.begin());
478 NormalsData3DVector::const_iterator aEnd(rSource.maVector.end());
479 maVector.insert(aIndex, aStart, aEnd);
481 mnUsedEntries += std::count_if(aStart, aEnd,
482 [](NormalsData3DVector::const_reference rData) { return !rData.equalZero(); });
486 void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
488 if(nCount)
490 const NormalsData3DVector::iterator aDeleteStart(maVector.begin() + nIndex);
491 const NormalsData3DVector::iterator aDeleteEnd(aDeleteStart + nCount);
493 auto nDeleteUsed = std::count_if(aDeleteStart, aDeleteEnd,
494 [](NormalsData3DVector::const_reference rData) { return !rData.equalZero(); });
495 mnUsedEntries -= std::min(mnUsedEntries, static_cast<sal_uInt32>(nDeleteUsed));
497 // remove point data
498 maVector.erase(aDeleteStart, aDeleteEnd);
502 void flip()
504 if(maVector.size() <= 1)
505 return;
507 const sal_uInt32 nHalfSize(maVector.size() >> 1);
508 NormalsData3DVector::iterator aStart(maVector.begin());
509 NormalsData3DVector::iterator aEnd(maVector.end() - 1);
511 for(sal_uInt32 a(0); a < nHalfSize; a++)
513 std::swap(*aStart, *aEnd);
514 ++aStart;
515 --aEnd;
519 void transform(const basegfx::B3DHomMatrix& rMatrix)
521 for (auto & elem : maVector)
523 elem *= rMatrix;
528 class TextureCoordinate2D
530 typedef std::vector< ::basegfx::B2DPoint > TextureData2DVector;
532 TextureData2DVector maVector;
533 sal_uInt32 mnUsedEntries;
535 public:
536 explicit TextureCoordinate2D(sal_uInt32 nCount)
537 : maVector(nCount),
538 mnUsedEntries(0)
542 TextureCoordinate2D(const TextureCoordinate2D& rOriginal, sal_uInt32 nIndex, sal_uInt32 nCount)
543 : mnUsedEntries(0)
545 TextureData2DVector::const_iterator aStart(rOriginal.maVector.begin());
546 aStart += nIndex;
547 TextureData2DVector::const_iterator aEnd(aStart);
548 aEnd += nCount;
549 maVector.reserve(nCount);
551 for(; aStart != aEnd; ++aStart)
553 if(!aStart->equalZero())
554 mnUsedEntries++;
556 maVector.push_back(*aStart);
560 bool operator==(const TextureCoordinate2D& rCandidate) const
562 return (maVector == rCandidate.maVector);
565 bool isUsed() const
567 return (mnUsedEntries != 0);
570 const ::basegfx::B2DPoint& getTextureCoordinate(sal_uInt32 nIndex) const
572 return maVector[nIndex];
575 void setTextureCoordinate(sal_uInt32 nIndex, const ::basegfx::B2DPoint& rValue)
577 bool bWasUsed(mnUsedEntries && !maVector[nIndex].equalZero());
578 bool bIsUsed(!rValue.equalZero());
580 if(bWasUsed)
582 if(bIsUsed)
584 maVector[nIndex] = rValue;
586 else
588 maVector[nIndex] = ::basegfx::B2DPoint::getEmptyPoint();
589 mnUsedEntries--;
592 else
594 if(bIsUsed)
596 maVector[nIndex] = rValue;
597 mnUsedEntries++;
602 void insert(sal_uInt32 nIndex, const ::basegfx::B2DPoint& rValue, sal_uInt32 nCount)
604 if(nCount)
606 // add nCount copies of rValue
607 TextureData2DVector::iterator aIndex(maVector.begin());
608 aIndex += nIndex;
609 maVector.insert(aIndex, nCount, rValue);
611 if(!rValue.equalZero())
612 mnUsedEntries += nCount;
616 void insert(sal_uInt32 nIndex, const TextureCoordinate2D& rSource)
618 const sal_uInt32 nCount(rSource.maVector.size());
620 if(nCount)
622 // insert data
623 TextureData2DVector::iterator aIndex(maVector.begin());
624 aIndex += nIndex;
625 TextureData2DVector::const_iterator aStart(rSource.maVector.begin());
626 TextureData2DVector::const_iterator aEnd(rSource.maVector.end());
627 maVector.insert(aIndex, aStart, aEnd);
629 mnUsedEntries += std::count_if(aStart, aEnd,
630 [](TextureData2DVector::const_reference rData) { return !rData.equalZero(); });
634 void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
636 if(nCount)
638 const TextureData2DVector::iterator aDeleteStart(maVector.begin() + nIndex);
639 const TextureData2DVector::iterator aDeleteEnd(aDeleteStart + nCount);
641 auto nDeleteUsed = std::count_if(aDeleteStart, aDeleteEnd,
642 [](TextureData2DVector::const_reference rData) { return !rData.equalZero(); });
643 mnUsedEntries -= std::min(mnUsedEntries, static_cast<sal_uInt32>(nDeleteUsed));
645 // remove point data
646 maVector.erase(aDeleteStart, aDeleteEnd);
650 void flip()
652 if(maVector.size() <= 1)
653 return;
655 const sal_uInt32 nHalfSize(maVector.size() >> 1);
656 TextureData2DVector::iterator aStart(maVector.begin());
657 TextureData2DVector::iterator aEnd(maVector.end() - 1);
659 for(sal_uInt32 a(0); a < nHalfSize; a++)
661 std::swap(*aStart, *aEnd);
662 ++aStart;
663 --aEnd;
667 void transform(const ::basegfx::B2DHomMatrix& rMatrix)
669 for (auto & elem : maVector)
671 elem *= rMatrix;
678 class ImplB3DPolygon
680 // The point vector. This vector exists always and defines the
681 // count of members.
682 CoordinateDataArray3D maPoints;
684 // The BColor vector. This vectors are created on demand
685 // and may be zero.
686 std::unique_ptr<BColorArray> mpBColors;
688 // The Normals vector. This vectors are created on demand
689 // and may be zero.
690 std::unique_ptr<NormalsArray3D> mpNormals;
692 // The TextureCoordinates vector. This vectors are created on demand
693 // and may be zero.
694 std::unique_ptr<TextureCoordinate2D> mpTextureCoordinates;
696 // flag which decides if this polygon is opened or closed
697 bool mbIsClosed : 1;
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 : maPoints(0),
704 mbIsClosed(false)
706 // complete initialization with defaults
709 ImplB3DPolygon(const ImplB3DPolygon& rToBeCopied)
710 : maPoints(rToBeCopied.maPoints),
711 mbIsClosed(rToBeCopied.mbIsClosed)
713 // complete initialization using copy
714 if(rToBeCopied.mpBColors && rToBeCopied.mpBColors->isUsed())
716 mpBColors.reset( new BColorArray(*rToBeCopied.mpBColors) );
719 if(rToBeCopied.mpNormals && rToBeCopied.mpNormals->isUsed())
721 mpNormals.reset( new NormalsArray3D(*rToBeCopied.mpNormals) );
724 if(rToBeCopied.mpTextureCoordinates && rToBeCopied.mpTextureCoordinates->isUsed())
726 mpTextureCoordinates.reset( new TextureCoordinate2D(*rToBeCopied.mpTextureCoordinates) );
730 ImplB3DPolygon(const ImplB3DPolygon& rToBeCopied, sal_uInt32 nIndex, sal_uInt32 nCount)
731 : maPoints(rToBeCopied.maPoints, nIndex, nCount),
732 mbIsClosed(rToBeCopied.mbIsClosed)
734 // complete initialization using partly copy
735 if(rToBeCopied.mpBColors && rToBeCopied.mpBColors->isUsed())
737 mpBColors.reset( new BColorArray(*rToBeCopied.mpBColors, nIndex, nCount) );
739 if(!mpBColors->isUsed())
741 mpBColors.reset();
745 if(rToBeCopied.mpNormals && rToBeCopied.mpNormals->isUsed())
747 mpNormals.reset( new NormalsArray3D(*rToBeCopied.mpNormals, nIndex, nCount) );
749 if(!mpNormals->isUsed())
751 mpNormals.reset();
755 if(rToBeCopied.mpTextureCoordinates && rToBeCopied.mpTextureCoordinates->isUsed())
757 mpTextureCoordinates.reset( new TextureCoordinate2D(*rToBeCopied.mpTextureCoordinates, nIndex, nCount) );
759 if(!mpTextureCoordinates->isUsed())
761 mpTextureCoordinates.reset();
766 sal_uInt32 count() const
768 return maPoints.count();
771 bool isClosed() const
773 return mbIsClosed;
776 void setClosed(bool bNew)
778 if(bNew != mbIsClosed)
780 mbIsClosed = bNew;
784 bool impBColorsAreEqual(const ImplB3DPolygon& rCandidate) const
786 bool bBColorsAreEqual(true);
788 if(mpBColors)
790 if(rCandidate.mpBColors)
792 bBColorsAreEqual = (*mpBColors == *rCandidate.mpBColors);
794 else
796 // candidate has no BColors, so it's assumed all unused.
797 bBColorsAreEqual = !mpBColors->isUsed();
800 else
802 if(rCandidate.mpBColors)
804 // we have no TextureCoordinates, so it's assumed all unused.
805 bBColorsAreEqual = !rCandidate.mpBColors->isUsed();
809 return bBColorsAreEqual;
812 bool impNormalsAreEqual(const ImplB3DPolygon& rCandidate) const
814 bool bNormalsAreEqual(true);
816 if(mpNormals)
818 if(rCandidate.mpNormals)
820 bNormalsAreEqual = (*mpNormals == *rCandidate.mpNormals);
822 else
824 // candidate has no normals, so it's assumed all unused.
825 bNormalsAreEqual = !mpNormals->isUsed();
828 else
830 if(rCandidate.mpNormals)
832 // we have no normals, so it's assumed all unused.
833 bNormalsAreEqual = !rCandidate.mpNormals->isUsed();
837 return bNormalsAreEqual;
840 bool impTextureCoordinatesAreEqual(const ImplB3DPolygon& rCandidate) const
842 bool bTextureCoordinatesAreEqual(true);
844 if(mpTextureCoordinates)
846 if(rCandidate.mpTextureCoordinates)
848 bTextureCoordinatesAreEqual = (*mpTextureCoordinates == *rCandidate.mpTextureCoordinates);
850 else
852 // candidate has no TextureCoordinates, so it's assumed all unused.
853 bTextureCoordinatesAreEqual = !mpTextureCoordinates->isUsed();
856 else
858 if(rCandidate.mpTextureCoordinates)
860 // we have no TextureCoordinates, so it's assumed all unused.
861 bTextureCoordinatesAreEqual = !rCandidate.mpTextureCoordinates->isUsed();
865 return bTextureCoordinatesAreEqual;
868 bool operator==(const ImplB3DPolygon& rCandidate) const
870 if(mbIsClosed == rCandidate.mbIsClosed)
872 if(maPoints == rCandidate.maPoints)
874 if(impBColorsAreEqual(rCandidate))
876 if(impNormalsAreEqual(rCandidate))
878 if(impTextureCoordinatesAreEqual(rCandidate))
880 return true;
887 return false;
890 const ::basegfx::B3DPoint& getPoint(sal_uInt32 nIndex) const
892 return maPoints.getCoordinate(nIndex);
895 void setPoint(sal_uInt32 nIndex, const ::basegfx::B3DPoint& rValue)
897 maPoints.setCoordinate(nIndex, rValue);
900 void insert(sal_uInt32 nIndex, const ::basegfx::B3DPoint& rPoint, sal_uInt32 nCount)
902 if(!nCount)
903 return;
905 CoordinateData3D aCoordinate(rPoint);
906 maPoints.insert(nIndex, aCoordinate, nCount);
908 if(mpBColors)
910 mpBColors->insert(nIndex, ::basegfx::BColor::getEmptyBColor(), nCount);
913 if(mpNormals)
915 mpNormals->insert(nIndex, ::basegfx::B3DVector::getEmptyVector(), nCount);
918 if(mpTextureCoordinates)
920 mpTextureCoordinates->insert(nIndex, ::basegfx::B2DPoint::getEmptyPoint(), nCount);
924 const ::basegfx::BColor& getBColor(sal_uInt32 nIndex) const
926 if(mpBColors)
928 return mpBColors->getBColor(nIndex);
930 else
932 return ::basegfx::BColor::getEmptyBColor();
936 void setBColor(sal_uInt32 nIndex, const ::basegfx::BColor& rValue)
938 if(!mpBColors)
940 if(!rValue.equalZero())
942 mpBColors.reset( new BColorArray(maPoints.count()) );
943 mpBColors->setBColor(nIndex, rValue);
946 else
948 mpBColors->setBColor(nIndex, rValue);
950 if(!mpBColors->isUsed())
952 mpBColors.reset();
957 bool areBColorsUsed() const
959 return (mpBColors && mpBColors->isUsed());
962 void clearBColors()
964 mpBColors.reset();
967 ::basegfx::B3DVector getNormal() const
969 return maPoints.getNormal();
972 const ::basegfx::B3DVector& getNormal(sal_uInt32 nIndex) const
974 if(mpNormals)
976 return mpNormals->getNormal(nIndex);
978 else
980 return ::basegfx::B3DVector::getEmptyVector();
984 void setNormal(sal_uInt32 nIndex, const ::basegfx::B3DVector& rValue)
986 if(!mpNormals)
988 if(!rValue.equalZero())
990 mpNormals.reset( new NormalsArray3D(maPoints.count()) );
991 mpNormals->setNormal(nIndex, rValue);
994 else
996 mpNormals->setNormal(nIndex, rValue);
998 if(!mpNormals->isUsed())
1000 mpNormals.reset();
1005 void transformNormals(const ::basegfx::B3DHomMatrix& rMatrix)
1007 if(mpNormals)
1009 mpNormals->transform(rMatrix);
1013 bool areNormalsUsed() const
1015 return (mpNormals && mpNormals->isUsed());
1018 void clearNormals()
1020 mpNormals.reset();
1023 const ::basegfx::B2DPoint& getTextureCoordinate(sal_uInt32 nIndex) const
1025 if(mpTextureCoordinates)
1027 return mpTextureCoordinates->getTextureCoordinate(nIndex);
1029 else
1031 return ::basegfx::B2DPoint::getEmptyPoint();
1035 void setTextureCoordinate(sal_uInt32 nIndex, const ::basegfx::B2DPoint& rValue)
1037 if(!mpTextureCoordinates)
1039 if(!rValue.equalZero())
1041 mpTextureCoordinates.reset( new TextureCoordinate2D(maPoints.count()) );
1042 mpTextureCoordinates->setTextureCoordinate(nIndex, rValue);
1045 else
1047 mpTextureCoordinates->setTextureCoordinate(nIndex, rValue);
1049 if(!mpTextureCoordinates->isUsed())
1051 mpTextureCoordinates.reset();
1056 bool areTextureCoordinatesUsed() const
1058 return (mpTextureCoordinates && mpTextureCoordinates->isUsed());
1061 void clearTextureCoordinates()
1063 mpTextureCoordinates.reset();
1066 void transformTextureCoordinates(const ::basegfx::B2DHomMatrix& rMatrix)
1068 if(mpTextureCoordinates)
1070 mpTextureCoordinates->transform(rMatrix);
1074 void insert(sal_uInt32 nIndex, const ImplB3DPolygon& rSource)
1076 const sal_uInt32 nCount(rSource.maPoints.count());
1078 if(!nCount)
1079 return;
1081 maPoints.insert(nIndex, rSource.maPoints);
1083 if(rSource.mpBColors && rSource.mpBColors->isUsed())
1085 if(!mpBColors)
1087 mpBColors.reset( new BColorArray(maPoints.count()) );
1090 mpBColors->insert(nIndex, *rSource.mpBColors);
1092 else
1094 if(mpBColors)
1096 mpBColors->insert(nIndex, ::basegfx::BColor::getEmptyBColor(), nCount);
1100 if(rSource.mpNormals && rSource.mpNormals->isUsed())
1102 if(!mpNormals)
1104 mpNormals.reset( new NormalsArray3D(maPoints.count()) );
1107 mpNormals->insert(nIndex, *rSource.mpNormals);
1109 else
1111 if(mpNormals)
1113 mpNormals->insert(nIndex, ::basegfx::B3DVector::getEmptyVector(), nCount);
1117 if(rSource.mpTextureCoordinates && rSource.mpTextureCoordinates->isUsed())
1119 if(!mpTextureCoordinates)
1121 mpTextureCoordinates.reset( new TextureCoordinate2D(maPoints.count()) );
1124 mpTextureCoordinates->insert(nIndex, *rSource.mpTextureCoordinates);
1126 else
1128 if(mpTextureCoordinates)
1130 mpTextureCoordinates->insert(nIndex, ::basegfx::B2DPoint::getEmptyPoint(), nCount);
1135 void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
1137 if(!nCount)
1138 return;
1140 maPoints.remove(nIndex, nCount);
1142 if(mpBColors)
1144 mpBColors->remove(nIndex, nCount);
1146 if(!mpBColors->isUsed())
1148 mpBColors.reset();
1152 if(mpNormals)
1154 mpNormals->remove(nIndex, nCount);
1156 if(!mpNormals->isUsed())
1158 mpNormals.reset();
1162 if(mpTextureCoordinates)
1164 mpTextureCoordinates->remove(nIndex, nCount);
1166 if(!mpTextureCoordinates->isUsed())
1168 mpTextureCoordinates.reset();
1173 void flip()
1175 if(maPoints.count() <= 1)
1176 return;
1178 maPoints.flip();
1180 if(mpBColors)
1182 mpBColors->flip();
1185 if(mpNormals)
1187 mpNormals->flip();
1190 if(mpTextureCoordinates)
1192 mpTextureCoordinates->flip();
1196 bool hasDoublePoints() const
1198 if(mbIsClosed)
1200 // check for same start and end point
1201 const sal_uInt32 nIndex(maPoints.count() - 1);
1203 if(maPoints.getCoordinate(0) == maPoints.getCoordinate(nIndex))
1205 const bool bBColorEqual(!mpBColors || (mpBColors->getBColor(0) == mpBColors->getBColor(nIndex)));
1207 if(bBColorEqual)
1209 const bool bNormalsEqual(!mpNormals || (mpNormals->getNormal(0) == mpNormals->getNormal(nIndex)));
1211 if(bNormalsEqual)
1213 const bool bTextureCoordinatesEqual(!mpTextureCoordinates || (mpTextureCoordinates->getTextureCoordinate(0) == mpTextureCoordinates->getTextureCoordinate(nIndex)));
1215 if(bTextureCoordinatesEqual)
1217 return true;
1224 // test for range
1225 for(sal_uInt32 a(0); a < maPoints.count() - 1; a++)
1227 if(maPoints.getCoordinate(a) == maPoints.getCoordinate(a + 1))
1229 const bool bBColorEqual(!mpBColors || (mpBColors->getBColor(a) == mpBColors->getBColor(a + 1)));
1231 if(bBColorEqual)
1233 const bool bNormalsEqual(!mpNormals || (mpNormals->getNormal(a) == mpNormals->getNormal(a + 1)));
1235 if(bNormalsEqual)
1237 const bool bTextureCoordinatesEqual(!mpTextureCoordinates || (mpTextureCoordinates->getTextureCoordinate(a) == mpTextureCoordinates->getTextureCoordinate(a + 1)));
1239 if(bTextureCoordinatesEqual)
1241 return true;
1248 return false;
1251 void removeDoublePointsAtBeginEnd()
1253 // Only remove DoublePoints at Begin and End when poly is closed
1254 if(!mbIsClosed)
1255 return;
1257 bool bRemove;
1261 bRemove = false;
1263 if(maPoints.count() > 1)
1265 const sal_uInt32 nIndex(maPoints.count() - 1);
1266 bRemove = (maPoints.getCoordinate(0) == maPoints.getCoordinate(nIndex));
1268 if(bRemove && mpBColors && mpBColors->getBColor(0) != mpBColors->getBColor(nIndex))
1270 bRemove = false;
1273 if(bRemove && mpNormals && mpNormals->getNormal(0) != mpNormals->getNormal(nIndex))
1275 bRemove = false;
1278 if(bRemove && mpTextureCoordinates && mpTextureCoordinates->getTextureCoordinate(0) != mpTextureCoordinates->getTextureCoordinate(nIndex))
1280 bRemove = false;
1284 if(bRemove)
1286 const sal_uInt32 nIndex(maPoints.count() - 1);
1287 remove(nIndex, 1);
1289 } while(bRemove);
1292 void removeDoublePointsWholeTrack()
1294 sal_uInt32 nIndex(0);
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 while((maPoints.count() > 1) && (nIndex <= maPoints.count() - 2))
1300 const sal_uInt32 nNextIndex(nIndex + 1);
1301 bool bRemove(maPoints.getCoordinate(nIndex) == maPoints.getCoordinate(nNextIndex));
1303 if(bRemove && mpBColors && mpBColors->getBColor(nIndex) != mpBColors->getBColor(nNextIndex))
1305 bRemove = false;
1308 if(bRemove && mpNormals && mpNormals->getNormal(nIndex) != mpNormals->getNormal(nNextIndex))
1310 bRemove = false;
1313 if(bRemove && mpTextureCoordinates && mpTextureCoordinates->getTextureCoordinate(nIndex) != mpTextureCoordinates->getTextureCoordinate(nNextIndex))
1315 bRemove = false;
1318 if(bRemove)
1320 // if next is same as index and the control vectors are unused, delete index
1321 remove(nIndex, 1);
1323 else
1325 // if different, step forward
1326 nIndex++;
1331 void transform(const ::basegfx::B3DHomMatrix& rMatrix)
1333 maPoints.transform(rMatrix);
1337 namespace basegfx
1339 namespace {
1341 B3DPolygon::ImplType const & getDefaultPolygon() {
1342 static B3DPolygon::ImplType const singleton;
1343 return singleton;
1348 B3DPolygon::B3DPolygon() :
1349 mpPolygon(getDefaultPolygon())
1353 B3DPolygon::B3DPolygon(const B3DPolygon&) = default;
1355 B3DPolygon::B3DPolygon(B3DPolygon&&) = default;
1357 B3DPolygon::~B3DPolygon() = default;
1359 B3DPolygon& B3DPolygon::operator=(const B3DPolygon&) = default;
1361 B3DPolygon& B3DPolygon::operator=(B3DPolygon&&) = default;
1363 bool B3DPolygon::operator==(const B3DPolygon& rPolygon) const
1365 if(mpPolygon.same_object(rPolygon.mpPolygon))
1366 return true;
1368 return (*mpPolygon == *rPolygon.mpPolygon);
1371 sal_uInt32 B3DPolygon::count() const
1373 return mpPolygon->count();
1376 basegfx::B3DPoint const & B3DPolygon::getB3DPoint(sal_uInt32 nIndex) const
1378 OSL_ENSURE(nIndex < mpPolygon->count(), "B3DPolygon access outside range (!)");
1380 return mpPolygon->getPoint(nIndex);
1383 void B3DPolygon::setB3DPoint(sal_uInt32 nIndex, const basegfx::B3DPoint& rValue)
1385 OSL_ENSURE(nIndex < std::as_const(mpPolygon)->count(), "B3DPolygon access outside range (!)");
1387 if(getB3DPoint(nIndex) != rValue)
1388 mpPolygon->setPoint(nIndex, rValue);
1391 BColor const & B3DPolygon::getBColor(sal_uInt32 nIndex) const
1393 OSL_ENSURE(nIndex < mpPolygon->count(), "B3DPolygon access outside range (!)");
1395 return mpPolygon->getBColor(nIndex);
1398 void B3DPolygon::setBColor(sal_uInt32 nIndex, const BColor& rValue)
1400 OSL_ENSURE(nIndex < std::as_const(mpPolygon)->count(), "B3DPolygon access outside range (!)");
1402 if(std::as_const(mpPolygon)->getBColor(nIndex) != rValue)
1403 mpPolygon->setBColor(nIndex, rValue);
1406 bool B3DPolygon::areBColorsUsed() const
1408 return mpPolygon->areBColorsUsed();
1411 void B3DPolygon::clearBColors()
1413 if(std::as_const(mpPolygon)->areBColorsUsed())
1414 mpPolygon->clearBColors();
1417 B3DVector B3DPolygon::getNormal() const
1419 return mpPolygon->getNormal();
1422 B3DVector const & B3DPolygon::getNormal(sal_uInt32 nIndex) const
1424 OSL_ENSURE(nIndex < mpPolygon->count(), "B3DPolygon access outside range (!)");
1426 return mpPolygon->getNormal(nIndex);
1429 void B3DPolygon::setNormal(sal_uInt32 nIndex, const B3DVector& rValue)
1431 OSL_ENSURE(nIndex < std::as_const(mpPolygon)->count(), "B3DPolygon access outside range (!)");
1433 if(std::as_const(mpPolygon)->getNormal(nIndex) != rValue)
1434 mpPolygon->setNormal(nIndex, rValue);
1437 void B3DPolygon::transformNormals(const B3DHomMatrix& rMatrix)
1439 if(std::as_const(mpPolygon)->areNormalsUsed() && !rMatrix.isIdentity())
1440 mpPolygon->transformNormals(rMatrix);
1443 bool B3DPolygon::areNormalsUsed() const
1445 return mpPolygon->areNormalsUsed();
1448 void B3DPolygon::clearNormals()
1450 if(std::as_const(mpPolygon)->areNormalsUsed())
1451 mpPolygon->clearNormals();
1454 B2DPoint const & B3DPolygon::getTextureCoordinate(sal_uInt32 nIndex) const
1456 OSL_ENSURE(nIndex < mpPolygon->count(), "B3DPolygon access outside range (!)");
1458 return mpPolygon->getTextureCoordinate(nIndex);
1461 void B3DPolygon::setTextureCoordinate(sal_uInt32 nIndex, const B2DPoint& rValue)
1463 OSL_ENSURE(nIndex < std::as_const(mpPolygon)->count(), "B3DPolygon access outside range (!)");
1465 if(std::as_const(mpPolygon)->getTextureCoordinate(nIndex) != rValue)
1466 mpPolygon->setTextureCoordinate(nIndex, rValue);
1469 void B3DPolygon::transformTextureCoordinates(const B2DHomMatrix& rMatrix)
1471 if(std::as_const(mpPolygon)->areTextureCoordinatesUsed() && !rMatrix.isIdentity())
1472 mpPolygon->transformTextureCoordinates(rMatrix);
1475 bool B3DPolygon::areTextureCoordinatesUsed() const
1477 return mpPolygon->areTextureCoordinatesUsed();
1480 void B3DPolygon::clearTextureCoordinates()
1482 if(std::as_const(mpPolygon)->areTextureCoordinatesUsed())
1483 mpPolygon->clearTextureCoordinates();
1486 void B3DPolygon::append(const basegfx::B3DPoint& rPoint, sal_uInt32 nCount)
1488 if(nCount)
1489 mpPolygon->insert(std::as_const(mpPolygon)->count(), rPoint, nCount);
1492 void B3DPolygon::append(const B3DPolygon& rPoly, sal_uInt32 nIndex, sal_uInt32 nCount)
1494 if(!rPoly.count())
1495 return;
1497 if(!nCount)
1499 nCount = rPoly.count();
1502 if(nIndex == 0 && nCount == rPoly.count())
1504 mpPolygon->insert(std::as_const(mpPolygon)->count(), *rPoly.mpPolygon);
1506 else
1508 OSL_ENSURE(nIndex + nCount <= rPoly.mpPolygon->count(), "B3DPolygon Append outside range (!)");
1509 ImplB3DPolygon aTempPoly(*rPoly.mpPolygon, nIndex, nCount);
1510 mpPolygon->insert(std::as_const(mpPolygon)->count(), aTempPoly);
1514 void B3DPolygon::remove(sal_uInt32 nIndex, sal_uInt32 nCount)
1516 OSL_ENSURE(nIndex + nCount <= std::as_const(mpPolygon)->count(), "B3DPolygon Remove outside range (!)");
1518 if(nCount)
1519 mpPolygon->remove(nIndex, nCount);
1522 void B3DPolygon::clear()
1524 mpPolygon = getDefaultPolygon();
1527 bool B3DPolygon::isClosed() const
1529 return mpPolygon->isClosed();
1532 void B3DPolygon::setClosed(bool bNew)
1534 if(isClosed() != bNew)
1535 mpPolygon->setClosed(bNew);
1538 void B3DPolygon::flip()
1540 if(count() > 1)
1541 mpPolygon->flip();
1544 bool B3DPolygon::hasDoublePoints() const
1546 return (mpPolygon->count() > 1 && mpPolygon->hasDoublePoints());
1549 void B3DPolygon::removeDoublePoints()
1551 if(hasDoublePoints())
1553 mpPolygon->removeDoublePointsAtBeginEnd();
1554 mpPolygon->removeDoublePointsWholeTrack();
1558 void B3DPolygon::transform(const basegfx::B3DHomMatrix& rMatrix)
1560 if(std::as_const(mpPolygon)->count() && !rMatrix.isIdentity())
1562 mpPolygon->transform(rMatrix);
1565 } // end of namespace basegfx
1567 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */