get common edge (#5869)
* get common edge Signed-off-by: Jess Frazelle <github@jessfraz.com> * fmt Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * add get common edge Signed-off-by: Jess Frazelle <github@jessfraz.com> * docs Signed-off-by: Jess Frazelle <github@jessfraz.com> --------- Signed-off-by: Jess Frazelle <github@jessfraz.com>
This commit is contained in:
54
docs/kcl/getCommonEdge.md
Normal file
54
docs/kcl/getCommonEdge.md
Normal file
File diff suppressed because one or more lines are too long
@ -65,6 +65,7 @@ layout: manual
|
|||||||
* [`fillet`](kcl/fillet)
|
* [`fillet`](kcl/fillet)
|
||||||
* [`floor`](kcl/floor)
|
* [`floor`](kcl/floor)
|
||||||
* [`ft`](kcl/ft)
|
* [`ft`](kcl/ft)
|
||||||
|
* [`getCommonEdge`](kcl/getCommonEdge)
|
||||||
* [`getNextAdjacentEdge`](kcl/getNextAdjacentEdge)
|
* [`getNextAdjacentEdge`](kcl/getNextAdjacentEdge)
|
||||||
* [`getOppositeEdge`](kcl/getOppositeEdge)
|
* [`getOppositeEdge`](kcl/getOppositeEdge)
|
||||||
* [`getPreviousAdjacentEdge`](kcl/getPreviousAdjacentEdge)
|
* [`getPreviousAdjacentEdge`](kcl/getPreviousAdjacentEdge)
|
||||||
|
@ -100842,6 +100842,62 @@
|
|||||||
"totalWidth = 10 * ft()"
|
"totalWidth = 10 * ft()"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "getCommonEdge",
|
||||||
|
"summary": "Get the shared edge between two faces.",
|
||||||
|
"description": "",
|
||||||
|
"tags": [],
|
||||||
|
"keywordArguments": true,
|
||||||
|
"args": [
|
||||||
|
{
|
||||||
|
"name": "faces",
|
||||||
|
"type": "[TagIdentifier]",
|
||||||
|
"schema": {
|
||||||
|
"$schema": "https://spec.openapis.org/oas/3.0/schema/2019-04-02#/definitions/Schema",
|
||||||
|
"title": "Array_of_TagIdentifier",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/TagIdentifier"
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"TagIdentifier": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"value"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"value": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": true,
|
||||||
|
"includeInSnippet": true,
|
||||||
|
"description": "The tags of the faces you want to find the common edge between",
|
||||||
|
"labelRequired": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"returnValue": {
|
||||||
|
"name": "",
|
||||||
|
"type": "Uuid",
|
||||||
|
"schema": {
|
||||||
|
"$schema": "https://spec.openapis.org/oas/3.0/schema/2019-04-02#/definitions/Schema",
|
||||||
|
"title": "Uuid",
|
||||||
|
"type": "string",
|
||||||
|
"format": "uuid"
|
||||||
|
},
|
||||||
|
"required": true,
|
||||||
|
"includeInSnippet": true,
|
||||||
|
"labelRequired": true
|
||||||
|
},
|
||||||
|
"unpublished": false,
|
||||||
|
"deprecated": false,
|
||||||
|
"examples": [
|
||||||
|
"// Get an edge shared between two faces, created after a chamfer.\n\n\nscale = 20\npart001 = startSketchOn('XY')\n |> startProfileAt([0, 0], %)\n |> line(end = [0, scale])\n |> line(end = [scale, 0])\n |> line(end = [0, -scale])\n |> close(tag = $line0)\n |> extrude(length = 20, tagEnd = $end0)\n // We tag the chamfer to reference it later.\n |> chamfer(length = 10, tags = [getOppositeEdge(line0)], tag = $chamfer0)\n\n// Get the shared edge between the chamfer and the extrusion.\ncommonEdge = getCommonEdge(faces = [chamfer0, end0])\n\n// Chamfer the shared edge.\n// TODO: uncomment this when ssi for fillets lands\n// chamfer(part001, length = 5, tags = [commonEdge])"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "getNextAdjacentEdge",
|
"name": "getNextAdjacentEdge",
|
||||||
"summary": "Get the next adjacent edge to the edge given.",
|
"summary": "Get the next adjacent edge to the edge given.",
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
@ -144,7 +144,7 @@ impl Args {
|
|||||||
KclError::Type(KclErrorDetails {
|
KclError::Type(KclErrorDetails {
|
||||||
source_ranges: vec![self.source_range],
|
source_ranges: vec![self.source_range],
|
||||||
message: format!(
|
message: format!(
|
||||||
"The optional arg {label} was given, but it was the wrong type. It should be type {} but it was {}",
|
"The arg {label} was given, but it was the wrong type. It should be type {} but it was {}",
|
||||||
type_name::<T>(),
|
type_name::<T>(),
|
||||||
arg.value.human_friendly_type(),
|
arg.value.human_friendly_type(),
|
||||||
),
|
),
|
||||||
@ -423,7 +423,7 @@ impl Args {
|
|||||||
|
|
||||||
// Run flush.
|
// Run flush.
|
||||||
// Yes, we do need to actually flush the batch here, or references will fail later.
|
// Yes, we do need to actually flush the batch here, or references will fail later.
|
||||||
self.ctx.engine.flush_batch(false, SourceRange::default()).await?;
|
self.ctx.engine.flush_batch(false, self.source_range).await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -972,6 +972,22 @@ impl<'a> FromKclValue<'a> for TagIdentifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> FromKclValue<'a> for Vec<TagIdentifier> {
|
||||||
|
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
|
||||||
|
match arg {
|
||||||
|
KclValue::HomArray { value, .. } => {
|
||||||
|
let tags = value.iter().map(|v| v.get_tag_identifier().unwrap()).collect();
|
||||||
|
Some(tags)
|
||||||
|
}
|
||||||
|
KclValue::MixedArray { value, .. } => {
|
||||||
|
let tags = value.iter().map(|v| v.get_tag_identifier().unwrap()).collect();
|
||||||
|
Some(tags)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> FromKclValue<'a> for KclValue {
|
impl<'a> FromKclValue<'a> for KclValue {
|
||||||
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
|
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
|
||||||
Some(arg.clone())
|
Some(arg.clone())
|
||||||
|
369
rust/kcl-lib/src/std/edge.rs
Normal file
369
rust/kcl-lib/src/std/edge.rs
Normal file
@ -0,0 +1,369 @@
|
|||||||
|
//! Edge helper functions.
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use kcl_derive_docs::stdlib;
|
||||||
|
use kcmc::{each_cmd as mcmd, ok_response::OkModelingCmdResponse, websocket::OkWebSocketResponseData, ModelingCmd};
|
||||||
|
use kittycad_modeling_cmds as kcmc;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
errors::{KclError, KclErrorDetails},
|
||||||
|
execution::{ExecState, ExtrudeSurface, KclValue, TagIdentifier},
|
||||||
|
std::Args,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Get the opposite edge to the edge given.
|
||||||
|
pub async fn get_opposite_edge(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||||
|
let tag: TagIdentifier = args.get_data()?;
|
||||||
|
|
||||||
|
let edge = inner_get_opposite_edge(tag, exec_state, args.clone()).await?;
|
||||||
|
Ok(KclValue::Uuid {
|
||||||
|
value: edge,
|
||||||
|
meta: vec![args.source_range.into()],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the opposite edge to the edge given.
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// exampleSketch = startSketchOn('XZ')
|
||||||
|
/// |> startProfileAt([0, 0], %)
|
||||||
|
/// |> line(end = [10, 0])
|
||||||
|
/// |> angledLine({
|
||||||
|
/// angle = 60,
|
||||||
|
/// length = 10,
|
||||||
|
/// }, %)
|
||||||
|
/// |> angledLine({
|
||||||
|
/// angle = 120,
|
||||||
|
/// length = 10,
|
||||||
|
/// }, %)
|
||||||
|
/// |> line(end = [-10, 0])
|
||||||
|
/// |> angledLine({
|
||||||
|
/// angle = 240,
|
||||||
|
/// length = 10,
|
||||||
|
/// }, %, $referenceEdge)
|
||||||
|
/// |> close()
|
||||||
|
///
|
||||||
|
/// example = extrude(exampleSketch, length = 5)
|
||||||
|
/// |> fillet(
|
||||||
|
/// radius = 3,
|
||||||
|
/// tags = [getOppositeEdge(referenceEdge)],
|
||||||
|
/// )
|
||||||
|
/// ```
|
||||||
|
#[stdlib {
|
||||||
|
name = "getOppositeEdge",
|
||||||
|
}]
|
||||||
|
async fn inner_get_opposite_edge(tag: TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<Uuid, KclError> {
|
||||||
|
if args.ctx.no_engine_commands().await {
|
||||||
|
return Ok(exec_state.next_uuid());
|
||||||
|
}
|
||||||
|
let face_id = args.get_adjacent_face_to_tag(exec_state, &tag, false).await?;
|
||||||
|
|
||||||
|
let id = exec_state.next_uuid();
|
||||||
|
let tagged_path = args.get_tag_engine_info(exec_state, &tag)?;
|
||||||
|
|
||||||
|
let resp = args
|
||||||
|
.send_modeling_cmd(
|
||||||
|
id,
|
||||||
|
ModelingCmd::from(mcmd::Solid3dGetOppositeEdge {
|
||||||
|
edge_id: tagged_path.id,
|
||||||
|
object_id: tagged_path.sketch,
|
||||||
|
face_id,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
let OkWebSocketResponseData::Modeling {
|
||||||
|
modeling_response: OkModelingCmdResponse::Solid3dGetOppositeEdge(opposite_edge),
|
||||||
|
} = &resp
|
||||||
|
else {
|
||||||
|
return Err(KclError::Engine(KclErrorDetails {
|
||||||
|
message: format!("mcmd::Solid3dGetOppositeEdge response was not as expected: {:?}", resp),
|
||||||
|
source_ranges: vec![args.source_range],
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(opposite_edge.edge)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the next adjacent edge to the edge given.
|
||||||
|
pub async fn get_next_adjacent_edge(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||||
|
let tag: TagIdentifier = args.get_data()?;
|
||||||
|
|
||||||
|
let edge = inner_get_next_adjacent_edge(tag, exec_state, args.clone()).await?;
|
||||||
|
Ok(KclValue::Uuid {
|
||||||
|
value: edge,
|
||||||
|
meta: vec![args.source_range.into()],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the next adjacent edge to the edge given.
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// exampleSketch = startSketchOn('XZ')
|
||||||
|
/// |> startProfileAt([0, 0], %)
|
||||||
|
/// |> line(end = [10, 0])
|
||||||
|
/// |> angledLine({
|
||||||
|
/// angle = 60,
|
||||||
|
/// length = 10,
|
||||||
|
/// }, %)
|
||||||
|
/// |> angledLine({
|
||||||
|
/// angle = 120,
|
||||||
|
/// length = 10,
|
||||||
|
/// }, %)
|
||||||
|
/// |> line(end = [-10, 0])
|
||||||
|
/// |> angledLine({
|
||||||
|
/// angle = 240,
|
||||||
|
/// length = 10,
|
||||||
|
/// }, %, $referenceEdge)
|
||||||
|
/// |> close()
|
||||||
|
///
|
||||||
|
/// example = extrude(exampleSketch, length = 5)
|
||||||
|
/// |> fillet(
|
||||||
|
/// radius = 3,
|
||||||
|
/// tags = [getNextAdjacentEdge(referenceEdge)],
|
||||||
|
/// )
|
||||||
|
/// ```
|
||||||
|
#[stdlib {
|
||||||
|
name = "getNextAdjacentEdge",
|
||||||
|
}]
|
||||||
|
async fn inner_get_next_adjacent_edge(
|
||||||
|
tag: TagIdentifier,
|
||||||
|
exec_state: &mut ExecState,
|
||||||
|
args: Args,
|
||||||
|
) -> Result<Uuid, KclError> {
|
||||||
|
if args.ctx.no_engine_commands().await {
|
||||||
|
return Ok(exec_state.next_uuid());
|
||||||
|
}
|
||||||
|
let face_id = args.get_adjacent_face_to_tag(exec_state, &tag, false).await?;
|
||||||
|
|
||||||
|
let id = exec_state.next_uuid();
|
||||||
|
let tagged_path = args.get_tag_engine_info(exec_state, &tag)?;
|
||||||
|
|
||||||
|
let resp = args
|
||||||
|
.send_modeling_cmd(
|
||||||
|
id,
|
||||||
|
ModelingCmd::from(mcmd::Solid3dGetNextAdjacentEdge {
|
||||||
|
edge_id: tagged_path.id,
|
||||||
|
object_id: tagged_path.sketch,
|
||||||
|
face_id,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let OkWebSocketResponseData::Modeling {
|
||||||
|
modeling_response: OkModelingCmdResponse::Solid3dGetNextAdjacentEdge(adjacent_edge),
|
||||||
|
} = &resp
|
||||||
|
else {
|
||||||
|
return Err(KclError::Engine(KclErrorDetails {
|
||||||
|
message: format!(
|
||||||
|
"mcmd::Solid3dGetNextAdjacentEdge response was not as expected: {:?}",
|
||||||
|
resp
|
||||||
|
),
|
||||||
|
source_ranges: vec![args.source_range],
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
adjacent_edge.edge.ok_or_else(|| {
|
||||||
|
KclError::Type(KclErrorDetails {
|
||||||
|
message: format!("No edge found next adjacent to tag: `{}`", tag.value),
|
||||||
|
source_ranges: vec![args.source_range],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the previous adjacent edge to the edge given.
|
||||||
|
pub async fn get_previous_adjacent_edge(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||||
|
let tag: TagIdentifier = args.get_data()?;
|
||||||
|
|
||||||
|
let edge = inner_get_previous_adjacent_edge(tag, exec_state, args.clone()).await?;
|
||||||
|
Ok(KclValue::Uuid {
|
||||||
|
value: edge,
|
||||||
|
meta: vec![args.source_range.into()],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the previous adjacent edge to the edge given.
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// exampleSketch = startSketchOn('XZ')
|
||||||
|
/// |> startProfileAt([0, 0], %)
|
||||||
|
/// |> line(end = [10, 0])
|
||||||
|
/// |> angledLine({
|
||||||
|
/// angle = 60,
|
||||||
|
/// length = 10,
|
||||||
|
/// }, %)
|
||||||
|
/// |> angledLine({
|
||||||
|
/// angle = 120,
|
||||||
|
/// length = 10,
|
||||||
|
/// }, %)
|
||||||
|
/// |> line(end = [-10, 0])
|
||||||
|
/// |> angledLine({
|
||||||
|
/// angle = 240,
|
||||||
|
/// length = 10,
|
||||||
|
/// }, %, $referenceEdge)
|
||||||
|
/// |> close()
|
||||||
|
///
|
||||||
|
/// example = extrude(exampleSketch, length = 5)
|
||||||
|
/// |> fillet(
|
||||||
|
/// radius = 3,
|
||||||
|
/// tags = [getPreviousAdjacentEdge(referenceEdge)],
|
||||||
|
/// )
|
||||||
|
/// ```
|
||||||
|
#[stdlib {
|
||||||
|
name = "getPreviousAdjacentEdge",
|
||||||
|
}]
|
||||||
|
async fn inner_get_previous_adjacent_edge(
|
||||||
|
tag: TagIdentifier,
|
||||||
|
exec_state: &mut ExecState,
|
||||||
|
args: Args,
|
||||||
|
) -> Result<Uuid, KclError> {
|
||||||
|
if args.ctx.no_engine_commands().await {
|
||||||
|
return Ok(exec_state.next_uuid());
|
||||||
|
}
|
||||||
|
let face_id = args.get_adjacent_face_to_tag(exec_state, &tag, false).await?;
|
||||||
|
|
||||||
|
let id = exec_state.next_uuid();
|
||||||
|
let tagged_path = args.get_tag_engine_info(exec_state, &tag)?;
|
||||||
|
|
||||||
|
let resp = args
|
||||||
|
.send_modeling_cmd(
|
||||||
|
id,
|
||||||
|
ModelingCmd::from(mcmd::Solid3dGetPrevAdjacentEdge {
|
||||||
|
edge_id: tagged_path.id,
|
||||||
|
object_id: tagged_path.sketch,
|
||||||
|
face_id,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
let OkWebSocketResponseData::Modeling {
|
||||||
|
modeling_response: OkModelingCmdResponse::Solid3dGetPrevAdjacentEdge(adjacent_edge),
|
||||||
|
} = &resp
|
||||||
|
else {
|
||||||
|
return Err(KclError::Engine(KclErrorDetails {
|
||||||
|
message: format!(
|
||||||
|
"mcmd::Solid3dGetPrevAdjacentEdge response was not as expected: {:?}",
|
||||||
|
resp
|
||||||
|
),
|
||||||
|
source_ranges: vec![args.source_range],
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
adjacent_edge.edge.ok_or_else(|| {
|
||||||
|
KclError::Type(KclErrorDetails {
|
||||||
|
message: format!("No edge found previous adjacent to tag: `{}`", tag.value),
|
||||||
|
source_ranges: vec![args.source_range],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the shared edge between two faces.
|
||||||
|
pub async fn get_common_edge(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||||
|
let faces: Vec<TagIdentifier> = args.get_kw_arg("faces")?;
|
||||||
|
|
||||||
|
let edge = inner_get_common_edge(faces, exec_state, args.clone()).await?;
|
||||||
|
Ok(KclValue::Uuid {
|
||||||
|
value: edge,
|
||||||
|
meta: vec![args.source_range.into()],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the shared edge between two faces.
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// // Get an edge shared between two faces, created after a chamfer.
|
||||||
|
///
|
||||||
|
/// scale = 20
|
||||||
|
/// part001 = startSketchOn('XY')
|
||||||
|
/// |> startProfileAt([0, 0], %)
|
||||||
|
/// |> line(end = [0, scale])
|
||||||
|
/// |> line(end = [scale, 0])
|
||||||
|
/// |> line(end = [0, -scale])
|
||||||
|
/// |> close(tag = $line0)
|
||||||
|
/// |> extrude(length = 20, tagEnd = $end0)
|
||||||
|
/// // We tag the chamfer to reference it later.
|
||||||
|
/// |> chamfer(length = 10, tags = [getOppositeEdge(line0)], tag = $chamfer0)
|
||||||
|
///
|
||||||
|
/// // Get the shared edge between the chamfer and the extrusion.
|
||||||
|
/// commonEdge = getCommonEdge(faces = [chamfer0, end0])
|
||||||
|
///
|
||||||
|
/// // Chamfer the shared edge.
|
||||||
|
/// // TODO: uncomment this when ssi for fillets lands
|
||||||
|
/// // chamfer(part001, length = 5, tags = [commonEdge])
|
||||||
|
/// ```
|
||||||
|
#[stdlib {
|
||||||
|
name = "getCommonEdge",
|
||||||
|
feature_tree_operation = false,
|
||||||
|
keywords = true,
|
||||||
|
unlabeled_first = false,
|
||||||
|
args = {
|
||||||
|
faces = { docs = "The tags of the faces you want to find the common edge between" },
|
||||||
|
},
|
||||||
|
}]
|
||||||
|
async fn inner_get_common_edge(
|
||||||
|
faces: Vec<TagIdentifier>,
|
||||||
|
exec_state: &mut ExecState,
|
||||||
|
args: Args,
|
||||||
|
) -> Result<Uuid, KclError> {
|
||||||
|
let id = exec_state.next_uuid();
|
||||||
|
if args.ctx.no_engine_commands().await {
|
||||||
|
return Ok(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if faces.len() != 2 {
|
||||||
|
return Err(KclError::Type(KclErrorDetails {
|
||||||
|
message: "getCommonEdge requires exactly two tags for faces".to_string(),
|
||||||
|
source_ranges: vec![args.source_range],
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
let first_face_id = args.get_adjacent_face_to_tag(exec_state, &faces[0], false).await?;
|
||||||
|
let second_face_id = args.get_adjacent_face_to_tag(exec_state, &faces[1], false).await?;
|
||||||
|
|
||||||
|
let first_tagged_path = args.get_tag_engine_info(exec_state, &faces[0])?.clone();
|
||||||
|
let second_tagged_path = args.get_tag_engine_info(exec_state, &faces[1])?;
|
||||||
|
|
||||||
|
if first_tagged_path.sketch != second_tagged_path.sketch {
|
||||||
|
return Err(KclError::Type(KclErrorDetails {
|
||||||
|
message: "getCommonEdge requires the faces to be in the same original sketch".to_string(),
|
||||||
|
source_ranges: vec![args.source_range],
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flush the batch for our fillets/chamfers if there are any.
|
||||||
|
// If we have a chamfer/fillet, flush the batch.
|
||||||
|
// TODO: we likely want to be a lot more persnickety _which_ fillets we are flushing
|
||||||
|
// but for now, we'll just flush everything.
|
||||||
|
if let Some(ExtrudeSurface::Chamfer { .. } | ExtrudeSurface::Fillet { .. }) = first_tagged_path.surface {
|
||||||
|
args.ctx.engine.flush_batch(true, args.source_range).await?;
|
||||||
|
} else if let Some(ExtrudeSurface::Chamfer { .. } | ExtrudeSurface::Fillet { .. }) = second_tagged_path.surface {
|
||||||
|
args.ctx.engine.flush_batch(true, args.source_range).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let resp = args
|
||||||
|
.send_modeling_cmd(
|
||||||
|
id,
|
||||||
|
ModelingCmd::from(mcmd::Solid3dGetCommonEdge {
|
||||||
|
object_id: first_tagged_path.sketch,
|
||||||
|
face_ids: [first_face_id, second_face_id],
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
let OkWebSocketResponseData::Modeling {
|
||||||
|
modeling_response: OkModelingCmdResponse::Solid3dGetCommonEdge(common_edge),
|
||||||
|
} = &resp
|
||||||
|
else {
|
||||||
|
return Err(KclError::Engine(KclErrorDetails {
|
||||||
|
message: format!("mcmd::Solid3dGetCommonEdge response was not as expected: {:?}", resp),
|
||||||
|
source_ranges: vec![args.source_range],
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
common_edge.edge.ok_or_else(|| {
|
||||||
|
KclError::Type(KclErrorDetails {
|
||||||
|
message: format!(
|
||||||
|
"No common edge was found between `{}` and `{}`",
|
||||||
|
faces[0].value, faces[1].value
|
||||||
|
),
|
||||||
|
source_ranges: vec![args.source_range],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
@ -3,14 +3,10 @@
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use kcl_derive_docs::stdlib;
|
use kcl_derive_docs::stdlib;
|
||||||
use kcmc::{
|
use kcmc::{each_cmd as mcmd, length_unit::LengthUnit, shared::CutType, ModelingCmd};
|
||||||
each_cmd as mcmd, length_unit::LengthUnit, ok_response::OkModelingCmdResponse, shared::CutType,
|
|
||||||
websocket::OkWebSocketResponseData, ModelingCmd,
|
|
||||||
};
|
|
||||||
use kittycad_modeling_cmds as kcmc;
|
use kittycad_modeling_cmds as kcmc;
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
@ -199,250 +195,6 @@ async fn inner_fillet(
|
|||||||
Ok(solid)
|
Ok(solid)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the opposite edge to the edge given.
|
|
||||||
pub async fn get_opposite_edge(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
|
||||||
let tag: TagIdentifier = args.get_data()?;
|
|
||||||
|
|
||||||
let edge = inner_get_opposite_edge(tag, exec_state, args.clone()).await?;
|
|
||||||
Ok(KclValue::Uuid {
|
|
||||||
value: edge,
|
|
||||||
meta: vec![args.source_range.into()],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the opposite edge to the edge given.
|
|
||||||
///
|
|
||||||
/// ```no_run
|
|
||||||
/// exampleSketch = startSketchOn('XZ')
|
|
||||||
/// |> startProfileAt([0, 0], %)
|
|
||||||
/// |> line(end = [10, 0])
|
|
||||||
/// |> angledLine({
|
|
||||||
/// angle = 60,
|
|
||||||
/// length = 10,
|
|
||||||
/// }, %)
|
|
||||||
/// |> angledLine({
|
|
||||||
/// angle = 120,
|
|
||||||
/// length = 10,
|
|
||||||
/// }, %)
|
|
||||||
/// |> line(end = [-10, 0])
|
|
||||||
/// |> angledLine({
|
|
||||||
/// angle = 240,
|
|
||||||
/// length = 10,
|
|
||||||
/// }, %, $referenceEdge)
|
|
||||||
/// |> close()
|
|
||||||
///
|
|
||||||
/// example = extrude(exampleSketch, length = 5)
|
|
||||||
/// |> fillet(
|
|
||||||
/// radius = 3,
|
|
||||||
/// tags = [getOppositeEdge(referenceEdge)],
|
|
||||||
/// )
|
|
||||||
/// ```
|
|
||||||
#[stdlib {
|
|
||||||
name = "getOppositeEdge",
|
|
||||||
}]
|
|
||||||
async fn inner_get_opposite_edge(tag: TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<Uuid, KclError> {
|
|
||||||
if args.ctx.no_engine_commands().await {
|
|
||||||
return Ok(exec_state.next_uuid());
|
|
||||||
}
|
|
||||||
let face_id = args.get_adjacent_face_to_tag(exec_state, &tag, false).await?;
|
|
||||||
|
|
||||||
let id = exec_state.next_uuid();
|
|
||||||
let tagged_path = args.get_tag_engine_info(exec_state, &tag)?;
|
|
||||||
|
|
||||||
let resp = args
|
|
||||||
.send_modeling_cmd(
|
|
||||||
id,
|
|
||||||
ModelingCmd::from(mcmd::Solid3dGetOppositeEdge {
|
|
||||||
edge_id: tagged_path.id,
|
|
||||||
object_id: tagged_path.sketch,
|
|
||||||
face_id,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
let OkWebSocketResponseData::Modeling {
|
|
||||||
modeling_response: OkModelingCmdResponse::Solid3dGetOppositeEdge(opposite_edge),
|
|
||||||
} = &resp
|
|
||||||
else {
|
|
||||||
return Err(KclError::Engine(KclErrorDetails {
|
|
||||||
message: format!("mcmd::Solid3dGetOppositeEdge response was not as expected: {:?}", resp),
|
|
||||||
source_ranges: vec![args.source_range],
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(opposite_edge.edge)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the next adjacent edge to the edge given.
|
|
||||||
pub async fn get_next_adjacent_edge(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
|
||||||
let tag: TagIdentifier = args.get_data()?;
|
|
||||||
|
|
||||||
let edge = inner_get_next_adjacent_edge(tag, exec_state, args.clone()).await?;
|
|
||||||
Ok(KclValue::Uuid {
|
|
||||||
value: edge,
|
|
||||||
meta: vec![args.source_range.into()],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the next adjacent edge to the edge given.
|
|
||||||
///
|
|
||||||
/// ```no_run
|
|
||||||
/// exampleSketch = startSketchOn('XZ')
|
|
||||||
/// |> startProfileAt([0, 0], %)
|
|
||||||
/// |> line(end = [10, 0])
|
|
||||||
/// |> angledLine({
|
|
||||||
/// angle = 60,
|
|
||||||
/// length = 10,
|
|
||||||
/// }, %)
|
|
||||||
/// |> angledLine({
|
|
||||||
/// angle = 120,
|
|
||||||
/// length = 10,
|
|
||||||
/// }, %)
|
|
||||||
/// |> line(end = [-10, 0])
|
|
||||||
/// |> angledLine({
|
|
||||||
/// angle = 240,
|
|
||||||
/// length = 10,
|
|
||||||
/// }, %, $referenceEdge)
|
|
||||||
/// |> close()
|
|
||||||
///
|
|
||||||
/// example = extrude(exampleSketch, length = 5)
|
|
||||||
/// |> fillet(
|
|
||||||
/// radius = 3,
|
|
||||||
/// tags = [getNextAdjacentEdge(referenceEdge)],
|
|
||||||
/// )
|
|
||||||
/// ```
|
|
||||||
#[stdlib {
|
|
||||||
name = "getNextAdjacentEdge",
|
|
||||||
}]
|
|
||||||
async fn inner_get_next_adjacent_edge(
|
|
||||||
tag: TagIdentifier,
|
|
||||||
exec_state: &mut ExecState,
|
|
||||||
args: Args,
|
|
||||||
) -> Result<Uuid, KclError> {
|
|
||||||
if args.ctx.no_engine_commands().await {
|
|
||||||
return Ok(exec_state.next_uuid());
|
|
||||||
}
|
|
||||||
let face_id = args.get_adjacent_face_to_tag(exec_state, &tag, false).await?;
|
|
||||||
|
|
||||||
let id = exec_state.next_uuid();
|
|
||||||
let tagged_path = args.get_tag_engine_info(exec_state, &tag)?;
|
|
||||||
|
|
||||||
let resp = args
|
|
||||||
.send_modeling_cmd(
|
|
||||||
id,
|
|
||||||
ModelingCmd::from(mcmd::Solid3dGetNextAdjacentEdge {
|
|
||||||
edge_id: tagged_path.id,
|
|
||||||
object_id: tagged_path.sketch,
|
|
||||||
face_id,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let OkWebSocketResponseData::Modeling {
|
|
||||||
modeling_response: OkModelingCmdResponse::Solid3dGetNextAdjacentEdge(adjacent_edge),
|
|
||||||
} = &resp
|
|
||||||
else {
|
|
||||||
return Err(KclError::Engine(KclErrorDetails {
|
|
||||||
message: format!(
|
|
||||||
"mcmd::Solid3dGetNextAdjacentEdge response was not as expected: {:?}",
|
|
||||||
resp
|
|
||||||
),
|
|
||||||
source_ranges: vec![args.source_range],
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
adjacent_edge.edge.ok_or_else(|| {
|
|
||||||
KclError::Type(KclErrorDetails {
|
|
||||||
message: format!("No edge found next adjacent to tag: `{}`", tag.value),
|
|
||||||
source_ranges: vec![args.source_range],
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the previous adjacent edge to the edge given.
|
|
||||||
pub async fn get_previous_adjacent_edge(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
|
||||||
let tag: TagIdentifier = args.get_data()?;
|
|
||||||
|
|
||||||
let edge = inner_get_previous_adjacent_edge(tag, exec_state, args.clone()).await?;
|
|
||||||
Ok(KclValue::Uuid {
|
|
||||||
value: edge,
|
|
||||||
meta: vec![args.source_range.into()],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the previous adjacent edge to the edge given.
|
|
||||||
///
|
|
||||||
/// ```no_run
|
|
||||||
/// exampleSketch = startSketchOn('XZ')
|
|
||||||
/// |> startProfileAt([0, 0], %)
|
|
||||||
/// |> line(end = [10, 0])
|
|
||||||
/// |> angledLine({
|
|
||||||
/// angle = 60,
|
|
||||||
/// length = 10,
|
|
||||||
/// }, %)
|
|
||||||
/// |> angledLine({
|
|
||||||
/// angle = 120,
|
|
||||||
/// length = 10,
|
|
||||||
/// }, %)
|
|
||||||
/// |> line(end = [-10, 0])
|
|
||||||
/// |> angledLine({
|
|
||||||
/// angle = 240,
|
|
||||||
/// length = 10,
|
|
||||||
/// }, %, $referenceEdge)
|
|
||||||
/// |> close()
|
|
||||||
///
|
|
||||||
/// example = extrude(exampleSketch, length = 5)
|
|
||||||
/// |> fillet(
|
|
||||||
/// radius = 3,
|
|
||||||
/// tags = [getPreviousAdjacentEdge(referenceEdge)],
|
|
||||||
/// )
|
|
||||||
/// ```
|
|
||||||
#[stdlib {
|
|
||||||
name = "getPreviousAdjacentEdge",
|
|
||||||
}]
|
|
||||||
async fn inner_get_previous_adjacent_edge(
|
|
||||||
tag: TagIdentifier,
|
|
||||||
exec_state: &mut ExecState,
|
|
||||||
args: Args,
|
|
||||||
) -> Result<Uuid, KclError> {
|
|
||||||
if args.ctx.no_engine_commands().await {
|
|
||||||
return Ok(exec_state.next_uuid());
|
|
||||||
}
|
|
||||||
let face_id = args.get_adjacent_face_to_tag(exec_state, &tag, false).await?;
|
|
||||||
|
|
||||||
let id = exec_state.next_uuid();
|
|
||||||
let tagged_path = args.get_tag_engine_info(exec_state, &tag)?;
|
|
||||||
|
|
||||||
let resp = args
|
|
||||||
.send_modeling_cmd(
|
|
||||||
id,
|
|
||||||
ModelingCmd::from(mcmd::Solid3dGetPrevAdjacentEdge {
|
|
||||||
edge_id: tagged_path.id,
|
|
||||||
object_id: tagged_path.sketch,
|
|
||||||
face_id,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
let OkWebSocketResponseData::Modeling {
|
|
||||||
modeling_response: OkModelingCmdResponse::Solid3dGetPrevAdjacentEdge(adjacent_edge),
|
|
||||||
} = &resp
|
|
||||||
else {
|
|
||||||
return Err(KclError::Engine(KclErrorDetails {
|
|
||||||
message: format!(
|
|
||||||
"mcmd::Solid3dGetPrevAdjacentEdge response was not as expected: {:?}",
|
|
||||||
resp
|
|
||||||
),
|
|
||||||
source_ranges: vec![args.source_range],
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
adjacent_edge.edge.ok_or_else(|| {
|
|
||||||
KclError::Type(KclErrorDetails {
|
|
||||||
message: format!("No edge found previous adjacent to tag: `{}`", tag.value),
|
|
||||||
source_ranges: vec![args.source_range],
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn default_tolerance(units: &UnitLength) -> f64 {
|
pub(crate) fn default_tolerance(units: &UnitLength) -> f64 {
|
||||||
match units {
|
match units {
|
||||||
UnitLength::Mm => 0.0000001,
|
UnitLength::Mm => 0.0000001,
|
||||||
|
@ -7,6 +7,7 @@ pub mod assert;
|
|||||||
pub mod axis_or_reference;
|
pub mod axis_or_reference;
|
||||||
pub mod chamfer;
|
pub mod chamfer;
|
||||||
pub mod convert;
|
pub mod convert;
|
||||||
|
pub mod edge;
|
||||||
pub mod extrude;
|
pub mod extrude;
|
||||||
pub mod fillet;
|
pub mod fillet;
|
||||||
pub mod helix;
|
pub mod helix;
|
||||||
@ -107,9 +108,10 @@ lazy_static! {
|
|||||||
Box::new(crate::std::array::Pop),
|
Box::new(crate::std::array::Pop),
|
||||||
Box::new(crate::std::chamfer::Chamfer),
|
Box::new(crate::std::chamfer::Chamfer),
|
||||||
Box::new(crate::std::fillet::Fillet),
|
Box::new(crate::std::fillet::Fillet),
|
||||||
Box::new(crate::std::fillet::GetOppositeEdge),
|
Box::new(crate::std::edge::GetOppositeEdge),
|
||||||
Box::new(crate::std::fillet::GetNextAdjacentEdge),
|
Box::new(crate::std::edge::GetNextAdjacentEdge),
|
||||||
Box::new(crate::std::fillet::GetPreviousAdjacentEdge),
|
Box::new(crate::std::edge::GetPreviousAdjacentEdge),
|
||||||
|
Box::new(crate::std::edge::GetCommonEdge),
|
||||||
Box::new(crate::std::helix::Helix),
|
Box::new(crate::std::helix::Helix),
|
||||||
Box::new(crate::std::helix::HelixRevolutions),
|
Box::new(crate::std::helix::HelixRevolutions),
|
||||||
Box::new(crate::std::shell::Shell),
|
Box::new(crate::std::shell::Shell),
|
||||||
|
@ -11,13 +11,12 @@ use parse_display::{Display, FromStr};
|
|||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::execution::kcl_value::RuntimeType;
|
|
||||||
use crate::execution::PrimitiveType;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
execution::{
|
execution::{
|
||||||
Artifact, ArtifactId, BasePath, CodeRef, ExecState, Face, GeoMeta, KclValue, Path, Plane, Point2d, Point3d,
|
kcl_value::RuntimeType, Artifact, ArtifactId, BasePath, CodeRef, ExecState, Face, GeoMeta, KclValue, Path,
|
||||||
Sketch, SketchSurface, Solid, StartSketchOnFace, StartSketchOnPlane, TagEngineInfo, TagIdentifier,
|
Plane, Point2d, Point3d, PrimitiveType, Sketch, SketchSurface, Solid, StartSketchOnFace, StartSketchOnPlane,
|
||||||
|
TagEngineInfo, TagIdentifier,
|
||||||
},
|
},
|
||||||
parsing::ast::types::TagNode,
|
parsing::ast::types::TagNode,
|
||||||
std::{
|
std::{
|
||||||
|
Binary file not shown.
After Width: | Height: | Size: 140 KiB |
Reference in New Issue
Block a user