Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
21 : #include <basegfx/tools/canvastools.hxx>
22 : #include <basegfx/polygon/b2dpolygontools.hxx>
23 : #include <basegfx/polygon/b2dpolypolygontools.hxx>
24 : #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
25 : #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
26 : #include <drawinglayer/geometry/viewinformation2d.hxx>
27 : #include <basegfx/polygon/b2dlinegeometry.hxx>
28 : #include <boost/math/special_functions/next.hpp>
29 : #include <com/sun/star/drawing/LineCap.hpp>
30 : #include <comphelper/random.hxx>
31 :
32 : using namespace com::sun::star;
33 :
34 :
35 :
36 : namespace drawinglayer
37 : {
38 : namespace primitive2d
39 : {
40 83091 : PolygonHairlinePrimitive2D::PolygonHairlinePrimitive2D(
41 : const basegfx::B2DPolygon& rPolygon,
42 : const basegfx::BColor& rBColor)
43 : : BasePrimitive2D(),
44 : maPolygon(rPolygon),
45 83091 : maBColor(rBColor)
46 : {
47 83091 : }
48 :
49 5472 : bool PolygonHairlinePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
50 : {
51 5472 : if(BasePrimitive2D::operator==(rPrimitive))
52 : {
53 5472 : const PolygonHairlinePrimitive2D& rCompare = static_cast<const PolygonHairlinePrimitive2D&>(rPrimitive);
54 :
55 5472 : return (getB2DPolygon() == rCompare.getB2DPolygon()
56 5472 : && getBColor() == rCompare.getBColor());
57 : }
58 :
59 0 : return false;
60 : }
61 :
62 7852 : basegfx::B2DRange PolygonHairlinePrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
63 : {
64 : // this is a hairline, thus the line width is view-dependent. Get range of polygon
65 : // as base size
66 7852 : basegfx::B2DRange aRetval(getB2DPolygon().getB2DRange());
67 :
68 7852 : if(!aRetval.isEmpty())
69 : {
70 : // Calculate view-dependent hairline width
71 7852 : const basegfx::B2DVector aDiscreteSize(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 0.0));
72 7852 : const double fDiscreteHalfLineWidth(aDiscreteSize.getLength() * 0.5);
73 :
74 7852 : if(basegfx::fTools::more(fDiscreteHalfLineWidth, 0.0))
75 : {
76 7852 : aRetval.grow(fDiscreteHalfLineWidth);
77 7852 : }
78 : }
79 :
80 : // return range
81 7852 : return aRetval;
82 : }
83 :
84 : // provide unique ID
85 107777 : ImplPrimitive2DIDBlock(PolygonHairlinePrimitive2D, PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D)
86 :
87 : } // end of namespace primitive2d
88 : } // end of namespace drawinglayer
89 :
90 :
91 :
92 : namespace drawinglayer
93 : {
94 : namespace primitive2d
95 : {
96 0 : Primitive2DSequence PolygonMarkerPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
97 : {
98 : // calculate logic DashLength
99 0 : const basegfx::B2DVector aDashVector(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(getDiscreteDashLength(), 0.0));
100 0 : const double fLogicDashLength(aDashVector.getX());
101 :
102 0 : if(fLogicDashLength > 0.0 && !getRGBColorA().equal(getRGBColorB()))
103 : {
104 : // apply dashing; get line and gap snippets
105 0 : ::std::vector< double > aDash;
106 0 : basegfx::B2DPolyPolygon aDashedPolyPolyA;
107 0 : basegfx::B2DPolyPolygon aDashedPolyPolyB;
108 :
109 0 : aDash.push_back(fLogicDashLength);
110 0 : aDash.push_back(fLogicDashLength);
111 0 : basegfx::tools::applyLineDashing(getB2DPolygon(), aDash, &aDashedPolyPolyA, &aDashedPolyPolyB, 2.0 * fLogicDashLength);
112 :
113 : // prepare return value
114 0 : Primitive2DSequence aRetval(2);
115 :
116 0 : aRetval[0] = Primitive2DReference(new PolyPolygonHairlinePrimitive2D(aDashedPolyPolyA, getRGBColorA()));
117 0 : aRetval[1] = Primitive2DReference(new PolyPolygonHairlinePrimitive2D(aDashedPolyPolyB, getRGBColorB()));
118 :
119 0 : return aRetval;
120 : }
121 : else
122 : {
123 0 : const Primitive2DReference xRef(new PolygonHairlinePrimitive2D(getB2DPolygon(), getRGBColorA()));
124 0 : return Primitive2DSequence(&xRef, 1L);
125 0 : }
126 : }
127 :
128 0 : PolygonMarkerPrimitive2D::PolygonMarkerPrimitive2D(
129 : const basegfx::B2DPolygon& rPolygon,
130 : const basegfx::BColor& rRGBColorA,
131 : const basegfx::BColor& rRGBColorB,
132 : double fDiscreteDashLength)
133 : : BufferedDecompositionPrimitive2D(),
134 : maPolygon(rPolygon),
135 : maRGBColorA(rRGBColorA),
136 : maRGBColorB(rRGBColorB),
137 : mfDiscreteDashLength(fDiscreteDashLength),
138 0 : maLastInverseObjectToViewTransformation()
139 : {
140 0 : }
141 :
142 0 : bool PolygonMarkerPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
143 : {
144 0 : if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
145 : {
146 0 : const PolygonMarkerPrimitive2D& rCompare = static_cast<const PolygonMarkerPrimitive2D&>(rPrimitive);
147 :
148 0 : return (getB2DPolygon() == rCompare.getB2DPolygon()
149 0 : && getRGBColorA() == rCompare.getRGBColorA()
150 0 : && getRGBColorB() == rCompare.getRGBColorB()
151 0 : && getDiscreteDashLength() == rCompare.getDiscreteDashLength());
152 : }
153 :
154 0 : return false;
155 : }
156 :
157 0 : basegfx::B2DRange PolygonMarkerPrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
158 : {
159 : // this is a hairline, thus the line width is view-dependent. Get range of polygon
160 : // as base size
161 0 : basegfx::B2DRange aRetval(getB2DPolygon().getB2DRange());
162 :
163 0 : if(!aRetval.isEmpty())
164 : {
165 : // Calculate view-dependent hairline width
166 0 : const basegfx::B2DVector aDiscreteSize(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 0.0));
167 0 : const double fDiscreteHalfLineWidth(aDiscreteSize.getLength() * 0.5);
168 :
169 0 : if(basegfx::fTools::more(fDiscreteHalfLineWidth, 0.0))
170 : {
171 0 : aRetval.grow(fDiscreteHalfLineWidth);
172 0 : }
173 : }
174 :
175 : // return range
176 0 : return aRetval;
177 : }
178 :
179 0 : Primitive2DSequence PolygonMarkerPrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
180 : {
181 0 : ::osl::MutexGuard aGuard( m_aMutex );
182 0 : bool bNeedNewDecomposition(false);
183 :
184 0 : if(getBuffered2DDecomposition().hasElements())
185 : {
186 0 : if(rViewInformation.getInverseObjectToViewTransformation() != maLastInverseObjectToViewTransformation)
187 : {
188 0 : bNeedNewDecomposition = true;
189 : }
190 : }
191 :
192 0 : if(bNeedNewDecomposition)
193 : {
194 : // conditions of last local decomposition have changed, delete
195 0 : const_cast< PolygonMarkerPrimitive2D* >(this)->setBuffered2DDecomposition(Primitive2DSequence());
196 : }
197 :
198 0 : if(!getBuffered2DDecomposition().hasElements())
199 : {
200 : // remember last used InverseObjectToViewTransformation
201 0 : PolygonMarkerPrimitive2D* pThat = const_cast< PolygonMarkerPrimitive2D* >(this);
202 0 : pThat->maLastInverseObjectToViewTransformation = rViewInformation.getInverseObjectToViewTransformation();
203 : }
204 :
205 : // use parent implementation
206 0 : return BufferedDecompositionPrimitive2D::get2DDecomposition(rViewInformation);
207 : }
208 :
209 : // provide unique ID
210 0 : ImplPrimitive2DIDBlock(PolygonMarkerPrimitive2D, PRIMITIVE2D_ID_POLYGONMARKERPRIMITIVE2D)
211 :
212 : } // end of namespace primitive2d
213 : } // end of namespace drawinglayer
214 :
215 : namespace drawinglayer
216 : {
217 : namespace tools
218 : {
219 0 : double getRandomColorRange()
220 : {
221 0 : return comphelper::rng::uniform_real_distribution(0.0, boost::math::nextafter(1.0, DBL_MAX));
222 : }
223 : }
224 :
225 : namespace primitive2d
226 : {
227 13258 : Primitive2DSequence PolygonStrokePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
228 : {
229 13258 : if(getB2DPolygon().count())
230 : {
231 : // #i102241# try to simplify before usage
232 13258 : const basegfx::B2DPolygon aB2DPolygon(basegfx::tools::simplifyCurveSegments(getB2DPolygon()));
233 26516 : basegfx::B2DPolyPolygon aHairLinePolyPolygon;
234 :
235 13258 : if(getStrokeAttribute().isDefault() || 0.0 == getStrokeAttribute().getFullDotDashLen())
236 : {
237 : // no line dashing, just copy
238 12858 : aHairLinePolyPolygon.append(aB2DPolygon);
239 : }
240 : else
241 : {
242 : // apply LineStyle
243 : basegfx::tools::applyLineDashing(
244 400 : aB2DPolygon, getStrokeAttribute().getDotDashArray(),
245 800 : &aHairLinePolyPolygon, 0, getStrokeAttribute().getFullDotDashLen());
246 : }
247 :
248 13258 : const sal_uInt32 nCount(aHairLinePolyPolygon.count());
249 :
250 13258 : if(!getLineAttribute().isDefault() && getLineAttribute().getWidth())
251 : {
252 : // create fat line data
253 2725 : const double fHalfLineWidth(getLineAttribute().getWidth() / 2.0);
254 2725 : const basegfx::B2DLineJoin aLineJoin(getLineAttribute().getLineJoin());
255 2725 : const com::sun::star::drawing::LineCap aLineCap(getLineAttribute().getLineCap());
256 2725 : basegfx::B2DPolyPolygon aAreaPolyPolygon;
257 :
258 12115 : for(sal_uInt32 a(0L); a < nCount; a++)
259 : {
260 : // New version of createAreaGeometry; now creates bezier polygons
261 : aAreaPolyPolygon.append(basegfx::tools::createAreaGeometry(
262 : aHairLinePolyPolygon.getB2DPolygon(a),
263 : fHalfLineWidth,
264 : aLineJoin,
265 9390 : aLineCap));
266 : }
267 :
268 : // prepare return value
269 5450 : Primitive2DSequence aRetval(aAreaPolyPolygon.count());
270 :
271 : // create primitive
272 67520 : 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 tools::PolyPolygon (XORed as fill rule). Alternatively, a
276 : // melting process may be used here one day.
277 64795 : const basegfx::B2DPolyPolygon aNewPolyPolygon(aAreaPolyPolygon.getB2DPolygon(b));
278 : static bool bTestByUsingRandomColor(false);
279 : const basegfx::BColor aColor(bTestByUsingRandomColor
280 : ? basegfx::BColor(tools::getRandomColorRange(), tools::getRandomColorRange(), tools::getRandomColorRange())
281 129590 : : getLineAttribute().getColor());
282 129590 : const Primitive2DReference xRef(new PolyPolygonColorPrimitive2D(aNewPolyPolygon, aColor));
283 64795 : aRetval[b] = xRef;
284 64795 : }
285 :
286 5450 : return aRetval;
287 : }
288 : else
289 : {
290 : // prepare return value
291 : const Primitive2DReference xRef(
292 : new PolyPolygonHairlinePrimitive2D(
293 : aHairLinePolyPolygon,
294 10533 : getLineAttribute().getColor()));
295 :
296 10533 : return Primitive2DSequence(&xRef, 1);
297 13258 : }
298 : }
299 : else
300 : {
301 0 : return Primitive2DSequence();
302 : }
303 : }
304 :
305 40548 : 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 40548 : maStrokeAttribute(rStrokeAttribute)
313 : {
314 40548 : }
315 :
316 1748 : PolygonStrokePrimitive2D::PolygonStrokePrimitive2D(
317 : const basegfx::B2DPolygon& rPolygon,
318 : const attribute::LineAttribute& rLineAttribute)
319 : : BufferedDecompositionPrimitive2D(),
320 : maPolygon(rPolygon),
321 : maLineAttribute(rLineAttribute),
322 1748 : maStrokeAttribute()
323 : {
324 1748 : }
325 :
326 40 : bool PolygonStrokePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
327 : {
328 40 : if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
329 : {
330 40 : const PolygonStrokePrimitive2D& rCompare = static_cast<const PolygonStrokePrimitive2D&>(rPrimitive);
331 :
332 40 : return (getB2DPolygon() == rCompare.getB2DPolygon()
333 40 : && getLineAttribute() == rCompare.getLineAttribute()
334 80 : && getStrokeAttribute() == rCompare.getStrokeAttribute());
335 : }
336 :
337 0 : return false;
338 : }
339 :
340 176366 : basegfx::B2DRange PolygonStrokePrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
341 : {
342 176366 : basegfx::B2DRange aRetval;
343 :
344 176366 : if(getLineAttribute().getWidth())
345 : {
346 58984 : bool bUseDecomposition(false);
347 :
348 58984 : if(basegfx::B2DLINEJOIN_MITER == getLineAttribute().getLineJoin())
349 : {
350 : // if line is mitered, use parent call since mitered line
351 : // geometry may use more space than the geometry grown by half line width
352 2964 : bUseDecomposition = true;
353 : }
354 :
355 58984 : if(!bUseDecomposition && com::sun::star::drawing::LineCap_SQUARE == getLineAttribute().getLineCap())
356 : {
357 : // when drawing::LineCap_SQUARE is used the below method to grow the polygon
358 : // range by half line width will not work, so use decomposition. Interestingly,
359 : // the grow method below works perfectly for LineCap_ROUND since the grow is in
360 : // all directions and the rounded cap needs the same grow in all directions independent
361 : // from it's orientation. Unfortunately this is not the case for drawing::LineCap_SQUARE
362 0 : bUseDecomposition = true;
363 : }
364 :
365 58984 : if(bUseDecomposition)
366 : {
367 : // get correct range by using the decomposition fallback, reasons see above cases
368 2964 : aRetval = BufferedDecompositionPrimitive2D::getB2DRange(rViewInformation);
369 : }
370 : else
371 : {
372 : // for all other B2DLINEJOIN_* get the range from the base geometry
373 : // and expand by half the line width
374 56020 : aRetval = getB2DPolygon().getB2DRange();
375 56020 : aRetval.grow(getLineAttribute().getWidth() * 0.5);
376 : }
377 : }
378 : else
379 : {
380 : // this is a hairline, thus the line width is view-dependent. Get range of polygon
381 : // as base size
382 117382 : aRetval = getB2DPolygon().getB2DRange();
383 :
384 117382 : if(!aRetval.isEmpty())
385 : {
386 : // Calculate view-dependent hairline width
387 117382 : const basegfx::B2DVector aDiscreteSize(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 0.0));
388 117382 : const double fDiscreteHalfLineWidth(aDiscreteSize.getLength() * 0.5);
389 :
390 117382 : if(basegfx::fTools::more(fDiscreteHalfLineWidth, 0.0))
391 : {
392 117382 : aRetval.grow(fDiscreteHalfLineWidth);
393 117382 : }
394 : }
395 : }
396 :
397 176366 : return aRetval;
398 : }
399 :
400 : // provide unique ID
401 27641 : ImplPrimitive2DIDBlock(PolygonStrokePrimitive2D, PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D)
402 :
403 : } // end of namespace primitive2d
404 : } // end of namespace drawinglayer
405 :
406 :
407 :
408 : namespace drawinglayer
409 : {
410 : namespace primitive2d
411 : {
412 0 : Primitive2DSequence PolygonWavePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
413 : {
414 0 : Primitive2DSequence aRetval;
415 :
416 0 : if(getB2DPolygon().count())
417 : {
418 0 : const bool bHasWidth(!basegfx::fTools::equalZero(getWaveWidth()));
419 0 : const bool bHasHeight(!basegfx::fTools::equalZero(getWaveHeight()));
420 :
421 0 : if(bHasWidth && bHasHeight)
422 : {
423 : // create waveline curve
424 0 : const basegfx::B2DPolygon aWaveline(basegfx::tools::createWaveline(getB2DPolygon(), getWaveWidth(), getWaveHeight()));
425 0 : const Primitive2DReference xRef(new PolygonStrokePrimitive2D(aWaveline, getLineAttribute(), getStrokeAttribute()));
426 0 : aRetval = Primitive2DSequence(&xRef, 1);
427 : }
428 : else
429 : {
430 : // flat waveline, decompose to simple line primitive
431 0 : const Primitive2DReference xRef(new PolygonStrokePrimitive2D(getB2DPolygon(), getLineAttribute(), getStrokeAttribute()));
432 0 : aRetval = Primitive2DSequence(&xRef, 1);
433 : }
434 : }
435 :
436 0 : return aRetval;
437 : }
438 :
439 0 : PolygonWavePrimitive2D::PolygonWavePrimitive2D(
440 : const basegfx::B2DPolygon& rPolygon,
441 : const attribute::LineAttribute& rLineAttribute,
442 : const attribute::StrokeAttribute& rStrokeAttribute,
443 : double fWaveWidth,
444 : double fWaveHeight)
445 : : PolygonStrokePrimitive2D(rPolygon, rLineAttribute, rStrokeAttribute),
446 : mfWaveWidth(fWaveWidth),
447 0 : mfWaveHeight(fWaveHeight)
448 : {
449 0 : if(mfWaveWidth < 0.0)
450 : {
451 0 : mfWaveWidth = 0.0;
452 : }
453 :
454 0 : if(mfWaveHeight < 0.0)
455 : {
456 0 : mfWaveHeight = 0.0;
457 : }
458 0 : }
459 :
460 0 : PolygonWavePrimitive2D::PolygonWavePrimitive2D(
461 : const basegfx::B2DPolygon& rPolygon,
462 : const attribute::LineAttribute& rLineAttribute,
463 : double fWaveWidth,
464 : double fWaveHeight)
465 : : PolygonStrokePrimitive2D(rPolygon, rLineAttribute),
466 : mfWaveWidth(fWaveWidth),
467 0 : mfWaveHeight(fWaveHeight)
468 : {
469 0 : if(mfWaveWidth < 0.0)
470 : {
471 0 : mfWaveWidth = 0.0;
472 : }
473 :
474 0 : if(mfWaveHeight < 0.0)
475 : {
476 0 : mfWaveHeight = 0.0;
477 : }
478 0 : }
479 :
480 0 : bool PolygonWavePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
481 : {
482 0 : if(PolygonStrokePrimitive2D::operator==(rPrimitive))
483 : {
484 0 : const PolygonWavePrimitive2D& rCompare = static_cast<const PolygonWavePrimitive2D&>(rPrimitive);
485 :
486 0 : return (getWaveWidth() == rCompare.getWaveWidth()
487 0 : && getWaveHeight() == rCompare.getWaveHeight());
488 : }
489 :
490 0 : return false;
491 : }
492 :
493 0 : basegfx::B2DRange PolygonWavePrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
494 : {
495 : // get range of parent
496 0 : basegfx::B2DRange aRetval(PolygonStrokePrimitive2D::getB2DRange(rViewInformation));
497 :
498 : // if WaveHeight, grow by it
499 0 : if(basegfx::fTools::more(getWaveHeight(), 0.0))
500 : {
501 0 : aRetval.grow(getWaveHeight());
502 : }
503 :
504 : // if line width, grow by it
505 0 : if(basegfx::fTools::more(getLineAttribute().getWidth(), 0.0))
506 : {
507 0 : aRetval.grow(getLineAttribute().getWidth() * 0.5);
508 : }
509 :
510 0 : return aRetval;
511 : }
512 :
513 : // provide unique ID
514 0 : ImplPrimitive2DIDBlock(PolygonWavePrimitive2D, PRIMITIVE2D_ID_POLYGONWAVEPRIMITIVE2D)
515 :
516 : } // end of namespace primitive2d
517 : } // end of namespace drawinglayer
518 :
519 :
520 :
521 : namespace drawinglayer
522 : {
523 : namespace primitive2d
524 : {
525 786 : Primitive2DSequence PolygonStrokeArrowPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
526 : {
527 : // copy local polygon, it may be changed
528 786 : basegfx::B2DPolygon aLocalPolygon(getB2DPolygon());
529 786 : aLocalPolygon.removeDoublePoints();
530 1572 : basegfx::B2DPolyPolygon aArrowA;
531 1572 : basegfx::B2DPolyPolygon aArrowB;
532 :
533 786 : if(!aLocalPolygon.isClosed() && aLocalPolygon.count() > 1)
534 : {
535 : // apply arrows
536 288 : const double fPolyLength(basegfx::tools::getLength(aLocalPolygon));
537 288 : double fStart(0.0);
538 288 : double fEnd(0.0);
539 288 : double fStartOverlap(0.0);
540 288 : double fEndOverlap(0.0);
541 :
542 288 : if(!getStart().isDefault() && getStart().isActive())
543 : {
544 : // create start arrow primitive and consume
545 408 : aArrowA = basegfx::tools::createAreaGeometryForLineStartEnd(
546 204 : aLocalPolygon, getStart().getB2DPolyPolygon(), true, getStart().getWidth(),
547 204 : fPolyLength, getStart().isCentered() ? 0.5 : 0.0, &fStart);
548 :
549 : // create some overlapping, compromise between straight and peaked markers
550 : // for marker width 0.3cm and marker line width 0.02cm
551 102 : fStartOverlap = getStart().getWidth() / 15.0;
552 : }
553 :
554 288 : if(!getEnd().isDefault() && getEnd().isActive())
555 : {
556 : // create end arrow primitive and consume
557 1032 : aArrowB = basegfx::tools::createAreaGeometryForLineStartEnd(
558 516 : aLocalPolygon, getEnd().getB2DPolyPolygon(), false, getEnd().getWidth(),
559 516 : fPolyLength, getEnd().isCentered() ? 0.5 : 0.0, &fEnd);
560 :
561 : // create some overlapping
562 258 : fEndOverlap = getEnd().getWidth() / 15.0;
563 : }
564 :
565 288 : if(0.0 != fStart || 0.0 != fEnd)
566 : {
567 : // build new poly, consume something from old poly
568 288 : aLocalPolygon = basegfx::tools::getSnippetAbsolute(aLocalPolygon, fStart-fStartOverlap, fPolyLength - fEnd + fEndOverlap, fPolyLength);
569 : }
570 : }
571 :
572 : // prepare return value
573 786 : Primitive2DSequence aRetval(1L + (aArrowA.count() ? 1L : 0L) + (aArrowB.count() ? 1L : 0L));
574 786 : sal_uInt32 nInd(0L);
575 :
576 : // add shaft
577 : const Primitive2DReference xRefShaft(new
578 : PolygonStrokePrimitive2D(
579 1572 : aLocalPolygon, getLineAttribute(), getStrokeAttribute()));
580 786 : aRetval[nInd++] = xRefShaft;
581 :
582 786 : if(aArrowA.count())
583 : {
584 : const Primitive2DReference xRefA(
585 : new PolyPolygonColorPrimitive2D(
586 102 : aArrowA, getLineAttribute().getColor()));
587 102 : aRetval[nInd++] = xRefA;
588 : }
589 :
590 786 : if(aArrowB.count())
591 : {
592 : const Primitive2DReference xRefB(
593 : new PolyPolygonColorPrimitive2D(
594 258 : aArrowB, getLineAttribute().getColor()));
595 258 : aRetval[nInd++] = xRefB;
596 : }
597 :
598 1572 : return aRetval;
599 : }
600 :
601 786 : 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 786 : maEnd(rEnd)
610 : {
611 786 : }
612 :
613 0 : 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 0 : maEnd(rEnd)
621 : {
622 0 : }
623 :
624 0 : bool PolygonStrokeArrowPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
625 : {
626 0 : if(PolygonStrokePrimitive2D::operator==(rPrimitive))
627 : {
628 0 : const PolygonStrokeArrowPrimitive2D& rCompare = static_cast<const PolygonStrokeArrowPrimitive2D&>(rPrimitive);
629 :
630 0 : return (getStart() == rCompare.getStart()
631 0 : && getEnd() == rCompare.getEnd());
632 : }
633 :
634 0 : return false;
635 : }
636 :
637 1600 : basegfx::B2DRange PolygonStrokeArrowPrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
638 : {
639 1600 : basegfx::B2DRange aRetval;
640 :
641 1600 : if(getStart().isActive() || getEnd().isActive())
642 : {
643 : // use decomposition when line start/end is used
644 1600 : return BufferedDecompositionPrimitive2D::getB2DRange(rViewInformation);
645 : }
646 : else
647 : {
648 : // get range from parent
649 0 : return PolygonStrokePrimitive2D::getB2DRange(rViewInformation);
650 : }
651 : }
652 :
653 : // provide unique ID
654 236 : ImplPrimitive2DIDBlock(PolygonStrokeArrowPrimitive2D, PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D)
655 :
656 : } // end of namespace primitive2d
657 1143 : } // end of namespace drawinglayer
658 :
659 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|