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