Kill the remaining Design-tab UI freezes

query_topology: indexing a body face-by-face was quadratic — face_by_index
re-walks the explorer and edge_by_index rebuilds the whole indexed map on every
single call. On a 15.7k-face / 25.6k-edge imported solid this blew past the
MCP 15 s main-thread timeout with the UI frozen throughout. GeometryEngine
gains faces_of()/edges_of(), which enumerate once in the very same order (ids
stay interchangeable with the _by_index accessors, so fillet/up_to_face targets
are unaffected). Measured on that body: 15 s timeout -> 0.46 s.

Feature ops: every commit-time m_doc.recompute() (fillet, cut, shell, boolean,
extrude, ...) now goes through recompute_guarded(), which runs the rebuild on a
worker thread. Live-preview/drag paths stay inline on purpose — yielding inside
a drag would be worse than the stall.

run_off_ui_thread(): the progress dialog is now created only after 300 ms, so a
fast op does not flash a dialog, while input stays blocked (wxWindowDisabler)
for the whole operation since the worker owns the document.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BVzKmX6Y1aEteit1HTXG4Q
This commit is contained in:
Tommaso Bianchi
2026-07-15 00:13:10 +02:00
co-authored by Claude Opus 4.8
parent 01aa6903f0
commit f4160595b0
5 changed files with 89 additions and 22 deletions
+3
View File
@@ -37,6 +37,9 @@ class DesignPanel : public wxPanel
public:
explicit DesignPanel(wxWindow* parent);
void on_tab_shown(); // re-sync bed to the active printer when the Design tab is activated
// Rebuild off the UI thread (progress dialog only if it turns out to be slow), so a feature
// op on a heavy imported solid does not freeze the window. Returns m_doc.recompute()'s result.
bool recompute_guarded(const wxString& message);
// MCP control hooks: let the external control server (McpControl.cpp) drive and
// perceive the SAME kernel the GUI uses. Called only on the wx main thread.