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