Skip to content

Create a Radio button for sample by count option #2727

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2274,7 +2274,8 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
NodeInput::network(concrete!(f64), 2), // From the document node's parameters
NodeInput::network(concrete!(f64), 3), // From the document node's parameters
NodeInput::network(concrete!(bool), 4), // From the document node's parameters
NodeInput::node(NodeId(0), 0), // From output 0 of SubpathSegmentLengthsNode
NodeInput::network(concrete!(bool), 5),
NodeInput::node(NodeId(0), 0), // From output 0 of SubpathSegmentLengthsNode
],
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::vector::SamplePointsNode")),
manual_composition: Some(generic!(T)),
Expand Down Expand Up @@ -2311,6 +2312,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
NodeInput::value(TaggedValue::F64(0.), false),
NodeInput::value(TaggedValue::F64(0.), false),
NodeInput::value(TaggedValue::Bool(false), false),
NodeInput::value(TaggedValue::Bool(false), false),
],
..Default::default()
},
Expand Down Expand Up @@ -2397,6 +2399,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
}),
),
Into::<PropertiesRow>::into(("Adaptive Spacing", "Round 'Spacing' to a nearby value that divides into the path length evenly.")),
Into::<PropertiesRow>::into(("Count Points", "Calculate the distance between points based on the number provided.")),
],
output_names: vec!["Vector".to_string()],
..Default::default()
Expand Down
24 changes: 14 additions & 10 deletions node-graph/gcore/src/vector/algorithms/bezpath_algorithms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub fn tangent_on_bezpath(bezpath: &BezPath, t: f64, euclidian: bool, segments_l
}
}

pub fn sample_points_on_bezpath(bezpath: BezPath, spacing: f64, start_offset: f64, stop_offset: f64, adaptive_spacing: bool, segments_length: &[f64]) -> Option<BezPath> {
pub fn sample_points_on_bezpath(bezpath: BezPath, spacing: f64, start_offset: f64, stop_offset: f64, adaptive_spacing: bool, count_points: bool, segments_length: &[f64]) -> Option<BezPath> {
let mut sample_bezpath = BezPath::new();

let was_closed = matches!(bezpath.elements().last(), Some(PathEl::ClosePath));
Expand All @@ -34,17 +34,21 @@ pub fn sample_points_on_bezpath(bezpath: BezPath, spacing: f64, start_offset: f6
}

// Determine the number of points to generate along the path.
let sample_count = if adaptive_spacing {
// Calculate point count to evenly distribute points while covering the entire path.
// With adaptive spacing, we widen or narrow the points as necessary to ensure the last point is always at the end of the path.
(used_length / spacing).round()
let sample_count = if count_points {
spacing
} else {
// Calculate point count based on exact spacing, which may not cover the entire path.
if adaptive_spacing {
// Calculate point count to evenly distribute points while covering the entire path.
// With adaptive spacing, we widen or narrow the points as necessary to ensure the last point is always at the end of the path.
(used_length / spacing).round()
} else {
// Calculate point count based on exact spacing, which may not cover the entire path.

// Without adaptive spacing, we just evenly space the points at the exact specified spacing, usually falling short before the end of the path.
let count = (used_length / spacing + f64::EPSILON).floor();
used_length -= used_length % spacing;
count
// Without adaptive spacing, we just evenly space the points at the exact specified spacing, usually falling short before the end of the path.
let count = (used_length / spacing + f64::EPSILON).floor();
used_length -= used_length % spacing;
count
}
};

// Skip if there are no points to generate.
Expand Down
8 changes: 4 additions & 4 deletions node-graph/gcore/src/vector/vector_nodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1247,7 +1247,7 @@ where
}

#[node_macro::node(category(""), path(graphene_core::vector))]
async fn sample_points(_: impl Ctx, vector_data: VectorDataTable, spacing: f64, start_offset: f64, stop_offset: f64, adaptive_spacing: bool, subpath_segment_lengths: Vec<f64>) -> VectorDataTable {
async fn sample_points(_: impl Ctx, vector_data: VectorDataTable, spacing: f64, start_offset: f64, stop_offset: f64, adaptive_spacing: bool, count_point : bool, subpath_segment_lengths: Vec<f64>) -> VectorDataTable {
// Limit the smallest spacing to something sensible to avoid freezing the application.
let spacing = spacing.max(0.01);

Expand Down Expand Up @@ -1285,7 +1285,7 @@ async fn sample_points(_: impl Ctx, vector_data: VectorDataTable, spacing: f64,
// Increment the segment index by the number of segments in the current bezpath to calculate the next bezpath segment's length.
next_segment_index += segment_count;

let Some(mut sample_bezpath) = sample_points_on_bezpath(bezpath, spacing, start_offset, stop_offset, adaptive_spacing, current_bezpath_segments_length) else {
let Some(mut sample_bezpath) = sample_points_on_bezpath(bezpath, spacing, start_offset, stop_offset, adaptive_spacing, count_point, current_bezpath_segments_length) else {
continue;
};

Expand Down Expand Up @@ -2049,7 +2049,7 @@ mod test {
#[tokio::test]
async fn sample_points() {
let path = Subpath::from_bezier(&Bezier::from_cubic_dvec2(DVec2::ZERO, DVec2::ZERO, DVec2::X * 100., DVec2::X * 100.));
let sample_points = super::sample_points(Footprint::default(), vector_node(path), 30., 0., 0., false, vec![100.]).await;
let sample_points = super::sample_points(Footprint::default(), vector_node(path), 30., 0., 0., false, false, vec![100.]).await;
let sample_points = sample_points.instance_ref_iter().next().unwrap().instance;
assert_eq!(sample_points.point_domain.positions().len(), 4);
for (pos, expected) in sample_points.point_domain.positions().iter().zip([DVec2::X * 0., DVec2::X * 30., DVec2::X * 60., DVec2::X * 90.]) {
Expand All @@ -2059,7 +2059,7 @@ mod test {
#[tokio::test]
async fn adaptive_spacing() {
let path = Subpath::from_bezier(&Bezier::from_cubic_dvec2(DVec2::ZERO, DVec2::ZERO, DVec2::X * 100., DVec2::X * 100.));
let sample_points = super::sample_points(Footprint::default(), vector_node(path), 18., 45., 10., true, vec![100.]).await;
let sample_points = super::sample_points(Footprint::default(), vector_node(path), 18., 45., 10., true, false, vec![100.]).await;
let sample_points = sample_points.instance_ref_iter().next().unwrap().instance;
assert_eq!(sample_points.point_domain.positions().len(), 4);
for (pos, expected) in sample_points.point_domain.positions().iter().zip([DVec2::X * 45., DVec2::X * 60., DVec2::X * 75., DVec2::X * 90.]) {
Expand Down