Java 确定坐标是否在直线上

Java 确定坐标是否在直线上,java,geometry,awt,line,coordinates,Java,Geometry,Awt,Line,Coordinates,我正在编写一个小应用程序,允许用户绘制多个形状,然后删除或调整它们的大小。它在矩形和椭圆形上工作得很好,但我对线条有问题 下面是我编写的一个方法,用于查找屏幕上单击的点是否是特定行的一部分: public boolean containsLocation(int x, int y) { int m = (getY2() - getY()) / (getX2() - getX()); int b = getY() - (m * getX()); if (y == (

我正在编写一个小应用程序,允许用户绘制多个形状,然后删除或调整它们的大小。它在矩形和椭圆形上工作得很好,但我对线条有问题

下面是我编写的一个方法,用于查找屏幕上单击的点是否是特定行的一部分:

    public boolean containsLocation(int x, int y) {
    int m = (getY2() - getY()) / (getX2() - getX());
    int b = getY() - (m * getX());
    if (y == (m * x) +  b) {
        return true;
    }
    return false;
我使用著名的y=mx+b公式替换y和x,这是点击点上的坐标,以确定点击点是否是直线的一部分

原始坐标是使用getter getX()、getY()和getX2()、getY2()确定的

问题是,当我单击屏幕以删除该行时,仅当我单击该行开始的第一个坐标(x,y)时,它才起作用

当我单击线路上的任何其他位置时,都不会发生任何事情

既然数学不是最强项,谁能解释一下我做错了什么

以下是我的全系列课程:

    public class Line extends Shape{

private int x2, y2; 

public Line (int x, int y, int x2, int y2, Color lineColor) {
    super(x, y, lineColor);
    this.x2 = x2;
    this.y2 = y2;
}

public void draw(Graphics g) {
    g.setColor(getLineColor());
    g.drawLine(getX(), getY(), getX2(), getY2());

}

@Override
public boolean containsLocation(int x, int y) {
    int m = (getY2() - getY()) / (getX2() - getX());
    int b = getY() - (m * getX());
    if (y == (m * x) +  b) {
        return true;
    }
    return false;
}

public int getX2() {
    return x2;
}

public void setX2(int x2) {
    this.x2 = x2;
}

public int getY2() {
    return y2;
}

public void setY2(int y2) {
    this.y2 = y2;
}
}

下面是通过直线扩展的形状类:

    public abstract class Shape {
    private int x, y;
    private Color lineColor;

     public Shape(int x, int y, Color lineColor) {
    this.x = x;
    this.y = y;
    this.lineColor = lineColor;
    }

    public abstract void draw(Graphics g);
    public abstract boolean containsLocation(int x, int y);

    public int getX() {
    return x;
    }

    public void setX(int x) {
    this.x = x;
    }

    public int getY() {
    return y;
    }

    public void setY(int y) {
    this.y = y;
    }

    public Color getLineColor() {
    return lineColor;
    }

    public void setLineColor(Color lineColor) {
    this.lineColor = lineColor;
    }

    }
下面是调用containsLocation的方法:

    public Shape shapeFinder(int x, int y){
    for (int i = shapes.size()-1; i >=0; i--){
        if (shapes.get(i).containsLocation(x, y)){
            return shapes.get(i);
        }
    }

    return null;

}
下面是应该删除线的方法(它适用于椭圆和矩形):


实际上,您需要使用Math.atan2之类的工具来计算直线的方向(以弧度表示的角度)。然后,可以将反向旋转应用于直线的一个点,将另一个点视为中心,并应用于鼠标坐标。您的线现在是水平线,因此检查鼠标是否在其上方是笔直的

参见旋转矩阵

public class LineDemo {
    public static void main(String[] args) {
        System.out.println(containsLocation(50, 75, 50, 50, 50, 100));
    }

    public static boolean containsLocation(int x, int y, int x1, int y1, int x2, int y2) {
        double dy = y2 - y1;
        double dx = x2 - x1;
        double dist = Math.sqrt(dx*dx + dy*dy);

        double angle = Math.atan2(dy, dx);
        double cos = Math.cos(-angle);
        double sin = Math.sin(-angle);

        double xRot = (x - x1) * cos - (y - y1) * sin;
        double yRot = (x - x1) * sin + (y - y1) * cos;

        // Actually, I only rotated the mouse point, since
        // I can use the first point of the line and its
        // euclidian distance to know where the rotated
        // second point would end.

        if (0 <= xRot && xRot <= dist) {
            double tolerance = 3; // distance tolerance in pixels

            if (Math.abs(yRot) <= tolerance) {
                return true;
            }
        }

        return false;
    }
}
公共类LineDemo{
公共静态void main(字符串[]args){
系统输出打印LN(容器位置(50,75,50,50,50,100));
}
公共静态布尔包含位置(int x,int y,int x1,int y1,int x2,int y2){
双dy=y2-y1;
双dx=x2-x1;
双距离=数学sqrt(dx*dx+dy*dy);
双角度=数学atan2(dy,dx);
双余弦=数学余弦(-角度);
双正弦=数学正弦(-角度);
双xRot=(x-x1)*cos-(y-y1)*sin;
双yRot=(x-x1)*sin+(y-y1)*cos;
//实际上,我只旋转了鼠标点,因为
//我可以使用直线的第一个点及其
//欧几里得距离知道旋转的位置
//第二点将结束。

如果(0你使用整数除法来计算斜率。我用(100100)到(120153)的例子,它给了我2的斜率。它应该是2.65的斜率


但无论如何,在我的直线中间你永远找不到任何整数点——我的线上没有X和Y都是整数的点。如果你正确地计算了斜率,你就能得到端点,但是你需要在中间找到一种不同的计算点的方法。我们的方法?

getX()
getY()
返回
int
s?它也会在垂直线上被零除,就像
getX2()-getX()
0
一样。你需要提供更多的细节。我猜是精确性让你头疼,但我们需要看看getX()etc返回。但只是想一想……如果直线从(100100)到(120153),则不可能单击该直线,因为该直线上没有点(保存端点)其中X和Y都是整数。我尝试过使用double,稍后将它们转换回int,但没有效果。我将粘贴我的line类。放入一些print line语句,以便查看所有变量值。这可能会帮助您缩小导致问题的语句范围。您应该使用double。您不能执行
float dist=Math.sqrt(…)
-这是一个错误,因为
sqrt()
返回一个
double
。是的,需要一个cast。我经常使用float而不是double来适应一些Android设备上缺少FPU单元的情况。感谢您指出这一点!而且,这显然不起作用。:)我用我的示例行(100100)测试了(120153)并询问(120153)是否在那一行,您的代码说否。我肯定某个地方有符号问题,对此表示抱歉,我没有测试就很快写了出来。我不应该:p我会修复错误并让您知道。在您说
if时(getX()
当我从(100100)到(120153)开始并测试(120153)时,我的xRot等于56.648。你应该测试0到dist之间的xRot。你还需要测试相等性,所以:
如果(0)作为附加点,我还警告说一条线是无限细的,因此可能应该考虑到它的某个范围
public class LineDemo {
    public static void main(String[] args) {
        System.out.println(containsLocation(50, 75, 50, 50, 50, 100));
    }

    public static boolean containsLocation(int x, int y, int x1, int y1, int x2, int y2) {
        double dy = y2 - y1;
        double dx = x2 - x1;
        double dist = Math.sqrt(dx*dx + dy*dy);

        double angle = Math.atan2(dy, dx);
        double cos = Math.cos(-angle);
        double sin = Math.sin(-angle);

        double xRot = (x - x1) * cos - (y - y1) * sin;
        double yRot = (x - x1) * sin + (y - y1) * cos;

        // Actually, I only rotated the mouse point, since
        // I can use the first point of the line and its
        // euclidian distance to know where the rotated
        // second point would end.

        if (0 <= xRot && xRot <= dist) {
            double tolerance = 3; // distance tolerance in pixels

            if (Math.abs(yRot) <= tolerance) {
                return true;
            }
        }

        return false;
    }
}