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