Compare commits
10 Commits
v0.26.1
...
achalmers/
Author | SHA1 | Date | |
---|---|---|---|
976d5d2b4f | |||
4925251c29 | |||
9772869545 | |||
a7e830cd02 | |||
ca102116b6 | |||
c2fba89e77 | |||
7e31678ba2 | |||
1140ced121 | |||
32b7ddaa7c | |||
2525f99515 |
24348
docs/kcl/std.json
@ -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 |
|
||||||
|
|
||||||
|
|
||||||
|
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": "",
|
"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": {
|
||||||
|
@ -746,7 +746,6 @@ export class SceneEntities {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
...this.mouseEnterLeaveCallbacks(),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
setupDraftRectangle = async (
|
setupDraftRectangle = async (
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
8
src/wasm-lib/Cargo.lock
generated
@ -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",
|
||||||
|
@ -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"
|
||||||
|
@ -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"] }
|
||||||
|
@ -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:?}");
|
||||||
|
@ -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 {
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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)])
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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")]
|
#[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')
|
||||||
|
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!("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",
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|