【翻译】计算机几何基础算法(三)

本文介绍了一种用于计算凸包的算法及其性能,并探讨了如何通过叉乘判断多边形内点的位置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

凸包

对于一组点,能将所有点包含在内的最小的凸多边形就是所谓的凸包。这个凸包是有该组点中的若干点组成的。可以想象这些点是一块板上钉的钉子,用一个弹性很好的橡皮筋箍住所有的点,那么这条橡皮筋所形成的多边形就是凸包。有很多种不同的算法可以计算凸包,本文中,我们将讨论其中一种算法,该算法在大多数情况下的性能足够好,但是比起其他一些算法还是相当慢的。


首先,我们可以遍历所有点,找到最左边的点(x最小),如果有两个以上的点的x相同,那么我们取最高的那个点(y最大)。显然该点必然是凸包上的一个点,我们就设该点P为起点。现在我们以顺时针方向遍历所有的点。这里我们要使用叉乘算子。如何确定哪一个点是下一个点呢?我们可以任选一个未用的点N作为下一个点,然后遍历所有其他未用的点,假设是X。如果(X-P) x (N-P) 是负的,我们将X设为新的下一个点N。在我们遍历所有点后,得到的点N就是凸包上的下一个点。下面的图示表明了该算法的步骤:


接着同样的方法我们可以找到凸包的下一个点,直到我们返回起点。

这里我们是使用叉乘寻找顺时针的下一个点是很容易理解的。不过在有几点共线的时候,事情稍稍有点复杂。假设不考虑共线的情况,代码很简单:

convexHull(point[] X){
int N = lengthof(X);
int p = 0;
//First find the leftmost point
for(int i = 1; i<N; i++){
if(X[i] < X[p])
p = i;
}
int start = p;
do{
int n = -1;
for(int i = 0; i<N; i++){
//Don't go back to the same point you came from
if(i == p)continue;
//If there is no N yet, set it to i
if(n == -1)n = i;
int cross = (X[i] - X[p]) x (X[n] - X[p]);
if(cross < 0){
//As described above, set N=X
n = i;
}
}
p = n;
}while(start!=p);
}

如果考虑共线的情况,代码稍微复杂一些。首先我们添加一个bool型的参数,该参数指定线上的点是否记为凸包上的点。

//If onEdge is true, use as many points as possible for
//the convex hull, otherwise as few as possible.
convexHull(point[] X, boolean onEdge){
int N = lengthof(X);
int p = 0;
boolean[] used = new boolean[N];
//First find the leftmost point
for(int i = 1; i<N; i++){
if(X[i] < X[p])
p = i;
}
int start = p;
do{
int n = -1;
int dist = onEdge?INF:0;
for(int i = 0; i<N; i++){
//X[i] is the X in the discussion
//Don't go back to the same point you came from
if(i==p)continue;
//Don't go to a visited point
if(used[i])continue;
//If there is no N yet, set it to X
if(n == -1)n = i;
int cross = (X[i] - X[p]) x (X[n] - X[p]);
//d is the distance from P to X
int d = (X[i] - X[p]) (X[i] - X[p]);
if(cross < 0){
//As described above, set N=X
n = i;
dist = d;
}else if(cross == 0){
//In this case, both N and X are in the
//same direction. If onEdge is true, pick the
//closest one, otherwise pick the farthest one.
if(onEdge && d < dist){
dist = d;
n = i;
}else if(!onEdge && d > dist){
dist = d;
n = i;
}
}
}
p = n;
used[p] = true;
}while(start!=p);
}

(译注:该算法复杂度为O(N^2),有更好的算法,复杂度为O(NLogN),参见维基:

http://zh.wikipedia.org/w/index.php?title=%E5%87%B8%E5%8C%85&variant=zh-cn

http://en.wikipedia.org/wiki/Convex_hull_algorithms

多边形内点

给出一个任意多边形的顶点和一个点,测试该点是否在多边形内、外或边上。

这个问题可以简单使用线-线交点和点-线距离的算法。

首先我们可以使用点-线距离来测试该点是否在边上。如果该点到任意一条边的距离为0,那么显然是在边上。

然后,我们要检测该点是否在多边形内部。想象一下以该点为起点,向任意方向画一条射线,每一次该射线和边相交,该射线就由多边形内部穿越到外部或相反。这样,如果该点在多变形内部,该射线必然和边相交奇数次。技术上我们不需要真的画一条无限长的射线,我们只要有一足够长的线段即可。如果另一端点没有选好,你有时会陷入困境,例如线段两点均在多边形内部或和某一条边重合。简单但是龌龊的做法是用一个足够大随机数作为线段的另一个端点,这个方法虽然不优美且不安全,但是在实践中它管用。这线段和某一条边重合的概率是如此之小以至于你可以拍胸脯说可以得到正确的解答。如果你还是不放心,你可以选几个随机点,然后返回最普遍的答案。

String testPoint(verts, x, y){
int N = lengthof(verts);
int cnt = 0;
double x2 = random()*1000+1000;
double y2 = random()*1000+1000;
for(int i = 0; i<N; i++){
if(distPointToSegment(verts[i],verts[(i+1)%N],x,y) == 0)
return "BOUNDARY";
if(segmentsIntersect((verts[i],verts[(i+1)%N],{x,y},{x2,y2}))
cnt++;
}
if(cnt%2 == 0)return "EXTERIOR";
else return "INTERIOR";
}

内容概要:本文档提供了关于“微型车间生产线的设计与生产数据采集试验研究”的毕业设计复现代码,涵盖从论文结构生成、机械结构设计、PLC控制系统设计、生产数据采集与分析系统、有限元分析、进度管理、文献管理和论文排版系统的完整实现。通过Python代码和API调用,详细展示了各个模块的功能实现和相互协作。例如,利用SolidWorks API设计机械结构,通过PLC控制系统模拟生产流程,使用数据分析工具进行生产数据的采集和异常检测,以及利用进度管理系统规划项目时间表。 适合人群:具有机械工程、自动化控制或计算机编程基础的学生或研究人员,尤其是从事智能制造领域相关工作的人员。 使用场景及目标:①帮助学生或研究人员快速搭建和理解微型车间生产线的设计与实现;②提供完整的代码框架,便于修改和扩展以适应不同的应用场景;③作为教学或科研项目的参考资料,用于学习和研究智能制造技术。 阅读建议:此资源不仅包含详细的代码实现,还涉及多个学科领域的知识,如机械设计、电气控制、数据分析等。因此,在学习过程中,建议读者结合实际操作,逐步理解每个模块的功能和原理,并尝试调整参数以观察不同设置下的系统表现。同时,可以参考提供的文献资料,深入研究相关理论和技术背景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值