Skip to content

Commit 72d08c5

Browse files
authored
デフォルトサーバーから直接インポートできるようにしました (Synesthesias#146)
* デフォルトURLからメタデータを取得できることのユニットテスト * jsonパースで、問題が起きたときに落ちない例外で済ますために json["key"] を json.at("key") に置き換え * readme追記 * CoordinateSystem.ToNaturalLanguageを追加 * デフォルトURLからファイルをダウンロードできることのテスト * 同上 * CMSサーバーでは Bearer認証が設定されていると逆に認証失敗になるので、その仕様に合わせた * fix mac os test failure * 同上 * サードパーティのライセンス表記と、libplateauのライセンス表記を追加 * 同上 * Create LICENCE.md * fix typo in the readme * Update LICENCE.md * Update LICENCE.md * Update LICENCE.md
1 parent d24abfa commit 72d08c5

File tree

8 files changed

+1692
-35
lines changed

8 files changed

+1692
-35
lines changed

LICENCE.md

Lines changed: 514 additions & 0 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ Windows, Mac, Linux でのテストと成果物のダウンロードができま
161161
- Unreal Engine で利用する都合上、ヘッダーファイルで `std::filesystem` は利用しない
162162
- .cppファイル内での利用は可
163163
- パスの受け渡しは string(中身はutf8形式) で行い、`.cpp`内で `auto path = std::filesystem::u8path(path_str)` で path に直すのが良い
164+
- コンテナ要素へのアクセスは `[i]` ではなく `.at(i)` を用いる。Unityからの利用で範囲外アクセスになったとき、前者は例外も出さずに問答無用でUnityが落ちる。後者は例外として補足できる。
164165

165166
# トラブルシューティング
166167
- **Q.** 手元のマシンではユニットテストが通るのに、CIサーバーの自動テストが通りません。
@@ -172,6 +173,14 @@ Windows, Mac, Linux でのテストと成果物のダウンロードができま
172173

173174

174175
# ライセンス
176+
## ライセンス制約
177+
libcitygml は LGPL ライセンスのため、libcitygml と静的リンクする libplateau にも LGPLライセンスが伝播します。
178+
したがって、このリポジトリはLGPLライセンスで公開しなければなりません。
179+
なお、libplateauと動的リンクする PLATEAU SDK for Unity には LGPLライセンスは伝播しません。
180+
181+
## ライセンス管理
182+
サードパーティソフトの権利表記を ThirdPartyNotices.md に記載してください。
183+
175184
- libplateau本体
176185
- 未定
177186

ThirdPartyNotices.md

Lines changed: 1059 additions & 0 deletions
Large diffs are not rendered by default.

include/plateau/network/client.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ namespace plateau::network {
4848
/**
4949
* @param server_url 接続先のURLです。空文字の場合、デフォルトのものを利用します。
5050
* @param api_token 接続時のBearer認証トークンです。空文字の場合、デフォルトのものを利用します。
51+
* 空文字の場合にデフォルトになる理由は、利用者側からデフォルトURL等が見えないほうが安全だからです。
5152
*/
5253
Client(const std::string& server_url, const std::string& api_token);
5354

@@ -64,6 +65,13 @@ namespace plateau::network {
6465
* 受け取る json の例 : https://plateau-api-mock-v2.deta.dev/sdk/datasets/23ku/files
6566
*/
6667
DatasetFiles getFiles(const std::string& id) const;
68+
69+
/**
70+
* @brief ファイルをダウンロードします。
71+
* @param destination_directory_path ダウンロード先のローカルディレクトリのパスです。
72+
* @param url URLです。
73+
* @return ダウンロードしたファイルのパスを返します。
74+
*/
6775
std::string download(const std::string& destination_directory_path, const std::string& url) const;
6876

6977
/// 開発用に用意したモックサーバーのURLです。

src/network/client.cpp

Lines changed: 41 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,14 @@ namespace fs = std::filesystem;
1010

1111
namespace {
1212
/// httplib::Client を作成し、それにURLとAPIトークンを設定して返します。
13+
/// APIトークンが空文字なら Bearer 認証を設定しません。
1314
httplib::Client createHttpLibClient(const std::string& url, const std::string& api_token) {
1415
auto client = httplib::Client(url);
1516
// Bearer認証を設定します。
16-
httplib::Headers headers = {{"Authorization", "Bearer " + api_token}};
17-
client.set_default_headers(headers);
17+
if(!api_token.empty()){
18+
httplib::Headers headers = {{"Authorization", "Bearer " + api_token}};
19+
client.set_default_headers(headers);
20+
}
1821
return client;
1922
}
2023

@@ -64,22 +67,22 @@ namespace plateau::network {
6467
if (res && res->status == 200) {
6568
auto jres = json::parse(res->body);
6669

67-
for (int i = 0; i < jres["data"].size(); i++) {
68-
DatasetMetadataGroup dataset_meta_data_group;
69-
dataset_meta_data_group.id = jres["data"][i]["id"];
70-
dataset_meta_data_group.title = jres["data"][i]["title"];
71-
72-
for (int j = 0; j < jres["data"][i]["data"].size(); j++) {
73-
DatasetMetadata dataset_meta_data;
74-
dataset_meta_data.id = jres["data"][i]["data"][j]["id"];
75-
dataset_meta_data.title = jres["data"][i]["data"][j]["title"];
76-
dataset_meta_data.description = jres["data"][i]["data"][j]["description"];
77-
if (jres["data"][i]["data"][j].contains("featureTypes")) {
78-
dataset_meta_data.feature_types = jres["data"][i]["data"][j]["featureTypes"];
70+
for (auto & json_dataset_metadata_group : jres.at("data")) {
71+
DatasetMetadataGroup dataset_metadata_group;
72+
dataset_metadata_group.id = json_dataset_metadata_group.at("id");
73+
dataset_metadata_group.title = json_dataset_metadata_group.at("title");
74+
75+
for (auto & json_dataset_metadata : json_dataset_metadata_group.at("data")) {
76+
DatasetMetadata dataset_metadata;
77+
dataset_metadata.id = json_dataset_metadata.at("id");
78+
dataset_metadata.title = json_dataset_metadata.at("title");
79+
dataset_metadata.description = json_dataset_metadata.at("description");
80+
if (json_dataset_metadata.contains("featureTypes")) {
81+
dataset_metadata.feature_types = json_dataset_metadata.at("featureTypes");
7982
}
80-
dataset_meta_data_group.datasets.push_back(dataset_meta_data);
83+
dataset_metadata_group.datasets.push_back(dataset_metadata);
8184
}
82-
out_metadata_groups.push_back(dataset_meta_data_group);
85+
out_metadata_groups.push_back(dataset_metadata_group);
8386
}
8487
}
8588
}
@@ -107,11 +110,11 @@ namespace plateau::network {
107110
dataset_files.emplace(key, std::vector<DatasetFileItem>());
108111
for (const auto& file_item: file_items) { // 各ファイルについて
109112
DatasetFileItem dataset_file;
110-
dataset_file.max_lod = file_item["maxLod"].get<int>();
111-
dataset_file.mesh_code = file_item["code"];
112-
dataset_file.url = file_item["url"];
113+
dataset_file.max_lod = file_item.at("maxLod").get<int>();
114+
dataset_file.mesh_code = file_item.at("code");
115+
dataset_file.url = file_item.at("url");
113116

114-
dataset_files[key].push_back(dataset_file);
117+
dataset_files.at(key).push_back(dataset_file);
115118
}
116119
}
117120
}
@@ -126,22 +129,35 @@ namespace plateau::network {
126129
auto gml_file_path = fs::absolute(fs::path(destination_directory) / gml_file);
127130
fs::create_directories(destination_directory);
128131

129-
auto cli = createHttpLibClient(server_url_, api_token_);
130-
cli.enable_server_certificate_verification(false);
131-
132132
// '\\' を '/' に置換
133133
auto pos = url_str.find(u8'\\');
134134
while (pos != std::string::npos) {
135135
url_str.replace(pos, 1, u8"/");
136136
pos = url_str.find(u8'\\', pos + 1);
137137
}
138138

139-
auto path_after_domain = url_str.substr(url_str.substr(8).find('/') + 8);
139+
// URL をドメイン部とそれ以降に分けます。
140+
auto domain_end_pos = url_str.substr(8).find('/') + 8;
141+
auto path_after_domain = url_str.substr(domain_end_pos);
142+
auto path_domain = url_str.substr(0, domain_end_pos);
143+
144+
// HTTPリクエストを投げます。
145+
// 注意:
146+
// ここでは api_token は空文字、すなわち Bearer認証を利用しません。
147+
// APIサーバーから json を受け取るためには api_token が必要なのに対して、
148+
// cmsサーバーからgmlファイルを受け取るためには Bearer認証されていると認証失敗扱いになるためです。
149+
auto cli = createHttpLibClient(path_domain, ""/* api_token_ を利用せず空文字*/);
150+
151+
// この1行がないと、MacとUbuntuでモックサーバーに対するテストが失敗します。
152+
cli.enable_server_certificate_verification(false);
153+
140154
auto res = cli.Get(path_after_domain);
155+
// 結果を受け取ります。
141156
auto content_type = res->get_header_value("Content-Type");
142157
bool is_text =
143158
content_type.find("text") != std::string::npos ||
144-
content_type.find("json") != std::string::npos;
159+
content_type.find("json") != std::string::npos ||
160+
content_type.find("xml") != std::string::npos;
145161
auto ofs_mode = std::ios_base::openmode(is_text ? 0 : std::ios::binary);
146162
auto ofs = std::ofstream(gml_file_path.c_str(), ofs_mode);
147163
if (!ofs.is_open()) {

test/test_dataset.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ TEST_F(DatasetTest, fetch_local_generates_files) { // NOLINT
110110
};
111111
checkFilesExist(images, image_dir);
112112

113-
fs::remove_all(temp_test_dir);
113+
// fs::remove_all(temp_test_dir);
114114
}
115115

116116
TEST_F(DatasetTest, fetch_server_generates_files) { // NOLINT
@@ -127,6 +127,7 @@ TEST_F(DatasetTest, fetch_server_generates_files) { // NOLINT
127127
auto gml_path = fs::path(bldg_dir).append(u8"53392642_bldg_6697_2_op.gml").make_preferred();
128128
// auto gml_path = fs::path(bldg_dir).append("53392587_bldg_6697_2_op.gml").make_preferred();
129129
ASSERT_TRUE(fs::exists(gml_path)) << fs::absolute(gml_path) << " does not exist.";
130+
ASSERT_TRUE(fs::file_size(gml_path) > 0) << "gml file is not empty.";
130131

131132
// codelistsファイルがコピー先に存在します。
132133
auto codelists_dir = fs::path(temp_test_dir).append(u8"13100_tokyo23-ku_2020_citygml_3_2_op/codelists");

test/test_network_client.cpp

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,30 +8,60 @@ namespace plateau::network {
88
class ClientTest : public ::testing::Test {
99
protected:
1010
void SetUp() override {
11-
// client.setApiServerUrl(Client::getDefaultServerUrl());
1211
}
1312

14-
// Client client = Client();
1513
};
1614

17-
TEST_F(ClientTest, GetMetadata) { // NOLINT
18-
auto meta_data = Client::createClientForMockServer().getMetadata();
19-
ASSERT_NE(meta_data->size(), 0) << "Metadata Exists.";
20-
if (!meta_data->empty()) {
21-
ASSERT_EQ(meta_data->at(0).id, "tokyo");
15+
TEST_F(ClientTest, GetMetadataOfMockServer) { // NOLINT
16+
auto metadata_groups = Client::createClientForMockServer().getMetadata();
17+
ASSERT_NE(metadata_groups->size(), 0) << "Metadata Exists.";
18+
if (!metadata_groups->empty()) {
19+
ASSERT_EQ(metadata_groups->at(0).id, "tokyo");
2220
}
2321
}
2422

25-
TEST_F(ClientTest, GetFiles){ // NOLINT
23+
TEST_F(ClientTest, GetFilesOfMockServer){ // NOLINT
2624
auto files = Client::createClientForMockServer().getFiles("23ku");
2725
ASSERT_TRUE(!files.empty());
2826
}
2927

30-
TEST_F(ClientTest, Download) { // NOLINT
28+
TEST_F(ClientTest, DownloadFromMockServer) { // NOLINT
3129
std::string gml_file_name = "53392642_bldg_6697_2_op.gml";
3230
fs::remove(gml_file_name);
3331
auto fpath_str = Client::createClientForMockServer().download(u8".", Client::getMockServerUrl() + u8"/13100_tokyo23-ku_2020_citygml_3_2_op/udx/bldg/53392642_bldg_6697_2_op.gml");
3432
auto fpath = fs::u8path(fpath_str);
3533
ASSERT_TRUE(fs::file_size(fpath));
3634
}
35+
36+
TEST_F(ClientTest, GetMetadataOfDefaultServer) { // NOLINT
37+
auto client = Client("", "");
38+
auto metadata_groups = client.getMetadata();
39+
ASSERT_TRUE(!metadata_groups->empty()) << "Metadata groups is not empty.";
40+
auto metadata_group = metadata_groups->at(0);
41+
ASSERT_TRUE(!metadata_group.datasets.empty()) << "First metadata group has metadata.";
42+
ASSERT_TRUE(!metadata_group.title.empty()) << "First metadata group has title.";
43+
ASSERT_TRUE(!metadata_group.id.empty()) << "First metadata group has id.";
44+
auto metadata = metadata_group.datasets.at(0);
45+
ASSERT_TRUE(!metadata.title.empty()) << "Metadata has title.";
46+
ASSERT_TRUE(!metadata.id.empty()) << "Metadata has id.";
47+
}
48+
49+
TEST_F(ClientTest, DownloadFilesOfDefaultServer) { // NOLINT
50+
auto client = Client("", "");
51+
auto first_id = client.getMetadata()->at(0).datasets.at(0).id;
52+
auto files = client.getFiles(first_id);
53+
ASSERT_TRUE(!files.empty()) << "Dataset files is not empty.";
54+
auto files_of_first_package = files.begin()->second;
55+
ASSERT_TRUE(!files_of_first_package.empty());
56+
auto file = files_of_first_package.at(0);
57+
ASSERT_TRUE(0 <= file.max_lod && file.max_lod <= 4 );
58+
ASSERT_TRUE(!file.mesh_code.empty());
59+
ASSERT_TRUE(!file.url.empty());
60+
auto url = file.url;
61+
fs::remove("./" + fs::path(url).filename().u8string());
62+
auto downloaded_path = fs::u8path(client.download("./", url));
63+
ASSERT_TRUE(fs::exists(downloaded_path));
64+
ASSERT_TRUE(fs::file_size(downloaded_path) > 0);
65+
fs::remove(downloaded_path);
66+
}
3767
}

wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Geometries/GeoReference.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,26 @@ public enum CoordinateSystem
2828
EUN = 3
2929
}
3030

31+
public static class CoordinateSystemExtension
32+
{
33+
public static string ToNaturalLanguage(this CoordinateSystem system)
34+
{
35+
switch (system)
36+
{
37+
case CoordinateSystem.ENU:
38+
return "ENU(PLATEAUでの座標系)";
39+
case CoordinateSystem.ESU:
40+
return "ESU(Unreal Engineでの座標系)";
41+
case CoordinateSystem.EUN:
42+
return "EUN(Unityでの座標系)";
43+
case CoordinateSystem.WUN:
44+
return "WUN(EUNの左右反転補正)";
45+
default:
46+
throw new ArgumentOutOfRangeException(nameof(system), "Unknown coordinate system.");
47+
}
48+
}
49+
}
50+
3151
/// <summary>
3252
/// 極座標と平面直角座標を変換します。
3353
/// また座標変換の基準を保持します。

0 commit comments

Comments
 (0)