Compare commits
	
		
			1 Commits
		
	
	
		
			achalmers/
			...
			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
	