Compare commits
10 Commits
v0.26.1
...
achalmers/
Author | SHA1 | Date | |
---|---|---|---|
976d5d2b4f | |||
4925251c29 | |||
9772869545 | |||
a7e830cd02 | |||
ca102116b6 | |||
c2fba89e77 | |||
7e31678ba2 | |||
1140ced121 | |||
32b7ddaa7c | |||
2525f99515 |
29432
docs/kcl/std.json
@ -18,7 +18,7 @@ Engine information for a tag.
|
||||
|----------|------|-------------|----------|
|
||||
| `id` |`string`| The id of the tagged object. | No |
|
||||
| `sketch` |`string`| The sketch the tag is on. | No |
|
||||
| `path` |[`BasePath`](/docs/kcl/types/BasePath)| The path the tag is on. | No |
|
||||
| `path` |[`Path`](/docs/kcl/types/Path)| The path the tag is on. | No |
|
||||
| `surface` |[`ExtrudeSurface`](/docs/kcl/types/ExtrudeSurface)| The surface information for the tag. | No |
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 44 KiB |
@ -996,7 +996,7 @@
|
||||
},
|
||||
"description": "",
|
||||
"title": "machine-api",
|
||||
"version": "0.1.0"
|
||||
"version": "0.1.1"
|
||||
},
|
||||
"openapi": "3.0.3",
|
||||
"paths": {
|
||||
|
@ -746,7 +746,6 @@ export class SceneEntities {
|
||||
},
|
||||
})
|
||||
},
|
||||
...this.mouseEnterLeaveCallbacks(),
|
||||
})
|
||||
}
|
||||
setupDraftRectangle = async (
|
||||
|
@ -213,7 +213,7 @@ export class SceneInfra {
|
||||
to: Coords2d
|
||||
angle?: number
|
||||
}): SegmentOverlayPayload | null {
|
||||
if (group.userData.pathToNode && arrowGroup) {
|
||||
if (!group.userData.draft && group.userData.pathToNode && arrowGroup) {
|
||||
const vector = new Vector3(0, 0, 0)
|
||||
|
||||
// Get the position of the object3D in world space
|
||||
|
@ -147,6 +147,7 @@ class StraightSegment implements SegmentUtils {
|
||||
segmentGroup.name = STRAIGHT_SEGMENT
|
||||
segmentGroup.userData = {
|
||||
type: STRAIGHT_SEGMENT,
|
||||
draft: isDraftSegment,
|
||||
id,
|
||||
from,
|
||||
to,
|
||||
@ -347,6 +348,7 @@ class TangentialArcToSegment implements SegmentUtils {
|
||||
mesh.name = meshName
|
||||
group.userData = {
|
||||
type: TANGENTIAL_ARC_TO_SEGMENT,
|
||||
draft: isDraftSegment,
|
||||
id,
|
||||
from,
|
||||
to,
|
||||
@ -515,11 +517,18 @@ class CircleSegment implements SegmentUtils {
|
||||
const meshType = isDraftSegment ? CIRCLE_SEGMENT_DASH : CIRCLE_SEGMENT_BODY
|
||||
const arrowGroup = createArrowhead(scale, theme, color)
|
||||
const circleCenterGroup = createCircleCenterHandle(scale, theme, color)
|
||||
// A radius indicator that appears from the center to the perimeter
|
||||
const radiusIndicatorGroup = createLengthIndicator({
|
||||
from: center,
|
||||
to: [center[0] + radius, center[1]],
|
||||
scale,
|
||||
})
|
||||
|
||||
arcMesh.userData.type = meshType
|
||||
arcMesh.name = meshType
|
||||
group.userData = {
|
||||
type: CIRCLE_SEGMENT,
|
||||
draft: isDraftSegment,
|
||||
id,
|
||||
from,
|
||||
radius,
|
||||
@ -532,7 +541,7 @@ class CircleSegment implements SegmentUtils {
|
||||
}
|
||||
group.name = CIRCLE_SEGMENT
|
||||
|
||||
group.add(arcMesh, arrowGroup, circleCenterGroup)
|
||||
group.add(arcMesh, arrowGroup, circleCenterGroup, radiusIndicatorGroup)
|
||||
const updateOverlaysCallback = this.update({
|
||||
prevSegment,
|
||||
input,
|
||||
@ -564,6 +573,9 @@ class CircleSegment implements SegmentUtils {
|
||||
group.userData.radius = radius
|
||||
group.userData.prevSegment = prevSegment
|
||||
const arrowGroup = group.getObjectByName(ARROWHEAD) as Group
|
||||
const radiusLengthIndicator = group.getObjectByName(
|
||||
SEGMENT_LENGTH_LABEL
|
||||
) as Group
|
||||
const circleCenterHandle = group.getObjectByName(
|
||||
CIRCLE_CENTER_HANDLE
|
||||
) as Group
|
||||
@ -581,11 +593,14 @@ class CircleSegment implements SegmentUtils {
|
||||
}
|
||||
|
||||
if (arrowGroup) {
|
||||
arrowGroup.position.set(
|
||||
center[0] + Math.cos(Math.PI / 4) * radius,
|
||||
center[1] + Math.sin(Math.PI / 4) * radius,
|
||||
0
|
||||
)
|
||||
// The arrowhead is placed at the perimeter of the circle,
|
||||
// pointing up and to the right
|
||||
const arrowPoint = {
|
||||
x: center[0] + Math.cos(Math.PI / 4) * radius,
|
||||
y: center[1] + Math.sin(Math.PI / 4) * radius,
|
||||
}
|
||||
|
||||
arrowGroup.position.set(arrowPoint.x, arrowPoint.y, 0)
|
||||
|
||||
const arrowheadAngle = Math.PI / 4
|
||||
arrowGroup.quaternion.setFromUnitVectors(
|
||||
@ -596,6 +611,31 @@ class CircleSegment implements SegmentUtils {
|
||||
arrowGroup.visible = isHandlesVisible
|
||||
}
|
||||
|
||||
if (radiusLengthIndicator) {
|
||||
// The radius indicator is placed at the midpoint of the radius,
|
||||
// at a 45 degree CCW angle from the positive X-axis
|
||||
const indicatorPoint = {
|
||||
x: center[0] + (Math.cos(Math.PI / 4) * radius) / 2,
|
||||
y: center[1] + (Math.sin(Math.PI / 4) * radius) / 2,
|
||||
}
|
||||
const labelWrapper = radiusLengthIndicator.getObjectByName(
|
||||
SEGMENT_LENGTH_LABEL_TEXT
|
||||
) as CSS2DObject
|
||||
const labelWrapperElem = labelWrapper.element as HTMLDivElement
|
||||
const label = labelWrapperElem.children[0] as HTMLParagraphElement
|
||||
label.innerText = `${roundOff(radius)}`
|
||||
label.classList.add(SEGMENT_LENGTH_LABEL_TEXT)
|
||||
const isPlaneBackFace = center[0] > indicatorPoint.x
|
||||
label.style.setProperty(
|
||||
'--degree',
|
||||
`${isPlaneBackFace ? '45' : '-45'}deg`
|
||||
)
|
||||
label.style.setProperty('--x', `0px`)
|
||||
label.style.setProperty('--y', `0px`)
|
||||
labelWrapper.position.set(indicatorPoint.x, indicatorPoint.y, 0)
|
||||
radiusLengthIndicator.visible = isHandlesVisible
|
||||
}
|
||||
|
||||
if (circleCenterHandle) {
|
||||
circleCenterHandle.position.set(center[0], center[1], 0)
|
||||
circleCenterHandle.scale.set(scale, scale, scale)
|
||||
|
@ -140,6 +140,13 @@ const FileTreeItem = ({
|
||||
async (eventType, path) => {
|
||||
// Don't try to read a file that was removed.
|
||||
if (isCurrentFile && eventType !== 'unlink') {
|
||||
// Prevents a cyclic read / write causing editor problems such as
|
||||
// misplaced cursor positions.
|
||||
if (codeManager.writeCausedByAppCheckedInFileTreeFileSystemWatcher) {
|
||||
codeManager.writeCausedByAppCheckedInFileTreeFileSystemWatcher = false
|
||||
return
|
||||
}
|
||||
|
||||
let code = await window.electron.readFile(path, { encoding: 'utf-8' })
|
||||
code = normalizeLineEndings(code)
|
||||
codeManager.updateCodeStateEditor(code)
|
||||
|
@ -20,6 +20,8 @@ export default class CodeManager {
|
||||
private _hotkeys: { [key: string]: () => void } = {}
|
||||
private timeoutWriter: ReturnType<typeof setTimeout> | undefined = undefined
|
||||
|
||||
public writeCausedByAppCheckedInFileTreeFileSystemWatcher = false
|
||||
|
||||
constructor() {
|
||||
if (isDesktop()) {
|
||||
this.code = ''
|
||||
@ -120,6 +122,7 @@ export default class CodeManager {
|
||||
// and file-system watchers which read, will receive empty data during
|
||||
// writes.
|
||||
clearTimeout(this.timeoutWriter)
|
||||
this.writeCausedByAppCheckedInFileTreeFileSystemWatcher = true
|
||||
this.timeoutWriter = setTimeout(() => {
|
||||
// Wait one event loop to give a chance for params to be set
|
||||
// Save the file to disk
|
||||
|
8
src/wasm-lib/Cargo.lock
generated
@ -1684,9 +1684,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kittycad-modeling-cmds"
|
||||
version = "0.2.70"
|
||||
version = "0.2.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b135696d07a4fab928e5abace4dd05f4976eafab5d73e5747a85dc5a684b936c"
|
||||
checksum = "c6d2160dcb0e5373b1242a760dbf17fb9c12de523c410c11b145381c852b377b"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
@ -2586,9 +2586,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.11.0"
|
||||
version = "1.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8"
|
||||
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
|
@ -72,7 +72,7 @@ members = [
|
||||
[workspace.dependencies]
|
||||
http = "1"
|
||||
kittycad = { version = "0.3.23", default-features = false, features = ["js", "requests"] }
|
||||
kittycad-modeling-cmds = { version = "0.2.70", features = ["websocket"] }
|
||||
kittycad-modeling-cmds = { version = "0.2.71", features = ["websocket"] }
|
||||
|
||||
[[test]]
|
||||
name = "executor"
|
||||
|
@ -17,7 +17,7 @@ convert_case = "0.6.0"
|
||||
once_cell = "1.20.2"
|
||||
proc-macro2 = "1"
|
||||
quote = "1"
|
||||
regex = "1.10"
|
||||
regex = "1.11"
|
||||
serde = { version = "1.0.213", features = ["derive"] }
|
||||
serde_tokenstream = "0.2"
|
||||
syn = { version = "2.0.85", features = ["full"] }
|
||||
|
@ -31,7 +31,7 @@ pub struct ServerArgs {
|
||||
/// Where to find the engine.
|
||||
/// If none, uses the prod engine.
|
||||
/// This is useful for testing a local engine instance.
|
||||
/// Overridden by the $LOCAL_ENGINE_ADDR environment variable.
|
||||
/// Overridden by the $ZOO_HOST environment variable.
|
||||
pub engine_address: Option<String>,
|
||||
}
|
||||
|
||||
@ -44,8 +44,8 @@ impl ServerArgs {
|
||||
num_engine_conns: pargs.opt_value_from_str("--num-engine-conns")?.unwrap_or(1),
|
||||
engine_address: pargs.opt_value_from_str("--engine-address")?,
|
||||
};
|
||||
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
|
||||
println!("Overriding engine address via $LOCAL_ENGINE_ADDR");
|
||||
if let Ok(addr) = std::env::var("ZOO_HOST") {
|
||||
println!("Overriding engine address via $ZOO_HOST");
|
||||
args.engine_address = Some(addr);
|
||||
}
|
||||
println!("Config is {args:?}");
|
||||
|
@ -1127,7 +1127,7 @@ pub struct TagEngineInfo {
|
||||
/// The sketch the tag is on.
|
||||
pub sketch: uuid::Uuid,
|
||||
/// The path the tag is on.
|
||||
pub path: Option<BasePath>,
|
||||
pub path: Option<Path>,
|
||||
/// The surface information for the tag.
|
||||
pub surface: Option<ExtrudeSurface>,
|
||||
}
|
||||
@ -1206,7 +1206,7 @@ impl Sketch {
|
||||
tag_identifier.info = Some(TagEngineInfo {
|
||||
id: base.geo_meta.id,
|
||||
sketch: self.id,
|
||||
path: Some(base.clone()),
|
||||
path: Some(current_path.clone()),
|
||||
surface: None,
|
||||
});
|
||||
|
||||
@ -1658,6 +1658,32 @@ pub enum Path {
|
||||
},
|
||||
}
|
||||
|
||||
/// What kind of path is this?
|
||||
#[derive(Display)]
|
||||
enum PathType {
|
||||
ToPoint,
|
||||
Base,
|
||||
TangentialArc,
|
||||
TangentialArcTo,
|
||||
Circle,
|
||||
Horizontal,
|
||||
AngledLineTo,
|
||||
}
|
||||
|
||||
impl From<Path> for PathType {
|
||||
fn from(value: Path) -> Self {
|
||||
match value {
|
||||
Path::ToPoint { .. } => Self::ToPoint,
|
||||
Path::TangentialArcTo { .. } => Self::TangentialArcTo,
|
||||
Path::TangentialArc { .. } => Self::TangentialArc,
|
||||
Path::Circle { .. } => Self::Circle,
|
||||
Path::Horizontal { .. } => Self::Horizontal,
|
||||
Path::AngledLineTo { .. } => Self::AngledLineTo,
|
||||
Path::Base { .. } => Self::Base,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Path {
|
||||
pub fn get_id(&self) -> uuid::Uuid {
|
||||
match self {
|
||||
@ -1695,6 +1721,21 @@ impl Path {
|
||||
}
|
||||
}
|
||||
|
||||
/// Where does this path segment start?
|
||||
pub fn get_from(&self) -> &[f64; 2] {
|
||||
&self.get_base().from
|
||||
}
|
||||
/// Where does this path segment end?
|
||||
pub fn get_to(&self) -> &[f64; 2] {
|
||||
&self.get_base().to
|
||||
}
|
||||
|
||||
/// Length of this path segment, in cartesian plane.
|
||||
pub fn length(&self) -> f64 {
|
||||
// TODO 4297: check what type of line this path is, don't assume linear.
|
||||
((self.get_from()[1] - self.get_to()[1]).powi(2) + (self.get_from()[0] - self.get_to()[0]).powi(2)).sqrt()
|
||||
}
|
||||
|
||||
pub fn get_base_mut(&mut self) -> Option<&mut BasePath> {
|
||||
match self {
|
||||
Path::ToPoint { base } => Some(base),
|
||||
@ -1962,7 +2003,7 @@ impl ExecutorContext {
|
||||
// Create the client.
|
||||
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
// Set a local engine address if it's set.
|
||||
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
|
||||
if let Ok(addr) = std::env::var("ZOO_HOST") {
|
||||
client.set_base_url(addr);
|
||||
}
|
||||
if let Some(addr) = engine_addr {
|
||||
|
@ -24,7 +24,7 @@ fn new_zoo_client() -> kittycad::Client {
|
||||
// Create the client.
|
||||
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
// Set a local engine address if it's set.
|
||||
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
|
||||
if let Ok(addr) = std::env::var("ZOO_HOST") {
|
||||
client.set_base_url(addr);
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@ fn inner_segment_end_x(tag: &TagIdentifier, exec_state: &mut ExecState, args: Ar
|
||||
})
|
||||
})?;
|
||||
|
||||
Ok(path.to[0])
|
||||
Ok(path.get_base().to[0])
|
||||
}
|
||||
|
||||
/// Returns the segment end of y.
|
||||
@ -79,7 +79,7 @@ fn inner_segment_end_y(tag: &TagIdentifier, exec_state: &mut ExecState, args: Ar
|
||||
})
|
||||
})?;
|
||||
|
||||
Ok(path.to[1])
|
||||
Ok(path.get_to()[1])
|
||||
}
|
||||
|
||||
/// Returns the last segment of x.
|
||||
@ -202,7 +202,7 @@ fn inner_segment_length(tag: &TagIdentifier, exec_state: &mut ExecState, args: A
|
||||
})
|
||||
})?;
|
||||
|
||||
let result = ((path.from[1] - path.to[1]).powi(2) + (path.from[0] - path.to[0]).powi(2)).sqrt();
|
||||
let result = path.length();
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
@ -242,7 +242,7 @@ fn inner_segment_angle(tag: &TagIdentifier, exec_state: &mut ExecState, args: Ar
|
||||
})
|
||||
})?;
|
||||
|
||||
let result = between(path.from.into(), path.to.into());
|
||||
let result = between(path.get_from().into(), path.get_to().into());
|
||||
|
||||
Ok(result.to_degrees())
|
||||
}
|
||||
@ -286,7 +286,7 @@ fn inner_angle_to_match_length_x(
|
||||
})
|
||||
})?;
|
||||
|
||||
let length = ((path.from[1] - path.to[1]).powi(2) + (path.from[0] - path.to[0]).powi(2)).sqrt();
|
||||
let length = path.length();
|
||||
|
||||
let last_line = sketch
|
||||
.paths
|
||||
@ -350,7 +350,7 @@ fn inner_angle_to_match_length_y(
|
||||
})
|
||||
})?;
|
||||
|
||||
let length = ((path.from[1] - path.to[1]).powi(2) + (path.from[0] - path.to[0]).powi(2)).sqrt();
|
||||
let length = path.length();
|
||||
|
||||
let last_line = sketch
|
||||
.paths
|
||||
|
@ -813,7 +813,7 @@ async fn inner_angled_line_that_intersects(
|
||||
|
||||
let from = sketch.current_pen_position()?;
|
||||
let to = intersection_with_parallel_line(
|
||||
&[path.from.into(), path.to.into()],
|
||||
&[path.get_from().into(), path.get_to().into()],
|
||||
data.offset.unwrap_or_default(),
|
||||
data.angle,
|
||||
from,
|
||||
@ -1244,7 +1244,9 @@ pub(crate) async fn inner_start_profile_at(
|
||||
tag_identifier.info = Some(TagEngineInfo {
|
||||
id: current_path.geo_meta.id,
|
||||
sketch: path_id,
|
||||
path: Some(current_path.clone()),
|
||||
path: Some(Path::Base {
|
||||
base: current_path.clone(),
|
||||
}),
|
||||
surface: None,
|
||||
});
|
||||
HashMap::from([(tag.name.to_string(), tag_identifier)])
|
||||
|
@ -67,7 +67,7 @@ async fn new_context(units: UnitLength, with_auth: bool) -> anyhow::Result<Execu
|
||||
// Create the client.
|
||||
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
// Set a local engine address if it's set.
|
||||
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
|
||||
if let Ok(addr) = std::env::var("ZOO_HOST") {
|
||||
if with_auth {
|
||||
client.set_base_url(addr);
|
||||
}
|
||||
|
@ -0,0 +1,15 @@
|
||||
exampleSketch = startSketchOn('XZ')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line([0, 2], %)
|
||||
|> line([3, 1], %)
|
||||
|> line([0, -4], %)
|
||||
|> close(%)
|
||||
|> extrude(1, %)
|
||||
|
||||
pattn1 = patternLinear3d({
|
||||
axis: [1, 0, 0],
|
||||
instances: 7,
|
||||
distance: 6
|
||||
}, exampleSketch)
|
||||
|
||||
pattn2 = patternCircular3d({axis: [0,0, 1], center: [-20, -20, -20], instances: 41, arcDegrees: 360, rotateDuplicates: false}, pattn1)
|
@ -0,0 +1,19 @@
|
||||
exampleSketch = startSketchOn('XZ')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line([0, 2], %)
|
||||
|> line([3, 1], %)
|
||||
|> line([0, -4], %)
|
||||
|> close(%)
|
||||
|> extrude(1, %)
|
||||
|
||||
pattn1 = patternLinear3d({
|
||||
axis: [1, 0, 0],
|
||||
instances: 7,
|
||||
distance: 6
|
||||
}, exampleSketch)
|
||||
|
||||
pattn2 = patternLinear3d({
|
||||
axis: [0, 0, 1],
|
||||
distance: 1,
|
||||
instances: 7
|
||||
}, pattn1)
|
6
src/wasm-lib/tests/executor/inputs/neg_xz_plane.kcl
Normal file
@ -0,0 +1,6 @@
|
||||
part001 = startSketchOn('-XZ')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> lineTo([100, 100], %)
|
||||
|> lineTo([100, 0], %)
|
||||
|> close(%)
|
||||
|> extrude(5 + 7, %)
|
@ -0,0 +1,55 @@
|
||||
// Shelf Bracket
|
||||
// This is a shelf bracket made out of 6061-T6 aluminum sheet metal. The required thickness is calculated based on a point load of 300 lbs applied to the end of the shelf. There are two brackets holding up the shelf, so the moment experienced is divided by 2. The shelf is 1 foot long from the wall.
|
||||
|
||||
|
||||
// Define our bracket feet lengths
|
||||
shelfMountL = 8 // The length of the bracket holding up the shelf is 6 inches
|
||||
wallMountL = 6 // the length of the bracket
|
||||
|
||||
|
||||
// Define constants required to calculate the thickness needed to support 300 lbs
|
||||
sigmaAllow = 35000 // psi
|
||||
width = 6 // inch
|
||||
p = 300 // Force on shelf - lbs
|
||||
L = 12 // inches
|
||||
M = L * p / 2 // Moment experienced at fixed end of bracket
|
||||
FOS = 2 // Factor of safety of 2 to be conservative
|
||||
|
||||
|
||||
// Calculate the thickness off the bending stress and factor of safety
|
||||
thickness = sqrt(6 * M * FOS / (width * sigmaAllow))
|
||||
|
||||
// 0.25 inch fillet radius
|
||||
filletR = 0.25
|
||||
|
||||
// Sketch the bracket and extrude with fillets
|
||||
bracket = startSketchOn('XY')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line([0, wallMountL], %, $outerEdge)
|
||||
|> line([-shelfMountL, 0], %, $seg01)
|
||||
|> line([0, -thickness], %)
|
||||
|> line([shelfMountL - thickness, 0], %, $innerEdge)
|
||||
|> line([0, -wallMountL + thickness], %)
|
||||
|> close(%)
|
||||
|> extrude(width, %)
|
||||
|> fillet({
|
||||
radius: filletR,
|
||||
tags: [
|
||||
getNextAdjacentEdge(innerEdge)
|
||||
]
|
||||
}, %)
|
||||
|> fillet({
|
||||
radius: filletR + thickness,
|
||||
tags: [
|
||||
getNextAdjacentEdge(outerEdge)
|
||||
]
|
||||
}, %)
|
||||
|
||||
sketch001 = startSketchOn(bracket, seg01)
|
||||
|> startProfileAt([4.28, 3.83], %)
|
||||
|> line([2.17, -0.03], %)
|
||||
|> line([-0.07, -1.8], %)
|
||||
|> line([-2.07, 0.05], %)
|
||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> close(%)
|
||||
|> extrude(10, %)
|
6
src/wasm-lib/tests/executor/inputs/xz_plane.kcl
Normal file
@ -0,0 +1,6 @@
|
||||
part001 = startSketchOn('XZ')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> lineTo([100, 100], %)
|
||||
|> lineTo([100, 0], %)
|
||||
|> close(%)
|
||||
|> extrude(5 + 7, %)
|
@ -1389,84 +1389,6 @@ extrusion = startSketchOn('XY')
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn kcl_test_xz_plane() {
|
||||
let code = r#"part001 = startSketchOn('XZ')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> lineTo([100, 100], %)
|
||||
|> lineTo([100, 0], %)
|
||||
|> close(%)
|
||||
|> extrude(5 + 7, %)
|
||||
"#;
|
||||
|
||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||
assert_out("xz_plane", &result);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn kcl_test_neg_xz_plane() {
|
||||
let code = r#"part001 = startSketchOn('-XZ')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> lineTo([100, 100], %)
|
||||
|> lineTo([100, 0], %)
|
||||
|> close(%)
|
||||
|> extrude(5 + 7, %)
|
||||
"#;
|
||||
|
||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||
assert_out("neg_xz_plane", &result);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn kcl_test_linear_pattern3d_a_pattern() {
|
||||
let code = r#"exampleSketch = startSketchOn('XZ')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line([0, 2], %)
|
||||
|> line([3, 1], %)
|
||||
|> line([0, -4], %)
|
||||
|> close(%)
|
||||
|> extrude(1, %)
|
||||
|
||||
pattn1 = patternLinear3d({
|
||||
axis: [1, 0, 0],
|
||||
instances: 7,
|
||||
distance: 6
|
||||
}, exampleSketch)
|
||||
|
||||
pattn2 = patternLinear3d({
|
||||
axis: [0, 0, 1],
|
||||
distance: 1,
|
||||
instances: 7
|
||||
}, pattn1)
|
||||
"#;
|
||||
|
||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||
assert_out("linear_pattern3d_a_pattern", &result);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn kcl_test_circular_pattern3d_a_pattern() {
|
||||
let code = r#"exampleSketch = startSketchOn('XZ')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line([0, 2], %)
|
||||
|> line([3, 1], %)
|
||||
|> line([0, -4], %)
|
||||
|> close(%)
|
||||
|> extrude(1, %)
|
||||
|
||||
pattn1 = patternLinear3d({
|
||||
axis: [1, 0, 0],
|
||||
instances: 7,
|
||||
distance: 6
|
||||
}, exampleSketch)
|
||||
|
||||
pattn2 = patternCircular3d({axis: [0,0, 1], center: [-20, -20, -20], instances: 41, arcDegrees: 360, rotateDuplicates: false}, pattn1)
|
||||
"#;
|
||||
|
||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||
assert_out("circular_pattern3d_a_pattern", &result);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn kcl_test_array_of_sketches() {
|
||||
let code = r#"plane001 = startSketchOn('XZ')
|
||||
@ -1496,69 +1418,6 @@ extrude(10, sketch001)
|
||||
assert_out("array_of_sketches", &result);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn kcl_test_sketch_on_face_after_fillets_referencing_face() {
|
||||
let code = r#"// Shelf Bracket
|
||||
// This is a shelf bracket made out of 6061-T6 aluminum sheet metal. The required thickness is calculated based on a point load of 300 lbs applied to the end of the shelf. There are two brackets holding up the shelf, so the moment experienced is divided by 2. The shelf is 1 foot long from the wall.
|
||||
|
||||
|
||||
// Define our bracket feet lengths
|
||||
shelfMountL = 8 // The length of the bracket holding up the shelf is 6 inches
|
||||
wallMountL = 6 // the length of the bracket
|
||||
|
||||
|
||||
// Define constants required to calculate the thickness needed to support 300 lbs
|
||||
sigmaAllow = 35000 // psi
|
||||
width = 6 // inch
|
||||
p = 300 // Force on shelf - lbs
|
||||
L = 12 // inches
|
||||
M = L * p / 2 // Moment experienced at fixed end of bracket
|
||||
FOS = 2 // Factor of safety of 2 to be conservative
|
||||
|
||||
|
||||
// Calculate the thickness off the bending stress and factor of safety
|
||||
thickness = sqrt(6 * M * FOS / (width * sigmaAllow))
|
||||
|
||||
// 0.25 inch fillet radius
|
||||
filletR = 0.25
|
||||
|
||||
// Sketch the bracket and extrude with fillets
|
||||
bracket = startSketchOn('XY')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line([0, wallMountL], %, $outerEdge)
|
||||
|> line([-shelfMountL, 0], %, $seg01)
|
||||
|> line([0, -thickness], %)
|
||||
|> line([shelfMountL - thickness, 0], %, $innerEdge)
|
||||
|> line([0, -wallMountL + thickness], %)
|
||||
|> close(%)
|
||||
|> extrude(width, %)
|
||||
|> fillet({
|
||||
radius: filletR,
|
||||
tags: [
|
||||
getNextAdjacentEdge(innerEdge)
|
||||
]
|
||||
}, %)
|
||||
|> fillet({
|
||||
radius: filletR + thickness,
|
||||
tags: [
|
||||
getNextAdjacentEdge(outerEdge)
|
||||
]
|
||||
}, %)
|
||||
|
||||
sketch001 = startSketchOn(bracket, seg01)
|
||||
|> startProfileAt([4.28, 3.83], %)
|
||||
|> line([2.17, -0.03], %)
|
||||
|> line([-0.07, -1.8], %)
|
||||
|> line([-2.07, 0.05], %)
|
||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> close(%)
|
||||
|> extrude(10, %)
|
||||
"#;
|
||||
|
||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||
assert_out("sketch_on_face_after_fillets_referencing_face", &result);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn kcl_test_circular_pattern3d_array_of_extrudes() {
|
||||
let code = r#"plane001 = startSketchOn('XZ')
|
||||
|
Before Width: | Height: | Size: 133 KiB After Width: | Height: | Size: 127 KiB |
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 33 KiB |
@ -19,6 +19,15 @@ macro_rules! kcl_test {
|
||||
}
|
||||
|
||||
kcl_test!("sketch_on_face", kcl_test_sketch_on_face);
|
||||
kcl_test!("neg_xz_plane", kcl_test_neg_xz_plane);
|
||||
kcl_test!("xz_plane", kcl_test_xz_plane);
|
||||
kcl_test!(
|
||||
"sketch_on_face_after_fillets_referencing_face",
|
||||
kcl_test_sketch_on_face_after_fillets_referencing_face
|
||||
);
|
||||
kcl_test!("circular_pattern3d_a_pattern", kcl_test_circular_pattern3d_a_pattern);
|
||||
kcl_test!("linear_pattern3d_a_pattern", kcl_test_linear_pattern3d_a_pattern);
|
||||
|
||||
kcl_test!("tangential_arc", kcl_test_tangential_arc);
|
||||
kcl_test!(
|
||||
"big_number_angle_to_match_length_x",
|
||||
|
@ -27,7 +27,7 @@ async fn setup(code: &str, name: &str) -> Result<(ExecutorContext, Program, uuid
|
||||
// Create the client.
|
||||
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
// Set a local engine address if it's set.
|
||||
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
|
||||
if let Ok(addr) = std::env::var("ZOO_HOST") {
|
||||
client.set_base_url(addr);
|
||||
}
|
||||
|
||||
|