New nodes: shape/curve primitives (#1389)

* Add new Primitive Shape/Curve Nodes

* Elipse Node and Debug

* N-input Spline node

* Debuging

* Debug

* fmt

* remov debug

* Changes from code review

* Debug: Empty Spline Input

* Changes from code review

* Fix spelling of ellipse

* Rename polygon to regular polygon

---------

Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
Ezbaze
2023-08-27 22:22:09 +01:00
committed by GitHub
parent 9d27bf49cf
commit 226b96260c
7 changed files with 263 additions and 15 deletions

View File

@@ -1915,11 +1915,90 @@ fn static_nodes() -> Vec<DocumentNodeType> {
},
(*IMAGINATE_NODE).clone(),
DocumentNodeType {
name: "Unit Circle Generator",
name: "Circle",
category: "Vector",
identifier: NodeImplementation::proto("graphene_core::vector::generator_nodes::UnitCircleGenerator"),
inputs: vec![DocumentInputType::none()],
identifier: NodeImplementation::proto("graphene_core::vector::generator_nodes::CircleGenerator<_>"),
inputs: vec![DocumentInputType::none(), DocumentInputType::value("Radius", TaggedValue::F32(50.), false)],
outputs: vec![DocumentOutputType::new("Vector", FrontendGraphDataType::Subpath)],
properties: node_properties::circle_properties,
..Default::default()
},
DocumentNodeType {
name: "Ellipse",
category: "Vector",
identifier: NodeImplementation::proto("graphene_core::vector::generator_nodes::EllipseGenerator<_, _>"),
inputs: vec![
DocumentInputType::none(),
DocumentInputType::value("Radius X", TaggedValue::F32(50.), false),
DocumentInputType::value("Radius Y", TaggedValue::F32(25.), false),
],
outputs: vec![DocumentOutputType::new("Vector", FrontendGraphDataType::Subpath)],
properties: node_properties::ellipse_properties,
..Default::default()
},
DocumentNodeType {
name: "Rectangle",
category: "Vector",
identifier: NodeImplementation::proto("graphene_core::vector::generator_nodes::RectangleGenerator<_, _>"),
inputs: vec![
DocumentInputType::none(),
DocumentInputType::value("Size X", TaggedValue::F32(100.), false),
DocumentInputType::value("Size Y", TaggedValue::F32(100.), false),
],
outputs: vec![DocumentOutputType::new("Vector", FrontendGraphDataType::Subpath)],
properties: node_properties::rectangle_properties,
..Default::default()
},
DocumentNodeType {
name: "Regular Polygon",
category: "Vector",
identifier: NodeImplementation::proto("graphene_core::vector::generator_nodes::RegularPolygonGenerator<_, _>"),
inputs: vec![
DocumentInputType::none(),
DocumentInputType::value("Sides", TaggedValue::U32(6), false),
DocumentInputType::value("Radius", TaggedValue::F32(50.), false),
],
outputs: vec![DocumentOutputType::new("Vector", FrontendGraphDataType::Subpath)],
properties: node_properties::regular_polygon_properties,
..Default::default()
},
DocumentNodeType {
name: "Star",
category: "Vector",
identifier: NodeImplementation::proto("graphene_core::vector::generator_nodes::StarGenerator<_, _, _>"),
inputs: vec![
DocumentInputType::none(),
DocumentInputType::value("Sides", TaggedValue::U32(5), false),
DocumentInputType::value("Radius", TaggedValue::F32(50.), false),
DocumentInputType::value("Inner Radius", TaggedValue::F32(25.), false),
],
outputs: vec![DocumentOutputType::new("Vector", FrontendGraphDataType::Subpath)],
properties: node_properties::star_properties,
..Default::default()
},
DocumentNodeType {
name: "Line",
category: "Vector",
identifier: NodeImplementation::proto("graphene_core::vector::generator_nodes::LineGenerator<_, _>"),
inputs: vec![
DocumentInputType::none(),
DocumentInputType::value("Start", TaggedValue::DVec2(DVec2::new(0., -50.)), false),
DocumentInputType::value("End", TaggedValue::DVec2(DVec2::new(0., 50.)), false),
],
outputs: vec![DocumentOutputType::new("Vector", FrontendGraphDataType::Subpath)],
properties: node_properties::line_properties,
..Default::default()
},
DocumentNodeType {
name: "Spline",
category: "Vector",
identifier: NodeImplementation::proto("graphene_core::vector::generator_nodes::SplineGenerator<_>"),
inputs: vec![
DocumentInputType::none(),
DocumentInputType::value("Points", TaggedValue::VecDVec2(vec![DVec2::new(0., -50.), DVec2::new(25., 0.), DVec2::new(0., 50.)]), false),
],
outputs: vec![DocumentOutputType::new("Vector", FrontendGraphDataType::Subpath)],
properties: node_properties::spline_properties,
..Default::default()
},
DocumentNodeType {

View File

@@ -217,6 +217,36 @@ fn vec_f32_input(document_node: &DocumentNode, node_id: NodeId, index: usize, na
}
widgets
}
fn vec_dvec2_input(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, text_props: TextInput, blank_assist: bool) -> Vec<WidgetHolder> {
let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::Color, blank_assist);
let from_string = |string: &str| {
string
.split(|c: char| !c.is_alphanumeric() && !matches!(c, '.' | '+' | '-'))
.filter(|x| !x.is_empty())
.map(|x| x.parse::<f64>().ok())
.collect::<Option<Vec<_>>>()
.map(|numbers| numbers.chunks_exact(2).map(|vals| DVec2::new(vals[0], vals[1])).collect())
.map(TaggedValue::VecDVec2)
};
if let NodeInput::Value {
tagged_value: TaggedValue::VecDVec2(x),
exposed: false,
} = &document_node.inputs[index]
{
widgets.extend_from_slice(&[
Separator::new(SeparatorType::Unrelated).widget_holder(),
text_props
.value(x.iter().map(|v| format!("({}, {})", v.x, v.y)).collect::<Vec<_>>().join(", "))
.on_update(optionally_update_value(move |x: &TextInput| from_string(&x.value), node_id, index))
.widget_holder(),
])
}
widgets
}
fn font_inputs(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, blank_assist: bool) -> (Vec<WidgetHolder>, Option<Vec<WidgetHolder>>) {
let mut first_widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist);
let mut second_widgets = None;
@@ -1139,6 +1169,55 @@ pub fn modulo_properties(document_node: &DocumentNode, node_id: NodeId, _context
vec![operand("Modulo", 1)]
}
pub fn circle_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
vec![LayoutGroup::Row {
widgets: number_widget(document_node, node_id, 1, "Radius", NumberInput::default(), true),
}]
}
pub fn ellipse_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let operand = |name: &str, index| {
let widgets = number_widget(document_node, node_id, index, name, NumberInput::default(), true);
LayoutGroup::Row { widgets }
};
vec![operand("Radius X", 1), operand("Radius Y", 2)]
}
pub fn rectangle_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let operand = |name: &str, index| {
let widgets = number_widget(document_node, node_id, index, name, NumberInput::default(), true);
LayoutGroup::Row { widgets }
};
vec![operand("Size X", 1), operand("Size Y", 2)]
}
pub fn regular_polygon_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let points = number_widget(document_node, node_id, 1, "Points", NumberInput::default().min(3.), true);
let radius = number_widget(document_node, node_id, 2, "Radius", NumberInput::default(), true);
vec![LayoutGroup::Row { widgets: points }, LayoutGroup::Row { widgets: radius }]
}
pub fn star_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let points = number_widget(document_node, node_id, 1, "Points", NumberInput::default().min(2.), true);
let radius = number_widget(document_node, node_id, 2, "Radius", NumberInput::default(), true);
let inner_radius = number_widget(document_node, node_id, 3, "Inner Radius", NumberInput::default(), true);
vec![LayoutGroup::Row { widgets: points }, LayoutGroup::Row { widgets: radius }, LayoutGroup::Row { widgets: inner_radius }]
}
pub fn line_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let operand = |name: &str, index| vec2_widget(document_node, node_id, index, name, "X", "Y", "px", add_blank_assist);
vec![operand("Start", 1), operand("End", 2)]
}
pub fn spline_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
vec![LayoutGroup::Row {
widgets: vec_dvec2_input(document_node, node_id, 1, "Points", TextInput::default().centered(true), true),
}]
}
pub fn transform_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let translation_assist = |widgets: &mut Vec<WidgetHolder>| {
let pivot_index = 5;

View File

@@ -265,7 +265,7 @@ impl Fsm for PolygonToolFsmState {
let subpath = match tool_options.primitive_shape_type {
PrimitiveShapeType::Polygon => bezier_rs::Subpath::new_regular_polygon(DVec2::ZERO, tool_options.vertices as u64, 1.),
PrimitiveShapeType::Star => bezier_rs::Subpath::new_regular_star_polygon(DVec2::ZERO, tool_options.vertices as u64, 1., 0.5),
PrimitiveShapeType::Star => bezier_rs::Subpath::new_star_polygon(DVec2::ZERO, tool_options.vertices as u64, 1., 0.5),
};
graph_modification_utils::new_vector_layer(vec![subpath], layer_path.clone(), responses);