最近做一个项目:需要查询一个站点(已知该站点经纬度)500米范围内的其它站点。所以,我首先想到的是,对每条记录,去进行遍历,跟数据库中的每一个点进行距离计算,当距离小于500米时,认为匹配。这样做确实能够得到结果,但是效率极其低下,因为每条记录都要去循环匹配n条数据,其消耗的时间可想而知。

于是我就想到一个先过滤出大概的经纬度范围再进行计算。比方说正方形的四个点,于是我在网上搜索,意外的,查询到了一个关于这个计算附近地点搜索初探,里面使用Python,PHP,C实现了这个想法。所以参考了一下原文中的算法,使用Java进行了实现。

实现原理也是很相似的,先算出该点周围的矩形的四个点,然后使用经纬度去直接匹配数据库中的记录。

思路:首先算出“给定坐标附近500米”这个范围的坐标范围。 虽然它是个圆,但我们可以先求出该圆的外接正方形,然后拿正方形的经纬度范围去搜索数据库。 图是我盗的:

值得一提的是,维基百科推荐使用Haversine公式,理由是Great-circle distance公式用到了大量余弦函数, 而两点间距离很短时(比如地球表面上相距几百米的两点),余弦函数会得出0.999...的结果, 会导致较大的舍入误差。而Haversine公式采用了正弦函数,即使距离很小,也能保持足够的有效数字。 以前采用三角函数表计算时的确会有这个问题,但经过实际验证,采用计算机来计算时,两个公式的区别不大。 稳妥起见,这里还是采用Haversine公式。

其中

R为地球半径,可取平均值 6371km;

φ1, φ2 表示两点的纬度;

Δλ 表示两点经度的差值。

import java.util.HashMap;

import java.util.Map;

public class MapDistance {

private static double EARTH_RADIUS = 6378.137;

private static double rad(double d) {

return d * Math.PI / 180.0;

}

/**

* 根据两个位置的经纬度,来计算两地的距离(单位为KM)

* 参数为String类型

* @param lat1 用户经度

* @param lng1 用户纬度

* @param lat2 商家经度

* @param lng2 商家纬度

* @return

*/

public static String getDistance(String lat1Str, String lng1Str, String lat2Str, String lng2Str) {

Double lat1 = Double.parseDouble(lat1Str);

Double lng1 = Double.parseDouble(lng1Str);

Double lat2 = Double.parseDouble(lat2Str);

Double lng2 = Double.parseDouble(lng2Str);

double radLat1 = rad(lat1);

double radLat2 = rad(lat2);

double difference = radLat1 - radLat2;

double mdifference = rad(lng1) - rad(lng2);

double distance = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(difference / 2), 2)

+ Math.cos(radLat1) * Math.cos(radLat2)

* Math.pow(Math.sin(mdifference / 2), 2)));

distance = distance * EARTH_RADIUS;

distance = Math.round(distance * 10000) / 10000;

String distanceStr = distance+"";

distanceStr = distanceStr.

substring(0, distanceStr.indexOf("."));

return distanceStr;

}

/**

* 获取当前用户一定距离以内的经纬度值

* 单位米 return minLat

* 最小经度 minLng

* 最小纬度 maxLat

* 最大经度 maxLng

* 最大纬度 minLat

*/

public static Map getAround(String latStr, String lngStr, String raidus) {

Map map = new HashMap();

Double latitude = Double.parseDouble(latStr);// 传值给经度

Double longitude = Double.parseDouble(lngStr);// 传值给纬度

Double degree = (24901 * 1609) / 360.0; // 获取每度

double raidusMile = Double.parseDouble(raidus);

Double mpdLng = Double.parseDouble((degree * Math.cos(latitude * (Math.PI / 180))+"").replace("-", ""));

Double dpmLng = 1 / mpdLng;

Double radiusLng = dpmLng * raidusMile;

//获取最小经度

Double minLat = longitude - radiusLng;

// 获取最大经度

Double maxLat = longitude + radiusLng;

Double dpmLat = 1 / degree;

Double radiusLat = dpmLat * raidusMile;

// 获取最小纬度

Double minLng = latitude - radiusLat;

// 获取最大纬度

Double maxLng = latitude + radiusLat;

map.put("minLat", minLat+"");

map.put("maxLat", maxLat+"");

map.put("minLng", minLng+"");

map.put("maxLng", maxLng+"");

return map;

}

public static void main(String[] args) {

//测试经纬度:117.11811 36.68484

//测试经纬度2:117.00999000000002 36.66123

//System.out.println(getDistance("117.11811","36.68484","117.00999000000002","36.66123"));

System.out.println(getAround("117.11811", "36.68484", "13000"));

//117.01028712333508(Double), 117.22593287666493(Double),

//36.44829619896034(Double), 36.92138380103966(Double)

}

}

算法数学上实现思路: 判断一个点是在一个多边形内部的集中情况

第一:目标点在多边形的某一个顶点上,我们认为目标点在多边形内部

第二:目标点在多边形的任意一天边上,我们认为目标点在多边形内部

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

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

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

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

package cn.liuzw.point;

import java.util.ArrayList;

/**

* 点和线的一些公用方法

*

* @author liuZhiwei

* 2016年8月6日 下午3:48:38

*/

public class Point {

/**

* 是否有 横断

* 参数为四个点的坐标

* @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;

}

/**

* 目标点是否在目标边上边上

*

* @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));

}

/**

* 判断目标点是否在多边形内(由多个点组成)

*

* @param px 目标点的经度坐标

* @param py 目标点的纬度坐标

* @param polygonXA 多边形的经度坐标集合

* @param polygonYA 多边形的纬度坐标集合

* @return

*/

public boolean isPointInPolygon ( double px , double py , ArrayList polygonXA , ArrayList 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;

}

}

现在通常都是接口实现 需要考虑到数据库和效率 通常都是mysql  数据量也大 如何去实现就各位自行发展吧

地球经纬度java语言表示_java根据2个经纬度点,计算这2个经纬度点之间的距离(通过经度纬度得到距离)-Go语言中文社区...相关推荐

  1. 根据2个经纬度点,计算这2个经纬度点之间的距离(通过经度纬度得到距离)

    根据2个经纬度点,计算这2个经纬度点之间的距离(通过经度纬度得到距离) 球面上任意两点之间的距离计算公式可以参考维基百科上的下述文章. Great-circle distance Haversine ...

  2. java根据2个经纬度点,计算这2个经纬度点之间的距离(通过经度纬度得到距离)

    最近做一个项目:需要查询一个站点(已知该站点经纬度)500米范围内的其它站点.所以,我首先想到的是,对每条记录,去进行遍历,跟数据库中的每一个点进行距离计算,当距离小于500米时,认为匹配.这样做确实 ...

  3. R语言使用zoo包中的rollapply函数计算两个时间序列数据列之间的滚动相关性(Rolling correlations)、例如,计算两种商品销售额之间的3个月的滚动相关性

    R语言时间序列数据滚动相关性分析(Rolling correlations).R语言使用zoo包中的rollapply函数计算两个时间序列数据列之间的滚动相关性(Rolling correlation ...

  4. java取模数_java如何用负数做模数计算?

    负数模数的两个定义都在使用 – 有些语言使用一个定义,另一个使用另一个定义. 如果你想得到一个负数的负数input,那么你可以使用这个: int r = x % n; if (r > 0 &am ...

  5. java 线性计算器_java版科学计算器,支持表达式计算

    <java版科学计算器,支持表达式计算>由会员分享,可在线阅读,更多相关<java版科学计算器,支持表达式计算(12页珍藏版)>请在人人文库网上搜索. 1.程序设计综合设计题目 ...

  6. 与时间相关的java源码_Java 基于当前时间获取和计算时间

    import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java. ...

  7. java到期日期_java 常用时间操作类,计算到期提醒,N年后,N月后的日期

    packagecom.zjjerp.tool;importjava.text.ParseException;importjava.text.ParsePosition;importjava.text. ...

  8. python语言中文社区-python的汉语

    广告关闭 2017年12月,云+社区对外发布,从最开始的技术博客到现在拥有多个社区产品.未来,我们一起乘风破浪,创造无限可能. sdk 3.0 实现了统一化,各个语言版本的 sdk具备使用方法相同.接 ...

  9. 练习-Java分支结构综合练习二之物流运费计算

    第1关:练习-Java分支结构综合练习二之物流运费计算 任务描述 编程要求 测试说明 任务描述 货物的运输费用与距离和重量有关,距离 S 越远,每公里的运费越低.总运输费用 Exp 的计算公式为:Ex ...

  10. java代码例子_Java与C++两大语言比较

    Java Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承.指针等概念,因此Java语言具有功能强大和简单易用两个特征.Java语言作为静态面向对象编程 ...

最新文章

  1. mysql配置文件检查方法
  2. 40个很棒的由html5开发的网络游戏案例
  3. cad卸载_怎么把CAD卸载干净,老司机来教你
  4. linux arp 文件,LINUX 下ARP 的查找
  5. DOTNET Core MVC(二)路由初探
  6. hadoop ha 参考
  7. 如何选择自己适合的引流平台?
  8. php emoji处理微信表情
  9. paypal android app,PayPal
  10. 数独android程序,Android-数独世界自动完成标准数独的小脚本
  11. linux基础之系统安装
  12. Android加载PDF文档
  13. 2.5 信道的极限容量
  14. 【天光学术】财务会计论文:家电连锁零售企业财务分析方法与注意问题(节选)
  15. 怎么把ppt文件转换成pdf?解决方法有这几种
  16. php修改excel表格数据,php修改excel表格数据-php怎么导入Excel表格到数据库,根据表格内的字段......
  17. 关于分布式存储,这是你应该知道的
  18. leetcode198强盗抢劫
  19. 携职教育:为什么要考中级会计证?落户补贴、职场进阶…
  20. ISIC-2017 和 PH2 皮肤镜图像分割数据集

热门文章

  1. 【电源模块】LM2596 DCDC降压模块设计
  2. 移动应用开发--实现QQ登录界面(Android)
  3. Scrapy爬虫框架详解
  4. Mirillis Action! v4.17.0 高清游戏视频录制软件
  5. c语言求利用麦克劳林公式求sinx值,用泰勒公式求sin(x)的近似值
  6. Mac上命令行安装证书p12文件及描述文件mobileprovision
  7. try固定搭配_【昂立推荐】初中英语动词固定搭配大全,值得收藏!
  8. SSL安全证书:免费的SSL证书申请渠道有哪些?
  9. Spring系列缓存注解@Cacheable @CacheEvit @CachePut 使用姿势介绍
  10. c++ de-mangle 反编译器命名工具:c++filt