File conversion-cad to geojson

foreword

Based on the previous article GeoServer series - publishing geojson data through mongodb , common geographical files can be unified into geojson and saved to mongodb in business, which is convenient for unified maintenance and release of geoserver. This article will give an example of converting cad format to geojson.

1, the necessary dependencies

  • Gdal is used for file conversion and parsing. You need to download and configure environment variables first (I use 3.3). After installation, you can use the following command to view the version

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

  • pom import

    <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, conversion entrance

    /**
     * dwg转geojson
     *
     * @param fileName gdb文件名  xxx.dwg
     * @param fileMd5  文件md5值   1232131
     * @return
     */
    @Override
    public 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.dxf
        String outFile = dwgpath.replace(".dwg", ".dxf");
        String res = dwg2dxf(dwgpath, outFile);
        if (res != null) {
            return res;
        }
        //2,dxf转换成json  D:\TS\temp\cadtest\cadtest.geojson
        String jsonPath = outFile.replace(".dxf", "转换前.geojson");
        res = dxfToJson(outFile, jsonPath);
        if (res != null) {
            return res;
        }
        //3,坐标转换  D:\TS\temp\cadtest\cadtest转换.geojson
        long 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 to 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, dxf to geojson

    /**
     * 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");

        //读取文件转化为DataSource
        DataSource ds = ogr.Open(dxfPath, 0);
        if (ds == null) {
            return "打开文件失败," + dxfPath;
        }
        //获取geojso
        Driver geojsonDriver = ogr.GetDriverByName("GeoJSON");
        DataSource geojsonDataSource = geojsonDriver.CopyDataSource(ds, geoJsonPath);
        geojsonDataSource.delete();
        ds.delete();
        return null;
    }

5. Coordinate transformation (here comes the key point)

Because the cad file does not have a coordinate system, a coordinate system needs to be preset to convert the coordinates in the geojson in the previous step

    /**
     * 坐标转换
     *
     * @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中的layer
        Layer oLayer = ds2.GetLayerByIndex(0);
        if (oLayer == null) {
            log.error("从dwg的geojson中获取layer 获取失败:{}", geoJsonPath);
            ds2.delete();
            return "从dwg的geojson中获取layer 获取失败";
        }

        //新创建一个图层geojson
        Driver 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, an unpretentious line-by-line coordinate transformation

Read the Feature of geojson line by line and traverse each coordinate

    /**
     * 转换每个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;
    }

Correction of latitude and longitude reversal

    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);
        }
    }

Hard dishes (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.html
        double L0 = 105;
        Y -= 500000;
        double[] result = new double[2];
        double iPI = 0.0174532925199433;//pi/180
        double a = 6378137.0; //长半轴 m
        double b = 6356752.31414; //短半轴 m
        //扁率 a-b/a
        double 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);
    }

Guess you like

Origin blog.csdn.net/u012796085/article/details/129840633