<dependency>
<groupId>org.locationtech.jts</groupId>
<artifactId>jts-core</artifactId>
<version>1.19.0</version>
</dependency>
1. 拆分
将一条MultiLineString拆分为两条MultiLineString
- 入参(根据自身情况设置):
"line": "{\"type\":\"Feature\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[106.20715987451636,30.3858925902819],[106.24233249673533,30.390289168059272]]},\"properties\":null}"
- 将String转换为Geometry类型
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.geotools.geojson.geom.GeometryJSON;
import org.locationtech.jts.geom.*;
import org.locationtech.jts.io.ByteOrderValues;
import org.locationtech.jts.io.WKBReader;
import org.locationtech.jts.io.WKBWriter;
import org.locationtech.jts.operation.distance.DistanceOp;
import javax.annotation.PostConstruct;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;
public static Geometry getGeomFromJSONString(String json) {
if (json == null) {
return null;
}
boolean validObject = JSON.isValidObject(json);
if (!validObject) {
return null;
}
JSONObject geometry = JSON.parseObject(json).getJSONObject("geometry");
if (geometry == null) {
return null;
}
return toGeom(geometry.toJSONString());
}
@PostConstruct
public void init() {
geometryUtils = this;
}
public static Geometry toGeom(String geom) {
if (StringUtils.isEmpty(geom)) {
return null;
}
try {
Geometry read = new GeometryJSON().read(geom);
if (read.getGeometryType().equals("MultiLineString")) {
read = read.getFactory().createLineString(read.getCoordinates());
}
return read;
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return null;
}
- 对原MultiLineString进行拆分
public static List<List<LineString>> getSegmentation(
Geometry multilineString, Geometry lineString) {
List<List<LineString>> lineList = new ArrayList<>();
if (multilineString == null || lineString == null) {
return null;
}
if (!multilineString.getGeometryType().equals(Geometry.TYPENAME_MULTILINESTRING)
|| !lineString.getGeometryType().equals(Geometry.TYPENAME_LINESTRING)) {
return null;
}
Geometry lsGeom = lineString.getGeometryN(0);
LineString ls = (LineString) lsGeom;
Geometry geometry0 = multilineString.getGeometryN(0);
LineString line0 = (LineString) geometry0;
Point start = line0.getStartPoint();
Point end = line0.getEndPoint();
int geometries = multilineString.getNumGeometries();
List<LineString> firstLineList = new ArrayList<>();
List<LineString> secondLineList = new ArrayList<>();
lineList.add(firstLineList);
lineList.add(secondLineList);
int noPint = 0;
for (int i = 0; i < geometries; i++) {
Geometry mlsGeom = multilineString.getGeometryN(i);
LineString mls = (LineString) mlsGeom;
Point startPoint = mls.getStartPoint();
// 检查两个几何对象是否相交
Geometry intersection = mls.intersection(ls);
// 容差值
double epsilon = 0.0000000001;
double startDistance = startPoint.distance(start);
double endDistance = startPoint.distance(end);
if (intersection instanceof Point) {
// 如果是点,说明只有一个交点
Point point = (Point) intersection;
// 查找切断点在LineString上的最近点
Coordinate nearestPoint = DistanceOp.nearestPoints(lineString, point)[0];
Coordinate[] coords = mls.getCoordinates();
// 创建切断点两侧的坐标数组
// 定义距离阈值
double threshold = 0.05; // 例如,0.05米
Coordinate coordinate = nearestPoint;
// 在目前的LineString 中找到一个最近的点分割
int index = 0;
int index2 = 0;
for (Coordinate coord : coords) {
double distance = coord.distance(nearestPoint);
index++;
if (distance == 0.0) {
index2 = index;
threshold = distance;
coordinate = coord;
} else if (distance <= threshold) {
index2 = index;
threshold = distance;
coordinate = coord;
}
}
System.out.println("点位:" + coordinate + "index:" + index2);
if (coordinate.equals(coords[0]) || coordinate.equals(coords[coords.length - 1])) {
if (Math.abs(startDistance - endDistance) < epsilon) {
firstLineList.add(mls);
} else {
secondLineList.add(mls);
}
} else {
Coordinate[] firstPartCoords = new Coordinate[index2];
System.arraycopy(mls.getCoordinates(), 0, firstPartCoords, 0, index2);
LineString firstPart = geometryFactory.createLineString(firstPartCoords);
// 保留分割点,用于判断两段LineString的前后连接关系
Coordinate[] secondPartCoords = new Coordinate[mls.getNumPoints() - index2 + 1];
System.arraycopy(
mls.getCoordinates(),
index2 - 1,
secondPartCoords,
0,
mls.getNumPoints() - index2 + 1);
LineString secondPart = geometryFactory.createLineString(secondPartCoords);
if (Math.abs(startDistance - endDistance) < epsilon) {
firstLineList.add(firstPart);
secondLineList.add(secondPart);
} else {
firstLineList.add(secondPart);
secondLineList.add(firstPart);
}
}
} else if (intersection instanceof MultiPoint) {
// 如果是多点,说明有多个交点
throw new BusinessException("该划线与该河段存在多个交点,请重新绘制划线");
// MultiPoint multiPoint = (MultiPoint) intersection;
// List<Coordinate> intersectionPoints = new ArrayList<>();
// for (int i = 0; i < multiPoint.getNumGeometries(); i++) {
// Point point = (Point) multiPoint.getGeometryN(i);
// intersectionPoints.add(new Coordinate(point.getX(), point.getY()));
// System.out.println("Intersection point " + (i + 1) + ": " + point);
// }
// 这里可以对intersectionPoints列表做进一步的处理
} else {
// 没有交点或交集不是点类型
noPint++;
boolean b = startDistance > endDistance && startDistance != 0.0;
boolean b1 = startDistance < endDistance && endDistance != 0.0;
// 判断那边是起点
if (firstLineList.size() > 0
&& firstLineList.get(0).getStartPoint().distance(start) == 0.0) {
// 如果第一条线的起点在firstLineList
if (endDistance == 0.0 || b) {
secondLineList.add(mls);
} else if (startDistance == 0.0 || b1) {
firstLineList.add(mls);
}
} else if (secondLineList.size() > 0
&& secondLineList.get(0).getStartPoint().distance(start) == 0.0) {
// 如果第一条线的起点在secondLineList
if (endDistance == 0.0 || b) {
firstLineList.add(mls);
} else if (startDistance == 0.0 || b1) {
secondLineList.add(mls);
}
} else if (firstLineList.size() == 0 && secondLineList.size() == 0) {
firstLineList.add(mls);
}
}
}
if (noPint == geometries) {
throw new BusinessException("该划线与该河段没有交点");
}
return lineList;
}
- 对List进行转化MultiLineString
public static MultiLineString getMultiLineString(List<LineString> lineStrings) {
try {
return geometryFactory.createMultiLineString(lineStrings.toArray(new LineString[0]));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
- 拆分成功
2. 合并
将多条MultiLineString拆分为一条MultiLineString
-
入参(根据自身情况设置),我是直接从库里拿对应geometry(MultiLineString)类型数据。
-
对多个geometry(MultiLineString)进行合并
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.geotools.geojson.geom.GeometryJSON;
import org.locationtech.jts.geom.*;
import org.locationtech.jts.io.ByteOrderValues;
import org.locationtech.jts.io.WKBReader;
import org.locationtech.jts.io.WKBWriter;
import org.locationtech.jts.operation.distance.DistanceOp;
import javax.annotation.PostConstruct;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;
public static Geometry mergeLine(List<Geometry> geom) {
int index = geom.get(0).getNumGeometries();
for (int i = 0; i < geom.size() - 1; i++) {
if (geom.get(i).getNumGeometries() < geom.get(i + 1).getNumGeometries()) {
index = geom.get(i + 1).getNumGeometries();
}
}
List<LineString> lineList = new ArrayList<>();
for (int i = 0; i < index; i++) {
List<LineString> line = new ArrayList<>();
int size = 0;
for (Geometry geometry : geom) {
LineString ls = null;
if (i < geometry.getNumGeometries()) {
Geometry mlsGeom = geometry.getGeometryN(i);
ls = (LineString) mlsGeom;
}
if (ls != null) {
line.add(ls);
} else {
size++;
}
}
if (size == geom.size()) {
throw new BusinessException("河段不存在");
}
lineList.add(mergeLineStrings(line));
}
if (!CollectionUtils.isEmpty(lineList)) {
// 对List<LineString>进行转化MultiLineString
return getMultiLineString(lineList);
}
return null;
}
public static LineString mergeLineStrings(List<LineString> line) {
if (line.size() == 1) {
return line.get(0);
}
// 先排序
List<LineString> lineList = new ArrayList<>();
int numPoints = line.get(0).getNumPoints();
int size = 0;
lineList.add(line.get(0));
while (lineList.size() < line.size()) {
for (LineString lineString : line) {
if (!lineString.equals(lineList.get(0))
&& !lineString.equals(lineList.get(lineList.size() - 1))) {
if (lineString.getStartPoint().equals(lineList.get(lineList.size() - 1).getEndPoint())) {
numPoints = numPoints + lineString.getNumPoints() - 1;
lineList.add(lineString);
} else if (lineString.getEndPoint().equals(lineList.get(0).getStartPoint())) {
numPoints = numPoints + lineString.getNumPoints() - 1;
lineList.add(0, lineString);
}
}
size++;
}
if (size >= 100) {
// 避免死循环,根据自己的情况设置
throw new BusinessException("合并失败");
}
}
// 进行合并
CoordinateSequenceFactory csFactory =
lineList.get(0).getFactory().getCoordinateSequenceFactory();
CoordinateSequence mergedSeq = csFactory.create(numPoints, 2); // 假设是二维坐标
// 使用System.arraycopy复制坐标到新的坐标序列中
System.arraycopy(
lineList.get(0).getCoordinateSequence().toCoordinateArray(),
0,
mergedSeq.toCoordinateArray(),
0,
lineList.get(0).getNumPoints());
int points = lineList.get(0).getNumPoints();
for (int i = 1; i < lineList.size(); i++) {
System.arraycopy(
lineList.get(i).getCoordinateSequence().toCoordinateArray(),
1,
mergedSeq.toCoordinateArray(),
points,
lineList.get(i).getNumPoints() - 1);
points = points + lineList.get(i).getNumPoints() - 1;
}
// 使用新的坐标序列创建合并后的LineString
return geometryFactory.createLineString(mergedSeq);
}
public static MultiLineString getMultiLineString(List<LineString> lineStrings) {
try {
return geometryFactory.createMultiLineString(lineStrings.toArray(new LineString[0]));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
- 合并成功