feat: Grid snap adaptive spacing + Polar tracking improvements
Grid snap (F9):
• snap spacing now tracks the visible grid zoom level — computed via
compute_grid_step() (same adaptive pow-of-5 logic as draw_grid),
updated on every ViewportMove so zooming in/out keeps snap aligned
with the grid lines on screen
Polar tracking (F10):
• configurable angle increment stored in polar_increment_deg (default 45°)
• right-click the POLAR pill to cycle through 15 → 30 → 45 → 90°
• pill label shows current angle ("POLAR 45°")
• visual guide line: while drawing with polar on, a dashed cyan line is
drawn from last_point along the snapped direction across the viewport
• SetPolarAngle message + handler; all polar_constrain() calls use the
stored increment instead of the hardcoded 45°
ROADMAP updated: Grid snap and Polar tracking marked ✅.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
b3dcbe6eb9
commit
4c1c13cab6
6 changed files with 165 additions and 21 deletions
|
|
@ -43,8 +43,10 @@ pub(super) struct H7CAD {
|
|||
pre_cmd_tangent: Option<bool>,
|
||||
/// Orthogonal drawing constraint (F8): constrains picks to 0°/90°/180°/270°.
|
||||
ortho_mode: bool,
|
||||
/// Polar tracking (F10): constrains picks to 45° angle increments.
|
||||
/// Polar tracking (F10): constrains picks to configurable angle increments.
|
||||
polar_mode: bool,
|
||||
/// Polar tracking angle increment in degrees (15 / 30 / 45 / 90).
|
||||
polar_increment_deg: f32,
|
||||
/// Show grid lines in the viewport (F7).
|
||||
show_grid: bool,
|
||||
/// Show the UCS icon in the bottom-left corner of model space (UCSICON).
|
||||
|
|
@ -224,8 +226,10 @@ pub enum Message {
|
|||
ToggleGrid,
|
||||
/// Toggle orthogonal drawing constraint — F8 / ORTHO status-bar button.
|
||||
ToggleOrtho,
|
||||
/// Toggle polar-angle constraint (45° increments) — F10 / POLAR status-bar button.
|
||||
/// Toggle polar-angle constraint — F10 / POLAR status-bar button.
|
||||
TogglePolar,
|
||||
/// Set polar tracking angle increment (right-click POLAR button).
|
||||
SetPolarAngle(f32),
|
||||
/// Toggle an individual snap mode (from popup row click).
|
||||
ToggleSnap(crate::snap::SnapType),
|
||||
/// Open / close the OSNAP popup (▾ arrow click).
|
||||
|
|
@ -429,6 +433,7 @@ impl H7CAD {
|
|||
pre_cmd_tangent: None,
|
||||
ortho_mode: false,
|
||||
polar_mode: false,
|
||||
polar_increment_deg: 45.0,
|
||||
show_grid: false,
|
||||
show_ucs_icon: true,
|
||||
last_point: None,
|
||||
|
|
|
|||
|
|
@ -814,7 +814,7 @@ impl H7CAD {
|
|||
if self.ortho_mode {
|
||||
snapped = ortho_constrain(snapped, base);
|
||||
} else if self.polar_mode {
|
||||
snapped = polar_constrain(snapped, base, 45.0);
|
||||
snapped = polar_constrain(snapped, base, self.polar_increment_deg);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -846,6 +846,9 @@ impl H7CAD {
|
|||
.pick_on_target_plane(p, bounds)
|
||||
};
|
||||
let view_proj = self.tabs[i].scene.camera.borrow().view_proj(bounds);
|
||||
// Sync grid-snap spacing to the adaptive spacing of the visible grid.
|
||||
self.snapper.grid_spacing =
|
||||
crate::ui::overlay::compute_grid_step(view_proj, bounds);
|
||||
// In MSPACE, map paper-space cursor to model space so that
|
||||
// command previews and snapping work in the correct coordinate space.
|
||||
let cursor_world = self.tabs[i].scene.paper_to_model(cursor_paper);
|
||||
|
|
@ -879,14 +882,14 @@ impl H7CAD {
|
|||
if self.ortho_mode {
|
||||
pt = ortho_constrain(pt, base);
|
||||
} else if self.polar_mode {
|
||||
pt = polar_constrain(pt, base, 45.0);
|
||||
pt = polar_constrain(pt, base, self.polar_increment_deg);
|
||||
}
|
||||
}
|
||||
pt
|
||||
};
|
||||
self.tabs[i].last_cursor_world = effective;
|
||||
|
||||
let previews = if needs_entity {
|
||||
let mut previews = if needs_entity {
|
||||
let hover_handle =
|
||||
scene::hit_test::click_hit(p, &all_wires, view_proj, bounds)
|
||||
.and_then(|s| Scene::handle_from_wire_name(s))
|
||||
|
|
@ -899,6 +902,37 @@ impl H7CAD {
|
|||
.map(|c| c.on_preview_wires(effective))
|
||||
.unwrap_or_default()
|
||||
};
|
||||
// Polar tracking guide line: dotted line from last_point along
|
||||
// the snapped angle direction, extending across the drawing.
|
||||
if self.polar_mode && !needs_entity {
|
||||
if let Some(base) = self.last_point {
|
||||
let dx = effective.x - base.x;
|
||||
let dy = effective.y - base.y;
|
||||
if (dx * dx + dy * dy).sqrt() > 1e-4 {
|
||||
let far = 1e5_f32;
|
||||
let dir = glam::Vec3::new(dx, dy, 0.0).normalize();
|
||||
let far_pos = base + dir * far;
|
||||
let far_neg = base - dir * far;
|
||||
let guide = crate::scene::WireModel {
|
||||
name: "__polar_guide__".into(),
|
||||
points: vec![
|
||||
[far_neg.x, far_neg.y, far_neg.z],
|
||||
[far_pos.x, far_pos.y, far_pos.z],
|
||||
],
|
||||
color: [0.2, 0.7, 0.9, 0.6],
|
||||
selected: false,
|
||||
aci: 0,
|
||||
pattern_length: 0.8,
|
||||
pattern: [0.5, -0.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||
line_weight_px: 1.0,
|
||||
snap_pts: vec![],
|
||||
tangent_geoms: vec![],
|
||||
key_vertices: vec![],
|
||||
};
|
||||
previews.push(guide);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.tabs[i].scene.set_preview_wires(previews);
|
||||
} else {
|
||||
self.tabs[i].snap_result = None;
|
||||
|
|
@ -1046,7 +1080,7 @@ impl H7CAD {
|
|||
if self.ortho_mode {
|
||||
pt = ortho_constrain(pt, base);
|
||||
} else if self.polar_mode {
|
||||
pt = polar_constrain(pt, base, 45.0);
|
||||
pt = polar_constrain(pt, base, self.polar_increment_deg);
|
||||
}
|
||||
}
|
||||
pt
|
||||
|
|
@ -1481,6 +1515,12 @@ impl H7CAD {
|
|||
if self.polar_mode { self.ortho_mode = false; }
|
||||
Task::none()
|
||||
}
|
||||
Message::SetPolarAngle(deg) => {
|
||||
self.polar_increment_deg = deg;
|
||||
self.polar_mode = true;
|
||||
self.ortho_mode = false;
|
||||
Task::none()
|
||||
}
|
||||
Message::ToggleSnap(t) => { self.snapper.toggle(t); Task::none() }
|
||||
Message::ToggleSnapPopup => { self.snap_popup_open ^= true; Task::none() }
|
||||
Message::CloseSnapPopup => { self.snap_popup_open = false; Task::none() }
|
||||
|
|
|
|||
|
|
@ -177,6 +177,7 @@ impl H7CAD {
|
|||
self.snap_popup_open,
|
||||
self.ortho_mode,
|
||||
self.polar_mode,
|
||||
self.polar_increment_deg,
|
||||
self.show_grid,
|
||||
tab.scene.layout_names(),
|
||||
tab.scene.current_layout.clone(),
|
||||
|
|
|
|||
Loading…
Reference in a new issue