forked from 1b-agent/opencadstudio-upstream
perf(xref): fix O(n²) AcDs parse and skip host re-tessellation
Opening a drawing that xrefs several 3D-heavy DWGs (e.g. Clinic.dwg with 5 discipline files) took ~137s, effectively all of it inside the DWG parser's AcDs SAB blob extraction. Bump the acadrust pin to ceef045, which bounds the AcDs end-marker search so a missing marker family no longer scans the whole buffer per record. Total xref resolve for Clinic.dwg drops from ~97s to ~4s. Also make the post-xref mesh pass incremental: the host solids were already tessellated by the background loader and the merge assigns fresh handles to every imported entity, so `populate_missing_meshes_from_document` keeps the cached host meshes and tessellates only the merged xref solids instead of clearing and rebuilding the whole document. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
cbf454979d
commit
13de968ee9
3 files changed
+37
-7
No files matched your search
Generated
+1
-1
@@ -71,7 +71,7 @@ checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "acadrust"
|
name = "acadrust"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
source = "git+https://github.com/HakanSeven12/acadrust?branch=main#f76e41adb47b09c66b3032d3727468e4303bcaf0"
|
source = "git+https://github.com/HakanSeven12/acadrust?branch=main#ceef045ed9fe4658dfb1ad488fe12f65c0311135"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash 0.8.12",
|
"ahash 0.8.12",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
|||||||
@@ -394,10 +394,12 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
|
|||||||
// built the mesh caches above, so those caches contain none of
|
// built the mesh caches above, so those caches contain none of
|
||||||
// the xref'd geometry. The wire pass rebuilds from the document
|
// the xref'd geometry. The wire pass rebuilds from the document
|
||||||
// each frame (bump_geometry covers it), but 3D-solid meshes are
|
// each frame (bump_geometry covers it), but 3D-solid meshes are
|
||||||
// only tessellated by `populate_meshes_from_document` — re-run it
|
// only tessellated by populate — run the incremental variant so
|
||||||
// so xref'd solids (walls, floors, roofs) actually render. (#203)
|
// the already-cached host solids are kept and only the newly
|
||||||
|
// merged xref solids (walls, floors, roofs) are tessellated,
|
||||||
|
// avoiding a full re-tessellation of the whole drawing. (#203)
|
||||||
if xref_merged {
|
if xref_merged {
|
||||||
self.tabs[i].scene.populate_meshes_from_document();
|
self.tabs[i].scene.populate_missing_meshes_from_document();
|
||||||
}
|
}
|
||||||
self.tabs[i].scene.selected = rustc_hash::FxHashSet::default();
|
self.tabs[i].scene.selected = rustc_hash::FxHashSet::default();
|
||||||
self.tabs[i].scene.preview_wires = vec![];
|
self.tabs[i].scene.preview_wires = vec![];
|
||||||
|
|||||||
+31
-3
@@ -1209,8 +1209,28 @@ impl Scene {
|
|||||||
/// Called after loading a document or after undo/redo so that every
|
/// Called after loading a document or after undo/redo so that every
|
||||||
/// `Solid3D` entity is represented in the mesh cache.
|
/// `Solid3D` entity is represented in the mesh cache.
|
||||||
pub fn populate_meshes_from_document(&mut self) {
|
pub fn populate_meshes_from_document(&mut self) {
|
||||||
self.meshes.clear();
|
self.populate_meshes_impl(false);
|
||||||
self.block_meshes.clear();
|
}
|
||||||
|
|
||||||
|
/// Like [`populate_meshes_from_document`] but tessellates only solids
|
||||||
|
/// whose handle is not already cached — the existing meshes are kept.
|
||||||
|
///
|
||||||
|
/// Used after an XREF merge: the host document's solids were already
|
||||||
|
/// tessellated by the background loader, and the merge assigns brand-new
|
||||||
|
/// handles to every imported xref entity (see `merge_xref_into_block`),
|
||||||
|
/// so cached handles are guaranteed to be host solids. This turns the
|
||||||
|
/// post-xref pass from "re-tessellate host + all xrefs" into "tessellate
|
||||||
|
/// only the newly merged xref solids" — the dominant cost when a drawing
|
||||||
|
/// attaches several large xrefs. (#203)
|
||||||
|
pub fn populate_missing_meshes_from_document(&mut self) {
|
||||||
|
self.populate_meshes_impl(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn populate_meshes_impl(&mut self, incremental: bool) {
|
||||||
|
if !incremental {
|
||||||
|
self.meshes.clear();
|
||||||
|
self.block_meshes.clear();
|
||||||
|
}
|
||||||
// BLOCK-entity handles of the layout (model + paper) blocks. A solid
|
// BLOCK-entity handles of the layout (model + paper) blocks. A solid
|
||||||
// owned by one of these is top-level; anything else lives in a block
|
// owned by one of these is top-level; anything else lives in a block
|
||||||
// definition and is instanced per INSERT instead. (#123)
|
// definition and is instanced per INSERT instead. (#123)
|
||||||
@@ -1234,9 +1254,17 @@ impl Scene {
|
|||||||
.entities()
|
.entities()
|
||||||
.filter_map(|e| match e {
|
.filter_map(|e| match e {
|
||||||
EntityType::Solid3D(_) | EntityType::Region(_) | EntityType::Body(_) | EntityType::Surface(_) => {
|
EntityType::Solid3D(_) | EntityType::Region(_) | EntityType::Body(_) | EntityType::Surface(_) => {
|
||||||
|
let handle = e.common().handle;
|
||||||
|
// Incremental (post-xref) pass: leave already-tessellated
|
||||||
|
// host solids untouched, only build the newly merged ones.
|
||||||
|
if incremental
|
||||||
|
&& (self.meshes.contains_key(&handle) || self.block_meshes.contains_key(&handle))
|
||||||
|
{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
let color = self.render_style(e).0;
|
let color = self.render_style(e).0;
|
||||||
let top_level = layout_blocks.contains(&e.common().owner_handle);
|
let top_level = layout_blocks.contains(&e.common().owner_handle);
|
||||||
Some((e.common().handle, e.clone(), color, top_level))
|
Some((handle, e.clone(), color, top_level))
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in new issue
Block a user