mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 22:28:10 +08:00
Rename the nodes 'Length' -> 'Magnitude', 'Flatten Path' -> 'Combine Paths', 'Vec2 Value' -> 'Combine Vec2', and add a new 'Vec2 Value' node (#4349)
* Rename the node 'Length' -> 'Magnitude' * Rename the node 'Flatten Path' -> 'Combine Paths' * Replace the node 'Vec2 Value' with 'Combine Vec2' and add a new 'Vec2 Value' that's actually a vec2 * Update demo artwork
This commit is contained in:
committed by
Dennis Kobert
parent
9556904aed
commit
4f49c000e8
2
demo-artwork/isometric-fountain.graphite
generated
2
demo-artwork/isometric-fountain.graphite
generated
File diff suppressed because one or more lines are too long
2
demo-artwork/painted-dreams.graphite
generated
2
demo-artwork/painted-dreams.graphite
generated
File diff suppressed because one or more lines are too long
2
demo-artwork/parametric-dunescape.graphite
generated
2
demo-artwork/parametric-dunescape.graphite
generated
File diff suppressed because one or more lines are too long
@@ -433,17 +433,17 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
return None;
|
||||
};
|
||||
|
||||
// If inserting a 'Path' node, insert a 'Flatten Path' node if the type is `Graphic`.
|
||||
// If inserting a 'Path' node, insert a 'Combine Paths' node if the type is `Graphic`.
|
||||
// TODO: Allow the 'Path' node to operate on `List` data by utilizing the reference (index or ID?) for each item.
|
||||
if node_definition.identifier == "Path" {
|
||||
let layer_input_type = self.network_interface.input_type(&InputConnector::node(output_layer.to_node(), 1), &[]);
|
||||
if layer_input_type.compiled_nested_type() == Some(&concrete!(List<Graphic>)) {
|
||||
let Some(flatten_path_definition) = resolve_proto_node_type(graphene_std::vector_nodes::flatten_path::IDENTIFIER) else {
|
||||
log::error!("Flatten Path does not exist in ModifyInputsContext::existing_node_id");
|
||||
let Some(combine_paths_definition) = resolve_proto_node_type(graphene_std::vector_nodes::combine_paths::IDENTIFIER) else {
|
||||
log::error!("Combine Paths does not exist in ModifyInputsContext::existing_node_id");
|
||||
return None;
|
||||
};
|
||||
let node_id = NodeId::new();
|
||||
self.network_interface.insert_node(node_id, flatten_path_definition.default_node_template(), &[]);
|
||||
self.network_interface.insert_node(node_id, combine_paths_definition.default_node_template(), &[]);
|
||||
self.network_interface.move_node_to_chain_start(&node_id, output_layer, &[], self.import);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -840,9 +840,9 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
|
||||
inputs: vec![NodeInput::node(NodeId(4), 0), NodeInput::node(NodeId(3), 0)],
|
||||
..Default::default()
|
||||
},
|
||||
// 6: Flatten Path
|
||||
// 6: Combine Paths
|
||||
DocumentNode {
|
||||
implementation: DocumentNodeImplementation::ProtoNode(vector::flatten_path::IDENTIFIER),
|
||||
implementation: DocumentNodeImplementation::ProtoNode(vector::combine_paths::IDENTIFIER),
|
||||
inputs: vec![NodeInput::node(NodeId(5), 0)],
|
||||
..Default::default()
|
||||
},
|
||||
@@ -917,7 +917,7 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
// 6: Flatten Path
|
||||
// 6: Combine Paths
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(35, 0)),
|
||||
@@ -1285,7 +1285,7 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
|
||||
description: Cow::Borrowed(
|
||||
"Decomposes the X and Y components of a vec2.\n\
|
||||
\n\
|
||||
The inverse of this node is \"Vec2 Value\", which can have either or both its X and Y parameters exposed as graph inputs.",
|
||||
The inverse of this node is **Combine Vec2**, which composes a vec2 from its X and Y components.",
|
||||
),
|
||||
properties: None,
|
||||
},
|
||||
|
||||
@@ -297,8 +297,8 @@ const NODE_REPLACEMENTS: &[NodeReplacement<'static>] = &[
|
||||
],
|
||||
},
|
||||
NodeReplacement {
|
||||
node: graphene_std::math_nodes::length::IDENTIFIER,
|
||||
aliases: &["graphene_math_nodes::LengthNode", "graphene_core::ops::LenghtNode"],
|
||||
node: graphene_std::math_nodes::magnitude::IDENTIFIER,
|
||||
aliases: &["math_nodes::LengthNode", "graphene_math_nodes::LengthNode", "graphene_core::ops::LenghtNode"],
|
||||
},
|
||||
NodeReplacement {
|
||||
node: graphene_std::math_nodes::less_than::IDENTIFIER,
|
||||
@@ -423,6 +423,8 @@ const NODE_REPLACEMENTS: &[NodeReplacement<'static>] = &[
|
||||
node: graphene_std::math_nodes::as_u_64::IDENTIFIER,
|
||||
aliases: &["graphene_math_nodes::ToU64Node", "graphene_core::ops::ToU64Node", "math_nodes::ToU64Node"],
|
||||
},
|
||||
// The old 'Vec2 Value' node took separate X and Y inputs, a role now filled by 'Combine Vec2', while the new 'Vec2 Value' node takes a single vec2 input.
|
||||
// Old references (including these older aliases) are remapped here to `vec_2_value::IDENTIFIER` so the per-node migration in `migrate_node` can detect the leftover 3-input shape and convert it into a 'Combine Vec2' node.
|
||||
NodeReplacement {
|
||||
node: graphene_std::math_nodes::vec_2_value::IDENTIFIER,
|
||||
aliases: &[
|
||||
@@ -806,7 +808,7 @@ const NODE_REPLACEMENTS: &[NodeReplacement<'static>] = &[
|
||||
aliases: &["graphene_core::vector::vector_nodes::FillNode", "graphene_core::vector::FillNode"],
|
||||
},
|
||||
NodeReplacement {
|
||||
node: graphene_std::vector::flatten_path::IDENTIFIER,
|
||||
node: graphene_std::vector::combine_paths::IDENTIFIER,
|
||||
aliases: &[
|
||||
"graphene_core::vector::vector_nodes::FlattenPathNode",
|
||||
"graphene_core::vector::FlattenVectorElementsNode",
|
||||
@@ -2068,6 +2070,20 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
||||
.set_input(&InputConnector::node(*node_id, 2), NodeInput::value(TaggedValue::Bool(false), false), network_path);
|
||||
}
|
||||
|
||||
// Convert the old 'Vec2 Value' node, identified by its leftover 3-input shape with separate X and Y inputs,
|
||||
// into the 'Combine Vec2' node which now fills that role (the new 'Vec2 Value' node instead takes a single vec2 input)
|
||||
if reference == DefinitionIdentifier::ProtoNode(graphene_std::math_nodes::vec_2_value::IDENTIFIER) && inputs_count == 3 {
|
||||
let combine_vec2_reference = DefinitionIdentifier::ProtoNode(graphene_std::math_nodes::combine_vec_2::IDENTIFIER);
|
||||
let mut node_template = resolve_document_node_type(&combine_vec2_reference)?.default_node_template();
|
||||
document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
|
||||
|
||||
let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
|
||||
|
||||
document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path);
|
||||
document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path);
|
||||
document.network_interface.set_input(&InputConnector::node(*node_id, 2), old_inputs[2].clone(), network_path);
|
||||
}
|
||||
|
||||
// Upgrade the Mirror node to add the `keep_original` boolean input
|
||||
if reference == DefinitionIdentifier::ProtoNode(graphene_std::graphic::mirror::IDENTIFIER) && inputs_count == 3 {
|
||||
let mut node_template = resolve_document_node_type(&reference)?.default_node_template();
|
||||
|
||||
@@ -100,21 +100,21 @@ pub fn merge_layers(document: &DocumentMessageHandler, first_layer: LayerNodeIde
|
||||
delete_children: false,
|
||||
});
|
||||
|
||||
// Add a Flatten Path node after the merge
|
||||
let flatten_node_id = NodeId::new();
|
||||
let flatten_node = document_node_definitions::resolve_proto_node_type(graphene_std::vector::flatten_path::IDENTIFIER)
|
||||
.expect("Failed to create flatten node")
|
||||
// Add a Combine Paths node after the merge
|
||||
let combine_paths_node_id = NodeId::new();
|
||||
let combine_paths_node = document_node_definitions::resolve_proto_node_type(graphene_std::vector::combine_paths::IDENTIFIER)
|
||||
.expect("Failed to create combine paths node")
|
||||
.default_node_template();
|
||||
responses.add(NodeGraphMessage::InsertNode {
|
||||
node_id: flatten_node_id,
|
||||
node_template: Box::new(flatten_node),
|
||||
node_id: combine_paths_node_id,
|
||||
node_template: Box::new(combine_paths_node),
|
||||
});
|
||||
responses.add(NodeGraphMessage::MoveNodeToChainStart {
|
||||
node_id: flatten_node_id,
|
||||
node_id: combine_paths_node_id,
|
||||
parent: first_layer,
|
||||
});
|
||||
|
||||
// Add a path node after the flatten node
|
||||
// Add a path node after the combine paths node
|
||||
let path_node_id = NodeId::new();
|
||||
let path_node = document_node_definitions::resolve_network_node_type("Path")
|
||||
.expect("Failed to create path node")
|
||||
|
||||
@@ -421,7 +421,7 @@ impl ShapeState {
|
||||
(point.as_handle().is_some() && self.ignore_handles) || (point.as_anchor().is_some() && self.ignore_anchors)
|
||||
}
|
||||
|
||||
/// Applies a dummy vector modification to the layer. In the case where a group containing some vector data is selected, this triggers the creation of a Flatten Path node.
|
||||
/// Applies a dummy vector modification to the layer. In the case where a group containing some vector data is selected, this triggers the creation of a Combine Paths node.
|
||||
fn add_dummy_modification_to_trigger_graph_reorganization(layer: LayerNodeIdentifier, start_point: PointId, _end_point: PointId, responses: &mut VecDeque<Message>) {
|
||||
// Apply a zero-delta to one of the points to trigger reorganization
|
||||
let dummy_modification = VectorModificationType::ApplyPointDelta {
|
||||
|
||||
@@ -42,9 +42,9 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, Vec<RegistryEntry>> {
|
||||
);
|
||||
// The path flattening's plain vector rows, served under its identifier.
|
||||
node_types.extend(
|
||||
graphene_std::vector::flatten_path_vector_entries()
|
||||
graphene_std::vector::combine_paths_vector_entries()
|
||||
.into_iter()
|
||||
.map(|entry| (graphene_std::vector::flatten_path::IDENTIFIER.clone(), entry)),
|
||||
.map(|entry| (graphene_std::vector::combine_paths::IDENTIFIER.clone(), entry)),
|
||||
);
|
||||
// The solidify's plain vector rows, served under its identifier.
|
||||
node_types.extend(
|
||||
|
||||
@@ -1830,7 +1830,7 @@ fn collect_vector_metadata<S: LaneSource<Element = Vector>>(source: &S, metadata
|
||||
}
|
||||
|
||||
// If this item carries a snapshot of upstream graphic content (e.g. it was produced by Boolean Operation,
|
||||
// Flatten Path, Morph, or any other destructive merge), recurse into that snapshot so the editor can
|
||||
// Combine Paths, Morph, or any other destructive merge), recurse into that snapshot so the editor can
|
||||
// surface the original child layers' click targets.
|
||||
if let Some(upstream_nested_layers) = source.attr::<EditorMergedLayers>(index).filter(|layers| !layers.is_empty()) {
|
||||
let mut upstream_footprint = footprint;
|
||||
|
||||
@@ -4,7 +4,7 @@ use glam::{DVec2, IVec2, UVec2};
|
||||
|
||||
/// Obtains the X or Y component of a vec2.
|
||||
///
|
||||
/// The inverse of this node is "Vec2 Value", which can have either or both its X and Y parameters exposed as graph inputs.
|
||||
/// The inverse of this node is **Combine Vec2**, which composes a vec2 from its X and Y components.
|
||||
#[node_macro::node(name("Extract XY"), category("Math: Vector"))]
|
||||
fn extract_xy<T: Into<DVec2>>(_: impl Ctx, #[implementations(DVec2, IVec2, UVec2)] vector: T, axis: XY) -> f64 {
|
||||
match axis {
|
||||
|
||||
@@ -399,7 +399,7 @@ fn vector_row_count(level: GraphicLevel<'_>) -> usize {
|
||||
// TODO: Flattening erases the upstream `Graphic` hierarchy that editor metadata collection walks to populate
|
||||
// TODO: `upstream_footprints` / `local_transforms` / `click_targets` per child layer, so the pre-flattened list
|
||||
// TODO: is stashed on row 0 for `collect_metadata` to recurse into (as Boolean Operation, Solidify Stroke,
|
||||
// TODO: Flatten Path, Morph and Rasterize do). Driving each layer's metadata from its own Monitor's captured
|
||||
// TODO: Combine Paths, Morph and Rasterize do). Driving each layer's metadata from its own Monitor's captured
|
||||
// TODO: `(Context, List<Graphic>)` would make this attribute unnecessary.
|
||||
/// The parked merged-layers snapshot for row 0. Row 0 carries a composed
|
||||
/// transform the snapshot's own transforms already include, so the snapshot is
|
||||
|
||||
@@ -802,8 +802,8 @@ fn percentage_value(_: impl Ctx, _primary: (), percentage: Percentage) -> f64 {
|
||||
|
||||
/// Constructs a two-dimensional vector value which may be set to any XY pair.
|
||||
#[node_macro::node(category("Value"), name("Vec2 Value"))]
|
||||
fn vec2_value(_: impl Ctx, _primary: (), x: f64, y: f64) -> DVec2 {
|
||||
DVec2::new(x, y)
|
||||
fn vec2_value(_: impl Ctx, _primary: (), #[name("Vec2")] vec2: DVec2) -> DVec2 {
|
||||
vec2
|
||||
}
|
||||
|
||||
/// Constructs a color value which may be set to any color.
|
||||
@@ -896,6 +896,23 @@ fn footprint_value(_: impl Ctx, _primary: (), transform: DAffine2, #[default(100
|
||||
}
|
||||
}
|
||||
|
||||
/// Composes a vec2 from its X and Y components.
|
||||
///
|
||||
/// The inverse of this node is **Split Vec2**, which decomposes a vec2 back into its X and Y components.
|
||||
#[node_macro::node(category("Math: Vector"), name("Combine Vec2"))]
|
||||
fn combine_vec2(
|
||||
_: impl Ctx,
|
||||
_primary: (),
|
||||
/// The X component of the vec2.
|
||||
#[expose]
|
||||
x: f64,
|
||||
/// The Y component of the vec2.
|
||||
#[expose]
|
||||
y: f64,
|
||||
) -> DVec2 {
|
||||
DVec2::new(x, y)
|
||||
}
|
||||
|
||||
/// The dot product operation (`·`) calculates the degree of similarity of a vec2 pair based on their angles and lengths.
|
||||
///
|
||||
/// Calculated as `‖a‖‖b‖cos(θ)`, it represents the product of their lengths (`‖a‖‖b‖`) scaled by the alignment of their directions (`cos(θ)`).
|
||||
@@ -964,10 +981,9 @@ fn angle_to<T: ToPosition, U: ToPosition>(
|
||||
if radians { angle } else { angle.to_degrees() }
|
||||
}
|
||||
|
||||
// TODO: Rename to "Magnitude"
|
||||
/// The magnitude operator (`‖x‖`) calculates the length of a vec2, which is the distance from the base to the tip of the arrow represented by the vector.
|
||||
#[node_macro::node(category("Math: Vector"))]
|
||||
fn length(_: impl Ctx, vector: DVec2) -> f64 {
|
||||
fn magnitude(_: impl Ctx, vector: DVec2) -> f64 {
|
||||
vector.length()
|
||||
}
|
||||
|
||||
@@ -991,9 +1007,9 @@ mod test {
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn length_function() {
|
||||
pub fn magnitude_function() {
|
||||
let vector = DVec2::new(3., 4.);
|
||||
assert_eq!(length(&(), vector), 5.);
|
||||
assert_eq!(magnitude(&(), vector), 5.);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -2057,9 +2057,9 @@ fn flatten_path_core<'e>(
|
||||
))
|
||||
}
|
||||
|
||||
// TODO: Rename to "Combine Paths" and make this happen per-element instead of flattening every element into a single path. The migration for this should then become a Flatten Vector -> Combine Paths pair of nodes.
|
||||
// TODO: Make this happen per-element instead of flattening every element into a single path. The migration for this should then become a Flatten Vector -> Combine Paths pair of nodes.
|
||||
#[node_macro::node(category("Vector"), path(graphene_core::vector))]
|
||||
pub fn flatten_path<'e>(
|
||||
pub fn combine_paths<'e>(
|
||||
ctx: impl Ctx + ExtractArena<'e> + ExtractIndex + InjectIndex + Copy,
|
||||
content: IList<Graphic<'static>>,
|
||||
) -> Result<
|
||||
@@ -2087,10 +2087,10 @@ pub fn flatten_path<'e>(
|
||||
Ok((content.lane(carrier).map_element(element), transform, fill, stroke, layer_path, merged))
|
||||
}
|
||||
|
||||
/// The path flattening over a plain vector level, as [`flatten_path`].
|
||||
/// Registered under the flatten path identifier.
|
||||
/// The path flattening over a plain vector level, as [`combine_paths`].
|
||||
/// Registered under the combine paths identifier.
|
||||
#[node_macro::node(category(""))]
|
||||
pub fn flatten_path_vector<'e>(
|
||||
pub fn combine_paths_vector<'e>(
|
||||
ctx: impl Ctx + ExtractArena<'e> + ExtractIndex + InjectIndex + Copy,
|
||||
content: IList<Vector>,
|
||||
) -> Result<
|
||||
@@ -2118,7 +2118,7 @@ pub fn flatten_path_vector<'e>(
|
||||
Ok((content.lane(carrier).map_element(element), transform, fill, stroke, layer_path, merged))
|
||||
}
|
||||
|
||||
pub use _flatten_path_vector_mod::flatten_path_vector_entries;
|
||||
pub use _combine_paths_vector_mod::combine_paths_vector_entries;
|
||||
|
||||
/// Convert vector geometry into a polyline composed of evenly spaced points.
|
||||
#[node_macro::node(category("Vector: Modifier"), path(core_types::vector), properties("sample_polyline_properties"), memoize)]
|
||||
@@ -4137,6 +4137,7 @@ mod test {
|
||||
assert_eq!(manipulator_groups_anchors[i], expected_bounding_box[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sample_polyline() {
|
||||
let path = BezPath::from_vec(vec![PathEl::MoveTo(Point::ZERO), PathEl::CurveTo(Point::ZERO, Point::new(100., 0.), Point::new(100., 0.))]);
|
||||
|
||||
Reference in New Issue
Block a user