Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions include/plateau/polygon_mesh/mesh_extractor.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <plateau/polygon_mesh/mesh_extract_options.h>
#include <plateau/geometry/geo_coordinate.h>
#include "citygml/citymodel.h"
#include "citygml/citygmllogger.h"
#include "model.h"

namespace plateau::polygonMesh {
Expand Down Expand Up @@ -33,6 +34,7 @@ namespace plateau::polygonMesh {
* 生ポインタのdeleteはDLLの利用者の責任です。
*/
static void extract(Model& out_model, const citygml::CityModel& city_model, const MeshExtractOptions& options);
static void extract(Model& out_model, const citygml::CityModel& city_model, const MeshExtractOptions& options, const std::shared_ptr<citygml::CityGMLLogger>& logger);

/**
* CityModelから範囲内のModelを取り出します。
Expand All @@ -43,6 +45,7 @@ namespace plateau::polygonMesh {
* CityModelから範囲内のModelを取り出します。
*/
static void extractInExtents(Model& out_model, const citygml::CityModel& city_model, const MeshExtractOptions& options, const std::vector<plateau::geometry::Extent>& extents);
static void extractInExtents(Model& out_model, const citygml::CityModel& city_model, const MeshExtractOptions& options, const std::vector<plateau::geometry::Extent>& extents, const std::shared_ptr<citygml::CityGMLLogger>& logger);

/**
* 引数で与えられた LOD の主要地物について、次を判定して bool で返します。
Expand Down
20 changes: 20 additions & 0 deletions src/c_wrapper/mesh_extractor_c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "city_model_c.h"
#include <plateau/polygon_mesh/mesh_extractor.h>
#include <plateau/geometry/geo_coordinate.h>
#include <plateau_dll_logger.h>

using namespace libplateau;
using namespace plateau::polygonMesh;
Expand Down Expand Up @@ -43,4 +44,23 @@ extern "C"{
API_CATCH;
return APIResult::ErrorUnknown;
}

LIBPLATEAU_C_EXPORT APIResult LIBPLATEAU_C_API plateau_mesh_extractor_extract_in_extents_with_log(
const CityModelHandle* const city_model_handle,
const MeshExtractOptions options,
const std::vector<plateau::geometry::Extent>* extents,
Model* const out_model,
const DllLogLevel logLevel,
LogCallbackFuncPtr logErrorCallback,
LogCallbackFuncPtr logWarnCallback,
LogCallbackFuncPtr logInfoCallback) {
API_TRY{
auto logger = std::make_shared<PlateauDllLogger>(logLevel);
logger->setLogCallbacks(logErrorCallback, logWarnCallback, logInfoCallback);
MeshExtractor::extractInExtents(*out_model, city_model_handle->getCityModel(), options, *extents, logger);
return APIResult::Success;
}
API_CATCH;
return APIResult::ErrorUnknown;
}
}
64 changes: 59 additions & 5 deletions src/polygon_mesh/mesh_extractor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
#include <plateau/polygon_mesh/polygon_mesh_utils.h>
#include <plateau/dataset/gml_file.h>
#include <plateau/texture/texture_packer.h>
#include <chrono>

#include "plateau_dll_logger.h"

namespace {
using namespace plateau;
Expand All @@ -17,6 +20,34 @@ namespace {
using namespace citygml;
namespace fs = std::filesystem;

class Stopwatch {
public:
Stopwatch(std::shared_ptr<citygml::CityGMLLogger> logger, const std::string& task_name)
: logger_(std::move(logger)), task_name_(task_name) {
total_start_time_ = std::chrono::steady_clock::now();
stage_start_time_ = total_start_time_;
logger_->log(citygml::CityGMLLogger::LOGLEVEL::LL_INFO, task_name_ + " start.");
}

~Stopwatch() {
const auto total_duration = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - total_start_time_).count();
logger_->log(citygml::CityGMLLogger::LOGLEVEL::LL_INFO, task_name_ + " finished. Total: " + std::to_string(total_duration) + "ms");
}

void log_stage(const std::string& stage_name) {
const auto end_time = std::chrono::steady_clock::now();
const auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - stage_start_time_).count();
logger_->log(citygml::CityGMLLogger::LOGLEVEL::LL_INFO, " " + stage_name + " : " + std::to_string(duration) + "ms");
stage_start_time_ = end_time;
}

private:
std::shared_ptr<citygml::CityGMLLogger> logger_;
std::string task_name_;
std::chrono::steady_clock::time_point total_start_time_;
std::chrono::steady_clock::time_point stage_start_time_;
};
Comment on lines +23 to +49
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Stopwatch のデストラクタでの例外安全性に注意が必要です。

デストラクタ内で logger_->log() を呼び出していますが、スタックアンワインド中にこのデストラクタが呼ばれた場合、log メソッドが例外を投げると std::terminate() が呼ばれてしまいます。

以下のように noexcept 指定と try-catch で保護することを推奨します:

-    ~Stopwatch() {
+    ~Stopwatch() noexcept {
+        try {
             const auto total_duration = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - total_start_time_).count();
             logger_->log(citygml::CityGMLLogger::LOGLEVEL::LL_INFO, task_name_ + " finished. Total: " + std::to_string(total_duration) + "ms");
+        } catch (...) {
+            // ログ出力に失敗しても無視する
+        }
     }
🤖 Prompt for AI Agents
In src/polygon_mesh/mesh_extractor.cpp around lines 23 to 49, the Stopwatch
destructor calls logger_->log() which can throw during stack unwinding and cause
std::terminate; make the destructor noexcept and wrap its logging calls in a
try-catch block (catch all exceptions) while optionally checking logger_ for
null before use; do the same protection for any final logging in the destructor,
and consider using non-throwing logging helpers or std::terminate-safe fallback
if logging fails.


bool shouldSkipCityObj(const CityObject& city_obj, const MeshExtractOptions& options, const std::vector<geometry::Extent>& extents) {

// 範囲内であっても、COT_Roomは意図的に省きます。なぜなら、LOD4の建物においてRoomと天井、床等が完全に重複するのをなくしたいからです。
Expand All @@ -36,14 +67,25 @@ namespace {
void extractInner(
Model& out_model, const CityModel& city_model,
const MeshExtractOptions& options,
const std::vector<geometry::Extent>& extents_before_adjust) {
const std::vector<geometry::Extent>& extents_before_adjust,
std::shared_ptr<citygml::CityGMLLogger> logger) {

if (options.max_lod < options.min_lod) throw std::logic_error("Invalid LOD range.");
if (logger == nullptr) {
logger = std::make_shared<PlateauDllLogger>();
}

Stopwatch stopwatch(logger, "MeshExtractor");

if (options.max_lod < options.min_lod) {
logger->log(citygml::CityGMLLogger::LOGLEVEL::LL_ERROR, "Invalid LOD range.");
throw std::logic_error("Invalid LOD range.");
}

const auto geo_reference = geometry::GeoReference(options.coordinate_zone_id, options.reference_point, options.unit_scale, options.mesh_axes);

// 範囲の境界上にある地物を取り逃さないように、範囲を少し広げます。
auto extents = MeshExtractor::extendExtents(extents_before_adjust, 1.2f);
stopwatch.log_stage("Initialize");

// rootNode として LODノード を作ります。
for (unsigned lod = options.min_lod; lod <= options.max_lod; lod++) {
Expand Down Expand Up @@ -143,23 +185,27 @@ namespace {

out_model.addNode(std::move(lod_node));
}
stopwatch.log_stage("LOD loop");
out_model.eraseEmptyNodes();
out_model.assignNodeHierarchy();
stopwatch.log_stage("Node arrange");

// テクスチャを結合します。
if (options.enable_texture_packing) {
TexturePacker packer(options.texture_packing_resolution, options.texture_packing_resolution);
packer.process(out_model);
}
stopwatch.log_stage("Texture packing");

// 現在の都市モデルが地形であるなら、衛星写真または地図用のUVを付与し、地図タイルをダウンロードします。
auto package = GmlFile(city_model.getGmlPath()).getPackage();
if(package == PredefinedCityModelPackage::Relief && options.attach_map_tile) {
const auto gml_path = fs::u8path(city_model.getGmlPath());
const auto map_download_dest = gml_path.parent_path() / (gml_path.filename().u8string() + "_map");
MapAttacher().attach(out_model, options.map_tile_url, map_download_dest, options.map_tile_zoom_level,
geo_reference);
geo_reference);
}
stopwatch.log_stage("Map attach");
}
}

Expand All @@ -173,7 +219,11 @@ namespace plateau::polygonMesh {

void MeshExtractor::extract(Model& out_model, const CityModel& city_model,
const MeshExtractOptions& options) {
extractInner(out_model, city_model, options, { plateau::geometry::Extent::all() });
extractInner(out_model, city_model, options, { plateau::geometry::Extent::all() }, nullptr);
}

void MeshExtractor::extract(Model& out_model, const citygml::CityModel& city_model, const MeshExtractOptions& options, const std::shared_ptr<citygml::CityGMLLogger>& logger) {
extractInner(out_model, city_model, options, { plateau::geometry::Extent::all() }, logger);
}

std::shared_ptr<Model> MeshExtractor::extractInExtents(
Expand All @@ -190,7 +240,11 @@ namespace plateau::polygonMesh {
const MeshExtractOptions& options,
const std::vector<plateau::geometry::Extent>& extents) {

extractInner(out_model, city_model, options, extents);
extractInner(out_model, city_model, options, extents, nullptr);
}

void MeshExtractor::extractInExtents(Model& out_model, const citygml::CityModel& city_model, const MeshExtractOptions& options, const std::vector<plateau::geometry::Extent>& extents, const std::shared_ptr<citygml::CityGMLLogger>& logger) {
extractInner(out_model, city_model, options, extents, logger);
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,22 @@ public static void Extract(ref Model outModel, CityModel cityModel, MeshExtractO
/// 結果は <paramref name="outModel"/> に格納されます。
/// 通常、<paramref name="outModel"/> には new したばかりの Model を渡してください。
/// </summary>
public static void ExtractInExtents(ref Model outModel, CityModel cityModel, MeshExtractOptions options, List<Extent> extents)
public static void ExtractInExtents(ref Model outModel, CityModel cityModel, MeshExtractOptions options, List<Extent> extents,
LogCallbacks logCallbacks = null, DllLogLevel logLevel = DllLogLevel.Error)
{
if (logCallbacks == null)
{
logCallbacks = LogCallbacks.StdOut;
}
var nativeExtents = NativeVectorExtent.Create();
foreach (var extent in extents)
{
nativeExtents.Add(extent);
}

var result = NativeMethods.plateau_mesh_extractor_extract_in_extents(
cityModel.Handle, options, nativeExtents.Handle, outModel.Handle
var result = NativeMethods.plateau_mesh_extractor_extract_in_extents_with_log(
cityModel.Handle, options, nativeExtents.Handle, outModel.Handle, logLevel,
logCallbacks.LogErrorFuncPtr, logCallbacks.LogWarnFuncPtr, logCallbacks.LogInfoFuncPtr
);
DLLUtil.CheckDllError(result);
}
Expand All @@ -60,6 +66,18 @@ internal static extern APIResult plateau_mesh_extractor_extract_in_extents(
MeshExtractOptions options,
[In] IntPtr extentsPtr,
[In] IntPtr outModelPtr);

[DllImport(DLLUtil.DllName)]
internal static extern APIResult plateau_mesh_extractor_extract_in_extents_with_log(
[In] IntPtr cityModelPtr,
MeshExtractOptions options,
[In] IntPtr extentsPtr,
[In] IntPtr outModelPtr,
DllLogLevel logLevel,
[In] IntPtr logErrorCallback,
[In] IntPtr logWarnCallback,
[In] IntPtr logInfoCallback
);
}
}
}