问题
- 如何识别多边形中一个顶点的凹凸性
- 如何判断一个多边形的凹凸性(若多边形有一个点为凹的,则多边形为凹的)
- 如何通过填充凹坑的方式将凹多边形转化为凸多边形
方法
将多边形点集顺序修改为逆时针顺序
判断多边形点击顺序的方法可以参考判断多边形点集顺序,如果判断出多边形点击顺序为顺时针的话,直接将集合反转一下即可
判断一个点是否为凹点
注意:使用这方法判断的前提是多边形点击顺序是逆时针的才行
最终实现
/**
* 将凹多边形转化为凸多边形
*/
public class ConcaveToConvexApi {
/**
* 将凹多边形转化为凸多边形
*
* @param pointList
* @return
*/
public List<Point> concaveToConvex(List<Point> pointList) {
List<Point> pointListClone = (List<Point>) deepClone(pointList);
将点集方向转化为逆时针方向
this.correctPolygonDirection(pointListClone);
删除掉凹点
int j = 0;
while (j < pointListClone.size()) {
int i = (j - 1 + pointListClone.size()) % pointListClone.size();
int k = (j + 1) % pointListClone.size();
double x1 = pointListClone.get(j).getX() - pointListClone.get(i).getX();
double y1 = pointListClone.get(j).getY() - pointListClone.get(i).getY();
double x2 = pointListClone.get(k).getX() - pointListClone.get(i).getX();
double y2 = pointListClone.get(k).getY() - pointListClone.get(i).getY();
//叉积
double crossProduct = x1 * y2 - x2 * y1;
if (crossProduct > 0) {
//凸顶点
j++;
} else {
//凹顶点或者共线
pointListClone.remove(j);
if (j == pointListClone.size()) {
/*
一开始是 A B C D E F G 开始时j=0,GAB不触发删除
但是FGA触发删除之后,序列变成A B C D E F,可能FAB也会触发删除,因此需要将j重置于0
*/
j = 0;
} else {
if (j > 0) {
//这里为什么j--,可以看程序下面的图
j--;
}
}
}
}
return pointListClone;
}
/**
* 修正零件的点位方向
* 先找出最高那个点的索引i,然后在对{i.x-(i-1).x,i.y-(i-1).y}和{(i+1).x-(i-1).x,(i+1).y-(i-1).y}来求叉积,看正负就知道了
*
* @param pointList
*/
private void correctPolygonDirection(List<Point> pointList) {
if (pointList.size() == 0) {
return;
}
找到零件的最高点
int highestPointIndex = -1;
double highestY = -Double.MAX_VALUE;
for (int i = 0; i < pointList.size(); i++) {
if (pointList.get(i).getY() > highestY) {
highestY = pointList.get(i).getY();
highestPointIndex = i;
}
}
纠正坐标
///判断随着索引的进位,夹角是否为正数
//存储方向,1:顺时针;-1:逆时针
int direction = 0;
Point lastPoint = pointList.get((highestPointIndex - 1 + pointList.size()) % pointList.size());
Point curPoint = pointList.get(highestPointIndex);
Point nextPoint = pointList.get((highestPointIndex + 1) % pointList.size());
double x1 = curPoint.getX() - lastPoint.getX();
double y1 = curPoint.getY() - lastPoint.getY();
double x2 = nextPoint.getX() - lastPoint.getX();
double y2 = nextPoint.getY() - lastPoint.getY();
//计算向量的叉积
double crossProduct = x1 * y2 - x2 * y1;
if (crossProduct > 0) {
direction = -1;
} else if (crossProduct < 0) {
direction = 1;
}
//如果是顺时针的话,需要改为逆时针
if (direction == 1) {
//将集合的元素反转
Collections.reverse(pointList);
}
}
}