Swap interface into IfcViewerFull

Replace the old IfcViewerFull application tree with the interface-based viewer while preserving the IfcViewerFull target and build workflow.

Generated with the assistance of an AI coding tool.
This commit is contained in:
Dion Moult
2026-05-15 07:18:26 +10:00
parent 03b8b9c1bd
commit 4a91e6a87d
117 changed files with 672 additions and 3201 deletions
+75 -4
View File
@@ -1,3 +1,4 @@
# This file was generated with the assistance of an AI coding tool.
################################################################################
# #
# This file is part of IfcOpenShell. #
@@ -19,19 +20,89 @@
message("Running CMakeLists.txt in /src/ifcviewer-full")
file(GLOB IFCVIEWER_FULL_CPP_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
file(GLOB IFCVIEWER_FULL_H_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.h)
set(IFCVIEWER_FULL_FILES ${IFCVIEWER_FULL_CPP_FILES} ${IFCVIEWER_FULL_H_FILES})
set(QT_VERSION 6 CACHE STRING "Qt version")
find_package(Qt${QT_VERSION} COMPONENTS Core Gui Widgets Svg REQUIRED PATHS ${QT_DIR})
set(IFCVIEWER_FULL_FILES
${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ElementRegistry.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ElementRegistry.h
${CMAKE_CURRENT_SOURCE_DIR}/InterfaceSettings.cpp
${CMAKE_CURRENT_SOURCE_DIR}/InterfaceSettings.h
${CMAKE_CURRENT_SOURCE_DIR}/SessionState.cpp
${CMAKE_CURRENT_SOURCE_DIR}/SessionState.h
${CMAKE_CURRENT_SOURCE_DIR}/MainWindow.cpp
${CMAKE_CURRENT_SOURCE_DIR}/MainWindow.h
${CMAKE_CURRENT_SOURCE_DIR}/Measurement.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Measurement.h
${CMAKE_CURRENT_SOURCE_DIR}/components/SvgIcon.cpp
${CMAKE_CURRENT_SOURCE_DIR}/components/SvgIcon.h
${CMAKE_CURRENT_SOURCE_DIR}/components/Style.cpp
${CMAKE_CURRENT_SOURCE_DIR}/components/Style.h
${CMAKE_CURRENT_SOURCE_DIR}/components/Dialog.cpp
${CMAKE_CURRENT_SOURCE_DIR}/components/Dialog.h
${CMAKE_CURRENT_SOURCE_DIR}/components/Tabs.cpp
${CMAKE_CURRENT_SOURCE_DIR}/components/Tabs.h
${CMAKE_CURRENT_SOURCE_DIR}/components/KeyValueTable.cpp
${CMAKE_CURRENT_SOURCE_DIR}/components/KeyValueTable.h
${CMAKE_CURRENT_SOURCE_DIR}/components/Buttons.cpp
${CMAKE_CURRENT_SOURCE_DIR}/components/Buttons.h
${CMAKE_CURRENT_SOURCE_DIR}/components/Section.cpp
${CMAKE_CURRENT_SOURCE_DIR}/components/Section.h
${CMAKE_CURRENT_SOURCE_DIR}/components/Panel.cpp
${CMAKE_CURRENT_SOURCE_DIR}/components/Panel.h
${CMAKE_CURRENT_SOURCE_DIR}/modules/models/AddModelDialog.cpp
${CMAKE_CURRENT_SOURCE_DIR}/modules/models/AddModelDialog.h
${CMAKE_CURRENT_SOURCE_DIR}/modules/models/SettingsDialog.cpp
${CMAKE_CURRENT_SOURCE_DIR}/modules/models/SettingsDialog.h
${CMAKE_CURRENT_SOURCE_DIR}/modules/models/SettingsView.cpp
${CMAKE_CURRENT_SOURCE_DIR}/modules/models/SettingsView.h
${CMAKE_CURRENT_SOURCE_DIR}/modules/models/Types.h
${CMAKE_CURRENT_SOURCE_DIR}/modules/models/Controller.cpp
${CMAKE_CURRENT_SOURCE_DIR}/modules/models/Controller.h
${CMAKE_CURRENT_SOURCE_DIR}/modules/models/Panel.cpp
${CMAKE_CURRENT_SOURCE_DIR}/modules/models/Panel.h
${CMAKE_CURRENT_SOURCE_DIR}/modules/models/View.cpp
${CMAKE_CURRENT_SOURCE_DIR}/modules/models/View.h
${CMAKE_CURRENT_SOURCE_DIR}/modules/todo/Panel.cpp
${CMAKE_CURRENT_SOURCE_DIR}/modules/todo/Panel.h
${CMAKE_CURRENT_SOURCE_DIR}/modules/properties/Types.h
${CMAKE_CURRENT_SOURCE_DIR}/modules/properties/Panel.cpp
${CMAKE_CURRENT_SOURCE_DIR}/modules/properties/Panel.h
${CMAKE_CURRENT_SOURCE_DIR}/modules/properties/View.cpp
${CMAKE_CURRENT_SOURCE_DIR}/modules/properties/View.h
${CMAKE_CURRENT_SOURCE_DIR}/modules/project/Controller.cpp
${CMAKE_CURRENT_SOURCE_DIR}/modules/project/Controller.h
${CMAKE_CURRENT_SOURCE_DIR}/modules/settings/Dialog.cpp
${CMAKE_CURRENT_SOURCE_DIR}/modules/settings/Dialog.h
${CMAKE_CURRENT_SOURCE_DIR}/modules/spatial_hierarchy/Types.h
${CMAKE_CURRENT_SOURCE_DIR}/modules/spatial_hierarchy/Panel.cpp
${CMAKE_CURRENT_SOURCE_DIR}/modules/spatial_hierarchy/Panel.h
${CMAKE_CURRENT_SOURCE_DIR}/modules/spatial_hierarchy/View.cpp
${CMAKE_CURRENT_SOURCE_DIR}/modules/spatial_hierarchy/View.h
${CMAKE_CURRENT_SOURCE_DIR}/modules/viewport/Panel.cpp
${CMAKE_CURRENT_SOURCE_DIR}/modules/viewport/Panel.h
${CMAKE_CURRENT_SOURCE_DIR}/modules/viewport/Controller.cpp
${CMAKE_CURRENT_SOURCE_DIR}/modules/viewport/Controller.h
${CMAKE_CURRENT_SOURCE_DIR}/interface_resources.qrc
)
add_executable(IfcViewerFull ${IFCVIEWER_FULL_FILES})
set_target_properties(IfcViewerFull PROPERTIES
AUTOMOC ON
AUTORCC ON
WIN32_EXECUTABLE ON
MACOSX_BUNDLE ON
)
target_link_libraries(IfcViewerFull PRIVATE IfcViewer)
target_link_libraries(IfcViewerFull PRIVATE
IfcViewer
Qt${QT_VERSION}::Core
Qt${QT_VERSION}::Gui
Qt${QT_VERSION}::Svg
Qt${QT_VERSION}::Widgets
)
install(TARGETS IfcViewerFull EXPORT ${IFCOPENSHELL_EXPORT_TARGETS})
ifcopenshell_deploy_qt_runtime(IfcViewerFull)
@@ -1,174 +0,0 @@
/********************************************************************************
* *
* 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 "FederationSettingsDialog.h"
#include "Federation.h"
#include <QComboBox>
#include <QDialogButtonBox>
#include <QDoubleSpinBox>
#include <QFormLayout>
#include <QGroupBox>
#include <QLabel>
#include <QShowEvent>
#include <QStringList>
#include <QVBoxLayout>
namespace {
// Common length units users will pick. itemData() carries
// (prefix, name) — empty prefix for non-prefixed or conversion-based units.
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" },
};
} // namespace
FederationSettingsDialog::FederationSettingsDialog(Federation* federation,
QWidget* parent)
: QDialog(parent), federation_(federation)
{
setWindowTitle("Federation Settings");
setupUi();
}
void FederationSettingsDialog::setupUi() {
auto* root = new QVBoxLayout(this);
// Unit
{
auto* group = new QGroupBox("Federation Unit", this);
auto* form = new QFormLayout(group);
unit_combo_ = new QComboBox(group);
for (const auto& uc : kUnitChoices) {
QStringList data;
data << QString::fromUtf8(uc.prefix) << QString::fromUtf8(uc.name);
unit_combo_->addItem(uc.label, data);
}
unit_combo_->setToolTip(
"All Federated False Origin and Model Transformation numbers "
"are interpreted in this unit. Changing it after data has been "
"entered re-interprets the numbers — same physical location "
"expressed in the new unit.");
form->addRow("Unit", unit_combo_);
root->addWidget(group);
}
// Federated False Origin
{
auto* group = new QGroupBox("Federated False Origin", this);
group->setToolTip(
"Nominate a point in the federation that becomes the new (0,0,0). "
"Optional Z-rotation aligns north for the federation.");
auto* form = new QFormLayout(group);
auto build_xyz = [this](QDoubleSpinBox*& sb) {
sb = new QDoubleSpinBox();
sb->setRange(-1e12, 1e12);
sb->setDecimals(6);
sb->setSingleStep(1.0);
};
build_xyz(xyz_x_);
build_xyz(xyz_y_);
build_xyz(xyz_z_);
form->addRow("X", xyz_x_);
form->addRow("Y", xyz_y_);
form->addRow("Z", xyz_z_);
rz_deg_ = new QDoubleSpinBox();
rz_deg_->setRange(-360.0, 360.0);
rz_deg_->setDecimals(6);
rz_deg_->setSingleStep(1.0);
form->addRow("Z rotation (°)", rz_deg_);
root->addWidget(group);
}
auto* button_box = new QDialogButtonBox(
QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
root->addWidget(button_box);
connect(button_box, &QDialogButtonBox::accepted, this,
&FederationSettingsDialog::onAccepted);
connect(button_box, &QDialogButtonBox::rejected, this, &QDialog::reject);
}
void FederationSettingsDialog::showEvent(QShowEvent* event) {
syncFromFederation();
QDialog::showEvent(event);
}
void FederationSettingsDialog::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;
}
}
if (idx >= 0) {
unit_combo_->setCurrentIndex(idx);
} else {
// Federation has a unit that isn't in the common list — fall back to
// the first entry. Saving keeps whatever the user picks; the
// original federation unit is preserved unless they hit Ok.
unit_combo_->setCurrentIndex(0);
}
const auto& origin = federation_->federatedFalseOrigin();
xyz_x_->setValue(origin.xyz.x());
xyz_y_->setValue(origin.xyz.y());
xyz_z_->setValue(origin.xyz.z());
rz_deg_->setValue(origin.rz_deg);
}
void FederationSettingsDialog::onAccepted() {
if (!federation_) { accept(); return; }
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(xyz_x_->value(), xyz_y_->value(), xyz_z_->value());
origin.rz_deg = rz_deg_->value();
federation_->setFederatedFalseOrigin(origin);
accept();
}
@@ -1,61 +0,0 @@
/********************************************************************************
* *
* 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/>. *
* *
********************************************************************************/
#ifndef FEDERATIONSETTINGSDIALOG_H
#define FEDERATIONSETTINGSDIALOG_H
#include <QDialog>
QT_BEGIN_NAMESPACE
class QComboBox;
class QDoubleSpinBox;
QT_END_NAMESPACE
class Federation;
// Edits federation-wide state: the display unit (used to interpret all
// FederatedFalseOrigin / ModelTransformation numeric inputs) and the
// FederatedFalseOrigin (XYZ + Z-axis rotation in that unit). On Ok,
// calls Federation::setConfig + setFederatedFalseOrigin, which fire the
// granular Federation signals and trigger the viewport to recompose.
class FederationSettingsDialog : public QDialog {
Q_OBJECT
public:
explicit FederationSettingsDialog(Federation* federation, QWidget* parent = nullptr);
protected:
void showEvent(QShowEvent* event) override;
private:
void setupUi();
void syncFromFederation();
void onAccepted();
Federation* federation_ = nullptr;
// The combobox encodes (prefix, name) pairs in user data; common length
// units are listed. itemData(idx) returns a QStringList { prefix, name }.
QComboBox* unit_combo_ = nullptr;
QDoubleSpinBox* xyz_x_ = nullptr;
QDoubleSpinBox* xyz_y_ = nullptr;
QDoubleSpinBox* xyz_z_ = nullptr;
QDoubleSpinBox* rz_deg_ = nullptr;
};
#endif
File diff suppressed because it is too large Load Diff
+68 -177
View File
@@ -1,3 +1,4 @@
// This file was generated with the assistance of an AI coding tool.
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
@@ -17,195 +18,85 @@
* *
********************************************************************************/
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#ifndef IFCINTERFACE_SHELL_MAINWINDOW_H
#define IFCINTERFACE_SHELL_MAINWINDOW_H
#include <QHash>
#include <QMainWindow>
#include <QTreeWidget>
#include <QTableWidget>
#include <QProgressBar>
#include <QLabel>
#include <QSplitter>
#include <QElapsedTimer>
#include <map>
#include <unordered_map>
#include <vector>
#include "Measurement.h"
#include "ViewportWindow.h"
#include "SceneLoader.h"
#include <QStringList>
class QLabel;
class QDockWidget;
class QProgressBar;
class QStackedWidget;
class QToolButton;
class Federation;
class SettingsWindow;
class FederationSettingsDialog;
class ModelTransformationDialog;
class SceneLoader;
namespace ifcinterface { class ElementRegistry; }
namespace ifcinterface { class SessionState; }
namespace ifcinterface::components { class TabBar; }
namespace ifcinterface::modules::models { class ModelsPanelController; }
namespace ifcinterface::modules::models { class ModelsPanel; }
namespace ifcinterface::modules::models { class ModelsPanelView; }
namespace ifcinterface::modules::project { class ProjectController; }
namespace ifcinterface::modules::spatial_hierarchy { class SpatialHierarchyPanel; }
namespace ifcinterface::modules::spatial_hierarchy { class SpatialHierarchyPanelView; }
namespace ifcinterface::modules::properties { class PropertiesPanel; }
namespace ifcinterface::modules::properties { class PropertiesPanelView; }
namespace ifcinterface::modules::viewport { class ViewportController; }
namespace ifcinterface::modules::viewport { class ViewportPanel; }
namespace ifcinterface::shell {
class MainWindow : public QMainWindow {
Q_OBJECT
public:
explicit MainWindow(QWidget* parent = nullptr);
~MainWindow();
void addFiles(const QStringList& paths);
bool openFederation(const QString& path);
void setPendingCamera(const QString& params);
void setPendingBenchmark(int frames);
protected:
void closeEvent(QCloseEvent* event) override;
private slots:
void onFileOpen();
void onDatabaseOpen();
void onFederationNew();
void onFederationOpen();
bool onFederationSave();
bool onFederationSaveAs();
void onSetHomeView();
void onGoHomeView();
void onFileSettings();
void onFederationSettings();
void onModelTransformations();
void onObjectPicked(uint32_t object_id);
void onTreeSelectionChanged();
void onTreeContextMenu(const QPoint& pos);
void onLoadStarted(uint32_t mid, QString display_name);
void onLoadProgressChanged(int percent);
void onSidecarElementsReady(uint32_t mid,
std::vector<PackedElementInfo> elements,
std::string string_table);
void onLoadedFromSidecar(uint32_t mid, qint64 elapsed_ms);
void onDataSourceReady(uint32_t mid);
void onStreamedElementsReady(uint32_t mid, std::vector<ElementInfo> elements);
void onLoadedFromStream(uint32_t mid, qint64 elapsed_ms);
void onLoadCancelled(uint32_t mid);
void onLoadError(uint32_t mid, QString message);
void onAllLoadsFinished();
private:
void setupUi();
void setupMenus();
void loadModelsFromPaths(const QStringList& paths,
const QStringList& fed_ids);
void clearScene();
bool confirmDiscardIfDirty();
void setupChrome();
void setupRibbon();
void setupViewport();
void setupPanels();
void setupStatus();
void setupLoader();
QWidget* buildHomeRibbonPage();
QWidget* buildNavigateRibbonPage();
QWidget* buildInspectRibbonPage();
QWidget* buildPanelsRibbonPage();
void updateWindowTitle();
void populateProperties(uint32_t object_id);
// Push the volume HUD + per-object volume labels for the current
// selection. No-op when a measurement tool is active — that tool
// owns the overlay state until it's exited.
void updateVolumeReadout();
void appendElementToTree(uint32_t model_id,
uint32_t object_id,
int ifc_id,
int parent_ifc_id,
const std::string& guid,
const std::string& name,
const std::string& type);
void writeSidecarForModel(uint32_t mid);
void removeModelUi(uint32_t mid);
void removeModel(uint32_t mid);
// Returns the model_id whose tree root is `item`, or 0 if `item` is not
// a model root (i.e. an element row, group, or null).
uint32_t modelIdForRoot(QTreeWidgetItem* item) const;
// Returns the group_id whose tree item is `item`, or empty string when
// `item` is null or is not a group item.
QString groupIdForItem(QTreeWidgetItem* item) const;
// Place / reparent a model root under its group (or at top level when
// group_id is empty / unknown). Idempotent. No-op if there's no tree
// root yet for `mid`.
void reparentModelTreeRoot(uint32_t mid);
// Place / reparent a group item under its parent group (or at top
// level). Idempotent. No-op if there's no tree item for `group_id`.
void reparentGroupTreeItem(const QString& group_id);
// Lazily create the QTreeWidgetItem for `group_id` if not already in
// group_tree_items_. Returns the item. Sets text + flags but does
// not place it under a parent — call reparentGroupTreeItem afterwards.
QTreeWidgetItem* ensureGroupTreeItem(const QString& group_id);
// Recompute italic/grey on a group row from current effective visibility.
void refreshGroupRowAppearance(const QString& group_id);
// Walk descendants of `group_id` and re-push effective visibility to
// the viewport for every model under it. When `group_id` is empty,
// re-pushes every model in the federation.
void applyVisibilityCascadeFromGroup(const QString& group_id);
// Walk every group_id whose ancestor chain currently includes
// `group_id` (inclusive).
std::vector<QString> descendantGroupIds(const QString& group_id) const;
// Push the federation's `visible` flag for `mid` onto the viewport.
// No-op if `mid` is not in the federation map. Idempotent — safe to
// call before the model is finalised on the viewport (hideModel is a
// lookup-and-set on models_gpu_; missing entries are skipped).
void applyModelVisibilityToViewport(uint32_t mid);
void applyPendingBenchmark();
QToolButton* makePanelToggle(const QString& text, QDockWidget* dock);
// 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);
// Push a model's ModelTransformation (stage 4) matrix to the viewport,
// composed from the federation's authoring intent + the model's units
// + the active CoordinateOperation matrix. Identity when the model is
// not in the federation.
void applyModelTransformationToViewport(uint32_t mid);
// Push the federation-wide FederatedFalseOrigin (stage 3) matrix to
// the viewport. Affects every loaded model.
void applyFederatedFalseOriginToViewport();
// For an untitled federation whose FederatedFalseOrigin is still at
// its default, derive a sensible origin from `mid`'s first instance
// placement + georef and push it via Federation. Idempotent: a
// non-default origin (user-edited, already guessed by a sibling load
// in the same batch, or loaded from a saved .ifcfed) is left
// untouched, so multi-file batches naturally anchor on whichever
// model finishes first.
void maybeGuessFederatedFalseOrigin(uint32_t mid);
QString formatElapsed(qint64 ms) const;
ViewportWindow* viewport_ = nullptr;
SceneLoader* loader_ = nullptr;
Federation* federation_ = nullptr;
SettingsWindow* settings_ = nullptr;
FederationSettingsDialog* federation_settings_ = nullptr;
ModelTransformationDialog* model_transformations_ = nullptr;
QWidget* viewport_container_ = nullptr;
QTreeWidget* element_tree_ = nullptr;
QTableWidget* property_table_ = nullptr;
QProgressBar* progress_bar_ = nullptr;
QLabel* status_label_ = nullptr;
QLabel* stats_label_ = nullptr;
// Per-model tree roots, keyed by model_id. May live at the top level
// of element_tree_ or as a child of a group tree item.
std::map<uint32_t, QTreeWidgetItem*> tree_roots_;
// Per-group tree items, keyed by Federation group id.
std::unordered_map<QString, QTreeWidgetItem*> group_tree_items_;
// Bidirectional federation_id <-> model_id map. Federation owns the
// persistent ids; SceneLoader owns the runtime model_ids.
std::unordered_map<QString, uint32_t> fed_id_to_model_id_;
std::unordered_map<uint32_t, QString> model_id_to_fed_id_;
// Display-side element registry for tree + property lookup.
std::unordered_map<uint32_t, ElementInfo> element_map_;
std::unordered_map<uint32_t, QTreeWidgetItem*> tree_items_;
// Scoped (model_id, ifc_id) -> object_id
std::unordered_map<uint64_t, uint32_t> scoped_ifc_id_to_object_id_;
static uint64_t scopedKey(uint32_t model_id, int ifc_id) {
return (static_cast<uint64_t>(model_id) << 32) | static_cast<uint32_t>(ifc_id);
}
QString pending_camera_;
int pending_benchmark_ = 0;
AreaMeasurement area_measurement_;
LengthMeasurement length_measurement_;
private:
Federation* federation_ = nullptr;
QLabel* status_mode_label_ = nullptr;
QLabel* status_selection_label_ = nullptr;
QLabel* status_perf_label_ = nullptr;
QProgressBar* status_progress_bar_ = nullptr;
ifcinterface::components::TabBar* ribbon_tabs_ = nullptr;
QStackedWidget* ribbon_pages_ = nullptr;
ifcinterface::modules::viewport::ViewportPanel* viewport_widget_ = nullptr;
ifcinterface::modules::viewport::ViewportController* viewport_controller_ = nullptr;
SceneLoader* loader_ = nullptr;
ifcinterface::ElementRegistry* element_registry_ = nullptr;
ifcinterface::SessionState* session_state_ = nullptr;
ifcinterface::modules::models::ModelsPanel* models_panel_ = nullptr;
ifcinterface::modules::spatial_hierarchy::SpatialHierarchyPanel* spatial_panel_ = nullptr;
QDockWidget* layers_panel_ = nullptr;
ifcinterface::modules::properties::PropertiesPanel* properties_panel_ = nullptr;
QDockWidget* stored_views_panel_ = nullptr;
QDockWidget* search_panel_ = nullptr;
QDockWidget* spreadsheet_panel_ = nullptr;
QDockWidget* audit_panel_ = nullptr;
QDockWidget* clash_panel_ = nullptr;
QDockWidget* issues_panel_ = nullptr;
ifcinterface::modules::models::ModelsPanelController* models_controller_ = nullptr;
ifcinterface::modules::models::ModelsPanelView* models_view_ = nullptr;
ifcinterface::modules::project::ProjectController* project_controller_ = nullptr;
ifcinterface::modules::spatial_hierarchy::SpatialHierarchyPanelView* spatial_view_ = nullptr;
ifcinterface::modules::properties::PropertiesPanelView* properties_view_ = nullptr;
};
#endif // MAINWINDOW_H
} // namespace ifcinterface::shell
#endif
+1
View File
@@ -1,3 +1,4 @@
// This file was generated with the assistance of an AI coding tool.
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
+4 -3
View File
@@ -1,3 +1,4 @@
// This file was generated with the assistance of an AI coding tool.
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
@@ -17,8 +18,8 @@
* *
********************************************************************************/
#ifndef IFCVIEWER_FULL_MEASUREMENT_H
#define IFCVIEWER_FULL_MEASUREMENT_H
#ifndef IFCINTERFACE_MEASUREMENT_H
#define IFCINTERFACE_MEASUREMENT_H
#include <cstddef>
#include "ViewportWindow.h"
@@ -158,4 +159,4 @@ private:
ViewportWindow::MeshLocalPick first_pick_{};
};
#endif // IFCVIEWER_FULL_MEASUREMENT_H
#endif // IFCINTERFACE_MEASUREMENT_H
@@ -1,248 +0,0 @@
/********************************************************************************
* *
* 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 "ModelTransformationDialog.h"
#include "Federation.h"
#include <QButtonGroup>
#include <QComboBox>
#include <QDialogButtonBox>
#include <QDoubleSpinBox>
#include <QFormLayout>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QLabel>
#include <QRadioButton>
#include <QShowEvent>
#include <QVBoxLayout>
namespace {
QString unitDisplay(const FederationConfig& cfg) {
QString s;
if (!cfg.unit_prefix.empty()) s += QString::fromStdString(cfg.unit_prefix) + " ";
s += QString::fromStdString(cfg.unit_name);
return s;
}
} // namespace
ModelTransformationDialog::ModelTransformationDialog(Federation* federation,
QWidget* parent)
: QDialog(parent), federation_(federation)
{
setWindowTitle("Model Transformation");
setupUi();
}
void ModelTransformationDialog::setupUi() {
auto* root = new QVBoxLayout(this);
// Model picker.
{
auto* row = new QHBoxLayout();
row->addWidget(new QLabel("Model:", this));
model_combo_ = new QComboBox(this);
row->addWidget(model_combo_, 1);
root->addLayout(row);
connect(model_combo_, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &ModelTransformationDialog::onModelChanged);
}
auto build_xyz = [](QDoubleSpinBox*& sb) {
sb = new QDoubleSpinBox();
sb->setRange(-1e12, 1e12);
sb->setDecimals(6);
sb->setSingleStep(1.0);
};
// A-frame + A.
{
auto* group = new QGroupBox("Point A", this);
group->setToolTip(
"The model-side anchor point. ModelLocal expresses A in the "
"model's project length unit, before its CoordinateOperation. "
"ModelGlobal expresses A in the model's map unit, after its "
"CoordinateOperation.");
auto* form = new QFormLayout(group);
radio_local_ = new QRadioButton("ModelLocal", group);
radio_global_ = new QRadioButton("ModelGlobal", group);
radio_global_->setChecked(true);
auto* af_group = new QButtonGroup(this);
af_group->addButton(radio_local_);
af_group->addButton(radio_global_);
connect(radio_local_, &QRadioButton::toggled,
this, &ModelTransformationDialog::onAFrameToggled);
connect(radio_global_, &QRadioButton::toggled,
this, &ModelTransformationDialog::onAFrameToggled);
auto* af_row = new QHBoxLayout();
af_row->addWidget(radio_local_);
af_row->addWidget(radio_global_);
af_row->addStretch();
form->addRow("Frame", af_row);
build_xyz(a_x_); build_xyz(a_y_); build_xyz(a_z_);
form->addRow("X", a_x_);
form->addRow("Y", a_y_);
form->addRow("Z", a_z_);
a_unit_label_ = new QLabel("(model unit)", group);
form->addRow("Unit", a_unit_label_);
root->addWidget(group);
}
// B.
{
auto* group = new QGroupBox("Point B (federation target)", this);
group->setToolTip(
"Where in the federation point A should land. In federation units.");
auto* form = new QFormLayout(group);
build_xyz(b_x_); build_xyz(b_y_); build_xyz(b_z_);
form->addRow("X", b_x_);
form->addRow("Y", b_y_);
form->addRow("Z", b_z_);
b_unit_label_ = new QLabel("(federation unit)", group);
form->addRow("Unit", b_unit_label_);
root->addWidget(group);
}
// Rotation (intrinsic XYZ).
{
auto* group = new QGroupBox("Rotation (intrinsic XYZ, degrees)", this);
group->setToolTip(
"Composed as R = R_z(rz) · R_y(ry) · R_x(rx). Y-up models "
"rotated to Z-up: rx = 90, ry = 0, rz = 0.");
auto* form = new QFormLayout(group);
rx_ = new QDoubleSpinBox(); rx_->setRange(-360, 360); rx_->setDecimals(6);
ry_ = new QDoubleSpinBox(); ry_->setRange(-360, 360); ry_->setDecimals(6);
rz_ = new QDoubleSpinBox(); rz_->setRange(-360, 360); rz_->setDecimals(6);
form->addRow("rx (°)", rx_);
form->addRow("ry (°)", ry_);
form->addRow("rz (°)", rz_);
root->addWidget(group);
}
// Pivot.
{
auto* group = new QGroupBox("Rotation Pivot", this);
group->setToolTip(
"The point the rotation rotates around, in federation units. "
"Set pivot = B to keep A landing on B regardless of rotation.");
auto* form = new QFormLayout(group);
build_xyz(pivot_x_); build_xyz(pivot_y_); build_xyz(pivot_z_);
form->addRow("X", pivot_x_);
form->addRow("Y", pivot_y_);
form->addRow("Z", pivot_z_);
pivot_unit_label_ = new QLabel("(federation unit)", group);
form->addRow("Unit", pivot_unit_label_);
root->addWidget(group);
}
auto* button_box = new QDialogButtonBox(
QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
root->addWidget(button_box);
connect(button_box, &QDialogButtonBox::accepted, this,
&ModelTransformationDialog::onAccepted);
connect(button_box, &QDialogButtonBox::rejected, this, &QDialog::reject);
}
void ModelTransformationDialog::showEvent(QShowEvent* event) {
populateModelCombo();
refreshUnitLabels();
if (model_combo_->count() > 0) {
syncFromModel(model_combo_->currentData().toString());
}
QDialog::showEvent(event);
}
void ModelTransformationDialog::populateModelCombo() {
model_combo_->blockSignals(true);
QString prev_id = model_combo_->currentData().toString();
model_combo_->clear();
if (federation_) {
for (const auto& m : federation_->models()) {
QString label = m.display_name.isEmpty() ? m.id : m.display_name;
model_combo_->addItem(label, m.id);
}
}
int restore = -1;
for (int i = 0; i < model_combo_->count(); ++i) {
if (model_combo_->itemData(i).toString() == prev_id) { restore = i; break; }
}
if (restore >= 0) model_combo_->setCurrentIndex(restore);
model_combo_->blockSignals(false);
}
void ModelTransformationDialog::syncFromModel(const QString& fed_id) {
if (!federation_) return;
const Federation::Model* m = federation_->findById(fed_id);
if (!m) return;
const ModelTransformation& xf = m->model_transformation;
radio_local_->setChecked(xf.a_frame == AFrame::ModelLocal);
radio_global_->setChecked(xf.a_frame == AFrame::ModelGlobal);
a_x_->setValue(xf.a.x()); a_y_->setValue(xf.a.y()); a_z_->setValue(xf.a.z());
b_x_->setValue(xf.b.x()); b_y_->setValue(xf.b.y()); b_z_->setValue(xf.b.z());
rx_->setValue(xf.rxyz_deg.x());
ry_->setValue(xf.rxyz_deg.y());
rz_->setValue(xf.rxyz_deg.z());
pivot_x_->setValue(xf.pivot.x());
pivot_y_->setValue(xf.pivot.y());
pivot_z_->setValue(xf.pivot.z());
}
void ModelTransformationDialog::refreshUnitLabels() {
if (!federation_) return;
const QString fed_unit = unitDisplay(federation_->config());
b_unit_label_->setText("(federation: " + fed_unit + ")");
pivot_unit_label_->setText("(federation: " + fed_unit + ")");
onAFrameToggled();
}
void ModelTransformationDialog::onModelChanged(int /*idx*/) {
if (model_combo_->count() == 0) return;
syncFromModel(model_combo_->currentData().toString());
}
void ModelTransformationDialog::onAFrameToggled() {
if (!a_unit_label_) return;
if (radio_local_->isChecked()) {
a_unit_label_->setText("(model project length unit, e.g. millimetre)");
} else {
a_unit_label_->setText("(model map unit, e.g. metre)");
}
}
void ModelTransformationDialog::onAccepted() {
if (!federation_ || model_combo_->count() == 0) { accept(); return; }
const QString fed_id = model_combo_->currentData().toString();
ModelTransformation xf;
xf.a_frame = radio_local_->isChecked() ? AFrame::ModelLocal : AFrame::ModelGlobal;
xf.a = Eigen::Vector3d(a_x_->value(), a_y_->value(), a_z_->value());
xf.b = Eigen::Vector3d(b_x_->value(), b_y_->value(), b_z_->value());
xf.rxyz_deg = Eigen::Vector3d(rx_->value(), ry_->value(), rz_->value());
xf.pivot = Eigen::Vector3d(pivot_x_->value(), pivot_y_->value(), pivot_z_->value());
federation_->setModelTransformation(fed_id, xf);
accept();
}
@@ -1,88 +0,0 @@
/********************************************************************************
* *
* 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/>. *
* *
********************************************************************************/
#ifndef MODELTRANSFORMATIONDIALOG_H
#define MODELTRANSFORMATIONDIALOG_H
#include <QDialog>
#include <QString>
QT_BEGIN_NAMESPACE
class QComboBox;
class QDoubleSpinBox;
class QLabel;
class QRadioButton;
QT_END_NAMESPACE
class Federation;
// Edits one model's ModelTransformation (the per-model placement within
// the federation: a_frame, a, b, rxyz Euler degrees, pivot). A combobox
// at the top picks which model to edit. Switching models discards any
// unsaved form edits — Ok saves the currently-visible model. On Ok,
// calls Federation::setModelTransformation, which fires
// modelTransformationChanged → MainWindow recomposes the viewport for
// that model.
class ModelTransformationDialog : public QDialog {
Q_OBJECT
public:
explicit ModelTransformationDialog(Federation* federation, QWidget* parent = nullptr);
protected:
void showEvent(QShowEvent* event) override;
private slots:
void onModelChanged(int idx);
void onAFrameToggled();
void onAccepted();
private:
void setupUi();
void populateModelCombo();
void syncFromModel(const QString& fed_id);
void refreshUnitLabels();
Federation* federation_ = nullptr;
QComboBox* model_combo_ = nullptr;
QRadioButton* radio_local_ = nullptr;
QRadioButton* radio_global_ = nullptr;
QDoubleSpinBox* a_x_ = nullptr;
QDoubleSpinBox* a_y_ = nullptr;
QDoubleSpinBox* a_z_ = nullptr;
QLabel* a_unit_label_ = nullptr;
QDoubleSpinBox* b_x_ = nullptr;
QDoubleSpinBox* b_y_ = nullptr;
QDoubleSpinBox* b_z_ = nullptr;
QLabel* b_unit_label_ = nullptr;
QDoubleSpinBox* rx_ = nullptr;
QDoubleSpinBox* ry_ = nullptr;
QDoubleSpinBox* rz_ = nullptr;
QDoubleSpinBox* pivot_x_ = nullptr;
QDoubleSpinBox* pivot_y_ = nullptr;
QDoubleSpinBox* pivot_z_ = nullptr;
QLabel* pivot_unit_label_ = nullptr;
};
#endif
-171
View File
@@ -1,171 +0,0 @@
/********************************************************************************
* *
* 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 "SettingsWindow.h"
#include "AppSettings.h"
#include <QCheckBox>
#include <QDialogButtonBox>
#include <QDoubleSpinBox>
#include <QFormLayout>
#include <QLineEdit>
#include <QShowEvent>
#include <QSpinBox>
#include <QVBoxLayout>
SettingsWindow::SettingsWindow(QWidget *parent)
: QDialog(parent)
{
setWindowTitle("Settings");
setupUi();
}
void SettingsWindow::setupUi() {
auto* form = new QFormLayout();
geometry_library_edit_ = new QLineEdit(this);
geometry_library_edit_->setMinimumWidth(280);
form->addRow("Geometry Library", geometry_library_edit_);
show_stats_check_ = new QCheckBox(this);
form->addRow("Show Performance Stats", show_stats_check_);
backface_culling_check_ = new QCheckBox(this);
backface_culling_check_->setToolTip(
"Skip triangles facing away from the camera. Big FPS win on "
"closed solids; disable if you see holes in open geometry.");
form->addRow("Backface Culling", backface_culling_check_);
void_limit_spin_ = new QSpinBox(this);
void_limit_spin_->setRange(0, 100000);
void_limit_spin_->setToolTip(
"Skip elements with more openings (HasOpenings) than this. "
"A handful of pathological elements can dominate boolean-subtraction "
"time; dropping them keeps load times sane.");
form->addRow("Void Limit", void_limit_spin_);
deflection_tolerance_spin_ = new QDoubleSpinBox(this);
deflection_tolerance_spin_->setRange(0.000001, 1000.0);
deflection_tolerance_spin_->setDecimals(6);
deflection_tolerance_spin_->setSingleStep(0.001);
deflection_tolerance_spin_->setToolTip(
"Linear chord error between curved geometry and its triangulation, "
"in model length units. Smaller = smoother curves but more "
"triangles and slower load.");
form->addRow("Deflection Tolerance", deflection_tolerance_spin_);
angular_tolerance_spin_ = new QDoubleSpinBox(this);
angular_tolerance_spin_->setRange(0.000001, 3.141592);
angular_tolerance_spin_->setDecimals(6);
angular_tolerance_spin_->setSingleStep(0.05);
angular_tolerance_spin_->setToolTip(
"Maximum angle (radians) between adjacent facet normals on a "
"curved surface. Smaller = smoother shading but more triangles.");
form->addRow("Angular Tolerance", angular_tolerance_spin_);
min_pixel_radius_spin_ = new QDoubleSpinBox(this);
min_pixel_radius_spin_->setRange(0.0, 100.0);
min_pixel_radius_spin_->setDecimals(2);
min_pixel_radius_spin_->setSingleStep(0.5);
min_pixel_radius_spin_->setToolTip(
"Minimum projected sphere radius (in pixels) for an instance to "
"be drawn. Bigger = faster but more pop-in on small detail.");
form->addRow("Min Pixel Radius", min_pixel_radius_spin_);
motion_min_pixel_radius_spin_ = new QDoubleSpinBox(this);
motion_min_pixel_radius_spin_->setRange(0.0, 100.0);
motion_min_pixel_radius_spin_->setDecimals(2);
motion_min_pixel_radius_spin_->setSingleStep(1.0);
motion_min_pixel_radius_spin_->setToolTip(
"Aggressive cull threshold while the camera is moving. 0 = no "
"motion boost (motion uses the same threshold as still frames). "
"Big perceived FPS win on heavy scenes.");
form->addRow("Motion Min Pixel Radius", motion_min_pixel_radius_spin_);
lod1_pixel_threshold_spin_ = new QDoubleSpinBox(this);
lod1_pixel_threshold_spin_->setRange(0.0, 1000.0);
lod1_pixel_threshold_spin_->setDecimals(1);
lod1_pixel_threshold_spin_->setSingleStep(1.0);
lod1_pixel_threshold_spin_->setToolTip(
"Pixel radius below which an instance switches to its LOD1 "
"representation. 0 disables LOD1 entirely (always draw LOD0).");
form->addRow("LOD1 Pixel Threshold", lod1_pixel_threshold_spin_);
hiz_enabled_check_ = new QCheckBox(this);
hiz_enabled_check_->setToolTip(
"Enable HiZ (hierarchical Z) occlusion culling. Hides geometry "
"behind opaque blockers based on a downsampled depth pyramid "
"from the previous frame. Big perf win on dense interiors.");
form->addRow("HiZ Occlusion", hiz_enabled_check_);
hiz_resolution_spin_ = new QSpinBox(this);
hiz_resolution_spin_->setRange(64, 4096);
hiz_resolution_spin_->setSingleStep(64);
hiz_resolution_spin_->setToolTip(
"Base HiZ pyramid width in texels (height tracks aspect). "
"Bigger = tighter occlusion but more readback bandwidth. "
"Changes take effect on next viewport reinitialization.");
form->addRow("HiZ Resolution", hiz_resolution_spin_);
auto* button_box = new QDialogButtonBox(
QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
auto* root = new QVBoxLayout(this);
root->addLayout(form);
root->addWidget(button_box);
connect(button_box, &QDialogButtonBox::accepted, this, &SettingsWindow::onAccepted);
connect(button_box, &QDialogButtonBox::rejected, this, &SettingsWindow::reject);
}
void SettingsWindow::showEvent(QShowEvent* event) {
// Re-sync widgets from the persisted settings every time the dialog is
// shown, so a previous Cancel doesn't leave stale text in the field.
syncFromSettings();
QDialog::showEvent(event);
}
void SettingsWindow::syncFromSettings() {
geometry_library_edit_->setText(AppSettings::instance().geometryLibrary());
show_stats_check_->setChecked(AppSettings::instance().showStats());
backface_culling_check_->setChecked(AppSettings::instance().backfaceCulling());
void_limit_spin_->setValue(AppSettings::instance().voidLimit());
deflection_tolerance_spin_->setValue(AppSettings::instance().deflectionTolerance());
angular_tolerance_spin_->setValue(AppSettings::instance().angularTolerance());
min_pixel_radius_spin_->setValue(AppSettings::instance().minPixelRadius());
motion_min_pixel_radius_spin_->setValue(AppSettings::instance().motionMinPixelRadius());
lod1_pixel_threshold_spin_->setValue(AppSettings::instance().lod1PixelThreshold());
hiz_enabled_check_->setChecked(AppSettings::instance().hizEnabled());
hiz_resolution_spin_->setValue(AppSettings::instance().hizResolution());
}
void SettingsWindow::onAccepted() {
AppSettings::instance().setGeometryLibrary(geometry_library_edit_->text());
AppSettings::instance().setShowStats(show_stats_check_->isChecked());
AppSettings::instance().setBackfaceCulling(backface_culling_check_->isChecked());
AppSettings::instance().setVoidLimit(void_limit_spin_->value());
AppSettings::instance().setDeflectionTolerance(deflection_tolerance_spin_->value());
AppSettings::instance().setAngularTolerance(angular_tolerance_spin_->value());
AppSettings::instance().setMinPixelRadius(min_pixel_radius_spin_->value());
AppSettings::instance().setMotionMinPixelRadius(motion_min_pixel_radius_spin_->value());
AppSettings::instance().setLod1PixelThreshold(lod1_pixel_threshold_spin_->value());
AppSettings::instance().setHizEnabled(hiz_enabled_check_->isChecked());
AppSettings::instance().setHizResolution(hiz_resolution_spin_->value());
accept();
}
-59
View File
@@ -1,59 +0,0 @@
/********************************************************************************
* *
* 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/>. *
* *
********************************************************************************/
#ifndef SETTINGSWINDOW_H
#define SETTINGSWINDOW_H
#include <QDialog>
class QCheckBox;
class QDoubleSpinBox;
class QLineEdit;
class QShowEvent;
class QSpinBox;
class SettingsWindow : public QDialog {
Q_OBJECT
public:
explicit SettingsWindow(QWidget *parent = nullptr);
protected:
void showEvent(QShowEvent* event) override;
private slots:
void onAccepted();
private:
void setupUi();
void syncFromSettings();
QLineEdit* geometry_library_edit_ = nullptr;
QCheckBox* show_stats_check_ = nullptr;
QCheckBox* backface_culling_check_ = nullptr;
QSpinBox* void_limit_spin_ = nullptr;
QDoubleSpinBox* deflection_tolerance_spin_ = nullptr;
QDoubleSpinBox* angular_tolerance_spin_ = nullptr;
QDoubleSpinBox* min_pixel_radius_spin_ = nullptr;
QDoubleSpinBox* motion_min_pixel_radius_spin_ = nullptr;
QDoubleSpinBox* lod1_pixel_threshold_spin_ = nullptr;
QSpinBox* hiz_resolution_spin_ = nullptr;
QCheckBox* hiz_enabled_check_ = nullptr;
};
#endif

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Before

Width:  |  Height:  |  Size: 1005 B

After

Width:  |  Height:  |  Size: 1005 B

Before

Width:  |  Height:  |  Size: 644 B

After

Width:  |  Height:  |  Size: 644 B

Before

Width:  |  Height:  |  Size: 227 B

After

Width:  |  Height:  |  Size: 227 B

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Before

Width:  |  Height:  |  Size: 562 B

After

Width:  |  Height:  |  Size: 562 B

Before

Width:  |  Height:  |  Size: 556 B

After

Width:  |  Height:  |  Size: 556 B

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Before

Width:  |  Height:  |  Size: 834 B

After

Width:  |  Height:  |  Size: 834 B

Before

Width:  |  Height:  |  Size: 437 B

After

Width:  |  Height:  |  Size: 437 B

Before

Width:  |  Height:  |  Size: 611 B

After

Width:  |  Height:  |  Size: 611 B

Before

Width:  |  Height:  |  Size: 688 B

After

Width:  |  Height:  |  Size: 688 B

Before

Width:  |  Height:  |  Size: 528 B

After

Width:  |  Height:  |  Size: 528 B

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Before

Width:  |  Height:  |  Size: 532 B

After

Width:  |  Height:  |  Size: 532 B

Before

Width:  |  Height:  |  Size: 465 B

After

Width:  |  Height:  |  Size: 465 B

Before

Width:  |  Height:  |  Size: 426 B

After

Width:  |  Height:  |  Size: 426 B

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Before

Width:  |  Height:  |  Size: 674 B

After

Width:  |  Height:  |  Size: 674 B

Before

Width:  |  Height:  |  Size: 942 B

After

Width:  |  Height:  |  Size: 942 B

Before

Width:  |  Height:  |  Size: 691 B

After

Width:  |  Height:  |  Size: 691 B

Before

Width:  |  Height:  |  Size: 632 B

After

Width:  |  Height:  |  Size: 632 B

Before

Width:  |  Height:  |  Size: 651 B

After

Width:  |  Height:  |  Size: 651 B

Before

Width:  |  Height:  |  Size: 460 B

After

Width:  |  Height:  |  Size: 460 B

Before

Width:  |  Height:  |  Size: 700 B

After

Width:  |  Height:  |  Size: 700 B

Before

Width:  |  Height:  |  Size: 579 B

After

Width:  |  Height:  |  Size: 579 B

Before

Width:  |  Height:  |  Size: 426 B

After

Width:  |  Height:  |  Size: 426 B

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Before

Width:  |  Height:  |  Size: 435 B

After

Width:  |  Height:  |  Size: 435 B

Before

Width:  |  Height:  |  Size: 795 B

After

Width:  |  Height:  |  Size: 795 B

Before

Width:  |  Height:  |  Size: 995 B

After

Width:  |  Height:  |  Size: 995 B

Before

Width:  |  Height:  |  Size: 458 B

After

Width:  |  Height:  |  Size: 458 B

Before

Width:  |  Height:  |  Size: 717 B

After

Width:  |  Height:  |  Size: 717 B

Before

Width:  |  Height:  |  Size: 1020 B

After

Width:  |  Height:  |  Size: 1020 B

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Before

Width:  |  Height:  |  Size: 875 B

After

Width:  |  Height:  |  Size: 875 B

Before

Width:  |  Height:  |  Size: 786 B

After

Width:  |  Height:  |  Size: 786 B

Before

Width:  |  Height:  |  Size: 533 B

After

Width:  |  Height:  |  Size: 533 B

Before

Width:  |  Height:  |  Size: 516 B

After

Width:  |  Height:  |  Size: 516 B

Before

Width:  |  Height:  |  Size: 545 B

After

Width:  |  Height:  |  Size: 545 B

+40 -35
View File
@@ -1,3 +1,4 @@
// This file was generated with the assistance of an AI coding tool.
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
@@ -17,18 +18,40 @@
* *
********************************************************************************/
#include <QApplication>
#include <QSurfaceFormat>
#include <QCommandLineParser>
#include "MainWindow.h"
#include "InterfaceSettings.h"
#include "components/Style.h"
#include <QApplication>
#include <QCommandLineParser>
#include <QFont>
#include <QFontDatabase>
#include <QSurfaceFormat>
namespace {
void installUiFont() {
const int font_id = QFontDatabase::addApplicationFont(
":/fonts/DMSans-VariableFont_opsz,wght.ttf");
QString family;
if (font_id >= 0) {
const QStringList families = QFontDatabase::applicationFontFamilies(font_id);
if (!families.isEmpty()) {
family = families.front();
}
}
if (!family.isEmpty()) {
QApplication::setFont(QFont(family, 10));
}
}
} // namespace
int main(int argc, char* argv[]) {
QApplication app(argc, argv);
app.setApplicationName("IfcViewer");
app.setOrganizationName("IfcOpenShell");
// Request OpenGL 4.5 Core globally
QSurfaceFormat fmt;
fmt.setVersion(4, 5);
fmt.setProfile(QSurfaceFormat::CoreProfile);
@@ -38,39 +61,21 @@ int main(int argc, char* argv[]) {
QSurfaceFormat::setDefaultFormat(fmt);
QCommandLineParser parser;
parser.setApplicationDescription("IfcOpenShell IFC Viewer");
parser.setApplicationDescription("IfcOpenShell IFC viewer");
parser.addHelpOption();
parser.addPositionalArgument("files",
"IFC file(s) and/or one .ifcfed federation to open",
"[files...]");
parser.addOption({{"c", "camera"},
"Set camera: tx,ty,tz,dist,yaw,pitch", "params"});
parser.addOption({{"b", "benchmark"},
"Run N frames then print stats and exit", "frames"});
parser.process(app);
MainWindow window;
installUiFont();
const auto applyStyle = [&app]() {
app.setStyleSheet(ifcinterface::components::style::buildAppStyleSheet());
};
applyStyle();
QObject::connect(&ifcinterface::InterfaceSettings::instance(),
&ifcinterface::InterfaceSettings::themeChanged,
&app,
applyStyle);
ifcinterface::shell::MainWindow window;
window.show();
auto args = parser.positionalArguments();
QStringList file_args;
QString fed_arg;
for (const auto& a : args) {
if (fed_arg.isEmpty() && a.endsWith(".ifcfed", Qt::CaseInsensitive)) {
fed_arg = a;
} else {
file_args << a;
}
}
if (!fed_arg.isEmpty()) window.openFederation(fed_arg);
if (!file_args.isEmpty()) window.addFiles(file_args);
if (parser.isSet("camera")) {
window.setPendingCamera(parser.value("camera"));
}
if (parser.isSet("benchmark")) {
window.setPendingBenchmark(parser.value("benchmark").toInt());
}
return app.exec();
}
@@ -144,7 +144,7 @@ void ModelsPanelController::bindLoader(SceneLoader* loader) {
connect(loader, &SceneLoader::loadError, this,
[this, host = host_](uint32_t /*mid*/, const QString& message) {
session_state_->setStatusMessage("Error", message);
QMessageBox::warning(host, "IfcInterfaceMockup", message);
QMessageBox::warning(host, "IfcViewer", message);
});
connect(loader, &SceneLoader::allLoadsFinished, this,
[this, loader]() {

Some files were not shown because too many files have changed in this diff Show More