mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 01:41:57 +00:00
ifcviewer: load RocksDB-backed IFC models
The viewer can now open a .rdb directory (as produced by RocksDbSerializer / convert_path_to_rocksdb) anywhere it accepts an .ifc file. The full GUI gets an "Add Database..." File menu entry that opens a directory chooser; the streamer lets the file constructor autodetect the format and opens the store read-only so multiple viewers can share a database without taking the exclusive RocksDB lock. Parallel mapping on RocksDB-backed files still produces non-deterministic shape counts (the race is outside the instance cache), so force num_threads=1 for the iterator when the storage is RocksDB. Serial RocksDB (~2.6s) and parallel SPF (~0.7s) both produce 107 shapes on AC20-FZK-Haus; @todo in-source points at the remaining thread-safety work. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -132,6 +132,7 @@ void MainWindow::setupMenus() {
|
||||
auto* file_menu = menuBar()->addMenu("&File");
|
||||
auto* open_action = file_menu->addAction("&Add Files...", this, &MainWindow::onFileOpen);
|
||||
open_action->setShortcut(QKeySequence::Open);
|
||||
file_menu->addAction("Add &Database...", this, &MainWindow::onDatabaseOpen);
|
||||
file_menu->addAction("&Settings...", this, &MainWindow::onFileSettings);
|
||||
file_menu->addSeparator();
|
||||
file_menu->addAction("&Quit", QKeySequence::Quit, qApp, &QApplication::quit);
|
||||
@@ -146,6 +147,15 @@ void MainWindow::onFileOpen() {
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::onDatabaseOpen() {
|
||||
QString path = QFileDialog::getExistingDirectory(
|
||||
this, "Add IFC Database", QString(),
|
||||
QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
|
||||
if (!path.isEmpty()) {
|
||||
addFiles({ path });
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::onFileSettings() {
|
||||
if (settings_ == nullptr) {
|
||||
settings_ = new SettingsWindow(this);
|
||||
|
||||
@@ -48,6 +48,7 @@ public:
|
||||
|
||||
private slots:
|
||||
void onFileOpen();
|
||||
void onDatabaseOpen();
|
||||
void onFileSettings();
|
||||
void onObjectPicked(uint32_t object_id);
|
||||
void onTreeSelectionChanged();
|
||||
|
||||
@@ -263,7 +263,10 @@ static void worldAabbFromLocal(const float local_min[3],
|
||||
|
||||
void GeometryStreamer::run(const std::string& path, int num_threads) {
|
||||
try {
|
||||
ifc_file_ = std::make_unique<ifcopenshell::file>(path);
|
||||
// read_only is a no-op for SPF; for RocksDB it allows concurrent
|
||||
// readers and avoids acquiring the exclusive DB lock.
|
||||
ifc_file_ = std::make_unique<ifcopenshell::file>(
|
||||
path, ifcopenshell::FT_AUTODETECT, /*read_only=*/true);
|
||||
} catch (const std::exception& e) {
|
||||
emit errorOccurred(QString("Failed to parse IFC file: %1").arg(e.what()));
|
||||
return;
|
||||
@@ -281,6 +284,12 @@ void GeometryStreamer::run(const std::string& path, int num_threads) {
|
||||
// time, but results are cached in the sidecar so it's a one-shot hit.
|
||||
settings.set("reorient-shells", true);
|
||||
|
||||
// @todo parallel mapping on RocksDB-backed files still races somewhere
|
||||
// outside the instance cache, producing inconsistent shape counts. Force
|
||||
// serial iteration for RocksDB until the read path is fully thread-safe.
|
||||
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;
|
||||
|
||||
std::unique_ptr<IfcGeom::Iterator> iterator;
|
||||
try {
|
||||
const std::string geometry_library =
|
||||
@@ -288,7 +297,8 @@ void GeometryStreamer::run(const std::string& path, int num_threads) {
|
||||
auto kernel = ifcopenshell::geometry::kernels::construct(
|
||||
ifc_file_.get(), geometry_library, settings);
|
||||
iterator = std::make_unique<IfcGeom::Iterator>(
|
||||
std::move(kernel), settings, ifc_file_.get(), std::vector<ifcopenshell::geometry::filter_t>(), num_threads);
|
||||
std::move(kernel), settings, ifc_file_.get(),
|
||||
std::vector<ifcopenshell::geometry::filter_t>(), effective_threads);
|
||||
} catch (const std::exception& e) {
|
||||
emit errorOccurred(QString("Failed to create geometry iterator: %1").arg(e.what()));
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user