Add interface sidecar writeback

Port the streamed-model sidecar writeback path into the interface, including packed element metadata, georef persistence, LOD generation, and viewport LOD application.

Generated with the assistance of an AI coding tool.
This commit is contained in:
Dion Moult
2026-05-14 10:06:19 +10:00
parent a755e96c13
commit cee2dbcc85
4 changed files with 80 additions and 0 deletions
+11
View File
@@ -53,6 +53,17 @@ void ElementRegistry::removeModel(uint32_t model_id) {
}
}
std::vector<BasicElementInfo> ElementRegistry::basicElementInfoForModel(uint32_t model_id) const {
std::vector<BasicElementInfo> result;
result.reserve(elements_.size());
for (const auto& [object_id, info] : elements_) {
(void)object_id;
if (info.model_id != model_id) continue;
result.push_back(info);
}
return result;
}
std::optional<BasicElementInfo> ElementRegistry::findBasicElementInfo(uint32_t object_id) const {
auto it = elements_.find(object_id);
if (it == elements_.end()) return std::nullopt;
+1
View File
@@ -53,6 +53,7 @@ public:
void bindLoader(SceneLoader* loader);
void clear();
void removeModel(uint32_t model_id);
std::vector<BasicElementInfo> basicElementInfoForModel(uint32_t model_id) const;
std::optional<BasicElementInfo> findBasicElementInfo(uint32_t object_id) const;
std::optional<express::Base> findEntity(uint32_t object_id) const;
@@ -27,14 +27,20 @@
#include "../../SessionState.h"
#include "AddModelDialog.h"
#include "../../../ifcviewer/Federation.h"
#include "../../../ifcviewer/LodBuilder.h"
#include "../../../ifcviewer/SceneLoader.h"
#include "../../../ifcviewer/SidecarCache.h"
#include "../../../ifcviewer/ViewportWindow.h"
#include <QElapsedTimer>
#include <QFileDialog>
#include <QDebug>
#include <QListView>
#include <QMessageBox>
#include <QTreeView>
#include <Eigen/Dense>
namespace ifcinterface::modules::models {
ModelsPanelController::ModelsPanelController(QWidget* host,
@@ -102,6 +108,7 @@ void ModelsPanelController::bindLoader(SceneLoader* loader) {
});
connect(loader, &SceneLoader::loadedFromStream, this,
[this, loader](uint32_t mid, qint64 elapsed_ms) {
writeSidecarForModel(loader, mid);
session_state_->setStatusMessage(
"Loaded",
QString("%1 streamed in %2")
@@ -226,4 +233,64 @@ QString ModelsPanelController::formatElapsed(qint64 ms) const {
: QString::number(ms) + " ms";
}
void ModelsPanelController::writeSidecarForModel(SceneLoader* loader, uint32_t mid) const {
if (!loader || !viewport_ || !session_state_) return;
SidecarData sidecar_data;
if (!viewport_->snapshotModel(mid, sidecar_data)) return;
if (const ModelGeoref* georef = loader->modelGeoref(mid)) {
sidecar_data.has_coordinate_operation = georef->has_coordinate_operation ? 1 : 0;
Eigen::Map<Eigen::Matrix<double, 4, 4, Eigen::ColMajor>>(
sidecar_data.coordinate_operation_meters) = georef->coordinate_operation_meters;
sidecar_data.project_length_to_meters = georef->units.project_length_to_meters;
sidecar_data.map_unit_to_meters = georef->units.map_unit_to_meters;
}
auto* element_registry = session_state_->elementRegistry();
if (element_registry) {
for (const auto& info : element_registry->basicElementInfoForModel(mid)) {
PackedElementInfo packed;
packed.object_id = info.object_id;
packed.model_id = info.model_id;
packed.ifc_id = info.ifc_id;
packed.parent_id = info.parent_id;
const std::string guid = info.guid.toStdString();
packed.guid_offset = static_cast<uint32_t>(sidecar_data.string_table.size());
packed.guid_length = static_cast<uint32_t>(guid.size());
sidecar_data.string_table += guid;
const std::string name = info.name.toStdString();
packed.name_offset = static_cast<uint32_t>(sidecar_data.string_table.size());
packed.name_length = static_cast<uint32_t>(name.size());
sidecar_data.string_table += name;
const std::string type = info.type.toStdString();
packed.type_offset = static_cast<uint32_t>(sidecar_data.string_table.size());
packed.type_length = static_cast<uint32_t>(type.size());
sidecar_data.string_table += type;
sidecar_data.elements.push_back(packed);
}
}
QElapsedTimer lod_timer;
lod_timer.start();
buildLods(sidecar_data);
const LodStats lod_stats = summariseLods(sidecar_data);
qDebug(" LOD build: %lld ms — %u/%u meshes got LOD1 "
"(%u tris -> %u tris for those meshes)",
lod_timer.elapsed(),
lod_stats.meshes_with_lod1, lod_stats.meshes_total,
lod_stats.tris_lod0_for_lod1, lod_stats.tris_lod1);
viewport_->applyLodExtension(mid, sidecar_data);
QElapsedTimer sidecar_timer;
sidecar_timer.start();
const bool ok = writeSidecar(loader->filePath(mid).toStdString(), sidecar_data);
qDebug(" Sidecar write: %lld ms (%s)", sidecar_timer.elapsed(), ok ? "ok" : "FAILED");
}
} // namespace ifcinterface::modules::models
@@ -54,6 +54,7 @@ public:
private:
QString formatElapsed(qint64 ms) const;
void writeSidecarForModel(SceneLoader* loader, uint32_t mid) const;
QWidget* host_ = nullptr;
ModelsPanel* widget_ = nullptr;