forked from 1b-agent/opencadstudio-upstream
fix(clipboard): paste anchor at bounding-box lower-left, not center (#285)
COPYCLIP/CUTCLIP used the mean of each entity's bounding-box centre as the paste anchor. Standard clipboard behaviour puts the lower-left corner of the box enclosing all copied items under the cursor. Union each entity's bbox min corner instead, and rename clipboard_centroid -> clipboard_base (COPYBASE also stores a picked point there, so "centroid" was inaccurate). Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
1 parent
f5870b011d
commit
c249a99d4c
6 files changed
+40
-38
No files matched your search
@@ -1,6 +1,6 @@
|
||||
// COPYBASE — copy the current selection to the clipboard using a base point the
|
||||
// user picks (rather than the selection's centroid, as COPYCLIP does). The
|
||||
// command only collects the base point; the host performs the copy when it
|
||||
// user picks (rather than the selection's lower-left corner, as COPYCLIP does).
|
||||
// The command only collects the base point; the host performs the copy when it
|
||||
// receives the dispatched `COPYBASE_AT <x> <y> <z>` token.
|
||||
|
||||
use glam::DVec3;
|
||||
|
||||
@@ -32,8 +32,9 @@ pub struct PasteCommand {
|
||||
/// just this 5-point rectangle instead — O(1) per frame. `None` = ghost the
|
||||
/// full wires.
|
||||
bbox_wire: Option<WireModel>,
|
||||
/// Centroid of the clipboard entities (offset origin for translation).
|
||||
centroid: Vec3,
|
||||
/// Paste anchor — lower-left corner of the clipboard entities (offset origin
|
||||
/// for translation; the point that tracks the cursor).
|
||||
base: Vec3,
|
||||
}
|
||||
|
||||
impl PasteCommand {
|
||||
@@ -44,17 +45,17 @@ impl PasteCommand {
|
||||
const MAX_PREVIEW_WIRES: usize = 20_000;
|
||||
const MAX_PREVIEW_POINTS: usize = 300_000;
|
||||
|
||||
pub fn new(wires: Vec<WireModel>, centroid: Vec3) -> Self {
|
||||
pub fn new(wires: Vec<WireModel>, base: Vec3) -> Self {
|
||||
let total_points: usize = wires.iter().map(|w| w.points.len()).sum();
|
||||
let too_heavy =
|
||||
wires.len() > Self::MAX_PREVIEW_WIRES || total_points > Self::MAX_PREVIEW_POINTS;
|
||||
if too_heavy {
|
||||
if let Some(bbox_wire) = Self::bbox_outline(&wires) {
|
||||
// Drop the full wires — the box is all the ghost needs now.
|
||||
return Self { wires: Vec::new(), bbox_wire: Some(bbox_wire), centroid };
|
||||
return Self { wires: Vec::new(), bbox_wire: Some(bbox_wire), base };
|
||||
}
|
||||
}
|
||||
Self { wires, bbox_wire: None, centroid }
|
||||
Self { wires, bbox_wire: None, base }
|
||||
}
|
||||
|
||||
/// Build a closed rectangle outline around the XY extent of `wires`, in the
|
||||
@@ -119,7 +120,7 @@ impl CadCommand for PasteCommand {
|
||||
|
||||
fn on_preview_wires(&mut self, pt: DVec3) -> Vec<WireModel> {
|
||||
let pt = pt.as_vec3();
|
||||
let delta = pt - self.centroid;
|
||||
let delta = pt - self.base;
|
||||
// Large clipboard: ghost just the bounding box — O(1) per frame.
|
||||
if let Some(bbox) = &self.bbox_wire {
|
||||
return vec![bbox.translated(delta)];
|
||||
|
||||
Reference in new issue
Block a user