mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-03 02:25:55 +00:00
Extrude: a face picked off the profile's plane is the target by default (#11201)
With a profile or face picked, clicking a face, vertex or parallel plane that is not in the profile's plane now sets Extrude to To Object, not one more profile. Clicking into the Profiles box first makes the next picks profiles again. Preference extrude_auto_to_object (Tools) turns it off. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1582,7 +1582,7 @@ impl Dialog {
|
||||
fn extrude_target(&self, s: &Session, h: &Hit) -> Option<Sel> {
|
||||
let Kind::Extrude { thin: false, smart, .. } = &self.kind else { return None };
|
||||
let to_active = self.active_input().is_some_and(|i| i.label == TO_OBJECT);
|
||||
if !to_active && (self.active != 0 || !smart.auto_to_object) {
|
||||
if !to_active && (self.active != 0 || !smart.auto_to_object || smart.profiles_chosen) {
|
||||
return None;
|
||||
}
|
||||
let reference = profile_plane(s, self.inputs.first()?.items.first()?)?;
|
||||
@@ -1607,7 +1607,10 @@ impl Dialog {
|
||||
/// To Object with it. False when the pick is not one.
|
||||
fn take_extrude_target(&mut self, s: &Session, sel: &Sel) -> bool {
|
||||
if self.active != 0
|
||||
|| !matches!(self.kind, Kind::Extrude { thin: false, smart: crate::smart_extrude::Smart { auto_to_object: true, .. }, .. })
|
||||
|| !matches!(
|
||||
self.kind,
|
||||
Kind::Extrude { thin: false, smart: crate::smart_extrude::Smart { auto_to_object: true, profiles_chosen: false, .. }, .. }
|
||||
)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -2831,6 +2834,10 @@ pub(crate) fn input_rows_range(d: &mut Dialog, ui: &mut egui::Ui, s: &Session, n
|
||||
}
|
||||
if let Some(i) = activate {
|
||||
d.active = i;
|
||||
// A click into the Profiles box is a choice to add profiles by pick (Extrude's automatic To Object).
|
||||
if let Kind::Extrude { smart, .. } = &mut d.kind {
|
||||
smart.profiles_chosen = i == 0;
|
||||
}
|
||||
}
|
||||
if let Some(i) = clear {
|
||||
if let Some(key) = stored_input_reference_key(d, i) {
|
||||
|
||||
@@ -180,9 +180,7 @@ fn target_below_keeps_its_side_and_exact_length() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn off_by_default_a_face_off_the_profile_plane_joins_the_profiles() {
|
||||
let h = Harness::new();
|
||||
assert!(!h.app.preferences.extrude_auto_to_object, "the preference starts off");
|
||||
fn with_the_preference_off_a_face_off_the_profile_plane_joins_the_profiles() {
|
||||
let mut h = scene_with(false);
|
||||
assert!(click(&mut h, |h| face_hit(h, Vec3::new(40.0, 10.0, 20.0))));
|
||||
let d = dialog(&h);
|
||||
@@ -209,3 +207,60 @@ fn manual_to_object_accepts_a_parallel_plane_with_automatic_switching_off() {
|
||||
assert_eq!(commands[0].1["to"], json!([0.0, 0.0, 25.0]));
|
||||
assert!((solidcraft_engine::extrude_reach(&h.app.session, &commands[0].1).unwrap() - 25.0).abs() < 1e-9);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_preference_starts_on() {
|
||||
assert!(Harness::new().app.preferences.extrude_auto_to_object);
|
||||
}
|
||||
|
||||
/// The scene with the box's top face (z = 20) picked as the profile instead of the sketch.
|
||||
fn face_profile_scene() -> Harness {
|
||||
let mut h = scene();
|
||||
let top = face_sel(&h.app.session, Vec3::new(40.0, 10.0, 20.0)).unwrap();
|
||||
h.app.dialog.as_mut().unwrap().inputs[0].items = vec![top];
|
||||
h.frames(2);
|
||||
h
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn face_profile_then_the_opposite_face_is_the_target() {
|
||||
let mut h = face_profile_scene();
|
||||
assert!(click(&mut h, |h| face_hit(h, Vec3::new(40.0, 10.0, 0.0))));
|
||||
let d = dialog(&h);
|
||||
assert!(matches!(to_object(d), Some(Sel::Face { .. })), "the bottom face is where it goes to");
|
||||
assert_eq!(d.inputs[0].items.len(), 1, "the top face stays the only profile");
|
||||
let commands = apply_commands(&h.app, d).unwrap();
|
||||
assert!(commands[0].1.get("to").is_some());
|
||||
let reach = solidcraft_engine::extrude_reach(&h.app.session, &commands[0].1).unwrap();
|
||||
assert!((reach + 20.0).abs() < 1e-9, "{reach}: 20 mm down through the body");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn face_profile_then_a_parallel_face_of_another_body_is_the_target() {
|
||||
let mut h = face_profile_scene();
|
||||
assert!(click(&mut h, |h| face_hit(h, Vec3::new(70.0, 10.0, 30.0))));
|
||||
let d = dialog(&h);
|
||||
assert!(matches!(to_object(d), Some(Sel::Face { .. })));
|
||||
assert_eq!(d.inputs[0].items.len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_side_face_is_a_target_at_its_picked_point() {
|
||||
let mut h = face_profile_scene();
|
||||
assert!(click(&mut h, |h| face_hit(h, Vec3::new(50.0, 10.0, 10.0))));
|
||||
let d = dialog(&h);
|
||||
assert!(matches!(to_object(d), Some(Sel::Face { .. })), "a non-parallel planar face is taken as the target");
|
||||
assert_eq!(d.inputs[0].items.len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn clicking_into_the_profiles_box_adds_an_off_plane_face_as_a_profile() {
|
||||
let mut h = scene();
|
||||
let at = crate::scenario::rect_of("dialog:field:Profiles").expect("the Profiles field is drawn").center();
|
||||
h.step(&json!({"click": [at.x, at.y]})).unwrap();
|
||||
h.frames(2);
|
||||
assert!(click(&mut h, |h| face_hit(h, Vec3::new(40.0, 10.0, 20.0))));
|
||||
let d = dialog(&h);
|
||||
assert!(to_object(d).is_none(), "the box was chosen, so the pick is a profile");
|
||||
assert_eq!(d.inputs[0].items.len(), 2);
|
||||
}
|
||||
|
||||
@@ -1334,8 +1334,9 @@ preference_settings! {
|
||||
/// over the view (the default), the dialog, or nothing (#7717).
|
||||
stand_up_unknown: StandUpUnknown = StandUpUnknown::default(), PAGE_DESIGN;
|
||||
/// Extrude: with a profile picked, a face, vertex or parallel plane picked off its plane
|
||||
/// switches the extent to To Object (off: picks only add profiles, as before).
|
||||
extrude_auto_to_object: bool = false, PAGE_TOOLS => check("Extrude to a picked target", "In Extrude, with a profile picked, picking a face, vertex or parallel plane off its plane switches the extent to To Object");
|
||||
/// switches the extent to To Object (off: picks only add profiles, as before). A click into the
|
||||
/// Profiles box makes the next picks profiles again.
|
||||
extrude_auto_to_object: bool = true, PAGE_TOOLS => check("Extrude to a picked target", "In Extrude, with a profile picked, picking a face, vertex or parallel plane off its plane switches the extent to To Object");
|
||||
/// Extrude turns the view to isometric each time it opens, so the depth can be seen (#9176).
|
||||
/// Off (the default): the view stays as it is.
|
||||
extrude_view_isometric: bool = false, PAGE_TOOLS => check_id("prefs.extrude_view_isometric");
|
||||
@@ -5787,7 +5788,7 @@ mod tests {
|
||||
("direct_interaction", json!(true), PAGE_TOOLS),
|
||||
("hole_snaps", json!(true), PAGE_TOOLS),
|
||||
("hole_moves", json!(true), PAGE_TOOLS),
|
||||
("extrude_auto_to_object", json!(true), PAGE_TOOLS),
|
||||
("extrude_auto_to_object", json!(false), PAGE_TOOLS),
|
||||
("extrude_view_isometric", json!(true), PAGE_TOOLS),
|
||||
("extrude_view_return", json!(true), PAGE_TOOLS),
|
||||
("auto_operation", json!(false), PAGE_TOOLS),
|
||||
|
||||
@@ -40,6 +40,9 @@ pub struct Smart {
|
||||
pub shown: Option<Vec<String>>,
|
||||
/// Picks off the profile plane become the To Object target (Preferences › Design).
|
||||
pub auto_to_object: bool,
|
||||
/// The user clicked into the Profiles box: until another input is chosen, an off-plane pick
|
||||
/// is one more profile, not the To Object target.
|
||||
pub profiles_chosen: bool,
|
||||
/// The engine's automatic operation for the last parameters and design: a key over all it
|
||||
/// depends on, and its answer. It probes the bodies' triangles, too slow to ask every frame.
|
||||
pub auto: Option<(u64, Option<&'static str>)>,
|
||||
|
||||
@@ -39,14 +39,15 @@ one as a separate piece, and the feature's warning says so: "`Body1` is now in 2
|
||||
pieces". Combine joins the bodies it is given without that warning. Changing the default does not
|
||||
alter operations already saved in a design.
|
||||
|
||||
**Extrude to a picked target** (Preferences › Design, off by default) lets a pick choose the
|
||||
**Extrude to a picked target** (Preferences › Tools, on by default) lets a pick choose the
|
||||
extent. With it on and a profile selected in the solid Extrude dialog, picking a face away from
|
||||
its plane, a curved face, an off-plane vertex or a parallel plane automatically switches
|
||||
**Distance** to **To Object**. Coplanar faces still join the profile selection; non-parallel
|
||||
planes are not targets. The extent can still be chosen manually. For a new extrusion without
|
||||
planes are not targets. Clicking into the **Profiles** box first makes the next picks profiles
|
||||
again, even off the plane. The extent can still be chosen manually. For a new extrusion without
|
||||
start or end offsets or a From Object input, the target also sets the stored distance and
|
||||
one-sided direction, so returning to **Distance** keeps that reach. Thin Extrude keeps its
|
||||
existing picks. With the setting off, picks only add profiles, as before.
|
||||
existing picks. With the setting off, picks only add profiles.
|
||||
|
||||
A positive extrude taper slopes the side walls outward, so the profile grows along the
|
||||
extrusion direction and the far end is larger; a negative taper slopes them inward, making
|
||||
|
||||
@@ -474,7 +474,7 @@ One setting per line, sorted by name. A change that adds a setting adds its own
|
||||
- `default_units`
|
||||
- `dialog_buttons` (`bottom` (default), `top`: a feature dialog's OK, Cancel and Apply sit in its title row instead of under its inputs, #6708; the buttons keep their handles, and `dialog:close` is then Cancel's; the Sketch panel's Finish Sketch row moves above its options, #9860)
|
||||
- `dialog_place` (`edge` (default) or `left_column`: command dialogs open in the left column in place of the browser and the History, #6707)
|
||||
- `extrude_auto_to_object` (default false: in the Extrude dialog, with a profile picked, a face, vertex or parallel plane picked off its plane switches the extent to To Object; it applies to Extrude dialogs opened afterwards)
|
||||
- `extrude_auto_to_object` (default true: in the Extrude dialog, with a profile picked, a face, vertex or parallel plane picked off its plane switches the extent to To Object, unless the Profiles box was clicked into; it applies to Extrude dialogs opened afterwards)
|
||||
- `frame_rate_details` (default false: with the frame rate, a frame-time graph of the frames drawn with the triangles over it, a frame-time histogram and what the GPU drew; clicking the readout switches it)
|
||||
- `graphics_adapter` (exact card name, or empty for Automatic; applies after restart; `WGPU_ADAPTER_NAME` takes precedence)
|
||||
- `hidden_toolbar_tabs` (default `[]`: all existing tabs, including Sheet Metal and Weldments, stay visible; lists tabs to hide, each once, e.g. `["SURFACE", "SHEET METAL"]`; hidden tabs stay hidden regardless of the design's features; [ribbon layout](ribbon-layout.md))
|
||||
|
||||
@@ -12,7 +12,7 @@ Each group is a 120x64 figure at the left of its checkboxes, with a group name u
|
||||
|---|---|---|---|---|---|---|
|
||||
| Hole: Snap to centres | Checkbox | `Prefs.hole_snaps` | `false` | "The middle of a face and the centres of its round edges." | `tool-hole` | Today's label "Snap to face and edge centres". |
|
||||
| Hole: Move by click or drag | Checkbox | `Prefs.hole_moves` | `false` | "Picking the face again moves the hole instead of removing it." | `tool-hole` | Today's label "Move holes by clicking or dragging". |
|
||||
| Extrude: Extrude to a picked target | Checkbox | `Prefs.extrude_auto_to_object` | `false` | "A face, vertex or parallel plane switches the extent to To Object." | `tool-extrude` | |
|
||||
| Extrude: Extrude to a picked target | Checkbox | `Prefs.extrude_auto_to_object` | `true` | "A face, vertex or parallel plane switches the extent to To Object." | `tool-extrude` | |
|
||||
| Extrude: Choose the operation automatically | Checkbox | `Prefs.auto_operation` | `true` | "Join, New Body or Cut, from what the material touches." | `tool-extrude` | |
|
||||
| Rest, Boss, Snap Fit: Placement handles | Checkbox | `Prefs.placement_handles` | `false` | "A marker to drag the feature across the model and a ring to turn it." | `tool-placement` | |
|
||||
|
||||
|
||||
Reference in New Issue
Block a user