New node: Offset Path (#2030)

* New node: Offset Path

* Fix CI
This commit is contained in:
Keavon Chambers 2024-10-11 14:50:54 -07:00 committed by GitHub
parent 7a56af01ef
commit f7d83d2632
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 95 additions and 16 deletions

View file

@ -380,17 +380,24 @@ impl<PointId: crate::Identifier> Subpath<PointId> {
///
/// Alternatively, this can be interpreted as limiting the angle that the miter can form.
/// When the limit is exceeded, no manipulator group will be returned.
/// This value should be at least 1. If not, the default of 4 will be used.
/// This value should be greater than 0. If not, the default of 4 will be used.
pub(crate) fn miter_line_join(&self, other: &Subpath<PointId>, miter_limit: Option<f64>) -> Option<ManipulatorGroup<PointId>> {
let miter_limit = match miter_limit {
Some(miter_limit) if miter_limit >= 1. => miter_limit,
Some(miter_limit) if miter_limit > f64::EPSILON => miter_limit,
_ => 4.,
};
let in_segment = self.get_segment(self.len_segments() - 1).unwrap();
let out_segment = other.get_segment(0).unwrap();
// TODO: Besides returning None using the `?` operator, is there a more appropriate way to handle a `None` result from `get_segment`?
let in_segment = self.get_segment(self.len_segments() - 1)?;
let out_segment = other.get_segment(0)?;
let in_tangent = in_segment.tangent(TValue::Parametric(1.));
let out_tangent = out_segment.tangent(TValue::Parametric(0.));
if in_tangent == DVec2::ZERO || out_tangent == DVec2::ZERO {
// Avoid panic from normalizing zero vectors
// TODO: Besides returning None, is there a more appropriate way to handle this?
return None;
}
let normalized_in_tangent = in_tangent.normalize();
let normalized_out_tangent = out_tangent.normalize();
@ -400,11 +407,16 @@ impl<PointId: crate::Identifier> Subpath<PointId> {
let start_to_intersection = intersection - in_segment.end();
let intersection_to_end = out_segment.start() - intersection;
if start_to_intersection == DVec2::ZERO || intersection_to_end == DVec2::ZERO {
// Avoid panic from normalizing zero vectors
// TODO: Besides returning None, is there a more appropriate way to handle this?
return None;
}
// Draw the miter join if the intersection occurs in the correct direction with respect to the path
if start_to_intersection.normalize().abs_diff_eq(in_tangent, MAX_ABSOLUTE_DIFFERENCE)
&& intersection_to_end.normalize().abs_diff_eq(out_tangent, MAX_ABSOLUTE_DIFFERENCE)
&& miter_limit >= 1. / (start_to_intersection.angle_to(-intersection_to_end).abs() / 2.).sin()
&& miter_limit > f64::EPSILON / (start_to_intersection.angle_to(-intersection_to_end).abs() / 2.).sin()
{
return Some(ManipulatorGroup {
anchor: intersection,