> 文章列表 > 文件转换-cad转geojson

文件转换-cad转geojson

文件转换-cad转geojson

前言

基于前一篇文章GeoServer系列-通过mongodb发布geojson数据,业务上可将常见的地理文件统一为geojson保存到mongodb,方便统一维护和发布geoserver,这一篇将举例cad格式转geojson。

1,必要的依赖

  • 文件转换和解析用到了gdal,需要先下载并配置环境变量(我用的3.3),安装后可使用以下命令查看版本

    C:\\Users\\CDLX>gdalinfo.exe --version
    GDAL 3.3.0, released 2021/04/26

  • pom引入

    <dependencies><dependency><groupId>org.gdal</groupId><artifactId>gdal</artifactId><version>3.2.0</version></dependency>
    </dependencies>
    <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.7</version>
    </dependency>
    

2,转换入口

    /*** dwg转geojson** @param fileName gdb文件名  xxx.dwg* @param fileMd5  文件md5值   1232131* @return*/@Overridepublic String dwgToJson(String fileName,String userId, String fileMd5) {String wsDirPath = fileDirectory + "/" + fileMd5 + userId;//文件名String dwgname = fileName.substring(0, fileName.lastIndexOf("."));String dwgpath = wsDirPath + "/" + fileName;//1,dwg转dxf D:\\TS\\temp\\cadtest\\cadtest.dxfString outFile = dwgpath.replace(".dwg", ".dxf");String res = dwg2dxf(dwgpath, outFile);if (res != null) {return res;}//2,dxf转换成json  D:\\TS\\temp\\cadtest\\cadtest.geojsonString jsonPath = outFile.replace(".dxf", "转换前.geojson");res = dxfToJson(outFile, jsonPath);if (res != null) {return res;}//3,坐标转换  D:\\TS\\temp\\cadtest\\cadtest转换.geojsonlong begin = System.currentTimeMillis();String newJsonPath = jsonPath.replace("转换前.geojson", "") + ".geojson";res = geoJsonCov(jsonPath, newJsonPath, dwgname);if (res != null) {return res;}long end = System.currentTimeMillis();log.info("dwg坐标转换耗时:{}", (end - begin));return null;}

3,dwg转dxf

    public String dwg2dxf(String dwgPath, String outFile) {File dwgFile = new File(dwgPath);if (dwgFile.exists()) {if (!dwgFile.getName().endsWith(".dwg")) {return "文件格式错误";}LoadOptions loadOptions = new LoadOptions();loadOptions.setSpecifiedEncoding(CodePages.SimpChinese);CadImage cadImage = (CadImage) Image.load(dwgFile.getAbsolutePath(), loadOptions);cadImage.save(outFile);cadImage.close();return null;} else {return "dwg文件不存在," + dwgPath;}}

4,dwg转dxf

    /*** dxf转json** @param dxfPath     D:\\TS\\sharding\\filemd5\\cadtest.dxf* @param geoJsonPath D:\\TS\\sharding\\filemd5\\cadtest.geojson*/public String dxfToJson(String dxfPath, String geoJsonPath) {ogr.RegisterAll();//支持中文路径gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");gdal.SetConfigOption("DXF_ENCODING", "UTF-8");//读取文件转化为DataSourceDataSource ds = ogr.Open(dxfPath, 0);if (ds == null) {return "打开文件失败," + dxfPath;}//获取geojsoDriver geojsonDriver = ogr.GetDriverByName("GeoJSON");DataSource geojsonDataSource = geojsonDriver.CopyDataSource(ds, geoJsonPath);geojsonDataSource.delete();ds.delete();return null;}

5,坐标转换(重点来了)

因为cad文件没有坐标系,需要预设一个坐标系,将上一步中geojson中的坐标进行转换

    /*** 坐标转换** @param geoJsonPath D:\\\\ITS\\\\Sharding\\filemd5\\xx.geojson* @param outputJson  D:\\\\ITS\\\\Sharding\\filemd5\\xx转换.geojson* @param dwgName     图层名称*/public String geoJsonCov(String geoJsonPath, String outputJson, String dwgName) {ogr.RegisterAll();gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");//支持中文路径gdal.SetConfigOption("DXF_ENCODING", "UTF-8");DataSource ds2 = ogr.Open(geoJsonPath, 0);System.out.println("----------坐标转换开始-----------");//读取第一个图层,这个图层不是cad中的layerLayer oLayer = ds2.GetLayerByIndex(0);if (oLayer == null) {log.error("从dwg的geojson中获取layer 获取失败:{}", geoJsonPath);ds2.delete();return "从dwg的geojson中获取layer 获取失败";}//新创建一个图层geojsonDriver geojsonDriver = ogr.GetDriverByName("GeoJSON");SpatialReference epsg2000 = new SpatialReference("");epsg2000.ImportFromEPSG(4490);DataSource dataSource = geojsonDriver.CreateDataSource(outputJson, null);Layer geojsonLayer = dataSource.CreateLayer(dwgName, epsg2000, ogrConstants.wkbUnknown, null);Feature feature;String geometryStr;String newGeometryStr;while ((feature = oLayer.GetNextFeature()) != null) {//获取空间属性Geometry geometry = feature.GetGeometryRef();// 解决自相交问题//geometry = geometry.Buffer(0.0);//System.out.println(geometry.ExportToJson());geometryStr = geometry.GetCurveGeometry().ExportToJson();if (geometryStr == null) {continue;}newGeometryStr = String.valueOf(paseCoordinates(geometryStr));Geometry newGeometry = Geometry.CreateFromJson(newGeometryStr);//传给新建的矢量图层Feature dstFeature = feature.Clone();dstFeature.SetGeometry(newGeometry);geojsonLayer.CreateFeature(dstFeature);}geojsonDriver.delete();ds2.delete();dataSource.delete();return null;}

6,一个朴实无华的逐行坐标转换

逐行读取geojson的Feature,遍历每个坐标

    /*** 转换每个Feature的坐标* @param coordinatesStr Feature原始json字符串* @return*/public StringBuffer paseCoordinates(String coordinatesStr) {//String a = "{ \\"type\\": \\"Feature\\", \\"id\\": 0, \\"properties\\": { \\"Layer\\": \\"SXSS\\", \\"SubClasses\\": \\"AcDbEntity:AcDbBlockReference\\", \\"Linetype\\": \\"Continuous\\", \\"EntityHandle\\": \\"4F2\\" }, \\"geometry\\": { \\"type\\": \\"MultiLineString\\", \\"coordinates\\": [ [ [ 406567.373450083076023, 3058272.568403942044824 ], [ 406565.039480640378315, 3058269.633257158566266 ] ], [ [ 406565.039480640378315, 3058269.633257158566266 ], [ 406565.597624949878082, 3058269.85315527068451 ] ], [ [ 406565.039480640378315, 3058269.633257158566266 ], [ 406565.128001464472618, 3058270.226590381469578 ] ] ] } }";int offset = coordinatesStr.indexOf("coordinates\\":") + 13;String b = coordinatesStr.substring(offset);//System.out.println(b);String[] c = b.split("\\\\],");StringBuffer stringBuffer = new StringBuffer();int n = c.length;for (String d : c) {//System.out.println(d);int begin = d.lastIndexOf("[");int end = d.indexOf("]");String oldZb = d.substring(begin < 0 ? 0 : begin + 1, end < 0 ? d.length() - 1 : end - 1);//System.out.println(oldZb);String newZb = CadUtil.covStr(oldZb);//System.out.println(newZb);if (begin > 0) {stringBuffer.append(d, 0, begin + 1).append(newZb);}if (n != 1) {stringBuffer.append("]");}if (end > 0) {stringBuffer.append(d.substring(end - 1));}if (n > 1) {stringBuffer.append(",");}n--;}stringBuffer.insert(0, coordinatesStr.substring(0, offset));return stringBuffer;}

纠正经纬度颠倒问题

    public static String covStr(String zb) {String[] poi = zb.trim().split(",");double x = Double.parseDouble(poi[0]);double y = Double.parseDouble(poi[1]);//坐标经纬度交换if (x > y) {return dxfToSwapxy(x, y);} else {return dxfToSwapxy(y, x);}}

硬菜(x_x)

    /*** 坐标转换** @param X* @param Y* @return*/public static String dxfToSwapxy(double X, double Y) {double lat, lon;//中央子午线,结合这个网址进行查找,目前用的EPSG:4532中的123D。https://wenku.baidu.com/view/e219e246e3bd960590c69ec3d5bbfd0a7856d530.htmldouble L0 = 105;Y -= 500000;double[] result = new double[2];double iPI = 0.0174532925199433;//pi/180double a = 6378137.0; //长半轴 mdouble b = 6356752.31414; //短半轴 m//扁率 a-b/adouble e = 0.0818191910428; //第一偏心率 Math.sqrt(5)double ee = Math.sqrt(a * a - b * b) / b; //第二偏心率double bf = 0; //底点纬度double a0 = 1 + (3 * e * e / 4) + (45 * e * e * e * e / 64) + (175 * e * e * e * e * e * e / 256) + (11025 * e * e * e * e * e * e * e * e / 16384) + (43659 * e * e * e * e * e * e * e * e * e * e / 65536);double b0 = X / (a * (1 - e * e) * a0);double c1 = 3 * e * e / 8 + 3 * e * e * e * e / 16 + 213 * e * e * e * e * e * e / 2048 + 255 * e * e * e * e * e * e * e * e / 4096;double c2 = 21 * e * e * e * e / 256 + 21 * e * e * e * e * e * e / 256 + 533 * e * e * e * e * e * e * e * e / 8192;double c3 = 151 * e * e * e * e * e * e * e * e / 6144 + 151 * e * e * e * e * e * e * e * e / 4096;double c4 = 1097 * e * e * e * e * e * e * e * e / 131072;bf = b0 + c1 * Math.sin(2 * b0) + c2 * Math.sin(4 * b0) + c3 * Math.sin(6 * b0) + c4 * Math.sin(8 * b0); // bf =b0+c1*sin2b0 + c2*sin4b0 + c3*sin6b0 +c4*sin8b0 +...double tf = Math.tan(bf);double n2 = ee * ee * Math.cos(bf) * Math.cos(bf); //第二偏心率平方成bf余弦平方double c = a * a / b;double v = Math.sqrt(1 + ee * ee * Math.cos(bf) * Math.cos(bf));double mf = c / (v * v * v); //子午圈半径double nf = c / v;//卯酉圈半径//纬度计算lat = bf - (tf / (2 * mf) * Y) * (Y / nf) * (1 - 1 / 12 * (5 + 3 * tf * tf + n2 - 9 * n2 * tf * tf) * (Y * Y / (nf * nf)) + 1 / 360 * (61 + 90 * tf * tf + 45 * tf * tf * tf * tf) * (Y * Y * Y * Y / (nf * nf * nf * nf)));//经度偏差lon = 1 / (nf * Math.cos(bf)) * Y - (1 / (6 * nf * nf * nf * Math.cos(bf))) * (1 + 2 * tf * tf + n2) * Y * Y * Y + (1 / (120 * nf * nf * nf * nf * nf * Math.cos(bf))) * (5 + 28 * tf * tf + 24 * tf * tf * tf * tf) * Y * Y * Y * Y * Y;result[0] = retain6(lat / iPI);result[1] = retain6(L0 + lon / iPI);return result[1] + "," + result[0];}public static double retain6(double num) {String result = String.format("%.10f", num);//小数点后面保留10位小数return Double.valueOf(result);}