use arael::utils::Float as _;
#[derive(Clone, Copy, Debug, PartialEq, Default, serde::Serialize, serde::Deserialize)]
#[arael::model]
pub enum LineStyle {
#[default]
Solid,
Dashed,
DashDot,
}
impl LineStyle {
pub fn next(self) -> Self {
match self {
LineStyle::Solid => LineStyle::Dashed,
LineStyle::Dashed => LineStyle::DashDot,
LineStyle::DashDot => LineStyle::Solid,
}
}
pub fn from_name(s: &str) -> Option<Self> {
match s {
"solid" => Some(Self::Solid),
"dashed" => Some(Self::Dashed),
"dashdot" | "dash_dot" | "dash-dot" => Some(Self::DashDot),
_ => None,
}
}
pub fn name(self) -> &'static str {
match self {
Self::Solid => "solid",
Self::Dashed => "dashed",
Self::DashDot => "dashdot",
}
}
}
#[derive(serde::Serialize, serde::Deserialize)]
#[arael::model]
pub struct PointConstraints {
pub has_fix_x: bool,
pub fix_x: f64,
pub has_fix_y: bool,
pub fix_y: f64,
}
#[derive(serde::Serialize, serde::Deserialize)]
#[arael::model]
pub struct LineConstraints {
pub horizontal: bool,
pub vertical: bool,
pub has_length: bool,
pub length: f64,
#[serde(default)]
pub has_angle: bool,
#[serde(default)]
pub target_angle: f64,
#[serde(skip, default = "default_dir_sign_nan")]
pub h_dir_sign: f64,
#[serde(skip, default = "default_dir_sign_nan")]
pub v_dir_sign: f64,
}
fn default_dir_sign_nan() -> f64 { f64::NAN }
#[derive(serde::Serialize, serde::Deserialize)]
#[arael::model]
pub struct ArcConstraints {
pub has_target_radius: bool,
pub target_radius: f64,
#[serde(default)]
pub has_target_radius_b: bool,
#[serde(default)]
pub target_radius_b: f64,
#[serde(default)]
pub has_target_sweep: bool,
#[serde(default)]
pub target_sweep: f64,
#[serde(default = "default_sweep_sign")]
pub sweep_sign: f64,
#[serde(default)]
pub has_target_rotation: bool,
#[serde(default)]
pub target_rotation: f64,
}
fn default_sweep_sign() -> f64 { 1.0 }
fn default_ccw() -> bool { true }
fn default_param_zero() -> arael::model::Param<f64> { arael::model::Param::fixed(0.0) }
#[derive(serde::Serialize, serde::Deserialize)]
#[arael::model]
#[arael(constraint(hb, name = "drift", {
let d = point.pos - point.pos_value;
[d.x * sketch.drift_isigma, d.y * sketch.drift_isigma]
}))]
#[arael(constraint(hb, guard = self.drag_pull > 0.0, name = "drag_pull", {
let d = point.pos - point.pos_value;
[d.x * point.drag_pull, d.y * point.drag_pull]
}))]
#[arael(constraint(hb, guard = self.constraints.has_fix_x, name = "fix_x", {
[(point.pos.x - point.constraints.fix_x) * sketch.constraint_isigma]
}))]
#[arael(constraint(hb, guard = self.constraints.has_fix_y, name = "fix_y", {
[(point.pos.y - point.constraints.fix_y) * sketch.constraint_isigma]
}))]
pub struct Point {
pub pos: Param<vect2d>,
pub constraints: PointConstraints,
pub helper: bool,
#[serde(default)]
pub quiet: bool,
pub name: String,
#[serde(skip)]
pub drag_pull: f64,
#[arael(constraint_index)]
#[serde(skip)]
pub cid: u32,
#[serde(skip)]
pub hb: SelfBlock<Point>,
}
#[derive(serde::Serialize, serde::Deserialize)]
#[arael::model]
#[arael(constraint(hb, name = "drift", {
let d1 = line.p1 - line.p1_value;
let d2 = line.p2 - line.p2_value;
[d1.x * sketch.drift_isigma, d1.y * sketch.drift_isigma,
d2.x * sketch.drift_isigma, d2.y * sketch.drift_isigma]
}))]
#[arael(constraint(hb, name = "drift_length", {
let dx = line.p2.x - line.p1.x;
let dy = line.p2.y - line.p1.y;
let dx0 = line.p2_value.x - line.p1_value.x;
let dy0 = line.p2_value.y - line.p1_value.y;
[(sqrt(dx * dx + dy * dy + 1e-6) - sqrt(dx0 * dx0 + dy0 * dy0 + 1e-6)) * sketch.drift_isigma]
}))]
#[arael(constraint(hb, name = "drift_angle", {
let angle = safe_atan2(line.p2.y - line.p1.y, line.p2.x - line.p1.x);
let angle0 = safe_atan2(line.p2_value.y - line.p1_value.y, line.p2_value.x - line.p1_value.x);
[rad_diff(angle, angle0) * sketch.drift_isigma]
}))]
#[arael(constraint(hb, guard = self.constraints.horizontal, name = "horizontal", {
[(line.p1.y - line.p2.y) * sketch.constraint_isigma]
}))]
#[arael(constraint(hb, guard = self.constraints.horizontal, name = "horizontal_dir", {
let d = -line.constraints.h_dir_sign * (line.p2.x - line.p1.x);
[heaviside(d) * d * sketch.constraint_isigma]
}))]
#[arael(constraint(hb, guard = self.constraints.vertical, name = "vertical", {
[(line.p1.x - line.p2.x) * sketch.constraint_isigma]
}))]
#[arael(constraint(hb, guard = self.constraints.vertical, name = "vertical_dir", {
let d = -line.constraints.v_dir_sign * (line.p2.y - line.p1.y);
[heaviside(d) * d * sketch.constraint_isigma]
}))]
#[arael(constraint(hb, guard = self.constraints.has_length, name = "length_target", {
let dx = line.p2.x - line.p1.x;
let dy = line.p2.y - line.p1.y;
[(sqrt(dx * dx + dy * dy) - line.constraints.length) * sketch.constraint_isigma]
}))]
#[arael(constraint(hb, guard = self.constraints.has_angle, name = "angle_target", {
[(atan2(line.p2.y - line.p1.y, line.p2.x - line.p1.x) - line.constraints.target_angle) * sketch.constraint_isigma]
}))]
#[arael(constraint(hb, name = "min_length", {
let dx = line.p2.x - line.p1.x;
let dy = line.p2.y - line.p1.y;
let d = sketch.min_length * sketch.min_length - (dx * dx + dy * dy);
[heaviside(d) * d * sketch.constraint_isigma * sketch.constraint_isigma]
}))]
pub struct Line {
pub p1: Param<vect2d>,
pub p2: Param<vect2d>,
pub constraints: LineConstraints,
pub style: LineStyle,
#[serde(default)]
pub construction: bool,
#[serde(default)]
pub quiet: bool,
pub name: String,
#[arael(constraint_index)]
#[serde(skip)]
pub cid: u32,
#[serde(skip)]
pub hb: SelfBlock<Line>,
}
#[derive(serde::Serialize, serde::Deserialize)]
#[arael::model]
#[arael(constraint(hb, name = "drift", {
let dc = arc.center - arc.center_value;
let dr = arc.radius - arc.radius_value;
let drb = arc.radius_b - arc.radius_b_value;
let drot = arc.rotation - arc.rotation_value;
let dsa = arc.start_angle - arc.start_angle_value;
let dea = arc.end_angle - arc.end_angle_value;
[dc.x * sketch.drift_isigma, dc.y * sketch.drift_isigma,
dr * sketch.drift_isigma, drb * sketch.drift_isigma,
drot * sketch.drift_isigma,
dsa * sketch.drift_isigma, dea * sketch.drift_isigma]
}))]
#[arael(constraint(hb, guard = self.constraints.has_target_radius, name = "radius_target", {
[(arc.radius - arc.constraints.target_radius) * sketch.constraint_isigma]
}))]
#[arael(constraint(hb, guard = self.constraints.has_target_radius_b, name = "radius_b_target", {
[(arc.radius_b - arc.constraints.target_radius_b) * sketch.constraint_isigma]
}))]
#[arael(constraint(hb, guard = !self.is_ellipse, name = "radius_b_eq_radius", {
[(arc.radius_b - arc.radius) * sketch.constraint_isigma]
}))]
#[arael(constraint(hb, name = "min_radius", {
let d = sketch.min_length - arc.radius;
[heaviside(d) * d * d * sketch.constraint_isigma * sketch.constraint_isigma]
}))]
#[arael(constraint(hb, guard = self.is_ellipse, name = "min_radius_b", {
let d = sketch.min_length - arc.radius_b;
[heaviside(d) * d * d * sketch.constraint_isigma * sketch.constraint_isigma]
}))]
#[arael(constraint(hb, guard = self.constraints.has_target_sweep, name = "sweep", {
[(arc.end_angle - arc.start_angle - arc.constraints.sweep_sign * arc.constraints.target_sweep) * arc.radius * sketch.constraint_isigma]
}))]
#[arael(constraint(hb, guard = self.constraints.has_target_rotation && self.is_ellipse, name = "rotation", {
[(arc.rotation - arc.constraints.target_rotation) * sketch.constraint_isigma]
}))]
pub struct Arc {
pub center: Param<vect2d>,
pub radius: Param<f64>,
#[serde(default = "default_param_zero")]
pub radius_b: Param<f64>,
#[serde(default = "default_param_zero")]
pub rotation: Param<f64>,
pub start_angle: Param<f64>,
pub end_angle: Param<f64>,
pub closed: bool,
#[serde(default)]
pub is_ellipse: bool,
#[serde(default = "default_ccw")]
pub ccw: bool,
pub style: LineStyle,
#[serde(default)]
pub construction: bool,
#[serde(default)]
pub quiet: bool,
pub name: String,
pub constraints: ArcConstraints,
#[arael(constraint_index)]
#[serde(skip)]
pub cid: u32,
#[serde(skip)]
pub hb: SelfBlock<Arc>,
}