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