Add intersect constraint UI (#71)

* Add intersect constraint UI

* add more combos for intersect constraint
This commit is contained in:
Kurt Hutten
2023-03-19 18:46:39 +11:00
committed by GitHub
parent 0995780abb
commit 22c356a841
9 changed files with 439 additions and 78 deletions

View File

@ -22,7 +22,7 @@
"react-json-view": "^1.21.3", "react-json-view": "^1.21.3",
"react-modal-promise": "^1.0.2", "react-modal-promise": "^1.0.2",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"sketch-helpers": "^0.0.1", "sketch-helpers": "^0.0.2",
"swr": "^2.0.4", "swr": "^2.0.4",
"three": "^0.146.0", "three": "^0.146.0",
"typescript": "^4.4.2", "typescript": "^4.4.2",

View File

@ -4,6 +4,7 @@ import { getNodePathFromSourceRange } from './lang/queryAst'
import { HorzVert } from './components/Toolbar/HorzVert' import { HorzVert } from './components/Toolbar/HorzVert'
import { EqualLength } from './components/Toolbar/EqualLength' import { EqualLength } from './components/Toolbar/EqualLength'
import { EqualAngle } from './components/Toolbar/EqualAngle' import { EqualAngle } from './components/Toolbar/EqualAngle'
import { Intersect } from './components/Toolbar/Intersect'
import { SetHorzDistance } from './components/Toolbar/SetHorzDistance' import { SetHorzDistance } from './components/Toolbar/SetHorzDistance'
import { SetAngleLength } from './components/Toolbar/SetAngleLength' import { SetAngleLength } from './components/Toolbar/SetAngleLength'
@ -123,38 +124,42 @@ export const Toolbar = () => {
Exit sketch Exit sketch
</button> </button>
)} )}
{toolTips.map((sketchFnName) => { {toolTips
if ( .filter(
guiMode.mode !== 'sketch' || (sketchFnName) => !['angledLineThatIntersects'].includes(sketchFnName)
!('isTooltip' in guiMode || guiMode.sketchMode === 'sketchEdit')
) )
return null .map((sketchFnName) => {
return ( if (
<button guiMode.mode !== 'sketch' ||
key={sketchFnName} !('isTooltip' in guiMode || guiMode.sketchMode === 'sketchEdit')
className={`border m-0.5 px-0.5 rounded text-xs ${ )
guiMode.sketchMode === sketchFnName && 'bg-gray-400' return null
}`} return (
onClick={() => <button
setGuiMode({ key={sketchFnName}
...guiMode, className={`border m-0.5 px-0.5 rounded text-xs ${
...(guiMode.sketchMode === sketchFnName guiMode.sketchMode === sketchFnName && 'bg-gray-400'
? { }`}
sketchMode: 'sketchEdit', onClick={() =>
// todo: ...guiMod is adding isTooltip: true, will probably just fix with xstate migtaion setGuiMode({
} ...guiMode,
: { ...(guiMode.sketchMode === sketchFnName
sketchMode: sketchFnName, ? {
isTooltip: true, sketchMode: 'sketchEdit',
}), // todo: ...guiMod is adding isTooltip: true, will probably just fix with xstate migtaion
}) }
} : {
> sketchMode: sketchFnName,
{sketchFnName} isTooltip: true,
{guiMode.sketchMode === sketchFnName && '✅'} }),
</button> })
) }
})} >
{sketchFnName}
{guiMode.sketchMode === sketchFnName && '✅'}
</button>
)
})}
<br></br> <br></br>
<HorzVert horOrVert="horizontal" /> <HorzVert horOrVert="horizontal" />
<HorzVert horOrVert="vertical" /> <HorzVert horOrVert="vertical" />
@ -164,6 +169,7 @@ export const Toolbar = () => {
<SetHorzDistance horOrVert="setVertDistance" /> <SetHorzDistance horOrVert="setVertDistance" />
<SetAngleLength angleOrLength="setAngle" /> <SetAngleLength angleOrLength="setAngle" />
<SetAngleLength angleOrLength="setLength" /> <SetAngleLength angleOrLength="setLength" />
<Intersect />
</div> </div>
) )
} }

View File

@ -0,0 +1,146 @@
import { useState, useEffect } from 'react'
import { create } from 'react-modal-promise'
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,
transformSecondarySketchLinesTagFirst,
getTransformInfos,
} from '../../lang/std/sketchcombos'
import { GetInfoModal } from '../SetHorVertDistanceModal'
import {
createIdentifier,
createVariableDeclaration,
} from '../../lang/modifyAst'
const getModalInfo = create(GetInfoModal as any)
export const Intersect = () => {
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,
'startSketchAt', // TODO probably a better place for this to live
].includes(node.callee.name as any)
)
const theTransforms = getTransformInfos(
selectionRanges.slice(1),
ast,
'intersect'
)
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={async () => {
if (transformInfos && ast) {
const { modifiedAst, tagInfo, valueUsedInTransform } =
transformSecondarySketchLinesTagFirst({
ast: JSON.parse(JSON.stringify(ast)),
selectionRanges,
transformInfos,
programMemory,
})
const {
segName,
value,
valueNode,
variableName,
newVariableInsertIndex,
}: {
segName: string
value: number
valueNode: Value
variableName?: string
newVariableInsertIndex: number
} = await getModalInfo({
segName: tagInfo?.tag,
isSegNameEditable: !tagInfo?.isTagExisting,
value: valueUsedInTransform,
initialVariableName: 'offset',
} as any)
if (segName === tagInfo?.tag && value === valueUsedInTransform) {
updateAst(modifiedAst)
} else {
// transform again but forcing certain values
const { modifiedAst: _modifiedAst } =
transformSecondarySketchLinesTagFirst({
ast,
selectionRanges,
transformInfos,
programMemory,
forceSegName: segName,
forceValueUsedInTransform: variableName
? createIdentifier(variableName)
: valueNode,
})
if (variableName) {
const newBody = [..._modifiedAst.body]
newBody.splice(
newVariableInsertIndex,
0,
createVariableDeclaration(variableName, valueNode)
)
_modifiedAst.body = newBody
}
updateAst(_modifiedAst)
}
}
}}
className={`border m-1 px-1 rounded text-xs ${
enable ? 'bg-gray-50 text-gray-800' : 'bg-gray-200 text-gray-400'
}`}
disabled={!enable}
>
Intersect
</button>
)
}

View File

@ -507,7 +507,8 @@ function executeObjectExpression(
} else if (property.value.type === 'BinaryExpression') { } else if (property.value.type === 'BinaryExpression') {
obj[property.key.name] = getBinaryExpressionResult( obj[property.key.name] = getBinaryExpressionResult(
property.value, property.value,
_programMemory _programMemory,
_pipeInfo
) )
} else if (property.value.type === 'PipeExpression') { } else if (property.value.type === 'PipeExpression') {
obj[property.key.name] = getPipeExpressionResult( obj[property.key.name] = getPipeExpressionResult(

View File

@ -12,6 +12,7 @@ import {
VariableDeclarator, VariableDeclarator,
Value, Value,
Literal, Literal,
VariableDeclaration,
} from '../abstractSyntaxTree' } from '../abstractSyntaxTree'
import { import {
getNodeFromPath, getNodeFromPath,
@ -41,6 +42,10 @@ import {
} from '../modifyAst' } from '../modifyAst'
import { roundOff, getLength, getAngle } from '../../lib/utils' import { roundOff, getLength, getAngle } from '../../lib/utils'
import { getSketchSegmentIndexFromSourceRange } from './sketchConstraints' import { getSketchSegmentIndexFromSourceRange } from './sketchConstraints'
import {
intersectionWithParallelLine,
perpendicularDistance,
} from 'sketch-helpers'
export type Coords2d = [number, number] export type Coords2d = [number, number]
@ -312,7 +317,7 @@ export const line: SketchLineHelper = {
}, },
updateArgs: ({ node, pathToNode, to, from }) => { updateArgs: ({ node, pathToNode, to, from }) => {
const _node = { ...node } const _node = { ...node }
const { node: callExpression, path } = getNodeFromPath<CallExpression>( const { node: callExpression } = getNodeFromPath<CallExpression>(
_node, _node,
pathToNode pathToNode
) )
@ -338,9 +343,9 @@ export const line: SketchLineHelper = {
) { ) {
toProp.value = toArrExp toProp.value = toArrExp
} }
mutateObjExpProp(callExpression.arguments?.[0], toArrExp, 'to')
} else { } else {
mutateArrExp(callExpression.arguments?.[0], toArrExp) || mutateArrExp(callExpression.arguments?.[0], toArrExp)
mutateObjExpProp(callExpression.arguments?.[0], toArrExp, 'to')
} }
return { return {
modifiedAst: _node, modifiedAst: _node,
@ -397,7 +402,7 @@ export const xLineTo: SketchLineHelper = {
pathToNode, pathToNode,
} }
}, },
updateArgs: ({ node, pathToNode, to, from }) => { updateArgs: ({ node, pathToNode, to }) => {
const _node = { ...node } const _node = { ...node }
const { node: callExpression } = getNodeFromPath<CallExpression>( const { node: callExpression } = getNodeFromPath<CallExpression>(
_node, _node,
@ -1084,6 +1089,126 @@ export const angledLineToY: SketchLineHelper = {
addTag: addTagWithTo('angleTo'), addTag: addTagWithTo('angleTo'),
} }
export const angledLineThatIntersects: SketchLineHelper = {
fn: (
{ sourceRange, programMemory },
data: {
angle: number
intersectTag: string
offset?: number
tag?: string
},
previousSketch: SketchGroup
) => {
if (!previousSketch) throw new Error('lineTo must be called after lineTo')
const intersectPath = previousSketch.value.find(
({ name }) => name === data.intersectTag
)
if (!intersectPath) throw new Error('intersectTag must match a line')
const from = getCoordsFromPaths(
previousSketch,
previousSketch.value.length - 1
)
const to = intersectionWithParallelLine({
line1: [intersectPath.from, intersectPath.to],
line1Offset: data.offset || 0,
line2Point: from,
line2Angle: data.angle,
})
return lineTo.fn(
{ sourceRange, programMemory },
{ to, tag: data.tag },
previousSketch
)
},
add: ({
node,
pathToNode,
to,
from,
createCallback,
replaceExisting,
referencedSegment,
}) => {
const _node = { ...node }
const { node: pipe } = getNodeFromPath<PipeExpression>(
_node,
pathToNode,
'PipeExpression'
)
const angle = createLiteral(roundOff(getAngle(from, to), 0))
if (!referencedSegment)
throw new Error('referencedSegment must be provided')
const offset = createLiteral(
roundOff(
perpendicularDistance(
referencedSegment?.from,
referencedSegment?.to,
to
),
2
)
)
if (replaceExisting && createCallback) {
const { callExp, valueUsedInTransform } = createCallback([angle, offset])
const callIndex = getLastIndex(pathToNode)
pipe.body[callIndex] = callExp
return {
modifiedAst: _node,
pathToNode,
valueUsedInTransform,
}
}
throw new Error('not implemented')
},
updateArgs: ({ node, pathToNode, to, from, previousProgramMemory }) => {
const _node = { ...node }
const { node: callExpression, path } = getNodeFromPath<CallExpression>(
_node,
pathToNode
)
const angle = roundOff(getAngle(from, to), 0)
const firstArg = callExpression.arguments?.[0]
const intersectTag =
firstArg.type === 'ObjectExpression'
? firstArg.properties.find((p) => p.key.name === 'intersectTag')
?.value || createLiteral('')
: createLiteral('')
const intersectTagName =
intersectTag.type === 'Literal' ? intersectTag.value : ''
const { node: varDec } = getNodeFromPath<VariableDeclaration>(
_node,
pathToNode,
'VariableDeclaration'
)
const varName = varDec.declarations[0].id.name
const sketchGroup = previousProgramMemory.root[varName] as SketchGroup
const intersectPath = sketchGroup.value.find(
({ name }) => name === intersectTagName
)
let offset = 0
if (intersectPath) {
offset = roundOff(
perpendicularDistance(intersectPath?.from, intersectPath?.to, to),
2
)
}
const angleLit = createLiteral(angle)
mutateObjExpProp(firstArg, angleLit, 'angle')
mutateObjExpProp(firstArg, createLiteral(offset), 'offset')
return {
modifiedAst: _node,
pathToNode,
}
},
addTag: addTagWithTo('angleTo'), // TODO might be wrong
}
export const sketchLineHelperMap: { [key: string]: SketchLineHelper } = { export const sketchLineHelperMap: { [key: string]: SketchLineHelper } = {
line, line,
lineTo, lineTo,
@ -1096,6 +1221,7 @@ export const sketchLineHelperMap: { [key: string]: SketchLineHelper } = {
angledLineOfYLength, angledLineOfYLength,
angledLineToX, angledLineToX,
angledLineToY, angledLineToY,
angledLineThatIntersects,
} as const } as const
export function changeSketchArguments( export function changeSketchArguments(
@ -1116,6 +1242,7 @@ export function changeSketchArguments(
if (callExpression?.callee?.name in sketchLineHelperMap) { if (callExpression?.callee?.name in sketchLineHelperMap) {
const { updateArgs } = sketchLineHelperMap[callExpression.callee.name] const { updateArgs } = sketchLineHelperMap[callExpression.callee.name]
if (!updateArgs) throw new Error('not a sketch line helper')
return updateArgs({ return updateArgs({
node: _node, node: _node,
previousProgramMemory: programMemory, previousProgramMemory: programMemory,
@ -1235,7 +1362,8 @@ export function replaceSketchLine({
createCallback: TransformCallback createCallback: TransformCallback
referencedSegment?: Path referencedSegment?: Path
}): { modifiedAst: Program; valueUsedInTransform?: number } { }): { modifiedAst: Program; valueUsedInTransform?: number } {
if (!toolTips.includes(fnName)) throw new Error('not a tooltip') if (![...toolTips, 'intersect'].includes(fnName))
throw new Error('not a tooltip')
const _node = { ...node } const _node = { ...node }
const thePath = getNodePathFromSourceRange(_node, sourceRange) const thePath = getNodePathFromSourceRange(_node, sourceRange)
@ -1540,6 +1668,26 @@ function getFirstArgValuesForXYLineFns(callExpression: CallExpression): {
throw new Error('expected ArrayExpression or ObjectExpression') throw new Error('expected ArrayExpression or ObjectExpression')
} }
const getAngledLineThatIntersects = (
callExp: CallExpression
): {
val: [Value, Value]
tag?: Value
} => {
const firstArg = callExp.arguments[0]
if (firstArg.type === 'ObjectExpression') {
const tag = firstArg.properties.find((p) => p.key.name === 'tag')?.value
const angle = firstArg.properties.find((p) => p.key.name === 'angle')?.value
const offset = firstArg.properties.find(
(p) => p.key.name === 'offset'
)?.value
if (angle && offset) {
return { val: [angle, offset], tag }
}
}
throw new Error('expected ArrayExpression or ObjectExpression')
}
export function getFirstArg(callExp: CallExpression): { export function getFirstArg(callExp: CallExpression): {
val: Value | [Value, Value] val: Value | [Value, Value]
tag?: Value tag?: Value
@ -1565,5 +1713,8 @@ export function getFirstArg(callExp: CallExpression): {
if (['startSketchAt'].includes(name)) { if (['startSketchAt'].includes(name)) {
return getFirstArgValuesForXYLineFns(callExp) return getFirstArgValuesForXYLineFns(callExp)
} }
if (['angledLineThatIntersects'].includes(name)) {
return getAngledLineThatIntersects(callExp)
}
throw new Error('unexpected call expression') throw new Error('unexpected call expression')
} }

View File

@ -17,6 +17,7 @@ import {
createCallExpression, createCallExpression,
createIdentifier, createIdentifier,
createLiteral, createLiteral,
createObjectExpression,
createPipeSubstitution, createPipeSubstitution,
createUnaryExpression, createUnaryExpression,
giveSketchFnCallTag, giveSketchFnCallTag,
@ -43,6 +44,7 @@ export type ConstraintType =
| 'setVertDistance' | 'setVertDistance'
| 'setAngle' | 'setAngle'
| 'setLength' | 'setLength'
| 'intersect'
function createCallWrapper( function createCallWrapper(
a: TooTip, a: TooTip,
@ -59,6 +61,38 @@ function createCallWrapper(
} }
} }
function intersectCallWrapper({
fnName,
angleVal,
offsetVal,
intersectTag,
tag,
valueUsedInTransform,
}: {
fnName: string
angleVal: Value
offsetVal: Value
intersectTag: Value
tag?: Value
valueUsedInTransform?: number
}): ReturnType<TransformCallback> {
const firstArg: any = {
angle: angleVal,
offset: offsetVal,
intersectTag,
}
if (tag) {
firstArg['tag'] = tag
}
return {
callExp: createCallExpression(fnName, [
createObjectExpression(firstArg),
createPipeSubstitution(),
]),
valueUsedInTransform,
}
}
export type TransformInfo = { export type TransformInfo = {
tooltip: TooTip tooltip: TooTip
createNode: (a: { createNode: (a: {
@ -71,7 +105,7 @@ export type TransformInfo = {
} }
type TransformMap = { type TransformMap = {
[key in TooTip]: { [key in TooTip]?: {
[key in LineInputsType | 'free']?: { [key in LineInputsType | 'free']?: {
[key in ConstraintType]?: TransformInfo [key in ConstraintType]?: TransformInfo
} }
@ -307,6 +341,44 @@ const setHorzVertDistanceConstraintLineCreateNode =
} }
} }
const setAngledIntersectLineForLines: TransformInfo['createNode'] =
({ referenceSegName, tag, forceValueUsedInTransform }) =>
(args) => {
const valueUsedInTransform = roundOff(
args[1].type === 'Literal' ? Number(args[1].value) : 0,
2
)
const angle = args[0].type === 'Literal' ? Number(args[0].value) : 0
return intersectCallWrapper({
fnName: 'angledLineThatIntersects',
angleVal: createLiteral(angle),
offsetVal:
forceValueUsedInTransform || createLiteral(valueUsedInTransform),
intersectTag: createLiteral(referenceSegName),
tag,
valueUsedInTransform,
})
}
const setAngledIntersectForAngledLines: TransformInfo['createNode'] =
({ referenceSegName, tag, forceValueUsedInTransform, varValA }) =>
(args) => {
const valueUsedInTransform = roundOff(
args[1].type === 'Literal' ? Number(args[1].value) : 0,
2
)
// const angle = args[0].type === 'Literal' ? Number(args[0].value) : 0
return intersectCallWrapper({
fnName: 'angledLineThatIntersects',
angleVal: varValA,
offsetVal:
forceValueUsedInTransform || createLiteral(valueUsedInTransform),
intersectTag: createLiteral(referenceSegName),
tag,
valueUsedInTransform,
})
}
const transformMap: TransformMap = { const transformMap: TransformMap = {
line: { line: {
xRelative: { xRelative: {
@ -404,6 +476,10 @@ const transformMap: TransformMap = {
tooltip: 'angledLine', tooltip: 'angledLine',
createNode: basicAngledLineCreateNode('ang'), createNode: basicAngledLineCreateNode('ang'),
}, },
intersect: {
tooltip: 'angledLineThatIntersects',
createNode: setAngledIntersectLineForLines,
},
}, },
}, },
lineTo: { lineTo: {
@ -524,6 +600,10 @@ const transformMap: TransformMap = {
tooltip: 'angledLineToX', tooltip: 'angledLineToX',
createNode: setHorzVertDistanceForAngleLineCreateNode('x'), createNode: setHorzVertDistanceForAngleLineCreateNode('x'),
}, },
intersect: {
tooltip: 'angledLineThatIntersects',
createNode: setAngledIntersectForAngledLines,
},
}, },
free: { free: {
equalLength: { equalLength: {
@ -798,6 +878,10 @@ const transformMap: TransformMap = {
tooltip: 'xLine', tooltip: 'xLine',
createNode: xyLineSetLength('xLine'), createNode: xyLineSetLength('xLine'),
}, },
intersect: {
tooltip: 'angledLineThatIntersects',
createNode: setAngledIntersectLineForLines,
},
}, },
}, },
yLine: { yLine: {
@ -817,6 +901,10 @@ const transformMap: TransformMap = {
tooltip: 'yLineTo', tooltip: 'yLineTo',
createNode: setHorVertDistanceForXYLines('y'), createNode: setHorVertDistanceForXYLines('y'),
}, },
intersect: {
tooltip: 'angledLineThatIntersects',
createNode: setAngledIntersectLineForLines,
},
}, },
}, },
xLineTo: { xLineTo: {

View File

@ -12,7 +12,7 @@ import {
angledLineToY, angledLineToY,
closee, closee,
startSketchAt, startSketchAt,
getCoordsFromPaths, angledLineThatIntersects,
} from './sketch' } from './sketch'
import { import {
segLen, segLen,
@ -29,7 +29,6 @@ import { Quaternion, Vector3 } from 'three'
import { SketchGroup, ExtrudeGroup, Position, Rotation } from '../executor' import { SketchGroup, ExtrudeGroup, Position, Rotation } from '../executor'
import { InternalFn, InternalFnNames, InternalFirstArg } from './stdTypes' import { InternalFn, InternalFnNames, InternalFirstArg } from './stdTypes'
import { intersectionWithParallelLine } from 'sketch-helpers'
const transform: InternalFn = <T extends SketchGroup | ExtrudeGroup>( const transform: InternalFn = <T extends SketchGroup | ExtrudeGroup>(
{ sourceRange }: InternalFirstArg, { sourceRange }: InternalFirstArg,
@ -82,38 +81,6 @@ const translate: InternalFn = <T extends SketchGroup | ExtrudeGroup>(
} }
} }
const angledLineThatIntersects: InternalFn = (
{ sourceRange, programMemory },
data: {
angle: number
intersectTag: string
offset?: number
tag?: string
},
previousSketch: SketchGroup
) => {
if (!previousSketch) throw new Error('lineTo must be called after lineTo')
const intersectPath = previousSketch.value.find(
({ name }) => name === data.intersectTag
)
if (!intersectPath) throw new Error('intersectTag must match a line')
const from = getCoordsFromPaths(
previousSketch,
previousSketch.value.length - 1
)
const to = intersectionWithParallelLine({
line1: [intersectPath.from, intersectPath.to],
line1Offset: data.offset || 0,
line2Point: from,
line2Angle: data.angle,
})
return lineTo.fn(
{ sourceRange, programMemory },
{ to, tag: data.tag },
previousSketch
)
}
const min: InternalFn = (_, a: number, b: number): number => Math.min(a, b) const min: InternalFn = (_, a: number, b: number): number => Math.min(a, b)
const legLen: InternalFn = (_, hypotenuse: number, leg: number): number => const legLen: InternalFn = (_, hypotenuse: number, leg: number): number =>
@ -158,7 +125,7 @@ export const internalFns: { [key in InternalFnNames]: InternalFn } = {
angledLineToX: angledLineToX.fn, angledLineToX: angledLineToX.fn,
angledLineOfYLength: angledLineOfYLength.fn, angledLineOfYLength: angledLineOfYLength.fn,
angledLineToY: angledLineToY.fn, angledLineToY: angledLineToY.fn,
angledLineThatIntersects, angledLineThatIntersects: angledLineThatIntersects.fn,
startSketchAt, startSketchAt,
closee, closee,
} }

View File

@ -22,6 +22,7 @@ export type TooTip =
| 'yLine' | 'yLine'
| 'xLineTo' | 'xLineTo'
| 'yLineTo' | 'yLineTo'
| 'angledLineThatIntersects'
export const toolTips: TooTip[] = [ export const toolTips: TooTip[] = [
'lineTo', 'lineTo',
@ -35,6 +36,7 @@ export const toolTips: TooTip[] = [
'yLine', 'yLine',
'xLineTo', 'xLineTo',
'yLineTo', 'yLineTo',
'angledLineThatIntersects',
] ]
export type GuiModes = export type GuiModes =

View File

@ -9360,10 +9360,10 @@ sisteransi@^1.0.4, sisteransi@^1.0.5:
resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed"
integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==
sketch-helpers@^0.0.1: sketch-helpers@^0.0.2:
version "0.0.1" version "0.0.2"
resolved "https://registry.yarnpkg.com/sketch-helpers/-/sketch-helpers-0.0.1.tgz#637ead1f6e39276408d2c2e2a48dfefe13dc0cb0" resolved "https://registry.yarnpkg.com/sketch-helpers/-/sketch-helpers-0.0.2.tgz#7b088303a82d3b7008abfe4e20a476c6da20cc0e"
integrity sha512-ePn4nTA5sVNR6+8JalyCPQ+K7tpuYtCrccw2QGL6H2N3JRq6bO8x9RmZpyjTe/+T0uSrd2+F41d+ibsrjHHSFg== integrity sha512-3VnjIlqg3ORxcIR9vATazvvQt6/4vzPymcorQ30vigjjZEXPHf4xT6Zh7pbZmR58RJBKEU1AtAANhqYar4CRFQ==
slash@^3.0.0: slash@^3.0.0:
version "3.0.0" version "3.0.0"