snap to profile start (#1616)
* fix camera set from debug panel * add snap to for closing sketch * clean up file that shouldn't have been committed
This commit is contained in:
@ -1127,3 +1127,86 @@ test('Can edit segments by dragging their handles', async ({
|
|||||||
|> line([14.69, 2.73], %)
|
|> line([14.69, 2.73], %)
|
||||||
|> tangentialArcTo([27.6, -3.25], %)`)
|
|> tangentialArcTo([27.6, -3.25], %)`)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('Snap to close works (at any scale)', async ({ page }) => {
|
||||||
|
const u = getUtils(page)
|
||||||
|
await page.setViewportSize({ width: 1200, height: 500 })
|
||||||
|
await page.goto('/')
|
||||||
|
await u.waitForAuthSkipAppStart()
|
||||||
|
await u.openDebugPanel()
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
page.getByRole('button', { name: 'Start Sketch' })
|
||||||
|
).not.toBeDisabled()
|
||||||
|
await expect(page.getByRole('button', { name: 'Start Sketch' })).toBeVisible()
|
||||||
|
|
||||||
|
const doSnapAtDifferentScales = async (
|
||||||
|
camPos: [number, number, number],
|
||||||
|
expectedCode: string
|
||||||
|
) => {
|
||||||
|
await u.clearCommandLogs()
|
||||||
|
await page.getByRole('button', { name: 'Start Sketch' }).click()
|
||||||
|
await page.waitForTimeout(100)
|
||||||
|
|
||||||
|
await u.openAndClearDebugPanel()
|
||||||
|
await u.updateCamPosition(camPos)
|
||||||
|
await u.closeDebugPanel()
|
||||||
|
|
||||||
|
// select a plane
|
||||||
|
await page.mouse.click(700, 200)
|
||||||
|
await expect(page.locator('.cm-content')).toHaveText(
|
||||||
|
`const part001 = startSketchOn('XZ')`
|
||||||
|
)
|
||||||
|
|
||||||
|
let prevContent = await page.locator('.cm-content').innerText()
|
||||||
|
|
||||||
|
const pointA = [700, 200]
|
||||||
|
const pointB = [900, 200]
|
||||||
|
const pointC = [900, 400]
|
||||||
|
|
||||||
|
// draw three lines
|
||||||
|
await page.mouse.click(pointA[0], pointA[1])
|
||||||
|
await page.waitForTimeout(100)
|
||||||
|
await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
|
||||||
|
prevContent = await page.locator('.cm-content').innerText()
|
||||||
|
|
||||||
|
await page.mouse.click(pointB[0], pointB[1])
|
||||||
|
await page.waitForTimeout(100)
|
||||||
|
await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
|
||||||
|
prevContent = await page.locator('.cm-content').innerText()
|
||||||
|
|
||||||
|
await page.mouse.click(pointC[0], pointC[1])
|
||||||
|
await page.waitForTimeout(100)
|
||||||
|
await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
|
||||||
|
prevContent = await page.locator('.cm-content').innerText()
|
||||||
|
|
||||||
|
await page.mouse.move(pointA[0] - 12, pointA[1] + 12)
|
||||||
|
const pointNotQuiteA = [pointA[0] - 7, pointA[1] + 7]
|
||||||
|
await page.mouse.move(pointNotQuiteA[0], pointNotQuiteA[1], { steps: 10 })
|
||||||
|
|
||||||
|
await page.mouse.click(pointNotQuiteA[0], pointNotQuiteA[1])
|
||||||
|
await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
|
||||||
|
prevContent = await page.locator('.cm-content').innerText()
|
||||||
|
|
||||||
|
await expect(page.locator('.cm-content')).toHaveText(expectedCode)
|
||||||
|
|
||||||
|
// exit sketch
|
||||||
|
await u.openAndClearDebugPanel()
|
||||||
|
await page.getByRole('button', { name: 'Exit Sketch' }).click()
|
||||||
|
await u.expectCmdLog('[data-message-type="execution-done"]')
|
||||||
|
await u.removeCurrentCode()
|
||||||
|
}
|
||||||
|
|
||||||
|
const codeTemplate = (
|
||||||
|
scale = 1,
|
||||||
|
fudge = 0
|
||||||
|
) => `const part001 = startSketchOn('XZ')
|
||||||
|
|> startProfileAt([${roundOff(scale * 87.68)}, ${roundOff(scale * 43.84)}], %)
|
||||||
|
|> line([${roundOff(scale * 175.36)}, 0], %)
|
||||||
|
|> line([0, -${roundOff(scale * 175.37) + fudge}], %)
|
||||||
|
|> close(%)`
|
||||||
|
|
||||||
|
await doSnapAtDifferentScales([0, 100, 100], codeTemplate(0.01, 0.01))
|
||||||
|
|
||||||
|
await doSnapAtDifferentScales([0, 10000, 10000], codeTemplate())
|
||||||
|
})
|
||||||
|
@ -31,12 +31,6 @@ test.beforeEach(async ({ context, page }) => {
|
|||||||
|
|
||||||
test.setTimeout(60000)
|
test.setTimeout(60000)
|
||||||
|
|
||||||
const commonPoints = {
|
|
||||||
startAt: '[26.38, -35.59]',
|
|
||||||
num1: 26.63,
|
|
||||||
num2: 53.01,
|
|
||||||
}
|
|
||||||
|
|
||||||
test('change camera, show planes', async ({ page, context }) => {
|
test('change camera, show planes', async ({ page, context }) => {
|
||||||
const u = getUtils(page)
|
const u = getUtils(page)
|
||||||
await page.setViewportSize({ width: 1200, height: 500 })
|
await page.setViewportSize({ width: 1200, height: 500 })
|
||||||
@ -46,21 +40,21 @@ test('change camera, show planes', async ({ page, context }) => {
|
|||||||
|
|
||||||
const camPos: [number, number, number] = [0, 85, 85]
|
const camPos: [number, number, number] = [0, 85, 85]
|
||||||
await u.updateCamPosition(camPos)
|
await u.updateCamPosition(camPos)
|
||||||
|
await page.waitForTimeout(200)
|
||||||
|
|
||||||
// rotate
|
// rotate
|
||||||
await u.closeDebugPanel()
|
await u.closeDebugPanel()
|
||||||
await page.mouse.move(700, 200)
|
await page.mouse.move(700, 200)
|
||||||
await page.mouse.down({ button: 'right' })
|
await page.mouse.down({ button: 'right' })
|
||||||
await page.mouse.move(600, 300)
|
await page.mouse.move(600, 300, { steps: 10 })
|
||||||
await page.mouse.up({ button: 'right' })
|
await page.mouse.up({ button: 'right' })
|
||||||
|
|
||||||
await u.openDebugPanel()
|
await u.openAndClearDebugPanel()
|
||||||
await page.waitForTimeout(500)
|
|
||||||
await u.clearCommandLogs()
|
|
||||||
|
|
||||||
await page.getByRole('button', { name: 'Start Sketch' }).click()
|
await page.getByRole('button', { name: 'Start Sketch' }).click()
|
||||||
|
|
||||||
await u.closeDebugPanel()
|
await u.closeDebugPanel()
|
||||||
|
await page.waitForTimeout(200)
|
||||||
|
|
||||||
await expect(page).toHaveScreenshot({
|
await expect(page).toHaveScreenshot({
|
||||||
maxDiffPixels: 100,
|
maxDiffPixels: 100,
|
||||||
@ -70,6 +64,7 @@ test('change camera, show planes', async ({ page, context }) => {
|
|||||||
await page.getByRole('button', { name: 'Exit Sketch' }).click()
|
await page.getByRole('button', { name: 'Exit Sketch' }).click()
|
||||||
|
|
||||||
await u.updateCamPosition(camPos)
|
await u.updateCamPosition(camPos)
|
||||||
|
await page.waitForTimeout(200)
|
||||||
|
|
||||||
await u.clearCommandLogs()
|
await u.clearCommandLogs()
|
||||||
await u.closeDebugPanel()
|
await u.closeDebugPanel()
|
||||||
@ -77,7 +72,7 @@ test('change camera, show planes', async ({ page, context }) => {
|
|||||||
await page.keyboard.down('Shift')
|
await page.keyboard.down('Shift')
|
||||||
await page.mouse.move(600, 200)
|
await page.mouse.move(600, 200)
|
||||||
await page.mouse.down({ button: 'right' })
|
await page.mouse.down({ button: 'right' })
|
||||||
await page.mouse.move(700, 200)
|
await page.mouse.move(700, 200, { steps: 10 })
|
||||||
await page.mouse.up({ button: 'right' })
|
await page.mouse.up({ button: 'right' })
|
||||||
await page.keyboard.up('Shift')
|
await page.keyboard.up('Shift')
|
||||||
|
|
||||||
@ -87,37 +82,13 @@ test('change camera, show planes', async ({ page, context }) => {
|
|||||||
|
|
||||||
await page.getByRole('button', { name: 'Start Sketch' }).click()
|
await page.getByRole('button', { name: 'Start Sketch' }).click()
|
||||||
await u.closeDebugPanel()
|
await u.closeDebugPanel()
|
||||||
|
await page.waitForTimeout(200)
|
||||||
|
|
||||||
await expect(page).toHaveScreenshot({
|
await expect(page).toHaveScreenshot({
|
||||||
maxDiffPixels: 100,
|
maxDiffPixels: 100,
|
||||||
})
|
})
|
||||||
|
|
||||||
await u.openAndClearDebugPanel()
|
// zoom was too unstable to keep as a PW test)
|
||||||
await page.getByRole('button', { name: 'Exit Sketch' }).click()
|
|
||||||
|
|
||||||
await u.updateCamPosition(camPos)
|
|
||||||
|
|
||||||
await u.clearCommandLogs()
|
|
||||||
await u.closeDebugPanel()
|
|
||||||
|
|
||||||
// zoom
|
|
||||||
await page.keyboard.down('Control')
|
|
||||||
await page.mouse.move(700, 400)
|
|
||||||
await page.mouse.down({ button: 'right' })
|
|
||||||
await page.mouse.move(700, 300)
|
|
||||||
await page.mouse.up({ button: 'right' })
|
|
||||||
await page.keyboard.up('Control')
|
|
||||||
|
|
||||||
await u.openDebugPanel()
|
|
||||||
await page.waitForTimeout(300)
|
|
||||||
await u.clearCommandLogs()
|
|
||||||
|
|
||||||
await page.getByRole('button', { name: 'Start Sketch' }).click()
|
|
||||||
await u.closeDebugPanel()
|
|
||||||
|
|
||||||
await expect(page).toHaveScreenshot({
|
|
||||||
maxDiffPixels: 100,
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test('exports of each format should work', async ({ page, context }) => {
|
test('exports of each format should work', async ({ page, context }) => {
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 110 KiB |
Binary file not shown.
Before Width: | Height: | Size: 126 KiB After Width: | Height: | Size: 78 KiB |
Binary file not shown.
Before Width: | Height: | Size: 115 KiB |
@ -209,6 +209,7 @@ export class CameraControls {
|
|||||||
this.camera.zoom = camProps.zoom || 1
|
this.camera.zoom = camProps.zoom || 1
|
||||||
}
|
}
|
||||||
this.camera.updateProjectionMatrix()
|
this.camera.updateProjectionMatrix()
|
||||||
|
console.log('doing this thing', camProps)
|
||||||
this.update(true)
|
this.update(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -569,7 +570,7 @@ export class CameraControls {
|
|||||||
update = (forceUpdate = false) => {
|
update = (forceUpdate = false) => {
|
||||||
// If there are any changes that need to be applied to the camera, apply them here.
|
// If there are any changes that need to be applied to the camera, apply them here.
|
||||||
|
|
||||||
let didChange = forceUpdate
|
let didChange = false
|
||||||
if (this.pendingRotation) {
|
if (this.pendingRotation) {
|
||||||
this.rotateCamera(this.pendingRotation.x, this.pendingRotation.y)
|
this.rotateCamera(this.pendingRotation.x, this.pendingRotation.y)
|
||||||
this.pendingRotation = null // Clear the pending rotation after applying it
|
this.pendingRotation = null // Clear the pending rotation after applying it
|
||||||
@ -621,8 +622,8 @@ export class CameraControls {
|
|||||||
|
|
||||||
// Update the camera's matrices
|
// Update the camera's matrices
|
||||||
this.camera.updateMatrixWorld()
|
this.camera.updateMatrixWorld()
|
||||||
if (didChange) {
|
if (didChange || forceUpdate) {
|
||||||
this.onCameraChange()
|
this.onCameraChange(forceUpdate)
|
||||||
}
|
}
|
||||||
|
|
||||||
// damping would be implemented here in update if we choose to add it.
|
// damping would be implemented here in update if we choose to add it.
|
||||||
@ -898,7 +899,7 @@ export class CameraControls {
|
|||||||
this.reactCameraPropertiesCallback(a)
|
this.reactCameraPropertiesCallback(a)
|
||||||
}, 200)
|
}, 200)
|
||||||
|
|
||||||
onCameraChange = () => {
|
onCameraChange = (forceUpdate = false) => {
|
||||||
const distance = this.target.distanceTo(this.camera.position)
|
const distance = this.target.distanceTo(this.camera.position)
|
||||||
if (this.camera.far / 2.1 < distance || this.camera.far / 1.9 > distance) {
|
if (this.camera.far / 2.1 < distance || this.camera.far / 1.9 > distance) {
|
||||||
this.camera.far = distance * 2
|
this.camera.far = distance * 2
|
||||||
@ -906,7 +907,7 @@ export class CameraControls {
|
|||||||
this.camera.updateProjectionMatrix()
|
this.camera.updateProjectionMatrix()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.syncDirection === 'clientToEngine')
|
if (this.syncDirection === 'clientToEngine' || forceUpdate)
|
||||||
throttledUpdateEngineCamera({
|
throttledUpdateEngineCamera({
|
||||||
quaternion: this.camera.quaternion,
|
quaternion: this.camera.quaternion,
|
||||||
position: this.camera.position,
|
position: this.camera.position,
|
||||||
|
@ -3,10 +3,13 @@ import {
|
|||||||
DoubleSide,
|
DoubleSide,
|
||||||
ExtrudeGeometry,
|
ExtrudeGeometry,
|
||||||
Group,
|
Group,
|
||||||
|
Intersection,
|
||||||
LineCurve3,
|
LineCurve3,
|
||||||
Matrix4,
|
Matrix4,
|
||||||
Mesh,
|
Mesh,
|
||||||
MeshBasicMaterial,
|
MeshBasicMaterial,
|
||||||
|
Object3D,
|
||||||
|
Object3DEventMap,
|
||||||
OrthographicCamera,
|
OrthographicCamera,
|
||||||
PerspectiveCamera,
|
PerspectiveCamera,
|
||||||
PlaneGeometry,
|
PlaneGeometry,
|
||||||
@ -24,6 +27,7 @@ import {
|
|||||||
defaultPlaneColor,
|
defaultPlaneColor,
|
||||||
getSceneScale,
|
getSceneScale,
|
||||||
INTERSECTION_PLANE_LAYER,
|
INTERSECTION_PLANE_LAYER,
|
||||||
|
OnMouseEnterLeaveArgs,
|
||||||
RAYCASTABLE_PLANE,
|
RAYCASTABLE_PLANE,
|
||||||
sceneInfra,
|
sceneInfra,
|
||||||
SKETCH_GROUP_SEGMENTS,
|
SKETCH_GROUP_SEGMENTS,
|
||||||
@ -64,7 +68,6 @@ import {
|
|||||||
addCloseToPipe,
|
addCloseToPipe,
|
||||||
addNewSketchLn,
|
addNewSketchLn,
|
||||||
changeSketchArguments,
|
changeSketchArguments,
|
||||||
compareVec2Epsilon2,
|
|
||||||
updateStartProfileAtArgs,
|
updateStartProfileAtArgs,
|
||||||
} from 'lang/std/sketch'
|
} from 'lang/std/sketch'
|
||||||
import { isReducedMotion, throttle } from 'lib/utils'
|
import { isReducedMotion, throttle } from 'lib/utils'
|
||||||
@ -300,8 +303,8 @@ class SceneEntities {
|
|||||||
: perspScale(sceneInfra.camControls.camera, dummy)) /
|
: perspScale(sceneInfra.camControls.camera, dummy)) /
|
||||||
sceneInfra._baseUnitMultiplier
|
sceneInfra._baseUnitMultiplier
|
||||||
|
|
||||||
let segPathToNode = getNodePathFromSourceRange(
|
const segPathToNode = getNodePathFromSourceRange(
|
||||||
draftSegment ? truncatedAst : kclManager.ast,
|
kclManager.ast,
|
||||||
sketchGroup.start.__geoMeta.sourceRange
|
sketchGroup.start.__geoMeta.sourceRange
|
||||||
)
|
)
|
||||||
const _profileStart = profileStart({
|
const _profileStart = profileStart({
|
||||||
@ -319,9 +322,23 @@ class SceneEntities {
|
|||||||
|
|
||||||
sketchGroup.value.forEach((segment, index) => {
|
sketchGroup.value.forEach((segment, index) => {
|
||||||
let segPathToNode = getNodePathFromSourceRange(
|
let segPathToNode = getNodePathFromSourceRange(
|
||||||
draftSegment ? truncatedAst : kclManager.ast,
|
kclManager.ast,
|
||||||
segment.__geoMeta.sourceRange
|
segment.__geoMeta.sourceRange
|
||||||
)
|
)
|
||||||
|
if (draftSegment && (sketchGroup.value[index - 1] || sketchGroup.start)) {
|
||||||
|
const previousSegment =
|
||||||
|
sketchGroup.value[index - 1] || sketchGroup.start
|
||||||
|
const previousSegmentPathToNode = getNodePathFromSourceRange(
|
||||||
|
kclManager.ast,
|
||||||
|
previousSegment.__geoMeta.sourceRange
|
||||||
|
)
|
||||||
|
const bodyIndex = previousSegmentPathToNode[1][0]
|
||||||
|
segPathToNode = getNodePathFromSourceRange(
|
||||||
|
truncatedAst,
|
||||||
|
segment.__geoMeta.sourceRange
|
||||||
|
)
|
||||||
|
segPathToNode[1][0] = bodyIndex
|
||||||
|
}
|
||||||
const isDraftSegment =
|
const isDraftSegment =
|
||||||
draftSegment && index === sketchGroup.value.length - 1
|
draftSegment && index === sketchGroup.value.length - 1
|
||||||
let seg
|
let seg
|
||||||
@ -364,11 +381,12 @@ class SceneEntities {
|
|||||||
this.scene.add(group)
|
this.scene.add(group)
|
||||||
if (!draftSegment) {
|
if (!draftSegment) {
|
||||||
sceneInfra.setCallbacks({
|
sceneInfra.setCallbacks({
|
||||||
onDrag: ({ selected, intersectionPoint, mouseEvent }) => {
|
onDrag: ({ selected, intersectionPoint, mouseEvent, intersects }) => {
|
||||||
if (mouseEvent.which !== 1) return
|
if (mouseEvent.which !== 1) return
|
||||||
this.onDragSegment({
|
this.onDragSegment({
|
||||||
object: selected,
|
object: selected,
|
||||||
intersection2d: intersectionPoint.twoD,
|
intersection2d: intersectionPoint.twoD,
|
||||||
|
intersects,
|
||||||
sketchPathToNode,
|
sketchPathToNode,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@ -389,81 +407,32 @@ class SceneEntities {
|
|||||||
if (!event) return
|
if (!event) return
|
||||||
sceneInfra.modelingSend(event)
|
sceneInfra.modelingSend(event)
|
||||||
},
|
},
|
||||||
onMouseEnter: ({ selected }) => {
|
...mouseEnterLeaveCallbacks(),
|
||||||
// TODO change the color of the segment to yellow?
|
|
||||||
// Give a few pixels grace around each of the segments
|
|
||||||
// for hover.
|
|
||||||
if ([X_AXIS, Y_AXIS].includes(selected?.userData?.type)) {
|
|
||||||
const obj = selected as Mesh
|
|
||||||
const mat = obj.material as MeshBasicMaterial
|
|
||||||
mat.color.set(obj.userData.baseColor)
|
|
||||||
mat.color.offsetHSL(0, 0, 0.5)
|
|
||||||
}
|
|
||||||
const parent = getParentGroup(selected, [
|
|
||||||
STRAIGHT_SEGMENT,
|
|
||||||
TANGENTIAL_ARC_TO_SEGMENT,
|
|
||||||
PROFILE_START,
|
|
||||||
])
|
|
||||||
if (parent?.userData?.pathToNode) {
|
|
||||||
const updatedAst = parse(recast(kclManager.ast))
|
|
||||||
const node = getNodeFromPath<CallExpression>(
|
|
||||||
updatedAst,
|
|
||||||
parent.userData.pathToNode,
|
|
||||||
'CallExpression'
|
|
||||||
).node
|
|
||||||
sceneInfra.highlightCallback([node.start, node.end])
|
|
||||||
const yellow = 0xffff00
|
|
||||||
colorSegment(selected, yellow)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
sceneInfra.highlightCallback([0, 0])
|
|
||||||
},
|
|
||||||
onMouseLeave: ({ selected }) => {
|
|
||||||
sceneInfra.highlightCallback([0, 0])
|
|
||||||
const parent = getParentGroup(selected, [
|
|
||||||
STRAIGHT_SEGMENT,
|
|
||||||
TANGENTIAL_ARC_TO_SEGMENT,
|
|
||||||
PROFILE_START,
|
|
||||||
])
|
|
||||||
const isSelected = parent?.userData?.isSelected
|
|
||||||
colorSegment(selected, isSelected ? 0x0000ff : 0xffffff)
|
|
||||||
if ([X_AXIS, Y_AXIS].includes(selected?.userData?.type)) {
|
|
||||||
const obj = selected as Mesh
|
|
||||||
const mat = obj.material as MeshBasicMaterial
|
|
||||||
mat.color.set(obj.userData.baseColor)
|
|
||||||
if (obj.userData.isSelected) mat.color.offsetHSL(0, 0, 0.2)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
sceneInfra.setCallbacks({
|
sceneInfra.setCallbacks({
|
||||||
onDrag: () => {},
|
|
||||||
onClick: async (args) => {
|
onClick: async (args) => {
|
||||||
if (!args) return
|
if (!args) return
|
||||||
if (args.mouseEvent.which !== 1) return
|
if (args.mouseEvent.which !== 1) return
|
||||||
const { intersectionPoint } = args
|
const { intersectionPoint } = args
|
||||||
if (!intersectionPoint?.twoD) return
|
let intersection2d = intersectionPoint?.twoD
|
||||||
|
const profileStart = args.intersects
|
||||||
|
.map(({ object }) => getParentGroup(object, [PROFILE_START]))
|
||||||
|
.find((a) => a?.name === PROFILE_START)
|
||||||
|
|
||||||
const firstSeg = sketchGroup.value[0]
|
|
||||||
const isClosingSketch = compareVec2Epsilon2(
|
|
||||||
firstSeg.from,
|
|
||||||
[intersectionPoint.twoD.x, intersectionPoint.twoD.y],
|
|
||||||
0.5
|
|
||||||
)
|
|
||||||
let modifiedAst
|
let modifiedAst
|
||||||
if (isClosingSketch) {
|
if (profileStart) {
|
||||||
// TODO close needs a better UX
|
|
||||||
modifiedAst = addCloseToPipe({
|
modifiedAst = addCloseToPipe({
|
||||||
node: kclManager.ast,
|
node: kclManager.ast,
|
||||||
programMemory: kclManager.programMemory,
|
programMemory: kclManager.programMemory,
|
||||||
pathToNode: sketchPathToNode,
|
pathToNode: sketchPathToNode,
|
||||||
})
|
})
|
||||||
} else {
|
} else if (intersection2d) {
|
||||||
const lastSegment = sketchGroup.value.slice(-1)[0]
|
const lastSegment = sketchGroup.value.slice(-1)[0]
|
||||||
modifiedAst = addNewSketchLn({
|
modifiedAst = addNewSketchLn({
|
||||||
node: kclManager.ast,
|
node: kclManager.ast,
|
||||||
programMemory: kclManager.programMemory,
|
programMemory: kclManager.programMemory,
|
||||||
to: [intersectionPoint.twoD.x, intersectionPoint.twoD.y],
|
to: [intersection2d.x, intersection2d.y],
|
||||||
from: [lastSegment.to[0], lastSegment.to[1]],
|
from: [lastSegment.to[0], lastSegment.to[1]],
|
||||||
fnName:
|
fnName:
|
||||||
lastSegment.type === 'TangentialArcTo'
|
lastSegment.type === 'TangentialArcTo'
|
||||||
@ -471,6 +440,9 @@ class SceneEntities {
|
|||||||
: 'line',
|
: 'line',
|
||||||
pathToNode: sketchPathToNode,
|
pathToNode: sketchPathToNode,
|
||||||
}).modifiedAst
|
}).modifiedAst
|
||||||
|
} else {
|
||||||
|
// return early as we didn't modify the ast
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
kclManager.executeAstMock(modifiedAst, { updates: 'code' })
|
kclManager.executeAstMock(modifiedAst, { updates: 'code' })
|
||||||
@ -481,6 +453,7 @@ class SceneEntities {
|
|||||||
this.onDragSegment({
|
this.onDragSegment({
|
||||||
intersection2d: args.intersectionPoint.twoD,
|
intersection2d: args.intersectionPoint.twoD,
|
||||||
object: Object.values(this.activeSegments).slice(-1)[0],
|
object: Object.values(this.activeSegments).slice(-1)[0],
|
||||||
|
intersects: args.intersects,
|
||||||
sketchPathToNode,
|
sketchPathToNode,
|
||||||
draftInfo: {
|
draftInfo: {
|
||||||
draftSegment,
|
draftSegment,
|
||||||
@ -490,6 +463,7 @@ class SceneEntities {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
...mouseEnterLeaveCallbacks(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
sceneInfra.camControls.enableRotate = false
|
sceneInfra.camControls.enableRotate = false
|
||||||
@ -526,13 +500,15 @@ class SceneEntities {
|
|||||||
)
|
)
|
||||||
onDragSegment({
|
onDragSegment({
|
||||||
object,
|
object,
|
||||||
intersection2d,
|
intersection2d: _intersection2d,
|
||||||
sketchPathToNode,
|
sketchPathToNode,
|
||||||
draftInfo,
|
draftInfo,
|
||||||
|
intersects,
|
||||||
}: {
|
}: {
|
||||||
object: any
|
object: any
|
||||||
intersection2d: Vector2
|
intersection2d: Vector2
|
||||||
sketchPathToNode: PathToNode
|
sketchPathToNode: PathToNode
|
||||||
|
intersects: Intersection<Object3D<Object3DEventMap>>[]
|
||||||
draftInfo?: {
|
draftInfo?: {
|
||||||
draftSegment: DraftSegment
|
draftSegment: DraftSegment
|
||||||
truncatedAst: Program
|
truncatedAst: Program
|
||||||
@ -540,6 +516,15 @@ class SceneEntities {
|
|||||||
variableDeclarationName: string
|
variableDeclarationName: string
|
||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
|
const profileStart =
|
||||||
|
draftInfo &&
|
||||||
|
intersects
|
||||||
|
.map(({ object }) => getParentGroup(object, [PROFILE_START]))
|
||||||
|
.find((a) => a?.name === PROFILE_START)
|
||||||
|
const intersection2d = profileStart
|
||||||
|
? new Vector2(profileStart.position.x, profileStart.position.y)
|
||||||
|
: _intersection2d
|
||||||
|
|
||||||
const group = getParentGroup(object, [
|
const group = getParentGroup(object, [
|
||||||
STRAIGHT_SEGMENT,
|
STRAIGHT_SEGMENT,
|
||||||
TANGENTIAL_ARC_TO_SEGMENT,
|
TANGENTIAL_ARC_TO_SEGMENT,
|
||||||
@ -1095,3 +1080,50 @@ function massageFormats(a: any): Vector3 {
|
|||||||
? new Vector3(a[0], a[1], a[2])
|
? new Vector3(a[0], a[1], a[2])
|
||||||
: new Vector3(a.x, a.y, a.z)
|
: new Vector3(a.x, a.y, a.z)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function mouseEnterLeaveCallbacks() {
|
||||||
|
return {
|
||||||
|
onMouseEnter: ({ selected }: OnMouseEnterLeaveArgs) => {
|
||||||
|
if ([X_AXIS, Y_AXIS].includes(selected?.userData?.type)) {
|
||||||
|
const obj = selected as Mesh
|
||||||
|
const mat = obj.material as MeshBasicMaterial
|
||||||
|
mat.color.set(obj.userData.baseColor)
|
||||||
|
mat.color.offsetHSL(0, 0, 0.5)
|
||||||
|
}
|
||||||
|
const parent = getParentGroup(selected, [
|
||||||
|
STRAIGHT_SEGMENT,
|
||||||
|
TANGENTIAL_ARC_TO_SEGMENT,
|
||||||
|
PROFILE_START,
|
||||||
|
])
|
||||||
|
if (parent?.userData?.pathToNode) {
|
||||||
|
const updatedAst = parse(recast(kclManager.ast))
|
||||||
|
const node = getNodeFromPath<CallExpression>(
|
||||||
|
updatedAst,
|
||||||
|
parent.userData.pathToNode,
|
||||||
|
'CallExpression'
|
||||||
|
).node
|
||||||
|
sceneInfra.highlightCallback([node.start, node.end])
|
||||||
|
const yellow = 0xffff00
|
||||||
|
colorSegment(selected, yellow)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sceneInfra.highlightCallback([0, 0])
|
||||||
|
},
|
||||||
|
onMouseLeave: ({ selected }: OnMouseEnterLeaveArgs) => {
|
||||||
|
sceneInfra.highlightCallback([0, 0])
|
||||||
|
const parent = getParentGroup(selected, [
|
||||||
|
STRAIGHT_SEGMENT,
|
||||||
|
TANGENTIAL_ARC_TO_SEGMENT,
|
||||||
|
PROFILE_START,
|
||||||
|
])
|
||||||
|
const isSelected = parent?.userData?.isSelected
|
||||||
|
colorSegment(selected, isSelected ? 0x0000ff : 0xffffff)
|
||||||
|
if ([X_AXIS, Y_AXIS].includes(selected?.userData?.type)) {
|
||||||
|
const obj = selected as Mesh
|
||||||
|
const mat = obj.material as MeshBasicMaterial
|
||||||
|
mat.color.set(obj.userData.baseColor)
|
||||||
|
if (obj.userData.isSelected) mat.color.offsetHSL(0, 0, 0.2)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -48,7 +48,7 @@ export const AXIS_GROUP = 'axisGroup'
|
|||||||
export const SKETCH_GROUP_SEGMENTS = 'sketch-group-segments'
|
export const SKETCH_GROUP_SEGMENTS = 'sketch-group-segments'
|
||||||
export const ARROWHEAD = 'arrowhead'
|
export const ARROWHEAD = 'arrowhead'
|
||||||
|
|
||||||
interface OnMouseEnterLeaveArgs {
|
export interface OnMouseEnterLeaveArgs {
|
||||||
selected: Object3D<Object3DEventMap>
|
selected: Object3D<Object3DEventMap>
|
||||||
mouseEvent: MouseEvent
|
mouseEvent: MouseEvent
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user