diff --git a/app/src/modules/simulation/human/instances/instance/humanUi.tsx b/app/src/modules/simulation/human/instances/instance/humanUi.tsx index 17335b1..64c01ef 100644 --- a/app/src/modules/simulation/human/instances/instance/humanUi.tsx +++ b/app/src/modules/simulation/human/instances/instance/humanUi.tsx @@ -1,5 +1,6 @@ -import { useEffect, useRef, useState } from 'react' -import { useGLTF } from '@react-three/drei'; +import { useEffect, useMemo, useRef, useState } from 'react' +import * as THREE from 'three' +import { Line, useGLTF } from '@react-three/drei'; import { useFrame, useThree } from '@react-three/fiber'; import { useIsDragging, useIsRotating, useSelectedAction, useSelectedEventSphere } from '../../../../../store/simulation/useSimulationStore'; import { useProductContext } from '../../../products/productContext'; @@ -27,7 +28,7 @@ function HumanUi() { const { humanStore, productStore } = useSceneContext(); const { selectedProduct } = selectedProductStore(); const { humans, getHumanById } = humanStore(); - const { updateEvent, updateAction, getActionByUuid } = productStore(); + const { updateEvent, getActionByUuid } = productStore(); const [startPosition, setStartPosition] = useState<[number, number, number]>([0, 1, 0]); const [endPosition, setEndPosition] = useState<[number, number, number]>([0, 1, 0]); const [assemblyPosition, setAssemblyPosition] = useState<[number, number, number]>([0, 1, 0]); @@ -313,64 +314,49 @@ function HumanUi() { rotation={[0, Math.PI, 0]} > {isAssembly ? ( - { - if (e.object.parent.name === "handle") { - handlePointerDown(e, "assembly", "assembly"); - } else { - handlePointerDown(e, "assembly", "assembly"); - } - }} - onPointerMissed={() => { - setIsDragging(null); - setIsRotating(null); - if (controls) (controls as any).enabled = true; - }} + outerGroupRef={outerGroup} + type="assembly" + subtype="assembly" + color="#0f87f7" + setIsDragging={setIsDragging} + setIsRotating={setIsRotating} + handlePointerDown={handlePointerDown} /> ) : ( <> - { - if (e.object.parent.name === "handle") { - handlePointerDown(e, "start", "start"); - } else { - handlePointerDown(e, "start", "start"); - } - }} - onPointerMissed={() => { - setIsDragging(null); - setIsRotating(null); - if (controls) (controls as any).enabled = true; - }} + outerGroupRef={outerGroup} + type="start" + subtype="start" + color="green" + setIsDragging={setIsDragging} + setIsRotating={setIsRotating} + handlePointerDown={handlePointerDown} /> - - { - if (e.object.parent.name === "handle") { - handlePointerDown(e, "end", "end"); - } else { - handlePointerDown(e, "end", "end"); - } - }} - onPointerMissed={() => { - setIsDragging(null); - setIsRotating(null); - if (controls) (controls as any).enabled = true; - }} + outerGroupRef={outerGroup} + type="end" + subtype="end" + color="orange" + setIsDragging={setIsDragging} + setIsRotating={setIsRotating} + handlePointerDown={handlePointerDown} /> )} @@ -380,4 +366,99 @@ function HumanUi() { ); } -export default HumanUi; \ No newline at end of file +export default HumanUi; + +const MarkerPrimitive = ({ + name, + refProp, + object, + position, + rotation, + outerGroupRef, + type, + subtype, + color, + setIsDragging, + setIsRotating, + handlePointerDown, +}: { + name: string; + refProp: any; + object: THREE.Object3D; + position: [number, number, number]; + rotation: [number, number, number]; + outerGroupRef: React.RefObject; + type: string; + subtype: string; + color: string; + setIsDragging: (val: any) => void; + setIsRotating: (val: any) => void; + handlePointerDown: any; +}) => { + const { controls, scene } = useThree(); + const [hitPoint, setHitPoint] = useState(null); + + const lineRef = useRef(null); + + useFrame(() => { + if (!refProp.current || !outerGroupRef.current) return; + + const worldPos = new THREE.Vector3(); + refProp.current.getWorldPosition(worldPos); + const localMarkerPos = outerGroupRef.current.worldToLocal(worldPos.clone()); + + const rayOrigin = worldPos.clone(); + const direction = new THREE.Vector3(0, -1, 0); + const raycaster = new THREE.Raycaster(rayOrigin, direction, 0.1, 1000); + const intersects = raycaster.intersectObjects(scene.children, true); + + const hit = intersects.find(i => i.object.name !== name); + + if (hit) { + const localHit = outerGroupRef.current.worldToLocal(hit.point.clone()); + setHitPoint(localHit); + + if (lineRef.current) { + const positions = new Float32Array([localMarkerPos.x, localMarkerPos.y, localMarkerPos.z, localHit.x, localHit.y, localHit.z]); + lineRef.current.setAttribute('position', new THREE.BufferAttribute(positions, 3)); + lineRef.current.attributes.position.needsUpdate = true; + } + } else { + setHitPoint(null); + } + }); + + return ( + <> + { + handlePointerDown(e, type, subtype); + }} + onPointerMissed={() => { + setIsDragging(null); + setIsRotating(null); + if (controls) (controls as any).enabled = true; + }} + /> + + {hitPoint && ( + <> + + + + + + + + + + + )} + + ); +}; diff --git a/app/src/modules/simulation/spatialUI/vehicle/vehicleUI.tsx b/app/src/modules/simulation/spatialUI/vehicle/vehicleUI.tsx index 9bd36b5..7e59da1 100644 --- a/app/src/modules/simulation/spatialUI/vehicle/vehicleUI.tsx +++ b/app/src/modules/simulation/spatialUI/vehicle/vehicleUI.tsx @@ -1,6 +1,7 @@ import { useEffect, useRef, useState } from "react"; import * as Types from "../../../../types/world/worldTypes"; import { useGLTF } from "@react-three/drei"; +import * as THREE from "three"; import { useFrame, useThree } from "@react-three/fiber"; import { useSelectedEventSphere, useIsDragging, useIsRotating, } from "../../../../store/simulation/useSimulationStore"; import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi"; @@ -342,41 +343,120 @@ const VehicleUI = () => { {/* Start Marker */} - { - e.stopPropagation(); - handlePointerDown(e, "start", "start"); - }} + outerGroupRef={outerGroup} + color="green" + handlePointerDown={handlePointerDown} + setIsDragging={setIsDragging} + setIsRotating={setIsRotating} + /> + + {/* End Marker */} + + + ) : null; +}; + +export default VehicleUI; + +export const VehicleMarkerPrimitive = ({ + name, + object, + position, + rotation, + outerGroupRef, + color, + handlePointerDown, + setIsDragging, + setIsRotating, +}: { + name: string; + object: THREE.Object3D; + position: [number, number, number]; + rotation: [number, number, number]; + outerGroupRef: React.RefObject; + color: string; + handlePointerDown: (e: any, type: "start" | "end", rotation: "start" | "end") => void; + setIsDragging: (val: any) => void; + setIsRotating: (val: any) => void; +}) => { + const { scene } = useThree(); + const markerRef = useRef(null); + const lineRef = useRef(null); + const [hitPoint, setHitPoint] = useState(null); + + useFrame(() => { + if (!markerRef.current || !outerGroupRef.current) return; + + const worldPos = new THREE.Vector3(); + markerRef.current.getWorldPosition(worldPos); + const localMarkerPos = outerGroupRef.current.worldToLocal(worldPos.clone()); + + const rayOrigin = worldPos.clone(); + const direction = new THREE.Vector3(0, -1, 0); + const raycaster = new THREE.Raycaster(rayOrigin, direction, 0.1, 1000); + const intersects = raycaster.intersectObjects(scene.children, true); + + const hit = intersects.find(i => i.object.name !== name); + if (hit) { + const localHit = outerGroupRef.current.worldToLocal(hit.point.clone()); + setHitPoint(localHit); + + if (lineRef.current) { + const positions = new Float32Array([ + localMarkerPos.x, localMarkerPos.y, localMarkerPos.z, + localHit.x, localHit.y, localHit.z + ]); + lineRef.current.setAttribute('position', new THREE.BufferAttribute(positions, 3)); + lineRef.current.attributes.position.needsUpdate = true; + } + } else { + setHitPoint(null); + } + }); + + return ( + <> + handlePointerDown(e, name === "startMarker" ? "start" : "end", name === "startMarker" ? "start" : "end")} onPointerMissed={() => { - controls.enabled = true; setIsDragging(null); setIsRotating(null); }} /> - {/* End Marker */} - { - e.stopPropagation(); - handlePointerDown(e, "end", "end"); - }} - onPointerMissed={() => { - controls.enabled = true; - setIsDragging(null); - setIsRotating(null); - }} - /> - - ) : null; -}; -export default VehicleUI; + {hitPoint && ( + <> + + + + + + + + + + + )} + + ); +}; \ No newline at end of file