fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / drawinglayer / source / primitive2d / polygonprimitive2d.cxx
blob2ca0966e60ec1f8078a447e7c0d8a17714c3fd58
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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>
30 //////////////////////////////////////////////////////////////////////////////
32 using namespace com::sun::star;
34 //////////////////////////////////////////////////////////////////////////////
36 namespace drawinglayer
38 namespace primitive2d
40 PolygonHairlinePrimitive2D::PolygonHairlinePrimitive2D(
41 const basegfx::B2DPolygon& rPolygon,
42 const basegfx::BColor& rBColor)
43 : BasePrimitive2D(),
44 maPolygon(rPolygon),
45 maBColor(rBColor)
49 bool PolygonHairlinePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
51 if(BasePrimitive2D::operator==(rPrimitive))
53 const PolygonHairlinePrimitive2D& rCompare = (PolygonHairlinePrimitive2D&)rPrimitive;
55 return (getB2DPolygon() == rCompare.getB2DPolygon()
56 && getBColor() == rCompare.getBColor());
59 return false;
62 basegfx::B2DRange PolygonHairlinePrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
64 // this is a hairline, thus the line width is view-dependent. Get range of polygon
65 // as base size
66 basegfx::B2DRange aRetval(getB2DPolygon().getB2DRange());
68 if(!aRetval.isEmpty())
70 // Calculate view-dependent hairline width
71 const basegfx::B2DVector aDiscreteSize(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 0.0));
72 const double fDiscreteHalfLineWidth(aDiscreteSize.getLength() * 0.5);
74 if(basegfx::fTools::more(fDiscreteHalfLineWidth, 0.0))
76 aRetval.grow(fDiscreteHalfLineWidth);
80 // return range
81 return aRetval;
84 // provide unique ID
85 ImplPrimitive2DIDBlock(PolygonHairlinePrimitive2D, PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D)
87 } // end of namespace primitive2d
88 } // end of namespace drawinglayer
90 //////////////////////////////////////////////////////////////////////////////
92 namespace drawinglayer
94 namespace primitive2d
96 Primitive2DSequence PolygonMarkerPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
98 // calculate logic DashLength
99 const basegfx::B2DVector aDashVector(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(getDiscreteDashLength(), 0.0));
100 const double fLogicDashLength(aDashVector.getX());
102 if(fLogicDashLength > 0.0 && !getRGBColorA().equal(getRGBColorB()))
104 // apply dashing; get line and gap snippets
105 ::std::vector< double > aDash;
106 basegfx::B2DPolyPolygon aDashedPolyPolyA;
107 basegfx::B2DPolyPolygon aDashedPolyPolyB;
109 aDash.push_back(fLogicDashLength);
110 aDash.push_back(fLogicDashLength);
111 basegfx::tools::applyLineDashing(getB2DPolygon(), aDash, &aDashedPolyPolyA, &aDashedPolyPolyB, 2.0 * fLogicDashLength);
113 // prepare return value
114 Primitive2DSequence aRetval(2);
116 aRetval[0] = Primitive2DReference(new PolyPolygonHairlinePrimitive2D(aDashedPolyPolyA, getRGBColorA()));
117 aRetval[1] = Primitive2DReference(new PolyPolygonHairlinePrimitive2D(aDashedPolyPolyB, getRGBColorB()));
119 return aRetval;
121 else
123 const Primitive2DReference xRef(new PolygonHairlinePrimitive2D(getB2DPolygon(), getRGBColorA()));
124 return Primitive2DSequence(&xRef, 1L);
128 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 maLastInverseObjectToViewTransformation()
142 bool PolygonMarkerPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
144 if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
146 const PolygonMarkerPrimitive2D& rCompare = (PolygonMarkerPrimitive2D&)rPrimitive;
148 return (getB2DPolygon() == rCompare.getB2DPolygon()
149 && getRGBColorA() == rCompare.getRGBColorA()
150 && getRGBColorB() == rCompare.getRGBColorB()
151 && getDiscreteDashLength() == rCompare.getDiscreteDashLength());
154 return false;
157 basegfx::B2DRange PolygonMarkerPrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
159 // this is a hairline, thus the line width is view-dependent. Get range of polygon
160 // as base size
161 basegfx::B2DRange aRetval(getB2DPolygon().getB2DRange());
163 if(!aRetval.isEmpty())
165 // Calculate view-dependent hairline width
166 const basegfx::B2DVector aDiscreteSize(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 0.0));
167 const double fDiscreteHalfLineWidth(aDiscreteSize.getLength() * 0.5);
169 if(basegfx::fTools::more(fDiscreteHalfLineWidth, 0.0))
171 aRetval.grow(fDiscreteHalfLineWidth);
175 // return range
176 return aRetval;
179 Primitive2DSequence PolygonMarkerPrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
181 ::osl::MutexGuard aGuard( m_aMutex );
182 bool bNeedNewDecomposition(false);
184 if(getBuffered2DDecomposition().hasElements())
186 if(rViewInformation.getInverseObjectToViewTransformation() != maLastInverseObjectToViewTransformation)
188 bNeedNewDecomposition = true;
192 if(bNeedNewDecomposition)
194 // conditions of last local decomposition have changed, delete
195 const_cast< PolygonMarkerPrimitive2D* >(this)->setBuffered2DDecomposition(Primitive2DSequence());
198 if(!getBuffered2DDecomposition().hasElements())
200 // remember last used InverseObjectToViewTransformation
201 PolygonMarkerPrimitive2D* pThat = const_cast< PolygonMarkerPrimitive2D* >(this);
202 pThat->maLastInverseObjectToViewTransformation = rViewInformation.getInverseObjectToViewTransformation();
205 // use parent implementation
206 return BufferedDecompositionPrimitive2D::get2DDecomposition(rViewInformation);
209 // provide unique ID
210 ImplPrimitive2DIDBlock(PolygonMarkerPrimitive2D, PRIMITIVE2D_ID_POLYGONMARKERPRIMITIVE2D)
212 } // end of namespace primitive2d
213 } // end of namespace drawinglayer
215 //////////////////////////////////////////////////////////////////////////////
217 namespace drawinglayer
219 namespace primitive2d
221 Primitive2DSequence PolygonStrokePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
223 if(getB2DPolygon().count())
225 // #i102241# try to simplify before usage
226 const basegfx::B2DPolygon aB2DPolygon(basegfx::tools::simplifyCurveSegments(getB2DPolygon()));
227 basegfx::B2DPolyPolygon aHairLinePolyPolygon;
229 if(getStrokeAttribute().isDefault() || 0.0 == getStrokeAttribute().getFullDotDashLen())
231 // no line dashing, just copy
232 aHairLinePolyPolygon.append(aB2DPolygon);
234 else
236 // apply LineStyle
237 basegfx::tools::applyLineDashing(
238 aB2DPolygon, getStrokeAttribute().getDotDashArray(),
239 &aHairLinePolyPolygon, 0, getStrokeAttribute().getFullDotDashLen());
242 const sal_uInt32 nCount(aHairLinePolyPolygon.count());
244 if(!getLineAttribute().isDefault() && getLineAttribute().getWidth())
246 // create fat line data
247 const double fHalfLineWidth(getLineAttribute().getWidth() / 2.0);
248 const basegfx::B2DLineJoin aLineJoin(getLineAttribute().getLineJoin());
249 const com::sun::star::drawing::LineCap aLineCap(getLineAttribute().getLineCap());
250 basegfx::B2DPolyPolygon aAreaPolyPolygon;
252 for(sal_uInt32 a(0L); a < nCount; a++)
254 // New version of createAreaGeometry; now creates bezier polygons
255 aAreaPolyPolygon.append(basegfx::tools::createAreaGeometry(
256 aHairLinePolyPolygon.getB2DPolygon(a),
257 fHalfLineWidth,
258 aLineJoin,
259 aLineCap));
262 // prepare return value
263 Primitive2DSequence aRetval(aAreaPolyPolygon.count());
265 // create primitive
266 for(sal_uInt32 b(0L); b < aAreaPolyPolygon.count(); b++)
268 // put into single polyPolygon primitives to make clear that this is NOT meant
269 // to be painted as a single PolyPolygon (XORed as fill rule). Alternatively, a
270 // melting process may be used here one day.
271 const basegfx::B2DPolyPolygon aNewPolyPolygon(aAreaPolyPolygon.getB2DPolygon(b));
272 static bool bTestByUsingRandomColor(false);
273 const basegfx::BColor aColor(bTestByUsingRandomColor
274 ? basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)
275 : getLineAttribute().getColor());
276 const Primitive2DReference xRef(new PolyPolygonColorPrimitive2D(aNewPolyPolygon, aColor));
277 aRetval[b] = xRef;
280 return aRetval;
282 else
284 // prepare return value
285 const Primitive2DReference xRef(
286 new PolyPolygonHairlinePrimitive2D(
287 aHairLinePolyPolygon,
288 getLineAttribute().getColor()));
290 return Primitive2DSequence(&xRef, 1);
293 else
295 return Primitive2DSequence();
299 PolygonStrokePrimitive2D::PolygonStrokePrimitive2D(
300 const basegfx::B2DPolygon& rPolygon,
301 const attribute::LineAttribute& rLineAttribute,
302 const attribute::StrokeAttribute& rStrokeAttribute)
303 : BufferedDecompositionPrimitive2D(),
304 maPolygon(rPolygon),
305 maLineAttribute(rLineAttribute),
306 maStrokeAttribute(rStrokeAttribute)
310 PolygonStrokePrimitive2D::PolygonStrokePrimitive2D(
311 const basegfx::B2DPolygon& rPolygon,
312 const attribute::LineAttribute& rLineAttribute)
313 : BufferedDecompositionPrimitive2D(),
314 maPolygon(rPolygon),
315 maLineAttribute(rLineAttribute),
316 maStrokeAttribute()
320 bool PolygonStrokePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
322 if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
324 const PolygonStrokePrimitive2D& rCompare = (PolygonStrokePrimitive2D&)rPrimitive;
326 return (getB2DPolygon() == rCompare.getB2DPolygon()
327 && getLineAttribute() == rCompare.getLineAttribute()
328 && getStrokeAttribute() == rCompare.getStrokeAttribute());
331 return false;
334 basegfx::B2DRange PolygonStrokePrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
336 basegfx::B2DRange aRetval;
338 if(getLineAttribute().getWidth())
340 bool bUseDecomposition(false);
342 if(basegfx::B2DLINEJOIN_MITER == getLineAttribute().getLineJoin())
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 bUseDecomposition = true;
349 if(!bUseDecomposition && com::sun::star::drawing::LineCap_SQUARE == getLineAttribute().getLineCap())
351 // when drawing::LineCap_SQUARE is used the below method to grow the polygon
352 // range by half line width will not work, so use decomposition. Interestingly,
353 // the grow method below works perfectly for LineCap_ROUND since the grow is in
354 // all directions and the rounded cap needs the same grow in all directions independent
355 // from it's orientation. Unfortunately this is not the case for drawing::LineCap_SQUARE
356 bUseDecomposition = true;
359 if(bUseDecomposition)
361 // get correct range by using the decomposition fallback, reasons see above cases
362 aRetval = BufferedDecompositionPrimitive2D::getB2DRange(rViewInformation);
364 else
366 // for all other B2DLINEJOIN_* get the range from the base geometry
367 // and expand by half the line width
368 aRetval = getB2DPolygon().getB2DRange();
369 aRetval.grow(getLineAttribute().getWidth() * 0.5);
372 else
374 // this is a hairline, thus the line width is view-dependent. Get range of polygon
375 // as base size
376 aRetval = getB2DPolygon().getB2DRange();
378 if(!aRetval.isEmpty())
380 // Calculate view-dependent hairline width
381 const basegfx::B2DVector aDiscreteSize(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 0.0));
382 const double fDiscreteHalfLineWidth(aDiscreteSize.getLength() * 0.5);
384 if(basegfx::fTools::more(fDiscreteHalfLineWidth, 0.0))
386 aRetval.grow(fDiscreteHalfLineWidth);
391 return aRetval;
394 // provide unique ID
395 ImplPrimitive2DIDBlock(PolygonStrokePrimitive2D, PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D)
397 } // end of namespace primitive2d
398 } // end of namespace drawinglayer
400 //////////////////////////////////////////////////////////////////////////////
402 namespace drawinglayer
404 namespace primitive2d
406 Primitive2DSequence PolygonWavePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
408 Primitive2DSequence aRetval;
410 if(getB2DPolygon().count())
412 const bool bHasWidth(!basegfx::fTools::equalZero(getWaveWidth()));
413 const bool bHasHeight(!basegfx::fTools::equalZero(getWaveHeight()));
415 if(bHasWidth && bHasHeight)
417 // create waveline curve
418 const basegfx::B2DPolygon aWaveline(basegfx::tools::createWaveline(getB2DPolygon(), getWaveWidth(), getWaveHeight()));
419 const Primitive2DReference xRef(new PolygonStrokePrimitive2D(aWaveline, getLineAttribute(), getStrokeAttribute()));
420 aRetval = Primitive2DSequence(&xRef, 1);
422 else
424 // flat waveline, decompose to simple line primitive
425 const Primitive2DReference xRef(new PolygonStrokePrimitive2D(getB2DPolygon(), getLineAttribute(), getStrokeAttribute()));
426 aRetval = Primitive2DSequence(&xRef, 1);
430 return aRetval;
433 PolygonWavePrimitive2D::PolygonWavePrimitive2D(
434 const basegfx::B2DPolygon& rPolygon,
435 const attribute::LineAttribute& rLineAttribute,
436 const attribute::StrokeAttribute& rStrokeAttribute,
437 double fWaveWidth,
438 double fWaveHeight)
439 : PolygonStrokePrimitive2D(rPolygon, rLineAttribute, rStrokeAttribute),
440 mfWaveWidth(fWaveWidth),
441 mfWaveHeight(fWaveHeight)
443 if(mfWaveWidth < 0.0)
445 mfWaveWidth = 0.0;
448 if(mfWaveHeight < 0.0)
450 mfWaveHeight = 0.0;
454 PolygonWavePrimitive2D::PolygonWavePrimitive2D(
455 const basegfx::B2DPolygon& rPolygon,
456 const attribute::LineAttribute& rLineAttribute,
457 double fWaveWidth,
458 double fWaveHeight)
459 : PolygonStrokePrimitive2D(rPolygon, rLineAttribute),
460 mfWaveWidth(fWaveWidth),
461 mfWaveHeight(fWaveHeight)
463 if(mfWaveWidth < 0.0)
465 mfWaveWidth = 0.0;
468 if(mfWaveHeight < 0.0)
470 mfWaveHeight = 0.0;
474 bool PolygonWavePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
476 if(PolygonStrokePrimitive2D::operator==(rPrimitive))
478 const PolygonWavePrimitive2D& rCompare = (PolygonWavePrimitive2D&)rPrimitive;
480 return (getWaveWidth() == rCompare.getWaveWidth()
481 && getWaveHeight() == rCompare.getWaveHeight());
484 return false;
487 basegfx::B2DRange PolygonWavePrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
489 // get range of parent
490 basegfx::B2DRange aRetval(PolygonStrokePrimitive2D::getB2DRange(rViewInformation));
492 // if WaveHeight, grow by it
493 if(basegfx::fTools::more(getWaveHeight(), 0.0))
495 aRetval.grow(getWaveHeight());
498 // if line width, grow by it
499 if(basegfx::fTools::more(getLineAttribute().getWidth(), 0.0))
501 aRetval.grow(getLineAttribute().getWidth() * 0.5);
504 return aRetval;
507 // provide unique ID
508 ImplPrimitive2DIDBlock(PolygonWavePrimitive2D, PRIMITIVE2D_ID_POLYGONWAVEPRIMITIVE2D)
510 } // end of namespace primitive2d
511 } // end of namespace drawinglayer
513 //////////////////////////////////////////////////////////////////////////////
515 namespace drawinglayer
517 namespace primitive2d
519 Primitive2DSequence PolygonStrokeArrowPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
521 // copy local polygon, it may be changed
522 basegfx::B2DPolygon aLocalPolygon(getB2DPolygon());
523 aLocalPolygon.removeDoublePoints();
524 basegfx::B2DPolyPolygon aArrowA;
525 basegfx::B2DPolyPolygon aArrowB;
527 if(!aLocalPolygon.isClosed() && aLocalPolygon.count() > 1)
529 // apply arrows
530 const double fPolyLength(basegfx::tools::getLength(aLocalPolygon));
531 double fStart(0.0);
532 double fEnd(0.0);
533 double fStartOverlap(0.0);
534 double fEndOverlap(0.0);
536 if(!getStart().isDefault() && getStart().isActive())
538 // create start arrow primitive and consume
539 aArrowA = basegfx::tools::createAreaGeometryForLineStartEnd(
540 aLocalPolygon, getStart().getB2DPolyPolygon(), true, getStart().getWidth(),
541 fPolyLength, getStart().isCentered() ? 0.5 : 0.0, &fStart);
543 // create some overlapping, compromise between straight and peaked markers
544 // for marker width 0.3cm and marker line width 0.02cm
545 fStartOverlap = getStart().getWidth() / 15.0;
548 if(!getEnd().isDefault() && getEnd().isActive())
550 // create end arrow primitive and consume
551 aArrowB = basegfx::tools::createAreaGeometryForLineStartEnd(
552 aLocalPolygon, getEnd().getB2DPolyPolygon(), false, getEnd().getWidth(),
553 fPolyLength, getEnd().isCentered() ? 0.5 : 0.0, &fEnd);
555 // create some overlapping
556 fEndOverlap = getEnd().getWidth() / 15.0;
559 if(0.0 != fStart || 0.0 != fEnd)
561 // build new poly, consume something from old poly
562 aLocalPolygon = basegfx::tools::getSnippetAbsolute(aLocalPolygon, fStart-fStartOverlap, fPolyLength - fEnd + fEndOverlap, fPolyLength);
566 // prepare return value
567 Primitive2DSequence aRetval(1L + (aArrowA.count() ? 1L : 0L) + (aArrowB.count() ? 1L : 0L));
568 sal_uInt32 nInd(0L);
570 // add shaft
571 const Primitive2DReference xRefShaft(new
572 PolygonStrokePrimitive2D(
573 aLocalPolygon, getLineAttribute(), getStrokeAttribute()));
574 aRetval[nInd++] = xRefShaft;
576 if(aArrowA.count())
578 const Primitive2DReference xRefA(
579 new PolyPolygonColorPrimitive2D(
580 aArrowA, getLineAttribute().getColor()));
581 aRetval[nInd++] = xRefA;
584 if(aArrowB.count())
586 const Primitive2DReference xRefB(
587 new PolyPolygonColorPrimitive2D(
588 aArrowB, getLineAttribute().getColor()));
589 aRetval[nInd++] = xRefB;
592 return aRetval;
595 PolygonStrokeArrowPrimitive2D::PolygonStrokeArrowPrimitive2D(
596 const basegfx::B2DPolygon& rPolygon,
597 const attribute::LineAttribute& rLineAttribute,
598 const attribute::StrokeAttribute& rStrokeAttribute,
599 const attribute::LineStartEndAttribute& rStart,
600 const attribute::LineStartEndAttribute& rEnd)
601 : PolygonStrokePrimitive2D(rPolygon, rLineAttribute, rStrokeAttribute),
602 maStart(rStart),
603 maEnd(rEnd)
607 bool PolygonStrokeArrowPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
609 if(PolygonStrokePrimitive2D::operator==(rPrimitive))
611 const PolygonStrokeArrowPrimitive2D& rCompare = (PolygonStrokeArrowPrimitive2D&)rPrimitive;
613 return (getStart() == rCompare.getStart()
614 && getEnd() == rCompare.getEnd());
617 return false;
620 basegfx::B2DRange PolygonStrokeArrowPrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
622 basegfx::B2DRange aRetval;
624 if(getStart().isActive() || getEnd().isActive())
626 // use decomposition when line start/end is used
627 return BufferedDecompositionPrimitive2D::getB2DRange(rViewInformation);
629 else
631 // get range from parent
632 return PolygonStrokePrimitive2D::getB2DRange(rViewInformation);
636 // provide unique ID
637 ImplPrimitive2DIDBlock(PolygonStrokeArrowPrimitive2D, PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D)
639 } // end of namespace primitive2d
640 } // end of namespace drawinglayer
642 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */