1pub mod icons;
26pub mod kept;
27pub mod lit;
28pub mod picture;
29#[cfg(test)]
30mod tests;
31mod tree;
32
33use std::{cell::RefCell, collections::BTreeMap, rc::Rc};
34
35use crate::editing::{
36 Extent, Pointer,
37 hit::{ElementHit, Scene, cycled, nearer},
38};
39use geop_core_math::{
40 geop_error::GeopResult,
41 polygon::polygons_contain,
42 primitives::{CoordinateSystem, DatumComponent, DatumKind, FrameAxis, Motion, Pose, Ray},
43 scalars::Scalar,
44 vector::{Vector2, Vector3},
45};
46use geop_core_program::{
47 element::{ElementReference, HasElements, Kind, PickedElement, whole},
48 placed::{INSTANCE_SEPARATOR, Located},
49 reader::Reader,
50 target::{Target, TargetReference},
51};
52use serde::Serialize;
53use tree::FaceTree;
54pub use tree::triangles_tested;
55
56pub mod drawn {
59 pub const VERTEX: &str = "vertex";
61 pub const EDGE: &str = "edge";
63 pub const FACE: &str = "face";
65 pub const SKETCH: &str = "sketch";
67 pub const SKETCH_POINT: &str = "sketch_point";
69 pub const SKETCH_CURVE: &str = "sketch_curve";
71 pub const DATUM: &str = "datum";
73 pub const FRAME: &str = "frame";
77}
78
79const END_OF_AN_EDGE: f64 = 0.2;
82
83const NEAR_CORNER: f64 = 4.0;
86const NEAR_SIDE: f64 = 3.0;
87
88#[derive(Clone, Debug, PartialEq)]
94pub struct FramePick {
95 pub on: PickedElement,
96 pub at: Option<PickedElement>,
97}
98
99impl FramePick {
100 pub fn picked(&self) -> PickedElement {
102 let named = |p: &PickedElement| format!("{}/{}", p.kind, p.name);
103 let name = match &self.at {
104 None => named(&self.on),
105 Some(at) => format!("{}|{}", named(&self.on), named(at)),
106 };
107 PickedElement {
108 target: self.on.target.clone(),
109 kind: drawn::FRAME.to_string(),
110 name,
111 }
112 }
113
114 pub fn of(picked: &PickedElement) -> Option<Self> {
116 (picked.kind == drawn::FRAME).then_some(())?;
117 let element = |text: &str| {
118 let (kind, name) = text.split_once('/')?;
119 Some(PickedElement {
120 target: picked.target.clone(),
121 kind: kind.to_string(),
122 name: name.to_string(),
123 })
124 };
125 let (on, at) = match picked.name.split_once('|') {
126 Some((on, at)) => (on, Some(element(at)?)),
127 None => (picked.name.as_str(), None),
128 };
129 Some(Self {
130 on: element(on)?,
131 at,
132 })
133 }
134}
135
136pub const RESOLUTION: usize = 24;
140
141pub const FRAME: f64 = 10.0;
146
147pub const EMPTY_EXTENT: f64 = 100.0;
151
152#[derive(Clone, Debug, Serialize)]
154pub struct ViewVertex {
155 pub name: String,
156 pub solid: Option<String>,
158 pub faces: Vec<String>,
161 pub at: Vector3,
162}
163
164#[derive(Clone, Debug, Serialize)]
166pub struct ViewEdge {
167 pub name: String,
168 pub solid: Option<String>,
170 pub faces: Vec<String>,
173 pub polyline: Vec<Vector3>,
174 pub within_a_surface: bool,
179 #[serde(skip)]
181 pub ends: [String; 2],
182}
183
184#[derive(Clone, Debug, Serialize)]
188pub struct ViewFace {
189 pub name: String,
190 #[serde(skip_serializing_if = "Vec::is_empty")]
193 pub also: Vec<String>,
194 pub solid: Option<String>,
196 #[serde(skip_serializing_if = "Option::is_none")]
198 pub feature: Option<String>,
199 #[serde(serialize_with = "FaceMesh::serialize_key")]
200 pub mesh: Rc<FaceMesh>,
201}
202
203#[derive(Debug)]
218pub struct FaceMesh {
219 pub key: String,
220 pub triangles: Vec<[Vector3; 3]>,
221 pub normals: Vec<[Vector3; 3]>,
222}
223
224impl Serialize for FaceMesh {
225 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
226 use serde::ser::SerializeStruct;
227 let mut index: std::collections::HashMap<[u32; 6], u32> = Default::default();
228 let (mut positions, mut normals, mut indices) = (Vec::new(), Vec::new(), Vec::new());
229 for (points, at) in self.triangles.iter().zip(&self.normals) {
230 for (p, n) in points.iter().zip(at) {
231 let p = p.to_array().map(|x| x.to_f64() as f32);
232 let n = n.to_array().map(|x| x.to_f64() as f32);
233 let bits = [p[0], p[1], p[2], n[0], n[1], n[2]].map(f32::to_bits);
234 let next = index.len() as u32;
235 let corner = *index.entry(bits).or_insert_with(|| {
236 positions.extend(p.iter().flat_map(|x| x.to_le_bytes()));
237 normals.extend(n.iter().flat_map(|x| x.to_le_bytes()));
238 next
239 });
240 indices.extend(corner.to_le_bytes());
241 }
242 }
243 let base64 = geop_core_program::workspace::base64;
244 let mut s = serializer.serialize_struct("FaceMesh", 3)?;
245 s.serialize_field("positions", &base64(&positions))?;
246 s.serialize_field("normals", &base64(&normals))?;
247 s.serialize_field("indices", &base64(&indices))?;
248 s.end()
249 }
250}
251
252impl FaceMesh {
253 pub fn new(triangles: Vec<[Vector3; 3]>, normals: Vec<[Vector3; 3]>) -> Rc<Self> {
256 use std::hash::{Hash, Hasher};
257 FACES_DRAWN.set(FACES_DRAWN.get() + 1);
258 let sharp = |corners: Vec<[Vector3; 3]>| -> Vec<[Vector3; 3]> {
259 (corners.into_iter())
260 .map(|corner| corner.map(|p| p.map(|x| Scalar::from_f64(x.to_f64()))))
261 .collect()
262 };
263 let (triangles, normals) = (sharp(triangles), sharp(normals));
264 let mut key = std::hash::DefaultHasher::new();
265 for p in triangles.iter().chain(&normals).flatten() {
266 for x in p.to_array() {
267 x.to_f64().to_bits().hash(&mut key);
268 }
269 }
270 triangles.len().hash(&mut key);
271 Rc::new(Self {
272 key: format!("{:016x}", key.finish()),
273 triangles,
274 normals,
275 })
276 }
277
278 fn serialize_key<S: serde::Serializer>(mesh: &Rc<Self>, s: S) -> Result<S::Ok, S::Error> {
280 s.serialize_str(&mesh.key)
281 }
282}
283
284#[derive(Clone, Debug, Serialize)]
287pub struct ViewCurve {
288 pub id: String,
289 pub construction: bool,
290 pub polyline: Vec<Vector2>,
291}
292
293#[derive(Clone, Debug, Serialize)]
296pub struct ViewSketchPoint {
297 pub id: String,
298 pub at: Vector2,
299}
300
301#[derive(Clone, Debug, Serialize)]
305pub struct ViewSketch {
306 pub name: String,
307 pub target: String,
309 pub plane: CoordinateSystem,
310 #[serde(skip)]
311 pub regions: Vec<Vec<Vec<Vector2>>>,
312 pub curves: Vec<ViewCurve>,
313 pub points: Vec<ViewSketchPoint>,
314}
315
316#[derive(Clone, Debug, Serialize)]
319pub struct ViewDatum {
320 pub name: String,
321 pub kind: DatumKind,
322 pub frame: CoordinateSystem,
323 #[serde(skip)]
325 pub components: Vec<(DatumComponent, String)>,
326}
327
328#[derive(Clone, Debug, PartialEq, Serialize)]
331pub struct ViewAnnotation {
332 pub name: String,
333 pub label: String,
334 pub polyline: Vec<Vector3>,
335}
336
337#[derive(Clone, Debug, Default, PartialEq)]
340pub struct Annotations(pub Vec<ViewAnnotation>);
341
342pub fn annotations(step: &str) -> TargetReference<Annotations> {
345 TargetReference::new(format!("annotations:{step}"))
346}
347
348pub fn annotations_of(reader: &Reader) -> Vec<ViewAnnotation> {
350 (reader.targets_of::<Annotations>().into_iter())
351 .filter_map(|target| {
352 let whole = ElementReference::<Annotations, Annotations>::whole(target);
353 reader
354 .retrieve_element(&whole)
355 .ok()
356 .map(|drawn| drawn.0.clone())
357 })
358 .flatten()
359 .collect()
360}
361
362impl Target for Annotations {}
364
365impl Kind for Annotations {
367 const NAME: &'static str = "annotations";
368}
369
370impl HasElements<Annotations> for Annotations {
371 type Element<'a> = &'a Annotations;
372
373 fn element(&self, name: &str) -> GeopResult<&Annotations> {
374 whole(self, name)
375 }
376
377 fn names_target(name: &str) -> bool {
378 name.starts_with("annotations:")
379 }
380}
381
382#[derive(Clone, Debug, PartialEq, Serialize)]
385pub struct Listed {
386 pub kind: String,
388 pub name: String,
389 pub elements: Vec<PickedElement>,
392}
393
394#[derive(Clone, Debug, Default, PartialEq)]
397pub struct Listing(pub Vec<Listed>);
398
399pub fn listing(step: &str) -> TargetReference<Listing> {
401 TargetReference::new(format!("listing:{step}"))
402}
403
404pub fn listed_by_steps(reader: &Reader) -> Vec<Listed> {
406 (reader.targets_of::<Listing>().into_iter())
407 .filter_map(|target| {
408 let whole = ElementReference::<Listing, Listing>::whole(target);
409 reader
410 .retrieve_element(&whole)
411 .ok()
412 .map(|listing| listing.0.clone())
413 })
414 .flatten()
415 .collect()
416}
417
418impl Target for Listing {}
420
421impl Kind for Listing {
423 const NAME: &'static str = "listing";
424}
425
426impl HasElements<Listing> for Listing {
427 type Element<'a> = &'a Listing;
428
429 fn element(&self, name: &str) -> GeopResult<&Listing> {
430 whole(self, name)
431 }
432
433 fn names_target(name: &str) -> bool {
434 name.starts_with("listing:")
435 }
436}
437
438#[derive(Clone, Serialize)]
442pub struct ViewInstance {
443 pub name: String,
446 pub component: String,
448 pub frame: CoordinateSystem,
450 #[serde(skip)]
451 pub pose: Pose,
452 #[serde(skip)]
454 pub view: Rc<PartView>,
455 #[serde(skip)]
458 pub state: Option<String>,
459 #[serde(skip)]
461 pub fixed: bool,
462 #[serde(skip_serializing_if = "Option::is_none")]
465 pub color: Option<String>,
466}
467
468impl std::fmt::Debug for ViewInstance {
469 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
470 write!(
471 f,
472 "ViewInstance({}, {}, {:?})",
473 self.name, self.component, self.pose
474 )
475 }
476}
477
478#[derive(Clone, Debug, Serialize)]
482pub struct PartView {
483 pub model: String,
486 pub vertices: Vec<ViewVertex>,
487 pub edges: Vec<ViewEdge>,
488 pub faces: Vec<ViewFace>,
489 pub sketches: Vec<ViewSketch>,
490 pub datum_target: String,
492 pub datums: Vec<ViewDatum>,
493 pub annotations: Vec<ViewAnnotation>,
495 pub solids: Vec<String>,
497 #[serde(skip)]
500 pub instances: Vec<ViewInstance>,
501 pub extent: Extent,
506 pub color: Option<String>,
508 #[serde(skip_serializing_if = "BTreeMap::is_empty")]
514 pub face_colors: BTreeMap<String, String>,
515 #[serde(skip)]
519 faces_tree: RefCell<Option<Rc<FaceTree>>>,
520}
521
522struct Layer<'v> {
525 view: &'v PartView,
526 pointer: Pointer,
527 near: bool,
532 motion: Option<(Motion, Motion)>,
534 instance: Option<&'v str>,
536 hidden: &'v [String],
538}
539
540impl Layer<'_> {
541 fn hides(&self, name: &str) -> bool {
545 let key = Located::in_instance(self.instance.unwrap_or_default(), name).key();
546 self.hidden.binary_search(&key).is_ok()
547 }
548
549 fn shows_face(&self, face: &ViewFace) -> bool {
552 match &face.solid {
553 Some(solid) => !self.hides(solid),
554 None => !self.hides(&face.name),
555 }
556 }
557
558 fn shows_boundary(&self, solid: &Option<String>, faces: &[String]) -> bool {
562 match solid {
563 Some(solid) => !self.hides(solid),
564 None => faces.is_empty() || faces.iter().any(|f| !self.hides(f)),
565 }
566 }
567
568 fn pick_face(&self) -> Option<(Scalar, &ViewFace)> {
570 (self.view).pick_face(&self.pointer, |f| self.shows_face(f))
571 }
572
573 fn faces_entered(&self) -> Vec<(Scalar, &ViewFace)> {
575 (self.view).faces_entered(&self.pointer, |f| self.shows_face(f))
576 }
577
578 fn element(&self, target: &str, kind: &str, name: &str) -> PickedElement {
581 PickedElement {
582 target: Located::in_instance(self.instance.unwrap_or_default(), target),
583 kind: kind.to_string(),
584 name: name.to_string(),
585 }
586 }
587
588 fn world(&self, p: Vector3) -> Vector3 {
590 match &self.motion {
591 Some((there, _)) => there.apply(&p),
592 None => p,
593 }
594 }
595
596 fn local(&self, p: Vector3) -> Vector3 {
598 match &self.motion {
599 Some((_, back)) => back.apply(&p),
600 None => p,
601 }
602 }
603
604 fn hit(&self, target: &str, kind: &str, name: &str, point: Vector3, t: Scalar) -> ElementHit {
607 ElementHit {
608 element: self.element(target, kind, name),
609 point: self.world(point),
610 t,
611 }
612 }
613}
614
615impl PartView {
616 pub fn color_of_face(&self, face: &ViewFace) -> Option<&String> {
619 (std::iter::once(&face.name).chain(&face.also)).find_map(|name| self.face_colors.get(name))
620 }
621
622 pub fn blank(extent: Extent) -> Self {
625 Self {
626 model: String::new(),
627 vertices: Vec::new(),
628 edges: Vec::new(),
629 faces: Vec::new(),
630 sketches: Vec::new(),
631 datum_target: String::new(),
632 datums: Vec::new(),
633 annotations: Vec::new(),
634 solids: Vec::new(),
635 instances: Vec::new(),
636 extent,
637 color: None,
638 face_colors: BTreeMap::new(),
639 faces_tree: RefCell::default(),
640 }
641 }
642
643 pub fn new() -> Self {
645 Self::blank(Extent {
646 center: Vector3::zero(),
647 size: Scalar::from_f64(EMPTY_EXTENT),
648 })
649 }
650
651 pub fn add(&mut self, drawn: &PartView) {
655 if !drawn.model.is_empty() {
656 self.model.clone_from(&drawn.model);
657 }
658 if !drawn.datum_target.is_empty() {
659 self.datum_target.clone_from(&drawn.datum_target);
660 }
661 if drawn.color.is_some() {
662 self.color.clone_from(&drawn.color);
663 }
664 (self.face_colors).extend(
665 drawn
666 .face_colors
667 .iter()
668 .map(|(k, v)| (k.clone(), v.clone())),
669 );
670 self.vertices.extend_from_slice(&drawn.vertices);
671 self.edges.extend_from_slice(&drawn.edges);
672 self.faces.extend_from_slice(&drawn.faces);
673 self.sketches.extend_from_slice(&drawn.sketches);
674 self.datums.extend_from_slice(&drawn.datums);
675 self.annotations.extend_from_slice(&drawn.annotations);
676 self.solids.extend_from_slice(&drawn.solids);
677 self.instances.extend_from_slice(&drawn.instances);
678 }
679
680 pub fn finish(mut self) -> Self {
682 PARTS_DRAWN.set(PARTS_DRAWN.get() + 1);
683 self.extent = self.measure();
684 self
685 }
686
687 fn near(&self, pointer: &Pointer) -> bool {
694 let Ok(radius) = self.extent.size.div(Scalar::TWO) else {
695 return true;
696 };
697 let (dist, t) = pointer.ray.distance_to_point(&self.extent.center);
698 !dist
699 .sub(radius)
700 .definitely_greater(pointer.reach_at(1.0, t.add(radius)))
701 }
702
703 fn layers<'v>(&'v self, pointer: &Pointer, hidden: &'v [String]) -> Vec<Layer<'v>> {
707 let mut layers = vec![Layer {
708 view: self,
709 pointer: *pointer,
710 near: true,
711 motion: None,
712 instance: None,
713 hidden,
714 }];
715 let instance_hidden = |name: &str| {
716 let mut path = name;
717 loop {
718 if hidden.binary_search_by(|h| h.as_str().cmp(path)).is_ok() {
719 return true;
720 }
721 match path.rsplit_once(INSTANCE_SEPARATOR) {
722 Some((outer, _)) => path = outer,
723 None => return false,
724 }
725 }
726 };
727 for instance in self.instances.iter().filter(|i| !instance_hidden(&i.name)) {
728 let back = instance.pose.inverse().motion();
729 let ray = &pointer.ray;
730 let Ok(ray) = Ray::try_new(back.apply(ray.origin()), back.rotate(ray.dir())) else {
731 continue;
732 };
733 let view = &*instance.view;
734 let pointer = Pointer {
735 cycle: pointer.cycle,
736 ray,
737 reach: pointer.reach,
738 };
739 layers.push(Layer {
740 near: view.near(&pointer),
741 view,
742 pointer,
743 motion: Some((instance.pose.motion(), back)),
744 instance: Some(&instance.name),
745 hidden,
746 });
747 }
748 layers
749 }
750
751 pub fn part_to_drag(
758 &self,
759 pointer: &Pointer,
760 hidden: &[String],
761 ) -> Option<(&ViewInstance, Scalar)> {
762 let layers = self.layers(pointer, hidden);
763 let (t, hit) = layers
765 .iter()
766 .filter(|l| l.near)
767 .filter_map(|l| Some((l.pick_face()?.0, l.instance)))
768 .min_by(|a, b| nearer(a.0, b.0))?;
769 let hit = hit?;
770 let moved = self
771 .instances
772 .iter()
773 .filter(|i| i.state.is_some() && !i.fixed)
774 .filter(|i| {
775 i.name == hit
776 || (hit.strip_prefix(&i.name))
777 .is_some_and(|r| r.starts_with(INSTANCE_SEPARATOR))
778 })
779 .max_by_key(|i| i.name.len())?;
780 Some((moved, t))
781 }
782
783 pub fn pick_instance(
786 &self,
787 instance: &str,
788 pointer: &Pointer,
789 hidden: &[String],
790 ) -> Option<Scalar> {
791 let layers = self.layers(pointer, hidden);
792 let layer = layers.iter().find(|l| l.instance == Some(instance))?;
793 layer.near.then(|| layer.pick_face())?.map(|(t, _)| t)
794 }
795
796 fn own_box(&self) -> Option<Vector3> {
799 let sketch_points = self.sketches.iter().flat_map(|sketch| {
800 (sketch.curves.iter())
801 .flat_map(|c| &c.polyline)
802 .map(|p| sketch.plane.uv_to_xyz(p))
803 });
804 (self.vertices.iter())
805 .map(|v| v.at)
806 .chain(self.edges.iter().flat_map(|e| e.polyline.iter().copied()))
807 .chain((self.faces.iter()).flat_map(|f| f.mesh.triangles.iter().flatten().copied()))
808 .chain(sketch_points)
809 .reduce(|a, b| a.union(&b))
810 }
811
812 fn measure(&self) -> Extent {
815 let mut corners = Vec::new();
819 for instance in &self.instances {
820 let Some(own) = instance.view.own_box() else {
821 continue;
822 };
823 let motion = instance.pose.motion();
824 for i in 0..8 {
825 let corner = Vector3::from_array([0, 1, 2].map(|k| match i >> k & 1 {
826 0 => own[k].lower(),
827 _ => own[k].upper(),
828 }));
829 corners.push(motion.apply(&corner));
830 }
831 }
832 let hull = self.own_box().into_iter();
833 let hull = hull.into_iter().chain(corners).reduce(|a, b| a.union(&b));
834 let Some(hull) = hull else {
835 return Extent {
836 center: Vector3::zero(),
837 size: Scalar::from_f64(EMPTY_EXTENT),
838 };
839 };
840 let size = Vector3::from_array([0, 1, 2].map(|k| hull[k].width())).norm();
841 Extent {
842 center: Vector3::from_array([0, 1, 2].map(|k| hull[k].midpoint())),
843 size: if size.definitely_less(Scalar::ONE) {
844 Scalar::ONE
845 } else {
846 size
847 },
848 }
849 }
850
851 pub fn under(
866 &self,
867 pointer: &Pointer,
868 accepts: &[String],
869 hidden: &[String],
870 ) -> Vec<ElementHit> {
871 let accepted = |kind: &str| accepts.iter().any(|a| a == kind);
872 if accepted(drawn::FRAME) {
873 return self.frames_under(pointer, hidden);
874 }
875 let layers = self.layers(pointer, hidden);
876 let mut first = None;
878 let mut all = Vec::new();
879 if accepted(drawn::DATUM) {
880 let [balls, axes, planes] = (layers.iter()).map(|l| l.view.frame_parts_under(l)).fold(
881 Default::default(),
882 |mut parts: [Vec<_>; 3], of| {
883 for (part, hits) in parts.iter_mut().zip(of) {
884 part.extend(hits);
885 }
886 parts
887 },
888 );
889 first = (nearest(balls.iter().cloned()))
890 .or_else(|| nearest(axes.iter().cloned()))
891 .or_else(|| nearest(planes.iter().cloned()));
892 all.extend(balls.into_iter().chain(axes).chain(planes));
893 }
894
895 let mut faces: Vec<_> = (layers.iter())
899 .filter(|l| l.near)
900 .flat_map(|l| l.faces_entered().into_iter().map(move |(t, f)| (t, l, f)))
901 .collect();
902 faces.sort_by(|a, b| nearer(a.0, b.0));
903 let face = faces.first();
904 let visible = |t: Scalar, faces: &[String], layer: &Layer<'_>| {
911 face.is_none_or(|(ft, l, f)| {
912 (l.instance == layer.instance && faces.contains(&f.name))
913 || !t.definitely_greater(ft.add(pointer.reach_at(1.0, *ft)))
914 })
915 };
916
917 let mut points = Vec::new();
919 for l in layers.iter().filter(|l| l.near) {
920 let ray = &l.pointer.ray;
921 let near = |at: &Vector3, faces: &[String]| {
922 let (dist, t) = ray.distance_to_point(at);
923 (l.pointer.within(dist, t, 1.0)).then(|| (t, visible(t, faces, l)))
924 };
925 if accepted(drawn::VERTEX) {
926 for v in (l.view.vertices.iter()).filter(|v| l.shows_boundary(&v.solid, &v.faces)) {
927 if let Some((t, seen)) = near(&v.at, &v.faces) {
928 points.push((l.hit(&l.view.model, drawn::VERTEX, &v.name, v.at, t), seen));
929 }
930 }
931 }
932 if accepted(drawn::SKETCH_POINT) {
933 for sketch in l.view.sketches.iter().filter(|s| !l.hides(&s.name)) {
934 for p in &sketch.points {
935 let at = sketch.plane.uv_to_xyz(&p.at);
936 if let Some((t, seen)) = near(&at, &[]) {
937 let hit = l.hit(&sketch.target, drawn::SKETCH_POINT, &p.id, at, t);
938 points.push((hit, seen));
939 }
940 }
941 }
942 }
943 }
944 let (mut edges, mut sketch_curves) = (Vec::new(), Vec::new());
945 for l in layers.iter().filter(|l| l.near) {
946 let ray = &l.pointer.ray;
947 let hit_along = |polyline: &mut dyn Iterator<Item = (Vector3, Vector3)>,
951 faces: &[String]| {
952 polyline
953 .map(|(a, b)| ray.distance_to_segment(&a, &b))
954 .filter(|&(dist, t)| l.pointer.within(dist, t, 1.0))
955 .map(|(_, t)| (t, visible(t, faces, l)))
956 .min_by(|a, b| b.1.cmp(&a.1).then(nearer(a.0, b.0)))
957 };
958 if accepted(drawn::EDGE) {
959 for e in (l.view.edges.iter()).filter(|e| l.shows_boundary(&e.solid, &e.faces)) {
960 let mut segments = e.polyline.array_windows().map(|&[a, b]| (a, b));
961 if let Some((t, seen)) = hit_along(&mut segments, &e.faces) {
962 let hit = l.hit(&l.view.model, drawn::EDGE, &e.name, ray.at(t), t);
963 edges.push((hit, seen));
964 }
965 }
966 }
967 if accepted(drawn::SKETCH_CURVE) {
968 for sketch in l.view.sketches.iter().filter(|s| !l.hides(&s.name)) {
969 for c in &sketch.curves {
970 let world = |p: &Vector2| sketch.plane.uv_to_xyz(p);
971 let mut segments = c
972 .polyline
973 .array_windows()
974 .map(|[a, b]| (world(a), world(b)));
975 if let Some((t, seen)) = hit_along(&mut segments, &[]) {
976 let at = ray.at(t);
977 let hit = l.hit(&sketch.target, drawn::SKETCH_CURVE, &c.id, at, t);
978 sketch_curves.push((hit, seen));
979 }
980 }
981 }
982 }
983 }
984 let seen = |hits: &[(ElementHit, bool)]| {
985 nearest(
986 (hits.iter())
987 .filter(|(_, seen)| *seen)
988 .map(|(hit, _)| hit.clone()),
989 )
990 };
991 if first.is_none() {
992 first = seen(&points);
993 }
994 if first.is_none() {
998 first = match (seen(&edges), seen(&sketch_curves)) {
999 (Some(edge), Some(drawn))
1000 if edge
1001 .t
1002 .definitely_greater(drawn.t.add(pointer.reach_at(1.0, drawn.t))) =>
1003 {
1004 Some(drawn)
1005 }
1006 (edge, drawn) => edge.or(drawn),
1007 };
1008 }
1009 all.extend((points.into_iter().chain(edges).chain(sketch_curves)).map(|(hit, _)| hit));
1010
1011 let mut areas: Vec<ElementHit> = Vec::new();
1012 if accepted(drawn::FACE) {
1013 for (t, l, f) in &faces {
1014 let point = l.pointer.ray.at(*t);
1015 areas.push(l.hit(&l.view.model, drawn::FACE, &f.name, point, *t));
1016 }
1017 }
1018 for l in &layers {
1019 if accepted(drawn::SKETCH) {
1020 areas.extend(l.view.sketches_under(l));
1021 }
1022 if accepted(drawn::DATUM) {
1023 let extent = Extent {
1024 center: l.local(self.extent.center),
1025 size: self.extent.size,
1026 };
1027 areas.extend(l.view.datums_under(l, extent));
1028 }
1029 }
1030 if first.is_none() {
1031 first = nearest(areas.iter().cloned());
1032 }
1033 all.extend(areas);
1034 all.sort_by(|a, b| nearer(a.t, b.t));
1035 let mut under: Vec<ElementHit> = Vec::new();
1036 for hit in first.into_iter().chain(all) {
1037 if !under.iter().any(|u| u.element == hit.element) {
1038 under.push(hit);
1039 }
1040 }
1041 under
1042 }
1043
1044 pub fn pick(
1047 &self,
1048 pointer: &Pointer,
1049 accepts: &[String],
1050 hidden: &[String],
1051 ) -> Option<ElementHit> {
1052 cycled(self.under(pointer, accepts, hidden), pointer.cycle)
1053 }
1054
1055 fn frames_under(&self, pointer: &Pointer, hidden: &[String]) -> Vec<ElementHit> {
1058 let kinds = [
1059 drawn::DATUM,
1060 drawn::VERTEX,
1061 drawn::EDGE,
1062 drawn::FACE,
1063 drawn::SKETCH_POINT,
1064 drawn::SKETCH_CURVE,
1065 ];
1066 let accepts: Vec<String> = kinds.iter().map(|k| k.to_string()).collect();
1067 let layers = self.layers(pointer, hidden);
1068 let mut frames: Vec<ElementHit> = Vec::new();
1069 for hit in self.under(pointer, &accepts, hidden) {
1070 if let Some(frame) = self.frame_on(&layers, hit)
1071 && !frames.iter().any(|f| f.element == frame.element)
1072 {
1073 frames.push(frame);
1074 }
1075 }
1076 frames
1077 }
1078
1079 fn frame_on(&self, layers: &[Layer<'_>], hit: ElementHit) -> Option<ElementHit> {
1085 let instance = Some(hit.element.target.path()).filter(|path| !path.is_empty());
1086 let layer = layers.iter().find(|l| l.instance == instance)?;
1087 let view = layer.view;
1088 let element = |kind: &str, name: &str| PickedElement {
1089 target: hit.element.target.clone(),
1090 kind: kind.to_string(),
1091 name: name.to_string(),
1092 };
1093 let at = match hit.element.kind.as_str() {
1094 drawn::VERTEX => {
1095 let vertex = view.vertices.iter().find(|v| v.name == hit.element.name)?;
1096 let under = layer.pick_face();
1097 if let Some((_, face)) = under.filter(|(_, f)| vertex.faces.contains(&f.name)) {
1098 let on = element(drawn::FACE, &face.name);
1099 let frame = FramePick {
1100 on,
1101 at: Some(hit.element.clone()),
1102 };
1103 return Some(ElementHit {
1104 element: frame.picked(),
1105 ..hit
1106 });
1107 }
1108 None
1109 }
1110 drawn::EDGE => {
1111 let edge = view.edges.iter().find(|e| e.name == hit.element.name)?;
1112 let (first, last) = (edge.polyline.first()?, edge.polyline.last()?);
1113 let local = layer.local(hit.point);
1114 let reach = last.sub(first).norm().mul(Scalar::from_f64(END_OF_AN_EDGE));
1115 if local.sub(first).norm().definitely_less(reach) {
1116 Some(element(drawn::VERTEX, &edge.ends[0]))
1117 } else if local.sub(last).norm().definitely_less(reach) {
1118 Some(element(drawn::VERTEX, &edge.ends[1]))
1119 } else {
1120 None
1121 }
1122 }
1123 drawn::FACE => (view.corner_or_side_near(&layer.pointer, &hit.element.name))
1124 .map(|(kind, name)| element(kind, &name)),
1125 _ => None,
1126 };
1127 let frame = FramePick {
1128 on: hit.element.clone(),
1129 at,
1130 };
1131 Some(ElementHit {
1132 element: frame.picked(),
1133 ..hit
1134 })
1135 }
1136
1137 fn corner_or_side_near(&self, pointer: &Pointer, face: &str) -> Option<(&'static str, String)> {
1141 let ray = &pointer.ray;
1142 let corner = (self.vertices.iter())
1143 .filter(|v| v.faces.iter().any(|f| f == face))
1144 .map(|v| (v, ray.distance_to_point(&v.at)))
1145 .filter(|(_, (dist, t))| pointer.within(*dist, *t, NEAR_CORNER))
1146 .min_by(|a, b| nearer(a.1.0, b.1.0))
1147 .map(|(v, _)| (drawn::VERTEX, v.name.clone()));
1148 corner.or_else(|| {
1149 (self.edges.iter())
1150 .filter(|e| e.faces.iter().any(|f| f == face))
1151 .filter_map(|e| {
1152 (e.polyline.array_windows())
1153 .map(|[a, b]| ray.distance_to_segment(a, b))
1154 .filter(|(dist, t)| pointer.within(*dist, *t, NEAR_SIDE))
1155 .min_by(|a, b| nearer(a.0, b.0))
1156 .map(|(dist, _)| (e, dist))
1157 })
1158 .min_by(|a, b| nearer(a.1, b.1))
1159 .map(|(e, _)| (drawn::EDGE, e.name.clone()))
1160 })
1161 }
1162
1163 fn faces_entered(
1168 &self,
1169 pointer: &Pointer,
1170 shown: impl Fn(&ViewFace) -> bool,
1171 ) -> Vec<(Scalar, &ViewFace)> {
1172 let mut hits = Vec::new();
1173 self.faces_tree().near(&pointer.ray, |f, t| {
1174 if let Some(face) = self.faces.get(f).filter(|face| shown(face))
1175 && let Some([a, b, c]) = face.mesh.triangles.get(t)
1176 && let Some(hit) = pointer.ray.intersect_triangle(a, b, c)
1177 {
1178 hits.push(((f, t), hit, face));
1179 }
1180 });
1181 hits.sort_by_key(|(at, ..)| *at);
1182 let mut entered: Vec<(usize, Scalar, &ViewFace)> = Vec::new();
1183 for ((f, _), hit, face) in hits {
1184 match entered.last_mut() {
1185 Some((g, t, _)) if *g == f => {
1186 if nearer(hit, *t).is_lt() {
1187 *t = hit;
1188 }
1189 }
1190 _ => entered.push((f, hit, face)),
1191 }
1192 }
1193 entered.sort_by(|a, b| nearer(a.1, b.1));
1194 entered.into_iter().map(|(_, t, face)| (t, face)).collect()
1195 }
1196
1197 fn pick_face(
1200 &self,
1201 pointer: &Pointer,
1202 shown: impl Fn(&ViewFace) -> bool,
1203 ) -> Option<(Scalar, &ViewFace)> {
1204 self.faces_entered(pointer, shown).into_iter().next()
1205 }
1206
1207 fn faces_tree(&self) -> Rc<FaceTree> {
1210 let mut kept = self.faces_tree.borrow_mut();
1211 if let Some(tree) = kept.as_ref().filter(|tree| tree.is_of(&self.faces)) {
1212 return tree.clone();
1213 }
1214 let tree = Rc::new(FaceTree::of(&self.faces));
1215 *kept = Some(tree.clone());
1216 tree
1217 }
1218
1219 fn sketches_under(&self, layer: &Layer<'_>) -> Vec<ElementHit> {
1222 let pointer = &layer.pointer;
1223 let shown = self.sketches.iter().filter(|s| !layer.hides(&s.name));
1224 let hits = shown.filter_map(|sketch| {
1225 let (t, p) = pointer.ray.intersect_uv_plane(&sketch.plane)?;
1226 let reach = pointer.reach_at(1.0, t);
1227 let in_region = sketch
1228 .regions
1229 .iter()
1230 .any(|loops| polygons_contain(loops, &p));
1231 let on_curve = || {
1232 sketch.curves.iter().any(|c| {
1233 c.polyline
1234 .array_windows()
1235 .any(|[a, b]| !p.distance_to_segment(a, b).definitely_greater(reach))
1236 })
1237 };
1238 (in_region || on_curve())
1239 .then(|| layer.hit(&sketch.target, drawn::SKETCH, "", pointer.ray.at(t), t))
1240 });
1241 hits.collect()
1242 }
1243
1244 fn datums_under(&self, layer: &Layer<'_>, extent: Extent) -> Vec<ElementHit> {
1249 let pointer = &layer.pointer;
1250 let Extent { center, size } = extent;
1251 let ray = &pointer.ray;
1252 let Ok(half) = size.div(Scalar::TWO) else {
1253 return Vec::new();
1254 };
1255 let shown = self.datums.iter().filter(|d| !layer.hides(&d.name));
1256 let hits = shown.filter_map(|d| {
1257 let f = &d.frame;
1258 let (origin, w) = (f.origin(), f.w());
1259 let t = match d.kind {
1260 DatumKind::Frame => None?,
1261 DatumKind::Point => {
1262 let (dist, t) = ray.distance_to_point(origin);
1263 pointer.within(dist, t, 1.0).then_some(t)?
1264 }
1265 DatumKind::Axis => {
1266 let mid = origin.add(&w.prod_scalar(center.sub(origin).prod_dot(w)));
1267 let reach = w.prod_scalar(size);
1268 let (dist, t) = ray.distance_to_segment(&mid.sub(&reach), &mid.add(&reach));
1269 pointer.within(dist, t, 1.0).then_some(t)?
1270 }
1271 DatumKind::Plane => {
1272 let (t, point) = ray.intersect_plane(origin, w)?;
1273 let d = point.sub(¢er);
1274 let inside = |axis: &Vector3| !d.prod_dot(axis).abs().definitely_greater(half);
1275 (inside(f.u()) && inside(f.v())).then_some(t)?
1276 }
1277 };
1278 Some(layer.hit(&self.datum_target, drawn::DATUM, &d.name, ray.at(t), t))
1279 });
1280 hits.collect()
1281 }
1282
1283 fn frame_parts_under(&self, layer: &Layer<'_>) -> [Vec<ElementHit>; 3] {
1290 let pointer = &layer.pointer;
1291 let ray = &pointer.ray;
1292 let frac = |size: Scalar, x: f64| size.mul(Scalar::from_f64(x));
1293 let hit = |name: &str, point: Vector3, t: Scalar| {
1294 layer.hit(&self.datum_target, drawn::DATUM, name, point, t)
1295 };
1296 let (mut balls, mut axes, mut planes) = (Vec::new(), Vec::new(), Vec::new());
1297 let frames =
1298 (self.datums.iter()).filter(|d| d.kind == DatumKind::Frame && !layer.hides(&d.name));
1299 for d in frames {
1300 let f = &d.frame;
1301 let origin = f.origin();
1302 let size = pointer.reach_at(FRAME, ray.closest_to_point(origin));
1303 let (dist, t) = ray.distance_to_point(origin);
1304 if !dist.definitely_greater(frac(size, 0.12)) {
1305 balls.push(hit(&d.name, *origin, t));
1306 }
1307 for (component, name) in &d.components {
1308 match *component {
1309 DatumComponent::Axis(axis) => {
1310 let dir = axis.of(f);
1311 let (a, b) = (
1312 origin.add(&dir.prod_scalar(frac(size, 0.1))),
1313 origin.add(&dir.prod_scalar(size)),
1314 );
1315 let (dist, t) = ray.distance_to_segment(&a, &b);
1316 if pointer.within(dist, t, 0.6) {
1317 axes.push(hit(name, b, t));
1318 }
1319 }
1320 DatumComponent::Plane(normal) => {
1321 let Some((t, point)) = ray.intersect_plane(origin, &normal.of(f)) else {
1322 continue;
1323 };
1324 let local = point.sub(origin);
1325 let in_square = (FrameAxis::ALL.iter())
1326 .filter(|&&other| other != normal)
1327 .all(|other| {
1328 let x = (local.prod_dot(&other.of(f)).div(size))
1329 .unwrap_or(Scalar::INFINITY);
1330 !x.sub(Scalar::from_f64(0.45))
1331 .abs()
1332 .definitely_greater(Scalar::from_f64(0.15))
1333 });
1334 if in_square {
1335 planes.push(hit(name, point, t));
1336 }
1337 }
1338 }
1339 }
1340 }
1341 [balls, axes, planes]
1342 }
1343}
1344
1345impl Default for PartView {
1346 fn default() -> Self {
1347 Self::new()
1348 }
1349}
1350
1351thread_local! {
1352 static PARTS_DRAWN: std::cell::Cell<usize> = const { std::cell::Cell::new(0) };
1353 static FACES_DRAWN: std::cell::Cell<usize> = const { std::cell::Cell::new(0) };
1354}
1355
1356pub fn faces_drawn() -> usize {
1360 FACES_DRAWN.get()
1361}
1362
1363pub fn parts_drawn() -> usize {
1367 PARTS_DRAWN.get()
1368}
1369
1370#[derive(Clone, Copy, Debug)]
1374pub struct Visible<'v> {
1375 pub view: &'v PartView,
1376 pub hidden: &'v [String],
1378}
1379
1380impl Scene for PartView {
1382 fn under(&self, pointer: &Pointer, accepts: &[String]) -> Vec<ElementHit> {
1383 PartView::under(self, pointer, accepts, &[])
1384 }
1385
1386 fn hit_instance(&self, name: &str, pointer: &Pointer) -> Option<Scalar> {
1387 self.pick_instance(name, pointer, &[])
1388 }
1389}
1390
1391impl<'v> Visible<'v> {
1392 pub fn part_to_drag(&self, pointer: &Pointer) -> Option<(&'v ViewInstance, Scalar)> {
1395 self.view.part_to_drag(pointer, self.hidden)
1396 }
1397}
1398
1399impl Scene for Visible<'_> {
1400 fn under(&self, pointer: &Pointer, accepts: &[String]) -> Vec<ElementHit> {
1401 self.view.under(pointer, accepts, self.hidden)
1402 }
1403
1404 fn hit_instance(&self, name: &str, pointer: &Pointer) -> Option<Scalar> {
1405 self.view.pick_instance(name, pointer, self.hidden)
1406 }
1407}
1408
1409fn nearest(hits: impl IntoIterator<Item = ElementHit>) -> Option<ElementHit> {
1411 hits.into_iter().min_by(|a, b| nearer(a.t, b.t))
1412}