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);
}
}