get overlays working for circle three point

This commit is contained in:
Kurt Hutten Irev-Dev
2025-02-03 17:53:08 +11:00
parent 5a5138a703
commit 84d17454e9
9 changed files with 138 additions and 60 deletions

View File

@ -182,12 +182,15 @@ const Overlays = () => {
style={{ zIndex: '99999999' }} style={{ zIndex: '99999999' }}
> >
{Object.entries(context.segmentOverlays) {Object.entries(context.segmentOverlays)
.filter((a) => a[1].visible) .flatMap((a) =>
.map(([pathToNodeString, overlay], index) => { a[1].map((b) => ({ pathToNodeString: a[0], overlay: b }))
)
.filter((a) => a.overlay.visible)
.map(({ pathToNodeString, overlay }, index) => {
return ( return (
<Overlay <Overlay
overlay={overlay} overlay={overlay}
key={pathToNodeString} key={pathToNodeString + String(index)}
pathToNodeString={pathToNodeString} pathToNodeString={pathToNodeString}
overlayIndex={index} overlayIndex={index}
/> />
@ -229,7 +232,8 @@ const Overlay = ({
const constraints = getConstraintInfo( const constraints = getConstraintInfo(
callExpression, callExpression,
codeManager.code, codeManager.code,
overlay.pathToNode overlay.pathToNode,
overlay.filterValue
) )
const offset = 20 // px const offset = 20 // px
@ -249,7 +253,6 @@ const Overlay = ({
state.matches({ Sketch: 'Tangential arc to' }) || state.matches({ Sketch: 'Tangential arc to' }) ||
state.matches({ Sketch: 'Rectangle tool' }) state.matches({ Sketch: 'Rectangle tool' })
) )
return ( return (
<div className={`absolute w-0 h-0`}> <div className={`absolute w-0 h-0`}>
<div <div
@ -307,17 +310,18 @@ const Overlay = ({
this will likely change soon when we implement multi-profile so we'll leave it for now this will likely change soon when we implement multi-profile so we'll leave it for now
issue: https://github.com/KittyCAD/modeling-app/issues/3910 issue: https://github.com/KittyCAD/modeling-app/issues/3910
*/} */}
{callExpression?.callee?.name !== 'circle' && ( {callExpression?.callee?.name !== 'circle' &&
<SegmentMenu callExpression?.callee?.name !== 'circleThreePoint' && (
verticalPosition={ <SegmentMenu
overlay.windowCoords[1] > window.innerHeight / 2 verticalPosition={
? 'top' overlay.windowCoords[1] > window.innerHeight / 2
: 'bottom' ? 'top'
} : 'bottom'
pathToNode={overlay.pathToNode} }
stdLibFnName={constraints[0]?.stdLibFnName} pathToNode={overlay.pathToNode}
/> stdLibFnName={constraints[0]?.stdLibFnName}
)} />
)}
</div> </div>
)} )}
</div> </div>

View File

@ -71,7 +71,6 @@ import {
SegmentUtils, SegmentUtils,
segmentUtils, segmentUtils,
} from './segments' } from './segments'
import { CircleThreePoint } from './circleThreePoint'
import { import {
addCallExpressionsToPipe, addCallExpressionsToPipe,
addCloseToPipe, addCloseToPipe,

View File

@ -182,13 +182,15 @@ export class SceneInfra {
callbacks: (() => SegmentOverlayPayload | null)[] = [] callbacks: (() => SegmentOverlayPayload | null)[] = []
_overlayCallbacks(callbacks: (() => SegmentOverlayPayload | null)[]) { _overlayCallbacks(callbacks: (() => SegmentOverlayPayload | null)[]) {
const segmentOverlayPayload: SegmentOverlayPayload = { const segmentOverlayPayload: SegmentOverlayPayload = {
type: 'set-many', type: 'add-many',
overlays: {}, overlays: {},
} }
callbacks.forEach((cb) => { callbacks.forEach((cb) => {
const overlay = cb() const overlay = cb()
if (overlay?.type === 'set-one') { if (overlay?.type === 'set-one') {
segmentOverlayPayload.overlays[overlay.pathToNodeString] = overlay.seg segmentOverlayPayload.overlays[overlay.pathToNodeString] = overlay.seg
} else if (overlay?.type === 'add-many') {
Object.assign(segmentOverlayPayload.overlays, overlay.overlays)
} }
}) })
this.modelingSend({ this.modelingSend({
@ -213,25 +215,27 @@ export class SceneInfra {
overlayThrottleMap: { [pathToNodeString: string]: number } = {} overlayThrottleMap: { [pathToNodeString: string]: number } = {}
updateOverlayDetails({ updateOverlayDetails({
arrowGroup, handle,
group, group,
isHandlesVisible, isHandlesVisible,
from, from,
to, to,
angle, angle,
hasThreeDotMenu,
}: { }: {
arrowGroup: Group handle: Group
group: Group group: Group
isHandlesVisible: boolean isHandlesVisible: boolean
from: Coords2d from: Coords2d
to: Coords2d to: Coords2d
hasThreeDotMenu: boolean
angle?: number angle?: number
}): SegmentOverlayPayload | null { }): SegmentOverlayPayload | null {
if (!group.userData.draft && group.userData.pathToNode && arrowGroup) { if (!group.userData.draft && group.userData.pathToNode && handle) {
const vector = new Vector3(0, 0, 0) const vector = new Vector3(0, 0, 0)
// Get the position of the object3D in world space // Get the position of the object3D in world space
arrowGroup.getWorldPosition(vector) handle.getWorldPosition(vector)
// Project that position to screen space // Project that position to screen space
vector.project(this.camControls.camera) vector.project(this.camControls.camera)
@ -244,13 +248,16 @@ export class SceneInfra {
return { return {
type: 'set-one', type: 'set-one',
pathToNodeString, pathToNodeString,
seg: { seg: [
windowCoords: [x, y], {
angle: _angle, windowCoords: [x, y],
group, angle: _angle,
pathToNode: group.userData.pathToNode, group,
visible: isHandlesVisible, pathToNode: group.userData.pathToNode,
}, visible: isHandlesVisible,
hasThreeDotMenu,
},
],
} }
} }
return null return null

View File

@ -64,7 +64,11 @@ import {
} from './sceneInfra' } from './sceneInfra'
import { Themes, getThemeColorForThreeJs } from 'lib/theme' import { Themes, getThemeColorForThreeJs } from 'lib/theme'
import { normaliseAngle, roundOff } from 'lib/utils' import { normaliseAngle, roundOff } from 'lib/utils'
import { SegmentOverlayPayload } from 'machines/modelingMachine' import {
SegmentOverlay,
SegmentOverlayPayload,
SegmentOverlays,
} from 'machines/modelingMachine'
import { SegmentInputs } from 'lang/std/stdTypes' import { SegmentInputs } from 'lang/std/stdTypes'
import { err } from 'lib/trap' import { err } from 'lib/trap'
import { editorManager, sceneInfra } from 'lib/singletons' import { editorManager, sceneInfra } from 'lib/singletons'
@ -315,11 +319,12 @@ class StraightSegment implements SegmentUtils {
} }
return () => return () =>
sceneInfra.updateOverlayDetails({ sceneInfra.updateOverlayDetails({
arrowGroup, handle: arrowGroup,
group, group,
isHandlesVisible, isHandlesVisible,
from, from,
to, to,
hasThreeDotMenu: true,
}) })
} }
} }
@ -491,12 +496,13 @@ class TangentialArcToSegment implements SegmentUtils {
) )
return () => return () =>
sceneInfra.updateOverlayDetails({ sceneInfra.updateOverlayDetails({
arrowGroup, handle: arrowGroup,
group, group,
isHandlesVisible, isHandlesVisible,
from, from,
to, to,
angle, angle,
hasThreeDotMenu: true,
}) })
} }
} }
@ -692,12 +698,13 @@ class CircleSegment implements SegmentUtils {
} }
return () => return () =>
sceneInfra.updateOverlayDetails({ sceneInfra.updateOverlayDetails({
arrowGroup, handle: arrowGroup,
group, group,
isHandlesVisible, isHandlesVisible,
from: from, from: from,
to: [center[0], center[1]], to: [center[0], center[1]],
angle: Math.PI / 4, angle: Math.PI / 4,
hasThreeDotMenu: true,
}) })
} }
} }
@ -826,7 +833,6 @@ class CircleThreePointSegment implements SegmentUtils {
].map((handle) => group.getObjectByName(handle) as Group) ].map((handle) => group.getObjectByName(handle) as Group)
handles.forEach((handle, i) => { handles.forEach((handle, i) => {
const point = points[i] const point = points[i]
console.log('point', point, handle)
if (handle && point) { if (handle && point) {
handle.position.set(point[0], point[1], 0) handle.position.set(point[0], point[1], 0)
handle.scale.set(scale, scale, scale) handle.scale.set(scale, scale, scale)
@ -878,15 +884,45 @@ class CircleThreePointSegment implements SegmentUtils {
scale, scale,
}) })
} }
return () => return () => {
sceneInfra.updateOverlayDetails({ const overlays: SegmentOverlays = {}
arrowGroup: {} as any, const points = [p1, p2, p3]
group, const overlayDetails = handles.map((handle, index) => {
isHandlesVisible, const currentPoint = points[index]
from: [0, 0], const angle = Math.atan2(
to: [center[0], center[1]], currentPoint[1] - center[1],
angle: Math.PI / 4, currentPoint[0] - center[0]
)
return sceneInfra.updateOverlayDetails({
handle,
group,
isHandlesVisible,
from: [0, 0],
to: [center[0], center[1]],
angle: angle,
hasThreeDotMenu: index === 0,
})
}) })
const segmentOverlays: SegmentOverlay[] = []
overlayDetails.forEach((payload, index) => {
if (payload?.type === 'set-one') {
overlays[payload.pathToNodeString] = payload.seg
segmentOverlays.push({
...payload.seg[0],
filterValue: index === 0 ? 'p1' : index === 1 ? 'p2' : 'p3',
})
}
})
const segmentOverlayPayload: SegmentOverlayPayload = {
type: 'set-one',
pathToNodeString:
overlayDetails[0]?.type === 'set-one'
? overlayDetails[0].pathToNodeString
: '',
seg: segmentOverlays,
}
return segmentOverlayPayload
}
} }
} }

View File

@ -281,7 +281,11 @@ export const ModelingMachineProvider = ({
'Set Segment Overlays': assign({ 'Set Segment Overlays': assign({
segmentOverlays: ({ context: { segmentOverlays }, event }) => { segmentOverlays: ({ context: { segmentOverlays }, event }) => {
if (event.type !== 'Set Segment Overlays') return {} if (event.type !== 'Set Segment Overlays') return {}
if (event.data.type === 'set-many') return event.data.overlays if (event.data.type === 'add-many')
return {
...segmentOverlays,
...event.data.overlays,
}
if (event.data.type === 'set-one') if (event.data.type === 'set-one')
return { return {
...segmentOverlays, ...segmentOverlays,

View File

@ -27,6 +27,7 @@ export type ToolTip =
| 'angledLineThatIntersects' | 'angledLineThatIntersects'
| 'tangentialArcTo' | 'tangentialArcTo'
| 'circle' | 'circle'
| 'circleThreePoint'
export const toolTips: Array<ToolTip> = [ export const toolTips: Array<ToolTip> = [
'line', 'line',

View File

@ -161,7 +161,8 @@ const commonConstraintInfoHelper = (
} }
], ],
code: string, code: string,
pathToNode: PathToNode pathToNode: PathToNode,
filterValue?: string
) => { ) => {
if (callExp.type !== 'CallExpression') return [] if (callExp.type !== 'CallExpression') return []
const firstArg = callExp.arguments?.[0] const firstArg = callExp.arguments?.[0]
@ -251,7 +252,8 @@ const horzVertConstraintInfoHelper = (
stdLibFnName: ConstrainInfo['stdLibFnName'], stdLibFnName: ConstrainInfo['stdLibFnName'],
abbreviatedInput: AbbreviatedInput, abbreviatedInput: AbbreviatedInput,
code: string, code: string,
pathToNode: PathToNode pathToNode: PathToNode,
filterValue?: string
) => { ) => {
if (callExp.type !== 'CallExpression') return [] if (callExp.type !== 'CallExpression') return []
const firstArg = callExp.arguments?.[0] const firstArg = callExp.arguments?.[0]
@ -1240,7 +1242,12 @@ export const circleThreePoint: SketchLineHelper = {
}, },
getTag: getTag(), getTag: getTag(),
addTag: addTag(), addTag: addTag(),
getConstraintInfo: (callExp: CallExpression, code, pathToNode) => { getConstraintInfo: (
callExp: CallExpression,
code,
pathToNode,
filterValue
) => {
if (callExp.type !== 'CallExpression') return [] if (callExp.type !== 'CallExpression') return []
const firstArg = callExp.arguments?.[0] const firstArg = callExp.arguments?.[0]
if (firstArg.type !== 'ObjectExpression') return [] if (firstArg.type !== 'ObjectExpression') return []
@ -1290,9 +1297,9 @@ export const circleThreePoint: SketchLineHelper = {
const pathToP3XArg: PathToNode = [...pathToP3ArrayExpression, [0, 'index']] const pathToP3XArg: PathToNode = [...pathToP3ArrayExpression, [0, 'index']]
const pathToP3YArg: PathToNode = [...pathToP3ArrayExpression, [1, 'index']] const pathToP3YArg: PathToNode = [...pathToP3ArrayExpression, [1, 'index']]
return [ const constraints: (ConstrainInfo & { filterValue: string })[] = [
{ {
stdLibFnName: 'circle', stdLibFnName: 'circleThreePoint',
type: 'xAbsolute', type: 'xAbsolute',
isConstrained: isNotLiteralArrayOrStatic(p1Details.expr.elements[0]), isConstrained: isNotLiteralArrayOrStatic(p1Details.expr.elements[0]),
sourceRange: [ sourceRange: [
@ -1310,9 +1317,10 @@ export const circleThreePoint: SketchLineHelper = {
index: 0, index: 0,
key: 'p1', key: 'p1',
}, },
filterValue: 'p1',
}, },
{ {
stdLibFnName: 'circle', stdLibFnName: 'circleThreePoint',
type: 'yAbsolute', type: 'yAbsolute',
isConstrained: isNotLiteralArrayOrStatic(p1Details.expr.elements[1]), isConstrained: isNotLiteralArrayOrStatic(p1Details.expr.elements[1]),
sourceRange: [ sourceRange: [
@ -1330,9 +1338,10 @@ export const circleThreePoint: SketchLineHelper = {
index: 1, index: 1,
key: 'p1', key: 'p1',
}, },
filterValue: 'p1',
}, },
{ {
stdLibFnName: 'circle', stdLibFnName: 'circleThreePoint',
type: 'xAbsolute', type: 'xAbsolute',
isConstrained: isNotLiteralArrayOrStatic(p2Details.expr.elements[0]), isConstrained: isNotLiteralArrayOrStatic(p2Details.expr.elements[0]),
sourceRange: [ sourceRange: [
@ -1350,9 +1359,10 @@ export const circleThreePoint: SketchLineHelper = {
index: 0, index: 0,
key: 'p2', key: 'p2',
}, },
filterValue: 'p2',
}, },
{ {
stdLibFnName: 'circle', stdLibFnName: 'circleThreePoint',
type: 'yAbsolute', type: 'yAbsolute',
isConstrained: isNotLiteralArrayOrStatic(p2Details.expr.elements[1]), isConstrained: isNotLiteralArrayOrStatic(p2Details.expr.elements[1]),
sourceRange: [ sourceRange: [
@ -1370,9 +1380,10 @@ export const circleThreePoint: SketchLineHelper = {
index: 1, index: 1,
key: 'p2', key: 'p2',
}, },
filterValue: 'p2',
}, },
{ {
stdLibFnName: 'circle', stdLibFnName: 'circleThreePoint',
type: 'xAbsolute', type: 'xAbsolute',
isConstrained: isNotLiteralArrayOrStatic(p3Details.expr.elements[0]), isConstrained: isNotLiteralArrayOrStatic(p3Details.expr.elements[0]),
sourceRange: [ sourceRange: [
@ -1390,9 +1401,10 @@ export const circleThreePoint: SketchLineHelper = {
index: 0, index: 0,
key: 'p3', key: 'p3',
}, },
filterValue: 'p3',
}, },
{ {
stdLibFnName: 'circle', stdLibFnName: 'circleThreePoint',
type: 'yAbsolute', type: 'yAbsolute',
isConstrained: isNotLiteralArrayOrStatic(p3Details.expr.elements[1]), isConstrained: isNotLiteralArrayOrStatic(p3Details.expr.elements[1]),
sourceRange: [ sourceRange: [
@ -1410,8 +1422,19 @@ export const circleThreePoint: SketchLineHelper = {
index: 1, index: 1,
key: 'p3', key: 'p3',
}, },
filterValue: 'p3',
}, },
] ]
const finalConstraints: ConstrainInfo[] = []
constraints.forEach((constraint) => {
if (!filterValue) {
finalConstraints.push(constraint)
}
if (filterValue && constraint.filterValue === filterValue) {
finalConstraints.push(constraint)
}
})
return finalConstraints
}, },
} }
export const angledLine: SketchLineHelper = { export const angledLine: SketchLineHelper = {
@ -2229,14 +2252,16 @@ export function changeSketchArguments(
export function getConstraintInfo( export function getConstraintInfo(
callExpression: Node<CallExpression>, callExpression: Node<CallExpression>,
code: string, code: string,
pathToNode: PathToNode pathToNode: PathToNode,
filterValue?: string
): ConstrainInfo[] { ): ConstrainInfo[] {
const fnName = callExpression?.callee?.name || '' const fnName = callExpression?.callee?.name || ''
if (!(fnName in sketchLineHelperMap)) return [] if (!(fnName in sketchLineHelperMap)) return []
return sketchLineHelperMap[fnName].getConstraintInfo( return sketchLineHelperMap[fnName].getConstraintInfo(
callExpression, callExpression,
code, code,
pathToNode pathToNode,
filterValue
) )
} }

View File

@ -250,6 +250,7 @@ export interface SketchLineHelper {
getConstraintInfo: ( getConstraintInfo: (
callExp: Node<CallExpression>, callExp: Node<CallExpression>,
code: string, code: string,
pathToNode: PathToNode pathToNode: PathToNode,
filterValue?: string
) => ConstrainInfo[] ) => ConstrainInfo[]
} }

View File

@ -85,7 +85,6 @@ import { MachineManager } from 'components/MachineManagerProvider'
import { addShell } from 'lang/modifyAst/addShell' import { addShell } from 'lang/modifyAst/addShell'
import { KclCommandValue } from 'lib/commandTypes' import { KclCommandValue } from 'lib/commandTypes'
import { getPathsFromPlaneArtifact } from 'lang/std/artifactGraph' import { getPathsFromPlaneArtifact } from 'lang/std/artifactGraph'
import { CircleThreePoint } from '../clientSideScene/circleThreePoint'
export const MODELING_PERSIST_KEY = 'MODELING_PERSIST_KEY' export const MODELING_PERSIST_KEY = 'MODELING_PERSIST_KEY'
@ -153,10 +152,12 @@ export interface SegmentOverlay {
group: any group: any
pathToNode: PathToNode pathToNode: PathToNode
visible: boolean visible: boolean
hasThreeDotMenu: boolean
filterValue?: string
} }
export interface SegmentOverlays { export interface SegmentOverlays {
[pathToNodeString: string]: SegmentOverlay [pathToNodeString: string]: SegmentOverlay[]
} }
export interface EdgeCutInfo { export interface EdgeCutInfo {
@ -207,7 +208,7 @@ export type SegmentOverlayPayload =
| { | {
type: 'set-one' type: 'set-one'
pathToNodeString: string pathToNodeString: string
seg: SegmentOverlay seg: SegmentOverlay[]
} }
| { | {
type: 'delete-one' type: 'delete-one'
@ -215,7 +216,7 @@ export type SegmentOverlayPayload =
} }
| { type: 'clear' } | { type: 'clear' }
| { | {
type: 'set-many' type: 'add-many'
overlays: SegmentOverlays overlays: SegmentOverlays
} }