From 979f71d43f8c8bdd7dafd6db822275d98e7ca15a Mon Sep 17 00:00:00 2001 From: Nalvazhuthi Date: Tue, 29 Apr 2025 10:18:05 +0530 Subject: [PATCH] Added vehicle UI --- app/package-lock.json | 66 +-- app/src/assets/gltf-glb/arrow_green.glb | Bin 0 -> 4580 bytes app/src/assets/gltf-glb/arrow_red.glb | Bin 0 -> 4580 bytes app/src/modules/scene/scene.tsx | 45 +- .../events/points/creator/pointsCreator.tsx | 392 ++++++++++-------- .../simulation/ui/vehicle/useDraggableGLTF.ts | 131 ++++++ .../simulation/ui/vehicle/vehicleUI.tsx | 283 +++++++++++++ .../modules/simulation/vehicle/vehicles.tsx | 286 ++++++------- 8 files changed, 817 insertions(+), 386 deletions(-) create mode 100644 app/src/assets/gltf-glb/arrow_green.glb create mode 100644 app/src/assets/gltf-glb/arrow_red.glb create mode 100644 app/src/modules/simulation/ui/vehicle/useDraggableGLTF.ts create mode 100644 app/src/modules/simulation/ui/vehicle/vehicleUI.tsx diff --git a/app/package-lock.json b/app/package-lock.json index fa04c9f..3d5aea4 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -30,7 +30,6 @@ "glob": "^11.0.0", "gsap": "^3.12.5", "html2canvas": "^1.4.1", - "immer": "^10.1.1", "leva": "^0.10.0", "mqtt": "^5.10.4", "postprocessing": "^6.36.4", @@ -2022,7 +2021,7 @@ "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "devOptional": true, + "dev": true, "dependencies": { "@jridgewell/trace-mapping": "0.3.9" }, @@ -2034,7 +2033,7 @@ "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "devOptional": true, + "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -4137,26 +4136,6 @@ "url": "https://github.com/sponsors/gregberge" } }, - "node_modules/@testing-library/dom": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", - "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "5.3.0", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.5.0", - "pretty-format": "^27.0.2" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/@testing-library/jest-dom": { "version": "5.17.0", "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.17.0.tgz", @@ -4268,25 +4247,25 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "devOptional": true + "dev": true }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "devOptional": true + "dev": true }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "devOptional": true + "dev": true }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "devOptional": true + "dev": true }, "node_modules/@turf/along": { "version": "7.2.0", @@ -9040,7 +9019,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "devOptional": true + "dev": true }, "node_modules/cross-env": { "version": "7.0.3", @@ -9917,7 +9896,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "devOptional": true, + "dev": true, "engines": { "node": ">=0.3.1" } @@ -12747,10 +12726,9 @@ "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" }, "node_modules/immer": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.1.tgz", - "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==", - "license": "MIT", + "version": "9.0.21", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", + "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", "funding": { "type": "opencollective", "url": "https://opencollective.com/immer" @@ -15281,7 +15259,7 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "devOptional": true + "dev": true }, "node_modules/makeerror": { "version": "1.0.12", @@ -18012,16 +17990,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/react-dev-utils/node_modules/immer": { - "version": "9.0.21", - "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", - "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/immer" - } - }, "node_modules/react-dev-utils/node_modules/loader-utils": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.3.1.tgz", @@ -20759,7 +20727,7 @@ "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "devOptional": true, + "dev": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -20802,7 +20770,7 @@ "version": "8.3.4", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", - "devOptional": true, + "dev": true, "dependencies": { "acorn": "^8.11.0" }, @@ -20814,7 +20782,7 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "devOptional": true + "dev": true }, "node_modules/tsconfig-paths": { "version": "3.15.0", @@ -21310,7 +21278,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "devOptional": true + "dev": true }, "node_modules/v8-to-istanbul": { "version": "8.1.1", @@ -22369,7 +22337,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "devOptional": true, + "dev": true, "engines": { "node": ">=6" } diff --git a/app/src/assets/gltf-glb/arrow_green.glb b/app/src/assets/gltf-glb/arrow_green.glb new file mode 100644 index 0000000000000000000000000000000000000000..8e02527b34c890ef80210fd869ef7fd103ac2cf4 GIT binary patch literal 4580 zcmc&%eOOdg8b5O{AHxj8hoVNJ&|M`L$MK%~eWw&q!7p$K(6x+UfU8Wx49*Nj;%p=7 zqGgHs=wi0XVzn-%rB>`_7{s$in^usmwryr6Nj_V-nps%RzITQZEG?~lp8bQlGv}Q5 z>-YP;@3|~0&(9HB zV3IVYT(Orb&ZLXK`&ODUzy3#i#M zatlkH))Gfyh2knJEOAs+Iu)1S%IM#$u(}ne&06j%R4Qz+u~aE^xt)rAk-Lm480;}u zSyE+l{-js1ag{(Bl$q}T=7KzGD7&=+)~G!Ho{_RUN)>g3HsS&g*aUyqP->oj<9>^r zaw~Wh@O)Mzl$!MNA7KEprmhNW5SiSd@YOX|2Fx45o!4(?B6*R(mNp{{Q9$^Rqvz4kmxt&$YrF^sd zc{b5BhO8@#o!N@pT3&7|$#qmMDzk$qR0S4WUCLBPxx<-hE%ECRfTLNFrda@t=Qs%q zvIxKlqDTueO-n2f+YAd!G|O-@%Sr-=MS&4nmIrPj!TvBohad}QFyf^(6Yo($zC!vz zRR)i$`N%Bh7@(2iG3I4KG-3$Puq+mMmSIJfVE zF$HQlgNGBe6syYN+Sro@;>(v8jOkxcG4nsD7^_wG&xyFmUMIMVhOazz;Jm&mE7mFMX9SmJ8V0~e;P&%3JM0eMi>SER8rL_m^hw+mjjWZ8IhMn8BpXvpa2ah zQ|5RX^hKLk39c0^Nt`HyNI_ngfaFaA4|)bQax&(?NQLnS9$?Myf`N;Q!!#U~uUCy~ z&esFu<>!AIMuvki_&qg3l>_%dpveQj{iC4xUbm7Jcr7&Z0*q>P!Lo3n|IHN!SMW0V z!C{VrK|1&_FGxRfT;RUv8-p6vYcr5be_n%38eI$Ge-GMq4J04)tkbeFUDN{*gX7jS$#qPy~q( zn8QOuYRCuzsm?Sgnv5_EwGyo%qr%sd*;?|m&~Jte+mrJ3*Ufb=#_j1;KHOl<=zRa4 zy{6i8so*Lh#Jf>z^=$OU%wKmd`>TNhkqSWE_@R>~P zz84*Pt^2SBCCpFoo;Vg36CI7b!-k`xNsrE38IIa?4^jvv{~DoV(^e#+hQ(c{Nz`y> z4ca}7MB2k;x1h@Csi8$RL%dNC+j~?_%Ng>Ip=j@X&jX*J_QzqdbpvweXpUsQukpTN z!N^_nHySk4I*iXX zr=aHMokZ`U7mLv&arzk=wEVvD=;`L2P0jIp;#u~c&Fq1uv$u`uS$z7%VN@*4BmHN87erM%&|h1a12gb&E^0ZlrU5PDhs;h%_lblQ>ha!V7ui$XY z@QW>vp4xf`@)6V0e8ib4>fbfVr9zu%2yG1`tz^YG-N7Bi!9Aaze{kuOFWh=zeeW$N zP@3mZJ&A_KLFjM4jgrxGe-}<5uV-2XiI$|i9F30L-5HC#Cu3y-b)Hz7h*rN2#7@6^ zBs#r3D;yQIfZh0Zy*F!<{X1P*rv_cn!pe}W>O^=P^}vVsyat611@qIl7HwY^PDL`(!6@toQljXFy|n~Y*M0C4L*pNxvmZ;C>TLtxV{f(uBl}`(m|92Sf{W5W0+@NHQZndY2}gk82GZrHhO;%O^^2GbKkX zh+Yx@X%hOEz8;+-ZwxOC?&EeQITC4s&DgdKh%x4| zz*Ef)7;HPIpQMI{;K1Nu{!(*@oLF?D&*!roo;=o*@@d}8t+V>_4^Ph6+GOea({_!& z^;@Rtd5Gt)A2ft+#7QXbQ1#KuFAcYU zY%rI0vfCT>f7Cl(K;yQDg~sn`WHRSAO>EJ$HP#NVGw4d(TwlyPSbwUx>8{YwS}DP^ z>!XH{C$V&A&d6=s4&Br6uq`KH=s9M4%$SF2m-U=&+Lu3X;{Cez$9|u_>X>1~p@*x) zb6uIs;`6ml*ziC}?yA1Zz3LY~wZ2h6Cd1nS8~U`Oq`t>m=KA)AvUDdq>pRt zD7Ezz4tqa-MMvb83v})IuBLx_kIek;+mAHbhOo^JU%@x#W9C+hEB zvhjg48_8e!UK9T^ci9ue+g_Nm=)+B`Q^mJB@}F!@>DC{eUUBmg-GK=gUlYq>ZDVQ+ z$;RD%)M^pkOzje0ChI)wd-v|v9yheDnemLlak3+|{mW0b+)UxSDt=e}?DC$rPTzkF z_Kl;@YmdKm@GSj3skTq#4I?9nP>ntcT^PM)(t@0xLhn0sd+%J?tWVQzkGUg;cx1hn a*iSUAU5SRP-R4)J`urv~9N-Adk^cgSWrJG) literal 0 HcmV?d00001 diff --git a/app/src/assets/gltf-glb/arrow_red.glb b/app/src/assets/gltf-glb/arrow_red.glb new file mode 100644 index 0000000000000000000000000000000000000000..02bfea4e3c8da0dde04aa66041f4817b7849bf37 GIT binary patch literal 4580 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 [ - { name: "forward", keys: ["ArrowUp", "w", "W"] }, - { name: "backward", keys: ["ArrowDown", "s", "S"] }, - { name: "left", keys: ["ArrowLeft", "a", "A"] }, - { name: "right", keys: ["ArrowRight", "d", "D"] },], - []); + const map = useMemo( + () => [ + { name: "forward", keys: ["ArrowUp", "w", "W"] }, + { name: "backward", keys: ["ArrowDown", "s", "S"] }, + { name: "left", keys: ["ArrowLeft", "a", "A"] }, + { name: "right", keys: ["ArrowRight", "d", "D"] }, + ], + [] + ); - return ( - - { e.preventDefault(); }}> + return ( + + { + e.preventDefault(); + }} + > + - + - + - + - - - - - - - ); + + + + ); } diff --git a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx index bc2f4db..e503419 100644 --- a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx +++ b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx @@ -1,173 +1,237 @@ -import React, { useEffect, useRef, useState } from 'react'; -import * as THREE from 'three'; -import { useEventsStore } from '../../../../../store/simulation/useEventsStore'; -import useModuleStore from '../../../../../store/useModuleStore'; -import { TransformControls } from '@react-three/drei'; -import { detectModifierKeys } from '../../../../../utils/shortcutkeys/detectModifierKeys'; -import { useSelectedEventSphere, useSelectedEventData } from '../../../../../store/simulation/useSimulationStore'; +import React, { useEffect, useRef, useState } from "react"; +import * as THREE from "three"; +import { useEventsStore } from "../../../../../store/simulation/useEventsStore"; +import useModuleStore from "../../../../../store/useModuleStore"; +import { TransformControls } from "@react-three/drei"; +import { detectModifierKeys } from "../../../../../utils/shortcutkeys/detectModifierKeys"; +import { + useSelectedEventSphere, + useSelectedEventData, +} from "../../../../../store/simulation/useSimulationStore"; function PointsCreator() { - const { events, updatePoint, getPointByUuid, getEventByModelUuid } = useEventsStore(); - const { activeModule } = useModuleStore(); - const transformRef = useRef(null); - const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null); - const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({}); - const { selectedEventSphere, setSelectedEventSphere, clearSelectedEventSphere } = useSelectedEventSphere(); - const { setSelectedEventData, clearSelectedEventData } = useSelectedEventData(); + const { events, updatePoint, getPointByUuid, getEventByModelUuid } = + useEventsStore(); + const { activeModule } = useModuleStore(); + const transformRef = useRef(null); + const [transformMode, setTransformMode] = useState< + "translate" | "rotate" | null + >(null); + const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({}); + const { + selectedEventSphere, + setSelectedEventSphere, + clearSelectedEventSphere, + } = useSelectedEventSphere(); + const { setSelectedEventData, clearSelectedEventData } = + useSelectedEventData(); - useEffect(() => { - if (selectedEventSphere) { - const eventData = getEventByModelUuid(selectedEventSphere.userData.modelUuid); - if (eventData) { - setSelectedEventData( - eventData, - selectedEventSphere.userData.pointUuid - ); - } else { - clearSelectedEventData(); - } - } else { - clearSelectedEventData(); - } - }, [selectedEventSphere]); - - useEffect(() => { - const handleKeyDown = (e: KeyboardEvent) => { - const keyCombination = detectModifierKeys(e); - if (!selectedEventSphere) return; - if (keyCombination === "G") { - setTransformMode((prev) => (prev === "translate" ? null : "translate")); - } - if (keyCombination === "R") { - setTransformMode((prev) => (prev === "rotate" ? null : "rotate")); - } - }; - - window.addEventListener("keydown", handleKeyDown); - return () => window.removeEventListener("keydown", handleKeyDown); - }, [selectedEventSphere]); - - const updatePointToState = (selectedEventSphere: THREE.Mesh) => { - let point = JSON.parse(JSON.stringify(getPointByUuid(selectedEventSphere.userData.modelUuid, selectedEventSphere.userData.pointUuid))); - if (point) { - point.position = [selectedEventSphere.position.x, selectedEventSphere.position.y, selectedEventSphere.position.z]; - updatePoint(selectedEventSphere.userData.modelUuid, selectedEventSphere.userData.pointUuid, point) - } + useEffect(() => { + if (selectedEventSphere) { + const eventData = getEventByModelUuid( + selectedEventSphere.userData.modelUuid + ); + if (eventData) { + setSelectedEventData(eventData, selectedEventSphere.userData.pointUuid); + } else { + clearSelectedEventData(); + } + } else { + clearSelectedEventData(); } + }, [selectedEventSphere]); - return ( - <> - {activeModule === 'simulation' && - <> - - {events.map((event, i) => { - if (event.type === 'transfer') { - return ( - - {event.points.map((point, j) => ( - (sphereRefs.current[point.uuid] = el!)} - onClick={(e) => { - e.stopPropagation(); - setSelectedEventSphere(sphereRefs.current[point.uuid]); - }} - onPointerMissed={() => { - clearSelectedEventSphere(); - setTransformMode(null); - }} - key={`${i}-${j}`} - position={new THREE.Vector3(...point.position)} - userData={{ modelUuid: event.modelUuid, pointUuid: point.uuid }} - > - - - - ))} - - ); - } else if (event.type === 'vehicle') { - return ( - - (sphereRefs.current[event.point.uuid] = el!)} - onClick={(e) => { - e.stopPropagation(); - setSelectedEventSphere(sphereRefs.current[event.point.uuid]); - }} - onPointerMissed={() => { - clearSelectedEventSphere(); - setTransformMode(null); - }} - position={new THREE.Vector3(...event.point.position)} - userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }} - > - - - - - ); - } else if (event.type === 'roboticArm') { - return ( - - (sphereRefs.current[event.point.uuid] = el!)} - onClick={(e) => { - e.stopPropagation(); - setSelectedEventSphere(sphereRefs.current[event.point.uuid]); - }} - onPointerMissed={() => { - clearSelectedEventSphere(); - setTransformMode(null); - }} - position={new THREE.Vector3(...event.point.position)} - userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }} - > - - - - - ); - } else if (event.type === 'machine') { - return ( - - (sphereRefs.current[event.point.uuid] = el!)} - onClick={(e) => { - e.stopPropagation(); - setSelectedEventSphere(sphereRefs.current[event.point.uuid]); - }} - onPointerMissed={() => { - clearSelectedEventSphere(); - setTransformMode(null); - }} - position={new THREE.Vector3(...event.point.position)} - userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }} - > - - - - - ); - } else { - return null; - } - })} - - {(selectedEventSphere && transformMode) && - { updatePointToState(selectedEventSphere) }} /> - } - - } - + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + const keyCombination = detectModifierKeys(e); + if (!selectedEventSphere) return; + if (keyCombination === "G") { + setTransformMode((prev) => (prev === "translate" ? null : "translate")); + } + if (keyCombination === "R") { + setTransformMode((prev) => (prev === "rotate" ? null : "rotate")); + } + }; + + window.addEventListener("keydown", handleKeyDown); + return () => window.removeEventListener("keydown", handleKeyDown); + }, [selectedEventSphere]); + + const updatePointToState = (selectedEventSphere: THREE.Mesh) => { + let point = JSON.parse( + JSON.stringify( + getPointByUuid( + selectedEventSphere.userData.modelUuid, + selectedEventSphere.userData.pointUuid + ) + ) ); + if (point) { + point.position = [ + selectedEventSphere.position.x, + selectedEventSphere.position.y, + selectedEventSphere.position.z, + ]; + updatePoint( + selectedEventSphere.userData.modelUuid, + selectedEventSphere.userData.pointUuid, + point + ); + } + }; + + return ( + <> + {activeModule === "simulation" && ( + <> + + {events.map((event, i) => { + if (event.type === "transfer") { + return ( + + {event.points.map((point, j) => ( + (sphereRefs.current[point.uuid] = el!)} + onClick={(e) => { + e.stopPropagation(); + setSelectedEventSphere( + sphereRefs.current[point.uuid] + ); + }} + onPointerMissed={() => { + // clearSelectedEventSphere(); + setTransformMode(null); + }} + key={`${i}-${j}`} + position={new THREE.Vector3(...point.position)} + userData={{ + modelUuid: event.modelUuid, + pointUuid: point.uuid, + }} + > + + + + ))} + + ); + } else if (event.type === "vehicle") { + return ( + + (sphereRefs.current[event.point.uuid] = el!)} + onClick={(e) => { + e.stopPropagation(); + setSelectedEventSphere( + sphereRefs.current[event.point.uuid] + ); + }} + onPointerMissed={() => { + // clearSelectedEventSphere(); + setTransformMode(null); + }} + position={new THREE.Vector3(...event.point.position)} + userData={{ + modelUuid: event.modelUuid, + pointUuid: event.point.uuid, + }} + > + + + + + ); + } else if (event.type === "roboticArm") { + return ( + + (sphereRefs.current[event.point.uuid] = el!)} + onClick={(e) => { + e.stopPropagation(); + setSelectedEventSphere( + sphereRefs.current[event.point.uuid] + ); + }} + onPointerMissed={() => { + // clearSelectedEventSphere(); + setTransformMode(null); + }} + position={new THREE.Vector3(...event.point.position)} + userData={{ + modelUuid: event.modelUuid, + pointUuid: event.point.uuid, + }} + > + + + + + ); + } else if (event.type === "machine") { + return ( + + (sphereRefs.current[event.point.uuid] = el!)} + onClick={(e) => { + e.stopPropagation(); + setSelectedEventSphere( + sphereRefs.current[event.point.uuid] + ); + }} + onPointerMissed={() => { + // clearSelectedEventSphere(); + setTransformMode(null); + }} + position={new THREE.Vector3(...event.point.position)} + userData={{ + modelUuid: event.modelUuid, + pointUuid: event.point.uuid, + }} + > + + + + + ); + } else { + return null; + } + })} + + {selectedEventSphere && transformMode && ( + { + updatePointToState(selectedEventSphere); + }} + /> + )} + + )} + + ); } export default PointsCreator; diff --git a/app/src/modules/simulation/ui/vehicle/useDraggableGLTF.ts b/app/src/modules/simulation/ui/vehicle/useDraggableGLTF.ts new file mode 100644 index 0000000..b7e9272 --- /dev/null +++ b/app/src/modules/simulation/ui/vehicle/useDraggableGLTF.ts @@ -0,0 +1,131 @@ +import { useRef } from "react"; +import * as THREE from "three"; +import { ThreeEvent, useThree } from "@react-three/fiber"; + +type OnUpdateCallback = (object: THREE.Object3D) => void; + +export default function useDraggableGLTF(onUpdate: OnUpdateCallback) { + const { camera, gl, controls, scene } = useThree(); + const activeObjRef = useRef(null); + const planeRef = useRef( + new THREE.Plane(new THREE.Vector3(0, 1, 0), 0) + ); + const offsetRef = useRef(new THREE.Vector3()); + const initialPositionRef = useRef(new THREE.Vector3()); + + const raycaster = new THREE.Raycaster(); + const pointer = new THREE.Vector2(); + + const handlePointerDown = (e: ThreeEvent) => { + e.stopPropagation(); + + let obj: THREE.Object3D | null = e.object; + + // Traverse up until we find modelUuid in userData + while (obj && !obj.userData?.modelUuid) { + obj = obj.parent; + } + + if (!obj) return; + + // Disable orbit controls while dragging + if (controls) (controls as any).enabled = false; + + activeObjRef.current = obj; + initialPositionRef.current.copy(obj.position); + + // Get world position + const objectWorldPos = new THREE.Vector3(); + obj.getWorldPosition(objectWorldPos); + + // Set plane at the object's Y level + planeRef.current.set(new THREE.Vector3(0, 1, 0), -objectWorldPos.y); + + // Convert pointer to NDC + const rect = gl.domElement.getBoundingClientRect(); + pointer.x = ((e.clientX - rect.left) / rect.width) * 2 - 1; + pointer.y = -((e.clientY - rect.top) / rect.height) * 2 + 1; + + // Raycast to intersection + raycaster.setFromCamera(pointer, camera); + const intersection = new THREE.Vector3(); + raycaster.ray.intersectPlane(planeRef.current, intersection); + + // Calculate offset + offsetRef.current.copy(objectWorldPos).sub(intersection); + + // Start listening for drag + gl.domElement.addEventListener("pointermove", handlePointerMove); + gl.domElement.addEventListener("pointerup", handlePointerUp); + }; + + const handlePointerMove = (e: PointerEvent) => { + if (!activeObjRef.current) return; + + // Check if Shift key is pressed + const isShiftKeyPressed = e.shiftKey; + + // Get the mouse position relative to the canvas + const rect = gl.domElement.getBoundingClientRect(); + pointer.x = ((e.clientX - rect.left) / rect.width) * 2 - 1; + pointer.y = -((e.clientY - rect.top) / rect.height) * 2 + 1; + + // Update raycaster to point to the mouse position + raycaster.setFromCamera(pointer, camera); + + // Create a vector to store intersection point + const intersection = new THREE.Vector3(); + const intersects = raycaster.ray.intersectPlane(planeRef.current, intersection); + if (!intersects) return; + + // Add offset for dragging + intersection.add(offsetRef.current); + console.log('intersection: ', intersection); + + // Get the parent's world matrix if exists + const parent = activeObjRef.current.parent; + const targetPosition = new THREE.Vector3(); + + if (isShiftKeyPressed) { + console.log('isShiftKeyPressed: ', isShiftKeyPressed); + // For Y-axis only movement, maintain original X and Z + console.log('initialPositionRef: ', initialPositionRef); + console.log('intersection.y: ', intersection); + targetPosition.set( + initialPositionRef.current.x, + intersection.y, + initialPositionRef.current.z + ); + } else { + // For free movement + targetPosition.copy(intersection); + } + + // Convert world position to local if object is nested inside a parent + if (parent) { + parent.worldToLocal(targetPosition); + } + + // Update object position + activeObjRef.current.position.copy(targetPosition); + }; + + const handlePointerUp = () => { + if (controls) (controls as any).enabled = true; + + if (activeObjRef.current) { + // Pass the updated position to the onUpdate callback to persist it + onUpdate(activeObjRef.current); + } + + gl.domElement.removeEventListener("pointermove", handlePointerMove); + gl.domElement.removeEventListener("pointerup", handlePointerUp); + + activeObjRef.current = null; + }; + + return { handlePointerDown }; +} + + + diff --git a/app/src/modules/simulation/ui/vehicle/vehicleUI.tsx b/app/src/modules/simulation/ui/vehicle/vehicleUI.tsx new file mode 100644 index 0000000..f927c33 --- /dev/null +++ b/app/src/modules/simulation/ui/vehicle/vehicleUI.tsx @@ -0,0 +1,283 @@ +import React, { useRef, useEffect, useState } from "react"; +import startPoint from "../../../../assets/gltf-glb/arrow_green.glb"; +import startEnd from "../../../../assets/gltf-glb/arrow_red.glb"; +import { useGLTF } from "@react-three/drei"; +import { useSelectedEventSphere } from "../../../../store/simulation/useSimulationStore"; +import * as THREE from "three"; +import { useThree } from "@react-three/fiber"; + +type VehicleUIProps = { + vehicleStatusSample: VehicleEventSchema[]; + setVehicleStatusSample: React.Dispatch< + React.SetStateAction + >; +}; + +const VehicleUI: React.FC = ({ + vehicleStatusSample, + setVehicleStatusSample, +}) => { + const { scene: startScene } = useGLTF(startPoint) as any; + const { scene: endScene } = useGLTF(startEnd) as any; + const { camera, gl, controls } = useThree(); + const { selectedEventSphere } = useSelectedEventSphere(); + + const startMarker = useRef(null); + const endMarker = useRef(null); + const hasInitialized = useRef(false); + + const [draggedMarker, setDraggedMarker] = useState<"start" | "end" | null>( + null + ); + const [dragOffset, setDragOffset] = useState(null); + const [isRotating, setIsRotating] = useState(false); + + const raycaster = useRef(new THREE.Raycaster()); + const plane = useRef(new THREE.Plane(new THREE.Vector3(0, 1, 0), 0)); // Y = 0 plane + const mouse = useRef(new THREE.Vector2()); + const prevMousePos = useRef({ x: 0, y: 0 }); + + // Initialize start/end markers + useEffect(() => { + if ( + selectedEventSphere && + startMarker.current && + endMarker.current && + !hasInitialized.current + ) { + startMarker.current.clear(); + endMarker.current.clear(); + + const startClone = startScene.clone(); + const endClone = endScene.clone(); + + startClone.name = "start-marker"; + endClone.name = "end-marker"; + + startClone.traverse((child: any) => { + if (child.isMesh && child.name.toLowerCase().includes("handle")) { + child.name = "handle"; + } + }); + endClone.traverse((child: any) => { + if (child.isMesh && child.name.toLowerCase().includes("handle")) { + child.name = "handle"; + } + }); + + startMarker.current.add(startClone); + endMarker.current.add(endClone); + + hasInitialized.current = true; + } + }, [selectedEventSphere, startScene, endScene]); + + // Position start/end markers + useEffect(() => { + if (!selectedEventSphere || !startMarker.current || !endMarker.current) + return; + + const selectedVehicle = vehicleStatusSample.find( + (vehicle) => vehicle.modelUuid === selectedEventSphere.userData.modelUuid + ); + + if (selectedVehicle?.point?.action) { + const { pickUpPoint, unLoadPoint } = selectedVehicle.point.action; + + // Update start marker position + if (pickUpPoint) { + const localPos = new THREE.Vector3( + pickUpPoint.x, + pickUpPoint.y, + pickUpPoint.z + ); + const worldPos = selectedEventSphere.localToWorld(localPos); + worldPos.y = 0; // Force y to 0 + startMarker.current.position.copy(worldPos); + } else { + const defaultLocal = new THREE.Vector3(0, 0, 1.5); + const defaultWorld = selectedEventSphere.localToWorld(defaultLocal); + defaultWorld.y = 0; // Force y to 0 + startMarker.current.position.copy(defaultWorld); + } + + // Update end marker position + if (unLoadPoint) { + const localPos = new THREE.Vector3( + unLoadPoint.x, + unLoadPoint.y, + unLoadPoint.z + ); + const worldPos = selectedEventSphere.localToWorld(localPos); + worldPos.y = 0; // Force y to 0 + endMarker.current.position.copy(worldPos); + } else { + const defaultLocal = new THREE.Vector3(0, 0, -1.5); + const defaultWorld = selectedEventSphere.localToWorld(defaultLocal); + defaultWorld.y = 0; // Force y to 0 + endMarker.current.position.copy(defaultWorld); + } + } + }, [selectedEventSphere, vehicleStatusSample]); + + // Handle dragging and rotation + const handlePointerDown = (e: any, markerType: "start" | "end") => { + if (!selectedEventSphere) return; + + if (e.object.name === "handle") { + setIsRotating(true); + prevMousePos.current = { x: e.clientX, y: e.clientY }; + if (controls) (controls as any).enabled = false; + e.stopPropagation(); + setDraggedMarker(markerType); + return; + } + + setDraggedMarker(markerType); + if (controls) (controls as any).enabled = false; + + const marker = + markerType === "start" ? startMarker.current : endMarker.current; + if (!marker) return; + + mouse.current.x = (e.clientX / gl.domElement.clientWidth) * 2 - 1; + mouse.current.y = -(e.clientY / gl.domElement.clientHeight) * 2 + 1; + + raycaster.current.setFromCamera(mouse.current, camera); + + const intersectPoint = new THREE.Vector3(); + raycaster.current.ray.intersectPlane(plane.current, intersectPoint); + + const offset = new THREE.Vector3().subVectors( + marker.position, + intersectPoint + ); + setDragOffset(offset); + }; + + const handlePointerMove = (e: PointerEvent) => { + if (!selectedEventSphere) return; + + if (isRotating) { + const deltaX = e.clientX - prevMousePos.current.x; + prevMousePos.current = { x: e.clientX, y: e.clientY }; + + const rotationSpeed = 0.01; + const marker = + draggedMarker === "start" ? startMarker.current : endMarker.current; + + if (marker) { + marker.rotation.y -= deltaX * rotationSpeed; + } + return; + } + + if (!draggedMarker || !dragOffset) return; + + mouse.current.x = (e.clientX / gl.domElement.clientWidth) * 2 - 1; + mouse.current.y = -(e.clientY / gl.domElement.clientHeight) * 2 + 1; + + raycaster.current.setFromCamera(mouse.current, camera); + + const intersectPoint = new THREE.Vector3(); + raycaster.current.ray.intersectPlane(plane.current, intersectPoint); + + if (!intersectPoint) return; + + const newPos = { + x: intersectPoint.x + dragOffset.x, + y: 0, + z: intersectPoint.z + dragOffset.z, + }; + + if (draggedMarker === "start" && startMarker.current) { + startMarker.current.position.set(newPos.x, newPos.y, newPos.z); + } else if (draggedMarker === "end" && endMarker.current) { + endMarker.current.position.set(newPos.x, newPos.y, newPos.z); + } + }; + + const handlePointerUp = () => { + if (isRotating) { + setIsRotating(false); + if (controls) (controls as any).enabled = true; + return; + } + + if (!selectedEventSphere || !draggedMarker || !dragOffset) { + if (controls) (controls as any).enabled = true; + return; + } + + if (controls) (controls as any).enabled = true; + + const marker = + draggedMarker === "start" ? startMarker.current : endMarker.current; + if (!marker) return; + + const worldPos = marker.position.clone(); + const localPos = selectedEventSphere.worldToLocal(worldPos); + + // Direct update (no snapping, ground level forced at y = 0) + const updatedLocalPos = { x: localPos.x, y: 0, z: localPos.z }; + + setVehicleStatusSample((prev) => + prev.map((vehicle) => { + if ( + vehicle.modelUuid === selectedEventSphere.userData.modelUuid && + selectedEventSphere + ) { + const updatedVehicle = { + ...vehicle, + point: { + ...vehicle.point, + action: { + ...vehicle.point?.action, + ...(draggedMarker === "start" + ? { pickUpPoint: updatedLocalPos } + : { unLoadPoint: updatedLocalPos }), + }, + }, + }; + return updatedVehicle; + } + return vehicle; + }) + ); + + setDraggedMarker(null); + setDragOffset(null); + }; + + useEffect(() => { + window.addEventListener("pointermove", handlePointerMove); + window.addEventListener("pointerup", handlePointerUp); + + return () => { + window.removeEventListener("pointermove", handlePointerMove); + window.removeEventListener("pointerup", handlePointerUp); + }; + }, [draggedMarker, dragOffset, isRotating]); + + if (!selectedEventSphere) { + hasInitialized.current = false; + return null; + } + + return ( + + handlePointerDown(e, "start")} + /> + handlePointerDown(e, "end")} + /> + + ); +}; + +export default VehicleUI; diff --git a/app/src/modules/simulation/vehicle/vehicles.tsx b/app/src/modules/simulation/vehicle/vehicles.tsx index f0b4d17..65376f2 100644 --- a/app/src/modules/simulation/vehicle/vehicles.tsx +++ b/app/src/modules/simulation/vehicle/vehicles.tsx @@ -1,162 +1,140 @@ -import React, { useEffect } from 'react' -import VehicleInstances from './instances/vehicleInstances'; -import { useVehicleStore } from '../../../store/simulation/useVehicleStore'; -import { useFloorItems } from '../../../store/store'; - +import React, { useEffect, useState } from "react"; +import VehicleInstances from "./instances/vehicleInstances"; +import { useVehicleStore } from "../../../store/simulation/useVehicleStore"; +import { useFloorItems } from "../../../store/store"; +import { useSelectedEventSphere } from "../../../store/simulation/useSimulationStore"; +import VehicleUI from "../ui/vehicle/vehicleUI"; function Vehicles() { + const { vehicles, addVehicle } = useVehicleStore(); + const { selectedEventSphere } = useSelectedEventSphere(); - const { vehicles, addVehicle } = useVehicleStore(); + const { floorItems } = useFloorItems(); - const { floorItems } = useFloorItems(); - - const vehicleStatusSample: VehicleEventSchema[] = [ - { - modelUuid: "9356f710-4727-4b50-bdb2-9c1e747ecc74", - modelName: "AGV", - position: [97.9252965204558, 0, 37.96138815638661], - rotation: [0, 0, 0], - state: "idle", - type: "vehicle", - speed: 2.5, - point: { - uuid: "point-789", - position: [0, 1, 0], - rotation: [0, 0, 0], - action: { - actionUuid: "action-456", - actionName: "Deliver to Zone A", - actionType: "travel", - unLoadDuration: 10, - loadCapacity: 2, - pickUpPoint: { x: 98.71483985219794, y: 0, z: 28.66321267938962 }, - unLoadPoint: { x: 105.71483985219794, y: 0, z: 28.66321267938962 }, - triggers: [ - { - triggerUuid: "trig-001", - triggerName: "Start Travel", - triggerType: "onComplete", - delay: 0, - triggeredAsset: { - triggeredModel: { modelName: "ArmBot-X", modelUuid: "arm-001" }, - triggeredPoint: { pointName: "Pickup Arm Point", pointUuid: "arm-point-01" }, - triggeredAction: { actionName: "Grab Widget", actionUuid: "grab-001" } - } - }, - { - triggerUuid: "trig-002", - triggerName: "Complete Travel", - triggerType: "onComplete", - delay: 2, - triggeredAsset: null - } - ] - } - } + const [vehicleStatusSample, setVehicleStatusSample] = useState< + VehicleEventSchema[] + >([ + + { + modelUuid: "68f8dc55-7802-47fe-aa1c-eade54b4320a", + modelName: "AGV", + position: [89.61609306554463, 0, 33.634136622267356], + rotation: [0, 0, 0], + state: "idle", + type: "vehicle", + speed: 2.5, + point: { + uuid: "point-789", + position: [0, 1, 0], + rotation: [0, 0, 0], + action: { + actionUuid: "action-456", + actionName: "Deliver to Zone A", + actionType: "travel", + unLoadDuration: 10, + loadCapacity: 2, + pickUpPoint: null, + unLoadPoint: null, + triggers: [ + { + triggerUuid: "trig-001", + triggerName: "Start Travel", + triggerType: "onStart", + delay: 0, + triggeredAsset: { + triggeredModel: { modelName: "ArmBot-X", modelUuid: "arm-001" }, + triggeredPoint: { + pointName: "Pickup Arm Point", + pointUuid: "arm-point-01", + }, + triggeredAction: { + actionName: "Grab Widget", + actionUuid: "grab-001", + }, + }, + }, + { + triggerUuid: "trig-002", + triggerName: "Complete Travel", + triggerType: "onComplete", + delay: 2, + triggeredAsset: null, + }, + ], }, - { - modelUuid: "b06960bb-3d2e-41f7-a646-335f389c68b4", - modelName: "AGV", - position: [89.61609306554463, 0, 33.634136622267356], - rotation: [0, 0, 0], - state: "idle", - type: "vehicle", - speed: 2.5, - point: { - uuid: "point-789", - position: [0, 1, 0], - rotation: [0, 0, 0], - action: { - actionUuid: "action-456", - actionName: "Deliver to Zone A", - actionType: "travel", - unLoadDuration: 10, - loadCapacity: 2, - pickUpPoint: { x: 90, y: 0, z: 28 }, - unLoadPoint: { x: 20, y: 0, z: 10 }, - triggers: [ - { - triggerUuid: "trig-001", - triggerName: "Start Travel", - triggerType: "onStart", - delay: 0, - triggeredAsset: { - triggeredModel: { modelName: "ArmBot-X", modelUuid: "arm-001" }, - triggeredPoint: { pointName: "Pickup Arm Point", pointUuid: "arm-point-01" }, - triggeredAction: { actionName: "Grab Widget", actionUuid: "grab-001" } - } - }, - { - triggerUuid: "trig-002", - triggerName: "Complete Travel", - triggerType: "onComplete", - delay: 2, - triggeredAsset: null - } - ] - } - } - }, { - modelUuid: "e729a4f1-11d2-4778-8d6a-468f1b4f6b79", - modelName: "forklift", - position: [98.85729337188162, 0, 38.36616546567653], - rotation: [0, 0, 0], - state: "idle", - type: "vehicle", - speed: 2.5, - point: { - uuid: "point-789", - position: [0, 1, 0], - rotation: [0, 0, 0], - action: { - actionUuid: "action-456", - actionName: "Deliver to Zone A", - actionType: "travel", - unLoadDuration: 15, - loadCapacity: 5, - pickUpPoint: { x: 98.71483985219794, y: 0, z: 28.66321267938962 }, - unLoadPoint: { x: 20, y: 0, z: 10 }, - triggers: [ - { - triggerUuid: "trig-001", - triggerName: "Start Travel", - triggerType: "onStart", - delay: 0, - triggeredAsset: { - triggeredModel: { modelName: "ArmBot-X", modelUuid: "arm-001" }, - triggeredPoint: { pointName: "Pickup Arm Point", pointUuid: "arm-point-01" }, - triggeredAction: { actionName: "Grab Widget", actionUuid: "grab-001" } - } - }, - { - triggerUuid: "trig-002", - triggerName: "Complete Travel", - triggerType: "onComplete", - delay: 2, - triggeredAsset: null - } - ] - } - } - } - ]; + }, + }, + { + modelUuid: "3a8f6da6-da57-4ef5-91e3-b8daf89e5753", + modelName: "forklift", + position: [98.85729337188162, 0, 38.36616546567653], + rotation: [0, 0, 0], + state: "idle", + type: "vehicle", + speed: 2.5, + point: { + uuid: "point-789", + position: [0, 1, 0], + rotation: [0, 0, 0], + action: { + actionUuid: "action-456", + actionName: "Deliver to Zone A", + actionType: "travel", + unLoadDuration: 15, + loadCapacity: 5, + pickUpPoint: null, + unLoadPoint: null, + triggers: [ + { + triggerUuid: "trig-001", + triggerName: "Start Travel", + triggerType: "onStart", + delay: 0, + triggeredAsset: { + triggeredModel: { modelName: "ArmBot-X", modelUuid: "arm-001" }, + triggeredPoint: { + pointName: "Pickup Arm Point", + pointUuid: "arm-point-01", + }, + triggeredAction: { + actionName: "Grab Widget", + actionUuid: "grab-001", + }, + }, + }, + { + triggerUuid: "trig-002", + triggerName: "Complete Travel", + triggerType: "onComplete", + delay: 2, + triggeredAsset: null, + }, + ], + }, + }, + }, + ]); + // useEffect(()) + console.log("vehicleStatusSample", vehicleStatusSample); + useEffect(() => { + addVehicle("123", vehicleStatusSample[0]); + // addVehicle('123', vehicleStatusSample[1]); + // addVehicle('123', vehicleStatusSample[2]); + }, []); + useEffect(() => {}, [vehicles]); - useEffect(() => { - addVehicle('123', vehicleStatusSample[0]); - // addVehicle('123', vehicleStatusSample[1]); - // addVehicle('123', vehicleStatusSample[2]); - }, []) - - useEffect(() => { - console.log('vehicles: ', vehicles); - }, [vehicles]) - - - return ( - <> - - - ) + return ( + <> + + + + ); } -export default Vehicles; \ No newline at end of file +export default Vehicles; + + +