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/b2dpolygon.hxx>
32 #include <basegfx/point/b2dpoint.hxx>
33 #include <basegfx/vector/b2dvector.hxx>
34 #include <basegfx/matrix/b2dhommatrix.hxx>
35 #include <basegfx/curve/b2dcubicbezier.hxx>
36 #include <rtl/instance.hxx>
37 #include <basegfx/polygon/b2dpolygontools.hxx>
38 #include <boost/scoped_ptr.hpp>
39 #include <vector>
40 #include <algorithm>
41 
42 //////////////////////////////////////////////////////////////////////////////
43 
44 struct CoordinateData2D : public basegfx::B2DPoint
45 {
46 public:
47     CoordinateData2D() {}
48 
49 	explicit CoordinateData2D(const basegfx::B2DPoint& rData)
50     :	B2DPoint(rData)
51 	{}
52 
53     CoordinateData2D& operator=(const basegfx::B2DPoint& rData)
54     {
55         B2DPoint::operator=(rData);
56         return *this;
57 	}
58 
59 	void transform(const basegfx::B2DHomMatrix& rMatrix)
60 	{
61         *this *= rMatrix;
62 	}
63 };
64 
65 //////////////////////////////////////////////////////////////////////////////
66 
67 class CoordinateDataArray2D
68 {
69 	typedef ::std::vector< CoordinateData2D > CoordinateData2DVector;
70 
71 	CoordinateData2DVector							maVector;
72 
73 public:
74 	explicit CoordinateDataArray2D(sal_uInt32 nCount)
75 	:	maVector(nCount)
76 	{
77 	}
78 
79 	explicit CoordinateDataArray2D(const CoordinateDataArray2D& rOriginal)
80 	:	maVector(rOriginal.maVector)
81 	{
82 	}
83 
84 	CoordinateDataArray2D(const CoordinateDataArray2D& rOriginal, sal_uInt32 nIndex, sal_uInt32 nCount)
85 	:	maVector(rOriginal.maVector.begin() + nIndex, rOriginal.maVector.begin() + (nIndex + nCount))
86 	{
87 	}
88 
89 	sal_uInt32 count() const
90 	{
91 		return maVector.size();
92 	}
93 
94 	bool operator==(const CoordinateDataArray2D& rCandidate) const
95 	{
96 		return (maVector == rCandidate.maVector);
97 	}
98 
99 	const basegfx::B2DPoint& getCoordinate(sal_uInt32 nIndex) const
100 	{
101         return maVector[nIndex];
102 	}
103 
104 	void setCoordinate(sal_uInt32 nIndex, const basegfx::B2DPoint& rValue)
105 	{
106         maVector[nIndex] = rValue;
107 	}
108 
109 	void reserve(sal_uInt32 nCount)
110 	{
111 		maVector.reserve(nCount);
112 	}
113 
114 	void append(const CoordinateData2D& rValue)
115 	{
116 		maVector.push_back(rValue);
117 	}
118 
119 	void insert(sal_uInt32 nIndex, const CoordinateData2D& rValue, sal_uInt32 nCount)
120 	{
121 		if(nCount)
122 		{
123 			// add nCount copies of rValue
124 			CoordinateData2DVector::iterator aIndex(maVector.begin());
125 			aIndex += nIndex;
126 			maVector.insert(aIndex, nCount, rValue);
127 		}
128 	}
129 
130 	void insert(sal_uInt32 nIndex, const CoordinateDataArray2D& rSource)
131 	{
132 		const sal_uInt32 nCount(rSource.maVector.size());
133 
134 		if(nCount)
135 		{
136 			// insert data
137 			CoordinateData2DVector::iterator aIndex(maVector.begin());
138 			aIndex += nIndex;
139 			CoordinateData2DVector::const_iterator aStart(rSource.maVector.begin());
140 			CoordinateData2DVector::const_iterator aEnd(rSource.maVector.end());
141 			maVector.insert(aIndex, aStart, aEnd);
142 		}
143 	}
144 
145 	void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
146 	{
147 		if(nCount)
148 		{
149 			// remove point data
150 			CoordinateData2DVector::iterator aStart(maVector.begin());
151 			aStart += nIndex;
152 			const CoordinateData2DVector::iterator aEnd(aStart + nCount);
153 			maVector.erase(aStart, aEnd);
154 		}
155 	}
156 
157 	void flip(bool bIsClosed)
158 	{
159 		if(maVector.size() > 1)
160 		{
161 			// to keep the same point at index 0, just flip all points except the
162 			// first one when closed
163 			const sal_uInt32 nHalfSize(bIsClosed ? (maVector.size() - 1) >> 1 : maVector.size() >> 1);
164 			CoordinateData2DVector::iterator aStart(bIsClosed ? maVector.begin() + 1 : maVector.begin());
165 			CoordinateData2DVector::iterator aEnd(maVector.end() - 1);
166 
167 			for(sal_uInt32 a(0); a < nHalfSize; a++)
168 			{
169 				::std::swap(*aStart, *aEnd);
170 				aStart++;
171 				aEnd--;
172 			}
173 		}
174 	}
175 
176 	void removeDoublePointsAtBeginEnd()
177 	{
178 		// remove from end as long as there are at least two points
179 		// and begin/end are equal
180 		while((maVector.size() > 1) && (maVector[0] == maVector[maVector.size() - 1]))
181 		{
182 			maVector.pop_back();
183 		}
184 	}
185 
186 	void removeDoublePointsWholeTrack()
187 	{
188 		sal_uInt32 nIndex(0);
189 
190 		// test as long as there are at least two points and as long as the index
191 		// is smaller or equal second last point
192 		while((maVector.size() > 1) && (nIndex <= maVector.size() - 2))
193 		{
194 			if(maVector[nIndex] == maVector[nIndex + 1])
195 			{
196 				// if next is same as index, delete next
197 				maVector.erase(maVector.begin() + (nIndex + 1));
198 			}
199 			else
200 			{
201 				// if different, step forward
202 				nIndex++;
203 			}
204 		}
205 	}
206 
207 	void transform(const basegfx::B2DHomMatrix& rMatrix)
208 	{
209 		CoordinateData2DVector::iterator aStart(maVector.begin());
210 		CoordinateData2DVector::iterator aEnd(maVector.end());
211 
212 		for(; aStart != aEnd; aStart++)
213 		{
214 			aStart->transform(rMatrix);
215 		}
216 	}
217 
218     const basegfx::B2DPoint* begin() const
219     {
220         if(maVector.empty())
221             return 0;
222         else
223             return &maVector.front();
224     }
225 
226     const basegfx::B2DPoint* end() const
227     {
228         if(maVector.empty())
229             return 0;
230         else
231             return (&maVector.back())+1;
232     }
233 
234     basegfx::B2DPoint* begin()
235     {
236         if(maVector.empty())
237             return 0;
238         else
239             return &maVector.front();
240     }
241 
242     basegfx::B2DPoint* end()
243     {
244         if(maVector.empty())
245             return 0;
246         else
247             return (&maVector.back())+1;
248     }
249 };
250 
251 //////////////////////////////////////////////////////////////////////////////
252 
253 class ControlVectorPair2D
254 {
255 	basegfx::B2DVector							maPrevVector;
256 	basegfx::B2DVector							maNextVector;
257 
258 public:
259 	const basegfx::B2DVector& getPrevVector() const
260 	{
261 		return maPrevVector;
262 	}
263 
264 	void setPrevVector(const basegfx::B2DVector& rValue)
265 	{
266 		if(rValue != maPrevVector)
267 			maPrevVector = rValue;
268 	}
269 
270 	const basegfx::B2DVector& getNextVector() const
271 	{
272 		return maNextVector;
273 	}
274 
275 	void setNextVector(const basegfx::B2DVector& rValue)
276 	{
277 		if(rValue != maNextVector)
278 			maNextVector = rValue;
279 	}
280 
281 	bool operator==(const ControlVectorPair2D& rData) const
282 	{
283 		return (maPrevVector == rData.getPrevVector() && maNextVector == rData.getNextVector());
284 	}
285 
286 	void flip()
287 	{
288 		::std::swap(maPrevVector, maNextVector);
289 	}
290 };
291 
292 //////////////////////////////////////////////////////////////////////////////
293 
294 class ControlVectorArray2D
295 {
296 	typedef ::std::vector< ControlVectorPair2D > ControlVectorPair2DVector;
297 
298 	ControlVectorPair2DVector							maVector;
299 	sal_uInt32											mnUsedVectors;
300 
301 public:
302 	explicit ControlVectorArray2D(sal_uInt32 nCount)
303 	:	maVector(nCount),
304 		mnUsedVectors(0)
305 	{}
306 
307 	ControlVectorArray2D(const ControlVectorArray2D& rOriginal, sal_uInt32 nIndex, sal_uInt32 nCount)
308 	:	maVector(),
309 		mnUsedVectors(0)
310 	{
311 		ControlVectorPair2DVector::const_iterator aStart(rOriginal.maVector.begin());
312 		aStart += nIndex;
313 		ControlVectorPair2DVector::const_iterator aEnd(aStart);
314 		aEnd += nCount;
315 		maVector.reserve(nCount);
316 
317 		for(; aStart != aEnd; aStart++)
318 		{
319 			if(!aStart->getPrevVector().equalZero())
320 				mnUsedVectors++;
321 
322 			if(!aStart->getNextVector().equalZero())
323 				mnUsedVectors++;
324 
325 			maVector.push_back(*aStart);
326 		}
327 	}
328 
329 	sal_uInt32 count() const
330 	{
331 		return maVector.size();
332 	}
333 
334 	bool operator==(const ControlVectorArray2D& rCandidate) const
335 	{
336 		return (maVector == rCandidate.maVector);
337 	}
338 
339 	bool isUsed() const
340 	{
341 		return (0 != mnUsedVectors);
342 	}
343 
344 	const basegfx::B2DVector& getPrevVector(sal_uInt32 nIndex) const
345 	{
346 		return maVector[nIndex].getPrevVector();
347 	}
348 
349 	void setPrevVector(sal_uInt32 nIndex, const basegfx::B2DVector& rValue)
350 	{
351 		bool bWasUsed(mnUsedVectors && !maVector[nIndex].getPrevVector().equalZero());
352 		bool bIsUsed(!rValue.equalZero());
353 
354 		if(bWasUsed)
355 		{
356 			if(bIsUsed)
357 			{
358 				maVector[nIndex].setPrevVector(rValue);
359 			}
360 			else
361 			{
362 				maVector[nIndex].setPrevVector(basegfx::B2DVector::getEmptyVector());
363 				mnUsedVectors--;
364 			}
365 		}
366 		else
367 		{
368 			if(bIsUsed)
369 			{
370 				maVector[nIndex].setPrevVector(rValue);
371 				mnUsedVectors++;
372 			}
373 		}
374 	}
375 
376 	const basegfx::B2DVector& getNextVector(sal_uInt32 nIndex) const
377 	{
378 		return maVector[nIndex].getNextVector();
379 	}
380 
381 	void setNextVector(sal_uInt32 nIndex, const basegfx::B2DVector& rValue)
382 	{
383 		bool bWasUsed(mnUsedVectors && !maVector[nIndex].getNextVector().equalZero());
384 		bool bIsUsed(!rValue.equalZero());
385 
386 		if(bWasUsed)
387 		{
388 			if(bIsUsed)
389 			{
390 				maVector[nIndex].setNextVector(rValue);
391 			}
392 			else
393 			{
394 				maVector[nIndex].setNextVector(basegfx::B2DVector::getEmptyVector());
395 				mnUsedVectors--;
396 			}
397 		}
398 		else
399 		{
400 			if(bIsUsed)
401 			{
402 				maVector[nIndex].setNextVector(rValue);
403 				mnUsedVectors++;
404 			}
405 		}
406 	}
407 
408 	void append(const ControlVectorPair2D& rValue)
409 	{
410 		maVector.push_back(rValue);
411 
412 		if(!rValue.getPrevVector().equalZero())
413 			mnUsedVectors += 1;
414 
415 		if(!rValue.getNextVector().equalZero())
416 			mnUsedVectors += 1;
417 	}
418 
419 	void insert(sal_uInt32 nIndex, const ControlVectorPair2D& rValue, sal_uInt32 nCount)
420 	{
421 		if(nCount)
422 		{
423 			// add nCount copies of rValue
424 			ControlVectorPair2DVector::iterator aIndex(maVector.begin());
425 			aIndex += nIndex;
426 			maVector.insert(aIndex, nCount, rValue);
427 
428 			if(!rValue.getPrevVector().equalZero())
429 				mnUsedVectors += nCount;
430 
431 			if(!rValue.getNextVector().equalZero())
432 				mnUsedVectors += nCount;
433 		}
434 	}
435 
436 	void insert(sal_uInt32 nIndex, const ControlVectorArray2D& rSource)
437 	{
438 		const sal_uInt32 nCount(rSource.maVector.size());
439 
440 		if(nCount)
441 		{
442 			// insert data
443 			ControlVectorPair2DVector::iterator aIndex(maVector.begin());
444 			aIndex += nIndex;
445 			ControlVectorPair2DVector::const_iterator aStart(rSource.maVector.begin());
446 			ControlVectorPair2DVector::const_iterator aEnd(rSource.maVector.end());
447 			maVector.insert(aIndex, aStart, aEnd);
448 
449 			for(; aStart != aEnd; aStart++)
450 			{
451 				if(!aStart->getPrevVector().equalZero())
452 					mnUsedVectors++;
453 
454 				if(!aStart->getNextVector().equalZero())
455 					mnUsedVectors++;
456 			}
457 		}
458 	}
459 
460 	void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
461 	{
462 		if(nCount)
463 		{
464 			const ControlVectorPair2DVector::iterator aDeleteStart(maVector.begin() + nIndex);
465 			const ControlVectorPair2DVector::iterator aDeleteEnd(aDeleteStart + nCount);
466 			ControlVectorPair2DVector::const_iterator aStart(aDeleteStart);
467 
468 			for(; mnUsedVectors && aStart != aDeleteEnd; aStart++)
469 			{
470 				if(!aStart->getPrevVector().equalZero())
471 					mnUsedVectors--;
472 
473 				if(mnUsedVectors && !aStart->getNextVector().equalZero())
474 					mnUsedVectors--;
475 			}
476 
477 			// remove point data
478 			maVector.erase(aDeleteStart, aDeleteEnd);
479 		}
480 	}
481 
482 	void flip(bool bIsClosed)
483 	{
484 		if(maVector.size() > 1)
485 		{
486 			// to keep the same point at index 0, just flip all points except the
487 			// first one when closed
488 			const sal_uInt32 nHalfSize(bIsClosed ? (maVector.size() - 1) >> 1 : maVector.size() >> 1);
489 			ControlVectorPair2DVector::iterator aStart(bIsClosed ? maVector.begin() + 1 : maVector.begin());
490 			ControlVectorPair2DVector::iterator aEnd(maVector.end() - 1);
491 
492 			for(sal_uInt32 a(0); a < nHalfSize; a++)
493 			{
494 				// swap Prev and Next
495 				aStart->flip();
496 				aEnd->flip();
497 
498 				// swap entries
499 				::std::swap(*aStart, *aEnd);
500 
501 				aStart++;
502 				aEnd--;
503 			}
504 
505 			if(aStart == aEnd)
506 			{
507 				// swap Prev and Next at middle element (if exists)
508 				aStart->flip();
509 			}
510 
511 			if(bIsClosed)
512 			{
513 				// swap Prev and Next at start element
514 				maVector.begin()->flip();
515 			}
516 		}
517 	}
518 };
519 
520 //////////////////////////////////////////////////////////////////////////////
521 
522 class ImplBufferedData
523 {
524 private:
525 	// Possibility to hold the last subdivision
526 	boost::scoped_ptr< basegfx::B2DPolygon >		mpDefaultSubdivision;
527 
528     // Possibility to hold the last B2DRange calculation
529 	boost::scoped_ptr< basegfx::B2DRange >		    mpB2DRange;
530 
531 public:
532     ImplBufferedData()
533     :   mpDefaultSubdivision(),
534         mpB2DRange()
535     {}
536 
537     const basegfx::B2DPolygon& getDefaultAdaptiveSubdivision(const basegfx::B2DPolygon& rSource) const
538 	{
539 		if(!mpDefaultSubdivision)
540 		{
541 			const_cast< ImplBufferedData* >(this)->mpDefaultSubdivision.reset(new basegfx::B2DPolygon(basegfx::tools::adaptiveSubdivideByCount(rSource, 9)));
542 		}
543 
544         return *mpDefaultSubdivision;
545 	}
546 
547     const basegfx::B2DRange& getB2DRange(const basegfx::B2DPolygon& rSource) const
548     {
549 		if(!mpB2DRange)
550 		{
551 			basegfx::B2DRange aNewRange;
552 			const sal_uInt32 nPointCount(rSource.count());
553 
554 			if(nPointCount)
555 			{
556 				for(sal_uInt32 a(0); a < nPointCount; a++)
557 				{
558 					aNewRange.expand(rSource.getB2DPoint(a));
559 				}
560 
561 				if(rSource.areControlPointsUsed())
562 				{
563 					const sal_uInt32 nEdgeCount(rSource.isClosed() ? nPointCount : nPointCount - 1);
564 
565 					if(nEdgeCount)
566 					{
567 						basegfx::B2DCubicBezier aEdge;
568 						aEdge.setStartPoint(rSource.getB2DPoint(0));
569 
570 						for(sal_uInt32 b(0); b < nEdgeCount; b++)
571 						{
572 							const sal_uInt32 nNextIndex((b + 1) % nPointCount);
573 							aEdge.setControlPointA(rSource.getNextControlPoint(b));
574 							aEdge.setControlPointB(rSource.getPrevControlPoint(nNextIndex));
575 							aEdge.setEndPoint(rSource.getB2DPoint(nNextIndex));
576 
577 							if(aEdge.isBezier())
578 							{
579 								const basegfx::B2DRange aBezierRangeWithControlPoints(aEdge.getRange());
580 
581 								if(!aNewRange.isInside(aBezierRangeWithControlPoints))
582 								{
583 									// the range with control points of the current edge is not completely
584 									// inside the current range without control points. Expand current range by
585 									// subdividing the bezier segment.
586 									// Ideal here is a subdivision at the extreme values, so use
587 									// getAllExtremumPositions to get all extremas in one run
588 									::std::vector< double > aExtremas;
589 
590 									aExtremas.reserve(4);
591 									aEdge.getAllExtremumPositions(aExtremas);
592 
593 									const sal_uInt32 nExtremaCount(aExtremas.size());
594 
595 									for(sal_uInt32 c(0); c < nExtremaCount; c++)
596 									{
597 										aNewRange.expand(aEdge.interpolatePoint(aExtremas[c]));
598 									}
599 								}
600 							}
601 
602 							// prepare next edge
603 							aEdge.setStartPoint(aEdge.getEndPoint());
604 						}
605 					}
606 				}
607 			}
608 
609 			const_cast< ImplBufferedData* >(this)->mpB2DRange.reset(new basegfx::B2DRange(aNewRange));
610 		}
611 
612         return *mpB2DRange;
613     }
614 };
615 
616 //////////////////////////////////////////////////////////////////////////////
617 
618 class ImplB2DPolygon
619 {
620 private:
621 	// The point vector. This vector exists always and defines the
622 	// count of members.
623 	CoordinateDataArray2D							maPoints;
624 
625 	// The control point vectors. This vectors are created on demand
626 	// and may be zero.
627 	boost::scoped_ptr< ControlVectorArray2D >		mpControlVector;
628 
629     // buffered data for e.g. default subdivision and range
630     boost::scoped_ptr< ImplBufferedData >           mpBufferedData;
631 
632 	// flag which decides if this polygon is opened or closed
633 	bool                                            mbIsClosed;
634 
635 public:
636 	const basegfx::B2DPolygon& getDefaultAdaptiveSubdivision(const basegfx::B2DPolygon& rSource) const
637 	{
638 		if(!mpControlVector || !mpControlVector->isUsed())
639         {
640     		return rSource;
641         }
642 
643         if(!mpBufferedData)
644         {
645 			const_cast< ImplB2DPolygon* >(this)->mpBufferedData.reset(new ImplBufferedData);
646         }
647 
648         return mpBufferedData->getDefaultAdaptiveSubdivision(rSource);
649 	}
650 
651 	const basegfx::B2DRange& getB2DRange(const basegfx::B2DPolygon& rSource) const
652     {
653         if(!mpBufferedData)
654         {
655 			const_cast< ImplB2DPolygon* >(this)->mpBufferedData.reset(new ImplBufferedData);
656         }
657 
658         return mpBufferedData->getB2DRange(rSource);
659     }
660 
661 	ImplB2DPolygon()
662 	:	maPoints(0),
663 		mpControlVector(),
664 		mpBufferedData(),
665         mbIsClosed(false)
666 	{}
667 
668 	ImplB2DPolygon(const ImplB2DPolygon& rToBeCopied)
669 	:	maPoints(rToBeCopied.maPoints),
670 		mpControlVector(),
671 		mpBufferedData(),
672 		mbIsClosed(rToBeCopied.mbIsClosed)
673 	{
674 		// complete initialization using copy
675 		if(rToBeCopied.mpControlVector && rToBeCopied.mpControlVector->isUsed())
676         {
677 			mpControlVector.reset( new ControlVectorArray2D(*rToBeCopied.mpControlVector) );
678         }
679 	}
680 
681 	ImplB2DPolygon(const ImplB2DPolygon& rToBeCopied, sal_uInt32 nIndex, sal_uInt32 nCount)
682 	:	maPoints(rToBeCopied.maPoints, nIndex, nCount),
683 		mpControlVector(),
684 		mpBufferedData(),
685 		mbIsClosed(rToBeCopied.mbIsClosed)
686 	{
687 		// complete initialization using partly copy
688 		if(rToBeCopied.mpControlVector && rToBeCopied.mpControlVector->isUsed())
689 		{
690 			mpControlVector.reset( new ControlVectorArray2D(*rToBeCopied.mpControlVector, nIndex, nCount) );
691 
692 			if(!mpControlVector->isUsed())
693                 mpControlVector.reset();
694 		}
695 	}
696 
697     ImplB2DPolygon& operator=( const ImplB2DPolygon& rToBeCopied )
698     {
699 		maPoints = rToBeCopied.maPoints;
700 		mpControlVector.reset();
701 		mpBufferedData.reset();
702 		mbIsClosed = rToBeCopied.mbIsClosed;
703 
704 		// complete initialization using copy
705 		if(rToBeCopied.mpControlVector && rToBeCopied.mpControlVector->isUsed())
706 			mpControlVector.reset( new ControlVectorArray2D(*rToBeCopied.mpControlVector) );
707 
708         return *this;
709     }
710 
711 	sal_uInt32 count() const
712 	{
713 		return maPoints.count();
714 	}
715 
716 	bool isClosed() const
717 	{
718 		return mbIsClosed;
719 	}
720 
721 	void setClosed(bool bNew)
722 	{
723 		if(bNew != mbIsClosed)
724 		{
725 			mpBufferedData.reset();
726 			mbIsClosed = bNew;
727 		}
728 	}
729 
730 	bool operator==(const ImplB2DPolygon& rCandidate) const
731 	{
732 		if(mbIsClosed == rCandidate.mbIsClosed)
733 		{
734 			if(maPoints == rCandidate.maPoints)
735 			{
736 				bool bControlVectorsAreEqual(true);
737 
738 				if(mpControlVector)
739 				{
740 					if(rCandidate.mpControlVector)
741 					{
742 						bControlVectorsAreEqual = ((*mpControlVector) == (*rCandidate.mpControlVector));
743 					}
744 					else
745 					{
746 						// candidate has no control vector, so it's assumed all unused.
747 						bControlVectorsAreEqual = !mpControlVector->isUsed();
748 					}
749 				}
750 				else
751 				{
752 					if(rCandidate.mpControlVector)
753 					{
754 						// we have no control vector, so it's assumed all unused.
755 						bControlVectorsAreEqual = !rCandidate.mpControlVector->isUsed();
756 					}
757 				}
758 
759 				if(bControlVectorsAreEqual)
760 				{
761 					return true;
762 				}
763 			}
764 		}
765 
766 		return false;
767 	}
768 
769 	const basegfx::B2DPoint& getPoint(sal_uInt32 nIndex) const
770 	{
771 		return maPoints.getCoordinate(nIndex);
772 	}
773 
774 	void setPoint(sal_uInt32 nIndex, const basegfx::B2DPoint& rValue)
775 	{
776 		mpBufferedData.reset();
777 		maPoints.setCoordinate(nIndex, rValue);
778 	}
779 
780 	void reserve(sal_uInt32 nCount)
781 	{
782 		maPoints.reserve(nCount);
783 	}
784 
785 	void append(const basegfx::B2DPoint& rPoint)
786 	{
787 		mpBufferedData.reset(); // TODO: is this needed?
788 		const CoordinateData2D aCoordinate(rPoint);
789 		maPoints.append(aCoordinate);
790 
791 		if(mpControlVector)
792 		{
793 			const ControlVectorPair2D aVectorPair;
794 			mpControlVector->append(aVectorPair);
795 		}
796 	}
797 
798 	void insert(sal_uInt32 nIndex, const basegfx::B2DPoint& rPoint, sal_uInt32 nCount)
799 	{
800 		if(nCount)
801 		{
802 			mpBufferedData.reset();
803 			CoordinateData2D aCoordinate(rPoint);
804 			maPoints.insert(nIndex, aCoordinate, nCount);
805 
806 			if(mpControlVector)
807 			{
808 				ControlVectorPair2D aVectorPair;
809 				mpControlVector->insert(nIndex, aVectorPair, nCount);
810 			}
811 		}
812 	}
813 
814 	const basegfx::B2DVector& getPrevControlVector(sal_uInt32 nIndex) const
815 	{
816 		if(mpControlVector)
817 		{
818 			return mpControlVector->getPrevVector(nIndex);
819 		}
820 		else
821 		{
822 			return basegfx::B2DVector::getEmptyVector();
823 		}
824 	}
825 
826 	void setPrevControlVector(sal_uInt32 nIndex, const basegfx::B2DVector& rValue)
827 	{
828 		if(!mpControlVector)
829 		{
830 			if(!rValue.equalZero())
831 			{
832 				mpBufferedData.reset();
833 				mpControlVector.reset( new ControlVectorArray2D(maPoints.count()) );
834 				mpControlVector->setPrevVector(nIndex, rValue);
835 			}
836 		}
837 		else
838 		{
839 			mpBufferedData.reset();
840 			mpControlVector->setPrevVector(nIndex, rValue);
841 
842 			if(!mpControlVector->isUsed())
843                 mpControlVector.reset();
844 		}
845 	}
846 
847 	const basegfx::B2DVector& getNextControlVector(sal_uInt32 nIndex) const
848 	{
849 		if(mpControlVector)
850 		{
851 			return mpControlVector->getNextVector(nIndex);
852 		}
853 		else
854 		{
855 			return basegfx::B2DVector::getEmptyVector();
856 		}
857 	}
858 
859 	void setNextControlVector(sal_uInt32 nIndex, const basegfx::B2DVector& rValue)
860 	{
861 		if(!mpControlVector)
862 		{
863 			if(!rValue.equalZero())
864 			{
865 				mpBufferedData.reset();
866 				mpControlVector.reset( new ControlVectorArray2D(maPoints.count()) );
867 				mpControlVector->setNextVector(nIndex, rValue);
868 			}
869 		}
870 		else
871 		{
872 			mpBufferedData.reset();
873 			mpControlVector->setNextVector(nIndex, rValue);
874 
875 			if(!mpControlVector->isUsed())
876                 mpControlVector.reset();
877 		}
878 	}
879 
880 	bool areControlPointsUsed() const
881 	{
882 		return (mpControlVector && mpControlVector->isUsed());
883 	}
884 
885 	void resetControlVectors(sal_uInt32 nIndex)
886 	{
887 		setPrevControlVector(nIndex, basegfx::B2DVector::getEmptyVector());
888 		setNextControlVector(nIndex, basegfx::B2DVector::getEmptyVector());
889 	}
890 
891 	void resetControlVectors()
892 	{
893 		mpBufferedData.reset();
894 		mpControlVector.reset();
895 	}
896 
897 	void setControlVectors(sal_uInt32 nIndex, const basegfx::B2DVector& rPrev, const basegfx::B2DVector& rNext)
898 	{
899 		setPrevControlVector(nIndex, rPrev);
900 		setNextControlVector(nIndex, rNext);
901 	}
902 
903 	void appendBezierSegment(const basegfx::B2DVector& rNext, const basegfx::B2DVector& rPrev, const basegfx::B2DPoint& rPoint)
904 	{
905 		mpBufferedData.reset();
906 		const sal_uInt32 nCount(maPoints.count());
907 
908         if(nCount)
909 		{
910 			setNextControlVector(nCount - 1, rNext);
911 		}
912 
913 		insert(nCount, rPoint, 1);
914 		setPrevControlVector(nCount, rPrev);
915 	}
916 
917 	void insert(sal_uInt32 nIndex, const ImplB2DPolygon& rSource)
918 	{
919 		const sal_uInt32 nCount(rSource.maPoints.count());
920 
921 		if(nCount)
922 		{
923 			mpBufferedData.reset();
924 
925 			if(rSource.mpControlVector && rSource.mpControlVector->isUsed() && !mpControlVector)
926 			{
927 				mpControlVector.reset( new ControlVectorArray2D(maPoints.count()) );
928 			}
929 
930 			maPoints.insert(nIndex, rSource.maPoints);
931 
932 			if(rSource.mpControlVector)
933 			{
934 				mpControlVector->insert(nIndex, *rSource.mpControlVector);
935 
936 				if(!mpControlVector->isUsed())
937                     mpControlVector.reset();
938 			}
939 			else if(mpControlVector)
940 			{
941 				ControlVectorPair2D aVectorPair;
942 				mpControlVector->insert(nIndex, aVectorPair, nCount);
943 			}
944 		}
945 	}
946 
947 	void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
948 	{
949 		if(nCount)
950 		{
951 			mpBufferedData.reset();
952 			maPoints.remove(nIndex, nCount);
953 
954 			if(mpControlVector)
955 			{
956 				mpControlVector->remove(nIndex, nCount);
957 
958 				if(!mpControlVector->isUsed())
959                     mpControlVector.reset();
960 			}
961 		}
962 	}
963 
964 	void flip()
965 	{
966 		if(maPoints.count() > 1)
967 		{
968 			mpBufferedData.reset();
969 
970 			// flip points
971 			maPoints.flip(mbIsClosed);
972 
973 			if(mpControlVector)
974 			{
975 				// flip control vector
976 				mpControlVector->flip(mbIsClosed);
977 			}
978 		}
979 	}
980 
981 	bool hasDoublePoints() const
982 	{
983 		if(mbIsClosed)
984 		{
985 			// check for same start and end point
986 			const sal_uInt32 nIndex(maPoints.count() - 1);
987 
988 			if(maPoints.getCoordinate(0) == maPoints.getCoordinate(nIndex))
989 			{
990 				if(mpControlVector)
991 				{
992 					if(mpControlVector->getNextVector(nIndex).equalZero() && mpControlVector->getPrevVector(0).equalZero())
993 					{
994 						return true;
995 					}
996 				}
997 				else
998 				{
999 					return true;
1000 				}
1001 			}
1002 		}
1003 
1004 		// test for range
1005 		for(sal_uInt32 a(0); a < maPoints.count() - 1; a++)
1006 		{
1007 			if(maPoints.getCoordinate(a) == maPoints.getCoordinate(a + 1))
1008 			{
1009 				if(mpControlVector)
1010 				{
1011 					if(mpControlVector->getNextVector(a).equalZero() && mpControlVector->getPrevVector(a + 1).equalZero())
1012 					{
1013 						return true;
1014 					}
1015 				}
1016 				else
1017 				{
1018 					return true;
1019 				}
1020 			}
1021 		}
1022 
1023 		return false;
1024 	}
1025 
1026 	void removeDoublePointsAtBeginEnd()
1027 	{
1028 		// Only remove DoublePoints at Begin and End when poly is closed
1029 		if(mbIsClosed)
1030 		{
1031 			mpBufferedData.reset();
1032 
1033             if(mpControlVector)
1034 			{
1035 				bool bRemove;
1036 
1037 				do
1038 				{
1039 					bRemove = false;
1040 
1041 					if(maPoints.count() > 1)
1042 					{
1043 						const sal_uInt32 nIndex(maPoints.count() - 1);
1044 
1045 						if(maPoints.getCoordinate(0) == maPoints.getCoordinate(nIndex))
1046 						{
1047 							if(mpControlVector)
1048 							{
1049 								if(mpControlVector->getNextVector(nIndex).equalZero() && mpControlVector->getPrevVector(0).equalZero())
1050 								{
1051 									bRemove = true;
1052 								}
1053 							}
1054 							else
1055 							{
1056 								bRemove = true;
1057 							}
1058 						}
1059 					}
1060 
1061 					if(bRemove)
1062 					{
1063 						const sal_uInt32 nIndex(maPoints.count() - 1);
1064 
1065 						if(mpControlVector && !mpControlVector->getPrevVector(nIndex).equalZero())
1066 						{
1067 							mpControlVector->setPrevVector(0, mpControlVector->getPrevVector(nIndex));
1068 						}
1069 
1070 						remove(nIndex, 1);
1071 					}
1072 				}
1073 				while(bRemove);
1074 			}
1075 			else
1076 			{
1077 				maPoints.removeDoublePointsAtBeginEnd();
1078 			}
1079 		}
1080 	}
1081 
1082 	void removeDoublePointsWholeTrack()
1083 	{
1084 		mpBufferedData.reset();
1085 
1086         if(mpControlVector)
1087 		{
1088 			sal_uInt32 nIndex(0);
1089 
1090 			// test as long as there are at least two points and as long as the index
1091 			// is smaller or equal second last point
1092 			while((maPoints.count() > 1) && (nIndex <= maPoints.count() - 2))
1093 			{
1094 				bool bRemove(maPoints.getCoordinate(nIndex) == maPoints.getCoordinate(nIndex + 1));
1095 
1096 				if(bRemove)
1097 				{
1098 					if(mpControlVector)
1099 					{
1100 						if(!mpControlVector->getNextVector(nIndex).equalZero() || !mpControlVector->getPrevVector(nIndex + 1).equalZero())
1101 						{
1102 							bRemove = false;
1103 						}
1104 					}
1105 				}
1106 
1107 				if(bRemove)
1108 				{
1109 					if(mpControlVector && !mpControlVector->getPrevVector(nIndex).equalZero())
1110 					{
1111 						mpControlVector->setPrevVector(nIndex + 1, mpControlVector->getPrevVector(nIndex));
1112 					}
1113 
1114 					// if next is same as index and the control vectors are unused, delete index
1115 					remove(nIndex, 1);
1116 				}
1117 				else
1118 				{
1119 					// if different, step forward
1120 					nIndex++;
1121 				}
1122 			}
1123 		}
1124 		else
1125 		{
1126 			maPoints.removeDoublePointsWholeTrack();
1127 		}
1128 	}
1129 
1130 	void transform(const basegfx::B2DHomMatrix& rMatrix)
1131 	{
1132 		mpBufferedData.reset();
1133 
1134         if(mpControlVector)
1135 		{
1136 			for(sal_uInt32 a(0); a < maPoints.count(); a++)
1137 			{
1138 				basegfx::B2DPoint aCandidate = maPoints.getCoordinate(a);
1139 
1140 				if(mpControlVector->isUsed())
1141 				{
1142 					const basegfx::B2DVector& rPrevVector(mpControlVector->getPrevVector(a));
1143 					const basegfx::B2DVector& rNextVector(mpControlVector->getNextVector(a));
1144 
1145 					if(!rPrevVector.equalZero())
1146 					{
1147 						basegfx::B2DVector aPrevVector(rMatrix * rPrevVector);
1148 						mpControlVector->setPrevVector(a, aPrevVector);
1149 					}
1150 
1151 					if(!rNextVector.equalZero())
1152 					{
1153 						basegfx::B2DVector aNextVector(rMatrix * rNextVector);
1154 						mpControlVector->setNextVector(a, aNextVector);
1155 					}
1156 				}
1157 
1158 				aCandidate *= rMatrix;
1159 				maPoints.setCoordinate(a, aCandidate);
1160 			}
1161 
1162 			if(!mpControlVector->isUsed())
1163                 mpControlVector.reset();
1164 		}
1165 		else
1166 		{
1167 			maPoints.transform(rMatrix);
1168 		}
1169 	}
1170 
1171     const basegfx::B2DPoint* begin() const
1172     {
1173         return maPoints.begin();
1174     }
1175 
1176     const basegfx::B2DPoint* end() const
1177     {
1178         return maPoints.end();
1179     }
1180 
1181     basegfx::B2DPoint* begin()
1182     {
1183        mpBufferedData.reset();
1184        return maPoints.begin();
1185     }
1186 
1187     basegfx::B2DPoint* end()
1188     {
1189         mpBufferedData.reset();
1190         return maPoints.end();
1191     }
1192 };
1193 
1194 //////////////////////////////////////////////////////////////////////////////
1195 
1196 namespace basegfx
1197 {
1198     namespace
1199 	{
1200 		struct DefaultPolygon: public rtl::Static<B2DPolygon::ImplType, DefaultPolygon> {};
1201 	}
1202 
1203 	B2DPolygon::B2DPolygon()
1204 	:	mpPolygon(DefaultPolygon::get())
1205 	{}
1206 
1207 	B2DPolygon::B2DPolygon(const B2DPolygon& rPolygon)
1208 	:	mpPolygon(rPolygon.mpPolygon)
1209 	{}
1210 
1211 	B2DPolygon::B2DPolygon(const B2DPolygon& rPolygon, sal_uInt32 nIndex, sal_uInt32 nCount)
1212 	:	mpPolygon(ImplB2DPolygon(*rPolygon.mpPolygon, nIndex, nCount))
1213 	{
1214         // TODO(P2): one extra temporary here (cow_wrapper copies
1215         // given ImplB2DPolygon into its internal impl_t wrapper type)
1216 		OSL_ENSURE(nIndex + nCount <= rPolygon.mpPolygon->count(), "B2DPolygon constructor outside range (!)");
1217 	}
1218 
1219 	B2DPolygon::~B2DPolygon()
1220 	{
1221 	}
1222 
1223 	B2DPolygon& B2DPolygon::operator=(const B2DPolygon& rPolygon)
1224 	{
1225 		mpPolygon = rPolygon.mpPolygon;
1226 		return *this;
1227 	}
1228 
1229     void B2DPolygon::makeUnique()
1230     {
1231         mpPolygon.make_unique();
1232     }
1233 
1234 	bool B2DPolygon::operator==(const B2DPolygon& rPolygon) const
1235 	{
1236 		if(mpPolygon.same_object(rPolygon.mpPolygon))
1237 			return true;
1238 
1239 		return ((*mpPolygon) == (*rPolygon.mpPolygon));
1240 	}
1241 
1242 	bool B2DPolygon::operator!=(const B2DPolygon& rPolygon) const
1243 	{
1244         return !(*this == rPolygon);
1245 	}
1246 
1247 	sal_uInt32 B2DPolygon::count() const
1248 	{
1249 		return mpPolygon->count();
1250 	}
1251 
1252     B2DPoint B2DPolygon::getB2DPoint(sal_uInt32 nIndex) const
1253 	{
1254 		OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1255 
1256 		return mpPolygon->getPoint(nIndex);
1257 	}
1258 
1259 	void B2DPolygon::setB2DPoint(sal_uInt32 nIndex, const B2DPoint& rValue)
1260 	{
1261 		OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1262 
1263 		if(getB2DPoint(nIndex) != rValue)
1264 		{
1265 			mpPolygon->setPoint(nIndex, rValue);
1266 		}
1267 	}
1268 
1269 	void B2DPolygon::reserve(sal_uInt32 nCount)
1270 	{
1271 		mpPolygon->reserve(nCount);
1272 	}
1273 
1274 	void B2DPolygon::insert(sal_uInt32 nIndex, const B2DPoint& rPoint, sal_uInt32 nCount)
1275 	{
1276 		OSL_ENSURE(nIndex <= mpPolygon->count(), "B2DPolygon Insert outside range (!)");
1277 
1278 		if(nCount)
1279 		{
1280 			mpPolygon->insert(nIndex, rPoint, nCount);
1281 		}
1282 	}
1283 
1284 	void B2DPolygon::append(const B2DPoint& rPoint, sal_uInt32 nCount)
1285 	{
1286 		if(nCount)
1287 		{
1288 			mpPolygon->insert(mpPolygon->count(), rPoint, nCount);
1289 		}
1290 	}
1291 
1292 	void B2DPolygon::append(const B2DPoint& rPoint)
1293 	{
1294 		mpPolygon->append(rPoint);
1295 	}
1296 
1297 	B2DPoint B2DPolygon::getPrevControlPoint(sal_uInt32 nIndex) const
1298 	{
1299 		OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1300 
1301 		if(mpPolygon->areControlPointsUsed())
1302 		{
1303 			return mpPolygon->getPoint(nIndex) + mpPolygon->getPrevControlVector(nIndex);
1304 		}
1305 		else
1306 		{
1307 			return mpPolygon->getPoint(nIndex);
1308 		}
1309 	}
1310 
1311 	B2DPoint B2DPolygon::getNextControlPoint(sal_uInt32 nIndex) const
1312 	{
1313 		OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1314 
1315 		if(mpPolygon->areControlPointsUsed())
1316 		{
1317 			return mpPolygon->getPoint(nIndex) + mpPolygon->getNextControlVector(nIndex);
1318 		}
1319 		else
1320 		{
1321 			return mpPolygon->getPoint(nIndex);
1322 		}
1323 	}
1324 
1325 	void B2DPolygon::setPrevControlPoint(sal_uInt32 nIndex, const B2DPoint& rValue)
1326 	{
1327 		OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1328 		const basegfx::B2DVector aNewVector(rValue - mpPolygon->getPoint(nIndex));
1329 
1330 		if(mpPolygon->getPrevControlVector(nIndex) != aNewVector)
1331 		{
1332 			mpPolygon->setPrevControlVector(nIndex, aNewVector);
1333 		}
1334 	}
1335 
1336 	void B2DPolygon::setNextControlPoint(sal_uInt32 nIndex, const B2DPoint& rValue)
1337 	{
1338 		OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1339 		const basegfx::B2DVector aNewVector(rValue - mpPolygon->getPoint(nIndex));
1340 
1341 		if(mpPolygon->getNextControlVector(nIndex) != aNewVector)
1342 		{
1343 			mpPolygon->setNextControlVector(nIndex, aNewVector);
1344 		}
1345 	}
1346 
1347 	void B2DPolygon::setControlPoints(sal_uInt32 nIndex, const basegfx::B2DPoint& rPrev, const basegfx::B2DPoint& rNext)
1348 	{
1349 		OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1350 		const B2DPoint aPoint(mpPolygon->getPoint(nIndex));
1351 		const basegfx::B2DVector aNewPrev(rPrev - aPoint);
1352 		const basegfx::B2DVector aNewNext(rNext - aPoint);
1353 
1354 		if(mpPolygon->getPrevControlVector(nIndex) != aNewPrev || mpPolygon->getNextControlVector(nIndex) != aNewNext)
1355 		{
1356 			mpPolygon->setControlVectors(nIndex, aNewPrev, aNewNext);
1357 		}
1358 	}
1359 
1360 	void B2DPolygon::resetPrevControlPoint(sal_uInt32 nIndex)
1361 	{
1362 		OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1363 
1364 		if(mpPolygon->areControlPointsUsed() && !mpPolygon->getPrevControlVector(nIndex).equalZero())
1365 		{
1366 			mpPolygon->setPrevControlVector(nIndex, B2DVector::getEmptyVector());
1367 		}
1368 	}
1369 
1370 	void B2DPolygon::resetNextControlPoint(sal_uInt32 nIndex)
1371 	{
1372 		OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1373 
1374 		if(mpPolygon->areControlPointsUsed() && !mpPolygon->getNextControlVector(nIndex).equalZero())
1375 		{
1376 			mpPolygon->setNextControlVector(nIndex, B2DVector::getEmptyVector());
1377 		}
1378 	}
1379 
1380 	void B2DPolygon::resetControlPoints(sal_uInt32 nIndex)
1381 	{
1382 		OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1383 
1384 		if(mpPolygon->areControlPointsUsed() &&
1385 			(!mpPolygon->getPrevControlVector(nIndex).equalZero() || !mpPolygon->getNextControlVector(nIndex).equalZero()))
1386 		{
1387 			mpPolygon->resetControlVectors(nIndex);
1388 		}
1389 	}
1390 
1391 	void B2DPolygon::resetControlPoints()
1392 	{
1393 		if(mpPolygon->areControlPointsUsed())
1394 		{
1395 			mpPolygon->resetControlVectors();
1396 		}
1397 	}
1398 
1399 	void B2DPolygon::appendBezierSegment(
1400 		const B2DPoint& rNextControlPoint,
1401 		const B2DPoint& rPrevControlPoint,
1402 		const B2DPoint& rPoint)
1403 	{
1404 		const B2DVector aNewNextVector(mpPolygon->count() ? B2DVector(rNextControlPoint - mpPolygon->getPoint(mpPolygon->count() - 1)) : B2DVector::getEmptyVector());
1405 		const B2DVector aNewPrevVector(rPrevControlPoint - rPoint);
1406 
1407 		if(aNewNextVector.equalZero() && aNewPrevVector.equalZero())
1408 		{
1409 			mpPolygon->insert(mpPolygon->count(), rPoint, 1);
1410 		}
1411 		else
1412 		{
1413 			mpPolygon->appendBezierSegment(aNewNextVector, aNewPrevVector, rPoint);
1414 		}
1415 	}
1416 
1417 	bool B2DPolygon::areControlPointsUsed() const
1418 	{
1419 		return mpPolygon->areControlPointsUsed();
1420 	}
1421 
1422 	bool B2DPolygon::isPrevControlPointUsed(sal_uInt32 nIndex) const
1423 	{
1424 		OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1425 
1426 		return (mpPolygon->areControlPointsUsed() && !mpPolygon->getPrevControlVector(nIndex).equalZero());
1427 	}
1428 
1429 	bool B2DPolygon::isNextControlPointUsed(sal_uInt32 nIndex) const
1430 	{
1431 		OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1432 
1433 		return (mpPolygon->areControlPointsUsed() && !mpPolygon->getNextControlVector(nIndex).equalZero());
1434 	}
1435 
1436 	B2VectorContinuity B2DPolygon::getContinuityInPoint(sal_uInt32 nIndex) const
1437 	{
1438 		OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1439 
1440 		if(mpPolygon->areControlPointsUsed())
1441 		{
1442 			const B2DVector& rPrev(mpPolygon->getPrevControlVector(nIndex));
1443 			const B2DVector& rNext(mpPolygon->getNextControlVector(nIndex));
1444 
1445 			return getContinuity(rPrev, rNext);
1446 		}
1447 		else
1448 		{
1449 			return CONTINUITY_NONE;
1450 		}
1451 	}
1452 
1453     bool B2DPolygon::isBezierSegment(sal_uInt32 nIndex) const
1454     {
1455 		OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1456 
1457         if(mpPolygon->areControlPointsUsed())
1458 		{
1459             // Check if the edge exists
1460             const bool bNextIndexValidWithoutClose(nIndex + 1 < mpPolygon->count());
1461 
1462             if(bNextIndexValidWithoutClose || mpPolygon->isClosed())
1463             {
1464                 const sal_uInt32 nNextIndex(bNextIndexValidWithoutClose ? nIndex + 1 : 0);
1465                 return (!mpPolygon->getPrevControlVector(nNextIndex).equalZero()
1466                     || !mpPolygon->getNextControlVector(nIndex).equalZero());
1467             }
1468             else
1469             {
1470                 // no valid edge -> no bezier segment, even when local next
1471                 // vector may be used
1472                 return false;
1473             }
1474         }
1475         else
1476         {
1477             // no control points -> no bezier segment
1478             return false;
1479         }
1480     }
1481 
1482     void B2DPolygon::getBezierSegment(sal_uInt32 nIndex, B2DCubicBezier& rTarget) const
1483     {
1484 		OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1485         const bool bNextIndexValidWithoutClose(nIndex + 1 < mpPolygon->count());
1486 
1487         if(bNextIndexValidWithoutClose || mpPolygon->isClosed())
1488         {
1489             const sal_uInt32 nNextIndex(bNextIndexValidWithoutClose ? nIndex + 1 : 0);
1490             rTarget.setStartPoint(mpPolygon->getPoint(nIndex));
1491             rTarget.setEndPoint(mpPolygon->getPoint(nNextIndex));
1492 
1493             if(mpPolygon->areControlPointsUsed())
1494             {
1495                 rTarget.setControlPointA(rTarget.getStartPoint() + mpPolygon->getNextControlVector(nIndex));
1496                 rTarget.setControlPointB(rTarget.getEndPoint() + mpPolygon->getPrevControlVector(nNextIndex));
1497             }
1498             else
1499             {
1500                 // no bezier, reset control poins at rTarget
1501                 rTarget.setControlPointA(rTarget.getStartPoint());
1502                 rTarget.setControlPointB(rTarget.getEndPoint());
1503             }
1504         }
1505         else
1506         {
1507             // no valid edge at all, reset rTarget to current point
1508     		const B2DPoint aPoint(mpPolygon->getPoint(nIndex));
1509             rTarget.setStartPoint(aPoint);
1510             rTarget.setEndPoint(aPoint);
1511             rTarget.setControlPointA(aPoint);
1512             rTarget.setControlPointB(aPoint);
1513         }
1514     }
1515 
1516     B2DPolygon B2DPolygon::getDefaultAdaptiveSubdivision() const
1517 	{
1518 		return mpPolygon->getDefaultAdaptiveSubdivision(*this);
1519 	}
1520 
1521     B2DRange B2DPolygon::getB2DRange() const
1522 	{
1523 		return mpPolygon->getB2DRange(*this);
1524 	}
1525 
1526 	void B2DPolygon::insert(sal_uInt32 nIndex, const B2DPolygon& rPoly, sal_uInt32 nIndex2, sal_uInt32 nCount)
1527 	{
1528 		OSL_ENSURE(nIndex <= mpPolygon->count(), "B2DPolygon Insert outside range (!)");
1529 
1530 		if(rPoly.count())
1531 		{
1532 			if(!nCount)
1533 			{
1534 				nCount = rPoly.count();
1535 			}
1536 
1537 			if(0 == nIndex2 && nCount == rPoly.count())
1538 			{
1539 				mpPolygon->insert(nIndex, *rPoly.mpPolygon);
1540 			}
1541 			else
1542 			{
1543 				OSL_ENSURE(nIndex2 + nCount <= rPoly.mpPolygon->count(), "B2DPolygon Insert outside range (!)");
1544 				ImplB2DPolygon aTempPoly(*rPoly.mpPolygon, nIndex2, nCount);
1545 				mpPolygon->insert(nIndex, aTempPoly);
1546 			}
1547 		}
1548 	}
1549 
1550 	void B2DPolygon::append(const B2DPolygon& rPoly, sal_uInt32 nIndex, sal_uInt32 nCount)
1551 	{
1552 		if(rPoly.count())
1553 		{
1554 			if(!nCount)
1555 			{
1556 				nCount = rPoly.count();
1557 			}
1558 
1559 			if(0 == nIndex && nCount == rPoly.count())
1560 			{
1561 				mpPolygon->insert(mpPolygon->count(), *rPoly.mpPolygon);
1562 			}
1563 			else
1564 			{
1565 				OSL_ENSURE(nIndex + nCount <= rPoly.mpPolygon->count(), "B2DPolygon Append outside range (!)");
1566 				ImplB2DPolygon aTempPoly(*rPoly.mpPolygon, nIndex, nCount);
1567 				mpPolygon->insert(mpPolygon->count(), aTempPoly);
1568 			}
1569 		}
1570 	}
1571 
1572 	void B2DPolygon::remove(sal_uInt32 nIndex, sal_uInt32 nCount)
1573 	{
1574 		OSL_ENSURE(nIndex + nCount <= mpPolygon->count(), "B2DPolygon Remove outside range (!)");
1575 
1576 		if(nCount)
1577 		{
1578 			mpPolygon->remove(nIndex, nCount);
1579 		}
1580 	}
1581 
1582 	void B2DPolygon::clear()
1583 	{
1584 		mpPolygon = DefaultPolygon::get();
1585 	}
1586 
1587 	bool B2DPolygon::isClosed() const
1588 	{
1589 		return mpPolygon->isClosed();
1590 	}
1591 
1592 	void B2DPolygon::setClosed(bool bNew)
1593 	{
1594 		if(isClosed() != bNew)
1595 		{
1596 			mpPolygon->setClosed(bNew);
1597 		}
1598 	}
1599 
1600 	void B2DPolygon::flip()
1601 	{
1602 		if(count() > 1)
1603 		{
1604 			mpPolygon->flip();
1605 		}
1606 	}
1607 
1608 	bool B2DPolygon::hasDoublePoints() const
1609 	{
1610 		return (mpPolygon->count() > 1 && mpPolygon->hasDoublePoints());
1611 	}
1612 
1613 	void B2DPolygon::removeDoublePoints()
1614 	{
1615 		if(hasDoublePoints())
1616 		{
1617 			mpPolygon->removeDoublePointsAtBeginEnd();
1618 			mpPolygon->removeDoublePointsWholeTrack();
1619 		}
1620 	}
1621 
1622 	void B2DPolygon::transform(const B2DHomMatrix& rMatrix)
1623 	{
1624 		if(mpPolygon->count() && !rMatrix.isIdentity())
1625 		{
1626 			mpPolygon->transform(rMatrix);
1627 		}
1628 	}
1629 
1630     const B2DPoint* B2DPolygon::begin() const
1631     {
1632         return mpPolygon->begin();
1633     }
1634 
1635     const B2DPoint* B2DPolygon::end() const
1636     {
1637         return mpPolygon->end();
1638     }
1639 
1640     B2DPoint* B2DPolygon::begin()
1641     {
1642         return mpPolygon->begin();
1643     }
1644 
1645     B2DPoint* B2DPolygon::end()
1646     {
1647         return mpPolygon->end();
1648     }
1649 } // end of namespace basegfx
1650 
1651 //////////////////////////////////////////////////////////////////////////////
1652 // eof
1653