Your SlideShare is downloading. ×
Geolocation on Rails
Nächste SlideShare
Wird geladen in ...5

Thanks for flagging this SlideShare!

Oops! An error has occurred.

Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Geolocation on Rails


Published on

Published in: Technologie, Business

0 Kommentare
30 Gefällt mir
  • Hinterlassen Sie den ersten Kommentar

Keine Downloads
Bei Slideshare
Aus Einbettungen
Anzahl an Einbettungen
Gefällt mir
Einbettungen 0
No embeds

Inhalte melden
Als unangemessen gemeldet Als unangemessen melden
Als unangemessen melden

Wählen Sie Ihren Grund, warum Sie diese Präsentation als unangemessen melden.

No notes for slide


  • 1. What isgeolocation?
  • 2. identication of a real-world geographic location
  • 3. identication of a real-world geographic location = context
  • 4. Brief history: early days many 1000s BC: smoke signals as early as 3200 BC: celestial navigation from 1000 BC: homing pigeons between 1100-1200 AD: the magnetic compass
  • 5. Brief history: modern era early 1900s: radio triangulation 1960s: satellite GPS 1990s: automotive GPS navigation
  • 6. Brief history: web era late 1990s: IP lookup mid 2000s: WiFi, GSM relevation 2004: A-GPS on smartphones
  • 7. Brief history: web era late 1990s: IP lookup mid 2000s: WiFi, GSM relevation 2004: A-GPS on smartphones
  • 8. Location-aware apps Later also Google, Facebook, and Twitter
  • 9. Cool!Lets join the party
  • 10. Cool!Lets join the party introducing: Stalk my Friends
  • 11. 1st step: display a map Well use Google Maps # app/views/layouts/application.html.slim = javascript_include_tag // app/assets/javascripts/maps.js $(document).ready(function() { var mapOptions = { zoom: 8, center: new google.maps.LatLng(43.7710332, 11.2480006), mapTypeId: google.maps.MapTypeId.ROADMAP }; var map = new google.maps.Map($(’#map’)[0], mapOptions); });git: google maps
  • 12. 2nd step: geolocate if (navigator.geolocation) { navigator.geolocation.getCurrentPosition( function(p) { var latlng = new google.maps.LatLng(p.coords.latitude, p.coords.longitude); $(’span#position’).text(latlng); if (myMarker) myMarker.setMap(null); myMarker = new google.maps.Marker( {position: latlng, map: map, title: This is me} ); }, function(error) { alert(error.message); }, {maximumAge: 600000} ); } else { console.error(No HTML5? What are you using, IE6?); }git: HTML5 geolocation
  • 13. Geolocation APIsupported by all current browerslocation sources: 1. GPS 2. WiFi/Bluetooth MAC address 3. GSM/CDMA cell IDs 4. IP addressone-shot vs continuous
  • 14. Geocode New feature: set the position manually.
  • 15. Geocode New feature: set the position manually. We need to geocode the address.
  • 16. Geocode New feature: set the position manually. We need to geocode the address. Several services: Google: 2.500 requests/day [1] Yahoo!: 50.000 requests/day [2] Bing: 50.000 requests/day [3] Nominatim: 1 request/second [4] FreeGeoIP: 1000 requests/hour [5] and ? many others...
  • 17. Gems for geocode Geokit (deprecated, still lacks support for Rails 3) [7] Graticule [6] Geocoder [8]
  • 18. Geocoder gem in action # Gemfile gem geocoder # map_controller.rb def geocode position = Geocoder.coordinates(params[:query]) respond_to do |wants| wants.json { render :json = position } end end // applications.js $(’[data-action=cheat]’).click(function() { $.getJSON(’/geocode/’, {query: $(’#address’).val()}, map.cheat); }); git: geocoding
  • 19. Awesome! We have a user position. Now to interact with other users we need:store lat/long (and address, eventually) in a DBquery the DB for nearby points
  • 20. 1st approach: D.I.Y. I # migration class CreateUsers ActiveRecord::Migration def change create_table :users do |t| t.string :name t.float :latitude t.float :longitude t.string :address t.timestamps end end end
  • 21. 1st approach: D.I.Y. II # app/controllers/users_controller.rb class UsersController ApplicationController respond_to :json def index @users = @user.nearbys(params[:radius]) respond_with @users end end
  • 22. 1st approach: D.I.Y. III # app/models/user.rb class User ActiveRecord::Base attr_accessible :address, :latitude, :longitude, :name def nearbys(radius) # ... oh s@#!t end end
  • 23. Let’s do some math Earth is a sphere: coordinates are in degree, distance is in meters. Solve the second (inverse) geodetic problem Given two points, determine the azimuth and length of the line (straight line, arc or geodesic) that connects them. [9] spherical model: Haversine formula (approximation) oblate spheroid model: Vincentys formulae
  • 24. Haversine formula d = 2r arcsin h(φ2 − φ1 ) + cos(φ1 ) cos(φ2 ) h(ψ2 − ψ1 ) (1) =2 r arcsin sin2 φ2 − φ1 2 + cos(φ1 ) cos(φ2 ) sin2 ψ2 − ψ1 2 (2) where: h() is the haversine function: h(θ) = sin(θ/2) 2 = 1−cos(θ) 2 d distance r radius of the sphere (6371.0 km) φ1 , φ2 latitude of point 1 and latitude of point 2 ψ1 , ψ2 longitude of point 1 and longitude of point 2
  • 25. Geocoder to the rescue! # app/models/user.rb geocoded_by :address reverse_geocoded_by :latitude, :longitude after_validation :reverse_geocode # app/controllers/users_controller.rb def index @users = @user.nearbys(params[:radius]) respond_with @users end Geocoder implements the Haversine formula directly in the SQL query.git: Geocoder backend
  • 26. Geocoder goodies # Nearest point user = User.near(Firenze, 50, :order = distance).first # distance from arbitrary point to user user.distance_from([40.714, 11.234]) # Find the bearing (direction) between places bearing = user.bearing_to(Paris, France) Geocoder::Calculations.compass_point(bearing) = NW # find the geographic center (aka center of gravity) polygon = [user1, user2, [40.22,-73.99], user4] Geocoder::Calculations.geographic_center(polygon) = [35.14968, -90.048929]
  • 27. Geocoder considerations Pros simple and easy to use Cons only circle areas SLOW (depends on the DBMS)
  • 28. 2nd approach: PostGIS PostGIS [10] is an extention for PostgreSQL that adds support for geographic objects. Alternatives are: MySQL: implements the datatype geometry Sqlite: with SpatiaLite extension
  • 29. PostGIS setup # install on a ubuntu box sudo apt-get install postgresql-9.1-postgis # prepare the db createdb template_postgis createlang plpgsql template_postigs psql -Upostgres -d template_postgis -f [...]/postgis.sql psql -Upostgres -d template_postgis -f [...]/spatial_ref_sys.sql psql -Upostgres -d template_postgis -f [...]/postgis_comments.sql # inside postgres console UPDATE pg_database SET datistemplate = TRUE WHERE datname = ’template_postgis’;
  • 30. PostGIS features PostGIS follows the OpenGIS Simple Features Specication for SQL [11] data types for points, linestrings, polygons, multipoints, multilinestrings, multipolygons and geometrycollections functions for measurement like area, distance, length and perimeter spatial indexes for high speed spatial querying
  • 31. PostGIS with Ruby Well use gem activerecord-postgis-adapter to integrate postgis data types in ActiveRecord.
  • 32. ActiveRecord PostGIS # config/database.yml development: adapter: postgis encoding: unicode database: stalk_my_friends pool: 5 username: nebirhos template: template_postgis # migration add_column :users, :position, :point, :geographic = true add_index :users, :position, :spatial = true # app/models/user.rb self.rgeo_factory_generator = RGeo::Geographic.simple_mercator_factory # SRID 4326, used by Google Maps
  • 33. PostGIS query # app/models/user.rb def nearbys(radius) radius = radius.to_i*1000 User.where( ST_Distance(position, ?, false) = ? , position, radius ).where(id ?, id) endgit: master
  • 34. Questions?
  • 35. Thanks for watching! Francesco Disperati | @nebirhos Source code of the demo app available at Special thanks to Cantiere Creativo and Silvia Shell
  • 36. Random stuff cited Google Geocode API Yahoo! PlaceFinder Bing API Nominatim FreeGeoIP Graticule Geokit Geocoder Geodesy on Wikipedia PostGIS OpenGIS PostGIS ActiveRecord Adapter