adds tangentalArc and tangentalArcTo to the stdlib (#748)

* start of tangental arc

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* update docs

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fixes

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
This commit is contained in:
Jess Frazelle
2023-09-29 14:41:14 -07:00
committed by GitHub
parent a367be4e2b
commit 83907fa9db
11 changed files with 2452 additions and 5 deletions

File diff suppressed because it is too large Load Diff

View File

@ -50,6 +50,8 @@
* [`sqrt`](#sqrt)
* [`startSketchAt`](#startSketchAt)
* [`tan`](#tan)
* [`tangentalArc`](#tangentalArc)
* [`tangentalArcTo`](#tangentalArcTo)
* [`tau`](#tau)
* [`xLine`](#xLine)
* [`xLineTo`](#xLineTo)
@ -3234,6 +3236,320 @@ tan(num: number) -> number
### tangentalArc
Draw an arc.
```
tangentalArc(data: TangentalArcData, sketch_group: SketchGroup) -> SketchGroup
```
#### Arguments
* `data`: `TangentalArcData` - Data to draw a tangental arc.
```
{
// Offset of the arc, in degrees.
offset: number,
// Radius of the arc. Not to be confused with Raiders of the Lost Ark.
radius: number,
} |
{
// The tag.
tag: string,
// Where the arc should end. Must lie in the same plane as the current path pen position. Must not be colinear with current path pen position.
to: [number],
} |
[number]
```
* `sketch_group`: `SketchGroup` - A sketch group is a collection of paths.
```
{
// The id of the sketch group.
id: uuid,
// The position of the sketch group.
position: [number],
// The rotation of the sketch group.
rotation: [number],
// The starting path.
start: {
// The from point.
from: [number],
// The name of the path.
name: string,
// The to point.
to: [number],
},
// The paths in the sketch group.
value: [{
// The from point.
from: [number],
// The name of the path.
name: string,
// The to point.
to: [number],
type: string,
} |
{
// The from point.
from: [number],
// The name of the path.
name: string,
// The to point.
to: [number],
type: string,
// The x coordinate.
x: number,
} |
{
// The from point.
from: [number],
// The name of the path.
name: string,
// The to point.
to: [number],
type: string,
// The x coordinate.
x: number,
// The y coordinate.
y: number,
} |
{
// The from point.
from: [number],
// The name of the path.
name: string,
// The to point.
to: [number],
type: string,
}],
}
```
#### Returns
* `SketchGroup` - A sketch group is a collection of paths.
```
{
// The id of the sketch group.
id: uuid,
// The position of the sketch group.
position: [number],
// The rotation of the sketch group.
rotation: [number],
// The starting path.
start: {
// The from point.
from: [number],
// The name of the path.
name: string,
// The to point.
to: [number],
},
// The paths in the sketch group.
value: [{
// The from point.
from: [number],
// The name of the path.
name: string,
// The to point.
to: [number],
type: string,
} |
{
// The from point.
from: [number],
// The name of the path.
name: string,
// The to point.
to: [number],
type: string,
// The x coordinate.
x: number,
} |
{
// The from point.
from: [number],
// The name of the path.
name: string,
// The to point.
to: [number],
type: string,
// The x coordinate.
x: number,
// The y coordinate.
y: number,
} |
{
// The from point.
from: [number],
// The name of the path.
name: string,
// The to point.
to: [number],
type: string,
}],
}
```
### tangentalArcTo
Draw an arc.
```
tangentalArcTo(data: TangentalArcToData, sketch_group: SketchGroup) -> SketchGroup
```
#### Arguments
* `data`: `TangentalArcToData` - Data to draw a tangental arc to a specific point.
```
{
// The tag.
tag: string,
// Where the arc should end. Must lie in the same plane as the current path pen position. Must not be colinear with current path pen position.
to: [number],
} |
[number]
```
* `sketch_group`: `SketchGroup` - A sketch group is a collection of paths.
```
{
// The id of the sketch group.
id: uuid,
// The position of the sketch group.
position: [number],
// The rotation of the sketch group.
rotation: [number],
// The starting path.
start: {
// The from point.
from: [number],
// The name of the path.
name: string,
// The to point.
to: [number],
},
// The paths in the sketch group.
value: [{
// The from point.
from: [number],
// The name of the path.
name: string,
// The to point.
to: [number],
type: string,
} |
{
// The from point.
from: [number],
// The name of the path.
name: string,
// The to point.
to: [number],
type: string,
// The x coordinate.
x: number,
} |
{
// The from point.
from: [number],
// The name of the path.
name: string,
// The to point.
to: [number],
type: string,
// The x coordinate.
x: number,
// The y coordinate.
y: number,
} |
{
// The from point.
from: [number],
// The name of the path.
name: string,
// The to point.
to: [number],
type: string,
}],
}
```
#### Returns
* `SketchGroup` - A sketch group is a collection of paths.
```
{
// The id of the sketch group.
id: uuid,
// The position of the sketch group.
position: [number],
// The rotation of the sketch group.
rotation: [number],
// The starting path.
start: {
// The from point.
from: [number],
// The name of the path.
name: string,
// The to point.
to: [number],
},
// The paths in the sketch group.
value: [{
// The from point.
from: [number],
// The name of the path.
name: string,
// The to point.
to: [number],
type: string,
} |
{
// The from point.
from: [number],
// The name of the path.
name: string,
// The to point.
to: [number],
type: string,
// The x coordinate.
x: number,
} |
{
// The from point.
from: [number],
// The name of the path.
name: string,
// The to point.
to: [number],
type: string,
// The x coordinate.
x: number,
// The y coordinate.
y: number,
} |
{
// The from point.
from: [number],
// The name of the path.
name: string,
// The to point.
to: [number],
type: string,
}],
}
```
### tau
Return the value of `tau`. The full circle constant (τ). Equal to 2π.

View File

@ -695,6 +695,20 @@ dependencies = [
"syn 2.0.37",
]
[[package]]
name = "derive-docs"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c357dec14992ba88803535217ed83d6f6cd80efcb8fa8e3f8a30a9b84fadc1c7"
dependencies = [
"convert_case",
"proc-macro2",
"quote",
"serde",
"serde_tokenstream",
"syn 2.0.37",
]
[[package]]
name = "diff"
version = "0.1.13"
@ -1376,7 +1390,7 @@ dependencies = [
[[package]]
name = "kcl-lib"
version = "0.1.31"
version = "0.1.32"
dependencies = [
"anyhow",
"async-recursion",
@ -1385,7 +1399,7 @@ dependencies = [
"clap",
"criterion",
"dashmap",
"derive-docs",
"derive-docs 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"expectorate",
"futures",
"itertools 0.11.0",

View File

@ -1,7 +1,7 @@
[package]
name = "kcl-lib"
description = "KittyCAD Language"
version = "0.1.31"
version = "0.1.32"
edition = "2021"
license = "MIT"
@ -13,8 +13,8 @@ async-recursion = "1.0.5"
async-trait = "0.1.73"
clap = { version = "4.4.6", features = ["cargo", "derive", "env", "unicode"], optional = true }
dashmap = "5.5.3"
#derive-docs = { version = "0.1.4" }
derive-docs = { path = "../derive-docs" }
derive-docs = { version = "0.1.4" }
#derive-docs = { path = "../derive-docs" }
kittycad = { version = "0.2.27", default-features = false, features = ["js"] }
lazy_static = "1.4.0"
parse-display = "0.8.2"

View File

@ -61,6 +61,8 @@ impl StdLib {
Box::new(crate::std::sketch::StartSketchAt),
Box::new(crate::std::sketch::Close),
Box::new(crate::std::sketch::Arc),
Box::new(crate::std::sketch::TangentalArc),
Box::new(crate::std::sketch::TangentalArcTo),
Box::new(crate::std::sketch::BezierCurve),
Box::new(crate::std::math::Cos),
Box::new(crate::std::math::Sin),

View File

@ -879,6 +879,214 @@ async fn inner_arc(data: ArcData, sketch_group: Box<SketchGroup>, args: Args) ->
Ok(new_sketch_group)
}
/// Data to draw a tangental arc.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, ts_rs::TS)]
#[ts(export)]
#[serde(rename_all = "camelCase", untagged)]
pub enum TangentalArcData {
RadiusAndOffset {
/// Radius of the arc.
/// Not to be confused with Raiders of the Lost Ark.
radius: f64,
/// Offset of the arc, in degrees.
offset: f64,
},
/// A point with a tag.
PointWithTag {
/// Where the arc should end. Must lie in the same plane as the current path pen position. Must not be colinear with current path pen position.
to: [f64; 2],
/// The tag.
tag: String,
},
/// A point where the arc should end. Must lie in the same plane as the current path pen position. Must not be colinear with current path pen position.
Point([f64; 2]),
}
/// Draw a tangental arc.
pub async fn tangental_arc(args: Args) -> Result<MemoryItem, KclError> {
let (data, sketch_group): (TangentalArcData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
let new_sketch_group = inner_tangental_arc(data, sketch_group, args).await?;
Ok(MemoryItem::SketchGroup(new_sketch_group))
}
/// Draw an arc.
#[stdlib {
name = "tangentalArc",
}]
async fn inner_tangental_arc(
data: TangentalArcData,
sketch_group: Box<SketchGroup>,
args: Args,
) -> Result<Box<SketchGroup>, KclError> {
let from: Point2d = sketch_group.get_coords_from_paths()?;
let id = uuid::Uuid::new_v4();
let to = match &data {
TangentalArcData::RadiusAndOffset { radius, offset } => {
// Calculate the end point from the angle and radius.
let end_angle = Angle::from_degrees(*offset);
let start_angle = Angle::from_degrees(0.0);
let (_, to) = arc_center_and_end(from, start_angle, end_angle, *radius);
args.send_modeling_cmd(
id,
ModelingCmd::ExtendPath {
path: sketch_group.id,
segment: kittycad::types::PathSegment::TangentialArc {
radius: *radius,
offset: kittycad::types::Angle {
unit: kittycad::types::UnitAngle::Degrees,
value: *offset,
},
},
},
)
.await?;
to.into()
}
TangentalArcData::PointWithTag { to, .. } => {
args.send_modeling_cmd(
id,
ModelingCmd::ExtendPath {
path: sketch_group.id,
segment: kittycad::types::PathSegment::TangentialArcTo {
angle_snap_increment: None,
to: kittycad::types::Point3D {
x: to[0],
y: to[1],
z: 0.0,
},
},
},
)
.await?;
*to
}
TangentalArcData::Point(to) => {
args.send_modeling_cmd(
id,
ModelingCmd::ExtendPath {
path: sketch_group.id,
segment: kittycad::types::PathSegment::TangentialArcTo {
angle_snap_increment: None,
to: kittycad::types::Point3D {
x: to[0],
y: to[1],
z: 0.0,
},
},
},
)
.await?;
*to
}
};
let to = [from.x + to[0], from.y + to[1]];
let current_path = Path::ToPoint {
base: BasePath {
from: from.into(),
to,
name: "".to_string(),
geo_meta: GeoMeta {
id,
metadata: args.source_range.into(),
},
},
};
let mut new_sketch_group = sketch_group.clone();
new_sketch_group.value.push(current_path);
Ok(new_sketch_group)
}
/// Data to draw a tangental arc to a specific point.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, ts_rs::TS)]
#[ts(export)]
#[serde(rename_all = "camelCase", untagged)]
pub enum TangentalArcToData {
/// A point with a tag.
PointWithTag {
/// Where the arc should end. Must lie in the same plane as the current path pen position. Must not be colinear with current path pen position.
to: [f64; 2],
/// The tag.
tag: String,
},
/// A point where the arc should end. Must lie in the same plane as the current path pen position. Must not be colinear with current path pen position.
Point([f64; 2]),
}
/// Draw a tangental arc to a specific point.
pub async fn tangental_arc_to(args: Args) -> Result<MemoryItem, KclError> {
let (data, sketch_group): (TangentalArcToData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
let new_sketch_group = inner_tangental_arc_to(data, sketch_group, args).await?;
Ok(MemoryItem::SketchGroup(new_sketch_group))
}
/// Draw an arc.
#[stdlib {
name = "tangentalArcTo",
}]
async fn inner_tangental_arc_to(
data: TangentalArcToData,
sketch_group: Box<SketchGroup>,
args: Args,
) -> Result<Box<SketchGroup>, KclError> {
let from: Point2d = sketch_group.get_coords_from_paths()?;
let to = match &data {
TangentalArcToData::PointWithTag { to, .. } => to,
TangentalArcToData::Point(to) => to,
};
let delta = [to[0] - from.x, to[1] - from.y];
let id = uuid::Uuid::new_v4();
args.send_modeling_cmd(
id,
ModelingCmd::ExtendPath {
path: sketch_group.id,
segment: kittycad::types::PathSegment::TangentialArcTo {
angle_snap_increment: None,
to: kittycad::types::Point3D {
x: delta[0],
y: delta[1],
z: 0.0,
},
},
},
)
.await?;
let current_path = Path::ToPoint {
base: BasePath {
from: from.into(),
to: *to,
name: if let TangentalArcToData::PointWithTag { tag, .. } = data {
tag.to_string()
} else {
"".to_string()
},
geo_meta: GeoMeta {
id,
metadata: args.source_range.into(),
},
},
};
let mut new_sketch_group = sketch_group.clone();
new_sketch_group.value.push(current_path);
Ok(new_sketch_group)
}
/// Data to draw a bezier curve.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]

View File

@ -10,6 +10,15 @@ pub struct Angle {
degrees: f64,
}
impl From<kittycad::types::Angle> for Angle {
fn from(angle: kittycad::types::Angle) -> Self {
match angle.unit {
kittycad::types::UnitAngle::Degrees => Self::from_degrees(angle.value),
kittycad::types::UnitAngle::Radians => Self::from_radians(angle.value),
}
}
}
impl Angle {
const ZERO: Self = Self { degrees: 0.0 };
/// Make an angle of the given degrees.

View File

@ -252,3 +252,42 @@ box(-20, -5, 10)"#;
let result = execute_and_snapshot(code).await.unwrap();
twenty_twenty::assert_image("tests/executor/outputs/negative_args.png", &result, 1.0);
}
#[tokio::test(flavor = "multi_thread")]
async fn test_basic_tangental_arc() {
let code = r#"const boxSketch = startSketchAt([0, 0])
|> line([0, 10], %)
|> tangentalArc({radius: 5, offset: 90}, %)
|> line([5, -15], %)
|> extrude(10, %)
"#;
let result = execute_and_snapshot(code).await.unwrap();
twenty_twenty::assert_image("tests/executor/outputs/tangental_arc.png", &result, 1.0);
}
#[tokio::test(flavor = "multi_thread")]
async fn test_basic_tangental_arc_with_point() {
let code = r#"const boxSketch = startSketchAt([0, 0])
|> line([0, 10], %)
|> tangentalArc([-5, 5], %)
|> line([5, -15], %)
|> extrude(10, %)
"#;
let result = execute_and_snapshot(code).await.unwrap();
twenty_twenty::assert_image("tests/executor/outputs/tangental_arc_with_point.png", &result, 1.0);
}
#[tokio::test(flavor = "multi_thread")]
async fn test_basic_tangental_arc_to() {
let code = r#"const boxSketch = startSketchAt([0, 0])
|> line([0, 10], %)
|> tangentalArcTo([-5, 15], %)
|> line([5, -15], %)
|> extrude(10, %)
"#;
let result = execute_and_snapshot(code).await.unwrap();
twenty_twenty::assert_image("tests/executor/outputs/tangental_arc_to.png", &result, 1.0);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB