xref: /aoo41x/main/tools/source/generic/poly.cxx (revision a61ca253)
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_tools.hxx"
26 
27 #define _SV_POLY_CXX
28 #include <osl/endian.h>
29 #include <tools/bigint.hxx>
30 #include <tools/debug.hxx>
31 #include <tools/stream.hxx>
32 #include <tools/vcompat.hxx>
33 #include <poly.h>
34 #include <tools/line.hxx>
35 #ifndef _VECTOR2D_H
36 #include <tools/vector2d.hxx>
37 #endif
38 #ifndef _POLY_HXX
39 #include <tools/poly.hxx>
40 #endif
41 #include <basegfx/polygon/b2dpolygon.hxx>
42 #include <basegfx/point/b2dpoint.hxx>
43 #include <basegfx/vector/b2dvector.hxx>
44 #include <basegfx/polygon/b2dpolygontools.hxx>
45 #include <basegfx/curve/b2dcubicbezier.hxx>
46 
47 #include <vector>
48 #include <iterator>
49 #include <algorithm>
50 #include <cstring>
51 #include <limits.h>
52 #include <cmath>
53 
54 
55 // =======================================================================
56 
57 DBG_NAME( Polygon )
58 
59 // -----------------------------------------------------------------------
60 
61 #define EDGE_LEFT		1
62 #define EDGE_TOP		2
63 #define EDGE_RIGHT		4
64 #define EDGE_BOTTOM 	8
65 #define EDGE_HORZ		(EDGE_RIGHT | EDGE_LEFT)
66 #define EDGE_VERT		(EDGE_TOP | EDGE_BOTTOM)
67 #define	SMALL_DVALUE	0.0000001
68 #define FSQRT2			1.4142135623730950488016887242097
69 
70 // -----------------------------------------------------------------------
71 
72 static ImplPolygonData aStaticImplPolygon =
73 {
74 	NULL, NULL, 0, 0
75 };
76 
77 // =======================================================================
78 
ImplPolygon(sal_uInt16 nInitSize,sal_Bool bFlags)79 ImplPolygon::ImplPolygon( sal_uInt16 nInitSize, sal_Bool bFlags  )
80 {
81 	if ( nInitSize )
82 	{
83 		mpPointAry = (Point*)new char[(sal_uIntPtr)nInitSize*sizeof(Point)];
84 		memset( mpPointAry, 0, (sal_uIntPtr)nInitSize*sizeof(Point) );
85 	}
86 	else
87 		mpPointAry = NULL;
88 
89 	if( bFlags )
90 	{
91 		mpFlagAry = new sal_uInt8[ nInitSize ];
92 		memset( mpPointAry, 0, nInitSize );
93 	}
94 	else
95 		mpFlagAry = NULL;
96 
97 	mnRefCount = 1;
98 	mnPoints = nInitSize;
99 }
100 
101 // -----------------------------------------------------------------------
102 
ImplPolygon(const ImplPolygon & rImpPoly)103 ImplPolygon::ImplPolygon( const ImplPolygon& rImpPoly )
104 {
105 	if ( rImpPoly.mnPoints )
106 	{
107 		mpPointAry = (Point*)new char[(sal_uIntPtr)rImpPoly.mnPoints*sizeof(Point)];
108 		memcpy( mpPointAry, rImpPoly.mpPointAry, (sal_uIntPtr)rImpPoly.mnPoints*sizeof(Point) );
109 
110 		if( rImpPoly.mpFlagAry )
111 		{
112 			mpFlagAry = new sal_uInt8[ rImpPoly.mnPoints ];
113 			memcpy( mpFlagAry, rImpPoly.mpFlagAry, rImpPoly.mnPoints );
114 		}
115 		else
116 			mpFlagAry = NULL;
117 	}
118 	else
119 	{
120 		mpPointAry = NULL;
121 		mpFlagAry = NULL;
122 	}
123 
124 	mnRefCount = 1;
125 	mnPoints   = rImpPoly.mnPoints;
126 }
127 
128 // -----------------------------------------------------------------------
129 
ImplPolygon(sal_uInt16 nInitSize,const Point * pInitAry,const sal_uInt8 * pInitFlags)130 ImplPolygon::ImplPolygon( sal_uInt16 nInitSize, const Point* pInitAry, const sal_uInt8* pInitFlags )
131 {
132 	if ( nInitSize )
133 	{
134 		mpPointAry = (Point*)new char[(sal_uIntPtr)nInitSize*sizeof(Point)];
135 		memcpy( mpPointAry, pInitAry, (sal_uIntPtr)nInitSize*sizeof( Point ) );
136 
137 		if( pInitFlags )
138 		{
139 			mpFlagAry = new sal_uInt8[ nInitSize ];
140 			memcpy( mpFlagAry, pInitFlags, nInitSize );
141 		}
142 		else
143 			mpFlagAry = NULL;
144 	}
145 	else
146 	{
147 		mpPointAry = NULL;
148 		mpFlagAry  = NULL;
149 	}
150 
151 	mnRefCount = 1;
152 	mnPoints   = nInitSize;
153 }
154 
155 // -----------------------------------------------------------------------
156 
~ImplPolygon()157 ImplPolygon::~ImplPolygon()
158 {
159 	if ( mpPointAry )
160 	{
161 		delete[] (char*) mpPointAry;
162 	}
163 
164 	if( mpFlagAry )
165 		delete[] mpFlagAry;
166 }
167 
168 // -----------------------------------------------------------------------
169 
ImplSetSize(sal_uInt16 nNewSize,sal_Bool bResize)170 void ImplPolygon::ImplSetSize( sal_uInt16 nNewSize, sal_Bool bResize )
171 {
172 	if( mnPoints == nNewSize )
173 		return;
174 
175 	Point* pNewAry;
176 
177 	if ( nNewSize )
178 	{
179 		pNewAry = (Point*)new char[(sal_uIntPtr)nNewSize*sizeof(Point)];
180 
181 		if ( bResize )
182 		{
183 			// Alte Punkte kopieren
184 			if ( mnPoints < nNewSize )
185 			{
186 				// Neue Punkte mit 0 initialisieren
187 				memset( pNewAry+mnPoints, 0, (sal_uIntPtr)(nNewSize-mnPoints)*sizeof(Point) );
188 				if ( mpPointAry )
189 					memcpy( pNewAry, mpPointAry, mnPoints*sizeof(Point) );
190 			}
191 			else
192 			{
193 				if ( mpPointAry )
194 					memcpy( pNewAry, mpPointAry, (sal_uIntPtr)nNewSize*sizeof(Point) );
195 			}
196 		}
197 	}
198 	else
199 		pNewAry = NULL;
200 
201 	if ( mpPointAry )
202 		delete[] (char*) mpPointAry;
203 
204 	// ggf. FlagArray beruecksichtigen
205 	if( mpFlagAry )
206 	{
207 		sal_uInt8* pNewFlagAry;
208 
209 		if( nNewSize )
210 		{
211 			pNewFlagAry = new sal_uInt8[ nNewSize ];
212 
213 			if( bResize )
214 			{
215 				// Alte Flags kopieren
216 				if ( mnPoints < nNewSize )
217 				{
218 					// Neue Punkte mit 0 initialisieren
219 					memset( pNewFlagAry+mnPoints, 0, nNewSize-mnPoints );
220 					memcpy( pNewFlagAry, mpFlagAry, mnPoints );
221 				}
222 				else
223 					memcpy( pNewFlagAry, mpFlagAry, nNewSize );
224 			}
225 		}
226 		else
227 			pNewFlagAry = NULL;
228 
229 		delete[] mpFlagAry;
230 		mpFlagAry  = pNewFlagAry;
231 	}
232 
233 	mpPointAry = pNewAry;
234 	mnPoints   = nNewSize;
235 }
236 
237 // -----------------------------------------------------------------------
238 
ImplSplit(sal_uInt16 nPos,sal_uInt16 nSpace,ImplPolygon * pInitPoly)239 void ImplPolygon::ImplSplit( sal_uInt16 nPos, sal_uInt16 nSpace, ImplPolygon* pInitPoly )
240 {
241 	const sal_uIntPtr 	nSpaceSize = nSpace * sizeof( Point );
242 
243 	//Can't fit this in :-(, throw ?
244 	if (mnPoints + nSpace > USHRT_MAX)
245 		return;
246 
247 	const sal_uInt16	nNewSize = mnPoints + nSpace;
248 
249 	if( nPos >= mnPoints )
250 	{
251 		// Hinten anhaengen
252 		nPos = mnPoints;
253 		ImplSetSize( nNewSize, sal_True );
254 
255 		if( pInitPoly )
256 		{
257 			memcpy( mpPointAry + nPos, pInitPoly->mpPointAry, nSpaceSize );
258 
259 			if( pInitPoly->mpFlagAry )
260 				memcpy( mpFlagAry + nPos, pInitPoly->mpFlagAry, nSpace );
261 		}
262 	}
263 	else
264 	{
265 		// PointArray ist in diesem Zweig immer vorhanden
266 		const sal_uInt16	nSecPos = nPos + nSpace;
267 		const sal_uInt16	nRest = mnPoints - nPos;
268 
269 		Point* pNewAry = (Point*) new char[ (sal_uIntPtr) nNewSize * sizeof( Point ) ];
270 
271 		memcpy( pNewAry, mpPointAry, nPos * sizeof( Point ) );
272 
273 		if( pInitPoly )
274 			memcpy( pNewAry + nPos, pInitPoly->mpPointAry, nSpaceSize );
275 		else
276 			memset( pNewAry + nPos, 0, nSpaceSize );
277 
278 		memcpy( pNewAry + nSecPos, mpPointAry + nPos, nRest * sizeof( Point ) );
279 		delete[] (char*) mpPointAry;
280 
281 		// ggf. FlagArray beruecksichtigen
282 		if( mpFlagAry )
283 		{
284 			sal_uInt8* pNewFlagAry = new sal_uInt8[ nNewSize ];
285 
286 			memcpy( pNewFlagAry, mpFlagAry, nPos );
287 
288 			if( pInitPoly && pInitPoly->mpFlagAry )
289 				memcpy( pNewFlagAry + nPos, pInitPoly->mpFlagAry, nSpace );
290 			else
291 				memset( pNewFlagAry + nPos, 0, nSpace );
292 
293 			memcpy( pNewFlagAry + nSecPos, mpFlagAry + nPos, nRest );
294 			delete[] mpFlagAry;
295 			mpFlagAry = pNewFlagAry;
296 		}
297 
298 		mpPointAry = pNewAry;
299 		mnPoints   = nNewSize;
300 	}
301 }
302 
303 // -----------------------------------------------------------------------
304 
ImplRemove(sal_uInt16 nPos,sal_uInt16 nCount)305 void ImplPolygon::ImplRemove( sal_uInt16 nPos, sal_uInt16 nCount )
306 {
307 	const sal_uInt16 nRemoveCount = Min( (sal_uInt16) ( mnPoints - nPos ), (sal_uInt16) nCount );
308 
309 	if( nRemoveCount )
310 	{
311 		const sal_uInt16	nNewSize = mnPoints - nRemoveCount;
312 		const sal_uInt16	nSecPos = nPos + nRemoveCount;
313 		const sal_uInt16	nRest = mnPoints - nSecPos;
314 
315 		Point* pNewAry = (Point*) new char[ (sal_uIntPtr) nNewSize * sizeof( Point ) ];
316 
317 		memcpy( pNewAry, mpPointAry, nPos * sizeof( Point ) );
318 		memcpy( pNewAry + nPos, mpPointAry + nSecPos, nRest * sizeof( Point ) );
319 
320 		delete[] (char*) mpPointAry;
321 
322 		// ggf. FlagArray beruecksichtigen
323 		if( mpFlagAry )
324 		{
325 			sal_uInt8* pNewFlagAry = new sal_uInt8[ nNewSize ];
326 
327 			memcpy( pNewFlagAry, mpFlagAry, nPos );
328 			memcpy( pNewFlagAry + nPos, mpFlagAry + nSecPos, nRest );
329 			delete[] mpFlagAry;
330 			mpFlagAry = pNewFlagAry;
331 		}
332 
333 		mpPointAry = pNewAry;
334 		mnPoints   = nNewSize;
335 	}
336 }
337 
338 // -----------------------------------------------------------------------
339 
ImplCreateFlagArray()340 void ImplPolygon::ImplCreateFlagArray()
341 {
342 	if( !mpFlagAry )
343 	{
344 		mpFlagAry = new sal_uInt8[ mnPoints ];
345 		memset( mpFlagAry, 0, mnPoints );
346 	}
347 }
348 
349 // =======================================================================
350 
ImplMakeUnique()351 inline void Polygon::ImplMakeUnique()
352 {
353 	// Falls noch andere Referenzen bestehen, dann kopieren
354 	if ( mpImplPolygon->mnRefCount != 1 )
355 	{
356 		if ( mpImplPolygon->mnRefCount )
357 			mpImplPolygon->mnRefCount--;
358 		mpImplPolygon = new ImplPolygon( *mpImplPolygon );
359 	}
360 }
361 
362 // -----------------------------------------------------------------------
363 
ImplGetAngle(const Point & rCenter,const Point & rPt)364 inline double ImplGetAngle( const Point& rCenter, const Point& rPt )
365 {
366 	const long nDX = rPt.X() - rCenter.X();
367 	return( atan2( -rPt.Y() + rCenter.Y(), ( ( nDX == 0L ) ? 0.000000001 : nDX ) ) );
368 }
369 
370 // -----------------------------------------------------------------------
371 
Polygon()372 Polygon::Polygon()
373 {
374 	DBG_CTOR( Polygon, NULL );
375 	mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
376 }
377 
378 // -----------------------------------------------------------------------
379 
Polygon(sal_uInt16 nSize)380 Polygon::Polygon( sal_uInt16 nSize )
381 {
382 	DBG_CTOR( Polygon, NULL );
383 
384 	if ( nSize )
385 		mpImplPolygon = new ImplPolygon( nSize );
386 	else
387 		mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
388 }
389 
390 // -----------------------------------------------------------------------
391 
Polygon(sal_uInt16 nPoints,const Point * pPtAry,const sal_uInt8 * pFlagAry)392 Polygon::Polygon( sal_uInt16 nPoints, const Point* pPtAry, const sal_uInt8* pFlagAry )
393 {
394 	DBG_CTOR( Polygon, NULL );
395 
396 	if( nPoints )
397 		mpImplPolygon = new ImplPolygon( nPoints, pPtAry, pFlagAry );
398 	else
399 		mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
400 }
401 
402 // -----------------------------------------------------------------------
403 
Polygon(const Polygon & rPoly)404 Polygon::Polygon( const Polygon& rPoly )
405 {
406 	DBG_CTOR( Polygon, NULL );
407 	DBG_CHKOBJ( &rPoly, Polygon, NULL );
408 	DBG_ASSERT( rPoly.mpImplPolygon->mnRefCount < 0xFFFFFFFE, "Polygon: RefCount overflow" );
409 
410 	mpImplPolygon = rPoly.mpImplPolygon;
411 	if ( mpImplPolygon->mnRefCount )
412 		mpImplPolygon->mnRefCount++;
413 }
414 
415 // -----------------------------------------------------------------------
416 
Polygon(const Rectangle & rRect)417 Polygon::Polygon( const Rectangle& rRect )
418 {
419 	DBG_CTOR( Polygon, NULL );
420 
421 	if ( rRect.IsEmpty() )
422 		mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
423 	else
424 	{
425 		mpImplPolygon = new ImplPolygon( 5 );
426 		mpImplPolygon->mpPointAry[0] = rRect.TopLeft();
427 		mpImplPolygon->mpPointAry[1] = rRect.TopRight();
428 		mpImplPolygon->mpPointAry[2] = rRect.BottomRight();
429 		mpImplPolygon->mpPointAry[3] = rRect.BottomLeft();
430 		mpImplPolygon->mpPointAry[4] = rRect.TopLeft();
431 	}
432 }
433 
434 // -----------------------------------------------------------------------
435 
Polygon(const Rectangle & rRect,sal_uIntPtr nHorzRound,sal_uIntPtr nVertRound)436 Polygon::Polygon( const Rectangle& rRect, sal_uIntPtr nHorzRound, sal_uIntPtr nVertRound )
437 {
438 	DBG_CTOR( Polygon, NULL );
439 
440 	if ( rRect.IsEmpty() )
441 		mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
442 	else
443 	{
444 		Rectangle aRect( rRect );
445 		aRect.Justify();			// SJ: i9140
446 
447 		nHorzRound = Min( nHorzRound, (sal_uIntPtr) labs( aRect.GetWidth() >> 1 ) );
448 		nVertRound = Min( nVertRound, (sal_uIntPtr) labs( aRect.GetHeight() >> 1 ) );
449 
450 		if( !nHorzRound && !nVertRound )
451 		{
452 			mpImplPolygon = new ImplPolygon( 5 );
453 			mpImplPolygon->mpPointAry[0] = aRect.TopLeft();
454 			mpImplPolygon->mpPointAry[1] = aRect.TopRight();
455 			mpImplPolygon->mpPointAry[2] = aRect.BottomRight();
456 			mpImplPolygon->mpPointAry[3] = aRect.BottomLeft();
457 			mpImplPolygon->mpPointAry[4] = aRect.TopLeft();
458 		}
459 		else
460 		{
461 			const Point		aTL( aRect.Left() + nHorzRound, aRect.Top() + nVertRound );
462 			const Point		aTR( aRect.Right() - nHorzRound, aRect.Top() + nVertRound );
463 			const Point		aBR( aRect.Right() - nHorzRound, aRect.Bottom() - nVertRound );
464 			const Point		aBL( aRect.Left() + nHorzRound, aRect.Bottom() - nVertRound );
465 			Polygon*		pEllipsePoly = new Polygon( Point(), nHorzRound, nVertRound );
466 			sal_uInt16			i, nEnd, nSize4 = pEllipsePoly->GetSize() >> 2;
467 
468 			mpImplPolygon = new ImplPolygon( pEllipsePoly->GetSize() + 1 );
469 
470 			const Point*	pSrcAry = pEllipsePoly->GetConstPointAry();
471 			Point*			pDstAry = mpImplPolygon->mpPointAry;
472 
473 			for( i = 0, nEnd = nSize4; i < nEnd; i++ )
474 				( pDstAry[ i ] = pSrcAry[ i ] ) += aTR;
475 
476 			for( nEnd = nEnd + nSize4; i < nEnd; i++ )
477 				( pDstAry[ i ] = pSrcAry[ i ] ) += aTL;
478 
479 			for( nEnd = nEnd + nSize4; i < nEnd; i++ )
480 				( pDstAry[ i ] = pSrcAry[ i ] ) += aBL;
481 
482 			for( nEnd = nEnd + nSize4; i < nEnd; i++ )
483 				( pDstAry[ i ] = pSrcAry[ i ] ) += aBR;
484 
485 			pDstAry[ nEnd ] = pDstAry[ 0 ];
486 			delete pEllipsePoly;
487 		}
488 	}
489 }
490 
491 // -----------------------------------------------------------------------
492 
Polygon(const Point & rCenter,long nRadX,long nRadY,sal_uInt16 nPoints)493 Polygon::Polygon( const Point& rCenter, long nRadX, long nRadY, sal_uInt16 nPoints )
494 {
495 	DBG_CTOR( Polygon, NULL );
496 
497 	if( nRadX && nRadY )
498 	{
499 		// Default berechnen (abhaengig von Groesse)
500 		if( !nPoints )
501 		{
502 			nPoints = (sal_uInt16) ( F_PI * ( 1.5 * ( nRadX + nRadY ) -
503 								 sqrt( (double) labs( nRadX * nRadY ) ) ) );
504 
505 			nPoints = (sal_uInt16) MinMax( nPoints, 32, 256 );
506 
507 			if( ( nRadX > 32 ) && ( nRadY > 32 ) && ( nRadX + nRadY ) < 8192 )
508 				nPoints >>= 1;
509 		}
510 
511 		// Anzahl der Punkte auf durch 4 teilbare Zahl aufrunden
512 		mpImplPolygon = new ImplPolygon( nPoints = (nPoints + 3) & ~3 );
513 
514 		Point* pPt;
515 		sal_uInt16 i;
516 		sal_uInt16 nPoints2 = nPoints >> 1;
517 		sal_uInt16 nPoints4 = nPoints >> 2;
518 		double nAngle;
519 		double nAngleStep = F_PI2 / ( nPoints4 - 1 );
520 
521 		for( i=0, nAngle = 0.0; i < nPoints4; i++, nAngle += nAngleStep )
522 		{
523 			long nX = FRound( nRadX * cos( nAngle ) );
524 			long nY = FRound( -nRadY * sin( nAngle ) );
525 
526 			pPt = &(mpImplPolygon->mpPointAry[i]);
527 			pPt->X() =	nX + rCenter.X();
528 			pPt->Y() =	nY + rCenter.Y();
529 			pPt = &(mpImplPolygon->mpPointAry[nPoints2-i-1]);
530 			pPt->X() = -nX + rCenter.X();
531 			pPt->Y() =	nY + rCenter.Y();
532 			pPt = &(mpImplPolygon->mpPointAry[i+nPoints2]);
533 			pPt->X() = -nX + rCenter.X();
534 			pPt->Y() = -nY + rCenter.Y();
535 			pPt = &(mpImplPolygon->mpPointAry[nPoints-i-1]);
536 			pPt->X() =	nX + rCenter.X();
537 			pPt->Y() = -nY + rCenter.Y();
538 		}
539 	}
540 	else
541 		mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
542 }
543 
544 // -----------------------------------------------------------------------
545 
Polygon(const Rectangle & rBound,const Point & rStart,const Point & rEnd,PolyStyle eStyle)546 Polygon::Polygon( const Rectangle& rBound,
547 				  const Point& rStart, const Point& rEnd, PolyStyle eStyle )
548 {
549 	DBG_CTOR( Polygon, NULL );
550 
551 	const long	nWidth = rBound.GetWidth();
552 	const long	nHeight = rBound.GetHeight();
553 
554 	if( ( nWidth > 1 ) && ( nHeight > 1 ) )
555 	{
556 		const Point aCenter( rBound.Center() );
557 		const long	nRadX = aCenter.X() - rBound.Left();
558 		const long	nRadY = aCenter.Y() - rBound.Top();
559 		sal_uInt16		nPoints;
560 
561 		nPoints = (sal_uInt16) ( F_PI * ( 1.5 * ( nRadX + nRadY ) -
562 							 sqrt( (double) labs( nRadX * nRadY ) ) ) );
563 
564 		nPoints = (sal_uInt16) MinMax( nPoints, 32, 256 );
565 
566 		if( ( nRadX > 32 ) && ( nRadY > 32 ) && ( nRadX + nRadY ) < 8192 )
567 			nPoints >>= 1;
568 
569 		// Winkel berechnen
570 		const double	fRadX = nRadX;
571 		const double	fRadY = nRadY;
572 		const double	fCenterX = aCenter.X();
573 		const double	fCenterY = aCenter.Y();
574 		double			fStart = ImplGetAngle( aCenter, rStart );
575 		double			fEnd = ImplGetAngle( aCenter, rEnd );
576 		double			fDiff = fEnd - fStart;
577 		double			fStep;
578 		sal_uInt16			nStart;
579 		sal_uInt16			nEnd;
580 
581 		if( fDiff < 0. )
582 			fDiff += F_2PI;
583 
584 		// Punktanzahl proportional verkleinern ( fDiff / (2PI) );
585 		// ist eingentlich nur fuer einen Kreis richtig; wir
586 		// machen es hier aber trotzdem
587 		nPoints = Max( (sal_uInt16) ( ( fDiff * 0.1591549 ) * nPoints ), (sal_uInt16) 16 );
588 		fStep = fDiff / ( nPoints - 1 );
589 
590 		if( POLY_PIE == eStyle )
591 		{
592 			const Point aCenter2( FRound( fCenterX ), FRound( fCenterY ) );
593 
594 			nStart = 1;
595 			nEnd = nPoints + 1;
596 			mpImplPolygon = new ImplPolygon( nPoints + 2 );
597 			mpImplPolygon->mpPointAry[ 0 ] = aCenter2;
598 			mpImplPolygon->mpPointAry[ nEnd ] = aCenter2;
599 		}
600 		else
601 		{
602 			mpImplPolygon = new ImplPolygon( ( POLY_CHORD == eStyle ) ? ( nPoints + 1 ) : nPoints );
603 			nStart = 0;
604 			nEnd = nPoints;
605 		}
606 
607 		for(; nStart < nEnd; nStart++, fStart += fStep )
608 		{
609 			Point& rPt = mpImplPolygon->mpPointAry[ nStart ];
610 
611 			rPt.X() = FRound( fCenterX + fRadX * cos( fStart ) );
612 			rPt.Y() = FRound( fCenterY - fRadY * sin( fStart ) );
613 		}
614 
615 		if( POLY_CHORD == eStyle )
616 			mpImplPolygon->mpPointAry[ nPoints ] = mpImplPolygon->mpPointAry[ 0 ];
617 	}
618 	else
619 		mpImplPolygon = (ImplPolygon*) &aStaticImplPolygon;
620 }
621 
622 // -----------------------------------------------------------------------
623 
Polygon(const Point & rBezPt1,const Point & rCtrlPt1,const Point & rBezPt2,const Point & rCtrlPt2,sal_uInt16 nPoints)624 Polygon::Polygon( const Point& rBezPt1, const Point& rCtrlPt1,
625 				  const Point& rBezPt2, const Point& rCtrlPt2,
626 				  sal_uInt16 nPoints )
627 {
628 	DBG_CTOR( Polygon, NULL );
629 
630 	nPoints = ( 0 == nPoints ) ? 25 : ( ( nPoints < 2 ) ? 2 : nPoints );
631 
632 	const double	fInc = 1.0 / ( nPoints - 1 );
633 	double			fK_1 = 0.0, fK1_1 = 1.0;
634 	double			fK_2, fK_3, fK1_2, fK1_3, fK12, fK21;
635 	const double	fX0 = rBezPt1.X();
636 	const double	fY0 = rBezPt1.Y();
637 	const double	fX1 = 3.0 * rCtrlPt1.X();
638 	const double	fY1 = 3.0 * rCtrlPt1.Y();
639 	const double	fX2 = 3.0 * rCtrlPt2.X();;
640 	const double	fY2 = 3.0 * rCtrlPt2.Y();;
641 	const double	fX3 = rBezPt2.X();
642 	const double	fY3 = rBezPt2.Y();
643 
644 	mpImplPolygon = new ImplPolygon( nPoints );
645 
646 	for( sal_uInt16 i = 0; i < nPoints; i++, fK_1 += fInc, fK1_1 -= fInc )
647 	{
648 		Point& rPt = mpImplPolygon->mpPointAry[ i ];
649 
650 		fK_2 = fK_1, fK_3 = ( fK_2 *= fK_1 ), fK_3 *= fK_1;
651 		fK1_2 = fK1_1, fK1_3 = ( fK1_2 *= fK1_1 ), fK1_3 *= fK1_1;
652 		fK12 = fK_1 * fK1_2, fK21 = fK_2 * fK1_1;
653 
654 		rPt.X() = FRound( fK1_3 * fX0 + fK12 * fX1 + fK21 * fX2 + fK_3 * fX3 );
655 		rPt.Y() = FRound( fK1_3 * fY0 + fK12 * fY1 + fK21 * fY2 + fK_3 * fY3 );
656 	}
657 }
658 
659 // -----------------------------------------------------------------------
660 
~Polygon()661 Polygon::~Polygon()
662 {
663 	DBG_DTOR( Polygon, NULL );
664 
665 	// Wenn es keine statischen ImpDaten sind, dann loeschen, wenn es
666 	// die letzte Referenz ist, sonst Referenzcounter decrementieren
667 	if ( mpImplPolygon->mnRefCount )
668 	{
669 		if ( mpImplPolygon->mnRefCount > 1 )
670 			mpImplPolygon->mnRefCount--;
671 		else
672 			delete mpImplPolygon;
673 	}
674 }
675 
676 // -----------------------------------------------------------------------
677 
ImplGetPointAry()678 Point* Polygon::ImplGetPointAry()
679 {
680 	DBG_CHKTHIS( Polygon, NULL );
681 
682 	ImplMakeUnique();
683 	return (Point*)mpImplPolygon->mpPointAry;
684 }
685 
686 // -----------------------------------------------------------------------
687 
ImplGetFlagAry()688 sal_uInt8* Polygon::ImplGetFlagAry()
689 {
690 	DBG_CHKTHIS( Polygon, NULL );
691 
692 	ImplMakeUnique();
693 	mpImplPolygon->ImplCreateFlagArray();
694 	return mpImplPolygon->mpFlagAry;
695 }
696 
697 // -----------------------------------------------------------------------
698 
GetConstPointAry() const699 const Point* Polygon::GetConstPointAry() const
700 {
701 	DBG_CHKTHIS( Polygon, NULL );
702 	return (Point*)mpImplPolygon->mpPointAry;
703 }
704 
705 // -----------------------------------------------------------------------
706 
GetConstFlagAry() const707 const sal_uInt8* Polygon::GetConstFlagAry() const
708 {
709 	DBG_CHKTHIS( Polygon, NULL );
710 	return mpImplPolygon->mpFlagAry;
711 }
712 
713 // -----------------------------------------------------------------------
714 
SetPoint(const Point & rPt,sal_uInt16 nPos)715 void Polygon::SetPoint( const Point& rPt, sal_uInt16 nPos )
716 {
717 	DBG_CHKTHIS( Polygon, NULL );
718 	DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
719 				"Polygon::SetPoint(): nPos >= nPoints" );
720 
721 	ImplMakeUnique();
722 	mpImplPolygon->mpPointAry[nPos] = rPt;
723 }
724 
725 // -----------------------------------------------------------------------
726 
SetFlags(sal_uInt16 nPos,PolyFlags eFlags)727 void Polygon::SetFlags( sal_uInt16 nPos, PolyFlags eFlags )
728 {
729 	DBG_CHKTHIS( Polygon, NULL );
730 	DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
731 				"Polygon::SetFlags(): nPos >= nPoints" );
732 
733 	// we do only want to create the flag array if there
734 	// is at least one flag different to POLY_NORMAL
735 	if ( mpImplPolygon || ( eFlags != POLY_NORMAL ) )
736 	{
737 		ImplMakeUnique();
738 		mpImplPolygon->ImplCreateFlagArray();
739 		mpImplPolygon->mpFlagAry[ nPos ] = (sal_uInt8) eFlags;
740 	}
741 }
742 
743 // -----------------------------------------------------------------------
744 
GetPoint(sal_uInt16 nPos) const745 const Point& Polygon::GetPoint( sal_uInt16 nPos ) const
746 {
747 	DBG_CHKTHIS( Polygon, NULL );
748 	DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
749 				"Polygon::GetPoint(): nPos >= nPoints" );
750 
751 	return mpImplPolygon->mpPointAry[nPos];
752 }
753 
754 // -----------------------------------------------------------------------
755 
GetFlags(sal_uInt16 nPos) const756 PolyFlags Polygon::GetFlags( sal_uInt16 nPos ) const
757 {
758 	DBG_CHKTHIS( Polygon, NULL );
759 	DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
760 				"Polygon::GetFlags(): nPos >= nPoints" );
761 	return( mpImplPolygon->mpFlagAry ?
762 			(PolyFlags) mpImplPolygon->mpFlagAry[ nPos ] :
763 			POLY_NORMAL );
764 }
765 
766 // -----------------------------------------------------------------------
767 
HasFlags() const768 sal_Bool Polygon::HasFlags() const
769 {
770 	return mpImplPolygon->mpFlagAry != NULL;
771 }
772 
773 // -----------------------------------------------------------------------
774 
IsControl(sal_uInt16 nPos) const775 sal_Bool Polygon::IsControl(sal_uInt16 nPos) const
776 {
777 	DBG_CHKTHIS( Polygon, NULL );
778 	DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
779 				"Polygon::GetFlags(): nPos >= nPoints" );
780 	PolyFlags eFlags = mpImplPolygon->mpFlagAry ?
781 					   (PolyFlags) mpImplPolygon->mpFlagAry[ nPos ] : POLY_NORMAL;
782 
783 	return( POLY_CONTROL == eFlags );
784 }
785 
786 // -----------------------------------------------------------------------
787 
IsSmooth(sal_uInt16 nPos) const788 sal_Bool Polygon::IsSmooth(sal_uInt16 nPos) const
789 {
790 	DBG_CHKTHIS( Polygon, NULL );
791 	DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
792 				"Polygon::GetFlags(): nPos >= nPoints" );
793 	PolyFlags eFlags = mpImplPolygon->mpFlagAry ?
794 					   (PolyFlags) mpImplPolygon->mpFlagAry[ nPos ] : POLY_NORMAL;
795 
796 	return( ( POLY_SMOOTH == eFlags ) || ( POLY_SYMMTR == eFlags ) );
797 }
798 
799 // -----------------------------------------------------------------------
800 
IsRect() const801 sal_Bool Polygon::IsRect() const
802 {
803 	sal_Bool bIsRect = sal_False;
804 	if ( mpImplPolygon->mpFlagAry == NULL )
805 	{
806 		if ( ( ( mpImplPolygon->mnPoints == 5 ) && ( mpImplPolygon->mpPointAry[ 0 ] == mpImplPolygon->mpPointAry[ 4 ] ) ) ||
807 				( mpImplPolygon->mnPoints == 4 ) )
808 		{
809 			if ( ( mpImplPolygon->mpPointAry[ 0 ].X() == mpImplPolygon->mpPointAry[ 3 ].X() ) &&
810 					( mpImplPolygon->mpPointAry[ 0 ].Y() == mpImplPolygon->mpPointAry[ 1 ].Y() ) &&
811 						( mpImplPolygon->mpPointAry[ 1 ].X() == mpImplPolygon->mpPointAry[ 2 ].X() ) &&
812 							( mpImplPolygon->mpPointAry[ 2 ].Y() == mpImplPolygon->mpPointAry[ 3 ].Y() ) )
813 				bIsRect = sal_True;
814 		}
815 	}
816 	return bIsRect;
817 }
818 
819 // -----------------------------------------------------------------------
820 
SetSize(sal_uInt16 nNewSize)821 void Polygon::SetSize( sal_uInt16 nNewSize )
822 {
823 	DBG_CHKTHIS( Polygon, NULL );
824 
825 	if( nNewSize != mpImplPolygon->mnPoints )
826 	{
827 		ImplMakeUnique();
828 		mpImplPolygon->ImplSetSize( nNewSize );
829 	}
830 }
831 
832 // -----------------------------------------------------------------------
833 
GetSize() const834 sal_uInt16 Polygon::GetSize() const
835 {
836 	DBG_CHKTHIS( Polygon, NULL );
837 
838 	return mpImplPolygon->mnPoints;
839 }
840 
841 // -----------------------------------------------------------------------
842 
Clear()843 void Polygon::Clear()
844 {
845 	DBG_CHKTHIS( Polygon, NULL );
846 
847 	if ( mpImplPolygon->mnRefCount )
848 	{
849 		if ( mpImplPolygon->mnRefCount > 1 )
850 			mpImplPolygon->mnRefCount--;
851 		else
852 			delete mpImplPolygon;
853 	}
854 
855 	mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
856 }
857 
858 // -----------------------------------------------------------------------
859 
CalcDistance(sal_uInt16 nP1,sal_uInt16 nP2)860 double Polygon::CalcDistance( sal_uInt16 nP1, sal_uInt16 nP2 )
861 {
862 	DBG_ASSERT( nP1 < mpImplPolygon->mnPoints,
863 				"Polygon::CalcDistance(): nPos1 >= nPoints" );
864 	DBG_ASSERT( nP2 < mpImplPolygon->mnPoints,
865 				"Polygon::CalcDistance(): nPos2 >= nPoints" );
866 
867 	const Point& rP1 = mpImplPolygon->mpPointAry[ nP1 ];
868 	const Point& rP2 = mpImplPolygon->mpPointAry[ nP2 ];
869 	const double fDx = rP2.X() - rP1.X();
870 	const double fDy = rP2.Y() - rP1.Y();
871 
872 	return sqrt( fDx * fDx + fDy * fDy );
873 }
874 
875 // -----------------------------------------------------------------------
876 
Optimize(sal_uIntPtr nOptimizeFlags,const PolyOptimizeData * pData)877 void Polygon::Optimize( sal_uIntPtr nOptimizeFlags, const PolyOptimizeData* pData )
878 {
879 	DBG_CHKTHIS( Polygon, NULL );
880 	DBG_ASSERT( !mpImplPolygon->mpFlagAry, "Optimizing could fail with beziers!" );
881 
882 	sal_uInt16 nSize = mpImplPolygon->mnPoints;
883 
884 	if( nOptimizeFlags && nSize )
885 	{
886 		if( nOptimizeFlags & POLY_OPTIMIZE_EDGES )
887 		{
888 			const Rectangle	aBound( GetBoundRect() );
889 			const double	fArea = ( aBound.GetWidth() + aBound.GetHeight() ) * 0.5;
890 			const sal_uInt16	nPercent = pData ? pData->GetPercentValue() : 50;
891 
892 			Optimize( POLY_OPTIMIZE_NO_SAME );
893 			ImplReduceEdges( *this, fArea, nPercent );
894 		}
895 		else if( nOptimizeFlags & ( POLY_OPTIMIZE_REDUCE | POLY_OPTIMIZE_NO_SAME ) )
896 		{
897 			Polygon			aNewPoly;
898 			const Point&	rFirst = mpImplPolygon->mpPointAry[ 0 ];
899 			sal_uIntPtr			nReduce;
900 
901 			if( nOptimizeFlags & ( POLY_OPTIMIZE_REDUCE ) )
902 				nReduce = pData ? pData->GetAbsValue() : 4UL;
903 			else
904 				nReduce = 0UL;
905 
906 			while( nSize && ( mpImplPolygon->mpPointAry[ nSize - 1 ] == rFirst ) )
907 				nSize--;
908 
909 			if( nSize > 1 )
910 			{
911 				sal_uInt16 nLast = 0, nNewCount = 1;
912 
913 				aNewPoly.SetSize( nSize );
914 				aNewPoly[ 0 ] = rFirst;
915 
916 				for( sal_uInt16 i = 1; i < nSize; i++ )
917 				{
918 					if( ( mpImplPolygon->mpPointAry[ i ] != mpImplPolygon->mpPointAry[ nLast ] ) &&
919 						( !nReduce || ( nReduce < (sal_uIntPtr) FRound( CalcDistance( nLast, i ) ) ) ) )
920 					{
921 						aNewPoly[ nNewCount++ ] = mpImplPolygon->mpPointAry[ nLast = i ];
922 					}
923 				}
924 
925 				if( nNewCount == 1 )
926 					aNewPoly.Clear();
927 				else
928 					aNewPoly.SetSize( nNewCount );
929 			}
930 
931 			*this = aNewPoly;
932 		}
933 
934 		nSize = mpImplPolygon->mnPoints;
935 
936 		if( nSize > 1 )
937 		{
938 			if( ( nOptimizeFlags & POLY_OPTIMIZE_CLOSE ) &&
939 				( mpImplPolygon->mpPointAry[ 0 ] != mpImplPolygon->mpPointAry[ nSize - 1 ] ) )
940 			{
941 				SetSize( mpImplPolygon->mnPoints + 1 );
942 				mpImplPolygon->mpPointAry[ mpImplPolygon->mnPoints - 1 ] = mpImplPolygon->mpPointAry[ 0 ];
943 			}
944 			else if( ( nOptimizeFlags & POLY_OPTIMIZE_OPEN ) &&
945 					 ( mpImplPolygon->mpPointAry[ 0 ] == mpImplPolygon->mpPointAry[ nSize - 1 ] ) )
946 			{
947 				const Point& rFirst = mpImplPolygon->mpPointAry[ 0 ];
948 
949 				while( nSize && ( mpImplPolygon->mpPointAry[ nSize - 1 ] == rFirst ) )
950 					nSize--;
951 
952 				SetSize( nSize );
953 			}
954 		}
955 	}
956 }
957 
958 // =======================================================================
959 
960 /* Recursively subdivide cubic bezier curve via deCasteljau.
961 
962    @param rPointIter
963    Output iterator, where the subdivided polylines are written to.
964 
965    @param d
966    Squared difference of curve to a straight line
967 
968    @param P*
969    Exactly four points, interpreted as support and control points of
970    a cubic bezier curve. Must be in device coordinates, since stop
971    criterion is based on the following assumption: the device has a
972    finite resolution, it is thus sufficient to stop subdivision if the
973    curve does not deviate more than one pixel from a straight line.
974 
975 */
ImplAdaptiveSubdivide(::std::back_insert_iterator<::std::vector<Point>> & rPointIter,const double old_d2,int recursionDepth,const double d2,const double P1x,const double P1y,const double P2x,const double P2y,const double P3x,const double P3y,const double P4x,const double P4y)976 static void ImplAdaptiveSubdivide( ::std::back_insert_iterator< ::std::vector< Point > >& rPointIter,
977                                    const double old_d2,
978                                    int recursionDepth,
979                                    const double d2,
980                                    const double P1x, const double P1y,
981                                    const double P2x, const double P2y,
982                                    const double P3x, const double P3y,
983                                    const double P4x, const double P4y )
984 {
985     // Hard limit on recursion depth, empiric number.
986     enum {maxRecursionDepth=128};
987 
988     // Perform bezier flatness test (lecture notes from R. Schaback,
989     // Mathematics of Computer-Aided Design, Uni Goettingen, 2000)
990     //
991     // ||P(t) - L(t)|| <= max     ||b_j - b_0 - j/n(b_n - b_0)||
992     //                    0<=j<=n
993     //
994     // What is calculated here is an upper bound to the distance from
995     // a line through b_0 and b_3 (P1 and P4 in our notation) and the
996     // curve. We can drop 0 and n from the running indices, since the
997     // argument of max becomes zero for those cases.
998     const double fJ1x( P2x - P1x - 1.0/3.0*(P4x - P1x) );
999     const double fJ1y( P2y - P1y - 1.0/3.0*(P4y - P1y) );
1000     const double fJ2x( P3x - P1x - 2.0/3.0*(P4x - P1x) );
1001     const double fJ2y( P3y - P1y - 2.0/3.0*(P4y - P1y) );
1002     const double distance2( ::std::max( fJ1x*fJ1x + fJ1y*fJ1y,
1003                                         fJ2x*fJ2x + fJ2y*fJ2y) );
1004 
1005     // stop if error measure does not improve anymore. This is a
1006     // safety guard against floating point inaccuracies.
1007     // stop at recursion level 128. This is a safety guard against
1008     // floating point inaccuracies.
1009     // stop if distance from line is guaranteed to be bounded by d
1010     if( old_d2 > d2 &&
1011         recursionDepth < maxRecursionDepth &&
1012         distance2 >= d2 )
1013     {
1014         // deCasteljau bezier arc, split at t=0.5
1015         // Foley/vanDam, p. 508
1016         const double L1x( P1x ), 		   	 L1y( P1y );
1017         const double L2x( (P1x + P2x)*0.5 ), L2y( (P1y + P2y)*0.5 );
1018         const double Hx ( (P2x + P3x)*0.5 ), Hy ( (P2y + P3y)*0.5 );
1019         const double L3x( (L2x + Hx)*0.5 ),  L3y( (L2y + Hy)*0.5 );
1020         const double R4x( P4x ), 		   	 R4y( P4y );
1021         const double R3x( (P3x + P4x)*0.5 ), R3y( (P3y + P4y)*0.5 );
1022         const double R2x( (Hx + R3x)*0.5 ),  R2y( (Hy + R3y)*0.5 );
1023         const double R1x( (L3x + R2x)*0.5 ), R1y( (L3y + R2y)*0.5 );
1024         const double L4x( R1x ), 		     L4y( R1y );
1025 
1026 		// subdivide further
1027         ++recursionDepth;
1028         ImplAdaptiveSubdivide(rPointIter, distance2, recursionDepth, d2, L1x, L1y, L2x, L2y, L3x, L3y, L4x, L4y);
1029         ImplAdaptiveSubdivide(rPointIter, distance2, recursionDepth, d2, R1x, R1y, R2x, R2y, R3x, R3y, R4x, R4y);
1030     }
1031 	else
1032 	{
1033 		// requested resolution reached.
1034 		// Add end points to output iterator.
1035 		// order is preserved, since this is so to say depth first traversal.
1036 		*rPointIter++ = Point( FRound(P1x), FRound(P1y) );
1037 	}
1038 }
1039 
1040 // =======================================================================
1041 
AdaptiveSubdivide(Polygon & rResult,const double d) const1042 void Polygon::AdaptiveSubdivide( Polygon& rResult, const double d ) const
1043 {
1044 	if( !mpImplPolygon->mpFlagAry )
1045 	{
1046 		rResult = *this;
1047 	}
1048 	else
1049 	{
1050 		sal_uInt16 i;
1051 		sal_uInt16 nPts( GetSize() );
1052 		::std::vector< Point > aPoints;
1053         aPoints.reserve( nPts );
1054 		::std::back_insert_iterator< ::std::vector< Point > > aPointIter( aPoints );
1055 
1056 		for(i=0; i<nPts;)
1057 		{
1058 			if( ( i + 3 ) < nPts )
1059             {
1060                 sal_uInt8 P1( mpImplPolygon->mpFlagAry[ i ] );
1061                 sal_uInt8 P4( mpImplPolygon->mpFlagAry[ i + 3 ] );
1062 
1063                 if( ( POLY_NORMAL == P1 || POLY_SMOOTH == P1 || POLY_SYMMTR == P1 ) &&
1064                     ( POLY_CONTROL == mpImplPolygon->mpFlagAry[ i + 1 ] ) &&
1065                     ( POLY_CONTROL == mpImplPolygon->mpFlagAry[ i + 2 ] ) &&
1066                     ( POLY_NORMAL == P4 || POLY_SMOOTH == P4 || POLY_SYMMTR == P4 ) )
1067                 {
1068                     ImplAdaptiveSubdivide( aPointIter, d*d+1.0, 0, d*d,
1069                                            mpImplPolygon->mpPointAry[ i ].X(),   mpImplPolygon->mpPointAry[ i ].Y(),
1070                                            mpImplPolygon->mpPointAry[ i+1 ].X(), mpImplPolygon->mpPointAry[ i+1 ].Y(),
1071                                            mpImplPolygon->mpPointAry[ i+2 ].X(), mpImplPolygon->mpPointAry[ i+2 ].Y(),
1072                                            mpImplPolygon->mpPointAry[ i+3 ].X(), mpImplPolygon->mpPointAry[ i+3 ].Y() );
1073                     i += 3;
1074                     continue;
1075                 }
1076             }
1077 
1078             *aPointIter++ = mpImplPolygon->mpPointAry[ i++ ];
1079 
1080             if (aPoints.size() >= SAL_MAX_UINT16)
1081             {
1082                 OSL_ENSURE(aPoints.size() < SAL_MAX_UINT16,
1083                     "Polygon::AdapativeSubdivision created polygon too many points;"
1084                     " using original polygon instead");
1085 
1086                 // The resulting polygon can not hold all the points
1087                 // that we have created so far.  Stop the subdivision
1088                 // and return a copy of the unmodified polygon.
1089                 rResult = *this;
1090                 return;
1091             }
1092 		}
1093 
1094 		// fill result polygon
1095 		rResult = Polygon( (sal_uInt16)aPoints.size() ); // ensure sufficient size for copy
1096 		::std::copy(aPoints.begin(), aPoints.end(), rResult.mpImplPolygon->mpPointAry);
1097 	}
1098 }
1099 
1100 // -----------------------------------------------------------------------
1101 
GetIntersection(const PolyPolygon & rPolyPoly,PolyPolygon & rResult) const1102 void Polygon::GetIntersection( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
1103 {
1104 	const PolyPolygon aTmp( *this );
1105 	aTmp.GetIntersection( rPolyPoly, rResult );
1106 }
1107 
1108 // -----------------------------------------------------------------------
1109 
GetUnion(const PolyPolygon & rPolyPoly,PolyPolygon & rResult) const1110 void Polygon::GetUnion( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
1111 {
1112 	const PolyPolygon aTmp( *this );
1113 	aTmp.GetUnion( rPolyPoly, rResult );
1114 }
1115 
1116 // -----------------------------------------------------------------------
1117 
GetDifference(const PolyPolygon & rPolyPoly,PolyPolygon & rResult) const1118 void Polygon::GetDifference( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
1119 {
1120 	const PolyPolygon aTmp( *this );
1121 	aTmp.GetDifference( rPolyPoly, rResult );
1122 }
1123 
1124 // -----------------------------------------------------------------------
1125 
GetXOR(const PolyPolygon & rPolyPoly,PolyPolygon & rResult) const1126 void Polygon::GetXOR( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
1127 {
1128 	const PolyPolygon aTmp( *this );
1129 	aTmp.GetXOR( rPolyPoly, rResult );
1130 }
1131 
1132 // -----------------------------------------------------------------------
1133 
ImplReduceEdges(Polygon & rPoly,const double & rArea,sal_uInt16 nPercent)1134 void Polygon::ImplReduceEdges( Polygon& rPoly, const double& rArea, sal_uInt16 nPercent )
1135 {
1136 	const double	fBound = 2000.0 * ( 100 - nPercent ) * 0.01;
1137 	sal_uInt16			nNumNoChange = 0, nNumRuns = 0;
1138 
1139 	while( nNumNoChange < 2 )
1140 	{
1141 		sal_uInt16	nPntCnt = rPoly.GetSize(), nNewPos = 0;
1142 		Polygon	aNewPoly( nPntCnt );
1143 		sal_Bool	bChangeInThisRun = sal_False;
1144 
1145 		for( sal_uInt16 n = 0; n < nPntCnt; n++ )
1146 		{
1147 			sal_Bool bDeletePoint = sal_False;
1148 
1149 			if( ( n + nNumRuns ) % 2 )
1150 			{
1151 				sal_uInt16		nIndPrev = !n ? nPntCnt - 1 : n - 1;
1152 				sal_uInt16		nIndPrevPrev = !nIndPrev ? nPntCnt - 1 : nIndPrev - 1;
1153 				sal_uInt16		nIndNext = ( n == nPntCnt-1 ) ? 0 : n + 1;
1154 				sal_uInt16		nIndNextNext = ( nIndNext == nPntCnt - 1 ) ? 0 : nIndNext + 1;
1155 				Vector2D	aVec1( rPoly[ nIndPrev ] ); aVec1 -= rPoly[ nIndPrevPrev ];
1156 				Vector2D	aVec2( rPoly[ n ] ); aVec2 -= rPoly[ nIndPrev ];
1157 				Vector2D	aVec3( rPoly[ nIndNext ] ); aVec3 -= rPoly[ n ];
1158 				Vector2D	aVec4( rPoly[ nIndNextNext ] ); aVec4 -= rPoly[ nIndNext ];
1159 				double		fDist1 = aVec1.GetLength(), fDist2 = aVec2.GetLength();
1160 				double		fDist3 = aVec3.GetLength(), fDist4 = aVec4.GetLength();
1161 				double		fTurnB = aVec2.Normalize().Scalar( aVec3.Normalize() );
1162 
1163 				if( fabs( fTurnB ) < ( 1.0 + SMALL_DVALUE ) && fabs( fTurnB ) > ( 1.0 - SMALL_DVALUE ) )
1164 					bDeletePoint = sal_True;
1165 				else
1166 				{
1167 					Vector2D	aVecB( rPoly[ nIndNext ] );
1168 					double		fDistB = ( aVecB -= rPoly[ nIndPrev ] ).GetLength();
1169 					double		fLenWithB = fDist2 + fDist3;
1170 					double		fLenFact = ( fDistB != 0.0 ) ? fLenWithB / fDistB : 1.0;
1171 					double		fTurnPrev = aVec1.Normalize().Scalar( aVec2 );
1172 					double		fTurnNext = aVec3.Scalar( aVec4.Normalize() );
1173 					double		fGradPrev, fGradB, fGradNext;
1174 
1175 					if( fabs( fTurnPrev ) < ( 1.0 + SMALL_DVALUE ) && fabs( fTurnPrev ) > ( 1.0 - SMALL_DVALUE ) )
1176 						fGradPrev = 0.0;
1177 					else
1178 						fGradPrev = acos( fTurnPrev ) / ( aVec1.IsNegative( aVec2 ) ? -F_PI180 : F_PI180 );
1179 
1180 					fGradB = acos( fTurnB ) / ( aVec2.IsNegative( aVec3 ) ? -F_PI180 : F_PI180 );
1181 
1182 					if( fabs( fTurnNext ) < ( 1.0 + SMALL_DVALUE ) && fabs( fTurnNext ) > ( 1.0 - SMALL_DVALUE ) )
1183 						fGradNext = 0.0;
1184 					else
1185 						fGradNext = acos( fTurnNext ) / ( aVec3.IsNegative( aVec4 ) ? -F_PI180 : F_PI180 );
1186 
1187 					if( ( fGradPrev > 0.0 && fGradB < 0.0 && fGradNext > 0.0 ) ||
1188 						( fGradPrev < 0.0 && fGradB > 0.0 && fGradNext < 0.0 ) )
1189 					{
1190 						if( ( fLenFact < ( FSQRT2 + SMALL_DVALUE ) ) &&
1191 							( ( ( fDist1 + fDist4 ) / ( fDist2 + fDist3 ) ) * 2000.0 ) > fBound )
1192 						{
1193 							bDeletePoint = sal_True;
1194 						}
1195 					}
1196 					else
1197 					{
1198 						double fRelLen = 1.0 - sqrt( fDistB / rArea );
1199 
1200 						if( fRelLen < 0.0 )
1201 							fRelLen = 0.0;
1202 						else if( fRelLen > 1.0 )
1203 							fRelLen = 1.0;
1204 
1205 						if( ( (sal_uInt32) ( ( ( fLenFact - 1.0 ) * 1000000.0 ) + 0.5 ) < fBound ) &&
1206 							( fabs( fGradB ) <= ( fRelLen * fBound * 0.01 ) ) )
1207 						{
1208 							bDeletePoint = sal_True;
1209 						}
1210 					}
1211 				}
1212 			}
1213 
1214 			if( !bDeletePoint )
1215 				aNewPoly[ nNewPos++ ] = rPoly[ n ];
1216 			else
1217 				bChangeInThisRun = sal_True;
1218 		}
1219 
1220 		if( bChangeInThisRun && nNewPos )
1221 		{
1222 			aNewPoly.SetSize( nNewPos );
1223 			rPoly = aNewPoly;
1224 			nNumNoChange = 0;
1225 		}
1226 		else
1227 			nNumNoChange++;
1228 
1229 		nNumRuns++;
1230 	}
1231 }
1232 
1233 // -----------------------------------------------------------------------
1234 
Move(long nHorzMove,long nVertMove)1235 void Polygon::Move( long nHorzMove, long nVertMove )
1236 {
1237 	DBG_CHKTHIS( Polygon, NULL );
1238 
1239 	// Diese Abfrage sollte man fuer die DrawEngine durchfuehren
1240 	if ( !nHorzMove && !nVertMove )
1241 		return;
1242 
1243 	ImplMakeUnique();
1244 
1245 	// Punkte verschieben
1246 	sal_uInt16 nCount = mpImplPolygon->mnPoints;
1247 	for ( sal_uInt16 i = 0; i < nCount; i++ )
1248 	{
1249 		Point* pPt = &(mpImplPolygon->mpPointAry[i]);
1250 		pPt->X() += nHorzMove;
1251 		pPt->Y() += nVertMove;
1252 	}
1253 }
1254 
1255 // -----------------------------------------------------------------------
1256 
Translate(const Point & rTrans)1257 void Polygon::Translate(const Point& rTrans)
1258 {
1259 	DBG_CHKTHIS( Polygon, NULL );
1260 	ImplMakeUnique();
1261 
1262 	for ( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1263 		mpImplPolygon->mpPointAry[ i ] += rTrans;
1264 }
1265 
1266 // -----------------------------------------------------------------------
1267 
Scale(double fScaleX,double fScaleY)1268 void Polygon::Scale( double fScaleX, double fScaleY )
1269 {
1270 	DBG_CHKTHIS( Polygon, NULL );
1271 	ImplMakeUnique();
1272 
1273 	for ( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1274 	{
1275 		Point& rPnt = mpImplPolygon->mpPointAry[i];
1276 		rPnt.X() = (long) ( fScaleX * rPnt.X() );
1277 		rPnt.Y() = (long) ( fScaleY * rPnt.Y() );
1278 	}
1279 }
1280 
1281 // -----------------------------------------------------------------------
1282 
Rotate(const Point & rCenter,sal_uInt16 nAngle10)1283 void Polygon::Rotate( const Point& rCenter, sal_uInt16 nAngle10 )
1284 {
1285 	DBG_CHKTHIS( Polygon, NULL );
1286 	nAngle10 %= 3600;
1287 
1288 	if( nAngle10 )
1289 	{
1290 		const double fAngle = F_PI1800 * nAngle10;
1291 		Rotate( rCenter, sin( fAngle ), cos( fAngle ) );
1292 	}
1293 }
1294 
1295 // -----------------------------------------------------------------------
1296 
Rotate(const Point & rCenter,double fSin,double fCos)1297 void Polygon::Rotate( const Point& rCenter, double fSin, double fCos )
1298 {
1299 	DBG_CHKTHIS( Polygon, NULL );
1300 	ImplMakeUnique();
1301 
1302 	long nX, nY;
1303 	long nCenterX = rCenter.X();
1304 	long nCenterY = rCenter.Y();
1305 
1306 	for( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1307 	{
1308 		Point& rPt = mpImplPolygon->mpPointAry[ i ];
1309 
1310 		nX = rPt.X() - nCenterX;
1311 		nY = rPt.Y() - nCenterY;
1312 		rPt.X() = (long) FRound( fCos * nX + fSin * nY ) + nCenterX;
1313 		rPt.Y() = -(long) FRound( fSin * nX - fCos * nY ) + nCenterY;
1314 	}
1315 }
1316 
1317 // -----------------------------------------------------------------------
1318 
SlantX(long nYRef,double fSin,double fCos)1319 void Polygon::SlantX( long nYRef, double fSin, double fCos )
1320 {
1321 	DBG_CHKTHIS( Polygon, NULL );
1322 	ImplMakeUnique();
1323 
1324 	for( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1325 	{
1326 		Point&		rPnt = mpImplPolygon->mpPointAry[ i ];
1327 		const long	nDy = rPnt.Y() - nYRef;
1328 
1329 		rPnt.X() += (long)( fSin * nDy );
1330 		rPnt.Y() = nYRef + (long)( fCos * nDy );
1331 	}
1332 }
1333 
1334 // -----------------------------------------------------------------------
1335 
SlantY(long nXRef,double fSin,double fCos)1336 void Polygon::SlantY( long nXRef, double fSin, double fCos )
1337 {
1338 	DBG_CHKTHIS( Polygon, NULL );
1339 	ImplMakeUnique();
1340 
1341 	for( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1342 	{
1343 		Point&		rPnt = mpImplPolygon->mpPointAry[ i ];
1344 		const long	nDx = rPnt.X() - nXRef;
1345 
1346 		rPnt.X() = nXRef + (long)( fCos * nDx );
1347 		rPnt.Y() -= (long)( fSin * nDx );
1348 	}
1349 }
1350 
1351 // -----------------------------------------------------------------------
1352 
Distort(const Rectangle & rRefRect,const Polygon & rDistortedRect)1353 void Polygon::Distort( const Rectangle& rRefRect, const Polygon& rDistortedRect )
1354 {
1355 	DBG_CHKTHIS( Polygon, NULL );
1356 	ImplMakeUnique();
1357 
1358 	long	Xr, Wr, X1, X2, X3, X4;
1359 	long	Yr, Hr, Y1, Y2, Y3, Y4;
1360 	double	fTx, fTy, fUx, fUy;
1361 
1362 	Xr = rRefRect.Left();
1363 	Yr = rRefRect.Top();
1364 	Wr = rRefRect.GetWidth();
1365 	Hr = rRefRect.GetHeight();
1366 
1367 	if( Wr && Hr )
1368 	{
1369 		DBG_ASSERT( rDistortedRect.mpImplPolygon->mnPoints >= 4, "Distort rect too small!" );
1370 
1371 		X1 = rDistortedRect[0].X();
1372 		Y1 = rDistortedRect[0].Y();
1373 		X2 = rDistortedRect[1].X();
1374 		Y2 = rDistortedRect[1].Y();
1375 		X3 = rDistortedRect[3].X();
1376 		Y3 = rDistortedRect[3].Y();
1377 		X4 = rDistortedRect[2].X();
1378 		Y4 = rDistortedRect[2].Y();
1379 
1380 		for( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1381 		{
1382 			Point& rPnt = mpImplPolygon->mpPointAry[ i ];
1383 
1384 			fTx = (double)( rPnt.X() - Xr) / Wr;
1385 			fTy = (double)( rPnt.Y() - Yr) / Hr;
1386 			fUx = 1.0 - fTx;
1387 			fUy = 1.0 - fTy;
1388 
1389 			rPnt.X() = (long) ( fUy * (fUx * X1 + fTx * X2) + fTy * (fUx * X3 + fTx * X4) );
1390 			rPnt.Y() = (long) ( fUx * (fUy * Y1 + fTy * Y3) + fTx * (fUy * Y2 + fTy * Y4) );
1391 		}
1392 	}
1393 }
1394 
1395 // -----------------------------------------------------------------------
1396 
1397 class ImplPointFilter
1398 {
1399 public:
1400 	virtual void LastPoint() = 0;
1401 	virtual void Input( const Point& rPoint ) = 0;
1402 };
1403 
1404 class ImplPolygonPointFilter : public ImplPointFilter
1405 {
1406 public:
1407 	ImplPolygon*	mpPoly; 	// Nicht loeschen, wird dem Polygon zugewiesen
1408 	sal_uInt16			mnSize;
1409 
ImplPolygonPointFilter(sal_uInt16 nDestSize)1410 					ImplPolygonPointFilter( sal_uInt16 nDestSize ) :
1411 						mnSize( 0 )
1412 					{
1413 						mpPoly = new ImplPolygon( nDestSize );
1414 					}
1415 
1416 	virtual void	LastPoint();
1417 	virtual void	Input( const Point& rPoint );
1418 };
1419 
Input(const Point & rPoint)1420 void ImplPolygonPointFilter::Input( const Point& rPoint )
1421 {
1422 	if ( !mnSize || (rPoint != mpPoly->mpPointAry[mnSize-1]) )
1423 	{
1424 		mnSize++;
1425 		if ( mnSize > mpPoly->mnPoints )
1426 			mpPoly->ImplSetSize( mnSize );
1427 		mpPoly->mpPointAry[mnSize-1] = rPoint;
1428 	}
1429 }
1430 
LastPoint()1431 void ImplPolygonPointFilter::LastPoint()
1432 {
1433 	if ( mnSize < mpPoly->mnPoints )
1434 		mpPoly->ImplSetSize( mnSize );
1435 };
1436 
1437 class ImplEdgePointFilter : public ImplPointFilter
1438 {
1439 	Point				maFirstPoint;
1440 	Point				maLastPoint;
1441 	ImplPointFilter&	mrNextFilter;
1442 	const long			mnLow;
1443 	const long			mnHigh;
1444 	const int			mnEdge;
1445 	int 				mnLastOutside;
1446 	sal_Bool				mbFirst;
1447 
1448 public:
ImplEdgePointFilter(int nEdge,long nLow,long nHigh,ImplPointFilter & rNextFilter)1449 						ImplEdgePointFilter( int nEdge, long nLow, long nHigh,
1450 											 ImplPointFilter& rNextFilter ) :
1451 							mrNextFilter( rNextFilter ),
1452 							mnLow( nLow ),
1453 							mnHigh( nHigh ),
1454 							mnEdge( nEdge ),
1455 							mbFirst( sal_True )
1456 						{
1457 						}
1458 
1459 	Point				EdgeSection( const Point& rPoint, int nEdge ) const;
1460 	int 				VisibleSide( const Point& rPoint ) const;
IsPolygon() const1461 	int 				IsPolygon() const
1462 							{ return maFirstPoint == maLastPoint; }
1463 
1464 	virtual void		Input( const Point& rPoint );
1465 	virtual void		LastPoint();
1466 };
1467 
VisibleSide(const Point & rPoint) const1468 inline int ImplEdgePointFilter::VisibleSide( const Point& rPoint ) const
1469 {
1470 	if ( mnEdge & EDGE_HORZ )
1471 	{
1472 		return rPoint.X() < mnLow ? EDGE_LEFT :
1473 									 rPoint.X() > mnHigh ? EDGE_RIGHT : 0;
1474 	}
1475 	else
1476 	{
1477 		return rPoint.Y() < mnLow ? EDGE_TOP :
1478 									 rPoint.Y() > mnHigh ? EDGE_BOTTOM : 0;
1479 	}
1480 }
1481 
EdgeSection(const Point & rPoint,int nEdge) const1482 Point ImplEdgePointFilter::EdgeSection( const Point& rPoint, int nEdge ) const
1483 {
1484 	long lx = maLastPoint.X();
1485 	long ly = maLastPoint.Y();
1486 	long md = rPoint.X() - lx;
1487 	long mn = rPoint.Y() - ly;
1488 	long nNewX;
1489 	long nNewY;
1490 
1491 	if ( nEdge & EDGE_VERT )
1492 	{
1493 		nNewY = (nEdge == EDGE_TOP) ? mnLow : mnHigh;
1494 		long dy = nNewY - ly;
1495 		if ( !md )
1496 			nNewX = lx;
1497 		else if ( (LONG_MAX / Abs(md)) >= Abs(dy) )
1498 			nNewX = (dy * md) / mn + lx;
1499 		else
1500 		{
1501 			BigInt ady = dy;
1502 			ady *= md;
1503 			if( ady.IsNeg() )
1504 				if( mn < 0 )
1505 					ady += mn/2;
1506 				else
1507 					ady -= (mn-1)/2;
1508 			else
1509 				if( mn < 0 )
1510 					ady -= (mn+1)/2;
1511 				else
1512 					ady += mn/2;
1513 			ady /= mn;
1514 			nNewX = (long)ady + lx;
1515 		}
1516 	}
1517 	else
1518 	{
1519 		nNewX = (nEdge == EDGE_LEFT) ? mnLow : mnHigh;
1520 		long dx = nNewX - lx;
1521 		if ( !mn )
1522 			nNewY = ly;
1523 		else if ( (LONG_MAX / Abs(mn)) >= Abs(dx) )
1524 			nNewY = (dx * mn) / md + ly;
1525 		else
1526 		{
1527 			BigInt adx = dx;
1528 			adx *= mn;
1529 			if( adx.IsNeg() )
1530 				if( md < 0 )
1531 					adx += md/2;
1532 				else
1533 					adx -= (md-1)/2;
1534 			else
1535 				if( md < 0 )
1536 					adx -= (md+1)/2;
1537 				else
1538 					adx += md/2;
1539 			adx /= md;
1540 			nNewY = (long)adx + ly;
1541 		}
1542 	}
1543 
1544 	return Point( nNewX, nNewY );
1545 }
1546 
Input(const Point & rPoint)1547 void ImplEdgePointFilter::Input( const Point& rPoint )
1548 {
1549 	int nOutside = VisibleSide( rPoint );
1550 
1551 	if ( mbFirst )
1552 	{
1553 		maFirstPoint = rPoint;
1554 		mbFirst 	 = sal_False;
1555 		if ( !nOutside )
1556 			mrNextFilter.Input( rPoint );
1557 	}
1558 	else if ( rPoint == maLastPoint )
1559 		return;
1560 	else if ( !nOutside )
1561 	{
1562 		if ( mnLastOutside )
1563 			mrNextFilter.Input( EdgeSection( rPoint, mnLastOutside ) );
1564 		mrNextFilter.Input( rPoint );
1565 	}
1566 	else if ( !mnLastOutside )
1567 		mrNextFilter.Input( EdgeSection( rPoint, nOutside ) );
1568 	else if ( nOutside != mnLastOutside )
1569 	{
1570 		mrNextFilter.Input( EdgeSection( rPoint, mnLastOutside ) );
1571 		mrNextFilter.Input( EdgeSection( rPoint, nOutside ) );
1572 	}
1573 
1574 	maLastPoint    = rPoint;
1575 	mnLastOutside  = nOutside;
1576 }
1577 
LastPoint()1578 void ImplEdgePointFilter::LastPoint()
1579 {
1580 	if ( !mbFirst )
1581 	{
1582 		int nOutside = VisibleSide( maFirstPoint );
1583 
1584 		if ( nOutside != mnLastOutside )
1585 			Input( maFirstPoint );
1586 		mrNextFilter.LastPoint();
1587 	}
1588 }
1589 
1590 // -----------------------------------------------------------------------
1591 
Clip(const Rectangle & rRect,sal_Bool bPolygon)1592 void Polygon::Clip( const Rectangle& rRect, sal_Bool bPolygon )
1593 {
1594     // #105251# Justify rect befor edge filtering
1595     Rectangle				aJustifiedRect( rRect );
1596     aJustifiedRect.Justify();
1597 
1598 	sal_uInt16					nSourceSize = mpImplPolygon->mnPoints;
1599 	ImplPolygonPointFilter	aPolygon( nSourceSize );
1600 	ImplEdgePointFilter 	aHorzFilter( EDGE_HORZ, aJustifiedRect.Left(), aJustifiedRect.Right(),
1601 										 aPolygon );
1602 	ImplEdgePointFilter 	aVertFilter( EDGE_VERT, aJustifiedRect.Top(), aJustifiedRect.Bottom(),
1603 										 aHorzFilter );
1604 
1605 	for ( sal_uInt16 i = 0; i < nSourceSize; i++ )
1606 		aVertFilter.Input( mpImplPolygon->mpPointAry[i] );
1607 	if ( bPolygon || aVertFilter.IsPolygon() )
1608 		aVertFilter.LastPoint();
1609 	else
1610 		aPolygon.LastPoint();
1611 
1612 	// Alte ImpPolygon-Daten loeschen und die vom ImpPolygonPointFilter
1613 	// zuweisen
1614 	if ( mpImplPolygon->mnRefCount )
1615 	{
1616 		if ( mpImplPolygon->mnRefCount > 1 )
1617 			mpImplPolygon->mnRefCount--;
1618 		else
1619 			delete mpImplPolygon;
1620 	}
1621 	mpImplPolygon = aPolygon.mpPoly;
1622 }
1623 
1624 // -----------------------------------------------------------------------
1625 
GetBoundRect() const1626 Rectangle Polygon::GetBoundRect() const
1627 {
1628 	DBG_CHKTHIS( Polygon, NULL );
1629     // Removing the assert. Bezier curves have the attribute that each single
1630     // curve segment defined by four points can not exit the four-point polygon
1631     // defined by that points. This allows to say that the curve segment can also
1632     // never leave the Range of it's defining points.
1633     // The result is that Polygon::GetBoundRect() may not create the minimal
1634     // BoundRect of the Polygon (to get that, use basegfx::B2DPolygon classes),
1635     // but will always create a valid BoundRect, at least as long as this method
1636     // 'blindly' travels over all points, including control points.
1637     //
1638 	// DBG_ASSERT( !mpImplPolygon->mpFlagAry, "GetBoundRect could fail with beziers!" );
1639 
1640 	sal_uInt16	nCount = mpImplPolygon->mnPoints;
1641 	if( ! nCount )
1642 		return Rectangle();
1643 
1644 	long	nXMin, nXMax, nYMin, nYMax;
1645 
1646 	const Point* pPt = &(mpImplPolygon->mpPointAry[0]);
1647 	nXMin = nXMax = pPt->X();
1648 	nYMin = nYMax = pPt->Y();
1649 
1650 	for ( sal_uInt16 i = 0; i < nCount; i++ )
1651 	{
1652 		pPt = &(mpImplPolygon->mpPointAry[i]);
1653 
1654 		if ( pPt->X() < nXMin )
1655 			nXMin = pPt->X();
1656 		if ( pPt->X() > nXMax )
1657 			nXMax = pPt->X();
1658 		if ( pPt->Y() < nYMin )
1659 			nYMin = pPt->Y();
1660 		if ( pPt->Y() > nYMax )
1661 			nYMax = pPt->Y();
1662 	}
1663 
1664 	return Rectangle( nXMin, nYMin, nXMax, nYMax );
1665 }
1666 
1667 // -----------------------------------------------------------------------
1668 
GetArea() const1669 double Polygon::GetArea() const
1670 {
1671 	const double fArea = GetSignedArea();
1672 	return( ( fArea < 0.0 ) ? -fArea : fArea );
1673 }
1674 
1675 // -----------------------------------------------------------------------
1676 
GetSignedArea() const1677 double Polygon::GetSignedArea() const
1678 {
1679 	DBG_CHKTHIS( Polygon, NULL );
1680 	DBG_ASSERT( !mpImplPolygon->mpFlagAry, "GetArea could fail with beziers!" );
1681 
1682 	double fArea = 0.0;
1683 
1684 	if( mpImplPolygon->mnPoints > 2 )
1685 	{
1686 		const sal_uInt16 nCount1 = mpImplPolygon->mnPoints - 1;
1687 
1688 		for( sal_uInt16 i = 0; i < nCount1; )
1689 		{
1690 			const Point& rPt = mpImplPolygon->mpPointAry[ i ];
1691 			const Point& rPt1 = mpImplPolygon->mpPointAry[ ++i ];
1692 			fArea += ( rPt.X() - rPt1.X() ) * ( rPt.Y() + rPt1.Y() );
1693 		}
1694 
1695 		const Point& rPt = mpImplPolygon->mpPointAry[ nCount1 ];
1696 		const Point& rPt0 = mpImplPolygon->mpPointAry[ 0 ];
1697 		fArea += ( rPt.X() - rPt0.X() ) * ( rPt.Y() + rPt0.Y() );
1698 	}
1699 
1700 	return fArea;
1701 }
1702 
1703 // -----------------------------------------------------------------------
1704 
IsInside(const Point & rPoint) const1705 sal_Bool Polygon::IsInside( const Point& rPoint ) const
1706 {
1707 	DBG_CHKTHIS( Polygon, NULL );
1708 	DBG_ASSERT( !mpImplPolygon->mpFlagAry, "IsInside could fail with beziers!" );
1709 
1710 	const Rectangle aBound( GetBoundRect() );
1711 	const Line		aLine( rPoint, Point( aBound.Right() + 100L, rPoint.Y() ) );
1712 	sal_uInt16			nCount = mpImplPolygon->mnPoints;
1713 	sal_uInt16			nPCounter = 0;
1714 
1715 	if ( ( nCount > 2 ) && aBound.IsInside( rPoint ) )
1716 	{
1717 		Point	aPt1( mpImplPolygon->mpPointAry[ 0 ] );
1718 		Point	aIntersection;
1719 		Point	aLastIntersection;
1720 
1721 		while ( ( aPt1 == mpImplPolygon->mpPointAry[ nCount - 1 ] ) && ( nCount > 3 ) )
1722 			nCount--;
1723 
1724 		for ( sal_uInt16 i = 1; i <= nCount; i++ )
1725 		{
1726 			const Point& rPt2 = mpImplPolygon->mpPointAry[ ( i < nCount ) ? i : 0 ];
1727 
1728 			if ( aLine.Intersection( Line( aPt1, rPt2 ), aIntersection ) )
1729 			{
1730 				// Hiermit verhindern wir das Einfuegen von
1731 				// doppelten Intersections, die gleich hintereinander folgen
1732 				if ( nPCounter )
1733 				{
1734 					if ( aIntersection != aLastIntersection )
1735 					{
1736 						aLastIntersection = aIntersection;
1737 						nPCounter++;
1738 					}
1739 				}
1740 				else
1741 				{
1742 					aLastIntersection = aIntersection;
1743 					nPCounter++;
1744 				}
1745 			}
1746 
1747 			aPt1 = rPt2;
1748 		}
1749 	}
1750 
1751 	// innerhalb, wenn die Anzahl der Schnittpunkte ungerade ist
1752 	return ( ( nPCounter & 1 ) == 1 );
1753 }
1754 
1755 // -----------------------------------------------------------------------
1756 
IsRightOrientated() const1757 sal_Bool Polygon::IsRightOrientated() const
1758 {
1759 	DBG_CHKTHIS( Polygon, NULL );
1760 	return GetSignedArea() >= 0.0;
1761 }
1762 
1763 // -----------------------------------------------------------------------
1764 
Insert(sal_uInt16 nPos,const Point & rPt,PolyFlags eFlags)1765 void Polygon::Insert( sal_uInt16 nPos, const Point& rPt, PolyFlags eFlags )
1766 {
1767 	DBG_CHKTHIS( Polygon, NULL );
1768 	ImplMakeUnique();
1769 
1770 	if( nPos >= mpImplPolygon->mnPoints )
1771 		nPos = mpImplPolygon->mnPoints;
1772 
1773 	mpImplPolygon->ImplSplit( nPos, 1 );
1774 	mpImplPolygon->mpPointAry[ nPos ] = rPt;
1775 
1776 	if( POLY_NORMAL != eFlags )
1777 	{
1778 		mpImplPolygon->ImplCreateFlagArray();
1779 		mpImplPolygon->mpFlagAry[ nPos ] = (sal_uInt8) eFlags;
1780 	}
1781 }
1782 
1783 // -----------------------------------------------------------------------
1784 
Insert(sal_uInt16 nPos,const Polygon & rPoly)1785 void Polygon::Insert( sal_uInt16 nPos, const Polygon& rPoly )
1786 {
1787 	DBG_CHKTHIS( Polygon, NULL );
1788 	const sal_uInt16 nInsertCount = rPoly.mpImplPolygon->mnPoints;
1789 
1790 	if( nInsertCount )
1791 	{
1792 		ImplMakeUnique();
1793 
1794 		if( nPos >= mpImplPolygon->mnPoints )
1795 			nPos = mpImplPolygon->mnPoints;
1796 
1797 		if( rPoly.mpImplPolygon->mpFlagAry )
1798 			mpImplPolygon->ImplCreateFlagArray();
1799 
1800 		mpImplPolygon->ImplSplit( nPos, nInsertCount, rPoly.mpImplPolygon );
1801 	}
1802 }
1803 
1804 // -----------------------------------------------------------------------
1805 
Remove(sal_uInt16 nPos,sal_uInt16 nCount)1806 void Polygon::Remove( sal_uInt16 nPos, sal_uInt16 nCount )
1807 {
1808 	DBG_CHKTHIS( Polygon, NULL );
1809 	if( nCount && ( nPos < mpImplPolygon->mnPoints ) )
1810 	{
1811 		ImplMakeUnique();
1812 		mpImplPolygon->ImplRemove( nPos, nCount );
1813 	}
1814 }
1815 
1816 // -----------------------------------------------------------------------
1817 
operator [](sal_uInt16 nPos)1818 Point& Polygon::operator[]( sal_uInt16 nPos )
1819 {
1820 	DBG_CHKTHIS( Polygon, NULL );
1821 	DBG_ASSERT( nPos < mpImplPolygon->mnPoints, "Polygon::[]: nPos >= nPoints" );
1822 
1823 	ImplMakeUnique();
1824 	return mpImplPolygon->mpPointAry[nPos];
1825 }
1826 
1827 // -----------------------------------------------------------------------
1828 
operator =(const Polygon & rPoly)1829 Polygon& Polygon::operator=( const Polygon& rPoly )
1830 {
1831 	DBG_CHKTHIS( Polygon, NULL );
1832 	DBG_CHKOBJ( &rPoly, Polygon, NULL );
1833 	DBG_ASSERT( rPoly.mpImplPolygon->mnRefCount < 0xFFFFFFFE, "Polygon: RefCount overflow" );
1834 
1835 	// Zuerst Referenzcounter erhoehen, damit man sich selbst zuweisen kann
1836 	// RefCount == 0 fuer statische Objekte
1837 	if ( rPoly.mpImplPolygon->mnRefCount )
1838 		rPoly.mpImplPolygon->mnRefCount++;
1839 
1840 	// Wenn es keine statischen ImpDaten sind, dann loeschen, wenn es
1841 	// die letzte Referenz ist, sonst Referenzcounter decrementieren
1842 	if ( mpImplPolygon->mnRefCount )
1843 	{
1844 		if ( mpImplPolygon->mnRefCount > 1 )
1845 			mpImplPolygon->mnRefCount--;
1846 		else
1847 			delete mpImplPolygon;
1848 	}
1849 
1850 	mpImplPolygon = rPoly.mpImplPolygon;
1851 	return *this;
1852 }
1853 
1854 // -----------------------------------------------------------------------
1855 
operator ==(const Polygon & rPoly) const1856 sal_Bool Polygon::operator==( const Polygon& rPoly ) const
1857 {
1858 	DBG_CHKTHIS( Polygon, NULL );
1859 	DBG_CHKOBJ( &rPoly, Polygon, NULL );
1860 
1861 	if ( (rPoly.mpImplPolygon == mpImplPolygon) )
1862 		return sal_True;
1863 	else
1864 		return sal_False;
1865 }
1866 
1867 // -----------------------------------------------------------------------
1868 
IsEqual(const Polygon & rPoly) const1869 sal_Bool Polygon::IsEqual( const Polygon& rPoly ) const
1870 {
1871 	sal_Bool bIsEqual = sal_True;;
1872 	sal_uInt16 i;
1873 	if ( GetSize() != rPoly.GetSize() )
1874 		bIsEqual = sal_False;
1875 	else
1876 	{
1877 		for ( i = 0; i < GetSize(); i++ )
1878 		{
1879 			if ( ( GetPoint( i ) != rPoly.GetPoint( i ) ) ||
1880 				( GetFlags( i ) != rPoly.GetFlags( i ) ) )
1881 			{
1882 				bIsEqual = sal_False;
1883 				break;
1884 			}
1885 		}
1886 	}
1887 	return bIsEqual;
1888 }
1889 
1890 // -----------------------------------------------------------------------
1891 
operator >>(SvStream & rIStream,Polygon & rPoly)1892 SvStream& operator>>( SvStream& rIStream, Polygon& rPoly )
1893 {
1894 	DBG_CHKOBJ( &rPoly, Polygon, NULL );
1895 	DBG_ASSERTWARNING( rIStream.GetVersion(), "Polygon::>> - Solar-Version not set on rIStream" );
1896 
1897 	sal_uInt16			i;
1898 	sal_uInt16			nStart;
1899 	sal_uInt16			nCurPoints;
1900 	sal_uInt16			nPoints;
1901 	unsigned char	bShort;
1902 	short			nShortX;
1903 	short			nShortY;
1904 	long			nLongX;
1905 	long			nLongY;
1906 
1907 	// Anzahl der Punkte einlesen und Array erzeugen
1908 	rIStream >> nPoints;
1909 	if ( rPoly.mpImplPolygon->mnRefCount != 1 )
1910 	{
1911 		if ( rPoly.mpImplPolygon->mnRefCount )
1912 			rPoly.mpImplPolygon->mnRefCount--;
1913 		rPoly.mpImplPolygon = new ImplPolygon( nPoints );
1914 	}
1915 	else
1916 		rPoly.mpImplPolygon->ImplSetSize( nPoints, sal_False );
1917 
1918 	// Je nach CompressMode das Polygon einlesen
1919 	if ( rIStream.GetCompressMode() == COMPRESSMODE_FULL )
1920 	{
1921 		i = 0;
1922 		while ( i < nPoints )
1923 		{
1924 			rIStream >> bShort >> nCurPoints;
1925 
1926 			if ( bShort )
1927 			{
1928 				for ( nStart = i; i < nStart+nCurPoints; i++ )
1929 				{
1930 					rIStream >> nShortX >> nShortY;
1931 					rPoly.mpImplPolygon->mpPointAry[i].X() = nShortX;
1932 					rPoly.mpImplPolygon->mpPointAry[i].Y() = nShortY;
1933 				}
1934 			}
1935 			else
1936 			{
1937 				for ( nStart = i; i < nStart+nCurPoints; i++ )
1938 				{
1939 					rIStream >> nLongX >> nLongY;
1940 					rPoly.mpImplPolygon->mpPointAry[i].X() = nLongX;
1941 					rPoly.mpImplPolygon->mpPointAry[i].Y() = nLongY;
1942 				}
1943 			}
1944 		}
1945 	}
1946 	else
1947 	{
1948 		// Feststellen, ob ueber die Operatoren geschrieben werden muss
1949 #if (SAL_TYPES_SIZEOFLONG) != 4
1950 		if ( 1 )
1951 #else
1952 #ifdef OSL_BIGENDIAN
1953 		if ( rIStream.GetNumberFormatInt() != NUMBERFORMAT_INT_BIGENDIAN )
1954 #else
1955 		if ( rIStream.GetNumberFormatInt() != NUMBERFORMAT_INT_LITTLEENDIAN )
1956 #endif
1957 #endif
1958 		{
1959 			for( i = 0; i < nPoints; i++ )
1960 			{
1961 				rIStream >> rPoly.mpImplPolygon->mpPointAry[i].X()
1962 						 >> rPoly.mpImplPolygon->mpPointAry[i].Y();
1963 			}
1964 		}
1965 		else
1966 			rIStream.Read( rPoly.mpImplPolygon->mpPointAry, nPoints*sizeof(Point) );
1967 	}
1968 
1969 	return rIStream;
1970 }
1971 
1972 // -----------------------------------------------------------------------
1973 
operator <<(SvStream & rOStream,const Polygon & rPoly)1974 SvStream& operator<<( SvStream& rOStream, const Polygon& rPoly )
1975 {
1976 	DBG_CHKOBJ( &rPoly, Polygon, NULL );
1977 	DBG_ASSERTWARNING( rOStream.GetVersion(), "Polygon::<< - Solar-Version not set on rOStream" );
1978 
1979 	unsigned char	bShort;
1980 	unsigned char	bCurShort;
1981 	sal_uInt16			nStart;
1982 	sal_uInt16			i;
1983 	sal_uInt16			nPoints = rPoly.GetSize();
1984 
1985 	// Anzahl der Punkte rausschreiben
1986 	rOStream << nPoints;
1987 
1988 	// Je nach CompressMode das Polygon rausschreiben
1989 	if ( rOStream.GetCompressMode() == COMPRESSMODE_FULL )
1990 	{
1991 		i = 0;
1992 		while ( i < nPoints )
1993 		{
1994 			nStart = i;
1995 
1996 			// Feststellen, welcher Typ geschrieben werden soll
1997 			if ( ((rPoly.mpImplPolygon->mpPointAry[nStart].X() >= SHRT_MIN) &&
1998 				  (rPoly.mpImplPolygon->mpPointAry[nStart].X() <= SHRT_MAX)) &&
1999 				 ((rPoly.mpImplPolygon->mpPointAry[nStart].Y() >= SHRT_MIN) &&
2000 				  (rPoly.mpImplPolygon->mpPointAry[nStart].Y() <= SHRT_MAX)) )
2001 				bShort = sal_True;
2002 			else
2003 				bShort = sal_False;
2004 			while ( i < nPoints )
2005 			{
2006 				// Feststellen, welcher Typ geschrieben werden soll
2007 				if ( ((rPoly.mpImplPolygon->mpPointAry[nStart].X() >= SHRT_MIN) &&
2008 					  (rPoly.mpImplPolygon->mpPointAry[nStart].X() <= SHRT_MAX)) &&
2009 					 ((rPoly.mpImplPolygon->mpPointAry[nStart].Y() >= SHRT_MIN) &&
2010 					  (rPoly.mpImplPolygon->mpPointAry[nStart].Y() <= SHRT_MAX)) )
2011 					bCurShort = sal_True;
2012 				else
2013 					bCurShort = sal_False;
2014 
2015 				// Wenn sich die Werte in einen anderen Bereich begeben,
2016 				// muessen wir neu rausschreiben
2017 				if ( bCurShort != bShort )
2018 				{
2019 					bShort = bCurShort;
2020 					break;
2021 				}
2022 
2023 				i++;
2024 			}
2025 
2026 			rOStream << bShort << (sal_uInt16)(i-nStart);
2027 
2028 			if ( bShort )
2029 			{
2030 				for( ; nStart < i; nStart++ )
2031 				{
2032 					rOStream << (short)rPoly.mpImplPolygon->mpPointAry[nStart].X()
2033 							 << (short)rPoly.mpImplPolygon->mpPointAry[nStart].Y();
2034 				}
2035 			}
2036 			else
2037 			{
2038 				for( ; nStart < i; nStart++ )
2039 				{
2040 					rOStream << rPoly.mpImplPolygon->mpPointAry[nStart].X()
2041 							 << rPoly.mpImplPolygon->mpPointAry[nStart].Y();
2042 				}
2043 			}
2044 		}
2045 	}
2046 	else
2047 	{
2048 		// Feststellen, ob ueber die Operatoren geschrieben werden muss
2049 #if (SAL_TYPES_SIZEOFLONG) != 4
2050 		if ( 1 )
2051 #else
2052 #ifdef OSL_BIGENDIAN
2053 		if ( rOStream.GetNumberFormatInt() != NUMBERFORMAT_INT_BIGENDIAN )
2054 #else
2055 		if ( rOStream.GetNumberFormatInt() != NUMBERFORMAT_INT_LITTLEENDIAN )
2056 #endif
2057 #endif
2058 		{
2059 			for( i = 0; i < nPoints; i++ )
2060 			{
2061 				rOStream << rPoly.mpImplPolygon->mpPointAry[i].X()
2062 						 << rPoly.mpImplPolygon->mpPointAry[i].Y();
2063 			}
2064 		}
2065 		else
2066 		{
2067 			if ( nPoints )
2068 				rOStream.Write( rPoly.mpImplPolygon->mpPointAry, nPoints*sizeof(Point) );
2069 		}
2070 	}
2071 
2072 	return rOStream;
2073 }
2074 
2075 // -----------------------------------------------------------------------
2076 
ImplRead(SvStream & rIStream)2077 void Polygon::ImplRead( SvStream& rIStream )
2078 {
2079 	sal_uInt8	bHasPolyFlags;
2080 
2081 	rIStream >> *this
2082 			 >> bHasPolyFlags;
2083 
2084 	if ( bHasPolyFlags )
2085 	{
2086 		mpImplPolygon->mpFlagAry = new sal_uInt8[ mpImplPolygon->mnPoints ];
2087 		rIStream.Read( mpImplPolygon->mpFlagAry, mpImplPolygon->mnPoints );
2088 	}
2089 }
2090 
2091 // -----------------------------------------------------------------------
2092 
Read(SvStream & rIStream)2093 void Polygon::Read( SvStream& rIStream )
2094 {
2095 	VersionCompat aCompat( rIStream, STREAM_READ );
2096 
2097     ImplRead( rIStream );
2098 }
2099 
2100 // -----------------------------------------------------------------------
2101 
ImplWrite(SvStream & rOStream) const2102 void Polygon::ImplWrite( SvStream& rOStream ) const
2103 {
2104 	sal_uInt8	bHasPolyFlags = mpImplPolygon->mpFlagAry != NULL;
2105 	rOStream << *this
2106 			 << bHasPolyFlags;
2107 
2108 	if ( bHasPolyFlags )
2109 		rOStream.Write( mpImplPolygon->mpFlagAry, mpImplPolygon->mnPoints );
2110 }
2111 
2112 // -----------------------------------------------------------------------
2113 
Write(SvStream & rOStream) const2114 void Polygon::Write( SvStream& rOStream ) const
2115 {
2116 	VersionCompat aCompat( rOStream, STREAM_WRITE, 1 );
2117 
2118     ImplWrite( rOStream );
2119 }
2120 
2121 // -----------------------------------------------------------------------
2122 // numerical correction method for B2DPolygon
impCorrectContinuity(basegfx::B2DPolygon & roPolygon,sal_uInt32 nIndex,sal_uInt8 nCFlag)2123 void impCorrectContinuity(basegfx::B2DPolygon& roPolygon, sal_uInt32 nIndex, sal_uInt8 nCFlag)
2124 {
2125 	const sal_uInt32 nPointCount(roPolygon.count());
2126 	OSL_ENSURE(nIndex < nPointCount, "impCorrectContinuity: index access out of range (!)");
2127 
2128 	if(nIndex < nPointCount && (POLY_SMOOTH == nCFlag || POLY_SYMMTR == nCFlag))
2129 	{
2130 		if(roPolygon.isPrevControlPointUsed(nIndex) && roPolygon.isNextControlPointUsed(nIndex))
2131 		{
2132             // #115917# Patch from osnola (modified, thanks for showing the porblem)
2133             //
2134             // The correction is needed because an integer polygon with control points
2135             // is converted to double precision. When C1 or C2 is used the involved vectors
2136             // may not have the same directions/lengths since these come from integer coordinates
2137             //  and may have been snapped to different nearest integer coordinates. The snap error
2138             // is in the range of +-1 in y and y, thus 0.0 <= error <= sqrt(2.0). Nonetheless,
2139             // it needs to be corrected to be able to detect the continuity in this points
2140             // correctly.
2141             //
2142             // We only have the integer data here (already in double precision form, but no mantisses
2143             // used), so the best correction is to use:
2144             //
2145             // for C1: The longest vector since it potentially has best preserved the original vector.
2146             //         Even better the sum of the vectors, weighted by their length. This gives the
2147             //         normal vector addition to get the vector itself, lengths need to be preserved.
2148             // for C2: The mediated vector(s) since both should be the same, but mirrored
2149 
2150             // extract the point and vectors
2151 			const basegfx::B2DPoint aPoint(roPolygon.getB2DPoint(nIndex));
2152             const basegfx::B2DVector aNext(roPolygon.getNextControlPoint(nIndex) - aPoint);
2153             const basegfx::B2DVector aPrev(aPoint - roPolygon.getPrevControlPoint(nIndex));
2154 
2155             // calculate common direction vector, normalize
2156             const basegfx::B2DVector aDirection(aNext + aPrev);
2157 
2158 			if(POLY_SMOOTH == nCFlag)
2159 			{
2160                 // C1: apply common direction vector, preserve individual lengths
2161                 const double fInvDirectionLen(1.0 / aDirection.getLength());
2162 				roPolygon.setNextControlPoint(nIndex, basegfx::B2DPoint(aPoint + (aDirection * (aNext.getLength() * fInvDirectionLen))));
2163 				roPolygon.setPrevControlPoint(nIndex, basegfx::B2DPoint(aPoint - (aDirection * (aPrev.getLength() * fInvDirectionLen))));
2164 			}
2165 			else // POLY_SYMMTR
2166 			{
2167                 // C2: get mediated length. Taking half of the unnormalized direction would be
2168                 // an approximation, but not correct.
2169                 const double fMedLength((aNext.getLength() + aPrev.getLength()) * (0.5 / aDirection.getLength()));
2170                 const basegfx::B2DVector aScaledDirection(aDirection * fMedLength);
2171 
2172                 // Bring Direction to correct length and apply
2173 				roPolygon.setNextControlPoint(nIndex, basegfx::B2DPoint(aPoint + aScaledDirection));
2174 				roPolygon.setPrevControlPoint(nIndex, basegfx::B2DPoint(aPoint - aScaledDirection));
2175 			}
2176 		}
2177 	}
2178 }
2179 
2180 // -----------------------------------------------------------------------
2181 // convert to basegfx::B2DPolygon and return
getB2DPolygon() const2182 basegfx::B2DPolygon Polygon::getB2DPolygon() const
2183 {
2184 	basegfx::B2DPolygon aRetval;
2185 	const sal_uInt16 nCount(mpImplPolygon->mnPoints);
2186 
2187 	if(nCount)
2188 	{
2189 		if(mpImplPolygon->mpFlagAry)
2190 		{
2191 			// handling for curves. Add start point
2192 			const Point aStartPoint(mpImplPolygon->mpPointAry[0]);
2193 			sal_uInt8 nPointFlag(mpImplPolygon->mpFlagAry[0]);
2194 			aRetval.append(basegfx::B2DPoint(aStartPoint.X(), aStartPoint.Y()));
2195 			Point aControlA, aControlB;
2196 
2197 			for(sal_uInt16 a(1); a < nCount;)
2198 			{
2199 				bool bControlA(false);
2200 				bool bControlB(false);
2201 
2202 				if(POLY_CONTROL == mpImplPolygon->mpFlagAry[a])
2203 				{
2204 					aControlA = mpImplPolygon->mpPointAry[a++];
2205 					bControlA = true;
2206 				}
2207 
2208 				if(a < nCount && POLY_CONTROL == mpImplPolygon->mpFlagAry[a])
2209 				{
2210 					aControlB = mpImplPolygon->mpPointAry[a++];
2211 					bControlB = true;
2212 				}
2213 
2214 				// assert invalid polygons
2215 				OSL_ENSURE(bControlA == bControlB, "Polygon::getB2DPolygon: Invalid source polygon (!)");
2216 
2217 				if(a < nCount)
2218 				{
2219 					const Point aEndPoint(mpImplPolygon->mpPointAry[a]);
2220 
2221 					if(bControlA)
2222 					{
2223 						// bezier edge, add
2224 						aRetval.appendBezierSegment(
2225 							basegfx::B2DPoint(aControlA.X(), aControlA.Y()),
2226 							basegfx::B2DPoint(aControlB.X(), aControlB.Y()),
2227 							basegfx::B2DPoint(aEndPoint.X(), aEndPoint.Y()));
2228 
2229 						impCorrectContinuity(aRetval, aRetval.count() - 2, nPointFlag);
2230 					}
2231 					else
2232 					{
2233 						// no bezier edge, add end point
2234 						aRetval.append(basegfx::B2DPoint(aEndPoint.X(), aEndPoint.Y()));
2235 					}
2236 
2237 					nPointFlag = mpImplPolygon->mpFlagAry[a++];
2238 				}
2239 			}
2240 
2241 			// if exist, remove double first/last points, set closed and correct control points
2242 			basegfx::tools::checkClosed(aRetval);
2243 
2244 			if(aRetval.isClosed())
2245 			{
2246 				// closeWithGeometryChange did really close, so last point(s) were removed.
2247 				// Correct the continuity in the changed point
2248 				impCorrectContinuity(aRetval, 0, mpImplPolygon->mpFlagAry[0]);
2249 			}
2250 		}
2251 		else
2252 		{
2253 			// extra handling for non-curves (most-used case) for speedup
2254 			for(sal_uInt16 a(0); a < nCount; a++)
2255 			{
2256 				// get point and add
2257 				const Point aPoint(mpImplPolygon->mpPointAry[a]);
2258 				aRetval.append(basegfx::B2DPoint(aPoint.X(), aPoint.Y()));
2259 			}
2260 
2261 			// set closed flag
2262 			basegfx::tools::checkClosed(aRetval);
2263 		}
2264 	}
2265 
2266 	return aRetval;
2267 }
2268 
2269 // -----------------------------------------------------------------------
2270 // constructor to convert from basegfx::B2DPolygon
2271 // #i76891# Needed to change from adding all control points (even for unused
2272 // edges) and creating a fixed-size Polygon in the first run to creating the
2273 // minimal Polygon. This requires a temporary Point- and Flag-Array for curves
2274 // and a memcopy at ImplPolygon creation, but contains no zero-controlpoints
2275 // for straight edges.
Polygon(const basegfx::B2DPolygon & rPolygon)2276 Polygon::Polygon(const basegfx::B2DPolygon& rPolygon)
2277 :	mpImplPolygon(0)
2278 {
2279 	DBG_CTOR( Polygon, NULL );
2280 
2281 	const bool bCurve(rPolygon.areControlPointsUsed());
2282 	const bool bClosed(rPolygon.isClosed());
2283 	sal_uInt32 nB2DLocalCount(rPolygon.count());
2284 
2285 	if(bCurve)
2286 	{
2287 		// #127979# Reduce source point count hard to the limit of the tools Polygon
2288 		if(nB2DLocalCount > ((0x0000ffff / 3L) - 1L))
2289 		{
2290 			DBG_ERROR("Polygon::Polygon: Too many points in given B2DPolygon, need to reduce hard to maximum of tools Polygon (!)");
2291 			nB2DLocalCount = ((0x0000ffff / 3L) - 1L);
2292 		}
2293 
2294 		// calculate target point count
2295 		const sal_uInt32 nLoopCount(bClosed ? nB2DLocalCount : (nB2DLocalCount ? nB2DLocalCount - 1L : 0L ));
2296 
2297 		if(nLoopCount)
2298 		{
2299 			// calculate maximum array size and allocate; prepare insert index
2300 			const sal_uInt32 nMaxTargetCount((nLoopCount * 3) + 1);
2301 			mpImplPolygon = new ImplPolygon(static_cast< sal_uInt16 >(nMaxTargetCount), true);
2302 
2303 			// prepare insert index and current point
2304 			sal_uInt32 nArrayInsert(0);
2305 			basegfx::B2DCubicBezier aBezier;
2306 			aBezier.setStartPoint(rPolygon.getB2DPoint(0));
2307 
2308 			for(sal_uInt32 a(0L); a < nLoopCount; a++)
2309 			{
2310 				// add current point (always) and remember StartPointIndex for evtl. later corrections
2311 				const Point aStartPoint(FRound(aBezier.getStartPoint().getX()), FRound(aBezier.getStartPoint().getY()));
2312 				const sal_uInt32 nStartPointIndex(nArrayInsert);
2313 				mpImplPolygon->mpPointAry[nStartPointIndex] = aStartPoint;
2314 				mpImplPolygon->mpFlagAry[nStartPointIndex] = (sal_uInt8)POLY_NORMAL;
2315 				nArrayInsert++;
2316 
2317 				// prepare next segment
2318 				const sal_uInt32 nNextIndex((a + 1) % nB2DLocalCount);
2319 				aBezier.setEndPoint(rPolygon.getB2DPoint(nNextIndex));
2320 				aBezier.setControlPointA(rPolygon.getNextControlPoint(a));
2321 				aBezier.setControlPointB(rPolygon.getPrevControlPoint(nNextIndex));
2322 
2323 				if(aBezier.isBezier())
2324 				{
2325 					// if one is used, add always two control points due to the old schema
2326 					mpImplPolygon->mpPointAry[nArrayInsert] = Point(FRound(aBezier.getControlPointA().getX()), FRound(aBezier.getControlPointA().getY()));
2327 					mpImplPolygon->mpFlagAry[nArrayInsert] = (sal_uInt8)POLY_CONTROL;
2328 					nArrayInsert++;
2329 
2330 					mpImplPolygon->mpPointAry[nArrayInsert] = Point(FRound(aBezier.getControlPointB().getX()), FRound(aBezier.getControlPointB().getY()));
2331 					mpImplPolygon->mpFlagAry[nArrayInsert] = (sal_uInt8)POLY_CONTROL;
2332 					nArrayInsert++;
2333 				}
2334 
2335 				// test continuity with previous control point to set flag value
2336 				if(aBezier.getControlPointA() != aBezier.getStartPoint() && (bClosed || a))
2337 				{
2338 					const basegfx::B2VectorContinuity eCont(rPolygon.getContinuityInPoint(a));
2339 
2340 					if(basegfx::CONTINUITY_C1 == eCont)
2341 					{
2342 						mpImplPolygon->mpFlagAry[nStartPointIndex] = (sal_uInt8)POLY_SMOOTH;
2343 					}
2344 					else if(basegfx::CONTINUITY_C2 == eCont)
2345 					{
2346 						mpImplPolygon->mpFlagAry[nStartPointIndex] = (sal_uInt8)POLY_SYMMTR;
2347 					}
2348 				}
2349 
2350 				// prepare next polygon step
2351 				aBezier.setStartPoint(aBezier.getEndPoint());
2352 			}
2353 
2354 			if(bClosed)
2355 			{
2356 				// add first point again as closing point due to old definition
2357 				mpImplPolygon->mpPointAry[nArrayInsert] = mpImplPolygon->mpPointAry[0];
2358 				mpImplPolygon->mpFlagAry[nArrayInsert] = (sal_uInt8)POLY_NORMAL;
2359 				nArrayInsert++;
2360 			}
2361 			else
2362 			{
2363 				// add last point as closing point
2364 				const basegfx::B2DPoint aClosingPoint(rPolygon.getB2DPoint(nB2DLocalCount - 1L));
2365 				const Point aEnd(FRound(aClosingPoint.getX()), FRound(aClosingPoint.getY()));
2366 				mpImplPolygon->mpPointAry[nArrayInsert] = aEnd;
2367 				mpImplPolygon->mpFlagAry[nArrayInsert] = (sal_uInt8)POLY_NORMAL;
2368 				nArrayInsert++;
2369 			}
2370 
2371 			DBG_ASSERT(nArrayInsert <= nMaxTargetCount, "Polygon::Polygon from basegfx::B2DPolygon: wrong max point count estimation (!)");
2372 
2373 			if(nArrayInsert != nMaxTargetCount)
2374 			{
2375 				mpImplPolygon->ImplSetSize(static_cast< sal_uInt16 >(nArrayInsert), true);
2376 			}
2377 		}
2378 	}
2379 	else
2380 	{
2381 		// #127979# Reduce source point count hard to the limit of the tools Polygon
2382 		if(nB2DLocalCount > (0x0000ffff - 1L))
2383 		{
2384 			DBG_ERROR("Polygon::Polygon: Too many points in given B2DPolygon, need to reduce hard to maximum of tools Polygon (!)");
2385 			nB2DLocalCount = (0x0000ffff - 1L);
2386 		}
2387 
2388 		if(nB2DLocalCount)
2389 		{
2390 			// point list creation
2391 			const sal_uInt32 nTargetCount(nB2DLocalCount + (bClosed ? 1L : 0L));
2392 			mpImplPolygon = new ImplPolygon( static_cast< sal_uInt16 >(nTargetCount) );
2393 			sal_uInt16 nIndex(0);
2394 
2395 			for(sal_uInt32 a(0L); a < nB2DLocalCount; a++)
2396 			{
2397 				basegfx::B2DPoint aB2DPoint(rPolygon.getB2DPoint(a));
2398 				Point aPoint(FRound(aB2DPoint.getX()), FRound(aB2DPoint.getY()));
2399 				mpImplPolygon->mpPointAry[nIndex++] = aPoint;
2400 			}
2401 
2402 			if(bClosed)
2403 			{
2404 				// add first point as closing point
2405 				mpImplPolygon->mpPointAry[nIndex] = mpImplPolygon->mpPointAry[0];
2406 			}
2407 		}
2408 	}
2409 
2410 	if(!mpImplPolygon)
2411 	{
2412 		// no content yet, create empty polygon
2413 		mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
2414 	}
2415 }
2416 
2417 // eof
2418