【问题标题】:Setting single coordinates for RGeo Point为 RGeo 点设置单个坐标
【发布时间】:2012-11-06 03:19:54
【问题描述】:

RGeo 为 POINT 功能提供内置方法,例如 getter 方法 lat()lon() 从 POINT 对象中提取纬度和经度值。不幸的是,这些不能作为二传手。例如:

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

我可以这样做:

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

但我做不到:

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

关于如何实现 setter 方法的任何建议?你会在 Model 中做还是扩展 Feature 类?

【问题讨论】:

    标签: ruby-on-rails geocoding geospatial postgis


    【解决方案1】:

    我发现了一些可行的方法,尽管可能有更优雅的解决方案。

    在我的Location 模型中,我添加了这些方法:

      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
    

    【讨论】:

    • 当我运行这个时,我看到undefined method 'rgeo_factory_for_column' for #&lt;Class:0x007f86b4b5e6f8&gt;
    【解决方案2】:

    我是 RGeo 的作者,因此您可以在此基础上认为此答案具有权威性。

    简而言之,请避免这样做。 RGeo 对象故意没有设置方法,因为它们是不可变对象。这样它们就可以被缓存、用作哈希键、跨线程使用等。一些 RGeo 计算假设特征对象的值永远不会改变,因此进行这样的更改可能会产生意想不到的和不可预测的后果。

    如果你真的想要一个“改变”的值,创建一个新对象。例如:

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

    【讨论】:

    • 感谢丹尼尔澄清这一点。
    • 阅读以“我是您提出问题的图书馆的作者”开头的答案总是很有趣。太棒了:)
    【解决方案3】:

    我最终在我的模型中做了这样的事情:

    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
    

    然后你可以像这样更新位置:

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

    我没有在 after_initialize 块中加载经度/纬度,因为在我的应用程序中,我们从不需要读取数据,只需写入即可。不过,您可以轻松添加它。

    感谢this answer 进行验证。

    【讨论】:

      猜你喜欢
      • 2013-05-20
      • 1970-01-01
      • 1970-01-01
      • 2016-04-17
      • 1970-01-01
      • 2011-10-23
      • 2018-11-21
      • 1970-01-01
      • 2020-09-15
      相关资源
      最近更新 更多