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坐标与多边形的每一个点进行比较,我们会得到一个目标点所在的行与多边形边的交点的列表。如果目标点的两边点的个数都是奇数个则该目标点在多边形内,否则在多边形外。

相关文章
|
2月前
|
存储 人工智能 算法
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
这篇文章详细介绍了Dijkstra和Floyd算法,这两种算法分别用于解决单源和多源最短路径问题,并且提供了Java语言的实现代码。
95 3
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
|
3天前
|
缓存 算法 搜索推荐
Java中的算法优化与复杂度分析
在Java开发中,理解和优化算法的时间复杂度和空间复杂度是提升程序性能的关键。通过合理选择数据结构、避免重复计算、应用分治法等策略,可以显著提高算法效率。在实际开发中,应该根据具体需求和场景,选择合适的优化方法,从而编写出高效、可靠的代码。
16 6
|
4月前
|
搜索推荐 算法 Java
手写快排:教你用Java写出高效排序算法!
快速排序(QuickSort)是经典的排序算法之一,基于分治思想,平均时间复杂度为O(n log n),广泛应用于各种场合。在这篇文章中,我们将手写一个Java版本的快速排序,从基础实现到优化策略,并逐步解析代码背后的逻辑。
189 1
|
2月前
|
算法 搜索推荐 Java
java 后端 使用 Graphics2D 制作海报,画echarts图,带工具类,各种细节:如头像切割成圆形,文字换行算法(完美实验success),解决画上文字、图片后不清晰问题
这篇文章介绍了如何使用Java后端技术,结合Graphics2D和Echarts等工具,生成包含个性化信息和图表的海报,并提供了详细的代码实现和GitHub项目链接。
156 0
java 后端 使用 Graphics2D 制作海报,画echarts图,带工具类,各种细节:如头像切割成圆形,文字换行算法(完美实验success),解决画上文字、图片后不清晰问题
|
2月前
|
算法 Java 数据中心
探讨面试常见问题雪花算法、时钟回拨问题,java中优雅的实现方式
【10月更文挑战第2天】在大数据量系统中,分布式ID生成是一个关键问题。为了保证在分布式环境下生成的ID唯一、有序且高效,业界提出了多种解决方案,其中雪花算法(Snowflake Algorithm)是一种广泛应用的分布式ID生成算法。本文将详细介绍雪花算法的原理、实现及其处理时钟回拨问题的方法,并提供Java代码示例。
93 2
|
2月前
|
算法 Java Linux
java制作海报一:java使用Graphics2D 在图片上写字,文字换行算法详解
这篇文章介绍了如何在Java中使用Graphics2D在图片上绘制文字,并实现自动换行的功能。
154 0
|
2月前
|
算法 Java 测试技术
数据结构 —— Java自定义代码实现顺序表,包含测试用例以及ArrayList的使用以及相关算法题
文章详细介绍了如何用Java自定义实现一个顺序表类,包括插入、删除、获取数据元素、求数据个数等功能,并对顺序表进行了测试,最后还提及了Java中自带的顺序表实现类ArrayList。
36 0
|
4月前
|
设计模式 缓存 算法
揭秘策略模式:如何用Java设计模式轻松切换算法?
【8月更文挑战第30天】设计模式是解决软件开发中特定问题的可重用方案。其中,策略模式是一种常用的行为型模式,允许在运行时选择算法行为。它通过定义一系列可互换的算法来封装具体的实现,使算法的变化与客户端分离。例如,在电商系统中,可以通过定义 `DiscountStrategy` 接口和多种折扣策略类(如 `FidelityDiscount`、`BulkDiscount` 和 `NoDiscount`),在运行时动态切换不同的折扣逻辑。这样,`ShoppingCart` 类无需关心具体折扣计算细节,只需设置不同的策略即可实现灵活的价格计算,符合开闭原则并提高代码的可维护性和扩展性。
73 2
|
4月前
|
安全 算法 Java
java系列之~~网络通信安全 非对称加密算法的介绍说明
这篇文章介绍了非对称加密算法,包括其定义、加密解密过程、数字签名功能,以及与对称加密算法的比较,并解释了非对称加密在网络安全中的应用,特别是在公钥基础设施和信任网络中的重要性。
|
4月前
|
数据采集 搜索推荐 算法
【高手进阶】Java排序算法:从零到精通——揭秘冒泡、快速、归并排序的原理与实战应用,让你的代码效率飙升!
【8月更文挑战第21天】Java排序算法是编程基础的重要部分,在算法设计与分析及实际开发中不可或缺。本文介绍内部排序算法,包括简单的冒泡排序及其逐步优化至高效的快速排序和稳定的归并排序,并提供了每种算法的Java实现示例。此外,还探讨了排序算法在电子商务、搜索引擎和数据分析等领域的广泛应用,帮助读者更好地理解和应用这些算法。
49 0