Bezier-rs: Subpath offset and bezier offset improvements (#1039)

* Added subpath offset

* Enhanced offset to produce smooth curves

* Lots of outline bugfixes

* Fixed failing unit tests

* Added subpath outline

* Refactor bezier offset and outline to return Subpaths

* Fix outline bug due to smooth joining and removed reduce optimization that causes jumping approximations

* Bugfix when subpath angle is acute but doesn't intersect

* Stylistic changes per review

* Stylistic changes per review and updated doc comments

---------

Co-authored-by: Hannah Li <hannahli2010@gmail.com>
Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
Rob Nadal
2023-03-03 14:21:21 -05:00
committed by GitHub
co-authored by Hannah Li Keavon Chambers
parent 0512cb249f
commit 2fd5c26450
16 changed files with 611 additions and 168 deletions
+5 -5
View File
@@ -53,7 +53,7 @@ impl Bezier {
}
/// Returns the non-normalized vector representing the tangent at the point `t` along the curve.
fn non_normalized_tangent(&self, t: f64) -> DVec2 {
pub(crate) fn non_normalized_tangent(&self, t: f64) -> DVec2 {
match self.handles {
BezierHandles::Linear => self.end - self.start,
_ => self.derivative().unwrap().evaluate(TValue::Parametric(t)),
@@ -202,7 +202,7 @@ impl Bezier {
/// Implementation of the algorithm to find curve intersections by iterating on bounding boxes.
/// - `self_original_t_interval` - Used to identify the `t` values of the original parent of `self` that the current iteration is representing.
/// - `other_original_t_interval` - Used to identify the `t` values of the original parent of `other` that the current iteration is representing.
fn intersections_between_subcurves(&self, self_original_t_interval: Range<f64>, other: &Bezier, other_original_t_interval: Range<f64>, error: f64) -> Vec<[f64; 2]> {
pub(crate) fn intersections_between_subcurves(&self, self_original_t_interval: Range<f64>, other: &Bezier, other_original_t_interval: Range<f64>, error: f64) -> Vec<[f64; 2]> {
let bounding_box1 = self.bounding_box();
let bounding_box2 = other.bounding_box();
@@ -245,8 +245,8 @@ impl Bezier {
// TODO: Use an `impl Iterator` return type instead of a `Vec`
/// Returns a list of filtered parametric `t` values that correspond to intersection points between the current bezier curve and the provided one
/// such that the difference between adjacent `t` values in sorted order is greater than some minimum seperation value. If the difference
/// between 2 adjacent `t` values is lesss than the minimum difference, the filtering takes the larger `t` value and discards the smaller `t` value.
/// such that the difference between adjacent `t` values in sorted order is greater than some minimum separation value. If the difference
/// between 2 adjacent `t` values is less than the minimum difference, the filtering takes the larger `t` value and discards the smaller `t` value.
/// The returned `t` values are with respect to the current bezier, not the provided parameter.
/// If the provided curve is linear, then zero intersection points will be returned along colinear segments.
/// - `error` - For intersections where the provided bezier is non-linear, `error` defines the threshold for bounding boxes to be considered an intersection point.
@@ -259,7 +259,7 @@ impl Bezier {
intersection_t_values.sort_by(|a, b| a.partial_cmp(b).unwrap());
intersection_t_values.iter().fold(Vec::new(), |mut accumulator, t| {
if !accumulator.is_empty() && (accumulator.last().unwrap() - t).abs() < minimum_seperation.unwrap_or(MIN_SEPERATION_VALUE) {
if !accumulator.is_empty() && (accumulator.last().unwrap() - t).abs() < minimum_seperation.unwrap_or(MIN_SEPARATION_VALUE) {
accumulator.pop();
}
accumulator.push(*t);