1use arael::utils::Float as _;
2
3#[derive(Clone, Copy, Debug, PartialEq, Default, serde::Serialize, serde::Deserialize)]
8#[arael::model]
9pub enum LineStyle {
10 #[default]
11 Solid,
12 Dashed,
13 DashDot,
14}
15
16impl LineStyle {
17 pub fn next(self) -> Self {
18 match self {
19 LineStyle::Solid => LineStyle::Dashed,
20 LineStyle::Dashed => LineStyle::DashDot,
21 LineStyle::DashDot => LineStyle::Solid,
22 }
23 }
24 pub fn from_name(s: &str) -> Option<Self> {
25 match s {
26 "solid" => Some(Self::Solid),
27 "dashed" => Some(Self::Dashed),
28 "dashdot" | "dash_dot" | "dash-dot" => Some(Self::DashDot),
29 _ => None,
30 }
31 }
32 pub fn name(self) -> &'static str {
33 match self {
34 Self::Solid => "solid",
35 Self::Dashed => "dashed",
36 Self::DashDot => "dashdot",
37 }
38 }
39}
40
41#[derive(serde::Serialize, serde::Deserialize)]
46#[arael::model]
47pub struct PointConstraints {
48 pub has_fix_x: bool,
49 pub fix_x: f64,
50 pub has_fix_y: bool,
51 pub fix_y: f64,
52}
53
54#[derive(serde::Serialize, serde::Deserialize)]
55#[arael::model]
56pub struct LineConstraints {
57 pub horizontal: bool,
58 pub vertical: bool,
59 pub has_length: bool,
60 pub length: f64,
61 #[serde(default)]
62 pub has_angle: bool,
63 #[serde(default)]
64 pub target_angle: f64,
65 #[serde(skip, default = "default_dir_sign_nan")]
72 pub h_dir_sign: f64,
73 #[serde(skip, default = "default_dir_sign_nan")]
75 pub v_dir_sign: f64,
76}
77
78fn default_dir_sign_nan() -> f64 { f64::NAN }
79
80#[derive(serde::Serialize, serde::Deserialize)]
81#[arael::model]
82pub struct ArcConstraints {
83 pub has_target_radius: bool,
84 pub target_radius: f64,
85 #[serde(default)]
86 pub has_target_radius_b: bool,
87 #[serde(default)]
88 pub target_radius_b: f64,
89 #[serde(default)]
90 pub has_target_sweep: bool,
91 #[serde(default)]
92 pub target_sweep: f64,
93 #[serde(default = "default_sweep_sign")]
94 pub sweep_sign: f64,
95 #[serde(default)]
100 pub has_target_rotation: bool,
101 #[serde(default)]
102 pub target_rotation: f64,
103}
104
105fn default_sweep_sign() -> f64 { 1.0 }
106fn default_ccw() -> bool { true }
107fn default_param_zero() -> arael::model::Param<f64> { arael::model::Param::fixed(0.0) }
108
109#[derive(serde::Serialize, serde::Deserialize)]
114#[arael::model]
115#[arael(constraint(hb, name = "drift", {
117 let d = point.pos - point.pos_value;
118 [d.x * sketch.drift_isigma, d.y * sketch.drift_isigma]
119}))]
120#[arael(constraint(hb, guard = self.drag_pull > 0.0, name = "drag_pull", {
128 let d = point.pos - point.pos_value;
129 [d.x * point.drag_pull, d.y * point.drag_pull]
130}))]
131#[arael(constraint(hb, guard = self.constraints.has_fix_x, name = "fix_x", {
133 [(point.pos.x - point.constraints.fix_x) * sketch.constraint_isigma]
134}))]
135#[arael(constraint(hb, guard = self.constraints.has_fix_y, name = "fix_y", {
137 [(point.pos.y - point.constraints.fix_y) * sketch.constraint_isigma]
138}))]
139pub struct Point {
140 pub pos: Param<vect2d>,
141 pub constraints: PointConstraints,
142 pub helper: bool,
143 #[serde(default)]
144 pub quiet: bool,
145 pub name: String,
146 #[serde(skip)]
151 pub drag_pull: f64,
152 #[arael(constraint_index)]
153 #[serde(skip)]
154 pub cid: u32,
155 #[serde(skip)]
156 pub hb: SelfBlock<Point>,
157}
158
159#[derive(serde::Serialize, serde::Deserialize)]
160#[arael::model]
161#[arael(constraint(hb, name = "drift", {
163 let d1 = line.p1 - line.p1_value;
164 let d2 = line.p2 - line.p2_value;
165 [d1.x * sketch.drift_isigma, d1.y * sketch.drift_isigma,
166 d2.x * sketch.drift_isigma, d2.y * sketch.drift_isigma]
167}))]
168#[arael(constraint(hb, name = "drift_length", {
170 let dx = line.p2.x - line.p1.x;
171 let dy = line.p2.y - line.p1.y;
172 let dx0 = line.p2_value.x - line.p1_value.x;
173 let dy0 = line.p2_value.y - line.p1_value.y;
174 [(sqrt(dx * dx + dy * dy + 1e-6) - sqrt(dx0 * dx0 + dy0 * dy0 + 1e-6)) * sketch.drift_isigma]
175}))]
176#[arael(constraint(hb, name = "drift_angle", {
178 let angle = safe_atan2(line.p2.y - line.p1.y, line.p2.x - line.p1.x);
179 let angle0 = safe_atan2(line.p2_value.y - line.p1_value.y, line.p2_value.x - line.p1_value.x);
180 [rad_diff(angle, angle0) * sketch.drift_isigma]
181}))]
182#[arael(constraint(hb, guard = self.constraints.horizontal, name = "horizontal", {
184 [(line.p1.y - line.p2.y) * sketch.constraint_isigma]
185}))]
186#[arael(constraint(hb, guard = self.constraints.horizontal, name = "horizontal_dir", {
194 let d = -line.constraints.h_dir_sign * (line.p2.x - line.p1.x);
195 [heaviside(d) * d * sketch.constraint_isigma]
196}))]
197#[arael(constraint(hb, guard = self.constraints.vertical, name = "vertical", {
199 [(line.p1.x - line.p2.x) * sketch.constraint_isigma]
200}))]
201#[arael(constraint(hb, guard = self.constraints.vertical, name = "vertical_dir", {
203 let d = -line.constraints.v_dir_sign * (line.p2.y - line.p1.y);
204 [heaviside(d) * d * sketch.constraint_isigma]
205}))]
206#[arael(constraint(hb, guard = self.constraints.has_length, name = "length_target", {
208 let dx = line.p2.x - line.p1.x;
209 let dy = line.p2.y - line.p1.y;
210 [(sqrt(dx * dx + dy * dy) - line.constraints.length) * sketch.constraint_isigma]
211}))]
212#[arael(constraint(hb, guard = self.constraints.has_angle, name = "angle_target", {
214 [(atan2(line.p2.y - line.p1.y, line.p2.x - line.p1.x) - line.constraints.target_angle) * sketch.constraint_isigma]
215}))]
216#[arael(constraint(hb, name = "min_length", {
221 let dx = line.p2.x - line.p1.x;
222 let dy = line.p2.y - line.p1.y;
223 let d = sketch.min_length * sketch.min_length - (dx * dx + dy * dy);
224 [heaviside(d) * d * sketch.constraint_isigma * sketch.constraint_isigma]
225}))]
226pub struct Line {
227 pub p1: Param<vect2d>,
228 pub p2: Param<vect2d>,
229 pub constraints: LineConstraints,
230 pub style: LineStyle,
231 #[serde(default)]
232 pub construction: bool,
233 #[serde(default)]
234 pub quiet: bool,
235 pub name: String,
236 #[arael(constraint_index)]
237 #[serde(skip)]
238 pub cid: u32,
239 #[serde(skip)]
240 pub hb: SelfBlock<Line>,
241}
242
243#[derive(serde::Serialize, serde::Deserialize)]
244#[arael::model]
245#[arael(constraint(hb, name = "drift", {
247 let dc = arc.center - arc.center_value;
248 let dr = arc.radius - arc.radius_value;
249 let drb = arc.radius_b - arc.radius_b_value;
250 let drot = arc.rotation - arc.rotation_value;
251 let dsa = arc.start_angle - arc.start_angle_value;
252 let dea = arc.end_angle - arc.end_angle_value;
253 [dc.x * sketch.drift_isigma, dc.y * sketch.drift_isigma,
254 dr * sketch.drift_isigma, drb * sketch.drift_isigma,
255 drot * sketch.drift_isigma,
256 dsa * sketch.drift_isigma, dea * sketch.drift_isigma]
257}))]
258#[arael(constraint(hb, guard = self.constraints.has_target_radius, name = "radius_target", {
260 [(arc.radius - arc.constraints.target_radius) * sketch.constraint_isigma]
261}))]
262#[arael(constraint(hb, guard = self.constraints.has_target_radius_b, name = "radius_b_target", {
264 [(arc.radius_b - arc.constraints.target_radius_b) * sketch.constraint_isigma]
265}))]
266#[arael(constraint(hb, guard = !self.is_ellipse, name = "radius_b_eq_radius", {
268 [(arc.radius_b - arc.radius) * sketch.constraint_isigma]
269}))]
270#[arael(constraint(hb, name = "min_radius", {
275 let d = sketch.min_length - arc.radius;
276 [heaviside(d) * d * d * sketch.constraint_isigma * sketch.constraint_isigma]
277}))]
278#[arael(constraint(hb, guard = self.is_ellipse, name = "min_radius_b", {
280 let d = sketch.min_length - arc.radius_b;
281 [heaviside(d) * d * d * sketch.constraint_isigma * sketch.constraint_isigma]
282}))]
283#[arael(constraint(hb, guard = self.constraints.has_target_sweep, name = "sweep", {
285 [(arc.end_angle - arc.start_angle - arc.constraints.sweep_sign * arc.constraints.target_sweep) * arc.radius * sketch.constraint_isigma]
286}))]
287#[arael(constraint(hb, guard = self.constraints.has_target_rotation && self.is_ellipse, name = "rotation", {
296 [(arc.rotation - arc.constraints.target_rotation) * sketch.constraint_isigma]
297}))]
298pub struct Arc {
299 pub center: Param<vect2d>,
300 pub radius: Param<f64>,
301 #[serde(default = "default_param_zero")]
302 pub radius_b: Param<f64>,
303 #[serde(default = "default_param_zero")]
304 pub rotation: Param<f64>,
305 pub start_angle: Param<f64>,
306 pub end_angle: Param<f64>,
307 pub closed: bool,
310 #[serde(default)]
313 pub is_ellipse: bool,
314 #[serde(default = "default_ccw")]
317 pub ccw: bool,
318 pub style: LineStyle,
319 #[serde(default)]
320 pub construction: bool,
321 #[serde(default)]
322 pub quiet: bool,
323 pub name: String,
324 pub constraints: ArcConstraints,
325 #[arael(constraint_index)]
326 #[serde(skip)]
327 pub cid: u32,
328 #[serde(skip)]
329 pub hb: SelfBlock<Arc>,
330}