Merge remote-tracking branch 'origin/simulation-agv-v2' into v2

This commit is contained in:
2025-05-13 18:43:01 +05:30
12 changed files with 520 additions and 308 deletions

View File

@@ -4,13 +4,53 @@ import { computeArea } from '../functions/computeArea';
import { Html } from '@react-three/drei'; import { Html } from '@react-three/drei';
import * as CONSTANTS from "../../../types/world/worldConstants"; import * as CONSTANTS from "../../../types/world/worldConstants";
import * as turf from '@turf/turf'; import * as turf from '@turf/turf';
import * as THREE from "three"
const CalculateAreaGroup = () => { const CalculateAreaGroup = () => {
const { roomsState } = useRoomsState(); const { roomsState } = useRoomsState();
const { toggleView } = useToggleView(); const { toggleView } = useToggleView();
const savedTheme: string | null = localStorage.getItem('theme');
return ( return (
<group name="roomArea" visible={toggleView}> <group name="roomArea" visible={toggleView}>
<group name="roomFills" visible={toggleView}>
{roomsState.length > 0 &&
roomsState.flat().map((room: any, index: number) => {
const coordinates = room.coordinates;
if (!coordinates || coordinates.length < 3) return null;
const yPos = (room.layer || 0) * CONSTANTS.zoneConfig.height;
const coords2D = coordinates.map((p: any) => new THREE.Vector2(p.position.x, p.position.z));
// console.log('coords2D: ', coords2D);
if (!coords2D[0].equals(coords2D[coords2D.length - 1])) {
coords2D.push(coords2D[0]);
}
const shape = new THREE.Shape(coords2D);
const extrudeSettings = {
depth: 0.01,
bevelEnabled: false,
};
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
geometry.rotateX(Math.PI / 2);
const material = new THREE.MeshBasicMaterial({
color: savedTheme === "dark" ? "#d2baff" : '#6f42c1',
side: THREE.DoubleSide,
transparent: true,
opacity: 0.4,
depthWrite: false,
});
return (
<group key={`roomFill-${index}`}>
<mesh geometry={geometry} material={material} position={[0, yPos, 0]} />
</group>
);
})}
</group>
{roomsState.length > 0 && {roomsState.length > 0 &&
roomsState.flat().map((room: any, index: number) => { roomsState.flat().map((room: any, index: number) => {
if (!toggleView) return null; if (!toggleView) return null;

View File

@@ -376,7 +376,6 @@ const ZoneGroup: React.FC = () => {
setZonePoints(updatedZonePoints); setZonePoints(updatedZonePoints);
addZoneToBackend(newZone); addZoneToBackend(newZone);
setStartPoint(null); setStartPoint(null);
setEndPoint(null); setEndPoint(null);
} }

View File

@@ -41,8 +41,17 @@ function Ui() {
const AssetPreview: React.FC<AssetPreviewProps> = ({ const AssetPreview: React.FC<AssetPreviewProps> = ({
selectedCard, selectedCard,
setSelectedCard, setSelectedCard,
modelUrl, modelUrl
}) => { }) => {
// Ensure rating is a valid number between 0 and 5
const rating = Math.max(
0,
Math.min(5, isNaN(selectedCard.rating) ? 0 : selectedCard.rating)
);
// Ensure that the rating is a valid positive integer for array length
const starsArray = Array.from({ length: rating }, (_, index) => index);
return ( return (
<div className="assetPreview-wrapper"> <div className="assetPreview-wrapper">
<div className="assetPreview"> <div className="assetPreview">
@@ -65,7 +74,7 @@ const AssetPreview: React.FC<AssetPreviewProps> = ({
> >
<Suspense fallback={<Ui />}> <Suspense fallback={<Ui />}>
{selectedCard.assetName && modelUrl && ( {selectedCard.assetName && modelUrl && (
<GltfLoader fromServer={modelUrl} /> <GltfLoader fromServer={modelUrl} assetId={selectedCard?.AssetID} />
)} )}
<OrbitControls minPolarAngle={0} maxPolarAngle={Math.PI / 2} /> <OrbitControls minPolarAngle={0} maxPolarAngle={Math.PI / 2} />
<ContactShadows <ContactShadows

View File

@@ -16,7 +16,8 @@ interface CardProps {
views: number; views: number;
image: string; image: string;
description: string; description: string;
AssetID: string; AssetID: string
modelUrl: string
onSelectCard: (cardData: { onSelectCard: (cardData: {
assetName: string; assetName: string;
uploadedOn: number; uploadedOn: number;
@@ -36,18 +37,17 @@ const Card: React.FC<CardProps> = ({
views, views,
image, image,
description, description,
onSelectCard,
AssetID, AssetID,
modelUrl,
onSelectCard,
}) => { }) => {
const handleCardSelect = () => { const handleCardSelect = () => {
console.log('assetName: ', assetName);
console.log('AssetID: ', AssetID);
onSelectCard({ onSelectCard({
assetName, assetName, uploadedOn, price, rating, views, description, AssetID
uploadedOn,
price,
rating,
views,
description,
AssetID,
}); });
}; };

View File

@@ -66,6 +66,7 @@ const CardsContainer: React.FC<ModelsProps> = ({ models }) => {
AssetID={assetDetail.AssetID} AssetID={assetDetail.AssetID}
image={assetDetail.thumbnail} image={assetDetail.thumbnail}
description={assetDetail.description} description={assetDetail.description}
modelUrl={modelUrl}
/> />
</React.Fragment> </React.Fragment>
))} ))}

View File

@@ -10,6 +10,7 @@ interface GltfLoaderProps {
setAnimations?: (animations?: string[]) => void; setAnimations?: (animations?: string[]) => void;
selectedAnimation?: string; selectedAnimation?: string;
setSelectedAnimation?: (animation: string) => void; setSelectedAnimation?: (animation: string) => void;
assetId: string
} }
@@ -18,6 +19,7 @@ const GltfLoader: React.FC<GltfLoaderProps> = ({
fromServer, fromServer,
setAnimations, setAnimations,
selectedAnimation, selectedAnimation,
assetId
}) => { }) => {
const { scene, animations } = useGLTF(fromServer ?? "") as { const { scene, animations } = useGLTF(fromServer ?? "") as {
scene: Object3D; scene: Object3D;

View File

@@ -33,6 +33,7 @@ const MarketPlace = () => {
try { try {
const filt = await getAssetImages("67d934ad0f42a1fdadb19aa6"); const filt = await getAssetImages("67d934ad0f42a1fdadb19aa6");
setModels(filt.items); setModels(filt.items);
console.log('filt.items: ', filt.items);
setFilteredModels(filt.items); setFilteredModels(filt.items);
setisLoading(false); setisLoading(false);
} catch { } catch {

View File

@@ -1,4 +1,4 @@
import React, { useRef } from "react"; import React, { useRef, useState } from "react";
import { import {
Vector3, Vector3,
Raycaster, Raycaster,
@@ -21,6 +21,17 @@ const DistanceFindingControls = ({
object, object,
}: DistanceFindingControlsProps) => { }: DistanceFindingControlsProps) => {
const { camera, scene } = useThree(); const { camera, scene } = useThree();
const [labelValues, setLabelValues] = useState<{
textPosX: any;
textNegX: any;
textPosZ: any;
textNegZ: any;
}>({
textPosX: "",
textNegX: "",
textPosZ: "",
textNegZ: "",
});
// Refs for measurement lines // Refs for measurement lines
const line1 = useRef<Line>(null); const line1 = useRef<Line>(null);
@@ -167,13 +178,14 @@ const DistanceFindingControls = ({
} }
} }
} }
// Update line geometry
if (points[1]) { if (points[1]) {
geometry.dispose(); geometry.dispose();
geometry.setFromPoints([points[0], points[1]]); geometry.setFromPoints([points[0], points[1]]);
line.geometry = geometry; line.geometry = geometry;
// Calculate the distance only once
const distance = points[0].distanceTo(points[1]).toFixed(2);
// Update measurement text // Update measurement text
if (mesh?.current) { if (mesh?.current) {
geometry.computeBoundingSphere(); geometry.computeBoundingSphere();
@@ -181,9 +193,28 @@ const DistanceFindingControls = ({
if (center) { if (center) {
mesh.current.position.copy(center); mesh.current.position.copy(center);
} }
const label = document.getElementById(mesh.current.name); const label = document.getElementById(mesh.current.name);
if (label) { if (label) {
label.innerText = `${points[0].distanceTo(points[1]).toFixed(2)}m`; label.innerText = `${distance}m`;
// Update specific label state based on the label ID
switch (label.id) {
case "textPosX":
setLabelValues((prevState) => ({ ...prevState, textPosX: distance }));
break;
case "textNegX":
setLabelValues((prevState) => ({ ...prevState, textNegX: distance }));
break;
case "textPosZ":
setLabelValues((prevState) => ({ ...prevState, textPosZ: distance }));
break;
case "textNegZ":
setLabelValues((prevState) => ({ ...prevState, textNegZ: distance }));
break;
default:
break;
}
} }
} }
} else { } else {
@@ -191,9 +222,31 @@ const DistanceFindingControls = ({
geometry.dispose(); geometry.dispose();
geometry.setFromPoints([new Vector3(), new Vector3()]); geometry.setFromPoints([new Vector3(), new Vector3()]);
line.geometry = geometry; line.geometry = geometry;
const label = document.getElementById(mesh?.current?.name ?? ""); const label = document.getElementById(mesh?.current?.name ?? "");
if (label) label.innerText = ""; if (label) {
label.innerText = "";
// Clear the corresponding label value in the state
switch (label.id) {
case "textPosX":
setLabelValues((prevState) => ({ ...prevState, textPosX: "" }));
break;
case "textNegX":
setLabelValues((prevState) => ({ ...prevState, textNegX: "" }));
break;
case "textPosZ":
setLabelValues((prevState) => ({ ...prevState, textPosZ: "" }));
break;
case "textNegZ":
setLabelValues((prevState) => ({ ...prevState, textNegZ: "" }));
break;
default:
break;
} }
}
}
}; };
const Material = new LineBasicMaterial({ color: "#d2baff" }); const Material = new LineBasicMaterial({ color: "#d2baff" });
@@ -208,39 +261,54 @@ const DistanceFindingControls = ({
wrapperClass="distance-text-wrapper" wrapperClass="distance-text-wrapper"
className="distance-text" className="distance-text"
zIndexRange={[1, 0]} zIndexRange={[1, 0]}
style={{ pointerEvents: "none" }} style={{
pointerEvents: "none",
visibility: labelValues.textPosX === "" ? "hidden" : "visible",
}}
> >
<div className="distance-label" id="textPosX"></div> <div className="distance-label" id="textPosX">{labelValues.textPosX}</div>
</Html> </Html>
</group> </group>
<group name="textNegX" ref={textNegX}> <group name="textNegX" ref={textNegX}>
<Html <Html
wrapperClass="distance-text-wrapper" wrapperClass="distance-text-wrapper"
className="distance-text" className="distance-text"
zIndexRange={[1, 0]} zIndexRange={[1, 0]}
style={{ pointerEvents: "none" }} style={{
pointerEvents: "none",
visibility: labelValues.textNegX === "" ? "hidden" : "visible",
}}
> >
<div className="distance-label" id="textNegX"></div> <div className="distance-label" id="textNegX">{labelValues.textNegX}</div>
</Html> </Html>
</group> </group>
<group name="textPosZ" ref={textPosZ}> <group name="textPosZ" ref={textPosZ}>
<Html <Html
wrapperClass="distance-text-wrapper" wrapperClass="distance-text-wrapper"
className="distance-text" className="distance-text"
zIndexRange={[2, 0]} zIndexRange={[2, 0]}
style={{ pointerEvents: "none" }} style={{
pointerEvents: "none",
visibility: labelValues.textPosZ === "" ? "hidden" : "visible",
}}
> >
<div className="distance-label" id="textPosZ"></div> <div className="distance-label" id="textPosZ">{labelValues.textPosZ}</div>
</Html> </Html>
</group> </group>
<group name="textNegZ" ref={textNegZ}> <group name="textNegZ" ref={textNegZ}>
<Html <Html
wrapperClass="distance-text-wrapper" wrapperClass="distance-text-wrapper"
className="distance-text" className="distance-text"
zIndexRange={[1, 0]} zIndexRange={[1, 0]}
style={{ pointerEvents: "none" }} style={{
pointerEvents: "none",
visibility: labelValues.textNegZ === "" ? "hidden" : "visible",
}}
> >
<div className="distance-label" id="textNegZ"></div> <div className="distance-label" id="textNegZ">{labelValues.textNegZ}</div>
</Html> </Html>
</group> </group>
@@ -262,7 +330,8 @@ const DistanceFindingControls = ({
ref={line4} ref={line4}
/> />
</> </>
)} )
}
</> </>
); );
}; };

View File

@@ -64,7 +64,91 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
} }
}, [isReset, isPlaying]) }, [isReset, isPlaying])
useFrame((_, delta) => { // useFrame((_, delta) => {
// const object = scene.getObjectByProperty('uuid', agvUuid);
// if (!object || currentPath.length < 2) return;
// if (isPaused) return;
// let totalDistance = 0;
// const distances = [];
// let accumulatedDistance = 0;
// let index = 0;
// const rotationSpeed = 1;
// for (let i = 0; i < currentPath.length - 1; i++) {
// const start = new THREE.Vector3(...currentPath[i]);
// const end = new THREE.Vector3(...currentPath[i + 1]);
// const segmentDistance = start.distanceTo(end);
// distances.push(segmentDistance);
// totalDistance += segmentDistance;
// }
// while (index < distances.length && progressRef.current > accumulatedDistance + distances[index]) {
// accumulatedDistance += distances[index];
// index++;
// }
// if (index < distances.length) {
// const start = new THREE.Vector3(...currentPath[index]);
// const end = new THREE.Vector3(...currentPath[index + 1]);
// const segmentDistance = distances[index];
// const currentDirection = new THREE.Vector3().subVectors(end, start).normalize();
// const targetAngle = Math.atan2(currentDirection.x, currentDirection.z);
// const currentAngle = object.rotation.y;
// let angleDifference = targetAngle - currentAngle;
// if (angleDifference > Math.PI) angleDifference -= 2 * Math.PI;
// if (angleDifference < -Math.PI) angleDifference += 2 * Math.PI;
// const maxRotationStep = (rotationSpeed * speed * agvDetail.speed) * delta;
// object.rotation.y += Math.sign(angleDifference) * Math.min(Math.abs(angleDifference), maxRotationStep);
// const isAligned = Math.abs(angleDifference) < 0.01;
// if (isAligned) {
// progressRef.current += delta * (speed * agvDetail.speed);
// const t = (progressRef.current - accumulatedDistance) / segmentDistance;
// const position = start.clone().lerp(end, t);
// object.position.copy(position);
// }
// }
// if (progressRef.current >= totalDistance) {
// if (restRotation && objectRotation) {
// const targetEuler = new THREE.Euler(
// objectRotation.x,
// objectRotation.y - (agvDetail.point.action.steeringAngle),
// objectRotation.z
// );
// const targetQuaternion = new THREE.Quaternion().setFromEuler(targetEuler);
// object.quaternion.slerp(targetQuaternion, delta * (rotationSpeed * speed * agvDetail.speed));
// if (object.quaternion.angleTo(targetQuaternion) < 0.01) {
// object.quaternion.copy(targetQuaternion);
// object.rotation.copy(targetEuler);
// setRestingRotation(false);
// }
// return;
// }
// }
// if (progressRef.current >= totalDistance) {
// setRestingRotation(true);
// progressRef.current = 0;
// movingForward.current = !movingForward.current;
// setCurrentPath([]);
// handleCallBack();
// if (currentPhase === 'pickup-drop') {
// requestAnimationFrame(startUnloadingProcess);
// }
// }
// });
const lastTimeRef = useRef(performance.now());
useFrame(() => {
const now = performance.now();
const delta = (now - lastTimeRef.current) / 1000;
lastTimeRef.current = now;
const object = scene.getObjectByProperty('uuid', agvUuid); const object = scene.getObjectByProperty('uuid', agvUuid);
if (!object || currentPath.length < 2) return; if (!object || currentPath.length < 2) return;
if (isPaused) return; if (isPaused) return;
@@ -95,7 +179,6 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
const currentDirection = new THREE.Vector3().subVectors(end, start).normalize(); const currentDirection = new THREE.Vector3().subVectors(end, start).normalize();
const targetAngle = Math.atan2(currentDirection.x, currentDirection.z); const targetAngle = Math.atan2(currentDirection.x, currentDirection.z);
const currentAngle = object.rotation.y; const currentAngle = object.rotation.y;
let angleDifference = targetAngle - currentAngle; let angleDifference = targetAngle - currentAngle;
@@ -118,7 +201,7 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
if (restRotation && objectRotation) { if (restRotation && objectRotation) {
const targetEuler = new THREE.Euler( const targetEuler = new THREE.Euler(
objectRotation.x, objectRotation.x,
objectRotation.y - (agvDetail.point.action.steeringAngle), objectRotation.y - agvDetail.point.action.steeringAngle,
objectRotation.z objectRotation.z
); );
const targetQuaternion = new THREE.Quaternion().setFromEuler(targetEuler); const targetQuaternion = new THREE.Quaternion().setFromEuler(targetEuler);
@@ -131,6 +214,7 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
return; return;
} }
} }
if (progressRef.current >= totalDistance) { if (progressRef.current >= totalDistance) {
setRestingRotation(true); setRestingRotation(true);
progressRef.current = 0; progressRef.current = 0;

View File

@@ -11,7 +11,10 @@ import { useProductStore } from '../../../../../store/simulation/useProductStore
import { useSelectedProduct } from '../../../../../store/simulation/useSimulationStore'; import { useSelectedProduct } from '../../../../../store/simulation/useSimulationStore';
import { useTriggerHandler } from '../../../triggers/triggerHandler/useTriggerHandler'; import { useTriggerHandler } from '../../../triggers/triggerHandler/useTriggerHandler';
import MaterialAnimator from '../animator/materialAnimator'; import MaterialAnimator from '../animator/materialAnimator';
type Timer = {
start: number | null;
active: boolean;
};
function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>) { function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>) {
const { navMesh } = useNavMesh(); const { navMesh } = useNavMesh();
const { isPlaying } = usePlayButtonStore(); const { isPlaying } = usePlayButtonStore();
@@ -51,7 +54,7 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
); );
function vehicleStatus(modelId: string, status: string) { function vehicleStatus(modelId: string, status: string) {
// console.log(`${modelId} , ${status}`); //
} }
// Function to reset everything // Function to reset everything
@@ -144,6 +147,9 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
} }
} }
function startUnloadingProcess() { function startUnloadingProcess() {
if (agvDetail.point.action.triggers.length > 0) { if (agvDetail.point.action.triggers.length > 0) {
const trigger = getTriggerByUuid(selectedProduct.productId, agvDetail.point.action.triggers[0].triggerUuid); const trigger = getTriggerByUuid(selectedProduct.productId, agvDetail.point.action.triggers[0].triggerUuid);

View File

@@ -1,5 +1,6 @@
let BackEnd_url = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; let BackEnd_url = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
export const getAssetDetails = async (filename: string) => { export const getAssetDetails = async (filename: string) => {
console.log('filename: ', filename);
try { try {
const response = await fetch(`${BackEnd_url}/api/v1/assetDetails`, { const response = await fetch(`${BackEnd_url}/api/v1/assetDetails`, {
method: "POST", method: "POST",