java实现经纬度坐标是否在范围内的算法

简介: java实现经纬度坐标是否在范围内的算法

需求是:一个点(经纬度)是否在一个多边形内部,多边形有多个点构成,每个点是一个实际的经纬度坐标,有多个点构成一个多边形,

算法数学上实现思路: 判断一个点是在一个多边形内部的集中情况
第一:目标点在多边形的某一个顶点上,我们认为目标点在多边形内部
第二:目标点在多边形的任意一天边上,我们认为目标点在多边形内部
第三:这种情况就比较复杂了,不在某天边上,也不和任何一个顶点重合.这时候就需要我们自己去算了,解决方案是将目标点的Y坐标与多边形的每一个点进行比较,我们会得到一个目标点所在的行与多边形边的交点的列表。如果目标点的两边点的个数都是奇数个则该目标点在多边形内,否则在多边形外。

这种算法适合凸多边形也适合凹多边形,所以是一种通用的算法,同时也解决了多边形的点的顺序不同导致的形状不同,比如一个五边形,可以是凸五边形,也可以是一个凹五边形,这个根据点的位置和顺序决定的。
image.png

有了数学上的实现思路,辣么我们就可以用java 或者去他语言去实现一个点(经纬度)是否在一个多边形内部了(多个点构成)。

我们先写一个 对点和线的一些公用方法,

package cn.liuzw.point;
import java.util.ArrayList;
 
/**
 *  <span style="font-family: Arial; font-size: 14px; line-height: 26px;">点和线的一些公用方法</span><br/>
 * 
 * @author liuZhiwei
 * 2016年8月6日 下午3:48:38
 */
public class Point {
    
    /**
     *  是否有 横断<br/>
     *  参数为四个点的坐标
     * @param px1
     * @param py1
     * @param px2
     * @param py2
     * @param px3
     * @param py3
     * @param px4
     * @param py4
     * @return  
     */
    public boolean isIntersect ( double px1 , double py1 , double px2 , double py2 , double px3 , double py3 , double px4 ,  
            double py4 )  
    {  
        boolean flag = false;  
        double d = (px2 - px1) * (py4 - py3) - (py2 - py1) * (px4 - px3);  
        if ( d != 0 )  
        {  
            double r = ((py1 - py3) * (px4 - px3) - (px1 - px3) * (py4 - py3)) / d;  
            double s = ((py1 - py3) * (px2 - px1) - (px1 - px3) * (py2 - py1)) / d;  
            if ( (r >= 0) && (r <= 1) && (s >= 0) && (s <= 1) )  
            {  
                flag = true;  
            }  
        }  
        return flag;  
    } 
    /**
     *  目标点是否在目标边上边上<br/>
     *  
     * @param px0 目标点的经度坐标
     * @param py0 目标点的纬度坐标
     * @param px1 目标线的起点(终点)经度坐标
     * @param py1 目标线的起点(终点)纬度坐标
     * @param px2 目标线的终点(起点)经度坐标
     * @param py2 目标线的终点(起点)纬度坐标
     * @return
     */
    public boolean isPointOnLine ( double px0 , double py0 , double px1 , double py1 , double px2 , double py2 )  
    {  
        boolean flag = false;  
        double ESP = 1e-9;//无限小的正数
        if ( (Math.abs(Multiply(px0, py0, px1, py1, px2, py2)) < ESP) && ((px0 - px1) * (px0 - px2) <= 0)  
                && ((py0 - py1) * (py0 - py2) <= 0) )  
        {  
            flag = true;  
        }  
        return flag;  
    } 
 
    public double Multiply ( double px0 , double py0 , double px1 , double py1 , double px2 , double py2 )  
    {  
        return ((px1 - px0) * (py2 - py0) - (px2 - px0) * (py1 - py0));  
    }
 
    /**
     * 判断目标点是否在多边形内(由多个点组成)<br/>
     * 
     * @param px 目标点的经度坐标
     * @param py 目标点的纬度坐标
     * @param polygonXA 多边形的经度坐标集合
     * @param polygonYA 多边形的纬度坐标集合
     * @return
     */
    public boolean isPointInPolygon ( double px , double py , ArrayList<Double> polygonXA , ArrayList<Double> polygonYA )  
    {  
        boolean isInside = false;  
        double ESP = 1e-9;  
        int count = 0;  
        double linePoint1x;  
        double linePoint1y;  
        double linePoint2x = 180;  
        double linePoint2y;  
 
        linePoint1x = px;  
        linePoint1y = py;  
        linePoint2y = py;  
 
        for (int i = 0; i < polygonXA.size() - 1; i++)  
        {  
            double cx1 = polygonXA.get(i);  
            double cy1 = polygonYA.get(i);  
            double cx2 = polygonXA.get(i + 1);  
            double cy2 = polygonYA.get(i + 1); 
            //如果目标点在任何一条线上
            if ( isPointOnLine(px, py, cx1, cy1, cx2, cy2) )  
            {  
                return true;  
            }
            //如果线段的长度无限小(趋于零)那么这两点实际是重合的,不足以构成一条线段
            if ( Math.abs(cy2 - cy1) < ESP )  
            {  
                continue;  
            }  
            //第一个点是否在以目标点为基础衍生的平行纬度线
            if ( isPointOnLine(cx1, cy1, linePoint1x, linePoint1y, linePoint2x, linePoint2y) )  
            {  
                //第二个点在第一个的下方,靠近赤道纬度为零(最小纬度)
                if ( cy1 > cy2 )  
                    count++;  
            }
            //第二个点是否在以目标点为基础衍生的平行纬度线
            else if ( isPointOnLine(cx2, cy2, linePoint1x, linePoint1y, linePoint2x, linePoint2y) )  
            {  
                //第二个点在第一个的上方,靠近极点(南极或北极)纬度为90(最大纬度)
                if ( cy2 > cy1 )  
                    count++;  
            }
            //由两点组成的线段是否和以目标点为基础衍生的平行纬度线相交
            else if ( isIntersect(cx1, cy1, cx2, cy2, linePoint1x, linePoint1y, linePoint2x, linePoint2y) )  
            {  
                count++;  
            }  
        }  
        if ( count % 2 == 1 )  
        {  
            isInside = true;  
        }  
 
        return isInside;  
    }  
}

里面有三个方法,两个原子方法,一个主方法
第一个判断是否与横断 目标端和y轴 也就是东经0也叫西经180的一条经度线构成的一天平行于纬度(赤道)的一天线段和多边形的任意一天线段是否有横断。参数是四个点的坐标分别是目标点和目标点组成线段的一个点(在西经180度上) 多边形的任意连续的两个点(可以构成一条线段)

第二个是目标点是否在目标边上边上,

点三个是主方法,外接只需要调用这个方法,这个而方法的逻辑就是,第一步先判断目标点的坐标是否和多边形的任意一个顶点的坐标重合,如果重合直接放回true,说明目标点在该多边形内,如果都不重合,在判断是否在多边形的任意一条边上,如果在 返回true,如果以上两种情况都不成立在理由低三种算法,计算目标点平行于赤道的线和多边形的焦点,在判断焦点的个数。如果l两边的焦点是基数个返回true。

我可以写main方法去测试该程序。

package cn.liuzw.bean;
 
import java.util.Random;
 
/**
 * 点实体类<br/>
 * 
 * @author liuZhiwei
 * 2016年8月15日 下午7:16:14
 */
public class Area {
    
    public static Random rd=new Random();
    
    public Double createDouble(){
        return (double) rd.nextInt(1000);
    }
    public Area() {
        this.px = createDouble();
        this.py = createDouble();
    }
    
    public Area(Double px, Double py) {
        super();
        this.px = px;
        this.py = py;
    }
    
    public Area(Double px, Double py, String name) {
        super();
        this.px = px;
        this.py = py;
        this.name = name;
    }
    private Double px;
    private Double py;
    private String name;
    public Double getPx() {
        return px;
    }
    public void setPx(Double px) {
        this.px = px;
    }
    public Double getPy() {
        return py;
    }
    public void setPy(Double py) {
        this.py = py;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Area [px=" + px + ", py=" + py + ", name=" + name + "]";
    }
    
    public String getPoint() {
        StringBuffer buffer=new StringBuffer();
        buffer.append("(").append(px).append(",").append(py).append(")");
        return buffer.toString();
    }    
}

main方法测试类

package cn.liuzw.test;
 
import java.util.ArrayList;
import java.util.List;
 
import cn.liuzw.bean.Area;
import cn.liuzw.point.Point;
 
public class GraphicalMain {
    public static void main(String[] args) {
        //(113.944421,22.528841) (113.94629,22.529208)
        //isPointInPolygon(area.createDouble(),area.createDouble()); (114.082402,22.550271) 114.075323,22.543528)
        isPointInPolygon(113.947871,22.52804);
        
    }
    private static Boolean isPointInPolygon( double px , double py ){
        Area a1=new Area(113.941853,22.530777);
        Area a3=new Area(113.94788,22.527597);
        Area a2=new Area(113.940487,22.527789);
        Area a4=new Area(113.947925,22.530618);
        Area a5=new Area(113.941772,22.530727);
        List<Area> areas=new ArrayList<Area>();
        areas.add(a1);
        areas.add(a2);
        areas.add(a3);
        areas.add(a4);
        ArrayList<Double> polygonXA = new ArrayList<Double>();  
        ArrayList<Double> polygonYA = new ArrayList<Double>(); 
        for(int i=0;i<areas.size();i++){
            Area area=areas.get(i);
            polygonXA.add(area.getPx());
            polygonYA.add(area.getPy());
        }
        Point point=new Point();
        Boolean flag= point.isPointInPolygon(px, py, polygonXA, polygonYA);
        StringBuffer buffer=new StringBuffer();
        buffer.append("目标点").append("(").append(px).append(",").append(py).append(")").append("\n");
        buffer.append(flag?"在":"不在").append("\t").append("由\n");
        for(int i=0;i<areas.size();i++){
            Area area=areas.get(i);
            buffer.append(area.getPoint()).append("; ");
            //buffer.append("第"+i+"个点"+area.getPoint()).append("\n");
            System.out.println("第"+(i+1)+"个点"+area.getPoint());
        }
        StringBuffer sb=new StringBuffer();
        sb.append("目标点:").append("(").append(px).append(",").append(py).append(")").append("\n");
        System.out.println(sb);
        buffer.append(areas.size()).append("个点组成的").append(areas.size()).append("边行内");
        System.out.println(buffer.toString());
        return  flag;
    }
}

需求是:一个点(经纬度)是否在一个多边形内部,多边形有多个点构成,每个点是一个实际的经纬度坐标,有多个点构成一个多边形,
需求是:一个点(经纬度)是否在一个多边形内部,多边形有多个点构成,每个点是一个实际的经纬度坐标,有多个点构成一个多边形,
算法数学上实现思路: 判断一个点是在一个多边形内部的集中情况
第一:目标点在多边形的某一个顶点上,我们认为目标点在多边形内部
第二:目标点在多边形的任意一天边上,我们认为目标点在多边形内部
第三:这种情况就比较复杂了,不在某天边上,也不和任何一个顶点重合.这时候就需要我们自己去算了,解决方案是将目标点的Y坐标与多边形的每一个点进行比较,我们会得到一个目标点所在的行与多边形边的交点的列表。如果目标点的两边点的个数都是奇数个则该目标点在多边形内,否则在多边形外。

相关文章
|
1月前
|
负载均衡 NoSQL 算法
一天五道Java面试题----第十天(简述Redis事务实现--------->负载均衡算法、类型)
这篇文章是关于Java面试中Redis相关问题的笔记,包括Redis事务实现、集群方案、主从复制原理、CAP和BASE理论以及负载均衡算法和类型。
一天五道Java面试题----第十天(简述Redis事务实现--------->负载均衡算法、类型)
|
30天前
|
搜索推荐 算法 Java
手写快排:教你用Java写出高效排序算法!
快速排序(QuickSort)是经典的排序算法之一,基于分治思想,平均时间复杂度为O(n log n),广泛应用于各种场合。在这篇文章中,我们将手写一个Java版本的快速排序,从基础实现到优化策略,并逐步解析代码背后的逻辑。
41 1
|
20天前
|
设计模式 缓存 算法
揭秘策略模式:如何用Java设计模式轻松切换算法?
【8月更文挑战第30天】设计模式是解决软件开发中特定问题的可重用方案。其中,策略模式是一种常用的行为型模式,允许在运行时选择算法行为。它通过定义一系列可互换的算法来封装具体的实现,使算法的变化与客户端分离。例如,在电商系统中,可以通过定义 `DiscountStrategy` 接口和多种折扣策略类(如 `FidelityDiscount`、`BulkDiscount` 和 `NoDiscount`),在运行时动态切换不同的折扣逻辑。这样,`ShoppingCart` 类无需关心具体折扣计算细节,只需设置不同的策略即可实现灵活的价格计算,符合开闭原则并提高代码的可维护性和扩展性。
36 2
|
28天前
|
安全 算法 Java
java系列之~~网络通信安全 非对称加密算法的介绍说明
这篇文章介绍了非对称加密算法,包括其定义、加密解密过程、数字签名功能,以及与对称加密算法的比较,并解释了非对称加密在网络安全中的应用,特别是在公钥基础设施和信任网络中的重要性。
|
1月前
|
搜索推荐 算法 Java
经典排序算法之-----选择排序(Java实现)
这篇文章通过Java代码示例详细解释了选择排序算法的实现过程,包括算法的基本思想、核心代码、辅助函数以及测试结果,展示了如何通过选择排序对数组进行升序排列。
经典排序算法之-----选择排序(Java实现)
|
1月前
|
搜索推荐 算法 Java
|
1月前
|
存储 算法 Java
LeetCode经典算法题:打家劫舍java详解
LeetCode经典算法题:打家劫舍java详解
46 2
|
1月前
|
人工智能 算法 Java
LeetCode经典算法题:井字游戏+优势洗牌+Dota2参议院java解法
LeetCode经典算法题:井字游戏+优势洗牌+Dota2参议院java解法
37 1
|
29天前
|
数据采集 搜索推荐 算法
【高手进阶】Java排序算法:从零到精通——揭秘冒泡、快速、归并排序的原理与实战应用,让你的代码效率飙升!
【8月更文挑战第21天】Java排序算法是编程基础的重要部分,在算法设计与分析及实际开发中不可或缺。本文介绍内部排序算法,包括简单的冒泡排序及其逐步优化至高效的快速排序和稳定的归并排序,并提供了每种算法的Java实现示例。此外,还探讨了排序算法在电子商务、搜索引擎和数据分析等领域的广泛应用,帮助读者更好地理解和应用这些算法。
19 0
|
1月前
|
算法 Java
HanLP — HMM隐马尔可夫模型 -- 维特比(Viterbi)算法 --示例代码 - Java
HanLP — HMM隐马尔可夫模型 -- 维特比(Viterbi)算法 --示例代码 - Java
29 0