2005-10-04 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / System.Drawing / System.Drawing.Drawing2D / ExtendedGeneralPath.jvm.cs
1 //
2 // System.Drawing.Drawing2D.ExtendedGeneralPath.cs
3 //
4 // Author:
5 // Bors Kirzner <boris@mainsoft.com>    
6 //
7 // Copyright (C) 2005 Mainsoft Corporation, (http://www.mainsoft.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //\r
28 \r
29 using System;\r
30 \r
31 using java.awt;\r
32 using java.awt.geom;\r
33 using java.lang;\r
34 \r
35 namespace System.Drawing.Drawing2D\r
36 {\r
37         internal class ExtendedGeneralPath : Shape, ICloneable\r
38         {\r
39                 #region Fields\r
40 \r
41                 public const int WIND_EVEN_ODD = 0; //PathIterator__Finals.WIND_EVEN_ODD;\r
42                 public const int WIND_NON_ZERO = 1; //PathIterator__Finals.WIND_NON_ZERO;\r
43                 \r
44                 public const sbyte SEG_MOVETO  = 0; //(byte) PathIterator__Finals.SEG_MOVETO;\r
45                 public const sbyte SEG_LINETO  = 1; //(byte) PathIterator__Finals.SEG_LINETO;\r
46                 public const sbyte SEG_QUADTO  = 2; //(byte) PathIterator__Finals.SEG_QUADTO;\r
47                 public const sbyte SEG_CUBICTO = 3; //(byte) PathIterator__Finals.SEG_CUBICTO;\r
48                 public const sbyte SEG_CLOSE   = 4; //(byte) PathIterator__Finals.SEG_CLOSE;\r
49                 \r
50                 public const sbyte SEG_START      = 16; // segment start\r
51 \r
52                 public const sbyte SEG_MASK       = SEG_MOVETO | SEG_LINETO | SEG_QUADTO | SEG_CUBICTO | SEG_CLOSE; // mask to eliminate SEG_CLOSE and SEG_MARKER\r
53 \r
54                 private const sbyte SEG_MARKER = 32; // path marker\r
55                 \r
56 \r
57                 private sbyte [] _types;\r
58                 private float [] _coords;\r
59                 private int _typesCount;\r
60                 private int _coordsCount;\r
61                 private int _windingRule;\r
62 \r
63                 private PathData _pathData;\r
64                 private GeneralPath _generalPath;\r
65 \r
66                 const int INIT_SIZE = 20;\r
67                 const int EXPAND_MAX = 500;\r
68 \r
69                 #endregion // Fileds\r
70 \r
71                 #region Constructors\r
72 \r
73             public ExtendedGeneralPath() : this (WIND_NON_ZERO, INIT_SIZE, INIT_SIZE)\r
74                 {\r
75                 }\r
76 \r
77                 public ExtendedGeneralPath(int rule) : this (rule, INIT_SIZE, INIT_SIZE)\r
78                 {\r
79                 }\r
80 \r
81                 public ExtendedGeneralPath(int rule, int initialCapacity) : this (rule, initialCapacity, initialCapacity)\r
82                 {\r
83                 }\r
84 \r
85                 public ExtendedGeneralPath(Shape s) : this(WIND_NON_ZERO, INIT_SIZE, INIT_SIZE)\r
86                 {\r
87                         PathIterator pi = s.getPathIterator (null);\r
88                         setWindingRule (pi.getWindingRule ());\r
89                         append (pi, false);\r
90                 }\r
91 \r
92                 private ExtendedGeneralPath(int rule, int initialTypes, int initialCoords) \r
93                 {\r
94                         setWindingRule(rule);\r
95                         Reset (initialTypes, initialCoords);\r
96                 }\r
97 \r
98                 #endregion // Constructors\r
99 \r
100                 #region Properties\r
101 \r
102                 private GeneralPath GeneralPath\r
103                 {\r
104                         get {\r
105                                 if (_generalPath == null) {                             \r
106                                         _generalPath = GetGeneralPath ();\r
107                                 }\r
108                                 return _generalPath;\r
109                         }\r
110                 }\r
111 \r
112                 public sbyte [] Types\r
113                 {\r
114                         get { return _types; }\r
115                 }\r
116 \r
117                 public float [] Coords\r
118                 {\r
119                         get { return _coords; }\r
120                 }\r
121 \r
122                 public int TypesCount\r
123                 {\r
124                         get { return _typesCount; }\r
125                 }\r
126 \r
127                 public int CoordsCount\r
128                 {\r
129                         get { return _coordsCount; }\r
130                 }\r
131 \r
132                 public bool LastFigureClosed\r
133                 {\r
134                         get { \r
135                                 return ((TypesCount == 0) || \r
136                                         ((Types [TypesCount - 1] & ExtendedGeneralPath.SEG_CLOSE) != 0) ||\r
137                                         ((Types [TypesCount - 1] & ExtendedGeneralPath.SEG_START) != 0));\r
138                         }\r
139                 }\r
140 \r
141                 public int PointCount\r
142                 {\r
143                         get {\r
144                                 return CoordsCount / 2;\r
145                         }\r
146                 }\r
147 \r
148                 public PathData PathData \r
149                 {\r
150                         get \r
151                         {\r
152                                 if (_pathData == null)\r
153                                         _pathData = GetPathData ();\r
154                                 \r
155                                 return _pathData;\r
156                         }\r
157                 }\r
158 \r
159                 #endregion // Properties\r
160 \r
161                 #region Methods\r
162 \r
163                 #region CachedData\r
164 \r
165                 private void ClearCache ()\r
166                 {\r
167                         _pathData = null;\r
168                         _generalPath = null;\r
169                 }\r
170 \r
171                 private GeneralPath GetGeneralPath ()\r
172                 {\r
173                         PathIterator iter = getPathIterator (null);\r
174                         GeneralPath path = new GeneralPath ();\r
175                         path.append (iter, false);\r
176                         return path;\r
177                 }\r
178 \r
179                 private PathData GetPathData ()\r
180                 {\r
181                         PathData pathData = new PathData();\r
182                         pathData.Types = new byte [PointCount];\r
183                         pathData.Points = new PointF [PointCount];\r
184                         int tpos = 0;\r
185                         int ppos = 0;\r
186                         int cpos = 0;\r
187                         byte marker;\r
188                         bool start;\r
189                         for (int i = 0; i < TypesCount; i++) {\r
190                                 sbyte segmentType = (sbyte)(Types [i] & SEG_MASK);\r
191 \r
192                                 // set the masks and the markers\r
193                                 marker = ((Types [i] & SEG_MARKER) != 0) ? (byte)PathPointType.PathMarker : (byte)0;\r
194                                 start = ((Types [i] & SEG_START) != 0);\r
195                                 \r
196                                 switch (segmentType) {\r
197                                         case SEG_CLOSE:\r
198                                                 pathData.InternalTypes [tpos - 1] = (byte) (pathData.InternalTypes [tpos - 1] | (byte) PathPointType.CloseSubpath | marker);\r
199                                                 break;\r
200                                         case SEG_MOVETO:\r
201                                                 pathData.InternalTypes [tpos++] = (byte)((byte) PathPointType.Start | marker);\r
202                                                 pathData.InternalPoints [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);\r
203                                                 break;\r
204                                         case SEG_LINETO:\r
205                                                 pathData.InternalTypes [tpos++] = (byte) ((byte) PathPointType.Line | marker);\r
206                                                 pathData.InternalPoints [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);\r
207                                                 break;\r
208                                         case SEG_QUADTO:\r
209                                                 // FIXME : use 4 cp , two of which \r
210                                                 pathData.InternalTypes [tpos++] = (byte)(byte) PathPointType.Bezier;\r
211                                                 pathData.InternalPoints [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);\r
212                                                 pathData.InternalTypes [tpos++] = (byte) ((byte)PathPointType.Bezier | marker);\r
213                                                 pathData.InternalPoints [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);\r
214                                                 break;\r
215                                         case SEG_CUBICTO:\r
216                                                 pathData.InternalTypes [tpos++] = (byte)(byte) PathPointType.Bezier3;\r
217                                                 pathData.InternalPoints [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);\r
218                                                 pathData.InternalTypes [tpos++] = (byte) PathPointType.Bezier3;\r
219                                                 pathData.InternalPoints [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);\r
220                                                 pathData.InternalTypes [tpos++] = (byte) ((byte)PathPointType.Bezier3 | marker);\r
221                                                 pathData.InternalPoints [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);\r
222                                                 break;\r
223                                 }\r
224                         }\r
225                         return pathData;\r
226                 }\r
227 \r
228                 #endregion // CachedData\r
229 \r
230                 public void append(Shape s)\r
231                 {\r
232                         append (s, !LastFigureClosed);\r
233                 }\r
234 \r
235                 #region GeneralPath\r
236 \r
237                 public void append(PathIterator pi, bool connect) \r
238                 {\r
239                         ClearCache ();\r
240                         float [] coords = new float [6];\r
241                         while (!pi.isDone ()) {\r
242                                 switch (pi.currentSegment (coords)) {\r
243                                         case SEG_MOVETO:\r
244                                                 if (!connect || _typesCount < 1 || _coordsCount < 2) {\r
245                                                         moveTo (coords [0], coords [1]);\r
246                                                         break;\r
247                                                 }\r
248                                                 if (_types [_typesCount - 1] != SEG_CLOSE &&\r
249                                                         _coords [_coordsCount - 2] == coords [0] &&\r
250                                                         _coords [_coordsCount - 1] == coords [1])\r
251                                                         break;  \r
252                                                 goto case SEG_LINETO;\r
253                                         case SEG_LINETO:\r
254                                                 lineTo (coords [0], coords [1]);\r
255                                                 break;\r
256                                         case SEG_QUADTO:\r
257                                                 quadTo (coords [0], coords [1], coords [2], coords [3]);\r
258                                                 break;\r
259                                         case SEG_CUBICTO:\r
260                                                 curveTo (coords [0], coords [1], coords [2], coords [3], coords [4], coords [5]);\r
261                                                 break;\r
262                                         case SEG_CLOSE:\r
263                                                 closePath ();\r
264                                         break;\r
265                                 }\r
266                                 pi.next ();\r
267                                 connect = false;\r
268                         }\r
269                 }\r
270 \r
271                 public void append(Shape s, bool connect) \r
272                 {\r
273                         PathIterator pi = s.getPathIterator (null);\r
274                         append (pi,connect);\r
275                 }\r
276 \r
277                 public object Clone() \r
278                 {\r
279                         ExtendedGeneralPath copy = (ExtendedGeneralPath)MemberwiseClone ();\r
280                         copy._types = (sbyte []) _types.Clone ();\r
281                         copy._coords = (float []) _coords.Clone ();\r
282                         return copy;\r
283                 }\r
284 \r
285                 public void closePath() \r
286                 {\r
287                         ClearCache ();\r
288                         if (_typesCount == 0 || _types[_typesCount - 1] != SEG_CLOSE) {\r
289                                 needRoom (1, 0, true);\r
290                                 _types [_typesCount++] = SEG_CLOSE;\r
291                         }\r
292                 }\r
293 \r
294                 public bool contains(double x, double y) \r
295                 {                       \r
296                         return GeneralPath.contains (x, y);\r
297                 }\r
298 \r
299                 public bool contains(double x, double y, double w, double h) \r
300                 {\r
301                         return GeneralPath.contains (x, y, w, h);\r
302                 }\r
303 \r
304                 public bool contains(Point2D p) \r
305                 {\r
306                         return contains (p.getX (), p.getY ());\r
307                 }\r
308 \r
309                 public bool contains(Rectangle2D r) \r
310                 {\r
311                         return contains (r.getX (), r.getY (), r.getWidth (), r.getHeight ());\r
312                 }\r
313 \r
314                 public Shape createTransformedShape(AffineTransform at) \r
315                 {\r
316                         ExtendedGeneralPath gp = (ExtendedGeneralPath) Clone ();\r
317                         if (at != null) {\r
318                                 gp.transform (at);\r
319                         }\r
320                         return gp;\r
321                 }\r
322 \r
323                 public void curveTo(float x1, float y1, float x2, float y2, float x3, float y3) \r
324                 {\r
325                         ClearCache ();\r
326                         needRoom (1, 6, true);\r
327                         _types [_typesCount++] = SEG_CUBICTO;\r
328                         _coords [_coordsCount++] = x1;\r
329                         _coords [_coordsCount++] = y1;\r
330                         _coords [_coordsCount++] = x2;\r
331                         _coords [_coordsCount++] = y2;\r
332                         _coords [_coordsCount++] = x3;\r
333                         _coords [_coordsCount++] = y3;\r
334                 }\r
335 \r
336                 public java.awt.Rectangle getBounds() \r
337                 {\r
338                         return getBounds2D ().getBounds ();\r
339                 }\r
340 \r
341                 public Rectangle2D getBounds2D() \r
342                 {\r
343                         float x1, y1, x2, y2;\r
344                         int i = _coordsCount;\r
345                         if (i > 0) {\r
346                                 y1 = y2 = _coords [--i];\r
347                                 x1 = x2 = _coords [--i];\r
348                                 while (i > 0) {\r
349                                         float y = _coords [--i];\r
350                                         float x = _coords [--i];\r
351                                         if (x < x1) x1 = x;\r
352                                         if (y < y1) y1 = y;\r
353                                         if (x > x2) x2 = x;\r
354                                         if (y > y2) y2 = y;\r
355                                 }\r
356                         } \r
357                         else {\r
358                                 x1 = y1 = x2 = y2 = 0f;\r
359                         }\r
360                         return new Rectangle2D.Float (x1, y1, x2 - x1, y2 - y1);\r
361                 }\r
362 \r
363                 public Point2D getCurrentPoint() \r
364                 {\r
365                         if (_typesCount < 1 || _coordsCount < 2)\r
366                                 return null;\r
367                         \r
368                         int index = _coordsCount;\r
369                         if (_types [_typesCount - 1] == SEG_CLOSE)\r
370                                 for (int i = _typesCount - 2; i > 0; i--) {\r
371                                         switch (_types [i]) {\r
372                                                 case SEG_MOVETO:\r
373                                                         //break loop;\r
374                                                         goto loopend;\r
375                                                 case SEG_LINETO:\r
376                                                         index -= 2;\r
377                                                         break;\r
378                                                 case SEG_QUADTO:\r
379                                                         index -= 4;\r
380                                                         break;\r
381                                                 case SEG_CUBICTO:\r
382                                                         index -= 6;\r
383                                                         break;\r
384                                                 case SEG_CLOSE:\r
385                                                         break;\r
386                                         }\r
387                                 }\r
388                         loopend:\r
389 \r
390                         return new Point2D.Float (_coords [index - 2], _coords [index - 1]);\r
391                 }\r
392 \r
393                 public PathIterator getPathIterator(AffineTransform at) {\r
394                         return new GeneralPathIterator (this, at);\r
395                 }\r
396 \r
397                 public PathIterator getPathIterator(AffineTransform at, double flatness) {\r
398                         return new FlatteningPathIterator (getPathIterator (at), flatness);\r
399                 }\r
400 \r
401                 public int getWindingRule() \r
402                 {\r
403                         return _windingRule;\r
404                 }\r
405 \r
406                 public bool intersects(double x, double y, double w, double h) \r
407                 {\r
408                         return GeneralPath.intersects (x, y, w, h);\r
409                 }\r
410 \r
411                 public bool intersects(Rectangle2D r) \r
412                 {\r
413                         return intersects (r.getX (), r.getY (), r.getWidth (), r.getHeight ());\r
414                 }\r
415 \r
416                 public void lineTo(float x, float y) \r
417                 {\r
418                         ClearCache ();\r
419                         needRoom (1, 2, true);\r
420                         _types [_typesCount++] = SEG_LINETO;\r
421                         _coords [_coordsCount++] = x;\r
422                         _coords [_coordsCount++] = y;\r
423                 }\r
424 \r
425                 public void moveTo(float x, float y) \r
426                 {\r
427                         ClearCache ();\r
428                         if (_typesCount > 0 && _types [_typesCount - 1] == SEG_MOVETO) {\r
429                                 _coords [_coordsCount - 2] = x;\r
430                                 _coords [_coordsCount - 1] = y;\r
431                         } \r
432                         else {\r
433                                 needRoom (1, 2, false);\r
434                                 _types [_typesCount++] = SEG_MOVETO;\r
435                                 _coords [_coordsCount++] = x;\r
436                                 _coords [_coordsCount++] = y;\r
437                         }\r
438                 }\r
439 \r
440                 public void quadTo(float x1, float y1, float x2, float y2) \r
441                 {\r
442                         ClearCache ();\r
443                         needRoom (1, 4, true);\r
444                         _types [_typesCount++] = SEG_QUADTO;\r
445                         _coords [_coordsCount++] = x1;\r
446                         _coords [_coordsCount++] = y1;\r
447                         _coords [_coordsCount++] = x2;\r
448                         _coords [_coordsCount++] = y2;\r
449                 }\r
450 \r
451                 public void reset() \r
452                 {\r
453                         ClearCache ();\r
454                         _typesCount = 0;\r
455                         _coordsCount = 0;\r
456                 }\r
457 \r
458                 public void setWindingRule(int rule) \r
459                 {\r
460                         if (rule != WIND_EVEN_ODD && rule != WIND_NON_ZERO) {\r
461                                 throw new IllegalArgumentException ("winding rule must be WIND_EVEN_ODD or WIND_NON_ZERO");\r
462                         }\r
463                         _windingRule = rule;\r
464                 }\r
465 \r
466                 public void transform(AffineTransform at) \r
467                 {\r
468                         ClearCache ();\r
469                         at.transform (_coords, 0, _coords, 0, _coordsCount/2);\r
470                 }\r
471 \r
472                 private void needRoom(int newTypes, int newCoords, bool needMove) \r
473                 {\r
474                         if (needMove && _typesCount == 0)\r
475                                 throw new IllegalPathStateException ("missing initial moveto in path definition");\r
476                         \r
477                         int size = _coords.Length;\r
478                         if (_coordsCount + newCoords > size) {\r
479                                 int grow = size;\r
480                                 if (grow > EXPAND_MAX * 2)\r
481                                         grow = EXPAND_MAX * 2;\r
482                                 \r
483                                 if (grow < newCoords)\r
484                                         grow = newCoords;\r
485                                 \r
486                                 float [] arr = new float [size + grow];\r
487                                 Array.Copy (_coords, 0, arr, 0, _coordsCount);\r
488                                 _coords = arr;\r
489                         }\r
490                         size = _types.Length;\r
491                         if (_typesCount + newTypes > size) {\r
492                                 int grow = size;\r
493                                 if (grow > EXPAND_MAX)\r
494                                         grow = EXPAND_MAX;\r
495                                 \r
496                                 if (grow < newTypes)\r
497                                         grow = newTypes;\r
498                                 \r
499                                 sbyte [] arr = new sbyte [size + grow];\r
500                                 Array.Copy (_types, 0, arr, 0, _typesCount);\r
501                                 _types = arr;\r
502                         }\r
503                 }\r
504 \r
505                 #endregion // GeneralPath\r
506 \r
507                 public void SetMarkers()\r
508                 {\r
509                         ClearCache ();\r
510                         if (TypesCount > 0)\r
511                                 Types [ TypesCount - 1] |= SEG_MARKER;\r
512                 }\r
513 \r
514                 public void ClearMarkers()\r
515                 {\r
516                         ClearCache ();\r
517                         for (int i = 0; i < TypesCount; i++)\r
518                                 Types [i] &= ~SEG_MARKER;\r
519                 }\r
520 \r
521                 public void StartFigure ()\r
522                 {\r
523                         ClearCache ();\r
524                         if (TypesCount > 0)\r
525                                 Types [TypesCount - 1] |= ExtendedGeneralPath.SEG_START;\r
526                 }\r
527 \r
528                 private void Reset (int initialTypes, int initialCoords)\r
529                 {\r
530                         ClearCache ();\r
531                         _types = new sbyte [initialTypes];\r
532                         _coords = new float [initialCoords * 2];\r
533                         _typesCount = 0;\r
534                         _coordsCount = 0;\r
535                 }\r
536 \r
537                 internal void Clear ()\r
538                 {\r
539                         Reset (INIT_SIZE, INIT_SIZE);\r
540                 }\r
541 \r
542                 internal void Reverse ()\r
543                 {\r
544                         ClearCache ();\r
545                         // revert coordinates\r
546                         for (int i=0, max = CoordsCount / 2; i < max;) {\r
547                                 int ix = i++;\r
548                                 int iy = i++;\r
549                                 int rix = CoordsCount - i;\r
550                                 int riy = rix + 1;\r
551                                 float tmpx = Coords [ix];\r
552                                 float tmpy = Coords [iy];\r
553                                 Coords [ix] = Coords [rix];\r
554                                 Coords [iy] = Coords [riy];\r
555                                 Coords [rix] = tmpx;\r
556                                 Coords [riy] = tmpy;\r
557                         }\r
558 \r
559                         // revert types\r
560                         sbyte [] newTypes = new sbyte [TypesCount];\r
561                         int oldIdx = 0;\r
562                         int newIdx = TypesCount - 1;\r
563                         int copyStart;\r
564                         int copyEnd;\r
565                         sbyte mask1 = 0;\r
566                         sbyte mask2 = 0;\r
567                         sbyte closeMask = 0;\r
568                         bool closedFigure = false;\r
569                         \r
570                         while (oldIdx < TypesCount) {\r
571                                 // start copying after moveto\r
572                                 copyStart = ++oldIdx;\r
573                                 // continue to the next figure start\r
574                                 while ((Types [oldIdx] != SEG_MOVETO) && (oldIdx < TypesCount))\r
575                                         oldIdx++;\r
576 \r
577                                 copyEnd = oldIdx - 1;\r
578                                 // check whenever current figure is closed\r
579                                 if ((Types [oldIdx - 1] & SEG_CLOSE) != 0) {\r
580                                         closedFigure = true;\r
581                                         // close figure\r
582                                         newTypes [newIdx--] = (sbyte)(SEG_CLOSE | mask1);\r
583                                         mask1 = 0;\r
584                                         mask2 = 0;\r
585                                         // end copy one cell earlier\r
586                                         copyEnd--;\r
587                                         closeMask = (sbyte)(Types [oldIdx - 1] & (sbyte)SEG_MARKER);\r
588                                 }\r
589                                 else {\r
590                                         mask2 = mask1;\r
591                                         mask1 = 0;\r
592                                 }\r
593 \r
594                                 // copy reverted "inner" types\r
595                                 for(int i = copyStart; i <= copyEnd; i++) {\r
596                                         newTypes [newIdx--] = (sbyte)((Types [i] & SEG_MASK) | mask2);\r
597                                         mask2 = mask1;\r
598                                         mask1 = (sbyte)(Types [i] & (sbyte)SEG_MARKER);\r
599                                 }\r
600 \r
601                                 // copy moveto\r
602                                 newTypes [newIdx--] = SEG_MOVETO;\r
603 \r
604                                 // pass close mask to the nex figure\r
605                                 if (closedFigure) {\r
606                                         mask1 = closeMask;\r
607                                         closedFigure = false;\r
608                                 }\r
609                         }\r
610 \r
611                         _types = newTypes;\r
612                 }\r
613 \r
614                 public PointF GetLastPoint ()\r
615                 {\r
616                         if (CoordsCount == 0)\r
617                                 throw new System.ArgumentException ("Invalid parameter used.");\r
618 \r
619                         return new PointF (Coords [CoordsCount - 2], Coords [CoordsCount - 1]);\r
620                 }\r
621 \r
622                 #endregion //Methods\r
623 \r
624                 #region Private helpers\r
625 \r
626 #if DEBUG\r
627                 private void Print()\r
628                 {\r
629                         Console.WriteLine ("\n\n");\r
630                         float [] fpoints = _coords;\r
631                         int cpos = 0;\r
632                         for (int i=0; i < _typesCount; i++) {\r
633                                 sbyte type = _types [i];\r
634                                 string marker = String.Empty;\r
635                                 if ((type & SEG_MARKER) != 0)\r
636                                         marker = " | MARKER";\r
637 \r
638                                 switch (type & SEG_MASK) {\r
639                                         case SEG_CLOSE:\r
640                                                 Console.WriteLine ("CLOSE {0}",marker);\r
641                                                 break;\r
642                                         case SEG_MOVETO:\r
643                                                 Console.WriteLine("{0}{3} ({1},{2})","MOVETO", fpoints[cpos++], fpoints[cpos++], marker);\r
644                                                 break;\r
645                                         case SEG_LINETO:\r
646                                                 Console.WriteLine("{0}{3} ({1},{2})","LINETO", fpoints[cpos++], fpoints[cpos++], marker);\r
647                                                 break;\r
648                                         case SEG_QUADTO:\r
649                                                 Console.WriteLine("{0}{3} ({1},{2})","QUADTO", fpoints[cpos++], fpoints[cpos++], marker);\r
650                                                 Console.WriteLine("       ({1},{2})","QUADTO", fpoints[cpos++], fpoints[cpos++]);\r
651                                                 break;\r
652                                         case SEG_CUBICTO:\r
653                                                 Console.WriteLine("{0}{3} ({1},{2})","CUBICTO", fpoints[cpos++], fpoints[cpos++], marker);\r
654                                                 Console.WriteLine("        ({1},{2})","CUBICTO", fpoints[cpos++], fpoints[cpos++]);\r
655                                                 Console.WriteLine("        ({1},{2})","CUBICTO", fpoints[cpos++], fpoints[cpos++]);\r
656                                                 break;\r
657                                 }\r
658                         }\r
659                 }\r
660 #endif\r
661                 #endregion // Private helpers\r
662                 \r
663         }\r
664 }\r