From 925c91ccfabdcb3392e0da81d95bdcb67dc0c14b Mon Sep 17 00:00:00 2001 From: Hakan Seven Date: Tue, 13 Oct 2026 08:04:13 +0300 Subject: [PATCH] fix(pasteblock): place the block at the picked point The pasted block is defined around the clipboard base, so its origin is already that point, but the insertion still subtracted the base and landed the block offset from the pick. The base now only positions the world-space preview, and it stays f64. Fixes #1731 Co-Authored-By: Claude Opus 5.5 --- src/app/commands/blocks.rs | 2 +- src/modules/insert/insert_block.rs | 16 +++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/app/commands/blocks.rs b/src/app/commands/blocks.rs index e4e869ed0..d6b680840 100644 --- a/src/app/commands/blocks.rs +++ b/src/app/commands/blocks.rs @@ -371,7 +371,7 @@ impl OpenCADStudio { let wires = self.tabs[i].scene.wires_for_entities(&self.clipboard); use crate::modules::insert::insert_block::InsertBlockCommand; let cmd = - InsertBlockCommand::new_for_block(name, wires, base.as_vec3()); + InsertBlockCommand::new_for_block(name, wires, base); self.command_line.push_info(&cmd.prompt()); self.tabs[i].active_cmd = Some(Box::new(cmd)); } diff --git a/src/modules/insert/insert_block.rs b/src/modules/insert/insert_block.rs index b9e19c473..ed2225bd1 100644 --- a/src/modules/insert/insert_block.rs +++ b/src/modules/insert/insert_block.rs @@ -15,7 +15,7 @@ use crate::t; use codec::entities::{AttributeDefinition, AttributeEntity, Entity, Insert}; use codec::types::Vector3; use codec::EntityType; -use glam::{DVec3, Vec3}; +use glam::DVec3; use crate::app::settings::BlockInsertOptions; use crate::command::{CadCommand, CmdResult, DynField, InputKind, WorkingPlane}; @@ -130,6 +130,10 @@ pub struct InsertBlockCommand { /// through the same base-point convention the render path uses, so the /// host injects it when it resolves the block's ATTDEFs. block_base: Vector3, + /// Where the preview wires' block origin sits: zero for wires taken from + /// the definition, the clipboard base for paste-as-block, whose preview + /// is the clipboard in world coordinates. + preview_origin: DVec3, } impl InsertBlockCommand { @@ -157,6 +161,7 @@ impl InsertBlockCommand { pending_insert: None, plane: WorkingPlane::default(), block_base: Vector3::ZERO, + preview_origin: DVec3::ZERO, } } @@ -219,12 +224,13 @@ impl InsertBlockCommand { command } - /// Paste-as-block: the block is placed at the picked point. - pub fn new_for_block(name: String, preview_wires: Vec, base: Vec3) -> Self { + /// Paste-as-block: the block is placed at the picked point. The block + /// was defined around `base`, so its origin is the clipboard base. + pub fn new_for_block(name: String, preview_wires: Vec, base: DVec3) -> Self { let mut command = Self::base_state(Mode::Paste, Self::single_picker(&name)); command.name = name; command.preview = preview_wires; - command.base = base.as_dvec3(); + command.preview_origin = base; command.preset_scale = [Some(1.0); 3]; command.preset_rotation = Some(0.0); command.step = Step::Point; @@ -822,7 +828,7 @@ impl CadCommand for InsertBlockCommand { self.preset_scale[2].unwrap_or(1.0), ]; let (sin, cos) = self.preset_rotation.unwrap_or(0.0).sin_cos(); - let base = self.base; + let base = self.preview_origin + self.base; let origin = self.plane.to_local(pt); let plane = self.plane; self.preview