mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-19 11:43:53 +00:00
ifcviewer: gate CoordinateOperation on a settings toggle
AppSettings.applyCoordinateOperation (default false, persisted via
QSettings) controls whether each loaded model's IfcCoordinateOperation
is applied at upload time. Off keeps models in their local engineering
frame (current behaviour). On lifts each model into map coordinates
via the stage-2 georef matrix cached on SceneLoader.
MainWindow:
- applyCoordinateOperationToViewport(mid) reads the toggle, fetches
the model's ModelGeoref, and pushes either the
coordinate_operation_meters matrix or identity to the viewport.
- Called from onLoadedFromStream (streamer path) and onDataSourceReady
(sidecar-hit path, where the IFC arrives asynchronously).
- Subscribed to AppSettings::applyCoordinateOperationChanged: a
runtime toggle walks every loaded model and re-applies, so users
can flip georef on/off without reloading.
SettingsWindow gains a "Apply Coordinate Operation" checkbox alongside
the existing per-load toggles.
Default-off so the change is opt-in — users with georeferenced models
(UTM coords etc.) can flip the toggle to see them in their map frame
once they're ready. Visual verification on a real georeferenced
model still pending.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -89,6 +89,16 @@ MainWindow::MainWindow(QWidget* parent)
|
||||
if (!show) stats_label_->clear();
|
||||
});
|
||||
|
||||
// Toggling the CoordinateOperation setting walks every loaded model
|
||||
// and pushes either its georef matrix or identity to the viewport.
|
||||
connect(&AppSettings::instance(),
|
||||
&AppSettings::applyCoordinateOperationChanged,
|
||||
this, [this](bool /*enabled*/) {
|
||||
for (const auto& kv : fed_id_to_model_id_) {
|
||||
applyCoordinateOperationToViewport(kv.second);
|
||||
}
|
||||
});
|
||||
|
||||
updateWindowTitle();
|
||||
resize(1400, 900);
|
||||
}
|
||||
@@ -457,6 +467,13 @@ void MainWindow::onSidecarElementsReady(uint32_t mid,
|
||||
}
|
||||
|
||||
void MainWindow::onDataSourceReady(uint32_t mid) {
|
||||
// The IFC file is now available — push the model's CoordinateOperation
|
||||
// (or identity) to the viewport. Sidecar-hit models get here for the
|
||||
// first time; stream-loaded models also pass through here when a
|
||||
// separate data source opens, but applyCoordinateOperationToViewport
|
||||
// is idempotent so double-applying is harmless.
|
||||
applyCoordinateOperationToViewport(mid);
|
||||
|
||||
// Re-populate if the current selection belongs to this model, since
|
||||
// populateProperties() now has an ifcFile() to query.
|
||||
auto items = element_tree_->selectedItems();
|
||||
@@ -468,6 +485,18 @@ void MainWindow::onDataSourceReady(uint32_t mid) {
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::applyCoordinateOperationToViewport(uint32_t mid) {
|
||||
Eigen::Matrix4d M = Eigen::Matrix4d::Identity();
|
||||
if (AppSettings::instance().applyCoordinateOperation()) {
|
||||
if (const ModelGeoref* gr = loader_->modelGeoref(mid)) {
|
||||
if (gr->has_coordinate_operation) {
|
||||
M = gr->coordinate_operation_meters;
|
||||
}
|
||||
}
|
||||
}
|
||||
viewport_->setModelCoordinateOperation(mid, M);
|
||||
}
|
||||
|
||||
void MainWindow::onLoadedFromSidecar(uint32_t /*mid*/, qint64 elapsed_ms) {
|
||||
progress_bar_->setVisible(false);
|
||||
status_label_->setText(QString("%1 elements across %2 model(s) — loaded from cache in %3")
|
||||
@@ -572,6 +601,10 @@ void MainWindow::onLoadedFromStream(uint32_t mid, qint64 elapsed_ms) {
|
||||
.arg(loader_->modelCount())
|
||||
.arg(formatElapsed(elapsed_ms)));
|
||||
|
||||
// Stream path: the IFC is owned by the streamer, so georef is
|
||||
// computable now. (Sidecar-hit models defer to onDataSourceReady.)
|
||||
applyCoordinateOperationToViewport(mid);
|
||||
|
||||
writeSidecarForModel(mid);
|
||||
}
|
||||
|
||||
|
||||
@@ -96,6 +96,13 @@ private:
|
||||
void writeSidecarForModel(uint32_t mid);
|
||||
void removeModelUi(uint32_t mid);
|
||||
void applyPendingBenchmark();
|
||||
|
||||
// Push a model's CoordinateOperation matrix to the viewport (or
|
||||
// identity, when the AppSettings toggle is off or the model has no
|
||||
// map conversion). No-op if the model isn't yet known to the loader
|
||||
// or its IFC file isn't available (sidecar-hit before data-source
|
||||
// load); the call retries on onDataSourceReady.
|
||||
void applyCoordinateOperationToViewport(uint32_t mid);
|
||||
QString formatElapsed(qint64 ms) const;
|
||||
|
||||
ViewportWindow* viewport_ = nullptr;
|
||||
|
||||
@@ -59,6 +59,14 @@ void SettingsWindow::setupUi() {
|
||||
"and, on sidecar hits, avoids a second file read.");
|
||||
form->addRow("Load Property Data Source", load_data_source_check_);
|
||||
|
||||
apply_coordinate_operation_check_ = new QCheckBox(this);
|
||||
apply_coordinate_operation_check_->setToolTip(
|
||||
"Apply each model's IfcCoordinateOperation (e.g. IfcMapConversion) "
|
||||
"after load so it lands in georeferenced map coordinates. "
|
||||
"Disable to keep models in their local engineering frame.");
|
||||
form->addRow("Apply Coordinate Operation",
|
||||
apply_coordinate_operation_check_);
|
||||
|
||||
void_limit_spin_ = new QSpinBox(this);
|
||||
void_limit_spin_->setRange(0, 100000);
|
||||
void_limit_spin_->setToolTip(
|
||||
@@ -109,6 +117,8 @@ void SettingsWindow::syncFromSettings() {
|
||||
show_stats_check_->setChecked(AppSettings::instance().showStats());
|
||||
backface_culling_check_->setChecked(AppSettings::instance().backfaceCulling());
|
||||
load_data_source_check_->setChecked(AppSettings::instance().loadDataSource());
|
||||
apply_coordinate_operation_check_->setChecked(
|
||||
AppSettings::instance().applyCoordinateOperation());
|
||||
void_limit_spin_->setValue(AppSettings::instance().voidLimit());
|
||||
deflection_tolerance_spin_->setValue(AppSettings::instance().deflectionTolerance());
|
||||
angular_tolerance_spin_->setValue(AppSettings::instance().angularTolerance());
|
||||
@@ -119,6 +129,8 @@ void SettingsWindow::onAccepted() {
|
||||
AppSettings::instance().setShowStats(show_stats_check_->isChecked());
|
||||
AppSettings::instance().setBackfaceCulling(backface_culling_check_->isChecked());
|
||||
AppSettings::instance().setLoadDataSource(load_data_source_check_->isChecked());
|
||||
AppSettings::instance().setApplyCoordinateOperation(
|
||||
apply_coordinate_operation_check_->isChecked());
|
||||
AppSettings::instance().setVoidLimit(void_limit_spin_->value());
|
||||
AppSettings::instance().setDeflectionTolerance(deflection_tolerance_spin_->value());
|
||||
AppSettings::instance().setAngularTolerance(angular_tolerance_spin_->value());
|
||||
|
||||
@@ -47,6 +47,7 @@ private:
|
||||
QCheckBox* show_stats_check_ = nullptr;
|
||||
QCheckBox* backface_culling_check_ = nullptr;
|
||||
QCheckBox* load_data_source_check_ = nullptr;
|
||||
QCheckBox* apply_coordinate_operation_check_ = nullptr;
|
||||
QSpinBox* void_limit_spin_ = nullptr;
|
||||
QDoubleSpinBox* deflection_tolerance_spin_ = nullptr;
|
||||
QDoubleSpinBox* angular_tolerance_spin_ = nullptr;
|
||||
|
||||
Reference in New Issue
Block a user