diff options
Diffstat (limited to 'mcs/class/System.Drawing/System.Drawing.Drawing2D/ExtendedGeneralPath.jvm.cs')
-rw-r--r-- | mcs/class/System.Drawing/System.Drawing.Drawing2D/ExtendedGeneralPath.jvm.cs | 700 |
1 files changed, 700 insertions, 0 deletions
diff --git a/mcs/class/System.Drawing/System.Drawing.Drawing2D/ExtendedGeneralPath.jvm.cs b/mcs/class/System.Drawing/System.Drawing.Drawing2D/ExtendedGeneralPath.jvm.cs new file mode 100644 index 00000000000..7c9c9d81363 --- /dev/null +++ b/mcs/class/System.Drawing/System.Drawing.Drawing2D/ExtendedGeneralPath.jvm.cs @@ -0,0 +1,700 @@ +// +// 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. +//
+
+using System;
+
+using java.awt;
+using java.awt.geom;
+using java.lang;
+
+namespace System.Drawing.Drawing2D
+{
+ internal class ExtendedGeneralPath : Shape, ICloneable
+ {
+ #region Fields
+
+ public const int WIND_EVEN_ODD = 0; //PathIterator__Finals.WIND_EVEN_ODD;
+ public const int WIND_NON_ZERO = 1; //PathIterator__Finals.WIND_NON_ZERO;
+
+ public const sbyte SEG_MOVETO = 0; //(byte) PathIterator__Finals.SEG_MOVETO;
+ public const sbyte SEG_LINETO = 1; //(byte) PathIterator__Finals.SEG_LINETO;
+ public const sbyte SEG_QUADTO = 2; //(byte) PathIterator__Finals.SEG_QUADTO;
+ public const sbyte SEG_CUBICTO = 3; //(byte) PathIterator__Finals.SEG_CUBICTO;
+ public const sbyte SEG_CLOSE = 4; //(byte) PathIterator__Finals.SEG_CLOSE;
+
+ public const sbyte SEG_START = 16; // segment start
+
+ public const sbyte SEG_MASK = SEG_MOVETO | SEG_LINETO | SEG_QUADTO | SEG_CUBICTO | SEG_CLOSE; // mask to eliminate SEG_CLOSE and SEG_MARKER
+
+ private const sbyte SEG_MARKER = 32; // path marker
+
+
+ private sbyte [] _types;
+ private float [] _coords;
+ private int _typesCount;
+ private int _coordsCount;
+ private int _windingRule;
+
+ private PathData _pathData;
+ private GeneralPath _generalPath;
+
+ const int INIT_SIZE = 20;
+ const int EXPAND_MAX = 500;
+
+ #endregion // Fileds
+
+ #region Constructors
+
+ public ExtendedGeneralPath() : this (WIND_NON_ZERO, INIT_SIZE, INIT_SIZE)
+ {
+ }
+
+ public ExtendedGeneralPath(int rule) : this (rule, INIT_SIZE, INIT_SIZE)
+ {
+ }
+
+ public ExtendedGeneralPath(int rule, int initialCapacity) : this (rule, initialCapacity, initialCapacity)
+ {
+ }
+
+ public ExtendedGeneralPath(Shape s) : this(WIND_NON_ZERO, INIT_SIZE, INIT_SIZE)
+ {
+ PathIterator pi = s.getPathIterator (null);
+ setWindingRule (pi.getWindingRule ());
+ append (pi, false);
+ }
+
+ private ExtendedGeneralPath(int rule, int initialTypes, int initialCoords)
+ {
+ setWindingRule(rule);
+ Reset (initialTypes, initialCoords);
+ }
+
+ #endregion // Constructors
+
+ #region Properties
+
+ private GeneralPath GeneralPath
+ {
+ get {
+ if (_generalPath == null) {
+ _generalPath = GetGeneralPath ();
+ }
+ return _generalPath;
+ }
+ }
+
+ public sbyte [] Types
+ {
+ get { return _types; }
+ }
+
+ public float [] Coords
+ {
+ get { return _coords; }
+ }
+
+ public int TypesCount
+ {
+ get { return _typesCount; }
+ }
+
+ public int CoordsCount
+ {
+ get { return _coordsCount; }
+ }
+
+ public bool LastFigureClosed
+ {
+ get {
+ return ((TypesCount == 0) ||
+ ((Types [TypesCount - 1] & ExtendedGeneralPath.SEG_CLOSE) != 0) ||
+ ((Types [TypesCount - 1] & ExtendedGeneralPath.SEG_START) != 0));
+ }
+ }
+
+ public int PointCount
+ {
+ get {
+ return CoordsCount / 2;
+ }
+ }
+
+ public PathData PathData
+ {
+ get
+ {
+ if (_pathData == null)
+ _pathData = GetPathData ();
+
+ return _pathData;
+ }
+ }
+
+ #endregion // Properties
+
+ #region Methods
+
+ #region CachedData
+
+ private void ClearCache ()
+ {
+ _pathData = null;
+ _generalPath = null;
+ }
+
+ private GeneralPath GetGeneralPath ()
+ {
+ PathIterator iter = getPathIterator (null);
+ GeneralPath path = new GeneralPath ();
+ path.append (iter, false);
+ return path;
+ }
+
+ private PathData GetPathData ()
+ {
+ PathData pathData = new PathData();
+ int nPts = PointCount;
+ for (int i = 0; i < TypesCount; i++)
+ if ((Types [i] & SEG_MASK) == SEG_QUADTO)
+ nPts++;
+
+ pathData.Types = new byte [nPts];
+ pathData.Points = new PointF [nPts];
+ int tpos = 0;
+ int ppos = 0;
+ int cpos = 0;
+ byte marker;
+ bool start;
+ for (int i = 0; i < TypesCount; i++) {
+ sbyte segmentType = (sbyte)(Types [i] & SEG_MASK);
+
+ // set the masks and the markers
+ marker = ((Types [i] & SEG_MARKER) != 0) ? (byte)PathPointType.PathMarker : (byte)0;
+ start = ((Types [i] & SEG_START) != 0);
+
+ switch (segmentType) {
+ case SEG_CLOSE:
+ pathData.InternalTypes [tpos - 1] = (byte) (pathData.InternalTypes [tpos - 1] | (byte) PathPointType.CloseSubpath | marker);
+ break;
+ case SEG_MOVETO:
+ pathData.InternalTypes [tpos++] = (byte)((byte) PathPointType.Start | marker);
+ pathData.InternalPoints [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);
+ break;
+ case SEG_LINETO:
+ pathData.InternalTypes [tpos++] = (byte) ((byte) PathPointType.Line | marker);
+ pathData.InternalPoints [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);
+ break;
+ case SEG_QUADTO:
+ /*
+ .net does not support Quadratic curves, so convert to Cubic according to http://pfaedit.sourceforge.net/bezier.html
+
+ The end points of the cubic will be the same as the quadratic's.
+ CP0 = QP0
+ CP3 = QP2
+
+ The two control points for the cubic are:
+
+ CP1 = QP0 + 2/3 *(QP1-QP0)
+ CP2 = CP1 + 1/3 *(QP2-QP0)
+ */
+
+ float x0 = Coords[cpos-2]; //QP0
+ float y0 = Coords[cpos-1]; //QP0
+
+ float x1 = x0 + (2/3 * (Coords [cpos++]-x0));
+ float y1 = y0 + (2/3 * (Coords [cpos++]-y0));
+
+ float x3 = Coords [cpos++]; //QP2
+ float y3 = Coords [cpos++]; //QP2
+
+ float x2 = x1 + (1/3 * (x3-x0));
+ float y2 = y1 + (1/3 * (y3-y0));
+
+ pathData.InternalTypes [tpos++] = (byte)(byte) PathPointType.Bezier;
+ pathData.InternalPoints [ppos++] = new PointF (x1, y1);
+ pathData.InternalTypes [tpos++] = (byte)(byte) PathPointType.Bezier;
+ pathData.InternalPoints [ppos++] = new PointF (x2, y2);
+ pathData.InternalTypes [tpos++] = (byte) ((byte)PathPointType.Bezier | marker);
+ pathData.InternalPoints [ppos++] = new PointF (x3, y3);
+ break;
+ case SEG_CUBICTO:
+ pathData.InternalTypes [tpos++] = (byte)(byte) PathPointType.Bezier3;
+ pathData.InternalPoints [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);
+ pathData.InternalTypes [tpos++] = (byte) PathPointType.Bezier3;
+ pathData.InternalPoints [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);
+ pathData.InternalTypes [tpos++] = (byte) ((byte)PathPointType.Bezier3 | marker);
+ pathData.InternalPoints [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);
+ break;
+ }
+ }
+ return pathData;
+ }
+
+ #endregion // CachedData
+
+ public void append(Shape s)
+ {
+ append (s, !LastFigureClosed);
+ }
+
+ #region GeneralPath
+
+ public void append(PathIterator pi, bool connect)
+ {
+ ClearCache ();
+ float [] coords = new float [6];
+ while (!pi.isDone ()) {
+ switch (pi.currentSegment (coords)) {
+ case SEG_MOVETO:
+ if (!connect || _typesCount < 1 || _coordsCount < 2) {
+ moveTo (coords [0], coords [1]);
+ break;
+ }
+ if (_types [_typesCount - 1] != SEG_CLOSE &&
+ _coords [_coordsCount - 2] == coords [0] &&
+ _coords [_coordsCount - 1] == coords [1])
+ break;
+ goto case SEG_LINETO;
+ case SEG_LINETO:
+ lineTo (coords [0], coords [1]);
+ break;
+ case SEG_QUADTO:
+ quadTo (coords [0], coords [1], coords [2], coords [3]);
+ break;
+ case SEG_CUBICTO:
+ curveTo (coords [0], coords [1], coords [2], coords [3], coords [4], coords [5]);
+ break;
+ case SEG_CLOSE:
+ closePath ();
+ break;
+ }
+ pi.next ();
+ connect = false;
+ }
+ }
+
+ public void append(Shape s, bool connect)
+ {
+ PathIterator pi = s.getPathIterator (null);
+ append (pi,connect);
+ }
+
+ public object Clone()
+ {
+ ExtendedGeneralPath copy = (ExtendedGeneralPath)MemberwiseClone ();
+ copy._types = (sbyte []) _types.Clone ();
+ copy._coords = (float []) _coords.Clone ();
+ return copy;
+ }
+
+ public void closePath()
+ {
+ ClearCache ();
+ if (_typesCount == 0 || _types[_typesCount - 1] != SEG_CLOSE) {
+ needRoom (1, 0, true);
+ _types [_typesCount++] = SEG_CLOSE;
+ }
+ }
+
+ public bool contains(double x, double y)
+ {
+ return GeneralPath.contains (x, y);
+ }
+
+ public bool contains(double x, double y, double w, double h)
+ {
+ return GeneralPath.contains (x, y, w, h);
+ }
+
+ public bool contains(Point2D p)
+ {
+ return contains (p.getX (), p.getY ());
+ }
+
+ public bool contains(Rectangle2D r)
+ {
+ return contains (r.getX (), r.getY (), r.getWidth (), r.getHeight ());
+ }
+
+ public Shape createTransformedShape(AffineTransform at)
+ {
+ ExtendedGeneralPath gp = (ExtendedGeneralPath) Clone ();
+ if (at != null) {
+ gp.transform (at);
+ }
+ return gp;
+ }
+
+ public void curveTo(float x1, float y1, float x2, float y2, float x3, float y3)
+ {
+ ClearCache ();
+ needRoom (1, 6, true);
+ _types [_typesCount++] = SEG_CUBICTO;
+ _coords [_coordsCount++] = x1;
+ _coords [_coordsCount++] = y1;
+ _coords [_coordsCount++] = x2;
+ _coords [_coordsCount++] = y2;
+ _coords [_coordsCount++] = x3;
+ _coords [_coordsCount++] = y3;
+ }
+
+ public java.awt.Rectangle getBounds()
+ {
+ return getBounds2D ().getBounds ();
+ }
+
+ public Rectangle2D getBounds2D()
+ {
+ float x1, y1, x2, y2;
+ int i = _coordsCount;
+ if (i > 0) {
+ y1 = y2 = _coords [--i];
+ x1 = x2 = _coords [--i];
+ while (i > 0) {
+ float y = _coords [--i];
+ float x = _coords [--i];
+ if (x < x1) x1 = x;
+ if (y < y1) y1 = y;
+ if (x > x2) x2 = x;
+ if (y > y2) y2 = y;
+ }
+ }
+ else {
+ x1 = y1 = x2 = y2 = 0f;
+ }
+ return new Rectangle2D.Float (x1, y1, x2 - x1, y2 - y1);
+ }
+
+ public Point2D getCurrentPoint()
+ {
+ if (_typesCount < 1 || _coordsCount < 2)
+ return null;
+
+ int index = _coordsCount;
+ if (_types [_typesCount - 1] == SEG_CLOSE)
+ for (int i = _typesCount - 2; i > 0; i--) {
+ switch (_types [i]) {
+ case SEG_MOVETO:
+ //break loop;
+ goto loopend;
+ case SEG_LINETO:
+ index -= 2;
+ break;
+ case SEG_QUADTO:
+ index -= 4;
+ break;
+ case SEG_CUBICTO:
+ index -= 6;
+ break;
+ case SEG_CLOSE:
+ break;
+ }
+ }
+ loopend:
+
+ return new Point2D.Float (_coords [index - 2], _coords [index - 1]);
+ }
+
+ public PathIterator getPathIterator(AffineTransform at) {
+ return new GeneralPathIterator (this, at);
+ }
+
+ public PathIterator getPathIterator(AffineTransform at, double flatness) {
+ return new FlatteningPathIterator (getPathIterator (at), flatness);
+ }
+
+ public int getWindingRule()
+ {
+ return _windingRule;
+ }
+
+ public bool intersects(double x, double y, double w, double h)
+ {
+ return GeneralPath.intersects (x, y, w, h);
+ }
+
+ public bool intersects(Rectangle2D r)
+ {
+ return intersects (r.getX (), r.getY (), r.getWidth (), r.getHeight ());
+ }
+
+ public void lineTo(float x, float y)
+ {
+ ClearCache ();
+ needRoom (1, 2, true);
+ _types [_typesCount++] = SEG_LINETO;
+ _coords [_coordsCount++] = x;
+ _coords [_coordsCount++] = y;
+ }
+
+ public void moveTo(float x, float y)
+ {
+ ClearCache ();
+ if (_typesCount > 0 && _types [_typesCount - 1] == SEG_MOVETO) {
+ _coords [_coordsCount - 2] = x;
+ _coords [_coordsCount - 1] = y;
+ }
+ else {
+ needRoom (1, 2, false);
+ _types [_typesCount++] = SEG_MOVETO;
+ _coords [_coordsCount++] = x;
+ _coords [_coordsCount++] = y;
+ }
+ }
+
+ public void quadTo(float x1, float y1, float x2, float y2)
+ {
+ // restore quadTo as cubic affects quality
+ ClearCache ();
+ needRoom (1, 4, true);
+ _types [_typesCount++] = SEG_QUADTO;
+ _coords [_coordsCount++] = x1;
+ _coords [_coordsCount++] = y1;
+ _coords [_coordsCount++] = x2;
+ _coords [_coordsCount++] = y2;
+ }
+
+ public void reset()
+ {
+ ClearCache ();
+ _typesCount = 0;
+ _coordsCount = 0;
+ }
+
+ public void setWindingRule(int rule)
+ {
+ if (rule != WIND_EVEN_ODD && rule != WIND_NON_ZERO) {
+ throw new IllegalArgumentException ("winding rule must be WIND_EVEN_ODD or WIND_NON_ZERO");
+ }
+ _windingRule = rule;
+ }
+
+ public void transform(AffineTransform at)
+ {
+ transform(at, 0, CoordsCount);
+ }
+
+ public void transform(AffineTransform at, int startCoord, int numCoords) {
+ ClearCache ();
+ at.transform (_coords, startCoord, _coords, startCoord, numCoords/2);
+ }
+
+ private void needRoom(int newTypes, int newCoords, bool needMove)
+ {
+ if (needMove && _typesCount == 0)
+ throw new IllegalPathStateException ("missing initial moveto in path definition");
+
+ int size = _coords.Length;
+ if (_coordsCount + newCoords > size) {
+ int grow = size;
+ if (grow > EXPAND_MAX * 2)
+ grow = EXPAND_MAX * 2;
+
+ if (grow < newCoords)
+ grow = newCoords;
+
+ float [] arr = new float [size + grow];
+ Array.Copy (_coords, 0, arr, 0, _coordsCount);
+ _coords = arr;
+ }
+ size = _types.Length;
+ if (_typesCount + newTypes > size) {
+ int grow = size;
+ if (grow > EXPAND_MAX)
+ grow = EXPAND_MAX;
+
+ if (grow < newTypes)
+ grow = newTypes;
+
+ sbyte [] arr = new sbyte [size + grow];
+ Array.Copy (_types, 0, arr, 0, _typesCount);
+ _types = arr;
+ }
+ }
+
+ #endregion // GeneralPath
+
+ public void SetMarkers()
+ {
+ ClearCache ();
+ if (TypesCount > 0)
+ Types [ TypesCount - 1] |= SEG_MARKER;
+ }
+
+ public void ClearMarkers()
+ {
+ ClearCache ();
+ for (int i = 0; i < TypesCount; i++)
+ Types [i] &= ~SEG_MARKER;
+ }
+
+ public void StartFigure ()
+ {
+ ClearCache ();
+ if (TypesCount > 0)
+ Types [TypesCount - 1] |= ExtendedGeneralPath.SEG_START;
+ }
+
+ private void Reset (int initialTypes, int initialCoords)
+ {
+ ClearCache ();
+ _types = new sbyte [initialTypes];
+ _coords = new float [initialCoords * 2];
+ _typesCount = 0;
+ _coordsCount = 0;
+ }
+
+ internal void Clear ()
+ {
+ Reset (INIT_SIZE, INIT_SIZE);
+ }
+
+ internal void Reverse ()
+ {
+ ClearCache ();
+ // revert coordinates
+ for (int i=0, max = CoordsCount / 2; i < max;) {
+ int ix = i++;
+ int iy = i++;
+ int rix = CoordsCount - i;
+ int riy = rix + 1;
+ float tmpx = Coords [ix];
+ float tmpy = Coords [iy];
+ Coords [ix] = Coords [rix];
+ Coords [iy] = Coords [riy];
+ Coords [rix] = tmpx;
+ Coords [riy] = tmpy;
+ }
+
+ // revert types
+ sbyte [] newTypes = new sbyte [TypesCount];
+ int oldIdx = 0;
+ int newIdx = TypesCount - 1;
+ int copyStart;
+ int copyEnd;
+ sbyte mask1 = 0;
+ sbyte mask2 = 0;
+ sbyte closeMask = 0;
+ bool closedFigure = false;
+
+ while (oldIdx < TypesCount) {
+ // start copying after moveto
+ copyStart = ++oldIdx;
+ // continue to the next figure start
+ while ((Types [oldIdx] != SEG_MOVETO) && (oldIdx < TypesCount))
+ oldIdx++;
+
+ copyEnd = oldIdx - 1;
+ // check whenever current figure is closed
+ if ((Types [oldIdx - 1] & SEG_CLOSE) != 0) {
+ closedFigure = true;
+ // close figure
+ newTypes [newIdx--] = (sbyte)(SEG_CLOSE | mask1);
+ mask1 = 0;
+ mask2 = 0;
+ // end copy one cell earlier
+ copyEnd--;
+ closeMask = (sbyte)(Types [oldIdx - 1] & (sbyte)SEG_MARKER);
+ }
+ else {
+ mask2 = mask1;
+ mask1 = 0;
+ }
+
+ // copy reverted "inner" types
+ for(int i = copyStart; i <= copyEnd; i++) {
+ newTypes [newIdx--] = (sbyte)((Types [i] & SEG_MASK) | mask2);
+ mask2 = mask1;
+ mask1 = (sbyte)(Types [i] & (sbyte)SEG_MARKER);
+ }
+
+ // copy moveto
+ newTypes [newIdx--] = SEG_MOVETO;
+
+ // pass close mask to the nex figure
+ if (closedFigure) {
+ mask1 = closeMask;
+ closedFigure = false;
+ }
+ }
+
+ _types = newTypes;
+ }
+
+ public PointF GetLastPoint ()
+ {
+ if (CoordsCount == 0)
+ throw new System.ArgumentException ("Invalid parameter used.");
+
+ return new PointF (Coords [CoordsCount - 2], Coords [CoordsCount - 1]);
+ }
+
+ #endregion //Methods
+
+ #region Private helpers
+
+#if DEBUG
+ private void Print()
+ {
+ Console.WriteLine ("\n\n");
+ float [] fpoints = _coords;
+ int cpos = 0;
+ for (int i=0; i < _typesCount; i++) {
+ sbyte type = _types [i];
+ string marker = String.Empty;
+ if ((type & SEG_MARKER) != 0)
+ marker = " | MARKER";
+
+ switch (type & SEG_MASK) {
+ case SEG_CLOSE:
+ Console.WriteLine ("CLOSE {0}",marker);
+ break;
+ case SEG_MOVETO:
+ Console.WriteLine("{0}{3} ({1},{2})","MOVETO", fpoints[cpos++], fpoints[cpos++], marker);
+ break;
+ case SEG_LINETO:
+ Console.WriteLine("{0}{3} ({1},{2})","LINETO", fpoints[cpos++], fpoints[cpos++], marker);
+ break;
+ case SEG_QUADTO:
+ Console.WriteLine("{0}{3} ({1},{2})","QUADTO", fpoints[cpos++], fpoints[cpos++], marker);
+ Console.WriteLine(" ({1},{2})","QUADTO", fpoints[cpos++], fpoints[cpos++]);
+ break;
+ case SEG_CUBICTO:
+ Console.WriteLine("{0}{3} ({1},{2})","CUBICTO", fpoints[cpos++], fpoints[cpos++], marker);
+ Console.WriteLine(" ({1},{2})","CUBICTO", fpoints[cpos++], fpoints[cpos++]);
+ Console.WriteLine(" ({1},{2})","CUBICTO", fpoints[cpos++], fpoints[cpos++]);
+ break;
+ }
+ }
+ }
+#endif
+ #endregion // Private helpers
+
+ }
+}
|