当前位置:   article > 正文

geotools使用_org.geotools

org.geotools

项目中遇到要用经纬度计算长度,周长,面积,电子栅栏的情况,可以使用geotools

准备工作

首先我们引入jar依赖

  1. <dependency>
  2. <groupId>org.geotools</groupId>
  3. <artifactId>gt-geometry</artifactId>
  4. <version>24.2</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.geotools</groupId>
  8. <artifactId>gt-epsg-hsql</artifactId>
  9. <version>24.2</version>
  10. </dependency>

很多同学会说下载不下来,我也遇到了这种情况,是马云的仓库里没有,这里我们换个仓库下载,

要贴在repositories标签里

  1. <!-- 下载 geotools用的 -->
  2. <repository>
  3. <id>osgeo</id>
  4. <name>OSGeo Release Repository</name>
  5. <url>https://repo.osgeo.org/repository/release/</url>
  6. <snapshots><enabled>false</enabled></snapshots>
  7. <releases><enabled>true</enabled></releases>
  8. </repository>
  9. <repository>
  10. <id>osgeo-snapshot</id>
  11. <name>OSGeo Snapshot Repository</name>
  12. <url>https://repo.osgeo.org/repository/snapshot/</url>
  13. <snapshots><enabled>true</enabled></snapshots>
  14. <releases><enabled>false</enabled></releases>
  15. </repository>
  16. <!-- 下载 geotools用的 -->

依赖搞定了,我们试试API

场景1:判断点是否在电子围栏中

我这次所有API用到的import如下

值得注意的是我的代码大多数来自ChatGPT,但是他给的不一定完全正确,他告诉我要引入24.2版本的,但是24.2版本的org.locationtech.jts这个包名和旧版本的不一样了

  1. import org.geotools.geometry.jts.JTS;
  2. import org.geotools.geometry.jts.JTSFactoryFinder;
  3. import org.geotools.referencing.CRS;
  4. import org.geotools.referencing.GeodeticCalculator;
  5. import org.geotools.referencing.crs.DefaultGeographicCRS;
  6. import org.locationtech.jts.geom.*;
  7. import org.locationtech.jts.geom.impl.CoordinateArraySequence;
  8. import org.locationtech.jts.io.WKTReader;
  9. import org.opengis.referencing.crs.CoordinateReferenceSystem;
  10. import org.opengis.referencing.operation.MathTransform;
  1. // 判断点是否在电子围栏中
  2. public static boolean isPointInFence(double lon, double lat, String fenceWkt) throws Exception {
  3. GeometryFactory gf = new GeometryFactory();
  4. WKTReader reader = new WKTReader(gf);
  5. // 解析电子围栏的边界点列表
  6. Coordinate[] coords = parseCoordinates(fenceWkt);
  7. LinearRing ring = new LinearRing(new CoordinateArraySequence(coords), gf);
  8. Polygon fence = new Polygon(ring, null, gf);
  9. // 创建目标点
  10. Point point = gf.createPoint(new Coordinate(lon, lat));
  11. // 判断点是否在围栏内
  12. return fence.contains(point);
  13. }
  14. // 解析WKT格式的坐标串
  15. private static Coordinate[] parseCoordinates(String wkt) throws Exception {
  16. WKTReader reader = new WKTReader();
  17. Geometry geom = reader.read(wkt);
  18. return geom.getCoordinates();
  19. }
  1. // 测试--点是否在电子围栏中
  2. String fenceWkt = "POLYGON((116.412928 39.930636,116.413198 39.928658,116.417348 39.928713,116.417043 39.930678,116.412928 39.930636))";
  3. double lon = 116.414797;
  4. double lat = 39.929792;
  5. boolean isInFence = GeoToolsUtils.isPointInFence(lon, lat, fenceWkt);
  6. System.out.println(isInFence);

场景2:经纬度点与点之间的距离

  1. public static double geotoolsDistance(double lon1, double lat1, double lon2, double lat2) throws Exception {
  2. CoordinateReferenceSystem crs = org.geotools.referencing.crs.DefaultGeographicCRS.WGS84;
  3. GeodeticCalculator gc = new GeodeticCalculator(crs);
  4. JTSFactoryFinder.getGeometryFactory(null);
  5. Coordinate coord1 = new Coordinate(lon1, lat1);
  6. Coordinate coord2 = new Coordinate(lon2, lat2);
  7. gc.setStartingPosition(org.geotools.geometry.jts.JTS.toDirectPosition(coord1, crs));
  8. gc.setDestinationPosition(org.geotools.geometry.jts.JTS.toDirectPosition(coord2, crs));
  9. return gc.getOrthodromicDistance() / 1000; // 单位为千米
  10. }

一开始ChatGPT给的代码是下面的

  1. public static final double R = 6371.0; // 地球平均半径,单位为千米
  2. public static double haversine(double lon1, double lat1, double lon2, double lat2) {
  3. double dLat = Math.toRadians(lat2 - lat1);
  4. double dLon = Math.toRadians(lon2 - lon1);
  5. double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
  6. Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) *
  7. Math.sin(dLon / 2) * Math.sin(dLon / 2);
  8. double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
  9. double d = R * c;
  10. return d;
  11. }
  1. //经纬度点与点之间的距离
  2. double distance = GeoToolsUtils.geotoolsDistance(116.509442, 39.98279, 116.509442, 39.982556);
  3. System.out.println(distance);
  4. double distance2 = GeoToolsUtils.haversine(116.509442, 39.98279, 116.509442, 39.982556);
  5. System.out.println(distance2);
  1. GeoTools计算的:0.025982026110380408
  2. 数学计算的:0.026019612834710798

场景三:判断点是否在圆内

就是给定圆心和半径

  1. public static boolean isInCircle(double lon1, double lat1, double lon2, double lat2, double radius) {
  2. double distance = haversine(lon1, lat1, lon2, lat2); // 计算两点之间的距离
  3. return distance <= radius;
  4. }

场景四:计算多边形面积

这个是结合地球半径,把多边形拆成多个三角形计算得出结果

  1. // 地球半径
  2. private static final double EARTH_RADIUS = 6378137.0; // meters
  3. // 计算多边形面积
  4. public static double calculatePolygonArea(List<Coordinate> coordinates) {
  5. double area = 0.0;
  6. int numPoints = coordinates.size();
  7. if (numPoints > 2) {
  8. for (int i = 0; i < numPoints; i++) {
  9. Coordinate p1 = coordinates.get(i);
  10. Coordinate p2 = coordinates.get((i + 1) % numPoints);
  11. area += Math.toRadians(p2.getX() - p1.getX()) *
  12. (2 + Math.sin(Math.toRadians(p1.getY())) +
  13. Math.sin(Math.toRadians(p2.getY())));
  14. }
  15. area = area * EARTH_RADIUS * EARTH_RADIUS / 2.0;
  16. }
  17. return Math.abs(area);
  18. }

测试

  1. List<Coordinate> polygonCoordinates = new ArrayList<>();
  2. polygonCoordinates.add(new Coordinate(116.412928, 39.930636)); // 左上角经纬度坐标
  3. polygonCoordinates.add(new Coordinate(116.413198, 39.928658)); // 左下角经纬度坐标
  4. polygonCoordinates.add(new Coordinate(116.417348, 39.928713)); // 右下角经纬度坐标
  5. polygonCoordinates.add(new Coordinate(116.417043, 39.930678)); // 右上角经纬度坐标
  6. polygonCoordinates.add(new Coordinate(116.412928, 39.930636)); // 右上角经纬度坐标
  7. double v = GeoToolsUtils.calculatePolygonArea(polygonCoordinates);
  8. System.out.println("多面积为:" + v);

"Mercator投影"。Mercator投影是一种圆柱投影,这个算法和通过球表面积计算的结果有很大出入,推荐用上的的解法。

  1. public static double calculateArea(List<Coordinate> coordinates) throws Exception {
  2. // 定义源坐标系和目标坐标系
  3. // 创建多边形对象
  4. GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory();
  5. LinearRing linearRing = geometryFactory.createLinearRing(coordinates.toArray(new Coordinate[0]));
  6. Polygon polygon = geometryFactory.createPolygon(linearRing, null);
  7. // 创建坐标参考系对象
  8. CoordinateReferenceSystem sourceCRS = DefaultGeographicCRS.WGS84;
  9. CoordinateReferenceSystem targetCRS = CRS.decode("EPSG:3857");
  10. // 创建坐标转换对象
  11. MathTransform transform = CRS.findMathTransform(sourceCRS, targetCRS);
  12. // 对多边形进行坐标转换
  13. Geometry geometry = JTS.transform(polygon, transform);
  14. System.out.println(geometry.getLength());
  15. // 计算多边形的面积
  16. return geometry.getArea();
  17. }

判断点是否在多边形内其他解法

  1. // 检查点是否位于多边形内
  2. public static boolean isPointInPolygon(Point2D.Double point, List<Point2D.Double> polygonCoords) {
  3. Path2D.Double polygon = new Path2D.Double();
  4. for (int i = 0; i < polygonCoords.size(); i++) {
  5. Point2D.Double coord = polygonCoords.get(i);
  6. if (i == 0) {
  7. polygon.moveTo(coord.getX(), coord.getY());
  8. } else {
  9. polygon.lineTo(coord.getX(), coord.getY());
  10. }
  11. }
  12. polygon.closePath();
  13. return polygon.contains(point);
  14. }
  1. public static void main(String[] args) {
  2. // 电子栅栏多边形的经纬度坐标列表
  3. List<Point2D.Double> polygonCoords = new ArrayList<>();
  4. polygonCoords.add(new Point2D.Double(39.930636, 116.412928));
  5. polygonCoords.add(new Point2D.Double(39.928658, 116.413198));
  6. polygonCoords.add(new Point2D.Double(39.928713, 116.417348));
  7. polygonCoords.add(new Point2D.Double(39.930678, 116.417043));
  8. polygonCoords.add(new Point2D.Double(39.930636, 116.412928));
  9. // 点的经纬度坐标列表
  10. List<Point2D.Double> pointCoords = new ArrayList<>();
  11. pointCoords.add(new Point2D.Double(39.929792, 116.414797));
  12. pointCoords.add(new Point2D.Double(39.929798, 116.414797));
  13. pointCoords.add(new Point2D.Double(37.400, -122.700));
  14. for (Point2D.Double point : pointCoords) {
  15. if (isPointInPolygon(point, polygonCoords)) {
  16. System.out.println("Point (" + point.getX() + ", " + point.getY() + ") is inside the polygon.");
  17. } else {
  18. System.out.println("Point (" + point.getX() + ", " + point.getY() + ") is outside the polygon.");
  19. }
  20. }
  21. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/476157
推荐阅读
  

闽ICP备14008679号