Compare commits
	
		
			6 Commits
		
	
	
		
			tab-demo
			...
			jtran/fix-
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 1953ca0607 | |||
| cb9fa71645 | |||
| a7f0a5607d | |||
| eb28ed6cbf | |||
| 3c84ef8592 | |||
| 9b966de7f0 | 
| @ -84,7 +84,11 @@ import { | ||||
|   createPipeSubstitution, | ||||
|   findUniqueName, | ||||
| } from 'lang/modifyAst' | ||||
| import { Selections, getEventForSegmentSelection } from 'lib/selections' | ||||
| import { | ||||
|   Selection, | ||||
|   Selections, | ||||
|   getEventForSegmentSelection, | ||||
| } from 'lib/selections' | ||||
| import { getTangentPointFromPreviousArc } from 'lib/utils2d' | ||||
| import { createGridHelper, orthoScale, perspScale } from './helpers' | ||||
| import { Models } from '@kittycad/lib' | ||||
| @ -98,6 +102,11 @@ import { | ||||
| import { getThemeColorForThreeJs } from 'lib/theme' | ||||
| import { err, trap } from 'lib/trap' | ||||
| import { CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer' | ||||
| import { | ||||
|   ArtifactGraph, | ||||
|   ArtifactId, | ||||
|   getPlaneOrFaceFromSelection, | ||||
| } from 'lang/std/artifactGraph' | ||||
|  | ||||
| type DraftSegment = 'line' | 'tangentialArcTo' | ||||
|  | ||||
| @ -582,15 +591,20 @@ export class SceneEntities { | ||||
|     const _node1 = getNodeFromPath<VariableDeclaration>( | ||||
|       _ast, | ||||
|       sketchPathToNode || [], | ||||
|       'VariableDeclaration' | ||||
|     ) | ||||
|       ['VariableDeclaration', 'ExpressionStatement'] | ||||
|     ) as { node: { type: string } } | Error | ||||
|     if (trap(_node1)) return Promise.reject(_node1) | ||||
|     const variableDeclarationName = | ||||
|       _node1.node?.declarations?.[0]?.id?.name || '' | ||||
|     const variableDeclarationName = (_node1.node.type === 'VariableDeclaration') ? | ||||
|       (_node1.node as VariableDeclaration).declarations[0]?.id?.name || '' : | ||||
|       '' | ||||
|  | ||||
|     const sg = kclManager.programMemory.get( | ||||
|     const sgMemItem = kclManager.programMemory.get( | ||||
|       variableDeclarationName | ||||
|     ) as SketchGroup | ||||
|     ) | ||||
|     if (sgMemItem?.type !== 'SketchGroup') { | ||||
|       return Promise.reject(new Error('SketchGroup not found in programMemory')) | ||||
|     } | ||||
|     const sg: SketchGroup = sgMemItem | ||||
|     const lastSeg = sg.value.slice(-1)[0] || sg.start | ||||
|  | ||||
|     const index = sg.value.length // because we've added a new segment that's not in the memory yet, no need for `-1` | ||||
| @ -1762,6 +1776,33 @@ export function getParentGroup( | ||||
|   return null | ||||
| } | ||||
|  | ||||
| export async function planeOrFaceFromSelection({ | ||||
|   artifactGraph, | ||||
|   selection, | ||||
| }: { | ||||
|   artifactGraph: ArtifactGraph | ||||
|   selection: Selection | ||||
| }): Promise<{ | ||||
|   id: ArtifactId | ||||
|   faceDetails: Models['GetSketchModePlane_type'] | ||||
| } | null> { | ||||
|   // If the selection doesn't have an artifactId associated with it, we can't | ||||
|   // do it. | ||||
|   if (!selection.artifactId) return null | ||||
|  | ||||
|   const planeOrFace = getPlaneOrFaceFromSelection( | ||||
|     selection.artifactId, | ||||
|     artifactGraph | ||||
|   ) | ||||
|   if (!planeOrFace) return null | ||||
|   if (planeOrFace?.type === 'plane') { | ||||
|     const faceDetails = await getFaceDetails(planeOrFace.id) | ||||
|     return { id: planeOrFace.id, faceDetails } | ||||
|   } | ||||
|   // TODO: Handle wall or cap artifact. | ||||
|   return null | ||||
| } | ||||
|  | ||||
| export function sketchGroupFromPathToNode({ | ||||
|   pathToNode, | ||||
|   ast, | ||||
| @ -1827,11 +1868,51 @@ export function getSketchQuaternion( | ||||
|   return getQuaternionFromZAxis(massageFormats(zAxis)) | ||||
| } | ||||
| export async function getSketchOrientationDetails( | ||||
|   artifactGraph: ArtifactGraph, | ||||
|   selection: Selection, | ||||
|   sketchPathToNode: PathToNode | ||||
| ): Promise<{ | ||||
|   quat: Quaternion | ||||
|   sketchDetails: SketchDetails & { faceId?: string } | ||||
|   sketchDetails: { | ||||
|     zAxis: [number, number, number] | ||||
|     yAxis: [number, number, number] | ||||
|     origin: [number, number, number] | ||||
|     faceId: string | ||||
|   } | ||||
| }> { | ||||
|   const plane = await planeOrFaceFromSelection({ | ||||
|     artifactGraph, | ||||
|     selection, | ||||
|   }) | ||||
|   if (plane) { | ||||
|     const details = plane.faceDetails | ||||
|     console.warn('Found plane', plane) | ||||
|     const zAxis: [number, number, number] = [ | ||||
|       details.z_axis.x, | ||||
|       details.z_axis.y, | ||||
|       details.z_axis.z, | ||||
|     ] | ||||
|     const yAxis: [number, number, number] = [ | ||||
|       details.y_axis.x, | ||||
|       details.y_axis.y, | ||||
|       details.y_axis.z, | ||||
|     ] | ||||
|     const origin: [number, number, number] = [ | ||||
|       details.origin.x, | ||||
|       details.origin.y, | ||||
|       details.origin.z, | ||||
|     ] | ||||
|     return { | ||||
|       sketchDetails: { | ||||
|         zAxis, | ||||
|         yAxis, | ||||
|         origin, | ||||
|         faceId: plane.id, | ||||
|       }, | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // We couldn't find the plane or face, so try to look at the AST, and find it | ||||
|   // through there. | ||||
|   const sketchGroup = sketchGroupFromPathToNode({ | ||||
|     pathToNode: sketchPathToNode, | ||||
|     ast: kclManager.ast, | ||||
| @ -1843,9 +1924,7 @@ export async function getSketchOrientationDetails( | ||||
|   if (sketchGroup.on.type === 'plane') { | ||||
|     const zAxis = sketchGroup?.on.zAxis | ||||
|     return { | ||||
|       quat: getQuaternionFromZAxis(massageFormats(zAxis)), | ||||
|       sketchDetails: { | ||||
|         sketchPathToNode, | ||||
|         zAxis: [zAxis.x, zAxis.y, zAxis.z], | ||||
|         yAxis: [ | ||||
|           sketchGroup.on.yAxis.x, | ||||
| @ -1864,14 +1943,8 @@ export async function getSketchOrientationDetails( | ||||
|     if (!faceInfo?.origin || !faceInfo?.z_axis || !faceInfo?.y_axis) | ||||
|       return Promise.reject('face info') | ||||
|     const { z_axis, y_axis, origin } = faceInfo | ||||
|     const quaternion = quaternionFromUpNForward( | ||||
|       new Vector3(y_axis.x, y_axis.y, y_axis.z), | ||||
|       new Vector3(z_axis.x, z_axis.y, z_axis.z) | ||||
|     ) | ||||
|     return { | ||||
|       quat: quaternion, | ||||
|       sketchDetails: { | ||||
|         sketchPathToNode, | ||||
|         zAxis: [z_axis.x, z_axis.y, z_axis.z], | ||||
|         yAxis: [y_axis.x, y_axis.y, y_axis.z], | ||||
|         origin: [origin.x, origin.y, origin.z], | ||||
|  | ||||
| @ -589,12 +589,17 @@ export const ModelingMachineProvider = ({ | ||||
|           } | ||||
|         }, | ||||
|         'animate-to-sketch': async ({ selectionRanges }) => { | ||||
|           const sourceRange = selectionRanges.codeBasedSelections[0].range | ||||
|           const selection = selectionRanges.codeBasedSelections[0] | ||||
|           const sourceRange = selection.range | ||||
|           const sketchPathToNode = getNodePathFromSourceRange( | ||||
|             kclManager.ast, | ||||
|             sourceRange | ||||
|           ) | ||||
|           const info = await getSketchOrientationDetails(sketchPathToNode || []) | ||||
|           const info = await getSketchOrientationDetails( | ||||
|             engineCommandManager.artifactGraph, | ||||
|             selection, | ||||
|             sketchPathToNode || [] | ||||
|           ) | ||||
|           await letEngineAnimateAndSyncCamAfter( | ||||
|             engineCommandManager, | ||||
|             info?.sketchDetails?.faceId || '' | ||||
|  | ||||
| @ -18,6 +18,7 @@ import { | ||||
|   ProgramMemory, | ||||
|   SourceRange, | ||||
|   SketchGroup, | ||||
|   ExpressionStatement, | ||||
| } from './wasm' | ||||
| import { | ||||
|   isNodeSafeToReplacePath, | ||||
| @ -82,15 +83,22 @@ export function addStartProfileAt( | ||||
|   const _node1 = getNodeFromPath<VariableDeclaration>( | ||||
|     node, | ||||
|     pathToNode, | ||||
|     'VariableDeclaration' | ||||
|   ) | ||||
|     ['VariableDeclaration', 'ExpressionStatement'] | ||||
|   ) as { node: { type: string } } | Error | ||||
|   if (err(_node1)) return _node1 | ||||
|   const variableDeclaration = _node1.node | ||||
|   if (variableDeclaration.type !== 'VariableDeclaration') { | ||||
|     return new Error('variableDeclaration.init.type !== PipeExpression') | ||||
|   } | ||||
|   const _node = { ...node } | ||||
|   const init = variableDeclaration.declarations[0].init | ||||
|   let expr: Value | ||||
|   let variableDeclaration: VariableDeclaration | undefined | ||||
|   if (_node1.node.type === 'VariableDeclaration') { | ||||
|     const node: VariableDeclaration = _node1.node as VariableDeclaration | ||||
|     variableDeclaration = node | ||||
|     expr = node.declarations[0].init | ||||
|   } else if (_node1.node.type === 'ExpressionStatement') { | ||||
|     const node: ExpressionStatement = _node1.node as ExpressionStatement | ||||
|     expr = node.expression | ||||
|   } else { | ||||
|     return new Error(`Unrecognized node type ${_node1.node.type}`) | ||||
|   } | ||||
|   const startProfileAt = createCallExpressionStdLib('startProfileAt', [ | ||||
|     createArrayExpression([ | ||||
|       createLiteral(roundOff(at[0])), | ||||
| @ -98,11 +106,11 @@ export function addStartProfileAt( | ||||
|     ]), | ||||
|     createPipeSubstitution(), | ||||
|   ]) | ||||
|   if (init.type === 'PipeExpression') { | ||||
|     init.body.splice(1, 0, startProfileAt) | ||||
|   } else { | ||||
|   if (expr.type === 'PipeExpression') { | ||||
|     expr.body.splice(1, 0, startProfileAt) | ||||
|   } else if (variableDeclaration) { | ||||
|     variableDeclaration.declarations[0].init = createPipeExpression([ | ||||
|       init, | ||||
|       expr, | ||||
|       startProfileAt, | ||||
|     ]) | ||||
|   } | ||||
|  | ||||
| @ -791,7 +791,7 @@ export function isSingleCursorInPipe( | ||||
|   const pathToNode = getNodePathFromSourceRange(ast, selection.range) | ||||
|   const nodeTypes = pathToNode.map(([, type]) => type) | ||||
|   if (nodeTypes.includes('FunctionExpression')) return false | ||||
|   if (!nodeTypes.includes('VariableDeclaration')) return false | ||||
|   // if (!nodeTypes.includes('VariableDeclaration')) return false | ||||
|   if (nodeTypes.includes('PipeExpression')) return true | ||||
|   return false | ||||
| } | ||||
|  | ||||
| @ -3,6 +3,8 @@ import { Models } from '@kittycad/lib' | ||||
| import { getNodePathFromSourceRange } from 'lang/queryAst' | ||||
| import { err } from 'lib/trap' | ||||
|  | ||||
| export type ArtifactId = string | ||||
|  | ||||
| interface CommonCommandProperties { | ||||
|   range: SourceRange | ||||
|   pathToNode: PathToNode | ||||
| @ -10,17 +12,20 @@ interface CommonCommandProperties { | ||||
|  | ||||
| export interface PlaneArtifact { | ||||
|   type: 'plane' | ||||
|   id: ArtifactId | ||||
|   pathIds: Array<string> | ||||
|   codeRef: CommonCommandProperties | ||||
| } | ||||
| export interface PlaneArtifactRich { | ||||
|   type: 'plane' | ||||
|   id: ArtifactId | ||||
|   paths: Array<PathArtifact> | ||||
|   codeRef: CommonCommandProperties | ||||
| } | ||||
|  | ||||
| export interface PathArtifact { | ||||
|   type: 'path' | ||||
|   id: ArtifactId | ||||
|   planeId: string | ||||
|   segIds: Array<string> | ||||
|   extrusionId: string | ||||
| @ -30,10 +35,12 @@ export interface PathArtifact { | ||||
|  | ||||
| interface solid2D { | ||||
|   type: 'solid2D' | ||||
|   id: ArtifactId | ||||
|   pathId: string | ||||
| } | ||||
| export interface PathArtifactRich { | ||||
|   type: 'path' | ||||
|   id: ArtifactId | ||||
|   plane: PlaneArtifact | WallArtifact | ||||
|   segments: Array<SegmentArtifact> | ||||
|   extrusion: ExtrusionArtifact | ||||
| @ -42,6 +49,7 @@ export interface PathArtifactRich { | ||||
|  | ||||
| interface SegmentArtifact { | ||||
|   type: 'segment' | ||||
|   id: ArtifactId | ||||
|   pathId: string | ||||
|   surfaceId: string | ||||
|   edgeIds: Array<string> | ||||
| @ -50,6 +58,7 @@ interface SegmentArtifact { | ||||
| } | ||||
| interface SegmentArtifactRich { | ||||
|   type: 'segment' | ||||
|   id: ArtifactId | ||||
|   path: PathArtifact | ||||
|   surf: WallArtifact | ||||
|   edges: Array<ExtrudeEdge> | ||||
| @ -59,6 +68,7 @@ interface SegmentArtifactRich { | ||||
|  | ||||
| interface ExtrusionArtifact { | ||||
|   type: 'extrusion' | ||||
|   id: ArtifactId | ||||
|   pathId: string | ||||
|   surfaceIds: Array<string> | ||||
|   edgeIds: Array<string> | ||||
| @ -66,6 +76,7 @@ interface ExtrusionArtifact { | ||||
| } | ||||
| interface ExtrusionArtifactRich { | ||||
|   type: 'extrusion' | ||||
|   id: ArtifactId | ||||
|   path: PathArtifact | ||||
|   surfaces: Array<WallArtifact | CapArtifact> | ||||
|   edges: Array<ExtrudeEdge> | ||||
| @ -74,6 +85,7 @@ interface ExtrusionArtifactRich { | ||||
|  | ||||
| interface WallArtifact { | ||||
|   type: 'wall' | ||||
|   id: ArtifactId | ||||
|   segId: string | ||||
|   edgeCutEdgeIds: Array<string> | ||||
|   extrusionId: string | ||||
| @ -81,6 +93,7 @@ interface WallArtifact { | ||||
| } | ||||
| interface CapArtifact { | ||||
|   type: 'cap' | ||||
|   id: ArtifactId | ||||
|   subType: 'start' | 'end' | ||||
|   edgeCutEdgeIds: Array<string> | ||||
|   extrusionId: string | ||||
| @ -89,6 +102,7 @@ interface CapArtifact { | ||||
|  | ||||
| interface ExtrudeEdge { | ||||
|   type: 'extrudeEdge' | ||||
|   id: ArtifactId | ||||
|   segId: string | ||||
|   extrusionId: string | ||||
|   edgeId: string | ||||
| @ -97,6 +111,7 @@ interface ExtrudeEdge { | ||||
| /** A edgeCut is a more generic term for both fillet or chamfer */ | ||||
| interface EdgeCut { | ||||
|   type: 'edgeCut' | ||||
|   id: ArtifactId | ||||
|   subType: 'fillet' | 'chamfer' | ||||
|   consumedEdgeId: string | ||||
|   edgeIds: Array<string> | ||||
| @ -106,6 +121,7 @@ interface EdgeCut { | ||||
|  | ||||
| interface EdgeCutEdge { | ||||
|   type: 'edgeCutEdge' | ||||
|   id: ArtifactId | ||||
|   edgeCutId: string | ||||
|   surfaceId: string | ||||
| } | ||||
| @ -122,7 +138,7 @@ export type Artifact = | ||||
|   | EdgeCutEdge | ||||
|   | solid2D | ||||
|  | ||||
| export type ArtifactGraph = Map<string, Artifact> | ||||
| export type ArtifactGraph = Map<ArtifactId, Artifact> | ||||
|  | ||||
| export type EngineCommand = Models['WebSocketRequest_type'] | ||||
|  | ||||
| @ -149,7 +165,7 @@ export function createArtifactGraph({ | ||||
|   responseMap: ResponseMap | ||||
|   ast: Program | ||||
| }) { | ||||
|   const myMap = new Map<string, Artifact>() | ||||
|   const myMap = new Map<ArtifactId, Artifact>() | ||||
|  | ||||
|   /** see docstring for {@link getArtifactsToUpdate} as to why this is needed */ | ||||
|   let currentPlaneId = '' | ||||
| @ -166,7 +182,7 @@ export function createArtifactGraph({ | ||||
|     const artifactsToUpdate = getArtifactsToUpdate({ | ||||
|       orderedCommand, | ||||
|       responseMap, | ||||
|       getArtifact: (id: string) => myMap.get(id), | ||||
|       getArtifact: (id: ArtifactId) => myMap.get(id), | ||||
|       currentPlaneId, | ||||
|       ast, | ||||
|     }) | ||||
| @ -210,7 +226,7 @@ function mergeArtifacts( | ||||
|  * It does not mutate the map directly, but returns an array of artifacts to update | ||||
|  * | ||||
|  * @param currentPlaneId is only needed for `start_path` commands because this command does not have a pathId | ||||
|  * instead it relies on the id used with the `enable_sketch_mode` command, so this much be kept track of | ||||
|  * instead it relies on the id used with the `enable_sketch_mode` command, so this must be kept track of | ||||
|  * outside of this function. It would be good to update the `start_path` command to include the planeId so we | ||||
|  * can remove this. | ||||
|  */ | ||||
| @ -224,11 +240,11 @@ export function getArtifactsToUpdate({ | ||||
|   orderedCommand: OrderedCommand | ||||
|   responseMap: ResponseMap | ||||
|   /** Passing in a getter because we don't wan this function to update the map directly */ | ||||
|   getArtifact: (id: string) => Artifact | undefined | ||||
|   getArtifact: (id: ArtifactId) => Artifact | undefined | ||||
|   currentPlaneId: string | ||||
|   ast: Program | ||||
| }): Array<{ | ||||
|   id: string | ||||
|   id: ArtifactId | ||||
|   artifact: Artifact | ||||
| }> { | ||||
|   const pathToNode = getNodePathFromSourceRange(ast, range) | ||||
| @ -253,6 +269,7 @@ export function getArtifactsToUpdate({ | ||||
|           id: currentPlaneId, | ||||
|           artifact: { | ||||
|             type: 'wall', | ||||
|             id: currentPlaneId, | ||||
|             segId: existingPlane.segId, | ||||
|             edgeCutEdgeIds: existingPlane.edgeCutEdgeIds, | ||||
|             extrusionId: existingPlane.extrusionId, | ||||
| @ -262,7 +279,10 @@ export function getArtifactsToUpdate({ | ||||
|       ] | ||||
|     } else { | ||||
|       return [ | ||||
|         { id: currentPlaneId, artifact: { type: 'plane', pathIds, codeRef } }, | ||||
|         { | ||||
|           id: currentPlaneId, | ||||
|           artifact: { type: 'plane', id: currentPlaneId, pathIds, codeRef }, | ||||
|         }, | ||||
|       ] | ||||
|     } | ||||
|   } else if (cmd.type === 'start_path') { | ||||
| @ -270,6 +290,7 @@ export function getArtifactsToUpdate({ | ||||
|       id, | ||||
|       artifact: { | ||||
|         type: 'path', | ||||
|         id, | ||||
|         segIds: [], | ||||
|         planeId: currentPlaneId, | ||||
|         extrusionId: '', | ||||
| @ -282,7 +303,7 @@ export function getArtifactsToUpdate({ | ||||
|     if (plane?.type === 'plane') { | ||||
|       returnArr.push({ | ||||
|         id: currentPlaneId, | ||||
|         artifact: { type: 'plane', pathIds: [id], codeRef }, | ||||
|         artifact: { type: 'plane', id: currentPlaneId, pathIds: [id], codeRef }, | ||||
|       }) | ||||
|     } | ||||
|     if (plane?.type === 'wall') { | ||||
| @ -290,6 +311,7 @@ export function getArtifactsToUpdate({ | ||||
|         id: currentPlaneId, | ||||
|         artifact: { | ||||
|           type: 'wall', | ||||
|           id: currentPlaneId, | ||||
|           segId: plane.segId, | ||||
|           edgeCutEdgeIds: plane.edgeCutEdgeIds, | ||||
|           extrusionId: plane.extrusionId, | ||||
| @ -304,6 +326,7 @@ export function getArtifactsToUpdate({ | ||||
|       id, | ||||
|       artifact: { | ||||
|         type: 'segment', | ||||
|         id, | ||||
|         pathId, | ||||
|         surfaceId: '', | ||||
|         edgeIds: [], | ||||
| @ -313,21 +336,22 @@ export function getArtifactsToUpdate({ | ||||
|     const path = getArtifact(pathId) | ||||
|     if (path?.type === 'path') | ||||
|       returnArr.push({ | ||||
|         id: pathId, | ||||
|         id: path.id, | ||||
|         artifact: { ...path, segIds: [id] }, | ||||
|       }) | ||||
|     if ( | ||||
|       response?.type === 'modeling' && | ||||
|       response.data.modeling_response.type === 'close_path' | ||||
|     ) { | ||||
|       const id = response.data.modeling_response.data.face_id | ||||
|       returnArr.push({ | ||||
|         id: response.data.modeling_response.data.face_id, | ||||
|         artifact: { type: 'solid2D', pathId }, | ||||
|         id, | ||||
|         artifact: { type: 'solid2D', id, pathId }, | ||||
|       }) | ||||
|       const path = getArtifact(pathId) | ||||
|       if (path?.type === 'path') | ||||
|         returnArr.push({ | ||||
|           id: pathId, | ||||
|           id: path.id, | ||||
|           artifact: { | ||||
|             ...path, | ||||
|             solid2dId: response.data.modeling_response.data.face_id, | ||||
| @ -340,6 +364,7 @@ export function getArtifactsToUpdate({ | ||||
|       id, | ||||
|       artifact: { | ||||
|         type: 'extrusion', | ||||
|         id, | ||||
|         pathId: cmd.target, | ||||
|         surfaceIds: [], | ||||
|         edgeIds: [], | ||||
| @ -349,7 +374,7 @@ export function getArtifactsToUpdate({ | ||||
|     const path = getArtifact(cmd.target) | ||||
|     if (path?.type === 'path') | ||||
|       returnArr.push({ | ||||
|         id: cmd.target, | ||||
|         id: path.id, | ||||
|         artifact: { ...path, extrusionId: id }, | ||||
|       }) | ||||
|     return returnArr | ||||
| @ -371,6 +396,7 @@ export function getArtifactsToUpdate({ | ||||
|               id: face_id, | ||||
|               artifact: { | ||||
|                 type: 'wall', | ||||
|                 id: face_id, | ||||
|                 segId: curve_id, | ||||
|                 edgeCutEdgeIds: [], | ||||
|                 extrusionId: path.extrusionId, | ||||
| @ -378,7 +404,7 @@ export function getArtifactsToUpdate({ | ||||
|               }, | ||||
|             }) | ||||
|             returnArr.push({ | ||||
|               id: curve_id, | ||||
|               id: seg.id, | ||||
|               artifact: { ...seg, surfaceId: face_id }, | ||||
|             }) | ||||
|             const extrusion = getArtifact(path.extrusionId) | ||||
| @ -403,6 +429,7 @@ export function getArtifactsToUpdate({ | ||||
|             id: face_id, | ||||
|             artifact: { | ||||
|               type: 'cap', | ||||
|               id: face_id, | ||||
|               subType: cap === 'bottom' ? 'start' : 'end', | ||||
|               edgeCutEdgeIds: [], | ||||
|               extrusionId: path.extrusionId, | ||||
| @ -412,7 +439,7 @@ export function getArtifactsToUpdate({ | ||||
|           const extrusion = getArtifact(path.extrusionId) | ||||
|           if (extrusion?.type !== 'extrusion') return | ||||
|           returnArr.push({ | ||||
|             id: path.extrusionId, | ||||
|             id: extrusion.id, | ||||
|             artifact: { | ||||
|               ...extrusion, | ||||
|               surfaceIds: [face_id], | ||||
| @ -427,6 +454,7 @@ export function getArtifactsToUpdate({ | ||||
|       id, | ||||
|       artifact: { | ||||
|         type: 'edgeCut', | ||||
|         id, | ||||
|         subType: cmd.cut_type, | ||||
|         consumedEdgeId: cmd.edge_id, | ||||
|         edgeIds: [], | ||||
| @ -437,7 +465,7 @@ export function getArtifactsToUpdate({ | ||||
|     const consumedEdge = getArtifact(cmd.edge_id) | ||||
|     if (consumedEdge?.type === 'segment') { | ||||
|       returnArr.push({ | ||||
|         id: cmd.edge_id, | ||||
|         id: consumedEdge.id, | ||||
|         artifact: { ...consumedEdge, edgeCutId: id }, | ||||
|       }) | ||||
|     } | ||||
| @ -464,7 +492,7 @@ export function filterArtifacts<T extends Artifact['type'][]>( | ||||
|         (!predicate || | ||||
|           predicate(value as Extract<Artifact, { type: T[number] }>)) | ||||
|     ) | ||||
|   ) as Map<string, Extract<Artifact, { type: T[number] }>> | ||||
|   ) as Map<ArtifactId, Extract<Artifact, { type: T[number] }>> | ||||
| } | ||||
|  | ||||
| export function getArtifactsOfTypes<T extends Artifact['type'][]>( | ||||
| @ -478,7 +506,7 @@ export function getArtifactsOfTypes<T extends Artifact['type'][]>( | ||||
|     predicate?: (value: Extract<Artifact, { type: T[number] }>) => boolean | ||||
|   }, | ||||
|   map: ArtifactGraph | ||||
| ): Map<string, Extract<Artifact, { type: T[number] }>> { | ||||
| ): Map<ArtifactId, Extract<Artifact, { type: T[number] }>> { | ||||
|   return new Map( | ||||
|     [...map].filter( | ||||
|       ([key, value]) => | ||||
| @ -487,7 +515,7 @@ export function getArtifactsOfTypes<T extends Artifact['type'][]>( | ||||
|         (!predicate || | ||||
|           predicate(value as Extract<Artifact, { type: T[number] }>)) | ||||
|     ) | ||||
|   ) as Map<string, Extract<Artifact, { type: T[number] }>> | ||||
|   ) as Map<ArtifactId, Extract<Artifact, { type: T[number] }>> | ||||
| } | ||||
|  | ||||
| export function getArtifactOfTypes<T extends Artifact['type'][]>( | ||||
| @ -495,7 +523,7 @@ export function getArtifactOfTypes<T extends Artifact['type'][]>( | ||||
|     key, | ||||
|     types, | ||||
|   }: { | ||||
|     key: string | ||||
|     key: ArtifactId | ||||
|     types: T | ||||
|   }, | ||||
|   map: ArtifactGraph | ||||
| @ -517,6 +545,7 @@ export function expandPlane( | ||||
|   ) | ||||
|   return { | ||||
|     type: 'plane', | ||||
|     id: plane.id, | ||||
|     paths: Array.from(paths.values()), | ||||
|     codeRef: plane.codeRef, | ||||
|   } | ||||
| @ -545,6 +574,7 @@ export function expandPath( | ||||
|   if (err(plane)) return plane | ||||
|   return { | ||||
|     type: 'path', | ||||
|     id: path.id, | ||||
|     segments: Array.from(segs.values()), | ||||
|     extrusion, | ||||
|     plane, | ||||
| @ -571,6 +601,7 @@ export function expandExtrusion( | ||||
|   if (err(path)) return path | ||||
|   return { | ||||
|     type: 'extrusion', | ||||
|     id: extrusion.id, | ||||
|     surfaces: Array.from(surfs.values()), | ||||
|     edges: Array.from(edges.values()), | ||||
|     path, | ||||
| @ -606,6 +637,7 @@ export function expandSegment( | ||||
|  | ||||
|   return { | ||||
|     type: 'segment', | ||||
|     id: segment.id, | ||||
|     path, | ||||
|     surf, | ||||
|     edges: Array.from(edges.values()), | ||||
| @ -656,7 +688,7 @@ export function getWallCodeRef( | ||||
| } | ||||
|  | ||||
| export function getExtrusionFromSuspectedExtrudeSurface( | ||||
|   id: string, | ||||
|   id: ArtifactId, | ||||
|   artifactGraph: ArtifactGraph | ||||
| ): ExtrusionArtifact | Error { | ||||
|   const artifact = getArtifactOfTypes( | ||||
| @ -671,7 +703,7 @@ export function getExtrusionFromSuspectedExtrudeSurface( | ||||
| } | ||||
|  | ||||
| export function getExtrusionFromSuspectedPath( | ||||
|   id: string, | ||||
|   id: ArtifactId, | ||||
|   artifactGraph: ArtifactGraph | ||||
| ): ExtrusionArtifact | Error { | ||||
|   const path = getArtifactOfTypes({ key: id, types: ['path'] }, artifactGraph) | ||||
| @ -681,3 +713,33 @@ export function getExtrusionFromSuspectedPath( | ||||
|     artifactGraph | ||||
|   ) | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Get the plane or face from a selection. | ||||
|  * | ||||
|  * TODO: Handle sketch on face. | ||||
|  */ | ||||
| export function getPlaneOrFaceFromSelection( | ||||
|   id: ArtifactId, | ||||
|   artifactGraph: ArtifactGraph | ||||
| ): PlaneArtifactRich | null { | ||||
|   const selection = artifactGraph.get(id) | ||||
|   if (!selection) return null | ||||
|   if (selection.type === 'solid2D') { | ||||
|     const path = artifactGraph.get(selection.pathId) | ||||
|     if (path?.type !== 'path') return null | ||||
|     const plane = artifactGraph.get(path.planeId) | ||||
|     if (plane?.type !== 'plane') return null | ||||
|     return expandPlane(plane, artifactGraph) | ||||
|   } else if (selection.type === 'wall' || selection.type === 'cap') { | ||||
|     const extrusion = artifactGraph.get(selection.extrusionId) | ||||
|     if (extrusion?.type !== 'extrusion') return null | ||||
|     const path = artifactGraph.get(extrusion.pathId) | ||||
|     if (path?.type !== 'path') return null | ||||
|     const plane = artifactGraph.get(path.planeId) | ||||
|     // TODO: For sketch on face, this won't be a plane. | ||||
|     if (plane?.type !== 'plane') return null | ||||
|     return expandPlane(plane, artifactGraph) | ||||
|   } | ||||
|   return null | ||||
| } | ||||
|  | ||||
| @ -30,6 +30,7 @@ import { AXIS_GROUP, X_AXIS } from 'clientSideScene/sceneInfra' | ||||
| import { PathToNodeMap } from 'lang/std/sketchcombos' | ||||
| import { err } from 'lib/trap' | ||||
| import { | ||||
|   ArtifactId, | ||||
|   getArtifactOfTypes, | ||||
|   getArtifactsOfTypes, | ||||
|   getCapCodeRef, | ||||
| @ -56,6 +57,7 @@ export type Selection = { | ||||
|     | 'line' | ||||
|     | 'arc' | ||||
|     | 'all' | ||||
|   artifactId?: ArtifactId | ||||
|   range: SourceRange | ||||
| } | ||||
| export type Selections = { | ||||
| @ -100,7 +102,11 @@ export async function getEventForSelectWithPoint({ | ||||
|       type: 'Set selection', | ||||
|       data: { | ||||
|         selectionType: 'singleCodeCursor', | ||||
|         selection: { range: codeRef.range, type: 'solid2D' }, | ||||
|         selection: { | ||||
|           artifactId: data.entity_id, | ||||
|           range: codeRef.range, | ||||
|           type: 'solid2D', | ||||
|         }, | ||||
|       }, | ||||
|     } | ||||
|   } | ||||
| @ -112,6 +118,7 @@ export async function getEventForSelectWithPoint({ | ||||
|       data: { | ||||
|         selectionType: 'singleCodeCursor', | ||||
|         selection: { | ||||
|           artifactId: data.entity_id, | ||||
|           range: codeRef.range, | ||||
|           type: _artifact?.subType === 'end' ? 'end-cap' : 'start-cap', | ||||
|         }, | ||||
| @ -128,7 +135,11 @@ export async function getEventForSelectWithPoint({ | ||||
|       type: 'Set selection', | ||||
|       data: { | ||||
|         selectionType: 'singleCodeCursor', | ||||
|         selection: { range: codeRef.range, type: 'extrude-wall' }, | ||||
|         selection: { | ||||
|           artifactId: data.entity_id, | ||||
|           range: codeRef.range, | ||||
|           type: 'extrude-wall', | ||||
|         }, | ||||
|       }, | ||||
|     } | ||||
|   } | ||||
| @ -137,7 +148,11 @@ export async function getEventForSelectWithPoint({ | ||||
|       type: 'Set selection', | ||||
|       data: { | ||||
|         selectionType: 'singleCodeCursor', | ||||
|         selection: { range: _artifact.codeRef.range, type: 'default' }, | ||||
|         selection: { | ||||
|           artifactId: data.entity_id, | ||||
|           range: _artifact.codeRef.range, | ||||
|           type: 'default', | ||||
|         }, | ||||
|       }, | ||||
|     } | ||||
|   } | ||||
| @ -642,9 +657,12 @@ export function updateSelections( | ||||
|       const nodeMeta = getNodeFromPath<Value>(ast, pathToNode) | ||||
|       if (err(nodeMeta)) return undefined | ||||
|       const node = nodeMeta.node | ||||
|       const prevCodeBasedSelection = | ||||
|         prevSelectionRanges.codeBasedSelections[Number(index)] | ||||
|       return { | ||||
|         artifactId: prevCodeBasedSelection?.artifactId, | ||||
|         range: [node.start, node.end], | ||||
|         type: prevSelectionRanges.codeBasedSelections[Number(index)]?.type, | ||||
|         type: prevCodeBasedSelection?.type, | ||||
|       } | ||||
|     }) | ||||
|     .filter((x?: Selection) => x !== undefined) as Selection[] | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	