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大学的时候学过,之后就没写过了,这里基本上全是抄的,哈哈哈哈,抄得不好见谅!忘记抄的谁的了,就不注明了。