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