两条线之间的内角

发布于 2024-09-03 19:45:30 字数 588 浏览 8 评论 0原文

我有两条线路:Line1 和 Line2。每条线由两个点 (P1L1(x1, y1), P2L1(x2, y2)P1L1(x1, y1), P2L3(x2, y3)) 定义。我想知道这两条线定义的内角。

为此,我计算每条线与横坐标的角度:

double theta1 = atan(m1) * (180.0 / PI);
double theta2 = atan(m2) * (180.0 / PI);

在知道角度后,我计算以下内容:

double angle = abs(theta2 - theta1);

我遇到的问题或疑问是:有时我得到正确的角度,但有时我得到互补的角度(对于我来说,外部)。我怎么知道什么时候减去180°才能知道内角?有没有更好的算法可以做到这一点?因为我尝试了一些方法:点积, 以下公式:

result = (m1 - m2) / (1.0 + (m1 * m2));

但我总是遇到同样的问题;我从来不知道我什么时候有外角或内角!

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.

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 180º to know the inner angle? There is any algorithm better to do that? Because I tried some methods: dot product,
following formula:

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!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

树深时见影 2024-09-10 19:45:30

我认为您正在寻找的是 内部产品 (您可能还想查看两个角度的点积条目)。在你的情况下,这是由以下给出的:

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

答案以弧度为单位。

编辑:这是一个完整的实现。将有问题的值替换到 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;
}

上面的代码产生:

rad = 2.12667   deg = 121.849
rad = 0.0939257 deg = 5.38155

I think what you're looking for is the inner product (you may also want to look over the dot product entry) 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.

#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

隱形的亼 2024-09-10 19:45:30
if (result > 180)
{
     result = 360 - result;
}

这样它就永远是内角。得到结果后添加即可。

if (result > 180)
{
     result = 360 - result;
}

That way it will always be the inner angle. Just add it after you get result.

落花浅忆 2024-09-10 19:45:30

如果您想要介于 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;

}

注意: 旋转将为顺时针方向;

If you want in between angle in 0 degree to 360 degree then use following code; Its fully tested and functional:

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;

我也只是我 2024-09-10 19:45:30

整点比给出的答案容易得多:

当您使用 atan(slope) 时,您会丢失(字面意思)一点信息,即在范围 (0. .2*PI),它为函数 tan() 提供相同的值。

只需使用 atan2(deltax, deltay) 即可获得正确的角度。例如

atan2(1,1) == PI/4
atan2(-1,-1) == 5*PI/4

然后减去,取绝对值,如果大于PI则从2*PI中减去。

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().

Just use atan2(deltax, deltay) and you get the right angle. For instance

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.

凶凌 2024-09-10 19:45:30

2 个向量之间的内角 (v1, v2) = arc cos ( 内积 (v1,v2) / (module(v1) * module(v2)) )。

其中内积(v1,v2) = xv1*xv2 + yv1*yv2

module(v) = sqrt(pow(xv,2) + pow(yv,2))

因此,您的问题的答案是在以下示例中实现的:

#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;
}

Inner angle between 2 vectors (v1, v2) = arc cos ( inner product(v1,v2) / (module(v1) * module(v2)) ).

Where inner product(v1,v2) = xv1*xv2 + yv1*yv2

module(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;
}
谜兔 2024-09-10 19:45:30

如果您使用绝对值,您将始终得到锐角。即切线 theta = m1-m2 在 (1 +m1 * m2) 上的绝对值。如果您采用反正切,则无论计算器如何设置,您的答案都将以弧度或度为单位。抱歉,这不是编程术语,我是数学老师,不是程序员......

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...

水溶 2024-09-10 19:45:30

获得外角与内角完全取决于减法的顺序(想一想)。您需要从较大的 theta 中减去较小的 theta,以便始终可靠地获得内角。由于您期望的数据类型,您可能还想使用 atan2 函数。

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.

奢华的一滴泪 2024-09-10 19:45:30

我希望我正确理解你的问题,因为想要两条线相交的锐角而不是钝角。我说得对吗?

相交的锐角和钝角互为 180 度余角。即

 acute + obtuse = PI.

http://www.mathworks.com/access/helpdesk /help/techdoc/ref/atan.html
证明 atan 在 +/- pi/2 处渐近。

因此,atan 的两个结果之间的最大差异是 pi 或 180 度,无论您使用梯度的 +/- 表示法还是正的 0 到 pi 表示法。

考虑以下伪代码:

acuteAngle(m1, m2){
  a = atan(m1) - atan(m2);

  // if obtuse get the complementary acute angle:
  if (a>PI/2) 
    a = PI - a;
  return a;
} 

函数 acuteAngle 从数学角度说明了您需要执行的操作。

然而,它不能用于 PI/2 邻域中的角度值,因为无论表示钝角还是锐角,角度与该邻域中结果的二元比较都是有问题的。

因此,我们必须比较两条线的点的坐标。
我们找出由 [(x2,y2)(x3,y3)] 组成的第三条线是否比假设的斜边短、等于或长。

凭借毕达哥拉斯定理,
如果角度恰好为 PI/2 或 90 度,则会形成斜边。我们把他假设的斜边线称为 L3Hypo。

通过头脑中的几何可视化,

  • 如果第三条线长于
    L3Hypo,钝角。
  • 如果较短,则角度是锐角。
  • 否则,完美90。

因此,

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)

因此,下面的伪代码,

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

假设你已经有了这个功能
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;

我可能在伪代码中犯了一些拼写错误(希望没有),但我演示了这个概念的要点。如果是这样,有人可能会很友善地编辑掉拼写错误。

进一步
然而,经过深思熟虑,我发现由于指令的原因,精确度的斗争集中在其最薄弱的环节

#define PI 3.14159blah..blah..blah.

,所以,我们不妨省去所有麻烦,简单地这样做:

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

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.

 acute + obtuse = PI.

http://www.mathworks.com/access/helpdesk/help/techdoc/ref/atan.html
exhibits that an atan is asymptotic at +/- 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.

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.

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.

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.

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.

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.

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

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.

Further
However, 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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文