initial set horz-vert distance constraint (#42)
inital set horz-vert distance constraint
This commit is contained in:
@ -3,6 +3,7 @@ import { extrudeSketch, sketchOnExtrudedFace } from './lang/modifyAst'
|
|||||||
import { getNodePathFromSourceRange } from './lang/queryAst'
|
import { getNodePathFromSourceRange } from './lang/queryAst'
|
||||||
import { HorzVert } from './components/Toolbar/HorzVert'
|
import { HorzVert } from './components/Toolbar/HorzVert'
|
||||||
import { Equal } from './components/Toolbar/Equal'
|
import { Equal } from './components/Toolbar/Equal'
|
||||||
|
import { SetHorzDistance } from './components/Toolbar/SetHorzDistance'
|
||||||
|
|
||||||
export const Toolbar = () => {
|
export const Toolbar = () => {
|
||||||
const {
|
const {
|
||||||
@ -156,6 +157,8 @@ export const Toolbar = () => {
|
|||||||
<HorzVert horOrVert="horizontal" />
|
<HorzVert horOrVert="horizontal" />
|
||||||
<HorzVert horOrVert="vertical" />
|
<HorzVert horOrVert="vertical" />
|
||||||
<Equal />
|
<Equal />
|
||||||
|
<SetHorzDistance horOrVert="setHorzDistance" />
|
||||||
|
<SetHorzDistance horOrVert="setVertDistance" />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
97
src/components/Toolbar/SetHorzDistance.tsx
Normal file
97
src/components/Toolbar/SetHorzDistance.tsx
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
import { useState, useEffect } from 'react'
|
||||||
|
import { toolTips, useStore } from '../../useStore'
|
||||||
|
import { Value, VariableDeclarator } from '../../lang/abstractSyntaxTree'
|
||||||
|
import {
|
||||||
|
getNodePathFromSourceRange,
|
||||||
|
getNodeFromPath,
|
||||||
|
} from '../../lang/queryAst'
|
||||||
|
import { isSketchVariablesLinked } from '../../lang/std/sketchConstraints'
|
||||||
|
import {
|
||||||
|
TransformInfo,
|
||||||
|
transformAstForSketchLines,
|
||||||
|
getTransformInfos,
|
||||||
|
} from '../../lang/std/sketchcombos'
|
||||||
|
|
||||||
|
export const SetHorzDistance = ({
|
||||||
|
horOrVert,
|
||||||
|
}: {
|
||||||
|
horOrVert: 'setHorzDistance' | 'setVertDistance'
|
||||||
|
}) => {
|
||||||
|
const { guiMode, selectionRanges, ast, programMemory, updateAst } = useStore(
|
||||||
|
(s) => ({
|
||||||
|
guiMode: s.guiMode,
|
||||||
|
ast: s.ast,
|
||||||
|
updateAst: s.updateAst,
|
||||||
|
selectionRanges: s.selectionRanges,
|
||||||
|
programMemory: s.programMemory,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
const [enable, setEnable] = useState(false)
|
||||||
|
const [transformInfos, setTransformInfos] = useState<TransformInfo[]>()
|
||||||
|
useEffect(() => {
|
||||||
|
if (!ast) return
|
||||||
|
const paths = selectionRanges.map((selectionRange) =>
|
||||||
|
getNodePathFromSourceRange(ast, selectionRange)
|
||||||
|
)
|
||||||
|
const nodes = paths.map(
|
||||||
|
(pathToNode) => getNodeFromPath<Value>(ast, pathToNode).node
|
||||||
|
)
|
||||||
|
const varDecs = paths.map(
|
||||||
|
(pathToNode) =>
|
||||||
|
getNodeFromPath<VariableDeclarator>(
|
||||||
|
ast,
|
||||||
|
pathToNode,
|
||||||
|
'VariableDeclarator'
|
||||||
|
)?.node
|
||||||
|
)
|
||||||
|
const primaryLine = varDecs[0]
|
||||||
|
const secondaryVarDecs = varDecs.slice(1)
|
||||||
|
const isOthersLinkedToPrimary = secondaryVarDecs.every((secondary) =>
|
||||||
|
isSketchVariablesLinked(secondary, primaryLine, ast)
|
||||||
|
)
|
||||||
|
const isAllTooltips = nodes.every(
|
||||||
|
(node) =>
|
||||||
|
node?.type === 'CallExpression' &&
|
||||||
|
toolTips.includes(node.callee.name as any)
|
||||||
|
)
|
||||||
|
|
||||||
|
const theTransforms = getTransformInfos(
|
||||||
|
selectionRanges.slice(1),
|
||||||
|
ast,
|
||||||
|
horOrVert
|
||||||
|
)
|
||||||
|
setTransformInfos(theTransforms)
|
||||||
|
|
||||||
|
const _enableEqual =
|
||||||
|
secondaryVarDecs.length === 1 &&
|
||||||
|
isAllTooltips &&
|
||||||
|
isOthersLinkedToPrimary &&
|
||||||
|
theTransforms.every(Boolean)
|
||||||
|
setEnable(_enableEqual)
|
||||||
|
}, [guiMode, selectionRanges])
|
||||||
|
if (guiMode.mode !== 'sketch') return null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
onClick={() =>
|
||||||
|
transformInfos &&
|
||||||
|
ast &&
|
||||||
|
updateAst(
|
||||||
|
transformAstForSketchLines({
|
||||||
|
ast,
|
||||||
|
selectionRanges,
|
||||||
|
transformInfos,
|
||||||
|
programMemory,
|
||||||
|
})?.modifiedAst
|
||||||
|
)
|
||||||
|
}
|
||||||
|
className={`border m-1 px-1 rounded ${
|
||||||
|
enable ? 'bg-gray-50 text-gray-800' : 'bg-gray-200 text-gray-400'
|
||||||
|
}`}
|
||||||
|
disabled={!enable}
|
||||||
|
title="yo dawg"
|
||||||
|
>
|
||||||
|
{horOrVert}
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
}
|
@ -89,12 +89,11 @@ export function createFirstArg(
|
|||||||
|
|
||||||
export const lineTo: SketchLineHelper = {
|
export const lineTo: SketchLineHelper = {
|
||||||
fn: (
|
fn: (
|
||||||
{ sourceRange, programMemory },
|
{ sourceRange },
|
||||||
data:
|
data:
|
||||||
| [number, number]
|
| [number, number]
|
||||||
| {
|
| {
|
||||||
to: [number, number]
|
to: [number, number]
|
||||||
// name?: string
|
|
||||||
tag?: string
|
tag?: string
|
||||||
},
|
},
|
||||||
previousSketch: SketchGroup
|
previousSketch: SketchGroup
|
||||||
@ -135,18 +134,38 @@ export const lineTo: SketchLineHelper = {
|
|||||||
value: [...sketchGroup.value, currentPath],
|
value: [...sketchGroup.value, currentPath],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
add: ({ node, pathToNode, to }) => {
|
add: ({
|
||||||
|
node,
|
||||||
|
pathToNode,
|
||||||
|
to,
|
||||||
|
createCallback,
|
||||||
|
replaceExisting,
|
||||||
|
referencedSegment,
|
||||||
|
}) => {
|
||||||
const _node = { ...node }
|
const _node = { ...node }
|
||||||
const { node: pipe } = getNodeFromPath<PipeExpression>(
|
const { node: pipe } = getNodeFromPath<PipeExpression>(
|
||||||
_node,
|
_node,
|
||||||
pathToNode,
|
pathToNode,
|
||||||
'PipeExpression'
|
'PipeExpression'
|
||||||
)
|
)
|
||||||
const newLine = createCallExpression('lineTo', [
|
|
||||||
createArrayExpression([createLiteral(to[0]), createLiteral(to[1])]),
|
const newVals: [Value, Value] = [
|
||||||
|
createLiteral(roundOff(to[0], 2)),
|
||||||
|
createLiteral(roundOff(to[1], 2)),
|
||||||
|
]
|
||||||
|
|
||||||
|
const newLine = createCallback
|
||||||
|
? createCallback(newVals, referencedSegment)
|
||||||
|
: createCallExpression('lineTo', [
|
||||||
|
createArrayExpression(newVals),
|
||||||
createPipeSubstitution(),
|
createPipeSubstitution(),
|
||||||
])
|
])
|
||||||
|
const callIndex = getLastIndex(pathToNode)
|
||||||
|
if (replaceExisting) {
|
||||||
|
pipe.body[callIndex] = newLine
|
||||||
|
} else {
|
||||||
pipe.body = [...pipe.body, newLine]
|
pipe.body = [...pipe.body, newLine]
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
modifiedAst: _node,
|
modifiedAst: _node,
|
||||||
pathToNode,
|
pathToNode,
|
||||||
@ -237,7 +256,6 @@ export const line: SketchLineHelper = {
|
|||||||
pathToNode,
|
pathToNode,
|
||||||
'PipeExpression'
|
'PipeExpression'
|
||||||
)
|
)
|
||||||
if (!from) throw new Error('no from') // todo #29 remove
|
|
||||||
const { node: varDec } = getNodeFromPath<VariableDeclarator>(
|
const { node: varDec } = getNodeFromPath<VariableDeclarator>(
|
||||||
_node,
|
_node,
|
||||||
pathToNode,
|
pathToNode,
|
||||||
@ -431,7 +449,6 @@ export const xLine: SketchLineHelper = {
|
|||||||
add: ({ node, pathToNode, to, from, replaceExisting, createCallback }) => {
|
add: ({ node, pathToNode, to, from, replaceExisting, createCallback }) => {
|
||||||
const _node = { ...node }
|
const _node = { ...node }
|
||||||
const getNode = getNodeFromPathCurry(_node, pathToNode)
|
const getNode = getNodeFromPathCurry(_node, pathToNode)
|
||||||
if (!from) throw new Error('no from') // todo #29 remove
|
|
||||||
const { node: pipe } = getNode<PipeExpression>('PipeExpression')
|
const { node: pipe } = getNode<PipeExpression>('PipeExpression')
|
||||||
|
|
||||||
const newVal = createLiteral(roundOff(to[0] - from[0], 2))
|
const newVal = createLiteral(roundOff(to[0] - from[0], 2))
|
||||||
@ -487,7 +504,6 @@ export const yLine: SketchLineHelper = {
|
|||||||
add: ({ node, pathToNode, to, from, replaceExisting, createCallback }) => {
|
add: ({ node, pathToNode, to, from, replaceExisting, createCallback }) => {
|
||||||
const _node = { ...node }
|
const _node = { ...node }
|
||||||
const getNode = getNodeFromPathCurry(_node, pathToNode)
|
const getNode = getNodeFromPathCurry(_node, pathToNode)
|
||||||
if (!from) throw new Error('no from') // todo #29 remove
|
|
||||||
const { node: pipe } = getNode<PipeExpression>('PipeExpression')
|
const { node: pipe } = getNode<PipeExpression>('PipeExpression')
|
||||||
const newVal = createLiteral(roundOff(to[1] - from[1], 2))
|
const newVal = createLiteral(roundOff(to[1] - from[1], 2))
|
||||||
const newLine = createCallback
|
const newLine = createCallback
|
||||||
@ -577,7 +593,6 @@ export const angledLine: SketchLineHelper = {
|
|||||||
const getNode = getNodeFromPathCurry(_node, pathToNode)
|
const getNode = getNodeFromPathCurry(_node, pathToNode)
|
||||||
const { node: pipe } = getNode<PipeExpression>('PipeExpression')
|
const { node: pipe } = getNode<PipeExpression>('PipeExpression')
|
||||||
|
|
||||||
if (!from) throw new Error('no from') // todo #29 remove
|
|
||||||
const newAngleVal = createLiteral(roundOff(getAngle(from, to), 0))
|
const newAngleVal = createLiteral(roundOff(getAngle(from, to), 0))
|
||||||
const newLengthVal = createLiteral(roundOff(getLength(from, to), 2))
|
const newLengthVal = createLiteral(roundOff(getLength(from, to), 2))
|
||||||
const newLine = createCallback
|
const newLine = createCallback
|
||||||
@ -668,7 +683,6 @@ export const angledLineOfXLength: SketchLineHelper = {
|
|||||||
const variableName = varDec.id.name
|
const variableName = varDec.id.name
|
||||||
const sketch = previousProgramMemory?.root?.[variableName]
|
const sketch = previousProgramMemory?.root?.[variableName]
|
||||||
if (sketch.type !== 'sketchGroup') throw new Error('not a sketchGroup')
|
if (sketch.type !== 'sketchGroup') throw new Error('not a sketchGroup')
|
||||||
if (!from) throw new Error('no from') // todo #29 remove
|
|
||||||
const angle = createLiteral(roundOff(getAngle(from, to), 0))
|
const angle = createLiteral(roundOff(getAngle(from, to), 0))
|
||||||
const xLength = createLiteral(roundOff(Math.abs(from[0] - to[0]), 2) || 0.1)
|
const xLength = createLiteral(roundOff(Math.abs(from[0] - to[0]), 2) || 0.1)
|
||||||
const newLine = createCallback
|
const newLine = createCallback
|
||||||
@ -762,7 +776,6 @@ export const angledLineOfYLength: SketchLineHelper = {
|
|||||||
const variableName = varDec.id.name
|
const variableName = varDec.id.name
|
||||||
const sketch = previousProgramMemory?.root?.[variableName]
|
const sketch = previousProgramMemory?.root?.[variableName]
|
||||||
if (sketch.type !== 'sketchGroup') throw new Error('not a sketchGroup')
|
if (sketch.type !== 'sketchGroup') throw new Error('not a sketchGroup')
|
||||||
if (!from) throw new Error('no from') // todo #29 remove
|
|
||||||
|
|
||||||
const angle = createLiteral(roundOff(getAngle(from, to), 0))
|
const angle = createLiteral(roundOff(getAngle(from, to), 0))
|
||||||
const yLength = createLiteral(roundOff(Math.abs(from[1] - to[1]), 2) || 0.1)
|
const yLength = createLiteral(roundOff(Math.abs(from[1] - to[1]), 2) || 0.1)
|
||||||
@ -848,7 +861,6 @@ export const angledLineToX: SketchLineHelper = {
|
|||||||
pathToNode,
|
pathToNode,
|
||||||
'PipeExpression'
|
'PipeExpression'
|
||||||
)
|
)
|
||||||
if (!from) throw new Error('no from') // todo #29 remove
|
|
||||||
const angle = createLiteral(roundOff(getAngle(from, to), 0))
|
const angle = createLiteral(roundOff(getAngle(from, to), 0))
|
||||||
const xArg = createLiteral(roundOff(to[0], 2))
|
const xArg = createLiteral(roundOff(to[0], 2))
|
||||||
const newLine = createCallback
|
const newLine = createCallback
|
||||||
@ -930,7 +942,6 @@ export const angledLineToY: SketchLineHelper = {
|
|||||||
pathToNode,
|
pathToNode,
|
||||||
'PipeExpression'
|
'PipeExpression'
|
||||||
)
|
)
|
||||||
if (!from) throw new Error('no from') // todo #29 remove
|
|
||||||
const angle = createLiteral(roundOff(getAngle(from, to), 0))
|
const angle = createLiteral(roundOff(getAngle(from, to), 0))
|
||||||
const yArg = createLiteral(roundOff(to[1], 2))
|
const yArg = createLiteral(roundOff(to[1], 2))
|
||||||
const newLine = createCallback
|
const newLine = createCallback
|
||||||
@ -1067,6 +1078,7 @@ export function replaceSketchLine({
|
|||||||
to,
|
to,
|
||||||
from,
|
from,
|
||||||
createCallback,
|
createCallback,
|
||||||
|
referencedSegment,
|
||||||
}: {
|
}: {
|
||||||
node: Program
|
node: Program
|
||||||
programMemory: ProgramMemory
|
programMemory: ProgramMemory
|
||||||
@ -1075,6 +1087,7 @@ export function replaceSketchLine({
|
|||||||
to: [number, number]
|
to: [number, number]
|
||||||
from: [number, number]
|
from: [number, number]
|
||||||
createCallback: TransformCallback
|
createCallback: TransformCallback
|
||||||
|
referencedSegment?: Path
|
||||||
}): { modifiedAst: Program } {
|
}): { modifiedAst: Program } {
|
||||||
if (!toolTips.includes(fnName)) throw new Error('not a tooltip')
|
if (!toolTips.includes(fnName)) throw new Error('not a tooltip')
|
||||||
const _node = { ...node }
|
const _node = { ...node }
|
||||||
@ -1085,6 +1098,7 @@ export function replaceSketchLine({
|
|||||||
node: _node,
|
node: _node,
|
||||||
previousProgramMemory: programMemory,
|
previousProgramMemory: programMemory,
|
||||||
pathToNode: thePath,
|
pathToNode: thePath,
|
||||||
|
referencedSegment,
|
||||||
to,
|
to,
|
||||||
from,
|
from,
|
||||||
replaceExisting: true,
|
replaceExisting: true,
|
||||||
|
@ -33,6 +33,28 @@ export const segLen: InternalFn = (
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function segEndFactory(which: 'x' | 'y'): InternalFn {
|
||||||
|
return (_, segName: string, sketchGroup: SketchGroup): number => {
|
||||||
|
const line = sketchGroup?.value.find((seg) => seg.name === segName)
|
||||||
|
// maybe this should throw, but the language doesn't have a way to handle errors yet
|
||||||
|
if (!line) return 0
|
||||||
|
return which === 'x' ? line.to[0] : line.to[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const segEndX: InternalFn = segEndFactory('x')
|
||||||
|
export const segEndY: InternalFn = segEndFactory('y')
|
||||||
|
|
||||||
|
function lastSegFactory(which: 'x' | 'y'): InternalFn {
|
||||||
|
return (_, sketchGroup: SketchGroup): number => {
|
||||||
|
const lastLine = sketchGroup?.value[sketchGroup.value.length - 1]
|
||||||
|
return which === 'x' ? lastLine.to[0] : lastLine.to[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const lastSegX: InternalFn = lastSegFactory('x')
|
||||||
|
export const lastSegY: InternalFn = lastSegFactory('y')
|
||||||
|
|
||||||
function angleToMatchLengthFactory(which: 'x' | 'y'): InternalFn {
|
function angleToMatchLengthFactory(which: 'x' | 'y'): InternalFn {
|
||||||
return (_, segName: string, to: number, sketchGroup: SketchGroup): number => {
|
return (_, segName: string, to: number, sketchGroup: SketchGroup): number => {
|
||||||
const isX = which === 'x'
|
const isX = which === 'x'
|
||||||
|
@ -5,9 +5,10 @@ import {
|
|||||||
getTransformInfos,
|
getTransformInfos,
|
||||||
transformAstForSketchLines,
|
transformAstForSketchLines,
|
||||||
transformAstForHorzVert,
|
transformAstForHorzVert,
|
||||||
|
ConstraintType,
|
||||||
} from './sketchcombos'
|
} from './sketchcombos'
|
||||||
import { initPromise } from '../rust'
|
import { initPromise } from '../rust'
|
||||||
import { Ranges, TooTip } from '../../useStore'
|
import { TooTip } from '../../useStore'
|
||||||
import { executor } from '../../lang/executor'
|
import { executor } from '../../lang/executor'
|
||||||
import { recast } from '../../lang/recast'
|
import { recast } from '../../lang/recast'
|
||||||
|
|
||||||
@ -242,14 +243,6 @@ const part001 = startSketchAt([0, 0])
|
|||||||
|> angledLineToY([301, myVar], %) // select for vertical constraint 10
|
|> angledLineToY([301, myVar], %) // select for vertical constraint 10
|
||||||
show(part001)`
|
show(part001)`
|
||||||
it('It should transform horizontal lines the ast', () => {
|
it('It should transform horizontal lines the ast', () => {
|
||||||
// const inputScript = `const myVar = 2
|
|
||||||
// const part001 = startSketchAt([0, 0])
|
|
||||||
// |> lineTo([1, 1], %)
|
|
||||||
// |> line([-6.28, 1.4], %) // select for horizontal constraint 1
|
|
||||||
// |> line([-1.07, myVar], %) // select for vertical constraint 1
|
|
||||||
// |> line([myVar, 4.32], %) // select for horizontal constraint 2
|
|
||||||
// |> line([6.35, -1.12], %) // select for vertical constraint 2
|
|
||||||
// show(part001)`
|
|
||||||
const expectModifiedScript = `const myVar = 2
|
const expectModifiedScript = `const myVar = 2
|
||||||
const myVar2 = 12
|
const myVar2 = 12
|
||||||
const myVar3 = -10
|
const myVar3 = -10
|
||||||
@ -348,3 +341,89 @@ show(part001)`
|
|||||||
expect(newCode).toBe(expectModifiedScript)
|
expect(newCode).toBe(expectModifiedScript)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('testing transformAstForSketchLines for vertical and horizontal distance constraints', () => {
|
||||||
|
describe('testing setHorzDistance for line', () => {
|
||||||
|
const inputScript = `const myVar = 1
|
||||||
|
const part001 = startSketchAt([0, 0])
|
||||||
|
|> line([0.31, 1.67], %) // base selection
|
||||||
|
|> line([0.45, 1.46], %)
|
||||||
|
|> line([0.45, 1.46], %) // free
|
||||||
|
|> line([myVar, 0.01], %) // xRelative
|
||||||
|
|> line([0.7, myVar], %) // yRelative
|
||||||
|
show(part001)`
|
||||||
|
it('testing for free to horizontal and vertical distance', () => {
|
||||||
|
const expectedHorizontalCode = helperThing(
|
||||||
|
inputScript,
|
||||||
|
['// base selection', '// free'],
|
||||||
|
'setHorzDistance'
|
||||||
|
)
|
||||||
|
const expectedVerticalCode = helperThing(
|
||||||
|
inputScript,
|
||||||
|
['// base selection', '// free'],
|
||||||
|
'setVertDistance'
|
||||||
|
)
|
||||||
|
expect(expectedHorizontalCode).toContain(
|
||||||
|
`lineTo([segEndX('seg01', %) + 1.21, 4.59], %) // free`
|
||||||
|
)
|
||||||
|
expect(expectedVerticalCode).toContain(
|
||||||
|
`lineTo([1.21, segEndY('seg01', %) + 4.59], %) // free`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
it('testing for xRelative to vertical distance', () => {
|
||||||
|
const expectedCode = helperThing(
|
||||||
|
inputScript,
|
||||||
|
['// base selection', '// xRelative'],
|
||||||
|
'setVertDistance'
|
||||||
|
)
|
||||||
|
expect(expectedCode).toContain(`|> lineTo([
|
||||||
|
lastSegX(%) + myVar,
|
||||||
|
segEndY('seg01', %) + 4.6
|
||||||
|
], %) // xRelative`)
|
||||||
|
})
|
||||||
|
it('testing for yRelative to horizontal distance', () => {
|
||||||
|
const expectedCode = helperThing(
|
||||||
|
inputScript,
|
||||||
|
['// base selection', '// yRelative'],
|
||||||
|
'setHorzDistance'
|
||||||
|
)
|
||||||
|
expect(expectedCode).toContain(`|> lineTo([
|
||||||
|
segEndX('seg01', %) + 2.91,
|
||||||
|
lastSegY(%) + myVar
|
||||||
|
], %) // yRelative`)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
function helperThing(
|
||||||
|
inputScript: string,
|
||||||
|
linesOfInterest: string[],
|
||||||
|
constraint: ConstraintType
|
||||||
|
): string {
|
||||||
|
const ast = abstractSyntaxTree(lexer(inputScript))
|
||||||
|
const selectionRanges = inputScript
|
||||||
|
.split('\n')
|
||||||
|
.filter((ln) =>
|
||||||
|
linesOfInterest.some((lineOfInterest) => ln.includes(lineOfInterest))
|
||||||
|
)
|
||||||
|
.map((ln) => {
|
||||||
|
const comment = ln.split('//')[1]
|
||||||
|
const start = inputScript.indexOf('//' + comment) - 7
|
||||||
|
return [start, start]
|
||||||
|
}) as [number, number][]
|
||||||
|
|
||||||
|
const programMemory = executor(ast)
|
||||||
|
const transformInfos = getTransformInfos(
|
||||||
|
selectionRanges.slice(1),
|
||||||
|
ast,
|
||||||
|
constraint
|
||||||
|
)
|
||||||
|
|
||||||
|
const newAst = transformAstForSketchLines({
|
||||||
|
ast,
|
||||||
|
selectionRanges,
|
||||||
|
transformInfos,
|
||||||
|
programMemory,
|
||||||
|
})?.modifiedAst
|
||||||
|
return recast(newAst)
|
||||||
|
}
|
||||||
|
@ -21,8 +21,9 @@ import {
|
|||||||
giveSketchFnCallTag,
|
giveSketchFnCallTag,
|
||||||
} from '../modifyAst'
|
} from '../modifyAst'
|
||||||
import { createFirstArg, getFirstArg, replaceSketchLine } from './sketch'
|
import { createFirstArg, getFirstArg, replaceSketchLine } from './sketch'
|
||||||
import { ProgramMemory } from '../executor'
|
import { Path, ProgramMemory } from '../executor'
|
||||||
import { getSketchSegmentIndexFromSourceRange } from './sketchConstraints'
|
import { getSketchSegmentIndexFromSourceRange } from './sketchConstraints'
|
||||||
|
import { roundOff } from '../../lib/utils'
|
||||||
|
|
||||||
type LineInputsType =
|
type LineInputsType =
|
||||||
| 'xAbsolute'
|
| 'xAbsolute'
|
||||||
@ -37,6 +38,8 @@ export type ConstraintType =
|
|||||||
| 'vertical'
|
| 'vertical'
|
||||||
| 'horizontal'
|
| 'horizontal'
|
||||||
| 'equalangle'
|
| 'equalangle'
|
||||||
|
| 'setHorzDistance'
|
||||||
|
| 'setVertDistance'
|
||||||
|
|
||||||
function createCallWrapper(
|
function createCallWrapper(
|
||||||
a: TooTip,
|
a: TooTip,
|
||||||
@ -54,7 +57,8 @@ export function replaceSketchCall(
|
|||||||
ast: Program,
|
ast: Program,
|
||||||
range: Range,
|
range: Range,
|
||||||
transformTo: TooTip,
|
transformTo: TooTip,
|
||||||
createCallback: TransformCallback
|
createCallback: TransformCallback,
|
||||||
|
referenceSegName: string
|
||||||
): { modifiedAst: Program } {
|
): { modifiedAst: Program } {
|
||||||
const path = getNodePathFromSourceRange(ast, range)
|
const path = getNodePathFromSourceRange(ast, range)
|
||||||
const getNode = getNodeFromPathCurry(ast, path)
|
const getNode = getNodeFromPathCurry(ast, path)
|
||||||
@ -65,11 +69,15 @@ export function replaceSketchCall(
|
|||||||
if (!sketchGroup || sketchGroup.type !== 'sketchGroup')
|
if (!sketchGroup || sketchGroup.type !== 'sketchGroup')
|
||||||
throw new Error('not a sketch group')
|
throw new Error('not a sketch group')
|
||||||
const seg = getSketchSegmentIndexFromSourceRange(sketchGroup, range)
|
const seg = getSketchSegmentIndexFromSourceRange(sketchGroup, range)
|
||||||
|
const referencedSegment = sketchGroup.value.find(
|
||||||
|
(path) => path.name === referenceSegName
|
||||||
|
)
|
||||||
const { to, from } = seg
|
const { to, from } = seg
|
||||||
const { modifiedAst } = replaceSketchLine({
|
const { modifiedAst } = replaceSketchLine({
|
||||||
node: ast,
|
node: ast,
|
||||||
programMemory,
|
programMemory,
|
||||||
sourceRange: range,
|
sourceRange: range,
|
||||||
|
referencedSegment,
|
||||||
fnName: transformTo || (callExp.callee.name as TooTip),
|
fnName: transformTo || (callExp.callee.name as TooTip),
|
||||||
to,
|
to,
|
||||||
from,
|
from,
|
||||||
@ -85,7 +93,7 @@ export type TransformInfo = {
|
|||||||
varValB: Value // y / length or x y for angledLineOfXlength etc
|
varValB: Value // y / length or x y for angledLineOfXlength etc
|
||||||
referenceSegName: string
|
referenceSegName: string
|
||||||
tag?: Value
|
tag?: Value
|
||||||
}) => (args: [Value, Value]) => Value
|
}) => (args: [Value, Value], referencedSegment?: Path) => Value
|
||||||
}
|
}
|
||||||
|
|
||||||
type TransformMap = {
|
type TransformMap = {
|
||||||
@ -163,6 +171,57 @@ const getAngleLengthSign = (arg: Value, legAngleVal: BinaryPart) => {
|
|||||||
return normalisedAngle > 90 ? createUnaryExpression(legAngleVal) : legAngleVal
|
return normalisedAngle > 90 ? createUnaryExpression(legAngleVal) : legAngleVal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const setHorzVertDistanceCreateNode =
|
||||||
|
(isX = true): TransformInfo['createNode'] =>
|
||||||
|
({ referenceSegName, tag }) => {
|
||||||
|
return (args, referencedSegment) => {
|
||||||
|
const makeBinExp = (index: 0 | 1) => {
|
||||||
|
const arg = getArgLiteralVal(args?.[index])
|
||||||
|
return createBinaryExpression([
|
||||||
|
createSegEnd(referenceSegName, isX),
|
||||||
|
'+',
|
||||||
|
createLiteral(
|
||||||
|
roundOff(arg - (referencedSegment?.to?.[index] || 0), 2)
|
||||||
|
),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
return createCallWrapper(
|
||||||
|
'lineTo',
|
||||||
|
isX ? [makeBinExp(0), args[1]] : [args[0], makeBinExp(1)],
|
||||||
|
tag
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const setHorzVertDistanceConstraintLineCreateNode =
|
||||||
|
(isX: boolean): TransformInfo['createNode'] =>
|
||||||
|
({ referenceSegName, tag, varValA, varValB }) => {
|
||||||
|
const varVal = (isX ? varValB : varValA) as BinaryPart
|
||||||
|
const varValBinExp = createBinaryExpression([
|
||||||
|
createLastSeg(!isX),
|
||||||
|
'+',
|
||||||
|
varVal,
|
||||||
|
])
|
||||||
|
|
||||||
|
return (args, referencedSegment) => {
|
||||||
|
const makeBinExp = (index: 0 | 1) => {
|
||||||
|
const arg = getArgLiteralVal(args?.[index])
|
||||||
|
return createBinaryExpression([
|
||||||
|
createSegEnd(referenceSegName, isX),
|
||||||
|
'+',
|
||||||
|
createLiteral(
|
||||||
|
roundOff(arg - (referencedSegment?.to?.[index] || 0), 2)
|
||||||
|
),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
return createCallWrapper(
|
||||||
|
'lineTo',
|
||||||
|
isX ? [makeBinExp(0), varValBinExp] : [varValBinExp, makeBinExp(1)],
|
||||||
|
tag
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const transformMap: TransformMap = {
|
const transformMap: TransformMap = {
|
||||||
line: {
|
line: {
|
||||||
xRelative: {
|
xRelative: {
|
||||||
@ -188,6 +247,10 @@ const transformMap: TransformMap = {
|
|||||||
() =>
|
() =>
|
||||||
createCallWrapper('xLine', varValA, tag),
|
createCallWrapper('xLine', varValA, tag),
|
||||||
},
|
},
|
||||||
|
setVertDistance: {
|
||||||
|
tooltip: 'lineTo',
|
||||||
|
createNode: setHorzVertDistanceConstraintLineCreateNode(false),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
yRelative: {
|
yRelative: {
|
||||||
equalLength: {
|
equalLength: {
|
||||||
@ -212,6 +275,10 @@ const transformMap: TransformMap = {
|
|||||||
() =>
|
() =>
|
||||||
createCallWrapper('yLine', varValB, tag),
|
createCallWrapper('yLine', varValB, tag),
|
||||||
},
|
},
|
||||||
|
setHorzDistance: {
|
||||||
|
tooltip: 'lineTo',
|
||||||
|
createNode: setHorzVertDistanceConstraintLineCreateNode(true),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
free: {
|
free: {
|
||||||
equalLength: {
|
equalLength: {
|
||||||
@ -232,6 +299,14 @@ const transformMap: TransformMap = {
|
|||||||
(args) =>
|
(args) =>
|
||||||
createCallWrapper('yLine', args[1], tag),
|
createCallWrapper('yLine', args[1], tag),
|
||||||
},
|
},
|
||||||
|
setHorzDistance: {
|
||||||
|
tooltip: 'lineTo',
|
||||||
|
createNode: setHorzVertDistanceCreateNode(true),
|
||||||
|
},
|
||||||
|
setVertDistance: {
|
||||||
|
tooltip: 'lineTo',
|
||||||
|
createNode: setHorzVertDistanceCreateNode(false),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
lineTo: {
|
lineTo: {
|
||||||
@ -792,7 +867,8 @@ export function transformAstForSketchLines({
|
|||||||
referenceSegName: tag,
|
referenceSegName: tag,
|
||||||
varValA,
|
varValA,
|
||||||
varValB,
|
varValB,
|
||||||
})
|
}),
|
||||||
|
tag
|
||||||
)
|
)
|
||||||
node = modifiedAst
|
node = modifiedAst
|
||||||
})
|
})
|
||||||
@ -837,7 +913,8 @@ export function transformAstForHorzVert({
|
|||||||
varValA,
|
varValA,
|
||||||
varValB,
|
varValB,
|
||||||
tag,
|
tag,
|
||||||
})
|
}),
|
||||||
|
tag?.type === 'Literal' ? String(tag.value) : ''
|
||||||
)
|
)
|
||||||
node = modifiedAst
|
node = modifiedAst
|
||||||
})
|
})
|
||||||
@ -850,3 +927,20 @@ function createSegLen(referenceSegName: string): Value {
|
|||||||
createPipeSubstitution(),
|
createPipeSubstitution(),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createSegEnd(referenceSegName: string, isX: boolean): CallExpression {
|
||||||
|
return createCallExpression(isX ? 'segEndX' : 'segEndY', [
|
||||||
|
createLiteral(referenceSegName),
|
||||||
|
createPipeSubstitution(),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
function createLastSeg(isX: boolean): CallExpression {
|
||||||
|
return createCallExpression(isX ? 'lastSegX' : 'lastSegY', [
|
||||||
|
createPipeSubstitution(),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
function getArgLiteralVal(arg: Value): number {
|
||||||
|
return arg?.type === 'Literal' ? Number(arg.value) : 0
|
||||||
|
}
|
||||||
|
@ -17,6 +17,10 @@ import {
|
|||||||
segLen,
|
segLen,
|
||||||
angleToMatchLengthX,
|
angleToMatchLengthX,
|
||||||
angleToMatchLengthY,
|
angleToMatchLengthY,
|
||||||
|
segEndX,
|
||||||
|
segEndY,
|
||||||
|
lastSegX,
|
||||||
|
lastSegY,
|
||||||
} from './sketchConstraints'
|
} from './sketchConstraints'
|
||||||
import { extrude, getExtrudeWallTransform } from './extrude'
|
import { extrude, getExtrudeWallTransform } from './extrude'
|
||||||
import { Quaternion, Vector3 } from 'three'
|
import { Quaternion, Vector3 } from 'three'
|
||||||
@ -100,6 +104,10 @@ export const internalFns: { [key in InternalFnNames]: InternalFn } = {
|
|||||||
legLen,
|
legLen,
|
||||||
legAngX,
|
legAngX,
|
||||||
legAngY,
|
legAngY,
|
||||||
|
segEndX,
|
||||||
|
segEndY,
|
||||||
|
lastSegX,
|
||||||
|
lastSegY,
|
||||||
segLen,
|
segLen,
|
||||||
angleToMatchLengthX,
|
angleToMatchLengthX,
|
||||||
angleToMatchLengthY,
|
angleToMatchLengthY,
|
||||||
|
@ -24,6 +24,10 @@ export type InternalFnNames =
|
|||||||
| 'legLen'
|
| 'legLen'
|
||||||
| 'legAngX'
|
| 'legAngX'
|
||||||
| 'legAngY'
|
| 'legAngY'
|
||||||
|
| 'segEndX'
|
||||||
|
| 'segEndY'
|
||||||
|
| 'lastSegX'
|
||||||
|
| 'lastSegY'
|
||||||
| 'segLen'
|
| 'segLen'
|
||||||
| 'angleToMatchLengthX'
|
| 'angleToMatchLengthX'
|
||||||
| 'angleToMatchLengthY'
|
| 'angleToMatchLengthY'
|
||||||
@ -52,7 +56,8 @@ export interface ModifyAstBase {
|
|||||||
|
|
||||||
interface addCall extends ModifyAstBase {
|
interface addCall extends ModifyAstBase {
|
||||||
to: [number, number]
|
to: [number, number]
|
||||||
from?: [number, number]
|
from: [number, number]
|
||||||
|
referencedSegment?: Path
|
||||||
replaceExisting?: boolean
|
replaceExisting?: boolean
|
||||||
createCallback?: TransformCallback // TODO: #29 probably should not be optional
|
createCallback?: TransformCallback // TODO: #29 probably should not be optional
|
||||||
}
|
}
|
||||||
@ -62,7 +67,10 @@ interface updateArgs extends ModifyAstBase {
|
|||||||
to: [number, number]
|
to: [number, number]
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TransformCallback = (args: [Value, Value]) => Value
|
export type TransformCallback = (
|
||||||
|
args: [Value, Value],
|
||||||
|
referencedSegment?: Path
|
||||||
|
) => Value
|
||||||
|
|
||||||
export type SketchCallTransfromMap = {
|
export type SketchCallTransfromMap = {
|
||||||
[key in TooTip]: TransformCallback
|
[key in TooTip]: TransformCallback
|
||||||
|
Reference in New Issue
Block a user