using System; using System.Collections; using System.Drawing; using System.Drawing.Drawing2D; using System.Globalization; using System.Runtime.Serialization; using System.Windows.Forms; namespace CraftSynth.ImageEditor { /// /// Polygon graphic object /// //[Serializable] public class DrawPolygon : DrawLine { private ArrayList pointArray; // list of points private Cursor handleCursor; private const string entryLength = "Length"; private const string entryPoint = "Point"; private bool _disposed; public DrawPolygon() { pointArray = new ArrayList(); LoadCursor(); Initialize(); } #region Destruction protected override void Dispose(bool disposing) { if (!this._disposed) { if (disposing) { // Free any managed objects here. if (this.handleCursor != null) { this.handleCursor.Dispose(); } this._disposed = true; } // Free any unmanaged objects here. this._disposed = true; } base.Dispose(disposing); } ~DrawPolygon() { this.Dispose(false); } #endregion public DrawPolygon(int x1, int y1, int x2, int y2, Color lineColor, int lineWidth, DrawingPens.PenType penType, LineCap endCap) { pointArray = new ArrayList(); pointArray.Add(new Point(x1, y1)); pointArray.Add(new Point(x2, y2)); Color = lineColor; PenWidth = lineWidth; PenType = penType; EndCap = endCap; LoadCursor(); Initialize(); } /// /// Clone this instance /// public override DrawObject Clone() { DrawPolygon drawPolygon = new DrawPolygon(); foreach (Point p in pointArray) { drawPolygon.pointArray.Add(p); } FillDrawObjectFields(drawPolygon); return drawPolygon; } public override void Draw(Graphics g) { g.SmoothingMode = SmoothingMode.AntiAlias; Pen pen; if (DrawPen == null) { pen = new Pen(Color, PenWidth); DrawingPens.SetCurrentPen(ref pen, PenType, EndCap); } else pen = DrawPen.Clone() as Pen; // Convert the array of points to a GraphicsPath object so lines are mitered correctly at the intersections // (not to mention the object is drawn faster then drawing individual lines) Point[] pts = new Point[pointArray.Count]; for (int i = 0; i < pointArray.Count; i++) { Point px = (Point)pointArray[i]; pts[i] = px; } byte[] types = new byte[pointArray.Count]; for (int i = 0; i < pointArray.Count; i++) types[i] = (byte)PathPointType.Line; GraphicsPath gp = new GraphicsPath(pts, types); // Rotate the path about it's center if necessary if (Rotation != 0) { RectangleF pathBounds = gp.GetBounds(); Matrix m = new Matrix(); m.RotateAt(Rotation, new PointF(pathBounds.Left + (pathBounds.Width / 2), pathBounds.Top + (pathBounds.Height / 2)), MatrixOrder.Append); gp.Transform(m); } g.DrawPath(pen, gp); //g.DrawCurve(pen, pts); // //// For DrawBeziers() to work, the pts array must have a minimum of 4 points. //// The pts array may have more than 4 points, but if so, then after the first 4 points, remaining points must be in sets of 3 for the call to work. //// The following code will adjust the pts array to properly fit these requirements. //int numPoints = pts.Length; //if (numPoints - 4 <= 0) //{ // // Cannot call DrawBeziers() so return, drawing nothing. // gp.Dispose(); // pen.Dispose(); // return; //} //while ((numPoints - 4) % 3 != 0 && numPoints - 4 > 0) //{ // // Chop off the last point from the pts array // numPoints--; // Array.Resize(ref pts, numPoints); //} //g.DrawBeziers(pen, pts); gp.Dispose(); if (pen != null) pen.Dispose(); } public void AddPoint(Point point) { pointArray.Add(point); } public override int HandleCount { get { return pointArray.Count; } } /// /// Get handle point by 1-based number /// /// /// public override Point GetHandle(int handleNumber) { if (handleNumber < 1) handleNumber = 1; if (handleNumber > pointArray.Count) handleNumber = pointArray.Count; return ((Point)pointArray[handleNumber - 1]); } public override Cursor GetHandleCursor(int handleNumber) { return handleCursor; } public override void MoveHandleTo(Point point, int handleNumber) { if (handleNumber < 1) handleNumber = 1; if (handleNumber > pointArray.Count) handleNumber = pointArray.Count; pointArray[handleNumber - 1] = point; Dirty = true; Invalidate(); } public override void Move(int deltaX, int deltaY) { int n = pointArray.Count; for (int i = 0; i < n; i++) { Point point; point = new Point(((Point)pointArray[i]).X + deltaX, ((Point)pointArray[i]).Y + deltaY); pointArray[i] = point; } Dirty = true; Invalidate(); } public override void SaveToStream(SerializationInfo info, int orderNumber, int objectIndex) { info.AddValue( String.Format(CultureInfo.InvariantCulture, "{0}{1}-{2}", entryLength, orderNumber, objectIndex), pointArray.Count); int i = 0; foreach (Point p in pointArray) { info.AddValue( String.Format(CultureInfo.InvariantCulture, "{0}{1}-{2}-{3}", new object[] {entryPoint, orderNumber, objectIndex, i++}), p); } base.SaveToStream(info, orderNumber, objectIndex); } public override void LoadFromStream(SerializationInfo info, int orderNumber, int objectIndex) { int n = info.GetInt32( String.Format(CultureInfo.InvariantCulture, "{0}{1}-{2}", entryLength, orderNumber, objectIndex)); for (int i = 0; i < n; i++) { Point point; point = (Point)info.GetValue( String.Format(CultureInfo.InvariantCulture, "{0}{1}-{2}-{3}", new object[] {entryPoint, orderNumber, objectIndex, i}), typeof (Point)); pointArray.Add(point); } base.LoadFromStream(info, orderNumber, objectIndex); } /// /// Create graphic object used for hit test /// protected override void CreateObjects() { if (AreaPath != null) return; // Create closed path which contains all polygon vertexes AreaPath = new GraphicsPath(); int x1 = 0, y1 = 0; // previous point IEnumerator enumerator = pointArray.GetEnumerator(); if (enumerator.MoveNext()) { x1 = ((Point)enumerator.Current).X; y1 = ((Point)enumerator.Current).Y; } while (enumerator.MoveNext()) { int x2, y2; // current point x2 = ((Point)enumerator.Current).X; y2 = ((Point)enumerator.Current).Y; AreaPath.AddLine(x1, y1, x2, y2); x1 = x2; y1 = y2; } AreaPath.CloseFigure(); // Create region from the path AreaRegion = new Region(AreaPath); } private void LoadCursor() { handleCursor = new Cursor(GetType(), "PolyHandle.cur"); } } }