Fix Path tool's Path node transform calculation by skipping local transform based on first instance source ID (#2843)

* First instance source id

* Set source node id and migrations
This commit is contained in:
James Lindsay
2025-07-07 23:09:21 +01:00
committed by GitHub
parent 88c059a607
commit 4a83067081
15 changed files with 126 additions and 58 deletions

View File

@@ -356,7 +356,7 @@ pub struct ContextImpl<'a> {
}
impl<'a> ContextImpl<'a> {
pub fn with_footprint<'f>(&self, new_footprint: &'f Footprint, varargs: Option<&'f impl (Borrow<[DynRef<'f>]>)>) -> ContextImpl<'f>
pub fn with_footprint<'f>(&self, new_footprint: &'f Footprint, varargs: Option<&'f impl Borrow<[DynRef<'f>]>>) -> ContextImpl<'f>
where
'a: 'f,
{

View File

@@ -1,7 +1,7 @@
use super::*;
use crate::Ctx;
use crate::instances::Instance;
use crate::uuid::generate_uuid;
use crate::uuid::{NodeId, generate_uuid};
use bezier_rs::BezierHandles;
use dyn_any::DynAny;
use kurbo::{BezPath, PathEl, Point};
@@ -420,12 +420,17 @@ impl Hash for VectorModification {
/// A node that applies a procedural modification to some [`VectorData`].
#[node_macro::node(category(""))]
async fn path_modify(_ctx: impl Ctx, mut vector_data: VectorDataTable, modification: Box<VectorModification>) -> VectorDataTable {
async fn path_modify(_ctx: impl Ctx, mut vector_data: VectorDataTable, modification: Box<VectorModification>, node_path: Vec<NodeId>) -> VectorDataTable {
if vector_data.is_empty() {
vector_data.push(Instance::default());
}
let vector_data_instance = vector_data.get_mut(0).expect("push should give one item");
modification.apply(vector_data_instance.instance);
// Update the source node id
let this_node_path = node_path.iter().rev().nth(1).copied();
*vector_data_instance.source_node_id = vector_data_instance.source_node_id.or(this_node_path);
if vector_data.len() > 1 {
warn!("The path modify ran on {} instances of vector data. Only the first can be modified.", vector_data.len());
}

View File

@@ -97,7 +97,7 @@ macro_rules! tagged_value {
}
}
/// Attempts to downcast the dynamic type to a tagged value
pub fn try_from_std_any_ref(input: &(dyn std::any::Any)) -> Result<Self, String> {
pub fn try_from_std_any_ref(input: &dyn std::any::Any) -> Result<Self, String> {
use std::any::TypeId;
match input.type_id() {

View File

@@ -18,7 +18,6 @@ use graphene_svg_renderer::{GraphicElementRendered, RenderParams, RenderSvgSegme
use base64::Engine;
#[cfg(target_arch = "wasm32")]
use glam::DAffine2;
use std::collections::{HashMap, HashSet};
use std::sync::Arc;
#[cfg(target_arch = "wasm32")]
use wasm_bindgen::JsCast;
@@ -278,12 +277,7 @@ async fn render<'a: 'n, T: 'n + GraphicElementRendered + WasmNotSend>(
#[cfg(all(feature = "vello", not(test)))]
let use_vello = use_vello && surface_handle.is_some();
let mut metadata = RenderMetadata {
upstream_footprints: HashMap::new(),
local_transforms: HashMap::new(),
click_targets: HashMap::new(),
clip_targets: HashSet::new(),
};
let mut metadata = RenderMetadata::default();
data.collect_metadata(&mut metadata, footprint, None);
let output_format = render_config.export_format;

View File

@@ -198,6 +198,7 @@ pub fn to_transform(transform: DAffine2) -> usvg::Transform {
pub struct RenderMetadata {
pub upstream_footprints: HashMap<NodeId, Footprint>,
pub local_transforms: HashMap<NodeId, DAffine2>,
pub first_instance_source_id: HashMap<NodeId, Option<NodeId>>,
pub click_targets: HashMap<NodeId, Vec<ClickTarget>>,
pub clip_targets: HashSet<NodeId>,
}
@@ -1090,6 +1091,7 @@ impl GraphicElementRendered for GraphicElement {
metadata.upstream_footprints.insert(element_id, footprint);
// TODO: Find a way to handle more than one row of the graphical data table
if let Some(vector_data) = vector_data.instance_ref_iter().next() {
metadata.first_instance_source_id.insert(element_id, *vector_data.source_node_id);
metadata.local_transforms.insert(element_id, *vector_data.transform);
}
}