java - 用 vector 计算3点之间的角度,需要更精确(java)

标签 java vector double point angle

我需要计算三个点之间的角度。我已经使用 vector 做到了这一点,看起来它可以工作,但有时我会得到 NaN 结果。为了计算角度,我使用了 arcos(dot(v1,v2)/(length(v1)*length(v2))) 公式。代码如下:

private static double angleBetween(Point previous, Point center, Point next) {
        Vector2D vCenter = new Vector2D(center.x, center.y );
        Vector2D vPrev = new Vector2D(previous.x, previous.y );
        Vector2D vNext = new Vector2D(next.x, next.y );

        Vector2D a = vCenter.minus(vPrev);
        Vector2D b = vCenter.minus(vNext);

        double dot = Vector2D.dot(a, b);

        double la = a.length();

        double lb = b.length();

        double l = la*lb;

        double acos = Math.acos(dot/l);

        double deg = Math.toDegrees(acos);

        return deg;

        }

Vector2D 类:

public double length() {
        return Math.sqrt(x * x + y * y);
    };

public static double dot(Vector2D v1, Vector2D v2) {
        return v1.x * v2.x + v1.y * v2.y;
    };

public Vector2D minus(Vector2D v) {
        return new Vector2D(x - v.x, y - v.y);
    };

调试程序我发现了为什么会发生这种情况。例如设:

center = (127,356)
previous = (117,358)
next = (137,354)

//calculating the vectors
a = (-10,2) //center - prev
b = (10,-2) //center - next

dot = -10*10 + 2*-2 = 104

la = sqrt(-10*-10 + 2*2) = sqrt(104) = see attachment
lb = sqrt(10*10 + -2*-2) = sqrt(104) = see attachment

l = la * lb = see attachment

acos = NaN 因为 dot/l>1 因为 sqrt() 没有给我确切的结果,所以我失去了精度因此 la*lb 值不是 104。

据我所知,double是java中最精确的数字类型。我该如何解决这个问题?

attchment: la,lb,l values

PS 这可能看起来是一种非常罕见的情况,但我遇到过很多这样的情况,所以我不能忽视它。

最佳答案

解决此问题的最佳方法是使用适当的数据类型,例如 java.math.BigDecimal并使用 java.math.MathContext 类型的实例定义计算精度。例如:

double l = la*lb;
BigDecimal lWrapper = new BigDecimal(l, new MathContext(5));
l = lWrapper.doubleValue();

还有另一种方法可以解决此问题。使用以下公式:

angle = atan(length(crossProduct(a, b)) / dotProduct(a, b)) // Because the domain of definition of the tan function is R

公式推导:

  cos(angle) = dotProduct(a, b)   / (length(a) * length(b)) and
  sin(angle) = length(crossProduct(a, b)) / (length(a) * length(b))

有一个

 tan(angle) = sin(angle) / cos(angle)

所以

tan(angle) = length(crossProduct(a, b)) / (length(a) * length(b)) / dotProduct(a, b)   / (length(a) * length(b))
tan(angle) = length(crossProduct(a, b)) / dotProduct(a, b)

应用 tan 的反转函数:

angle = atan(length(crossProduct(a, b)) / dotProduct(a, b))

A, B ∈ ℜ2 的叉积:

|| A x B || = det(A,B) = ((A.x * B.y) - (A.y * B.x))

备注:

  1. ||x||是 vector x ⇔ length(a) 的长度
  2. ∀ A, B ∈ ℜ2: || A x B ||等于A、B的行列式
  3. 您可以使用符号(|| A x B ||)来找出方向

关于java - 用 vector 计算3点之间的角度,需要更精确(java),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36939041/

相关文章:

java - 在JBOSS 7中,war文件可以访问位于ear/lib而不是web-inf/lib中的jar文件

java - Java 的 Vector 和 JTable 的问题

c++ - 迭代 std::vector 时删除(间接)

java - 为什么选择 Float 而不是 Double?反之亦然?

java - Java 和 C# 中的尾调用?

java - JNI 在 C++ 中使用 .hpp 库

java - 如何将数据从java程序传递到javafx应用程序图表?

c++ - 检查两个 vector 是否平行的最有效方法

c++ - 如何以用户友好的形式将 'double' 转换为 'string'

java - 如何使用 Java 打印没有科学记数法的 double 值?