mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-28 17:38:12 +08:00
Convert cut_path, separate_subpaths, and path_is_closed to fold kernels
This commit is contained in:
@@ -1602,8 +1602,7 @@ fn solidify_stroke_vector_extent(content: ListIn<'_, Vector>, level: LevelIn) ->
|
|||||||
|
|
||||||
pub use _solidify_stroke_vector_mod::solidify_stroke_vector_entries;
|
pub use _solidify_stroke_vector_mod::solidify_stroke_vector_entries;
|
||||||
|
|
||||||
#[node_macro::node(category("Vector: Modifier"), path(core_types::vector))]
|
fn separate_subpaths_core(content: List<Vector>) -> List<Vector> {
|
||||||
fn separate_subpaths(_: impl Ctx, content: List<Vector>) -> List<Vector> {
|
|
||||||
content
|
content
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flat_map(|row| {
|
.flat_map(|row| {
|
||||||
@@ -1632,22 +1631,63 @@ fn separate_subpaths(_: impl Ctx, content: List<Vector>) -> List<Vector> {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Splits each vector element into one element per subpath, keeping the source element's attributes on every split-off lane.
|
||||||
|
#[node_macro::node(category("Vector: Modifier"), path(core_types::vector), extent(separate_subpaths_extent))]
|
||||||
|
fn separate_subpaths<'e>(
|
||||||
|
ctx: impl Ctx + ExtractArena<'e> + ExtractIndex + InjectIndex + Copy,
|
||||||
|
content: IList<Vector>,
|
||||||
|
) -> Result<
|
||||||
|
IList<(
|
||||||
|
Vector,
|
||||||
|
Attr<'e, TransformAttr>,
|
||||||
|
Attr<'e, Fill>,
|
||||||
|
Attr<'e, StrokeAttr>,
|
||||||
|
Attr<'e, BlendModeAttr>,
|
||||||
|
Attr<'e, Opacity>,
|
||||||
|
Attr<'e, OpacityFill>,
|
||||||
|
Attr<'e, ClippingMask>,
|
||||||
|
Attr<'e, EditorLayerPath>,
|
||||||
|
Attr<'e, EditorMergedLayers>,
|
||||||
|
)>,
|
||||||
|
Interrupt,
|
||||||
|
> {
|
||||||
|
let output = separate_subpaths_core(legacy_vector_list_of(content));
|
||||||
|
emit_legacy_lane(ctx.arena(), output, ctx.innermost_index() as usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A row splits into one lane per subpath, so the count depends on the
|
||||||
|
/// content: the level reports the subject's count as a lower bound and
|
||||||
|
/// consumers drain to the past-end signal.
|
||||||
|
fn separate_subpaths_extent(content: ListIn<'_, Vector>, level: LevelIn) -> GPoll<Extent> {
|
||||||
|
match level.top() {
|
||||||
|
true => content.total().map(|total| {
|
||||||
|
Extent::AtLeast(match total {
|
||||||
|
Extent::Exactly(count) | Extent::AtLeast(count) => count,
|
||||||
|
Extent::Free => 0,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
false => GPoll::Final(Extent::Exactly(1)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Determines if the subpath at the given index (across all vector element subpaths) is closed, meaning its ends are connected together forming a loop.
|
/// Determines if the subpath at the given index (across all vector element subpaths) is closed, meaning its ends are connected together forming a loop.
|
||||||
#[node_macro::node(name("Path is Closed"), category("Vector: Measure"), path(core_types::vector))]
|
#[node_macro::node(name("Path is Closed"), category("Vector: Measure"), path(core_types::vector))]
|
||||||
fn path_is_closed(
|
fn path_is_closed(
|
||||||
_: impl Ctx,
|
_: impl Ctx + ExtractIndex + InjectIndex + Copy,
|
||||||
/// The vector content whose subpaths are inspected.
|
/// The vector content whose subpaths are inspected.
|
||||||
content: List<Vector>,
|
content: IList<Vector>,
|
||||||
/// The index of the subpath to check, counting across subpaths in all vector elements.
|
/// The index of the subpath to check, counting across subpaths in all vector elements.
|
||||||
index: f64,
|
index: f64,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
content
|
(0..content.len())
|
||||||
.iter_element_values()
|
.flat_map(|row| content.element_ref(row).build_stroke_path_iter().map(|(_, closed)| closed))
|
||||||
.flat_map(|vector| vector.build_stroke_path_iter().map(|(_, closed)| closed))
|
|
||||||
.nth(index.max(0.) as usize)
|
.nth(index.max(0.) as usize)
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Converts with the write-attribute family: the record form needs a lazy
|
||||||
|
// value input on a record node, which the macro does not accept yet, and it
|
||||||
|
// shares that family's per-item index convention.
|
||||||
#[node_macro::node(category("Vector"), path(graphene_core::vector))]
|
#[node_macro::node(category("Vector"), path(graphene_core::vector))]
|
||||||
fn map_points(ctx: impl Ctx + DeriveCtx, content: List<Vector>, mapped: impl Node<Context<'_>, Output = DVec2>) -> Result<List<Vector>, Interrupt> {
|
fn map_points(ctx: impl Ctx + DeriveCtx, content: List<Vector>, mapped: impl Node<Context<'_>, Output = DVec2>) -> Result<List<Vector>, Interrupt> {
|
||||||
let spilled = ctx.index_head();
|
let spilled = ctx.index_head();
|
||||||
@@ -2027,21 +2067,22 @@ fn decimate(
|
|||||||
(result, Attr(transform_attribute))
|
(result, Attr(transform_attribute))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cuts a path at a given progression from 0 to 1 along the path, creating two new subpaths from the original one (if the path is initially open) or one open subpath (if the path is initially closed).
|
/// The materialized vector level as the legacy list the cross-lane cores walk.
|
||||||
///
|
fn legacy_vector_list_of(content: core_types::node::List<'_, Vector>) -> List<Vector> {
|
||||||
/// If multiple subpaths make up the path, the whole number part of the progression value selects the subpath and the decimal part determines the position along it.
|
// SAFETY: a materialized input's frames are arena-resident.
|
||||||
#[node_macro::node(category("Vector: Modifier"), path(graphene_core::vector))]
|
let item = unsafe { core_types::record::GroupItem::from_resident(content.batch()) };
|
||||||
fn cut_path(
|
graphic_types::graphic::run_to_render_list::<Vector>(&item).expect("the run holds the row's element type")
|
||||||
_: impl Ctx,
|
}
|
||||||
/// The path to insert a cut into.
|
|
||||||
mut content: List<Vector>,
|
/// A count-preserving cross-lane node's extent: the subject's own counts.
|
||||||
/// The factor from the start to the end of the path, 0–1 for one subpath, 1–2 for a second subpath, and so on.
|
fn subject_counts_extent(content: ListIn<'_, Vector>, level: LevelIn) -> GPoll<Extent> {
|
||||||
progression: Progression,
|
match level.top() {
|
||||||
/// Swap the direction of the path.
|
true => content.total(),
|
||||||
reverse: bool,
|
false => GPoll::Final(Extent::Exactly(1)),
|
||||||
/// Traverse the path using each segment's Bézier curve parameterization instead of the Euclidean distance. Faster to compute but doesn't respect actual distances.
|
}
|
||||||
parameterized_distance: bool,
|
}
|
||||||
) -> List<Vector> {
|
|
||||||
|
fn cut_path_core(mut content: List<Vector>, progression: f64, reverse: bool, parameterized_distance: bool) -> List<Vector> {
|
||||||
let euclidian = !parameterized_distance;
|
let euclidian = !parameterized_distance;
|
||||||
|
|
||||||
let bezpaths = content
|
let bezpaths = content
|
||||||
@@ -2080,6 +2121,43 @@ fn cut_path(
|
|||||||
content
|
content
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Cuts a path at a given progression from 0 to 1 along the path, creating two new subpaths from the original one (if the path is initially open) or one open subpath (if the path is initially closed).
|
||||||
|
///
|
||||||
|
/// If multiple subpaths make up the path, the whole number part of the progression value selects the subpath and the decimal part determines the position along it.
|
||||||
|
#[node_macro::node(category("Vector: Modifier"), path(graphene_core::vector), extent(cut_path_extent))]
|
||||||
|
fn cut_path<'e>(
|
||||||
|
ctx: impl Ctx + ExtractArena<'e> + ExtractIndex + InjectIndex + Copy,
|
||||||
|
/// The path to insert a cut into.
|
||||||
|
content: IList<Vector>,
|
||||||
|
/// The factor from the start to the end of the path, 0–1 for one subpath, 1–2 for a second subpath, and so on.
|
||||||
|
progression: Progression,
|
||||||
|
/// Swap the direction of the path.
|
||||||
|
reverse: bool,
|
||||||
|
/// Traverse the path using each segment's Bézier curve parameterization instead of the Euclidean distance. Faster to compute but doesn't respect actual distances.
|
||||||
|
parameterized_distance: bool,
|
||||||
|
) -> Result<
|
||||||
|
IList<(
|
||||||
|
Vector,
|
||||||
|
Attr<'e, TransformAttr>,
|
||||||
|
Attr<'e, Fill>,
|
||||||
|
Attr<'e, StrokeAttr>,
|
||||||
|
Attr<'e, BlendModeAttr>,
|
||||||
|
Attr<'e, Opacity>,
|
||||||
|
Attr<'e, OpacityFill>,
|
||||||
|
Attr<'e, ClippingMask>,
|
||||||
|
Attr<'e, EditorLayerPath>,
|
||||||
|
Attr<'e, EditorMergedLayers>,
|
||||||
|
)>,
|
||||||
|
Interrupt,
|
||||||
|
> {
|
||||||
|
let output = cut_path_core(legacy_vector_list_of(content), progression, reverse, parameterized_distance);
|
||||||
|
emit_legacy_lane(ctx.arena(), output, ctx.innermost_index() as usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cut_path_extent(content: ListIn<'_, Vector>, _progression: ValueIn<'_, f64>, _reverse: ValueIn<'_, bool>, _parameterized_distance: ValueIn<'_, bool>, level: LevelIn) -> GPoll<Extent> {
|
||||||
|
subject_counts_extent(content, level)
|
||||||
|
}
|
||||||
|
|
||||||
/// Cuts path segments into separate disconnected pieces where each is a distinct subpath.
|
/// Cuts path segments into separate disconnected pieces where each is a distinct subpath.
|
||||||
#[node_macro::node(category("Vector: Modifier"), path(core_types::vector))]
|
#[node_macro::node(category("Vector: Modifier"), path(core_types::vector))]
|
||||||
fn cut_segments(_: impl Ctx, mut content: Vector) -> Vector {
|
fn cut_segments(_: impl Ctx, mut content: Vector) -> Vector {
|
||||||
|
|||||||
Reference in New Issue
Block a user