GIS算法的计算几何基础(1)
一、实验目标
1. 矢量叉积计算
要求从键盘上输入数据,计算叉积
分析输入两个矢量的坐标信息,输出其二者的叉积,应用矢量叉积公式
2. 折线拐向判断
要求从键盘上输入数据,判断其拐向
分析输入折线的端点坐标,输出折线的拐向信息,应用矢量叉积公式
3. 判断矩形是否包含点
要求从键盘上输入点与矩形,判断点是否在矩形内
分析输入点坐标和矩形的一对对顶点,输出点是否在矩形内的判断结果
二、基本原理
1. 矢量叉积计算
2. 折线拐向判断
将两段折线P0P1P_0P_1P0P1、P0P2P_0P_2P0P2抽象成两个矢量P、Q,由矢量叉乘的定义:
① P×Q>0P×Q > 0P×Q>0,P在Q的顺时针方向 => 折线在P1P_1P1处右拐
② P×Q=0P×Q = 0P×Q=0,P与Q共线 => P0、P1、P2P_0、P_1、P_2P0、P1、P2三点共线
③ P×Q<0P×Q < 0P×Q<0,P在Q的逆时针方向 => 折线在P1P_1P1处左拐

转化为数学表达式: P0(x0,y0)、P1(x1,y1)、P2(x2,y2)=>P×Q=(x2−x0)(y1−y0)−(x1−x0)(y2−y0)P_0(x_0, y_0)、P_1(x_1, y_1)、P_2(x_2, y_2) => P×Q = (x_2-x_0)(y_1-y_0) - (x_1-x_0)(y_2-y_0)P0(x0,y0)、P1(x1,y1)、P2(x2,y2)=>P×Q=(x2−x0)(y1−y0)−(x1−x0)(y2−y0)
3. 判断矩形是否包含点
在坐标系中,确定一个矩形需要四个参数:xmin、xmax、ymin、ymaxx_{min}、x_{max}、y_{min}、y_{max}xmin、xmax、ymin、ymax,仅需一对对顶点即可获取上述的四个参数,如:
P1、P1′:x1=xmin、y1=ymin、x1′=xmax、y1′=ymaxP_1、P_1': x_1 = x_{min} 、y_1 = y_{min} 、x_1' = x_{max} 、y_1' = y_{max}P1、P1′:x1=xmin、y1=ymin、x1′=xmax、y1′=ymax P2、P2′:x2=xmin、y2=ymin、x2′=xmax、y2′=ymaxP_2、P_2': x_2 = x_{min} 、y_2 = y_{min} 、x_2' = x_{max} 、y_2' = y_{max}P2、P2′:x2=xmin、y2=ymin、x2′=xmax、y2′=ymax

若xmin<x0<xmaxx_{min} < x_0 < x_{max}xmin<x0<xmax且ymin<y0<ymaxy_{min} < y_0 < y_{max}ymin<y0<ymax则点在矩形内部
三、实现思路
1. 矢量叉积计算
① 用结构体来保存矢量,为保障程序处理数据的多样性,矢量的两个分量使用双精度类型来定义
typedef struct {
double x;
double y;
} Vector;
② 运用“原理”中推出的数学表达式,编写函数计算矢量叉积
double operation(Vector v1, Vector v2){
return (v1.x*v2.y) - (v1.y*v2.x);
}
③ 在主函数中读入用户输入的矢量,并调用运算函数计算出结果,将结果打印出来
int main(){
Vector v1,v2;
printf("请输入第一个矢量:");
scanf("%lf,%lf",&v1.x,&v1.y);
printf("请输入第二个矢量:");
scanf("%lf,%lf",&v2.x,&v2.y);
double result = operation(v1,v2);
printf("叉乘结果为%.1lf\n",result);
return 0;
}
2. 折线拐向判断
① 用结构体来保存线段的端点,为保障程序处理数据的多样性,点的x、y坐标值使用双精度类型来定义
typedef struct {
double x;
double y;
} Point;
② 构造函数来判断折线的拐向。将折线抽象成共起点的两个矢量,使用矢量叉乘结果(转为整型)的正负来判断折线的拐向,并直接打印出来
void Judge(Point P1, Point P2, Point P0){
int product;
product= (int)(P2.x-P0.x)*(P1.y-P0.y)-(P1.x-P0.x)*(P2.y-P0.y);
if(product>0){
printf("折线在P1点右拐");
}
else if(product<0)
printf("折线在P1点左拐");
else if(product==0)
printf("三个点在一条直线上");
}
③ 在主函数中读入用户输入的矢量,并调用运算函数计算出结果
int main(){
//输入线段的两个点P1和P2
Point P1,P2,P0;
printf("请依次输入线段的顶点和两个端点\n");
scanf("%lf,%lf",&P0.x,&P0.y);
scanf("%lf,%lf",&P1.x,&P1.y);
scanf("%lf,%lf",&P2.x,&P2.y);
//使用函数进行判断
Judge(P1, P2, P0);
return 0;
}
3. 判断矩形是否包含点
① 用结构体来保存线段的端点,为保障程序处理数据的多样性,点的x、y坐标值使用双精度类型来定义
typedef struct {
double x;
double y;
} Point;
② 构造最大最小值函数用于判断矩形对顶点坐标的最大最小值
double Max(double x, double y){
return x>y?x:y;
}
double Min(double x, double y){
return x<y?x:y;
}
③ 构造函数判断点是否在矩形中。由前文中的“原理”可知,仅需一对对顶点即可确定矩形的坐标范围,使用flag变量返回0和1来表达是和否
int Judge(Point P1, Point P2, Point P0){
int flag;
if (((P1.x<=P0.x)&&(P1.y<=P0.y))&&((P2.x>P0.x)&&(P2.y>P0.y)))
return flag=1;
else
return flag=0;
}
④ 在main函数中获取用户输入的信息,调用最大最小值函数确定矩形的范围,将值传递进判断函数中进行判断,最后输出判断结果
int main(){
//输入线段的两个点P1和P2
Point P1,P2;
double x1,x2,y1,y2;
printf("请输入矩形的两个对顶点\n");
scanf("%lf,%lf",&x1,&y1);
getchar(); // 吸收回车键
scanf("%lf,%lf",&x2,&y2);
getchar(); // 吸收回车键
P1.x = Min(x1,x2);
P2.x = Max(x1,x2);
P1.y = Min(y1,y2);
P2.y = Max(y1,y2);
//输入待判断的点坐标
Point P0;
printf("请输入待判断的点坐标\n");
scanf("%lf,%lf",&P0.x,&P0.y);
//使用函数进行判断
int judgement = Judge(P1, P2, P0);
if(judgement)
printf("点在矩形内部");
else{
printf("点在矩形外部");
}
return 0;
}
四、测试及运行
1. 矢量叉积计算
验证数据选取P1(1,1)、P2(1,2)P_1(1,1)、P_2(1,2)P1(1,1)、P2(1,2),计算结果应为1.0,使用程序运行该组数据,输出结果与预期结果一致。

2. 折线拐向判断
验证数据选取P0(1,1)、P1(1,2)、P2(2,1)P_0(1,1)、P_1(1,2)、P_2(2,1)P0(1,1)、P1(1,2)、P2(2,1)以及P0(1,1)、P1(2,1)、P2(1,2)P_0(1,1)、P_1(2,1)、P_2(1,2)P0(1,1)、P1(2,1)、P2(1,2),两次的结果应分别为右拐和左拐,使用程序运行该组数据,输出结果与预期结果一致。
3. 判断矩形是否包含点
验证数据选取以点(1,1)、(1,3)、(3,3)、(3,1)(1,1)、(1,3)、(3,3)、(3,1)(1,1)、(1,3)、(3,3)、(3,1)为顶点的矩形和点P0(2,2.5)P_0(2,2.5)P0(2,2.5),为确保不同对顶点能得到相同的结果,分别输入了主对角线对顶点以及副对角线对顶点,均得到相同且正确的结果

转载自:https://juejin.cn/post/7346419290199048218