addNewSketchLn should close when latest point matches start (#479)

* addNewSketchLn should close when latest point matches start

* Fix types

* Include close in test case

* Add handling for continuing to sketch

* Fix types again

* close line edits (#523)

* add close to pipe

* undo some previous changes

---------

Co-authored-by: Kurt Hutten <k.hutten@protonmail.ch>
This commit is contained in:
Adam Sunderland
2023-09-14 09:34:37 -04:00
committed by GitHub
parent 66ba60dc8e
commit cdb4c36cf5
3 changed files with 111 additions and 18 deletions

View File

@ -14,7 +14,13 @@ import { useGlobalStateContext } from 'hooks/useGlobalStateContext'
import { CameraDragInteractionType_type } from '@kittycad/lib/dist/types/src/models'
import { Models } from '@kittycad/lib'
import { addStartSketch } from 'lang/modifyAst'
import { addNewSketchLn } from 'lang/std/sketch'
import {
addCloseToPipe,
addNewSketchLn,
compareVec2Epsilon,
} from 'lang/std/sketch'
import { getNodeFromPath } from 'lang/queryAst'
import { Program, VariableDeclarator } from 'lang/abstractSyntaxTreeTypes'
export const Stream = ({ className = '' }) => {
const [isLoading, setIsLoading] = useState(true)
@ -204,8 +210,8 @@ export const Stream = ({ className = '' }) => {
window: { x, y },
}
}
engineCommandManager?.sendSceneCommand(command).then(async ({ data }) => {
if (command.cmd.type !== 'mouse_click' || !ast) return
engineCommandManager?.sendSceneCommand(command).then(async (resp) => {
if (command?.cmd?.type !== 'mouse_click' || !ast) return
if (
!(
guiMode.mode === 'sketch' &&
@ -214,13 +220,16 @@ export const Stream = ({ className = '' }) => {
)
return
if (data?.data?.entities_modified?.length && guiMode.waitingFirstClick) {
if (
resp?.data?.data?.entities_modified?.length &&
guiMode.waitingFirstClick
) {
const curve = await engineCommandManager?.sendSceneCommand({
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
type: 'curve_get_control_points',
curve_id: data?.data?.entities_modified[0],
curve_id: resp?.data?.data?.entities_modified[0],
},
})
const coords: { x: number; y: number }[] =
@ -243,7 +252,7 @@ export const Stream = ({ className = '' }) => {
})
updateAst(_modifiedAst)
} else if (
data?.data?.entities_modified?.length &&
resp?.data?.data?.entities_modified?.length &&
!guiMode.waitingFirstClick
) {
const curve = await engineCommandManager?.sendSceneCommand({
@ -251,18 +260,46 @@ export const Stream = ({ className = '' }) => {
cmd_id: uuidv4(),
cmd: {
type: 'curve_get_control_points',
curve_id: data?.data?.entities_modified[0],
curve_id: resp?.data?.data?.entities_modified[0],
},
})
const coords: { x: number; y: number }[] =
curve.data.data.control_points
const _modifiedAst = addNewSketchLn({
const { node: varDec } = getNodeFromPath<VariableDeclarator>(
ast,
guiMode.pathToNode,
'VariableDeclarator'
)
const variableName = varDec.id.name
const sketchGroup = programMemory.root[variableName]
if (!sketchGroup || sketchGroup.type !== 'SketchGroup') return
const initialCoords = sketchGroup.value[0].from
const isClose = compareVec2Epsilon(initialCoords, [
coords[1].x,
coords[1].y,
])
let _modifiedAst: Program
if (!isClose) {
_modifiedAst = addNewSketchLn({
node: ast,
programMemory,
to: [coords[1].x, coords[1].y],
fnName: 'line',
pathToNode: guiMode.pathToNode,
}).modifiedAst
} else {
_modifiedAst = addCloseToPipe({
node: ast,
programMemory,
pathToNode: guiMode.pathToNode,
})
setGuiMode({
mode: 'default',
})
}
updateAst(_modifiedAst)
}
})

View File

@ -4,6 +4,7 @@ import {
addNewSketchLn,
getYComponent,
getXComponent,
addCloseToPipe,
} from './sketch'
import { parser_wasm } from '../abstractSyntaxTree'
import { getNodePathFromSourceRange } from '../queryAst'
@ -146,7 +147,7 @@ show(mySketch001)`
const programMemory = await enginelessExecutor(ast)
const sourceStart = code.indexOf(lineToChange)
expect(sourceStart).toBe(66)
const { modifiedAst } = addNewSketchLn({
let { modifiedAst } = addNewSketchLn({
node: ast,
programMemory,
to: [2, 3],
@ -160,12 +161,33 @@ show(mySketch001)`
],
})
// Enable rotations #152
const expectedCode = `const mySketch001 = startSketchAt([0, 0])
let expectedCode = `const mySketch001 = startSketchAt([0, 0])
// |> rx(45, %)
|> lineTo([-1.59, -1.54], %)
|> lineTo([0.46, -5.82], %)
|> lineTo([2, 3], %)
show(mySketch001)
`
expect(recast(modifiedAst)).toBe(expectedCode)
modifiedAst = addCloseToPipe({
node: ast,
programMemory,
pathToNode: [
['body', ''],
[0, 'index'],
['declarations', 'VariableDeclaration'],
[0, 'index'],
['init', 'VariableDeclarator'],
],
})
expectedCode = `const mySketch001 = startSketchAt([0, 0])
// |> rx(45, %)
|> lineTo([-1.59, -1.54], %)
|> lineTo([0.46, -5.82], %)
|> close(%)
show(mySketch001)
`
expect(recast(modifiedAst)).toBe(expectedCode)
})

View File

@ -947,13 +947,25 @@ interface CreateLineFnCallArgs {
pathToNode: PathToNode
}
export function compareVec2Epsilon(
vec1: [number, number],
vec2: [number, number]
) {
const compareEpsilon = 0.015625 // or 2^-6
const xDifference = Math.abs(vec1[0] - vec2[0])
const yDifference = Math.abs(vec1[0] - vec2[0])
return xDifference < compareEpsilon && yDifference < compareEpsilon
}
export function addNewSketchLn({
node: _node,
programMemory: previousProgramMemory,
to,
fnName,
pathToNode,
}: Omit<CreateLineFnCallArgs, 'from'>): { modifiedAst: Program } {
}: Omit<CreateLineFnCallArgs, 'from'>): {
modifiedAst: Program
} {
const node = JSON.parse(JSON.stringify(_node))
const { add, updateArgs } = sketchLineHelperMap?.[fnName] || {}
if (!add || !updateArgs) throw new Error('not a sketch line helper')
@ -971,7 +983,6 @@ export function addNewSketchLn({
const last = sketch.value[sketch.value.length - 1] || sketch.start
const from = last.to
return add({
node,
previousProgramMemory,
@ -982,6 +993,29 @@ export function addNewSketchLn({
})
}
export function addCloseToPipe({
node,
pathToNode,
}: {
node: Program
programMemory: ProgramMemory
pathToNode: PathToNode
}) {
const _node = { ...node }
const closeExpression = createCallExpression('close', [
createPipeSubstitution(),
])
const pipeExpression = getNodeFromPath<PipeExpression>(
_node,
pathToNode,
'PipeExpression'
).node
if (pipeExpression.type !== 'PipeExpression')
throw new Error('not a pipe expression')
pipeExpression.body = [...pipeExpression.body, closeExpression]
return _node
}
export function replaceSketchLine({
node,
programMemory,