当前位置: 首页 > 工具软件 > WKT > 使用案例 >

GeoTools:WKT、GeoJson、Feature、FeatureCollection相互转换

萧宏峻
2023-12-01

测试用例:

package top.reid.smart.geo;

import cn.hutool.json.JSONUtil;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class GeoToolsTest {

    String geoJsonStr = "{\n" +
            "            \"type\":\"Point\",\n" +
            "            \"coordinates\":[105.380859375,31.57853542647338]\n" +
            "            }";

    String geoJsonStr2 = "{\"type\":\"Feature\",\n" +
            "        \"properties\":{},\n" +
            "        \"geometry\":{\n" +
            "            \"type\":\"Point\",\n" +
            "            \"coordinates\":[105.380859375,31.57853542647338]\n" +
            "            }\n" +
            "        }";

    String geoJsonStr3 = "{\n" +
            "  \"type\": \"FeatureCollection\",\n" +
            "  \"features\": [\n" +
            "        {\"type\":\"Feature\",\n" +
            "        \"properties\":{},\n" +
            "        \"geometry\":{\n" +
            "            \"type\":\"Point\",\n" +
            "            \"coordinates\":[105.380859375,31.57853542647338]\n" +
            "            }\n" +
            "        },\n" +
            "\t\t{\"type\":\"Feature\",\n" +
            "        \"properties\":{},\n" +
            "        \"geometry\":{\n" +
            "            \"type\":\"Point\",\n" +
            "            \"coordinates\":[105.380859375,31.57853542647338]\n" +
            "            }\n" +
            "        }\n" +
            "    ]\n" +
            "}";

    String[] wktStr = new String[]{"POINT(6 10)", "LINESTRING(3 4,10 50,20 25)", "POLYGON((1 1,5 1,5 5,1 5,1 1),(2 2,2 3,3 3,3 2,2 2))",
            "MULTIPOINT(3.5 5.6, 4.8 10.5)", "MULTILINESTRING((3 4,10 50,20 25),(-5 -8,-10 -8,-15 -4))", "MULTIPOLYGON(((1 1,5 1,5 5,1 5,1 1),(2 2,2 3,3 3,3 2,2 2)),((6 3,9 2,9 4,6 3)))",
            "GEOMETRYCOLLECTION(POINT(4 6),LINESTRING(4 6,7 10))", "POINT ZM (1 1 5 60)", "POINT M (1 1 80)"};

    @Test
    void getGeometryType() {
        for (String s : wktStr) {
            System.out.println("Geo 几何类型:" + GeoTools.getGeometryType(s));
        }
    }

    @Test
    void isWkt() {
        for (String s : wktStr) {
            System.out.println("是规范的 WKT:" + GeoTools.isWkt(s));
        }
    }

    @Test
    void isNotWkt() {
        for (String s : wktStr) {
            System.out.println("不是规范的 WKT:" + GeoTools.isNotWkt(geoJsonStr2));
        }
    }

    @Test
    void isGeoJson() {
        System.out.println("是规范的 GeoJson:" + GeoTools.isGeoJson(geoJsonStr3));
    }

    @Test
    void isNotGeoJson() {
        System.out.println("不是规范的 GeoJson:" + GeoTools.isNotGeoJson(geoJsonStr3));
    }

    @Test
    void geoJsonToWkt() {
        System.out.println("GeoJson 转 WKT:" + GeoTools.geoJsonToWkt(JSONUtil.parseObj(geoJsonStr)));
        System.out.println("GeoJson 转 WKT:" + GeoTools.geoJsonToWkt(JSONUtil.parseObj(geoJsonStr2)));
        System.out.println("GeoJson 转 WKT:" + GeoTools.geoJsonToWkt(JSONUtil.parseObj(geoJsonStr3)));
    }

    @Test
    void wktToGeoJson() {
        for (String s : wktStr) {
            System.out.println("WKT 转 GeoJson:" + GeoTools.wktToGeoJson(s));
        }
    }

    @Test
    void wktToFeature() {
        for (String s : wktStr) {
            System.out.println("WKT 转 Feature:" + GeoTools.wktToFeature(s));
        }
    }

    @Test
    void wktToFeatureCollection() {
        for (String s : wktStr) {
            System.out.println("WKT 转 FeatureCollection:" + GeoTools.wktToFeatureCollection(s));
        }
    }
}

小工具:

package top.reid.smart.geo;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import org.geotools.data.DataUtilities;
import org.geotools.data.collection.ListFeatureCollection;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.geojson.GeoJSONUtil;
import org.geotools.geojson.feature.FeatureJSON;
import org.geotools.geojson.geom.GeometryJSON;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryCollection;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.io.WKTReader;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;

import java.io.IOException;
import java.io.Reader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 地质工具
 * </p>
 *
 * @Author REID
 * @Blog https://blog.csdn.net/qq_39035773
 * @GitHub https://github.com/BeginnerA
 * @Data 2020/11/11
 * @Version V1.0
 **/
public class GeoTools {

    private static final WKTReader READER = new WKTReader();

    /**
     * 要素集合根节点
     */
    private static final String[] COLLECTION_TYPE = new String[]{"FeatureCollection"};

    /**
     * 地理要素类型
     */
    private static final String[] FEATURES_TYPE = new String[]{"Feature"};

    /**
     * 地理数据类型
     * 点、线、面、几何集合
     */
    private static final String[] GEO_TYPE = new String[]{"Geometry", "Point", "LineString", "Polygon", "MultiPoint", "MultiLineString", "MultiPolygon", "GeometryCollection"};

    /**
     * 获取 Geo 几何类型
     * @param wktStr WKT 字符串
     * @return Geo 几何类型
     */
    public static String getGeometryType(String wktStr) {
        String type = null;
        if (StrUtil.isNotEmpty(wktStr)) {
            try {
                Geometry read = READER.read(wktStr);
                type = read.getGeometryType();
            }catch (Exception e) {
                System.out.println("非规范 WKT 字符串:"+ e);
                e.printStackTrace();
            }
        }
        return type;
    }

    /**
     * 是规范的 WKT
     * @param wktStr WKT 字符串
     * @return 是、否
     */
    public static boolean isWkt(String wktStr) {
        for (String s : GEO_TYPE) {
            if (wktStr.toLowerCase().startsWith(s.toLowerCase())) {
                return true;
            }
        }
        return false;
    }

    /**
     * 不是规范的 WKT
     * @param wktStr WKT 字符串
     * @return 是、否
     */
    public static boolean isNotWkt(String wktStr) {
        return !isWkt(wktStr);
    }

    /**
     * 是规范的 GeoJson
     * @param geoJsonStr GeoJson 字符串
     * @return 是、否
     */
    public static boolean isGeoJson(String geoJsonStr) {
        try {
            JSONObject jsonObject = JSONUtil.parseObj(geoJsonStr);
            return isGeoJson(jsonObject);
        }catch (Exception e) {
            return false;
        }
    }

    /**
     * 不是规范的 GeoJson
     * @param geoJsonStr GeoJson 字符串
     * @return 是、否
     */
    public static boolean isNotGeoJson(String geoJsonStr) {
        return !isGeoJson(geoJsonStr);
    }

    /**
     * 是规范的 GeoJson
     * @param geoJson GeoJson 对象
     * @return 是、否
     */
    public static boolean isGeoJson(JSONObject geoJson) {
        String type = geoJson.getStr("type");
        boolean mark = false;
        // 判断根节点
        if (ArrayUtil.containsIgnoreCase(COLLECTION_TYPE, type)) {
            JSONArray jsonArray = geoJson.get("features", JSONArray.class);
            for (Object jsonStr : jsonArray) {
                JSONObject jsonObject = JSONUtil.parseObj(jsonStr);
                type = jsonObject.getStr("type");
                // 判断地理要素
                if (ArrayUtil.containsIgnoreCase(FEATURES_TYPE, type)) {
                    type = jsonObject.get("geometry", JSONObject.class).getStr("type");
                    // 判断几何要素
                    mark = ArrayUtil.containsIgnoreCase(GEO_TYPE, type);
                }
                if (!mark) {
                    return false;
                }
            }
        }else {
            // 判断地理要素
            if (ArrayUtil.containsIgnoreCase(FEATURES_TYPE, type)) {
                type = geoJson.get("geometry", JSONObject.class).getStr("type");
            }
            // 数据是几何数据
            mark = ArrayUtil.containsIgnoreCase(GEO_TYPE, type);
        }
        return mark;
    }

    /**
     * 不是规范的 GeoJson
     * @param geoJson GeoJson 对象
     * @return 是、否
     */
    public static boolean isNotGeoJson(JSONObject geoJson) {
        return !isGeoJson(geoJson);
    }

    /**
     * GeoJson 转 WKT
     * @param geoJson GeoJson 对象
     * @return WKT 字符串
     */
    public static String geoJsonToWkt(JSONObject geoJson) {
        String wkt = null;
        GeometryJSON gJson = new GeometryJSON();
        try {
            if(isGeoJson(geoJson)){
                String type = geoJson.getStr("type");
                // 判断是否根节点
                if (ArrayUtil.containsIgnoreCase(COLLECTION_TYPE, type)) {
                    JSONArray geometriesArray = geoJson.get("features", JSONArray.class);
                    // 定义一个数组装图形对象
                    int size = geometriesArray.size();
                    Geometry[] geometries = new Geometry[size];
                    for (int i = 0; i < size; i++){
                        String str = JSONUtil.parseObj(geometriesArray.get(i)).getStr("geometry");
                        // 使用 GeoUtil 去读取 str
                        Reader reader = GeoJSONUtil.toReader(str);
                        Geometry geometry = gJson.read(reader);
                        geometries[i] = geometry;
                    }
                    GeometryCollection geometryCollection = new GeometryCollection(geometries, new GeometryFactory());
                    wkt = geometryCollection.toText();
                }else {
                    String geoStr = geoJson.toString();
                    // 判断是否地理要素节点
                    if (ArrayUtil.containsIgnoreCase(FEATURES_TYPE, type)) {
                        geoStr = geoJson.getStr("geometry");
                    }
                    Reader reader = GeoJSONUtil.toReader(geoStr);
                    Geometry read = gJson.read(reader);
                    wkt = read.toText();
                }
            }
        } catch (IOException e){
            System.out.println("GeoJson 转 WKT 出现异常:"+ e);
            e.printStackTrace();
        }
        return wkt;
    }

    /**
     * WKT 转 GeoJson
     * @param wktStr WKT 字符串
     * @return GeoJson 对象
     */
    public static JSONObject wktToGeoJson(String wktStr) {
        JSONObject jsonObject = new JSONObject();
        try {
            Geometry geometry = READER.read(wktStr);
            StringWriter writer = new StringWriter();
            GeometryJSON geometryJson = new GeometryJSON();
            geometryJson.write(geometry, writer);
            jsonObject = JSONUtil.parseObj(writer.toString());
        } catch (Exception e) {
            System.out.println("WKT 转 GeoJson 出现异常:"+ e);
            e.printStackTrace();
        }
        return jsonObject;
    }

    /**
     * WKT 转 Feature
     * @param wktStr WKT 字符串
     * @return Feature JSON 对象
     */
    public static JSONObject wktToFeature(String wktStr) {
        JSONObject jsonObject = new JSONObject();
        try {
            SimpleFeatureType type = DataUtilities.createType("Link", "geometry:"+getGeometryType(wktStr));
            SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(type);
            // 按照TYPE中声明的顺序为属性赋值就可以,其他方法我暂未尝试
            featureBuilder.add(READER.read(wktStr));
            SimpleFeature feature = featureBuilder.buildFeature(null);
            StringWriter writer = new StringWriter();
            FeatureJSON fJson = new FeatureJSON();
            fJson.writeFeature(feature, writer);
            jsonObject = JSONUtil.parseObj(writer.toString());
        }catch (Exception e) {
            System.out.println("WKT 转 Feature 出现异常:"+ e);
            e.printStackTrace();
        }
        return jsonObject;
    }

    /**
     * WKT 转 FeatureCollection
     * @param wktStr  WKT 字符串
     * @return FeatureCollection JSON 对象
     */
    public static JSONObject wktToFeatureCollection(String wktStr) {
        JSONObject jsonObject = new JSONObject();
        try {
            String geometryType = getGeometryType(wktStr);
            if (StrUtil.isNotEmpty(geometryType)) {
                SimpleFeatureType type = DataUtilities.createType("Link", "geometry:" + geometryType);
                SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(type);
                List<SimpleFeature> features = new ArrayList<>();
                SimpleFeatureCollection collection = new ListFeatureCollection(type, features);
                featureBuilder.add(READER.read(wktStr));
                SimpleFeature feature = featureBuilder.buildFeature(null);
                features.add(feature);
                StringWriter writer = new StringWriter();
                FeatureJSON fJson = new FeatureJSON();
                fJson.writeFeatureCollection(collection, writer);
                jsonObject = JSONUtil.parseObj(writer.toString());
            }
        }catch (Exception e) {
            System.out.println("WKT 转 FeatureCollection 出现异常:"+ e);
            e.printStackTrace();
        }
        return jsonObject;
    }
}

​​​​​​​

 类似资料: