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