geop_ops_pattern/
pattern.rs1use geop_core_editor::{
6 edit_form::{EditForm, FormState},
7 editable::{Context, OperationGroup, OperationInfo, OperationTier},
8 part_operation,
9 part_operation::PartOperation,
10};
11use geop_core_math::{geop_error::GeopResult, primitives::Motion};
12use geop_core_program::{part::StepContext, reader::Reader};
13use geop_ops_model::spacing::{Frames, PointsRef};
14use geop_ops_model::{ModelOperation, NamedModel};
15use serde::{Deserialize, Serialize};
16
17use crate::common::{Naming, Pattern as Repeats, Seeds, build_pattern, placed_by, run_pattern};
18
19#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize)]
34pub struct Pattern;
35
36#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
37pub struct PatternArgs {
38 #[serde(flatten)]
41 pub seeds: Seeds,
42 pub frames: Frames,
44}
45
46impl Repeats for PatternArgs {
47 const NAMING: Naming = Naming {
48 kind: "pattern",
49 labelled: true,
50 };
51
52 fn seeds(&self) -> &Seeds {
53 &self.seeds
54 }
55
56 fn seed_label(&self) -> &'static str {
58 match &self.frames {
59 Frames::Linear {
60 second: Some(_), ..
61 }
62 | Frames::Fill { .. } => "0.0",
63 _ => "0",
64 }
65 }
66
67 fn placements(&self, reader: &Reader) -> GeopResult<Vec<(String, Motion)>> {
68 placed_by(&self.frames, reader, &self.seeds)
69 }
70}
71
72part_operation!(Pattern(PatternArgs));
73
74impl PartOperation for Pattern {
75 const KIND: &'static str = "pattern";
76 const INFO: OperationInfo = OperationInfo::new(
77 "Pattern",
78 "Copy bodies or features along a curve, at points, from a table of offsets, filling a face or at holes — or in a row, or round an axis.",
79 OperationGroup::Bodies,
80 OperationTier::Small,
81 )
82 .shortcut("Shift+A")
83 .icon(crate::icons::PATTERN);
84 type Args = PatternArgs;
85 type Session = ();
86
87 fn new_args(_: &Context) -> PatternArgs {
89 PatternArgs {
90 seeds: Seeds::default(),
91 frames: Frames::Points {
92 points: Vec::<PointsRef>::new(),
93 from: None,
94 },
95 }
96 }
97
98 fn run(ctx: &mut StepContext, args: &PatternArgs) -> GeopResult<()> {
99 run_pattern::<Self>(ctx, args)
100 }
101
102 fn form<'a>(
105 context: &'a Context<'a>,
106 args: &PatternArgs,
107 _: &FormState<()>,
108 ) -> EditForm<'a, PatternArgs> {
109 let before = &context.before;
110 let mut f = EditForm::default();
111 let at = args.seeds.center(before);
112 let set_seeds = |args: &mut PatternArgs, seeds| args.seeds = seeds;
113 (args.seeds).fields(&mut f, before, set_seeds, |f| {
114 args.frames
115 .fields(f, before, at, |args: &mut PatternArgs, frames| {
116 args.frames = frames
117 });
118 });
119 f
120 }
121}
122
123impl ModelOperation for Pattern {
124 fn build(
125 model: &mut NamedModel,
126 reader: &Reader,
127 step: &str,
128 args: &PatternArgs,
129 ) -> GeopResult<()> {
130 build_pattern(model, reader, step, args)
131 }
132}