Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fillet UI #2718

Merged
merged 9 commits into from
Jul 15, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions src/Toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,15 @@ export function Toolbar({
}),
{ enabled: !disableAllButtons, scopes: ['modeling'] }
)
useHotkeys(
'f',
() =>
commandBarSend({
type: 'Find and select command',
data: { name: 'Fillet', ownerMachine: 'modeling' },
}),
{ enabled: !disableAllButtons, scopes: ['modeling'] }
)

function handleToolbarButtonsWheelEvent(ev: WheelEvent<HTMLSpanElement>) {
const span = toolbarButtonsRef.current
Expand Down Expand Up @@ -404,6 +413,38 @@ export function Toolbar({
</ActionButton>
</li>
)}
{state.matches('idle') && (
<li className="contents">
<ActionButton
className={buttonClassName}
Element="button"
onClick={() =>
commandBarSend({
type: 'Find and select command',
data: { name: 'Fillet', ownerMachine: 'modeling' },
})
}
disabled={!state.can('Fillet') || disableAllButtons}
title={
state.can('Fillet') ? 'fillet' : 'sketches need to be closed'
}
iconStart={{
icon: 'fillet', // todo: add fillet icon
iconClassName,
bgClassName,
}}
>
Fillet
<Tooltip
delay={1250}
position="bottom"
className="!px-2 !text-xs"
>
Shortcut: F
</Tooltip>
</ActionButton>
</li>
)}
</ul>
</menu>
)
Expand Down
23 changes: 22 additions & 1 deletion src/components/CommandBar/CommandBarSelectionInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,25 @@ import { modelingMachine } from 'machines/modelingMachine'
import { useCallback, useEffect, useRef, useState } from 'react'
import { StateFrom } from 'xstate'

const semanticEntityNames = {
face: ['extrude-wall', 'start-cap', 'end-cap'],
edge: ['edge', 'line', 'arc'],
point: ['point', 'line-end', 'line-mid'],
}

function getSemanticSelectionType(selectionType: string[]) {
const semanticSelectionType = new Set()
selectionType.forEach((type) => {
Object.entries(semanticEntityNames).forEach(([entity, entityTypes]) => {
if (entityTypes.includes(type)) {
semanticSelectionType.add(entity)
}
})
})

return Array.from(semanticSelectionType)
}

const selectionSelector = (snapshot: StateFrom<typeof modelingMachine>) =>
snapshot.context.selectionRanges

Expand Down Expand Up @@ -85,7 +104,9 @@ function CommandBarSelectionInput({
>
{canSubmitSelection
? getSelectionTypeDisplayText(selection) + ' selected'
: `Please select ${arg.multiple ? 'one or more faces' : 'one face'}`}
: `Please select ${
arg.multiple ? 'one or more ' : 'one '
}${getSemanticSelectionType(arg.selectionTypes).join(' or ')}`}
<input
id="selection"
name="selection"
Expand Down
16 changes: 16 additions & 0 deletions src/components/CustomIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,22 @@ const CustomIconMap = {
/>
</svg>
),
fillet: (
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M8 5H5V15H15V12C15 8.13401 11.866 5 8 5ZM5 4H4V5V15V16H5H15H16V15V12C16 7.58172 12.4183 4 8 4H5Z"
fill="currentColor"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M4.5 3.5H5.5H8.5C12.9183 3.5 16.5 7.08172 16.5 11.5V14.5V15.5H16V12C16 7.58172 12.4182 4 7.99996 4H4.5V3.5Z"
fill="currentColor"
/>
</svg>
),
file: (
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
Expand Down
71 changes: 69 additions & 2 deletions src/components/ModelingMachineProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { applyConstraintAngleLength } from './Toolbar/setAngleLength'
import {
Selections,
canExtrudeSelection,
canFilletSelection,
handleSelectionBatch,
isSelectionLastLine,
isRangeInbetweenCharacters,
Expand All @@ -54,11 +55,14 @@ import {
sketchOnExtrudedFace,
startSketchOnDefault,
} from 'lang/modifyAst'
import { Program, parse, recast } from 'lang/wasm'
import { Program, parse, recast, CallExpression } from 'lang/wasm'
import {
getNodeFromPath,
getNodePathFromSourceRange,
hasExtrudableGeometry,
hasSketchPipeBeenExtruded,
isSingleCursorInPipe,
traverse,
} from 'lang/queryAst'
import { TEST } from 'env'
import { exportFromEngine } from 'lib/exportFromEngine'
Expand All @@ -72,6 +76,7 @@ import { uuidv4 } from 'lib/utils'
import { err, trap } from 'lib/trap'
import { useCommandsContext } from 'hooks/useCommandsContext'
import { modelingMachineEvent } from 'editor/manager'
import { sketchLineHelperMap } from 'lang/std/sketch'

type MachineContext<T extends AnyStateMachine> = {
state: StateFrom<T>
Expand Down Expand Up @@ -444,6 +449,69 @@ export const ModelingMachineProvider = ({
if (selectionRanges.codeBasedSelections.length <= 0) return false
return true
},
'has valid fillet selection': ({ selectionRanges }) => {
// case 0: check if there is anything filletable in the scene
let extrudeExists = false
kclManager.ast.body.forEach((node) => {
traverse(node, {
enter(node) {
if (
node.type === 'CallExpression' &&
node.callee.name === 'extrude'
) {
extrudeExists = true
}
},
})
})
if (!extrudeExists) return false

// case 1: nothing selected, test whether the extrusion exists
if (selectionRanges) {
if (selectionRanges.codeBasedSelections.length === 0) {
return true
}
const range0 = selectionRanges.codeBasedSelections[0].range[0]
const codeLength = codeManager.code.length
if (range0 === codeLength) {
return true
}
}

// case 2: scketch segment selected, test wehter it is extruded
// TODO: add loft / sweep check
if (selectionRanges.codeBasedSelections.length > 0) {
const isExtruded = hasSketchPipeBeenExtruded(
selectionRanges.codeBasedSelections[0],
kclManager.ast
)
if (isExtruded) {
const pathToSelectedNode = getNodePathFromSourceRange(
kclManager.ast,
selectionRanges.codeBasedSelections[0].range
)
const segmentNode = getNodeFromPath<CallExpression>(
kclManager.ast,
pathToSelectedNode,
'CallExpression'
)
if (err(segmentNode)) return false
if (segmentNode.node.type === 'CallExpression') {
// check wethe segment is in sketchLineHelperMap
const segmentName = segmentNode.node.callee.name
if (segmentName in sketchLineHelperMap) {
return true
} else {
return false
}
}
} else {
return false
}
}

return canFilletSelection(selectionRanges)
},
'Selection is on face': ({ selectionRanges }, { data }) => {
if (data?.forceNewSketch) return false
if (!isSingleCursorInPipe(selectionRanges, kclManager.ast))
Expand Down Expand Up @@ -494,7 +562,6 @@ export const ModelingMachineProvider = ({
kclManager.ast,
data.sketchPathToNode,
data.extrudePathToNode,
kclManager.programMemory,
data.cap
)
if (trap(sketched)) return Promise.reject(sketched)
Expand Down
14 changes: 3 additions & 11 deletions src/lang/modifyAst.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,6 @@ describe('testing sketchOnExtrudedFace', () => {
const ast = parse(code)
if (err(ast)) throw ast

const programMemory = await enginelessExecutor(ast)
const segmentSnippet = `line([9.7, 9.19], %)`
const segmentRange: [number, number] = [
code.indexOf(segmentSnippet),
Expand All @@ -321,8 +320,7 @@ describe('testing sketchOnExtrudedFace', () => {
const extruded = sketchOnExtrudedFace(
ast,
segmentPathToNode,
extrudePathToNode,
programMemory
extrudePathToNode
)
if (err(extruded)) throw extruded
const { modifiedAst } = extruded
Expand All @@ -345,7 +343,6 @@ const sketch001 = startSketchOn(part001, seg01)`)
|> extrude(5 + 7, %)`
const ast = parse(code)
if (err(ast)) throw ast
const programMemory = await enginelessExecutor(ast)
const segmentSnippet = `close(%)`
const segmentRange: [number, number] = [
code.indexOf(segmentSnippet),
Expand All @@ -362,8 +359,7 @@ const sketch001 = startSketchOn(part001, seg01)`)
const extruded = sketchOnExtrudedFace(
ast,
segmentPathToNode,
extrudePathToNode,
programMemory
extrudePathToNode
)
if (err(extruded)) throw extruded
const { modifiedAst } = extruded
Expand All @@ -386,7 +382,6 @@ const sketch001 = startSketchOn(part001, seg01)`)
|> extrude(5 + 7, %)`
const ast = parse(code)
if (err(ast)) throw ast
const programMemory = await enginelessExecutor(ast)
const sketchSnippet = `startProfileAt([3.58, 2.06], %)`
const sketchRange: [number, number] = [
code.indexOf(sketchSnippet),
Expand All @@ -404,7 +399,6 @@ const sketch001 = startSketchOn(part001, seg01)`)
ast,
sketchPathToNode,
extrudePathToNode,
programMemory,
'end'
)
if (err(extruded)) throw extruded
Expand Down Expand Up @@ -436,7 +430,6 @@ const sketch001 = startSketchOn(part001, 'END')`)
const part001 = extrude(5 + 7, sketch001)`
const ast = parse(code)
if (err(ast)) throw ast
const programMemory = await enginelessExecutor(ast)
const segmentSnippet = `line([4.99, -0.46], %)`
const segmentRange: [number, number] = [
code.indexOf(segmentSnippet),
Expand All @@ -453,8 +446,7 @@ const sketch001 = startSketchOn(part001, 'END')`)
const updatedAst = sketchOnExtrudedFace(
ast,
segmentPathToNode,
extrudePathToNode,
programMemory
extrudePathToNode
)
if (err(updatedAst)) throw updatedAst
const newCode = recast(updatedAst.modifiedAst)
Expand Down
2 changes: 0 additions & 2 deletions src/lang/modifyAst.ts
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,6 @@ export function sketchOnExtrudedFace(
node: Program,
sketchPathToNode: PathToNode,
extrudePathToNode: PathToNode,
programMemory: ProgramMemory,
cap: 'none' | 'start' | 'end' = 'none'
): { modifiedAst: Program; pathToNode: PathToNode } | Error {
let _node = { ...node }
Expand Down Expand Up @@ -388,7 +387,6 @@ export function sketchOnExtrudedFace(
if (cap === 'none') {
const __tag = addTagForSketchOnFace(
{
previousProgramMemory: programMemory,
pathToNode: sketchPathToNode,
node: _node,
},
Expand Down
Loading