Java调用开源GDAL解析dxf成shp,再调用开源GeoTools解析shp文件

  • 需求

    最近项目要做国产化,有一个导入CAD的功能需要修改。要换成开源的或者国产的技术去解析CAD。DWG格式的,懂的都懂,开源的不可能解析,国产收费的那些CAD公司,个人认为也是买的AutoCAD的接口解析的。所以我们只能改成解析CAD的另一种文件格式:DXF文件。

  • 方案

    解析dxf用开源的GDAL,调用GDAL驱动把dxf转成shp文件,然后再用开源的GeoTools去解析shp文件。

    GDAL的依赖下载地址:https://www.gisinternals.com/release.php

    调用GDAL动态链接库:

      windows系统:

        (1)第一种简单粗暴的方式就是把gdal包bin目录下所有的dll文件和bin\gdal\java下的dll文件丢到你的JDK的bin目录下,对应的jar包也许在\bin\gdal\java目录下。

        (2)第二种是自己新建一个文件夹把需要的dll文件全放在一起,然后自己配环境变量(总之让系统能找到你的库就行了)。

      Linux和docker镜像:

         在Linux上,gdal官网上没有编译好的包,要自己去下gdal的源码包,然后自己编译,后面会生成.so文件和jar包,和windows一样可以配置环境变量或者把so文件丢到jdk的bin目录下。

         docker镜像,可以去dockerhub(https://hub.docker.com/r/osgeo/gdal/tags?page=1&ordering=last_updated)下载镜像,然后镜像里边会有相应的jar包和so文件(一般比较大的镜像才会有),可以直接拿里边的jar包和so文件来用。或者直接在镜像里部署应用也可以。docker镜像的jar包和so文件不知道在linux上能不能用,按道理应该可以吧,这个没试过。但是docker镜像上的好像有系统的区别?(还有好多疑问啊,后面遇到了再验证吧)。

      注意:jar包和so文件是一一对应的,就是镜像里的jar包和你自己编译生成的so文件不能配合使用,但是windows上调用dll动态链接库,用到的jar包却不讲究,不管是docker还是linux上的jar包都可以用(至少我在项目中测试是这样的,我也不知道为啥)

    GeoTools包下载地址(也可以用maven):https://sourceforge.net/projects/geotools/files/

  • 代码

  

DXF转SHP代码片段:

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.*;

import org.geotools.data.shapefile.ShapefileDataStore;
import org.opengis.feature.Property;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.geotools.data.FeatureSource;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;

import org.gdal.gdal.gdal;
import org.gdal.ogr.DataSource;
import org.gdal.ogr.Driver;
import org.gdal.ogr.Layer;
import org.gdal.ogr.ogr;

public String getDxfData() throws Exception{
            
            //dxf文件路径
            String filePath ="C:\\WorkSpace\\rect_field_demo.dxf";
            // 注册所有的驱动
            ogr.RegisterAll();
            gdal.SetConfigOption("DXF_ENCODING","UTF-8");
            gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8","YES");//支持中文路径
            gdal.SetConfigOption("SHAPE_ENCODING","CP936");//属性表字段支持中文
            DataSource ds = ogr.Open(filePath,1);
            if (ds == null)
            {
                System.out.println("打开文件失败!" );
                return null;
            }
            System.out.println("打开文件成功!" );
            Layer oLayer = ds.GetLayerByIndex(0);
            if(oLayer == null){
                System.out.println("获取失败");
                return null;
            }
            oLayer.ResetReading();
            Driver dv = ogr.GetDriverByName("ESRI Shapefile"); //调用驱动转shp
            String extfile = "C:\\WorkSpace\\rect_field_demo.shp";
            DataSource dataSource = dv.CopyDataSource(ds, extfile);//创建shp文件并写入内容
            dataSource.delete();    //释放与数据源对象关联的本机资源并关闭文件(这句非常重要,如果没有关闭文件,那么下面的解析shp就解析不了)
            String geometry = getShpData("C:\\WorkSpace\\rect_field_demo.shp",coordInfo);

            return geometry;

        }
解析shp文件public static String getShpData(String filePath) throws Exception {
        File file = new File(filePath);
        long fileSize = file.length();
        List<Map<String,Object>> list = new ArrayList<Map<String, Object>>();
        ShapefileDataStore shpDataStore = new ShapefileDataStore(file.toURL());
        shpDataStore.setStringCharset(Charset.forName("GBK"));
        String typeName = shpDataStore.getTypeNames()[0];
        FeatureSource<SimpleFeatureType, SimpleFeature> featureSource = null;
        featureSource = (FeatureSource<SimpleFeatureType, SimpleFeature>)shpDataStore.getFeatureSource(typeName);//这里我看了很多人的博客都没有指定类(FeatureSource<SimpleFeatureType, SimpleFeature>),难道不会报错吗,反正我的会
        FeatureCollection<SimpleFeatureType, SimpleFeature> result = featureSource.getFeatures();

        FeatureIterator<SimpleFeature> itertor = result.features();
        while (itertor.hasNext())
        {
            Map<String,Object> data  = new HashMap<String, Object>();
            SimpleFeature feature = itertor.next();
            Collection<Property> p = feature.getProperties();
            Iterator<Property> it = p.iterator();
            while(it.hasNext()) {
                Property pro = it.next();
                String field = pro.getName().toString();
                String value = pro.getValue().toString();
                field = field.equals("the_geom")?"wkt":field;
                data.put(field, value);
            }
            list.add(data);
        }
        JSONArray jsonarray = JSONArray.fromObject(list);
        return jsonarray.toString();
    }

ps:Java大学的时候学过,之后就没写过了,这里基本上全是抄的,哈哈哈哈,抄得不好见谅!忘记抄的谁的了,就不注明了。