1use std::collections::BTreeMap;
10
11use geop_core_editor::registry::ExampleSet;
12use geop_core_math::{geop_error::GeopResult, primitives::FrameAxis, vector::Vector3};
13use geop_core_program::{
14 element::ElementReference, numeric::NumericInput, operation_registry::OperationRegistry,
15 part::Part, program::Program, runner::Runner,
16};
17use geop_core_sketch::CurveId;
18use geop_lib_sweep::Orientation;
19use geop_ops_model::datums::origin_plane;
20use geop_ops_model::parameters::{
21 DefineParameters, LookupTable, Material, Parameter, ParameterKind, Parameters, PartProperties,
22 Row, set_parameters,
23};
24use geop_ops_model::sketch::{
25 Constraint, Sketch, SketchPlane,
26 figures::{circle, n, polygon, rectangle, rectangle_outline, solved},
27 sketch, sketch_element, whole_sketch,
28};
29use geop_ops_model::sketch3d::{Constraint3d, Sketch3d, sketch3d_path};
30use geop_ops_model::{Combine, element};
31use geop_ops_sketch::{
32 AddSketch, AddSketchArgs,
33 references::{Projected, Reference, Source},
34};
35use geop_ops_sketch3d::AddSketch3dArgs;
36
37use crate::{
38 Extent, Extents, Extrude, ExtrudeArgs, Output, PathRef, RevolveArgs, RevolveAxis, SweepArgs,
39};
40
41pub fn set() -> ExampleSet {
43 ExampleSet {
44 programs: vec![
45 ("box_with_drill_hole", box_with_drill_hole),
46 ("bracket", bracket),
47 ("cross_drilled_shaft", cross_drilled_shaft),
48 ("handle_with_hole", handle_with_hole),
49 ("luggage_tag", luggage_tag),
50 ("revolved_cone_on_box", revolved_cone_on_box),
51 ("parametric_plate", parametric_plate),
52 ("pipe", pipe),
53 ("horn", horn),
54 ("motor_flange", motor_flange),
55 ("edge_part", edge_part),
56 ("name_plate", name_plate),
57 ("coil_spring", coil_spring),
58 ("square_thread", square_thread),
59 ],
60 workspaces: Vec::new(),
61 }
62}
63
64fn built(program: &Program) -> GeopResult<Part> {
67 let operations = (OperationRegistry::default())
68 .with(DefineParameters)?
69 .with(LookupTable)?
70 .with(PartProperties)?
71 .with(AddSketch)?
72 .with(Extrude)?;
73 let mut part = Part::default();
74 program.run(&Runner::new(operations), &mut part)?;
75 Ok(part)
76}
77
78fn on_face(name: impl Into<String>) -> SketchPlane {
80 SketchPlane::Face(element(name))
81}
82
83fn on_origin(normal: FrameAxis) -> SketchPlane {
85 SketchPlane::Datum(origin_plane(normal))
86}
87
88pub fn coil_spring() -> Program {
92 let mut program = Program::new();
93 program.push(
94 "section",
95 AddSketchArgs::on(
96 on_origin(FrameAxis::Y),
97 rectangle_outline(9.0, -1.0, 11.0, 1.0),
98 ),
99 );
100 let mut route = Sketch3d::new();
101 let at = |p: [f64; 3]| Vector3::from_array(p.map(n));
102 let start = route.add_point(at([10.0, 0.0, 0.0]));
103 let base = route.add_point(at([0.0, 0.0, 0.0]));
104 let top = route.add_point(at([0.0, 0.0, 20.0]));
105 route
106 .add_helix(start, base, top, n(3.0), false)
107 .expect("the helix has an axis and a start off it");
108 program.push(
109 "route",
110 AddSketch3dArgs {
111 sketch: route,
112 references: Vec::new(),
113 },
114 );
115 program.push(
116 "coil",
117 SweepArgs {
118 profile: whole_sketch("section"),
119 path: Some(PathRef::Sketch3d(sketch3d_path("route"))),
120 orientation: Orientation::FollowPath,
121 twist: 0.0,
122 end_scale: 1.0,
123 rails: Vec::new(),
124 output: Output::Solid(Combine::NewBody),
125 },
126 );
127 program
128}
129
130pub fn name_plate() -> Program {
137 let mut program = Program::new();
138
139 let mut outline = Sketch::new();
140 rectangle(&mut outline, [0.0, 0.0], 40.0, 14.0);
141 program.push(
142 "outline",
143 AddSketchArgs::on(on_origin(FrameAxis::Z), solved(outline)),
144 );
145 program.push(
146 "plate",
147 ExtrudeArgs {
148 sketch: whole_sketch("outline"),
149 extent: Extents::blind(3.0),
150 output: Output::Solid(Combine::NewBody),
151 draft: 0.0,
152 },
153 );
154
155 let mut lettering = Sketch::new();
156 let anchor = lettering.new_point_at([7.0, 3.5]);
157 lettering.constrain(Constraint::Fix {
158 point: anchor,
159 x: n(7.0),
160 y: n(3.5),
161 });
162 lettering.add_text(anchor, "GEOP", n(7.0), n(0.0));
163 program.push(
164 "lettering",
165 AddSketchArgs::on(on_face("extrude(plate,end)"), solved(lettering)),
166 );
167 program.push(
168 "letters",
169 ExtrudeArgs {
170 sketch: whole_sketch("lettering"),
171 extent: Extents::blind(1.0),
172 output: Output::Solid(Combine::join("extrude(plate)")),
173 draft: 0.0,
174 },
175 );
176 program
177}
178
179pub fn box_with_drill_hole() -> Program {
184 let mut program = Program::new();
185
186 let mut outline = Sketch::new();
187 rectangle(&mut outline, [0.0, 0.0], 2.0, 2.0);
188 program.push(
189 "outline",
190 AddSketchArgs::on(on_origin(FrameAxis::Z), solved(outline)),
191 );
192 program.push(
193 "box",
194 ExtrudeArgs {
195 sketch: whole_sketch("outline"),
196 extent: Extents::blind(1.0),
197 output: Output::Solid(Combine::NewBody),
198 draft: 0.0,
199 },
200 );
201
202 let mut hole = Sketch::new();
203 circle(&mut hole, [1.0, 1.0], 0.4);
204 program.push(
205 "hole_sketch",
206 AddSketchArgs::on(on_face("extrude(box,end)"), solved(hole)),
207 );
208 program.push(
209 "hole",
210 ExtrudeArgs {
211 sketch: whole_sketch("hole_sketch"),
212 extent: Extents::blind(-0.5),
213 output: Output::Solid(Combine::cut("extrude(box)")),
214 draft: 0.0,
215 },
216 );
217 program
218}
219
220pub fn bracket() -> Program {
228 let mut program = Program::new();
229
230 let mut outline = Sketch::new();
231 rectangle(&mut outline, [0.0, 0.0], 40.0, 40.0);
232 program.push(
233 "outline",
234 AddSketchArgs::on(on_origin(FrameAxis::Z), solved(outline)),
235 );
236 program.push(
237 "block",
238 ExtrudeArgs {
239 sketch: whole_sketch("outline"),
240 extent: Extents::blind(10.0),
241 output: Output::Solid(Combine::NewBody),
242 draft: 0.0,
243 },
244 );
245
246 let mut hole = Sketch::new();
247 circle(&mut hole, [20.0, 20.0], 3.0);
248 program.push(
249 "hole_sketch",
250 AddSketchArgs::on(on_face("extrude(block,end)"), solved(hole)),
251 );
252 program.push(
253 "hole",
254 ExtrudeArgs {
255 sketch: whole_sketch("hole_sketch"),
256 extent: Extents::blind(-10.0),
257 output: Output::Solid(Combine::cut("extrude(block)")),
258 draft: 0.0,
259 },
260 );
261 program
262}
263
264pub fn cross_drilled_shaft() -> Program {
270 let mut program = Program::new();
271
272 let mut section = Sketch::new();
274 let (p, l) = polygon(
275 &mut section,
276 &[
277 [0.0, 0.0],
278 [1.0, 0.0],
279 [1.0, 1.0],
280 [0.6, 1.0],
281 [0.6, 3.0],
282 [0.0, 3.0],
283 ],
284 );
285 let axis = l[5];
286 section.constrain(Constraint::Fix {
287 point: p[0],
288 x: n(0.0),
289 y: n(0.0),
290 });
291 section.constrain(Constraint::Vertical { line: axis });
292 for (line, horizontal) in [
293 (l[0], true),
294 (l[1], false),
295 (l[2], true),
296 (l[3], false),
297 (l[4], true),
298 ] {
299 section.constrain(if horizontal {
300 Constraint::Horizontal { line }
301 } else {
302 Constraint::Vertical { line }
303 });
304 }
305 section.constrain(Constraint::Length {
306 curve: l[0],
307 value: n(1.0),
308 });
309 section.constrain(Constraint::Length {
310 curve: l[1],
311 value: n(1.0),
312 });
313 section.constrain(Constraint::Length {
314 curve: l[3],
315 value: n(2.0),
316 });
317 section.constrain(Constraint::Length {
318 curve: l[4],
319 value: n(0.6),
320 });
321 program.push(
322 "section",
323 AddSketchArgs::on(on_origin(FrameAxis::X), solved(section)),
324 );
325 program.push(
326 "shaft",
327 RevolveArgs {
328 sketch: whole_sketch("section"),
329 axis: Some(RevolveAxis::Sketch(sketch_element("section", axis))),
330 extent: Extents::blind(360.0),
331 output: Output::Solid(Combine::NewBody),
332 },
333 );
334
335 let mut bore = Sketch::new();
338 circle(&mut bore, [0.0, -2.2], 0.25);
339 program.push(
340 "bore_sketch",
341 AddSketchArgs::on(on_origin(FrameAxis::Y), solved(bore)),
342 );
343 program.push(
344 "bore",
345 ExtrudeArgs {
346 sketch: whole_sketch("bore_sketch"),
347 extent: Extents {
348 side1: Extent::blind(3.0),
349 symmetric: true,
350 side2: None,
351 reversed: false,
352 },
353 output: Output::Solid(Combine::cut("revolve(shaft)")),
354 draft: 0.0,
355 },
356 );
357 program
358}
359
360pub fn handle_with_hole() -> Program {
373 let mut program = Program::new();
374
375 let mut outline = Sketch::new();
376 let outer_points = [
377 (0.01007682018456503, 0.8939399106232252),
378 (-0.9693901017551558, 0.8213868052943569),
379 (-1.00566665441959, 0.3175457960661055),
380 (-0.9452057333121998, -0.3555857922628385),
381 (0.09472210973491128, -0.9481028191152622),
382 (0.695300592734987, -0.3878316168534466),
383 (1.384555093359235, -0.4523232660346628),
384 (1.6233271012047248, -0.9224957048864859),
385 (1.9214381194506664, 0.15401630544608172),
386 (1.2092840203075834, 0.8578895429712221),
387 ]
388 .map(|(x, y)| outline.add_point(n(x), n(y)));
389 let mut outer_loop = outer_points.to_vec();
390 outer_loop.push(outer_points[0]);
391 outline.add_spline(outer_loop);
392
393 let inner_points = [
394 (0.27854547786607586, 0.568500810276078),
395 (-0.3241022513094386, 0.561767316095346),
396 (-0.3645032163938306, 0.00962079327532167),
397 (0.03950643445008967, -0.4246895813818926),
398 (0.507484280010964, -0.11831559615858644),
399 (0.8643594715897602, 0.12072344725739975),
400 (1.1202322504575766, -0.1452495728815144),
401 (1.2919363520662426, 0.18805838906471978),
402 (1.0427970673791584, 0.470865144655464),
403 ]
404 .map(|(x, y)| outline.add_point(n(x), n(y)));
405 let mut inner_loop = inner_points.to_vec();
406 inner_loop.push(inner_points[0]);
407 outline.add_spline(inner_loop);
408
409 program.push(
410 "outline",
411 AddSketchArgs::on(on_origin(FrameAxis::Z), solved(outline)),
412 );
413 program.push(
414 "handle",
415 ExtrudeArgs {
416 sketch: whole_sketch("outline"),
417 extent: Extents::blind(1.0),
418 output: Output::Solid(Combine::NewBody),
419 draft: 0.0,
420 },
421 );
422
423 let mut hole = Sketch::new();
424 let center = hole.add_point(n(0.32989396295411244), n(-0.5632891678453777));
425 hole.add_circle(center, n(0.31727744879927977));
426 program.push(
427 "hole_sketch",
428 AddSketchArgs::on(on_origin(FrameAxis::Y), solved(hole)),
429 );
430 program.push(
431 "hole",
432 ExtrudeArgs {
433 sketch: whole_sketch("hole_sketch"),
434 extent: Extents {
435 side1: Extent::blind(2.44),
436 symmetric: true,
437 side2: None,
438 reversed: false,
439 },
440 output: Output::Solid(Combine::cut("extrude(handle)")),
441 draft: 0.0,
442 },
443 );
444 program
445}
446
447pub fn luggage_tag() -> Program {
452 let mut program = Program::new();
453
454 let mut outline = Sketch::new();
455 let p0 = outline.add_point(n(-0.7051397478635735), n(0.7809633733011653));
456 let p1 = outline.add_point(n(-0.7051397478646341), n(-0.6729821470985564));
457 let p4 = outline.add_point(n(0.695311597099524), n(-0.6729821470973941));
458 let p7 = outline.add_point(n(0.695311597101934), n(0.7809633732995341));
459 let left = outline.add_line(p0, p1);
460 let bottom = outline.add_line(p1, p4);
461 let right = outline.add_line(p4, p7);
462 let top = outline.add_arc(p7, p0, n(std::f64::consts::PI));
463 outline.constrain(Constraint::Vertical { line: left });
464 outline.constrain(Constraint::Horizontal { line: bottom });
465 outline.constrain(Constraint::Vertical { line: right });
466 outline.constrain(Constraint::Tangent { a: top, b: right });
467 outline.constrain(Constraint::Tangent { a: top, b: left });
468
469 let hole_center = outline.add_point(n(-0.004914075380876311), n(0.7809633733016882));
470 let hole = outline.add_circle(hole_center, n(0.30711303824557856));
471 outline.constrain(Constraint::Concentric { a: hole, b: top });
472
473 let w_tl = outline.add_point(n(-0.5551397478558091), n(0.08482972707824256));
474 let w_tr = outline.add_point(n(0.5453115971039223), n(0.08482972707824256));
475 let w_br = outline.add_point(n(0.5453115971014348), n(-0.5229821471055477));
476 let w_bl = outline.add_point(n(-0.5551397478598076), n(-0.5229821471049918));
477 let w_top = outline.add_line(w_tl, w_tr);
478 let w_right = outline.add_line(w_tr, w_br);
479 let w_bottom = outline.add_line(w_br, w_bl);
480 let w_left = outline.add_line(w_bl, w_tl);
481 outline.constrain(Constraint::Horizontal { line: w_top });
482 outline.constrain(Constraint::Vertical { line: w_right });
483 outline.constrain(Constraint::Horizontal { line: w_bottom });
484 outline.constrain(Constraint::Vertical { line: w_left });
485 outline.constrain(Constraint::PointLineDistance {
486 point: w_br,
487 line: right,
488 value: n(0.15),
489 });
490 outline.constrain(Constraint::PointLineDistance {
491 point: w_bl,
492 line: left,
493 value: n(0.15),
494 });
495 outline.constrain(Constraint::PointLineDistance {
496 point: w_br,
497 line: bottom,
498 value: n(0.15),
499 });
500
501 program.push(
502 "outline",
503 AddSketchArgs::on(on_origin(FrameAxis::Z), solved(outline)),
504 );
505 program.push(
506 "tag",
507 ExtrudeArgs {
508 sketch: whole_sketch("outline"),
509 extent: Extents {
510 side1: Extent::blind(1.0 / 3.0),
511 symmetric: true,
512 side2: None,
513 reversed: false,
514 },
515 output: Output::Solid(Combine::NewBody),
516 draft: 0.0,
517 },
518 );
519 program
520}
521
522pub fn revolved_cone_on_box() -> Program {
533 let mut program = Program::new();
534
535 let mut outline = Sketch::new();
536 let p0 = outline.add_point(n(-2.046526714311965), n(1.182776884816516));
537 let p1 = outline.add_point(n(2.2456482324612383), n(-1.2774916901086213));
538 let p2 = outline.add_point(n(2.2456482324612383), n(1.182776884816516));
539 let p3 = outline.add_point(n(-2.046526714311965), n(-1.2774916901086213));
540 let top = outline.add_line(p0, p2);
541 outline.constrain(Constraint::Horizontal { line: top });
542 let right = outline.add_line(p2, p1);
543 outline.constrain(Constraint::Vertical { line: right });
544 let bottom = outline.add_line(p1, p3);
545 outline.constrain(Constraint::Horizontal { line: bottom });
546 let left = outline.add_line(p3, p0);
547 outline.constrain(Constraint::Vertical { line: left });
548 let center = outline.add_point(n(-0.6692695471128323), n(0.04905776553659026));
549 outline.add_circle(center, n(0.771466957205246));
550 program.push(
551 "sketch1",
552 AddSketchArgs::on(on_origin(FrameAxis::Z), outline),
553 );
554 program.push(
555 "extrude1",
556 ExtrudeArgs {
557 sketch: whole_sketch("sketch1"),
558 extent: Extents::blind(1.8900000000000001),
559 output: Output::Solid(Combine::NewBody),
560 draft: 0.0,
561 },
562 );
563
564 let mut triangle = Sketch::new();
565 let q0 = triangle.add_point(n(-0.2654953575323612), n(1.4039697276195047));
566 let q1 = triangle.add_point(n(-0.8683910652620968), n(0.8073854454124275));
567 let axis = triangle.add_line(q0, q1);
568 let q3 = triangle.add_point(n(1.9210929721682684), n(0.8073854454124275));
569 let base = triangle.add_line(q1, q3);
570 triangle.constrain(Constraint::Horizontal { line: base });
571 triangle.add_line(q3, q0);
572 program.push(
573 "sketch2",
574 AddSketchArgs::on(
575 on_face(format!("extrude(extrude1,sketch1,{right})")),
576 triangle,
577 ),
578 );
579 program.push(
580 "revolve1",
581 RevolveArgs {
582 sketch: whole_sketch("sketch2"),
583 axis: Some(RevolveAxis::Sketch(sketch_element("sketch2", axis))),
584 extent: Extents::blind(360.0),
585 output: Output::Solid(Combine::join("extrude(extrude1)")),
586 },
587 );
588 program
589}
590
591pub fn parametric_plate() -> Program {
599 let mut program = Program::new();
600 set_parameters(
601 &mut program,
602 Parameters {
603 title: None,
604 designation: None,
605 color: Some("#d0893e".into()),
606 material: Material::named("Aluminium 6061"),
607 values: vec![
608 Parameter::number("width", "4", 1.0, 10.0),
609 Parameter::number("depth", "width / 2", 0.5, 10.0),
610 Parameter {
611 name: "screw".into(),
612 kind: ParameterKind::Table {
613 columns: vec!["clearance".into(), "head".into()],
614 rows: [
615 ("M3", 0.34, 0.6),
616 ("M4", 0.45, 0.8),
617 ("M5", 0.55, 1.0),
618 ("M6", 0.66, 1.2),
619 ]
620 .map(|(name, clearance, head)| Row {
621 name: name.into(),
622 values: vec![clearance, head],
623 })
624 .to_vec(),
625 selected: "M4".into(),
626 },
627 },
628 Parameter::number("thickness", "0.5", 0.1, 2.0),
629 ],
630 },
631 );
632
633 let mut outline = Sketch::new();
634 let lines = rectangle(&mut outline, [0.0, 0.0], 4.0, 2.0);
635 let length = |line: CurveId| {
636 outline
637 .constraints
638 .iter()
639 .find(|(_, c)| matches!(c, Constraint::Length { curve, .. } if *curve == line))
640 .map(|(&id, _)| id)
641 .expect("the rectangle's lengths")
642 };
643 let formulas = BTreeMap::from([
644 (length(lines[0]), NumericInput::from("width")),
645 (length(lines[1]), NumericInput::from("depth")),
646 ]);
647 program.push(
648 "outline",
649 AddSketchArgs {
650 formulas,
651 ..AddSketchArgs::on(on_origin(FrameAxis::Z), solved(outline))
652 },
653 );
654 program.push(
655 "plate",
656 ExtrudeArgs {
657 sketch: whole_sketch("outline"),
658 extent: Extents::blind("thickness"),
659 output: Output::Solid(Combine::NewBody),
660 draft: 0.0,
661 },
662 );
663
664 let mut hole = Sketch::new();
667 let top = "extrude(plate,end)";
668 let mut projection = Reference::new(Source::Projection {
669 entity: Projected::Face(element(top)),
670 });
671 let part = built(&program).expect("the plate builds");
672 let reader = part.current();
673 let plane = (on_face(top).resolve(&reader)).expect("the top is planar");
674 projection
675 .update(&mut hole, &reader, &plane)
676 .expect("the top projects");
677 let corner = |p: &str| projection.points[&format!("extrude(plate,outline,{p},end)")];
678 let diagonal = hole.add_line(corner("p0"), corner("p2"));
679 hole.set_construction(diagonal, true);
680 let center = hole.add_point(n(2.0), n(1.0));
681 let circle = hole.add_circle(center, n(0.2));
682 hole.constrain(Constraint::Midpoint {
683 point: center,
684 curve: diagonal,
685 });
686 let diameter = hole.constrain(Constraint::Diameter {
687 curve: circle,
688 value: n(0.45),
689 });
690 program.push(
691 "hole_sketch",
692 AddSketchArgs {
693 references: vec![projection],
694 formulas: BTreeMap::from([(diameter, NumericInput::from("screw.clearance"))]),
695 ..AddSketchArgs::on(on_face(top), solved(hole))
696 },
697 );
698 program.push(
699 "hole",
700 ExtrudeArgs {
701 sketch: whole_sketch("hole_sketch"),
702 extent: Extents::blind(-0.3),
703 output: Output::Solid(Combine::cut("extrude(plate)")),
704 draft: 0.0,
705 },
706 );
707 program
708}
709
710pub fn pipe_route(bend: f64) -> Sketch3d {
715 let mut s = Sketch3d::new();
716 let (r, h) = (bend, std::f64::consts::FRAC_1_SQRT_2);
717 let v = |x: f64, y: f64, z: f64| Vector3::from_array([x, y, z].map(n));
718 let p = [
719 s.add_point(v(0.0, 0.0, 0.0)),
720 s.add_point(v(4.0 - r, 0.0, 0.0)),
721 s.add_point(v(4.0 - r + r * h, r - r * h, 0.0)),
722 s.add_point(v(4.0, r, 0.0)),
723 s.add_point(v(4.0, 4.0 - r, 0.0)),
724 s.add_point(v(4.0, 4.0 - r + r * h, r - r * h)),
725 s.add_point(v(4.0, 4.0, r)),
726 s.add_point(v(4.0, 4.0, 4.0)),
727 ];
728 let curves = [
729 s.add_line(p[0], p[1]),
730 s.add_arc(p[1], p[2], p[3]),
731 s.add_line(p[3], p[4]),
732 s.add_arc(p[4], p[5], p[6]),
733 s.add_line(p[6], p[7]),
734 ];
735 for axis in geop_core_sketch::space::Coordinate::ALL {
736 s.constrain(Constraint3d::Coordinate {
737 point: p[0],
738 axis,
739 value: n(0.0),
740 });
741 }
742 s.constrain(Constraint3d::ParallelTo {
743 line: curves[0],
744 direction: v(1.0, 0.0, 0.0),
745 });
746 s.constrain(Constraint3d::Length {
747 line: curves[0],
748 value: n(4.0 - r),
749 });
750 for w in curves.windows(2) {
751 s.constrain(Constraint3d::Tangent { a: w[0], b: w[1] });
752 }
753 for arc in [curves[1], curves[3]] {
754 s.constrain(Constraint3d::Radius { arc, value: n(r) });
755 }
756 let report = s.solve().expect("the route is valid");
757 assert!(report.converged, "the route does not solve: {report:?}");
758 s
759}
760
761pub fn pipe() -> Program {
765 let mut program = Program::new();
766 let mut section = Sketch::new();
767 circle(&mut section, [0.0, 0.0], 0.3);
768 program.push(
769 "section",
770 AddSketchArgs::on(on_origin(FrameAxis::X), solved(section)),
771 );
772 program.push(
773 "route",
774 AddSketch3dArgs {
775 sketch: pipe_route(1.0),
776 references: Vec::new(),
777 },
778 );
779 program.push(
780 "pipe",
781 SweepArgs {
782 profile: whole_sketch("section"),
783 path: Some(PathRef::Sketch3d(sketch3d_path("route"))),
784 orientation: Orientation::FollowPath,
785 twist: 0.0,
786 end_scale: 1.0,
787 rails: Vec::new(),
788 output: Output::Solid(Combine::NewBody),
789 },
790 );
791 program
792}
793
794pub fn horn() -> Program {
798 let base = |axis| Some(on_origin(axis));
799 let mut program = Program::new();
800 let mut mouth = Sketch::new();
801 let c = mouth.add_point(n(0.0), n(0.0));
802 mouth.add_circle(c, n(0.5));
803 program.push(
804 "mouth",
805 AddSketchArgs {
806 plane: base(FrameAxis::X),
807 sketch: mouth,
808 ..Default::default()
809 },
810 );
811 let mut axis = Sketch::new();
812 let (a, b) = (
813 axis.add_point(n(0.0), n(0.0)),
814 axis.add_point(n(4.0), n(0.0)),
815 );
816 axis.add_line(a, b);
817 program.push(
818 "axis",
819 AddSketchArgs {
820 plane: base(FrameAxis::Z),
821 sketch: axis,
822 ..Default::default()
823 },
824 );
825 let mut flare = Sketch::new();
826 let points =
827 [[0.0, 0.5], [1.5, 0.4], [3.0, 0.9], [4.0, 1.6]].map(|[x, y]| flare.add_point(n(x), n(y)));
828 flare.add_spline(points.to_vec());
829 program.push(
830 "flare",
831 AddSketchArgs {
832 plane: base(FrameAxis::Z),
833 sketch: flare,
834 ..Default::default()
835 },
836 );
837 program.push(
838 "horn",
839 SweepArgs {
840 profile: whole_sketch("mouth"),
841 path: Some(PathRef::Sketch(ElementReference::whole(sketch("axis")))),
842 orientation: Orientation::FollowPath,
843 twist: 0.0,
844 end_scale: 1.0,
845 rails: vec![PathRef::Sketch(ElementReference::whole(sketch("flare")))],
846 output: Output::Solid(Combine::NewBody),
847 },
848 );
849 program
850}
851
852pub fn motor_flange() -> Program {
857 let mut program = Program::new();
858 let mut outline = Sketch::new();
859 let middle = outline.add_point(n(0.0), n(0.0));
860 outline.constrain(Constraint::Fix {
861 point: middle,
862 x: n(0.0),
863 y: n(0.0),
864 });
865 let rim = outline.add_circle(middle, n(16.0));
866 outline.constrain(Constraint::Radius {
867 curve: rim,
868 value: n(15.0),
869 });
870 outline
871 .offset(&[rim], n(10.0), geop_core_sketch::offset::Corners::Round)
872 .expect("a circle offsets inwards by less than its radius");
873 let bolt = circle(&mut outline, [11.0, 0.0], 1.2);
874 outline
875 .pattern(
876 &[bolt],
877 &geop_core_sketch::copies::Step::Round {
878 center: middle,
879 angle: n(std::f64::consts::PI / 3.0),
880 },
881 6,
882 )
883 .expect("a hole off the middle turns round it");
884 program.push(
885 "outline",
886 AddSketchArgs::on(on_origin(FrameAxis::Z), solved(outline)),
887 );
888 program.push(
889 "flange",
890 ExtrudeArgs {
891 sketch: whole_sketch("outline"),
892 extent: Extents::blind(2.5),
893 output: Output::Solid(Combine::NewBody),
894 draft: 0.0,
895 },
896 );
897 program
898}
899
900pub fn square_thread() -> Program {
905 Program::from_json(include_str!("drawn/square_thread.geop"))
906 .expect("a drawn example is a program")
907}
908
909pub fn edge_part() -> Program {
917 Program::from_json(include_str!("drawn/edge_part.geop")).expect("a drawn example is a program")
918}