博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
点在面内(1)
阅读量:6978 次
发布时间:2019-06-27

本文共 8121 字,大约阅读时间需要 27 分钟。

hot3.png

title: 点在面内(1)

date: 2015-11-14 11:23:45
categories: ANDROID

tags: 点在面内

我的博客:

【参考文献】:

1、

2、

经过在网上的一番搜索,发现目前比较通用的就是射线法,而我采用的就是X轴射线法。主要理论来源于西安交大的一篇论文(即参考文献的第二条)

<!--more-->

代码讲解:

主要的类有两个:一个是坐标点的抽象类,另一个是位置关系判断工具类。

package com.niux.crm.core.common.bmap;/** * 用于构造百度地图中的经纬度点 *  * @author zhengtian * @date 2013-8-5 下午02:54:41 */public class BmapPoint {    private double lng;// 经度    private double lat;// 纬度    public BmapPoint() {    }    public BmapPoint(double lng, double lat) {        this.lng = lng;        this.lat = lat;    }    @Override    public boolean equals(Object obj) {        if (obj instanceof BmapPoint) {            BmapPoint bmapPoint = (BmapPoint) obj;            return (bmapPoint.getLng() == lng && bmapPoint.getLat() == lat) ? true : false;        } else {            return false;        }    }    public double getLng() {        return lng;    }    public void setLng(double lng) {        this.lng = lng;    }    public double getLat() {        return lat;    }    public void setLat(double lat) {        this.lat = lat;    }}

2、位置关系判断工具类

点与多边形的位置关系的判定规则:

1、,根据多边形的坐标,虚拟出一个外包矩形,主要是为了提前过滤不相关的点,减少运算量。

2、然后判断是否有重合的点。
3、判断点与斜线的交点。
4、判断点过顶点的情况。
5、判断点与边重合的情况。
6、判断点在边上的情况。

其中点过顶点,以及点与边重合的情况,主要采用了加权边的思想,论文与代码中有注释。

package com.niux.crm.core.common.bmap;import java.util.Arrays;/** * 用于点与多边形位置关系的判断 *  * @author zhengtian * @date 2013-8-5 上午11:59:35 */public class GraphUtils {    /**     * 判断点是否在多边形内(基本思路是用交点法)     *      * @param point     * @param boundaryPoints     * @return     */    public static boolean isPointInPolygon(BmapPoint point, BmapPoint[] boundaryPoints) {        // 防止第一个点与最后一个点相同        if (boundaryPoints != null && boundaryPoints.length > 0                && boundaryPoints[boundaryPoints.length - 1].equals(boundaryPoints[0])) {            boundaryPoints = Arrays.copyOf(boundaryPoints, boundaryPoints.length - 1);        }        int pointCount = boundaryPoints.length;        // 首先判断点是否在多边形的外包矩形内,如果在,则进一步判断,否则返回false        if (!isPointInRectangle(point, boundaryPoints)) {            return false;        }        // 如果点与多边形的其中一个顶点重合,那么直接返回true        for (int i = 0; i < pointCount; i++) {            if (point.equals(boundaryPoints[i])) {                return true;            }        }        /**         * 基本思想是利用X轴射线法,计算射线与多边形各边的交点,如果是偶数,则点在多边形外,否则在多边形内。还会考虑一些特殊情况,如点在多边形顶点上         * , 点在多边形边上等特殊情况。         */        // X轴射线与多边形的交点数        int intersectPointCount = 0;        // X轴射线与多边形的交点权值        float intersectPointWeights = 0;        // 浮点类型计算时候与0比较时候的容差        double precision = 2e-10;        // 边P1P2的两个端点        BmapPoint point1 = boundaryPoints[0], point2;        // 循环判断所有的边        for (int i = 1; i <= pointCount; i++) {            point2 = boundaryPoints[i % pointCount];            /**             * 如果点的y坐标在边P1P2的y坐标开区间范围之外,那么不相交。             */            if (point.getLat() < Math.min(point1.getLat(), point2.getLat())                    || point.getLat() > Math.max(point1.getLat(), point2.getLat())) {                point1 = point2;                continue;            }            /**             * 此处判断射线与边相交             */            if (point.getLat() > Math.min(point1.getLat(), point2.getLat())                    && point.getLat() < Math.max(point1.getLat(), point2.getLat())) {// 如果点的y坐标在边P1P2的y坐标开区间内                if (point1.getLng() == point2.getLng()) {// 若边P1P2是垂直的                    if (point.getLng() == point1.getLng()) {                        // 若点在垂直的边P1P2上,则点在多边形内                        return true;                    } else if (point.getLng() < point1.getLng()) {                        // 若点在在垂直的边P1P2左边,则点与该边必然有交点                        ++intersectPointCount;                    }                } else {// 若边P1P2是斜线                    if (point.getLng() <= Math.min(point1.getLng(), point2.getLng())) {// 点point的x坐标在点P1和P2的左侧                        ++intersectPointCount;                    } else if (point.getLng() > Math.min(point1.getLng(), point2.getLng())                            && point.getLng() < Math.max(point1.getLng(), point2.getLng())) {// 点point的x坐标在点P1和P2的x坐标中间                        double slopeDiff = 0.0d;                        if (point1.getLat() > point2.getLat()) {                            slopeDiff = (point.getLat() - point2.getLat()) / (point.getLng() - point2.getLng())                                    - (point1.getLat() - point2.getLat()) / (point1.getLng() - point2.getLng());                        } else {                            slopeDiff = (point.getLat() - point1.getLat()) / (point.getLng() - point1.getLng())                                    - (point2.getLat() - point1.getLat()) / (point2.getLng() - point1.getLng());                        }                        if (slopeDiff > 0) {                            if (slopeDiff < precision) {// 由于double精度在计算时会有损失,故匹配一定的容差。经试验,坐标经度可以达到0.0001                                // 点在斜线P1P2上                                return true;                            } else {                                // 点与斜线P1P2有交点                                intersectPointCount++;                            }                        }                    }                }            } else {                // 边P1P2水平                if (point1.getLat() == point2.getLat()) {                    if (point.getLng() <= Math.max(point1.getLng(), point2.getLng())                            && point.getLng() >= Math.min(point1.getLng(), point2.getLng())) {                        // 若点在水平的边P1P2上,则点在多边形内                        return true;                    }                }                /**                 * 判断点通过多边形顶点                 */                if (((point.getLat() == point1.getLat() && point.getLng() < point1.getLng()))                        || (point.getLat() == point2.getLat() && point.getLng() < point2.getLng())) {                    if (point2.getLat() < point1.getLat()) {                        intersectPointWeights += -0.5;                    } else if (point2.getLat() > point1.getLat()) {                        intersectPointWeights += 0.5;                    }                }            }            point1 = point2;        }        if ((intersectPointCount + Math.abs(intersectPointWeights)) % 2 == 0) {// 偶数在多边形外            return false;        } else { // 奇数在多边形内            return true;        }    }    /**     * 判断点是否在矩形内在矩形边界上,也算在矩形内(根据这些点,构造一个外包矩形)     *      * @param point     *            点对象     * @param boundaryPoints     *            矩形边界点     * @return     */    public static boolean isPointInRectangle(BmapPoint point, BmapPoint[] boundaryPoints) {        BmapPoint southWestPoint = getSouthWestPoint(boundaryPoints); // 西南角点        BmapPoint northEastPoint = getNorthEastPoint(boundaryPoints); // 东北角点        return (point.getLng() >= southWestPoint.getLng() && point.getLng() <= northEastPoint.getLng()                && point.getLat() >= southWestPoint.getLat() && point.getLat() <= northEastPoint.getLat());    }    /**     * 根据这组坐标,画一个矩形,然后得到这个矩形西南角的顶点坐标     *      * @param vertexs     * @return     */    private static BmapPoint getSouthWestPoint(BmapPoint[] vertexs) {        double minLng = vertexs[0].getLng(), minLat = vertexs[0].getLat();        for (BmapPoint bmapPoint : vertexs) {            double lng = bmapPoint.getLng();            double lat = bmapPoint.getLat();            if (lng < minLng) {                minLng = lng;            }            if (lat < minLat) {                minLat = lat;            }        }        return new BmapPoint(minLng, minLat);    }    /**     * 根据这组坐标,画一个矩形,然后得到这个矩形东北角的顶点坐标     *      * @param vertexs     * @return     */    private static BmapPoint getNorthEastPoint(BmapPoint[] vertexs) {        double maxLng = 0.0d, maxLat = 0.0d;        for (BmapPoint bmapPoint : vertexs) {            double lng = bmapPoint.getLng();            double lat = bmapPoint.getLat();            if (lng > maxLng) {                maxLng = lng;            }            if (lat > maxLat) {                maxLat = lat;            }        }        return new BmapPoint(maxLng, maxLat);    }}

转载于:https://my.oschina.net/coolwxb/blog/631336

你可能感兴趣的文章
菜鸟学习HTML5+CSS3(一)
查看>>
Inno Setup制作应用程序安装包
查看>>
小知识点
查看>>
scrollview gridview
查看>>
获取用户所属浏览器和设备
查看>>
20135306黄韧 信息安全系统设计基础期中学习总结
查看>>
Magento(麦进斗)安装问题
查看>>
大数据概述
查看>>
客户端动态调用WCF服务中的方法
查看>>
v-cloak,v-text,v-html的基本使用
查看>>
[POI2009]KAM-Pebbles BZOJ1115 [ 待填坑 ] 博弈
查看>>
Web充斥着存在漏洞的过期JavaScript库
查看>>
%f%g%e区别
查看>>
Ubuntu Vim YouCompleteMe 安装
查看>>
修改360浏览器 标题栏 显示的文字
查看>>
在Centos 7下编译openwrt+njit-client
查看>>
微软重新释出MS10-015 解决蓝屏问题
查看>>
计算机组成原理-第3章-3.1
查看>>
约瑟夫环 猴子选大王
查看>>
win7安装mysql-8.0.13-winx64
查看>>