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