- 需求
最近項目要做國產化,有一個導入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大學的時候學過,之后就沒寫過了,這里基本上全是抄的,哈哈哈哈,抄得不好見諒!忘記抄的誰的了,就不注明了。