fix(precision): keep BLOCK base and TEXT/MTEXT insertion points in f64 (#311)
Three commit helpers narrowed a typed/picked point back to f32 before it reached the persisted entity, so the coordinate was quantized to the f32 grid (worse at large/UTM extents): - Scene::create_block_from_entities took the base point as glam::Vec3, so the block's local-space translation and the replacement INSERT's insert point were f32. Param is now DVec3 (matching the sibling define_block_from_owned_entities); the command_driver handler no longer downcasts with as_vec3(). - The MTEXT and TEXT in-place editors stored `pos` as Vec3 and built the committed insertion_point from it, quantizing a new label's position and re-quantizing an existing one on edit. Both `pos` fields are now DVec3. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
1f89b78a7e
commit
553b91015f
5 changed files with 20 additions and 20 deletions
|
|
@ -378,7 +378,7 @@ impl OpenCADStudio {
|
||||||
self.push_undo_snapshot(i, "BLOCK");
|
self.push_undo_snapshot(i, "BLOCK");
|
||||||
match self.tabs[i]
|
match self.tabs[i]
|
||||||
.scene
|
.scene
|
||||||
.create_block_from_entities(&handles, &name, base.as_vec3())
|
.create_block_from_entities(&handles, &name, base)
|
||||||
{
|
{
|
||||||
Ok(insert_handle) => {
|
Ok(insert_handle) => {
|
||||||
self.tabs[i].dirty = true;
|
self.tabs[i].dirty = true;
|
||||||
|
|
@ -1858,7 +1858,7 @@ impl OpenCADStudio {
|
||||||
} => {
|
} => {
|
||||||
self.tabs[i].active_cmd = None;
|
self.tabs[i].active_cmd = None;
|
||||||
self.tabs[i].snap_result = None;
|
self.tabs[i].snap_result = None;
|
||||||
self.open_mtext_editor(pos.as_vec3(), handle, &initial, height);
|
self.open_mtext_editor(pos, handle, &initial, height);
|
||||||
}
|
}
|
||||||
CmdResult::OpenTextEditor {
|
CmdResult::OpenTextEditor {
|
||||||
pos,
|
pos,
|
||||||
|
|
@ -1869,7 +1869,7 @@ impl OpenCADStudio {
|
||||||
self.tabs[i].active_cmd = None;
|
self.tabs[i].active_cmd = None;
|
||||||
self.tabs[i].snap_result = None;
|
self.tabs[i].snap_result = None;
|
||||||
self.open_text_inline(
|
self.open_text_inline(
|
||||||
pos.as_vec3(),
|
pos,
|
||||||
handle,
|
handle,
|
||||||
&initial,
|
&initial,
|
||||||
height,
|
height,
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ use acadrust::entities::mtext_format::{
|
||||||
};
|
};
|
||||||
use acadrust::types::Vector3;
|
use acadrust::types::Vector3;
|
||||||
use acadrust::{EntityType, Handle, MText};
|
use acadrust::{EntityType, Handle, MText};
|
||||||
use glam::Vec3;
|
use glam::DVec3;
|
||||||
use iced::widget::text_editor;
|
use iced::widget::text_editor;
|
||||||
|
|
||||||
/// Character-level format toggles applied to the current selection by the
|
/// Character-level format toggles applied to the current selection by the
|
||||||
|
|
@ -76,7 +76,7 @@ impl std::fmt::Display for JustifyChoice {
|
||||||
/// Live state of the open MText editor. Absent (`None`) when no editor is up.
|
/// Live state of the open MText editor. Absent (`None`) when no editor is up.
|
||||||
pub struct MTextEditorState {
|
pub struct MTextEditorState {
|
||||||
/// World insertion point (WCS, same convention the committed entity uses).
|
/// World insertion point (WCS, same convention the committed entity uses).
|
||||||
pub pos: Vec3,
|
pub pos: DVec3,
|
||||||
/// The editable text buffer (raw value with inline codes).
|
/// The editable text buffer (raw value with inline codes).
|
||||||
pub content: text_editor::Content,
|
pub content: text_editor::Content,
|
||||||
/// Structured mirror of `content`, parsed via acadrust `parse_mtext` — the
|
/// Structured mirror of `content`, parsed via acadrust `parse_mtext` — the
|
||||||
|
|
@ -133,7 +133,7 @@ pub struct MTextEditorState {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MTextEditorState {
|
impl MTextEditorState {
|
||||||
pub fn new(pos: Vec3, initial: &str, height: f64, editing: Option<Handle>) -> Self {
|
pub fn new(pos: DVec3, initial: &str, height: f64, editing: Option<Handle>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
pos,
|
pos,
|
||||||
content: text_editor::Content::with_text(initial),
|
content: text_editor::Content::with_text(initial),
|
||||||
|
|
@ -224,7 +224,7 @@ impl MTextEditorState {
|
||||||
let h = self.height_value();
|
let h = self.height_value();
|
||||||
MText {
|
MText {
|
||||||
value: self.folded_value(),
|
value: self.folded_value(),
|
||||||
insertion_point: Vector3::new(self.pos.x as f64, self.pos.y as f64, self.pos.z as f64),
|
insertion_point: Vector3::new(self.pos.x, self.pos.y, self.pos.z),
|
||||||
height: h,
|
height: h,
|
||||||
rectangle_width: self.rect_width,
|
rectangle_width: self.rect_width,
|
||||||
attachment_point: self.attachment,
|
attachment_point: self.attachment,
|
||||||
|
|
@ -495,7 +495,7 @@ impl super::OpenCADStudio {
|
||||||
/// The committed slot is chosen by the edited entity's type.
|
/// The committed slot is chosen by the edited entity's type.
|
||||||
pub(super) fn open_mtext_editor(
|
pub(super) fn open_mtext_editor(
|
||||||
&mut self,
|
&mut self,
|
||||||
pos: Vec3,
|
pos: DVec3,
|
||||||
handle: Option<Handle>,
|
handle: Option<Handle>,
|
||||||
initial: &str,
|
initial: &str,
|
||||||
height: f64,
|
height: f64,
|
||||||
|
|
@ -1234,7 +1234,7 @@ mod cell_tests {
|
||||||
// (replacing the old hand-built `\f;\C;…` prefix), and survive serialization.
|
// (replacing the old hand-built `\f;\C;…` prefix), and survive serialization.
|
||||||
#[test]
|
#[test]
|
||||||
fn global_defaults_fold_into_spans() {
|
fn global_defaults_fold_into_spans() {
|
||||||
let mut ed = MTextEditorState::new(Vec3::ZERO, "hello world", 2.5, None);
|
let mut ed = MTextEditorState::new(DVec3::ZERO, "hello world", 2.5, None);
|
||||||
ed.font = "Arial".to_string();
|
ed.font = "Arial".to_string();
|
||||||
ed.color_aci = 1; // red
|
ed.color_aci = 1; // red
|
||||||
ed.oblique = "15".to_string();
|
ed.oblique = "15".to_string();
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
use acadrust::types::Vector3;
|
use acadrust::types::Vector3;
|
||||||
use acadrust::{EntityType, Handle, Text};
|
use acadrust::{EntityType, Handle, Text};
|
||||||
use glam::Vec3;
|
use glam::DVec3;
|
||||||
|
|
||||||
/// Which text slot of which entity an editor session reads from and writes to.
|
/// Which text slot of which entity an editor session reads from and writes to.
|
||||||
/// `Text`/`AttDef`/`AttEnt`/`Dim`/`Tolerance` are plain (single-line box);
|
/// `Text`/`AttDef`/`AttEnt`/`Dim`/`Tolerance` are plain (single-line box);
|
||||||
|
|
@ -78,15 +78,15 @@ pub fn write_text_field(entity: &mut EntityType, field: TextEntityField, value:
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn vec3(v: Vector3) -> Vec3 {
|
fn vec3(v: Vector3) -> DVec3 {
|
||||||
Vec3::new(v.x as f32, v.y as f32, v.z as f32)
|
DVec3::new(v.x, v.y, v.z)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Live state of the open in-place TEXT editor. Absent (`None`) when no editor
|
/// Live state of the open in-place TEXT editor. Absent (`None`) when no editor
|
||||||
/// is up.
|
/// is up.
|
||||||
pub struct TextInlineState {
|
pub struct TextInlineState {
|
||||||
/// World insertion point (WCS, same convention the committed entity uses).
|
/// World insertion point (WCS, same convention the committed entity uses).
|
||||||
pub pos: Vec3,
|
pub pos: DVec3,
|
||||||
/// The plain text being entered.
|
/// The plain text being entered.
|
||||||
pub value: String,
|
pub value: String,
|
||||||
/// Text height (drawing units), used when creating a new TEXT entity.
|
/// Text height (drawing units), used when creating a new TEXT entity.
|
||||||
|
|
@ -156,7 +156,7 @@ impl super::OpenCADStudio {
|
||||||
EntityType::MultiLeader(ml) => {
|
EntityType::MultiLeader(ml) => {
|
||||||
(vec3(ml.context.text_location), ml.context.text_height)
|
(vec3(ml.context.text_location), ml.context.text_height)
|
||||||
}
|
}
|
||||||
_ => (Vec3::ZERO, 0.25),
|
_ => (DVec3::ZERO, 0.25),
|
||||||
};
|
};
|
||||||
|
|
||||||
if field.is_rich() {
|
if field.is_rich() {
|
||||||
|
|
@ -172,7 +172,7 @@ impl super::OpenCADStudio {
|
||||||
/// commit. `handle` is `Some` when editing an existing entity.
|
/// commit. `handle` is `Some` when editing an existing entity.
|
||||||
pub(super) fn open_text_inline(
|
pub(super) fn open_text_inline(
|
||||||
&mut self,
|
&mut self,
|
||||||
pos: Vec3,
|
pos: DVec3,
|
||||||
handle: Option<Handle>,
|
handle: Option<Handle>,
|
||||||
initial: &str,
|
initial: &str,
|
||||||
height: f64,
|
height: f64,
|
||||||
|
|
@ -211,7 +211,7 @@ impl super::OpenCADStudio {
|
||||||
} else {
|
} else {
|
||||||
let mut t = Text::with_value(
|
let mut t = Text::with_value(
|
||||||
&ed.value,
|
&ed.value,
|
||||||
Vector3::new(ed.pos.x as f64, ed.pos.y as f64, ed.pos.z as f64),
|
Vector3::new(ed.pos.x, ed.pos.y, ed.pos.z),
|
||||||
)
|
)
|
||||||
.with_height(ed.height);
|
.with_height(ed.height);
|
||||||
// New text inherits the document's current text style (STYLE), not
|
// New text inherits the document's current text style (STYLE), not
|
||||||
|
|
|
||||||
|
|
@ -250,7 +250,7 @@ impl Scene {
|
||||||
&mut self,
|
&mut self,
|
||||||
handles: &[Handle],
|
handles: &[Handle],
|
||||||
name: &str,
|
name: &str,
|
||||||
base: glam::Vec3,
|
base: glam::DVec3,
|
||||||
) -> Result<Handle, String> {
|
) -> Result<Handle, String> {
|
||||||
let name = name.trim();
|
let name = name.trim();
|
||||||
if name.is_empty() {
|
if name.is_empty() {
|
||||||
|
|
@ -299,7 +299,7 @@ impl Scene {
|
||||||
.add_entity(EntityType::BlockEnd(block_end))
|
.add_entity(EntityType::BlockEnd(block_end))
|
||||||
.map_err(|e| e.to_string())?;
|
.map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
let local = EntityTransform::Translate((-base).as_dvec3());
|
let local = EntityTransform::Translate(-base);
|
||||||
for (old_handle, mut entity) in source_entities {
|
for (old_handle, mut entity) in source_entities {
|
||||||
view::dispatch::apply_transform(&mut entity, &local);
|
view::dispatch::apply_transform(&mut entity, &local);
|
||||||
entity = crate::modules::draw::modify::explode::normalize_entity_for_block(entity);
|
entity = crate::modules::draw::modify::explode::normalize_entity_for_block(entity);
|
||||||
|
|
@ -313,7 +313,7 @@ impl Scene {
|
||||||
|
|
||||||
let insert = DxfInsert::new(
|
let insert = DxfInsert::new(
|
||||||
name,
|
name,
|
||||||
acadrust::types::Vector3::new(base.x as f64, base.y as f64, base.z as f64),
|
acadrust::types::Vector3::new(base.x, base.y, base.z),
|
||||||
);
|
);
|
||||||
Ok(self.add_entity(EntityType::Insert(insert)))
|
Ok(self.add_entity(EntityType::Insert(insert)))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ fn block_internal_hatch_reaches_export() {
|
||||||
// minimal shape of "coloured fill nested in a block".
|
// minimal shape of "coloured fill nested in a block".
|
||||||
let h = scene.add_entity(EntityType::Hatch(square_hatch(5)));
|
let h = scene.add_entity(EntityType::Hatch(square_hatch(5)));
|
||||||
scene
|
scene
|
||||||
.create_block_from_entities(&[h], "LOGO", glam::Vec3::ZERO)
|
.create_block_from_entities(&[h], "LOGO", glam::DVec3::ZERO)
|
||||||
.expect("wrap hatch into a block + insert");
|
.expect("wrap hatch into a block + insert");
|
||||||
scene.populate_hatches_from_document();
|
scene.populate_hatches_from_document();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue