drag sphere - edit sketch working for xy plane
This commit is contained in:
119
src/App.tsx
119
src/App.tsx
@ -3,14 +3,9 @@ import { Canvas } from '@react-three/fiber'
|
|||||||
import { Allotment } from 'allotment'
|
import { Allotment } from 'allotment'
|
||||||
import { OrbitControls, OrthographicCamera } from '@react-three/drei'
|
import { OrbitControls, OrthographicCamera } from '@react-three/drei'
|
||||||
import { lexer } from './lang/tokeniser'
|
import { lexer } from './lang/tokeniser'
|
||||||
import {
|
import { abstractSyntaxTree } from './lang/abstractSyntaxTree'
|
||||||
abstractSyntaxTree,
|
|
||||||
getNodePathFromSourceRange,
|
|
||||||
getNodeFromPath
|
|
||||||
} from './lang/abstractSyntaxTree'
|
|
||||||
import { executor, processShownObjects, ViewerArtifact } from './lang/executor'
|
import { executor, processShownObjects, ViewerArtifact } from './lang/executor'
|
||||||
import { recast } from './lang/recast'
|
import { recast } from './lang/recast'
|
||||||
import { BufferGeometry } from 'three'
|
|
||||||
import CodeMirror from '@uiw/react-codemirror'
|
import CodeMirror from '@uiw/react-codemirror'
|
||||||
import { javascript } from '@codemirror/lang-javascript'
|
import { javascript } from '@codemirror/lang-javascript'
|
||||||
import { ViewUpdate } from '@codemirror/view'
|
import { ViewUpdate } from '@codemirror/view'
|
||||||
@ -19,12 +14,12 @@ import {
|
|||||||
addLineHighlight,
|
addLineHighlight,
|
||||||
} from './editor/highlightextension'
|
} from './editor/highlightextension'
|
||||||
import { useStore } from './useStore'
|
import { useStore } from './useStore'
|
||||||
import { isOverlapping } from './lib/utils'
|
|
||||||
import { Toolbar } from './Toolbar'
|
import { Toolbar } from './Toolbar'
|
||||||
import { BasePlanes } from './components/BasePlanes'
|
import { BasePlanes } from './components/BasePlanes'
|
||||||
import { SketchPlane } from './components/SketchPlane'
|
import { SketchPlane } from './components/SketchPlane'
|
||||||
import { Logs } from './components/Logs'
|
import { Logs } from './components/Logs'
|
||||||
import { AxisIndicator } from './components/AxisIndicator'
|
import { AxisIndicator } from './components/AxisIndicator'
|
||||||
|
import { RenderViewerArtifacts } from './components/SketchLine'
|
||||||
|
|
||||||
const OrrthographicCamera = OrthographicCamera as any
|
const OrrthographicCamera = OrthographicCamera as any
|
||||||
|
|
||||||
@ -160,7 +155,7 @@ function App() {
|
|||||||
<OrbitControls
|
<OrbitControls
|
||||||
enableDamping={false}
|
enableDamping={false}
|
||||||
enablePan
|
enablePan
|
||||||
enableRotate
|
enableRotate={!(guiMode.mode === 'canEditSketch' || guiMode.mode === 'sketch')}
|
||||||
enableZoom
|
enableZoom
|
||||||
reverseOrbit={false}
|
reverseOrbit={false}
|
||||||
/>
|
/>
|
||||||
@ -199,111 +194,3 @@ function App() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default App
|
export default App
|
||||||
|
|
||||||
function Line({
|
|
||||||
geo,
|
|
||||||
sourceRange,
|
|
||||||
forceHighlight = false,
|
|
||||||
}: {
|
|
||||||
geo: BufferGeometry
|
|
||||||
sourceRange: [number, number]
|
|
||||||
forceHighlight?: boolean
|
|
||||||
}) {
|
|
||||||
const { setHighlightRange, selectionRange, guiMode, setGuiMode, ast } =
|
|
||||||
useStore(
|
|
||||||
({ setHighlightRange, selectionRange, guiMode, setGuiMode, ast }) => ({
|
|
||||||
setHighlightRange,
|
|
||||||
selectionRange,
|
|
||||||
guiMode,
|
|
||||||
setGuiMode,
|
|
||||||
ast,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
// This reference will give us direct access to the mesh
|
|
||||||
const ref = useRef<BufferGeometry | undefined>() as any
|
|
||||||
const [hovered, setHover] = useState(false)
|
|
||||||
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 axis = piper.type !== 'PipeExpression' ? 'xy'
|
|
||||||
: piper?.body?.[1]?.callee?.name === 'rx' ? 'xz' : 'yz'
|
|
||||||
setGuiMode({ mode: 'canEditSketch', pathToNode, axis })
|
|
||||||
setDidSetCanEdit(true)
|
|
||||||
} else if (
|
|
||||||
!shouldHighlight &&
|
|
||||||
didSetCanEdit &&
|
|
||||||
guiMode.mode === 'canEditSketch'
|
|
||||||
) {
|
|
||||||
setGuiMode({ mode: 'default' })
|
|
||||||
setDidSetCanEdit(false)
|
|
||||||
}
|
|
||||||
}, [selectionRange, sourceRange])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<mesh
|
|
||||||
ref={ref}
|
|
||||||
onPointerOver={(event) => {
|
|
||||||
setHover(true)
|
|
||||||
setHighlightRange(sourceRange)
|
|
||||||
}}
|
|
||||||
onPointerOut={(event) => {
|
|
||||||
setHover(false)
|
|
||||||
setHighlightRange([0, 0])
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<primitive object={geo} />
|
|
||||||
<meshStandardMaterial
|
|
||||||
color={
|
|
||||||
hovered
|
|
||||||
? 'hotpink'
|
|
||||||
: editorCursor || forceHighlight
|
|
||||||
? 'skyblue'
|
|
||||||
: 'orange'
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</mesh>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function RenderViewerArtifacts({
|
|
||||||
artifact,
|
|
||||||
forceHighlight = false,
|
|
||||||
}: {
|
|
||||||
artifact: ViewerArtifact
|
|
||||||
forceHighlight?: boolean
|
|
||||||
}) {
|
|
||||||
const { selectionRange } = useStore(({ selectionRange }) => ({
|
|
||||||
selectionRange,
|
|
||||||
}))
|
|
||||||
const [editorCursor, setEditorCursor] = useState(false)
|
|
||||||
useEffect(() => {
|
|
||||||
const shouldHighlight = isOverlapping(artifact.sourceRange, selectionRange)
|
|
||||||
setEditorCursor(shouldHighlight)
|
|
||||||
}, [selectionRange, artifact.sourceRange])
|
|
||||||
if (artifact.type === 'sketchLine') {
|
|
||||||
const { geo, sourceRange } = artifact
|
|
||||||
return (
|
|
||||||
<Line
|
|
||||||
geo={geo}
|
|
||||||
sourceRange={sourceRange}
|
|
||||||
forceHighlight={forceHighlight || editorCursor}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{artifact.children.map((artifact, index) => (
|
|
||||||
<RenderViewerArtifacts
|
|
||||||
artifact={artifact}
|
|
||||||
key={index}
|
|
||||||
forceHighlight={forceHighlight || editorCursor}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
274
src/components/SketchLine.tsx
Normal file
274
src/components/SketchLine.tsx
Normal file
@ -0,0 +1,274 @@
|
|||||||
|
import { useRef, useState, useEffect, useMemo } from 'react'
|
||||||
|
import {
|
||||||
|
getNodePathFromSourceRange,
|
||||||
|
getNodeFromPath,
|
||||||
|
CallExpression,
|
||||||
|
changeArguments,
|
||||||
|
} from '../lang/abstractSyntaxTree'
|
||||||
|
import { ViewerArtifact } from '../lang/executor'
|
||||||
|
import { BufferGeometry } from 'three'
|
||||||
|
import { useStore } from '../useStore'
|
||||||
|
import { isOverlapping } from '../lib/utils'
|
||||||
|
import { LineGeos } from '../lang/engine'
|
||||||
|
import { Vector3 } 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 axis =
|
||||||
|
piper.type !== 'PipeExpression'
|
||||||
|
? 'xy'
|
||||||
|
: piper?.body?.[1]?.callee?.name === 'rx'
|
||||||
|
? 'xz'
|
||||||
|
: 'yz'
|
||||||
|
setGuiMode({ mode: 'canEditSketch', pathToNode, axis })
|
||||||
|
setDidSetCanEdit(true)
|
||||||
|
} else if (
|
||||||
|
!shouldHighlight &&
|
||||||
|
didSetCanEdit &&
|
||||||
|
guiMode.mode === 'canEditSketch'
|
||||||
|
) {
|
||||||
|
setGuiMode({ mode: 'default' })
|
||||||
|
setDidSetCanEdit(false)
|
||||||
|
}
|
||||||
|
}, [selectionRange, sourceRange])
|
||||||
|
return {
|
||||||
|
editorCursor,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function SketchLine({
|
||||||
|
geo,
|
||||||
|
sourceRange,
|
||||||
|
forceHighlight = false,
|
||||||
|
}: {
|
||||||
|
geo: LineGeos
|
||||||
|
sourceRange: [number, number]
|
||||||
|
forceHighlight?: boolean
|
||||||
|
}) {
|
||||||
|
const { editorCursor } = useHeightlight(sourceRange)
|
||||||
|
const { setHighlightRange } = useStore(
|
||||||
|
({ setHighlightRange, selectionRange, guiMode, setGuiMode, ast }) => ({
|
||||||
|
setHighlightRange,
|
||||||
|
selectionRange,
|
||||||
|
guiMode,
|
||||||
|
setGuiMode,
|
||||||
|
ast,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
// This reference will give us direct access to the mesh
|
||||||
|
const ref = useRef<BufferGeometry | undefined>() as any
|
||||||
|
const [hovered, setHover] = useState(false)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<mesh
|
||||||
|
ref={ref}
|
||||||
|
onPointerOver={(event) => {
|
||||||
|
setHover(true)
|
||||||
|
setHighlightRange(sourceRange)
|
||||||
|
}}
|
||||||
|
onPointerOut={(event) => {
|
||||||
|
setHover(false)
|
||||||
|
setHighlightRange([0, 0])
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<primitive object={geo.line} />
|
||||||
|
<meshStandardMaterial
|
||||||
|
color={
|
||||||
|
hovered
|
||||||
|
? 'hotpink'
|
||||||
|
: editorCursor || forceHighlight
|
||||||
|
? 'skyblue'
|
||||||
|
: 'orange'
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</mesh>
|
||||||
|
<MovingSphere
|
||||||
|
geo={geo.tip}
|
||||||
|
sourceRange={sourceRange}
|
||||||
|
editorCursor={editorCursor || forceHighlight}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const roundOff = (num: number, places: number): number => {
|
||||||
|
const x = Math.pow(10, places)
|
||||||
|
return Math.round(num * x) / x
|
||||||
|
}
|
||||||
|
|
||||||
|
function MovingSphere({
|
||||||
|
geo,
|
||||||
|
sourceRange,
|
||||||
|
editorCursor,
|
||||||
|
}: {
|
||||||
|
geo: BufferGeometry
|
||||||
|
sourceRange: [number, number]
|
||||||
|
editorCursor: boolean
|
||||||
|
}) {
|
||||||
|
const ref = useRef<BufferGeometry | undefined>() as any
|
||||||
|
const lastPointerRef = useRef<Vector3>(new Vector3())
|
||||||
|
const [hovered, setHover] = useState(false)
|
||||||
|
const [isMouseDown, setIsMouseDown] = useState(false)
|
||||||
|
|
||||||
|
const { setHighlightRange, guiMode, ast, updateAst } = useStore((s) => ({
|
||||||
|
setHighlightRange: s.setHighlightRange,
|
||||||
|
selectionRange: s.selectionRange,
|
||||||
|
guiMode: s.guiMode,
|
||||||
|
setGuiMode: s.setGuiMode,
|
||||||
|
ast: s.ast,
|
||||||
|
updateAst: s.updateAst,
|
||||||
|
}))
|
||||||
|
const { originalXY } = useMemo(() => {
|
||||||
|
if (ast) {
|
||||||
|
const thePath = getNodePathFromSourceRange(ast, sourceRange)
|
||||||
|
const callExpression = getNodeFromPath(ast, thePath) as CallExpression
|
||||||
|
const [xArg, yArg] = callExpression?.arguments || []
|
||||||
|
const x = xArg?.type === 'Literal' ? xArg.value : -1
|
||||||
|
const y = yArg?.type === 'Literal' ? yArg.value : -1
|
||||||
|
console.log(callExpression)
|
||||||
|
return {
|
||||||
|
originalXY: [x, y],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
originalXY: [-1, -1],
|
||||||
|
}
|
||||||
|
}, [ast])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleMouseUp = () => {
|
||||||
|
if (isMouseDown && ast) {
|
||||||
|
const thePath = getNodePathFromSourceRange(ast, sourceRange)
|
||||||
|
const theNewPoints: [number, number] = [
|
||||||
|
roundOff(lastPointerRef.current.x, 2),
|
||||||
|
roundOff(lastPointerRef.current.y, 2),
|
||||||
|
]
|
||||||
|
console.log('theNewPoints', theNewPoints)
|
||||||
|
const { modifiedAst } = changeArguments(ast, thePath, theNewPoints)
|
||||||
|
updateAst(modifiedAst)
|
||||||
|
ref.current.position.set(0, 0, 0)
|
||||||
|
}
|
||||||
|
setIsMouseDown(false)
|
||||||
|
}
|
||||||
|
window.addEventListener('mouseup', handleMouseUp)
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('mouseup', handleMouseUp)
|
||||||
|
}
|
||||||
|
}, [isMouseDown, ast])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<mesh
|
||||||
|
ref={ref}
|
||||||
|
onPointerOver={(event) => {
|
||||||
|
setHover(true)
|
||||||
|
setHighlightRange(sourceRange)
|
||||||
|
}}
|
||||||
|
onPointerOut={(event) => {
|
||||||
|
setHover(false)
|
||||||
|
setHighlightRange([0, 0])
|
||||||
|
}}
|
||||||
|
onPointerDown={() => setIsMouseDown(true)}
|
||||||
|
>
|
||||||
|
<primitive object={geo} scale={hovered ? 2 : 1} />
|
||||||
|
<meshStandardMaterial
|
||||||
|
color={hovered ? 'hotpink' : editorCursor ? 'skyblue' : 'orange'}
|
||||||
|
/>
|
||||||
|
</mesh>
|
||||||
|
{isMouseDown && (
|
||||||
|
<mesh
|
||||||
|
position={[0, 0, 0.05]}
|
||||||
|
onPointerMove={(a) => {
|
||||||
|
const point = a.point
|
||||||
|
if (
|
||||||
|
lastPointerRef.current.x === 0 &&
|
||||||
|
lastPointerRef.current.y === 0 &&
|
||||||
|
lastPointerRef.current.z === 0
|
||||||
|
) {
|
||||||
|
lastPointerRef.current.set(point.x, point.y, point.z)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (guiMode.mode)
|
||||||
|
if (ref.current) {
|
||||||
|
const diff = new Vector3().subVectors(
|
||||||
|
point,
|
||||||
|
lastPointerRef.current
|
||||||
|
)
|
||||||
|
console.log(originalXY)
|
||||||
|
if (originalXY[0] === -1) {
|
||||||
|
diff.x = 0
|
||||||
|
}
|
||||||
|
if (originalXY[1] === -1) {
|
||||||
|
diff.y = 0
|
||||||
|
}
|
||||||
|
ref.current.position.add(diff)
|
||||||
|
lastPointerRef.current.set(point.x, point.y, point.z)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
name="my-mesh"
|
||||||
|
>
|
||||||
|
<planeGeometry args={[50, 50]} />
|
||||||
|
<meshStandardMaterial color="blue" transparent opacity={0.2} />
|
||||||
|
</mesh>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function RenderViewerArtifacts({
|
||||||
|
artifact,
|
||||||
|
forceHighlight = false,
|
||||||
|
}: {
|
||||||
|
artifact: ViewerArtifact
|
||||||
|
forceHighlight?: boolean
|
||||||
|
}) {
|
||||||
|
const { selectionRange } = useStore(({ selectionRange }) => ({
|
||||||
|
selectionRange,
|
||||||
|
}))
|
||||||
|
const [editorCursor, setEditorCursor] = useState(false)
|
||||||
|
useEffect(() => {
|
||||||
|
const shouldHighlight = isOverlapping(artifact.sourceRange, selectionRange)
|
||||||
|
setEditorCursor(shouldHighlight)
|
||||||
|
}, [selectionRange, artifact.sourceRange])
|
||||||
|
if (artifact.type === 'sketchLine') {
|
||||||
|
const { geo, sourceRange } = artifact
|
||||||
|
return (
|
||||||
|
<SketchLine
|
||||||
|
geo={geo}
|
||||||
|
sourceRange={sourceRange}
|
||||||
|
forceHighlight={forceHighlight || editorCursor}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (artifact.type === 'sketchBase') {
|
||||||
|
console.log('BASE TODO')
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{artifact.children.map((artifact, index) => (
|
||||||
|
<RenderViewerArtifacts
|
||||||
|
artifact={artifact}
|
||||||
|
key={index}
|
||||||
|
forceHighlight={forceHighlight || editorCursor}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
@ -1215,6 +1215,38 @@ export function addLine(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function changeArguments(
|
||||||
|
node: Program,
|
||||||
|
pathToNode: (string | number)[],
|
||||||
|
args: [number, number]
|
||||||
|
): { modifiedAst: Program; pathToNode: (string | number)[] }{
|
||||||
|
const _node = { ...node }
|
||||||
|
const dumbyStartend = { start: 0, end: 0 }
|
||||||
|
// const thePath = getNodePathFromSourceRange(_node, sourceRange)
|
||||||
|
const callExpression = getNodeFromPath(_node, pathToNode) as CallExpression
|
||||||
|
const newXArg: CallExpression['arguments'][number] = callExpression.arguments[0].type === 'Literal' ? {
|
||||||
|
type: 'Literal',
|
||||||
|
...dumbyStartend,
|
||||||
|
value: args[0],
|
||||||
|
raw: `${args[0]}`,
|
||||||
|
} : {
|
||||||
|
...callExpression.arguments[0]
|
||||||
|
}
|
||||||
|
const newYArg: CallExpression['arguments'][number] = callExpression.arguments[1].type === 'Literal' ? {
|
||||||
|
type: 'Literal',
|
||||||
|
...dumbyStartend,
|
||||||
|
value: args[1],
|
||||||
|
raw: `${args[1]}`,
|
||||||
|
} : {
|
||||||
|
...callExpression.arguments[1]
|
||||||
|
}
|
||||||
|
callExpression.arguments = [newXArg, newYArg]
|
||||||
|
return {
|
||||||
|
modifiedAst: _node,
|
||||||
|
pathToNode,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function isCallExpression(tokens: Token[], index: number): number {
|
function isCallExpression(tokens: Token[], index: number): number {
|
||||||
const currentToken = tokens[index]
|
const currentToken = tokens[index]
|
||||||
const veryNextToken = tokens[index + 1] // i.e. no whitespace
|
const veryNextToken = tokens[index + 1] // i.e. no whitespace
|
||||||
|
@ -7,15 +7,21 @@ export function baseGeo({ from }: { from: [number, number, number] }) {
|
|||||||
return baseSphere
|
return baseSphere
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface LineGeos {
|
||||||
|
line: BufferGeometry
|
||||||
|
tip: BufferGeometry
|
||||||
|
centre: BufferGeometry
|
||||||
|
}
|
||||||
|
|
||||||
export function lineGeo({
|
export function lineGeo({
|
||||||
from,
|
from,
|
||||||
to,
|
to,
|
||||||
}: {
|
}: {
|
||||||
from: [number, number, number]
|
from: [number, number, number]
|
||||||
to: [number, number, number]
|
to: [number, number, number]
|
||||||
}): BufferGeometry {
|
}): LineGeos {
|
||||||
const sq = (a: number): number => a * a
|
const sq = (a: number): number => a * a
|
||||||
const center = [
|
const centre = [
|
||||||
(from[0] + to[0]) / 2,
|
(from[0] + to[0]) / 2,
|
||||||
(from[1] + to[1]) / 2,
|
(from[1] + to[1]) / 2,
|
||||||
(from[2] + to[2]) / 2,
|
(from[2] + to[2]) / 2,
|
||||||
@ -34,15 +40,23 @@ export function lineGeo({
|
|||||||
const lineBody = new BoxGeometry(Hypotenuse3d, 0.1, 0.1)
|
const lineBody = new BoxGeometry(Hypotenuse3d, 0.1, 0.1)
|
||||||
lineBody.rotateY(ang1)
|
lineBody.rotateY(ang1)
|
||||||
lineBody.rotateZ(ang2)
|
lineBody.rotateZ(ang2)
|
||||||
lineBody.translate(center[0], center[1], center[2])
|
lineBody.translate(centre[0], centre[1], centre[2])
|
||||||
|
|
||||||
// create line end balls with SphereGeometry at `to` and `from` with radius of 0.15
|
// create line end balls with SphereGeometry at `to` and `from` with radius of 0.15
|
||||||
const lineEnd1 = new SphereGeometry(0.15)
|
const lineEnd1 = new SphereGeometry(0.15)
|
||||||
lineEnd1.translate(to[0], to[1], to[2])
|
lineEnd1.translate(to[0], to[1], to[2])
|
||||||
|
|
||||||
|
const centreSphere = new SphereGeometry(0.15)
|
||||||
|
centreSphere.translate(centre[0], centre[1], centre[2])
|
||||||
// const lineEnd2 = new SphereGeometry(0.15);
|
// const lineEnd2 = new SphereGeometry(0.15);
|
||||||
// lineEnd2.translate(from[0], from[1], from[2])
|
// lineEnd2.translate(from[0], from[1], from[2])
|
||||||
|
|
||||||
// group all three geometries
|
// group all three geometries
|
||||||
return mergeBufferGeometries([lineBody, lineEnd1])
|
// return mergeBufferGeometries([lineBody, lineEnd1])
|
||||||
// return mergeBufferGeometries([lineBody, lineEnd1, lineEnd2]);
|
// return mergeBufferGeometries([lineBody, lineEnd1, lineEnd2]);
|
||||||
|
return {
|
||||||
|
line: lineBody,
|
||||||
|
tip: lineEnd1,
|
||||||
|
centre: centreSphere,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import {
|
|||||||
} from './abstractSyntaxTree'
|
} from './abstractSyntaxTree'
|
||||||
import { Path, Transform, SketchGeo, sketchFns } from './sketch'
|
import { Path, Transform, SketchGeo, sketchFns } from './sketch'
|
||||||
import { BufferGeometry } from 'three'
|
import { BufferGeometry } from 'three'
|
||||||
|
import { LineGeos } from './engine'
|
||||||
|
|
||||||
export interface ProgramMemory {
|
export interface ProgramMemory {
|
||||||
root: { [key: string]: any }
|
root: { [key: string]: any }
|
||||||
@ -296,6 +297,11 @@ export type ViewerArtifact =
|
|||||||
| {
|
| {
|
||||||
type: 'sketchLine'
|
type: 'sketchLine'
|
||||||
sourceRange: SourceRange
|
sourceRange: SourceRange
|
||||||
|
geo: LineGeos
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: 'sketchBase',
|
||||||
|
sourceRange: SourceRange,
|
||||||
geo: BufferGeometry
|
geo: BufferGeometry
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
@ -315,7 +321,28 @@ export const processShownObjects = (
|
|||||||
previousTransforms: PreviousTransforms = []
|
previousTransforms: PreviousTransforms = []
|
||||||
): ViewerArtifact[] => {
|
): ViewerArtifact[] => {
|
||||||
if (geoMeta?.type === 'sketchGeo') {
|
if (geoMeta?.type === 'sketchGeo') {
|
||||||
return geoMeta.sketch.map(({ geo, sourceRange }) => {
|
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()
|
const newGeo = geo.clone()
|
||||||
previousTransforms.forEach(({ rotation, transform }) => {
|
previousTransforms.forEach(({ rotation, transform }) => {
|
||||||
newGeo.rotateX(rotation[0])
|
newGeo.rotateX(rotation[0])
|
||||||
@ -323,12 +350,15 @@ export const processShownObjects = (
|
|||||||
newGeo.rotateZ(rotation[2])
|
newGeo.rotateZ(rotation[2])
|
||||||
newGeo.translate(transform[0], transform[1], transform[2])
|
newGeo.translate(transform[0], transform[1], transform[2])
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type: 'sketchLine',
|
type: 'sketchBase',
|
||||||
geo: newGeo,
|
geo: newGeo,
|
||||||
sourceRange,
|
sourceRange,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
console.log('type',type)
|
||||||
|
|
||||||
|
throw new Error('Unknown geo type')
|
||||||
})
|
})
|
||||||
} else if (geoMeta.type === 'transform') {
|
} else if (geoMeta.type === 'transform') {
|
||||||
const referencedVar = geoMeta.sketch
|
const referencedVar = geoMeta.sketch
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { ProgramMemory } from './executor'
|
import { ProgramMemory } from './executor'
|
||||||
import { lineGeo, baseGeo } from './engine'
|
import { lineGeo, baseGeo, LineGeos } from './engine'
|
||||||
import { BufferGeometry } from 'three'
|
import { BufferGeometry } from 'three'
|
||||||
|
|
||||||
type Coords2d = [number, number]
|
type Coords2d = [number, number]
|
||||||
@ -37,7 +37,7 @@ export type Path =
|
|||||||
name?: string
|
name?: string
|
||||||
to: Coords2d
|
to: Coords2d
|
||||||
previousPath: Path
|
previousPath: Path
|
||||||
geo: BufferGeometry
|
geo: LineGeos
|
||||||
sourceRange: SourceRange
|
sourceRange: SourceRange
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
@ -45,7 +45,7 @@ export type Path =
|
|||||||
name?: string
|
name?: string
|
||||||
firstPath: Path
|
firstPath: Path
|
||||||
previousPath: Path
|
previousPath: Path
|
||||||
geo: BufferGeometry
|
geo: LineGeos
|
||||||
sourceRange: SourceRange
|
sourceRange: SourceRange
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
|
Reference in New Issue
Block a user