xref: /trunk/main/basegfx/source/polygon/b3dpolygon.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_basegfx.hxx"
30 #include <osl/diagnose.h>
31 #include <basegfx/polygon/b3dpolygon.hxx>
32 #include <basegfx/point/b3dpoint.hxx>
33 #include <basegfx/matrix/b3dhommatrix.hxx>
34 #include <rtl/instance.hxx>
35 #include <basegfx/point/b2dpoint.hxx>
36 #include <basegfx/color/bcolor.hxx>
37 #include <basegfx/matrix/b2dhommatrix.hxx>
38 #include <vector>
39 #include <algorithm>
40 
41 //////////////////////////////////////////////////////////////////////////////
42 
43 class CoordinateData3D
44 {
45     basegfx::B3DPoint                               maPoint;
46 
47 public:
48     CoordinateData3D()
49     :   maPoint()
50     {
51     }
52 
53     explicit CoordinateData3D(const basegfx::B3DPoint& rData)
54     :   maPoint(rData)
55     {
56     }
57 
58     const basegfx::B3DPoint& getCoordinate() const
59     {
60         return maPoint;
61     }
62 
63     void setCoordinate(const basegfx::B3DPoint& rValue)
64     {
65         if(rValue != maPoint)
66             maPoint = rValue;
67     }
68 
69     bool operator==(const CoordinateData3D& rData) const
70     {
71         return (maPoint == rData.getCoordinate());
72     }
73 
74     void transform(const basegfx::B3DHomMatrix& rMatrix)
75     {
76         maPoint *= rMatrix;
77     }
78 };
79 
80 //////////////////////////////////////////////////////////////////////////////
81 
82 class CoordinateDataArray3D
83 {
84     typedef ::std::vector< CoordinateData3D > CoordinateData3DVector;
85 
86     CoordinateData3DVector                          maVector;
87 
88 public:
89     explicit CoordinateDataArray3D(sal_uInt32 nCount)
90     :   maVector(nCount)
91     {
92     }
93 
94     explicit CoordinateDataArray3D(const CoordinateDataArray3D& rOriginal)
95     :   maVector(rOriginal.maVector)
96     {
97     }
98 
99     CoordinateDataArray3D(const CoordinateDataArray3D& rOriginal, sal_uInt32 nIndex, sal_uInt32 nCount)
100     :   maVector(rOriginal.maVector.begin() + nIndex, rOriginal.maVector.begin() + (nIndex + nCount))
101     {
102     }
103 
104     ~CoordinateDataArray3D()
105     {
106     }
107 
108     ::basegfx::B3DVector getNormal() const
109     {
110         ::basegfx::B3DVector aRetval;
111         const sal_uInt32 nPointCount(maVector.size());
112 
113         if(nPointCount > 2)
114         {
115             sal_uInt32 nISmallest(0);
116             sal_uInt32 a(0);
117             const basegfx::B3DPoint* pSmallest(&maVector[0].getCoordinate());
118             const basegfx::B3DPoint* pNext(0);
119             const basegfx::B3DPoint* pPrev(0);
120 
121             // To guarantee a correctly oriented point, choose an outmost one
122             // which then cannot be concave
123             for(a = 1; a < nPointCount; a++)
124             {
125                 const basegfx::B3DPoint& rCandidate = maVector[a].getCoordinate();
126 
127                 if((rCandidate.getX() < pSmallest->getX())
128                     || (rCandidate.getX() == pSmallest->getX() && rCandidate.getY() < pSmallest->getY())
129                     || (rCandidate.getX() == pSmallest->getX() && rCandidate.getY() == pSmallest->getY() && rCandidate.getZ() < pSmallest->getZ()))
130                 {
131                     nISmallest = a;
132                     pSmallest = &rCandidate;
133                 }
134             }
135 
136             // look for a next point different from minimal one
137             for(a = (nISmallest + 1) % nPointCount; a != nISmallest; a = (a + 1) % nPointCount)
138             {
139                 const basegfx::B3DPoint& rCandidate = maVector[a].getCoordinate();
140 
141                 if(!rCandidate.equal(*pSmallest))
142                 {
143                     pNext = &rCandidate;
144                     break;
145                 }
146             }
147 
148             // look for a previous point different from minimal one
149             for(a = (nISmallest + nPointCount - 1) % nPointCount; a != nISmallest; a = (a + nPointCount - 1) % nPointCount)
150             {
151                 const basegfx::B3DPoint& rCandidate = maVector[a].getCoordinate();
152 
153                 if(!rCandidate.equal(*pSmallest))
154                 {
155                     pPrev = &rCandidate;
156                     break;
157                 }
158             }
159 
160             // we always have a minimal point. If we also have a different next and previous,
161             // we can calculate the normal
162             if(pNext && pPrev)
163             {
164                 const basegfx::B3DVector aPrev(*pPrev - *pSmallest);
165                 const basegfx::B3DVector aNext(*pNext - *pSmallest);
166 
167                 aRetval = cross(aPrev, aNext);
168                 aRetval.normalize();
169             }
170         }
171 
172         return aRetval;
173     }
174 
175     sal_uInt32 count() const
176     {
177         return maVector.size();
178     }
179 
180     bool operator==(const CoordinateDataArray3D& rCandidate) const
181     {
182         return (maVector == rCandidate.maVector);
183     }
184 
185     const basegfx::B3DPoint& getCoordinate(sal_uInt32 nIndex) const
186     {
187         return maVector[nIndex].getCoordinate();
188     }
189 
190     void setCoordinate(sal_uInt32 nIndex, const basegfx::B3DPoint& rValue)
191     {
192         maVector[nIndex].setCoordinate(rValue);
193     }
194 
195     void insert(sal_uInt32 nIndex, const CoordinateData3D& rValue, sal_uInt32 nCount)
196     {
197         if(nCount)
198         {
199             // add nCount copies of rValue
200             CoordinateData3DVector::iterator aIndex(maVector.begin());
201             aIndex += nIndex;
202             maVector.insert(aIndex, nCount, rValue);
203         }
204     }
205 
206     void insert(sal_uInt32 nIndex, const CoordinateDataArray3D& rSource)
207     {
208         const sal_uInt32 nCount(rSource.maVector.size());
209 
210         if(nCount)
211         {
212             // insert data
213             CoordinateData3DVector::iterator aIndex(maVector.begin());
214             aIndex += nIndex;
215             CoordinateData3DVector::const_iterator aStart(rSource.maVector.begin());
216             CoordinateData3DVector::const_iterator aEnd(rSource.maVector.end());
217             maVector.insert(aIndex, aStart, aEnd);
218         }
219     }
220 
221     void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
222     {
223         if(nCount)
224         {
225             // remove point data
226             CoordinateData3DVector::iterator aStart(maVector.begin());
227             aStart += nIndex;
228             const CoordinateData3DVector::iterator aEnd(aStart + nCount);
229             maVector.erase(aStart, aEnd);
230         }
231     }
232 
233     void flip()
234     {
235         if(maVector.size() > 1)
236         {
237             const sal_uInt32 nHalfSize(maVector.size() >> 1L);
238             CoordinateData3DVector::iterator aStart(maVector.begin());
239             CoordinateData3DVector::iterator aEnd(maVector.end() - 1L);
240 
241             for(sal_uInt32 a(0); a < nHalfSize; a++)
242             {
243                 ::std::swap(*aStart, *aEnd);
244                 aStart++;
245                 aEnd--;
246             }
247         }
248     }
249 
250     void transform(const ::basegfx::B3DHomMatrix& rMatrix)
251     {
252         CoordinateData3DVector::iterator aStart(maVector.begin());
253         CoordinateData3DVector::iterator aEnd(maVector.end());
254 
255         for(; aStart != aEnd; aStart++)
256         {
257             aStart->transform(rMatrix);
258         }
259     }
260 };
261 
262 //////////////////////////////////////////////////////////////////////////////
263 
264 class BColorArray
265 {
266     typedef ::std::vector< ::basegfx::BColor > BColorDataVector;
267 
268     BColorDataVector                                    maVector;
269     sal_uInt32                                          mnUsedEntries;
270 
271 public:
272     explicit BColorArray(sal_uInt32 nCount)
273     :   maVector(nCount),
274         mnUsedEntries(0L)
275     {
276     }
277 
278     explicit BColorArray(const BColorArray& rOriginal)
279     :   maVector(rOriginal.maVector),
280         mnUsedEntries(rOriginal.mnUsedEntries)
281     {
282     }
283 
284     BColorArray(const BColorArray& rOriginal, sal_uInt32 nIndex, sal_uInt32 nCount)
285     :   maVector(),
286         mnUsedEntries(0L)
287     {
288         BColorDataVector::const_iterator aStart(rOriginal.maVector.begin());
289         aStart += nIndex;
290         BColorDataVector::const_iterator aEnd(aStart);
291         aEnd += nCount;
292         maVector.reserve(nCount);
293 
294         for(; aStart != aEnd; aStart++)
295         {
296             if(!aStart->equalZero())
297                 mnUsedEntries++;
298 
299             maVector.push_back(*aStart);
300         }
301     }
302 
303     ~BColorArray()
304     {
305     }
306 
307     sal_uInt32 count() const
308     {
309         return maVector.size();
310     }
311 
312     bool operator==(const BColorArray& rCandidate) const
313     {
314         return (maVector == rCandidate.maVector);
315     }
316 
317     bool isUsed() const
318     {
319         return (0L != mnUsedEntries);
320     }
321 
322     const ::basegfx::BColor& getBColor(sal_uInt32 nIndex) const
323     {
324         return maVector[nIndex];
325     }
326 
327     void setBColor(sal_uInt32 nIndex, const ::basegfx::BColor& rValue)
328     {
329         bool bWasUsed(mnUsedEntries && !maVector[nIndex].equalZero());
330         bool bIsUsed(!rValue.equalZero());
331 
332         if(bWasUsed)
333         {
334             if(bIsUsed)
335             {
336                 maVector[nIndex] = rValue;
337             }
338             else
339             {
340                 maVector[nIndex] = ::basegfx::BColor::getEmptyBColor();
341                 mnUsedEntries--;
342             }
343         }
344         else
345         {
346             if(bIsUsed)
347             {
348                 maVector[nIndex] = rValue;
349                 mnUsedEntries++;
350             }
351         }
352     }
353 
354     void insert(sal_uInt32 nIndex, const ::basegfx::BColor& rValue, sal_uInt32 nCount)
355     {
356         if(nCount)
357         {
358             // add nCount copies of rValue
359             BColorDataVector::iterator aIndex(maVector.begin());
360             aIndex += nIndex;
361             maVector.insert(aIndex, nCount, rValue);
362 
363             if(!rValue.equalZero())
364                 mnUsedEntries += nCount;
365         }
366     }
367 
368     void insert(sal_uInt32 nIndex, const BColorArray& rSource)
369     {
370         const sal_uInt32 nCount(rSource.maVector.size());
371 
372         if(nCount)
373         {
374             // insert data
375             BColorDataVector::iterator aIndex(maVector.begin());
376             aIndex += nIndex;
377             BColorDataVector::const_iterator aStart(rSource.maVector.begin());
378             BColorDataVector::const_iterator aEnd(rSource.maVector.end());
379             maVector.insert(aIndex, aStart, aEnd);
380 
381             for(; aStart != aEnd; aStart++)
382             {
383                 if(!aStart->equalZero())
384                     mnUsedEntries++;
385             }
386         }
387     }
388 
389     void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
390     {
391         if(nCount)
392         {
393             const BColorDataVector::iterator aDeleteStart(maVector.begin() + nIndex);
394             const BColorDataVector::iterator aDeleteEnd(aDeleteStart + nCount);
395             BColorDataVector::const_iterator aStart(aDeleteStart);
396 
397             for(; mnUsedEntries && aStart != aDeleteEnd; aStart++)
398             {
399                 if(!aStart->equalZero())
400                     mnUsedEntries--;
401             }
402 
403             // remove point data
404             maVector.erase(aDeleteStart, aDeleteEnd);
405         }
406     }
407 
408     void flip()
409     {
410         if(maVector.size() > 1)
411         {
412             const sal_uInt32 nHalfSize(maVector.size() >> 1L);
413             BColorDataVector::iterator aStart(maVector.begin());
414             BColorDataVector::iterator aEnd(maVector.end() - 1L);
415 
416             for(sal_uInt32 a(0); a < nHalfSize; a++)
417             {
418                 ::std::swap(*aStart, *aEnd);
419                 aStart++;
420                 aEnd--;
421             }
422         }
423     }
424 };
425 
426 //////////////////////////////////////////////////////////////////////////////
427 
428 class NormalsArray3D
429 {
430     typedef ::std::vector< ::basegfx::B3DVector > NormalsData3DVector;
431 
432     NormalsData3DVector                                 maVector;
433     sal_uInt32                                          mnUsedEntries;
434 
435 public:
436     explicit NormalsArray3D(sal_uInt32 nCount)
437     :   maVector(nCount),
438         mnUsedEntries(0L)
439     {
440     }
441 
442     explicit NormalsArray3D(const NormalsArray3D& rOriginal)
443     :   maVector(rOriginal.maVector),
444         mnUsedEntries(rOriginal.mnUsedEntries)
445     {
446     }
447 
448     NormalsArray3D(const NormalsArray3D& rOriginal, sal_uInt32 nIndex, sal_uInt32 nCount)
449     :   maVector(),
450         mnUsedEntries(0L)
451     {
452         NormalsData3DVector::const_iterator aStart(rOriginal.maVector.begin());
453         aStart += nIndex;
454         NormalsData3DVector::const_iterator aEnd(aStart);
455         aEnd += nCount;
456         maVector.reserve(nCount);
457 
458         for(; aStart != aEnd; aStart++)
459         {
460             if(!aStart->equalZero())
461                 mnUsedEntries++;
462 
463             maVector.push_back(*aStart);
464         }
465     }
466 
467     ~NormalsArray3D()
468     {
469     }
470 
471     sal_uInt32 count() const
472     {
473         return maVector.size();
474     }
475 
476     bool operator==(const NormalsArray3D& rCandidate) const
477     {
478         return (maVector == rCandidate.maVector);
479     }
480 
481     bool isUsed() const
482     {
483         return (0L != mnUsedEntries);
484     }
485 
486     const ::basegfx::B3DVector& getNormal(sal_uInt32 nIndex) const
487     {
488         return maVector[nIndex];
489     }
490 
491     void setNormal(sal_uInt32 nIndex, const ::basegfx::B3DVector& rValue)
492     {
493         bool bWasUsed(mnUsedEntries && !maVector[nIndex].equalZero());
494         bool bIsUsed(!rValue.equalZero());
495 
496         if(bWasUsed)
497         {
498             if(bIsUsed)
499             {
500                 maVector[nIndex] = rValue;
501             }
502             else
503             {
504                 maVector[nIndex] = ::basegfx::B3DVector::getEmptyVector();
505                 mnUsedEntries--;
506             }
507         }
508         else
509         {
510             if(bIsUsed)
511             {
512                 maVector[nIndex] = rValue;
513                 mnUsedEntries++;
514             }
515         }
516     }
517 
518     void insert(sal_uInt32 nIndex, const ::basegfx::B3DVector& rValue, sal_uInt32 nCount)
519     {
520         if(nCount)
521         {
522             // add nCount copies of rValue
523             NormalsData3DVector::iterator aIndex(maVector.begin());
524             aIndex += nIndex;
525             maVector.insert(aIndex, nCount, rValue);
526 
527             if(!rValue.equalZero())
528                 mnUsedEntries += nCount;
529         }
530     }
531 
532     void insert(sal_uInt32 nIndex, const NormalsArray3D& rSource)
533     {
534         const sal_uInt32 nCount(rSource.maVector.size());
535 
536         if(nCount)
537         {
538             // insert data
539             NormalsData3DVector::iterator aIndex(maVector.begin());
540             aIndex += nIndex;
541             NormalsData3DVector::const_iterator aStart(rSource.maVector.begin());
542             NormalsData3DVector::const_iterator aEnd(rSource.maVector.end());
543             maVector.insert(aIndex, aStart, aEnd);
544 
545             for(; aStart != aEnd; aStart++)
546             {
547                 if(!aStart->equalZero())
548                     mnUsedEntries++;
549             }
550         }
551     }
552 
553     void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
554     {
555         if(nCount)
556         {
557             const NormalsData3DVector::iterator aDeleteStart(maVector.begin() + nIndex);
558             const NormalsData3DVector::iterator aDeleteEnd(aDeleteStart + nCount);
559             NormalsData3DVector::const_iterator aStart(aDeleteStart);
560 
561             for(; mnUsedEntries && aStart != aDeleteEnd; aStart++)
562             {
563                 if(!aStart->equalZero())
564                     mnUsedEntries--;
565             }
566 
567             // remove point data
568             maVector.erase(aDeleteStart, aDeleteEnd);
569         }
570     }
571 
572     void flip()
573     {
574         if(maVector.size() > 1)
575         {
576             const sal_uInt32 nHalfSize(maVector.size() >> 1L);
577             NormalsData3DVector::iterator aStart(maVector.begin());
578             NormalsData3DVector::iterator aEnd(maVector.end() - 1L);
579 
580             for(sal_uInt32 a(0); a < nHalfSize; a++)
581             {
582                 ::std::swap(*aStart, *aEnd);
583                 aStart++;
584                 aEnd--;
585             }
586         }
587     }
588 
589     void transform(const basegfx::B3DHomMatrix& rMatrix)
590     {
591         NormalsData3DVector::iterator aStart(maVector.begin());
592         NormalsData3DVector::iterator aEnd(maVector.end());
593 
594         for(; aStart != aEnd; aStart++)
595         {
596             (*aStart) *= rMatrix;
597         }
598     }
599 };
600 
601 //////////////////////////////////////////////////////////////////////////////
602 
603 class TextureCoordinate2D
604 {
605     typedef ::std::vector< ::basegfx::B2DPoint > TextureData2DVector;
606 
607     TextureData2DVector                                 maVector;
608     sal_uInt32                                          mnUsedEntries;
609 
610 public:
611     explicit TextureCoordinate2D(sal_uInt32 nCount)
612     :   maVector(nCount),
613         mnUsedEntries(0L)
614     {
615     }
616 
617     explicit TextureCoordinate2D(const TextureCoordinate2D& rOriginal)
618     :   maVector(rOriginal.maVector),
619         mnUsedEntries(rOriginal.mnUsedEntries)
620     {
621     }
622 
623     TextureCoordinate2D(const TextureCoordinate2D& rOriginal, sal_uInt32 nIndex, sal_uInt32 nCount)
624     :   maVector(),
625         mnUsedEntries(0L)
626     {
627         TextureData2DVector::const_iterator aStart(rOriginal.maVector.begin());
628         aStart += nIndex;
629         TextureData2DVector::const_iterator aEnd(aStart);
630         aEnd += nCount;
631         maVector.reserve(nCount);
632 
633         for(; aStart != aEnd; aStart++)
634         {
635             if(!aStart->equalZero())
636                 mnUsedEntries++;
637 
638             maVector.push_back(*aStart);
639         }
640     }
641 
642     ~TextureCoordinate2D()
643     {
644     }
645 
646     sal_uInt32 count() const
647     {
648         return maVector.size();
649     }
650 
651     bool operator==(const TextureCoordinate2D& rCandidate) const
652     {
653         return (maVector == rCandidate.maVector);
654     }
655 
656     bool isUsed() const
657     {
658         return (0L != mnUsedEntries);
659     }
660 
661     const ::basegfx::B2DPoint& getTextureCoordinate(sal_uInt32 nIndex) const
662     {
663         return maVector[nIndex];
664     }
665 
666     void setTextureCoordinate(sal_uInt32 nIndex, const ::basegfx::B2DPoint& rValue)
667     {
668         bool bWasUsed(mnUsedEntries && !maVector[nIndex].equalZero());
669         bool bIsUsed(!rValue.equalZero());
670 
671         if(bWasUsed)
672         {
673             if(bIsUsed)
674             {
675                 maVector[nIndex] = rValue;
676             }
677             else
678             {
679                 maVector[nIndex] = ::basegfx::B2DPoint::getEmptyPoint();
680                 mnUsedEntries--;
681             }
682         }
683         else
684         {
685             if(bIsUsed)
686             {
687                 maVector[nIndex] = rValue;
688                 mnUsedEntries++;
689             }
690         }
691     }
692 
693     void insert(sal_uInt32 nIndex, const ::basegfx::B2DPoint& rValue, sal_uInt32 nCount)
694     {
695         if(nCount)
696         {
697             // add nCount copies of rValue
698             TextureData2DVector::iterator aIndex(maVector.begin());
699             aIndex += nIndex;
700             maVector.insert(aIndex, nCount, rValue);
701 
702             if(!rValue.equalZero())
703                 mnUsedEntries += nCount;
704         }
705     }
706 
707     void insert(sal_uInt32 nIndex, const TextureCoordinate2D& rSource)
708     {
709         const sal_uInt32 nCount(rSource.maVector.size());
710 
711         if(nCount)
712         {
713             // insert data
714             TextureData2DVector::iterator aIndex(maVector.begin());
715             aIndex += nIndex;
716             TextureData2DVector::const_iterator aStart(rSource.maVector.begin());
717             TextureData2DVector::const_iterator aEnd(rSource.maVector.end());
718             maVector.insert(aIndex, aStart, aEnd);
719 
720             for(; aStart != aEnd; aStart++)
721             {
722                 if(!aStart->equalZero())
723                     mnUsedEntries++;
724             }
725         }
726     }
727 
728     void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
729     {
730         if(nCount)
731         {
732             const TextureData2DVector::iterator aDeleteStart(maVector.begin() + nIndex);
733             const TextureData2DVector::iterator aDeleteEnd(aDeleteStart + nCount);
734             TextureData2DVector::const_iterator aStart(aDeleteStart);
735 
736             for(; mnUsedEntries && aStart != aDeleteEnd; aStart++)
737             {
738                 if(!aStart->equalZero())
739                     mnUsedEntries--;
740             }
741 
742             // remove point data
743             maVector.erase(aDeleteStart, aDeleteEnd);
744         }
745     }
746 
747     void flip()
748     {
749         if(maVector.size() > 1)
750         {
751             const sal_uInt32 nHalfSize(maVector.size() >> 1L);
752             TextureData2DVector::iterator aStart(maVector.begin());
753             TextureData2DVector::iterator aEnd(maVector.end() - 1L);
754 
755             for(sal_uInt32 a(0); a < nHalfSize; a++)
756             {
757                 ::std::swap(*aStart, *aEnd);
758                 aStart++;
759                 aEnd--;
760             }
761         }
762     }
763 
764     void transform(const ::basegfx::B2DHomMatrix& rMatrix)
765     {
766         TextureData2DVector::iterator aStart(maVector.begin());
767         TextureData2DVector::iterator aEnd(maVector.end());
768 
769         for(; aStart != aEnd; aStart++)
770         {
771             (*aStart) *= rMatrix;
772         }
773     }
774 };
775 
776 //////////////////////////////////////////////////////////////////////////////
777 
778 class ImplB3DPolygon
779 {
780     // The point vector. This vector exists always and defines the
781     // count of members.
782     CoordinateDataArray3D                           maPoints;
783 
784     // The BColor vector. This vectors are created on demand
785     // and may be zero.
786     BColorArray*                                    mpBColors;
787 
788     // The Normals vector. This vectors are created on demand
789     // and may be zero.
790     NormalsArray3D*                                 mpNormals;
791 
792     // The TextureCoordinates vector. This vectors are created on demand
793     // and may be zero.
794     TextureCoordinate2D*                            mpTextureCoordiantes;
795 
796     // The calculated plane normal. mbPlaneNormalValid says if it's valid.
797     ::basegfx::B3DVector                            maPlaneNormal;
798 
799     // bitfield
800     // flag which decides if this polygon is opened or closed
801     unsigned                                        mbIsClosed : 1;
802 
803     // flag which says if maPlaneNormal is up-to-date
804     unsigned                                        mbPlaneNormalValid : 1;
805 
806 protected:
807     void invalidatePlaneNormal()
808     {
809         if(mbPlaneNormalValid)
810         {
811             mbPlaneNormalValid = false;
812         }
813     }
814 
815 public:
816     // This constructor is only used from the static identity polygon, thus
817     // the RefCount is set to 1 to never 'delete' this static incarnation.
818     ImplB3DPolygon()
819     :   maPoints(0L),
820         mpBColors(0L),
821         mpNormals(0L),
822         mpTextureCoordiantes(0L),
823         maPlaneNormal(::basegfx::B3DVector::getEmptyVector()),
824         mbIsClosed(false),
825         mbPlaneNormalValid(true)
826     {
827         // complete initialization with defaults
828     }
829 
830     ImplB3DPolygon(const ImplB3DPolygon& rToBeCopied)
831     :   maPoints(rToBeCopied.maPoints),
832         mpBColors(0L),
833         mpNormals(0L),
834         mpTextureCoordiantes(0L),
835         maPlaneNormal(rToBeCopied.maPlaneNormal),
836         mbIsClosed(rToBeCopied.mbIsClosed),
837         mbPlaneNormalValid(rToBeCopied.mbPlaneNormalValid)
838     {
839         // complete initialization using copy
840         if(rToBeCopied.mpBColors && rToBeCopied.mpBColors->isUsed())
841         {
842             mpBColors = new BColorArray(*rToBeCopied.mpBColors);
843         }
844 
845         if(rToBeCopied.mpNormals && rToBeCopied.mpNormals->isUsed())
846         {
847             mpNormals = new NormalsArray3D(*rToBeCopied.mpNormals);
848         }
849 
850         if(rToBeCopied.mpTextureCoordiantes && rToBeCopied.mpTextureCoordiantes->isUsed())
851         {
852             mpTextureCoordiantes = new TextureCoordinate2D(*rToBeCopied.mpTextureCoordiantes);
853         }
854     }
855 
856     ImplB3DPolygon(const ImplB3DPolygon& rToBeCopied, sal_uInt32 nIndex, sal_uInt32 nCount)
857     :   maPoints(rToBeCopied.maPoints, nIndex, nCount),
858         mpBColors(0L),
859         mpNormals(0L),
860         mpTextureCoordiantes(0L),
861         maPlaneNormal(::basegfx::B3DVector::getEmptyVector()),
862         mbIsClosed(rToBeCopied.mbIsClosed),
863         mbPlaneNormalValid(false)
864     {
865         // complete initialization using partly copy
866         if(rToBeCopied.mpBColors && rToBeCopied.mpBColors->isUsed())
867         {
868             mpBColors = new BColorArray(*rToBeCopied.mpBColors, nIndex, nCount);
869 
870             if(!mpBColors->isUsed())
871             {
872                 delete mpBColors;
873                 mpBColors = 0L;
874             }
875         }
876 
877         if(rToBeCopied.mpNormals && rToBeCopied.mpNormals->isUsed())
878         {
879             mpNormals = new NormalsArray3D(*rToBeCopied.mpNormals, nIndex, nCount);
880 
881             if(!mpNormals->isUsed())
882             {
883                 delete mpNormals;
884                 mpNormals = 0L;
885             }
886         }
887 
888         if(rToBeCopied.mpTextureCoordiantes && rToBeCopied.mpTextureCoordiantes->isUsed())
889         {
890             mpTextureCoordiantes = new TextureCoordinate2D(*rToBeCopied.mpTextureCoordiantes, nIndex, nCount);
891 
892             if(!mpTextureCoordiantes->isUsed())
893             {
894                 delete mpTextureCoordiantes;
895                 mpTextureCoordiantes = 0L;
896             }
897         }
898     }
899 
900     ~ImplB3DPolygon()
901     {
902         if(mpBColors)
903         {
904             delete mpBColors;
905             mpBColors = 0L;
906         }
907 
908         if(mpNormals)
909         {
910             delete mpNormals;
911             mpNormals = 0L;
912         }
913 
914         if(mpTextureCoordiantes)
915         {
916             delete mpTextureCoordiantes;
917             mpTextureCoordiantes = 0L;
918         }
919     }
920 
921     sal_uInt32 count() const
922     {
923         return maPoints.count();
924     }
925 
926     bool isClosed() const
927     {
928         return mbIsClosed;
929     }
930 
931     void setClosed(bool bNew)
932     {
933         if(bNew != (bool)mbIsClosed)
934         {
935             mbIsClosed = bNew;
936         }
937     }
938 
939     inline bool impBColorsAreEqual(const ImplB3DPolygon& rCandidate) const
940     {
941         bool bBColorsAreEqual(true);
942 
943         if(mpBColors)
944         {
945             if(rCandidate.mpBColors)
946             {
947                 bBColorsAreEqual = (*mpBColors == *rCandidate.mpBColors);
948             }
949             else
950             {
951                 // candidate has no BColors, so it's assumed all unused.
952                 bBColorsAreEqual = !mpBColors->isUsed();
953             }
954         }
955         else
956         {
957             if(rCandidate.mpBColors)
958             {
959                 // we have no TextureCoordiantes, so it's assumed all unused.
960                 bBColorsAreEqual = !rCandidate.mpBColors->isUsed();
961             }
962         }
963 
964         return bBColorsAreEqual;
965     }
966 
967     inline bool impNormalsAreEqual(const ImplB3DPolygon& rCandidate) const
968     {
969         bool bNormalsAreEqual(true);
970 
971         if(mpNormals)
972         {
973             if(rCandidate.mpNormals)
974             {
975                 bNormalsAreEqual = (*mpNormals == *rCandidate.mpNormals);
976             }
977             else
978             {
979                 // candidate has no normals, so it's assumed all unused.
980                 bNormalsAreEqual = !mpNormals->isUsed();
981             }
982         }
983         else
984         {
985             if(rCandidate.mpNormals)
986             {
987                 // we have no normals, so it's assumed all unused.
988                 bNormalsAreEqual = !rCandidate.mpNormals->isUsed();
989             }
990         }
991 
992         return bNormalsAreEqual;
993     }
994 
995     inline bool impTextureCoordinatesAreEqual(const ImplB3DPolygon& rCandidate) const
996     {
997         bool bTextureCoordinatesAreEqual(true);
998 
999         if(mpTextureCoordiantes)
1000         {
1001             if(rCandidate.mpTextureCoordiantes)
1002             {
1003                 bTextureCoordinatesAreEqual = (*mpTextureCoordiantes == *rCandidate.mpTextureCoordiantes);
1004             }
1005             else
1006             {
1007                 // candidate has no TextureCoordinates, so it's assumed all unused.
1008                 bTextureCoordinatesAreEqual = !mpTextureCoordiantes->isUsed();
1009             }
1010         }
1011         else
1012         {
1013             if(rCandidate.mpTextureCoordiantes)
1014             {
1015                 // we have no TextureCoordiantes, so it's assumed all unused.
1016                 bTextureCoordinatesAreEqual = !rCandidate.mpTextureCoordiantes->isUsed();
1017             }
1018         }
1019 
1020         return bTextureCoordinatesAreEqual;
1021     }
1022 
1023     bool operator==(const ImplB3DPolygon& rCandidate) const
1024     {
1025         if(mbIsClosed == rCandidate.mbIsClosed)
1026         {
1027             if(maPoints == rCandidate.maPoints)
1028             {
1029                 if(impBColorsAreEqual(rCandidate))
1030                 {
1031                     if(impNormalsAreEqual(rCandidate))
1032                     {
1033                         if(impTextureCoordinatesAreEqual(rCandidate))
1034                         {
1035                             return true;
1036                         }
1037                     }
1038                 }
1039             }
1040         }
1041 
1042         return false;
1043     }
1044 
1045     const ::basegfx::B3DPoint& getPoint(sal_uInt32 nIndex) const
1046     {
1047         return maPoints.getCoordinate(nIndex);
1048     }
1049 
1050     void setPoint(sal_uInt32 nIndex, const ::basegfx::B3DPoint& rValue)
1051     {
1052         maPoints.setCoordinate(nIndex, rValue);
1053         invalidatePlaneNormal();
1054     }
1055 
1056     void insert(sal_uInt32 nIndex, const ::basegfx::B3DPoint& rPoint, sal_uInt32 nCount)
1057     {
1058         if(nCount)
1059         {
1060             CoordinateData3D aCoordinate(rPoint);
1061             maPoints.insert(nIndex, aCoordinate, nCount);
1062             invalidatePlaneNormal();
1063 
1064             if(mpBColors)
1065             {
1066                 mpBColors->insert(nIndex, ::basegfx::BColor::getEmptyBColor(), nCount);
1067             }
1068 
1069             if(mpNormals)
1070             {
1071                 mpNormals->insert(nIndex, ::basegfx::B3DVector::getEmptyVector(), nCount);
1072             }
1073 
1074             if(mpTextureCoordiantes)
1075             {
1076                 mpTextureCoordiantes->insert(nIndex, ::basegfx::B2DPoint::getEmptyPoint(), nCount);
1077             }
1078         }
1079     }
1080 
1081     const ::basegfx::BColor& getBColor(sal_uInt32 nIndex) const
1082     {
1083         if(mpBColors)
1084         {
1085             return mpBColors->getBColor(nIndex);
1086         }
1087         else
1088         {
1089             return ::basegfx::BColor::getEmptyBColor();
1090         }
1091     }
1092 
1093     void setBColor(sal_uInt32 nIndex, const ::basegfx::BColor& rValue)
1094     {
1095         if(!mpBColors)
1096         {
1097             if(!rValue.equalZero())
1098             {
1099                 mpBColors = new BColorArray(maPoints.count());
1100                 mpBColors->setBColor(nIndex, rValue);
1101             }
1102         }
1103         else
1104         {
1105             mpBColors->setBColor(nIndex, rValue);
1106 
1107             if(!mpBColors->isUsed())
1108             {
1109                 delete mpBColors;
1110                 mpBColors = 0L;
1111             }
1112         }
1113     }
1114 
1115     bool areBColorsUsed() const
1116     {
1117         return (mpBColors && mpBColors->isUsed());
1118     }
1119 
1120     void clearBColors()
1121     {
1122         if(mpBColors)
1123         {
1124             delete mpBColors;
1125             mpBColors = 0L;
1126         }
1127     }
1128 
1129     const ::basegfx::B3DVector& getNormal() const
1130     {
1131         if(!mbPlaneNormalValid)
1132         {
1133             const_cast< ImplB3DPolygon* >(this)->maPlaneNormal = maPoints.getNormal();
1134             const_cast< ImplB3DPolygon* >(this)->mbPlaneNormalValid = true;
1135         }
1136 
1137         return maPlaneNormal;
1138     }
1139 
1140     const ::basegfx::B3DVector& getNormal(sal_uInt32 nIndex) const
1141     {
1142         if(mpNormals)
1143         {
1144             return mpNormals->getNormal(nIndex);
1145         }
1146         else
1147         {
1148             return ::basegfx::B3DVector::getEmptyVector();
1149         }
1150     }
1151 
1152     void setNormal(sal_uInt32 nIndex, const ::basegfx::B3DVector& rValue)
1153     {
1154         if(!mpNormals)
1155         {
1156             if(!rValue.equalZero())
1157             {
1158                 mpNormals = new NormalsArray3D(maPoints.count());
1159                 mpNormals->setNormal(nIndex, rValue);
1160             }
1161         }
1162         else
1163         {
1164             mpNormals->setNormal(nIndex, rValue);
1165 
1166             if(!mpNormals->isUsed())
1167             {
1168                 delete mpNormals;
1169                 mpNormals = 0L;
1170             }
1171         }
1172     }
1173 
1174     void transformNormals(const ::basegfx::B3DHomMatrix& rMatrix)
1175     {
1176         if(mpNormals)
1177         {
1178             mpNormals->transform(rMatrix);
1179         }
1180     }
1181 
1182     bool areNormalsUsed() const
1183     {
1184         return (mpNormals && mpNormals->isUsed());
1185     }
1186 
1187     void clearNormals()
1188     {
1189         if(mpNormals)
1190         {
1191             delete mpNormals;
1192             mpNormals = 0L;
1193         }
1194     }
1195 
1196     const ::basegfx::B2DPoint& getTextureCoordinate(sal_uInt32 nIndex) const
1197     {
1198         if(mpTextureCoordiantes)
1199         {
1200             return mpTextureCoordiantes->getTextureCoordinate(nIndex);
1201         }
1202         else
1203         {
1204             return ::basegfx::B2DPoint::getEmptyPoint();
1205         }
1206     }
1207 
1208     void setTextureCoordinate(sal_uInt32 nIndex, const ::basegfx::B2DPoint& rValue)
1209     {
1210         if(!mpTextureCoordiantes)
1211         {
1212             if(!rValue.equalZero())
1213             {
1214                 mpTextureCoordiantes = new TextureCoordinate2D(maPoints.count());
1215                 mpTextureCoordiantes->setTextureCoordinate(nIndex, rValue);
1216             }
1217         }
1218         else
1219         {
1220             mpTextureCoordiantes->setTextureCoordinate(nIndex, rValue);
1221 
1222             if(!mpTextureCoordiantes->isUsed())
1223             {
1224                 delete mpTextureCoordiantes;
1225                 mpTextureCoordiantes = 0L;
1226             }
1227         }
1228     }
1229 
1230     bool areTextureCoordinatesUsed() const
1231     {
1232         return (mpTextureCoordiantes && mpTextureCoordiantes->isUsed());
1233     }
1234 
1235     void clearTextureCoordinates()
1236     {
1237         if(mpTextureCoordiantes)
1238         {
1239             delete mpTextureCoordiantes;
1240             mpTextureCoordiantes = 0L;
1241         }
1242     }
1243 
1244     void transformTextureCoordinates(const ::basegfx::B2DHomMatrix& rMatrix)
1245     {
1246         if(mpTextureCoordiantes)
1247         {
1248             mpTextureCoordiantes->transform(rMatrix);
1249         }
1250     }
1251 
1252     void insert(sal_uInt32 nIndex, const ImplB3DPolygon& rSource)
1253     {
1254         const sal_uInt32 nCount(rSource.maPoints.count());
1255 
1256         if(nCount)
1257         {
1258             maPoints.insert(nIndex, rSource.maPoints);
1259             invalidatePlaneNormal();
1260 
1261             if(rSource.mpBColors && rSource.mpBColors->isUsed())
1262             {
1263                 if(!mpBColors)
1264                 {
1265                     mpBColors = new BColorArray(maPoints.count());
1266                 }
1267 
1268                 mpBColors->insert(nIndex, *rSource.mpBColors);
1269             }
1270             else
1271             {
1272                 if(mpBColors)
1273                 {
1274                     mpBColors->insert(nIndex, ::basegfx::BColor::getEmptyBColor(), nCount);
1275                 }
1276             }
1277 
1278             if(rSource.mpNormals && rSource.mpNormals->isUsed())
1279             {
1280                 if(!mpNormals)
1281                 {
1282                     mpNormals = new NormalsArray3D(maPoints.count());
1283                 }
1284 
1285                 mpNormals->insert(nIndex, *rSource.mpNormals);
1286             }
1287             else
1288             {
1289                 if(mpNormals)
1290                 {
1291                     mpNormals->insert(nIndex, ::basegfx::B3DVector::getEmptyVector(), nCount);
1292                 }
1293             }
1294 
1295             if(rSource.mpTextureCoordiantes && rSource.mpTextureCoordiantes->isUsed())
1296             {
1297                 if(!mpTextureCoordiantes)
1298                 {
1299                     mpTextureCoordiantes = new TextureCoordinate2D(maPoints.count());
1300                 }
1301 
1302                 mpTextureCoordiantes->insert(nIndex, *rSource.mpTextureCoordiantes);
1303             }
1304             else
1305             {
1306                 if(mpTextureCoordiantes)
1307                 {
1308                     mpTextureCoordiantes->insert(nIndex, ::basegfx::B2DPoint::getEmptyPoint(), nCount);
1309                 }
1310             }
1311         }
1312     }
1313 
1314     void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
1315     {
1316         if(nCount)
1317         {
1318             maPoints.remove(nIndex, nCount);
1319             invalidatePlaneNormal();
1320 
1321             if(mpBColors)
1322             {
1323                 mpBColors->remove(nIndex, nCount);
1324 
1325                 if(!mpBColors->isUsed())
1326                 {
1327                     delete mpBColors;
1328                     mpBColors = 0L;
1329                 }
1330             }
1331 
1332             if(mpNormals)
1333             {
1334                 mpNormals->remove(nIndex, nCount);
1335 
1336                 if(!mpNormals->isUsed())
1337                 {
1338                     delete mpNormals;
1339                     mpNormals = 0L;
1340                 }
1341             }
1342 
1343             if(mpTextureCoordiantes)
1344             {
1345                 mpTextureCoordiantes->remove(nIndex, nCount);
1346 
1347                 if(!mpTextureCoordiantes->isUsed())
1348                 {
1349                     delete mpTextureCoordiantes;
1350                     mpTextureCoordiantes = 0L;
1351                 }
1352             }
1353         }
1354     }
1355 
1356     void flip()
1357     {
1358         if(maPoints.count() > 1)
1359         {
1360             maPoints.flip();
1361 
1362             if(mbPlaneNormalValid)
1363             {
1364                 // mirror plane normal
1365                 maPlaneNormal = -maPlaneNormal;
1366             }
1367 
1368             if(mpBColors)
1369             {
1370                 mpBColors->flip();
1371             }
1372 
1373             if(mpNormals)
1374             {
1375                 mpNormals->flip();
1376             }
1377 
1378             if(mpTextureCoordiantes)
1379             {
1380                 mpTextureCoordiantes->flip();
1381             }
1382         }
1383     }
1384 
1385     bool hasDoublePoints() const
1386     {
1387         if(mbIsClosed)
1388         {
1389             // check for same start and end point
1390             const sal_uInt32 nIndex(maPoints.count() - 1L);
1391 
1392             if(maPoints.getCoordinate(0L) == maPoints.getCoordinate(nIndex))
1393             {
1394                 const bool bBColorEqual(!mpBColors || (mpBColors->getBColor(0L) == mpBColors->getBColor(nIndex)));
1395 
1396                 if(bBColorEqual)
1397                 {
1398                     const bool bNormalsEqual(!mpNormals || (mpNormals->getNormal(0L) == mpNormals->getNormal(nIndex)));
1399 
1400                     if(bNormalsEqual)
1401                     {
1402                         const bool bTextureCoordinatesEqual(!mpTextureCoordiantes || (mpTextureCoordiantes->getTextureCoordinate(0L) == mpTextureCoordiantes->getTextureCoordinate(nIndex)));
1403 
1404                         if(bTextureCoordinatesEqual)
1405                         {
1406                             return true;
1407                         }
1408                     }
1409                 }
1410             }
1411         }
1412 
1413         // test for range
1414         for(sal_uInt32 a(0L); a < maPoints.count() - 1L; a++)
1415         {
1416             if(maPoints.getCoordinate(a) == maPoints.getCoordinate(a + 1L))
1417             {
1418                 const bool bBColorEqual(!mpBColors || (mpBColors->getBColor(a) == mpBColors->getBColor(a + 1L)));
1419 
1420                 if(bBColorEqual)
1421                 {
1422                     const bool bNormalsEqual(!mpNormals || (mpNormals->getNormal(a) == mpNormals->getNormal(a + 1L)));
1423 
1424                     if(bNormalsEqual)
1425                     {
1426                         const bool bTextureCoordinatesEqual(!mpTextureCoordiantes || (mpTextureCoordiantes->getTextureCoordinate(a) == mpTextureCoordiantes->getTextureCoordinate(a + 1L)));
1427 
1428                         if(bTextureCoordinatesEqual)
1429                         {
1430                             return true;
1431                         }
1432                     }
1433                 }
1434             }
1435         }
1436 
1437         return false;
1438     }
1439 
1440     void removeDoublePointsAtBeginEnd()
1441     {
1442         // Only remove DoublePoints at Begin and End when poly is closed
1443         if(mbIsClosed)
1444         {
1445             bool bRemove;
1446 
1447             do
1448             {
1449                 bRemove = false;
1450 
1451                 if(maPoints.count() > 1L)
1452                 {
1453                     const sal_uInt32 nIndex(maPoints.count() - 1L);
1454                     bRemove = (maPoints.getCoordinate(0L) == maPoints.getCoordinate(nIndex));
1455 
1456                     if(bRemove && mpBColors && !(mpBColors->getBColor(0L) == mpBColors->getBColor(nIndex)))
1457                     {
1458                         bRemove = false;
1459                     }
1460 
1461                     if(bRemove && mpNormals && !(mpNormals->getNormal(0L) == mpNormals->getNormal(nIndex)))
1462                     {
1463                         bRemove = false;
1464                     }
1465 
1466                     if(bRemove && mpTextureCoordiantes && !(mpTextureCoordiantes->getTextureCoordinate(0L) == mpTextureCoordiantes->getTextureCoordinate(nIndex)))
1467                     {
1468                         bRemove = false;
1469                     }
1470                 }
1471 
1472                 if(bRemove)
1473                 {
1474                     const sal_uInt32 nIndex(maPoints.count() - 1L);
1475                     remove(nIndex, 1L);
1476                 }
1477             } while(bRemove);
1478         }
1479     }
1480 
1481     void removeDoublePointsWholeTrack()
1482     {
1483         sal_uInt32 nIndex(0L);
1484 
1485         // test as long as there are at least two points and as long as the index
1486         // is smaller or equal second last point
1487         while((maPoints.count() > 1L) && (nIndex <= maPoints.count() - 2L))
1488         {
1489             const sal_uInt32 nNextIndex(nIndex + 1L);
1490             bool bRemove(maPoints.getCoordinate(nIndex) == maPoints.getCoordinate(nNextIndex));
1491 
1492             if(bRemove && mpBColors && !(mpBColors->getBColor(nIndex) == mpBColors->getBColor(nNextIndex)))
1493             {
1494                 bRemove = false;
1495             }
1496 
1497             if(bRemove && mpNormals && !(mpNormals->getNormal(nIndex) == mpNormals->getNormal(nNextIndex)))
1498             {
1499                 bRemove = false;
1500             }
1501 
1502             if(bRemove && mpTextureCoordiantes && !(mpTextureCoordiantes->getTextureCoordinate(nIndex) == mpTextureCoordiantes->getTextureCoordinate(nNextIndex)))
1503             {
1504                 bRemove = false;
1505             }
1506 
1507             if(bRemove)
1508             {
1509                 // if next is same as index and the control vectors are unused, delete index
1510                 remove(nIndex, 1L);
1511             }
1512             else
1513             {
1514                 // if different, step forward
1515                 nIndex++;
1516             }
1517         }
1518     }
1519 
1520     void transform(const ::basegfx::B3DHomMatrix& rMatrix)
1521     {
1522         maPoints.transform(rMatrix);
1523 
1524         // Here, it seems to be possible to transform a valid plane normal and to avoid
1525         // invalidation, but it's not true. If the transformation contains shears or e.g.
1526         // perspective projection, the orthogonality to the transformed plane will not
1527         // be preserved. It may be possible to test that at the matrix to not invalidate in
1528         // all cases or to extract a matrix which does not 'shear' the vector which is
1529         // a normal in this case. As long as this is not sure, i will just invalidate.
1530         invalidatePlaneNormal();
1531     }
1532 };
1533 
1534 //////////////////////////////////////////////////////////////////////////////
1535 
1536 namespace basegfx
1537 {
1538     namespace { struct DefaultPolygon : public rtl::Static< B3DPolygon::ImplType,
1539                                                             DefaultPolygon > {}; }
1540 
1541     B3DPolygon::B3DPolygon() :
1542         mpPolygon(DefaultPolygon::get())
1543     {
1544     }
1545 
1546     B3DPolygon::B3DPolygon(const B3DPolygon& rPolygon) :
1547         mpPolygon(rPolygon.mpPolygon)
1548     {
1549     }
1550 
1551     B3DPolygon::B3DPolygon(const B3DPolygon& rPolygon, sal_uInt32 nIndex, sal_uInt32 nCount) :
1552         mpPolygon(ImplB3DPolygon(*rPolygon.mpPolygon, nIndex, nCount))
1553     {
1554         // TODO(P2): one extra temporary here (cow_wrapper copies
1555         // given ImplB3DPolygon into its internal impl_t wrapper type)
1556         OSL_ENSURE(nIndex + nCount > rPolygon.mpPolygon->count(), "B3DPolygon constructor outside range (!)");
1557     }
1558 
1559     B3DPolygon::~B3DPolygon()
1560     {
1561     }
1562 
1563     B3DPolygon& B3DPolygon::operator=(const B3DPolygon& rPolygon)
1564     {
1565         mpPolygon = rPolygon.mpPolygon;
1566         return *this;
1567     }
1568 
1569     void B3DPolygon::makeUnique()
1570     {
1571         mpPolygon.make_unique();
1572     }
1573 
1574     bool B3DPolygon::operator==(const B3DPolygon& rPolygon) const
1575     {
1576         if(mpPolygon.same_object(rPolygon.mpPolygon))
1577             return true;
1578 
1579         return (*mpPolygon == *rPolygon.mpPolygon);
1580     }
1581 
1582     bool B3DPolygon::operator!=(const B3DPolygon& rPolygon) const
1583     {
1584         return !(*this == rPolygon);
1585     }
1586 
1587     sal_uInt32 B3DPolygon::count() const
1588     {
1589         return mpPolygon->count();
1590     }
1591 
1592     basegfx::B3DPoint B3DPolygon::getB3DPoint(sal_uInt32 nIndex) const
1593     {
1594         OSL_ENSURE(nIndex < mpPolygon->count(), "B3DPolygon access outside range (!)");
1595 
1596         return mpPolygon->getPoint(nIndex);
1597     }
1598 
1599     void B3DPolygon::setB3DPoint(sal_uInt32 nIndex, const basegfx::B3DPoint& rValue)
1600     {
1601         OSL_ENSURE(nIndex < mpPolygon->count(), "B3DPolygon access outside range (!)");
1602 
1603         if(getB3DPoint(nIndex) != rValue)
1604             mpPolygon->setPoint(nIndex, rValue);
1605     }
1606 
1607     BColor B3DPolygon::getBColor(sal_uInt32 nIndex) const
1608     {
1609         OSL_ENSURE(nIndex < mpPolygon->count(), "B3DPolygon access outside range (!)");
1610 
1611         return mpPolygon->getBColor(nIndex);
1612     }
1613 
1614     void B3DPolygon::setBColor(sal_uInt32 nIndex, const BColor& rValue)
1615     {
1616         OSL_ENSURE(nIndex < mpPolygon->count(), "B3DPolygon access outside range (!)");
1617 
1618         if(mpPolygon->getBColor(nIndex) != rValue)
1619             mpPolygon->setBColor(nIndex, rValue);
1620     }
1621 
1622     bool B3DPolygon::areBColorsUsed() const
1623     {
1624         return mpPolygon->areBColorsUsed();
1625     }
1626 
1627     void B3DPolygon::clearBColors()
1628     {
1629         if(mpPolygon->areBColorsUsed())
1630             mpPolygon->clearBColors();
1631     }
1632 
1633     B3DVector B3DPolygon::getNormal() const
1634     {
1635         return mpPolygon->getNormal();
1636     }
1637 
1638     B3DVector B3DPolygon::getNormal(sal_uInt32 nIndex) const
1639     {
1640         OSL_ENSURE(nIndex < mpPolygon->count(), "B3DPolygon access outside range (!)");
1641 
1642         return mpPolygon->getNormal(nIndex);
1643     }
1644 
1645     void B3DPolygon::setNormal(sal_uInt32 nIndex, const B3DVector& rValue)
1646     {
1647         OSL_ENSURE(nIndex < mpPolygon->count(), "B3DPolygon access outside range (!)");
1648 
1649         if(mpPolygon->getNormal(nIndex) != rValue)
1650             mpPolygon->setNormal(nIndex, rValue);
1651     }
1652 
1653     void B3DPolygon::transformNormals(const B3DHomMatrix& rMatrix)
1654     {
1655         if(mpPolygon->areNormalsUsed() && !rMatrix.isIdentity())
1656             mpPolygon->transformNormals(rMatrix);
1657     }
1658 
1659     bool B3DPolygon::areNormalsUsed() const
1660     {
1661         return mpPolygon->areNormalsUsed();
1662     }
1663 
1664     void B3DPolygon::clearNormals()
1665     {
1666         if(mpPolygon->areNormalsUsed())
1667             mpPolygon->clearNormals();
1668     }
1669 
1670     B2DPoint B3DPolygon::getTextureCoordinate(sal_uInt32 nIndex) const
1671     {
1672         OSL_ENSURE(nIndex < mpPolygon->count(), "B3DPolygon access outside range (!)");
1673 
1674         return mpPolygon->getTextureCoordinate(nIndex);
1675     }
1676 
1677     void B3DPolygon::setTextureCoordinate(sal_uInt32 nIndex, const B2DPoint& rValue)
1678     {
1679         OSL_ENSURE(nIndex < mpPolygon->count(), "B3DPolygon access outside range (!)");
1680 
1681         if(mpPolygon->getTextureCoordinate(nIndex) != rValue)
1682             mpPolygon->setTextureCoordinate(nIndex, rValue);
1683     }
1684 
1685     void B3DPolygon::transformTextureCoordiantes(const B2DHomMatrix& rMatrix)
1686     {
1687         if(mpPolygon->areTextureCoordinatesUsed() && !rMatrix.isIdentity())
1688             mpPolygon->transformTextureCoordinates(rMatrix);
1689     }
1690 
1691     bool B3DPolygon::areTextureCoordinatesUsed() const
1692     {
1693         return mpPolygon->areTextureCoordinatesUsed();
1694     }
1695 
1696     void B3DPolygon::clearTextureCoordinates()
1697     {
1698         if(mpPolygon->areTextureCoordinatesUsed())
1699             mpPolygon->clearTextureCoordinates();
1700     }
1701 
1702     void B3DPolygon::insert(sal_uInt32 nIndex, const ::basegfx::B3DPoint& rPoint, sal_uInt32 nCount)
1703     {
1704         OSL_ENSURE(nIndex <= mpPolygon->count(), "B3DPolygon Insert outside range (!)");
1705 
1706         if(nCount)
1707             mpPolygon->insert(nIndex, rPoint, nCount);
1708     }
1709 
1710     void B3DPolygon::append(const basegfx::B3DPoint& rPoint, sal_uInt32 nCount)
1711     {
1712         if(nCount)
1713             mpPolygon->insert(mpPolygon->count(), rPoint, nCount);
1714     }
1715 
1716     void B3DPolygon::insert(sal_uInt32 nIndex, const B3DPolygon& rPoly, sal_uInt32 nIndex2, sal_uInt32 nCount)
1717     {
1718         OSL_ENSURE(nIndex <= mpPolygon->count(), "B3DPolygon Insert outside range (!)");
1719 
1720         if(rPoly.count())
1721         {
1722             if(!nCount)
1723             {
1724                 nCount = rPoly.count();
1725             }
1726 
1727             if(0L == nIndex2 && nCount == rPoly.count())
1728             {
1729                 mpPolygon->insert(nIndex, *rPoly.mpPolygon);
1730             }
1731             else
1732             {
1733                 OSL_ENSURE(nIndex2 + nCount <= rPoly.mpPolygon->count(), "B3DPolygon Insert outside range (!)");
1734                 ImplB3DPolygon aTempPoly(*rPoly.mpPolygon, nIndex2, nCount);
1735                 mpPolygon->insert(nIndex, aTempPoly);
1736             }
1737         }
1738     }
1739 
1740     void B3DPolygon::append(const B3DPolygon& rPoly, sal_uInt32 nIndex, sal_uInt32 nCount)
1741     {
1742         if(rPoly.count())
1743         {
1744             if(!nCount)
1745             {
1746                 nCount = rPoly.count();
1747             }
1748 
1749             if(0L == nIndex && nCount == rPoly.count())
1750             {
1751                 mpPolygon->insert(mpPolygon->count(), *rPoly.mpPolygon);
1752             }
1753             else
1754             {
1755                 OSL_ENSURE(nIndex + nCount <= rPoly.mpPolygon->count(), "B3DPolygon Append outside range (!)");
1756                 ImplB3DPolygon aTempPoly(*rPoly.mpPolygon, nIndex, nCount);
1757                 mpPolygon->insert(mpPolygon->count(), aTempPoly);
1758             }
1759         }
1760     }
1761 
1762     void B3DPolygon::remove(sal_uInt32 nIndex, sal_uInt32 nCount)
1763     {
1764         OSL_ENSURE(nIndex + nCount <= mpPolygon->count(), "B3DPolygon Remove outside range (!)");
1765 
1766         if(nCount)
1767             mpPolygon->remove(nIndex, nCount);
1768     }
1769 
1770     void B3DPolygon::clear()
1771     {
1772         mpPolygon = DefaultPolygon::get();
1773     }
1774 
1775     bool B3DPolygon::isClosed() const
1776     {
1777         return mpPolygon->isClosed();
1778     }
1779 
1780     void B3DPolygon::setClosed(bool bNew)
1781     {
1782         if(isClosed() != bNew)
1783             mpPolygon->setClosed(bNew);
1784     }
1785 
1786     void B3DPolygon::flip()
1787     {
1788         if(count() > 1)
1789             mpPolygon->flip();
1790     }
1791 
1792     bool B3DPolygon::hasDoublePoints() const
1793     {
1794         return (mpPolygon->count() > 1L && mpPolygon->hasDoublePoints());
1795     }
1796 
1797     void B3DPolygon::removeDoublePoints()
1798     {
1799         if(hasDoublePoints())
1800         {
1801             mpPolygon->removeDoublePointsAtBeginEnd();
1802             mpPolygon->removeDoublePointsWholeTrack();
1803         }
1804     }
1805 
1806     void B3DPolygon::transform(const basegfx::B3DHomMatrix& rMatrix)
1807     {
1808         if(mpPolygon->count() && !rMatrix.isIdentity())
1809         {
1810             mpPolygon->transform(rMatrix);
1811         }
1812     }
1813 } // end of namespace basegfx
1814 
1815 //////////////////////////////////////////////////////////////////////////////
1816 // eof
1817