Skip to content

Commit fb68c05

Browse files
committed
add:国土基本図郭のロジックを追加
1 parent 8572c2e commit fb68c05

File tree

2 files changed

+278
-16
lines changed

2 files changed

+278
-16
lines changed

include/plateau/dataset/standard_map_grid.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
#pragma once
22

33
#include <string>
4+
#include <tuple>
45

56
#include <libplateau_api.h>
67
#include "plateau/geometry/geo_coordinate.h"
78
#include "plateau/dataset/grid_code.h"
89

910
namespace plateau::dataset {
11+
enum class StandardMapGridLevel;
1012
/**
1113
* \brief 国土基本図図郭を表します。
1214
*
@@ -59,5 +61,40 @@ namespace plateau::dataset {
5961
private:
6062
std::string code_; // 図郭コード
6163
bool is_valid_; // コードが有効かどうか
64+
StandardMapGridLevel level_;
65+
66+
int coordinate_origin_; // 原点
67+
char first_row_; // 1文字目の行(A-T)
68+
char first_col_; // 2文字目の列(A-H)
69+
int second_row_;
70+
int second_col_;
71+
int third_row_;
72+
int third_col_;
73+
74+
/**
75+
* \brief 図郭コードから平面直角座標系での範囲を計算します。
76+
* \return 平面直角座標系での範囲(min, max)
77+
*/
78+
std::pair<TVec3d, TVec3d> calculateGridExtent() const;
79+
80+
/**
81+
* サブグリッドの範囲を計算します。
82+
* @param min_x 最小X座標(入出力)
83+
* @param min_y 最小Y座標(入出力)
84+
* @param max_x 最大X座標(出力)
85+
* @param max_y 最大Y座標(出力)
86+
* @param row_index 行インデックス
87+
* @param col_index 列インデックス
88+
* @param cell_width セルの幅
89+
* @param cell_height セルの高さ
90+
* @param is_x_right X方向の向き(右方向ならtrue)
91+
* @param is_y_upper Y方向の向き(上方向ならtrue)
92+
*/
93+
void calculateSubGridExtent(
94+
double& min_x, double& min_y,
95+
double& max_x, double& max_y,
96+
int row_index, int col_index,
97+
double cell_width, double cell_height,
98+
bool is_x_right, bool is_y_upper) const;
6299
};
63100
}

src/dataset/standard_map_grid.cpp

Lines changed: 241 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,247 @@
11
#include "plateau/dataset/standard_map_grid.h"
2+
3+
#include <algorithm>
4+
25
#include "plateau/geometry/geo_coordinate.h"
36
#include <cctype>
47
#include <stdexcept>
8+
#include <plateau/geometry/geo_reference.h>
9+
#include <plateau/polygon_mesh/mesh_extract_options.h>
510

611
namespace plateau::dataset {
712

8-
StandardMapGrid::StandardMapGrid(const std::string& code) : code_(code), is_valid_(false) {
9-
// コードの形式を検証
10-
// TODO
11-
is_valid_ = true;
13+
enum class StandardMapGridLevel
14+
{
15+
Invalid = -1,
16+
Level50000 = 0,
17+
Level5000 = 1,
18+
Level2500 = 2,
19+
Level1000 = 3,
20+
Level500 = 4,
21+
};
22+
23+
namespace {
24+
constexpr int level5000_division_count = 10;
25+
constexpr int level2500_division_count = 2;
26+
constexpr int level1000_division_count = 5;
27+
constexpr int level500_division_count = 10;
28+
29+
// 1セルのサイズ
30+
constexpr double level50000_cell_width = 40000.0; // 40km
31+
constexpr double level50000_cell_height = 30000.0; // 30km
32+
constexpr int level50000_row_count = 20; // 縦方向の分割数
33+
34+
constexpr double level5000_cell_height = level50000_cell_height / level5000_division_count; // 3km
35+
constexpr double level5000_cell_width = level50000_cell_width / level5000_division_count; // 4km
36+
37+
constexpr double level2500_cell_height = level5000_cell_height / level2500_division_count; // 1.5km
38+
constexpr double level2500_cell_width = level5000_cell_width / level2500_division_count; // 2km
39+
40+
constexpr double level1000_cell_height = level5000_cell_height / level1000_division_count; // 600m
41+
constexpr double level1000_cell_width = level5000_cell_width / level1000_division_count; // 800m
42+
43+
constexpr double level500_cell_height = level5000_cell_height / level500_division_count; // 300m
44+
constexpr double level500_cell_width = level5000_cell_width / level500_division_count; // 400m
45+
46+
// 原点から端までのセル数
47+
constexpr double row_half_count = 10.0;
48+
constexpr double col_half_count = 4.0;
49+
}
50+
51+
/**
52+
* 図郭コードの文字列からレベル(詳細度)を返します。
53+
*/
54+
StandardMapGridLevel parseLevel(const std::string& code) {
55+
56+
if (code.size() == 4) {
57+
return StandardMapGridLevel::Level50000;
58+
}
59+
if (code.size() == 6) {
60+
return StandardMapGridLevel::Level5000;
61+
}
62+
if (code.size() == 7) {
63+
return StandardMapGridLevel::Level2500;
64+
}
65+
if (code.size() == 8) {
66+
// 末尾がアルファベットであれば1000
67+
if (std::isalpha(code.back())) {
68+
return StandardMapGridLevel::Level1000;
69+
}
70+
// 末尾が数字であれば500
71+
else {
72+
return StandardMapGridLevel::Level500;
73+
}
74+
}
75+
76+
// サポート対象外
77+
return StandardMapGridLevel::Invalid;
78+
}
79+
80+
StandardMapGrid::StandardMapGrid(const std::string& code) : code_(code), is_valid_(true) {
81+
// 図郭コードの文字列が数字とアルファベットからなることをチェックします。
82+
if (!std::all_of(code_.begin(), code_.end(), [](char c)
83+
{
84+
return std::isalnum(c);
85+
})) {
86+
is_valid_ = false;
87+
return;
88+
}
89+
90+
// 図郭コードのレベル(詳細度)をチェックします。
91+
level_ = parseLevel(code);
92+
if (level_ == StandardMapGridLevel::Invalid) {
93+
is_valid_ = false;
94+
return;
95+
}
96+
97+
// 原点設定
98+
coordinate_origin_ = std::stoi(code.substr(0, 2));
99+
100+
// 図郭コードの行番号、列番号を取得します。
101+
first_row_ = code[2]; // 1文字目は行
102+
first_col_ = code[3]; // 2文字目は列
103+
if (level_ == StandardMapGridLevel::Level50000) {
104+
return;
105+
}
106+
107+
second_row_ = std::stoi(code.substr(4, 1));
108+
second_col_ = std::stoi(code.substr(5, 1));
109+
110+
if (level_ == StandardMapGridLevel::Level5000) {
111+
return;
112+
}
113+
114+
if (level_ == StandardMapGridLevel::Level2500) {
115+
// 2×2分割のインデックスを計算
116+
int third = std::stoi(code.substr(6, 1)); // 1-4
117+
third_row_ = (third - 1) / 2; // 0 or 1
118+
third_col_ = (third - 1) % 2; // 0 or 1
119+
return;
120+
}
121+
122+
if (level_ == StandardMapGridLevel::Level1000) {
123+
third_row_ = std::stoi(code.substr(6, 1)); // 0-4
124+
third_col_ = code.substr(7, 1)[0] - 'A'; // 0-4 (A-E)
125+
return;
126+
}
127+
128+
// Level500
129+
third_row_ = std::stoi(code.substr(6, 1)); // 0-9
130+
third_col_ = std::stoi(code.substr(7, 1)); // 0-9
12131
}
13132

14133
std::string StandardMapGrid::get() const {
15134
return code_;
16135
}
17136

137+
std::pair<TVec3d, TVec3d> StandardMapGrid::calculateGridExtent() const {
138+
double min_x = 0.0, min_y = 0.0;
139+
double max_x = 0.0, max_y = 0.0;
140+
141+
// 親セルの位置に基づいて方向フラグを設定(スコープ外でも使用するため、ここで定義)
142+
bool is_x_right = false;
143+
bool is_y_upper = false;
144+
145+
// Level50000の計算
146+
{
147+
// 南北方向(行)のインデックス計算
148+
// A行から数えて何番目かを計算(0始まり)
149+
int row_index = first_row_ - 'A';
150+
151+
// 東西方向(列)のインデックス計算
152+
// A列から数えて何番目かを計算(0始まり)
153+
int col_index = first_col_ - 'A';
154+
155+
// 基準点からの距離を計算
156+
// 列(X座標): 原点から左右対称(左が負、右が正)
157+
min_x = (col_index - col_half_count) * level50000_cell_width;
158+
max_x = min_x + level50000_cell_width;
159+
160+
// 行(Y座標): 原点から上下対称(上が正、下が負)
161+
min_y = (row_half_count - row_index) * level50000_cell_height;
162+
max_y = min_y + level50000_cell_height;
163+
164+
// 親セルの位置に基づいて方向フラグを設定
165+
is_x_right = col_index >= col_half_count; // E列より右側
166+
is_y_upper = row_index <= row_half_count; // 中央より上側
167+
}
168+
169+
if (level_ == StandardMapGridLevel::Level50000) {
170+
return {TVec3d(min_x, min_y, 0), TVec3d(max_x, max_y, 0)};
171+
}
172+
173+
// Level5000の計算
174+
calculateSubGridExtent(
175+
min_x, min_y, max_x, max_y,
176+
second_row_, second_col_,
177+
level5000_cell_width, level5000_cell_height,
178+
is_x_right, is_y_upper);
179+
180+
if (level_ == StandardMapGridLevel::Level5000) {
181+
return {TVec3d(min_x, min_y, 0), TVec3d(max_x, max_y, 0)};
182+
}
183+
184+
if (level_ == StandardMapGridLevel::Level2500) {
185+
calculateSubGridExtent(
186+
min_x, min_y, max_x, max_y,
187+
third_row_, third_col_,
188+
level2500_cell_width, level2500_cell_height,
189+
is_x_right, is_y_upper);
190+
return {TVec3d(min_x, min_y, 0), TVec3d(max_x, max_y, 0)};
191+
} else if (level_ == StandardMapGridLevel::Level1000) {
192+
calculateSubGridExtent(
193+
min_x, min_y, max_x, max_y,
194+
third_row_, third_col_,
195+
level1000_cell_width, level1000_cell_height,
196+
is_x_right, is_y_upper);
197+
return {TVec3d(min_x, min_y, 0), TVec3d(max_x, max_y, 0)};
198+
} else { // Level500
199+
calculateSubGridExtent(
200+
min_x, min_y, max_x, max_y,
201+
third_row_, third_col_,
202+
level500_cell_width, level500_cell_height,
203+
is_x_right, is_y_upper);
204+
return {TVec3d(min_x, min_y, 0), TVec3d(max_x, max_y, 0)};
205+
}
206+
}
207+
208+
void StandardMapGrid::calculateSubGridExtent(
209+
double& min_x, double& min_y,
210+
double& max_x, double& max_y,
211+
int row_index, int col_index,
212+
double cell_width, double cell_height,
213+
bool is_x_right, bool is_y_upper) const {
214+
215+
// X座標の計算
216+
// is_x_rightがtrueの場合、親セルの左端から右方向に移動
217+
// is_x_rightがfalseの場合、親セルの左端から左方向に移動
218+
min_x = min_x + (is_x_right ? col_index * cell_width : -col_index * cell_width);
219+
max_x = min_x + cell_width;
220+
221+
// Y座標の計算
222+
// is_y_upperがtrueの場合、親セルの下端から上方向に移動
223+
// is_y_upperがfalseの場合、親セルの下端から下方向に移動
224+
min_y = min_y + (is_y_upper ? row_index * cell_height : -row_index * cell_height);
225+
max_y = min_y + cell_height;
226+
}
227+
18228
geometry::Extent StandardMapGrid::getExtent() const {
19229
if (!isValid()) {
20230
throw std::runtime_error("Invalid standard map grid code.");
21231
}
232+
233+
const auto [planeMin, planeMax] = calculateGridExtent();
234+
235+
// GeoReferenceを取得
236+
plateau::polygonMesh::MeshExtractOptions options;
237+
options.coordinate_zone_id = coordinate_origin_;
238+
const auto geo_reference = geometry::GeoReference(options.coordinate_zone_id, options.reference_point, options.unit_scale, options.mesh_axes);
239+
240+
// 平面直角座標系から緯度経度に変換
241+
const auto min_coordinate = geo_reference.unproject(planeMin);
242+
const auto max_coordinate = geo_reference.unproject(planeMax);
22243

23-
// TODO: 図郭コードから緯度経度範囲を計算する実装を追加
24-
// この実装は図郭コードの仕様に基づいて行う必要があります
25-
return geometry::Extent(geometry::GeoCoordinate(0, 0, 0), geometry::GeoCoordinate(0, 0, 0));
244+
return geometry::Extent(min_coordinate, max_coordinate);
26245
}
27246

28247
bool StandardMapGrid::isWithin(const GridCode& other) const {
@@ -31,28 +250,34 @@ namespace plateau::dataset {
31250
// 同じ型の場合のみ比較
32251
const auto* other_grid = dynamic_cast<const StandardMapGrid*>(&other);
33252
if (other_grid == nullptr) return false;
34-
35-
// TODO: 図郭の包含関係を判定する実装を追加
36-
return false;
253+
254+
if (code_ == other_grid->code_) {
255+
return true;
256+
}
257+
258+
// Level50000の場合は先頭4文字、Level50000以外の場合は先頭6文字で比較
259+
const size_t compare_length = (level_ == StandardMapGridLevel::Level50000) ? 4 : 6;
260+
return code_.substr(0, compare_length) == other_grid->code_.substr(0, compare_length);
37261
}
38262

39263
bool StandardMapGrid::isValid() const {
40264
return is_valid_;
41265
}
42266

43267
std::shared_ptr<GridCode> StandardMapGrid::upper() {
44-
// 仮実装: 自分自身のコピーを返す
45-
return std::make_shared<StandardMapGrid>(code_);
268+
// 1段階上のレベルの図郭コードに変換
269+
auto new_code = std::make_shared<StandardMapGrid>(code_);
270+
new_code->level_ = static_cast<StandardMapGridLevel>(static_cast<int>(level_) - 1);
271+
new_code->is_valid_ = new_code->level_ >= StandardMapGridLevel::Level50000;
272+
return new_code;
46273
}
47274

48275
int StandardMapGrid::getLevel() const {
49-
// 仮実装: 常に1を返す
50-
return 1;
276+
return (int)level_;
51277
}
52278

53279
bool StandardMapGrid::isLargestLevel() const {
54-
// 仮実装: 常にtrueを返す
55-
return true;
280+
return level_ == StandardMapGridLevel::Level50000;
56281
}
57282

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

0 commit comments

Comments
 (0)