判断顶点凹凸性、判断多边形的凹凸性、填充凹坑将凹多边形处理为凸多边形【java实现+原理讲解】

问题

  1. 如何识别多边形中一个顶点的凹凸性
  2. 如何判断一个多边形的凹凸性(若多边形有一个点为凹的,则多边形为凹的)
  3. 如何通过填充凹坑的方式将凹多边形转化为凸多边形

方法

将多边形点集顺序修改为逆时针顺序

判断多边形点击顺序的方法可以参考判断多边形点集顺序,如果判断出多边形点击顺序为顺时针的话,直接将集合反转一下即可

判断一个点是否为凹点

在这里插入图片描述
注意:使用这方法判断的前提是多边形点击顺序是逆时针的才行

最终实现

/**
* 将凹多边形转化为凸多边形
*/
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);
       }
   }

}

在这里插入图片描述

测试

在这里插入图片描述

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hello Dam

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值