Complete parametric drawing interoperability

This commit is contained in:
Hakan Seven committed 2026-09-14 23:51:37 +03:00
1 parent 7aff9fa046
commit 753df67ee4
13 files changed
+1602 -138

No files matched your search

+206
View File
@@ -127,6 +127,77 @@ fn horizontal_constraint_levels_the_line_when_an_endpoint_moves() {
);
}
#[test]
fn horizontal_constraint_levels_a_polyline_segment() {
let mut scene = Scene::new();
let polyline = scene.add_entity(EntityType::LwPolyline(
acadrust::entities::LwPolyline::from_points(vec![
acadrust::types::Vector2::new(0.0, 0.0),
acadrust::types::Vector2::new(5.0, 2.0),
acadrust::types::Vector2::new(10.0, 7.0),
]),
));
scene
.sketch_constraint_set_mut(SketchScope::ModelSpace)
.add(
ConstraintKind::Horizontal,
vec![SketchRef::segment(polyline, 1)],
None,
);
scene.bump_entities(&[(polyline, ChangeKind::Modified)]);
let EntityType::LwPolyline(polyline) = scene.document.get_entity(polyline).unwrap() else {
panic!("expected a lightweight polyline");
};
assert!(
(polyline.vertices[1].location.y - polyline.vertices[2].location.y).abs() < 1e-6,
"the selected segment should be horizontal"
);
}
#[test]
fn horizontal_constraint_does_not_flatten_a_polyline_arc_segment() {
let mut source = acadrust::entities::LwPolyline::new();
source.add_point_with_bulge(acadrust::types::Vector2::new(0.0, 0.0), 0.5);
source.add_point(acadrust::types::Vector2::new(5.0, 2.0));
let mut scene = Scene::new();
let polyline = scene.add_entity(EntityType::LwPolyline(source));
scene
.sketch_constraint_set_mut(SketchScope::ModelSpace)
.add(
ConstraintKind::Horizontal,
vec![SketchRef::segment(polyline, 0)],
None,
);
scene.bump_entities(&[(polyline, ChangeKind::Modified)]);
let EntityType::LwPolyline(polyline) = scene.document.get_entity(polyline).unwrap() else {
panic!("expected a lightweight polyline");
};
assert_eq!(polyline.vertices[0].location.y, 0.0);
assert_eq!(polyline.vertices[1].location.y, 2.0);
assert_eq!(polyline.vertices[0].bulge, 0.5);
}
#[test]
fn horizontal_constraint_aligns_two_selected_points() {
let mut scene = Scene::new();
let a = add_line(&mut scene, 0.0, 1.0, 4.0, 3.0);
let b = add_line(&mut scene, 8.0, 7.0, 12.0, 9.0);
scene
.sketch_constraint_set_mut(SketchScope::ModelSpace)
.add(
ConstraintKind::Horizontal,
vec![SketchRef::point(a, 0), SketchRef::point(b, 0)],
None,
);
scene.bump_entities(&[(b, ChangeKind::Modified)]);
let (a_start, _) = line_endpoints(&scene, a);
let (b_start, _) = line_endpoints(&scene, b);
assert!((a_start.y - b_start.y).abs() < 1e-6);
}
#[test]
fn parallel_constraint_rotates_the_other_line_when_one_moves() {
let mut scene = Scene::new();
@@ -655,6 +726,55 @@ fn midpoint_constraint_pulls_a_point_onto_a_lines_midpoint() {
);
}
#[test]
fn midpoint_constraint_supports_a_point_entity() {
let mut scene = Scene::new();
let base = add_line(&mut scene, 0.0, 0.0, 10.0, 6.0);
let point = scene.add_entity(EntityType::Point(acadrust::entities::Point::at(
Vector3::new(20.0, 20.0, 0.0),
)));
scene
.sketch_constraint_set_mut(SketchScope::ModelSpace)
.add(
ConstraintKind::Midpoint,
vec![SketchRef::point(point, 0), SketchRef::whole(base)],
None,
);
scene.bump_entities(&[(base, ChangeKind::Modified)]);
let (start, end) = line_endpoints(&scene, base);
let EntityType::Point(point) = scene.document.get_entity(point).unwrap() else {
panic!("expected a point");
};
assert!((point.location.x - (start.x + end.x) / 2.0).abs() < 1e-6);
assert!((point.location.y - (start.y + end.y) / 2.0).abs() < 1e-6);
}
#[test]
fn coincident_constraint_supports_a_block_insertion_point() {
let mut scene = Scene::new();
let line = add_line(&mut scene, 0.0, 0.0, 10.0, 4.0);
let insert = scene.add_entity(EntityType::Insert(acadrust::entities::Insert::new(
"fixture",
Vector3::new(30.0, 20.0, 0.0),
)));
scene
.sketch_constraint_set_mut(SketchScope::ModelSpace)
.add(
ConstraintKind::Coincident,
vec![SketchRef::point(line, 1), SketchRef::point(insert, 0)],
None,
);
scene.bump_entities(&[(line, ChangeKind::Modified)]);
let (_, end) = line_endpoints(&scene, line);
let EntityType::Insert(insert) = scene.document.get_entity(insert).unwrap() else {
panic!("expected a block reference");
};
assert!((insert.insert_point.x - end.x).abs() < 1e-6);
assert!((insert.insert_point.y - end.y).abs() < 1e-6);
}
#[test]
fn fixed_constraint_holds_an_entity_in_place_despite_a_connected_edit() {
let mut scene = Scene::new();
@@ -723,6 +843,92 @@ fn point_on_curve_constraint_pulls_a_point_onto_a_circles_circumference() {
);
}
#[test]
fn point_on_curve_constraint_pulls_a_point_onto_an_ellipse() {
let mut scene = Scene::new();
let ellipse = add_ellipse(&mut scene, 0.0, 0.0, (5.0, 0.0), 0.6);
let marker = add_line(&mut scene, 12.0, 8.0, 13.0, 8.0);
scene
.sketch_constraint_set_mut(SketchScope::ModelSpace)
.add(
ConstraintKind::PointOnCurve,
vec![SketchRef::point(marker, 0), SketchRef::whole(ellipse)],
None,
);
scene.bump_entities(&[(marker, ChangeKind::Modified)]);
let (center, major, ratio) = ellipse_geom(&scene, ellipse);
let (point, _) = line_endpoints(&scene, marker);
let a = major.length();
let b = a * ratio;
let u = major / a;
let v = Vector3::new(-u.y, u.x, 0.0);
let offset = point - center;
let equation = (offset.dot(&u) / a).powi(2) + (offset.dot(&v) / b).powi(2);
assert!(
(equation - 1.0).abs() < 1e-5,
"point should satisfy the solved ellipse equation: {equation}"
);
}
#[test]
fn tangent_constraint_solves_an_ellipse_and_line() {
let mut scene = Scene::new();
let ellipse = add_ellipse(&mut scene, 0.0, 0.0, (5.0, 0.0), 0.6);
let line = add_line(&mut scene, -8.0, 8.0, 8.0, 8.0);
scene
.sketch_constraint_set_mut(SketchScope::ModelSpace)
.add(
ConstraintKind::Tangent,
vec![SketchRef::whole(ellipse), SketchRef::whole(line)],
None,
);
scene.bump_entities(&[(line, ChangeKind::Modified)]);
let (center, major, ratio) = ellipse_geom(&scene, ellipse);
let (start, end) = line_endpoints(&scene, line);
let direction = (end - start).normalize();
let normal = Vector3::new(-direction.y, direction.x, 0.0);
let unit_major = major.normalize();
let unit_minor = Vector3::new(-unit_major.y, unit_major.x, 0.0);
let a = major.length();
let b = a * ratio;
let support =
((a * normal.dot(&unit_major)).powi(2) + (b * normal.dot(&unit_minor)).powi(2)).sqrt();
let distance = (center - start).dot(&normal).abs();
assert!(
(distance - support).abs() < 1e-5,
"line should be tangent to the solved ellipse: distance={distance} support={support}"
);
}
#[test]
fn equal_constraint_matches_ellipse_major_axes() {
let mut scene = Scene::new();
let a = add_ellipse(&mut scene, 0.0, 0.0, (5.0, 0.0), 0.6);
let b = add_ellipse(&mut scene, 20.0, 0.0, (2.0, 0.0), 0.5);
scene
.sketch_constraint_set_mut(SketchScope::ModelSpace)
.add(
ConstraintKind::Equal,
vec![SketchRef::whole(a), SketchRef::whole(b)],
None,
);
scene.bump_entities(&[(b, ChangeKind::Modified)]);
let (_, major_a, _) = ellipse_geom(&scene, a);
let (_, major_b, _) = ellipse_geom(&scene, b);
assert!(
(major_a.length() - major_b.length()).abs() < 1e-5,
"ellipse major radii should match: {} vs {}",
major_a.length(),
major_b.length()
);
}
#[test]
fn equal_distance_constraint_matches_a_second_point_pairs_separation() {
let mut scene = Scene::new();