feat: Refactor HumanUi and VehicleUI components; introduce MarkerPrimitive for improved marker handling and interaction
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import { useEffect, useRef, useState } from 'react'
|
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||||
import { useGLTF } from '@react-three/drei';
|
import * as THREE from 'three'
|
||||||
|
import { Line, useGLTF } from '@react-three/drei';
|
||||||
import { useFrame, useThree } from '@react-three/fiber';
|
import { useFrame, useThree } from '@react-three/fiber';
|
||||||
import { useIsDragging, useIsRotating, useSelectedAction, useSelectedEventSphere } from '../../../../../store/simulation/useSimulationStore';
|
import { useIsDragging, useIsRotating, useSelectedAction, useSelectedEventSphere } from '../../../../../store/simulation/useSimulationStore';
|
||||||
import { useProductContext } from '../../../products/productContext';
|
import { useProductContext } from '../../../products/productContext';
|
||||||
@@ -27,7 +28,7 @@ function HumanUi() {
|
|||||||
const { humanStore, productStore } = useSceneContext();
|
const { humanStore, productStore } = useSceneContext();
|
||||||
const { selectedProduct } = selectedProductStore();
|
const { selectedProduct } = selectedProductStore();
|
||||||
const { humans, getHumanById } = humanStore();
|
const { humans, getHumanById } = humanStore();
|
||||||
const { updateEvent, updateAction, getActionByUuid } = productStore();
|
const { updateEvent, getActionByUuid } = productStore();
|
||||||
const [startPosition, setStartPosition] = useState<[number, number, number]>([0, 1, 0]);
|
const [startPosition, setStartPosition] = useState<[number, number, number]>([0, 1, 0]);
|
||||||
const [endPosition, setEndPosition] = 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]);
|
const [assemblyPosition, setAssemblyPosition] = useState<[number, number, number]>([0, 1, 0]);
|
||||||
@@ -313,64 +314,49 @@ function HumanUi() {
|
|||||||
rotation={[0, Math.PI, 0]}
|
rotation={[0, Math.PI, 0]}
|
||||||
>
|
>
|
||||||
{isAssembly ? (
|
{isAssembly ? (
|
||||||
<primitive
|
<MarkerPrimitive
|
||||||
ref={assemblyMarker}
|
name="assemblyMarker"
|
||||||
|
refProp={assemblyMarker}
|
||||||
object={assemblyScene}
|
object={assemblyScene}
|
||||||
position={assemblyPosition}
|
position={assemblyPosition}
|
||||||
rotation={assemblyRotation}
|
rotation={assemblyRotation}
|
||||||
onPointerDown={(e: any) => {
|
outerGroupRef={outerGroup}
|
||||||
if (e.object.parent.name === "handle") {
|
type="assembly"
|
||||||
handlePointerDown(e, "assembly", "assembly");
|
subtype="assembly"
|
||||||
} else {
|
color="#0f87f7"
|
||||||
handlePointerDown(e, "assembly", "assembly");
|
setIsDragging={setIsDragging}
|
||||||
}
|
setIsRotating={setIsRotating}
|
||||||
}}
|
handlePointerDown={handlePointerDown}
|
||||||
onPointerMissed={() => {
|
|
||||||
setIsDragging(null);
|
|
||||||
setIsRotating(null);
|
|
||||||
if (controls) (controls as any).enabled = true;
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<primitive
|
<MarkerPrimitive
|
||||||
name="startMarker"
|
name="startMarker"
|
||||||
|
refProp={startMarker}
|
||||||
object={startScene}
|
object={startScene}
|
||||||
ref={startMarker}
|
|
||||||
position={startPosition}
|
position={startPosition}
|
||||||
rotation={startRotation}
|
rotation={startRotation}
|
||||||
onPointerDown={(e: any) => {
|
outerGroupRef={outerGroup}
|
||||||
if (e.object.parent.name === "handle") {
|
type="start"
|
||||||
handlePointerDown(e, "start", "start");
|
subtype="start"
|
||||||
} else {
|
color="green"
|
||||||
handlePointerDown(e, "start", "start");
|
setIsDragging={setIsDragging}
|
||||||
}
|
setIsRotating={setIsRotating}
|
||||||
}}
|
handlePointerDown={handlePointerDown}
|
||||||
onPointerMissed={() => {
|
|
||||||
setIsDragging(null);
|
|
||||||
setIsRotating(null);
|
|
||||||
if (controls) (controls as any).enabled = true;
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
|
<MarkerPrimitive
|
||||||
<primitive
|
|
||||||
name="endMarker"
|
name="endMarker"
|
||||||
|
refProp={endMarker}
|
||||||
object={endScene}
|
object={endScene}
|
||||||
ref={endMarker}
|
|
||||||
position={endPosition}
|
position={endPosition}
|
||||||
rotation={endRotation}
|
rotation={endRotation}
|
||||||
onPointerDown={(e: any) => {
|
outerGroupRef={outerGroup}
|
||||||
if (e.object.parent.name === "handle") {
|
type="end"
|
||||||
handlePointerDown(e, "end", "end");
|
subtype="end"
|
||||||
} else {
|
color="orange"
|
||||||
handlePointerDown(e, "end", "end");
|
setIsDragging={setIsDragging}
|
||||||
}
|
setIsRotating={setIsRotating}
|
||||||
}}
|
handlePointerDown={handlePointerDown}
|
||||||
onPointerMissed={() => {
|
|
||||||
setIsDragging(null);
|
|
||||||
setIsRotating(null);
|
|
||||||
if (controls) (controls as any).enabled = true;
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@@ -380,4 +366,99 @@ function HumanUi() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default HumanUi;
|
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<THREE.Group>;
|
||||||
|
type: string;
|
||||||
|
subtype: string;
|
||||||
|
color: string;
|
||||||
|
setIsDragging: (val: any) => void;
|
||||||
|
setIsRotating: (val: any) => void;
|
||||||
|
handlePointerDown: any;
|
||||||
|
}) => {
|
||||||
|
const { controls, scene } = useThree();
|
||||||
|
const [hitPoint, setHitPoint] = useState<THREE.Vector3 | null>(null);
|
||||||
|
|
||||||
|
const lineRef = useRef<THREE.BufferGeometry>(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 (
|
||||||
|
<>
|
||||||
|
<primitive
|
||||||
|
name={name}
|
||||||
|
ref={refProp}
|
||||||
|
object={object}
|
||||||
|
position={position}
|
||||||
|
rotation={rotation}
|
||||||
|
onPointerDown={(e: any) => {
|
||||||
|
handlePointerDown(e, type, subtype);
|
||||||
|
}}
|
||||||
|
onPointerMissed={() => {
|
||||||
|
setIsDragging(null);
|
||||||
|
setIsRotating(null);
|
||||||
|
if (controls) (controls as any).enabled = true;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{hitPoint && (
|
||||||
|
<>
|
||||||
|
<mesh name={name} position={hitPoint} rotation={[-Math.PI / 2, 0, 0]}>
|
||||||
|
<torusGeometry args={[0.15, 0.02, 3, 32]} />
|
||||||
|
<meshBasicMaterial color={color} transparent opacity={0.8} depthWrite={false} />
|
||||||
|
</mesh>
|
||||||
|
|
||||||
|
<line>
|
||||||
|
<bufferGeometry ref={lineRef} />
|
||||||
|
<lineBasicMaterial color={color} />
|
||||||
|
</line>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import * as Types from "../../../../types/world/worldTypes";
|
import * as Types from "../../../../types/world/worldTypes";
|
||||||
import { useGLTF } from "@react-three/drei";
|
import { useGLTF } from "@react-three/drei";
|
||||||
|
import * as THREE from "three";
|
||||||
import { useFrame, useThree } from "@react-three/fiber";
|
import { useFrame, useThree } from "@react-three/fiber";
|
||||||
import { useSelectedEventSphere, useIsDragging, useIsRotating, } from "../../../../store/simulation/useSimulationStore";
|
import { useSelectedEventSphere, useIsDragging, useIsRotating, } from "../../../../store/simulation/useSimulationStore";
|
||||||
import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi";
|
import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi";
|
||||||
@@ -342,41 +343,120 @@ const VehicleUI = () => {
|
|||||||
</group>
|
</group>
|
||||||
|
|
||||||
{/* Start Marker */}
|
{/* Start Marker */}
|
||||||
<primitive
|
<VehicleMarkerPrimitive
|
||||||
name="startMarker"
|
name="startMarker"
|
||||||
object={startScene}
|
object={startScene}
|
||||||
ref={startMarker}
|
|
||||||
position={startPosition}
|
position={startPosition}
|
||||||
rotation={startRotation}
|
rotation={startRotation}
|
||||||
onPointerDown={(e: any) => {
|
outerGroupRef={outerGroup}
|
||||||
e.stopPropagation();
|
color="green"
|
||||||
handlePointerDown(e, "start", "start");
|
handlePointerDown={handlePointerDown}
|
||||||
}}
|
setIsDragging={setIsDragging}
|
||||||
|
setIsRotating={setIsRotating}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* End Marker */}
|
||||||
|
<VehicleMarkerPrimitive
|
||||||
|
name="endMarker"
|
||||||
|
object={endScene}
|
||||||
|
position={endPosition}
|
||||||
|
rotation={endRotation}
|
||||||
|
outerGroupRef={outerGroup}
|
||||||
|
color="red"
|
||||||
|
handlePointerDown={handlePointerDown}
|
||||||
|
setIsDragging={setIsDragging}
|
||||||
|
setIsRotating={setIsRotating}
|
||||||
|
/>
|
||||||
|
</group>
|
||||||
|
) : 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<THREE.Group>;
|
||||||
|
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<THREE.Group>(null);
|
||||||
|
const lineRef = useRef<THREE.BufferGeometry>(null);
|
||||||
|
const [hitPoint, setHitPoint] = useState<THREE.Vector3 | null>(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 (
|
||||||
|
<>
|
||||||
|
<primitive
|
||||||
|
name={name}
|
||||||
|
ref={markerRef}
|
||||||
|
object={object}
|
||||||
|
position={position}
|
||||||
|
rotation={rotation}
|
||||||
|
onPointerDown={(e: any) => handlePointerDown(e, name === "startMarker" ? "start" : "end", name === "startMarker" ? "start" : "end")}
|
||||||
onPointerMissed={() => {
|
onPointerMissed={() => {
|
||||||
controls.enabled = true;
|
|
||||||
setIsDragging(null);
|
setIsDragging(null);
|
||||||
setIsRotating(null);
|
setIsRotating(null);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* End Marker */}
|
{hitPoint && (
|
||||||
<primitive
|
<>
|
||||||
name="endMarker"
|
<mesh name={`${name}-torus`} position={hitPoint} rotation={[-Math.PI / 2, 0, 0]}>
|
||||||
object={endScene}
|
<torusGeometry args={[0.15, 0.02, 3, 32]} />
|
||||||
ref={endMarker}
|
<meshBasicMaterial color={color} transparent opacity={0.8} depthWrite={false} />
|
||||||
position={endPosition}
|
</mesh>
|
||||||
rotation={endRotation}
|
|
||||||
onPointerDown={(e: any) => {
|
<line>
|
||||||
e.stopPropagation();
|
<bufferGeometry ref={lineRef} />
|
||||||
handlePointerDown(e, "end", "end");
|
<lineBasicMaterial color={color} />
|
||||||
}}
|
</line>
|
||||||
onPointerMissed={() => {
|
</>
|
||||||
controls.enabled = true;
|
)}
|
||||||
setIsDragging(null);
|
</>
|
||||||
setIsRotating(null);
|
);
|
||||||
}}
|
};
|
||||||
/>
|
|
||||||
</group>
|
|
||||||
) : null;
|
|
||||||
};
|
|
||||||
export default VehicleUI;
|
|
||||||
Reference in New Issue
Block a user