• Speichern
Geolocation on Rails
Upcoming SlideShare
Loading in...5

Geolocation on Rails






Views auf SlideShare
Views einbetten


Gefällt mir

5 Einbettungen 483

http://xn--vssby-gra.se 478
https://twitter.com 2 1 1
https://www.linkedin.com 1


Details hochladen

Uploaded via as Adobe PDF


© Alle Rechte vorbehalten

Report content

Als unangemessen gemeldet Als unangemessen melden
Als unangemessen melden

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

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Ihre Nachricht erscheint hier
Kommentar posten
Kommentar bearbeiten

Geolocation on Rails Geolocation on Rails Presentation Transcript

  • What isgeolocation?
  • identication of a real-world geographic location
  • identication of a real-world geographic location = context View slide
  • 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 View slide
  • Brief history: modern era early 1900s: radio triangulation 1960s: satellite GPS 1990s: automotive GPS navigation
  • Brief history: web era late 1990s: IP lookup mid 2000s: WiFi, GSM relevation 2004: A-GPS on smartphones
  • Brief history: web era late 1990s: IP lookup mid 2000s: WiFi, GSM relevation 2004: A-GPS on smartphones
  • Location-aware apps Later also Google, Facebook, and Twitter
  • Cool!Lets join the party
  • Cool!Lets join the party introducing: Stalk my Friends
  • 1st step: display a map Well use Google Maps # app/views/layouts/application.html.slim = javascript_include_tag "https://maps.googleapis.com/maps/api/js" // 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
  • 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
  • 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
  • Geocode New feature: set the position manually.
  • Geocode New feature: set the position manually. We need to geocode the address.
  • 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] Geocoder.ca and Geocoder.us: ? many others...
  • Gems for geocode Geokit (deprecated, still lacks support for Rails 3) [7] Graticule [6] Geocoder [8]
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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]
  • Geocoder considerations Pros simple and easy to use Cons only circle areas SLOW (depends on the DBMS)
  • 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
  • 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’;
  • 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
  • PostGIS with Ruby Well use gem activerecord-postgis-adapter to integrate postgis data types in ActiveRecord.
  • 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
  • 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
  • Questions?
  • Thanks for watching! Francesco Disperati | @nebirhos http://nebirhos.com Source code of the demo app available at https://github.com/nebirhos/stalk-my-friends Special thanks to Cantiere Creativo and Silvia Shell
  • Random stuff cited Google Geocode API https://developers.google.com/maps/documentation/geocoding/ Yahoo! PlaceFinder http://developer.yahoo.com/geo/placefinder/guide/responses.html Bing API http://msdn.microsoft.com/en-us/library/ff701715.aspx Nominatim http://wiki.openstreetmap.org/wiki/Nominatim FreeGeoIP http://github.com/fiorix/freegeoip/blob/master/README.rst Graticule http://graticule.rubyforge.org/ Geokit http://geokit.rubyforge.org/ Geocoder http://www.rubygeocoder.com/ Geodesy on Wikipedia http://en.wikipedia.org/wiki/Geodesy PostGIS http://postgis.refractions.net/ OpenGIS http://www.opengeospatial.org/standards/sfs PostGIS ActiveRecord Adapter https://github.com/dazuma/activerecord-postgis-adapter