mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-21 07:38:12 +08:00
Rename graphic subtypes to remove their "data" and "group" suffixes (#2990)
* Rename VectorData to Vector * Rename other VectorData* types to Vector* * Move assorted data types out of vector_data.rs into misc.rs * Rename vector_data.rs to vector_types.rs and remove the vector_types module folder * Rename other references to "vector data" * Remove label widgets for raster/vector/group to use "-" instead * Rename RasterData to Raster * Rename GraphicGroup to Group * Fix migrations and rename graphic_element.rs -> graphic.rs * Rename TaggedValue::ArtboardGroup -> TaggedValue::Artboard
This commit is contained in:
@@ -692,7 +692,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
|
||||
});
|
||||
|
||||
if layer_to_move.parent(self.metadata()) != Some(parent) {
|
||||
// TODO: Fix this so it works when dragging a layer into a group parent which has a Transform node, which used to work before #2689 caused this regression by removing the empty VectorData table row.
|
||||
// TODO: Fix this so it works when dragging a layer into a group parent which has a Transform node, which used to work before #2689 caused this regression by removing the empty vector table row.
|
||||
// TODO: See #2688 for this issue.
|
||||
let layer_local_transform = self.network_interface.document_metadata().transform_to_viewport(layer_to_move);
|
||||
let undo_transform = self.network_interface.document_metadata().transform_to_viewport(parent).inverse();
|
||||
@@ -2907,7 +2907,7 @@ impl DocumentMessageHandler {
|
||||
/// Create a network interface with a single export
|
||||
fn default_document_network_interface() -> NodeNetworkInterface {
|
||||
let mut network_interface = NodeNetworkInterface::default();
|
||||
network_interface.add_export(TaggedValue::ArtboardGroup(Default::default()), -1, "", &[]);
|
||||
network_interface.add_export(TaggedValue::Artboard(Default::default()), -1, "", &[]);
|
||||
network_interface
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -174,7 +174,7 @@ impl MessageHandler<GraphOperationMessage, GraphOperationMessageContext<'_>> for
|
||||
GraphOperationMessage::NewVectorLayer { id, subpaths, parent, insert_index } => {
|
||||
let mut modify_inputs = ModifyInputsContext::new(network_interface, responses);
|
||||
let layer = modify_inputs.create_layer(id);
|
||||
modify_inputs.insert_vector_data(subpaths, layer, true, true, true);
|
||||
modify_inputs.insert_vector(subpaths, layer, true, true, true);
|
||||
network_interface.move_layer_to_stack(layer, parent, insert_index, &[]);
|
||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||
}
|
||||
@@ -349,7 +349,7 @@ fn import_usvg_node(modify_inputs: &mut ModifyInputsContext, node: &usvg::Node,
|
||||
let subpaths = convert_usvg_path(path);
|
||||
let bounds = subpaths.iter().filter_map(|subpath| subpath.bounding_box()).reduce(Quad::combine_bounds).unwrap_or_default();
|
||||
|
||||
modify_inputs.insert_vector_data(subpaths, layer, true, path.fill().is_some(), path.stroke().is_some());
|
||||
modify_inputs.insert_vector(subpaths, layer, true, path.fill().is_some(), path.stroke().is_some());
|
||||
|
||||
if let Some(transform_node_id) = modify_inputs.existing_node_id("Transform", true) {
|
||||
transform_utils::update_transform(modify_inputs.network_interface, &transform_node_id, transform * usvg_transform(node.abs_transform()));
|
||||
|
||||
@@ -14,7 +14,7 @@ use graphene_std::raster::BlendMode;
|
||||
use graphene_std::raster_types::{CPU, Raster};
|
||||
use graphene_std::table::Table;
|
||||
use graphene_std::text::{Font, TypesettingConfig};
|
||||
use graphene_std::vector::VectorData;
|
||||
use graphene_std::vector::Vector;
|
||||
use graphene_std::vector::style::{Fill, Stroke};
|
||||
use graphene_std::vector::{PointId, VectorModificationType};
|
||||
use graphene_std::{Graphic, NodeInputDecleration};
|
||||
@@ -131,8 +131,8 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
/// Creates an artboard as the primary export for the document network
|
||||
pub fn create_artboard(&mut self, new_id: NodeId, artboard: Artboard) -> LayerNodeIdentifier {
|
||||
let artboard_node_template = resolve_document_node_type("Artboard").expect("Node").node_template_input_override([
|
||||
Some(NodeInput::value(TaggedValue::ArtboardGroup(Default::default()), true)),
|
||||
Some(NodeInput::value(TaggedValue::GraphicGroup(Default::default()), true)),
|
||||
Some(NodeInput::value(TaggedValue::Artboard(Default::default()), true)),
|
||||
Some(NodeInput::value(TaggedValue::Group(Default::default()), true)),
|
||||
Some(NodeInput::value(TaggedValue::DVec2(artboard.location.into()), false)),
|
||||
Some(NodeInput::value(TaggedValue::DVec2(artboard.dimensions.into()), false)),
|
||||
Some(NodeInput::value(TaggedValue::Color(artboard.background), false)),
|
||||
@@ -144,7 +144,7 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
|
||||
pub fn insert_boolean_data(&mut self, operation: graphene_std::path_bool::BooleanOperation, layer: LayerNodeIdentifier) {
|
||||
let boolean = resolve_document_node_type("Boolean Operation").expect("Boolean node does not exist").node_template_input_override([
|
||||
Some(NodeInput::value(TaggedValue::GraphicGroup(Default::default()), true)),
|
||||
Some(NodeInput::value(TaggedValue::Group(Default::default()), true)),
|
||||
Some(NodeInput::value(TaggedValue::BooleanOperation(operation), false)),
|
||||
]);
|
||||
|
||||
@@ -153,12 +153,12 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
self.network_interface.move_node_to_chain_start(&boolean_id, layer, &[]);
|
||||
}
|
||||
|
||||
pub fn insert_vector_data(&mut self, subpaths: Vec<Subpath<PointId>>, layer: LayerNodeIdentifier, include_transform: bool, include_fill: bool, include_stroke: bool) {
|
||||
let vector_data = Table::new_from_element(VectorData::from_subpaths(subpaths, true));
|
||||
pub fn insert_vector(&mut self, subpaths: Vec<Subpath<PointId>>, layer: LayerNodeIdentifier, include_transform: bool, include_fill: bool, include_stroke: bool) {
|
||||
let vector = Table::new_from_element(Vector::from_subpaths(subpaths, true));
|
||||
|
||||
let shape = resolve_document_node_type("Path")
|
||||
.expect("Path node does not exist")
|
||||
.node_template_input_override([Some(NodeInput::value(TaggedValue::VectorData(vector_data), false))]);
|
||||
.node_template_input_override([Some(NodeInput::value(TaggedValue::Vector(vector), false))]);
|
||||
let shape_id = NodeId::new();
|
||||
self.network_interface.insert_node(shape_id, shape, &[]);
|
||||
self.network_interface.move_node_to_chain_start(&shape_id, layer, &[]);
|
||||
@@ -223,7 +223,7 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
let transform = resolve_document_node_type("Transform").expect("Transform node does not exist").default_node_template();
|
||||
let image = resolve_document_node_type("Image Value")
|
||||
.expect("ImageValue node does not exist")
|
||||
.node_template_input_override([Some(NodeInput::value(TaggedValue::None, false)), Some(NodeInput::value(TaggedValue::RasterData(image_frame), false))]);
|
||||
.node_template_input_override([Some(NodeInput::value(TaggedValue::None, false)), Some(NodeInput::value(TaggedValue::Raster(image_frame), false))]);
|
||||
|
||||
let image_id = NodeId::new();
|
||||
self.network_interface.insert_node(image_id, image, &[]);
|
||||
@@ -296,11 +296,12 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
pub fn create_node(&mut self, reference: &str) -> Option<NodeId> {
|
||||
let output_layer = self.get_output_layer()?;
|
||||
let Some(node_definition) = resolve_document_node_type(reference) else {
|
||||
log::error!("Node type {} does not exist in ModifyInputsContext::existing_node_id", reference);
|
||||
log::error!("Node type {reference} does not exist in ModifyInputsContext::existing_node_id");
|
||||
return None;
|
||||
};
|
||||
// If inserting a path node, insert a Flatten Path if the type is a graphic group.
|
||||
// TODO: Allow the path node to operate on Graphic Group data by utilizing the reference for each vector data in a group.
|
||||
|
||||
// If inserting a path node, insert a Flatten Path if the type is Group.
|
||||
// TODO: Allow the path node to operate on Group data by utilizing the reference for each Vector in a group.
|
||||
if node_definition.identifier == "Path" {
|
||||
let layer_input_type = self.network_interface.input_type(&InputConnector::node(output_layer.to_node(), 1), &[]).0.nested_type().clone();
|
||||
if layer_input_type == concrete!(Table<Graphic>) {
|
||||
|
||||
@@ -24,7 +24,7 @@ use graphene_std::table::Table;
|
||||
use graphene_std::text::{Font, TypesettingConfig};
|
||||
#[allow(unused_imports)]
|
||||
use graphene_std::transform::Footprint;
|
||||
use graphene_std::vector::VectorData;
|
||||
use graphene_std::vector::Vector;
|
||||
use graphene_std::*;
|
||||
use std::collections::{HashMap, HashSet, VecDeque};
|
||||
|
||||
@@ -232,14 +232,14 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
// Secondary (left) input type coercion
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::network(generic!(T), 1)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(graphic_element::to_element::IDENTIFIER),
|
||||
implementation: DocumentNodeImplementation::ProtoNode(graphic::to_element::IDENTIFIER),
|
||||
manual_composition: Some(concrete!(Context)),
|
||||
..Default::default()
|
||||
},
|
||||
// Primary (bottom) input type coercion
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::network(generic!(T), 0)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(graphic_element::to_group::IDENTIFIER),
|
||||
implementation: DocumentNodeImplementation::ProtoNode(graphic::to_group::IDENTIFIER),
|
||||
manual_composition: Some(concrete!(Context)),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -258,7 +258,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
NodeInput::node(NodeId(2), 0),
|
||||
NodeInput::Reflection(graph_craft::document::DocumentNodeMetadata::DocumentNodePath),
|
||||
],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(graphic_element::layer::IDENTIFIER),
|
||||
implementation: DocumentNodeImplementation::ProtoNode(graphic::layer::IDENTIFIER),
|
||||
..Default::default()
|
||||
},
|
||||
]
|
||||
@@ -269,8 +269,8 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
..Default::default()
|
||||
}),
|
||||
inputs: vec![
|
||||
NodeInput::value(TaggedValue::GraphicGroup(Default::default()), true),
|
||||
NodeInput::value(TaggedValue::GraphicGroup(Default::default()), true),
|
||||
NodeInput::value(TaggedValue::Group(Default::default()), true),
|
||||
NodeInput::value(TaggedValue::Group(Default::default()), true),
|
||||
],
|
||||
..Default::default()
|
||||
},
|
||||
@@ -377,8 +377,8 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
..Default::default()
|
||||
}),
|
||||
inputs: vec![
|
||||
NodeInput::value(TaggedValue::ArtboardGroup(Default::default()), true),
|
||||
NodeInput::value(TaggedValue::GraphicGroup(Default::default()), true),
|
||||
NodeInput::value(TaggedValue::Artboard(Default::default()), true),
|
||||
NodeInput::value(TaggedValue::Group(Default::default()), true),
|
||||
NodeInput::value(TaggedValue::DVec2(DVec2::ZERO), false),
|
||||
NodeInput::value(TaggedValue::DVec2(DVec2::new(1920., 1080.)), false),
|
||||
NodeInput::value(TaggedValue::Color(Color::WHITE), false),
|
||||
@@ -628,7 +628,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
..Default::default()
|
||||
}),
|
||||
inputs: vec![
|
||||
NodeInput::value(TaggedValue::VectorData(Default::default()), true),
|
||||
NodeInput::value(TaggedValue::Vector(Default::default()), true),
|
||||
NodeInput::value(
|
||||
TaggedValue::Footprint(Footprint {
|
||||
transform: DAffine2::from_scale_angle_translation(DVec2::new(1000., 1000.), 0., DVec2::new(0., 0.)),
|
||||
@@ -682,7 +682,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
description: Cow::Borrowed("Rasterizes the given vector data"),
|
||||
description: Cow::Borrowed("TODO"),
|
||||
properties: None,
|
||||
},
|
||||
DocumentNodeDefinition {
|
||||
@@ -794,7 +794,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
.collect(),
|
||||
..Default::default()
|
||||
}),
|
||||
inputs: vec![NodeInput::value(TaggedValue::RasterData(Default::default()), true)],
|
||||
inputs: vec![NodeInput::value(TaggedValue::Raster(Default::default()), true)],
|
||||
..Default::default()
|
||||
},
|
||||
persistent_node_metadata: DocumentNodePersistentMetadata {
|
||||
@@ -879,7 +879,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
|
||||
..Default::default()
|
||||
}),
|
||||
inputs: vec![NodeInput::value(TaggedValue::RasterData(Default::default()), true)],
|
||||
inputs: vec![NodeInput::value(TaggedValue::Raster(Default::default()), true)],
|
||||
..Default::default()
|
||||
},
|
||||
persistent_node_metadata: DocumentNodePersistentMetadata {
|
||||
@@ -947,7 +947,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
..Default::default()
|
||||
}),
|
||||
inputs: vec![
|
||||
NodeInput::value(TaggedValue::RasterData(Default::default()), true),
|
||||
NodeInput::value(TaggedValue::Raster(Default::default()), true),
|
||||
NodeInput::value(TaggedValue::BrushStrokes(Vec::new()), false),
|
||||
NodeInput::value(TaggedValue::BrushCache(BrushCache::default()), false),
|
||||
],
|
||||
@@ -986,7 +986,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
node_template: NodeTemplate {
|
||||
document_node: DocumentNode {
|
||||
implementation: DocumentNodeImplementation::ProtoNode(memo::memo::IDENTIFIER),
|
||||
inputs: vec![NodeInput::value(TaggedValue::RasterData(Default::default()), true)],
|
||||
inputs: vec![NodeInput::value(TaggedValue::Raster(Default::default()), true)],
|
||||
manual_composition: Some(concrete!(Context)),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -1005,7 +1005,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
node_template: NodeTemplate {
|
||||
document_node: DocumentNode {
|
||||
implementation: DocumentNodeImplementation::ProtoNode(memo::impure_memo::IDENTIFIER),
|
||||
inputs: vec![NodeInput::value(TaggedValue::RasterData(Default::default()), true)],
|
||||
inputs: vec![NodeInput::value(TaggedValue::Raster(Default::default()), true)],
|
||||
manual_composition: Some(concrete!(Context)),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -1117,7 +1117,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
.collect(),
|
||||
..Default::default()
|
||||
}),
|
||||
inputs: vec![NodeInput::value(TaggedValue::RasterData(Default::default()), true)],
|
||||
inputs: vec![NodeInput::value(TaggedValue::Raster(Default::default()), true)],
|
||||
..Default::default()
|
||||
},
|
||||
persistent_node_metadata: DocumentNodePersistentMetadata {
|
||||
@@ -1196,7 +1196,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
// document_node: DocumentNode {
|
||||
// implementation: DocumentNodeImplementation::proto("graphene_core::raster::CurvesNode"),
|
||||
// inputs: vec![
|
||||
// NodeInput::value(TaggedValue::RasterData(Default::default()), true),
|
||||
// NodeInput::value(TaggedValue::Raster(Default::default()), true),
|
||||
// NodeInput::value(TaggedValue::Curve(Default::default()), false),
|
||||
// ],
|
||||
// ..Default::default()
|
||||
@@ -1219,7 +1219,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
exports: vec![NodeInput::node(NodeId(1), 0)],
|
||||
nodes: vec![
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::network(concrete!(Table<VectorData>), 0)],
|
||||
inputs: vec![NodeInput::network(concrete!(Table<Vector>), 0)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(memo::monitor::IDENTIFIER),
|
||||
manual_composition: Some(generic!(T)),
|
||||
skip_deduplication: true,
|
||||
@@ -1243,14 +1243,14 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
..Default::default()
|
||||
}),
|
||||
inputs: vec![
|
||||
NodeInput::value(TaggedValue::VectorData(Default::default()), true),
|
||||
NodeInput::value(TaggedValue::Vector(Default::default()), true),
|
||||
NodeInput::value(TaggedValue::VectorModification(Default::default()), false),
|
||||
],
|
||||
..Default::default()
|
||||
},
|
||||
persistent_node_metadata: DocumentNodePersistentMetadata {
|
||||
input_metadata: vec![("Vector Data", "TODO").into(), ("Modification", "TODO").into()],
|
||||
output_names: vec!["Vector Data".to_string()],
|
||||
input_metadata: vec![("Content", "TODO").into(), ("Modification", "TODO").into()],
|
||||
output_names: vec!["Modified".to_string()],
|
||||
network_metadata: Some(NodeNetworkMetadata {
|
||||
persistent_metadata: NodeNetworkPersistentMetadata {
|
||||
node_metadata: [
|
||||
@@ -1374,7 +1374,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
}),
|
||||
),
|
||||
InputMetadata::with_name_description_override("Align", "TODO", WidgetOverride::Custom("text_align".to_string())),
|
||||
("Per-Glyph Instances", "Splits each text glyph into its own row in the table of vector data.").into(),
|
||||
("Per-Glyph Instances", "Splits each text glyph into its own row in the table of vector geometry.").into(),
|
||||
],
|
||||
output_names: vec!["Vector".to_string()],
|
||||
..Default::default()
|
||||
@@ -1496,7 +1496,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
exports: vec![NodeInput::node(NodeId(3), 0)],
|
||||
nodes: vec![
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::network(concrete!(Table<VectorData>), 0), NodeInput::network(concrete!(vector::style::Fill), 1)],
|
||||
inputs: vec![NodeInput::network(concrete!(Table<Vector>), 0), NodeInput::network(concrete!(vector::style::Fill), 1)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(path_bool::boolean_operation::IDENTIFIER),
|
||||
manual_composition: Some(generic!(T)),
|
||||
..Default::default()
|
||||
@@ -1527,7 +1527,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
..Default::default()
|
||||
}),
|
||||
inputs: vec![
|
||||
NodeInput::value(TaggedValue::GraphicGroup(Default::default()), true),
|
||||
NodeInput::value(TaggedValue::Group(Default::default()), true),
|
||||
NodeInput::value(TaggedValue::BooleanOperation(path_bool::BooleanOperation::Union), false),
|
||||
],
|
||||
..Default::default()
|
||||
@@ -1594,14 +1594,14 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
exports: vec![NodeInput::node(NodeId(4), 0)],
|
||||
nodes: [
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::network(concrete!(Table<VectorData>), 0)],
|
||||
inputs: vec![NodeInput::network(concrete!(Table<Vector>), 0)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(vector::subpath_segment_lengths::IDENTIFIER),
|
||||
manual_composition: Some(generic!(T)),
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNode {
|
||||
inputs: vec![
|
||||
NodeInput::network(concrete!(Table<VectorData>), 0),
|
||||
NodeInput::network(concrete!(Table<Vector>), 0),
|
||||
NodeInput::network(concrete!(vector::misc::PointSpacingType), 1),
|
||||
NodeInput::network(concrete!(f64), 2),
|
||||
NodeInput::network(concrete!(u32), 3),
|
||||
@@ -1640,7 +1640,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
..Default::default()
|
||||
}),
|
||||
inputs: vec![
|
||||
NodeInput::value(TaggedValue::VectorData(Default::default()), true),
|
||||
NodeInput::value(TaggedValue::Vector(Default::default()), true),
|
||||
NodeInput::value(TaggedValue::PointSpacingType(Default::default()), false),
|
||||
NodeInput::value(TaggedValue::F64(100.), false),
|
||||
NodeInput::value(TaggedValue::U32(100), false),
|
||||
@@ -1704,7 +1704,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
..Default::default()
|
||||
}),
|
||||
input_metadata: vec![
|
||||
("Vector Data", "The shape to be resampled and converted into a polyline.").into(),
|
||||
("Content", "The shape to be resampled and converted into a polyline.").into(),
|
||||
("Spacing", node_properties::SAMPLE_POLYLINE_TOOLTIP_SPACING).into(),
|
||||
InputMetadata::with_name_description_override(
|
||||
"Separation",
|
||||
@@ -1761,7 +1761,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
nodes: [
|
||||
DocumentNode {
|
||||
inputs: vec![
|
||||
NodeInput::network(concrete!(Table<VectorData>), 0),
|
||||
NodeInput::network(concrete!(Table<Vector>), 0),
|
||||
NodeInput::network(concrete!(f64), 1),
|
||||
NodeInput::network(concrete!(u32), 2),
|
||||
],
|
||||
@@ -1795,7 +1795,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
..Default::default()
|
||||
}),
|
||||
inputs: vec![
|
||||
NodeInput::value(TaggedValue::VectorData(Default::default()), true),
|
||||
NodeInput::value(TaggedValue::Vector(Default::default()), true),
|
||||
NodeInput::value(TaggedValue::F64(10.), false),
|
||||
NodeInput::value(TaggedValue::U32(0), false),
|
||||
],
|
||||
@@ -1847,7 +1847,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
..Default::default()
|
||||
}),
|
||||
input_metadata: vec![
|
||||
("Vector Data", "TODO").into(),
|
||||
("Content", "TODO").into(),
|
||||
InputMetadata::with_name_description_override(
|
||||
"Separation Disk Diameter",
|
||||
"TODO",
|
||||
|
||||
@@ -11,6 +11,7 @@ use glam::{DAffine2, DVec2};
|
||||
use graph_craft::Type;
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graph_craft::document::{DocumentNode, DocumentNodeImplementation, NodeId, NodeInput};
|
||||
use graphene_std::NodeInputDecleration;
|
||||
use graphene_std::animation::RealTimeMode;
|
||||
use graphene_std::extract_xy::XY;
|
||||
use graphene_std::path_bool::BooleanOperation;
|
||||
@@ -19,14 +20,10 @@ use graphene_std::raster::{
|
||||
BlendMode, CellularDistanceFunction, CellularReturnType, Color, DomainWarpType, FractalType, LuminanceCalculation, NoiseType, RedGreenBlue, RedGreenBlueAlpha, RelativeAbsolute,
|
||||
SelectiveColorChoice,
|
||||
};
|
||||
use graphene_std::raster_types::{CPU, GPU, Raster};
|
||||
use graphene_std::table::Table;
|
||||
use graphene_std::text::{Font, TextAlign};
|
||||
use graphene_std::transform::{Footprint, ReferencePoint, Transform};
|
||||
use graphene_std::vector::VectorData;
|
||||
use graphene_std::vector::misc::{ArcType, CentroidType, GridType, MergeByDistanceAlgorithm, PointSpacingType};
|
||||
use graphene_std::vector::style::{Fill, FillChoice, FillType, GradientStops, GradientType, PaintOrder, StrokeAlign, StrokeCap, StrokeJoin};
|
||||
use graphene_std::{Graphic, NodeInputDecleration};
|
||||
|
||||
pub(crate) fn string_properties(text: &str) -> Vec<LayoutGroup> {
|
||||
let widget = TextLabel::new(text).widget_holder();
|
||||
@@ -180,12 +177,6 @@ pub(crate) fn property_from_type(
|
||||
// ==========================
|
||||
Some(x) if x == TypeId::of::<Vec<f64>>() => array_of_number_widget(default_info, TextInput::default()).into(),
|
||||
Some(x) if x == TypeId::of::<Vec<DVec2>>() => array_of_vec2_widget(default_info, TextInput::default()).into(),
|
||||
// ====================
|
||||
// GRAPHICAL DATA TYPES
|
||||
// ====================
|
||||
Some(x) if x == TypeId::of::<Table<VectorData>>() => vector_data_widget(default_info).into(),
|
||||
Some(x) if x == TypeId::of::<Table<Raster<CPU>>>() || x == TypeId::of::<Table<Raster<GPU>>>() => raster_widget(default_info).into(),
|
||||
Some(x) if x == TypeId::of::<Table<Graphic>>() => group_widget(default_info).into(),
|
||||
// ============
|
||||
// STRUCT TYPES
|
||||
// ============
|
||||
@@ -794,33 +785,6 @@ pub fn font_inputs(parameter_widgets_info: ParameterWidgetsInfo) -> (Vec<WidgetH
|
||||
(first_widgets, second_widgets)
|
||||
}
|
||||
|
||||
pub fn vector_data_widget(parameter_widgets_info: ParameterWidgetsInfo) -> Vec<WidgetHolder> {
|
||||
let mut widgets = start_widgets(parameter_widgets_info);
|
||||
|
||||
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
||||
widgets.push(TextLabel::new("Vector data is supplied through the node graph").widget_holder());
|
||||
|
||||
widgets
|
||||
}
|
||||
|
||||
pub fn raster_widget(parameter_widgets_info: ParameterWidgetsInfo) -> Vec<WidgetHolder> {
|
||||
let mut widgets = start_widgets(parameter_widgets_info);
|
||||
|
||||
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
||||
widgets.push(TextLabel::new("Raster data is supplied through the node graph").widget_holder());
|
||||
|
||||
widgets
|
||||
}
|
||||
|
||||
pub fn group_widget(parameter_widgets_info: ParameterWidgetsInfo) -> Vec<WidgetHolder> {
|
||||
let mut widgets = start_widgets(parameter_widgets_info);
|
||||
|
||||
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
||||
widgets.push(TextLabel::new("Group data is supplied through the node graph").widget_holder());
|
||||
|
||||
widgets
|
||||
}
|
||||
|
||||
pub fn number_widget(parameter_widgets_info: ParameterWidgetsInfo, number_props: NumberInput) -> Vec<WidgetHolder> {
|
||||
let ParameterWidgetsInfo { document_node, node_id, index, .. } = parameter_widgets_info;
|
||||
|
||||
@@ -1880,7 +1844,7 @@ pub fn math_properties(node_id: NodeId, context: &mut NodePropertiesContext) ->
|
||||
let mut expression = x.value.trim().to_string();
|
||||
|
||||
if ["+", "-", "*", "/", "^", "%"].iter().any(|&infix| infix == expression) {
|
||||
expression = format!("A {} B", expression);
|
||||
expression = format!("A {expression} B");
|
||||
} else if expression == "^" {
|
||||
expression = String::from("A^B");
|
||||
}
|
||||
@@ -2078,7 +2042,7 @@ pub mod choice {
|
||||
pub fn property_row(self) -> LayoutGroup {
|
||||
let ParameterWidgetsInfo { document_node, node_id, index, .. } = self.parameter_info;
|
||||
let Some(document_node) = document_node else {
|
||||
log::error!("Could not get document node when building property row for node {:?}", node_id);
|
||||
log::error!("Could not get document node when building property row for node {node_id:?}");
|
||||
return LayoutGroup::Row { widgets: Vec::new() };
|
||||
};
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ pub enum FrontendGraphDataType {
|
||||
#[default]
|
||||
General,
|
||||
Raster,
|
||||
VectorData,
|
||||
Vector,
|
||||
Number,
|
||||
Group,
|
||||
Artboard,
|
||||
@@ -18,8 +18,8 @@ pub enum FrontendGraphDataType {
|
||||
impl FrontendGraphDataType {
|
||||
pub fn from_type(input: &Type) -> Self {
|
||||
match TaggedValue::from_type_or_none(input) {
|
||||
TaggedValue::RasterData(_) => Self::Raster,
|
||||
TaggedValue::VectorData(_) => Self::VectorData,
|
||||
TaggedValue::Raster(_) => Self::Raster,
|
||||
TaggedValue::Vector(_) => Self::Vector,
|
||||
TaggedValue::U32(_)
|
||||
| TaggedValue::U64(_)
|
||||
| TaggedValue::F64(_)
|
||||
@@ -28,8 +28,8 @@ impl FrontendGraphDataType {
|
||||
| TaggedValue::VecF64(_)
|
||||
| TaggedValue::VecDVec2(_)
|
||||
| TaggedValue::DAffine2(_) => Self::Number,
|
||||
TaggedValue::GraphicGroup(_) => Self::Group,
|
||||
TaggedValue::ArtboardGroup(_) => Self::Artboard,
|
||||
TaggedValue::Group(_) => Self::Group,
|
||||
TaggedValue::Artboard(_) => Self::Artboard,
|
||||
_ => Self::General,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use crate::messages::tool::common_functionality::shape_editor::{SelectedLayerSta
|
||||
use crate::messages::tool::tool_messages::tool_prelude::{DocumentMessageHandler, PreferencesMessageHandler};
|
||||
use bezier_rs::{Bezier, BezierHandles};
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graphene_std::vector::ManipulatorPointId;
|
||||
use graphene_std::vector::misc::ManipulatorPointId;
|
||||
use graphene_std::vector::{PointId, SegmentId};
|
||||
use wasm_bindgen::JsCast;
|
||||
|
||||
@@ -42,9 +42,9 @@ pub fn selected_segments(network_interface: &NodeNetworkInterface, shape_editor:
|
||||
// TODO: Currently if there are two duplicate layers, both of their segments get overlays
|
||||
// Adding segments which are are connected to selected anchors
|
||||
for layer in network_interface.selected_nodes().selected_layers(network_interface.document_metadata()) {
|
||||
let Some(vector_data) = network_interface.compute_modified_vector(layer) else { continue };
|
||||
let Some(vector) = network_interface.compute_modified_vector(layer) else { continue };
|
||||
|
||||
for (segment_id, _bezier, start, end) in vector_data.segment_bezier_iter() {
|
||||
for (segment_id, _bezier, start, end) in vector.segment_bezier_iter() {
|
||||
if selected_anchors.contains(&start) || selected_anchors.contains(&end) {
|
||||
selected_segments.push(segment_id);
|
||||
}
|
||||
@@ -118,14 +118,14 @@ pub fn path_overlays(document: &DocumentMessageHandler, draw_handles: DrawHandle
|
||||
let display_anchors = overlay_context.visibility_settings.anchors();
|
||||
|
||||
for layer in document.network_interface.selected_nodes().selected_layers(document.metadata()) {
|
||||
let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { continue };
|
||||
let Some(vector) = document.network_interface.compute_modified_vector(layer) else { continue };
|
||||
let transform = document.metadata().transform_to_viewport_if_feeds(layer, &document.network_interface);
|
||||
if display_path {
|
||||
overlay_context.outline_vector(&vector_data, transform);
|
||||
overlay_context.outline_vector(&vector, transform);
|
||||
}
|
||||
|
||||
// Get the selected segments and then add a bold line overlay on them
|
||||
for (segment_id, bezier, _, _) in vector_data.segment_bezier_iter() {
|
||||
for (segment_id, bezier, _, _) in vector.segment_bezier_iter() {
|
||||
let Some(selected_shape_state) = shape_editor.selected_shape_state.get_mut(&layer) else {
|
||||
continue;
|
||||
};
|
||||
@@ -139,30 +139,30 @@ pub fn path_overlays(document: &DocumentMessageHandler, draw_handles: DrawHandle
|
||||
let is_selected = |point: ManipulatorPointId| selected.is_some_and(|selected| selected.is_point_selected(point));
|
||||
|
||||
if display_handles {
|
||||
let opposite_handles_data: Vec<(PointId, SegmentId)> = shape_editor.selected_points().filter_map(|point_id| vector_data.adjacent_segment(point_id)).collect();
|
||||
let opposite_handles_data: Vec<(PointId, SegmentId)> = shape_editor.selected_points().filter_map(|point_id| vector.adjacent_segment(point_id)).collect();
|
||||
|
||||
match draw_handles {
|
||||
DrawHandles::All => {
|
||||
vector_data.segment_bezier_iter().for_each(|(segment_id, bezier, _start, _end)| {
|
||||
vector.segment_bezier_iter().for_each(|(segment_id, bezier, _start, _end)| {
|
||||
overlay_bezier_handles(bezier, segment_id, transform, is_selected, overlay_context);
|
||||
});
|
||||
}
|
||||
DrawHandles::SelectedAnchors(ref selected_segments) => {
|
||||
vector_data
|
||||
vector
|
||||
.segment_bezier_iter()
|
||||
.filter(|(segment_id, ..)| selected_segments.contains(segment_id))
|
||||
.for_each(|(segment_id, bezier, _start, _end)| {
|
||||
overlay_bezier_handles(bezier, segment_id, transform, is_selected, overlay_context);
|
||||
});
|
||||
|
||||
for (segment_id, bezier, start, end) in vector_data.segment_bezier_iter() {
|
||||
for (segment_id, bezier, start, end) in vector.segment_bezier_iter() {
|
||||
if let Some((corresponding_anchor, _)) = opposite_handles_data.iter().find(|(_, adj_segment_id)| adj_segment_id == &segment_id) {
|
||||
overlay_bezier_handle_specific_point(bezier, segment_id, (start, end), *corresponding_anchor, transform, is_selected, overlay_context);
|
||||
}
|
||||
}
|
||||
}
|
||||
DrawHandles::FrontierHandles(ref segment_endpoints) => {
|
||||
vector_data
|
||||
vector
|
||||
.segment_bezier_iter()
|
||||
.filter(|(segment_id, ..)| segment_endpoints.contains_key(segment_id))
|
||||
.for_each(|(segment_id, bezier, start, end)| {
|
||||
@@ -179,7 +179,7 @@ pub fn path_overlays(document: &DocumentMessageHandler, draw_handles: DrawHandle
|
||||
}
|
||||
|
||||
if display_anchors {
|
||||
for (&id, &position) in vector_data.point_domain.ids().iter().zip(vector_data.point_domain.positions()) {
|
||||
for (&id, &position) in vector.point_domain.ids().iter().zip(vector.point_domain.positions()) {
|
||||
overlay_context.manipulator_anchor(transform.transform_point2(position), is_selected(ManipulatorPointId::Anchor(id)), None);
|
||||
}
|
||||
}
|
||||
@@ -192,7 +192,7 @@ pub fn path_endpoint_overlays(document: &DocumentMessageHandler, shape_editor: &
|
||||
}
|
||||
|
||||
for layer in document.network_interface.selected_nodes().selected_layers(document.metadata()) {
|
||||
let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else {
|
||||
let Some(vector) = document.network_interface.compute_modified_vector(layer) else {
|
||||
continue;
|
||||
};
|
||||
//let document_to_viewport = document.navigation_handler.calculate_offset_transform(overlay_context.size / 2., &document.document_ptz);
|
||||
@@ -200,8 +200,8 @@ pub fn path_endpoint_overlays(document: &DocumentMessageHandler, shape_editor: &
|
||||
let selected = shape_editor.selected_shape_state.get(&layer);
|
||||
let is_selected = |selected: Option<&SelectedLayerState>, point: ManipulatorPointId| selected.is_some_and(|selected| selected.is_point_selected(point));
|
||||
|
||||
for point in vector_data.extendable_points(preferences.vector_meshes) {
|
||||
let Some(position) = vector_data.point_domain.position_from_id(point) else { continue };
|
||||
for point in vector.extendable_points(preferences.vector_meshes) {
|
||||
let Some(position) = vector.point_domain.position_from_id(point) else { continue };
|
||||
let position = transform.transform_point2(position);
|
||||
overlay_context.manipulator_anchor(position, is_selected(selected, ManipulatorPointId::Anchor(point)), None);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ use glam::{DAffine2, DVec2};
|
||||
use graphene_std::Color;
|
||||
use graphene_std::math::quad::Quad;
|
||||
use graphene_std::vector::click_target::ClickTargetType;
|
||||
use graphene_std::vector::{PointId, SegmentId, VectorData};
|
||||
use graphene_std::vector::{PointId, SegmentId, Vector};
|
||||
use std::collections::HashMap;
|
||||
use wasm_bindgen::{JsCast, JsValue};
|
||||
use web_sys::{OffscreenCanvas, OffscreenCanvasRenderingContext2d};
|
||||
@@ -757,12 +757,12 @@ impl OverlayContext {
|
||||
}
|
||||
|
||||
/// Used by the Pen and Path tools to outline the path of the shape.
|
||||
pub fn outline_vector(&mut self, vector_data: &VectorData, transform: DAffine2) {
|
||||
pub fn outline_vector(&mut self, vector: &Vector, transform: DAffine2) {
|
||||
self.start_dpi_aware_transform();
|
||||
|
||||
self.render_context.begin_path();
|
||||
let mut last_point = None;
|
||||
for (_, bezier, start_id, end_id) in vector_data.segment_bezier_iter() {
|
||||
for (_, bezier, start_id, end_id) in vector.segment_bezier_iter() {
|
||||
let move_to = last_point != Some(start_id);
|
||||
last_point = Some(end_id);
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ use glam::{DAffine2, DVec2};
|
||||
use graphene_std::Color;
|
||||
use graphene_std::math::quad::Quad;
|
||||
use graphene_std::vector::click_target::ClickTargetType;
|
||||
use graphene_std::vector::{PointId, SegmentId, VectorData};
|
||||
use graphene_std::vector::{PointId, SegmentId, Vector};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, Mutex, MutexGuard};
|
||||
use vello::Scene;
|
||||
@@ -338,8 +338,8 @@ impl OverlayContext {
|
||||
}
|
||||
|
||||
/// Used by the Pen and Path tools to outline the path of the shape.
|
||||
pub fn outline_vector(&mut self, vector_data: &VectorData, transform: DAffine2) {
|
||||
self.internal().outline_vector(vector_data, transform);
|
||||
pub fn outline_vector(&mut self, vector: &Vector, transform: DAffine2) {
|
||||
self.internal().outline_vector(vector, transform);
|
||||
}
|
||||
|
||||
/// Used by the Pen tool in order to show how the bezier curve would look like.
|
||||
@@ -834,12 +834,12 @@ impl OverlayContextInternal {
|
||||
}
|
||||
|
||||
/// Used by the Pen and Path tools to outline the path of the shape.
|
||||
fn outline_vector(&mut self, vector_data: &VectorData, transform: DAffine2) {
|
||||
fn outline_vector(&mut self, vector: &Vector, transform: DAffine2) {
|
||||
let vello_transform = self.get_transform();
|
||||
let mut path = BezPath::new();
|
||||
|
||||
let mut last_point = None;
|
||||
for (_, bezier, start_id, end_id) in vector_data.segment_bezier_iter() {
|
||||
for (_, bezier, start_id, end_id) in vector.segment_bezier_iter() {
|
||||
let move_to = last_point != Some(start_id);
|
||||
last_point = Some(end_id);
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ use graph_craft::document::NodeId;
|
||||
use graphene_std::math::quad::Quad;
|
||||
use graphene_std::transform::Footprint;
|
||||
use graphene_std::vector::click_target::{ClickTarget, ClickTargetType};
|
||||
use graphene_std::vector::{PointId, VectorData};
|
||||
use graphene_std::vector::{PointId, Vector};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::num::NonZeroU64;
|
||||
|
||||
@@ -26,7 +26,7 @@ pub struct DocumentMetadata {
|
||||
pub structure: HashMap<LayerNodeIdentifier, NodeRelations>,
|
||||
pub click_targets: HashMap<LayerNodeIdentifier, Vec<ClickTarget>>,
|
||||
pub clip_targets: HashSet<NodeId>,
|
||||
pub vector_modify: HashMap<NodeId, VectorData>,
|
||||
pub vector_modify: HashMap<NodeId, Vector>,
|
||||
/// Transform from document space to viewport space.
|
||||
pub document_to_viewport: DAffine2,
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ use graphene_std::math::quad::Quad;
|
||||
use graphene_std::table::Table;
|
||||
use graphene_std::transform::Footprint;
|
||||
use graphene_std::vector::click_target::{ClickTarget, ClickTargetType};
|
||||
use graphene_std::vector::{PointId, VectorData, VectorModificationType};
|
||||
use graphene_std::vector::{PointId, Vector, VectorModificationType};
|
||||
use interpreted_executor::dynamic_executor::ResolvedDocumentNodeTypes;
|
||||
use interpreted_executor::node_registry::NODE_REGISTRY;
|
||||
use serde_json::{Value, json};
|
||||
@@ -675,7 +675,7 @@ impl NodeNetworkInterface {
|
||||
let valid_implementation = (0..number_of_inputs).filter(|iterator_index| iterator_index != input_index).all(|iterator_index| {
|
||||
let input_type = self.input_type(&InputConnector::node(*node_id, iterator_index), network_path).0;
|
||||
// Value inputs are stored as concrete, so they are compared to the nested type. Node inputs are stored as fn, so they are compared to the entire type.
|
||||
// For example a node input of (Footprint) -> VectorData would not be compatible with () -> VectorData
|
||||
// For example a node input of (Footprint) -> Vector would not be compatible with () -> Vector
|
||||
node_io.inputs.get(iterator_index).map(|ty| ty.nested_type().clone()).as_ref() == Some(&input_type) || node_io.inputs.get(iterator_index) == Some(&input_type)
|
||||
});
|
||||
if valid_implementation { node_io.inputs.get(*input_index).cloned() } else { None }
|
||||
@@ -3444,12 +3444,12 @@ impl NodeNetworkInterface {
|
||||
(layer_widths, chain_widths, has_left_input_wire)
|
||||
}
|
||||
|
||||
pub fn compute_modified_vector(&self, layer: LayerNodeIdentifier) -> Option<VectorData> {
|
||||
pub fn compute_modified_vector(&self, layer: LayerNodeIdentifier) -> Option<Vector> {
|
||||
let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, self);
|
||||
|
||||
if let Some(path_node) = graph_layer.upstream_visible_node_id_from_name_in_layer("Path") {
|
||||
if let Some(vector_data) = self.document_metadata.vector_modify.get(&path_node) {
|
||||
let mut modified = vector_data.clone();
|
||||
if let Some(vector) = self.document_metadata.vector_modify.get(&path_node) {
|
||||
let mut modified = vector.clone();
|
||||
|
||||
let path_node = self.document_network().nodes.get(&path_node);
|
||||
let modification_input = path_node.and_then(|node: &DocumentNode| node.inputs.get(1)).and_then(|input| input.as_value());
|
||||
@@ -3464,7 +3464,7 @@ impl NodeNetworkInterface {
|
||||
.click_targets
|
||||
.get(&layer)
|
||||
.map(|click| click.iter().map(ClickTarget::target_type))
|
||||
.map(|target_types| VectorData::from_target_types(target_types, true))
|
||||
.map(|target_types| Vector::from_target_types(target_types, true))
|
||||
}
|
||||
|
||||
/// Loads the structure of layer nodes from a node graph.
|
||||
@@ -3575,7 +3575,7 @@ impl NodeNetworkInterface {
|
||||
}
|
||||
|
||||
/// Update the vector modify of the layers
|
||||
pub fn update_vector_modify(&mut self, new_vector_modify: HashMap<NodeId, VectorData>) {
|
||||
pub fn update_vector_modify(&mut self, new_vector_modify: HashMap<NodeId, Vector>) {
|
||||
self.document_metadata.vector_modify = new_vector_modify;
|
||||
}
|
||||
}
|
||||
@@ -6613,22 +6613,26 @@ fn migrate_output_names<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Re
|
||||
|
||||
const REPLACEMENTS: &[(&str, &str)] = &[
|
||||
// Single to table data
|
||||
("VectorData", "Table<VectorData>"),
|
||||
("GraphicGroup", "Table<GraphicGroup>"),
|
||||
("VectorData", "Table<Vector>"),
|
||||
("GraphicGroup", "Table<Group>"),
|
||||
("ImageFrame", "Table<Image>"),
|
||||
// `ImageFrame` to `Image` rename
|
||||
("Instances<ImageFrame>", "Table<Image>"),
|
||||
// `Instances` to `Table` rename
|
||||
("Instances<VectorData>", "Table<VectorData>"),
|
||||
("Instances<GraphicGroup>", "Table<GraphicGroup>"),
|
||||
("Instances<VectorData>", "Table<Vector>"),
|
||||
("Instances<GraphicGroup>", "Table<Group>"),
|
||||
("Instances<Image>", "Table<Image>"),
|
||||
("Instances<GraphicElement>", "Table<Graphic>"),
|
||||
("Table<GraphicElement>", "Table<Graphic>"),
|
||||
("Future<Instances<VectorData>>", "Future<Table<VectorData>>"),
|
||||
("Future<Instances<GraphicGroup>>", "Future<Table<GraphicGroup>>"),
|
||||
("Future<Instances<Vector>>", "Future<Table<Vector>>"),
|
||||
("Future<Instances<GraphicGroup>>", "Future<Table<Group>>"),
|
||||
("Future<Instances<Image>>", "Future<Table<Image>>"),
|
||||
("Future<Instances<GraphicElement>>", "Future<Table<Graphic>>"),
|
||||
("Future<Table<GraphicElement>>", "Future<Table<Graphic>>"),
|
||||
("Future<Table<VectorData>>", "Future<Table<Vector>>"),
|
||||
("Table<VectorData>", "Table<Vector>"),
|
||||
("Table<GraphicGroup>", "Table<Group>"),
|
||||
("Future<Table<GraphicGroup>>", "Future<Table<Group>>"),
|
||||
];
|
||||
|
||||
let mut names = Vec::<String>::deserialize(deserializer)?;
|
||||
|
||||
@@ -8,7 +8,8 @@ use crate::messages::tool::common_functionality::shape_editor::ShapeState;
|
||||
use crate::messages::tool::utility_types::ToolType;
|
||||
use glam::{DAffine2, DMat2, DVec2};
|
||||
use graphene_std::renderer::Quad;
|
||||
use graphene_std::vector::{HandleExt, HandleId, ManipulatorPointId, PointId, VectorModificationType};
|
||||
use graphene_std::vector::misc::{HandleId, ManipulatorPointId};
|
||||
use graphene_std::vector::{HandleExt, PointId, VectorModificationType};
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use std::f64::consts::PI;
|
||||
|
||||
@@ -79,7 +80,7 @@ impl OriginalTransforms {
|
||||
if path_map.contains_key(&layer) {
|
||||
continue;
|
||||
}
|
||||
let Some(vector_data) = network_interface.compute_modified_vector(layer) else {
|
||||
let Some(vector) = network_interface.compute_modified_vector(layer) else {
|
||||
continue;
|
||||
};
|
||||
let Some(selected_points) = shape_editor.selected_points_in_layer(layer) else {
|
||||
@@ -91,7 +92,7 @@ impl OriginalTransforms {
|
||||
|
||||
let mut selected_points = selected_points.clone();
|
||||
|
||||
for (segment_id, _, start, end) in vector_data.segment_bezier_iter() {
|
||||
for (segment_id, _, start, end) in vector.segment_bezier_iter() {
|
||||
if selected_segments.contains(&segment_id) {
|
||||
selected_points.insert(ManipulatorPointId::Anchor(start));
|
||||
selected_points.insert(ManipulatorPointId::Anchor(end));
|
||||
@@ -100,23 +101,23 @@ impl OriginalTransforms {
|
||||
|
||||
// Anchors also move their handles
|
||||
let anchor_ids = selected_points.iter().filter_map(|point| point.as_anchor());
|
||||
let anchors = anchor_ids.filter_map(|id| vector_data.point_domain.position_from_id(id).map(|pos| (id, AnchorPoint { initial: pos, current: pos })));
|
||||
let anchors = anchor_ids.filter_map(|id| vector.point_domain.position_from_id(id).map(|pos| (id, AnchorPoint { initial: pos, current: pos })));
|
||||
let anchors = anchors.collect();
|
||||
|
||||
let selected_handles = selected_points.iter().filter_map(|point| point.as_handle());
|
||||
let anchor_ids = selected_points.iter().filter_map(|point| point.as_anchor());
|
||||
let connected_handles = anchor_ids.flat_map(|point| vector_data.all_connected(point));
|
||||
let connected_handles = anchor_ids.flat_map(|point| vector.all_connected(point));
|
||||
let all_handles = selected_handles.chain(connected_handles);
|
||||
|
||||
let handles = all_handles
|
||||
.filter_map(|id| {
|
||||
let anchor = id.to_manipulator_point().get_anchor(&vector_data)?;
|
||||
let initial = id.to_manipulator_point().get_position(&vector_data)?;
|
||||
let relative = vector_data.point_domain.position_from_id(anchor)?;
|
||||
let other_handle = vector_data
|
||||
let anchor = id.to_manipulator_point().get_anchor(&vector)?;
|
||||
let initial = id.to_manipulator_point().get_position(&vector)?;
|
||||
let relative = vector.point_domain.position_from_id(anchor)?;
|
||||
let other_handle = vector
|
||||
.other_colinear_handle(id)
|
||||
.filter(|other| !selected_points.contains(&other.to_manipulator_point()) && !selected_points.contains(&ManipulatorPointId::Anchor(anchor)));
|
||||
let mirror = other_handle.and_then(|id| Some((id, id.to_manipulator_point().get_position(&vector_data)?)));
|
||||
let mirror = other_handle.and_then(|id| Some((id, id.to_manipulator_point().get_position(&vector)?)));
|
||||
|
||||
Some((id, HandlePoint { initial, relative, anchor, mirror }))
|
||||
})
|
||||
|
||||
@@ -13,7 +13,7 @@ use graphene_std::ProtoNodeIdentifier;
|
||||
use graphene_std::table::Table;
|
||||
use graphene_std::text::{TextAlign, TypesettingConfig};
|
||||
use graphene_std::uuid::NodeId;
|
||||
use graphene_std::vector::VectorData;
|
||||
use graphene_std::vector::Vector;
|
||||
use graphene_std::vector::style::{PaintOrder, StrokeAlign};
|
||||
use std::collections::HashMap;
|
||||
|
||||
@@ -38,12 +38,28 @@ const NODE_REPLACEMENTS: &[NodeReplacement<'static>] = &[
|
||||
aliases: &["graphene_core::ConstructArtboardNode", "graphene_core::graphic_element::ToArtboardNode"],
|
||||
},
|
||||
NodeReplacement {
|
||||
node: graphene_std::graphic_element::to_element::IDENTIFIER,
|
||||
node: graphene_std::graphic::to_element::IDENTIFIER,
|
||||
aliases: &["graphene_core::ToGraphicElementNode", "graphene_core::graphic_element::ToElementNode"],
|
||||
},
|
||||
NodeReplacement {
|
||||
node: graphene_std::graphic_element::to_group::IDENTIFIER,
|
||||
aliases: &["graphene_core::ToGraphicGroupNode"],
|
||||
node: graphene_std::graphic::to_group::IDENTIFIER,
|
||||
aliases: &["graphene_core::ToGraphicGroupNode", "graphene_core::graphic_element::ToGroupNode"],
|
||||
},
|
||||
NodeReplacement {
|
||||
node: graphene_std::graphic::layer::IDENTIFIER,
|
||||
aliases: &["graphene_core::graphic_element::LayerNode"],
|
||||
},
|
||||
NodeReplacement {
|
||||
node: graphene_std::graphic::flatten_group::IDENTIFIER,
|
||||
aliases: &["graphene_core::graphic_element::FlattenGroupNode"],
|
||||
},
|
||||
NodeReplacement {
|
||||
node: graphene_std::graphic::flatten_vector::IDENTIFIER,
|
||||
aliases: &["graphene_core::graphic_element::FlattenVectorNode"],
|
||||
},
|
||||
NodeReplacement {
|
||||
node: graphene_std::graphic::index::IDENTIFIER,
|
||||
aliases: &["graphene_core::graphic_element::IndexNode"],
|
||||
},
|
||||
// math_nodes
|
||||
NodeReplacement {
|
||||
@@ -456,6 +472,10 @@ const NODE_REPLACEMENTS: &[NodeReplacement<'static>] = &[
|
||||
node: graphene_std::path_bool::boolean_operation::IDENTIFIER,
|
||||
aliases: &["graphene_std::vector::BooleanOperationNode"],
|
||||
},
|
||||
NodeReplacement {
|
||||
node: graphene_std::vector::path_modify::IDENTIFIER,
|
||||
aliases: &["graphene_core::vector::vector_data::modification::PathModifyNode"],
|
||||
},
|
||||
// brush
|
||||
NodeReplacement {
|
||||
node: graphene_std::brush::brush::brush_stamp_generator::IDENTIFIER,
|
||||
@@ -591,13 +611,13 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
||||
return None;
|
||||
}
|
||||
|
||||
// Obtain the document node for the given node ID, extract the vector points, and create vector data from the list of points
|
||||
// Obtain the document node for the given node ID, extract the vector points, and create a Vector path from the list of points
|
||||
let node = document.network_interface.document_node(node_id, network_path)?;
|
||||
let Some(TaggedValue::VecDVec2(points)) = node.inputs.get(1).and_then(|tagged_value| tagged_value.as_value()) else {
|
||||
log::error!("The old Spline node's input at index 1 is not a TaggedValue::VecDVec2");
|
||||
return None;
|
||||
};
|
||||
let vector_data = VectorData::from_subpath(Subpath::from_anchors_linear(points.to_vec(), false));
|
||||
let vector = Vector::from_subpath(Subpath::from_anchors_linear(points.to_vec(), false));
|
||||
|
||||
// Retrieve the output connectors linked to the "Spline" node's output port
|
||||
let Some(spline_outputs) = document.network_interface.outward_wires(network_path)?.get(&OutputConnector::node(*node_id, 0)).cloned() else {
|
||||
@@ -611,13 +631,13 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
||||
return None;
|
||||
};
|
||||
|
||||
// Get the "Path" node definition and fill it in with the vector data and default vector modification
|
||||
// Get the "Path" node definition and fill it in with the Vector path and default vector modification
|
||||
let Some(path_node_type) = resolve_document_node_type("Path") else {
|
||||
log::error!("Path node does not exist.");
|
||||
return None;
|
||||
};
|
||||
let path_node = path_node_type.node_template_input_override([
|
||||
Some(NodeInput::value(TaggedValue::VectorData(Table::new_from_element(vector_data)), true)),
|
||||
Some(NodeInput::value(TaggedValue::Vector(Table::new_from_element(vector)), true)),
|
||||
Some(NodeInput::value(TaggedValue::VectorModification(Default::default()), false)),
|
||||
]);
|
||||
|
||||
|
||||
@@ -29,7 +29,8 @@ use graph_craft::document::NodeId;
|
||||
use graphene_std::Color;
|
||||
use graphene_std::renderer::Quad;
|
||||
use graphene_std::text::Font;
|
||||
use graphene_std::vector::{HandleId, PointId, SegmentId, VectorData, VectorModificationType};
|
||||
use graphene_std::vector::misc::HandleId;
|
||||
use graphene_std::vector::{PointId, SegmentId, Vector, VectorModificationType};
|
||||
use std::vec;
|
||||
|
||||
#[derive(ExtractField)]
|
||||
@@ -567,7 +568,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
||||
|
||||
// If not using Path tool, create new layers and add paths into those
|
||||
if let Some(document) = self.active_document() {
|
||||
let Ok(data) = serde_json::from_str::<Vec<(LayerNodeIdentifier, VectorData, DAffine2)>>(&data) else {
|
||||
let Ok(data) = serde_json::from_str::<Vec<(LayerNodeIdentifier, Vector, DAffine2)>>(&data) else {
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -603,7 +604,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
||||
let stroke = graphene_std::vector::style::Stroke::new(Some(stroke_color.to_gamma_srgb()), DEFAULT_STROKE_WIDTH);
|
||||
responses.add(GraphOperationMessage::StrokeSet { layer, stroke });
|
||||
|
||||
// Create new point ids and add those into the existing vector data
|
||||
// Create new point ids and add those into the existing Vector path
|
||||
let mut points_map = HashMap::new();
|
||||
for (point, position) in new_vector.point_domain.iter() {
|
||||
let new_point_id = PointId::generate();
|
||||
@@ -612,7 +613,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
||||
responses.add(GraphOperationMessage::Vector { layer, modification_type });
|
||||
}
|
||||
|
||||
// Create new segment ids and add the segments into the existing vector data
|
||||
// Create new segment ids and add the segments into the existing Vector path
|
||||
let mut segments_map = HashMap::new();
|
||||
for (segment_id, bezier, start, end) in new_vector.segment_bezier_iter() {
|
||||
let new_segment_id = SegmentId::generate();
|
||||
|
||||
@@ -19,13 +19,13 @@ pub enum SpreadsheetMessage {
|
||||
len: usize,
|
||||
},
|
||||
|
||||
ViewVectorDataDomain {
|
||||
domain: VectorDataDomain,
|
||||
ViewVectorDomain {
|
||||
domain: VectorDomain,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Default, Debug, serde::Serialize, serde::Deserialize)]
|
||||
pub enum VectorDataDomain {
|
||||
pub enum VectorDomain {
|
||||
#[default]
|
||||
Points,
|
||||
Segments,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use super::VectorDataDomain;
|
||||
use super::VectorDomain;
|
||||
use crate::messages::layout::utility_types::layout_widget::{Layout, LayoutGroup, LayoutTarget, WidgetLayout};
|
||||
use crate::messages::prelude::*;
|
||||
use crate::messages::tool::tool_messages::tool_prelude::*;
|
||||
@@ -8,7 +8,7 @@ use graphene_std::Context;
|
||||
use graphene_std::memo::IORecord;
|
||||
use graphene_std::raster::Image;
|
||||
use graphene_std::table::Table;
|
||||
use graphene_std::vector::VectorData;
|
||||
use graphene_std::vector::Vector;
|
||||
use graphene_std::{Artboard, Graphic};
|
||||
use std::any::Any;
|
||||
use std::sync::Arc;
|
||||
@@ -21,7 +21,7 @@ pub struct SpreadsheetMessageHandler {
|
||||
inspect_node: Option<NodeId>,
|
||||
introspected_data: Option<Arc<dyn Any + Send + Sync>>,
|
||||
element_path: Vec<usize>,
|
||||
viewing_vector_data_domain: VectorDataDomain,
|
||||
viewing_vector_domain: VectorDomain,
|
||||
}
|
||||
|
||||
#[message_handler_data]
|
||||
@@ -54,8 +54,8 @@ impl MessageHandler<SpreadsheetMessage, ()> for SpreadsheetMessageHandler {
|
||||
self.update_layout(responses);
|
||||
}
|
||||
|
||||
SpreadsheetMessage::ViewVectorDataDomain { domain } => {
|
||||
self.viewing_vector_data_domain = domain;
|
||||
SpreadsheetMessage::ViewVectorDomain { domain } => {
|
||||
self.viewing_vector_domain = domain;
|
||||
self.update_layout(responses);
|
||||
}
|
||||
}
|
||||
@@ -79,7 +79,7 @@ impl SpreadsheetMessageHandler {
|
||||
current_depth: 0,
|
||||
desired_path: &mut self.element_path,
|
||||
breadcrumbs: Vec::new(),
|
||||
vector_data_domain: self.viewing_vector_data_domain,
|
||||
vector_domain: self.viewing_vector_domain,
|
||||
};
|
||||
let mut layout = self
|
||||
.introspected_data
|
||||
@@ -106,7 +106,7 @@ struct LayoutData<'a> {
|
||||
current_depth: usize,
|
||||
desired_path: &'a mut Vec<usize>,
|
||||
breadcrumbs: Vec<String>,
|
||||
vector_data_domain: VectorDataDomain,
|
||||
vector_domain: VectorDomain,
|
||||
}
|
||||
|
||||
fn generate_layout(introspected_data: &Arc<dyn std::any::Any + Send + Sync + 'static>, data: &mut LayoutData) -> Option<Vec<LayoutGroup>> {
|
||||
@@ -116,9 +116,9 @@ fn generate_layout(introspected_data: &Arc<dyn std::any::Any + Send + Sync + 'st
|
||||
Some(io.output.layout_with_breadcrumb(data))
|
||||
} else if let Some(io) = introspected_data.downcast_ref::<IORecord<(), Table<Artboard>>>() {
|
||||
Some(io.output.layout_with_breadcrumb(data))
|
||||
} else if let Some(io) = introspected_data.downcast_ref::<IORecord<Context, Table<VectorData>>>() {
|
||||
} else if let Some(io) = introspected_data.downcast_ref::<IORecord<Context, Table<Vector>>>() {
|
||||
Some(io.output.layout_with_breadcrumb(data))
|
||||
} else if let Some(io) = introspected_data.downcast_ref::<IORecord<(), Table<VectorData>>>() {
|
||||
} else if let Some(io) = introspected_data.downcast_ref::<IORecord<(), Table<Vector>>>() {
|
||||
Some(io.output.layout_with_breadcrumb(data))
|
||||
} else if let Some(io) = introspected_data.downcast_ref::<IORecord<Context, Table<Graphic>>>() {
|
||||
Some(io.output.layout_with_breadcrumb(data))
|
||||
@@ -154,10 +154,10 @@ impl TableRowLayout for Graphic {
|
||||
}
|
||||
fn identifier(&self) -> String {
|
||||
match self {
|
||||
Self::GraphicGroup(table) => table.identifier(),
|
||||
Self::VectorData(table) => table.identifier(),
|
||||
Self::RasterDataCPU(_) => "RasterDataCPU".to_string(),
|
||||
Self::RasterDataGPU(_) => "RasterDataGPU".to_string(),
|
||||
Self::Group(group) => group.identifier(),
|
||||
Self::Vector(vector) => vector.identifier(),
|
||||
Self::RasterCPU(_) => "Raster (on CPU)".to_string(),
|
||||
Self::RasterGPU(_) => "Raster (on GPU)".to_string(),
|
||||
}
|
||||
}
|
||||
// Don't put a breadcrumb for Graphic
|
||||
@@ -166,48 +166,48 @@ impl TableRowLayout for Graphic {
|
||||
}
|
||||
fn compute_layout(&self, data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
match self {
|
||||
Self::GraphicGroup(table) => table.layout_with_breadcrumb(data),
|
||||
Self::VectorData(table) => table.layout_with_breadcrumb(data),
|
||||
Self::RasterDataCPU(_) => label("Raster is not supported"),
|
||||
Self::RasterDataGPU(_) => label("Raster is not supported"),
|
||||
Self::Group(table) => table.layout_with_breadcrumb(data),
|
||||
Self::Vector(table) => table.layout_with_breadcrumb(data),
|
||||
Self::RasterCPU(_) => label("Raster is not supported"),
|
||||
Self::RasterGPU(_) => label("Raster is not supported"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TableRowLayout for VectorData {
|
||||
impl TableRowLayout for Vector {
|
||||
fn type_name() -> &'static str {
|
||||
"VectorData"
|
||||
"Vector"
|
||||
}
|
||||
fn identifier(&self) -> String {
|
||||
format!("Vector Data (points={}, segments={})", self.point_domain.ids().len(), self.segment_domain.ids().len())
|
||||
format!("Vector ({} points, {} segments)", self.point_domain.ids().len(), self.segment_domain.ids().len())
|
||||
}
|
||||
fn compute_layout(&self, data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
let colinear = self.colinear_manipulators.iter().map(|[a, b]| format!("[{a} / {b}]")).collect::<Vec<_>>().join(", ");
|
||||
let colinear = if colinear.is_empty() { "None" } else { &colinear };
|
||||
let style = vec![
|
||||
TextLabel::new(format!(
|
||||
"{}\n\nColinear Handle IDs: {}\n\nUpstream Graphic Group Table: {}",
|
||||
"{}\n\nColinear Handle IDs: {}\n\nUpstream Group Table: {}",
|
||||
self.style,
|
||||
colinear,
|
||||
if self.upstream_graphic_group.is_some() { "Yes" } else { "No" }
|
||||
if self.upstream_group.is_some() { "Yes" } else { "No" }
|
||||
))
|
||||
.multiline(true)
|
||||
.widget_holder(),
|
||||
];
|
||||
|
||||
let domain_entries = [VectorDataDomain::Points, VectorDataDomain::Segments, VectorDataDomain::Regions]
|
||||
let domain_entries = [VectorDomain::Points, VectorDomain::Segments, VectorDomain::Regions]
|
||||
.into_iter()
|
||||
.map(|domain| {
|
||||
RadioEntryData::new(format!("{domain:?}"))
|
||||
.label(format!("{domain:?}"))
|
||||
.on_update(move |_| SpreadsheetMessage::ViewVectorDataDomain { domain }.into())
|
||||
.on_update(move |_| SpreadsheetMessage::ViewVectorDomain { domain }.into())
|
||||
})
|
||||
.collect();
|
||||
let domain = vec![RadioInput::new(domain_entries).selected_index(Some(data.vector_data_domain as u32)).widget_holder()];
|
||||
let domain = vec![RadioInput::new(domain_entries).selected_index(Some(data.vector_domain as u32)).widget_holder()];
|
||||
|
||||
let mut table_rows = Vec::new();
|
||||
match data.vector_data_domain {
|
||||
VectorDataDomain::Points => {
|
||||
match data.vector_domain {
|
||||
VectorDomain::Points => {
|
||||
table_rows.push(column_headings(&["", "position"]));
|
||||
table_rows.extend(
|
||||
self.point_domain
|
||||
@@ -215,7 +215,7 @@ impl TableRowLayout for VectorData {
|
||||
.map(|(id, position)| vec![TextLabel::new(format!("{}", id.inner())).widget_holder(), TextLabel::new(format!("{}", position)).widget_holder()]),
|
||||
);
|
||||
}
|
||||
VectorDataDomain::Segments => {
|
||||
VectorDomain::Segments => {
|
||||
table_rows.push(column_headings(&["", "start_index", "end_index", "handles"]));
|
||||
table_rows.extend(self.segment_domain.iter().map(|(id, start, end, handles)| {
|
||||
vec![
|
||||
@@ -226,7 +226,7 @@ impl TableRowLayout for VectorData {
|
||||
]
|
||||
}));
|
||||
}
|
||||
VectorDataDomain::Regions => {
|
||||
VectorDomain::Regions => {
|
||||
table_rows.push(column_headings(&["", "segment_range", "fill"]));
|
||||
table_rows.extend(self.region_domain.iter().map(|(id, segment_range, fill)| {
|
||||
vec![
|
||||
@@ -263,7 +263,7 @@ impl TableRowLayout for Artboard {
|
||||
self.label.clone()
|
||||
}
|
||||
fn compute_layout(&self, data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
self.graphic_group.compute_layout(data)
|
||||
self.group.compute_layout(data)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,8 +14,9 @@ use graphene_std::raster::BlendMode;
|
||||
use graphene_std::raster_types::{CPU, GPU, Raster};
|
||||
use graphene_std::table::Table;
|
||||
use graphene_std::text::{Font, TypesettingConfig};
|
||||
use graphene_std::vector::misc::ManipulatorPointId;
|
||||
use graphene_std::vector::style::Gradient;
|
||||
use graphene_std::vector::{ManipulatorPointId, PointId, SegmentId, VectorModificationType};
|
||||
use graphene_std::vector::{PointId, SegmentId, VectorModificationType};
|
||||
use std::collections::VecDeque;
|
||||
|
||||
/// Returns the ID of the first Spline node in the horizontal flow which is not followed by a `Path` node, or `None` if none exists.
|
||||
@@ -34,7 +35,7 @@ pub fn merge_layers(document: &DocumentMessageHandler, first_layer: LayerNodeIde
|
||||
if first_layer == second_layer {
|
||||
return;
|
||||
}
|
||||
// Calculate the downstream transforms in order to bring the other vector data into the same layer space
|
||||
// Calculate the downstream transforms in order to bring the other vector geometry into the same layer space
|
||||
let first_layer_transform = document.metadata().downstream_transform_to_document(first_layer);
|
||||
let second_layer_transform = document.metadata().downstream_transform_to_document(second_layer);
|
||||
|
||||
@@ -162,24 +163,24 @@ pub fn merge_layers(document: &DocumentMessageHandler, first_layer: LayerNodeIde
|
||||
/// Merge the `first_endpoint` with `second_endpoint`.
|
||||
pub fn merge_points(document: &DocumentMessageHandler, layer: LayerNodeIdentifier, first_endpoint: PointId, second_endpont: PointId, responses: &mut VecDeque<Message>) {
|
||||
let transform = document.metadata().transform_to_document(layer);
|
||||
let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { return };
|
||||
let Some(vector) = document.network_interface.compute_modified_vector(layer) else { return };
|
||||
|
||||
let segment = vector_data.segment_bezier_iter().find(|(_, _, start, end)| *end == second_endpont || *start == second_endpont);
|
||||
let segment = vector.segment_bezier_iter().find(|(_, _, start, end)| *end == second_endpont || *start == second_endpont);
|
||||
let Some((segment, _, mut segment_start_point, mut segment_end_point)) = segment else {
|
||||
log::error!("Could not get the segment for second_endpoint.");
|
||||
return;
|
||||
};
|
||||
|
||||
let mut handles = [None; 2];
|
||||
if let Some(handle_position) = ManipulatorPointId::PrimaryHandle(segment).get_position(&vector_data) {
|
||||
let anchor_position = ManipulatorPointId::Anchor(segment_start_point).get_position(&vector_data).unwrap();
|
||||
if let Some(handle_position) = ManipulatorPointId::PrimaryHandle(segment).get_position(&vector) {
|
||||
let anchor_position = ManipulatorPointId::Anchor(segment_start_point).get_position(&vector).unwrap();
|
||||
let handle_position = transform.transform_point2(handle_position);
|
||||
let anchor_position = transform.transform_point2(anchor_position);
|
||||
let anchor_to_handle = handle_position - anchor_position;
|
||||
handles[0] = Some(anchor_to_handle);
|
||||
}
|
||||
if let Some(handle_position) = ManipulatorPointId::EndHandle(segment).get_position(&vector_data) {
|
||||
let anchor_position = ManipulatorPointId::Anchor(segment_end_point).get_position(&vector_data).unwrap();
|
||||
if let Some(handle_position) = ManipulatorPointId::EndHandle(segment).get_position(&vector) {
|
||||
let anchor_position = ManipulatorPointId::Anchor(segment_end_point).get_position(&vector).unwrap();
|
||||
let handle_position = transform.transform_point2(handle_position);
|
||||
let anchor_position = transform.transform_point2(anchor_position);
|
||||
let anchor_to_handle = handle_position - anchor_position;
|
||||
|
||||
@@ -8,7 +8,8 @@ use crate::messages::tool::tool_messages::path_tool::PathOptionsUpdate;
|
||||
use crate::messages::tool::tool_messages::select_tool::SelectOptionsUpdate;
|
||||
use crate::messages::tool::tool_messages::tool_prelude::*;
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graphene_std::{transform::ReferencePoint, vector::ManipulatorPointId};
|
||||
use graphene_std::transform::ReferencePoint;
|
||||
use graphene_std::vector::misc::ManipulatorPointId;
|
||||
use std::fmt;
|
||||
|
||||
pub fn pin_pivot_widget(active: bool, enabled: bool, source: PivotToolSource) -> WidgetHolder {
|
||||
|
||||
@@ -13,8 +13,8 @@ use crate::messages::tool::common_functionality::utility_functions::{is_intersec
|
||||
use crate::messages::tool::tool_messages::path_tool::{PathOverlayMode, PointSelectState};
|
||||
use bezier_rs::{Bezier, BezierHandles, Subpath, TValue};
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graphene_std::vector::{HandleExt, HandleId, SegmentId};
|
||||
use graphene_std::vector::{ManipulatorPointId, PointId, VectorData, VectorModificationType};
|
||||
use graphene_std::vector::misc::{HandleId, ManipulatorPointId};
|
||||
use graphene_std::vector::{HandleExt, PointId, SegmentId, Vector, VectorModificationType};
|
||||
use std::f64::consts::TAU;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
@@ -164,13 +164,13 @@ pub struct ShapeState {
|
||||
pub struct SelectedPointsInfo {
|
||||
pub points: Vec<ManipulatorPointInfo>,
|
||||
pub offset: DVec2,
|
||||
pub vector_data: VectorData,
|
||||
pub vector: Vector,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SelectedSegmentsInfo {
|
||||
pub segments: Vec<SegmentId>,
|
||||
pub vector_data: VectorData,
|
||||
pub vector: Vector,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
@@ -323,10 +323,10 @@ impl ClosestSegment {
|
||||
(handle1 - handle2).try_normalize()
|
||||
} else {
|
||||
let [first_point, last_point] = self.points();
|
||||
if let Some(vector_data) = document.network_interface.compute_modified_vector(self.layer()) {
|
||||
if let Some(vector) = document.network_interface.compute_modified_vector(self.layer()) {
|
||||
if let (Some(pos1), Some(pos2)) = (
|
||||
ManipulatorPointId::Anchor(first_point).get_position(&vector_data),
|
||||
ManipulatorPointId::Anchor(last_point).get_position(&vector_data),
|
||||
ManipulatorPointId::Anchor(first_point).get_position(&vector),
|
||||
ManipulatorPointId::Anchor(last_point).get_position(&vector),
|
||||
) {
|
||||
(pos1 - pos2).try_normalize()
|
||||
} else {
|
||||
@@ -373,13 +373,13 @@ impl ClosestSegment {
|
||||
|
||||
// If adjacent segments have colinear handles, their direction is changed but their handle lengths is preserved
|
||||
// TODO: Find something which is more appropriate
|
||||
let vector_data = document.network_interface.compute_modified_vector(self.layer())?;
|
||||
let vector = document.network_interface.compute_modified_vector(self.layer())?;
|
||||
|
||||
if break_colinear_molding {
|
||||
// Disable G1 continuity
|
||||
let other_handles = [
|
||||
restore_previous_handle_position(handle1, c1, start, &vector_data, layer, responses),
|
||||
restore_previous_handle_position(handle2, c2, end, &vector_data, layer, responses),
|
||||
restore_previous_handle_position(handle1, c1, start, &vector, layer, responses),
|
||||
restore_previous_handle_position(handle2, c2, end, &vector, layer, responses),
|
||||
];
|
||||
|
||||
// Store other HandleId in tool data to regain colinearity later
|
||||
@@ -390,15 +390,15 @@ impl ClosestSegment {
|
||||
}
|
||||
} else {
|
||||
// Move the colinear handles so that colinearity is maintained
|
||||
adjust_handle_colinearity(handle1, start, nc1, &vector_data, layer, responses);
|
||||
adjust_handle_colinearity(handle2, end, nc2, &vector_data, layer, responses);
|
||||
adjust_handle_colinearity(handle1, start, nc1, &vector, layer, responses);
|
||||
adjust_handle_colinearity(handle2, end, nc2, &vector, layer, responses);
|
||||
|
||||
if let Some(adjacent_handles) = temporary_adjacent_handles_while_molding {
|
||||
if let Some(other_handle1) = adjacent_handles[0] {
|
||||
restore_g1_continuity(handle1, other_handle1, nc1, start, &vector_data, layer, responses);
|
||||
restore_g1_continuity(handle1, other_handle1, nc1, start, &vector, layer, responses);
|
||||
}
|
||||
if let Some(other_handle2) = adjacent_handles[1] {
|
||||
restore_g1_continuity(handle2, other_handle2, nc2, end, &vector_data, layer, responses);
|
||||
restore_g1_continuity(handle2, other_handle2, nc2, end, &vector, layer, responses);
|
||||
}
|
||||
}
|
||||
None
|
||||
@@ -441,10 +441,10 @@ impl ShapeState {
|
||||
let (layer1, start_point) = all_selected_points[0];
|
||||
let (layer2, end_point) = all_selected_points[1];
|
||||
|
||||
let Some(vector_data1) = document.network_interface.compute_modified_vector(layer1) else { return };
|
||||
let Some(vector_data2) = document.network_interface.compute_modified_vector(layer2) else { return };
|
||||
let Some(vector1) = document.network_interface.compute_modified_vector(layer1) else { return };
|
||||
let Some(vector2) = document.network_interface.compute_modified_vector(layer2) else { return };
|
||||
|
||||
if vector_data1.all_connected(start_point).count() != 1 || vector_data2.all_connected(end_point).count() != 1 {
|
||||
if vector1.all_connected(start_point).count() != 1 || vector2.all_connected(end_point).count() != 1 {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -477,15 +477,9 @@ impl ShapeState {
|
||||
|
||||
// If no points are selected, try to find a single continuous subpath in each layer to connect the endpoints of
|
||||
for &layer in self.selected_shape_state.keys() {
|
||||
let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { continue };
|
||||
let Some(vector) = document.network_interface.compute_modified_vector(layer) else { continue };
|
||||
|
||||
let endpoints: Vec<PointId> = vector_data
|
||||
.point_domain
|
||||
.ids()
|
||||
.iter()
|
||||
.copied()
|
||||
.filter(|&point_id| vector_data.all_connected(point_id).count() == 1)
|
||||
.collect();
|
||||
let endpoints: Vec<PointId> = vector.point_domain.ids().iter().copied().filter(|&point_id| vector.all_connected(point_id).count() == 1).collect();
|
||||
|
||||
if endpoints.len() == 2 {
|
||||
let start_point = endpoints[0];
|
||||
@@ -515,29 +509,27 @@ impl ShapeState {
|
||||
let mut offset = mouse_delta;
|
||||
let mut best_snapped = SnappedPoint::infinite_snap(document.metadata().document_to_viewport.inverse().transform_point2(input.mouse.position));
|
||||
for (layer, state) in &self.selected_shape_state {
|
||||
let Some(vector_data) = document.network_interface.compute_modified_vector(*layer) else {
|
||||
continue;
|
||||
};
|
||||
let Some(vector) = document.network_interface.compute_modified_vector(*layer) else { continue };
|
||||
|
||||
let to_document = document.metadata().transform_to_document_if_feeds(*layer, &document.network_interface);
|
||||
|
||||
for &selected in &state.selected_points {
|
||||
let source = match selected {
|
||||
ManipulatorPointId::Anchor(_) if vector_data.colinear(selected) => SnapSource::Path(PathSnapSource::AnchorPointWithColinearHandles),
|
||||
ManipulatorPointId::Anchor(_) if vector.colinear(selected) => SnapSource::Path(PathSnapSource::AnchorPointWithColinearHandles),
|
||||
ManipulatorPointId::Anchor(_) => SnapSource::Path(PathSnapSource::AnchorPointWithFreeHandles),
|
||||
// TODO: This doesn't actually work for handles, instead handles enter the arm above for free handles
|
||||
ManipulatorPointId::PrimaryHandle(_) | ManipulatorPointId::EndHandle(_) => SnapSource::Path(PathSnapSource::HandlePoint),
|
||||
};
|
||||
|
||||
let Some(position) = selected.get_position(&vector_data) else { continue };
|
||||
let Some(position) = selected.get_position(&vector) else { continue };
|
||||
let mut point = SnapCandidatePoint::new_source(to_document.transform_point2(position) + mouse_delta, source);
|
||||
|
||||
if let Some(id) = selected.as_anchor() {
|
||||
for neighbor in vector_data.connected_points(id) {
|
||||
for neighbor in vector.connected_points(id) {
|
||||
if state.is_point_selected(ManipulatorPointId::Anchor(neighbor)) {
|
||||
continue;
|
||||
}
|
||||
let Some(position) = vector_data.point_domain.position_from_id(neighbor) else { continue };
|
||||
let Some(position) = vector.point_domain.position_from_id(neighbor) else { continue };
|
||||
point.neighbors.push(to_document.transform_point2(position));
|
||||
}
|
||||
}
|
||||
@@ -569,8 +561,8 @@ impl ShapeState {
|
||||
}
|
||||
|
||||
if let Some((layer, manipulator_point_id)) = self.find_nearest_visible_point_indices(network_interface, mouse_position, select_threshold, path_overlay_mode, frontier_handles_info) {
|
||||
let vector_data = network_interface.compute_modified_vector(layer)?;
|
||||
let point_position = manipulator_point_id.get_position(&vector_data)?;
|
||||
let vector = network_interface.compute_modified_vector(layer)?;
|
||||
let point_position = manipulator_point_id.get_position(&vector)?;
|
||||
|
||||
let selected_shape_state = self.selected_shape_state.get(&layer)?;
|
||||
let already_selected = selected_shape_state.is_point_selected(manipulator_point_id);
|
||||
@@ -600,7 +592,7 @@ impl ShapeState {
|
||||
.flat_map(|(layer, state)| state.selected_points.iter().map(|&point_id| ManipulatorPointInfo { layer: *layer, point_id }))
|
||||
.collect();
|
||||
|
||||
return Some(Some(SelectedPointsInfo { points, offset, vector_data }));
|
||||
return Some(Some(SelectedPointsInfo { points, offset, vector }));
|
||||
}
|
||||
None
|
||||
}
|
||||
@@ -623,13 +615,13 @@ impl ShapeState {
|
||||
if !point_editing_mode && matches!(manipulator_point_id, ManipulatorPointId::Anchor(_)) {
|
||||
return None;
|
||||
}
|
||||
let vector_data = network_interface.compute_modified_vector(layer)?;
|
||||
let point_position = manipulator_point_id.get_position(&vector_data)?;
|
||||
let vector = network_interface.compute_modified_vector(layer)?;
|
||||
let point_position = manipulator_point_id.get_position(&vector)?;
|
||||
|
||||
// Check if point is visible under current overlay mode or not
|
||||
let selected_segments = selected_segments(network_interface, self);
|
||||
let selected_points = self.selected_points().cloned().collect::<HashSet<_>>();
|
||||
if !is_visible_point(manipulator_point_id, &vector_data, path_overlay_mode, frontier_handles_info, selected_segments, &selected_points) {
|
||||
if !is_visible_point(manipulator_point_id, &vector, path_overlay_mode, frontier_handles_info, selected_segments, &selected_points) {
|
||||
return None;
|
||||
}
|
||||
|
||||
@@ -650,7 +642,7 @@ impl ShapeState {
|
||||
.flat_map(|(layer, state)| state.selected_points.iter().map(|&point_id| ManipulatorPointInfo { layer: *layer, point_id }))
|
||||
.collect();
|
||||
|
||||
let selection_info = SelectedPointsInfo { points, offset, vector_data };
|
||||
let selection_info = SelectedPointsInfo { points, offset, vector };
|
||||
|
||||
// Return the current selection state and info
|
||||
return Some((already_selected, Some(selection_info)));
|
||||
@@ -670,16 +662,14 @@ impl ShapeState {
|
||||
|
||||
/// Selects all anchors connected to the selected subpath, and deselects all handles, for the given layer.
|
||||
pub fn select_connected(&mut self, document: &DocumentMessageHandler, layer: LayerNodeIdentifier, mouse: DVec2, points: bool, segments: bool) {
|
||||
let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else {
|
||||
return;
|
||||
};
|
||||
let Some(vector) = document.network_interface.compute_modified_vector(layer) else { return };
|
||||
let to_viewport = document.metadata().transform_to_viewport_if_feeds(layer, &document.network_interface);
|
||||
let layer_mouse = to_viewport.inverse().transform_point2(mouse);
|
||||
let state = self.selected_shape_state.entry(layer).or_default();
|
||||
|
||||
let mut selected_stack = Vec::new();
|
||||
// Find all subpaths that have been clicked
|
||||
for stroke in vector_data.stroke_bezier_paths() {
|
||||
for stroke in vector.stroke_bezier_paths() {
|
||||
if stroke.contains_point(layer_mouse) {
|
||||
if let Some(first) = stroke.manipulator_groups().first() {
|
||||
selected_stack.push(first.id);
|
||||
@@ -691,12 +681,12 @@ impl ShapeState {
|
||||
if selected_stack.is_empty() {
|
||||
// Fall back on just selecting all points/segments in the layer
|
||||
if points {
|
||||
for &point in vector_data.point_domain.ids() {
|
||||
for &point in vector.point_domain.ids() {
|
||||
state.select_point(ManipulatorPointId::Anchor(point));
|
||||
}
|
||||
}
|
||||
if segments {
|
||||
for &segment in vector_data.segment_domain.ids() {
|
||||
for &segment in vector.segment_domain.ids() {
|
||||
state.select_segment(segment);
|
||||
}
|
||||
}
|
||||
@@ -708,7 +698,7 @@ impl ShapeState {
|
||||
while let Some(point) = selected_stack.pop() {
|
||||
if !connected_points.contains(&point) {
|
||||
connected_points.insert(point);
|
||||
selected_stack.extend(vector_data.connected_points(point));
|
||||
selected_stack.extend(vector.connected_points(point));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -717,7 +707,7 @@ impl ShapeState {
|
||||
}
|
||||
|
||||
if segments {
|
||||
for (id, _, start, end) in vector_data.segment_bezier_iter() {
|
||||
for (id, _, start, end) in vector.segment_bezier_iter() {
|
||||
if connected_points.contains(&start) || connected_points.contains(&end) {
|
||||
state.select_segment(id);
|
||||
}
|
||||
@@ -740,13 +730,11 @@ impl ShapeState {
|
||||
|
||||
/// Internal helper function that selects all anchors, and deselects all handles, for a layer given its [`LayerNodeIdentifier`] and [`SelectedLayerState`].
|
||||
fn select_all_anchors_in_layer_with_state(document: &DocumentMessageHandler, layer: LayerNodeIdentifier, state: &mut SelectedLayerState) {
|
||||
let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else {
|
||||
return;
|
||||
};
|
||||
let Some(vector) = document.network_interface.compute_modified_vector(layer) else { return };
|
||||
|
||||
state.clear_points();
|
||||
|
||||
for &point in vector_data.point_domain.ids() {
|
||||
for &point in vector.point_domain.ids() {
|
||||
state.select_point(ManipulatorPointId::Anchor(point))
|
||||
}
|
||||
}
|
||||
@@ -856,7 +844,7 @@ impl ShapeState {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn move_anchor(&self, point: PointId, vector_data: &VectorData, delta: DVec2, layer: LayerNodeIdentifier, selected: Option<&SelectedLayerState>, responses: &mut VecDeque<Message>) {
|
||||
pub fn move_anchor(&self, point: PointId, vector: &Vector, delta: DVec2, layer: LayerNodeIdentifier, selected: Option<&SelectedLayerState>, responses: &mut VecDeque<Message>) {
|
||||
// Move anchor
|
||||
responses.add(GraphOperationMessage::Vector {
|
||||
layer,
|
||||
@@ -864,8 +852,8 @@ impl ShapeState {
|
||||
});
|
||||
|
||||
// Move the other handle for a quadratic bezier
|
||||
for segment in vector_data.end_connected(point) {
|
||||
let Some((start, _end, bezier)) = vector_data.segment_points_from_id(segment) else { continue };
|
||||
for segment in vector.end_connected(point) {
|
||||
let Some((start, _end, bezier)) = vector.segment_points_from_id(segment) else { continue };
|
||||
|
||||
if let BezierHandles::Quadratic { handle } = bezier.handles {
|
||||
if selected.is_some_and(|selected| selected.is_point_selected(ManipulatorPointId::Anchor(start))) {
|
||||
@@ -894,18 +882,18 @@ impl ShapeState {
|
||||
return None;
|
||||
}
|
||||
|
||||
let vector_data = network_interface.compute_modified_vector(layer)?;
|
||||
let vector = network_interface.compute_modified_vector(layer)?;
|
||||
let transform = network_interface.document_metadata().transform_to_document_if_feeds(layer, network_interface).inverse();
|
||||
let position = transform.transform_point2(new_position);
|
||||
let current_position = point.get_position(&vector_data)?;
|
||||
let current_position = point.get_position(&vector)?;
|
||||
let delta = position - current_position;
|
||||
|
||||
match *point {
|
||||
ManipulatorPointId::Anchor(point) => self.move_anchor(point, &vector_data, delta, layer, None, responses),
|
||||
ManipulatorPointId::Anchor(point) => self.move_anchor(point, &vector, delta, layer, None, responses),
|
||||
ManipulatorPointId::PrimaryHandle(segment) => {
|
||||
self.move_primary(segment, delta, layer, responses);
|
||||
if let Some(handle) = point.as_handle() {
|
||||
if let Some(handles) = vector_data.colinear_manipulators.iter().find(|handles| handles[0] == handle || handles[1] == handle) {
|
||||
if let Some(handles) = vector.colinear_manipulators.iter().find(|handles| handles[0] == handle || handles[1] == handle) {
|
||||
let modification_type = VectorModificationType::SetG1Continuous { handles: *handles, enabled: false };
|
||||
responses.add(GraphOperationMessage::Vector { layer, modification_type });
|
||||
}
|
||||
@@ -914,7 +902,7 @@ impl ShapeState {
|
||||
ManipulatorPointId::EndHandle(segment) => {
|
||||
self.move_end(segment, delta, layer, responses);
|
||||
if let Some(handle) = point.as_handle() {
|
||||
if let Some(handles) = vector_data.colinear_manipulators.iter().find(|handles| handles[0] == handle || handles[1] == handle) {
|
||||
if let Some(handles) = vector.colinear_manipulators.iter().find(|handles| handles[0] == handle || handles[1] == handle) {
|
||||
let modification_type = VectorModificationType::SetG1Continuous { handles: *handles, enabled: false };
|
||||
responses.add(GraphOperationMessage::Vector { layer, modification_type });
|
||||
}
|
||||
@@ -948,28 +936,26 @@ impl ShapeState {
|
||||
if first_is_colinear { ManipulatorAngle::Colinear } else { ManipulatorAngle::Free }
|
||||
}
|
||||
|
||||
pub fn convert_manipulator_handles_to_colinear(&self, vector_data: &VectorData, point_id: PointId, responses: &mut VecDeque<Message>, layer: LayerNodeIdentifier) {
|
||||
let Some(anchor_position) = ManipulatorPointId::Anchor(point_id).get_position(vector_data) else {
|
||||
pub fn convert_manipulator_handles_to_colinear(&self, vector: &Vector, point_id: PointId, responses: &mut VecDeque<Message>, layer: LayerNodeIdentifier) {
|
||||
let Some(anchor_position) = ManipulatorPointId::Anchor(point_id).get_position(vector) else {
|
||||
return;
|
||||
};
|
||||
let handles = vector_data.all_connected(point_id).take(2).collect::<Vec<_>>();
|
||||
let non_zero_handles = handles.iter().filter(|handle| handle.length(vector_data) > 1e-6).count();
|
||||
let handles = vector.all_connected(point_id).take(2).collect::<Vec<_>>();
|
||||
let non_zero_handles = handles.iter().filter(|handle| handle.length(vector) > 1e-6).count();
|
||||
let handle_segments = handles.iter().map(|handles| handles.segment).collect::<Vec<_>>();
|
||||
|
||||
// Check if the anchor is connected to linear segments and has no handles
|
||||
let linear_segments = vector_data.connected_linear_segments(point_id) != 0;
|
||||
let linear_segments = vector.connected_linear_segments(point_id) != 0;
|
||||
|
||||
// Grab the next and previous manipulator groups by simply looking at the next / previous index
|
||||
let points = handles.iter().map(|handle| vector_data.other_point(handle.segment, point_id));
|
||||
let anchor_positions = points
|
||||
.map(|point| point.and_then(|point| ManipulatorPointId::Anchor(point).get_position(vector_data)))
|
||||
.collect::<Vec<_>>();
|
||||
let points = handles.iter().map(|handle| vector.other_point(handle.segment, point_id));
|
||||
let anchor_positions = points.map(|point| point.and_then(|point| ManipulatorPointId::Anchor(point).get_position(vector))).collect::<Vec<_>>();
|
||||
|
||||
let mut segment_angle = 0.;
|
||||
let mut segment_count = 0.;
|
||||
|
||||
for segment in &handle_segments {
|
||||
let Some(angle) = calculate_segment_angle(point_id, *segment, vector_data, false) else {
|
||||
let Some(angle) = calculate_segment_angle(point_id, *segment, vector, false) else {
|
||||
continue;
|
||||
};
|
||||
segment_angle += angle;
|
||||
@@ -1002,15 +988,15 @@ impl ShapeState {
|
||||
|
||||
if non_zero_handles != 0 && !linear_segments {
|
||||
let [a, b] = handles.as_slice() else { return };
|
||||
let (non_zero_handle, zero_handle) = if a.length(vector_data) > 1e-6 { (a, b) } else { (b, a) };
|
||||
let (non_zero_handle, zero_handle) = if a.length(vector) > 1e-6 { (a, b) } else { (b, a) };
|
||||
let Some(direction) = non_zero_handle
|
||||
.to_manipulator_point()
|
||||
.get_position(vector_data)
|
||||
.get_position(vector)
|
||||
.and_then(|position| (position - anchor_position).try_normalize())
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let new_position = -direction * non_zero_handle.length(vector_data);
|
||||
let new_position = -direction * non_zero_handle.length(vector);
|
||||
let modification_type = zero_handle.set_relative_position(new_position);
|
||||
responses.add(GraphOperationMessage::Vector { layer, modification_type });
|
||||
} else {
|
||||
@@ -1031,7 +1017,7 @@ impl ShapeState {
|
||||
responses.add(GraphOperationMessage::Vector { layer, modification_type });
|
||||
|
||||
// Create the opposite handle if it doesn't exist (if it is not a cubic segment)
|
||||
if handle.opposite().to_manipulator_point().get_position(vector_data).is_none() {
|
||||
if handle.opposite().to_manipulator_point().get_position(vector).is_none() {
|
||||
let modification_type = handle.opposite().set_relative_position(DVec2::ZERO);
|
||||
responses.add(GraphOperationMessage::Vector { layer, modification_type });
|
||||
}
|
||||
@@ -1050,36 +1036,34 @@ impl ShapeState {
|
||||
let mut skip_set = HashSet::new();
|
||||
|
||||
for (&layer, layer_state) in self.selected_shape_state.iter() {
|
||||
let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else {
|
||||
continue;
|
||||
};
|
||||
let Some(vector) = document.network_interface.compute_modified_vector(layer) else { continue };
|
||||
let transform = document.metadata().transform_to_document_if_feeds(layer, &document.network_interface);
|
||||
|
||||
for &point in layer_state.selected_points.iter() {
|
||||
// Skip a point which has more than 2 segments connected (vector meshes)
|
||||
if let ManipulatorPointId::Anchor(anchor) = point {
|
||||
if vector_data.all_connected(anchor).count() > 2 {
|
||||
if vector.all_connected(anchor).count() > 2 {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Here we take handles as the current handle and the most opposite non-colinear-handle
|
||||
|
||||
let is_handle_colinear = |handle: HandleId| -> bool { vector_data.colinear_manipulators.iter().any(|&handles| handles[0] == handle || handles[1] == handle) };
|
||||
let is_handle_colinear = |handle: HandleId| -> bool { vector.colinear_manipulators.iter().any(|&handles| handles[0] == handle || handles[1] == handle) };
|
||||
|
||||
let other_handles = if matches!(point, ManipulatorPointId::Anchor(_)) {
|
||||
point.get_handle_pair(&vector_data)
|
||||
point.get_handle_pair(&vector)
|
||||
} else {
|
||||
point.get_all_connected_handles(&vector_data).and_then(|handles| {
|
||||
point.get_all_connected_handles(&vector).and_then(|handles| {
|
||||
let mut non_colinear_handles = handles.iter().filter(|&handle| !is_handle_colinear(*handle)).clone().collect::<Vec<_>>();
|
||||
|
||||
// Sort these by angle from the current handle
|
||||
non_colinear_handles.sort_by(|&handle_a, &handle_b| {
|
||||
let anchor = point.get_anchor_position(&vector_data).expect("No anchor position for handle");
|
||||
let orig_handle_pos = point.get_position(&vector_data).expect("No handle position");
|
||||
let anchor = point.get_anchor_position(&vector).expect("No anchor position for handle");
|
||||
let orig_handle_pos = point.get_position(&vector).expect("No handle position");
|
||||
|
||||
let a_pos = handle_a.to_manipulator_point().get_position(&vector_data).expect("No handle position");
|
||||
let b_pos = handle_b.to_manipulator_point().get_position(&vector_data).expect("No handle position");
|
||||
let a_pos = handle_a.to_manipulator_point().get_position(&vector).expect("No handle position");
|
||||
let b_pos = handle_b.to_manipulator_point().get_position(&vector).expect("No handle position");
|
||||
|
||||
let v_orig = (orig_handle_pos - anchor).normalize_or_zero();
|
||||
|
||||
@@ -1112,13 +1096,13 @@ impl ShapeState {
|
||||
skip_set.insert(handles);
|
||||
|
||||
let [selected0, selected1] = handles.map(|handle| layer_state.selected_points.contains(&handle.to_manipulator_point()));
|
||||
let handle_positions = handles.map(|handle| handle.to_manipulator_point().get_position(&vector_data));
|
||||
let handle_positions = handles.map(|handle| handle.to_manipulator_point().get_position(&vector));
|
||||
|
||||
let Some(anchor_id) = point.get_anchor(&vector_data) else { continue };
|
||||
let Some(anchor) = vector_data.point_domain.position_from_id(anchor_id) else { continue };
|
||||
let Some(anchor_id) = point.get_anchor(&vector) else { continue };
|
||||
let Some(anchor) = vector.point_domain.position_from_id(anchor_id) else { continue };
|
||||
|
||||
let anchor_points = handles.map(|handle| vector_data.other_point(handle.segment, anchor_id));
|
||||
let anchor_positions = anchor_points.map(|point| point.and_then(|point| vector_data.point_domain.position_from_id(point)));
|
||||
let anchor_points = handles.map(|handle| vector.other_point(handle.segment, anchor_id));
|
||||
let anchor_positions = anchor_points.map(|point| point.and_then(|point| vector.point_domain.position_from_id(point)));
|
||||
|
||||
// If one handle is selected (but both exist), only move the other handle
|
||||
if let (true, [Some(pos0), Some(pos1)]) = ((selected0 ^ selected1), handle_positions) {
|
||||
@@ -1160,7 +1144,7 @@ impl ShapeState {
|
||||
responses.add(GraphOperationMessage::Vector { layer, modification_type });
|
||||
|
||||
// Create the opposite handle if it doesn't exist (if it is not a cubic segment)
|
||||
if handles[index].opposite().to_manipulator_point().get_position(&vector_data).is_none() {
|
||||
if handles[index].opposite().to_manipulator_point().get_position(&vector).is_none() {
|
||||
let modification_type = handles[index].opposite().set_relative_position(DVec2::ZERO);
|
||||
responses.add(GraphOperationMessage::Vector { layer, modification_type });
|
||||
}
|
||||
@@ -1187,7 +1171,7 @@ impl ShapeState {
|
||||
responses: &mut VecDeque<Message>,
|
||||
) {
|
||||
for (&layer, state) in &self.selected_shape_state {
|
||||
let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { continue };
|
||||
let Some(vector) = document.network_interface.compute_modified_vector(layer) else { continue };
|
||||
|
||||
let opposing_handles = handle_lengths.as_ref().and_then(|handle_lengths| handle_lengths.get(&layer));
|
||||
|
||||
@@ -1203,7 +1187,7 @@ impl ShapeState {
|
||||
// Make a new collection of anchor points which needs to be moved
|
||||
let mut affected_points = state.selected_points.clone();
|
||||
|
||||
for (segment_id, _, start, end) in vector_data.segment_bezier_iter() {
|
||||
for (segment_id, _, start, end) in vector.segment_bezier_iter() {
|
||||
if state.is_segment_selected(segment_id) {
|
||||
affected_points.insert(ManipulatorPointId::Anchor(start));
|
||||
affected_points.insert(ManipulatorPointId::Anchor(end));
|
||||
@@ -1217,28 +1201,28 @@ impl ShapeState {
|
||||
|
||||
let handle = match point {
|
||||
ManipulatorPointId::Anchor(point) => {
|
||||
self.move_anchor(point, &vector_data, delta, layer, Some(state), responses);
|
||||
self.move_anchor(point, &vector, delta, layer, Some(state), responses);
|
||||
continue;
|
||||
}
|
||||
ManipulatorPointId::PrimaryHandle(segment) => HandleId::primary(segment),
|
||||
ManipulatorPointId::EndHandle(segment) => HandleId::end(segment),
|
||||
};
|
||||
|
||||
let Some(anchor_id) = point.get_anchor(&vector_data) else { continue };
|
||||
let Some(anchor_id) = point.get_anchor(&vector) else { continue };
|
||||
if state.is_point_selected(ManipulatorPointId::Anchor(anchor_id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let Some(anchor_position) = vector_data.point_domain.position_from_id(anchor_id) else { continue };
|
||||
let Some(anchor_position) = vector.point_domain.position_from_id(anchor_id) else { continue };
|
||||
|
||||
let Some(handle_position) = point.get_position(&vector_data) else { continue };
|
||||
let Some(handle_position) = point.get_position(&vector) else { continue };
|
||||
let handle_position = handle_position + delta;
|
||||
|
||||
let modification_type = handle.set_relative_position(handle_position - anchor_position);
|
||||
|
||||
responses.add(GraphOperationMessage::Vector { layer, modification_type });
|
||||
|
||||
let Some(other) = vector_data.other_colinear_handle(handle) else { continue };
|
||||
let Some(other) = vector.other_colinear_handle(handle) else { continue };
|
||||
|
||||
if skip_opposite_handle {
|
||||
continue;
|
||||
@@ -1262,7 +1246,7 @@ impl ShapeState {
|
||||
} else {
|
||||
// TODO: Is this equivalent to `transform_to_document_space`? If changed, the before and after should be tested.
|
||||
let transform = document.metadata().document_to_viewport.inverse() * transform_to_viewport_space;
|
||||
let Some(other_position) = other.to_manipulator_point().get_position(&vector_data) else {
|
||||
let Some(other_position) = other.to_manipulator_point().get_position(&vector) else {
|
||||
continue;
|
||||
};
|
||||
let direction = transform.transform_vector2(handle_position - anchor_position).try_normalize();
|
||||
@@ -1284,9 +1268,9 @@ impl ShapeState {
|
||||
self.selected_shape_state
|
||||
.iter()
|
||||
.filter_map(|(&layer, state)| {
|
||||
let vector_data = document.network_interface.compute_modified_vector(layer)?;
|
||||
let vector = document.network_interface.compute_modified_vector(layer)?;
|
||||
let transform = document.metadata().transform_to_document_if_feeds(layer, &document.network_interface);
|
||||
let opposing_handle_lengths = vector_data
|
||||
let opposing_handle_lengths = vector
|
||||
.colinear_manipulators
|
||||
.iter()
|
||||
.filter_map(|&handles| {
|
||||
@@ -1294,7 +1278,7 @@ impl ShapeState {
|
||||
// i) Exactly one handle is selected.
|
||||
// ii) The anchor is not selected.
|
||||
|
||||
let anchor = handles[0].to_manipulator_point().get_anchor(&vector_data)?;
|
||||
let anchor = handles[0].to_manipulator_point().get_anchor(&vector)?;
|
||||
let anchor_selected = state.is_point_selected(ManipulatorPointId::Anchor(anchor));
|
||||
if anchor_selected {
|
||||
return None;
|
||||
@@ -1308,8 +1292,8 @@ impl ShapeState {
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
let opposing_handle_position = other.to_manipulator_point().get_position(&vector_data)?;
|
||||
let anchor_position = vector_data.point_domain.position_from_id(anchor)?;
|
||||
let opposing_handle_position = other.to_manipulator_point().get_position(&vector)?;
|
||||
let anchor_position = vector.point_domain.position_from_id(anchor)?;
|
||||
|
||||
let opposing_handle_length = transform.transform_vector2(opposing_handle_position - anchor_position).length();
|
||||
Some((other, opposing_handle_length))
|
||||
@@ -1320,15 +1304,15 @@ impl ShapeState {
|
||||
.collect::<HashMap<_, _>>()
|
||||
}
|
||||
|
||||
pub fn dissolve_segment(&self, responses: &mut VecDeque<Message>, layer: LayerNodeIdentifier, vector_data: &VectorData, segment: SegmentId, points: [PointId; 2]) {
|
||||
pub fn dissolve_segment(&self, responses: &mut VecDeque<Message>, layer: LayerNodeIdentifier, vector: &Vector, segment: SegmentId, points: [PointId; 2]) {
|
||||
// Checking which point is terminal point
|
||||
let is_point1_terminal = vector_data.connected_count(points[0]) == 1;
|
||||
let is_point2_terminal = vector_data.connected_count(points[1]) == 1;
|
||||
let is_point1_terminal = vector.connected_count(points[0]) == 1;
|
||||
let is_point2_terminal = vector.connected_count(points[1]) == 1;
|
||||
|
||||
// Delete the segment and terminal points
|
||||
let modification_type = VectorModificationType::RemoveSegment { id: segment };
|
||||
responses.add(GraphOperationMessage::Vector { layer, modification_type });
|
||||
for &handles in vector_data.colinear_manipulators.iter().filter(|handles| handles.iter().any(|handle| handle.segment == segment)) {
|
||||
for &handles in vector.colinear_manipulators.iter().filter(|handles| handles.iter().any(|handle| handle.segment == segment)) {
|
||||
let modification_type = VectorModificationType::SetG1Continuous { handles, enabled: false };
|
||||
responses.add(GraphOperationMessage::Vector { layer, modification_type });
|
||||
}
|
||||
@@ -1343,27 +1327,27 @@ impl ShapeState {
|
||||
}
|
||||
}
|
||||
|
||||
fn dissolve_anchor(anchor: PointId, responses: &mut VecDeque<Message>, layer: LayerNodeIdentifier, vector_data: &VectorData) -> Option<[(HandleId, PointId); 2]> {
|
||||
fn dissolve_anchor(anchor: PointId, responses: &mut VecDeque<Message>, layer: LayerNodeIdentifier, vector: &Vector) -> Option<[(HandleId, PointId); 2]> {
|
||||
// Delete point
|
||||
let modification_type = VectorModificationType::RemovePoint { id: anchor };
|
||||
responses.add(GraphOperationMessage::Vector { layer, modification_type });
|
||||
|
||||
// Delete connected segments
|
||||
for HandleId { segment, .. } in vector_data.all_connected(anchor) {
|
||||
for HandleId { segment, .. } in vector.all_connected(anchor) {
|
||||
let modification_type = VectorModificationType::RemoveSegment { id: segment };
|
||||
responses.add(GraphOperationMessage::Vector { layer, modification_type });
|
||||
for &handles in vector_data.colinear_manipulators.iter().filter(|handles| handles.iter().any(|handle| handle.segment == segment)) {
|
||||
for &handles in vector.colinear_manipulators.iter().filter(|handles| handles.iter().any(|handle| handle.segment == segment)) {
|
||||
let modification_type = VectorModificationType::SetG1Continuous { handles, enabled: false };
|
||||
responses.add(GraphOperationMessage::Vector { layer, modification_type });
|
||||
}
|
||||
}
|
||||
|
||||
// Add in new segment if possible
|
||||
let mut handles = ManipulatorPointId::Anchor(anchor).get_handle_pair(vector_data)?;
|
||||
let mut handles = ManipulatorPointId::Anchor(anchor).get_handle_pair(vector)?;
|
||||
handles.reverse();
|
||||
let opposites = handles.map(|handle| handle.opposite());
|
||||
|
||||
let [Some(start), Some(end)] = opposites.map(|opposite| opposite.to_manipulator_point().get_anchor(vector_data)) else {
|
||||
let [Some(start), Some(end)] = opposites.map(|opposite| opposite.to_manipulator_point().get_anchor(vector)) else {
|
||||
return None;
|
||||
};
|
||||
Some([(handles[0], start), (handles[1], end)])
|
||||
@@ -1374,17 +1358,15 @@ impl ShapeState {
|
||||
for (&layer, state) in &mut self.selected_shape_state {
|
||||
let mut missing_anchors = HashMap::new();
|
||||
let mut deleted_anchors = HashSet::new();
|
||||
let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else {
|
||||
continue;
|
||||
};
|
||||
let Some(vector) = document.network_interface.compute_modified_vector(layer) else { continue };
|
||||
|
||||
let selected_segments = &state.selected_segments;
|
||||
|
||||
for point in std::mem::take(&mut state.selected_points) {
|
||||
match point {
|
||||
ManipulatorPointId::Anchor(anchor) => {
|
||||
if let Some(handles) = Self::dissolve_anchor(anchor, responses, layer, &vector_data) {
|
||||
if !vector_data.all_connected(anchor).any(|a| selected_segments.contains(&a.segment)) && vector_data.all_connected(anchor).count() <= 2 {
|
||||
if let Some(handles) = Self::dissolve_anchor(anchor, responses, layer, &vector) {
|
||||
if !vector.all_connected(anchor).any(|a| selected_segments.contains(&a.segment)) && vector.all_connected(anchor).count() <= 2 {
|
||||
missing_anchors.insert(anchor, handles);
|
||||
}
|
||||
}
|
||||
@@ -1398,7 +1380,7 @@ impl ShapeState {
|
||||
responses.add(GraphOperationMessage::Vector { layer, modification_type });
|
||||
|
||||
// Disable the g1 continuous
|
||||
for &handles in &vector_data.colinear_manipulators {
|
||||
for &handles in &vector.colinear_manipulators {
|
||||
if handles.contains(&handle) {
|
||||
let modification_type = VectorModificationType::SetG1Continuous { handles, enabled: false };
|
||||
responses.add(GraphOperationMessage::Vector { layer, modification_type });
|
||||
@@ -1436,11 +1418,8 @@ impl ShapeState {
|
||||
// Grab the handles from the opposite side of the segment(s) being deleted and make it relative to the anchor
|
||||
let [handle_start, handle_end] = [start, end].map(|(handle, _)| {
|
||||
let handle = handle.opposite();
|
||||
let handle_position = handle.to_manipulator_point().get_position(&vector_data);
|
||||
let relative_position = handle
|
||||
.to_manipulator_point()
|
||||
.get_anchor(&vector_data)
|
||||
.and_then(|anchor| vector_data.point_domain.position_from_id(anchor));
|
||||
let handle_position = handle.to_manipulator_point().get_position(&vector);
|
||||
let relative_position = handle.to_manipulator_point().get_anchor(&vector).and_then(|anchor| vector.point_domain.position_from_id(anchor));
|
||||
handle_position.and_then(|handle| relative_position.map(|relative| handle - relative)).unwrap_or_default()
|
||||
});
|
||||
|
||||
@@ -1454,12 +1433,12 @@ impl ShapeState {
|
||||
|
||||
responses.add(GraphOperationMessage::Vector { layer, modification_type });
|
||||
|
||||
for &handles in vector_data.colinear_manipulators.iter() {
|
||||
for &handles in vector.colinear_manipulators.iter() {
|
||||
if !handles.iter().any(|&handle| handle == start.0.opposite() || handle == end.0.opposite()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let Some(anchor) = handles[0].to_manipulator_point().get_anchor(&vector_data) else { continue };
|
||||
let Some(anchor) = handles[0].to_manipulator_point().get_anchor(&vector) else { continue };
|
||||
let Some(other) = handles.iter().find(|&&handle| handle != start.0.opposite() && handle != end.0.opposite()) else {
|
||||
continue;
|
||||
};
|
||||
@@ -1482,13 +1461,11 @@ impl ShapeState {
|
||||
|
||||
pub fn delete_selected_segments(&mut self, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
for (&layer, state) in &self.selected_shape_state {
|
||||
let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else {
|
||||
continue;
|
||||
};
|
||||
let Some(vector) = document.network_interface.compute_modified_vector(layer) else { continue };
|
||||
|
||||
for (segment, _, start, end) in vector_data.segment_bezier_iter() {
|
||||
for (segment, _, start, end) in vector.segment_bezier_iter() {
|
||||
if state.selected_segments.contains(&segment) {
|
||||
self.dissolve_segment(responses, layer, &vector_data, segment, [start, end]);
|
||||
self.dissolve_segment(responses, layer, &vector, segment, [start, end]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1496,13 +1473,11 @@ impl ShapeState {
|
||||
|
||||
pub fn delete_hanging_selected_anchors(&mut self, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
for (&layer, state) in &self.selected_shape_state {
|
||||
let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else {
|
||||
continue;
|
||||
};
|
||||
let Some(vector) = document.network_interface.compute_modified_vector(layer) else { continue };
|
||||
|
||||
for point in &state.selected_points {
|
||||
if let ManipulatorPointId::Anchor(anchor) = point {
|
||||
if vector_data.all_connected(*anchor).all(|segment| state.is_segment_selected(segment.segment)) {
|
||||
if vector.all_connected(*anchor).all(|segment| state.is_segment_selected(segment.segment)) {
|
||||
let modification_type = VectorModificationType::RemovePoint { id: *anchor };
|
||||
responses.add(GraphOperationMessage::Vector { layer, modification_type });
|
||||
}
|
||||
@@ -1513,16 +1488,16 @@ impl ShapeState {
|
||||
|
||||
pub fn break_path_at_selected_point(&self, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
for (&layer, state) in &self.selected_shape_state {
|
||||
let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { continue };
|
||||
let Some(vector) = document.network_interface.compute_modified_vector(layer) else { continue };
|
||||
|
||||
for &delete in &state.selected_points {
|
||||
let Some(point) = delete.get_anchor(&vector_data) else { continue };
|
||||
let Some(pos) = vector_data.point_domain.position_from_id(point) else { continue };
|
||||
let Some(point) = delete.get_anchor(&vector) else { continue };
|
||||
let Some(pos) = vector.point_domain.position_from_id(point) else { continue };
|
||||
|
||||
let mut used_initial_point = false;
|
||||
for handle in vector_data.all_connected(point) {
|
||||
for handle in vector.all_connected(point) {
|
||||
// Disable the g1 continuous
|
||||
for &handles in &vector_data.colinear_manipulators {
|
||||
for &handles in &vector.colinear_manipulators {
|
||||
if handles.contains(&handle) {
|
||||
let modification_type = VectorModificationType::SetG1Continuous { handles, enabled: false };
|
||||
responses.add(GraphOperationMessage::Vector { layer, modification_type });
|
||||
@@ -1544,8 +1519,8 @@ impl ShapeState {
|
||||
// Update segment
|
||||
let HandleId { ty, segment } = handle;
|
||||
let modification_type = match ty {
|
||||
graphene_std::vector::HandleType::Primary => VectorModificationType::SetStartPoint { segment, id },
|
||||
graphene_std::vector::HandleType::End => VectorModificationType::SetEndPoint { segment, id },
|
||||
graphene_std::vector::misc::HandleType::Primary => VectorModificationType::SetStartPoint { segment, id },
|
||||
graphene_std::vector::misc::HandleType::End => VectorModificationType::SetEndPoint { segment, id },
|
||||
};
|
||||
|
||||
responses.add(GraphOperationMessage::Vector { layer, modification_type });
|
||||
@@ -1557,19 +1532,17 @@ impl ShapeState {
|
||||
/// Delete point(s) and adjacent segments.
|
||||
pub fn delete_point_and_break_path(&mut self, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
for (&layer, state) in &mut self.selected_shape_state {
|
||||
let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else {
|
||||
continue;
|
||||
};
|
||||
let Some(vector) = document.network_interface.compute_modified_vector(layer) else { continue };
|
||||
|
||||
for delete in std::mem::take(&mut state.selected_points) {
|
||||
let Some(point) = delete.get_anchor(&vector_data) else { continue };
|
||||
let Some(point) = delete.get_anchor(&vector) else { continue };
|
||||
|
||||
// Delete point
|
||||
let modification_type = VectorModificationType::RemovePoint { id: point };
|
||||
responses.add(GraphOperationMessage::Vector { layer, modification_type });
|
||||
|
||||
// Delete connected segments
|
||||
for HandleId { segment, .. } in vector_data.all_connected(point) {
|
||||
for HandleId { segment, .. } in vector.all_connected(point) {
|
||||
let modification_type = VectorModificationType::RemoveSegment { id: segment };
|
||||
responses.add(GraphOperationMessage::Vector { layer, modification_type });
|
||||
}
|
||||
@@ -1580,18 +1553,18 @@ impl ShapeState {
|
||||
/// Disable colinear handles colinear.
|
||||
pub fn disable_colinear_handles_state_on_selected(&self, network_interface: &NodeNetworkInterface, responses: &mut VecDeque<Message>) {
|
||||
for (&layer, state) in &self.selected_shape_state {
|
||||
let Some(vector_data) = network_interface.compute_modified_vector(layer) else { continue };
|
||||
let Some(vector) = network_interface.compute_modified_vector(layer) else { continue };
|
||||
|
||||
for &point in &state.selected_points {
|
||||
if let ManipulatorPointId::Anchor(point) = point {
|
||||
for connected in vector_data.all_connected(point) {
|
||||
if let Some(&handles) = vector_data.colinear_manipulators.iter().find(|target| target.contains(&connected)) {
|
||||
for connected in vector.all_connected(point) {
|
||||
if let Some(&handles) = vector.colinear_manipulators.iter().find(|target| target.contains(&connected)) {
|
||||
let modification_type = VectorModificationType::SetG1Continuous { handles, enabled: false };
|
||||
responses.add(GraphOperationMessage::Vector { layer, modification_type });
|
||||
}
|
||||
}
|
||||
} else if let Some(handle) = point.as_handle() {
|
||||
if let Some(handles) = vector_data.colinear_manipulators.iter().find(|handles| handles[0] == handle || handles[1] == handle) {
|
||||
if let Some(handles) = vector.colinear_manipulators.iter().find(|handles| handles[0] == handle || handles[1] == handle) {
|
||||
let modification_type = VectorModificationType::SetG1Continuous { handles: *handles, enabled: false };
|
||||
responses.add(GraphOperationMessage::Vector { layer, modification_type });
|
||||
}
|
||||
@@ -1642,11 +1615,11 @@ impl ShapeState {
|
||||
// Choose the first point under the threshold
|
||||
if distance_squared < select_threshold_squared {
|
||||
// Check if point is visible in current PathOverlayMode
|
||||
let vector_data = network_interface.compute_modified_vector(layer)?;
|
||||
let vector = network_interface.compute_modified_vector(layer)?;
|
||||
let selected_segments = selected_segments(network_interface, self);
|
||||
let selected_points = self.selected_points().cloned().collect::<HashSet<_>>();
|
||||
|
||||
if !is_visible_point(manipulator_point_id, &vector_data, path_overlay_mode, frontier_handles_info, selected_segments, &selected_points) {
|
||||
if !is_visible_point(manipulator_point_id, &vector, path_overlay_mode, frontier_handles_info, selected_segments, &selected_points) {
|
||||
return None;
|
||||
}
|
||||
|
||||
@@ -1666,11 +1639,11 @@ impl ShapeState {
|
||||
let mut closest_distance_squared: f64 = f64::MAX;
|
||||
let mut manipulator_point = None;
|
||||
|
||||
let vector_data = network_interface.compute_modified_vector(layer)?;
|
||||
let vector = network_interface.compute_modified_vector(layer)?;
|
||||
let viewspace = network_interface.document_metadata().transform_to_viewport_if_feeds(layer, network_interface);
|
||||
|
||||
// Handles
|
||||
for (segment_id, bezier, _, _) in vector_data.segment_bezier_iter() {
|
||||
for (segment_id, bezier, _, _) in vector.segment_bezier_iter() {
|
||||
let bezier = bezier.apply_transformation(|point| viewspace.transform_point2(point));
|
||||
let valid = |handle: DVec2, control: DVec2| handle.distance_squared(control) > crate::consts::HIDE_HANDLE_DISTANCE.powi(2);
|
||||
|
||||
@@ -1689,7 +1662,7 @@ impl ShapeState {
|
||||
}
|
||||
|
||||
// Anchors
|
||||
for (&id, &point) in vector_data.point_domain.ids().iter().zip(vector_data.point_domain.positions()) {
|
||||
for (&id, &point) in vector.point_domain.ids().iter().zip(vector.point_domain.positions()) {
|
||||
let point = viewspace.transform_point2(point);
|
||||
|
||||
if point.distance_squared(pos) <= closest_distance_squared {
|
||||
@@ -1711,9 +1684,9 @@ impl ShapeState {
|
||||
let mut closest = None;
|
||||
let mut closest_distance_squared: f64 = tolerance * tolerance;
|
||||
|
||||
let vector_data = network_interface.compute_modified_vector(layer)?;
|
||||
let vector = network_interface.compute_modified_vector(layer)?;
|
||||
|
||||
for (segment, mut bezier, start, end) in vector_data.segment_bezier_iter() {
|
||||
for (segment, mut bezier, start, end) in vector.segment_bezier_iter() {
|
||||
let t = bezier.project(layer_pos);
|
||||
let layerspace = bezier.evaluate(TValue::Parametric(t));
|
||||
|
||||
@@ -1730,8 +1703,8 @@ impl ShapeState {
|
||||
}
|
||||
}
|
||||
|
||||
let primary_handle = vector_data.colinear_manipulators.iter().find(|handles| handles.contains(&HandleId::primary(segment)));
|
||||
let end_handle = vector_data.colinear_manipulators.iter().find(|handles| handles.contains(&HandleId::end(segment)));
|
||||
let primary_handle = vector.colinear_manipulators.iter().find(|handles| handles.contains(&HandleId::primary(segment)));
|
||||
let end_handle = vector.colinear_manipulators.iter().find(|handles| handles.contains(&HandleId::end(segment)));
|
||||
let primary_handle = primary_handle.and_then(|&handles| handles.into_iter().find(|handle| handle.segment != segment));
|
||||
let end_handle = end_handle.and_then(|&handles| handles.into_iter().find(|handle| handle.segment != segment));
|
||||
|
||||
@@ -1761,13 +1734,13 @@ impl ShapeState {
|
||||
}
|
||||
pub fn get_dragging_state(&self, network_interface: &NodeNetworkInterface) -> PointSelectState {
|
||||
for &layer in self.selected_shape_state.keys() {
|
||||
let Some(vector_data) = network_interface.compute_modified_vector(layer) else { continue };
|
||||
let Some(vector) = network_interface.compute_modified_vector(layer) else { continue };
|
||||
|
||||
for point in self.selected_points() {
|
||||
if point.as_anchor().is_some() {
|
||||
return PointSelectState::Anchor;
|
||||
}
|
||||
if point.get_handle_pair(&vector_data).is_some() {
|
||||
if point.get_handle_pair(&vector).is_some() {
|
||||
return PointSelectState::HandleWithPair;
|
||||
}
|
||||
}
|
||||
@@ -1778,13 +1751,13 @@ impl ShapeState {
|
||||
/// Returns true if at least one handle with pair is selected
|
||||
pub fn handle_with_pair_selected(&mut self, network_interface: &NodeNetworkInterface) -> bool {
|
||||
for &layer in self.selected_shape_state.keys() {
|
||||
let Some(vector_data) = network_interface.compute_modified_vector(layer) else { continue };
|
||||
let Some(vector) = network_interface.compute_modified_vector(layer) else { continue };
|
||||
|
||||
for point in self.selected_points() {
|
||||
if point.as_anchor().is_some() {
|
||||
return false;
|
||||
}
|
||||
if point.get_handle_pair(&vector_data).is_some() {
|
||||
if point.get_handle_pair(&vector).is_some() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1798,22 +1771,22 @@ impl ShapeState {
|
||||
let mut handles_to_update = Vec::new();
|
||||
|
||||
for &layer in self.selected_shape_state.keys() {
|
||||
let Some(vector_data) = network_interface.compute_modified_vector(layer) else { continue };
|
||||
let Some(vector) = network_interface.compute_modified_vector(layer) else { continue };
|
||||
|
||||
for point in self.selected_points() {
|
||||
if point.as_anchor().is_some() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(other_handles) = point.get_all_connected_handles(&vector_data) {
|
||||
if let Some(other_handles) = point.get_all_connected_handles(&vector) {
|
||||
// Find the next closest handle in the clockwise sense
|
||||
let mut candidates = other_handles.clone();
|
||||
candidates.sort_by(|&handle_a, &handle_b| {
|
||||
let anchor = point.get_anchor_position(&vector_data).expect("No anchor position for handle");
|
||||
let orig_handle_pos = point.get_position(&vector_data).expect("No handle position");
|
||||
let anchor = point.get_anchor_position(&vector).expect("No anchor position for handle");
|
||||
let orig_handle_pos = point.get_position(&vector).expect("No handle position");
|
||||
|
||||
let a_pos = handle_a.to_manipulator_point().get_position(&vector_data).expect("No handle position");
|
||||
let b_pos = handle_b.to_manipulator_point().get_position(&vector_data).expect("No handle position");
|
||||
let a_pos = handle_a.to_manipulator_point().get_position(&vector).expect("No handle position");
|
||||
let b_pos = handle_b.to_manipulator_point().get_position(&vector).expect("No handle position");
|
||||
|
||||
let v_orig = (orig_handle_pos - anchor).normalize_or_zero();
|
||||
|
||||
@@ -1861,13 +1834,11 @@ impl ShapeState {
|
||||
let mut points_to_select: Vec<(LayerNodeIdentifier, Option<PointId>, Option<ManipulatorPointId>)> = Vec::new();
|
||||
|
||||
for &layer in self.selected_shape_state.keys() {
|
||||
let Some(vector_data) = network_interface.compute_modified_vector(layer) else {
|
||||
continue;
|
||||
};
|
||||
let Some(vector) = network_interface.compute_modified_vector(layer) else { continue };
|
||||
|
||||
for point in self.selected_points().filter(|point| point.as_handle().is_some()) {
|
||||
let anchor = point.get_anchor(&vector_data);
|
||||
match point.get_handle_pair(&vector_data) {
|
||||
let anchor = point.get_anchor(&vector);
|
||||
match point.get_handle_pair(&vector) {
|
||||
Some(handles) => {
|
||||
points_to_select.push((layer, anchor, Some(handles[1].to_manipulator_point())));
|
||||
}
|
||||
@@ -1907,14 +1878,14 @@ impl ShapeState {
|
||||
/// This can can be activated by double clicking on an anchor with the Path tool.
|
||||
pub fn flip_smooth_sharp(&self, network_interface: &NodeNetworkInterface, target: glam::DVec2, tolerance: f64, responses: &mut VecDeque<Message>) -> bool {
|
||||
let mut process_layer = |layer| {
|
||||
let vector_data = network_interface.compute_modified_vector(layer)?;
|
||||
let vector = network_interface.compute_modified_vector(layer)?;
|
||||
let transform_to_screenspace = network_interface.document_metadata().transform_to_viewport_if_feeds(layer, network_interface);
|
||||
|
||||
let mut result = None;
|
||||
let mut closest_distance_squared = tolerance * tolerance;
|
||||
|
||||
// Find the closest anchor point on the current layer
|
||||
for (&id, &anchor) in vector_data.point_domain.ids().iter().zip(vector_data.point_domain.positions()) {
|
||||
for (&id, &anchor) in vector.point_domain.ids().iter().zip(vector.point_domain.positions()) {
|
||||
let screenspace = transform_to_screenspace.transform_point2(anchor);
|
||||
let distance_squared = screenspace.distance_squared(target);
|
||||
|
||||
@@ -1925,23 +1896,23 @@ impl ShapeState {
|
||||
}
|
||||
|
||||
let (id, anchor) = result?;
|
||||
let handles = vector_data.all_connected(id);
|
||||
let handles = vector.all_connected(id);
|
||||
let positions = handles
|
||||
.filter_map(|handle| handle.to_manipulator_point().get_position(&vector_data))
|
||||
.filter_map(|handle| handle.to_manipulator_point().get_position(&vector))
|
||||
.filter(|&handle| anchor.abs_diff_eq(handle, 1e-5))
|
||||
.count();
|
||||
|
||||
// Check if the anchor is connected to linear segments.
|
||||
let one_or_more_segment_linear = vector_data.connected_linear_segments(id) != 0;
|
||||
let one_or_more_segment_linear = vector.connected_linear_segments(id) != 0;
|
||||
|
||||
// Check by comparing the handle positions to the anchor if this manipulator group is a point
|
||||
for point in self.selected_points() {
|
||||
let Some(point_id) = point.as_anchor() else { continue };
|
||||
if positions != 0 || one_or_more_segment_linear {
|
||||
self.convert_manipulator_handles_to_colinear(&vector_data, point_id, responses, layer);
|
||||
self.convert_manipulator_handles_to_colinear(&vector, point_id, responses, layer);
|
||||
} else {
|
||||
for handle in vector_data.all_connected(point_id) {
|
||||
let Some(bezier) = vector_data.segment_from_id(handle.segment) else { continue };
|
||||
for handle in vector.all_connected(point_id) {
|
||||
let Some(bezier) = vector.segment_from_id(handle.segment) else { continue };
|
||||
|
||||
match bezier.handles {
|
||||
BezierHandles::Linear => {}
|
||||
@@ -1952,7 +1923,7 @@ impl ShapeState {
|
||||
responses.add(GraphOperationMessage::Vector { layer, modification_type });
|
||||
|
||||
// Set the manipulator to have non-colinear handles
|
||||
for &handles in &vector_data.colinear_manipulators {
|
||||
for &handles in &vector.colinear_manipulators {
|
||||
if handles.contains(&HandleId::primary(segment)) {
|
||||
let modification_type = VectorModificationType::SetG1Continuous { handles, enabled: false };
|
||||
responses.add(GraphOperationMessage::Vector { layer, modification_type });
|
||||
@@ -1965,7 +1936,7 @@ impl ShapeState {
|
||||
responses.add(GraphOperationMessage::Vector { layer, modification_type });
|
||||
|
||||
// Set the manipulator to have non-colinear handles
|
||||
for &handles in &vector_data.colinear_manipulators {
|
||||
for &handles in &vector.colinear_manipulators {
|
||||
if handles.contains(&handle) {
|
||||
let modification_type = VectorModificationType::SetG1Continuous { handles, enabled: false };
|
||||
responses.add(GraphOperationMessage::Vector { layer, modification_type });
|
||||
@@ -2019,14 +1990,14 @@ impl ShapeState {
|
||||
|
||||
for (layer, points) in points_inside {
|
||||
let Some(state) = self.selected_shape_state.get_mut(&layer) else { continue };
|
||||
let Some(vector_data) = network_interface.compute_modified_vector(layer) else { continue };
|
||||
let Some(vector) = network_interface.compute_modified_vector(layer) else { continue };
|
||||
|
||||
for point in points {
|
||||
match (point, selection_change) {
|
||||
(_, SelectionChange::Shrink) => state.deselect_point(point),
|
||||
(ManipulatorPointId::EndHandle(_) | ManipulatorPointId::PrimaryHandle(_), _) => {
|
||||
let handle = point.as_handle().expect("Handle cannot be converted");
|
||||
if handle.length(&vector_data) > 0. {
|
||||
if handle.length(&vector) > 0. {
|
||||
state.select_point(point);
|
||||
}
|
||||
}
|
||||
@@ -2043,9 +2014,9 @@ impl ShapeState {
|
||||
}
|
||||
|
||||
// Also select/deselect the endpoints of respective segments
|
||||
let Some(vector_data) = network_interface.compute_modified_vector(layer) else { continue };
|
||||
let Some(vector) = network_interface.compute_modified_vector(layer) else { continue };
|
||||
if !select_points && select_segments {
|
||||
vector_data
|
||||
vector
|
||||
.segment_bezier_iter()
|
||||
.filter(|(segment, _, _, _)| segments.contains(segment))
|
||||
.for_each(|(_, _, start, end)| match selection_change {
|
||||
@@ -2081,17 +2052,17 @@ impl ShapeState {
|
||||
let mut segments_inside: HashMap<LayerNodeIdentifier, HashSet<SegmentId>> = HashMap::new();
|
||||
|
||||
for &layer in self.selected_shape_state.keys() {
|
||||
let vector_data = network_interface.compute_modified_vector(layer);
|
||||
let Some(vector_data) = vector_data else { continue };
|
||||
let vector = network_interface.compute_modified_vector(layer);
|
||||
let Some(vector) = vector else { continue };
|
||||
let transform = network_interface.document_metadata().transform_to_viewport_if_feeds(layer, network_interface);
|
||||
|
||||
assert_eq!(vector_data.segment_domain.ids().len(), vector_data.start_point().count());
|
||||
assert_eq!(vector_data.segment_domain.ids().len(), vector_data.end_point().count());
|
||||
for start in vector_data.start_point() {
|
||||
assert!(vector_data.point_domain.ids().contains(&start));
|
||||
assert_eq!(vector.segment_domain.ids().len(), vector.start_point().count());
|
||||
assert_eq!(vector.segment_domain.ids().len(), vector.end_point().count());
|
||||
for start in vector.start_point() {
|
||||
assert!(vector.point_domain.ids().contains(&start));
|
||||
}
|
||||
for end in vector_data.end_point() {
|
||||
assert!(vector_data.point_domain.ids().contains(&end));
|
||||
for end in vector.end_point() {
|
||||
assert!(vector.point_domain.ids().contains(&end));
|
||||
}
|
||||
|
||||
let polygon_subpath = if let SelectionShape::Lasso(polygon) = selection_shape {
|
||||
@@ -2105,7 +2076,7 @@ impl ShapeState {
|
||||
};
|
||||
|
||||
// Selection segments
|
||||
for (id, bezier, _, _) in vector_data.segment_bezier_iter() {
|
||||
for (id, bezier, _, _) in vector.segment_bezier_iter() {
|
||||
if select_segments {
|
||||
// Select segments if they lie inside the bounding box or lasso polygon
|
||||
let segment_bbox = calculate_bezier_bbox(bezier);
|
||||
@@ -2154,7 +2125,7 @@ impl ShapeState {
|
||||
};
|
||||
|
||||
if select && select_points {
|
||||
let is_visible_handle = is_visible_point(id, &vector_data, path_overlay_mode, frontier_handles_info, selected_segments.clone(), &selected_points);
|
||||
let is_visible_handle = is_visible_point(id, &vector, path_overlay_mode, frontier_handles_info, selected_segments.clone(), &selected_points);
|
||||
|
||||
if is_visible_handle {
|
||||
points_inside.entry(layer).or_default().insert(id);
|
||||
@@ -2164,7 +2135,7 @@ impl ShapeState {
|
||||
}
|
||||
|
||||
// Checking for selection of anchor points
|
||||
for (&id, &position) in vector_data.point_domain.ids().iter().zip(vector_data.point_domain.positions()) {
|
||||
for (&id, &position) in vector.point_domain.ids().iter().zip(vector.point_domain.positions()) {
|
||||
let transformed_position = transform.transform_point2(position);
|
||||
|
||||
let select = match selection_shape {
|
||||
|
||||
@@ -205,12 +205,12 @@ pub fn transform_cage_overlays(document: &DocumentMessageHandler, tool_data: &mu
|
||||
|
||||
pub fn anchor_overlays(document: &DocumentMessageHandler, overlay_context: &mut OverlayContext) {
|
||||
for layer in document.network_interface.selected_nodes().selected_layers(document.metadata()) {
|
||||
let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { continue };
|
||||
let Some(vector) = document.network_interface.compute_modified_vector(layer) else { continue };
|
||||
let transform = document.metadata().transform_to_viewport(layer);
|
||||
|
||||
overlay_context.outline_vector(&vector_data, transform);
|
||||
overlay_context.outline_vector(&vector, transform);
|
||||
|
||||
for (_, &position) in vector_data.point_domain.ids().iter().zip(vector_data.point_domain.positions()) {
|
||||
for (_, &position) in vector.point_domain.ids().iter().zip(vector.point_domain.positions()) {
|
||||
overlay_context.manipulator_anchor(transform.transform_point2(position), false, None);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,8 @@ use graph_craft::document::value::TaggedValue;
|
||||
use graphene_std::renderer::Quad;
|
||||
use graphene_std::table::Table;
|
||||
use graphene_std::text::{FontCache, load_font};
|
||||
use graphene_std::vector::{HandleExt, HandleId, ManipulatorPointId, PointId, SegmentId, VectorData, VectorModification, VectorModificationType};
|
||||
use graphene_std::vector::misc::{HandleId, ManipulatorPointId};
|
||||
use graphene_std::vector::{HandleExt, PointId, SegmentId, Vector, VectorModification, VectorModificationType};
|
||||
use kurbo::{CubicBez, Line, ParamCurveExtrema, PathSeg, Point, QuadBez};
|
||||
|
||||
/// Determines if a path should be extended. Goal in viewport space. Returns the path and if it is extending from the start, if applicable.
|
||||
@@ -47,14 +48,12 @@ where
|
||||
let mut best_distance_squared = max_distance * max_distance;
|
||||
for layer in layers {
|
||||
let viewspace = document.metadata().transform_to_viewport(layer);
|
||||
let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else {
|
||||
continue;
|
||||
};
|
||||
for id in vector_data.extendable_points(preferences.vector_meshes) {
|
||||
let Some(vector) = document.network_interface.compute_modified_vector(layer) else { continue };
|
||||
for id in vector.extendable_points(preferences.vector_meshes) {
|
||||
if exclude(id) {
|
||||
continue;
|
||||
}
|
||||
let Some(point) = vector_data.point_domain.position_from_id(id) else { continue };
|
||||
let Some(point) = vector.point_domain.position_from_id(id) else { continue };
|
||||
|
||||
let distance_squared = viewspace.transform_point2(point).distance_squared(goal);
|
||||
|
||||
@@ -88,16 +87,16 @@ pub fn text_bounding_box(layer: LayerNodeIdentifier, document: &DocumentMessageH
|
||||
Quad::from_box([DVec2::ZERO + vertical_offset, far + vertical_offset])
|
||||
}
|
||||
|
||||
pub fn calculate_segment_angle(anchor: PointId, segment: SegmentId, vector_data: &VectorData, prefer_handle_direction: bool) -> Option<f64> {
|
||||
let is_start = |point: PointId, segment: SegmentId| vector_data.segment_start_from_id(segment) == Some(point);
|
||||
let anchor_position = vector_data.point_domain.position_from_id(anchor)?;
|
||||
let end_handle = ManipulatorPointId::EndHandle(segment).get_position(vector_data);
|
||||
let start_handle = ManipulatorPointId::PrimaryHandle(segment).get_position(vector_data);
|
||||
pub fn calculate_segment_angle(anchor: PointId, segment: SegmentId, vector: &Vector, prefer_handle_direction: bool) -> Option<f64> {
|
||||
let is_start = |point: PointId, segment: SegmentId| vector.segment_start_from_id(segment) == Some(point);
|
||||
let anchor_position = vector.point_domain.position_from_id(anchor)?;
|
||||
let end_handle = ManipulatorPointId::EndHandle(segment).get_position(vector);
|
||||
let start_handle = ManipulatorPointId::PrimaryHandle(segment).get_position(vector);
|
||||
|
||||
let start_point = if is_start(anchor, segment) {
|
||||
vector_data.segment_end_from_id(segment).and_then(|id| vector_data.point_domain.position_from_id(id))
|
||||
vector.segment_end_from_id(segment).and_then(|id| vector.point_domain.position_from_id(id))
|
||||
} else {
|
||||
vector_data.segment_start_from_id(segment).and_then(|id| vector_data.point_domain.position_from_id(id))
|
||||
vector.segment_start_from_id(segment).and_then(|id| vector.point_domain.position_from_id(id))
|
||||
};
|
||||
|
||||
let required_handle = if is_start(anchor, segment) {
|
||||
@@ -115,9 +114,9 @@ pub fn calculate_segment_angle(anchor: PointId, segment: SegmentId, vector_data:
|
||||
required_handle.map(|handle| -(handle - anchor_position).angle_to(DVec2::X))
|
||||
}
|
||||
|
||||
pub fn adjust_handle_colinearity(handle: HandleId, anchor_position: DVec2, target_control_point: DVec2, vector_data: &VectorData, layer: LayerNodeIdentifier, responses: &mut VecDeque<Message>) {
|
||||
let Some(other_handle) = vector_data.other_colinear_handle(handle) else { return };
|
||||
let Some(handle_position) = other_handle.to_manipulator_point().get_position(vector_data) else {
|
||||
pub fn adjust_handle_colinearity(handle: HandleId, anchor_position: DVec2, target_control_point: DVec2, vector: &Vector, layer: LayerNodeIdentifier, responses: &mut VecDeque<Message>) {
|
||||
let Some(other_handle) = vector.other_colinear_handle(handle) else { return };
|
||||
let Some(handle_position) = other_handle.to_manipulator_point().get_position(vector) else {
|
||||
return;
|
||||
};
|
||||
let Some(direction) = (anchor_position - target_control_point).try_normalize() else { return };
|
||||
@@ -132,12 +131,12 @@ pub fn restore_previous_handle_position(
|
||||
handle: HandleId,
|
||||
original_c: DVec2,
|
||||
anchor_position: DVec2,
|
||||
vector_data: &VectorData,
|
||||
vector: &Vector,
|
||||
layer: LayerNodeIdentifier,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) -> Option<HandleId> {
|
||||
let other_handle = vector_data.other_colinear_handle(handle)?;
|
||||
let handle_position = other_handle.to_manipulator_point().get_position(vector_data)?;
|
||||
let other_handle = vector.other_colinear_handle(handle)?;
|
||||
let handle_position = other_handle.to_manipulator_point().get_position(vector)?;
|
||||
let direction = (anchor_position - original_c).try_normalize()?;
|
||||
|
||||
let old_relative_position = (handle_position - anchor_position).length() * direction;
|
||||
@@ -151,16 +150,8 @@ pub fn restore_previous_handle_position(
|
||||
Some(other_handle)
|
||||
}
|
||||
|
||||
pub fn restore_g1_continuity(
|
||||
handle: HandleId,
|
||||
other_handle: HandleId,
|
||||
control_point: DVec2,
|
||||
anchor_position: DVec2,
|
||||
vector_data: &VectorData,
|
||||
layer: LayerNodeIdentifier,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) {
|
||||
let Some(handle_position) = other_handle.to_manipulator_point().get_position(vector_data) else {
|
||||
pub fn restore_g1_continuity(handle: HandleId, other_handle: HandleId, control_point: DVec2, anchor_position: DVec2, vector: &Vector, layer: LayerNodeIdentifier, responses: &mut VecDeque<Message>) {
|
||||
let Some(handle_position) = other_handle.to_manipulator_point().get_position(vector) else {
|
||||
return;
|
||||
};
|
||||
let Some(direction) = (anchor_position - control_point).try_normalize() else { return };
|
||||
@@ -177,7 +168,7 @@ pub fn restore_g1_continuity(
|
||||
/// Check whether a point is visible in the current overlay mode.
|
||||
pub fn is_visible_point(
|
||||
manipulator_point_id: ManipulatorPointId,
|
||||
vector_data: &VectorData,
|
||||
vector: &Vector,
|
||||
path_overlay_mode: PathOverlayMode,
|
||||
frontier_handles_info: &Option<HashMap<SegmentId, Vec<PointId>>>,
|
||||
selected_segments: Vec<SegmentId>,
|
||||
@@ -194,14 +185,14 @@ pub fn is_visible_point(
|
||||
}
|
||||
|
||||
// Either the segment is a part of selected segments or the opposite handle is a part of existing selection
|
||||
let Some(handle_pair) = manipulator_point_id.get_handle_pair(vector_data) else { return false };
|
||||
let Some(handle_pair) = manipulator_point_id.get_handle_pair(vector) else { return false };
|
||||
let other_handle = handle_pair[1].to_manipulator_point();
|
||||
|
||||
// Return whether the list of selected points contain the other handle
|
||||
selected_points.contains(&other_handle)
|
||||
}
|
||||
(PathOverlayMode::FrontierHandles, false) => {
|
||||
let Some(anchor) = manipulator_point_id.get_anchor(vector_data) else {
|
||||
let Some(anchor) = manipulator_point_id.get_anchor(vector) else {
|
||||
warn!("No anchor for selected handle");
|
||||
return false;
|
||||
};
|
||||
@@ -600,13 +591,13 @@ pub fn make_path_editable_is_allowed(network_interface: &NodeNetworkInterface, m
|
||||
return None;
|
||||
}
|
||||
|
||||
// Must be a layer of type Table<VectorData>
|
||||
// Must be a layer of type Table<Vector>
|
||||
let compatible_type = NodeGraphLayer::new(first_layer, network_interface)
|
||||
.horizontal_layer_flow()
|
||||
.nth(1)
|
||||
.map(|node_id| {
|
||||
let (output_type, _) = network_interface.output_type(&node_id, 0, &[]);
|
||||
output_type.nested_type() == concrete!(Table<VectorData>).nested_type()
|
||||
output_type.nested_type() == concrete!(Table<Vector>).nested_type()
|
||||
})
|
||||
.unwrap_or_default();
|
||||
if !compatible_type {
|
||||
|
||||
@@ -11,6 +11,7 @@ use crate::messages::tool::common_functionality::snapping::SnapData;
|
||||
use crate::messages::tool::common_functionality::snapping::SnapManager;
|
||||
use crate::messages::tool::common_functionality::transformation_cage::*;
|
||||
use graph_craft::document::NodeId;
|
||||
use graphene_std::Artboard;
|
||||
use graphene_std::renderer::Quad;
|
||||
use graphene_std::table::Table;
|
||||
|
||||
@@ -337,8 +338,8 @@ impl Fsm for ArtboardToolFsmState {
|
||||
|
||||
responses.add(GraphOperationMessage::NewArtboard {
|
||||
id,
|
||||
artboard: graphene_std::Artboard {
|
||||
graphic_group: Table::new(),
|
||||
artboard: Artboard {
|
||||
group: Table::new(),
|
||||
label: String::from("Artboard"),
|
||||
location: start.min(end).round().as_ivec2(),
|
||||
dimensions: (start.round() - end.round()).abs().as_ivec2(),
|
||||
|
||||
@@ -360,9 +360,9 @@ mod test_freehand {
|
||||
use crate::messages::tool::tool_messages::freehand_tool::FreehandOptionsUpdate;
|
||||
use crate::test_utils::test_prelude::*;
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graphene_std::vector::VectorData;
|
||||
use graphene_std::vector::Vector;
|
||||
|
||||
async fn get_vector_data(editor: &mut EditorTestUtils) -> Vec<(VectorData, DAffine2)> {
|
||||
async fn get_vector_and_transform_list(editor: &mut EditorTestUtils) -> Vec<(Vector, DAffine2)> {
|
||||
let document = editor.active_document();
|
||||
let layers = document.metadata().all_layers();
|
||||
|
||||
@@ -372,23 +372,22 @@ mod test_freehand {
|
||||
// Only get layers with path nodes
|
||||
let _ = graph_layer.upstream_visible_node_id_from_name_in_layer("Path")?;
|
||||
|
||||
let vector_data = document.network_interface.compute_modified_vector(layer)?;
|
||||
let vector = document.network_interface.compute_modified_vector(layer)?;
|
||||
let transform = document.metadata().transform_to_viewport(layer);
|
||||
Some((vector_data, transform))
|
||||
Some((vector, transform))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn verify_path_points(vector_data_list: &[(VectorData, DAffine2)], expected_captured_points: &[DVec2], tolerance: f64) -> Result<(), String> {
|
||||
assert_eq!(vector_data_list.len(), 1, "there should be one vector data");
|
||||
fn verify_path_points(vector_and_transform_list: &[(Vector, DAffine2)], expected_captured_points: &[DVec2], tolerance: f64) -> Result<(), String> {
|
||||
assert_eq!(vector_and_transform_list.len(), 1, "There should be one row of Vector geometry");
|
||||
|
||||
let path_data = vector_data_list.iter().find(|(data, _)| data.point_domain.ids().len() > 0).ok_or("Could not find path data")?;
|
||||
let (vector, transform) = vector_and_transform_list.iter().find(|(data, _)| data.point_domain.ids().len() > 0).ok_or("Could not find path data")?;
|
||||
|
||||
let (vector_data, transform) = path_data;
|
||||
let point_count = vector_data.point_domain.ids().len();
|
||||
let segment_count = vector_data.segment_domain.ids().len();
|
||||
let point_count = vector.point_domain.ids().len();
|
||||
let segment_count = vector.segment_domain.ids().len();
|
||||
|
||||
let actual_positions: Vec<DVec2> = vector_data.point_domain.positions().iter().map(|&position| transform.transform_point2(position)).collect();
|
||||
let actual_positions: Vec<DVec2> = vector.point_domain.positions().iter().map(|&position| transform.transform_point2(position)).collect();
|
||||
|
||||
if segment_count != point_count - 1 {
|
||||
return Err(format!("Expected segments to be one less than points, got {} segments for {} points", segment_count, point_count));
|
||||
@@ -435,8 +434,8 @@ mod test_freehand {
|
||||
let expected_captured_points = &mouse_points[1..];
|
||||
editor.drag_path(&mouse_points, ModifierKeys::empty()).await;
|
||||
|
||||
let vector_data_list = get_vector_data(&mut editor).await;
|
||||
verify_path_points(&vector_data_list, expected_captured_points, 1.).expect("Path points verification failed");
|
||||
let vector_and_transform_list = get_vector_and_transform_list(&mut editor).await;
|
||||
verify_path_points(&vector_and_transform_list, expected_captured_points, 1.).expect("Path points verification failed");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -468,12 +467,12 @@ mod test_freehand {
|
||||
)
|
||||
.await;
|
||||
|
||||
let initial_vector_data = get_vector_data(&mut editor).await;
|
||||
assert!(!initial_vector_data.is_empty(), "No vector data found after initial drawing");
|
||||
let initial_vector_and_transform_list = get_vector_and_transform_list(&mut editor).await;
|
||||
assert!(!initial_vector_and_transform_list.is_empty(), "No Vector geometry found after initial drawing");
|
||||
|
||||
let (initial_data, transform) = &initial_vector_data[0];
|
||||
let initial_point_count = initial_data.point_domain.ids().len();
|
||||
let initial_segment_count = initial_data.segment_domain.ids().len();
|
||||
let (initial_vector, initial_transform) = &initial_vector_and_transform_list[0];
|
||||
let initial_point_count = initial_vector.point_domain.ids().len();
|
||||
let initial_segment_count = initial_vector.segment_domain.ids().len();
|
||||
|
||||
assert!(initial_point_count >= 2, "Expected at least 2 points in initial path, found {}", initial_point_count);
|
||||
assert_eq!(
|
||||
@@ -484,15 +483,15 @@ mod test_freehand {
|
||||
initial_segment_count
|
||||
);
|
||||
|
||||
let extendable_points = initial_data.extendable_points(false).collect::<Vec<_>>();
|
||||
let extendable_points = initial_vector.extendable_points(false).collect::<Vec<_>>();
|
||||
assert!(!extendable_points.is_empty(), "No extendable points found in the path");
|
||||
|
||||
let endpoint_id = extendable_points[0];
|
||||
let endpoint_pos_option = initial_data.point_domain.position_from_id(endpoint_id);
|
||||
let endpoint_pos_option = initial_vector.point_domain.position_from_id(endpoint_id);
|
||||
assert!(endpoint_pos_option.is_some(), "Could not find position for endpoint");
|
||||
|
||||
let endpoint_pos = endpoint_pos_option.unwrap();
|
||||
let endpoint_viewport_pos = transform.transform_point2(endpoint_pos);
|
||||
let endpoint_viewport_pos = initial_transform.transform_point2(endpoint_pos);
|
||||
|
||||
assert!(endpoint_viewport_pos.is_finite(), "Endpoint position is not finite");
|
||||
|
||||
@@ -527,12 +526,12 @@ mod test_freehand {
|
||||
)
|
||||
.await;
|
||||
|
||||
let extended_vector_data = get_vector_data(&mut editor).await;
|
||||
assert!(!extended_vector_data.is_empty(), "No vector data found after extension");
|
||||
let extended_vector_and_transform = get_vector_and_transform_list(&mut editor).await;
|
||||
assert!(!extended_vector_and_transform.is_empty(), "No Vector geometry found after extension");
|
||||
|
||||
let (extended_data, _) = &extended_vector_data[0];
|
||||
let extended_point_count = extended_data.point_domain.ids().len();
|
||||
let extended_segment_count = extended_data.segment_domain.ids().len();
|
||||
let (extended_vector, _) = &extended_vector_and_transform[0];
|
||||
let extended_point_count = extended_vector.point_domain.ids().len();
|
||||
let extended_segment_count = extended_vector.segment_domain.ids().len();
|
||||
|
||||
assert!(
|
||||
extended_point_count > initial_point_count,
|
||||
@@ -585,12 +584,12 @@ mod test_freehand {
|
||||
)
|
||||
.await;
|
||||
|
||||
let initial_vector_data = get_vector_data(&mut editor).await;
|
||||
assert!(!initial_vector_data.is_empty(), "No vector data found after initial drawing");
|
||||
let initial_vector_and_transform = get_vector_and_transform_list(&mut editor).await;
|
||||
assert!(!initial_vector_and_transform.is_empty(), "No vector geometry found after initial drawing");
|
||||
|
||||
let (initial_data, _) = &initial_vector_data[0];
|
||||
let initial_point_count = initial_data.point_domain.ids().len();
|
||||
let initial_segment_count = initial_data.segment_domain.ids().len();
|
||||
let (initial_vector, _) = &initial_vector_and_transform[0];
|
||||
let initial_point_count = initial_vector.point_domain.ids().len();
|
||||
let initial_segment_count = initial_vector.segment_domain.ids().len();
|
||||
|
||||
let existing_layer_id = {
|
||||
let document = editor.active_document();
|
||||
@@ -636,8 +635,8 @@ mod test_freehand {
|
||||
)
|
||||
.await;
|
||||
|
||||
let final_vector_data = get_vector_data(&mut editor).await;
|
||||
assert!(!final_vector_data.is_empty(), "No vector data found after second drawing");
|
||||
let final_vector_and_transform = get_vector_and_transform_list(&mut editor).await;
|
||||
assert!(!final_vector_and_transform.is_empty(), "No vector geometry found after second drawing");
|
||||
|
||||
// Verify we still have only one layer
|
||||
let layer_count = {
|
||||
@@ -646,9 +645,9 @@ mod test_freehand {
|
||||
};
|
||||
assert_eq!(layer_count, 1, "Expected only one layer after drawing with Shift key");
|
||||
|
||||
let (final_data, _) = &final_vector_data[0];
|
||||
let final_point_count = final_data.point_domain.ids().len();
|
||||
let final_segment_count = final_data.segment_domain.ids().len();
|
||||
let (final_vector, _) = &final_vector_and_transform[0];
|
||||
let final_point_count = final_vector.point_domain.ids().len();
|
||||
let final_segment_count = final_vector.segment_domain.ids().len();
|
||||
|
||||
assert!(
|
||||
final_point_count > initial_point_count,
|
||||
|
||||
@@ -27,8 +27,8 @@ use graphene_std::renderer::Quad;
|
||||
use graphene_std::transform::ReferencePoint;
|
||||
use graphene_std::uuid::NodeId;
|
||||
use graphene_std::vector::click_target::ClickTargetType;
|
||||
use graphene_std::vector::{HandleExt, HandleId, NoHashBuilder, SegmentId, VectorData};
|
||||
use graphene_std::vector::{ManipulatorPointId, PointId, VectorModificationType};
|
||||
use graphene_std::vector::misc::{HandleId, ManipulatorPointId};
|
||||
use graphene_std::vector::{HandleExt, NoHashBuilder, PointId, SegmentId, Vector, VectorModificationType};
|
||||
use std::vec;
|
||||
|
||||
#[derive(Default, ExtractField)]
|
||||
@@ -285,7 +285,7 @@ impl LayoutHolder for PathTool {
|
||||
.selected_index(Some(self.options.path_overlay_mode as u32))
|
||||
.widget_holder();
|
||||
|
||||
// Works only if a single layer is selected and its type is vectordata
|
||||
// Works only if a single layer is selected and its type is Vector
|
||||
let path_node_button = TextButton::new("Make Path Editable")
|
||||
.icon(Some("NodeShape".into()))
|
||||
.tooltip("Make Path Editable")
|
||||
@@ -619,10 +619,10 @@ impl PathToolData {
|
||||
self.can_toggle_colinearity = match &selection_status {
|
||||
SelectionStatus::None => false,
|
||||
SelectionStatus::One(single_selected_point) => {
|
||||
let vector_data = document.network_interface.compute_modified_vector(single_selected_point.layer).unwrap();
|
||||
if single_selected_point.id.get_handle_pair(&vector_data).is_some() {
|
||||
let anchor = single_selected_point.id.get_anchor(&vector_data).expect("Cannot find connected anchor");
|
||||
vector_data.all_connected(anchor).count() <= 2
|
||||
let vector = document.network_interface.compute_modified_vector(single_selected_point.layer).unwrap();
|
||||
if single_selected_point.id.get_handle_pair(&vector).is_some() {
|
||||
let anchor = single_selected_point.id.get_anchor(&vector).expect("Cannot find connected anchor");
|
||||
vector.all_connected(anchor).count() <= 2
|
||||
} else {
|
||||
false
|
||||
}
|
||||
@@ -761,13 +761,13 @@ impl PathToolData {
|
||||
if handle_drag_from_anchor {
|
||||
if let Some((layer, point)) = shape_editor.find_nearest_point_indices(&document.network_interface, input.mouse.position, SELECTION_THRESHOLD) {
|
||||
// Check that selected point is an anchor
|
||||
if let (Some(point_id), Some(vector_data)) = (point.as_anchor(), document.network_interface.compute_modified_vector(layer)) {
|
||||
let handles = vector_data.all_connected(point_id).collect::<Vec<_>>();
|
||||
if let (Some(point_id), Some(vector)) = (point.as_anchor(), document.network_interface.compute_modified_vector(layer)) {
|
||||
let handles = vector.all_connected(point_id).collect::<Vec<_>>();
|
||||
self.alt_clicked_on_anchor = true;
|
||||
for handle in &handles {
|
||||
let modification_type = handle.set_relative_position(DVec2::ZERO);
|
||||
responses.add(GraphOperationMessage::Vector { layer, modification_type });
|
||||
for &handles in &vector_data.colinear_manipulators {
|
||||
for &handles in &vector.colinear_manipulators {
|
||||
if handles.contains(handle) {
|
||||
let modification_type = VectorModificationType::SetG1Continuous { handles, enabled: false };
|
||||
responses.add(GraphOperationMessage::Vector { layer, modification_type });
|
||||
@@ -783,16 +783,16 @@ impl PathToolData {
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((Some(point), Some(vector_data))) = shape_editor
|
||||
if let Some((Some(point), Some(vector))) = shape_editor
|
||||
.find_nearest_point_indices(&document.network_interface, input.mouse.position, SELECTION_THRESHOLD)
|
||||
.map(|(layer, point)| (point.as_anchor(), document.network_interface.compute_modified_vector(layer)))
|
||||
{
|
||||
let handles = vector_data
|
||||
let handles = vector
|
||||
.all_connected(point)
|
||||
.filter(|handle| handle.length(&vector_data) < 1e-6)
|
||||
.filter(|handle| handle.length(&vector) < 1e-6)
|
||||
.map(|handle| handle.to_manipulator_point())
|
||||
.collect::<Vec<_>>();
|
||||
let endpoint = vector_data.extendable_points(false).any(|anchor| point == anchor);
|
||||
let endpoint = vector.extendable_points(false).any(|anchor| point == anchor);
|
||||
|
||||
if drag_zero_handle && (handles.len() == 1 && !endpoint) {
|
||||
shape_editor.deselect_all_points();
|
||||
@@ -883,27 +883,25 @@ impl PathToolData {
|
||||
let mut manipulators = HashMap::with_hasher(NoHashBuilder);
|
||||
let mut unselected = Vec::new();
|
||||
for (&layer, state) in &shape_editor.selected_shape_state {
|
||||
let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else {
|
||||
continue;
|
||||
};
|
||||
let Some(vector) = document.network_interface.compute_modified_vector(layer) else { continue };
|
||||
let transform = document.metadata().transform_to_document_if_feeds(layer, &document.network_interface);
|
||||
|
||||
let mut layer_manipulators = HashSet::with_hasher(NoHashBuilder);
|
||||
for point in state.selected_points() {
|
||||
let Some(anchor) = point.get_anchor(&vector_data) else { continue };
|
||||
let Some(anchor) = point.get_anchor(&vector) else { continue };
|
||||
layer_manipulators.insert(anchor);
|
||||
let Some([handle1, handle2]) = point.get_handle_pair(&vector_data) else { continue };
|
||||
let Some([handle1, handle2]) = point.get_handle_pair(&vector) else { continue };
|
||||
let Some(handle) = point.as_handle() else { continue };
|
||||
// Check which handle is selected and which is opposite
|
||||
let opposite = if handle == handle1 { handle2 } else { handle1 };
|
||||
|
||||
self.opposite_handle_position = if self.opposite_handle_position.is_none() {
|
||||
opposite.to_manipulator_point().get_position(&vector_data)
|
||||
opposite.to_manipulator_point().get_position(&vector)
|
||||
} else {
|
||||
self.opposite_handle_position
|
||||
};
|
||||
}
|
||||
for (&id, &position) in vector_data.point_domain.ids().iter().zip(vector_data.point_domain.positions()) {
|
||||
for (&id, &position) in vector.point_domain.ids().iter().zip(vector.point_domain.positions()) {
|
||||
if layer_manipulators.contains(&id) {
|
||||
continue;
|
||||
}
|
||||
@@ -956,17 +954,17 @@ impl PathToolData {
|
||||
return false;
|
||||
};
|
||||
|
||||
let Some(vector_data) = document.network_interface.compute_modified_vector(*layer) else {
|
||||
let Some(vector) = document.network_interface.compute_modified_vector(*layer) else {
|
||||
self.opposing_handle_lengths = Some(shape_editor.opposing_handle_lengths(document));
|
||||
return false;
|
||||
};
|
||||
|
||||
// Check if handle has a pair (to ignore handles of edges of open paths)
|
||||
if let Some(handle_pair) = selected_handle_id.get_handle_pair(&vector_data) {
|
||||
if let Some(handle_pair) = selected_handle_id.get_handle_pair(&vector) {
|
||||
let opposite_handle_length = handle_pair.iter().filter(|&&h| h.to_manipulator_point() != selected_handle_id).find_map(|&h| {
|
||||
let opp_handle_pos = h.to_manipulator_point().get_position(&vector_data)?;
|
||||
let opp_anchor_id = h.to_manipulator_point().get_anchor(&vector_data)?;
|
||||
let opp_anchor_pos = vector_data.point_domain.position_from_id(opp_anchor_id)?;
|
||||
let opp_handle_pos = h.to_manipulator_point().get_position(&vector)?;
|
||||
let opp_anchor_id = h.to_manipulator_point().get_anchor(&vector)?;
|
||||
let opp_anchor_pos = vector.point_domain.position_from_id(opp_anchor_id)?;
|
||||
Some((opp_handle_pos - opp_anchor_pos).length())
|
||||
});
|
||||
|
||||
@@ -997,11 +995,11 @@ impl PathToolData {
|
||||
let handle_id = selected_handle.to_manipulator_point();
|
||||
|
||||
let layer_to_document = document.metadata().transform_to_document_if_feeds(*layer, &document.network_interface);
|
||||
let vector_data = document.network_interface.compute_modified_vector(*layer)?;
|
||||
let vector = document.network_interface.compute_modified_vector(*layer)?;
|
||||
|
||||
let handle_position_local = selected_handle.to_manipulator_point().get_position(&vector_data)?;
|
||||
let anchor_id = selected_handle.to_manipulator_point().get_anchor(&vector_data)?;
|
||||
let anchor_position_local = vector_data.point_domain.position_from_id(anchor_id)?;
|
||||
let handle_position_local = selected_handle.to_manipulator_point().get_position(&vector)?;
|
||||
let anchor_id = selected_handle.to_manipulator_point().get_anchor(&vector)?;
|
||||
let anchor_position_local = vector.point_domain.position_from_id(anchor_id)?;
|
||||
|
||||
let handle_position_document = layer_to_document.transform_point2(handle_position_local);
|
||||
let anchor_position_document = layer_to_document.transform_point2(anchor_position_local);
|
||||
@@ -1024,24 +1022,24 @@ impl PathToolData {
|
||||
) -> f64 {
|
||||
let current_angle = -handle_vector.angle_to(DVec2::X);
|
||||
|
||||
if let Some((vector_data, layer)) = shape_editor
|
||||
if let Some((vector, layer)) = shape_editor
|
||||
.selected_shape_state
|
||||
.iter()
|
||||
.next()
|
||||
.and_then(|(layer, _)| document.network_interface.compute_modified_vector(*layer).map(|vector_data| (vector_data, layer)))
|
||||
.and_then(|(layer, _)| document.network_interface.compute_modified_vector(*layer).map(|vector| (vector, layer)))
|
||||
{
|
||||
let adjacent_anchor = check_handle_over_adjacent_anchor(handle_id, &vector_data);
|
||||
let adjacent_anchor = check_handle_over_adjacent_anchor(handle_id, &vector);
|
||||
let mut required_angle = None;
|
||||
|
||||
// If the handle is dragged over one of its adjacent anchors while holding down the Ctrl key, compute the angle based on the tangent formed with the neighboring anchor points.
|
||||
if adjacent_anchor.is_some() && lock_angle && !self.angle_locked {
|
||||
let anchor = handle_id.get_anchor(&vector_data);
|
||||
let (angle, anchor_position) = calculate_adjacent_anchor_tangent(handle_id, anchor, adjacent_anchor, &vector_data);
|
||||
let anchor = handle_id.get_anchor(&vector);
|
||||
let (angle, anchor_position) = calculate_adjacent_anchor_tangent(handle_id, anchor, adjacent_anchor, &vector);
|
||||
|
||||
let layer_to_document = document.metadata().transform_to_document_if_feeds(*layer, &document.network_interface);
|
||||
|
||||
self.adjacent_anchor_offset = handle_id
|
||||
.get_anchor_position(&vector_data)
|
||||
.get_anchor_position(&vector)
|
||||
.and_then(|handle_anchor| anchor_position.map(|adjacent_anchor| layer_to_document.transform_point2(adjacent_anchor) - layer_to_document.transform_point2(handle_anchor)));
|
||||
|
||||
required_angle = angle;
|
||||
@@ -1049,7 +1047,7 @@ impl PathToolData {
|
||||
|
||||
// If the handle is dragged near its adjacent anchors while holding down the Ctrl key, compute the angle using the tangent direction of neighboring segments.
|
||||
if relative_vector.length() < 25. && lock_angle && !self.angle_locked {
|
||||
required_angle = calculate_lock_angle(self, shape_editor, responses, document, &vector_data, handle_id, tangent_to_neighboring_tangents);
|
||||
required_angle = calculate_lock_angle(self, shape_editor, responses, document, &vector, handle_id, tangent_to_neighboring_tangents);
|
||||
}
|
||||
|
||||
// Finalize and apply angle locking if a valid target angle was determined.
|
||||
@@ -1158,17 +1156,17 @@ impl PathToolData {
|
||||
self.snapping_axis = None;
|
||||
}
|
||||
|
||||
fn get_normalized_tangent(&mut self, point: PointId, segment: SegmentId, vector_data: &VectorData) -> Option<DVec2> {
|
||||
let other_point = vector_data.other_point(segment, point)?;
|
||||
let position = ManipulatorPointId::Anchor(point).get_position(vector_data)?;
|
||||
fn get_normalized_tangent(&mut self, point: PointId, segment: SegmentId, vector: &Vector) -> Option<DVec2> {
|
||||
let other_point = vector.other_point(segment, point)?;
|
||||
let position = ManipulatorPointId::Anchor(point).get_position(vector)?;
|
||||
|
||||
let mut handles = vector_data.all_connected(other_point);
|
||||
let mut handles = vector.all_connected(other_point);
|
||||
let other_handle = handles.find(|handle| handle.segment == segment)?;
|
||||
|
||||
let target_position = if other_handle.length(vector_data) == 0. {
|
||||
ManipulatorPointId::Anchor(other_point).get_position(vector_data)?
|
||||
let target_position = if other_handle.length(vector) == 0. {
|
||||
ManipulatorPointId::Anchor(other_point).get_position(vector)?
|
||||
} else {
|
||||
other_handle.to_manipulator_point().get_position(vector_data)?
|
||||
other_handle.to_manipulator_point().get_position(vector)?
|
||||
};
|
||||
|
||||
let tangent_vector = target_position - position;
|
||||
@@ -1207,19 +1205,17 @@ impl PathToolData {
|
||||
let Some(layer) = document.network_interface.selected_nodes().selected_layers(document.metadata()).next() else {
|
||||
return false;
|
||||
};
|
||||
let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else {
|
||||
return false;
|
||||
};
|
||||
let Some(vector) = document.network_interface.compute_modified_vector(layer) else { return false };
|
||||
|
||||
// Check that the handles of anchor point are also colinear
|
||||
if !vector_data.colinear(*anchor) {
|
||||
if !vector.colinear(*anchor) {
|
||||
return false;
|
||||
};
|
||||
|
||||
let Some(point_id) = anchor.as_anchor() else { return false };
|
||||
|
||||
let mut connected_segments = [None, None];
|
||||
for (segment, bezier, start, end) in vector_data.segment_bezier_iter() {
|
||||
for (segment, bezier, start, end) in vector.segment_bezier_iter() {
|
||||
if start == point_id || end == point_id {
|
||||
match (connected_segments[0], connected_segments[1]) {
|
||||
(None, None) => connected_segments[0] = Some(SlidingSegmentData { segment_id: segment, bezier, start }),
|
||||
@@ -1253,7 +1249,7 @@ impl PathToolData {
|
||||
let anchor = sliding_point_info.anchor;
|
||||
let layer = sliding_point_info.layer;
|
||||
|
||||
let Some(vector_data) = network_interface.compute_modified_vector(layer) else { return };
|
||||
let Some(vector) = network_interface.compute_modified_vector(layer) else { return };
|
||||
let transform = network_interface.document_metadata().transform_to_viewport_if_feeds(layer, network_interface);
|
||||
let layer_pos = transform.inverse().transform_point2(target_position);
|
||||
|
||||
@@ -1272,12 +1268,12 @@ impl PathToolData {
|
||||
};
|
||||
|
||||
// Move the anchor to the new position
|
||||
let Some(current_position) = ManipulatorPointId::Anchor(anchor).get_position(&vector_data) else {
|
||||
let Some(current_position) = ManipulatorPointId::Anchor(anchor).get_position(&vector) else {
|
||||
return;
|
||||
};
|
||||
let delta = new_position - current_position;
|
||||
|
||||
shape_editor.move_anchor(anchor, &vector_data, delta, layer, None, responses);
|
||||
shape_editor.move_anchor(anchor, &vector, delta, layer, None, responses);
|
||||
|
||||
// Make a split at the t_value
|
||||
let [first, second] = closer_segment.bezier.split(TValue::Parametric(t_value));
|
||||
@@ -1419,19 +1415,19 @@ impl PathToolData {
|
||||
let Some(layer) = document.network_interface.selected_nodes().selected_layers(document.metadata()).next() else {
|
||||
return;
|
||||
};
|
||||
let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { return };
|
||||
let Some(point_id) = shape_editor.selected_points().next().unwrap().get_anchor(&vector_data) else {
|
||||
let Some(vector) = document.network_interface.compute_modified_vector(layer) else { return };
|
||||
let Some(point_id) = shape_editor.selected_points().next().unwrap().get_anchor(&vector) else {
|
||||
return;
|
||||
};
|
||||
|
||||
if vector_data.connected_count(point_id) == 2 {
|
||||
let connected_segments: Vec<HandleId> = vector_data.all_connected(point_id).collect();
|
||||
if vector.connected_count(point_id) == 2 {
|
||||
let connected_segments: Vec<HandleId> = vector.all_connected(point_id).collect();
|
||||
let segment1 = connected_segments[0];
|
||||
let Some(tangent1) = self.get_normalized_tangent(point_id, segment1.segment, &vector_data) else {
|
||||
let Some(tangent1) = self.get_normalized_tangent(point_id, segment1.segment, &vector) else {
|
||||
return;
|
||||
};
|
||||
let segment2 = connected_segments[1];
|
||||
let Some(tangent2) = self.get_normalized_tangent(point_id, segment2.segment, &vector_data) else {
|
||||
let Some(tangent2) = self.get_normalized_tangent(point_id, segment2.segment, &vector) else {
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -1565,11 +1561,11 @@ impl Fsm for PathToolFsmState {
|
||||
let selected_layers = shape_editor.selected_layers().cloned().collect::<Vec<_>>();
|
||||
|
||||
for layer in selected_layers {
|
||||
let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { continue };
|
||||
let Some(vector) = document.network_interface.compute_modified_vector(layer) else { continue };
|
||||
|
||||
let selected_state = shape_editor.selected_shape_state.entry(layer).or_default();
|
||||
|
||||
for (segment, _, start, end) in vector_data.segment_bezier_iter() {
|
||||
for (segment, _, start, end) in vector.segment_bezier_iter() {
|
||||
if selected_state.is_segment_selected(segment) {
|
||||
selected_state.select_point(ManipulatorPointId::Anchor(start));
|
||||
selected_state.select_point(ManipulatorPointId::Anchor(end));
|
||||
@@ -1610,11 +1606,11 @@ impl Fsm for PathToolFsmState {
|
||||
let selected_layers = shape_editor.selected_layers().cloned().collect::<Vec<_>>();
|
||||
|
||||
for layer in selected_layers {
|
||||
let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { continue };
|
||||
let Some(vector) = document.network_interface.compute_modified_vector(layer) else { continue };
|
||||
|
||||
let selected_state = shape_editor.selected_shape_state.entry(layer).or_default();
|
||||
|
||||
for (segment, _, start, end) in vector_data.segment_bezier_iter() {
|
||||
for (segment, _, start, end) in vector.segment_bezier_iter() {
|
||||
let first_selected = selected_state.is_point_selected(ManipulatorPointId::Anchor(start));
|
||||
let second_selected = selected_state.is_point_selected(ManipulatorPointId::Anchor(end));
|
||||
if first_selected && second_selected {
|
||||
@@ -1663,12 +1659,12 @@ impl Fsm for PathToolFsmState {
|
||||
let mut segment_endpoints: HashMap<SegmentId, Vec<PointId>> = HashMap::new();
|
||||
|
||||
for layer in document.network_interface.selected_nodes().selected_layers(document.metadata()) {
|
||||
let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { continue };
|
||||
let Some(vector) = document.network_interface.compute_modified_vector(layer) else { continue };
|
||||
|
||||
// The points which are part of only one segment will be rendered
|
||||
let mut selected_segments_by_point: HashMap<PointId, Vec<SegmentId>> = HashMap::new();
|
||||
|
||||
for (segment_id, _bezier, start, end) in vector_data.segment_bezier_iter() {
|
||||
for (segment_id, _bezier, start, end) in vector.segment_bezier_iter() {
|
||||
if selected_segments.contains(&segment_id) {
|
||||
selected_segments_by_point.entry(start).or_default().push(segment_id);
|
||||
selected_segments_by_point.entry(end).or_default().push(segment_id);
|
||||
@@ -1721,8 +1717,8 @@ impl Fsm for PathToolFsmState {
|
||||
);
|
||||
|
||||
let Some((layer, manipulator_point_id)) = nearest_visible_point_indices else { return };
|
||||
let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { return };
|
||||
let Some(position) = manipulator_point_id.get_position(&vector_data) else {
|
||||
let Some(vector) = document.network_interface.compute_modified_vector(layer) else { return };
|
||||
let Some(position) = manipulator_point_id.get_position(&vector) else {
|
||||
error!("No position for hovered point");
|
||||
return;
|
||||
};
|
||||
@@ -1847,10 +1843,10 @@ impl Fsm for PathToolFsmState {
|
||||
};
|
||||
|
||||
for (layer, points) in points_inside {
|
||||
let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { continue };
|
||||
let Some(vector) = document.network_interface.compute_modified_vector(layer) else { continue };
|
||||
|
||||
for point in points {
|
||||
let Some(position) = point.get_position(&vector_data) else { continue };
|
||||
let Some(position) = point.get_position(&vector) else { continue };
|
||||
|
||||
let transform = document.metadata().transform_to_viewport(layer);
|
||||
let position = transform.transform_point2(position);
|
||||
@@ -1865,11 +1861,11 @@ impl Fsm for PathToolFsmState {
|
||||
}
|
||||
|
||||
for (layer, segments) in segments_inside {
|
||||
let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { continue };
|
||||
let Some(vector) = document.network_interface.compute_modified_vector(layer) else { continue };
|
||||
|
||||
let transform = document.metadata().transform_to_viewport_if_feeds(layer, &document.network_interface);
|
||||
|
||||
for (segment, bezier, _, _) in vector_data.segment_bezier_iter() {
|
||||
for (segment, bezier, _, _) in vector.segment_bezier_iter() {
|
||||
if segments.contains(&segment) {
|
||||
overlay_context.outline_overlay_bezier(bezier, transform);
|
||||
}
|
||||
@@ -2392,8 +2388,8 @@ impl Fsm for PathToolFsmState {
|
||||
|
||||
if !drag_occurred && !tool_data.molding_segment && ((point_mode && !segment_mode) || (segment_mode && tool_data.segment_editing_modifier)) {
|
||||
if tool_data.delete_segment_pressed {
|
||||
if let Some(vector_data) = document.network_interface.compute_modified_vector(segment.layer()) {
|
||||
shape_editor.dissolve_segment(responses, segment.layer(), &vector_data, segment.segment(), segment.points());
|
||||
if let Some(vector) = document.network_interface.compute_modified_vector(segment.layer()) {
|
||||
shape_editor.dissolve_segment(responses, segment.layer(), &vector, segment.segment(), segment.points());
|
||||
}
|
||||
} else {
|
||||
let is_segment_selected = shape_editor
|
||||
@@ -2580,17 +2576,15 @@ impl Fsm for PathToolFsmState {
|
||||
continue;
|
||||
}
|
||||
|
||||
let Some(old_vector_data) = document.network_interface.compute_modified_vector(layer) else {
|
||||
continue;
|
||||
};
|
||||
let Some(old_vector) = document.network_interface.compute_modified_vector(layer) else { continue };
|
||||
|
||||
// Also get the transform node that is applied on the layer if it exists
|
||||
let transform = document.metadata().transform_to_document(layer);
|
||||
|
||||
let mut new_vector_data = VectorData::default();
|
||||
let mut new_vector = Vector::default();
|
||||
|
||||
let mut selected_points_by_segment = HashSet::new();
|
||||
old_vector_data
|
||||
old_vector
|
||||
.segment_bezier_iter()
|
||||
.filter(|(segment, _, _, _)| layer_selection_state.is_segment_selected(*segment))
|
||||
.for_each(|(_, _, start, end)| {
|
||||
@@ -2599,16 +2593,16 @@ impl Fsm for PathToolFsmState {
|
||||
});
|
||||
|
||||
// Add all the selected points
|
||||
for (point, position) in old_vector_data.point_domain.iter() {
|
||||
for (point, position) in old_vector.point_domain.iter() {
|
||||
if layer_selection_state.is_point_selected(ManipulatorPointId::Anchor(point)) || selected_points_by_segment.contains(&point) {
|
||||
new_vector_data.point_domain.push(point, position);
|
||||
new_vector.point_domain.push(point, position);
|
||||
}
|
||||
}
|
||||
|
||||
let find_index = |id: PointId| new_vector_data.point_domain.iter().enumerate().find(|(_, (point_id, _))| *point_id == id).map(|(index, _)| index);
|
||||
let find_index = |id: PointId| new_vector.point_domain.iter().enumerate().find(|(_, (point_id, _))| *point_id == id).map(|(index, _)| index);
|
||||
|
||||
// Add segments which have selected ends
|
||||
for ((segment_id, bezier, start, end), stroke) in old_vector_data.segment_bezier_iter().zip(old_vector_data.segment_domain.stroke().iter()) {
|
||||
for ((segment_id, bezier, start, end), stroke) in old_vector.segment_bezier_iter().zip(old_vector.segment_domain.stroke().iter()) {
|
||||
let both_ends_selected = layer_selection_state.is_point_selected(ManipulatorPointId::Anchor(start)) && layer_selection_state.is_point_selected(ManipulatorPointId::Anchor(end));
|
||||
|
||||
let segment_selected = layer_selection_state.is_segment_selected(segment_id);
|
||||
@@ -2618,17 +2612,17 @@ impl Fsm for PathToolFsmState {
|
||||
error!("Point does not exist in point domain");
|
||||
return PathToolFsmState::Ready;
|
||||
};
|
||||
new_vector_data.segment_domain.push(segment_id, start_index, end_index, bezier.handles, *stroke);
|
||||
new_vector.segment_domain.push(segment_id, start_index, end_index, bezier.handles, *stroke);
|
||||
}
|
||||
}
|
||||
|
||||
for handles in old_vector_data.colinear_manipulators {
|
||||
if new_vector_data.segment_domain.ids().contains(&handles[0].segment) && new_vector_data.segment_domain.ids().contains(&handles[1].segment) {
|
||||
new_vector_data.colinear_manipulators.push(handles);
|
||||
for handles in old_vector.colinear_manipulators {
|
||||
if new_vector.segment_domain.ids().contains(&handles[0].segment) && new_vector.segment_domain.ids().contains(&handles[1].segment) {
|
||||
new_vector.colinear_manipulators.push(handles);
|
||||
}
|
||||
}
|
||||
|
||||
buffer.push((layer, new_vector_data, transform));
|
||||
buffer.push((layer, new_vector, transform));
|
||||
}
|
||||
|
||||
if clipboard == Clipboard::Device {
|
||||
@@ -2650,7 +2644,7 @@ impl Fsm for PathToolFsmState {
|
||||
}
|
||||
(_, PathToolMessage::Paste { data }) => {
|
||||
// Deserialize the data
|
||||
if let Ok(data) = serde_json::from_str::<Vec<(LayerNodeIdentifier, VectorData, DAffine2)>>(&data) {
|
||||
if let Ok(data) = serde_json::from_str::<Vec<(LayerNodeIdentifier, Vector, DAffine2)>>(&data) {
|
||||
shape_editor.deselect_all_points();
|
||||
responses.add(DocumentMessage::AddTransaction);
|
||||
let mut new_layers = Vec::new();
|
||||
@@ -2690,7 +2684,7 @@ impl Fsm for PathToolFsmState {
|
||||
layer
|
||||
};
|
||||
|
||||
// Create new point ids and add those into the existing vector data
|
||||
// Create new point ids and add those into the existing vector content
|
||||
let mut points_map = HashMap::new();
|
||||
for (point, position) in new_vector.point_domain.iter() {
|
||||
let new_point_id = PointId::generate();
|
||||
@@ -2701,7 +2695,7 @@ impl Fsm for PathToolFsmState {
|
||||
responses.add(GraphOperationMessage::Vector { layer, modification_type });
|
||||
}
|
||||
|
||||
// Create new segment ids and add the segments into the existing vector data
|
||||
// Create new segment ids and add the segments into the existing vector content
|
||||
let mut segments_map = HashMap::new();
|
||||
for (segment_id, bezier, start, end) in new_vector.segment_bezier_iter() {
|
||||
let new_segment_id = SegmentId::generate();
|
||||
@@ -2777,13 +2771,13 @@ impl Fsm for PathToolFsmState {
|
||||
if layer_selection_state.is_empty() {
|
||||
continue;
|
||||
}
|
||||
let Some(old_vector_data) = document.network_interface.compute_modified_vector(layer) else {
|
||||
let Some(old_vector) = document.network_interface.compute_modified_vector(layer) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
// Add all the selected points
|
||||
let mut selected_points_by_segment = HashSet::new();
|
||||
old_vector_data
|
||||
old_vector
|
||||
.segment_bezier_iter()
|
||||
.filter(|(segment, _, _, _)| layer_selection_state.is_segment_selected(*segment))
|
||||
.for_each(|(_, _, start, end)| {
|
||||
@@ -2792,7 +2786,7 @@ impl Fsm for PathToolFsmState {
|
||||
});
|
||||
|
||||
let mut points_map = HashMap::new();
|
||||
for (point, position) in old_vector_data.point_domain.iter() {
|
||||
for (point, position) in old_vector.point_domain.iter() {
|
||||
// TODO: Either the point is selected or it is an endpoint of a selected segment
|
||||
|
||||
if layer_selection_state.is_point_selected(ManipulatorPointId::Anchor(point)) || selected_points_by_segment.contains(&point) {
|
||||
@@ -2808,7 +2802,7 @@ impl Fsm for PathToolFsmState {
|
||||
|
||||
let mut segments_map = HashMap::new();
|
||||
|
||||
for (segment_id, bezier, start, end) in old_vector_data.segment_bezier_iter() {
|
||||
for (segment_id, bezier, start, end) in old_vector.segment_bezier_iter() {
|
||||
let both_ends_selected = layer_selection_state.is_point_selected(ManipulatorPointId::Anchor(start)) && layer_selection_state.is_point_selected(ManipulatorPointId::Anchor(end));
|
||||
|
||||
let segment_selected = layer_selection_state.is_segment_selected(segment_id);
|
||||
@@ -2830,7 +2824,7 @@ impl Fsm for PathToolFsmState {
|
||||
}
|
||||
}
|
||||
|
||||
for handles in old_vector_data.colinear_manipulators {
|
||||
for handles in old_vector.colinear_manipulators {
|
||||
let to_new_handle = |handle: HandleId| -> HandleId {
|
||||
HandleId {
|
||||
ty: handle.ty,
|
||||
@@ -3104,13 +3098,13 @@ fn get_selection_status(network_interface: &NodeNetworkInterface, shape_state: &
|
||||
let Some(layer) = selection_layers.find(|(_, v)| *v > 0).map(|(k, _)| k) else {
|
||||
return SelectionStatus::None;
|
||||
};
|
||||
let Some(vector_data) = network_interface.compute_modified_vector(layer) else {
|
||||
let Some(vector) = network_interface.compute_modified_vector(layer) else {
|
||||
return SelectionStatus::None;
|
||||
};
|
||||
let Some(&point) = shape_state.selected_points().next() else {
|
||||
return SelectionStatus::None;
|
||||
};
|
||||
let Some(local_position) = point.get_position(&vector_data) else {
|
||||
let Some(local_position) = point.get_position(&vector) else {
|
||||
return SelectionStatus::None;
|
||||
};
|
||||
|
||||
@@ -3118,7 +3112,7 @@ fn get_selection_status(network_interface: &NodeNetworkInterface, shape_state: &
|
||||
.document_metadata()
|
||||
.transform_to_document_if_feeds(layer, network_interface)
|
||||
.transform_point2(local_position);
|
||||
let manipulator_angle = if vector_data.colinear(point) { ManipulatorAngle::Colinear } else { ManipulatorAngle::Free };
|
||||
let manipulator_angle = if vector.colinear(point) { ManipulatorAngle::Colinear } else { ManipulatorAngle::Free };
|
||||
|
||||
return SelectionStatus::One(SingleSelectedPoint {
|
||||
coordinates,
|
||||
@@ -3143,40 +3137,40 @@ fn calculate_lock_angle(
|
||||
shape_state: &mut ShapeState,
|
||||
responses: &mut VecDeque<Message>,
|
||||
document: &DocumentMessageHandler,
|
||||
vector_data: &VectorData,
|
||||
vector: &Vector,
|
||||
handle_id: ManipulatorPointId,
|
||||
tangent_to_neighboring_tangents: bool,
|
||||
) -> Option<f64> {
|
||||
let anchor = handle_id.get_anchor(vector_data)?;
|
||||
let anchor_position = vector_data.point_domain.position_from_id(anchor);
|
||||
let anchor = handle_id.get_anchor(vector)?;
|
||||
let anchor_position = vector.point_domain.position_from_id(anchor);
|
||||
let current_segment = handle_id.get_segment();
|
||||
let points_connected = vector_data.connected_count(anchor);
|
||||
let points_connected = vector.connected_count(anchor);
|
||||
|
||||
let (anchor_position, segment) = anchor_position.zip(current_segment)?;
|
||||
if points_connected == 1 {
|
||||
calculate_segment_angle(anchor, segment, vector_data, false)
|
||||
calculate_segment_angle(anchor, segment, vector, false)
|
||||
} else {
|
||||
let opposite_handle = handle_id
|
||||
.get_handle_pair(vector_data)
|
||||
.get_handle_pair(vector)
|
||||
.iter()
|
||||
.flatten()
|
||||
.find(|&h| h.to_manipulator_point() != handle_id)
|
||||
.copied()
|
||||
.map(|h| h.to_manipulator_point());
|
||||
let opposite_handle_position = opposite_handle.and_then(|h| h.get_position(vector_data)).filter(|pos| (pos - anchor_position).length() > 1e-6);
|
||||
let opposite_handle_position = opposite_handle.and_then(|h| h.get_position(vector)).filter(|pos| (pos - anchor_position).length() > 1e-6);
|
||||
|
||||
if let Some(opposite_pos) = opposite_handle_position {
|
||||
if !vector_data.colinear_manipulators.iter().flatten().map(|h| h.to_manipulator_point()).any(|h| h == handle_id) {
|
||||
if !vector.colinear_manipulators.iter().flatten().map(|h| h.to_manipulator_point()).any(|h| h == handle_id) {
|
||||
shape_state.convert_selected_manipulators_to_colinear_handles(responses, document);
|
||||
tool_data.temporary_colinear_handles = true;
|
||||
}
|
||||
Some(-(opposite_pos - anchor_position).angle_to(DVec2::X))
|
||||
} else {
|
||||
let angle_1 = vector_data
|
||||
let angle_1 = vector
|
||||
.adjacent_segment(&handle_id)
|
||||
.and_then(|(_, adjacent_segment)| calculate_segment_angle(anchor, adjacent_segment, vector_data, false));
|
||||
.and_then(|(_, adjacent_segment)| calculate_segment_angle(anchor, adjacent_segment, vector, false));
|
||||
|
||||
let angle_2 = calculate_segment_angle(anchor, segment, vector_data, false);
|
||||
let angle_2 = calculate_segment_angle(anchor, segment, vector, false);
|
||||
|
||||
match (angle_1, angle_2) {
|
||||
(Some(angle_1), Some(angle_2)) => {
|
||||
@@ -3195,37 +3189,32 @@ fn calculate_lock_angle(
|
||||
}
|
||||
}
|
||||
|
||||
fn check_handle_over_adjacent_anchor(handle_id: ManipulatorPointId, vector_data: &VectorData) -> Option<PointId> {
|
||||
let (anchor, handle_position) = handle_id.get_anchor(vector_data).zip(handle_id.get_position(vector_data))?;
|
||||
fn check_handle_over_adjacent_anchor(handle_id: ManipulatorPointId, vector: &Vector) -> Option<PointId> {
|
||||
let (anchor, handle_position) = handle_id.get_anchor(vector).zip(handle_id.get_position(vector))?;
|
||||
|
||||
let check_if_close = |point_id: &PointId| {
|
||||
let Some(anchor_position) = vector_data.point_domain.position_from_id(*point_id) else {
|
||||
let Some(anchor_position) = vector.point_domain.position_from_id(*point_id) else {
|
||||
return false;
|
||||
};
|
||||
(anchor_position - handle_position).length() < 10.
|
||||
};
|
||||
|
||||
vector_data.connected_points(anchor).find(check_if_close)
|
||||
vector.connected_points(anchor).find(check_if_close)
|
||||
}
|
||||
fn calculate_adjacent_anchor_tangent(
|
||||
currently_dragged_handle: ManipulatorPointId,
|
||||
anchor: Option<PointId>,
|
||||
adjacent_anchor: Option<PointId>,
|
||||
vector_data: &VectorData,
|
||||
) -> (Option<f64>, Option<DVec2>) {
|
||||
fn calculate_adjacent_anchor_tangent(currently_dragged_handle: ManipulatorPointId, anchor: Option<PointId>, adjacent_anchor: Option<PointId>, vector: &Vector) -> (Option<f64>, Option<DVec2>) {
|
||||
// Early return if no anchor or no adjacent anchors
|
||||
|
||||
let Some((dragged_handle_anchor, adjacent_anchor)) = anchor.zip(adjacent_anchor) else {
|
||||
return (None, None);
|
||||
};
|
||||
let adjacent_anchor_position = vector_data.point_domain.position_from_id(adjacent_anchor);
|
||||
let adjacent_anchor_position = vector.point_domain.position_from_id(adjacent_anchor);
|
||||
|
||||
let handles: Vec<_> = vector_data.all_connected(adjacent_anchor).filter(|handle| handle.length(vector_data) > 1e-6).collect();
|
||||
let handles: Vec<_> = vector.all_connected(adjacent_anchor).filter(|handle| handle.length(vector) > 1e-6).collect();
|
||||
|
||||
match handles.len() {
|
||||
0 => {
|
||||
// Find non-shared segments
|
||||
let non_shared_segment: Vec<_> = vector_data
|
||||
let non_shared_segment: Vec<_> = vector
|
||||
.segment_bezier_iter()
|
||||
.filter_map(|(segment_id, _, start, end)| {
|
||||
let touches_adjacent = start == adjacent_anchor || end == adjacent_anchor;
|
||||
@@ -3237,7 +3226,7 @@ fn calculate_adjacent_anchor_tangent(
|
||||
|
||||
match non_shared_segment.first() {
|
||||
Some(&segment) => {
|
||||
let angle = calculate_segment_angle(adjacent_anchor, segment, vector_data, true);
|
||||
let angle = calculate_segment_angle(adjacent_anchor, segment, vector, true);
|
||||
(angle, adjacent_anchor_position)
|
||||
}
|
||||
None => (None, None),
|
||||
@@ -3246,7 +3235,7 @@ fn calculate_adjacent_anchor_tangent(
|
||||
|
||||
1 => {
|
||||
let segment = handles[0].segment;
|
||||
let angle = calculate_segment_angle(adjacent_anchor, segment, vector_data, true);
|
||||
let angle = calculate_segment_angle(adjacent_anchor, segment, vector, true);
|
||||
(angle, adjacent_anchor_position)
|
||||
}
|
||||
|
||||
@@ -3261,7 +3250,7 @@ fn calculate_adjacent_anchor_tangent(
|
||||
};
|
||||
|
||||
let angle = shared_segment_handle
|
||||
.get_position(vector_data)
|
||||
.get_position(vector)
|
||||
.zip(adjacent_anchor_position)
|
||||
.map(|(handle, anchor)| -(handle - anchor).angle_to(DVec2::X));
|
||||
|
||||
@@ -3296,8 +3285,8 @@ fn update_dynamic_hints(
|
||||
shape_editor.selected_points().next(),
|
||||
document.network_interface.selected_nodes().selected_layers(document.metadata()).next(),
|
||||
) {
|
||||
if let Some(vector_data) = document.network_interface.compute_modified_vector(layer) {
|
||||
single_colinear_anchor_selected = vector_data.colinear(*anchor)
|
||||
if let Some(vector) = document.network_interface.compute_modified_vector(layer) {
|
||||
single_colinear_anchor_selected = vector.colinear(*anchor)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3448,9 +3437,9 @@ fn update_dynamic_hints(
|
||||
let handle1 = HandleId::primary(segment.segment());
|
||||
let handle2 = HandleId::end(segment.segment());
|
||||
|
||||
if let Some(vector_data) = document.network_interface.compute_modified_vector(segment.layer()) {
|
||||
let other_handle1 = vector_data.other_colinear_handle(handle1);
|
||||
let other_handle2 = vector_data.other_colinear_handle(handle2);
|
||||
if let Some(vector) = document.network_interface.compute_modified_vector(segment.layer()) {
|
||||
let other_handle1 = vector.other_colinear_handle(handle1);
|
||||
let other_handle2 = vector.other_colinear_handle(handle2);
|
||||
if other_handle1.is_some() || other_handle2.is_some() {
|
||||
has_colinear_anchors = true;
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@ use crate::messages::tool::common_functionality::utility_functions::{calculate_s
|
||||
use bezier_rs::{Bezier, BezierHandles};
|
||||
use graph_craft::document::NodeId;
|
||||
use graphene_std::Color;
|
||||
use graphene_std::vector::{HandleId, ManipulatorPointId, NoHashBuilder, SegmentId, StrokeId, VectorData};
|
||||
use graphene_std::vector::{PointId, VectorModificationType};
|
||||
use graphene_std::vector::misc::{HandleId, ManipulatorPointId};
|
||||
use graphene_std::vector::{NoHashBuilder, PointId, SegmentId, StrokeId, Vector, VectorModificationType};
|
||||
|
||||
#[derive(Default, ExtractField)]
|
||||
pub struct PenTool {
|
||||
@@ -395,11 +395,11 @@ impl PenToolData {
|
||||
}
|
||||
|
||||
/// Check whether target handle is primary, end, or `self.handle_end`
|
||||
fn check_end_handle_type(&self, vector_data: &VectorData) -> TargetHandle {
|
||||
fn check_end_handle_type(&self, vector: &Vector) -> TargetHandle {
|
||||
match (self.handle_end, self.prior_segment_endpoint, self.prior_segment, self.path_closed) {
|
||||
(Some(_), _, _, false) => TargetHandle::PreviewInHandle,
|
||||
(None, Some(point), Some(segment), false) | (Some(_), Some(point), Some(segment), true) => {
|
||||
if vector_data.segment_start_from_id(segment) == Some(point) {
|
||||
if vector.segment_start_from_id(segment) == Some(point) {
|
||||
TargetHandle::PriorOutHandle(segment)
|
||||
} else {
|
||||
TargetHandle::PriorInHandle(segment)
|
||||
@@ -409,23 +409,23 @@ impl PenToolData {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_grs_end_handle(&self, vector_data: &VectorData) -> TargetHandle {
|
||||
fn check_grs_end_handle(&self, vector: &Vector) -> TargetHandle {
|
||||
let Some(point) = self.latest_point().map(|point| point.id) else { return TargetHandle::None };
|
||||
let Some(segment) = self.prior_segment else { return TargetHandle::None };
|
||||
|
||||
if vector_data.segment_start_from_id(segment) == Some(point) {
|
||||
if vector.segment_start_from_id(segment) == Some(point) {
|
||||
TargetHandle::PriorOutHandle(segment)
|
||||
} else {
|
||||
TargetHandle::PriorInHandle(segment)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_opposite_handle_type(&self, handle_type: TargetHandle, vector_data: &VectorData) -> TargetHandle {
|
||||
fn get_opposite_handle_type(&self, handle_type: TargetHandle, vector: &Vector) -> TargetHandle {
|
||||
match handle_type {
|
||||
TargetHandle::FuturePreviewOutHandle => self.check_end_handle_type(vector_data),
|
||||
TargetHandle::FuturePreviewOutHandle => self.check_end_handle_type(vector),
|
||||
TargetHandle::PreviewInHandle => match (self.path_closed, self.prior_segment_endpoint, self.prior_segment) {
|
||||
(true, Some(point), Some(segment)) => {
|
||||
if vector_data.segment_start_from_id(segment) == Some(point) {
|
||||
if vector.segment_start_from_id(segment) == Some(point) {
|
||||
TargetHandle::PriorOutHandle(segment)
|
||||
} else {
|
||||
TargetHandle::PriorInHandle(segment)
|
||||
@@ -472,10 +472,10 @@ impl PenToolData {
|
||||
}
|
||||
}
|
||||
|
||||
fn target_handle_position(&self, handle_type: TargetHandle, vector_data: &VectorData) -> Option<DVec2> {
|
||||
fn target_handle_position(&self, handle_type: TargetHandle, vector: &Vector) -> Option<DVec2> {
|
||||
match handle_type {
|
||||
TargetHandle::PriorOutHandle(segment) => ManipulatorPointId::PrimaryHandle(segment).get_position(vector_data),
|
||||
TargetHandle::PriorInHandle(segment) => ManipulatorPointId::EndHandle(segment).get_position(vector_data),
|
||||
TargetHandle::PriorOutHandle(segment) => ManipulatorPointId::PrimaryHandle(segment).get_position(vector),
|
||||
TargetHandle::PriorInHandle(segment) => ManipulatorPointId::EndHandle(segment).get_position(vector),
|
||||
TargetHandle::PreviewInHandle => self.handle_end,
|
||||
TargetHandle::FuturePreviewOutHandle => Some(self.next_handle_start),
|
||||
TargetHandle::None => None,
|
||||
@@ -488,11 +488,11 @@ impl PenToolData {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(vector_data) = layer.and_then(|layer| document.network_interface.compute_modified_vector(layer)) else {
|
||||
let Some(vector) = layer.and_then(|layer| document.network_interface.compute_modified_vector(layer)) else {
|
||||
return;
|
||||
};
|
||||
|
||||
match self.check_end_handle_type(&vector_data) {
|
||||
match self.check_end_handle_type(&vector) {
|
||||
TargetHandle::PriorInHandle(segment) => shape_state.deselect_point(ManipulatorPointId::EndHandle(segment)),
|
||||
TargetHandle::PriorOutHandle(segment) => shape_state.deselect_point(ManipulatorPointId::PrimaryHandle(segment)),
|
||||
_ => {}
|
||||
@@ -518,18 +518,14 @@ impl PenToolData {
|
||||
self.latest_points.len() == 1 && self.latest_point().is_some_and(|point| point.pos == self.next_point)
|
||||
}
|
||||
|
||||
// When the vector data transform changes, the positions of the points must be recalculated.
|
||||
// When the vector transform changes, the positions of the points must be recalculated.
|
||||
fn recalculate_latest_points_position(&mut self, document: &DocumentMessageHandler) {
|
||||
let selected_nodes = document.network_interface.selected_nodes();
|
||||
let mut selected_layers = selected_nodes.selected_layers(document.metadata());
|
||||
if let (Some(layer), None) = (selected_layers.next(), selected_layers.next()) {
|
||||
let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else {
|
||||
return;
|
||||
};
|
||||
let Some(vector) = document.network_interface.compute_modified_vector(layer) else { return };
|
||||
for point in &mut self.latest_points {
|
||||
let Some(pos) = vector_data.point_domain.position_from_id(point.id) else {
|
||||
continue;
|
||||
};
|
||||
let Some(pos) = vector.point_domain.position_from_id(point.id) else { continue };
|
||||
point.pos = pos;
|
||||
point.handle_start = point.pos;
|
||||
}
|
||||
@@ -549,7 +545,7 @@ impl PenToolData {
|
||||
self.g1_continuous = true;
|
||||
let document = snap_data.document;
|
||||
self.next_handle_start = self.next_point;
|
||||
let vector_data = document.network_interface.compute_modified_vector(layer).unwrap();
|
||||
let vector = document.network_interface.compute_modified_vector(layer).unwrap();
|
||||
self.update_handle_type(TargetHandle::FuturePreviewOutHandle);
|
||||
self.handle_mode = HandleMode::ColinearLocked;
|
||||
|
||||
@@ -565,7 +561,7 @@ impl PenToolData {
|
||||
self.store_clicked_endpoint(document, &transform, snap_data.input, preferences);
|
||||
|
||||
if self.modifiers.lock_angle {
|
||||
self.set_lock_angle(&vector_data, id, self.prior_segment);
|
||||
self.set_lock_angle(&vector, id, self.prior_segment);
|
||||
let last_segment = self.prior_segment;
|
||||
let Some(point) = self.latest_point_mut() else { return };
|
||||
point.in_segment = last_segment;
|
||||
@@ -579,7 +575,7 @@ impl PenToolData {
|
||||
}
|
||||
|
||||
// Closing path
|
||||
let closing_path_on_point = self.close_path_on_point(snap_data, &vector_data, document, preferences, id, &transform);
|
||||
let closing_path_on_point = self.close_path_on_point(snap_data, &vector, document, preferences, id, &transform);
|
||||
if !closing_path_on_point && preferences.vector_meshes {
|
||||
// Attempt to find nearest segment and close path on segment by creating an anchor point on it
|
||||
let tolerance = crate::consts::SNAP_POINT_TOLERANCE;
|
||||
@@ -600,24 +596,16 @@ impl PenToolData {
|
||||
|
||||
self.handle_mode = HandleMode::Free;
|
||||
if let (true, Some(prior_endpoint)) = (self.modifiers.lock_angle, self.prior_segment_endpoint) {
|
||||
self.set_lock_angle(&vector_data, prior_endpoint, self.prior_segment);
|
||||
self.set_lock_angle(&vector, prior_endpoint, self.prior_segment);
|
||||
self.switch_to_free_on_ctrl_release = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn close_path_on_point(
|
||||
&mut self,
|
||||
snap_data: SnapData,
|
||||
vector_data: &VectorData,
|
||||
document: &DocumentMessageHandler,
|
||||
preferences: &PreferencesMessageHandler,
|
||||
id: PointId,
|
||||
transform: &DAffine2,
|
||||
) -> bool {
|
||||
for id in vector_data.extendable_points(preferences.vector_meshes).filter(|&point| point != id) {
|
||||
let Some(pos) = vector_data.point_domain.position_from_id(id) else { continue };
|
||||
fn close_path_on_point(&mut self, snap_data: SnapData, vector: &Vector, document: &DocumentMessageHandler, preferences: &PreferencesMessageHandler, id: PointId, transform: &DAffine2) -> bool {
|
||||
for id in vector.extendable_points(preferences.vector_meshes).filter(|&point| point != id) {
|
||||
let Some(pos) = vector.point_domain.position_from_id(id) else { continue };
|
||||
let transformed_distance_between_squared = transform.transform_point2(pos).distance_squared(transform.transform_point2(self.next_point));
|
||||
let snap_point_tolerance_squared = crate::consts::SNAP_POINT_TOLERANCE.powi(2);
|
||||
|
||||
@@ -629,7 +617,7 @@ impl PenToolData {
|
||||
self.store_clicked_endpoint(document, transform, snap_data.input, preferences);
|
||||
self.handle_mode = HandleMode::Free;
|
||||
if let (true, Some(prior_endpoint)) = (self.modifiers.lock_angle, self.prior_segment_endpoint) {
|
||||
self.set_lock_angle(vector_data, prior_endpoint, self.prior_segment);
|
||||
self.set_lock_angle(vector, prior_endpoint, self.prior_segment);
|
||||
self.switch_to_free_on_ctrl_release = true;
|
||||
}
|
||||
return true;
|
||||
@@ -662,11 +650,11 @@ impl PenToolData {
|
||||
let selected_nodes = document.network_interface.selected_nodes();
|
||||
let mut selected_layers = selected_nodes.selected_layers(document.metadata());
|
||||
let layer = selected_layers.next().filter(|_| selected_layers.next().is_none()).or(self.current_layer)?;
|
||||
let vector_data = document.network_interface.compute_modified_vector(layer)?;
|
||||
let vector = document.network_interface.compute_modified_vector(layer)?;
|
||||
let start = self.latest_point()?.id;
|
||||
let transform = document.metadata().document_to_viewport * transform;
|
||||
for id in vector_data.extendable_points(preferences.vector_meshes).filter(|&point| point != start) {
|
||||
let Some(pos) = vector_data.point_domain.position_from_id(id) else { continue };
|
||||
for id in vector.extendable_points(preferences.vector_meshes).filter(|&point| point != start) {
|
||||
let Some(pos) = vector.point_domain.position_from_id(id) else { continue };
|
||||
let transformed_distance_between_squared = transform.transform_point2(pos).distance_squared(transform.transform_point2(next_point));
|
||||
let snap_point_tolerance_squared = crate::consts::SNAP_POINT_TOLERANCE.powi(2);
|
||||
if transformed_distance_between_squared < snap_point_tolerance_squared {
|
||||
@@ -687,15 +675,15 @@ impl PenToolData {
|
||||
// Store the segment
|
||||
let id = SegmentId::generate();
|
||||
if self.path_closed {
|
||||
if let Some((handles, handle1_pos)) = match self.get_opposite_handle_type(TargetHandle::PreviewInHandle, &vector_data) {
|
||||
if let Some((handles, handle1_pos)) = match self.get_opposite_handle_type(TargetHandle::PreviewInHandle, &vector) {
|
||||
TargetHandle::PriorOutHandle(segment) => {
|
||||
let handles = [HandleId::end(id), HandleId::primary(segment)];
|
||||
let handle1_pos = handles[1].to_manipulator_point().get_position(&vector_data);
|
||||
let handle1_pos = handles[1].to_manipulator_point().get_position(&vector);
|
||||
handle1_pos.map(|pos| (handles, pos))
|
||||
}
|
||||
TargetHandle::PriorInHandle(segment) => {
|
||||
let handles = [HandleId::end(id), HandleId::end(segment)];
|
||||
let handle1_pos = handles[1].to_manipulator_point().get_position(&vector_data);
|
||||
let handle1_pos = handles[1].to_manipulator_point().get_position(&vector);
|
||||
handle1_pos.map(|pos| (handles, pos))
|
||||
}
|
||||
_ => None,
|
||||
@@ -719,14 +707,14 @@ impl PenToolData {
|
||||
|
||||
// Mirror
|
||||
if let Some((last_segment, last_point)) = self.latest_point().and_then(|point| point.in_segment).zip(self.latest_point()) {
|
||||
let end = vector_data.segment_end_from_id(last_segment) == Some(last_point.id);
|
||||
let end = vector.segment_end_from_id(last_segment) == Some(last_point.id);
|
||||
let handles = if end {
|
||||
[HandleId::end(last_segment), HandleId::primary(id)]
|
||||
} else {
|
||||
[HandleId::primary(last_segment), HandleId::primary(id)]
|
||||
};
|
||||
|
||||
if let Some(h1) = handles[0].to_manipulator_point().get_position(&vector_data) {
|
||||
if let Some(h1) = handles[0].to_manipulator_point().get_position(&vector) {
|
||||
let angle = (h1 - last_point.pos).angle_to(last_point.handle_start - last_point.pos);
|
||||
let pi = std::f64::consts::PI;
|
||||
let colinear = (angle - pi).abs() < 1e-6 || (angle + pi).abs() < 1e-6;
|
||||
@@ -758,13 +746,13 @@ impl PenToolData {
|
||||
transform: &DAffine2,
|
||||
snap_data: &SnapData<'_>,
|
||||
mouse: &DVec2,
|
||||
vector_data: &VectorData,
|
||||
vector: &Vector,
|
||||
input: &InputPreprocessorMessageHandler,
|
||||
) -> Option<DVec2> {
|
||||
let reference_handle = if self.path_closed { TargetHandle::PreviewInHandle } else { TargetHandle::FuturePreviewOutHandle };
|
||||
let end_handle = self.get_opposite_handle_type(reference_handle, vector_data);
|
||||
let end_handle_pos = self.target_handle_position(end_handle, vector_data);
|
||||
let ref_pos = self.target_handle_position(reference_handle, vector_data)?;
|
||||
let end_handle = self.get_opposite_handle_type(reference_handle, vector);
|
||||
let end_handle_pos = self.target_handle_position(end_handle, vector);
|
||||
let ref_pos = self.target_handle_position(reference_handle, vector)?;
|
||||
let snap = &mut self.snap_manager;
|
||||
let snap_data = SnapData::new_snap_cache(snap_data.document, input, &self.snap_cache);
|
||||
|
||||
@@ -826,7 +814,7 @@ impl PenToolData {
|
||||
responses: &mut VecDeque<Message>,
|
||||
) {
|
||||
// Validate necessary data exists
|
||||
let Some(vector_data) = layer.and_then(|layer| document.network_interface.compute_modified_vector(layer)) else {
|
||||
let Some(vector) = layer.and_then(|layer| document.network_interface.compute_modified_vector(layer)) else {
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -842,9 +830,9 @@ impl PenToolData {
|
||||
let should_swap_to_start = !self.path_closed && !matches!(self.handle_type, TargetHandle::None | TargetHandle::FuturePreviewOutHandle);
|
||||
|
||||
if should_swap_to_opposite {
|
||||
let opposite_type = self.get_opposite_handle_type(self.handle_type, &vector_data);
|
||||
let opposite_type = self.get_opposite_handle_type(self.handle_type, &vector);
|
||||
// Update offset
|
||||
let Some(handle_pos) = self.target_handle_position(opposite_type, &vector_data) else {
|
||||
let Some(handle_pos) = self.target_handle_position(opposite_type, &vector) else {
|
||||
self.handle_swapped = false;
|
||||
return;
|
||||
};
|
||||
@@ -894,7 +882,7 @@ impl PenToolData {
|
||||
Some(PenToolFsmState::DraggingHandle(self.handle_mode))
|
||||
}
|
||||
|
||||
fn move_anchor_and_handles(&mut self, delta: DVec2, layer: LayerNodeIdentifier, responses: &mut VecDeque<Message>, vector_data: &VectorData) {
|
||||
fn move_anchor_and_handles(&mut self, delta: DVec2, layer: LayerNodeIdentifier, responses: &mut VecDeque<Message>, vector: &Vector) {
|
||||
if self.handle_end.is_none() {
|
||||
if let Some(latest_pt) = self.latest_point_mut() {
|
||||
latest_pt.pos += delta;
|
||||
@@ -912,10 +900,10 @@ impl PenToolData {
|
||||
let reference_handle = if self.path_closed { TargetHandle::PreviewInHandle } else { TargetHandle::FuturePreviewOutHandle };
|
||||
|
||||
// Move the end handle
|
||||
let end_handle_type = self.get_opposite_handle_type(reference_handle, vector_data);
|
||||
let end_handle_type = self.get_opposite_handle_type(reference_handle, vector);
|
||||
match end_handle_type {
|
||||
TargetHandle::PriorInHandle(..) | TargetHandle::PriorOutHandle(..) => {
|
||||
let Some(handle_pos) = self.target_handle_position(end_handle_type, vector_data) else { return };
|
||||
let Some(handle_pos) = self.target_handle_position(end_handle_type, vector) else { return };
|
||||
self.update_target_handle_pos(end_handle_type, self.next_point, responses, handle_pos + delta, layer);
|
||||
}
|
||||
_ => {}
|
||||
@@ -934,13 +922,13 @@ impl PenToolData {
|
||||
let colinear = (self.handle_mode == HandleMode::ColinearEquidistant && self.modifiers.break_handle) || (self.handle_mode == HandleMode::ColinearLocked && !self.modifiers.break_handle);
|
||||
let document = snap_data.document;
|
||||
let Some(layer) = layer else { return Some(PenToolFsmState::DraggingHandle(self.handle_mode)) };
|
||||
let vector_data = document.network_interface.compute_modified_vector(layer)?;
|
||||
let vector = document.network_interface.compute_modified_vector(layer)?;
|
||||
let viewport_to_document = document.metadata().document_to_viewport.inverse();
|
||||
let mut mouse_pos = mouse;
|
||||
|
||||
// Handles pressing Space to drag anchor and its handles
|
||||
if self.modifiers.move_anchor_with_handles {
|
||||
let Some(delta) = self.space_anchor_handle_snap(&viewport_to_document, &transform, &snap_data, &mouse, &vector_data, input) else {
|
||||
let Some(delta) = self.space_anchor_handle_snap(&viewport_to_document, &transform, &snap_data, &mouse, &vector, input) else {
|
||||
return Some(PenToolFsmState::DraggingHandle(self.handle_mode));
|
||||
};
|
||||
|
||||
@@ -959,7 +947,7 @@ impl PenToolData {
|
||||
};
|
||||
}
|
||||
|
||||
self.move_anchor_and_handles(delta, layer, responses, &vector_data);
|
||||
self.move_anchor_and_handles(delta, layer, responses, &vector);
|
||||
|
||||
responses.add(OverlaysMessage::Draw);
|
||||
return Some(PenToolFsmState::DraggingHandle(self.handle_mode));
|
||||
@@ -994,8 +982,8 @@ impl PenToolData {
|
||||
match self.handle_mode {
|
||||
HandleMode::ColinearLocked | HandleMode::ColinearEquidistant => {
|
||||
self.g1_continuous = true;
|
||||
self.apply_colinear_constraint(responses, layer, self.next_point, &vector_data);
|
||||
self.adjust_handle_length(responses, layer, &vector_data);
|
||||
self.apply_colinear_constraint(responses, layer, self.next_point, &vector);
|
||||
self.adjust_handle_length(responses, layer, &vector);
|
||||
}
|
||||
HandleMode::Free => {
|
||||
self.g1_continuous = false;
|
||||
@@ -1006,7 +994,7 @@ impl PenToolData {
|
||||
let Some(endpoint) = self.prior_segment_endpoint else {
|
||||
return Some(PenToolFsmState::DraggingHandle(self.handle_mode));
|
||||
};
|
||||
self.set_lock_angle(&vector_data, endpoint, self.prior_segment);
|
||||
self.set_lock_angle(&vector, endpoint, self.prior_segment);
|
||||
self.switch_to_free_on_ctrl_release = true;
|
||||
let last_segment = self.prior_segment;
|
||||
if let Some(latest) = self.latest_point_mut() {
|
||||
@@ -1020,19 +1008,19 @@ impl PenToolData {
|
||||
}
|
||||
|
||||
/// Makes the opposite handle equidistant or locks its length.
|
||||
fn adjust_handle_length(&mut self, responses: &mut VecDeque<Message>, layer: LayerNodeIdentifier, vector_data: &VectorData) {
|
||||
let opposite_handle_type = self.get_opposite_handle_type(self.handle_type, vector_data);
|
||||
fn adjust_handle_length(&mut self, responses: &mut VecDeque<Message>, layer: LayerNodeIdentifier, vector: &Vector) {
|
||||
let opposite_handle_type = self.get_opposite_handle_type(self.handle_type, vector);
|
||||
match self.handle_mode {
|
||||
HandleMode::ColinearEquidistant => {
|
||||
if self.modifiers.break_handle {
|
||||
// Store handle for later restoration only when Alt is first pressed
|
||||
if !self.alt_pressed {
|
||||
self.previous_handle_end_pos = self.target_handle_position(opposite_handle_type, vector_data);
|
||||
self.previous_handle_end_pos = self.target_handle_position(opposite_handle_type, vector);
|
||||
self.alt_pressed = true;
|
||||
}
|
||||
|
||||
// Set handle to opposite position of the other handle
|
||||
let Some(new_position) = self.target_handle_position(self.handle_type, vector_data).map(|handle| self.next_point * 2. - handle) else {
|
||||
let Some(new_position) = self.target_handle_position(self.handle_type, vector).map(|handle| self.next_point * 2. - handle) else {
|
||||
return;
|
||||
};
|
||||
self.update_target_handle_pos(opposite_handle_type, self.next_point, responses, new_position, layer);
|
||||
@@ -1047,7 +1035,7 @@ impl PenToolData {
|
||||
}
|
||||
HandleMode::ColinearLocked => {
|
||||
if !self.modifiers.break_handle {
|
||||
let Some(new_position) = self.target_handle_position(self.handle_type, vector_data).map(|handle| self.next_point * 2. - handle) else {
|
||||
let Some(new_position) = self.target_handle_position(self.handle_type, vector).map(|handle| self.next_point * 2. - handle) else {
|
||||
return;
|
||||
};
|
||||
self.update_target_handle_pos(opposite_handle_type, self.next_point, responses, new_position, layer);
|
||||
@@ -1057,23 +1045,23 @@ impl PenToolData {
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_colinear_constraint(&mut self, responses: &mut VecDeque<Message>, layer: LayerNodeIdentifier, anchor_pos: DVec2, vector_data: &VectorData) {
|
||||
let Some(handle) = self.target_handle_position(self.handle_type, vector_data) else {
|
||||
return;
|
||||
};
|
||||
fn apply_colinear_constraint(&mut self, responses: &mut VecDeque<Message>, layer: LayerNodeIdentifier, anchor_pos: DVec2, vector: &Vector) {
|
||||
let Some(handle) = self.target_handle_position(self.handle_type, vector) else { return };
|
||||
|
||||
if (anchor_pos - handle).length() < 1e-6 && self.modifiers.lock_angle {
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(direction) = (anchor_pos - handle).try_normalize() else {
|
||||
return;
|
||||
};
|
||||
let opposite_handle = self.get_opposite_handle_type(self.handle_type, vector_data);
|
||||
let Some(handle_offset) = self.target_handle_position(opposite_handle, vector_data).map(|handle| (handle - anchor_pos).length()) else {
|
||||
let Some(direction) = (anchor_pos - handle).try_normalize() else { return };
|
||||
|
||||
let opposite_handle = self.get_opposite_handle_type(self.handle_type, vector);
|
||||
|
||||
let Some(handle_offset) = self.target_handle_position(opposite_handle, vector).map(|handle| (handle - anchor_pos).length()) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let new_handle_position = anchor_pos + handle_offset * direction;
|
||||
|
||||
self.update_target_handle_pos(opposite_handle, self.next_point, responses, new_handle_position, layer);
|
||||
}
|
||||
|
||||
@@ -1086,10 +1074,10 @@ impl PenToolData {
|
||||
let selected_nodes = document.network_interface.selected_nodes();
|
||||
let mut selected_layers = selected_nodes.selected_layers(document.metadata());
|
||||
let layer = selected_layers.next().filter(|_| selected_layers.next().is_none()).or(self.current_layer)?;
|
||||
let vector_data = document.network_interface.compute_modified_vector(layer)?;
|
||||
let vector = document.network_interface.compute_modified_vector(layer)?;
|
||||
let transform = document.metadata().document_to_viewport * transform;
|
||||
for point in vector_data.extendable_points(preferences.vector_meshes) {
|
||||
let Some(pos) = vector_data.point_domain.position_from_id(point) else { continue };
|
||||
for point in vector.extendable_points(preferences.vector_meshes) {
|
||||
let Some(pos) = vector.point_domain.position_from_id(point) else { continue };
|
||||
let transformed_distance_between_squared = transform.transform_point2(pos).distance_squared(transform.transform_point2(self.next_point));
|
||||
let snap_point_tolerance_squared = crate::consts::SNAP_POINT_TOLERANCE.powi(2);
|
||||
if transformed_distance_between_squared < snap_point_tolerance_squared {
|
||||
@@ -1217,11 +1205,11 @@ impl PenToolData {
|
||||
|
||||
if append {
|
||||
if let Some((layer, point, _)) = closest_point(document, viewport, tolerance, document.metadata().all_layers(), |_| false, preferences) {
|
||||
let vector_data = document.network_interface.compute_modified_vector(layer).unwrap();
|
||||
let segment = vector_data.all_connected(point).collect::<Vec<_>>().first().map(|s| s.segment);
|
||||
let vector = document.network_interface.compute_modified_vector(layer).unwrap();
|
||||
let segment = vector.all_connected(point).collect::<Vec<_>>().first().map(|s| s.segment);
|
||||
|
||||
if self.modifiers.lock_angle {
|
||||
self.set_lock_angle(&vector_data, point, segment);
|
||||
self.set_lock_angle(&vector, point, segment);
|
||||
self.switch_to_free_on_ctrl_release = true;
|
||||
}
|
||||
}
|
||||
@@ -1235,11 +1223,11 @@ impl PenToolData {
|
||||
}
|
||||
|
||||
if let Some((layer, point, _position)) = closest_point(document, viewport, tolerance, document.metadata().all_layers(), |_| false, preferences) {
|
||||
let vector_data = document.network_interface.compute_modified_vector(layer).unwrap();
|
||||
let segment = vector_data.all_connected(point).collect::<Vec<_>>().first().map(|s| s.segment);
|
||||
let vector = document.network_interface.compute_modified_vector(layer).unwrap();
|
||||
let segment = vector.all_connected(point).collect::<Vec<_>>().first().map(|s| s.segment);
|
||||
self.handle_mode = HandleMode::Free;
|
||||
if self.modifiers.lock_angle {
|
||||
self.set_lock_angle(&vector_data, point, segment);
|
||||
self.set_lock_angle(&vector, point, segment);
|
||||
self.switch_to_free_on_ctrl_release = true;
|
||||
}
|
||||
}
|
||||
@@ -1265,9 +1253,9 @@ impl PenToolData {
|
||||
|
||||
/// Perform extension of an existing path
|
||||
fn extend_existing_path(&mut self, document: &DocumentMessageHandler, layer: LayerNodeIdentifier, point: PointId, position: DVec2) {
|
||||
let vector_data = document.network_interface.compute_modified_vector(layer);
|
||||
let (handle_start, in_segment) = if let Some(vector_data) = &vector_data {
|
||||
vector_data
|
||||
let vector = document.network_interface.compute_modified_vector(layer);
|
||||
let (handle_start, in_segment) = if let Some(vector) = &vector {
|
||||
vector
|
||||
.segment_bezier_iter()
|
||||
.find_map(|(segment_id, bezier, start, end)| {
|
||||
let is_end = point == end;
|
||||
@@ -1310,12 +1298,12 @@ impl PenToolData {
|
||||
|
||||
self.next_point = position;
|
||||
self.next_handle_start = handle_start;
|
||||
let vector_data = document.network_interface.compute_modified_vector(layer).unwrap();
|
||||
let segment = vector_data.all_connected(point).collect::<Vec<_>>().first().map(|s| s.segment);
|
||||
let vector = document.network_interface.compute_modified_vector(layer).unwrap();
|
||||
let segment = vector.all_connected(point).collect::<Vec<_>>().first().map(|s| s.segment);
|
||||
self.handle_mode = HandleMode::Free;
|
||||
|
||||
if self.modifiers.lock_angle {
|
||||
self.set_lock_angle(&vector_data, point, segment);
|
||||
self.set_lock_angle(&vector, point, segment);
|
||||
self.switch_to_free_on_ctrl_release = true;
|
||||
}
|
||||
}
|
||||
@@ -1340,11 +1328,11 @@ impl PenToolData {
|
||||
if let Some((layer, point, _position)) = closest_point(document, viewport, tolerance, document.metadata().all_layers(), |_| false, preferences) {
|
||||
self.prior_segment_endpoint = Some(point);
|
||||
self.prior_segment_layer = Some(layer);
|
||||
let vector_data = document.network_interface.compute_modified_vector(layer).unwrap();
|
||||
let segment = vector_data.all_connected(point).collect::<Vec<_>>().first().map(|s| s.segment);
|
||||
let vector = document.network_interface.compute_modified_vector(layer).unwrap();
|
||||
let segment = vector.all_connected(point).collect::<Vec<_>>().first().map(|s| s.segment);
|
||||
self.prior_segment = segment;
|
||||
layer_manipulators.insert(point);
|
||||
for (&id, &position) in vector_data.point_domain.ids().iter().zip(vector_data.point_domain.positions()) {
|
||||
for (&id, &position) in vector.point_domain.ids().iter().zip(vector.point_domain.positions()) {
|
||||
if id == point {
|
||||
continue;
|
||||
}
|
||||
@@ -1355,8 +1343,8 @@ impl PenToolData {
|
||||
}
|
||||
}
|
||||
|
||||
fn set_lock_angle(&mut self, vector_data: &VectorData, anchor: PointId, segment: Option<SegmentId>) {
|
||||
let anchor_position = vector_data.point_domain.position_from_id(anchor);
|
||||
fn set_lock_angle(&mut self, vector: &Vector, anchor: PointId, segment: Option<SegmentId>) {
|
||||
let anchor_position = vector.point_domain.position_from_id(anchor);
|
||||
|
||||
let Some((anchor_position, segment)) = anchor_position.zip(segment) else {
|
||||
self.handle_mode = HandleMode::Free;
|
||||
@@ -1365,7 +1353,7 @@ impl PenToolData {
|
||||
|
||||
match (self.handle_type, self.path_closed) {
|
||||
(TargetHandle::FuturePreviewOutHandle, _) | (TargetHandle::PreviewInHandle, true) => {
|
||||
if let Some(required_handle) = calculate_segment_angle(anchor, segment, vector_data, true) {
|
||||
if let Some(required_handle) = calculate_segment_angle(anchor, segment, vector, true) {
|
||||
self.angle = required_handle;
|
||||
self.handle_mode = HandleMode::ColinearEquidistant;
|
||||
}
|
||||
@@ -1460,12 +1448,12 @@ impl Fsm for PenToolFsmState {
|
||||
responses.add(TransformLayerMessage::BeginScalePen { last_point, handle });
|
||||
}
|
||||
|
||||
let vector_data = document.network_interface.compute_modified_vector(layer).unwrap();
|
||||
let vector = document.network_interface.compute_modified_vector(layer).unwrap();
|
||||
tool_data.previous_handle_start_pos = latest.handle_start;
|
||||
let opposite_handle = tool_data.check_grs_end_handle(&vector_data);
|
||||
tool_data.previous_handle_end_pos = tool_data.target_handle_position(opposite_handle, &vector_data);
|
||||
let opposite_handle = tool_data.check_grs_end_handle(&vector);
|
||||
tool_data.previous_handle_end_pos = tool_data.target_handle_position(opposite_handle, &vector);
|
||||
let handle1 = latest_handle_start - latest_pos;
|
||||
let Some(opposite_handle_pos) = tool_data.target_handle_position(opposite_handle, &vector_data) else {
|
||||
let Some(opposite_handle_pos) = tool_data.target_handle_position(opposite_handle, &vector) else {
|
||||
return PenToolFsmState::GRSHandle;
|
||||
};
|
||||
let handle2 = opposite_handle_pos - latest_pos;
|
||||
@@ -1476,8 +1464,8 @@ impl Fsm for PenToolFsmState {
|
||||
}
|
||||
(PenToolFsmState::GRSHandle, PenToolMessage::FinalPosition { final_position }) => {
|
||||
let Some(layer) = layer else { return PenToolFsmState::GRSHandle };
|
||||
let vector_data = document.network_interface.compute_modified_vector(layer);
|
||||
let Some(vector_data) = vector_data else { return PenToolFsmState::GRSHandle };
|
||||
let vector = document.network_interface.compute_modified_vector(layer);
|
||||
let Some(vector) = vector else { return PenToolFsmState::GRSHandle };
|
||||
|
||||
if let Some(latest_pt) = tool_data.latest_point_mut() {
|
||||
let layer_space_to_viewport = document.metadata().transform_to_viewport(layer);
|
||||
@@ -1489,8 +1477,8 @@ impl Fsm for PenToolFsmState {
|
||||
let Some(latest) = tool_data.latest_point() else {
|
||||
return PenToolFsmState::GRSHandle;
|
||||
};
|
||||
let opposite_handle = tool_data.check_grs_end_handle(&vector_data);
|
||||
let Some(opposite_handle_pos) = tool_data.target_handle_position(opposite_handle, &vector_data) else {
|
||||
let opposite_handle = tool_data.check_grs_end_handle(&vector);
|
||||
let Some(opposite_handle_pos) = tool_data.target_handle_position(opposite_handle, &vector) else {
|
||||
return PenToolFsmState::GRSHandle;
|
||||
};
|
||||
|
||||
@@ -1531,8 +1519,8 @@ impl Fsm for PenToolFsmState {
|
||||
tool_data.next_handle_start = input.mouse.position;
|
||||
|
||||
let Some(layer) = layer else { return PenToolFsmState::GRSHandle };
|
||||
let vector_data = document.network_interface.compute_modified_vector(layer).unwrap();
|
||||
let opposite_handle = tool_data.check_grs_end_handle(&vector_data);
|
||||
let vector = document.network_interface.compute_modified_vector(layer).unwrap();
|
||||
let opposite_handle = tool_data.check_grs_end_handle(&vector);
|
||||
|
||||
let previous = tool_data.previous_handle_start_pos;
|
||||
if let Some(latest) = tool_data.latest_point_mut() {
|
||||
@@ -1722,10 +1710,10 @@ impl Fsm for PenToolFsmState {
|
||||
let start = latest_point.id;
|
||||
|
||||
if let Some(layer) = layer
|
||||
&& let Some(mut vector_data) = document.network_interface.compute_modified_vector(layer)
|
||||
&& let Some(mut vector) = document.network_interface.compute_modified_vector(layer)
|
||||
{
|
||||
let closest_point = vector_data.extendable_points(preferences.vector_meshes).filter(|&id| id != start).find(|&id| {
|
||||
vector_data.point_domain.position_from_id(id).map_or(false, |pos| {
|
||||
let closest_point = vector.extendable_points(preferences.vector_meshes).filter(|&id| id != start).find(|&id| {
|
||||
vector.point_domain.position_from_id(id).is_some_and(|pos| {
|
||||
let dist_sq = transform.transform_point2(pos).distance_squared(transform.transform_point2(next_point));
|
||||
dist_sq < crate::consts::SNAP_POINT_TOLERANCE.powi(2)
|
||||
})
|
||||
@@ -1734,21 +1722,21 @@ impl Fsm for PenToolFsmState {
|
||||
// We have the point. Join the 2 vertices and check if any path is closed.
|
||||
if let Some(end) = closest_point {
|
||||
let segment_id = SegmentId::generate();
|
||||
vector_data.push(segment_id, start, end, BezierHandles::Cubic { handle_start, handle_end }, StrokeId::ZERO);
|
||||
vector.push(segment_id, start, end, BezierHandles::Cubic { handle_start, handle_end }, StrokeId::ZERO);
|
||||
|
||||
let grouped_segments = vector_data.auto_join_paths();
|
||||
let grouped_segments = vector.auto_join_paths();
|
||||
let closed_paths = grouped_segments.iter().filter(|path| path.is_closed() && path.contains(segment_id));
|
||||
|
||||
let subpaths: Vec<_> = closed_paths
|
||||
.filter_map(|path| {
|
||||
let segments = path.edges.iter().filter_map(|edge| {
|
||||
vector_data
|
||||
vector
|
||||
.segment_domain
|
||||
.iter()
|
||||
.find(|(id, _, _, _)| id == &edge.id)
|
||||
.map(|(_, start, end, bezier)| if start == edge.start { (bezier, start, end) } else { (bezier.reversed(), end, start) })
|
||||
});
|
||||
vector_data.subpath_from_segments_ignore_discontinuities(segments)
|
||||
vector.subpath_from_segments_ignore_discontinuities(segments)
|
||||
})
|
||||
.collect();
|
||||
|
||||
@@ -1817,7 +1805,8 @@ impl Fsm for PenToolFsmState {
|
||||
}
|
||||
// Merge two layers if the point is connected to the end point of another path
|
||||
|
||||
// This might not be the correct solution to artboards being included as the other layer, which occurs due to the compute_modified_vector call in should_extend using the click targets for a layer instead of vector data.
|
||||
// This might not be the correct solution to artboards being included as the other layer,
|
||||
// which occurs due to the `compute_modified_vector` call in `should_extend` using the click targets for a layer instead of vector.
|
||||
let layers = LayerNodeIdentifier::ROOT_PARENT
|
||||
.descendants(document.metadata())
|
||||
.filter(|layer| !document.network_interface.is_artboard(&layer.to_node(), &[]));
|
||||
@@ -1887,7 +1876,7 @@ impl Fsm for PenToolFsmState {
|
||||
tool_data.toggle_colinear_debounce = true;
|
||||
}
|
||||
|
||||
let Some(vector_data) = layer.and_then(|layer| document.network_interface.compute_modified_vector(layer)) else {
|
||||
let Some(vector) = layer.and_then(|layer| document.network_interface.compute_modified_vector(layer)) else {
|
||||
return self;
|
||||
};
|
||||
|
||||
@@ -1901,7 +1890,7 @@ impl Fsm for PenToolFsmState {
|
||||
document
|
||||
.metadata()
|
||||
.transform_to_viewport(layer)
|
||||
.transform_point2(tool_data.target_handle_position(reference_handle, &vector_data).unwrap())
|
||||
.transform_point2(tool_data.target_handle_position(reference_handle, &vector).unwrap())
|
||||
});
|
||||
tool_data.handle_start_offset = handle_start.map(|start| start - input.mouse.position);
|
||||
tool_data.space_pressed = true;
|
||||
@@ -2075,8 +2064,8 @@ impl Fsm for PenToolFsmState {
|
||||
}
|
||||
(PenToolFsmState::DraggingHandle(..), PenToolMessage::Confirm) => {
|
||||
// Confirm to end path
|
||||
if let Some((vector_data, layer)) = layer.and_then(|layer| document.network_interface.compute_modified_vector(layer)).zip(layer) {
|
||||
let single_point_in_layer = vector_data.point_domain.ids().len() == 1;
|
||||
if let Some((vector, layer)) = layer.and_then(|layer| document.network_interface.compute_modified_vector(layer)).zip(layer) {
|
||||
let single_point_in_layer = vector.point_domain.ids().len() == 1;
|
||||
tool_data.finish_placing_handle(SnapData::new(document, input), transform, preferences, responses);
|
||||
let latest_points = tool_data.latest_points.len() == 1;
|
||||
|
||||
@@ -2129,8 +2118,8 @@ impl Fsm for PenToolFsmState {
|
||||
}
|
||||
}
|
||||
(PenToolFsmState::PlacingAnchor, PenToolMessage::Abort) => {
|
||||
let should_delete_layer = if let Some(vector_data) = layer.and_then(|layer| document.network_interface.compute_modified_vector(layer)) {
|
||||
vector_data.point_domain.ids().len() == 1
|
||||
let should_delete_layer = if let Some(vector) = layer.and_then(|layer| document.network_interface.compute_modified_vector(layer)) {
|
||||
vector.point_domain.ids().len() == 1
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
@@ -548,15 +548,15 @@ mod test_spline_tool {
|
||||
use crate::test_utils::test_prelude::*;
|
||||
use glam::DAffine2;
|
||||
use graphene_std::vector::PointId;
|
||||
use graphene_std::vector::VectorData;
|
||||
use graphene_std::vector::Vector;
|
||||
|
||||
fn assert_point_positions(vector_data: &VectorData, layer_to_viewport: DAffine2, expected_points: &[DVec2], epsilon: f64) {
|
||||
let points_in_viewport: Vec<DVec2> = vector_data
|
||||
fn assert_point_positions(vector: &Vector, layer_to_viewport: DAffine2, expected_points: &[DVec2], epsilon: f64) {
|
||||
let points_in_viewport: Vec<DVec2> = vector
|
||||
.point_domain
|
||||
.ids()
|
||||
.iter()
|
||||
.filter_map(|&point_id| {
|
||||
let position = vector_data.point_domain.position_from_id(point_id)?;
|
||||
let position = vector.point_domain.position_from_id(point_id)?;
|
||||
Some(layer_to_viewport.transform_point2(position))
|
||||
})
|
||||
.collect();
|
||||
@@ -601,19 +601,19 @@ mod test_spline_tool {
|
||||
|
||||
let first_spline_node = find_spline(document, spline_layer).expect("Spline node not found in the layer");
|
||||
|
||||
let first_vector_data = document.network_interface.compute_modified_vector(spline_layer).expect("Vector data not found for the spline layer");
|
||||
let first_vector = document.network_interface.compute_modified_vector(spline_layer).expect("Vector not found for the spline layer");
|
||||
|
||||
// Verify initial spline has correct number of points and segments
|
||||
let initial_point_count = first_vector_data.point_domain.ids().len();
|
||||
let initial_segment_count = first_vector_data.segment_domain.ids().len();
|
||||
let initial_point_count = first_vector.point_domain.ids().len();
|
||||
let initial_segment_count = first_vector.segment_domain.ids().len();
|
||||
assert_eq!(initial_point_count, 3, "Expected 3 points in initial spline, found {}", initial_point_count);
|
||||
assert_eq!(initial_segment_count, 2, "Expected 2 segments in initial spline, found {}", initial_segment_count);
|
||||
|
||||
let layer_to_viewport = document.metadata().transform_to_viewport(spline_layer);
|
||||
|
||||
let endpoints: Vec<(PointId, DVec2)> = first_vector_data
|
||||
let endpoints: Vec<(PointId, DVec2)> = first_vector
|
||||
.extendable_points(false)
|
||||
.filter_map(|point_id| first_vector_data.point_domain.position_from_id(point_id).map(|pos| (point_id, layer_to_viewport.transform_point2(pos))))
|
||||
.filter_map(|point_id| first_vector.point_domain.position_from_id(point_id).map(|pos| (point_id, layer_to_viewport.transform_point2(pos))))
|
||||
.collect();
|
||||
|
||||
assert_eq!(endpoints.len(), 2, "Expected 2 endpoints in the initial spline");
|
||||
@@ -632,14 +632,14 @@ mod test_spline_tool {
|
||||
editor.press(Key::Enter, ModifierKeys::empty()).await;
|
||||
|
||||
let document = editor.active_document();
|
||||
let extended_vector_data = document
|
||||
let extended_vector = document
|
||||
.network_interface
|
||||
.compute_modified_vector(spline_layer)
|
||||
.expect("Vector data not found for the extended spline layer");
|
||||
.expect("Vector not found for the extended spline layer");
|
||||
|
||||
// Verify extended spline has correct number of points and segments
|
||||
let extended_point_count = extended_vector_data.point_domain.ids().len();
|
||||
let extended_segment_count = extended_vector_data.segment_domain.ids().len();
|
||||
let extended_point_count = extended_vector.point_domain.ids().len();
|
||||
let extended_segment_count = extended_vector.segment_domain.ids().len();
|
||||
|
||||
assert_eq!(extended_point_count, 5, "Expected 5 points in extended spline, found {}", extended_point_count);
|
||||
assert_eq!(extended_segment_count, 4, "Expected 4 segments in extended spline, found {}", extended_segment_count);
|
||||
@@ -653,7 +653,7 @@ mod test_spline_tool {
|
||||
|
||||
let all_expected_points = [initial_points[0], initial_points[1], initial_points[2], continuation_points[0], continuation_points[1]];
|
||||
|
||||
assert_point_positions(&extended_vector_data, layer_to_viewport, &all_expected_points, 1e-10);
|
||||
assert_point_positions(&extended_vector, layer_to_viewport, &all_expected_points, 1e-10);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -688,14 +688,14 @@ mod test_spline_tool {
|
||||
.selected_visible_and_unlocked_layers(network_interface)
|
||||
.next()
|
||||
.expect("Should have a selected layer");
|
||||
let vector_data = network_interface.compute_modified_vector(layer).expect("Should have vector data");
|
||||
let vector = network_interface.compute_modified_vector(layer).expect("Should have vector data");
|
||||
let layer_to_viewport = document.metadata().transform_to_viewport(layer);
|
||||
|
||||
// Expected points in viewport coordinates
|
||||
let expected_points = vec![DVec2::new(50., 50.), DVec2::new(100., 50.), DVec2::new(150., 100.)];
|
||||
|
||||
// Assert all points are correctly positioned
|
||||
assert_point_positions(&vector_data, layer_to_viewport, &expected_points, 1e-10);
|
||||
assert_point_positions(&vector, layer_to_viewport, &expected_points, 1e-10);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -728,14 +728,14 @@ mod test_spline_tool {
|
||||
.selected_visible_and_unlocked_layers(network_interface)
|
||||
.next()
|
||||
.expect("Should have a selected layer");
|
||||
let vector_data = network_interface.compute_modified_vector(layer).expect("Should have vector data");
|
||||
let vector = network_interface.compute_modified_vector(layer).expect("Should have vector data");
|
||||
let layer_to_viewport = document.metadata().transform_to_viewport(layer);
|
||||
|
||||
// Expected points in viewport coordinates
|
||||
let expected_points = vec![DVec2::new(50., 50.), DVec2::new(100., 50.), DVec2::new(150., 100.)];
|
||||
|
||||
// Assert all points are correctly positioned
|
||||
assert_point_positions(&vector_data, layer_to_viewport, &expected_points, 1e-10);
|
||||
assert_point_positions(&vector, layer_to_viewport, &expected_points, 1e-10);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -766,14 +766,14 @@ mod test_spline_tool {
|
||||
.selected_visible_and_unlocked_layers(network_interface)
|
||||
.next()
|
||||
.expect("Should have a selected layer");
|
||||
let vector_data = network_interface.compute_modified_vector(layer).expect("Should have vector data");
|
||||
let vector = network_interface.compute_modified_vector(layer).expect("Should have vector data");
|
||||
let layer_to_viewport = document.metadata().transform_to_viewport(layer);
|
||||
|
||||
// Expected points in viewport coordinates
|
||||
let expected_points = vec![DVec2::new(50., 50.), DVec2::new(100., 50.), DVec2::new(150., 100.)];
|
||||
|
||||
// Assert all points are correctly positioned
|
||||
assert_point_positions(&vector_data, layer_to_viewport, &expected_points, 1e-10);
|
||||
assert_point_positions(&vector, layer_to_viewport, &expected_points, 1e-10);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -805,14 +805,14 @@ mod test_spline_tool {
|
||||
.selected_visible_and_unlocked_layers(network_interface)
|
||||
.next()
|
||||
.expect("Should have a selected layer");
|
||||
let vector_data = network_interface.compute_modified_vector(layer).expect("Should have vector data");
|
||||
let vector = network_interface.compute_modified_vector(layer).expect("Should have vector data");
|
||||
let layer_to_viewport = document.metadata().transform_to_viewport(layer);
|
||||
|
||||
// Expected points in viewport coordinates
|
||||
let expected_points = vec![DVec2::new(50., 50.), DVec2::new(100., 50.), DVec2::new(150., 100.)];
|
||||
|
||||
// Assert all points are correctly positioned
|
||||
assert_point_positions(&vector_data, layer_to_viewport, &expected_points, 1e-10);
|
||||
assert_point_positions(&vector, layer_to_viewport, &expected_points, 1e-10);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -845,17 +845,17 @@ mod test_spline_tool {
|
||||
let spline_layer = layers.next().expect("Failed to find the spline layer");
|
||||
assert!(find_spline(document, spline_layer).is_some(), "Spline node not found in the layer");
|
||||
|
||||
let vector_data = document.network_interface.compute_modified_vector(spline_layer).expect("Vector data not found for the spline layer");
|
||||
let vector = document.network_interface.compute_modified_vector(spline_layer).expect("Vector not found for the spline layer");
|
||||
|
||||
// Verify we have the correct number of points and segments
|
||||
let point_count = vector_data.point_domain.ids().len();
|
||||
let segment_count = vector_data.segment_domain.ids().len();
|
||||
let point_count = vector.point_domain.ids().len();
|
||||
let segment_count = vector.segment_domain.ids().len();
|
||||
|
||||
assert_eq!(point_count, 3, "Expected 3 points in the spline, found {}", point_count);
|
||||
assert_eq!(segment_count, 2, "Expected 2 segments in the spline, found {}", segment_count);
|
||||
|
||||
let layer_to_viewport = document.metadata().transform_to_viewport(spline_layer);
|
||||
|
||||
assert_point_positions(&vector_data, layer_to_viewport, &spline_points, 1e-10);
|
||||
assert_point_positions(&vector, layer_to_viewport, &spline_points, 1e-10);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,9 +11,9 @@ use crate::messages::tool::tool_messages::tool_prelude::Key;
|
||||
use crate::messages::tool::utility_types::{ToolData, ToolType};
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graphene_std::renderer::Quad;
|
||||
use graphene_std::vector::ManipulatorPointId;
|
||||
use graphene_std::vector::click_target::ClickTargetType;
|
||||
use graphene_std::vector::{VectorData, VectorModificationType};
|
||||
use graphene_std::vector::misc::ManipulatorPointId;
|
||||
use graphene_std::vector::{Vector, VectorModificationType};
|
||||
use std::f64::consts::{PI, TAU};
|
||||
|
||||
const TRANSFORM_GRS_OVERLAY_PROVIDER: OverlayProvider = |context| TransformLayerMessage::Overlays(context).into();
|
||||
@@ -123,14 +123,14 @@ impl MessageHandler<TransformLayerMessage, TransformLayerMessageContext<'_>> for
|
||||
self.grab_target = self.local_pivot;
|
||||
}
|
||||
// Here vector data from all layers is not considered which can be a problem in pivot calculation
|
||||
else if let Some(vector_data) = selected_layers.first().and_then(|&layer| document.network_interface.compute_modified_vector(layer)) {
|
||||
else if let Some(vector) = selected_layers.first().and_then(|&layer| document.network_interface.compute_modified_vector(layer)) {
|
||||
*selected.original_transforms = OriginalTransforms::default();
|
||||
|
||||
let viewspace = document.metadata().transform_to_viewport(selected_layers[0]);
|
||||
let selected_segments = shape_editor.selected_segments().collect::<HashSet<_>>();
|
||||
let mut affected_points = shape_editor.selected_points().copied().collect::<Vec<_>>();
|
||||
|
||||
for (segment_id, _, start, end) in vector_data.segment_bezier_iter() {
|
||||
for (segment_id, _, start, end) in vector.segment_bezier_iter() {
|
||||
if selected_segments.contains(&segment_id) {
|
||||
affected_points.push(ManipulatorPointId::Anchor(start));
|
||||
affected_points.push(ManipulatorPointId::Anchor(end));
|
||||
@@ -139,11 +139,11 @@ impl MessageHandler<TransformLayerMessage, TransformLayerMessageContext<'_>> for
|
||||
|
||||
let affected_point_refs = affected_points.iter().collect();
|
||||
|
||||
let get_location = |point: &&ManipulatorPointId| point.get_position(&vector_data).map(|position| viewspace.transform_point2(position));
|
||||
let get_location = |point: &&ManipulatorPointId| point.get_position(&vector).map(|position| viewspace.transform_point2(position));
|
||||
if let (Some((new_pivot, grab_target)), bounds) = calculate_pivot(
|
||||
document,
|
||||
&affected_point_refs,
|
||||
&vector_data,
|
||||
&vector,
|
||||
viewspace,
|
||||
|point: &ManipulatorPointId| get_location(&point),
|
||||
&mut self.pivot_gizmo,
|
||||
@@ -362,12 +362,12 @@ impl MessageHandler<TransformLayerMessage, TransformLayerMessageContext<'_>> for
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(vector_data) = selected_layers.first().and_then(|&layer| document.network_interface.compute_modified_vector(layer)) {
|
||||
if let Some(vector) = selected_layers.first().and_then(|&layer| document.network_interface.compute_modified_vector(layer)) {
|
||||
if let [point] = selected_points.as_slice() {
|
||||
if matches!(point, ManipulatorPointId::Anchor(_)) {
|
||||
if let Some([handle1, handle2]) = point.get_handle_pair(&vector_data) {
|
||||
let handle1_length = handle1.length(&vector_data);
|
||||
let handle2_length = handle2.length(&vector_data);
|
||||
if let Some([handle1, handle2]) = point.get_handle_pair(&vector) {
|
||||
let handle1_length = handle1.length(&vector);
|
||||
let handle2_length = handle2.length(&vector);
|
||||
|
||||
if (handle1_length == 0. && handle2_length == 0. && !using_select_tool) || (handle1_length == f64::MAX && handle2_length == f64::MAX && !using_select_tool) {
|
||||
// G should work for this point but not R and S
|
||||
@@ -378,7 +378,7 @@ impl MessageHandler<TransformLayerMessage, TransformLayerMessageContext<'_>> for
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let handle_length = point.as_handle().map(|handle| handle.length(&vector_data));
|
||||
let handle_length = point.as_handle().map(|handle| handle.length(&vector));
|
||||
|
||||
if handle_length == Some(0.) {
|
||||
selected.original_transforms.clear();
|
||||
@@ -693,7 +693,7 @@ impl TransformLayerMessageHandler {
|
||||
fn calculate_pivot(
|
||||
document: &DocumentMessageHandler,
|
||||
selected_points: &Vec<&ManipulatorPointId>,
|
||||
vector_data: &VectorData,
|
||||
vector: &Vector,
|
||||
viewspace: DAffine2,
|
||||
get_location: impl Fn(&ManipulatorPointId) -> Option<DVec2>,
|
||||
gizmo: &mut PivotGizmo,
|
||||
@@ -736,8 +736,8 @@ fn calculate_pivot(
|
||||
ManipulatorPointId::PrimaryHandle(_) | ManipulatorPointId::EndHandle(_) => {
|
||||
// Get the anchor position and transform it to the pivot
|
||||
let (Some(pivot_position), Some(position)) = (
|
||||
point.get_anchor_position(vector_data).map(|anchor_position| viewspace.transform_point2(anchor_position)),
|
||||
point.get_position(vector_data),
|
||||
point.get_anchor_position(vector).map(|anchor_position| viewspace.transform_point2(anchor_position)),
|
||||
point.get_position(vector),
|
||||
) else {
|
||||
return (None, None);
|
||||
};
|
||||
@@ -774,15 +774,15 @@ fn project_edge_to_quad(edge: DVec2, quad: &Quad, local: bool, axis_constraint:
|
||||
|
||||
fn update_colinear_handles(selected_layers: &[LayerNodeIdentifier], document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
for &layer in selected_layers {
|
||||
let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { continue };
|
||||
let Some(vector) = document.network_interface.compute_modified_vector(layer) else { continue };
|
||||
|
||||
for [handle1, handle2] in &vector_data.colinear_manipulators {
|
||||
for [handle1, handle2] in &vector.colinear_manipulators {
|
||||
let manipulator1 = handle1.to_manipulator_point();
|
||||
let manipulator2 = handle2.to_manipulator_point();
|
||||
|
||||
let Some(anchor) = manipulator1.get_anchor_position(&vector_data) else { continue };
|
||||
let Some(pos1) = manipulator1.get_position(&vector_data).map(|pos| pos - anchor) else { continue };
|
||||
let Some(pos2) = manipulator2.get_position(&vector_data).map(|pos| pos - anchor) else { continue };
|
||||
let Some(anchor) = manipulator1.get_anchor_position(&vector) else { continue };
|
||||
let Some(pos1) = manipulator1.get_position(&vector).map(|pos| pos - anchor) else { continue };
|
||||
let Some(pos2) = manipulator2.get_position(&vector).map(|pos| pos - anchor) else { continue };
|
||||
|
||||
let angle = pos1.angle_to(pos2);
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ use graphene_std::renderer::{Render, RenderParams, SvgRender};
|
||||
use graphene_std::renderer::{RenderMetadata, format_transform_matrix};
|
||||
use graphene_std::text::FontCache;
|
||||
use graphene_std::transform::Footprint;
|
||||
use graphene_std::vector::VectorData;
|
||||
use graphene_std::vector::Vector;
|
||||
use graphene_std::vector::style::ViewMode;
|
||||
use interpreted_executor::dynamic_executor::ResolvedDocumentNodeTypesDelta;
|
||||
|
||||
@@ -34,7 +34,7 @@ pub struct ExecutionResponse {
|
||||
result: Result<TaggedValue, String>,
|
||||
responses: VecDeque<FrontendMessage>,
|
||||
transform: DAffine2,
|
||||
vector_modify: HashMap<NodeId, VectorData>,
|
||||
vector_modify: HashMap<NodeId, Vector>,
|
||||
/// The resulting value from the temporary inspected during execution
|
||||
inspect_result: Option<InspectResult>,
|
||||
}
|
||||
@@ -377,9 +377,9 @@ impl NodeGraphExecutor {
|
||||
TaggedValue::F64(render_object) => Self::debug_render(render_object, transform, responses),
|
||||
TaggedValue::DVec2(render_object) => Self::debug_render(render_object, transform, responses),
|
||||
TaggedValue::OptionalColor(render_object) => Self::debug_render(render_object, transform, responses),
|
||||
TaggedValue::VectorData(render_object) => Self::debug_render(render_object, transform, responses),
|
||||
TaggedValue::GraphicGroup(render_object) => Self::debug_render(render_object, transform, responses),
|
||||
TaggedValue::RasterData(render_object) => Self::debug_render(render_object, transform, responses),
|
||||
TaggedValue::Vector(render_object) => Self::debug_render(render_object, transform, responses),
|
||||
TaggedValue::Group(render_object) => Self::debug_render(render_object, transform, responses),
|
||||
TaggedValue::Raster(render_object) => Self::debug_render(render_object, transform, responses),
|
||||
TaggedValue::Palette(render_object) => Self::debug_render(render_object, transform, responses),
|
||||
_ => {
|
||||
return Err(format!("Invalid node graph output type: {node_graph_output:#?}"));
|
||||
|
||||
@@ -14,7 +14,7 @@ use graphene_std::renderer::{Render, RenderParams, SvgRender};
|
||||
use graphene_std::renderer::{RenderSvgSegmentList, SvgSegment};
|
||||
use graphene_std::table::{Table, TableRow};
|
||||
use graphene_std::text::FontCache;
|
||||
use graphene_std::vector::VectorData;
|
||||
use graphene_std::vector::Vector;
|
||||
use graphene_std::vector::style::ViewMode;
|
||||
use graphene_std::wasm_application_io::{RenderOutputType, WasmApplicationIo, WasmEditorApi};
|
||||
use interpreted_executor::dynamic_executor::{DynamicExecutor, IntrospectError, ResolvedDocumentNodeTypesDelta};
|
||||
@@ -51,7 +51,7 @@ pub struct NodeRuntime {
|
||||
// TODO: Remove, it doesn't need to be persisted anymore
|
||||
/// The current renders of the thumbnails for layer nodes.
|
||||
thumbnail_renders: HashMap<NodeId, Vec<SvgSegment>>,
|
||||
vector_modify: HashMap<NodeId, VectorData>,
|
||||
vector_modify: HashMap<NodeId, Vector>,
|
||||
}
|
||||
|
||||
/// Messages passed from the editor thread to the node runtime thread.
|
||||
@@ -309,11 +309,11 @@ impl NodeRuntime {
|
||||
};
|
||||
|
||||
if let Some(io) = introspected_data.downcast_ref::<IORecord<Context, graphene_std::Graphic>>() {
|
||||
Self::process_graphic_element(&mut self.thumbnail_renders, parent_network_node_id, &io.output, responses, update_thumbnails)
|
||||
Self::process_graphic(&mut self.thumbnail_renders, parent_network_node_id, &io.output, responses, update_thumbnails)
|
||||
} else if let Some(io) = introspected_data.downcast_ref::<IORecord<Context, graphene_std::Artboard>>() {
|
||||
Self::process_graphic_element(&mut self.thumbnail_renders, parent_network_node_id, &io.output, responses, update_thumbnails)
|
||||
Self::process_graphic(&mut self.thumbnail_renders, parent_network_node_id, &io.output, responses, update_thumbnails)
|
||||
// Insert the vector modify if we are dealing with vector data
|
||||
} else if let Some(record) = introspected_data.downcast_ref::<IORecord<Context, Table<VectorData>>>() {
|
||||
} else if let Some(record) = introspected_data.downcast_ref::<IORecord<Context, Table<Vector>>>() {
|
||||
let default = TableRow::default();
|
||||
self.vector_modify
|
||||
.insert(parent_network_node_id, record.output.iter_ref().next().unwrap_or_else(|| default.as_ref()).element.clone());
|
||||
@@ -323,12 +323,11 @@ impl NodeRuntime {
|
||||
}
|
||||
}
|
||||
|
||||
// If this is `Graphic` data:
|
||||
// Regenerate click targets and thumbnails for the layers in the graph, modifying the state and updating the UI.
|
||||
fn process_graphic_element(
|
||||
// If this is `Graphic` data, regenerate click targets and thumbnails for the layers in the graph, modifying the state and updating the UI.
|
||||
fn process_graphic(
|
||||
thumbnail_renders: &mut HashMap<NodeId, Vec<SvgSegment>>,
|
||||
parent_network_node_id: NodeId,
|
||||
graphic_element: &impl Render,
|
||||
graphic: &impl Render,
|
||||
responses: &mut VecDeque<FrontendMessage>,
|
||||
update_thumbnails: bool,
|
||||
) {
|
||||
@@ -339,7 +338,7 @@ impl NodeRuntime {
|
||||
}
|
||||
|
||||
// Skip thumbnails if the layer is too complex (for performance)
|
||||
if graphic_element.render_complexity() > 1000 {
|
||||
if graphic.render_complexity() > 1000 {
|
||||
let old = thumbnail_renders.insert(parent_network_node_id, Vec::new());
|
||||
if old.is_none_or(|v| !v.is_empty()) {
|
||||
responses.push_back(FrontendMessage::UpdateNodeThumbnail {
|
||||
@@ -350,7 +349,7 @@ impl NodeRuntime {
|
||||
return;
|
||||
}
|
||||
|
||||
let bounds = graphic_element.bounding_box(DAffine2::IDENTITY, true);
|
||||
let bounds = graphic.bounding_box(DAffine2::IDENTITY, true);
|
||||
|
||||
// Render the thumbnail from a `Graphic` into an SVG string
|
||||
let render_params = RenderParams {
|
||||
@@ -363,7 +362,7 @@ impl NodeRuntime {
|
||||
alignment_parent_transform: None,
|
||||
};
|
||||
let mut render = SvgRender::new();
|
||||
graphic_element.render_svg(&mut render, &render_params);
|
||||
graphic.render_svg(&mut render, &render_params);
|
||||
|
||||
// And give the SVG a viewbox and outer <svg>...</svg> wrapper tag
|
||||
let [min, max] = bounds.unwrap_or_default();
|
||||
|
||||
Reference in New Issue
Block a user