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_drawinglayer.hxx" 26 27 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx> 28 #include <basegfx/tools/canvastools.hxx> 29 #include <basegfx/polygon/b2dpolygontools.hxx> 30 #include <basegfx/polygon/b2dpolypolygontools.hxx> 31 #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> 32 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> 33 #include <drawinglayer/geometry/viewinformation2d.hxx> 34 #include <basegfx/polygon/b2dlinegeometry.hxx> 35 #include <com/sun/star/drawing/LineCap.hpp> 36 37 ////////////////////////////////////////////////////////////////////////////// 38 39 using namespace com::sun::star; 40 41 ////////////////////////////////////////////////////////////////////////////// 42 43 namespace drawinglayer 44 { 45 namespace primitive2d 46 { PolygonHairlinePrimitive2D(const basegfx::B2DPolygon & rPolygon,const basegfx::BColor & rBColor)47 PolygonHairlinePrimitive2D::PolygonHairlinePrimitive2D( 48 const basegfx::B2DPolygon& rPolygon, 49 const basegfx::BColor& rBColor) 50 : BasePrimitive2D(), 51 maPolygon(rPolygon), 52 maBColor(rBColor) 53 { 54 } 55 operator ==(const BasePrimitive2D & rPrimitive) const56 bool PolygonHairlinePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const 57 { 58 if(BasePrimitive2D::operator==(rPrimitive)) 59 { 60 const PolygonHairlinePrimitive2D& rCompare = (PolygonHairlinePrimitive2D&)rPrimitive; 61 62 return (getB2DPolygon() == rCompare.getB2DPolygon() 63 && getBColor() == rCompare.getBColor()); 64 } 65 66 return false; 67 } 68 getB2DRange(const geometry::ViewInformation2D & rViewInformation) const69 basegfx::B2DRange PolygonHairlinePrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const 70 { 71 // this is a hairline, thus the line width is view-dependent. Get range of polygon 72 // as base size 73 basegfx::B2DRange aRetval(getB2DPolygon().getB2DRange()); 74 75 if(!aRetval.isEmpty()) 76 { 77 // Calculate view-dependent hairline width 78 const basegfx::B2DVector aDiscreteSize(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 0.0)); 79 const double fDiscreteHalfLineWidth(aDiscreteSize.getLength() * 0.5); 80 81 if(basegfx::fTools::more(fDiscreteHalfLineWidth, 0.0)) 82 { 83 aRetval.grow(fDiscreteHalfLineWidth); 84 } 85 } 86 87 // return range 88 return aRetval; 89 } 90 91 // provide unique ID 92 ImplPrimitrive2DIDBlock(PolygonHairlinePrimitive2D, PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D) 93 94 } // end of namespace primitive2d 95 } // end of namespace drawinglayer 96 97 ////////////////////////////////////////////////////////////////////////////// 98 99 namespace drawinglayer 100 { 101 namespace primitive2d 102 { create2DDecomposition(const geometry::ViewInformation2D & rViewInformation) const103 Primitive2DSequence PolygonMarkerPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const 104 { 105 // calculate logic DashLength 106 const basegfx::B2DVector aDashVector(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(getDiscreteDashLength(), 0.0)); 107 const double fLogicDashLength(aDashVector.getX()); 108 109 if(fLogicDashLength > 0.0 && !getRGBColorA().equal(getRGBColorB())) 110 { 111 // apply dashing; get line and gap snippets 112 ::std::vector< double > aDash; 113 basegfx::B2DPolyPolygon aDashedPolyPolyA; 114 basegfx::B2DPolyPolygon aDashedPolyPolyB; 115 116 aDash.push_back(fLogicDashLength); 117 aDash.push_back(fLogicDashLength); 118 basegfx::tools::applyLineDashing(getB2DPolygon(), aDash, &aDashedPolyPolyA, &aDashedPolyPolyB, 2.0 * fLogicDashLength); 119 120 // prepare return value 121 Primitive2DSequence aRetval(2); 122 123 aRetval[0] = Primitive2DReference(new PolyPolygonHairlinePrimitive2D(aDashedPolyPolyA, getRGBColorA())); 124 aRetval[1] = Primitive2DReference(new PolyPolygonHairlinePrimitive2D(aDashedPolyPolyB, getRGBColorB())); 125 126 return aRetval; 127 } 128 else 129 { 130 const Primitive2DReference xRef(new PolygonHairlinePrimitive2D(getB2DPolygon(), getRGBColorA())); 131 return Primitive2DSequence(&xRef, 1L); 132 } 133 } 134 PolygonMarkerPrimitive2D(const basegfx::B2DPolygon & rPolygon,const basegfx::BColor & rRGBColorA,const basegfx::BColor & rRGBColorB,double fDiscreteDashLength)135 PolygonMarkerPrimitive2D::PolygonMarkerPrimitive2D( 136 const basegfx::B2DPolygon& rPolygon, 137 const basegfx::BColor& rRGBColorA, 138 const basegfx::BColor& rRGBColorB, 139 double fDiscreteDashLength) 140 : BufferedDecompositionPrimitive2D(), 141 maPolygon(rPolygon), 142 maRGBColorA(rRGBColorA), 143 maRGBColorB(rRGBColorB), 144 mfDiscreteDashLength(fDiscreteDashLength), 145 maLastInverseObjectToViewTransformation() 146 { 147 } 148 operator ==(const BasePrimitive2D & rPrimitive) const149 bool PolygonMarkerPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const 150 { 151 if(BufferedDecompositionPrimitive2D::operator==(rPrimitive)) 152 { 153 const PolygonMarkerPrimitive2D& rCompare = (PolygonMarkerPrimitive2D&)rPrimitive; 154 155 return (getB2DPolygon() == rCompare.getB2DPolygon() 156 && getRGBColorA() == rCompare.getRGBColorA() 157 && getRGBColorB() == rCompare.getRGBColorB() 158 && getDiscreteDashLength() == rCompare.getDiscreteDashLength()); 159 } 160 161 return false; 162 } 163 getB2DRange(const geometry::ViewInformation2D & rViewInformation) const164 basegfx::B2DRange PolygonMarkerPrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const 165 { 166 // this is a hairline, thus the line width is view-dependent. Get range of polygon 167 // as base size 168 basegfx::B2DRange aRetval(getB2DPolygon().getB2DRange()); 169 170 if(!aRetval.isEmpty()) 171 { 172 // Calculate view-dependent hairline width 173 const basegfx::B2DVector aDiscreteSize(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 0.0)); 174 const double fDiscreteHalfLineWidth(aDiscreteSize.getLength() * 0.5); 175 176 if(basegfx::fTools::more(fDiscreteHalfLineWidth, 0.0)) 177 { 178 aRetval.grow(fDiscreteHalfLineWidth); 179 } 180 } 181 182 // return range 183 return aRetval; 184 } 185 get2DDecomposition(const geometry::ViewInformation2D & rViewInformation) const186 Primitive2DSequence PolygonMarkerPrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const 187 { 188 ::osl::MutexGuard aGuard( m_aMutex ); 189 bool bNeedNewDecomposition(false); 190 191 if(getBuffered2DDecomposition().hasElements()) 192 { 193 if(rViewInformation.getInverseObjectToViewTransformation() != maLastInverseObjectToViewTransformation) 194 { 195 bNeedNewDecomposition = true; 196 } 197 } 198 199 if(bNeedNewDecomposition) 200 { 201 // conditions of last local decomposition have changed, delete 202 const_cast< PolygonMarkerPrimitive2D* >(this)->setBuffered2DDecomposition(Primitive2DSequence()); 203 } 204 205 if(!getBuffered2DDecomposition().hasElements()) 206 { 207 // remember last used InverseObjectToViewTransformation 208 PolygonMarkerPrimitive2D* pThat = const_cast< PolygonMarkerPrimitive2D* >(this); 209 pThat->maLastInverseObjectToViewTransformation = rViewInformation.getInverseObjectToViewTransformation(); 210 } 211 212 // use parent implementation 213 return BufferedDecompositionPrimitive2D::get2DDecomposition(rViewInformation); 214 } 215 216 // provide unique ID 217 ImplPrimitrive2DIDBlock(PolygonMarkerPrimitive2D, PRIMITIVE2D_ID_POLYGONMARKERPRIMITIVE2D) 218 219 } // end of namespace primitive2d 220 } // end of namespace drawinglayer 221 222 ////////////////////////////////////////////////////////////////////////////// 223 224 namespace drawinglayer 225 { 226 namespace primitive2d 227 { create2DDecomposition(const geometry::ViewInformation2D &) const228 Primitive2DSequence PolygonStrokePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const 229 { 230 if(getB2DPolygon().count()) 231 { 232 // #i102241# try to simplify before usage 233 const basegfx::B2DPolygon aB2DPolygon(basegfx::tools::simplifyCurveSegments(getB2DPolygon())); 234 basegfx::B2DPolyPolygon aHairLinePolyPolygon; 235 236 if(getStrokeAttribute().isDefault() || 0.0 == getStrokeAttribute().getFullDotDashLen()) 237 { 238 // no line dashing, just copy 239 aHairLinePolyPolygon.append(aB2DPolygon); 240 } 241 else 242 { 243 // apply LineStyle 244 basegfx::tools::applyLineDashing( 245 aB2DPolygon, getStrokeAttribute().getDotDashArray(), 246 &aHairLinePolyPolygon, 0, getStrokeAttribute().getFullDotDashLen()); 247 } 248 249 const sal_uInt32 nCount(aHairLinePolyPolygon.count()); 250 251 if(!getLineAttribute().isDefault() && getLineAttribute().getWidth()) 252 { 253 // create fat line data 254 const double fHalfLineWidth(getLineAttribute().getWidth() / 2.0); 255 const basegfx::B2DLineJoin aLineJoin(getLineAttribute().getLineJoin()); 256 const com::sun::star::drawing::LineCap aLineCap(getLineAttribute().getLineCap()); 257 basegfx::B2DPolyPolygon aAreaPolyPolygon; 258 259 for(sal_uInt32 a(0L); a < nCount; a++) 260 { 261 // New version of createAreaGeometry; now creates bezier polygons 262 aAreaPolyPolygon.append(basegfx::tools::createAreaGeometry( 263 aHairLinePolyPolygon.getB2DPolygon(a), 264 fHalfLineWidth, 265 aLineJoin, 266 aLineCap)); 267 } 268 269 // prepare return value 270 Primitive2DSequence aRetval(aAreaPolyPolygon.count()); 271 272 // create primitive 273 for(sal_uInt32 b(0L); b < aAreaPolyPolygon.count(); b++) 274 { 275 // put into single polyPolygon primitives to make clear that this is NOT meant 276 // to be painted as a single PolyPolygon (XORed as fill rule). Alternatively, a 277 // melting process may be used here one day. 278 const basegfx::B2DPolyPolygon aNewPolyPolygon(aAreaPolyPolygon.getB2DPolygon(b)); 279 static bool bTestByUsingRandomColor(false); 280 const basegfx::BColor aColor(bTestByUsingRandomColor 281 ? basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0) 282 : getLineAttribute().getColor()); 283 const Primitive2DReference xRef(new PolyPolygonColorPrimitive2D(aNewPolyPolygon, aColor)); 284 aRetval[b] = xRef; 285 } 286 287 return aRetval; 288 } 289 else 290 { 291 // prepare return value 292 const Primitive2DReference xRef( 293 new PolyPolygonHairlinePrimitive2D( 294 aHairLinePolyPolygon, 295 getLineAttribute().getColor())); 296 297 return Primitive2DSequence(&xRef, 1); 298 } 299 } 300 else 301 { 302 return Primitive2DSequence(); 303 } 304 } 305 PolygonStrokePrimitive2D(const basegfx::B2DPolygon & rPolygon,const attribute::LineAttribute & rLineAttribute,const attribute::StrokeAttribute & rStrokeAttribute)306 PolygonStrokePrimitive2D::PolygonStrokePrimitive2D( 307 const basegfx::B2DPolygon& rPolygon, 308 const attribute::LineAttribute& rLineAttribute, 309 const attribute::StrokeAttribute& rStrokeAttribute) 310 : BufferedDecompositionPrimitive2D(), 311 maPolygon(rPolygon), 312 maLineAttribute(rLineAttribute), 313 maStrokeAttribute(rStrokeAttribute) 314 { 315 } 316 PolygonStrokePrimitive2D(const basegfx::B2DPolygon & rPolygon,const attribute::LineAttribute & rLineAttribute)317 PolygonStrokePrimitive2D::PolygonStrokePrimitive2D( 318 const basegfx::B2DPolygon& rPolygon, 319 const attribute::LineAttribute& rLineAttribute) 320 : BufferedDecompositionPrimitive2D(), 321 maPolygon(rPolygon), 322 maLineAttribute(rLineAttribute), 323 maStrokeAttribute() 324 { 325 } 326 operator ==(const BasePrimitive2D & rPrimitive) const327 bool PolygonStrokePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const 328 { 329 if(BufferedDecompositionPrimitive2D::operator==(rPrimitive)) 330 { 331 const PolygonStrokePrimitive2D& rCompare = (PolygonStrokePrimitive2D&)rPrimitive; 332 333 return (getB2DPolygon() == rCompare.getB2DPolygon() 334 && getLineAttribute() == rCompare.getLineAttribute() 335 && getStrokeAttribute() == rCompare.getStrokeAttribute()); 336 } 337 338 return false; 339 } 340 getB2DRange(const geometry::ViewInformation2D & rViewInformation) const341 basegfx::B2DRange PolygonStrokePrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const 342 { 343 basegfx::B2DRange aRetval; 344 345 if(getLineAttribute().getWidth()) 346 { 347 bool bUseDecomposition(false); 348 349 if(basegfx::B2DLINEJOIN_MITER == getLineAttribute().getLineJoin()) 350 { 351 // if line is mitered, use parent call since mitered line 352 // geometry may use more space than the geometry grown by half line width 353 bUseDecomposition = true; 354 } 355 356 if(!bUseDecomposition && com::sun::star::drawing::LineCap_SQUARE == getLineAttribute().getLineCap()) 357 { 358 // when drawing::LineCap_SQUARE is used the below method to grow the polygon 359 // range by half line width will not work, so use decomposition. Interestingly, 360 // the grow method below works perfectly for LineCap_ROUND since the grow is in 361 // all directions and the rounded cap needs the same grow in all directions independent 362 // from it's orientation. Unfortunately this is not the case for drawing::LineCap_SQUARE 363 bUseDecomposition = true; 364 } 365 366 if(bUseDecomposition) 367 { 368 // get correct range by using the decomposition fallback, reasons see above cases 369 aRetval = BufferedDecompositionPrimitive2D::getB2DRange(rViewInformation); 370 } 371 else 372 { 373 // for all other B2DLINEJOIN_* get the range from the base geometry 374 // and expand by half the line width 375 aRetval = getB2DPolygon().getB2DRange(); 376 aRetval.grow(getLineAttribute().getWidth() * 0.5); 377 } 378 } 379 else 380 { 381 // this is a hairline, thus the line width is view-dependent. Get range of polygon 382 // as base size 383 aRetval = getB2DPolygon().getB2DRange(); 384 385 if(!aRetval.isEmpty()) 386 { 387 // Calculate view-dependent hairline width 388 const basegfx::B2DVector aDiscreteSize(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 0.0)); 389 const double fDiscreteHalfLineWidth(aDiscreteSize.getLength() * 0.5); 390 391 if(basegfx::fTools::more(fDiscreteHalfLineWidth, 0.0)) 392 { 393 aRetval.grow(fDiscreteHalfLineWidth); 394 } 395 } 396 } 397 398 return aRetval; 399 } 400 401 // provide unique ID 402 ImplPrimitrive2DIDBlock(PolygonStrokePrimitive2D, PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D) 403 404 } // end of namespace primitive2d 405 } // end of namespace drawinglayer 406 407 ////////////////////////////////////////////////////////////////////////////// 408 409 namespace drawinglayer 410 { 411 namespace primitive2d 412 { create2DDecomposition(const geometry::ViewInformation2D &) const413 Primitive2DSequence PolygonWavePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const 414 { 415 Primitive2DSequence aRetval; 416 417 if(getB2DPolygon().count()) 418 { 419 const bool bHasWidth(!basegfx::fTools::equalZero(getWaveWidth())); 420 const bool bHasHeight(!basegfx::fTools::equalZero(getWaveHeight())); 421 422 if(bHasWidth && bHasHeight) 423 { 424 // create waveline curve 425 const basegfx::B2DPolygon aWaveline(basegfx::tools::createWaveline(getB2DPolygon(), getWaveWidth(), getWaveHeight())); 426 const Primitive2DReference xRef(new PolygonStrokePrimitive2D(aWaveline, getLineAttribute(), getStrokeAttribute())); 427 aRetval = Primitive2DSequence(&xRef, 1); 428 } 429 else 430 { 431 // flat waveline, decompose to simple line primitive 432 const Primitive2DReference xRef(new PolygonStrokePrimitive2D(getB2DPolygon(), getLineAttribute(), getStrokeAttribute())); 433 aRetval = Primitive2DSequence(&xRef, 1); 434 } 435 } 436 437 return aRetval; 438 } 439 PolygonWavePrimitive2D(const basegfx::B2DPolygon & rPolygon,const attribute::LineAttribute & rLineAttribute,const attribute::StrokeAttribute & rStrokeAttribute,double fWaveWidth,double fWaveHeight)440 PolygonWavePrimitive2D::PolygonWavePrimitive2D( 441 const basegfx::B2DPolygon& rPolygon, 442 const attribute::LineAttribute& rLineAttribute, 443 const attribute::StrokeAttribute& rStrokeAttribute, 444 double fWaveWidth, 445 double fWaveHeight) 446 : PolygonStrokePrimitive2D(rPolygon, rLineAttribute, rStrokeAttribute), 447 mfWaveWidth(fWaveWidth), 448 mfWaveHeight(fWaveHeight) 449 { 450 if(mfWaveWidth < 0.0) 451 { 452 mfWaveWidth = 0.0; 453 } 454 455 if(mfWaveHeight < 0.0) 456 { 457 mfWaveHeight = 0.0; 458 } 459 } 460 PolygonWavePrimitive2D(const basegfx::B2DPolygon & rPolygon,const attribute::LineAttribute & rLineAttribute,double fWaveWidth,double fWaveHeight)461 PolygonWavePrimitive2D::PolygonWavePrimitive2D( 462 const basegfx::B2DPolygon& rPolygon, 463 const attribute::LineAttribute& rLineAttribute, 464 double fWaveWidth, 465 double fWaveHeight) 466 : PolygonStrokePrimitive2D(rPolygon, rLineAttribute), 467 mfWaveWidth(fWaveWidth), 468 mfWaveHeight(fWaveHeight) 469 { 470 if(mfWaveWidth < 0.0) 471 { 472 mfWaveWidth = 0.0; 473 } 474 475 if(mfWaveHeight < 0.0) 476 { 477 mfWaveHeight = 0.0; 478 } 479 } 480 operator ==(const BasePrimitive2D & rPrimitive) const481 bool PolygonWavePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const 482 { 483 if(PolygonStrokePrimitive2D::operator==(rPrimitive)) 484 { 485 const PolygonWavePrimitive2D& rCompare = (PolygonWavePrimitive2D&)rPrimitive; 486 487 return (getWaveWidth() == rCompare.getWaveWidth() 488 && getWaveHeight() == rCompare.getWaveHeight()); 489 } 490 491 return false; 492 } 493 getB2DRange(const geometry::ViewInformation2D & rViewInformation) const494 basegfx::B2DRange PolygonWavePrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const 495 { 496 // get range of parent 497 basegfx::B2DRange aRetval(PolygonStrokePrimitive2D::getB2DRange(rViewInformation)); 498 499 // if WaveHeight, grow by it 500 if(basegfx::fTools::more(getWaveHeight(), 0.0)) 501 { 502 aRetval.grow(getWaveHeight()); 503 } 504 505 // if line width, grow by it 506 if(basegfx::fTools::more(getLineAttribute().getWidth(), 0.0)) 507 { 508 aRetval.grow(getLineAttribute().getWidth() * 0.5); 509 } 510 511 return aRetval; 512 } 513 514 // provide unique ID 515 ImplPrimitrive2DIDBlock(PolygonWavePrimitive2D, PRIMITIVE2D_ID_POLYGONWAVEPRIMITIVE2D) 516 517 } // end of namespace primitive2d 518 } // end of namespace drawinglayer 519 520 ////////////////////////////////////////////////////////////////////////////// 521 522 namespace drawinglayer 523 { 524 namespace primitive2d 525 { create2DDecomposition(const geometry::ViewInformation2D &) const526 Primitive2DSequence PolygonStrokeArrowPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const 527 { 528 // copy local polygon, it may be changed 529 basegfx::B2DPolygon aLocalPolygon(getB2DPolygon()); 530 basegfx::B2DPolyPolygon aArrowA; 531 basegfx::B2DPolyPolygon aArrowB; 532 533 if(!aLocalPolygon.isClosed()) 534 { 535 // apply arrows 536 const double fPolyLength(basegfx::tools::getLength(aLocalPolygon)); 537 double fStart(0.0); 538 double fEnd(0.0); 539 double fStartOverlap(0.0); 540 double fEndOverlap(0.0); 541 542 if(!getStart().isDefault() && getStart().isActive()) 543 { 544 // create start arrow primitive and consume 545 aArrowA = basegfx::tools::createAreaGeometryForLineStartEnd( 546 aLocalPolygon, getStart().getB2DPolyPolygon(), true, getStart().getWidth(), 547 fPolyLength, getStart().isCentered() ? 0.5 : 0.0, &fStart); 548 549 // create some overlapping, compromise between straight and peaked markers 550 // best for marker width 0.3cm and marker line width 0.02cm 551 fStartOverlap = getStart().getWidth() / 15.0; 552 } 553 554 if(!getEnd().isDefault() && getEnd().isActive()) 555 { 556 // create end arrow primitive and consume 557 aArrowB = basegfx::tools::createAreaGeometryForLineStartEnd( 558 aLocalPolygon, getEnd().getB2DPolyPolygon(), false, getEnd().getWidth(), 559 fPolyLength, getEnd().isCentered() ? 0.5 : 0.0, &fEnd); 560 561 // create some overlapping 562 fEndOverlap = getEnd().getWidth() / 15.0; 563 } 564 565 if(0.0 != fStart || 0.0 != fEnd) 566 { 567 // build new poly, consume something from old poly 568 aLocalPolygon = basegfx::tools::getSnippetAbsolute(aLocalPolygon, fStart-fStartOverlap, fPolyLength - fEnd + fEndOverlap, fPolyLength); 569 } 570 } 571 572 // prepare return value 573 Primitive2DSequence aRetval(1L + (aArrowA.count() ? 1L : 0L) + (aArrowB.count() ? 1L : 0L)); 574 sal_uInt32 nInd(0L); 575 576 // add shaft 577 const Primitive2DReference xRefShaft(new 578 PolygonStrokePrimitive2D( 579 aLocalPolygon, getLineAttribute(), getStrokeAttribute())); 580 aRetval[nInd++] = xRefShaft; 581 582 if(aArrowA.count()) 583 { 584 const Primitive2DReference xRefA( 585 new PolyPolygonColorPrimitive2D( 586 aArrowA, getLineAttribute().getColor())); 587 aRetval[nInd++] = xRefA; 588 } 589 590 if(aArrowB.count()) 591 { 592 const Primitive2DReference xRefB( 593 new PolyPolygonColorPrimitive2D( 594 aArrowB, getLineAttribute().getColor())); 595 aRetval[nInd++] = xRefB; 596 } 597 598 return aRetval; 599 } 600 PolygonStrokeArrowPrimitive2D(const basegfx::B2DPolygon & rPolygon,const attribute::LineAttribute & rLineAttribute,const attribute::StrokeAttribute & rStrokeAttribute,const attribute::LineStartEndAttribute & rStart,const attribute::LineStartEndAttribute & rEnd)601 PolygonStrokeArrowPrimitive2D::PolygonStrokeArrowPrimitive2D( 602 const basegfx::B2DPolygon& rPolygon, 603 const attribute::LineAttribute& rLineAttribute, 604 const attribute::StrokeAttribute& rStrokeAttribute, 605 const attribute::LineStartEndAttribute& rStart, 606 const attribute::LineStartEndAttribute& rEnd) 607 : PolygonStrokePrimitive2D(rPolygon, rLineAttribute, rStrokeAttribute), 608 maStart(rStart), 609 maEnd(rEnd) 610 { 611 } 612 PolygonStrokeArrowPrimitive2D(const basegfx::B2DPolygon & rPolygon,const attribute::LineAttribute & rLineAttribute,const attribute::LineStartEndAttribute & rStart,const attribute::LineStartEndAttribute & rEnd)613 PolygonStrokeArrowPrimitive2D::PolygonStrokeArrowPrimitive2D( 614 const basegfx::B2DPolygon& rPolygon, 615 const attribute::LineAttribute& rLineAttribute, 616 const attribute::LineStartEndAttribute& rStart, 617 const attribute::LineStartEndAttribute& rEnd) 618 : PolygonStrokePrimitive2D(rPolygon, rLineAttribute), 619 maStart(rStart), 620 maEnd(rEnd) 621 { 622 } 623 operator ==(const BasePrimitive2D & rPrimitive) const624 bool PolygonStrokeArrowPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const 625 { 626 if(PolygonStrokePrimitive2D::operator==(rPrimitive)) 627 { 628 const PolygonStrokeArrowPrimitive2D& rCompare = (PolygonStrokeArrowPrimitive2D&)rPrimitive; 629 630 return (getStart() == rCompare.getStart() 631 && getEnd() == rCompare.getEnd()); 632 } 633 634 return false; 635 } 636 getB2DRange(const geometry::ViewInformation2D & rViewInformation) const637 basegfx::B2DRange PolygonStrokeArrowPrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const 638 { 639 basegfx::B2DRange aRetval; 640 641 if(getStart().isActive() || getEnd().isActive()) 642 { 643 // use decomposition when line start/end is used 644 return BufferedDecompositionPrimitive2D::getB2DRange(rViewInformation); 645 } 646 else 647 { 648 // get range from parent 649 return PolygonStrokePrimitive2D::getB2DRange(rViewInformation); 650 } 651 } 652 653 // provide unique ID 654 ImplPrimitrive2DIDBlock(PolygonStrokeArrowPrimitive2D, PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D) 655 656 } // end of namespace primitive2d 657 } // end of namespace drawinglayer 658 659 ////////////////////////////////////////////////////////////////////////////// 660 // eof 661