Repository: GraphiteEditor/Graphite
File: editor/src/messages/tool/common_functionality/shapes/arrow_shape.rs (Rust)

Code before:

		let vector = document.network_interface.compute_modified_vector(layer);
		let existing_point_ids: Vec<PointId> = vector.as_ref().map(|v| v.point_domain.ids().to_vec()).unwrap_or_default();
		let existing_segment_ids: Vec<SegmentId> = vector.as_ref().map(|v| v.segment_domain.ids().to_vec()).unwrap_or_default();

		for point_id in existing_point_ids {
			responses.add(GraphOperationMessage::Vector {
				layer,
				modification_type: VectorModificationType::RemovePoint { id: point_id },
			});
		}

		for segment_id in existing_segment_ids {
			responses.add(GraphOperationMessage::Vector {
				layer,
				modification_type: VectorModificationType::RemoveSegment { id: segment_id },
			});
		}

		let point_ids: Vec<PointId> = viewport_anchors
			.iter()
			.map(|&pos| {
				let id = PointId::generate();
				responses.add(GraphOperationMessage::Vector {
					layer,
					modification_type: VectorModificationType::InsertPoint { id, position: pos },
				});
				id
			})
			.collect();

		for i in 0..point_ids.len() {
			let id = SegmentId::generate();
			let points = [point_ids[i], point_ids[(i + 1) % point_ids.len()]];
			responses.add(GraphOperationMessage::Vector {
				layer,
				modification_type: VectorModificationType::InsertSegment { id, points, handles: [None, None] },
			});
		}

		responses.add(NodeGraphMessage::RunDocumentGraph);
	}

	pub fn overlays(_document: &DocumentMessageHandler, _tool_data: &ShapeToolData, _overlay_context: &mut OverlayContext) {}
}


Review comment (bug):
Note that this inserts the point in layer space. You said above that you `Build arrow in viewport space`.

To convert between the viewport and the layer space, you can do something like:
```rs
document.metadata().transform_to_viewport(layer).inverse().transform_point2(pos)
```

Alternatively you can set the transform on the layer itself:
```rs
responses.add(GraphOperationMessage::TransformSet {
	layer,
	transform: DAffine2::IDENTITY,
	transform_in: TransformIn::Viewport,
	skip_rerender: false,
});
```

Note that the line tool is broken and produces offset lines when inside a transformed parent layer. I would recommend that you avoid implementing this bug into you new tool.

Code after:

		// Calculate proportional dimensions based on arrow length
		let shaft_width = length_document * 0.1;
		let head_width = length_document * 0.3;
		let head_length = length_document * 0.2;

		// Update Arrow node parameters with document space coordinates (like Line tool)
		responses.add(NodeGraphMessage::SetInput {
			input_connector: InputConnector::node(node_id, 1),
			input: NodeInput::value(TaggedValue::DVec2(start_document), false),
		});
		responses.add(NodeGraphMessage::SetInput {
			input_connector: InputConnector::node(node_id, 2),
			input: NodeInput::value(TaggedValue::DVec2(end_document), false),
		});
		responses.add(NodeGraphMessage::SetInput {
			input_connector: InputConnector::node(node_id, 3),
			input: NodeInput::value(TaggedValue::F64(shaft_width), false),
		});
		responses.add(NodeGraphMessage::SetInput {
			input_connector: InputConnector::node(node_id, 4),
			input: NodeInput::value(TaggedValue::F64(head_width), false),
		});
		responses.add(NodeGraphMessage::SetInput {
			input_connector: InputConnector::node(node_id, 5),
			input: NodeInput::value(TaggedValue::F64(head_length), false),
		});

		responses.add(NodeGraphMessage::RunDocumentGraph);
	}

	pub fn overlays(_document: &DocumentMessageHandler, _tool_data: &ShapeToolData, _overlay_context: &mut OverlayContext) {}
}