如何在Javascript中找到SVG上两条直线(路径)之间的角度?

时间:2017-02-10 12:08:31

标签: javascript math svg angle

我在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);
}

Image

4 个答案:

答案 0 :(得分:3)

您可以利用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);

答案 1 :(得分:1)

您想要public partial class MainWindow : Window, INotifyPropertyChanged { private Dictionary<int, string> cbTypeVals = new Dictionary<int, string>(); private Dictionary<UInt16, string> cbSrcValueVals = new Dictionary<UInt16, string>(); private Dictionary<UInt16, string> cbDiagVals = new Dictionary<UInt16, string>(); public MainWindow() { InitializeComponent(); _source = cbTypeVals; //... } private System.Collections.IEnumerable _source; public System.Collections.IEnumerable Source { get { return _source; } set { _source = value; OnPropertyChanged(); } } private void OnAutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e) { if (e.PropertyName == "Binding") { AutoCommitComboBoxColumn cb = new AutoCommitComboBoxColumn(); e.Column = cb; //bind the ItemsSource property to the Source property of the window here... cb.SetBinding(AutoCommitComboBoxColumn.ItemsSourceProperty, new Binding("Source") { Source = this }); cb.ItemsSource = cbSrcValueVals; cb.DisplayMemberPath = "Value"; cb.SelectedValuePath = "Key"; cb.SelectedValueBinding = new Binding("Binding"); e.Column.Header = "Binding"; e.Column.CellStyle = new Style(typeof(DataGridCell)); e.Column.CellStyle.Setters.Add(new Setter(DataGridCell.HorizontalAlignmentProperty, HorizontalAlignment.Stretch)); } //... } private void OnComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e) { //set the value of the Source property to a new collection and raise the PropertyChanged event here... Source = cbDiagVals; } public event PropertyChangedEventHandler PropertyChanged; private virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } //... } P0-C而不是P1-DP0-C:只需翻译其中一个细分,让P1-CD重合:C(然后是P1' = P1 - D + C)。

答案 2 :(得分:0)

找到两行之间的角度(@):

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))
}

答案 3 :(得分:0)

在提交答案后,我意识到这与@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点之间角度的函数(无论算法有什么限制),你可以在两个断开的线段上使用相同的函数,只需简单地翻译一个两个端点重合,然后使用相同的功能(同样,算法仍有任何限制)。

&#13;
&#13;
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}
  )
);
&#13;
&#13;
&#13;