Java 检查投影在线段上的点是否不在其外部

Java 检查投影在线段上的点是否不在其外部,java,math,geometry,computational-geometry,Java,Math,Geometry,Computational Geometry,见上图;基本上,我想要一个简单的测试来检查一个点是否在线段的范围内。我的信息(或输入,如果您愿意)是点的坐标和线段终止点的坐标。我想要的输出是一个简单的布尔值。如何用一种简单的方法来检查这一点?确定通过粗体线端点的垂直虚线的方程式并不难 让粗体线由点(x1,y1)和(x2,y2)定义。然后,它有一个斜率 m = (y2 - y1) / (x2 - x1) (如果ya(x*)较大,则相反) 下面应该可以做到这一点: public static boolean check(double x1, d


见上图;基本上,我想要一个简单的测试来检查一个点是否在线段的范围内。我的信息(或输入,如果您愿意)是点的坐标和线段终止点的坐标。我想要的输出是一个简单的布尔值。如何用一种简单的方法来检查这一点?

确定通过粗体线端点的垂直虚线的方程式并不难

让粗体线由点
(x1,y1)
(x2,y2)
定义。然后,它有一个斜率

m = (y2 - y1) / (x2 - x1) (如果
ya(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){
如果(x1==x2){//特殊情况

返回y1 假设端点是(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;
}

如果使用内积,可以进行简单而统一的检查。两个向量之间的内积可以几何可视化为两个向量的长度与两个向量之间夹角的余弦的乘积,或者一个向量的长度与(正交)向量长度的乘积另一个投影到由该向量确定的直线上

在您的情况下,如果将向量
v
从线段的一个端点投影到所考虑的点,则当且仅当投影落在连接两个端点的线段
s
上时,该点位于允许区域内。这相当于

0 <= v·s <= s·s

0我选择了丹尼尔·菲舍尔(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;
}
公共布尔插入范围(矢量3开始、矢量3结束、矢量3点){
矢量3δ=结束-开始;
浮点内积=(point.x-start.x)*delta.x+(point.y-start.y)*delta.y+(point.z-start.z)*delta.z;

return innerProduct>=0&&innerProduct此答案没有带来任何新内容为什么不呢?对于需要在3D而不是2D中进行此操作的人,可能会很有用。有关此主题的有趣阅读:
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;
}
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;
}
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;
}