计算线段之间的夹角和对应的圆弧上的点

计算线段之间的夹角和对应的圆弧上的点

Tim 138 2024-09-12

角度

计算两条线段之间的夹角

1. 计算两点间距离公式

d=\sqrt{(x2-x1)^2+(y2-y1)^2}

其中(x1,y1) 是线段的起点,(x2,y2) 是线段的终点

2.余弦定理

c^2 = a^2 + b^2 - 2ab\cos(\theta)

其中 a, b, c 分别是三角形的三边,\theta a b 之间的夹角。从余弦定力中解出\cos(\theta)

\cos(\theta)=\frac{a^2+b^2-c^2}{2ab}

3.反余弦函数

\theta = \arccos\left(\frac{a^2 + b^2 - c^2}{2ab}\right)

4.角度转换

\theta_{\text{degrees}} = \theta_{\text{radians}} \times \frac{180}{\pi}

代码实现

 // Calculate angle
 double a = Math.Sqrt(Math.Pow((origin.X - x1.X),2)  + Math.Pow((origin.Y - x1.Y),2));
 double b = Math.Sqrt(Math.Pow((origin.X - x2.X),2)  + Math.Pow((origin.Y - x2.Y),2));
 double c = Math.Sqrt(Math.Pow((x2.X - x1.X),2)  + Math.Pow((x2.Y - x1.Y),2));

 double cTheta = (a * a + b * b - c * c) / (2 * a * b);
 double theta = Math.Acos(cTheta) * 180 / Math.PI;

圆弧上的点

实际程序中需要通过计算角度的正弦值(得通过向量来计算)来判断角度是否处于水平轴下方。

5.计算起始角度

反正切计算线段与水平坐标轴的夹角

\theta_0 = \arctan\left(\frac{y_2 - y_1}{x_2 - x_1}\right)

其中(x1,y1) 是线段的起点,(x2,y2) 是线段的终点

6.正弦值计算

向量叉积(也称为外积或向量积)的基本性质之一:向量叉积的结果是一个向量,其等于两个向量的模长乘以它们之间夹角的正弦值

通过两个向量的叉积算法(得出平行四边形的面积)来计算两个向量之间的夹角正弦值

三角形面积\times2=|\vec{u}||\vec{v}|\times\sin(\theta)

\sin{(\theta)}=\frac{|\vec{u} \times \vec{v}|}{|\vec{u}||\vec{v}|}

向量计算:

u=(x2-x1,y2-y1) \\ \ \ \ \ \ \ v=(x3-x1,y3-y1)

向量叉积:

\vec{u}\times\vec{v}=u_xv_y-u_yv_x

向量的模(长度):

|\vec{u}|=\sqrt{x^2+y^2}\\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ =\sqrt{(x2-x1)^2+(y2-y1)^2}
|\vec{v}|=\sqrt{x^2+y^2}\\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ =\sqrt{(x3-x1)^2+(y3-y1)^2}

最后得出公式:

\sin(\theta) = \frac{(x_2 - x_1)(y_3 - y_1) - (y_2 - y_1)(x_3 - x_1)}{a \times b}

其中(x1,y1)是线段a和线段b的起点,(x2,y2) 是线段a 的终点,(x3,y3)是线段b的终点

7. 上点的坐标计算

x = x_{\text{center}} + r \cos(\theta) \\ y = y_{\text{center}} - r \sin(\theta)

其中, (x_{\text{center}}, y_{\text{center}}) 是圆心坐标,r 是圆的半径, \theta 是从圆心到点的角度

代码实现

  double r=25;//半径  
  //起始角度
  double theta0 = Math.Atan((origin.Y - x1.Y) / (x1.X - origin.X + 1e-10)) * 180 / Math.PI;

  var pointList = new List<System.Windows.Point>();//保存圆弧上的点

  //计算正弦值
  double sin_ab = ((x1.X - origin.X) * (x2.Y - origin.Y) - (x1.Y - origin.Y) * (x2.X - origin.X)) / (a * b);

  if (sin_ab <= 0)
  {  //水平轴上方
      for (double delta = 0; delta <= theta; delta++)
      {
          double th = delta + theta0;
          pointList.Add(new System.Windows.Point(origin.X + r * Math.Cos(th * Math.PI / 180), origin.Y - r * Math.Sin(th * Math.PI / 180)));
      }
  }
  else
  {
      for (double delta = -theta; delta <= 0; delta++)
      {
          double th = delta + theta0;
          pointList.Add(new System.Windows.Point(origin.X + r * Math.Cos(th * Math.PI / 180), inoriginiP.Y - r * Math.Sin(th * Math.PI / 180)));
      }
  }