* roottypes.cs: Rename from tree.cs.
[mono.git] / mcs / class / System.Drawing / System.Drawing.Drawing2D / GraphicsPath.jvm.cs
1 //
2 // System.Drawing.Drawing2D.GraphicsPath.cs
3 //
4 // Author:
5 // Konstantin Triger <kostat@mainsoft.com>
6 // Bors Kirzner <boris@mainsoft.com>    
7 //
8 // Copyright (C) 2005 Mainsoft Corporation, (http://www.mainsoft.com)
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //\r
29 using System;\r
30 using System.Drawing;\r
31 using System.Drawing.Text;\r
32 using System.Collections;\r
33 using java.awt.geom;\r
34 using java.awt;\r
35 \r
36 namespace System.Drawing.Drawing2D\r
37 {\r
38         public sealed class GraphicsPath : BasicShape, ICloneable\r
39         {\r
40                 internal enum JPI {\r
41                         SEG_MOVETO = ExtendedGeneralPath.SEG_MOVETO,\r
42                         SEG_LINETO = ExtendedGeneralPath.SEG_LINETO,\r
43                         SEG_QUADTO = ExtendedGeneralPath.SEG_QUADTO,\r
44                         SEG_CUBICTO = ExtendedGeneralPath.SEG_CUBICTO,\r
45                         SEG_CLOSE = ExtendedGeneralPath.SEG_CLOSE\r
46                 }\r
47 \r
48                 #region Internal\r
49 \r
50                 internal ExtendedGeneralPath NativeObject\r
51                 {\r
52                         get \r
53                         {\r
54                                 return (ExtendedGeneralPath)Shape;\r
55                         }\r
56                 }\r
57 \r
58                 GraphicsPath (ExtendedGeneralPath ptr) : base(ptr)\r
59                 {\r
60                 }\r
61                 #endregion\r
62 \r
63                 #region  C-tors.\r
64                 public GraphicsPath ():\r
65                         this(FillMode.Alternate)\r
66                 {\r
67                 }\r
68                 \r
69                 public GraphicsPath (FillMode fillMode) : this(new ExtendedGeneralPath ())\r
70                 {\r
71                         FillMode = fillMode;\r
72                 }\r
73                 \r
74                 public GraphicsPath (Point[] pts, byte[] types) : this(pts, types, FillMode.Alternate)\r
75                 {\r
76                 }\r
77                 \r
78                 public GraphicsPath (PointF [] pts, byte [] types) : this(pts, types, FillMode.Alternate)\r
79                 {\r
80                 }\r
81                 \r
82                 public GraphicsPath (Point [] pts, byte [] types, FillMode fillMode) : this(new ExtendedGeneralPath ())\r
83                 {\r
84                         FillMode = fillMode;\r
85                         SetPath (pts, types);\r
86                 }\r
87 \r
88                 public GraphicsPath (PointF [] pts, byte [] types, FillMode fillMode) : this(new ExtendedGeneralPath ())\r
89                 {\r
90                         FillMode = fillMode;\r
91                         SetPath (pts, types);\r
92                 }\r
93 \r
94                 #endregion\r
95 \r
96                 #region Clone\r
97                 public object Clone ()\r
98                 {\r
99                         return new GraphicsPath ((ExtendedGeneralPath) NativeObject.Clone ());\r
100                 }\r
101                 #endregion\r
102 \r
103                 #region Properties\r
104                 public FillMode FillMode \r
105                 {\r
106                         get \r
107                         {   if(NativeObject.getWindingRule() == GeneralPath.WIND_EVEN_ODD)\r
108                                         return FillMode.Alternate;\r
109                                 else\r
110                                         return FillMode.Winding;\r
111                         }\r
112 \r
113                         set \r
114                         {\r
115                                 if (value == FillMode.Alternate)\r
116                                         NativeObject.setWindingRule (GeneralPath.WIND_EVEN_ODD);\r
117                                 else\r
118                                         NativeObject.setWindingRule (GeneralPath.WIND_NON_ZERO);\r
119                         }\r
120                 }\r
121 \r
122                 public PathData PathData \r
123                 {\r
124                         get { return NativeObject.PathData; }\r
125                 }\r
126 \r
127                 public PointF [] PathPoints \r
128                 {\r
129                         get \r
130                         {\r
131                                 return PathData.Points;\r
132                         }\r
133                 }\r
134 \r
135                 public byte [] PathTypes \r
136                 {\r
137                         get \r
138                         {\r
139                                 return PathData.Types;                  \r
140                         }\r
141                 }\r
142                 #endregion\r
143 \r
144                 #region PointCount\r
145                 public int PointCount \r
146                 {\r
147                         get \r
148                         {\r
149                                 return NativeObject.PointCount;\r
150                         }\r
151                 }\r
152                 #endregion\r
153                         \r
154                 #region AddArc\r
155                 public void AddArc (Rectangle rect, float startAngle, float sweepAngle)\r
156                 {\r
157                         AddArc(rect.X,rect.Y,rect.Width,rect.Height,startAngle,sweepAngle);                     \r
158                 }\r
159 \r
160                 public void AddArc (RectangleF rect, float startAngle, float sweepAngle)\r
161                 {\r
162                         AddArc(rect.X,rect.Y,rect.Width,rect.Height,startAngle,sweepAngle);\r
163                 }\r
164 \r
165                 public void AddArc (int x, int y, int width, int height, float startAngle, float sweepAngle)\r
166                 {\r
167                         AddArc((float)x,(float)y,(float)width,(float)height,startAngle,sweepAngle);\r
168                 }\r
169 \r
170                 public void AddArc (float x, float y, float width, float height, float startAngle, float sweepAngle)\r
171                 {\r
172                         Shape shape = null;\r
173 \r
174                         if (sweepAngle >= 360)\r
175                                 shape = new Ellipse2D.Float(x, y, width, height);\r
176                         else {\r
177 \r
178                                 double d1Tod2 = width/height;\r
179                                 double sqrd1Tod2 = d1Tod2*d1Tod2;\r
180                                 double start = ConvertArcAngle(sqrd1Tod2, startAngle);\r
181                                 double extent = ConvertArcAngle(sqrd1Tod2, startAngle+sweepAngle) - start;\r
182 \r
183                                 shape = new Arc2D.Double(x,y,width,height,-start,-extent,Arc2D.OPEN);\r
184                         }\r
185 \r
186                         NativeObject.append(shape);\r
187                 }\r
188 \r
189                 /// <summary>\r
190                 /// .Net computes an angle by intersection of ellipse with a ray\r
191                 /// java does the following: x1 = d1*cos(a), y1 = d2*sin(a)\r
192                 /// where: d1 = width/2, d2 = height/2\r
193                 /// we need to find angle x, which satisfies:\r
194                 /// x1 = m*cos(a) = d1*cos(x)\r
195                 /// y1 = m*sin(a) = d2*sin(x)\r
196                 /// (x1*x1)/(d1*d1) + (x2*x2)/(d2*d2) = 1\r
197                 /// </summary>\r
198                 /// <param name="sqrd1Tod2">(d1/d2)*(d1/d2)</param>\r
199                 /// <param name="angle">angle in degrees</param>\r
200                 /// <returns>converted angle in degrees</returns>\r
201                 static double ConvertArcAngle(double sqrd1Tod2, double angle) {\r
202                         double angleRad = java.lang.Math.toRadians(angle);\r
203                         double tan = Math.Tan(angleRad);\r
204                         double cosx = 1/Math.Sqrt( sqrd1Tod2 * (tan*tan) + 1);\r
205                         double xRad = Math.Acos(cosx);\r
206                         double x = java.lang.Math.toDegrees(xRad);\r
207                         int q = (Math.Abs((int)angle))/90;\r
208 \r
209                         switch (q&3) {\r
210                                 case 1:\r
211                                         x = 180-x;\r
212                                         break;\r
213                                 case 2:\r
214                                         x = 180+x;\r
215                                         break;\r
216                                 case 3:\r
217                                         x = 360-x;\r
218                                         break;\r
219                         }\r
220 \r
221                         if (angle < 0)\r
222                                 x = -x;\r
223 \r
224                         x += (((int)angle)/360)*360;\r
225 \r
226                         return x;\r
227                 }\r
228 \r
229                 #endregion\r
230                 \r
231                 #region AddBezier(s)\r
232                 public void AddBezier (Point pt1, Point pt2, Point pt3, Point pt4)\r
233                 {\r
234                         AddBezier(pt1.X,pt1.Y,pt2.X,pt2.Y,pt3.X,pt3.Y,pt4.X,pt4.Y);\r
235                 }\r
236 \r
237                 public void AddBezier (PointF pt1, PointF pt2, PointF pt3, PointF pt4)\r
238                 {                       \r
239                         AddBezier(pt1.X,pt1.Y,pt2.X,pt2.Y,pt3.X,pt3.Y,pt4.X,pt4.Y);\r
240                 }\r
241 \r
242                 public void AddBezier (int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4)\r
243                 {\r
244                         AddBezier((float)x1,(float)y1,(float)x2,(float)y2,(float)x3,(float)y3,(float)x4,(float)y4);\r
245                 }\r
246 \r
247                 public void AddBezier (float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4)\r
248                 {\r
249                         CubicCurve2D cc = new CubicCurve2D.Float(x1,y1,x2,y2,x3,y3,x4,y4);\r
250                         NativeObject.append(cc);\r
251                 }\r
252 \r
253                 public void AddBeziers (Point [] pts)\r
254                 {\r
255                         if (pts == null)\r
256                                 throw new ArgumentNullException("points");\r
257 \r
258                         AddBezier(pts [0].X,pts [0].Y,\r
259                                         pts [1].X,pts [1].Y,\r
260                                         pts [2].X,pts [2].Y,\r
261                                         pts [3].X,pts [3].Y);\r
262 \r
263                         for (int i = 4; i < pts.Length; i += 3) {\r
264                                 NativeObject.curveTo(   \r
265                                         pts [i].X,pts [i].Y,\r
266                                         pts [i+1].X,pts [i+1].Y,\r
267                                         pts [i+2].X,pts [i+2].Y);\r
268                         }\r
269                 }\r
270 \r
271                 public void AddBeziers (PointF [] pts)\r
272                 {\r
273                         if (pts == null)\r
274                                 throw new ArgumentNullException("points");\r
275 \r
276                         AddBezier(pts [0].X,pts [0].Y,\r
277                                 pts [1].X,pts [1].Y,\r
278                                 pts [2].X,pts [2].Y,\r
279                                 pts [3].X,pts [3].Y);\r
280 \r
281                         for (int i = 4; i < pts.Length; i += 3) {\r
282                                 NativeObject.curveTo(   \r
283                                         pts [i].X,pts [i].Y,\r
284                                         pts [i+1].X,pts [i+1].Y,\r
285                                         pts [i+2].X,pts [i+2].Y);\r
286                         }\r
287                 }\r
288                 #endregion\r
289 \r
290                 #region AddEllipse\r
291                 public void AddEllipse (float x, float y, float width, float height)\r
292                 {\r
293                         Ellipse2D e = new Ellipse2D.Float(x,y,width,height);\r
294                         NativeObject.append(e,false);\r
295                 }\r
296 \r
297                 public void AddEllipse (RectangleF r)\r
298                 {\r
299                         AddEllipse(r.X,r.Y,r.Width,r.Height);\r
300                 }\r
301                 \r
302                 public void AddEllipse (Rectangle r)\r
303                 {\r
304                         AddEllipse(r.X,r.Y,r.Width,r.Height);\r
305                 }\r
306                 \r
307                 public void AddEllipse (int x, int y, int width, int height)\r
308                 {\r
309                         AddEllipse((float)x, (float)y, (float)width, (float)height);\r
310                 }\r
311                 #endregion\r
312                 \r
313                 #region AddLine\r
314                 public void AddLine (float x1, float y1, float x2, float y2)\r
315                 {\r
316                         Line2D l = new Line2D.Float(x1,y1,x2,y2);\r
317                         NativeObject.append(l);\r
318                 }\r
319 \r
320                 public void AddLine (Point a, Point b)\r
321                 {\r
322                         AddLine(a.X,a.Y,b.X,b.Y);\r
323                 }\r
324 \r
325                 public void AddLine (PointF a, PointF b)\r
326                 {\r
327                         AddLine(a.X,a.Y,b.X,b.Y);\r
328                 }\r
329 \r
330                 public void AddLine (int x1, int y1, int x2, int y2)\r
331                 {\r
332                         AddLine((float)x1,(float)y1,(float)x2,(float)y2);\r
333                 }\r
334 \r
335                 public void AddLines (Point [] points)\r
336                 {                       \r
337                         if (points == null)\r
338                                 throw new ArgumentNullException("points");\r
339 \r
340                         if (points.Length == 0)\r
341                                 return;\r
342 \r
343                         if (NativeObject.LastFigureClosed)\r
344                                 NativeObject.moveTo(points[0].X, points[0].Y);\r
345                         else\r
346                                 NativeObject.lineTo(points[0].X, points[0].Y);\r
347 \r
348                         for (int i = 1; i < points.Length; i ++)\r
349                                 NativeObject.lineTo(points[i].X, points[i].Y);\r
350                 }\r
351 \r
352                 public void AddLines (PointF [] points)\r
353                 {\r
354                         if (points == null)\r
355                                 throw new ArgumentNullException("points");\r
356 \r
357                         if (points.Length == 0)\r
358                                 return;\r
359 \r
360                         if (NativeObject.LastFigureClosed)\r
361                                 NativeObject.moveTo(points[0].X, points[0].Y);\r
362                         else\r
363                                 NativeObject.lineTo(points[0].X, points[0].Y);\r
364 \r
365                         for (int i = 1; i < points.Length; i ++)\r
366                                 NativeObject.lineTo(points[i].X, points[i].Y);\r
367                 }\r
368                 #endregion\r
369         \r
370                 #region AddPie\r
371                 public void AddPie (float x, float y, float width, float height, float startAngle, float sweepAngle)\r
372                 {\r
373                         Shape shape = null;\r
374 \r
375                         if (sweepAngle >= 360)\r
376                                 shape = new Ellipse2D.Float(x, y, width, height);\r
377                         else {\r
378 \r
379                                 double d1Tod2 = width/height;\r
380                                 double sqrd1Tod2 = d1Tod2*d1Tod2;\r
381                                 double start = ConvertArcAngle(sqrd1Tod2, startAngle);\r
382                                 double extent = ConvertArcAngle(sqrd1Tod2, startAngle+sweepAngle) - start;\r
383 \r
384                                 shape = new Arc2D.Double(x,y,width,height,-start,-extent,Arc2D.PIE);\r
385                         }\r
386 \r
387                         NativeObject.append(shape,false);\r
388                 }\r
389 \r
390                 public void AddPie (Rectangle rect, float startAngle, float sweepAngle)\r
391                 {\r
392                         AddPie((float)rect.X, (float)rect.Y,(float)rect.Width,(float)rect.Height,startAngle,sweepAngle);                \r
393                 }\r
394 \r
395                 public void AddPie (int x, int y, int width, int height, float startAngle, float sweepAngle)\r
396                 {\r
397                         AddPie((float)x,(float)y,(float)width,(float)height,startAngle,sweepAngle);             \r
398                 }\r
399                 #endregion\r
400 \r
401                 #region AddPolygon\r
402                 public void AddPolygon (Point [] points)\r
403                 {\r
404                         if (points == null)\r
405                                 throw new ArgumentNullException("points");\r
406 \r
407                         if (points.Length < 3)\r
408                                 throw new ArgumentException("Invalid parameter used.");\r
409 \r
410                         NativeObject.moveTo((float)points[0].X,(float)points[0].Y);\r
411                         for (int i = 1; i< points.Length; i++)\r
412                         {\r
413                                 NativeObject.lineTo((float)points[i].X,(float)points[i].Y);\r
414                         }\r
415                         NativeObject.closePath();\r
416                 }\r
417 \r
418                 public void AddPolygon (PointF [] points)\r
419                 {\r
420                         if (points == null)\r
421                                 throw new ArgumentNullException("points");\r
422 \r
423                         if (points.Length < 3)\r
424                                 throw new ArgumentException("Invalid parameter used.");\r
425 \r
426                         NativeObject.moveTo(points[0].X,points[0].Y);\r
427                         for (int i = 1; i < points.Length; i++)\r
428                         {\r
429                                 NativeObject.lineTo(points[i].X,points[i].Y);\r
430                         }\r
431                         NativeObject.closePath();\r
432                 }\r
433                 #endregion\r
434 \r
435                 #region AddRectangle(s)\r
436                 internal void AddRectangle(float x,float y, float w, float h)\r
437                 {\r
438                         NativeObject.moveTo(x, y);\r
439                         NativeObject.lineTo (x + w, y);\r
440                         NativeObject.lineTo (x + w, y + h);\r
441                         NativeObject.lineTo (x, y + h);\r
442                         NativeObject.closePath ();\r
443                 }\r
444                 public void AddRectangle (RectangleF rect)\r
445                 {\r
446                         AddRectangle(rect.X,rect.Y,rect.Width,rect.Height);\r
447                 }\r
448 \r
449                 public void AddRectangle (Rectangle rect)\r
450                 {\r
451                         AddRectangle(rect.X,rect.Y,rect.Width,rect.Height);\r
452                 }\r
453 \r
454                 public void AddRectangles (Rectangle [] rects)\r
455                 {\r
456                         foreach(Rectangle rect in rects)\r
457                                 AddRectangle(rect.X,rect.Y,rect.Width,rect.Height);\r
458                 }\r
459 \r
460                 public void AddRectangles (RectangleF [] rects)\r
461                 {\r
462                         foreach(RectangleF rect in rects)\r
463                                 AddRectangle(rect.X,rect.Y,rect.Width,rect.Height);\r
464                 }\r
465                 #endregion\r
466 \r
467                 #region AddPath\r
468                 public void AddPath (GraphicsPath addingPath, bool connect)\r
469                 {\r
470                         if (NativeObject.LastFigureClosed || addingPath.NativeObject.LastFigureClosed)\r
471                                 connect = false;\r
472 \r
473                         NativeObject.append(addingPath.NativeObject,connect);\r
474                 }\r
475                 #endregion\r
476 \r
477                 #region GetLastPoint\r
478                 public PointF GetLastPoint ()\r
479                 {\r
480                         return NativeObject.GetLastPoint ();\r
481                 }\r
482                 #endregion\r
483 \r
484                 #region Reset\r
485                 public void Reset ()\r
486                 {\r
487                         NativeObject.reset();\r
488                 }\r
489                 #endregion\r
490 \r
491                 #region GetBounds\r
492                 public RectangleF GetBounds ()\r
493                 {\r
494                         return GetBounds (null, null);\r
495                 }               \r
496 \r
497                 public RectangleF GetBounds (Matrix matrix)\r
498                 {\r
499                         return GetBounds (matrix, null);\r
500                 }\r
501 \r
502                 public RectangleF GetBounds (Matrix matrix, Pen pen)\r
503                 {\r
504                         // FIXME : we do not know exacly how the bounding rectangle \r
505                         // is calculated so this implementation obtains different bounds\r
506                         // that still contains the path widened by oen and transformed by matrix\r
507                         // the order of operations is similar to widening, as .Net does.\r
508 \r
509                         // first get original shape bounds\r
510                         //Shape shape = NativeObject.getBounds2D();\r
511                         Shape shape = NativeObject;\r
512 \r
513                         // stroke bounds\r
514                         if (pen != null)\r
515                                 shape = ((Stroke)pen).createStrokedShape (shape);\r
516 \r
517                         Rectangle2D rect = shape.getBounds2D ();\r
518 \r
519                         // transform bounds                     \r
520                         if (matrix != null)\r
521                                 rect = matrix.NativeObject.createTransformedShape(rect).getBounds2D();\r
522 \r
523                         return new RectangleF (rect);\r
524                 }\r
525                 #endregion\r
526         \r
527                 #region Transform\r
528                 public void Transform (Matrix matrix)\r
529                 {\r
530                         if(matrix == null)\r
531                                 return;\r
532 \r
533                         NativeObject.transform(matrix.NativeObject);\r
534                 }\r
535                 #endregion\r
536 \r
537                 #region IsVisible\r
538                 public bool IsVisible (Point point)\r
539                 {\r
540                         return IsVisible (point.X, point.Y, null);\r
541                 }               \r
542                 \r
543                 public bool IsVisible (PointF point)\r
544                 {\r
545                         return IsVisible (point.X, point.Y, null);\r
546                 }               \r
547                 \r
548                 public bool IsVisible (int x, int y)\r
549                 {\r
550                         return IsVisible (x, y, null);\r
551                 }\r
552 \r
553                 public bool IsVisible (float x, float y)\r
554                 {\r
555                         return IsVisible (x, y, null);\r
556                 }                               \r
557                 \r
558                 public bool IsVisible (Point pt, Graphics graphics)\r
559                 {\r
560                         return IsVisible (pt.X, pt.Y, graphics);\r
561                 }               \r
562                 \r
563                 public bool IsVisible (PointF pt, Graphics graphics)\r
564                 {\r
565                         return IsVisible (pt.X, pt.Y, graphics);\r
566                 }               \r
567                                 \r
568                 public bool IsVisible (int x, int y, Graphics graphics)\r
569                 {\r
570                         return IsVisible((float)x,(float)y,null);\r
571                 }               \r
572                 \r
573                 public bool IsVisible (float x, float y, Graphics graphics)\r
574                 {\r
575                         // LAMESPEC : .Net is currently ignorig Graphics object\r
576                         //if (graphics != null && !graphics.IsVisible(x,y))\r
577                         //      return false;\r
578 \r
579                         return NativeObject.contains(x,y);\r
580                 }\r
581                 #endregion\r
582         \r
583                 #region Reverse\r
584                 public void Reverse ()\r
585                 {\r
586                         NativeObject.Reverse ();\r
587                 }\r
588                 #endregion\r
589              \r
590                 #region AddClosedCurve\r
591                 public void AddClosedCurve (Point [] points)\r
592                 {\r
593                         AddClosedCurve(points, 0.5f);\r
594                 }\r
595 \r
596                 public void AddClosedCurve (PointF [] points)\r
597                 {\r
598                         AddClosedCurve(points, 0.5f);\r
599                 }\r
600 \r
601                 public void AddClosedCurve (Point [] points, float tension)\r
602                 {\r
603                         if (points == null)\r
604                                 throw new ArgumentNullException("points");\r
605 \r
606                         if (points.Length < 3)\r
607                                 throw new ArgumentException("Invalid parameter used.");\r
608 \r
609                         int length = (points.Length + 3)*2;\r
610 \r
611                         float[] pts = new float[length];\r
612                         pts[--length] = points[1].Y;\r
613                         pts[--length] = points[1].X;\r
614                         pts[--length] = points[0].Y;\r
615                         pts[--length] = points[0].X;\r
616 \r
617                         for (int i = points.Length-1; i >= 0; i--) {\r
618                                 pts[--length] = points[i].Y;\r
619                                 pts[--length] = points[i].X;\r
620                         }\r
621 \r
622                         pts[--length] = points[points.Length-1].Y;\r
623                         pts[--length] = points[points.Length-1].X;\r
624 \r
625                         AddCurve(pts, !NativeObject.LastFigureClosed, tension);\r
626                         CloseFigure ();\r
627                 }\r
628 \r
629                 public void AddClosedCurve (PointF [] points, float tension)\r
630                 {\r
631                         if (points == null)\r
632                                 throw new ArgumentNullException("points");\r
633 \r
634                         if (points.Length < 3)\r
635                                 throw new ArgumentException("Invalid parameter used.");\r
636 \r
637                         int length = (points.Length + 3)*2;\r
638 \r
639                         float[] pts = new float[length];\r
640                         pts[--length] = points[1].Y;\r
641                         pts[--length] = points[1].X;\r
642                         pts[--length] = points[0].Y;\r
643                         pts[--length] = points[0].X;\r
644 \r
645                         for (int i = points.Length-1; i >= 0; i--) {\r
646                                 pts[--length] = points[i].Y;\r
647                                 pts[--length] = points[i].X;\r
648                         }\r
649 \r
650                         pts[--length] = points[points.Length-1].Y;\r
651                         pts[--length] = points[points.Length-1].X;\r
652 \r
653                         AddCurve(pts, !NativeObject.LastFigureClosed, tension);\r
654                         CloseFigure ();\r
655                 }\r
656                 #endregion\r
657 \r
658                 #region AddCurve\r
659                 //we have now two approaches for drawing cardinal curves\r
660                 //the first one is to convert cardinals into approximate beziers\r
661                 //the second one - to draw curve ourself with all interpolation staff\r
662                 //here. I preffer the first one because we could utilize java antialiasing and\r
663                 //flattening features, otherwise curves will be more strict but less cool\r
664                 public void AddCurve (Point [] points)\r
665                 {\r
666                         AddCurve(points,0.5F);\r
667                 }\r
668                 \r
669                 public void AddCurve (PointF [] points)\r
670                 {\r
671                         AddCurve(points,0.5f);\r
672                 }\r
673                 \r
674                 public void AddCurve (Point [] points, float tension)\r
675                 {\r
676                         AddCurve(points, 0, points.Length-1, tension);\r
677                 }\r
678                 \r
679                 public void AddCurve (PointF [] points, float tension)\r
680                 {\r
681                         AddCurve(points, 0, points.Length-1, tension);\r
682                 }\r
683 \r
684                 public void AddCurve (Point [] points, int offset, int numberOfSegments, float tension)\r
685                 {\r
686                         int nPoints = numberOfSegments + 1;\r
687                         int length = nPoints*2 + 4;\r
688                         float[] pts = new float[length];\r
689 \r
690                         int lastP = offset + nPoints;\r
691                         if (lastP == points.Length) {\r
692                                 lastP--;\r
693                                 pts[--length] = points[lastP].Y;\r
694                                 pts[--length] = points[lastP].X;\r
695                         }\r
696 \r
697                         for (; length > 0 && lastP >= 0; lastP--) {\r
698                                 pts[--length] = points[lastP].Y;\r
699                                 pts[--length] = points[lastP].X;\r
700                         }\r
701 \r
702                         if (length > 0) {\r
703                                 pts[1] = points[0].Y;\r
704                                 pts[0] = points[0].X;\r
705                         }\r
706 \r
707                         AddCurve(pts, !NativeObject.LastFigureClosed, tension);\r
708                 }\r
709                 \r
710                 public void AddCurve (PointF [] points, int offset, int numberOfSegments, float tension)\r
711                 {\r
712                         int nPoints = numberOfSegments + 1;\r
713                         int length = nPoints*2 + 4;\r
714                         float[] pts = new float[length];\r
715 \r
716                         int lastP = offset + nPoints;\r
717                         if (lastP == points.Length) {\r
718                                 lastP--;\r
719                                 pts[--length] = points[lastP].Y;\r
720                                 pts[--length] = points[lastP].X;\r
721                         }\r
722 \r
723                         for (; length > 0 && lastP >= 0; lastP--) {\r
724                                 pts[--length] = points[lastP].Y;\r
725                                 pts[--length] = points[lastP].X;\r
726                         }\r
727 \r
728                         if (length > 0) {\r
729                                 pts[1] = points[0].Y;\r
730                                 pts[0] = points[0].X;\r
731                         }\r
732 \r
733                         AddCurve(pts, !NativeObject.LastFigureClosed, tension);\r
734                 }\r
735 \r
736                 /// <summary>\r
737                 /// Based on http://pubpages.unh.edu/~cs770/a5/cardinal.html\r
738                 /// </summary>\r
739                 /// <param name="pts">point array (x1,y1,x2,y2 ...).\r
740                 /// The first and last points considered only for calculations, but are not added.</param>\r
741                 void AddCurve(float[] pts, bool connect, float tension) {\r
742                         tension /= 3f; //looks like a good pick\r
743 \r
744                         if (connect)\r
745                                 NativeObject.lineTo(pts[2],pts[3]);\r
746                         else\r
747                                 NativeObject.moveTo(pts[2],pts[3]);\r
748 \r
749                         float dx = pts[4] - pts[0];\r
750                         float dy = pts[5] - pts[1];\r
751 \r
752                         float sx = pts[2] + tension*dx;\r
753                         float sy = pts[3] + tension*dy;\r
754 \r
755                         for (int offset = 2, total = pts.Length-4; offset < total; offset += 2) {\r
756                                 int cur_offset = offset;\r
757                                 int pX = cur_offset++;\r
758                                 int pY = cur_offset++;\r
759                                 int X = cur_offset++;\r
760                                 int Y = cur_offset++;\r
761                                 int nX = cur_offset++;\r
762                                 int nY = cur_offset++;\r
763 \r
764                                 dx = pts[nX] - pts[pX];\r
765                                 dy = pts[nY] - pts[pY];\r
766 \r
767                                 float rx = pts[X] - tension*dx;\r
768                                 float ry = pts[Y] - tension*dy;\r
769                                 \r
770                                 NativeObject.curveTo(sx, sy, rx, ry, pts[X], pts[Y]);\r
771 \r
772                                 sx = pts[X] + tension*dx;\r
773                                 sy = pts[Y] + tension*dy;\r
774                         }\r
775                 }\r
776                 #endregion\r
777 \r
778                 #region AddString\r
779                 public void AddString (string s, FontFamily family, int style,  float emSize,  Point origin,   StringFormat format)\r
780                 {\r
781                         AddString(s, new Font(family, emSize, (FontStyle)style, GraphicsUnit.World), origin.X, origin.Y, float.PositiveInfinity, float.PositiveInfinity,\r
782                                 format);\r
783                 }       \r
784                 \r
785                 public void AddString (string s,  FontFamily family,  int style,  float emSize,  PointF origin,   StringFormat format)\r
786                 {\r
787                         AddString(s, new Font(family, emSize, (FontStyle)style, GraphicsUnit.World), origin.X, origin.Y, float.PositiveInfinity, float.PositiveInfinity,\r
788                                 format);\r
789                 }       \r
790                 \r
791                 public void AddString (string s, FontFamily family, int style, float emSize,  Rectangle layoutRect, StringFormat format)\r
792                 {\r
793                         AddString(s, new Font(family, emSize, (FontStyle)style, GraphicsUnit.World),\r
794                                 layoutRect.X, layoutRect.Y, layoutRect.Width, layoutRect.Height,\r
795                                 format);\r
796                 }       \r
797                 \r
798                 public void AddString (string s, FontFamily family, int style, float emSize,  RectangleF layoutRect,   StringFormat format)\r
799                 {\r
800                         AddString(s, new Font(family, emSize, (FontStyle)style, GraphicsUnit.World),\r
801                                 layoutRect.X, layoutRect.Y, layoutRect.Width, layoutRect.Height,\r
802                                 format);\r
803                 }\r
804 \r
805                 void AddString (string s, Font font,\r
806                         float x, float y, float width, float height, \r
807                         StringFormat format) {\r
808 \r
809                         TextLineIterator iter = new TextLineIterator(s, font,\r
810                                 new java.awt.font.FontRenderContext(null, false, false),\r
811                                 format, width, height);\r
812 \r
813                         int coordsCount = NativeObject.CoordsCount;\r
814 \r
815                         for (LineLayout layout = iter.NextLine(); layout != null; layout = iter.NextLine()) {\r
816                                 NativeObject.append(layout.GetOutline(x, y), false);\r
817                         }\r
818 \r
819                         AffineTransform lineAlignT = iter.CalcLineAlignmentTransform();\r
820                         if (lineAlignT != null)\r
821                                 NativeObject.transform(lineAlignT, coordsCount, NativeObject.CoordsCount - coordsCount);\r
822                 }\r
823                 #endregion\r
824                 \r
825                 #region ClearMarkers\r
826                 public void ClearMarkers()               \r
827                 {\r
828                         NativeObject.ClearMarkers ();\r
829                 }\r
830                 #endregion\r
831         \r
832                 #region Close\r
833                 public void CloseAllFigures()\r
834                 {\r
835                         ExtendedGeneralPath p = new ExtendedGeneralPath();\r
836                         PathIterator pi = NativeObject.getPathIterator(null);\r
837                         JPI lastSeg = JPI.SEG_CLOSE;\r
838                         float [] points = new float[6];\r
839  \r
840                         p.setWindingRule(pi.getWindingRule());\r
841                         while(!pi.isDone())\r
842                         {\r
843                                 JPI curSeg = (JPI)pi.currentSegment(points);\r
844                                 switch(curSeg)\r
845                                 {\r
846                                         case JPI.SEG_CLOSE:\r
847                                                 p.closePath();\r
848                                                 break;\r
849                                         case JPI.SEG_MOVETO:\r
850                                                 if(lastSeg != JPI.SEG_CLOSE)\r
851                                                         p.closePath();\r
852                                                 p.moveTo(points[0],points[1]);\r
853                                                 break;\r
854                                         case JPI.SEG_LINETO:\r
855                                                 p.lineTo(points[0],points[1]);\r
856                                                 break;\r
857                                         case JPI.SEG_QUADTO:\r
858                                                 p.quadTo(points[0],points[1],points[2],points[3]);\r
859                                                 break;\r
860                                         case JPI.SEG_CUBICTO:\r
861                                                 p.curveTo(points[0],points[1],points[2],points[3],points[4],points[5]);\r
862                                                 break;\r
863                                         default:\r
864                                                 break;\r
865                                 }                               \r
866                                 lastSeg = curSeg;\r
867                                 pi.next();\r
868                         }\r
869 \r
870                         p.closePath();\r
871                         Shape = p;\r
872                 }       \r
873                 \r
874                 public void CloseFigure() {\r
875                         if (!NativeObject.LastFigureClosed)\r
876                                 NativeObject.closePath();\r
877                 }\r
878                 #endregion\r
879 \r
880                 #region Flatten\r
881                 public void Flatten ()\r
882                 {\r
883                         // 1/4 is the FlatnessDefault as defined in GdiPlusEnums.h\r
884                         Flatten (null, 1.0f / 4.0f); \r
885                 }       \r
886   \r
887                 public void Flatten (Matrix matrix)\r
888                 {\r
889                         Flatten (matrix, 1.0f / 4.0f);\r
890                 }\r
891                 \r
892                 public void Flatten (Matrix matrix, float flatness)\r
893                 {\r
894                         AffineTransform tr = null;\r
895                         if(matrix != null)                      \r
896                                 tr = matrix.NativeObject;\r
897 \r
898                         //FIXME : Review (perfomance reasons).\r
899                         PathIterator pi = NativeObject.getPathIterator(tr,flatness);\r
900                         ExtendedGeneralPath newPath = new ExtendedGeneralPath();\r
901                         newPath.append(pi,false);\r
902                         Shape = newPath;\r
903                 }\r
904                 #endregion\r
905         \r
906                 #region GetOutlineVisible\r
907                 public bool IsOutlineVisible (Point point, Pen pen)\r
908                 {\r
909                         return IsOutlineVisible (point.X, point.Y, pen, null);\r
910                 }               \r
911                 \r
912                 public bool IsOutlineVisible (PointF point, Pen pen)\r
913                 {\r
914                         return IsOutlineVisible (point.X, point.Y, pen, null);\r
915                 } \r
916                 \r
917                 public bool IsOutlineVisible (int x, int y, Pen pen)\r
918                 {\r
919                         return IsOutlineVisible (x, y, pen, null);\r
920                 }\r
921 \r
922                 public bool IsOutlineVisible (float x, float y, Pen pen)\r
923                 {\r
924                         return IsOutlineVisible (x, y, pen, null);\r
925                 }               \r
926                 \r
927                 public bool IsOutlineVisible (Point pt, Pen pen, Graphics graphics)\r
928                 {\r
929                         return IsOutlineVisible (pt.X, pt.Y, pen, graphics);\r
930                 }               \r
931                 \r
932                 public bool IsOutlineVisible (PointF pt, Pen pen, Graphics graphics)\r
933                 {\r
934                         return IsOutlineVisible (pt.X, pt.Y, pen, graphics);\r
935                 }               \r
936                                 \r
937                 public bool IsOutlineVisible (int x, int y, Pen pen, Graphics graphics)\r
938                 {\r
939                         // LAMESPEC : .Net is currently ignorig Graphics object\r
940                         //if (graphics != null) {\r
941                         //      if (!graphics.IsVisible (x, y))\r
942                         //              return false;                           \r
943                         //}\r
944 \r
945                         return ((Stroke)pen).createStrokedShape (NativeObject).contains (x, y);\r
946                 }               \r
947                                 \r
948                 public bool IsOutlineVisible (float x, float y, Pen pen, Graphics graphics)\r
949                 {\r
950                         return ((Stroke)pen).createStrokedShape (NativeObject).contains (x, y);\r
951                 }               \r
952                 #endregion\r
953         \r
954                 #region SetMarkers \r
955                 public void SetMarkers ()\r
956                 {\r
957                         NativeObject.SetMarkers ();\r
958                 }\r
959                 #endregion\r
960                 \r
961                 #region StartFigure\r
962                 public void StartFigure()\r
963                 {\r
964                         NativeObject.StartFigure ();\r
965                 }\r
966                 #endregion\r
967                         \r
968                 #region Warp\r
969                 [MonoTODO]\r
970                 public void Warp (PointF[] destPoints, RectangleF srcRect)\r
971                 {\r
972                         Warp (destPoints, srcRect, null, WarpMode.Perspective, 1.0f / 4.0f);\r
973                 }               \r
974 \r
975                 [MonoTODO]\r
976                 public void Warp (PointF[] destPoints, RectangleF srcRect, Matrix matrix)\r
977                 {\r
978                         Warp (destPoints, srcRect, matrix, WarpMode.Perspective, 1.0f / 4.0f);\r
979                 }               \r
980 \r
981                 [MonoTODO]\r
982                 public void Warp (PointF[] destPoints, RectangleF srcRect, Matrix matrix, WarpMode warpMode)\r
983                 {\r
984                         Warp (destPoints, srcRect, matrix, warpMode, 1.0f / 4.0f);\r
985                 }               \r
986 \r
987                 [MonoTODO]\r
988                 public void Warp (PointF[] destPoints, RectangleF srcRect, Matrix matrix,  WarpMode warpMode, float flatness)\r
989                 {\r
990                         throw new NotImplementedException();\r
991                 }\r
992                 #endregion\r
993         \r
994                 #region Widen\r
995                 public void Widen (Pen pen)\r
996                 {\r
997                         Widen (pen, null);\r
998                 }               \r
999                 \r
1000                 public void Widen (Pen pen, Matrix matrix)\r
1001                 {       \r
1002                         Widen (pen, matrix, 2f/3f);\r
1003                 }               \r
1004                                 \r
1005                 public void Widen (Pen pen, Matrix matrix, float flatness)\r
1006                 {\r
1007                         if (pen == null)\r
1008                                 throw new ArgumentNullException("pen");\r
1009 \r
1010                         Shape = new ExtendedGeneralPath(((Stroke)pen).createStrokedShape(this));\r
1011                         Flatten(matrix, flatness);\r
1012                 } \r
1013                 #endregion\r
1014 \r
1015                 private void SetPath (Point [] pts, byte [] types)\r
1016                 {\r
1017                         NativeObject.Clear ();\r
1018                         if (((PathPointType)types [0] & PathPointType.PathTypeMask) != PathPointType.Start)\r
1019                                 NativeObject.moveTo (pts [0].X, pts [0].Y);\r
1020 \r
1021                         for (int i=0; i < pts.Length; i++) {\r
1022                                 switch (((PathPointType)types [i] & PathPointType.PathTypeMask)) {\r
1023                                         case PathPointType.Start :\r
1024                                                 NativeObject.moveTo (pts [i].X, pts [i].Y);\r
1025                                                 break;\r
1026                                         case PathPointType.Line :\r
1027                                                 NativeObject.lineTo (pts [i].X, pts [i].Y);\r
1028                                                 break;\r
1029                                         case PathPointType.Bezier3 :\r
1030                                                 float x1 = pts [i].X;\r
1031                                                 float y1 = pts [i].Y;\r
1032                                                 i++;\r
1033                                                 float x2 = pts [i].X;\r
1034                                                 float y2 = pts [i].Y;\r
1035                                                 i++;\r
1036                                                 float x3 = pts [i].X;\r
1037                                                 float y3 = pts [i].Y;\r
1038                                                 NativeObject.curveTo (x1,y1, x2, y2, x3, y3);\r
1039                                                 break;                                          \r
1040                                 }\r
1041                                 if (((PathPointType)types [i] & PathPointType.CloseSubpath) != 0)\r
1042                                         NativeObject.closePath();\r
1043 \r
1044                                 if (((PathPointType)types [i] & PathPointType.PathMarker) != 0)\r
1045                                         NativeObject.SetMarkers ();\r
1046                         }\r
1047                 }\r
1048 \r
1049                 internal void SetPath (PointF [] pts, byte [] types)\r
1050                 {\r
1051                         NativeObject.Clear ();\r
1052                         if (((PathPointType)types [0] & PathPointType.PathTypeMask) != PathPointType.Start)\r
1053                                 NativeObject.moveTo (pts [0].X, pts [0].Y);\r
1054                         for (int i=0; i < pts.Length; i++) {\r
1055                                 switch (((PathPointType)types [i] & PathPointType.PathTypeMask)) {\r
1056                                         case PathPointType.Start :\r
1057                                                 NativeObject.moveTo (pts [i].X, pts [i].Y);\r
1058                                                 break;\r
1059                                         case PathPointType.Line :\r
1060                                                 NativeObject.lineTo (pts [i].X, pts [i].Y);\r
1061                                                 break;\r
1062                                         case PathPointType.Bezier3 :\r
1063                                                 float x1 = pts [i].X;\r
1064                                                 float y1 = pts [i].Y;\r
1065                                                 i++;\r
1066                                                 float x2 = pts [i].X;\r
1067                                                 float y2 = pts [i].Y;\r
1068                                                 i++;\r
1069                                                 float x3 = pts [i].X;\r
1070                                                 float y3 = pts [i].Y;\r
1071                                                 NativeObject.curveTo (x1,y1, x2, y2, x3, y3);\r
1072                                                 break;                                          \r
1073                                 }\r
1074                                 if (((PathPointType)types [i] & PathPointType.CloseSubpath) != 0)\r
1075                                         NativeObject.closePath();\r
1076 \r
1077                                 if (((PathPointType)types [i] & PathPointType.PathMarker) != 0)\r
1078                                         NativeObject.SetMarkers ();\r
1079                         }\r
1080                 }\r
1081         }\r
1082 }\r