#7408 Can not pick sketch plane using the feature tree and related improvements (#7609)

* Add ability to pick default plane in feature tree in 'Sketch no face' mode

* add ability to select deoffset plane where starting a new sketch

* use selectDefaultSketchPlane

* refactor: remove some duplication

* warning cleanups

* feature tree items selectable depedngin on no face sketch mode

* lint

* fix small jump because of border:none when going into and back from 'No face sketch' mode

* grey out items other than offset planes in 'No face sketch' mode

* start sketching on plane in context menu

* sketch on offset plane with context menu

* add ability to right click on default plane and start sketch on it

* default planes in feature tree should be selectable because of right click context menu

* add right click Start sketch option for selected plane on the canvas

* selectDefaultSketchPlane returns error now

* circular deps

* move select functions to lib/selections.ts to avoid circular deps

* add test for clicking on feature tree after starting a new sketch

* graphite suggestion

* fix bug of not being able to create offset plane using another offset plane with command bar

* add ability to select default plane on feature when going through the Offset plane command bar flow
This commit is contained in:
Andrew Varga
2025-07-04 19:14:12 +02:00
committed by GitHub
parent 01230b0aa1
commit 5f7a75a327
7 changed files with 442 additions and 150 deletions

View File

@ -34,6 +34,7 @@ import {
kclManager,
rustContext,
sceneEntitiesManager,
sceneInfra,
} from '@src/lib/singletons'
import { err } from '@src/lib/trap'
import {
@ -803,3 +804,156 @@ export function getSemanticSelectionType(selectionType: Artifact['type'][]) {
return Array.from(semanticSelectionType)
}
export function selectDefaultSketchPlane(
defaultPlaneId: string
): Error | boolean {
const defaultPlanes = rustContext.defaultPlanes
if (!defaultPlanes) {
return new Error('No default planes defined in rustContext')
}
if (
![
defaultPlanes.xy,
defaultPlanes.xz,
defaultPlanes.yz,
defaultPlanes.negXy,
defaultPlanes.negXz,
defaultPlanes.negYz,
].includes(defaultPlaneId)
) {
// Supplied defaultPlaneId is not a valid default plane id
return false
}
const camVector = sceneInfra.camControls.camera.position
.clone()
.sub(sceneInfra.camControls.target)
// TODO can we get this information from rust land when it creates the default planes?
// maybe returned from make_default_planes (src/wasm-lib/src/wasm.rs)
let zAxis: [number, number, number] = [0, 0, 1]
let yAxis: [number, number, number] = [0, 1, 0]
if (defaultPlanes?.xy === defaultPlaneId) {
zAxis = [0, 0, 1]
yAxis = [0, 1, 0]
if (camVector.z < 0) {
zAxis = [0, 0, -1]
defaultPlaneId = defaultPlanes?.negXy || ''
}
} else if (defaultPlanes?.yz === defaultPlaneId) {
zAxis = [1, 0, 0]
yAxis = [0, 0, 1]
if (camVector.x < 0) {
zAxis = [-1, 0, 0]
defaultPlaneId = defaultPlanes?.negYz || ''
}
} else if (defaultPlanes?.xz === defaultPlaneId) {
zAxis = [0, 1, 0]
yAxis = [0, 0, 1]
defaultPlaneId = defaultPlanes?.negXz || ''
if (camVector.y < 0) {
zAxis = [0, -1, 0]
defaultPlaneId = defaultPlanes?.xz || ''
}
}
const defaultPlaneStrMap: Record<string, DefaultPlaneStr> = {
[defaultPlanes.xy]: 'XY',
[defaultPlanes.xz]: 'XZ',
[defaultPlanes.yz]: 'YZ',
[defaultPlanes.negXy]: '-XY',
[defaultPlanes.negXz]: '-XZ',
[defaultPlanes.negYz]: '-YZ',
}
sceneInfra.modelingSend({
type: 'Select sketch plane',
data: {
type: 'defaultPlane',
planeId: defaultPlaneId,
plane: defaultPlaneStrMap[defaultPlaneId],
zAxis,
yAxis,
},
})
return true
}
export async function selectOffsetSketchPlane(artifact: Artifact | undefined) {
return new Promise((resolve) => {
if (artifact?.type === 'plane') {
const planeId = artifact.id
void sceneEntitiesManager
.getFaceDetails(planeId)
.then((planeInfo) => {
// Apply camera-based orientation logic similar to default planes
let zAxis: [number, number, number] = [
planeInfo.z_axis.x,
planeInfo.z_axis.y,
planeInfo.z_axis.z,
]
let yAxis: [number, number, number] = [
planeInfo.y_axis.x,
planeInfo.y_axis.y,
planeInfo.y_axis.z,
]
// Get camera vector to determine which side of the plane we're viewing from
const camVector = sceneInfra.camControls.camera.position
.clone()
.sub(sceneInfra.camControls.target)
// Determine the canonical (absolute) plane orientation
const absZAxis: [number, number, number] = [
Math.abs(zAxis[0]),
Math.abs(zAxis[1]),
Math.abs(zAxis[2]),
]
// Find the dominant axis (like default planes do)
const maxComponent = Math.max(...absZAxis)
const dominantAxisIndex = absZAxis.indexOf(maxComponent)
// Check camera position against canonical orientation (like default planes)
const cameraComponents = [camVector.x, camVector.y, camVector.z]
let negated = cameraComponents[dominantAxisIndex] < 0
if (dominantAxisIndex === 1) {
// offset of the XZ is being weird, not sure if this is a camera bug
negated = !negated
}
sceneInfra.modelingSend({
type: 'Select sketch plane',
data: {
type: 'offsetPlane',
zAxis,
yAxis,
position: [
planeInfo.origin.x,
planeInfo.origin.y,
planeInfo.origin.z,
].map((num) => num / sceneInfra._baseUnitMultiplier) as [
number,
number,
number,
],
planeId,
pathToNode: artifact.codeRef.pathToNode,
negated,
},
})
resolve(true)
})
.catch((error) => {
console.error('Error getting face details:', error)
resolve(false)
})
} else {
// selectOffsetSketchPlane called with an invalid artifact type',
resolve(false)
}
})
}