1 /*************************************************************************
3 * OpenOffice.org - a multi-platform office productivity suite
5 * $RCSfile: polygonprimitive2d.cxx,v $
9 * last change: $Author: aw $ $Date: 2008-05-27 14:11:20 $
11 * The Contents of this file are made available subject to
12 * the terms of GNU Lesser General Public License Version 2.1.
15 * GNU Lesser General Public License Version 2.1
16 * =============================================
17 * Copyright 2005 by Sun Microsystems, Inc.
18 * 901 San Antonio Road, Palo Alto, CA 94303, USA
20 * This library is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU Lesser General Public
22 * License version 2.1, as published by the Free Software Foundation.
24 * This library is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27 * Lesser General Public License for more details.
29 * You should have received a copy of the GNU Lesser General Public
30 * License along with this library; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
34 ************************************************************************/
36 // MARKER(update_precomp.py): autogen include statement, do not remove
37 #include "precompiled_drawinglayer.hxx"
39 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
40 #include <basegfx/tools/canvastools.hxx>
41 #include <basegfx/polygon/b2dpolygontools.hxx>
42 #include <basegfx/polygon/b2dpolypolygontools.hxx>
43 #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
44 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
45 #include <drawinglayer/geometry/viewinformation2d.hxx>
47 //////////////////////////////////////////////////////////////////////////////
49 using namespace com::sun::star
;
51 //////////////////////////////////////////////////////////////////////////////
53 namespace drawinglayer
57 PolygonHairlinePrimitive2D::PolygonHairlinePrimitive2D(
58 const basegfx::B2DPolygon
& rPolygon
,
59 const basegfx::BColor
& rBColor
)
66 bool PolygonHairlinePrimitive2D::operator==(const BasePrimitive2D
& rPrimitive
) const
68 if(BasePrimitive2D::operator==(rPrimitive
))
70 const PolygonHairlinePrimitive2D
& rCompare
= (PolygonHairlinePrimitive2D
&)rPrimitive
;
72 return (getB2DPolygon() == rCompare
.getB2DPolygon()
73 && getBColor() == rCompare
.getBColor());
79 basegfx::B2DRange
PolygonHairlinePrimitive2D::getB2DRange(const geometry::ViewInformation2D
& rViewInformation
) const
81 // this is a hairline, thus the line width is view-dependent. Get range of polygon
83 basegfx::B2DRange
aRetval(getB2DPolygon().getB2DRange());
85 if(!aRetval
.isEmpty())
87 // Calculate view-dependent hairline width
88 const basegfx::B2DVector
aDiscreteSize(rViewInformation
.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 0.0));
89 const double fDiscreteHalfLineWidth(aDiscreteSize
.getLength() * 0.5);
91 if(basegfx::fTools::more(fDiscreteHalfLineWidth
, 0.0))
93 aRetval
.grow(fDiscreteHalfLineWidth
);
102 ImplPrimitrive2DIDBlock(PolygonHairlinePrimitive2D
, PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D
)
104 } // end of namespace primitive2d
105 } // end of namespace drawinglayer
107 //////////////////////////////////////////////////////////////////////////////
109 namespace drawinglayer
111 namespace primitive2d
113 Primitive2DSequence
PolygonMarkerPrimitive2D::createLocalDecomposition(const geometry::ViewInformation2D
& rViewInformation
) const
115 // calculate logic DashLength
116 const basegfx::B2DVector
aDashVector(rViewInformation
.getInverseObjectToViewTransformation() * basegfx::B2DVector(getDiscreteDashLength(), 0.0));
117 const double fLogicDashLength(aDashVector
.getX());
119 if(fLogicDashLength
> 0.0 && !getRGBColorA().equal(getRGBColorB()))
121 // apply dashing; get line and gap snippets
122 ::std::vector
< double > aDash
;
123 basegfx::B2DPolyPolygon aDashedPolyPolyA
;
124 basegfx::B2DPolyPolygon aDashedPolyPolyB
;
126 aDash
.push_back(fLogicDashLength
);
127 aDash
.push_back(fLogicDashLength
);
128 basegfx::tools::applyLineDashing(getB2DPolygon(), aDash
, &aDashedPolyPolyA
, &aDashedPolyPolyB
, 2.0 * fLogicDashLength
);
130 // prepare return value
131 Primitive2DSequence
aRetval(2);
133 aRetval
[0] = Primitive2DReference(new PolyPolygonHairlinePrimitive2D(aDashedPolyPolyA
, getRGBColorA()));
134 aRetval
[1] = Primitive2DReference(new PolyPolygonHairlinePrimitive2D(aDashedPolyPolyB
, getRGBColorB()));
140 const Primitive2DReference
xRef(new PolygonHairlinePrimitive2D(getB2DPolygon(), getRGBColorA()));
141 return Primitive2DSequence(&xRef
, 1L);
145 PolygonMarkerPrimitive2D::PolygonMarkerPrimitive2D(
146 const basegfx::B2DPolygon
& rPolygon
,
147 const basegfx::BColor
& rRGBColorA
,
148 const basegfx::BColor
& rRGBColorB
,
149 double fDiscreteDashLength
)
152 maRGBColorA(rRGBColorA
),
153 maRGBColorB(rRGBColorB
),
154 mfDiscreteDashLength(fDiscreteDashLength
),
155 maLastInverseObjectToViewTransformation()
159 bool PolygonMarkerPrimitive2D::operator==(const BasePrimitive2D
& rPrimitive
) const
161 if(BasePrimitive2D::operator==(rPrimitive
))
163 const PolygonMarkerPrimitive2D
& rCompare
= (PolygonMarkerPrimitive2D
&)rPrimitive
;
165 return (getB2DPolygon() == rCompare
.getB2DPolygon()
166 && getRGBColorA() == rCompare
.getRGBColorA()
167 && getRGBColorB() == rCompare
.getRGBColorB()
168 && getDiscreteDashLength() == rCompare
.getDiscreteDashLength());
174 basegfx::B2DRange
PolygonMarkerPrimitive2D::getB2DRange(const geometry::ViewInformation2D
& rViewInformation
) const
176 // this is a hairline, thus the line width is view-dependent. Get range of polygon
178 basegfx::B2DRange
aRetval(getB2DPolygon().getB2DRange());
180 if(!aRetval
.isEmpty())
182 // Calculate view-dependent hairline width
183 const basegfx::B2DVector
aDiscreteSize(rViewInformation
.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 0.0));
184 const double fDiscreteHalfLineWidth(aDiscreteSize
.getLength() * 0.5);
186 if(basegfx::fTools::more(fDiscreteHalfLineWidth
, 0.0))
188 aRetval
.grow(fDiscreteHalfLineWidth
);
196 Primitive2DSequence
PolygonMarkerPrimitive2D::get2DDecomposition(const geometry::ViewInformation2D
& rViewInformation
) const
198 ::osl::MutexGuard
aGuard( m_aMutex
);
199 bool bNeedNewDecomposition(false);
201 if(getLocalDecomposition().hasElements())
203 if(rViewInformation
.getInverseObjectToViewTransformation() != maLastInverseObjectToViewTransformation
)
205 bNeedNewDecomposition
= true;
209 if(bNeedNewDecomposition
)
211 // conditions of last local decomposition have changed, delete
212 const_cast< PolygonMarkerPrimitive2D
* >(this)->setLocalDecomposition(Primitive2DSequence());
215 if(!getLocalDecomposition().hasElements())
217 // remember last used InverseObjectToViewTransformation
218 PolygonMarkerPrimitive2D
* pThat
= const_cast< PolygonMarkerPrimitive2D
* >(this);
219 pThat
->maLastInverseObjectToViewTransformation
= rViewInformation
.getInverseObjectToViewTransformation();
222 // use parent implementation
223 return BasePrimitive2D::get2DDecomposition(rViewInformation
);
227 ImplPrimitrive2DIDBlock(PolygonMarkerPrimitive2D
, PRIMITIVE2D_ID_POLYGONMARKERPRIMITIVE2D
)
229 } // end of namespace primitive2d
230 } // end of namespace drawinglayer
232 //////////////////////////////////////////////////////////////////////////////
234 namespace drawinglayer
236 namespace primitive2d
238 Primitive2DSequence
PolygonStrokePrimitive2D::createLocalDecomposition(const geometry::ViewInformation2D
& /*rViewInformation*/) const
240 if(getB2DPolygon().count())
242 // #i102241# try to simplify before usage
243 const basegfx::B2DPolygon
aB2DPolygon(basegfx::tools::simplifyCurveSegments(getB2DPolygon()));
244 basegfx::B2DPolyPolygon aHairLinePolyPolygon
;
246 if(0.0 == getStrokeAttribute().getFullDotDashLen())
248 // no line dashing, just copy
249 aHairLinePolyPolygon
.append(aB2DPolygon
);
254 basegfx::tools::applyLineDashing(aB2DPolygon
, getStrokeAttribute().getDotDashArray(), &aHairLinePolyPolygon
, 0, getStrokeAttribute().getFullDotDashLen());
257 const sal_uInt32
nCount(aHairLinePolyPolygon
.count());
259 if(getLineAttribute().getWidth())
261 // create fat line data
262 const double fHalfLineWidth(getLineAttribute().getWidth() / 2.0);
263 const basegfx::B2DLineJoin
aLineJoin(getLineAttribute().getLineJoin());
264 basegfx::B2DPolyPolygon aAreaPolyPolygon
;
266 for(sal_uInt32
a(0L); a
< nCount
; a
++)
268 // New version of createAreaGeometry; now creates bezier polygons
269 aAreaPolyPolygon
.append(basegfx::tools::createAreaGeometry(
270 aHairLinePolyPolygon
.getB2DPolygon(a
), fHalfLineWidth
, aLineJoin
));
273 // prepare return value
274 Primitive2DSequence
aRetval(aAreaPolyPolygon
.count());
277 for(sal_uInt32
b(0L); b
< aAreaPolyPolygon
.count(); b
++)
279 // put into single polyPolygon primitives to make clear that this is NOT meant
280 // to be painted as a single PolyPolygon (XORed as fill rule). Alternatively, a
281 // melting process may be used here one day.
282 const basegfx::B2DPolyPolygon
aNewPolyPolygon(aAreaPolyPolygon
.getB2DPolygon(b
));
283 static bool bTestByUsingRandomColor(false);
284 const basegfx::BColor
aColor(bTestByUsingRandomColor
285 ? basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)
286 : getLineAttribute().getColor());
287 const Primitive2DReference
xRef(new PolyPolygonColorPrimitive2D(aNewPolyPolygon
, aColor
));
295 // prepare return value
296 const Primitive2DReference
xRef(new PolyPolygonHairlinePrimitive2D(aHairLinePolyPolygon
, getLineAttribute().getColor()));
297 return Primitive2DSequence(&xRef
, 1);
302 return Primitive2DSequence();
306 PolygonStrokePrimitive2D::PolygonStrokePrimitive2D(
307 const basegfx::B2DPolygon
& rPolygon
,
308 const attribute::LineAttribute
& rLineAttribute
,
309 const attribute::StrokeAttribute
& rStrokeAttribute
)
312 maLineAttribute(rLineAttribute
),
313 maStrokeAttribute(rStrokeAttribute
)
317 PolygonStrokePrimitive2D::PolygonStrokePrimitive2D(
318 const basegfx::B2DPolygon
& rPolygon
,
319 const attribute::LineAttribute
& rLineAttribute
)
322 maLineAttribute(rLineAttribute
),
327 bool PolygonStrokePrimitive2D::operator==(const BasePrimitive2D
& rPrimitive
) const
329 if(BasePrimitive2D::operator==(rPrimitive
))
331 const PolygonStrokePrimitive2D
& rCompare
= (PolygonStrokePrimitive2D
&)rPrimitive
;
333 return (getB2DPolygon() == rCompare
.getB2DPolygon()
334 && getLineAttribute() == rCompare
.getLineAttribute()
335 && getStrokeAttribute() == rCompare
.getStrokeAttribute());
341 basegfx::B2DRange
PolygonStrokePrimitive2D::getB2DRange(const geometry::ViewInformation2D
& rViewInformation
) const
343 basegfx::B2DRange aRetval
;
345 if(getLineAttribute().getWidth())
347 if(basegfx::B2DLINEJOIN_MITER
== getLineAttribute().getLineJoin())
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 aRetval
= BasePrimitive2D::getB2DRange(rViewInformation
);
355 // for all other B2DLINEJOIN_* get the range from the base geometry
356 // and expand by half the line width
357 aRetval
= getB2DPolygon().getB2DRange();
358 aRetval
.grow(getLineAttribute().getWidth() * 0.5);
363 // this is a hairline, thus the line width is view-dependent. Get range of polygon
365 aRetval
= getB2DPolygon().getB2DRange();
367 if(!aRetval
.isEmpty())
369 // Calculate view-dependent hairline width
370 const basegfx::B2DVector
aDiscreteSize(rViewInformation
.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 0.0));
371 const double fDiscreteHalfLineWidth(aDiscreteSize
.getLength() * 0.5);
373 if(basegfx::fTools::more(fDiscreteHalfLineWidth
, 0.0))
375 aRetval
.grow(fDiscreteHalfLineWidth
);
384 ImplPrimitrive2DIDBlock(PolygonStrokePrimitive2D
, PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D
)
386 } // end of namespace primitive2d
387 } // end of namespace drawinglayer
389 //////////////////////////////////////////////////////////////////////////////
391 namespace drawinglayer
393 namespace primitive2d
395 Primitive2DSequence
PolygonWavePrimitive2D::createLocalDecomposition(const geometry::ViewInformation2D
& /*rViewInformation*/) const
397 Primitive2DSequence aRetval
;
399 if(getB2DPolygon().count())
401 const bool bHasWidth(!basegfx::fTools::equalZero(getWaveWidth()));
402 const bool bHasHeight(!basegfx::fTools::equalZero(getWaveHeight()));
404 if(bHasWidth
&& bHasHeight
)
406 // create waveline curve
407 const basegfx::B2DPolygon
aWaveline(basegfx::tools::createWaveline(getB2DPolygon(), getWaveWidth(), getWaveHeight()));
408 const Primitive2DReference
xRef(new PolygonStrokePrimitive2D(aWaveline
, getLineAttribute(), getStrokeAttribute()));
409 aRetval
= Primitive2DSequence(&xRef
, 1);
413 // flat waveline, decompose to simple line primitive
414 const Primitive2DReference
xRef(new PolygonStrokePrimitive2D(getB2DPolygon(), getLineAttribute(), getStrokeAttribute()));
415 aRetval
= Primitive2DSequence(&xRef
, 1);
422 PolygonWavePrimitive2D::PolygonWavePrimitive2D(
423 const basegfx::B2DPolygon
& rPolygon
,
424 const attribute::LineAttribute
& rLineAttribute
,
425 const attribute::StrokeAttribute
& rStrokeAttribute
,
428 : PolygonStrokePrimitive2D(rPolygon
, rLineAttribute
, rStrokeAttribute
),
429 mfWaveWidth(fWaveWidth
),
430 mfWaveHeight(fWaveHeight
)
432 if(mfWaveWidth
< 0.0)
437 if(mfWaveHeight
< 0.0)
443 PolygonWavePrimitive2D::PolygonWavePrimitive2D(
444 const basegfx::B2DPolygon
& rPolygon
,
445 const attribute::LineAttribute
& rLineAttribute
,
448 : PolygonStrokePrimitive2D(rPolygon
, rLineAttribute
),
449 mfWaveWidth(fWaveWidth
),
450 mfWaveHeight(fWaveHeight
)
452 if(mfWaveWidth
< 0.0)
457 if(mfWaveHeight
< 0.0)
463 bool PolygonWavePrimitive2D::operator==(const BasePrimitive2D
& rPrimitive
) const
465 if(PolygonStrokePrimitive2D::operator==(rPrimitive
))
467 const PolygonWavePrimitive2D
& rCompare
= (PolygonWavePrimitive2D
&)rPrimitive
;
469 return (getWaveWidth() == rCompare
.getWaveWidth()
470 && getWaveHeight() == rCompare
.getWaveHeight());
476 basegfx::B2DRange
PolygonWavePrimitive2D::getB2DRange(const geometry::ViewInformation2D
& rViewInformation
) const
478 // get range of parent
479 basegfx::B2DRange
aRetval(PolygonStrokePrimitive2D::getB2DRange(rViewInformation
));
481 // if WaveHeight, grow by it
482 if(basegfx::fTools::more(getWaveHeight(), 0.0))
484 aRetval
.grow(getWaveHeight());
487 // if line width, grow by it
488 if(basegfx::fTools::more(getLineAttribute().getWidth(), 0.0))
490 aRetval
.grow(getLineAttribute().getWidth() * 0.5);
497 ImplPrimitrive2DIDBlock(PolygonWavePrimitive2D
, PRIMITIVE2D_ID_POLYGONWAVEPRIMITIVE2D
)
499 } // end of namespace primitive2d
500 } // end of namespace drawinglayer
502 //////////////////////////////////////////////////////////////////////////////
504 namespace drawinglayer
506 namespace primitive2d
508 Primitive2DSequence
PolygonStrokeArrowPrimitive2D::createLocalDecomposition(const geometry::ViewInformation2D
& /*rViewInformation*/) const
510 // copy local polygon, it may be changed
511 basegfx::B2DPolygon
aLocalPolygon(getB2DPolygon());
512 basegfx::B2DPolyPolygon aArrowA
;
513 basegfx::B2DPolyPolygon aArrowB
;
515 if(!aLocalPolygon
.isClosed())
518 const double fPolyLength(basegfx::tools::getLength(aLocalPolygon
));
522 if(getStart().isActive())
524 // create start arrow primitive and consume
525 aArrowA
= basegfx::tools::createAreaGeometryForLineStartEnd(
526 aLocalPolygon
, getStart().getB2DPolyPolygon(), true, getStart().getWidth(),
527 fPolyLength
, getStart().isCentered() ? 0.5 : 0.0, &fStart
);
529 // create some overlapping
533 if(getEnd().isActive())
535 // create end arrow primitive and consume
536 aArrowB
= basegfx::tools::createAreaGeometryForLineStartEnd(
537 aLocalPolygon
, getEnd().getB2DPolyPolygon(), false, getEnd().getWidth(),
538 fPolyLength
, getEnd().isCentered() ? 0.5 : 0.0, &fEnd
);
540 // create some overlapping
544 if(0.0 != fStart
|| 0.0 != fEnd
)
546 // build new poly, consume something from old poly
547 aLocalPolygon
= basegfx::tools::getSnippetAbsolute(aLocalPolygon
, fStart
, fPolyLength
- fEnd
, fPolyLength
);
551 // prepare return value
552 Primitive2DSequence
aRetval(1L + (aArrowA
.count() ? 1L : 0L) + (aArrowB
.count() ? 1L : 0L));
556 const Primitive2DReference
xRefShaft(new PolygonStrokePrimitive2D(aLocalPolygon
, getLineAttribute(), getStrokeAttribute()));
557 aRetval
[nInd
++] = xRefShaft
;
561 const Primitive2DReference
xRefA(new PolyPolygonColorPrimitive2D(aArrowA
, getLineAttribute().getColor()));
562 aRetval
[nInd
++] = xRefA
;
567 const Primitive2DReference
xRefB(new PolyPolygonColorPrimitive2D(aArrowB
, getLineAttribute().getColor()));
568 aRetval
[nInd
++] = xRefB
;
574 PolygonStrokeArrowPrimitive2D::PolygonStrokeArrowPrimitive2D(
575 const basegfx::B2DPolygon
& rPolygon
,
576 const attribute::LineAttribute
& rLineAttribute
,
577 const attribute::StrokeAttribute
& rStrokeAttribute
,
578 const attribute::LineStartEndAttribute
& rStart
,
579 const attribute::LineStartEndAttribute
& rEnd
)
580 : PolygonStrokePrimitive2D(rPolygon
, rLineAttribute
, rStrokeAttribute
),
586 PolygonStrokeArrowPrimitive2D::PolygonStrokeArrowPrimitive2D(
587 const basegfx::B2DPolygon
& rPolygon
,
588 const attribute::LineAttribute
& rLineAttribute
,
589 const attribute::LineStartEndAttribute
& rStart
,
590 const attribute::LineStartEndAttribute
& rEnd
)
591 : PolygonStrokePrimitive2D(rPolygon
, rLineAttribute
),
597 bool PolygonStrokeArrowPrimitive2D::operator==(const BasePrimitive2D
& rPrimitive
) const
599 if(PolygonStrokePrimitive2D::operator==(rPrimitive
))
601 const PolygonStrokeArrowPrimitive2D
& rCompare
= (PolygonStrokeArrowPrimitive2D
&)rPrimitive
;
603 return (getStart() == rCompare
.getStart()
604 && getEnd() == rCompare
.getEnd());
610 basegfx::B2DRange
PolygonStrokeArrowPrimitive2D::getB2DRange(const geometry::ViewInformation2D
& rViewInformation
) const
612 basegfx::B2DRange aRetval
;
614 if(getStart().isActive() || getEnd().isActive())
616 // use decomposition when line start/end is used
617 return BasePrimitive2D::getB2DRange(rViewInformation
);
621 // get range from parent
622 return PolygonStrokePrimitive2D::getB2DRange(rViewInformation
);
627 ImplPrimitrive2DIDBlock(PolygonStrokeArrowPrimitive2D
, PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D
)
629 } // end of namespace primitive2d
630 } // end of namespace drawinglayer
632 //////////////////////////////////////////////////////////////////////////////