こんにちは。
ニジボックスでネィティブアプリを開発していることが多い@ochimです。
モチベーション
- 緯度経度から近くの駅を取得するAPIを探してみたが、手軽に使えるのがない。
- SimpleAPIとかあるけどhttpsじゃない
- サーバーサイドのSwiftを試してみたい
準備
- Hexavilleのインストール。
curl -L https://rawgit.com/noppoMan/Hexaville/master/install.sh | bash
source ~/.bashrc
- 駅データ.jpから駅データをダウンロードする(会員登録が必要)
Hexaville は簡単に言えば、Swiftの為のモダンなWebアプリケーションフレームワーク及びエンジンです。Swiftで作られたwebアプリをAWS Lambda と ApiGatewayで実行する事をコンセプトにしているそうです。詳しくはリンク先を
環境
- Mac OS 10.12.6
- Swift 4.0
- Xcode 9.2
プロジェクトを作る
hexaville generate NearStations
cd NearStations
swift package generate-xcodeproj
これでxcodeprojファイルが作成されるので、あとはXcodeで開発できます
今回のソース構成
実装
ロジック部分を晒します。
Convert.swift
import Foundation
import HexavilleFramework
struct Convert {
static func convertCSV() -> [[String]] {
do {
let asset = AssetLoader.shared.availableAbsolutePathForAssets()
let csvPath = "\(asset!)/station20171109free.csv"
let csvStr = try String(contentsOfFile:csvPath, encoding:String.Encoding.utf8)
var result: [[String]] = []
let rows = csvStr.components(separatedBy: .newlines)
for row in rows {
let columns = row.components(separatedBy: ",")
result.append(columns)
}
result.remove(at: result.count-1)
return result
} catch {
return []
}
}
}
駅データのcsvを取り込んで配列化しています。
Station.swift
import Foundation
struct Station {
func radians (deg: Double) -> Double {
return deg * Double.pi / 180
}
func rectangularCoordinateSystem (lat: Double, lng: Double) -> (Double,Double,Double) {
let h = radians(deg:lat)
let t = radians(deg:lng)
let x = cos(h) * cos(t)
let y = cos(h) * sin(t)
let z = sin(h)
return (x, y, z)
}
func calcDistance(lat1: Double, lng1: Double, lat2: Double, lng2: Double) -> Double{
let Re = 6378.137 // 地球の半径
let (x1, y1, z1) = rectangularCoordinateSystem(lat:lat1, lng:lng1)
let (x2, y2, z2) = rectangularCoordinateSystem(lat:lat2, lng:lng2)
return Re * acos(x1*x2 + y1*y2 + z1*z2)
}
/** 付近の駅を取得 **/
func getNearStations (lat: Double, lng: Double) -> [[String:String]] {
let stations = Convert.convertCSV()
var array: [[String:String]] = []
for station:[String] in stations {
var dic :[String:String] = [:]
let distance = calcDistance(lat1:lat, lng1:lng, lat2:atof(station[10]), lng2:atof(station[9]))
dic["km"] = String(format:"%f", distance)
dic["name"] = station[2]
array.append(dic)
}
array = array.sorted(by: { $0["km"]! < $1["km"]! })
return array[0...2].map{$0}
}
}
getNearStations() で付近の駅を近い順に3件取得しています。
2地点の緯度経度から距離を計算するのに使った方法はこちら
動作確認
ローカルで実行して確認
ニジボックスの入っているビルで試してみましょう。緯度:35.660944, 経度:139.775199
よっしゃ!
付近の駅3件の名前と距離を表示しています。
このままデプロイするか、てところなんですが、
息切れしたので、デプロイは次回に取っておきます。
ソースコードをgithubに上げました。こちら
参考
-
Lambdaで最寄駅検索APIを作ってみた
このページのJavascriptをSwiftに書き直した感じです。ありがとうございます!