GeoJson轉ArcGIS的EsriJson

GIS開發者發表於2020-10-24

這次遇到了一個小問題,postgresql只能到處geojson(畢竟是一個標準格式),而客戶需求的是ArcGIS支援的EsriJson格式。需要在資料之間進行一個轉換。再網上查閱了一定資料,最後發現下面的程式碼比較可行。這裡分享一下:

主要程式碼

package com.cic.analysis.business.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cic.common.utils.StringUtils;

import java.math.BigDecimal;
import java.util.*;

public class EsriGeoJsonUtil {
//EsriJson轉geoJson
    public static String esri2geo(String ersiJson){
        Map geoMap = new HashMap();
        try {
            List geoFs = new ArrayList();
            geoMap.put("type", "FeatureCollection");
            Map esriMap = (Map) JSON.parse(ersiJson);
            Object esriFs = esriMap.get("features");
            if(esriFs instanceof List){
                esriFs = (List<Map<String, Object>>) esriFs;
                for(int i=0; i< ((List) esriFs).size(); i++){
                    Map esriF = (Map) ((List) esriFs).get(i);
                    Map geoF = new HashMap();
                    geoF.put("type", "Feature");
                    geoF.put("properties", esriF.get("attributes"));
                    Map<String, Object> geometry = (Map<String, Object>) esriF.get("geometry");
                    if(null != geometry.get("x")){
                        geoF.put("geometry", geoPoint(geometry));
                    }else if(null != geometry.get("points")){
                        geoF.put("geometry", geoPoints(geometry));
                    }else if(null != geometry.get("paths")){
                        geoF.put("geometry", geoLine(geometry));
                    }else if(null != geometry.get("rings")){
                        geoF.put("geometry", geoPoly(geometry));
                    }
                    geoFs.add(geoF);
                }
                geoMap.put("features", geoFs);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return new JSONObject(geoMap).toString();
    }
    //geoJosn轉EsriJson
    public static String geo2ersi(String geoJson, String idAttribute){
        Map esriMap = new HashMap();
        try {
            Map geoMap = (Map) JSON.parse(geoJson);
            esriMap = getEsriGeo(geoMap, idAttribute);
            Map spatialReference = new HashMap();
            spatialReference.put("wkid", 4326);
            esriMap.put("spatialReference",spatialReference);
        }catch (Exception e){
            e.printStackTrace();
        }
        return new JSONObject(esriMap).toString();
    }
   
    public static Map getEsriGeo(Map geoMap, String idAttribute){
        Map esriMap = new HashMap();
        idAttribute = StringUtils.isNotEmpty(idAttribute)? idAttribute:"OBJECTID";
        String type = geoMap.get("type").toString();
        switch (type){
            case "Point":
                List<BigDecimal> coords = (List<BigDecimal>) geoMap.get("coordinates");
                esriMap.put("x", coords.get(0));
                esriMap.put("y", coords.get(1));
                break;
            case "MultiPoint":
                esriMap.put("points",geoMap.get("coordinates"));
                break;
            case "LineString":
                List<Object> coordsList = new ArrayList<>();
                coordsList.add(geoMap.get("coordinates"));
                esriMap.put("paths",coordsList);
                break;
            case "MultiLineString":
                esriMap.put("paths",geoMap.get("coordinates"));
                break;
            case "Polygon":
                List<List<List<BigDecimal>>> coordinates = (List<List<List<BigDecimal>>>) geoMap.get("coordinates");
                List<List<List<BigDecimal>>> rings = orientRings(coordinates);
                esriMap.put("rings", rings);
                break;
            case "MultiPolygon":
                List<List<List<List<BigDecimal>>>> mcoordinates = (List<List<List<List<BigDecimal>>>>) geoMap.get("coordinates");
                List<List<List<BigDecimal>>> mrings = flattenMultiPolygonRings(mcoordinates);
                esriMap.put("rings", mrings);
                break;
            case "Feature":
                if (null != geoMap.get("geometry")) {
                    Map geometry = getEsriGeo((Map) geoMap.get("geometry"), idAttribute);
                    esriMap.put("geometry", geometry);
                }
                if(null != geoMap.get("properties")){
                    Map properties = (Map) geoMap.get("properties");
                    if (null != geoMap.get("id")) {
                        properties.put(idAttribute, geoMap.get("id"));
                    }
                    esriMap.put("attributes", properties);
                }
                break;
            case "FeatureCollection":
                List<Object> esriFs = new ArrayList<>();
                List<Map> features = (List<Map>) geoMap.get("features");
                for (int i = 0; i < features.size(); i++) {
                    esriFs.add(getEsriGeo(features.get(i), idAttribute));
                }
                esriMap.put("features", esriFs);
                esriMap.put("geometryType","esriGeometryPolygon");
                break;
            case "GeometryCollection":
                List<Object> esriFsc = new ArrayList<>();
                List<Map> geometries = (List<Map>) geoMap.get("geometries");
                for (int i = 0; i < geometries.size(); i++) {
                    esriFsc.add(getEsriGeo(geometries.get(i), idAttribute));
                }
                esriMap.put("geometries", esriFsc);
                esriMap.put("geometryType","esriGeometryPolygon");
                break;
        }
        return esriMap;
    }


    public static Map geoPoint(Map<String, Object> geometry){
        Map geo = new HashMap();
        geo.put("type", "point");
        BigDecimal x = (BigDecimal) geometry.get("x");
        BigDecimal y = (BigDecimal) geometry.get("y");
        List<BigDecimal> coords = new ArrayList<>();
        coords.add(x);
        coords.add(y);
        geo.put("coordinates", coords);
        return geo;
    }

    public static Map geoPoints(Map<String, Object> geometry){
        Map geo = new HashMap();
        List<Object> points = (List<Object>) geometry.get("points");
        if(points.size()==1){
            geo.put("type", "Point");
            geo.put("coordinates", points.get(0));
        }else{
            geo.put("type", "MultiPoint");
            geo.put("coordinates", points);
        }
        return geo;
    }

    public static Map geoLine(Map<String, Object> geometry){
        Map geo = new HashMap();
        List<Object> paths = (List<Object>) geometry.get("paths");
        if(paths.size()==1){
            geo.put("type", "LineString");
            geo.put("coordinates", paths.get(0));
        }else{
            geo.put("type", "MultiLineString");
            geo.put("coordinates", paths);
        }
        return geo;
    }

    public static Map geoPoly(Map<String, Object> geometry){
        Map geo = new HashMap();
        List<List<List<BigDecimal>>> rings = (List<List<List<BigDecimal>>>) geometry.get("rings");
        if(rings.size()==1){
            geo.put("type", "Polygon");
            geo.put("coordinates", rings);
        }else{
            List<List<List<List<BigDecimal>>>> coords = new ArrayList();
            String type = "";
            int len = coords.size() - 1;
            for(int i=0; i< rings.size(); i++){
                if(ringIsClockwise( rings.get(i))){
                    List<List<List<BigDecimal>>> item = new ArrayList<>();
                    item.add(rings.get(i));
                    coords.add(item);
                    len++;
                }else{
                    coords.get(len).add(rings.get(i));
                }
            }
            if(coords.size() == 1){
                type="Polygon";
            }else{
                type="MultiPolygon";
            }
            geo.put("type", type);
            geo.put("coordinates",coords.size()==1?coords.get(0): coords);
        }
        return geo;
    }

    public static boolean ringIsClockwise(List<List<BigDecimal>> rings){
        int total = 0;
        List<BigDecimal> pt1 = null;
        List<BigDecimal> pt2 = null;
        for(int i=0; i< rings.size()-1; i++){
            pt1 = rings.get(i);
            pt2 = rings.get(i+1);
            total += (pt2.get(0).doubleValue() - pt1.get(0).doubleValue())*  (pt2.get(1).doubleValue() + pt1.get(1).doubleValue());
        }
        return total>=0;
    }

    public static List<List<List<BigDecimal>>> orientRings ( List<List<List<BigDecimal>>> polygon) {
        List<List<List<BigDecimal>>> ringsList = new ArrayList<>();
        List<List<BigDecimal>> outerRing = closeRing(polygon.get(0));
        if (outerRing.size() >= 4) {
            if (!ringIsClockwise(outerRing)) {
                Collections.reverse(outerRing);
            }
            ringsList.add(outerRing);
            polygon.remove(0);
            for (int i = 0; i < polygon.size(); i++) {
                List<List<BigDecimal>> hole = closeRing(polygon.get(i));
                if (hole.size() >= 4) {
                    if (ringIsClockwise(hole)) {
                        Collections.reverse(hole);
                    }
                    ringsList.add(hole);
                }
            }
        }
        return ringsList;
    }

    public static List<List<BigDecimal>> closeRing (List<List<BigDecimal>> coords) {
        if (!pointsEqual(coords.get(0), coords.get(coords.size()-1))) {
            coords.add(coords.get(0));
        }
        return coords;
    }

    public static boolean pointsEqual (List<BigDecimal> a, List<BigDecimal> b) {
        for (int i = 0; i < a.size(); i++) {
            if (a.get(i).compareTo(b.get(i)) != 0) {
                return false;
            }
        }
        return true;
    }

    public static List<List<List<BigDecimal>>> flattenMultiPolygonRings (List<List<List<List<BigDecimal>>>> rings) {
        List<List<List<BigDecimal>>> polygonList = new ArrayList<>();
        for (int i = 0; i < rings.size(); i++) {
            List<List<List<BigDecimal>>> polygons = orientRings(rings.get(i));
            for (int x = polygons.size() - 1; x >= 0; x--) {
                List<List<BigDecimal>> polygon = polygons.get(x);
                polygonList.add(polygon);
            }
        }
        return polygonList;
    }

}

測試程式碼

package com.cic.analysis.business.utils;

import org.junit.Test;

import static org.junit.Assert.*;

public class EsriGeoJsonUtilTest {

    @Test
    public void esri2geo() {
        String geoJson="{\n" +
                "  \"type\": \"FeatureCollection\",\n" +
                "  \"features\": [\n" +
                "    {\n" +
                "      \"type\": \"Feature\",\n" +
                "      \"properties\": {\n" +
                "        \"color\":\"#dddddd\",\n" +
                "        \"id\":\"2222\"\n" +
                "      },\n" +
                "      \"geometry\": {\n" +
                "        \"type\": \"Polygon\",\n" +
                "        \"coordinates\": [\n" +
                "          [\n" +
                "            [\n" +
                "              -9.84375,\n" +
                "              55.57834467218206\n" +
                "            ],\n" +
                "            [\n" +
                "              -48.515625,\n" +
                "              7.013667927566642\n" +
                "            ],\n" +
                "            [\n" +
                "              67.1484375,\n" +
                "              -8.754794702435618\n" +
                "            ],\n" +
                "            [\n" +
                "              31.9921875,\n" +
                "              48.69096039092549\n" +
                "            ],\n" +
                "            [\n" +
                "              -9.84375,\n" +
                "              55.57834467218206\n" +
                "            ]\n" +
                "          ]\n" +
                "        ]\n" +
                "      }\n" +
                "    }\n" +
                "  ]\n" +
                "}";
        System.out.println(EsriGeoJsonUtil.geo2ersi(geoJson,""));

    }
}

輸出結果

{"features":[{"geometry":{"rings":[[[-9.84375,55.57834467218206],[31.9921875,48.69096039092549],[67.1484375,-8.754794702435618],[-48.515625,7.013667927566642],[-9.84375,55.57834467218206]]]},"attributes":{"color":"#dddddd","id":"2222"}}],"spatialReference":{"wkid":4326},"geometryType":"esriGeometryPolygon"}

 

相關文章