使用 Rails / PostGIS / RGeo 存储 Google 地图地理数据
Storing Google Maps geo data with Rails / PostGIS / RGeo
在执行 Daniel Azuma's solution 以处理 Google 使用 RGeo 地图地理数据时遇到问题 / Rails。
设置
位置table:
create_table "locations", force: :cascade do |t|
t.string "name",
t.geometry "polygon", limit: {:srid=>3857, :type=>"polygon"}
end
位置class:
class Location < ActiveRecord::Base
# Create a simple mercator factory. This factory itself is
# geographic (latitude-longitude) but it also contains a
# companion projection factory that uses EPSG 3857.
FACTORY = RGeo::Geographic.simple_mercator_factory
# To interact in projected coordinates,
# just use the "polygon" attributes directly.
def polygon_projected
self.polygon
end
def polygon_projected=(value)
self.polygon = value
end
# To use geographic (lat/lon) coordinates,
# convert them using the wrapper factory.
def polygon_geographic
FACTORY.unproject(self.polygon)
end
def polygon_geographic=(value)
self.polygon = FACTORY.project(value)
end
def self.from_geojson(geojson)
location = Location.new
decoded_polygon = RGeo::GeoJSON.decode(geojson, json_parser: :json, geo_factory: RGeo::Geographic.simple_mercator_factory)
location.polygon_geographic = decoded_polygon
return location
end
end
initializers/rgeo.rb:
RGeo::ActiveRecord::SpatialFactoryStore.instance.tap do |config|
# By default, use the GEOS implementation for spatial columns.
config.default = RGeo::Geos.factory_generator
end
问题
所以我们开始吧 - 我从包含来自 Google 地图的坐标的 geojson 形状创建一个新的 Location 对象:
manhattan_polygon_data = '{"type":"Polygon","coordinates":[[[-73.9784998975546,40.7367992185915],[-73.9808911983494,40.7334453322506],[-73.9899687850649,40.7350399153528],[-73.9894998975546,40.7395992185915]]]}'
location = Location.from_geojson(manhattan_polygon_data)
此时,我们所有的地理属性都正常工作:
# Test geo properties:
location.polygon_projected
=> #<RGeo::Geos::CAPIPolygonImpl:0x3fc428c0c7dc "POLYGON ((-8235248.938246019 4973596.780357394, -8235515.136632829 4973104.057720993, -8236525.648963631 4973338.316345756, -8236473.452644745 4974008.150049943, -8235248.938246019 4973596.780357394))">
location.polygon_geographic
=> #<RGeo::Geographic::ProjectedPolygonImpl:0x3fc425d137a0 "POLYGON ((-73.9784998975546 40.73679921859151, -73.9808911983494 40.73344533225058, -73.9899687850649 40.73503991535281, -73.9894998975546 40.73959921859151, -73.9784998975546 40.73679921859151))">
但是当我们保存并从数据库中重新读取时,出现了问题:
# Save and retrieve from DB:
location.save!
location_from_db = Location.find(location.id)
# Test geo properties again:
location_from_db.polygon_projected
=> #<RGeo::Geos::CAPIPolygonImpl:0x3fc425cfb664 "POLYGON ((-8235248.938246019 4973596.780357394, -8235515.136632829 4973104.057720993, -8236525.648963631 4973338.316345756, -8236473.452644745 4974008.150049943, -8235248.938246019 4973596.780357394))">
location_from_db.polygon_geographic
RGeo::Error::InvalidGeometry: You can unproject only features that are in the projected coordinate space.
from /usr/local/lib/ruby/gems/2.3.0/gems/rgeo-0.5.3/lib/rgeo/geographic/factory.rb:270:in `unproject'
鉴于两个对象的投影几何形状相同,我不确定为什么后者 unproject
操作失败。
在这里找到我的答案:Simple Mercator Factory Project/Unproject - Google Groups
问题是我为属性使用的工厂实例与 ActiveRecord 适配器使用的工厂实例不同。解决方案是在初始化程序中创建简单墨卡托工厂的单个实例。
位置class:
class Location < ActiveRecord::Base
# To interact in projected coordinates,
# just use the "polygon" attributes directly.
def polygon_projected
self.polygon
end
def polygon_projected=(value)
self.polygon = value
end
# To use geographic (lat/lon) coordinates,
# convert them using the wrapper factory.
def polygon_geographic
FACTORY.unproject(self.polygon)
end
def polygon_geographic=(value)
self.polygon = FACTORY.project(value)
end
def self.from_geojson(geojson)
location = Location.new
decoded_polygon = RGeo::GeoJSON.decode(geojson, json_parser: :json, geo_factory: RGeo::Geographic.simple_mercator_factory)
location.polygon_geographic = decoded_polygon
return location
end
end
initializers/rgeo.rb:
# Create a single instance of simple mercator factory.
# This factory itself is geographic (latitude-longitude)
# but it also contains a companion projection factory that uses EPSG 3857.
FACTORY = RGeo::Geographic.simple_mercator_factory
RGeo::ActiveRecord::SpatialFactoryStore.instance.tap do |config|
config.default = FACTORY.projection_factory
end
在执行 Daniel Azuma's solution 以处理 Google 使用 RGeo 地图地理数据时遇到问题 / Rails。
设置
位置table:
create_table "locations", force: :cascade do |t|
t.string "name",
t.geometry "polygon", limit: {:srid=>3857, :type=>"polygon"}
end
位置class:
class Location < ActiveRecord::Base
# Create a simple mercator factory. This factory itself is
# geographic (latitude-longitude) but it also contains a
# companion projection factory that uses EPSG 3857.
FACTORY = RGeo::Geographic.simple_mercator_factory
# To interact in projected coordinates,
# just use the "polygon" attributes directly.
def polygon_projected
self.polygon
end
def polygon_projected=(value)
self.polygon = value
end
# To use geographic (lat/lon) coordinates,
# convert them using the wrapper factory.
def polygon_geographic
FACTORY.unproject(self.polygon)
end
def polygon_geographic=(value)
self.polygon = FACTORY.project(value)
end
def self.from_geojson(geojson)
location = Location.new
decoded_polygon = RGeo::GeoJSON.decode(geojson, json_parser: :json, geo_factory: RGeo::Geographic.simple_mercator_factory)
location.polygon_geographic = decoded_polygon
return location
end
end
initializers/rgeo.rb:
RGeo::ActiveRecord::SpatialFactoryStore.instance.tap do |config|
# By default, use the GEOS implementation for spatial columns.
config.default = RGeo::Geos.factory_generator
end
问题
所以我们开始吧 - 我从包含来自 Google 地图的坐标的 geojson 形状创建一个新的 Location 对象:
manhattan_polygon_data = '{"type":"Polygon","coordinates":[[[-73.9784998975546,40.7367992185915],[-73.9808911983494,40.7334453322506],[-73.9899687850649,40.7350399153528],[-73.9894998975546,40.7395992185915]]]}'
location = Location.from_geojson(manhattan_polygon_data)
此时,我们所有的地理属性都正常工作:
# Test geo properties:
location.polygon_projected
=> #<RGeo::Geos::CAPIPolygonImpl:0x3fc428c0c7dc "POLYGON ((-8235248.938246019 4973596.780357394, -8235515.136632829 4973104.057720993, -8236525.648963631 4973338.316345756, -8236473.452644745 4974008.150049943, -8235248.938246019 4973596.780357394))">
location.polygon_geographic
=> #<RGeo::Geographic::ProjectedPolygonImpl:0x3fc425d137a0 "POLYGON ((-73.9784998975546 40.73679921859151, -73.9808911983494 40.73344533225058, -73.9899687850649 40.73503991535281, -73.9894998975546 40.73959921859151, -73.9784998975546 40.73679921859151))">
但是当我们保存并从数据库中重新读取时,出现了问题:
# Save and retrieve from DB:
location.save!
location_from_db = Location.find(location.id)
# Test geo properties again:
location_from_db.polygon_projected
=> #<RGeo::Geos::CAPIPolygonImpl:0x3fc425cfb664 "POLYGON ((-8235248.938246019 4973596.780357394, -8235515.136632829 4973104.057720993, -8236525.648963631 4973338.316345756, -8236473.452644745 4974008.150049943, -8235248.938246019 4973596.780357394))">
location_from_db.polygon_geographic
RGeo::Error::InvalidGeometry: You can unproject only features that are in the projected coordinate space.
from /usr/local/lib/ruby/gems/2.3.0/gems/rgeo-0.5.3/lib/rgeo/geographic/factory.rb:270:in `unproject'
鉴于两个对象的投影几何形状相同,我不确定为什么后者 unproject
操作失败。
在这里找到我的答案:Simple Mercator Factory Project/Unproject - Google Groups
问题是我为属性使用的工厂实例与 ActiveRecord 适配器使用的工厂实例不同。解决方案是在初始化程序中创建简单墨卡托工厂的单个实例。
位置class:
class Location < ActiveRecord::Base
# To interact in projected coordinates,
# just use the "polygon" attributes directly.
def polygon_projected
self.polygon
end
def polygon_projected=(value)
self.polygon = value
end
# To use geographic (lat/lon) coordinates,
# convert them using the wrapper factory.
def polygon_geographic
FACTORY.unproject(self.polygon)
end
def polygon_geographic=(value)
self.polygon = FACTORY.project(value)
end
def self.from_geojson(geojson)
location = Location.new
decoded_polygon = RGeo::GeoJSON.decode(geojson, json_parser: :json, geo_factory: RGeo::Geographic.simple_mercator_factory)
location.polygon_geographic = decoded_polygon
return location
end
end
initializers/rgeo.rb:
# Create a single instance of simple mercator factory.
# This factory itself is geographic (latitude-longitude)
# but it also contains a companion projection factory that uses EPSG 3857.
FACTORY = RGeo::Geographic.simple_mercator_factory
RGeo::ActiveRecord::SpatialFactoryStore.instance.tap do |config|
config.default = FACTORY.projection_factory
end