暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

利用 Spring Boot 与 Geodesy 库进行地理空间计算

源话编程 2024-08-16
564

👋 热爱编程的小伙伴们,欢迎来到我的编程技术分享公众号!在这里,我会分享编程技巧、实战经验、技术干货,还有各种有趣的编程话题!

地理空间计算在很多应用场景中都非常有用,比如地图应用、物流路线规划、位置服务等。在这篇文章中,我们将详细介绍如何使用 Spring Boot 与 Geodesy 库结合,实现距离计算和其他常见的地理空间计算功能。

1. 什么是 Geodesy 库?

Geodesy 库是一款用于地理空间计算的 Java 库,它提供了多种地理计算方法,如距离计算、方位角计算、纬度经度转换等。该库可以帮助我们处理地理坐标,并基于这些坐标进行各种计算。

2. 项目初始化

我们将使用 Spring Boot 来构建这个项目,并集成 Geodesy 库。首先,创建一个新的 Spring Boot 项目,并添加必要的依赖。

2.1 添加 Maven 依赖

pom.xml
中添加 Geodesy 库的依赖:

<dependency>
    <groupId>org.gavaghan</groupId>
    <artifactId>geodesy</artifactId>
    <version>1.1.3</version>
</dependency>

此外,确保 Spring Boot 的相关依赖已经正确配置。

3. 使用 Geodesy 库进行距离计算

现在我们来实现一个简单的距离计算功能。

3.1 创建 GeospatialService 类

service
包中创建一个GeospatialService
类,负责地理空间计算逻辑:

package com.example.geospatial.service;

import org.gavaghan.geodesy.Ellipsoid;
import org.gavaghan.geodesy.GlobalCoordinates;
import org.gavaghan.geodesy.GeodeticCalculator;
import org.springframework.stereotype.Service;

@Service
public class GeospatialService {

    private final GeodeticCalculator geoCalc = new GeodeticCalculator();
    private final Ellipsoid reference = Ellipsoid.WGS84;

    public double calculateDistance(double latitude1, double longitude1, double latitude2, double longitude2) {
        GlobalCoordinates source = new GlobalCoordinates(latitude1, longitude1);
        GlobalCoordinates destination = new GlobalCoordinates(latitude2, longitude2);
        return geoCalc.calculateGeodeticCurve(reference, source, destination).getEllipsoidalDistance();
    }
}

3.2 创建GeospatialController类

controller
包中创建一个GeospatialController
类,提供一个 API 端点供外部调用:

package com.example.geospatial.controller;

import com.example.geospatial.service.GeospatialService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class GeospatialController {

    @Autowired
    private GeospatialService geospatialService;

    @GetMapping("/distance")
    public double getDistance(@RequestParam double latitude1,
                              @RequestParam double longitude1,
                              @RequestParam double latitude2,
                              @RequestParam double longitude2)
 
{
        return geospatialService.calculateDistance(latitude1, longitude1, latitude2, longitude2);
    }
}

3.3 代码解析

  1. GeodeticCalculator: 用于计算两个地理坐标之间的距离。
  2. Ellipsoid: 使用 WGS84 椭球作为地球的参考椭球体。
  3. GlobalCoordinates: 用于表示地理坐标(纬度和经度)。

3.4 示例请求

假设你想计算从北京(纬度:39.9042,经度:116.4074)到上海(纬度:31.2304,经度:121.4737)的距离,可以通过如下URL访问:

http://localhost:8080/distance?latitude1=39.9042&longitude1=116.4074&latitude2=31.2304&longitude2=121.4737

返回的结果是两地之间的距离,单位为米。

4. 扩展地理空间计算功能

除了距离计算,Geodesy 库还可以实现其他地理空间计算功能,比如方位角计算、两点间的中点计算等。

4.1 计算方位角

我们可以在GeospatialService
中添加一个计算方位角的方法:

public double calculateAzimuth(double latitude1, double longitude1, double latitude2, double longitude2) {
    GlobalCoordinates source = new GlobalCoordinates(latitude1, longitude1);
    GlobalCoordinates destination = new GlobalCoordinates(latitude2, longitude2);
    return geoCalc.calculateGeodeticCurve(reference, source, destination).getAzimuth();
}

然后在GeospatialController
中提供一个新的 API 端点:

@GetMapping("/azimuth")
public double getAzimuth(@RequestParam double latitude1,
                         @RequestParam double longitude1,
                         @RequestParam double latitude2,
                         @RequestParam double longitude2)
 
{
    return geospatialService.calculateAzimuth(latitude1, longitude1, latitude2, longitude2);
}

4.2 计算两点间的中点

类似地,可以计算两点间的中点:

public GlobalCoordinates calculateMidpoint(double latitude1, double longitude1, double latitude2, double longitude2) {
    // 简单实现,两点的平均值作为中点
    double midLatitude = (latitude1 + latitude2) / 2;
    double midLongitude = (longitude1 + longitude2) / 2;
    return new GlobalCoordinates(midLatitude, midLongitude);
}

4.3 计算两点之间的航行时间(Estimated Time of Arrival, ETA)

在导航或物流系统中,估算到达时间(ETA)是一个重要的功能。虽然Geodesy库本身不直接提供此功能,但我们可以结合速度和距离来计算ETA。

public double calculateETA(double latitude1, double longitude1, double latitude2, double longitude2, double speed) {
    double distance = calculateDistance(latitude1, longitude1, latitude2, longitude2);
    return distance / speed; // 返回时间,单位为小时
}

通过计算两个地点之间的距离并结合平均速度,你可以估算出到达时间。

4.4 计算地理边界(Bounding Box)

地理边界(Bounding Box)是确定某个地理区域的矩形边界,常用于地理查询或地图显示。

public BoundingBox calculateBoundingBox(double latitude, double longitude, double distanceInMeters) {
    GlobalCoordinates center = new GlobalCoordinates(latitude, longitude);
    double earthRadius = 6371000// 地球半径,单位为米

    double latOffset = distanceInMeters / earthRadius * (180 / Math.PI);
    double lonOffset = distanceInMeters / (earthRadius * Math.cos(Math.toRadians(latitude))) * (180 / Math.PI);

    double minLatitude = latitude - latOffset;
    double maxLatitude = latitude + latOffset;
    double minLongitude = longitude - lonOffset;
    double maxLongitude = longitude + lonOffset;

    return new BoundingBox(minLatitude, maxLatitude, minLongitude, maxLongitude);
}

4.5 判定点是否在多边形内

判定某个点是否在指定的多边形内是一个典型的地理空间计算问题,常用于地理围栏应用中。

public boolean isPointInPolygon(double latitude, double longitude, List<GlobalCoordinates> polygon) {
    int intersectCount = 0;
    for (int i = 0; i < polygon.size() - 1; i++) {
        GlobalCoordinates p1 = polygon.get(i);
        GlobalCoordinates p2 = polygon.get(i + 1);
        if (rayCastIntersect(latitude, longitude, p1, p2)) {
            intersectCount++;
        }
    }
    return (intersectCount % 2) == 1// 奇数个交点表示点在多边形内
}

4.6 计算点的平移(Translate Point)

在某些应用中,你可能需要根据某个点和距离,计算出一个新的点位置,这种操作称为点的平移。

public GlobalCoordinates translatePoint(double latitude, double longitude, double distanceInMeters, double bearing) {
    GlobalCoordinates startPoint = new GlobalCoordinates(latitude, longitude);
    double angularDistance = distanceInMeters / Ellipsoid.WGS84.getSemiMajorAxis();

    double newLat = Math.asin(Math.sin(Math.toRadians(latitude)) * Math.cos(angularDistance) +
            Math.cos(Math.toRadians(latitude)) * Math.sin(angularDistance) * Math.cos(Math.toRadians(bearing)));
    double newLon = Math.toRadians(longitude) +
            Math.atan2(Math.sin(Math.toRadians(bearing)) * Math.sin(angularDistance) * Math.cos(Math.toRadians(latitude)),
                    Math.cos(angularDistance) - Math.sin(Math.toRadians(latitude)) * Math.sin(newLat));

    return new GlobalCoordinates(Math.toDegrees(newLat), Math.toDegrees(newLon));
}

4.7 计算多边形的面积

在一些地理应用中,计算多边形的面积也是非常常见的需求,尤其是在GIS系统中。

public double calculatePolygonArea(List<GlobalCoordinates> polygon) {
    double area = 0.0;
    for (int i = 0; i < polygon.size() - 1; i++) {
        GlobalCoordinates p1 = polygon.get(i);
        GlobalCoordinates p2 = polygon.get(i + 1);
        area += Math.toRadians(p2.getLongitude() - p1.getLongitude()) *
                (2 + Math.sin(Math.toRadians(p1.getLatitude())) + Math.sin(Math.toRadians(p2.getLatitude())));
    }
    area = area * Ellipsoid.WGS84.getSemiMajorAxis() * Ellipsoid.WGS84.getSemiMajorAxis() / 2.0;
    return Math.abs(area); // 返回面积,单位为平方米
}

扩展:与数据库或GIS工具的集成

Geodesy 库的功能可以与数据库中的地理数据(如 PostGIS )或 GIS 工具(如 GeoTools )结合使用,以便在复杂的地理空间应用中处理大规模的地理数据。

结语

本文介绍了如何使用 Spring Boot 结合 Geodesy 库来实现地理空间计算功能,如距离计算和方位角计算等。通过这些功能,你可以轻松地在你的应用程序中实现地理位置相关的计算逻辑。

Geodesy 库是一个功能强大的工具,可以大大简化地理空间计算的复杂性。在实际项目中,你可以根据需求扩展和定制这些功能,以满足不同场景的应用。


个人观点,仅供参考,非常感谢各位朋友们的支持与关注

如果你觉得这个作品对你有帮助,请不吝点赞在看,分享给身边更多的朋友。如果你有任何疑问或建议,欢迎在评论区留言交流。


文章转载自源话编程,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论