找到坐标相交的位置

时间:2017-09-30 23:13:01

标签: c# linear-algebra intersection linear algebra

我传递的是Points[]数组,需要确定一个交叉点。在我的测试中,我找到了一个始终显示“No Intersect”的坐标集 - 我需要一种方法来解释这个问题。对于下面给定的坐标,C#中的公式/方程计算交叉点是什么?

private void button1_Click(object sender, EventArgs e)
{
    Point[] points = new Point[] { new Point { X = -1000, Y = 70 }, new Point { X = 0, Y = 78 }, new Point { X = 0, Y = 96 }, new Point { X = 1000, Y = 96 } };
    PointF returnedPoint = new PointF();
    PointF ftp = new PointF();
    ftp.X = (float)6;
    ftp.Y = (float)91.5;
    PointF lsd = new PointF();
    lsd.X = (float)0;
    lsd.Y = (float)111.285194;
    for (int i = 0; i < points.Count() - 1; i++)
    {
        if (points.Count() - 1 < 0)
        {
            MessageBox.Show(String.Format("Invalid data input"));
            return;
        }
        if (i != 0)
        {
            float X1value = points[i].X;
            float X2value = points[i - 1].X;
            float Y1value = points[i].Y;
            float Y2value = points[i - 1].Y;
            GetIntersectCoordiates(ftp, lsd, new PointF(X1value, Y1value), new PointF(X2value, Y2value), ref returnedPoint);
        }
        else { continue; }
        if (Convert.ToString(returnedPoint.X) != "0" && Convert.ToString(returnedPoint.Y) != "0")
        {
            MessageBox.Show(Convert.ToString(returnedPoint.X));
            MessageBox.Show(Convert.ToString(returnedPoint.Y));
        }
        else { MessageBox.Show("There is no intersect point with these coordinates"); }
    }
}
bool GetIntersectCoordiates(PointF p1, PointF p2, PointF q1, PointF q2, ref PointF returnedPoint)
{
    double x21 = p2.X - p1.X;
    double y21 = p2.Y - p1.Y;
    double x31 = q1.X - p1.X;
    double y31 = q1.Y - p1.Y;
    double x43 = q2.X - q1.X;
    double y43 = q2.Y - q1.Y;
    double PD = x43 * y21 - x21 * y43;
    if (PD == 0)
    {
        return false;
    }
    double s = (x43 * y31 - x31 * y43) / PD;
    double t = (x21 * y31 - x31 * y21) / PD;
    if ((s >= 0) && (s <= 1) && (t >= 0) && (t <= 1))
    {
        returnedPoint.X = (float)(p1.X + (p2.X - p1.X) * s);
        returnedPoint.Y = (float)(p1.Y + (p2.Y - p1.Y) * s);
        return true;
    }
    return false;
}

1 个答案:

答案 0 :(得分:0)

目前还不清楚你在这里要做什么。我将提供一个迷你几何库,其中Vector2类包含(x,y)类型值,Point2使用齐次坐标保持平面位置,Line2保持平面线也使用齐次坐标

Geometry静态类中定义了一些常见操作,如连接点以形成线,或相交线来形成点。

这是例如如何使用此库:

static class Program
{
    static void Main(string[] args)
    {
        // Start Program Here

        // Define three points, A, B, & C
        Point2 A = Point2.FromCoordinates(3, -1);
        Point2 B = Point2.FromCoordinates(0.8, 2);
        Point2 C = Point2.FromCoordinates(-1, 0.2);

        // Get a line between A & B
        Line2 AB = Line2.FromTwoPoints(A, B);
        // Get point on line closest to C
        Point2 D = Geometry.Closest(AB, C);
        // Check distance between C & AB equals distance between C & D
        double d_CAB = Geometry.Distance(C, AB);
        double d_CD = Geometry.Distance(C, D);
        double diff = d_CAB-d_CD;

        // Check that D is coincident to AB
        bool check_DAB = Geometry.AreNear(D, AB);

        // Get a line between C & D
        Line2 CD = Line2.FromTwoPoints(C, D);
        // Get a line @ C parallel to AB
        Line2 L = Line2.ThroughPointParallelToLine(C, AB);
        double d_CAB2 = Geometry.Distance(L, AB);
        double diff2 = d_CAB2-d_CAB;

        // Get a line @ C perpendicular to AB
        Line2 M = Line2.ThroughPointNormalToLine(C, AB);
        // Check intersection of M and AB that is actually point D
        bool check_DM = Geometry.AreNear(D, Geometry.Meet(M, AB));
    }
}

和我写的那个库(需要VS2015 +)

using static System.Math;

using PointF =  System.Drawing.PointF;
public struct Vector2 : IEquatable<Vector2>
{
    public Vector2(double x, double y) { this.X=x; this.Y=y; }
    public static readonly Vector2 Zero = new Vector2(0, 0);
    public static readonly Vector2 UnitX = new Vector2(1, 0);
    public static readonly Vector2 UnitY = new Vector2(0, 1);
    public double Magnitude => Math.Sqrt(X*X+Y*Y);
    public Vector2 Direction => Normalized();
    public double X { get; }
    public double Y { get; }
    public bool IsZero => X*X+Y*Y==0;
    public Vector2 Normalized() => Magnitude>0 ? this/Magnitude : Zero;
    public static Vector2 operator +(Vector2 a, Vector2 b)
    {
        return new Vector2(a.X+b.X, a.Y+b.Y);
    }
    public static Vector2 operator -(Vector2 a, Vector2 b)
    {
        return new Vector2(a.X-b.X, a.Y-b.Y);
    }
    public static Vector2 operator *(double f, Vector2 a)
    {
        return new Vector2(f*a.X, f*a.Y);
    }
    public static Vector2 operator *(Vector2 a, double f) { return f*a; }
    public static Vector2 operator /(Vector2 a, double d) { return (1/d)*a; }

    public override bool Equals(object obj)
    {
        if (obj is Vector2)
        {
            return Equals((Vector2)obj);
        }
        return false;
    }
    public bool Equals(Vector2 other)
    {
        return X==other.X&&Y==other.Y;
    }
    public static bool operator ==(Vector2 u, Vector2 v)
    {
        return u.Equals(v);
    }
    public static bool operator !=(Vector2 u, Vector2 v)
    {
        return !(u==v);
    }
    public override int GetHashCode()
    {
        unchecked
        {
            int hc = 17;
            hc=23*hc+X.GetHashCode();
            hc=23*hc+Y.GetHashCode();
            return hc;
        }
    }
}
public struct Point2
{
    /// <summary>
    /// Define a point by three homogeneous coordinates
    /// </summary>
    public Point2(double u, double v, double w)
    {
        this.U=u;
        this.V=v;
        this.W=w;
    }
    /// <summary>
    /// Define a point from (x,y) coordinates
    /// </summary>
    public static Point2 FromCoordinates(double x, double y)
    {
        return new Point2(x, y, 1);
    }
    /// <summary>
    /// Define a point from vector coordinates
    /// </summary>
    public static Point2 FromCoordinates(Vector2 r)
    {
        return new Point2(r.X, r.Y, 1);
    }
    /// <summary>
    /// Get point along a direction, at a certain distance
    /// </summary>
    /// <param name="n">The direction</param>
    /// <param name="d">The distance</param>
    public static Point2 FromDirectionAndDistance(Vector2 n, double d)
    {
        n=n.Direction;
        return new Point2(d*n.X, d*n.Y, 1);
    }
    /// <summary>
    /// Define a point where two lines meet (intersection)
    /// </summary>
    public static Point2 FromTwoLiness(Line2 m, Line2 n) { return Geometry.Meet(m, n); }
    /// <summary>
    /// A point at the origin
    /// </summary>
    public static readonly Point2 Origin = new Point2(0, 0, 1);
    /// <summary>
    /// A point on the unit x-axis
    /// </summary>
    public static readonly Point2 OneX = new Point2(1, 0, 1);
    /// <summary>
    /// A point on the unit y-axis
    /// </summary>
    public static readonly Point2 OneY = new Point2(0, 1, 1);
    /// <summary>
    /// First point at the horizon (infinity)
    /// </summary>
    public static readonly Point2 I = new Point2(1, 0, 0);
    /// <summary>
    /// Second point at the horizon (infinity);
    /// </summary>
    public static readonly Point2 J = new Point2(0, 1, 0);

    public double U { get; }
    public double V { get; }
    public double W { get; }
    public Point2 Normalized() => FromCoordinates(Coordinates);
    public bool IsFinite => !IsInfinite;
    public bool IsInfinite => W==0;
    /// <summary>
    /// The (x,y) coordinates of the point
    /// </summary>
    public Vector2 Coordinates => new Vector2(U/W, V/W);
    /// <summary>
    /// The center is at the point
    /// </summary>
    public Point2 Center => this;
    /// <summary>
    /// The direction is from the origin to the point
    /// </summary>
    public Vector2 Direction => new Vector2(U, V).Direction;
    /// <summary>
    /// The distance to the origin
    /// </summary>
    public double Distance => Sqrt(U*U+V*V)/Magnitude;
    /// <summary>
    /// The magnitude is weight of the point
    /// </summary>
    public double Magnitude => W;
    /// <summary>
    /// Offset a point by a vector
    /// </summary>
    /// <param name="p">The point</param>
    /// <param name="e">The offset vector</param>
    /// <returns>A new point</returns>
    public static Point2 operator +(Point2 p, Vector2 e)
    {
        return new Point2(p.U+p.W*e.X, p.V+p.W*e.Y, p.W);
    }
    /// <summary>
    /// Get the offset between two points
    /// </summary>
    public static Vector2 operator -(Point2 p, Point2 q)
    {
        return p.Coordinates-q.Coordinates;
    }
    /// <summary>
    /// Inner product between point and line. This is proportional to the distance
    /// and hence it is zero when the point is on the line.
    /// </summary>
    public static double operator *(Point2 p, Line2 m)
    {
        return m.A*p.U+m.B*p.V+m.C*p.W;
    }
    /// <summary>
    /// Defines the point joint operator (cross product) between two points
    /// </summary>
    public static Line2 operator ^(Point2 p, Point2 q) { return Geometry.Join(p, q); }
    /// <summary>
    /// Conversion between Point2 and PointF
    /// </summary>
    public static implicit operator PointF(Point2 p)
    {
        return new PointF((float)(p.U/p.W), (float)(p.V/p.W));
    }
}
public struct Line2
{
    /// <summary>
    /// Define a line by three coefficients (a,b,c) such that the 
    /// equation of the line is `a*x+b*y+c=0`
    /// </summary>
    public Line2(double a, double b, double c)
    {
        this.A=a;
        this.B=b;
        this.C=c;
    }
    /// <summary>
    /// Define a line joining two points
    /// </summary>
    public static Line2 FromTwoPoints(Point2 p, Point2 q) { return Geometry.Join(p, q); }
    /// <summary>
    /// Define a line along a directrion and through a point
    /// </summary>
    /// <param name="p">The point</param>
    /// <param name="e">The direction</param>
    public static Line2 ThroughPointAlongDirection(Point2 p, Vector2 e)
    {
        return new Line2(-p.W*e.Y, p.W*e.X, p.U*e.Y-p.V*e.X);
    }
    /// <summary>
    /// Define a line parallel to another line and through a point
    /// </summary>
    /// <param name="p">The point</param>
    /// <param name="m">The other line</param>
    /// <returns></returns>
    public static Line2 ThroughPointParallelToLine(Point2 p, Line2 m)
    {
        return new Line2(m.A*p.W, m.B*p.W, -m.A*p.U-m.B*p.V);
    }
    /// <summary>
    /// Define a line perpendicular to another line and through a point
    /// </summary>
    /// <param name="p">The point</param>
    /// <param name="m">The other line</param>
    /// <returns></returns>
    public static Line2 ThroughPointNormalToLine(Point2 p, Line2 m)
    {
        return new Line2(-m.B*p.W, m.A*p.W, m.B*p.U-m.A*p.V);
    }
    /// <summary>
    /// Define a line normal to a direction and a certain distance from the origin
    /// </summary>
    /// <param name="n">The normal vector</param>
    /// <param name="d">The distance. Positive & negative values are valid</param>
    public static Line2 FromNormalAndDistance(Vector2 n, double d)
    {
        return new Line2(n.X, n.Y, -d*n.Magnitude);
    }
    /// <summary>
    /// Define a line along a direction and a certain distance from the origin
    /// </summary>
    /// <param name="e">The direction vector</param>
    /// <param name="d">The distance. Positive & negative values are valid</param>
    public static Line2 FromDirectionAndDistance(Vector2 e, double d)
    {
        return new Line2(-e.Y, e.X, -d*e.Magnitude);
    }
    /// <summary>
    /// X-axis is the line defined by `y=0`
    /// </summary>
    public static readonly Line2 XAxis = new Line2(0, 1, 0);
    /// <summary>
    /// Y-axis is the line defined by `x=0`
    /// </summary>
    public static readonly Line2 YAxis = new Line2(1, 0, 0);
    /// <summary>
    /// The horizon is the unique line at infinity
    /// </summary>
    public static readonly Line2 Horizon = new Line2(0, 0, 1);
    public double A { get; }
    public double B { get; }
    public double C { get; }
    public Line2 Normalized() => FromNormalAndDistance(Normal, Distance);
    public bool IsFinite => !IsInfinite;
    public bool IsInfinite => A*A+B*B==0;
    /// <summary>
    /// The center of the line is the point on the line closest to the origin
    /// </summary>
    public Point2 Center => new Point2(-A*C, -B*C, A*A+B*B);
    /// <summary>
    /// The direction vector along the line
    /// </summary>
    public Vector2 Direction => new Vector2(-B, A).Direction;
    /// <summary>
    /// The normal vector to the line
    /// </summary>
    public Vector2 Normal => new Vector2(A, B).Direction;
    /// <summary>
    /// The closest distance of the line to the origin
    /// </summary>
    public double Distance => C/Magnitude;
    /// <summary>
    /// The magnitude of the line is norm of the [A,B] vector
    /// </summary>
    public double Magnitude => Sqrt(A*A+B*B);
    /// <summary>
    /// Offset a line by a vector. 
    /// </summary>
    /// <param name="a">The line</param>
    /// <param name="e">The offset vector</param>
    /// <returns>A parallel line</returns>
    public static Line2 operator +(Line2 a, Vector2 e)
    {
        return new Line2(a.A, a.B, a.C-a.A*e.X-a.B*e.Y);
    }
    /// <summary>
    /// Get the offset vector of two parallel lines
    /// </summary>
    public static Vector2 operator -(Line2 m, Line2 n)
    {
        return Geometry.IsParallel(m, n) ? m.Normal*Geometry.Distance(m, n) : Vector2.Zero;
    }
    /// <summary>
    /// Inner product between point and line. This is proportional to the distance
    /// and hence it is zero when the point is on the line.
    /// </summary>
    public static double operator *(Line2 m, Point2 p)
    {
        return m.A*p.U+m.B*p.V+m.C*p.W;
    }
    /// <summary>
    /// Defines the line meet operator (cross product) between two lines
    /// </summary>
    public static Point2 operator ^(Line2 m, Line2 n) { return Geometry.Meet(m, n); }
}
public static class Geometry
{
    public static double Dot(Point2 p, Line2 m) { return p * m; }
    public static double Dot(Line2 m, Point2 p) { return m * p; }
    public static Point2 Cross(Line2 m, Line2 n) { return m ^ n; }
    public static Line2 Cross(Point2 p, Point2 q) { return p ^ q; }
    /// <summary>
    /// Check for parallelism between two lines. Due to roundoff errors
    /// this will return false when lines are almost parallel.
    /// </summary>
    public static bool IsParallel(Line2 m, Line2 n)
    {
        return m.A*n.B-m.B*n.A==0;
    }
    /// <summary>
    /// Check for coincidence between two points. Due to roundoff errors
    /// this will return false when two points are nearly coincident.
    /// </summary>
    public static bool IsCoincident(Point2 p, Point2 q)
    {
        return p.U*q.W-q.U*p.W==0
            &&p.V*q.W-q.V*p.V==0;
    }
    /// <summary>
    /// Check for parallelism and separation between two lines
    /// </summary>
    public static bool IsCoincident(Line2 m, Line2 n)
    {
        return IsParallel(m, n)&& Distance(m,n)==0;
    }
    /// <summary>
    /// Check if a line is passing through a point
    /// </summary>
    public static bool IsCoincident(Line2 m, Point2 p) => IsCoincident(p, m);
    /// <summary>
    /// Check if point lies on a line
    /// </summary>
    public static bool IsCoincident(Point2 p, Line2 m)
    {
        return p*m==0;
    }
    /// <summary>
    /// Check if two points are near each other within tolerance
    /// </summary>
    public static bool AreNear(Point2 p, Point2 q, double tolerance = 1e-12)
    {
        p=p.Normalized();
        q=q.Normalized();
        return Distance(p, q)<=tolerance;
    }
    /// <summary>
    /// Check if a point is almost on a line within tolerance
    /// </summary>
    public static bool AreNear(Point2 p, Line2 m, double tolerance = 1e-12)
    {
        p=p.Normalized();
        m=m.Normalized();
        return Distance(p, m)<=tolerance;
    }
    /// <summary>
    /// Check that two lines are almost parallel within tolerance
    /// </summary>
    public static bool AreAlmostParallel(Line2 m, Line2 n, double tolerance = 1e-12)
    {
        m=m.Normalized();
        n=n.Normalized();
        return Math.Abs(m.A*n.B-m.B*n.A)<=tolerance;
    }
    /// <summary>
    /// The point where two lines meet.
    /// </summary>
    public static Point2 Meet(Line2 m, Line2 n)
    {
        // | ma |   | na |   | (mb*nc-mc*nb) |
        // | mb | × | nb | = |-(ma*nc-mc*na) |
        // | mc |   | nc |   |  ma*nb-mb*na  |
        return new Point2(
            m.B*n.C-m.C*n.B,
            m.C*n.A-m.A*n.C,
            m.A*n.B-m.B*n.A);
    }
    /// <summary>
    /// The line joining two points
    /// </summary>
    public static Line2 Join(Point2 p, Point2 q)
    {
        // | px |   | qx |   |  (py-qy)    |
        // | py | × | qy | = | -(px-qx)    |
        // |  1 |   |  1 |   | px*qy-py*qx |
        return new Line2(
            p.V*q.W-p.W*q.V, 
            p.W*q.U-p.U*q.W, 
            p.U*q.V-p.V*q.U);
    }
    /// <summary>
    /// Calculate the cartesian distance between two points
    /// </summary>
    public static double Distance(Point2 p, Point2 q)
    {
        var u = p.U*q.W-q.U*p.W;
        var v = p.V*q.W-q.V*p.W;
        return Sqrt(u*u+v*v)/(p.W*q.W);
    }
    /// <summary>
    /// Calculate the offset of a line from a point
    /// </summary>
    public static double Distance(Line2 m, Point2 p) => Distance(p, m);
    /// <summary>
    /// Calculate the closest distance of a line to a point
    /// </summary>
    public static double Distance(Point2 p, Line2 m)
    {
        // Use the inner product `m*p = A*U+B*V+C*W`
        return Abs(m*p)/(p.W*m.Magnitude);
    }
    /// <summary>
    /// Calculate the distance between paralllel lines. 
    /// Returns 0 if lines intersect or are coincident.
    /// </summary>
    public static double Distance(Line2 m, Line2 n)
    {
        // Check that lines are parallel
        if (IsParallel(m,n))
        {
            return n.Distance-m.Distance;
        }
        // If they intersect, the distance is zero
        return 0;
    }
    /// <summary>
    /// Get point on line closet to some other point
    /// </summary>
    /// <param name="m">The line</param>
    /// <param name="p">The other point</param>
    /// <returns>A point on the line</returns>
    public static Point2 Closest(Line2 m, Point2 p)
    {
        return new Point2(
            m.B*m.B*p.U-m.A*(m.B*p.V+m.C*p.W),
            m.A*m.A*p.V-m.B*(m.A*p.U+m.C*p.W),
            p.W*(m.A*m.A+m.B*m.B));
    }
}

参考:http://robotics.stanford.edu/~birch/projective/node4.html