Skip to content

Commit e5fef73

Browse files
authored
Merge pull request #271 from Synesthesias/feature/add_standard_map_grid
国土基本図郭の範囲取得実装追加
2 parents 1ee58e6 + a967910 commit e5fef73

File tree

5 files changed

+619
-25
lines changed

5 files changed

+619
-25
lines changed

include/plateau/dataset/standard_map_grid.h

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,25 @@
77
#include "plateau/dataset/grid_code.h"
88

99
namespace plateau::dataset {
10+
11+
enum class StandardMapGridLevel
12+
{
13+
Invalid = -1,
14+
Level50000 = 0,
15+
Level5000 = 1,
16+
Level2500 = 2,
17+
Level1000 = 3,
18+
Level500 = 4,
19+
};
20+
1021
/**
1122
* \brief 国土基本図図郭を表します。
1223
*
1324
* 国土基本図の図郭コードを扱い、緯度経度範囲の取得などの機能を提供します。
1425
*/
1526
class LIBPLATEAU_EXPORT StandardMapGrid : public GridCode {
1627
public:
17-
explicit StandardMapGrid(std::string code);
28+
explicit StandardMapGrid(std::string code);
1829
StandardMapGrid() = default;
1930

2031
/**
@@ -53,8 +64,23 @@ namespace plateau::dataset {
5364
bool operator==(const StandardMapGrid& other) const;
5465
bool operator<(const StandardMapGrid& other) const;
5566

67+
/**
68+
* \brief 図郭コードから平面直角座標系での範囲を計算します。
69+
* \return 平面直角座標系での範囲(min, max)
70+
*/
71+
std::pair<TVec3d, TVec3d> calculateGridExtent() const;
72+
5673
private:
5774
std::string code_; // 図郭コード
5875
bool is_valid_ = false; // コードが有効かどうか
76+
StandardMapGridLevel level_;
77+
78+
int coordinate_origin_; // 原点
79+
char first_row_; // 1文字目はrow座標(東西, A-H)
80+
char first_column_; // 2文字目はcolumn座標(南北, A-T)
81+
int second_row_;
82+
int second_column_;
83+
int third_row_;
84+
int third_column_;
5985
};
60-
}
86+
}

src/dataset/standard_map_grid.cpp

Lines changed: 262 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,304 @@
11
#include "plateau/dataset/standard_map_grid.h"
2+
#include <algorithm>
23
#include "plateau/geometry/geo_coordinate.h"
34
#include <stdexcept>
45
#include <utility>
6+
#include <plateau/geometry/geo_reference.h>
7+
#include <plateau/polygon_mesh/mesh_extract_options.h>
8+
#include <iostream>
59

610
namespace plateau::dataset {
711

8-
StandardMapGrid::StandardMapGrid(std::string code) : code_(std::move(code)), is_valid_(false) {
9-
// コードの形式を検証
10-
// TODO
11-
is_valid_ = true;
12+
namespace {
13+
constexpr int level5000_division_count = 10;
14+
constexpr int level2500_division_count = 2;
15+
constexpr int level1000_division_count = 5;
16+
constexpr int level500_division_count = 10;
17+
18+
// 1セルのサイズ
19+
constexpr double level50000_cell_column = 30000.0; // 南北30km
20+
constexpr double level50000_cell_row = 40000.0; // 東西40km
21+
22+
constexpr double level5000_cell_column = level50000_cell_column / level5000_division_count; // 南北4km
23+
constexpr double level5000_cell_row = level50000_cell_row / level5000_division_count; // 東西3km
24+
25+
constexpr double level2500_cell_column = level5000_cell_column / level2500_division_count; // 南北2km
26+
constexpr double level2500_cell_row = level5000_cell_row / level2500_division_count; // 東西1.5km
27+
28+
constexpr double level1000_cell_column = level5000_cell_column / level1000_division_count; // 南北800m
29+
constexpr double level1000_cell_row = level5000_cell_row / level1000_division_count; // 東西600m
30+
31+
constexpr double level500_cell_column = level5000_cell_column / level500_division_count; // 南北400m
32+
constexpr double level500_cell_row = level5000_cell_row / level500_division_count; // 東西300m
33+
34+
/**
35+
* 図郭コードの文字列からレベル(詳細度)を返します。
36+
*/
37+
StandardMapGridLevel parseLevel(const std::string& code) {
38+
if (code.size() == 4) {
39+
return StandardMapGridLevel::Level50000;
40+
}
41+
if (code.size() == 6) {
42+
return StandardMapGridLevel::Level5000;
43+
}
44+
if (code.size() == 7) {
45+
return StandardMapGridLevel::Level2500;
46+
}
47+
if (code.size() == 8) {
48+
// 末尾がアルファベットであれば1000
49+
if (std::isalpha(code.back())) {
50+
return StandardMapGridLevel::Level1000;
51+
}
52+
// 末尾が数字であれば500
53+
else {
54+
return StandardMapGridLevel::Level500;
55+
}
56+
}
57+
58+
// サポート対象外
59+
return StandardMapGridLevel::Invalid;
60+
}
61+
62+
/**
63+
* 計算された平面直角座標をTVec3dのペアに変換します。
64+
*/
65+
std::pair<TVec3d, TVec3d> createExtentPair(
66+
double min_column, double min_row,
67+
double max_column, double max_row) {
68+
// column: 南北方向(緯度):Y軸
69+
// row: 東西方向(経度):X軸
70+
return {TVec3d(min_row, 0, min_column), TVec3d(max_row, 0, max_column)};
71+
}
72+
73+
void calculateSubGridExtent(
74+
double& min_column, double& min_row,
75+
double& max_column, double& max_row,
76+
int column_index, int row_index,
77+
double cell_column, double cell_row) {
78+
79+
// column座標(南北)の計算
80+
min_column = min_column + (column_index * cell_column);
81+
max_column = min_column + cell_column;
82+
83+
// row座標(東西)の計算
84+
min_row = min_row + (row_index * cell_row);
85+
max_row = min_row + cell_row;
86+
}
87+
}
88+
89+
StandardMapGrid::StandardMapGrid(std::string code) : code_(std::move(code)) {
90+
try {
91+
is_valid_ = true;
92+
93+
// 図郭コードの文字列が数字とアルファベットからなることをチェックします。
94+
if (!std::all_of(code_.begin(), code_.end(), [](char c)
95+
{
96+
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z');
97+
})) {
98+
is_valid_ = false;
99+
return;
100+
}
101+
102+
// 図郭コードのレベル(詳細度)をチェックします。
103+
level_ = parseLevel(code_);
104+
if (level_ == StandardMapGridLevel::Invalid) {
105+
is_valid_ = false;
106+
return;
107+
}
108+
109+
// 原点設定
110+
coordinate_origin_ = std::stoi(code_.substr(0, 2));
111+
112+
// 図郭コードのcolumn, row座標を取得します。
113+
first_column_ = code_[2]; // 1文字目はcolumn座標(南北)
114+
first_row_ = code_[3]; // 2文字目はrow座標(東西)
115+
116+
// 文字の範囲チェック
117+
if (first_column_ < 'A' || first_column_ > 'T' ||
118+
first_row_ < 'A' || first_row_ > 'H') {
119+
is_valid_ = false;
120+
return;
121+
}
122+
123+
if (level_ == StandardMapGridLevel::Level50000) {
124+
return;
125+
}
126+
127+
// 基点は左下(90)
128+
second_column_ = 9 - std::stoi(code_.substr(4, 1));
129+
second_row_ = std::stoi(code_.substr(5, 1));
130+
131+
if (level_ == StandardMapGridLevel::Level5000) {
132+
return;
133+
}
134+
135+
if (level_ == StandardMapGridLevel::Level2500) {
136+
// 基点は左下
137+
int third = std::stoi(code_.substr(6, 1)); // 1-4
138+
switch (third) {
139+
case 1: // 左上
140+
third_column_ = 1;
141+
third_row_ = 0;
142+
break;
143+
case 2: // 右上
144+
third_column_ = 1;
145+
third_row_ = 1;
146+
break;
147+
case 3: // 左下
148+
third_column_ = 0;
149+
third_row_ = 0;
150+
break;
151+
case 4: // 右下
152+
third_column_ = 0;
153+
third_row_ = 1;
154+
break;
155+
default:
156+
is_valid_ = false;
157+
break;
158+
}
159+
return;
160+
}
161+
162+
if (level_ == StandardMapGridLevel::Level1000) {
163+
// 基点は左下(4A)
164+
third_column_ = 4 - std::stoi(code_.substr(6, 1)); // 0-4
165+
third_row_ = code_.substr(7, 1)[0] - 'A'; // 0-4 (A-E)
166+
167+
// Level1000の範囲チェック
168+
if (third_column_ < 0 || third_column_ > 4 ||
169+
third_row_ < 0 || third_row_ > 4) {
170+
is_valid_ = false;
171+
}
172+
return;
173+
}
174+
175+
// Level500
176+
// 基点は左下(9A)
177+
third_column_ = 9 - std::stoi(code_.substr(6, 1)); // 0-9
178+
third_row_ = std::stoi(code_.substr(7, 1)); // 0-9
179+
180+
} catch (const std::exception& e) {
181+
is_valid_ = false;
182+
std::cerr << "Failed to parse grid code " << code_ << ": " << e.what() << std::endl;
183+
}
12184
}
13185

14186
std::string StandardMapGrid::get() const {
15187
return code_;
16188
}
17189

190+
std::pair<TVec3d, TVec3d> StandardMapGrid::calculateGridExtent() const {
191+
// 東西方向のインデックスを計算(東がプラス、西がマイナス)
192+
int row_index = first_row_ - 'E';
193+
194+
// 南北方向のインデックスを計算(北がプラス、南がマイナス)
195+
int column_index = 'J' - first_column_;
196+
197+
// Level50000の計算
198+
// column座標(南北)の計算
199+
double min_column = column_index * level50000_cell_column;
200+
double max_column = min_column + level50000_cell_column;
201+
202+
// row座標(東西)の計算
203+
double min_row = row_index * level50000_cell_row;
204+
double max_row = min_row + level50000_cell_row;
205+
206+
if (level_ == StandardMapGridLevel::Level50000) {
207+
return createExtentPair(min_column, min_row, max_column, max_row);
208+
}
209+
210+
// Level5000の計算
211+
calculateSubGridExtent(
212+
min_column, min_row, max_column, max_row,
213+
second_column_, second_row_,
214+
level5000_cell_column, level5000_cell_row);
215+
216+
if (level_ == StandardMapGridLevel::Level5000) {
217+
return createExtentPair(min_column, min_row, max_column, max_row);
218+
}
219+
220+
if (level_ == StandardMapGridLevel::Level2500) {
221+
222+
calculateSubGridExtent(
223+
min_column, min_row, max_column, max_row,
224+
third_column_, third_row_,
225+
level2500_cell_column, level2500_cell_row);
226+
return createExtentPair(min_column, min_row, max_column, max_row);
227+
228+
} else if (level_ == StandardMapGridLevel::Level1000) {
229+
230+
calculateSubGridExtent(
231+
min_column, min_row, max_column, max_row,
232+
third_column_, third_row_,
233+
level1000_cell_column, level1000_cell_row);
234+
return createExtentPair(min_column, min_row, max_column, max_row);
235+
236+
} else { // Level500
237+
238+
calculateSubGridExtent(
239+
min_column, min_row, max_column, max_row,
240+
third_column_, third_row_,
241+
level500_cell_column, level500_cell_row);
242+
return createExtentPair(min_column, min_row, max_column, max_row);
243+
}
244+
}
245+
18246
geometry::Extent StandardMapGrid::getExtent() const {
19247
if (!isValid()) {
20248
throw std::runtime_error("Invalid standard map grid code.");
21249
}
22-
23-
// TODO: 図郭コードから緯度経度範囲を計算する実装を追加
24-
// この実装は図郭コードの仕様に基づいて行う必要があります
25-
return {geometry::GeoCoordinate(0, 0, 0), geometry::GeoCoordinate(0, 0, 0)};
250+
251+
const auto [planeMin, planeMax] = calculateGridExtent();
252+
253+
// GeoReferenceを取得
254+
plateau::polygonMesh::MeshExtractOptions options;
255+
options.coordinate_zone_id = coordinate_origin_;
256+
const auto geo_reference = geometry::GeoReference(options.coordinate_zone_id, options.reference_point, options.unit_scale, options.mesh_axes);
257+
258+
// 平面直角座標系から緯度経度に変換
259+
const auto min_coordinate = geo_reference.unproject(planeMin);
260+
const auto max_coordinate = geo_reference.unproject(planeMax);
261+
262+
return geometry::Extent(min_coordinate, max_coordinate);
26263
}
27264

28265
bool StandardMapGrid::isValid() const {
29266
return is_valid_;
30267
}
31268

32269
std::shared_ptr<GridCode> StandardMapGrid::upper() const {
33-
// 仮実装: 自分自身のコピーを返す
34-
return std::shared_ptr<GridCode>(upperRaw());
270+
// 1段階上のレベルの図郭コードに変換
271+
auto new_grid_code = std::shared_ptr<GridCode>(upperRaw());
272+
return new_grid_code;
35273
}
36274

37275
GridCode* StandardMapGrid::upperRaw() const {
38-
// 仮実装: 自分自身のコピーを返す
39-
return new StandardMapGrid(code_);
276+
if (level_ == StandardMapGridLevel::Level50000) {
277+
auto* new_grid = new StandardMapGrid(code_);
278+
new_grid->is_valid_ = false;
279+
return new_grid;
280+
}
281+
282+
const std::string upper_code = level_ > StandardMapGridLevel::Level5000
283+
? code_.substr(0, 6)
284+
: code_.substr(0, 4);
285+
return new StandardMapGrid(upper_code);
40286
}
41287

42288
int StandardMapGrid::getLevel() const {
43-
// 仮実装: 常に1を返す
44-
return 1;
289+
return (int)level_;
45290
}
46291

47292
bool StandardMapGrid::isLargestLevel() const {
48-
// 仮実装: 常にtrueを返す
49-
return true;
293+
return level_ == StandardMapGridLevel::Level50000;
50294
}
51295

52296
bool StandardMapGrid::isSmallerThanNormalGml() const {
53-
// 仮実装
54-
return false;
297+
return level_ < StandardMapGridLevel::Level2500;
55298
}
56299

57300
bool StandardMapGrid::isNormalGmlLevel() const {
58-
// 仮実装: 常にtrueを返す
59-
return true;
301+
return level_ == StandardMapGridLevel::Level2500;
60302
}
61303

62304
bool StandardMapGrid::operator==(const StandardMapGrid& other) const {

test/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ add_executable(plateau_test
3030
"test_mesh_extractor.cpp"
3131
"test_grid_merger.cpp"
3232
"test_mesh_code.cpp"
33-
"test_dataset.cpp"
3433
"test_vector_tile.cpp"
3534
"test_obj_writer.cpp"
3635
"test_gltf_writer.cpp"
@@ -49,6 +48,7 @@ add_executable(plateau_test
4948
"test_map_zoom_level_searcher.cpp"
5049
"test_height_map_aligner.cpp"
5150
"test_heightmap_mesh_generator.cpp"
51+
"test_standard_map_grid.cpp"
5252
"test_geo_reference.cpp"
5353
)
5454

0 commit comments

Comments
 (0)