Version 6.1.0.2, tag libreoffice-6.1.0.2
[LibreOffice.git] / basegfx / source / polygon / b3dpolygon.cxx
blob58be07cfe897187d3945908572996ec9613dc91f
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 <rtl/instance.hxx>
25 #include <basegfx/point/b2dpoint.hxx>
26 #include <basegfx/color/bcolor.hxx>
27 #include <basegfx/matrix/b2dhommatrix.hxx>
28 #include <vector>
29 #include <algorithm>
31 class CoordinateData3D
33 basegfx::B3DPoint maPoint;
35 public:
36 CoordinateData3D()
37 : maPoint()
41 explicit CoordinateData3D(const basegfx::B3DPoint& rData)
42 : maPoint(rData)
46 const basegfx::B3DPoint& getCoordinate() const
48 return maPoint;
51 void setCoordinate(const basegfx::B3DPoint& rValue)
53 if(rValue != maPoint)
54 maPoint = rValue;
57 bool operator==(const CoordinateData3D& rData) const
59 return (maPoint == rData.getCoordinate());
62 void transform(const basegfx::B3DHomMatrix& rMatrix)
64 maPoint *= rMatrix;
68 class CoordinateDataArray3D
70 typedef std::vector< CoordinateData3D > CoordinateData3DVector;
72 CoordinateData3DVector maVector;
74 public:
75 explicit CoordinateDataArray3D(sal_uInt32 nCount)
76 : maVector(nCount)
80 CoordinateDataArray3D(const CoordinateDataArray3D& rOriginal, sal_uInt32 nIndex, sal_uInt32 nCount)
81 : maVector(rOriginal.maVector.begin() + nIndex, rOriginal.maVector.begin() + (nIndex + nCount))
85 ::basegfx::B3DVector getNormal() const
87 ::basegfx::B3DVector aRetval;
88 const sal_uInt32 nPointCount(maVector.size());
90 if(nPointCount > 2)
92 sal_uInt32 nISmallest(0);
93 sal_uInt32 a(0);
94 const basegfx::B3DPoint* pSmallest(&maVector[0].getCoordinate());
95 const basegfx::B3DPoint* pNext(nullptr);
96 const basegfx::B3DPoint* pPrev(nullptr);
98 // To guarantee a correctly oriented point, choose an outmost one
99 // which then cannot be concave
100 for(a = 1; a < nPointCount; a++)
102 const basegfx::B3DPoint& rCandidate = maVector[a].getCoordinate();
104 if((rCandidate.getX() < pSmallest->getX())
105 || (rCandidate.getX() == pSmallest->getX() && rCandidate.getY() < pSmallest->getY())
106 || (rCandidate.getX() == pSmallest->getX() && rCandidate.getY() == pSmallest->getY() && rCandidate.getZ() < pSmallest->getZ()))
108 nISmallest = a;
109 pSmallest = &rCandidate;
113 // look for a next point different from minimal one
114 for(a = (nISmallest + 1) % nPointCount; a != nISmallest; a = (a + 1) % nPointCount)
116 const basegfx::B3DPoint& rCandidate = maVector[a].getCoordinate();
118 if(!rCandidate.equal(*pSmallest))
120 pNext = &rCandidate;
121 break;
125 // look for a previous point different from minimal one
126 for(a = (nISmallest + nPointCount - 1) % nPointCount; a != nISmallest; a = (a + nPointCount - 1) % nPointCount)
128 const basegfx::B3DPoint& rCandidate = maVector[a].getCoordinate();
130 if(!rCandidate.equal(*pSmallest))
132 pPrev = &rCandidate;
133 break;
137 // we always have a minimal point. If we also have a different next and previous,
138 // we can calculate the normal
139 if(pNext && pPrev)
141 const basegfx::B3DVector aPrev(*pPrev - *pSmallest);
142 const basegfx::B3DVector aNext(*pNext - *pSmallest);
144 aRetval = cross(aPrev, aNext);
145 aRetval.normalize();
149 return aRetval;
152 sal_uInt32 count() const
154 return maVector.size();
157 bool operator==(const CoordinateDataArray3D& rCandidate) const
159 return (maVector == rCandidate.maVector);
162 const basegfx::B3DPoint& getCoordinate(sal_uInt32 nIndex) const
164 return maVector[nIndex].getCoordinate();
167 void setCoordinate(sal_uInt32 nIndex, const basegfx::B3DPoint& rValue)
169 maVector[nIndex].setCoordinate(rValue);
172 void insert(sal_uInt32 nIndex, const CoordinateData3D& rValue, sal_uInt32 nCount)
174 if(nCount)
176 // add nCount copies of rValue
177 CoordinateData3DVector::iterator aIndex(maVector.begin());
178 aIndex += nIndex;
179 maVector.insert(aIndex, nCount, rValue);
183 void insert(sal_uInt32 nIndex, const CoordinateDataArray3D& rSource)
185 const sal_uInt32 nCount(rSource.maVector.size());
187 if(nCount)
189 // insert data
190 CoordinateData3DVector::iterator aIndex(maVector.begin());
191 aIndex += nIndex;
192 CoordinateData3DVector::const_iterator aStart(rSource.maVector.begin());
193 CoordinateData3DVector::const_iterator aEnd(rSource.maVector.end());
194 maVector.insert(aIndex, aStart, aEnd);
198 void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
200 if(nCount)
202 // remove point data
203 CoordinateData3DVector::iterator aStart(maVector.begin());
204 aStart += nIndex;
205 const CoordinateData3DVector::iterator aEnd(aStart + nCount);
206 maVector.erase(aStart, aEnd);
210 void flip()
212 if(maVector.size() > 1)
214 const sal_uInt32 nHalfSize(maVector.size() >> 1);
215 CoordinateData3DVector::iterator aStart(maVector.begin());
216 CoordinateData3DVector::iterator aEnd(maVector.end() - 1);
218 for(sal_uInt32 a(0); a < nHalfSize; a++)
220 std::swap(*aStart, *aEnd);
221 ++aStart;
222 --aEnd;
227 void transform(const ::basegfx::B3DHomMatrix& rMatrix)
229 for (auto & elem : maVector)
231 elem.transform(rMatrix);
236 class BColorArray
238 typedef std::vector< ::basegfx::BColor > BColorDataVector;
240 BColorDataVector maVector;
241 sal_uInt32 mnUsedEntries;
243 public:
244 explicit BColorArray(sal_uInt32 nCount)
245 : maVector(nCount),
246 mnUsedEntries(0)
250 BColorArray(const BColorArray& rOriginal, sal_uInt32 nIndex, sal_uInt32 nCount)
251 : maVector(),
252 mnUsedEntries(0)
254 BColorDataVector::const_iterator aStart(rOriginal.maVector.begin());
255 aStart += nIndex;
256 BColorDataVector::const_iterator aEnd(aStart);
257 assert(nCount <= rOriginal.maVector.size());
258 aEnd += nCount;
259 maVector.reserve(nCount);
261 for(; aStart != aEnd; ++aStart)
263 if(!aStart->equalZero())
264 mnUsedEntries++;
266 maVector.push_back(*aStart);
270 bool operator==(const BColorArray& rCandidate) const
272 return (maVector == rCandidate.maVector);
275 bool isUsed() const
277 return (mnUsedEntries != 0);
280 const ::basegfx::BColor& getBColor(sal_uInt32 nIndex) const
282 return maVector[nIndex];
285 void setBColor(sal_uInt32 nIndex, const ::basegfx::BColor& rValue)
287 bool bWasUsed(mnUsedEntries && !maVector[nIndex].equalZero());
288 bool bIsUsed(!rValue.equalZero());
290 if(bWasUsed)
292 if(bIsUsed)
294 maVector[nIndex] = rValue;
296 else
298 maVector[nIndex] = ::basegfx::BColor::getEmptyBColor();
299 mnUsedEntries--;
302 else
304 if(bIsUsed)
306 maVector[nIndex] = rValue;
307 mnUsedEntries++;
312 void insert(sal_uInt32 nIndex, const ::basegfx::BColor& rValue, sal_uInt32 nCount)
314 if(nCount)
316 // add nCount copies of rValue
317 BColorDataVector::iterator aIndex(maVector.begin());
318 aIndex += nIndex;
319 maVector.insert(aIndex, nCount, rValue);
321 if(!rValue.equalZero())
322 mnUsedEntries += nCount;
326 void insert(sal_uInt32 nIndex, const BColorArray& rSource)
328 const sal_uInt32 nCount(rSource.maVector.size());
330 if(nCount)
332 // insert data
333 BColorDataVector::iterator aIndex(maVector.begin());
334 aIndex += nIndex;
335 BColorDataVector::const_iterator aStart(rSource.maVector.begin());
336 BColorDataVector::const_iterator aEnd(rSource.maVector.end());
337 maVector.insert(aIndex, aStart, aEnd);
339 for(; aStart != aEnd; ++aStart)
341 if(!aStart->equalZero())
342 mnUsedEntries++;
347 void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
349 if(nCount)
351 const BColorDataVector::iterator aDeleteStart(maVector.begin() + nIndex);
352 const BColorDataVector::iterator aDeleteEnd(aDeleteStart + nCount);
353 BColorDataVector::const_iterator aStart(aDeleteStart);
355 for(; mnUsedEntries && aStart != aDeleteEnd; ++aStart)
357 if(!aStart->equalZero())
358 mnUsedEntries--;
361 // remove point data
362 maVector.erase(aDeleteStart, aDeleteEnd);
366 void flip()
368 if(maVector.size() > 1)
370 const sal_uInt32 nHalfSize(maVector.size() >> 1);
371 BColorDataVector::iterator aStart(maVector.begin());
372 BColorDataVector::iterator aEnd(maVector.end() - 1);
374 for(sal_uInt32 a(0); a < nHalfSize; a++)
376 std::swap(*aStart, *aEnd);
377 ++aStart;
378 --aEnd;
384 class NormalsArray3D
386 typedef std::vector< ::basegfx::B3DVector > NormalsData3DVector;
388 NormalsData3DVector maVector;
389 sal_uInt32 mnUsedEntries;
391 public:
392 explicit NormalsArray3D(sal_uInt32 nCount)
393 : maVector(nCount),
394 mnUsedEntries(0)
398 NormalsArray3D(const NormalsArray3D& rOriginal, sal_uInt32 nIndex, sal_uInt32 nCount)
399 : maVector(),
400 mnUsedEntries(0)
402 NormalsData3DVector::const_iterator aStart(rOriginal.maVector.begin());
403 aStart += nIndex;
404 NormalsData3DVector::const_iterator aEnd(aStart);
405 aEnd += nCount;
406 maVector.reserve(nCount);
408 for(; aStart != aEnd; ++aStart)
410 if(!aStart->equalZero())
411 mnUsedEntries++;
413 maVector.push_back(*aStart);
417 bool operator==(const NormalsArray3D& rCandidate) const
419 return (maVector == rCandidate.maVector);
422 bool isUsed() const
424 return (mnUsedEntries != 0);
427 const ::basegfx::B3DVector& getNormal(sal_uInt32 nIndex) const
429 return maVector[nIndex];
432 void setNormal(sal_uInt32 nIndex, const ::basegfx::B3DVector& rValue)
434 bool bWasUsed(mnUsedEntries && !maVector[nIndex].equalZero());
435 bool bIsUsed(!rValue.equalZero());
437 if(bWasUsed)
439 if(bIsUsed)
441 maVector[nIndex] = rValue;
443 else
445 maVector[nIndex] = ::basegfx::B3DVector::getEmptyVector();
446 mnUsedEntries--;
449 else
451 if(bIsUsed)
453 maVector[nIndex] = rValue;
454 mnUsedEntries++;
459 void insert(sal_uInt32 nIndex, const ::basegfx::B3DVector& rValue, sal_uInt32 nCount)
461 if(nCount)
463 // add nCount copies of rValue
464 NormalsData3DVector::iterator aIndex(maVector.begin());
465 aIndex += nIndex;
466 maVector.insert(aIndex, nCount, rValue);
468 if(!rValue.equalZero())
469 mnUsedEntries += nCount;
473 void insert(sal_uInt32 nIndex, const NormalsArray3D& rSource)
475 const sal_uInt32 nCount(rSource.maVector.size());
477 if(nCount)
479 // insert data
480 NormalsData3DVector::iterator aIndex(maVector.begin());
481 aIndex += nIndex;
482 NormalsData3DVector::const_iterator aStart(rSource.maVector.begin());
483 NormalsData3DVector::const_iterator aEnd(rSource.maVector.end());
484 maVector.insert(aIndex, aStart, aEnd);
486 for(; aStart != aEnd; ++aStart)
488 if(!aStart->equalZero())
489 mnUsedEntries++;
494 void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
496 if(nCount)
498 const NormalsData3DVector::iterator aDeleteStart(maVector.begin() + nIndex);
499 const NormalsData3DVector::iterator aDeleteEnd(aDeleteStart + nCount);
500 NormalsData3DVector::const_iterator aStart(aDeleteStart);
502 for(; mnUsedEntries && aStart != aDeleteEnd; ++aStart)
504 if(!aStart->equalZero())
505 mnUsedEntries--;
508 // remove point data
509 maVector.erase(aDeleteStart, aDeleteEnd);
513 void flip()
515 if(maVector.size() > 1)
517 const sal_uInt32 nHalfSize(maVector.size() >> 1);
518 NormalsData3DVector::iterator aStart(maVector.begin());
519 NormalsData3DVector::iterator aEnd(maVector.end() - 1);
521 for(sal_uInt32 a(0); a < nHalfSize; a++)
523 std::swap(*aStart, *aEnd);
524 ++aStart;
525 --aEnd;
530 void transform(const basegfx::B3DHomMatrix& rMatrix)
532 for (auto & elem : maVector)
534 elem *= rMatrix;
539 class TextureCoordinate2D
541 typedef std::vector< ::basegfx::B2DPoint > TextureData2DVector;
543 TextureData2DVector maVector;
544 sal_uInt32 mnUsedEntries;
546 public:
547 explicit TextureCoordinate2D(sal_uInt32 nCount)
548 : maVector(nCount),
549 mnUsedEntries(0)
553 TextureCoordinate2D(const TextureCoordinate2D& rOriginal, sal_uInt32 nIndex, sal_uInt32 nCount)
554 : maVector(),
555 mnUsedEntries(0)
557 TextureData2DVector::const_iterator aStart(rOriginal.maVector.begin());
558 aStart += nIndex;
559 TextureData2DVector::const_iterator aEnd(aStart);
560 aEnd += nCount;
561 maVector.reserve(nCount);
563 for(; aStart != aEnd; ++aStart)
565 if(!aStart->equalZero())
566 mnUsedEntries++;
568 maVector.push_back(*aStart);
572 bool operator==(const TextureCoordinate2D& rCandidate) const
574 return (maVector == rCandidate.maVector);
577 bool isUsed() const
579 return (mnUsedEntries != 0);
582 const ::basegfx::B2DPoint& getTextureCoordinate(sal_uInt32 nIndex) const
584 return maVector[nIndex];
587 void setTextureCoordinate(sal_uInt32 nIndex, const ::basegfx::B2DPoint& rValue)
589 bool bWasUsed(mnUsedEntries && !maVector[nIndex].equalZero());
590 bool bIsUsed(!rValue.equalZero());
592 if(bWasUsed)
594 if(bIsUsed)
596 maVector[nIndex] = rValue;
598 else
600 maVector[nIndex] = ::basegfx::B2DPoint::getEmptyPoint();
601 mnUsedEntries--;
604 else
606 if(bIsUsed)
608 maVector[nIndex] = rValue;
609 mnUsedEntries++;
614 void insert(sal_uInt32 nIndex, const ::basegfx::B2DPoint& rValue, sal_uInt32 nCount)
616 if(nCount)
618 // add nCount copies of rValue
619 TextureData2DVector::iterator aIndex(maVector.begin());
620 aIndex += nIndex;
621 maVector.insert(aIndex, nCount, rValue);
623 if(!rValue.equalZero())
624 mnUsedEntries += nCount;
628 void insert(sal_uInt32 nIndex, const TextureCoordinate2D& rSource)
630 const sal_uInt32 nCount(rSource.maVector.size());
632 if(nCount)
634 // insert data
635 TextureData2DVector::iterator aIndex(maVector.begin());
636 aIndex += nIndex;
637 TextureData2DVector::const_iterator aStart(rSource.maVector.begin());
638 TextureData2DVector::const_iterator aEnd(rSource.maVector.end());
639 maVector.insert(aIndex, aStart, aEnd);
641 for(; aStart != aEnd; ++aStart)
643 if(!aStart->equalZero())
644 mnUsedEntries++;
649 void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
651 if(nCount)
653 const TextureData2DVector::iterator aDeleteStart(maVector.begin() + nIndex);
654 const TextureData2DVector::iterator aDeleteEnd(aDeleteStart + nCount);
655 TextureData2DVector::const_iterator aStart(aDeleteStart);
657 for(; mnUsedEntries && aStart != aDeleteEnd; ++aStart)
659 if(!aStart->equalZero())
660 mnUsedEntries--;
663 // remove point data
664 maVector.erase(aDeleteStart, aDeleteEnd);
668 void flip()
670 if(maVector.size() > 1)
672 const sal_uInt32 nHalfSize(maVector.size() >> 1);
673 TextureData2DVector::iterator aStart(maVector.begin());
674 TextureData2DVector::iterator aEnd(maVector.end() - 1);
676 for(sal_uInt32 a(0); a < nHalfSize; a++)
678 std::swap(*aStart, *aEnd);
679 ++aStart;
680 --aEnd;
685 void transform(const ::basegfx::B2DHomMatrix& rMatrix)
687 for (auto & elem : maVector)
689 elem *= rMatrix;
694 class ImplB3DPolygon
696 // The point vector. This vector exists always and defines the
697 // count of members.
698 CoordinateDataArray3D maPoints;
700 // The BColor vector. This vectors are created on demand
701 // and may be zero.
702 std::unique_ptr<BColorArray> mpBColors;
704 // The Normals vector. This vectors are created on demand
705 // and may be zero.
706 std::unique_ptr<NormalsArray3D> mpNormals;
708 // The TextureCoordinates vector. This vectors are created on demand
709 // and may be zero.
710 std::unique_ptr<TextureCoordinate2D> mpTextureCoordinates;
712 // The calculated plane normal. mbPlaneNormalValid says if it's valid.
713 ::basegfx::B3DVector maPlaneNormal;
715 // flag which decides if this polygon is opened or closed
716 bool mbIsClosed : 1;
718 // flag which says if maPlaneNormal is up-to-date
719 bool mbPlaneNormalValid : 1;
721 protected:
722 void invalidatePlaneNormal()
724 if(mbPlaneNormalValid)
726 mbPlaneNormalValid = false;
730 public:
731 // This constructor is only used from the static identity polygon, thus
732 // the RefCount is set to 1 to never 'delete' this static incarnation.
733 ImplB3DPolygon()
734 : maPoints(0),
735 mpBColors(nullptr),
736 mpNormals(nullptr),
737 mpTextureCoordinates(nullptr),
738 maPlaneNormal(::basegfx::B3DVector::getEmptyVector()),
739 mbIsClosed(false),
740 mbPlaneNormalValid(true)
742 // complete initialization with defaults
745 ImplB3DPolygon(const ImplB3DPolygon& rToBeCopied)
746 : maPoints(rToBeCopied.maPoints),
747 mpBColors(nullptr),
748 mpNormals(nullptr),
749 mpTextureCoordinates(nullptr),
750 maPlaneNormal(rToBeCopied.maPlaneNormal),
751 mbIsClosed(rToBeCopied.mbIsClosed),
752 mbPlaneNormalValid(rToBeCopied.mbPlaneNormalValid)
754 // complete initialization using copy
755 if(rToBeCopied.mpBColors && rToBeCopied.mpBColors->isUsed())
757 mpBColors.reset( new BColorArray(*rToBeCopied.mpBColors) );
760 if(rToBeCopied.mpNormals && rToBeCopied.mpNormals->isUsed())
762 mpNormals.reset( new NormalsArray3D(*rToBeCopied.mpNormals) );
765 if(rToBeCopied.mpTextureCoordinates && rToBeCopied.mpTextureCoordinates->isUsed())
767 mpTextureCoordinates.reset( new TextureCoordinate2D(*rToBeCopied.mpTextureCoordinates) );
771 ImplB3DPolygon(const ImplB3DPolygon& rToBeCopied, sal_uInt32 nIndex, sal_uInt32 nCount)
772 : maPoints(rToBeCopied.maPoints, nIndex, nCount),
773 mpBColors(nullptr),
774 mpNormals(nullptr),
775 mpTextureCoordinates(nullptr),
776 maPlaneNormal(::basegfx::B3DVector::getEmptyVector()),
777 mbIsClosed(rToBeCopied.mbIsClosed),
778 mbPlaneNormalValid(false)
780 // complete initialization using partly copy
781 if(rToBeCopied.mpBColors && rToBeCopied.mpBColors->isUsed())
783 mpBColors.reset( new BColorArray(*rToBeCopied.mpBColors, nIndex, nCount) );
785 if(!mpBColors->isUsed())
787 mpBColors.reset();
791 if(rToBeCopied.mpNormals && rToBeCopied.mpNormals->isUsed())
793 mpNormals.reset( new NormalsArray3D(*rToBeCopied.mpNormals, nIndex, nCount) );
795 if(!mpNormals->isUsed())
797 mpNormals.reset();
801 if(rToBeCopied.mpTextureCoordinates && rToBeCopied.mpTextureCoordinates->isUsed())
803 mpTextureCoordinates.reset( new TextureCoordinate2D(*rToBeCopied.mpTextureCoordinates, nIndex, nCount) );
805 if(!mpTextureCoordinates->isUsed())
807 mpTextureCoordinates.reset();
812 sal_uInt32 count() const
814 return maPoints.count();
817 bool isClosed() const
819 return mbIsClosed;
822 void setClosed(bool bNew)
824 if(bNew != mbIsClosed)
826 mbIsClosed = bNew;
830 bool impBColorsAreEqual(const ImplB3DPolygon& rCandidate) const
832 bool bBColorsAreEqual(true);
834 if(mpBColors)
836 if(rCandidate.mpBColors)
838 bBColorsAreEqual = (*mpBColors == *rCandidate.mpBColors);
840 else
842 // candidate has no BColors, so it's assumed all unused.
843 bBColorsAreEqual = !mpBColors->isUsed();
846 else
848 if(rCandidate.mpBColors)
850 // we have no TextureCoordinates, so it's assumed all unused.
851 bBColorsAreEqual = !rCandidate.mpBColors->isUsed();
855 return bBColorsAreEqual;
858 bool impNormalsAreEqual(const ImplB3DPolygon& rCandidate) const
860 bool bNormalsAreEqual(true);
862 if(mpNormals)
864 if(rCandidate.mpNormals)
866 bNormalsAreEqual = (*mpNormals == *rCandidate.mpNormals);
868 else
870 // candidate has no normals, so it's assumed all unused.
871 bNormalsAreEqual = !mpNormals->isUsed();
874 else
876 if(rCandidate.mpNormals)
878 // we have no normals, so it's assumed all unused.
879 bNormalsAreEqual = !rCandidate.mpNormals->isUsed();
883 return bNormalsAreEqual;
886 bool impTextureCoordinatesAreEqual(const ImplB3DPolygon& rCandidate) const
888 bool bTextureCoordinatesAreEqual(true);
890 if(mpTextureCoordinates)
892 if(rCandidate.mpTextureCoordinates)
894 bTextureCoordinatesAreEqual = (*mpTextureCoordinates == *rCandidate.mpTextureCoordinates);
896 else
898 // candidate has no TextureCoordinates, so it's assumed all unused.
899 bTextureCoordinatesAreEqual = !mpTextureCoordinates->isUsed();
902 else
904 if(rCandidate.mpTextureCoordinates)
906 // we have no TextureCoordinates, so it's assumed all unused.
907 bTextureCoordinatesAreEqual = !rCandidate.mpTextureCoordinates->isUsed();
911 return bTextureCoordinatesAreEqual;
914 bool operator==(const ImplB3DPolygon& rCandidate) const
916 if(mbIsClosed == rCandidate.mbIsClosed)
918 if(maPoints == rCandidate.maPoints)
920 if(impBColorsAreEqual(rCandidate))
922 if(impNormalsAreEqual(rCandidate))
924 if(impTextureCoordinatesAreEqual(rCandidate))
926 return true;
933 return false;
936 const ::basegfx::B3DPoint& getPoint(sal_uInt32 nIndex) const
938 return maPoints.getCoordinate(nIndex);
941 void setPoint(sal_uInt32 nIndex, const ::basegfx::B3DPoint& rValue)
943 maPoints.setCoordinate(nIndex, rValue);
944 invalidatePlaneNormal();
947 void insert(sal_uInt32 nIndex, const ::basegfx::B3DPoint& rPoint, sal_uInt32 nCount)
949 if(nCount)
951 CoordinateData3D aCoordinate(rPoint);
952 maPoints.insert(nIndex, aCoordinate, nCount);
953 invalidatePlaneNormal();
955 if(mpBColors)
957 mpBColors->insert(nIndex, ::basegfx::BColor::getEmptyBColor(), nCount);
960 if(mpNormals)
962 mpNormals->insert(nIndex, ::basegfx::B3DVector::getEmptyVector(), nCount);
965 if(mpTextureCoordinates)
967 mpTextureCoordinates->insert(nIndex, ::basegfx::B2DPoint::getEmptyPoint(), nCount);
972 const ::basegfx::BColor& getBColor(sal_uInt32 nIndex) const
974 if(mpBColors)
976 return mpBColors->getBColor(nIndex);
978 else
980 return ::basegfx::BColor::getEmptyBColor();
984 void setBColor(sal_uInt32 nIndex, const ::basegfx::BColor& rValue)
986 if(!mpBColors)
988 if(!rValue.equalZero())
990 mpBColors.reset( new BColorArray(maPoints.count()) );
991 mpBColors->setBColor(nIndex, rValue);
994 else
996 mpBColors->setBColor(nIndex, rValue);
998 if(!mpBColors->isUsed())
1000 mpBColors.reset();
1005 bool areBColorsUsed() const
1007 return (mpBColors && mpBColors->isUsed());
1010 void clearBColors()
1012 mpBColors.reset();
1015 const ::basegfx::B3DVector& getNormal() const
1017 if(!mbPlaneNormalValid)
1019 const_cast< ImplB3DPolygon* >(this)->maPlaneNormal = maPoints.getNormal();
1020 const_cast< ImplB3DPolygon* >(this)->mbPlaneNormalValid = true;
1023 return maPlaneNormal;
1026 const ::basegfx::B3DVector& getNormal(sal_uInt32 nIndex) const
1028 if(mpNormals)
1030 return mpNormals->getNormal(nIndex);
1032 else
1034 return ::basegfx::B3DVector::getEmptyVector();
1038 void setNormal(sal_uInt32 nIndex, const ::basegfx::B3DVector& rValue)
1040 if(!mpNormals)
1042 if(!rValue.equalZero())
1044 mpNormals.reset( new NormalsArray3D(maPoints.count()) );
1045 mpNormals->setNormal(nIndex, rValue);
1048 else
1050 mpNormals->setNormal(nIndex, rValue);
1052 if(!mpNormals->isUsed())
1054 mpNormals.reset();
1059 void transformNormals(const ::basegfx::B3DHomMatrix& rMatrix)
1061 if(mpNormals)
1063 mpNormals->transform(rMatrix);
1067 bool areNormalsUsed() const
1069 return (mpNormals && mpNormals->isUsed());
1072 void clearNormals()
1074 mpNormals.reset();
1077 const ::basegfx::B2DPoint& getTextureCoordinate(sal_uInt32 nIndex) const
1079 if(mpTextureCoordinates)
1081 return mpTextureCoordinates->getTextureCoordinate(nIndex);
1083 else
1085 return ::basegfx::B2DPoint::getEmptyPoint();
1089 void setTextureCoordinate(sal_uInt32 nIndex, const ::basegfx::B2DPoint& rValue)
1091 if(!mpTextureCoordinates)
1093 if(!rValue.equalZero())
1095 mpTextureCoordinates.reset( new TextureCoordinate2D(maPoints.count()) );
1096 mpTextureCoordinates->setTextureCoordinate(nIndex, rValue);
1099 else
1101 mpTextureCoordinates->setTextureCoordinate(nIndex, rValue);
1103 if(!mpTextureCoordinates->isUsed())
1105 mpTextureCoordinates.reset();
1110 bool areTextureCoordinatesUsed() const
1112 return (mpTextureCoordinates && mpTextureCoordinates->isUsed());
1115 void clearTextureCoordinates()
1117 mpTextureCoordinates.reset();
1120 void transformTextureCoordinates(const ::basegfx::B2DHomMatrix& rMatrix)
1122 if(mpTextureCoordinates)
1124 mpTextureCoordinates->transform(rMatrix);
1128 void insert(sal_uInt32 nIndex, const ImplB3DPolygon& rSource)
1130 const sal_uInt32 nCount(rSource.maPoints.count());
1132 if(nCount)
1134 maPoints.insert(nIndex, rSource.maPoints);
1135 invalidatePlaneNormal();
1137 if(rSource.mpBColors && rSource.mpBColors->isUsed())
1139 if(!mpBColors)
1141 mpBColors.reset( new BColorArray(maPoints.count()) );
1144 mpBColors->insert(nIndex, *rSource.mpBColors);
1146 else
1148 if(mpBColors)
1150 mpBColors->insert(nIndex, ::basegfx::BColor::getEmptyBColor(), nCount);
1154 if(rSource.mpNormals && rSource.mpNormals->isUsed())
1156 if(!mpNormals)
1158 mpNormals.reset( new NormalsArray3D(maPoints.count()) );
1161 mpNormals->insert(nIndex, *rSource.mpNormals);
1163 else
1165 if(mpNormals)
1167 mpNormals->insert(nIndex, ::basegfx::B3DVector::getEmptyVector(), nCount);
1171 if(rSource.mpTextureCoordinates && rSource.mpTextureCoordinates->isUsed())
1173 if(!mpTextureCoordinates)
1175 mpTextureCoordinates.reset( new TextureCoordinate2D(maPoints.count()) );
1178 mpTextureCoordinates->insert(nIndex, *rSource.mpTextureCoordinates);
1180 else
1182 if(mpTextureCoordinates)
1184 mpTextureCoordinates->insert(nIndex, ::basegfx::B2DPoint::getEmptyPoint(), nCount);
1190 void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
1192 if(nCount)
1194 maPoints.remove(nIndex, nCount);
1195 invalidatePlaneNormal();
1197 if(mpBColors)
1199 mpBColors->remove(nIndex, nCount);
1201 if(!mpBColors->isUsed())
1203 mpBColors.reset();
1207 if(mpNormals)
1209 mpNormals->remove(nIndex, nCount);
1211 if(!mpNormals->isUsed())
1213 mpNormals.reset();
1217 if(mpTextureCoordinates)
1219 mpTextureCoordinates->remove(nIndex, nCount);
1221 if(!mpTextureCoordinates->isUsed())
1223 mpTextureCoordinates.reset();
1229 void flip()
1231 if(maPoints.count() > 1)
1233 maPoints.flip();
1235 if(mbPlaneNormalValid)
1237 // mirror plane normal
1238 maPlaneNormal = -maPlaneNormal;
1241 if(mpBColors)
1243 mpBColors->flip();
1246 if(mpNormals)
1248 mpNormals->flip();
1251 if(mpTextureCoordinates)
1253 mpTextureCoordinates->flip();
1258 bool hasDoublePoints() const
1260 if(mbIsClosed)
1262 // check for same start and end point
1263 const sal_uInt32 nIndex(maPoints.count() - 1);
1265 if(maPoints.getCoordinate(0) == maPoints.getCoordinate(nIndex))
1267 const bool bBColorEqual(!mpBColors || (mpBColors->getBColor(0) == mpBColors->getBColor(nIndex)));
1269 if(bBColorEqual)
1271 const bool bNormalsEqual(!mpNormals || (mpNormals->getNormal(0) == mpNormals->getNormal(nIndex)));
1273 if(bNormalsEqual)
1275 const bool bTextureCoordinatesEqual(!mpTextureCoordinates || (mpTextureCoordinates->getTextureCoordinate(0) == mpTextureCoordinates->getTextureCoordinate(nIndex)));
1277 if(bTextureCoordinatesEqual)
1279 return true;
1286 // test for range
1287 for(sal_uInt32 a(0); a < maPoints.count() - 1; a++)
1289 if(maPoints.getCoordinate(a) == maPoints.getCoordinate(a + 1))
1291 const bool bBColorEqual(!mpBColors || (mpBColors->getBColor(a) == mpBColors->getBColor(a + 1)));
1293 if(bBColorEqual)
1295 const bool bNormalsEqual(!mpNormals || (mpNormals->getNormal(a) == mpNormals->getNormal(a + 1)));
1297 if(bNormalsEqual)
1299 const bool bTextureCoordinatesEqual(!mpTextureCoordinates || (mpTextureCoordinates->getTextureCoordinate(a) == mpTextureCoordinates->getTextureCoordinate(a + 1)));
1301 if(bTextureCoordinatesEqual)
1303 return true;
1310 return false;
1313 void removeDoublePointsAtBeginEnd()
1315 // Only remove DoublePoints at Begin and End when poly is closed
1316 if(mbIsClosed)
1318 bool bRemove;
1322 bRemove = false;
1324 if(maPoints.count() > 1)
1326 const sal_uInt32 nIndex(maPoints.count() - 1);
1327 bRemove = (maPoints.getCoordinate(0) == maPoints.getCoordinate(nIndex));
1329 if(bRemove && mpBColors && !(mpBColors->getBColor(0) == mpBColors->getBColor(nIndex)))
1331 bRemove = false;
1334 if(bRemove && mpNormals && !(mpNormals->getNormal(0) == mpNormals->getNormal(nIndex)))
1336 bRemove = false;
1339 if(bRemove && mpTextureCoordinates && !(mpTextureCoordinates->getTextureCoordinate(0) == mpTextureCoordinates->getTextureCoordinate(nIndex)))
1341 bRemove = false;
1345 if(bRemove)
1347 const sal_uInt32 nIndex(maPoints.count() - 1);
1348 remove(nIndex, 1);
1350 } while(bRemove);
1354 void removeDoublePointsWholeTrack()
1356 sal_uInt32 nIndex(0);
1358 // test as long as there are at least two points and as long as the index
1359 // is smaller or equal second last point
1360 while((maPoints.count() > 1) && (nIndex <= maPoints.count() - 2))
1362 const sal_uInt32 nNextIndex(nIndex + 1);
1363 bool bRemove(maPoints.getCoordinate(nIndex) == maPoints.getCoordinate(nNextIndex));
1365 if(bRemove && mpBColors && !(mpBColors->getBColor(nIndex) == mpBColors->getBColor(nNextIndex)))
1367 bRemove = false;
1370 if(bRemove && mpNormals && !(mpNormals->getNormal(nIndex) == mpNormals->getNormal(nNextIndex)))
1372 bRemove = false;
1375 if(bRemove && mpTextureCoordinates && !(mpTextureCoordinates->getTextureCoordinate(nIndex) == mpTextureCoordinates->getTextureCoordinate(nNextIndex)))
1377 bRemove = false;
1380 if(bRemove)
1382 // if next is same as index and the control vectors are unused, delete index
1383 remove(nIndex, 1);
1385 else
1387 // if different, step forward
1388 nIndex++;
1393 void transform(const ::basegfx::B3DHomMatrix& rMatrix)
1395 maPoints.transform(rMatrix);
1397 // Here, it seems to be possible to transform a valid plane normal and to avoid
1398 // invalidation, but it's not true. If the transformation contains shears or e.g.
1399 // perspective projection, the orthogonality to the transformed plane will not
1400 // be preserved. It may be possible to test that at the matrix to not invalidate in
1401 // all cases or to extract a matrix which does not 'shear' the vector which is
1402 // a normal in this case. As long as this is not sure, i will just invalidate.
1403 invalidatePlaneNormal();
1407 namespace basegfx
1409 namespace { struct DefaultPolygon : public rtl::Static< B3DPolygon::ImplType,
1410 DefaultPolygon > {}; }
1412 B3DPolygon::B3DPolygon() :
1413 mpPolygon(DefaultPolygon::get())
1417 B3DPolygon::B3DPolygon(const B3DPolygon&) = default;
1419 B3DPolygon::B3DPolygon(B3DPolygon&&) = default;
1421 B3DPolygon::~B3DPolygon() = default;
1423 B3DPolygon& B3DPolygon::operator=(const B3DPolygon&) = default;
1425 B3DPolygon& B3DPolygon::operator=(B3DPolygon&&) = default;
1427 bool B3DPolygon::operator==(const B3DPolygon& rPolygon) const
1429 if(mpPolygon.same_object(rPolygon.mpPolygon))
1430 return true;
1432 return (*mpPolygon == *rPolygon.mpPolygon);
1435 bool B3DPolygon::operator!=(const B3DPolygon& rPolygon) const
1437 return !(*this == rPolygon);
1440 sal_uInt32 B3DPolygon::count() const
1442 return mpPolygon->count();
1445 basegfx::B3DPoint const & B3DPolygon::getB3DPoint(sal_uInt32 nIndex) const
1447 OSL_ENSURE(nIndex < mpPolygon->count(), "B3DPolygon access outside range (!)");
1449 return mpPolygon->getPoint(nIndex);
1452 void B3DPolygon::setB3DPoint(sal_uInt32 nIndex, const basegfx::B3DPoint& rValue)
1454 OSL_ENSURE(nIndex < mpPolygon->count(), "B3DPolygon access outside range (!)");
1456 if(getB3DPoint(nIndex) != rValue)
1457 mpPolygon->setPoint(nIndex, rValue);
1460 BColor const & B3DPolygon::getBColor(sal_uInt32 nIndex) const
1462 OSL_ENSURE(nIndex < mpPolygon->count(), "B3DPolygon access outside range (!)");
1464 return mpPolygon->getBColor(nIndex);
1467 void B3DPolygon::setBColor(sal_uInt32 nIndex, const BColor& rValue)
1469 OSL_ENSURE(nIndex < mpPolygon->count(), "B3DPolygon access outside range (!)");
1471 if(mpPolygon->getBColor(nIndex) != rValue)
1472 mpPolygon->setBColor(nIndex, rValue);
1475 bool B3DPolygon::areBColorsUsed() const
1477 return mpPolygon->areBColorsUsed();
1480 void B3DPolygon::clearBColors()
1482 if(mpPolygon->areBColorsUsed())
1483 mpPolygon->clearBColors();
1486 B3DVector const & B3DPolygon::getNormal() const
1488 return mpPolygon->getNormal();
1491 B3DVector const & B3DPolygon::getNormal(sal_uInt32 nIndex) const
1493 OSL_ENSURE(nIndex < mpPolygon->count(), "B3DPolygon access outside range (!)");
1495 return mpPolygon->getNormal(nIndex);
1498 void B3DPolygon::setNormal(sal_uInt32 nIndex, const B3DVector& rValue)
1500 OSL_ENSURE(nIndex < mpPolygon->count(), "B3DPolygon access outside range (!)");
1502 if(mpPolygon->getNormal(nIndex) != rValue)
1503 mpPolygon->setNormal(nIndex, rValue);
1506 void B3DPolygon::transformNormals(const B3DHomMatrix& rMatrix)
1508 if(mpPolygon->areNormalsUsed() && !rMatrix.isIdentity())
1509 mpPolygon->transformNormals(rMatrix);
1512 bool B3DPolygon::areNormalsUsed() const
1514 return mpPolygon->areNormalsUsed();
1517 void B3DPolygon::clearNormals()
1519 if(mpPolygon->areNormalsUsed())
1520 mpPolygon->clearNormals();
1523 B2DPoint const & B3DPolygon::getTextureCoordinate(sal_uInt32 nIndex) const
1525 OSL_ENSURE(nIndex < mpPolygon->count(), "B3DPolygon access outside range (!)");
1527 return mpPolygon->getTextureCoordinate(nIndex);
1530 void B3DPolygon::setTextureCoordinate(sal_uInt32 nIndex, const B2DPoint& rValue)
1532 OSL_ENSURE(nIndex < mpPolygon->count(), "B3DPolygon access outside range (!)");
1534 if(mpPolygon->getTextureCoordinate(nIndex) != rValue)
1535 mpPolygon->setTextureCoordinate(nIndex, rValue);
1538 void B3DPolygon::transformTextureCoordinates(const B2DHomMatrix& rMatrix)
1540 if(mpPolygon->areTextureCoordinatesUsed() && !rMatrix.isIdentity())
1541 mpPolygon->transformTextureCoordinates(rMatrix);
1544 bool B3DPolygon::areTextureCoordinatesUsed() const
1546 return mpPolygon->areTextureCoordinatesUsed();
1549 void B3DPolygon::clearTextureCoordinates()
1551 if(mpPolygon->areTextureCoordinatesUsed())
1552 mpPolygon->clearTextureCoordinates();
1555 void B3DPolygon::append(const basegfx::B3DPoint& rPoint, sal_uInt32 nCount)
1557 if(nCount)
1558 mpPolygon->insert(mpPolygon->count(), rPoint, nCount);
1561 void B3DPolygon::append(const B3DPolygon& rPoly, sal_uInt32 nIndex, sal_uInt32 nCount)
1563 if(rPoly.count())
1565 if(!nCount)
1567 nCount = rPoly.count();
1570 if(nIndex == 0 && nCount == rPoly.count())
1572 mpPolygon->insert(mpPolygon->count(), *rPoly.mpPolygon);
1574 else
1576 OSL_ENSURE(nIndex + nCount <= rPoly.mpPolygon->count(), "B3DPolygon Append outside range (!)");
1577 ImplB3DPolygon aTempPoly(*rPoly.mpPolygon, nIndex, nCount);
1578 mpPolygon->insert(mpPolygon->count(), aTempPoly);
1583 void B3DPolygon::remove(sal_uInt32 nIndex, sal_uInt32 nCount)
1585 OSL_ENSURE(nIndex + nCount <= mpPolygon->count(), "B3DPolygon Remove outside range (!)");
1587 if(nCount)
1588 mpPolygon->remove(nIndex, nCount);
1591 void B3DPolygon::clear()
1593 mpPolygon = DefaultPolygon::get();
1596 bool B3DPolygon::isClosed() const
1598 return mpPolygon->isClosed();
1601 void B3DPolygon::setClosed(bool bNew)
1603 if(isClosed() != bNew)
1604 mpPolygon->setClosed(bNew);
1607 void B3DPolygon::flip()
1609 if(count() > 1)
1610 mpPolygon->flip();
1613 bool B3DPolygon::hasDoublePoints() const
1615 return (mpPolygon->count() > 1 && mpPolygon->hasDoublePoints());
1618 void B3DPolygon::removeDoublePoints()
1620 if(hasDoublePoints())
1622 mpPolygon->removeDoublePointsAtBeginEnd();
1623 mpPolygon->removeDoublePointsWholeTrack();
1627 void B3DPolygon::transform(const basegfx::B3DHomMatrix& rMatrix)
1629 if(mpPolygon->count() && !rMatrix.isIdentity())
1631 mpPolygon->transform(rMatrix);
1634 } // end of namespace basegfx
1636 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */