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