[英]How to determine the intersection point between the straight line and circle?
我在圓內有一個點,在圓外有另一個點。 我想找到線與圓相交的點。 我怎么能在 Windows Phone 8 中做到這一點。請給我任何想法。
這是一個既簡單又復雜的問題,很大程度上取決於您的意思。 我從你的開篇文章中得知你在談論線段而不是真正的(無限)線。
在這種情況下,您有幾個案例需要解決。 只有一點在圓內,一點在圓外時,才會發生相交。 下面的算法沒有捕捉到以下情況
這些被歸入“無交集”結果。 這僅處理嚴格在圓內一點和圓外一點的情況。
首先你需要一些輔助功能。 這些使用基本幾何來確定點是在圓內還是圓外(圓上的點算作“外”),以及兩點是否形成與圓相交的線段。
private bool IsInsideCircle(Point CirclePos, float CircleRad, Point checkPoint)
{
if (Math.Sqrt(Math.Pow((CirclePos.X - checkPoint.X), 2) +
Math.Pow((CirclePos.Y - checkPoint.Y), 2)) < CircleRad)
{ return true; } else return false;
}
private bool IsIntersecting(Point CirclePos, float CircleRad, Point LineStart,
Point LineEnd)
{
if (IsInsideCircle(CirclePos, CircleRad, LineStart) ^
IsInsideCircle(CirclePos, CircleRad, LineEnd))
{ return true; } else return false;
}
請注意^
(異或)的使用 - 我們希望精確地在里面一點,在外面一點。
有了這個,我們可以處理更大的功能:
private int Intersect (Point CirclePos, float CircleRad,
Point LineStart, Point LineEnd, ref Point Intersection)
{
if (IsIntersecting(CirclePos, CircleRad, LineStart, LineEnd))
{
//Calculate terms of the linear and quadratic equations
var M = (LineEnd.Y - LineStart.Y) / (LineEnd.X - LineStart.X);
var B = LineStart.Y - M * LineStart.X;
var a = 1 + M*M;
var b = 2 * (M*B - M*CirclePos.Y - CirclePos.X);
var c = CirclePos.X * CirclePos.X + B * B + CirclePos.Y * CirclePos.Y -
CircleRad * CircleRad - 2 * B * CirclePos.Y;
// solve quadratic equation
var sqRtTerm = Math.Sqrt(b * b - 4 * a * c);
var x = ((-b) + sqRtTerm)/(2*a);
// make sure we have the correct root for our line segment
if ((x < Math.Min(LineStart.X, LineEnd.X) ||
(x > Math.Max(LineStart.X, LineEnd.X))))
{ x = ((-b) - sqRtTerm) / (2 * a); }
//solve for the y-component
var y = M * x + B;
// Intersection Calculated
Intersection = new Point(x, y);
return 0;
} else {
// Line segment does not intersect at one point. It is either
// fully outside, fully inside, intersects at two points, is
// tangential to, or one or more points is exactly on the
// circle radius.
Intersection = new Point(0, 0);
return -1;
}
}
此函數將交點作為ref
參數並返回-1
(無交點)或0
(找到交點)。 如果您想擴展它以區分邊緣情況,我使用了int
返回值。 交點是從基本幾何計算的 - 請記住,一條線表示為(請參閱:斜率截距和點斜率表格)
和一個圓(以(Cx, Cy)
為中心,半徑為r
)是
您可以通過替換來解決這個方程組:
擴展和收集您得到的術語:
這是形式的標准二次方程
這可以通過二次公式解決(參見: 二次公式):
這為我們的線段所在的無限線提供了兩個根——我們在上面做了最后的檢查,以確保我們為我們的特定線段選擇了解決方案。
這就是為什么在數學課上專心很重要!
現在......取決於你在做什么,有很多方法可以優化它。 上面的解決方案概述了基本方法,但如果需要,當然還有空間可以更快地執行此操作。 顯然,還可以將參數調整為您使用的任何類型的點或對象。 我試圖使它盡可能通用。
此外,為了展示如何調用它的示例:
Point iPt = new Point();
var rslt = Intersect(new Point(2,3), 5.0f, new Point(2,2),
new Point(8,6), ref iPt);
if (rslt == 0) {
MessageBox.Show(String.Format("Intersection at: x = {0}, y = {1}",
iPt.X, iPt.Y));
}
else {
MessageBox.Show("No Intersection");
}
數學上有一個小錯別字。 c# 代碼沒問題。
... r^2 - B*Cy) = 0
應該
... r^2 - 2B*Cy) = 0
還有 c = (Cx^2 + Cy^2 + B^2 - r^2 - 2B*Cy)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.