Skip to content
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 @@ -368,6 +368,10 @@ pub fn get_spiral_id(layer: LayerNodeIdentifier, network_interface: &NodeNetwork
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Spiral")
}

pub fn get_teardrop_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<NodeId> {
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Teardrop")
}

pub fn get_text_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<NodeId> {
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Text")
}
Expand Down
2 changes: 2 additions & 0 deletions editor/src/messages/tool/common_functionality/shapes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ pub mod rectangle_shape;
pub mod shape_utility;
pub mod spiral_shape;
pub mod star_shape;
pub mod teardrop_shape;

pub use super::shapes::ellipse_shape::Ellipse;
pub use super::shapes::line_shape::{Line, LineEnd};
pub use super::shapes::rectangle_shape::Rectangle;
pub use super::shapes::teardrop_shape::Teardrop;
pub use crate::messages::tool::tool_messages::shape_tool::ShapeToolData;
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ pub enum ShapeType {
Polygon = 0,
Star,
Circle,
Teardrop,
Arc,
Spiral,
Grid,
Expand All @@ -42,6 +43,7 @@ impl ShapeType {
Self::Polygon => "Polygon",
Self::Star => "Star",
Self::Circle => "Circle",
Self::Teardrop => "Teardrop",
Self::Arc => "Arc",
Self::Grid => "Grid",
Self::Spiral => "Spiral",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn;
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type;
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeTemplate};
use crate::messages::tool::common_functionality::graph_modification_utils;
use crate::messages::tool::common_functionality::shapes::shape_utility::ShapeToolModifierKey;
use crate::messages::tool::tool_messages::shape_tool::ShapeToolData;
use crate::messages::tool::tool_messages::tool_prelude::*;
use glam::DAffine2;
use graph_craft::document::NodeInput;
use graph_craft::document::value::TaggedValue;

#[derive(Default)]
pub struct Teardrop;

impl Teardrop {
pub fn create_node() -> NodeTemplate {
let node_type = resolve_document_node_type("Teardrop").expect("Teardrop can't be found");
node_type.node_template_input_override([None, Some(NodeInput::value(TaggedValue::F64(0.5), false)), Some(NodeInput::value(TaggedValue::F64(0.5), false))])
}

pub fn update_shape(
document: &DocumentMessageHandler,
ipp: &InputPreprocessorMessageHandler,
viewport: &ViewportMessageHandler,
layer: LayerNodeIdentifier,
shape_tool_data: &mut ShapeToolData,
modifier: ShapeToolModifierKey,
responses: &mut VecDeque<Message>,
) {
let [center, lock_ratio, _] = modifier;

if let Some([start, end]) = shape_tool_data.data.calculate_points(document, ipp, viewport, center, lock_ratio) {
let Some(node_id) = graph_modification_utils::get_teardrop_id(layer, &document.network_interface) else {
return;
};

responses.add(NodeGraphMessage::SetInput {
input_connector: InputConnector::node(node_id, 1),
input: NodeInput::value(TaggedValue::F64(((start.x - end.x) / 2.).abs()), false),
});
responses.add(NodeGraphMessage::SetInput {
input_connector: InputConnector::node(node_id, 2),
input: NodeInput::value(TaggedValue::F64(((start.y - end.y) / 2.).abs()), false),
});
responses.add(GraphOperationMessage::TransformSet {
layer,
transform: DAffine2::from_translation(start.midpoint(end)),
transform_in: TransformIn::Viewport,
skip_rerender: false,
});
}
}
}
36 changes: 33 additions & 3 deletions editor/src/messages/tool/tool_messages/shape_tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use crate::messages::tool::common_functionality::shapes::polygon_shape::Polygon;
use crate::messages::tool::common_functionality::shapes::shape_utility::{ShapeToolModifierKey, ShapeType, anchor_overlays, transform_cage_overlays};
use crate::messages::tool::common_functionality::shapes::spiral_shape::Spiral;
use crate::messages::tool::common_functionality::shapes::star_shape::Star;
use crate::messages::tool::common_functionality::shapes::teardrop_shape::Teardrop;
use crate::messages::tool::common_functionality::shapes::{Ellipse, Line, Rectangle};
use crate::messages::tool::common_functionality::snapping::{self, SnapCandidatePoint, SnapData, SnapTypeConfiguration};
use crate::messages::tool::common_functionality::transformation_cage::{BoundingBoxManager, EdgeBool};
Expand Down Expand Up @@ -150,6 +151,12 @@ fn create_shape_option_widget(shape_type: ShapeType) -> WidgetInstance {
}
.into()
}),
MenuListEntry::new("Teardrop").label("Teardrop").on_commit(move |_| {
ShapeToolMessage::UpdateOptions {
options: ShapeOptionsUpdate::ShapeType(ShapeType::Teardrop),
}
.into()
}),
MenuListEntry::new("Arc").label("Arc").on_commit(move |_| {
ShapeToolMessage::UpdateOptions {
options: ShapeOptionsUpdate::ShapeType(ShapeType::Arc),
Expand Down Expand Up @@ -804,7 +811,15 @@ impl Fsm for ShapeToolFsmState {
};

match tool_data.current_shape {
ShapeType::Polygon | ShapeType::Star | ShapeType::Circle | ShapeType::Arc | ShapeType::Spiral | ShapeType::Grid | ShapeType::Rectangle | ShapeType::Ellipse => {
ShapeType::Polygon
| ShapeType::Star
| ShapeType::Circle
| ShapeType::Teardrop
| ShapeType::Arc
| ShapeType::Spiral
| ShapeType::Grid
| ShapeType::Rectangle
| ShapeType::Ellipse => {
tool_data.data.start(document, input, viewport);
}
ShapeType::Line => {
Expand All @@ -823,6 +838,7 @@ impl Fsm for ShapeToolFsmState {
ShapeType::Polygon => Polygon::create_node(tool_options.vertices),
ShapeType::Star => Star::create_node(tool_options.vertices),
ShapeType::Circle => Circle::create_node(),
ShapeType::Teardrop => Teardrop::create_node(),
ShapeType::Arc => Arc::create_node(tool_options.arc_type),
ShapeType::Spiral => Spiral::create_node(tool_options.spiral_type, tool_options.turns),
ShapeType::Grid => Grid::create_node(tool_options.grid_type),
Expand All @@ -837,7 +853,15 @@ impl Fsm for ShapeToolFsmState {
let defered_responses = &mut VecDeque::new();

match tool_data.current_shape {
ShapeType::Polygon | ShapeType::Star | ShapeType::Circle | ShapeType::Arc | ShapeType::Spiral | ShapeType::Grid | ShapeType::Rectangle | ShapeType::Ellipse => {
ShapeType::Polygon
| ShapeType::Star
| ShapeType::Circle
| ShapeType::Teardrop
| ShapeType::Arc
| ShapeType::Spiral
| ShapeType::Grid
| ShapeType::Rectangle
| ShapeType::Ellipse => {
defered_responses.add(GraphOperationMessage::TransformSet {
layer,
transform: DAffine2::from_scale_angle_translation(DVec2::ONE, 0., input.mouse.position),
Expand Down Expand Up @@ -873,6 +897,7 @@ impl Fsm for ShapeToolFsmState {
ShapeType::Polygon => Polygon::update_shape(document, input, viewport, layer, tool_data, modifier, responses),
ShapeType::Star => Star::update_shape(document, input, viewport, layer, tool_data, modifier, responses),
ShapeType::Circle => Circle::update_shape(document, input, viewport, layer, tool_data, modifier, responses),
ShapeType::Teardrop => Teardrop::update_shape(document, input, viewport, layer, tool_data, modifier, responses),
ShapeType::Arc => Arc::update_shape(document, input, viewport, layer, tool_data, modifier, responses),
ShapeType::Spiral => Spiral::update_shape(document, input, viewport, layer, tool_data, responses),
ShapeType::Grid => Grid::update_shape(document, input, layer, tool_options.grid_type, tool_data, modifier, responses),
Expand Down Expand Up @@ -1120,6 +1145,11 @@ fn update_dynamic_hints(state: &ShapeToolFsmState, responses: &mut VecDeque<Mess
HintInfo::mouse(MouseMotion::LmbDrag, "Draw Circle"),
HintInfo::keys([Key::Alt], "From Center").prepend_plus(),
])],
ShapeType::Teardrop => vec![HintGroup(vec![
HintInfo::mouse(MouseMotion::LmbDrag, "Draw Teardrop"),
HintInfo::keys([Key::Shift], "Constrain Circular").prepend_plus(),
HintInfo::keys([Key::Alt], "From Center").prepend_plus(),
])],
ShapeType::Arc => vec![HintGroup(vec![
HintInfo::mouse(MouseMotion::LmbDrag, "Draw Arc"),
HintInfo::keys([Key::Shift], "Constrain Arc").prepend_plus(),
Expand All @@ -1138,7 +1168,7 @@ fn update_dynamic_hints(state: &ShapeToolFsmState, responses: &mut VecDeque<Mess
let tool_hint_group = match shape {
ShapeType::Polygon | ShapeType::Star | ShapeType::Arc => HintGroup(vec![HintInfo::keys([Key::Shift], "Constrain Regular"), HintInfo::keys([Key::Alt], "From Center")]),
ShapeType::Rectangle => HintGroup(vec![HintInfo::keys([Key::Shift], "Constrain Square"), HintInfo::keys([Key::Alt], "From Center")]),
ShapeType::Ellipse => HintGroup(vec![HintInfo::keys([Key::Shift], "Constrain Circular"), HintInfo::keys([Key::Alt], "From Center")]),
ShapeType::Ellipse | ShapeType::Teardrop => HintGroup(vec![HintInfo::keys([Key::Shift], "Constrain Circular"), HintInfo::keys([Key::Alt], "From Center")]),
ShapeType::Grid => HintGroup(vec![HintInfo::keys([Key::Shift], "Constrain Regular"), HintInfo::keys([Key::Alt], "From Center")]),
ShapeType::Line => HintGroup(vec![
HintInfo::keys([Key::Shift], "15° Increments"),
Expand Down
23 changes: 23 additions & 0 deletions node-graph/libraries/vector-types/src/subpath/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,29 @@ impl<PointId: Identifier> Subpath<PointId> {
Self::new(manipulator_groups, true)
}

/// Constructs a teardrop with `corner1` and `corner2` as the two corners of the bounding box.
pub fn new_teardrop(corner1: DVec2, corner2: DVec2) -> Self {
let size = (corner1 - corner2).abs();
let center = (corner1 + corner2) / 2.;
let top = DVec2::new(center.x, corner1.y);
let bottom = DVec2::new(center.x, corner2.y);
let left = DVec2::new(corner1.x, center.y / 2.);
let right = DVec2::new(corner2.x, center.y / 2.);

// Based on https://pomax.github.io/bezierinfo/#circles_cubic
const HANDLE_OFFSET_FACTOR: f64 = 0.551784777779014;
let bottom_handle_offset = size * HANDLE_OFFSET_FACTOR * 0.5;
let sides_handle_offset = size * HANDLE_OFFSET_FACTOR * 0.375; //*0.5*0.75

let manipulator_groups = vec![
ManipulatorGroup::new(top, None, None),
ManipulatorGroup::new(right, Some(right - sides_handle_offset * DVec2::Y), Some(right + bottom_handle_offset * DVec2::Y)),
ManipulatorGroup::new(bottom, Some(bottom + bottom_handle_offset * DVec2::X), Some(bottom - bottom_handle_offset * DVec2::X)),
ManipulatorGroup::new(left, Some(left + bottom_handle_offset * DVec2::Y), Some(left - sides_handle_offset * DVec2::Y)),
];
Self::new(manipulator_groups, true)
}

/// Constructs an arc by a `radius`, `angle_start` and `angle_size`. Angles must be in radians. Slice option makes it look like pie or pacman.
pub fn new_arc(radius: f64, start_angle: f64, sweep_angle: f64, arc_type: ArcType) -> Self {
// Prevents glitches from numerical imprecision that have been observed during animation playback after about a minute
Expand Down
27 changes: 27 additions & 0 deletions node-graph/nodes/vector/src/generator_nodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,33 @@ fn circle(
Table::new_from_element(Vector::from_subpath(subpath::Subpath::new_ellipse(DVec2::splat(-radius), DVec2::splat(radius))))
}

/// Generates a teardrop shape with a chosen radius
#[node_macro::node(category("Vector: Shape"))]
fn teardrop(
_: impl Ctx,
_primary: (),
#[unit(" px")]
#[default(50)]
radius_x: f64,
#[unit(" px")]
#[default(25)]
radius_y: f64,
) -> Table<Vector> {
let corner1 = DVec2::new(-radius_x, -radius_y * 2.);
let corner2 = DVec2::new(radius_x, radius_y * 0.75);

let mut teardrop = Vector::from_subpath(subpath::Subpath::new_teardrop(corner1, corner2));

let len = teardrop.segment_domain.ids().len();
for i in 0..len {
teardrop
.colinear_manipulators
.push([HandleId::end(teardrop.segment_domain.ids()[i]), HandleId::primary(teardrop.segment_domain.ids()[(i + 1) % len])]);
}

Table::new_from_element(teardrop)
}

/// 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(
Expand Down