using PropertyTools.DataAnnotations; using System; using System.Collections.Generic; using System.Reflection; namespace VisionCommon { public class PointTypeMismatchException : Exception { public PointTypeMismatchException(DoublePoint p1, DoublePoint p2) : base(CreateMessage(p1, p2)) { } private static string CreateMessage(DoublePoint p1, DoublePoint p2) { return string.Format( "Point Type mismatch : p1({0}), p2({1})", p1.GetType().ToString(), p2.GetType().ToString()); } } public abstract class DoublePoint { protected string _StringFormat; protected string _StringSpecifier; [Converter(typeof(CoordUnitValueConverter))] public double X { get; set; } = default(double); [Converter(typeof(CoordUnitValueConverter))] public double Y { get; set; } = default(double); public DoublePoint() : this(0, 0) { } public DoublePoint(double x, double y) { X = x; Y = y; SetToStringFormat(); } public DoublePoint(DoublePoint p) : this(p.X, p.Y) { } protected abstract void SetToStringFormat(); public DoublePoint Clone() { return Create(this); } private static DoublePoint Create(Type type, double x, double y) { ConstructorInfo ctor = type.GetConstructor( new[] { typeof(double), typeof(double) }); return (DoublePoint)ctor.Invoke(new object[] { x, y }); } private static DoublePoint Create(DoublePoint p) { Type type = p.GetType(); ConstructorInfo ctor = type.GetConstructor( new[] { typeof(DoublePoint) }); return (DoublePoint)ctor.Invoke(new object[] { p }); } public static DoublePoint operator +(DoublePoint p) { return Create(p); } public static DoublePoint operator +(DoublePoint p1, DoublePoint p2) { if (p1.GetType() != p2.GetType()) { throw new PointTypeMismatchException(p1, p2); } return Create( p1.GetType(), p1.X + p2.X, p1.Y + p2.Y); } public static DoublePoint operator -(DoublePoint p) { return Create( p.GetType(), -p.X, -p.Y); } public static DoublePoint operator -(DoublePoint p1, DoublePoint p2) { if (p1.GetType() != p2.GetType()) { throw new PointTypeMismatchException(p1, p2); } return Create( p1.GetType(), p1.X - p2.X, p1.Y - p2.Y); } public static DoublePoint operator *(DoublePoint p, double s) { return Create( p.GetType(), p.X * s, p.Y * s); } public static DoublePoint operator /(DoublePoint p, double s) { return Create( p.GetType(), p.X / s, p.Y / s); } public static bool operator ==(DoublePoint p1, DoublePoint p2) { if (p1.GetType() != p2.GetType()) { return false; } return (MathUtil.Equals(p1.X, p2.X) && MathUtil.Equals(p1.Y, p2.Y)); } public static bool operator !=(DoublePoint p1, DoublePoint p2) { if (p1.GetType() != p2.GetType()) { return true; } return ((!MathUtil.Equals(p1.X, p2.X)) || (!MathUtil.Equals(p1.Y, p2.Y))); } public static DoublePoint GetCentroid(DoublePoint p1, DoublePoint p2) { return Create( p1.GetType(), (p1.X + p2.X) * 0.5, (p1.Y + p2.Y) * 0.5); } public static DoublePoint GetCentroid(List points) { for (int i = 1; i < points.Count; i++) { if (points[0].GetType() != points[i].GetType()) { throw new PointTypeMismatchException(points[0], points[i]); } } double centroidX = 0; double centroidY = 0; foreach (var p in points) { centroidX += p.X; centroidY += p.Y; } return Create( points[0].GetType(), centroidX / points.Count, centroidY / points.Count); } public static DoublePoint Transform(DoublePoint p1, TransformScaleTranslation transform) { return Create( p1.GetType(), (p1.X * transform.ScaleX) + transform.TranslationX, (p1.Y * transform.ScaleY) + transform.TranslationY); } public override bool Equals(object p) { DoublePoint dp = p as DoublePoint; if (this.GetType() != dp.GetType()) { return false; } return (MathUtil.Equals(this.X, dp.X) && MathUtil.Equals(this.Y, dp.Y)); } public override int GetHashCode() { return base.GetHashCode(); } public override string ToString() { return String.Format(_StringFormat, X.ToString(_StringSpecifier), Y.ToString(_StringSpecifier)); } } public class ImagePoint : DoublePoint { // I(X.12, Y.12) private const string STRING_FORMAT = "I({0}, {1})"; private const string STRING_SPECIFIER = "F2"; public ImagePoint() : base() { } public ImagePoint(double x, double y) : base(x, y) { } public ImagePoint(DoublePoint p) : this(p.X, p.Y) { } protected override void SetToStringFormat() { base._StringFormat = STRING_FORMAT; base._StringSpecifier = STRING_SPECIFIER; } } public class StaticPoint : DoublePoint { // S(X.1234, Y.1234) private const string STRING_FORMAT = "S({0}, {1})"; private const string STRING_SPECIFIER = "F4"; public StaticPoint() : base() { } public StaticPoint(double x, double y) : base(x, y) { } public StaticPoint(DoublePoint p) : this(p.X, p.Y) { } protected override void SetToStringFormat() { base._StringFormat = STRING_FORMAT; base._StringSpecifier = STRING_SPECIFIER; } } public class MotionPoint : DoublePoint { // M(X.1234, Y.1234) private const string STRING_FORMAT = "M({0}, {1})"; private const string STRING_SPECIFIER = "F4"; public MotionPoint() : base() { } public MotionPoint(double x, double y) : base(x, y) { } public MotionPoint(DoublePoint p) : this(p.X, p.Y) { } protected override void SetToStringFormat() { base._StringFormat = STRING_FORMAT; base._StringSpecifier = STRING_SPECIFIER; } } }