Skip to content

Commit 8a482ca

Browse files
timon-schellingKeavon
authored andcommitted
Review fixes
1 parent ce60075 commit 8a482ca

File tree

1 file changed

+68
-68
lines changed

1 file changed

+68
-68
lines changed

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

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

2229-
// Compute per-segment arc lengths for spatial positioning along the control path
2230-
let segment_lengths: Vec<f64> = control_bezpath.segments().map(|seg| seg.perimeter(DEFAULT_ACCURACY)).collect();
2231-
2232-
// Compute segment weights based on the user's chosen spacing metric
2233-
let segment_weights: Vec<f64> = match distribution {
2234-
InterpolationDistribution::Objects => vec![1.; segment_count],
2235-
InterpolationDistribution::Distances => segment_lengths.clone(),
2236-
InterpolationDistribution::Angles | InterpolationDistribution::Sizes | InterpolationDistribution::Slants => (0..segment_count)
2237-
.map(|i| {
2238-
let source_index = (content_offset + i).min(max_content_index);
2239-
let target_index = if is_closed && i >= subpath_anchors - 1 {
2240-
content_offset
2241-
} else {
2242-
(content_offset + i + 1).min(max_content_index)
2243-
};
2229+
// Map the fractional progression to a segment index and local blend time using the chosen weights.
2230+
let (local_source_index, time) = if fractional_progression >= 1. {
2231+
(segment_count - 1, 1.)
2232+
} else if matches!(distribution, InterpolationDistribution::Objects) {
2233+
// Fast path for uniform distribution: direct index calculation without allocation or iteration
2234+
let scaled = fractional_progression * segment_count as f64;
2235+
let index = (scaled.ceil() as usize).saturating_sub(1);
2236+
(index, scaled - index as f64)
2237+
} else {
2238+
// Compute segment weights based on the user's chosen spacing metric
2239+
let segment_weights: Vec<f64> = match distribution {
2240+
InterpolationDistribution::Objects => unreachable!(),
2241+
InterpolationDistribution::Distances => control_bezpath.segments().map(|seg| seg.perimeter(DEFAULT_ACCURACY)).collect(),
2242+
InterpolationDistribution::Angles | InterpolationDistribution::Sizes | InterpolationDistribution::Slants => (0..segment_count)
2243+
.map(|i| {
2244+
let source_index = (content_offset + i).min(max_content_index);
2245+
let target_index = if is_closed && i >= subpath_anchors - 1 {
2246+
content_offset
2247+
} else {
2248+
(content_offset + i + 1).min(max_content_index)
2249+
};
22442250

2245-
let (Some(source), Some(target)) = (content.get(source_index), content.get(target_index)) else {
2246-
return 0.;
2247-
};
2248-
let (s_angle, s_scale, s_skew) = source.transform.decompose_rotation_scale_skew();
2249-
let (t_angle, t_scale, t_skew) = target.transform.decompose_rotation_scale_skew();
2250-
2251-
match distribution {
2252-
InterpolationDistribution::Angles => {
2253-
let mut diff = t_angle - s_angle;
2254-
if diff > PI {
2255-
diff -= TAU;
2256-
} else if diff < -PI {
2257-
diff += TAU;
2251+
let (Some(source), Some(target)) = (content.get(source_index), content.get(target_index)) else {
2252+
return 0.;
2253+
};
2254+
let (s_angle, s_scale, s_skew) = source.transform.decompose_rotation_scale_skew();
2255+
let (t_angle, t_scale, t_skew) = target.transform.decompose_rotation_scale_skew();
2256+
2257+
match distribution {
2258+
InterpolationDistribution::Angles => {
2259+
let mut diff = t_angle - s_angle;
2260+
if diff > PI {
2261+
diff -= TAU;
2262+
} else if diff < -PI {
2263+
diff += TAU;
2264+
}
2265+
diff.abs()
22582266
}
2259-
diff.abs()
2267+
InterpolationDistribution::Sizes => (t_scale - s_scale).length(),
2268+
InterpolationDistribution::Slants => (t_skew.atan() - s_skew.atan()).abs(),
2269+
_ => unreachable!(),
22602270
}
2261-
InterpolationDistribution::Sizes => (t_scale - s_scale).length(),
2262-
InterpolationDistribution::Slants => (t_skew.atan() - s_skew.atan()).abs(),
2263-
_ => unreachable!(),
2264-
}
2265-
})
2266-
.collect(),
2267-
};
2271+
})
2272+
.collect(),
2273+
};
22682274

2269-
let total_weight: f64 = segment_weights.iter().sum();
2275+
let total_weight: f64 = segment_weights.iter().sum();
22702276

2271-
// Map the fractional progression to a segment index and local blend time using the chosen weights.
2272-
// When all weights are zero (all elements identical in the chosen metric), there's zero interval to traverse.
2273-
let (local_source_index, time) = if total_weight <= f64::EPSILON {
2274-
(0, 0.)
2275-
} else if fractional_progression >= 1. {
2276-
(segment_count - 1, 1.)
2277-
} else {
2278-
let mut accumulator = 0.;
2279-
let mut found_index = segment_count - 1;
2280-
let mut found_t = 1.;
2281-
for (i, weight) in segment_weights.iter().enumerate() {
2282-
let ratio = weight / total_weight;
2283-
if fractional_progression <= accumulator + ratio {
2284-
found_index = i;
2285-
found_t = if ratio > f64::EPSILON { (fractional_progression - accumulator) / ratio } else { 0. };
2286-
break;
2277+
// When all weights are zero (all elements identical in the chosen metric), there's zero interval to traverse.
2278+
if total_weight <= f64::EPSILON {
2279+
(0, 0.)
2280+
} else {
2281+
let mut accumulator = 0.;
2282+
let mut found_index = segment_count - 1;
2283+
let mut found_t = 1.;
2284+
for (i, weight) in segment_weights.iter().enumerate() {
2285+
let ratio = weight / total_weight;
2286+
if fractional_progression <= accumulator + ratio {
2287+
found_index = i;
2288+
found_t = if ratio > f64::EPSILON { (fractional_progression - accumulator) / ratio } else { 0. };
2289+
break;
2290+
}
2291+
accumulator += ratio;
22872292
}
2288-
accumulator += ratio;
2293+
(found_index, found_t)
22892294
}
2290-
(found_index, found_t)
22912295
};
22922296

22932297
// Convert the blend time to a parametric t for evaluating spatial position on the control path
@@ -2312,11 +2316,6 @@ async fn morph<I: IntoGraphicTable + 'n + Send + Clone>(
23122316
let source_index = source_index.min(max_content_index);
23132317
let target_index = target_index.min(max_content_index);
23142318

2315-
// At the end of an open subpath with no more interpolation needed, return the final element
2316-
if !is_closed && time >= 1. && local_source_index >= subpath_anchors - 2 {
2317-
return content.into_iter().nth(target_index).into_iter().collect();
2318-
}
2319-
23202319
// Use indexed access to borrow only the two rows we need, avoiding collecting the entire table
23212320
let (Some(source_row), Some(target_row)) = (content.get(source_index), content.get(target_index)) else {
23222321
return content;
@@ -2373,16 +2372,17 @@ async fn morph<I: IntoGraphicTable + 'n + Send + Clone>(
23732372
}
23742373
}
23752374

2376-
// Fast path: when exactly at the source object, clone its geometry directly instead of
2377-
// extracting manipulator groups, subdividing, interpolating, and rebuilding the vector.
2378-
if time == 0. {
2379-
let mut vector = source_row.element.clone();
2380-
vector.upstream_data = Some(graphic_table_content);
2381-
2375+
// Fast path: when exactly at either endpoint, clone the corresponding geometry directly
2376+
// instead of extracting manipulator groups, subdividing, interpolating, and rebuilding.
2377+
if time == 0. || time == 1. {
2378+
let row = if time == 0. { source_row } else { target_row };
23822379
return Table::new_from_row(TableRow {
2383-
element: vector,
2380+
element: Vector {
2381+
upstream_data: Some(graphic_table_content),
2382+
..row.element.clone()
2383+
},
2384+
alpha_blending: *row.alpha_blending,
23842385
transform: lerped_transform,
2385-
alpha_blending: *source_row.alpha_blending,
23862386
..Default::default()
23872387
});
23882388
}

0 commit comments

Comments
 (0)