C++ 两条线之间的内角
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2946327/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Inner angle between two lines
提问by osanchezmon
I have two lines: Line1 and Line2. Each line is defined by two points (P1L1(x1, y1), P2L1(x2, y2)
and P1L1(x1, y1), P2L3(x2, y3))
. I want to know the inner angle defined by these two lines.
我有两条线:Line1 和 Line2。每条线由两个点(P1L1(x1, y1), P2L1(x2, y2)
和定义P1L1(x1, y1), P2L3(x2, y3))
。我想知道这两条线定义的内角。
For do it I calculate the angle of each line with the abscissa:
为此,我用横坐标计算每条线的角度:
double theta1 = atan(m1) * (180.0 / PI);
double theta2 = atan(m2) * (180.0 / PI);
After to know the angle I calculate the following:
知道角度后,我计算如下:
double angle = abs(theta2 - theta1);
The problem or doubt that I have is: sometimes I get the correct angle but sometimes I get the complementary angle (for me outer). How can I know when subtract 180o
to know the inner angle? There is any algorithm better to do that? Because I tried some methods: dot product,
following formula:
我遇到的问题或疑问是:有时我得到了正确的角度,但有时我得到了互补角(对我来说是外角)。我怎么知道什么时候减去180o
才能知道内角?有什么算法可以更好地做到这一点?因为我尝试了一些方法:点积,以下公式:
result = (m1 - m2) / (1.0 + (m1 * m2));
But always I have the same problem; I never known when I have the outer angle or the inner angle!
但我总是有同样的问题;我从来不知道我什么时候有外角或内角!
回答by andand
I think what you're looking for is the inner product(you may also want to look over the dot productentry) of the two angles. In your case, that's given by:
我认为您要寻找的是两个角度的内积(您可能还想查看点积条目)。在你的情况下,这是由:
float dx21 = x2-x1;
float dx31 = x3-x1;
float dy21 = y2-y1;
float dy31 = y3-y1;
float m12 = sqrt( dx21*dx21 + dy21*dy21 );
float m13 = sqrt( dx31*dx31 + dy31*dy31 );
float theta = acos( (dx21*dx31 + dy21*dy31) / (m12 * m13) );
Answer is in radians.
答案是弧度。
EDIT:Here's a complete implementation. Substitute the problematic values in p1, p2, and p3 and let me know what you get. The point p1 is the vertex where the two lines intersect, in accordance with your definition of the two lines.
编辑:这是一个完整的实现。替换 p1、p2 和 p3 中的有问题的值,让我知道您得到了什么。根据您对两条线的定义,点 p1 是两条线相交的顶点。
#include <math.h>
#include <iostream>
template <typename T> class Vector2D
{
private:
T x;
T y;
public:
explicit Vector2D(const T& x=0, const T& y=0) : x(x), y(y) {}
Vector2D(const Vector2D<T>& src) : x(src.x), y(src.y) {}
virtual ~Vector2D() {}
// Accessors
inline T X() const { return x; }
inline T Y() const { return y; }
inline T X(const T& x) { this->x = x; }
inline T Y(const T& y) { this->y = y; }
// Vector arithmetic
inline Vector2D<T> operator-() const
{ return Vector2D<T>(-x, -y); }
inline Vector2D<T> operator+() const
{ return Vector2D<T>(+x, +y); }
inline Vector2D<T> operator+(const Vector2D<T>& v) const
{ return Vector2D<T>(x+v.x, y+v.y); }
inline Vector2D<T> operator-(const Vector2D<T>& v) const
{ return Vector2D<T>(x-v.x, y-v.y); }
inline Vector2D<T> operator*(const T& s) const
{ return Vector2D<T>(x*s, y*s); }
// Dot product
inline T operator*(const Vector2D<T>& v) const
{ return x*v.x + y*v.y; }
// l-2 norm
inline T norm() const { return sqrt(x*x + y*y); }
// inner angle (radians)
static T angle(const Vector2D<T>& v1, const Vector2D<T>& v2)
{
return acos( (v1 * v2) / (v1.norm() * v2.norm()) );
}
};
int main()
{
Vector2D<double> p1(215, 294);
Vector2D<double> p2(174, 228);
Vector2D<double> p3(303, 294);
double rad = Vector2D<double>::angle(p2-p1, p3-p1);
double deg = rad * 180.0 / M_PI;
std::cout << "rad = " << rad << "\tdeg = " << deg << std::endl;
p1 = Vector2D<double>(153, 457);
p2 = Vector2D<double>(19, 457);
p3 = Vector2D<double>(15, 470);
rad = Vector2D<double>::angle(p2-p1, p3-p1);
deg = rad * 180.0 / M_PI;
std::cout << "rad = " << rad << "\tdeg = " << deg << std::endl;
return 0;
}
The code above yields:
上面的代码产生:
rad = 2.12667 deg = 121.849
rad = 0.0939257 deg = 5.38155
回答by osanchezmon
if (result > 180)
{
result = 360 - result;
}
That way it will always be the inner angle. Just add it after you get result.
这样,它将始终是内角。得到结果后添加它。
回答by msmq
If you want in between angle in 0 degree to 360 degree then use following code; Its fully tested and functional:
如果您想要在 0 度到 360 度之间的角度,请使用以下代码;它经过全面测试且功能齐全:
static inline CGFloat angleBetweenLinesInRadians(CGPoint line1Start, CGPoint line1End, CGPoint line2Start, CGPoint line2End) {
double angle1 = atan2(line1Start.y-line1End.y, line1Start.x-line1End.x);
double angle2 = atan2(line2Start.y-line2End.y, line2Start.x-line2End.x);
double result = (angle2-angle1) * 180 / 3.14;
if (result<0) {
result+=360;
}
return result;
}
}
Note:Rotation will be clockwise;
注意:旋转将是顺时针;
回答by rewritten
The whole point is much easier than the given answers:
整点比给定的答案要容易得多:
When you use atan(slope) you lose (literally) one bit of information, that is there are exactly two angles (theta) and (theta+PI) in the range (0..2*PI), which give the same value for the function tan().
当您使用 atan(slope) 时,您会丢失(字面意思)一位信息,即范围 (0..2*PI) 中恰好有两个角度 (theta) 和 (theta+PI),它们给出相同的值对于函数 tan()。
Just use atan2(deltax, deltay) and you get the right angle. For instance
只需使用 atan2(deltax, deltay) 即可获得正确的角度。例如
atan2(1,1) == PI/4
atan2(-1,-1) == 5*PI/4
Then subtract, take absolute value, and if greater than PI subtract from 2*PI.
然后减去,取绝对值,如果大于PI,则从2*PI中减去。
回答by Steve
If you use abolute value you will always get the acute angle. That is tangent theta = abs value of m1-m2 over (1 +m1 * m2). If you take inverse tangent your answer will be in radians or degrees however the calculator is set. Sorry this isnt programming lingo, I am a math teacher, not a programmer...
如果您使用绝对值,您将始终获得锐角。即切线 theta = m1-m2 在 (1 +m1 * m2) 上的绝对值。如果您取反正切,您的答案将以弧度或度数表示,但计算器已设置。抱歉,这不是编程术语,我是数学老师,不是程序员...
回答by Jorg B Jorge
Inner angle between 2 vectors (v1, v2) = arc cos ( inner product(v1,v2) / (module(v1) * module(v2)) ).
2 个向量之间的内角 (v1, v2) = arc cos ( 内积(v1,v2) / (module(v1) * module(v2)) )。
Where inner product(v1,v2) = xv1*xv2 + yv1*yv2
其中内积(v1,v2) = xv1*xv2 + yv1*yv2
module(v) = sqrt(pow(xv,2) + pow(yv,2))
模块(v) = sqrt(pow(xv,2) + pow(yv,2))
So, the answer of your question is implemented on the following example:
因此,您的问题的答案是在以下示例中实现的:
#define PI 3.14159258
int main()
{
double x1,y1,x2,y2,y3;
double m1, m2;
double mod1, mod2, innerp, angle;
cout << "x1 :";
cin >> x1;
cout << "y1 :";
cin >> y1;
cout << "x2 :";
cin >> x2;
cout << "y2 :";
cin >> y2;
cout << "y3 :";
cin >> y3;
m1 = atan((y2-y1)/(x2-x1)) * 180 / PI;
m2 = atan((y3-y1)/(x2-x1)) * 180 / PI;
mod1 = sqrt(pow(y2-y1,2)+pow(x2-x1,2));
mod2 = sqrt(pow(y3-y1,2)+pow(x2-x1,2));
innerp = (x2-x1)*(x2-x1) + (y2-y1)*(y3-y1);
angle = acos(innerp / (mod1 * mod2)) * 180 / PI;
cout << "m1 : " << m1 << endl;
cout << "m2 : " << m2 << endl;
cout << "angle : " << angle << endl;
}
回答by Blessed Geek
I hope I understand your question correctly as wanting the acute angle rather than the obtuse angle of the intersection of two lines. Am I correct?
我希望我正确理解你的问题,因为想要锐角而不是两条线相交的钝角。我对么?
Acute and obtuse angles of an intersection are 180 deg complements of each other. i.e.
交点的锐角和钝角互为 180 度互补。IE
acute + obtuse = PI.
http://www.mathworks.com/access/helpdesk/help/techdoc/ref/atan.htmlexhibits that an atan is asymptotic at +/- pi/2.
http://www.mathworks.com/access/helpdesk/help/techdoc/ref/atan.html表明 atan 在 +/- pi/2 处渐近。
Therefore, the max difference between two results of atan is pi or 180 deg, whether you use the +/-
notation or positive 0 to pi
notation of a gradient.
因此,无论您使用 梯度的+/-
表示法还是正0 to pi
表示法,atan 的两个结果之间的最大差异是 pi 或 180 度。
Consider the following pseudocode:
考虑以下伪代码:
acuteAngle(m1, m2){
a = atan(m1) - atan(m2);
// if obtuse get the complementary acute angle:
if (a>PI/2)
a = PI - a;
return a;
}
The function acuteAngle
illustrates what you need to do, mathematically.
该函数从acuteAngle
数学上说明了您需要做什么。
However, it cannot be used for values of angles in the neighbourhood of PI/2 because binary comparisons of angles with results in that neighbourhood is questionable whether an obtuse or acute angle is represented.
但是,它不能用于 PI/2 邻域中的角度值,因为角度与该邻域中的结果的二进制比较是有问题的,是表示钝角还是锐角。
Therefore, we have to compare the coordinates of the points of the two lines.
We find out whether the 3rd line formed from [(x2,y2)(x3,y3)]
is shorter, equal or longer than the hypothetical hypotenuse.
因此,我们必须比较两条线的点的坐标。我们找出由 形成的第三条线是否[(x2,y2)(x3,y3)]
比假设的斜边更短、等于或更长。
By virtue of Pythagoras' theorem, A hypotenuse is formed if the angle is exactly PI/2 or 90 deg. Let's call his hypothetical hypotenuse line L3Hypo.
根据毕达哥拉斯定理,如果角度正好是 PI/2 或 90 度,则形成斜边。让我们称他的假设斜边线为 L3Hypo。
By geometrical visualisation in your mind,
通过你头脑中的几何可视化,
- If the 3rd line is longer than L3Hypo, the angle is obtuse.
- If shorter, the angle is acute.
- Otherwise, perfect 90.
- 如果第 3 条线长于 L3Hypo,则角度为钝角。
- 如果较短,则角度为锐角。
- 否则,完美的90。
Therefore,
所以,
L1.lengthSquared = sq(x2-x1) + sq(y2-y1)
L2.lengthSquared = sq(x3-x1) + sq(y3-y1)
L3Hypo.lengthSquared = L1.lengthSquared + L2.lengthSquared
L3.lengthSquared = sq(x3-x2) + sq(y3-y2)
Therefore, the following pseudo-code,
因此,下面的伪代码,
struct Point{
double x, y;
}
// no need to struct, for clarity only
struct Line{
double lengthSquared;
}
#define sq(n) (n*n)
int isObtuse(Point P1, P2, P3){
Line L1, L2, L3, L3Hypo;
L1.lengthSquared = sq(P2.x-P1.x) + sq(P2.y-P1.y);
L2.lengthSquared = sq(P3.x-P1.x) + sq(P3.y-P1.y);
L3Hypo.lengthSquared = L1.lengthSquared + L2.lengthSquared;
L3.lengthSquared = sq(P3.x-P2.x) + sq(P3.y-P2.y);
if (L3>L3Hypo) return 1; //obtuse
else if (L3<L3Hypo) return -1; //acute
else return 0;
}
Presuming you already have the function getGradient(Point P, Q):
假设您已经拥有 getGradient(Point P, Q) 函数:
double m1m2 = getGradient(P1,P2);
double m1m3 = getGradient(P1,P3);
double a = Abs(atan(m1m2) - atan(m1m3));
if (isObtuse(P1, P2, P3)>0)
a = PI - a;
I may have committed some typo mistakes in the pseudo-code (hopefully not) but I demonstrated the gist of the concept. If so, someone could be so kind to edit away the typos.
我可能在伪代码中犯了一些拼写错误(希望不是),但我展示了这个概念的要点。如果是这样,那么有人会很友好地编辑掉错别字。
FurtherHowever, after mulling over it, I find that the struggle for precision pivots on its weakest link due to the directive
此外,经过深思熟虑后,我发现由于指令,精度的斗争转向了其最薄弱的环节
#define PI 3.14159blah..blah..blah.
So, we might as well save all the trouble and simply do this:
所以,我们不妨省去所有的麻烦,简单地这样做:
double m1m2 = getGradient(P1,P2);
double m1m3 = getGradient(P1,P3);
double a = Abs(atan(m1m2) - atan(m1m3));
double b = PI - a;
return min(a, b);//the smaller of the two is the acute
回答by Donnie
Getting the outer angle vs the inner angle is determined entirely by the order of your subtractions (think about it). You need to subtract the smaller theta from the larger in order to reliably always get the inner angle. You also probably want to use the atan2
function because of the type of data you're expecting.
获得外角与内角完全由减法的顺序决定(想想看)。您需要从较大的 theta 中减去较小的 theta,以便始终可靠地获得内角。atan2
由于您期望的数据类型,您可能还想使用该函数。