Nadro/adhoc/stdlib arcTo (three point arc) (#4485)
* feat: implementing arcTo in standard library, first pass * feat: computing center and radius for arcto * fix: updating comment for arcTo * fix: cargo fmt fix * fix: bug, the x was used twice! * fix: Cleaning up some code and adding more comments * fix: this has to be removed * fix: resolved merge conflicts with main and updated the codebase to remove the JSON stuff * fix: addressing cargo clippy issues * fix: typos * fix: adding generated docs * Update doc test snapshots --------- Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
This commit is contained in:
File diff suppressed because one or more lines are too long
@ -20,6 +20,7 @@ layout: manual
|
|||||||
* [`angledLineToX`](kcl/angledLineToX)
|
* [`angledLineToX`](kcl/angledLineToX)
|
||||||
* [`angledLineToY`](kcl/angledLineToY)
|
* [`angledLineToY`](kcl/angledLineToY)
|
||||||
* [`arc`](kcl/arc)
|
* [`arc`](kcl/arc)
|
||||||
|
* [`arcTo`](kcl/arcTo)
|
||||||
* [`asin`](kcl/asin)
|
* [`asin`](kcl/asin)
|
||||||
* [`assert`](kcl/assert)
|
* [`assert`](kcl/assert)
|
||||||
* [`assertEqual`](kcl/assertEqual)
|
* [`assertEqual`](kcl/assertEqual)
|
||||||
|
4100
docs/kcl/std.json
4100
docs/kcl/std.json
File diff suppressed because it is too large
Load Diff
@ -1071,6 +1071,15 @@ impl<'a> FromKclValue<'a> for super::sketch::ArcData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> FromKclValue<'a> for super::sketch::ArcToData {
|
||||||
|
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
|
||||||
|
let obj = arg.as_object()?;
|
||||||
|
let_field_of!(obj, end);
|
||||||
|
let_field_of!(obj, interior);
|
||||||
|
Some(Self { end, interior })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> FromKclValue<'a> for super::revolve::RevolveData {
|
impl<'a> FromKclValue<'a> for super::revolve::RevolveData {
|
||||||
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
|
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
|
||||||
let obj = arg.as_object()?;
|
let obj = arg.as_object()?;
|
||||||
|
@ -91,6 +91,7 @@ lazy_static! {
|
|||||||
Box::new(crate::std::sketch::ProfileStart),
|
Box::new(crate::std::sketch::ProfileStart),
|
||||||
Box::new(crate::std::sketch::Close),
|
Box::new(crate::std::sketch::Close),
|
||||||
Box::new(crate::std::sketch::Arc),
|
Box::new(crate::std::sketch::Arc),
|
||||||
|
Box::new(crate::std::sketch::ArcTo),
|
||||||
Box::new(crate::std::sketch::TangentialArc),
|
Box::new(crate::std::sketch::TangentialArc),
|
||||||
Box::new(crate::std::sketch::TangentialArcTo),
|
Box::new(crate::std::sketch::TangentialArcTo),
|
||||||
Box::new(crate::std::sketch::TangentialArcToRelative),
|
Box::new(crate::std::sketch::TangentialArcToRelative),
|
||||||
|
@ -1486,6 +1486,17 @@ pub enum ArcData {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Data to draw a three point arc (arcTo).
|
||||||
|
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
||||||
|
#[ts(export)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct ArcToData {
|
||||||
|
/// End point of the arc. A point in 3D space
|
||||||
|
pub end: [f64; 2],
|
||||||
|
/// Interior point of the arc. A point in 3D space
|
||||||
|
pub interior: [f64; 2],
|
||||||
|
}
|
||||||
|
|
||||||
/// Draw an arc.
|
/// Draw an arc.
|
||||||
pub async fn arc(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
pub async fn arc(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||||
let (data, sketch, tag): (ArcData, Sketch, Option<TagNode>) = args.get_data_and_sketch_and_tag()?;
|
let (data, sketch, tag): (ArcData, Sketch, Option<TagNode>) = args.get_data_and_sketch_and_tag()?;
|
||||||
@ -1516,7 +1527,7 @@ pub async fn arc(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kcl
|
|||||||
/// radius: 16
|
/// radius: 16
|
||||||
/// }, %)
|
/// }, %)
|
||||||
/// |> close(%)
|
/// |> close(%)
|
||||||
// const example = extrude(10, exampleSketch)
|
/// const example = extrude(10, exampleSketch)
|
||||||
/// ```
|
/// ```
|
||||||
#[stdlib {
|
#[stdlib {
|
||||||
name = "arc",
|
name = "arc",
|
||||||
@ -1595,6 +1606,104 @@ pub(crate) async fn inner_arc(
|
|||||||
Ok(new_sketch)
|
Ok(new_sketch)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Draw a three point arc.
|
||||||
|
pub async fn arc_to(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||||
|
let (data, sketch, tag): (ArcToData, Sketch, Option<TagNode>) = args.get_data_and_sketch_and_tag()?;
|
||||||
|
|
||||||
|
let new_sketch = inner_arc_to(data, sketch, tag, exec_state, args).await?;
|
||||||
|
Ok(KclValue::Sketch {
|
||||||
|
value: Box::new(new_sketch),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Draw a 3 point arc.
|
||||||
|
///
|
||||||
|
/// The arc is constructed such that the start point is the current position of the sketch and two more points defined as the end and interior point.
|
||||||
|
/// The interior point is placed between the start point and end point. The radius of the arc will be controlled by how far the interior point is placed from
|
||||||
|
/// the start and end.
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// const exampleSketch = startSketchOn('XZ')
|
||||||
|
/// |> startProfileAt([0, 0], %)
|
||||||
|
/// |> arcTo({
|
||||||
|
/// end: [10,0],
|
||||||
|
/// interior: [5,5]
|
||||||
|
/// }, %)
|
||||||
|
/// |> close(%)
|
||||||
|
/// const example = extrude(10, exampleSketch)
|
||||||
|
/// ```
|
||||||
|
#[stdlib {
|
||||||
|
name = "arcTo",
|
||||||
|
}]
|
||||||
|
pub(crate) async fn inner_arc_to(
|
||||||
|
data: ArcToData,
|
||||||
|
sketch: Sketch,
|
||||||
|
tag: Option<TagNode>,
|
||||||
|
exec_state: &mut ExecState,
|
||||||
|
args: Args,
|
||||||
|
) -> Result<Sketch, KclError> {
|
||||||
|
let from: Point2d = sketch.current_pen_position()?;
|
||||||
|
let id = exec_state.id_generator.next_uuid();
|
||||||
|
|
||||||
|
// The start point is taken from the path you are extending.
|
||||||
|
args.batch_modeling_cmd(
|
||||||
|
id,
|
||||||
|
ModelingCmd::from(mcmd::ExtendPath {
|
||||||
|
path: sketch.id.into(),
|
||||||
|
segment: PathSegment::ArcTo {
|
||||||
|
end: kcmc::shared::Point3d {
|
||||||
|
x: LengthUnit(data.end[0]),
|
||||||
|
y: LengthUnit(data.end[1]),
|
||||||
|
z: LengthUnit(0.0),
|
||||||
|
},
|
||||||
|
interior: kcmc::shared::Point3d {
|
||||||
|
x: LengthUnit(data.interior[0]),
|
||||||
|
y: LengthUnit(data.interior[1]),
|
||||||
|
z: LengthUnit(0.0),
|
||||||
|
},
|
||||||
|
relative: false,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let start = [from.x, from.y];
|
||||||
|
let interior = [data.interior[0], data.interior[1]];
|
||||||
|
let end = [data.end[0], data.end[1]];
|
||||||
|
|
||||||
|
// compute the center of the circle since we do not have the value returned from the engine
|
||||||
|
let center = calculate_circle_center(start, interior, end);
|
||||||
|
|
||||||
|
// compute the radius since we do not have the value returned from the engine
|
||||||
|
// Pick any of the 3 points since they all lie along the circle
|
||||||
|
let sum_of_square_differences =
|
||||||
|
(center[0] - start[0] * center[0] - start[0]) + (center[1] - start[1] * center[1] - start[1]);
|
||||||
|
let radius = sum_of_square_differences.sqrt();
|
||||||
|
|
||||||
|
let current_path = Path::Arc {
|
||||||
|
base: BasePath {
|
||||||
|
from: from.into(),
|
||||||
|
to: data.end,
|
||||||
|
tag: tag.clone(),
|
||||||
|
geo_meta: GeoMeta {
|
||||||
|
id,
|
||||||
|
metadata: args.source_range.into(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
center,
|
||||||
|
radius,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut new_sketch = sketch.clone();
|
||||||
|
if let Some(tag) = &tag {
|
||||||
|
new_sketch.add_tag(tag, ¤t_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
new_sketch.paths.push(current_path);
|
||||||
|
|
||||||
|
Ok(new_sketch)
|
||||||
|
}
|
||||||
|
|
||||||
/// Data to draw a tangential arc.
|
/// Data to draw a tangential arc.
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, ts_rs::TS)]
|
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, ts_rs::TS)]
|
||||||
#[ts(export)]
|
#[ts(export)]
|
||||||
@ -1914,6 +2023,42 @@ async fn inner_tangential_arc_to_relative(
|
|||||||
Ok(new_sketch)
|
Ok(new_sketch)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculate the center of 3 points
|
||||||
|
// To calculate the center of the 3 point circle 2 perpendicular lines are created
|
||||||
|
// These perpendicular lines will intersect at the center of the circle.
|
||||||
|
fn calculate_circle_center(p1: [f64; 2], p2: [f64; 2], p3: [f64; 2]) -> [f64; 2] {
|
||||||
|
// y2 - y1
|
||||||
|
let y_2_1 = p2[1] - p1[1];
|
||||||
|
// y3 - y2
|
||||||
|
let y_3_2 = p3[1] - p2[1];
|
||||||
|
// x2 - x1
|
||||||
|
let x_2_1 = p2[0] - p1[0];
|
||||||
|
// x3 - x2
|
||||||
|
let x_3_2 = p3[0] - p2[0];
|
||||||
|
|
||||||
|
// Slope of two perpendicular lines
|
||||||
|
let slope_a = y_2_1 / x_2_1;
|
||||||
|
let slope_b = y_3_2 / x_3_2;
|
||||||
|
|
||||||
|
// Values for line intersection
|
||||||
|
// y1 - y3
|
||||||
|
let y_1_3 = p1[1] - p3[1];
|
||||||
|
// x1 + x2
|
||||||
|
let x_1_2 = p1[0] + p2[0];
|
||||||
|
// x2 + x3
|
||||||
|
let x_2_3 = p2[0] + p3[0];
|
||||||
|
// y1 + y2
|
||||||
|
let y_1_2 = p1[1] + p2[1];
|
||||||
|
|
||||||
|
// Solve for the intersection of these two lines
|
||||||
|
let numerator = (slope_a * slope_b * y_1_3) + (slope_b * x_1_2) - (slope_a * x_2_3);
|
||||||
|
let x = numerator / (2.0 * (slope_b - slope_a));
|
||||||
|
|
||||||
|
let y = ((-1.0 / slope_a) * (x - (x_1_2 / 2.0))) + (y_1_2 / 2.0);
|
||||||
|
|
||||||
|
[x, y]
|
||||||
|
}
|
||||||
|
|
||||||
/// Data to draw a bezier curve.
|
/// Data to draw a bezier curve.
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
||||||
#[ts(export)]
|
#[ts(export)]
|
||||||
@ -2090,7 +2235,7 @@ mod tests {
|
|||||||
|
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
use crate::{executor::TagIdentifier, std::sketch::PlaneData};
|
use crate::{executor::TagIdentifier, std::sketch::calculate_circle_center, std::sketch::PlaneData};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_deserialize_plane_data() {
|
fn test_deserialize_plane_data() {
|
||||||
@ -2161,4 +2306,11 @@ mod tests {
|
|||||||
crate::std::sketch::FaceTag::StartOrEnd(crate::std::sketch::StartOrEnd::Start)
|
crate::std::sketch::FaceTag::StartOrEnd(crate::std::sketch::StartOrEnd::Start)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_circle_center() {
|
||||||
|
let actual = calculate_circle_center([0.0, 0.0], [5.0, 5.0], [10.0, 0.0]);
|
||||||
|
assert_eq!(actual[0], 5.0);
|
||||||
|
assert_eq!(actual[1], 0.0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 50 KiB |
BIN
src/wasm-lib/kcl/tests/outputs/serial_test_example_arc_to0.png
Normal file
BIN
src/wasm-lib/kcl/tests/outputs/serial_test_example_arc_to0.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 63 KiB |
Reference in New Issue
Block a user