Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
27180fe
複数GML結合機能
sevendev Jul 2, 2025
402c6f6
weak_ptrに変更(意味ないかも)
sevendev Jul 4, 2025
1bac893
結合時、最大LODのみを含める
sevendev Jul 4, 2025
26d76e9
最大LODのみGrid Merge , Group id ではなくGrid id を使う
sevendev Jul 7, 2025
b655432
city_modelのgrid分けの処理もTile extractorで行う
sevendev Jul 7, 2025
c15deec
Grid id ごとに階層化
sevendev Jul 7, 2025
69f1c86
Model/Node側のメソッドでchild node 有無判定( Mapを使わない )
sevendev Jul 8, 2025
03a811b
group / grid id を両方渡す
sevendev Jul 8, 2025
cf0dff1
Grid名変更
sevendev Jul 10, 2025
fd40c85
Grid名変更
sevendev Aug 18, 2025
70432d8
AIコメント対応
sevendev Aug 19, 2025
4db4a48
AIコメント対応
sevendev Aug 19, 2025
528a6ed
nitpickコメント対応
sevendev Aug 19, 2025
857913a
AIコメント対応
sevendev Aug 19, 2025
20735ae
AIコメント対応
sevendev Aug 19, 2025
e6fafaf
コメント変更
sevendev Aug 19, 2025
b5bc42c
AIコメント対応
sevendev Aug 19, 2025
fd86c9e
Unit Testが通らないので元の仕様にRevert
sevendev Aug 19, 2025
31a127d
コメント変更
sevendev Aug 19, 2025
cfd7877
refactor
sevendev Aug 20, 2025
1f3ff96
Added Unit Test.
sevendev Aug 20, 2025
dd4e68b
C#libでTestが通らなくなるのでudxのパス変更
sevendev Aug 20, 2025
625bfc9
nitpick対応
sevendev Aug 21, 2025
f02038d
nitpick対応
sevendev Aug 21, 2025
0c051e8
githubでwinのbuildが完了しないため.net standard 2.0にrevert
sevendev Aug 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion include/plateau/polygon_mesh/mesh_extract_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ namespace plateau::polygonMesh {
attach_map_tile(true),
map_tile_zoom_level(15),
map_tile_url("https://cyberjapandata.gsi.go.jp/xyz/seamlessphoto/{z}/{x}/{y}.jpg"),
epsg_code(plateau::geometry::CoordinateReferenceFactory::default_epsg)
epsg_code(plateau::geometry::CoordinateReferenceFactory::default_epsg),
highest_lod_only(false)
{}
Comment thread
sevendev marked this conversation as resolved.

public:
Expand Down Expand Up @@ -117,5 +118,13 @@ namespace plateau::polygonMesh {
* 平面直角座標系は、EPSGコードに応じて基準点を取得します。
*/
int epsg_code;

/**
* 最高LODのみを抽出するかどうかを指定します。
* true の場合、min_lod..max_lod の範囲のうち最大のLOD(= max_lod)に相当するポリゴンのみを抽出し、
* 他のLODは無視します。false の場合、min_lod から max_lod までの範囲のポリゴンを抽出します。
* (もし「データセット内で検出された実在の最大LOD」のみを対象にする仕様であれば、その旨に書き換えてください)
*/
bool highest_lod_only;
};
}
2 changes: 2 additions & 0 deletions include/plateau/polygon_mesh/mesh_extractor.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,7 @@ namespace plateau::polygonMesh {
*/
static bool shouldContainPrimaryMesh(unsigned lod, const citygml::CityObject& primary_obj);
static bool isTypeToSkip(citygml::CityObject::CityObjectsType type);

static std::vector<plateau::geometry::Extent> extendExtents(const std::vector<plateau::geometry::Extent>& src_extents, float multiplier);
};
}
1 change: 1 addition & 0 deletions include/plateau/polygon_mesh/model.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ namespace plateau::polygonMesh {

Node& getRootNodeAt(size_t index);
const Node& getRootNodeAt(size_t index) const;
const int getRootNodeIndexByName(const std::string& name) const;

/// 各ノードのペアレント、ルートを設定します。
void assignNodeHierarchy();
Expand Down
2 changes: 2 additions & 0 deletions include/plateau/polygon_mesh/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ namespace plateau::polygonMesh {
Node& getChildAt(unsigned int index);
const Node& getChildAt(unsigned int index) const;

int getChildIndexByName(const std::string& name) const; // 見つからない場合は -1 を返す

/// Parent Node設定
void setParentNode(Node* node);
const Node& getParentNode() const; //Model.assignNodeHierarchyを呼ぶことで取得可能になります。
Expand Down
9 changes: 9 additions & 0 deletions include/plateau/polygon_mesh/polygon_mesh_types.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#pragma once

#include <memory>
#include <vector>

namespace plateau::polygonMesh {
class citygml::CityModel;
using CityModelVector = std::shared_ptr<std::vector<std::weak_ptr<const citygml::CityModel>>>;
}
Comment thread
sevendev marked this conversation as resolved.
47 changes: 47 additions & 0 deletions include/plateau/polygon_mesh/tile_extractor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#pragma once

#include <plateau/polygon_mesh/mesh_extractor.h>
#include <plateau/polygon_mesh/polygon_mesh_types.h>
#include <libplateau_api.h>
#include <memory>
#include "citygml/citymodel.h"
#include "model.h"

namespace plateau::polygonMesh {

/**
* TileExtractorは、複数のCityModelからメッシュを抽出し、指定された範囲(extents)に基づいて結合メッシュを抽出するクラスです。
*
*/
class LIBPLATEAU_EXPORT TileExtractor : public MeshExtractor {
public:

/**
* CityModelのリストを結合し範囲内のModelを取り出します。
*/
static std::shared_ptr<Model> extractWithCombine(
const CityModelVector& city_models, const MeshExtractOptions& options,
const std::vector<plateau::geometry::Extent>& extents);

/**
* CityModelのリストを結合し範囲内のModelを取り出します。
*/
static void extractWithCombine(Model& out_model,
const CityModelVector& city_models, const MeshExtractOptions& options,
const std::vector<plateau::geometry::Extent>& extents);

/**
* CityModelから範囲内のModelを取り出しグリッド分割します。
*/
static std::shared_ptr<Model> extractWithGrid(
const citygml::CityModel& city_model, const MeshExtractOptions& options,
const std::vector<plateau::geometry::Extent>& extents);

/**
* CityModelから範囲内のModelを取り出しグリッド分割します。
*/
static void extractWithGrid(Model& out_model,
const citygml::CityModel& city_model, const MeshExtractOptions& options,
const std::vector<plateau::geometry::Extent>& extents);
};
}
4 changes: 3 additions & 1 deletion src/c_wrapper/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ add_library(c_wrapper OBJECT
"height_map_aligner_c.cpp"
"material_adjuster_by_attr.cpp"
"material_adjuster_by_type_c.cpp"
"heightmap_mesh_generator_c.cpp")
"heightmap_mesh_generator_c.cpp"
"tile_extractor_c.cpp"
)

if(NOT(IOS OR ANDROID))
# 非モバイル向け
Expand Down
74 changes: 74 additions & 0 deletions src/c_wrapper/tile_extractor_c.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#include "libplateau_c.h"
#include "city_model_c.h"
#include <plateau/polygon_mesh/tile_extractor.h>

using namespace libplateau;
using namespace plateau::polygonMesh;

extern "C"{

LIBPLATEAU_C_EXPORT APIResult LIBPLATEAU_C_API plateau_tile_extractor_extract_with_combine(
const CityModelHandle* const* city_model_handles,
const int city_model_size,
const MeshExtractOptions options,
const std::vector<plateau::geometry::Extent>* extents,
Model* const out_model) {
API_TRY{

if (out_model == nullptr || extents == nullptr) {
return APIResult::ErrorInvalidArgument;
}
if (city_model_size < 0) {
return APIResult::ErrorInvalidArgument;
}
if (city_model_size > 0 && city_model_handles == nullptr) {
return APIResult::ErrorInvalidArgument;
}

CityModelVector city_models = std::make_shared<std::vector<std::weak_ptr<const citygml::CityModel>>>();
city_models->reserve(static_cast<size_t>(city_model_size));
for (int i = 0; i < city_model_size; ++i) {
if (!city_model_handles[i]) {
continue; // nullptr の場合はスキップ
}
auto ptr = city_model_handles[i]->getCityModelPtr(); // 共有所有権を値で受ける
if (!ptr) {
continue; // 空の shared_ptr はスキップ
}
std::weak_ptr<const citygml::CityModel> weak = ptr;
city_models->push_back(weak);
}

if (city_models->empty()) {
// 入力に有効な CityModel が含まれていない
return APIResult::ErrorInvalidArgument;
}

TileExtractor::extractWithCombine(*out_model, city_models, options, *extents);
return APIResult::Success;

}
API_CATCH;
return APIResult::ErrorUnknown;
}

LIBPLATEAU_C_EXPORT APIResult LIBPLATEAU_C_API plateau_tile_extractor_extract_with_grid(
const CityModelHandle* const city_model_handle,
const MeshExtractOptions options,
const std::vector<plateau::geometry::Extent>* extents,
Model* const out_model) {
API_TRY{
if (out_model == nullptr || extents == nullptr || city_model_handle == nullptr) {
return APIResult::ErrorInvalidArgument;
}
auto cityModelPtr = city_model_handle->getCityModelPtr();
if (!cityModelPtr) {
return APIResult::ErrorInvalidArgument;
}
TileExtractor::extractWithGrid(*out_model, *cityModelPtr, options, *extents);
return APIResult::Success;
}
API_CATCH;
return APIResult::ErrorUnknown;
}
}
1 change: 1 addition & 0 deletions src/polygon_mesh/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ target_sources(plateau PRIVATE
"city_object_list.cpp"
"map_attacher.cpp"
"transform.cpp"
"tile_extractor.cpp"
)
89 changes: 82 additions & 7 deletions src/polygon_mesh/area_mesh_factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <plateau/polygon_mesh/primary_city_object_types.h>
#include <plateau/polygon_mesh/mesh_factory.h>
#include <plateau/polygon_mesh/polygon_mesh_utils.h>
#include <plateau/polygon_mesh/tile_extractor.h>

namespace {
using namespace plateau;
Expand All @@ -13,7 +14,7 @@ namespace {
* グリッド番号と、そのグリッドに属する CityObject のリストを対応付ける辞書です。
*/
using GridIDToObjectsMap = std::map<unsigned, std::list<const citygml::CityObject*>>;
using GroupIDToObjectsMap = GridIDToObjectsMap;
using GroupGridIDToObjectsMap = std::map<std::pair<unsigned, unsigned>, std::list<const citygml::CityObject*>>;

bool shouldSkipCityObj(const citygml::CityObject& city_obj, const MeshExtractOptions& options, const std::vector<geometry::Extent>& extents) {
if (!options.exclude_city_object_outside_extent)
Expand Down Expand Up @@ -104,7 +105,7 @@ namespace plateau::polygonMesh {
// 仕様上、あるオブジェクトのLOD i が存在すれば、同じオブジェクトの lod 0 to i-1 がすべて存在します。したがって、各オブジェクトは必ず上記グループのどれか1つに該当するはずです。
// そのようにグループ分けする利点は、
// 「高いLODを表示したが、低いLODにしか対応していない箇所が穴になってしまう」という状況で、穴をちょうど埋める範囲の低LODグループが存在することです。
auto group_id_to_primary_objects_map = GroupIDToObjectsMap();
auto group_id_to_primary_objects_map = GroupGridIDToObjectsMap();
for (const auto& [grid_id, primary_objects_in_grid] : grid_id_to_primary_objects_map) {
for (const auto& primary_object : primary_objects_in_grid) {
// この CityObject について、最大でどのLODまで存在するか確認します。
Expand All @@ -117,19 +118,30 @@ namespace plateau::polygonMesh {
break;
}
}

if (options.highest_lod_only) {
// highest_lod_only オプションが有効な場合、最大LODのみを対象とします。
if (lod != max_lod_in_obj) {
// 最大LOD以外はスキップします。
continue;
}
}

// グループに追加します。
unsigned group_id = grid_id * (PolygonMeshUtils::max_lod_in_specification_ + 1) + max_lod_in_obj;
if (group_id_to_primary_objects_map.find(group_id) == group_id_to_primary_objects_map.end())
group_id_to_primary_objects_map[group_id] = std::list<const CityObject*>();
const auto group_grid_id = std::make_pair(group_id, grid_id);
if (group_id_to_primary_objects_map.find(group_grid_id) == group_id_to_primary_objects_map.end())
group_id_to_primary_objects_map[group_grid_id] = std::list<const CityObject*>();

group_id_to_primary_objects_map.at(group_id).push_back(primary_object);
group_id_to_primary_objects_map.at(group_grid_id).push_back(primary_object);
}
}

// グループごとにメッシュを結合します。
auto merged_meshes = GridMergeResult();

// グループごとのループ
for (const auto& [group_id, primary_objects] : group_id_to_primary_objects_map) {
for (const auto& [id, primary_objects] : group_id_to_primary_objects_map) {
// 1グループのメッシュ生成
MeshFactory mesh_factory(nullptr, options, extents, geo_reference);

Expand All @@ -148,8 +160,71 @@ namespace plateau::polygonMesh {
mesh_factory.incrementPrimaryIndex();
}
mesh_factory.optimizeMesh();
merged_meshes.emplace(group_id, mesh_factory.releaseMesh());
merged_meshes.emplace(id, mesh_factory.releaseMesh());
}
return merged_meshes;
}

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

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

const auto& _city_models = *city_models;
for (const auto& city_model : _city_models) {

if (city_model.expired()) continue; // 参照が切れている場合はスキップ

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

all_primary_city_objects->insert(all_primary_city_objects->end(),
city_objects.begin(), city_objects.end());
}

auto merged_meshes = GridMergeResult();

// メッシュ生成
MeshFactory mesh_factory(nullptr, options, extents, geo_reference);

// グループ内の各主要地物のループ
const auto& all_primary_city_objects_in_model = *all_primary_city_objects;
for (const auto& primary_object : all_primary_city_objects_in_model) {

if (options.highest_lod_only) {
// highest_lod_only オプションが有効な場合、最大LODのみを対象とします。
unsigned max_lod_in_obj = PolygonMeshUtils::max_lod_in_specification_;
for (unsigned target_lod = lod + 1; target_lod <= PolygonMeshUtils::max_lod_in_specification_; ++target_lod) {
bool target_lod_exists =
PolygonMeshUtils::findFirstPolygon(primary_object, target_lod) != nullptr;
if (!target_lod_exists) {
max_lod_in_obj = target_lod - 1;
break;
}
}
if (lod != max_lod_in_obj) {
// 最大LOD以外はスキップします。
continue;
}
}
Comment thread
sevendev marked this conversation as resolved.

if (MeshExtractor::isTypeToSkip(primary_object->getType())) continue;
if (MeshExtractor::shouldContainPrimaryMesh(lod, *primary_object)) {
mesh_factory.addPolygonsInPrimaryCityObject(*primary_object, lod, gmlPath);
}

if (lod >= 2) {
// 主要地物の子である各最小地物をメッシュに加えます。
auto atomic_objects = PolygonMeshUtils::getChildCityObjectsRecursive(*primary_object);
mesh_factory.addPolygonsInAtomicCityObjects(*primary_object, atomic_objects, lod, gmlPath);
}
mesh_factory.incrementPrimaryIndex();
}
mesh_factory.optimizeMesh();
merged_meshes.emplace(std::make_pair(0,0), mesh_factory.releaseMesh());

return merged_meshes;
}
}
17 changes: 14 additions & 3 deletions src/polygon_mesh/area_mesh_factory.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@

#include "citygml/citymodel.h"
#include "plateau/geometry/geo_reference.h"
#include <plateau/polygon_mesh/mesh_extractor.h>
#include <plateau/polygon_mesh/mesh.h>
#include <plateau/polygon_mesh/mesh_extract_options.h>
#include <plateau/polygon_mesh/polygon_mesh_types.h>
#include <map>
#include <memory>
#include <utility>

namespace plateau::polygonMesh {
/// グループIDと、その結合後Meshのmapです。
using GridMergeResult = std::map<unsigned, std::unique_ptr<Mesh>>;
// グループIDとグリッドIDのペアをキーとし、その結合後Meshのmapです。
// キー: std::pair<group_id, grid_id>
using GridMergeResult = std::map<std::pair<unsigned, unsigned>, std::unique_ptr<Mesh>>;
Comment thread
sevendev marked this conversation as resolved.

/**
* cityModel をグリッド状に分割し、各地物オブジェクトをグリッドに分類します。
Expand All @@ -24,5 +28,12 @@ namespace plateau::polygonMesh {
static GridMergeResult
gridMerge(const citygml::CityModel& city_model, const MeshExtractOptions& options, unsigned lod,
const plateau::geometry::GeoReference& geo_reference, const std::vector<plateau::geometry::Extent>& extents);

/**
* 複数のcity_model内のメッシュを結合して返します。
*/
static GridMergeResult
combine(const CityModelVector& city_models, const MeshExtractOptions& options, unsigned lod,
const plateau::geometry::GeoReference& geo_reference, const std::vector<plateau::geometry::Extent>& extents);
};
}
Loading
Loading