文章目录JTS使用实践一、前言简介环境二、正文基础说明使用记录创建几何要素操作示例JTS使用实践一、前言简介JTSTopologySuite是一个开源的Java软件库,它为欧几里得平面线性几何提供了一个对象模型以及一组基本的几何函数。
文章目录JTS Topology Suite(Java Topology Suite)是一个开源的Java软件库,它为欧几里得平面线性几何提供了一个对象模型以及一组基本的几何函数。
环境二、正文 基础说明locationtech(JTS):https://locationtech.github.io/jts/
JTS 特性:https://locationtech.github.io/jts/jts-features.html
GitHub(JTS):https://github.com/locationtech/jts
JTS java doc:http://locationtech.github.io/jts/javadoc/overview-summary.html
GeoTools(JTS):https://docs.geotools.org/latest/userguide/library/jts/index.html
wikipedia(JTS):https://en.wikipedia.org/wiki/JTS_Topology_Suite
wikipedia(WKT):https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry
PostGIS 拓扑关系:https://postgis.net/docs/reference.html#idm15481
polygon 和 multipolygon 的区别:https://gis.stackexchange.com/questions/225368/understanding-difference-between-polygon-and-multipolygon-for-shapefiles-in-qgis/225373
几何类型 | WKT |
---|---|
Point | POINT (30 10) |
LineString | LINESTRING (30 10, 10 30, 40 40) |
Polygon | POLYGON ((35 10, 45 45, 15 40, 10 20, 35 10),(20 30, 35 35, 30 20, 20 30)) |
Polygon-with-hole | POLYGON ((35 10, 45 45, 15 40, 10 20, 35 10), (20 30, 35 35, 30 20, 20 30)) |
MultiPoint | MULTIPOINT ((10 40), (40 30), (20 20), (30 10)) |
MultiPoint | MULTIPOINT (10 40, 40 30, 20 20, 30 10) |
MultiLineString | MULTILINESTRING ((10 10, 20 20, 10 40),(40 40, 30 30, 40 20, 30 10)) |
MultiPolygon | MULTIPOLYGON (((30 20, 45 40, 10 40, 30 20)), ((15 5, 40 10, 10 20, 5 10, 15 5))) |
MultiPolygon-with-hole | MULTIPOLYGON (((40 40, 20 45, 45 30, 40 40)), ((20 35, 10 30, 10 10, 30 5, 45 20, 20 35), (30 20, 20 15, 20 25, 30 20))) |
GeometryCollection | GEOMETRYCOLLECTION (POINT (40 10), LINESTRING (10 10, 20 20, 10 40), POLYGON ((40 40, 20 45, 45 30, 40 40))) |
关键字 | 说明 | 参考 |
---|---|---|
equals (相等) | 如果两个几何在空间中包含相同的一组点,则返回 true | ST_Equals |
disjoint(不相交) | 如果两个几何在空间上不相交(它们没有共同点),则返回 true | ST_Disjoint |
intersects(相交) | 如果两个几何/地理在 2D 空间上相交(至少有一个共同点),则返回 true | ST_Intersects |
touches(接触) | 如果两个几何体至少有一个共同点,但它们的内部不相交,则返回 true | ST_Touches |
crosses(交叉) | 如果两个几何具有一些(但不是全部)共同的内部点,则返回 true | ST_Crosses |
within(内含) | 如果几何 A 完全在几何 B 内部,则返回 true | ST_Within |
contains (包含) | 当且仅当 B 的任何点都不在 A 的外部,并且 B 内部的至少一个点在 A 的内部时,才返回 true | ST_Contains |
overlaps(重叠) | 如果两个几何体相交并具有相同的维度,但彼此不完全包含,则返回 true | ST_Overlaps |
关键字 | 说明 | 参考 |
---|---|---|
buffer(缓冲区) | 返回一个几何图形,该几何图形涵盖距几何图形给定距离内的所有点 | ST_Buffer |
convexHull(凸壳) | 计算几何的凸壳 | ST_ConvexHull |
intersection(交集) | 返回表示几何 A 和 B 共享部分的几何 | ST_Intersection |
union(合并) | 返回表示输入几何的点集合并的几何 | ST_Union |
difference(差异) | 返回表示几何 A 中不与几何 B 相交的部分的几何 | ST_Difference |
symDifference(对称差异) | 返回表示几何 A 和 B 不相交部分的几何 | ST_SymDifference |
创建几何要素org.locationtech.jts jts-core 1.18.2
package com.example; import org.locationtech.jts.geom.*; import org.locationtech.jts.io.ParseException; import org.locationtech.jts.io.WKTReader; import java.util.List; import java.util.Map; public class JTSGeometryUtil { // 几何工厂对象 private GeometryFactory geometryFactory = new GeometryFactory(); public Point getPoint(Double lng, Double lat){ Coordinate coordinate = new Coordinate(lng, lat); return geometryFactory.createPoint(coordinate); } public Point getPointByWKT(Double lng, Double lat) throws ParseException { StringBuilder wktSB = new StringBuilder(); // POINT(111 22) wktSB.append("POINT").append("(").append( lng ).append(" ").append( lat ).append(")"); return (Point) createGeometry(wktSB.toString()); } public MultiPoint getMultiPoint(Coordinate [] coordinates){ return geometryFactory.createMultiPointFromCoords(coordinates); } public MultiPoint getMultiPointByWKT(Coordinate [] coordinates) throws ParseException { // MULTIPOINT(111 22 ,111 22) String wktStr = createWktString("MULTIPOINT", coordinates); return (MultiPoint) createGeometry(wktStr); } public LineString getLineString(Coordinate [] coordinates){ return geometryFactory.createLineString(coordinates); } public LineString getLineStringByWKT(Coordinate [] coordinates) throws ParseException { String wktStr = createWktString("LINESTRING", coordinates); return (LineString) createGeometry(wktStr); } public MultiLineString getMultiLineString(List操作示例coordList){ LineString [] lineStrings = new LineString[coordList.size()]; for(int m=0; m lineStrings[m] = getLineString(coordList.get(m)); } return geometryFactory.createMultiLineString(lineStrings); } public MultiLineString getMultiLineStringByWKT(List coordList) throws ParseException { String wktStr = createMultiWktString("MULTILINESTRING", coordList); return (MultiLineString) createGeometry(wktStr); } public Polygon getPolygon(Coordinate [] coordinates){ return geometryFactory.createPolygon(coordinates); } public Polygon getPolygon(Coordinate [] shellCoordinates, List holeCoordList){ LinearRing shell = geometryFactory.createLinearRing(shellCoordinates); LinearRing[] holes = new LinearRing[holeCoordList.size()]; for(int m=0; m Coordinate [] holeCoordinates = holeCoordList.get(m); holes[m] = geometryFactory.createLinearRing(holeCoordinates); } return geometryFactory.createPolygon(shell, holes); } public Polygon getPolygonByWKT(Coordinate [] coordinates) throws ParseException { String wktStr = createWktStringWithPolygon("POLYGON", coordinates, null); return (Polygon) createGeometry(wktStr); } public Polygon getPolygonByWKT(Coordinate [] shellCoordinates, List holeCoordList) throws ParseException { String wktStr = createWktStringWithPolygon("POLYGON", shellCoordinates, holeCoordList); return (Polygon) createGeometry(wktStr); } public MultiPolygon getMultiPolygon(List coordList){ Polygon [] polygons = new Polygon[ coordList.size() ]; for(int i=0; i polygons[i] = geometryFactory.createPolygon(coordList.get(i)); } return geometryFactory.createMultiPolygon(polygons); } public MultiPolygon getMultiPolygon(Map > coordinateMap){ Polygon [] polygons = new Polygon[ coordinateMap.size() ]; int index = 0; for(Map.Entry > item : coordinateMap.entrySet()){ LinearRing shell = geometryFactory.createLinearRing(item.getKey()); // 面边界 LinearRing[] holes = new LinearRing[item.getValue().size()]; // 孔洞 for(int m=0; m Coordinate [] holeCoordinates = item.getValue().get(m); holes[m] = geometryFactory.createLinearRing(holeCoordinates); } polygons[index] = geometryFactory.createPolygon(shell, holes); index++; } return geometryFactory.createMultiPolygon(polygons); } public MultiPolygon getMultiPolygonByWKT(List coordList) throws ParseException { StringBuilder wktSB = new StringBuilder(); wktSB.append("MULTIPOLYGON").append("("); int index = 0; for(Coordinate [] coordinates : coordList){ if(index > 0) { wktSB.append(","); } // 1. 处理面边界 wktSB.append("("); wktSB.append("("); // 面边界start wktSB.append(coordinatesToWktStr(coordinates)); wktSB.append(")"); // 面边界end wktSB.append(")"); index++; } wktSB.append(")"); return (MultiPolygon) createGeometry(wktSB.toString()); } public MultiPolygon getMultiPolygonByWKT(Map > coordinateMap) throws ParseException { StringBuilder wktSB = new StringBuilder(); wktSB.append("MULTIPOLYGON").append("("); int index = 0; for(Map.Entry > item : coordinateMap.entrySet()){ Coordinate [] shellCoordinates = item.getKey(); List holeCoordList = item.getValue(); if(index > 0) { wktSB.append(","); } wktSB.append("("); wktSB.append(coordinatesToWktStr(shellCoordinates, holeCoordList)); wktSB.append(")"); index++; } wktSB.append(")"); return (MultiPolygon) createGeometry(wktSB.toString()); } public Polygon getCircle(double lng, double lat, final double radius) { final int arcs = 32; // 弧线点数量 Coordinate coords[] = new Coordinate[ arcs + 1 ]; for (int i = 0; i < arcs; i++) { // 角度转弧度计算 double angle = ((double) i / (double) arcs) * Math.PI * 2.0; double dx = Math.cos(angle) * radius; double dy = Math.sin(angle) * radius; coords[i] = new Coordinate((double) lng + dx, (double) lat + dy); } coords[arcs] = coords[0]; // 将第一个数据放在最后,形成闭环 LinearRing ring = geometryFactory.createLinearRing(coords); // 圆环线 Polygon polygon = geometryFactory.createPolygon(ring, null); return polygon; } public Geometry createGeometry(String wktStr) throws ParseException { WKTReader wktReader = new WKTReader(geometryFactory); return wktReader.read(wktStr); } public String createWktString(String geomType, Coordinate [] coordinates){ StringBuilder wktSB = new StringBuilder(); wktSB.append(geomType).append("("); wktSB.append(coordinatesToWktStr(coordinates)); wktSB.append(")"); return wktSB.toString(); } private String coordinatesToWktStr(Coordinate [] coordinates){ StringBuilder wktSB = new StringBuilder(); for(int i=0; i Coordinate coordinate = coordinates[i]; wktSB.append( coordinate.getX() ).append(" ").append( coordinate.getY() ); if(coordinates.length-1 != i){ wktSB.append(","); } // 最后一个坐标不需要加逗号 } return wktSB.toString(); } private String coordinatesToWktStr(Coordinate [] shellCoordinates, List holeCoordList){ StringBuilder wktSB = new StringBuilder(); // 1. 处理面边界 wktSB.append("("); // 面边界start wktSB.append(coordinatesToWktStr(shellCoordinates)); wktSB.append(")"); // 面边界end // 2. 处理多个孔洞 if(holeCoordList != null && holeCoordList.size() > 0){ for(int n=0; n Coordinate [] holeCoordinates = holeCoordList.get(n); wktSB.append(","); wktSB.append("("); // 面边界start wktSB.append(coordinatesToWktStr(holeCoordinates)); wktSB.append(")"); // 面边界end } } return wktSB.toString(); } public String createMultiWktString(String geomType, List coordList){ StringBuilder wktSB = new StringBuilder(); wktSB.append(geomType).append("("); for(int m=0; m Coordinate [] coordinates = coordList.get(m); wktSB.append("("); for(int n=0; n Coordinate coordinate = coordinates[n]; wktSB.append( coordinate.getX() ).append(" ").append( coordinate.getY() ); if(coordinates.length-1 != n){ wktSB.append(","); } // 最后一个坐标不需要加逗号 } wktSB.append(")"); if(coordList.size()-1 != m){ wktSB.append(","); } // 最后一个坐标不需要加逗号 } wktSB.append(")"); return wktSB.toString(); } public String createWktStringWithPolygon(String geomType, Coordinate [] shellCoordinates, List holeCoordList){ StringBuilder wktSB = new StringBuilder(); wktSB.append(geomType).append("("); wktSB.append(coordinatesToWktStr(shellCoordinates, holeCoordList)); wktSB.append(")"); return wktSB.toString(); } }
package com.example; import org.locationtech.jts.geom.*; public class App { public static void main( String[] args ) { App app = new App(); // 拓扑关系 contains app.doContains(); // 叠加分析 intersection app.doIntersection(); } private JTSGeometryUtil jtsGeometryUtil = new JTSGeometryUtil(); public void doContains(){ // 点 Point point = jtsGeometryUtil.getPoint(116.403406,39.93397); // 面 Coordinate[] coordinates = new Coordinate[4]; coordinates[0] = new Coordinate(116.361725,39.95676); // 首尾坐标相同 coordinates[1] = new Coordinate(116.364887,39.908515); coordinates[2] = new Coordinate(116.442501,39.909622); coordinates[2] = new Coordinate(116.440488,39.955654); coordinates[3] = new Coordinate(116.361725,39.95676); // 首尾坐标相同 Polygon polygon = jtsGeometryUtil.getPolygon(coordinates); // 操作 boolean result = polygon.contains(point); System.out.println(result); } public void doIntersection(){ // 线一 Coordinate [] coordinates1 = new Coordinate[2]; coordinates1[0] = new Coordinate(116.361725,39.95676); coordinates1[1] = new Coordinate(116.442501,39.909622); LineString lineString1 = jtsGeometryUtil.getLineString(coordinates1); // 线二 Coordinate [] coordinates2 = new Coordinate[2]; coordinates2[0] = new Coordinate(116.364887,39.908515); coordinates2[1] = new Coordinate(116.440488,39.955654); LineString lineString2 = jtsGeometryUtil.getLineString(coordinates2); // 操作 Geometry geometry = lineString1.intersection(lineString2); System.out.println(geometry); } }