GeoTools使用--多面合并的空洞处理_java geotools临近的面合并-程序员宅基地

技术标签: java  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();
    }
}

效果图,红色框中的为根据关键点保留的空白区域。
在这里插入图片描述

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/aofavx/article/details/105092116

智能推荐

基于模板匹配的数字识别_基于模板匹配的数字电表数字识别-程序员宅基地

文章浏览阅读6.9k次,点赞5次,收藏35次。基于模板匹配的数字识别,将标准的8*16像素的数字0123456789读取,二值化,对每个数字进行等分区域分割,统计每个区域内的黑色像素点的个数,即为特征初值。采用欧式距离的模板匹配法。z//基于模板匹配的数字识别#include#include#include#include #includeusing namespace std; int main()_基于模板匹配的数字电表数字识别

Python代码的编写运行方式介绍_python安装好后怎么写代码-程序员宅基地

文章浏览阅读7.2k次,点赞11次,收藏74次。Python代码的编写运行方式详解_python安装好后怎么写代码

VS Code使用code runner插件无法识别gcc编译C语言程序_vscode无法识别gcc-程序员宅基地

文章浏览阅读1.2k次。VS Code配置Code runner_vscode无法识别gcc

Unity3D中使用mesh collider和box collider的区别-程序员宅基地

文章浏览阅读1.5w次,点赞10次,收藏14次。Unity3D中使用mesh collider和box collider的区别踩坑过程记录。设备是HTC的VIVE 和 Unity 5.xCPU: Intel Xeon Silver 4116 * 2GPU: NVIDIA Quadro P6000RAM: 64GB这个问题是在解决项目卡顿问题的同时出现的:最近在用U3D做一个VR项目,需求是要给网格加碰撞体以实现获取手柄射线与..._mesh collider和box collider

关于jar包后台运行及端口占用问题_centos启动jar包不显示端口占用-程序员宅基地

文章浏览阅读4.7k次。问题场景问题一:后端项目jar包打包上传运行,终端上正常,终端退出后,项目未能运行。问题二:第二次上传jar包并运行时提示该端口被占用。解决方法问题一:使用nohub命令启动jar包。nohup java -jar 1.0.0.jar &问题二:由于两次使用的同一个端口,先查找到当前端口正在运行的进程的进程号。netstat -lnp|grep 端口号然后用杀掉进程..._centos启动jar包不显示端口占用

MySql—视图、函数、存储过程、触发器_触发器 存储过程 函数 视图-程序员宅基地

文章浏览阅读3.9k次,点赞6次,收藏39次。MySql高级—视图、函数、存储过程、触发器目录 一、视图 11、视图的定义 1 2、视图的作用 1 (1)可以简化查询。 1 (2)可以进行权限控制, 3 3、查询视图 4 4、修改视图 4 5、删除视图 4_触发器 存储过程 函数 视图

随便推点

Java---简单易懂的KNN算法_jf.knn-%; 9 &-程序员宅基地

文章浏览阅读399次。一,简单介绍KNN算法---就是获取临近点,范围内,哪一种点最多(例如:红点:6,黑点:2,未知点肯定是红点),就是属于最多一方定义样本,拥有四个样本,已知A区两点分别(2,5)和(1,4),B区(8,1)和(9,2),求灰点(4,3)属于哪一区?代码定义实体类/** * 定义数据和数据类型 * @author peng * */ private s..._jf.knn-%; 9 &

最新版ffmpeg 提取视频关键帧_从视频中获取flag-程序员宅基地

文章浏览阅读8.9k次,点赞2次,收藏9次。对于ffmpeg的配置请看我的上篇博客:http://blog.csdn.net/kuaile123/article/details/11367309所用视频为 flv格式的,用的vs2010,电脑为64位,下面的也是64位,别下错了。因为ffmpeg的函数和版本有关系,这里记录下我所用的整合的版本,是昨天下的最新版的,需要请下载http://download.csdn.n_从视频中获取flag

【ARM Cache 系列文章 11 -- ARM Cache 直接映射 详细介绍】

在直接映射缓存中,每个内存地址通过某种映射函数(通常是地址的一部分)映射到一个特定的缓存行。这种结构简单,硬件实现成本较低,但可能会导致较高的缓存冲突(两个内存地址映射到同一缓存行),从而降低缓存效率。在介绍直接映射之前,以停车场停车作为例子,先把结构的特点简单地概括出来,便于读者了解。

Objective-C学习计划

持续学习,跟进Objective-C的最新发展和技术。了解Objective-C的基本语法和编程概念。掌握Objective-C的高级特性和常用框架。应用所学知识,完成实际项目。

【数据结构】最小生成树(Prim算法、Kruskal算法)解析+完整代码

设R为G的所有生成树的集合,若T为R中边的权值之和最小的生成树,则T称为G的最小生成树(MST)。每次选则一条权值最小的边,使这条边的两头连通(原本已经连通的不选),直到所有结点都连通。,生成树不同,每棵树的权(即树中所有边上的权值之和)也可能不同。1.最小生成树可能有多个,但边的权值之和总是唯一且最小的;每次将代价最小的新顶点纳入生成树,直到所有顶点都纳入为止。数组,找到最小值,将其加入树中,并继续遍历与其相连的边。数组,初始为false,判断结点是否加入树。最低的,且还没加入树的顶点。

python访问组策略_python 模块 wmi 远程连接 windows 获取配置信息-程序员宅基地

文章浏览阅读216次。python 模块 wmi 远程连接 windows 获取配置信息_python windows组策略