+//
+// System.Drawing.Drawing2D.ExtendedGeneralPath.cs
+//
+// Author:
+// Bors Kirzner <boris@mainsoft.com>
+//
+// Copyright (C) 2005 Mainsoft Corporation, (http://www.mainsoft.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//\r
+\r
using System;\r
\r
using java.awt;\r
private int _coordsCount;\r
private int _windingRule;\r
\r
+ private PathData _pathData;\r
+ private GeneralPath _generalPath;\r
+\r
const int INIT_SIZE = 20;\r
const int EXPAND_MAX = 500;\r
\r
private ExtendedGeneralPath(int rule, int initialTypes, int initialCoords) \r
{\r
setWindingRule(rule);\r
- _types = new sbyte [initialTypes];\r
- _coords = new float [initialCoords * 2];\r
+ Reset (initialTypes, initialCoords);\r
}\r
\r
#endregion // Constructors\r
private GeneralPath GeneralPath\r
{\r
get {\r
- PathIterator iter = getPathIterator (null);\r
- GeneralPath path = new GeneralPath ();\r
- path.append (iter, false);\r
- return path;\r
+ if (_generalPath == null) { \r
+ _generalPath = GetGeneralPath ();\r
+ }\r
+ return _generalPath;\r
}\r
}\r
\r
}\r
}\r
\r
+ public int PointCount\r
+ {\r
+ get {\r
+ return CoordsCount / 2;\r
+ }\r
+ }\r
\r
+ public PathData PathData \r
+ {\r
+ get \r
+ {\r
+ if (_pathData == null)\r
+ _pathData = GetPathData ();\r
+ \r
+ return _pathData;\r
+ }\r
+ }\r
\r
#endregion // Properties\r
\r
#region Methods\r
\r
+ #region CachedData\r
+\r
+ private void ClearCache ()\r
+ {\r
+ _pathData = null;\r
+ _generalPath = null;\r
+ }\r
+\r
+ private GeneralPath GetGeneralPath ()\r
+ {\r
+ PathIterator iter = getPathIterator (null);\r
+ GeneralPath path = new GeneralPath ();\r
+ path.append (iter, false);\r
+ return path;\r
+ }\r
+\r
+ private PathData GetPathData ()\r
+ {\r
+ PathData pathData = new PathData();\r
+ pathData.Types = new byte [PointCount];\r
+ pathData.Points = new PointF [PointCount];\r
+ int tpos = 0;\r
+ int ppos = 0;\r
+ int cpos = 0;\r
+ byte marker;\r
+ bool start;\r
+ for (int i = 0; i < TypesCount; i++) {\r
+ sbyte segmentType = (sbyte)(Types [i] & SEG_MASK);\r
+\r
+ // set the masks and the markers\r
+ marker = ((Types [i] & SEG_MARKER) != 0) ? (byte)PathPointType.PathMarker : (byte)0;\r
+ start = ((Types [i] & SEG_START) != 0);\r
+ \r
+ switch (segmentType) {\r
+ case SEG_CLOSE:\r
+ pathData.InternalTypes [tpos - 1] = (byte) (pathData.InternalTypes [tpos - 1] | (byte) PathPointType.CloseSubpath | marker);\r
+ break;\r
+ case SEG_MOVETO:\r
+ pathData.InternalTypes [tpos++] = (byte)((byte) PathPointType.Start | marker);\r
+ pathData.InternalPoints [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);\r
+ break;\r
+ case SEG_LINETO:\r
+ pathData.InternalTypes [tpos++] = (byte) ((byte) PathPointType.Line | marker);\r
+ pathData.InternalPoints [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);\r
+ break;\r
+ case SEG_QUADTO:\r
+ // FIXME : use 4 cp , two of which \r
+ pathData.InternalTypes [tpos++] = (byte)(byte) PathPointType.Bezier;\r
+ pathData.InternalPoints [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);\r
+ pathData.InternalTypes [tpos++] = (byte) ((byte)PathPointType.Bezier | marker);\r
+ pathData.InternalPoints [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);\r
+ break;\r
+ case SEG_CUBICTO:\r
+ pathData.InternalTypes [tpos++] = (byte)(byte) PathPointType.Bezier3;\r
+ pathData.InternalPoints [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);\r
+ pathData.InternalTypes [tpos++] = (byte) PathPointType.Bezier3;\r
+ pathData.InternalPoints [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);\r
+ pathData.InternalTypes [tpos++] = (byte) ((byte)PathPointType.Bezier3 | marker);\r
+ pathData.InternalPoints [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);\r
+ break;\r
+ }\r
+ }\r
+ return pathData;\r
+ }\r
+\r
+ #endregion // CachedData\r
+\r
public void append(Shape s)\r
{\r
append (s, !LastFigureClosed);\r
\r
public void append(PathIterator pi, bool connect) \r
{\r
+ ClearCache ();\r
float [] coords = new float [6];\r
while (!pi.isDone ()) {\r
switch (pi.currentSegment (coords)) {\r
\r
public object Clone() \r
{\r
- ExtendedGeneralPath copy = new ExtendedGeneralPath ();\r
+ ExtendedGeneralPath copy = (ExtendedGeneralPath)MemberwiseClone ();\r
copy._types = (sbyte []) _types.Clone ();\r
copy._coords = (float []) _coords.Clone ();\r
return copy;\r
\r
public void closePath() \r
{\r
+ ClearCache ();\r
if (_typesCount == 0 || _types[_typesCount - 1] != SEG_CLOSE) {\r
needRoom (1, 0, true);\r
_types [_typesCount++] = SEG_CLOSE;\r
\r
public void curveTo(float x1, float y1, float x2, float y2, float x3, float y3) \r
{\r
+ ClearCache ();\r
needRoom (1, 6, true);\r
_types [_typesCount++] = SEG_CUBICTO;\r
_coords [_coordsCount++] = x1;\r
\r
public void lineTo(float x, float y) \r
{\r
+ ClearCache ();\r
needRoom (1, 2, true);\r
_types [_typesCount++] = SEG_LINETO;\r
_coords [_coordsCount++] = x;\r
\r
public void moveTo(float x, float y) \r
{\r
+ ClearCache ();\r
if (_typesCount > 0 && _types [_typesCount - 1] == SEG_MOVETO) {\r
_coords [_coordsCount - 2] = x;\r
_coords [_coordsCount - 1] = y;\r
\r
public void quadTo(float x1, float y1, float x2, float y2) \r
{\r
+ ClearCache ();\r
needRoom (1, 4, true);\r
_types [_typesCount++] = SEG_QUADTO;\r
_coords [_coordsCount++] = x1;\r
\r
public void reset() \r
{\r
+ ClearCache ();\r
_typesCount = 0;\r
_coordsCount = 0;\r
}\r
\r
public void transform(AffineTransform at) \r
{\r
+ ClearCache ();\r
at.transform (_coords, 0, _coords, 0, _coordsCount/2);\r
}\r
\r
\r
public void SetMarkers()\r
{\r
- Types [ TypesCount - 1] |= SEG_MARKER;\r
+ ClearCache ();\r
+ if (TypesCount > 0)\r
+ Types [ TypesCount - 1] |= SEG_MARKER;\r
}\r
\r
public void ClearMarkers()\r
{\r
+ ClearCache ();\r
for (int i = 0; i < TypesCount; i++)\r
Types [i] &= ~SEG_MARKER;\r
}\r
\r
+ public void StartFigure ()\r
+ {\r
+ ClearCache ();\r
+ if (TypesCount > 0)\r
+ Types [TypesCount - 1] |= ExtendedGeneralPath.SEG_START;\r
+ }\r
+\r
+ private void Reset (int initialTypes, int initialCoords)\r
+ {\r
+ ClearCache ();\r
+ _types = new sbyte [initialTypes];\r
+ _coords = new float [initialCoords * 2];\r
+ _typesCount = 0;\r
+ _coordsCount = 0;\r
+ }\r
+\r
+ internal void Clear ()\r
+ {\r
+ Reset (INIT_SIZE, INIT_SIZE);\r
+ }\r
+\r
+ internal void Reverse ()\r
+ {\r
+ ClearCache ();\r
+ // revert coordinates\r
+ for (int i=0, max = CoordsCount / 2; i < max;) {\r
+ int ix = i++;\r
+ int iy = i++;\r
+ int rix = CoordsCount - i;\r
+ int riy = rix + 1;\r
+ float tmpx = Coords [ix];\r
+ float tmpy = Coords [iy];\r
+ Coords [ix] = Coords [rix];\r
+ Coords [iy] = Coords [riy];\r
+ Coords [rix] = tmpx;\r
+ Coords [riy] = tmpy;\r
+ }\r
+\r
+ // revert types\r
+ sbyte [] newTypes = new sbyte [TypesCount];\r
+ int oldIdx = 0;\r
+ int newIdx = TypesCount - 1;\r
+ int copyStart;\r
+ int copyEnd;\r
+ sbyte mask1 = 0;\r
+ sbyte mask2 = 0;\r
+ sbyte closeMask = 0;\r
+ bool closedFigure = false;\r
+ \r
+ while (oldIdx < TypesCount) {\r
+ // start copying after moveto\r
+ copyStart = ++oldIdx;\r
+ // continue to the next figure start\r
+ while ((Types [oldIdx] != SEG_MOVETO) && (oldIdx < TypesCount))\r
+ oldIdx++;\r
+\r
+ copyEnd = oldIdx - 1;\r
+ // check whenever current figure is closed\r
+ if ((Types [oldIdx - 1] & SEG_CLOSE) != 0) {\r
+ closedFigure = true;\r
+ // close figure\r
+ newTypes [newIdx--] = (sbyte)(SEG_CLOSE | mask1);\r
+ mask1 = 0;\r
+ mask2 = 0;\r
+ // end copy one cell earlier\r
+ copyEnd--;\r
+ closeMask = (sbyte)(Types [oldIdx - 1] & (sbyte)SEG_MARKER);\r
+ }\r
+ else {\r
+ mask2 = mask1;\r
+ mask1 = 0;\r
+ }\r
+\r
+ // copy reverted "inner" types\r
+ for(int i = copyStart; i <= copyEnd; i++) {\r
+ newTypes [newIdx--] = (sbyte)((Types [i] & SEG_MASK) | mask2);\r
+ mask2 = mask1;\r
+ mask1 = (sbyte)(Types [i] & (sbyte)SEG_MARKER);\r
+ }\r
+\r
+ // copy moveto\r
+ newTypes [newIdx--] = SEG_MOVETO;\r
+\r
+ // pass close mask to the nex figure\r
+ if (closedFigure) {\r
+ mask1 = closeMask;\r
+ closedFigure = false;\r
+ }\r
+ }\r
+\r
+ _types = newTypes;\r
+ }\r
+\r
+ public PointF GetLastPoint ()\r
+ {\r
+ if (CoordsCount == 0)\r
+ throw new System.ArgumentException ("Invalid parameter used.");\r
+\r
+ return new PointF (Coords [CoordsCount - 2], Coords [CoordsCount - 1]);\r
+ }\r
+\r
#endregion //Methods\r
\r
+ #region Private helpers\r
+\r
+#if DEBUG\r
+ private void Print()\r
+ {\r
+ Console.WriteLine ("\n\n");\r
+ float [] fpoints = _coords;\r
+ int cpos = 0;\r
+ for (int i=0; i < _typesCount; i++) {\r
+ sbyte type = _types [i];\r
+ string marker = String.Empty;\r
+ if ((type & SEG_MARKER) != 0)\r
+ marker = " | MARKER";\r
+\r
+ switch (type & SEG_MASK) {\r
+ case SEG_CLOSE:\r
+ Console.WriteLine ("CLOSE {0}",marker);\r
+ break;\r
+ case SEG_MOVETO:\r
+ Console.WriteLine("{0}{3} ({1},{2})","MOVETO", fpoints[cpos++], fpoints[cpos++], marker);\r
+ break;\r
+ case SEG_LINETO:\r
+ Console.WriteLine("{0}{3} ({1},{2})","LINETO", fpoints[cpos++], fpoints[cpos++], marker);\r
+ break;\r
+ case SEG_QUADTO:\r
+ Console.WriteLine("{0}{3} ({1},{2})","QUADTO", fpoints[cpos++], fpoints[cpos++], marker);\r
+ Console.WriteLine(" ({1},{2})","QUADTO", fpoints[cpos++], fpoints[cpos++]);\r
+ break;\r
+ case SEG_CUBICTO:\r
+ Console.WriteLine("{0}{3} ({1},{2})","CUBICTO", fpoints[cpos++], fpoints[cpos++], marker);\r
+ Console.WriteLine(" ({1},{2})","CUBICTO", fpoints[cpos++], fpoints[cpos++]);\r
+ Console.WriteLine(" ({1},{2})","CUBICTO", fpoints[cpos++], fpoints[cpos++]);\r
+ break;\r
+ }\r
+ }\r
+ }\r
+#endif\r
+ #endregion // Private helpers\r
\r
}\r
}\r