10
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Turf.jsを使用して地球上の2点間の距離を計測する

Posted at

はじめに

仕事である特定の2点間の距離を計測する必要が出てきたので
以前他のPJで使用されていた、Turf.jsというライブラリがあったので試してみました。

作業環境

  • node 12.0.0
  • npm 6.9.0
  • Turf.js 6.9.0

前提条件

  • 複数の箇所の緯度・経度をデータとして持っている
    • データはjson形式のファイル(lists.json)
  • できれば外部ファイルに書き出して確認したい
  • 上記と、ある特定の一点との距離を計測する必要がある
  • 地球上(球面状)の2点間の計算
lists.json
[
    {
        "NAME": "名古屋駅",
        "LATITUDE": 35.170406,
        "LONGITUDE": 136.881695,
        "Distance": 267.50358367757696
    },
    {
        "NAME": "大阪駅",
        "LATITUDE": 34.702485,
        "LONGITUDE": 135.495951,
        "Distance": 403.0278954652313
    }
]

事前準備

まずは今回の作業を行うのにディレクトリを作っておきます。

mkdir turf_test
cd turf_test

Turf.jsについて

参考にさせていただいたスライドからそのまま引用すると

軽量・高速・オープンなWeb地図用のGISライブラリ

とあります。
公式サイトを見る限りかなり色々できそうです。

Turf.js公式サイト

ただ色々できる分、全て入れるとかなりの容量になります。

npm install @turf/turf

上記コマンドでインストールをすると本体や関連しているライブラリ含めて、17.3MBあります。
全て入れた状態でも使用はできるんですが、公式サイトを見る限りかなりモジュール化が徹底されているようなので、用途に沿ったものだけを入れていきます。

ここで前提条件を思い出します。
基本的には2点間の計測ができれば良いので、それを実現できそうなものを公式サイトから探しました。

distanceがそれに該当しそうです。
distanceの説明

記載されている説明を直訳します。(ありがとうgoogle翻訳)

Calculates the distance between two points in degrees, radians, miles, or kilometers. This uses the Haversine formula to account for global curvature.

2つのポイント間の距離を度、ラジアン、マイル、またはキロメートルで計算します。これは、Haversine公式を使用して、全体的な曲率を考慮します。

説明を見る限りでは今回の要件を満たしていそうです。
というわけでこれをインストールしていきます。

distanceの実装

該当の機能の説明を見る限り@turf/distanceだけあれば十分なようです。
インストールします。

npm init
npm install @turf/distance

ちなみにこのモジュールだけだと、131KBだけです。

まずは公式に載っている通りの内容を実行してみます。
今回はターミナルから直接叩くことを想定しています。

ファイルの作成。

touch index.js

今回は東京駅から名古屋駅までの距離を計測します。
まずは公式サイトに載っているテストコードを掲載

テストコード
var from = turf.point([-75.343, 39.984]);
var to = turf.point([-75.534, 39.123]);
var options = {units: 'miles'};

var distance = turf.distance(from, to, options);

ちなみに公式はライブラリが全部入っている前提のコードのようなので、以下のように変更しました。

index.js
// turf.js呼び出し
const { point } = require('@turf/helpers')
const distance = require('@turf/distance').default

const from = point([139.766765, 35.681283]); //[経度, 緯度] 東京駅
const to = point([136.881695, 35.170406]); //[経度, 緯度] 名古屋駅
const options = { units: 'kilometers' }; // degrees, radians, miles, kilometersが指定可能

const result = distance(from, to, options);
console.log(result) // 267.50358367757696
node index.js
// consoleに右記が出力 → 267.50358367757696

だいたい267Kmほどの距離があるようです。
試しにgooglemapでも距離計測をしておきます。

スクリーンショット 2019-09-14 21.57.43.png

おおよそあっています。

ファイルの外部読み込みから、吐き出しまで

  • 複数の箇所の緯度・経度をデータとして持っている
    • データはjson形式のファイル(lists.json)
  • できれば外部ファイルに書き出して確認したい

上記も含めてコードに落とし込みました。
これを実行すると該当のディレクトリにresults.jsonが吐き出されます。

Node.jsにおける外部ファイルの読み込み、書き出しの説明に関しては割愛します。

index.js
// turf.js
const { point } = require('@turf/helpers')
const distance = require('@turf/distance').default

// 設定ファイルの読み込み
const fs = require('fs');
const util = require('util');
const readFile = util.promisify(fs.readFile);
let results = []

const now = new Date()

const isNumber = (value => {
  return ((typeof value === 'number') && (isFinite(value)));
})

let errorTarget = ''
readFile('lists.json', 'utf-8')
  .then((data) => {
    lists = JSON.parse(data);

    lists.forEach((d, index) => {
      if ((d.LONGITUDE && d.LATITUDE) && (isNumber(d.LONGITUDE) && isNumber(d.LATITUDE))) {
        let pt1 = point([139.766765, 35.681283], { 'name': '東京駅' })
        let pt2 = point([Number(d.LONGITUDE), Number(d.LATITUDE)], { 'name': d.name })

        const result = distance(pt1, pt2, { units: 'kilometers' })
        d.DISTANCE = result
        results.push(d)
      }
    })
  })
  .catch((err) => {
    console.log(err)
    throw err;
  }).finally(() => {
    fs.writeFileSync(`results.json`, JSON.stringify(results, null, '    '));
  })


生成物

最終的に吐き出された生成物は以下です。

results.json
[
    {
        "NAME": "名古屋駅",
        "LATITUDE": 35.170406,
        "LONGITUDE": 136.881695,
        "DISTANCE": 267.50358367757696
    },
    {
        "NAME": "大阪駅",
        "LATITUDE": 34.702485,
        "LONGITUDE": 135.495951,
        "DISTANCE": 403.0278954652313
    }
]

まとめ

初めはgoogleのAPIを有料になってでも叩かないとあかんかなーと思っていたんですが、
意外と簡単にいけてびっくりしました。
公式サイト見る限りかなり多機能なので、他にも活用してみたいものです。

最後まで読んでくださってありがとうございました。

参考

10
8
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
10
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?