赞
踩
项目中遇到要用经纬度计算长度,周长,面积,电子栅栏的情况,可以使用geotools
首先我们引入jar依赖
- <dependency>
- <groupId>org.geotools</groupId>
- <artifactId>gt-geometry</artifactId>
- <version>24.2</version>
- </dependency>
- <dependency>
- <groupId>org.geotools</groupId>
- <artifactId>gt-epsg-hsql</artifactId>
- <version>24.2</version>
- </dependency>
很多同学会说下载不下来,我也遇到了这种情况,是马云的仓库里没有,这里我们换个仓库下载,
要贴在repositories标签里
- <!-- 下载 geotools用的 -->
- <repository>
- <id>osgeo</id>
- <name>OSGeo Release Repository</name>
- <url>https://repo.osgeo.org/repository/release/</url>
- <snapshots><enabled>false</enabled></snapshots>
- <releases><enabled>true</enabled></releases>
- </repository>
- <repository>
- <id>osgeo-snapshot</id>
- <name>OSGeo Snapshot Repository</name>
- <url>https://repo.osgeo.org/repository/snapshot/</url>
- <snapshots><enabled>true</enabled></snapshots>
- <releases><enabled>false</enabled></releases>
- </repository>
- <!-- 下载 geotools用的 -->
依赖搞定了,我们试试API
我这次所有API用到的import如下
值得注意的是我的代码大多数来自ChatGPT,但是他给的不一定完全正确,他告诉我要引入24.2版本的,但是24.2版本的org.locationtech.jts这个包名和旧版本的不一样了
- import org.geotools.geometry.jts.JTS;
- import org.geotools.geometry.jts.JTSFactoryFinder;
- import org.geotools.referencing.CRS;
- import org.geotools.referencing.GeodeticCalculator;
- import org.geotools.referencing.crs.DefaultGeographicCRS;
- import org.locationtech.jts.geom.*;
- import org.locationtech.jts.geom.impl.CoordinateArraySequence;
- import org.locationtech.jts.io.WKTReader;
- import org.opengis.referencing.crs.CoordinateReferenceSystem;
- import org.opengis.referencing.operation.MathTransform;
- // 判断点是否在电子围栏中
- public static boolean isPointInFence(double lon, double lat, String fenceWkt) throws Exception {
- GeometryFactory gf = new GeometryFactory();
- WKTReader reader = new WKTReader(gf);
-
- // 解析电子围栏的边界点列表
- Coordinate[] coords = parseCoordinates(fenceWkt);
- LinearRing ring = new LinearRing(new CoordinateArraySequence(coords), gf);
- Polygon fence = new Polygon(ring, null, gf);
-
- // 创建目标点
- Point point = gf.createPoint(new Coordinate(lon, lat));
-
- // 判断点是否在围栏内
- return fence.contains(point);
- }
-
- // 解析WKT格式的坐标串
- private static Coordinate[] parseCoordinates(String wkt) throws Exception {
- WKTReader reader = new WKTReader();
- Geometry geom = reader.read(wkt);
- return geom.getCoordinates();
- }
- // 测试--点是否在电子围栏中
- String fenceWkt = "POLYGON((116.412928 39.930636,116.413198 39.928658,116.417348 39.928713,116.417043 39.930678,116.412928 39.930636))";
- double lon = 116.414797;
- double lat = 39.929792;
- boolean isInFence = GeoToolsUtils.isPointInFence(lon, lat, fenceWkt);
- System.out.println(isInFence);
- public static double geotoolsDistance(double lon1, double lat1, double lon2, double lat2) throws Exception {
- CoordinateReferenceSystem crs = org.geotools.referencing.crs.DefaultGeographicCRS.WGS84;
- GeodeticCalculator gc = new GeodeticCalculator(crs);
- JTSFactoryFinder.getGeometryFactory(null);
- Coordinate coord1 = new Coordinate(lon1, lat1);
- Coordinate coord2 = new Coordinate(lon2, lat2);
- gc.setStartingPosition(org.geotools.geometry.jts.JTS.toDirectPosition(coord1, crs));
- gc.setDestinationPosition(org.geotools.geometry.jts.JTS.toDirectPosition(coord2, crs));
- return gc.getOrthodromicDistance() / 1000; // 单位为千米
- }
一开始ChatGPT给的代码是下面的
- public static final double R = 6371.0; // 地球平均半径,单位为千米
-
- public static double haversine(double lon1, double lat1, double lon2, double lat2) {
- double dLat = Math.toRadians(lat2 - lat1);
- double dLon = Math.toRadians(lon2 - lon1);
- double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
- Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) *
- Math.sin(dLon / 2) * Math.sin(dLon / 2);
- double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
- double d = R * c;
- return d;
- }
- //经纬度点与点之间的距离
- double distance = GeoToolsUtils.geotoolsDistance(116.509442, 39.98279, 116.509442, 39.982556);
- System.out.println(distance);
- double distance2 = GeoToolsUtils.haversine(116.509442, 39.98279, 116.509442, 39.982556);
- System.out.println(distance2);
- GeoTools计算的:0.025982026110380408
- 数学计算的:0.026019612834710798
就是给定圆心和半径
- public static boolean isInCircle(double lon1, double lat1, double lon2, double lat2, double radius) {
- double distance = haversine(lon1, lat1, lon2, lat2); // 计算两点之间的距离
- return distance <= radius;
- }
这个是结合地球半径,把多边形拆成多个三角形计算得出结果
- // 地球半径
- private static final double EARTH_RADIUS = 6378137.0; // meters
-
- // 计算多边形面积
- public static double calculatePolygonArea(List<Coordinate> coordinates) {
- double area = 0.0;
- int numPoints = coordinates.size();
-
- if (numPoints > 2) {
- for (int i = 0; i < numPoints; i++) {
- Coordinate p1 = coordinates.get(i);
- Coordinate p2 = coordinates.get((i + 1) % numPoints);
- area += Math.toRadians(p2.getX() - p1.getX()) *
- (2 + Math.sin(Math.toRadians(p1.getY())) +
- Math.sin(Math.toRadians(p2.getY())));
- }
- area = area * EARTH_RADIUS * EARTH_RADIUS / 2.0;
- }
-
- return Math.abs(area);
- }
测试
- List<Coordinate> polygonCoordinates = new ArrayList<>();
- polygonCoordinates.add(new Coordinate(116.412928, 39.930636)); // 左上角经纬度坐标
- polygonCoordinates.add(new Coordinate(116.413198, 39.928658)); // 左下角经纬度坐标
- polygonCoordinates.add(new Coordinate(116.417348, 39.928713)); // 右下角经纬度坐标
- polygonCoordinates.add(new Coordinate(116.417043, 39.930678)); // 右上角经纬度坐标
- polygonCoordinates.add(new Coordinate(116.412928, 39.930636)); // 右上角经纬度坐标
-
- double v = GeoToolsUtils.calculatePolygonArea(polygonCoordinates);
- System.out.println("多面积为:" + v);
"Mercator投影"。Mercator投影是一种圆柱投影,这个算法和通过球表面积计算的结果有很大出入,推荐用上的的解法。
- public static double calculateArea(List<Coordinate> coordinates) throws Exception {
- // 定义源坐标系和目标坐标系
- // 创建多边形对象
- GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory();
- LinearRing linearRing = geometryFactory.createLinearRing(coordinates.toArray(new Coordinate[0]));
- Polygon polygon = geometryFactory.createPolygon(linearRing, null);
-
- // 创建坐标参考系对象
- CoordinateReferenceSystem sourceCRS = DefaultGeographicCRS.WGS84;
- CoordinateReferenceSystem targetCRS = CRS.decode("EPSG:3857");
-
- // 创建坐标转换对象
- MathTransform transform = CRS.findMathTransform(sourceCRS, targetCRS);
-
- // 对多边形进行坐标转换
- Geometry geometry = JTS.transform(polygon, transform);
- System.out.println(geometry.getLength());
- // 计算多边形的面积
- return geometry.getArea();
- }
判断点是否在多边形内其他解法
- // 检查点是否位于多边形内
- public static boolean isPointInPolygon(Point2D.Double point, List<Point2D.Double> polygonCoords) {
- Path2D.Double polygon = new Path2D.Double();
- for (int i = 0; i < polygonCoords.size(); i++) {
- Point2D.Double coord = polygonCoords.get(i);
- if (i == 0) {
- polygon.moveTo(coord.getX(), coord.getY());
- } else {
- polygon.lineTo(coord.getX(), coord.getY());
- }
- }
- polygon.closePath();
- return polygon.contains(point);
- }
- public static void main(String[] args) {
- // 电子栅栏多边形的经纬度坐标列表
- List<Point2D.Double> polygonCoords = new ArrayList<>();
- polygonCoords.add(new Point2D.Double(39.930636, 116.412928));
- polygonCoords.add(new Point2D.Double(39.928658, 116.413198));
- polygonCoords.add(new Point2D.Double(39.928713, 116.417348));
- polygonCoords.add(new Point2D.Double(39.930678, 116.417043));
- polygonCoords.add(new Point2D.Double(39.930636, 116.412928));
-
- // 点的经纬度坐标列表
- List<Point2D.Double> pointCoords = new ArrayList<>();
- pointCoords.add(new Point2D.Double(39.929792, 116.414797));
- pointCoords.add(new Point2D.Double(39.929798, 116.414797));
- pointCoords.add(new Point2D.Double(37.400, -122.700));
-
- for (Point2D.Double point : pointCoords) {
- if (isPointInPolygon(point, polygonCoords)) {
- System.out.println("Point (" + point.getX() + ", " + point.getY() + ") is inside the polygon.");
- } else {
- System.out.println("Point (" + point.getX() + ", " + point.getY() + ") is outside the polygon.");
- }
- }
- }
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。