2012-11-30 16 views
5

Ho un'app per rotaie che utilizza rgeo 0.3.19 con supporto proj4 che si collega a un database PostGIS 1.5 con la gemma rgeo-activerecord 0.4.5.RGeo Projected Buffer Polygon troppo piccolo

La mia app ha un modello chiamato Region che contiene un punto geografico, un raggio e una forma di poligono. Quando una nuova regione sta per salvarla, usa la funzione di buffer della geofactory della regione per creare un poligono usando il raggio e il punto geografico.

Ecco la geofactory che viene utilizzato per il modello di regione

GEOFACTORY = RGeo::Geographic.projected_factory(:buffer_resolution => 8, :projection_proj4 => '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m [email protected] +wktext +no_defs', :projection_srid => 3857) 

Il projection_srid che sto usando è quella di Apple e Google Maps proiezione di Mercatore 3857. Il problema è che il buffer che si sta creando non ha le stesse dimensioni di quello che sto disegnando in entrambe le mappe apple o google maps. Ad esempio, se uso il costruito in funzione di MapKit MKCircle

[MKCircle circleWithCenterCoordinate:self.coordinate radius:50]; 

Il cerchio sarà disegnare e sovrapporre come questo. iOS Drawing Radius

Ma se prendo le coordinate che sono state create formano la funzione di buffer che compongono la forma poligonale nel database e li diagramma su google maps ottengo questo.

GoogleMaps Radius

Come si può vedere, il poligono che è stato creato utilizzando lo stesso sistema di proiezione è più piccola di quanto dovrebbe essere. Questo problema cresce esponenzialmente fuori controllo in base alla dimensione del raggio definito. Ho anche provato a utilizzare la factory simple_mercator come definita in RGeo che ha prodotto gli stessi risultati.

Si spera che qualcuno abbia qualche idea sul perché, quando un longitudine, il punto proiettato sulla latitudine viene bufferizzato, crea un poligono di dimensioni errate.

risposta

9

Quello che stai osservando qui è distorsione Mercator. Una distanza di "50" in una proiezione di mercatore non corrisponde a 50 metri sulla superficie del pianeta reale, a meno che tu non sia all'Equatore.

Il cerchio disegnato dalla mappa iOS è corretto: è il raggio di 50 metri. Quello che sospetto che tu abbia creato per creare la tua seconda immagine è stato proiettare il punto in una proiezione di Mercatore (secondo il Proj4 che hai fornito). Quindi è stato creato un buffer con raggio 50 nel sistema di coordinate proiettato. Tuttavia, 50 unità Mercator alla latitudine 40,61 corrispondono a circa 37,96 metri in superficie della distanza terrestre. Quindi, quando proietti quel poligono di nuovo in latitudine e longitudine e lo trama, questo è quello che vedi: un cerchio di 38 metri.

Un modo per visualizzare questo è guardare la mappa del mondo su Google Maps. Disegna un cerchio di raggio 50 pixel all'equatore. E poi disegna un altro cerchio di raggio 50 pixel sulla Groenlandia. Sulla mappa (nelle coordinate di Mercator), quei cerchi hanno le stesse dimensioni. Ma, se conosci la tua proiezione di Mercatore, sai che distorce la Groenlandia perché la Groenlandia è lontana dall'Equatore, quindi la tua cerchia sulla Groenlandia è in realtà molto più piccola nella tua vita rispetto al tuo cerchio sopra l'equatore. A 40 gradi di latitudine, la distorsione non è così grave, ma è ancora lì.

Se si desidera correggere questo, è abbastanza facile. La distorsione delle dimensioni causata dalla proiezione di Mercatore è proporzionale alla secante della latitudine. Cioè, 50 unità di mercatore sull'equatore sono uguali a 50 metri, ma 50 unità di mercatore alla latitudine x (in radianti), corrispondono a 50/sec (x) metri. Quindi se vuoi un raggio di 50 metri, moltiplica 50 per s (latitudine) e usa quel numero come raggio nelle coordinate di Mercatore.In RGeo-speak:

p_lonlat = GEOFACTORY.point(40.610355377197266, -75.38220214843749) 
p_proj = p_lonlat.projection 
buf_proj = p_proj.buffer(50.0 * (1/Math.cos(p_lonlat.y/180.0 * Math::PI))) 
buf_lonlat = GEOFACTORY.unproject(buf_proj) 
+0

Grazie per la modifica, MobileOverlord. Ho dimenticato che non c'era una funzione secante in Ruby. Questo è quello che ottengo per postare il codice senza prima provarlo ... :-) –

Problemi correlati