cleanup code we are no longer using (#319)
Signed-off-by: Jess Frazelle <github@jessfraz.com>
This commit is contained in:
@ -1,80 +0,0 @@
|
|||||||
import { InternalFn } from './stdTypes'
|
|
||||||
import {
|
|
||||||
ExtrudeGroup,
|
|
||||||
ExtrudeSurface,
|
|
||||||
SketchGroup,
|
|
||||||
Position,
|
|
||||||
Rotation,
|
|
||||||
} from '../executor'
|
|
||||||
import { clockwiseSign } from './std'
|
|
||||||
import { generateUuidFromHashSeed } from '../../lib/uuid'
|
|
||||||
|
|
||||||
export const extrude: InternalFn = (
|
|
||||||
{ sourceRange, engineCommandManager, code },
|
|
||||||
length: number,
|
|
||||||
sketchVal: SketchGroup
|
|
||||||
): ExtrudeGroup => {
|
|
||||||
const sketch = sketchVal
|
|
||||||
const { position, rotation } = sketchVal
|
|
||||||
|
|
||||||
const id = generateUuidFromHashSeed(
|
|
||||||
JSON.stringify({
|
|
||||||
code,
|
|
||||||
sourceRange,
|
|
||||||
data: {
|
|
||||||
length,
|
|
||||||
sketchVal,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
const extrudeSurfaces: ExtrudeSurface[] = []
|
|
||||||
const extrusionDirection = clockwiseSign(sketch.value.map((line) => line.to))
|
|
||||||
engineCommandManager.sendModelingCommand({
|
|
||||||
id,
|
|
||||||
range: sourceRange,
|
|
||||||
command: {
|
|
||||||
type: 'modeling_cmd_req',
|
|
||||||
cmd: {
|
|
||||||
type: 'extrude',
|
|
||||||
target: sketch.id,
|
|
||||||
distance: length,
|
|
||||||
cap: true,
|
|
||||||
},
|
|
||||||
cmd_id: id,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
return {
|
|
||||||
type: 'extrudeGroup',
|
|
||||||
id,
|
|
||||||
value: extrudeSurfaces, // TODO, this is just an empty array now, should be deleted.
|
|
||||||
height: length,
|
|
||||||
position,
|
|
||||||
rotation,
|
|
||||||
__meta: [
|
|
||||||
{
|
|
||||||
sourceRange,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
sourceRange: sketchVal.__meta[0].sourceRange,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getExtrudeWallTransform: InternalFn = (
|
|
||||||
_,
|
|
||||||
pathName: string,
|
|
||||||
extrudeGroup: ExtrudeGroup
|
|
||||||
): {
|
|
||||||
position: Position
|
|
||||||
quaternion: Rotation
|
|
||||||
} => {
|
|
||||||
const path = extrudeGroup?.value.find((path) => path.name === pathName)
|
|
||||||
if (!path) throw new Error(`Could not find path with name ${pathName}`)
|
|
||||||
return {
|
|
||||||
position: path.position,
|
|
||||||
quaternion: path.rotation,
|
|
||||||
}
|
|
||||||
}
|
|
@ -23,12 +23,7 @@ import { GuiModes, toolTips, TooTip } from '../../useStore'
|
|||||||
import { splitPathAtPipeExpression } from '../modifyAst'
|
import { splitPathAtPipeExpression } from '../modifyAst'
|
||||||
import { generateUuidFromHashSeed } from '../../lib/uuid'
|
import { generateUuidFromHashSeed } from '../../lib/uuid'
|
||||||
|
|
||||||
import {
|
import { SketchLineHelper, ModifyAstBase, TransformCallback } from './stdTypes'
|
||||||
SketchLineHelper,
|
|
||||||
ModifyAstBase,
|
|
||||||
InternalFn,
|
|
||||||
TransformCallback,
|
|
||||||
} from './stdTypes'
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
createLiteral,
|
createLiteral,
|
||||||
@ -42,10 +37,7 @@ import {
|
|||||||
} from '../modifyAst'
|
} from '../modifyAst'
|
||||||
import { roundOff, getLength, getAngle } from '../../lib/utils'
|
import { roundOff, getLength, getAngle } from '../../lib/utils'
|
||||||
import { getSketchSegmentFromSourceRange } from './sketchConstraints'
|
import { getSketchSegmentFromSourceRange } from './sketchConstraints'
|
||||||
import {
|
import { perpendicularDistance } from 'sketch-helpers'
|
||||||
intersectionWithParallelLine,
|
|
||||||
perpendicularDistance,
|
|
||||||
} from 'sketch-helpers'
|
|
||||||
|
|
||||||
export type Coords2d = [number, number]
|
export type Coords2d = [number, number]
|
||||||
|
|
||||||
@ -115,44 +107,6 @@ function makeId(seed: string | any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const lineTo: SketchLineHelper = {
|
export const lineTo: SketchLineHelper = {
|
||||||
fn: (
|
|
||||||
{ sourceRange, code },
|
|
||||||
data:
|
|
||||||
| [number, number]
|
|
||||||
| {
|
|
||||||
to: [number, number]
|
|
||||||
tag?: string
|
|
||||||
},
|
|
||||||
previousSketch: SketchGroup
|
|
||||||
): SketchGroup => {
|
|
||||||
if (!previousSketch)
|
|
||||||
throw new Error('lineTo must be called after startSketchAt')
|
|
||||||
const sketchGroup = { ...previousSketch }
|
|
||||||
const from = getCoordsFromPaths(sketchGroup, sketchGroup.value.length - 1)
|
|
||||||
const to = 'to' in data ? data.to : data
|
|
||||||
|
|
||||||
const id = makeId({
|
|
||||||
code,
|
|
||||||
sourceRange,
|
|
||||||
data,
|
|
||||||
})
|
|
||||||
const currentPath: Path = {
|
|
||||||
type: 'toPoint',
|
|
||||||
to,
|
|
||||||
from,
|
|
||||||
__geoMeta: {
|
|
||||||
sourceRange,
|
|
||||||
id,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if ('tag' in data) {
|
|
||||||
currentPath.name = data.tag
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
...sketchGroup,
|
|
||||||
value: [...sketchGroup.value, currentPath],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
add: ({
|
add: ({
|
||||||
node,
|
node,
|
||||||
pathToNode,
|
pathToNode,
|
||||||
@ -220,75 +174,6 @@ export const lineTo: SketchLineHelper = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const line: SketchLineHelper = {
|
export const line: SketchLineHelper = {
|
||||||
fn: (
|
|
||||||
{ sourceRange, engineCommandManager, code },
|
|
||||||
data:
|
|
||||||
| [number, number]
|
|
||||||
| 'default'
|
|
||||||
| {
|
|
||||||
to: [number, number] | 'default'
|
|
||||||
// name?: string
|
|
||||||
tag?: string
|
|
||||||
},
|
|
||||||
previousSketch: SketchGroup
|
|
||||||
): SketchGroup => {
|
|
||||||
if (!previousSketch) throw new Error('lineTo must be called after lineTo')
|
|
||||||
const sketchGroup = { ...previousSketch }
|
|
||||||
const from = getCoordsFromPaths(sketchGroup, sketchGroup.value.length - 1)
|
|
||||||
let args: [number, number] = [0.2, 1]
|
|
||||||
if (data !== 'default' && 'to' in data && data.to !== 'default') {
|
|
||||||
args = data.to
|
|
||||||
} else if (data !== 'default' && !('to' in data)) {
|
|
||||||
args = data
|
|
||||||
}
|
|
||||||
|
|
||||||
const to: [number, number] = [from[0] + args[0], from[1] + args[1]]
|
|
||||||
const lineData: LineData = {
|
|
||||||
from: [...from, 0],
|
|
||||||
to: [...to, 0],
|
|
||||||
}
|
|
||||||
const id = makeId({
|
|
||||||
code,
|
|
||||||
sourceRange,
|
|
||||||
data,
|
|
||||||
})
|
|
||||||
engineCommandManager.sendModelingCommand({
|
|
||||||
id,
|
|
||||||
range: sourceRange,
|
|
||||||
command: {
|
|
||||||
type: 'modeling_cmd_req',
|
|
||||||
cmd: {
|
|
||||||
type: 'extend_path',
|
|
||||||
path: sketchGroup.id,
|
|
||||||
segment: {
|
|
||||||
type: 'line',
|
|
||||||
end: {
|
|
||||||
x: lineData.to[0],
|
|
||||||
y: lineData.to[1],
|
|
||||||
z: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
cmd_id: id,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
const currentPath: Path = {
|
|
||||||
type: 'toPoint',
|
|
||||||
to,
|
|
||||||
from,
|
|
||||||
__geoMeta: {
|
|
||||||
id,
|
|
||||||
sourceRange,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if (data !== 'default' && 'tag' in data) {
|
|
||||||
currentPath.name = data.tag
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
...sketchGroup,
|
|
||||||
value: [...sketchGroup.value, currentPath],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
add: ({
|
add: ({
|
||||||
node,
|
node,
|
||||||
previousProgramMemory,
|
previousProgramMemory,
|
||||||
@ -382,25 +267,6 @@ export const line: SketchLineHelper = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const xLineTo: SketchLineHelper = {
|
export const xLineTo: SketchLineHelper = {
|
||||||
fn: (
|
|
||||||
meta,
|
|
||||||
data:
|
|
||||||
| number
|
|
||||||
| {
|
|
||||||
to: number
|
|
||||||
// name?: string
|
|
||||||
tag?: string
|
|
||||||
},
|
|
||||||
previousSketch: SketchGroup
|
|
||||||
) => {
|
|
||||||
if (!previousSketch) throw new Error('bad bad bad')
|
|
||||||
const from = getCoordsFromPaths(
|
|
||||||
previousSketch,
|
|
||||||
previousSketch.value.length - 1
|
|
||||||
)
|
|
||||||
const [xVal, tag] = typeof data !== 'number' ? [data.to, data.tag] : [data]
|
|
||||||
return lineTo.fn(meta, { to: [xVal, from[1]], tag }, previousSketch)
|
|
||||||
},
|
|
||||||
add: ({ node, pathToNode, to, replaceExisting, createCallback }) => {
|
add: ({ node, pathToNode, to, replaceExisting, createCallback }) => {
|
||||||
const _node = { ...node }
|
const _node = { ...node }
|
||||||
const getNode = getNodeFromPathCurry(_node, pathToNode)
|
const getNode = getNodeFromPathCurry(_node, pathToNode)
|
||||||
@ -449,25 +315,6 @@ export const xLineTo: SketchLineHelper = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const yLineTo: SketchLineHelper = {
|
export const yLineTo: SketchLineHelper = {
|
||||||
fn: (
|
|
||||||
meta,
|
|
||||||
data:
|
|
||||||
| number
|
|
||||||
| {
|
|
||||||
to: number
|
|
||||||
// name?: string
|
|
||||||
tag?: string
|
|
||||||
},
|
|
||||||
previousSketch: SketchGroup
|
|
||||||
) => {
|
|
||||||
if (!previousSketch) throw new Error('bad bad bad')
|
|
||||||
const from = getCoordsFromPaths(
|
|
||||||
previousSketch,
|
|
||||||
previousSketch.value.length - 1
|
|
||||||
)
|
|
||||||
const [yVal, tag] = typeof data !== 'number' ? [data.to, data.tag] : [data]
|
|
||||||
return lineTo.fn(meta, { to: [from[0], yVal], tag }, previousSketch)
|
|
||||||
},
|
|
||||||
add: ({ node, pathToNode, to, replaceExisting, createCallback }) => {
|
add: ({ node, pathToNode, to, replaceExisting, createCallback }) => {
|
||||||
const _node = { ...node }
|
const _node = { ...node }
|
||||||
const getNode = getNodeFromPathCurry(_node, pathToNode)
|
const getNode = getNodeFromPathCurry(_node, pathToNode)
|
||||||
@ -516,21 +363,6 @@ export const yLineTo: SketchLineHelper = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const xLine: SketchLineHelper = {
|
export const xLine: SketchLineHelper = {
|
||||||
fn: (
|
|
||||||
meta,
|
|
||||||
data:
|
|
||||||
| number
|
|
||||||
| {
|
|
||||||
length: number
|
|
||||||
tag?: string
|
|
||||||
},
|
|
||||||
previousSketch: SketchGroup
|
|
||||||
) => {
|
|
||||||
if (!previousSketch) throw new Error('bad bad bad')
|
|
||||||
const [xVal, tag] =
|
|
||||||
typeof data !== 'number' ? [data.length, data.tag] : [data]
|
|
||||||
return line.fn(meta, { to: [xVal, 0], tag }, previousSketch)
|
|
||||||
},
|
|
||||||
add: ({ node, pathToNode, to, from, replaceExisting, createCallback }) => {
|
add: ({ node, pathToNode, to, from, replaceExisting, createCallback }) => {
|
||||||
const _node = { ...node }
|
const _node = { ...node }
|
||||||
const getNode = getNodeFromPathCurry(_node, pathToNode)
|
const getNode = getNodeFromPathCurry(_node, pathToNode)
|
||||||
@ -581,22 +413,6 @@ export const xLine: SketchLineHelper = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const yLine: SketchLineHelper = {
|
export const yLine: SketchLineHelper = {
|
||||||
fn: (
|
|
||||||
meta,
|
|
||||||
data:
|
|
||||||
| number
|
|
||||||
| {
|
|
||||||
length: number
|
|
||||||
// name?: string
|
|
||||||
tag?: string
|
|
||||||
},
|
|
||||||
previousSketch: SketchGroup
|
|
||||||
) => {
|
|
||||||
if (!previousSketch) throw new Error('bad bad bad')
|
|
||||||
const [yVal, tag] =
|
|
||||||
typeof data !== 'number' ? [data.length, data.tag] : [data]
|
|
||||||
return line.fn(meta, { to: [0, yVal], tag }, previousSketch)
|
|
||||||
},
|
|
||||||
add: ({ node, pathToNode, to, from, replaceExisting, createCallback }) => {
|
add: ({ node, pathToNode, to, from, replaceExisting, createCallback }) => {
|
||||||
const _node = { ...node }
|
const _node = { ...node }
|
||||||
const getNode = getNodeFromPathCurry(_node, pathToNode)
|
const getNode = getNodeFromPathCurry(_node, pathToNode)
|
||||||
@ -641,47 +457,6 @@ export const yLine: SketchLineHelper = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const angledLine: SketchLineHelper = {
|
export const angledLine: SketchLineHelper = {
|
||||||
fn: (
|
|
||||||
{ sourceRange, engineCommandManager, code },
|
|
||||||
data:
|
|
||||||
| [number, number]
|
|
||||||
| {
|
|
||||||
angle: number
|
|
||||||
length: number
|
|
||||||
tag?: string
|
|
||||||
},
|
|
||||||
previousSketch: SketchGroup
|
|
||||||
) => {
|
|
||||||
if (!previousSketch) throw new Error('lineTo must be called after lineTo')
|
|
||||||
const sketchGroup = { ...previousSketch }
|
|
||||||
const from = getCoordsFromPaths(sketchGroup, sketchGroup.value.length - 1)
|
|
||||||
const [angle, length] = 'angle' in data ? [data.angle, data.length] : data
|
|
||||||
const to: [number, number] = [
|
|
||||||
from[0] + length * Math.cos((angle * Math.PI) / 180),
|
|
||||||
from[1] + length * Math.sin((angle * Math.PI) / 180),
|
|
||||||
]
|
|
||||||
const id = makeId({
|
|
||||||
code,
|
|
||||||
sourceRange,
|
|
||||||
data,
|
|
||||||
})
|
|
||||||
const currentPath: Path = {
|
|
||||||
type: 'toPoint',
|
|
||||||
to,
|
|
||||||
from,
|
|
||||||
__geoMeta: {
|
|
||||||
id,
|
|
||||||
sourceRange,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if ('tag' in data) {
|
|
||||||
currentPath.name = data.tag
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
...sketchGroup,
|
|
||||||
value: [...sketchGroup.value, currentPath],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
add: ({
|
add: ({
|
||||||
node,
|
node,
|
||||||
pathToNode,
|
pathToNode,
|
||||||
@ -749,26 +524,6 @@ export const angledLine: SketchLineHelper = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const angledLineOfXLength: SketchLineHelper = {
|
export const angledLineOfXLength: SketchLineHelper = {
|
||||||
fn: (
|
|
||||||
{ sourceRange, programMemory, engineCommandManager, code },
|
|
||||||
data:
|
|
||||||
| [number, number]
|
|
||||||
| {
|
|
||||||
angle: number
|
|
||||||
length: number
|
|
||||||
tag?: string
|
|
||||||
},
|
|
||||||
previousSketch: SketchGroup
|
|
||||||
) => {
|
|
||||||
if (!previousSketch) throw new Error('lineTo must be called after lineTo')
|
|
||||||
const [angle, length, tag] =
|
|
||||||
'angle' in data ? [data.angle, data.length, data.tag] : data
|
|
||||||
return line.fn(
|
|
||||||
{ sourceRange, programMemory, engineCommandManager, code },
|
|
||||||
{ to: getYComponent(angle, length), tag },
|
|
||||||
previousSketch
|
|
||||||
)
|
|
||||||
},
|
|
||||||
add: ({
|
add: ({
|
||||||
node,
|
node,
|
||||||
previousProgramMemory,
|
previousProgramMemory,
|
||||||
@ -842,26 +597,6 @@ export const angledLineOfXLength: SketchLineHelper = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const angledLineOfYLength: SketchLineHelper = {
|
export const angledLineOfYLength: SketchLineHelper = {
|
||||||
fn: (
|
|
||||||
{ sourceRange, programMemory, engineCommandManager, code },
|
|
||||||
data:
|
|
||||||
| [number, number]
|
|
||||||
| {
|
|
||||||
angle: number
|
|
||||||
length: number
|
|
||||||
tag?: string
|
|
||||||
},
|
|
||||||
previousSketch: SketchGroup
|
|
||||||
) => {
|
|
||||||
if (!previousSketch) throw new Error('lineTo must be called after lineTo')
|
|
||||||
const [angle, length, tag] =
|
|
||||||
'angle' in data ? [data.angle, data.length, data.tag] : data
|
|
||||||
return line.fn(
|
|
||||||
{ sourceRange, programMemory, engineCommandManager, code },
|
|
||||||
{ to: getXComponent(angle, length), tag },
|
|
||||||
previousSketch
|
|
||||||
)
|
|
||||||
},
|
|
||||||
add: ({
|
add: ({
|
||||||
node,
|
node,
|
||||||
previousProgramMemory,
|
previousProgramMemory,
|
||||||
@ -936,33 +671,6 @@ export const angledLineOfYLength: SketchLineHelper = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const angledLineToX: SketchLineHelper = {
|
export const angledLineToX: SketchLineHelper = {
|
||||||
fn: (
|
|
||||||
{ sourceRange, programMemory, engineCommandManager, code },
|
|
||||||
data:
|
|
||||||
| [number, number]
|
|
||||||
| {
|
|
||||||
angle: number
|
|
||||||
to: number
|
|
||||||
tag?: string
|
|
||||||
},
|
|
||||||
previousSketch: SketchGroup
|
|
||||||
) => {
|
|
||||||
if (!previousSketch) throw new Error('lineTo must be called after lineTo')
|
|
||||||
const from = getCoordsFromPaths(
|
|
||||||
previousSketch,
|
|
||||||
previousSketch.value.length - 1
|
|
||||||
)
|
|
||||||
const [angle, xTo, tag] =
|
|
||||||
'angle' in data ? [data.angle, data.to, data.tag] : data
|
|
||||||
const xComponent = xTo - from[0]
|
|
||||||
const yComponent = xComponent * Math.tan((angle * Math.PI) / 180)
|
|
||||||
const yTo = from[1] + yComponent
|
|
||||||
return lineTo.fn(
|
|
||||||
{ sourceRange, programMemory, engineCommandManager, code },
|
|
||||||
{ to: [xTo, yTo], tag },
|
|
||||||
previousSketch
|
|
||||||
)
|
|
||||||
},
|
|
||||||
add: ({
|
add: ({
|
||||||
node,
|
node,
|
||||||
pathToNode,
|
pathToNode,
|
||||||
@ -1032,33 +740,6 @@ export const angledLineToX: SketchLineHelper = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const angledLineToY: SketchLineHelper = {
|
export const angledLineToY: SketchLineHelper = {
|
||||||
fn: (
|
|
||||||
{ sourceRange, programMemory, engineCommandManager, code },
|
|
||||||
data:
|
|
||||||
| [number, number]
|
|
||||||
| {
|
|
||||||
angle: number
|
|
||||||
to: number
|
|
||||||
tag?: string
|
|
||||||
},
|
|
||||||
previousSketch: SketchGroup
|
|
||||||
) => {
|
|
||||||
if (!previousSketch) throw new Error('lineTo must be called after lineTo')
|
|
||||||
const from = getCoordsFromPaths(
|
|
||||||
previousSketch,
|
|
||||||
previousSketch.value.length - 1
|
|
||||||
)
|
|
||||||
const [angle, yTo, tag] =
|
|
||||||
'angle' in data ? [data.angle, data.to, data.tag] : data
|
|
||||||
const yComponent = yTo - from[1]
|
|
||||||
const xComponent = yComponent / Math.tan((angle * Math.PI) / 180)
|
|
||||||
const xTo = from[0] + xComponent
|
|
||||||
return lineTo.fn(
|
|
||||||
{ sourceRange, programMemory, engineCommandManager, code },
|
|
||||||
{ to: [xTo, yTo], tag },
|
|
||||||
previousSketch
|
|
||||||
)
|
|
||||||
},
|
|
||||||
add: ({
|
add: ({
|
||||||
node,
|
node,
|
||||||
pathToNode,
|
pathToNode,
|
||||||
@ -1129,37 +810,6 @@ export const angledLineToY: SketchLineHelper = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const angledLineThatIntersects: SketchLineHelper = {
|
export const angledLineThatIntersects: SketchLineHelper = {
|
||||||
fn: (
|
|
||||||
{ sourceRange, programMemory, engineCommandManager, code },
|
|
||||||
data: {
|
|
||||||
angle: number
|
|
||||||
intersectTag: string
|
|
||||||
offset?: number
|
|
||||||
tag?: string
|
|
||||||
},
|
|
||||||
previousSketch: SketchGroup
|
|
||||||
) => {
|
|
||||||
if (!previousSketch) throw new Error('lineTo must be called after lineTo')
|
|
||||||
const intersectPath = previousSketch.value.find(
|
|
||||||
({ name }) => name === data.intersectTag
|
|
||||||
)
|
|
||||||
if (!intersectPath) throw new Error('intersectTag must match a line')
|
|
||||||
const from = getCoordsFromPaths(
|
|
||||||
previousSketch,
|
|
||||||
previousSketch.value.length - 1
|
|
||||||
)
|
|
||||||
const to = intersectionWithParallelLine({
|
|
||||||
line1: [intersectPath.from, intersectPath.to],
|
|
||||||
line1Offset: data.offset || 0,
|
|
||||||
line2Point: from,
|
|
||||||
line2Angle: data.angle,
|
|
||||||
})
|
|
||||||
return lineTo.fn(
|
|
||||||
{ sourceRange, programMemory, engineCommandManager, code },
|
|
||||||
{ to, tag: data.tag },
|
|
||||||
previousSketch
|
|
||||||
)
|
|
||||||
},
|
|
||||||
add: ({
|
add: ({
|
||||||
node,
|
node,
|
||||||
pathToNode,
|
pathToNode,
|
||||||
@ -1522,133 +1172,6 @@ function addTagWithTo(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const close: InternalFn = (
|
|
||||||
{ sourceRange, engineCommandManager, code },
|
|
||||||
sketchGroup: SketchGroup
|
|
||||||
): SketchGroup => {
|
|
||||||
const from = getCoordsFromPaths(sketchGroup, sketchGroup.value.length - 1)
|
|
||||||
const to = sketchGroup.start
|
|
||||||
? sketchGroup.start.from
|
|
||||||
: getCoordsFromPaths(sketchGroup, 0)
|
|
||||||
|
|
||||||
const id = makeId({
|
|
||||||
code,
|
|
||||||
sourceRange,
|
|
||||||
data: sketchGroup,
|
|
||||||
})
|
|
||||||
engineCommandManager.sendModelingCommand({
|
|
||||||
id,
|
|
||||||
range: sourceRange,
|
|
||||||
command: {
|
|
||||||
type: 'modeling_cmd_req',
|
|
||||||
cmd: {
|
|
||||||
type: 'close_path',
|
|
||||||
path_id: sketchGroup.id,
|
|
||||||
},
|
|
||||||
cmd_id: id,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const currentPath: Path = {
|
|
||||||
type: 'toPoint',
|
|
||||||
to,
|
|
||||||
from,
|
|
||||||
__geoMeta: {
|
|
||||||
id,
|
|
||||||
sourceRange,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
const newValue = [...sketchGroup.value]
|
|
||||||
newValue.push(currentPath)
|
|
||||||
return {
|
|
||||||
...sketchGroup,
|
|
||||||
value: newValue,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const startSketchAt: InternalFn = (
|
|
||||||
{ sourceRange, programMemory, engineCommandManager, code },
|
|
||||||
data:
|
|
||||||
| [number, number]
|
|
||||||
| 'default'
|
|
||||||
| {
|
|
||||||
to: [number, number] | 'default'
|
|
||||||
// name?: string
|
|
||||||
tag?: string
|
|
||||||
}
|
|
||||||
): SketchGroup => {
|
|
||||||
let to: [number, number] = [0, 0]
|
|
||||||
if (data !== 'default' && 'to' in data && data.to !== 'default') {
|
|
||||||
to = data.to
|
|
||||||
} else if (data !== 'default' && !('to' in data)) {
|
|
||||||
to = data
|
|
||||||
}
|
|
||||||
|
|
||||||
const lineData: { to: [number, number, number] } = {
|
|
||||||
to: [...to, 0],
|
|
||||||
}
|
|
||||||
const id = makeId({
|
|
||||||
code,
|
|
||||||
sourceRange,
|
|
||||||
data,
|
|
||||||
})
|
|
||||||
const pathId = makeId({
|
|
||||||
code,
|
|
||||||
sourceRange,
|
|
||||||
data,
|
|
||||||
isPath: true,
|
|
||||||
})
|
|
||||||
engineCommandManager.sendModelingCommand({
|
|
||||||
id: pathId,
|
|
||||||
range: sourceRange,
|
|
||||||
command: {
|
|
||||||
type: 'modeling_cmd_req',
|
|
||||||
cmd: {
|
|
||||||
type: 'start_path',
|
|
||||||
},
|
|
||||||
cmd_id: pathId,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
engineCommandManager.sendSceneCommand({
|
|
||||||
type: 'modeling_cmd_req',
|
|
||||||
cmd: {
|
|
||||||
type: 'move_path_pen',
|
|
||||||
path: pathId,
|
|
||||||
to: {
|
|
||||||
x: lineData.to[0],
|
|
||||||
y: lineData.to[1],
|
|
||||||
z: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
cmd_id: id,
|
|
||||||
})
|
|
||||||
const currentPath: Path = {
|
|
||||||
type: 'base',
|
|
||||||
to,
|
|
||||||
from: to,
|
|
||||||
__geoMeta: {
|
|
||||||
id,
|
|
||||||
sourceRange,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if (data !== 'default' && 'tag' in data) {
|
|
||||||
currentPath.name = data.tag
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
type: 'sketchGroup',
|
|
||||||
start: currentPath,
|
|
||||||
value: [],
|
|
||||||
position: [0, 0, 0],
|
|
||||||
rotation: [0, 0, 0, 1],
|
|
||||||
id: pathId,
|
|
||||||
__meta: [
|
|
||||||
{
|
|
||||||
sourceRange,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getYComponent(
|
export function getYComponent(
|
||||||
angleDegree: number,
|
angleDegree: number,
|
||||||
xComponent: number
|
xComponent: number
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { getAngle } from '../../lib/utils'
|
|
||||||
import { TooTip, toolTips } from '../../useStore'
|
import { TooTip, toolTips } from '../../useStore'
|
||||||
import {
|
import {
|
||||||
Program,
|
Program,
|
||||||
@ -6,7 +5,6 @@ import {
|
|||||||
CallExpression,
|
CallExpression,
|
||||||
} from '../abstractSyntaxTreeTypes'
|
} from '../abstractSyntaxTreeTypes'
|
||||||
import { SketchGroup, SourceRange } from '../executor'
|
import { SketchGroup, SourceRange } from '../executor'
|
||||||
import { InternalFn } from './stdTypes'
|
|
||||||
|
|
||||||
export function getSketchSegmentFromSourceRange(
|
export function getSketchSegmentFromSourceRange(
|
||||||
sketchGroup: SketchGroup,
|
sketchGroup: SketchGroup,
|
||||||
@ -36,79 +34,6 @@ export function getSketchSegmentFromSourceRange(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const segLen: InternalFn = (
|
|
||||||
_,
|
|
||||||
segName: string,
|
|
||||||
sketchGroup: SketchGroup
|
|
||||||
): number => {
|
|
||||||
const line = sketchGroup?.value.find((seg) => seg?.name === segName)
|
|
||||||
// maybe this should throw, but the language doesn't have a way to handle errors yet
|
|
||||||
if (!line) return 0
|
|
||||||
|
|
||||||
return Math.sqrt(
|
|
||||||
(line.from[1] - line.to[1]) ** 2 + (line.from[0] - line.to[0]) ** 2
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const segAng: InternalFn = (
|
|
||||||
_,
|
|
||||||
segName: string,
|
|
||||||
sketchGroup: SketchGroup
|
|
||||||
): number => {
|
|
||||||
const line = sketchGroup?.value.find((seg) => seg.name === segName)
|
|
||||||
// maybe this should throw, but the language doesn't have a way to handle errors yet
|
|
||||||
if (!line) return 0
|
|
||||||
return getAngle(line.from, line.to)
|
|
||||||
}
|
|
||||||
|
|
||||||
function segEndFactory(which: 'x' | 'y'): InternalFn {
|
|
||||||
return (_, segName: string, sketchGroup: SketchGroup): number => {
|
|
||||||
const line =
|
|
||||||
sketchGroup?.start?.name === segName
|
|
||||||
? sketchGroup?.start
|
|
||||||
: sketchGroup?.value.find((seg) => seg.name === segName)
|
|
||||||
// maybe this should throw, but the language doesn't have a way to handle errors yet
|
|
||||||
if (!line) return 0
|
|
||||||
return which === 'x' ? line.to[0] : line.to[1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const segEndX: InternalFn = segEndFactory('x')
|
|
||||||
export const segEndY: InternalFn = segEndFactory('y')
|
|
||||||
|
|
||||||
function lastSegFactory(which: 'x' | 'y'): InternalFn {
|
|
||||||
return (_, sketchGroup: SketchGroup): number => {
|
|
||||||
const lastLine = sketchGroup?.value[sketchGroup.value.length - 1]
|
|
||||||
return which === 'x' ? lastLine.to[0] : lastLine.to[1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const lastSegX: InternalFn = lastSegFactory('x')
|
|
||||||
export const lastSegY: InternalFn = lastSegFactory('y')
|
|
||||||
|
|
||||||
function angleToMatchLengthFactory(which: 'x' | 'y'): InternalFn {
|
|
||||||
return (_, segName: string, to: number, sketchGroup: SketchGroup): number => {
|
|
||||||
const isX = which === 'x'
|
|
||||||
const lineToMatch = sketchGroup?.value.find((seg) => seg.name === segName)
|
|
||||||
// maybe this should throw, but the language doesn't have a way to handle errors yet
|
|
||||||
if (!lineToMatch) return 0
|
|
||||||
const lengthToMatch = Math.sqrt(
|
|
||||||
(lineToMatch.from[1] - lineToMatch.to[1]) ** 2 +
|
|
||||||
(lineToMatch.from[0] - lineToMatch.to[0]) ** 2
|
|
||||||
)
|
|
||||||
|
|
||||||
const lastLine = sketchGroup?.value[sketchGroup.value.length - 1]
|
|
||||||
const diff = Math.abs(to - (isX ? lastLine.to[0] : lastLine.to[1]))
|
|
||||||
|
|
||||||
const angleR = Math[isX ? 'acos' : 'asin'](diff / lengthToMatch)
|
|
||||||
|
|
||||||
return diff > lengthToMatch ? 0 : (angleR * 180) / Math.PI
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const angleToMatchLengthX: InternalFn = angleToMatchLengthFactory('x')
|
|
||||||
export const angleToMatchLengthY: InternalFn = angleToMatchLengthFactory('y')
|
|
||||||
|
|
||||||
export function isSketchVariablesLinked(
|
export function isSketchVariablesLinked(
|
||||||
secondaryVarDec: VariableDeclarator,
|
secondaryVarDec: VariableDeclarator,
|
||||||
primaryVarDec: VariableDeclarator,
|
primaryVarDec: VariableDeclarator,
|
||||||
|
@ -1,170 +0,0 @@
|
|||||||
import {
|
|
||||||
lineTo,
|
|
||||||
xLineTo,
|
|
||||||
yLineTo,
|
|
||||||
line,
|
|
||||||
xLine,
|
|
||||||
yLine,
|
|
||||||
angledLine,
|
|
||||||
angledLineOfXLength,
|
|
||||||
angledLineToX,
|
|
||||||
angledLineOfYLength,
|
|
||||||
angledLineToY,
|
|
||||||
close,
|
|
||||||
startSketchAt,
|
|
||||||
angledLineThatIntersects,
|
|
||||||
} from './sketch'
|
|
||||||
import {
|
|
||||||
segLen,
|
|
||||||
segAng,
|
|
||||||
angleToMatchLengthX,
|
|
||||||
angleToMatchLengthY,
|
|
||||||
segEndX,
|
|
||||||
segEndY,
|
|
||||||
lastSegX,
|
|
||||||
lastSegY,
|
|
||||||
} from './sketchConstraints'
|
|
||||||
import { getExtrudeWallTransform, extrude } from './extrude'
|
|
||||||
|
|
||||||
import { InternalFn, InternalFnNames } from './stdTypes'
|
|
||||||
|
|
||||||
// const transform: InternalFn = <T extends SketchGroup | ExtrudeGroup>(
|
|
||||||
// { sourceRange }: InternalFirstArg,
|
|
||||||
// transformInfo: {
|
|
||||||
// position: Position
|
|
||||||
// quaternion: Rotation
|
|
||||||
// },
|
|
||||||
// sketch: T
|
|
||||||
// ): T => {
|
|
||||||
// const quaternionToApply = new Quaternion(...transformInfo?.quaternion)
|
|
||||||
// const newQuaternion = new Quaternion(...sketch.rotation).multiply(
|
|
||||||
// quaternionToApply.invert()
|
|
||||||
// )
|
|
||||||
|
|
||||||
// const oldPosition = new Vector3(...sketch?.position)
|
|
||||||
// const newPosition = oldPosition
|
|
||||||
// .applyQuaternion(quaternionToApply)
|
|
||||||
// .add(new Vector3(...transformInfo?.position))
|
|
||||||
// return {
|
|
||||||
// ...sketch,
|
|
||||||
// position: newPosition.toArray(),
|
|
||||||
// rotation: newQuaternion.toArray(),
|
|
||||||
// __meta: [
|
|
||||||
// ...sketch.__meta,
|
|
||||||
// {
|
|
||||||
// sourceRange,
|
|
||||||
// pathToNode: [], // TODO
|
|
||||||
// },
|
|
||||||
// ],
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const translate: InternalFn = <T extends SketchGroup | ExtrudeGroup>(
|
|
||||||
// { sourceRange }: InternalFirstArg,
|
|
||||||
// vec3: [number, number, number],
|
|
||||||
// sketch: T
|
|
||||||
// ): T => {
|
|
||||||
// const oldPosition = new Vector3(...sketch.position)
|
|
||||||
// const newPosition = oldPosition.add(new Vector3(...vec3))
|
|
||||||
// return {
|
|
||||||
// ...sketch,
|
|
||||||
// position: newPosition.toArray(),
|
|
||||||
// __meta: [
|
|
||||||
// ...sketch.__meta,
|
|
||||||
// {
|
|
||||||
// sourceRange,
|
|
||||||
// pathToNode: [], // TODO
|
|
||||||
// },
|
|
||||||
// ],
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
const min: InternalFn = (_, a: number, b: number): number => Math.min(a, b)
|
|
||||||
|
|
||||||
const legLen: InternalFn = (_, hypotenuse: number, leg: number): number =>
|
|
||||||
Math.sqrt(
|
|
||||||
hypotenuse ** 2 - Math.min(Math.abs(leg), Math.abs(hypotenuse)) ** 2
|
|
||||||
)
|
|
||||||
|
|
||||||
const legAngX: InternalFn = (_, hypotenuse: number, leg: number): number =>
|
|
||||||
(Math.acos(Math.min(leg, hypotenuse) / hypotenuse) * 180) / Math.PI
|
|
||||||
|
|
||||||
const legAngY: InternalFn = (_, hypotenuse: number, leg: number): number =>
|
|
||||||
(Math.asin(Math.min(leg, hypotenuse) / hypotenuse) * 180) / Math.PI
|
|
||||||
|
|
||||||
export const internalFns: { [key in InternalFnNames]: InternalFn } = {
|
|
||||||
// TODO - re-enable these
|
|
||||||
// rx: rotateOnAxis([1, 0, 0]), // Enable rotations #152
|
|
||||||
// ry: rotateOnAxis([0, 1, 0]),
|
|
||||||
// rz: rotateOnAxis([0, 0, 1]),
|
|
||||||
extrude,
|
|
||||||
// translate,
|
|
||||||
// transform,
|
|
||||||
getExtrudeWallTransform,
|
|
||||||
min,
|
|
||||||
legLen,
|
|
||||||
legAngX,
|
|
||||||
legAngY,
|
|
||||||
segEndX,
|
|
||||||
segEndY,
|
|
||||||
lastSegX,
|
|
||||||
lastSegY,
|
|
||||||
segLen,
|
|
||||||
segAng,
|
|
||||||
angleToMatchLengthX,
|
|
||||||
angleToMatchLengthY,
|
|
||||||
lineTo: lineTo.fn,
|
|
||||||
xLineTo: xLineTo.fn,
|
|
||||||
yLineTo: yLineTo.fn,
|
|
||||||
line: line.fn,
|
|
||||||
xLine: xLine.fn,
|
|
||||||
yLine: yLine.fn,
|
|
||||||
angledLine: angledLine.fn,
|
|
||||||
angledLineOfXLength: angledLineOfXLength.fn,
|
|
||||||
angledLineToX: angledLineToX.fn,
|
|
||||||
angledLineOfYLength: angledLineOfYLength.fn,
|
|
||||||
angledLineToY: angledLineToY.fn,
|
|
||||||
angledLineThatIntersects: angledLineThatIntersects.fn,
|
|
||||||
startSketchAt,
|
|
||||||
close,
|
|
||||||
}
|
|
||||||
|
|
||||||
// function rotateOnAxis<T extends SketchGroup | ExtrudeGroup>(
|
|
||||||
// axisMultiplier: [number, number, number]
|
|
||||||
// ): InternalFn {
|
|
||||||
// return ({ sourceRange }, rotationD: number, sketch: T): T => {
|
|
||||||
// const rotationR = rotationD * (Math.PI / 180)
|
|
||||||
// const rotateVec = new Vector3(...axisMultiplier)
|
|
||||||
// const quaternion = new Quaternion()
|
|
||||||
// quaternion.setFromAxisAngle(rotateVec, rotationR)
|
|
||||||
|
|
||||||
// const position = new Vector3(...sketch.position)
|
|
||||||
// .applyQuaternion(quaternion)
|
|
||||||
// .toArray()
|
|
||||||
|
|
||||||
// const existingQuat = new Quaternion(...sketch.rotation)
|
|
||||||
// const rotation = quaternion.multiply(existingQuat).toArray()
|
|
||||||
// return {
|
|
||||||
// ...sketch,
|
|
||||||
// rotation,
|
|
||||||
// position,
|
|
||||||
// __meta: [
|
|
||||||
// ...sketch.__meta,
|
|
||||||
// {
|
|
||||||
// sourceRange,
|
|
||||||
// pathToNode: [], // TODO
|
|
||||||
// },
|
|
||||||
// ],
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
export 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
|
|
||||||
}
|
|
@ -17,44 +17,6 @@ export interface PathReturn {
|
|||||||
currentPath: Path
|
currentPath: Path
|
||||||
}
|
}
|
||||||
|
|
||||||
export type InternalFn = (internals: InternalFirstArg, ...args: any[]) => any
|
|
||||||
|
|
||||||
export type InternalFnNames =
|
|
||||||
// TODO re-enable these
|
|
||||||
// | 'translate'
|
|
||||||
// | 'transform'
|
|
||||||
// | 'rx' // Enable rotations #152
|
|
||||||
// | 'ry'
|
|
||||||
// | 'rz'
|
|
||||||
| 'extrude'
|
|
||||||
| 'getExtrudeWallTransform'
|
|
||||||
| 'min'
|
|
||||||
| 'legLen'
|
|
||||||
| 'legAngX'
|
|
||||||
| 'legAngY'
|
|
||||||
| 'segEndX'
|
|
||||||
| 'segEndY'
|
|
||||||
| 'lastSegX'
|
|
||||||
| 'lastSegY'
|
|
||||||
| 'segLen'
|
|
||||||
| 'segAng'
|
|
||||||
| 'angleToMatchLengthX'
|
|
||||||
| 'angleToMatchLengthY'
|
|
||||||
| 'lineTo'
|
|
||||||
| 'yLineTo'
|
|
||||||
| 'xLineTo'
|
|
||||||
| 'line'
|
|
||||||
| 'yLine'
|
|
||||||
| 'xLine'
|
|
||||||
| 'angledLine'
|
|
||||||
| 'angledLineOfXLength'
|
|
||||||
| 'angledLineToX'
|
|
||||||
| 'angledLineOfYLength'
|
|
||||||
| 'angledLineToY'
|
|
||||||
| 'startSketchAt'
|
|
||||||
| 'close'
|
|
||||||
| 'angledLineThatIntersects'
|
|
||||||
|
|
||||||
export interface ModifyAstBase {
|
export interface ModifyAstBase {
|
||||||
node: Program
|
node: Program
|
||||||
previousProgramMemory: ProgramMemory
|
previousProgramMemory: ProgramMemory
|
||||||
@ -87,7 +49,6 @@ export type SketchCallTransfromMap = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface SketchLineHelper {
|
export interface SketchLineHelper {
|
||||||
fn: InternalFn
|
|
||||||
add: (a: addCall) => {
|
add: (a: addCall) => {
|
||||||
modifiedAst: Program
|
modifiedAst: Program
|
||||||
pathToNode: PathToNode
|
pathToNode: PathToNode
|
||||||
|
1
src/wasm-lib/Cargo.lock
generated
1
src/wasm-lib/Cargo.lock
generated
@ -1249,7 +1249,6 @@ dependencies = [
|
|||||||
"uuid",
|
"uuid",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
"web-sys",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -30,32 +30,6 @@ uuid = { version = "1.4.1", features = ["v4", "js", "serde"] }
|
|||||||
wasm-bindgen = "0.2.87"
|
wasm-bindgen = "0.2.87"
|
||||||
wasm-bindgen-futures = "0.4.37"
|
wasm-bindgen-futures = "0.4.37"
|
||||||
|
|
||||||
[dependencies.web-sys]
|
|
||||||
version = "0.3.64"
|
|
||||||
features = [
|
|
||||||
"BinaryType",
|
|
||||||
"Blob",
|
|
||||||
"CloseEvent",
|
|
||||||
"ErrorEvent",
|
|
||||||
"FileReader",
|
|
||||||
"MessageEvent",
|
|
||||||
"ProgressEvent",
|
|
||||||
"RtcConfiguration",
|
|
||||||
"RtcIceServer",
|
|
||||||
"RtcIceTransportPolicy",
|
|
||||||
"RtcPeerConnection",
|
|
||||||
"RtcSignalingState",
|
|
||||||
"RtcSdpType",
|
|
||||||
"RtcSessionDescriptionInit",
|
|
||||||
"RtcPeerConnectionIceEvent",
|
|
||||||
"RtcIceCandidate",
|
|
||||||
"RtcDataChannel",
|
|
||||||
"RtcDataChannelEvent",
|
|
||||||
"RtcRtpTransceiver",
|
|
||||||
"WebSocket",
|
|
||||||
]
|
|
||||||
optional = true
|
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
panic = "abort"
|
panic = "abort"
|
||||||
debug = true
|
debug = true
|
||||||
@ -66,5 +40,5 @@ tokio = { version = "1.32.0", features = ["rt-multi-thread", "macros", "time"] }
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["web"]
|
default = ["web"]
|
||||||
web = ["dep:gloo-file", "dep:js-sys", "dep:web-sys"]
|
web = ["dep:gloo-file", "dep:js-sys"]
|
||||||
noweb = ["dep:futures", "dep:httparse", "dep:tokio", "dep:tokio-tungstenite"]
|
noweb = ["dep:futures", "dep:httparse", "dep:tokio", "dep:tokio-tungstenite"]
|
||||||
|
@ -56,343 +56,3 @@ impl EngineConnection {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*use anyhow::Result;
|
|
||||||
use kittycad::types::{WebSocketMessages, WebSocketResponses};
|
|
||||||
use wasm_bindgen::prelude::*;
|
|
||||||
use web_sys::{CloseEvent, ErrorEvent, MessageEvent, RtcDataChannel, RtcPeerConnection, WebSocket};
|
|
||||||
|
|
||||||
use crate::errors::{KclError, KclErrorDetails};
|
|
||||||
|
|
||||||
macro_rules! console_log {
|
|
||||||
($($t:tt)*) => (log(&format_args!($($t)*).to_string()))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
extern "C" {
|
|
||||||
#[wasm_bindgen(js_namespace = console)]
|
|
||||||
fn log(s: &str);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct EngineConnection {
|
|
||||||
ws: WebSocket,
|
|
||||||
pc: RtcPeerConnection,
|
|
||||||
lossy_data_channel: RtcDataChannel,
|
|
||||||
|
|
||||||
ready: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EngineConnection {
|
|
||||||
pub async fn new(
|
|
||||||
conn_str: &str,
|
|
||||||
auth_token: &str,
|
|
||||||
_origin: &str,
|
|
||||||
) -> Result<EngineConnection, JsValue> {
|
|
||||||
// Setup the websocket connection.
|
|
||||||
let ws = WebSocket::new(conn_str)?;
|
|
||||||
|
|
||||||
// Setup the WebRTC connection.
|
|
||||||
let pc = RtcPeerConnection::new()?;
|
|
||||||
let lossy_data_channel = pc.create_data_channel("unreliable_modeling_cmds");
|
|
||||||
|
|
||||||
let cloned_ws = ws.clone();
|
|
||||||
let cloned_auth_token = auth_token.to_owned();
|
|
||||||
let onopen_callback = Closure::<dyn FnMut()>::new(move || {
|
|
||||||
println!("Connected to websocket, waiting for ICE servers");
|
|
||||||
|
|
||||||
// Send our token for auth.
|
|
||||||
cloned_ws
|
|
||||||
.send_with_str(&cloned_auth_token)
|
|
||||||
.expect("failed to send auth token");
|
|
||||||
});
|
|
||||||
ws.set_onopen(Some(onopen_callback.as_ref().unchecked_ref()));
|
|
||||||
onopen_callback.forget();
|
|
||||||
|
|
||||||
let onerror_callback = Closure::<dyn FnMut(_)>::new(move |e: ErrorEvent| {
|
|
||||||
console_log!("error event: {:?}", e);
|
|
||||||
});
|
|
||||||
ws.set_onerror(Some(onerror_callback.as_ref().unchecked_ref()));
|
|
||||||
onerror_callback.forget();
|
|
||||||
|
|
||||||
// For small binary messages, like CBOR, Arraybuffer is more efficient than Blob handling
|
|
||||||
// Export is huge so let's use Blob.
|
|
||||||
ws.set_binary_type(web_sys::BinaryType::Blob);
|
|
||||||
|
|
||||||
let engine_conn = EngineConnection {
|
|
||||||
ws,
|
|
||||||
pc,
|
|
||||||
lossy_data_channel,
|
|
||||||
ready: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut cloned_engine_conn = engine_conn.clone();
|
|
||||||
let onclose_callback = Closure::<dyn FnMut(_)>::new(move |e: CloseEvent| {
|
|
||||||
console_log!("close event: {:?}", e);
|
|
||||||
cloned_engine_conn
|
|
||||||
.close()
|
|
||||||
.expect("failed to close engine connection");
|
|
||||||
});
|
|
||||||
engine_conn
|
|
||||||
.ws
|
|
||||||
.set_onclose(Some(onclose_callback.as_ref().unchecked_ref()));
|
|
||||||
onclose_callback.forget();
|
|
||||||
|
|
||||||
let mut cloned_engine_conn = engine_conn.clone();
|
|
||||||
let onmessage_callback = Closure::<dyn FnMut(_)>::new(move |msg: MessageEvent| {
|
|
||||||
// Parse the message as our types.
|
|
||||||
let msg = match parse_message(msg) {
|
|
||||||
Ok(msg) => msg,
|
|
||||||
Err(e) => {
|
|
||||||
console_log!("Failed to parse message: {:?}", e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
match msg {
|
|
||||||
WebSocketResponses::IceServerInfo { ice_servers } => {
|
|
||||||
// When we set the Configuration, we want to always force
|
|
||||||
// iceTransportPolicy to 'relay', since we know the topology
|
|
||||||
// of the ICE/STUN/TUN server and the engine. We don't wish to
|
|
||||||
// talk to the engine in any configuration /other/ than relay
|
|
||||||
// from a infra POV.
|
|
||||||
let mut config = web_sys::RtcConfiguration::new();
|
|
||||||
let converted_ice_servers = js_sys::Array::new();
|
|
||||||
for server in ice_servers {
|
|
||||||
let mut ice_server = web_sys::RtcIceServer::new();
|
|
||||||
let urls = js_sys::Array::new();
|
|
||||||
for url in server.urls {
|
|
||||||
urls.push(&JsValue::from(url));
|
|
||||||
}
|
|
||||||
ice_server.urls(&urls.into());
|
|
||||||
if let Some(credential) = server.credential {
|
|
||||||
ice_server.credential(&credential);
|
|
||||||
}
|
|
||||||
if let Some(username) = server.username {
|
|
||||||
ice_server.username(&username);
|
|
||||||
}
|
|
||||||
converted_ice_servers.push(&ice_server.into());
|
|
||||||
}
|
|
||||||
config.ice_servers(&converted_ice_servers.into());
|
|
||||||
config.ice_transport_policy(web_sys::RtcIceTransportPolicy::Relay);
|
|
||||||
cloned_engine_conn.pc = web_sys::RtcPeerConnection::new_with_configuration(
|
|
||||||
&config,
|
|
||||||
)
|
|
||||||
.expect("Failed to create RtcPeerConnection with our custom configuration");
|
|
||||||
|
|
||||||
// We have an ICE Servers set now. We just setConfiguration, so let's
|
|
||||||
// start adding things we care about to the PeerConnection and let
|
|
||||||
// ICE negotiation happen in the background. Everything from here
|
|
||||||
// until the end of this function is setup of our end of the
|
|
||||||
// PeerConnection and waiting for events to fire our callbacks.
|
|
||||||
|
|
||||||
let mut cloned_engine_conn2 = cloned_engine_conn.clone();
|
|
||||||
let onicecandidate_callback =
|
|
||||||
Closure::<dyn FnMut(_)>::new(move |ev: MessageEvent| {
|
|
||||||
if !cloned_engine_conn2.ready {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let ev: web_sys::RtcPeerConnectionIceEvent = ev
|
|
||||||
.dyn_into()
|
|
||||||
.expect("Failed to cast to RtcPeerConnectionIceEvent");
|
|
||||||
|
|
||||||
if let Some(candidate) = ev.candidate() {
|
|
||||||
console_log!("sending trickle ice candidate");
|
|
||||||
cloned_engine_conn2
|
|
||||||
.ws_send(WebSocketMessages::TrickleIce {
|
|
||||||
candidate: kittycad::types::RtcIceCandidateInit {
|
|
||||||
candidate: candidate.candidate(),
|
|
||||||
sdp_mid: candidate.sdp_mid(),
|
|
||||||
sdp_m_line_index: candidate.sdp_m_line_index(),
|
|
||||||
username_fragment: Default::default(),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.expect("failed to send trickle ice candidate");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
cloned_engine_conn
|
|
||||||
.pc
|
|
||||||
.set_onicecandidate(Some(onicecandidate_callback.as_ref().unchecked_ref()));
|
|
||||||
onicecandidate_callback.forget();
|
|
||||||
|
|
||||||
let onconnectionstatechange_callback =
|
|
||||||
Closure::<dyn FnMut(_)>::new(move |e: MessageEvent| {
|
|
||||||
console_log!("connection state changed: {:?}", e);
|
|
||||||
});
|
|
||||||
cloned_engine_conn.pc.set_onconnectionstatechange(Some(
|
|
||||||
onconnectionstatechange_callback.as_ref().unchecked_ref(),
|
|
||||||
));
|
|
||||||
onconnectionstatechange_callback.forget();
|
|
||||||
|
|
||||||
// Offer to receive 1 video track
|
|
||||||
cloned_engine_conn.pc.add_transceiver_with_str("video");
|
|
||||||
|
|
||||||
// Finally (but actually firstly!), to kick things off, we're going to
|
|
||||||
// generate our SDP, set it on our PeerConnection, and let the server
|
|
||||||
// know about our capabilities.
|
|
||||||
let cloned_engine_conn2 = cloned_engine_conn.clone();
|
|
||||||
let create_offer_callback = Closure::<dyn FnMut(_)>::new(move |v: JsValue| {
|
|
||||||
let desc: web_sys::RtcSessionDescriptionInit = v.into();
|
|
||||||
let _ = cloned_engine_conn2.pc.set_local_description(&desc);
|
|
||||||
console_log!("sent sdp_offer begin");
|
|
||||||
let object: js_sys::Object = desc.into();
|
|
||||||
console_log!("got offer object: {:?}", object);
|
|
||||||
/*cloned_engine_conn2
|
|
||||||
.send(WebSocketMessages::SdpOffer {
|
|
||||||
offer: kittycad::types::RtcSessionDescription {
|
|
||||||
sdp: desc.sdp(),
|
|
||||||
type_: kittycad::types::RtcSdpType::Offer,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.expect("failed to send sdp offer");*/
|
|
||||||
});
|
|
||||||
let create_offer_catch = Closure::<dyn FnMut(_)>::new(move |v: JsValue| {
|
|
||||||
console_log!("Failed to create offer: {:?}", v);
|
|
||||||
});
|
|
||||||
let _ = cloned_engine_conn
|
|
||||||
.pc
|
|
||||||
.create_offer()
|
|
||||||
.then(&create_offer_callback)
|
|
||||||
.catch(&create_offer_catch);
|
|
||||||
create_offer_callback.forget();
|
|
||||||
create_offer_catch.forget();
|
|
||||||
}
|
|
||||||
WebSocketResponses::SdpAnswer { answer } => {
|
|
||||||
if answer.type_ == kittycad::types::RtcSdpType::Unspecified {
|
|
||||||
console_log!("Received an unspecified rtc sdp answer, ignoring");
|
|
||||||
} else if cloned_engine_conn.pc.signaling_state()
|
|
||||||
!= web_sys::RtcSignalingState::Stable
|
|
||||||
{
|
|
||||||
// If the connection is stable, we shouldn't bother updating the
|
|
||||||
// SDP, since we have a stable connection to the backend. If we
|
|
||||||
// need to renegotiate, the whole PeerConnection needs to get
|
|
||||||
// tore down.
|
|
||||||
let mut desc =
|
|
||||||
web_sys::RtcSessionDescriptionInit::new(match answer.type_ {
|
|
||||||
kittycad::types::RtcSdpType::Offer => web_sys::RtcSdpType::Offer,
|
|
||||||
kittycad::types::RtcSdpType::Pranswer => {
|
|
||||||
web_sys::RtcSdpType::Pranswer
|
|
||||||
}
|
|
||||||
kittycad::types::RtcSdpType::Answer => web_sys::RtcSdpType::Answer,
|
|
||||||
kittycad::types::RtcSdpType::Rollback => {
|
|
||||||
web_sys::RtcSdpType::Rollback
|
|
||||||
}
|
|
||||||
kittycad::types::RtcSdpType::Unspecified => {
|
|
||||||
unreachable!(
|
|
||||||
"Unspecified RtcSdpType should have been handled above"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
desc.sdp(answer.sdp.as_str());
|
|
||||||
let _ = cloned_engine_conn.pc.set_remote_description(&desc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
WebSocketResponses::TrickleIce { candidate } => {
|
|
||||||
console_log!("got trickle ice candidate: {:?}", candidate);
|
|
||||||
// this.pc?.addIceCandidate(message.candidate as RTCIceCandidateInit)
|
|
||||||
/*let mut candidate_init = web_sys::RtcIceCandidateInit::new(candidate.candidate);
|
|
||||||
cloned_engine_conn
|
|
||||||
.pc
|
|
||||||
.add_ice_candidate_with_opt_rtc_ice_candidate_init(&candidate_init);*/
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
WebSocketResponses::Modeling { .. } => {}
|
|
||||||
WebSocketResponses::Export { .. } => {}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// set message event handler on WebSocket
|
|
||||||
engine_conn
|
|
||||||
.ws
|
|
||||||
.set_onmessage(Some(onmessage_callback.as_ref().unchecked_ref()));
|
|
||||||
// forget the callback to keep it alive
|
|
||||||
onmessage_callback.forget();
|
|
||||||
|
|
||||||
Ok(engine_conn)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn close(&mut self) -> Result<(), JsValue> {
|
|
||||||
self.ready = false;
|
|
||||||
self.ws.close()?;
|
|
||||||
self.pc.close();
|
|
||||||
self.lossy_data_channel.close();
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ws_send(&mut self, msg: kittycad::types::WebSocketMessages) -> Result<(), JsValue> {
|
|
||||||
self.ws.send_with_str(
|
|
||||||
serde_json::to_string(&msg)
|
|
||||||
.map_err(|err| JsValue::from(err.to_string()))?
|
|
||||||
.as_str(),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lossy_send(&mut self, msg: kittycad::types::WebSocketMessages) -> Result<(), JsValue> {
|
|
||||||
self.lossy_data_channel.send_with_str(
|
|
||||||
serde_json::to_string(&msg)
|
|
||||||
.map_err(|err| JsValue::from(err.to_string()))?
|
|
||||||
.as_str(),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn send_lossy_cmd(
|
|
||||||
&mut self,
|
|
||||||
id: uuid::Uuid,
|
|
||||||
source_range: crate::executor::SourceRange,
|
|
||||||
cmd: kittycad::types::ModelingCmd,
|
|
||||||
) -> Result<(), KclError> {
|
|
||||||
self.lossy_send(WebSocketMessages::ModelingCmdReq { cmd, cmd_id: id })
|
|
||||||
.map_err(|e| {
|
|
||||||
KclError::Engine(KclErrorDetails {
|
|
||||||
message: format!("Failed to send modeling command: {:?}", e),
|
|
||||||
source_ranges: vec![source_range],
|
|
||||||
})
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn send_modeling_cmd(
|
|
||||||
&mut self,
|
|
||||||
id: uuid::Uuid,
|
|
||||||
source_range: crate::executor::SourceRange,
|
|
||||||
cmd: kittycad::types::ModelingCmd,
|
|
||||||
) -> Result<(), KclError> {
|
|
||||||
self.ws_send(WebSocketMessages::ModelingCmdReq { cmd, cmd_id: id })
|
|
||||||
.map_err(|e| {
|
|
||||||
KclError::Engine(KclErrorDetails {
|
|
||||||
message: format!("Failed to send modeling command: {:?}", e),
|
|
||||||
source_ranges: vec![source_range],
|
|
||||||
})
|
|
||||||
})?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_message(msg: MessageEvent) -> Result<WebSocketResponses> {
|
|
||||||
if let Ok(abuf) = msg.data().dyn_into::<js_sys::ArrayBuffer>() {
|
|
||||||
let array = js_sys::Uint8Array::new(&abuf);
|
|
||||||
Ok(serde_json::from_slice(&array.to_vec())?)
|
|
||||||
} else if let Ok(blob) = msg.data().dyn_into::<web_sys::Blob>() {
|
|
||||||
let (sender, receiver) = std::sync::mpsc::channel();
|
|
||||||
gloo_file::callbacks::read_as_bytes(&blob.into(), move |res| {
|
|
||||||
sender.send(res).unwrap();
|
|
||||||
});
|
|
||||||
let value = receiver.recv()??;
|
|
||||||
Ok(serde_json::from_slice(&value)?)
|
|
||||||
} else if let Ok(txt) = msg.data().dyn_into::<js_sys::JsString>() {
|
|
||||||
console_log!("message event, received Text: {:?}", txt);
|
|
||||||
let s = txt
|
|
||||||
.as_string()
|
|
||||||
.ok_or_else(|| anyhow::anyhow!("Failed to convert JsString: {:?}", txt))?;
|
|
||||||
Ok(serde_json::from_str(&s)?)
|
|
||||||
} else {
|
|
||||||
console_log!("message event, received Unknown: {:?}", msg.data());
|
|
||||||
anyhow::bail!("message event, received Unknown: {:?}", msg.data());
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
Reference in New Issue
Block a user