@@ -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