Skip to content

Comments

Pen/Freehand/Splines tool set its origin to the first drawn point#3795

Draft
jsjgdh wants to merge 1 commit intoGraphiteEditor:masterfrom
jsjgdh:offset
Draft

Pen/Freehand/Splines tool set its origin to the first drawn point#3795
jsjgdh wants to merge 1 commit intoGraphiteEditor:masterfrom
jsjgdh:offset

Conversation

@jsjgdh
Copy link
Contributor

@jsjgdh jsjgdh commented Feb 21, 2026

closes #2776

@gemini-code-assist
Copy link

Summary of Changes

Hello @jsjgdh, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request resolves an issue where vector drawing tools were not correctly establishing the origin for newly created layers. By modifying the layer creation process to explicitly include and configure a Transform node with an Origin Offset corresponding to the initial drawing point, the PR ensures that all vector shapes behave as expected from their point of creation.

Highlights

  • Vector Tool Origin Fix: The Pen, Freehand, Splines, and Shape tools now correctly set the origin of newly created vector layers to the first drawn point or the drag start position.
  • Transform Node Initialization: The insert_vector function and the new_custom layer creation utility have been updated to ensure a Transform node is properly initialized with an Origin Offset based on the initial drawing point.
  • Graph Node Structure: The node graph for new vector layers now explicitly includes a Transform node, which is configured with the appropriate origin offset.
Changelog
  • editor/src/messages/portfolio/document/graph_operation/utility_types.rs
    • Captured the first anchor point of a vector path when inserting it.
    • Initialized the Origin Offset of the Transform node using the first anchor point during vector insertion.
  • editor/src/messages/tool/common_functionality/graph_modification_utils.rs
    • Modified the new_custom function to explicitly insert a Transform node into the custom layer's node graph.
  • editor/src/messages/tool/tool_messages/freehand_tool.rs
    • Imported NodeInput for graph manipulation.
    • Updated the Freehand tool to create new paths with a Transform node, setting its Origin Offset to the mouse's initial document space position.
  • editor/src/messages/tool/tool_messages/pen_tool.rs
    • Imported TaggedValue and NodeInput for graph manipulation.
    • Modified the Pen tool to create new paths with a Transform node, setting its Origin Offset to the initial snapped point.
  • editor/src/messages/tool/tool_messages/shape_tool.rs
    • Imported TaggedValue and NodeInput for graph manipulation.
    • Updated the Shape tool to create new shapes with a Transform node, setting its Origin Offset to the drag start position.
  • editor/src/messages/tool/tool_messages/spline_tool.rs
    • Imported TaggedValue for graph manipulation.
    • Modified the Spline tool to initialize new splines with a Transform node, setting its Origin Offset to the initial snapped point.
Activity
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

The pull request addresses issue #2776 by modifying the origin of Pen/Freehand/Splines tools to the first drawn point. This involves adding a first_anchor variable to capture the initial point and then using it to set the ORIGIN_OFFSET_INDEX of the Transform node. The changes are consistent across utility_types.rs, graph_modification_utils.rs, freehand_tool.rs, pen_tool.rs, shape_tool.rs, and spline_tool.rs to ensure the new behavior is applied to all relevant tools. The modifications appear to correctly implement the desired functionality.

}

pub fn insert_vector(&mut self, subpaths: Vec<Subpath<PointId>>, layer: LayerNodeIdentifier, include_transform: bool, include_fill: bool, include_stroke: bool) {
let first_anchor = subpaths.first().and_then(|subpath| subpath.manipulator_groups().first().map(|group| group.anchor));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This line correctly captures the first anchor point from the subpaths, which is then used to set the origin offset for the transform node. This is a good approach to ensure the tool's origin is anchored to the initial drawing point.

Comment on lines +168 to +173
let mut transform = resolve_network_node_type("Transform").expect("Transform node does not exist").default_node_template();
if let Some(anchor) = first_anchor {
const ORIGIN_OFFSET_INDEX: usize = 5;
if let Some(origin_offset) = transform.document_node.inputs.get_mut(ORIGIN_OFFSET_INDEX) {
*origin_offset = NodeInput::value(TaggedValue::DVec2(anchor), false);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The logic here correctly applies the first_anchor to the ORIGIN_OFFSET_INDEX of the Transform node. This ensures that the vector layer's transform is correctly initialized with the starting point of the drawn path.

Comment on lines +246 to +253
let transform_node_id = NodeId::new();
let mut nodes = nodes;

// Insert a Transform node
let transform_node = crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_network_node_type("Transform")
.expect("Transform node does not exist")
.default_node_template();
nodes.push((transform_node_id, transform_node));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This new section introduces a Transform node into the custom layer creation. While this is necessary for the new origin functionality, it might be beneficial to pass the transform_node_id and transform_node as arguments to new_custom if they are always going to be the same, to avoid redundant code in the calling sites. However, given the context of setting the origin, this approach is acceptable for now.

use crate::messages::tool::common_functionality::utility_functions::should_extend;
use glam::DVec2;
use graph_craft::document::NodeId;
use graph_craft::document::{NodeId, NodeInput};

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Adding NodeInput to the use statement is necessary for the new Transform node logic. This is a correct and required change.

Comment on lines +291 to +298
let mut transform_node = resolve_network_node_type("Transform").expect("Transform node does not exist").default_node_template();
if let Some(input) = transform_node.document_node.inputs.get_mut(0) {
*input = NodeInput::node(NodeId(1), 0);
}
const ORIGIN_OFFSET_INDEX: usize = 5;
if let Some(origin_offset) = transform_node.document_node.inputs.get_mut(ORIGIN_OFFSET_INDEX) {
*origin_offset = NodeInput::value(graph_craft::document::value::TaggedValue::DVec2(document_space_position), false);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This block correctly initializes a Transform node and sets its ORIGIN_OFFSET_INDEX to the document_space_position. This ensures that the freehand tool's origin is set to the first drawn point, aligning with the PR's objective.

Comment on lines +940 to +949
let mut transform_node = crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_network_node_type("Transform")
.expect("Transform node does not exist")
.default_node_template();
if let Some(input) = transform_node.document_node.inputs.get_mut(0) {
*input = NodeInput::node(NodeId(1), 0);
}
const ORIGIN_OFFSET_INDEX: usize = 5;
if let Some(origin_offset) = transform_node.document_node.inputs.get_mut(ORIGIN_OFFSET_INDEX) {
*origin_offset = NodeInput::value(TaggedValue::DVec2(tool_data.data.drag_start), false);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This block correctly initializes a Transform node and sets its ORIGIN_OFFSET_INDEX to the tool_data.data.drag_start. This ensures that the shape tool's origin is set to the first drawn point, aligning with the PR's objective.

if let Some(origin_offset) = transform_node.document_node.inputs.get_mut(ORIGIN_OFFSET_INDEX) {
*origin_offset = NodeInput::value(TaggedValue::DVec2(tool_data.data.drag_start), false);
}
let nodes = vec![(NodeId(0), transform_node), (NodeId(1), node)];

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The nodes vector is updated to include both the Transform node and the shape node, with NodeId(0) assigned to the Transform node and NodeId(1) to the shape node. This order is crucial for the graph's data flow, as the shape node's input is set to NodeId(1) (the Transform node) in the previous lines.

use crate::messages::tool::common_functionality::graph_modification_utils::{self, find_spline, merge_layers, merge_points};
use crate::messages::tool::common_functionality::snapping::{SnapCandidatePoint, SnapData, SnapManager, SnapTypeConfiguration, SnappedPoint};
use crate::messages::tool::common_functionality::utility_functions::{closest_point, should_extend};
use graph_craft::document::value::TaggedValue;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Adding TaggedValue to the use statement is necessary for the new Transform node logic. This is a correct and required change.

Comment on lines +397 to +404
let mut transform_node = resolve_network_node_type("Transform").expect("Transform node does not exist").default_node_template();
if let Some(input) = transform_node.document_node.inputs.get_mut(0) {
*input = NodeInput::node(NodeId(1), 0);
}
const ORIGIN_OFFSET_INDEX: usize = 5;
if let Some(origin_offset) = transform_node.document_node.inputs.get_mut(ORIGIN_OFFSET_INDEX) {
*origin_offset = NodeInput::value(TaggedValue::DVec2(snapped.snapped_point_document), false);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This block correctly initializes a Transform node and sets its ORIGIN_OFFSET_INDEX to the snapped.snapped_point_document. This ensures that the spline tool's origin is set to the first drawn point, aligning with the PR's objective.

*origin_offset = NodeInput::value(TaggedValue::DVec2(snapped.snapped_point_document), false);
}

let nodes = vec![(NodeId(2), path_node), (NodeId(1), spline_node), (NodeId(0), transform_node)];

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The nodes vector is updated to include the Path node, Spline node, and Transform node, with NodeId(0) assigned to the Transform node, NodeId(1) to the Spline node, and NodeId(2) to the Path node. This order is crucial for the graph's data flow, as the Spline node's input is set to NodeId(2) (the Path node) and the Transform node's input is set to NodeId(1) (the Spline node) in the previous lines.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Pen/Freehand/Splines tool should set its origin to the first drawn point location when the new layer is created

1 participant