use super::*;
impl EngineState {
pub fn pick_candidates_at(&self, x: f64, y: f64) -> Vec<pick::PickCandidate> {
let mut out = pick::pick(&self.scene, &self.camera, x, y, &self.pick_options());
out.extend(self.plane_candidates_at(x, y));
sort_pick_candidates(&mut out);
out
}
pub(super) fn plane_candidates_at(&self, x: f64, y: f64) -> Vec<pick::PickCandidate> {
let cam = gizmo_camera(&self.camera);
let (_, _, forward) = self.camera.basis();
self.widgets
.datum_plane_hits(&cam, x as f32, y as f32)
.into_iter()
.map(|(name, point)| {
let position = [point[0] as f64, point[1] as f64, point[2] as f64];
pick::PickCandidate {
kind: pick::PickKind::Plane,
name,
solid: String::new(),
depth: crate::view::dot3(
crate::view::sub3(position, self.camera.eye),
forward,
),
screen_dist: 0.0,
position,
}
})
.collect()
}
pub(super) fn pick_top_at(
&self,
x: f64,
y: f64,
kinds: &[String],
) -> Option<pick::PickCandidate> {
self.pick_candidates_at(x, y)
.into_iter()
.find(|c| kinds.is_empty() || self.candidate_admitted(kinds, c))
}
pub(super) fn candidate_admitted(
&self,
kinds: &[String],
candidate: &pick::PickCandidate,
) -> bool {
if candidate.kind == pick::PickKind::Solid && self.candidate_is_sketch(candidate) {
return kinds.iter().any(|k| k.eq_ignore_ascii_case("SKETCH"));
}
kind_admitted(kinds, candidate.kind)
}
pub fn candidate_kind_label(&self, candidate: &pick::PickCandidate) -> &'static str {
if candidate.kind == pick::PickKind::Solid && self.candidate_is_sketch(candidate) {
return "SKETCH";
}
candidate.kind.as_str()
}
pub(super) fn candidate_is_sketch(&self, candidate: &pick::PickCandidate) -> bool {
let name = if candidate.solid.is_empty() {
candidate.name.as_str()
} else {
candidate.solid.as_str()
};
self.scene
.solid(name)
.is_some_and(|solid| solid.is_sketch)
}
}
pub(super) fn kind_admitted(kinds: &[String], kind: pick::PickKind) -> bool {
let name = kind.as_str();
let datum_alias = kind == pick::PickKind::Plane;
kinds
.iter()
.any(|k| k.eq_ignore_ascii_case(name) || (datum_alias && k.eq_ignore_ascii_case("DATUM")))
}
pub(super) fn sort_pick_candidates(candidates: &mut [pick::PickCandidate]) {
candidates.sort_by(|a, b| {
(a.kind as u8)
.cmp(&(b.kind as u8))
.then(a.depth.total_cmp(&b.depth))
.then(a.screen_dist.total_cmp(&b.screen_dist))
});
}