use coeffs in conic fn
This commit is contained in:
@ -1323,6 +1323,34 @@ impl<'a> FromKclValue<'a> for [TyF64; 3] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> FromKclValue<'a> for [TyF64; 6] {
|
||||||
|
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
|
||||||
|
match arg {
|
||||||
|
KclValue::Tuple { value, meta: _ } | KclValue::HomArray { value, .. } => {
|
||||||
|
if value.len() != 6 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let v0 = value.first()?;
|
||||||
|
let v1 = value.get(1)?;
|
||||||
|
let v2 = value.get(2)?;
|
||||||
|
let v3 = value.get(3)?;
|
||||||
|
let v4 = value.get(4)?;
|
||||||
|
let v5 = value.get(5)?;
|
||||||
|
let array = [
|
||||||
|
v0.as_ty_f64()?,
|
||||||
|
v1.as_ty_f64()?,
|
||||||
|
v2.as_ty_f64()?,
|
||||||
|
v3.as_ty_f64()?,
|
||||||
|
v4.as_ty_f64()?,
|
||||||
|
v5.as_ty_f64()?,
|
||||||
|
];
|
||||||
|
Some(array)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> FromKclValue<'a> for Sketch {
|
impl<'a> FromKclValue<'a> for Sketch {
|
||||||
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
|
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
|
||||||
let KclValue::Sketch { value } = arg else {
|
let KclValue::Sketch { value } = arg else {
|
||||||
|
@ -32,6 +32,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::utils::untype_array;
|
||||||
use super::utils::untype_point;
|
use super::utils::untype_point;
|
||||||
|
|
||||||
/// A tag for a face.
|
/// A tag for a face.
|
||||||
@ -2850,11 +2851,9 @@ pub(crate) async fn inner_hyperbolic(
|
|||||||
pub async fn parabolic_point(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
pub async fn parabolic_point(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||||
let x: Option<TyF64> = args.get_kw_arg_opt_typed("x", &RuntimeType::length(), exec_state)?;
|
let x: Option<TyF64> = args.get_kw_arg_opt_typed("x", &RuntimeType::length(), exec_state)?;
|
||||||
let y: Option<TyF64> = args.get_kw_arg_opt_typed("y", &RuntimeType::length(), exec_state)?;
|
let y: Option<TyF64> = args.get_kw_arg_opt_typed("y", &RuntimeType::length(), exec_state)?;
|
||||||
let coefficient_a: TyF64 = args.get_kw_arg_typed("a", &RuntimeType::count(), exec_state)?;
|
let coefficients: [TyF64; 3] = args.get_kw_arg_typed("coefficients", &RuntimeType::any_array(), exec_state)?;
|
||||||
let coefficient_b: TyF64 = args.get_kw_arg_typed("b", &RuntimeType::count(), exec_state)?;
|
|
||||||
let coefficient_c: TyF64 = args.get_kw_arg_typed("c", &RuntimeType::count(), exec_state)?;
|
|
||||||
|
|
||||||
let parabolic_point = inner_parabolic_point(x, y, coefficient_a, coefficient_b, coefficient_c, &args).await?;
|
let parabolic_point = inner_parabolic_point(x, y, &coefficients, &args).await?;
|
||||||
|
|
||||||
args.make_kcl_val_from_point(parabolic_point, exec_state.length_unit().into())
|
args.make_kcl_val_from_point(parabolic_point, exec_state.length_unit().into())
|
||||||
}
|
}
|
||||||
@ -2869,9 +2868,7 @@ pub async fn parabolic_point(exec_state: &mut ExecState, args: Args) -> Result<K
|
|||||||
name = "parabolicPoint",
|
name = "parabolicPoint",
|
||||||
unlabeled_first = false,
|
unlabeled_first = false,
|
||||||
args = {
|
args = {
|
||||||
a = { docs = "The coefficient a of the parabolic equation y = ax^2 + bx + c." },
|
coefficients = { docs = "The coefficients [a, b, c] of the parabolic equation y = ax^2 + bx + c." },
|
||||||
b = { docs = "The coefficient b of the parabolic equation y = ax^2 + bx + c." },
|
|
||||||
c = { docs = "The coefficient c of the parabolic equation y = ax^2 + bx + c." },
|
|
||||||
x = { docs = "The x value of the parabolic equation y = ax^2. Will calculate the point y that satisfies the equation and returns (x, y). Incompatible with `y`."},
|
x = { docs = "The x value of the parabolic equation y = ax^2. Will calculate the point y that satisfies the equation and returns (x, y). Incompatible with `y`."},
|
||||||
y = { docs = "The y value of the parabolic equation y = ax^2. Will calculate the point x that satisfies the equation and returns (x, y). Incompatible with `x`."},
|
y = { docs = "The y value of the parabolic equation y = ax^2. Will calculate the point x that satisfies the equation and returns (x, y). Incompatible with `x`."},
|
||||||
},
|
},
|
||||||
@ -2880,14 +2877,12 @@ pub async fn parabolic_point(exec_state: &mut ExecState, args: Args) -> Result<K
|
|||||||
async fn inner_parabolic_point(
|
async fn inner_parabolic_point(
|
||||||
x: Option<TyF64>,
|
x: Option<TyF64>,
|
||||||
y: Option<TyF64>,
|
y: Option<TyF64>,
|
||||||
a: TyF64,
|
coefficients: &[TyF64; 3],
|
||||||
b: TyF64,
|
|
||||||
c: TyF64,
|
|
||||||
args: &Args,
|
args: &Args,
|
||||||
) -> Result<[f64; 2], KclError> {
|
) -> Result<[f64; 2], KclError> {
|
||||||
let a = a.n;
|
let a = coefficients[0].n;
|
||||||
let b = b.n;
|
let b = coefficients[1].n;
|
||||||
let c = c.n;
|
let c = coefficients[2].n;
|
||||||
if let Some(x) = x {
|
if let Some(x) = x {
|
||||||
Ok((x.n, a * x.n.powf(2.0) + b * x.n + c).into())
|
Ok((x.n, a * x.n.powf(2.0) + b * x.n + c).into())
|
||||||
} else if let Some(y) = y {
|
} else if let Some(y) = y {
|
||||||
@ -2906,25 +2901,13 @@ pub async fn parabolic(exec_state: &mut ExecState, args: Args) -> Result<KclValu
|
|||||||
let sketch =
|
let sketch =
|
||||||
args.get_unlabeled_kw_arg_typed("sketch", &RuntimeType::Primitive(PrimitiveType::Sketch), exec_state)?;
|
args.get_unlabeled_kw_arg_typed("sketch", &RuntimeType::Primitive(PrimitiveType::Sketch), exec_state)?;
|
||||||
|
|
||||||
let coefficient_a: Option<TyF64> = args.get_kw_arg_opt_typed("a", &RuntimeType::count(), exec_state)?;
|
let coefficients: Option<[TyF64; 3]> =
|
||||||
let coefficient_b: Option<TyF64> = args.get_kw_arg_opt_typed("b", &RuntimeType::count(), exec_state)?;
|
args.get_kw_arg_opt_typed("coefficients", &RuntimeType::any_array(), exec_state)?;
|
||||||
let coefficient_c: Option<TyF64> = args.get_kw_arg_opt_typed("c", &RuntimeType::count(), exec_state)?;
|
|
||||||
let interior: Option<[TyF64; 2]> = args.get_kw_arg_opt_typed("interior", &RuntimeType::point2d(), exec_state)?;
|
let interior: Option<[TyF64; 2]> = args.get_kw_arg_opt_typed("interior", &RuntimeType::point2d(), exec_state)?;
|
||||||
let end: [TyF64; 2] = args.get_kw_arg_typed("end", &RuntimeType::point2d(), exec_state)?;
|
let end: [TyF64; 2] = args.get_kw_arg_typed("end", &RuntimeType::point2d(), exec_state)?;
|
||||||
let tag = args.get_kw_arg_opt(NEW_TAG_KW)?;
|
let tag = args.get_kw_arg_opt(NEW_TAG_KW)?;
|
||||||
|
|
||||||
let new_sketch = inner_parabolic(
|
let new_sketch = inner_parabolic(sketch, coefficients, interior, end, tag, exec_state, args).await?;
|
||||||
sketch,
|
|
||||||
coefficient_a,
|
|
||||||
coefficient_b,
|
|
||||||
coefficient_c,
|
|
||||||
interior,
|
|
||||||
end,
|
|
||||||
tag,
|
|
||||||
exec_state,
|
|
||||||
args,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
Ok(KclValue::Sketch {
|
Ok(KclValue::Sketch {
|
||||||
value: Box::new(new_sketch),
|
value: Box::new(new_sketch),
|
||||||
})
|
})
|
||||||
@ -2951,10 +2934,8 @@ fn parabolic_tangent(point: Point2d, a: f64, b: f64) -> [f64; 2] {
|
|||||||
unlabeled_first = true,
|
unlabeled_first = true,
|
||||||
args = {
|
args = {
|
||||||
sketch = { docs = "Which sketch should this path be added to?" },
|
sketch = { docs = "Which sketch should this path be added to?" },
|
||||||
a = { docs = "The coefficient a of the parabolic equation y = ax^2 + bx + c." },
|
coefficients = { docs = "The coefficienta [a, b, c] of the parabolic equation y = ax^2 + bx + c. Incompatible with `interior`." },
|
||||||
b = { docs = "The coefficient b of the parabolic equation y = ax^2 + bx + c." },
|
interior = { docs = "Any point between the arc's start and end?. Incompatible with `coefficients." },
|
||||||
c = { docs = "The coefficient c of the parabolic equation y = ax^2 + bx + c." },
|
|
||||||
interior = { docs = "Any point between the arc's start and end?" },
|
|
||||||
end = { docs = "Where should this arc end?" },
|
end = { docs = "Where should this arc end?" },
|
||||||
tag = { docs = "Create a new tag which refers to this line"},
|
tag = { docs = "Create a new tag which refers to this line"},
|
||||||
},
|
},
|
||||||
@ -2962,9 +2943,7 @@ fn parabolic_tangent(point: Point2d, a: f64, b: f64) -> [f64; 2] {
|
|||||||
}]
|
}]
|
||||||
pub(crate) async fn inner_parabolic(
|
pub(crate) async fn inner_parabolic(
|
||||||
sketch: Sketch,
|
sketch: Sketch,
|
||||||
a: Option<TyF64>,
|
coefficients: Option<[TyF64; 3]>,
|
||||||
b: Option<TyF64>,
|
|
||||||
c: Option<TyF64>,
|
|
||||||
interior: Option<[TyF64; 2]>,
|
interior: Option<[TyF64; 2]>,
|
||||||
end: [TyF64; 2],
|
end: [TyF64; 2],
|
||||||
tag: Option<TagNode>,
|
tag: Option<TagNode>,
|
||||||
@ -2974,9 +2953,7 @@ pub(crate) async fn inner_parabolic(
|
|||||||
let from = sketch.current_pen_position()?;
|
let from = sketch.current_pen_position()?;
|
||||||
let id = exec_state.next_uuid();
|
let id = exec_state.next_uuid();
|
||||||
|
|
||||||
if (a.is_some() && b.is_some() && c.is_some() && interior.is_some())
|
if (coefficients.is_some() && interior.is_some()) || (coefficients.is_none() && interior.is_none()) {
|
||||||
|| (a.is_none() && b.is_none() && c.is_none() && interior.is_none())
|
|
||||||
{
|
|
||||||
return Err(KclError::Type(KclErrorDetails::new(
|
return Err(KclError::Type(KclErrorDetails::new(
|
||||||
"Invalid combination of arguments. Either provide (a, b, c) or (interior)".to_owned(),
|
"Invalid combination of arguments. Either provide (a, b, c) or (interior)".to_owned(),
|
||||||
vec![args.source_range],
|
vec![args.source_range],
|
||||||
@ -2993,9 +2970,7 @@ pub(crate) async fn inner_parabolic(
|
|||||||
inner_parabolic_point(
|
inner_parabolic_point(
|
||||||
Some(TyF64::count(0.5 * (from.x + end[0]))),
|
Some(TyF64::count(0.5 * (from.x + end[0]))),
|
||||||
None,
|
None,
|
||||||
a.clone().unwrap(),
|
coefficients.as_ref().unwrap(),
|
||||||
b.clone().unwrap(),
|
|
||||||
c.clone().unwrap(),
|
|
||||||
&args,
|
&args,
|
||||||
)
|
)
|
||||||
.await?,
|
.await?,
|
||||||
@ -3008,9 +2983,9 @@ pub(crate) async fn inner_parabolic(
|
|||||||
units: from.units,
|
units: from.units,
|
||||||
};
|
};
|
||||||
|
|
||||||
let (a, b, _c) = match (a, b, c) {
|
let (a, b, _c) = if let Some([a, b, c]) = coefficients {
|
||||||
(Some(a), Some(b), Some(c)) => (a.n, b.n, c.n),
|
(a.n, b.n, c.n)
|
||||||
_ => {
|
} else {
|
||||||
// Any three points is enough to uniquely define a parabola
|
// Any three points is enough to uniquely define a parabola
|
||||||
let denom = (from.x - interior[0]) * (from.x - end_point.x) * (interior[0] - end_point.x);
|
let denom = (from.x - interior[0]) * (from.x - end_point.x) * (interior[0] - end_point.x);
|
||||||
let a = (end_point.x * (interior[1] - from.y)
|
let a = (end_point.x * (interior[1] - from.y)
|
||||||
@ -3027,7 +3002,6 @@ pub(crate) async fn inner_parabolic(
|
|||||||
/ denom;
|
/ denom;
|
||||||
|
|
||||||
(a, b, c)
|
(a, b, c)
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let start_tangent = parabolic_tangent(from, a, b);
|
let start_tangent = parabolic_tangent(from, a, b);
|
||||||
@ -3071,6 +3045,16 @@ pub(crate) async fn inner_parabolic(
|
|||||||
Ok(new_sketch)
|
Ok(new_sketch)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn conic_tangent(coefficients: [f64; 6], point: [f64; 2]) -> [f64; 2] {
|
||||||
|
let [a, b, c, d, e, _] = coefficients;
|
||||||
|
|
||||||
|
(
|
||||||
|
c * point[0] + 2.0 * b * point[1] + e,
|
||||||
|
-(2.0 * a * point[0] + c * point[1] + d),
|
||||||
|
)
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
/// Draw a conic section
|
/// Draw a conic section
|
||||||
pub async fn conic(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
pub async fn conic(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||||
let sketch =
|
let sketch =
|
||||||
@ -3078,12 +3062,26 @@ pub async fn conic(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
|||||||
|
|
||||||
let start_tangent: Option<[TyF64; 2]> =
|
let start_tangent: Option<[TyF64; 2]> =
|
||||||
args.get_kw_arg_opt_typed("startTangent", &RuntimeType::point2d(), exec_state)?;
|
args.get_kw_arg_opt_typed("startTangent", &RuntimeType::point2d(), exec_state)?;
|
||||||
let end_tangent: [TyF64; 2] = args.get_kw_arg_typed("endTangent", &RuntimeType::point2d(), exec_state)?;
|
let end_tangent: Option<[TyF64; 2]> =
|
||||||
|
args.get_kw_arg_opt_typed("endTangent", &RuntimeType::point2d(), exec_state)?;
|
||||||
let end: [TyF64; 2] = args.get_kw_arg_typed("end", &RuntimeType::point2d(), exec_state)?;
|
let end: [TyF64; 2] = args.get_kw_arg_typed("end", &RuntimeType::point2d(), exec_state)?;
|
||||||
let interior: [TyF64; 2] = args.get_kw_arg_typed("interior", &RuntimeType::point2d(), exec_state)?;
|
let interior: [TyF64; 2] = args.get_kw_arg_typed("interior", &RuntimeType::point2d(), exec_state)?;
|
||||||
|
let coefficients: Option<[TyF64; 6]> =
|
||||||
|
args.get_kw_arg_opt_typed("coefficients", &RuntimeType::any_array(), exec_state)?;
|
||||||
let tag = args.get_kw_arg_opt(NEW_TAG_KW)?;
|
let tag = args.get_kw_arg_opt(NEW_TAG_KW)?;
|
||||||
|
|
||||||
let new_sketch = inner_conic(sketch, start_tangent, end, end_tangent, interior, tag, exec_state, args).await?;
|
let new_sketch = inner_conic(
|
||||||
|
sketch,
|
||||||
|
start_tangent,
|
||||||
|
end,
|
||||||
|
end_tangent,
|
||||||
|
interior,
|
||||||
|
coefficients,
|
||||||
|
tag,
|
||||||
|
exec_state,
|
||||||
|
args,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
Ok(KclValue::Sketch {
|
Ok(KclValue::Sketch {
|
||||||
value: Box::new(new_sketch),
|
value: Box::new(new_sketch),
|
||||||
})
|
})
|
||||||
@ -3108,7 +3106,8 @@ pub async fn conic(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
|||||||
sketch = { docs = "Which sketch should this path be added to?" },
|
sketch = { docs = "Which sketch should this path be added to?" },
|
||||||
start_tangent = { docs = "The tangent of the conic at the start point (the end of the previous path segement)" },
|
start_tangent = { docs = "The tangent of the conic at the start point (the end of the previous path segement)" },
|
||||||
end_tangent = { docs = "The tangent of the conic at the end point" },
|
end_tangent = { docs = "The tangent of the conic at the end point" },
|
||||||
interior = { docs = "Any point between the arc's start and end?" },
|
interior = { docs = "Any point between the arc's start and end? Incompatible with `coefficients`." },
|
||||||
|
coefficients = { docs = "The coefficients [a, b, c, d, e, f] of the generic conic equation ax^2 + by^2 + cxy + dx + ey + f = 0. Incompatible with `endTangent`."},
|
||||||
end = { docs = "Where should this arc end?" },
|
end = { docs = "Where should this arc end?" },
|
||||||
tag = { docs = "Create a new tag which refers to this line"},
|
tag = { docs = "Create a new tag which refers to this line"},
|
||||||
},
|
},
|
||||||
@ -3119,29 +3118,45 @@ pub(crate) async fn inner_conic(
|
|||||||
sketch: Sketch,
|
sketch: Sketch,
|
||||||
start_tangent: Option<[TyF64; 2]>,
|
start_tangent: Option<[TyF64; 2]>,
|
||||||
end: [TyF64; 2],
|
end: [TyF64; 2],
|
||||||
end_tangent: [TyF64; 2],
|
end_tangent: Option<[TyF64; 2]>,
|
||||||
interior: [TyF64; 2],
|
interior: [TyF64; 2],
|
||||||
|
coefficients: Option<[TyF64; 6]>,
|
||||||
tag: Option<TagNode>,
|
tag: Option<TagNode>,
|
||||||
exec_state: &mut ExecState,
|
exec_state: &mut ExecState,
|
||||||
args: Args,
|
args: Args,
|
||||||
) -> Result<Sketch, KclError> {
|
) -> Result<Sketch, KclError> {
|
||||||
let from: Point2d = sketch.current_pen_position()?;
|
let from: Point2d = sketch.current_pen_position()?;
|
||||||
let id = exec_state.next_uuid();
|
let id = exec_state.next_uuid();
|
||||||
let (end_tangent, _) = untype_point(end_tangent);
|
|
||||||
let (end, _) = untype_point(end);
|
if (coefficients.is_some() && (start_tangent.is_some() || end_tangent.is_some()))
|
||||||
|
|| (coefficients.is_none() && (start_tangent.is_none() && end_tangent.is_none()))
|
||||||
|
{
|
||||||
|
return Err(KclError::Type(KclErrorDetails::new(
|
||||||
|
"Invalid combination of arguments. Either provide coefficients or interior".to_owned(),
|
||||||
|
vec![args.source_range],
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
let (end, _) = untype_array(end);
|
||||||
let (interior, _) = untype_point(interior);
|
let (interior, _) = untype_point(interior);
|
||||||
|
|
||||||
let (start_tangent, _) = if let Some(start_tangent) = start_tangent {
|
let (start_tangent, end_tangent) = if let Some(coeffs) = coefficients {
|
||||||
untype_point(start_tangent)
|
let (coeffs, _) = untype_array(coeffs);
|
||||||
|
(conic_tangent(coeffs, [from.x, from.y]), conic_tangent(coeffs, end))
|
||||||
|
} else {
|
||||||
|
let start = if let Some(start_tangent) = start_tangent {
|
||||||
|
let (start, _) = untype_point(start_tangent);
|
||||||
|
start
|
||||||
} else {
|
} else {
|
||||||
let previous_point = sketch
|
let previous_point = sketch
|
||||||
.get_tangential_info_from_paths()
|
.get_tangential_info_from_paths()
|
||||||
.tan_previous_point(from.ignore_units());
|
.tan_previous_point(from.ignore_units());
|
||||||
let from = from.ignore_units();
|
let from = from.ignore_units();
|
||||||
(
|
[from[0] - previous_point[0], from[1] - previous_point[1]]
|
||||||
[from[0] - previous_point[0], from[1] - previous_point[1]],
|
};
|
||||||
NumericType::Any,
|
|
||||||
)
|
let (end_tan, _) = untype_point(end_tangent.unwrap());
|
||||||
|
(start, end_tan)
|
||||||
};
|
};
|
||||||
|
|
||||||
args.batch_modeling_cmd(
|
args.batch_modeling_cmd(
|
||||||
|
@ -10,6 +10,15 @@ pub(crate) fn untype_point(p: [TyF64; 2]) -> ([f64; 2], NumericType) {
|
|||||||
([x, y], ty)
|
([x, y], ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn untype_array<const N: usize>(p: [TyF64; N]) -> ([f64; N], NumericType) {
|
||||||
|
let (vec, ty) = NumericType::combine_eq_array(&p);
|
||||||
|
(
|
||||||
|
vec.try_into()
|
||||||
|
.unwrap_or_else(|v: Vec<f64>| panic!("Expected a Vec of length {} but it was {}", N, v.len())),
|
||||||
|
ty,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn point_to_mm(p: [TyF64; 2]) -> [f64; 2] {
|
pub(crate) fn point_to_mm(p: [TyF64; 2]) -> [f64; 2] {
|
||||||
[p[0].to_mm(), p[1].to_mm()]
|
[p[0].to_mm(), p[1].to_mm()]
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user