1#![allow(async_fn_in_trait)]
2
3use serde::{Deserialize, Serialize};
4
5use crate::{
6 ExecutorContext,
7 frontend::api::{
8 Expr, FileId, Number, ObjectId, ProjectId, Result, SceneGraph, SceneGraphDelta, SourceDelta, Version,
9 },
10};
11
12#[derive(Debug, Clone)]
14pub struct NewSegmentInfo {
15 pub segment_id: ObjectId,
16 pub start_point_id: ObjectId,
17 pub end_point_id: ObjectId,
18 pub center_point_id: Option<ObjectId>,
19}
20
21pub trait SketchApi {
22 async fn execute_mock(
25 &mut self,
26 ctx: &ExecutorContext,
27 version: Version,
28 sketch: ObjectId,
29 ) -> Result<(SourceDelta, SceneGraphDelta)>;
30
31 async fn new_sketch(
32 &mut self,
33 ctx: &ExecutorContext,
34 project: ProjectId,
35 file: FileId,
36 version: Version,
37 args: SketchCtor,
38 ) -> Result<(SourceDelta, SceneGraphDelta, ObjectId)>;
39
40 async fn edit_sketch(
42 &mut self,
43 ctx: &ExecutorContext,
44 project: ProjectId,
45 file: FileId,
46 version: Version,
47 sketch: ObjectId,
48 ) -> Result<SceneGraphDelta>;
49
50 async fn exit_sketch(&mut self, ctx: &ExecutorContext, version: Version, sketch: ObjectId) -> Result<SceneGraph>;
51
52 async fn delete_sketch(
53 &mut self,
54 ctx: &ExecutorContext,
55 version: Version,
56 sketch: ObjectId,
57 ) -> Result<(SourceDelta, SceneGraphDelta)>;
58
59 async fn add_segment(
60 &mut self,
61 ctx: &ExecutorContext,
62 version: Version,
63 sketch: ObjectId,
64 segment: SegmentCtor,
65 label: Option<String>,
66 ) -> Result<(SourceDelta, SceneGraphDelta)>;
67
68 async fn edit_segments(
69 &mut self,
70 ctx: &ExecutorContext,
71 version: Version,
72 sketch: ObjectId,
73 segments: Vec<ExistingSegmentCtor>,
74 ) -> Result<(SourceDelta, SceneGraphDelta)>;
75
76 async fn delete_objects(
77 &mut self,
78 ctx: &ExecutorContext,
79 version: Version,
80 sketch: ObjectId,
81 constraint_ids: Vec<ObjectId>,
82 segment_ids: Vec<ObjectId>,
83 ) -> Result<(SourceDelta, SceneGraphDelta)>;
84
85 async fn add_constraint(
86 &mut self,
87 ctx: &ExecutorContext,
88 version: Version,
89 sketch: ObjectId,
90 constraint: Constraint,
91 ) -> Result<(SourceDelta, SceneGraphDelta)>;
92
93 async fn chain_segment(
94 &mut self,
95 ctx: &ExecutorContext,
96 version: Version,
97 sketch: ObjectId,
98 previous_segment_end_point_id: ObjectId,
99 segment: SegmentCtor,
100 label: Option<String>,
101 ) -> Result<(SourceDelta, SceneGraphDelta)>;
102
103 async fn edit_constraint(
104 &mut self,
105 ctx: &ExecutorContext,
106 version: Version,
107 sketch: ObjectId,
108 constraint_id: ObjectId,
109 value_expression: String,
110 ) -> Result<(SourceDelta, SceneGraphDelta)>;
111
112 #[allow(clippy::too_many_arguments)]
116 async fn batch_split_segment_operations(
117 &mut self,
118 ctx: &ExecutorContext,
119 version: Version,
120 sketch: ObjectId,
121 edit_segments: Vec<ExistingSegmentCtor>,
122 add_constraints: Vec<Constraint>,
123 delete_constraint_ids: Vec<ObjectId>,
124 new_segment_info: NewSegmentInfo,
125 ) -> Result<(SourceDelta, SceneGraphDelta)>;
126
127 async fn batch_tail_cut_operations(
130 &mut self,
131 ctx: &ExecutorContext,
132 version: Version,
133 sketch: ObjectId,
134 edit_segments: Vec<ExistingSegmentCtor>,
135 add_constraints: Vec<Constraint>,
136 delete_constraint_ids: Vec<ObjectId>,
137 ) -> Result<(SourceDelta, SceneGraphDelta)>;
138}
139
140#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
141#[ts(export, export_to = "FrontendApi.ts", rename = "ApiSketch")]
142pub struct Sketch {
143 pub args: SketchCtor,
144 pub plane: ObjectId,
145 pub segments: Vec<ObjectId>,
146 pub constraints: Vec<ObjectId>,
147}
148
149#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
153#[ts(export, export_to = "FrontendApi.ts")]
154pub struct SketchCtor {
155 pub on: String,
160}
161
162#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
163#[ts(export, export_to = "FrontendApi.ts", rename = "ApiPoint")]
164pub struct Point {
165 pub position: Point2d<Number>,
166 pub ctor: Option<PointCtor>,
167 pub owner: Option<ObjectId>,
168 pub freedom: Freedom,
169 pub constraints: Vec<ObjectId>,
170}
171
172#[derive(Debug, Clone, Copy, PartialEq, Deserialize, Serialize, ts_rs::TS)]
173#[ts(export, export_to = "FrontendApi.ts")]
174pub enum Freedom {
175 Free,
176 Fixed,
177 Conflict,
178}
179
180impl Freedom {
181 pub fn merge(self, other: Self) -> Self {
187 match (self, other) {
188 (Self::Conflict, _) | (_, Self::Conflict) => Self::Conflict,
189 (Self::Free, _) | (_, Self::Free) => Self::Free,
190 (Self::Fixed, Self::Fixed) => Self::Fixed,
191 }
192 }
193}
194
195#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
196#[ts(export, export_to = "FrontendApi.ts", rename = "ApiSegment")]
197#[serde(tag = "type")]
198pub enum Segment {
199 Point(Point),
200 Line(Line),
201 Arc(Arc),
202 Circle(Circle),
203}
204
205#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
206#[ts(export, export_to = "FrontendApi.ts")]
207pub struct ExistingSegmentCtor {
208 pub id: ObjectId,
209 pub ctor: SegmentCtor,
210}
211
212#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
213#[ts(export, export_to = "FrontendApi.ts")]
214#[serde(tag = "type")]
215pub enum SegmentCtor {
216 Point(PointCtor),
217 Line(LineCtor),
218 Arc(ArcCtor),
219 TangentArc(TangentArcCtor),
220 Circle(CircleCtor),
221}
222
223#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
224#[ts(export, export_to = "FrontendApi.ts")]
225pub struct PointCtor {
226 pub position: Point2d<Expr>,
227}
228
229#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
230#[ts(export, export_to = "FrontendApi.ts", rename = "ApiPoint2d")]
231pub struct Point2d<U: std::fmt::Debug + Clone + ts_rs::TS> {
232 pub x: U,
233 pub y: U,
234}
235
236#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
237#[ts(export, export_to = "FrontendApi.ts", rename = "ApiLine")]
238pub struct Line {
239 pub start: ObjectId,
240 pub end: ObjectId,
241 pub ctor: SegmentCtor,
243 pub ctor_applicable: bool,
249 pub construction: bool,
250}
251
252#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
253#[ts(export, export_to = "FrontendApi.ts")]
254pub struct LineCtor {
255 pub start: Point2d<Expr>,
256 pub end: Point2d<Expr>,
257 #[serde(skip_serializing_if = "Option::is_none")]
258 #[ts(optional)]
259 pub construction: Option<bool>,
260}
261
262#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
263#[ts(export, export_to = "FrontendApi.ts", rename = "ApiStartOrEnd")]
264#[serde(tag = "type")]
265pub enum StartOrEnd<T> {
266 Start(T),
267 End(T),
268}
269
270#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
271#[ts(export, export_to = "FrontendApi.ts", rename = "ApiArc")]
272pub struct Arc {
273 pub start: ObjectId,
274 pub end: ObjectId,
275 pub center: ObjectId,
276 pub ctor: SegmentCtor,
278 pub ctor_applicable: bool,
279 pub construction: bool,
280}
281
282#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
283#[ts(export, export_to = "FrontendApi.ts")]
284pub struct ArcCtor {
285 pub start: Point2d<Expr>,
286 pub end: Point2d<Expr>,
287 pub center: Point2d<Expr>,
288 #[serde(skip_serializing_if = "Option::is_none")]
289 #[ts(optional)]
290 pub construction: Option<bool>,
291}
292
293#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
294#[ts(export, export_to = "FrontendApi.ts")]
295pub struct TangentArcCtor {
296 pub start: Point2d<Expr>,
297 pub end: Point2d<Expr>,
298 pub tangent: StartOrEnd<ObjectId>,
299}
300
301#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
302#[ts(export, export_to = "FrontendApi.ts", rename = "ApiCircle")]
303pub struct Circle {
304 pub start: ObjectId,
305 pub radius: Number,
306 pub ctor: SegmentCtor,
308 pub ctor_applicable: bool,
309}
310
311#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
312#[ts(export, export_to = "FrontendApi.ts")]
313pub struct CircleCtor {
314 pub center: Point2d<Expr>,
315 pub radius: Expr,
316}
317
318#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
319#[ts(export, export_to = "FrontendApi.ts", rename = "ApiConstraint")]
320#[serde(tag = "type")]
321pub enum Constraint {
322 Coincident(Coincident),
323 Distance(Distance),
324 Diameter(Diameter),
325 HorizontalDistance(Distance),
326 VerticalDistance(Distance),
327 Horizontal(Horizontal),
328 LinesEqualLength(LinesEqualLength),
329 Parallel(Parallel),
330 Perpendicular(Perpendicular),
331 Radius(Radius),
332 Vertical(Vertical),
333}
334
335#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
336#[ts(export, export_to = "FrontendApi.ts")]
337pub struct Coincident {
338 pub segments: Vec<ObjectId>,
339}
340
341#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
342#[ts(export, export_to = "FrontendApi.ts")]
343pub struct Distance {
344 pub points: Vec<ObjectId>,
345 pub distance: Number,
346 pub source: ConstraintSource,
347}
348
349#[derive(Debug, Clone, Default, PartialEq, Deserialize, Serialize, ts_rs::TS)]
350#[ts(export, export_to = "FrontendApi.ts")]
351pub struct ConstraintSource {
352 pub expr: String,
353 pub is_literal: bool,
354}
355
356#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
357#[ts(export, export_to = "FrontendApi.ts")]
358pub struct Radius {
359 pub arc: ObjectId,
360 pub radius: Number,
361}
362
363#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
364#[ts(export, export_to = "FrontendApi.ts")]
365pub struct Diameter {
366 pub arc: ObjectId,
367 pub diameter: Number,
368}
369
370#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
371#[ts(export, export_to = "FrontendApi.ts")]
372pub struct Horizontal {
373 pub line: ObjectId,
374}
375
376#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
377#[ts(export, export_to = "FrontendApi.ts")]
378pub struct LinesEqualLength {
379 pub lines: Vec<ObjectId>,
380}
381
382#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
383#[ts(export, export_to = "FrontendApi.ts")]
384pub struct Vertical {
385 pub line: ObjectId,
386}
387
388#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
389#[ts(export, export_to = "FrontendApi.ts", optional_fields)]
390pub struct Parallel {
391 pub lines: Vec<ObjectId>,
392}
393
394#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
395#[ts(export, export_to = "FrontendApi.ts", optional_fields)]
396pub struct Perpendicular {
397 pub lines: Vec<ObjectId>,
398}