forked from 1b-agent/opencadstudio-upstream
perf(clipboard): derive the paste anchor from bounding boxes
COPYCLIP/CUTCLIP computed the clipboard anchor by tessellating every selected entity and averaging all wire vertices — O(total geometry), ~250 ms when copying a whole drawing. The anchor only fixes which point of the selection sits under the cursor at paste, so the mean of each entity's bounding-box centre is an equally valid, far cheaper origin.
This commit is contained in:
1 parent
4d7588e1e0
commit
56835791af
2 files changed
+25
-25
No files matched your search
@@ -70,8 +70,9 @@ impl OpenCADStudio {
|
||||
.iter()
|
||||
.filter_map(|&h| self.tabs[i].scene.document.get_entity(h).cloned())
|
||||
.collect();
|
||||
self.clipboard_centroid = super::super::helpers::entities_centroid(
|
||||
&self.tabs[i].scene.wire_models_for(&handles),
|
||||
self.clipboard_centroid = super::super::helpers::entities_centroid_by_bbox(
|
||||
&self.tabs[i].scene.document,
|
||||
&handles,
|
||||
);
|
||||
self.clipboard = entities;
|
||||
self.clipboard_deps = super::super::ClipboardDeps::capture(
|
||||
@@ -158,8 +159,9 @@ impl OpenCADStudio {
|
||||
.iter()
|
||||
.filter_map(|&h| self.tabs[i].scene.document.get_entity(h).cloned())
|
||||
.collect();
|
||||
self.clipboard_centroid = super::super::helpers::entities_centroid(
|
||||
&self.tabs[i].scene.wire_models_for(&handles),
|
||||
self.clipboard_centroid = super::super::helpers::entities_centroid_by_bbox(
|
||||
&self.tabs[i].scene.document,
|
||||
&handles,
|
||||
);
|
||||
let count = entities.len();
|
||||
self.clipboard = entities;
|
||||
|
||||
+19
-21
@@ -1,4 +1,3 @@
|
||||
use crate::scene::WireModel;
|
||||
use crate::ui::overlay::GridPlane;
|
||||
use acadrust::tables::Ucs;
|
||||
|
||||
@@ -253,28 +252,27 @@ pub(super) fn polar_constrain_near(
|
||||
|
||||
// ── Clipboard / selection helpers ──────────────────────────────────────────
|
||||
|
||||
/// Compute the centroid of a set of wire models (average of all points).
|
||||
pub(super) fn entities_centroid(wires: &[WireModel]) -> glam::DVec3 {
|
||||
// Reconstruct each vertex's absolute f64 from the double-single high/low
|
||||
// pair and accumulate in f64: summing the f32 `points` alone at UTM scale
|
||||
// (~5.7e6) both quantizes each term ~0.5 m and loses low bits across the
|
||||
// running total, drifting the paste base / block base metres off.
|
||||
/// Cheap copy/paste anchor: the mean of each entity's bounding-box centre.
|
||||
/// Replaces averaging every tessellated wire vertex, which cost O(total
|
||||
/// geometry) and stalled a whole-drawing copy. The anchor only sets which point
|
||||
/// of the selection sits under the cursor, so a per-entity bbox centre is an
|
||||
/// equally valid, far cheaper origin.
|
||||
pub(super) fn entities_centroid_by_bbox(
|
||||
doc: &acadrust::CadDocument,
|
||||
handles: &[acadrust::Handle],
|
||||
) -> glam::DVec3 {
|
||||
let mut sum = glam::DVec3::ZERO;
|
||||
let mut count = 0usize;
|
||||
for w in wires {
|
||||
for (i, p) in w.points.iter().enumerate() {
|
||||
// Wire models carry NaN points as separators between disjoint
|
||||
// segments; summing them poisons the whole centroid into NaN,
|
||||
// which then makes every paste base point NaN. (#129)
|
||||
if !p[0].is_finite() || !p[1].is_finite() || !p[2].is_finite() {
|
||||
continue;
|
||||
}
|
||||
let l = w.points_low.get(i).copied().unwrap_or([0.0; 3]);
|
||||
sum += glam::DVec3::new(
|
||||
p[0] as f64 + l[0] as f64,
|
||||
p[1] as f64 + l[1] as f64,
|
||||
p[2] as f64 + l[2] as f64,
|
||||
);
|
||||
for &h in handles {
|
||||
let Some(e) = doc.get_entity(h) else { continue };
|
||||
let bb = e.as_entity().bounding_box();
|
||||
let c = glam::DVec3::new(
|
||||
(bb.min.x + bb.max.x) * 0.5,
|
||||
(bb.min.y + bb.max.y) * 0.5,
|
||||
(bb.min.z + bb.max.z) * 0.5,
|
||||
);
|
||||
if c.x.is_finite() && c.y.is_finite() && c.z.is_finite() {
|
||||
sum += c;
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user