2012-11-17 5 views
6

RGeo bietet integrierte Methoden für POINT-Funktionen, z. B. Gettermethoden lat() und lon(), um Längen- und Breitenwerte von einem POINT-Objekt abzurufen. Leider funktionieren diese nicht als Setter. Zum Beispiel:Einstellen einzelner Koordinaten für RGeo Punkt

point = RGeo::Geographic.spherical_factory(:srid => 4326).point(3,5)  // => #<RGeo::Geographic::SphericalPointImpl:0x817e521c "POINT (3.0 5.0)"> 

Ich kann dies tun:

point.lat  // => 5.0 
point.lon  // => 3.0 

Aber ich kann nicht tun:

point.lat = 4 // => NoMethodError: undefined method `lat=' for #<RGeo::Geographic::SphericalPointImpl:0x00000104024770> 

Irgendwelche Vorschläge, wie Setter-Methoden zu implementieren? Würdest du es im Model machen oder die Feature-Class erweitern?

Antwort

27

Ich bin der Autor von RGEO, so können Sie diese Antwort maßgebliche auf dieser Grundlage prüfen.

Kurz gesagt, bitte vermeiden Sie dies. RGeo-Objekte haben absichtlich keine Setter-Methoden, da sie unveränderliche Objekte sein sollen. Dies ist so, dass sie zwischengespeichert, als Hash-Schlüssel verwendet und über Threads hinweg verwendet werden können. Einige der RGeo-Berechnungen gehen davon aus, dass sich der Wert eines Feature-Objekts niemals ändert. Daher können solche Änderungen unerwartete und unvorhersehbare Konsequenzen haben.

Wenn Sie wirklich einen "geänderten" Wert wünschen, erstellen Sie ein neues Objekt. Zum Beispiel:

p1 = my_create_a_point() 
p2 = p1.factory.point(p1.lon + 20.0, p2.lat) 
+0

Danke für die Klärung, Daniel. – donsteffenski

+3

Es macht immer Spaß, eine Antwort zu lesen, die mit "Ich bin der Autor der Bibliothek, die Sie Fragen stellen" beginnt. Groß :) – SpacyRicochet

2

Ich habe etwas gefunden, das funktioniert, obwohl es elegantere Lösungen geben könnte.

In meinen Location Modell habe ich Methoden hinzugefügt Thesen:

after_initialize :init 


    def init 
    self.latlon ||= Location.rgeo_factory_for_column(:latlon).point(0, 0) 
    end 

    def latitude 
    self.latlon.lat 
    end 

    def latitude=(value) 
    lon = self.latlon.lon 
    self.latlon = Location.rgeo_factory_for_column(:latlon).point(lon, value) 
    end 

    def longitude 
    self.latlon.lon 
    end 

    def longitude=(value) 
    lat = self.latlon.lat 
    self.latlon = Location.rgeo_factory_for_column(:latlon).point(value, lat) 
    end 
+0

Wenn ich dies ausführen, sehe ich 'undefined Methode 'rgeo_factory_for_column' für # ' – mkirk

0

landete ich in meinem Modell so etwas wie dies zu tun:

class MyModel < ActiveRecord::Base 

    attr_accessor :longitude, :latitude 
    attr_accessible :longitude, :latitude 

    validates :longitude, numericality: { greater_than_or_equal_to: -180, less_than_or_equal_to: 180 }, allow_blank: true 
    validates :latitude, numericality: { greater_than_or_equal_to: -90, less_than_or_equal_to: 90 }, allow_blank: true 

    before_save :update_gps_location 

    def update_gps_location 
    if longitude.present? || latitude.present? 
     long = longitude || self.gps_location.longitude 
     lat = latitude || self.gps_location.latitude 
     self.gps_location = RGeo::Geographic.spherical_factory(srid: 4326).point(long, lat) 
    end 
    end 
end 

Dann können Sie einfach die Position aktualisieren wie so:

my_model.update_attributes(longitude: -122, latitude: 37) 

ich nicht laden Längengrad/Breitengrad in einem after_initialize-Block, da ich die Daten in meiner App nie lesen, sondern nur schreiben muss. Das könnte man leicht hinzufügen.

Kredit an this answer für die Validierungen.

Verwandte Themen