Skip to content
Open
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
99 changes: 70 additions & 29 deletions node-graph/nodes/vector/src/generator_nodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,40 +42,66 @@ impl CornerRadius for [f64; 4] {
/// Generates a circle shape with a chosen radius.
#[node_macro::node(category("Vector: Shape"))]
fn circle(
_: impl Ctx,
_primary: (),
#[unit(" px")]
#[default(50.)]
radius: f64,
_: impl Ctx,
_primary: (),
#[unit(" px")]
#[default(50.)]
radius: f64,
) -> Table<Vector> {
let radius = radius.abs();
Table::new_from_element(Vector::from_subpath(subpath::Subpath::new_ellipse(DVec2::splat(-radius), DVec2::splat(radius))))
let radius = radius.abs();
// 1. Create the vector
let mut circle = Vector::from_subpath(subpath::Subpath::new_ellipse(DVec2::splat(-radius), DVec2::splat(radius)));

// Created the collinear_manipulators so that all handles are linked, making it easier to edit the circle as a circle instead of a 4 point shape.
let ids = circle.segment_domain.ids();
let len = ids.len();
for i in 0..len {
circle.colinear_manipulators.push([
HandleId::end(ids[i]),
HandleId::primary(ids[(i + 1) % len]),
]);
}

Table::new_from_element(circle)
}

/// Generates an arc shape forming a portion of a circle which may be open, closed, or a pie slice.
#[node_macro::node(category("Vector: Shape"))]
fn arc(
_: impl Ctx,
_primary: (),
#[unit(" px")]
#[default(50.)]
radius: f64,
start_angle: Angle,
#[default(270.)]
#[range((0., 360.))]
sweep_angle: Angle,
arc_type: ArcType,
_: impl Ctx,
_primary: (),
#[unit(" px")]
#[default(50.)]
radius: f64,
start_angle: Angle,
#[default(270.)]
#[range((0., 360.))]
sweep_angle: Angle,
arc_type: ArcType,
) -> Table<Vector> {
Table::new_from_element(Vector::from_subpath(subpath::Subpath::new_arc(
radius,
start_angle / 360. * std::f64::consts::TAU,
sweep_angle / 360. * std::f64::consts::TAU,
match arc_type {
ArcType::Open => subpath::ArcType::Open,
ArcType::Closed => subpath::ArcType::Closed,
ArcType::PieSlice => subpath::ArcType::PieSlice,
},
)))
let mut arc_vector = Vector::from_subpath(subpath::Subpath::new_arc(
radius,
start_angle / 360. * std::f64::consts::TAU,
sweep_angle / 360. * std::f64::consts::TAU,
match arc_type {
ArcType::Open => subpath::ArcType::Open,
ArcType::Closed => subpath::ArcType::Closed,
ArcType::PieSlice => subpath::ArcType::PieSlice,
},
));

// 2. Link handles only if both adjacent segments are cubic beziers
let len = arc_vector.segment_domain.ids().len();
for i in 0..len.saturating_sub(1) {
if arc_vector.segment_domain.handles()[i].is_cubic() && arc_vector.segment_domain.handles()[i + 1].is_cubic() {
arc_vector.colinear_manipulators.push([
HandleId::end(arc_vector.segment_domain.ids()[i]),
HandleId::primary(arc_vector.segment_domain.ids()[i + 1])
]);
}
}

Table::new_from_element(arc_vector)
}

/// Generates a spiral shape that winds from an inner to an outer radius.
Expand All @@ -90,14 +116,29 @@ fn spiral(
#[default(25)] outer_radius: f64,
#[default(90.)] angular_resolution: f64,
) -> Table<Vector> {
Table::new_from_element(Vector::from_subpath(subpath::Subpath::new_spiral(

let mut spiral_vector = Vector::from_subpath(subpath::Subpath::new_spiral(
inner_radius,
outer_radius,
turns,
start_angle.to_radians(),
angular_resolution.to_radians(),
spiral_type,
)))
));


let len = spiral_vector.segment_domain.ids().len();
for i in 0..len.saturating_sub(1) {
// Ensure both segments meeting at the anchor point are cubic beziers
if spiral_vector.segment_domain.handles()[i].is_cubic() && spiral_vector.segment_domain.handles()[i + 1].is_cubic() {
spiral_vector.colinear_manipulators.push([
HandleId::end(spiral_vector.segment_domain.ids()[i]),
HandleId::primary(spiral_vector.segment_domain.ids()[i + 1])
]);
}
}

Table::new_from_element(spiral_vector)
}

/// Generates an ellipse shape (an oval or stretched circle) with the chosen radii.
Expand Down