geop_ops_model/
resolve.rs1use geop_core_geometry::shape::Plane;
5use geop_core_math::geop_error::{GeopError, GeopResult};
6use geop_core_topology::{Body, EdgeId, FaceId, ShellId, SolidId, VertexId};
7
8use super::NamedModel;
9use super::ids::RefId;
10
11impl NamedModel {
12 fn named<T>(
14 &self,
15 name: &str,
16 kind: &str,
17 extract: impl Fn(RefId) -> Option<T>,
18 ) -> GeopResult<T> {
19 let id = self.names.id_of(name).ok_or_else(|| {
20 let step = name.split_once(',').map_or(name, |(head, _)| head);
23 let step = step.split_once('(').map_or(step, |(_, id)| id);
24 let mut similar: Vec<&str> = self
25 .names()
26 .iter()
27 .map(|(_, n)| n)
28 .filter(|n| n.contains(step))
29 .collect();
30 similar.sort_unstable();
31 similar.truncate(12);
32 GeopError::new(format!(
33 "no entity is named {name:?} (names of {step:?}: {similar:?})"
34 ))
35 })?;
36 extract(id).ok_or_else(|| GeopError::new(format!("{name:?} names {id}, not a {kind}")))
37 }
38
39 pub fn vertex_id(&self, name: &str) -> GeopResult<VertexId> {
40 self.named(name, "vertex", |r| match r {
41 RefId::Vertex(id) => Some(id),
42 _ => None,
43 })
44 }
45
46 pub fn edge_id(&self, name: &str) -> GeopResult<EdgeId> {
47 self.named(name, "edge", |r| match r {
48 RefId::Edge(id) => Some(id),
49 _ => None,
50 })
51 }
52
53 pub fn face_id(&self, name: &str) -> GeopResult<FaceId> {
54 self.named(name, "face", |r| match r {
55 RefId::Face(id) => Some(id),
56 _ => None,
57 })
58 }
59
60 pub fn solid_id(&self, name: &str) -> GeopResult<SolidId> {
61 self.named(name, "solid", |r| match r {
62 RefId::Solid(id) => Some(id),
63 _ => None,
64 })
65 }
66
67 pub fn solid_of_face(&self, face: FaceId, why: &str) -> GeopResult<SolidId> {
70 match self.topology().body_of_face(face)? {
71 Body::Solid(solid) => Ok(solid),
72 Body::Sheet(_) => Err(GeopError::new(format!(
73 "face {:?} stands on its own: {why}",
74 self.name(face)?
75 ))),
76 }
77 }
78
79 pub fn solid_name_of_face(&self, face: FaceId, why: &str) -> GeopResult<String> {
81 let solid = self.solid_of_face(face, why)?;
82 Ok(self.name(solid)?.to_string())
83 }
84
85 pub fn sheet_of_face(&self, face: FaceId, why: &str) -> GeopResult<ShellId> {
88 match self.topology().body_of_face(face)? {
89 Body::Sheet(sheet) => Ok(sheet),
90 Body::Solid(_) => Err(GeopError::new(format!(
91 "face {:?} is a face of a solid, not one standing on its own: {why}",
92 self.name(face)?
93 ))),
94 }
95 }
96
97 pub fn plane_of_face(&self, face: FaceId, why: &str) -> GeopResult<Plane> {
100 match self.topology().get_face(face)?.surface.as_plane()? {
101 Some(plane) => Ok(plane),
102 None => Err(GeopError::new(format!(
103 "face {:?} is not planar: {why}",
104 self.name(face)?
105 ))),
106 }
107 }
108
109 pub fn solid_names(&self) -> Vec<String> {
111 self.topology()
113 .solids
114 .keys()
115 .filter_map(|&s| self.name_of(s).map(str::to_string))
116 .collect()
117 }
118
119 pub fn newest_solid(&self) -> Option<String> {
122 self.solid_names().pop()
123 }
124
125 pub fn sheet_face_names(&self) -> Vec<String> {
128 let model = self.topology();
129 model
130 .faces
131 .iter()
132 .filter(|(_, f)| {
133 model
134 .shells
135 .get(&f.shell)
136 .is_some_and(|s| s.solid.is_none())
137 })
138 .filter_map(|(&f, _)| self.name_of(f).map(str::to_string))
139 .collect()
140 }
141}