2026-05-09 22:00:19 +10:00
|
|
|
// This file was generated with the assistance of an AI coding tool.
|
|
|
|
|
/********************************************************************************
|
|
|
|
|
* *
|
|
|
|
|
* This file is part of IfcOpenShell. *
|
|
|
|
|
* *
|
|
|
|
|
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
|
|
|
|
* it under the terms of the Lesser GNU General Public License as published by *
|
|
|
|
|
* the Free Software Foundation, either version 3.0 of the License, or *
|
|
|
|
|
* (at your option) any later version. *
|
|
|
|
|
* *
|
|
|
|
|
* IfcOpenShell is distributed in the hope that it will be useful, *
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
|
|
|
* Lesser GNU General Public License for more details. *
|
|
|
|
|
* *
|
|
|
|
|
* You should have received a copy of the Lesser GNU General Public License *
|
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
|
|
|
|
* *
|
|
|
|
|
********************************************************************************/
|
|
|
|
|
|
|
|
|
|
#include "SettingsDialog.h"
|
2026-05-15 06:55:48 +10:00
|
|
|
#include "SettingsView.h"
|
2026-05-09 22:00:19 +10:00
|
|
|
|
2026-05-10 22:04:03 +10:00
|
|
|
#include "../../SessionState.h"
|
2026-05-09 22:00:19 +10:00
|
|
|
#include "../../../ifcviewer/Federation.h"
|
2026-05-10 22:04:03 +10:00
|
|
|
#include "../../../ifcviewer/SceneLoader.h"
|
2026-05-09 22:00:19 +10:00
|
|
|
#include "../../components/Section.h"
|
|
|
|
|
#include "../../components/Style.h"
|
|
|
|
|
#include "../../components/SvgIcon.h"
|
|
|
|
|
#include "../../components/Tabs.h"
|
|
|
|
|
|
|
|
|
|
#include <QComboBox>
|
|
|
|
|
#include <QDialogButtonBox>
|
|
|
|
|
#include <QFormLayout>
|
2026-05-10 22:04:03 +10:00
|
|
|
#include <QHeaderView>
|
2026-05-09 22:00:19 +10:00
|
|
|
#include <QHBoxLayout>
|
|
|
|
|
#include <QLabel>
|
|
|
|
|
#include <QLineEdit>
|
|
|
|
|
#include <QPushButton>
|
2026-05-10 22:04:03 +10:00
|
|
|
#include <QRegularExpression>
|
|
|
|
|
#include <QSizePolicy>
|
2026-05-09 22:00:19 +10:00
|
|
|
#include <QShowEvent>
|
2026-05-10 22:04:03 +10:00
|
|
|
#include <QSignalBlocker>
|
|
|
|
|
#include <QScrollBar>
|
|
|
|
|
#include <QTableWidget>
|
|
|
|
|
#include <QTableWidgetItem>
|
2026-05-09 22:00:19 +10:00
|
|
|
#include <QVBoxLayout>
|
|
|
|
|
|
2026-05-15 07:22:31 +10:00
|
|
|
namespace ifcviewerfull::modules::models {
|
2026-05-09 22:00:19 +10:00
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
|
|
struct UnitChoice {
|
|
|
|
|
const char* label;
|
|
|
|
|
const char* prefix;
|
|
|
|
|
const char* name;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const UnitChoice kUnitChoices[] = {
|
|
|
|
|
{"Metres (m)", "", "METRE"},
|
|
|
|
|
{"Millimetres (mm)", "MILLI", "METRE"},
|
|
|
|
|
{"Centimetres (cm)", "CENTI", "METRE"},
|
|
|
|
|
{"Kilometres (km)", "KILO", "METRE"},
|
|
|
|
|
{"Feet (ft)", "", "foot"},
|
|
|
|
|
{"Inches (in)", "", "inch"},
|
|
|
|
|
{"Yards (yd)", "", "yard"},
|
|
|
|
|
{"Miles (mi)", "", "mile"},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
QLineEdit* makeNumericField(QWidget* parent, const QString& placeholder = {}) {
|
|
|
|
|
auto* field = new QLineEdit(parent);
|
|
|
|
|
field->setPlaceholderText(placeholder);
|
|
|
|
|
field->setMaximumWidth(96);
|
|
|
|
|
return field;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-10 22:04:03 +10:00
|
|
|
QWidget* makeEqualThirdsRow(QWidget* parent, QLineEdit* a, QLineEdit* b, QLineEdit* c) {
|
|
|
|
|
auto* row = new QWidget(parent);
|
|
|
|
|
auto* layout = new QHBoxLayout(row);
|
|
|
|
|
layout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
|
layout->setSpacing(components::style::metrics::padding);
|
|
|
|
|
for (QLineEdit* field : {a, b, c}) {
|
|
|
|
|
field->setMaximumWidth(QWIDGETSIZE_MAX);
|
|
|
|
|
field->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
|
|
|
|
layout->addWidget(field, 1);
|
|
|
|
|
}
|
|
|
|
|
return row;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-09 22:00:19 +10:00
|
|
|
QString formatNumber(double value) {
|
|
|
|
|
return QString::number(value, 'f', 6);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double parseNumber(QLineEdit* field) {
|
|
|
|
|
bool ok = false;
|
|
|
|
|
const double value = field->text().toDouble(&ok);
|
|
|
|
|
return ok ? value : 0.0;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-10 22:04:03 +10:00
|
|
|
QString formatVector3(const Eigen::Vector3d& value) {
|
|
|
|
|
return QString("%1, %2, %3").arg(formatNumber(value.x()), formatNumber(value.y()), formatNumber(value.z()));
|
2026-05-09 22:00:19 +10:00
|
|
|
}
|
|
|
|
|
|
2026-05-10 22:04:03 +10:00
|
|
|
Eigen::Vector3d parseVector3(const QString& text) {
|
|
|
|
|
const QStringList parts = text.split(QRegularExpression("[,\\s]+"), Qt::SkipEmptyParts);
|
|
|
|
|
if (parts.size() != 3) return Eigen::Vector3d::Zero();
|
|
|
|
|
|
|
|
|
|
bool ok_x = false;
|
|
|
|
|
bool ok_y = false;
|
|
|
|
|
bool ok_z = false;
|
|
|
|
|
const double x = parts[0].toDouble(&ok_x);
|
|
|
|
|
const double y = parts[1].toDouble(&ok_y);
|
|
|
|
|
const double z = parts[2].toDouble(&ok_z);
|
|
|
|
|
if (!ok_x || !ok_y || !ok_z) return Eigen::Vector3d::Zero();
|
|
|
|
|
return Eigen::Vector3d(x, y, z);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QLabel* makeReadOnlyValue(QWidget* parent) {
|
|
|
|
|
auto* label = new QLabel(parent);
|
|
|
|
|
label->setTextInteractionFlags(Qt::TextSelectableByMouse);
|
|
|
|
|
label->setWordWrap(true);
|
|
|
|
|
return label;
|
2026-05-09 22:00:19 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
2026-05-15 07:22:31 +10:00
|
|
|
SettingsDialog::SettingsDialog(ifcviewerfull::SessionState* session_state, QWidget* parent)
|
2026-05-11 09:17:45 +10:00
|
|
|
: components::TabbedDialog(parent)
|
2026-05-10 22:04:03 +10:00
|
|
|
, session_state_(session_state)
|
|
|
|
|
, federation_(session_state ? session_state->federation() : nullptr)
|
|
|
|
|
, loader_(session_state ? session_state->loader() : nullptr)
|
2026-05-15 06:55:48 +10:00
|
|
|
, settings_view_(new SettingsView(this, session_state))
|
2026-05-09 22:00:19 +10:00
|
|
|
{
|
|
|
|
|
setObjectName("appDialog");
|
|
|
|
|
setWindowTitle("Model Settings");
|
|
|
|
|
setModal(true);
|
2026-05-10 22:04:03 +10:00
|
|
|
resize(980, 560);
|
2026-05-09 22:00:19 +10:00
|
|
|
setupUi();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SettingsDialog::showEvent(QShowEvent* event) {
|
2026-05-10 22:04:03 +10:00
|
|
|
federation_ = session_state_ ? session_state_->federation() : federation_;
|
|
|
|
|
loader_ = session_state_ ? session_state_->loader() : loader_;
|
2026-05-09 22:00:19 +10:00
|
|
|
syncFromFederation();
|
2026-05-10 22:04:03 +10:00
|
|
|
populateModelTable();
|
2026-05-09 22:00:19 +10:00
|
|
|
QDialog::showEvent(event);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SettingsDialog::setupUi() {
|
2026-05-11 09:17:45 +10:00
|
|
|
auto* federation_tab = new QWidget(this);
|
2026-05-09 22:00:19 +10:00
|
|
|
auto* federation_layout = new QVBoxLayout(federation_tab);
|
|
|
|
|
federation_layout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
|
federation_layout->setSpacing(components::style::metrics::padding);
|
2026-05-10 22:04:03 +10:00
|
|
|
federation_layout->setAlignment(Qt::AlignTop);
|
2026-05-09 22:00:19 +10:00
|
|
|
|
2026-05-10 22:04:03 +10:00
|
|
|
auto* federation_unit_section =
|
|
|
|
|
new components::Section("Federation Unit", components::SectionHeaderMode::Visible, federation_tab);
|
|
|
|
|
auto* unit_hint = new QLabel(
|
|
|
|
|
"All measurements, federated false origins, and destination model transforms will be interpreted in this unit.",
|
|
|
|
|
federation_unit_section);
|
|
|
|
|
unit_hint->setProperty("textRole", "secondary");
|
|
|
|
|
unit_hint->setWordWrap(true);
|
2026-05-09 22:00:19 +10:00
|
|
|
auto* federation_unit_body = new QWidget(federation_unit_section);
|
|
|
|
|
auto* federation_unit_form = new QFormLayout(federation_unit_body);
|
|
|
|
|
federation_unit_form->setContentsMargins(0, 0, 0, 0);
|
|
|
|
|
federation_unit_form->setHorizontalSpacing(16);
|
|
|
|
|
federation_unit_form->setVerticalSpacing(10);
|
|
|
|
|
unit_combo_ = new QComboBox(federation_unit_body);
|
|
|
|
|
for (const auto& uc : kUnitChoices) {
|
|
|
|
|
QStringList data;
|
|
|
|
|
data << QString::fromUtf8(uc.prefix) << QString::fromUtf8(uc.name);
|
|
|
|
|
unit_combo_->addItem(uc.label, data);
|
|
|
|
|
}
|
|
|
|
|
federation_unit_form->addRow("Unit", unit_combo_);
|
2026-05-10 22:04:03 +10:00
|
|
|
federation_unit_section->addBodyWidget(unit_hint);
|
2026-05-09 22:00:19 +10:00
|
|
|
federation_unit_section->addBodyWidget(federation_unit_body);
|
|
|
|
|
|
2026-05-10 22:04:03 +10:00
|
|
|
auto* origin_section =
|
|
|
|
|
new components::Section("Federated False Origin", components::SectionHeaderMode::Visible, federation_tab);
|
|
|
|
|
auto* origin_hint = new QLabel(
|
|
|
|
|
"Nominate a false origin and project north to use when viewing the federation of models.",
|
|
|
|
|
origin_section);
|
|
|
|
|
origin_hint->setProperty("textRole", "secondary");
|
|
|
|
|
origin_hint->setWordWrap(true);
|
2026-05-09 22:00:19 +10:00
|
|
|
auto* origin_body = new QWidget(origin_section);
|
|
|
|
|
auto* origin_form = new QFormLayout(origin_body);
|
|
|
|
|
origin_form->setContentsMargins(0, 0, 0, 0);
|
|
|
|
|
origin_form->setHorizontalSpacing(16);
|
|
|
|
|
origin_form->setVerticalSpacing(10);
|
|
|
|
|
xyz_x_ = makeNumericField(origin_body, "X");
|
|
|
|
|
xyz_y_ = makeNumericField(origin_body, "Y");
|
|
|
|
|
xyz_z_ = makeNumericField(origin_body, "Z");
|
|
|
|
|
rz_deg_ = makeNumericField(origin_body, "deg");
|
2026-05-10 22:04:03 +10:00
|
|
|
origin_form->addRow("XYZ", makeEqualThirdsRow(origin_body, xyz_x_, xyz_y_, xyz_z_));
|
2026-05-09 22:00:19 +10:00
|
|
|
origin_form->addRow("Z rotation (°)", rz_deg_);
|
2026-05-10 22:04:03 +10:00
|
|
|
origin_section->addBodyWidget(origin_hint);
|
2026-05-09 22:00:19 +10:00
|
|
|
origin_section->addBodyWidget(origin_body);
|
|
|
|
|
|
|
|
|
|
federation_layout->addWidget(federation_unit_section);
|
|
|
|
|
federation_layout->addWidget(origin_section);
|
|
|
|
|
federation_layout->addStretch(1);
|
|
|
|
|
|
2026-05-11 09:17:45 +10:00
|
|
|
auto* model_tab = new QWidget(this);
|
2026-05-09 22:00:19 +10:00
|
|
|
auto* model_layout = new QVBoxLayout(model_tab);
|
|
|
|
|
model_layout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
|
model_layout->setSpacing(components::style::metrics::padding);
|
2026-05-10 22:04:03 +10:00
|
|
|
model_layout->setAlignment(Qt::AlignTop);
|
|
|
|
|
|
|
|
|
|
auto* georef_section =
|
|
|
|
|
new components::Section("Selected Model Georeferencing", components::SectionHeaderMode::Visible, model_tab);
|
|
|
|
|
auto* georef_body = new QWidget(georef_section);
|
|
|
|
|
auto* georef_layout = new QHBoxLayout(georef_body);
|
|
|
|
|
georef_layout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
|
georef_layout->setSpacing(16);
|
|
|
|
|
georef_layout->setAlignment(Qt::AlignTop);
|
|
|
|
|
georef_present_value_ = makeReadOnlyValue(georef_body);
|
|
|
|
|
georef_type_value_ = makeReadOnlyValue(georef_body);
|
2026-05-15 06:55:48 +10:00
|
|
|
georef_project_unit_value_ = makeReadOnlyValue(georef_body);
|
|
|
|
|
georef_map_unit_value_ = makeReadOnlyValue(georef_body);
|
2026-05-10 22:04:03 +10:00
|
|
|
georef_easting_value_ = makeReadOnlyValue(georef_body);
|
|
|
|
|
georef_northing_value_ = makeReadOnlyValue(georef_body);
|
|
|
|
|
georef_height_value_ = makeReadOnlyValue(georef_body);
|
|
|
|
|
georef_x_axis_abscissa_value_ = makeReadOnlyValue(georef_body);
|
|
|
|
|
georef_x_axis_ordinate_value_ = makeReadOnlyValue(georef_body);
|
|
|
|
|
georef_rotation_dd_value_ = makeReadOnlyValue(georef_body);
|
|
|
|
|
georef_rotation_dms_value_ = makeReadOnlyValue(georef_body);
|
|
|
|
|
georef_scale_value_ = makeReadOnlyValue(georef_body);
|
|
|
|
|
georef_factor_x_value_ = makeReadOnlyValue(georef_body);
|
|
|
|
|
georef_factor_y_value_ = makeReadOnlyValue(georef_body);
|
|
|
|
|
georef_factor_z_value_ = makeReadOnlyValue(georef_body);
|
|
|
|
|
|
|
|
|
|
auto* georef_col_1 = new QFormLayout();
|
|
|
|
|
georef_col_1->setContentsMargins(0, 0, 0, 0);
|
|
|
|
|
georef_col_1->setHorizontalSpacing(12);
|
|
|
|
|
georef_col_1->setVerticalSpacing(8);
|
|
|
|
|
georef_col_1->addRow("Georeferenced", georef_present_value_);
|
|
|
|
|
georef_col_1->addRow("Coordinate Operation", georef_type_value_);
|
2026-05-15 06:55:48 +10:00
|
|
|
georef_col_1->addRow("Project Unit", georef_project_unit_value_);
|
|
|
|
|
georef_col_1->addRow("Map Unit", georef_map_unit_value_);
|
2026-05-10 22:04:03 +10:00
|
|
|
georef_col_1->addRow("Easting", georef_easting_value_);
|
|
|
|
|
georef_col_1->addRow("Northing", georef_northing_value_);
|
|
|
|
|
georef_col_1->addRow("OrthogonalHeight", georef_height_value_);
|
|
|
|
|
|
|
|
|
|
auto* georef_col_2 = new QFormLayout();
|
|
|
|
|
georef_col_2->setContentsMargins(0, 0, 0, 0);
|
|
|
|
|
georef_col_2->setHorizontalSpacing(12);
|
|
|
|
|
georef_col_2->setVerticalSpacing(8);
|
|
|
|
|
georef_col_2->addRow("XAxisAbscissa", georef_x_axis_abscissa_value_);
|
|
|
|
|
georef_col_2->addRow("XAxisOrdinate", georef_x_axis_ordinate_value_);
|
|
|
|
|
georef_col_2->addRow("Rotation (DD)", georef_rotation_dd_value_);
|
|
|
|
|
georef_col_2->addRow("Rotation (DMS)", georef_rotation_dms_value_);
|
|
|
|
|
|
|
|
|
|
auto* georef_col_3 = new QFormLayout();
|
|
|
|
|
georef_col_3->setContentsMargins(0, 0, 0, 0);
|
|
|
|
|
georef_col_3->setHorizontalSpacing(12);
|
|
|
|
|
georef_col_3->setVerticalSpacing(8);
|
|
|
|
|
georef_col_3->addRow("Scale", georef_scale_value_);
|
|
|
|
|
georef_col_3->addRow("FactorX", georef_factor_x_value_);
|
|
|
|
|
georef_col_3->addRow("FactorY", georef_factor_y_value_);
|
|
|
|
|
georef_col_3->addRow("FactorZ", georef_factor_z_value_);
|
|
|
|
|
|
|
|
|
|
auto* georef_col_1_widget = new QWidget(georef_body);
|
|
|
|
|
georef_col_1_widget->setLayout(georef_col_1);
|
|
|
|
|
auto* georef_col_2_widget = new QWidget(georef_body);
|
|
|
|
|
georef_col_2_widget->setLayout(georef_col_2);
|
|
|
|
|
auto* georef_col_3_widget = new QWidget(georef_body);
|
|
|
|
|
georef_col_3_widget->setLayout(georef_col_3);
|
|
|
|
|
|
|
|
|
|
georef_layout->addWidget(georef_col_1_widget, 1);
|
|
|
|
|
georef_layout->addWidget(georef_col_2_widget, 1);
|
|
|
|
|
georef_layout->addWidget(georef_col_3_widget, 1);
|
|
|
|
|
georef_section->addBodyWidget(georef_body);
|
|
|
|
|
|
|
|
|
|
auto* table_section =
|
|
|
|
|
new components::Section("Model Transformations", components::SectionHeaderMode::Visible, model_tab);
|
|
|
|
|
auto* table_body = new QWidget(table_section);
|
|
|
|
|
auto* table_layout = new QVBoxLayout(table_body);
|
|
|
|
|
table_layout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
|
table_layout->setSpacing(components::style::metrics::padding);
|
|
|
|
|
|
|
|
|
|
model_table_ = new QTableWidget(table_body);
|
|
|
|
|
model_table_->setObjectName("modelCoordinatesTable");
|
|
|
|
|
model_table_->setColumnCount(6);
|
|
|
|
|
model_table_->setHorizontalHeaderLabels(
|
|
|
|
|
{"Model", "From", "From Point", "To Point", "Rotate", "Pivot Point"});
|
|
|
|
|
model_table_->verticalHeader()->setVisible(false);
|
|
|
|
|
model_table_->horizontalHeader()->setStretchLastSection(false);
|
|
|
|
|
model_table_->horizontalHeader()->setSectionsMovable(false);
|
|
|
|
|
model_table_->horizontalHeader()->setSectionsClickable(true);
|
|
|
|
|
model_table_->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);
|
|
|
|
|
model_table_->horizontalHeader()->resizeSection(0, 180);
|
|
|
|
|
model_table_->horizontalHeader()->resizeSection(1, 150);
|
|
|
|
|
model_table_->horizontalHeader()->resizeSection(2, 180);
|
|
|
|
|
model_table_->horizontalHeader()->resizeSection(3, 180);
|
|
|
|
|
model_table_->horizontalHeader()->resizeSection(4, 180);
|
|
|
|
|
model_table_->horizontalHeader()->resizeSection(5, 180);
|
|
|
|
|
model_table_->setSelectionBehavior(QAbstractItemView::SelectRows);
|
|
|
|
|
model_table_->setSelectionMode(QAbstractItemView::SingleSelection);
|
|
|
|
|
model_table_->setShowGrid(true);
|
|
|
|
|
model_table_->setWordWrap(false);
|
|
|
|
|
model_table_->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed);
|
|
|
|
|
model_table_->setAlternatingRowColors(false);
|
|
|
|
|
model_table_->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
|
|
|
|
|
|
|
|
auto* table_hint = new QLabel(
|
|
|
|
|
"This section lets you override model coordinates by specifying an optional translation from a point to "
|
|
|
|
|
"another desired point, and an optional rotation.",
|
|
|
|
|
table_section);
|
|
|
|
|
table_hint->setProperty("textRole", "secondary");
|
|
|
|
|
table_hint->setWordWrap(true);
|
|
|
|
|
|
|
|
|
|
table_layout->addWidget(model_table_, 1);
|
|
|
|
|
table_section->addBodyWidget(table_hint);
|
|
|
|
|
table_section->addBodyWidget(table_body);
|
|
|
|
|
model_layout->addWidget(georef_section);
|
|
|
|
|
model_layout->addWidget(table_section);
|
2026-05-09 22:00:19 +10:00
|
|
|
|
2026-05-11 09:17:45 +10:00
|
|
|
addTab("Federation", federation_tab);
|
|
|
|
|
addTab("Model", model_tab);
|
2026-05-09 22:00:19 +10:00
|
|
|
|
2026-05-10 22:04:03 +10:00
|
|
|
connect(model_table_, &QTableWidget::currentCellChanged, this,
|
|
|
|
|
[this](int /*current_row*/, int /*current_column*/, int /*previous_row*/, int /*previous_column*/) {
|
|
|
|
|
updateSelectedModelGeoref();
|
2026-05-09 22:00:19 +10:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
auto* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
|
|
|
|
|
if (auto* ok = buttons->button(QDialogButtonBox::Ok)) {
|
|
|
|
|
ok->setText("OK");
|
|
|
|
|
ok->setIcon(components::icons::makeSvgIcon(":/icons/check.svg"));
|
|
|
|
|
}
|
|
|
|
|
if (auto* cancel = buttons->button(QDialogButtonBox::Cancel)) {
|
|
|
|
|
cancel->setText("Cancel");
|
|
|
|
|
cancel->setIcon(components::icons::makeSvgIcon(":/icons/xmark-circle.svg"));
|
|
|
|
|
}
|
|
|
|
|
connect(buttons, &QDialogButtonBox::accepted, this, [this]() { onAccepted(); });
|
|
|
|
|
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
|
|
|
|
|
2026-05-10 22:04:03 +10:00
|
|
|
addFooterWidget(buttons);
|
2026-05-09 22:00:19 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SettingsDialog::syncFromFederation() {
|
|
|
|
|
if (!federation_) return;
|
|
|
|
|
|
|
|
|
|
const auto& cfg = federation_->config();
|
|
|
|
|
int idx = -1;
|
|
|
|
|
for (int i = 0; i < unit_combo_->count(); ++i) {
|
|
|
|
|
const QStringList data = unit_combo_->itemData(i).toStringList();
|
|
|
|
|
if (data.size() == 2 &&
|
|
|
|
|
data[0].toStdString() == cfg.unit_prefix &&
|
|
|
|
|
data[1].toStdString() == cfg.unit_name) {
|
|
|
|
|
idx = i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
unit_combo_->setCurrentIndex(idx >= 0 ? idx : 0);
|
|
|
|
|
|
|
|
|
|
const auto& origin = federation_->federatedFalseOrigin();
|
|
|
|
|
xyz_x_->setText(formatNumber(origin.xyz.x()));
|
|
|
|
|
xyz_y_->setText(formatNumber(origin.xyz.y()));
|
|
|
|
|
xyz_z_->setText(formatNumber(origin.xyz.z()));
|
|
|
|
|
rz_deg_->setText(formatNumber(origin.rz_deg));
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-10 22:04:03 +10:00
|
|
|
void SettingsDialog::populateModelTable() {
|
|
|
|
|
model_rows_.clear();
|
|
|
|
|
const QSignalBlocker blocker(model_table_);
|
|
|
|
|
model_table_->clearContents();
|
|
|
|
|
model_table_->setRowCount(0);
|
|
|
|
|
if (!federation_) return;
|
|
|
|
|
|
|
|
|
|
int row = 0;
|
|
|
|
|
for (const auto& model : federation_->models()) {
|
|
|
|
|
const auto& xf = model.model_transformation;
|
|
|
|
|
model_table_->insertRow(row);
|
|
|
|
|
|
|
|
|
|
auto* model_item = new QTableWidgetItem(model.display_name.isEmpty() ? model.id : model.display_name);
|
|
|
|
|
model_item->setData(Qt::UserRole, model.id);
|
|
|
|
|
model_table_->setItem(row, 0, model_item);
|
|
|
|
|
|
|
|
|
|
ModelRowWidgets widgets;
|
|
|
|
|
widgets.fed_id = model.id;
|
|
|
|
|
|
|
|
|
|
widgets.frame = new QComboBox(model_table_);
|
|
|
|
|
widgets.frame->addItem("Local", static_cast<int>(AFrame::ModelLocal));
|
|
|
|
|
widgets.frame->addItem("Global", static_cast<int>(AFrame::ModelGlobal));
|
|
|
|
|
widgets.frame->setCurrentIndex(xf.a_frame == AFrame::ModelGlobal ? 1 : 0);
|
|
|
|
|
model_table_->setCellWidget(row, 1, widgets.frame);
|
|
|
|
|
|
|
|
|
|
widgets.from_point = new QTableWidgetItem(formatVector3(xf.a));
|
|
|
|
|
widgets.to_point = new QTableWidgetItem(formatVector3(xf.b));
|
|
|
|
|
widgets.rotate = new QTableWidgetItem(formatVector3(xf.rxyz_deg));
|
|
|
|
|
widgets.pivot = new QTableWidgetItem(formatVector3(xf.pivot));
|
|
|
|
|
model_table_->setItem(row, 2, widgets.from_point);
|
|
|
|
|
model_table_->setItem(row, 3, widgets.to_point);
|
|
|
|
|
model_table_->setItem(row, 4, widgets.rotate);
|
|
|
|
|
model_table_->setItem(row, 5, widgets.pivot);
|
|
|
|
|
|
|
|
|
|
model_rows_.push_back(widgets);
|
|
|
|
|
model_table_->setRowHeight(row, 42);
|
|
|
|
|
++row;
|
2026-05-09 22:00:19 +10:00
|
|
|
}
|
2026-05-10 22:04:03 +10:00
|
|
|
|
|
|
|
|
int table_height = model_table_->frameWidth() * 2 + model_table_->horizontalHeader()->height();
|
|
|
|
|
for (int i = 0; i < model_table_->rowCount(); ++i) {
|
|
|
|
|
table_height += model_table_->rowHeight(i);
|
2026-05-09 22:00:19 +10:00
|
|
|
}
|
2026-05-10 22:04:03 +10:00
|
|
|
if (model_table_->horizontalScrollBar()->isVisible()) {
|
|
|
|
|
table_height += model_table_->horizontalScrollBar()->sizeHint().height();
|
|
|
|
|
}
|
|
|
|
|
model_table_->setMinimumHeight(table_height);
|
|
|
|
|
model_table_->setMaximumHeight(table_height);
|
2026-05-09 22:00:19 +10:00
|
|
|
|
2026-05-10 22:04:03 +10:00
|
|
|
if (model_table_->rowCount() > 0) {
|
|
|
|
|
model_table_->setCurrentCell(0, 0);
|
|
|
|
|
}
|
|
|
|
|
updateSelectedModelGeoref();
|
2026-05-09 22:00:19 +10:00
|
|
|
}
|
|
|
|
|
|
2026-05-15 06:55:48 +10:00
|
|
|
void SettingsDialog::renderSelectedModelGeoref(const SelectedModelGeorefState& state) {
|
|
|
|
|
georef_present_value_->setText(state.georef_present);
|
|
|
|
|
georef_type_value_->setText(state.coordinate_operation_type);
|
|
|
|
|
georef_project_unit_value_->setText(state.project_unit);
|
|
|
|
|
georef_map_unit_value_->setText(state.map_unit);
|
|
|
|
|
georef_easting_value_->setText(state.easting);
|
|
|
|
|
georef_northing_value_->setText(state.northing);
|
|
|
|
|
georef_height_value_->setText(state.height);
|
|
|
|
|
georef_x_axis_abscissa_value_->setText(state.x_axis_abscissa);
|
|
|
|
|
georef_x_axis_ordinate_value_->setText(state.x_axis_ordinate);
|
|
|
|
|
georef_rotation_dd_value_->setText(state.rotation_dd);
|
|
|
|
|
georef_rotation_dms_value_->setText(state.rotation_dms);
|
|
|
|
|
georef_scale_value_->setText(state.scale);
|
|
|
|
|
georef_factor_x_value_->setText(state.factor_x);
|
|
|
|
|
georef_factor_y_value_->setText(state.factor_y);
|
|
|
|
|
georef_factor_z_value_->setText(state.factor_z);
|
|
|
|
|
}
|
2026-05-10 22:04:03 +10:00
|
|
|
|
2026-05-15 06:55:48 +10:00
|
|
|
void SettingsDialog::updateSelectedModelGeoref() {
|
2026-05-10 22:04:03 +10:00
|
|
|
const int row = model_table_->currentRow();
|
|
|
|
|
if (row < 0 || row >= static_cast<int>(model_rows_.size())) {
|
2026-05-15 06:55:48 +10:00
|
|
|
renderSelectedModelGeoref(
|
|
|
|
|
{"No model selected", "—", "—", "—", "—", "—", "—", "—", "—", "—", "—", "—", "—", "—", "—"});
|
2026-05-10 22:04:03 +10:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-15 06:55:48 +10:00
|
|
|
if (!settings_view_) {
|
|
|
|
|
renderSelectedModelGeoref(
|
|
|
|
|
{"Unavailable", "No settings view", "—", "—", "—", "—", "—", "—", "—", "—", "—", "—", "—", "—", "—"});
|
2026-05-10 22:04:03 +10:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-15 06:55:48 +10:00
|
|
|
settings_view_->refresh(model_rows_[row].fed_id);
|
2026-05-09 22:00:19 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SettingsDialog::onAccepted() {
|
|
|
|
|
if (federation_) {
|
|
|
|
|
const QStringList data = unit_combo_->currentData().toStringList();
|
|
|
|
|
FederationConfig cfg;
|
|
|
|
|
if (data.size() == 2) {
|
|
|
|
|
cfg.unit_prefix = data[0].toStdString();
|
|
|
|
|
cfg.unit_name = data[1].toStdString();
|
|
|
|
|
}
|
|
|
|
|
federation_->setConfig(cfg);
|
|
|
|
|
|
|
|
|
|
FederatedFalseOrigin origin;
|
|
|
|
|
origin.xyz = Eigen::Vector3d(parseNumber(xyz_x_), parseNumber(xyz_y_), parseNumber(xyz_z_));
|
|
|
|
|
origin.rz_deg = parseNumber(rz_deg_);
|
|
|
|
|
federation_->setFederatedFalseOrigin(origin);
|
|
|
|
|
|
2026-05-10 22:04:03 +10:00
|
|
|
for (const auto& row : model_rows_) {
|
2026-05-09 22:00:19 +10:00
|
|
|
ModelTransformation xf;
|
2026-05-10 22:04:03 +10:00
|
|
|
xf.a_frame = static_cast<AFrame>(row.frame->currentData().toInt());
|
|
|
|
|
xf.a = parseVector3(row.from_point->text());
|
|
|
|
|
xf.b = parseVector3(row.to_point->text());
|
|
|
|
|
xf.rxyz_deg = parseVector3(row.rotate->text());
|
|
|
|
|
xf.pivot = parseVector3(row.pivot->text());
|
|
|
|
|
federation_->setModelTransformation(row.fed_id, xf);
|
2026-05-09 22:00:19 +10:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
accept();
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-15 07:22:31 +10:00
|
|
|
} // namespace ifcviewerfull::modules::models
|