ifcviewer: fix progress bar capping at ~1/n during streaming

The streamer carved [0,100] evenly across N prioritised contexts (and
again across the net/gross passes).  In practice nearly every element
yields from the first (Body) context, so smooth progress only ever
filled range/n of the bar — typically ~20% — before snapping forward.
Drive progress directly from yielded element count over total instead.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Dion Moult
2026-05-09 07:50:32 +10:00
parent 3e066443be
commit 994fa4bc03
+22 -33
View File
@@ -482,12 +482,15 @@ void GeometryStreamer::run(const std::string& path, int num_threads) {
QElapsedTimer stream_timer;
stream_timer.start();
// Split the 0100 progress range proportionally to element counts so
// the bar advances roughly with wall time across both passes.
// Drive the bar from yields across all passes/contexts. Earlier the
// [0,100] range was carved evenly across N prioritised contexts, but
// in practice nearly every element yields from the first (Body)
// context, so smooth progress only ever filled 1/n of the bar before
// jumping to the next allocation — visually, a typical 5-context
// file looked like it capped at ~20%.
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);
size_t yielded_count = 0;
int last_emitted_progress = 0;
// High-priority context first, so each element gets its preferred
// representation; lower-priority contexts only pick up elements the
@@ -497,9 +500,7 @@ void GeometryStreamer::run(const std::string& path, int num_threads) {
prioritisedContextIds(ifc_file_.get());
auto run_pass = [&](const std::set<int>& include_ids,
bool is_gross,
int progress_lo,
int progress_hi) -> bool {
bool is_gross) -> bool {
if (include_ids.empty()) return true;
ifcopenshell::geometry::Settings base_settings = settings;
@@ -510,8 +511,7 @@ void GeometryStreamer::run(const std::string& path, int num_threads) {
// Elements that haven't yet produced geometry from any context.
std::set<int> remaining = include_ids;
auto run_iterator = [&](ifcopenshell::geometry::Settings& iter_settings,
int sub_lo, int sub_hi) -> bool {
auto run_iterator = [&](ifcopenshell::geometry::Settings& iter_settings) -> bool {
if (remaining.empty()) return true;
std::vector<ifcopenshell::geometry::filter_t> filters;
@@ -535,14 +535,10 @@ void GeometryStreamer::run(const std::string& path, int num_threads) {
if (!iterator->initialize()) {
// No geometry survived this context for the remaining ids.
// Still advance progress so the bar doesn't stall.
progress_ = sub_hi;
emit progressChanged(sub_hi);
// Subsequent contexts will pick them up; nothing to emit.
return true;
}
int last_progress = sub_lo;
do {
if (cancel_requested_.load()) break;
@@ -656,11 +652,13 @@ void GeometryStreamer::run(const std::string& path, int num_threads) {
emit instanceReady(std::move(inst));
total_shapes++;
yielded_count++;
const int p = sub_lo +
(iterator->progress() * (sub_hi - sub_lo)) / 100;
if (p != last_progress) {
last_progress = p;
const int p = total_count > 0
? static_cast<int>((100 * yielded_count) / total_count)
: 100;
if (p != last_emitted_progress) {
last_emitted_progress = p;
progress_ = p;
emit progressChanged(p);
}
@@ -672,12 +670,10 @@ void GeometryStreamer::run(const std::string& path, int num_threads) {
if (prioritised_contexts.empty()) {
// No IfcGeometricRepresentationContext entities — fall back to
// a single iterator pass without context-id filtering.
return run_iterator(base_settings, progress_lo, progress_hi);
return run_iterator(base_settings);
}
const int range = progress_hi - progress_lo;
const int n = static_cast<int>(prioritised_contexts.size());
for (int i = 0; i < n; ++i) {
for (size_t i = 0; i < prioritised_contexts.size(); ++i) {
if (cancel_requested_.load()) break;
if (remaining.empty()) break;
@@ -685,22 +681,15 @@ void GeometryStreamer::run(const std::string& path, int num_threads) {
iter_settings.set("context-ids",
std::set<int>{ prioritised_contexts[i] });
const int sub_lo = progress_lo + (range * i) / n;
const int sub_hi = (i + 1 == n)
? progress_hi
: progress_lo + (range * (i + 1)) / n;
if (!run_iterator(iter_settings, sub_lo, sub_hi)) return false;
if (!run_iterator(iter_settings)) return false;
}
progress_ = progress_hi;
emit progressChanged(progress_hi);
return true;
};
if (!run_pass(net_ids, /*is_gross=*/false, 0, net_progress_end)) return;
if (!run_pass(net_ids, /*is_gross=*/false)) return;
if (!cancel_requested_.load()) {
run_pass(gross_ids, /*is_gross=*/true, net_progress_end, 100);
run_pass(gross_ids, /*is_gross=*/true);
}
progress_ = 100;