【问题标题】:How to find angle between two straight lines (paths) on a SVG in Javascript?如何在Javascript中找到SVG上两条直线(路径)之间的角度?
【发布时间】:2017-02-10 12:08:30
【问题描述】:

我在 SVG 画布中有两条直线作为 <path>。使用 LineA (A1x, A1y) (A2x, A2y) 和 LineB (B1x, B1y) (B2x, B2y) 的像素坐标如何计算这些线之间的角度。

我有下面的代码,它适用于三个点(它适用于下图中的绿色案例)。 (A2x, A2y) != (B1x, B1y)时不起作用。

如何修改此公式以使其即使在未连接线的情况下也能正常工作。

function find_angle(p0,p1,c) {
var p0c = Math.sqrt(Math.pow(c.x-p0.x,2)+
                    Math.pow(c.y-p0.y,2));  
var p1c = Math.sqrt(Math.pow(c.x-p1.x,2)+
                    Math.pow(c.y-p1.y,2));
var p0p1 = Math.sqrt(Math.pow(p1.x-p0.x,2)+
                     Math.pow(p1.y-p0.y,2));
var angle = Math.acos((p1c*p1c+p0c*p0c-p0p1*p0p1)/(2*p1c*p0c));
return angle * (180 / Math.PI);
}

【问题讨论】:

  • 2D 向量将使用点积或叉积轻松为您提供这个答案。我更喜欢后者,因为你有两个角度可供选择。叉积允许您通过指定平面外方向来选择哪一个。
  • 无论您使用 (p0,p1,c) 还是 (p1,p0,c) 调用,您当前的函数都会为您提供相同的结果。这真的是你想要的吗?

标签: javascript math svg angle


【解决方案1】:

您可以利用 Math.atan2 函数对这些段进行方向向量的叉积和点积。注意 atan2 返回 -Pi...Pi 范围内的有符号角度

//find vector components
var dAx = A2x - A1x;
var dAy = A2y - A1y;
var dBx = B2x - B1x;
var dBy = B2y - B1y;
var angle = Math.atan2(dAx * dBy - dAy * dBx, dAx * dBx + dAy * dBy);
if(angle < 0) {angle = angle * -1;}
var degree_angle = angle * (180 / Math.PI);

【讨论】:

    【解决方案2】:

    您想要P0-CP1-D 而不是P0-CP1-C:只需翻译其中一个片段以使DC 重合:P1' = P1 - D + C(然后是D' = C)。

    【讨论】:

    • 我在提交答案后意识到,我使用了您在此处提倡的更概念性语言的相同方法。
    【解决方案3】:

    提交答案后,我意识到这与@YvesDaoust 提供的解决方案相同。这个答案是对我在这里用一个 JavaScript 示例充实的相同方法的更简洁的概念总结。

    答案很简单:

    function find_disconnected_angle(p0,c0, p1,c1) {
      return find_angle({x:p0.x-c0.x+c1.x,y:p0.y-c0.y+c1.y},p1,c1);
    }
    

    您可以使用三角学基础知识从头开始计算角度。但是,为了让您的生活更轻松,您也可以只使用已有的功能。首先,只需在数学上平移一条线,使其端点之一与另一条线的端点之一重合。有四种不同的方法可以匹配每条线的一个端点,每种方法都会产生可能不同的角度测量值。然而,这并没有比你必须找出你想要的四个角度中的哪个角度更大,当你取每个原始未平移线段,将每个线段延伸成一条无限线,并检查四个角度时,那些两条线相交。

    您需要一个将 4 个点作为输入的函数,即 p0、p1、p2 和 p3。然而,为了明确哪些点是巧合的,我将它们标记为 p0、c0、p1 和 c1,这样 p0 和 c0 都以使 c0 和 c1 重合的方式移动,结果分三点:p0new、p1 和 c,后者等于 c1 和 c0new。

    更新:在更仔细地检查您的原始函数后,我意识到我上面关于选择四个可能角度的讨论可能与您编写的确切函数实现无关,因为点的顺序p0 和 p1 对您的功能无关紧要。您可以重写您的原始函数,也许使用其他答案中的一些概念,以便能够更全面地控制您得到的角度,如果这确实是您想要的。在任何情况下,我的答案背后的一般概念都成立:如果您已经有一个计算 3 点之间角度的函数(无论算法有什么限制),您可以通过简单地翻译一个这样的方法在两个断开的线段上使用相同的函数两个端点重合,然后使用相同的函数(同样,算法仍然有任何限制)。

    function find_angle(p0,p1,c) {
      var p0c = Math.sqrt(Math.pow(c.x-p0.x,2)+
                          Math.pow(c.y-p0.y,2));  
      var p1c = Math.sqrt(Math.pow(c.x-p1.x,2)+
                          Math.pow(c.y-p1.y,2));
      var p0p1 = Math.sqrt(Math.pow(p1.x-p0.x,2)+
                           Math.pow(p1.y-p0.y,2));
      var angle = Math.acos((p1c*p1c+p0c*p0c-p0p1*p0p1)/(2*p1c*p0c));
      return angle * (180 / Math.PI);
    }
    
    function find_disconnected_angle(p0,c0, p1,c1) {
      return find_angle({x:p0.x-c0.x+c1.x,y:p0.y-c0.y+c1.y},p1,c1);
    }
    
    console.log(
      find_angle(
        {x: 7, y: 2},
        {x: 7, y: 7},
        {x: 2, y: 2}
      )
    );
    
    console.log(
      find_disconnected_angle(
        {x: 27, y: 42},
        {x: 22, y: 42},
        {x:  7, y:  7},
        {x:  2, y:  2}
      )
    );

    【讨论】:

      【解决方案4】:

      找出两条线之间的角度(@):

      tan@ = (m1-m2)/(1+m1.m2)

      其中 m1 和 m2 分别是线条的梯度。 JS方面:

      var m1 = (A1y-A2y)/(A1x-A2x)
      var m2 = (B1y-B2y)/(B1x-B2x)
      var angle
      if(m1*m2==-1){
          angle = Math.PI/2
      }else{
          angle = Math.atan((m1-m2)/(1+m1*m2))
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-14
        • 1970-01-01
        • 1970-01-01
        • 2012-08-13
        相关资源
        最近更新 更多