port over to quanternions

This commit is contained in:
Kurt Hutten IrevDev
2022-12-23 07:37:42 +11:00
parent 6abc0d2798
commit 07a40cdd11
6 changed files with 112 additions and 44 deletions

View File

@ -28,6 +28,7 @@ export const Toolbar = () => {
sketchMode: 'sketchEdit', sketchMode: 'sketchEdit',
pathToNode: guiMode.pathToNode, pathToNode: guiMode.pathToNode,
axis: guiMode.axis, axis: guiMode.axis,
quaternion: guiMode.quaternion,
}) })
}} }}
className="border m-1 px-1 rounded" className="border m-1 px-1 rounded"
@ -51,10 +52,13 @@ export const Toolbar = () => {
className={`border m-1 px-1 rounded ${ className={`border m-1 px-1 rounded ${
guiMode.sketchMode === 'points' && 'bg-gray-400' guiMode.sketchMode === 'points' && 'bg-gray-400'
}`} }`}
onClick={() => setGuiMode({ onClick={() =>
...guiMode, setGuiMode({
sketchMode: guiMode.sketchMode === 'points' ? 'sketchEdit' :'points', ...guiMode,
})} sketchMode:
guiMode.sketchMode === 'points' ? 'sketchEdit' : 'points',
})
}
> >
LineTo{guiMode.sketchMode === 'points' && '✅'} LineTo{guiMode.sketchMode === 'points' && '✅'}
</button> </button>

View File

@ -1,9 +1,10 @@
import { useState } from 'react' import { useState } from 'react'
import { DoubleSide } from 'three' import { DoubleSide, Vector3 } from 'three'
import { useStore } from '../useStore' import { useStore } from '../useStore'
import { Intersection } from '@react-three/fiber' import { Intersection } from '@react-three/fiber'
import { Text } from '@react-three/drei' import { Text } from '@react-three/drei'
import { addSketchTo, Program } from '../lang/abstractSyntaxTree' import { addSketchTo, Program } from '../lang/abstractSyntaxTree'
import { Quaternion } from 'three'
const opacity = 0.1 const opacity = 0.1
@ -52,12 +53,19 @@ export const BasePlanes = () => {
body: [], body: [],
} }
const axis = axisIndex === 0 ? 'xy' : axisIndex === 1 ? 'xz' : 'yz' const axis = axisIndex === 0 ? 'xy' : axisIndex === 1 ? 'xz' : 'yz'
const quaternion = new Quaternion()
if (axisIndex === 1) {
quaternion.setFromAxisAngle(new Vector3(1, 0, 0), Math.PI / 2)
} else if (axisIndex === 2) {
quaternion.setFromAxisAngle(new Vector3(0, 1, 0), Math.PI / 2)
}
const { modifiedAst, id, pathToNode } = addSketchTo(_ast, axis) const { modifiedAst, id, pathToNode } = addSketchTo(_ast, axis)
setGuiMode({ setGuiMode({
mode: 'sketch', mode: 'sketch',
sketchMode: 'sketchEdit', sketchMode: 'sketchEdit',
axis, axis,
quaternion,
pathToNode, pathToNode,
}) })
@ -88,10 +96,20 @@ export const BasePlanes = () => {
transparent transparent
opacity={opacity + (axisIndex === index ? 0.3 : 0)} opacity={opacity + (axisIndex === index ? 0.3 : 0)}
/> />
<Text fontSize={1} color="#555" position={[1, 1, 0.01]} font={'/roboto.woff'}> <Text
fontSize={1}
color="#555"
position={[1, 1, 0.01]}
font={'/roboto.woff'}
>
{index === 0 ? 'xy' : index === 1 ? 'xz' : 'yz'} {index === 0 ? 'xy' : index === 1 ? 'xz' : 'yz'}
</Text> </Text>
<Text fontSize={1} color="#555" position={[1, 1, -0.01]} font={'/roboto.woff'}> <Text
fontSize={1}
color="#555"
position={[1, 1, -0.01]}
font={'/roboto.woff'}
>
{index === 0 ? 'xy' : index === 1 ? 'xz' : 'yz'} {index === 0 ? 'xy' : index === 1 ? 'xz' : 'yz'}
</Text> </Text>
</mesh> </mesh>

View File

@ -10,7 +10,7 @@ import { BufferGeometry } from 'three'
import { useStore } from '../useStore' import { useStore } from '../useStore'
import { isOverlapping } from '../lib/utils' import { isOverlapping } from '../lib/utils'
import { LineGeos } from '../lang/engine' import { LineGeos } from '../lang/engine'
import { Vector3 } from 'three' import { Vector3, DoubleSide, Quaternion, Vector2 } from 'three'
function useHeightlight(sourceRange: [number, number]) { function useHeightlight(sourceRange: [number, number]) {
const { selectionRange, guiMode, setGuiMode, ast } = useStore((s) => ({ const { selectionRange, guiMode, setGuiMode, ast } = useStore((s) => ({
@ -29,13 +29,25 @@ function useHeightlight(sourceRange: [number, number]) {
if (shouldHighlight && guiMode.mode === 'default' && ast) { if (shouldHighlight && guiMode.mode === 'default' && ast) {
const pathToNode = getNodePathFromSourceRange(ast, sourceRange) const pathToNode = getNodePathFromSourceRange(ast, sourceRange)
const piper = getNodeFromPath(ast, pathToNode, 'PipeExpression') 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)
}
const axis = const axis =
piper.type !== 'PipeExpression' piper.type !== 'PipeExpression'
? 'xy' ? 'xy'
: piper?.body?.[1]?.callee?.name === 'rx' : piper?.body?.[1]?.callee?.name === 'rx'
? 'xz' ? 'xz'
: 'yz' : 'yz'
setGuiMode({ mode: 'canEditSketch', pathToNode, axis }) setGuiMode({ mode: 'canEditSketch', pathToNode, axis, quaternion }) // TODO needs fix
setDidSetCanEdit(true) setDidSetCanEdit(true)
} else if ( } else if (
!shouldHighlight && !shouldHighlight &&
@ -122,7 +134,9 @@ function MovingSphere({
editorCursor: boolean editorCursor: boolean
}) { }) {
const ref = useRef<BufferGeometry | undefined>() as any const ref = useRef<BufferGeometry | undefined>() as any
const detectionPlaneRef = useRef<BufferGeometry | undefined>() as any
const lastPointerRef = useRef<Vector3>(new Vector3()) const lastPointerRef = useRef<Vector3>(new Vector3())
const point2DRef = useRef<Vector2>(new Vector2())
const [hovered, setHover] = useState(false) const [hovered, setHover] = useState(false)
const [isMouseDown, setIsMouseDown] = useState(false) const [isMouseDown, setIsMouseDown] = useState(false)
@ -141,7 +155,6 @@ function MovingSphere({
const [xArg, yArg] = callExpression?.arguments || [] const [xArg, yArg] = callExpression?.arguments || []
const x = xArg?.type === 'Literal' ? xArg.value : -1 const x = xArg?.type === 'Literal' ? xArg.value : -1
const y = yArg?.type === 'Literal' ? yArg.value : -1 const y = yArg?.type === 'Literal' ? yArg.value : -1
console.log(callExpression)
return { return {
originalXY: [x, y], originalXY: [x, y],
} }
@ -155,11 +168,11 @@ function MovingSphere({
const handleMouseUp = () => { const handleMouseUp = () => {
if (isMouseDown && ast) { if (isMouseDown && ast) {
const thePath = getNodePathFromSourceRange(ast, sourceRange) const thePath = getNodePathFromSourceRange(ast, sourceRange)
const theNewPoints: [number, number] = [ let [x, y] = [
roundOff(lastPointerRef.current.x, 2), roundOff(point2DRef.current.x, 2),
roundOff(lastPointerRef.current.y, 2), roundOff(point2DRef.current.y, 2),
] ]
console.log('theNewPoints', theNewPoints) let theNewPoints: [number, number] = [x, y]
const { modifiedAst } = changeArguments(ast, thePath, theNewPoints) const { modifiedAst } = changeArguments(ast, thePath, theNewPoints)
updateAst(modifiedAst) updateAst(modifiedAst)
ref.current.position.set(0, 0, 0) ref.current.position.set(0, 0, 0)
@ -172,6 +185,14 @@ function MovingSphere({
} }
}, [isMouseDown, ast]) }, [isMouseDown, ast])
let clickDetectPlaneQuaternion = new Quaternion()
if (
guiMode.mode === 'canEditSketch' ||
(guiMode.mode === 'sketch' && guiMode.sketchMode === 'sketchEdit')
) {
clickDetectPlaneQuaternion = guiMode.quaternion.clone()
}
return ( return (
<> <>
<mesh <mesh
@ -193,9 +214,23 @@ function MovingSphere({
</mesh> </mesh>
{isMouseDown && ( {isMouseDown && (
<mesh <mesh
position={[0, 0, 0.05]} position={[0, 0, -0.05]}
quaternion={clickDetectPlaneQuaternion}
onPointerMove={(a) => { onPointerMove={(a) => {
const point = a.point const point = a.point
const transformedPoint = point.clone()
let inverseQuaternion = new Quaternion()
if (
guiMode.mode === 'canEditSketch' ||
(guiMode.mode === 'sketch' && guiMode.sketchMode === 'sketchEdit')
) {
inverseQuaternion = guiMode.quaternion.clone()
}
inverseQuaternion = inverseQuaternion.invert()
transformedPoint.applyQuaternion(inverseQuaternion)
point2DRef.current.set(transformedPoint.x, transformedPoint.y)
if ( if (
lastPointerRef.current.x === 0 && lastPointerRef.current.x === 0 &&
lastPointerRef.current.y === 0 && lastPointerRef.current.y === 0 &&
@ -223,8 +258,13 @@ function MovingSphere({
}} }}
name="my-mesh" name="my-mesh"
> >
<planeGeometry args={[50, 50]} /> <planeGeometry args={[50, 50]} ref={detectionPlaneRef} />
<meshStandardMaterial color="blue" transparent opacity={0.2} /> <meshStandardMaterial
side={DoubleSide}
color="blue"
transparent
opacity={0}
/>
</mesh> </mesh>
)} )}
</> </>

View File

@ -1,5 +1,5 @@
import { useStore } from '../useStore' import { useStore } from '../useStore'
import { DoubleSide } from 'three' import { DoubleSide, Vector3, Quaternion } from 'three'
import { addLine, Program } from '../lang/abstractSyntaxTree' import { addLine, Program } from '../lang/abstractSyntaxTree'
export const SketchPlane = () => { export const SketchPlane = () => {
@ -14,28 +14,27 @@ export const SketchPlane = () => {
if (guiMode.mode !== 'sketch') { if (guiMode.mode !== 'sketch') {
return null return null
} }
if (guiMode.sketchMode !== 'points' && guiMode.sketchMode !== 'sketchEdit' ) { if (guiMode.sketchMode !== 'points' && guiMode.sketchMode !== 'sketchEdit') {
return null return null
} }
const sketchGridName = 'sketchGrid' const sketchGridName = 'sketchGrid'
const ninety = Math.PI / 2 let clickDetectQuaternion = guiMode.quaternion.clone()
const gridRotation: [number, number, number] = [0, 0, 0]
const clickDetectPlaneRotation: [number, number, number] = [0, 0, 0] let temp = new Quaternion().setFromAxisAngle(
if (guiMode.axis === 'xy') { new Vector3(1, 0, 0),
gridRotation[0] = ninety Math.PI / 2
} else if (guiMode.axis === 'xz') { )
clickDetectPlaneRotation[0] = ninety const gridQuaternion = new Quaternion().multiplyQuaternions(
} else if (guiMode.axis === 'yz') { guiMode.quaternion,
gridRotation[2] = ninety temp
clickDetectPlaneRotation[1] = ninety )
}
return ( return (
<> <>
<mesh <mesh
rotation={clickDetectPlaneRotation} quaternion={clickDetectQuaternion}
name={sketchGridName} name={sketchGridName}
onClick={(e) => { onClick={(e) => {
if (guiMode.sketchMode !== 'points') { if (guiMode.sketchMode !== 'points') {
@ -44,7 +43,12 @@ export const SketchPlane = () => {
const sketchGridIntersection = e.intersections.find( const sketchGridIntersection = e.intersections.find(
({ object }) => object.name === sketchGridName ({ object }) => object.name === sketchGridName
) )
const point = roundy(sketchGridIntersection?.point) const inverseQuaternion = clickDetectQuaternion.clone().invert()
let transformedPoint = sketchGridIntersection?.point.clone()
if (transformedPoint)
transformedPoint.applyQuaternion(inverseQuaternion)
const point = roundy(transformedPoint)
let _ast: Program = ast let _ast: Program = ast
? ast ? ast
: { : {
@ -53,12 +57,7 @@ export const SketchPlane = () => {
end: 0, end: 0,
body: [], body: [],
} }
let addLinePoint: [number, number] = [point.x, point.y] const addLinePoint: [number, number] = [point.x, point.y]
if (guiMode.axis === 'xz') {
addLinePoint = [point.x, point.z]
} else if (guiMode.axis === 'yz') {
addLinePoint = [point.z, point.y]
}
const { modifiedAst } = addLine( const { modifiedAst } = addLine(
_ast, _ast,
guiMode.pathToNode, guiMode.pathToNode,
@ -75,7 +74,10 @@ export const SketchPlane = () => {
transparent transparent
/> />
</mesh> </mesh>
<gridHelper args={[30, 40, 'blue', 'hotpink']} rotation={gridRotation} /> <gridHelper
args={[30, 40, 'blue', 'hotpink']}
quaternion={gridQuaternion}
/>
</> </>
) )
} }

View File

@ -1016,8 +1016,8 @@ export function addSketchTo(
{ {
type: 'Literal', type: 'Literal',
...dumbyStartend, ...dumbyStartend,
value: axis === 'yz' ? -90 : 90, value: axis === 'yz' ? 90 : 90,
raw: axis === 'yz' ? '-90' : '90', raw: axis === 'yz' ? '90' : '90',
}, },
{ {
type: 'PipeSubstitution', type: 'PipeSubstitution',

View File

@ -3,6 +3,7 @@ import { addLineHighlight, EditorView } from './editor/highlightextension'
import { Program, abstractSyntaxTree } from './lang/abstractSyntaxTree' import { Program, abstractSyntaxTree } from './lang/abstractSyntaxTree'
import { recast } from './lang/recast' import { recast } from './lang/recast'
import { lexer } from './lang/tokeniser' import { lexer } from './lang/tokeniser'
import { Quaternion } from 'three'
export type Range = [number, number] export type Range = [number, number]
@ -17,6 +18,7 @@ type GuiModes =
mode: 'sketch' mode: 'sketch'
sketchMode: 'points' sketchMode: 'points'
axis: Plane axis: Plane
quaternion: Quaternion
id?: string id?: string
pathToNode: PathToNode pathToNode: PathToNode
} }
@ -24,8 +26,9 @@ type GuiModes =
mode: 'sketch' mode: 'sketch'
sketchMode: 'sketchEdit' sketchMode: 'sketchEdit'
axis: Plane axis: Plane
quaternion: Quaternion
pathToNode: PathToNode pathToNode: PathToNode
} }
| { | {
mode: 'sketch' mode: 'sketch'
sketchMode: 'selectFace' sketchMode: 'selectFace'
@ -34,7 +37,8 @@ type GuiModes =
mode: 'canEditSketch' mode: 'canEditSketch'
pathToNode: PathToNode pathToNode: PathToNode
axis: Plane axis: Plane
} quaternion: Quaternion
}
interface StoreState { interface StoreState {
editorView: EditorView | null editorView: EditorView | null
@ -121,5 +125,5 @@ export const useStore = create<StoreState>()((set, get) => ({
}, },
setError: (error = '') => { setError: (error = '') => {
set({ errorState: { isError: !!error, error } }) set({ errorState: { isError: !!error, error } })
} },
})) }))