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