Refactor mouse event args (#1613)
* refactor mouse event interfaces Importantly returning multiple intersections from raycastRing, but other clean up * refactor enter exit args interface * type tweak
This commit is contained in:
@ -364,17 +364,18 @@ class SceneEntities {
|
|||||||
this.scene.add(group)
|
this.scene.add(group)
|
||||||
if (!draftSegment) {
|
if (!draftSegment) {
|
||||||
sceneInfra.setCallbacks({
|
sceneInfra.setCallbacks({
|
||||||
onDrag: (args) => {
|
onDrag: ({ selected, intersectionPoint, mouseEvent }) => {
|
||||||
if (args.event.which !== 1) return
|
if (mouseEvent.which !== 1) return
|
||||||
this.onDragSegment({
|
this.onDragSegment({
|
||||||
...args,
|
object: selected,
|
||||||
|
intersection2d: intersectionPoint.twoD,
|
||||||
sketchPathToNode,
|
sketchPathToNode,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
onMove: () => {},
|
onMove: () => {},
|
||||||
onClick: (args) => {
|
onClick: (args) => {
|
||||||
if (args?.event.which !== 1) return
|
if (args?.mouseEvent.which !== 1) return
|
||||||
if (!args || !args.object) {
|
if (!args || !args.selected) {
|
||||||
sceneInfra.modelingSend({
|
sceneInfra.modelingSend({
|
||||||
type: 'Set selection',
|
type: 'Set selection',
|
||||||
data: {
|
data: {
|
||||||
@ -383,22 +384,22 @@ class SceneEntities {
|
|||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const { object } = args
|
const { selected } = args
|
||||||
const event = getEventForSegmentSelection(object)
|
const event = getEventForSegmentSelection(selected)
|
||||||
if (!event) return
|
if (!event) return
|
||||||
sceneInfra.modelingSend(event)
|
sceneInfra.modelingSend(event)
|
||||||
},
|
},
|
||||||
onMouseEnter: ({ object }) => {
|
onMouseEnter: ({ selected }) => {
|
||||||
// TODO change the color of the segment to yellow?
|
// TODO change the color of the segment to yellow?
|
||||||
// Give a few pixels grace around each of the segments
|
// Give a few pixels grace around each of the segments
|
||||||
// for hover.
|
// for hover.
|
||||||
if ([X_AXIS, Y_AXIS].includes(object?.userData?.type)) {
|
if ([X_AXIS, Y_AXIS].includes(selected?.userData?.type)) {
|
||||||
const obj = object as Mesh
|
const obj = selected as Mesh
|
||||||
const mat = obj.material as MeshBasicMaterial
|
const mat = obj.material as MeshBasicMaterial
|
||||||
mat.color.set(obj.userData.baseColor)
|
mat.color.set(obj.userData.baseColor)
|
||||||
mat.color.offsetHSL(0, 0, 0.5)
|
mat.color.offsetHSL(0, 0, 0.5)
|
||||||
}
|
}
|
||||||
const parent = getParentGroup(object, [
|
const parent = getParentGroup(selected, [
|
||||||
STRAIGHT_SEGMENT,
|
STRAIGHT_SEGMENT,
|
||||||
TANGENTIAL_ARC_TO_SEGMENT,
|
TANGENTIAL_ARC_TO_SEGMENT,
|
||||||
PROFILE_START,
|
PROFILE_START,
|
||||||
@ -412,22 +413,22 @@ class SceneEntities {
|
|||||||
).node
|
).node
|
||||||
sceneInfra.highlightCallback([node.start, node.end])
|
sceneInfra.highlightCallback([node.start, node.end])
|
||||||
const yellow = 0xffff00
|
const yellow = 0xffff00
|
||||||
colorSegment(object, yellow)
|
colorSegment(selected, yellow)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sceneInfra.highlightCallback([0, 0])
|
sceneInfra.highlightCallback([0, 0])
|
||||||
},
|
},
|
||||||
onMouseLeave: ({ object }) => {
|
onMouseLeave: ({ selected }) => {
|
||||||
sceneInfra.highlightCallback([0, 0])
|
sceneInfra.highlightCallback([0, 0])
|
||||||
const parent = getParentGroup(object, [
|
const parent = getParentGroup(selected, [
|
||||||
STRAIGHT_SEGMENT,
|
STRAIGHT_SEGMENT,
|
||||||
TANGENTIAL_ARC_TO_SEGMENT,
|
TANGENTIAL_ARC_TO_SEGMENT,
|
||||||
PROFILE_START,
|
PROFILE_START,
|
||||||
])
|
])
|
||||||
const isSelected = parent?.userData?.isSelected
|
const isSelected = parent?.userData?.isSelected
|
||||||
colorSegment(object, isSelected ? 0x0000ff : 0xffffff)
|
colorSegment(selected, isSelected ? 0x0000ff : 0xffffff)
|
||||||
if ([X_AXIS, Y_AXIS].includes(object?.userData?.type)) {
|
if ([X_AXIS, Y_AXIS].includes(selected?.userData?.type)) {
|
||||||
const obj = object as Mesh
|
const obj = selected as Mesh
|
||||||
const mat = obj.material as MeshBasicMaterial
|
const mat = obj.material as MeshBasicMaterial
|
||||||
mat.color.set(obj.userData.baseColor)
|
mat.color.set(obj.userData.baseColor)
|
||||||
if (obj.userData.isSelected) mat.color.offsetHSL(0, 0, 0.2)
|
if (obj.userData.isSelected) mat.color.offsetHSL(0, 0, 0.2)
|
||||||
@ -439,14 +440,14 @@ class SceneEntities {
|
|||||||
onDrag: () => {},
|
onDrag: () => {},
|
||||||
onClick: async (args) => {
|
onClick: async (args) => {
|
||||||
if (!args) return
|
if (!args) return
|
||||||
if (args.event.which !== 1) return
|
if (args.mouseEvent.which !== 1) return
|
||||||
const { intersection2d } = args
|
const { intersectionPoint } = args
|
||||||
if (!intersection2d) return
|
if (!intersectionPoint?.twoD) return
|
||||||
|
|
||||||
const firstSeg = sketchGroup.value[0]
|
const firstSeg = sketchGroup.value[0]
|
||||||
const isClosingSketch = compareVec2Epsilon2(
|
const isClosingSketch = compareVec2Epsilon2(
|
||||||
firstSeg.from,
|
firstSeg.from,
|
||||||
[intersection2d.x, intersection2d.y],
|
[intersectionPoint.twoD.x, intersectionPoint.twoD.y],
|
||||||
0.5
|
0.5
|
||||||
)
|
)
|
||||||
let modifiedAst
|
let modifiedAst
|
||||||
@ -462,7 +463,7 @@ class SceneEntities {
|
|||||||
modifiedAst = addNewSketchLn({
|
modifiedAst = addNewSketchLn({
|
||||||
node: kclManager.ast,
|
node: kclManager.ast,
|
||||||
programMemory: kclManager.programMemory,
|
programMemory: kclManager.programMemory,
|
||||||
to: [intersection2d.x, intersection2d.y],
|
to: [intersectionPoint.twoD.x, intersectionPoint.twoD.y],
|
||||||
from: [lastSegment.to[0], lastSegment.to[1]],
|
from: [lastSegment.to[0], lastSegment.to[1]],
|
||||||
fnName:
|
fnName:
|
||||||
lastSegment.type === 'TangentialArcTo'
|
lastSegment.type === 'TangentialArcTo'
|
||||||
@ -478,7 +479,7 @@ class SceneEntities {
|
|||||||
},
|
},
|
||||||
onMove: (args) => {
|
onMove: (args) => {
|
||||||
this.onDragSegment({
|
this.onDragSegment({
|
||||||
...args,
|
intersection2d: args.intersectionPoint.twoD,
|
||||||
object: Object.values(this.activeSegments).slice(-1)[0],
|
object: Object.values(this.activeSegments).slice(-1)[0],
|
||||||
sketchPathToNode,
|
sketchPathToNode,
|
||||||
draftInfo: {
|
draftInfo: {
|
||||||
@ -525,15 +526,11 @@ class SceneEntities {
|
|||||||
)
|
)
|
||||||
onDragSegment({
|
onDragSegment({
|
||||||
object,
|
object,
|
||||||
event,
|
|
||||||
intersectPoint,
|
|
||||||
intersection2d,
|
intersection2d,
|
||||||
sketchPathToNode,
|
sketchPathToNode,
|
||||||
draftInfo,
|
draftInfo,
|
||||||
}: {
|
}: {
|
||||||
object: any
|
object: any
|
||||||
event: any
|
|
||||||
intersectPoint: Vector3
|
|
||||||
intersection2d: Vector2
|
intersection2d: Vector2
|
||||||
sketchPathToNode: PathToNode
|
sketchPathToNode: PathToNode
|
||||||
draftInfo?: {
|
draftInfo?: {
|
||||||
@ -851,22 +848,24 @@ class SceneEntities {
|
|||||||
}
|
}
|
||||||
setupDefaultPlaneHover() {
|
setupDefaultPlaneHover() {
|
||||||
sceneInfra.setCallbacks({
|
sceneInfra.setCallbacks({
|
||||||
onMouseEnter: ({ object }) => {
|
onMouseEnter: ({ selected }) => {
|
||||||
if (object.parent.userData.type !== DEFAULT_PLANES) return
|
if (!(selected instanceof Mesh && selected.parent)) return
|
||||||
const type: DefaultPlane = object.userData.type
|
if (selected.parent.userData.type !== DEFAULT_PLANES) return
|
||||||
object.material.color = defaultPlaneColor(type, 0.5, 1)
|
const type: DefaultPlane = selected.userData.type
|
||||||
|
selected.material.color = defaultPlaneColor(type, 0.5, 1)
|
||||||
},
|
},
|
||||||
onMouseLeave: ({ object }) => {
|
onMouseLeave: ({ selected }) => {
|
||||||
if (object.parent.userData.type !== DEFAULT_PLANES) return
|
if (!(selected instanceof Mesh && selected.parent)) return
|
||||||
const type: DefaultPlane = object.userData.type
|
if (selected.parent.userData.type !== DEFAULT_PLANES) return
|
||||||
object.material.color = defaultPlaneColor(type)
|
const type: DefaultPlane = selected.userData.type
|
||||||
|
selected.material.color = defaultPlaneColor(type)
|
||||||
},
|
},
|
||||||
onClick: (args) => {
|
onClick: (args) => {
|
||||||
if (!args || !args.object) return
|
if (!args || !args.intersects?.[0]) return
|
||||||
if (args.event.which !== 1) return
|
if (args.mouseEvent.which !== 1) return
|
||||||
const { intersection } = args
|
const { intersects } = args
|
||||||
const type = intersection.object.name || ''
|
const type = intersects?.[0].object.name || ''
|
||||||
const posNorm = Number(intersection.normal?.z) > 0
|
const posNorm = Number(intersects?.[0]?.normal?.z) > 0
|
||||||
let planeString: DefaultPlaneStr = posNorm ? 'XY' : '-XY'
|
let planeString: DefaultPlaneStr = posNorm ? 'XY' : '-XY'
|
||||||
let normal: [number, number, number] = posNorm ? [0, 0, 1] : [0, 0, -1]
|
let normal: [number, number, number] = posNorm ? [0, 0, 1] : [0, 0, -1]
|
||||||
if (type === YZ_PLANE) {
|
if (type === YZ_PLANE) {
|
||||||
|
@ -48,31 +48,36 @@ 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 BaseCallbackArgs2 {
|
interface OnMouseEnterLeaveArgs {
|
||||||
object: any
|
selected: Object3D<Object3DEventMap>
|
||||||
event: any
|
mouseEvent: MouseEvent
|
||||||
}
|
|
||||||
interface BaseCallbackArgs {
|
|
||||||
event: any
|
|
||||||
}
|
|
||||||
interface OnDragCallbackArgs extends BaseCallbackArgs {
|
|
||||||
object: any
|
|
||||||
intersection2d: Vector2
|
|
||||||
intersectPoint: Vector3
|
|
||||||
intersection: Intersection<Object3D<Object3DEventMap>>
|
|
||||||
}
|
|
||||||
interface OnClickCallbackArgs extends BaseCallbackArgs {
|
|
||||||
intersection2d?: Vector2
|
|
||||||
intersectPoint: Vector3
|
|
||||||
intersection: Intersection<Object3D<Object3DEventMap>>
|
|
||||||
object?: any
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface onMoveCallbackArgs {
|
interface OnDragCallbackArgs extends OnMouseEnterLeaveArgs {
|
||||||
event: any
|
intersectionPoint: {
|
||||||
intersection2d: Vector2
|
twoD: Vector2
|
||||||
intersectPoint: Vector3
|
threeD: Vector3
|
||||||
intersection: Intersection<Object3D<Object3DEventMap>>
|
}
|
||||||
|
intersects: Intersection<Object3D<Object3DEventMap>>[]
|
||||||
|
}
|
||||||
|
interface OnClickCallbackArgs {
|
||||||
|
mouseEvent: MouseEvent
|
||||||
|
intersectionPoint?: {
|
||||||
|
twoD: Vector2
|
||||||
|
threeD: Vector3
|
||||||
|
}
|
||||||
|
intersects: Intersection<Object3D<Object3DEventMap>>[]
|
||||||
|
selected?: Object3D<Object3DEventMap>
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OnMoveCallbackArgs {
|
||||||
|
mouseEvent: MouseEvent
|
||||||
|
intersectionPoint: {
|
||||||
|
twoD: Vector2
|
||||||
|
threeD: Vector3
|
||||||
|
}
|
||||||
|
intersects: Intersection<Object3D<Object3DEventMap>>[]
|
||||||
|
selected?: Object3D<Object3DEventMap>
|
||||||
}
|
}
|
||||||
|
|
||||||
// This singleton class is responsible for all of the under the hood setup for the client side scene.
|
// This singleton class is responsible for all of the under the hood setup for the client side scene.
|
||||||
@ -90,16 +95,16 @@ class SceneInfra {
|
|||||||
_baseUnit: BaseUnit = 'mm'
|
_baseUnit: BaseUnit = 'mm'
|
||||||
_baseUnitMultiplier = 1
|
_baseUnitMultiplier = 1
|
||||||
onDragCallback: (arg: OnDragCallbackArgs) => void = () => {}
|
onDragCallback: (arg: OnDragCallbackArgs) => void = () => {}
|
||||||
onMoveCallback: (arg: onMoveCallbackArgs) => void = () => {}
|
onMoveCallback: (arg: OnMoveCallbackArgs) => void = () => {}
|
||||||
onClickCallback: (arg?: OnClickCallbackArgs) => void = () => {}
|
onClickCallback: (arg?: OnClickCallbackArgs) => void = () => {}
|
||||||
onMouseEnter: (arg: BaseCallbackArgs2) => void = () => {}
|
onMouseEnter: (arg: OnMouseEnterLeaveArgs) => void = () => {}
|
||||||
onMouseLeave: (arg: BaseCallbackArgs2) => void = () => {}
|
onMouseLeave: (arg: OnMouseEnterLeaveArgs) => void = () => {}
|
||||||
setCallbacks = (callbacks: {
|
setCallbacks = (callbacks: {
|
||||||
onDrag?: (arg: OnDragCallbackArgs) => void
|
onDrag?: (arg: OnDragCallbackArgs) => void
|
||||||
onMove?: (arg: onMoveCallbackArgs) => void
|
onMove?: (arg: OnMoveCallbackArgs) => void
|
||||||
onClick?: (arg?: OnClickCallbackArgs) => void
|
onClick?: (arg?: OnClickCallbackArgs) => void
|
||||||
onMouseEnter?: (arg: BaseCallbackArgs2) => void
|
onMouseEnter?: (arg: OnMouseEnterLeaveArgs) => void
|
||||||
onMouseLeave?: (arg: BaseCallbackArgs2) => void
|
onMouseLeave?: (arg: OnMouseEnterLeaveArgs) => void
|
||||||
}) => {
|
}) => {
|
||||||
this.onDragCallback = callbacks.onDrag || this.onDragCallback
|
this.onDragCallback = callbacks.onDrag || this.onDragCallback
|
||||||
this.onMoveCallback = callbacks.onMove || this.onMoveCallback
|
this.onMoveCallback = callbacks.onMove || this.onMoveCallback
|
||||||
@ -142,10 +147,9 @@ class SceneInfra {
|
|||||||
currentMouseVector = new Vector2()
|
currentMouseVector = new Vector2()
|
||||||
selected: {
|
selected: {
|
||||||
mouseDownVector: Vector2
|
mouseDownVector: Vector2
|
||||||
object: any
|
object: Object3D<Object3DEventMap>
|
||||||
hasBeenDragged: boolean
|
hasBeenDragged: boolean
|
||||||
} | null = null
|
} | null = null
|
||||||
selectedObject: null | any = null
|
|
||||||
mouseDownVector: null | Vector2 = null
|
mouseDownVector: null | Vector2 = null
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -242,8 +246,8 @@ class SceneInfra {
|
|||||||
// Dispose of any other resources like geometries, materials, textures
|
// Dispose of any other resources like geometries, materials, textures
|
||||||
}
|
}
|
||||||
getPlaneIntersectPoint = (): {
|
getPlaneIntersectPoint = (): {
|
||||||
intersection2d?: Vector2
|
twoD?: Vector2
|
||||||
intersectPoint: Vector3
|
threeD?: Vector3
|
||||||
intersection: Intersection<Object3D<Object3DEventMap>>
|
intersection: Intersection<Object3D<Object3DEventMap>>
|
||||||
} | null => {
|
} | null => {
|
||||||
this.planeRaycaster.setFromCamera(
|
this.planeRaycaster.setFromCamera(
|
||||||
@ -254,23 +258,11 @@ class SceneInfra {
|
|||||||
this.scene.children,
|
this.scene.children,
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
if (
|
const recastablePlaneIntersect = planeIntersects.find(
|
||||||
planeIntersects.length > 0 &&
|
(intersect) => intersect.object.name === RAYCASTABLE_PLANE
|
||||||
planeIntersects[0].object.userData.type !== RAYCASTABLE_PLANE
|
|
||||||
) {
|
|
||||||
const intersect = planeIntersects[0]
|
|
||||||
return {
|
|
||||||
intersectPoint: intersect.point,
|
|
||||||
intersection: intersect,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
!(
|
|
||||||
planeIntersects.length > 0 &&
|
|
||||||
planeIntersects[0].object.userData.type === RAYCASTABLE_PLANE
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
return null
|
if (!planeIntersects.length) return null
|
||||||
|
if (!recastablePlaneIntersect) return { intersection: planeIntersects[0] }
|
||||||
const planePosition = planeIntersects[0].object.position
|
const planePosition = planeIntersects[0].object.position
|
||||||
const inversePlaneQuaternion = planeIntersects[0].object.quaternion
|
const inversePlaneQuaternion = planeIntersects[0].object.quaternion
|
||||||
.clone()
|
.clone()
|
||||||
@ -285,19 +277,21 @@ class SceneInfra {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
intersection2d: new Vector2(
|
twoD: new Vector2(
|
||||||
transformedPoint.x / this._baseUnitMultiplier,
|
transformedPoint.x / this._baseUnitMultiplier,
|
||||||
transformedPoint.y / this._baseUnitMultiplier
|
transformedPoint.y / this._baseUnitMultiplier
|
||||||
), // z should be 0
|
), // z should be 0
|
||||||
intersectPoint: intersectPoint.divideScalar(this._baseUnitMultiplier),
|
threeD: intersectPoint.divideScalar(this._baseUnitMultiplier),
|
||||||
intersection: planeIntersects[0],
|
intersection: planeIntersects[0],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onMouseMove = (event: MouseEvent) => {
|
onMouseMove = (mouseEvent: MouseEvent) => {
|
||||||
this.currentMouseVector.x = (event.clientX / window.innerWidth) * 2 - 1
|
this.currentMouseVector.x = (mouseEvent.clientX / window.innerWidth) * 2 - 1
|
||||||
this.currentMouseVector.y = -(event.clientY / window.innerHeight) * 2 + 1
|
this.currentMouseVector.y =
|
||||||
|
-(mouseEvent.clientY / window.innerHeight) * 2 + 1
|
||||||
|
|
||||||
const planeIntersectPoint = this.getPlaneIntersectPoint()
|
const planeIntersectPoint = this.getPlaneIntersectPoint()
|
||||||
|
const intersects = this.raycastRing()
|
||||||
|
|
||||||
if (this.selected) {
|
if (this.selected) {
|
||||||
const hasBeenDragged = !compareVec2Epsilon2(
|
const hasBeenDragged = !compareVec2Epsilon2(
|
||||||
@ -313,47 +307,56 @@ class SceneInfra {
|
|||||||
if (
|
if (
|
||||||
hasBeenDragged &&
|
hasBeenDragged &&
|
||||||
planeIntersectPoint &&
|
planeIntersectPoint &&
|
||||||
planeIntersectPoint.intersection2d
|
planeIntersectPoint.twoD &&
|
||||||
|
planeIntersectPoint.threeD
|
||||||
) {
|
) {
|
||||||
// // console.log('onDrag', this.selected)
|
// // console.log('onDrag', this.selected)
|
||||||
|
|
||||||
this.onDragCallback({
|
this.onDragCallback({
|
||||||
object: this.selected.object,
|
mouseEvent,
|
||||||
event,
|
intersectionPoint: {
|
||||||
intersection2d: planeIntersectPoint.intersection2d,
|
twoD: planeIntersectPoint.twoD,
|
||||||
...planeIntersectPoint,
|
threeD: planeIntersectPoint.threeD,
|
||||||
|
},
|
||||||
|
intersects,
|
||||||
|
selected: this.selected.object,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else if (planeIntersectPoint && planeIntersectPoint.intersection2d) {
|
} else if (
|
||||||
|
planeIntersectPoint &&
|
||||||
|
planeIntersectPoint.twoD &&
|
||||||
|
planeIntersectPoint.threeD
|
||||||
|
) {
|
||||||
this.onMoveCallback({
|
this.onMoveCallback({
|
||||||
event,
|
mouseEvent,
|
||||||
intersection2d: planeIntersectPoint.intersection2d,
|
intersectionPoint: {
|
||||||
...planeIntersectPoint,
|
twoD: planeIntersectPoint.twoD,
|
||||||
|
threeD: planeIntersectPoint.threeD,
|
||||||
|
},
|
||||||
|
intersects,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const intersect = this.raycastRing()
|
if (intersects[0]) {
|
||||||
|
const firstIntersectObject = intersects[0].object
|
||||||
if (intersect) {
|
|
||||||
const firstIntersectObject = intersect.object
|
|
||||||
if (this.hoveredObject !== firstIntersectObject) {
|
if (this.hoveredObject !== firstIntersectObject) {
|
||||||
if (this.hoveredObject) {
|
if (this.hoveredObject) {
|
||||||
this.onMouseLeave({
|
this.onMouseLeave({
|
||||||
object: this.hoveredObject,
|
selected: this.hoveredObject,
|
||||||
event,
|
mouseEvent: mouseEvent,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
this.hoveredObject = firstIntersectObject
|
this.hoveredObject = firstIntersectObject
|
||||||
this.onMouseEnter({
|
this.onMouseEnter({
|
||||||
object: this.hoveredObject,
|
selected: this.hoveredObject,
|
||||||
event,
|
mouseEvent: mouseEvent,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (this.hoveredObject) {
|
if (this.hoveredObject) {
|
||||||
this.onMouseLeave({
|
this.onMouseLeave({
|
||||||
object: this.hoveredObject,
|
selected: this.hoveredObject,
|
||||||
event,
|
mouseEvent: mouseEvent,
|
||||||
})
|
})
|
||||||
this.hoveredObject = null
|
this.hoveredObject = null
|
||||||
}
|
}
|
||||||
@ -363,41 +366,38 @@ class SceneInfra {
|
|||||||
raycastRing = (
|
raycastRing = (
|
||||||
pixelRadius = 8,
|
pixelRadius = 8,
|
||||||
rayRingCount = 32
|
rayRingCount = 32
|
||||||
): Intersection<Object3D<Object3DEventMap>> | undefined => {
|
): Intersection<Object3D<Object3DEventMap>>[] => {
|
||||||
const mouseDownVector = this.currentMouseVector.clone()
|
const mouseDownVector = this.currentMouseVector.clone()
|
||||||
let closestIntersection:
|
const intersectionsMap = new Map<
|
||||||
| Intersection<Object3D<Object3DEventMap>>
|
Object3D,
|
||||||
| undefined = undefined
|
Intersection<Object3D<Object3DEventMap>>
|
||||||
let closestDistance = Infinity
|
>()
|
||||||
|
|
||||||
const updateClosestIntersection = (
|
const updateIntersectionsMap = (
|
||||||
intersections: Intersection<Object3D<Object3DEventMap>>[]
|
intersections: Intersection<Object3D<Object3DEventMap>>[]
|
||||||
) => {
|
) => {
|
||||||
let intersection = null
|
intersections.forEach((intersection) => {
|
||||||
for (let i = 0; i < intersections.length; i++) {
|
if (intersection.object.type !== 'GridHelper') {
|
||||||
if (intersections[i].object.type !== 'GridHelper') {
|
const existingIntersection = intersectionsMap.get(intersection.object)
|
||||||
intersection = intersections[i]
|
if (
|
||||||
break
|
!existingIntersection ||
|
||||||
|
existingIntersection.distance > intersection.distance
|
||||||
|
) {
|
||||||
|
intersectionsMap.set(intersection.object, intersection)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
if (!intersection) return
|
|
||||||
|
|
||||||
if (intersection.distance < closestDistance) {
|
|
||||||
closestDistance = intersection.distance
|
|
||||||
closestIntersection = intersection
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the center point
|
// Check the center point
|
||||||
this.raycaster.setFromCamera(mouseDownVector, this.camControls.camera)
|
this.raycaster.setFromCamera(mouseDownVector, this.camControls.camera)
|
||||||
updateClosestIntersection(
|
updateIntersectionsMap(
|
||||||
this.raycaster.intersectObjects(this.scene.children, true)
|
this.raycaster.intersectObjects(this.scene.children, true)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Check the ring points
|
// Check the ring points
|
||||||
for (let i = 0; i < rayRingCount; i++) {
|
for (let i = 0; i < rayRingCount; i++) {
|
||||||
const angle = (i / rayRingCount) * Math.PI * 2
|
const angle = (i / rayRingCount) * Math.PI * 2
|
||||||
|
|
||||||
const offsetX = ((pixelRadius * Math.cos(angle)) / window.innerWidth) * 2
|
const offsetX = ((pixelRadius * Math.cos(angle)) / window.innerWidth) * 2
|
||||||
const offsetY = ((pixelRadius * Math.sin(angle)) / window.innerHeight) * 2
|
const offsetY = ((pixelRadius * Math.sin(angle)) / window.innerHeight) * 2
|
||||||
const ringVector = new Vector2(
|
const ringVector = new Vector2(
|
||||||
@ -405,11 +405,15 @@ class SceneInfra {
|
|||||||
mouseDownVector.y - offsetY
|
mouseDownVector.y - offsetY
|
||||||
)
|
)
|
||||||
this.raycaster.setFromCamera(ringVector, this.camControls.camera)
|
this.raycaster.setFromCamera(ringVector, this.camControls.camera)
|
||||||
updateClosestIntersection(
|
updateIntersectionsMap(
|
||||||
this.raycaster.intersectObjects(this.scene.children, true)
|
this.raycaster.intersectObjects(this.scene.children, true)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return closestIntersection
|
|
||||||
|
// Convert the map values to an array and sort by distance
|
||||||
|
return Array.from(intersectionsMap.values()).sort(
|
||||||
|
(a, b) => a.distance - b.distance
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
onMouseDown = (event: MouseEvent) => {
|
onMouseDown = (event: MouseEvent) => {
|
||||||
@ -417,45 +421,60 @@ class SceneInfra {
|
|||||||
this.currentMouseVector.y = -(event.clientY / window.innerHeight) * 2 + 1
|
this.currentMouseVector.y = -(event.clientY / window.innerHeight) * 2 + 1
|
||||||
|
|
||||||
const mouseDownVector = this.currentMouseVector.clone()
|
const mouseDownVector = this.currentMouseVector.clone()
|
||||||
const intersect = this.raycastRing()
|
const intersect = this.raycastRing()[0]
|
||||||
|
|
||||||
if (intersect) {
|
if (intersect) {
|
||||||
const intersectParent = intersect?.object?.parent as Group
|
const intersectParent = intersect?.object?.parent as Group
|
||||||
this.selected = intersectParent.isGroup
|
this.selected = intersectParent.isGroup
|
||||||
? {
|
? {
|
||||||
mouseDownVector,
|
mouseDownVector,
|
||||||
object: intersect?.object,
|
object: intersect.object,
|
||||||
hasBeenDragged: false,
|
hasBeenDragged: false,
|
||||||
}
|
}
|
||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMouseUp = (event: MouseEvent) => {
|
onMouseUp = (mouseEvent: MouseEvent) => {
|
||||||
this.currentMouseVector.x = (event.clientX / window.innerWidth) * 2 - 1
|
this.currentMouseVector.x = (mouseEvent.clientX / window.innerWidth) * 2 - 1
|
||||||
this.currentMouseVector.y = -(event.clientY / window.innerHeight) * 2 + 1
|
this.currentMouseVector.y =
|
||||||
|
-(mouseEvent.clientY / window.innerHeight) * 2 + 1
|
||||||
const planeIntersectPoint = this.getPlaneIntersectPoint()
|
const planeIntersectPoint = this.getPlaneIntersectPoint()
|
||||||
|
const intersects = this.raycastRing()
|
||||||
|
|
||||||
if (this.selected) {
|
if (this.selected) {
|
||||||
if (this.selected.hasBeenDragged) {
|
if (this.selected.hasBeenDragged) {
|
||||||
// this is where we could fire a onDragEnd event
|
// this is where we could fire a onDragEnd event
|
||||||
// console.log('onDragEnd', this.selected)
|
// console.log('onDragEnd', this.selected)
|
||||||
} else if (planeIntersectPoint) {
|
} else if (planeIntersectPoint?.twoD && planeIntersectPoint?.threeD) {
|
||||||
// fire onClick event as there was no drags
|
// fire onClick event as there was no drags
|
||||||
this.onClickCallback({
|
this.onClickCallback({
|
||||||
object: this.selected?.object,
|
mouseEvent,
|
||||||
event,
|
intersectionPoint: {
|
||||||
...planeIntersectPoint,
|
twoD: planeIntersectPoint.twoD,
|
||||||
|
threeD: planeIntersectPoint.threeD,
|
||||||
|
},
|
||||||
|
intersects,
|
||||||
|
selected: this.selected.object,
|
||||||
|
})
|
||||||
|
} else if (planeIntersectPoint) {
|
||||||
|
this.onClickCallback({
|
||||||
|
mouseEvent,
|
||||||
|
intersects,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
this.onClickCallback()
|
this.onClickCallback()
|
||||||
}
|
}
|
||||||
// Clear the selected state whether it was dragged or not
|
// Clear the selected state whether it was dragged or not
|
||||||
this.selected = null
|
this.selected = null
|
||||||
} else if (planeIntersectPoint) {
|
} else if (planeIntersectPoint?.twoD && planeIntersectPoint?.threeD) {
|
||||||
this.onClickCallback({
|
this.onClickCallback({
|
||||||
event,
|
mouseEvent,
|
||||||
...planeIntersectPoint,
|
intersectionPoint: {
|
||||||
|
twoD: planeIntersectPoint.twoD,
|
||||||
|
threeD: planeIntersectPoint.threeD,
|
||||||
|
},
|
||||||
|
intersects,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
this.onClickCallback()
|
this.onClickCallback()
|
||||||
|
@ -829,13 +829,13 @@ export const modelingMachine = createMachine(
|
|||||||
sceneInfra.setCallbacks({
|
sceneInfra.setCallbacks({
|
||||||
onClick: async (args) => {
|
onClick: async (args) => {
|
||||||
if (!args) return
|
if (!args) return
|
||||||
if (args.event.which !== 1) return
|
if (args.mouseEvent.which !== 1) return
|
||||||
const { intersection2d } = args
|
const { intersectionPoint } = args
|
||||||
if (!intersection2d || !sketchPathToNode) return
|
if (!intersectionPoint?.twoD || !sketchPathToNode) return
|
||||||
const { modifiedAst } = addStartProfileAt(
|
const { modifiedAst } = addStartProfileAt(
|
||||||
kclManager.ast,
|
kclManager.ast,
|
||||||
sketchPathToNode,
|
sketchPathToNode,
|
||||||
[intersection2d.x, intersection2d.y]
|
[intersectionPoint.twoD.x, intersectionPoint.twoD.y]
|
||||||
)
|
)
|
||||||
await kclManager.updateAst(modifiedAst, false)
|
await kclManager.updateAst(modifiedAst, false)
|
||||||
sceneEntitiesManager.removeIntersectionPlane()
|
sceneEntitiesManager.removeIntersectionPlane()
|
||||||
|
Reference in New Issue
Block a user