三角形:海伦公式
S = 1 2 ( x 1 y 2 + x 2 y 3 + x 3 y 1 − x 1 y 3 − x 2 y 1 − x 3 y 2 ) ; S = \frac 12 (x1y2+x2y3+x3y1-x1y3-x2y1-x3y2); S=21(x1y2+x2y3+x3y1−x1y3−x2y1−x3y2);
//三角形面积
double sTriangulation1(vector<double>x, vector<double>y) {
//海伦公式
double S =0.5* ((x[0]*y[1] + x[1]*y[2] + x[2]*y[0]) - (x[1]*y[0] + x[2]*y[1] + x[0]*y[2]));
if (S < 0)
return -S;
return S;
}
double sTriangulation2(vector<double>x, vector<double>y) {
//向量 与原点
int n = x.size();
double sum = 0;
for (int i = 0; i < n; i++) {
sum += 0.5 * (x[i]*y[(i+1)%n]-x[(i+1)%n]*y[i]);
}
if (sum < 0)
sum = -sum;
return sum;
}
多边形面积
考虑有凹边形,统一使用 向量 计算面积的方式,有正负
思路 : 向量法 (点数组需要时顺/逆时针排序的)
- S A B C = 1 2 A B → ∗ B C → S_{ABC} =\frac 1 2\overrightarrow{AB} * \overrightarrow{BC} SABC=21AB∗BC
- 以 原点(0,0) 为 第一个点,那么三角学的面积可以写成
S A B C = S O B C − S O A B − S O A C S_{ABC}=S_{OBC}-S_{OAB}-S_{OAC} SABC=SOBC−SOAB−SOAC
这里默认 BC是最远的边,但一般不知是哪个边,无法提前确认+ -,故都使用 向量去做- S A B C = S O A B + S O B C + S O C A S_{ABC}=S_{OAB}+S_{OBC}+S_{OCA} SABC=SOAB+SOBC+SOCA
(上一个结束点 是下一个开始点 循环到第一个开始点)- 同理 五边形ABCDE有:
S A B C D E = S O A B + S O B C + S O C D + S O D E + S O E A S_{ABCDE}=S_{OAB}+S_{OBC}+S_{OCD}+S_{ODE}+S_{OEA} SABCDE=SOAB+SOBC+SOCD+SODE+SOEA
对于一个 S O A B S_{OAB} SOAB的计算公式; 其中 A ( x 1 , y 1 ) , B ( x 2 , y 2 ) A(x_1,y_1),B(x_2,y_2) A(x1,y1),B(x2,y2):
S = 1 2 0 A → ∗ 0 B → = 1 2 ( x 1 ∗ y 2 − x 2 ∗ y 1 ) S=\frac 1 2\overrightarrow{0A} * \overrightarrow{0B}=\frac12(x_1*y_2-x_2*y_1) S=210A∗0B=21(x1∗y2−x2∗y1)
//x={1,0,-1,0},y={0,1,0,-1}; S=2.0
//x={0,1,0},y={0,0,1}; S=0.5
double SumTriangulation(vector<double>x, vector<double>y) {
//看成任意两边间与原点的面积(有正负)//N个 最后一个是OEA
int n = x.size();//n个点 有n-1次
vector<double> sum;
double s = 0.0;
for (int i = 0; i < n-1; i++) {
s= 0.5 * (x[i] * y[i + 1] - x[i + 1]*y[i]);
sum.push_back(s);
}
//最后一个三角形 OEA
s= 0.5 * (x[n-1] * y[0] - x[0] * y[n-1]);
sum.push_back(s);
s = 0;
//输出看看
for (int i = 0; i < sum.size(); i++) {
cout << sum[i] << " ";
s += sum[i];
}
cout <<endl;
return s;
}
P点是否在多边形内
思路:射线法 (默认时顺/逆时针排序的)
- 通过p点引出一条 水平右射线
- 判断射线与 多边形的边的交点和数量,奇数就是在内
- 特殊边界:
- 交点刚好是多边形的点,不算
- 交点在左边,不算
- 加速判断 P(x,y) 与 边 ( x 1 , y 1 ) , ( x 2 , y 2 ) (x_1,y_1),(x_2,y_2) (x1,y1),(x2,y2)
- y > = m a x ( y 1 , y 2 ) y>=max(y_1,y_2) y>=max(y1,y2), 没有
- y < = m i n ( y 1 , y 2 ) y<=min(y_1,y_2) y<=min(y1,y2),没有 (这两包含了 交点刚好是边的情况)
- x > = m a x ( x 1 , x 2 ) x>=max(x_1,x_2) x>=max(x1,x2),没有
- y 1 = = y 2 y_1==y_2 y1==y2 ,边水平,没有
- 利用两点式,求出 交点 X
两点式: y − y 1 X − x 1 = y 2 − y 1 x 2 − x 1 = \frac{y-y_1}{X-x_1}=\frac{y_2-y_1}{x_2-x_1}= X−x1y−y1=x2−x1y2−y1=
转化为: X = ( y − y 1 ) ∗ ( x 2 − x 1 ) ( y − y 1 ) + x 1 X=\frac{(y-y_1)*(x_2-x_1)}{(y-y_1)}+x_1 X=(y−y1)(y−y1)∗(x2−x1)+x1
//点在多边面内
//map<pair<int,int>>(x,y)
bool PtInPolygon(vector<double>x, vector<double>y, double px, double py) {
int n = x.size();
int count = 0;
for (int i = 0; i < n; i++) {
//判断 是否跳过
if(y[i]==y[(i + 1) % n]) continue;
if(py>= max(y[i], y[(i + 1) % n])) continue;
if(py<= min(y[i], y[(i + 1) % n])) continue;
if(px>= max(x[i], x[(i + 1) % n])) continue;
//两点式
double X = ((y[(i + 1) % n] - y[i]) * (x[(i + 1) % n])/(py-y[i]) - x[i]) + x[i];
if (X > px) //还是有出现在左边的情况 去掉
count++;
}
if (count % 2 == 1)
return true;
return false;
}