Nadro/adhoc/center rectangle (#4480)
* fix: big commit, doing this to save work then do a PR cleanup; center rectangle * fix: making a center function for each scenario * fix: reverting the update rectangle code since I have a center rectangle one * fix: does not allow seletcing circle or rectangle tool while selecting a face * chore: adding comment to better read the HTML * fix: cleaning up for PR * fix: pushing broken code for someone to checkout * fix: fixed the typescript issues, removed the as keyword for my center rectangle expressions * fix: removing comment * fix: removed as for type narrowing checks
This commit is contained in:
@ -141,6 +141,7 @@ export function Toolbar({
|
|||||||
>
|
>
|
||||||
{/* A menu item will either be a vertical line break, a button with a dropdown, or a single button */}
|
{/* A menu item will either be a vertical line break, a button with a dropdown, or a single button */}
|
||||||
{currentModeItems.map((maybeIconConfig, i) => {
|
{currentModeItems.map((maybeIconConfig, i) => {
|
||||||
|
// Vertical Line Break
|
||||||
if (maybeIconConfig === 'break') {
|
if (maybeIconConfig === 'break') {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@ -149,6 +150,7 @@ export function Toolbar({
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
} else if (Array.isArray(maybeIconConfig)) {
|
} else if (Array.isArray(maybeIconConfig)) {
|
||||||
|
// A button with a dropdown
|
||||||
return (
|
return (
|
||||||
<ActionButtonDropdown
|
<ActionButtonDropdown
|
||||||
Element="button"
|
Element="button"
|
||||||
@ -215,6 +217,7 @@ export function Toolbar({
|
|||||||
}
|
}
|
||||||
const itemConfig = maybeIconConfig
|
const itemConfig = maybeIconConfig
|
||||||
|
|
||||||
|
// A single button
|
||||||
return (
|
return (
|
||||||
<div className="relative" key={itemConfig.id}>
|
<div className="relative" key={itemConfig.id}>
|
||||||
<ActionButton
|
<ActionButton
|
||||||
|
|||||||
@ -89,6 +89,7 @@ import { EngineCommandManager } from 'lang/std/engineConnection'
|
|||||||
import {
|
import {
|
||||||
getRectangleCallExpressions,
|
getRectangleCallExpressions,
|
||||||
updateRectangleSketch,
|
updateRectangleSketch,
|
||||||
|
updateCenterRectangleSketch,
|
||||||
} from 'lib/rectangleTool'
|
} from 'lib/rectangleTool'
|
||||||
import { getThemeColorForThreeJs, Themes } from 'lib/theme'
|
import { getThemeColorForThreeJs, Themes } from 'lib/theme'
|
||||||
import { err, reportRejection, trap } from 'lib/trap'
|
import { err, reportRejection, trap } from 'lib/trap'
|
||||||
@ -1043,6 +1044,169 @@ export class SceneEntities {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
setupDraftCenterRectangle = async (
|
||||||
|
sketchPathToNode: PathToNode,
|
||||||
|
forward: [number, number, number],
|
||||||
|
up: [number, number, number],
|
||||||
|
sketchOrigin: [number, number, number],
|
||||||
|
rectangleOrigin: [x: number, y: number]
|
||||||
|
) => {
|
||||||
|
let _ast = structuredClone(kclManager.ast)
|
||||||
|
const _node1 = getNodeFromPath<VariableDeclaration>(
|
||||||
|
_ast,
|
||||||
|
sketchPathToNode || [],
|
||||||
|
'VariableDeclaration'
|
||||||
|
)
|
||||||
|
if (trap(_node1)) return Promise.reject(_node1)
|
||||||
|
|
||||||
|
// startSketchOn already exists
|
||||||
|
const variableDeclarationName =
|
||||||
|
_node1.node?.declarations?.[0]?.id?.name || ''
|
||||||
|
const startSketchOn = _node1.node?.declarations
|
||||||
|
const startSketchOnInit = startSketchOn?.[0]?.init
|
||||||
|
|
||||||
|
const tags: [string, string, string] = [
|
||||||
|
findUniqueName(_ast, 'rectangleSegmentA'),
|
||||||
|
findUniqueName(_ast, 'rectangleSegmentB'),
|
||||||
|
findUniqueName(_ast, 'rectangleSegmentC'),
|
||||||
|
]
|
||||||
|
|
||||||
|
startSketchOn[0].init = createPipeExpression([
|
||||||
|
startSketchOnInit,
|
||||||
|
...getRectangleCallExpressions(rectangleOrigin, tags),
|
||||||
|
])
|
||||||
|
|
||||||
|
let _recastAst = parse(recast(_ast))
|
||||||
|
if (trap(_recastAst)) return Promise.reject(_recastAst)
|
||||||
|
_ast = _recastAst
|
||||||
|
|
||||||
|
const { programMemoryOverride, truncatedAst } = await this.setupSketch({
|
||||||
|
sketchPathToNode,
|
||||||
|
forward,
|
||||||
|
up,
|
||||||
|
position: sketchOrigin,
|
||||||
|
maybeModdedAst: _ast,
|
||||||
|
draftExpressionsIndices: { start: 0, end: 3 },
|
||||||
|
})
|
||||||
|
|
||||||
|
sceneInfra.setCallbacks({
|
||||||
|
onMove: async (args) => {
|
||||||
|
// Update the width and height of the draft rectangle
|
||||||
|
const pathToNodeTwo = structuredClone(sketchPathToNode)
|
||||||
|
pathToNodeTwo[1][0] = 0
|
||||||
|
|
||||||
|
const _node = getNodeFromPath<VariableDeclaration>(
|
||||||
|
truncatedAst,
|
||||||
|
pathToNodeTwo || [],
|
||||||
|
'VariableDeclaration'
|
||||||
|
)
|
||||||
|
if (trap(_node)) return Promise.reject(_node)
|
||||||
|
const sketchInit = _node.node?.declarations?.[0]?.init
|
||||||
|
|
||||||
|
const x = (args.intersectionPoint.twoD.x || 0) - rectangleOrigin[0]
|
||||||
|
const y = (args.intersectionPoint.twoD.y || 0) - rectangleOrigin[1]
|
||||||
|
|
||||||
|
if (sketchInit.type === 'PipeExpression') {
|
||||||
|
updateCenterRectangleSketch(
|
||||||
|
sketchInit,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
tags[0],
|
||||||
|
rectangleOrigin[0],
|
||||||
|
rectangleOrigin[1]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const { execState } = await executeAst({
|
||||||
|
ast: truncatedAst,
|
||||||
|
useFakeExecutor: true,
|
||||||
|
engineCommandManager: this.engineCommandManager,
|
||||||
|
programMemoryOverride,
|
||||||
|
idGenerator: kclManager.execState.idGenerator,
|
||||||
|
})
|
||||||
|
const programMemory = execState.memory
|
||||||
|
this.sceneProgramMemory = programMemory
|
||||||
|
const sketch = sketchFromKclValue(
|
||||||
|
programMemory.get(variableDeclarationName),
|
||||||
|
variableDeclarationName
|
||||||
|
)
|
||||||
|
if (err(sketch)) return Promise.reject(sketch)
|
||||||
|
const sgPaths = sketch.paths
|
||||||
|
const orthoFactor = orthoScale(sceneInfra.camControls.camera)
|
||||||
|
|
||||||
|
this.updateSegment(sketch.start, 0, 0, _ast, orthoFactor, sketch)
|
||||||
|
sgPaths.forEach((seg, index) =>
|
||||||
|
this.updateSegment(seg, index, 0, _ast, orthoFactor, sketch)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onClick: async (args) => {
|
||||||
|
// If there is a valid camera interaction that matches, do that instead
|
||||||
|
const interaction = sceneInfra.camControls.getInteractionType(
|
||||||
|
args.mouseEvent
|
||||||
|
)
|
||||||
|
if (interaction !== 'none') return
|
||||||
|
// Commit the rectangle to the full AST/code and return to sketch.idle
|
||||||
|
const cornerPoint = args.intersectionPoint?.twoD
|
||||||
|
if (!cornerPoint || args.mouseEvent.button !== 0) return
|
||||||
|
|
||||||
|
const x = roundOff((cornerPoint.x || 0) - rectangleOrigin[0])
|
||||||
|
const y = roundOff((cornerPoint.y || 0) - rectangleOrigin[1])
|
||||||
|
|
||||||
|
const _node = getNodeFromPath<VariableDeclaration>(
|
||||||
|
_ast,
|
||||||
|
sketchPathToNode || [],
|
||||||
|
'VariableDeclaration'
|
||||||
|
)
|
||||||
|
if (trap(_node)) return
|
||||||
|
const sketchInit = _node.node?.declarations?.[0]?.init
|
||||||
|
|
||||||
|
if (sketchInit.type === 'PipeExpression') {
|
||||||
|
updateCenterRectangleSketch(
|
||||||
|
sketchInit,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
tags[0],
|
||||||
|
rectangleOrigin[0],
|
||||||
|
rectangleOrigin[1]
|
||||||
|
)
|
||||||
|
|
||||||
|
let _recastAst = parse(recast(_ast))
|
||||||
|
if (trap(_recastAst)) return
|
||||||
|
_ast = _recastAst
|
||||||
|
|
||||||
|
// Update the primary AST and unequip the rectangle tool
|
||||||
|
await kclManager.executeAstMock(_ast)
|
||||||
|
sceneInfra.modelingSend({ type: 'Finish center rectangle' })
|
||||||
|
|
||||||
|
const { execState } = await executeAst({
|
||||||
|
ast: _ast,
|
||||||
|
useFakeExecutor: true,
|
||||||
|
engineCommandManager: this.engineCommandManager,
|
||||||
|
programMemoryOverride,
|
||||||
|
idGenerator: kclManager.execState.idGenerator,
|
||||||
|
})
|
||||||
|
const programMemory = execState.memory
|
||||||
|
|
||||||
|
// Prepare to update the THREEjs scene
|
||||||
|
this.sceneProgramMemory = programMemory
|
||||||
|
const sketch = sketchFromKclValue(
|
||||||
|
programMemory.get(variableDeclarationName),
|
||||||
|
variableDeclarationName
|
||||||
|
)
|
||||||
|
if (err(sketch)) return
|
||||||
|
const sgPaths = sketch.paths
|
||||||
|
const orthoFactor = orthoScale(sceneInfra.camControls.camera)
|
||||||
|
|
||||||
|
// Update the starting segment of the THREEjs scene
|
||||||
|
this.updateSegment(sketch.start, 0, 0, _ast, orthoFactor, sketch)
|
||||||
|
// Update the rest of the segments of the THREEjs scene
|
||||||
|
sgPaths.forEach((seg, index) =>
|
||||||
|
this.updateSegment(seg, index, 0, _ast, orthoFactor, sketch)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
setupDraftCircle = async (
|
setupDraftCircle = async (
|
||||||
sketchPathToNode: PathToNode,
|
sketchPathToNode: PathToNode,
|
||||||
forward: [number, number, number],
|
forward: [number, number, number],
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import {
|
|||||||
VariableDeclarator,
|
VariableDeclarator,
|
||||||
Expr,
|
Expr,
|
||||||
Literal,
|
Literal,
|
||||||
|
LiteralValue,
|
||||||
PipeSubstitution,
|
PipeSubstitution,
|
||||||
Identifier,
|
Identifier,
|
||||||
ArrayExpression,
|
ArrayExpression,
|
||||||
@ -573,7 +574,7 @@ export function splitPathAtPipeExpression(pathToNode: PathToNode): {
|
|||||||
return splitPathAtPipeExpression(pathToNode.slice(0, -1))
|
return splitPathAtPipeExpression(pathToNode.slice(0, -1))
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createLiteral(value: string | number): Node<Literal> {
|
export function createLiteral(value: LiteralValue): Node<Literal> {
|
||||||
return {
|
return {
|
||||||
type: 'Literal',
|
type: 'Literal',
|
||||||
start: 0,
|
start: 0,
|
||||||
|
|||||||
@ -1,5 +1,12 @@
|
|||||||
import { Selections } from 'lib/selections'
|
import { Selections } from 'lib/selections'
|
||||||
import { Program, PathToNode } from './wasm'
|
import {
|
||||||
|
Program,
|
||||||
|
PathToNode,
|
||||||
|
CallExpression,
|
||||||
|
Literal,
|
||||||
|
ArrayExpression,
|
||||||
|
BinaryExpression,
|
||||||
|
} from './wasm'
|
||||||
import { getNodeFromPath } from './queryAst'
|
import { getNodeFromPath } from './queryAst'
|
||||||
import { ArtifactGraph, filterArtifacts } from 'lang/std/artifactGraph'
|
import { ArtifactGraph, filterArtifacts } from 'lang/std/artifactGraph'
|
||||||
import { isOverlap } from 'lib/utils'
|
import { isOverlap } from 'lib/utils'
|
||||||
@ -84,3 +91,19 @@ export function isCursorInSketchCommandRange(
|
|||||||
([, artifact]) => artifact.type === 'path'
|
([, artifact]) => artifact.type === 'path'
|
||||||
)?.[0] || false
|
)?.[0] || false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isCallExpression(e: any): e is CallExpression {
|
||||||
|
return e && e.type === 'CallExpression'
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isArrayExpression(e: any): e is ArrayExpression {
|
||||||
|
return e && e.type === 'ArrayExpression'
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isLiteral(e: any): e is Literal {
|
||||||
|
return e && e.type === 'Literal'
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isBinaryExpression(e: any): e is BinaryExpression {
|
||||||
|
return e && e.type === 'BinaryExpression'
|
||||||
|
}
|
||||||
|
|||||||
@ -62,6 +62,7 @@ export type { CallExpression } from '../wasm-lib/kcl/bindings/CallExpression'
|
|||||||
export type { VariableDeclarator } from '../wasm-lib/kcl/bindings/VariableDeclarator'
|
export type { VariableDeclarator } from '../wasm-lib/kcl/bindings/VariableDeclarator'
|
||||||
export type { BinaryPart } from '../wasm-lib/kcl/bindings/BinaryPart'
|
export type { BinaryPart } from '../wasm-lib/kcl/bindings/BinaryPart'
|
||||||
export type { Literal } from '../wasm-lib/kcl/bindings/Literal'
|
export type { Literal } from '../wasm-lib/kcl/bindings/Literal'
|
||||||
|
export type { LiteralValue } from '../wasm-lib/kcl/bindings/LiteralValue'
|
||||||
export type { ArrayExpression } from '../wasm-lib/kcl/bindings/ArrayExpression'
|
export type { ArrayExpression } from '../wasm-lib/kcl/bindings/ArrayExpression'
|
||||||
|
|
||||||
export type SyntaxType =
|
export type SyntaxType =
|
||||||
@ -81,6 +82,7 @@ export type SyntaxType =
|
|||||||
| 'PipeExpression'
|
| 'PipeExpression'
|
||||||
| 'PipeSubstitution'
|
| 'PipeSubstitution'
|
||||||
| 'Literal'
|
| 'Literal'
|
||||||
|
| 'LiteralValue'
|
||||||
| 'NonCodeNode'
|
| 'NonCodeNode'
|
||||||
| 'UnaryExpression'
|
| 'UnaryExpression'
|
||||||
|
|
||||||
|
|||||||
@ -9,8 +9,16 @@ import {
|
|||||||
createUnaryExpression,
|
createUnaryExpression,
|
||||||
} from 'lang/modifyAst'
|
} from 'lang/modifyAst'
|
||||||
import { ArrayExpression, CallExpression, PipeExpression } from 'lang/wasm'
|
import { ArrayExpression, CallExpression, PipeExpression } from 'lang/wasm'
|
||||||
|
import { roundOff } from 'lib/utils'
|
||||||
|
import {
|
||||||
|
isCallExpression,
|
||||||
|
isArrayExpression,
|
||||||
|
isLiteral,
|
||||||
|
isBinaryExpression,
|
||||||
|
} from 'lang/util'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* It does not create the startSketchOn and it does not create the startProfileAt.
|
||||||
* Returns AST expressions for this KCL code:
|
* Returns AST expressions for this KCL code:
|
||||||
* const yo = startSketchOn('XY')
|
* const yo = startSketchOn('XY')
|
||||||
* |> startProfileAt([0, 0], %)
|
* |> startProfileAt([0, 0], %)
|
||||||
@ -92,3 +100,69 @@ export function updateRectangleSketch(
|
|||||||
createLiteral(Math.abs(y)), // This will be the height of the rectangle
|
createLiteral(Math.abs(y)), // This will be the height of the rectangle
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mutates the pipeExpression to update the center rectangle sketch
|
||||||
|
* @param pipeExpression
|
||||||
|
* @param x
|
||||||
|
* @param y
|
||||||
|
* @param tag
|
||||||
|
*/
|
||||||
|
export function updateCenterRectangleSketch(
|
||||||
|
pipeExpression: PipeExpression,
|
||||||
|
deltaX: number,
|
||||||
|
deltaY: number,
|
||||||
|
tag: string,
|
||||||
|
originX: number,
|
||||||
|
originY: number
|
||||||
|
) {
|
||||||
|
let startX = originX - Math.abs(deltaX)
|
||||||
|
let startY = originY - Math.abs(deltaY)
|
||||||
|
|
||||||
|
// pipeExpression.body[1] is startProfileAt
|
||||||
|
let callExpression = pipeExpression.body[1]
|
||||||
|
if (isCallExpression(callExpression)) {
|
||||||
|
const arrayExpression = callExpression.arguments[0]
|
||||||
|
if (isArrayExpression(arrayExpression)) {
|
||||||
|
callExpression.arguments[0] = createArrayExpression([
|
||||||
|
createLiteral(roundOff(startX)),
|
||||||
|
createLiteral(roundOff(startY)),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const twoX = deltaX * 2
|
||||||
|
const twoY = deltaY * 2
|
||||||
|
|
||||||
|
callExpression = pipeExpression.body[2]
|
||||||
|
if (isCallExpression(callExpression)) {
|
||||||
|
const arrayExpression = callExpression.arguments[0]
|
||||||
|
if (isArrayExpression(arrayExpression)) {
|
||||||
|
const literal = arrayExpression.elements[0]
|
||||||
|
if (isLiteral(literal)) {
|
||||||
|
callExpression.arguments[0] = createArrayExpression([
|
||||||
|
createLiteral(literal.value),
|
||||||
|
createLiteral(Math.abs(twoX)),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
callExpression = pipeExpression.body[3]
|
||||||
|
if (isCallExpression(callExpression)) {
|
||||||
|
const arrayExpression = callExpression.arguments[0]
|
||||||
|
if (isArrayExpression(arrayExpression)) {
|
||||||
|
const binaryExpression = arrayExpression.elements[0]
|
||||||
|
if (isBinaryExpression(binaryExpression)) {
|
||||||
|
callExpression.arguments[0] = createArrayExpression([
|
||||||
|
createBinaryExpression([
|
||||||
|
createCallExpressionStdLib('segAng', [createIdentifier(tag)]),
|
||||||
|
binaryExpression.operator,
|
||||||
|
createLiteral(90),
|
||||||
|
]), // 90 offset from the previous line
|
||||||
|
createLiteral(Math.abs(twoY)), // This will be the height of the rectangle
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -407,8 +407,9 @@ export const toolbarConfig: Record<ToolbarModeName, ToolbarMode> = {
|
|||||||
status: 'available',
|
status: 'available',
|
||||||
title: 'Center circle',
|
title: 'Center circle',
|
||||||
disabled: (state) =>
|
disabled: (state) =>
|
||||||
!canRectangleOrCircleTool(state.context) &&
|
state.matches('Sketch no face') ||
|
||||||
!state.matches({ Sketch: 'Circle tool' }),
|
(!canRectangleOrCircleTool(state.context) &&
|
||||||
|
!state.matches({ Sketch: 'Circle tool' })),
|
||||||
isActive: (state) => state.matches({ Sketch: 'Circle tool' }),
|
isActive: (state) => state.matches({ Sketch: 'Circle tool' }),
|
||||||
hotkey: (state) =>
|
hotkey: (state) =>
|
||||||
state.matches({ Sketch: 'Circle tool' }) ? ['Esc', 'C'] : 'C',
|
state.matches({ Sketch: 'Circle tool' }) ? ['Esc', 'C'] : 'C',
|
||||||
@ -448,8 +449,9 @@ export const toolbarConfig: Record<ToolbarModeName, ToolbarMode> = {
|
|||||||
icon: 'rectangle',
|
icon: 'rectangle',
|
||||||
status: 'available',
|
status: 'available',
|
||||||
disabled: (state) =>
|
disabled: (state) =>
|
||||||
!canRectangleOrCircleTool(state.context) &&
|
state.matches('Sketch no face') ||
|
||||||
!state.matches({ Sketch: 'Rectangle tool' }),
|
(!canRectangleOrCircleTool(state.context) &&
|
||||||
|
!state.matches({ Sketch: 'Rectangle tool' })),
|
||||||
title: 'Corner rectangle',
|
title: 'Corner rectangle',
|
||||||
hotkey: (state) =>
|
hotkey: (state) =>
|
||||||
state.matches({ Sketch: 'Rectangle tool' }) ? ['Esc', 'R'] : 'R',
|
state.matches({ Sketch: 'Rectangle tool' }) ? ['Esc', 'R'] : 'R',
|
||||||
@ -459,13 +461,33 @@ export const toolbarConfig: Record<ToolbarModeName, ToolbarMode> = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'center-rectangle',
|
id: 'center-rectangle',
|
||||||
onClick: () => console.error('Center rectangle not yet implemented'),
|
onClick: ({ modelingState, modelingSend }) =>
|
||||||
icon: 'rectangle',
|
modelingSend({
|
||||||
status: 'unavailable',
|
type: 'change tool',
|
||||||
|
data: {
|
||||||
|
tool: !modelingState.matches({
|
||||||
|
Sketch: 'Center Rectangle tool',
|
||||||
|
})
|
||||||
|
? 'center rectangle'
|
||||||
|
: 'none',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
icon: 'arc',
|
||||||
|
status: 'available',
|
||||||
|
disabled: (state) =>
|
||||||
|
state.matches('Sketch no face') ||
|
||||||
|
(!canRectangleOrCircleTool(state.context) &&
|
||||||
|
!state.matches({ Sketch: 'Center Rectangle tool' })),
|
||||||
title: 'Center rectangle',
|
title: 'Center rectangle',
|
||||||
showTitle: false,
|
hotkey: (state) =>
|
||||||
|
state.matches({ Sketch: 'Center Rectangle tool' })
|
||||||
|
? ['Esc', 'C']
|
||||||
|
: 'C',
|
||||||
description: 'Start drawing a rectangle from its center',
|
description: 'Start drawing a rectangle from its center',
|
||||||
links: [],
|
links: [],
|
||||||
|
isActive: (state) => {
|
||||||
|
return state.matches({ Sketch: 'Center Rectangle tool' })
|
||||||
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
{
|
{
|
||||||
|
|||||||
@ -184,6 +184,7 @@ export type SketchTool =
|
|||||||
| 'line'
|
| 'line'
|
||||||
| 'tangentialArc'
|
| 'tangentialArc'
|
||||||
| 'rectangle'
|
| 'rectangle'
|
||||||
|
| 'center rectangle'
|
||||||
| 'circle'
|
| 'circle'
|
||||||
| 'none'
|
| 'none'
|
||||||
|
|
||||||
@ -238,6 +239,10 @@ export type ModelingMachineEvent =
|
|||||||
type: 'Add rectangle origin'
|
type: 'Add rectangle origin'
|
||||||
data: [x: number, y: number]
|
data: [x: number, y: number]
|
||||||
}
|
}
|
||||||
|
| {
|
||||||
|
type: 'Add center rectangle origin'
|
||||||
|
data: [x: number, y: number]
|
||||||
|
}
|
||||||
| {
|
| {
|
||||||
type: 'Add circle origin'
|
type: 'Add circle origin'
|
||||||
data: [x: number, y: number]
|
data: [x: number, y: number]
|
||||||
@ -278,6 +283,7 @@ export type ModelingMachineEvent =
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
| { type: 'Finish rectangle' }
|
| { type: 'Finish rectangle' }
|
||||||
|
| { type: 'Finish center rectangle' }
|
||||||
| { type: 'Finish circle' }
|
| { type: 'Finish circle' }
|
||||||
| { type: 'Artifact graph populated' }
|
| { type: 'Artifact graph populated' }
|
||||||
| { type: 'Artifact graph emptied' }
|
| { type: 'Artifact graph emptied' }
|
||||||
@ -506,6 +512,9 @@ export const modelingMachine = setup({
|
|||||||
'next is rectangle': ({ context: { sketchDetails, currentTool } }) =>
|
'next is rectangle': ({ context: { sketchDetails, currentTool } }) =>
|
||||||
currentTool === 'rectangle' &&
|
currentTool === 'rectangle' &&
|
||||||
canRectangleOrCircleTool({ sketchDetails }),
|
canRectangleOrCircleTool({ sketchDetails }),
|
||||||
|
'next is center rectangle': ({ context: { sketchDetails, currentTool } }) =>
|
||||||
|
currentTool === 'center rectangle' &&
|
||||||
|
canRectangleOrCircleTool({ sketchDetails }),
|
||||||
'next is circle': ({ context: { sketchDetails, currentTool } }) =>
|
'next is circle': ({ context: { sketchDetails, currentTool } }) =>
|
||||||
currentTool === 'circle' && canRectangleOrCircleTool({ sketchDetails }),
|
currentTool === 'circle' && canRectangleOrCircleTool({ sketchDetails }),
|
||||||
'next is line': ({ context }) => context.currentTool === 'line',
|
'next is line': ({ context }) => context.currentTool === 'line',
|
||||||
@ -806,6 +815,26 @@ export const modelingMachine = setup({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
'listen for center rectangle origin': ({ context: { sketchDetails } }) => {
|
||||||
|
if (!sketchDetails) return
|
||||||
|
// setupNoPointsListener has the code for startProfileAt onClick
|
||||||
|
sceneEntitiesManager.setupNoPointsListener({
|
||||||
|
sketchDetails,
|
||||||
|
afterClick: (args) => {
|
||||||
|
const twoD = args.intersectionPoint?.twoD
|
||||||
|
if (twoD) {
|
||||||
|
sceneInfra.modelingSend({
|
||||||
|
type: 'Add center rectangle origin',
|
||||||
|
data: [twoD.x, twoD.y],
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
console.error('No intersection point found')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
'listen for circle origin': ({ context: { sketchDetails } }) => {
|
'listen for circle origin': ({ context: { sketchDetails } }) => {
|
||||||
if (!sketchDetails) return
|
if (!sketchDetails) return
|
||||||
sceneEntitiesManager.createIntersectionPlane()
|
sceneEntitiesManager.createIntersectionPlane()
|
||||||
@ -859,6 +888,21 @@ export const modelingMachine = setup({
|
|||||||
return codeManager.updateEditorWithAstAndWriteToFile(kclManager.ast)
|
return codeManager.updateEditorWithAstAndWriteToFile(kclManager.ast)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
'set up draft center rectangle': ({
|
||||||
|
context: { sketchDetails },
|
||||||
|
event,
|
||||||
|
}) => {
|
||||||
|
if (event.type !== 'Add center rectangle origin') return
|
||||||
|
if (!sketchDetails || !event.data) return
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
|
sceneEntitiesManager.setupDraftCenterRectangle(
|
||||||
|
sketchDetails.sketchPathToNode,
|
||||||
|
sketchDetails.zAxis,
|
||||||
|
sketchDetails.yAxis,
|
||||||
|
sketchDetails.origin,
|
||||||
|
event.data
|
||||||
|
)
|
||||||
|
},
|
||||||
'set up draft circle': ({ context: { sketchDetails }, event }) => {
|
'set up draft circle': ({ context: { sketchDetails }, event }) => {
|
||||||
if (event.type !== 'Add circle origin') return
|
if (event.type !== 'Add circle origin') return
|
||||||
if (!sketchDetails || !event.data) return
|
if (!sketchDetails || !event.data) return
|
||||||
@ -1822,6 +1866,40 @@ export const modelingMachine = setup({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
'Center Rectangle tool': {
|
||||||
|
entry: ['listen for center rectangle origin'],
|
||||||
|
|
||||||
|
states: {
|
||||||
|
'Awaiting corner': {
|
||||||
|
on: {
|
||||||
|
'Finish center rectangle': 'Finished Center Rectangle',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
'Awaiting origin': {
|
||||||
|
on: {
|
||||||
|
'Add center rectangle origin': {
|
||||||
|
target: 'Awaiting corner',
|
||||||
|
// TODO
|
||||||
|
actions: 'set up draft center rectangle',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
'Finished Center Rectangle': {
|
||||||
|
always: '#Modeling.Sketch.SketchIdle',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
initial: 'Awaiting origin',
|
||||||
|
|
||||||
|
on: {
|
||||||
|
'change tool': {
|
||||||
|
target: 'Change Tool',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
'clean slate': {
|
'clean slate': {
|
||||||
always: 'SketchIdle',
|
always: 'SketchIdle',
|
||||||
},
|
},
|
||||||
@ -2015,6 +2093,10 @@ export const modelingMachine = setup({
|
|||||||
target: 'Circle tool',
|
target: 'Circle tool',
|
||||||
guard: 'next is circle',
|
guard: 'next is circle',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
target: 'Center Rectangle tool',
|
||||||
|
guard: 'next is center rectangle',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
entry: 'assign tool in context',
|
entry: 'assign tool in context',
|
||||||
|
|||||||
Reference in New Issue
Block a user