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