判断一个点是否在多边形区域内

项目github地址:bitcarmanlee easy-algorithm-interview-and-practice
欢迎大家star,留言,一起学习进步

在做LBS,POI相关项目时,经常需要判断一个点是否在某个区域中的问题。在实际场景中,这个区域肯定是没有任何规律的不规则形状。针对这种场景,搜索了几种对应的解法。重点是,最后给大家奉上能工作的源码!有需要的同学们千万不能错过。

1.射线法,PNPoly算法

本算法是由W. Randolph Franklin提出的。算法的思路如下:
从待测点出发作一条射线,可沿y轴方向也可没x轴方向,然后判断这条射线与不规则区域的交点数量。如果点的两边交点的个数都是奇数个则该点在多边形内,否则在多边形外。
这个算法对于任意不规则图形都适用。
关于本算法更详细的介绍,请参考参考文献1。

2.多边形面积算法

非凹多边形,凹多边形需要切割为凸多边形。
第四点分别与三角形的两个点组成的面积分别设为S1,S2,S3,只要S1+S2+S3>原来的三角形面积就不在三角形范围中.可以使用海伦公式 。

3.可用的解决方案

重点来了…
在实际的项目过程中,不管多精巧的算法,实现功能完成项目是第一位的。算法再好,还得自己去实现去测试,尤其是各种边界条件测试,绝对是要吐血。所以,不管什么算法,啥也不说了,先上代码。

import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by wanglei on 17-2-14.
 */
public class MapTools {

    public static List genPointList() {
        List list = new ArrayList();
        Point2D.Double p1 = new Point2D.Double(0.0,0.0);
        Point2D.Double p2 = new Point2D.Double(0.0,0.5);
        Point2D.Double p3 = new Point2D.Double(0.0,1.0);
        Point2D.Double p4 = new Point2D.Double(1.0,0.5);
        Point2D.Double p5 = new Point2D.Double(1.0,1.0);
        Point2D.Double p6 = new Point2D.Double(1.0,0.5);
        Point2D.Double p7 = new Point2D.Double(1.0,0.0);
        Point2D.Double p8 = new Point2D.Double(0.5,0.0);

        Point2D.Double[] points = {p1,p2,p3,p4,p5,p6,p7,p8};
        for (int i = 0; i < points.length; i++) {
            list.add(points[i]);
        }

        return list;
    }

    public static boolean checkWithPath(Point2D.Double point, List<Point2D.Double> polygon) {
        GeneralPath p = new GeneralPath();
        Point2D.Double first = polygon.get(0);
        p.moveTo(first.x,first.y);
        for(Point2D.Double d: polygon) {
            p.lineTo(d.x,d.y);
        }
        p.lineTo(first.x,first.y);
        p.closePath();
        return p.contains(point);
    }

    public static void main(String[] args) {
        List list = genPointList();
        Point2D.Double p1 = new Point2D.Double(1.5,1.5);
        Point2D.Double p2 = new Point2D.Double(0.2,0.3);
        Point2D.Double p3 = new Point2D.Double(1.5,0.1);
        Point2D.Double p4 = new Point2D.Double(0.8,0.0);
        Point2D.Double p5 = new Point2D.Double(0.08,0.01);
        List<Point2D.Double> testList = new ArrayList();
        testList.add(p1);
        testList.add(p2);
        testList.add(p3);
        testList.add(p4);
        testList.add(p5);
        for(Point2D.Double each:testList) {
            boolean flag = checkWithPath(each,list);
            System.out.println(each.toString() + " is in polygon: " + flag);
        }
    }
}

上面的代码主要是用到了java.awt.geom包。java.awt.geom是jdk自带的类包,不用任何额外的安装。GeneralPath 类表示根据直线、二次曲线和三次 (Bézier) 曲线构造的几何路径。它可以包含多个子路径。GeneralPath继承自java.awt.geom.Path2D。那么这个Path2D是干嘛的呢?看看jdk里面的一段注解:

/**
 * The {@code Path2D} class provides a simple, yet flexible
 * shape which represents an arbitrary geometric path.
 * It can fully represent any path which can be iterated by the
 * {@link PathIterator} interface including all of its segment
 * types and winding rules and it implements all of the
 * basic hit testing methods of the {@link Shape} interface.
 * <p>

第一句话就告诉了我们Path2D是干嘛的:Path2D类提供了一个简单,灵活的形状类,用来表示任意几何路径。

测试代码中,生成了一个边长为1的正方形矩形区域,其中一个顶点为(0,0)。最后的测试结果为:

Point2D.Double[1.5, 1.5] is in polygon: false
Point2D.Double[0.2, 0.3] is in polygon: true
Point2D.Double[1.5, 0.1] is in polygon: false
Point2D.Double[0.8, 0.0] is in polygon: true
Point2D.Double[0.08, 0.01] is in polygon: true

测试结果准确无误,完美地满足了我们的需求!
时间关系,没有来得及具体研究jdk里源码的实现细节,后续可以进一步研究Path2D的实现算法。

参考文档:
1.http://blog.csdn.net/hjh2005/article/details/9246967
2.http://www.apihome.cn/api/java/GeneralPath.html
3.jdk源码

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值