PostGIS笔记(中)


Rails 和 PostgreSQL 的连接、postGIS 的 安装之类就都不赘述了。
PostgreSQL里postGIS安装好之后,就可以开始配置Rails这边了:

ActiveRecord with PostGIS

Gemfile 添加 activerecord-postgis-adapter 。
database.yml 里修改 adapter 和 schema_search_path

default: &default
  adapter: postgis
  schema_search_path: public,postgis

其他设置就让他默认吧。创建 migration:

class CreatePortals < ActiveRecord::Migration[5.0]
  def change
    create_table :portals do |t|
      t.st_point :lonlat, null: false, geographic: true
      t.timestamps
    end
    add_index :portals, :lonlat, using: :gist
  end
end

这里主要解释一下 geographic: true 这个选项。

 

Geography & Geometry

Geometry:平面坐标系,计算出的两点间距离单位是度(degree)
Geography:地理坐标系,SRID-4326计算出的两点间距离单位是米(meter)

没研究过地理,从头到尾都没怎么明白什么SRID 4326/3785/3857 是什么,好希望有人可以翻译一下 Web Mercator(Wiki) 给我等小白说明下是什么东西。
按照 activerecord-postgis-adapter 的文档,默认 geography 的 SRID 是 4326。

Geometry 和 Geograpy 的具体区别,这里用一个例子说明一下:
已知东京站(Lat: 35.681167, Lng: 139.767052)和横滨站(Lat: 35.465786, Lng: 139.622313),计算东京站到横滨站到距离,可以用 ST_Distance 方法,这个方法即支持Geometry又支持Geography。

  • ST_GeomFromText: Return a specified ST_Geometry value from Well-Known Text representation (WKT)
  • ST_GeogFromText: Return a specified ST_Geography value from Well-Known Text representation (WKT)
SELECT ST_Distance(
  ST_GeomFromText('POINT(139.767052 35.681167)'),
  ST_GeomFromText('POINT(139.622313 35.465786)')
);

输出结果是 0.259496345411655 度。

SELECT ST_Distance(
  ST_GeogFromText('POINT(139.767052 35.681167)'),
  ST_GeogFromText('POINT(139.622313 35.465786)')
);

输出结果是 27261.54830124 米。

为了验证结果是否正确,高三以后就没学过数学的我用了一个很蠢的方法:用GoogleMaps的工具来测量距离。结果如图:

Distance From Tokyo Station to Yokohama Station – Google Maps

结果和第二个值几乎是一样的。
至于弧度结果的验证我不会,抱歉。

 

范围n米以内的所有结果

基于Geography是以米为单位的优势,完成“取范围n千米以内所有的记录”这个需求变简单了,数学不好的我也不用纠结“怎么把度换算成米”这个可能会耗费我大量时间的难题。

但是这里要说一下,Geometry的方法比Geography多很多很多很多,参见文档PostGIS Function Support Matrix。至于什么时候用Geometry什么时候用Geography,还是参见文档,基本上Geography的计算对比Geometry需要更多CPU。

接下来直接用 ST_DWithin 这个方法就能取到需要的结果。

 

(写不动了,到这里结束分三章写吧……)

附:PostGIS 2.3文档PDF

, ,