GeoTools使用--多面合并的空洞处理

在项目中经常用到多个城市地理数据的合并,但因城市的边界的规则性,就造成了在合并两个城市边界时出现了中间有空洞区域的情况。
以青海与甘肃张掖地理边界进行合并为例(为什么不用甘肃省的,因为省与省的地理边界往往是从同一套地理数据中提取的,存在边界空洞的情况就少一些)。来说明一下我的处理思路。

1.边界数据来源:阿里的地图选择器。datav.aliyun.com/tools/atlas。
2.在使用Geotools的Polygon.union进行合并后会出现边界有许多线段,从地图上放大看,其实是小块的空白区域。[如图1]
GeoTools使用--多面合并的空洞处理_第1张图片3.查看了Geotools的文档,有一个GeometryFilter的介绍(它的一些实现类有LineStringExtracter,PolygonExtracter)。可以对需要的几何图形进行过来筛选。
4.参考PolygonExtracter写了一个根据空洞图形内的标识坐标,来筛选哪些空洞图形可以保留,哪些空洞图形可以去掉。
主要是在filter方法,先获取面的外边界,生成一个全面图形。然后遍历原始面的内线InteriorRing,判断哪些标记点在内线图形上,就在全面图形中symDifference掉需要留空的区域。

import java.util.*;
import com.vividsolutions.jts.geom.*;
/**
 * 对面进行处理,去掉内部的空洞面。只保留inPointst满足条件的内部空洞面。
 */
public class MyPolygonExtracter implements GeometryFilter {

  private List inPoints;
  private List<Geometry> geometries;

  /**
   * @param inPoints 需要保留区域的标识 。说明:如果给定的inpoints中的其中一个坐标在孔洞平面的内部,就保留这个孔洞
   * @param list
   */
  private MyPolygonExtracter(List<Point> inPoints, List<Geometry> list) {
    this.inPoints=inPoints;
    this.geometries=list;
  }

  /**
   * @param geom 多平面合并后的面图形
   * @param inPoints 需要保留区域的标识 。说明:如果给定的inpoints中的其中一个坐标在孔洞平面的内部,就保留这个孔洞
   * @return
   */
  public static Geometry getPolygons(Geometry geom, List<Point> inPoints) {
    List<Geometry> list=new ArrayList<>();
    if (geom instanceof Polygon) {
      geom.apply(new MyPolygonExtracter(inPoints,list));
    } else if (geom instanceof MultiPolygon) {
      geom.apply(new MyPolygonExtracter(inPoints,list));
    }
    return list.get(0);
  }

  @Override
  public void filter(Geometry g) {
    if(g instanceof Polygon){
      Polygon polygon=(Polygon)g;
      //使用面的外边界生成一个大面
      Geometry tempExterPoly =g.getFactory().createPolygon(polygon.getExteriorRing().getCoordinates());
      if(geometries.size()==0){
        geometries.add(tempExterPoly);
      }else {
        geometries.set(0,geometries.get(0).union(tempExterPoly));
      }
      //得到面内空洞区域的数量
      int line=polygon.getNumInteriorRing();
      for(int i=0;i<line;i++){
        //获取空洞区域线边界
        LineString linearRingIn=((Polygon) g).getInteriorRingN(i);
        //生成空洞面
        Polygon temP=g.getFactory().createPolygon(linearRingIn.getCoordinates());
        //判断
        if(pointInPolygon(temP)){
          //symDifference 从外边界面中去掉空洞面
          geometries.set(0,geometries.get(0).symDifference(temP));
        }
      }
    }else if(g instanceof  MultiPolygon){
      int geoNums= ((MultiPolygon)g).getNumGeometries();
      for(int i=0;i<geoNums;i++){
        filter(g.getGeometryN(i));
      }
    }
  }

  /**
   * 判断 inPoints的坐标是否在空洞面内部
   * @param polygon
   * @return
   */
  private boolean pointInPolygon(Polygon polygon) {
    for (int i = 0; inPoints!=null &&i <inPoints.size() ; i++) {
      if( polygon.contains((Point)inPoints.get(i))){
        return true;
      }
    }
    return false;
  }
}

4.调用方法进行测试和测试效果


import cn.hutool.core.io.FileUtil;
import com.fw121.web.util.MyPolygonExtracter;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.Point;
import org.geotools.geojson.geom.GeometryJSON;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

public class PolygonUnionTest {

    GeometryJSON geometryJSON;

    @Before
    public  void before(){
        geometryJSON=new GeometryJSON();
    }

    @Test
    public void uninTest() throws IOException {
        String qinghai= FileUtil.readUtf8String("C:\\Users\\DELL\\Desktop\\qinghai.json");
        String zhangye= FileUtil.readUtf8String("C:\\Users\\DELL\\Desktop\\zhangye.json");
        Geometry qinghaiGeo=geometryJSON.read(qinghai);
        Geometry zhangyeGeo=geometryJSON.read(zhangye);
        Geometry unionPolygon=qinghaiGeo.union(zhangyeGeo);
        System.out.println(toGeoJsonStr(unionPolygon));

        //需要保留空洞的标识坐标点
        List<Point> inPoint=new ArrayList<>();
        Coordinate coords  = new Coordinate(100.5733966, 38.247051);
        inPoint.add(unionPolygon.getFactory().createPoint(coords));

        Geometry geometry = MyPolygonExtracter.getPolygons(unionPolygon,inPoint);
        System.out.println(toGeoJsonStr(geometry));
    }

    public  String toGeoJsonStr(Geometry geometry) throws IOException {
        StringWriter w = new StringWriter();
        geometryJSON.write(geometry,w);
        return w.toString();
    }
}

效果图,红色框中的为根据关键点保留的空白区域。
GeoTools使用--多面合并的空洞处理_第2张图片

你可能感兴趣的:(GeoTools使用--多面合并的空洞处理)