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