initial implementation of sketching on extrude face
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
import { useStore } from './useStore'
|
||||
import { extrudeSketch } from './lang/modifyAst'
|
||||
import { extrudeSketch, sketchOnExtrudedFace } from './lang/modifyAst'
|
||||
import { getNodePathFromSourceRange } from './lang/abstractSyntaxTree'
|
||||
|
||||
export const Toolbar = () => {
|
||||
@ -27,8 +27,21 @@ export const Toolbar = () => {
|
||||
Start sketch
|
||||
</button>
|
||||
)}
|
||||
{guiMode.mode === 'canEditSketch' && (
|
||||
{guiMode.mode === 'canEditExtrude' && (
|
||||
<button
|
||||
onClick={() => {
|
||||
if (!ast) return
|
||||
const pathToNode = getNodePathFromSourceRange(ast, selectionRange)
|
||||
const { modifiedAst } = sketchOnExtrudedFace(ast, pathToNode)
|
||||
updateAst(modifiedAst)
|
||||
}}
|
||||
className="border m-1 px-1 rounded"
|
||||
>
|
||||
SketchOnFace
|
||||
</button>
|
||||
)}
|
||||
{(guiMode.mode === 'canEditSketch' || false) && (
|
||||
/*guiMode.mode === 'canEditExtrude'*/ <button
|
||||
onClick={() => {
|
||||
setGuiMode({
|
||||
mode: 'sketch',
|
||||
@ -48,8 +61,8 @@ export const Toolbar = () => {
|
||||
<button
|
||||
onClick={() => {
|
||||
if (!ast) return
|
||||
const pathToNote = getNodePathFromSourceRange(ast, selectionRange)
|
||||
const { modifiedAst } = extrudeSketch(ast, pathToNote)
|
||||
const pathToNode = getNodePathFromSourceRange(ast, selectionRange)
|
||||
const { modifiedAst } = extrudeSketch(ast, pathToNode)
|
||||
updateAst(modifiedAst)
|
||||
}}
|
||||
className="border m-1 px-1 rounded"
|
||||
@ -59,8 +72,8 @@ export const Toolbar = () => {
|
||||
<button
|
||||
onClick={() => {
|
||||
if (!ast) return
|
||||
const pathToNote = getNodePathFromSourceRange(ast, selectionRange)
|
||||
const { modifiedAst } = extrudeSketch(ast, pathToNote, false)
|
||||
const pathToNode = getNodePathFromSourceRange(ast, selectionRange)
|
||||
const { modifiedAst } = extrudeSketch(ast, pathToNode, false)
|
||||
updateAst(modifiedAst)
|
||||
}}
|
||||
className="border m-1 px-1 rounded"
|
||||
@ -70,7 +83,7 @@ export const Toolbar = () => {
|
||||
</>
|
||||
)}
|
||||
|
||||
{guiMode.mode !== 'default' && (
|
||||
{guiMode.mode === 'sketch' && (
|
||||
<button
|
||||
onClick={() => setGuiMode({ mode: 'default' })}
|
||||
className="border m-1 px-1 rounded"
|
||||
|
@ -216,7 +216,7 @@ function RenderViewerArtifact({
|
||||
const [editorCursor, setEditorCursor] = useState(false)
|
||||
useEffect(() => {
|
||||
const shouldHighlight = isOverlapping(
|
||||
artifact.__meta.slice(-1)[0].sourceRange,
|
||||
artifact.__meta[0].sourceRange,
|
||||
selectionRange
|
||||
)
|
||||
setEditorCursor(shouldHighlight)
|
||||
@ -238,10 +238,22 @@ function RenderViewerArtifact({
|
||||
)
|
||||
const { rotation, position } = artifact
|
||||
setGuiMode({ mode: 'canEditSketch', pathToNode, rotation, position })
|
||||
} else if (
|
||||
shouldHighlight &&
|
||||
(guiMode.mode === 'default' || guiMode.mode === 'canEditSketch') &&
|
||||
ast &&
|
||||
artifact.type === 'extrudeGroup'
|
||||
) {
|
||||
const pathToNode = getNodePathFromSourceRange(
|
||||
ast,
|
||||
artifact.__meta[0].sourceRange
|
||||
)
|
||||
const { rotation, position } = artifact
|
||||
setGuiMode({ mode: 'canEditExtrude', pathToNode, rotation, position })
|
||||
} else if (
|
||||
!shouldHighlight &&
|
||||
guiMode.mode === 'canEditSketch' &&
|
||||
artifact.type === 'sketchGroup'
|
||||
(guiMode.mode === 'canEditSketch' || guiMode.mode === 'canEditExtrude') &&
|
||||
(artifact.type === 'sketchGroup' || artifact.type === 'extrudeGroup')
|
||||
) {
|
||||
setGuiMode({ mode: 'default' })
|
||||
}
|
||||
|
@ -98,6 +98,10 @@ show(mySketch001)`
|
||||
sourceRange: [89, 102],
|
||||
pathToNode: [],
|
||||
},
|
||||
{
|
||||
sourceRange: [20, 68],
|
||||
pathToNode: ['body', 0, 'declarations', 0, 'init', 0],
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
@ -176,6 +180,10 @@ show(theExtrude, sk2)`
|
||||
sourceRange: [138, 166],
|
||||
pathToNode: [],
|
||||
},
|
||||
{
|
||||
sourceRange: [12, 75],
|
||||
pathToNode: ['body', 0, 'declarations', 0, 'init', 0],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@ -224,6 +232,10 @@ show(theExtrude, sk2)`
|
||||
sourceRange: [334, 347],
|
||||
pathToNode: [],
|
||||
},
|
||||
{
|
||||
sourceRange: [237, 299],
|
||||
pathToNode: ['body', 3, 'declarations', 0, 'init', 0],
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
|
@ -10,6 +10,7 @@ import {
|
||||
getNodeFromPath,
|
||||
VariableDeclarator,
|
||||
} from './abstractSyntaxTree'
|
||||
import { PathToNode } from './executor'
|
||||
|
||||
export function addSketchTo(
|
||||
node: Program,
|
||||
@ -107,6 +108,7 @@ export function addSketchTo(
|
||||
function findUniqueName(
|
||||
ast: Program | string,
|
||||
name: string,
|
||||
pad = 3,
|
||||
index = 1
|
||||
): string {
|
||||
let searchStr = ''
|
||||
@ -115,13 +117,13 @@ function findUniqueName(
|
||||
} else {
|
||||
searchStr = JSON.stringify(ast)
|
||||
}
|
||||
const indexStr = `${index}`.padStart(3, '0')
|
||||
const indexStr = `${index}`.padStart(pad, '0')
|
||||
const newName = `${name}${indexStr}`
|
||||
const isInString = searchStr.includes(newName)
|
||||
if (!isInString) {
|
||||
return newName
|
||||
}
|
||||
return findUniqueName(searchStr, name, index + 1)
|
||||
return findUniqueName(searchStr, name, pad, index + 1)
|
||||
}
|
||||
|
||||
function addToShow(node: Program, name: string): Program {
|
||||
@ -375,3 +377,136 @@ export function extrudeSketch(
|
||||
pathToNode: [...pathToNode.slice(0, -1), showCallIndex],
|
||||
}
|
||||
}
|
||||
|
||||
export function sketchOnExtrudedFace(
|
||||
node: Program,
|
||||
pathToNode: (string | number)[]
|
||||
): { modifiedAst: Program; pathToNode: (string | number)[] } {
|
||||
const _node = { ...node }
|
||||
const dumbyStartend = { start: 0, end: 0 }
|
||||
const newSketchName = findUniqueName(node, 'part')
|
||||
const oldSketchName = getNodeFromPath(_node, pathToNode, 'VariableDeclarator')
|
||||
.id.name
|
||||
const expression = getNodeFromPath(_node, pathToNode, 'CallExpression') as
|
||||
| VariableDeclarator
|
||||
| CallExpression
|
||||
const pathName =
|
||||
expression.type === 'VariableDeclarator'
|
||||
? expression.id.name
|
||||
: findUniqueName(node, 'path', 2)
|
||||
|
||||
if (expression.type === 'CallExpression') {
|
||||
const block = getNodeFromPath(_node, pathToNode, 'BlockStatement')
|
||||
const expressionIndex = getLastIndex(pathToNode)
|
||||
if (expression.callee.name !== 'lineTo')
|
||||
throw new Error('expected a lineTo call')
|
||||
const newExpression: VariableDeclaration = {
|
||||
type: 'VariableDeclaration',
|
||||
...dumbyStartend,
|
||||
declarations: [
|
||||
{
|
||||
type: 'VariableDeclarator',
|
||||
...dumbyStartend,
|
||||
id: {
|
||||
type: 'Identifier',
|
||||
...dumbyStartend,
|
||||
name: pathName,
|
||||
},
|
||||
init: expression,
|
||||
},
|
||||
],
|
||||
kind: 'path',
|
||||
}
|
||||
|
||||
block.body.splice(expressionIndex, 1, newExpression)
|
||||
}
|
||||
|
||||
// create pipe expression with a sketch block piped into a transform function
|
||||
const sketchPipe: PipeExpression = {
|
||||
type: 'PipeExpression',
|
||||
...dumbyStartend,
|
||||
body: [
|
||||
{
|
||||
type: 'SketchExpression',
|
||||
...dumbyStartend,
|
||||
body: {
|
||||
type: 'BlockStatement',
|
||||
...dumbyStartend,
|
||||
body: [],
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'CallExpression',
|
||||
...dumbyStartend,
|
||||
callee: {
|
||||
type: 'Identifier',
|
||||
...dumbyStartend,
|
||||
name: 'transform',
|
||||
},
|
||||
optional: false,
|
||||
arguments: [
|
||||
{
|
||||
type: 'CallExpression',
|
||||
...dumbyStartend,
|
||||
callee: {
|
||||
type: 'Identifier',
|
||||
...dumbyStartend,
|
||||
name: 'getExtrudeWallTransform',
|
||||
},
|
||||
optional: false,
|
||||
arguments: [
|
||||
{
|
||||
type: 'Literal',
|
||||
...dumbyStartend,
|
||||
value: pathName,
|
||||
raw: `'${pathName}'`,
|
||||
},
|
||||
{
|
||||
type: 'Identifier',
|
||||
...dumbyStartend,
|
||||
name: oldSketchName,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'PipeSubstitution',
|
||||
...dumbyStartend,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
const variableDec: VariableDeclaration = {
|
||||
type: 'VariableDeclaration',
|
||||
...dumbyStartend,
|
||||
declarations: [
|
||||
{
|
||||
type: 'VariableDeclarator',
|
||||
...dumbyStartend,
|
||||
id: {
|
||||
type: 'Identifier',
|
||||
...dumbyStartend,
|
||||
name: newSketchName,
|
||||
},
|
||||
init: sketchPipe,
|
||||
},
|
||||
],
|
||||
kind: 'sketch',
|
||||
}
|
||||
|
||||
const showIndex = getShowIndex(_node)
|
||||
_node.body.splice(showIndex, 0, variableDec)
|
||||
|
||||
return {
|
||||
modifiedAst: addToShow(_node, newSketchName),
|
||||
pathToNode,
|
||||
}
|
||||
}
|
||||
|
||||
const getLastIndex = (pathToNode: PathToNode): number => {
|
||||
const last = pathToNode[pathToNode.length - 1]
|
||||
if (typeof last === 'number') {
|
||||
return last
|
||||
}
|
||||
return getLastIndex(pathToNode.slice(0, -1))
|
||||
}
|
||||
|
@ -228,6 +228,10 @@ export const sketchFns = {
|
||||
sourceRange,
|
||||
pathToNode: [], // TODO
|
||||
},
|
||||
{
|
||||
sourceRange: sketchVal.__meta[0].sourceRange,
|
||||
pathToNode: sketchVal.__meta[0].pathToNode,
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
|
@ -36,6 +36,12 @@ type GuiModes =
|
||||
rotation: Rotation
|
||||
position: Position
|
||||
}
|
||||
| {
|
||||
mode: 'canEditExtrude'
|
||||
pathToNode: PathToNode
|
||||
rotation: Rotation
|
||||
position: Position
|
||||
}
|
||||
|
||||
interface StoreState {
|
||||
editorView: EditorView | null
|
||||
|
Reference in New Issue
Block a user