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