Skip to content

Commit faad4f0

Browse files
committed
test impl
1 parent 8e7950e commit faad4f0

File tree

2 files changed

+117
-80
lines changed

2 files changed

+117
-80
lines changed

include/plateau/polygon_mesh/mesh_extract_options.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ namespace plateau::polygonMesh {
3939
map_tile_zoom_level(15),
4040
map_tile_url("https://cyberjapandata.gsi.go.jp/xyz/seamlessphoto/{z}/{x}/{y}.jpg"),
4141
epsg_code(plateau::geometry::CoordinateReferenceFactory::default_epsg),
42-
highest_lod_only(false)
42+
highest_lod_only(false),
43+
enable_lod_grouping(true)
4344
{}
4445

4546
public:
@@ -126,5 +127,10 @@ namespace plateau::polygonMesh {
126127
* (もし「データセット内で検出された実在の最大LOD」のみを対象にする仕様であれば、その旨に書き換えてください)
127128
*/
128129
bool highest_lod_only;
130+
131+
/**
132+
* 各LOD内でのグルーピングを有効にするかどうかを指定します。
133+
*/
134+
bool enable_lod_grouping;
129135
};
130136
}

src/polygon_mesh/area_mesh_factory.cpp

Lines changed: 110 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -79,35 +79,24 @@ namespace {
7979
}
8080
}
8181

82-
namespace plateau::polygonMesh {
83-
using namespace citygml;
82+
namespace {
83+
/**
84+
* CityObjectのリストをLODに基づいてグループ化します。
85+
* enable_lod_grouping が true の場合、各オブジェクトの最大LODに応じてグループ分けします。
86+
* false の場合、全てのオブジェクトを単一のグループ(group_id=0)にまとめます。
87+
*/
88+
GroupGridIDToObjectsMap groupByLod(
89+
const std::list<const citygml::CityObject*>& primary_objects,
90+
unsigned grid_id,
91+
const plateau::polygonMesh::MeshExtractOptions& options,
92+
unsigned lod) {
8493

85-
GridMergeResult
86-
AreaMeshFactory::gridMerge(const CityModel& city_model, const MeshExtractOptions& options, unsigned lod,
87-
const geometry::GeoReference& geo_reference, const std::vector<plateau::geometry::Extent>& extents) {
88-
// city_model に含まれる 主要地物 をグリッドに分類します。
89-
const auto& all_primary_city_objects =
90-
city_model.getAllCityObjectsOfType(PrimaryCityObjectTypes::getPrimaryTypeMask());
91-
const auto& city_envelope = city_model.getEnvelope();
92-
auto grid_id_to_primary_objects_map = classifyCityObjectsToGrid(all_primary_city_objects, city_envelope, options, extents);
93-
94-
// グリッドをさらに分割してグループにします。
95-
// グループの分割基準:
96-
// 仕様上存在しうる最大LODをm として、各オブジェクトを次のグループに分けます。
97-
// - 同じオブジェクトが (0, 1, 2, ..., m) のLODであるポリゴンをどれも有する つまり 全LODに対応する
98-
// - 同じオブジェクトが (0, 1, 2, ..., m-1) のLODであるポリゴンをどれも有し、mを有しない つまり 最大LODを除く全LODに対応する
99-
// - ...
100-
// - 同じオブジェクトが (0, 1) のLODであるポリゴンをどれも有し、(2, 3, ..., m)のLODであるポリゴンをどれも有しない つまり LOD 0, 1のみに対応する
101-
// - 同じオブジェクトが (0) のLODであるポリゴンを有し、(1, 2, 3, ..., m) のLODであるポリゴンをどれも有しない つまり LOD 0 のみに対応する
102-
// 今の仕様上、mは3なので、各グリッドは最大4つに分割されます。
103-
// したがって、grid 0 と group 0 to 3 が対応します。 grid1 と group 4 to 7 が対応します。
104-
// 一般化すると、 grid i と group (i*m) to (i*(m+1)-1)が対応します。
105-
// 仕様上、あるオブジェクトのLOD i が存在すれば、同じオブジェクトの lod 0 to i-1 がすべて存在します。したがって、各オブジェクトは必ず上記グループのどれか1つに該当するはずです。
106-
// そのようにグループ分けする利点は、
107-
// 「高いLODを表示したが、低いLODにしか対応していない箇所が穴になってしまう」という状況で、穴をちょうど埋める範囲の低LODグループが存在することです。
108-
auto group_id_to_primary_objects_map = GroupGridIDToObjectsMap();
109-
for (const auto& [grid_id, primary_objects_in_grid] : grid_id_to_primary_objects_map) {
110-
for (const auto& primary_object : primary_objects_in_grid) {
94+
using namespace plateau::polygonMesh;
95+
GroupGridIDToObjectsMap result;
96+
97+
if (options.enable_lod_grouping) {
98+
// LODグループ化が有効な場合: 各オブジェクトの最大LODに応じてグループ分け
99+
for (const auto& primary_object : primary_objects) {
111100
// この CityObject について、最大でどのLODまで存在するか確認します。
112101
unsigned max_lod_in_obj = PolygonMeshUtils::max_lod_in_specification_;
113102
for (unsigned target_lod = lod + 1; target_lod <= PolygonMeshUtils::max_lod_in_specification_; ++target_lod) {
@@ -129,15 +118,56 @@ namespace plateau::polygonMesh {
129118

130119
// グループに追加します。
131120
unsigned group_id = grid_id * (PolygonMeshUtils::max_lod_in_specification_ + 1) + max_lod_in_obj;
132-
const auto group_grid_id = std::make_pair(group_id, grid_id);
133-
if (group_id_to_primary_objects_map.find(group_grid_id) == group_id_to_primary_objects_map.end())
134-
group_id_to_primary_objects_map[group_grid_id] = std::list<const CityObject*>();
121+
const auto group_grid_id = std::make_pair(group_id, grid_id);
122+
if (result.find(group_grid_id) == result.end())
123+
result[group_grid_id] = std::list<const citygml::CityObject*>();
124+
125+
result.at(group_grid_id).push_back(primary_object);
126+
}
127+
} else {
128+
// LODグループ化が無効な場合: グリッドごとに1つのグループにまとめる
129+
for (const auto& primary_object : primary_objects) {
130+
if (options.highest_lod_only) {
131+
// highest_lod_only オプションが有効な場合、最大LODのみを対象とします。
132+
unsigned max_lod_in_obj = PolygonMeshUtils::max_lod_in_specification_;
133+
for (unsigned target_lod = lod + 1; target_lod <= PolygonMeshUtils::max_lod_in_specification_; ++target_lod) {
134+
bool target_lod_exists =
135+
PolygonMeshUtils::findFirstPolygon(primary_object, target_lod) != nullptr;
136+
if (!target_lod_exists) {
137+
max_lod_in_obj = target_lod - 1;
138+
break;
139+
}
140+
}
141+
if (lod != max_lod_in_obj) {
142+
// 最大LOD以外はスキップします。
143+
continue;
144+
}
145+
}
135146

136-
group_id_to_primary_objects_map.at(group_grid_id).push_back(primary_object);
147+
// グリッドIDをそのままグループIDとして使用(LODによる細分化なし)
148+
const auto group_grid_id = std::make_pair(grid_id, grid_id);
149+
if (result.find(group_grid_id) == result.end())
150+
result[group_grid_id] = std::list<const citygml::CityObject*>();
151+
152+
result.at(group_grid_id).push_back(primary_object);
137153
}
138154
}
139155

140-
// グループごとにメッシュを結合します。
156+
return result;
157+
}
158+
159+
/**
160+
* グループ化されたCityObjectsからメッシュを生成します。
161+
*/
162+
plateau::polygonMesh::GridMergeResult buildMeshesFromGroups(
163+
const GroupGridIDToObjectsMap& group_id_to_primary_objects_map,
164+
const plateau::polygonMesh::MeshExtractOptions& options,
165+
unsigned lod,
166+
const std::string& gml_path,
167+
const plateau::geometry::GeoReference& geo_reference,
168+
const std::vector<plateau::geometry::Extent>& extents) {
169+
170+
using namespace plateau::polygonMesh;
141171
auto merged_meshes = GridMergeResult();
142172

143173
// グループごとのループ
@@ -149,13 +179,13 @@ namespace plateau::polygonMesh {
149179
for (const auto& primary_object : primary_objects) {
150180
if(MeshExtractor::isTypeToSkip(primary_object->getType())) continue;
151181
if (MeshExtractor::shouldContainPrimaryMesh(lod, *primary_object)) {
152-
mesh_factory.addPolygonsInPrimaryCityObject(*primary_object, lod, city_model.getGmlPath());
182+
mesh_factory.addPolygonsInPrimaryCityObject(*primary_object, lod, gml_path);
153183
}
154184

155185
if (lod >= 2) {
156186
// 主要地物の子である各最小地物をメッシュに加えます。
157187
auto atomic_objects = PolygonMeshUtils::getChildCityObjectsRecursive(*primary_object);
158-
mesh_factory.addPolygonsInAtomicCityObjects(*primary_object, atomic_objects, lod, city_model.getGmlPath());
188+
mesh_factory.addPolygonsInAtomicCityObjects(*primary_object, atomic_objects, lod, gml_path);
159189
}
160190
mesh_factory.incrementPrimaryIndex();
161191
}
@@ -164,67 +194,68 @@ namespace plateau::polygonMesh {
164194
}
165195
return merged_meshes;
166196
}
197+
}
198+
199+
namespace plateau::polygonMesh {
200+
using namespace citygml;
201+
202+
GridMergeResult
203+
AreaMeshFactory::gridMerge(const CityModel& city_model, const MeshExtractOptions& options, unsigned lod,
204+
const geometry::GeoReference& geo_reference, const std::vector<plateau::geometry::Extent>& extents) {
205+
// city_model に含まれる 主要地物 をグリッドに分類します。
206+
const auto& all_primary_city_objects =
207+
city_model.getAllCityObjectsOfType(PrimaryCityObjectTypes::getPrimaryTypeMask());
208+
const auto& city_envelope = city_model.getEnvelope();
209+
auto grid_id_to_primary_objects_map = classifyCityObjectsToGrid(all_primary_city_objects, city_envelope, options, extents);
210+
211+
// グリッドをさらに分割してグループにします。
212+
// グループの分割基準:
213+
// 仕様上存在しうる最大LODをm として、各オブジェクトを次のグループに分けます。
214+
// - 同じオブジェクトが (0, 1, 2, ..., m) のLODであるポリゴンをどれも有する つまり 全LODに対応する
215+
// - 同じオブジェクトが (0, 1, 2, ..., m-1) のLODであるポリゴンをどれも有し、mを有しない つまり 最大LODを除く全LODに対応する
216+
// - ...
217+
// - 同じオブジェクトが (0, 1) のLODであるポリゴンをどれも有し、(2, 3, ..., m)のLODであるポリゴンをどれも有しない つまり LOD 0, 1のみに対応する
218+
// - 同じオブジェクトが (0) のLODであるポリゴンを有し、(1, 2, 3, ..., m) のLODであるポリゴンをどれも有しない つまり LOD 0 のみに対応する
219+
// 今の仕様上、mは3なので、各グリッドは最大4つに分割されます。
220+
// したがって、grid 0 と group 0 to 3 が対応します。 grid1 と group 4 to 7 が対応します。
221+
// 一般化すると、 grid i と group (i*m) to (i*(m+1)-1)が対応します。
222+
// 仕様上、あるオブジェクトのLOD i が存在すれば、同じオブジェクトの lod 0 to i-1 がすべて存在します。したがって、各オブジェクトは必ず上記グループのどれか1つに該当するはずです。
223+
// そのようにグループ分けする利点は、
224+
// 「高いLODを表示したが、低いLODにしか対応していない箇所が穴になってしまう」という状況で、穴をちょうど埋める範囲の低LODグループが存在することです。
225+
auto group_id_to_primary_objects_map = GroupGridIDToObjectsMap();
226+
227+
// 各グリッドをLODでグループ化
228+
for (const auto& [grid_id, primary_objects_in_grid] : grid_id_to_primary_objects_map) {
229+
auto grouped = groupByLod(primary_objects_in_grid, grid_id, options, lod);
230+
group_id_to_primary_objects_map.insert(grouped.begin(), grouped.end());
231+
}
232+
233+
// グループごとにメッシュを結合
234+
return buildMeshesFromGroups(group_id_to_primary_objects_map, options, lod, city_model.getGmlPath(), geo_reference, extents);
235+
}
167236

168237
GridMergeResult
169238
AreaMeshFactory::combine(const CityModelVector& city_models, const MeshExtractOptions& options, unsigned lod,
170239
const plateau::geometry::GeoReference& geo_reference, const std::vector<plateau::geometry::Extent>& extents) {
171240

172241
const auto& gmlPath = city_models->empty() || city_models->front().expired() ? "" : city_models->front().lock()->getGmlPath();
173-
std::shared_ptr <std::vector<const CityObject*>> all_primary_city_objects = std::make_shared<std::vector<const CityObject*>>();
174242

243+
std::list<const CityObject*> all_primary_city_objects;
175244
const auto& _city_models = *city_models;
176245
for (const auto& city_model : _city_models) {
177-
178246
if (city_model.expired()) continue; // 参照が切れている場合はスキップ
179247

180248
auto city_objects =
181249
city_model.lock()->getAllCityObjectsOfType(PrimaryCityObjectTypes::getPrimaryTypeMask());
182250

183-
all_primary_city_objects->insert(all_primary_city_objects->end(),
251+
all_primary_city_objects.insert(all_primary_city_objects.end(),
184252
city_objects.begin(), city_objects.end());
185253
}
186254

187-
auto merged_meshes = GridMergeResult();
188-
189-
// メッシュ生成
190-
MeshFactory mesh_factory(nullptr, options, extents, geo_reference);
255+
// LODでグループ化(grid_id = 0 として扱う)
256+
auto group_id_to_primary_objects_map = groupByLod(all_primary_city_objects, 0, options, lod);
191257

192-
// グループ内の各主要地物のループ
193-
const auto& all_primary_city_objects_in_model = *all_primary_city_objects;
194-
for (const auto& primary_object : all_primary_city_objects_in_model) {
195-
196-
if (options.highest_lod_only) {
197-
// highest_lod_only オプションが有効な場合、最大LODのみを対象とします。
198-
unsigned max_lod_in_obj = PolygonMeshUtils::max_lod_in_specification_;
199-
for (unsigned target_lod = lod + 1; target_lod <= PolygonMeshUtils::max_lod_in_specification_; ++target_lod) {
200-
bool target_lod_exists =
201-
PolygonMeshUtils::findFirstPolygon(primary_object, target_lod) != nullptr;
202-
if (!target_lod_exists) {
203-
max_lod_in_obj = target_lod - 1;
204-
break;
205-
}
206-
}
207-
if (lod != max_lod_in_obj) {
208-
// 最大LOD以外はスキップします。
209-
continue;
210-
}
211-
}
212-
213-
if (MeshExtractor::isTypeToSkip(primary_object->getType())) continue;
214-
if (MeshExtractor::shouldContainPrimaryMesh(lod, *primary_object)) {
215-
mesh_factory.addPolygonsInPrimaryCityObject(*primary_object, lod, gmlPath);
216-
}
217-
218-
if (lod >= 2) {
219-
// 主要地物の子である各最小地物をメッシュに加えます。
220-
auto atomic_objects = PolygonMeshUtils::getChildCityObjectsRecursive(*primary_object);
221-
mesh_factory.addPolygonsInAtomicCityObjects(*primary_object, atomic_objects, lod, gmlPath);
222-
}
223-
mesh_factory.incrementPrimaryIndex();
224-
}
225-
mesh_factory.optimizeMesh();
226-
merged_meshes.emplace(std::make_pair(0,0), mesh_factory.releaseMesh());
227-
228-
return merged_meshes;
258+
// グループごとにメッシュを結合
259+
return buildMeshesFromGroups(group_id_to_primary_objects_map, options, lod, gmlPath, geo_reference, extents);
229260
}
230261
}

0 commit comments

Comments
 (0)