当前位置:首页 > 汽车 >

纬度之间的距离怎么求(纬度距离的计算公式)

来源:原点资讯(www.yd166.com)时间:2023-04-24 11:58:27作者:YD166手机阅读>>

手上有一个微信公众号项目有这样的一个需求,需要在用户打开微信公众号的时候将附近10公里的店铺按照距离用户当前位置的距离远近由近到远排序,展示在页面中,我们的前端程序猿比较low所以只能把这个计算放在后端。

我们来分析一下这个需求,这里我们需要从后台获取到店铺的列表,这里店铺位置的经纬度是入库的,所以可以随查询带出。用户当前的经纬度可以通过h5获取到,在公众号首页被打开的时候,将用户经纬度传递给后台。后台拿着这个经纬度后,遍历取出的店铺列表获取到店铺的经纬度进行计算。然后将结果返回给前端。

这里一个点是无法预知用户何时打开公众号,所以每次都即时计算距离,而且这个距离是不能入库的。因为每个用户所在位置不一样,这个距离就不一样。这里我们先来看一下项目原来的关键代码。

Service层:

/** * 查询全部列表并根据会员当前经纬度排序 * * @param point 经纬度坐标 * @param page 页码 * @param size 每页大小 * @return 店铺页面 */ public Page<Store> findAll(Point point, int page, int size) { List<Store> stores = storeDao.findAll(); //point有值才进行循环从而设置距离dis if (point.getLatitude() != null && point.getLongitude() != null) { for (Store store : stores) { //这里改写了store中的set store.setDis(point); } stores.sort(Comparator.comparing(Store::getDis)); } Pageable pageable = PageRequest.of(page - 1, size); Page<Store> storePage = List2PageUtil.list2Page(stores, pageable); return storePage; }

我们再看Store类。

/** * 通过百度的公式来计算两点之间的距离 * @param point 用户当前经纬度坐标 */ public void setDis(Point point) { double radLat1 = rad(Double.parseDouble(point.getLatitude())); double radLat2 = rad(Double.parseDouble(this.latitude)); double a = radLat1 - radLat2; double b = rad(Double.parseDouble(point.getLongitude())) - rad(Double.parseDouble(this.longitude)); double s = 2 * Math.asin(Math.sqrt(Math.abs(Math.pow(Math.sin(a/2),2) Math.cos(radLat1)*Math.cos(radLat2)*Math.pow(Math.sin(b/2),2)))); s = s * 6378.137; s = Math.round(s * 1000); this.dis = new BigDecimal(s); }

这里通过百度的公式来算了当前店铺和用户当前位置的距离。为了计算距离在Store对应的表里面增加了一个dis字段,然后保持空值。等到计算完了之后才把这个值加到Store对象中,可以说是相当繁琐了。

接下来我们想通过Redis提供的GeoHash来优化这些代码。关于什么是GeoHash,我稍后再写一个帖子来讲解。Geo特性是Redis3.2版本之后的一个新特性,这个功能可以将给定的地理位置信息存储起来并对这些信息进行操作。这里猜想可以利用Redis来解决这个问题。这里我们通过一个测试类来验证我们的猜想。

private RedisTemplate redisTemplate=null; @Test public void test() { redisTemplate=new RedisTemplate(); //添加店铺坐标 GeoOperations geoOperations = redisTemplate.opsForGeo(); geoOperations.add("store",new Point(118.11789, 24.479466) , "麦当劳(湖滨东路餐厅)"); geoOperations.add("store", new Point(118.088762, 24.467328), "陶乡涮涮锅(厦禾店)"); geoOperations.add("store", new Point(118.163978, 24.483079), "汕头八合里海记牛肉店(加州店)"); geoOperations.add("store", new Point(118.038997, 24.485467), "海底捞火锅(阿罗海城市广场店)"); geoOperations.add("store", new Point(118.178674, 24.49141), "必胜客(金山路餐厅)"); //假设用户当前坐标 118.129715, 24.49874 我们搜10公里以内的 Circle circle=new Circle(new Point(118.129715, 24.49874),new Distance(10,Metrics.KILOMETERS)); RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs .newGeoRadiusArgs().includeDistance() .includeCoordinates().sortAscending().limit(10); GeoResults<RedisGeoCommands.GeoLocation<String>> results=redisTemplate.opsForGeo().radius("store",circle,args); for (GeoResult<RedisGeoCommands.GeoLocation<String>> result : results) { System.out.println(result); } }

这里最早redisTemplate使用了自动注入但是注入不成功,报指针。于是采用在test方法里面new,结果运行依旧有问题。

java.lang.NullPointerException at org.springframework.data.redis.core.AbstractOperations.rawKey(AbstractOperations.java:112) at org.springframework.data.redis.core.DefaultGeoOperations.add(DefaultGeoOperations.java:57) at com.robot.merchant.StoreServiceTest.test(StoreServiceTest.java:28) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68) at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

打印redisTemplate并不为空,想到可能redisTemplate不空,但是里面可能某个值是空的。百度后发现需要添加redis相关的配置。修改方法:

private RedisTemplate redisTemplate = null; @Test public void test() { RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(); config.setPort(6379); config.setHostName("192.168.23.128"); JedisConnectionFactory factory = new JedisConnectionFactory(config); factory.afterPropertiesSet(); redisTemplate = new RedisTemplate(); redisTemplate.setConnectionFactory(factory); redisTemplate.afterPropertiesSet(); //添加店铺坐标 GeoOperations geoOperations = redisTemplate.opsForGeo(); geoOperations.add("store", new Point(118.11789, 24.479466), "麦当劳(湖滨东路餐厅)"); geoOperations.add("store", new Point(118.088762, 24.467328), "陶乡涮涮锅(厦禾店)"); geoOperations.add("store", new Point(118.163978, 24.483079), "汕头八合里海记牛肉店(加州店)"); geoOperations.add("store", new Point(118.038997, 24.485467), "海底捞火锅(阿罗海城市广场店)"); geoOperations.add("store", new Point(118.178674, 24.49141), "必胜客(金山路餐厅)"); //假设用户当前坐标 118.129715, 24.49874 我们搜10公里以内的 Circle circle = new Circle(new Point(118.129715, 24.49874), new Distance(10, Metrics.KILOMETERS)); RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs .newGeoRadiusArgs().includeDistance() .includeCoordinates().sortAscending().limit(10); GeoResults<RedisGeoCommands.GeoLocation<String>> results = redisTemplate.opsForGeo().radius("store", circle, args); for (GeoResult<RedisGeoCommands.GeoLocation<String>> result : results) { System.out.println(result); } }

运行报找不到JedisPoolConfig的字节码

Error:(21, 42) java: 无法访问redis.clients.jedis.JedisPoolConfig 找不到redis.clients.jedis.JedisPoolConfig的类文件

导入jedis的依赖,再次运行测试方法。成功通过。

GeoResult [content: RedisGeoCommands.GeoLocation(name=麦当劳(湖滨东路餐厅), point=Point [x=118.117889, y=24.479466]), distance: 2.4553 KILOMETERS, ] GeoResult [content: RedisGeoCommands.GeoLocation(name=汕头八合里海记牛肉店(加州店), point=Point [x=118.163981, y=24.483078]), distance: 3.8812 KILOMETERS, ] GeoResult [content: RedisGeoCommands.GeoLocation(name=必胜客(金山路餐厅), point=Point [x=118.178674, y=24.491410]), distance: 5.022 KILOMETERS, ] GeoResult [content: RedisGeoCommands.GeoLocation(name=陶乡涮涮锅(厦禾店), point=Point [x=118.088761, y=24.467328]), distance: 5.4216 KILOMETERS, ] GeoResult [content: RedisGeoCommands.GeoLocation(name=海底捞火锅(阿罗海城市广场店), point=Point [x=118.038995, y=24.485466]), distance: 9.3004 KILOMETERS, ] Process finished with exit code 0

这样证实我们可以通过redis来完成这个需求。这样就不再需要在set里面对距离进行计算了。

栏目热文

同一纬度经线的距离怎么算(同一纬度之间的距离怎么算)

同一纬度经线的距离怎么算(同一纬度之间的距离怎么算)

一、距离计算1.原理:纬度1°的经线长度=111km;赤道上经度1°的纬线长度=111km任何纬线上,经度1°的间隔=1...

2023-04-24 11:22:57查看全文 >>

吉利帝豪gl车门怎么打开(帝豪gl正常门打开图解)

吉利帝豪gl车门怎么打开(帝豪gl正常门打开图解)

车门怎么开?顺手一推就开,还是用其它方式?开车门看起来是件小事,其实里面存在着许多技巧。车外后视镜普遍存在一定的盲点,如...

2023-04-24 11:45:26查看全文 >>

吉利帝豪gl怎么打开车门(吉利帝豪gl打开车前盖图解)

吉利帝豪gl怎么打开车门(吉利帝豪gl打开车前盖图解)

吉利作为国产车,说实话很愿意支持,也很喜爱,但是两代车都让我有点心力交瘁了。我希望也祝愿国产品牌越来越好,吉利也越来越吉...

2023-04-24 11:18:21查看全文 >>

吉利帝豪gl引擎盖打开后如何关闭(吉利帝豪gl引擎盖怎么开)

吉利帝豪gl引擎盖打开后如何关闭(吉利帝豪gl引擎盖怎么开)

汽车引擎盖一般是不常打开的,只有出现故障时才会打开,那么当我们打开了汽车引擎盖后,要把它关闭时,汽车引擎盖怎么关闭呢,下...

2023-04-24 11:49:26查看全文 >>

吉利帝豪gl轿车牵引盖怎么打开(吉利帝豪gl汽车引擎盖内部图解)

吉利帝豪gl轿车牵引盖怎么打开(吉利帝豪gl汽车引擎盖内部图解)

拖车钩盖板是一个平时我们非常容易忽视的汽车结构。虽然平时不怎么起眼,但如果真的遇到了一些紧急或者突发状况时,需要其他救援...

2023-04-24 11:57:20查看全文 >>

纬度与纬度之间的距离公式(如何计算纬度之间的距离)

纬度与纬度之间的距离公式(如何计算纬度之间的距离)

【第一部分 方法指导】计算型选择题一般有两类。一类是题中提供信息材料,需要应用地理概念、原理、规律来解决问题。如区时与地...

2023-04-24 11:16:46查看全文 >>

纬度线是南北还是东西(纬度线是东西走向的吗)

纬度线是南北还是东西(纬度线是东西走向的吗)

经纬度是经度与纬度的合称,是利用三度空间的球面来定义地球上的空间的球面坐标系统。为了精确地表明各地在地球上的位置,人们给...

2023-04-24 11:54:19查看全文 >>

纬度线哪条最长(最低纬度线在哪)

纬度线哪条最长(最低纬度线在哪)

纬度是地球上任何一点在赤道以北或以南以度、分、秒为单位测量的角距离。赤道是环绕地球的一条线,位于南北两极之间,纬度为0°...

2023-04-24 11:22:45查看全文 >>

地图上的纬度1度的实际距离是多少(距离1公里经纬度最多差多少)

地图上的纬度1度的实际距离是多少(距离1公里经纬度最多差多少)

易错点一 对地图三要素理解不清 易错分析:学生容易出错的地方: (1)忽视图中的指向标,仍然按照“上北下南”的方法判断...

2023-04-24 11:36:41查看全文 >>

纬度线有多少条(经度纬度各是什么线)

纬度线有多少条(经度纬度各是什么线)

“经纬度线”是由经度和纬度表示地面点位置的球面坐标。经纬度线是怎么产生?又是如何测定的呢?早在公元前344年,亚历山大大...

2023-04-24 11:28:53查看全文 >>

文档排行