roll pitch yaw optional, can provide only 1 (#6115)
* roll pitch yaw optional, can provide only 1 Signed-off-by: Jess Frazelle <github@jessfraz.com> * fixes Signed-off-by: Jess Frazelle <github@jessfraz.com> --------- Signed-off-by: Jess Frazelle <github@jessfraz.com>
@ -256392,7 +256392,7 @@
|
|||||||
},
|
},
|
||||||
"required": false,
|
"required": false,
|
||||||
"includeInSnippet": true,
|
"includeInSnippet": true,
|
||||||
"description": "The roll angle in degrees. Must be used with `pitch` and `yaw`. Must be between -360 and 360.",
|
"description": "The roll angle in degrees. Must be between -360 and 360. Default is 0 if not given.",
|
||||||
"labelRequired": true
|
"labelRequired": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -257990,7 +257990,7 @@
|
|||||||
},
|
},
|
||||||
"required": false,
|
"required": false,
|
||||||
"includeInSnippet": true,
|
"includeInSnippet": true,
|
||||||
"description": "The pitch angle in degrees. Must be used with `roll` and `yaw`. Must be between -360 and 360.",
|
"description": "The pitch angle in degrees. Must be between -360 and 360. Default is 0 if not given.",
|
||||||
"labelRequired": true
|
"labelRequired": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -259588,7 +259588,7 @@
|
|||||||
},
|
},
|
||||||
"required": false,
|
"required": false,
|
||||||
"includeInSnippet": true,
|
"includeInSnippet": true,
|
||||||
"description": "The yaw angle in degrees. Must be used with `roll` and `pitch`. Must be between -360 and 360.",
|
"description": "The yaw angle in degrees. Must be between -360 and 360. Default is 0 if not given.",
|
||||||
"labelRequired": true
|
"labelRequired": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -266057,6 +266057,7 @@
|
|||||||
"deprecated": false,
|
"deprecated": false,
|
||||||
"examples": [
|
"examples": [
|
||||||
"// Rotate a pipe with roll, pitch, and yaw.\n\n// Create a path for the sweep.\nsweepPath = startSketchOn(XZ)\n |> startProfileAt([0.05, 0.05], %)\n |> line(end = [0, 7])\n |> tangentialArc({ offset = 90, radius = 5 }, %)\n |> line(end = [-3, 0])\n |> tangentialArc({ offset = -90, radius = 5 }, %)\n |> line(end = [0, 7])\n\n// Create a hole for the pipe.\npipeHole = startSketchOn(XY)\n |> circle(center = [0, 0], radius = 1.5)\n\nsweepSketch = startSketchOn(XY)\n |> circle(center = [0, 0], radius = 2)\n |> hole(pipeHole, %)\n |> sweep(path = sweepPath)\n |> rotate(roll = 10, pitch = 10, yaw = 90)",
|
"// Rotate a pipe with roll, pitch, and yaw.\n\n// Create a path for the sweep.\nsweepPath = startSketchOn(XZ)\n |> startProfileAt([0.05, 0.05], %)\n |> line(end = [0, 7])\n |> tangentialArc({ offset = 90, radius = 5 }, %)\n |> line(end = [-3, 0])\n |> tangentialArc({ offset = -90, radius = 5 }, %)\n |> line(end = [0, 7])\n\n// Create a hole for the pipe.\npipeHole = startSketchOn(XY)\n |> circle(center = [0, 0], radius = 1.5)\n\nsweepSketch = startSketchOn(XY)\n |> circle(center = [0, 0], radius = 2)\n |> hole(pipeHole, %)\n |> sweep(path = sweepPath)\n |> rotate(roll = 10, pitch = 10, yaw = 90)",
|
||||||
|
"// Rotate a pipe with just roll.\n\n// Create a path for the sweep.\nsweepPath = startSketchOn(XZ)\n |> startProfileAt([0.05, 0.05], %)\n |> line(end = [0, 7])\n |> tangentialArc({ offset = 90, radius = 5 }, %)\n |> line(end = [-3, 0])\n |> tangentialArc({ offset = -90, radius = 5 }, %)\n |> line(end = [0, 7])\n\n// Create a hole for the pipe.\npipeHole = startSketchOn(XY)\n |> circle(center = [0, 0], radius = 1.5)\n\nsweepSketch = startSketchOn(XY)\n |> circle(center = [0, 0], radius = 2)\n |> hole(pipeHole, %)\n |> sweep(path = sweepPath)\n |> rotate(roll = 10)",
|
||||||
"// Rotate a pipe about an axis with an angle.\n\n// Create a path for the sweep.\nsweepPath = startSketchOn(XZ)\n |> startProfileAt([0.05, 0.05], %)\n |> line(end = [0, 7])\n |> tangentialArc({ offset = 90, radius = 5 }, %)\n |> line(end = [-3, 0])\n |> tangentialArc({ offset = -90, radius = 5 }, %)\n |> line(end = [0, 7])\n\n// Create a hole for the pipe.\npipeHole = startSketchOn(XY)\n |> circle(center = [0, 0], radius = 1.5)\n\nsweepSketch = startSketchOn(XY)\n |> circle(center = [0, 0], radius = 2)\n |> hole(pipeHole, %)\n |> sweep(path = sweepPath)\n |> rotate(axis = [0, 0, 1.0], angle = 90)",
|
"// Rotate a pipe about an axis with an angle.\n\n// Create a path for the sweep.\nsweepPath = startSketchOn(XZ)\n |> startProfileAt([0.05, 0.05], %)\n |> line(end = [0, 7])\n |> tangentialArc({ offset = 90, radius = 5 }, %)\n |> line(end = [-3, 0])\n |> tangentialArc({ offset = -90, radius = 5 }, %)\n |> line(end = [0, 7])\n\n// Create a hole for the pipe.\npipeHole = startSketchOn(XY)\n |> circle(center = [0, 0], radius = 1.5)\n\nsweepSketch = startSketchOn(XY)\n |> circle(center = [0, 0], radius = 2)\n |> hole(pipeHole, %)\n |> sweep(path = sweepPath)\n |> rotate(axis = [0, 0, 1.0], angle = 90)",
|
||||||
"// Rotate an imported model.\n\n\nimport \"tests/inputs/cube.sldprt\" as cube\n\ncube\n |> rotate(axis = [0, 0, 1.0], angle = 90)",
|
"// Rotate an imported model.\n\n\nimport \"tests/inputs/cube.sldprt\" as cube\n\ncube\n |> rotate(axis = [0, 0, 1.0], angle = 90)",
|
||||||
"// Sweep two sketches along the same path.\n\n\nsketch001 = startSketchOn(XY)\nrectangleSketch = startProfileAt([-200, 23.86], sketch001)\n |> angledLine([0, 73.47], %, $rectangleSegmentA001)\n |> angledLine([\n segAng(rectangleSegmentA001) - 90,\n 50.61\n ], %)\n |> angledLine([\n segAng(rectangleSegmentA001),\n -segLen(rectangleSegmentA001)\n ], %)\n |> line(endAbsolute = [profileStartX(%), profileStartY(%)])\n |> close()\n\ncircleSketch = circle(sketch001, center = [200, -30.29], radius = 32.63)\n\nsketch002 = startSketchOn(YZ)\nsweepPath = startProfileAt([0, 0], sketch002)\n |> yLine(length = 231.81)\n |> tangentialArc({ radius = 80, offset = -90 }, %)\n |> xLine(length = 384.93)\n\nparts = sweep([rectangleSketch, circleSketch], path = sweepPath)\n\n// Rotate the sweeps.\nrotate(parts, axis = [0, 0, 1.0], angle = 90)",
|
"// Sweep two sketches along the same path.\n\n\nsketch001 = startSketchOn(XY)\nrectangleSketch = startProfileAt([-200, 23.86], sketch001)\n |> angledLine([0, 73.47], %, $rectangleSegmentA001)\n |> angledLine([\n segAng(rectangleSegmentA001) - 90,\n 50.61\n ], %)\n |> angledLine([\n segAng(rectangleSegmentA001),\n -segLen(rectangleSegmentA001)\n ], %)\n |> line(endAbsolute = [profileStartX(%), profileStartY(%)])\n |> close()\n\ncircleSketch = circle(sketch001, center = [200, -30.29], radius = 32.63)\n\nsketch002 = startSketchOn(YZ)\nsweepPath = startProfileAt([0, 0], sketch002)\n |> yLine(length = 231.81)\n |> tangentialArc({ radius = 80, offset = -90 }, %)\n |> xLine(length = 384.93)\n\nparts = sweep([rectangleSketch, circleSketch], path = sweepPath)\n\n// Rotate the sweeps.\nrotate(parts, axis = [0, 0, 1.0], angle = 90)",
|
||||||
|
@ -452,27 +452,8 @@ pub async fn rotate(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
// If they give us a roll, pitch, or yaw, they must give us all three.
|
// If they give us a roll, pitch, or yaw, they must give us at least one of them.
|
||||||
if roll.is_some() || pitch.is_some() || yaw.is_some() {
|
if roll.is_some() || pitch.is_some() || yaw.is_some() {
|
||||||
if roll.is_none() {
|
|
||||||
return Err(KclError::Semantic(KclErrorDetails {
|
|
||||||
message: "Expected `roll` to be provided when `pitch` or `yaw` is provided.".to_string(),
|
|
||||||
source_ranges: vec![args.source_range],
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
if pitch.is_none() {
|
|
||||||
return Err(KclError::Semantic(KclErrorDetails {
|
|
||||||
message: "Expected `pitch` to be provided when `roll` or `yaw` is provided.".to_string(),
|
|
||||||
source_ranges: vec![args.source_range],
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
if yaw.is_none() {
|
|
||||||
return Err(KclError::Semantic(KclErrorDetails {
|
|
||||||
message: "Expected `yaw` to be provided when `roll` or `pitch` is provided.".to_string(),
|
|
||||||
source_ranges: vec![args.source_range],
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure they didn't also provide an axis or angle.
|
// Ensure they didn't also provide an axis or angle.
|
||||||
if axis.is_some() || angle.is_some() {
|
if axis.is_some() || angle.is_some() {
|
||||||
return Err(KclError::Semantic(KclErrorDetails {
|
return Err(KclError::Semantic(KclErrorDetails {
|
||||||
@ -617,6 +598,43 @@ pub async fn rotate(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
|||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
|
/// // Rotate a pipe with just roll.
|
||||||
|
///
|
||||||
|
/// // Create a path for the sweep.
|
||||||
|
/// sweepPath = startSketchOn('XZ')
|
||||||
|
/// |> startProfileAt([0.05, 0.05], %)
|
||||||
|
/// |> line(end = [0, 7])
|
||||||
|
/// |> tangentialArc({
|
||||||
|
/// offset: 90,
|
||||||
|
/// radius: 5
|
||||||
|
/// }, %)
|
||||||
|
/// |> line(end = [-3, 0])
|
||||||
|
/// |> tangentialArc({
|
||||||
|
/// offset: -90,
|
||||||
|
/// radius: 5
|
||||||
|
/// }, %)
|
||||||
|
/// |> line(end = [0, 7])
|
||||||
|
///
|
||||||
|
/// // Create a hole for the pipe.
|
||||||
|
/// pipeHole = startSketchOn('XY')
|
||||||
|
/// |> circle(
|
||||||
|
/// center = [0, 0],
|
||||||
|
/// radius = 1.5,
|
||||||
|
/// )
|
||||||
|
///
|
||||||
|
/// sweepSketch = startSketchOn('XY')
|
||||||
|
/// |> circle(
|
||||||
|
/// center = [0, 0],
|
||||||
|
/// radius = 2,
|
||||||
|
/// )
|
||||||
|
/// |> hole(pipeHole, %)
|
||||||
|
/// |> sweep(path = sweepPath)
|
||||||
|
/// |> rotate(
|
||||||
|
/// roll = 10,
|
||||||
|
/// )
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
/// // Rotate a pipe about an axis with an angle.
|
/// // Rotate a pipe about an axis with an angle.
|
||||||
///
|
///
|
||||||
/// // Create a path for the sweep.
|
/// // Create a path for the sweep.
|
||||||
@ -728,9 +746,9 @@ pub async fn rotate(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
|||||||
unlabeled_first = true,
|
unlabeled_first = true,
|
||||||
args = {
|
args = {
|
||||||
objects = {docs = "The solid, sketch, or set of solids or sketches to rotate."},
|
objects = {docs = "The solid, sketch, or set of solids or sketches to rotate."},
|
||||||
roll = {docs = "The roll angle in degrees. Must be used with `pitch` and `yaw`. Must be between -360 and 360.", include_in_snippet = true},
|
roll = {docs = "The roll angle in degrees. Must be between -360 and 360. Default is 0 if not given.", include_in_snippet = true},
|
||||||
pitch = {docs = "The pitch angle in degrees. Must be used with `roll` and `yaw`. Must be between -360 and 360.", include_in_snippet = true},
|
pitch = {docs = "The pitch angle in degrees. Must be between -360 and 360. Default is 0 if not given.", include_in_snippet = true},
|
||||||
yaw = {docs = "The yaw angle in degrees. Must be used with `roll` and `pitch`. Must be between -360 and 360.", include_in_snippet = true},
|
yaw = {docs = "The yaw angle in degrees. Must be between -360 and 360. Default is 0 if not given.", include_in_snippet = true},
|
||||||
axis = {docs = "The axis to rotate around. Must be used with `angle`.", include_in_snippet = false},
|
axis = {docs = "The axis to rotate around. Must be used with `angle`.", include_in_snippet = false},
|
||||||
angle = {docs = "The angle to rotate in degrees. Must be used with `axis`. Must be between -360 and 360.", include_in_snippet = false},
|
angle = {docs = "The angle to rotate in degrees. Must be used with `axis`. Must be between -360 and 360.", include_in_snippet = false},
|
||||||
global = {docs = "If true, the transform is applied in global space. The origin of the model will move. By default, the transform is applied in local sketch axis, therefore the origin will not move."}
|
global = {docs = "If true, the transform is applied in global space. The origin of the model will move. By default, the transform is applied in local sketch axis, therefore the origin will not move."}
|
||||||
@ -757,30 +775,6 @@ async fn inner_rotate(
|
|||||||
for object_id in objects.ids() {
|
for object_id in objects.ids() {
|
||||||
let id = exec_state.next_uuid();
|
let id = exec_state.next_uuid();
|
||||||
|
|
||||||
if let (Some(roll), Some(pitch), Some(yaw)) = (roll, pitch, yaw) {
|
|
||||||
args.batch_modeling_cmd(
|
|
||||||
id,
|
|
||||||
ModelingCmd::from(mcmd::SetObjectTransform {
|
|
||||||
object_id,
|
|
||||||
transforms: vec![shared::ComponentTransform {
|
|
||||||
rotate_rpy: Some(shared::TransformBy::<Point3d<f64>> {
|
|
||||||
property: shared::Point3d {
|
|
||||||
x: roll,
|
|
||||||
y: pitch,
|
|
||||||
z: yaw,
|
|
||||||
},
|
|
||||||
set: false,
|
|
||||||
is_local: !global.unwrap_or(false),
|
|
||||||
}),
|
|
||||||
scale: None,
|
|
||||||
rotate_angle_axis: None,
|
|
||||||
translate: None,
|
|
||||||
}],
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let (Some(axis), Some(angle)) = (axis, angle) {
|
if let (Some(axis), Some(angle)) = (axis, angle) {
|
||||||
args.batch_modeling_cmd(
|
args.batch_modeling_cmd(
|
||||||
id,
|
id,
|
||||||
@ -804,6 +798,29 @@ async fn inner_rotate(
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
} else {
|
||||||
|
// Do roll, pitch, and yaw.
|
||||||
|
args.batch_modeling_cmd(
|
||||||
|
id,
|
||||||
|
ModelingCmd::from(mcmd::SetObjectTransform {
|
||||||
|
object_id,
|
||||||
|
transforms: vec![shared::ComponentTransform {
|
||||||
|
rotate_rpy: Some(shared::TransformBy::<Point3d<f64>> {
|
||||||
|
property: shared::Point3d {
|
||||||
|
x: roll.unwrap_or(0.0),
|
||||||
|
y: pitch.unwrap_or(0.0),
|
||||||
|
z: yaw.unwrap_or(0.0),
|
||||||
|
},
|
||||||
|
set: false,
|
||||||
|
is_local: !global.unwrap_or(false),
|
||||||
|
}),
|
||||||
|
scale: None,
|
||||||
|
rotate_angle_axis: None,
|
||||||
|
translate: None,
|
||||||
|
}],
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -923,24 +940,42 @@ sweepSketch = startSketchOn('XY')
|
|||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().message(),
|
result.unwrap_err().message(),
|
||||||
r#"Expected `roll` to be provided when `pitch` or `yaw` is provided."#.to_string()
|
r#"Expected `axis` and `angle` to not be provided when `roll`, `pitch`, and `yaw` are provided."#
|
||||||
|
.to_string()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
async fn test_rotate_yaw_no_pitch() {
|
async fn test_rotate_yaw_only() {
|
||||||
let ast = PIPE.to_string()
|
let ast = PIPE.to_string()
|
||||||
+ r#"
|
+ r#"
|
||||||
|> rotate(
|
|> rotate(
|
||||||
yaw = 90,
|
yaw = 90,
|
||||||
)
|
)
|
||||||
"#;
|
"#;
|
||||||
let result = parse_execute(&ast).await;
|
parse_execute(&ast).await.unwrap();
|
||||||
assert!(result.is_err());
|
}
|
||||||
assert_eq!(
|
|
||||||
result.unwrap_err().message(),
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
r#"Expected `roll` to be provided when `pitch` or `yaw` is provided."#.to_string()
|
async fn test_rotate_pitch_only() {
|
||||||
);
|
let ast = PIPE.to_string()
|
||||||
|
+ r#"
|
||||||
|
|> rotate(
|
||||||
|
pitch = 90,
|
||||||
|
)
|
||||||
|
"#;
|
||||||
|
parse_execute(&ast).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
|
async fn test_rotate_roll_only() {
|
||||||
|
let ast = PIPE.to_string()
|
||||||
|
+ r#"
|
||||||
|
|> rotate(
|
||||||
|
pitch = 90,
|
||||||
|
)
|
||||||
|
"#;
|
||||||
|
parse_execute(&ast).await.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
|
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 75 KiB |
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 55 KiB |
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 74 KiB |
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 64 KiB |
BIN
rust/kcl-lib/tests/outputs/serial_test_example_rotate5.png
Normal file
After Width: | Height: | Size: 85 KiB |