Match Fix geometric constraint behavior

1) FXCONSTRAINT (and the new GCFIX name) prompts "Select point or [Object]
   <Object>:" — a pick fixes that constraint point; Enter or O asks for one
   line, polyline segment, circle, arc, ellipse or spline; misses and
   unsupported objects report the reference messages and re-prompt.
2) Point, block, text, MText, attribute and table insertion points are
   addressable constraint points.
3) Re-applying Fixed to the same point or object reports that the constraint
   already exists instead of adding a duplicate.
4) A persistent Fixed holds its pre-edit geometry through MOVE, ROTATE,
   SCALE, STRETCH, grip and Properties edits: fixed points stay, free points
   of a partly fixed entity follow the edit, and size retention skips fixed
   entities.
5) Object mode on a polyline fixes the picked segment (natively persisted)
   instead of the whole polyline; arc segments pin endpoints, center and
   radius.
6) Ribbon label "Fix" with a padlock icon.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
ramox81andClaude Fable 5.1 committed 2026-09-18 15:38:33 +03:00
1 parent 2b38f798c0
commit f998b59193
9 files changed
+483 -206

No files matched your search

+37 -8
View File
@@ -1420,7 +1420,7 @@ impl OpenCADStudio {
}
}
"VCONSTRAINT" | "FXCONSTRAINT" => {
"VCONSTRAINT" => {
let handles = self.tabs[i].scene.selected_handles_in_order();
if handles.is_empty() {
use crate::modules::draw::select::SelectObjectsCommand;
@@ -1433,20 +1433,49 @@ impl OpenCADStudio {
} else {
use crate::command::CmdResult;
use crate::scene::parametric_constraints::{ConstraintKind, ParametricRef};
let (kind, label) = if cmd == "VCONSTRAINT" {
(ConstraintKind::Vertical, "Vertical constraint")
} else {
(ConstraintKind::Fixed, "Fixed constraint")
};
return Some(self.apply_cmd_result(CmdResult::AddParametricConstraint {
kind,
kind: ConstraintKind::Vertical,
refs: vec![ParametricRef::whole(handles[0])],
driving_param: None,
label,
label: "Vertical constraint",
}));
}
}
"FXCONSTRAINT" | "GCFIX" => {
use crate::command::CmdResult;
use crate::modules::parametric::FixConstraintCommand;
use crate::scene::parametric_constraints::ConstraintKind;
// One preselected whole curve applies at once (ribbon
// "select first, then click"); anything else goes through
// the reference's own point-or-object prompt.
let handles = self.tabs[i].scene.selected_handles_in_order();
if let [handle] = handles.as_slice() {
let reference = self.tabs[i]
.scene
.document
.get_entity(*handle)
.and_then(|entity| {
FixConstraintCommand::preselected_reference(entity, *handle)
});
if let Some(reference) = reference {
return Some(self.apply_cmd_result(CmdResult::AddParametricConstraint {
kind: ConstraintKind::Fixed,
refs: vec![reference],
driving_param: None,
label: "Fixed constraint",
}));
}
}
if !handles.is_empty() {
self.tabs[i].scene.deselect_all();
}
let command = FixConstraintCommand::new();
self.command_line.push_info(&command.prompt());
self.tabs[i].active_cmd = Some(Box::new(command));
}
"CCONSTRAINT" | "GCCOINCIDENT" => {
use crate::modules::parametric::CoincidentConstraintCommand;
let new_cmd = CoincidentConstraintCommand::new();