diff --git a/src/components/SketchLine.tsx b/src/components/SketchLine.tsx
index f66172ef8..2d97028cc 100644
--- a/src/components/SketchLine.tsx
+++ b/src/components/SketchLine.tsx
@@ -12,51 +12,6 @@ import { isOverlapping } from '../lib/utils'
import { LineGeos } from '../lang/engine'
import { Vector3, DoubleSide, Quaternion, Vector2 } from 'three'
-function useHeightlight(sourceRange: [number, number]) {
- const { selectionRange, guiMode, setGuiMode, ast } = useStore((s) => ({
- setHighlightRange: s.setHighlightRange,
- selectionRange: s.selectionRange,
- guiMode: s.guiMode,
- setGuiMode: s.setGuiMode,
- ast: s.ast,
- }))
- // This reference will give us direct access to the mesh
- const [editorCursor, setEditorCursor] = useState(false)
- const [didSetCanEdit, setDidSetCanEdit] = useState(false)
- useEffect(() => {
- const shouldHighlight = isOverlapping(sourceRange, selectionRange)
- setEditorCursor(shouldHighlight)
- if (shouldHighlight && guiMode.mode === 'default' && ast) {
- const pathToNode = getNodePathFromSourceRange(ast, sourceRange)
- const piper = getNodeFromPath(ast, pathToNode, 'PipeExpression')
- const quaternion = new Quaternion()
- if (piper.type === 'PipeExpression') {
- const rotateName = piper?.body?.[1]?.callee?.name
- const rotateValue = piper?.body?.[1]?.arguments[0].value
- let rotateAxis = new Vector3(1, 0, 0)
- if (rotateName === 'ry') {
- rotateAxis = new Vector3(0, 1, 0)
- } else if (rotateName === 'rz') {
- rotateAxis = new Vector3(0, 0, 1)
- }
- quaternion.setFromAxisAngle(rotateAxis, (Math.PI * rotateValue) / 180)
- }
- setGuiMode({ mode: 'canEditSketch', pathToNode, quaternion })
- setDidSetCanEdit(true)
- } else if (
- !shouldHighlight &&
- didSetCanEdit &&
- guiMode.mode === 'canEditSketch'
- ) {
- setGuiMode({ mode: 'default' })
- setDidSetCanEdit(false)
- }
- }, [selectionRange, sourceRange])
- return {
- editorCursor,
- }
-}
-
function SketchLine({
geo,
sourceRange,
@@ -66,7 +21,6 @@ function SketchLine({
sourceRange: [number, number]
forceHighlight?: boolean
}) {
- const { editorCursor } = useHeightlight(sourceRange)
const { setHighlightRange } = useStore(
({ setHighlightRange, selectionRange, guiMode, setGuiMode, ast }) => ({
setHighlightRange,
@@ -95,19 +49,13 @@ function SketchLine({
>
>
)
@@ -272,14 +220,51 @@ export function RenderViewerArtifacts({
artifact: ViewerArtifact
forceHighlight?: boolean
}) {
- const { selectionRange } = useStore(({ selectionRange }) => ({
- selectionRange,
- }))
+ const { selectionRange, guiMode, ast, setGuiMode } = useStore(
+ ({ selectionRange, guiMode, ast, setGuiMode }) => ({
+ selectionRange,
+ guiMode,
+ ast,
+ setGuiMode,
+ })
+ )
const [editorCursor, setEditorCursor] = useState(false)
useEffect(() => {
const shouldHighlight = isOverlapping(artifact.sourceRange, selectionRange)
- setEditorCursor(shouldHighlight)
+ setEditorCursor(shouldHighlight && artifact.type !== 'sketch')
}, [selectionRange, artifact.sourceRange])
+
+ useEffect(() => {
+ const shouldHighlight = isOverlapping(artifact.sourceRange, selectionRange)
+ if (
+ shouldHighlight &&
+ (guiMode.mode === 'default' || guiMode.mode === 'canEditSketch') &&
+ artifact.type === 'sketch' &&
+ ast
+ ) {
+ const pathToNode = getNodePathFromSourceRange(ast, artifact.sourceRange)
+ const piper = getNodeFromPath(ast, pathToNode, 'PipeExpression')
+ const quaternion = new Quaternion()
+ if (piper.type === 'PipeExpression') {
+ const rotateName = piper?.body?.[1]?.callee?.name
+ const rotateValue = piper?.body?.[1]?.arguments[0].value
+ let rotateAxis = new Vector3(1, 0, 0)
+ if (rotateName === 'ry') {
+ rotateAxis = new Vector3(0, 1, 0)
+ } else if (rotateName === 'rz') {
+ rotateAxis = new Vector3(0, 0, 1)
+ }
+ quaternion.setFromAxisAngle(rotateAxis, (Math.PI * rotateValue) / 180)
+ }
+ setGuiMode({ mode: 'canEditSketch', pathToNode, quaternion })
+ } else if (
+ !shouldHighlight &&
+ guiMode.mode === 'canEditSketch' &&
+ artifact.type === 'sketch'
+ ) {
+ setGuiMode({ mode: 'default' })
+ }
+ }, [selectionRange, artifact.sourceRange, ast, guiMode.mode, setGuiMode])
if (artifact.type === 'sketchLine') {
const { geo, sourceRange } = artifact
return (
diff --git a/src/lang/artifact.test.ts b/src/lang/artifact.test.ts
new file mode 100644
index 000000000..a2cc37c0e
--- /dev/null
+++ b/src/lang/artifact.test.ts
@@ -0,0 +1,70 @@
+import { abstractSyntaxTree } from './abstractSyntaxTree'
+import { lexer } from './tokeniser'
+import { executor, ViewerArtifact, processShownObjects } from './executor'
+
+describe('findClosingBrace', () => {
+ test('finds the closing brace', () => {
+ const code = `
+sketch mySketch001 {
+ lineTo(-1.59, -1.54)
+ lineTo(0.46, -5.82)
+}
+ |> rx(45, %)
+show(mySketch001)`
+ const programMemory = executor(abstractSyntaxTree(lexer(code)))
+ const geos: ViewerArtifact[] =
+ programMemory?.return?.flatMap(
+ ({ name }: { name: string }) =>
+ processShownObjects(programMemory, programMemory?.root?.[name]) || []
+ ) || []
+ const artifactsWithouGeos = removeGeo(geos)
+ expect(artifactsWithouGeos).toEqual([
+ {
+ type: 'parent',
+ sourceRange: [74, 83],
+ children: [
+ {
+ type: 'sketch',
+ sourceRange: [20, 68],
+ children: [
+ {
+ type: 'sketchBase',
+ sourceRange: [0, 0],
+ },
+ {
+ type: 'sketchLine',
+ sourceRange: [24, 44],
+ },
+ {
+ type: 'sketchLine',
+ sourceRange: [47, 66],
+ },
+ ],
+ },
+ ],
+ },
+ ])
+ })
+})
+
+function removeGeo(arts: ViewerArtifact[]): any {
+ return arts.map((art) => {
+ if (art.type === 'sketchLine' || art.type === 'sketchBase') {
+ const { geo, ...rest } = art
+ return rest
+ }
+ if (art.type === 'parent') {
+ return {
+ ...art,
+ children: removeGeo(art.children),
+ }
+ }
+ if (art.type === 'sketch') {
+ return {
+ ...art,
+ children: removeGeo(art.children),
+ }
+ }
+ return art
+ })
+}
diff --git a/src/lang/executor.ts b/src/lang/executor.ts
index c585b0934..465f7f759 100644
--- a/src/lang/executor.ts
+++ b/src/lang/executor.ts
@@ -309,6 +309,11 @@ export type ViewerArtifact =
sourceRange: SourceRange
children: ViewerArtifact[]
}
+ | {
+ type: 'sketch'
+ sourceRange: SourceRange
+ children: ViewerArtifact[]
+ }
type PreviousTransforms = {
rotation: [number, number, number]
@@ -321,43 +326,48 @@ export const processShownObjects = (
previousTransforms: PreviousTransforms = []
): ViewerArtifact[] => {
if (geoMeta?.type === 'sketchGeo') {
- return geoMeta.sketch.map(({ geo, sourceRange, type }) => {
- if (type === 'toPoint') {
- // const newGeo = geo.clone()
- const newGeo: LineGeos = {
- line: geo.line.clone(),
- tip: geo.tip.clone(),
- centre: geo.centre.clone(),
- }
- previousTransforms.forEach(({ rotation, transform }) => {
- Object.values(newGeo).forEach((geoItem) => {
- geoItem.rotateX(rotation[0])
- geoItem.rotateY(rotation[1])
- geoItem.rotateZ(rotation[2])
- geoItem.translate(transform[0], transform[1], transform[2])
- })
- })
- return {
- type: 'sketchLine',
- geo: newGeo,
- sourceRange,
- }
- } else if (type === 'base') {
- const newGeo = geo.clone()
- previousTransforms.forEach(({ rotation, transform }) => {
- newGeo.rotateX(rotation[0])
- newGeo.rotateY(rotation[1])
- newGeo.rotateZ(rotation[2])
- newGeo.translate(transform[0], transform[1], transform[2])
- })
- return {
- type: 'sketchBase',
- geo: newGeo,
- sourceRange,
- }
- }
- throw new Error('Unknown geo type')
- })
+ return [
+ {
+ type: 'sketch',
+ sourceRange: geoMeta.sourceRange,
+ children: geoMeta.sketch.map(({ geo, sourceRange, type }) => {
+ if (type === 'toPoint') {
+ const newGeo: LineGeos = {
+ line: geo.line.clone(),
+ tip: geo.tip.clone(),
+ centre: geo.centre.clone(),
+ }
+ previousTransforms.forEach(({ rotation, transform }) => {
+ Object.values(newGeo).forEach((geoItem) => {
+ geoItem.rotateX(rotation[0])
+ geoItem.rotateY(rotation[1])
+ geoItem.rotateZ(rotation[2])
+ geoItem.translate(transform[0], transform[1], transform[2])
+ })
+ })
+ return {
+ type: 'sketchLine',
+ geo: newGeo,
+ sourceRange,
+ }
+ } else if (type === 'base') {
+ const newGeo = geo.clone()
+ previousTransforms.forEach(({ rotation, transform }) => {
+ newGeo.rotateX(rotation[0])
+ newGeo.rotateY(rotation[1])
+ newGeo.rotateZ(rotation[2])
+ newGeo.translate(transform[0], transform[1], transform[2])
+ })
+ return {
+ type: 'sketchBase',
+ geo: newGeo,
+ sourceRange,
+ }
+ }
+ throw new Error('Unknown geo type')
+ }),
+ },
+ ]
} else if (geoMeta.type === 'transform') {
const referencedVar = geoMeta.sketch
const parentArtifact: ViewerArtifact = {