geop_ops_model/spacing/
references.rs1use std::collections::BTreeSet;
8
9use geop_core_editor::one_of;
10use geop_core_geometry::shape::Axis;
11use geop_core_math::{
12 geop_error::{GeopError, GeopResult, WithContext},
13 primitives::Motion,
14 vector::Vector3,
15 with_context,
16};
17use geop_core_program::{element::ElementReference, placed::InInstance, reader::Reader};
18use geop_core_sketch::CurveKind;
19
20use crate::{
21 Line, NamedModel, Plane, Point, Round,
22 datums::Datums,
23 parameters::located,
24 sketch::{PlacedSketch, SketchRef},
25};
26
27fn motion_of<T>(reader: &Reader, placed: &InInstance<T>) -> GeopResult<Motion> {
30 Ok(located(reader, &placed.instance)?.motion())
31}
32
33one_of! {
34 pub enum TurnAxis -> Axis {
39 Edge(ElementReference<NamedModel, Line>),
40 Round(ElementReference<NamedModel, Round>),
41 Datum(ElementReference<Datums, Line>),
42 Sketch(ElementReference<PlacedSketch, Line>),
43 SketchRound(ElementReference<PlacedSketch, Round>),
44 }
45}
46
47impl TurnAxis {
48 pub fn placed(&self, reader: &Reader) -> GeopResult<Axis> {
51 let axis = self.resolve_placed(reader)?;
52 Ok(axis.element.transform(&motion_of(reader, &axis)?))
53 }
54}
55
56one_of! {
57 pub enum PatternDirection {
61 Edge(ElementReference<NamedModel, Line>),
62 Face(ElementReference<NamedModel, Plane>),
63 Datum(ElementReference<Datums, Line>),
64 DatumPlane(ElementReference<Datums, Plane>),
65 Sketch(ElementReference<PlacedSketch, Line>),
66 SketchPlane(ElementReference<PlacedSketch, Plane>),
67 }
68}
69
70impl PatternDirection {
71 pub fn direction(&self, reader: &Reader) -> GeopResult<Vector3> {
75 let line = |placed: InInstance<Axis>| -> GeopResult<Vector3> {
76 Ok(motion_of(reader, &placed)?.rotate(&placed.element.direction))
77 };
78 let plane = |placed: InInstance<_>| -> GeopResult<Vector3> {
79 let motion = motion_of(reader, &placed)?;
80 let frame: geop_core_math::primitives::CoordinateSystem = placed.element;
81 Ok(motion.rotate(frame.w()))
82 };
83 match self {
84 PatternDirection::Edge(r) => line(reader.retrieve_placed(r)?),
85 PatternDirection::Datum(r) => line(reader.retrieve_placed(r)?),
86 PatternDirection::Sketch(r) => line(reader.retrieve_placed(r)?),
87 PatternDirection::Face(r) => plane(reader.retrieve_placed(r)?),
88 PatternDirection::DatumPlane(r) => plane(reader.retrieve_placed(r)?),
89 PatternDirection::SketchPlane(r) => plane(reader.retrieve_placed(r)?),
90 }
91 }
92}
93
94one_of! {
95 pub enum PointsRef {
99 Vertex(ElementReference<NamedModel, Point>),
100 Datum(ElementReference<Datums, Point>),
101 SketchPoint(ElementReference<PlacedSketch, Point>),
102 Sketch(SketchRef),
103 }
104}
105
106pub fn resolve_points(reader: &Reader, refs: &[PointsRef]) -> GeopResult<Vec<(String, Vector3)>> {
113 let mut found = Vec::new();
114 for point in refs {
115 let ctx = with_context!("the point {point:?}");
116 match point {
117 PointsRef::Sketch(sketch) => {
118 let placed = reader.retrieve_placed(sketch).with_context(ctx)?;
119 let motion = motion_of(reader, &placed).with_context(ctx)?;
120 let (name, sketch) = (&placed.element.name, &placed.element.sketch);
121 let on_curves: BTreeSet<_> = sketch
122 .curves
123 .values()
124 .filter(|c| !matches!(c.kind, CurveKind::Circle { .. }))
125 .flat_map(|c| c.points())
126 .collect();
127 let geometry = sketch.enclose().with_context(ctx)?;
128 let before = found.len();
129 for (&id, p) in &sketch.points {
130 if !p.fixed && !on_curves.contains(&id) {
131 let at = placed.element.plane.uv_to_xyz(&geometry.points[&id]);
132 found.push((format!("{name},{id}"), motion.apply(&at)));
133 }
134 }
135 if found.len() == before {
136 return Err(GeopError::new(format!(
137 "sketch {name:?} has no points of its own: place points in it, or pick them one by one"
138 )));
139 }
140 }
141 PointsRef::SketchPoint(at) => {
142 let whole = SketchRef::whole(at.target().clone());
143 let sketch = &reader
144 .retrieve_placed(&whole)
145 .with_context(ctx)?
146 .element
147 .name;
148 let p = reader.retrieve_placed(at).with_context(ctx)?;
149 let motion = motion_of(reader, &p).with_context(ctx)?;
150 found.push((format!("{sketch},{}", at.name()), motion.apply(&p.element)));
151 }
152 PointsRef::Vertex(at) => {
153 let p = reader.retrieve_placed(at).with_context(ctx)?;
154 let motion = motion_of(reader, &p).with_context(ctx)?;
155 found.push((at.name().to_string(), motion.apply(&p.element)));
156 }
157 PointsRef::Datum(at) => {
158 let p = reader.retrieve_placed(at).with_context(ctx)?;
159 let motion = motion_of(reader, &p).with_context(ctx)?;
160 found.push((at.name().to_string(), motion.apply(&p.element)));
161 }
162 }
163 }
164 let mut seen = BTreeSet::new();
165 for (scope, _) in &found {
166 if !seen.insert(scope) {
167 return Err(GeopError::new(format!("the point {scope} is picked twice")));
168 }
169 }
170 Ok(found)
171}