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