簡體   English   中英

檢查投影在線段上的點是否不在其外部

[英]Check if a point projected on a line segment is not outside it

插圖

見上圖; 基本上,我想要一個簡單的測試來檢查一個點是否在線段的范圍內。 我有的信息(或輸入,如果您願意)是點的坐標和線段終點的坐標。 我想要的輸出是一個簡單的布爾值。 我怎樣才能以簡單的方式檢查這個?

如果使用內部產品,您可以進行簡單統一的檢查。 兩個矢量之間的內積可以幾何可視化為兩個矢量的長度乘以兩者之間的角度的余弦的乘積,或者一個矢量的長度與(正交)投影的長度的乘積。另一個在由該向量確定的線上。

在您的情況下,如果將矢量v從段的一個端點投影到所考慮的點,則當且僅當投影落在連接兩個端點的段s上時,該點位於允許的區域內。 這相當於

0 <= v·s <= s·s

(如果要通過端點排除垂直於線段的線,則嚴格不等式)

public static boolean inRange(double start_x, double start_y, double end_x, double end_y,
                              double point_x, double point_y) {
    double dx = end_x - start_x;
    double dy = end_y - start_y;
    double innerProduct = (point_x - start_x)*dx + (point_y - start_y)*dy;
    return 0 <= innerProduct && innerProduct <= dx*dx + dy*dy;
}

通過粗線的端點確定那些垂直虛線的方程式並不難。

設粗線由點(x 1 , y 1 )(x 2 , y 2 ) 然后,它有一個斜坡

m = (y2 - y1) / (x2 - x1)

所以所有垂直線都是這種形式

y(x) = (-1/m)x + c

我們可以用它來確定通過(x 1 , y 1 )(x 2 , y 2 ) (分別)的垂直線的方程,它基本上代表了所有有效點必須駐留的區域的邊界:

ya(x) = (-1/m)x + y1 + x1/m
yb(x) = (-1/m)x + y2 + x2/m

因此,對於任意點(x*, y*) ,要確定它是否位於有效區域,您可以測試是否

ya(x*) <= y* <= yb(x*)

(如果y a (x*)更大,則相反)


以下應該做的伎倆:

public static boolean check(double x1, double y1, double x2, double y2,
            double x, double y) {

    if (x1 == x2) {  // special case
        return y1 < y2 ? (y1 <= y && y <= y2) : (y2 <= y && y <= y1);
    }

    double m = (y2 - y1) / (x2 - x1);
    double r1 = x1 + m * y1;
    double r2 = x2 + m * y2;
    double r = x + m * y;
    return r1 < r2 ? (r1 <= r && r <= r2) : (r2 <= r && r <= r1);
}

你可以通過計算角度來做到這一點。

假設你的端點是(x1,y1)和(x2,y2),你的點是(x,y)。

然后創建兩個向量,從一個端點到另一個端點,以及一個端點到您的點:

vec1 = (x - x1, y - y1);
vec2 = (x2 - x1, y2 - y1);

計算點積:

double dotp = (x-x1) * (x2-x1) + (y-y1) * (y2 - y1);

現在點積除以幅度給出角度的余弦:

double theta = Math.acos((dtop) / (Math.sqrt((x-x1) * (x-x1) + (y-y1) * (y-y1)) 
       * Math.sqrt((x2-x1) * (x2-x1) + (y2-y1) * (y2-y1))));

現在的訣竅是,如果你的角度大於PI / 2 ,那么你就是'出局'

public static boolean check(double x, double y, double x1, double y1, 
                            double x2, double y2) {
    // vectors are (dx1, dy1) and (dx2, dy2)
    double dx1 = x - x1, dx2 = x2 - x1, dy1 = y - y1, dy2 = y2 - y1;

    double dotp = dx1 * dx2 + dy1 * dy2;
    double theta = Math.acos(dotp  / (Math.sqrt(dx1 * dx1 + dy1 * dy1) 
                                      * Math.sqrt(dx2 * dx2 + dy2 * dy2)));
    theta = Math.abs(theta);

    if (theta > (Math.PI / 2))
        return false;
    dx1 = x - x2;
    dx2 = x1 - x2;
    dy1 = y - y2;
    dy2 = y1 - y2;
    dotp = dx1 * dx2 + dy1 * dy2;
    theta = Math.acos(dotp  / (Math.sqrt(dx1 * dx1 + dy1 * dy1) 
                               * Math.sqrt(dx2 * dx2 + dy2 * dy2)));
    theta = Math.abs(theta);

    if (theta > (Math.PI / 2))
        return false;
    return true;
}

我接受了Daniel Fischer的答案,這很好,並為3D和Unity調整了它:

public bool InSegmentRange(Vector3 start, Vector3 end, Vector3 point) {
    Vector3 delta = end - start;
    float innerProduct = (point.x - start.x) * delta.x + (point.y - start.y) * delta.y + (point.z - start.z) * delta.z;
    return innerProduct >= 0 && innerProduct <= delta.x * delta.x + delta.y * delta.y + delta.z * delta.z;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM