dmanaster
dmanaster

Reputation: 587

RGeo: Projecting polygons onto a google map with a different SRID

I have a polygon that represents a school district, which I have imported from NYC Open Data. I believe that the coordinates are in epsg projection 2263 - nad83 / new york long island

I am having trouble converting the coordinates to a format usable by Google Maps.

Here is my code that imports the polygons from the original shapefiles:

proj4 = "+proj=lcc +lat_1=41.03333333333333 +lat_2=40.66666666666666 +lat_0=40.16666666666666 +lon_0=-74 +x_0=300000.0000000001 +y_0=0 +ellps=GRS80 +datum=NAD83 +to_meter=0.3048006096012192 +no_defs"
factory = RGeo::Geographic.projected_factory(:projection_proj4 => proj4, :projection_srid => 2263)

RGeo::Shapefile::Reader.open("/Users/dmanaster1/flatiron_school/nycdata/db/source/ES_Zones_2013-2014.shp", :factory => factory.projection_factory) do |file|
  file.each do |record|
    school_zone = ES_Zone.new
    ...
    school_zone.geometry = record.geometry
    school_zone.save
  end
  file.rewind
end

In my model:

class ES_Zone < ActiveRecord::Base
  proj4 = "+proj=lcc +lat_1=41.03333333333333 +lat_2=40.66666666666666 +lat_0=40.16666666666666 +lon_0=-74 +x_0=300000.0000000001 +y_0=0 +ellps=GRS80 +datum=NAD83 +to_meter=0.3048006096012192 +no_defs"
  FACTORY = RGeo::Geographic.projected_factory(:projection_proj4 => proj4, :projection_srid => 2263)
  set_rgeo_factory_for_column(:geometry, FACTORY.projection_factory)
end

In my controller:

  def index
    polygons = format_polygon(ES_Zone.first)
    gon.polygons = JSON.parse(polygons.to_json)
  end

  private

  def format_polygon(zone)
    array = Array.new
    zone.geometry.each do |polygon|
      polygon.exterior_ring.points.each do |point|
        x = point.x
        y = point.y
        array << { "lng" => x, "lat" => y }
      end
    end
    [array]
  end

I know I am missing something about how to convert the coordinates, but I am not sure where to go from here, even after reading Daniel Azuma's excellent guide. Anyone know how to do this?

Upvotes: 2

Views: 2268

Answers (1)

nathanvda
nathanvda

Reputation: 50057

I generally do not convert data using rgeo, but I know my way around coordinate systems, so dazuma's guide was pretty clear to me.

You first define WGS84 (which will render just fine on top of Google Maps, which does use a slightly different coordinate system, but they map perfectly)

wgs84_proj4 = '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs'

wgs84_factory = RGeo::Geographic.spherical_factory(:srid => 4326, :proj4 => wgs84_proj4)

Now you have a factory that can create WGS84 points/geometries. Now use that factory to convert your geometry.

Suppose you have created the geometry with the factory you specified, for your ES_Zone, then you can simply do

some_es_zone_wgs84 = RGeo::Feature.cast(some_es_zone, :factory => wgs84_factory, :project => true)

But if you fetch them from the database, the factory will have the correct srid, but not the correct proj4 information to do this cast. However, this is easily fixed:

some_es_zone = ES_Zone.find(params[:id])
some_es_zone_2263  = RGeo::Feature.cast(some_es_zone, :factory => 2263_factory, :project => false)
some_es_zone_wgs84 = RGeo::Feature.cast(some_es_zone, :factory => wgs84_factory, :project => true)

So in short: cast it without projecting the geometry to use the correct factory, and then cast it to the wanted coordinate system and project. Since we now specifed from and to, it will work.

Now you could use the rgeo-geojson gem to convert it to geoJson and send it to your browser.

If you are using postgis, as I do, I generally just use the postgis capabilities to create the geoJson, which I then include in my page and render using leaflet.

So, I add the following method to my model:

def as_geojson
  sql = "SELECT ST_asgeojson(ST_Transform(ST_SetSRID(geom,31370),4326)) FROM samples where id = #{self.id};"

  cursor = Sample.connection.execute(sql)
  cursor.first["st_asgeojson"]
end

Notice I transform my geometries from Belgian coordinate system (EPRS 31370) to wgs84 (EPRS 4326) and convert it to geojson in one go. Also postgis knows all the projections, and they are maintained, so I do not have to fiddle with the proj4 definitions.

Another alternative I use (depends on the amount of spatial data), is that I use geoserver to serve the spatial data. So while I use rails to store it and maintain, I use geoserver to efficiently host and query it (and openlayers in the frontend). But it does involve setting up an extra component. So it depends on your needs.

Upvotes: 10

Related Questions