获取矩形和直线的交点

时间:2011-03-07 15:48:37

标签: c# wpf math

我需要获得矩形和直线的交点。 在矩形(矩形的中心)内有B点,在外面有A点。我需要在一个矩形边框上找到C点。 我也得到矩形的宽度和高度。

enter image description here

所有这些都是 WPF 应用程序,所以如果任何功能构建我会非常高兴。

6 个答案:

答案 0 :(得分:3)

这是基本的数学求解线 - 线交叉,检查tutorial

的topcoder
  

Line-Line Intersection最多的一个   您将在几何中找到的常见任务   问题是线路交叉。尽管   这是如此常见,很多事实   编码员仍然遇到麻烦。   第一个问题是,形式是什么   我们给出了线条和形式   我们会喜欢他们吗?理想情况下,每个   我们的线路将以形式出现   Ax + By = C,其中A,B和C是   定义该行的数字。   但是,我们很少有线   这种格式,但我们可以轻松   从两个生成这样的方程式   点。说我们有两个不同的   点,(x1,y1)和(x2,y2),和   想要找到A,B和C.   上面的等式。我们可以这样做   设置A = y2-y1 B = x1-x2 C =   A * X1 + B * Y1

答案 1 :(得分:3)

在不知道WPF或其任何功能的情况下,我就是这样做的:

  1. 创建一个临时点D,在B和C之间创建一个直角。
  2. CD的长度应该是已知的,因为B位于矩形的中心。因此,计算BD的长度应该很简单。
  3. 通过sqrt确定BC的长度((BD)^ 2 +(CD)^ 2)。
  4. 根据A的位置,您知道C是在矩形边的中点之前还是之后。因此,您可以使用BC的长度来计算侧面C的位置。

答案 2 :(得分:2)

使用ax和ay坐标为A和bx,坐标为B,并假设宽度为w且高度为h的矩形的中心为{0,0},则以下情况应该有效

IntersectionRectangleLine[{ax_, ay_}, {bx_, by_}, h_, w_] :=
  Module[{\[Mu]r, \[Mu]l, \[Mu]t, \[Mu]b},
    {\[Mu]r, \[Mu]l, \[Mu]t, \[Mu]b} = {-((-2 ay bx + 2 ax by - ax w + 
      bx w)/((ay - by) h)), -((-2 ay bx + 2 ax by + ax w - 
      bx w)/((ay - by) h)), -((
     2 ay bx - 2 ax by - ay h + by h)/((ax - bx) w)), -((
     2 ay bx - 2 ax by + ay h - by h)/((ax - bx) w))};
 Which[
   -1 <= \[Mu]r <= 1, {0, w/2} + \[Mu]r {h/2, 0},
   -1 <= \[Mu]l <= 1, {0, -w/2} + \[Mu]l {h/2, 0},
   -1 <= \[Mu]t <= 1, {h/2, 0} + \[Mu]t {0, w/2},
   -1 <= \[Mu]b <= 1, {-h/2, 0} + \[Mu]b {0, w/2}
 ]
]

这基于构成三角形的四条线的交叉点的解决方案

  In[114]:= Solve[Thread[\[Lambda] ({bx, by} - {ax, ay}) + {ax, ay} == {0, w/2} + \[Mu] {h/2, 0}], \[Mu], {\[Lambda]}]

 Out[114]= {{\[Mu] -> -((-2 ay bx + 2 ax by - ax w + bx w)/((ay - by) h))}}

(这里以第一行为例)。

对于Evgeny来说,这就是它在我的屏幕上的样子。相当多可读性。

prettier version of code

答案 3 :(得分:2)

C#,WPF的解决方案:

 /// <summary>
    /// Get Intersection point
    /// </summary>
    /// <param name="a1">a1 is line1 start</param>
    /// <param name="a2">a2 is line1 end</param>
    /// <param name="b1">b1 is line2 start</param>
    /// <param name="b2">b2 is line2 end</param>
    /// <returns></returns>
    public static Vector? Intersects(Vector a1, Vector a2, Vector b1, Vector b2)
    {
        Vector b = a2 - a1;
        Vector d = b2 - b1;
        var bDotDPerp = b.X * d.Y - b.Y * d.X;

        // if b dot d == 0, it means the lines are parallel so have infinite intersection points
        if (bDotDPerp == 0)
            return null;

        Vector c = b1 - a1;
        var t = (c.X * d.Y - c.Y * d.X) / bDotDPerp;
        if (t < 0 || t > 1)
            {
            return null;
        }

        var u = (c.X * b.Y - c.Y * b.X) / bDotDPerp;
        if (u < 0 || u > 1)
        {
            return null;
        }

        return a1 + t * b;
    }

修改  找到Link来回答上述问题的答案。

答案 4 :(得分:1)

如果你知道矩形的尺寸,我假设你做“

  • rX矩形宽度
  • rY矩形高度
  • Ay A的Y位置
  • Ax A的X位置
  • By B的Y位置
  • Bx B的X位置
  • Cy C的Y位置
  • Cx C的X位置

Cy = By + rY / 2

C位置位于矩形的顶部,因此它是By位置+ rY位置的一半

然后我们只需计算Cx位置。

Cx = (Bx + ((Ax - Bx) / (Ay - By)) * Cy)

您可以使用Point

获取A和B的X和Y Coordiantes

答案 5 :(得分:1)

Line Intersection Possibilities in Rectangle

希望它 100% 有效

我也遇到了同样的问题。所以经过两天的努力,我终于创建了这个方法,

主方法,

    // Tuple<entryPoint, exitPoint, lineStatus>
    private Tuple<Point, Point, Line> GetIntersectionPoint(Point a, Point b, Rectangle rect)
    {
        if (IsWithinRectangle(a, rect) && IsWithinRectangle(b, rect))
        {
            // Can't set null to Point that's why I am returning just empty object
            return new Tuple<Point, Point, Line>(new Point(), new Point(), Line.InsideTheRectangle);
        }
        else if (!IsWithinRectangle(a, rect) && !IsWithinRectangle(b, rect))
        {
            if (!LineIntersectsRectangle(a, b, rect))
            {
                // Can't set null to Point that's why I am returning just empty object
                return new Tuple<Point, Point, Line>(new Point(), new Point(), Line.NoIntersection);
            }

            Point entryPoint = new Point();
            Point exitPoint = new Point();

            bool entryPointFound = false;

            // Top Line of Chart Area
            if (LineIntersectsLine(a, b, new Point(0, 0), new Point(rect.Width, 0)))
            {
                entryPoint = GetPointFromYValue(a, b, 0);
                entryPointFound = true;
            }
            // Right Line of Chart Area
            if (LineIntersectsLine(a, b, new Point(rect.Width, 0), new Point(rect.Width, rect.Height)))
            {
                if (entryPointFound)
                    exitPoint = GetPointFromXValue(a, b, rect.Width);
                else
                {
                    entryPoint = GetPointFromXValue(a, b, rect.Width);
                    entryPointFound = true;
                }
            }
            // Bottom Line of Chart
            if (LineIntersectsLine(a, b, new Point(0, rect.Height), new Point(rect.Width, rect.Height)))
            {
                if (entryPointFound)
                    exitPoint = GetPointFromYValue(a, b, rect.Height);
                else
                {
                    entryPoint = GetPointFromYValue(a, b, rect.Height);
                }
            }
            // Left Line of Chart
            if (LineIntersectsLine(a, b, new Point(0, 0), new Point(0, rect.Height)))
            {
                exitPoint = GetPointFromXValue(a, b, 0);
            }

            return new Tuple<Point, Point, Line>(entryPoint, exitPoint, Line.EntryExit);
        }
        else
        {
            Point entryPoint = GetEntryIntersectionPoint(rect, a, b);
            return new Tuple<Point, Point, Line>(entryPoint, new Point(), Line.Entry);
        }
    }

支持方法,

    enum Line
    {
        // Inside the Rectangle so No Intersection Point(Both Entry Point and Exit Point will be Null)
        InsideTheRectangle,

        // One Point Inside the Rectangle another Point Outside the Rectangle. So it has only Entry Point
        Entry,

        // Both Point Outside the Rectangle but Intersecting. So It has both Entry and Exit Point
        EntryExit,

        // Both Point Outside the Rectangle and not Intersecting. So doesn't has both Entry and Exit Point
        NoIntersection
    }

    private Point GetEntryIntersectionPoint(Rectangle rect, Point a, Point b)
    {
        // For top line of the rectangle
        if (LineIntersectsLine(new Point(0, 0), new Point(rect.Width, 0), a, b))
        {
            return GetPointFromYValue(a, b, 0);
        }
        // For right side line of the rectangle
        else if (LineIntersectsLine(new Point(rect.Width, 0), new Point(rect.Width, rect.Height), a, b))
        {
            return GetPointFromXValue(a, b, rect.Width);
        }
        // For bottom line of the rectangle
        else if (LineIntersectsLine(new Point(0, rect.Height), new Point(rect.Width, rect.Height), a, b))
        {
            return GetPointFromYValue(a, b, rect.Height);
        }
        // For left side line of the rectangle
        else
        {
            return GetPointFromXValue(a, b, 0);
        }
    }

    public bool LineIntersectsRectangle(Point p1, Point p2, Rectangle r)
    {
        return LineIntersectsLine(p1, p2, new Point(r.X, r.Y), new Point(r.X + r.Width, r.Y)) ||
               LineIntersectsLine(p1, p2, new Point(r.X + r.Width, r.Y), new Point(r.X + r.Width, r.Y + r.Height)) ||
               LineIntersectsLine(p1, p2, new Point(r.X + r.Width, r.Y + r.Height), new Point(r.X, r.Y + r.Height)) ||
               LineIntersectsLine(p1, p2, new Point(r.X, r.Y + r.Height), new Point(r.X, r.Y)) ||
               (r.Contains(p1) && r.Contains(p2));
    }

    private bool LineIntersectsLine(Point l1p1, Point l1p2, Point l2p1, Point l2p2)
    {
        float q = (l1p1.Y - l2p1.Y) * (l2p2.X - l2p1.X) - (l1p1.X - l2p1.X) * (l2p2.Y - l2p1.Y);
        float d = (l1p2.X - l1p1.X) * (l2p2.Y - l2p1.Y) - (l1p2.Y - l1p1.Y) * (l2p2.X - l2p1.X);

        if (d == 0)
        {
            return false;
        }

        float r = q / d;

        q = (l1p1.Y - l2p1.Y) * (l1p2.X - l1p1.X) - (l1p1.X - l2p1.X) * (l1p2.Y - l1p1.Y);
        float s = q / d;

        if (r < 0 || r > 1 || s < 0 || s > 1)
        {
            return false;
        }

        return true;
    }

    // For Large values, processing with integer is not working properly
    // So I here I am dealing only with double for high accuracy
    private Point GetPointFromYValue(Point a, Point b, double y)
    {
        double x1 = a.X, x2 = b.X, y1 = a.Y, y2 = b.Y;
        double x = (((y - y1) * (x2 - x1)) / (y2 - y1)) + x1;
        return new Point((int)x, (int)y);
    }

    // For Large values, processing with integer is not working properly
    // So here I am dealing only with double for high accuracy
    private Point GetPointFromXValue(Point a, Point b, double x)
    {
        double x1 = a.X, x2 = b.X, y1 = a.Y, y2 = b.Y;
        double y = (((x - x1) * (y2 - y1)) / (x2 - x1)) + y1;
        return new Point((int)x, (int)y);
    }

    // rect.Contains(point) is not working properly in some cases.
    // So here I created my own method
    private bool IsWithinRectangle(Point a, Rectangle rect)
    {
        return a.X >= rect.X && a.X <= rect.X + rect.Width && a.Y >= rect.Y && a.Y <= rect.Y + rect.Height;
    }