geop_ops_parts/operation/
add_sketch.rs1use geop_core_math::{
4 geop_error::{GeopResult, WithContext},
5 scalars::Scalar,
6 vector::Vector2,
7 with_context,
8};
9use geop_core_part::{Part, PlacedSketch};
10use geop_core_sketch::Sketch;
11use geop_ops_parts_derive::OperationArgs;
12use serde::{Deserialize, Serialize};
13
14use super::{
15 EntityRef, Handle, HandleGroup, HandleMotion, Operation, arg_path, entity::resolve_plane,
16 extrude::to_f64,
17};
18
19#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize)]
24pub struct AddSketch;
25
26#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, OperationArgs)]
27pub struct AddSketchArgs {
28 #[arg(Plane)]
30 pub plane: EntityRef,
31 #[arg(Drawing { plane: "plane" })]
33 pub sketch: Sketch,
34}
35
36impl<S: Scalar> Operation<S> for AddSketch {
37 type Args = AddSketchArgs;
38
39 fn apply(
40 &self,
41 mut part: Part<S>,
42 operation_id: &str,
43 args: &AddSketchArgs,
44 ) -> GeopResult<Part<S>> {
45 let ctx = with_context!("add_sketch({operation_id}, plane={:?})", args.plane);
46 args.sketch.validate().with_context(ctx)?;
47 let plane = resolve_plane(&part, &args.plane).with_context(ctx)?;
48 let placed = PlacedSketch {
49 plane,
50 sketch: args.sketch.clone(),
51 };
52 part.add_sketch(placed, operation_id).with_context(ctx)?;
53 Ok(part)
54 }
55
56 fn handles(&self, before: &Part<S>, args: &AddSketchArgs) -> GeopResult<Vec<Handle>> {
58 let plane = resolve_plane(before, &args.plane)?;
59 let (u, v) = (to_f64(plane.u()), to_f64(plane.v()));
60 Ok(args
61 .sketch
62 .points
63 .iter()
64 .map(|(id, p)| {
65 let at = plane.uv_to_xyz(&Vector2::from_array([p.x, p.y].map(S::from_f64)));
66 let path = |c: &str| arg_path(&["sketch", "points", &id.0.to_string(), c]);
67 Handle {
68 label: id.to_string(),
69 group: HandleGroup::Sketch,
70 position: to_f64(&at),
71 motion: HandleMotion::Planar {
72 u,
73 v,
74 x: path("x"),
75 y: path("y"),
76 value: [p.x, p.y],
77 },
78 }
79 })
80 .collect())
81 }
82}