1#![allow(async_fn_in_trait)]
2
3use serde::{Deserialize, Serialize};
4
5use crate::{
6 ExecOutcome, ExecutorContext,
7 frontend::api::{
8 Expr, FileId, Number, ObjectId, Plane, 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<(SceneGraph, ExecOutcome)>;
21
22 async fn new_sketch(
23 &mut self,
24 ctx: &ExecutorContext,
25 project: ProjectId,
26 file: FileId,
27 version: Version,
28 args: SketchArgs,
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 edit_constraint(
85 &mut self,
86 ctx: &ExecutorContext,
87 version: Version,
88 sketch: ObjectId,
89 constraint_id: ObjectId,
90 constraint: Constraint,
91 ) -> Result<(SourceDelta, SceneGraphDelta)>;
92}
93
94#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
95#[ts(export, export_to = "FrontendApi.ts", rename = "ApiSketch")]
96pub struct Sketch {
97 pub args: SketchArgs,
98 pub segments: Vec<ObjectId>,
99 pub constraints: Vec<ObjectId>,
100}
101
102#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
103#[ts(export, export_to = "FrontendApi.ts")]
104pub struct SketchArgs {
105 pub on: Plane,
106}
107
108#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
109#[ts(export, export_to = "FrontendApi.ts", rename = "ApiPoint")]
110pub struct Point {
111 pub position: Point2d<Number>,
112 pub ctor: Option<PointCtor>,
113 pub owner: Option<ObjectId>,
114 pub freedom: Freedom,
115 pub constraints: Vec<ObjectId>,
116}
117
118#[derive(Debug, Clone, Copy, PartialEq, Deserialize, Serialize, ts_rs::TS)]
119#[ts(export, export_to = "FrontendApi.ts")]
120pub enum Freedom {
121 Free,
122 Fixed,
123 Conflict,
124}
125
126impl Freedom {
127 pub fn merge(self, other: Self) -> Self {
133 match (self, other) {
134 (Self::Conflict, _) | (_, Self::Conflict) => Self::Conflict,
135 (Self::Free, _) | (_, Self::Free) => Self::Free,
136 (Self::Fixed, Self::Fixed) => Self::Fixed,
137 }
138 }
139}
140
141#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
142#[ts(export, export_to = "FrontendApi.ts", rename = "ApiSegment")]
143#[serde(tag = "type")]
144pub enum Segment {
145 Point(Point),
146 Line(Line),
147 Arc(Arc),
148 Circle(Circle),
149}
150
151#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
152#[ts(export, export_to = "FrontendApi.ts")]
153pub struct ExistingSegmentCtor {
154 pub id: ObjectId,
155 pub ctor: SegmentCtor,
156}
157
158#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
159#[ts(export, export_to = "FrontendApi.ts")]
160#[serde(tag = "type")]
161pub enum SegmentCtor {
162 Point(PointCtor),
163 Line(LineCtor),
164 Arc(ArcCtor),
165 TangentArc(TangentArcCtor),
166 Circle(CircleCtor),
167}
168
169#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
170#[ts(export, export_to = "FrontendApi.ts")]
171pub struct PointCtor {
172 pub position: Point2d<Expr>,
173}
174
175#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
176#[ts(export, export_to = "FrontendApi.ts", rename = "ApiPoint2d")]
177pub struct Point2d<U: std::fmt::Debug + Clone + ts_rs::TS> {
178 pub x: U,
179 pub y: U,
180}
181
182#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
183#[ts(export, export_to = "FrontendApi.ts", rename = "ApiLine")]
184pub struct Line {
185 pub start: ObjectId,
186 pub end: ObjectId,
187 pub ctor: SegmentCtor,
189 pub ctor_applicable: bool,
195}
196
197#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
198#[ts(export, export_to = "FrontendApi.ts")]
199pub struct LineCtor {
200 pub start: Point2d<Expr>,
201 pub end: Point2d<Expr>,
202}
203
204#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
205#[ts(export, export_to = "FrontendApi.ts", rename = "ApiStartOrEnd")]
206#[serde(tag = "type")]
207pub enum StartOrEnd<T> {
208 Start(T),
209 End(T),
210}
211
212#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
213#[ts(export, export_to = "FrontendApi.ts", rename = "ApiArc")]
214pub struct Arc {
215 pub start: ObjectId,
216 pub end: ObjectId,
217 pub center: ObjectId,
218 pub ctor: SegmentCtor,
220 pub ctor_applicable: bool,
221}
222
223#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
224#[ts(export, export_to = "FrontendApi.ts")]
225pub struct ArcCtor {
226 pub start: Point2d<Expr>,
227 pub end: Point2d<Expr>,
228 pub center: Point2d<Expr>,
229}
230
231#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
232#[ts(export, export_to = "FrontendApi.ts")]
233pub struct TangentArcCtor {
234 pub start: Point2d<Expr>,
235 pub end: Point2d<Expr>,
236 pub tangent: StartOrEnd<ObjectId>,
237}
238
239#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
240#[ts(export, export_to = "FrontendApi.ts", rename = "ApiCircle")]
241pub struct Circle {
242 pub start: ObjectId,
243 pub radius: Number,
244 pub ctor: SegmentCtor,
246 pub ctor_applicable: bool,
247}
248
249#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
250#[ts(export, export_to = "FrontendApi.ts")]
251pub struct CircleCtor {
252 pub center: Point2d<Expr>,
253 pub radius: Expr,
254}
255
256#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
257#[ts(export, export_to = "FrontendApi.ts", rename = "ApiConstraint")]
258#[serde(tag = "type")]
259pub enum Constraint {
260 Coincident(Coincident),
261 Distance(Distance),
262 Horizontal(Horizontal),
263 LinesEqualLength(LinesEqualLength),
264 Parallel(Parallel),
265 Perpendicular(Perpendicular),
266 Vertical(Vertical),
267}
268
269#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
270#[ts(export, export_to = "FrontendApi.ts")]
271pub struct Coincident {
272 pub segments: Vec<ObjectId>,
273}
274
275#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
276#[ts(export, export_to = "FrontendApi.ts")]
277pub struct Distance {
278 pub points: Vec<ObjectId>,
279 pub distance: Number,
280}
281
282#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
283#[ts(export, export_to = "FrontendApi.ts")]
284pub struct Horizontal {
285 pub line: ObjectId,
286}
287
288#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
289#[ts(export, export_to = "FrontendApi.ts")]
290pub struct LinesEqualLength {
291 pub lines: Vec<ObjectId>,
292}
293
294#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
295#[ts(export, export_to = "FrontendApi.ts")]
296pub struct Vertical {
297 pub line: ObjectId,
298}
299
300#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
301#[ts(export, export_to = "FrontendApi.ts", optional_fields)]
302pub struct Parallel {
303 pub lines: Vec<ObjectId>,
304}
305
306#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
307#[ts(export, export_to = "FrontendApi.ts", optional_fields)]
308pub struct Perpendicular {
309 pub lines: Vec<ObjectId>,
310}