GeoTools使用--多面合併的空洞處理

在項目中經常用到多個城市地理數據的合併,但因城市的邊界的規則性,就造成了在合併兩個城市邊界時出現了中間有空洞區域的情況。
以青海與甘肅張掖地理邊界進行合併爲例(爲什麼不用甘肅省的,因爲省與省的地理邊界往往是從同一套地理數據中提取的,存在邊界空洞的情況就少一些)。來說明一下我的處理思路。

1.邊界數據來源:阿里的地圖選擇器。datav.aliyun.com/tools/atlas。
2.在使用Geotools的Polygon.union進行合併後會出現邊界有許多線段,從地圖上放大看,其實是小塊的空白區域。[如圖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();
    }
}

效果圖,紅色框中的爲根據關鍵點保留的空白區域。
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章