2026-04-02 23:28:00 +03:00
|
|
|
// ZOOM WINDOW command — pick two corners to define the zoom area.
|
|
|
|
|
|
feat(f64): command layer compiles on DVec3
Whole command/snap/grip/cursor chain now builds on f64 DVec3 end to end,
so picked points, snaps and grip drags stay precise at UTM-scale
coordinates instead of quantizing to ~0.5 m through f32.
- All ~80 command files migrated: draw (line/circle/arc/ellipse/shapes
in full f64; others via point methods), modify, annotate, insert, view,
inquiry, layers, groups, clipboard, layout.
- Entity apply_grip impls updated for GripApply::{Absolute,Translate}(DVec3).
- Construction sites (EntityTransform/CmdResult/DynAnchor) emit DVec3;
wire-preview boundaries cast to f32 only at the GPU edge.
- Modify/annotate commands keep internal Vec3 geometry where precision is
non-critical, casting at the DVec3 boundary; key draw commands store f64.
Builds clean (no warnings). Visual verification of crosshair/snap/grip at
extreme UTM zoom pending.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 03:51:50 +03:00
|
|
|
use glam::{DVec3, Vec3};
|
2026-08-02 22:09:25 +03:00
|
|
|
use crate::t;
|
2026-04-02 23:28:00 +03:00
|
|
|
|
|
|
|
|
use crate::command::{CadCommand, CmdResult};
|
2026-06-28 16:56:45 +03:00
|
|
|
use crate::modules::{IconKind, ModuleEvent, ToolDef};
|
2026-06-16 11:33:46 +03:00
|
|
|
use crate::scene::model::wire_model::WireModel;
|
2026-04-02 23:28:00 +03:00
|
|
|
|
2026-06-28 16:56:45 +03:00
|
|
|
pub const ICON: IconKind =
|
|
|
|
|
IconKind::Svg(include_bytes!("../../../assets/icons/zoom_window.svg"));
|
|
|
|
|
|
|
|
|
|
/// Ribbon button: zoom into a rectangle picked by two corners.
|
|
|
|
|
pub fn tool() -> ToolDef {
|
|
|
|
|
ToolDef {
|
|
|
|
|
id: "ZOOM_WINDOW",
|
|
|
|
|
label: "Zoom Window",
|
|
|
|
|
icon: ICON,
|
|
|
|
|
event: ModuleEvent::Command("ZOOM WINDOW".to_string()),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-02 23:28:00 +03:00
|
|
|
pub struct ZoomWindowCommand {
|
|
|
|
|
first: Option<Vec3>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl ZoomWindowCommand {
|
|
|
|
|
pub fn new() -> Self {
|
|
|
|
|
Self { first: None }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl CadCommand for ZoomWindowCommand {
|
|
|
|
|
fn name(&self) -> &'static str {
|
|
|
|
|
"ZOOM WINDOW"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn prompt(&self) -> String {
|
|
|
|
|
if self.first.is_none() {
|
2026-08-02 22:09:25 +03:00
|
|
|
t!("ZOOM WINDOW Specify first corner:").into_owned()
|
2026-04-02 23:28:00 +03:00
|
|
|
} else {
|
2026-08-02 22:09:25 +03:00
|
|
|
t!("ZOOM WINDOW Specify opposite corner:").into_owned()
|
2026-04-02 23:28:00 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
feat(f64): command layer compiles on DVec3
Whole command/snap/grip/cursor chain now builds on f64 DVec3 end to end,
so picked points, snaps and grip drags stay precise at UTM-scale
coordinates instead of quantizing to ~0.5 m through f32.
- All ~80 command files migrated: draw (line/circle/arc/ellipse/shapes
in full f64; others via point methods), modify, annotate, insert, view,
inquiry, layers, groups, clipboard, layout.
- Entity apply_grip impls updated for GripApply::{Absolute,Translate}(DVec3).
- Construction sites (EntityTransform/CmdResult/DynAnchor) emit DVec3;
wire-preview boundaries cast to f32 only at the GPU edge.
- Modify/annotate commands keep internal Vec3 geometry where precision is
non-critical, casting at the DVec3 boundary; key draw commands store f64.
Builds clean (no warnings). Visual verification of crosshair/snap/grip at
extreme UTM zoom pending.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 03:51:50 +03:00
|
|
|
fn on_point(&mut self, pt: DVec3) -> CmdResult { let pt = pt.as_vec3();
|
2026-04-02 23:28:00 +03:00
|
|
|
if let Some(p1) = self.first {
|
feat(f64): command layer compiles on DVec3
Whole command/snap/grip/cursor chain now builds on f64 DVec3 end to end,
so picked points, snaps and grip drags stay precise at UTM-scale
coordinates instead of quantizing to ~0.5 m through f32.
- All ~80 command files migrated: draw (line/circle/arc/ellipse/shapes
in full f64; others via point methods), modify, annotate, insert, view,
inquiry, layers, groups, clipboard, layout.
- Entity apply_grip impls updated for GripApply::{Absolute,Translate}(DVec3).
- Construction sites (EntityTransform/CmdResult/DynAnchor) emit DVec3;
wire-preview boundaries cast to f32 only at the GPU edge.
- Modify/annotate commands keep internal Vec3 geometry where precision is
non-critical, casting at the DVec3 boundary; key draw commands store f64.
Builds clean (no warnings). Visual verification of crosshair/snap/grip at
extreme UTM zoom pending.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 03:51:50 +03:00
|
|
|
CmdResult::ZoomToWindow { p1: p1.as_dvec3(), p2: pt.as_dvec3() }
|
2026-04-02 23:28:00 +03:00
|
|
|
} else {
|
|
|
|
|
self.first = Some(pt);
|
|
|
|
|
CmdResult::NeedPoint
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn on_enter(&mut self) -> CmdResult {
|
|
|
|
|
CmdResult::Cancel
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn on_escape(&mut self) -> CmdResult {
|
|
|
|
|
CmdResult::Cancel
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-21 23:14:08 +03:00
|
|
|
fn window_corner_pick(&self) -> bool {
|
|
|
|
|
// Both zoom-window corners are free points; Ortho/Polar must not pin
|
|
|
|
|
// the opposite corner to an axis or the window collapses to a line
|
|
|
|
|
// (#363, same class as #291).
|
|
|
|
|
true
|
|
|
|
|
}
|
|
|
|
|
|
feat(f64): command layer compiles on DVec3
Whole command/snap/grip/cursor chain now builds on f64 DVec3 end to end,
so picked points, snaps and grip drags stay precise at UTM-scale
coordinates instead of quantizing to ~0.5 m through f32.
- All ~80 command files migrated: draw (line/circle/arc/ellipse/shapes
in full f64; others via point methods), modify, annotate, insert, view,
inquiry, layers, groups, clipboard, layout.
- Entity apply_grip impls updated for GripApply::{Absolute,Translate}(DVec3).
- Construction sites (EntityTransform/CmdResult/DynAnchor) emit DVec3;
wire-preview boundaries cast to f32 only at the GPU edge.
- Modify/annotate commands keep internal Vec3 geometry where precision is
non-critical, casting at the DVec3 boundary; key draw commands store f64.
Builds clean (no warnings). Visual verification of crosshair/snap/grip at
extreme UTM zoom pending.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 03:51:50 +03:00
|
|
|
fn on_mouse_move(&mut self, pt: DVec3) -> Option<WireModel> { let pt = pt.as_vec3();
|
2026-04-02 23:28:00 +03:00
|
|
|
let p1 = self.first?;
|
|
|
|
|
let min = p1.min(pt);
|
|
|
|
|
let max = p1.max(pt);
|
|
|
|
|
// Draw a rectangle preview
|
|
|
|
|
Some(WireModel {
|
2026-07-20 16:36:06 +03:00
|
|
|
taper_widths: Vec::new(),
|
2026-07-20 14:50:27 +03:00
|
|
|
world_width: 0.0,
|
2026-07-21 15:53:28 +03:00
|
|
|
depth_override: None,
|
2026-07-18 15:15:24 +03:00
|
|
|
fill_is_3d: false,
|
2026-08-04 21:23:25 +03:00
|
|
|
fill_is_2d_solid: false,
|
fix(pick): hit-test lineweight width and thickness walls
Selection tested a flat 8 px radius around each wire's centreline and
nothing else, so two things the user can see were not pickable.
A wire renders as a band `line_weight_px` wide, so pick now widens to that
rendered half-width via `pick_tolerance_px`, mirroring the wire shader's
`select(0.5, half_width, lwdisplay_enable)`. Behaviour is unchanged for
every standard weight (the widest, 2.11 mm, renders 7.97 px half-width —
just under the 8 px threshold); this keeps the two sides from drifting
apart if the display boost in `lineweight_to_px` ever changes.
Entities extruded by a DXF thickness draw their wall as four edges with
nothing in between, so the interior was a hole the cursor fell through.
WireModel gains `pick_tris`: triangles hit-testing treats as solid and the
renderer never uploads. Kept apart from `fill_tris` because that channel
reaches the GPU, and a wall that rendered shaded would change how every
thickness drawing looks. Ranked below `fill_tris` — those are drawn, these
are not, so where they overlap the drawn face is what the user means.
Walls are dropped when a wire is projected into a floating viewport:
`points` are reprojected and clipped into paper coords there, so cloned
model-space triangles would hit-test at a model-scale offset. Extruded
entities stay selectable by their edges, which do get projected.
The wall loop runs on every hover that misses everything else, so it
rejects on the wire's AABB first — an extruded circle is ~128 triangles
and a drawing full of thickness would otherwise project every wall on
each mouse move.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 14:58:55 +03:00
|
|
|
pick_tris: Vec::new(),
|
|
|
|
|
pick_tris_low: Vec::new(),
|
2026-07-17 01:49:18 +03:00
|
|
|
dash_from_start: false,
|
2026-07-17 02:59:11 +03:00
|
|
|
dash_align_end: None,
|
refactor(text): per-entity SDF text — all text kinds, selection/hover highlight
Rearchitect SDF text from a document-wide collector to per-entity
production during tessellation, so each entity owns its glyph quads and
composite/nested text is covered for free (no re-explosion, no per-frame
document walk).
- WireModel gains `text_verts`: glyph quads ride on the wire, so they are
cached by the tess memo, cloned on hit, and transformed by the block
expand loop exactly like `points`.
- Text arm (tessellate.rs) builds the quads when SDF is on and suppresses
the strokes; render gathers text_verts from the viewport wire set
(`gather_text_verts`, cached on wire content id) — the old collector is
removed. Covers model, dimension, table, block-internal and paper-sheet
text uniformly.
- MLEADER text (lays out via layout_mtext, not the Text arm) gets its own
SDF branch driven by the per-run GlyphRun.
- Pick box comes from the rendered glyph quads (true text extent), not
entity_aabb which mis-places the box for MTEXT; composite paths no longer
clobber the empty text wire's tight AABB (dim pick box hugs the text).
- Selection / hover highlight via a text-highlight overlay (upload_text_
highlight, keyed on selection_generation) mirroring the selected-wire
xray overlay; base glyphs stay neutral so a deselect leaves no stale tint.
- Debug: env OCS_TEXT_BOX draws each run's glyph-bounds rectangle.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 17:01:36 +03:00
|
|
|
text_verts: Vec::new(),
|
2026-04-02 23:28:00 +03:00
|
|
|
name: "zoom_window_preview".into(),
|
|
|
|
|
points: vec![
|
|
|
|
|
[min.x, min.y, 0.0],
|
|
|
|
|
[max.x, min.y, 0.0],
|
|
|
|
|
[max.x, max.y, 0.0],
|
|
|
|
|
[min.x, max.y, 0.0],
|
|
|
|
|
[min.x, min.y, 0.0],
|
|
|
|
|
],
|
2026-06-23 17:08:54 +03:00
|
|
|
points_low: Vec::new(),
|
2026-04-02 23:28:00 +03:00
|
|
|
color: WireModel::CYAN,
|
|
|
|
|
selected: false,
|
|
|
|
|
pattern_length: 0.0,
|
|
|
|
|
pattern: [0.0; 8],
|
|
|
|
|
line_weight_px: 1.0,
|
|
|
|
|
snap_pts: vec![],
|
|
|
|
|
tangent_geoms: vec![],
|
2026-04-06 23:19:08 +03:00
|
|
|
aci: 0,
|
2026-04-02 23:28:00 +03:00
|
|
|
key_vertices: vec![],
|
2026-04-26 12:21:51 +03:00
|
|
|
aabb: WireModel::UNBOUNDED_AABB,
|
2026-05-06 06:55:28 +03:00
|
|
|
plinegen: true,
|
2026-05-06 23:24:26 +03:00
|
|
|
fill_tris: vec![],
|
2026-06-23 18:03:40 +03:00
|
|
|
fill_tris_low: Vec::new(),
|
2026-04-02 23:28:00 +03:00
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|