【问题标题】:Angle between two edges of a graph图的两条边之间的角度
【发布时间】:2014-10-20 07:38:17
【问题描述】:

我试图计算图中两条边之间的角度,为此我将两条边都转移到原点,然后使用点积来计算角度。我的问题是,对于像e1e2 这样的一些边缘,angle(e1,e2) 的输出是-1.#INDOO。 这是什么输出?这是一个错误吗? 这是我的代码:

double angle(Edge e1, Edge e2){
    Edge t1 = e1, t2 = e2;
    Point tail1 = t1.getTail(), head1 = t1.getHead();
    Point u(head1.getX() - tail1.getX(), head1.getY() - tail1.getY());

    Point tail2 = t2.getTail(), head2 = t2.getHead();
    Point v(head2.getX() - tail2.getX(), head2.getY() - tail2.getY());

    double dotProduct = u.getX()*v.getX() + u.getY()*v.getY();
    double cosAlpha = dotProduct / (e1.getLength()*e2.getLength());

    return acos(cosAlpha);
}

Edge 是一个包含两个点的类,Point 是一个包含两个双精度数 x 和 y 的类。 我使用angle(e1,e2) 来计算像b 这样的向量到像a 这样的向量的正交投影长度:

double orthogonalProjectionLength(Edge b, Edge a){
    return (b.getLength()*sin(angle(b, a) * (PI / 180)));
}

这个函数有时也会给我-1.#INDOO。你可以看到PointEdgehere的实现。 我的输入是二维空间中 n Points 的集合 S。 Iv 构造了 p 和 q 之间的所有边(p,q 在 S 中),然后尝试像这样计算角度:

for (int i = 0; i < E.size(); i++)
    for (int j = 0; j < E.size(); j++){
        if (i == j)
        cerr << fixed << angle(E[i], E[j]) << endl; //E : set of all edges
    }

如果问题来自cos()sin() 函数,我该如何解决?这里还有其他以更有效的方式计算 sin 和 cos 的库吗?

查看this 示例。 本例中的输入是两个不同的点(如 p 和 q),它们之间有两条边(pqqp)。 angle(pq , qp) 不应该总是 180 吗? angle(pq,pq)angle(qp,qp) 应该是 0。我的程序显示了两种不同的行为,有时是 angle(qp,qp) == angle(pq,pq) ==0angle(pq , qp) == angle(pq , qp) == 180.0,有时答案是 -1.#INDOO 对于所有四个边。

Here 是一个代码示例。 运行几次,你会看到错误。

【问题讨论】:

  • 请给我们举个例子。
  • 180 是干什么用的?一切都应该以弧度表示,所以只需将其保留为弧度即可。
  • 我很确定问题出在您发布的代码之外。但是您的问题似乎是边的长度为零,这会导致除以零的问题。如果没有看到更多代码,很难确定这是为什么。
  • 我会在整个计算过程中打印部分结果(或在调试器中逐步执行并查看结果)。最有可能的是,某些事情最终会以一种不符合您预期的方式进行计算。
  • 检查您的点积是否在&lt;-1,+1&gt; 范围内...由于浮点舍入,它可以是例如 1.000002045,这将导致 acos 失败。所以添加两个 if 并限制在这个范围内。或使用更快的方法:acos(0.99999*dot),但这会降低所有角度的精度,如果 0.9999 常数太大,则错误仍然存​​在

标签: c++ visual-c++ math


【解决方案1】:

您想要投影并且通过所有这些触发?您只需要在 a 方向上用单位向量点 b。所以最终的答案是

(Xa.Xb + Ya.Yb) / square_root(Xa^2 + Ya^2)

您是否检查过 cosAlpha 没有达到 1.000000000000000000000001?这可以解释结果,并提供另一个理由不要像这样到处走动。

【讨论】:

  • 还是要确保Xa^2 + Ya^2 != 0
  • 非常感谢,但无论如何我需要角度,因为我还想构建一个带有角度 TETA 的圆锥体,并检查是否有一个点在这个圆锥体中。
  • fejese 关于检查非零长度是正确的,但无论如何都很难想象你试图投影到一个点上。
  • 您的角度算法只返回锐角,因此它会错误地将负投影报告为正。即使您需要其他角度的角度,您仍然不应该将其包含在此投影中。
  • 追踪 cosAlpha。如果是 1.0000000001,那么 arccos 是不确定的。
【解决方案2】:

好像除以零。确保您的向量始终具有 0&lt; 长度。

【讨论】:

  • 这并没有提供问题的答案。要批评或要求作者澄清,请在其帖子下方发表评论。
  • 我觉得这是一个答案。不是完整的代码和一切,但仍然。它回答了 -1.#INDOO 错误是什么以及导致它的原因。
【解决方案3】:

答案来自我的评论

检查您的点积是否在&lt;-1,+1&gt; 范围内...

  • 由于浮点舍入,它可以是例如 1.000002045,这将导致 acos 失败。
  • 所以添加两个ifs 并限制在这个范围内。
  • 或使用更快的方式:acos(0.99999*dot)
  • 但这会降低所有角度的精度
  • 如果0.9999 常量太大,则错误仍然存​​在

【讨论】:

    【解决方案4】:

    一种推荐的计算角度的方法是使用atan2 函数,采用两个参数。它返回四个象限的角度。

    您可以通过两种方式使用它:

    • 分别计算uv的角度并减去:atan2(Vy, Vx) - atan2(Uy, Ux)

    • 计算叉积和点积:atan2(Ux.Vy - Uy.Vx, Ux.Uy + Vx.Vy)

    唯一失败的情况是(0, 0)

    【讨论】:

    • 非常感谢,这样做比我的方法容易。
    猜你喜欢
    • 1970-01-01
    • 2021-10-23
    • 2023-04-07
    • 2019-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多