-
-
+
+
+
+
+
+ {count?.toString()}/{totalCapacity}
+
+
+ {/* progress ui */}
+
+
+ {[...Array(5)].map((_, i) => {
+ const percentage = (count! / totalCapacity) * 100;
+ const start = i * 20;
+ const end = (i + 1) * 20;
+ // fill amount: 0 to 100
+ let fillPercent = 0;
+ if (percentage >= end) {
+ fillPercent = 100;
+ } else if (percentage <= start) {
+ fillPercent = 1;
+ } else {
+ fillPercent = ((percentage - start) / 20) * 100;
+ }
+ return (
+
+ );
+ })}
+
+
+ {Math.round((count! / totalCapacity) * 100).toString()}%
+
-
{count?.toString()}
)}
diff --git a/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts b/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts
index aa58646..e625116 100644
--- a/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts
+++ b/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts
@@ -204,7 +204,7 @@ function processLoadedModel(
actionName: "Action 1",
actionType: "travel",
unLoadDuration: 5,
- loadCapacity: 10,
+ loadCapacity: 1,
steeringAngle: 0,
pickUpPoint: null,
unLoadPoint: null,
@@ -290,7 +290,27 @@ function processLoadedModel(
}
};
addEvent(roboticArmEvent);
-
+ } else if (item.eventData.type === 'Storage') {
+ const storageEvent: StorageEventSchema = {
+ modelUuid: item.modelUuid,
+ modelName: item.modelName,
+ position: item.position,
+ rotation: [item.rotation.x, item.rotation.y, item.rotation.z], state: "idle",
+ type: "storageUnit",
+ point: {
+ uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(),
+ position: [item.eventData.point?.position[0] || 0, item.eventData.point?.position[1] || 0, item.eventData.point?.position[2] || 0],
+ rotation: [item.eventData.point?.rotation[0] || 0, item.eventData.point?.rotation[1] || 0, item.eventData.point?.rotation[2] || 0],
+ action: {
+ actionUuid: THREE.MathUtils.generateUUID(),
+ actionName: "Action 1",
+ actionType: "store",
+ storageCapacity: 10,
+ triggers: []
+ }
+ }
+ };
+ addEvent(storageEvent);
}
} else {
setFloorItems((prevItems) => [
diff --git a/app/src/modules/builder/builder.tsx b/app/src/modules/builder/builder.tsx
index fdf17bc..dfae129 100644
--- a/app/src/modules/builder/builder.tsx
+++ b/app/src/modules/builder/builder.tsx
@@ -20,7 +20,6 @@ import Window from "../../assets/gltf-glb/window.glb";
import {
useToggleView,
useDeletePointOrLine,
- useMovePoint,
useActiveLayer,
useWallVisibility,
useRoofVisibility,
@@ -52,65 +51,65 @@ import Layer2DVisibility from "./geomentries/layers/layer2DVisibility";
import ZoneGroup from "./groups/zoneGroup";
import MeasurementTool from "../scene/tools/measurementTool";
import NavMesh from "../simulation/vehicle/navMesh/navMesh";
+import CalculateAreaGroup from "./groups/calculateAreaGroup";
export default function Builder() {
- const state = useThree
(); // Importing the state from the useThree hook, which contains the scene, camera, and other Three.js elements.
- const csg = useRef(); // Reference for CSG object, used for 3D modeling.
- const CSGGroup = useRef() as Types.RefMesh; // Reference to a group of CSG objects.
- const scene = useRef() as Types.RefScene; // Reference to the scene.
- const camera = useRef() as Types.RefCamera; // Reference to the camera object.
- const controls = useRef(); // Reference to the controls object.
- const raycaster = useRef() as Types.RefRaycaster; // Reference for raycaster used for detecting objects being pointed at in the scene.
- const dragPointControls = useRef() as Types.RefDragControl; // Reference for drag point controls, an array for drag control.
+ const state = useThree(); // Importing the state from the useThree hook, which contains the scene, camera, and other Three.js elements.
+ const csg = useRef(); // Reference for CSG object, used for 3D modeling.
+ const CSGGroup = useRef() as Types.RefMesh; // Reference to a group of CSG objects.
+ const scene = useRef() as Types.RefScene; // Reference to the scene.
+ const camera = useRef() as Types.RefCamera; // Reference to the camera object.
+ const controls = useRef(); // Reference to the controls object.
+ const raycaster = useRef() as Types.RefRaycaster; // Reference for raycaster used for detecting objects being pointed at in the scene.
+ const dragPointControls = useRef() as Types.RefDragControl; // Reference for drag point controls, an array for drag control.
- // Assigning the scene and camera from the Three.js state to the references.
+ // Assigning the scene and camera from the Three.js state to the references.
- scene.current = state.scene;
- camera.current = state.camera;
- controls.current = state.controls;
- raycaster.current = state.raycaster;
+ scene.current = state.scene;
+ camera.current = state.camera;
+ controls.current = state.controls;
+ raycaster.current = state.raycaster;
- const plane = useRef(null); // Reference for a plane object for raycaster reference.
- const grid = useRef() as any; // Reference for a grid object for raycaster reference.
- const snappedPoint = useRef() as Types.RefVector3; // Reference for storing a snapped point at the (end = isSnapped) and (start = ispreSnapped) of the line.
- const isSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (end).
- const anglesnappedPoint = useRef() as Types.RefVector3; // Reference for storing an angle-snapped point when the line is in 90 degree etc...
- const isAngleSnapped = useRef(false) as Types.RefBoolean; // Boolean to indicate if angle snapping is active.
- const isSnappedUUID = useRef() as Types.RefString; // UUID reference to identify the snapped point.
- const ispreSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (start).
- const tempLoader = useRef() as Types.RefMesh; // Reference for a temporary loader for the floor items.
- const isTempLoader = useRef() as Types.RefBoolean; // Reference to check if a temporary loader is active.
- const Tube = useRef() as Types.RefTubeGeometry; // Reference for tubes used for reference line creation and updation.
- const line = useRef([]) as Types.RefLine; // Reference for line which stores the current line that is being drawn.
- const lines = useRef([]) as Types.RefLines; // Reference for lines which stores all the lines that are ever drawn.
- const onlyFloorline = useRef([]); // Reference for floor lines which does not have walls or roof and have only floor used to store the current line that is being drawn.
- const onlyFloorlines = useRef([]); // Reference for all the floor lines that are ever drawn.
- const ReferenceLineMesh = useRef() as Types.RefMesh; // Reference for storing the mesh of the reference line for moving it during draw.
- const LineCreated = useRef(false) as Types.RefBoolean; // Boolean to track whether the reference line is created or not.
- const referencePole = useRef() as Types.RefMesh; // Reference for a pole that is used as the reference for the user to show where it is placed.
- const itemsGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the floor items (Gltf).
- const floorGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the roofs and the floors.
- const AttachedObject = useRef() as Types.RefMesh; // Reference for an object that is attached using dbl click for transform controls rotation.
- const floorPlanGroup = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines group and the points group.
- const floorPlanGroupLine = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines that are drawn.
- const floorPlanGroupPoint = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the points that are created.
- const floorGroupAisle = useRef() as Types.RefGroup;
- const zoneGroup = useRef() as Types.RefGroup;
- const currentLayerPoint = useRef([]) as Types.RefMeshArray; // Reference for points that re in the current layer used to update the points in drag controls.
- const hoveredDeletablePoint = useRef() as Types.RefMesh; // Reference for the currently hovered point that can be deleted.
- const hoveredDeletableLine = useRef() as Types.RefMesh; // Reference for the currently hovered line that can be deleted.
- const hoveredDeletableFloorItem = useRef() as Types.RefMesh; // Reference for the currently hovered floor item that can be deleted.
- const hoveredDeletableWallItem = useRef() as Types.RefMesh; // Reference for the currently hovered wall item that can be deleted.
- const hoveredDeletablePillar = useRef() as Types.RefMesh; // Reference for the currently hovered pillar that can be deleted.
- const currentWallItem = useRef() as Types.RefMesh; // Reference for the currently selected wall item that can be scaled, dragged etc...
+ const plane = useRef(null); // Reference for a plane object for raycaster reference.
+ const grid = useRef() as any; // Reference for a grid object for raycaster reference.
+ const snappedPoint = useRef() as Types.RefVector3; // Reference for storing a snapped point at the (end = isSnapped) and (start = ispreSnapped) of the line.
+ const isSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (end).
+ const anglesnappedPoint = useRef() as Types.RefVector3; // Reference for storing an angle-snapped point when the line is in 90 degree etc...
+ const isAngleSnapped = useRef(false) as Types.RefBoolean; // Boolean to indicate if angle snapping is active.
+ const isSnappedUUID = useRef() as Types.RefString; // UUID reference to identify the snapped point.
+ const ispreSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (start).
+ const tempLoader = useRef() as Types.RefMesh; // Reference for a temporary loader for the floor items.
+ const isTempLoader = useRef() as Types.RefBoolean; // Reference to check if a temporary loader is active.
+ const Tube = useRef() as Types.RefTubeGeometry; // Reference for tubes used for reference line creation and updation.
+ const line = useRef([]) as Types.RefLine; // Reference for line which stores the current line that is being drawn.
+ const lines = useRef([]) as Types.RefLines; // Reference for lines which stores all the lines that are ever drawn.
+ const onlyFloorline = useRef([]); // Reference for floor lines which does not have walls or roof and have only floor used to store the current line that is being drawn.
+ const onlyFloorlines = useRef([]); // Reference for all the floor lines that are ever drawn.
+ const ReferenceLineMesh = useRef() as Types.RefMesh; // Reference for storing the mesh of the reference line for moving it during draw.
+ const LineCreated = useRef(false) as Types.RefBoolean; // Boolean to track whether the reference line is created or not.
+ const referencePole = useRef() as Types.RefMesh; // Reference for a pole that is used as the reference for the user to show where it is placed.
+ const itemsGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the floor items (Gltf).
+ const floorGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the roofs and the floors.
+ const AttachedObject = useRef() as Types.RefMesh; // Reference for an object that is attached using dbl click for transform controls rotation.
+ const floorPlanGroup = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines group and the points group.
+ const floorPlanGroupLine = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines that are drawn.
+ const floorPlanGroupPoint = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the points that are created.
+ const floorGroupAisle = useRef() as Types.RefGroup;
+ const zoneGroup = useRef() as Types.RefGroup;
+ const currentLayerPoint = useRef([]) as Types.RefMeshArray; // Reference for points that re in the current layer used to update the points in drag controls.
+ const hoveredDeletablePoint = useRef() as Types.RefMesh; // Reference for the currently hovered point that can be deleted.
+ const hoveredDeletableLine = useRef() as Types.RefMesh; // Reference for the currently hovered line that can be deleted.
+ const hoveredDeletableFloorItem = useRef() as Types.RefMesh; // Reference for the currently hovered floor item that can be deleted.
+ const hoveredDeletableWallItem = useRef() as Types.RefMesh; // Reference for the currently hovered wall item that can be deleted.
+ const hoveredDeletablePillar = useRef() as Types.RefMesh; // Reference for the currently hovered pillar that can be deleted.
+ const currentWallItem = useRef() as Types.RefMesh; // Reference for the currently selected wall item that can be scaled, dragged etc...
- const cursorPosition = new THREE.Vector3(); // 3D vector for storing the cursor position.
+ const cursorPosition = new THREE.Vector3(); // 3D vector for storing the cursor position.
const [selectedItemsIndex, setSelectedItemsIndex] = useState(null); // State for tracking the index of the selected item.
const { activeLayer } = useActiveLayer(); // State that changes based on which layer the user chooses in Layers.jsx.
const { toggleView } = useToggleView(); // State for toggling between 2D and 3D.
const { toolMode, setToolMode } = useToolMode();
- const { setMovePoint } = useMovePoint(); // State that stores a boolean which represents whether the move mode is active or not.
const { setDeletePointOrLine } = useDeletePointOrLine();
const { setRoofVisibility } = useRoofVisibility();
const { setWallVisibility } = useWallVisibility();
@@ -121,48 +120,45 @@ export default function Builder() {
const { setWalls } = useWalls();
const { refTextupdate, setRefTextUpdate } = useRefTextUpdate();
- // const loader = new GLTFLoader();
- // const dracoLoader = new DRACOLoader();
+ // const loader = new GLTFLoader();
+ // const dracoLoader = new DRACOLoader();
- // dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/');
- // loader.setDRACOLoader(dracoLoader);
+ // dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/');
+ // loader.setDRACOLoader(dracoLoader);
- ////////// Assest Configuration Values //////////
+ ////////// Assest Configuration Values //////////
- const AssetConfigurations: Types.AssetConfigurations = {
- arch: {
- modelUrl: arch,
- scale: [0.75, 0.75, 0.75],
- csgscale: [2, 4, 0.5],
- csgposition: [0, 2, 0],
- positionY: () => 0,
- type: "Fixed-Move",
- },
- door: {
- modelUrl: door,
- scale: [0.75, 0.75, 0.75],
- csgscale: [2, 4, 0.5],
- csgposition: [0, 2, 0],
- positionY: () => 0,
- type: "Fixed-Move",
- },
- window: {
- modelUrl: Window,
- scale: [0.75, 0.75, 0.75],
- csgscale: [5, 3, 0.5],
- csgposition: [0, 1.5, 0],
- positionY: (intersectionPoint) => intersectionPoint.point.y,
- type: "Free-Move",
- },
- };
+ const AssetConfigurations: Types.AssetConfigurations = {
+ arch: {
+ modelUrl: arch,
+ scale: [0.75, 0.75, 0.75],
+ csgscale: [2, 4, 0.5],
+ csgposition: [0, 2, 0],
+ positionY: () => 0,
+ type: "Fixed-Move",
+ },
+ door: {
+ modelUrl: door,
+ scale: [0.75, 0.75, 0.75],
+ csgscale: [2, 4, 0.5],
+ csgposition: [0, 2, 0],
+ positionY: () => 0,
+ type: "Fixed-Move",
+ },
+ window: {
+ modelUrl: Window,
+ scale: [0.75, 0.75, 0.75],
+ csgscale: [5, 3, 0.5],
+ csgposition: [0, 1.5, 0],
+ positionY: (intersectionPoint) => intersectionPoint.point.y,
+ type: "Free-Move",
+ },
+ };
- ////////// All Toggle's //////////
+ ////////// All Toggle's //////////
useEffect(() => {
setRefTextUpdate((prevUpdate: number) => prevUpdate - 1);
- if (dragPointControls.current) {
- dragPointControls.current.enabled = false;
- }
if (toggleView) {
Layer2DVisibility(
activeLayer,
@@ -175,174 +171,173 @@ export default function Builder() {
} else {
setToolMode(null);
setDeletePointOrLine(false);
- setMovePoint(false);
loadWalls(lines, setWalls);
setUpdateScene(true);
line.current = [];
}
}, [toggleView]);
- useEffect(() => {
- THREE.Cache.clear();
- THREE.Cache.enabled = true;
- }, []);
+ useEffect(() => {
+ THREE.Cache.clear();
+ THREE.Cache.enabled = true;
+ }, []);
- useEffect(() => {
- const email = localStorage.getItem("email");
- const organization = email!.split("@")[1].split(".")[0];
+ useEffect(() => {
+ const email = localStorage.getItem("email");
+ const organization = email!.split("@")[1].split(".")[0];
- async function fetchVisibility() {
- const visibility = await findEnvironment(
- organization,
- localStorage.getItem("userId")!
- );
- if (visibility) {
- setRoofVisibility(visibility.roofVisibility);
- setWallVisibility(visibility.wallVisibility);
- setShadows(visibility.shadowVisibility);
- setRenderDistance(visibility.renderDistance);
- setLimitDistance(visibility.limitDistance);
- }
- }
- fetchVisibility();
- }, []);
+ async function fetchVisibility() {
+ const visibility = await findEnvironment(
+ organization,
+ localStorage.getItem("userId")!
+ );
+ if (visibility) {
+ setRoofVisibility(visibility.roofVisibility);
+ setWallVisibility(visibility.wallVisibility);
+ setShadows(visibility.shadowVisibility);
+ setRenderDistance(visibility.renderDistance);
+ setLimitDistance(visibility.limitDistance);
+ }
+ }
+ fetchVisibility();
+ }, []);
- ////////// UseFrame is Here //////////
+ ////////// UseFrame is Here //////////
- useFrame(() => {
- if (toolMode) {
- Draw(
- state,
- plane,
- cursorPosition,
- floorPlanGroupPoint,
- floorPlanGroupLine,
- snappedPoint,
- isSnapped,
- isSnappedUUID,
- line,
- lines,
- ispreSnapped,
- floorPlanGroup,
- ReferenceLineMesh,
- LineCreated,
- setRefTextUpdate,
- Tube,
- anglesnappedPoint,
- isAngleSnapped,
- toolMode
- );
- }
- });
+ useFrame(() => {
+ if (toolMode) {
+ Draw(
+ state,
+ plane,
+ cursorPosition,
+ floorPlanGroupPoint,
+ floorPlanGroupLine,
+ snappedPoint,
+ isSnapped,
+ isSnappedUUID,
+ line,
+ lines,
+ ispreSnapped,
+ floorPlanGroup,
+ ReferenceLineMesh,
+ LineCreated,
+ setRefTextUpdate,
+ Tube,
+ anglesnappedPoint,
+ isAngleSnapped,
+ toolMode
+ );
+ }
+ });
- ////////// Return //////////
+ ////////// Return //////////
- return (
- <>
-
+ return (
+ <>
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
-
- >
- );
+
+
+
+ >
+ );
}
diff --git a/app/src/modules/builder/functions/computeArea.ts b/app/src/modules/builder/functions/computeArea.ts
new file mode 100644
index 0000000..2bd499b
--- /dev/null
+++ b/app/src/modules/builder/functions/computeArea.ts
@@ -0,0 +1,29 @@
+import { Vector2 } from "three";
+
+export function computeArea(data: any, type: "zone" | "rooms" | "aisle"): any {
+ if (type === "zone") {
+ const points3D = data.map((p: any) => new Vector2(p[0], p[2]));
+ let area = 0;
+ for (let i = 0; i < points3D.length - 1; i++) {
+ const current = points3D[i];
+ const next = points3D[i + 1];
+ area += current.x * next.y - next.x * current.y;
+ }
+
+ return Math.abs(area) / 2;
+ }
+
+ if (type === "rooms") {
+ const points2D = data.coordinates.map(
+ (coordinate: any) =>
+ new Vector2(coordinate.position.x, coordinate.position.z)
+ );
+ let area = 0;
+ for (let i = 0; i < points2D.length - 1; i++) {
+ const current = points2D[i];
+ const next = points2D[i + 1];
+ area += current.x * next.y - next.x * current.y;
+ }
+ return Math.abs(area) / 2;
+ }
+}
diff --git a/app/src/modules/builder/geomentries/assets/addAssetModel.ts b/app/src/modules/builder/geomentries/assets/addAssetModel.ts
index 707b8c0..6023422 100644
--- a/app/src/modules/builder/geomentries/assets/addAssetModel.ts
+++ b/app/src/modules/builder/geomentries/assets/addAssetModel.ts
@@ -265,7 +265,7 @@ async function handleModelLoad(
actionName: "Action 1",
actionType: "travel",
unLoadDuration: 5,
- loadCapacity: 10,
+ loadCapacity: 1,
steeringAngle: 0,
pickUpPoint: null,
unLoadPoint: null,
@@ -342,6 +342,33 @@ async function handleModelLoad(
position: machineEvent.point.position,
rotation: machineEvent.point.rotation
};
+ } else if (selectedItem.type === "Storage") {
+ const storageEvent: StorageEventSchema = {
+ modelUuid: newFloorItem.modelUuid,
+ modelName: newFloorItem.modelName,
+ position: newFloorItem.position,
+ rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
+ state: "idle",
+ type: "storageUnit",
+ point: {
+ uuid: THREE.MathUtils.generateUUID(),
+ position: [data.points[0].x, data.points[0].y, data.points[0].z],
+ rotation: [0, 0, 0],
+ action: {
+ actionUuid: THREE.MathUtils.generateUUID(),
+ actionName: "Action 1",
+ actionType: "store",
+ storageCapacity: 10,
+ triggers: []
+ }
+ }
+ }
+ addEvent(storageEvent);
+ eventData.point = {
+ uuid: storageEvent.point.uuid,
+ position: storageEvent.point.position,
+ rotation: storageEvent.point.rotation
+ };
}
const completeData = {
diff --git a/app/src/modules/builder/geomentries/lines/distanceText/distanceText.tsx b/app/src/modules/builder/geomentries/lines/distanceText/distanceText.tsx
index b8c0947..40a68a3 100644
--- a/app/src/modules/builder/geomentries/lines/distanceText/distanceText.tsx
+++ b/app/src/modules/builder/geomentries/lines/distanceText/distanceText.tsx
@@ -2,180 +2,226 @@ import { useEffect, useState } from "react";
import { getLines } from "../../../../../services/factoryBuilder/lines/getLinesApi";
import * as THREE from "three";
import {
- useActiveLayer,
- useDeletedLines,
- useNewLines,
- useRoomsState,
- useToggleView,
+ useActiveLayer,
+ useDeletedLines,
+ useNewLines,
+ useRoomsState,
+ useToggleView,
} from "../../../../../store/store";
import objectLinesToArray from "../lineConvertions/objectLinesToArray";
import { Html } from "@react-three/drei";
+import { Vector2 } from "three";
import * as Types from "../../../../../types/world/worldTypes";
import getRoomsFromLines from "../getRoomsFromLines";
+import * as turf from '@turf/turf';
const DistanceText = () => {
- const [lines, setLines] = useState<
- {
- distance: string;
- position: THREE.Vector3;
- userData: Types.Line;
- layer: string;
- }[]
- >([]);
- const { activeLayer } = useActiveLayer();
- const { toggleView } = useToggleView();
- const { newLines, setNewLines } = useNewLines();
- const { deletedLines, setDeletedLines } = useDeletedLines();
- const [linesState, setLinesState] = useState([]);
- const { roomsState, setRoomsState } = useRoomsState();
+ const [lines, setLines] = useState<
+ {
+ distance: string;
+ position: THREE.Vector3;
+ userData: Types.Line;
+ layer: string;
+ }[]
+ >([]);
+ const { activeLayer } = useActiveLayer();
+ const { toggleView } = useToggleView();
+ const { newLines, setNewLines } = useNewLines();
+ const { deletedLines, setDeletedLines } = useDeletedLines();
+ const [linesState, setLinesState] = useState([]);
+ const { roomsState, setRoomsState } = useRoomsState();
- useEffect(() => {
- if (linesState.length === 0) return;
- const getLines = async () => {
- if (lines.length > 2) {
- const linesByLayer = linesState.reduce((acc: { [key: number]: any[] }, pair) => {
- const layer = pair[0][2];
- if (!acc[layer]) acc[layer] = [];
- acc[layer].push(pair);
- return acc;
- }, {});
- for (const layer in linesByLayer) {
- const rooms: Types.Rooms = await getRoomsFromLines({ current: linesByLayer[layer] });
- }
- }
+ useEffect(() => {
+
+ if (linesState.length === 0) return;
+ const getLines = async () => {
+ const points3D = linesState.map(line => {
+ const startPoint = line[0][0]; // First point of each wall line
+ return [startPoint.x, 0, startPoint.z];
+ });
+
+ // Ensure the polygon is closed
+ if (
+ points3D[0][0] !== points3D[points3D.length - 1][0] ||
+ points3D[0][1] !== points3D[points3D.length - 1][1]
+ ) {
+ points3D.push(points3D[0]);
+ }
+
+ // Convert to 2D for turf (x, z)
+ const coords2D = points3D.map(p => [p[0], p[1]]);
+
+ const projected = points3D.map((p: any) => new Vector2(p[0], p[1]));
+
+ // Shoelace formula for 2D polygon
+ let area = 0;
+ const n = projected.length;
+ for (let i = 0; i < n - 1; i++) {
+ const curr = projected[i];
+ const next = projected[i + 1];
+ area += curr.x * next.y - next.x * curr.y;
+
+ }
+
+
+
+ // return Math.abs(area) / 2;
+
+ // Build polygon and compute area
+ // const polygon = turf.polygon([coords2D]);
+ // const area = turf.area(polygon);
+ // const area = computeAreaFrom3DPoints(coords2D)
+
+ //
+ if (lines.length > 2) {
+ const linesByLayer = linesState.reduce((acc: { [key: number]: any[] }, pair) => {
+ const layer = pair[0][2];
+ if (!acc[layer]) acc[layer] = [];
+ acc[layer].push(pair);
+ return acc;
+ }, {});
+
+
+ for (const layer in linesByLayer) {
+ const rooms: Types.Rooms = await getRoomsFromLines({ current: linesByLayer[layer] });
+ setRoomsState(rooms)
}
- getLines();
- }, [linesState])
+ }
+ }
+ getLines();
+ }, [linesState, roomsState])
- useEffect(() => {
- const email = localStorage.getItem("email");
- if (!email) return;
- const organization = email.split("@")[1].split(".")[0];
- getLines(organization).then((data) => {
- data = objectLinesToArray(data);
- setLinesState(data);
+ useEffect(() => {
+ const email = localStorage.getItem("email");
+ if (!email) return;
+ const organization = email.split("@")[1].split(".")[0];
- const lines = data
- .filter((line: Types.Line) => line[0][2] === activeLayer)
- .map((line: Types.Line) => {
- const point1 = new THREE.Vector3(
- line[0][0].x,
- line[0][0].y,
- line[0][0].z
- );
- const point2 = new THREE.Vector3(
- line[1][0].x,
- line[1][0].y,
- line[1][0].z
- );
- const distance = point1.distanceTo(point2);
- const midpoint = new THREE.Vector3()
- .addVectors(point1, point2)
- .divideScalar(2);
- return {
- distance: distance.toFixed(1),
- position: midpoint,
- userData: line,
- layer: activeLayer,
- };
- });
- setLines(lines);
+ getLines(organization).then((data) => {
+ data = objectLinesToArray(data);
+ setLinesState(data);
+
+ const lines = data
+ .filter((line: Types.Line) => line[0][2] === activeLayer)
+ .map((line: Types.Line) => {
+ const point1 = new THREE.Vector3(
+ line[0][0].x,
+ line[0][0].y,
+ line[0][0].z
+ );
+ const point2 = new THREE.Vector3(
+ line[1][0].x,
+ line[1][0].y,
+ line[1][0].z
+ );
+ const distance = point1.distanceTo(point2);
+ const midpoint = new THREE.Vector3()
+ .addVectors(point1, point2)
+ .divideScalar(2);
+ return {
+ distance: distance.toFixed(1),
+ position: midpoint,
+ userData: line,
+ layer: activeLayer,
+ };
});
- }, [activeLayer]);
+ setLines(lines);
+ });
+ }, [activeLayer]);
- useEffect(() => {
- if (newLines.length > 0) {
- if (newLines[0][0][2] !== activeLayer) return;
- const newLinesData = newLines.map((line: Types.Line) => {
- const point1 = new THREE.Vector3(
- line[0][0].x,
- line[0][0].y,
- line[0][0].z
- );
- const point2 = new THREE.Vector3(
- line[1][0].x,
- line[1][0].y,
- line[1][0].z
- );
- const distance = point1.distanceTo(point2);
- const midpoint = new THREE.Vector3()
- .addVectors(point1, point2)
- .divideScalar(2);
+ useEffect(() => {
+ if (newLines.length > 0) {
+ if (newLines[0][0][2] !== activeLayer) return;
+ const newLinesData = newLines.map((line: Types.Line) => {
+ const point1 = new THREE.Vector3(
+ line[0][0].x,
+ line[0][0].y,
+ line[0][0].z
+ );
+ const point2 = new THREE.Vector3(
+ line[1][0].x,
+ line[1][0].y,
+ line[1][0].z
+ );
+ const distance = point1.distanceTo(point2);
+ const midpoint = new THREE.Vector3()
+ .addVectors(point1, point2)
+ .divideScalar(2);
- return {
- distance: distance.toFixed(1),
- position: midpoint,
- userData: line,
- layer: activeLayer,
- };
- });
- setLines((prevLines) => [...prevLines, ...newLinesData]);
- setLinesState((prevLines) => [...prevLines, ...newLines]);
- setNewLines([]);
- }
- }, [newLines, activeLayer]);
+ return {
+ distance: distance.toFixed(1),
+ position: midpoint,
+ userData: line,
+ layer: activeLayer,
+ };
+ });
+ setLines((prevLines) => [...prevLines, ...newLinesData]);
+ setLinesState((prevLines) => [...prevLines, ...newLines]);
+ setNewLines([]);
+ }
+ }, [newLines, activeLayer]);
- useEffect(() => {
- if ((deletedLines as Types.Lines).length > 0) {
- setLines((prevLines) =>
- prevLines.filter(
- (line) =>
- !deletedLines.some(
- (deletedLine: any) =>
- deletedLine[0][1] === line.userData[0][1] &&
- deletedLine[1][1] === line.userData[1][1]
- )
- )
- );
+ useEffect(() => {
+ if ((deletedLines as Types.Lines).length > 0) {
+ setLines((prevLines) =>
+ prevLines.filter(
+ (line) =>
+ !deletedLines.some(
+ (deletedLine: any) =>
+ deletedLine[0][1] === line.userData[0][1] &&
+ deletedLine[1][1] === line.userData[1][1]
+ )
+ )
+ );
- setLinesState(prev =>
- prev.filter(line =>
- !(deletedLines as Types.Lines).some(
- deleted =>
- line[0][1] === deleted[0][1] && line[1][1] === deleted[1][1]
- )
- )
- );
+ setLinesState(prev =>
+ prev.filter(line =>
+ !(deletedLines as Types.Lines).some(
+ deleted =>
+ line[0][1] === deleted[0][1] && line[1][1] === deleted[1][1]
+ )
+ )
+ );
- setDeletedLines([]);
- }
- }, [deletedLines]);
+ setDeletedLines([]);
+ setRoomsState([])
+ }
+ }, [deletedLines]);
- return (
- <>
- {toggleView && (
-
- {lines.map((text) => (
-
-
- {text.distance} m
-
-
- ))}
-
- )}
- >
- );
+ return (
+ <>
+ {toggleView && (
+
+ {lines.map((text) => (
+
+
+ {text.distance} m
+
+
+ ))}
+
+ )}
+ >
+ );
};
export default DistanceText;
diff --git a/app/src/modules/builder/groups/calculateAreaGroup.tsx b/app/src/modules/builder/groups/calculateAreaGroup.tsx
new file mode 100644
index 0000000..e50ae4b
--- /dev/null
+++ b/app/src/modules/builder/groups/calculateAreaGroup.tsx
@@ -0,0 +1,65 @@
+import React, { useEffect } from 'react';
+import { useRoomsState, useToggleView } from '../../../store/store';
+import { computeArea } from '../functions/computeArea';
+import { Html } from '@react-three/drei';
+import * as CONSTANTS from "../../../types/world/worldConstants";
+import * as turf from '@turf/turf';
+
+const CalculateAreaGroup = () => {
+ const { roomsState } = useRoomsState();
+ const { toggleView } = useToggleView();
+
+ return (
+
+ {roomsState.length > 0 &&
+ roomsState.flat().map((room: any, index: number) => {
+ if (!toggleView) return null;
+ const coordinates = room.coordinates;
+
+ if (!coordinates || coordinates.length < 3) return null;
+
+ let coords2D = coordinates.map((p: any) => [p.position.x, p.position.z]);
+
+ const first = coords2D[0];
+ const last = coords2D[coords2D.length - 1];
+ if (first[0] !== last[0] || first[1] !== last[1]) {
+ coords2D.push(first);
+ }
+
+ const polygon = turf.polygon([coords2D]);
+ const center2D = turf.center(polygon).geometry.coordinates;
+
+ const sumY = coordinates.reduce((sum: number, p: any) => sum + p.position.y, 0);
+ const avgY = sumY / coordinates.length;
+
+ const area = computeArea(room, "rooms");
+ const formattedArea = `${area.toFixed(2)} m²`;
+
+ const htmlPosition: [number, number, number] = [
+ center2D[0],
+ avgY + CONSTANTS.zoneConfig.height,
+ center2D[1],
+ ];
+
+ return (
+
+
+ Room ({formattedArea})
+
+
+ );
+ })}
+
+ );
+}
+
+export default CalculateAreaGroup;
diff --git a/app/src/modules/builder/groups/floorGroup.tsx b/app/src/modules/builder/groups/floorGroup.tsx
index e589380..f4d2ee7 100644
--- a/app/src/modules/builder/groups/floorGroup.tsx
+++ b/app/src/modules/builder/groups/floorGroup.tsx
@@ -1,5 +1,12 @@
import { useFrame, useThree } from "@react-three/fiber";
-import { useAddAction, useDeleteTool, useRoofVisibility, useToggleView, useWallVisibility, useUpdateScene } from "../../../store/store";
+import {
+ useAddAction,
+ useDeleteTool,
+ useRoofVisibility,
+ useToggleView,
+ useWallVisibility,
+ useUpdateScene,
+} from "../../../store/store";
import hideRoof from "../geomentries/roofs/hideRoof";
import hideWalls from "../geomentries/walls/hideWalls";
import addAndUpdateReferencePillar from "../geomentries/pillars/addAndUpdateReferencePillar";
@@ -9,93 +16,97 @@ import DeletePillar from "../geomentries/pillars/deletePillar";
import DeletableHoveredPillar from "../geomentries/pillars/deletableHoveredPillar";
import loadFloor from "../geomentries/floors/loadFloor";
-const FloorGroup = ({ floorGroup, lines, referencePole, hoveredDeletablePillar }: any) => {
- const state = useThree();
- const { roofVisibility, setRoofVisibility } = useRoofVisibility();
- const { wallVisibility, setWallVisibility } = useWallVisibility();
- const { toggleView, setToggleView } = useToggleView();
- const { scene, camera, pointer, raycaster, gl } = useThree();
- const { addAction, setAddAction } = useAddAction();
- const { deleteTool, setDeleteTool } = useDeleteTool();
- const { updateScene, setUpdateScene } = useUpdateScene();
+const FloorGroup = ({
+ floorGroup,
+ lines,
+ referencePole,
+ hoveredDeletablePillar,
+}: any) => {
+ const state = useThree();
+ const { roofVisibility } = useRoofVisibility();
+ const { wallVisibility } = useWallVisibility();
+ const { toggleView } = useToggleView();
+ const { scene, camera, raycaster, gl } = useThree();
+ const { addAction } = useAddAction();
+ const { deleteTool } = useDeleteTool();
+ const { updateScene, setUpdateScene } = useUpdateScene();
- useEffect(() => {
- if (updateScene) {
- loadFloor(lines, floorGroup);
- setUpdateScene(false);
+ useEffect(() => {
+ if (updateScene) {
+ loadFloor(lines, floorGroup);
+ setUpdateScene(false);
+ }
+ }, [updateScene]);
+
+ useEffect(() => {
+ if (!addAction) {
+ if (referencePole.current) {
+ (referencePole.current as any).material.dispose();
+ (referencePole.current.geometry as any).dispose();
+ floorGroup.current.remove(referencePole.current);
+ referencePole.current = undefined;
+ }
+ }
+ }, [addAction]);
+
+ useEffect(() => {
+ const canvasElement = gl.domElement;
+ let drag = false;
+ let isLeftMouseDown = false;
+
+ const onMouseDown = (evt: any) => {
+ if (evt.button === 0) {
+ isLeftMouseDown = true;
+ drag = false;
+ }
+ };
+
+ const onMouseUp = (evt: any) => {
+ if (evt.button === 0) {
+ isLeftMouseDown = false;
+ if (!drag) {
+ if (addAction === "pillar") {
+ addPillar(referencePole, floorGroup);
+ }
+ if (deleteTool) {
+ DeletePillar(hoveredDeletablePillar, floorGroup);
+ }
}
- }, [updateScene])
+ }
+ };
- useEffect(() => {
- if (!addAction) {
- if (referencePole.current) {
- (referencePole.current as any).material.dispose();
- (referencePole.current.geometry as any).dispose();
- floorGroup.current.remove(referencePole.current);
- referencePole.current = undefined;
- }
- }
- }, [addAction]);
+ const onMouseMove = () => {
+ if (isLeftMouseDown) {
+ drag = true;
+ }
+ };
- useEffect(() => {
- const canvasElement = gl.domElement;
- let drag = false;
- let isLeftMouseDown = false;
+ canvasElement.addEventListener("mousedown", onMouseDown);
+ canvasElement.addEventListener("mouseup", onMouseUp);
+ canvasElement.addEventListener("mousemove", onMouseMove);
- const onMouseDown = (evt: any) => {
- if (evt.button === 0) {
- isLeftMouseDown = true;
- drag = false;
- }
- };
+ return () => {
+ canvasElement.removeEventListener("mousedown", onMouseDown);
+ canvasElement.removeEventListener("mouseup", onMouseUp);
+ canvasElement.removeEventListener("mousemove", onMouseMove);
+ };
+ }, [deleteTool, addAction]);
- const onMouseUp = (evt: any) => {
- if (evt.button === 0) {
- isLeftMouseDown = false;
- if (!drag) {
- if (addAction === "pillar") {
- addPillar(referencePole, floorGroup);
- }
- if (deleteTool) {
- DeletePillar(hoveredDeletablePillar, floorGroup);
- }
- }
- }
- };
+ useFrame(() => {
+ hideRoof(roofVisibility, floorGroup, camera);
+ hideWalls(wallVisibility, scene, camera);
- const onMouseMove = () => {
- if (isLeftMouseDown) {
- drag = true;
- }
- };
+ if (addAction === "pillar") {
+ addAndUpdateReferencePillar(raycaster, floorGroup, referencePole);
+ }
+ if (deleteTool) {
+ DeletableHoveredPillar(state, floorGroup, hoveredDeletablePillar);
+ }
+ });
- canvasElement.addEventListener("mousedown", onMouseDown);
- canvasElement.addEventListener("mouseup", onMouseUp);
- canvasElement.addEventListener("mousemove", onMouseMove);
+ return (
+
+ );
+};
- return () => {
- canvasElement.removeEventListener("mousedown", onMouseDown);
- canvasElement.removeEventListener("mouseup", onMouseUp);
- canvasElement.removeEventListener("mousemove", onMouseMove);
- };
- }, [deleteTool, addAction])
-
- useFrame(() => {
- hideRoof(roofVisibility, floorGroup, camera);
- hideWalls(wallVisibility, scene, camera);
-
- if (addAction === "pillar") {
- addAndUpdateReferencePillar(raycaster, floorGroup, referencePole);
- }
- if (deleteTool) {
- DeletableHoveredPillar(state, floorGroup, hoveredDeletablePillar);
- }
- })
-
- return (
-
-
- )
-}
-
-export default FloorGroup;
\ No newline at end of file
+export default FloorGroup;
diff --git a/app/src/modules/builder/groups/floorGroupAisle.tsx b/app/src/modules/builder/groups/floorGroupAisle.tsx
index 23db1f5..2a6831c 100644
--- a/app/src/modules/builder/groups/floorGroupAisle.tsx
+++ b/app/src/modules/builder/groups/floorGroupAisle.tsx
@@ -2,7 +2,7 @@ import * as THREE from 'three';
import * as Types from '../../../types/world/worldTypes';
import * as CONSTANTS from '../../../types/world/worldConstants';
import { useThree } from "@react-three/fiber";
-import { useToggleView, useActiveLayer, useSocketStore, useDeletePointOrLine, useMovePoint, useUpdateScene, useNewLines, useToolMode } from "../../../store/store";
+import { useToggleView, useActiveLayer, useSocketStore, useDeletePointOrLine, useUpdateScene, useNewLines, useToolMode } from "../../../store/store";
import { useEffect } from "react";
import removeSoloPoint from "../geomentries/points/removeSoloPoint";
import removeReferenceLine from "../geomentries/lines/removeReferenceLine";
@@ -17,7 +17,6 @@ const FloorGroupAilse = ({ floorGroupAisle, plane, floorPlanGroupLine, floorPlan
const { toggleView, setToggleView } = useToggleView();
const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine();
const { toolMode, setToolMode } = useToolMode();
- const { movePoint, setMovePoint } = useMovePoint();
const { socket } = useSocketStore();
const { activeLayer } = useActiveLayer();
const { gl, raycaster, camera, pointer } = useThree();
@@ -34,7 +33,6 @@ const FloorGroupAilse = ({ floorGroupAisle, plane, floorPlanGroupLine, floorPlan
useEffect(() => {
if (toolMode === "Aisle") {
setDeletePointOrLine(false);
- setMovePoint(false);
} else {
removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint);
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
diff --git a/app/src/modules/builder/groups/floorPlanGroup.tsx b/app/src/modules/builder/groups/floorPlanGroup.tsx
index 12d75f0..c1c38f0 100644
--- a/app/src/modules/builder/groups/floorPlanGroup.tsx
+++ b/app/src/modules/builder/groups/floorPlanGroup.tsx
@@ -1,6 +1,6 @@
import { useEffect } from "react";
import * as Types from '../../../types/world/worldTypes';
-import { useActiveLayer, useDeletedLines, useDeletePointOrLine, useToolMode, useMovePoint, useNewLines, useRemovedLayer, useSocketStore, useToggleView, useUpdateScene } from "../../../store/store";
+import { useActiveLayer, useDeletedLines, useDeletePointOrLine, useToolMode, useNewLines, useRemovedLayer, useSocketStore, useToggleView, useUpdateScene } from "../../../store/store";
import Layer2DVisibility from "../geomentries/layers/layer2DVisibility";
import { useFrame, useThree } from "@react-three/fiber";
import DeletableLineorPoint from "../functions/deletableLineOrPoint";
@@ -24,7 +24,6 @@ const FloorPlanGroup = ({ floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoin
const { toggleView, setToggleView } = useToggleView();
const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine();
const { toolMode, setToolMode } = useToolMode();
- const { movePoint, setMovePoint } = useMovePoint();
const { removedLayer, setRemovedLayer } = useRemovedLayer();
const { updateScene, setUpdateScene } = useUpdateScene();
const { newLines, setNewLines } = useNewLines();
@@ -32,8 +31,16 @@ const FloorPlanGroup = ({ floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoin
const { socket } = useSocketStore();
useEffect(() => {
- addDragControl(dragPointControls, currentLayerPoint, state, floorPlanGroupPoint, floorPlanGroupLine, lines, onlyFloorlines, socket);
- }, [state]);
+ if (toolMode === 'move') {
+ addDragControl(dragPointControls, currentLayerPoint, state, floorPlanGroupPoint, floorPlanGroupLine, lines, onlyFloorlines, socket);
+ }
+
+ return () => {
+ if (dragPointControls.current) {
+ dragPointControls.current.enabled = false;
+ }
+ };
+ }, [toolMode, state]);
useEffect(() => {
const email = localStorage.getItem('email')
@@ -65,7 +72,6 @@ const FloorPlanGroup = ({ floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoin
useEffect(() => {
if (toolMode === "Wall" || toolMode === "Floor") {
setDeletePointOrLine(false);
- setMovePoint(false);
} else {
removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint);
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
@@ -73,8 +79,7 @@ const FloorPlanGroup = ({ floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoin
}, [toolMode]);
useEffect(() => {
- if (movePoint) {
- setToolMode(null);
+ if (toolMode === 'move' && toggleView) {
setDeletePointOrLine(false);
if (dragPointControls.current) {
dragPointControls.current.enabled = true;
@@ -84,12 +89,11 @@ const FloorPlanGroup = ({ floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoin
dragPointControls.current.enabled = false;
}
}
- }, [movePoint, toolMode]);
+ }, [toolMode, toggleView, state]);
useEffect(() => {
if (deletePointOrLine) {
setToolMode(null);
- setMovePoint(false);
}
}, [deletePointOrLine]);
diff --git a/app/src/modules/builder/groups/wallItemsGroup.tsx b/app/src/modules/builder/groups/wallItemsGroup.tsx
index f993754..76ba502 100644
--- a/app/src/modules/builder/groups/wallItemsGroup.tsx
+++ b/app/src/modules/builder/groups/wallItemsGroup.tsx
@@ -1,5 +1,13 @@
import { useEffect } from "react";
-import { useDeleteTool, useDeletePointOrLine, useObjectPosition, useObjectRotation, useObjectScale, useSelectedWallItem, useSocketStore, useWallItems } from "../../../store/store";
+import {
+ useDeleteTool,
+ useDeletePointOrLine,
+ useObjectPosition,
+ useObjectRotation,
+ useSelectedWallItem,
+ useSocketStore,
+ useWallItems,
+} from "../../../store/store";
import { Csg } from "../csg/csg";
import * as Types from "../../../types/world/worldTypes";
import * as CONSTANTS from "../../../types/world/worldConstants";
@@ -11,236 +19,277 @@ import loadInitialWallItems from "../IntialLoad/loadInitialWallItems";
import AddWallItems from "../geomentries/walls/addWallItems";
import useModuleStore from "../../../store/useModuleStore";
+const WallItemsGroup = ({
+ currentWallItem,
+ AssetConfigurations,
+ hoveredDeletableWallItem,
+ selectedItemsIndex,
+ setSelectedItemsIndex,
+ CSGGroup,
+}: any) => {
+ const state = useThree();
+ const { socket } = useSocketStore();
+ const { pointer, camera, raycaster } = state;
+ const { deleteTool } = useDeleteTool();
+ const { wallItems, setWallItems } = useWallItems();
+ const { setObjectPosition } = useObjectPosition();
+ const { setObjectRotation } = useObjectRotation();
+ const { deletePointOrLine } = useDeletePointOrLine();
+ const { setSelectedWallItem } = useSelectedWallItem();
+ const { activeModule } = useModuleStore();
-const WallItemsGroup = ({ currentWallItem, AssetConfigurations, hoveredDeletableWallItem, selectedItemsIndex, setSelectedItemsIndex, CSGGroup }: any) => {
- const state = useThree();
- const { socket } = useSocketStore();
- const { pointer, camera, raycaster } = state;
- const { deleteTool, setDeleteTool } = useDeleteTool();
- const { wallItems, setWallItems } = useWallItems();
- const { objectPosition, setObjectPosition } = useObjectPosition();
- const { objectScale, setObjectScale } = useObjectScale();
- const { objectRotation, setObjectRotation } = useObjectRotation();
- const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine();
- const { selectedWallItem, setSelectedWallItem } = useSelectedWallItem();
- const { activeModule } = useModuleStore();
+ useEffect(() => {
+ // Load Wall Items from the backend
+ loadInitialWallItems(setWallItems, AssetConfigurations);
+ }, []);
- useEffect(() => {
- // Load Wall Items from the backend
- loadInitialWallItems(setWallItems, AssetConfigurations);
- }, []);
+ ////////// Update the Scale value changes in thewallItems State //////////
+ ////////// Update the Position value changes in the selected item //////////
- ////////// Update the Scale value changes in thewallItems State //////////
+ ////////// Update the Rotation value changes in the selected item //////////
- ////////// Update the Position value changes in the selected item //////////
+ useEffect(() => {
+ const canvasElement = state.gl.domElement;
+ function handlePointerMove(e: any) {
+ if (
+ selectedItemsIndex !== null &&
+ !deletePointOrLine &&
+ e.buttons === 1
+ ) {
+ const Raycaster = state.raycaster;
+ const intersects = Raycaster.intersectObjects(
+ CSGGroup.current?.children[0].children!,
+ true
+ );
+ const Object = intersects.find((child) =>
+ child.object.name.includes("WallRaycastReference")
+ );
- ////////// Update the Rotation value changes in the selected item //////////
+ if (Object) {
+ (state.controls as any)!.enabled = false;
+ setWallItems((prevItems: any) => {
+ const updatedItems = [...prevItems];
+ let position: [number, number, number] = [0, 0, 0];
- useEffect(() => {
- const canvasElement = state.gl.domElement;
- function handlePointerMove(e: any) {
- if (selectedItemsIndex !== null && !deletePointOrLine && e.buttons === 1) {
- const Raycaster = state.raycaster;
- const intersects = Raycaster.intersectObjects(CSGGroup.current?.children[0].children!, true);
- const Object = intersects.find((child) => child.object.name.includes("WallRaycastReference"));
-
- if (Object) {
- (state.controls as any)!.enabled = false;
- setWallItems((prevItems: any) => {
- const updatedItems = [...prevItems];
- let position: [number, number, number] = [0, 0, 0];
-
- if (updatedItems[selectedItemsIndex].type === "Fixed-Move") {
- position = [Object!.point.x, Math.floor(Object!.point.y / CONSTANTS.wallConfig.height) * CONSTANTS.wallConfig.height, Object!.point.z];
- } else if (updatedItems[selectedItemsIndex].type === "Free-Move") {
- position = [Object!.point.x, Object!.point.y, Object!.point.z];
- }
-
- requestAnimationFrame(() => {
- setObjectPosition(new THREE.Vector3(...position));
- setObjectRotation({
- x: THREE.MathUtils.radToDeg(Object!.object.rotation.x),
- y: THREE.MathUtils.radToDeg(Object!.object.rotation.y),
- z: THREE.MathUtils.radToDeg(Object!.object.rotation.z),
- });
- });
-
- updatedItems[selectedItemsIndex] = {
- ...updatedItems[selectedItemsIndex],
- position: position,
- quaternion: Object!.object.quaternion.clone() as Types.QuaternionType,
- };
-
- return updatedItems;
- });
- }
+ if (updatedItems[selectedItemsIndex].type === "Fixed-Move") {
+ position = [
+ Object!.point.x,
+ Math.floor(Object!.point.y / CONSTANTS.wallConfig.height) *
+ CONSTANTS.wallConfig.height,
+ Object!.point.z,
+ ];
+ } else if (updatedItems[selectedItemsIndex].type === "Free-Move") {
+ position = [Object!.point.x, Object!.point.y, Object!.point.z];
}
+
+ requestAnimationFrame(() => {
+ setObjectPosition(new THREE.Vector3(...position));
+ setObjectRotation({
+ x: THREE.MathUtils.radToDeg(Object!.object.rotation.x),
+ y: THREE.MathUtils.radToDeg(Object!.object.rotation.y),
+ z: THREE.MathUtils.radToDeg(Object!.object.rotation.z),
+ });
+ });
+
+ updatedItems[selectedItemsIndex] = {
+ ...updatedItems[selectedItemsIndex],
+ position: position,
+ quaternion:
+ Object!.object.quaternion.clone() as Types.QuaternionType,
+ };
+
+ return updatedItems;
+ });
}
+ }
+ }
- async function handlePointerUp() {
- const Raycaster = state.raycaster;
- const intersects = Raycaster.intersectObjects(CSGGroup.current?.children[0].children!, true);
- const Object = intersects.find((child) => child.object.name.includes("WallRaycastReference"));
- if (Object) {
- if (selectedItemsIndex !== null) {
- let currentItem: any = null;
- setWallItems((prevItems: any) => {
- const updatedItems = [...prevItems];
- const WallItemsForStorage = updatedItems.map((item) => {
- const { model, ...rest } = item;
- return {
- ...rest,
- modelUuid: model?.uuid,
- };
- });
+ async function handlePointerUp() {
+ const Raycaster = state.raycaster;
+ const intersects = Raycaster.intersectObjects(
+ CSGGroup.current?.children[0].children!,
+ true
+ );
+ const Object = intersects.find((child) =>
+ child.object.name.includes("WallRaycastReference")
+ );
+ if (Object) {
+ if (selectedItemsIndex !== null) {
+ let currentItem: any = null;
+ setWallItems((prevItems: any) => {
+ const updatedItems = [...prevItems];
+ const WallItemsForStorage = updatedItems.map((item) => {
+ const { model, ...rest } = item;
+ return {
+ ...rest,
+ modelUuid: model?.uuid,
+ };
+ });
- currentItem = updatedItems[selectedItemsIndex];
- localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage));
- return updatedItems;
- });
+ currentItem = updatedItems[selectedItemsIndex];
+ localStorage.setItem(
+ "WallItems",
+ JSON.stringify(WallItemsForStorage)
+ );
+ return updatedItems;
+ });
- setTimeout(async () => {
+ setTimeout(async () => {
+ const email = localStorage.getItem("email");
+ const organization = email!.split("@")[1].split(".")[0];
- const email = localStorage.getItem('email')
- const organization = (email!.split("@")[1]).split(".")[0];
+ //REST
- //REST
+ // await setWallItem(
+ // organization,
+ // currentItem?.model?.uuid,
+ // currentItem.modelName,
+ // currentItem.type!,
+ // currentItem.csgposition!,
+ // currentItem.csgscale!,
+ // currentItem.position,
+ // currentItem.quaternion,
+ // currentItem.scale!,
+ // )
- // await setWallItem(
- // organization,
- // currentItem?.model?.uuid,
- // currentItem.modelName,
- // currentItem.type!,
- // currentItem.csgposition!,
- // currentItem.csgscale!,
- // currentItem.position,
- // currentItem.quaternion,
- // currentItem.scale!,
- // )
+ //SOCKET
- //SOCKET
+ const data = {
+ organization: organization,
+ modelUuid: currentItem.model?.uuid!,
+ modelName: currentItem.modelName!,
+ type: currentItem.type!,
+ csgposition: currentItem.csgposition!,
+ csgscale: currentItem.csgscale!,
+ position: currentItem.position!,
+ quaternion: currentItem.quaternion,
+ scale: currentItem.scale!,
+ socketId: socket.id,
+ };
- const data = {
- organization: organization,
- modelUuid: currentItem.model?.uuid!,
- modelName: currentItem.modelName!,
- type: currentItem.type!,
- csgposition: currentItem.csgposition!,
- csgscale: currentItem.csgscale!,
- position: currentItem.position!,
- quaternion: currentItem.quaternion,
- scale: currentItem.scale!,
- socketId: socket.id
- }
-
- socket.emit('v1:wallItems:set', data);
- }, 0);
- (state.controls as any)!.enabled = true;
- }
- }
+ socket.emit("v1:wallItems:set", data);
+ }, 0);
+ (state.controls as any)!.enabled = true;
}
+ }
+ }
- canvasElement.addEventListener("pointermove", handlePointerMove);
- canvasElement.addEventListener("pointerup", handlePointerUp);
+ canvasElement.addEventListener("pointermove", handlePointerMove);
+ canvasElement.addEventListener("pointerup", handlePointerUp);
- return () => {
- canvasElement.removeEventListener("pointermove", handlePointerMove);
- canvasElement.removeEventListener("pointerup", handlePointerUp);
- };
- }, [selectedItemsIndex]);
+ return () => {
+ canvasElement.removeEventListener("pointermove", handlePointerMove);
+ canvasElement.removeEventListener("pointerup", handlePointerUp);
+ };
+ }, [selectedItemsIndex]);
- useEffect(() => {
- const canvasElement = state.gl.domElement;
- let drag = false;
- let isLeftMouseDown = false;
+ useEffect(() => {
+ const canvasElement = state.gl.domElement;
+ let drag = false;
+ let isLeftMouseDown = false;
- const onMouseDown = (evt: any) => {
- if (evt.button === 0) {
- isLeftMouseDown = true;
- drag = false;
- }
- };
+ const onMouseDown = (evt: any) => {
+ if (evt.button === 0) {
+ isLeftMouseDown = true;
+ drag = false;
+ }
+ };
- const onMouseUp = (evt: any) => {
- if (evt.button === 0) {
- isLeftMouseDown = false;
- if (!drag && deleteTool && activeModule === "builder") {
- DeleteWallItems(hoveredDeletableWallItem, setWallItems, wallItems, socket);
- }
- }
- };
-
- const onMouseMove = () => {
- if (isLeftMouseDown) {
- drag = true;
- }
- };
-
- const onDrop = (event: any) => {
-
- if (!event.dataTransfer?.files[0]) return
-
- pointer.x = (event.clientX / window.innerWidth) * 2 - 1;
- pointer.y = -(event.clientY / window.innerHeight) * 2 + 1;
- raycaster.setFromCamera(pointer, camera);
-
- if (AssetConfigurations[(event.dataTransfer.files[0].name.split('.'))[0]]) {
- const selected = (event.dataTransfer.files[0].name.split('.'))[0];
-
- if (AssetConfigurations[selected]?.type) {
- AddWallItems(selected, raycaster, CSGGroup, AssetConfigurations, setWallItems, socket);
- }
- event.preventDefault();
- }
+ const onMouseUp = (evt: any) => {
+ if (evt.button === 0) {
+ isLeftMouseDown = false;
+ if (!drag && deleteTool && activeModule === "builder") {
+ DeleteWallItems(
+ hoveredDeletableWallItem,
+ setWallItems,
+ wallItems,
+ socket
+ );
}
+ }
+ };
- const onDragOver = (event: any) => {
- event.preventDefault();
- };
+ const onMouseMove = () => {
+ if (isLeftMouseDown) {
+ drag = true;
+ }
+ };
- canvasElement.addEventListener("mousedown", onMouseDown);
- canvasElement.addEventListener("mouseup", onMouseUp);
- canvasElement.addEventListener("mousemove", onMouseMove);
- canvasElement.addEventListener("drop", onDrop);
- canvasElement.addEventListener("dragover", onDragOver);
+ const onDrop = (event: any) => {
+ if (!event.dataTransfer?.files[0]) return;
- return () => {
- canvasElement.removeEventListener("mousedown", onMouseDown);
- canvasElement.removeEventListener("mouseup", onMouseUp);
- canvasElement.removeEventListener("mousemove", onMouseMove);
- canvasElement.removeEventListener("drop", onDrop);
- canvasElement.removeEventListener("dragover", onDragOver);
- };
- }, [deleteTool, wallItems])
+ pointer.x = (event.clientX / window.innerWidth) * 2 - 1;
+ pointer.y = -(event.clientY / window.innerHeight) * 2 + 1;
+ raycaster.setFromCamera(pointer, camera);
- useEffect(() => {
- if (deleteTool && activeModule === "builder") {
- handleMeshMissed(currentWallItem, setSelectedWallItem, setSelectedItemsIndex);
- setSelectedWallItem(null);
- setSelectedItemsIndex(null);
+ if (AssetConfigurations[event.dataTransfer.files[0].name.split(".")[0]]) {
+ const selected = event.dataTransfer.files[0].name.split(".")[0];
+
+ if (AssetConfigurations[selected]?.type) {
+ AddWallItems(
+ selected,
+ raycaster,
+ CSGGroup,
+ AssetConfigurations,
+ setWallItems,
+ socket
+ );
}
- }, [deleteTool])
+ event.preventDefault();
+ }
+ };
- return (
- <>
- {wallItems.map((item: Types.WallItem, index: number) => (
-
-
-
- ))}
- >
- )
-}
+ const onDragOver = (event: any) => {
+ event.preventDefault();
+ };
-export default WallItemsGroup;
\ No newline at end of file
+ canvasElement.addEventListener("mousedown", onMouseDown);
+ canvasElement.addEventListener("mouseup", onMouseUp);
+ canvasElement.addEventListener("mousemove", onMouseMove);
+ canvasElement.addEventListener("drop", onDrop);
+ canvasElement.addEventListener("dragover", onDragOver);
+
+ return () => {
+ canvasElement.removeEventListener("mousedown", onMouseDown);
+ canvasElement.removeEventListener("mouseup", onMouseUp);
+ canvasElement.removeEventListener("mousemove", onMouseMove);
+ canvasElement.removeEventListener("drop", onDrop);
+ canvasElement.removeEventListener("dragover", onDragOver);
+ };
+ }, [deleteTool, wallItems]);
+
+ useEffect(() => {
+ if (deleteTool && activeModule === "builder") {
+ handleMeshMissed(
+ currentWallItem,
+ setSelectedWallItem,
+ setSelectedItemsIndex
+ );
+ setSelectedWallItem(null);
+ setSelectedItemsIndex(null);
+ }
+ }, [deleteTool]);
+
+ return (
+ <>
+ {wallItems.map((item: Types.WallItem, index: number) => (
+
+
+
+ ))}
+ >
+ );
+};
+
+export default WallItemsGroup;
diff --git a/app/src/modules/builder/groups/zoneGroup.tsx b/app/src/modules/builder/groups/zoneGroup.tsx
index b0c8124..e6c0f1a 100644
--- a/app/src/modules/builder/groups/zoneGroup.tsx
+++ b/app/src/modules/builder/groups/zoneGroup.tsx
@@ -1,12 +1,11 @@
import React, { useState, useEffect, useMemo, useRef } from "react";
-import { Line, Sphere } from "@react-three/drei";
+import { Html, Line, Sphere } from "@react-three/drei";
import { useThree, useFrame } from "@react-three/fiber";
import * as THREE from "three";
import {
useActiveLayer,
useDeleteTool,
useDeletePointOrLine,
- useMovePoint,
useSocketStore,
useToggleView,
useToolMode,
@@ -17,6 +16,9 @@ import {
import { getZonesApi } from "../../../services/factoryBuilder/zones/getZonesApi";
import * as CONSTANTS from "../../../types/world/worldConstants";
+import * as turf from '@turf/turf';
+import { computeArea } from "../functions/computeArea";
+import { useSelectedZoneStore } from "../../../store/visualization/useZoneStore";
const ZoneGroup: React.FC = () => {
const { camera, pointer, gl, raycaster, scene, controls } = useThree();
@@ -25,6 +27,7 @@ const ZoneGroup: React.FC = () => {
const { zones, setZones } = useZones();
const { zonePoints, setZonePoints } = useZonePoints();
const [isDragging, setIsDragging] = useState(false);
+ const { selectedZone } = useSelectedZoneStore();
const [draggedSphere, setDraggedSphere] = useState(
null
);
@@ -36,7 +39,6 @@ const ZoneGroup: React.FC = () => {
const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine();
const { removedLayer, setRemovedLayer } = useRemovedLayer();
const { toolMode } = useToolMode();
- const { movePoint, setMovePoint } = useMovePoint();
const { setDeleteTool } = useDeleteTool();
const { activeLayer } = useActiveLayer();
const { socket } = useSocketStore();
@@ -139,7 +141,6 @@ const ZoneGroup: React.FC = () => {
setEndPoint(null);
} else {
setDeletePointOrLine(false);
- setMovePoint(false);
setDeleteTool(false);
}
if (!toggleView) {
@@ -311,7 +312,7 @@ const ZoneGroup: React.FC = () => {
true
);
- if (intersects.length > 0 && movePoint) {
+ if (intersects.length > 0 && toolMode === "move") {
const clickedObject = intersects[0].object;
const sphereIndex = zonePoints.findIndex((point: any) =>
point.equals(clickedObject.position)
@@ -329,7 +330,7 @@ const ZoneGroup: React.FC = () => {
if (evt.button === 0 && !drag && !isDragging && !deletePointOrLine) {
isLeftMouseDown = false;
- if (!startPoint && !movePoint) {
+ if (!startPoint && toolMode !== "move") {
raycaster.setFromCamera(pointer, camera);
const intersectionPoint = new THREE.Vector3();
const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
@@ -337,7 +338,7 @@ const ZoneGroup: React.FC = () => {
setStartPoint(point);
setEndPoint(null);
}
- } else if (startPoint && !movePoint) {
+ } else if (startPoint && toolMode !== "move") {
raycaster.setFromCamera(pointer, camera);
const intersectionPoint = new THREE.Vector3();
const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
@@ -439,7 +440,8 @@ const ZoneGroup: React.FC = () => {
intersects.length > 0 &&
intersects[0].object.name.includes("point")
) {
- gl.domElement.style.cursor = movePoint ? "pointer" : "default";
+ gl.domElement.style.cursor =
+ toolMode === "move" ? "pointer" : "default";
} else {
gl.domElement.style.cursor = "default";
}
@@ -479,7 +481,7 @@ const ZoneGroup: React.FC = () => {
setEndPoint(null);
};
- if (toolMode === "Zone" || deletePointOrLine || movePoint) {
+ if (toolMode === "Zone" || deletePointOrLine || toolMode === "move") {
canvasElement.addEventListener("mousedown", onMouseDown);
canvasElement.addEventListener("mouseup", onMouseUp);
canvasElement.addEventListener("mousemove", onMouseMove);
@@ -503,7 +505,6 @@ const ZoneGroup: React.FC = () => {
deletePointOrLine,
zonePoints,
draggedSphere,
- movePoint,
activeLayer,
raycaster,
pointer,
@@ -526,11 +527,16 @@ const ZoneGroup: React.FC = () => {
}
});
+
return (
{zones.map((zone: any) => (
-
+
{zone.points
.slice(0, -1)
.map((point: [number, number, number], index: number) => {
@@ -549,7 +555,7 @@ const ZoneGroup: React.FC = () => {
const midpoint = new THREE.Vector3(
(point1.x + point2.x) / 2,
CONSTANTS.zoneConfig.height / 2 +
- (zone.layer - 1) * CONSTANTS.zoneConfig.height,
+ (zone.layer - 1) * CONSTANTS.zoneConfig.height,
(point1.z + point2.z) / 2
);
@@ -592,7 +598,61 @@ const ZoneGroup: React.FC = () => {
}}
/>
))}
+
+
+ {zones.map((zone: any, index: any) => {
+ if (!toggleView) return null;
+ const points3D = zone.points;
+ const coords2D = points3D.map((p: any) => [p[0], p[2]]);
+
+ if (
+ coords2D.length < 3 ||
+ coords2D[0][0] !== coords2D[coords2D.length - 1][0] ||
+ coords2D[0][1] !== coords2D[coords2D.length - 1][1]
+ ) {
+ coords2D.push(coords2D[0]);
+ }
+
+ const polygon = turf.polygon([coords2D]);
+ const center2D = turf.center(polygon).geometry.coordinates;
+
+ const sumY = points3D.reduce((sum: number, p: any) => sum + p[1], 0);
+ const avgY = sumY / points3D.length;
+
+ const area = computeArea(points3D, "zone");
+ const formattedArea = `${area.toFixed(2)} m²`;
+
+ const htmlPosition: [number, number, number] = [
+ center2D[0],
+ avgY + CONSTANTS.zoneConfig.height,
+ center2D[1]
+ ];
+ return (
+
+
+ {zone.zoneName} ({formattedArea})
+
+
+ );
+ })}
+
+
{zones
.filter((zone: any) => zone.layer === activeLayer)
@@ -624,8 +684,18 @@ const ZoneGroup: React.FC = () => {
/>
)}
+
);
};
export default ZoneGroup;
+
+
+
+
+
+
+
+
+
diff --git a/app/src/modules/collaboration/camera/collabCams.tsx b/app/src/modules/collaboration/camera/collabCams.tsx
index 6ce26b0..fab6efe 100644
--- a/app/src/modules/collaboration/camera/collabCams.tsx
+++ b/app/src/modules/collaboration/camera/collabCams.tsx
@@ -12,6 +12,7 @@ import CollabUserIcon from "./collabUserIcon";
import useModuleStore from "../../../store/useModuleStore";
import { getAvatarColor } from "../functions/getAvatarColor";
import { useSelectedUserStore } from "../../../store/useCollabStore";
+import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
const CamModelsGroup = () => {
const navigate = useNavigate();
@@ -21,6 +22,7 @@ const CamModelsGroup = () => {
const { socket } = useSocketStore();
const { activeModule } = useModuleStore();
const { selectedUser, setSelectedUser } = useSelectedUserStore();
+ const { isPlaying } = usePlayButtonStore();
// eslint-disable-next-line react-hooks/exhaustive-deps
const loader = new GLTFLoader();
@@ -244,7 +246,8 @@ const CamModelsGroup = () => {
object={cam}
visible={
selectedUser?.name !== cam.userData.userName &&
- activeModule !== "visualization"
+ activeModule !== "visualization" &&
+ !isPlaying
}
>
{
fontFamily: "Arial, sans-serif",
display: `${activeModule !== "visualization" ? "" : "none"}`,
opacity: `${
- selectedUser?.name !== cam.userData.userName ? 1 : 0
+ selectedUser?.name !== cam.userData.userName && !isPlaying
+ ? 1
+ : 0
}`,
transition: "opacity .2s ease",
}}
diff --git a/app/src/modules/scene/controls/selectionControls/copyPasteControls.tsx b/app/src/modules/scene/controls/selectionControls/copyPasteControls.tsx
index b2e0ea5..82f21ab 100644
--- a/app/src/modules/scene/controls/selectionControls/copyPasteControls.tsx
+++ b/app/src/modules/scene/controls/selectionControls/copyPasteControls.tsx
@@ -150,6 +150,7 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas
};
let updatedEventData = null;
+
if (obj.userData.eventData) {
updatedEventData = JSON.parse(JSON.stringify(obj.userData.eventData));
updatedEventData.modelUuid = newFloorItem.modelUuid;
@@ -208,7 +209,7 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas
actionName: "Action 1",
actionType: "travel",
unLoadDuration: 5,
- loadCapacity: 10,
+ loadCapacity: 1,
steeringAngle: 0,
pickUpPoint: null,
unLoadPoint: null,
@@ -285,13 +286,37 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas
position: machineEvent.point.position,
rotation: machineEvent.point.rotation
};
+ } else if (obj.userData.eventData.type === "Storage") {
+ const storageEvent: StorageEventSchema = {
+ modelUuid: newFloorItem.modelUuid,
+ modelName: newFloorItem.modelName,
+ position: newFloorItem.position,
+ rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
+ state: "idle",
+ type: "storageUnit",
+ point: {
+ uuid: THREE.MathUtils.generateUUID(),
+ position: [updatedEventData.point.position[0], updatedEventData.point.position[1], updatedEventData.point.position[2]],
+ rotation: [updatedEventData.point.rotation[0], updatedEventData.point.rotation[1], updatedEventData.point.rotation[2]],
+ action: {
+ actionUuid: THREE.MathUtils.generateUUID(),
+ actionName: "Action 1",
+ actionType: "store",
+ storageCapacity: 10,
+ triggers: []
+ }
+ }
+ }
+ addEvent(storageEvent);
+ eventData.point = {
+ uuid: storageEvent.point.uuid,
+ position: storageEvent.point.position,
+ rotation: storageEvent.point.rotation
+ };
}
- obj.userData.eventData = eventData;
-
newFloorItem.eventData = eventData;
-
setFloorItems((prevItems: Types.FloorItems) => {
const updatedItems = [...(prevItems || []), newFloorItem];
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
@@ -335,6 +360,7 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas
name: newFloorItem.modelName,
modelId: newFloorItem.modelfileID,
modelUuid: newFloorItem.modelUuid,
+ eventData: JSON.parse(JSON.stringify(eventData))
};
itemsGroupRef.current.add(obj);
diff --git a/app/src/modules/scene/controls/selectionControls/distanceFindingControls.tsx b/app/src/modules/scene/controls/selectionControls/distanceFindingControls.tsx
new file mode 100644
index 0000000..25e6c96
--- /dev/null
+++ b/app/src/modules/scene/controls/selectionControls/distanceFindingControls.tsx
@@ -0,0 +1,270 @@
+import React, { useRef } from "react";
+import {
+ Vector3,
+ Raycaster,
+ BufferGeometry,
+ LineBasicMaterial,
+ Line,
+ Mesh,
+ Group,
+} from "three";
+import { useThree, useFrame } from "@react-three/fiber";
+import { Html } from "@react-three/drei";
+
+interface DistanceFindingControlsProps {
+ boundingBoxRef: React.RefObject;
+ object: number;
+}
+
+const DistanceFindingControls = ({
+ boundingBoxRef,
+ object,
+}: DistanceFindingControlsProps) => {
+ const { camera, scene } = useThree();
+
+ // Refs for measurement lines
+ const line1 = useRef(null);
+ const line2 = useRef(null);
+ const line3 = useRef(null);
+ const line4 = useRef(null);
+ const line5 = useRef(null);
+
+ // Refs for measurement text labels
+ const textPosX = useRef(null);
+ const textNegX = useRef(null);
+ const textPosZ = useRef(null);
+ const textNegZ = useRef(null);
+ const textPosY = useRef(null);
+
+ // Store line geometries to avoid recreation
+ const lineGeometries = useRef({
+ posX: new BufferGeometry(),
+ negX: new BufferGeometry(),
+ posZ: new BufferGeometry(),
+ negZ: new BufferGeometry(),
+ posY: new BufferGeometry(),
+ });
+
+ useFrame(() => {
+ if (!boundingBoxRef?.current) return;
+
+ boundingBoxRef.current.geometry.computeBoundingBox();
+ const bbox = boundingBoxRef.current.geometry.boundingBox;
+
+ if (!bbox) return;
+
+ const size = {
+ x: bbox.max.x - bbox.min.x,
+ y: bbox.max.y - bbox.min.y,
+ z: bbox.max.z - bbox.min.z,
+ };
+
+ const vec = boundingBoxRef.current?.getWorldPosition(new Vector3()).clone();
+
+ if (!vec) return;
+ updateLine({
+ line: line1.current,
+ geometry: lineGeometries.current.posX,
+ direction: new Vector3(1, 0, 0), // Positive X
+ angle: "pos",
+ mesh: textPosX,
+ vec,
+ size,
+ });
+ updateLine({
+ line: line2.current,
+ geometry: lineGeometries.current.negX,
+ direction: new Vector3(-1, 0, 0), // Negative X
+ angle: "neg",
+ mesh: textNegX,
+ vec,
+ size,
+ });
+ updateLine({
+ line: line3.current,
+ geometry: lineGeometries.current.posZ,
+ direction: new Vector3(0, 0, 1), // Positive Z
+ angle: "pos",
+ mesh: textPosZ,
+ vec,
+ size,
+ });
+ updateLine({
+ line: line4.current,
+ geometry: lineGeometries.current.negZ,
+ direction: new Vector3(0, 0, -1), // Negative Z
+ angle: "neg",
+ mesh: textNegZ,
+ vec,
+ size,
+ });
+ updateLine({
+ line: line5.current,
+ geometry: lineGeometries.current.posY,
+ direction: new Vector3(0, -1, 0), // Down (Y)
+ angle: "posY",
+ mesh: textPosY,
+ vec,
+ size,
+ });
+ });
+
+ const updateLine = ({
+ line,
+ geometry,
+ direction,
+ angle,
+ mesh,
+ vec,
+ size,
+ }: {
+ line: Line | null;
+ geometry: BufferGeometry;
+ direction: Vector3;
+ angle: string;
+ mesh: React.RefObject;
+ vec: Vector3;
+ size: { x: number; y: number; z: number };
+ }) => {
+ if (!line) return;
+
+ const points = [];
+
+ if (angle === "pos") {
+ points[0] = new Vector3(vec.x, vec.y, vec.z).add(
+ new Vector3((direction.x * size.x) / 2, 0, (direction.z * size.z) / 2)
+ );
+ } else if (angle === "neg") {
+ points[0] = new Vector3(vec.x, vec.y, vec.z).sub(
+ new Vector3((-direction.x * size.x) / 2, 0, (-direction.z * size.z) / 2)
+ );
+ } else if (angle === "posY") {
+ points[0] = new Vector3(vec.x, vec.y, vec.z).sub(
+ new Vector3(0, size.y / 2, 0)
+ );
+ }
+
+ const ray = new Raycaster();
+ if (camera) ray.camera = camera;
+ ray.set(new Vector3(vec.x, vec.y, vec.z), direction);
+ ray.params.Line.threshold = 0.1;
+
+ // Find intersection points
+ const wallsGroup = scene.children.find((val) =>
+ val?.name.includes("Walls")
+ );
+ const intersects = wallsGroup
+ ? ray.intersectObjects([wallsGroup], true)
+ : [];
+
+ // Find intersection point
+ if (intersects[0]) {
+ for (const intersect of intersects) {
+ if (intersect.object.name.includes("Wall")) {
+ points[1] =
+ angle !== "posY" ? intersect.point : new Vector3(vec.x, 0, vec.z); // Floor
+ break;
+ }
+ }
+ }
+
+ // Update line geometry
+ if (points[1]) {
+ geometry.dispose();
+ geometry.setFromPoints([points[0], points[1]]);
+ line.geometry = geometry;
+
+ // Update measurement text
+ if (mesh?.current) {
+ geometry.computeBoundingSphere();
+ const center = geometry.boundingSphere?.center;
+ if (center) {
+ mesh.current.position.copy(center);
+ }
+ const label = document.getElementById(mesh.current.name);
+ if (label) {
+ label.innerText = `${points[0].distanceTo(points[1]).toFixed(2)}m`;
+ }
+ }
+ } else {
+ // No intersection found - clear the line
+ geometry.dispose();
+ geometry.setFromPoints([new Vector3(), new Vector3()]);
+ line.geometry = geometry;
+ const label = document.getElementById(mesh?.current?.name ?? "");
+ if (label) label.innerText = "";
+ }
+ };
+
+ const Material = new LineBasicMaterial({ color: "#d2baff" });
+
+ return (
+ <>
+ {/* Measurement text labels */}
+ {boundingBoxRef.current && object > 0 && (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* Measurement lines */}
+
+
+
+
+ >
+ )}
+ >
+ );
+};
+
+export default DistanceFindingControls;
diff --git a/app/src/modules/scene/controls/selectionControls/duplicationControls.tsx b/app/src/modules/scene/controls/selectionControls/duplicationControls.tsx
index 86df41b..3e951a3 100644
--- a/app/src/modules/scene/controls/selectionControls/duplicationControls.tsx
+++ b/app/src/modules/scene/controls/selectionControls/duplicationControls.tsx
@@ -186,7 +186,7 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb
actionName: "Action 1",
actionType: "travel",
unLoadDuration: 5,
- loadCapacity: 10,
+ loadCapacity: 1,
steeringAngle: 0,
pickUpPoint: null,
unLoadPoint: null,
@@ -263,13 +263,37 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb
position: machineEvent.point.position,
rotation: machineEvent.point.rotation
};
+ } else if (obj.userData.eventData.type === "Storage") {
+ const storageEvent: StorageEventSchema = {
+ modelUuid: newFloorItem.modelUuid,
+ modelName: newFloorItem.modelName,
+ position: newFloorItem.position,
+ rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
+ state: "idle",
+ type: "storageUnit",
+ point: {
+ uuid: THREE.MathUtils.generateUUID(),
+ position: [updatedEventData.point.position[0], updatedEventData.point.position[1], updatedEventData.point.position[2]],
+ rotation: [updatedEventData.point.rotation[0], updatedEventData.point.rotation[1], updatedEventData.point.rotation[2]],
+ action: {
+ actionUuid: THREE.MathUtils.generateUUID(),
+ actionName: "Action 1",
+ actionType: "store",
+ storageCapacity: 10,
+ triggers: []
+ }
+ }
+ }
+ addEvent(storageEvent);
+ eventData.point = {
+ uuid: storageEvent.point.uuid,
+ position: storageEvent.point.position,
+ rotation: storageEvent.point.rotation
+ };
}
- obj.userData.eventData = eventData;
-
newFloorItem.eventData = eventData;
-
setFloorItems((prevItems: Types.FloorItems) => {
const updatedItems = [...(prevItems || []), newFloorItem];
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
@@ -313,6 +337,7 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb
name: newFloorItem.modelName,
modelId: newFloorItem.modelfileID,
modelUuid: newFloorItem.modelUuid,
+ eventData: JSON.parse(JSON.stringify(eventData))
};
itemsGroupRef.current.add(obj);
diff --git a/app/src/modules/scene/controls/selectionControls/moveControls.tsx b/app/src/modules/scene/controls/selectionControls/moveControls.tsx
index 5b33c14..498056a 100644
--- a/app/src/modules/scene/controls/selectionControls/moveControls.tsx
+++ b/app/src/modules/scene/controls/selectionControls/moveControls.tsx
@@ -1,7 +1,12 @@
import * as THREE from "three";
import { useEffect, useMemo, useRef, useState } from "react";
import { useFrame, useThree } from "@react-three/fiber";
-import { useFloorItems, useSelectedAssets, useSocketStore, useStartSimulation, useToggleView } from "../../../../store/store";
+import {
+ useFloorItems,
+ useSelectedAssets,
+ useSocketStore,
+ useToggleView,
+} from "../../../../store/store";
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
import { toast } from "react-toastify";
import * as Types from "../../../../types/world/worldTypes";
@@ -11,307 +16,373 @@ import { useProductStore } from "../../../../store/simulation/useProductStore";
import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore";
import { upsertProductOrEventApi } from "../../../../services/simulation/UpsertProductOrEventApi";
import { snapControls } from "../../../../utils/handleSnap";
+import DistanceFindingControls from "./distanceFindingControls";
-function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObjects, setCopiedObjects, pastedObjects, setpastedObjects, duplicatedObjects, setDuplicatedObjects, selectionGroup, rotatedObjects, setRotatedObjects, boundingBoxRef }: any) {
- const { camera, controls, gl, scene, pointer, raycaster } = useThree();
- const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
+function MoveControls({
+ movedObjects,
+ setMovedObjects,
+ itemsGroupRef,
+ copiedObjects,
+ setCopiedObjects,
+ pastedObjects,
+ setpastedObjects,
+ duplicatedObjects,
+ setDuplicatedObjects,
+ selectionGroup,
+ rotatedObjects,
+ setRotatedObjects,
+ boundingBoxRef,
+}: any) {
+ const { camera, controls, gl, scene, pointer, raycaster } = useThree();
+ const plane = useMemo(
+ () => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0),
+ []
+ );
- const { toggleView } = useToggleView();
- const { selectedAssets, setSelectedAssets } = useSelectedAssets();
- const { selectedProduct } = useSelectedProduct();
- const { floorItems, setFloorItems } = useFloorItems();
- const { socket } = useSocketStore();
- const itemsData = useRef([]);
- const [keyEvent, setKeyEvent] = useState<"Ctrl" | "Shift" | "Ctrl+Shift" | "">("")
+ const { toggleView } = useToggleView();
+ const { selectedAssets, setSelectedAssets } = useSelectedAssets();
+ const { selectedProduct } = useSelectedProduct();
+ const { floorItems, setFloorItems } = useFloorItems();
+ const { socket } = useSocketStore();
+ const itemsData = useRef([]);
+ const [keyEvent, setKeyEvent] = useState<
+ "Ctrl" | "Shift" | "Ctrl+Shift" | ""
+ >("");
+ const email = localStorage.getItem("email");
+ const organization = email!.split("@")[1].split(".")[0];
- const email = localStorage.getItem('email')
- const organization = (email!.split("@")[1]).split(".")[0];
-
- const updateBackend = (
- productName: string,
- productId: string,
- organization: string,
- eventData: EventsSchema
- ) => {
- upsertProductOrEventApi({
- productName: productName,
- productId: productId,
- organization: organization,
- eventDatas: eventData
- })
- }
-
- useEffect(() => {
- if (!camera || !scene || toggleView || !itemsGroupRef.current) return;
-
- const canvasElement = gl.domElement;
- canvasElement.tabIndex = 0;
-
- let isMoving = false;
-
- const onPointerDown = () => {
- isMoving = false;
- };
-
- const onPointerMove = () => {
- isMoving = true;
- };
- const onKeyUp = (event: KeyboardEvent) => {
- // When any modifier is released, reset snap
- const isModifierKey =
- event.key === "Control" || event.key === "Shift";
-
- if (isModifierKey) {
- setKeyEvent("");
- }
- };
-
- const onPointerUp = (event: PointerEvent) => {
- if (!isMoving && movedObjects.length > 0 && event.button === 0) {
- event.preventDefault();
- placeMovedAssets();
- }
- if (!isMoving && movedObjects.length > 0 && event.button === 2) {
- event.preventDefault();
-
- clearSelection();
- movedObjects.forEach((asset: any) => {
- if (itemsGroupRef.current) {
- itemsGroupRef.current.attach(asset);
- }
- });
-
- setFloorItems([...floorItems, ...itemsData.current]);
-
- setMovedObjects([]);
- itemsData.current = [];
- }
- setKeyEvent("")
- };
-
- const onKeyDown = (event: KeyboardEvent) => {
- const keyCombination = detectModifierKeys(event);
-
- if (pastedObjects.length > 0 || duplicatedObjects.length > 0 || rotatedObjects.length > 0) return;
-
- if (keyCombination === "Ctrl" || keyCombination === "Ctrl+Shift" || keyCombination === "Shift") {
- // update state here
- setKeyEvent(keyCombination)
- } else {
- setKeyEvent("")
- }
-
- if (keyCombination === "G") {
- if (selectedAssets.length > 0) {
- moveAssets();
- itemsData.current = floorItems.filter((item: { modelUuid: string }) => selectedAssets.some((asset: any) => asset.uuid === item.modelUuid));
- }
- }
-
- if (keyCombination === "ESCAPE") {
- event.preventDefault();
-
- clearSelection();
- movedObjects.forEach((asset: any) => {
- if (itemsGroupRef.current) {
- itemsGroupRef.current.attach(asset);
- }
- });
-
- setFloorItems([...floorItems, ...itemsData.current]);
-
- setMovedObjects([]);
- itemsData.current = [];
- }
- };
-
- if (!toggleView) {
- canvasElement.addEventListener("pointerdown", onPointerDown);
- canvasElement.addEventListener("pointermove", onPointerMove);
- canvasElement.addEventListener("pointerup", onPointerUp);
- canvasElement.addEventListener("keydown", onKeyDown);
- canvasElement?.addEventListener("keyup", onKeyUp);
- }
-
- return () => {
- canvasElement.removeEventListener("pointerdown", onPointerDown);
- canvasElement.removeEventListener("pointermove", onPointerMove);
- canvasElement.removeEventListener("pointerup", onPointerUp);
- canvasElement.removeEventListener("keydown", onKeyDown);
- canvasElement?.removeEventListener("keyup", onKeyUp);
- };
- }, [camera, controls, scene, toggleView, selectedAssets, socket, floorItems, pastedObjects, duplicatedObjects, movedObjects, rotatedObjects, keyEvent]);
-
- let moveSpeed = keyEvent === "Ctrl" || "Ctrl+Shift" ? 1 : 0.25;
-
- useFrame(() => {
- if (movedObjects.length > 0) {
- const intersectionPoint = new THREE.Vector3();
- raycaster.setFromCamera(pointer, camera);
- const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
-
- if (point) {
- let targetX = point.x;
- let targetZ = point.z;
- if (keyEvent === "Ctrl") {
- targetX = snapControls(targetX, "Ctrl");
- targetZ = snapControls(targetZ, "Ctrl");
- } else if (keyEvent === "Ctrl+Shift") {
- targetX = snapControls(targetX, "Ctrl+Shift");
- targetZ = snapControls(targetZ, "Ctrl+Shift");
- } else if (keyEvent === "Shift") {
- targetX = snapControls(targetX, "Shift");
- targetZ = snapControls(targetZ, "Shift");
- } else {
-
- }
-
- const position = new THREE.Vector3();
- if (boundingBoxRef.current) {
- boundingBoxRef.current.getWorldPosition(position);
- selectionGroup.current.position.lerp(
- new THREE.Vector3(
- targetX - (position.x - selectionGroup.current.position.x),
- selectionGroup.current.position.y,
- targetZ - (position.z - selectionGroup.current.position.z)
- ),
- moveSpeed
- );
- } else {
- const box = new THREE.Box3();
- movedObjects.forEach((obj: THREE.Object3D) => box.expandByObject(obj));
- const center = new THREE.Vector3();
- box.getCenter(center);
-
- selectionGroup.current.position.lerp(
- new THREE.Vector3(
- targetX - (center.x - selectionGroup.current.position.x),
- selectionGroup.current.position.y,
- targetZ - (center.z - selectionGroup.current.position.z)
- ),
- moveSpeed
- );
- }
- }
- }
+ const updateBackend = (
+ productName: string,
+ productId: string,
+ organization: string,
+ eventData: EventsSchema
+ ) => {
+ upsertProductOrEventApi({
+ productName: productName,
+ productId: productId,
+ organization: organization,
+ eventDatas: eventData,
});
+ };
+ useEffect(() => {
+ if (!camera || !scene || toggleView || !itemsGroupRef.current) return;
- const moveAssets = () => {
- const updatedItems = floorItems.filter((item: { modelUuid: string }) => !selectedAssets.some((asset: any) => asset.uuid === item.modelUuid));
- setFloorItems(updatedItems);
- setMovedObjects(selectedAssets);
- selectedAssets.forEach((asset: any) => { selectionGroup.current.attach(asset); });
- }
+ const canvasElement = gl.domElement;
+ canvasElement.tabIndex = 0;
- const placeMovedAssets = () => {
- if (movedObjects.length === 0) return;
+ let isMoving = false;
- movedObjects.forEach(async (obj: THREE.Object3D) => {
- const worldPosition = new THREE.Vector3();
- obj.getWorldPosition(worldPosition);
+ const onPointerDown = () => {
+ isMoving = false;
+ };
- selectionGroup.current.remove(obj);
- obj.position.copy(worldPosition);
+ const onPointerMove = () => {
+ isMoving = true;
+ };
+ const onKeyUp = (event: KeyboardEvent) => {
+ // When any modifier is released, reset snap
+ const isModifierKey = event.key === "Control" || event.key === "Shift";
- if (itemsGroupRef.current) {
+ if (isModifierKey) {
+ setKeyEvent("");
+ }
+ };
- const newFloorItem: Types.FloorItemType = {
- modelUuid: obj.uuid,
- modelName: obj.userData.name,
- modelfileID: obj.userData.modelId,
- position: [worldPosition.x, worldPosition.y, worldPosition.z],
- rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z, },
- isLocked: false,
- isVisible: true
- };
+ const onPointerUp = (event: PointerEvent) => {
+ if (!isMoving && movedObjects.length > 0 && event.button === 0) {
+ event.preventDefault();
+ placeMovedAssets();
+ }
+ if (!isMoving && movedObjects.length > 0 && event.button === 2) {
+ event.preventDefault();
- if (obj.userData.eventData) {
- const eventData = useEventsStore.getState().getEventByModelUuid(obj.userData.modelUuid);
- const productData = useProductStore.getState().getEventByModelUuid(useSelectedProduct.getState().selectedProduct.productId, obj.userData.modelUuid);
-
- if (eventData) {
- useEventsStore.getState().updateEvent(obj.userData.modelUuid, {
- position: [worldPosition.x, worldPosition.y, worldPosition.z],
- rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z],
- })
- }
- if (productData) {
- const event = useProductStore.getState().updateEvent(useSelectedProduct.getState().selectedProduct.productId, obj.userData.modelUuid, {
- position: [worldPosition.x, worldPosition.y, worldPosition.z],
- rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z],
- })
-
- if (event) {
- updateBackend(
- selectedProduct.productName,
- selectedProduct.productId,
- organization,
- event
- );
- }
-
- newFloorItem.eventData = eventData;
- }
- }
-
- setFloorItems((prevItems: Types.FloorItems) => {
- const updatedItems = [...(prevItems || []), newFloorItem];
- localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
- return updatedItems;
- });
-
- //REST
-
- // await setFloorItemApi(
- // organization,
- // obj.uuid,
- // obj.userData.name,
- // [worldPosition.x, worldPosition.y, worldPosition.z],
- // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
- // obj.userData.modelId,
- // false,
- // true,
- // );
-
- //SOCKET
-
- const data = {
- organization,
- modelUuid: newFloorItem.modelUuid,
- modelName: newFloorItem.modelName,
- modelfileID: newFloorItem.modelfileID,
- position: newFloorItem.position,
- rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
- isLocked: false,
- isVisible: true,
- socketId: socket.id,
- };
-
- socket.emit("v2:model-asset:add", data);
-
- itemsGroupRef.current.add(obj);
- }
- });
- toast.success("Object moved!");
-
- itemsData.current = [];
clearSelection();
- }
+ movedObjects.forEach((asset: any) => {
+ if (itemsGroupRef.current) {
+ itemsGroupRef.current.attach(asset);
+ }
+ });
+
+ setFloorItems([...floorItems, ...itemsData.current]);
- const clearSelection = () => {
- selectionGroup.current.children = [];
- selectionGroup.current.position.set(0, 0, 0);
- selectionGroup.current.rotation.set(0, 0, 0);
- setpastedObjects([]);
- setDuplicatedObjects([]);
setMovedObjects([]);
- setRotatedObjects([]);
- setSelectedAssets([]);
- setKeyEvent("")
+ itemsData.current = [];
+ }
+ setKeyEvent("");
+ };
+
+ const onKeyDown = (event: KeyboardEvent) => {
+ const keyCombination = detectModifierKeys(event);
+
+ if (
+ pastedObjects.length > 0 ||
+ duplicatedObjects.length > 0 ||
+ rotatedObjects.length > 0
+ )
+ return;
+
+ if (
+ keyCombination === "Ctrl" ||
+ keyCombination === "Ctrl+Shift" ||
+ keyCombination === "Shift"
+ ) {
+ // update state here
+ setKeyEvent(keyCombination);
+ } else {
+ setKeyEvent("");
+ }
+
+ if (keyCombination === "G") {
+ if (selectedAssets.length > 0) {
+ moveAssets();
+ itemsData.current = floorItems.filter((item: { modelUuid: string }) =>
+ selectedAssets.some((asset: any) => asset.uuid === item.modelUuid)
+ );
+ }
+ }
+
+ if (keyCombination === "ESCAPE") {
+ event.preventDefault();
+
+ clearSelection();
+ movedObjects.forEach((asset: any) => {
+ if (itemsGroupRef.current) {
+ itemsGroupRef.current.attach(asset);
+ }
+ });
+
+ setFloorItems([...floorItems, ...itemsData.current]);
+
+ setMovedObjects([]);
+ itemsData.current = [];
+ }
+ };
+
+ if (!toggleView) {
+ canvasElement.addEventListener("pointerdown", onPointerDown);
+ canvasElement.addEventListener("pointermove", onPointerMove);
+ canvasElement.addEventListener("pointerup", onPointerUp);
+ canvasElement.addEventListener("keydown", onKeyDown);
+ canvasElement?.addEventListener("keyup", onKeyUp);
}
- return null;
+ return () => {
+ canvasElement.removeEventListener("pointerdown", onPointerDown);
+ canvasElement.removeEventListener("pointermove", onPointerMove);
+ canvasElement.removeEventListener("pointerup", onPointerUp);
+ canvasElement.removeEventListener("keydown", onKeyDown);
+ canvasElement?.removeEventListener("keyup", onKeyUp);
+ };
+ }, [
+ camera,
+ controls,
+ scene,
+ toggleView,
+ selectedAssets,
+ socket,
+ floorItems,
+ pastedObjects,
+ duplicatedObjects,
+ movedObjects,
+ rotatedObjects,
+ keyEvent,
+ ]);
+
+ let moveSpeed = keyEvent === "Ctrl" || "Ctrl+Shift" ? 1 : 0.25;
+
+ useFrame(() => {
+ if (movedObjects.length > 0) {
+ const intersectionPoint = new THREE.Vector3();
+ raycaster.setFromCamera(pointer, camera);
+ const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
+
+ if (point) {
+ let targetX = point.x;
+ let targetZ = point.z;
+ if (keyEvent === "Ctrl") {
+ targetX = snapControls(targetX, "Ctrl");
+ targetZ = snapControls(targetZ, "Ctrl");
+ }
+ // else if (keyEvent === "Ctrl+Shift") {
+ // targetX = snapControls(targetX, "Ctrl+Shift");
+ // targetZ = snapControls(targetZ, "Ctrl+Shift");
+ // } else if (keyEvent === "Shift") {
+ // targetX = snapControls(targetX, "Shift");
+ // targetZ = snapControls(targetZ, "Shift");
+ // } else {
+ // }
+
+ const position = new THREE.Vector3();
+
+ if (boundingBoxRef.current) {
+ boundingBoxRef.current.getWorldPosition(position);
+ selectionGroup.current.position.lerp(
+ new THREE.Vector3(
+ targetX - (position.x - selectionGroup.current.position.x),
+ selectionGroup.current.position.y,
+ targetZ - (position.z - selectionGroup.current.position.z)
+ ),
+ moveSpeed
+ );
+ } else {
+ const box = new THREE.Box3();
+ movedObjects.forEach((obj: THREE.Object3D) =>
+ box.expandByObject(obj)
+ );
+ const center = new THREE.Vector3();
+ box.getCenter(center);
+
+ selectionGroup.current.position.lerp(
+ new THREE.Vector3(
+ targetX - (center.x - selectionGroup.current.position.x),
+ selectionGroup.current.position.y,
+ targetZ - (center.z - selectionGroup.current.position.z)
+ ),
+ moveSpeed
+ );
+ }
+ }
+ }
+ });
+
+ const moveAssets = () => {
+ const updatedItems = floorItems.filter(
+ (item: { modelUuid: string }) =>
+ !selectedAssets.some((asset: any) => asset.uuid === item.modelUuid)
+ );
+ setFloorItems(updatedItems);
+ setMovedObjects(selectedAssets);
+ selectedAssets.forEach((asset: any) => {
+ selectionGroup.current.attach(asset);
+ });
+ };
+
+ const placeMovedAssets = () => {
+ if (movedObjects.length === 0) return;
+
+ movedObjects.forEach(async (obj: THREE.Object3D) => {
+ const worldPosition = new THREE.Vector3();
+ obj.getWorldPosition(worldPosition);
+
+ selectionGroup.current.remove(obj);
+ obj.position.copy(worldPosition);
+
+ if (itemsGroupRef.current) {
+ const newFloorItem: Types.FloorItemType = {
+ modelUuid: obj.uuid,
+ modelName: obj.userData.name,
+ modelfileID: obj.userData.modelId,
+ position: [worldPosition.x, worldPosition.y, worldPosition.z],
+ rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
+ isLocked: false,
+ isVisible: true,
+ };
+
+ if (obj.userData.eventData) {
+ const eventData = useEventsStore
+ .getState()
+ .getEventByModelUuid(obj.userData.modelUuid);
+ const productData = useProductStore
+ .getState()
+ .getEventByModelUuid(
+ useSelectedProduct.getState().selectedProduct.productId,
+ obj.userData.modelUuid
+ );
+
+ if (eventData) {
+ useEventsStore.getState().updateEvent(obj.userData.modelUuid, {
+ position: [worldPosition.x, worldPosition.y, worldPosition.z],
+ rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z],
+ });
+ }
+ if (productData) {
+ const event = useProductStore
+ .getState()
+ .updateEvent(
+ useSelectedProduct.getState().selectedProduct.productId,
+ obj.userData.modelUuid,
+ {
+ position: [worldPosition.x, worldPosition.y, worldPosition.z],
+ rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z],
+ }
+ );
+
+ if (event) {
+ updateBackend(
+ selectedProduct.productName,
+ selectedProduct.productId,
+ organization,
+ event
+ );
+ }
+
+ newFloorItem.eventData = eventData;
+ }
+ }
+
+ setFloorItems((prevItems: Types.FloorItems) => {
+ const updatedItems = [...(prevItems || []), newFloorItem];
+ localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
+ return updatedItems;
+ });
+
+ //REST
+
+ // await setFloorItemApi(
+ // organization,
+ // obj.uuid,
+ // obj.userData.name,
+ // [worldPosition.x, worldPosition.y, worldPosition.z],
+ // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
+ // obj.userData.modelId,
+ // false,
+ // true,
+ // );
+
+ //SOCKET
+
+ const data = {
+ organization,
+ modelUuid: newFloorItem.modelUuid,
+ modelName: newFloorItem.modelName,
+ modelfileID: newFloorItem.modelfileID,
+ position: newFloorItem.position,
+ rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
+ isLocked: false,
+ isVisible: true,
+ socketId: socket.id,
+ };
+
+ socket.emit("v2:model-asset:add", data);
+
+ itemsGroupRef.current.add(obj);
+ }
+ });
+ toast.success("Object moved!");
+
+ itemsData.current = [];
+ clearSelection();
+ };
+
+ const clearSelection = () => {
+ selectionGroup.current.children = [];
+ selectionGroup.current.position.set(0, 0, 0);
+ selectionGroup.current.rotation.set(0, 0, 0);
+ setpastedObjects([]);
+ setDuplicatedObjects([]);
+ setMovedObjects([]);
+ setRotatedObjects([]);
+ setSelectedAssets([]);
+ setKeyEvent("");
+ };
+
+ return (
+
+ );
}
-export default MoveControls
\ No newline at end of file
+export default MoveControls;
diff --git a/app/src/modules/scene/controls/selectionControls/selectionControls.tsx b/app/src/modules/scene/controls/selectionControls/selectionControls.tsx
index 33a35c9..5041434 100644
--- a/app/src/modules/scene/controls/selectionControls/selectionControls.tsx
+++ b/app/src/modules/scene/controls/selectionControls/selectionControls.tsx
@@ -205,7 +205,7 @@ const SelectionControls: React.FC = () => {
const email = localStorage.getItem("email");
const organization = email!.split("@")[1].split(".")[0];
- const storedItems = JSON.parse(localStorage.getItem("FloorItems") || "[]");
+ const storedItems = JSON.parse(localStorage.getItem("FloorItems") ?? "[]");
const selectedUUIDs = selectedAssets.map((mesh: THREE.Object3D) => mesh.uuid);
const updatedStoredItems = storedItems.filter((item: { modelUuid: string }) => !selectedUUIDs.includes(item.modelUuid));
diff --git a/app/src/modules/simulation/actions/conveyor/actionHandler/useSpawnHandler.ts b/app/src/modules/simulation/actions/conveyor/actionHandler/useSpawnHandler.ts
index ab00964..dcd86b8 100644
--- a/app/src/modules/simulation/actions/conveyor/actionHandler/useSpawnHandler.ts
+++ b/app/src/modules/simulation/actions/conveyor/actionHandler/useSpawnHandler.ts
@@ -75,7 +75,7 @@ export function useSpawnHandler() {
isVisible: true,
isPaused: false,
isRendered: true,
- startTime:currentTime,
+ startTime: currentTime,
current: {
modelUuid: modelUuid,
pointUuid: pointUuid,
@@ -229,6 +229,6 @@ export function useSpawnHandler() {
return {
handleSpawn,
- clearCurrentSpawn: clearAllSpawns
+ clearAllSpawns
};
}
\ No newline at end of file
diff --git a/app/src/modules/simulation/actions/conveyor/useConveyorActions.ts b/app/src/modules/simulation/actions/conveyor/useConveyorActions.ts
index 1772444..600fae5 100644
--- a/app/src/modules/simulation/actions/conveyor/useConveyorActions.ts
+++ b/app/src/modules/simulation/actions/conveyor/useConveyorActions.ts
@@ -7,7 +7,7 @@ import { useDespawnHandler } from "./actionHandler/useDespawnHandler";
export function useConveyorActions() {
const { handleDefault } = useDefaultHandler();
- const { handleSpawn, clearCurrentSpawn } = useSpawnHandler();
+ const { handleSpawn, clearAllSpawns } = useSpawnHandler();
const { handleSwap } = useSwapHandler();
const { handleDespawn } = useDespawnHandler();
const { handleDelay, cleanupDelay } = useDelayHandler();
@@ -57,9 +57,9 @@ export function useConveyorActions() {
}, [handleDefaultAction, handleSpawnAction, handleSwapAction, handleDelayAction, handleDespawnAction]);
const cleanup = useCallback(() => {
- clearCurrentSpawn();
+ clearAllSpawns();
cleanupDelay();
- }, [clearCurrentSpawn, cleanupDelay]);
+ }, [clearAllSpawns, cleanupDelay]);
useEffect(() => {
return () => {
diff --git a/app/src/modules/simulation/actions/machine/actionHandler/useProcessHandler.ts b/app/src/modules/simulation/actions/machine/actionHandler/useProcessHandler.ts
new file mode 100644
index 0000000..a6bf16c
--- /dev/null
+++ b/app/src/modules/simulation/actions/machine/actionHandler/useProcessHandler.ts
@@ -0,0 +1,40 @@
+import { useCallback } from "react";
+import { useMaterialStore } from "../../../../../store/simulation/useMaterialStore";
+import { useMachineStore } from "../../../../../store/simulation/useMachineStore";
+import { useProductStore } from "../../../../../store/simulation/useProductStore";
+import { useSelectedProduct } from "../../../../../store/simulation/useSimulationStore";
+
+export function useProcessHandler() {
+ const { getMaterialById, setMaterial } = useMaterialStore();
+ const { addCurrentAction } = useMachineStore();
+ const { getModelUuidByActionUuid } = useProductStore();
+ const { selectedProduct } = useSelectedProduct();
+
+ const processLogStatus = (materialUuid: string, status: string) => {
+ // console.log(`${materialUuid}, ${status}`);
+ }
+
+ const handleProcess = useCallback((action: MachineAction, materialId?: string) => {
+ if (!action || action.actionType !== 'process' || !materialId) return;
+
+ const { swapMaterial: newMaterialType } = action;
+
+ const material = getMaterialById(materialId);
+ if (!material) return;
+
+ const modelUuid = getModelUuidByActionUuid(selectedProduct.productId, action.actionUuid);
+
+ if (!modelUuid) return;
+ setMaterial(material.materialId, newMaterialType);
+
+ addCurrentAction(modelUuid, action.actionUuid, newMaterialType, material.materialId);
+
+ processLogStatus(material.materialId, `Swapped to ${newMaterialType}`);
+ processLogStatus(material.materialId, `starts Process action`);
+
+ }, [getMaterialById]);
+
+ return {
+ handleProcess
+ };
+}
\ No newline at end of file
diff --git a/app/src/modules/simulation/actions/machine/useMachineActions.ts b/app/src/modules/simulation/actions/machine/useMachineActions.ts
index 38e8ce3..2bb0054 100644
--- a/app/src/modules/simulation/actions/machine/useMachineActions.ts
+++ b/app/src/modules/simulation/actions/machine/useMachineActions.ts
@@ -1,18 +1,19 @@
-import { useEffect, useCallback, useRef, useState } from 'react';
+import { useEffect, useCallback } from 'react';
+import { useProcessHandler } from './actionHandler/useProcessHandler';
export function useMachineActions() {
+ const { handleProcess } = useProcessHandler();
- const handleProcessAction = useCallback((action: MachineAction) => {
- if (!action || action.actionType !== 'process') return;
- console.log(`Machine processing for ${action.processTime}ms`);
- }, []);
+ const handleProcessAction = useCallback((action: MachineAction, materialId: string) => {
+ handleProcess(action, materialId);
+ }, [handleProcess]);
- const handleMachineAction = useCallback((action: MachineAction) => {
+ const handleMachineAction = useCallback((action: MachineAction, materialId: string) => {
if (!action) return;
switch (action.actionType) {
case 'process':
- handleProcessAction(action);
+ handleProcessAction(action, materialId);
break;
default:
console.warn(`Unknown machine action type: ${action.actionType}`);
diff --git a/app/src/modules/simulation/actions/roboticArm/actionHandler/usePickAndPlaceHandler.ts b/app/src/modules/simulation/actions/roboticArm/actionHandler/usePickAndPlaceHandler.ts
index 2f44cfe..5368a82 100644
--- a/app/src/modules/simulation/actions/roboticArm/actionHandler/usePickAndPlaceHandler.ts
+++ b/app/src/modules/simulation/actions/roboticArm/actionHandler/usePickAndPlaceHandler.ts
@@ -31,7 +31,7 @@ export function usePickAndPlaceHandler() {
material.materialId
);
- pickAndPlaceLogStatus(material.materialId, `if going to be picked by armBot ${modelUuid}`);
+ pickAndPlaceLogStatus(material.materialId, `is going to be picked by armBot ${modelUuid}`);
}, [getMaterialById, getModelUuidByActionUuid, addCurrentAction]);
diff --git a/app/src/modules/simulation/actions/storageUnit/actionHandler/useRetrieveHandler.ts b/app/src/modules/simulation/actions/storageUnit/actionHandler/useRetrieveHandler.ts
new file mode 100644
index 0000000..fbe51e5
--- /dev/null
+++ b/app/src/modules/simulation/actions/storageUnit/actionHandler/useRetrieveHandler.ts
@@ -0,0 +1,252 @@
+import { useCallback, useState, useEffect, useRef } from "react";
+import * as THREE from 'three';
+import { useFrame } from "@react-three/fiber";
+import { useMaterialStore } from "../../../../../store/simulation/useMaterialStore";
+import { useProductStore } from "../../../../../store/simulation/useProductStore";
+import { useSelectedProduct } from "../../../../../store/simulation/useSimulationStore";
+import { useStorageUnitStore } from "../../../../../store/simulation/useStorageUnitStore";
+import { useArmBotStore } from "../../../../../store/simulation/useArmBotStore";
+import { useVehicleStore } from "../../../../../store/simulation/useVehicleStore";
+import { usePlayButtonStore, usePauseButtonStore, useResetButtonStore } from "../../../../../store/usePlayButtonStore";
+
+export function useRetrieveHandler() {
+ const { addMaterial } = useMaterialStore();
+ const { getModelUuidByActionUuid, getPointUuidByActionUuid, getEventByModelUuid } = useProductStore();
+ const { getStorageUnitById, getLastMaterial, updateCurrentLoad, removeLastMaterial } = useStorageUnitStore();
+ const { getVehicleById, incrementVehicleLoad, addCurrentMaterial } = useVehicleStore();
+ const { selectedProduct } = useSelectedProduct();
+ const { getArmBotById, addCurrentAction } = useArmBotStore();
+ const { isPlaying } = usePlayButtonStore();
+ const { isPaused } = usePauseButtonStore();
+ const { isReset } = useResetButtonStore();
+
+ const [activeRetrievals, setActiveRetrievals] = useState
);
+ } else if (event.type === "storageUnit") {
+ return (
+
+ (sphereRefs.current[event.point.uuid] = el!)}
+ onClick={(e) => {
+ e.stopPropagation();
+ setSelectedEventSphere(
+ sphereRefs.current[event.point.uuid]
+ );
+ }}
+ position={new THREE.Vector3(...event.point.position)}
+ userData={{
+ modelUuid: event.modelUuid,
+ pointUuid: event.point.uuid,
+ }}
+ >
+
+
+
+
+ );
} else {
return null;
}
diff --git a/app/src/modules/simulation/machine/instances/animator/machineAnimator.tsx b/app/src/modules/simulation/machine/instances/animator/machineAnimator.tsx
index c4b4b44..8f1505f 100644
--- a/app/src/modules/simulation/machine/instances/animator/machineAnimator.tsx
+++ b/app/src/modules/simulation/machine/instances/animator/machineAnimator.tsx
@@ -1,5 +1,4 @@
-import { useFrame } from '@react-three/fiber';
-import React, { useEffect, useRef } from 'react';
+import { useEffect, useRef } from 'react';
import { useMachineStore } from '../../../../../store/simulation/useMachineStore';
import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore';
@@ -21,22 +20,19 @@ const MachineAnimator = ({ currentPhase, handleCallBack, processingTime, machine
const pauseTimeRef = useRef(null);
const { isPaused } = usePauseButtonStore();
const { removeCurrentAction } = useMachineStore();
- const { isReset, setReset } = useResetButtonStore();
+ const { isReset } = useResetButtonStore();
const { isPlaying } = usePlayButtonStore();
const { speed } = useAnimationPlaySpeed();
const isPlayingRef = useRef(false);
- const isResetRef = useRef(false)
-
useEffect(() => {
isPausedRef.current = isPaused;
}, [isPaused]);
+
useEffect(() => {
isPlayingRef.current = isPlaying;
}, [isPlaying]);
-
-
useEffect(() => {
if (isReset || !isPlaying) {
reset();
@@ -49,8 +45,6 @@ const MachineAnimator = ({ currentPhase, handleCallBack, processingTime, machine
}
}, [isReset, isPlaying])
-
-
useEffect(() => {
if (currentPhase === 'processing' && !animationStarted.current && machineUuid) {
animationStarted.current = true;
@@ -94,8 +88,6 @@ const MachineAnimator = ({ currentPhase, handleCallBack, processingTime, machine
}
}
-
-
return null;
}
diff --git a/app/src/modules/simulation/machine/instances/machineInstance/machineInstance.tsx b/app/src/modules/simulation/machine/instances/machineInstance/machineInstance.tsx
index b3d4498..525c9c9 100644
--- a/app/src/modules/simulation/machine/instances/machineInstance/machineInstance.tsx
+++ b/app/src/modules/simulation/machine/instances/machineInstance/machineInstance.tsx
@@ -1,13 +1,19 @@
-import React, { useEffect, useRef, useState } from 'react'
+import { useEffect, useRef, useState } from 'react'
import { useMachineStore } from '../../../../../store/simulation/useMachineStore';
import { usePlayButtonStore } from '../../../../../store/usePlayButtonStore';
import MachineAnimator from '../animator/machineAnimator';
+import { useProductStore } from '../../../../../store/simulation/useProductStore';
+import { useSelectedProduct } from '../../../../../store/simulation/useSimulationStore';
+import { useTriggerHandler } from '../../../triggers/triggerHandler/useTriggerHandler';
-function MachineInstance({ machineDetail }: any) {
+function MachineInstance({ machineDetail }: { machineDetail: MachineStatus }) {
const [currentPhase, setCurrentPhase] = useState('idle');
let isIncrememtable = useRef(true);
const { isPlaying } = usePlayButtonStore();
- const { machines, addCurrentAction, setMachineState, setMachineActive } = useMachineStore();
+ const { machines, setMachineState, setMachineActive } = useMachineStore();
+ const { selectedProduct } = useSelectedProduct();
+ const { getActionByUuid } = useProductStore();
+ const { triggerPointActions } = useTriggerHandler();
const reset = () => {
setCurrentPhase("idle");
@@ -15,23 +21,14 @@ function MachineInstance({ machineDetail }: any) {
setMachineActive(machineDetail.modelUuid, false);
isIncrememtable.current = true;
}
- const increment = () => {
- if (isIncrememtable.current) {
- addCurrentAction(machineDetail.modelUuid, "machine-action-2468-1357-8024")
- isIncrememtable.current = false;
- }
- }
+
function machineStatus(modelId: string, status: string) {
// console.log(`${modelId} , ${status}`);
-
}
useEffect(() => {
if (isPlaying) {
if (!machineDetail.isActive && machineDetail.state === "idle" && currentPhase == "idle" && !machineDetail.currentAction) {
- setTimeout(() => {
- increment();
- }, 5000);
machineStatus(machineDetail.modelUuid, 'Machine is idle and waiting for next instruction.')
} else if (!machineDetail.isActive && machineDetail.state === "idle" && currentPhase == "idle" && machineDetail.currentAction) {
setCurrentPhase("processing");
@@ -49,11 +46,15 @@ function MachineInstance({ machineDetail }: any) {
setCurrentPhase("idle")
isIncrememtable.current = true;
machineStatus(machineDetail.modelUuid, "Machine has completed the processing")
+
+ if (machineDetail.currentAction) {
+ const action = getActionByUuid(selectedProduct.productId, machineDetail.currentAction.actionUuid);
+ if (action && machineDetail.currentAction.materialId) {
+ triggerPointActions(action, machineDetail.currentAction.materialId)
+ }
+ }
}
}
- // console.log('currentPhase: ', currentPhase);
-
-
return (
<>
diff --git a/app/src/modules/simulation/machine/instances/machineInstances.tsx b/app/src/modules/simulation/machine/instances/machineInstances.tsx
index 594265d..e228b01 100644
--- a/app/src/modules/simulation/machine/instances/machineInstances.tsx
+++ b/app/src/modules/simulation/machine/instances/machineInstances.tsx
@@ -1,17 +1,20 @@
-import React from 'react'
-import MachineInstance from './machineInstance/machineInstance'
-import { useMachineStore } from '../../../../store/simulation/useMachineStore';
+import React from "react";
+import MachineInstance from "./machineInstance/machineInstance";
+import { useMachineStore } from "../../../../store/simulation/useMachineStore";
+import MachineContentUi from "../../ui3d/MachineContentUi";
function MachineInstances() {
const { machines } = useMachineStore();
return (
<>
{machines.map((machine: MachineStatus) => (
-
+
+
+
+
))}
-
>
- )
+ );
}
-export default MachineInstances
\ No newline at end of file
+export default MachineInstances;
diff --git a/app/src/modules/simulation/machine/machine.tsx b/app/src/modules/simulation/machine/machine.tsx
index 3d24f61..9e16e83 100644
--- a/app/src/modules/simulation/machine/machine.tsx
+++ b/app/src/modules/simulation/machine/machine.tsx
@@ -1,48 +1,6 @@
-import React, { useEffect } from 'react'
import MachineInstances from './instances/machineInstances'
-import { useMachineStore } from '../../../store/simulation/useMachineStore'
-import { useSelectedProduct } from '../../../store/simulation/useSimulationStore';
function Machine() {
- const { addMachine, addCurrentAction, removeMachine, machines } = useMachineStore();
- const { selectedProduct } = useSelectedProduct();
-
- const machineSample: MachineEventSchema[] = [
- {
- modelUuid: "machine-1234-5678-9012",
- modelName: "CNC Milling Machine",
- position: [10, 0, 5],
- rotation: [0, 0, 0],
- state: "idle",
- type: "machine",
- point: {
- uuid: "machine-point-9876-5432-1098",
- position: [10, 0.5, 5.2],
- rotation: [0, 0, 0],
- action: {
- actionUuid: "machine-action-2468-1357-8024",
- actionName: "Metal Processing",
- actionType: "process",
- processTime: 10,
- swapMaterial: "steel",
- triggers: []
- }
- }
- }
- ];
-
- useEffect(() => {
- removeMachine(machineSample[0].modelUuid);
- addMachine(selectedProduct.productId, machineSample[0]);
-
- // addCurrentAction(machineSample[0].modelUuid, machineSample[0].point.action.actionUuid);
- }, [])
-
-
- useEffect(() => {
-
- // console.log('machines: ', machines);
- }, [machines])
return (
<>
diff --git a/app/src/modules/simulation/materials/instances/material/materialModel.tsx b/app/src/modules/simulation/materials/instances/material/materialModel.tsx
index 2093584..244c7bf 100644
--- a/app/src/modules/simulation/materials/instances/material/materialModel.tsx
+++ b/app/src/modules/simulation/materials/instances/material/materialModel.tsx
@@ -21,7 +21,7 @@ interface ModelProps extends React.ComponentProps<'group'> {
matRef: React.Ref>
}
-export function MaterialModel({ materialType, matRef, ...props }: ModelProps) {
+export function MaterialModel({ materialType, matRef, ...props }: Readonly) {
const path = modelPaths[materialType] || modelPaths['Default material'];
const gltf = useGLTF(path);
const cloned = useMemo(() => gltf?.scene.clone(), [gltf]);
diff --git a/app/src/modules/simulation/products/products.tsx b/app/src/modules/simulation/products/products.tsx
index 4a4807d..9536caa 100644
--- a/app/src/modules/simulation/products/products.tsx
+++ b/app/src/modules/simulation/products/products.tsx
@@ -8,6 +8,8 @@ import { getAllProductsApi } from '../../../services/simulation/getallProductsAp
import { useVehicleStore } from '../../../store/simulation/useVehicleStore';
import { useArmBotStore } from '../../../store/simulation/useArmBotStore';
import { useConveyorStore } from '../../../store/simulation/useConveyorStore';
+import { useMachineStore } from '../../../store/simulation/useMachineStore';
+import { useStorageUnitStore } from '../../../store/simulation/useStorageUnitStore';
import { useResetButtonStore } from '../../../store/usePlayButtonStore';
function Products() {
@@ -15,7 +17,9 @@ function Products() {
const { selectedProduct, setSelectedProduct } = useSelectedProduct();
const { addVehicle, clearvehicles } = useVehicleStore();
const { addArmBot, clearArmBots } = useArmBotStore();
+ const { addMachine, clearMachines } = useMachineStore();
const { addConveyor, clearConveyors } = useConveyorStore();
+ const { setCurrentMaterials, clearStorageUnits, updateCurrentLoad, addStorageUnit } = useStorageUnitStore();
const { isReset } = useResetButtonStore();
useEffect(() => {
@@ -77,6 +81,48 @@ function Products() {
}
}, [selectedProduct, products, isReset]);
+ useEffect(() => {
+ if (selectedProduct.productId) {
+ const product = getProductById(selectedProduct.productId);
+ if (product) {
+ clearMachines();
+ product.eventDatas.forEach(events => {
+ if (events.type === 'machine') {
+ addMachine(selectedProduct.productId, events);
+ }
+ });
+ }
+ }
+ }, [selectedProduct, products, isReset]);
+
+ useEffect(() => {
+ if (selectedProduct.productId) {
+ const product = getProductById(selectedProduct.productId);
+ if (product) {
+ clearStorageUnits();
+ product.eventDatas.forEach(event => {
+ if (event.type === 'storageUnit') {
+ addStorageUnit(selectedProduct.productId, event);
+
+ if (event.point.action.actionType === 'retrieve') {
+ const storageAction = event.point.action as StorageAction;
+ const materials = Array.from({ length: storageAction.storageCapacity }, () => ({
+ materialType: storageAction.materialType || 'Default material',
+ materialId: THREE.MathUtils.generateUUID()
+ }));
+
+ setCurrentMaterials(event.modelUuid, materials);
+ updateCurrentLoad(event.modelUuid, storageAction.storageCapacity);
+ } else {
+ setCurrentMaterials(event.modelUuid, []);
+ updateCurrentLoad(event.modelUuid, 0);
+ }
+ }
+ });
+ }
+ }
+ }, [selectedProduct, products, isReset]);
+
return (
<>
diff --git a/app/src/modules/simulation/roboticArm/instances/animator/materialAnimator.tsx b/app/src/modules/simulation/roboticArm/instances/animator/materialAnimator.tsx
index 7ba6148..83745aa 100644
--- a/app/src/modules/simulation/roboticArm/instances/animator/materialAnimator.tsx
+++ b/app/src/modules/simulation/roboticArm/instances/animator/materialAnimator.tsx
@@ -1,5 +1,5 @@
import { useFrame } from '@react-three/fiber';
-import React, { useEffect, useRef, useState } from 'react';
+import { useEffect, useRef, useState } from 'react';
import * as THREE from 'three';
import { MaterialModel } from '../../../materials/instances/material/materialModel';
@@ -9,7 +9,7 @@ type MaterialAnimatorProps = {
currentPhase: string;
};
-export default function MaterialAnimator({ ikSolver, armBot, currentPhase }: MaterialAnimatorProps) {
+export default function MaterialAnimator({ ikSolver, armBot, currentPhase }: Readonly) {
const sphereRef = useRef(null);
const [isRendered, setIsRendered] = useState(false);
@@ -58,7 +58,7 @@ export default function MaterialAnimator({ ikSolver, armBot, currentPhase }: Mat
{isRendered && (
)}
>
diff --git a/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx
index be8c561..b457acc 100644
--- a/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx
+++ b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx
@@ -186,12 +186,12 @@ function RoboticArmAnimator({ HandleCallback, restPosition, ikSolver, targetBone
new THREE.Vector3(end[0], curveHeight, end[2]),
new THREE.Vector3(end[0], end[1], end[2])
];
-
+
const pathSegments: [THREE.Vector3, THREE.Vector3][] = [];
for (let i = 0; i < pathVectors.length - 1; i++) {
pathSegments.push([pathVectors[i], pathVectors[i + 1]]);
}
-
+
const segmentDistances = pathSegments.map(([p1, p2]) => p1.distanceTo(p2));
segmentDistancesRef.current = segmentDistances;
const totalDistance = segmentDistances.reduce((sum, d) => sum + d, 0);
@@ -209,11 +209,6 @@ function RoboticArmAnimator({ HandleCallback, restPosition, ikSolver, targetBone
if (!bone) return;
if (isPlaying) {
- if (isReset) {
- bone.position.copy(restPosition);
- setCustomCurvePoints([]);
- ikSolver.update();
- }
if (!isPaused && customCurvePoints && customCurvePoints.length > 0) {
const distances = segmentDistancesRef.current;
const totalDistance = totalDistanceRef.current;
@@ -248,7 +243,6 @@ function RoboticArmAnimator({ HandleCallback, restPosition, ikSolver, targetBone
progressRef.current = 0;
startTimeRef.current = null;
}
-
ikSolver.update();
}
} else if (!isPlaying && currentPath.length === 0) {
@@ -257,9 +251,8 @@ function RoboticArmAnimator({ HandleCallback, restPosition, ikSolver, targetBone
setCurrentPath([]);
setCustomCurvePoints([]);
bone.position.copy(restPosition);
-
+ ikSolver.update();
}
- ikSolver.update();
});
//Helper to Visible the Circle and Curve
diff --git a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx
index 75e7715..a26635f 100644
--- a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx
+++ b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx
@@ -10,6 +10,7 @@ import { useMaterialStore } from '../../../../../store/simulation/useMaterialSto
import { useArmBotStore } from '../../../../../store/simulation/useArmBotStore';
import { useProductStore } from '../../../../../store/simulation/useProductStore';
import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore';
+import { useStorageUnitStore } from '../../../../../store/simulation/useStorageUnitStore';
import { useSelectedProduct } from '../../../../../store/simulation/useSimulationStore';
import { useTriggerHandler } from '../../../triggers/triggerHandler/useTriggerHandler';
@@ -28,9 +29,10 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
const { setArmBotActive, setArmBotState, removeCurrentAction } = useArmBotStore();
const { decrementVehicleLoad, removeLastMaterial } = useVehicleStore();
+ const { removeLastMaterial: removeLastStorageMaterial, updateCurrentLoad } = useStorageUnitStore();
const { setIsVisible, getMaterialById } = useMaterialStore();
const { selectedProduct } = useSelectedProduct();
- const { getActionByUuid, getEventByModelUuid } = useProductStore();
+ const { getActionByUuid, getEventByActionUuid, getEventByModelUuid } = useProductStore();
const { triggerPointActions } = useTriggerHandler();
const { isPlaying } = usePlayButtonStore();
const { isReset } = useResetButtonStore();
@@ -41,6 +43,59 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
step();
}
+ const action = getActionByUuid(selectedProduct.productId, armBot.currentAction?.actionUuid || '');
+
+ const handlePickUpTrigger = () => {
+ if (armBot.currentAction && armBot.currentAction.materialId) {
+ const material = getMaterialById(armBot.currentAction.materialId);
+ if (material && material.previous && material.previous.modelUuid) {
+ const previousModel = getEventByActionUuid(selectedProduct.productId, material.previous.actionUuid);
+ if (previousModel) {
+ if (previousModel.type === 'transfer') {
+ setIsVisible(armBot.currentAction.materialId, false);
+ } else if (previousModel.type === 'machine') {
+ // machine specific logic
+ } else if (previousModel.type === 'vehicle') {
+ decrementVehicleLoad(previousModel.modelUuid, 1);
+ removeLastMaterial(previousModel.modelUuid);
+ } else if (previousModel.type === 'storageUnit') {
+ // storage unit logic
+ removeLastStorageMaterial(previousModel.modelUuid);
+ updateCurrentLoad(previousModel.modelUuid, -1)
+ }
+ } else {
+ setIsVisible(armBot.currentAction.materialId, false);
+ }
+ } else {
+ setIsVisible(armBot.currentAction.materialId, false);
+ }
+ }
+ }
+
+ const handleDropTrigger = () => {
+
+ if (armBot.currentAction) {
+ const action = getActionByUuid(selectedProduct.productId, armBot.currentAction.actionUuid);
+ if (action && action.triggers[0].triggeredAsset?.triggeredModel.modelUuid) {
+ const model = getEventByModelUuid(selectedProduct.productId, action?.triggers[0].triggeredAsset?.triggeredModel.modelUuid);
+ if (!model) return;
+ if (model.type === 'transfer') {
+ setIsVisible(armBot.currentAction.materialId || '', true);
+ } else if (model.type === 'machine') {
+ //
+ } else if (model.type === 'vehicle') {
+ //
+ } else if (model.type === 'storageUnit') {
+ //
+ }
+ }
+ if (action && armBot.currentAction.materialId) {
+ triggerPointActions(action, armBot.currentAction.materialId)
+ removeCurrentAction(armBot.modelUuid)
+ }
+ }
+ }
+
function step() {
if (isPausedRef.current) {
if (!pauseTimeRef.current) {
@@ -65,8 +120,9 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
setArmBotState(armBot.modelUuid, "running");
setCurrentPhase("start-to-end");
startTime = 0
- const startPoint = armBot.point.actions[0].process.startPoint;
- const endPoint = armBot.point.actions[0].process.endPoint;
+ if (!action) return;
+ const startPoint = (action as RoboticArmAction).process.startPoint;
+ const endPoint = (action as RoboticArmAction).process.endPoint;
if (startPoint && endPoint) {
let curve = createCurveBetweenTwoPoints(
new THREE.Vector3(startPoint[0], startPoint[1], startPoint[2]),
@@ -75,30 +131,8 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
logStatus(armBot.modelUuid, "picking the object");
setPath(curve.points.map(point => [point.x, point.y, point.z]))
- if (armBot.currentAction && armBot.currentAction.materialId) {
- const material = getMaterialById(armBot.currentAction.materialId)
- if (material && material.previous && material.previous.modelUuid) {
+ handlePickUpTrigger();
- const model = getEventByModelUuid(selectedProduct.productId, material.previous.modelUuid);
-
- if (model) {
- if (model.type === 'transfer') {
- setIsVisible(armBot.currentAction.materialId, false);
- } else if (model.type === 'machine') {
-
- } else if (model.type === 'vehicle') {
- decrementVehicleLoad(model.modelUuid, 1);
- removeLastMaterial(model.modelUuid);
- } else if (model.type === 'storageUnit') {
-
- }
- } else {
- setIsVisible(armBot.currentAction.materialId, false);
- }
- } else {
- setIsVisible(armBot.currentAction.materialId, false);
- }
- }
}
}
logStatus(armBot.modelUuid, "Moving armBot from start point to end position.")
@@ -107,7 +141,8 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
setArmBotState(armBot.modelUuid, "running");
setCurrentPhase("end-to-rest");
startTime = 0;
- const endPoint = armBot.point.actions[0].process.endPoint;
+ if (!action) return;
+ const endPoint = (action as RoboticArmAction).process.endPoint;
if (endPoint) {
let curve = createCurveBetweenTwoPoints(new THREE.Vector3(endPoint[0], endPoint[1], endPoint[2]), restPosition);
@@ -115,17 +150,8 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
logStatus(armBot.modelUuid, "dropping the object");
setPath(curve.points.map(point => [point.x, point.y, point.z]));
- if (armBot.currentAction) {
- setIsVisible(armBot.currentAction.materialId || '', true);
- }
+ handleDropTrigger();
- if (armBot.currentAction) {
- const action = getActionByUuid(selectedProduct.productId, armBot.currentAction.actionUuid);
- if (action && armBot.currentAction.materialId) {
- triggerPointActions(action, armBot.currentAction.materialId)
- removeCurrentAction(armBot.modelUuid)
- }
- }
}
}
logStatus(armBot.modelUuid, "Moving armBot from end point to rest position.")
@@ -190,7 +216,8 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
setArmBotActive(armBot.modelUuid, true);
setArmBotState(armBot.modelUuid, "running");
setCurrentPhase("rest-to-start");
- const startPoint = armBot.point.actions[0].process.startPoint;
+ if (!action) return;
+ const startPoint = (action as RoboticArmAction).process.startPoint;
if (startPoint) {
let curve = createCurveBetweenTwoPoints(targetBones.position, new THREE.Vector3(startPoint[0], startPoint[1], startPoint[2]));
if (curve) {
@@ -232,6 +259,7 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
}
const HandleCallback = () => {
+
if (armBot.isActive && armBot.state == "running" && currentPhase == "init-to-rest") {
logStatus(armBot.modelUuid, "Callback triggered: rest");
setArmBotActive(armBot.modelUuid, false)
@@ -262,6 +290,7 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
}
}
const logStatus = (id: string, status: string) => {
+ // console.log('status: ', status);
}
return (
@@ -269,8 +298,16 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
{!isReset && isPlaying && (
<>
-
+
>
)}
diff --git a/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx b/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx
index fc0865c..f57fbcd 100644
--- a/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx
+++ b/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx
@@ -1,21 +1,21 @@
import RoboticArmInstance from "./armInstance/roboticArmInstance";
import { useArmBotStore } from "../../../../store/simulation/useArmBotStore";
-import RoboticArmContentUi from "../../ui3d/RoboticArmContentUi";
+// import RoboticArmContentUi from "../../ui3d/RoboticArmContentUi";
import React from "react";
function RoboticArmInstances() {
- const { armBots } = useArmBotStore();
+ const { armBots } = useArmBotStore();
- return (
- <>
- {armBots?.map((robot: ArmBotStatus) => (
-
-
-
-
- ))}
- >
- );
+ return (
+ <>
+ {armBots?.map((robot: ArmBotStatus) => (
+
+
+ {/* */}
+
+ ))}
+ >
+ );
}
export default RoboticArmInstances;
diff --git a/app/src/modules/simulation/simulator/functions/determineExecutionMachineSequences.ts b/app/src/modules/simulation/simulator/functions/determineExecutionMachineSequences.ts
new file mode 100644
index 0000000..211b28f
--- /dev/null
+++ b/app/src/modules/simulation/simulator/functions/determineExecutionMachineSequences.ts
@@ -0,0 +1,101 @@
+import { extractTriggersFromPoint } from "./extractTriggersFromPoint";
+
+export async function determineExecutionMachineSequences(products: productsSchema): Promise {
+ const pointToEventMap = new Map();
+ const allPoints: PointsScheme[] = [];
+
+ // First pass: map points to their corresponding events
+ products.forEach(product => {
+ product.eventDatas.forEach(event => {
+ if (event.type === 'transfer') {
+ event.points.forEach(point => {
+ pointToEventMap.set(point.uuid, event);
+ allPoints.push(point);
+ });
+ } else if (
+ event.type === 'vehicle' ||
+ event.type === 'machine' ||
+ event.type === 'storageUnit' ||
+ event.type === 'roboticArm'
+ ) {
+ pointToEventMap.set(event.point.uuid, event);
+ allPoints.push(event.point);
+ }
+ });
+ });
+
+ // Build dependency graph
+ const dependencyGraph = new Map();
+ const reverseDependencyGraph = new Map();
+ const triggeredPoints = new Set();
+
+ allPoints.forEach(point => {
+ const triggers = extractTriggersFromPoint(point);
+ const dependencies: string[] = [];
+
+ triggers.forEach(trigger => {
+ const targetUuid = trigger.triggeredAsset?.triggeredPoint?.pointUuid;
+ if (targetUuid && pointToEventMap.has(targetUuid)) {
+ dependencies.push(targetUuid);
+ triggeredPoints.add(targetUuid);
+
+ if (!reverseDependencyGraph.has(targetUuid)) {
+ reverseDependencyGraph.set(targetUuid, []);
+ }
+ reverseDependencyGraph.get(targetUuid)!.push(point.uuid);
+ }
+ });
+
+ dependencyGraph.set(point.uuid, dependencies);
+ });
+
+ // Find root points (points that trigger others but are not triggered themselves)
+ const rootPoints = allPoints.filter(point => {
+ const hasOutgoingTriggers = extractTriggersFromPoint(point).some(
+ t => t.triggeredAsset?.triggeredPoint?.pointUuid
+ );
+ return hasOutgoingTriggers && !triggeredPoints.has(point.uuid);
+ });
+
+ const executionSequences: EventsSchema[][] = [];
+
+ function buildSequence(startUuid: string): EventsSchema[] {
+ const sequence: EventsSchema[] = [];
+ const visited = new Set();
+
+ function traverse(uuid: string) {
+ if (visited.has(uuid)) return;
+ visited.add(uuid);
+
+ const event = pointToEventMap.get(uuid);
+ if (event && !sequence.includes(event)) {
+ sequence.push(event);
+ }
+
+ const nextPoints = dependencyGraph.get(uuid) || [];
+ nextPoints.forEach(nextUuid => traverse(nextUuid));
+ }
+
+ traverse(startUuid);
+ return sequence;
+ }
+
+ // Build sequences from root points
+ rootPoints.forEach(root => {
+ executionSequences.push(buildSequence(root.uuid));
+ });
+
+ // Handle any isolated triggered points
+ const processedEvents = new Set(
+ executionSequences.flat().map(event => event)
+ );
+
+ allPoints.forEach(point => {
+ const event = pointToEventMap.get(point.uuid);
+ if (triggeredPoints.has(point.uuid) && event && !processedEvents.has(event)) {
+ executionSequences.push(buildSequence(point.uuid));
+ }
+ });
+
+ return executionSequences;
+}
\ No newline at end of file
diff --git a/app/src/modules/simulation/simulator/functions/determineExecutionOrder.ts b/app/src/modules/simulation/simulator/functions/determineExecutionOrder.ts
index fd42547..1f29ab3 100644
--- a/app/src/modules/simulation/simulator/functions/determineExecutionOrder.ts
+++ b/app/src/modules/simulation/simulator/functions/determineExecutionOrder.ts
@@ -18,10 +18,8 @@ export function determineExecutionOrder(products: productsSchema): PointsScheme[
});
} else if (event.type === 'vehicle' ||
event.type === 'machine' ||
- event.type === 'storageUnit') {
- pointMap.set(event.point.uuid, event.point);
- allPoints.push(event.point);
- } else if (event.type === 'roboticArm') {
+ event.type === 'storageUnit' ||
+ event.type === 'roboticArm') {
pointMap.set(event.point.uuid, event.point);
allPoints.push(event.point);
}
diff --git a/app/src/modules/simulation/simulator/functions/determineExecutionSequences.ts b/app/src/modules/simulation/simulator/functions/determineExecutionSequences.ts
index afd5324..bb88fb5 100644
--- a/app/src/modules/simulation/simulator/functions/determineExecutionSequences.ts
+++ b/app/src/modules/simulation/simulator/functions/determineExecutionSequences.ts
@@ -1,6 +1,6 @@
import { extractTriggersFromPoint } from "./extractTriggersFromPoint";
-export function determineExecutionSequences(products: productsSchema): PointsScheme[][] {
+export async function determineExecutionSequences(products: productsSchema): Promise {
// Create maps for all points
const pointMap = new Map();
const allPoints: PointsScheme[] = [];
diff --git a/app/src/modules/simulation/simulator/simulator.tsx b/app/src/modules/simulation/simulator/simulator.tsx
index 8c9d8f0..d6ff2fa 100644
--- a/app/src/modules/simulation/simulator/simulator.tsx
+++ b/app/src/modules/simulation/simulator/simulator.tsx
@@ -14,7 +14,7 @@ function Simulator() {
if (!isPlaying || isReset) return;
const executionOrder = determineExecutionOrder(products);
- executionOrder.map(point => {
+ executionOrder.forEach(point => {
const action = 'actions' in point ? point.actions[0] : point.action;
handleAction(action);
});
diff --git a/app/src/modules/simulation/spatialUI/arm/armBotUI.tsx b/app/src/modules/simulation/spatialUI/arm/armBotUI.tsx
index 4e1b01c..55e511a 100644
--- a/app/src/modules/simulation/spatialUI/arm/armBotUI.tsx
+++ b/app/src/modules/simulation/spatialUI/arm/armBotUI.tsx
@@ -3,6 +3,7 @@ import { useSelectedAction, useSelectedEventSphere, useSelectedProduct } from '.
import { useGLTF } from '@react-three/drei';
import { useThree } from '@react-three/fiber';
import { useProductStore } from '../../../../store/simulation/useProductStore';
+import { useArmBotStore } from '../../../../store/simulation/useArmBotStore';
import PickDropPoints from './PickDropPoints';
import useDraggableGLTF from './useDraggableGLTF';
import * as THREE from 'three';
@@ -23,6 +24,7 @@ const ArmBotUI = () => {
const { selectedProduct } = useSelectedProduct();
const { scene } = useThree();
const { selectedAction } = useSelectedAction();
+ const { armBots } = useArmBotStore();
const armUiPick = useGLTF(armPick) as any;
const armUiDrop = useGLTF(armDrop) as any;
@@ -53,7 +55,7 @@ const ArmBotUI = () => {
if (selectedEventSphere) {
const selectedArmBot = getEventByModelUuid(selectedProduct.productId, selectedEventSphere.userData.modelUuid);
- if (selectedArmBot?.type === "roboticArm") {
+ if (selectedArmBot?.type === "roboticArm" && selectedAction.actionId) {
setSelectedArmBotData(selectedArmBot);
const defaultPositions = getDefaultPositions(selectedArmBot.modelUuid);
const matchingAction = getActionByUuid(selectedProduct.productId, selectedAction.actionId);
@@ -73,7 +75,7 @@ const ArmBotUI = () => {
}
}
}
- }, [selectedEventSphere, selectedProduct, getEventByModelUuid, selectedAction]);
+ }, [armBots, selectedEventSphere, selectedProduct, getEventByModelUuid, selectedAction]);
function getDefaultPositions(modelUuid: string): Positions {
const modelData = getEventByModelUuid(selectedProduct.productId, modelUuid);
diff --git a/app/src/modules/simulation/spatialUI/vehicle/vehicleUI.tsx b/app/src/modules/simulation/spatialUI/vehicle/vehicleUI.tsx
index 843b81b..bb690d4 100644
--- a/app/src/modules/simulation/spatialUI/vehicle/vehicleUI.tsx
+++ b/app/src/modules/simulation/spatialUI/vehicle/vehicleUI.tsx
@@ -23,7 +23,7 @@ const VehicleUI = () => {
const prevMousePos = useRef({ x: 0, y: 0 });
const { selectedEventSphere } = useSelectedEventSphere();
const { selectedProduct } = useSelectedProduct();
- const { getVehicleById } = useVehicleStore();
+ const { vehicles, getVehicleById } = useVehicleStore();
const { updateEvent } = useProductStore();
const [startPosition, setStartPosition] = useState<[number, number, number]>([
0, 1, 0,
@@ -144,7 +144,7 @@ const VehicleUI = () => {
setSteeringRotation([0, steeringAngle, 0]);
}
}, 10);
- }, [selectedEventSphere, outerGroup.current]);
+ }, [selectedEventSphere, outerGroup.current, vehicles]);
const handlePointerDown = (
e: any,
diff --git a/app/src/modules/simulation/storageUnit/instances/animator/MaterialAnimator.tsx b/app/src/modules/simulation/storageUnit/instances/animator/MaterialAnimator.tsx
new file mode 100644
index 0000000..4ddc374
--- /dev/null
+++ b/app/src/modules/simulation/storageUnit/instances/animator/MaterialAnimator.tsx
@@ -0,0 +1,75 @@
+import React, { useEffect, useRef, useState, useMemo } from "react";
+import { MaterialModel } from "../../../materials/instances/material/materialModel";
+import { Object3D, Box3, Vector3 } from "three";
+import { useThree } from "@react-three/fiber";
+
+const MaterialAnimator = ({
+ storage,
+}: Readonly<{ storage: StorageUnitStatus }>) => {
+ const meshRef = useRef(null!);
+ const [hasLoad, setHasLoad] = useState(false);
+ const { scene } = useThree();
+ const padding = 0.1;
+
+ useEffect(() => {
+ setHasLoad(storage.currentLoad > 0);
+ }, [storage.currentLoad]);
+
+ const storageModel = useMemo(() => {
+ return scene.getObjectByProperty("uuid", storage.modelUuid) as Object3D;
+ }, [scene, storage.modelUuid]);
+
+ const materialPositions = useMemo(() => {
+ if (!storageModel || storage.currentMaterials.length === 0) return [];
+
+ const box = new Box3().setFromObject(storageModel);
+ const size = new Vector3();
+ box.getSize(size);
+
+ const matCount = storage.currentMaterials.length;
+
+ // Assumed size each material needs in world units
+ const materialWidth = 0.45;
+ const materialDepth = 0.45;
+ const materialHeight = 0.3;
+
+ const cols = Math.floor(size.x / materialWidth);
+ const rows = Math.floor(size.z / materialDepth);
+ const itemsPerLayer = cols * rows;
+
+ const origin = new Vector3(
+ box.min.x + materialWidth / 2,
+ box.max.y + padding, // slightly above the surface
+ box.min.z + materialDepth / 2
+ );
+
+ return Array.from({ length: matCount }, (_, i) => {
+ const layer = Math.floor(i / itemsPerLayer);
+ const layerIndex = i % itemsPerLayer;
+ const row = Math.floor(layerIndex / cols);
+ const col = layerIndex % cols;
+
+ return new Vector3(
+ origin.x + col * materialWidth,
+ origin.y + layer * (materialHeight + padding),
+ origin.z + row * materialDepth
+ );
+ });
+ }, [storageModel, storage.currentMaterials]);
+
+ return (
+
+ {hasLoad &&
+ storage.currentMaterials.map((mat, index) => (
+
+ ))}
+
+ );
+};
+
+export default MaterialAnimator;
diff --git a/app/src/modules/simulation/storageUnit/instances/storageUnitInstance/storageUnitInstance.tsx b/app/src/modules/simulation/storageUnit/instances/storageUnitInstance/storageUnitInstance.tsx
index 29d404e..b0f0514 100644
--- a/app/src/modules/simulation/storageUnit/instances/storageUnitInstance/storageUnitInstance.tsx
+++ b/app/src/modules/simulation/storageUnit/instances/storageUnitInstance/storageUnitInstance.tsx
@@ -1,10 +1,15 @@
-import React from 'react'
+import React, { useEffect } from 'react'
+import MaterialAnimator from '../animator/MaterialAnimator'
+
+function StorageUnitInstance({ storageUnit }: Readonly<{ storageUnit: StorageUnitStatus }>) {
+
+ useEffect(()=>{
+ // console.log('storageUnit: ', storageUnit);
+ },[storageUnit])
-function storageUnitInstance() {
return (
- <>
- >
+
)
}
-export default storageUnitInstance
\ No newline at end of file
+export default StorageUnitInstance
\ No newline at end of file
diff --git a/app/src/modules/simulation/storageUnit/instances/storageUnitInstances.tsx b/app/src/modules/simulation/storageUnit/instances/storageUnitInstances.tsx
index d79b5d8..29b6ea0 100644
--- a/app/src/modules/simulation/storageUnit/instances/storageUnitInstances.tsx
+++ b/app/src/modules/simulation/storageUnit/instances/storageUnitInstances.tsx
@@ -1,12 +1,19 @@
import React from 'react'
import StorageUnitInstance from './storageUnitInstance/storageUnitInstance'
+import { useStorageUnitStore } from '../../../../store/simulation/useStorageUnitStore'
+import StorageContentUi from '../../ui3d/StorageContentUi';
function StorageUnitInstances() {
+ const { storageUnits } = useStorageUnitStore();
+
return (
<>
-
-
-
+ {storageUnits.map((storageUnit: StorageUnitStatus) => (
+
+
+
+
+ ))}
>
)
}
diff --git a/app/src/modules/simulation/triggers/connector/triggerConnector.tsx b/app/src/modules/simulation/triggers/connector/triggerConnector.tsx
index a56436f..557831c 100644
--- a/app/src/modules/simulation/triggers/connector/triggerConnector.tsx
+++ b/app/src/modules/simulation/triggers/connector/triggerConnector.tsx
@@ -2,7 +2,7 @@ import { useEffect, useRef, useState } from "react";
import { useFrame, useThree } from "@react-three/fiber";
import * as THREE from "three";
import { useSubModuleStore } from "../../../../store/useModuleStore";
-import { useSelectedAsset } from "../../../../store/simulation/useSimulationStore";
+import { useSelectedAction, useSelectedAsset } from "../../../../store/simulation/useSimulationStore";
import { useProductStore } from "../../../../store/simulation/useProductStore";
import { useEventsStore } from "../../../../store/simulation/useEventsStore";
import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore";
@@ -22,7 +22,7 @@ interface ConnectionLine {
function TriggerConnector() {
const { gl, raycaster, scene, pointer, camera } = useThree();
const { subModule } = useSubModuleStore();
- const { products, getPointByUuid, getIsEventInProduct, getActionByUuid, addTrigger, removeTrigger, addEvent, getEventByModelUuid, getProductById } = useProductStore();
+ const { products, getPointByUuid, getIsEventInProduct, getActionByUuid, addTrigger, removeTrigger, addEvent, getEventByModelUuid, getPointUuidByActionUuid, getProductById } = useProductStore();
const { selectedAsset, clearSelectedAsset } = useSelectedAsset();
const { selectedProduct } = useSelectedProduct();
const [hoveredLineKey, setHoveredLineKey] = useState(null);
@@ -31,6 +31,7 @@ function TriggerConnector() {
const [currentLine, setCurrentLine] = useState<{ start: THREE.Vector3; end: THREE.Vector3; mid: THREE.Vector3; } | null>(null);
const { deleteTool } = useDeleteTool();
const { isPlaying } = usePlayButtonStore();
+ const { selectedAction } = useSelectedAction();
const [firstSelectedPoint, setFirstSelectedPoint] = useState<{
productId: string;
@@ -50,7 +51,7 @@ function TriggerConnector() {
organization: string,
eventData: EventsSchema
) => {
- const data =upsertProductOrEventApi({
+ upsertProductOrEventApi({
productName: productName,
productId: productId,
organization: organization,
@@ -130,6 +131,22 @@ function TriggerConnector() {
});
}
}
+ // Handle StorageUnit point
+ else if (event.type === "storageUnit" && 'point' in event) {
+ const point = event.point;
+ if (point.action?.triggers) {
+ point.action.triggers.forEach(trigger => {
+ if (trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint) {
+ newConnections.push({
+ id: `${point.uuid}-${trigger.triggeredAsset.triggeredPoint.pointUuid}-${trigger.triggerUuid}`,
+ startPointUuid: point.uuid,
+ endPointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
+ trigger
+ });
+ }
+ });
+ }
+ }
});
setConnections(newConnections);
@@ -201,6 +218,7 @@ function TriggerConnector() {
);
const event = getEventByModelUuid(selectedProduct.productId, modelUuid);
+ const clickedPointUuid = getPointUuidByActionUuid(selectedProduct.productId, selectedAction.actionId || '');
if (!point || !event) {
setFirstSelectedPoint(null);
@@ -215,11 +233,12 @@ function TriggerConnector() {
}
if (!firstSelectedPoint) {
+ if (point.uuid !== clickedPointUuid) return;
setFirstSelectedPoint({
productId: selectedProduct.productId,
modelUuid,
pointUuid,
- actionUuid
+ actionUuid: selectedAction.actionId || ''
});
} else {
const trigger: TriggerSchema = {
@@ -323,11 +342,13 @@ function TriggerConnector() {
}
};
- if (subModule === 'simulations' && !deleteTool) {
+ if (subModule === 'mechanics' && !deleteTool && selectedAction.actionId && selectedAction.actionName) {
canvasElement.addEventListener("mousedown", onMouseDown);
canvasElement.addEventListener("mouseup", onMouseUp);
canvasElement.addEventListener("mousemove", onMouseMove);
canvasElement.addEventListener('contextmenu', handleRightClick);
+ } else {
+ setFirstSelectedPoint(null);
}
return () => {
@@ -337,8 +358,7 @@ function TriggerConnector() {
canvasElement.removeEventListener('contextmenu', handleRightClick);
};
- }, [gl, subModule, selectedProduct, firstSelectedPoint, deleteTool]);
-
+ }, [gl, subModule, selectedProduct, firstSelectedPoint, deleteTool, selectedAction]);
useFrame(() => {
if (firstSelectedPoint) {
diff --git a/app/src/modules/simulation/triggers/trigger.tsx b/app/src/modules/simulation/triggers/trigger.tsx
index 110da2e..5f11709 100644
--- a/app/src/modules/simulation/triggers/trigger.tsx
+++ b/app/src/modules/simulation/triggers/trigger.tsx
@@ -1,7 +1,7 @@
-import React from 'react'
import TriggerConnector from './connector/triggerConnector'
function Trigger() {
+
return (
<>
diff --git a/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts b/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts
index c022e78..7db5730 100644
--- a/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts
+++ b/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts
@@ -5,6 +5,8 @@ import { useSelectedProduct } from '../../../../store/simulation/useSimulationSt
import { useMaterialStore } from '../../../../store/simulation/useMaterialStore';
import { useArmBotStore } from '../../../../store/simulation/useArmBotStore';
import { useVehicleStore } from '../../../../store/simulation/useVehicleStore';
+import { useMachineStore } from '../../../../store/simulation/useMachineStore';
+import { useStorageUnitStore } from '../../../../store/simulation/useStorageUnitStore';
export function useTriggerHandler() {
const { handleAction } = useActionHandler();
@@ -12,6 +14,8 @@ export function useTriggerHandler() {
const { getEventByTriggerUuid, getEventByModelUuid, getActionByUuid, getModelUuidByActionUuid } = useProductStore();
const { getArmBotById } = useArmBotStore();
const { getVehicleById } = useVehicleStore();
+ const { getMachineById } = useMachineStore();
+ const { getStorageUnitById } = useStorageUnitStore();
const { setCurrentLocation, setNextLocation, setPreviousLocation, getMaterialById, setIsPaused, setIsVisible, setEndTime } = useMaterialStore();
const handleTrigger = (trigger: TriggerSchema, action: Action, materialId?: string) => {
@@ -133,8 +137,6 @@ export function useTriggerHandler() {
if (armBot.isActive === false && armBot.state === 'idle') {
- setIsPaused(material.materialId, true);
-
// Handle current action from arm bot
handleAction(action, materialId);
@@ -219,10 +221,7 @@ export function useTriggerHandler() {
setIsVisible(materialId, false);
- if (action && armBot &&
- action.triggers[0].triggeredAsset?.triggeredModel.modelUuid &&
- action.triggers[0].triggeredAsset?.triggeredPoint?.pointUuid
- ) {
+ if (action && armBot) {
if (armBot.isActive === false && armBot.state === 'idle') {
@@ -240,7 +239,43 @@ export function useTriggerHandler() {
} else if (toEvent?.type === 'storageUnit') {
// Vehicle to Storage Unit
+ if (materialId && trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint && trigger.triggeredAsset.triggeredAction) {
+ const material = getMaterialById(materialId);
+ if (material) {
+ const action = getActionByUuid(selectedProduct.productId, trigger.triggeredAsset.triggeredAction.actionUuid);
+ const storageUnit = getStorageUnitById(trigger.triggeredAsset?.triggeredModel.modelUuid);
+ setPreviousLocation(material.materialId, {
+ modelUuid: material.current.modelUuid,
+ pointUuid: material.current.pointUuid,
+ actionUuid: material.current.actionUuid,
+ })
+
+ setCurrentLocation(material.materialId, {
+ modelUuid: trigger.triggeredAsset.triggeredModel.modelUuid,
+ pointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
+ actionUuid: trigger.triggeredAsset?.triggeredAction?.actionUuid,
+ });
+
+ setNextLocation(material.materialId, null);
+
+ setIsVisible(materialId, false);
+
+ if (action && storageUnit) {
+
+ if (storageUnit.currentLoad < storageUnit.point.action.storageCapacity) {
+
+ // Handle current action from vehicle
+ handleAction(action, materialId);
+
+ } else {
+
+ // Event Manager Needed
+
+ }
+ }
+ }
+ }
}
} else if (fromEvent?.type === 'machine') {
if (toEvent?.type === 'transfer') {
@@ -254,6 +289,43 @@ export function useTriggerHandler() {
} else if (toEvent?.type === 'roboticArm') {
// Machine to Robotic Arm
+ if (materialId && trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint && trigger.triggeredAsset.triggeredAction) {
+ const material = getMaterialById(materialId);
+ if (material) {
+ const action = getActionByUuid(selectedProduct.productId, trigger.triggeredAsset.triggeredAction.actionUuid);
+ const armBot = getArmBotById(trigger.triggeredAsset?.triggeredModel.modelUuid);
+
+ setPreviousLocation(material.materialId, {
+ modelUuid: material.current.modelUuid,
+ pointUuid: material.current.pointUuid,
+ actionUuid: material.current.actionUuid,
+ })
+
+ setCurrentLocation(material.materialId, {
+ modelUuid: trigger.triggeredAsset.triggeredModel.modelUuid,
+ pointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
+ actionUuid: trigger.triggeredAsset?.triggeredAction?.actionUuid,
+ });
+
+ setNextLocation(material.materialId, null);
+
+ setIsVisible(materialId, false);
+
+ if (action && armBot) {
+
+ if (armBot.isActive === false && armBot.state === 'idle') {
+
+ // Handle current action from arm bot
+ handleAction(action, materialId);
+
+ } else {
+
+ // Event Manager Needed
+
+ }
+ }
+ }
+ }
} else if (toEvent?.type === 'storageUnit') {
// Machine to Storage Unit
@@ -265,6 +337,7 @@ export function useTriggerHandler() {
if (materialId && trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint && trigger.triggeredAsset.triggeredAction) {
const material = getMaterialById(materialId);
if (material) {
+
setIsPaused(material.materialId, false);
setPreviousLocation(material.materialId, {
@@ -357,18 +430,6 @@ export function useTriggerHandler() {
const action = getActionByUuid(selectedProduct.productId, trigger.triggeredAsset.triggeredAction.actionUuid);
const vehicle = getVehicleById(trigger.triggeredAsset?.triggeredModel.modelUuid);
- setPreviousLocation(material.materialId, {
- modelUuid: material.current.modelUuid,
- pointUuid: material.current.pointUuid,
- actionUuid: material.current.actionUuid,
- })
-
- setCurrentLocation(material.materialId, {
- modelUuid: trigger.triggeredAsset.triggeredModel.modelUuid,
- pointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
- actionUuid: trigger.triggeredAsset?.triggeredAction?.actionUuid,
- });
-
setNextLocation(material.materialId, null);
if (action) {
@@ -379,6 +440,18 @@ export function useTriggerHandler() {
setIsVisible(materialId, false);
+ setPreviousLocation(material.materialId, {
+ modelUuid: material.current.modelUuid,
+ pointUuid: material.current.pointUuid,
+ actionUuid: material.current.actionUuid,
+ })
+
+ setCurrentLocation(material.materialId, {
+ modelUuid: trigger.triggeredAsset.triggeredModel.modelUuid,
+ pointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
+ actionUuid: trigger.triggeredAsset?.triggeredAction?.actionUuid,
+ });
+
// Handle current action from vehicle
handleAction(action, materialId);
@@ -396,12 +469,91 @@ export function useTriggerHandler() {
} else if (toEvent?.type === 'machine') {
// Robotic Arm to Machine
+ if (materialId && trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint && trigger.triggeredAsset.triggeredAction) {
+ const material = getMaterialById(materialId);
+ if (material) {
+
+ setIsPaused(material.materialId, false);
+
+ const action = getActionByUuid(selectedProduct.productId, trigger.triggeredAsset.triggeredAction.actionUuid);
+ const machine = getMachineById(trigger.triggeredAsset?.triggeredModel.modelUuid);
+ setNextLocation(material.materialId, null);
+
+ if (action) {
+
+ if (machine) {
+
+ if (machine.isActive === false && machine.state === 'idle') {
+
+ setIsVisible(materialId, false);
+
+ setPreviousLocation(material.materialId, {
+ modelUuid: material.current.modelUuid,
+ pointUuid: material.current.pointUuid,
+ actionUuid: material.current.actionUuid,
+ })
+
+ setCurrentLocation(material.materialId, {
+ modelUuid: trigger.triggeredAsset.triggeredModel.modelUuid,
+ pointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
+ actionUuid: trigger.triggeredAsset?.triggeredAction?.actionUuid,
+ });
+
+ // Handle current action from machine
+ handleAction(action, materialId);
+
+ } else {
+
+ // Event Manager Needed
+
+ }
+ }
+ }
+ }
+ }
+
} else if (toEvent?.type === 'roboticArm') {
// Robotic Arm to Robotic Arm
} else if (toEvent?.type === 'storageUnit') {
// Robotic Arm to Storage Unit
+ if (materialId && trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint && trigger.triggeredAsset.triggeredAction) {
+ const material = getMaterialById(materialId);
+ if (material) {
+ const action = getActionByUuid(selectedProduct.productId, trigger.triggeredAsset.triggeredAction.actionUuid);
+ const storageUnit = getStorageUnitById(trigger.triggeredAsset?.triggeredModel.modelUuid);
+ setPreviousLocation(material.materialId, {
+ modelUuid: material.current.modelUuid,
+ pointUuid: material.current.pointUuid,
+ actionUuid: material.current.actionUuid,
+ })
+
+ setCurrentLocation(material.materialId, {
+ modelUuid: trigger.triggeredAsset.triggeredModel.modelUuid,
+ pointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
+ actionUuid: trigger.triggeredAsset?.triggeredAction?.actionUuid,
+ });
+
+ setNextLocation(material.materialId, null);
+
+ setIsVisible(materialId, false);
+
+ if (action && storageUnit) {
+
+ if (storageUnit.currentLoad < storageUnit.point.action.storageCapacity) {
+
+ // Handle current action from vehicle
+ handleAction(action, materialId);
+
+ } else {
+
+ // Event Manager Needed
+
+ }
+ }
+ }
+ }
}
} else if (fromEvent?.type === 'storageUnit') {
if (toEvent?.type === 'transfer') {
diff --git a/app/src/modules/simulation/ui3d/MachineContentUi.tsx b/app/src/modules/simulation/ui3d/MachineContentUi.tsx
new file mode 100644
index 0000000..bad89ed
--- /dev/null
+++ b/app/src/modules/simulation/ui3d/MachineContentUi.tsx
@@ -0,0 +1,34 @@
+import { Html } from "@react-three/drei";
+import React from "react";
+import AssetDetailsCard from "../../../components/ui/simulation/AssetDetailsCard";
+import { Vector3 } from "three";
+
+type MachineContentUiProps = {
+ machine: MachineStatus;
+};
+
+const MachineContentUi: React.FC = ({ machine }) => {
+ return (
+
+
+
+ );
+};
+
+export default MachineContentUi;
diff --git a/app/src/modules/simulation/ui3d/RoboticArmContentUi.tsx b/app/src/modules/simulation/ui3d/RoboticArmContentUi.tsx
index c85e387..dbe32c6 100644
--- a/app/src/modules/simulation/ui3d/RoboticArmContentUi.tsx
+++ b/app/src/modules/simulation/ui3d/RoboticArmContentUi.tsx
@@ -3,11 +3,11 @@ import React from "react";
import AssetDetailsCard from "../../../components/ui/simulation/AssetDetailsCard";
import { Vector3 } from "three";
-type VehicleContentUiProps = {
+type RoboticArmContentUiProps = {
roboticArm: ArmBotStatus;
};
-const RoboticArmContentUi: React.FC = ({ roboticArm }) => {
+const RoboticArmContentUi: React.FC = ({ roboticArm }) => {
return (
= ({ storageUnit }) => {
+ return (
+
+
+
+ );
+};
+
+export default StorageContentUi;
diff --git a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx
index ba16302..a3af481 100644
--- a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx
+++ b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx
@@ -73,6 +73,7 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
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]);
@@ -95,14 +96,13 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
const currentDirection = new THREE.Vector3().subVectors(end, start).normalize();
const targetAngle = Math.atan2(currentDirection.x, currentDirection.z);
- const rotationSpeed = speed;
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 * delta;
+ 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;
@@ -122,7 +122,7 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
objectRotation.z
);
const targetQuaternion = new THREE.Quaternion().setFromEuler(targetEuler);
- object.quaternion.slerp(targetQuaternion, delta * 2);
+ object.quaternion.slerp(targetQuaternion, delta * (rotationSpeed * speed * agvDetail.speed));
if (object.quaternion.angleTo(targetQuaternion) < 0.01) {
object.quaternion.copy(targetQuaternion);
object.rotation.copy(targetEuler);
@@ -146,7 +146,8 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
return (
<>
{currentPath.length > 0 && (
-
+ // helper
+
{currentPath.map((point, index) => (
diff --git a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx
index a97730b..f4e7e61 100644
--- a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx
+++ b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx
@@ -5,6 +5,7 @@ import { NavMeshQuery } from '@recast-navigation/core';
import { useNavMesh } from '../../../../../store/store';
import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore } from '../../../../../store/usePlayButtonStore';
import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore';
+import { useStorageUnitStore } from '../../../../../store/simulation/useStorageUnitStore';
import { useMaterialStore } from '../../../../../store/simulation/useMaterialStore';
import { useProductStore } from '../../../../../store/simulation/useProductStore';
import { useSelectedProduct } from '../../../../../store/simulation/useSimulationStore';
@@ -15,10 +16,11 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
const { navMesh } = useNavMesh();
const { isPlaying } = usePlayButtonStore();
const { removeMaterial } = useMaterialStore();
+ const { getStorageUnitById } = useStorageUnitStore();
const { triggerPointActions } = useTriggerHandler();
const { getActionByUuid, getEventByModelUuid, getTriggerByUuid } = useProductStore();
const { selectedProduct } = useSelectedProduct();
- const { vehicles, setVehicleActive, setVehicleState, clearCurrentMaterials, setVehicleLoad, decrementVehicleLoad, removeLastMaterial } = useVehicleStore();
+ const { vehicles, setVehicleActive, setVehicleState, setVehiclePicking, clearCurrentMaterials, setVehicleLoad, decrementVehicleLoad, removeLastMaterial } = useVehicleStore();
const [currentPhase, setCurrentPhase] = useState('stationed');
const [path, setPath] = useState<[number, number, number][]>([]);
const pauseTimeRef = useRef(null);
@@ -56,6 +58,7 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
function reset() {
setCurrentPhase('stationed');
setVehicleActive(agvDetail.modelUuid, false);
+ setVehiclePicking(agvDetail.modelUuid, false);
setVehicleState(agvDetail.modelUuid, 'idle');
setVehicleLoad(agvDetail.modelUuid, 0);
setPath([]);
@@ -76,6 +79,7 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
setPath(toPickupPath);
setCurrentPhase('stationed-pickup');
setVehicleState(agvDetail.modelUuid, 'running');
+ setVehiclePicking(agvDetail.modelUuid, false);
setVehicleActive(agvDetail.modelUuid, true);
vehicleStatus(agvDetail.modelUuid, 'Started from station, heading to pickup');
return;
@@ -89,6 +93,7 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
setPath(toDrop);
setCurrentPhase('pickup-drop');
setVehicleState(agvDetail.modelUuid, 'running');
+ setVehiclePicking(agvDetail.modelUuid, false);
setVehicleActive(agvDetail.modelUuid, true);
vehicleStatus(agvDetail.modelUuid, 'Started from pickup point, heading to drop point');
}
@@ -102,6 +107,7 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
setPath(dropToPickup);
setCurrentPhase('drop-pickup');
setVehicleState(agvDetail.modelUuid, 'running');
+ setVehiclePicking(agvDetail.modelUuid, false);
setVehicleActive(agvDetail.modelUuid, true);
vehicleStatus(agvDetail.modelUuid, 'Started from dropping point, heading to pickup point');
}
@@ -116,18 +122,21 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
if (currentPhase === 'stationed-pickup') {
setCurrentPhase('picking');
setVehicleState(agvDetail.modelUuid, 'idle');
+ setVehiclePicking(agvDetail.modelUuid, true);
setVehicleActive(agvDetail.modelUuid, false);
vehicleStatus(agvDetail.modelUuid, 'Reached pickup point, waiting for material');
setPath([]);
} else if (currentPhase === 'pickup-drop') {
setCurrentPhase('dropping');
setVehicleState(agvDetail.modelUuid, 'idle');
+ setVehiclePicking(agvDetail.modelUuid, false);
setVehicleActive(agvDetail.modelUuid, false);
vehicleStatus(agvDetail.modelUuid, 'Reached drop point');
setPath([]);
} else if (currentPhase === 'drop-pickup') {
setCurrentPhase('picking');
setVehicleState(agvDetail.modelUuid, 'idle');
+ setVehiclePicking(agvDetail.modelUuid, true);
setVehicleActive(agvDetail.modelUuid, false);
setPath([]);
clearCurrentMaterials(agvDetail.modelUuid)
@@ -154,7 +163,10 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
handleMaterialDropToArmBot(action);
}
} else if (model.type === 'storageUnit') {
- //
+ const action = getActionByUuid(selectedProduct.productId, agvDetail.point.action.actionUuid);
+ if (action) {
+ handleMaterialDropToStorageUnit(action);
+ }
}
} else {
const droppedMaterial = agvDetail.currentLoad;
@@ -168,6 +180,82 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
}
}
+ function handleMaterialDropToStorageUnit(action: Action) {
+ if (action.triggers.length > 0 && action.triggers[0].triggeredAsset?.triggeredModel.modelUuid) {
+ const storageUnit = getStorageUnitById(action.triggers[0].triggeredAsset?.triggeredModel.modelUuid);
+ if (storageUnit) {
+ if (storageUnit.point.action.actionType === 'store') {
+ handleMaterialDropToStorage(
+ agvDetail.modelUuid,
+ agvDetail.currentLoad,
+ agvDetail.point.action.unLoadDuration,
+ storageUnit.modelUuid,
+ storageUnit.point.action.storageCapacity,
+ agvDetail.point.action
+ );
+ }
+ }
+ }
+ }
+
+ function handleMaterialDropToStorage(
+ vehicleId: string,
+ vehicleCurrentLoad: number,
+ unLoadDuration: number,
+ storageUnitId: string,
+ storageMaxCapacity: number,
+ action: VehicleAction
+ ) {
+ startTime = performance.now();
+ const fixedInterval = ((unLoadDuration / vehicleCurrentLoad) * (1000 / speed));
+
+ const unloadLoop = () => {
+ if (isPausedRef.current) {
+ pauseTimeRef.current ??= performance.now();
+ requestAnimationFrame(unloadLoop);
+ return;
+ }
+
+ if (pauseTimeRef.current) {
+ const pauseDuration = performance.now() - pauseTimeRef.current;
+ startTime += pauseDuration;
+ pauseTimeRef.current = null;
+ }
+
+ const elapsedTime = performance.now() - startTime;
+ const storageUnit = getStorageUnitById(storageUnitId);
+
+ if (elapsedTime >= fixedInterval) {
+ if (storageUnit && agvDetail &&
+ storageUnit.currentLoad < storageMaxCapacity &&
+ vehicleCurrentLoad > 0) {
+
+ decrementVehicleLoad(vehicleId, 1);
+ vehicleCurrentLoad -= 1;
+
+ const material = removeLastMaterial(vehicleId);
+ if (material) {
+
+ triggerPointActions(action, material.materialId);
+
+ }
+
+ if (vehicleCurrentLoad > 0 && storageUnit.currentLoad < storageMaxCapacity) {
+ startTime = performance.now();
+ requestAnimationFrame(unloadLoop);
+ }
+ }
+ } else {
+ requestAnimationFrame(unloadLoop);
+ }
+ };
+
+ const storageUnit = getStorageUnitById(storageUnitId);
+ if (storageUnit && vehicleCurrentLoad > 0 && storageUnit?.currentLoad < storageMaxCapacity) {
+ unloadLoop();
+ }
+ }
+
function handleMaterialDropToConveyor(action: Action) {
if (agvDetail.currentLoad > 1) {
//
@@ -206,9 +294,9 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
if (elapsedTime >= fixedInterval) {
let droppedMat = droppedMaterial - 1;
decrementVehicleLoad(agvDetail.modelUuid, 1);
- const materialId = removeLastMaterial(agvDetail.modelUuid);
- if (materialId) {
- removeMaterial(materialId);
+ const material = removeLastMaterial(agvDetail.modelUuid);
+ if (material) {
+ removeMaterial(material.materialId);
}
if (droppedMat > 0) {
startTime = performance.now();
diff --git a/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx b/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx
index fa5cc03..1c7cd51 100644
--- a/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx
+++ b/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx
@@ -4,18 +4,18 @@ import { useVehicleStore } from "../../../../store/simulation/useVehicleStore";
import VehicleContentUi from "../../ui3d/VehicleContentUi";
function VehicleInstances() {
- const { vehicles } = useVehicleStore();
+ const { vehicles } = useVehicleStore();
- return (
- <>
- {vehicles.map((vehicle: VehicleStatus) => (
-
-
-
-
- ))}
- >
- );
+ return (
+ <>
+ {vehicles.map((vehicle: VehicleStatus) => (
+
+
+
+
+ ))}
+ >
+ );
}
export default VehicleInstances;
diff --git a/app/src/modules/simulation/vehicle/navMesh/polygonGenerator.tsx b/app/src/modules/simulation/vehicle/navMesh/polygonGenerator.tsx
index 370304e..a1bbfb0 100644
--- a/app/src/modules/simulation/vehicle/navMesh/polygonGenerator.tsx
+++ b/app/src/modules/simulation/vehicle/navMesh/polygonGenerator.tsx
@@ -38,8 +38,13 @@ export default function PolygonGenerator({
turf.lineString(line.map((p: any) => p?.position))
);
- const polygons = turf.polygonize(turf.featureCollection(lineFeatures));
-
+ const validLineFeatures = lineFeatures.filter((line) => {
+ const coords = line.geometry.coordinates;
+ return coords.length >= 2;
+ });
+
+ const polygons = turf.polygonize(turf.featureCollection(validLineFeatures));
+
renderWallGeometry(wallPoints);
if (polygons.features.length > 0) {
diff --git a/app/src/modules/visualization/zone/zoneCameraTarget.tsx b/app/src/modules/visualization/zone/zoneCameraTarget.tsx
index c3116ef..7927dc8 100644
--- a/app/src/modules/visualization/zone/zoneCameraTarget.tsx
+++ b/app/src/modules/visualization/zone/zoneCameraTarget.tsx
@@ -2,90 +2,101 @@ import { useEffect, useMemo, useRef, useState } from "react";
import { useFrame, useThree } from "@react-three/fiber";
import * as THREE from "three";
import { useSelectedZoneStore } from "../../../store/visualization/useZoneStore";
-import { useEditPosition, usezonePosition, usezoneTarget } from "../../../store/store";
+import {
+ useEditPosition,
+ usezonePosition,
+ usezoneTarget,
+} from "../../../store/store";
export default function ZoneCentreTarget() {
- const { selectedZone, setSelectedZone } = useSelectedZoneStore();
- const [previousZoneCentre, setPreviousZoneCentre] = useState(null);
- const sphereRef = useRef(null);
- const { camera, controls }: any = useThree();
- const { zonePosition, setZonePosition } = usezonePosition();
- const { zoneTarget, setZoneTarget } = usezoneTarget();
- const { Edit, setEdit } = useEditPosition();
+ const { selectedZone } = useSelectedZoneStore();
+ const [previousZoneCentre, setPreviousZoneCentre] = useState(
+ null
+ );
+ const sphereRef = useRef(null);
+ const { controls }: any = useThree();
+ const { setZonePosition } = usezonePosition();
+ const { setZoneTarget } = usezoneTarget();
+ const { Edit } = useEditPosition();
- useEffect(() => {
- if (
- selectedZone.zoneViewPortTarget &&
- JSON.stringify(previousZoneCentre) !== JSON.stringify(selectedZone.zoneViewPortTarget)
- ) {
- setPreviousZoneCentre(selectedZone.zoneViewPortTarget);
- }
- }, [selectedZone.zoneViewPortTarget, previousZoneCentre]);
+ const TRANSITION_SPEED = 2000;
- const centrePoint = useMemo(() => {
- if (!previousZoneCentre || !selectedZone.zoneViewPortTarget) return null;
- return previousZoneCentre.map((value, index) =>
- (value + selectedZone.zoneViewPortTarget[index]) / 2
- );
- }, [previousZoneCentre, selectedZone.zoneViewPortTarget]);
+ useEffect(() => {
+ if (
+ selectedZone.zoneViewPortTarget &&
+ JSON.stringify(previousZoneCentre) !==
+ JSON.stringify(selectedZone.zoneViewPortTarget)
+ ) {
+ setPreviousZoneCentre(selectedZone.zoneViewPortTarget);
+ }
+ }, [selectedZone.zoneViewPortTarget, previousZoneCentre]);
- useEffect(() => {
- if (selectedZone.zoneName !== "") {
- if (sphereRef.current) {
- sphereRef.current.position.set(selectedZone.zoneViewPortTarget[0], selectedZone.zoneViewPortTarget[1], selectedZone.zoneViewPortTarget[2]);
- }
- if (centrePoint) {
-
- if (centrePoint.length > 0) {
-
- // let camPosition = new THREE.Vector3(...selectedZone.zoneViewPortPosition);
- // let CamTarget = new THREE.Vector3(...selectedZone.zoneViewPortTarget);
-
- // const direction = new THREE.Vector3().subVectors(CamTarget, camPosition).normalize();
-
- // const worldUp = new THREE.Vector3(0, 0, 1);
- // const right = new THREE.Vector3().crossVectors(worldUp, direction).normalize();
- // const up = new THREE.Vector3().crossVectors(direction, right).normalize();
- // const offsetPosition = up.clone().multiplyScalar(20);
- // camPosition.add(offsetPosition);
-
- const setCam = async () => {
- controls.setLookAt(centrePoint[0], 100, centrePoint[2], ...centrePoint, true);
- setTimeout(() => {
- controls?.setLookAt(
- ...selectedZone.zoneViewPortPosition,
- selectedZone.zoneViewPortTarget[0],
- selectedZone.zoneViewPortTarget[1],
- selectedZone.zoneViewPortTarget[2],
- true
- );
- }, 400)
- };
- setCam();
- } else {
-
- const setCam = async () => {
- controls?.setLookAt(
- ...selectedZone.zoneViewPortPosition,
- selectedZone.zoneViewPortTarget[0],
- selectedZone.zoneViewPortTarget[1],
- selectedZone.zoneViewPortTarget[2],
- true
- );
- };
- setCam();
- }
- }
- }
- }, [selectedZone.zoneViewPortTarget]);
-
- useFrame(() => {
- if (Edit) {
- setZonePosition([controls.getPosition().x, controls.getPosition().y, controls.getPosition().z])
- setZoneTarget([controls.getTarget().x, controls.getTarget().y, controls.getTarget().z])
- }
- })
- return (
- <> >
+ const centrePoint = useMemo(() => {
+ if (!previousZoneCentre || !selectedZone.zoneViewPortTarget) return null;
+ return previousZoneCentre.map(
+ (value, index) => (value + selectedZone.zoneViewPortTarget[index]) / 2
);
+ }, [previousZoneCentre, selectedZone.zoneViewPortTarget]);
+
+ useEffect(() => {
+ if (selectedZone.zoneName !== "") {
+ if (sphereRef.current) {
+ sphereRef.current.position.set(
+ selectedZone.zoneViewPortTarget[0],
+ selectedZone.zoneViewPortTarget[1],
+ selectedZone.zoneViewPortTarget[2]
+ );
+ }
+ if (centrePoint) {
+ if (centrePoint.length > 0) {
+ const setCam = async () => {
+ controls.setLookAt(
+ centrePoint[0],
+ 26,
+ centrePoint[2],
+ ...centrePoint,
+ true,
+ TRANSITION_SPEED
+ );
+ setTimeout(() => {
+ controls?.setLookAt(
+ ...selectedZone.zoneViewPortPosition,
+ ...selectedZone.zoneViewPortTarget,
+ true,
+ TRANSITION_SPEED
+ );
+ }, 100);
+ };
+ setCam();
+ } else {
+ const setCam = async () => {
+ controls?.setLookAt(
+ ...selectedZone.zoneViewPortPosition,
+ ...selectedZone.zoneViewPortTarget,
+ true,
+ TRANSITION_SPEED
+ );
+ };
+ setCam();
+ }
+ }
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [selectedZone.zoneViewPortTarget]);
+
+ useFrame(() => {
+ if (Edit) {
+ setZonePosition([
+ controls.getPosition().x,
+ controls.getPosition().y,
+ controls.getPosition().z,
+ ]);
+ setZoneTarget([
+ controls.getTarget().x,
+ controls.getTarget().y,
+ controls.getTarget().z,
+ ]);
+ }
+ });
+ return <>>;
}
diff --git a/app/src/pages/Project.tsx b/app/src/pages/Project.tsx
index aa203c3..8a432cf 100644
--- a/app/src/pages/Project.tsx
+++ b/app/src/pages/Project.tsx
@@ -136,26 +136,3 @@ const Project: React.FC = () => {
};
export default Project;
-
-// src/global.d.ts
-// import { LogType } from "../components/ui/log/LoggerContext";
-
-// export declare global {
-// const echo: {
-// log: (message: string) => void;
-// info: (message: string) => void;
-// warn: (message: string) => void;
-// error: (message: string) => void;
-// success: (message: string) => void;
-// clear: () => void;
-// };
-// }
-
-// Project.tsx:61 Uncaught ReferenceError: echo is not defined
-// at Project.tsx:61:1
-// at commitHookEffectListMount (react-dom.development.js:23189:1)
-// at commitPassiveMountOnFiber (react-dom.development.js:24965:1)
-// at commitPassiveMountEffects_complete (react-dom.development.js:24930:1)
-// at commitPassiveMountEffects_begin (react-dom.development.js:24917:1)
-// at commitPassiveMountEffects (react-dom.development.js:24905:1)
-// this error occurs some time's
diff --git a/app/src/store/simulation/useArmBotStore.ts b/app/src/store/simulation/useArmBotStore.ts
index a112552..7c4d38b 100644
--- a/app/src/store/simulation/useArmBotStore.ts
+++ b/app/src/store/simulation/useArmBotStore.ts
@@ -85,7 +85,7 @@ export const useArmBotStore = create()(
actionUuid: action.actionUuid,
actionName: action.actionName,
materialType: materialType,
- materialId:materialId
+ materialId: materialId
};
}
}
diff --git a/app/src/store/simulation/useMachineStore.ts b/app/src/store/simulation/useMachineStore.ts
index 5754da3..2c4c98a 100644
--- a/app/src/store/simulation/useMachineStore.ts
+++ b/app/src/store/simulation/useMachineStore.ts
@@ -12,7 +12,7 @@ interface MachineStore {
) => void;
clearMachines: () => void;
- addCurrentAction: (modelUuid: string, actionUuid: string) => void;
+ addCurrentAction: (modelUuid: string, actionUuid: string, materialType: string, materialId: string) => void;
removeCurrentAction: (modelUuid: string) => void;
setMachineActive: (modelUuid: string, isActive: boolean) => void;
@@ -69,16 +69,17 @@ export const useMachineStore = create()(
});
},
- addCurrentAction: (modelUuid) => {
+ addCurrentAction: (modelUuid, actionUuid, materialType, materialId) => {
set((state) => {
const armBot = state.machines.find(a => a.modelUuid === modelUuid);
if (armBot) {
const action = armBot.point.action;
if (action) {
armBot.currentAction = {
- actionUuid: action.actionUuid,
+ actionUuid: actionUuid,
actionName: action.actionName,
- materialType: null
+ materialType: materialType,
+ materialId: materialId
};
}
}
diff --git a/app/src/store/simulation/useProductStore.ts b/app/src/store/simulation/useProductStore.ts
index b90fd7d..e7d394a 100644
--- a/app/src/store/simulation/useProductStore.ts
+++ b/app/src/store/simulation/useProductStore.ts
@@ -61,6 +61,7 @@ type ProductsStore = {
// Helper functions
getProductById: (productId: string) => { productName: string; productId: string; eventDatas: EventsSchema[] } | undefined;
getEventByModelUuid: (productId: string, modelUuid: string) => EventsSchema | undefined;
+ getEventByActionUuid: (productId: string, actionUuid: string) => EventsSchema | undefined;
getEventByTriggerUuid: (productId: string, triggerUuid: string) => EventsSchema | undefined;
getEventByPointUuid: (productId: string, pointUuid: string) => EventsSchema | undefined;
getPointByUuid: (productId: string, modelUuid: string, pointUuid: string) => ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema | undefined;
@@ -543,6 +544,32 @@ export const useProductStore = create()(
return product.eventDatas.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
},
+ getEventByActionUuid: (productId, actionUuid) => {
+ const product = get().getProductById(productId);
+ if (!product) return undefined;
+
+ for (const event of product.eventDatas) {
+ if ('points' in event) {
+ for (const point of (event as ConveyorEventSchema).points) {
+ if (point.action?.actionUuid === actionUuid) {
+ return event;
+ }
+ }
+ } else if ('point' in event) {
+ const point = (event as any).point;
+ if ('action' in point && point.action?.actionUuid === actionUuid) {
+ return event;
+ } else if ('actions' in point) {
+ const action = point.actions.find((a: any) => a.actionUuid === actionUuid);
+ if (action) {
+ return event;
+ }
+ }
+ }
+ }
+ return undefined;
+ },
+
getEventByTriggerUuid: (productId, triggerUuid) => {
const product = get().getProductById(productId);
if (!product) return undefined;
diff --git a/app/src/store/simulation/useSimulationStore.ts b/app/src/store/simulation/useSimulationStore.ts
index 6e4321f..b3d3c78 100644
--- a/app/src/store/simulation/useSimulationStore.ts
+++ b/app/src/store/simulation/useSimulationStore.ts
@@ -93,14 +93,14 @@ export const useSelectedProduct = create()(
);
interface SelectedActionState {
- selectedAction: { actionId: string; actionName: string };
+ selectedAction: { actionId: string | null; actionName: string | null };
setSelectedAction: (actionId: string, actionName: string) => void;
clearSelectedAction: () => void;
}
export const useSelectedAction = create()(
immer((set) => ({
- selectedAction: { actionId: '', actionName: '' },
+ selectedAction: { actionId: null, actionName: null },
setSelectedAction: (actionId, actionName) => {
set((state) => {
state.selectedAction.actionId = actionId;
@@ -109,8 +109,8 @@ export const useSelectedAction = create()(
},
clearSelectedAction: () => {
set((state) => {
- state.selectedAction.actionId = '';
- state.selectedAction.actionName = '';
+ state.selectedAction.actionId = null;
+ state.selectedAction.actionName = null;
});
},
}))
diff --git a/app/src/store/simulation/useStorageUnitStore.ts b/app/src/store/simulation/useStorageUnitStore.ts
index aec2f12..171f674 100644
--- a/app/src/store/simulation/useStorageUnitStore.ts
+++ b/app/src/store/simulation/useStorageUnitStore.ts
@@ -15,11 +15,17 @@ interface StorageUnitStore {
setStorageUnitActive: (modelUuid: string, isActive: boolean) => void;
setStorageUnitState: (modelUuid: string, newState: StorageUnitStatus['state']) => void;
- updateStorageUnitLoad: (modelUuid: string, incrementBy: number) => void;
+ updateCurrentLoad: (modelUuid: string, incrementBy: number) => void;
incrementActiveTime: (modelUuid: string, incrementBy: number) => void;
incrementIdleTime: (modelUuid: string, incrementBy: number) => void;
+ addCurrentMaterial: (modelUuid: string, materialType: string, materialId: string) => void;
+ setCurrentMaterials: (modelUuid: string, materials: { materialType: string; materialId: string; }[]) => void;
+ getLastMaterial: (modelUuid: string) => { materialId: string; materialType: string; } | undefined;
+ removeLastMaterial: (modelUuid: string) => { materialId: string; materialType: string; } | undefined;
+ clearCurrentMaterials: (modelUuid: string) => void;
+
getStorageUnitById: (modelUuid: string) => StorageUnitStatus | undefined;
getStorageUnitsByProduct: (productId: string) => StorageUnitStatus[];
getStorageUnitsBystate: (state: string) => StorageUnitStatus[];
@@ -44,7 +50,8 @@ export const useStorageUnitStore = create()(
idleTime: 0,
activeTime: 0,
currentLoad: 0,
- state: 'idle',
+ currentMaterials: [],
+ state: 'idle'
});
}
});
@@ -89,7 +96,7 @@ export const useStorageUnitStore = create()(
});
},
- updateStorageUnitLoad: (modelUuid, incrementBy) => {
+ updateCurrentLoad: (modelUuid, incrementBy) => {
set((state) => {
const unit = state.storageUnits.find(s => s.modelUuid === modelUuid);
if (unit) {
@@ -116,6 +123,65 @@ export const useStorageUnitStore = create()(
});
},
+ addCurrentMaterial: (modelUuid, materialType, materialId) => {
+ set((state) => {
+ const storage = state.storageUnits.find((s) => s.modelUuid === modelUuid);
+ if (storage) {
+ storage.currentMaterials.push({ materialType, materialId });
+ }
+ });
+ },
+
+ setCurrentMaterials: (modelUuid, materials) => {
+ set((state) => {
+ const storage = state.storageUnits.find((s) => s.modelUuid === modelUuid);
+ if (storage) {
+ storage.currentMaterials = materials;
+ }
+ });
+ },
+
+ getLastMaterial: (modelUuid) => {
+ let removedMaterial: { materialId: string; materialType: string; } | undefined;
+ set((state) => {
+ const storage = state.storageUnits.find((s) => s.modelUuid === modelUuid);
+ if (storage) {
+ if (storage.currentMaterials.length > 0) {
+ const material = storage.currentMaterials[storage.currentMaterials.length - 1];
+ if (material) {
+ removedMaterial = { materialId: material.materialId, materialType: material.materialType };
+ }
+ }
+ }
+ });
+ return removedMaterial;
+ },
+
+ removeLastMaterial: (modelUuid) => {
+ let removedMaterial: { materialId: string; materialType: string; } | undefined;
+ set((state) => {
+ const storage = state.storageUnits.find((s) => s.modelUuid === modelUuid);
+ if (storage) {
+ if (storage.currentMaterials.length > 0) {
+ const material = storage.currentMaterials.pop();
+ if (material) {
+ removedMaterial = { materialId: material.materialId, materialType: material.materialType };
+ }
+ }
+ }
+ });
+ return removedMaterial;
+ },
+
+ clearCurrentMaterials: (modelUuid) => {
+ set((state) => {
+ const storage = state.storageUnits.find((s) => s.modelUuid === modelUuid);
+ if (storage) {
+ storage.currentMaterials = [];
+ }
+ });
+ },
+
getStorageUnitById: (modelUuid) => {
return get().storageUnits.find(s => s.modelUuid === modelUuid);
},
diff --git a/app/src/store/simulation/useVehicleStore.ts b/app/src/store/simulation/useVehicleStore.ts
index 7a393de..e69c233 100644
--- a/app/src/store/simulation/useVehicleStore.ts
+++ b/app/src/store/simulation/useVehicleStore.ts
@@ -13,6 +13,7 @@ interface VehiclesStore {
clearvehicles: () => void;
setVehicleActive: (modelUuid: string, isActive: boolean) => void;
+ setVehiclePicking: (modelUuid: string, isPicking: boolean) => void;
updateSteeringAngle: (modelUuid: string, steeringAngle: number) => void;
incrementVehicleLoad: (modelUuid: string, incrementBy: number) => void;
decrementVehicleLoad: (modelUuid: string, decrementBy: number) => void;
@@ -23,7 +24,7 @@ interface VehiclesStore {
) => void;
addCurrentMaterial: (modelUuid: string, materialType: string, materialId: string) => void;
setCurrentMaterials: (modelUuid: string, materials: { materialType: string; materialId: string; }[]) => void;
- removeLastMaterial: (modelUuid: string) => string | undefined;
+ removeLastMaterial: (modelUuid: string) => { materialId: string; materialType: string; } | undefined;
clearCurrentMaterials: (modelUuid: string) => void;
incrementActiveTime: (modelUuid: string, incrementBy: number) => void;
incrementIdleTime: (modelUuid: string, incrementBy: number) => void;
@@ -40,19 +41,19 @@ export const useVehicleStore = create()(
addVehicle: (productId, event) => {
set((state) => {
- const exists = state.vehicles.some(
- (v) => v.modelUuid === event.modelUuid
- );
+ const exists = state.vehicles.some((v) => v.modelUuid === event.modelUuid);
if (!exists) {
state.vehicles.push({
...event,
productId,
isActive: false,
+ isPicking: false,
idleTime: 0,
activeTime: 0,
currentLoad: 0,
currentMaterials: [],
distanceTraveled: 0,
+ state: 'idle'
});
}
});
@@ -90,6 +91,15 @@ export const useVehicleStore = create()(
});
},
+ setVehiclePicking: (modelUuid, isPicking) => {
+ set((state) => {
+ const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
+ if (vehicle) {
+ vehicle.isPicking = isPicking;
+ }
+ });
+ },
+
updateSteeringAngle: (modelUuid, steeringAngle) => {
set((state) => {
const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
@@ -154,19 +164,19 @@ export const useVehicleStore = create()(
},
removeLastMaterial: (modelUuid) => {
- let materialId: string | undefined;
+ let removedMaterial: { materialId: string; materialType: string; } | undefined;
set((state) => {
const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
if (vehicle) {
if (vehicle.currentMaterials.length > 0) {
const material = vehicle.currentMaterials.pop();
if (material) {
- materialId = material.materialId
+ removedMaterial = { materialId: material.materialId, materialType: material.materialType };
}
}
}
});
- return materialId;
+ return removedMaterial;
},
clearCurrentMaterials: (modelUuid) => {
diff --git a/app/src/store/store.ts b/app/src/store/store.ts
index 68740b7..61d84d5 100644
--- a/app/src/store/store.ts
+++ b/app/src/store/store.ts
@@ -4,434 +4,434 @@ import { create } from "zustand";
import { io } from "socket.io-client";
export const useSocketStore = create((set: any, get: any) => ({
- socket: null,
- initializeSocket: (email: string, organization: string) => {
- const existingSocket = get().socket;
- if (existingSocket) {
- return;
- }
+ socket: null,
+ initializeSocket: (email: string, organization: string) => {
+ const existingSocket = get().socket;
+ if (existingSocket) {
+ return;
+ }
- const socket = io(
- `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Builder`,
- {
- reconnection: true,
- auth: { email, organization },
- }
- );
+ const socket = io(
+ `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Builder`,
+ {
+ reconnection: true,
+ auth: { email, organization },
+ }
+ );
- const visualizationSocket = io(
- `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Visualization`,
- {
- reconnection: true,
- auth: { email, organization },
- }
- );
+ const visualizationSocket = io(
+ `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Visualization`,
+ {
+ reconnection: true,
+ auth: { email, organization },
+ }
+ );
- set({ socket, visualizationSocket });
- },
- disconnectSocket: () => {
- set((state: any) => {
- state.socket?.disconnect();
- state.visualizationSocket?.disconnect();
- return { socket: null };
- });
- },
+ set({ socket, visualizationSocket });
+ },
+ disconnectSocket: () => {
+ set((state: any) => {
+ state.socket?.disconnect();
+ state.visualizationSocket?.disconnect();
+ return { socket: null };
+ });
+ },
}));
export const useLoadingProgress = create<{
- loadingProgress: number;
- setLoadingProgress: (x: number) => void;
+ loadingProgress: number;
+ setLoadingProgress: (x: number) => void;
}>((set) => ({
- loadingProgress: 1,
- setLoadingProgress: (x: number) => set({ loadingProgress: x }),
+ loadingProgress: 1,
+ setLoadingProgress: (x: number) => set({ loadingProgress: x }),
}));
export const useOrganization = create((set: any) => ({
- organization: "",
- setOrganization: (x: any) => set(() => ({ organization: x })),
+ organization: "",
+ setOrganization: (x: any) => set(() => ({ organization: x })),
}));
export const useToggleView = create((set: any) => ({
- toggleView: false,
- setToggleView: (x: any) => set(() => ({ toggleView: x })),
+ toggleView: false,
+ setToggleView: (x: any) => set(() => ({ toggleView: x })),
}));
export const useUpdateScene = create((set: any) => ({
- updateScene: false,
- setUpdateScene: (x: any) => set(() => ({ updateScene: x })),
+ updateScene: false,
+ setUpdateScene: (x: any) => set(() => ({ updateScene: x })),
}));
export const useWalls = create((set: any) => ({
- walls: [],
- setWalls: (x: any) => set(() => ({ walls: x })),
+ walls: [],
+ setWalls: (x: any) => set(() => ({ walls: x })),
}));
export const useRoomsState = create((set: any) => ({
- roomsState: [],
- setRoomsState: (x: any) => set(() => ({ walls: x })),
+ roomsState: [],
+ setRoomsState: (x: any) => set(() => ({ roomsState: x })),
}));
export const useZones = create((set: any) => ({
- zones: [],
- setZones: (callback: any) =>
- set((state: any) => ({
- zones: typeof callback === "function" ? callback(state.zones) : callback,
- })),
+ zones: [],
+ setZones: (callback: any) =>
+ set((state: any) => ({
+ zones: typeof callback === "function" ? callback(state.zones) : callback,
+ })),
}));
interface ZonePointsState {
- zonePoints: THREE.Vector3[];
- setZonePoints: (points: THREE.Vector3[]) => void;
+ zonePoints: THREE.Vector3[];
+ setZonePoints: (points: THREE.Vector3[]) => void;
}
export const useZonePoints = create((set) => ({
- zonePoints: [],
- setZonePoints: (points) => set({ zonePoints: points }),
+ zonePoints: [],
+ setZonePoints: (points) => set({ zonePoints: points }),
}));
export const useSelectedItem = create((set: any) => ({
- selectedItem: { name: "", id: "", type: undefined },
- setSelectedItem: (x: any) => set(() => ({ selectedItem: x })),
+ selectedItem: { name: "", id: "", type: undefined },
+ setSelectedItem: (x: any) => set(() => ({ selectedItem: x })),
}));
export const useNavMesh = create((set: any) => ({
- navMesh: null,
- setNavMesh: (x: any) => set({ navMesh: x }),
+ navMesh: null,
+ setNavMesh: (x: any) => set({ navMesh: x }),
}));
export const useSelectedAssets = create((set: any) => ({
- selectedAssets: [],
- setSelectedAssets: (x: any) => set(() => ({ selectedAssets: x })),
+ selectedAssets: [],
+ setSelectedAssets: (x: any) => set(() => ({ selectedAssets: x })),
}));
export const useLayers = create((set: any) => ({
- Layers: 1,
- setLayers: (x: any) => set(() => ({ Layers: x })),
+ Layers: 1,
+ setLayers: (x: any) => set(() => ({ Layers: x })),
}));
export const useCamPosition = create((set: any) => ({
- camPosition: { x: undefined, y: undefined, z: undefined },
- setCamPosition: (newCamPosition: any) => set({ camPosition: newCamPosition }),
+ camPosition: { x: undefined, y: undefined, z: undefined },
+ setCamPosition: (newCamPosition: any) => set({ camPosition: newCamPosition }),
}));
export const useMenuVisible = create((set: any) => ({
- menuVisible: false,
- setMenuVisible: (x: any) => set(() => ({ menuVisible: x })),
+ menuVisible: false,
+ setMenuVisible: (x: any) => set(() => ({ menuVisible: x })),
}));
export const useDeleteTool = create((set: any) => ({
- deleteTool: false,
- setDeleteTool: (x: any) => set(() => ({ deleteTool: x })),
+ deleteTool: false,
+ setDeleteTool: (x: any) => set(() => ({ deleteTool: x })),
}));
export const useToolMode = create((set: any) => ({
- toolMode: null,
- setToolMode: (x: any) => set(() => ({ toolMode: x })),
+ toolMode: null,
+ setToolMode: (x: any) => set(() => ({ toolMode: x })),
}));
export const useNewLines = create((set: any) => ({
- newLines: [],
- setNewLines: (x: any) => set(() => ({ newLines: x })),
+ newLines: [],
+ setNewLines: (x: any) => set(() => ({ newLines: x })),
}));
export const useDeletedLines = create((set: any) => ({
- deletedLines: [],
- setDeletedLines: (x: any) => set(() => ({ deletedLines: x })),
+ deletedLines: [],
+ setDeletedLines: (x: any) => set(() => ({ deletedLines: x })),
}));
export const useMovePoint = create((set: any) => ({
- movePoint: false,
- setMovePoint: (x: any) => set(() => ({ movePoint: x })),
+ movePoint: false,
+ setMovePoint: (x: any) => set(() => ({ movePoint: x })),
}));
export const useTransformMode = create((set: any) => ({
- transformMode: null,
- setTransformMode: (x: any) => set(() => ({ transformMode: x })),
+ transformMode: null,
+ setTransformMode: (x: any) => set(() => ({ transformMode: x })),
}));
export const useDeletePointOrLine = create((set: any) => ({
- deletePointOrLine: false,
- setDeletePointOrLine: (x: any) => set(() => ({ deletePointOrLine: x })),
+ deletePointOrLine: false,
+ setDeletePointOrLine: (x: any) => set(() => ({ deletePointOrLine: x })),
}));
export const useFloorItems = create((set: any) => ({
- floorItems: null,
- setFloorItems: (callback: any) =>
- set((state: any) => ({
- floorItems:
- typeof callback === "function" ? callback(state.floorItems) : callback,
- })),
+ floorItems: null,
+ setFloorItems: (callback: any) =>
+ set((state: any) => ({
+ floorItems:
+ typeof callback === "function" ? callback(state.floorItems) : callback,
+ })),
}));
export const useWallItems = create((set: any) => ({
- wallItems: [],
- setWallItems: (callback: any) =>
- set((state: any) => ({
- wallItems:
- typeof callback === "function" ? callback(state.wallItems) : callback,
- })),
+ wallItems: [],
+ setWallItems: (callback: any) =>
+ set((state: any) => ({
+ wallItems:
+ typeof callback === "function" ? callback(state.wallItems) : callback,
+ })),
}));
export const useSelectedWallItem = create((set: any) => ({
- selectedWallItem: null,
- setSelectedWallItem: (x: any) => set(() => ({ selectedWallItem: x })),
+ selectedWallItem: null,
+ setSelectedWallItem: (x: any) => set(() => ({ selectedWallItem: x })),
}));
export const useSelectedFloorItem = create((set: any) => ({
- selectedFloorItem: null,
- setSelectedFloorItem: (x: any) => set(() => ({ selectedFloorItem: x })),
+ selectedFloorItem: null,
+ setSelectedFloorItem: (x: any) => set(() => ({ selectedFloorItem: x })),
}));
export const useDeletableFloorItem = create((set: any) => ({
- deletableFloorItem: null,
- setDeletableFloorItem: (x: any) => set(() => ({ deletableFloorItem: x })),
+ deletableFloorItem: null,
+ setDeletableFloorItem: (x: any) => set(() => ({ deletableFloorItem: x })),
}));
export const useSetScale = create((set: any) => ({
- scale: null,
- setScale: (x: any) => set(() => ({ scale: x })),
+ scale: null,
+ setScale: (x: any) => set(() => ({ scale: x })),
}));
export const useRoofVisibility = create((set: any) => ({
- roofVisibility: false,
- setRoofVisibility: (x: any) => set(() => ({ roofVisibility: x })),
+ roofVisibility: false,
+ setRoofVisibility: (x: any) => set(() => ({ roofVisibility: x })),
}));
export const useWallVisibility = create((set: any) => ({
- wallVisibility: false,
- setWallVisibility: (x: any) => set(() => ({ wallVisibility: x })),
+ wallVisibility: false,
+ setWallVisibility: (x: any) => set(() => ({ wallVisibility: x })),
}));
export const useShadows = create((set: any) => ({
- shadows: false,
- setShadows: (x: any) => set(() => ({ shadows: x })),
+ shadows: false,
+ setShadows: (x: any) => set(() => ({ shadows: x })),
}));
export const useSunPosition = create((set: any) => ({
- sunPosition: { x: undefined, y: undefined, z: undefined },
- setSunPosition: (newSuntPosition: any) =>
- set({ sunPosition: newSuntPosition }),
+ sunPosition: { x: undefined, y: undefined, z: undefined },
+ setSunPosition: (newSuntPosition: any) =>
+ set({ sunPosition: newSuntPosition }),
}));
export const useRemoveLayer = create((set: any) => ({
- removeLayer: false,
- setRemoveLayer: (x: any) => set(() => ({ removeLayer: x })),
+ removeLayer: false,
+ setRemoveLayer: (x: any) => set(() => ({ removeLayer: x })),
}));
export const useRemovedLayer = create((set: any) => ({
- removedLayer: null,
- setRemovedLayer: (x: any) => set(() => ({ removedLayer: x })),
+ removedLayer: null,
+ setRemovedLayer: (x: any) => set(() => ({ removedLayer: x })),
}));
export const useActiveLayer = create((set: any) => ({
- activeLayer: 1,
- setActiveLayer: (x: any) => set({ activeLayer: x }),
+ activeLayer: 1,
+ setActiveLayer: (x: any) => set({ activeLayer: x }),
}));
interface RefTextUpdateState {
- refTextupdate: number;
- setRefTextUpdate: (
- callback: (currentValue: number) => number | number
- ) => void;
+ refTextupdate: number;
+ setRefTextUpdate: (
+ callback: (currentValue: number) => number | number
+ ) => void;
}
export const useRefTextUpdate = create((set) => ({
- refTextupdate: -1000,
- setRefTextUpdate: (callback) =>
- set((state) => ({
- refTextupdate:
- typeof callback === "function"
- ? callback(state.refTextupdate)
- : callback,
- })),
+ refTextupdate: -1000,
+ setRefTextUpdate: (callback) =>
+ set((state) => ({
+ refTextupdate:
+ typeof callback === "function"
+ ? callback(state.refTextupdate)
+ : callback,
+ })),
}));
export const useResetCamera = create((set: any) => ({
- resetCamera: false,
- setResetCamera: (x: any) => set({ resetCamera: x }),
+ resetCamera: false,
+ setResetCamera: (x: any) => set({ resetCamera: x }),
}));
export const useAddAction = create((set: any) => ({
- addAction: null,
- setAddAction: (x: any) => set({ addAction: x }),
+ addAction: null,
+ setAddAction: (x: any) => set({ addAction: x }),
}));
export const useActiveTool = create((set: any) => ({
- activeTool: "cursor",
- setActiveTool: (x: any) => set({ activeTool: x }),
+ activeTool: "cursor",
+ setActiveTool: (x: any) => set({ activeTool: x }),
}));
export const useActiveSubTool = create((set: any) => ({
- activeSubTool: "cursor",
- setActiveSubTool: (x: any) => set({ activeSubTool: x }),
+ activeSubTool: "cursor",
+ setActiveSubTool: (x: any) => set({ activeSubTool: x }),
}));
export const use2DUndoRedo = create((set: any) => ({
- is2DUndoRedo: null,
- set2DUndoRedo: (x: any) => set({ is2DUndoRedo: x }),
+ is2DUndoRedo: null,
+ set2DUndoRedo: (x: any) => set({ is2DUndoRedo: x }),
}));
export const useElevation = create((set: any) => ({
- elevation: 45,
- setElevation: (x: any) => set({ elevation: x }),
+ elevation: 45,
+ setElevation: (x: any) => set({ elevation: x }),
}));
export const useAzimuth = create((set: any) => ({
- azimuth: -160,
- setAzimuth: (x: any) => set({ azimuth: x }),
+ azimuth: -160,
+ setAzimuth: (x: any) => set({ azimuth: x }),
}));
export const useRenderDistance = create((set: any) => ({
- renderDistance: 40,
- setRenderDistance: (x: any) => set({ renderDistance: x }),
+ renderDistance: 40,
+ setRenderDistance: (x: any) => set({ renderDistance: x }),
}));
export const useCamMode = create((set: any) => ({
- camMode: "ThirdPerson",
- setCamMode: (x: any) => set({ camMode: x }),
+ camMode: "ThirdPerson",
+ setCamMode: (x: any) => set({ camMode: x }),
}));
export const useUserName = create((set: any) => ({
- userName: "",
- setUserName: (x: any) => set({ userName: x }),
+ userName: "",
+ setUserName: (x: any) => set({ userName: x }),
}));
export const useObjectPosition = create((set: any) => ({
- objectPosition: { x: undefined, y: undefined, z: undefined },
- setObjectPosition: (newObjectPosition: any) =>
- set({ objectPosition: newObjectPosition }),
+ objectPosition: { x: undefined, y: undefined, z: undefined },
+ setObjectPosition: (newObjectPosition: any) =>
+ set({ objectPosition: newObjectPosition }),
}));
export const useObjectScale = create((set: any) => ({
- objectScale: { x: undefined, y: undefined, z: undefined },
- setObjectScale: (newObjectScale: any) => set({ objectScale: newObjectScale }),
+ objectScale: { x: undefined, y: undefined, z: undefined },
+ setObjectScale: (newObjectScale: any) => set({ objectScale: newObjectScale }),
}));
export const useObjectRotation = create((set: any) => ({
- objectRotation: { x: undefined, y: undefined, z: undefined },
- setObjectRotation: (newObjectRotation: any) =>
- set({ objectRotation: newObjectRotation }),
+ objectRotation: { x: undefined, y: undefined, z: undefined },
+ setObjectRotation: (newObjectRotation: any) =>
+ set({ objectRotation: newObjectRotation }),
}));
export const useDrieTemp = create((set: any) => ({
- drieTemp: undefined,
- setDrieTemp: (x: any) => set({ drieTemp: x }),
+ drieTemp: undefined,
+ setDrieTemp: (x: any) => set({ drieTemp: x }),
}));
export const useActiveUsers = create((set: any) => ({
- activeUsers: [],
- setActiveUsers: (callback: (prev: any[]) => any[] | any[]) =>
- set((state: { activeUsers: any[] }) => ({
- activeUsers:
- typeof callback === "function" ? callback(state.activeUsers) : callback,
- })),
+ activeUsers: [],
+ setActiveUsers: (callback: (prev: any[]) => any[] | any[]) =>
+ set((state: { activeUsers: any[] }) => ({
+ activeUsers:
+ typeof callback === "function" ? callback(state.activeUsers) : callback,
+ })),
}));
export const useDrieUIValue = create((set: any) => ({
- drieUIValue: { touch: null, temperature: null, humidity: null },
+ drieUIValue: { touch: null, temperature: null, humidity: null },
- setDrieUIValue: (x: any) =>
- set((state: any) => ({ drieUIValue: { ...state.drieUIValue, ...x } })),
+ setDrieUIValue: (x: any) =>
+ set((state: any) => ({ drieUIValue: { ...state.drieUIValue, ...x } })),
- setTouch: (value: any) =>
- set((state: any) => ({
- drieUIValue: { ...state.drieUIValue, touch: value },
- })),
- setTemperature: (value: any) =>
- set((state: any) => ({
- drieUIValue: { ...state.drieUIValue, temperature: value },
- })),
- setHumidity: (value: any) =>
- set((state: any) => ({
- drieUIValue: { ...state.drieUIValue, humidity: value },
- })),
+ setTouch: (value: any) =>
+ set((state: any) => ({
+ drieUIValue: { ...state.drieUIValue, touch: value },
+ })),
+ setTemperature: (value: any) =>
+ set((state: any) => ({
+ drieUIValue: { ...state.drieUIValue, temperature: value },
+ })),
+ setHumidity: (value: any) =>
+ set((state: any) => ({
+ drieUIValue: { ...state.drieUIValue, humidity: value },
+ })),
}));
export const useStartSimulation = create((set: any) => ({
- startSimulation: false,
- setStartSimulation: (x: any) => set({ startSimulation: x }),
+ startSimulation: false,
+ setStartSimulation: (x: any) => set({ startSimulation: x }),
}));
export const useEyeDropMode = create((set: any) => ({
- eyeDropMode: false,
- setEyeDropMode: (x: any) => set({ eyeDropMode: x }),
+ eyeDropMode: false,
+ setEyeDropMode: (x: any) => set({ eyeDropMode: x }),
}));
export const useEditingPoint = create((set: any) => ({
- editingPoint: false,
- setEditingPoint: (x: any) => set({ editingPoint: x }),
+ editingPoint: false,
+ setEditingPoint: (x: any) => set({ editingPoint: x }),
}));
export const usezoneTarget = create((set: any) => ({
- zoneTarget: [],
- setZoneTarget: (x: any) => set({ zoneTarget: x }),
+ zoneTarget: [],
+ setZoneTarget: (x: any) => set({ zoneTarget: x }),
}));
export const usezonePosition = create((set: any) => ({
- zonePosition: [],
- setZonePosition: (x: any) => set({ zonePosition: x }),
+ zonePosition: [],
+ setZonePosition: (x: any) => set({ zonePosition: x }),
}));
interface EditPositionState {
- Edit: boolean;
- setEdit: (value: boolean) => void;
+ Edit: boolean;
+ setEdit: (value: boolean) => void;
}
export const useEditPosition = create((set) => ({
- Edit: false,
- setEdit: (value) => set({ Edit: value }),
+ Edit: false,
+ setEdit: (value) => set({ Edit: value }),
}));
export const useAsset3dWidget = create((set: any) => ({
- widgetSelect: "",
- setWidgetSelect: (x: any) => set({ widgetSelect: x }),
+ widgetSelect: "",
+ setWidgetSelect: (x: any) => set({ widgetSelect: x }),
}));
export const useWidgetSubOption = create((set: any) => ({
- widgetSubOption: "2D",
- setWidgetSubOption: (x: any) => set({ widgetSubOption: x }),
+ widgetSubOption: "2D",
+ setWidgetSubOption: (x: any) => set({ widgetSubOption: x }),
}));
export const useLimitDistance = create((set: any) => ({
- limitDistance: true,
- setLimitDistance: (x: any) => set({ limitDistance: x }),
+ limitDistance: true,
+ setLimitDistance: (x: any) => set({ limitDistance: x }),
}));
export const useTileDistance = create((set: any) => ({
- gridValue: { size: 300, divisions: 75 },
- planeValue: { height: 300, width: 300 },
+ gridValue: { size: 300, divisions: 75 },
+ planeValue: { height: 300, width: 300 },
- setGridValue: (value: any) =>
- set((state: any) => ({
- gridValue: { ...state.gridValue, ...value },
- })),
+ setGridValue: (value: any) =>
+ set((state: any) => ({
+ gridValue: { ...state.gridValue, ...value },
+ })),
- setPlaneValue: (value: any) =>
- set((state: any) => ({
- planeValue: { ...state.planeValue, ...value },
- })),
+ setPlaneValue: (value: any) =>
+ set((state: any) => ({
+ planeValue: { ...state.planeValue, ...value },
+ })),
}));
export const usePlayAgv = create((set, get) => ({
- PlayAgv: [],
- setPlayAgv: (updateFn: (prev: any[]) => any[]) =>
- set({ PlayAgv: updateFn(get().PlayAgv) }),
+ PlayAgv: [],
+ setPlayAgv: (updateFn: (prev: any[]) => any[]) =>
+ set({ PlayAgv: updateFn(get().PlayAgv) }),
}));
// Define the Asset type
type Asset = {
- id: string;
- name: string;
- position?: [number, number, number]; // Optional: 3D position
- rotation?: { x: number; y: number; z: number }; // Optional: Euler rotation
+ id: string;
+ name: string;
+ position?: [number, number, number]; // Optional: 3D position
+ rotation?: { x: number; y: number; z: number }; // Optional: Euler rotation
};
// Zustand store type
type ZoneAssetState = {
- zoneAssetId: Asset | null;
- setZoneAssetId: (asset: Asset | null) => void;
+ zoneAssetId: Asset | null;
+ setZoneAssetId: (asset: Asset | null) => void;
};
// Zustand store
export const useZoneAssetId = create((set) => ({
- zoneAssetId: null,
- setZoneAssetId: (asset) => set({ zoneAssetId: asset }),
+ zoneAssetId: null,
+ setZoneAssetId: (asset) => set({ zoneAssetId: asset }),
}));
diff --git a/app/src/store/visualization/useZoneStore.ts b/app/src/store/visualization/useZoneStore.ts
index eb05790..c624941 100644
--- a/app/src/store/visualization/useZoneStore.ts
+++ b/app/src/store/visualization/useZoneStore.ts
@@ -29,25 +29,40 @@ interface SelectedZoneStore {
| Partial
| ((prev: SelectedZoneState) => SelectedZoneState)
) => void;
+ clearSelectedZone: () => void;
}
export const useSelectedZoneStore = create((set) => ({
selectedZone: {
- zoneName: "", // Empty string initially
- activeSides: [], // Empty array
- panelOrder: [], // Empty array
- lockedPanels: [], // Empty array
+ zoneName: "",
+ activeSides: [],
+ panelOrder: [],
+ lockedPanels: [],
points: [],
zoneId: "",
zoneViewPortTarget: [],
zoneViewPortPosition: [],
- widgets: [], // Empty array
+ widgets: [],
},
setSelectedZone: (zone) =>
set((state) => ({
selectedZone:
typeof zone === "function"
- ? zone(state.selectedZone) // Handle functional updates
- : { ...state.selectedZone, ...zone }, // Handle partial updates
+ ? zone(state.selectedZone)
+ : { ...state.selectedZone, ...zone },
+ })),
+ clearSelectedZone: () =>
+ set(() => ({
+ selectedZone: {
+ zoneName: "",
+ activeSides: [],
+ panelOrder: [],
+ lockedPanels: [],
+ points: [],
+ zoneId: "",
+ zoneViewPortTarget: [],
+ zoneViewPortPosition: [],
+ widgets: [],
+ },
})),
}));
diff --git a/app/src/styles/components/moduleToggle.scss b/app/src/styles/components/moduleToggle.scss
index 7e5b727..c985974 100644
--- a/app/src/styles/components/moduleToggle.scss
+++ b/app/src/styles/components/moduleToggle.scss
@@ -8,7 +8,7 @@
gap: 8px;
position: fixed;
left: 50%;
- top: 32px;
+ top: 22px;
transform: translateX(-50%);
z-index: #{$z-index-tools};
.module-list {
diff --git a/app/src/styles/components/simulation/simulation.scss b/app/src/styles/components/simulation/simulation.scss
index b98c23f..c57bfb0 100644
--- a/app/src/styles/components/simulation/simulation.scss
+++ b/app/src/styles/components/simulation/simulation.scss
@@ -425,8 +425,7 @@
animation: borderAnimation 5s linear infinite;
-webkit-mask: linear-gradient(#fff 0 0) content-box,
linear-gradient(#fff 0 0);
- mask: linear-gradient(#fff 0 0) content-box,
- linear-gradient(#fff 0 0);
+ mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
-webkit-mask-composite: xor;
mask-composite: exclude;
z-index: -1;
@@ -455,6 +454,10 @@
}
}
}
+ .storage-container{
+ font-size: var(--font-size-tiny);
+ color: var(--highlight-text-color);
+ }
}
}
@@ -485,32 +488,61 @@
.count-ui-wrapper {
position: absolute;
- right: -42px;
- top: 5px;
+ right: -16px;
+ top: -2px;
padding: 4px;
padding-right: 8px;
.count-ui-container {
- @include flex-center;
- gap: 6px;
- .icon{
+ background: var(--background-color-solid);
+ padding: 8px;
+ outline: 1px solid var(--border-color);
+ border-radius: #{$border-radius-large};
+ box-shadow: inset 0px 10px 50px #8080803a;
+ max-width: 80px;
+ position: absolute;
+ left: 0;
+ .content {
@include flex-center;
- padding: 3px;
- border-radius: #{$border-radius-circle};
- background: var(--background-color-accent);
- svg {
- scale: 0.6;
+ gap: 2px;
+ .icon {
+ @include flex-center;
+ }
+ .display {
+ font-size: var(--font-size-small);
}
}
- .value{
- position: absolute;
- width: 48px;
- background: var(--background-color-solid-gradient);
- border-radius: #{$border-radius-large};
- outline: 1px solid var(--border-color);
- padding: 4px 10px;
- padding-left: 16px;
- transform: translateX(28px);
- z-index: -1;
+ .value-container {
+ @include flex-center;
+ gap: 4px;
+ .progress-bar {
+ display: flex;
+ align-items: center;
+ gap: 1px;
+ height: 10px;
+ }
+
+ .block {
+ width: 5px;
+ height: 100%;
+ border-radius: 2px;
+ transition: background-color 0.3s;
+ background: var(--background-color);
+ overflow: hidden;
+ position: relative;
+ .fill {
+ height: 100%;
+ background: linear-gradient(
+ to top,
+ var(--background-color-accent) var(--process-fill-percentage),
+ transparent var(--process-fill-percentage)
+ );
+ }
+ }
+
+ .value {
+ font-size: var(--font-size-tiny);
+ color: var(--input-text-color);
+ }
}
}
}
diff --git a/app/src/styles/layout/sidebar.scss b/app/src/styles/layout/sidebar.scss
index 6e1889e..31ed4a6 100644
--- a/app/src/styles/layout/sidebar.scss
+++ b/app/src/styles/layout/sidebar.scss
@@ -4,7 +4,7 @@
.sidebar-left-wrapper {
width: 270px;
position: fixed;
- top: 32px;
+ top: 22px;
left: 8px;
background: var(--background-color);
backdrop-filter: blur(20px);
@@ -271,6 +271,7 @@
height: calc(100% - 16px);
max-height: 46vh;
overflow: auto;
+ margin: 0;
}
}
}
@@ -280,7 +281,7 @@
.sidebar-right-wrapper {
width: 320px;
position: fixed;
- top: 32px;
+ top: 22px;
right: 8px;
background: var(--background-color);
backdrop-filter: blur(20px);
@@ -454,12 +455,13 @@
height: calc(100% - 36px);
position: relative;
width: 304px;
- padding-bottom: 10px;
.no-event-selected {
color: #666;
padding: 16px;
grid-column: 1 / -1;
+ border-radius: #{$border-radius-large};
+ background: var(--background-color);
.products-list {
padding-top: 1rem;
@@ -778,8 +780,9 @@
.simulations-container,
.event-proprties-wrapper {
position: relative;
- max-height: calc(60vh - (47px - 35px));
- width: calc(100% - 4px);
+ max-height: calc(62vh - (47px - 35px));
+ width: 304px;
+ border-radius: #{$border-radius-large};
overflow-x: hidden;
.header {
@@ -989,6 +992,27 @@
.process-container {
padding: 0 12px;
margin: 6px 0;
+ padding-left: 16px;
+ position: relative;
+ &::after {
+ content: "↶";
+ rotate: -90deg;
+ transform: translate(-16px, 4px) scaleX(1);
+ height: 100%;
+ width: 1px;
+ position: absolute;
+ color: var(--text-color);
+ opacity: 0.4;
+ font-size: var(--font-size-regular);
+ outline-offset: -1px;
+ top: 0;
+ left: 4px;
+ }
+ &:last-child {
+ &::after {
+ display: none;
+ }
+ }
.value {
@include flex-space-between;
@@ -1034,7 +1058,7 @@
}
.compare-simulations-container {
- background: var(--background-color-gray);
+ background: var(--background-color);
padding: 12px;
border-radius: #{$border-radius-large};
@@ -1152,8 +1176,8 @@
}
.analysis-content-container {
- min-height: 50vh;
- max-height: 60vh;
+ min-height: 48vh;
+ max-height: 56vh;
overflow-y: auto;
.dropdown-header-container,
@@ -1207,7 +1231,7 @@
.create-custom-analysis-container {
margin: 6px;
- background: var(--background-color-gray);
+ background: var(--background-color);
padding: 12px;
border-radius: #{$border-radius-large};
@@ -1437,9 +1461,11 @@
width: 100%;
height: 100%;
font-size: var(--font-size-regular);
- background: linear-gradient(0deg,
- rgba(37, 24, 51, 0) 0%,
- rgba(52, 41, 61, 0.5) 100%);
+ background: linear-gradient(
+ 0deg,
+ rgba(37, 24, 51, 0) 0%,
+ rgba(52, 41, 61, 0.5) 100%
+ );
pointer-events: none;
backdrop-filter: blur(8px);
opacity: 0;
@@ -1480,26 +1506,48 @@
.sidebar-left-wrapper,
.sidebar-right-wrapper {
- height: calc(54vh + 150px);
transition: height 0.2s ease-in-out;
- .sidebar-left-container {
- height: 100%;
- .sidebar-left-content-container{
- max-height: 80%;
- .widget-left-sideBar{
- height: 80%;
- .widget2D.widgets-wrapper{
-
- min-height: 50vh;
- height: 60%;
-
- }
- }
- }
- }
}
.sidebar-left-wrapper.closed,
.sidebar-right-wrapper.closed {
- height: 52px;
-}
\ No newline at end of file
+ animation: closeSidebar 0.2s linear forwards;
+}
+
+.sidebar-left-wrapper.open,
+.sidebar-right-wrapper.open {
+ height: fit-content;
+ animation: openSidebar 0.2s linear;
+ .sidebar-right-container,
+ .sidebar-left-container {
+ opacity: 0;
+ animation: revealSmooth 0.3s 0.1s linear forwards;
+ }
+}
+
+@keyframes revealSmooth {
+ from {
+ opacity: 0;
+ }
+ to {
+ opacity: 1;
+ }
+}
+
+@keyframes closeSidebar {
+ from {
+ height: 60%;
+ }
+ to {
+ height: 52px;
+ }
+}
+
+@keyframes openSidebar {
+ from {
+ height: 52px;
+ }
+ to {
+ height: 60%;
+ }
+}
diff --git a/app/src/styles/scene/scene.scss b/app/src/styles/scene/scene.scss
index 40743e0..ff7fec3 100644
--- a/app/src/styles/scene/scene.scss
+++ b/app/src/styles/scene/scene.scss
@@ -19,6 +19,9 @@
border-radius: #{$border-radius-medium};
box-shadow: var(--box-shadow-light);
}
+ .area{
+ background: #008cff;
+ }
}
.pointer-none {
diff --git a/app/src/types/simulationTypes.d.ts b/app/src/types/simulationTypes.d.ts
index 1b8788a..f93a9d2 100644
--- a/app/src/types/simulationTypes.d.ts
+++ b/app/src/types/simulationTypes.d.ts
@@ -124,7 +124,8 @@ interface MachineAction {
interface StorageAction {
actionUuid: string;
actionName: string;
- actionType: "store";
+ actionType: "store" | "retrieve";
+ materialType?: string;
storageCapacity: number;
triggers: TriggerSchema[];
}
@@ -159,6 +160,7 @@ interface MachineStatus extends MachineEventSchema {
actionUuid: string;
actionName: string;
materialType: string | null;
+ materialId: string | null;
};
}
@@ -178,6 +180,7 @@ interface ArmBotStatus extends RoboticArmEventSchema {
interface VehicleStatus extends VehicleEventSchema {
productId: string;
isActive: boolean;
+ isPicking: boolean;
idleTime: number;
activeTime: number;
currentLoad: number;
@@ -191,12 +194,12 @@ interface StorageUnitStatus extends StorageEventSchema {
idleTime: number;
activeTime: number;
currentLoad: number;
- materials?: { materialName: string; materialId: string; }[];
+ currentMaterials: { materialType: string; materialId: string; }[];
}
interface MaterialSchema {
materialId: string;
- materialName: stri9ng;
+ materialName: string;
materialType: string;
isActive: boolean;
isVisible: boolean;
diff --git a/app/src/utils/shortcutkeys/handleShortcutKeys.ts b/app/src/utils/shortcutkeys/handleShortcutKeys.ts
index a08834c..2ff5f39 100644
--- a/app/src/utils/shortcutkeys/handleShortcutKeys.ts
+++ b/app/src/utils/shortcutkeys/handleShortcutKeys.ts
@@ -12,6 +12,7 @@ import {
} from "../../store/store";
import { usePlayButtonStore } from "../../store/usePlayButtonStore";
import { detectModifierKeys } from "./detectModifierKeys";
+import { useSelectedZoneStore } from "../../store/visualization/useZoneStore";
const KeyPressListener: React.FC = () => {
const { activeModule, setActiveModule } = useModuleStore();
@@ -25,6 +26,7 @@ const KeyPressListener: React.FC = () => {
const { setAddAction } = useAddAction();
const { setSelectedWallItem } = useSelectedWallItem();
const { setActiveTool } = useActiveTool();
+ const { clearSelectedZone} = useSelectedZoneStore();
const isTextInput = (element: Element | null): boolean =>
element instanceof HTMLInputElement ||
@@ -131,6 +133,7 @@ const KeyPressListener: React.FC = () => {
if (keyCombination === "ESCAPE") {
setActiveTool("cursor");
setIsPlaying(false);
+ clearSelectedZone();
}
// Placeholder for future implementation