xref: /AOO41X/main/drawinglayer/source/primitive2d/polygonprimitive2d.cxx (revision ff0525f24f03981d56b7579b645949f111420994)
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     {
47         PolygonHairlinePrimitive2D::PolygonHairlinePrimitive2D(
48             const basegfx::B2DPolygon& rPolygon,
49             const basegfx::BColor& rBColor)
50         :   BasePrimitive2D(),
51             maPolygon(rPolygon),
52             maBColor(rBColor)
53         {
54         }
55 
56         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 
69         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     {
103         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 
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 
149         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 
164         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 
186         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     {
228         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 
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 
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 
327         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 
341         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     {
413         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 
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 
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 
481         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 
494         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     {
526         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 
540                 if(!getStart().isDefault() && getStart().isActive())
541                 {
542                     // create start arrow primitive and consume
543                     aArrowA = basegfx::tools::createAreaGeometryForLineStartEnd(
544                         aLocalPolygon, getStart().getB2DPolyPolygon(), true, getStart().getWidth(),
545                         fPolyLength, getStart().isCentered() ? 0.5 : 0.0, &fStart);
546 
547                     // create some overlapping
548                     fStart *= 0.8;
549                 }
550 
551                 if(!getEnd().isDefault() && getEnd().isActive())
552                 {
553                     // create end arrow primitive and consume
554                     aArrowB = basegfx::tools::createAreaGeometryForLineStartEnd(
555                         aLocalPolygon, getEnd().getB2DPolyPolygon(), false, getEnd().getWidth(),
556                         fPolyLength, getEnd().isCentered() ? 0.5 : 0.0, &fEnd);
557 
558                     // create some overlapping
559                     fEnd *= 0.8;
560                 }
561 
562                 if(0.0 != fStart || 0.0 != fEnd)
563                 {
564                     // build new poly, consume something from old poly
565                     aLocalPolygon = basegfx::tools::getSnippetAbsolute(aLocalPolygon, fStart, fPolyLength - fEnd, fPolyLength);
566                 }
567             }
568 
569             // prepare return value
570             Primitive2DSequence aRetval(1L + (aArrowA.count() ? 1L : 0L) + (aArrowB.count() ? 1L : 0L));
571             sal_uInt32 nInd(0L);
572 
573             // add shaft
574             const Primitive2DReference xRefShaft(new
575                 PolygonStrokePrimitive2D(
576                     aLocalPolygon, getLineAttribute(), getStrokeAttribute()));
577             aRetval[nInd++] = xRefShaft;
578 
579             if(aArrowA.count())
580             {
581                 const Primitive2DReference xRefA(
582                     new PolyPolygonColorPrimitive2D(
583                         aArrowA, getLineAttribute().getColor()));
584                 aRetval[nInd++] = xRefA;
585             }
586 
587             if(aArrowB.count())
588             {
589                 const Primitive2DReference xRefB(
590                     new PolyPolygonColorPrimitive2D(
591                         aArrowB, getLineAttribute().getColor()));
592                 aRetval[nInd++] = xRefB;
593             }
594 
595             return aRetval;
596         }
597 
598         PolygonStrokeArrowPrimitive2D::PolygonStrokeArrowPrimitive2D(
599             const basegfx::B2DPolygon& rPolygon,
600             const attribute::LineAttribute& rLineAttribute,
601             const attribute::StrokeAttribute& rStrokeAttribute,
602             const attribute::LineStartEndAttribute& rStart,
603             const attribute::LineStartEndAttribute& rEnd)
604         :   PolygonStrokePrimitive2D(rPolygon, rLineAttribute, rStrokeAttribute),
605             maStart(rStart),
606             maEnd(rEnd)
607         {
608         }
609 
610         PolygonStrokeArrowPrimitive2D::PolygonStrokeArrowPrimitive2D(
611             const basegfx::B2DPolygon& rPolygon,
612             const attribute::LineAttribute& rLineAttribute,
613             const attribute::LineStartEndAttribute& rStart,
614             const attribute::LineStartEndAttribute& rEnd)
615         :   PolygonStrokePrimitive2D(rPolygon, rLineAttribute),
616             maStart(rStart),
617             maEnd(rEnd)
618         {
619         }
620 
621         bool PolygonStrokeArrowPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
622         {
623             if(PolygonStrokePrimitive2D::operator==(rPrimitive))
624             {
625                 const PolygonStrokeArrowPrimitive2D& rCompare = (PolygonStrokeArrowPrimitive2D&)rPrimitive;
626 
627                 return (getStart() == rCompare.getStart()
628                     && getEnd() == rCompare.getEnd());
629             }
630 
631             return false;
632         }
633 
634         basegfx::B2DRange PolygonStrokeArrowPrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
635         {
636             basegfx::B2DRange aRetval;
637 
638             if(getStart().isActive() || getEnd().isActive())
639             {
640                 // use decomposition when line start/end is used
641                 return BufferedDecompositionPrimitive2D::getB2DRange(rViewInformation);
642             }
643             else
644             {
645                 // get range from parent
646                 return PolygonStrokePrimitive2D::getB2DRange(rViewInformation);
647             }
648         }
649 
650         // provide unique ID
651         ImplPrimitrive2DIDBlock(PolygonStrokeArrowPrimitive2D, PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D)
652 
653     } // end of namespace primitive2d
654 } // end of namespace drawinglayer
655 
656 //////////////////////////////////////////////////////////////////////////////
657 // eof
658