Merge branch 'main' into pierremtb/issue5393-Add-edge-and-segment-selection-in-point-and-click-Helix-flow

This commit is contained in:
Pierre Jacquier
2025-03-19 17:21:54 -04:00
60 changed files with 23581 additions and 53 deletions

View File

@ -12,6 +12,8 @@ You can provide more than one sketch to extrude, and they will all be extruded i
extrude(
sketches: [Sketch],
length: number,
tagStart?: TagDeclarator,
tagEnd?: TagDeclarator,
): [Solid]
```
@ -22,6 +24,8 @@ extrude(
|----------|------|-------------|----------|
| `sketches` | [`[Sketch]`](/docs/kcl/types/Sketch) | Which sketch or sketches should be extruded | Yes |
| `length` | [`number`](/docs/kcl/types/number) | How far to extrude the given sketches | Yes |
| `tagStart` | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | A named tag for the face at the start of the extrusion, i.e. the original sketch | No |
| `tagEnd` | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | A named tag for the face at the end of the extrusion, i.e. the new face created by extruding the original sketch | No |
### Returns

View File

@ -15,6 +15,8 @@ loft(
bezApproximateRational: bool,
baseCurveIndex?: integer,
tolerance?: number,
tagStart?: TagDeclarator,
tagEnd?: TagDeclarator,
): Solid
```
@ -28,6 +30,8 @@ loft(
| `bezApproximateRational` | [`bool`](/docs/kcl/types/bool) | Attempt to approximate rational curves (such as arcs) using a bezier. This will remove banding around interpolations between arcs and non-arcs. It may produce errors in other scenarios Over time, this field won't be necessary. | Yes |
| `baseCurveIndex` | `integer` | This can be set to override the automatically determined topological base curve, which is usually the first section encountered. | No |
| `tolerance` | [`number`](/docs/kcl/types/number) | Tolerance for the loft operation. | No |
| `tagStart` | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | A named tag for the face at the start of the loft, i.e. the original sketch | No |
| `tagEnd` | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | A named tag for the face at the end of the loft, i.e. the last sketch | No |
### Returns

View File

@ -18,6 +18,8 @@ revolve(
axis: Axis2dOrEdgeReference,
angle?: number,
tolerance?: number,
tagStart?: TagDeclarator,
tagEnd?: TagDeclarator,
): [Solid]
```
@ -30,6 +32,8 @@ revolve(
| `axis` | [`Axis2dOrEdgeReference`](/docs/kcl/types/Axis2dOrEdgeReference) | Axis of revolution. | Yes |
| `angle` | [`number`](/docs/kcl/types/number) | Angle to revolve (in degrees). Default is 360. | No |
| `tolerance` | [`number`](/docs/kcl/types/number) | Tolerance for the revolve operation. | No |
| `tagStart` | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | A named tag for the face at the start of the revolve, i.e. the original sketch | No |
| `tagEnd` | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | A named tag for the face at the end of the revolve | No |
### Returns

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -16,6 +16,8 @@ sweep(
path: SweepPath,
sectional?: bool,
tolerance?: number,
tagStart?: TagDeclarator,
tagEnd?: TagDeclarator,
): [Solid]
```
@ -28,6 +30,8 @@ sweep(
| `path` | [`SweepPath`](/docs/kcl/types/SweepPath) | The path to sweep the sketch along | Yes |
| `sectional` | [`bool`](/docs/kcl/types/bool) | If true, the sweep will be broken up into sub-sweeps (extrusions, revolves, sweeps) based on the trajectory path components. | No |
| `tolerance` | [`number`](/docs/kcl/types/number) | Tolerance for this operation | No |
| `tagStart` | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | A named tag for the face at the start of the sweep, i.e. the original sketch | No |
| `tagEnd` | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | A named tag for the face at the end of the sweep | No |
### Returns

20
rust/Cargo.lock generated
View File

@ -1780,7 +1780,7 @@ dependencies = [
[[package]]
name = "kcl-bumper"
version = "0.1.50"
version = "0.1.51"
dependencies = [
"anyhow",
"clap",
@ -1791,7 +1791,7 @@ dependencies = [
[[package]]
name = "kcl-derive-docs"
version = "0.1.50"
version = "0.1.51"
dependencies = [
"Inflector",
"anyhow",
@ -1810,7 +1810,7 @@ dependencies = [
[[package]]
name = "kcl-directory-test-macro"
version = "0.1.50"
version = "0.1.51"
dependencies = [
"proc-macro2",
"quote",
@ -1819,7 +1819,7 @@ dependencies = [
[[package]]
name = "kcl-language-server"
version = "0.2.50"
version = "0.2.51"
dependencies = [
"anyhow",
"clap",
@ -1840,7 +1840,7 @@ dependencies = [
[[package]]
name = "kcl-language-server-release"
version = "0.1.50"
version = "0.1.51"
dependencies = [
"anyhow",
"clap",
@ -1860,7 +1860,7 @@ dependencies = [
[[package]]
name = "kcl-lib"
version = "0.2.50"
version = "0.2.51"
dependencies = [
"anyhow",
"approx 0.5.1",
@ -1928,7 +1928,7 @@ dependencies = [
[[package]]
name = "kcl-python-bindings"
version = "0.3.50"
version = "0.3.51"
dependencies = [
"anyhow",
"kcl-lib",
@ -1943,7 +1943,7 @@ dependencies = [
[[package]]
name = "kcl-test-server"
version = "0.1.50"
version = "0.1.51"
dependencies = [
"anyhow",
"hyper 0.14.32",
@ -1956,7 +1956,7 @@ dependencies = [
[[package]]
name = "kcl-to-core"
version = "0.1.50"
version = "0.1.51"
dependencies = [
"anyhow",
"async-trait",
@ -1970,7 +1970,7 @@ dependencies = [
[[package]]
name = "kcl-wasm-lib"
version = "0.1.50"
version = "0.1.51"
dependencies = [
"bson",
"console_error_panic_hook",

View File

@ -1,7 +1,7 @@
[package]
name = "kcl-bumper"
version = "0.1.50"
version = "0.1.51"
edition = "2021"
repository = "https://github.com/KittyCAD/modeling-api"
rust-version = "1.76"

View File

@ -1,7 +1,7 @@
[package]
name = "kcl-derive-docs"
description = "A tool for generating documentation from Rust derive macros"
version = "0.1.50"
version = "0.1.51"
edition = "2021"
license = "MIT"
repository = "https://github.com/KittyCAD/modeling-app"

View File

@ -1,7 +1,7 @@
[package]
name = "kcl-directory-test-macro"
description = "A tool for generating tests from a directory of kcl files"
version = "0.1.50"
version = "0.1.51"
edition = "2021"
license = "MIT"
repository = "https://github.com/KittyCAD/modeling-app"

View File

@ -1,6 +1,6 @@
[package]
name = "kcl-language-server-release"
version = "0.1.50"
version = "0.1.51"
edition = "2021"
authors = ["KittyCAD Inc <kcl@kittycad.io>"]
publish = false

View File

@ -2,7 +2,7 @@
name = "kcl-language-server"
description = "A language server for KCL."
authors = ["KittyCAD Inc <kcl@kittycad.io>"]
version = "0.2.50"
version = "0.2.51"
edition = "2021"
license = "MIT"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View File

@ -1,7 +1,7 @@
[package]
name = "kcl-lib"
description = "KittyCAD Language implementation and tools"
version = "0.2.50"
version = "0.2.51"
edition = "2021"
license = "MIT"
repository = "https://github.com/KittyCAD/modeling-app"

View File

@ -831,8 +831,7 @@ impl ExecutorContext {
.await?;
let (module_memory, _) = self
.exec_module_for_items(id, exec_state, ExecutionKind::Isolated, source_range)
.await
.unwrap();
.await?;
exec_state.mut_stack().memory.set_std(module_memory);
}

View File

@ -2289,3 +2289,66 @@ mod bad_units_in_annotation {
super::execute(TEST_NAME, true).await
}
}
mod translate_after_fillet {
const TEST_NAME: &str = "translate_after_fillet";
/// Test parsing KCL.
#[test]
fn parse() {
super::parse(TEST_NAME)
}
/// Test that parsing and unparsing KCL produces the original KCL input.
#[tokio::test(flavor = "multi_thread")]
async fn unparse() {
super::unparse(TEST_NAME).await
}
/// Test that KCL is executed correctly.
#[tokio::test(flavor = "multi_thread")]
async fn kcl_test_execute() {
super::execute(TEST_NAME, true).await
}
}
mod scale_after_fillet {
const TEST_NAME: &str = "scale_after_fillet";
/// Test parsing KCL.
#[test]
fn parse() {
super::parse(TEST_NAME)
}
/// Test that parsing and unparsing KCL produces the original KCL input.
#[tokio::test(flavor = "multi_thread")]
async fn unparse() {
super::unparse(TEST_NAME).await
}
/// Test that KCL is executed correctly.
#[tokio::test(flavor = "multi_thread")]
async fn kcl_test_execute() {
super::execute(TEST_NAME, true).await
}
}
mod rotate_after_fillet {
const TEST_NAME: &str = "rotate_after_fillet";
/// Test parsing KCL.
#[test]
fn parse() {
super::parse(TEST_NAME)
}
/// Test that parsing and unparsing KCL produces the original KCL input.
#[tokio::test(flavor = "multi_thread")]
async fn unparse() {
super::unparse(TEST_NAME).await
}
/// Test that KCL is executed correctly.
#[tokio::test(flavor = "multi_thread")]
async fn kcl_test_execute() {
super::execute(TEST_NAME, true).await
}
}

View File

@ -376,7 +376,7 @@ impl Args {
pub(crate) async fn flush_batch_for_solids(
&self,
exec_state: &mut ExecState,
solids: Vec<Solid>,
solids: &[Solid],
) -> Result<(), KclError> {
// Make sure we don't traverse sketches more than once.
let mut traversed_sketches = Vec::new();

View File

@ -22,6 +22,7 @@ use crate::{
kcl_value::{ArrayLen, RuntimeType},
ArtifactId, ExecState, ExtrudeSurface, GeoMeta, KclValue, Path, PrimitiveType, Sketch, SketchSurface, Solid,
},
parsing::ast::types::TagNode,
std::Args,
};
@ -33,8 +34,10 @@ pub async fn extrude(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
exec_state,
)?;
let length = args.get_kw_arg("length")?;
let tag_start = args.get_kw_arg_opt("tagStart")?;
let tag_end = args.get_kw_arg_opt("tagEnd")?;
let result = inner_extrude(sketches, length, exec_state, args).await?;
let result = inner_extrude(sketches, length, tag_start, tag_end, exec_state, args).await?;
Ok(result.into())
}
@ -96,11 +99,16 @@ pub async fn extrude(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
args = {
sketches = { docs = "Which sketch or sketches should be extruded"},
length = { docs = "How far to extrude the given sketches"},
tag_start = { docs = "A named tag for the face at the start of the extrusion, i.e. the original sketch" },
tag_end = { docs = "A named tag for the face at the end of the extrusion, i.e. the new face created by extruding the original sketch" },
}
}]
#[allow(clippy::too_many_arguments)]
async fn inner_extrude(
sketches: Vec<Sketch>,
length: f64,
tag_start: Option<TagNode>,
tag_end: Option<TagNode>,
exec_state: &mut ExecState,
args: Args,
) -> Result<Vec<Solid>, KclError> {
@ -121,18 +129,38 @@ async fn inner_extrude(
))
.await?;
solids.push(do_post_extrude(sketch.clone(), id.into(), length, exec_state, args.clone()).await?);
solids.push(
do_post_extrude(
sketch,
id.into(),
length,
&NamedCapTags {
start: tag_start.as_ref(),
end: tag_end.as_ref(),
},
exec_state,
&args,
)
.await?,
);
}
Ok(solids)
}
pub(crate) async fn do_post_extrude(
sketch: Sketch,
#[derive(Debug, Default)]
pub(crate) struct NamedCapTags<'a> {
pub start: Option<&'a TagNode>,
pub end: Option<&'a TagNode>,
}
pub(crate) async fn do_post_extrude<'a>(
sketch: &Sketch,
solid_id: ArtifactId,
length: f64,
named_cap_tags: &'a NamedCapTags<'a>,
exec_state: &mut ExecState,
args: Args,
args: &Args,
) -> Result<Solid, KclError> {
// Bring the object to the front of the scene.
// See: https://github.com/KittyCAD/modeling-app/issues/806
@ -217,10 +245,11 @@ pub(crate) async fn do_post_extrude(
sides: face_id_map,
start_cap_id,
end_cap_id,
} = analyze_faces(exec_state, &args, face_infos).await;
} = analyze_faces(exec_state, args, face_infos).await;
// Iterate over the sketch.value array and add face_id to GeoMeta
let no_engine_commands = args.ctx.no_engine_commands().await;
let new_value = sketch
let mut new_value: Vec<ExtrudeSurface> = sketch
.paths
.iter()
.flat_map(|path| {
@ -283,6 +312,48 @@ pub(crate) async fn do_post_extrude(
})
.collect();
// Add the tags for the start or end caps.
if let Some(tag_start) = named_cap_tags.start {
let Some(start_cap_id) = start_cap_id else {
return Err(KclError::Type(KclErrorDetails {
message: format!(
"Expected a start cap ID for tag `{}` for extrusion of sketch {:?}",
tag_start.name, sketch.id
),
source_ranges: vec![args.source_range],
}));
};
new_value.push(ExtrudeSurface::ExtrudePlane(crate::execution::ExtrudePlane {
face_id: start_cap_id,
tag: Some(tag_start.clone()),
geo_meta: GeoMeta {
id: start_cap_id,
metadata: args.source_range.into(),
},
}));
}
if let Some(tag_end) = named_cap_tags.end {
let Some(end_cap_id) = end_cap_id else {
return Err(KclError::Type(KclErrorDetails {
message: format!(
"Expected an end cap ID for tag `{}` for extrusion of sketch {:?}",
tag_end.name, sketch.id
),
source_ranges: vec![args.source_range],
}));
};
new_value.push(ExtrudeSurface::ExtrudePlane(crate::execution::ExtrudePlane {
face_id: end_cap_id,
tag: Some(tag_end.clone()),
geo_meta: GeoMeta {
id: end_cap_id,
metadata: args.source_range.into(),
},
}));
}
Ok(Solid {
// Ok so you would think that the id would be the id of the solid,
// that we passed in to the function, but it's actually the id of the

View File

@ -13,6 +13,7 @@ use crate::{
kcl_value::{ArrayLen, RuntimeType},
ExecState, KclValue, PrimitiveType, Sketch, Solid,
},
parsing::ast::types::TagNode,
std::{extrude::do_post_extrude, fillet::default_tolerance, Args},
};
@ -36,6 +37,8 @@ pub async fn loft(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
let base_curve_index: Option<u32> = args.get_kw_arg_opt("baseCurveIndex")?;
// Tolerance for the loft operation.
let tolerance: Option<f64> = args.get_kw_arg_opt("tolerance")?;
let tag_start = args.get_kw_arg_opt("tagStart")?;
let tag_end = args.get_kw_arg_opt("tagEnd")?;
let value = inner_loft(
sketches,
@ -43,6 +46,8 @@ pub async fn loft(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
bez_approximate_rational,
base_curve_index,
tolerance,
tag_start,
tag_end,
exec_state,
args,
)
@ -127,14 +132,19 @@ pub async fn loft(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
bez_approximate_rational = {docs = "Attempt to approximate rational curves (such as arcs) using a bezier. This will remove banding around interpolations between arcs and non-arcs. It may produce errors in other scenarios Over time, this field won't be necessary."},
base_curve_index = {docs = "This can be set to override the automatically determined topological base curve, which is usually the first section encountered."},
tolerance = {docs = "Tolerance for the loft operation."},
tag_start = { docs = "A named tag for the face at the start of the loft, i.e. the original sketch" },
tag_end = { docs = "A named tag for the face at the end of the loft, i.e. the last sketch" },
}
}]
#[allow(clippy::too_many_arguments)]
async fn inner_loft(
sketches: Vec<Sketch>,
v_degree: NonZeroU32,
bez_approximate_rational: bool,
base_curve_index: Option<u32>,
tolerance: Option<f64>,
tag_start: Option<TagNode>,
tag_end: Option<TagNode>,
exec_state: &mut ExecState,
args: Args,
) -> Result<Box<Solid>, KclError> {
@ -167,6 +177,17 @@ async fn inner_loft(
// Override its id with the loft id so we can get its faces later
sketch.id = id;
Ok(Box::new(
do_post_extrude(sketch, id.into(), 0.0, exec_state, args).await?,
do_post_extrude(
&sketch,
id.into(),
0.0,
&super::extrude::NamedCapTags {
start: tag_start.as_ref(),
end: tag_end.as_ref(),
},
exec_state,
&args,
)
.await?,
))
}

View File

@ -363,7 +363,7 @@ async fn execute_pattern_transform<T: GeometryTrait>(
// Flush the batch for our fillets/chamfers if there are any.
// If we do not flush these, then you won't be able to pattern something with fillets.
// Flush just the fillets/chamfers that apply to these solids.
T::flush_batch(args, exec_state, geo_set.clone()).await?;
T::flush_batch(args, exec_state, &geo_set).await?;
let starting: Vec<T> = geo_set.into();
if args.ctx.context_type == crate::execution::ContextType::Mock {
@ -614,7 +614,7 @@ trait GeometryTrait: Clone {
fn original_id(&self) -> Uuid;
fn set_id(&mut self, id: Uuid);
fn array_to_point3d(val: &KclValue, source_ranges: Vec<SourceRange>) -> Result<Point3d, KclError>;
async fn flush_batch(args: &Args, exec_state: &mut ExecState, set: Self::Set) -> Result<(), KclError>;
async fn flush_batch(args: &Args, exec_state: &mut ExecState, set: &Self::Set) -> Result<(), KclError>;
}
impl GeometryTrait for Sketch {
@ -633,7 +633,7 @@ impl GeometryTrait for Sketch {
Ok(Point3d { x, y, z: 0.0 })
}
async fn flush_batch(_: &Args, _: &mut ExecState, _: Self::Set) -> Result<(), KclError> {
async fn flush_batch(_: &Args, _: &mut ExecState, _: &Self::Set) -> Result<(), KclError> {
Ok(())
}
}
@ -656,7 +656,7 @@ impl GeometryTrait for Solid {
array_to_point3d(val, source_ranges)
}
async fn flush_batch(args: &Args, exec_state: &mut ExecState, solid_set: Self::Set) -> Result<(), KclError> {
async fn flush_batch(args: &Args, exec_state: &mut ExecState, solid_set: &Self::Set) -> Result<(), KclError> {
args.flush_batch_for_solids(exec_state, solid_set).await
}
}
@ -1221,7 +1221,7 @@ async fn inner_pattern_circular_3d(
// Flush the batch for our fillets/chamfers if there are any.
// If we do not flush these, then you won't be able to pattern something with fillets.
// Flush just the fillets/chamfers that apply to these solids.
args.flush_batch_for_solids(exec_state, solids.clone()).await?;
args.flush_batch_for_solids(exec_state, &solids).await?;
let starting_solids = solids;

View File

@ -11,6 +11,7 @@ use crate::{
kcl_value::{ArrayLen, RuntimeType},
ExecState, KclValue, PrimitiveType, Sketch, Solid,
},
parsing::ast::types::TagNode,
std::{axis_or_reference::Axis2dOrEdgeReference, extrude::do_post_extrude, fillet::default_tolerance, Args},
};
@ -24,8 +25,10 @@ pub async fn revolve(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
let axis: Axis2dOrEdgeReference = args.get_kw_arg("axis")?;
let angle = args.get_kw_arg_opt("angle")?;
let tolerance = args.get_kw_arg_opt("tolerance")?;
let tag_start = args.get_kw_arg_opt("tagStart")?;
let tag_end = args.get_kw_arg_opt("tagEnd")?;
let value = inner_revolve(sketches, axis, angle, tolerance, exec_state, args).await?;
let value = inner_revolve(sketches, axis, angle, tolerance, tag_start, tag_end, exec_state, args).await?;
Ok(value.into())
}
@ -234,13 +237,18 @@ pub async fn revolve(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
axis = { docs = "Axis of revolution." },
angle = { docs = "Angle to revolve (in degrees). Default is 360." },
tolerance = { docs = "Tolerance for the revolve operation." },
tag_start = { docs = "A named tag for the face at the start of the revolve, i.e. the original sketch" },
tag_end = { docs = "A named tag for the face at the end of the revolve" },
}
}]
#[allow(clippy::too_many_arguments)]
async fn inner_revolve(
sketches: Vec<Sketch>,
axis: Axis2dOrEdgeReference,
angle: Option<f64>,
tolerance: Option<f64>,
tag_start: Option<TagNode>,
tag_end: Option<TagNode>,
exec_state: &mut ExecState,
args: Args,
) -> Result<Vec<Solid>, KclError> {
@ -293,7 +301,20 @@ async fn inner_revolve(
}
}
solids.push(do_post_extrude(sketch.clone(), id.into(), 0.0, exec_state, args.clone()).await?);
solids.push(
do_post_extrude(
sketch,
id.into(),
0.0,
&super::extrude::NamedCapTags {
start: tag_start.as_ref(),
end: tag_end.as_ref(),
},
exec_state,
&args,
)
.await?,
);
}
Ok(solids)

View File

@ -210,7 +210,7 @@ async fn inner_shell(
for solid in &solids {
// Flush the batch for our fillets/chamfers if there are any.
// If we do not do these for sketch on face, things will fail with face does not exist.
args.flush_batch_for_solids(exec_state, vec![solid.clone()]).await?;
args.flush_batch_for_solids(exec_state, &[solid.clone()]).await?;
for tag in &faces {
let extrude_plane_id = tag.get_face_id(solid, exec_state, &args, false).await?;
@ -320,7 +320,7 @@ async fn inner_hollow(
) -> Result<Box<Solid>, KclError> {
// Flush the batch for our fillets/chamfers if there are any.
// If we do not do these for sketch on face, things will fail with face does not exist.
args.flush_batch_for_solids(exec_state, vec![(*solid).clone()]).await?;
args.flush_batch_for_solids(exec_state, &[(*solid).clone()]).await?;
args.batch_modeling_cmd(
exec_state.next_uuid(),

View File

@ -951,6 +951,37 @@ pub async fn start_sketch_on(exec_state: &mut ExecState, args: Args) -> Result<K
/// ```
///
/// ```no_run
/// // Sketch on the end of an extruded face by tagging the end face.
///
/// exampleSketch = startSketchOn(XY)
/// |> startProfileAt([0, 0], %)
/// |> line(end = [10, 0])
/// |> line(end = [0, 10])
/// |> line(end = [-10, 0])
/// |> close()
///
/// example = extrude(exampleSketch, length = 5, tagEnd = $end01)
///
/// exampleSketch002 = startSketchOn(example, end01)
/// |> startProfileAt([1, 1], %)
/// |> line(end = [8, 0])
/// |> line(end = [0, 8])
/// |> line(end = [-8, 0])
/// |> close()
///
/// example002 = extrude(exampleSketch002, length = 5, tagEnd = $end02)
///
/// exampleSketch003 = startSketchOn(example002, end02)
/// |> startProfileAt([2, 2], %)
/// |> line(end = [6, 0])
/// |> line(end = [0, 6])
/// |> line(end = [-6, 0])
/// |> close()
///
/// example003 = extrude(exampleSketch003, length = 5)
/// ```
///
/// ```no_run
/// exampleSketch = startSketchOn(XY)
/// |> startProfileAt([0, 0], %)
/// |> line(end = [10, 0])
@ -1004,6 +1035,32 @@ pub async fn start_sketch_on(exec_state: &mut ExecState, args: Args) -> Result<K
/// ```
///
/// ```no_run
/// // Sketch on the end of a revolved face by tagging the end face.
///
/// exampleSketch = startSketchOn(XY)
/// |> startProfileAt([4, 12], %)
/// |> line(end = [2, 0])
/// |> line(end = [0, -6])
/// |> line(end = [4, -6])
/// |> line(end = [0, -6])
/// |> line(end = [-3.75, -4.5])
/// |> line(end = [0, -5.5])
/// |> line(end = [-2, 0])
/// |> close()
///
/// example = revolve(exampleSketch, axis = 'y', angle = 180, tagEnd = $end01)
///
/// exampleSketch002 = startSketchOn(example, end01)
/// |> startProfileAt([4.5, -5], %)
/// |> line(end = [0, 5])
/// |> line(end = [5, 0])
/// |> line(end = [0, -5])
/// |> close()
///
/// example002 = extrude(exampleSketch002, length = 5)
/// ```
///
/// ```no_run
/// a1 = startSketchOn({
/// plane: {
/// origin = { x = 0, y = 0, z = 0 },
@ -1212,7 +1269,7 @@ pub(crate) async fn inner_start_profile_at(
SketchSurface::Face(face) => {
// Flush the batch for our fillets/chamfers if there are any.
// If we do not do these for sketch on face, things will fail with face does not exist.
args.flush_batch_for_solids(exec_state, vec![(*face.solid).clone()])
args.flush_batch_for_solids(exec_state, &[(*face.solid).clone()])
.await?;
}
SketchSurface::Plane(plane) if !plane.is_standard() => {

View File

@ -13,6 +13,7 @@ use crate::{
kcl_value::{ArrayLen, RuntimeType},
ExecState, Helix, KclValue, PrimitiveType, Sketch, Solid,
},
parsing::ast::types::TagNode,
std::{extrude::do_post_extrude, fillet::default_tolerance, Args},
};
@ -35,8 +36,13 @@ pub async fn sweep(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
let path: SweepPath = args.get_kw_arg("path")?;
let sectional = args.get_kw_arg_opt("sectional")?;
let tolerance = args.get_kw_arg_opt("tolerance")?;
let tag_start = args.get_kw_arg_opt("tagStart")?;
let tag_end = args.get_kw_arg_opt("tagEnd")?;
let value = inner_sweep(sketches, path, sectional, tolerance, exec_state, args).await?;
let value = inner_sweep(
sketches, path, sectional, tolerance, tag_start, tag_end, exec_state, args,
)
.await?;
Ok(value.into())
}
@ -145,13 +151,18 @@ pub async fn sweep(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
path = { docs = "The path to sweep the sketch along" },
sectional = { docs = "If true, the sweep will be broken up into sub-sweeps (extrusions, revolves, sweeps) based on the trajectory path components." },
tolerance = { docs = "Tolerance for this operation" },
tag_start = { docs = "A named tag for the face at the start of the sweep, i.e. the original sketch" },
tag_end = { docs = "A named tag for the face at the end of the sweep" },
}
}]
#[allow(clippy::too_many_arguments)]
async fn inner_sweep(
sketches: Vec<Sketch>,
path: SweepPath,
sectional: Option<bool>,
tolerance: Option<f64>,
tag_start: Option<TagNode>,
tag_end: Option<TagNode>,
exec_state: &mut ExecState,
args: Args,
) -> Result<Vec<Solid>, KclError> {
@ -174,7 +185,20 @@ async fn inner_sweep(
)
.await?;
solids.push(do_post_extrude(sketch.clone(), id.into(), 0.0, exec_state, args.clone()).await?);
solids.push(
do_post_extrude(
sketch,
id.into(),
0.0,
&super::extrude::NamedCapTags {
start: tag_start.as_ref(),
end: tag_end.as_ref(),
},
exec_state,
&args,
)
.await?,
);
}
Ok(solids)

View File

@ -147,6 +147,12 @@ async fn inner_scale(
exec_state: &mut ExecState,
args: Args,
) -> Result<SolidOrSketchOrImportedGeometry, KclError> {
// If we have a solid, flush the fillets and chamfers.
// Only transforms needs this, it is very odd, see: https://github.com/KittyCAD/modeling-app/issues/5880
if let SolidOrSketchOrImportedGeometry::SolidSet(solids) = &objects {
args.flush_batch_for_solids(exec_state, solids).await?;
}
for object_id in objects.ids() {
let id = exec_state.next_uuid();
@ -344,6 +350,12 @@ async fn inner_translate(
exec_state: &mut ExecState,
args: Args,
) -> Result<SolidOrSketchOrImportedGeometry, KclError> {
// If we have a solid, flush the fillets and chamfers.
// Only transforms needs this, it is very odd, see: https://github.com/KittyCAD/modeling-app/issues/5880
if let SolidOrSketchOrImportedGeometry::SolidSet(solids) = &objects {
args.flush_batch_for_solids(exec_state, solids).await?;
}
for object_id in objects.ids() {
let id = exec_state.next_uuid();
@ -690,6 +702,12 @@ async fn inner_rotate(
exec_state: &mut ExecState,
args: Args,
) -> Result<SolidOrSketchOrImportedGeometry, KclError> {
// If we have a solid, flush the fillets and chamfers.
// Only transforms needs this, it is very odd, see: https://github.com/KittyCAD/modeling-app/issues/5880
if let SolidOrSketchOrImportedGeometry::SolidSet(solids) = &objects {
args.flush_batch_for_solids(exec_state, solids).await?;
}
for object_id in objects.ids() {
let id = exec_state.next_uuid();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,6 @@
---
source: kcl-lib/src/simulation_tests.rs
description: Artifact graph flowchart rotate_after_fillet.kcl
extension: md
snapshot_kind: binary
---

View File

@ -0,0 +1,134 @@
```mermaid
flowchart LR
subgraph path2 [Path]
2["Path<br>[347, 417, 0]"]
3["Segment<br>[347, 417, 0]"]
4[Solid2d]
end
subgraph path13 [Path]
13["Path<br>[655, 742, 0]"]
14["Segment<br>[750, 833, 0]"]
15["Segment<br>[841, 924, 0]"]
16["Segment<br>[932, 1015, 0]"]
17["Segment<br>[1023, 1105, 0]"]
18["Segment<br>[1113, 1195, 0]"]
19["Segment<br>[1203, 1210, 0]"]
20[Solid2d]
end
subgraph path41 [Path]
41["Path<br>[1311, 1380, 0]"]
42["Segment<br>[1311, 1380, 0]"]
43[Solid2d]
end
1["Plane<br>[320, 339, 0]"]
5["Sweep Extrusion<br>[425, 458, 0]"]
6[Wall]
7["Cap Start"]
8["Cap End"]
9["SweepEdge Opposite"]
10["SweepEdge Adjacent"]
11["EdgeCut Fillet<br>[466, 532, 0]"]
12["EdgeCut Fillet<br>[466, 532, 0]"]
21["Sweep Extrusion<br>[1218, 1258, 0]"]
22[Wall]
23[Wall]
24[Wall]
25[Wall]
26[Wall]
27[Wall]
28["Cap Start"]
29["SweepEdge Opposite"]
30["SweepEdge Adjacent"]
31["SweepEdge Opposite"]
32["SweepEdge Adjacent"]
33["SweepEdge Opposite"]
34["SweepEdge Adjacent"]
35["SweepEdge Opposite"]
36["SweepEdge Adjacent"]
37["SweepEdge Opposite"]
38["SweepEdge Adjacent"]
39["SweepEdge Opposite"]
40["SweepEdge Adjacent"]
44["Sweep Extrusion<br>[1388, 1416, 0]"]
45[Wall]
46["Cap End"]
47["SweepEdge Opposite"]
48["SweepEdge Adjacent"]
49["EdgeCut Fillet<br>[1424, 1483, 0]"]
50["StartSketchOnFace<br>[615, 647, 0]"]
51["StartSketchOnFace<br>[1273, 1303, 0]"]
1 --- 2
2 --- 3
2 ---- 5
2 --- 4
3 --- 6
3 --- 9
3 --- 10
3 --- 11
5 --- 6
5 --- 7
5 --- 8
5 --- 9
5 --- 10
7 --- 13
8 --- 41
9 <--x 12
13 --- 14
13 --- 15
13 --- 16
13 --- 17
13 --- 18
13 --- 19
13 ---- 21
13 --- 20
14 --- 27
14 --- 39
14 --- 40
15 --- 26
15 --- 37
15 --- 38
16 --- 25
16 --- 35
16 --- 36
17 --- 24
17 --- 33
17 --- 34
18 --- 23
18 --- 31
18 --- 32
19 --- 22
19 --- 29
19 --- 30
21 --- 22
21 --- 23
21 --- 24
21 --- 25
21 --- 26
21 --- 27
21 --- 28
21 --- 29
21 --- 30
21 --- 31
21 --- 32
21 --- 33
21 --- 34
21 --- 35
21 --- 36
21 --- 37
21 --- 38
21 --- 39
21 --- 40
41 --- 42
41 ---- 44
41 --- 43
42 --- 45
42 --- 47
42 --- 48
44 --- 45
44 --- 46
44 --- 47
44 --- 48
47 <--x 49
7 <--x 50
8 <--x 51
```

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,57 @@
export boltDiameter = 0.625
export boltLength = 2.500
export boltHeadLength = boltDiameter
export boltHeadDiameter = 0.938
export boltHexDrive = 1 / 2
export boltHexFlatLength = boltHexDrive / (2 * cos(toRadians(30)))
export boltThreadLength = 1.75
export fn bolt() {
// Create the head of the cap screw
boltHead = startSketchOn('XZ')
|> circle(center = [0, 0], radius = boltHeadDiameter / 2, tag = $topEdge)
|> extrude(length = -boltHeadLength)
|> fillet(radius = 0.020, tags = [topEdge, getOppositeEdge(topEdge)])
// Define the sketch of the hex pattern on the screw head
hexPatternSketch = startSketchOn(boltHead, 'start')
|> startProfileAt([
boltHexDrive / 2,
boltHexFlatLength / 2
], %)
|> angledLine({
angle = 270,
length = boltHexFlatLength
}, %)
|> angledLine({
angle = 210,
length = boltHexFlatLength
}, %)
|> angledLine({
angle = 150,
length = boltHexFlatLength
}, %)
|> angledLine({
angle = 90,
length = boltHexFlatLength
}, %)
|> angledLine({
angle = 30,
length = boltHexFlatLength
}, %)
|> close()
|> extrude(length = -boltHeadLength * 0.75)
boltBody = startSketchOn(boltHead, 'end')
|> circle(center = [0, 0], radius = boltDiameter / 2, tag = $filletEdge)
|> extrude(length = boltLength)
|> fillet(radius = .020, tags = [getOppositeEdge(filletEdge)])
|> appearance(color = "#4dd043", metalness = 90, roughness = 90)
return boltBody
}
bolt()
|> rotate(roll = 3.14, pitch = 3.14, yaw = 3.14)
// https://www.mcmaster.com/91251a404/

View File

@ -0,0 +1,390 @@
---
source: kcl-lib/src/simulation_tests.rs
description: Operations executed rotate_after_fillet.kcl
---
[
{
"type": "UserDefinedFunctionCall",
"name": "cos",
"functionSourceRange": [
0,
0,
0
],
"unlabeledArg": null,
"labeledArgs": {},
"sourceRange": [
198,
216,
0
]
},
{
"type": "UserDefinedFunctionReturn"
},
{
"type": "UserDefinedFunctionCall",
"name": "bolt",
"functionSourceRange": [
264,
1573,
0
],
"unlabeledArg": null,
"labeledArgs": {},
"sourceRange": [
1575,
1581,
0
]
},
{
"labeledArgs": {
"data": {
"value": {
"type": "String",
"value": "XZ"
},
"sourceRange": [
334,
338,
0
]
}
},
"name": "startSketchOn",
"sourceRange": [
320,
339,
0
],
"type": "StdLibCall",
"unlabeledArg": null
},
{
"labeledArgs": {
"length": {
"value": {
"type": "Number",
"value": -0.625,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": [
442,
457,
0
]
}
},
"name": "extrude",
"sourceRange": [
425,
458,
0
],
"type": "StdLibCall",
"unlabeledArg": {
"value": {
"type": "Sketch",
"value": {
"artifactId": "[uuid]"
}
},
"sourceRange": [
425,
458,
0
]
}
},
{
"labeledArgs": {
"radius": {
"value": {
"type": "Number",
"value": 0.02,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": [
482,
487,
0
]
},
"tags": {
"value": {
"type": "Array",
"value": [
{
"type": "TagIdentifier",
"value": "topEdge",
"artifact_id": "[uuid]"
},
{
"type": "Uuid",
"value": "[uuid]"
}
]
},
"sourceRange": [
496,
531,
0
]
}
},
"name": "fillet",
"sourceRange": [
466,
532,
0
],
"type": "StdLibCall",
"unlabeledArg": {
"value": {
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
},
"sourceRange": [
466,
532,
0
]
}
},
{
"labeledArgs": {
"data": {
"value": {
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
},
"sourceRange": [
629,
637,
0
]
},
"tag": {
"value": {
"type": "String",
"value": "start"
},
"sourceRange": [
639,
646,
0
]
}
},
"name": "startSketchOn",
"sourceRange": [
615,
647,
0
],
"type": "StdLibCall",
"unlabeledArg": null
},
{
"labeledArgs": {
"length": {
"value": {
"type": "Number",
"value": -0.46875,
"ty": {
"type": "Unknown"
}
},
"sourceRange": [
1235,
1257,
0
]
}
},
"name": "extrude",
"sourceRange": [
1218,
1258,
0
],
"type": "StdLibCall",
"unlabeledArg": {
"value": {
"type": "Sketch",
"value": {
"artifactId": "[uuid]"
}
},
"sourceRange": [
1218,
1258,
0
]
}
},
{
"labeledArgs": {
"data": {
"value": {
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
},
"sourceRange": [
1287,
1295,
0
]
},
"tag": {
"value": {
"type": "String",
"value": "end"
},
"sourceRange": [
1297,
1302,
0
]
}
},
"name": "startSketchOn",
"sourceRange": [
1273,
1303,
0
],
"type": "StdLibCall",
"unlabeledArg": null
},
{
"labeledArgs": {
"length": {
"value": {
"type": "Number",
"value": 2.5,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": [
1405,
1415,
0
]
}
},
"name": "extrude",
"sourceRange": [
1388,
1416,
0
],
"type": "StdLibCall",
"unlabeledArg": {
"value": {
"type": "Sketch",
"value": {
"artifactId": "[uuid]"
}
},
"sourceRange": [
1388,
1416,
0
]
}
},
{
"labeledArgs": {
"radius": {
"value": {
"type": "Number",
"value": 0.02,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": [
1440,
1444,
0
]
},
"tags": {
"value": {
"type": "Array",
"value": [
{
"type": "Uuid",
"value": "[uuid]"
}
]
},
"sourceRange": [
1453,
1482,
0
]
}
},
"name": "fillet",
"sourceRange": [
1424,
1483,
0
],
"type": "StdLibCall",
"unlabeledArg": {
"value": {
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
},
"sourceRange": [
1424,
1483,
0
]
}
},
{
"type": "UserDefinedFunctionReturn"
}
]

View File

@ -0,0 +1,93 @@
---
source: kcl-lib/src/simulation_tests.rs
description: Variables in memory after executing rotate_after_fillet.kcl
---
{
"bolt": {
"type": "Function"
},
"boltDiameter": {
"type": "Number",
"value": 0.625,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"boltHeadDiameter": {
"type": "Number",
"value": 0.938,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"boltHeadLength": {
"type": "Number",
"value": 0.625,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"boltHexDrive": {
"type": "Number",
"value": 0.5,
"ty": {
"type": "Unknown"
}
},
"boltHexFlatLength": {
"type": "Number",
"value": 0.2887,
"ty": {
"type": "Unknown"
}
},
"boltLength": {
"type": "Number",
"value": 2.5,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"boltThreadLength": {
"type": "Number",
"value": 1.75,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"filletEdge": {
"type": "TagIdentifier",
"type": "TagIdentifier",
"value": "filletEdge"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,6 @@
---
source: kcl-lib/src/simulation_tests.rs
description: Artifact graph flowchart scale_after_fillet.kcl
extension: md
snapshot_kind: binary
---

View File

@ -0,0 +1,134 @@
```mermaid
flowchart LR
subgraph path2 [Path]
2["Path<br>[347, 417, 0]"]
3["Segment<br>[347, 417, 0]"]
4[Solid2d]
end
subgraph path13 [Path]
13["Path<br>[655, 742, 0]"]
14["Segment<br>[750, 833, 0]"]
15["Segment<br>[841, 924, 0]"]
16["Segment<br>[932, 1015, 0]"]
17["Segment<br>[1023, 1105, 0]"]
18["Segment<br>[1113, 1195, 0]"]
19["Segment<br>[1203, 1210, 0]"]
20[Solid2d]
end
subgraph path41 [Path]
41["Path<br>[1311, 1380, 0]"]
42["Segment<br>[1311, 1380, 0]"]
43[Solid2d]
end
1["Plane<br>[320, 339, 0]"]
5["Sweep Extrusion<br>[425, 458, 0]"]
6[Wall]
7["Cap Start"]
8["Cap End"]
9["SweepEdge Opposite"]
10["SweepEdge Adjacent"]
11["EdgeCut Fillet<br>[466, 532, 0]"]
12["EdgeCut Fillet<br>[466, 532, 0]"]
21["Sweep Extrusion<br>[1218, 1258, 0]"]
22[Wall]
23[Wall]
24[Wall]
25[Wall]
26[Wall]
27[Wall]
28["Cap Start"]
29["SweepEdge Opposite"]
30["SweepEdge Adjacent"]
31["SweepEdge Opposite"]
32["SweepEdge Adjacent"]
33["SweepEdge Opposite"]
34["SweepEdge Adjacent"]
35["SweepEdge Opposite"]
36["SweepEdge Adjacent"]
37["SweepEdge Opposite"]
38["SweepEdge Adjacent"]
39["SweepEdge Opposite"]
40["SweepEdge Adjacent"]
44["Sweep Extrusion<br>[1388, 1416, 0]"]
45[Wall]
46["Cap End"]
47["SweepEdge Opposite"]
48["SweepEdge Adjacent"]
49["EdgeCut Fillet<br>[1424, 1483, 0]"]
50["StartSketchOnFace<br>[615, 647, 0]"]
51["StartSketchOnFace<br>[1273, 1303, 0]"]
1 --- 2
2 --- 3
2 ---- 5
2 --- 4
3 --- 6
3 --- 9
3 --- 10
3 --- 11
5 --- 6
5 --- 7
5 --- 8
5 --- 9
5 --- 10
7 --- 13
8 --- 41
9 <--x 12
13 --- 14
13 --- 15
13 --- 16
13 --- 17
13 --- 18
13 --- 19
13 ---- 21
13 --- 20
14 --- 27
14 --- 39
14 --- 40
15 --- 26
15 --- 37
15 --- 38
16 --- 25
16 --- 35
16 --- 36
17 --- 24
17 --- 33
17 --- 34
18 --- 23
18 --- 31
18 --- 32
19 --- 22
19 --- 29
19 --- 30
21 --- 22
21 --- 23
21 --- 24
21 --- 25
21 --- 26
21 --- 27
21 --- 28
21 --- 29
21 --- 30
21 --- 31
21 --- 32
21 --- 33
21 --- 34
21 --- 35
21 --- 36
21 --- 37
21 --- 38
21 --- 39
21 --- 40
41 --- 42
41 ---- 44
41 --- 43
42 --- 45
42 --- 47
42 --- 48
44 --- 45
44 --- 46
44 --- 47
44 --- 48
47 <--x 49
7 <--x 50
8 <--x 51
```

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,57 @@
export boltDiameter = 0.625
export boltLength = 2.500
export boltHeadLength = boltDiameter
export boltHeadDiameter = 0.938
export boltHexDrive = 1 / 2
export boltHexFlatLength = boltHexDrive / (2 * cos(toRadians(30)))
export boltThreadLength = 1.75
export fn bolt() {
// Create the head of the cap screw
boltHead = startSketchOn('XZ')
|> circle(center = [0, 0], radius = boltHeadDiameter / 2, tag = $topEdge)
|> extrude(length = -boltHeadLength)
|> fillet(radius = 0.020, tags = [topEdge, getOppositeEdge(topEdge)])
// Define the sketch of the hex pattern on the screw head
hexPatternSketch = startSketchOn(boltHead, 'start')
|> startProfileAt([
boltHexDrive / 2,
boltHexFlatLength / 2
], %)
|> angledLine({
angle = 270,
length = boltHexFlatLength
}, %)
|> angledLine({
angle = 210,
length = boltHexFlatLength
}, %)
|> angledLine({
angle = 150,
length = boltHexFlatLength
}, %)
|> angledLine({
angle = 90,
length = boltHexFlatLength
}, %)
|> angledLine({
angle = 30,
length = boltHexFlatLength
}, %)
|> close()
|> extrude(length = -boltHeadLength * 0.75)
boltBody = startSketchOn(boltHead, 'end')
|> circle(center = [0, 0], radius = boltDiameter / 2, tag = $filletEdge)
|> extrude(length = boltLength)
|> fillet(radius = .020, tags = [getOppositeEdge(filletEdge)])
|> appearance(color = "#4dd043", metalness = 90, roughness = 90)
return boltBody
}
bolt()
|> scale(scale = [3.14, 3.14, 3.14])
// https://www.mcmaster.com/91251a404/

View File

@ -0,0 +1,390 @@
---
source: kcl-lib/src/simulation_tests.rs
description: Operations executed scale_after_fillet.kcl
---
[
{
"type": "UserDefinedFunctionCall",
"name": "cos",
"functionSourceRange": [
0,
0,
0
],
"unlabeledArg": null,
"labeledArgs": {},
"sourceRange": [
198,
216,
0
]
},
{
"type": "UserDefinedFunctionReturn"
},
{
"type": "UserDefinedFunctionCall",
"name": "bolt",
"functionSourceRange": [
264,
1573,
0
],
"unlabeledArg": null,
"labeledArgs": {},
"sourceRange": [
1575,
1581,
0
]
},
{
"labeledArgs": {
"data": {
"value": {
"type": "String",
"value": "XZ"
},
"sourceRange": [
334,
338,
0
]
}
},
"name": "startSketchOn",
"sourceRange": [
320,
339,
0
],
"type": "StdLibCall",
"unlabeledArg": null
},
{
"labeledArgs": {
"length": {
"value": {
"type": "Number",
"value": -0.625,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": [
442,
457,
0
]
}
},
"name": "extrude",
"sourceRange": [
425,
458,
0
],
"type": "StdLibCall",
"unlabeledArg": {
"value": {
"type": "Sketch",
"value": {
"artifactId": "[uuid]"
}
},
"sourceRange": [
425,
458,
0
]
}
},
{
"labeledArgs": {
"radius": {
"value": {
"type": "Number",
"value": 0.02,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": [
482,
487,
0
]
},
"tags": {
"value": {
"type": "Array",
"value": [
{
"type": "TagIdentifier",
"value": "topEdge",
"artifact_id": "[uuid]"
},
{
"type": "Uuid",
"value": "[uuid]"
}
]
},
"sourceRange": [
496,
531,
0
]
}
},
"name": "fillet",
"sourceRange": [
466,
532,
0
],
"type": "StdLibCall",
"unlabeledArg": {
"value": {
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
},
"sourceRange": [
466,
532,
0
]
}
},
{
"labeledArgs": {
"data": {
"value": {
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
},
"sourceRange": [
629,
637,
0
]
},
"tag": {
"value": {
"type": "String",
"value": "start"
},
"sourceRange": [
639,
646,
0
]
}
},
"name": "startSketchOn",
"sourceRange": [
615,
647,
0
],
"type": "StdLibCall",
"unlabeledArg": null
},
{
"labeledArgs": {
"length": {
"value": {
"type": "Number",
"value": -0.46875,
"ty": {
"type": "Unknown"
}
},
"sourceRange": [
1235,
1257,
0
]
}
},
"name": "extrude",
"sourceRange": [
1218,
1258,
0
],
"type": "StdLibCall",
"unlabeledArg": {
"value": {
"type": "Sketch",
"value": {
"artifactId": "[uuid]"
}
},
"sourceRange": [
1218,
1258,
0
]
}
},
{
"labeledArgs": {
"data": {
"value": {
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
},
"sourceRange": [
1287,
1295,
0
]
},
"tag": {
"value": {
"type": "String",
"value": "end"
},
"sourceRange": [
1297,
1302,
0
]
}
},
"name": "startSketchOn",
"sourceRange": [
1273,
1303,
0
],
"type": "StdLibCall",
"unlabeledArg": null
},
{
"labeledArgs": {
"length": {
"value": {
"type": "Number",
"value": 2.5,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": [
1405,
1415,
0
]
}
},
"name": "extrude",
"sourceRange": [
1388,
1416,
0
],
"type": "StdLibCall",
"unlabeledArg": {
"value": {
"type": "Sketch",
"value": {
"artifactId": "[uuid]"
}
},
"sourceRange": [
1388,
1416,
0
]
}
},
{
"labeledArgs": {
"radius": {
"value": {
"type": "Number",
"value": 0.02,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": [
1440,
1444,
0
]
},
"tags": {
"value": {
"type": "Array",
"value": [
{
"type": "Uuid",
"value": "[uuid]"
}
]
},
"sourceRange": [
1453,
1482,
0
]
}
},
"name": "fillet",
"sourceRange": [
1424,
1483,
0
],
"type": "StdLibCall",
"unlabeledArg": {
"value": {
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
},
"sourceRange": [
1424,
1483,
0
]
}
},
{
"type": "UserDefinedFunctionReturn"
}
]

View File

@ -0,0 +1,93 @@
---
source: kcl-lib/src/simulation_tests.rs
description: Variables in memory after executing scale_after_fillet.kcl
---
{
"bolt": {
"type": "Function"
},
"boltDiameter": {
"type": "Number",
"value": 0.625,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"boltHeadDiameter": {
"type": "Number",
"value": 0.938,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"boltHeadLength": {
"type": "Number",
"value": 0.625,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"boltHexDrive": {
"type": "Number",
"value": 0.5,
"ty": {
"type": "Unknown"
}
},
"boltHexFlatLength": {
"type": "Number",
"value": 0.2887,
"ty": {
"type": "Unknown"
}
},
"boltLength": {
"type": "Number",
"value": 2.5,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"boltThreadLength": {
"type": "Number",
"value": 1.75,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"filletEdge": {
"type": "TagIdentifier",
"type": "TagIdentifier",
"value": "filletEdge"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,6 @@
---
source: kcl-lib/src/simulation_tests.rs
description: Artifact graph flowchart translate_after_fillet.kcl
extension: md
snapshot_kind: binary
---

View File

@ -0,0 +1,134 @@
```mermaid
flowchart LR
subgraph path2 [Path]
2["Path<br>[347, 417, 0]"]
3["Segment<br>[347, 417, 0]"]
4[Solid2d]
end
subgraph path13 [Path]
13["Path<br>[655, 742, 0]"]
14["Segment<br>[750, 833, 0]"]
15["Segment<br>[841, 924, 0]"]
16["Segment<br>[932, 1015, 0]"]
17["Segment<br>[1023, 1105, 0]"]
18["Segment<br>[1113, 1195, 0]"]
19["Segment<br>[1203, 1210, 0]"]
20[Solid2d]
end
subgraph path41 [Path]
41["Path<br>[1311, 1380, 0]"]
42["Segment<br>[1311, 1380, 0]"]
43[Solid2d]
end
1["Plane<br>[320, 339, 0]"]
5["Sweep Extrusion<br>[425, 458, 0]"]
6[Wall]
7["Cap Start"]
8["Cap End"]
9["SweepEdge Opposite"]
10["SweepEdge Adjacent"]
11["EdgeCut Fillet<br>[466, 532, 0]"]
12["EdgeCut Fillet<br>[466, 532, 0]"]
21["Sweep Extrusion<br>[1218, 1258, 0]"]
22[Wall]
23[Wall]
24[Wall]
25[Wall]
26[Wall]
27[Wall]
28["Cap Start"]
29["SweepEdge Opposite"]
30["SweepEdge Adjacent"]
31["SweepEdge Opposite"]
32["SweepEdge Adjacent"]
33["SweepEdge Opposite"]
34["SweepEdge Adjacent"]
35["SweepEdge Opposite"]
36["SweepEdge Adjacent"]
37["SweepEdge Opposite"]
38["SweepEdge Adjacent"]
39["SweepEdge Opposite"]
40["SweepEdge Adjacent"]
44["Sweep Extrusion<br>[1388, 1416, 0]"]
45[Wall]
46["Cap End"]
47["SweepEdge Opposite"]
48["SweepEdge Adjacent"]
49["EdgeCut Fillet<br>[1424, 1483, 0]"]
50["StartSketchOnFace<br>[615, 647, 0]"]
51["StartSketchOnFace<br>[1273, 1303, 0]"]
1 --- 2
2 --- 3
2 ---- 5
2 --- 4
3 --- 6
3 --- 9
3 --- 10
3 --- 11
5 --- 6
5 --- 7
5 --- 8
5 --- 9
5 --- 10
7 --- 13
8 --- 41
9 <--x 12
13 --- 14
13 --- 15
13 --- 16
13 --- 17
13 --- 18
13 --- 19
13 ---- 21
13 --- 20
14 --- 27
14 --- 39
14 --- 40
15 --- 26
15 --- 37
15 --- 38
16 --- 25
16 --- 35
16 --- 36
17 --- 24
17 --- 33
17 --- 34
18 --- 23
18 --- 31
18 --- 32
19 --- 22
19 --- 29
19 --- 30
21 --- 22
21 --- 23
21 --- 24
21 --- 25
21 --- 26
21 --- 27
21 --- 28
21 --- 29
21 --- 30
21 --- 31
21 --- 32
21 --- 33
21 --- 34
21 --- 35
21 --- 36
21 --- 37
21 --- 38
21 --- 39
21 --- 40
41 --- 42
41 ---- 44
41 --- 43
42 --- 45
42 --- 47
42 --- 48
44 --- 45
44 --- 46
44 --- 47
44 --- 48
47 <--x 49
7 <--x 50
8 <--x 51
```

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,57 @@
export boltDiameter = 0.625
export boltLength = 2.500
export boltHeadLength = boltDiameter
export boltHeadDiameter = 0.938
export boltHexDrive = 1 / 2
export boltHexFlatLength = boltHexDrive / (2 * cos(toRadians(30)))
export boltThreadLength = 1.75
export fn bolt() {
// Create the head of the cap screw
boltHead = startSketchOn('XZ')
|> circle(center = [0, 0], radius = boltHeadDiameter / 2, tag = $topEdge)
|> extrude(length = -boltHeadLength)
|> fillet(radius = 0.020, tags = [topEdge, getOppositeEdge(topEdge)])
// Define the sketch of the hex pattern on the screw head
hexPatternSketch = startSketchOn(boltHead, 'start')
|> startProfileAt([
boltHexDrive / 2,
boltHexFlatLength / 2
], %)
|> angledLine({
angle = 270,
length = boltHexFlatLength
}, %)
|> angledLine({
angle = 210,
length = boltHexFlatLength
}, %)
|> angledLine({
angle = 150,
length = boltHexFlatLength
}, %)
|> angledLine({
angle = 90,
length = boltHexFlatLength
}, %)
|> angledLine({
angle = 30,
length = boltHexFlatLength
}, %)
|> close()
|> extrude(length = -boltHeadLength * 0.75)
boltBody = startSketchOn(boltHead, 'end')
|> circle(center = [0, 0], radius = boltDiameter / 2, tag = $filletEdge)
|> extrude(length = boltLength)
|> fillet(radius = .020, tags = [getOppositeEdge(filletEdge)])
|> appearance(color = "#4dd043", metalness = 90, roughness = 90)
return boltBody
}
bolt()
|> translate(translate = [10, 0, 0])
// https://www.mcmaster.com/91251a404/

View File

@ -0,0 +1,390 @@
---
source: kcl-lib/src/simulation_tests.rs
description: Operations executed translate_after_fillet.kcl
---
[
{
"type": "UserDefinedFunctionCall",
"name": "cos",
"functionSourceRange": [
0,
0,
0
],
"unlabeledArg": null,
"labeledArgs": {},
"sourceRange": [
198,
216,
0
]
},
{
"type": "UserDefinedFunctionReturn"
},
{
"type": "UserDefinedFunctionCall",
"name": "bolt",
"functionSourceRange": [
264,
1573,
0
],
"unlabeledArg": null,
"labeledArgs": {},
"sourceRange": [
1575,
1581,
0
]
},
{
"labeledArgs": {
"data": {
"value": {
"type": "String",
"value": "XZ"
},
"sourceRange": [
334,
338,
0
]
}
},
"name": "startSketchOn",
"sourceRange": [
320,
339,
0
],
"type": "StdLibCall",
"unlabeledArg": null
},
{
"labeledArgs": {
"length": {
"value": {
"type": "Number",
"value": -0.625,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": [
442,
457,
0
]
}
},
"name": "extrude",
"sourceRange": [
425,
458,
0
],
"type": "StdLibCall",
"unlabeledArg": {
"value": {
"type": "Sketch",
"value": {
"artifactId": "[uuid]"
}
},
"sourceRange": [
425,
458,
0
]
}
},
{
"labeledArgs": {
"radius": {
"value": {
"type": "Number",
"value": 0.02,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": [
482,
487,
0
]
},
"tags": {
"value": {
"type": "Array",
"value": [
{
"type": "TagIdentifier",
"value": "topEdge",
"artifact_id": "[uuid]"
},
{
"type": "Uuid",
"value": "[uuid]"
}
]
},
"sourceRange": [
496,
531,
0
]
}
},
"name": "fillet",
"sourceRange": [
466,
532,
0
],
"type": "StdLibCall",
"unlabeledArg": {
"value": {
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
},
"sourceRange": [
466,
532,
0
]
}
},
{
"labeledArgs": {
"data": {
"value": {
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
},
"sourceRange": [
629,
637,
0
]
},
"tag": {
"value": {
"type": "String",
"value": "start"
},
"sourceRange": [
639,
646,
0
]
}
},
"name": "startSketchOn",
"sourceRange": [
615,
647,
0
],
"type": "StdLibCall",
"unlabeledArg": null
},
{
"labeledArgs": {
"length": {
"value": {
"type": "Number",
"value": -0.46875,
"ty": {
"type": "Unknown"
}
},
"sourceRange": [
1235,
1257,
0
]
}
},
"name": "extrude",
"sourceRange": [
1218,
1258,
0
],
"type": "StdLibCall",
"unlabeledArg": {
"value": {
"type": "Sketch",
"value": {
"artifactId": "[uuid]"
}
},
"sourceRange": [
1218,
1258,
0
]
}
},
{
"labeledArgs": {
"data": {
"value": {
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
},
"sourceRange": [
1287,
1295,
0
]
},
"tag": {
"value": {
"type": "String",
"value": "end"
},
"sourceRange": [
1297,
1302,
0
]
}
},
"name": "startSketchOn",
"sourceRange": [
1273,
1303,
0
],
"type": "StdLibCall",
"unlabeledArg": null
},
{
"labeledArgs": {
"length": {
"value": {
"type": "Number",
"value": 2.5,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": [
1405,
1415,
0
]
}
},
"name": "extrude",
"sourceRange": [
1388,
1416,
0
],
"type": "StdLibCall",
"unlabeledArg": {
"value": {
"type": "Sketch",
"value": {
"artifactId": "[uuid]"
}
},
"sourceRange": [
1388,
1416,
0
]
}
},
{
"labeledArgs": {
"radius": {
"value": {
"type": "Number",
"value": 0.02,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"sourceRange": [
1440,
1444,
0
]
},
"tags": {
"value": {
"type": "Array",
"value": [
{
"type": "Uuid",
"value": "[uuid]"
}
]
},
"sourceRange": [
1453,
1482,
0
]
}
},
"name": "fillet",
"sourceRange": [
1424,
1483,
0
],
"type": "StdLibCall",
"unlabeledArg": {
"value": {
"type": "Solid",
"value": {
"artifactId": "[uuid]"
}
},
"sourceRange": [
1424,
1483,
0
]
}
},
{
"type": "UserDefinedFunctionReturn"
}
]

View File

@ -0,0 +1,93 @@
---
source: kcl-lib/src/simulation_tests.rs
description: Variables in memory after executing translate_after_fillet.kcl
---
{
"bolt": {
"type": "Function"
},
"boltDiameter": {
"type": "Number",
"value": 0.625,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"boltHeadDiameter": {
"type": "Number",
"value": 0.938,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"boltHeadLength": {
"type": "Number",
"value": 0.625,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"boltHexDrive": {
"type": "Number",
"value": 0.5,
"ty": {
"type": "Unknown"
}
},
"boltHexFlatLength": {
"type": "Number",
"value": 0.2887,
"ty": {
"type": "Unknown"
}
},
"boltLength": {
"type": "Number",
"value": 2.5,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"boltThreadLength": {
"type": "Number",
"value": 1.75,
"ty": {
"type": "Default",
"len": {
"type": "Mm"
},
"angle": {
"type": "Degrees"
}
}
},
"filletEdge": {
"type": "TagIdentifier",
"type": "TagIdentifier",
"value": "filletEdge"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

View File

@ -1,6 +1,6 @@
[package]
name = "kcl-python-bindings"
version = "0.3.50"
version = "0.3.51"
edition = "2021"
repository = "https://github.com/kittycad/modeling-app"

View File

@ -1,7 +1,7 @@
[package]
name = "kcl-test-server"
description = "A test server for KCL"
version = "0.1.50"
version = "0.1.51"
edition = "2021"
license = "MIT"

View File

@ -1,7 +1,7 @@
[package]
name = "kcl-to-core"
description = "Utility methods to convert kcl to engine core executable tests"
version = "0.1.50"
version = "0.1.51"
edition = "2021"
license = "MIT"
repository = "https://github.com/KittyCAD/modeling-app"

View File

@ -1,6 +1,6 @@
[package]
name = "kcl-wasm-lib"
version = "0.1.50"
version = "0.1.51"
edition = "2021"
repository = "https://github.com/KittyCAD/modeling-app"
rust-version = "1.83"

View File

@ -9,6 +9,7 @@ import { KCLError } from 'lang/errors'
import { Diagnostic } from '@codemirror/lint'
import { Node } from '@rust/kcl-lib/bindings/Node'
import RustContext from 'lib/rustContext'
import { EXECUTE_AST_INTERRUPT_ERROR_STRING } from 'lib/constants'
export type ToolTip =
| 'lineTo'
@ -116,10 +117,7 @@ function handleExecuteError(e: any): ExecutionResult {
let isInterrupted = false
if (e instanceof KCLError) {
// Detect if it is a force interrupt error which is not a KCL processing error.
if (
e.msg ===
'Failed to wait for promise from engine: JsValue("Force interrupt, executionIsStale, new AST requested")'
) {
if (e.msg.includes(EXECUTE_AST_INTERRUPT_ERROR_STRING)) {
isInterrupted = true
}
return {

View File

@ -1,3 +1,5 @@
import { Models } from '@kittycad/lib/dist/types/src'
export const APP_NAME = 'Modeling App'
/** Search string in new project names to increment as an index */
export const INDEX_IDENTIFIER = '$n'
@ -83,9 +85,24 @@ export const TELEMETRY_RAW_FILE_NAME = 'raw-metrics.txt'
export const PLAYWRIGHT_KEY = 'playwright'
/** Custom error message to match when rejectAllModelCommands is called
* allows us to match if the execution of executeAst was interrupted */
export const EXECUTE_AST_INTERRUPT_ERROR_MESSAGE =
* allows us to match if the execution of executeAst was interrupted
* This needs to be of type WebsocketResponse, so that we can parse it back out
* nicely on the rust side.
* */
export const EXECUTE_AST_INTERRUPT_ERROR_STRING =
'Force interrupt, executionIsStale, new AST requested'
const EXECUTE_AST_INTERRUPT_ERROR: Models['WebSocketResponse_type'] = {
success: false,
errors: [
{
message: EXECUTE_AST_INTERRUPT_ERROR_STRING,
error_code: 'bad_request',
},
],
}
export const EXECUTE_AST_INTERRUPT_ERROR_MESSAGE = JSON.stringify(
EXECUTE_AST_INTERRUPT_ERROR
)
/** The messages that appear for exporting toasts */
export const EXPORT_TOAST_MESSAGES = {