Compare commits
1 Commits
kcl-61
...
kurt-add-s
Author | SHA1 | Date | |
---|---|---|---|
3e0c44e689 |
@ -13,6 +13,7 @@ import {
|
||||
Quaternion,
|
||||
Scene,
|
||||
Shape,
|
||||
SphereGeometry,
|
||||
Vector2,
|
||||
Vector3,
|
||||
} from 'three'
|
||||
@ -85,6 +86,7 @@ export const TANGENTIAL_ARC_TO_SEGMENT = 'tangential-arc-to-segment'
|
||||
export const TANGENTIAL_ARC_TO_SEGMENT_BODY = 'tangential-arc-to-segment-body'
|
||||
export const TANGENTIAL_ARC_TO__SEGMENT_DASH =
|
||||
'tangential-arc-to-segment-body-dashed'
|
||||
export const EXTRA_SEGMENT_HANDLE = 'extraSegmentHandle'
|
||||
|
||||
// This singleton Class is responsible for all of the things the user sees and interacts with.
|
||||
// That mostly mean sketch elements.
|
||||
@ -239,12 +241,16 @@ class SceneEntities {
|
||||
ast,
|
||||
// is draft line assumes the last segment is a draft line, and mods it as the user moves the mouse
|
||||
draftSegment,
|
||||
skipListeners,
|
||||
}: {
|
||||
sketchPathToNode: PathToNode
|
||||
ast?: Program
|
||||
draftSegment?: DraftSegment
|
||||
skipListeners?: boolean
|
||||
}) {
|
||||
sceneInfra.resetMouseListeners()
|
||||
if (!skipListeners) {
|
||||
sceneInfra.resetMouseListeners()
|
||||
}
|
||||
this.createIntersectionPlane()
|
||||
|
||||
const { truncatedAst, programMemoryOverride, variableDeclarationName } =
|
||||
@ -326,11 +332,60 @@ class SceneEntities {
|
||||
this.currentSketchQuaternion
|
||||
)
|
||||
|
||||
let addingNewSegmentStatus: 'nothing' | 'pending' | 'added' = 'nothing'
|
||||
|
||||
this.scene.add(group)
|
||||
if (!draftSegment) {
|
||||
if (!draftSegment && !skipListeners) {
|
||||
sceneInfra.setCallbacks({
|
||||
onDrag: (args) => {
|
||||
onDragEnd: async () => {
|
||||
if (addingNewSegmentStatus !== 'nothing') {
|
||||
await this.tearDownSketch({ removeAxis: false })
|
||||
this.setupSketch({ sketchPathToNode })
|
||||
}
|
||||
},
|
||||
onDrag: async (args) => {
|
||||
if (args.event.which !== 1) return
|
||||
const group = getParentGroup(args.object, [EXTRA_SEGMENT_HANDLE])
|
||||
if (group?.name === EXTRA_SEGMENT_HANDLE) {
|
||||
const segGroup = getParentGroup(args.object)
|
||||
const pathToNode: PathToNode = segGroup?.userData?.pathToNode
|
||||
const pathToNodeIndex = pathToNode.findIndex(
|
||||
(x) => x[1] === 'PipeExpression'
|
||||
)
|
||||
const pipeIndex = pathToNode[pathToNodeIndex + 1][0] as number
|
||||
if (addingNewSegmentStatus === 'nothing') {
|
||||
const prevSegment = sketchGroup.value[pipeIndex - 2]
|
||||
const yo = addNewSketchLn({
|
||||
node: kclManager.ast,
|
||||
programMemory: kclManager.programMemory,
|
||||
to: [args.intersection2d.x, args.intersection2d.y],
|
||||
from: [prevSegment.from[0], prevSegment.from[1]],
|
||||
fnName:
|
||||
prevSegment.type === 'TangentialArcTo'
|
||||
? 'tangentialArcTo'
|
||||
: 'line',
|
||||
pathToNode: pathToNode,
|
||||
})
|
||||
addingNewSegmentStatus = 'pending'
|
||||
await kclManager.executeAstMock(yo.modifiedAst, {
|
||||
updates: 'code',
|
||||
})
|
||||
await this.tearDownSketch({ removeAxis: false })
|
||||
this.setupSketch({ sketchPathToNode, skipListeners: true })
|
||||
addingNewSegmentStatus = 'added'
|
||||
} else if (addingNewSegmentStatus === 'added') {
|
||||
const pathToNodeForNewSegment = pathToNode.slice(
|
||||
0,
|
||||
pathToNodeIndex
|
||||
)
|
||||
pathToNodeForNewSegment.push([pipeIndex - 2, 'index'])
|
||||
this.onDragSegment({
|
||||
...args,
|
||||
sketchPathToNode: pathToNodeForNewSegment,
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
this.onDragSegment({
|
||||
...args,
|
||||
sketchPathToNode,
|
||||
@ -391,7 +446,7 @@ class SceneEntities {
|
||||
}
|
||||
},
|
||||
})
|
||||
} else {
|
||||
} else if (draftSegment && !skipListeners) {
|
||||
sceneInfra.setCallbacks({
|
||||
onDrag: () => {},
|
||||
onClick: async (args) => {
|
||||
@ -500,6 +555,7 @@ class SceneEntities {
|
||||
variableDeclarationName: string
|
||||
}
|
||||
}) {
|
||||
if (object.name === STRAIGHT_SEGMENT_BODY) return
|
||||
const group = getParentGroup(object)
|
||||
if (!group) return
|
||||
const pathToNode: PathToNode = JSON.parse(
|
||||
@ -606,9 +662,7 @@ class SceneEntities {
|
||||
group.userData.from = from
|
||||
group.userData.to = to
|
||||
group.userData.prevSegment = prevSegment
|
||||
const arrowGroup = group.children.find(
|
||||
(child) => child.userData.type === ARROWHEAD
|
||||
) as Group
|
||||
const arrowGroup = group.getObjectByName(ARROWHEAD) as Group
|
||||
|
||||
arrowGroup.position.set(to[0], to[1], 0)
|
||||
|
||||
@ -683,9 +737,7 @@ class SceneEntities {
|
||||
const shape = new Shape()
|
||||
shape.moveTo(0, -0.08 * scale)
|
||||
shape.lineTo(0, 0.08 * scale) // The width of the line
|
||||
const arrowGroup = group.children.find(
|
||||
(child) => child.userData.type === ARROWHEAD
|
||||
) as Group
|
||||
const arrowGroup = group.getObjectByName(ARROWHEAD) as Group
|
||||
|
||||
arrowGroup.position.set(to[0], to[1], 0)
|
||||
|
||||
@ -698,6 +750,32 @@ class SceneEntities {
|
||||
arrowGroup.quaternion.setFromUnitVectors(new Vector3(0, 1, 0), dir)
|
||||
arrowGroup.scale.set(scale, scale, scale)
|
||||
|
||||
// TODO this should be created in setupSketch, not updateStraightSegment
|
||||
// it should only be updated here
|
||||
const extraSegmentHandle = (group.getObjectByName(EXTRA_SEGMENT_HANDLE) ||
|
||||
(() => {
|
||||
const mat = new MeshBasicMaterial({ color: 0xffffff })
|
||||
const sphereMesh = new Mesh(new SphereGeometry(0.6, 12, 12), mat)
|
||||
|
||||
const handleGroup = new Group()
|
||||
handleGroup.userData.type = EXTRA_SEGMENT_HANDLE
|
||||
handleGroup.name = EXTRA_SEGMENT_HANDLE
|
||||
handleGroup.add(sphereMesh)
|
||||
handleGroup.layers.set(SKETCH_LAYER)
|
||||
handleGroup.traverse((child) => {
|
||||
child.layers.set(SKETCH_LAYER)
|
||||
})
|
||||
return handleGroup
|
||||
})()) as Group
|
||||
|
||||
extraSegmentHandle.position.set(
|
||||
from[0] + 0.08 * (to[0] - from[0]),
|
||||
from[1] + 0.08 * (to[1] - from[1]),
|
||||
0
|
||||
)
|
||||
extraSegmentHandle.scale.set(scale, scale, scale)
|
||||
group.add(extraSegmentHandle)
|
||||
|
||||
const straightSegmentBody = group.children.find(
|
||||
(child) => child.userData.type === STRAIGHT_SEGMENT_BODY
|
||||
) as Mesh
|
||||
|
@ -88,18 +88,25 @@ class SceneInfra {
|
||||
fov = 45
|
||||
fovBeforeAnimate = 45
|
||||
isFovAnimationInProgress = false
|
||||
onDragStartCallback: (arg: OnDragCallbackArgs) => void = () => {}
|
||||
onDragEndCallback: (arg: OnDragCallbackArgs) => void = () => {}
|
||||
onDragCallback: (arg: OnDragCallbackArgs) => void = () => {}
|
||||
onMoveCallback: (arg: onMoveCallbackArgs) => void = () => {}
|
||||
onClickCallback: (arg?: OnClickCallbackArgs) => void = () => {}
|
||||
onMouseEnter: (arg: BaseCallbackArgs2) => void = () => {}
|
||||
onMouseLeave: (arg: BaseCallbackArgs2) => void = () => {}
|
||||
setCallbacks = (callbacks: {
|
||||
onDragStart?: (arg: OnDragCallbackArgs) => void
|
||||
onDragEnd?: (arg: OnDragCallbackArgs) => void
|
||||
onDrag?: (arg: OnDragCallbackArgs) => void
|
||||
onMove?: (arg: onMoveCallbackArgs) => void
|
||||
onClick?: (arg?: OnClickCallbackArgs) => void
|
||||
onMouseEnter?: (arg: BaseCallbackArgs2) => void
|
||||
onMouseLeave?: (arg: BaseCallbackArgs2) => void
|
||||
}) => {
|
||||
console.trace('setting callbacks')
|
||||
this.onDragStartCallback = callbacks.onDragStart || this.onDragStartCallback
|
||||
this.onDragEndCallback = callbacks.onDragEnd || this.onDragEndCallback
|
||||
this.onDragCallback = callbacks.onDrag || this.onDragCallback
|
||||
this.onMoveCallback = callbacks.onMove || this.onMoveCallback
|
||||
this.onClickCallback = callbacks.onClick || this.onClickCallback
|
||||
@ -109,6 +116,8 @@ class SceneInfra {
|
||||
}
|
||||
resetMouseListeners = () => {
|
||||
sceneInfra.setCallbacks({
|
||||
onDragStart: () => {},
|
||||
onDragEnd: () => {},
|
||||
onDrag: () => {},
|
||||
onMove: () => {},
|
||||
onClick: () => {},
|
||||
@ -420,8 +429,13 @@ class SceneInfra {
|
||||
|
||||
if (this.selected) {
|
||||
if (this.selected.hasBeenDragged) {
|
||||
// this is where we could fire a onDragEnd event
|
||||
// console.log('onDragEnd', this.selected)
|
||||
// TODO do the types properly here
|
||||
this.onDragEndCallback({
|
||||
object: this.selected.object,
|
||||
event,
|
||||
intersection2d: planeIntersectPoint?.intersection2d,
|
||||
...planeIntersectPoint,
|
||||
} as any)
|
||||
} else if (planeIntersectPoint) {
|
||||
// fire onClick event as there was no drags
|
||||
this.onClickCallback({
|
||||
|
@ -81,6 +81,7 @@ export function straightSegment({
|
||||
pathToNode,
|
||||
isSelected: false,
|
||||
}
|
||||
group.name = STRAIGHT_SEGMENT
|
||||
|
||||
const arrowGroup = createArrowhead(scale)
|
||||
arrowGroup.position.set(to[0], to[1], 0)
|
||||
@ -169,6 +170,7 @@ export function tangentialArcToSegment({
|
||||
pathToNode,
|
||||
isSelected: false,
|
||||
}
|
||||
group.name = TANGENTIAL_ARC_TO_SEGMENT
|
||||
|
||||
const arrowGroup = createArrowhead(scale)
|
||||
arrowGroup.position.set(to[0], to[1], 0)
|
||||
|
@ -181,6 +181,10 @@ export const line: SketchLineHelper = {
|
||||
pathToNode,
|
||||
'PipeExpression'
|
||||
)
|
||||
const { node: callExpression } = getNodeFromPath<
|
||||
PipeExpression | CallExpression
|
||||
>(_node, pathToNode, 'CallExpression')
|
||||
|
||||
const { node: varDec } = getNodeFromPath<VariableDeclarator>(
|
||||
_node,
|
||||
pathToNode,
|
||||
@ -190,6 +194,38 @@ export const line: SketchLineHelper = {
|
||||
const newXVal = createLiteral(roundOff(to[0] - from[0], 2))
|
||||
const newYVal = createLiteral(roundOff(to[1] - from[1], 2))
|
||||
|
||||
const isAddingSegmentBetween =
|
||||
callExpression.type === 'CallExpression' &&
|
||||
callExpression.start >= pipe.start &&
|
||||
callExpression.end <= pipe.end
|
||||
if (
|
||||
isAddingSegmentBetween &&
|
||||
!createCallback &&
|
||||
pipe.type === 'PipeExpression'
|
||||
) {
|
||||
const callExp = createCallExpression('line', [
|
||||
createArrayExpression([newXVal, newYVal]),
|
||||
createPipeSubstitution(),
|
||||
])
|
||||
const pathToNodeIndex = pathToNode.findIndex(
|
||||
(x) => x[1] === 'PipeExpression'
|
||||
)
|
||||
const pipeIndex = pathToNode[pathToNodeIndex + 1][0]
|
||||
if (typeof pipeIndex === 'undefined' || typeof pipeIndex === 'string') {
|
||||
console.warn('pipeIndex is undefined')
|
||||
return
|
||||
}
|
||||
pipe.body = [
|
||||
...pipe.body.slice(0, pipeIndex),
|
||||
callExp,
|
||||
...pipe.body.slice(pipeIndex),
|
||||
]
|
||||
return {
|
||||
modifiedAst: _node,
|
||||
pathToNode,
|
||||
}
|
||||
}
|
||||
|
||||
if (replaceExisting && createCallback && pipe.type !== 'CallExpression') {
|
||||
const { index: callIndex } = splitPathAtPipeExpression(pathToNode)
|
||||
const { callExp, valueUsedInTransform } = createCallback(
|
||||
@ -1011,15 +1047,6 @@ export function changeSketchArguments(
|
||||
throw new Error(`not a sketch line helper: ${callExpression?.callee?.name}`)
|
||||
}
|
||||
|
||||
interface CreateLineFnCallArgs {
|
||||
node: Program
|
||||
programMemory: ProgramMemory
|
||||
to: [number, number]
|
||||
from: [number, number]
|
||||
fnName: ToolTip
|
||||
pathToNode: PathToNode
|
||||
}
|
||||
|
||||
export function compareVec2Epsilon(
|
||||
vec1: [number, number],
|
||||
vec2: [number, number],
|
||||
@ -1044,6 +1071,15 @@ export function compareVec2Epsilon2(
|
||||
return distance < compareEpsilon
|
||||
}
|
||||
|
||||
interface CreateLineFnCallArgs {
|
||||
node: Program
|
||||
programMemory: ProgramMemory
|
||||
to: [number, number]
|
||||
from: [number, number]
|
||||
fnName: ToolTip
|
||||
pathToNode: PathToNode
|
||||
}
|
||||
|
||||
export function addNewSketchLn({
|
||||
node: _node,
|
||||
programMemory: previousProgramMemory,
|
||||
|
Reference in New Issue
Block a user