diff --git a/src/components/SketchLine.tsx b/src/components/SketchLine.tsx index 71ce0c5f1..87a445b59 100644 --- a/src/components/SketchLine.tsx +++ b/src/components/SketchLine.tsx @@ -12,6 +12,8 @@ import { Path, Rotation, Position, + PathToNode, + SourceRange, } from '../lang/executor' import { BufferGeometry } from 'three' import { useStore } from '../useStore' @@ -191,9 +193,10 @@ export function RenderViewerArtifacts({ }: { artifacts: (ExtrudeGroup | SketchGroup)[] }) { + useSetAppModeFromCursorLocation(artifacts) return ( <> - {artifacts.map((artifact, i) => ( + {artifacts?.map((artifact, i) => ( ))} @@ -205,59 +208,22 @@ function RenderViewerArtifact({ }: { artifact: ExtrudeGroup | SketchGroup }) { - const { selectionRange, guiMode, ast, setGuiMode } = useStore( - ({ selectionRange, guiMode, ast, setGuiMode }) => ({ - selectionRange, - guiMode, - ast, - setGuiMode, - }) - ) - const [editorCursor, setEditorCursor] = useState(false) - useEffect(() => { - const shouldHighlight = isOverlapping( - artifact.__meta[0].sourceRange, - selectionRange - ) - setEditorCursor(shouldHighlight) - }, [selectionRange, artifact.__meta]) - - useEffect(() => { - const shouldHighlight = artifact.__meta.some((aMeta) => - isOverlapping(aMeta.sourceRange, selectionRange) - ) - if ( - shouldHighlight && - (guiMode.mode === 'default' || guiMode.mode === 'canEditSketch') && - ast && - artifact.type === 'sketchGroup' - ) { - const pathToNode = getNodePathFromSourceRange( - ast, - artifact.__meta[0].sourceRange - ) - 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' || guiMode.mode === 'canEditExtrude') && - (artifact.type === 'sketchGroup' || artifact.type === 'extrudeGroup') - ) { - setGuiMode({ mode: 'default' }) - } - }, [selectionRange, artifact, ast, guiMode.mode, setGuiMode]) + // const { selectionRange, guiMode, ast, setGuiMode } = useStore( + // ({ selectionRange, guiMode, ast, setGuiMode }) => ({ + // selectionRange, + // guiMode, + // ast, + // setGuiMode, + // }) + // ) + // const [editorCursor, setEditorCursor] = useState(false) + // useEffect(() => { + // const shouldHighlight = isOverlapping( + // artifact.__meta.slice(-1)[0].sourceRange, + // selectionRange + // ) + // setEditorCursor(shouldHighlight) + // }, [selectionRange, artifact.__meta]) if (artifact.type === 'sketchGroup') { return ( @@ -266,7 +232,7 @@ function RenderViewerArtifact({ @@ -281,7 +247,7 @@ function RenderViewerArtifact({ @@ -454,3 +420,91 @@ function LineRender({ ) } + +type Boop = ExtrudeGroup | SketchGroup + +function useSetAppModeFromCursorLocation(artifacts: Boop[]) { + const { selectionRange, guiMode, setGuiMode, ast } = useStore( + ({ selectionRange, guiMode, setGuiMode, ast }) => ({ + selectionRange, + guiMode, + setGuiMode, + ast, + }) + ) + useEffect(() => { + const artifactsWithinCursorRange: ( + | { + parentType: Boop['type'] + isParent: true + pathToNode: PathToNode + sourceRange: SourceRange + rotation: Rotation + position: Position + } + | { + parentType: Boop['type'] + isParent: false + pathToNode: PathToNode + sourceRange: SourceRange + } + )[] = [] + artifacts.forEach((artifact) => { + artifact.value.forEach((geo) => { + if (isOverlapping(geo.__geoMeta.sourceRange, selectionRange)) { + artifactsWithinCursorRange.push({ + parentType: artifact.type, + isParent: false, + pathToNode: geo.__geoMeta.pathToNode, + sourceRange: geo.__geoMeta.sourceRange, + }) + } + }) + artifact.__meta.forEach((meta) => { + if (isOverlapping(meta.sourceRange, selectionRange)) { + artifactsWithinCursorRange.push({ + parentType: artifact.type, + isParent: true, + pathToNode: meta.pathToNode, + sourceRange: meta.sourceRange, + rotation: artifact.rotation, + position: artifact.position, + }) + } + }) + }) + const parentArtifacts = artifactsWithinCursorRange.filter((a) => a.isParent) + if (parentArtifacts.length > 1) { + console.log('multiple parents, might be an issue?', parentArtifacts) + } + const artifact = parentArtifacts[0] + const shouldHighlight = !!artifact + if ( + shouldHighlight && + (guiMode.mode === 'default' || guiMode.mode === 'canEditSketch') && + ast && + artifact.parentType === 'sketchGroup' && + artifact.isParent + ) { + const pathToNode = getNodePathFromSourceRange(ast, artifact.sourceRange) + const { rotation, position } = artifact + setGuiMode({ mode: 'canEditSketch', pathToNode, rotation, position }) + } else if ( + shouldHighlight && + (guiMode.mode === 'default' || guiMode.mode === 'canEditSketch') && + ast && + artifact.parentType === 'extrudeGroup' && + artifact.isParent + ) { + const pathToNode = getNodePathFromSourceRange(ast, artifact.sourceRange) + const { rotation, position } = artifact + setGuiMode({ mode: 'canEditExtrude', pathToNode, rotation, position }) + } else if ( + !shouldHighlight && + (guiMode.mode === 'canEditSketch' || guiMode.mode === 'canEditExtrude') + // (artifact.parentType === 'extrudeGroup' || artifact.type === 'extrudeGroup') + ) { + setGuiMode({ mode: 'default' }) + } + }, [artifacts, selectionRange]) +} diff --git a/src/lang/abstractSyntaxTree.ts b/src/lang/abstractSyntaxTree.ts index d773d4eae..748c3bd42 100644 --- a/src/lang/abstractSyntaxTree.ts +++ b/src/lang/abstractSyntaxTree.ts @@ -1348,7 +1348,8 @@ function debuggerr(tokens: Token[], indexes: number[], msg = ''): string { export function getNodeFromPath( node: Program, path: (string | number)[], - stopAt: string = '' + stopAt: string = '', + returnEarly = false ) { let currentNode = node as any let stopAtNode = null @@ -1363,6 +1364,9 @@ export function getNodeFromPath( // it will match the deepest node of the type // instead of returning at the first match stopAtNode = currentNode + if (returnEarly) { + return stopAtNode + } } } catch (e) { throw new Error( diff --git a/src/lang/artifact.test.ts b/src/lang/artifact.test.ts index b447b4183..3a4410868 100644 --- a/src/lang/artifact.test.ts +++ b/src/lang/artifact.test.ts @@ -74,6 +74,19 @@ show(mySketch001)` { type: 'extrudeGroup', value: [ + { + type: 'extrudePlane', + position: [-0.795, -0.5444722215136415, -0.5444722215136416], + rotation: [ + 0.35471170441873584, 0.3467252481708758, -0.14361830020955396, + 0.8563498075401887, + ], + __geoMeta: { + geo: 'PlaneGeometry', + sourceRange: [24, 44], + pathToNode: [], + }, + }, { type: 'extrudePlane', position: [ @@ -137,6 +150,19 @@ show(theExtrude, sk2)` { type: 'extrudeGroup', value: [ + { + type: 'extrudePlane', + position: [-0.1618929317752782, 0, 1.01798363377866], + rotation: [ + 0.3823192025331841, -0.04029905920751535, -0.016692416874629204, + 0.9230002039112793, + ], + __geoMeta: { + geo: 'PlaneGeometry', + sourceRange: [16, 31], + pathToNode: [], + }, + }, { type: 'extrudePlane', position: [ @@ -189,6 +215,21 @@ show(theExtrude, sk2)` { type: 'extrudeGroup', value: [ + { + type: 'extrudePlane', + position: [ + 0.5230004643466108, 4.393026831645281, 5.367870706359959, + ], + rotation: [ + -0.5548685410139091, 0.7377864971619333, 0.3261466075583827, + -0.20351996751370383, + ], + __geoMeta: { + geo: 'PlaneGeometry', + sourceRange: [241, 256], + pathToNode: [], + }, + }, { type: 'extrudePlane', position: [ diff --git a/src/lang/engine.tsx b/src/lang/engine.tsx index 54f06ffb0..3037783fb 100644 --- a/src/lang/engine.tsx +++ b/src/lang/engine.tsx @@ -98,10 +98,12 @@ export function extrudeGeo({ from, to, length, + extrusionDirection = 1, }: { from: [number, number, number] to: [number, number, number] length: number + extrusionDirection?: number }): { geo: BufferGeometry position: Position @@ -124,7 +126,13 @@ export function extrudeGeo({ face.translate(to[0], to[1], to[2]) const quat = new Quaternion() - const euler = new Euler(-Math.PI / 2, ry, rz * sign, 'XYZ') + const otherSign = ry === 0 ? 1 : -1 // don't ask questions, it works okay + const euler = new Euler( + (Math.PI * otherSign * extrusionDirection) / 2, + ry, + rz * sign * -otherSign, + 'XYZ' + ) quat.setFromEuler(euler) return { diff --git a/src/lang/modifyAst.ts b/src/lang/modifyAst.ts index 662da5a51..fbe530433 100644 --- a/src/lang/modifyAst.ts +++ b/src/lang/modifyAst.ts @@ -385,8 +385,12 @@ export function sketchOnExtrudedFace( const _node = { ...node } const dumbyStartend = { start: 0, end: 0 } const newSketchName = findUniqueName(node, 'part') - const oldSketchName = getNodeFromPath(_node, pathToNode, 'VariableDeclarator') - .id.name + const oldSketchName = getNodeFromPath( + _node, + pathToNode, + 'VariableDeclarator', + true + ).id.name const expression = getNodeFromPath(_node, pathToNode, 'CallExpression') as | VariableDeclarator | CallExpression diff --git a/src/lang/sketch.ts b/src/lang/sketch.ts index 21ee77826..ee22cadbb 100644 --- a/src/lang/sketch.ts +++ b/src/lang/sketch.ts @@ -173,13 +173,12 @@ export const sketchFns = { const { position, rotation } = sketchVal const extrudeSurfaces: ExtrudeSurface[] = [] + const extrusionDirection = clockwiseSign( + sketch.value.map((line) => line.to) + ) sketch.value.map((line, index) => { - if (line.type === 'toPoint' && index !== 0) { - const lastPoint = sketch.value[index - 1] - let from: [number, number] = [0, 0] - if (lastPoint.type === 'toPoint') { - from = lastPoint.to - } + if (line.type === 'toPoint') { + let from: [number, number] = line.from const to = line.to const { geo, @@ -189,6 +188,7 @@ export const sketchFns = { from: [from[0], from[1], 0], to: [to[0], to[1], 0], length, + extrusionDirection, }) const groupQuaternion = new Quaternion(...rotation) const currentWallQuat = new Quaternion(...faceRotation) @@ -344,3 +344,13 @@ function getExtrudeWallTransform( quaternion: path.rotation, } } + +function clockwiseSign(points: [number, number][]): number { + let sum = 0 + for (let i = 0; i < points.length; i++) { + const currentPoint = points[i] + const nextPoint = points[(i + 1) % points.length] + sum += (nextPoint[0] - currentPoint[0]) * (nextPoint[1] + currentPoint[1]) + } + return sum >= 0 ? 1 : -1 +}