Skip to content

Commit 5e8e80d

Browse files
Review fixes
1 parent 04b915f commit 5e8e80d

1 file changed

Lines changed: 68 additions & 68 deletions

File tree

node-graph/nodes/vector/src/vector_nodes.rs

Lines changed: 68 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -2151,68 +2151,72 @@ async fn morph<I: IntoGraphicTable + 'n + Send + Clone>(
21512151
let subpath_anchors = anchor_count(control_bezpath);
21522152
let max_content_index = content.len().saturating_sub(1);
21532153

2154-
// Compute per-segment arc lengths for spatial positioning along the control path
2155-
let segment_lengths: Vec<f64> = control_bezpath.segments().map(|seg| seg.perimeter(DEFAULT_ACCURACY)).collect();
2156-
2157-
// Compute segment weights based on the user's chosen spacing metric
2158-
let segment_weights: Vec<f64> = match distribution {
2159-
InterpolationDistribution::Objects => vec![1.; segment_count],
2160-
InterpolationDistribution::Distances => segment_lengths.clone(),
2161-
InterpolationDistribution::Angles | InterpolationDistribution::Sizes | InterpolationDistribution::Slants => (0..segment_count)
2162-
.map(|i| {
2163-
let source_index = (content_offset + i).min(max_content_index);
2164-
let target_index = if is_closed && i >= subpath_anchors - 1 {
2165-
content_offset
2166-
} else {
2167-
(content_offset + i + 1).min(max_content_index)
2168-
};
2154+
// Map the fractional progression to a segment index and local blend time using the chosen weights.
2155+
let (local_source_index, time) = if fractional_progression >= 1. {
2156+
(segment_count - 1, 1.)
2157+
} else if matches!(distribution, InterpolationDistribution::Objects) {
2158+
// Fast path for uniform distribution: direct index calculation without allocation or iteration
2159+
let scaled = fractional_progression * segment_count as f64;
2160+
let index = (scaled.ceil() as usize).saturating_sub(1);
2161+
(index, scaled - index as f64)
2162+
} else {
2163+
// Compute segment weights based on the user's chosen spacing metric
2164+
let segment_weights: Vec<f64> = match distribution {
2165+
InterpolationDistribution::Objects => unreachable!(),
2166+
InterpolationDistribution::Distances => control_bezpath.segments().map(|seg| seg.perimeter(DEFAULT_ACCURACY)).collect(),
2167+
InterpolationDistribution::Angles | InterpolationDistribution::Sizes | InterpolationDistribution::Slants => (0..segment_count)
2168+
.map(|i| {
2169+
let source_index = (content_offset + i).min(max_content_index);
2170+
let target_index = if is_closed && i >= subpath_anchors - 1 {
2171+
content_offset
2172+
} else {
2173+
(content_offset + i + 1).min(max_content_index)
2174+
};
21692175

2170-
let (Some(source), Some(target)) = (content.get(source_index), content.get(target_index)) else {
2171-
return 0.;
2172-
};
2173-
let (s_angle, s_scale, s_skew) = source.transform.decompose_rotation_scale_skew();
2174-
let (t_angle, t_scale, t_skew) = target.transform.decompose_rotation_scale_skew();
2175-
2176-
match distribution {
2177-
InterpolationDistribution::Angles => {
2178-
let mut diff = t_angle - s_angle;
2179-
if diff > PI {
2180-
diff -= TAU;
2181-
} else if diff < -PI {
2182-
diff += TAU;
2176+
let (Some(source), Some(target)) = (content.get(source_index), content.get(target_index)) else {
2177+
return 0.;
2178+
};
2179+
let (s_angle, s_scale, s_skew) = source.transform.decompose_rotation_scale_skew();
2180+
let (t_angle, t_scale, t_skew) = target.transform.decompose_rotation_scale_skew();
2181+
2182+
match distribution {
2183+
InterpolationDistribution::Angles => {
2184+
let mut diff = t_angle - s_angle;
2185+
if diff > PI {
2186+
diff -= TAU;
2187+
} else if diff < -PI {
2188+
diff += TAU;
2189+
}
2190+
diff.abs()
21832191
}
2184-
diff.abs()
2192+
InterpolationDistribution::Sizes => (t_scale - s_scale).length(),
2193+
InterpolationDistribution::Slants => (t_skew.atan() - s_skew.atan()).abs(),
2194+
_ => unreachable!(),
21852195
}
2186-
InterpolationDistribution::Sizes => (t_scale - s_scale).length(),
2187-
InterpolationDistribution::Slants => (t_skew.atan() - s_skew.atan()).abs(),
2188-
_ => unreachable!(),
2189-
}
2190-
})
2191-
.collect(),
2192-
};
2196+
})
2197+
.collect(),
2198+
};
21932199

2194-
let total_weight: f64 = segment_weights.iter().sum();
2200+
let total_weight: f64 = segment_weights.iter().sum();
21952201

2196-
// Map the fractional progression to a segment index and local blend time using the chosen weights.
2197-
// When all weights are zero (all elements identical in the chosen metric), there's zero interval to traverse.
2198-
let (local_source_index, time) = if total_weight <= f64::EPSILON {
2199-
(0, 0.)
2200-
} else if fractional_progression >= 1. {
2201-
(segment_count - 1, 1.)
2202-
} else {
2203-
let mut accumulator = 0.;
2204-
let mut found_index = segment_count - 1;
2205-
let mut found_t = 1.;
2206-
for (i, weight) in segment_weights.iter().enumerate() {
2207-
let ratio = weight / total_weight;
2208-
if fractional_progression <= accumulator + ratio {
2209-
found_index = i;
2210-
found_t = if ratio > f64::EPSILON { (fractional_progression - accumulator) / ratio } else { 0. };
2211-
break;
2202+
// When all weights are zero (all elements identical in the chosen metric), there's zero interval to traverse.
2203+
if total_weight <= f64::EPSILON {
2204+
(0, 0.)
2205+
} else {
2206+
let mut accumulator = 0.;
2207+
let mut found_index = segment_count - 1;
2208+
let mut found_t = 1.;
2209+
for (i, weight) in segment_weights.iter().enumerate() {
2210+
let ratio = weight / total_weight;
2211+
if fractional_progression <= accumulator + ratio {
2212+
found_index = i;
2213+
found_t = if ratio > f64::EPSILON { (fractional_progression - accumulator) / ratio } else { 0. };
2214+
break;
2215+
}
2216+
accumulator += ratio;
22122217
}
2213-
accumulator += ratio;
2218+
(found_index, found_t)
22142219
}
2215-
(found_index, found_t)
22162220
};
22172221

22182222
// Convert the blend time to a parametric t for evaluating spatial position on the control path
@@ -2237,11 +2241,6 @@ async fn morph<I: IntoGraphicTable + 'n + Send + Clone>(
22372241
let source_index = source_index.min(max_content_index);
22382242
let target_index = target_index.min(max_content_index);
22392243

2240-
// At the end of an open subpath with no more interpolation needed, return the final element
2241-
if !is_closed && time >= 1. && local_source_index >= subpath_anchors - 2 {
2242-
return content.into_iter().nth(target_index).into_iter().collect();
2243-
}
2244-
22452244
// Use indexed access to borrow only the two rows we need, avoiding collecting the entire table
22462245
let (Some(source_row), Some(target_row)) = (content.get(source_index), content.get(target_index)) else {
22472246
return content;
@@ -2298,16 +2297,17 @@ async fn morph<I: IntoGraphicTable + 'n + Send + Clone>(
22982297
}
22992298
}
23002299

2301-
// Fast path: when exactly at the source object, clone its geometry directly instead of
2302-
// extracting manipulator groups, subdividing, interpolating, and rebuilding the vector.
2303-
if time == 0. {
2304-
let mut vector = source_row.element.clone();
2305-
vector.upstream_data = Some(graphic_table_content);
2306-
2300+
// Fast path: when exactly at either endpoint, clone the corresponding geometry directly
2301+
// instead of extracting manipulator groups, subdividing, interpolating, and rebuilding.
2302+
if time == 0. || time == 1. {
2303+
let row = if time == 0. { source_row } else { target_row };
23072304
return Table::new_from_row(TableRow {
2308-
element: vector,
2305+
element: Vector {
2306+
upstream_data: Some(graphic_table_content),
2307+
..row.element.clone()
2308+
},
2309+
alpha_blending: *row.alpha_blending,
23092310
transform: lerped_transform,
2310-
alpha_blending: *source_row.alpha_blending,
23112311
..Default::default()
23122312
});
23132313
}

0 commit comments

Comments
 (0)