Update ooo320-m1
[ooovba.git] / drawinglayer / source / primitive2d / polygonprimitive2d.cxx
blobad9a23504f1f1288c6bfc87813031dd95d3c229c
1 /*************************************************************************
3 * OpenOffice.org - a multi-platform office productivity suite
5 * $RCSfile: polygonprimitive2d.cxx,v $
7 * $Revision: 1.12 $
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,
32 * MA 02111-1307 USA
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
55 namespace primitive2d
57 PolygonHairlinePrimitive2D::PolygonHairlinePrimitive2D(
58 const basegfx::B2DPolygon& rPolygon,
59 const basegfx::BColor& rBColor)
60 : BasePrimitive2D(),
61 maPolygon(rPolygon),
62 maBColor(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());
76 return false;
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
82 // as base size
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);
97 // return range
98 return aRetval;
101 // provide unique ID
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()));
136 return aRetval;
138 else
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)
150 : BasePrimitive2D(),
151 maPolygon(rPolygon),
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());
171 return false;
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
177 // as base size
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);
192 // return range
193 return aRetval;
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);
226 // provide unique ID
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);
251 else
253 // apply LineStyle
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());
276 // create primitive
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));
288 aRetval[b] = xRef;
291 return aRetval;
293 else
295 // prepare return value
296 const Primitive2DReference xRef(new PolyPolygonHairlinePrimitive2D(aHairLinePolyPolygon, getLineAttribute().getColor()));
297 return Primitive2DSequence(&xRef, 1);
300 else
302 return Primitive2DSequence();
306 PolygonStrokePrimitive2D::PolygonStrokePrimitive2D(
307 const basegfx::B2DPolygon& rPolygon,
308 const attribute::LineAttribute& rLineAttribute,
309 const attribute::StrokeAttribute& rStrokeAttribute)
310 : BasePrimitive2D(),
311 maPolygon(rPolygon),
312 maLineAttribute(rLineAttribute),
313 maStrokeAttribute(rStrokeAttribute)
317 PolygonStrokePrimitive2D::PolygonStrokePrimitive2D(
318 const basegfx::B2DPolygon& rPolygon,
319 const attribute::LineAttribute& rLineAttribute)
320 : BasePrimitive2D(),
321 maPolygon(rPolygon),
322 maLineAttribute(rLineAttribute),
323 maStrokeAttribute()
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());
338 return false;
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);
353 else
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);
361 else
363 // this is a hairline, thus the line width is view-dependent. Get range of polygon
364 // as base size
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);
380 return aRetval;
383 // provide unique ID
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);
411 else
413 // flat waveline, decompose to simple line primitive
414 const Primitive2DReference xRef(new PolygonStrokePrimitive2D(getB2DPolygon(), getLineAttribute(), getStrokeAttribute()));
415 aRetval = Primitive2DSequence(&xRef, 1);
419 return aRetval;
422 PolygonWavePrimitive2D::PolygonWavePrimitive2D(
423 const basegfx::B2DPolygon& rPolygon,
424 const attribute::LineAttribute& rLineAttribute,
425 const attribute::StrokeAttribute& rStrokeAttribute,
426 double fWaveWidth,
427 double fWaveHeight)
428 : PolygonStrokePrimitive2D(rPolygon, rLineAttribute, rStrokeAttribute),
429 mfWaveWidth(fWaveWidth),
430 mfWaveHeight(fWaveHeight)
432 if(mfWaveWidth < 0.0)
434 mfWaveWidth = 0.0;
437 if(mfWaveHeight < 0.0)
439 mfWaveHeight = 0.0;
443 PolygonWavePrimitive2D::PolygonWavePrimitive2D(
444 const basegfx::B2DPolygon& rPolygon,
445 const attribute::LineAttribute& rLineAttribute,
446 double fWaveWidth,
447 double fWaveHeight)
448 : PolygonStrokePrimitive2D(rPolygon, rLineAttribute),
449 mfWaveWidth(fWaveWidth),
450 mfWaveHeight(fWaveHeight)
452 if(mfWaveWidth < 0.0)
454 mfWaveWidth = 0.0;
457 if(mfWaveHeight < 0.0)
459 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());
473 return false;
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);
493 return aRetval;
496 // provide unique ID
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())
517 // apply arrows
518 const double fPolyLength(basegfx::tools::getLength(aLocalPolygon));
519 double fStart(0.0);
520 double fEnd(0.0);
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
530 fStart *= 0.8;
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
541 fEnd *= 0.8;
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));
553 sal_uInt32 nInd(0L);
555 // add shaft
556 const Primitive2DReference xRefShaft(new PolygonStrokePrimitive2D(aLocalPolygon, getLineAttribute(), getStrokeAttribute()));
557 aRetval[nInd++] = xRefShaft;
559 if(aArrowA.count())
561 const Primitive2DReference xRefA(new PolyPolygonColorPrimitive2D(aArrowA, getLineAttribute().getColor()));
562 aRetval[nInd++] = xRefA;
565 if(aArrowB.count())
567 const Primitive2DReference xRefB(new PolyPolygonColorPrimitive2D(aArrowB, getLineAttribute().getColor()));
568 aRetval[nInd++] = xRefB;
571 return aRetval;
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),
581 maStart(rStart),
582 maEnd(rEnd)
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),
592 maStart(rStart),
593 maEnd(rEnd)
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());
607 return false;
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);
619 else
621 // get range from parent
622 return PolygonStrokePrimitive2D::getB2DRange(rViewInformation);
626 // provide unique ID
627 ImplPrimitrive2DIDBlock(PolygonStrokeArrowPrimitive2D, PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D)
629 } // end of namespace primitive2d
630 } // end of namespace drawinglayer
632 //////////////////////////////////////////////////////////////////////////////
633 // eof