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