| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700 |
- //
- // System.Drawing.Drawing2D.ExtendedGeneralPath.cs
- //
- // Author:
- // Bors Kirzner <[email protected]>
- //
- // 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.Types [tpos - 1] = (byte) (pathData.Types [tpos - 1] | (byte) PathPointType.CloseSubpath | marker);
- break;
- case SEG_MOVETO:
- pathData.Types [tpos++] = (byte)((byte) PathPointType.Start | marker);
- pathData.Points [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);
- break;
- case SEG_LINETO:
- pathData.Types [tpos++] = (byte) ((byte) PathPointType.Line | marker);
- pathData.Points [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.Types [tpos++] = (byte)(byte) PathPointType.Bezier;
- pathData.Points [ppos++] = new PointF (x1, y1);
- pathData.Types [tpos++] = (byte)(byte) PathPointType.Bezier;
- pathData.Points [ppos++] = new PointF (x2, y2);
- pathData.Types [tpos++] = (byte) ((byte)PathPointType.Bezier | marker);
- pathData.Points [ppos++] = new PointF (x3, y3);
- break;
- case SEG_CUBICTO:
- pathData.Types [tpos++] = (byte)(byte) PathPointType.Bezier3;
- pathData.Points [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);
- pathData.Types [tpos++] = (byte) PathPointType.Bezier3;
- pathData.Points [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);
- pathData.Types [tpos++] = (byte) ((byte)PathPointType.Bezier3 | marker);
- pathData.Points [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
-
- }
- }
|