feat(arraypath): start the array from the path end nearest the pick

The travel direction of a path array now follows where the user clicks to
select the path: the array starts from the nearest end, so clicking near
either end picks the direction. A stored arc is always CCW regardless of how
it was drawn, so without this the array could run opposite to expectation.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hakan Seven 2026-06-16 03:27:22 +03:00
commit 75168145b3

View file

@ -493,6 +493,11 @@ pub struct ArrayPathCommand {
all_entities: Vec<EntityType>,
step: PathStep,
default_count: u32,
/// Where the user clicked to select the path. The array starts from the
/// path end nearest this point, so clicking near either end picks the
/// travel direction (a stored arc is always CCW regardless of how it was
/// drawn, so without this the array could run opposite to expectation).
pick_pt: Vec3,
}
impl ArrayPathCommand {
@ -507,9 +512,24 @@ impl ArrayPathCommand {
all_entities,
step: PathStep::SelectPath,
default_count: defaults::get_array_path_count() as u32,
pick_pt: Vec3::ZERO,
}
}
/// Sample the path and orient the points so index 0 is the end nearest the
/// pick point, giving the user control over the array's travel direction.
fn oriented_samples(&self, entity: &EntityType, count: usize) -> Vec<Vec3> {
let mut pts = Self::sample_path(entity, count);
if pts.len() >= 2 {
let d_first = self.pick_pt.distance_squared(pts[0]);
let d_last = self.pick_pt.distance_squared(pts[pts.len() - 1]);
if d_last < d_first {
pts.reverse();
}
}
pts
}
/// Sample `count` evenly-spaced points along `entity`.
fn sample_path(entity: &EntityType, count: usize) -> Vec<Vec3> {
if count == 0 {
@ -688,7 +708,7 @@ impl CadCommand for ArrayPathCommand {
}
}
fn on_entity_pick(&mut self, handle: Handle, _pt: Vec3) -> CmdResult {
fn on_entity_pick(&mut self, handle: Handle, pt: Vec3) -> CmdResult {
if handle.is_null() || self.handles.contains(&handle) {
return CmdResult::NeedPoint;
}
@ -698,6 +718,7 @@ impl CadCommand for ArrayPathCommand {
.find(|e| e.common().handle == handle)
.cloned()
{
self.pick_pt = pt;
self.step = PathStep::Count {
path_entity: entity,
};
@ -743,7 +764,7 @@ impl CadCommand for ArrayPathCommand {
self.default_count = v;
v
};
let pts = Self::sample_path(path_entity, count as usize);
let pts = self.oriented_samples(path_entity, count as usize);
let transforms = Self::build_transforms(&pts);
if transforms.is_empty() {
return Some(CmdResult::Cancel);
@ -755,7 +776,7 @@ impl CadCommand for ArrayPathCommand {
let PathStep::Count { path_entity } = &self.step else {
return vec![];
};
let pts = Self::sample_path(path_entity, self.default_count as usize);
let pts = self.oriented_samples(path_entity, self.default_count as usize);
let transforms = Self::build_transforms(&pts);
transforms
.iter()