Ruby on GeoTools で距離計算 3
geotools.rb を使って二点間の距離を求める記事の第3回です。第1回、第2回で、
http://d.hatena.ne.jp/hfu/20071002/1191299399
地点名 経度 緯度 渋谷のハチ公 139.700638888889 35.6590111111111 つくば市のエキスポセンターの H-II ロケット 140.111305555556 36.0862305555556
http://d.hatena.ne.jp/hfu/20071003/1191473160
- 渋谷とつくばが含まれる座標系は、平面直角座標系 IX 系で、その EPSG コードは EPSG:2451
- 渋谷とつくばが含まれる座標系は、UTM 54N で、その EPSG コードは EPSG:32654
- 日本のいわゆる世界測地系は、JGD2000 で、その EPSG コードは EPSG:4612
ということが分かりましたので、これを使って実際に距離を計算してみようと思います。
平面直角座標系 IX 系でのユークリッド距離
require 'geotools' jgd2000 = Geo::import_epsg_crs(4612) ix = Geo::import_epsg_crs(2451) shibuya = Geo::import_array_geometry([139.700638888889, 35.6590111111111]) tsukuba = Geo::import_array_geometry([140.111305555556, 36.0862305555556]) tr = Geo::Transform.new(jgd2000, ix) print "#{tr.transform(shibuya).distance(tr.transform(tsukuba))} m\n"
ユークリッド距離の計算に、JTS の関数 Geometry#distance を使っています。
$ ruby ix.rb
DEBUG: rjb primitive_conversion mode
60180.7390166327 m
UTM 54N でのユークリッド距離
require 'geotools' jgd2000 = Geo::import_epsg_crs(4612) utm54n = Geo::import_epsg_crs(32654) shibuya = Geo::import_array_geometry([139.700638888889, 35.6590111111111]) tsukuba = Geo::import_array_geometry([140.111305555556, 36.0862305555556]) tr = Geo::Transform.new(jgd2000, utm54n) print "#{tr.transform(shibuya).distance(tr.transform(tsukuba))} m\n"
$ ruby utm.rb
DEBUG: rjb primitive_conversion mode
60169.8952557551 m
大圏距離 1/2
まず、http://www.whitehat.net.nz/articles/2007/01/24/great-circle-distance-in-ruby にある、大圏距離算出の B アプローチのコードを使って計算:
# from: # http://www.whitehat.net.nz/articles/2007/01/24/great-circle-distance-in-ruby def distance(lat1, lon1, lat2, lon2, radius = 6_372_795.0) include Math # Convert coordinates to radians lat1, lon1, lat2, lon2 = [lat1, lon1, lat2, lon2].map do |v| v * PI / 180.0 end # Perform distance calculation distance = acos( cos(lat1) * cos(lat2) * cos(lon1 - lon2) + sin(lat1) * sin(lat2) ) * radius return distance end print "#{distance(139.700638888889, 35.6590111111111, 140.111305555556, 36.0862305555556)} m\n"
このコードは、地球を回転楕円体ではなくて球と近似して算出した大圏距離を求めているように見えます。
$ ruby gcd.rb
58375.8226658971 m
平面直角座標系 IX 系、UTM 54N 上の「地図上の距離」とずいぶん違ってきています。
大圏距離 2/2
それから、GeoTools にも、GeodeticCalculator というクラスがあるので、これを使って計算してみます。このクラスは、楕円体を考慮して距離を計算してくれるようです。スレッドセーフでないクラスだそうです。
require 'geotools' gc = Geo::Tools::GeodeticCalculator.new gc.setStartingGeographicPoint(139.700638888889, 35.6590111111111) gc.setDestinationGeographicPoint(140.111305555556, 36.0862305555556) print gc.toString print "#{gc.getOrthodromicDistance}m\n"
ここで、orthodromic distance という言葉が出てきますが、これは、
The orthodromic distance is the shortest distance between two points on a sphere's surface. The orthodromic path is always on a great circle. An other possible distance measurement is the loxodromic distance, which is a longer distance on a path with a constant direction on the compas.
http://deegree.sourceforge.net/deegree1.x.x_javadoc/org/deegree_impl/model/cs/Ellipsoid.html
ということですので、大圏距離と同じ意味であると思われます。
$ ruby geodetic.rb DEBUG: rjb primitive_conversion mode Ellipsoid: WGS84 Source point: 139°42.0'E 35°39.5'N Target point: 140°06.7'E 36°01.1'N 60186.64147204m
まとめ
渋谷のハチ公とつくばの H-II ロケットの距離は、以下のように計算されました。
距離の定義 | 距離 | WGS84 大圏距離との比 |
平面直角座標系 IX 系での地図上の距離 | 60180.7390166327 m | 0.99990193080619 |
UTM 54N 系での地図上の距離 | 60169.8952557551 m | 0.999721761908036 |
地球を球と近似した大圏距離 | 58375.8226658971 m | 0.969913277068565 |
地球を WGS84 で近似した大圏距離 | 60186.64147204 m | - |
ほとんど同じ結果が出ています。特に、平面直角座標系については60km動いて5m台の違いしかなく、やはり投影法として優秀なものだと思います。
考察
大圏距離の計算には単純なユークリッド距離の計算と比べ、計算上のコストがかかります。距離の算出を頻繁に行う場合には、データを投影しておいてユークリッド距離の計算ですますということが有効かもしれません。
このエントリの信頼性について
このエントリの内容には誤りがあるかもしれません。
ChangeLog
Tue Oct 9 05:51:40 CEST 2007: 大圏距離の計算の入力の値に、誤った数字が混入していることに気がつきました。これを修正しました。
geotools.rb
このエントリで使用した geotools.rb は、http://svgmapdata.sakura.ne.jp/geotools/ に公開されています。