Skip to content

Instantly share code, notes, and snippets.

@JerrySievert
Created May 31, 2013 16:06
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JerrySievert/5686037 to your computer and use it in GitHub Desktop.
Save JerrySievert/5686037 to your computer and use it in GitHub Desktop.
esri json to geojson
work=# select esriToGeoJSON('{"rings":[[[100,0],[101,0],[101,1],[100,1],[100,0]]],"spatialReference":{"wkid":4326}}');
esritogeojson
------------------------------------------------------------------------------
{"type":"Polygon","coordinates":[[[100,0],[101,0],[101,1],[100,1],[100,0]]]}
@JerrySievert
Copy link
Author

CREATE OR REPLACE FUNCTION esriToGeoJSON(input varchar) RETURNS
VARCHAR AS $$

  var arcgis,
      EarthRadius = 6378137,
      DegreesPerRadian = 57.295779513082320,
      RadiansPerDegree =  0.017453292519943,
      MercatorCRS = {
        "type": "link",
        "properties": {
          "href": "http://spatialreference.org/ref/sr-org/6928/ogcwkt/",
          "type": "ogcwkt"
        }
      },
      GeographicCRS = {
        "type": "link",
        "properties": {
          "href": "http://spatialreference.org/ref/epsg/4326/ogcwkt/",
          "type": "ogcwkt"
        }
      };


  try {
    arcgis = JSON.parse(input);
  } catch (err) {
    throw new Error("Unable to parse Esri JSON: " + err.toString());
    return null;
  }

  function findGeometryType(input){
    if(input.x && input.y){
      return "Point";
    }
    if(input.points){
      return "MultiPoint";
    }
    if(input.paths) {
      return (input.paths.length === 1) ? "LineString" : "MultiLineString";
    }
    if(input.rings) {
      return (input.rings.length === 1) ? "Polygon" : "MultiPolygon";
    }
    if(input.attributes && input.geometry) {
      return "Feature";
    }
    throw new Error("Terraformer: invalid ArcGIS input. Are you sure your data is properly formatted?");
    return null;
  }


  function radToDeg(rad) {
    return rad * DegreesPerRadian;
  }

  function degToRad(deg) {
    return deg * RadiansPerDegree;
  }

  function eachPosition(coordinates, func) {
    for (var i = 0; i < coordinates.length; i++) {
      // we found a number so lets convert this pair
      if(typeof coordinates[i][0] === "number"){
        coordinates[i] = func(coordinates[i]);
      }
      // we found an coordinates array it again and run THIS function against it
      if(typeof coordinates[i] === "object"){
        coordinates[i] = eachPosition(coordinates[i], func);
      }
    }
    return coordinates;
  }


  function positionToGeographic(position) {
    var x = position[0];
    var y = position[1];
    return [radToDeg(x / EarthRadius) - (Math.floor((radToDeg(x / EarthRadius) + 180) / 360) * 360), radToDeg((Math.PI / 2) - (2 * Math.atan(Math.exp(-1.0 * y / EarthRadius))))];
  }

  function positionToMercator(position) {
    var lng = position[0];
    var lat = Math.max(Math.min(position[1], 89.99999), -89.99999);
    return [degToRad(lng) * EarthRadius, EarthRadius/2.0 * Math.log( (1.0 + Math.sin(degToRad(lat))) / (1.0 - Math.sin(degToRad(lat))) )];
  }

  function applyConverter(geojson, converter, noCrs){
    if(geojson.type === "Point") {
      geojson.coordinates = converter(geojson.coordinates);
    } else if(geojson.type === "Feature") {
      geojson.geometry = applyConverter(geojson.geometry, converter, true);
    } else if(geojson.type === "FeatureCollection") {
      for (var f = 0; f < geojson.features.length; f++) {
        geojson.features[f] = applyConverter(geojson.features[f], converter, true);
      }
    } else if(geojson.type === "GeometryCollection") {
      for (var g = 0; g < geojson.geometries.length; g++) {
        geojson.geometries[g] = applyConverter(geojson.geometries[g], converter, true);
      }
    } else {
      geojson.coordinates = eachPosition(geojson.coordinates, converter);
    }

    if(!noCrs){
      if(converter === positionToMercator){
        geojson.crs = MercatorCRS;
      }
    }

    if(converter === positionToGeographic){
      delete geojson.crs;
    }

    return geojson;
  }

  // us
  var parse = plv8.find_function("esriToGeoJSON");

  var type = findGeometryType(arcgis);
  var inputSpatialReference = (arcgis.geometry) ? arcgis.geometry.spatialReference : arcgis.spatialReference;
  var geojson = {
    type: type
  };

  if(type === "Feature") {
    geojson.properties = arcgis.attributes;
  }

  switch(type){
  case "Point":
    geojson.coordinates = [arcgis.x, arcgis.y];
    break;
  case "MultiPoint":
    geojson.coordinates = arcgis.points;
    break;
  case "LineString":
    geojson.coordinates = arcgis.paths[0];
    break;
  case "MultiLineString":
    geojson.coordinates = arcgis.paths;
    break;
  case "Polygon":
    geojson.coordinates = arcgis.rings;
    break;
  case "MultiPolygon":
    geojson.coordinates = [arcgis.rings];
    break;
  case "Feature":
    geojson.geometry = parse(arcgis.geometry);
    break;
  }

  //convert spatial ref if needed
  if(inputSpatialReference && inputSpatialReference.wkid === 102100){
    geojson = applyConverter(geojson, positionToGeographic);
  }

  return JSON.stringify(geojson);

$$ LANGUAGE plv8 IMMUTABLE STRICT;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment