namespace VisualMath.Accord.Imaging { using System.Drawing; /// /// Represents an ordered pair of real x- and y-coordinates and scalar w that defines /// a point in a two-dimensional plane using homogeneous coordinates. /// /// /// /// /// In mathematics, homogeneous coordinates are a system of coordinates used in /// projective geometry much as Cartesian coordinates are used in Euclidean geometry. /// /// They have the advantage that the coordinates of a point, even those at infinity, /// can be represented using finite coordinates. Often formulas involving homogeneous /// coordinates are simpler and more symmetric than their Cartesian counterparts. /// /// Homogeneous coordinates have a range of applications, including computer graphics, /// where they allow affine transformations and, in general, projective transformations /// to be easily represented by a matrix. /// /// /// References: /// /// /// http://alumnus.caltech.edu/~woody/docs/3dmatrix.html /// /// http://simply3d.wordpress.com/2009/05/29/homogeneous-coordinates/ /// /// /// public struct PointH { private float px, py, pw; /// /// The first coordinate. /// public float X { get { return px; } set { px = value; } } /// /// The second coordinate. /// public float Y { get { return py; } set { py = value; } } /// /// The inverse scaling factor for X and Y. /// public float W { get { return pw; } set { pw = value; } } /// /// Creates a new point. /// public PointH(float x, float y) { px = x; py = y; pw = 1; } /// /// Creates a new point. /// public PointH(float x, float y, float w) { px = x; py = y; pw = w; } /// /// Transforms a point using a projection matrix. /// public void Transform(float[,] matrix) { px = matrix[0, 0] * px + matrix[0, 1] * py + matrix[0, 2] * pw; py = matrix[1, 0] * px + matrix[1, 1] * py + matrix[1, 2] * pw; pw = matrix[2, 0] * px + matrix[2, 1] * py + matrix[2, 2] * pw; } /// /// Normalizes the point to have unit scale. /// public void Normalize() { px = px / pw; py = py / pw; pw = 1; } /// /// Gets whether this point is normalized (w = 1). /// public bool IsNormalized { get { return pw == 1f; } } /// /// Gets whether this point is at infinity (w = 0). /// public bool IsAtInfinity { get { return pw == 0f; } } /// /// Gets whether this point is at the origin. /// public bool IsEmpty { get { return px == 0 && py == 0; } } /// /// Converts the point to a array representation. /// public double[] ToArray() { return new double[] { px, py, pw }; } /// /// Multiplication by scalar. /// public static PointH operator *(PointH a, float b) { return new PointH(b * a.X, b * a.Y, b * a.W); } /// /// Multiplication by scalar. /// public static PointH operator *(float b, PointH a) { return a * b; } /// /// Subtraction. /// public static PointH operator -(PointH a, PointH b) { return new PointH(a.X - b.X, a.Y - b.Y, a.W - b.W); } /// /// Addition. /// public static PointH operator +(PointH a, PointH b) { return new PointH(a.X + b.X, a.Y + b.Y, a.W + b.W); } /// /// Equality /// public static bool operator ==(PointH a, PointH b) { return (a.px / a.pw == b.px / b.pw && a.py / a.pw == b.py / b.pw); } /// /// Inequality /// public static bool operator !=(PointH a, PointH b) { return (a.px / a.pw != b.px / b.pw || a.py / a.pw != b.py / b.pw); } /// /// PointF Conversion /// public static implicit operator PointF(PointH a) { return new PointF((float)(a.px / a.pw), (float)(a.py / a.pw)); } /// /// Converts to a Integer point by computing the ceiling of the point coordinates. /// public static Point Ceiling(PointH point) { return new Point( (int)System.Math.Ceiling(point.px / point.pw), (int)System.Math.Ceiling(point.py / point.pw)); } /// /// Converts to a Integer point by rounding the point coordinates. /// public static Point Round(PointH point) { return new Point( (int)System.Math.Round(point.px / point.pw), (int)System.Math.Round(point.py / point.pw)); } /// /// Converts to a Integer point by truncating the point coordinates. /// public static Point Truncate(PointH point) { return new Point( (int)System.Math.Truncate(point.px / point.pw), (int)System.Math.Truncate(point.py / point.pw)); } /// /// Compares two objects for equality. /// public override bool Equals(object obj) { if (obj is PointH) { PointH p = (PointH)obj; if (px / pw == p.px / p.pw && py / pw == p.py / p.pw) return true; } return false; } /// /// Returns the hash code for this instance. /// public override int GetHashCode() { return px.GetHashCode() ^ py.GetHashCode() ^ pw.GetHashCode(); } /// /// Returns the empty point. /// public static readonly PointH Empty = new PointH(0, 0, 1); } }