三角形 Trigonometry
October 5, 2020About 6 min
三角形 Trigonometry
角度与弧度
角度
把一个圆周平均分成360份,其中每一份都是1º的角。这种以“度”作为单位度量角度单位制叫做角度制。
下图使我们常见的180º角度尺:

弧度

长度为半径长的弧,所对的圆心角是1弧度(Radian),用符号rad表示。
半径为r的圆的圆心角α所对的弧度长为l,那么角α的弧度数的绝对值是|α| = l/r。
换算
360º = 2π rad
180º = π rad
1º =(π / 180)rad ≈ 0.01745 rad
1 rad =(180 /π)º ≈ 57.30º
α 度的角 = α ·(π / 180)rad
常用的角度与弧度对照图

三角函数
在直角三角形ABC中,∠C = 90º

- 正弦(Sine):sinA = ∠A的对边与斜边的比
- 余弦(Cosine) :cosA = ∠A的邻边与斜边的比
- 正切(Tangent):tanA = ∠A的对边与邻边的比
- sin²A + cos²A = 1
在单位圆(Unit Circle)中,任意角 α 的三角函数(Trigonometric Function)

在相似三角形 Rt△ABC 与 Rt△AB′C′ 中,对于∠A,对边与斜边的比是一致的,邻边与斜边的比也是一致的。所以我们力求简单与方便计算,设定斜边为1,单位圆刚好能满足这个条件。
- 圆的圆心与直角坐标系的原点重合,圆的半径 r = 1,圆周上任意一点的坐标为(x, y)
- 自变量为角 α
- 函数是圆周上的坐标,或坐标和坐标的比值:sin α = y,cos α = x,tan α = y / x (x≠0)
三角函数在各个象限的取值
第一象限 | 第二象限 | 第三象限 | 第四象限 | x轴 | y轴 | |
---|---|---|---|---|---|---|
sin α | >0 | >0 | <0 | <0 | 0 | ±1 |
cos α | >0 | <0 | <0 | >0 | ±1 | 0 |
tan α | >0 | <0 | >0 | <0 | 0 | / |
正弦曲线

- y = sin x, x∈R, y∈[–1,1],周期为2π,函数图像以 x = (π/2) + kπ 为对称轴
- y = arcsin x, x∈[–1,1], y∈[–π/2,π/2]
- sin x = 0 ←→ arcsin x = 0
- sin x = 1/2 ←→ arcsin x = π/6
- sin x = √2/2 ←→ arcsin x = π/4
- sin x = 1 ←→ arcsin x = π/2
余弦曲线

- y = cos x, x∈R, y∈[–1,1],周期为2π,函数图像以 x = kπ 为对称轴
- y = arccos x, x∈[–1,1], y∈[0,π]
- cos x = 0 ←→ arccos x = π/2
- cos x = 1/2 ←→ arccos x = π/3
- cos x = √2/2 ←→ arccos x = π/4
- cos x = 1 ←→ arccos x = 0
三角函数线

图中的三条彩色线段 MP、OM、AT,分别叫正弦线、余弦线、正切线,统称为三角函数线
曲线视频
一些公式
平方
任意角α与-α的三角函数值之间的关系
两角和与差
常见问题
一个点是否在三角形中?
我们可以简单的观察下面两种情况:
- P点在△ABC外:
- P点在△ABC内:
可以看得出如果P点在三角形内的话,P点都在三角形边向量的左侧。我们是如何来判断一点在一个向量的某一边呢?我们知道两个向量的叉乘的结果可以判断这个两个向量是否同向,我们这里计算出每条边与边的起始点与P点连接的线段的叉乘,来判断点P是否与每条边同向,可以列出式子:
- Corss(AB,AP)
- Corss(BC,BP)
- Corss(CA,CP)
如果说这三个结果都为正,那么说明P点都在三角形的三边的一侧。简单的实现:
static bool insideTriangle(int x, int y, const Vector3f* _v)
{
// Implement this function to check if the point (x, y)
// is inside the triangle represented by _v[0], _v[1], _v[2]
Vector3f point(x + 0.5f, y + 0.5f, 1);
for (int i = 0; i < 3; i++)
{
Vector3f triangle2point = point - _v[i];
int index = (i + 1) % 3;
Vector3f triangleP2P = _v[index] - _v[i];
// case x , y cross equal z
if (triangleP2P.cross(triangle2point).z() < 0)
{
return false;
}
}
return true;
}
三角形重心
设P点的坐标(α, β, γ),为三角形的重心坐标。
我们这里简单的推导一下,:
- 根据向量的线性相关:AP = βAB + γAC
- 拆分上面式子:A - P = β(A - B) + γ(A - C)
- 整理得到:P = (1-β-γ)A + βB + γC = αA + βB + γC
- α = 1 - γ - β
- 0 < α < 1, 0 < β < 1, 0 < γ < 1
从上面可以看出这里的重心点P可以有很多值,只需要满足以上列举出来的规则。
我们使用距离比例算法来简单的推导实现,我们知道当α = 0 时,点p在BC线上,当α = 1 时,点p就是点A。我们可以简单认为 α 的值就是A点到BC线距离的比例,不过是反比例。因为一个点带入一个直线方程求到的解就是该点到方程的近似距离,然后就可以列出计算方式:(这里的0、1、2表示的是三角形的三个顶点的索引,也就是A、B、C点)
- α = f12(x, y)/f12(x0, y0) :点 P 到 BC 线的距离与点 A 到 BC 线的距离的比例
- β = f20(x, y)/f20(x1, y1) :点 P 到 CA 线的距离与点 B 到 CA 线的距离的比例
- γ = f01(x, y)/f01(x2, y2) :点 P 到 AB 线的距离与点 C 到 AB 线的距离的比例
我们可以根据直线公式获得:
- f01(x, y)=(y0 − y1)x + (x1 − x0)y + x0y1 − x1y0,
- f12(x, y)=(y1 − y2)x + (x2 − x1)y + x1y2 − x2y1,
- f20(x, y)=(y2 − y0)x + (x0 − x2)y + x2y0 − x0y2.
最终就可以求解出这个坐标,简单实现:
static std::tuple<float, float, float> computeBarycentric2D(float x, float y, const Vector4f *v)
{
float c1 = (x * (v[1].y() - v[2].y()) + (v[2].x() - v[1].x()) * y + v[1].x() * v[2].y() - v[2].x() * v[1].y()) / (v[0].x() * (v[1].y() - v[2].y()) + (v[2].x() - v[1].x()) * v[0].y() + v[1].x() * v[2].y() - v[2].x() * v[1].y());
float c2 = (x * (v[2].y() - v[0].y()) + (v[0].x() - v[2].x()) * y + v[2].x() * v[0].y() - v[0].x() * v[2].y()) / (v[1].x() * (v[2].y() - v[0].y()) + (v[0].x() - v[2].x()) * v[1].y() + v[2].x() * v[0].y() - v[0].x() * v[2].y());
float c3 = (x * (v[0].y() - v[1].y()) + (v[1].x() - v[0].x()) * y + v[0].x() * v[1].y() - v[1].x() * v[0].y()) / (v[2].x() * (v[0].y() - v[1].y()) + (v[1].x() - v[0].x()) * v[2].y() + v[0].x() * v[1].y() - v[1].x() * v[0].y());
return {c1, c2, c3};
}