mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 22:28:10 +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].
|
||||
/// 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 {
|
||||
return None;
|
||||
}
|
||||
@@ -184,7 +184,7 @@ pub enum TValue {
|
||||
}
|
||||
|
||||
/// 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.
|
||||
/// 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`.
|
||||
/// 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;
|
||||
|
||||
// Based on https://pomax.github.io/bezierinfo/#circles_cubic
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/// 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.
|
||||
#[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.
|
||||
///
|
||||
/// `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
|
||||
.segments()
|
||||
.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.
|
||||
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
|
||||
.segments()
|
||||
.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.
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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.
|
||||
///
|
||||
/// `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);
|
||||
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.
|
||||
/// - `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
|
||||
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);
|
||||
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`].
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// 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 {
|
||||
/// 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 mut point_to_node = FxHashMap::default();
|
||||
@@ -270,7 +270,7 @@ impl VectorIndex {
|
||||
/// # Panics
|
||||
///
|
||||
/// 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 (start, end) = self.point_graph.edge_endpoints(edge_idx).unwrap();
|
||||
let start_position = self.point_graph.node_weight(start).unwrap().position;
|
||||
@@ -285,7 +285,7 @@ impl VectorIndex {
|
||||
/// # Panics
|
||||
///
|
||||
/// 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();
|
||||
if start < end { [start, end] } else { [end, start] }
|
||||
}
|
||||
@@ -295,7 +295,7 @@ impl VectorIndex {
|
||||
/// # Panics
|
||||
///
|
||||
/// 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];
|
||||
data.point_domain.positions()[offset]
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ mod contants;
|
||||
pub mod intersection;
|
||||
pub mod merge_by_distance;
|
||||
pub mod offset_subpath;
|
||||
pub mod poisson_disk;
|
||||
mod poisson_disk;
|
||||
pub mod shapes;
|
||||
pub mod spline;
|
||||
pub mod util;
|
||||
|
||||
@@ -8,7 +8,7 @@ const DEEPEST_SUBDIVISION_LEVEL_BEFORE_DISCARDING: usize = 8;
|
||||
/// Based on the paper:
|
||||
/// "Poisson Disk Point Sets by Hierarchical Dart Throwing"
|
||||
/// <https://scholarsarchive.byu.edu/facpub/237/>
|
||||
pub fn poisson_disk_sample(
|
||||
pub(crate) fn poisson_disk_sample(
|
||||
offset: DVec2,
|
||||
width: 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.
|
||||
/// 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 {
|
||||
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 })
|
||||
}
|
||||
|
||||
pub fn top_left_corner(&self) -> DVec2 {
|
||||
fn top_left_corner(&self) -> DVec2 {
|
||||
self.0.abs()
|
||||
}
|
||||
|
||||
pub fn fully_in_shape(&self) -> bool {
|
||||
fn fully_in_shape(&self) -> bool {
|
||||
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
|
||||
active_squares: Vec<ActiveSquare>,
|
||||
/// Width and height of the squares in this level of subdivision
|
||||
@@ -214,7 +214,7 @@ pub struct ActiveListLevel {
|
||||
|
||||
impl ActiveListLevel {
|
||||
#[inline(always)]
|
||||
pub fn new(square_size: f64) -> Self {
|
||||
fn new(square_size: f64) -> Self {
|
||||
Self {
|
||||
active_squares: Vec::new(),
|
||||
square_size,
|
||||
@@ -222,7 +222,7 @@ impl ActiveListLevel {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_filled(
|
||||
fn new_filled(
|
||||
square_size: f64,
|
||||
offset: DVec2,
|
||||
width: f64,
|
||||
@@ -295,14 +295,14 @@ impl ActiveListLevel {
|
||||
|
||||
#[must_use]
|
||||
#[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);
|
||||
self.total_area = self.square_size.powi(2) * self.active_squares.len() as f64;
|
||||
targetted_square
|
||||
}
|
||||
|
||||
#[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 {
|
||||
self.active_squares.push(new_square);
|
||||
}
|
||||
@@ -310,28 +310,28 @@ impl ActiveListLevel {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn square_size(&self) -> f64 {
|
||||
fn square_size(&self) -> f64 {
|
||||
self.square_size
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn square_area(&self) -> f64 {
|
||||
fn square_area(&self) -> f64 {
|
||||
self.square_size.powi(2)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn total_area(&self) -> f64 {
|
||||
fn total_area(&self) -> f64 {
|
||||
self.total_area
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn not_empty(&self) -> bool {
|
||||
fn not_empty(&self) -> bool {
|
||||
!self.active_squares.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
#[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)
|
||||
storage_slots: [DVec2; 16],
|
||||
length: usize,
|
||||
@@ -339,19 +339,19 @@ pub struct PointsList {
|
||||
|
||||
impl PointsList {
|
||||
#[inline(always)]
|
||||
pub fn push(&mut self, point: DVec2) {
|
||||
fn push(&mut self, point: DVec2) {
|
||||
self.storage_slots[self.length] = point;
|
||||
self.length += 1;
|
||||
}
|
||||
|
||||
#[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
|
||||
self.storage_slots.into_iter().take(self.length).map(|point| (point.x.abs(), point.y.abs()).into())
|
||||
}
|
||||
|
||||
#[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
|
||||
self.storage_slots
|
||||
.into_iter()
|
||||
@@ -360,7 +360,7 @@ impl PointsList {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AccelerationGrid {
|
||||
struct AccelerationGrid {
|
||||
size: f64,
|
||||
dimension_x: usize,
|
||||
dimension_y: usize,
|
||||
@@ -369,7 +369,7 @@ pub struct AccelerationGrid {
|
||||
|
||||
impl AccelerationGrid {
|
||||
#[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_y = (height / size).ceil() as usize + 1;
|
||||
|
||||
@@ -382,7 +382,7 @@ impl AccelerationGrid {
|
||||
}
|
||||
|
||||
#[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 y = (point.y / self.size).floor() as usize;
|
||||
|
||||
@@ -408,7 +408,7 @@ impl AccelerationGrid {
|
||||
}
|
||||
|
||||
#[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 y = (point.y / self.size).floor() as usize;
|
||||
|
||||
@@ -416,7 +416,7 @@ impl AccelerationGrid {
|
||||
}
|
||||
|
||||
#[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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
#[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));
|
||||
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
|
||||
#[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.into_iter()
|
||||
.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.
|
||||
#[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)
|
||||
}
|
||||
|
||||
@@ -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))]
|
||||
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash, DynAny, node_macro::ChoiceType)]
|
||||
#[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.
|
||||
pub fn pathseg_points_vec(segment: PathSeg) -> Vec<Point> {
|
||||
fn pathseg_points_vec(segment: PathSeg) -> Vec<Point> {
|
||||
match segment {
|
||||
PathSeg::Line(line) => [line.p0, line.p1].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 }
|
||||
}
|
||||
|
||||
/// 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
|
||||
pub fn apply_transform(&mut self, affine_transform: DAffine2) {
|
||||
self.anchor = affine_transform.transform_point2(self.anchor);
|
||||
|
||||
@@ -295,7 +295,7 @@ impl Stroke {
|
||||
}
|
||||
|
||||
/// Get the effective stroke weight.
|
||||
pub fn effective_width(&self) -> f64 {
|
||||
pub(crate) fn effective_width(&self) -> f64 {
|
||||
self.weight
|
||||
* match self.align {
|
||||
StrokeAlign::Center => 1.,
|
||||
@@ -342,14 +342,6 @@ impl Stroke {
|
||||
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 {
|
||||
self.join_miter_limit as f32
|
||||
}
|
||||
@@ -359,31 +351,6 @@ impl Stroke {
|
||||
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 {
|
||||
self.weight > 0.
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ impl PointDomain {
|
||||
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);
|
||||
self.position.retain(|_| keep.next().unwrap_or_default());
|
||||
|
||||
@@ -171,16 +171,16 @@ impl PointDomain {
|
||||
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.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));
|
||||
}
|
||||
|
||||
pub fn transform(&mut self, transform: DAffine2) {
|
||||
pub(crate) fn transform(&mut self, transform: DAffine2) {
|
||||
for pos in &mut self.position {
|
||||
*pos = transform.transform_point2(*pos);
|
||||
}
|
||||
@@ -232,7 +232,7 @@ impl SegmentDomain {
|
||||
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
|
||||
.id
|
||||
.iter()
|
||||
@@ -348,7 +348,7 @@ impl SegmentDomain {
|
||||
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())
|
||||
}
|
||||
|
||||
@@ -387,7 +387,7 @@ impl SegmentDomain {
|
||||
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.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));
|
||||
@@ -395,11 +395,11 @@ impl SegmentDomain {
|
||||
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));
|
||||
}
|
||||
|
||||
pub fn transform(&mut self, transform: DAffine2) {
|
||||
pub(crate) fn transform(&mut self, transform: DAffine2) {
|
||||
for handles in &mut self.handles {
|
||||
*handles = handles.apply_transformation(|p| transform.transform_point2(p));
|
||||
}
|
||||
@@ -592,7 +592,7 @@ impl RegionDomain {
|
||||
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);
|
||||
self.segment_range.retain(|_| keep.next().unwrap_or_default());
|
||||
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.
|
||||
///
|
||||
/// 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 mut iter = keep.iter().copied();
|
||||
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)
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
|
||||
@@ -650,7 +650,7 @@ impl RegionDomain {
|
||||
&self.id
|
||||
}
|
||||
|
||||
pub fn segment_range(&self) -> &[std::ops::RangeInclusive<SegmentId>] {
|
||||
pub(crate) fn segment_range(&self) -> &[std::ops::RangeInclusive<SegmentId>] {
|
||||
&self.segment_range
|
||||
}
|
||||
|
||||
@@ -658,7 +658,7 @@ impl RegionDomain {
|
||||
&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.segment_range.extend(
|
||||
other
|
||||
@@ -669,7 +669,7 @@ impl RegionDomain {
|
||||
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.segment_range
|
||||
.iter_mut()
|
||||
@@ -696,11 +696,11 @@ pub struct 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 }
|
||||
}
|
||||
|
||||
pub fn reversed(&self) -> Self {
|
||||
fn reversed(&self) -> Self {
|
||||
Self {
|
||||
id: self.id,
|
||||
start: self.start,
|
||||
@@ -709,7 +709,7 @@ impl HalfEdge {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn normalize_direction(&self) -> Self {
|
||||
fn normalize_direction(&self) -> Self {
|
||||
if self.reverse {
|
||||
Self {
|
||||
id: self.id,
|
||||
@@ -729,14 +729,14 @@ pub struct FoundSubpath {
|
||||
}
|
||||
|
||||
impl FoundSubpath {
|
||||
pub fn endpoints(&self) -> Option<(&HalfEdge, &HalfEdge)> {
|
||||
fn endpoints(&self) -> Option<(&HalfEdge, &HalfEdge)> {
|
||||
match (self.edges.first(), self.edges.last()) {
|
||||
(Some(first), Some(last)) => Some((first, last)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push(&mut self, segment: HalfEdge) {
|
||||
fn push(&mut self, segment: HalfEdge) {
|
||||
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] }
|
||||
}
|
||||
|
||||
@@ -1108,7 +1108,7 @@ impl Vector {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn has_regions(&self) -> bool {
|
||||
fn has_regions(&self) -> bool {
|
||||
!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.
|
||||
pub struct IdMap {
|
||||
pub(crate) struct IdMap {
|
||||
pub point_offset: usize,
|
||||
pub point_map: HashMap<PointId, PointId>,
|
||||
pub segment_map: HashMap<SegmentId, SegmentId>,
|
||||
|
||||
@@ -16,7 +16,7 @@ use std::hash::Hash;
|
||||
/// Represents a procedural change to the [`PointDomain`] in [`Vector`].
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct PointModification {
|
||||
pub(crate) struct PointModification {
|
||||
add: Vec<PointId>,
|
||||
#[cfg_attr(feature = "serde", serde(serialize_with = "serialize_hashset"))]
|
||||
remove: HashSet<PointId>,
|
||||
@@ -83,7 +83,7 @@ impl PointModification {
|
||||
/// Represents a procedural change to the [`SegmentDomain`] in [`Vector`].
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct SegmentModification {
|
||||
pub(crate) struct SegmentModification {
|
||||
add: Vec<SegmentId>,
|
||||
#[cfg_attr(feature = "serde", serde(serialize_with = "serialize_hashset"))]
|
||||
remove: HashSet<SegmentId>,
|
||||
@@ -261,7 +261,7 @@ impl SegmentModification {
|
||||
/// Represents a procedural change to the [`RegionDomain`] in [`Vector`].
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct RegionModification {
|
||||
pub(crate) struct RegionModification {
|
||||
add: Vec<RegionId>,
|
||||
#[cfg_attr(feature = "serde", serde(serialize_with = "serialize_hashset"))]
|
||||
remove: HashSet<RegionId>,
|
||||
@@ -579,7 +579,7 @@ where
|
||||
}
|
||||
|
||||
/// 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
|
||||
T: Serialize + Eq + Hash + Ord,
|
||||
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.
|
||||
const CLOSE_POINT_TOLERANCE: f64 = 1e-6;
|
||||
|
||||
pub struct AppendBezpath<'a> {
|
||||
pub(crate) struct AppendBezpath<'a> {
|
||||
first_point: Option<Point>,
|
||||
last_point: Option<Point>,
|
||||
first_point_index: Option<usize>,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use super::misc::dvec2_to_point;
|
||||
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::{HandleId, ManipulatorPointId};
|
||||
use crate::vector::vector_modification::VectorExt;
|
||||
@@ -174,7 +174,7 @@ impl Vector {
|
||||
}
|
||||
|
||||
/// 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);
|
||||
self.stroke_bezpath_iter()
|
||||
.map(|mut bezpath| {
|
||||
|
||||
Reference in New Issue
Block a user