LoginSignup
5
2

More than 5 years have passed since last update.

SwiftとHexavilleで駅探索APIを作ってみた

Last updated at Posted at 2017-12-14

こんにちは。
ニジボックスでネィティブアプリを開発していることが多い@ochimです。

モチベーション

  • 緯度経度から近くの駅を取得するAPIを探してみたが、手軽に使えるのがない。
  • SimpleAPIとかあるけどhttpsじゃない
  • サーバーサイドのSwiftを試してみたい

準備

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で開発できます

今回のソース構成

スクリーンショット 2017-12-11 20.20.25.png

実装

ロジック部分を晒します。

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

スクリーンショット 2017-12-16 21.08.35.png

よっしゃ!
付近の駅3件の名前と距離を表示しています。

このままデプロイするか、てところなんですが、
息切れしたので、デプロイは次回に取っておきます。

ソースコードをgithubに上げました。こちら

参考

デプロイしました

別記事

5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2