geotools在项目中使用的频率很高,今天我们分享一下:比如用经纬度计算长度,周长,面积,电子栅栏。
1、pom文件引入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>
阿里云镜像下载失败,在添加一个镜像
<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>
2、判断点是否在多边形图形地图中
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();
}
测试验证
public static void main(String[] args) throws Exception {
// 测试--点是否在电子围栏中
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 = 16.414797;
double lat = 39.929792;
boolean isInFence = isPointInFence(lon, lat, fenceWkt);
System.out.println(isInFence);
}
3、两个点之间的距离
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; // 单位为千米
}
4、判断点是否在圆内
public static boolean isInCircle(double lon1, double lat1, double lon2, double lat2, double radius) {
double distance = haversine(lon1, lat1, lon2, lat2); // 计算两点之间的距离
return distance <= radius;
}
5、计算多边形的面积
// 地球半径
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);
6、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();
}
7、判断点是否在多边形内其他解决方案
// 检查点是否位于多边形内
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.");
}
}
}
8、投影和仿射转换方案
到此,今天分享完成,后续会持续更新,敬请期待!