forked from 1b-agent/opencadstudio-upstream
Merge pull request #1365 from ramox81/codex/axis-align-perpendicular
Turn an object onto its Horizontal/Vertical axis before solving
This commit is contained in:
commit
b131102784
2 files changed
+110
No files matched your search
@@ -3511,6 +3511,53 @@ impl OpenCADStudio {
|
||||
}
|
||||
}
|
||||
}
|
||||
// The solver cannot start from an axis lying exactly across
|
||||
// the datum (its equations are singular there), so turn the
|
||||
// object onto the axis about its anchor first — the
|
||||
// reference turns it about that anchor too — and let the
|
||||
// constraint hold what already fits.
|
||||
if let Some((handle, anchor, end, vertex)) =
|
||||
crate::scene::parametric_constraints::axis_alignment_target(
|
||||
&self.tabs[i].scene.document,
|
||||
&refs,
|
||||
)
|
||||
{
|
||||
let axis = (end.x - anchor.x, end.y - anchor.y);
|
||||
let length = axis.0.hypot(axis.1);
|
||||
let target = if axis.0 * direction.x + axis.1 * direction.y >= 0.0 {
|
||||
(direction.x, direction.y)
|
||||
} else {
|
||||
(-direction.x, -direction.y)
|
||||
};
|
||||
let angle = (axis.0 * target.1 - axis.1 * target.0)
|
||||
.atan2(axis.0 * target.0 + axis.1 * target.1);
|
||||
if length > 1.0e-9 && angle.abs() > 1.0e-9 {
|
||||
match vertex {
|
||||
Some(index) => {
|
||||
let moved =
|
||||
self.tabs[i].scene.document.get_entity(handle).cloned();
|
||||
if let Some(mut entity) = moved {
|
||||
if crate::scene::parametric_constraints::set_polyline_vertex(
|
||||
&mut entity,
|
||||
index,
|
||||
anchor.x + length * target.0,
|
||||
anchor.y + length * target.1,
|
||||
) {
|
||||
self.tabs[i].scene.update_entity(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
None => self.tabs[i].scene.transform_entities(
|
||||
&[handle],
|
||||
&EntityTransform::Rotate {
|
||||
center: glam::DVec3::new(anchor.x, anchor.y, anchor.z),
|
||||
axis: glam::DVec3::Z,
|
||||
angle_rad: angle,
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
let id = self.tabs[i]
|
||||
.scene
|
||||
.parametric_constraint_set_mut(scope)
|
||||
|
||||
@@ -202,6 +202,69 @@ pub(crate) fn directional_axis_endpoints(
|
||||
}
|
||||
}
|
||||
|
||||
/// The axis a lone Horizontal/Vertical reference — or two points on one
|
||||
/// entity — turns onto its datum: the entity, the anchor that stays, the
|
||||
/// axis end that moves, and for a polyline the vertex to move instead of
|
||||
/// turning the whole entity.
|
||||
pub(crate) fn axis_alignment_target(
|
||||
document: &acadrust::CadDocument,
|
||||
refs: &[ParametricRef],
|
||||
) -> Option<(Handle, Vector3, Vector3, Option<usize>)> {
|
||||
let (handle, start_marker, end_marker) = match refs {
|
||||
[reference] => {
|
||||
let entity = document.get_entity(reference.entity)?;
|
||||
if reference.directional_axis().is_some() {
|
||||
let [start, end] = directional_axis_endpoints(entity, *reference)?;
|
||||
return Some((reference.entity, start, end, None));
|
||||
}
|
||||
let index = reference.segment_index().map_or(0, |index| index as i32);
|
||||
(reference.entity, index, index + 1)
|
||||
}
|
||||
[first, second] if first.entity == second.entity => {
|
||||
(first.entity, first.marker?, second.marker?)
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
let entity = document.get_entity(handle)?;
|
||||
let start = resolve_point(entity, start_marker)?;
|
||||
let end = resolve_point(entity, end_marker)?;
|
||||
let vertex = matches!(
|
||||
entity,
|
||||
acadrust::EntityType::LwPolyline(_) | acadrust::EntityType::Polyline2D(_)
|
||||
)
|
||||
.then(|| usize::try_from(end_marker).ok())
|
||||
.flatten();
|
||||
Some((handle, start, end, vertex))
|
||||
}
|
||||
|
||||
/// Moves one polyline vertex in its plane; `false` for any other entity.
|
||||
pub(crate) fn set_polyline_vertex(
|
||||
entity: &mut acadrust::EntityType,
|
||||
index: usize,
|
||||
x: f64,
|
||||
y: f64,
|
||||
) -> bool {
|
||||
match entity {
|
||||
acadrust::EntityType::LwPolyline(polyline) => polyline
|
||||
.vertices
|
||||
.get_mut(index)
|
||||
.map(|vertex| {
|
||||
vertex.location.x = x;
|
||||
vertex.location.y = y;
|
||||
})
|
||||
.is_some(),
|
||||
acadrust::EntityType::Polyline2D(polyline) => polyline
|
||||
.vertices
|
||||
.get_mut(index)
|
||||
.map(|vertex| {
|
||||
vertex.location.x = x;
|
||||
vertex.location.y = y;
|
||||
})
|
||||
.is_some(),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Grabbed points are exact kernel inputs; the solver anchors the remaining
|
||||
/// endpoint coordinates according to the line's directional constraints.
|
||||
pub(crate) fn grip_solve_anchor_refs(
|
||||
|
||||
Reference in new issue
Block a user