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 add_segment(
44 &mut self,
45 ctx: &ExecutorContext,
46 version: Version,
47 sketch: ObjectId,
48 segment: SegmentCtor,
49 label: Option<String>,
50 ) -> Result<(SourceDelta, SceneGraphDelta)>;
51
52 async fn edit_segments(
53 &mut self,
54 ctx: &ExecutorContext,
55 version: Version,
56 sketch: ObjectId,
57 segments: Vec<ExistingSegmentCtor>,
58 ) -> Result<(SourceDelta, SceneGraphDelta)>;
59
60 async fn delete_objects(
61 &mut self,
62 ctx: &ExecutorContext,
63 version: Version,
64 sketch: ObjectId,
65 constraint_ids: Vec<ObjectId>,
66 segment_ids: Vec<ObjectId>,
67 ) -> Result<(SourceDelta, SceneGraphDelta)>;
68
69 async fn add_constraint(
70 &mut self,
71 ctx: &ExecutorContext,
72 version: Version,
73 sketch: ObjectId,
74 constraint: Constraint,
75 ) -> Result<(SourceDelta, SceneGraphDelta)>;
76
77 async fn edit_constraint(
78 &mut self,
79 ctx: &ExecutorContext,
80 version: Version,
81 sketch: ObjectId,
82 constraint_id: ObjectId,
83 constraint: Constraint,
84 ) -> Result<(SourceDelta, SceneGraphDelta)>;
85}
86
87#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
88#[ts(export, export_to = "FrontendApi.ts", rename = "ApiSketch")]
89pub struct Sketch {
90 pub args: SketchArgs,
91 pub segments: Vec<ObjectId>,
92 pub constraints: Vec<ObjectId>,
93 pub is_underconstrained: Option<bool>,
94}
95
96#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
97#[ts(export, export_to = "FrontendApi.ts")]
98pub struct SketchArgs {
99 pub on: Plane,
100}
101
102#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
103#[ts(export, export_to = "FrontendApi.ts", rename = "ApiPoint")]
104pub struct Point {
105 pub position: Point2d<Number>,
106 pub ctor: Option<PointCtor>,
107 pub owner: Option<ObjectId>,
108 pub freedom: Freedom,
109 pub constraints: Vec<ObjectId>,
110}
111
112#[derive(Debug, Clone, Copy, PartialEq, Deserialize, Serialize, ts_rs::TS)]
113#[ts(export, export_to = "FrontendApi.ts")]
114pub enum Freedom {
115 Free,
116 Fixed,
117 Conflict,
118}
119
120impl Freedom {
121 pub fn merge(self, other: Self) -> Self {
127 match (self, other) {
128 (Self::Conflict, _) | (_, Self::Conflict) => Self::Conflict,
129 (Self::Free, _) | (_, Self::Free) => Self::Free,
130 (Self::Fixed, Self::Fixed) => Self::Fixed,
131 }
132 }
133}
134
135#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
136#[ts(export, export_to = "FrontendApi.ts", rename = "ApiSegment")]
137#[serde(tag = "type")]
138pub enum Segment {
139 Point(Point),
140 Line(Line),
141 Arc(Arc),
142 Circle(Circle),
143}
144
145#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
146#[ts(export, export_to = "FrontendApi.ts")]
147pub struct ExistingSegmentCtor {
148 pub id: ObjectId,
149 pub ctor: SegmentCtor,
150}
151
152#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
153#[ts(export, export_to = "FrontendApi.ts")]
154#[serde(tag = "type")]
155pub enum SegmentCtor {
156 Point(PointCtor),
157 Line(LineCtor),
158 Arc(ArcCtor),
159 TangentArc(TangentArcCtor),
160 Circle(CircleCtor),
161}
162
163#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
164#[ts(export, export_to = "FrontendApi.ts")]
165pub struct PointCtor {
166 pub position: Point2d<Expr>,
167}
168
169#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
170#[ts(export, export_to = "FrontendApi.ts", rename = "ApiPoint2d")]
171pub struct Point2d<U: std::fmt::Debug + Clone + ts_rs::TS> {
172 pub x: U,
173 pub y: U,
174}
175
176#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
177#[ts(export, export_to = "FrontendApi.ts", rename = "ApiLine")]
178pub struct Line {
179 pub start: ObjectId,
180 pub end: ObjectId,
181 pub ctor: SegmentCtor,
183 pub ctor_applicable: bool,
189}
190
191#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
192#[ts(export, export_to = "FrontendApi.ts")]
193pub struct LineCtor {
194 pub start: Point2d<Expr>,
195 pub end: Point2d<Expr>,
196}
197
198#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
199#[ts(export, export_to = "FrontendApi.ts", rename = "ApiStartOrEnd")]
200#[serde(tag = "type")]
201pub enum StartOrEnd<T> {
202 Start(T),
203 End(T),
204}
205
206#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
207#[ts(export, export_to = "FrontendApi.ts", rename = "ApiArc")]
208pub struct Arc {
209 pub start: ObjectId,
210 pub end: ObjectId,
211 pub center: ObjectId,
212 pub ctor: SegmentCtor,
214 pub ctor_applicable: bool,
215}
216
217#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
218#[ts(export, export_to = "FrontendApi.ts")]
219pub struct ArcCtor {
220 pub start: Point2d<Expr>,
221 pub end: Point2d<Expr>,
222 pub center: Point2d<Expr>,
223}
224
225#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
226#[ts(export, export_to = "FrontendApi.ts")]
227pub struct TangentArcCtor {
228 pub start: Point2d<Expr>,
229 pub end: Point2d<Expr>,
230 pub tangent: StartOrEnd<ObjectId>,
231}
232
233#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
234#[ts(export, export_to = "FrontendApi.ts", rename = "ApiCircle")]
235pub struct Circle {
236 pub start: ObjectId,
237 pub radius: Number,
238 pub ctor: SegmentCtor,
240 pub ctor_applicable: bool,
241}
242
243#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
244#[ts(export, export_to = "FrontendApi.ts")]
245pub struct CircleCtor {
246 pub center: Point2d<Expr>,
247 pub radius: Expr,
248}
249
250#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
251#[ts(export, export_to = "FrontendApi.ts", rename = "ApiConstraint")]
252#[serde(tag = "type")]
253pub enum Constraint {
254 Coincident(Coincident),
255 Distance(Distance),
256 Horizontal(Horizontal),
257 LinesEqualLength(LinesEqualLength),
258 Parallel(Parallel),
259 Vertical(Vertical),
260}
261
262#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
263#[ts(export, export_to = "FrontendApi.ts")]
264pub struct Coincident {
265 pub points: Vec<ObjectId>,
266}
267
268#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
269#[ts(export, export_to = "FrontendApi.ts")]
270pub struct Distance {
271 pub points: Vec<ObjectId>,
272 pub distance: Number,
273}
274
275#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
276#[ts(export, export_to = "FrontendApi.ts")]
277pub struct Horizontal {
278 pub line: ObjectId,
279}
280
281#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
282#[ts(export, export_to = "FrontendApi.ts")]
283pub struct LinesEqualLength {
284 pub lines: Vec<ObjectId>,
285}
286
287#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
288#[ts(export, export_to = "FrontendApi.ts")]
289pub struct Vertical {
290 pub line: ObjectId,
291}
292
293#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS)]
294#[ts(export, export_to = "FrontendApi.ts", optional_fields)]
295pub struct Parallel {
296 pub lines: Vec<ObjectId>,
297}