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