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 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 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 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 157 ImplPolygon::~ImplPolygon() 158 { 159 if ( mpPointAry ) 160 { 161 delete[] (char*) mpPointAry; 162 } 163 164 if( mpFlagAry ) 165 delete[] mpFlagAry; 166 } 167 168 // ----------------------------------------------------------------------- 169 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 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 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 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 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 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 372 Polygon::Polygon() 373 { 374 DBG_CTOR( Polygon, NULL ); 375 mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon); 376 } 377 378 // ----------------------------------------------------------------------- 379 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 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 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 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 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 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 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 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 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 678 Point* Polygon::ImplGetPointAry() 679 { 680 DBG_CHKTHIS( Polygon, NULL ); 681 682 ImplMakeUnique(); 683 return (Point*)mpImplPolygon->mpPointAry; 684 } 685 686 // ----------------------------------------------------------------------- 687 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 699 const Point* Polygon::GetConstPointAry() const 700 { 701 DBG_CHKTHIS( Polygon, NULL ); 702 return (Point*)mpImplPolygon->mpPointAry; 703 } 704 705 // ----------------------------------------------------------------------- 706 707 const sal_uInt8* Polygon::GetConstFlagAry() const 708 { 709 DBG_CHKTHIS( Polygon, NULL ); 710 return mpImplPolygon->mpFlagAry; 711 } 712 713 // ----------------------------------------------------------------------- 714 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 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 745 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 756 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 768 sal_Bool Polygon::HasFlags() const 769 { 770 return mpImplPolygon->mpFlagAry != NULL; 771 } 772 773 // ----------------------------------------------------------------------- 774 775 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 788 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 801 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 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 834 sal_uInt16 Polygon::GetSize() const 835 { 836 DBG_CHKTHIS( Polygon, NULL ); 837 838 return mpImplPolygon->mnPoints; 839 } 840 841 // ----------------------------------------------------------------------- 842 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 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 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 */ 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 1042 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 1102 void Polygon::GetIntersection( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const 1103 { 1104 const PolyPolygon aTmp( *this ); 1105 aTmp.GetIntersection( rPolyPoly, rResult ); 1106 } 1107 1108 // ----------------------------------------------------------------------- 1109 1110 void Polygon::GetUnion( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const 1111 { 1112 const PolyPolygon aTmp( *this ); 1113 aTmp.GetUnion( rPolyPoly, rResult ); 1114 } 1115 1116 // ----------------------------------------------------------------------- 1117 1118 void Polygon::GetDifference( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const 1119 { 1120 const PolyPolygon aTmp( *this ); 1121 aTmp.GetDifference( rPolyPoly, rResult ); 1122 } 1123 1124 // ----------------------------------------------------------------------- 1125 1126 void Polygon::GetXOR( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const 1127 { 1128 const PolyPolygon aTmp( *this ); 1129 aTmp.GetXOR( rPolyPoly, rResult ); 1130 } 1131 1132 // ----------------------------------------------------------------------- 1133 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 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 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 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 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 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 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 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 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 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 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 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: 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; 1461 int IsPolygon() const 1462 { return maFirstPoint == maLastPoint; } 1463 1464 virtual void Input( const Point& rPoint ); 1465 virtual void LastPoint(); 1466 }; 1467 1468 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 1482 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 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 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 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 1626 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 1669 double Polygon::GetArea() const 1670 { 1671 const double fArea = GetSignedArea(); 1672 return( ( fArea < 0.0 ) ? -fArea : fArea ); 1673 } 1674 1675 // ----------------------------------------------------------------------- 1676 1677 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 1705 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 1757 sal_Bool Polygon::IsRightOrientated() const 1758 { 1759 DBG_CHKTHIS( Polygon, NULL ); 1760 return GetSignedArea() >= 0.0; 1761 } 1762 1763 // ----------------------------------------------------------------------- 1764 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 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 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 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 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 1856 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 1869 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 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 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 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 2093 void Polygon::Read( SvStream& rIStream ) 2094 { 2095 VersionCompat aCompat( rIStream, STREAM_READ ); 2096 2097 ImplRead( rIStream ); 2098 } 2099 2100 // ----------------------------------------------------------------------- 2101 2102 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 2114 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 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 2182 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. 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