1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_drawinglayer.hxx"
26 
27 #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
28 #include <basegfx/polygon/b2dpolypolygontools.hxx>
29 #include <basegfx/tools/canvastools.hxx>
30 #include <drawinglayer/primitive2d/fillgradientprimitive2d.hxx>
31 #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
32 #include <drawinglayer/primitive2d/fillhatchprimitive2d.hxx>
33 #include <basegfx/matrix/b2dhommatrix.hxx>
34 #include <drawinglayer/primitive2d/fillgraphicprimitive2d.hxx>
35 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
36 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
37 #include <basegfx/matrix/b2dhommatrixtools.hxx>
38 #include <vcl/graph.hxx>
39 
40 //////////////////////////////////////////////////////////////////////////////
41 
42 using namespace com::sun::star;
43 
44 //////////////////////////////////////////////////////////////////////////////
45 
46 namespace drawinglayer
47 {
48 	namespace primitive2d
49 	{
50 		Primitive2DSequence PolyPolygonHairlinePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
51 		{
52 			const basegfx::B2DPolyPolygon aPolyPolygon(getB2DPolyPolygon());
53 			const sal_uInt32 nCount(aPolyPolygon.count());
54 
55 			if(nCount)
56 			{
57 				Primitive2DSequence aRetval(nCount);
58 
59 				for(sal_uInt32 a(0L); a < nCount; a++)
60 				{
61 					aRetval[a] = Primitive2DReference(new PolygonHairlinePrimitive2D(aPolyPolygon.getB2DPolygon(a), getBColor()));
62 				}
63 
64 				return aRetval;
65 			}
66 			else
67 			{
68 				return Primitive2DSequence();
69 			}
70 		}
71 
72 		PolyPolygonHairlinePrimitive2D::PolyPolygonHairlinePrimitive2D(const basegfx::B2DPolyPolygon& rPolyPolygon, const basegfx::BColor& rBColor)
73 		:	BufferedDecompositionPrimitive2D(),
74 			maPolyPolygon(rPolyPolygon),
75 			maBColor(rBColor)
76 		{
77 		}
78 
79 		bool PolyPolygonHairlinePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
80 		{
81 			if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
82 			{
83 				const PolyPolygonHairlinePrimitive2D& rCompare = (PolyPolygonHairlinePrimitive2D&)rPrimitive;
84 
85 				return (getB2DPolyPolygon() == rCompare.getB2DPolyPolygon()
86 					&& getBColor() == rCompare.getBColor());
87 			}
88 
89 			return false;
90 		}
91 
92 		basegfx::B2DRange PolyPolygonHairlinePrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
93 		{
94 			// return range
95 			return basegfx::tools::getRange(getB2DPolyPolygon());
96 		}
97 
98 		// provide unique ID
99 		ImplPrimitrive2DIDBlock(PolyPolygonHairlinePrimitive2D, PRIMITIVE2D_ID_POLYPOLYGONHAIRLINEPRIMITIVE2D)
100 
101 	} // end of namespace primitive2d
102 } // end of namespace drawinglayer
103 
104 //////////////////////////////////////////////////////////////////////////////
105 
106 namespace drawinglayer
107 {
108 	namespace primitive2d
109 	{
110 		Primitive2DSequence PolyPolygonMarkerPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
111 		{
112 			const basegfx::B2DPolyPolygon aPolyPolygon(getB2DPolyPolygon());
113 			const sal_uInt32 nCount(aPolyPolygon.count());
114 
115 			if(nCount)
116 			{
117 				Primitive2DSequence aRetval(nCount);
118 
119 				for(sal_uInt32 a(0L); a < nCount; a++)
120 				{
121 					aRetval[a] = Primitive2DReference(new PolygonMarkerPrimitive2D(aPolyPolygon.getB2DPolygon(a), getRGBColorA(), getRGBColorB(), getDiscreteDashLength()));
122 				}
123 
124 				return aRetval;
125 			}
126 			else
127 			{
128 				return Primitive2DSequence();
129 			}
130 		}
131 
132 		PolyPolygonMarkerPrimitive2D::PolyPolygonMarkerPrimitive2D(
133 			const basegfx::B2DPolyPolygon& rPolyPolygon,
134 			const basegfx::BColor& rRGBColorA,
135 			const basegfx::BColor& rRGBColorB,
136 			double fDiscreteDashLength)
137 		:	BufferedDecompositionPrimitive2D(),
138 			maPolyPolygon(rPolyPolygon),
139 			maRGBColorA(rRGBColorA),
140 			maRGBColorB(rRGBColorB),
141 			mfDiscreteDashLength(fDiscreteDashLength)
142 		{
143 		}
144 
145 		bool PolyPolygonMarkerPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
146 		{
147 			if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
148 			{
149 				const PolyPolygonMarkerPrimitive2D& rCompare = (PolyPolygonMarkerPrimitive2D&)rPrimitive;
150 
151 				return (getB2DPolyPolygon() == rCompare.getB2DPolyPolygon()
152 					&& getRGBColorA() == rCompare.getRGBColorA()
153 					&& getRGBColorB() == rCompare.getRGBColorB()
154 					&& getDiscreteDashLength() == rCompare.getDiscreteDashLength());
155 			}
156 
157 			return false;
158 		}
159 
160 		basegfx::B2DRange PolyPolygonMarkerPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
161 		{
162 			// return range
163 			return basegfx::tools::getRange(getB2DPolyPolygon());
164 		}
165 
166 		// provide unique ID
167 		ImplPrimitrive2DIDBlock(PolyPolygonMarkerPrimitive2D, PRIMITIVE2D_ID_POLYPOLYGONMARKERPRIMITIVE2D)
168 
169 	} // end of namespace primitive2d
170 } // end of namespace drawinglayer
171 
172 //////////////////////////////////////////////////////////////////////////////
173 
174 namespace drawinglayer
175 {
176 	namespace primitive2d
177 	{
178 		Primitive2DSequence PolyPolygonStrokePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
179 		{
180 			const basegfx::B2DPolyPolygon aPolyPolygon(getB2DPolyPolygon());
181 			const sal_uInt32 nCount(aPolyPolygon.count());
182 
183 			if(nCount)
184 			{
185 				Primitive2DSequence aRetval(nCount);
186 
187 				for(sal_uInt32 a(0L); a < nCount; a++)
188 				{
189 					aRetval[a] = Primitive2DReference(
190                         new PolygonStrokePrimitive2D(
191                             aPolyPolygon.getB2DPolygon(a), getLineAttribute(), getStrokeAttribute()));
192 				}
193 
194 				return aRetval;
195 			}
196 			else
197 			{
198 				return Primitive2DSequence();
199 			}
200 		}
201 
202 		PolyPolygonStrokePrimitive2D::PolyPolygonStrokePrimitive2D(
203 			const basegfx::B2DPolyPolygon& rPolyPolygon,
204   			const attribute::LineAttribute& rLineAttribute,
205 			const attribute::StrokeAttribute& rStrokeAttribute)
206 		:	BufferedDecompositionPrimitive2D(),
207 			maPolyPolygon(rPolyPolygon),
208             maLineAttribute(rLineAttribute),
209 			maStrokeAttribute(rStrokeAttribute)
210 		{
211 		}
212 
213 		PolyPolygonStrokePrimitive2D::PolyPolygonStrokePrimitive2D(
214 			const basegfx::B2DPolyPolygon& rPolyPolygon,
215   			const attribute::LineAttribute& rLineAttribute)
216 		:	BufferedDecompositionPrimitive2D(),
217 			maPolyPolygon(rPolyPolygon),
218             maLineAttribute(rLineAttribute),
219 			maStrokeAttribute()
220 		{
221 		}
222 
223 		bool PolyPolygonStrokePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
224 		{
225 			if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
226 			{
227 				const PolyPolygonStrokePrimitive2D& rCompare = (PolyPolygonStrokePrimitive2D&)rPrimitive;
228 
229 				return (getB2DPolyPolygon() == rCompare.getB2DPolyPolygon()
230 					&& getLineAttribute() == rCompare.getLineAttribute()
231 					&& getStrokeAttribute() == rCompare.getStrokeAttribute());
232 			}
233 
234 			return false;
235 		}
236 
237 		basegfx::B2DRange PolyPolygonStrokePrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
238 		{
239 			// get range of it (subdivided)
240 			basegfx::B2DRange aRetval(basegfx::tools::getRange(getB2DPolyPolygon()));
241 
242 			// if width, grow by line width
243 			if(getLineAttribute().getWidth())
244 			{
245 				aRetval.grow(getLineAttribute().getWidth() / 2.0);
246 			}
247 
248 			return aRetval;
249 		}
250 
251 		// provide unique ID
252 		ImplPrimitrive2DIDBlock(PolyPolygonStrokePrimitive2D, PRIMITIVE2D_ID_POLYPOLYGONSTROKEPRIMITIVE2D)
253 
254 	} // end of namespace primitive2d
255 } // end of namespace drawinglayer
256 
257 //////////////////////////////////////////////////////////////////////////////
258 
259 namespace drawinglayer
260 {
261 	namespace primitive2d
262 	{
263 		Primitive2DSequence PolyPolygonStrokeArrowPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
264 		{
265 			const basegfx::B2DPolyPolygon aPolyPolygon(getB2DPolyPolygon());
266 			const sal_uInt32 nCount(aPolyPolygon.count());
267 
268 			if(nCount)
269 			{
270 				Primitive2DSequence aRetval(nCount);
271 
272 				for(sal_uInt32 a(0L); a < nCount; a++)
273 				{
274 					const basegfx::B2DPolygon aPolygon(aPolyPolygon.getB2DPolygon(a));
275 
276 					if(aPolygon.isClosed())
277 					{
278 						// no need for PolygonStrokeArrowPrimitive2D when polygon is closed
279 						aRetval[a] = Primitive2DReference(
280                             new PolygonStrokePrimitive2D(aPolygon, getLineAttribute(), getStrokeAttribute()));
281 					}
282 					else
283 					{
284 						aRetval[a] = Primitive2DReference(
285                             new PolygonStrokeArrowPrimitive2D(aPolygon, getLineAttribute(),
286                                 getStrokeAttribute(), getStart(), getEnd()));
287 					}
288 				}
289 
290 				return aRetval;
291 			}
292 			else
293 			{
294 				return Primitive2DSequence();
295 			}
296 		}
297 
298 		PolyPolygonStrokeArrowPrimitive2D::PolyPolygonStrokeArrowPrimitive2D(
299 			const basegfx::B2DPolyPolygon& rPolyPolygon,
300    			const attribute::LineAttribute& rLineAttribute,
301 			const attribute::StrokeAttribute& rStrokeAttribute,
302 			const attribute::LineStartEndAttribute& rStart,
303 			const attribute::LineStartEndAttribute& rEnd)
304 		:	PolyPolygonStrokePrimitive2D(rPolyPolygon, rLineAttribute, rStrokeAttribute),
305 			maStart(rStart),
306 			maEnd(rEnd)
307 		{
308 		}
309 
310 		PolyPolygonStrokeArrowPrimitive2D::PolyPolygonStrokeArrowPrimitive2D(
311 			const basegfx::B2DPolyPolygon& rPolyPolygon,
312    			const attribute::LineAttribute& rLineAttribute,
313 			const attribute::LineStartEndAttribute& rStart,
314 			const attribute::LineStartEndAttribute& rEnd)
315 		:	PolyPolygonStrokePrimitive2D(rPolyPolygon, rLineAttribute),
316 			maStart(rStart),
317 			maEnd(rEnd)
318 		{
319 		}
320 
321 		bool PolyPolygonStrokeArrowPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
322 		{
323 			if(PolyPolygonStrokePrimitive2D::operator==(rPrimitive))
324 			{
325 				const PolyPolygonStrokeArrowPrimitive2D& rCompare = (PolyPolygonStrokeArrowPrimitive2D&)rPrimitive;
326 
327 				return (getStart() == rCompare.getStart()
328 					&& getEnd() == rCompare.getEnd());
329 			}
330 
331 			return false;
332 		}
333 
334 		basegfx::B2DRange PolyPolygonStrokeArrowPrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
335 		{
336 			basegfx::B2DRange aRetval;
337 
338 			if(getStart().isActive() || getEnd().isActive())
339 			{
340 				// use decomposition when line start/end is used
341 				return BufferedDecompositionPrimitive2D::getB2DRange(rViewInformation);
342 			}
343 			else
344 			{
345 				// get range from parent
346 				return PolyPolygonStrokePrimitive2D::getB2DRange(rViewInformation);
347 			}
348 		}
349 
350 		// provide unique ID
351 		ImplPrimitrive2DIDBlock(PolyPolygonStrokeArrowPrimitive2D, PRIMITIVE2D_ID_POLYPOLYGONSTROKEARROWPRIMITIVE2D)
352 
353 	} // end of namespace primitive2d
354 } // end of namespace drawinglayer
355 
356 //////////////////////////////////////////////////////////////////////////////
357 
358 namespace drawinglayer
359 {
360 	namespace primitive2d
361 	{
362 		PolyPolygonColorPrimitive2D::PolyPolygonColorPrimitive2D(
363 			const basegfx::B2DPolyPolygon& rPolyPolygon,
364 			const basegfx::BColor& rBColor)
365 		:	BasePrimitive2D(),
366 			maPolyPolygon(rPolyPolygon),
367 			maBColor(rBColor)
368 		{
369 		}
370 
371 		bool PolyPolygonColorPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
372 		{
373 			if(BasePrimitive2D::operator==(rPrimitive))
374 			{
375 				const PolyPolygonColorPrimitive2D& rCompare = (PolyPolygonColorPrimitive2D&)rPrimitive;
376 
377 				return (getB2DPolyPolygon() == rCompare.getB2DPolyPolygon()
378 					&& getBColor() == rCompare.getBColor());
379 			}
380 
381 			return false;
382 		}
383 
384 		basegfx::B2DRange PolyPolygonColorPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
385 		{
386 			// return range
387 			return basegfx::tools::getRange(getB2DPolyPolygon());
388 		}
389 
390 		// provide unique ID
391 		ImplPrimitrive2DIDBlock(PolyPolygonColorPrimitive2D, PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D)
392 
393 	} // end of namespace primitive2d
394 } // end of namespace drawinglayer
395 
396 //////////////////////////////////////////////////////////////////////////////
397 
398 namespace drawinglayer
399 {
400 	namespace primitive2d
401 	{
402 		Primitive2DSequence PolyPolygonGradientPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
403 		{
404             if(!getFillGradient().isDefault())
405             {
406 			    // create SubSequence with FillGradientPrimitive2D
407 			    const basegfx::B2DRange aPolyPolygonRange(getB2DPolyPolygon().getB2DRange());
408 			    FillGradientPrimitive2D* pNewGradient = new FillGradientPrimitive2D(aPolyPolygonRange, getFillGradient());
409 			    const Primitive2DReference xSubRef(pNewGradient);
410 			    const Primitive2DSequence aSubSequence(&xSubRef, 1L);
411 
412 			    // create mask primitive
413 			    MaskPrimitive2D* pNewMask = new MaskPrimitive2D(getB2DPolyPolygon(), aSubSequence);
414 			    const Primitive2DReference xRef(pNewMask);
415 
416                 return Primitive2DSequence(&xRef, 1);
417             }
418             else
419             {
420                 return Primitive2DSequence();
421             }
422 		}
423 
424 		PolyPolygonGradientPrimitive2D::PolyPolygonGradientPrimitive2D(
425 			const basegfx::B2DPolyPolygon& rPolyPolygon,
426 			const attribute::FillGradientAttribute& rFillGradient)
427 		:	BufferedDecompositionPrimitive2D(),
428 			maPolyPolygon(rPolyPolygon),
429 			maFillGradient(rFillGradient)
430 		{
431 		}
432 
433 		bool PolyPolygonGradientPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
434 		{
435 			if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
436 			{
437 				const PolyPolygonGradientPrimitive2D& rCompare = (PolyPolygonGradientPrimitive2D&)rPrimitive;
438 
439 				return (getFillGradient() == rCompare.getFillGradient());
440 			}
441 
442 			return false;
443 		}
444 
445 		// provide unique ID
446 		ImplPrimitrive2DIDBlock(PolyPolygonGradientPrimitive2D, PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D)
447 
448 	} // end of namespace primitive2d
449 } // end of namespace drawinglayer
450 
451 //////////////////////////////////////////////////////////////////////////////
452 
453 namespace drawinglayer
454 {
455 	namespace primitive2d
456 	{
457 		Primitive2DSequence PolyPolygonHatchPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
458 		{
459             if(!getFillHatch().isDefault())
460             {
461 			    // create SubSequence with FillHatchPrimitive2D
462 			    const basegfx::B2DRange aPolyPolygonRange(getB2DPolyPolygon().getB2DRange());
463 			    FillHatchPrimitive2D* pNewHatch = new FillHatchPrimitive2D(aPolyPolygonRange, getBackgroundColor(), getFillHatch());
464 			    const Primitive2DReference xSubRef(pNewHatch);
465 			    const Primitive2DSequence aSubSequence(&xSubRef, 1L);
466 
467 			    // create mask primitive
468 			    MaskPrimitive2D* pNewMask = new MaskPrimitive2D(getB2DPolyPolygon(), aSubSequence);
469 			    const Primitive2DReference xRef(pNewMask);
470 
471                 return Primitive2DSequence(&xRef, 1);
472             }
473             else
474             {
475                 return Primitive2DSequence();
476             }
477 		}
478 
479 		PolyPolygonHatchPrimitive2D::PolyPolygonHatchPrimitive2D(
480 			const basegfx::B2DPolyPolygon& rPolyPolygon,
481 			const basegfx::BColor& rBackgroundColor,
482 			const attribute::FillHatchAttribute& rFillHatch)
483 		:	BufferedDecompositionPrimitive2D(),
484 			maPolyPolygon(rPolyPolygon),
485 			maBackgroundColor(rBackgroundColor),
486 			maFillHatch(rFillHatch)
487 		{
488 		}
489 
490 		bool PolyPolygonHatchPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
491 		{
492 			if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
493 			{
494 				const PolyPolygonHatchPrimitive2D& rCompare = (PolyPolygonHatchPrimitive2D&)rPrimitive;
495 
496 				return (getBackgroundColor() == rCompare.getBackgroundColor()
497 					&& getFillHatch() == rCompare.getFillHatch());
498 			}
499 
500 			return false;
501 		}
502 
503 		// provide unique ID
504 		ImplPrimitrive2DIDBlock(PolyPolygonHatchPrimitive2D, PRIMITIVE2D_ID_POLYPOLYGONHATCHPRIMITIVE2D)
505 
506 	} // end of namespace primitive2d
507 } // end of namespace drawinglayer
508 
509 //////////////////////////////////////////////////////////////////////////////
510 
511 namespace drawinglayer
512 {
513 	namespace primitive2d
514 	{
515 		Primitive2DSequence PolyPolygonGraphicPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
516 		{
517             if(!getFillGraphic().isDefault())
518             {
519                 const Graphic& rGraphic = getFillGraphic().getGraphic();
520                 const GraphicType aType(rGraphic.GetType());
521 
522                 // is there a bitmap or a metafile (do we have content)?
523                 if(GRAPHIC_BITMAP == aType || GRAPHIC_GDIMETAFILE == aType)
524                 {
525                     const Size aPrefSize(rGraphic.GetPrefSize());
526 
527                     // does content have a size?
528                     if(aPrefSize.Width() && aPrefSize.Height())
529                     {
530                         // create SubSequence with FillGraphicPrimitive2D based on polygon range
531                         const basegfx::B2DRange aPolyPolygonRange(getB2DPolyPolygon().getB2DRange());
532                         const basegfx::B2DHomMatrix aNewObjectTransform(
533                             basegfx::tools::createScaleTranslateB2DHomMatrix(
534                                 aPolyPolygonRange.getRange(),
535                                 aPolyPolygonRange.getMinimum()));
536                         const Primitive2DReference xSubRef(
537                             new FillGraphicPrimitive2D(
538                                 aNewObjectTransform,
539                                 getFillGraphic()));
540 
541                         // embed to mask primitive
542                         const Primitive2DReference xRef(
543                             new MaskPrimitive2D(
544                                 getB2DPolyPolygon(),
545                                 Primitive2DSequence(&xSubRef, 1)));
546 
547                         return Primitive2DSequence(&xRef, 1);
548                     }
549                 }
550             }
551 
552             return Primitive2DSequence();
553 		}
554 
555 		PolyPolygonGraphicPrimitive2D::PolyPolygonGraphicPrimitive2D(
556 			const basegfx::B2DPolyPolygon& rPolyPolygon,
557 			const attribute::FillGraphicAttribute& rFillGraphic)
558 		:	BufferedDecompositionPrimitive2D(),
559 			maPolyPolygon(rPolyPolygon),
560 			maFillGraphic(rFillGraphic)
561 		{
562 		}
563 
564 		bool PolyPolygonGraphicPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
565 		{
566 			if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
567 			{
568 				const PolyPolygonGraphicPrimitive2D& rCompare = (PolyPolygonGraphicPrimitive2D&)rPrimitive;
569 
570 				return (getFillGraphic() == rCompare.getFillGraphic());
571 			}
572 
573 			return false;
574 		}
575 
576 		// provide unique ID
577 		ImplPrimitrive2DIDBlock(PolyPolygonGraphicPrimitive2D, PRIMITIVE2D_ID_POLYPOLYGONGRAPHICPRIMITIVE2D)
578 
579 	} // end of namespace primitive2d
580 } // end of namespace drawinglayer
581 
582 //////////////////////////////////////////////////////////////////////////////
583 // eof
584