// From http://www.developingfor.net/free-code/polygonf using System; using System.Drawing; using System.Collections.Generic; using System.Text; namespace SWallTech.Drawing.Shapes { /// <summary> /// A Class representing a Polygon formed by an array of PointF objects. /// PolygonF objects are immutable. /// </summary> public class PolygonF { private PointF[] _pts; private float _minx = 0; private float _miny = 0; private float _maxx = 0; private float _maxy = 0; private float _xlength = 0; private float _ylength = 0; private PolygonF() { } /// <summary> /// Creates a new instance of a PolygonF based on the PointF[]. /// </summary> /// <param name="pts">The array of PointF used to create the PolygonF.</param> public PolygonF(PointF[] pts) { Points = pts; } private PointF[] Points { get { return _pts; } set { _pts = value; _minx = _pts[0].X; _maxx = _pts[0].X; _miny = _pts[0].Y; _maxy = _pts[0].Y; foreach (PointF pt in _pts) { if (pt.X < _minx) { _minx = pt.X; } if (pt.X > _maxx) { _maxx = pt.X; } if (pt.Y < _miny) { _miny = pt.Y; } if (pt.Y > _maxy) { _maxy = pt.Y; } } _xlength = Math.Abs(_maxx - _minx); _ylength = Math.Abs(_maxy - _miny); } } /// <summary> /// The Rectangular Bounds of the Polygon. /// </summary> public RectangleF Bounds { get { return new RectangleF(_minx, _miny, _maxx - _minx, _maxy - _miny); } } /// <summary> /// The Minimum X coordinate value in the PointF collection. /// </summary> public float MinimumX { get { return _minx; } } /// <summary> /// The Maximum X coordinate value in the PointF collection. /// </summary> public float MaximumX { get { return _maxx; } } /// <summary> /// The Minimum Y coordinate value in the PointF collection. /// </summary> public float MinimumY { get { return _miny; } } /// <summary> /// The Maximum Y coordinate value in the PointF collection. /// </summary> public float MaximumY { get { return _maxy; } } /// <summary> /// The number of Points in the Polygon. /// </summary> public int NumberOfPoints { get { return _pts.Length; } } /// <summary> /// Compares the supplied point and determines whether or not it is inside the Rectangular Bounds /// of the Polygon. /// </summary> /// <param name="pt">The PointF to compare.</param> /// <returns>True if the PointF is within the Rectangular Bounds, False if it is not.</returns> public bool IsInBounds(PointF pt) { return Bounds.Contains(pt); } /// <summary> /// Compares the supplied point and determines whether or not it is inside the Actual Bounds /// of the Polygon. /// </summary> /// <remarks>The calculation formula was converted from the C version available at /// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html /// </remarks> /// <param name="pt">The PointF to compare.</param> /// <returns>True if the PointF is within the Actual Bounds, False if it is not.</returns> public bool Contains(PointF pt) { bool isIn = false; if (IsInBounds(pt)) { int i, j = 0; // The following code is converted from a C version found at // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html for (i = 0, j = NumberOfPoints - 1; i < NumberOfPoints; j = i++) { if ( ( ((_pts[i].Y <= pt.Y) && (pt.Y < _pts[j].Y)) || ((_pts[j].Y <= pt.Y) && (pt.Y < _pts[i].Y)) ) && (pt.X < (_pts[j].X - _pts[i].X) * (pt.Y - _pts[i].Y) / (_pts[j].Y - _pts[i].Y) + _pts[i].X) ) { isIn = !isIn; } } } return isIn; } /// <summary> /// Returns the PointF that represents the center of the Rectangular Bounds of the Polygon. /// </summary> public PointF CenterPointOfBounds { get { float x = _minx + (_xlength / 2); float y = _miny + (_ylength / 2); return new PointF(x, y); } } /// <summary> /// NOT YET IMPLEMENTED. Currently returns the same as CenterPointOfBounds. /// This is intended to be the Visual Center of the Polygon, and will be implemented /// once I can figure out how to calculate that Point. /// </summary> public PointF CenterPoint { get { PointF pt = CenterPointOfBounds; return pt; } } /// <summary> /// Calculates the Area of the Polygon. /// </summary> public decimal Area { get { decimal xy = 0M; for (int i = 0; i < _pts.Length; i++) { PointF pt1; PointF pt2; if (i == _pts.Length - 1) { pt1 = _pts[i]; pt2 = _pts[0]; } else { pt1 = _pts[i]; pt2 = _pts[i + 1]; } xy += Convert.ToDecimal(pt1.X * pt2.Y); xy -= Convert.ToDecimal(pt1.Y * pt2.X); } decimal area = Convert.ToDecimal(Math.Abs(xy)) * .5M; return area; } } } /// <summary> /// A Class representing a Polygon formed by an array of Point objects. /// Polygon objects are immutable. /// </summary> public class Polygon { private Point[] _pts; private int _minx = 0; private int _miny = 0; private int _maxx = 0; private int _maxy = 0; private int _xlength = 0; private int _ylength = 0; private Polygon() { } /// <summary> /// Creates a new instance of a Polygon based on the Point[]. /// </summary> /// <param name="pts">The array of Point used to create the Polygon.</param> public Polygon(Point[] pts) { Points = pts; } private Point[] Points { get { return _pts; } set { _pts = value; _minx = _pts[0].X; _maxx = _pts[0].X; _miny = _pts[0].Y; _maxy = _pts[0].Y; foreach (Point pt in _pts) { if (pt.X < _minx) { _minx = pt.X; } if (pt.X > _maxx) { _maxx = pt.X; } if (pt.Y < _miny) { _miny = pt.Y; } if (pt.Y > _maxy) { _maxy = pt.Y; } } _xlength = Math.Abs(_maxx - _minx); _ylength = Math.Abs(_maxy - _miny); } } /// <summary> /// The Rectangular Bounds of the Polygon. /// </summary> public Rectangle Bounds { get { return new Rectangle(_minx, _miny, _maxx - _minx, _maxy - _miny); } } /// <summary> /// The Minimum X coordinate value in the PointF collection. /// </summary> public int MinimumX { get { return _minx; } } /// <summary> /// The Maximum X coordinate value in the PointF collection. /// </summary> public int MaximumX { get { return _maxx; } } /// <summary> /// The Minimum Y coordinate value in the PointF collection. /// </summary> public int MinimumY { get { return _miny; } } /// <summary> /// The Maximum Y coordinate value in the PointF collection. /// </summary> public int MaximumY { get { return _maxy; } } /// <summary> /// The number of Points in the Polygon. /// </summary> public int NumberOfPoints { get { return _pts.Length; } } /// <summary> /// Compares the supplied point and determines whether or not it is inside the Rectangular Bounds /// of the Polygon. /// </summary> /// <param name="pt">The PointF to compare.</param> /// <returns>True if the PointF is within the Rectangular Bounds, False if it is not.</returns> public bool IsInBounds(Point pt) { return Bounds.Contains(pt); } /// <summary> /// Compares the supplied point and determines whether or not it is inside the Actual Bounds /// of the Polygon. /// </summary> /// <remarks>The calculation formula was converted from the C version available at /// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html /// </remarks> /// <param name="pt">The PointF to compare.</param> /// <returns>True if the PointF is within the Actual Bounds, False if it is not.</returns> public bool Contains(Point pt) { bool isIn = false; if (IsInBounds(pt)) { int i, j = 0; // The following code is converted from a C version found at // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html for (i = 0, j = NumberOfPoints - 1; i < NumberOfPoints; j = i++) { if ( ( ((_pts[i].Y <= pt.Y) && (pt.Y < _pts[j].Y)) || ((_pts[j].Y <= pt.Y) && (pt.Y < _pts[i].Y)) ) && (pt.X < (_pts[j].X - _pts[i].X) * (pt.Y - _pts[i].Y) / (_pts[j].Y - _pts[i].Y) + _pts[i].X) ) { isIn = !isIn; } } } return isIn; } /// <summary> /// Returns the PointF that represents the center of the Rectangular Bounds of the Polygon. /// </summary> public Point CenterPointOfBounds { get { int x = _minx + (_xlength / 2); int y = _miny + (_ylength / 2); return new Point(x, y); } } /// <summary> /// NOT YET IMPLEMENTED. Currently returns the same as CenterPointOfBounds. /// This is intended to be the Visual Center of the Polygon, and will be implemented /// once I can figure out how to calculate that Point. /// </summary> public Point CenterPoint { get { Point pt = CenterPointOfBounds; return pt; } } /// <summary> /// Calculates the Area of the Polygon. /// </summary> public decimal Area { get { decimal xy = 0M; for (int i = 0; i < _pts.Length; i++) { Point pt1; Point pt2; if (i == _pts.Length - 1) { pt1 = _pts[i]; pt2 = _pts[0]; } else { pt1 = _pts[i]; pt2 = _pts[i + 1]; } xy += Convert.ToDecimal(pt1.X * pt2.Y); xy -= Convert.ToDecimal(pt1.Y * pt2.X); } decimal area = Convert.ToDecimal(Math.Abs(xy)) * .5M; return area; } } } }