1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
35 class CoordinateData3D
37 basegfx::B3DPoint maPoint
;
44 explicit CoordinateData3D(const basegfx::B3DPoint
& rData
)
49 const basegfx::B3DPoint
& getCoordinate() const
54 void setCoordinate(const basegfx::B3DPoint
& rValue
)
60 bool operator==(const CoordinateData3D
& rData
) const
62 return (maPoint
== rData
.getCoordinate());
65 void transform(const basegfx::B3DHomMatrix
& rMatrix
)
71 class CoordinateDataArray3D
73 typedef std::vector
< CoordinateData3D
> CoordinateData3DVector
;
75 CoordinateData3DVector maVector
;
78 explicit CoordinateDataArray3D(sal_uInt32 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());
95 sal_uInt32
nISmallest(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()))
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
))
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
))
140 // we always have a minimal point. If we also have a different next and previous,
141 // we can calculate the normal
144 const basegfx::B3DVector
aPrev(*pPrev
- *pSmallest
);
145 const basegfx::B3DVector
aNext(*pNext
- *pSmallest
);
147 aRetval
= cross(aPrev
, aNext
);
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
)
179 // add nCount copies of rValue
180 CoordinateData3DVector::iterator
aIndex(maVector
.begin());
182 maVector
.insert(aIndex
, nCount
, rValue
);
186 void insert(sal_uInt32 nIndex
, const CoordinateDataArray3D
& rSource
)
188 const sal_uInt32
nCount(rSource
.maVector
.size());
193 CoordinateData3DVector::iterator
aIndex(maVector
.begin());
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
)
206 CoordinateData3DVector::iterator
aStart(maVector
.begin());
208 const CoordinateData3DVector::iterator
aEnd(aStart
+ nCount
);
209 maVector
.erase(aStart
, aEnd
);
215 if(maVector
.size() <= 1)
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
);
230 void transform(const ::basegfx::B3DHomMatrix
& rMatrix
)
232 for (auto & elem
: maVector
)
234 elem
.transform(rMatrix
);
241 typedef std::vector
< ::basegfx::BColor
> BColorDataVector
;
243 BColorDataVector maVector
;
244 sal_uInt32 mnUsedEntries
;
247 explicit BColorArray(sal_uInt32 nCount
)
253 BColorArray(const BColorArray
& rOriginal
, sal_uInt32 nIndex
, sal_uInt32 nCount
)
256 BColorDataVector::const_iterator
aStart(rOriginal
.maVector
.begin());
258 BColorDataVector::const_iterator
aEnd(aStart
);
259 assert(nCount
<= rOriginal
.maVector
.size());
261 maVector
.reserve(nCount
);
263 for(; aStart
!= aEnd
; ++aStart
)
265 if(!aStart
->equalZero())
268 maVector
.push_back(*aStart
);
272 bool operator==(const BColorArray
& rCandidate
) const
274 return (maVector
== rCandidate
.maVector
);
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());
296 maVector
[nIndex
] = rValue
;
300 maVector
[nIndex
] = ::basegfx::BColor::getEmptyBColor();
308 maVector
[nIndex
] = rValue
;
314 void insert(sal_uInt32 nIndex
, const ::basegfx::BColor
& rValue
, sal_uInt32 nCount
)
318 // add nCount copies of rValue
319 BColorDataVector::iterator
aIndex(maVector
.begin());
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());
335 BColorDataVector::iterator
aIndex(maVector
.begin());
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
)
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
));
358 maVector
.erase(aDeleteStart
, aDeleteEnd
);
364 if(maVector
.size() <= 1)
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
);
382 typedef std::vector
< ::basegfx::B3DVector
> NormalsData3DVector
;
384 NormalsData3DVector maVector
;
385 sal_uInt32 mnUsedEntries
;
388 explicit NormalsArray3D(sal_uInt32 nCount
)
394 NormalsArray3D(const NormalsArray3D
& rOriginal
, sal_uInt32 nIndex
, sal_uInt32 nCount
)
397 NormalsData3DVector::const_iterator
aStart(rOriginal
.maVector
.begin());
399 NormalsData3DVector::const_iterator
aEnd(aStart
);
401 maVector
.reserve(nCount
);
403 for(; aStart
!= aEnd
; ++aStart
)
405 if(!aStart
->equalZero())
408 maVector
.push_back(*aStart
);
412 bool operator==(const NormalsArray3D
& rCandidate
) const
414 return (maVector
== rCandidate
.maVector
);
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());
436 maVector
[nIndex
] = rValue
;
440 maVector
[nIndex
] = ::basegfx::B3DVector::getEmptyVector();
448 maVector
[nIndex
] = rValue
;
454 void insert(sal_uInt32 nIndex
, const ::basegfx::B3DVector
& rValue
, sal_uInt32 nCount
)
458 // add nCount copies of rValue
459 NormalsData3DVector::iterator
aIndex(maVector
.begin());
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());
475 NormalsData3DVector::iterator
aIndex(maVector
.begin());
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
)
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
));
498 maVector
.erase(aDeleteStart
, aDeleteEnd
);
504 if(maVector
.size() <= 1)
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
);
519 void transform(const basegfx::B3DHomMatrix
& rMatrix
)
521 for (auto & elem
: maVector
)
528 class TextureCoordinate2D
530 typedef std::vector
< ::basegfx::B2DPoint
> TextureData2DVector
;
532 TextureData2DVector maVector
;
533 sal_uInt32 mnUsedEntries
;
536 explicit TextureCoordinate2D(sal_uInt32 nCount
)
542 TextureCoordinate2D(const TextureCoordinate2D
& rOriginal
, sal_uInt32 nIndex
, sal_uInt32 nCount
)
545 TextureData2DVector::const_iterator
aStart(rOriginal
.maVector
.begin());
547 TextureData2DVector::const_iterator
aEnd(aStart
);
549 maVector
.reserve(nCount
);
551 for(; aStart
!= aEnd
; ++aStart
)
553 if(!aStart
->equalZero())
556 maVector
.push_back(*aStart
);
560 bool operator==(const TextureCoordinate2D
& rCandidate
) const
562 return (maVector
== rCandidate
.maVector
);
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());
584 maVector
[nIndex
] = rValue
;
588 maVector
[nIndex
] = ::basegfx::B2DPoint::getEmptyPoint();
596 maVector
[nIndex
] = rValue
;
602 void insert(sal_uInt32 nIndex
, const ::basegfx::B2DPoint
& rValue
, sal_uInt32 nCount
)
606 // add nCount copies of rValue
607 TextureData2DVector::iterator
aIndex(maVector
.begin());
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());
623 TextureData2DVector::iterator
aIndex(maVector
.begin());
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
)
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
));
646 maVector
.erase(aDeleteStart
, aDeleteEnd
);
652 if(maVector
.size() <= 1)
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
);
667 void transform(const ::basegfx::B2DHomMatrix
& rMatrix
)
669 for (auto & elem
: maVector
)
680 // The point vector. This vector exists always and defines the
682 CoordinateDataArray3D maPoints
;
684 // The BColor vector. This vectors are created on demand
686 std::unique_ptr
<BColorArray
> mpBColors
;
688 // The Normals vector. This vectors are created on demand
690 std::unique_ptr
<NormalsArray3D
> mpNormals
;
692 // The TextureCoordinates vector. This vectors are created on demand
694 std::unique_ptr
<TextureCoordinate2D
> mpTextureCoordinates
;
696 // flag which decides if this polygon is opened or closed
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.
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())
745 if(rToBeCopied
.mpNormals
&& rToBeCopied
.mpNormals
->isUsed())
747 mpNormals
.reset( new NormalsArray3D(*rToBeCopied
.mpNormals
, nIndex
, nCount
) );
749 if(!mpNormals
->isUsed())
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
776 void setClosed(bool bNew
)
778 if(bNew
!= mbIsClosed
)
784 bool impBColorsAreEqual(const ImplB3DPolygon
& rCandidate
) const
786 bool bBColorsAreEqual(true);
790 if(rCandidate
.mpBColors
)
792 bBColorsAreEqual
= (*mpBColors
== *rCandidate
.mpBColors
);
796 // candidate has no BColors, so it's assumed all unused.
797 bBColorsAreEqual
= !mpBColors
->isUsed();
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);
818 if(rCandidate
.mpNormals
)
820 bNormalsAreEqual
= (*mpNormals
== *rCandidate
.mpNormals
);
824 // candidate has no normals, so it's assumed all unused.
825 bNormalsAreEqual
= !mpNormals
->isUsed();
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
);
852 // candidate has no TextureCoordinates, so it's assumed all unused.
853 bTextureCoordinatesAreEqual
= !mpTextureCoordinates
->isUsed();
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
))
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
)
905 CoordinateData3D
aCoordinate(rPoint
);
906 maPoints
.insert(nIndex
, aCoordinate
, nCount
);
910 mpBColors
->insert(nIndex
, ::basegfx::BColor::getEmptyBColor(), nCount
);
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
928 return mpBColors
->getBColor(nIndex
);
932 return ::basegfx::BColor::getEmptyBColor();
936 void setBColor(sal_uInt32 nIndex
, const ::basegfx::BColor
& rValue
)
940 if(!rValue
.equalZero())
942 mpBColors
.reset( new BColorArray(maPoints
.count()) );
943 mpBColors
->setBColor(nIndex
, rValue
);
948 mpBColors
->setBColor(nIndex
, rValue
);
950 if(!mpBColors
->isUsed())
957 bool areBColorsUsed() const
959 return (mpBColors
&& mpBColors
->isUsed());
967 ::basegfx::B3DVector
getNormal() const
969 return maPoints
.getNormal();
972 const ::basegfx::B3DVector
& getNormal(sal_uInt32 nIndex
) const
976 return mpNormals
->getNormal(nIndex
);
980 return ::basegfx::B3DVector::getEmptyVector();
984 void setNormal(sal_uInt32 nIndex
, const ::basegfx::B3DVector
& rValue
)
988 if(!rValue
.equalZero())
990 mpNormals
.reset( new NormalsArray3D(maPoints
.count()) );
991 mpNormals
->setNormal(nIndex
, rValue
);
996 mpNormals
->setNormal(nIndex
, rValue
);
998 if(!mpNormals
->isUsed())
1005 void transformNormals(const ::basegfx::B3DHomMatrix
& rMatrix
)
1009 mpNormals
->transform(rMatrix
);
1013 bool areNormalsUsed() const
1015 return (mpNormals
&& mpNormals
->isUsed());
1023 const ::basegfx::B2DPoint
& getTextureCoordinate(sal_uInt32 nIndex
) const
1025 if(mpTextureCoordinates
)
1027 return mpTextureCoordinates
->getTextureCoordinate(nIndex
);
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
);
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());
1081 maPoints
.insert(nIndex
, rSource
.maPoints
);
1083 if(rSource
.mpBColors
&& rSource
.mpBColors
->isUsed())
1087 mpBColors
.reset( new BColorArray(maPoints
.count()) );
1090 mpBColors
->insert(nIndex
, *rSource
.mpBColors
);
1096 mpBColors
->insert(nIndex
, ::basegfx::BColor::getEmptyBColor(), nCount
);
1100 if(rSource
.mpNormals
&& rSource
.mpNormals
->isUsed())
1104 mpNormals
.reset( new NormalsArray3D(maPoints
.count()) );
1107 mpNormals
->insert(nIndex
, *rSource
.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
);
1128 if(mpTextureCoordinates
)
1130 mpTextureCoordinates
->insert(nIndex
, ::basegfx::B2DPoint::getEmptyPoint(), nCount
);
1135 void remove(sal_uInt32 nIndex
, sal_uInt32 nCount
)
1140 maPoints
.remove(nIndex
, nCount
);
1144 mpBColors
->remove(nIndex
, nCount
);
1146 if(!mpBColors
->isUsed())
1154 mpNormals
->remove(nIndex
, nCount
);
1156 if(!mpNormals
->isUsed())
1162 if(mpTextureCoordinates
)
1164 mpTextureCoordinates
->remove(nIndex
, nCount
);
1166 if(!mpTextureCoordinates
->isUsed())
1168 mpTextureCoordinates
.reset();
1175 if(maPoints
.count() <= 1)
1190 if(mpTextureCoordinates
)
1192 mpTextureCoordinates
->flip();
1196 bool hasDoublePoints() const
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
)));
1209 const bool bNormalsEqual(!mpNormals
|| (mpNormals
->getNormal(0) == mpNormals
->getNormal(nIndex
)));
1213 const bool bTextureCoordinatesEqual(!mpTextureCoordinates
|| (mpTextureCoordinates
->getTextureCoordinate(0) == mpTextureCoordinates
->getTextureCoordinate(nIndex
)));
1215 if(bTextureCoordinatesEqual
)
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)));
1233 const bool bNormalsEqual(!mpNormals
|| (mpNormals
->getNormal(a
) == mpNormals
->getNormal(a
+ 1)));
1237 const bool bTextureCoordinatesEqual(!mpTextureCoordinates
|| (mpTextureCoordinates
->getTextureCoordinate(a
) == mpTextureCoordinates
->getTextureCoordinate(a
+ 1)));
1239 if(bTextureCoordinatesEqual
)
1251 void removeDoublePointsAtBeginEnd()
1253 // Only remove DoublePoints at Begin and End when poly is closed
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
))
1273 if(bRemove
&& mpNormals
&& mpNormals
->getNormal(0) != mpNormals
->getNormal(nIndex
))
1278 if(bRemove
&& mpTextureCoordinates
&& mpTextureCoordinates
->getTextureCoordinate(0) != mpTextureCoordinates
->getTextureCoordinate(nIndex
))
1286 const sal_uInt32
nIndex(maPoints
.count() - 1);
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
))
1308 if(bRemove
&& mpNormals
&& mpNormals
->getNormal(nIndex
) != mpNormals
->getNormal(nNextIndex
))
1313 if(bRemove
&& mpTextureCoordinates
&& mpTextureCoordinates
->getTextureCoordinate(nIndex
) != mpTextureCoordinates
->getTextureCoordinate(nNextIndex
))
1320 // if next is same as index and the control vectors are unused, delete index
1325 // if different, step forward
1331 void transform(const ::basegfx::B3DHomMatrix
& rMatrix
)
1333 maPoints
.transform(rMatrix
);
1341 B3DPolygon::ImplType
const & getDefaultPolygon() {
1342 static B3DPolygon::ImplType
const 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
))
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
)
1489 mpPolygon
->insert(std::as_const(mpPolygon
)->count(), rPoint
, nCount
);
1492 void B3DPolygon::append(const B3DPolygon
& rPoly
, sal_uInt32 nIndex
, sal_uInt32 nCount
)
1499 nCount
= rPoly
.count();
1502 if(nIndex
== 0 && nCount
== rPoly
.count())
1504 mpPolygon
->insert(std::as_const(mpPolygon
)->count(), *rPoly
.mpPolygon
);
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 (!)");
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()
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: */