Files
modeling-app/src/components/Toolbar/Intersect.tsx
Kurt Hutten 834f7133d8 Allow multiple profiles in the same sketch (#5196)
* Revert "Revert multi-profile (#4812)"

This reverts commit efe8089b08.

* fix poor 1000ms wait UX

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest-8-cores)

* trigger CI

* Add Rust side artifacts for startSketchOn face or plane (#4834)

* Add Rust side artifacts for startSketchOn face or plane

* move ast digging

---------

Co-authored-by: Kurt Hutten Irev-Dev <k.hutten@protonmail.ch>

* lint

* lint

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-macos-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-16-cores)

* trigger CI

* chore: disabled file watcher which prevents faster file write (#4835)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* partial fixes

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* Trigger CI

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* Trigger CI

* Fix up all the tests

* Fix partial execution

* wip

* WIP

* wip

* rust changes to make three point confrom to same as others since we're not ready with name params yet

* most of the fix for 3 point circle

* get overlays working for circle three point

* fmt

* fix types

* cargo fmt

* add face codef ref for walls and caps

* fix sketch on face after updates to rust side artifact graph

* some things needed for multi-profile tests

* bad attempts at fixing rust

* more

* more

* fix rust

* more rust fixes

* overlay fix

* remove duplicate test

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* lint and typing

* maybe fix a unit test

* small thing

* fix circ dep

* fix unit test

* fix some tests

* fix sweep point-and-click test

* fix more tests and add a fix me

* fix more tests

* fix electron specific test

* tsc

* more test tweaks

* update docs

* commint snaps?

* is clippy happy now?

* clippy again

* test works now without me changing anything big-fixed-itself

* small bug

* make three point have cross hair to make it consistent with othe rtools

* fix up state diagram

* fmt

* add draft point for first click of three point circ

* 1 test for three point circle

* 2 test for three point circle

* clean up

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* remove bad doc comment

* remove test skip

* remove onboarding test changes

* Update src/lang/modifyAst.ts

Co-authored-by: Jonathan Tran <jonnytran@gmail.com>

* Update output from simulation tests

* Fix to use correct source ranges

This also reduces cloning.

* Change back to skipping face cap none and both

* Update output after changing back to skipping none and both

* Fix clippy warning

* fix profile start snap bug

* add path ids to cap

* fix going into edit sketch

* make other startSketchOn's work

* fix snapshot test

* explain function name

* Update src/lib/rectangleTool.ts

Co-authored-by: Frank Noirot <frank@zoo.dev>

* rename error

* remove file tree from diff

* Update src/clientSideScene/segments.ts

Co-authored-by: Frank Noirot <frank@zoo.dev>

* nit

* Prevent double write to KCL code on revolve

* Update output after adding cap-to-path graph edge

* Fix edit/select sketch-on-cap via feature tree

* clean up for face codeRef

* fix changing tools part way through circle/rect tools

* fix delete of circle profile

* fix close profiles

* fix closing profile bug (tangentArcTo being ignored)

* remove stale comment

* Delete paths associated with sketch when the sketch plane is deleted

* Add support for deleting sketches on caps (not walls)

* get delet working for walls

* make delet of extrusions work for multi profile

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* Delete the sketch statement too on the cap and wall cases

* Don't write to file in `split-sketch-pipe-if-needed` unless necessary

* Don't wait for file write to complete within `updateEditorWithAstAndWriteToFile`
It is already debounced internally. If we await it, we will have to wait for a debounced timeout

* docs

* fix circ dep

* tsc

* fix selection enter sketch weirdness

* test fixes

* comment out and fixme for delete related tests

* add skip wins

* try and get last test to pass

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
Co-authored-by: Kevin Nadro <nadr0@users.noreply.github.com>
Co-authored-by: Pierre Jacquier <pierre@zoo.dev>
Co-authored-by: 49lf <ircsurfer33@gmail.com>
Co-authored-by: Frank Noirot <frank@zoo.dev>
Co-authored-by: Frank Noirot <frankjohnson1993@gmail.com>
2025-02-14 08:57:04 -05:00

218 lines
6.3 KiB
TypeScript

import { toolTips } from 'lang/langHelpers'
import { Program, Expr, VariableDeclarator } from '../../lang/wasm'
import { Selections } from 'lib/selections'
import {
getNodeFromPath,
isLinesParallelAndConstrained,
} from '../../lang/queryAst'
import { isSketchVariablesLinked } from '../../lang/std/sketchConstraints'
import {
transformSecondarySketchLinesTagFirst,
getTransformInfos,
PathToNodeMap,
isExprBinaryPart,
} from '../../lang/std/sketchcombos'
import { TransformInfo } from 'lang/std/stdTypes'
import { GetInfoModal, createInfoModal } from '../SetHorVertDistanceModal'
import { createVariableDeclaration } from '../../lang/modifyAst'
import { removeDoubleNegatives } from '../AvailableVarsHelpers'
import { engineCommandManager, kclManager } from 'lib/singletons'
import { err } from 'lib/trap'
import { Node } from 'wasm-lib/kcl/bindings/Node'
const getModalInfo = createInfoModal(GetInfoModal)
export function intersectInfo({
selectionRanges,
}: {
selectionRanges: Selections
}):
| {
transforms: TransformInfo[]
enabled: boolean
forcedSelectionRanges: Selections
}
| Error {
if (selectionRanges.graphSelections.length < 2) {
return {
enabled: false,
transforms: [],
forcedSelectionRanges: { ...selectionRanges },
}
}
const previousSegment =
selectionRanges.graphSelections.length > 1 &&
isLinesParallelAndConstrained(
kclManager.ast,
engineCommandManager.artifactGraph,
kclManager.variables,
selectionRanges.graphSelections[0],
selectionRanges.graphSelections[1]
)
if (err(previousSegment)) return previousSegment
const artifact = selectionRanges.graphSelections[1]?.artifact
const shouldUsePreviousSegment =
(!artifact || artifact.type === 'segment') &&
previousSegment &&
previousSegment.isParallelAndConstrained
const _forcedSelectionRanges: typeof selectionRanges = {
...selectionRanges,
graphSelections: [
selectionRanges.graphSelections?.[0],
shouldUsePreviousSegment && previousSegment.selection
? previousSegment.selection
: selectionRanges.graphSelections?.[1],
],
}
const _nodes = _forcedSelectionRanges.graphSelections.map(({ codeRef }) => {
const tmp = getNodeFromPath<Expr>(kclManager.ast, codeRef.pathToNode)
if (err(tmp)) return tmp
return tmp.node
})
const _err1 = _nodes.find(err)
if (err(_err1)) return _err1
const nodes = _nodes as Expr[]
const _varDecs = _forcedSelectionRanges.graphSelections.map(({ codeRef }) => {
const tmp = getNodeFromPath<VariableDeclarator>(
kclManager.ast,
codeRef.pathToNode,
'VariableDeclarator'
)
if (err(tmp)) return tmp
return tmp.node
})
const _err2 = _varDecs.find(err)
if (err(_err2)) return _err2
const varDecs = _varDecs as VariableDeclarator[]
const primaryLine = varDecs[0]
const secondaryVarDecs = varDecs.slice(1)
const isOthersLinkedToPrimary = secondaryVarDecs.every((secondary) =>
isSketchVariablesLinked(secondary, primaryLine, kclManager.ast)
)
const isAllTooltips = nodes.every(
(node) =>
(node?.type === 'CallExpression' || node?.type === 'CallExpressionKw') &&
[
...toolTips,
'startSketchAt', // TODO probably a better place for this to live
].includes(node.callee.name as any)
)
const theTransforms = getTransformInfos(
{
...selectionRanges,
graphSelections: _forcedSelectionRanges.graphSelections.slice(1),
},
kclManager.ast,
'intersect'
)
const forcedArtifact = _forcedSelectionRanges?.graphSelections?.[1]?.artifact
const _enableEqual =
secondaryVarDecs.length === 1 &&
isAllTooltips &&
isOthersLinkedToPrimary &&
theTransforms.every(Boolean) &&
(!forcedArtifact || forcedArtifact.type === 'segment')
return {
enabled: _enableEqual,
transforms: theTransforms,
forcedSelectionRanges: _forcedSelectionRanges,
}
}
export async function applyConstraintIntersect({
selectionRanges,
}: {
selectionRanges: Selections
}): Promise<{
modifiedAst: Node<Program>
pathToNodeMap: PathToNodeMap
exprInsertIndex: number
}> {
const info = intersectInfo({
selectionRanges,
})
if (err(info)) return Promise.reject(info)
const { transforms, forcedSelectionRanges } = info
const transform1 = transformSecondarySketchLinesTagFirst({
ast: structuredClone(kclManager.ast),
selectionRanges: forcedSelectionRanges,
transformInfos: transforms,
memVars: kclManager.variables,
})
if (err(transform1)) return Promise.reject(transform1)
const { modifiedAst, tagInfo, valueUsedInTransform, pathToNodeMap } =
transform1
const {
segName,
value,
valueNode,
variableName,
newVariableInsertIndex,
sign,
} = await getModalInfo({
segName: tagInfo?.tag,
isSegNameEditable: !tagInfo?.isTagExisting,
value: valueUsedInTransform,
initialVariableName: 'offset',
})
if (
!variableName &&
segName === tagInfo?.tag &&
Number(value) === valueUsedInTransform
) {
return {
modifiedAst,
pathToNodeMap,
exprInsertIndex: -1,
}
}
// transform again but forcing certain values
if (!isExprBinaryPart(valueNode))
return Promise.reject('Invalid valueNode, is not a BinaryPart')
const finalValue = removeDoubleNegatives(valueNode, sign, variableName)
const transform2 = transformSecondarySketchLinesTagFirst({
ast: kclManager.ast,
selectionRanges: forcedSelectionRanges,
transformInfos: transforms,
memVars: kclManager.variables,
forceSegName: segName,
forceValueUsedInTransform: finalValue,
})
if (err(transform2)) return Promise.reject(transform2)
const { modifiedAst: _modifiedAst, pathToNodeMap: _pathToNodeMap } =
transform2
let exprInsertIndex = -1
if (variableName) {
const newBody = [..._modifiedAst.body]
newBody.splice(
newVariableInsertIndex,
0,
createVariableDeclaration(variableName, valueNode)
)
_modifiedAst.body = newBody
Object.values(_pathToNodeMap).forEach((pathToNode) => {
const index = pathToNode.findIndex((a) => a[0] === 'body') + 1
pathToNode[index][0] = Number(pathToNode[index][0]) + 1
})
exprInsertIndex = newVariableInsertIndex
}
return {
modifiedAst: _modifiedAst,
pathToNodeMap: _pathToNodeMap,
exprInsertIndex,
}
}