Compare commits
4 Commits
kurt-add-s
...
v0.15.3
Author | SHA1 | Date | |
---|---|---|---|
47d40eb801 | |||
adc4b6148d | |||
27d0d4a28b | |||
fb609c19ef |
2
.gitignore
vendored
@ -54,3 +54,5 @@ e2e/playwright/export-snapshots/*embedded.gltf
|
|||||||
|
|
||||||
## generated files
|
## generated files
|
||||||
src/**/*.typegen.ts
|
src/**/*.typegen.ts
|
||||||
|
|
||||||
|
src/wasm-lib/grackle/stdlib_cube_partial.json
|
||||||
|
@ -8,10 +8,6 @@ once fixed in engine will just start working here with no language changes.
|
|||||||
model for that sketch and its underlying 3D object.
|
model for that sketch and its underlying 3D object.
|
||||||
If you see a red line around your model, it means this is happening.
|
If you see a red line around your model, it means this is happening.
|
||||||
|
|
||||||
- **Patterns**: If you try and pass a pattern to `hole` currently only the first
|
|
||||||
item in the pattern is being subtracted. This is an engine bug that is being
|
|
||||||
worked on.
|
|
||||||
|
|
||||||
- **Import**: Right now you can import a file, even if that file has brep data
|
- **Import**: Right now you can import a file, even if that file has brep data
|
||||||
you cannot edit it, after v1, the engine will account for this. You also cannot
|
you cannot edit it, after v1, the engine will account for this. You also cannot
|
||||||
currently move or transform the imported objects at all, once we have assemblies
|
currently move or transform the imported objects at all, once we have assemblies
|
||||||
|
@ -32506,14 +32506,14 @@
|
|||||||
"format": "double"
|
"format": "double"
|
||||||
},
|
},
|
||||||
"axis": {
|
"axis": {
|
||||||
"description": "The axis around which to make the pattern. This is a 3D vector.",
|
"description": "The axis around which to make the pattern. This is a 2D vector.",
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"format": "double"
|
"format": "double"
|
||||||
},
|
},
|
||||||
"maxItems": 3,
|
"maxItems": 2,
|
||||||
"minItems": 3
|
"minItems": 2
|
||||||
},
|
},
|
||||||
"center": {
|
"center": {
|
||||||
"description": "The center about which to make th pattern. This is a 3D vector.",
|
"description": "The center about which to make th pattern. This is a 3D vector.",
|
||||||
@ -35128,14 +35128,14 @@
|
|||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"axis": {
|
"axis": {
|
||||||
"description": "The axis of the pattern. This is a 3D vector.",
|
"description": "The axis of the pattern. This is a 2D vector.",
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"format": "double"
|
"format": "double"
|
||||||
},
|
},
|
||||||
"maxItems": 3,
|
"maxItems": 2,
|
||||||
"minItems": 3
|
"minItems": 2
|
||||||
},
|
},
|
||||||
"distance": {
|
"distance": {
|
||||||
"description": "The distance between each repetition. This can also be referred to as spacing.",
|
"description": "The distance between each repetition. This can also be referred to as spacing.",
|
||||||
|
@ -6086,8 +6086,8 @@ patternCircular(data: CircularPatternData, geometry: Geometry) -> Geometries
|
|||||||
{
|
{
|
||||||
// The arc angle (in degrees) to place the repetitions. Must be greater than 0.
|
// The arc angle (in degrees) to place the repetitions. Must be greater than 0.
|
||||||
arcDegrees: number,
|
arcDegrees: number,
|
||||||
// The axis around which to make the pattern. This is a 3D vector.
|
// The axis around which to make the pattern. This is a 2D vector.
|
||||||
axis: [number, number, number],
|
axis: [number, number],
|
||||||
// The center about which to make th pattern. This is a 3D vector.
|
// The center about which to make th pattern. This is a 3D vector.
|
||||||
center: [number, number, number],
|
center: [number, number, number],
|
||||||
// The number of repetitions. Must be greater than 0. This excludes the original entity. For example, if `repetitions` is 1, the original entity will be copied once.
|
// The number of repetitions. Must be greater than 0. This excludes the original entity. For example, if `repetitions` is 1, the original entity will be copied once.
|
||||||
@ -6355,8 +6355,8 @@ patternLinear(data: LinearPatternData, geometry: Geometry) -> Geometries
|
|||||||
* `data`: `LinearPatternData` - Data for a linear pattern.
|
* `data`: `LinearPatternData` - Data for a linear pattern.
|
||||||
```
|
```
|
||||||
{
|
{
|
||||||
// The axis of the pattern. This is a 3D vector.
|
// The axis of the pattern. This is a 2D vector.
|
||||||
axis: [number, number, number],
|
axis: [number, number],
|
||||||
// The distance between each repetition. This can also be referred to as spacing.
|
// The distance between each repetition. This can also be referred to as spacing.
|
||||||
distance: number,
|
distance: number,
|
||||||
// The number of repetitions. Must be greater than 0. This excludes the original entity. For example, if `repetitions` is 1, the original entity will be copied once.
|
// The number of repetitions. Must be greater than 0. This excludes the original entity. For example, if `repetitions` is 1, the original entity will be copied once.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "untitled-app",
|
"name": "untitled-app",
|
||||||
"version": "0.15.2",
|
"version": "0.15.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/autocomplete": "^6.10.2",
|
"@codemirror/autocomplete": "^6.10.2",
|
||||||
@ -10,7 +10,7 @@
|
|||||||
"@fortawesome/react-fontawesome": "^0.2.0",
|
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||||
"@headlessui/react": "^1.7.17",
|
"@headlessui/react": "^1.7.17",
|
||||||
"@headlessui/tailwindcss": "^0.2.0",
|
"@headlessui/tailwindcss": "^0.2.0",
|
||||||
"@kittycad/lib": "^0.0.53",
|
"@kittycad/lib": "^0.0.54",
|
||||||
"@lezer/javascript": "^1.4.9",
|
"@lezer/javascript": "^1.4.9",
|
||||||
"@open-rpc/client-js": "^1.8.1",
|
"@open-rpc/client-js": "^1.8.1",
|
||||||
"@react-hook/resize-observer": "^1.2.6",
|
"@react-hook/resize-observer": "^1.2.6",
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
},
|
},
|
||||||
"package": {
|
"package": {
|
||||||
"productName": "zoo-modeling-app",
|
"productName": "zoo-modeling-app",
|
||||||
"version": "0.15.2"
|
"version": "0.15.3"
|
||||||
},
|
},
|
||||||
"tauri": {
|
"tauri": {
|
||||||
"allowlist": {
|
"allowlist": {
|
||||||
|
@ -13,7 +13,6 @@ import {
|
|||||||
Quaternion,
|
Quaternion,
|
||||||
Scene,
|
Scene,
|
||||||
Shape,
|
Shape,
|
||||||
SphereGeometry,
|
|
||||||
Vector2,
|
Vector2,
|
||||||
Vector3,
|
Vector3,
|
||||||
} from 'three'
|
} from 'three'
|
||||||
@ -86,7 +85,6 @@ export const TANGENTIAL_ARC_TO_SEGMENT = 'tangential-arc-to-segment'
|
|||||||
export const TANGENTIAL_ARC_TO_SEGMENT_BODY = 'tangential-arc-to-segment-body'
|
export const TANGENTIAL_ARC_TO_SEGMENT_BODY = 'tangential-arc-to-segment-body'
|
||||||
export const TANGENTIAL_ARC_TO__SEGMENT_DASH =
|
export const TANGENTIAL_ARC_TO__SEGMENT_DASH =
|
||||||
'tangential-arc-to-segment-body-dashed'
|
'tangential-arc-to-segment-body-dashed'
|
||||||
export const EXTRA_SEGMENT_HANDLE = 'extraSegmentHandle'
|
|
||||||
|
|
||||||
// This singleton Class is responsible for all of the things the user sees and interacts with.
|
// This singleton Class is responsible for all of the things the user sees and interacts with.
|
||||||
// That mostly mean sketch elements.
|
// That mostly mean sketch elements.
|
||||||
@ -241,16 +239,12 @@ class SceneEntities {
|
|||||||
ast,
|
ast,
|
||||||
// is draft line assumes the last segment is a draft line, and mods it as the user moves the mouse
|
// is draft line assumes the last segment is a draft line, and mods it as the user moves the mouse
|
||||||
draftSegment,
|
draftSegment,
|
||||||
skipListeners,
|
|
||||||
}: {
|
}: {
|
||||||
sketchPathToNode: PathToNode
|
sketchPathToNode: PathToNode
|
||||||
ast?: Program
|
ast?: Program
|
||||||
draftSegment?: DraftSegment
|
draftSegment?: DraftSegment
|
||||||
skipListeners?: boolean
|
|
||||||
}) {
|
}) {
|
||||||
if (!skipListeners) {
|
sceneInfra.resetMouseListeners()
|
||||||
sceneInfra.resetMouseListeners()
|
|
||||||
}
|
|
||||||
this.createIntersectionPlane()
|
this.createIntersectionPlane()
|
||||||
|
|
||||||
const { truncatedAst, programMemoryOverride, variableDeclarationName } =
|
const { truncatedAst, programMemoryOverride, variableDeclarationName } =
|
||||||
@ -332,60 +326,11 @@ class SceneEntities {
|
|||||||
this.currentSketchQuaternion
|
this.currentSketchQuaternion
|
||||||
)
|
)
|
||||||
|
|
||||||
let addingNewSegmentStatus: 'nothing' | 'pending' | 'added' = 'nothing'
|
|
||||||
|
|
||||||
this.scene.add(group)
|
this.scene.add(group)
|
||||||
if (!draftSegment && !skipListeners) {
|
if (!draftSegment) {
|
||||||
sceneInfra.setCallbacks({
|
sceneInfra.setCallbacks({
|
||||||
onDragEnd: async () => {
|
onDrag: (args) => {
|
||||||
if (addingNewSegmentStatus !== 'nothing') {
|
|
||||||
await this.tearDownSketch({ removeAxis: false })
|
|
||||||
this.setupSketch({ sketchPathToNode })
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onDrag: async (args) => {
|
|
||||||
if (args.event.which !== 1) return
|
if (args.event.which !== 1) return
|
||||||
const group = getParentGroup(args.object, [EXTRA_SEGMENT_HANDLE])
|
|
||||||
if (group?.name === EXTRA_SEGMENT_HANDLE) {
|
|
||||||
const segGroup = getParentGroup(args.object)
|
|
||||||
const pathToNode: PathToNode = segGroup?.userData?.pathToNode
|
|
||||||
const pathToNodeIndex = pathToNode.findIndex(
|
|
||||||
(x) => x[1] === 'PipeExpression'
|
|
||||||
)
|
|
||||||
const pipeIndex = pathToNode[pathToNodeIndex + 1][0] as number
|
|
||||||
if (addingNewSegmentStatus === 'nothing') {
|
|
||||||
const prevSegment = sketchGroup.value[pipeIndex - 2]
|
|
||||||
const yo = addNewSketchLn({
|
|
||||||
node: kclManager.ast,
|
|
||||||
programMemory: kclManager.programMemory,
|
|
||||||
to: [args.intersection2d.x, args.intersection2d.y],
|
|
||||||
from: [prevSegment.from[0], prevSegment.from[1]],
|
|
||||||
fnName:
|
|
||||||
prevSegment.type === 'TangentialArcTo'
|
|
||||||
? 'tangentialArcTo'
|
|
||||||
: 'line',
|
|
||||||
pathToNode: pathToNode,
|
|
||||||
})
|
|
||||||
addingNewSegmentStatus = 'pending'
|
|
||||||
await kclManager.executeAstMock(yo.modifiedAst, {
|
|
||||||
updates: 'code',
|
|
||||||
})
|
|
||||||
await this.tearDownSketch({ removeAxis: false })
|
|
||||||
this.setupSketch({ sketchPathToNode, skipListeners: true })
|
|
||||||
addingNewSegmentStatus = 'added'
|
|
||||||
} else if (addingNewSegmentStatus === 'added') {
|
|
||||||
const pathToNodeForNewSegment = pathToNode.slice(
|
|
||||||
0,
|
|
||||||
pathToNodeIndex
|
|
||||||
)
|
|
||||||
pathToNodeForNewSegment.push([pipeIndex - 2, 'index'])
|
|
||||||
this.onDragSegment({
|
|
||||||
...args,
|
|
||||||
sketchPathToNode: pathToNodeForNewSegment,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.onDragSegment({
|
this.onDragSegment({
|
||||||
...args,
|
...args,
|
||||||
sketchPathToNode,
|
sketchPathToNode,
|
||||||
@ -446,7 +391,7 @@ class SceneEntities {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
} else if (draftSegment && !skipListeners) {
|
} else {
|
||||||
sceneInfra.setCallbacks({
|
sceneInfra.setCallbacks({
|
||||||
onDrag: () => {},
|
onDrag: () => {},
|
||||||
onClick: async (args) => {
|
onClick: async (args) => {
|
||||||
@ -555,7 +500,6 @@ class SceneEntities {
|
|||||||
variableDeclarationName: string
|
variableDeclarationName: string
|
||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
if (object.name === STRAIGHT_SEGMENT_BODY) return
|
|
||||||
const group = getParentGroup(object)
|
const group = getParentGroup(object)
|
||||||
if (!group) return
|
if (!group) return
|
||||||
const pathToNode: PathToNode = JSON.parse(
|
const pathToNode: PathToNode = JSON.parse(
|
||||||
@ -662,7 +606,9 @@ class SceneEntities {
|
|||||||
group.userData.from = from
|
group.userData.from = from
|
||||||
group.userData.to = to
|
group.userData.to = to
|
||||||
group.userData.prevSegment = prevSegment
|
group.userData.prevSegment = prevSegment
|
||||||
const arrowGroup = group.getObjectByName(ARROWHEAD) as Group
|
const arrowGroup = group.children.find(
|
||||||
|
(child) => child.userData.type === ARROWHEAD
|
||||||
|
) as Group
|
||||||
|
|
||||||
arrowGroup.position.set(to[0], to[1], 0)
|
arrowGroup.position.set(to[0], to[1], 0)
|
||||||
|
|
||||||
@ -737,7 +683,9 @@ class SceneEntities {
|
|||||||
const shape = new Shape()
|
const shape = new Shape()
|
||||||
shape.moveTo(0, -0.08 * scale)
|
shape.moveTo(0, -0.08 * scale)
|
||||||
shape.lineTo(0, 0.08 * scale) // The width of the line
|
shape.lineTo(0, 0.08 * scale) // The width of the line
|
||||||
const arrowGroup = group.getObjectByName(ARROWHEAD) as Group
|
const arrowGroup = group.children.find(
|
||||||
|
(child) => child.userData.type === ARROWHEAD
|
||||||
|
) as Group
|
||||||
|
|
||||||
arrowGroup.position.set(to[0], to[1], 0)
|
arrowGroup.position.set(to[0], to[1], 0)
|
||||||
|
|
||||||
@ -750,32 +698,6 @@ class SceneEntities {
|
|||||||
arrowGroup.quaternion.setFromUnitVectors(new Vector3(0, 1, 0), dir)
|
arrowGroup.quaternion.setFromUnitVectors(new Vector3(0, 1, 0), dir)
|
||||||
arrowGroup.scale.set(scale, scale, scale)
|
arrowGroup.scale.set(scale, scale, scale)
|
||||||
|
|
||||||
// TODO this should be created in setupSketch, not updateStraightSegment
|
|
||||||
// it should only be updated here
|
|
||||||
const extraSegmentHandle = (group.getObjectByName(EXTRA_SEGMENT_HANDLE) ||
|
|
||||||
(() => {
|
|
||||||
const mat = new MeshBasicMaterial({ color: 0xffffff })
|
|
||||||
const sphereMesh = new Mesh(new SphereGeometry(0.6, 12, 12), mat)
|
|
||||||
|
|
||||||
const handleGroup = new Group()
|
|
||||||
handleGroup.userData.type = EXTRA_SEGMENT_HANDLE
|
|
||||||
handleGroup.name = EXTRA_SEGMENT_HANDLE
|
|
||||||
handleGroup.add(sphereMesh)
|
|
||||||
handleGroup.layers.set(SKETCH_LAYER)
|
|
||||||
handleGroup.traverse((child) => {
|
|
||||||
child.layers.set(SKETCH_LAYER)
|
|
||||||
})
|
|
||||||
return handleGroup
|
|
||||||
})()) as Group
|
|
||||||
|
|
||||||
extraSegmentHandle.position.set(
|
|
||||||
from[0] + 0.08 * (to[0] - from[0]),
|
|
||||||
from[1] + 0.08 * (to[1] - from[1]),
|
|
||||||
0
|
|
||||||
)
|
|
||||||
extraSegmentHandle.scale.set(scale, scale, scale)
|
|
||||||
group.add(extraSegmentHandle)
|
|
||||||
|
|
||||||
const straightSegmentBody = group.children.find(
|
const straightSegmentBody = group.children.find(
|
||||||
(child) => child.userData.type === STRAIGHT_SEGMENT_BODY
|
(child) => child.userData.type === STRAIGHT_SEGMENT_BODY
|
||||||
) as Mesh
|
) as Mesh
|
||||||
|
@ -88,25 +88,18 @@ class SceneInfra {
|
|||||||
fov = 45
|
fov = 45
|
||||||
fovBeforeAnimate = 45
|
fovBeforeAnimate = 45
|
||||||
isFovAnimationInProgress = false
|
isFovAnimationInProgress = false
|
||||||
onDragStartCallback: (arg: OnDragCallbackArgs) => void = () => {}
|
|
||||||
onDragEndCallback: (arg: OnDragCallbackArgs) => void = () => {}
|
|
||||||
onDragCallback: (arg: OnDragCallbackArgs) => void = () => {}
|
onDragCallback: (arg: OnDragCallbackArgs) => void = () => {}
|
||||||
onMoveCallback: (arg: onMoveCallbackArgs) => void = () => {}
|
onMoveCallback: (arg: onMoveCallbackArgs) => void = () => {}
|
||||||
onClickCallback: (arg?: OnClickCallbackArgs) => void = () => {}
|
onClickCallback: (arg?: OnClickCallbackArgs) => void = () => {}
|
||||||
onMouseEnter: (arg: BaseCallbackArgs2) => void = () => {}
|
onMouseEnter: (arg: BaseCallbackArgs2) => void = () => {}
|
||||||
onMouseLeave: (arg: BaseCallbackArgs2) => void = () => {}
|
onMouseLeave: (arg: BaseCallbackArgs2) => void = () => {}
|
||||||
setCallbacks = (callbacks: {
|
setCallbacks = (callbacks: {
|
||||||
onDragStart?: (arg: OnDragCallbackArgs) => void
|
|
||||||
onDragEnd?: (arg: OnDragCallbackArgs) => void
|
|
||||||
onDrag?: (arg: OnDragCallbackArgs) => void
|
onDrag?: (arg: OnDragCallbackArgs) => void
|
||||||
onMove?: (arg: onMoveCallbackArgs) => void
|
onMove?: (arg: onMoveCallbackArgs) => void
|
||||||
onClick?: (arg?: OnClickCallbackArgs) => void
|
onClick?: (arg?: OnClickCallbackArgs) => void
|
||||||
onMouseEnter?: (arg: BaseCallbackArgs2) => void
|
onMouseEnter?: (arg: BaseCallbackArgs2) => void
|
||||||
onMouseLeave?: (arg: BaseCallbackArgs2) => void
|
onMouseLeave?: (arg: BaseCallbackArgs2) => void
|
||||||
}) => {
|
}) => {
|
||||||
console.trace('setting callbacks')
|
|
||||||
this.onDragStartCallback = callbacks.onDragStart || this.onDragStartCallback
|
|
||||||
this.onDragEndCallback = callbacks.onDragEnd || this.onDragEndCallback
|
|
||||||
this.onDragCallback = callbacks.onDrag || this.onDragCallback
|
this.onDragCallback = callbacks.onDrag || this.onDragCallback
|
||||||
this.onMoveCallback = callbacks.onMove || this.onMoveCallback
|
this.onMoveCallback = callbacks.onMove || this.onMoveCallback
|
||||||
this.onClickCallback = callbacks.onClick || this.onClickCallback
|
this.onClickCallback = callbacks.onClick || this.onClickCallback
|
||||||
@ -116,8 +109,6 @@ class SceneInfra {
|
|||||||
}
|
}
|
||||||
resetMouseListeners = () => {
|
resetMouseListeners = () => {
|
||||||
sceneInfra.setCallbacks({
|
sceneInfra.setCallbacks({
|
||||||
onDragStart: () => {},
|
|
||||||
onDragEnd: () => {},
|
|
||||||
onDrag: () => {},
|
onDrag: () => {},
|
||||||
onMove: () => {},
|
onMove: () => {},
|
||||||
onClick: () => {},
|
onClick: () => {},
|
||||||
@ -429,13 +420,8 @@ class SceneInfra {
|
|||||||
|
|
||||||
if (this.selected) {
|
if (this.selected) {
|
||||||
if (this.selected.hasBeenDragged) {
|
if (this.selected.hasBeenDragged) {
|
||||||
// TODO do the types properly here
|
// this is where we could fire a onDragEnd event
|
||||||
this.onDragEndCallback({
|
// console.log('onDragEnd', this.selected)
|
||||||
object: this.selected.object,
|
|
||||||
event,
|
|
||||||
intersection2d: planeIntersectPoint?.intersection2d,
|
|
||||||
...planeIntersectPoint,
|
|
||||||
} as any)
|
|
||||||
} else if (planeIntersectPoint) {
|
} else if (planeIntersectPoint) {
|
||||||
// fire onClick event as there was no drags
|
// fire onClick event as there was no drags
|
||||||
this.onClickCallback({
|
this.onClickCallback({
|
||||||
|
@ -81,7 +81,6 @@ export function straightSegment({
|
|||||||
pathToNode,
|
pathToNode,
|
||||||
isSelected: false,
|
isSelected: false,
|
||||||
}
|
}
|
||||||
group.name = STRAIGHT_SEGMENT
|
|
||||||
|
|
||||||
const arrowGroup = createArrowhead(scale)
|
const arrowGroup = createArrowhead(scale)
|
||||||
arrowGroup.position.set(to[0], to[1], 0)
|
arrowGroup.position.set(to[0], to[1], 0)
|
||||||
@ -170,7 +169,6 @@ export function tangentialArcToSegment({
|
|||||||
pathToNode,
|
pathToNode,
|
||||||
isSelected: false,
|
isSelected: false,
|
||||||
}
|
}
|
||||||
group.name = TANGENTIAL_ARC_TO_SEGMENT
|
|
||||||
|
|
||||||
const arrowGroup = createArrowhead(scale)
|
const arrowGroup = createArrowhead(scale)
|
||||||
arrowGroup.position.set(to[0], to[1], 0)
|
arrowGroup.position.set(to[0], to[1], 0)
|
||||||
|
@ -27,6 +27,8 @@ describe('UserSidebarMenu tests', () => {
|
|||||||
phone: '555-555-5555',
|
phone: '555-555-5555',
|
||||||
first_name: 'Test',
|
first_name: 'Test',
|
||||||
last_name: 'User',
|
last_name: 'User',
|
||||||
|
can_train_on_data: false,
|
||||||
|
is_service_account: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
render(
|
render(
|
||||||
@ -57,6 +59,8 @@ describe('UserSidebarMenu tests', () => {
|
|||||||
first_name: '',
|
first_name: '',
|
||||||
last_name: '',
|
last_name: '',
|
||||||
name: '',
|
name: '',
|
||||||
|
can_train_on_data: false,
|
||||||
|
is_service_account: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
render(
|
render(
|
||||||
@ -84,6 +88,8 @@ describe('UserSidebarMenu tests', () => {
|
|||||||
first_name: 'Test',
|
first_name: 'Test',
|
||||||
last_name: 'User',
|
last_name: 'User',
|
||||||
image: '',
|
image: '',
|
||||||
|
can_train_on_data: false,
|
||||||
|
is_service_account: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
render(
|
render(
|
||||||
|
@ -181,10 +181,6 @@ export const line: SketchLineHelper = {
|
|||||||
pathToNode,
|
pathToNode,
|
||||||
'PipeExpression'
|
'PipeExpression'
|
||||||
)
|
)
|
||||||
const { node: callExpression } = getNodeFromPath<
|
|
||||||
PipeExpression | CallExpression
|
|
||||||
>(_node, pathToNode, 'CallExpression')
|
|
||||||
|
|
||||||
const { node: varDec } = getNodeFromPath<VariableDeclarator>(
|
const { node: varDec } = getNodeFromPath<VariableDeclarator>(
|
||||||
_node,
|
_node,
|
||||||
pathToNode,
|
pathToNode,
|
||||||
@ -194,38 +190,6 @@ export const line: SketchLineHelper = {
|
|||||||
const newXVal = createLiteral(roundOff(to[0] - from[0], 2))
|
const newXVal = createLiteral(roundOff(to[0] - from[0], 2))
|
||||||
const newYVal = createLiteral(roundOff(to[1] - from[1], 2))
|
const newYVal = createLiteral(roundOff(to[1] - from[1], 2))
|
||||||
|
|
||||||
const isAddingSegmentBetween =
|
|
||||||
callExpression.type === 'CallExpression' &&
|
|
||||||
callExpression.start >= pipe.start &&
|
|
||||||
callExpression.end <= pipe.end
|
|
||||||
if (
|
|
||||||
isAddingSegmentBetween &&
|
|
||||||
!createCallback &&
|
|
||||||
pipe.type === 'PipeExpression'
|
|
||||||
) {
|
|
||||||
const callExp = createCallExpression('line', [
|
|
||||||
createArrayExpression([newXVal, newYVal]),
|
|
||||||
createPipeSubstitution(),
|
|
||||||
])
|
|
||||||
const pathToNodeIndex = pathToNode.findIndex(
|
|
||||||
(x) => x[1] === 'PipeExpression'
|
|
||||||
)
|
|
||||||
const pipeIndex = pathToNode[pathToNodeIndex + 1][0]
|
|
||||||
if (typeof pipeIndex === 'undefined' || typeof pipeIndex === 'string') {
|
|
||||||
console.warn('pipeIndex is undefined')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
pipe.body = [
|
|
||||||
...pipe.body.slice(0, pipeIndex),
|
|
||||||
callExp,
|
|
||||||
...pipe.body.slice(pipeIndex),
|
|
||||||
]
|
|
||||||
return {
|
|
||||||
modifiedAst: _node,
|
|
||||||
pathToNode,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (replaceExisting && createCallback && pipe.type !== 'CallExpression') {
|
if (replaceExisting && createCallback && pipe.type !== 'CallExpression') {
|
||||||
const { index: callIndex } = splitPathAtPipeExpression(pathToNode)
|
const { index: callIndex } = splitPathAtPipeExpression(pathToNode)
|
||||||
const { callExp, valueUsedInTransform } = createCallback(
|
const { callExp, valueUsedInTransform } = createCallback(
|
||||||
@ -1047,6 +1011,15 @@ export function changeSketchArguments(
|
|||||||
throw new Error(`not a sketch line helper: ${callExpression?.callee?.name}`)
|
throw new Error(`not a sketch line helper: ${callExpression?.callee?.name}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface CreateLineFnCallArgs {
|
||||||
|
node: Program
|
||||||
|
programMemory: ProgramMemory
|
||||||
|
to: [number, number]
|
||||||
|
from: [number, number]
|
||||||
|
fnName: ToolTip
|
||||||
|
pathToNode: PathToNode
|
||||||
|
}
|
||||||
|
|
||||||
export function compareVec2Epsilon(
|
export function compareVec2Epsilon(
|
||||||
vec1: [number, number],
|
vec1: [number, number],
|
||||||
vec2: [number, number],
|
vec2: [number, number],
|
||||||
@ -1071,15 +1044,6 @@ export function compareVec2Epsilon2(
|
|||||||
return distance < compareEpsilon
|
return distance < compareEpsilon
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CreateLineFnCallArgs {
|
|
||||||
node: Program
|
|
||||||
programMemory: ProgramMemory
|
|
||||||
to: [number, number]
|
|
||||||
from: [number, number]
|
|
||||||
fnName: ToolTip
|
|
||||||
pathToNode: PathToNode
|
|
||||||
}
|
|
||||||
|
|
||||||
export function addNewSketchLn({
|
export function addNewSketchLn({
|
||||||
node: _node,
|
node: _node,
|
||||||
programMemory: previousProgramMemory,
|
programMemory: previousProgramMemory,
|
||||||
|
@ -20,6 +20,8 @@ const LOCAL_USER: Models['User_type'] = {
|
|||||||
phone: '555-555-5555',
|
phone: '555-555-5555',
|
||||||
first_name: 'Test',
|
first_name: 'Test',
|
||||||
last_name: 'User',
|
last_name: 'User',
|
||||||
|
can_train_on_data: false,
|
||||||
|
is_service_account: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UserContext {
|
export interface UserContext {
|
||||||
|
47
src/wasm-lib/Cargo.lock
generated
@ -1460,13 +1460,17 @@ name = "grackle"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"kcl-lib",
|
"kcl-lib",
|
||||||
|
"kittycad",
|
||||||
"kittycad-execution-plan",
|
"kittycad-execution-plan",
|
||||||
|
"kittycad-execution-plan-macros",
|
||||||
"kittycad-execution-plan-traits",
|
"kittycad-execution-plan-traits",
|
||||||
|
"kittycad-modeling-cmds",
|
||||||
"kittycad-modeling-session",
|
"kittycad-modeling-session",
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1912,7 +1916,7 @@ dependencies = [
|
|||||||
"itertools 0.12.1",
|
"itertools 0.12.1",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"kittycad",
|
"kittycad",
|
||||||
"kittycad-execution-plan-macros 0.1.4 (git+https://github.com/KittyCAD/modeling-api?branch=main)",
|
"kittycad-execution-plan-macros",
|
||||||
"kittycad-execution-plan-traits",
|
"kittycad-execution-plan-traits",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"parse-display 0.9.0",
|
"parse-display 0.9.0",
|
||||||
@ -1986,7 +1990,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "kittycad-execution-plan"
|
name = "kittycad-execution-plan"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#08f05d91062380fe3a69f4baa1f1301532d31977"
|
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#9cb86ba54e4a60aa775fa2fd8af6f0ac9d05ebeb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"insta",
|
"insta",
|
||||||
@ -2004,19 +2008,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kittycad-execution-plan-macros"
|
name = "kittycad-execution-plan-macros"
|
||||||
version = "0.1.4"
|
version = "0.1.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#9cb86ba54e4a60aa775fa2fd8af6f0ac9d05ebeb"
|
||||||
checksum = "71d31b689c944d00aadda2ef83d8422a6efff97e1be5654a61f9d95496f0c19e"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 2.0.49",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "kittycad-execution-plan-macros"
|
|
||||||
version = "0.1.4"
|
|
||||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#632b75a0242400fa34373d7973b9149b0e08aa3f"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -2025,9 +2018,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kittycad-execution-plan-traits"
|
name = "kittycad-execution-plan-traits"
|
||||||
version = "0.1.10"
|
version = "0.1.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#9cb86ba54e4a60aa775fa2fd8af6f0ac9d05ebeb"
|
||||||
checksum = "a3ec8efd57b59697eb140b63c0ffe7db44fdfe5a55f14e45513411eba2280ba5"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
@ -2036,8 +2028,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kittycad-modeling-cmds"
|
name = "kittycad-modeling-cmds"
|
||||||
version = "0.1.18"
|
version = "0.1.25"
|
||||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#08f05d91062380fe3a69f4baa1f1301532d31977"
|
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#9cb86ba54e4a60aa775fa2fd8af6f0ac9d05ebeb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"chrono",
|
"chrono",
|
||||||
@ -2047,8 +2039,9 @@ dependencies = [
|
|||||||
"enum-iterator-derive",
|
"enum-iterator-derive",
|
||||||
"euler",
|
"euler",
|
||||||
"http 0.2.9",
|
"http 0.2.9",
|
||||||
"kittycad-execution-plan-macros 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"kittycad-execution-plan-macros",
|
||||||
"kittycad-execution-plan-traits",
|
"kittycad-execution-plan-traits",
|
||||||
|
"kittycad-modeling-cmds-macros",
|
||||||
"kittycad-unit-conversion-derive",
|
"kittycad-unit-conversion-derive",
|
||||||
"measurements",
|
"measurements",
|
||||||
"parse-display 0.8.2",
|
"parse-display 0.8.2",
|
||||||
@ -2061,10 +2054,20 @@ dependencies = [
|
|||||||
"webrtc",
|
"webrtc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "kittycad-modeling-cmds-macros"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#9cb86ba54e4a60aa775fa2fd8af6f0ac9d05ebeb"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.49",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kittycad-modeling-session"
|
name = "kittycad-modeling-session"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#08f05d91062380fe3a69f4baa1f1301532d31977"
|
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#9cb86ba54e4a60aa775fa2fd8af6f0ac9d05ebeb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures",
|
"futures",
|
||||||
"kittycad",
|
"kittycad",
|
||||||
|
@ -60,9 +60,10 @@ members = [
|
|||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
kittycad = { version = "0.2.54", default-features = false, features = ["js", "requests"] }
|
kittycad = { version = "0.2.54", default-features = false, features = ["js", "requests"] }
|
||||||
kittycad-execution-plan = { git = "https://github.com/KittyCAD/modeling-api", branch = "main" }
|
kittycad-execution-plan = { git = "https://github.com/KittyCAD/modeling-api", branch = "main" }
|
||||||
kittycad-execution-plan-traits = "0.1.10"
|
|
||||||
kittycad-modeling-session = { git = "https://github.com/KittyCAD/modeling-api", branch = "main" }
|
|
||||||
kittycad-execution-plan-macros = { git = "https://github.com/KittyCAD/modeling-api", branch = "main" }
|
kittycad-execution-plan-macros = { git = "https://github.com/KittyCAD/modeling-api", branch = "main" }
|
||||||
|
kittycad-execution-plan-traits = { git = "https://github.com/KittyCAD/modeling-api", branch = "main" }
|
||||||
|
kittycad-modeling-cmds = { git = "https://github.com/KittyCAD/modeling-api", branch = "main" }
|
||||||
|
kittycad-modeling-session = { git = "https://github.com/KittyCAD/modeling-api", branch = "main" }
|
||||||
|
|
||||||
[[test]]
|
[[test]]
|
||||||
name = "executor"
|
name = "executor"
|
||||||
@ -73,6 +74,9 @@ name = "modify"
|
|||||||
path = "tests/modify/main.rs"
|
path = "tests/modify/main.rs"
|
||||||
|
|
||||||
# Example: how to point modeling-api at a different repo (e.g. a branch or a local clone)
|
# Example: how to point modeling-api at a different repo (e.g. a branch or a local clone)
|
||||||
# [patch."https://github.com/KittyCAD/modeling-api"]
|
#[patch."https://github.com/KittyCAD/modeling-api"]
|
||||||
# kittycad-execution-plan = { path = "../../../modeling-api/execution-plan" }
|
#kittycad-execution-plan = { path = "../../../modeling-api/execution-plan" }
|
||||||
# kittycad-modeling-session = { path = "../../../modeling-api/modeling-session" }
|
#kittycad-execution-plan-macros = { path = "../../../modeling-api/execution-plan-macros" }
|
||||||
|
#kittycad-execution-plan-traits = { path = "../../../modeling-api/execution-plan-traits" }
|
||||||
|
#kittycad-modeling-cmds = { path = "../../../modeling-api/modeling-cmds" }
|
||||||
|
#kittycad-modeling-session = { path = "../../../modeling-api/modeling-session" }
|
||||||
|
@ -7,11 +7,15 @@ description = "A new executor for KCL which compiles to Execution Plans"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
kcl-lib = { path = "../kcl" }
|
kcl-lib = { path = "../kcl" }
|
||||||
|
kittycad = { workspace = true }
|
||||||
kittycad-execution-plan = { workspace = true }
|
kittycad-execution-plan = { workspace = true }
|
||||||
kittycad-execution-plan-traits = { workspace = true }
|
kittycad-execution-plan-traits = { workspace = true }
|
||||||
|
kittycad-execution-plan-macros = { workspace = true }
|
||||||
|
kittycad-modeling-cmds = { workspace = true }
|
||||||
kittycad-modeling-session = { workspace = true }
|
kittycad-modeling-session = { workspace = true }
|
||||||
thiserror = "1.0.57"
|
thiserror = "1.0.57"
|
||||||
tokio = { version = "1.36.0", features = ["macros", "rt"] }
|
tokio = { version = "1.36.0", features = ["macros", "rt"] }
|
||||||
|
uuid = "1.7"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
pretty_assertions = "1"
|
pretty_assertions = "1"
|
||||||
|
@ -103,7 +103,7 @@ impl BindingScope {
|
|||||||
("add".into(), EpBinding::from(KclFunction::Add(native_functions::Add))),
|
("add".into(), EpBinding::from(KclFunction::Add(native_functions::Add))),
|
||||||
(
|
(
|
||||||
"startSketchAt".into(),
|
"startSketchAt".into(),
|
||||||
EpBinding::from(KclFunction::StartSketchAt(native_functions::StartSketchAt)),
|
EpBinding::from(KclFunction::StartSketchAt(native_functions::sketch::StartSketchAt)),
|
||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
parent: None,
|
parent: None,
|
||||||
|
@ -45,6 +45,12 @@ pub enum CompileError {
|
|||||||
NoReturnStmt,
|
NoReturnStmt,
|
||||||
#[error("You used the %, which means \"substitute this argument for the value to the left in this |> pipeline\". But there is no such value, because you're not calling a pipeline.")]
|
#[error("You used the %, which means \"substitute this argument for the value to the left in this |> pipeline\". But there is no such value, because you're not calling a pipeline.")]
|
||||||
NotInPipeline,
|
NotInPipeline,
|
||||||
|
#[error("The function '{fn_name}' expects a parameter of type {expected} but you supplied {actual}")]
|
||||||
|
ArgWrongType {
|
||||||
|
fn_name: &'static str,
|
||||||
|
expected: &'static str,
|
||||||
|
actual: String,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
@ -618,7 +618,7 @@ impl Eq for UserDefinedFunction {}
|
|||||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||||
enum KclFunction {
|
enum KclFunction {
|
||||||
Id(native_functions::Id),
|
Id(native_functions::Id),
|
||||||
StartSketchAt(native_functions::StartSketchAt),
|
StartSketchAt(native_functions::sketch::StartSketchAt),
|
||||||
Add(native_functions::Add),
|
Add(native_functions::Add),
|
||||||
UserDefined(UserDefinedFunction),
|
UserDefined(UserDefinedFunction),
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,13 @@
|
|||||||
//! This includes some of the stdlib, e.g. `startSketchAt`.
|
//! This includes some of the stdlib, e.g. `startSketchAt`.
|
||||||
//! But some other stdlib functions will be written in KCL.
|
//! But some other stdlib functions will be written in KCL.
|
||||||
|
|
||||||
use kcl_lib::std::sketch::PlaneData;
|
|
||||||
use kittycad_execution_plan::{BinaryArithmetic, Destination, Instruction};
|
use kittycad_execution_plan::{BinaryArithmetic, Destination, Instruction};
|
||||||
use kittycad_execution_plan_traits::{Address, Value};
|
use kittycad_execution_plan_traits::Address;
|
||||||
|
|
||||||
use crate::{CompileError, EpBinding, EvalPlan};
|
use crate::{CompileError, EpBinding, EvalPlan};
|
||||||
|
|
||||||
|
pub mod sketch;
|
||||||
|
|
||||||
/// The identity function. Always returns its first input.
|
/// The identity function. Always returns its first input.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||||
@ -41,34 +42,6 @@ impl Callable for Id {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
|
||||||
pub struct StartSketchAt;
|
|
||||||
|
|
||||||
impl Callable for StartSketchAt {
|
|
||||||
fn call(&self, next_addr: &mut Address, _args: Vec<EpBinding>) -> Result<EvalPlan, CompileError> {
|
|
||||||
let mut instructions = Vec::new();
|
|
||||||
// Store the plane.
|
|
||||||
let plane = PlaneData::XY.into_parts();
|
|
||||||
instructions.push(Instruction::SetValue {
|
|
||||||
address: next_addr.offset_by(plane.len()),
|
|
||||||
value_parts: plane,
|
|
||||||
});
|
|
||||||
// TODO: Get the plane ID from global context.
|
|
||||||
// TODO: Send this command:
|
|
||||||
// ModelingCmd::SketchModeEnable {
|
|
||||||
// animated: false,
|
|
||||||
// ortho: false,
|
|
||||||
// plane_id: plane.id,
|
|
||||||
// // We pass in the normal for the plane here.
|
|
||||||
// disable_camera_with_plane: Some(plane.z_axis.clone().into()),
|
|
||||||
// },
|
|
||||||
// TODO: Send ModelingCmd::StartPath at the given point.
|
|
||||||
// TODO (maybe): Store the SketchGroup in KCEP memory.
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A test function that adds two numbers.
|
/// A test function that adds two numbers.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||||
|
7
src/wasm-lib/grackle/src/native_functions/sketch.rs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
//! Native functions for sketching on the plane.
|
||||||
|
|
||||||
|
pub mod helpers;
|
||||||
|
pub mod stdlib_functions;
|
||||||
|
pub mod types;
|
||||||
|
|
||||||
|
pub use stdlib_functions::StartSketchAt;
|
82
src/wasm-lib/grackle/src/native_functions/sketch/helpers.rs
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
use kittycad_execution_plan::{api_request::ApiRequest, Instruction};
|
||||||
|
use kittycad_execution_plan_traits::{Address, InMemory};
|
||||||
|
use kittycad_modeling_cmds::{id::ModelingCmdId, ModelingCmdEndpoint};
|
||||||
|
|
||||||
|
use crate::{binding_scope::EpBinding, error::CompileError};
|
||||||
|
|
||||||
|
/// Emit instructions for an API call with no parameters.
|
||||||
|
pub fn no_arg_api_call(instrs: &mut Vec<Instruction>, endpoint: ModelingCmdEndpoint, cmd_id: ModelingCmdId) {
|
||||||
|
instrs.push(Instruction::ApiRequest(ApiRequest {
|
||||||
|
endpoint,
|
||||||
|
store_response: None,
|
||||||
|
arguments: vec![],
|
||||||
|
cmd_id,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Emit instructions for an API call with the given parameters.
|
||||||
|
/// The API parameters are stored in the EP memory stack.
|
||||||
|
/// So, they have to be pushed onto the stack in the right order,
|
||||||
|
/// i.e. the reverse order in which the API call's Rust struct defines the fields.
|
||||||
|
pub fn stack_api_call<const N: usize>(
|
||||||
|
instrs: &mut Vec<Instruction>,
|
||||||
|
endpoint: ModelingCmdEndpoint,
|
||||||
|
store_response: Option<Address>,
|
||||||
|
cmd_id: ModelingCmdId,
|
||||||
|
data: [Vec<kittycad_execution_plan_traits::Primitive>; N],
|
||||||
|
) {
|
||||||
|
let arguments = vec![InMemory::StackPop; data.len()];
|
||||||
|
instrs.extend(data.map(|data| Instruction::StackPush { data }));
|
||||||
|
instrs.push(Instruction::ApiRequest(ApiRequest {
|
||||||
|
endpoint,
|
||||||
|
store_response,
|
||||||
|
arguments,
|
||||||
|
cmd_id,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn single_binding(b: EpBinding, fn_name: &'static str, expected: &'static str) -> Result<Address, CompileError> {
|
||||||
|
match b {
|
||||||
|
EpBinding::Single(a) => Ok(a),
|
||||||
|
EpBinding::Sequence { .. } => Err(CompileError::ArgWrongType {
|
||||||
|
fn_name,
|
||||||
|
expected,
|
||||||
|
actual: "array".to_owned(),
|
||||||
|
}),
|
||||||
|
EpBinding::Map { .. } => Err(CompileError::ArgWrongType {
|
||||||
|
fn_name,
|
||||||
|
expected,
|
||||||
|
actual: "object".to_owned(),
|
||||||
|
}),
|
||||||
|
EpBinding::Function(_) => Err(CompileError::ArgWrongType {
|
||||||
|
fn_name,
|
||||||
|
expected,
|
||||||
|
actual: "function".to_owned(),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sequence_binding(
|
||||||
|
b: EpBinding,
|
||||||
|
fn_name: &'static str,
|
||||||
|
expected: &'static str,
|
||||||
|
) -> Result<Vec<EpBinding>, CompileError> {
|
||||||
|
match b {
|
||||||
|
EpBinding::Sequence { elements, .. } => Ok(elements),
|
||||||
|
EpBinding::Single(_) => Err(CompileError::ArgWrongType {
|
||||||
|
fn_name,
|
||||||
|
expected,
|
||||||
|
actual: "single".to_owned(),
|
||||||
|
}),
|
||||||
|
EpBinding::Map { .. } => Err(CompileError::ArgWrongType {
|
||||||
|
fn_name,
|
||||||
|
expected,
|
||||||
|
actual: "object".to_owned(),
|
||||||
|
}),
|
||||||
|
EpBinding::Function(_) => Err(CompileError::ArgWrongType {
|
||||||
|
fn_name,
|
||||||
|
expected,
|
||||||
|
actual: "function".to_owned(),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,167 @@
|
|||||||
|
use kittycad_execution_plan::{api_request::ApiRequest, Instruction};
|
||||||
|
use kittycad_execution_plan_traits::{Address, InMemory, Value};
|
||||||
|
use kittycad_modeling_cmds::{
|
||||||
|
shared::{Point3d, Point4d},
|
||||||
|
ModelingCmdEndpoint,
|
||||||
|
};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
use crate::{binding_scope::EpBinding, error::CompileError, native_functions::Callable, EvalPlan};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
helpers::{no_arg_api_call, sequence_binding, single_binding, stack_api_call},
|
||||||
|
types::{Axes, BasePath, Plane, SketchGroup},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||||
|
pub struct StartSketchAt;
|
||||||
|
|
||||||
|
impl Callable for StartSketchAt {
|
||||||
|
fn call(&self, next_addr: &mut Address, args: Vec<EpBinding>) -> Result<EvalPlan, CompileError> {
|
||||||
|
let mut instructions = Vec::new();
|
||||||
|
// First, before we send any API calls, let's validate the arguments to this function.
|
||||||
|
let mut args_iter = args.into_iter();
|
||||||
|
let Some(start) = args_iter.next() else {
|
||||||
|
return Err(CompileError::NotEnoughArgs {
|
||||||
|
fn_name: "startSketchAt".into(),
|
||||||
|
required: 1,
|
||||||
|
actual: 0,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
let start_point = {
|
||||||
|
let expected = "2D point (array with length 2)";
|
||||||
|
let fn_name = "startSketchAt";
|
||||||
|
let elements = sequence_binding(start, "startSketchAt", "an array of length 2")?;
|
||||||
|
if elements.len() != 2 {
|
||||||
|
return Err(CompileError::ArgWrongType {
|
||||||
|
fn_name,
|
||||||
|
expected,
|
||||||
|
actual: format!("array of length {}", elements.len()),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// KCL stores points as an array.
|
||||||
|
// KC API stores them as Rust objects laid flat out in memory.
|
||||||
|
let start = next_addr.offset_by(2);
|
||||||
|
let start_x = start;
|
||||||
|
let start_y = start + 1;
|
||||||
|
let start_z = start + 2;
|
||||||
|
instructions.extend([
|
||||||
|
Instruction::Copy {
|
||||||
|
source: single_binding(elements[0].clone(), "startSketchAt (first parameter, elem 0)", "number")?,
|
||||||
|
destination: start_x,
|
||||||
|
},
|
||||||
|
Instruction::Copy {
|
||||||
|
source: single_binding(elements[1].clone(), "startSketchAt (first parameter, elem 1)", "number")?,
|
||||||
|
destination: start_y,
|
||||||
|
},
|
||||||
|
Instruction::SetPrimitive {
|
||||||
|
address: start_z,
|
||||||
|
value: 0.0.into(),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
start
|
||||||
|
};
|
||||||
|
let tag = match args_iter.next() {
|
||||||
|
None => None,
|
||||||
|
Some(b) => Some(single_binding(b, "startSketchAt", "a single string")?),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Define some constants:
|
||||||
|
let axes = Axes {
|
||||||
|
x: Point3d { x: 1.0, y: 0.0, z: 0.0 },
|
||||||
|
y: Point3d { x: 0.0, y: 1.0, z: 0.0 },
|
||||||
|
z: Point3d { x: 0.0, y: 0.0, z: 1.0 },
|
||||||
|
};
|
||||||
|
let origin = Point3d::default();
|
||||||
|
|
||||||
|
// Now the function can start.
|
||||||
|
// First API call: make the plane.
|
||||||
|
let plane_id = Uuid::new_v4();
|
||||||
|
stack_api_call(
|
||||||
|
&mut instructions,
|
||||||
|
ModelingCmdEndpoint::MakePlane,
|
||||||
|
None,
|
||||||
|
plane_id.into(),
|
||||||
|
[
|
||||||
|
Some(true).into_parts(), // hide
|
||||||
|
vec![false.into()], // clobber
|
||||||
|
vec![60.0.into()], // size
|
||||||
|
axes.y.into_parts(),
|
||||||
|
axes.x.into_parts(),
|
||||||
|
origin.into_parts(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Next, enter sketch mode.
|
||||||
|
stack_api_call(
|
||||||
|
&mut instructions,
|
||||||
|
ModelingCmdEndpoint::SketchModeEnable,
|
||||||
|
None,
|
||||||
|
Uuid::new_v4().into(),
|
||||||
|
[
|
||||||
|
Some(axes.z).into_parts(),
|
||||||
|
vec![false.into()], // animated
|
||||||
|
vec![false.into()], // ortho mode
|
||||||
|
vec![plane_id.into()],
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Then start a path
|
||||||
|
let path_id = Uuid::new_v4();
|
||||||
|
no_arg_api_call(&mut instructions, ModelingCmdEndpoint::StartPath, path_id.into());
|
||||||
|
|
||||||
|
// Move the path pen to the given point.
|
||||||
|
instructions.push(Instruction::StackPush {
|
||||||
|
data: vec![path_id.into()],
|
||||||
|
});
|
||||||
|
instructions.push(Instruction::ApiRequest(ApiRequest {
|
||||||
|
endpoint: ModelingCmdEndpoint::MovePathPen,
|
||||||
|
store_response: None,
|
||||||
|
arguments: vec![InMemory::StackPop, InMemory::Address(start_point)],
|
||||||
|
cmd_id: Uuid::new_v4().into(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Starting a sketch creates a sketch group.
|
||||||
|
// Updating the sketch will update this sketch group later.
|
||||||
|
let sketch_group = SketchGroup {
|
||||||
|
id: path_id,
|
||||||
|
position: origin,
|
||||||
|
rotation: Point4d {
|
||||||
|
x: 0.0,
|
||||||
|
y: 0.0,
|
||||||
|
z: 0.0,
|
||||||
|
w: 1.0,
|
||||||
|
},
|
||||||
|
// TODO: Must copy the existing data (from the arguments to this KCL function)
|
||||||
|
// over these values after writing to memory.
|
||||||
|
path_first: BasePath {
|
||||||
|
from: Default::default(),
|
||||||
|
to: Default::default(),
|
||||||
|
name: Default::default(),
|
||||||
|
},
|
||||||
|
path_rest: Vec::new(),
|
||||||
|
on: super::types::SketchSurface::Plane(Plane {
|
||||||
|
id: plane_id,
|
||||||
|
value: super::types::PlaneType::XY,
|
||||||
|
origin,
|
||||||
|
axes,
|
||||||
|
}),
|
||||||
|
axes,
|
||||||
|
entity_id: Some(plane_id),
|
||||||
|
};
|
||||||
|
let sketch_group_primitives = sketch_group.clone().into_parts();
|
||||||
|
|
||||||
|
let sketch_group_addr = next_addr.offset_by(sketch_group_primitives.len());
|
||||||
|
instructions.push(Instruction::SetValue {
|
||||||
|
address: sketch_group_addr,
|
||||||
|
value_parts: sketch_group_primitives,
|
||||||
|
});
|
||||||
|
instructions.extend(sketch_group.set_base_path(sketch_group_addr, start_point, tag));
|
||||||
|
|
||||||
|
Ok(EvalPlan {
|
||||||
|
instructions,
|
||||||
|
binding: EpBinding::Single(sketch_group_addr),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
133
src/wasm-lib/grackle/src/native_functions/sketch/types.rs
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
use kittycad_execution_plan::Instruction;
|
||||||
|
use kittycad_execution_plan_macros::ExecutionPlanValue;
|
||||||
|
use kittycad_execution_plan_traits::{Address, Value};
|
||||||
|
use kittycad_modeling_cmds::shared::{Point2d, Point3d, Point4d};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
/// A sketch group is a collection of paths.
|
||||||
|
#[derive(Clone, ExecutionPlanValue)]
|
||||||
|
pub struct SketchGroup {
|
||||||
|
/// The id of the sketch group.
|
||||||
|
pub id: Uuid,
|
||||||
|
/// What the sketch is on (can be a plane or a face).
|
||||||
|
pub on: SketchSurface,
|
||||||
|
/// The position of the sketch group.
|
||||||
|
pub position: Point3d,
|
||||||
|
/// The rotation of the sketch group base plane.
|
||||||
|
pub rotation: Point4d,
|
||||||
|
/// The X, Y and Z axes of this sketch's base plane, in 3D space.
|
||||||
|
pub axes: Axes,
|
||||||
|
/// The plane id or face id of the sketch group.
|
||||||
|
pub entity_id: Option<Uuid>,
|
||||||
|
/// The base path.
|
||||||
|
pub path_first: BasePath,
|
||||||
|
/// Paths after the first path, if any.
|
||||||
|
pub path_rest: Vec<Path>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SketchGroup {
|
||||||
|
pub fn set_base_path(&self, sketch_group: Address, start_point: Address, tag: Option<Address>) -> Vec<Instruction> {
|
||||||
|
let base_path_addr = sketch_group
|
||||||
|
+ self.id.into_parts().len()
|
||||||
|
+ self.on.into_parts().len()
|
||||||
|
+ self.position.into_parts().len()
|
||||||
|
+ self.rotation.into_parts().len()
|
||||||
|
+ self.axes.into_parts().len()
|
||||||
|
+ self.entity_id.into_parts().len()
|
||||||
|
+ self.entity_id.into_parts().len();
|
||||||
|
let mut out = vec![
|
||||||
|
// Copy over the `from` field.
|
||||||
|
Instruction::Copy {
|
||||||
|
source: start_point,
|
||||||
|
destination: base_path_addr,
|
||||||
|
},
|
||||||
|
// Copy over the `to` field.
|
||||||
|
Instruction::Copy {
|
||||||
|
source: start_point,
|
||||||
|
destination: base_path_addr + self.path_first.from.into_parts().len(),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
if let Some(tag) = tag {
|
||||||
|
// Copy over the `name` field.
|
||||||
|
out.push(Instruction::Copy {
|
||||||
|
source: tag,
|
||||||
|
destination: base_path_addr
|
||||||
|
+ self.path_first.from.into_parts().len()
|
||||||
|
+ self.path_first.to.into_parts().len(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
out
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The X, Y and Z axes.
|
||||||
|
#[derive(Clone, Copy, ExecutionPlanValue)]
|
||||||
|
pub struct Axes {
|
||||||
|
pub x: Point3d,
|
||||||
|
pub y: Point3d,
|
||||||
|
pub z: Point3d,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, ExecutionPlanValue)]
|
||||||
|
pub struct BasePath {
|
||||||
|
pub from: Point2d<f64>,
|
||||||
|
pub to: Point2d<f64>,
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A path.
|
||||||
|
#[derive(Clone, ExecutionPlanValue)]
|
||||||
|
pub enum Path {
|
||||||
|
/// A path that goes to a point.
|
||||||
|
ToPoint { base: BasePath },
|
||||||
|
/// A arc that is tangential to the last path segment that goes to a point
|
||||||
|
TangentialArcTo {
|
||||||
|
base: BasePath,
|
||||||
|
/// the arc's center
|
||||||
|
center: Point2d,
|
||||||
|
/// arc's direction
|
||||||
|
ccw: bool,
|
||||||
|
},
|
||||||
|
/// A path that is horizontal.
|
||||||
|
Horizontal {
|
||||||
|
base: BasePath,
|
||||||
|
/// The x coordinate.
|
||||||
|
x: f64,
|
||||||
|
},
|
||||||
|
/// An angled line to.
|
||||||
|
AngledLineTo {
|
||||||
|
base: BasePath,
|
||||||
|
/// The x coordinate.
|
||||||
|
x: Option<f64>,
|
||||||
|
/// The y coordinate.
|
||||||
|
y: Option<f64>,
|
||||||
|
},
|
||||||
|
/// A base path.
|
||||||
|
Base { base: BasePath },
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, ExecutionPlanValue)]
|
||||||
|
pub enum SketchSurface {
|
||||||
|
Plane(Plane),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A plane.
|
||||||
|
#[derive(Clone, Copy, ExecutionPlanValue)]
|
||||||
|
pub struct Plane {
|
||||||
|
/// The id of the plane.
|
||||||
|
pub id: Uuid,
|
||||||
|
// The code for the plane either a string or custom.
|
||||||
|
pub value: PlaneType,
|
||||||
|
/// Origin of the plane.
|
||||||
|
pub origin: Point3d,
|
||||||
|
pub axes: Axes,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Type for a plane.
|
||||||
|
#[derive(Clone, Copy, ExecutionPlanValue)]
|
||||||
|
pub enum PlaneType {
|
||||||
|
XY,
|
||||||
|
XZ,
|
||||||
|
YZ,
|
||||||
|
Custom,
|
||||||
|
}
|
@ -1,7 +1,9 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::env;
|
||||||
|
|
||||||
use ep::{Destination, UnaryArithmetic};
|
use ep::{Destination, UnaryArithmetic};
|
||||||
use ept::{ListHeader, ObjectHeader};
|
use ept::{ListHeader, ObjectHeader};
|
||||||
|
use kittycad_modeling_session::SessionBuilder;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -1044,6 +1046,71 @@ fn store_object_with_array_property() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn stdlib_cube_partial() {
|
||||||
|
let program = r#"
|
||||||
|
let cube = startSketchAt([22.0, 33.0])
|
||||||
|
"#;
|
||||||
|
let (plan, _scope) = must_plan(program);
|
||||||
|
std::fs::write("stdlib_cube_partial.json", serde_json::to_string_pretty(&plan).unwrap()).unwrap();
|
||||||
|
let ast = kcl_lib::parser::Parser::new(kcl_lib::token::lexer(program))
|
||||||
|
.ast()
|
||||||
|
.unwrap();
|
||||||
|
let mem = crate::execute(ast, Some(test_client().await)).await.unwrap();
|
||||||
|
dbg!(mem);
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn test_client() -> Session {
|
||||||
|
let kittycad_api_token = env::var("KITTYCAD_API_TOKEN").expect("You must set $KITTYCAD_API_TOKEN");
|
||||||
|
let kittycad_api_client = kittycad::Client::new(kittycad_api_token);
|
||||||
|
let session_builder = SessionBuilder {
|
||||||
|
client: kittycad_api_client,
|
||||||
|
fps: Some(10),
|
||||||
|
unlocked_framerate: Some(false),
|
||||||
|
video_res_height: Some(720),
|
||||||
|
video_res_width: Some(1280),
|
||||||
|
buffer_reqs: None,
|
||||||
|
await_response_timeout: None,
|
||||||
|
};
|
||||||
|
match Session::start(session_builder).await {
|
||||||
|
Err(e) => match e {
|
||||||
|
kittycad::types::error::Error::InvalidRequest(s) => panic!("Request did not meet requirements {s}"),
|
||||||
|
kittycad::types::error::Error::CommunicationError(e) => {
|
||||||
|
panic!(" A server error either due to the data, or with the connection: {e}")
|
||||||
|
}
|
||||||
|
kittycad::types::error::Error::RequestError(e) => panic!("Could not build request: {e}"),
|
||||||
|
kittycad::types::error::Error::SerdeError { error, status } => {
|
||||||
|
panic!("Serde error (HTTP {status}): {error}")
|
||||||
|
}
|
||||||
|
kittycad::types::error::Error::InvalidResponsePayload { error, response } => {
|
||||||
|
panic!("Invalid response payload. Error {error}, response {response:?}")
|
||||||
|
}
|
||||||
|
kittycad::types::error::Error::Server { body, status } => panic!("Server error (HTTP {status}): {body}"),
|
||||||
|
kittycad::types::error::Error::UnexpectedResponse(resp) => {
|
||||||
|
let status = resp.status();
|
||||||
|
let url = resp.url().to_owned();
|
||||||
|
match resp.text().await {
|
||||||
|
Ok(body) => panic!(
|
||||||
|
"Unexpected response from KittyCAD API.
|
||||||
|
URL:{url}
|
||||||
|
HTTP {status}
|
||||||
|
---Body----
|
||||||
|
{body}"
|
||||||
|
),
|
||||||
|
Err(e) => panic!(
|
||||||
|
"Unexpected response from KittyCAD API.
|
||||||
|
URL:{url}
|
||||||
|
HTTP {status}
|
||||||
|
---Body could not be read, the error is----
|
||||||
|
{e}"
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Ok(x) => x,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[ignore = "haven't done API calls or stdlib yet"]
|
#[ignore = "haven't done API calls or stdlib yet"]
|
||||||
#[test]
|
#[test]
|
||||||
fn stdlib_api_calls() {
|
fn stdlib_api_calls() {
|
||||||
|
@ -23,8 +23,8 @@ pub struct LinearPatternData {
|
|||||||
pub repetitions: usize,
|
pub repetitions: usize,
|
||||||
/// The distance between each repetition. This can also be referred to as spacing.
|
/// The distance between each repetition. This can also be referred to as spacing.
|
||||||
pub distance: f64,
|
pub distance: f64,
|
||||||
/// The axis of the pattern. This is a 3D vector.
|
/// The axis of the pattern. This is a 2D vector.
|
||||||
pub axis: [f64; 3],
|
pub axis: [f64; 2],
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Data for a circular pattern.
|
/// Data for a circular pattern.
|
||||||
@ -36,8 +36,8 @@ pub struct CircularPatternData {
|
|||||||
/// This excludes the original entity. For example, if `repetitions` is 1,
|
/// This excludes the original entity. For example, if `repetitions` is 1,
|
||||||
/// the original entity will be copied once.
|
/// the original entity will be copied once.
|
||||||
pub repetitions: usize,
|
pub repetitions: usize,
|
||||||
/// The axis around which to make the pattern. This is a 3D vector.
|
/// The axis around which to make the pattern. This is a 2D vector.
|
||||||
pub axis: [f64; 3],
|
pub axis: [f64; 2],
|
||||||
/// The center about which to make th pattern. This is a 3D vector.
|
/// The center about which to make th pattern. This is a 3D vector.
|
||||||
pub center: [f64; 3],
|
pub center: [f64; 3],
|
||||||
/// The arc angle (in degrees) to place the repetitions. Must be greater than 0.
|
/// The arc angle (in degrees) to place the repetitions. Must be greater than 0.
|
||||||
@ -50,7 +50,7 @@ pub struct CircularPatternData {
|
|||||||
pub async fn pattern_linear(args: Args) -> Result<MemoryItem, KclError> {
|
pub async fn pattern_linear(args: Args) -> Result<MemoryItem, KclError> {
|
||||||
let (data, geometry): (LinearPatternData, Geometry) = args.get_data_and_geometry()?;
|
let (data, geometry): (LinearPatternData, Geometry) = args.get_data_and_geometry()?;
|
||||||
|
|
||||||
if data.axis == [0.0, 0.0, 0.0] {
|
if data.axis == [0.0, 0.0] {
|
||||||
return Err(KclError::Semantic(KclErrorDetails {
|
return Err(KclError::Semantic(KclErrorDetails {
|
||||||
message:
|
message:
|
||||||
"The axis of the linear pattern cannot be the zero vector. Otherwise they will just duplicate in place."
|
"The axis of the linear pattern cannot be the zero vector. Otherwise they will just duplicate in place."
|
||||||
@ -70,7 +70,7 @@ pub async fn pattern_linear(args: Args) -> Result<MemoryItem, KclError> {
|
|||||||
pub async fn pattern_circular(args: Args) -> Result<MemoryItem, KclError> {
|
pub async fn pattern_circular(args: Args) -> Result<MemoryItem, KclError> {
|
||||||
let (data, geometry): (CircularPatternData, Geometry) = args.get_data_and_geometry()?;
|
let (data, geometry): (CircularPatternData, Geometry) = args.get_data_and_geometry()?;
|
||||||
|
|
||||||
if data.axis == [0.0, 0.0, 0.0] {
|
if data.axis == [0.0, 0.0] {
|
||||||
return Err(KclError::Semantic(KclErrorDetails {
|
return Err(KclError::Semantic(KclErrorDetails {
|
||||||
message:
|
message:
|
||||||
"The axis of the circular pattern cannot be the zero vector. Otherwise they will just duplicate in place."
|
"The axis of the circular pattern cannot be the zero vector. Otherwise they will just duplicate in place."
|
||||||
@ -97,7 +97,11 @@ async fn inner_pattern_linear(data: LinearPatternData, geometry: Geometry, args:
|
|||||||
.send_modeling_cmd(
|
.send_modeling_cmd(
|
||||||
id,
|
id,
|
||||||
ModelingCmd::EntityLinearPattern {
|
ModelingCmd::EntityLinearPattern {
|
||||||
axis: data.axis.into(),
|
axis: kittycad::types::Point3D {
|
||||||
|
x: data.axis[0],
|
||||||
|
y: data.axis[1],
|
||||||
|
z: 0.0,
|
||||||
|
},
|
||||||
entity_id: geometry.id(),
|
entity_id: geometry.id(),
|
||||||
num_repetitions: data.repetitions as u32,
|
num_repetitions: data.repetitions as u32,
|
||||||
spacing: data.distance,
|
spacing: data.distance,
|
||||||
@ -154,7 +158,11 @@ async fn inner_pattern_circular(
|
|||||||
.send_modeling_cmd(
|
.send_modeling_cmd(
|
||||||
id,
|
id,
|
||||||
ModelingCmd::EntityCircularPattern {
|
ModelingCmd::EntityCircularPattern {
|
||||||
axis: data.axis.into(),
|
axis: kittycad::types::Point3D {
|
||||||
|
x: data.axis[0],
|
||||||
|
y: data.axis[1],
|
||||||
|
z: 0.0,
|
||||||
|
},
|
||||||
entity_id: geometry.id(),
|
entity_id: geometry.id(),
|
||||||
center: data.center.into(),
|
center: data.center.into(),
|
||||||
num_repetitions: data.repetitions as u32,
|
num_repetitions: data.repetitions as u32,
|
||||||
|
@ -735,7 +735,7 @@ async fn serial_test_patterns_linear_basic() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const part = circle([0,0], 2)
|
const part = circle([0,0], 2)
|
||||||
|> patternLinear({axis: [0,0,1], repetitions: 12, distance: 2}, %)
|
|> patternLinear({axis: [0,1], repetitions: 12, distance: 2}, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, kittycad::types::UnitLength::Mm)
|
let result = execute_and_snapshot(code, kittycad::types::UnitLength::Mm)
|
||||||
@ -765,7 +765,7 @@ const part = startSketchOn('XY')
|
|||||||
|> line([0, -1], %)
|
|> line([0, -1], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
|> extrude(1, %)
|
|> extrude(1, %)
|
||||||
|> patternLinear({axis: [1, 0,1], repetitions: 3, distance: 6}, %)
|
|> patternLinear({axis: [1, 0], repetitions: 3, distance: 6}, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, kittycad::types::UnitLength::Mm)
|
let result = execute_and_snapshot(code, kittycad::types::UnitLength::Mm)
|
||||||
@ -789,7 +789,7 @@ async fn serial_test_patterns_linear_basic_negative_distance() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const part = circle([0,0], 2)
|
const part = circle([0,0], 2)
|
||||||
|> patternLinear({axis: [0,0,1], repetitions: 12, distance: -2}, %)
|
|> patternLinear({axis: [0,1], repetitions: 12, distance: -2}, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, kittycad::types::UnitLength::Mm)
|
let result = execute_and_snapshot(code, kittycad::types::UnitLength::Mm)
|
||||||
@ -817,7 +817,7 @@ async fn serial_test_patterns_linear_basic_negative_axis() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const part = circle([0,0], 2)
|
const part = circle([0,0], 2)
|
||||||
|> patternLinear({axis: [0,0,-1], repetitions: 12, distance: 2}, %)
|
|> patternLinear({axis: [0,-1], repetitions: 12, distance: 2}, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, kittycad::types::UnitLength::Mm)
|
let result = execute_and_snapshot(code, kittycad::types::UnitLength::Mm)
|
||||||
@ -845,7 +845,7 @@ async fn serial_test_patterns_linear_basic_holes() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const circles = circle([5, 5], 1)
|
const circles = circle([5, 5], 1)
|
||||||
|> patternLinear({axis: [1,1,0], repetitions: 12, distance: 3}, %)
|
|> patternLinear({axis: [1,1], repetitions: 12, distance: 3}, %)
|
||||||
|
|
||||||
const rectangle = startSketchOn('XY')
|
const rectangle = startSketchOn('XY')
|
||||||
|> startProfileAt([0, 0], %)
|
|> startProfileAt([0, 0], %)
|
||||||
@ -878,7 +878,7 @@ async fn serial_test_patterns_circular_basic_2d() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const part = circle([0,0], 2)
|
const part = circle([0,0], 2)
|
||||||
|> patternCircular({axis: [0,0,1], center: [20, 20, 20], repetitions: 12, arcDegrees: 210, rotateDuplicates: true}, %)
|
|> patternCircular({axis: [0,1], center: [20, 20, 20], repetitions: 12, arcDegrees: 210, rotateDuplicates: true}, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, kittycad::types::UnitLength::Mm)
|
let result = execute_and_snapshot(code, kittycad::types::UnitLength::Mm)
|
||||||
@ -908,7 +908,7 @@ const part = startSketchOn('XY')
|
|||||||
|> line([0, -1], %)
|
|> line([0, -1], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
|> extrude(1, %)
|
|> extrude(1, %)
|
||||||
|> patternCircular({axis: [0,1,0], center: [-20, -20, -20], repetitions: 40, arcDegrees: 360, rotateDuplicates: false}, %)
|
|> patternCircular({axis: [0,1], center: [-20, -20, -20], repetitions: 40, arcDegrees: 360, rotateDuplicates: false}, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, kittycad::types::UnitLength::Mm)
|
let result = execute_and_snapshot(code, kittycad::types::UnitLength::Mm)
|
||||||
@ -938,7 +938,7 @@ const part = startSketchOn('XY')
|
|||||||
|> line([0, -1], %)
|
|> line([0, -1], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
|> extrude(1, %)
|
|> extrude(1, %)
|
||||||
|> patternCircular({axis: [1,1,-1], center: [10, 0, 10], repetitions: 10, arcDegrees: 360, rotateDuplicates: true}, %)
|
|> patternCircular({axis: [1,1], center: [10, 0, 10], repetitions: 10, arcDegrees: 360, rotateDuplicates: true}, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = execute_and_snapshot(code, kittycad::types::UnitLength::Mm)
|
let result = execute_and_snapshot(code, kittycad::types::UnitLength::Mm)
|
||||||
|
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 98 KiB |
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 98 KiB |
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 95 KiB |
Before Width: | Height: | Size: 93 KiB After Width: | Height: | Size: 93 KiB |
Before Width: | Height: | Size: 115 KiB After Width: | Height: | Size: 116 KiB |
Before Width: | Height: | Size: 97 KiB After Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 97 KiB After Width: | Height: | Size: 96 KiB |
@ -1801,10 +1801,10 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@juggle/resize-observer/-/resize-observer-3.4.0.tgz#08d6c5e20cf7e4cc02fd181c4b0c225cd31dbb60"
|
resolved "https://registry.yarnpkg.com/@juggle/resize-observer/-/resize-observer-3.4.0.tgz#08d6c5e20cf7e4cc02fd181c4b0c225cd31dbb60"
|
||||||
integrity sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==
|
integrity sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==
|
||||||
|
|
||||||
"@kittycad/lib@^0.0.53":
|
"@kittycad/lib@^0.0.54":
|
||||||
version "0.0.53"
|
version "0.0.54"
|
||||||
resolved "https://registry.yarnpkg.com/@kittycad/lib/-/lib-0.0.53.tgz#32f10f63428c5f3bb6a435507dbfa72c1e7ba10d"
|
resolved "https://registry.yarnpkg.com/@kittycad/lib/-/lib-0.0.54.tgz#6744977a2048152a425809d690e986054213ceab"
|
||||||
integrity sha512-a0WTVVGKE+J7I1bERn8pcr8cC5/X14dFi78Y7wAsu8ok/SuHVTPoPHVCZ8bUmcWzY1iWpLC/HCIIHigXjkF3ZA==
|
integrity sha512-4fsQLo0+TDn65p4uAUa46/TpWvN55MCu5Yd5hriyF7Xt9PCrdvDsgBisn79Y5dPkh6lq5TMy16T+a1yKcdh/kg==
|
||||||
dependencies:
|
dependencies:
|
||||||
node-fetch "3.3.2"
|
node-fetch "3.3.2"
|
||||||
openapi-types "^12.0.0"
|
openapi-types "^12.0.0"
|
||||||
|