第三章课后习题(判断是否为多边形图形,求多边形面积)——程序设计艺术与方法实验三 计算几何
分析:
判断能否构成多边形,即判断是否存在两直线相交:两直线互相跨立;或一条线段的一个端点在另一条线段上
求多边形面积:取一顶点与其它顶点相连,相邻的边做向量积再除以2;也就是求每个三角形的面积。
代码:
#include<bits/stdc++.h>
using namespace std;
struct Point{//构造一个点的结构
double x, y;
Point() {}
Point(double _x, double _y){//构造函数
x = _x;
y = _y;
}
Point operator -(const Point& b) const {
return Point(x - b.x, y - b.y);
}
};
double crossProduct(Point p, Point p1, Point p2){//用来求叉积 p.p1叉乘p.p2
Point a = p1 - p;
Point b = p2 - p;//两个向量
return a.x * b.y - b.x * a.y;
}
bool isIntersect(Point a1, Point a2, Point b1, Point b2){//该函数用来判断线段a1.a2 与 线段 b1.b2是否相交
//这个if是快速排斥实验的条件
if (min(a1.x, a2.x) <= max(b1.x, b2.x) && min(b1.x, b2.x) <= max(a1.x, a2.x) &&
min(a1.y, a2.y) <= max(b1.y, b2.y) && min(b1.y, b2.y) <= max(a1.y, a2.y)){
//在满足快速排斥实验的基础上我们再进行跨立实验
double c1 = crossProduct(a1, b1, a2);//a1b 叉乘 a1a2
double c2 = crossProduct(a1, b2, a2);//a1b2 叉乘 a1a2
double c3 = crossProduct(b1, a1, b2);//b1a1 叉乘 b1b2
double c4 = crossProduct(b1, a2, b2);//b1a2 叉乘 b1b2
if (c1 * c2 <= 0 && c3 * c4 <= 0) return true; //两条直线相互跨立则返回true
}
return false;
}
bool isPolygon(vector<Point> points){//判断是否是合格的多边形
for (int i = 2; i < points.size() - 1; i++){//从第2条边开始判断第i条边与从第0条边开始不相邻的边是否相交 (说明:我们的边和点都是从0开始计数)
for (int j = 0; j < i - 1; j++){
if (isIntersect(points[i], points[i + 1], points[j], points[j + 1]))
return false;
}
}
//因为最后一条边的终点与起点相连 所以单独来一个for循环讨论
for (int j = 1; j < points.size() - 2; j++){
if (isIntersect(points[points.size() - 1], points[0], points[j], points[j + 1]))
return false;
}
return true;
}
double getArea(vector<Point> points){//叉积求面积
Point p0 = points.front();
double S = 0;
for (int i = 1; i < points.size() - 1; i++){
S += crossProduct(p0, points[i], points[i + 1]);
}
return fabs(S / 2.0);
}
int main(){
vector<Point> points;
int n = 0;
int i = 1;
double x, y;
while (cin >> n && n){
if (n < 3) cout << "Figure " << i << ": " << "Impossible !" << endl; // 点的个数小于3 则直接pass
else {
for (int j = 0; j < n; j++){
cin >> x >> y;
points.push_back(Point(x, y));//把点压入容器中
}
if (isPolygon(points)){//如果可以构成多边形则计算面积
double S = getArea(points);
cout << "Area";
cout << "Figure " << i << ": " << S << endl;
}
else{
cout << "Figure " << i << ": " << "Impossible !" << endl;
}
}
points.clear();//每回计算完毕清空容器进行下一次计算
i++;
}
return 0;
}
运行结果:
思考:
若一条线段端点在另一线段(除端点)上,则无法构成多边形;
若一条线段端点与另一线段的端点重合,则可能构成多边形。但若三条线段端点重合则无法形成多边形。