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