xref: /AOO41X/main/drawinglayer/source/primitive2d/polygonprimitive2d.cxx (revision 88e7420bd8e28c20c0032721cf5f459b86d7e953)
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