1use geop_core_math::{geop_error::GeopResult, primitives::FrameAxis};
13use geop_core_program::{element::ElementReference, program::Program};
14use geop_core_sketch::CurveId;
15use geop_ops_extrude_revolve::{Extent, Extents, ExtrudeArgs, Output, RevolveArgs, RevolveAxis};
16use geop_ops_model::Combine;
17use geop_ops_model::datums::{Datums, datums, origin_axis, origin_plane};
18use geop_ops_model::parameters::{
19 Material, Parameter, ParameterKind, Parameters, Row, set_parameters,
20};
21use geop_ops_model::selection::Selected;
22use geop_ops_model::sketch::{SketchPlane, sketch_element, whole_sketch};
23use geop_ops_reference_geometry::{AddDatumArgs, Construction};
24
25use super::{drawing::Drawing, tables::Table};
26
27pub const SIZE: &str = "size";
29
30pub fn size(table: Table) -> Parameter {
32 Parameter {
33 name: SIZE.into(),
34 kind: ParameterKind::Table {
35 columns: table.columns.iter().map(|c| c.to_string()).collect(),
36 rows: table
37 .rows
38 .into_iter()
39 .map(|(name, values)| Row { name, values })
40 .collect(),
41 selected: table.selected.into(),
42 },
43 }
44}
45
46pub fn family(material: &str, color: Option<&str>, values: Vec<Parameter>) -> Program {
49 let mut program = Program::new();
50 set_parameters(
51 &mut program,
52 Parameters {
53 material: Material::named(material),
54 color: color.map(Into::into),
55 values,
56 ..Parameters::default()
57 },
58 );
59 program
60}
61
62pub fn col(column: &str) -> String {
64 format!("{SIZE}.{column}")
65}
66
67pub fn profile_plane() -> SketchPlane {
70 SketchPlane::Datum(origin_plane(FrameAxis::X))
71}
72
73pub const BELOW: &str = "below";
75
76pub fn outline_plane() -> SketchPlane {
79 SketchPlane::Datum(origin_plane(FrameAxis::Z))
80}
81
82pub fn datum_plane(name: &str) -> SketchPlane {
84 SketchPlane::Datum(ElementReference::new(datums(), name))
85}
86
87pub fn datum(name: &str) -> Selected {
89 Selected::Datum(ElementReference::<Datums, _>::new(datums(), name))
90}
91
92pub fn swept(revolve: &str, sketch: &str, curve: CurveId) -> Vec<String> {
95 (0..4)
96 .map(|q| format!("revolve({revolve},{sketch},{curve},q{q})"))
97 .collect()
98}
99
100pub enum Around {
103 Line(CurveId),
104 ZAxis,
105}
106
107pub fn revolve(
111 program: &mut Program,
112 id: &str,
113 sketch: &str,
114 drawing: Drawing,
115 around: Around,
116 combine: Combine,
117) {
118 program.push(sketch, drawing.on(profile_plane()));
119 let axis = match around {
120 Around::Line(curve) => RevolveAxis::Sketch(sketch_element(sketch, curve)),
121 Around::ZAxis => RevolveAxis::Datum(origin_axis(FrameAxis::Z)),
122 };
123 program.push(
124 id,
125 RevolveArgs {
126 sketch: whole_sketch(sketch),
127 axis: Some(axis),
128 extent: Extents::blind(360.0),
129 output: Output::Solid(combine),
130 },
131 );
132}
133
134#[derive(Clone, Copy, PartialEq)]
137pub enum Through {
138 Up,
139 Both,
140}
141
142pub fn extrude(
146 program: &mut Program,
147 id: &str,
148 sketch: &str,
149 (drawing, plane): (Drawing, SketchPlane),
150 extent: Extents,
151 combine: Combine,
152) {
153 program.push(sketch, drawing.on(plane));
154 program.push(
155 id,
156 ExtrudeArgs {
157 sketch: whole_sketch(sketch),
158 extent,
159 output: Output::Solid(combine),
160 draft: 0.0,
161 },
162 );
163}
164
165pub fn cut_to(
169 program: &mut Program,
170 id: &str,
171 sketch: &str,
172 drawing: Drawing,
173 target: &str,
174 through: Through,
175) {
176 let plane = match through {
177 Through::Both => outline_plane(),
178 Through::Up => {
179 if program.index_of(BELOW).is_err() {
180 program.push(
181 BELOW,
182 AddDatumArgs {
183 selection: vec![datum(origin_plane(FrameAxis::Z).name())],
184 construction: Construction::Offset {
185 distance: (-1.0).into(),
186 },
187 },
188 );
189 }
190 datum_plane(BELOW)
191 }
192 };
193 let extent = Extents {
194 side1: Extent::ThroughAll,
195 symmetric: through == Through::Both,
196 side2: None,
197 reversed: false,
198 };
199 let combine = Combine::intersect(target);
200 extrude(program, id, sketch, (drawing, plane), extent, combine)
201}
202
203pub fn hexagon(drawing: &mut Drawing, across: &str) -> GeopResult<Vec<CurveId>> {
206 let flat = format!("({across}) / 2");
207 let half = format!("({across}) / (2 * sqrt(3))");
208 let corner = format!("({across}) / sqrt(3)");
209 let neg = |f: &str| format!("-{f}");
210 drawing.polygon(&[
211 [flat.clone(), neg(&half)],
212 [flat.clone(), half.clone()],
213 ["0".into(), corner.clone()],
214 [neg(&flat), half.clone()],
215 [neg(&flat), neg(&half)],
216 ["0".into(), neg(&corner)],
217 ])
218}
219
220pub fn axis_datum(program: &mut Program) {
223 program.push(
224 "axis",
225 AddDatumArgs {
226 selection: vec![datum(origin_axis(FrameAxis::Z).name())],
227 construction: Construction::AlongLine {},
228 },
229 );
230}
231
232pub fn plane_datum(program: &mut Program, id: &str, height: &str) {
236 offset_datum(program, id, origin_plane(FrameAxis::Z).name(), height);
237}
238
239pub fn offset_datum(program: &mut Program, id: &str, plane: &str, distance: &str) {
243 program.push(
244 id,
245 AddDatumArgs {
246 selection: vec![datum(plane)],
247 construction: Construction::Offset {
248 distance: distance.into(),
249 },
250 },
251 );
252}