算法就不介绍了,其他地方应该也搜得到。
如何判断三点A, B, C连线是逆时针?
(1) 通过判断C在AB连线上方还是下方判断,但需要根据斜率的正负,A, B位置关系分类讨论,比较麻烦。
(2) 通过计算向量叉积的方法。
在一般的常识或者教科书中规定叉乘只有3维才拥有,其实2维也可以拓展出来一个叉乘形式。
拓展方式:假设有两个2维向量a,b,我们直接把他们视为3维向量,z轴补0,那么这个时候的a,b向量的叉乘结果c,c.x=0,c.y=0,c.z=a.x* b.y-b.x *a.y。
有这样的性质:设k是a,b向量的叉积,如果k>0时,那么a正旋转到b的角度为<180°,如果k<0,那么a正旋转到b的角度为>180°,如果k=0 那么a,b向量平行。
代码
#include<stdio.h>
#include<math.h>
#include<time.h>
#include<stdlib.h>
#define PI 3.14159
typedef struct Point {
int x, y;
double angle;
}Point;
int less(Point a, Point b) { //定义点a小于点b法则(排序用)
if (a.angle != b.angle) return a.angle < b.angle;
else return a.x < b.x;
}
int ifAnticlockwise(Point a, Point b, Point c) { //是否为逆时针
int crossProduct = (b.x - a.x)*(c.y - b.y) - (b.y - a.y)*(c.x - b.x); //求向量积
return crossProduct >= 0; //向量积为正表示逆时针
}
int main() {
srand((unsigned)time(NULL));
int n, minx, maxx, miny, maxy;
scanf("%d%d%d%d%d", &n, &minx, &maxx, &miny, &maxy);
Point point[105];
for (int i = 0; i < n; i++) { //生成随机座标
point[i].x = rand() % (maxx - minx + 1) + minx;
point[i].y = rand() % (maxy - miny + 1) + miny;
}
double sx = 1000, sy = 1000;
for (int i = 0; i < n; i++) { //寻找起始点
if (point[i].y < sy) sx = point[i].x, sy = point[i].y;
else if (point[i].y == sy && point[i].x < sx) sx = point[i].x;
}
for (int i = 0; i < n; i++) { //求夹角
if (point[i].x == sx && point[i].y == sy) point[i].angle = 0;
else if (point[i].x == sx) point[i].angle = 90;
else {
point[i].angle = atan((point[i].y - sy)*1.0 / (point[i].x - sx));
if (point[i].angle < 0) point[i].angle = PI + point[i].angle;
//转换为与x轴正方向夹角
}
}
for (int i = 0; i < n - 1; i++) {
for (int j = i + 1; j < n; j++) { //冒泡排序
if (less(point[j], point[i])) {
Point temp = point[i];
point[i] = point[j];
point[j] = temp;
}
}
}
int cnt = 3; //栈顶指针
for (int i = 3; i < n; i++) {
if (ifAnticlockwise(point[cnt - 2], point[cnt - 1], point[i])) {
point[cnt++] = point[i]; //模拟入栈
}
else point[cnt - 1] = point[i]; //模拟出栈+入栈
}
for (int i = cnt - 1; i >= 0; i--) { //逆序输出
printf("%4d %4d ", point[i].x, point[i].y);
}
return 0;
}
程序测试
为了验证程序的正确性,先缩小了样本,随机生成横纵座标都在-10~10范围内的6个点,输出第一行为随机生成的6个点的横纵座标,接着输出结果。将点在matlab中绘制,可以验证程序正确。