forked from 1b-agent/opencadstudio-upstream
Keep untouched constraint geometry fixed during grip edits
This commit is contained in:
1 parent
07d8d7eb00
commit
bfd0c30329
2 files changed
+41
-29
No files matched your search
@@ -6137,9 +6137,9 @@ mod selection_preview_tests {
|
||||
.normalize()
|
||||
};
|
||||
assert!(direction(current[0]).dot(direction(current[1])).abs() < 1e-8);
|
||||
assert_ne!(
|
||||
assert_eq!(
|
||||
current[1], before[1],
|
||||
"constrained neighbor must follow each grip frame"
|
||||
"geometry outside the grip edit must stay fixed"
|
||||
);
|
||||
assert_eq!(
|
||||
current[0][0], before[0][0],
|
||||
|
||||
@@ -2636,11 +2636,24 @@ impl Scene {
|
||||
if !is_touched {
|
||||
continue;
|
||||
}
|
||||
let mut anchors = driven_refs.to_vec();
|
||||
for reference in set
|
||||
.constraints
|
||||
.iter()
|
||||
.filter(|constraint| constraint.enabled)
|
||||
.flat_map(|constraint| &constraint.refs)
|
||||
{
|
||||
if !touched.contains(&reference.entity)
|
||||
&& !anchors.iter().any(|anchor| anchor.entity == reference.entity)
|
||||
{
|
||||
anchors.push(ParametricRef::whole(reference.entity));
|
||||
}
|
||||
}
|
||||
let Some((solved, _dof, _conflicts)) = solve_scope(
|
||||
&self.document,
|
||||
&self.named_parameters,
|
||||
set,
|
||||
driven_refs,
|
||||
&anchors,
|
||||
retain_size,
|
||||
&retained_before,
|
||||
)
|
||||
@@ -2912,11 +2925,11 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
/// `solve_parametric_constraints_preview` reports the constrained
|
||||
/// neighbor's solved position without writing anything into the
|
||||
/// document itself — the grip-drag caller owns applying it.
|
||||
/// A grip preview treats geometry outside the edit as a fixed reference,
|
||||
/// so a parallel constraint projects the dragged endpoint without moving
|
||||
/// the other line or changing their separation.
|
||||
#[test]
|
||||
fn preview_solve_reports_the_neighbors_new_state_without_mutating_the_document() {
|
||||
fn preview_solve_keeps_untouched_parallel_geometry_fixed() {
|
||||
let mut scene = Scene::new();
|
||||
let a = scene.add_entity(EntityType::Line(acadrust::entities::Line::from_points(
|
||||
Vector3::new(0.0, 0.0, 0.0),
|
||||
@@ -2941,40 +2954,39 @@ mod tests {
|
||||
}
|
||||
let b_before = scene.document.get_entity(b).cloned();
|
||||
|
||||
let solved = scene.solve_parametric_constraints_preview(&[a], &[], false, &[]);
|
||||
let solved = scene.solve_parametric_constraints_preview(
|
||||
&[a],
|
||||
&[ParametricRef::point(a, 0)],
|
||||
false,
|
||||
&[],
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
scene.document.get_entity(b),
|
||||
b_before.as_ref(),
|
||||
"preview must not mutate the document"
|
||||
);
|
||||
// The whole scope solves together (every registered entity's params
|
||||
// are free, not just `b`'s — see `register_entity`'s doc comment),
|
||||
// so `a` itself may also have shifted slightly to reach the nearest
|
||||
// mutually-parallel configuration; read whichever position `a` ends
|
||||
// up at from `solved` too, rather than assuming it stayed exactly
|
||||
// where the simulated drag put it.
|
||||
let line_dir = |entity: &EntityType| {
|
||||
let EntityType::Line(l) = entity else {
|
||||
panic!("expected a Line")
|
||||
};
|
||||
(l.end.x - l.start.x, l.end.y - l.start.y)
|
||||
};
|
||||
let dir_a = solved
|
||||
let moved_a = solved
|
||||
.iter()
|
||||
.find(|(h, _)| *h == a)
|
||||
.map(|(_, e)| line_dir(e))
|
||||
.unwrap_or((10.0, 6.0));
|
||||
let (_, moved_entity) = solved
|
||||
.iter()
|
||||
.find(|(h, _)| *h == b)
|
||||
.expect("b should be reported as moved");
|
||||
let dir_b = line_dir(moved_entity);
|
||||
let cross = dir_a.0 * dir_b.1 - dir_a.1 * dir_b.0;
|
||||
.map(|(_, entity)| entity)
|
||||
.expect("the dragged line should be projected");
|
||||
assert!(solved.iter().all(|(handle, _)| *handle != b));
|
||||
let EntityType::Line(moved_a_line) = moved_a else {
|
||||
panic!("expected a Line")
|
||||
};
|
||||
assert_eq!(moved_a_line.start, Vector3::new(0.0, 0.0, 0.0));
|
||||
let EntityType::Line(fixed_b) = b_before.unwrap() else {
|
||||
panic!("expected a Line")
|
||||
};
|
||||
let dir_a = moved_a_line.end - moved_a_line.start;
|
||||
let dir_b = fixed_b.end - fixed_b.start;
|
||||
let cross = dir_a.x * dir_b.y - dir_a.y * dir_b.x;
|
||||
assert!(
|
||||
cross.abs() < 1e-6,
|
||||
"the previewed positions should be mutually parallel: dir_a={dir_a:?} dir_b={dir_b:?}"
|
||||
);
|
||||
assert_eq!(fixed_b.start.y - moved_a_line.start.y, 5.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in new issue
Block a user