[几何]判断点是否在不规则多边形内

原文链接:http://blog.csdn.net/shao941122/article/details/51504519

最近项目用到:在Google map上判断事发地点,是否在管辖区域内。也就是典型的判断一个点是否在不规则多边形内的例子。

但是Google Map没有提供相应的api,找资料发现百度地图提供了一个工具类,肿么办,为了一个工具类,加入百度地图吗,操蛋,这是不可能的!

百度地图api链接:
http://wiki.lbsyun.baidu.com/cms/androidsdk/doc/v3_7_0/com/baidu/mapapi/utils/SpatialRelationUtil.html

com.baidu.mapapi.utils
类 SpatialRelationUtil

java.lang.Object
com.baidu.mapapi.utils.SpatialRelationUtil

Point Inclusion

• 给定一个点和一个不规则多边形,如果判断点在多边形内部还是外部?
• 方向有助于在线性时间解决这个问题!

《[几何]判断点是否在不规则多边形内》

《[几何]判断点是否在不规则多边形内》

Point Inclusion — Part II

• 在每个点的右侧绘制一条水平线,并延伸到无穷远。(水平射线)
• 计算水平射线与多边形相交的次数。

我们有结论:

  • 偶数 ⇒ 点在外部
  • 奇数 ⇒ 点在内部

《[几何]判断点是否在不规则多边形内》

• d 和 g点怎么办? Degeneracy! (在判断一个点的水平射线和多边形一个边是否相交时,依据是:点的竖向坐标y 是否在 线段的竖向坐标[Ymin,Ymax]范围内,而d g点是y值完全等于多边形某一点的y值。而多边形的一个点必然关联两条线段。所以在判断空间关系时,无论取开区间(Ymin,Ymax) 还是闭区间[Ymin,Ymax], 必然造成双重计数,不影响结论)
那么下面自己搞一个吧,实测有效:

public class SpatialRelationUtil {  

    private SpatialRelationUtil() {  
    }  
 
    public class Point {  
        double x;  
        double y;  
    }  
  
    /** 
     * 返回一个点是否在一个多边形区域内 
     * 
     * @param mPoints 多边形坐标点列表 
     * @param point   待判断点 
     * @return true 多边形包含这个点,false 多边形未包含这个点。 
     */  
    public static boolean isPolygonContainsPoint(List<Point> mPoints, Point point) {  
        int nCross = 0;  
        for (int i = 0; i < mPoints.size(); i++) {  
            Point p1 = mPoints.get(i);  
            Point p2 = mPoints.get((i + 1) % mPoints.size());  
            // 取多边形任意一个边,做点point的水平延长线,求解与当前边的交点个数  
            // p1p2是水平线段,要么没有交点,要么有无限个交点  
            if (p1.y == p2.y)  
                continue;  
            // point 在p1p2 底部 --> 无交点  
            if (point.y < Math.min(p1.y, p2.y))  
                continue;  
            // point 在p1p2 顶部 --> 无交点  
            if (point.y >= Math.max(p1.y, p2.y))  
                continue;  
            // 求解 point点水平线与当前p1p2边的交点的 X 坐标  
            double x = (point.y - p1.y) * (p2.x - p1.x) / (p2.y - p1.y) + p1.x;  
            if (x > point.x) // 当x=point.x时,说明point在p1p2线段上  
                nCross++; // 只统计单边交点  
        }  
        // 单边交点为偶数,点在多边形之外 ---  
        return (nCross % 2 == 1);  
    }  
  
    /** 
     * 返回一个点是否在一个多边形边界上 
     * 
     * @param mPoints 多边形坐标点列表 
     * @param point   待判断点 
     * @return true 点在多边形边上,false 点不在多边形边上。 
     */  
    public static boolean isPointInPolygonBoundary(List<Point> mPoints, Point point) {  
        for (int i = 0; i < mPoints.size(); i++) {  
            Point p1 = mPoints.get(i);  
            Point p2 = mPoints.get((i + 1) % mPoints.size());  
            // 取多边形任意一个边,做点point的水平延长线,求解与当前边的交点个数  
  
            // point 在p1p2 底部 --> 无交点  
            if (point.y < Math.min(p1.y, p2.y))  
                continue;  
            // point 在p1p2 顶部 --> 无交点  
            if (point.y > Math.max(p1.y, p2.y))  
                continue;  
  
            // p1p2是水平线段,要么没有交点,要么有无限个交点  
            if (p1.y == p2.y) {  
                double minX = Math.min(p1.x, p2.x);  
                double maxX = Math.max(p1.x, p2.x);  
                // point在水平线段p1p2上,直接return true  
                if ((point.y == p1.y) && (point.x >= minX && point.x <= maxX)) {  
                    return true;  
                }  
            } else { // 求解交点  
                double x = (point.y - p1.y) * (p2.x - p1.x) / (p2.y - p1.y) + p1.x;  
                if (x == point.x) // 当x=point.x时,说明point在p1p2线段上  
                    return true;  
            }  
        }  
        return false;  
    }  
  
}  

使用说明:只需要将SpatialRelationUtil这个工具类,复制到你的项目就可以直接使用,不用添加任何jar包。
效果展示:这个Demo展示判断事发地点是否在管辖区域内,也就是判断圆心是否在某一个基础区域内,如果在基础区域内,显示圆的半径(单位英里),如果不在基础区域给予提示:Point not in jurisdiction(事发点不在管辖范围内)。

《[几何]判断点是否在不规则多边形内》

    原文作者:MapleShao
    原文地址: https://www.jianshu.com/p/3e3465ad1641
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞