java 合并、拆分MultiLineString

        <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;
  }
  • 合并成功
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值