Compare commits

...

10 Commits

Author SHA1 Message Date
976d5d2b4f Use ZOO_HOST not LOCAL_ENGINE_ADDR 2024-10-25 17:48:16 -05:00
4925251c29 Make application aware it saved the buffer and not something else (#4314)
Make application aware it saved the buffer and something else
2024-10-25 18:07:50 -04:00
9772869545 Add a radius length indicator to the circle sketch tool (#4304)
* Add a radius length indicator to the circle sketch tool

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)"

This reverts commit 15b078f641.

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: 49fl <ircsurfer33@gmail.com>
2024-10-25 17:42:27 -04:00
a7e830cd02 Update machine-api spec (#4305)
YOYO NEW API SPEC!

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-10-25 20:53:08 +00:00
ca102116b6 Bump kittycad-modeling-cmds from 0.2.70 to 0.2.71 in /src/wasm-lib (#4302)
Bumps [kittycad-modeling-cmds](https://github.com/KittyCAD/modeling-api) from 0.2.70 to 0.2.71.
- [Commits](https://github.com/KittyCAD/modeling-api/compare/kittycad-modeling-cmds-0.2.70...kittycad-modeling-cmds-0.2.71)

---
updated-dependencies:
- dependency-name: kittycad-modeling-cmds
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Adam Chalmers <adam.chalmers@zoo.dev>
2024-10-25 20:52:22 +00:00
c2fba89e77 Bump regex from 1.11.0 to 1.11.1 in /src/wasm-lib (#4301)
Bumps [regex](https://github.com/rust-lang/regex) from 1.11.0 to 1.11.1.
- [Release notes](https://github.com/rust-lang/regex/releases)
- [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/regex/compare/1.11.0...1.11.1)

---
updated-dependencies:
- dependency-name: regex
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-25 13:50:21 -07:00
7e31678ba2 Chore: Don't let draft lines receive mouseEnter/Leave events, or create invalid overlays (#4306) 2024-10-25 15:34:53 -04:00
1140ced121 Tags should refer to full paths, not just base paths. (#4299)
See "Problem 2" in https://github.com/KittyCAD/modeling-app/issues/4297

This is a pure refactor, it should not change any behaviour at all.
It adds more information into the tag system, but nothing reads that
extra information yet. It will be used to address problem 3 of the above
issue.
2024-10-25 10:27:40 -04:00
32b7ddaa7c Update circular pattern snapshots (#4303)
Engine changed (Serena fixed a bug with circular patterns), so snapshots need to be updated.
2024-10-25 08:28:46 -04:00
2525f99515 Move more KCL tests into files (#4260) 2024-10-25 01:52:43 +00:00
32 changed files with 18470 additions and 11371 deletions

File diff suppressed because it is too large Load Diff

View File

@ -18,7 +18,7 @@ Engine information for a tag.
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `id` |`string`| The id of the tagged object. | No | | `id` |`string`| The id of the tagged object. | No |
| `sketch` |`string`| The sketch the tag is on. | 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 | | `surface` |[`ExtrudeSurface`](/docs/kcl/types/ExtrudeSurface)| The surface information for the tag. | No |

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 44 KiB

View File

@ -996,7 +996,7 @@
}, },
"description": "", "description": "",
"title": "machine-api", "title": "machine-api",
"version": "0.1.0" "version": "0.1.1"
}, },
"openapi": "3.0.3", "openapi": "3.0.3",
"paths": { "paths": {

View File

@ -746,7 +746,6 @@ export class SceneEntities {
}, },
}) })
}, },
...this.mouseEnterLeaveCallbacks(),
}) })
} }
setupDraftRectangle = async ( setupDraftRectangle = async (

View File

@ -213,7 +213,7 @@ export class SceneInfra {
to: Coords2d to: Coords2d
angle?: number angle?: number
}): SegmentOverlayPayload | null { }): SegmentOverlayPayload | null {
if (group.userData.pathToNode && arrowGroup) { if (!group.userData.draft && group.userData.pathToNode && arrowGroup) {
const vector = new Vector3(0, 0, 0) const vector = new Vector3(0, 0, 0)
// Get the position of the object3D in world space // Get the position of the object3D in world space

View File

@ -147,6 +147,7 @@ class StraightSegment implements SegmentUtils {
segmentGroup.name = STRAIGHT_SEGMENT segmentGroup.name = STRAIGHT_SEGMENT
segmentGroup.userData = { segmentGroup.userData = {
type: STRAIGHT_SEGMENT, type: STRAIGHT_SEGMENT,
draft: isDraftSegment,
id, id,
from, from,
to, to,
@ -347,6 +348,7 @@ class TangentialArcToSegment implements SegmentUtils {
mesh.name = meshName mesh.name = meshName
group.userData = { group.userData = {
type: TANGENTIAL_ARC_TO_SEGMENT, type: TANGENTIAL_ARC_TO_SEGMENT,
draft: isDraftSegment,
id, id,
from, from,
to, to,
@ -515,11 +517,18 @@ class CircleSegment implements SegmentUtils {
const meshType = isDraftSegment ? CIRCLE_SEGMENT_DASH : CIRCLE_SEGMENT_BODY const meshType = isDraftSegment ? CIRCLE_SEGMENT_DASH : CIRCLE_SEGMENT_BODY
const arrowGroup = createArrowhead(scale, theme, color) const arrowGroup = createArrowhead(scale, theme, color)
const circleCenterGroup = createCircleCenterHandle(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.userData.type = meshType
arcMesh.name = meshType arcMesh.name = meshType
group.userData = { group.userData = {
type: CIRCLE_SEGMENT, type: CIRCLE_SEGMENT,
draft: isDraftSegment,
id, id,
from, from,
radius, radius,
@ -532,7 +541,7 @@ class CircleSegment implements SegmentUtils {
} }
group.name = CIRCLE_SEGMENT group.name = CIRCLE_SEGMENT
group.add(arcMesh, arrowGroup, circleCenterGroup) group.add(arcMesh, arrowGroup, circleCenterGroup, radiusIndicatorGroup)
const updateOverlaysCallback = this.update({ const updateOverlaysCallback = this.update({
prevSegment, prevSegment,
input, input,
@ -564,6 +573,9 @@ class CircleSegment implements SegmentUtils {
group.userData.radius = radius group.userData.radius = radius
group.userData.prevSegment = prevSegment group.userData.prevSegment = prevSegment
const arrowGroup = group.getObjectByName(ARROWHEAD) as Group const arrowGroup = group.getObjectByName(ARROWHEAD) as Group
const radiusLengthIndicator = group.getObjectByName(
SEGMENT_LENGTH_LABEL
) as Group
const circleCenterHandle = group.getObjectByName( const circleCenterHandle = group.getObjectByName(
CIRCLE_CENTER_HANDLE CIRCLE_CENTER_HANDLE
) as Group ) as Group
@ -581,11 +593,14 @@ class CircleSegment implements SegmentUtils {
} }
if (arrowGroup) { if (arrowGroup) {
arrowGroup.position.set( // The arrowhead is placed at the perimeter of the circle,
center[0] + Math.cos(Math.PI / 4) * radius, // pointing up and to the right
center[1] + Math.sin(Math.PI / 4) * radius, const arrowPoint = {
0 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 const arrowheadAngle = Math.PI / 4
arrowGroup.quaternion.setFromUnitVectors( arrowGroup.quaternion.setFromUnitVectors(
@ -596,6 +611,31 @@ class CircleSegment implements SegmentUtils {
arrowGroup.visible = isHandlesVisible 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) { if (circleCenterHandle) {
circleCenterHandle.position.set(center[0], center[1], 0) circleCenterHandle.position.set(center[0], center[1], 0)
circleCenterHandle.scale.set(scale, scale, scale) circleCenterHandle.scale.set(scale, scale, scale)

View File

@ -140,6 +140,13 @@ const FileTreeItem = ({
async (eventType, path) => { async (eventType, path) => {
// Don't try to read a file that was removed. // Don't try to read a file that was removed.
if (isCurrentFile && eventType !== 'unlink') { 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' }) let code = await window.electron.readFile(path, { encoding: 'utf-8' })
code = normalizeLineEndings(code) code = normalizeLineEndings(code)
codeManager.updateCodeStateEditor(code) codeManager.updateCodeStateEditor(code)

View File

@ -20,6 +20,8 @@ export default class CodeManager {
private _hotkeys: { [key: string]: () => void } = {} private _hotkeys: { [key: string]: () => void } = {}
private timeoutWriter: ReturnType<typeof setTimeout> | undefined = undefined private timeoutWriter: ReturnType<typeof setTimeout> | undefined = undefined
public writeCausedByAppCheckedInFileTreeFileSystemWatcher = false
constructor() { constructor() {
if (isDesktop()) { if (isDesktop()) {
this.code = '' this.code = ''
@ -120,6 +122,7 @@ export default class CodeManager {
// and file-system watchers which read, will receive empty data during // and file-system watchers which read, will receive empty data during
// writes. // writes.
clearTimeout(this.timeoutWriter) clearTimeout(this.timeoutWriter)
this.writeCausedByAppCheckedInFileTreeFileSystemWatcher = true
this.timeoutWriter = setTimeout(() => { this.timeoutWriter = setTimeout(() => {
// Wait one event loop to give a chance for params to be set // Wait one event loop to give a chance for params to be set
// Save the file to disk // Save the file to disk

View File

@ -1684,9 +1684,9 @@ dependencies = [
[[package]] [[package]]
name = "kittycad-modeling-cmds" name = "kittycad-modeling-cmds"
version = "0.2.70" version = "0.2.71"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b135696d07a4fab928e5abace4dd05f4976eafab5d73e5747a85dc5a684b936c" checksum = "c6d2160dcb0e5373b1242a760dbf17fb9c12de523c410c11b145381c852b377b"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"chrono", "chrono",
@ -2586,9 +2586,9 @@ dependencies = [
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.11.0" version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",

View File

@ -72,7 +72,7 @@ members = [
[workspace.dependencies] [workspace.dependencies]
http = "1" http = "1"
kittycad = { version = "0.3.23", default-features = false, features = ["js", "requests"] } 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]] [[test]]
name = "executor" name = "executor"

View File

@ -17,7 +17,7 @@ convert_case = "0.6.0"
once_cell = "1.20.2" once_cell = "1.20.2"
proc-macro2 = "1" proc-macro2 = "1"
quote = "1" quote = "1"
regex = "1.10" regex = "1.11"
serde = { version = "1.0.213", features = ["derive"] } serde = { version = "1.0.213", features = ["derive"] }
serde_tokenstream = "0.2" serde_tokenstream = "0.2"
syn = { version = "2.0.85", features = ["full"] } syn = { version = "2.0.85", features = ["full"] }

View File

@ -31,7 +31,7 @@ pub struct ServerArgs {
/// Where to find the engine. /// Where to find the engine.
/// If none, uses the prod engine. /// If none, uses the prod engine.
/// This is useful for testing a local engine instance. /// 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>, 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), num_engine_conns: pargs.opt_value_from_str("--num-engine-conns")?.unwrap_or(1),
engine_address: pargs.opt_value_from_str("--engine-address")?, engine_address: pargs.opt_value_from_str("--engine-address")?,
}; };
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") { if let Ok(addr) = std::env::var("ZOO_HOST") {
println!("Overriding engine address via $LOCAL_ENGINE_ADDR"); println!("Overriding engine address via $ZOO_HOST");
args.engine_address = Some(addr); args.engine_address = Some(addr);
} }
println!("Config is {args:?}"); println!("Config is {args:?}");

View File

@ -1127,7 +1127,7 @@ pub struct TagEngineInfo {
/// The sketch the tag is on. /// The sketch the tag is on.
pub sketch: uuid::Uuid, pub sketch: uuid::Uuid,
/// The path the tag is on. /// The path the tag is on.
pub path: Option<BasePath>, pub path: Option<Path>,
/// The surface information for the tag. /// The surface information for the tag.
pub surface: Option<ExtrudeSurface>, pub surface: Option<ExtrudeSurface>,
} }
@ -1206,7 +1206,7 @@ impl Sketch {
tag_identifier.info = Some(TagEngineInfo { tag_identifier.info = Some(TagEngineInfo {
id: base.geo_meta.id, id: base.geo_meta.id,
sketch: self.id, sketch: self.id,
path: Some(base.clone()), path: Some(current_path.clone()),
surface: None, 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 { impl Path {
pub fn get_id(&self) -> uuid::Uuid { pub fn get_id(&self) -> uuid::Uuid {
match self { 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> { pub fn get_base_mut(&mut self) -> Option<&mut BasePath> {
match self { match self {
Path::ToPoint { base } => Some(base), Path::ToPoint { base } => Some(base),
@ -1962,7 +2003,7 @@ impl ExecutorContext {
// Create the client. // Create the client.
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client); let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
// Set a local engine address if it's set. // 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); client.set_base_url(addr);
} }
if let Some(addr) = engine_addr { if let Some(addr) = engine_addr {

View File

@ -24,7 +24,7 @@ fn new_zoo_client() -> kittycad::Client {
// Create the client. // Create the client.
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client); let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
// Set a local engine address if it's set. // 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); client.set_base_url(addr);
} }

View File

@ -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. /// 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. /// 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) 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()) 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 let last_line = sketch
.paths .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 let last_line = sketch
.paths .paths

View File

@ -813,7 +813,7 @@ async fn inner_angled_line_that_intersects(
let from = sketch.current_pen_position()?; let from = sketch.current_pen_position()?;
let to = intersection_with_parallel_line( 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.offset.unwrap_or_default(),
data.angle, data.angle,
from, from,
@ -1244,7 +1244,9 @@ pub(crate) async fn inner_start_profile_at(
tag_identifier.info = Some(TagEngineInfo { tag_identifier.info = Some(TagEngineInfo {
id: current_path.geo_meta.id, id: current_path.geo_meta.id,
sketch: path_id, sketch: path_id,
path: Some(current_path.clone()), path: Some(Path::Base {
base: current_path.clone(),
}),
surface: None, surface: None,
}); });
HashMap::from([(tag.name.to_string(), tag_identifier)]) HashMap::from([(tag.name.to_string(), tag_identifier)])

View File

@ -67,7 +67,7 @@ async fn new_context(units: UnitLength, with_auth: bool) -> anyhow::Result<Execu
// Create the client. // Create the client.
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client); let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
// Set a local engine address if it's set. // 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 { if with_auth {
client.set_base_url(addr); client.set_base_url(addr);
} }

View File

@ -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)

View File

@ -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)

View File

@ -0,0 +1,6 @@
part001 = startSketchOn('-XZ')
|> startProfileAt([0, 0], %)
|> lineTo([100, 100], %)
|> lineTo([100, 0], %)
|> close(%)
|> extrude(5 + 7, %)

View File

@ -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, %)

View File

@ -0,0 +1,6 @@
part001 = startSketchOn('XZ')
|> startProfileAt([0, 0], %)
|> lineTo([100, 100], %)
|> lineTo([100, 0], %)
|> close(%)
|> extrude(5 + 7, %)

View File

@ -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")] #[tokio::test(flavor = "multi_thread")]
async fn kcl_test_array_of_sketches() { async fn kcl_test_array_of_sketches() {
let code = r#"plane001 = startSketchOn('XZ') let code = r#"plane001 = startSketchOn('XZ')
@ -1496,69 +1418,6 @@ extrude(10, sketch001)
assert_out("array_of_sketches", &result); 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")] #[tokio::test(flavor = "multi_thread")]
async fn kcl_test_circular_pattern3d_array_of_extrudes() { async fn kcl_test_circular_pattern3d_array_of_extrudes() {
let code = r#"plane001 = startSketchOn('XZ') let code = r#"plane001 = startSketchOn('XZ')

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 33 KiB

View File

@ -19,6 +19,15 @@ macro_rules! kcl_test {
} }
kcl_test!("sketch_on_face", kcl_test_sketch_on_face); 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!("tangential_arc", kcl_test_tangential_arc);
kcl_test!( kcl_test!(
"big_number_angle_to_match_length_x", "big_number_angle_to_match_length_x",

View File

@ -27,7 +27,7 @@ async fn setup(code: &str, name: &str) -> Result<(ExecutorContext, Program, uuid
// Create the client. // Create the client.
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client); let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
// Set a local engine address if it's set. // 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); client.set_base_url(addr);
} }