mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-10-01 00:58:12 +08:00
Clean up the Vector struct implementations by privatizing and deleting unused APIs (#4458)
Trim the Vector API surface by privatizing and deleting caller-less items
This commit is contained in:
@@ -12,7 +12,7 @@ const MAX_ABSOLUTE_DIFFERENCE: f64 = 1e-3;
|
|||||||
|
|
||||||
/// Splits the [`BezPath`] at segment index at `t` value which lie in the range of [0, 1].
|
/// Splits the [`BezPath`] at segment index at `t` value which lie in the range of [0, 1].
|
||||||
/// Returns [`None`] if the given [`BezPath`] has no segments or `t` is within f64::EPSILON of 0 or 1.
|
/// Returns [`None`] if the given [`BezPath`] has no segments or `t` is within f64::EPSILON of 0 or 1.
|
||||||
pub fn split_bezpath_at_segment(bezpath: &BezPath, segment_index: usize, t: f64) -> Option<(BezPath, BezPath)> {
|
fn split_bezpath_at_segment(bezpath: &BezPath, segment_index: usize, t: f64) -> Option<(BezPath, BezPath)> {
|
||||||
if t <= f64::EPSILON || (1. - t) <= f64::EPSILON || bezpath.segments().count() == 0 {
|
if t <= f64::EPSILON || (1. - t) <= f64::EPSILON || bezpath.segments().count() == 0 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@@ -184,7 +184,7 @@ pub enum TValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Default LUT step size in `compute_lookup_table` function.
|
/// Default LUT step size in `compute_lookup_table` function.
|
||||||
pub const DEFAULT_LUT_STEP_SIZE: usize = 10;
|
const DEFAULT_LUT_STEP_SIZE: usize = 10;
|
||||||
|
|
||||||
/// Return a selection of equidistant points on the bezier curve.
|
/// Return a selection of equidistant points on the bezier curve.
|
||||||
/// If no value is provided for `steps`, then the function will default `steps` to be 10.
|
/// If no value is provided for `steps`, then the function will default `steps` to be 10.
|
||||||
@@ -488,7 +488,7 @@ pub fn miter_line_join(bezpath1: &BezPath, bezpath2: &BezPath, miter_limit: Opti
|
|||||||
|
|
||||||
/// Computes the [`PathEl`] to form a circular join from `left` to `right`, along a circle around `center`.
|
/// Computes the [`PathEl`] to form a circular join from `left` to `right`, along a circle around `center`.
|
||||||
/// By default, the angle is assumed to be 180 degrees.
|
/// By default, the angle is assumed to be 180 degrees.
|
||||||
pub fn compute_circular_subpath_details(left: DVec2, arc_point: DVec2, right: DVec2, center: DVec2, angle: Option<f64>) -> [PathEl; 2] {
|
fn compute_circular_subpath_details(left: DVec2, arc_point: DVec2, right: DVec2, center: DVec2, angle: Option<f64>) -> [PathEl; 2] {
|
||||||
let center_to_arc_point = arc_point - center;
|
let center_to_arc_point = arc_point - center;
|
||||||
|
|
||||||
// Based on https://pomax.github.io/bezierinfo/#circles_cubic
|
// Based on https://pomax.github.io/bezierinfo/#circles_cubic
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/// Minimum allowable separation between adjacent `t` values when calculating curve intersections
|
/// Minimum allowable separation between adjacent `t` values when calculating curve intersections
|
||||||
pub const MIN_SEPARATION_VALUE: f64 = 5. * 1e-3;
|
pub(crate) const MIN_SEPARATION_VALUE: f64 = 5. * 1e-3;
|
||||||
|
|
||||||
/// Constant used to determine if `f64`s are equivalent.
|
/// Constant used to determine if `f64`s are equivalent.
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub const MAX_ABSOLUTE_DIFFERENCE: f64 = 1e-3;
|
pub(crate) const MAX_ABSOLUTE_DIFFERENCE: f64 = 1e-3;
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ fn cubic_cubic_intersections_lyon(cubic1: kurbo::CubicBez, cubic2: kurbo::CubicB
|
|||||||
/// that segment where the intersection occurred.
|
/// that segment where the intersection occurred.
|
||||||
///
|
///
|
||||||
/// `minimum_separation` is the minimum difference that two adjacent `t`-values must have when comparing adjacent `t`-values in sorted order.
|
/// `minimum_separation` is the minimum difference that two adjacent `t`-values must have when comparing adjacent `t`-values in sorted order.
|
||||||
pub fn bezpath_and_segment_intersections(bezpath: &BezPath, segment: PathSeg, accuracy: Option<f64>, minimum_separation: Option<f64>) -> Vec<(usize, f64)> {
|
fn bezpath_and_segment_intersections(bezpath: &BezPath, segment: PathSeg, accuracy: Option<f64>, minimum_separation: Option<f64>) -> Vec<(usize, f64)> {
|
||||||
bezpath
|
bezpath
|
||||||
.segments()
|
.segments()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
@@ -39,7 +39,7 @@ pub fn bezpath_and_segment_intersections(bezpath: &BezPath, segment: PathSeg, ac
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Calculates the intersection points the bezpath has with another given bezpath and returns a list of parametric `t`-values.
|
/// Calculates the intersection points the bezpath has with another given bezpath and returns a list of parametric `t`-values.
|
||||||
pub fn bezpath_intersections(bezpath1: &BezPath, bezpath2: &BezPath, accuracy: Option<f64>, minimum_separation: Option<f64>) -> Vec<(usize, f64)> {
|
pub(crate) fn bezpath_intersections(bezpath1: &BezPath, bezpath2: &BezPath, accuracy: Option<f64>, minimum_separation: Option<f64>) -> Vec<(usize, f64)> {
|
||||||
let mut intersection_t_values: Vec<(usize, f64)> = bezpath2
|
let mut intersection_t_values: Vec<(usize, f64)> = bezpath2
|
||||||
.segments()
|
.segments()
|
||||||
.flat_map(|bezier| bezpath_and_segment_intersections(bezpath1, bezier, accuracy, minimum_separation))
|
.flat_map(|bezier| bezpath_and_segment_intersections(bezpath1, bezier, accuracy, minimum_separation))
|
||||||
@@ -50,7 +50,7 @@ pub fn bezpath_intersections(bezpath1: &BezPath, bezpath2: &BezPath, accuracy: O
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Calculates the intersection points the segment has with another given segment and returns a list of parametric `t`-values with given accuracy.
|
/// Calculates the intersection points the segment has with another given segment and returns a list of parametric `t`-values with given accuracy.
|
||||||
pub fn segment_intersections(segment1: PathSeg, segment2: PathSeg, accuracy: Option<f64>) -> Vec<(f64, f64)> {
|
fn segment_intersections(segment1: PathSeg, segment2: PathSeg, accuracy: Option<f64>) -> Vec<(f64, f64)> {
|
||||||
let accuracy = accuracy.unwrap_or(DEFAULT_ACCURACY);
|
let accuracy = accuracy.unwrap_or(DEFAULT_ACCURACY);
|
||||||
|
|
||||||
match (segment1, segment2) {
|
match (segment1, segment2) {
|
||||||
@@ -66,7 +66,7 @@ pub fn segment_intersections(segment1: PathSeg, segment2: PathSeg, accuracy: Opt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn subsegment_intersections(segment1: PathSeg, min_t1: f64, max_t1: f64, segment2: PathSeg, min_t2: f64, max_t2: f64, accuracy: Option<f64>) -> Vec<(f64, f64)> {
|
fn subsegment_intersections(segment1: PathSeg, min_t1: f64, max_t1: f64, segment2: PathSeg, min_t2: f64, max_t2: f64, accuracy: Option<f64>) -> Vec<(f64, f64)> {
|
||||||
let accuracy = accuracy.unwrap_or(DEFAULT_ACCURACY);
|
let accuracy = accuracy.unwrap_or(DEFAULT_ACCURACY);
|
||||||
|
|
||||||
match (segment1, segment2) {
|
match (segment1, segment2) {
|
||||||
@@ -180,7 +180,7 @@ pub fn filtered_segment_intersections(segment1: PathSeg, segment2: PathSeg, accu
|
|||||||
/// `error`, for intersections where the provided bezier is non-linear, defines the threshold for bounding boxes to be considered an intersection point.
|
/// `error`, for intersections where the provided bezier is non-linear, defines the threshold for bounding boxes to be considered an intersection point.
|
||||||
///
|
///
|
||||||
/// `minimum_separation` is the minimum difference between adjacent `t` values in sorted order
|
/// `minimum_separation` is the minimum difference between adjacent `t` values in sorted order
|
||||||
pub fn filtered_all_segment_intersections(segment1: PathSeg, segment2: PathSeg, accuracy: Option<f64>, minimum_separation: Option<f64>) -> Vec<(f64, f64)> {
|
pub(crate) fn filtered_all_segment_intersections(segment1: PathSeg, segment2: PathSeg, accuracy: Option<f64>, minimum_separation: Option<f64>) -> Vec<(f64, f64)> {
|
||||||
let mut intersection_t_values = segment_intersections(segment1, segment2, accuracy);
|
let mut intersection_t_values = segment_intersections(segment1, segment2, accuracy);
|
||||||
intersection_t_values.sort_by(|a, b| (a.0 + a.1).partial_cmp(&(b.0 + b.1)).unwrap());
|
intersection_t_values.sort_by(|a, b| (a.0 + a.1).partial_cmp(&(b.0 + b.1)).unwrap());
|
||||||
|
|
||||||
@@ -240,7 +240,7 @@ fn pathseg_self_intersection(segment: PathSeg, accuracy: Option<f64>) -> Vec<(f6
|
|||||||
/// 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.
|
/// 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.
|
||||||
/// - `error` - For intersections with non-linear beziers, `error` defines the threshold for bounding boxes to be considered an intersection point.
|
/// - `error` - For intersections with non-linear beziers, `error` defines the threshold for bounding boxes to be considered an intersection point.
|
||||||
/// - `minimum_separation` - The minimum difference between adjacent `t` values in sorted order
|
/// - `minimum_separation` - The minimum difference between adjacent `t` values in sorted order
|
||||||
pub fn pathseg_self_intersections(segment: PathSeg, accuracy: Option<f64>, minimum_separation: Option<f64>) -> Vec<(f64, f64)> {
|
pub(crate) fn pathseg_self_intersections(segment: PathSeg, accuracy: Option<f64>, minimum_separation: Option<f64>) -> Vec<(f64, f64)> {
|
||||||
let mut intersection_t_values = pathseg_self_intersection(segment, accuracy);
|
let mut intersection_t_values = pathseg_self_intersection(segment, accuracy);
|
||||||
intersection_t_values.sort_by(|a, b| (a.0 + a.1).partial_cmp(&(b.0 + b.1)).unwrap());
|
intersection_t_values.sort_by(|a, b| (a.0 + a.1).partial_cmp(&(b.0 + b.1)).unwrap());
|
||||||
|
|
||||||
|
|||||||
@@ -224,7 +224,7 @@ pub(crate) struct Point {
|
|||||||
/// Useful indexes to speed up various operations on [`Vector`].
|
/// Useful indexes to speed up various operations on [`Vector`].
|
||||||
///
|
///
|
||||||
/// Important: It is the user's responsibility to ensure the indexes remain valid after mutations to the data.
|
/// Important: It is the user's responsibility to ensure the indexes remain valid after mutations to the data.
|
||||||
pub struct VectorIndex {
|
pub(crate) struct VectorIndex {
|
||||||
/// Points and segments form a graph. Store it here in a form amenable to graph algorithms.
|
/// Points and segments form a graph. Store it here in a form amenable to graph algorithms.
|
||||||
///
|
///
|
||||||
/// Currently, segment data is not stored as it is not used, but it could easily be added.
|
/// Currently, segment data is not stored as it is not used, but it could easily be added.
|
||||||
@@ -237,7 +237,7 @@ pub struct VectorIndex {
|
|||||||
|
|
||||||
impl VectorIndex {
|
impl VectorIndex {
|
||||||
/// Construct a [`VectorIndex`] by building indexes from the given [`Vector`]. Takes `O(n)` time.
|
/// Construct a [`VectorIndex`] by building indexes from the given [`Vector`]. Takes `O(n)` time.
|
||||||
pub fn build_from(data: &Vector) -> Self {
|
fn build_from(data: &Vector) -> Self {
|
||||||
let point_to_offset = data.point_domain.ids().iter().copied().enumerate().map(|(a, b)| (b, a)).collect::<FxHashMap<_, _>>();
|
let point_to_offset = data.point_domain.ids().iter().copied().enumerate().map(|(a, b)| (b, a)).collect::<FxHashMap<_, _>>();
|
||||||
|
|
||||||
let mut point_to_node = FxHashMap::default();
|
let mut point_to_node = FxHashMap::default();
|
||||||
@@ -270,7 +270,7 @@ impl VectorIndex {
|
|||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Will panic if no segment with the given ID is found.
|
/// Will panic if no segment with the given ID is found.
|
||||||
pub fn segment_chord_length(&self, id: SegmentId) -> f64 {
|
fn segment_chord_length(&self, id: SegmentId) -> f64 {
|
||||||
let edge_idx = self.segment_to_edge[&id];
|
let edge_idx = self.segment_to_edge[&id];
|
||||||
let (start, end) = self.point_graph.edge_endpoints(edge_idx).unwrap();
|
let (start, end) = self.point_graph.edge_endpoints(edge_idx).unwrap();
|
||||||
let start_position = self.point_graph.node_weight(start).unwrap().position;
|
let start_position = self.point_graph.node_weight(start).unwrap().position;
|
||||||
@@ -285,7 +285,7 @@ impl VectorIndex {
|
|||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// This function will panic if the ID is not present.
|
/// This function will panic if the ID is not present.
|
||||||
pub fn segment_ends(&self, id: SegmentId) -> [NodeIndex; 2] {
|
fn segment_ends(&self, id: SegmentId) -> [NodeIndex; 2] {
|
||||||
let (start, end) = self.point_graph.edge_endpoints(self.segment_to_edge[&id]).unwrap();
|
let (start, end) = self.point_graph.edge_endpoints(self.segment_to_edge[&id]).unwrap();
|
||||||
if start < end { [start, end] } else { [end, start] }
|
if start < end { [start, end] } else { [end, start] }
|
||||||
}
|
}
|
||||||
@@ -295,7 +295,7 @@ impl VectorIndex {
|
|||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Will panic if `id` isn't in the data.
|
/// Will panic if `id` isn't in the data.
|
||||||
pub fn point_position(&self, id: PointId, data: &Vector) -> DVec2 {
|
fn point_position(&self, id: PointId, data: &Vector) -> DVec2 {
|
||||||
let offset = self.point_to_offset[&id];
|
let offset = self.point_to_offset[&id];
|
||||||
data.point_domain.positions()[offset]
|
data.point_domain.positions()[offset]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ mod contants;
|
|||||||
pub mod intersection;
|
pub mod intersection;
|
||||||
pub mod merge_by_distance;
|
pub mod merge_by_distance;
|
||||||
pub mod offset_subpath;
|
pub mod offset_subpath;
|
||||||
pub mod poisson_disk;
|
mod poisson_disk;
|
||||||
pub mod shapes;
|
pub mod shapes;
|
||||||
pub mod spline;
|
pub mod spline;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ const DEEPEST_SUBDIVISION_LEVEL_BEFORE_DISCARDING: usize = 8;
|
|||||||
/// Based on the paper:
|
/// Based on the paper:
|
||||||
/// "Poisson Disk Point Sets by Hierarchical Dart Throwing"
|
/// "Poisson Disk Point Sets by Hierarchical Dart Throwing"
|
||||||
/// <https://scholarsarchive.byu.edu/facpub/237/>
|
/// <https://scholarsarchive.byu.edu/facpub/237/>
|
||||||
pub fn poisson_disk_sample(
|
pub(crate) fn poisson_disk_sample(
|
||||||
offset: DVec2,
|
offset: DVec2,
|
||||||
width: f64,
|
width: f64,
|
||||||
height: f64,
|
height: f64,
|
||||||
@@ -187,23 +187,23 @@ where
|
|||||||
|
|
||||||
/// A square (represented by its top left corner position and width/height of `square_size`) that is currently a candidate for targetting by the dart throwing process.
|
/// A square (represented by its top left corner position and width/height of `square_size`) that is currently a candidate for targetting by the dart throwing process.
|
||||||
/// The positive sign bit encodes if the square is contained entirely within the masking shape, or negative if it's outside or intersects the shape path.
|
/// The positive sign bit encodes if the square is contained entirely within the masking shape, or negative if it's outside or intersects the shape path.
|
||||||
pub struct ActiveSquare(DVec2);
|
struct ActiveSquare(DVec2);
|
||||||
|
|
||||||
impl ActiveSquare {
|
impl ActiveSquare {
|
||||||
pub fn new(top_left_corner: DVec2, fully_in_shape: bool) -> Self {
|
fn new(top_left_corner: DVec2, fully_in_shape: bool) -> Self {
|
||||||
Self(if fully_in_shape { top_left_corner } else { -top_left_corner })
|
Self(if fully_in_shape { top_left_corner } else { -top_left_corner })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn top_left_corner(&self) -> DVec2 {
|
fn top_left_corner(&self) -> DVec2 {
|
||||||
self.0.abs()
|
self.0.abs()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fully_in_shape(&self) -> bool {
|
fn fully_in_shape(&self) -> bool {
|
||||||
self.0.x.is_sign_positive()
|
self.0.x.is_sign_positive()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ActiveListLevel {
|
struct ActiveListLevel {
|
||||||
/// List of all subdivided squares of the same size that are currently candidates for targetting by the dart throwing process
|
/// List of all subdivided squares of the same size that are currently candidates for targetting by the dart throwing process
|
||||||
active_squares: Vec<ActiveSquare>,
|
active_squares: Vec<ActiveSquare>,
|
||||||
/// Width and height of the squares in this level of subdivision
|
/// Width and height of the squares in this level of subdivision
|
||||||
@@ -214,7 +214,7 @@ pub struct ActiveListLevel {
|
|||||||
|
|
||||||
impl ActiveListLevel {
|
impl ActiveListLevel {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn new(square_size: f64) -> Self {
|
fn new(square_size: f64) -> Self {
|
||||||
Self {
|
Self {
|
||||||
active_squares: Vec::new(),
|
active_squares: Vec::new(),
|
||||||
square_size,
|
square_size,
|
||||||
@@ -222,7 +222,7 @@ impl ActiveListLevel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_filled(
|
fn new_filled(
|
||||||
square_size: f64,
|
square_size: f64,
|
||||||
offset: DVec2,
|
offset: DVec2,
|
||||||
width: f64,
|
width: f64,
|
||||||
@@ -295,14 +295,14 @@ impl ActiveListLevel {
|
|||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn take_square(&mut self, active_square_index: usize) -> ActiveSquare {
|
fn take_square(&mut self, active_square_index: usize) -> ActiveSquare {
|
||||||
let targetted_square = self.active_squares.swap_remove(active_square_index);
|
let targetted_square = self.active_squares.swap_remove(active_square_index);
|
||||||
self.total_area = self.square_size.powi(2) * self.active_squares.len() as f64;
|
self.total_area = self.square_size.powi(2) * self.active_squares.len() as f64;
|
||||||
targetted_square
|
targetted_square
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn add_squares(&mut self, new_squares: impl Iterator<Item = ActiveSquare>) {
|
fn add_squares(&mut self, new_squares: impl Iterator<Item = ActiveSquare>) {
|
||||||
for new_square in new_squares {
|
for new_square in new_squares {
|
||||||
self.active_squares.push(new_square);
|
self.active_squares.push(new_square);
|
||||||
}
|
}
|
||||||
@@ -310,28 +310,28 @@ impl ActiveListLevel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn square_size(&self) -> f64 {
|
fn square_size(&self) -> f64 {
|
||||||
self.square_size
|
self.square_size
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn square_area(&self) -> f64 {
|
fn square_area(&self) -> f64 {
|
||||||
self.square_size.powi(2)
|
self.square_size.powi(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn total_area(&self) -> f64 {
|
fn total_area(&self) -> f64 {
|
||||||
self.total_area
|
self.total_area
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn not_empty(&self) -> bool {
|
fn not_empty(&self) -> bool {
|
||||||
!self.active_squares.is_empty()
|
!self.active_squares.is_empty()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
pub struct PointsList {
|
struct PointsList {
|
||||||
// The worst-case number of points in a 3x3 grid is 16 (one at each intersection of the four gridlines per axis)
|
// The worst-case number of points in a 3x3 grid is 16 (one at each intersection of the four gridlines per axis)
|
||||||
storage_slots: [DVec2; 16],
|
storage_slots: [DVec2; 16],
|
||||||
length: usize,
|
length: usize,
|
||||||
@@ -339,19 +339,19 @@ pub struct PointsList {
|
|||||||
|
|
||||||
impl PointsList {
|
impl PointsList {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn push(&mut self, point: DVec2) {
|
fn push(&mut self, point: DVec2) {
|
||||||
self.storage_slots[self.length] = point;
|
self.storage_slots[self.length] = point;
|
||||||
self.length += 1;
|
self.length += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn list_cell_and_neighbors(&self) -> impl Iterator<Item = DVec2> {
|
fn list_cell_and_neighbors(&self) -> impl Iterator<Item = DVec2> {
|
||||||
// The negative bit is used to store whether a point belongs to a neighboring cell
|
// The negative bit is used to store whether a point belongs to a neighboring cell
|
||||||
self.storage_slots.into_iter().take(self.length).map(|point| (point.x.abs(), point.y.abs()).into())
|
self.storage_slots.into_iter().take(self.length).map(|point| (point.x.abs(), point.y.abs()).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn list_cell(&self) -> impl Iterator<Item = DVec2> {
|
fn list_cell(&self) -> impl Iterator<Item = DVec2> {
|
||||||
// The negative bit is used to store whether a point belongs to a neighboring cell
|
// The negative bit is used to store whether a point belongs to a neighboring cell
|
||||||
self.storage_slots
|
self.storage_slots
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@@ -360,7 +360,7 @@ impl PointsList {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct AccelerationGrid {
|
struct AccelerationGrid {
|
||||||
size: f64,
|
size: f64,
|
||||||
dimension_x: usize,
|
dimension_x: usize,
|
||||||
dimension_y: usize,
|
dimension_y: usize,
|
||||||
@@ -369,7 +369,7 @@ pub struct AccelerationGrid {
|
|||||||
|
|
||||||
impl AccelerationGrid {
|
impl AccelerationGrid {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn new(width: f64, height: f64, size: f64) -> Self {
|
fn new(width: f64, height: f64, size: f64) -> Self {
|
||||||
let dimension_x = (width / size).ceil() as usize + 1;
|
let dimension_x = (width / size).ceil() as usize + 1;
|
||||||
let dimension_y = (height / size).ceil() as usize + 1;
|
let dimension_y = (height / size).ceil() as usize + 1;
|
||||||
|
|
||||||
@@ -382,7 +382,7 @@ impl AccelerationGrid {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn insert(&mut self, point: DVec2) {
|
fn insert(&mut self, point: DVec2) {
|
||||||
let x = (point.x / self.size).floor() as usize;
|
let x = (point.x / self.size).floor() as usize;
|
||||||
let y = (point.y / self.size).floor() as usize;
|
let y = (point.y / self.size).floor() as usize;
|
||||||
|
|
||||||
@@ -408,7 +408,7 @@ impl AccelerationGrid {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn nearby_points(&self, point: DVec2) -> impl Iterator<Item = DVec2> {
|
fn nearby_points(&self, point: DVec2) -> impl Iterator<Item = DVec2> {
|
||||||
let x = (point.x / self.size).floor() as usize;
|
let x = (point.x / self.size).floor() as usize;
|
||||||
let y = (point.y / self.size).floor() as usize;
|
let y = (point.y / self.size).floor() as usize;
|
||||||
|
|
||||||
@@ -416,7 +416,7 @@ impl AccelerationGrid {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn final_points(&self, offset: DVec2) -> Vec<DVec2> {
|
fn final_points(&self, offset: DVec2) -> Vec<DVec2> {
|
||||||
self.cells.iter().flat_map(|cell| cell.list_cell()).map(|point| point + offset).collect()
|
self.cells.iter().flat_map(|cell| cell.list_cell()).map(|point| point + offset).collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,14 +16,14 @@ pub fn pathseg_tangent(segment: PathSeg, t: f64) -> DVec2 {
|
|||||||
|
|
||||||
/// Compare points by allowing some maximum absolute difference to account for floating point errors
|
/// Compare points by allowing some maximum absolute difference to account for floating point errors
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub fn compare_points(p1: kurbo::Point, p2: kurbo::Point) -> bool {
|
pub(crate) fn compare_points(p1: kurbo::Point, p2: kurbo::Point) -> bool {
|
||||||
let (p1, p2) = (crate::vector::misc::point_to_dvec2(p1), crate::vector::misc::point_to_dvec2(p2));
|
let (p1, p2) = (crate::vector::misc::point_to_dvec2(p1), crate::vector::misc::point_to_dvec2(p2));
|
||||||
p1.abs_diff_eq(p2, super::contants::MAX_ABSOLUTE_DIFFERENCE)
|
p1.abs_diff_eq(p2, super::contants::MAX_ABSOLUTE_DIFFERENCE)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compare vectors of points by allowing some maximum absolute difference to account for floating point errors
|
/// Compare vectors of points by allowing some maximum absolute difference to account for floating point errors
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub fn compare_vec_of_points(a: Vec<kurbo::Point>, b: Vec<kurbo::Point>, max_absolute_difference: f64) -> bool {
|
pub(crate) fn compare_vec_of_points(a: Vec<kurbo::Point>, b: Vec<kurbo::Point>, max_absolute_difference: f64) -> bool {
|
||||||
a.len() == b.len()
|
a.len() == b.len()
|
||||||
&& a.into_iter()
|
&& a.into_iter()
|
||||||
.zip(b)
|
.zip(b)
|
||||||
@@ -33,6 +33,6 @@ pub fn compare_vec_of_points(a: Vec<kurbo::Point>, b: Vec<kurbo::Point>, max_abs
|
|||||||
|
|
||||||
/// Compare the two values in a `DVec2` independently with a provided max absolute value difference.
|
/// Compare the two values in a `DVec2` independently with a provided max absolute value difference.
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub fn dvec2_compare(a: kurbo::Point, b: kurbo::Point, max_abs_diff: f64) -> glam::BVec2 {
|
pub(crate) fn dvec2_compare(a: kurbo::Point, b: kurbo::Point, max_abs_diff: f64) -> glam::BVec2 {
|
||||||
glam::BVec2::new((a.x - b.x).abs() < max_abs_diff, (a.y - b.y).abs() < max_abs_diff)
|
glam::BVec2::new((a.x - b.x).abs() < max_abs_diff, (a.y - b.y).abs() < max_abs_diff)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,25 +120,6 @@ impl AsU64 for f64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait AsI64 {
|
|
||||||
fn as_i64(&self) -> i64;
|
|
||||||
}
|
|
||||||
impl AsI64 for u32 {
|
|
||||||
fn as_i64(&self) -> i64 {
|
|
||||||
*self as i64
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl AsI64 for u64 {
|
|
||||||
fn as_i64(&self) -> i64 {
|
|
||||||
*self as i64
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl AsI64 for f64 {
|
|
||||||
fn as_i64(&self) -> i64 {
|
|
||||||
*self as i64
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
|
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
|
||||||
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash, DynAny, node_macro::ChoiceType)]
|
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash, DynAny, node_macro::ChoiceType)]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
@@ -322,7 +303,7 @@ pub fn is_linear(segment: PathSeg) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get an vec of all the points in a path segment.
|
/// Get an vec of all the points in a path segment.
|
||||||
pub fn pathseg_points_vec(segment: PathSeg) -> Vec<Point> {
|
fn pathseg_points_vec(segment: PathSeg) -> Vec<Point> {
|
||||||
match segment {
|
match segment {
|
||||||
PathSeg::Line(line) => [line.p0, line.p1].to_vec(),
|
PathSeg::Line(line) => [line.p0, line.p1].to_vec(),
|
||||||
PathSeg::Quad(quad_bez) => [quad_bez.p0, quad_bez.p1, quad_bez.p2].to_vec(),
|
PathSeg::Quad(quad_bez) => [quad_bez.p0, quad_bez.p1, quad_bez.p2].to_vec(),
|
||||||
@@ -681,25 +662,6 @@ impl ManipulatorGroup {
|
|||||||
Self { anchor, in_handle, out_handle, id }
|
Self { anchor, in_handle, out_handle, id }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a new manipulator group from an anchor, in handle, out handle and an id
|
|
||||||
pub fn new_with_id(anchor: DVec2, in_handle: Option<DVec2>, out_handle: Option<DVec2>, id: PointId) -> Self {
|
|
||||||
Self { anchor, in_handle, out_handle, id }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a bezier curve that starts at the current manipulator group and finishes in the `end_group` manipulator group.
|
|
||||||
pub fn to_bezier(&self, end_group: &ManipulatorGroup) -> PathSeg {
|
|
||||||
let start = self.anchor;
|
|
||||||
let end = end_group.anchor;
|
|
||||||
let out_handle = self.out_handle;
|
|
||||||
let in_handle = end_group.in_handle;
|
|
||||||
|
|
||||||
match (out_handle, in_handle) {
|
|
||||||
(Some(handle1), Some(handle2)) => PathSeg::Cubic(CubicBez::new(dvec2_to_point(start), dvec2_to_point(handle1), dvec2_to_point(handle2), dvec2_to_point(end))),
|
|
||||||
(Some(handle), None) | (None, Some(handle)) => PathSeg::Quad(QuadBez::new(dvec2_to_point(start), dvec2_to_point(handle), dvec2_to_point(end))),
|
|
||||||
(None, None) => PathSeg::Line(Line::new(dvec2_to_point(start), dvec2_to_point(end))),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Apply a transformation to all of the [ManipulatorGroup] points
|
/// Apply a transformation to all of the [ManipulatorGroup] points
|
||||||
pub fn apply_transform(&mut self, affine_transform: DAffine2) {
|
pub fn apply_transform(&mut self, affine_transform: DAffine2) {
|
||||||
self.anchor = affine_transform.transform_point2(self.anchor);
|
self.anchor = affine_transform.transform_point2(self.anchor);
|
||||||
|
|||||||
@@ -295,7 +295,7 @@ impl Stroke {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get the effective stroke weight.
|
/// Get the effective stroke weight.
|
||||||
pub fn effective_width(&self) -> f64 {
|
pub(crate) fn effective_width(&self) -> f64 {
|
||||||
self.weight
|
self.weight
|
||||||
* match self.align {
|
* match self.align {
|
||||||
StrokeAlign::Center => 1.,
|
StrokeAlign::Center => 1.,
|
||||||
@@ -342,14 +342,6 @@ impl Stroke {
|
|||||||
self.dash_offset
|
self.dash_offset
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cap_index(&self) -> u32 {
|
|
||||||
self.cap as u32
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn join_index(&self) -> u32 {
|
|
||||||
self.join as u32
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn join_miter_limit(&self) -> f32 {
|
pub fn join_miter_limit(&self) -> f32 {
|
||||||
self.join_miter_limit as f32
|
self.join_miter_limit as f32
|
||||||
}
|
}
|
||||||
@@ -359,31 +351,6 @@ impl Stroke {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_dash_offset(mut self, dash_offset: f64) -> Self {
|
|
||||||
self.dash_offset = dash_offset;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_stroke_cap(mut self, stroke_cap: StrokeCap) -> Self {
|
|
||||||
self.cap = stroke_cap;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_stroke_join(mut self, stroke_join: StrokeJoin) -> Self {
|
|
||||||
self.join = stroke_join;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_stroke_join_miter_limit(mut self, limit: f64) -> Self {
|
|
||||||
self.join_miter_limit = limit;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_stroke_align(mut self, stroke_align: StrokeAlign) -> Self {
|
|
||||||
self.align = stroke_align;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn has_renderable_stroke(&self) -> bool {
|
pub fn has_renderable_stroke(&self) -> bool {
|
||||||
self.weight > 0.
|
self.weight > 0.
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ impl PointDomain {
|
|||||||
self.position.reserve(additional);
|
self.position.reserve(additional);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn retain(&mut self, segment_domain: &mut SegmentDomain, f: impl Fn(&PointId) -> bool) {
|
pub(crate) fn retain(&mut self, segment_domain: &mut SegmentDomain, f: impl Fn(&PointId) -> bool) {
|
||||||
let mut keep = self.id.iter().map(&f);
|
let mut keep = self.id.iter().map(&f);
|
||||||
self.position.retain(|_| keep.next().unwrap_or_default());
|
self.position.retain(|_| keep.next().unwrap_or_default());
|
||||||
|
|
||||||
@@ -171,16 +171,16 @@ impl PointDomain {
|
|||||||
self.id.iter().position(|&check_id| check_id == id)
|
self.id.iter().position(|&check_id| check_id == id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn concat(&mut self, other: &Self, transform: DAffine2, id_map: &IdMap) {
|
pub(crate) fn concat(&mut self, other: &Self, transform: DAffine2, id_map: &IdMap) {
|
||||||
self.id.extend(other.id.iter().map(|id| *id_map.point_map.get(id).unwrap_or(id)));
|
self.id.extend(other.id.iter().map(|id| *id_map.point_map.get(id).unwrap_or(id)));
|
||||||
self.position.extend(other.position.iter().map(|&pos| transform.transform_point2(pos)));
|
self.position.extend(other.position.iter().map(|&pos| transform.transform_point2(pos)));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn map_ids(&mut self, id_map: &IdMap) {
|
pub(crate) fn map_ids(&mut self, id_map: &IdMap) {
|
||||||
self.id.iter_mut().for_each(|id| *id = *id_map.point_map.get(id).unwrap_or(id));
|
self.id.iter_mut().for_each(|id| *id = *id_map.point_map.get(id).unwrap_or(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn transform(&mut self, transform: DAffine2) {
|
pub(crate) fn transform(&mut self, transform: DAffine2) {
|
||||||
for pos in &mut self.position {
|
for pos in &mut self.position {
|
||||||
*pos = transform.transform_point2(*pos);
|
*pos = transform.transform_point2(*pos);
|
||||||
}
|
}
|
||||||
@@ -232,7 +232,7 @@ impl SegmentDomain {
|
|||||||
self.stroke.reserve(additional);
|
self.stroke.reserve(additional);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn retain(&mut self, f: impl Fn(&SegmentId) -> bool, points_length: usize) {
|
pub(crate) fn retain(&mut self, f: impl Fn(&SegmentId) -> bool, points_length: usize) {
|
||||||
let additional_delete_ids = self
|
let additional_delete_ids = self
|
||||||
.id
|
.id
|
||||||
.iter()
|
.iter()
|
||||||
@@ -348,7 +348,7 @@ impl SegmentDomain {
|
|||||||
nested.map(|((a, b), c)| (a, b, c))
|
nested.map(|((a, b), c)| (a, b, c))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stroke_mut(&mut self) -> impl Iterator<Item = (SegmentId, &mut StrokeId)> {
|
pub(crate) fn stroke_mut(&mut self) -> impl Iterator<Item = (SegmentId, &mut StrokeId)> {
|
||||||
self.id.iter().copied().zip(self.stroke.iter_mut())
|
self.id.iter().copied().zip(self.stroke.iter_mut())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -387,7 +387,7 @@ impl SegmentDomain {
|
|||||||
self.id.iter().position(|&check_id| check_id == id)
|
self.id.iter().position(|&check_id| check_id == id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn concat(&mut self, other: &Self, transform: DAffine2, id_map: &IdMap) {
|
pub(crate) fn concat(&mut self, other: &Self, transform: DAffine2, id_map: &IdMap) {
|
||||||
self.id.extend(other.id.iter().map(|id| *id_map.segment_map.get(id).unwrap_or(id)));
|
self.id.extend(other.id.iter().map(|id| *id_map.segment_map.get(id).unwrap_or(id)));
|
||||||
self.start_point.extend(other.start_point.iter().map(|&index| id_map.point_offset + index));
|
self.start_point.extend(other.start_point.iter().map(|&index| id_map.point_offset + index));
|
||||||
self.end_point.extend(other.end_point.iter().map(|&index| id_map.point_offset + index));
|
self.end_point.extend(other.end_point.iter().map(|&index| id_map.point_offset + index));
|
||||||
@@ -395,11 +395,11 @@ impl SegmentDomain {
|
|||||||
self.stroke.extend(&other.stroke);
|
self.stroke.extend(&other.stroke);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn map_ids(&mut self, id_map: &IdMap) {
|
pub(crate) fn map_ids(&mut self, id_map: &IdMap) {
|
||||||
self.id.iter_mut().for_each(|id| *id = *id_map.segment_map.get(id).unwrap_or(id));
|
self.id.iter_mut().for_each(|id| *id = *id_map.segment_map.get(id).unwrap_or(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn transform(&mut self, transform: DAffine2) {
|
pub(crate) fn transform(&mut self, transform: DAffine2) {
|
||||||
for handles in &mut self.handles {
|
for handles in &mut self.handles {
|
||||||
*handles = handles.apply_transformation(|p| transform.transform_point2(p));
|
*handles = handles.apply_transformation(|p| transform.transform_point2(p));
|
||||||
}
|
}
|
||||||
@@ -592,7 +592,7 @@ impl RegionDomain {
|
|||||||
self.fill.reserve(additional);
|
self.fill.reserve(additional);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn retain(&mut self, f: impl Fn(&RegionId) -> bool) {
|
pub(crate) fn retain(&mut self, f: impl Fn(&RegionId) -> bool) {
|
||||||
let mut keep = self.id.iter().map(&f);
|
let mut keep = self.id.iter().map(&f);
|
||||||
self.segment_range.retain(|_| keep.next().unwrap_or_default());
|
self.segment_range.retain(|_| keep.next().unwrap_or_default());
|
||||||
let mut keep = self.id.iter().map(&f);
|
let mut keep = self.id.iter().map(&f);
|
||||||
@@ -603,7 +603,7 @@ impl RegionDomain {
|
|||||||
/// Like [`Self::retain`] but also gives the function access to the segment range.
|
/// Like [`Self::retain`] but also gives the function access to the segment range.
|
||||||
///
|
///
|
||||||
/// Note that this function requires an allocation that `retain` avoids.
|
/// Note that this function requires an allocation that `retain` avoids.
|
||||||
pub fn retain_with_region(&mut self, f: impl Fn(&RegionId, &std::ops::RangeInclusive<SegmentId>) -> bool) {
|
pub(crate) fn retain_with_region(&mut self, f: impl Fn(&RegionId, &std::ops::RangeInclusive<SegmentId>) -> bool) {
|
||||||
let keep = self.id.iter().zip(self.segment_range.iter()).map(|(id, range)| f(id, range)).collect::<Vec<_>>();
|
let keep = self.id.iter().zip(self.segment_range.iter()).map(|(id, range)| f(id, range)).collect::<Vec<_>>();
|
||||||
let mut iter = keep.iter().copied();
|
let mut iter = keep.iter().copied();
|
||||||
self.segment_range.retain(|_| iter.next().unwrap());
|
self.segment_range.retain(|_| iter.next().unwrap());
|
||||||
@@ -638,11 +638,11 @@ impl RegionDomain {
|
|||||||
self.id.iter().copied().max_by(|a, b| a.0.cmp(&b.0)).map(|mut id| id.next_id()).unwrap_or(RegionId::ZERO)
|
self.id.iter().copied().max_by(|a, b| a.0.cmp(&b.0)).map(|mut id| id.next_id()).unwrap_or(RegionId::ZERO)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn segment_range_mut(&mut self) -> impl Iterator<Item = (RegionId, &mut std::ops::RangeInclusive<SegmentId>)> {
|
pub(crate) fn segment_range_mut(&mut self) -> impl Iterator<Item = (RegionId, &mut std::ops::RangeInclusive<SegmentId>)> {
|
||||||
self.id.iter().copied().zip(self.segment_range.iter_mut())
|
self.id.iter().copied().zip(self.segment_range.iter_mut())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fill_mut(&mut self) -> impl Iterator<Item = (RegionId, &mut FillId)> {
|
pub(crate) fn fill_mut(&mut self) -> impl Iterator<Item = (RegionId, &mut FillId)> {
|
||||||
self.id.iter().copied().zip(self.fill.iter_mut())
|
self.id.iter().copied().zip(self.fill.iter_mut())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -650,7 +650,7 @@ impl RegionDomain {
|
|||||||
&self.id
|
&self.id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn segment_range(&self) -> &[std::ops::RangeInclusive<SegmentId>] {
|
pub(crate) fn segment_range(&self) -> &[std::ops::RangeInclusive<SegmentId>] {
|
||||||
&self.segment_range
|
&self.segment_range
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -658,7 +658,7 @@ impl RegionDomain {
|
|||||||
&self.fill
|
&self.fill
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn concat(&mut self, other: &Self, _transform: DAffine2, id_map: &IdMap) {
|
pub(crate) fn concat(&mut self, other: &Self, _transform: DAffine2, id_map: &IdMap) {
|
||||||
self.id.extend(other.id.iter().map(|id| *id_map.region_map.get(id).unwrap_or(id)));
|
self.id.extend(other.id.iter().map(|id| *id_map.region_map.get(id).unwrap_or(id)));
|
||||||
self.segment_range.extend(
|
self.segment_range.extend(
|
||||||
other
|
other
|
||||||
@@ -669,7 +669,7 @@ impl RegionDomain {
|
|||||||
self.fill.extend(&other.fill);
|
self.fill.extend(&other.fill);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn map_ids(&mut self, id_map: &IdMap) {
|
pub(crate) fn map_ids(&mut self, id_map: &IdMap) {
|
||||||
self.id.iter_mut().for_each(|id| *id = *id_map.region_map.get(id).unwrap_or(id));
|
self.id.iter_mut().for_each(|id| *id = *id_map.region_map.get(id).unwrap_or(id));
|
||||||
self.segment_range
|
self.segment_range
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
@@ -696,11 +696,11 @@ pub struct HalfEdge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl HalfEdge {
|
impl HalfEdge {
|
||||||
pub fn new(id: SegmentId, start: usize, end: usize, reverse: bool) -> Self {
|
fn new(id: SegmentId, start: usize, end: usize, reverse: bool) -> Self {
|
||||||
Self { id, start, end, reverse }
|
Self { id, start, end, reverse }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reversed(&self) -> Self {
|
fn reversed(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id: self.id,
|
id: self.id,
|
||||||
start: self.start,
|
start: self.start,
|
||||||
@@ -709,7 +709,7 @@ impl HalfEdge {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn normalize_direction(&self) -> Self {
|
fn normalize_direction(&self) -> Self {
|
||||||
if self.reverse {
|
if self.reverse {
|
||||||
Self {
|
Self {
|
||||||
id: self.id,
|
id: self.id,
|
||||||
@@ -729,14 +729,14 @@ pub struct FoundSubpath {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FoundSubpath {
|
impl FoundSubpath {
|
||||||
pub fn endpoints(&self) -> Option<(&HalfEdge, &HalfEdge)> {
|
fn endpoints(&self) -> Option<(&HalfEdge, &HalfEdge)> {
|
||||||
match (self.edges.first(), self.edges.last()) {
|
match (self.edges.first(), self.edges.last()) {
|
||||||
(Some(first), Some(last)) => Some((first, last)),
|
(Some(first), Some(last)) => Some((first, last)),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push(&mut self, segment: HalfEdge) {
|
fn push(&mut self, segment: HalfEdge) {
|
||||||
self.edges.push(segment);
|
self.edges.push(segment);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -747,7 +747,7 @@ impl FoundSubpath {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_segment(segment: HalfEdge) -> Self {
|
fn from_segment(segment: HalfEdge) -> Self {
|
||||||
Self { edges: vec![segment] }
|
Self { edges: vec![segment] }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1108,7 +1108,7 @@ impl Vector {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_regions(&self) -> bool {
|
fn has_regions(&self) -> bool {
|
||||||
!self.region_domain.id.is_empty()
|
!self.region_domain.id.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1321,7 +1321,7 @@ impl Iterator for StrokePathIter<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Represents the conversion of IDs used when concatenating vector paths with conflicting IDs.
|
/// Represents the conversion of IDs used when concatenating vector paths with conflicting IDs.
|
||||||
pub struct IdMap {
|
pub(crate) struct IdMap {
|
||||||
pub point_offset: usize,
|
pub point_offset: usize,
|
||||||
pub point_map: HashMap<PointId, PointId>,
|
pub point_map: HashMap<PointId, PointId>,
|
||||||
pub segment_map: HashMap<SegmentId, SegmentId>,
|
pub segment_map: HashMap<SegmentId, SegmentId>,
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ use std::hash::Hash;
|
|||||||
/// Represents a procedural change to the [`PointDomain`] in [`Vector`].
|
/// Represents a procedural change to the [`PointDomain`] in [`Vector`].
|
||||||
#[derive(Clone, Debug, Default, PartialEq)]
|
#[derive(Clone, Debug, Default, PartialEq)]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
pub struct PointModification {
|
pub(crate) struct PointModification {
|
||||||
add: Vec<PointId>,
|
add: Vec<PointId>,
|
||||||
#[cfg_attr(feature = "serde", serde(serialize_with = "serialize_hashset"))]
|
#[cfg_attr(feature = "serde", serde(serialize_with = "serialize_hashset"))]
|
||||||
remove: HashSet<PointId>,
|
remove: HashSet<PointId>,
|
||||||
@@ -83,7 +83,7 @@ impl PointModification {
|
|||||||
/// Represents a procedural change to the [`SegmentDomain`] in [`Vector`].
|
/// Represents a procedural change to the [`SegmentDomain`] in [`Vector`].
|
||||||
#[derive(Clone, Debug, Default, PartialEq)]
|
#[derive(Clone, Debug, Default, PartialEq)]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
pub struct SegmentModification {
|
pub(crate) struct SegmentModification {
|
||||||
add: Vec<SegmentId>,
|
add: Vec<SegmentId>,
|
||||||
#[cfg_attr(feature = "serde", serde(serialize_with = "serialize_hashset"))]
|
#[cfg_attr(feature = "serde", serde(serialize_with = "serialize_hashset"))]
|
||||||
remove: HashSet<SegmentId>,
|
remove: HashSet<SegmentId>,
|
||||||
@@ -261,7 +261,7 @@ impl SegmentModification {
|
|||||||
/// Represents a procedural change to the [`RegionDomain`] in [`Vector`].
|
/// Represents a procedural change to the [`RegionDomain`] in [`Vector`].
|
||||||
#[derive(Clone, Debug, Default, PartialEq)]
|
#[derive(Clone, Debug, Default, PartialEq)]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
pub struct RegionModification {
|
pub(crate) struct RegionModification {
|
||||||
add: Vec<RegionId>,
|
add: Vec<RegionId>,
|
||||||
#[cfg_attr(feature = "serde", serde(serialize_with = "serialize_hashset"))]
|
#[cfg_attr(feature = "serde", serde(serialize_with = "serialize_hashset"))]
|
||||||
remove: HashSet<RegionId>,
|
remove: HashSet<RegionId>,
|
||||||
@@ -579,7 +579,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Serializes as sorted `[value, ...]` (JSON array)
|
/// Serializes as sorted `[value, ...]` (JSON array)
|
||||||
pub fn serialize_hashset<T, S, H>(set: &HashSet<T, H>, serializer: S) -> Result<S::Ok, S::Error>
|
pub(crate) fn serialize_hashset<T, S, H>(set: &HashSet<T, H>, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
T: Serialize + Eq + Hash + Ord,
|
T: Serialize + Eq + Hash + Ord,
|
||||||
S: Serializer,
|
S: Serializer,
|
||||||
@@ -639,7 +639,7 @@ where
|
|||||||
/// Matches Kurbo's default path accuracy, so points within an offset operation's own precision are not split into separate anchors.
|
/// Matches Kurbo's default path accuracy, so points within an offset operation's own precision are not split into separate anchors.
|
||||||
const CLOSE_POINT_TOLERANCE: f64 = 1e-6;
|
const CLOSE_POINT_TOLERANCE: f64 = 1e-6;
|
||||||
|
|
||||||
pub struct AppendBezpath<'a> {
|
pub(crate) struct AppendBezpath<'a> {
|
||||||
first_point: Option<Point>,
|
first_point: Option<Point>,
|
||||||
last_point: Option<Point>,
|
last_point: Option<Point>,
|
||||||
first_point_index: Option<usize>,
|
first_point_index: Option<usize>,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use super::misc::dvec2_to_point;
|
use super::misc::dvec2_to_point;
|
||||||
use super::style::{Stroke, StrokeAlign, StrokeCap, StrokeJoin};
|
use super::style::{Stroke, StrokeAlign, StrokeCap, StrokeJoin};
|
||||||
pub use super::vector_attributes::*;
|
use super::vector_attributes::*;
|
||||||
use crate::vector::misc::{BezierHandles, ManipulatorGroup};
|
use crate::vector::misc::{BezierHandles, ManipulatorGroup};
|
||||||
use crate::vector::misc::{HandleId, ManipulatorPointId};
|
use crate::vector::misc::{HandleId, ManipulatorPointId};
|
||||||
use crate::vector::vector_modification::VectorExt;
|
use crate::vector::vector_modification::VectorExt;
|
||||||
@@ -174,7 +174,7 @@ impl Vector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Compute the bounding boxes of the bezpaths with the specified transform
|
/// Compute the bounding boxes of the bezpaths with the specified transform
|
||||||
pub fn bounding_box_with_transform_rect(&self, transform: DAffine2) -> Option<Rect> {
|
fn bounding_box_with_transform_rect(&self, transform: DAffine2) -> Option<Rect> {
|
||||||
let combine = |r1: Rect, r2: Rect| r1.union(r2);
|
let combine = |r1: Rect, r2: Rect| r1.union(r2);
|
||||||
self.stroke_bezpath_iter()
|
self.stroke_bezpath_iter()
|
||||||
.map(|mut bezpath| {
|
.map(|mut bezpath| {
|
||||||
|
|||||||
Reference in New Issue
Block a user