1use crate::{
10 Circle, Curve, Edge, Face, Line, NamedModel, Point, Round, Vertex,
11 datums::{AnyDatum, Datums},
12 parameters::located,
13 sketch::PlacedSketch,
14};
15use geop_core_editor::one_of;
16use geop_core_geometry::{
17 nurb_curve::NurbCurve3D,
18 shape::{Arc, Axis},
19};
20use geop_core_math::{
21 geop_error::{GeopError, GeopResult},
22 primitives::{CoordinateSystem, DatumKind, Motion},
23 vector::Vector3,
24};
25use geop_core_program::{element::ElementReference, placed::InInstance, reader::Reader};
26
27one_of! {
28 pub enum Selected {
30 Vertex(ElementReference<NamedModel, Vertex>),
31 Edge(ElementReference<NamedModel, Edge>),
32 Face(ElementReference<NamedModel, Face>),
33 Datum(ElementReference<Datums, AnyDatum>),
34 SketchPoint(ElementReference<PlacedSketch, Point>),
35 SketchCurve(ElementReference<PlacedSketch, Curve>),
36 }
37}
38
39#[derive(Clone, Copy, Debug, PartialEq, Eq)]
41pub enum Role {
42 Point,
43 Line,
44 Plane,
45 Curve,
47 Circle,
49 Round,
52}
53
54impl Role {
55 pub const ALL: [Role; 6] = [
56 Role::Point,
57 Role::Line,
58 Role::Plane,
59 Role::Curve,
60 Role::Circle,
61 Role::Round,
62 ];
63
64 pub fn name(self) -> &'static str {
66 match self {
67 Role::Point => "point",
68 Role::Line => "line",
69 Role::Plane => "plane",
70 Role::Curve => "curve",
71 Role::Circle => "circle",
72 Role::Round => "round",
73 }
74 }
75
76 pub fn describe(self) -> &'static str {
78 match self {
79 Role::Point => "a point",
80 Role::Line => "a line",
81 Role::Plane => "a plane",
82 Role::Curve => "an edge or a curve",
83 Role::Circle => "a circle or an arc",
84 Role::Round => "something round",
85 }
86 }
87}
88
89#[derive(Clone, Debug, Default)]
93pub struct Shape {
94 pub point: Option<Vector3>,
95 pub line: Option<Axis>,
97 pub plane: Option<CoordinateSystem>,
99 pub arc: Option<Arc>,
100 pub round: Option<Axis>,
102 pub curve: Option<NurbCurve3D>,
104 pub frame: Option<CoordinateSystem>,
106}
107
108impl Shape {
109 pub fn fits(&self, role: Role) -> bool {
111 match role {
112 Role::Point => self.point.is_some(),
113 Role::Line => self.line.is_some(),
114 Role::Plane => self.plane.is_some(),
115 Role::Curve => self.curve.is_some(),
116 Role::Circle => self.arc.is_some(),
117 Role::Round => self.round.is_some(),
118 }
119 }
120
121 pub fn roles(&self) -> Vec<Role> {
123 Role::ALL
124 .into_iter()
125 .filter(|&role| self.fits(role))
126 .collect()
127 }
128
129 pub fn transform(&self, motion: &Motion) -> GeopResult<Self> {
131 let frame = |frame: &Option<CoordinateSystem>| {
132 frame.as_ref().map(|f| motion.apply_frame(f)).transpose()
133 };
134 Ok(Shape {
135 point: self.point.map(|p| motion.apply(&p)),
136 line: self.line.as_ref().map(|l| l.transform(motion)),
137 plane: frame(&self.plane)?,
138 arc: self.arc.as_ref().map(|a| a.transform(motion)),
139 round: self.round.as_ref().map(|r| r.transform(motion)),
140 curve: self.curve.as_ref().map(|c| c.transform(motion)),
141 frame: frame(&self.frame)?,
142 })
143 }
144
145 fn of_curve(curve: NurbCurve3D) -> GeopResult<Self> {
147 let arc = curve.as_arc()?;
148 Ok(Shape {
149 line: curve.as_line()?,
150 round: arc.as_ref().map(|arc| arc.circle.axis()),
151 arc,
152 curve: Some(curve),
153 ..Shape::default()
154 })
155 }
156}
157
158impl Selected {
159 pub fn shape(&self, reader: &Reader) -> GeopResult<Shape> {
162 let InInstance { element, instance } = self.shape_in_instance(reader)?;
163 match instance.is_empty() {
164 true => Ok(element),
165 false => element.transform(&located(reader, &instance)?.motion()),
166 }
167 }
168
169 pub fn shape_in_instance(&self, reader: &Reader) -> GeopResult<InInstance<Shape>> {
173 let instance = self.instance();
174 let element = match instance.is_empty() {
175 true => self.own_shape(reader)?,
176 false => self.local().own_shape(&reader.placed_part(instance)?)?,
177 };
178 Ok(InInstance {
179 element,
180 instance: instance.to_string(),
181 })
182 }
183
184 fn own_shape(&self, reader: &Reader) -> GeopResult<Shape> {
186 Ok(match self {
187 Selected::Vertex(vertex) => {
188 let found = reader.retrieve_element(vertex)?;
189 Shape {
190 point: Some(found.model.topology().get_vertex(found.id)?.point),
191 ..Shape::default()
192 }
193 }
194 Selected::Edge(edge) => {
195 let found = reader.retrieve_element(edge)?;
196 Shape::of_curve(found.model.topology().get_edge(found.id)?.curve.clone())?
197 }
198 Selected::Face(face) => {
199 let found = reader.retrieve_element(face)?;
200 let surface = &found.model.topology().get_face(found.id)?.surface;
201 Shape {
202 plane: found.model.frame_of_face(found.id).ok(),
203 round: surface.axis_of_revolution()?,
204 ..Shape::default()
205 }
206 }
207 Selected::Datum(datum) => {
208 let datum = reader.retrieve_element(datum)?;
209 let frame = datum.frame;
210 let mut shape = Shape::default();
211 match datum.kind {
212 DatumKind::Point | DatumKind::Frame => shape.point = Some(*frame.origin()),
213 DatumKind::Axis => {
214 shape.line = Some(Axis::try_new(*frame.origin(), *frame.w())?)
215 }
216 DatumKind::Plane => shape.plane = Some(frame.clone()),
217 }
218 shape.frame = Some(frame);
219 shape
220 }
221 Selected::SketchPoint(point) => Shape {
222 point: Some(reader.retrieve_element(point)?),
223 ..Shape::default()
224 },
225 Selected::SketchCurve(curve) => {
226 let chain = reader.retrieve_element(curve)?;
227 let [one] = <[NurbCurve3D; 1]>::try_from(chain.curves).map_err(|_| {
228 GeopError::new(format!("the curve {:?} is more than one", curve.name()))
229 })?;
230 let mut shape = Shape::of_curve(one)?;
233 shape.line = shape
234 .line
235 .or_else(|| reader.retrieve_element(&as_kind::<Line>(curve)).ok());
236 shape.arc = shape
237 .arc
238 .or_else(|| reader.retrieve_element(&as_kind::<Circle>(curve)).ok());
239 shape.round = (shape.round)
240 .or_else(|| reader.retrieve_element(&as_kind::<Round>(curve)).ok());
241 shape
242 }
243 })
244 }
245}
246
247fn as_kind<K>(curve: &ElementReference<PlacedSketch, Curve>) -> ElementReference<PlacedSketch, K> {
249 ElementReference::new(curve.target().clone(), curve.name())
250}