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 <rtl/instance.hxx>
25 #include <basegfx/point/b2dpoint.hxx>
26 #include <basegfx/color/bcolor.hxx>
27 #include <basegfx/matrix/b2dhommatrix.hxx>
31 class CoordinateData3D
33 basegfx::B3DPoint maPoint
;
41 explicit CoordinateData3D(const basegfx::B3DPoint
& rData
)
46 const basegfx::B3DPoint
& getCoordinate() const
51 void setCoordinate(const basegfx::B3DPoint
& rValue
)
57 bool operator==(const CoordinateData3D
& rData
) const
59 return (maPoint
== rData
.getCoordinate());
62 void transform(const basegfx::B3DHomMatrix
& rMatrix
)
68 class CoordinateDataArray3D
70 typedef std::vector
< CoordinateData3D
> CoordinateData3DVector
;
72 CoordinateData3DVector maVector
;
75 explicit CoordinateDataArray3D(sal_uInt32 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());
92 sal_uInt32
nISmallest(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()))
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
))
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
))
137 // we always have a minimal point. If we also have a different next and previous,
138 // we can calculate the normal
141 const basegfx::B3DVector
aPrev(*pPrev
- *pSmallest
);
142 const basegfx::B3DVector
aNext(*pNext
- *pSmallest
);
144 aRetval
= cross(aPrev
, aNext
);
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
)
176 // add nCount copies of rValue
177 CoordinateData3DVector::iterator
aIndex(maVector
.begin());
179 maVector
.insert(aIndex
, nCount
, rValue
);
183 void insert(sal_uInt32 nIndex
, const CoordinateDataArray3D
& rSource
)
185 const sal_uInt32
nCount(rSource
.maVector
.size());
190 CoordinateData3DVector::iterator
aIndex(maVector
.begin());
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
)
203 CoordinateData3DVector::iterator
aStart(maVector
.begin());
205 const CoordinateData3DVector::iterator
aEnd(aStart
+ nCount
);
206 maVector
.erase(aStart
, aEnd
);
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
);
227 void transform(const ::basegfx::B3DHomMatrix
& rMatrix
)
229 for (auto & elem
: maVector
)
231 elem
.transform(rMatrix
);
238 typedef std::vector
< ::basegfx::BColor
> BColorDataVector
;
240 BColorDataVector maVector
;
241 sal_uInt32 mnUsedEntries
;
244 explicit BColorArray(sal_uInt32 nCount
)
250 BColorArray(const BColorArray
& rOriginal
, sal_uInt32 nIndex
, sal_uInt32 nCount
)
254 BColorDataVector::const_iterator
aStart(rOriginal
.maVector
.begin());
256 BColorDataVector::const_iterator
aEnd(aStart
);
257 assert(nCount
<= rOriginal
.maVector
.size());
259 maVector
.reserve(nCount
);
261 for(; aStart
!= aEnd
; ++aStart
)
263 if(!aStart
->equalZero())
266 maVector
.push_back(*aStart
);
270 bool operator==(const BColorArray
& rCandidate
) const
272 return (maVector
== rCandidate
.maVector
);
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());
294 maVector
[nIndex
] = rValue
;
298 maVector
[nIndex
] = ::basegfx::BColor::getEmptyBColor();
306 maVector
[nIndex
] = rValue
;
312 void insert(sal_uInt32 nIndex
, const ::basegfx::BColor
& rValue
, sal_uInt32 nCount
)
316 // add nCount copies of rValue
317 BColorDataVector::iterator
aIndex(maVector
.begin());
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());
333 BColorDataVector::iterator
aIndex(maVector
.begin());
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())
347 void remove(sal_uInt32 nIndex
, sal_uInt32 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())
362 maVector
.erase(aDeleteStart
, aDeleteEnd
);
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
);
386 typedef std::vector
< ::basegfx::B3DVector
> NormalsData3DVector
;
388 NormalsData3DVector maVector
;
389 sal_uInt32 mnUsedEntries
;
392 explicit NormalsArray3D(sal_uInt32 nCount
)
398 NormalsArray3D(const NormalsArray3D
& rOriginal
, sal_uInt32 nIndex
, sal_uInt32 nCount
)
402 NormalsData3DVector::const_iterator
aStart(rOriginal
.maVector
.begin());
404 NormalsData3DVector::const_iterator
aEnd(aStart
);
406 maVector
.reserve(nCount
);
408 for(; aStart
!= aEnd
; ++aStart
)
410 if(!aStart
->equalZero())
413 maVector
.push_back(*aStart
);
417 bool operator==(const NormalsArray3D
& rCandidate
) const
419 return (maVector
== rCandidate
.maVector
);
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());
441 maVector
[nIndex
] = rValue
;
445 maVector
[nIndex
] = ::basegfx::B3DVector::getEmptyVector();
453 maVector
[nIndex
] = rValue
;
459 void insert(sal_uInt32 nIndex
, const ::basegfx::B3DVector
& rValue
, sal_uInt32 nCount
)
463 // add nCount copies of rValue
464 NormalsData3DVector::iterator
aIndex(maVector
.begin());
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());
480 NormalsData3DVector::iterator
aIndex(maVector
.begin());
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())
494 void remove(sal_uInt32 nIndex
, sal_uInt32 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())
509 maVector
.erase(aDeleteStart
, aDeleteEnd
);
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
);
530 void transform(const basegfx::B3DHomMatrix
& rMatrix
)
532 for (auto & elem
: maVector
)
539 class TextureCoordinate2D
541 typedef std::vector
< ::basegfx::B2DPoint
> TextureData2DVector
;
543 TextureData2DVector maVector
;
544 sal_uInt32 mnUsedEntries
;
547 explicit TextureCoordinate2D(sal_uInt32 nCount
)
553 TextureCoordinate2D(const TextureCoordinate2D
& rOriginal
, sal_uInt32 nIndex
, sal_uInt32 nCount
)
557 TextureData2DVector::const_iterator
aStart(rOriginal
.maVector
.begin());
559 TextureData2DVector::const_iterator
aEnd(aStart
);
561 maVector
.reserve(nCount
);
563 for(; aStart
!= aEnd
; ++aStart
)
565 if(!aStart
->equalZero())
568 maVector
.push_back(*aStart
);
572 bool operator==(const TextureCoordinate2D
& rCandidate
) const
574 return (maVector
== rCandidate
.maVector
);
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());
596 maVector
[nIndex
] = rValue
;
600 maVector
[nIndex
] = ::basegfx::B2DPoint::getEmptyPoint();
608 maVector
[nIndex
] = rValue
;
614 void insert(sal_uInt32 nIndex
, const ::basegfx::B2DPoint
& rValue
, sal_uInt32 nCount
)
618 // add nCount copies of rValue
619 TextureData2DVector::iterator
aIndex(maVector
.begin());
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());
635 TextureData2DVector::iterator
aIndex(maVector
.begin());
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())
649 void remove(sal_uInt32 nIndex
, sal_uInt32 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())
664 maVector
.erase(aDeleteStart
, aDeleteEnd
);
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
);
685 void transform(const ::basegfx::B2DHomMatrix
& rMatrix
)
687 for (auto & elem
: maVector
)
696 // The point vector. This vector exists always and defines the
698 CoordinateDataArray3D maPoints
;
700 // The BColor vector. This vectors are created on demand
702 std::unique_ptr
<BColorArray
> mpBColors
;
704 // The Normals vector. This vectors are created on demand
706 std::unique_ptr
<NormalsArray3D
> mpNormals
;
708 // The TextureCoordinates vector. This vectors are created on demand
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
718 // flag which says if maPlaneNormal is up-to-date
719 bool mbPlaneNormalValid
: 1;
722 void invalidatePlaneNormal()
724 if(mbPlaneNormalValid
)
726 mbPlaneNormalValid
= false;
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.
737 mpTextureCoordinates(nullptr),
738 maPlaneNormal(::basegfx::B3DVector::getEmptyVector()),
740 mbPlaneNormalValid(true)
742 // complete initialization with defaults
745 ImplB3DPolygon(const ImplB3DPolygon
& rToBeCopied
)
746 : maPoints(rToBeCopied
.maPoints
),
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
),
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())
791 if(rToBeCopied
.mpNormals
&& rToBeCopied
.mpNormals
->isUsed())
793 mpNormals
.reset( new NormalsArray3D(*rToBeCopied
.mpNormals
, nIndex
, nCount
) );
795 if(!mpNormals
->isUsed())
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
822 void setClosed(bool bNew
)
824 if(bNew
!= mbIsClosed
)
830 bool impBColorsAreEqual(const ImplB3DPolygon
& rCandidate
) const
832 bool bBColorsAreEqual(true);
836 if(rCandidate
.mpBColors
)
838 bBColorsAreEqual
= (*mpBColors
== *rCandidate
.mpBColors
);
842 // candidate has no BColors, so it's assumed all unused.
843 bBColorsAreEqual
= !mpBColors
->isUsed();
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);
864 if(rCandidate
.mpNormals
)
866 bNormalsAreEqual
= (*mpNormals
== *rCandidate
.mpNormals
);
870 // candidate has no normals, so it's assumed all unused.
871 bNormalsAreEqual
= !mpNormals
->isUsed();
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
);
898 // candidate has no TextureCoordinates, so it's assumed all unused.
899 bTextureCoordinatesAreEqual
= !mpTextureCoordinates
->isUsed();
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
))
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
)
951 CoordinateData3D
aCoordinate(rPoint
);
952 maPoints
.insert(nIndex
, aCoordinate
, nCount
);
953 invalidatePlaneNormal();
957 mpBColors
->insert(nIndex
, ::basegfx::BColor::getEmptyBColor(), nCount
);
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
976 return mpBColors
->getBColor(nIndex
);
980 return ::basegfx::BColor::getEmptyBColor();
984 void setBColor(sal_uInt32 nIndex
, const ::basegfx::BColor
& rValue
)
988 if(!rValue
.equalZero())
990 mpBColors
.reset( new BColorArray(maPoints
.count()) );
991 mpBColors
->setBColor(nIndex
, rValue
);
996 mpBColors
->setBColor(nIndex
, rValue
);
998 if(!mpBColors
->isUsed())
1005 bool areBColorsUsed() const
1007 return (mpBColors
&& mpBColors
->isUsed());
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
1030 return mpNormals
->getNormal(nIndex
);
1034 return ::basegfx::B3DVector::getEmptyVector();
1038 void setNormal(sal_uInt32 nIndex
, const ::basegfx::B3DVector
& rValue
)
1042 if(!rValue
.equalZero())
1044 mpNormals
.reset( new NormalsArray3D(maPoints
.count()) );
1045 mpNormals
->setNormal(nIndex
, rValue
);
1050 mpNormals
->setNormal(nIndex
, rValue
);
1052 if(!mpNormals
->isUsed())
1059 void transformNormals(const ::basegfx::B3DHomMatrix
& rMatrix
)
1063 mpNormals
->transform(rMatrix
);
1067 bool areNormalsUsed() const
1069 return (mpNormals
&& mpNormals
->isUsed());
1077 const ::basegfx::B2DPoint
& getTextureCoordinate(sal_uInt32 nIndex
) const
1079 if(mpTextureCoordinates
)
1081 return mpTextureCoordinates
->getTextureCoordinate(nIndex
);
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
);
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());
1134 maPoints
.insert(nIndex
, rSource
.maPoints
);
1135 invalidatePlaneNormal();
1137 if(rSource
.mpBColors
&& rSource
.mpBColors
->isUsed())
1141 mpBColors
.reset( new BColorArray(maPoints
.count()) );
1144 mpBColors
->insert(nIndex
, *rSource
.mpBColors
);
1150 mpBColors
->insert(nIndex
, ::basegfx::BColor::getEmptyBColor(), nCount
);
1154 if(rSource
.mpNormals
&& rSource
.mpNormals
->isUsed())
1158 mpNormals
.reset( new NormalsArray3D(maPoints
.count()) );
1161 mpNormals
->insert(nIndex
, *rSource
.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
);
1182 if(mpTextureCoordinates
)
1184 mpTextureCoordinates
->insert(nIndex
, ::basegfx::B2DPoint::getEmptyPoint(), nCount
);
1190 void remove(sal_uInt32 nIndex
, sal_uInt32 nCount
)
1194 maPoints
.remove(nIndex
, nCount
);
1195 invalidatePlaneNormal();
1199 mpBColors
->remove(nIndex
, nCount
);
1201 if(!mpBColors
->isUsed())
1209 mpNormals
->remove(nIndex
, nCount
);
1211 if(!mpNormals
->isUsed())
1217 if(mpTextureCoordinates
)
1219 mpTextureCoordinates
->remove(nIndex
, nCount
);
1221 if(!mpTextureCoordinates
->isUsed())
1223 mpTextureCoordinates
.reset();
1231 if(maPoints
.count() > 1)
1235 if(mbPlaneNormalValid
)
1237 // mirror plane normal
1238 maPlaneNormal
= -maPlaneNormal
;
1251 if(mpTextureCoordinates
)
1253 mpTextureCoordinates
->flip();
1258 bool hasDoublePoints() const
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
)));
1271 const bool bNormalsEqual(!mpNormals
|| (mpNormals
->getNormal(0) == mpNormals
->getNormal(nIndex
)));
1275 const bool bTextureCoordinatesEqual(!mpTextureCoordinates
|| (mpTextureCoordinates
->getTextureCoordinate(0) == mpTextureCoordinates
->getTextureCoordinate(nIndex
)));
1277 if(bTextureCoordinatesEqual
)
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)));
1295 const bool bNormalsEqual(!mpNormals
|| (mpNormals
->getNormal(a
) == mpNormals
->getNormal(a
+ 1)));
1299 const bool bTextureCoordinatesEqual(!mpTextureCoordinates
|| (mpTextureCoordinates
->getTextureCoordinate(a
) == mpTextureCoordinates
->getTextureCoordinate(a
+ 1)));
1301 if(bTextureCoordinatesEqual
)
1313 void removeDoublePointsAtBeginEnd()
1315 // Only remove DoublePoints at Begin and End when poly is closed
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
)))
1334 if(bRemove
&& mpNormals
&& !(mpNormals
->getNormal(0) == mpNormals
->getNormal(nIndex
)))
1339 if(bRemove
&& mpTextureCoordinates
&& !(mpTextureCoordinates
->getTextureCoordinate(0) == mpTextureCoordinates
->getTextureCoordinate(nIndex
)))
1347 const sal_uInt32
nIndex(maPoints
.count() - 1);
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
)))
1370 if(bRemove
&& mpNormals
&& !(mpNormals
->getNormal(nIndex
) == mpNormals
->getNormal(nNextIndex
)))
1375 if(bRemove
&& mpTextureCoordinates
&& !(mpTextureCoordinates
->getTextureCoordinate(nIndex
) == mpTextureCoordinates
->getTextureCoordinate(nNextIndex
)))
1382 // if next is same as index and the control vectors are unused, delete index
1387 // if different, step forward
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();
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
))
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
)
1558 mpPolygon
->insert(mpPolygon
->count(), rPoint
, nCount
);
1561 void B3DPolygon::append(const B3DPolygon
& rPoly
, sal_uInt32 nIndex
, sal_uInt32 nCount
)
1567 nCount
= rPoly
.count();
1570 if(nIndex
== 0 && nCount
== rPoly
.count())
1572 mpPolygon
->insert(mpPolygon
->count(), *rPoly
.mpPolygon
);
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 (!)");
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()
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: */