緯度経度やGeo3x3の用に、地球上の場所を表す方法「ジオコードシステム」はいろいろあります。地理院地図でも参照可能な「場所情報コード/uPlace」を調べて実装、緯度経度地図に組み込みました。

緯度経度地図
マップを動かすとリアルタイムに緯度経度、Geo3x3、uPlaceが変わります。uPlaceは約3m単位で論理場所情報コードで表示しています。Geo3x3はこの地図での細かさに合わせてlevel20としています。

uPlace 場所情報コードは2種類あります。
1. シリアル付き場所情報コード、細かい緯度経度と所有者をデータベースに登録申請できます
2. 論理場所情報コード、申請不要で緯度経度と高さ情報で生成できます(精度約3m)

ブラウザとDenoで使えるESモジュールとして実装したので、下記のように簡単にエンコード、デコード可能です。(src on GitHub)

import { uPlace } from "https://taisukef.github.io/uPlace/uPlace.js"; const code = "00001B000000000309DF3925687B1D00"; const pos = uPlace.decode(code); console.log(pos); const code2 = uPlace.encode(35.942729, 136.198835, 8); // めがね会館8F console.log(code2);

3m精度で建物の階数指定できるので郵便や配達などにも便利そうです。

uPlaceは128bit/16byte/16進法32文字の ucode system の一種。 場所情報コードの仕様書を元に実装し、deno test でテストできるテストコード uPlace.test.js も書いたので割とちゃんと動きます。 (参考、テスト駆動開発(TDD)で安心、JavaScriptプログラミング!Denoでwebアプリ開発編

下記、uPlace.js内デコードする部分のJavaScriptのコードです。JavaScriptでのビット演算は32bitまでなので、緯度経度部分を分割するひと手間かけてます。

const decode = (code) => { if (!code || typeof code != "string" || code.length != 32) { throw new Error("not a ucode (hex encoded 32byte str)"); } const version = parseInt(code.substring(0, 1), 16); const tldcode = parseInt(code.substring(1, 1 + 4), 16); const classcode = parseInt(code.substring(1 + 4, 1 + 4 + 1), 16); const dc = parseInt(code.substring(1 + 4 + 1, 1 + 4 + 1 + 10), 16); const ic1 = parseInt(code.substring(1 + 4 + 1 + 10, 1 + 4 + 1 + 10 + 8), 16); const ic2 = parseInt(code.substring(1 + 4 + 1 + 10 + 8), 16); //console.log(version, tldcode, classcode, dc, ic1.toString(16), ic2.toString(16)); // .toString(16), ic) if (version != 0 || tldcode != 1 || classcode != 11 || dc != 3) { throw new Error("not a uPlace"); } const type = ic1 >>> (62 - 32); if (type != 0) { throw new Error("only supported type is 0"); } const south = (ic1 >> (61 - 32)) & 1; const latsec = (ic1 >> (1 + 23 + 8 + 1 + 6 - 32)) & 0x3fffff; // 22bit const west = (ic1 >> (23 + 8 + 1 + 6 - 32)) & 1; const lngsec = (((ic1 & 0x3f) << 17) | ((ic2 >>> (8 + 1 + 6)))) & 0x7fffff; // 23bit const levelx = (ic2 >> (1 + 6)) & 0xff; const level = levelx >= 0xfe ? levelx : levelx - 50; const levelmid = (ic2 >> 6) & 1; const serial = ic2 & 0x3f; const lat = latsec / (10 * 60 * 60) * (south ? -1 : 1); const lng = lngsec / (10 * 60 * 60) * (west ? -1 : 1); if (lat < -90 || lat > 90 || lng < -180 || lng > 180) { throw new Error("out of the earth"); } // console.log(type, south, latsec, lat, west, lngsec, lng, level, levelmid, serial); return { lat, lng, level, levelmid, serial }; };

32文字の固定長で長いプリフィックスがあるので、他のコードと間違いにくいところが結構いい感じです。 大まかに示したり、より高い精度で示すことはできないので、そんな場合はGeo3x3が便利です。 位置情報、DXしましょう!

2021/5/12、UNVT(国連ベクトルタイル)ワークショップ日本語版開催!
UNVTワークショップ日本語版 公開録画 | 512

古くは歩いて測量して回って作った地図。衛星によって大きく飛躍しましたが遠い存在になってしまった地図作り。手軽なドローンによって、また我々の手に戻ってきました。


武生中央公園 だるまちゃん広場 - VRふくい
いい時代ですね!


VRふくい
地理院地図の航空写真で見てみると、昔は球場だったことが分かります。Googleマップで見てみると建築中。地図は生き物、どんどんアップデートが必要です。 地元の地図は地元で創りましょう!

それにしても気持ちよく動いてくれますね!その秘密はGPU。CPUの高速化だけでは追いつかない大容量データの処理に活躍しているのはゲーム技術で培われた並列計算ハードウェアの発展によって、3Dを計算するための多量な計算を瞬時にやってくれます。

その速さを体験すべく、有名なマンデルブロの演算で見てみましょう。


mandelbrot-js by CPU
HTML5(JavaScript)で描くマンデルブロ集合」を元に高精細なCanvasで描画してみました。計算、がんばってる感ありますね。これがCPUのみの力で動かすマンデルブロ集合。


mandelbrot-js by GPU
Rendering the Mandelbrot Set With WebGL」こちらをベースに高精細化。クリックすると拡大、右クリックで縮小します。速い!

links
- オープンソースプロジェクト「Adopt Geodata」へ開発参画で国連貢献!? CSVと3D地図で語るVRふくい

Facebookで面白い地図アプリを発見「筑波研究学園都市内の公園」。 国土地理院の藤村さんによる「Adopt Geodata プロジェクト」の一環とのこと。 滑らかに動く3D地図を背景に、その場所の情報がすっと入ってくる。

筑波研究学園都市内の公園

こんなステキなことが簡単にできるとは! 気軽に共同開発できるプラットフォーム、GitHubを使った新たなオープンソースソフトウェア(OSS)プロジェクトだったので早速開発に参画。 HTML内のテキストデータを編集するだけで誰でも簡単にステキな地図で語れるようにすることに貢献。


Code for Japan 代表、関さんも参戦!Google Spreadsheetに対応!

TSVなどの外部ファイルに対応しては?というアイデアを元にひとまずCSV/YMLに対応、プルリク(プログラムの改善提案)をしたところサクッと承認され、貢献完了。 多くの人ががっつり使うオープンソースプロジェクトの場合、仕様の検討も、テストも入念にしたいところですが、このような若くて気軽なプロジェクトもありますよ。

藤村英範さんは、かんたん地図ライブラリ egmapjs でもお世話になっている国土地理院の中の人であり、国連の人!

ベクトルタイルを通じた国連貢献へのお誘い
日本がイニシアチブを取って進む新しい地図プロジェクト、もっと貢献できることがあるかもしれません。
「国連ベクトルタイルツールキット」で各国の地図配信を支援、国土地理院 藤村英範氏によるトークセッション開催(「mapbox/OpenStreetMap meetup」第4回レポート) │ GeoNews


ベクトル地図といえば、福井高専在学中のバイトの中心だった地図づくり。CDに入ったベクトルデータを変換してJavaアプレットで動く地図プロジェクト「Atlantis(コードネーム Mappilla)」を思い出す。


VRふくい
最近お気に入りの空飛ぶ一眼を使った360度写真オープンデータ。リスト表示を改め、地図語りバージョンをトップページとしました。 建物のローポリゴン3Dがオシャレですね!お手軽個人空撮オープンデータと地理院のベクトルタイル地図との合成すれば、テクスチャーマッピングも可能かも!?

CSVファイルでまとめて、HTMLを書くだけ!(csvファイル外部読み込みはローカルのファイルでは動きません。liveserverなどwebサーバーを起動するか、サーバーに転送して動かしましょう)

高専生の頃関わった1997年から24年。再び地図がおもしろい!現役高専生の参戦も大歓迎!

日本のステキを写真で集める「FIND/47」のデータは用途制限なく自由に使える、CC BYのオープンデータ。

FIND/47|みんなで集め、広めていくフォトアーカイブ。
現在1,299枚の47都道府県の高品質画像が最大1900万画素で使用可能。どの写真も美しい!

サイト自体もCC BY、一覧を取得する images.json と、サイトのHTMLを使って、CSVオープンデータとして整理するプログラムをJavaScript(Deno)で作って、GitHub公開。 ついでに、フルHD品質画像をダウンロードして、GitHub Pagesでホスティング。一括ダウンロードしてあれこれ活用する元ができました。(src on GitHub)

find47images.csv
画像URL、FIND/47での詳細リンク、タイトル、使用カメラやレンズ、焦点距離などの情報に加え、全データ位置情報付き!Geo3x3にエンコードして整理しました。


日本の風景オープンデータ
作ったCSVオープンデータを使ったサンプルアプリ、シャッフルして0.5秒ずつ並べていくだけのアプリです。JavaScriptのプログラムはこんな感じ。(src on GitHub

import { CSV } from "https://code4sabae.github.io/js/CSV.js"; import { sleep } from "https://js.sabae.cc/sleep.js"; import { shuffle } from "https://js.sabae.cc/shuffle.js"; window.onload = async () => { const url = "https://code4fukui.github.io/find47/find47images.csv"; const data = CSV.toJSON(await CSV.fetch(url)); console.log(data); shuffle(data); for (const d of data) { const imga = document.createElement("a"); imga.href = d.url; const img = new Image(); img.src = "https://code4fukui.github.io/find47/photo/" + d.id + ".jpg"; imga.appendChild(img); images.appendChild(imga); const a = document.createElement("a"); a.href = d.url; a.textContent = d.title + " © " + d.author; credits.appendChild(a); await sleep(500); } };

プログラムでHTMLの要素を生成しています。

これだけ美しい素材、日本中まるっと揃っているとうれしいですね!

うちの地元のあの風景がない!?
FIND/47では、投稿も受け付けています。自慢の写真、オープンデータにしましょう!


SABAE signboard
福井県の空からの360度写真オープンデータ「VRふくい」に「鯖江大看板」追加!
こちらも日本中、世界中に拡大できると楽しそう。

緯度、経度、精度、3つの値を1つのコードで表現する、パブリックドメインなジオコーディング「Geo3x3」の76コ目の実装プログラミング言語として、THPL対応!

Geo3x3 README.md

THPLとは、The HTML Programming Language、プログラミング言語としてのHTML。先日、エンコードを実装しましたが、THPLの言語自体に機能を足してデコードも実装。正式対応とすることができました。

足した機能は1つだけ、文字列から指定した場所の文字コードを取得する string/charCodeAt という機能。当初、簡単だったので、他の演算子と同様 math タグ内のエレメントとしての実装してプルリクしましたが、HTML標準から外れるということで、ご提案いただいた q タグによる実装に切り替えました。
add math.charCodeAt by taisukef · Pull Request #2 · uhyo/the-html-programming-language

オープンソースソフトウェア(OSS)のプログラミング言語は、言語自体を改造できるだけでなく、言語開発自体に貢献できるのがステキですね。

THPLは、TypeScriptで書かれたシンプルなプログラミング言語なので、プログラミング言語づくりの参考にもいい感じです。npm run build のコンパイル時間も30ミリ秒ほどと高速です!(liveserverと組み合わせればブラウザ上でのテストも簡単!)

今回の改造手順
1. THPLをフォーク
2. 抽象構文木(AST)式(expression.ts)に、QExpression/qExpressionを追加。
3. 構文解析器(パーサー)parseExpression.tsに、Qタグとciteプロパティ対応を追加。
4. インタプリタrunExpression.tsQExpressionへの対応と string/charCodeAt 処理を追加。
5. としてtest-charCodeAt.htmlを追加(ブラウザで動きます)。
6. プルリク

THPLにマージされたわけではありませんが、フライングでGeo3x3のTHPL対応としました。
taisukef/Geo3x3: geo zone encoding, serialize latitude and longitude

自作言語をお持ちの方、Geo3x3実装チャレンジしてみてください!

HTMLは、コンピューター言語ですが、プログラミング言語ではありません。

という定説を覆す記事。
「HTMLはプログラミング言語か」問題に終止符を打つ - Qiita
見事にHTMLがプログラミング言語になっていました。


The HTML Programming Language (THPL) を使って、緯度経度の表現 Geo3x3 のエンコードをHTMLで実装してみました。

HTMLはその仕様を自由に提案することができ、いろんな提案によって今日のHTMLがあります。 なので、HTMLが一般的にプログラミング言語と呼ばれる日が来る可能性も十分にあるわけです。

下記が、Geo3x3_encode.thpl.html 全文。Math.floorがないので、除算と引き算を使った関数 floor を定義し、文字列演算がないので、数を10倍しながらエンコードしています。 デコード処理を実現するには、文字列系の関数をいくつかTHPLに足す必要がある気がします。(src on GitHub)

<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width"> <title>Geo3x3_encode in THPL</title> <script src="https://unpkg.com/the-html-programming-language@0.1.0/browser.min.js"></script> </head> <body> <section title="floor"> <footer> <abbr><math><minus/></math><br> <slot></slot><br> <abbr><math><rem/></math><br><slot></slot><br>1</abbr> </abbr> </footer> </section> <section title="encode_loop"> <dl> <dt>lat</dt><dd><slot name="0"></slot></dd> <dt>lng</dt><dd><slot name="1"></slot></dd> <dt>level</dt><dd><slot name="2"></slot></dd> <dt>unit</dt><dd><slot name="3"></slot></dd> <dt>res</dt><dd><slot name="4"></slot></dd> </dl> <dl> <dt>x</dt><dd><abbr title="floor"><abbr><math><divide/></math><br><var>lng</var><br><var>unit</var></abbr></abbr></dd> <dt>y</dt><dd><abbr title="floor"><abbr><math><divide/></math><br><var>lat</var><br><var>unit</var></abbr></abbr></dd> <dt>n</dt><dd><abbr><math><plus/></math><br><var>x</var><br><abbr><math><times/></math><br><var>y</var><br>3</abbr><br>1</abbr></dd> </dl> <footer> <meter><var>level</var></meter> <ruby> <meter>1</meter> <rt><var>res</var></rt> <rt> <abbr title="encode_loop"> <abbr><math><minus/></math><br> <var>lat</var><br> <abbr><math><times/></math><br><var>y</var><br><var>unit</var></abbr> </abbr><br> <abbr><math><minus/></math><br> <var>lng</var><br> <abbr><math><times/></math><br><var>x</var><br><var>unit</var></abbr> </abbr><br> <abbr><math><minus/></math><br> <var>level</var><br> <meter>1</meter> </abbr><br> <abbr><math><divide/></math><br> <var>unit</var><br> <meter>3</meter> </abbr><br> <abbr><math><plus/></math><br> <abbr><math><times/></math><br><var>res</var><br>10</abbr><br> <var>n</var> </abbr> </abbr> </rt> </ruby> </footer> </section> <section title="encode"> <dl> <dt>lat</dt><dd><slot name="0"></slot></dd> <dt>lng</dt><dd><slot name="1"></slot></dd> <dt>level</dt><dd><slot name="2"></slot></dd> </dl> <dl> <dt>flg</dt><dd><abbr><math><lt/></math><br><var>lng</var><br>0</abbr></dd> <dt>lat</dt><dd><abbr><math><plus/></math><br><var>lat</var><br>90</abbr></dd> <dt>lng</dt><dd><var>flg</var><ruby> <meter>1</meter><rt><abbr><math><plus/></math><br><var>lng</var><br>180</abbr></rt> <rt><var>lng</var></rt></ruby></dd> <dt>prefix</dt><dd><var>flg</var><ruby><meter>1</meter><rt>W</rt><rt>E</rt></ruby></dd> </dl> <footer> <var>prefix</var> <abbr title="encode_loop"><var>lat</var><br><var>lng</var><br><var>level</var><br>60<br>0</abbr> </footer> </section> <p><output><abbr title="encode">35.65858<br/>139.745433<br/>14</abbr><wbr></output></p> <p><output><abbr title="encode">35.65858<br/>-139.745433<br/>14</abbr><wbr></output></p> </body> </html>

ちなみに、JavaScriptでの実装はこちら。

const encode = (lat, lng, level) => { let res = "E"; if (lng < 0.0) { res = "W"; lng += 180.0; } lat += 90.0; let unit = 180.0; for (let i = 1; i < level; i++) { unit /= 3.0; const x = Math.floor(lng / unit); const y = Math.floor(lat / unit); res += x + y * 3 + 1; lng -= x * unit; lat -= y * unit; } return res; }; console.log(encode(35.65858, 139.745433, 14)); console.log(encode(35.65858, -139.745433, 14));

いろんなプログラミング言語を見たい方は、こちら75言語で実装した「Geo3x3」をご覧ください。 おなじみC言語から、Scratch、関数型言語の代表LISPなど、違いをいろいろと楽しめますよ。

鳴かぬなら、鳴くのを創ろう!

日本生まれのプログラミング言語といえば Ruby
Swift, Elixir, Scala, Crystal, Groovy, D言語など、さまざまな新しい誕生する言語にも影響を与えています。


Geo3x3 in HSP
高専生にプログラミングをはじめたきっかけの言語として聞く、HSP (Hot Soup Processor) で、Geo3x3にて実装してみました。(src on GitHub)

#defcfunc gex3x3_encode double lat, double lng, int level if level < 1 { Return "" } if lng < 0 { res = "W" flng = lng + 180.0 } else { res = "E" flng = lng } flat = lat + 90.0 unit = 180.0 repeat level - 1 unit = unit / 3.0 x = int(flng / unit) y = int(flat / unit) n = x + y * 3 + 1 res = res + n flng = flng - double(x) * unit flat = flat - double(y) * unit loop return res

if文はカッコ、ループはend式なのがユニーク。

Ruby版と比較してみましょう。(src on GitHub)

module Geo3x3 module_function def encode(lat, lng, level) raise ArgumentError if level < 1 lat = lat.to_f lng = lng.to_f if lng >= 0 result = "E" else result = "W" lng += 180 end lat += 90 unit = 180.0 (level - 1).times do unit /= 3 x = (lng / unit).to_i y = (lat / unit).to_i result << "#{x + y * 3 + 1}" lng -= x * unit lat -= y * unit end result end

こちら国産言語、Kuinでの実装 (src on GitHub)

+func encode(lat: float, lng: float, level: int): []char var result: []char if(level < 1) do result :: "" ret result end if if(lng >= 0.0) do result :: "E" else do result :: "W" do lng :+ 180.0 end if do lat :+ 90.0 {180:the North Pole, 0:the South Pole} var unit: float :: 180.0 var i: int :: 1 var array: []char while(i < level) do unit :/ 3.0 var x: int :: (lng / unit) $ int var y: int :: (lat / unit) $ int do array :: "\{x + y * 3 + 1}" do result :: result ~ array do lng :- x $ float * unit do lat :- y $ float * unit do i :+ 1 end while ret result end func

こちらはend式。プログラミング言語で独特な使い方になり勝ちな「=」を代入では使わず、「:」としています。

日本語プログラミング言語のなでしこ3での実装。(src on GitHub)

●(緯度と、経度を、レベルで)Geo3x3エンコードとは もし、(経度>=0.0)ならば コード="E" 違えば コード="W" 経度=経度+180 ここまで。 緯度=緯度+90 ユニット=180 (レベル-1)回 ユニット=ユニット/3 X=INT(経度/ユニット) Y=INT(緯度/ユニット) コード=コード&(X+Y*3+1) 経度=経度-X*ユニット 緯度=緯度-Y*ユニット ここまで コードを戻す ここまで

おもしろいのは関数の呼び出し方。日本語っぽい書き方で取得できます。

35.65858と139.745433を14でGeo3x3エンコードして表示

ASCIIコードが基本だった昔と違ってユニコード時代。JavaScriptなど多くの言語で日本語の関数名や変数名が使えます。

class Geo3x3 { static エンコード(緯度, 経度, レベル) { if (レベル < 1) { return null; } if (typeof 緯度 == "string") { 緯度 = parseFloat(緯度); } if (typeof 経度 == "string") { 経度 = parseFloat(経度); } let コード = "E"; if (経度 < 0.0) { コード = "W"; 経度 += 180.0; } 緯度 += 90.0; // 180:the North Pole, 0:the South Pole let ユニット = 180.0; for (let i = 1; i < レベル; i++) { ユニット /= 3.0; const x = Math.floor(経度 / ユニット); const y = Math.floor(緯度 / ユニット); コード += x + y * 3 + 1; 経度 -= x * ユニット; 緯度 -= y * ユニット; } return コード; }

英単語で記述し、読むときだけ日本語になってくれるプログラミング言語やエディタの支援とかもいいかもしれません。

Geo3x3にうれしいお知らせ!
地球規模で行われる宝探し「ジオキャッシング」用のお助けアプリ「GC Wizard」の緯度経度変換の1つとしてGeo3x3を追加いただきました!

Search · Geo3x3 / S-Man42/GCWizard
Flutter/Dartで実装されている GC Wizard、GitHubにて、Geo3x3追加に関する変更履歴を見ることができます。 作っててよかった Dart版

class Geo3x3 { static String encode(num lat, num lng, num level) { if (level < 1) { return ""; } var res = ""; var lng2 = lng; if (lng >= 0) { res = "E"; } else { res = "W"; lng2 += 180; } var lat2 = lat + 90.0; var unit = 180.0; for (int i = 1; i < level; i++) { unit /= 3; final x = (lng2 / unit).toInt(); final y = (lat2 / unit).toInt(); res += (x + y * 3 + 1).toString(); lng2 -= x * unit; lat2 -= y * unit; } return res; }

Geo3x3の応用例としてご紹介するので、使われた方ぜひご一報ください。

3x3の領域で再帰的に分割する「Geo3x3」のいいところは、単純な前方一致で絞り込めるところ。

例えば、東京タワーのGeo3x3 E9139659937288 は、東京都港区あたりのメッシュ E913965 で始まります。 周辺を含めるときは1桁削って1から9を足すだけ。地球上、どの場所でも使えます。

緯度経度を持つ多量のデータから検索すると言えばデータベース。 select文でおなじみSQL(エスキューエル)は、主にデータベースからデータを取得するためのクエリー言語として使いますが、プログラムを組み込むことができるので、プログラミング言語でもあります。 ただし、標準化がちょっと遅かったせいで、データベースによって方言があります。

オープンソースでフリーで使える有名2大データベース、PostgreSQLMariaDB(MySQL互換)に対応しました。

Geo3x3 対応言語、58!

こちらがPostgreSQLのGeo3x3のエンコードのストアドファンクション(データベースに組み込めるストアドプロシージャーの関数版) src on GitHub

create or replace function Geo3x3_encode(lat real, lng real, level int) returns text as $$ declare result text; i int = 1; unit real = 180.0; x int = 0; y int = 0; begin if lng >= 0.0 then result = 'E'; else lng = lng + 180.0; result = 'W'; end if; lat = lat + 90.0; while i < level loop unit = unit / 3.0; x = floor(lng / unit); y = floor(lat / unit); result = concat(result, x + y * 3 + 1); lng = lng - x * unit; lat = lat - y * unit; i = i + 1; end loop; return result; end; $$ language plpgsql;

結構、普通に書けますね!

select Geo3x3_encode(35.65858, 139.745433, 14);

このように、select文内で利用できます。
エンコードは両SQLにあまり差はありませんが、緯度、経度、レベル、範囲を返すデコードの実装はまとめて値を返せるPostgreSQLとOUTを使って参照変数で返すMariaDB版(src on GitHub)とでちょっと違います。

問題、この言語は何でしょう?

module geo3x3 implicit none contains character(50) function geo3x3_encode(lat, lng, level) real lat real lng integer level real flat real flng real unit integer i, x, y flat = lat flng = lng if (lng >= 0.0) then geo3x3_encode = "E" else geo3x3_encode = "W" flng = flng + 180.0 end if flat = flat + 90.0 unit = 180.0 do i = 1, level - 1 unit = unit / 3 x = floor(flng / unit) y = floor(flat / unit) geo3x3_encode(i + 1: i + 1) = char(x + y * 3 + 1 + 48) flng = flng - x * unit flat = flat - y * unit end do end end

使う変数を関数の先頭で定義する感じがSQLと似てますね。 正解は1954年生まれ、高級言語のご先祖様、Fortran(フォートラン)! C言語も昔はこんな書き方してました。 なんと、スパコンの世界ではC++と並んで現役言語とか!
スパコンプログラマ日常 ~スパコンを使うのって難しいの?~ 東京大学物性研究所 物質設計評価施設 渡辺宙志

数値計算と言えば、名前は見たことあるMATLABとそのオープンソース版であるOctaveにも対応!
taisukef/Geo3x3: geo zone encoding, serialize latitude and longitude
プログラミング言語を巡る旅は続きます。

IchigoJamで4万を超える大きな数を扱う実験をしたので、緯度経度を1つのコードに変換するGeo3x3に対応しました。

北緯35.65858東経139.745433という緯度経度データと、E9139659937288という1つの文字列で表すGeo3x3(ジオ・スリーバイスリー)との相互変換をIchigoJamだけでできます!


IchigoJam R と IchigoJam S で実行している様子。Rだとエンコードとデコードがそれぞれ4秒/3秒、Sで30秒/17秒、がんばって変換している様子がかわいいですね!SでもVIDEO0を使うと3倍速になるので、悪くない速度です。

今回扱う緯度経度は360を超えないので、正数部を3桁、小数部を17桁とする20桁の固定小数として扱うことにしました。102コの配列を使って5つの固定小数を変数として保持します。 A,B,Cで変数を指定して呼び出すプログラムを作ってGSB(ゴーサブ)で呼び出す形にするとスッキリ書けます。

足し算(@ADD)、引き算(@SUB)、表示(@SHOW)、一桁の掛け算(@XMUL)、一桁の割り算(@XDIV)、割り算(@DIVX)、コピー(@A2B)をまとめました(プログラミングの世界で、ライブラリと呼びます)

100 @ADD:FORI=0TON-1:[C+I]=[A+I]+[B+I]:NEXT:A=C 110 @NORM:FORI=N-1TO1STEP-1:[A+I-1]=[A+I-1]+[A+I]/10:[A+I]=[A+I]%10:NEXT:RTN 150 @SUB:FORI=N-1TO0STEP-1:IF[A+I]<[B+I]&&I>0[A+I-1]=[A+I-1]-1:[A+I]=[A+I]+10 170 [C+I]=[A+I]-[B+I]:NEXT:RTN 200 @SHOW:?[S];[S+1];[S+2];".";:FORI=3TON-1:?[S+I];:NEXT:?:RTN 400 @XMUL:FORI=N-1TO0STEP-1:[A+I]=[A+I]*X:NEXT:GOTO@NORM 450 @XDIV:FORI=0TON-1:D=[A+I]%X:[A+I]=[A+I]/X:IFI<N-1[A+I+1]=[A+I+1]+D*10 460 NEXT:RTN 470 @DIVX:X=0 480 GSB@SUB:IF[C]<0:RTNELSEX=X+1:A=C:CONT 500 @A2B:FORI=0TON-1:[B+I]=[A+I]:NEXT:RTN

N: 桁数を指定
I, D: 内部で使用する

あとは、このライブラリを使ったエンコードとデコードを実装するだけです!

1 'GEO3x3 encode 10 CLV:N=20:L=14 20 LET[20],0,3,5,6,5,8,5,8 25 LET[40],1,3,9,7,4,5,4,3,3 'main 30 LET[0],1,8,0:[21]=[21]+9:A=20:GSB@NORM 35 IF[40]>=0?"E";ELSE?"W";:LET[60],1,8,0:[40]=-[40]:A=60:B=40:C=40:GSB@SUB 40 FORJ=1TOL-1 50 A=0:X=3:GSB@XDIV 60 A=20:B=60:GSB@A2B:A=60:B=0:C=80:GSB@DIVX:Y=X 70 A=40:B=60:GSB@A2B:A=60:B=0:GSB@DIVX 80 ?X+Y*3+1; 90 A=0:B=60:GSB@A2B:A=60:GSB@XMUL:A=40:B=60:C=40:GSB@SUB 95 A=0:B=60:GSB@A2B:A=60:X=Y:GSB@XMUL:A=20:B=60:C=20:GSB@SUB 99 NEXT:?:END

10行でレベル(Geo3x3の桁数)、20行、25行で緯度経度を配列へ設定するとGeo3x3が表示されます。ちょっと読みづらいですが、ライブラリを呼び出してる感が伝わると思います。 アルゴリズム(手順)は同じなので、JavaScript版やその他49言語のと同じなので、見比べてみましょう!(src on GitHub)

こちらはデコードプログラム

1 'GEO3x3 decode 10 CLV:N=20 12 S="E9139659937288" 'main 14 F=ASC(S)=87 16 LET[0],1,8,0 18 FORJ=1TOLEN(S)-1 20 M=ASC(S+J)-49:?M+1 22 X=3:A=0:GSB@XDIV 24 A=0:B=60:GSB@A2B:X=M%3:A=60:GSB@XMUL:B=40:C=40:GSB@ADD 26 A=0:B=60:GSB@A2B:X=M/3:A=60:GSB@XMUL:B=20:C=20:GSB@ADD 28 NEXT 30 X=2:A=0:GSB@XDIV 40 A=0:B=20:C=20:GSB@ADD 50 A=0:B=40:C=40:GSB@ADD 60 LET[80],0,9,0:A=20:B=80:C=20:GSB@SUB 70 IF F LET[80],1,8,0:A=40:B=80:C=40:GSB@SUB 80 S=20:GSB@SHOW:S=40:GSB@SHOW 90 END

どちらのプログラムもライブラリと合わせて1KBに収まっています!
固定小数ライブラリをマシン語化して高速化、効率化してみるのも楽しそう!(Armマシン語入門 / RISC-Vマシン語入門

サポートプログラミング言語、50言語達成!
と思った矢先、なんと、COBOL実装のプルリク
変数の桁数指定や、COMPUTEとEND-COMPUTEで終わる計算がシビレます!

プログラミングの世界は広大ですよ。

10年前は無力でした。

開発現場や技術から離れ、企画、広報、マネジメント寄りだった10年前。未曾有の危機に、何も創れなかった自分が悔して、2011年12月、毎日ひとつ何か作ろうと決め達成。 その勢いで2012年1月1日、一日一創をFacebookで宣言、2013年からブログ化)。 つくり続けて10年目、できることと仲間が増えました。

Code for Japan 代表、関さんのブログ。
sinsai.info からの10年|Hal Seki|note
オープンデータが提唱されたのは2009年、世界にはすでにオープンデータがあったようです。2010年に鯖江市長に話し、実現したのが2012年1月。 震災時のデータ不足の反省が後押しとなりました。

データを利用者に届けるのはアプリ。いかに速く作れるかが勝負です。地図アプリを速く作るためのツール「egmapjs」をよりシンプルにしました。


全1470個所 いしぶみマップ - 京都市オープンデータ x egmapjs
本日、京都からプルリクいただき改善された「京都いしぶみマップ」を、ESモジュール化したegmapjsをベースに書き直し。 CSVオープンデータを読み込み、マーカー表示、Geo3x3を含む詳細表示まで、割と素直なプログラムになっています。

<script type=module> import { initMap, showHere, convertDMS2D } from "https://code4fukui.github.io/egmapjs/egmap.mjs"; import { CSV } from "https://code4sabae.github.io/js/CSV.js"; import { Geo3x3 } from "https://taisukef.github.io/Geo3x3/Geo3x3.mjs"; window.onload = async () => { const map = initMap("mapid"); //const url = "https://data.city.kyoto.lg.jp/file/3969/download?token=Tka3iJPr"; // CORS err const url = "https://code4fukui.github.io/kyotoishibumi/ishibumi-data-281211.csv"; const data = CSV.toJSON(await CSV.fetch(url)); const lls = []; let cnt = 0; for (const c of data) { const d = { num: c["番号"], name: c["名称"], address: c["住所"], lat: c["北緯"], lng: c["東経"], }; if (!d.lat || !d.lng) { console.log("err: " + d.name + ", " + d.address + ", " + d.lat + ", " + d.lng) cnt++ continue } const [lat, lng] = convertDMS2D(d.lat, d.lng); const name = `<a href=https://www2.city.kyoto.lg.jp/somu/rekishi/fm/ishibumi/html/${d.num.toLowerCase()}.html target=_blank rel=noopener>${d.name}</a>`; const geo3x3 = Geo3x3.encode(lat, lng, 16); const geo3x3link = `Geo3x3: <a href=https://code4sabae.github.io/geo3x3-map/#${geo3x3} target=_blank>${geo3x3}</a>`; map.addIcon(lat, lng, [d.num, name, d.address, geo3x3link].join("<br>")); lls.push([lat, lng]); } console.log("緯度経度変換エラー数:" + cnt); map.fitBounds(lls); // 現在位置表示ボタン gotohere.onclick = showHere; }; </script>

いつ起きるかわからない災害。備えは十分とは言えません。
データと活用する力、蓄えておきましょう。

Tweet
クリエイティブ・コモンズ・ライセンス
この作品は「Creative Commons — CC BY 4.0」の下に提供されています。
CC BY / @taisukef / アイコン画像 / プロフィール画像 / RSS