
サンプル・プログラム
address2geowin.msi | インストーラ |
bin/address2geowin.exe | 実行プログラム本体 |
bin/libcurl-x64.dll | 実行時に必要になるDLL |
bin/etc/help.chm | ヘルプ・ファイル |
sour/address2geowin.cpp | ソース・プログラム |
sour/resource.h | リソース・ヘッダ |
sour/resource.rc | リソース・ファイル |
sour/application.ico | アプリケーション・アイコン |
sour/mystrings.cpp | 汎用文字列処理関数など(ソース) |
sour/mystrings.h | 汎用文字列処理関数など(ヘッダ) |
sour/pahooGeocode.cpp | 住所・緯度・経度に関わるクラス(ソース) |
sour/pahooGeocode.cpp | 住所・緯度・経度に関わるクラス(ヘッダ) |
sour/apikey.cpp | APIキーの管理(ソース) |
sour/apikey.hpp | APIキーの管理(ヘッダ) |
sour/makefile | ビルド |
使用ライブラリ
リソースの準備
Eclipse を起動し、新規プロジェクト address2geowin を用意する。
ResEdit を起動し、resource.rc を用意する。
Eclipse に戻り、ソース・プログラム "address2geowin.cpp" を追加する。
リンカー・フラグを -mwindows -static -lstdc++ -lgcc -lwinpthread -lcurl -lssl -lole32 "C:\pleiades\eclipse\mingw\mysys2\mingw32\bin\libcurl.dll" に設定する。

MSYS2 コマンドラインからビルドするのであれば、"makefile" を利用してほしい。
解説:定数など
  34: // 定数など ==================================================================
  35: #define MAKER "pahoo.org" //作成者
  36: #define APPNAME "address2geowin" //アプリケーション名
  37: #define APPNAMEJP "住所などから緯度・経度を求める"
  38: //アプリケーション名(日本語)
  39: #define APPVERSION "1.1.1" //バージョン
  40: #define APPYEAR "2020-22" //作成年
  41: #define REFERENCE "https://www.pahoo.org/e-soul/webtech/cpp01/cpp01-14-01.shtm" // 参考サイト
  42:
  43: //ヘルプ・ファイル
  44: #define HELPFILE ".\\etc\\help.chm"
  45:
  46: //デフォルト保存ファイル名
  47: #define SAVEFILE "address2geowin.txt"
  48:
  49: //現在のインターフェイス
  50: HINSTANCE hInst;
  51:
  52: //アプリケーション・ウィンドウ
  53: HWND hParent;
  54:
  55: //アプリケーション・ウィンドウ位置
  56: unsigned hParent_X, hParent_Y;
  57:
  58: //検索キー格納用
  59: string Query;
  60:
  61: //エラー・メッセージ格納用【変更不可】
  62: string ErrorMessage;
  63:
  64: //UserAgent
  65: string UserAgent;
  66:
  67: //pahooGeocodeオブジェクト
  68: pahooGeocode *pGC;
解説:クラス
今回は、WebAPIにアクセする処理を pahooGeocode クラス としてコーディングした。ソースは "pahooGeocode.cpp" ヘッダは "pahooGeocode.hpp" である。
  33: /**
  34: * コンストラクタ
  35: * @param string appname アプリケーション名
  36: */
  37: pahooGeocode::pahooGeocode(std::string appname) {
  38: pahooGeocode::getMyPath(appname.c_str());
  39: pahooGeocode::readGoogleApiKey();
  40: pahooGeocode::readYahooApiKey();
  41: }
  42:
  43: //デストラクタ
  44: pahooGeocode::~pahooGeocode() {
  45: }
ここでは、GoogleAPIキーやYahoo!アプリケーションIDの読み込みを行う。
このデストラクタは何もしない。
解説:住所検索サービスAPI
値 | サービス名 | メソッド | 制 約 |
---|---|---|---|
1 | getPointsGoogle | 有料(決められた無料枠あり)。全世界の住所、ランドマークの検索可能。 | |
2 | Yahoo!JAPAN | getPointsYOLP | 無料(?)。住所、ランドマーク、海外のどれを検索するか指定。ランドマークや海外地名検索はGoogleに劣る。 |
11 | HeartRails Geo API | getPointsHRG | 無料。住所、または住所の一部のみ検索可能。 |
12 | OSM Nominatim Search API | getPointsNominatim | 無料。全世界の住所、ランドマークの検索可能。精度はGoogleに劣る。 |
 679: /**
 680: * ジオコーダAPI を用いて検索キーワードから緯度・経度を求める
 681: *
 682: * @param wstring query 検索キーワード
 683: * 郵便番号表記 ###-####または#######(半角数字)
 684: * 緯度・経度表記 E##.##.##.#N###.##.##.#(半角数字)
 685: * 緯度・経度表記 ##.##,###.##(緯度,経度;半角数字)
 686: * @param string ua UserAgent
 687: * @param int api 0:APIを自動選定(省略時)
 688: * 1:Google Geocoding API
 689: * 2:Yahoo!ジオコーダAPI
 690: * 11:HeartRails Geo API
 691: * 12:OSM Nominatim Search API
 692: * @return int ヒットした地点数
 693: */
 694: int pahooGeocode::searchPoints(wstring query, string ua, int api=0) {
 695: static int apilist[] = { 1, 2, 11, 12 };
 696: int cnt;
 697: wsmatch mt1;
 698: //郵便番号パターン
 699: wregex re01(_SW("([0-9]{3})\\-?([0-9]{4})"));
 700: //緯度・経度パターン
 701: wregex re11(_SW("(E|e|W|w|N|n|S|s)([0-9]+)\\.([0-9]+)\\.([0-9]+\\.?[0-9]*)(E|e|W|w|N|n|S|s)([0-9]+)\\.([0-9]+)\\.([0-9]+\\.?[0-9]*)"));
 702: wregex re12(_SW("(E|e|W|w|N|n|S|s)([0-9]+\\.?[0-9]*)(E|e|W|w|N|n|S|s)([0-9]+\\.?[0-9]*)"));
 703: wregex re13(_SW("(\\+|\\-)*([0-9]+\\.?[0-9]*)\\s*,\\s*(\\+|\\-)*([0-9]+\\.?[0-9]*)"));
 704:
 705: //配列の初期化
 706: for (int i = 0; i <__SIZE_PPOINTS; i++) {
 707: this->Ppoints[i].longitude = 0;
 708: this->Ppoints[i].latitude = 0;
 709: this->Ppoints[i].address = L"";
 710: }
 711:
 712: //郵便番号かどうか
 713: if (regex_search(query, mt1, re01)) {
 714: cnt = this->getPointsHRG_postal(_WS(mt1[1].str() + mt1[2].str()), ua);
 715:
 716: //緯度・経度表記かどうか
 717: } else if (regex_search(query, mt1, re11)) {
 718: cnt = 0;
 719: string s1 = _WS(mt1[1].str());
 720: string s2 = _WS(mt1[5].str());
 721: double d1 = stod(mt1[2].str()) + stod(mt1[3].str()) / 60 + stod(mt1[4].str()) / (60 * 60);
 722: double d2 = stod(mt1[6].str()) + stod(mt1[7].str()) / 60 + stod(mt1[8].str()) / (60 * 60);
 723: if ((s1 == "E") || (s1 == "e")) {
 724: this->Ppoints[cnt].longitude = d1;
 725: } else if ((s1 == "S") || (s1 == "s")) {
 726: this->Ppoints[cnt].longitude = -d1;
 727: } else if ((s1 == "N") || (s1 == "n")) {
 728: this->Ppoints[cnt].latitude = d1;
 729: } else if ((s1 == "S") || (s1 == "s")) {
 730: this->Ppoints[cnt].latitude = -d1;
 731: }
 732: if ((s2 == "E") || (s2 == "e")) {
 733: this->Ppoints[cnt].longitude = d2;
 734: } else if ((s2 == "S") || (s2 == "s")) {
 735: this->Ppoints[cnt].longitude = -d2;
 736: } else if ((s2 == "N") || (s2 == "n")) {
 737: this->Ppoints[cnt].latitude = d2;
 738: } else if ((s2 == "S") || (s2 == "s")) {
 739: this->Ppoints[cnt].latitude = -d2;
 740: }
 741: cnt++;
 742: } else if (regex_search(query, mt1, re12)) {
 743: cnt = 0;
 744: string s1 = _WS(mt1[1].str());
 745: string s2 = _WS(mt1[3].str());
 746: double d1 = stod(mt1[2].str());
 747: double d2 = stod(mt1[4].str());
 748: if ((s1 == "E") || (s1 == "e")) {
 749: this->Ppoints[cnt].longitude = d1;
 750: } else if ((s1 == "S") || (s1 == "s")) {
 751: this->Ppoints[cnt].longitude = -d1;
 752: } else if ((s1 == "N") || (s1 == "n")) {
 753: this->Ppoints[cnt].latitude = d1;
 754: } else if ((s1 == "S") || (s1 == "s")) {
 755: this->Ppoints[cnt].latitude = -d1;
 756: }
 757: if ((s2 == "E") || (s2 == "e")) {
 758: this->Ppoints[cnt].longitude = d2;
 759: } else if ((s2 == "S") || (s2 == "s")) {
 760: this->Ppoints[cnt].longitude = -d2;
 761: } else if ((s2 == "N") || (s2 == "n")) {
 762: this->Ppoints[cnt].latitude = d2;
 763: } else if ((s2 == "S") || (s2 == "s")) {
 764: this->Ppoints[cnt].latitude = -d2;
 765: }
 766: cnt++;
 767: } else if (regex_search(query, mt1, re13)) {
 768: cnt = 0;
 769: string s1 = _WS(mt1[1].str());
 770: string s2 = _WS(mt1[3].str());
 771: double d1 = stod(mt1[2].str());
 772: double d2 = stod(mt1[4].str());
 773: if ((s1 == "") || (s1 == "+")) {
 774: this->Ppoints[cnt].latitude = d1;
 775: } else if (s1 == "-") {
 776: this->Ppoints[cnt].latitude = -d1;
 777: }
 778: if ((s2 == "") || (s2 == "+")) {
 779: this->Ppoints[cnt].longitude = d2;
 780: } else if (s2 == "-") {
 781: this->Ppoints[cnt].longitude = -d2;
 782: }
 783: cnt++;
 784:
 785: //APIを自動選定
 786: } else if (api == 0) {
 787: for (int api : apilist) {
 788: this->resetError();
 789: cnt = this->__searchPoints(query, ua, api);
 790: if (cnt > 0) break;
 791: }
 792: //API指定
 793: } else {
 794: cnt = this->__searchPoints(query, ua, api);
 795: }
 796:
 797: return cnt;
 798: }
自動選定の順序は、上表にしたがう。GoogleAPIキーやYahoo!アプリケーションIDが未登録の場合は、これらの呼び出しをスキップする。また、そのWebAPIを利用することができなかったり、検索結果がゼロだった場合は、次点のサービスを自動的に呼び出す。
参考サイト
- PHPで住所・ランドマークから緯度・経度を求める:ぱふぅ家のホームページ
- PHPでクラスを使ってテキストの読みやすさを調べる:ぱふぅ家のホームページ
- PHPで住所から緯度・経度を求める(Windowsアプリ版):ぱふぅ家のホームページ
- WiX によるWindowsインストーラー作成:ぱふぅ家のホームページ
- C++ 開発環境の準備:ぱふぅ家のホームページ
- デジタルスチルカメラ用画像ファイルフォーマット規格 Exif 2.3:カメラ映像機器工業会規格
「PHPで住所・ランドマークから緯度・経度を求める」で作ったPHPプログラムをC++に移植したものである。
(2022年11月20日)使用ライブラリをバージョンアップ
(2022年9月19日)UserAgent追加,各種パラメータの保存.