Sample Points node: employ caching and deduplication (#1546)
Sample Points node: split out expensive computation so it can be deduped
This commit is contained in:
parent
93aa10a76f
commit
121c1d2b9d
File diff suppressed because one or more lines are too long
|
|
@ -2643,6 +2643,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
name: "Copy to Points",
|
name: "Copy to Points",
|
||||||
category: "Vector",
|
category: "Vector",
|
||||||
|
// TODO: Wrap this implementation with a document node that has a cache node so the output is cached?
|
||||||
implementation: NodeImplementation::proto("graphene_core::vector::CopyToPoints<_, _>"),
|
implementation: NodeImplementation::proto("graphene_core::vector::CopyToPoints<_, _>"),
|
||||||
manual_composition: Some(concrete!(Footprint)),
|
manual_composition: Some(concrete!(Footprint)),
|
||||||
inputs: vec![
|
inputs: vec![
|
||||||
|
|
@ -2656,7 +2657,44 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
name: "Sample Points",
|
name: "Sample Points",
|
||||||
category: "Vector",
|
category: "Vector",
|
||||||
implementation: NodeImplementation::proto("graphene_core::vector::SamplePoints<_, _, _, _>"),
|
implementation: NodeImplementation::DocumentNode(NodeNetwork {
|
||||||
|
inputs: vec![NodeId(0), NodeId(2), NodeId(2), NodeId(2), NodeId(2)], // First is given to Identity, the rest are given to Sample Points
|
||||||
|
outputs: vec![NodeOutput::new(NodeId(2), 0)], // Taken from output 0 of Sample Points
|
||||||
|
nodes: [
|
||||||
|
DocumentNode {
|
||||||
|
name: "Identity".to_string(),
|
||||||
|
inputs: vec![NodeInput::Network(concrete!(graphene_core::vector::VectorData))], // From the document node's parameters
|
||||||
|
implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_core::ops::IdentityNode")),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
DocumentNode {
|
||||||
|
name: "Lengths of Segments of Subpaths".to_string(),
|
||||||
|
inputs: vec![NodeInput::node(NodeId(0), 0)], // From output 0 of Identity
|
||||||
|
implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_core::vector::LengthsOfSegmentsOfSubpaths")),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
DocumentNode {
|
||||||
|
name: "Sample Points".to_string(),
|
||||||
|
inputs: vec![
|
||||||
|
NodeInput::node(NodeId(0), 0), // From output 0 of Identity
|
||||||
|
NodeInput::Network(concrete!(f32)), // From the document node's parameters
|
||||||
|
NodeInput::Network(concrete!(f32)), // From the document node's parameters
|
||||||
|
NodeInput::Network(concrete!(f32)), // From the document node's parameters
|
||||||
|
NodeInput::Network(concrete!(bool)), // From the document node's parameters
|
||||||
|
NodeInput::node(NodeId(1), 0), // From output 0 of Lengths of Segments of Subpaths
|
||||||
|
],
|
||||||
|
implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_core::vector::SamplePoints<_, _, _, _, _, _>")),
|
||||||
|
manual_composition: Some(concrete!(Footprint)),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
// TODO: Add a cache node here?
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(id, node)| (NodeId(id as u64), node))
|
||||||
|
.collect(),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
inputs: vec![
|
inputs: vec![
|
||||||
DocumentInputType::value("Vector Data", TaggedValue::VectorData(graphene_core::vector::VectorData::empty()), true),
|
DocumentInputType::value("Vector Data", TaggedValue::VectorData(graphene_core::vector::VectorData::empty()), true),
|
||||||
DocumentInputType::value("Spacing", TaggedValue::F32(100.), false),
|
DocumentInputType::value("Spacing", TaggedValue::F32(100.), false),
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ where
|
||||||
for<'a> <CachedNode as Node<'a, ()>>::Output: core::future::Future<Output = T> + 'a,
|
for<'a> <CachedNode as Node<'a, ()>>::Output: core::future::Future<Output = T> + 'a,
|
||||||
{
|
{
|
||||||
// TODO: This should return a reference to the cached cached_value
|
// TODO: This should return a reference to the cached cached_value
|
||||||
// but that requires a lot of lifetime magic <- This was suggested by copilot but is pretty acurate xD
|
// but that requires a lot of lifetime magic <- This was suggested by copilot but is pretty accurate xD
|
||||||
type Output = Pin<Box<dyn Future<Output = T> + 'i>>;
|
type Output = Pin<Box<dyn Future<Output = T> + 'i>>;
|
||||||
fn eval(&'i self, input: ()) -> Pin<Box<dyn Future<Output = T> + 'i>> {
|
fn eval(&'i self, input: ()) -> Pin<Box<dyn Future<Output = T> + 'i>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
|
|
|
||||||
|
|
@ -203,27 +203,39 @@ async fn copy_to_points<I: GraphicElementRendered + Default + ConcatElement + Tr
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct SamplePoints<Spacing, StartOffset, StopOffset, AdaptiveSpacing> {
|
pub struct SamplePoints<VectorData, Spacing, StartOffset, StopOffset, AdaptiveSpacing, LengthsOfSegmentsOfSubpaths> {
|
||||||
|
vector_data: VectorData,
|
||||||
spacing: Spacing,
|
spacing: Spacing,
|
||||||
start_offset: StartOffset,
|
start_offset: StartOffset,
|
||||||
stop_offset: StopOffset,
|
stop_offset: StopOffset,
|
||||||
adaptive_spacing: AdaptiveSpacing,
|
adaptive_spacing: AdaptiveSpacing,
|
||||||
|
lengths_of_segments_of_subpaths: LengthsOfSegmentsOfSubpaths,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[node_macro::node_fn(SamplePoints)]
|
#[node_macro::node_fn(SamplePoints)]
|
||||||
fn sample_points(mut vector_data: VectorData, spacing: f32, start_offset: f32, stop_offset: f32, adaptive_spacing: bool) -> VectorData {
|
async fn sample_points<FV: Future<Output = VectorData>, FL: Future<Output = Vec<Vec<f64>>>>(
|
||||||
|
footprint: Footprint,
|
||||||
|
mut vector_data: impl Node<Footprint, Output = FV>,
|
||||||
|
spacing: f32,
|
||||||
|
start_offset: f32,
|
||||||
|
stop_offset: f32,
|
||||||
|
adaptive_spacing: bool,
|
||||||
|
lengths_of_segments_of_subpaths: impl Node<Footprint, Output = FL>,
|
||||||
|
) -> VectorData {
|
||||||
|
let mut vector_data = self.vector_data.eval(footprint).await;
|
||||||
|
let lengths_of_segments_of_subpaths = self.lengths_of_segments_of_subpaths.eval(footprint).await;
|
||||||
let spacing = spacing as f64;
|
let spacing = spacing as f64;
|
||||||
let start_offset = start_offset as f64;
|
let start_offset = start_offset as f64;
|
||||||
let stop_offset = stop_offset as f64;
|
let stop_offset = stop_offset as f64;
|
||||||
|
|
||||||
for subpath in &mut vector_data.subpaths {
|
for (index, subpath) in &mut vector_data.subpaths.iter_mut().enumerate() {
|
||||||
if subpath.is_empty() || !spacing.is_finite() || spacing <= 0. {
|
if subpath.is_empty() || !spacing.is_finite() || spacing <= 0. {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
subpath.apply_transform(vector_data.transform);
|
subpath.apply_transform(vector_data.transform);
|
||||||
|
|
||||||
let segment_lengths = subpath.iter().map(|bezier| bezier.length(None)).collect::<Vec<f64>>();
|
let segment_lengths = &lengths_of_segments_of_subpaths[index];
|
||||||
let total_length: f64 = segment_lengths.iter().sum();
|
let total_length: f64 = segment_lengths.iter().sum();
|
||||||
|
|
||||||
let mut used_length = total_length - start_offset - stop_offset;
|
let mut used_length = total_length - start_offset - stop_offset;
|
||||||
|
|
@ -265,7 +277,22 @@ fn sample_points(mut vector_data: VectorData, spacing: f32, start_offset: f32, s
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct SplinesFromPointsNode {}
|
pub struct LengthsOfSegmentsOfSubpaths;
|
||||||
|
|
||||||
|
#[node_macro::node_fn(LengthsOfSegmentsOfSubpaths)]
|
||||||
|
fn lengths_of_segments_of_subpaths(mut vector_data: VectorData) -> Vec<Vec<f64>> {
|
||||||
|
vector_data
|
||||||
|
.subpaths
|
||||||
|
.iter_mut()
|
||||||
|
.map(|subpath| {
|
||||||
|
subpath.apply_transform(vector_data.transform);
|
||||||
|
subpath.iter().map(|bezier| bezier.length(None)).collect()
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct SplinesFromPointsNode;
|
||||||
|
|
||||||
#[node_macro::node_fn(SplinesFromPointsNode)]
|
#[node_macro::node_fn(SplinesFromPointsNode)]
|
||||||
fn splines_from_points(mut vector_data: VectorData) -> VectorData {
|
fn splines_from_points(mut vector_data: VectorData) -> VectorData {
|
||||||
|
|
|
||||||
|
|
@ -734,7 +734,8 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
||||||
register_node!(graphene_std::raster::MandelbrotNode, input: Footprint, params: []),
|
register_node!(graphene_std::raster::MandelbrotNode, input: Footprint, params: []),
|
||||||
async_node!(graphene_core::vector::CopyToPoints<_, _>, input: Footprint, output: VectorData, fn_params: [Footprint => VectorData, Footprint => VectorData]),
|
async_node!(graphene_core::vector::CopyToPoints<_, _>, input: Footprint, output: VectorData, fn_params: [Footprint => VectorData, Footprint => VectorData]),
|
||||||
async_node!(graphene_core::vector::CopyToPoints<_, _>, input: Footprint, output: GraphicGroup, fn_params: [Footprint => VectorData, Footprint => GraphicGroup]),
|
async_node!(graphene_core::vector::CopyToPoints<_, _>, input: Footprint, output: GraphicGroup, fn_params: [Footprint => VectorData, Footprint => GraphicGroup]),
|
||||||
register_node!(graphene_core::vector::SamplePoints<_, _, _, _>, input: VectorData, params: [f32, f32, f32, bool]),
|
async_node!(graphene_core::vector::SamplePoints<_, _, _, _, _, _>, input: Footprint, output: VectorData, fn_params: [Footprint => VectorData, () => f32, () => f32, () => f32, () => bool, Footprint => Vec<Vec<f64>>]),
|
||||||
|
register_node!(graphene_core::vector::LengthsOfSegmentsOfSubpaths, input: VectorData, params: []),
|
||||||
register_node!(graphene_core::vector::SplinesFromPointsNode, input: VectorData, params: []),
|
register_node!(graphene_core::vector::SplinesFromPointsNode, input: VectorData, params: []),
|
||||||
register_node!(graphene_core::vector::generator_nodes::CircleGenerator<_>, input: (), params: [f32]),
|
register_node!(graphene_core::vector::generator_nodes::CircleGenerator<_>, input: (), params: [f32]),
|
||||||
register_node!(graphene_core::vector::generator_nodes::EllipseGenerator<_, _>, input: (), params: [f32, f32]),
|
register_node!(graphene_core::vector::generator_nodes::EllipseGenerator<_, _>, input: (), params: [f32, f32]),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue