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 10464702f4SAndrew Rist * 11464702f4SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12464702f4SAndrew Rist * 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. 19464702f4SAndrew Rist * 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> 355aaf853bSArmin 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 { PolygonHairlinePrimitive2D(const basegfx::B2DPolygon & rPolygon,const basegfx::BColor & rBColor)47cdf0e10cSrcweir PolygonHairlinePrimitive2D::PolygonHairlinePrimitive2D( 48cdf0e10cSrcweir const basegfx::B2DPolygon& rPolygon, 49cdf0e10cSrcweir const basegfx::BColor& rBColor) 50cdf0e10cSrcweir : BasePrimitive2D(), 51cdf0e10cSrcweir maPolygon(rPolygon), 52cdf0e10cSrcweir maBColor(rBColor) 53cdf0e10cSrcweir { 54cdf0e10cSrcweir } 55cdf0e10cSrcweir operator ==(const BasePrimitive2D & rPrimitive) const56cdf0e10cSrcweir 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 getB2DRange(const geometry::ViewInformation2D & rViewInformation) const69cdf0e10cSrcweir 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 { create2DDecomposition(const geometry::ViewInformation2D & rViewInformation) const103cdf0e10cSrcweir 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 PolygonMarkerPrimitive2D(const basegfx::B2DPolygon & rPolygon,const basegfx::BColor & rRGBColorA,const basegfx::BColor & rRGBColorB,double fDiscreteDashLength)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 operator ==(const BasePrimitive2D & rPrimitive) const149cdf0e10cSrcweir 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 getB2DRange(const geometry::ViewInformation2D & rViewInformation) const164cdf0e10cSrcweir 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 get2DDecomposition(const geometry::ViewInformation2D & rViewInformation) const186cdf0e10cSrcweir 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 { create2DDecomposition(const geometry::ViewInformation2D &) const228cdf0e10cSrcweir 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()); 2565aaf853bSArmin 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( 2635aaf853bSArmin Le Grand aHairLinePolyPolygon.getB2DPolygon(a), 2645aaf853bSArmin Le Grand fHalfLineWidth, 2655aaf853bSArmin Le Grand aLineJoin, 2665aaf853bSArmin 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 PolygonStrokePrimitive2D(const basegfx::B2DPolygon & rPolygon,const attribute::LineAttribute & rLineAttribute,const attribute::StrokeAttribute & rStrokeAttribute)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 PolygonStrokePrimitive2D(const basegfx::B2DPolygon & rPolygon,const attribute::LineAttribute & rLineAttribute)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 operator ==(const BasePrimitive2D & rPrimitive) const327cdf0e10cSrcweir 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 getB2DRange(const geometry::ViewInformation2D & rViewInformation) const341cdf0e10cSrcweir basegfx::B2DRange PolygonStrokePrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const 342cdf0e10cSrcweir { 343cdf0e10cSrcweir basegfx::B2DRange aRetval; 344cdf0e10cSrcweir 345cdf0e10cSrcweir if(getLineAttribute().getWidth()) 346cdf0e10cSrcweir { 3475aaf853bSArmin Le Grand bool bUseDecomposition(false); 3485aaf853bSArmin 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 3535aaf853bSArmin Le Grand bUseDecomposition = true; 3545aaf853bSArmin Le Grand } 3555aaf853bSArmin Le Grand 3565aaf853bSArmin Le Grand if(!bUseDecomposition && com::sun::star::drawing::LineCap_SQUARE == getLineAttribute().getLineCap()) 3575aaf853bSArmin Le Grand { 3585aaf853bSArmin Le Grand // when drawing::LineCap_SQUARE is used the below method to grow the polygon 3595aaf853bSArmin Le Grand // range by half line width will not work, so use decomposition. Interestingly, 3605aaf853bSArmin Le Grand // the grow method below works perfectly for LineCap_ROUND since the grow is in 3615aaf853bSArmin Le Grand // all directions and the rounded cap needs the same grow in all directions independent 3625aaf853bSArmin Le Grand // from it's orientation. Unfortunately this is not the case for drawing::LineCap_SQUARE 3635aaf853bSArmin Le Grand bUseDecomposition = true; 3645aaf853bSArmin Le Grand } 3655aaf853bSArmin Le Grand 3665aaf853bSArmin Le Grand if(bUseDecomposition) 3675aaf853bSArmin Le Grand { 3685aaf853bSArmin Le Grand // get correct range by using the decomposition fallback, reasons see above cases 3695aaf853bSArmin Le Grand 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 { create2DDecomposition(const geometry::ViewInformation2D &) const413cdf0e10cSrcweir 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 PolygonWavePrimitive2D(const basegfx::B2DPolygon & rPolygon,const attribute::LineAttribute & rLineAttribute,const attribute::StrokeAttribute & rStrokeAttribute,double fWaveWidth,double fWaveHeight)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 PolygonWavePrimitive2D(const basegfx::B2DPolygon & rPolygon,const attribute::LineAttribute & rLineAttribute,double fWaveWidth,double fWaveHeight)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 operator ==(const BasePrimitive2D & rPrimitive) const481cdf0e10cSrcweir 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 getB2DRange(const geometry::ViewInformation2D & rViewInformation) const494cdf0e10cSrcweir 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 { create2DDecomposition(const geometry::ViewInformation2D &) const526cdf0e10cSrcweir 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); 539*88e7420bSRegina Henschel double fStartOverlap(0.0); 540*88e7420bSRegina Henschel double fEndOverlap(0.0); 541cdf0e10cSrcweir 542cdf0e10cSrcweir if(!getStart().isDefault() && getStart().isActive()) 543cdf0e10cSrcweir { 544cdf0e10cSrcweir // create start arrow primitive and consume 545cdf0e10cSrcweir aArrowA = basegfx::tools::createAreaGeometryForLineStartEnd( 546cdf0e10cSrcweir aLocalPolygon, getStart().getB2DPolyPolygon(), true, getStart().getWidth(), 547cdf0e10cSrcweir fPolyLength, getStart().isCentered() ? 0.5 : 0.0, &fStart); 548cdf0e10cSrcweir 549*88e7420bSRegina Henschel // create some overlapping, compromise between straight and peaked markers 550*88e7420bSRegina Henschel // best for marker width 0.3cm and marker line width 0.02cm 551*88e7420bSRegina Henschel fStartOverlap = getStart().getWidth() / 15.0; 552cdf0e10cSrcweir } 553cdf0e10cSrcweir 554cdf0e10cSrcweir if(!getEnd().isDefault() && getEnd().isActive()) 555cdf0e10cSrcweir { 556cdf0e10cSrcweir // create end arrow primitive and consume 557cdf0e10cSrcweir aArrowB = basegfx::tools::createAreaGeometryForLineStartEnd( 558cdf0e10cSrcweir aLocalPolygon, getEnd().getB2DPolyPolygon(), false, getEnd().getWidth(), 559cdf0e10cSrcweir fPolyLength, getEnd().isCentered() ? 0.5 : 0.0, &fEnd); 560cdf0e10cSrcweir 561cdf0e10cSrcweir // create some overlapping 562*88e7420bSRegina Henschel fEndOverlap = getEnd().getWidth() / 15.0; 563cdf0e10cSrcweir } 564cdf0e10cSrcweir 565cdf0e10cSrcweir if(0.0 != fStart || 0.0 != fEnd) 566cdf0e10cSrcweir { 567cdf0e10cSrcweir // build new poly, consume something from old poly 568*88e7420bSRegina Henschel aLocalPolygon = basegfx::tools::getSnippetAbsolute(aLocalPolygon, fStart-fStartOverlap, fPolyLength - fEnd + fEndOverlap, fPolyLength); 569cdf0e10cSrcweir } 570cdf0e10cSrcweir } 571cdf0e10cSrcweir 572cdf0e10cSrcweir // prepare return value 573cdf0e10cSrcweir Primitive2DSequence aRetval(1L + (aArrowA.count() ? 1L : 0L) + (aArrowB.count() ? 1L : 0L)); 574cdf0e10cSrcweir sal_uInt32 nInd(0L); 575cdf0e10cSrcweir 576cdf0e10cSrcweir // add shaft 577cdf0e10cSrcweir const Primitive2DReference xRefShaft(new 578cdf0e10cSrcweir PolygonStrokePrimitive2D( 579cdf0e10cSrcweir aLocalPolygon, getLineAttribute(), getStrokeAttribute())); 580cdf0e10cSrcweir aRetval[nInd++] = xRefShaft; 581cdf0e10cSrcweir 582cdf0e10cSrcweir if(aArrowA.count()) 583cdf0e10cSrcweir { 584cdf0e10cSrcweir const Primitive2DReference xRefA( 585cdf0e10cSrcweir new PolyPolygonColorPrimitive2D( 586cdf0e10cSrcweir aArrowA, getLineAttribute().getColor())); 587cdf0e10cSrcweir aRetval[nInd++] = xRefA; 588cdf0e10cSrcweir } 589cdf0e10cSrcweir 590cdf0e10cSrcweir if(aArrowB.count()) 591cdf0e10cSrcweir { 592cdf0e10cSrcweir const Primitive2DReference xRefB( 593cdf0e10cSrcweir new PolyPolygonColorPrimitive2D( 594cdf0e10cSrcweir aArrowB, getLineAttribute().getColor())); 595cdf0e10cSrcweir aRetval[nInd++] = xRefB; 596cdf0e10cSrcweir } 597cdf0e10cSrcweir 598cdf0e10cSrcweir return aRetval; 599cdf0e10cSrcweir } 600cdf0e10cSrcweir PolygonStrokeArrowPrimitive2D(const basegfx::B2DPolygon & rPolygon,const attribute::LineAttribute & rLineAttribute,const attribute::StrokeAttribute & rStrokeAttribute,const attribute::LineStartEndAttribute & rStart,const attribute::LineStartEndAttribute & rEnd)601cdf0e10cSrcweir PolygonStrokeArrowPrimitive2D::PolygonStrokeArrowPrimitive2D( 602cdf0e10cSrcweir const basegfx::B2DPolygon& rPolygon, 603cdf0e10cSrcweir const attribute::LineAttribute& rLineAttribute, 604cdf0e10cSrcweir const attribute::StrokeAttribute& rStrokeAttribute, 605cdf0e10cSrcweir const attribute::LineStartEndAttribute& rStart, 606cdf0e10cSrcweir const attribute::LineStartEndAttribute& rEnd) 607cdf0e10cSrcweir : PolygonStrokePrimitive2D(rPolygon, rLineAttribute, rStrokeAttribute), 608cdf0e10cSrcweir maStart(rStart), 609cdf0e10cSrcweir maEnd(rEnd) 610cdf0e10cSrcweir { 611cdf0e10cSrcweir } 612cdf0e10cSrcweir PolygonStrokeArrowPrimitive2D(const basegfx::B2DPolygon & rPolygon,const attribute::LineAttribute & rLineAttribute,const attribute::LineStartEndAttribute & rStart,const attribute::LineStartEndAttribute & rEnd)613cdf0e10cSrcweir PolygonStrokeArrowPrimitive2D::PolygonStrokeArrowPrimitive2D( 614cdf0e10cSrcweir const basegfx::B2DPolygon& rPolygon, 615cdf0e10cSrcweir const attribute::LineAttribute& rLineAttribute, 616cdf0e10cSrcweir const attribute::LineStartEndAttribute& rStart, 617cdf0e10cSrcweir const attribute::LineStartEndAttribute& rEnd) 618cdf0e10cSrcweir : PolygonStrokePrimitive2D(rPolygon, rLineAttribute), 619cdf0e10cSrcweir maStart(rStart), 620cdf0e10cSrcweir maEnd(rEnd) 621cdf0e10cSrcweir { 622cdf0e10cSrcweir } 623cdf0e10cSrcweir operator ==(const BasePrimitive2D & rPrimitive) const624cdf0e10cSrcweir bool PolygonStrokeArrowPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const 625cdf0e10cSrcweir { 626cdf0e10cSrcweir if(PolygonStrokePrimitive2D::operator==(rPrimitive)) 627cdf0e10cSrcweir { 628cdf0e10cSrcweir const PolygonStrokeArrowPrimitive2D& rCompare = (PolygonStrokeArrowPrimitive2D&)rPrimitive; 629cdf0e10cSrcweir 630cdf0e10cSrcweir return (getStart() == rCompare.getStart() 631cdf0e10cSrcweir && getEnd() == rCompare.getEnd()); 632cdf0e10cSrcweir } 633cdf0e10cSrcweir 634cdf0e10cSrcweir return false; 635cdf0e10cSrcweir } 636cdf0e10cSrcweir getB2DRange(const geometry::ViewInformation2D & rViewInformation) const637cdf0e10cSrcweir basegfx::B2DRange PolygonStrokeArrowPrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const 638cdf0e10cSrcweir { 639cdf0e10cSrcweir basegfx::B2DRange aRetval; 640cdf0e10cSrcweir 641cdf0e10cSrcweir if(getStart().isActive() || getEnd().isActive()) 642cdf0e10cSrcweir { 643cdf0e10cSrcweir // use decomposition when line start/end is used 644cdf0e10cSrcweir return BufferedDecompositionPrimitive2D::getB2DRange(rViewInformation); 645cdf0e10cSrcweir } 646cdf0e10cSrcweir else 647cdf0e10cSrcweir { 648cdf0e10cSrcweir // get range from parent 649cdf0e10cSrcweir return PolygonStrokePrimitive2D::getB2DRange(rViewInformation); 650cdf0e10cSrcweir } 651cdf0e10cSrcweir } 652cdf0e10cSrcweir 653cdf0e10cSrcweir // provide unique ID 654cdf0e10cSrcweir ImplPrimitrive2DIDBlock(PolygonStrokeArrowPrimitive2D, PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D) 655cdf0e10cSrcweir 656cdf0e10cSrcweir } // end of namespace primitive2d 657cdf0e10cSrcweir } // end of namespace drawinglayer 658cdf0e10cSrcweir 659cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 660cdf0e10cSrcweir // eof 661