mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-24 12:07:06 +00:00
ifcviewer: filter iterator to net IfcElements, void-limit setting
Mirror bonsai's IfcImporter.process_element_filter so the streamer walks only IfcElement (plus IfcProxy on IFC2X3/IFC4), drops IfcFeatureElement except IfcSurfaceFeature, and routes elements with more openings than the configurable void limit through a second iterator pass with disable-opening-subtractions=true. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -25,6 +25,7 @@
|
|||||||
#include <QFormLayout>
|
#include <QFormLayout>
|
||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
#include <QShowEvent>
|
#include <QShowEvent>
|
||||||
|
#include <QSpinBox>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
SettingsWindow::SettingsWindow(QWidget *parent)
|
SettingsWindow::SettingsWindow(QWidget *parent)
|
||||||
@@ -57,6 +58,14 @@ void SettingsWindow::setupUi() {
|
|||||||
"and, on sidecar hits, avoids a second file read.");
|
"and, on sidecar hits, avoids a second file read.");
|
||||||
form->addRow("Load Property Data Source", load_data_source_check_);
|
form->addRow("Load Property Data Source", load_data_source_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_);
|
||||||
|
|
||||||
auto* button_box = new QDialogButtonBox(
|
auto* button_box = new QDialogButtonBox(
|
||||||
QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
|
QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
|
||||||
|
|
||||||
@@ -80,6 +89,7 @@ void SettingsWindow::syncFromSettings() {
|
|||||||
show_stats_check_->setChecked(AppSettings::instance().showStats());
|
show_stats_check_->setChecked(AppSettings::instance().showStats());
|
||||||
backface_culling_check_->setChecked(AppSettings::instance().backfaceCulling());
|
backface_culling_check_->setChecked(AppSettings::instance().backfaceCulling());
|
||||||
load_data_source_check_->setChecked(AppSettings::instance().loadDataSource());
|
load_data_source_check_->setChecked(AppSettings::instance().loadDataSource());
|
||||||
|
void_limit_spin_->setValue(AppSettings::instance().voidLimit());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SettingsWindow::onAccepted() {
|
void SettingsWindow::onAccepted() {
|
||||||
@@ -87,5 +97,6 @@ void SettingsWindow::onAccepted() {
|
|||||||
AppSettings::instance().setShowStats(show_stats_check_->isChecked());
|
AppSettings::instance().setShowStats(show_stats_check_->isChecked());
|
||||||
AppSettings::instance().setBackfaceCulling(backface_culling_check_->isChecked());
|
AppSettings::instance().setBackfaceCulling(backface_culling_check_->isChecked());
|
||||||
AppSettings::instance().setLoadDataSource(load_data_source_check_->isChecked());
|
AppSettings::instance().setLoadDataSource(load_data_source_check_->isChecked());
|
||||||
|
AppSettings::instance().setVoidLimit(void_limit_spin_->value());
|
||||||
accept();
|
accept();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
class QCheckBox;
|
class QCheckBox;
|
||||||
class QLineEdit;
|
class QLineEdit;
|
||||||
class QShowEvent;
|
class QShowEvent;
|
||||||
|
class QSpinBox;
|
||||||
|
|
||||||
class SettingsWindow : public QDialog {
|
class SettingsWindow : public QDialog {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -45,6 +46,7 @@ private:
|
|||||||
QCheckBox* show_stats_check_ = nullptr;
|
QCheckBox* show_stats_check_ = nullptr;
|
||||||
QCheckBox* backface_culling_check_ = nullptr;
|
QCheckBox* backface_culling_check_ = nullptr;
|
||||||
QCheckBox* load_data_source_check_ = nullptr;
|
QCheckBox* load_data_source_check_ = nullptr;
|
||||||
|
QSpinBox* void_limit_spin_ = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ constexpr const char* kGeometryLibraryDefault = "hybrid-cgal-simple-opencascade"
|
|||||||
constexpr const char* kShowStatsKey = "viewport/show_stats";
|
constexpr const char* kShowStatsKey = "viewport/show_stats";
|
||||||
constexpr const char* kBackfaceCullingKey = "viewport/backface_culling";
|
constexpr const char* kBackfaceCullingKey = "viewport/backface_culling";
|
||||||
constexpr const char* kLoadDataSourceKey = "loading/load_data_source";
|
constexpr const char* kLoadDataSourceKey = "loading/load_data_source";
|
||||||
|
constexpr const char* kVoidLimitKey = "loading/void_limit";
|
||||||
|
constexpr int kVoidLimitDefault = 30;
|
||||||
}
|
}
|
||||||
|
|
||||||
AppSettings& AppSettings::instance() {
|
AppSettings& AppSettings::instance() {
|
||||||
@@ -82,12 +84,26 @@ void AppSettings::setLoadDataSource(bool value) {
|
|||||||
emit loadDataSourceChanged(value);
|
emit loadDataSourceChanged(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int AppSettings::voidLimit() const {
|
||||||
|
return void_limit_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppSettings::setVoidLimit(int value) {
|
||||||
|
if (value < 0) value = 0;
|
||||||
|
if (void_limit_ == value) return;
|
||||||
|
void_limit_ = value;
|
||||||
|
persist();
|
||||||
|
emit voidLimitChanged(value);
|
||||||
|
}
|
||||||
|
|
||||||
void AppSettings::load() {
|
void AppSettings::load() {
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
geometry_library_ = settings.value(kGeometryLibraryKey, kGeometryLibraryDefault).toString();
|
geometry_library_ = settings.value(kGeometryLibraryKey, kGeometryLibraryDefault).toString();
|
||||||
show_stats_ = settings.value(kShowStatsKey, false).toBool();
|
show_stats_ = settings.value(kShowStatsKey, false).toBool();
|
||||||
backface_culling_ = settings.value(kBackfaceCullingKey, true).toBool();
|
backface_culling_ = settings.value(kBackfaceCullingKey, true).toBool();
|
||||||
load_data_source_ = settings.value(kLoadDataSourceKey, true).toBool();
|
load_data_source_ = settings.value(kLoadDataSourceKey, true).toBool();
|
||||||
|
void_limit_ = settings.value(kVoidLimitKey, kVoidLimitDefault).toInt();
|
||||||
|
if (void_limit_ < 0) void_limit_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppSettings::persist() {
|
void AppSettings::persist() {
|
||||||
@@ -96,4 +112,5 @@ void AppSettings::persist() {
|
|||||||
settings.setValue(kShowStatsKey, show_stats_);
|
settings.setValue(kShowStatsKey, show_stats_);
|
||||||
settings.setValue(kBackfaceCullingKey, backface_culling_);
|
settings.setValue(kBackfaceCullingKey, backface_culling_);
|
||||||
settings.setValue(kLoadDataSourceKey, load_data_source_);
|
settings.setValue(kLoadDataSourceKey, load_data_source_);
|
||||||
|
settings.setValue(kVoidLimitKey, void_limit_);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,11 +47,18 @@ public:
|
|||||||
bool loadDataSource() const;
|
bool loadDataSource() const;
|
||||||
void setLoadDataSource(bool value);
|
void setLoadDataSource(bool value);
|
||||||
|
|
||||||
|
// Skip elements with more than this many voids (HasOpenings inverse).
|
||||||
|
// Boolean subtraction of many openings is the dominant cost in some
|
||||||
|
// pathological exports; dropping those elements keeps load times sane.
|
||||||
|
int voidLimit() const;
|
||||||
|
void setVoidLimit(int value);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void geometryLibraryChanged(const QString& value);
|
void geometryLibraryChanged(const QString& value);
|
||||||
void showStatsChanged(bool value);
|
void showStatsChanged(bool value);
|
||||||
void backfaceCullingChanged(bool value);
|
void backfaceCullingChanged(bool value);
|
||||||
void loadDataSourceChanged(bool value);
|
void loadDataSourceChanged(bool value);
|
||||||
|
void voidLimitChanged(int value);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AppSettings();
|
AppSettings();
|
||||||
@@ -62,6 +69,7 @@ private:
|
|||||||
bool show_stats_ = false;
|
bool show_stats_ = false;
|
||||||
bool backface_culling_ = true;
|
bool backface_culling_ = true;
|
||||||
bool load_data_source_ = true;
|
bool load_data_source_ = true;
|
||||||
|
int void_limit_ = 30;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // APPSETTINGS_H
|
#endif // APPSETTINGS_H
|
||||||
|
|||||||
@@ -21,6 +21,8 @@
|
|||||||
#include "AppSettings.h"
|
#include "AppSettings.h"
|
||||||
#include "../ifcgeom/hybrid_kernel.h"
|
#include "../ifcgeom/hybrid_kernel.h"
|
||||||
#include "../ifcgeom/taxonomy.h"
|
#include "../ifcgeom/taxonomy.h"
|
||||||
|
#include "../ifcgeom/IfcGeomFilter.h"
|
||||||
|
#include "../ifcparse/express.h"
|
||||||
|
|
||||||
#include <Eigen/Dense>
|
#include <Eigen/Dense>
|
||||||
|
|
||||||
@@ -30,6 +32,7 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QElapsedTimer>
|
#include <QElapsedTimer>
|
||||||
@@ -294,30 +297,59 @@ void GeometryStreamer::run(const std::string& path, int num_threads) {
|
|||||||
const bool is_rocksdb = std::holds_alternative<ifcopenshell::impl::rocks_db_file_storage>(ifc_file_->storage_);
|
const bool is_rocksdb = std::holds_alternative<ifcopenshell::impl::rocks_db_file_storage>(ifc_file_->storage_);
|
||||||
const int effective_threads = is_rocksdb ? 1 : num_threads;
|
const int effective_threads = is_rocksdb ? 1 : num_threads;
|
||||||
|
|
||||||
std::unique_ptr<IfcGeom::Iterator> iterator;
|
// Mirror bonsai's IfcImporter.process_element_filter: walk IfcElement
|
||||||
try {
|
// (plus IfcProxy on IFC2X3/IFC4), drop IfcFeatureElement except
|
||||||
const std::string geometry_library =
|
// IfcSurfaceFeature, and split elements with more openings than the
|
||||||
AppSettings::instance().geometryLibrary().toStdString();
|
// configured void limit into a "gross" set that is rendered without
|
||||||
auto kernel = ifcopenshell::geometry::kernels::construct(
|
// opening subtractions. Both sets become include filters so we don't
|
||||||
ifc_file_.get(), geometry_library, settings);
|
// waste time mapping openings, spaces, grids, etc.
|
||||||
iterator = std::make_unique<IfcGeom::Iterator>(
|
std::set<int> net_ids;
|
||||||
std::move(kernel), settings, ifc_file_.get(),
|
std::set<int> gross_ids;
|
||||||
std::vector<ifcopenshell::geometry::filter_t>(), effective_threads);
|
{
|
||||||
} catch (const std::exception& e) {
|
const std::string& schema_name = ifc_file_->schema()->name();
|
||||||
emit errorOccurred(QString("Failed to create geometry iterator: %1").arg(e.what()));
|
std::vector<express::Base> elements =
|
||||||
return;
|
ifc_file_->instances_by_type("IfcElement");
|
||||||
|
if (schema_name == "IFC2X3" || schema_name == "IFC4") {
|
||||||
|
auto proxies = ifc_file_->instances_by_type("IfcProxy");
|
||||||
|
elements.insert(elements.end(), proxies.begin(), proxies.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
const int void_limit = AppSettings::instance().voidLimit();
|
||||||
|
for (const auto& e : elements) {
|
||||||
|
const auto& decl = e.declaration();
|
||||||
|
if (decl.is("IfcFeatureElement") && !decl.is("IfcSurfaceFeature")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int opening_count = 0;
|
||||||
|
if (decl.is("IfcElement")) {
|
||||||
|
try {
|
||||||
|
opening_count = static_cast<int>(
|
||||||
|
e.as<express::Entity>().get_inverse("HasOpenings").size());
|
||||||
|
} catch (...) {
|
||||||
|
// HasOpenings not declared on this entity — treat as 0.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (opening_count > void_limit) {
|
||||||
|
gross_ids.insert(e.id());
|
||||||
|
} else {
|
||||||
|
net_ids.insert(e.id());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!iterator->initialize()) {
|
if (net_ids.empty() && gross_ids.empty()) {
|
||||||
emit errorOccurred("No geometry found in IFC file");
|
emit errorOccurred("No geometry-bearing elements found in IFC file");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!gross_ids.empty()) {
|
||||||
|
qDebug("Excessive voids: %zu element(s) will be loaded without "
|
||||||
|
"opening subtractions",
|
||||||
|
gross_ids.size());
|
||||||
|
}
|
||||||
|
|
||||||
int last_progress = 0;
|
// Shared dedup + AABB state across passes — same geom.id() across
|
||||||
|
// net/gross passes still maps to one mesh upload.
|
||||||
// geom.id() → local_mesh_id within this model.
|
|
||||||
std::unordered_map<std::string, uint32_t> geom_to_local_mesh_id;
|
std::unordered_map<std::string, uint32_t> geom_to_local_mesh_id;
|
||||||
// local_mesh_id → (local AABB) so we can derive world AABBs for later instances.
|
|
||||||
struct MeshAabb { float lmin[3], lmax[3]; };
|
struct MeshAabb { float lmin[3], lmax[3]; };
|
||||||
std::vector<MeshAabb> mesh_aabbs;
|
std::vector<MeshAabb> mesh_aabbs;
|
||||||
|
|
||||||
@@ -326,92 +358,144 @@ void GeometryStreamer::run(const std::string& path, int num_threads) {
|
|||||||
QElapsedTimer stream_timer;
|
QElapsedTimer stream_timer;
|
||||||
stream_timer.start();
|
stream_timer.start();
|
||||||
|
|
||||||
do {
|
// Split the 0–100 progress range proportionally to element counts so
|
||||||
if (cancel_requested_.load()) break;
|
// the bar advances roughly with wall time across both passes.
|
||||||
|
const size_t total_count = net_ids.size() + gross_ids.size();
|
||||||
|
const int net_progress_end = total_count == 0
|
||||||
|
? 100
|
||||||
|
: static_cast<int>(100.0 * net_ids.size() / total_count + 0.5);
|
||||||
|
|
||||||
const IfcGeom::Element* elem = iterator->get();
|
auto run_pass = [&](const std::set<int>& include_ids,
|
||||||
if (!elem) continue;
|
bool is_gross,
|
||||||
|
int progress_lo,
|
||||||
|
int progress_hi) -> bool {
|
||||||
|
if (include_ids.empty()) return true;
|
||||||
|
|
||||||
const auto* tri_elem = dynamic_cast<const IfcGeom::TriangulationElement*>(elem);
|
ifcopenshell::geometry::Settings pass_settings = settings;
|
||||||
if (!tri_elem) continue;
|
if (is_gross) {
|
||||||
|
pass_settings.set("disable-opening-subtractions", true);
|
||||||
const auto& geom = tri_elem->geometry();
|
|
||||||
if (geom.verts().empty() || geom.faces().empty()) continue;
|
|
||||||
|
|
||||||
uint32_t object_id = next_object_id_++;
|
|
||||||
|
|
||||||
// Element metadata.
|
|
||||||
ElementInfo info;
|
|
||||||
info.object_id = object_id;
|
|
||||||
info.model_id = model_id_;
|
|
||||||
info.ifc_id = tri_elem->id();
|
|
||||||
info.guid = tri_elem->guid();
|
|
||||||
info.name = tri_elem->name();
|
|
||||||
info.type = tri_elem->type();
|
|
||||||
info.parent_id = tri_elem->parent_id();
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(elements_mutex_);
|
|
||||||
pending_elements_.push_back(std::move(info));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Representation dedup.
|
std::vector<ifcopenshell::geometry::filter_t> filters;
|
||||||
const std::string& geom_id = geom.id();
|
IfcGeom::instance_id_filter idf{
|
||||||
uint32_t local_mesh_id;
|
/*include=*/true, /*traverse=*/false, include_ids};
|
||||||
bool first_sight = false;
|
filters.push_back(idf);
|
||||||
if (geom_id.empty()) {
|
|
||||||
// No representation key — treat as unique.
|
std::unique_ptr<IfcGeom::Iterator> iterator;
|
||||||
local_mesh_id = total_meshes++;
|
try {
|
||||||
first_sight = true;
|
const std::string geometry_library =
|
||||||
} else {
|
AppSettings::instance().geometryLibrary().toStdString();
|
||||||
auto it = geom_to_local_mesh_id.find(geom_id);
|
auto kernel = ifcopenshell::geometry::kernels::construct(
|
||||||
if (it == geom_to_local_mesh_id.end()) {
|
ifc_file_.get(), geometry_library, pass_settings);
|
||||||
|
iterator = std::make_unique<IfcGeom::Iterator>(
|
||||||
|
std::move(kernel), pass_settings, ifc_file_.get(),
|
||||||
|
filters, effective_threads);
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
emit errorOccurred(QString("Failed to create geometry iterator: %1").arg(e.what()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!iterator->initialize()) {
|
||||||
|
// Empty pass — no geometry survived for these ids. Still
|
||||||
|
// advance progress to the upper bound so the bar doesn't stall.
|
||||||
|
progress_ = progress_hi;
|
||||||
|
emit progressChanged(progress_hi);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int last_progress = progress_lo;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (cancel_requested_.load()) break;
|
||||||
|
|
||||||
|
const IfcGeom::Element* elem = iterator->get();
|
||||||
|
if (!elem) continue;
|
||||||
|
|
||||||
|
const auto* tri_elem = dynamic_cast<const IfcGeom::TriangulationElement*>(elem);
|
||||||
|
if (!tri_elem) continue;
|
||||||
|
|
||||||
|
const auto& geom = tri_elem->geometry();
|
||||||
|
if (geom.verts().empty() || geom.faces().empty()) continue;
|
||||||
|
|
||||||
|
uint32_t object_id = next_object_id_++;
|
||||||
|
|
||||||
|
ElementInfo info;
|
||||||
|
info.object_id = object_id;
|
||||||
|
info.model_id = model_id_;
|
||||||
|
info.ifc_id = tri_elem->id();
|
||||||
|
info.guid = tri_elem->guid();
|
||||||
|
info.name = tri_elem->name();
|
||||||
|
info.type = tri_elem->type();
|
||||||
|
info.parent_id = tri_elem->parent_id();
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(elements_mutex_);
|
||||||
|
pending_elements_.push_back(std::move(info));
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& geom_id = geom.id();
|
||||||
|
uint32_t local_mesh_id;
|
||||||
|
bool first_sight = false;
|
||||||
|
if (geom_id.empty()) {
|
||||||
local_mesh_id = total_meshes++;
|
local_mesh_id = total_meshes++;
|
||||||
geom_to_local_mesh_id.emplace(geom_id, local_mesh_id);
|
|
||||||
first_sight = true;
|
first_sight = true;
|
||||||
} else {
|
} else {
|
||||||
local_mesh_id = it->second;
|
auto it = geom_to_local_mesh_id.find(geom_id);
|
||||||
|
if (it == geom_to_local_mesh_id.end()) {
|
||||||
|
local_mesh_id = total_meshes++;
|
||||||
|
geom_to_local_mesh_id.emplace(geom_id, local_mesh_id);
|
||||||
|
first_sight = true;
|
||||||
|
} else {
|
||||||
|
local_mesh_id = it->second;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (first_sight) {
|
if (first_sight) {
|
||||||
MeshChunk mesh_chunk = buildMeshChunk(model_id_, local_mesh_id, tri_elem);
|
MeshChunk mesh_chunk = buildMeshChunk(model_id_, local_mesh_id, tri_elem);
|
||||||
MeshAabb ma;
|
MeshAabb ma;
|
||||||
for (int a = 0; a < 3; ++a) {
|
for (int a = 0; a < 3; ++a) {
|
||||||
ma.lmin[a] = mesh_chunk.local_aabb_min[a];
|
ma.lmin[a] = mesh_chunk.local_aabb_min[a];
|
||||||
ma.lmax[a] = mesh_chunk.local_aabb_max[a];
|
ma.lmax[a] = mesh_chunk.local_aabb_max[a];
|
||||||
|
}
|
||||||
|
if (mesh_aabbs.size() <= local_mesh_id) mesh_aabbs.resize(local_mesh_id + 1);
|
||||||
|
mesh_aabbs[local_mesh_id] = ma;
|
||||||
|
if (!mesh_chunk.indices.empty()) {
|
||||||
|
emit meshReady(std::move(mesh_chunk));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (mesh_aabbs.size() <= local_mesh_id) mesh_aabbs.resize(local_mesh_id + 1);
|
|
||||||
mesh_aabbs[local_mesh_id] = ma;
|
const Eigen::Matrix4d& mat_d = tri_elem->transformation().data()->ccomponents();
|
||||||
if (!mesh_chunk.indices.empty()) {
|
InstanceChunk inst;
|
||||||
emit meshReady(std::move(mesh_chunk));
|
inst.model_id = model_id_;
|
||||||
|
inst.local_mesh_id = local_mesh_id;
|
||||||
|
inst.object_id = object_id;
|
||||||
|
inst.color_override_rgba8 = 0;
|
||||||
|
for (int i = 0; i < 16; ++i) {
|
||||||
|
inst.transform[i] = static_cast<float>(mat_d.data()[i]);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Transform (column-major 4x4, cast to float).
|
const MeshAabb& ma = mesh_aabbs[local_mesh_id];
|
||||||
const Eigen::Matrix4d& mat_d = tri_elem->transformation().data()->ccomponents();
|
worldAabbFromLocal(ma.lmin, ma.lmax, inst.transform,
|
||||||
InstanceChunk inst;
|
inst.world_aabb_min, inst.world_aabb_max);
|
||||||
inst.model_id = model_id_;
|
|
||||||
inst.local_mesh_id = local_mesh_id;
|
|
||||||
inst.object_id = object_id;
|
|
||||||
inst.color_override_rgba8 = 0; // 0 = use baked vertex color
|
|
||||||
for (int i = 0; i < 16; ++i) {
|
|
||||||
inst.transform[i] = static_cast<float>(mat_d.data()[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
const MeshAabb& ma = mesh_aabbs[local_mesh_id];
|
emit instanceReady(std::move(inst));
|
||||||
worldAabbFromLocal(ma.lmin, ma.lmax, inst.transform,
|
total_shapes++;
|
||||||
inst.world_aabb_min, inst.world_aabb_max);
|
|
||||||
|
|
||||||
emit instanceReady(std::move(inst));
|
const int p = progress_lo +
|
||||||
total_shapes++;
|
(iterator->progress() * (progress_hi - progress_lo)) / 100;
|
||||||
|
if (p != last_progress) {
|
||||||
|
last_progress = p;
|
||||||
|
progress_ = p;
|
||||||
|
emit progressChanged(p);
|
||||||
|
}
|
||||||
|
} while (iterator->next());
|
||||||
|
|
||||||
int p = iterator->progress();
|
return true;
|
||||||
if (p != last_progress) {
|
};
|
||||||
last_progress = p;
|
|
||||||
progress_ = p;
|
if (!run_pass(net_ids, /*is_gross=*/false, 0, net_progress_end)) return;
|
||||||
emit progressChanged(p);
|
if (!cancel_requested_.load()) {
|
||||||
}
|
run_pass(gross_ids, /*is_gross=*/true, net_progress_end, 100);
|
||||||
} while (iterator->next());
|
}
|
||||||
|
|
||||||
progress_ = 100;
|
progress_ = 100;
|
||||||
emit progressChanged(100);
|
emit progressChanged(100);
|
||||||
|
|||||||
Reference in New Issue
Block a user