add start of extrude
This commit is contained in:
@ -61,6 +61,51 @@ function SketchLine({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ExtrudeWall({
|
||||||
|
geo,
|
||||||
|
sourceRange,
|
||||||
|
forceHighlight = false,
|
||||||
|
}: {
|
||||||
|
geo: BufferGeometry
|
||||||
|
sourceRange: [number, number]
|
||||||
|
forceHighlight?: boolean
|
||||||
|
}) {
|
||||||
|
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} />
|
||||||
|
<meshStandardMaterial
|
||||||
|
side={DoubleSide}
|
||||||
|
color={hovered ? 'hotpink' : forceHighlight ? 'skyblue' : 'orange'}
|
||||||
|
/>
|
||||||
|
</mesh>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const roundOff = (num: number, places: number): number => {
|
const roundOff = (num: number, places: number): number => {
|
||||||
const x = Math.pow(10, places)
|
const x = Math.pow(10, places)
|
||||||
return Math.round(num * x) / x
|
return Math.round(num * x) / x
|
||||||
@ -187,7 +232,6 @@ function MovingSphere({
|
|||||||
point,
|
point,
|
||||||
lastPointerRef.current
|
lastPointerRef.current
|
||||||
)
|
)
|
||||||
console.log(originalXY)
|
|
||||||
if (originalXY[0] === -1) {
|
if (originalXY[0] === -1) {
|
||||||
diff.x = 0
|
diff.x = 0
|
||||||
}
|
}
|
||||||
@ -279,6 +323,15 @@ export function RenderViewerArtifacts({
|
|||||||
console.log('BASE TODO')
|
console.log('BASE TODO')
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
if (artifact.type === 'extrudeWall') {
|
||||||
|
return (
|
||||||
|
<ExtrudeWall
|
||||||
|
geo={artifact.geo}
|
||||||
|
sourceRange={artifact.sourceRange}
|
||||||
|
forceHighlight={forceHighlight || editorCursor}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{artifact.children.map((artifact, index) => (
|
{artifact.children.map((artifact, index) => (
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
import { BoxGeometry, SphereGeometry, BufferGeometry } from 'three'
|
import {
|
||||||
import { mergeBufferGeometries } from 'three/examples/jsm/utils/BufferGeometryUtils'
|
BoxGeometry,
|
||||||
|
SphereGeometry,
|
||||||
|
BufferGeometry,
|
||||||
|
PlaneGeometry,
|
||||||
|
} from 'three'
|
||||||
|
|
||||||
export function baseGeo({ from }: { from: [number, number, number] }) {
|
export function baseGeo({ from }: { from: [number, number, number] }) {
|
||||||
const baseSphere = new SphereGeometry(0.25)
|
const baseSphere = new SphereGeometry(0.25)
|
||||||
@ -7,6 +11,39 @@ export function baseGeo({ from }: { from: [number, number, number] }) {
|
|||||||
return baseSphere
|
return baseSphere
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function trigCalcs({
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
}: {
|
||||||
|
from: [number, number, number]
|
||||||
|
to: [number, number, number]
|
||||||
|
}) {
|
||||||
|
const sq = (a: number): number => a * a
|
||||||
|
const centre = [
|
||||||
|
(from[0] + to[0]) / 2,
|
||||||
|
(from[1] + to[1]) / 2,
|
||||||
|
(from[2] + to[2]) / 2,
|
||||||
|
]
|
||||||
|
const Hypotenuse3d = Math.sqrt(
|
||||||
|
sq(from[0] - to[0]) + sq(from[1] - to[1]) + sq(from[2] - to[2])
|
||||||
|
)
|
||||||
|
const ry = Math.atan2(from[2] - to[2], from[0] - to[0])
|
||||||
|
const Hypotenuse2d = Math.sqrt(sq(from[0] - to[0]) + sq(from[2] - to[2]))
|
||||||
|
const rz =
|
||||||
|
Math.abs(Math.atan((to[1] - from[1]) / Hypotenuse2d)) *
|
||||||
|
Math.sign(to[1] - from[1]) *
|
||||||
|
(Math.sign(to[0] - from[0]) || 1)
|
||||||
|
|
||||||
|
const sign = ry === 0 ? 1 : -1
|
||||||
|
return {
|
||||||
|
centre,
|
||||||
|
Hypotenuse: Hypotenuse3d,
|
||||||
|
ry,
|
||||||
|
rz,
|
||||||
|
sign,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export interface LineGeos {
|
export interface LineGeos {
|
||||||
line: BufferGeometry
|
line: BufferGeometry
|
||||||
tip: BufferGeometry
|
tip: BufferGeometry
|
||||||
@ -20,26 +57,18 @@ export function lineGeo({
|
|||||||
from: [number, number, number]
|
from: [number, number, number]
|
||||||
to: [number, number, number]
|
to: [number, number, number]
|
||||||
}): LineGeos {
|
}): LineGeos {
|
||||||
const sq = (a: number): number => a * a
|
const {
|
||||||
const centre = [
|
centre,
|
||||||
(from[0] + to[0]) / 2,
|
Hypotenuse: Hypotenuse3d,
|
||||||
(from[1] + to[1]) / 2,
|
ry,
|
||||||
(from[2] + to[2]) / 2,
|
rz,
|
||||||
]
|
// sign,
|
||||||
const Hypotenuse3d = Math.sqrt(
|
} = trigCalcs({ from, to })
|
||||||
sq(from[0] - to[0]) + sq(from[1] - to[1]) + sq(from[2] - to[2])
|
|
||||||
)
|
|
||||||
const ang1 = Math.atan2(from[2] - to[2], from[0] - to[0])
|
|
||||||
const Hypotenuse2d = Math.sqrt(sq(from[0] - to[0]) + sq(from[2] - to[2]))
|
|
||||||
const ang2 =
|
|
||||||
Math.abs(Math.atan((to[1] - from[1]) / Hypotenuse2d)) *
|
|
||||||
Math.sign(to[1] - from[1]) *
|
|
||||||
(Math.sign(to[0] - from[0]) || 1)
|
|
||||||
|
|
||||||
// create BoxGeometry with size [Hypotenuse3d, 0.1, 0.1] centered at center, with rotation of [0, ang1, ang2]
|
// create BoxGeometry with size [Hypotenuse3d, 0.1, 0.1] centered at center, with rotation of [0, ry, rz]
|
||||||
const lineBody = new BoxGeometry(Hypotenuse3d, 0.1, 0.1)
|
const lineBody = new BoxGeometry(Hypotenuse3d, 0.1, 0.1)
|
||||||
lineBody.rotateY(ang1)
|
lineBody.rotateY(ry)
|
||||||
lineBody.rotateZ(ang2)
|
lineBody.rotateZ(rz)
|
||||||
lineBody.translate(centre[0], centre[1], centre[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
|
||||||
@ -51,12 +80,41 @@ export function lineGeo({
|
|||||||
// 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
|
|
||||||
// return mergeBufferGeometries([lineBody, lineEnd1])
|
|
||||||
// return mergeBufferGeometries([lineBody, lineEnd1, lineEnd2]);
|
|
||||||
return {
|
return {
|
||||||
line: lineBody,
|
line: lineBody,
|
||||||
tip: lineEnd1,
|
tip: lineEnd1,
|
||||||
centre: centreSphere,
|
centre: centreSphere,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface extrudeWallGeo {
|
||||||
|
line: BufferGeometry
|
||||||
|
tip: BufferGeometry
|
||||||
|
centre: BufferGeometry
|
||||||
|
}
|
||||||
|
|
||||||
|
export function extrudeGeo({
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
}: {
|
||||||
|
from: [number, number, number]
|
||||||
|
to: [number, number, number]
|
||||||
|
}): BufferGeometry {
|
||||||
|
const {
|
||||||
|
// centre,
|
||||||
|
Hypotenuse: Hypotenuse3d,
|
||||||
|
ry,
|
||||||
|
rz,
|
||||||
|
sign,
|
||||||
|
} = trigCalcs({ from, to })
|
||||||
|
|
||||||
|
const face = new PlaneGeometry(Hypotenuse3d, 4, 2, 2)
|
||||||
|
face.rotateX(Math.PI / 2)
|
||||||
|
face.translate(Hypotenuse3d / 2, 0, -2 * sign)
|
||||||
|
|
||||||
|
face.rotateY(ry)
|
||||||
|
face.rotateZ(rz)
|
||||||
|
face.translate(to[0], to[1], to[2])
|
||||||
|
|
||||||
|
return face
|
||||||
|
}
|
||||||
|
@ -77,8 +77,7 @@ show(mySketch)
|
|||||||
sourceRange: [93, 100],
|
sourceRange: [93, 100],
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
expect(root.mySketch.sketch[0]).toEqual(root.mySketch.sketch[4].firstPath)
|
// expect(root.mySketch.sketch[0]).toEqual(root.mySketch.sketch[4].firstPath)
|
||||||
// hmm not sure what handle the "show" function
|
|
||||||
expect(_return).toEqual([
|
expect(_return).toEqual([
|
||||||
{
|
{
|
||||||
type: 'Identifier',
|
type: 'Identifier',
|
||||||
@ -195,11 +194,14 @@ function exe(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function removeGeoFromSketch(sketch: Transform | SketchGeo): any {
|
function removeGeoFromSketch(sketch: Transform | SketchGeo): any {
|
||||||
if (sketch.type !== 'sketchGeo') {
|
if (sketch.type !== 'sketchGeo' && sketch.type === 'transform') {
|
||||||
return removeGeoFromSketch(sketch.sketch)
|
return removeGeoFromSketch(sketch.sketch as any) // TODO fix type
|
||||||
}
|
}
|
||||||
return {
|
if (sketch.type === 'sketchGeo') {
|
||||||
...sketch,
|
return {
|
||||||
sketch: sketch.sketch.map(({ geo, previousPath, ...rest }: any) => rest),
|
...sketch,
|
||||||
|
sketch: sketch.sketch.map(({ geo, previousPath, ...rest }: any) => rest),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
throw new Error('not a sketch')
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import {
|
|||||||
BinaryExpression,
|
BinaryExpression,
|
||||||
PipeExpression,
|
PipeExpression,
|
||||||
} from './abstractSyntaxTree'
|
} from './abstractSyntaxTree'
|
||||||
import { Path, Transform, SketchGeo, sketchFns } from './sketch'
|
import { Path, Transform, SketchGeo, sketchFns, ExtrudeGeo } from './sketch'
|
||||||
import { BufferGeometry, Quaternion } from 'three'
|
import { BufferGeometry, Quaternion } from 'three'
|
||||||
import { LineGeos } from './engine'
|
import { LineGeos } from './engine'
|
||||||
|
|
||||||
@ -95,7 +95,7 @@ export const executor = (
|
|||||||
return executor(fnInit.body, fnMemory, { bodyType: 'block' }).return
|
return executor(fnInit.body, fnMemory, { bodyType: 'block' }).return
|
||||||
}
|
}
|
||||||
} else if (declaration.init.type === 'CallExpression') {
|
} else if (declaration.init.type === 'CallExpression') {
|
||||||
const fnName = declaration.init.callee.name
|
const functionName = declaration.init.callee.name
|
||||||
const fnArgs = declaration.init.arguments.map((arg) => {
|
const fnArgs = declaration.init.arguments.map((arg) => {
|
||||||
if (arg.type === 'Literal') {
|
if (arg.type === 'Literal') {
|
||||||
return arg.value
|
return arg.value
|
||||||
@ -103,13 +103,17 @@ export const executor = (
|
|||||||
return _programMemory.root[arg.name]
|
return _programMemory.root[arg.name]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if ('lineTo' === fnName || 'close' === fnName || 'base' === fnName) {
|
if (
|
||||||
|
'lineTo' === functionName ||
|
||||||
|
'close' === functionName ||
|
||||||
|
'base' === functionName
|
||||||
|
) {
|
||||||
if (options.bodyType !== 'sketch') {
|
if (options.bodyType !== 'sketch') {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Cannot call ${fnName} outside of a sketch declaration`
|
`Cannot call ${functionName} outside of a sketch declaration`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
const result = sketchFns[fnName](
|
const result = sketchFns[functionName](
|
||||||
_programMemory,
|
_programMemory,
|
||||||
variableName,
|
variableName,
|
||||||
[declaration.start, declaration.end],
|
[declaration.start, declaration.end],
|
||||||
@ -117,22 +121,39 @@ export const executor = (
|
|||||||
)
|
)
|
||||||
_programMemory._sketch = result.programMemory._sketch
|
_programMemory._sketch = result.programMemory._sketch
|
||||||
_programMemory.root[variableName] = result.currentPath
|
_programMemory.root[variableName] = result.currentPath
|
||||||
} else if ('rx' === fnName || 'ry' === fnName || 'rz' === fnName) {
|
} else if (
|
||||||
|
'rx' === functionName ||
|
||||||
|
'ry' === functionName ||
|
||||||
|
'rz' === functionName
|
||||||
|
) {
|
||||||
const sketch = declaration.init.arguments[1]
|
const sketch = declaration.init.arguments[1]
|
||||||
if (sketch.type !== 'Identifier')
|
if (sketch.type !== 'Identifier')
|
||||||
throw new Error('rx must be called with an identifier')
|
throw new Error('rx must be called with an identifier')
|
||||||
const sketchVal = _programMemory.root[sketch.name]
|
const sketchVal = _programMemory.root[sketch.name]
|
||||||
const result = sketchFns[fnName](
|
const result = sketchFns[functionName](
|
||||||
_programMemory,
|
_programMemory,
|
||||||
[declaration.start, declaration.end],
|
[declaration.start, declaration.end],
|
||||||
fnArgs[0],
|
fnArgs[0],
|
||||||
sketchVal
|
sketchVal
|
||||||
)
|
)
|
||||||
_programMemory.root[variableName] = result
|
_programMemory.root[variableName] = result
|
||||||
} else {
|
} else if (functionName === 'extrude') {
|
||||||
_programMemory.root[variableName] = _programMemory.root[fnName](
|
const sketch = declaration.init.arguments[1]
|
||||||
...fnArgs
|
if (sketch.type !== 'Identifier')
|
||||||
|
throw new Error('extrude must be called with an identifier')
|
||||||
|
const sketchVal = _programMemory.root[sketch.name]
|
||||||
|
const result = sketchFns[functionName](
|
||||||
|
_programMemory,
|
||||||
|
'yo',
|
||||||
|
[declaration.start, declaration.end],
|
||||||
|
fnArgs[0],
|
||||||
|
sketchVal
|
||||||
)
|
)
|
||||||
|
_programMemory.root[variableName] = result
|
||||||
|
} else {
|
||||||
|
_programMemory.root[variableName] = _programMemory.root[
|
||||||
|
functionName
|
||||||
|
](...fnArgs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -227,7 +248,7 @@ function executePipeBody(
|
|||||||
result,
|
result,
|
||||||
])
|
])
|
||||||
} else if (expression.type === 'CallExpression') {
|
} else if (expression.type === 'CallExpression') {
|
||||||
const fnName = expression.callee.name
|
const functionName = expression.callee.name
|
||||||
const fnArgs = expression.arguments.map((arg) => {
|
const fnArgs = expression.arguments.map((arg) => {
|
||||||
if (arg.type === 'Literal') {
|
if (arg.type === 'Literal') {
|
||||||
return arg.value
|
return arg.value
|
||||||
@ -238,8 +259,12 @@ function executePipeBody(
|
|||||||
}
|
}
|
||||||
throw new Error('Invalid argument type')
|
throw new Error('Invalid argument type')
|
||||||
})
|
})
|
||||||
if ('rx' === fnName || 'ry' === fnName || 'rz' === fnName) {
|
if (
|
||||||
const result = sketchFns[fnName](
|
'rx' === functionName ||
|
||||||
|
'ry' === functionName ||
|
||||||
|
'rz' === functionName
|
||||||
|
) {
|
||||||
|
const result = sketchFns[functionName](
|
||||||
programMemory,
|
programMemory,
|
||||||
[expression.start, expression.end],
|
[expression.start, expression.end],
|
||||||
fnArgs[0],
|
fnArgs[0],
|
||||||
@ -250,7 +275,20 @@ function executePipeBody(
|
|||||||
result,
|
result,
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
const result = programMemory.root[fnName](...fnArgs)
|
if (functionName === 'extrude') {
|
||||||
|
const result = sketchFns[functionName](
|
||||||
|
programMemory,
|
||||||
|
'yo',
|
||||||
|
[expression.start, expression.end],
|
||||||
|
fnArgs[0],
|
||||||
|
fnArgs[1]
|
||||||
|
)
|
||||||
|
return executePipeBody(body, programMemory, expressionIndex + 1, [
|
||||||
|
...previousResults,
|
||||||
|
result,
|
||||||
|
])
|
||||||
|
}
|
||||||
|
const result = programMemory.root[functionName](...fnArgs)
|
||||||
return executePipeBody(body, programMemory, expressionIndex + 1, [
|
return executePipeBody(body, programMemory, expressionIndex + 1, [
|
||||||
...previousResults,
|
...previousResults,
|
||||||
result,
|
result,
|
||||||
@ -304,6 +342,11 @@ export type ViewerArtifact =
|
|||||||
sourceRange: SourceRange
|
sourceRange: SourceRange
|
||||||
geo: BufferGeometry
|
geo: BufferGeometry
|
||||||
}
|
}
|
||||||
|
| {
|
||||||
|
type: 'extrudeWall'
|
||||||
|
sourceRange: SourceRange
|
||||||
|
geo: BufferGeometry
|
||||||
|
}
|
||||||
| {
|
| {
|
||||||
type: 'parent'
|
type: 'parent'
|
||||||
sourceRange: SourceRange
|
sourceRange: SourceRange
|
||||||
@ -322,7 +365,7 @@ type PreviousTransforms = {
|
|||||||
|
|
||||||
export const processShownObjects = (
|
export const processShownObjects = (
|
||||||
programMemory: ProgramMemory,
|
programMemory: ProgramMemory,
|
||||||
geoMeta: SketchGeo | Transform,
|
geoMeta: SketchGeo | ExtrudeGeo | Transform,
|
||||||
previousTransforms: PreviousTransforms = []
|
previousTransforms: PreviousTransforms = []
|
||||||
): ViewerArtifact[] => {
|
): ViewerArtifact[] => {
|
||||||
if (geoMeta?.type === 'sketchGeo') {
|
if (geoMeta?.type === 'sketchGeo') {
|
||||||
@ -349,7 +392,7 @@ export const processShownObjects = (
|
|||||||
sourceRange,
|
sourceRange,
|
||||||
}
|
}
|
||||||
} else if (type === 'base') {
|
} else if (type === 'base') {
|
||||||
const newGeo = geo.clone()
|
const newGeo: BufferGeometry = geo.clone()
|
||||||
previousTransforms.forEach(({ rotation, transform }) => {
|
previousTransforms.forEach(({ rotation, transform }) => {
|
||||||
newGeo.applyQuaternion(rotation)
|
newGeo.applyQuaternion(rotation)
|
||||||
newGeo.translate(transform[0], transform[1], transform[2])
|
newGeo.translate(transform[0], transform[1], transform[2])
|
||||||
@ -378,7 +421,19 @@ export const processShownObjects = (
|
|||||||
]),
|
]),
|
||||||
}
|
}
|
||||||
return [parentArtifact]
|
return [parentArtifact]
|
||||||
}
|
} else if (geoMeta.type === 'extrudeGeo') {
|
||||||
|
const result: ViewerArtifact[] = geoMeta.surfaces.map((a) => {
|
||||||
|
const geo: BufferGeometry = a.geo.clone()
|
||||||
|
|
||||||
|
geo.applyQuaternion(a.quaternion)
|
||||||
|
geo.translate(a.translate[0], a.translate[1], a.translate[2])
|
||||||
|
return {
|
||||||
|
type: 'extrudeWall',
|
||||||
|
sourceRange: a.sourceRanges[0],
|
||||||
|
geo,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return result
|
||||||
|
}
|
||||||
throw new Error('Unknown geoMeta type')
|
throw new Error('Unknown geoMeta type')
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { ProgramMemory } from './executor'
|
import { ProgramMemory } from './executor'
|
||||||
import { lineGeo, baseGeo, LineGeos } from './engine'
|
import { lineGeo, baseGeo, LineGeos, extrudeGeo } from './engine'
|
||||||
import { BufferGeometry } from 'three'
|
import { BufferGeometry } from 'three'
|
||||||
import { Quaternion, Vector3 } from 'three'
|
import { Quaternion, Vector3 } from 'three'
|
||||||
|
|
||||||
@ -21,7 +21,6 @@ export type Path =
|
|||||||
type: 'horizontalLineTo'
|
type: 'horizontalLineTo'
|
||||||
name?: string
|
name?: string
|
||||||
x: number
|
x: number
|
||||||
previousPath: Path
|
|
||||||
geo: BufferGeometry
|
geo: BufferGeometry
|
||||||
sourceRange: SourceRange
|
sourceRange: SourceRange
|
||||||
}
|
}
|
||||||
@ -29,7 +28,6 @@ export type Path =
|
|||||||
type: 'verticalLineTo'
|
type: 'verticalLineTo'
|
||||||
name?: string
|
name?: string
|
||||||
y: number
|
y: number
|
||||||
previousPath: Path
|
|
||||||
geo: BufferGeometry
|
geo: BufferGeometry
|
||||||
sourceRange: SourceRange
|
sourceRange: SourceRange
|
||||||
}
|
}
|
||||||
@ -37,15 +35,12 @@ export type Path =
|
|||||||
type: 'toPoint'
|
type: 'toPoint'
|
||||||
name?: string
|
name?: string
|
||||||
to: Coords2d
|
to: Coords2d
|
||||||
previousPath: Path
|
|
||||||
geo: LineGeos
|
geo: LineGeos
|
||||||
sourceRange: SourceRange
|
sourceRange: SourceRange
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
type: 'close'
|
type: 'close'
|
||||||
name?: string
|
name?: string
|
||||||
firstPath: Path
|
|
||||||
previousPath: Path
|
|
||||||
geo: LineGeos
|
geo: LineGeos
|
||||||
sourceRange: SourceRange
|
sourceRange: SourceRange
|
||||||
}
|
}
|
||||||
@ -60,7 +55,7 @@ export interface Transform {
|
|||||||
type: 'transform'
|
type: 'transform'
|
||||||
rotation: Rotation3
|
rotation: Rotation3
|
||||||
transform: Translate3
|
transform: Translate3
|
||||||
sketch: SketchGeo | Transform
|
sketch: SketchGeo | ExtrudeGeo | Transform
|
||||||
sourceRange: SourceRange
|
sourceRange: SourceRange
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,6 +65,20 @@ export interface SketchGeo {
|
|||||||
sourceRange: SourceRange
|
sourceRange: SourceRange
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ExtrudeFace {
|
||||||
|
type: 'extrudeFace'
|
||||||
|
quaternion: Quaternion
|
||||||
|
translate: [number, number, number]
|
||||||
|
geo: BufferGeometry
|
||||||
|
sourceRanges: SourceRange[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExtrudeGeo {
|
||||||
|
type: 'extrudeGeo'
|
||||||
|
surfaces: ExtrudeFace[]
|
||||||
|
sourceRange: SourceRange
|
||||||
|
}
|
||||||
|
|
||||||
function addBasePath(programMemory: ProgramMemory) {
|
function addBasePath(programMemory: ProgramMemory) {
|
||||||
const geo = baseGeo({ from: [0, 0, 0] })
|
const geo = baseGeo({ from: [0, 0, 0] })
|
||||||
const base: Path = {
|
const base: Path = {
|
||||||
@ -159,8 +168,6 @@ export const sketchFns = {
|
|||||||
|
|
||||||
const newPath: Path = {
|
const newPath: Path = {
|
||||||
type: 'close',
|
type: 'close',
|
||||||
firstPath,
|
|
||||||
previousPath: lastPath,
|
|
||||||
geo: lineGeo({ from: [...from, 0], to: [...to, 0] }),
|
geo: lineGeo({ from: [...from, 0], to: [...to, 0] }),
|
||||||
sourceRange,
|
sourceRange,
|
||||||
}
|
}
|
||||||
@ -195,7 +202,6 @@ export const sketchFns = {
|
|||||||
const currentPath: Path = {
|
const currentPath: Path = {
|
||||||
type: 'toPoint',
|
type: 'toPoint',
|
||||||
to: [x, y],
|
to: [x, y],
|
||||||
previousPath: lastPath,
|
|
||||||
geo: lineGeo({ from: [...from, 0], to: [x, y, 0] }),
|
geo: lineGeo({ from: [...from, 0], to: [x, y, 0] }),
|
||||||
sourceRange,
|
sourceRange,
|
||||||
}
|
}
|
||||||
@ -213,6 +219,101 @@ export const sketchFns = {
|
|||||||
rx: RotateOnAxis([1, 0, 0]),
|
rx: RotateOnAxis([1, 0, 0]),
|
||||||
ry: RotateOnAxis([0, 1, 0]),
|
ry: RotateOnAxis([0, 1, 0]),
|
||||||
rz: RotateOnAxis([0, 0, 1]),
|
rz: RotateOnAxis([0, 0, 1]),
|
||||||
|
extrude: (
|
||||||
|
programMemory: ProgramMemory,
|
||||||
|
name: string = '',
|
||||||
|
sourceRange: SourceRange,
|
||||||
|
length: any,
|
||||||
|
// sketchVal: any
|
||||||
|
sketchVal: SketchGeo | Transform
|
||||||
|
): ExtrudeGeo | Transform => {
|
||||||
|
const getSketchGeo = (sketchVal: SketchGeo | Transform): SketchGeo => {
|
||||||
|
if (
|
||||||
|
sketchVal.type === 'transform' &&
|
||||||
|
sketchVal.sketch.type === 'extrudeGeo'
|
||||||
|
)
|
||||||
|
throw new Error('Cannot extrude a extrude')
|
||||||
|
return sketchVal.type === 'transform'
|
||||||
|
? getSketchGeo(sketchVal.sketch as any) // TODO fix types
|
||||||
|
: (sketchVal as SketchGeo) // TODO fix types
|
||||||
|
}
|
||||||
|
interface CombinedTransforms {
|
||||||
|
position: [number, number, number]
|
||||||
|
quaternion: Quaternion
|
||||||
|
}
|
||||||
|
const combineATransforms = (
|
||||||
|
translate: [number, number, number],
|
||||||
|
rotate: Quaternion,
|
||||||
|
currentPosition: [number, number, number],
|
||||||
|
currentRotation: Quaternion
|
||||||
|
): CombinedTransforms => {
|
||||||
|
const newPosition = new Vector3(...currentPosition).applyQuaternion(
|
||||||
|
rotate
|
||||||
|
)
|
||||||
|
newPosition.add(new Vector3(...translate))
|
||||||
|
const newQuaternion = new Quaternion().multiplyQuaternions(
|
||||||
|
rotate.clone(),
|
||||||
|
currentRotation
|
||||||
|
)
|
||||||
|
return {
|
||||||
|
position: [newPosition.x, newPosition.y, newPosition.z],
|
||||||
|
quaternion: newQuaternion,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const transformFromSketch = (
|
||||||
|
sketchVal: SketchGeo | ExtrudeGeo | Transform,
|
||||||
|
currentPosition: [number, number, number] = [0, 0, 0],
|
||||||
|
currentRotation: Quaternion = new Quaternion()
|
||||||
|
): CombinedTransforms => {
|
||||||
|
if (sketchVal.type === 'transform') {
|
||||||
|
const { transform, rotation } = sketchVal
|
||||||
|
const { position, quaternion } = combineATransforms(
|
||||||
|
transform,
|
||||||
|
rotation,
|
||||||
|
currentPosition,
|
||||||
|
currentRotation
|
||||||
|
)
|
||||||
|
return transformFromSketch(sketchVal.sketch, position, quaternion)
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
position: currentPosition,
|
||||||
|
quaternion: currentRotation,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const sketch = getSketchGeo(sketchVal)
|
||||||
|
const { position, quaternion } = transformFromSketch(sketchVal)
|
||||||
|
|
||||||
|
const extrudeFaces: ExtrudeFace[] = []
|
||||||
|
console.log('sketch', sketch)
|
||||||
|
sketch.sketch.map((line, index) => {
|
||||||
|
if (line.type === 'toPoint' && index !== 0) {
|
||||||
|
const lastPoint = sketch.sketch[index - 1]
|
||||||
|
let from: [number, number] = [0, 0]
|
||||||
|
if (lastPoint.type === 'toPoint') {
|
||||||
|
from = lastPoint.to
|
||||||
|
} else if (lastPoint.type === 'base') {
|
||||||
|
from = lastPoint.from
|
||||||
|
}
|
||||||
|
const to = line.to
|
||||||
|
const geo = extrudeGeo({
|
||||||
|
from: [from[0], from[1], 0],
|
||||||
|
to: [to[0], to[1], 0],
|
||||||
|
})
|
||||||
|
extrudeFaces.push({
|
||||||
|
type: 'extrudeFace',
|
||||||
|
quaternion,
|
||||||
|
translate: position,
|
||||||
|
geo,
|
||||||
|
sourceRanges: [line.sourceRange, sourceRange],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
type: 'extrudeGeo',
|
||||||
|
sourceRange,
|
||||||
|
surfaces: extrudeFaces,
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
function RotateOnAxis(axisMultiplier: [number, number, number]) {
|
function RotateOnAxis(axisMultiplier: [number, number, number]) {
|
||||||
|
Reference in New Issue
Block a user