use correct properties
[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                         int nPts = PointCount;\r
183                         for (int i = 0; i < TypesCount; i++)\r
184                                 if ((Types [i] & SEG_MASK) == SEG_QUADTO)\r
185                                         nPts++;\r
186 \r
187                         pathData.Types = new byte [nPts];\r
188                         pathData.Points = new PointF [nPts];\r
189                         int tpos = 0;\r
190                         int ppos = 0;\r
191                         int cpos = 0;\r
192                         byte marker;\r
193                         bool start;\r
194                         for (int i = 0; i < TypesCount; i++) {\r
195                                 sbyte segmentType = (sbyte)(Types [i] & SEG_MASK);\r
196 \r
197                                 // set the masks and the markers\r
198                                 marker = ((Types [i] & SEG_MARKER) != 0) ? (byte)PathPointType.PathMarker : (byte)0;\r
199                                 start = ((Types [i] & SEG_START) != 0);\r
200                                 \r
201                                 switch (segmentType) {\r
202                                         case SEG_CLOSE:\r
203                                                 pathData.Types [tpos - 1] = (byte) (pathData.Types [tpos - 1] | (byte) PathPointType.CloseSubpath | marker);\r
204                                                 break;\r
205                                         case SEG_MOVETO:\r
206                                                 pathData.Types [tpos++] = (byte)((byte) PathPointType.Start | marker);\r
207                                                 pathData.Points [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);\r
208                                                 break;\r
209                                         case SEG_LINETO:\r
210                                                 pathData.Types [tpos++] = (byte) ((byte) PathPointType.Line | marker);\r
211                                                 pathData.Points [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);\r
212                                                 break;\r
213                                         case SEG_QUADTO:\r
214                                                 /*\r
215                                                         .net does not support Quadratic curves, so convert to Cubic according to http://pfaedit.sourceforge.net/bezier.html\r
216                                                           \r
217                                                         The end points of the cubic will be the same as the quadratic's.\r
218                                                         CP0 = QP0\r
219                                                         CP3 = QP2 \r
220 \r
221                                                         The two control points for the cubic are:\r
222 \r
223                                                         CP1 = QP0 + 2/3 *(QP1-QP0)\r
224                                                         CP2 = CP1 + 1/3 *(QP2-QP0) \r
225                                                 */\r
226 \r
227                                                 float x0 = Coords[cpos-2]; //QP0\r
228                                                 float y0 = Coords[cpos-1]; //QP0\r
229                         \r
230                                                 float x1 = x0 + (2/3 * (Coords [cpos++]-x0));\r
231                                                 float y1 = y0 + (2/3 * (Coords [cpos++]-y0));\r
232 \r
233                                                 float x3 = Coords [cpos++]; //QP2\r
234                                                 float y3 = Coords [cpos++]; //QP2\r
235                                                 \r
236                                                 float x2 = x1 + (1/3 * (x3-x0));\r
237                                                 float y2 = y1 + (1/3 * (y3-y0));\r
238 \r
239                                                 pathData.Types [tpos++] = (byte)(byte) PathPointType.Bezier;\r
240                                                 pathData.Points [ppos++] = new PointF (x1, y1);\r
241                                                 pathData.Types [tpos++] = (byte)(byte) PathPointType.Bezier;\r
242                                                 pathData.Points [ppos++] = new PointF (x2, y2);\r
243                                                 pathData.Types [tpos++] = (byte) ((byte)PathPointType.Bezier | marker);\r
244                                                 pathData.Points [ppos++] = new PointF (x3, y3);\r
245                                                 break;\r
246                                         case SEG_CUBICTO:\r
247                                                 pathData.Types [tpos++] = (byte)(byte) PathPointType.Bezier3;\r
248                                                 pathData.Points [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);\r
249                                                 pathData.Types [tpos++] = (byte) PathPointType.Bezier3;\r
250                                                 pathData.Points [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);\r
251                                                 pathData.Types [tpos++] = (byte) ((byte)PathPointType.Bezier3 | marker);\r
252                                                 pathData.Points [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);\r
253                                                 break;\r
254                                 }\r
255                         }\r
256                         return pathData;\r
257                 }\r
258 \r
259                 #endregion // CachedData\r
260 \r
261                 public void append(Shape s)\r
262                 {\r
263                         append (s, !LastFigureClosed);\r
264                 }\r
265 \r
266                 #region GeneralPath\r
267 \r
268                 public void append(PathIterator pi, bool connect) \r
269                 {\r
270                         ClearCache ();\r
271                         float [] coords = new float [6];\r
272                         while (!pi.isDone ()) {\r
273                                 switch (pi.currentSegment (coords)) {\r
274                                         case SEG_MOVETO:\r
275                                                 if (!connect || _typesCount < 1 || _coordsCount < 2) {\r
276                                                         moveTo (coords [0], coords [1]);\r
277                                                         break;\r
278                                                 }\r
279                                                 if (_types [_typesCount - 1] != SEG_CLOSE &&\r
280                                                         _coords [_coordsCount - 2] == coords [0] &&\r
281                                                         _coords [_coordsCount - 1] == coords [1])\r
282                                                         break;  \r
283                                                 goto case SEG_LINETO;\r
284                                         case SEG_LINETO:\r
285                                                 lineTo (coords [0], coords [1]);\r
286                                                 break;\r
287                                         case SEG_QUADTO:\r
288                                                 quadTo (coords [0], coords [1], coords [2], coords [3]);\r
289                                                 break;\r
290                                         case SEG_CUBICTO:\r
291                                                 curveTo (coords [0], coords [1], coords [2], coords [3], coords [4], coords [5]);\r
292                                                 break;\r
293                                         case SEG_CLOSE:\r
294                                                 closePath ();\r
295                                         break;\r
296                                 }\r
297                                 pi.next ();\r
298                                 connect = false;\r
299                         }\r
300                 }\r
301 \r
302                 public void append(Shape s, bool connect) \r
303                 {\r
304                         PathIterator pi = s.getPathIterator (null);\r
305                         append (pi,connect);\r
306                 }\r
307 \r
308                 public object Clone() \r
309                 {\r
310                         ExtendedGeneralPath copy = (ExtendedGeneralPath)MemberwiseClone ();\r
311                         copy._types = (sbyte []) _types.Clone ();\r
312                         copy._coords = (float []) _coords.Clone ();\r
313                         return copy;\r
314                 }\r
315 \r
316                 public void closePath() \r
317                 {\r
318                         ClearCache ();\r
319                         if (_typesCount == 0 || _types[_typesCount - 1] != SEG_CLOSE) {\r
320                                 needRoom (1, 0, true);\r
321                                 _types [_typesCount++] = SEG_CLOSE;\r
322                         }\r
323                 }\r
324 \r
325                 public bool contains(double x, double y) \r
326                 {                       \r
327                         return GeneralPath.contains (x, y);\r
328                 }\r
329 \r
330                 public bool contains(double x, double y, double w, double h) \r
331                 {\r
332                         return GeneralPath.contains (x, y, w, h);\r
333                 }\r
334 \r
335                 public bool contains(Point2D p) \r
336                 {\r
337                         return contains (p.getX (), p.getY ());\r
338                 }\r
339 \r
340                 public bool contains(Rectangle2D r) \r
341                 {\r
342                         return contains (r.getX (), r.getY (), r.getWidth (), r.getHeight ());\r
343                 }\r
344 \r
345                 public Shape createTransformedShape(AffineTransform at) \r
346                 {\r
347                         ExtendedGeneralPath gp = (ExtendedGeneralPath) Clone ();\r
348                         if (at != null) {\r
349                                 gp.transform (at);\r
350                         }\r
351                         return gp;\r
352                 }\r
353 \r
354                 public void curveTo(float x1, float y1, float x2, float y2, float x3, float y3) \r
355                 {\r
356                         ClearCache ();\r
357                         needRoom (1, 6, true);\r
358                         _types [_typesCount++] = SEG_CUBICTO;\r
359                         _coords [_coordsCount++] = x1;\r
360                         _coords [_coordsCount++] = y1;\r
361                         _coords [_coordsCount++] = x2;\r
362                         _coords [_coordsCount++] = y2;\r
363                         _coords [_coordsCount++] = x3;\r
364                         _coords [_coordsCount++] = y3;\r
365                 }\r
366 \r
367                 public java.awt.Rectangle getBounds() \r
368                 {\r
369                         return getBounds2D ().getBounds ();\r
370                 }\r
371 \r
372                 public Rectangle2D getBounds2D() \r
373                 {\r
374                         float x1, y1, x2, y2;\r
375                         int i = _coordsCount;\r
376                         if (i > 0) {\r
377                                 y1 = y2 = _coords [--i];\r
378                                 x1 = x2 = _coords [--i];\r
379                                 while (i > 0) {\r
380                                         float y = _coords [--i];\r
381                                         float x = _coords [--i];\r
382                                         if (x < x1) x1 = x;\r
383                                         if (y < y1) y1 = y;\r
384                                         if (x > x2) x2 = x;\r
385                                         if (y > y2) y2 = y;\r
386                                 }\r
387                         } \r
388                         else {\r
389                                 x1 = y1 = x2 = y2 = 0f;\r
390                         }\r
391                         return new Rectangle2D.Float (x1, y1, x2 - x1, y2 - y1);\r
392                 }\r
393 \r
394                 public Point2D getCurrentPoint() \r
395                 {\r
396                         if (_typesCount < 1 || _coordsCount < 2)\r
397                                 return null;\r
398                         \r
399                         int index = _coordsCount;\r
400                         if (_types [_typesCount - 1] == SEG_CLOSE)\r
401                                 for (int i = _typesCount - 2; i > 0; i--) {\r
402                                         switch (_types [i]) {\r
403                                                 case SEG_MOVETO:\r
404                                                         //break loop;\r
405                                                         goto loopend;\r
406                                                 case SEG_LINETO:\r
407                                                         index -= 2;\r
408                                                         break;\r
409                                                 case SEG_QUADTO:\r
410                                                         index -= 4;\r
411                                                         break;\r
412                                                 case SEG_CUBICTO:\r
413                                                         index -= 6;\r
414                                                         break;\r
415                                                 case SEG_CLOSE:\r
416                                                         break;\r
417                                         }\r
418                                 }\r
419                         loopend:\r
420 \r
421                         return new Point2D.Float (_coords [index - 2], _coords [index - 1]);\r
422                 }\r
423 \r
424                 public PathIterator getPathIterator(AffineTransform at) {\r
425                         return new GeneralPathIterator (this, at);\r
426                 }\r
427 \r
428                 public PathIterator getPathIterator(AffineTransform at, double flatness) {\r
429                         return new FlatteningPathIterator (getPathIterator (at), flatness);\r
430                 }\r
431 \r
432                 public int getWindingRule() \r
433                 {\r
434                         return _windingRule;\r
435                 }\r
436 \r
437                 public bool intersects(double x, double y, double w, double h) \r
438                 {\r
439                         return GeneralPath.intersects (x, y, w, h);\r
440                 }\r
441 \r
442                 public bool intersects(Rectangle2D r) \r
443                 {\r
444                         return intersects (r.getX (), r.getY (), r.getWidth (), r.getHeight ());\r
445                 }\r
446 \r
447                 public void lineTo(float x, float y) \r
448                 {\r
449                         ClearCache ();\r
450                         needRoom (1, 2, true);\r
451                         _types [_typesCount++] = SEG_LINETO;\r
452                         _coords [_coordsCount++] = x;\r
453                         _coords [_coordsCount++] = y;\r
454                 }\r
455 \r
456                 public void moveTo(float x, float y) \r
457                 {\r
458                         ClearCache ();\r
459                         if (_typesCount > 0 && _types [_typesCount - 1] == SEG_MOVETO) {\r
460                                 _coords [_coordsCount - 2] = x;\r
461                                 _coords [_coordsCount - 1] = y;\r
462                         } \r
463                         else {\r
464                                 needRoom (1, 2, false);\r
465                                 _types [_typesCount++] = SEG_MOVETO;\r
466                                 _coords [_coordsCount++] = x;\r
467                                 _coords [_coordsCount++] = y;\r
468                         }\r
469                 }\r
470 \r
471                 public void quadTo(float x1, float y1, float x2, float y2) \r
472                 {\r
473                         // restore quadTo as cubic affects quality\r
474                         ClearCache ();\r
475                         needRoom (1, 4, true);\r
476                         _types [_typesCount++] = SEG_QUADTO;\r
477                         _coords [_coordsCount++] = x1;\r
478                         _coords [_coordsCount++] = y1;\r
479                         _coords [_coordsCount++] = x2;\r
480                         _coords [_coordsCount++] = y2;\r
481                 }\r
482 \r
483                 public void reset() \r
484                 {\r
485                         ClearCache ();\r
486                         _typesCount = 0;\r
487                         _coordsCount = 0;\r
488                 }\r
489 \r
490                 public void setWindingRule(int rule) \r
491                 {\r
492                         if (rule != WIND_EVEN_ODD && rule != WIND_NON_ZERO) {\r
493                                 throw new IllegalArgumentException ("winding rule must be WIND_EVEN_ODD or WIND_NON_ZERO");\r
494                         }\r
495                         _windingRule = rule;\r
496                 }\r
497 \r
498                 public void transform(AffineTransform at) \r
499                 {\r
500                         transform(at, 0, CoordsCount);\r
501                 }\r
502 \r
503                 public void transform(AffineTransform at, int startCoord, int numCoords) {\r
504                         ClearCache ();\r
505                         at.transform (_coords, startCoord, _coords, startCoord, numCoords/2);\r
506                 }\r
507 \r
508                 private void needRoom(int newTypes, int newCoords, bool needMove) \r
509                 {\r
510                         if (needMove && _typesCount == 0)\r
511                                 throw new IllegalPathStateException ("missing initial moveto in path definition");\r
512                         \r
513                         int size = _coords.Length;\r
514                         if (_coordsCount + newCoords > size) {\r
515                                 int grow = size;\r
516                                 if (grow > EXPAND_MAX * 2)\r
517                                         grow = EXPAND_MAX * 2;\r
518                                 \r
519                                 if (grow < newCoords)\r
520                                         grow = newCoords;\r
521                                 \r
522                                 float [] arr = new float [size + grow];\r
523                                 Array.Copy (_coords, 0, arr, 0, _coordsCount);\r
524                                 _coords = arr;\r
525                         }\r
526                         size = _types.Length;\r
527                         if (_typesCount + newTypes > size) {\r
528                                 int grow = size;\r
529                                 if (grow > EXPAND_MAX)\r
530                                         grow = EXPAND_MAX;\r
531                                 \r
532                                 if (grow < newTypes)\r
533                                         grow = newTypes;\r
534                                 \r
535                                 sbyte [] arr = new sbyte [size + grow];\r
536                                 Array.Copy (_types, 0, arr, 0, _typesCount);\r
537                                 _types = arr;\r
538                         }\r
539                 }\r
540 \r
541                 #endregion // GeneralPath\r
542 \r
543                 public void SetMarkers()\r
544                 {\r
545                         ClearCache ();\r
546                         if (TypesCount > 0)\r
547                                 Types [ TypesCount - 1] |= SEG_MARKER;\r
548                 }\r
549 \r
550                 public void ClearMarkers()\r
551                 {\r
552                         ClearCache ();\r
553                         for (int i = 0; i < TypesCount; i++)\r
554                                 Types [i] &= ~SEG_MARKER;\r
555                 }\r
556 \r
557                 public void StartFigure ()\r
558                 {\r
559                         ClearCache ();\r
560                         if (TypesCount > 0)\r
561                                 Types [TypesCount - 1] |= ExtendedGeneralPath.SEG_START;\r
562                 }\r
563 \r
564                 private void Reset (int initialTypes, int initialCoords)\r
565                 {\r
566                         ClearCache ();\r
567                         _types = new sbyte [initialTypes];\r
568                         _coords = new float [initialCoords * 2];\r
569                         _typesCount = 0;\r
570                         _coordsCount = 0;\r
571                 }\r
572 \r
573                 internal void Clear ()\r
574                 {\r
575                         Reset (INIT_SIZE, INIT_SIZE);\r
576                 }\r
577 \r
578                 internal void Reverse ()\r
579                 {\r
580                         ClearCache ();\r
581                         // revert coordinates\r
582                         for (int i=0, max = CoordsCount / 2; i < max;) {\r
583                                 int ix = i++;\r
584                                 int iy = i++;\r
585                                 int rix = CoordsCount - i;\r
586                                 int riy = rix + 1;\r
587                                 float tmpx = Coords [ix];\r
588                                 float tmpy = Coords [iy];\r
589                                 Coords [ix] = Coords [rix];\r
590                                 Coords [iy] = Coords [riy];\r
591                                 Coords [rix] = tmpx;\r
592                                 Coords [riy] = tmpy;\r
593                         }\r
594 \r
595                         // revert types\r
596                         sbyte [] newTypes = new sbyte [TypesCount];\r
597                         int oldIdx = 0;\r
598                         int newIdx = TypesCount - 1;\r
599                         int copyStart;\r
600                         int copyEnd;\r
601                         sbyte mask1 = 0;\r
602                         sbyte mask2 = 0;\r
603                         sbyte closeMask = 0;\r
604                         bool closedFigure = false;\r
605                         \r
606                         while (oldIdx < TypesCount) {\r
607                                 // start copying after moveto\r
608                                 copyStart = ++oldIdx;\r
609                                 // continue to the next figure start\r
610                                 while ((Types [oldIdx] != SEG_MOVETO) && (oldIdx < TypesCount))\r
611                                         oldIdx++;\r
612 \r
613                                 copyEnd = oldIdx - 1;\r
614                                 // check whenever current figure is closed\r
615                                 if ((Types [oldIdx - 1] & SEG_CLOSE) != 0) {\r
616                                         closedFigure = true;\r
617                                         // close figure\r
618                                         newTypes [newIdx--] = (sbyte)(SEG_CLOSE | mask1);\r
619                                         mask1 = 0;\r
620                                         mask2 = 0;\r
621                                         // end copy one cell earlier\r
622                                         copyEnd--;\r
623                                         closeMask = (sbyte)(Types [oldIdx - 1] & (sbyte)SEG_MARKER);\r
624                                 }\r
625                                 else {\r
626                                         mask2 = mask1;\r
627                                         mask1 = 0;\r
628                                 }\r
629 \r
630                                 // copy reverted "inner" types\r
631                                 for(int i = copyStart; i <= copyEnd; i++) {\r
632                                         newTypes [newIdx--] = (sbyte)((Types [i] & SEG_MASK) | mask2);\r
633                                         mask2 = mask1;\r
634                                         mask1 = (sbyte)(Types [i] & (sbyte)SEG_MARKER);\r
635                                 }\r
636 \r
637                                 // copy moveto\r
638                                 newTypes [newIdx--] = SEG_MOVETO;\r
639 \r
640                                 // pass close mask to the nex figure\r
641                                 if (closedFigure) {\r
642                                         mask1 = closeMask;\r
643                                         closedFigure = false;\r
644                                 }\r
645                         }\r
646 \r
647                         _types = newTypes;\r
648                 }\r
649 \r
650                 public PointF GetLastPoint ()\r
651                 {\r
652                         if (CoordsCount == 0)\r
653                                 throw new System.ArgumentException ("Invalid parameter used.");\r
654 \r
655                         return new PointF (Coords [CoordsCount - 2], Coords [CoordsCount - 1]);\r
656                 }\r
657 \r
658                 #endregion //Methods\r
659 \r
660                 #region Private helpers\r
661 \r
662 #if DEBUG\r
663                 private void Print()\r
664                 {\r
665                         Console.WriteLine ("\n\n");\r
666                         float [] fpoints = _coords;\r
667                         int cpos = 0;\r
668                         for (int i=0; i < _typesCount; i++) {\r
669                                 sbyte type = _types [i];\r
670                                 string marker = String.Empty;\r
671                                 if ((type & SEG_MARKER) != 0)\r
672                                         marker = " | MARKER";\r
673 \r
674                                 switch (type & SEG_MASK) {\r
675                                         case SEG_CLOSE:\r
676                                                 Console.WriteLine ("CLOSE {0}",marker);\r
677                                                 break;\r
678                                         case SEG_MOVETO:\r
679                                                 Console.WriteLine("{0}{3} ({1},{2})","MOVETO", fpoints[cpos++], fpoints[cpos++], marker);\r
680                                                 break;\r
681                                         case SEG_LINETO:\r
682                                                 Console.WriteLine("{0}{3} ({1},{2})","LINETO", fpoints[cpos++], fpoints[cpos++], marker);\r
683                                                 break;\r
684                                         case SEG_QUADTO:\r
685                                                 Console.WriteLine("{0}{3} ({1},{2})","QUADTO", fpoints[cpos++], fpoints[cpos++], marker);\r
686                                                 Console.WriteLine("       ({1},{2})","QUADTO", fpoints[cpos++], fpoints[cpos++]);\r
687                                                 break;\r
688                                         case SEG_CUBICTO:\r
689                                                 Console.WriteLine("{0}{3} ({1},{2})","CUBICTO", fpoints[cpos++], fpoints[cpos++], marker);\r
690                                                 Console.WriteLine("        ({1},{2})","CUBICTO", fpoints[cpos++], fpoints[cpos++]);\r
691                                                 Console.WriteLine("        ({1},{2})","CUBICTO", fpoints[cpos++], fpoints[cpos++]);\r
692                                                 break;\r
693                                 }\r
694                         }\r
695                 }\r
696 #endif\r
697                 #endregion // Private helpers\r
698                 \r
699         }\r
700 }\r