Slide 1

Slide 1 text

Geospatial applications on Rails Sergey Nartimov Brainspec https://github.com/lest twitter: @just_lest

Slide 2

Slide 2 text

About • Rails, Rubinius, Elixir contributor • Software engineer at Brainspec Sergey Nartimov Brainspec https://github.com/lest twitter: @just_lest

Slide 3

Slide 3 text

Geospatial data

Slide 4

Slide 4 text

Geospatial data types • Point • Linestring • Polygon • Multi... • Geometry collection

Slide 5

Slide 5 text

Geospatial analysis • Coverage • Intersection • Distance • etc.

Slide 6

Slide 6 text

Geographic coordinate system

Slide 7

Slide 7 text

Geographic distance

Slide 8

Slide 8 text

Map projection

Slide 9

Slide 9 text

Mercator projection

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

Mercator projection

Slide 12

Slide 12 text

Mercator projection

Slide 13

Slide 13 text

Geospatial support

Slide 14

Slide 14 text

Geospatial support • MySQL • http://dev.mysql.com/doc/refman/5.5/en/ spatial-extensions.html

Slide 15

Slide 15 text

Geospatial support • MongoDB • http://www.mongodb.org/display/DOCS/ Geospatial+Indexing

Slide 16

Slide 16 text

Geospatial support • SpatiaLite • http://www.gaia-gis.it/gaia-sins/splite- doxy-4.0.0/index.html

Slide 17

Slide 17 text

Geospatial support • PostGIS • http://postgis.org/docs/

Slide 18

Slide 18 text

Rails & PostGIS

Slide 19

Slide 19 text

• https://github.com/dazuma/activerecord- postgis-adapter • https://github.com/dazuma/rgeo

Slide 20

Slide 20 text

# config/database.yml adapter: postgis # When postgresql >= 9.1 and postgis >= 2.0 postgis_extension: true # When postgresql < 9.1 or postgis < 2.0 # e.g. for postgresql 9.1 and postgis 1.5 on ubuntu script_dir: "/usr/share/postgresql/9.1/contrib/postgis-1.5" schema_search_path: public,postgis

Slide 21

Slide 21 text

create_table :locations do |t| t.point :coords, geographic: true end create_table :locations do |t| t.string :text t.point :coords, srid: 3785 end add_index :locations, :coords, spatial: true

Slide 22

Slide 22 text

class Location < ActiveRecord::Base GEOFACTORY = RGeo::Geographic.spherical_factory(srid: 4326) set_rgeo_factory_for_column :coords, GEOFACTORY end

Slide 23

Slide 23 text

Points in radius

Slide 24

Slide 24 text

point = Location::GEOFACTORY.point(27, 53) radius = 50_000 # 50 km Location.where('st_dwithin(coords, ?, ?)', point, radius) .order('st_distance(coords, ?)', point)

Slide 25

Slide 25 text

Squeel • https://github.com/ernie/squeel

Slide 26

Slide 26 text

point = Location::GEOFACTORY.point(27, 53) radius = 50_000 # 50 km Location.where { st_dwithin(coords, point, radius) } .order { st_distance(coords, point) }

Slide 27

Slide 27 text

class Location < ActiveRecord::Base GEOFACTORY = RGeo::Geographic.simple_mercator_factory set_rgeo_factory_for_column :coords, GEOFACTORY.projection_factory end point = Location::GEOFACTORY.point(27, 53) radius = 50_000 / Math.cos(lat * Math::PI / 180.0) Location.where { st_dwithin(coords, point, radius) } .order { st_distance(coords, point) }

Slide 28

Slide 28 text

Points in bounding box

Slide 29

Slide 29 text

No content

Slide 30

Slide 30 text

No content

Slide 31

Slide 31 text

sw = Location::GEOFACTORY.point(48.389537, 54.306922) ne = Location::GEOFACTORY.point(48.399643, 54.311216) bbox = RGeo::Cartesian::BoundingBox.create_from_points(sw, ne) Location.where('coords && ?', bbox)

Slide 32

Slide 32 text

Clustering • http://pgxn.org/dist/kmeans/ • http://postgis.refractions.net/docs/ ST_SnapToGrid.html

Slide 33

Slide 33 text

No content

Slide 34

Slide 34 text

Time zones example

Slide 35

Slide 35 text

• http://efele.net/maps/tz/world/

Slide 36

Slide 36 text

No content

Slide 37

Slide 37 text

• https://github.com/dazuma/rgeo-shapefile

Slide 38

Slide 38 text

class CreateTimeZonePolygons < ActiveRecord::Migration def change create_table :time_zone_polygons do |t| t.string :tzid t.geometry :geometry, geographic: true t.timestamps end add_index :time_zone_polygons, :geometry, spatial: true end end

Slide 39

Slide 39 text

class TimeZonePolygon < ActiveRecord::Base set_rgeo_factory_for_column :geometry, RGeo::Geographic.spherical_factory(srid: 4326) end

Slide 40

Slide 40 text

RGeo::Shapefile::Reader.open('tz_world.shp') do |file| file.each do |record| polygon = TimeZonePolygon.new polygon.tzid = record.attributes['TZID'] polygon.geometry = record.geometry polygon.save! end end

Slide 41

Slide 41 text

point = TimeZonePolygon::GEOFACTORY.point(27, 53) time_zone = TimeZonePolygon .where { st_covers(geometry, point) }.first time_zone.tzid # => "Europe/Minsk"

Slide 42

Slide 42 text

• Further improvements

Slide 43

Slide 43 text

Thanks <3 Sergey Nartimov Brainspec https://github.com/lest twitter: @just_lest