geop_ops_pattern/
mirror.rs1use geop_core_editor::{
4 edit_form::{EditForm, FormState},
5 editable::{Context, OperationGroup, OperationInfo, OperationTier},
6 part_operation,
7 part_operation::PartOperation,
8};
9use geop_core_math::{
10 geop_error::{GeopError, GeopResult},
11 primitives::{FrameAxis, Motion},
12};
13use geop_core_program::{part::StepContext, reader::Reader};
14use geop_ops_model::datums::origin_plane;
15use geop_ops_model::sketch::SketchPlane;
16use geop_ops_model::{ModelOperation, NamedModel};
17use serde::{Deserialize, Serialize};
18
19use crate::common::{Naming, Pattern, Seeds, build_pattern, run_pattern};
20
21#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize)]
32pub struct Mirror;
33
34#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
35pub struct MirrorArgs {
36 #[serde(flatten)]
39 pub seeds: Seeds,
40 pub plane: Option<SketchPlane>,
43}
44
45impl Pattern for MirrorArgs {
46 const NAMING: Naming = Naming {
47 kind: "mirror",
48 labelled: false,
49 };
50
51 fn seeds(&self) -> &Seeds {
52 &self.seeds
53 }
54
55 fn seed_label(&self) -> &'static str {
56 "seed"
57 }
58
59 fn placements(&self, reader: &Reader) -> GeopResult<Vec<(String, Motion)>> {
61 let Some(plane) = &self.plane else {
62 return Err(GeopError::new("pick a plane to mirror in"));
63 };
64 let plane = plane.resolve(reader)?;
65 Ok(vec![(
66 "image".to_string(),
67 Motion::mirror(plane.origin(), plane.w())?,
68 )])
69 }
70}
71
72part_operation!(Mirror(MirrorArgs));
73
74impl PartOperation for Mirror {
75 const KIND: &'static str = "mirror";
76 const INFO: OperationInfo = OperationInfo::new(
77 "Mirror",
78 "Mirror bodies in a plane.",
79 OperationGroup::Bodies,
80 OperationTier::Small,
81 )
82 .shortcut("M")
83 .icon(geop_core_editor::view::icons::MIRROR);
84 type Args = MirrorArgs;
85 type Session = ();
86
87 fn new_args(_: &Context) -> MirrorArgs {
89 MirrorArgs {
90 seeds: Seeds::default(),
93 plane: Some(SketchPlane::Datum(origin_plane(FrameAxis::X))),
94 }
95 }
96
97 fn run(ctx: &mut StepContext, args: &MirrorArgs) -> GeopResult<()> {
98 let _step = ctx.step();
99 run_pattern::<Self>(ctx, args)
100 }
101
102 fn form<'a>(
105 context: &'a Context<'a>,
106 args: &MirrorArgs,
107 _: &FormState<()>,
108 ) -> EditForm<'a, MirrorArgs> {
109 let before = &context.before;
110 let mut f = EditForm::default();
111 let set_seeds = |args: &mut MirrorArgs, seeds| args.seeds = seeds;
112 (args.seeds).fields(&mut f, before, set_seeds, |f| {
113 f.pick_one(
114 "plane",
115 "plane",
116 before,
117 args.plane.as_ref(),
118 |edit, picked| edit.args.plane = Some(picked),
119 );
120 });
121 f
122 }
123}
124
125impl ModelOperation for Mirror {
126 fn build(
127 model: &mut NamedModel,
128 reader: &Reader,
129 step: &str,
130 args: &MirrorArgs,
131 ) -> GeopResult<()> {
132 build_pattern(model, reader, step, args)
133 }
134}