RESASとYahoo!のWebAPIを使って観光資源への経路地図画像を出力する

## 概要

- 任意の位置(緯度経度)から一番近い観光資源への経路を地図画像に出力する
- 3つの WebAPI をマッシュアップ
 - RESAS-API 観光資源
 - YOLP 経路地図API
 - Yahoo!リバースジオコーダAPI

## 出力したサンプル地図画像

![sample.png](https://qiita-image-store.s3.amazonaws.com/0/139365/dd66cdf3-8d1e-3996-dcb7-6f3edc6c5ed2.png)

## サンプルソースコード

名古屋の中村公園駅から一番近い観光資源への経路地図画像を出力するサンプルコード。

```ruby
require 'json'
require 'open-uri'

def get_kanko_shigen_list(pref_code, city_code, resas_api_key)
  # RESAS-API - 観光資源
  # https://opendata.resas-portal.go.jp/docs/api/v1/tourism/attractions.html
  base_url = 'https://opendata.resas-portal.go.jp/api/v1/tourism/attractions'
  params = {
    'prefCode' => pref_code,
    'cityCode' => city_code,
  }
  url = base_url + '?' + URI.encode_www_form(params)
  puts('Kanko Shigen URL: ' + url)
  headers = {
    'X-API-KEY' => resas_api_key
  }
  json = open(url, headers).read
  data = JSON.parse(json)
  data['result']['data']
end

def get_address(lat, lng, yjdn_app_id)
  # YOLP(地図):Yahoo!リバースジオコーダAPI - Yahoo!デベロッパーネットワーク
  # http://developer.yahoo.co.jp/webapi/map/openlocalplatform/v1/reversegeocoder.html
  base_url = 'https://map.yahooapis.jp/geoapi/V1/reverseGeoCoder'
  params = {
    'appid' => yjdn_app_id,
    'lat' => lat,
    'lon' => lng,
    'output' => 'json',
  }
  url = base_url + '?' + URI.encode_www_form(params)
  puts('Reverse Geocoder URL: ' + url)
  json = open(url).read
  data = JSON.parse(json)
  data['Feature'][0]['Property']['AddressElement']
end

def get_codes(address_elements)
  codes = {};
  address_elements.each{|e|
    codes[e['Level']] = e['Code']
  }
  codes
end

# 大円距離(メートル)を求める
def distance(lat1, lng1, lat2, lng2)
  # 緯度経度をラジアンに変換
  rlat1 = lat1 * Math::PI / 180
  rlng1 = lng1 * Math::PI / 180
  rlat2 = lat2 * Math::PI / 180
  rlng2 = lng2 * Math::PI / 180
  # 球面三角法による距離計算
  a =
    Math::sin(rlat1) * Math::sin(rlat2) +
    Math::cos(rlat1) * Math::cos(rlat2) *
    Math::cos(rlng1 - rlng2)
  rr = Math::acos(a) # 2点間の中心角(ラジアン)
  earth_radius = 6378140 # 地球赤道半径(メートル)
  earth_radius * rr
end

def get_routemap_image(start_pos, end_pos, yjdn_app_id)
  # YOLP(地図):経路地図API - Yahoo!デベロッパーネットワーク
  # http://developer.yahoo.co.jp/webapi/map/openlocalplatform/v1/routemap.html
  base_url = 'https://map.yahooapis.jp/course/V1/routeMap'
  params = {
    'appid' => yjdn_app_id,
    'width' => '600',
    'height' => '600',
    'route' => "#{start_pos['lat']},#{start_pos['lng']},#{end_pos['lat']},#{end_pos['lng']}",
    'text' => "#{end_pos['lat']},#{end_pos['lng']}|width:24|label:#{end_pos['resourceName']}",
  }
  url = base_url + '?' + URI.encode_www_form(params)
  puts('Route Map URL: ' + url)
  open(url).read
end

# RESAS-API - 地域経済分析システム（RESAS）のAPI提供情報
# https://opendata.resas-portal.go.jp/

# RESAS-APIのAPIキーを指定
resas_api_key = '<YOUR RESAS API KEY>'

# Yahoo!デベロッパーネットワーク
# http://developer.yahoo.co.jp/

# Yahoo!デベロッパーネットワークのアプリケーションIDを指定
yjdn_app_id = '<YOUR APPID>'

# 経路地図画像出力先ファイル名を指定
output_file = 'sample.png'

# 基準となる緯度経度を指定
pos = {'lat' => 35.168068, 'lng' => 136.855273} # 中村公園駅

# 住所情報を取得
address = get_address(pos['lat'], pos['lng'], yjdn_app_id)

# 都道府県コードを取得
codes = get_codes(address)
pref_code = codes['prefecture']
city_code = '-'

# 観光資源情報を取得
list = get_kanko_shigen_list(pref_code, city_code, resas_api_key)

# 基準となる緯度経度から近い順に並び替える
list.sort!{|a, b|
  a['distance'] = distance(pos['lat'], pos['lng'], a['lat'], a['lng'])
  b['distance'] = distance(pos['lat'], pos['lng'], b['lat'], b['lng'])
  a['distance'] <=> b['distance']
}

# 環境資源情報を出力
puts '観光資源を近い順に上位10件'
list.first(10).each{|ks|
  puts("#{ks['resourceName']}: #{ks['distance']}メートル (#{ks['lat']},#{ks['lng']})")
}
puts("\n")

# 経路地図画像を取得してファイルへ出力
image = get_routemap_image(pos, list[0], yjdn_app_id)
open(output_file, 'wb').write(image)
```

## サンプルコードの出力結果(テキスト)

```
Reverse Geocoder URL: https://map.yahooapis.jp/geoapi/V1/reverseGeoCoder?appid=<YOUR APPID>&lat=35.168068&lon=136.855273&output=json
Kanko Shigen URL: https://opendata.resas-portal.go.jp/api/v1/tourism/attractions?prefCode=23&cityCode=-
観光資源を近い順に上位10件
秀吉清正記念館: 663.0252391838234メートル (35.173799,136.853289)
常泉寺: 709.1554516058555メートル (35.174403,136.856094)
一宮コスプレパレード: 2305.3084680276メートル (35.16802,136.880606)
香の物祭（萱津神社）: 2576.934315494503メートル (35.183983,136.834707)
奥山田のしだれ桜: 2854.2877742380765メートル (35.170649,136.88648)
観音寺（荒子）多宝塔: 3155.7745718622846メートル (35.140177,136.861479)
明眼院: 3236.622706672258メートル (35.174534,136.820595)
ハワイアンフェスティバルｉｎ吉良: 3304.229285843978メートル (35.1388,136.861318)
甚目寺観音: 4213.942678652466メートル (35.195117,136.822872)
大野城址（愛西市）: 4408.0719693974515メートル (35.166874,136.903691)

Route Map URL: https://map.yahooapis.jp/course/V1/routeMap?appid=<YOUR APPID>&width=600&height=600&route=35.168068%2C136.855273%2C35.173799%2C136.853289&text=35.173799%2C136.853289%7Cwidth%3A24%7Clabel%3A%E7%A7%80%E5%90%89%E6%B8%85%E6%AD%A3%E8%A8%98%E5%BF%B5%E9%A4%A8
```

## サンプルコードの出力結果(画像)

![sample.png](https://qiita-image-store.s3.amazonaws.com/0/139365/dd66cdf3-8d1e-3996-dcb7-6f3edc6c5ed2.png)

## 参考資料

- RESAS-API - 観光資源 https://opendata.resas-portal.go.jp/docs/api/v1/tourism/attractions.html
- YOLP(地図):経路地図API - Yahoo!デベロッパーネットワーク http://developer.yahoo.co.jp/webapi/map/openlocalplatform/v1/routemap.html
- YOLP(地図):Yahoo!リバースジオコーダAPI - Yahoo!デベロッパーネットワーク http://developer.yahoo.co.jp/webapi/map/openlocalplatform/v1/reversegeocoder.html
- 2点間の距離計算 (Go, Haskell, Java, LOGO, OCaml, Ruby, Rust) - Qiita http://qiita.com/niwasawa/items/5128101ef93a56e8a6af