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
12pub trait SketchApi {
13 async fn execute_mock(
16 &mut self,
17 ctx: &ExecutorContext,
18 version: Version,
19 sketch: ObjectId,
20 ) -> Result<(SourceDelta, SceneGraphDelta)>;
21
22 async fn new_sketch(
23 &mut self,
24 ctx: &ExecutorContext,
25 project: ProjectId,
26 file: FileId,
27 version: Version,
28 args: SketchCtor,
29 ) -> Result<(SourceDelta, SceneGraphDelta, ObjectId)>;
30
31 async fn edit_sketch(
33 &mut self,
34 ctx: &ExecutorContext,
35 project: ProjectId,
36 file: FileId,
37 version: Version,
38 sketch: ObjectId,
39 ) -> Result<SceneGraphDelta>;
40
41 async fn exit_sketch(&mut self, ctx: &ExecutorContext, version: Version, sketch: ObjectId) -> Result<SceneGraph>;
42
43 async fn delete_sketch(
44 &mut self,
45 ctx: &ExecutorContext,
46 version: Version,
47 sketch: ObjectId,
48 ) -> Result<(SourceDelta, SceneGraphDelta)>;
49
50 async fn add_segment(
51 &mut self,
52 ctx: &ExecutorContext,
53 version: Version,
54 sketch: ObjectId,
55 segment: SegmentCtor,
56 label: Option<String>,
57 ) -> Result<(SourceDelta, SceneGraphDelta)>;
58
59 async fn edit_segments(
60 &mut self,
61 ctx: &ExecutorContext,
62 version: Version,
63 sketch: ObjectId,
64 segments: Vec<ExistingSegmentCtor>,
65 ) -> Result<(SourceDelta, SceneGraphDelta)>;
66
67 async fn delete_objects(
68 &mut self,
69 ctx: &ExecutorContext,
70 version: Version,
71 sketch: ObjectId,
72 constraint_ids: Vec<ObjectId>,
73 segment_ids: Vec<ObjectId>,
74 ) -> Result<(SourceDelta, SceneGraphDelta)>;
75
76 async fn add_constraint(
77 &mut self,
78 ctx: &ExecutorContext,
79 version: Version,
80 sketch: ObjectId,
81 constraint: Constraint,
82 ) -> Result<(SourceDelta, SceneGraphDelta)>;
83
84 async fn chain_segment(
85 &mut self,
86 ctx: &ExecutorContext,
87 version: Version,
88 sketch: ObjectId,
89 previous_segment_end_point_id: ObjectId,
90 segment: SegmentCtor,
91 label: Option<String>,
92 ) -> Result<(SourceDelta, SceneGraphDelta)>;
93
94 async fn edit_constraint(
95 &mut self,
96 ctx: &ExecutorContext,
97 version: Version,
98 sketch: ObjectId,
99 constraint_id: ObjectId,
100 constraint: Constraint,
101 ) -> Result<(SourceDelta, SceneGraphDelta)>;
102}
103
104#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
105#[ts(export, export_to = "FrontendApi.ts", rename = "ApiSketch")]
106pub struct Sketch {
107 pub args: SketchCtor,
108 pub plane: ObjectId,
109 pub segments: Vec<ObjectId>,
110 pub constraints: Vec<ObjectId>,
111}
112
113#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
117#[ts(export, export_to = "FrontendApi.ts")]
118pub struct SketchCtor {
119 pub on: String,
124}
125
126#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
127#[ts(export, export_to = "FrontendApi.ts", rename = "ApiPoint")]
128pub struct Point {
129 pub position: Point2d<Number>,
130 pub ctor: Option<PointCtor>,
131 pub owner: Option<ObjectId>,
132 pub freedom: Freedom,
133 pub constraints: Vec<ObjectId>,
134}
135
136#[derive(Debug, Clone, Copy, PartialEq, Deserialize, Serialize, ts_rs::TS)]
137#[ts(export, export_to = "FrontendApi.ts")]
138pub enum Freedom {
139 Free,
140 Fixed,
141 Conflict,
142}
143
144impl Freedom {
145 pub fn merge(self, other: Self) -> Self {
151 match (self, other) {
152 (Self::Conflict, _) | (_, Self::Conflict) => Self::Conflict,
153 (Self::Free, _) | (_, Self::Free) => Self::Free,
154 (Self::Fixed, Self::Fixed) => Self::Fixed,
155 }
156 }
157}
158
159#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
160#[ts(export, export_to = "FrontendApi.ts", rename = "ApiSegment")]
161#[serde(tag = "type")]
162pub enum Segment {
163 Point(Point),
164 Line(Line),
165 Arc(Arc),
166 Circle(Circle),
167}
168
169#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
170#[ts(export, export_to = "FrontendApi.ts")]
171pub struct ExistingSegmentCtor {
172 pub id: ObjectId,
173 pub ctor: SegmentCtor,
174}
175
176#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
177#[ts(export, export_to = "FrontendApi.ts")]
178#[serde(tag = "type")]
179pub enum SegmentCtor {
180 Point(PointCtor),
181 Line(LineCtor),
182 Arc(ArcCtor),
183 TangentArc(TangentArcCtor),
184 Circle(CircleCtor),
185}
186
187#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
188#[ts(export, export_to = "FrontendApi.ts")]
189pub struct PointCtor {
190 pub position: Point2d<Expr>,
191}
192
193#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
194#[ts(export, export_to = "FrontendApi.ts", rename = "ApiPoint2d")]
195pub struct Point2d<U: std::fmt::Debug + Clone + ts_rs::TS> {
196 pub x: U,
197 pub y: U,
198}
199
200#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
201#[ts(export, export_to = "FrontendApi.ts", rename = "ApiLine")]
202pub struct Line {
203 pub start: ObjectId,
204 pub end: ObjectId,
205 pub ctor: SegmentCtor,
207 pub ctor_applicable: bool,
213 pub construction: bool,
214}
215
216#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
217#[ts(export, export_to = "FrontendApi.ts")]
218pub struct LineCtor {
219 pub start: Point2d<Expr>,
220 pub end: Point2d<Expr>,
221 #[serde(skip_serializing_if = "Option::is_none")]
222 #[ts(optional)]
223 pub construction: Option<bool>,
224}
225
226#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
227#[ts(export, export_to = "FrontendApi.ts", rename = "ApiStartOrEnd")]
228#[serde(tag = "type")]
229pub enum StartOrEnd<T> {
230 Start(T),
231 End(T),
232}
233
234#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
235#[ts(export, export_to = "FrontendApi.ts", rename = "ApiArc")]
236pub struct Arc {
237 pub start: ObjectId,
238 pub end: ObjectId,
239 pub center: ObjectId,
240 pub ctor: SegmentCtor,
242 pub ctor_applicable: bool,
243 pub construction: bool,
244}
245
246#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
247#[ts(export, export_to = "FrontendApi.ts")]
248pub struct ArcCtor {
249 pub start: Point2d<Expr>,
250 pub end: Point2d<Expr>,
251 pub center: Point2d<Expr>,
252 #[serde(skip_serializing_if = "Option::is_none")]
253 #[ts(optional)]
254 pub construction: Option<bool>,
255}
256
257#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
258#[ts(export, export_to = "FrontendApi.ts")]
259pub struct TangentArcCtor {
260 pub start: Point2d<Expr>,
261 pub end: Point2d<Expr>,
262 pub tangent: StartOrEnd<ObjectId>,
263}
264
265#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
266#[ts(export, export_to = "FrontendApi.ts", rename = "ApiCircle")]
267pub struct Circle {
268 pub start: ObjectId,
269 pub radius: Number,
270 pub ctor: SegmentCtor,
272 pub ctor_applicable: bool,
273}
274
275#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
276#[ts(export, export_to = "FrontendApi.ts")]
277pub struct CircleCtor {
278 pub center: Point2d<Expr>,
279 pub radius: Expr,
280}
281
282#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
283#[ts(export, export_to = "FrontendApi.ts", rename = "ApiConstraint")]
284#[serde(tag = "type")]
285pub enum Constraint {
286 Coincident(Coincident),
287 Distance(Distance),
288 Diameter(Diameter),
289 HorizontalDistance(Distance),
290 VerticalDistance(Distance),
291 Horizontal(Horizontal),
292 LinesEqualLength(LinesEqualLength),
293 Parallel(Parallel),
294 Perpendicular(Perpendicular),
295 Radius(Radius),
296 Vertical(Vertical),
297}
298
299#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
300#[ts(export, export_to = "FrontendApi.ts")]
301pub struct Coincident {
302 pub segments: Vec<ObjectId>,
303}
304
305#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
306#[ts(export, export_to = "FrontendApi.ts")]
307pub struct Distance {
308 pub points: Vec<ObjectId>,
309 pub distance: Number,
310}
311
312#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
313#[ts(export, export_to = "FrontendApi.ts")]
314pub struct Radius {
315 pub arc: ObjectId,
316 pub radius: Number,
317}
318
319#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
320#[ts(export, export_to = "FrontendApi.ts")]
321pub struct Diameter {
322 pub arc: ObjectId,
323 pub diameter: Number,
324}
325
326#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
327#[ts(export, export_to = "FrontendApi.ts")]
328pub struct Horizontal {
329 pub line: ObjectId,
330}
331
332#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
333#[ts(export, export_to = "FrontendApi.ts")]
334pub struct LinesEqualLength {
335 pub lines: Vec<ObjectId>,
336}
337
338#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
339#[ts(export, export_to = "FrontendApi.ts")]
340pub struct Vertical {
341 pub line: ObjectId,
342}
343
344#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
345#[ts(export, export_to = "FrontendApi.ts", optional_fields)]
346pub struct Parallel {
347 pub lines: Vec<ObjectId>,
348}
349
350#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
351#[ts(export, export_to = "FrontendApi.ts", optional_fields)]
352pub struct Perpendicular {
353 pub lines: Vec<ObjectId>,
354}