forked from 1b-agent/opencadstudio-upstream
Restrict parallel offsets to straight polyline segments
This commit is contained in:
1 parent
9ae1e6dd76
commit
dfc859dcf5
1 file changed
+29
-23
+29
-23
@@ -1176,7 +1176,6 @@ fn move_segment_parallel(pline: &mut LwPolyline, seg: usize, offset: f64) {
|
|||||||
let i0 = seg;
|
let i0 = seg;
|
||||||
let i1 = (seg + 1) % n;
|
let i1 = (seg + 1) % n;
|
||||||
if pline.vertices[i0].bulge.abs() >= 1.0e-9 {
|
if pline.vertices[i0].bulge.abs() >= 1.0e-9 {
|
||||||
move_arc_segment_parallel(pline, seg, offset);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let p0 = Vec2::new(pline.vertices[i0].location.x, pline.vertices[i0].location.y);
|
let p0 = Vec2::new(pline.vertices[i0].location.x, pline.vertices[i0].location.y);
|
||||||
@@ -1280,7 +1279,9 @@ fn move_segment_parallel(pline: &mut LwPolyline, seg: usize, offset: f64) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn move_arc_segment_parallel(pline: &mut LwPolyline, seg: usize, offset: f64) {
|
/// Resize an arc concentrically while preserving its neighboring geometry.
|
||||||
|
/// This is used exclusively by the Radius grip-menu action.
|
||||||
|
fn resize_arc_concentrically(pline: &mut LwPolyline, seg: usize, offset: f64) {
|
||||||
let n = pline.vertices.len();
|
let n = pline.vertices.len();
|
||||||
let i0 = seg;
|
let i0 = seg;
|
||||||
let i1 = (seg + 1) % n;
|
let i1 = (seg + 1) % n;
|
||||||
@@ -1534,7 +1535,7 @@ fn resize_arc_segment_radius(pline: &mut LwPolyline, seg: usize, radius: f64) {
|
|||||||
// Ordinary arcs keep their centre. Connected endpoints slide along the
|
// Ordinary arcs keep their centre. Connected endpoints slide along the
|
||||||
// infinite lines of their adjacent straight segments, preserving those
|
// infinite lines of their adjacent straight segments, preserving those
|
||||||
// lines' angles; only free open endpoints move radially.
|
// lines' angles; only free open endpoints move radially.
|
||||||
move_arc_segment_parallel(pline, seg, radius - original.radius);
|
resize_arc_concentrically(pline, seg, radius - original.radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_transform(pline: &mut LwPolyline, t: &EntityTransform) {
|
fn apply_transform(pline: &mut LwPolyline, t: &EntityTransform) {
|
||||||
@@ -1615,10 +1616,17 @@ impl crate::entities::traits::Grippable for LwPolyline {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
let mut items = Vec::new();
|
let mut items = Vec::new();
|
||||||
items.push(GripMenuItem {
|
if is_arc {
|
||||||
label: "Move Parallel",
|
items.push(GripMenuItem {
|
||||||
action: GripMenuAction::MoveParallel,
|
label: "Radius",
|
||||||
});
|
action: GripMenuAction::Radius,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
items.push(GripMenuItem {
|
||||||
|
label: "Move Parallel",
|
||||||
|
action: GripMenuAction::MoveParallel,
|
||||||
|
});
|
||||||
|
}
|
||||||
if is_rectangle(self) && seg < 4 {
|
if is_rectangle(self) && seg < 4 {
|
||||||
// Moving an edge changes the dimension perpendicular to it.
|
// Moving an edge changes the dimension perpendicular to it.
|
||||||
items.push(GripMenuItem {
|
items.push(GripMenuItem {
|
||||||
@@ -1641,12 +1649,6 @@ impl crate::entities::traits::Grippable for LwPolyline {
|
|||||||
},
|
},
|
||||||
convert,
|
convert,
|
||||||
]);
|
]);
|
||||||
if is_arc {
|
|
||||||
items.push(GripMenuItem {
|
|
||||||
label: "Radius",
|
|
||||||
action: GripMenuAction::Radius,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
items
|
items
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1664,7 +1666,8 @@ impl crate::entities::traits::Grippable for LwPolyline {
|
|||||||
} else {
|
} else {
|
||||||
n.saturating_sub(1)
|
n.saturating_sub(1)
|
||||||
};
|
};
|
||||||
return (seg < count).then_some("Parallel offset");
|
return (seg < count && self.vertices[seg].bulge.abs() < 1.0e-9)
|
||||||
|
.then_some("Parallel offset");
|
||||||
}
|
}
|
||||||
if action == A::Radius && grip_id >= n {
|
if action == A::Radius && grip_id >= n {
|
||||||
let seg = grip_id - n;
|
let seg = grip_id - n;
|
||||||
@@ -1721,7 +1724,7 @@ impl crate::entities::traits::Grippable for LwPolyline {
|
|||||||
} else {
|
} else {
|
||||||
n.saturating_sub(1)
|
n.saturating_sub(1)
|
||||||
};
|
};
|
||||||
if seg >= count {
|
if seg >= count || self.vertices[seg].bulge.abs() >= 1.0e-9 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let plane = crate::entities::curve::lwpolyline_curve(self)?.plane;
|
let plane = crate::entities::curve::lwpolyline_curve(self)?.plane;
|
||||||
@@ -1785,7 +1788,9 @@ impl crate::entities::traits::Grippable for LwPolyline {
|
|||||||
}
|
}
|
||||||
if action == A::MoveParallel {
|
if action == A::MoveParallel {
|
||||||
if let Some(seg) = grip_id.checked_sub(self.vertices.len()) {
|
if let Some(seg) = grip_id.checked_sub(self.vertices.len()) {
|
||||||
move_segment_parallel(self, seg, value);
|
if self.vertices.get(seg).is_some_and(|vertex| vertex.bulge.abs() < 1.0e-9) {
|
||||||
|
move_segment_parallel(self, seg, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -2048,12 +2053,13 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn arc_midpoint_offers_move_parallel_first() {
|
fn arc_midpoint_offers_radius_first_without_move_parallel() {
|
||||||
let mut pl = make_test_lwpolyline(2, 0.0);
|
let mut pl = make_test_lwpolyline(2, 0.0);
|
||||||
pl.vertices[0].bulge = 0.5;
|
pl.vertices[0].bulge = 0.5;
|
||||||
let menu = pl.grip_menu(2);
|
let menu = pl.grip_menu(2);
|
||||||
assert_eq!(menu[0].action, GripMenuAction::MoveParallel);
|
assert_eq!(menu[0].action, GripMenuAction::Radius);
|
||||||
assert_eq!(menu[1].action, GripMenuAction::Stretch);
|
assert_eq!(menu[1].action, GripMenuAction::Stretch);
|
||||||
|
assert!(!menu.iter().any(|item| item.action == GripMenuAction::MoveParallel));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -2146,7 +2152,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn move_parallel_offsets_arc_concentrically() {
|
fn radius_offsets_arc_concentrically() {
|
||||||
let mut pl = polyline(&[(0.0, 0.0), (10.0, 0.0)], false);
|
let mut pl = polyline(&[(0.0, 0.0), (10.0, 0.0)], false);
|
||||||
pl.vertices[0].bulge = 1.0;
|
pl.vertices[0].bulge = 1.0;
|
||||||
let original = crate::entities::common::BulgeArc::from_bulge(
|
let original = crate::entities::common::BulgeArc::from_bulge(
|
||||||
@@ -2156,7 +2162,7 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
move_segment_parallel(&mut pl, 0, 2.0);
|
resize_arc_concentrically(&mut pl, 0, 2.0);
|
||||||
|
|
||||||
let moved = crate::entities::common::BulgeArc::from_bulge(
|
let moved = crate::entities::common::BulgeArc::from_bulge(
|
||||||
[pl.vertices[0].location.x, pl.vertices[0].location.y],
|
[pl.vertices[0].location.x, pl.vertices[0].location.y],
|
||||||
@@ -2170,11 +2176,11 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn move_parallel_allows_an_open_arc_with_a_duplicate_end_vertex() {
|
fn radius_allows_an_open_arc_with_a_duplicate_end_vertex() {
|
||||||
let mut pl = polyline(&[(0.0, 0.0), (10.0, 0.0), (10.0, 0.0)], false);
|
let mut pl = polyline(&[(0.0, 0.0), (10.0, 0.0), (10.0, 0.0)], false);
|
||||||
pl.vertices[0].bulge = 1.0;
|
pl.vertices[0].bulge = 1.0;
|
||||||
|
|
||||||
move_segment_parallel(&mut pl, 0, 2.0);
|
resize_arc_concentrically(&mut pl, 0, 2.0);
|
||||||
|
|
||||||
let moved = crate::entities::common::BulgeArc::from_bulge(
|
let moved = crate::entities::common::BulgeArc::from_bulge(
|
||||||
[pl.vertices[0].location.x, pl.vertices[0].location.y],
|
[pl.vertices[0].location.x, pl.vertices[0].location.y],
|
||||||
@@ -2200,7 +2206,7 @@ mod tests {
|
|||||||
[shared.x, shared.y], [11.0, 0.0], pl.vertices[1].bulge,
|
[shared.x, shared.y], [11.0, 0.0], pl.vertices[1].bulge,
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
move_segment_parallel(&mut pl, 0, 1.0);
|
resize_arc_concentrically(&mut pl, 0, 1.0);
|
||||||
|
|
||||||
let after = crate::entities::common::BulgeArc::from_bulge(
|
let after = crate::entities::common::BulgeArc::from_bulge(
|
||||||
[pl.vertices[1].location.x, pl.vertices[1].location.y],
|
[pl.vertices[1].location.x, pl.vertices[1].location.y],
|
||||||
|
|||||||
Reference in new issue
Block a user