diff --git a/app/src/app.tsx b/app/src/app.tsx
index bbd5984..2b2a25d 100644
--- a/app/src/app.tsx
+++ b/app/src/app.tsx
@@ -10,25 +10,24 @@ import ForgotPassword from "./pages/ForgotPassword";
import PageNotFound from "./pages/PageNotFound";
const App: React.FC = () => {
+ useEffect(() => {
+ Cache.clear();
+ Cache.enabled = true;
+ }, []);
- useEffect(() => {
- Cache.clear();
- Cache.enabled = true;
- }, []);
-
- return (
-
-
-
- } />
- } />
- } />
- } />
- } />
-
-
-
- );
+ return (
+
+
+
+ } />
+ } />
+ } />
+ } />
+ } />
+
+
+
+ );
};
export default App;
diff --git a/app/src/components/layout/scenes/ComparisonScene.tsx b/app/src/components/layout/scenes/ComparisonScene.tsx
index b09e53e..18fe34f 100644
--- a/app/src/components/layout/scenes/ComparisonScene.tsx
+++ b/app/src/components/layout/scenes/ComparisonScene.tsx
@@ -1,5 +1,5 @@
import { useParams } from "react-router-dom";
-import { useCompareProductDataStore, useLoadingProgress, useSaveVersion } from "../../../store/builder/store";
+import { useCompareProductDataStore, useLoadingProgress, useIsComparing } from "../../../store/builder/store";
import { useComparisonProduct, useMainProduct } from "../../../store/simulation/useSimulationStore";
import { usePlayButtonStore } from "../../../store/ui/usePlayButtonStore";
import { useEffect, useState } from "react";
@@ -9,21 +9,18 @@ import CompareLayOut from "../../ui/compareVersion/CompareLayOut";
import ComparisonResult from "../../ui/compareVersion/ComparisonResult";
import RegularDropDown from "../../ui/inputs/RegularDropDown";
-import { getVersionHistoryApi } from "../../../services/factoryBuilder/versionControl/getVersionHistoryApi";
-
function ComparisonScene() {
const { isPlaying } = usePlayButtonStore();
const { productStore, versionStore } = useSceneContext();
- const { versionHistory, selectedVersion, setSelectedVersion, setVersions } = versionStore();
+ const { versionHistory, selectedVersion, setSelectedVersion } = versionStore();
const { products, selectedProduct } = productStore();
- const { isVersionSaved } = useSaveVersion();
+ const { isComparing } = useIsComparing();
const { activeModule } = useModuleStore();
const { comparisonProduct, setComparisonProduct } = useComparisonProduct();
const { mainProduct } = useMainProduct();
const { loadingProgress } = useLoadingProgress();
const { compareProductsData } = useCompareProductDataStore();
const [shouldShowComparisonResult, setShouldShowComparisonResult] = useState(false);
- const { projectId } = useParams();
const handleSelectVersion = (option: string) => {
const version = versionHistory.find((version) => version.versionName === option);
@@ -39,30 +36,6 @@ function ComparisonScene() {
}
};
- useEffect(() => {
- if (!projectId) return;
-
- getVersionHistoryApi(projectId)
- .then((data) => {
- const versions: VersionHistory = [];
- data.versions.forEach((version: any) => {
- versions.push({
- version: version.version,
- versionId: version.versionId,
- versionName: version.versionName,
- versionDescription: version.description,
- timeStamp: version.createdAt,
- createdBy: version.createdBy.userName,
- });
- });
- setVersions(versions);
- })
- .catch(() => {
- console.error("Error fetching version history");
- });
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [projectId]);
-
useEffect(() => {
if (mainProduct && comparisonProduct && compareProductsData.length > 1) {
const hasMain = compareProductsData.some((val) => val.productUuid === mainProduct.productUuid);
@@ -79,7 +52,7 @@ function ComparisonScene() {
return (
<>
- {isVersionSaved && activeModule === "simulation" && selectedProduct && (
+ {isComparing && activeModule === "simulation" && selectedProduct && (
<>
{selectedVersion && !isPlaying && (
diff --git a/app/src/components/layout/scenes/MainScene.tsx b/app/src/components/layout/scenes/MainScene.tsx
index 5db82a5..82b237f 100644
--- a/app/src/components/layout/scenes/MainScene.tsx
+++ b/app/src/components/layout/scenes/MainScene.tsx
@@ -1,6 +1,6 @@
import { useEffect } from "react";
import { useParams } from "react-router-dom";
-import { useLoadingProgress, useRenameModeStore, useSaveVersion, useSelectedComment, useSocketStore, useWidgetSubOption } from "../../../store/builder/store";
+import { useLoadingProgress, useRenameModeStore, useIsComparing, useSelectedComment, useSocketStore, useWidgetSubOption } from "../../../store/builder/store";
import useModuleStore, { useThreeDStore } from "../../../store/ui/useModuleStore";
import { usePlayButtonStore } from "../../../store/ui/usePlayButtonStore";
import { useSelectedZoneStore } from "../../../store/visualization/useZoneStore";
@@ -36,7 +36,7 @@ import { getVersionHistoryApi } from "../../../services/factoryBuilder/versionCo
function MainScene() {
const { setMainProduct } = useMainProduct();
- const { isVersionSaved, setIsVersionSaved } = useSaveVersion();
+ const { isComparing, setIsComparing } = useIsComparing();
const { activeModule } = useModuleStore();
const { selectedUser } = useSelectedUserStore();
const { loadingProgress } = useLoadingProgress();
@@ -67,9 +67,9 @@ function MainScene() {
useEffect(() => {
if (activeModule !== "simulation") {
clearComparisonProduct();
- setIsVersionSaved(false);
+ setIsComparing(false);
}
- }, [activeModule, clearComparisonProduct, setIsVersionSaved]);
+ }, [activeModule, clearComparisonProduct, setIsComparing]);
useEffect(() => {
if (!projectId) return;
@@ -162,14 +162,14 @@ function MainScene() {
{loadingProgress > 0 && }
{!isPlaying && (
<>
- {toggleThreeD && !isVersionSaved && }
+ {toggleThreeD && !isComparing && }
>
)}
{activeModule === "market" && }
- {activeModule !== "market" && !isPlaying && !isVersionSaved && }
+ {activeModule !== "market" && !isPlaying && !isComparing && }
{isPlaying && activeModule === "simulation" && loadingProgress === 0 && }
{isPlaying && activeModule !== "simulation" && }
@@ -204,7 +204,7 @@ function MainScene() {
- {selectedProduct && selectedVersion && isVersionSaved && !isPlaying && activeModule === "simulation" && (
+ {selectedProduct && selectedVersion && isComparing && !isPlaying && activeModule === "simulation" && (
{
const [activeOption, setActiveOption] = useState("Widgets");
@@ -16,7 +16,7 @@ const SideBarLeft: React.FC = () => {
const { toggleUILeft } = useToggleStore();
const { activeModule } = useModuleStore();
- const { isVersionSaved } = useSaveVersion();
+ const { isComparing } = useIsComparing();
// Reset activeOption whenever activeModule changes
useEffect(() => {
@@ -35,7 +35,7 @@ const SideBarLeft: React.FC = () => {
return (
@@ -74,7 +74,7 @@ const SideBarLeft: React.FC = () => {
} else {
return (
<>
- {!isVersionSaved && (
+ {!isComparing && (
<>
{
const { selectedEventData } = useSelectedEventData();
const { selectedEventSphere } = useSelectedEventSphere();
const { viewVersionHistory, setVersionHistoryVisible } = useVersionHistoryVisibleStore();
- const { isVersionSaved } = useSaveVersion();
+ const { isComparing } = useIsComparing();
const [displayComponent, setDisplayComponent] = useState("none");
@@ -80,7 +80,7 @@ const SideBarRight: React.FC = () => {
return;
}
- if (!isVersionSaved && activeModule === "simulation") {
+ if (!isComparing && activeModule === "simulation") {
if (subModule === "simulations") {
setDisplayComponent("simulations");
return;
@@ -155,7 +155,7 @@ const SideBarRight: React.FC = () => {
}
setDisplayComponent("none");
- }, [viewVersionHistory, activeModule, subModule, isVersionSaved, selectedFloorAsset, selectedWall, selectedFloor, selectedAisle, toolMode, selectedDecal]);
+ }, [viewVersionHistory, activeModule, subModule, isComparing, selectedFloorAsset, selectedWall, selectedFloor, selectedAisle, toolMode, selectedDecal]);
const renderComponent = () => {
switch (displayComponent) {
@@ -197,11 +197,11 @@ const SideBarRight: React.FC = () => {
};
return (
- e.stopPropagation()}>
+
e.stopPropagation()}>
{toggleUIRight && (
<>
- {(!isVersionSaved || activeModule !== "simulation") && (
+ {(!isComparing || activeModule !== "simulation") && (
{activeModule !== "simulation" && (
<>
diff --git a/app/src/components/layout/sidebarRight/simulation/Simulations.tsx b/app/src/components/layout/sidebarRight/simulation/Simulations.tsx
index e7b24ce..5ae7c47 100644
--- a/app/src/components/layout/sidebarRight/simulation/Simulations.tsx
+++ b/app/src/components/layout/sidebarRight/simulation/Simulations.tsx
@@ -13,7 +13,7 @@ import { deleteProductApi } from "../../../../services/simulation/products/delet
import { renameProductApi } from "../../../../services/simulation/products/renameProductApi";
import { determineExecutionMachineSequences } from "../../../../modules/simulation/simulator/functions/determineExecutionMachineSequences";
import ComparePopUp from "../../../ui/compareVersion/Compare";
-import { useCompareStore, useSaveVersion } from "../../../../store/builder/store";
+import { useCompareStore, useIsComparing } from "../../../../store/builder/store";
import { useToggleStore } from "../../../../store/ui/useUIToggleStore";
import { useParams } from "react-router-dom";
import { useSceneContext } from "../../../../modules/scene/sceneContext";
@@ -36,10 +36,10 @@ const Simulations: React.FC = () => {
const { setMainProduct } = useMainProduct();
const { selectedVersion } = versionStore();
const { comparePopUp, setComparePopUp } = useCompareStore();
- const { setIsVersionSaved } = useSaveVersion();
+ const { setIsComparing } = useIsComparing();
const handleSaveVersion = () => {
- setIsVersionSaved(true);
+ setIsComparing(true);
setComparePopUp(false);
setToggleUI(false, false);
};
diff --git a/app/src/components/ui/compareVersion/CompareLayOut.tsx b/app/src/components/ui/compareVersion/CompareLayOut.tsx
index 57b0f73..3c98b6f 100644
--- a/app/src/components/ui/compareVersion/CompareLayOut.tsx
+++ b/app/src/components/ui/compareVersion/CompareLayOut.tsx
@@ -1,19 +1,22 @@
+import { useParams } from "react-router-dom";
import React, { useState, useRef, useEffect, Suspense } from "react";
import { CompareLayoutIcon, LayoutIcon, ResizerIcon } from "../../icons/SimulationIcons";
-import { useLoadingProgress, useSaveVersion } from "../../../store/builder/store";
-import Search from "../inputs/Search";
-import OuterClick from "../../../utils/outerClick";
-import Scene from "../../../modules/scene/scene";
+import { useLoadingProgress, useIsComparing } from "../../../store/builder/store";
import { useComparisonProduct } from "../../../store/simulation/useSimulationStore";
import { usePlayButtonStore } from "../../../store/ui/usePlayButtonStore";
import { useSceneContext } from "../../../modules/scene/sceneContext";
import { getAllProductsApi } from "../../../services/simulation/products/getallProductsApi";
-import { useParams } from "react-router-dom";
+import Search from "../inputs/Search";
+import OuterClick from "../../../utils/outerClick";
+import Scene from "../../../modules/scene/scene";
+import useRestStates from "../../../hooks/useResetStates";
+
+import { getVersionHistoryApi } from "../../../services/factoryBuilder/versionControl/getVersionHistoryApi";
const CompareLayOut = () => {
const { clearComparisonProduct, comparisonProduct, setComparisonProduct } = useComparisonProduct();
const { versionStore } = useSceneContext();
- const { versionHistory, selectedVersion, setSelectedVersion, clearSelectedVersion } = versionStore();
+ const { versionHistory, selectedVersion, setSelectedVersion, clearSelectedVersion, setVersions } = versionStore();
const { setLoadingProgress } = useLoadingProgress();
const [width, setWidth] = useState("50vw");
const [isResizing, setIsResizing] = useState(false);
@@ -21,10 +24,43 @@ const CompareLayOut = () => {
const wrapperRef = useRef
(null);
const startWidthRef = useRef(0);
const startXRef = useRef(0);
- const { setIsVersionSaved } = useSaveVersion();
+ const { setIsComparing } = useIsComparing();
const { loadingProgress } = useLoadingProgress();
const { setIsPlaying } = usePlayButtonStore();
const { projectId } = useParams();
+ const { resetStates } = useRestStates();
+
+ useEffect(() => {
+ return () => {
+ if (selectedVersion?.versionId) {
+ resetStates();
+ }
+ };
+ }, [selectedVersion?.versionId]);
+
+ useEffect(() => {
+ if (!projectId) return;
+
+ getVersionHistoryApi(projectId)
+ .then((data) => {
+ const versions: VersionHistory = [];
+ data.versions.forEach((version: any) => {
+ versions.push({
+ version: version.version,
+ versionId: version.versionId,
+ versionName: version.versionName,
+ versionDescription: version.description,
+ timeStamp: version.createdAt,
+ createdBy: version.createdBy.userName,
+ });
+ });
+ setVersions(versions);
+ })
+ .catch(() => {
+ console.error("Error fetching version history");
+ });
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [projectId]);
useEffect(() => {
if (!comparisonProduct) {
@@ -71,7 +107,7 @@ const CompareLayOut = () => {
if (finalWidthVw <= 10) {
setWidth("0px");
- setIsVersionSaved(false);
+ setIsComparing(false);
clearComparisonProduct();
setIsPlaying(false);
} else {
diff --git a/app/src/modules/builder/asset/models/model/model.tsx b/app/src/modules/builder/asset/models/model/model.tsx
index 9788062..666595d 100644
--- a/app/src/modules/builder/asset/models/model/model.tsx
+++ b/app/src/modules/builder/asset/models/model/model.tsx
@@ -1,17 +1,17 @@
-import * as THREE from 'three';
-import { useEffect, useRef, useState } from 'react';
-import { retrieveGLTF, storeGLTF } from '../../../../../utils/indexDB/idbUtils';
-import { GLTF, GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
-import { useToggleView, useToolMode } from '../../../../../store/builder/store';
-import { AssetBoundingBox } from '../../functions/assetBoundingBox';
-import { useBuilderStore } from '../../../../../store/builder/useBuilderStore';
-import useModuleStore from '../../../../../store/ui/useModuleStore';
-import { useSceneContext } from '../../../../scene/sceneContext';
-import { SkeletonUtils } from 'three-stdlib';
+import * as THREE from "three";
+import { useEffect, useRef, useState } from "react";
+import { retrieveGLTF, storeGLTF } from "../../../../../utils/indexDB/idbUtils";
+import { GLTF, GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
+import { useToggleView, useToolMode } from "../../../../../store/builder/store";
+import { AssetBoundingBox } from "../../functions/assetBoundingBox";
+import { useBuilderStore } from "../../../../../store/builder/useBuilderStore";
+import useModuleStore from "../../../../../store/ui/useModuleStore";
+import { useSceneContext } from "../../../../scene/sceneContext";
+import { SkeletonUtils } from "three-stdlib";
-import { getAssetFieldApi } from '../../../../../services/factoryBuilder/asset/floorAsset/getAssetField';
-import { ModelAnimator } from './animator/modelAnimator';
-import { useModelEventHandlers } from './eventHandlers/useModelEventHandlers';
+import { getAssetFieldApi } from "../../../../../services/factoryBuilder/asset/floorAsset/getAssetField";
+import { ModelAnimator } from "./animator/modelAnimator";
+import { useModelEventHandlers } from "./eventHandlers/useModelEventHandlers";
function Model({ asset, isRendered, loader }: Readonly<{ asset: Asset; isRendered: boolean; loader: GLTFLoader }>) {
const url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
@@ -31,33 +31,33 @@ function Model({ asset, isRendered, loader }: Readonly<{ asset: Asset; isRendere
useEffect(() => {
if (!fieldData && asset.eventData) {
getAssetFieldApi(asset.assetId).then((data) => {
- if (data.type === 'ArmBot') {
+ if (data.type === "ArmBot") {
if (data.data) {
const fieldData: IK[] = data.data;
setFieldData(fieldData);
}
- } else if (data.type === 'Conveyor' || data.type === 'Crane') {
+ } else if (data.type === "Conveyor" || data.type === "Crane") {
if (data.data) {
const fieldData = data.data;
setFieldData(fieldData);
}
}
- })
+ });
}
- }, [asset.modelUuid, fieldData])
+ }, [asset.modelUuid, fieldData]);
useEffect(() => {
setDeletableFloorAsset(null);
if (selectedFloorAsset === null || selectedFloorAsset.userData.modelUuid !== asset.modelUuid) {
resetAnimation(asset.modelUuid);
}
- }, [activeModule, toolMode, selectedFloorAsset])
+ }, [activeModule, toolMode, selectedFloorAsset]);
useEffect(() => {
if (selectedFloorAsset && selectedFloorAsset.userData.modelUuid === asset.modelUuid) {
setSelectedFloorAsset(groupRef.current);
}
- }, [isRendered, selectedFloorAsset])
+ }, [isRendered, selectedFloorAsset]);
useEffect(() => {
if (selectedAssets.length > 0) {
@@ -69,7 +69,7 @@ function Model({ asset, isRendered, loader }: Readonly<{ asset: Asset; isRendere
} else {
setIsSelected(false);
}
- }, [selectedAssets])
+ }, [selectedAssets]);
useEffect(() => {
if (gltfScene) {
@@ -78,13 +78,13 @@ function Model({ asset, isRendered, loader }: Readonly<{ asset: Asset; isRendere
child.castShadow = true;
child.receiveShadow = true;
}
- })
+ });
}
}, [gltfScene]);
const logModelStatus = (modelId: string, status: string) => {
// console.log(modelId, status);
- }
+ };
useEffect(() => {
// Calculate Bounding Box
@@ -101,62 +101,61 @@ function Model({ asset, isRendered, loader }: Readonly<{ asset: Asset; isRendere
clone.animations = cachedModel.animations || [];
setGltfScene(clone);
calculateBoundingBox(clone);
- logModelStatus(assetId, 'cache-loaded');
+ logModelStatus(assetId, "cache-loaded");
return;
}
// Check IndexedDB
- retrieveGLTF(assetId).then((indexedDBModel) => {
- if (indexedDBModel) {
- const blobUrl = URL.createObjectURL(indexedDBModel);
- loader.load(
- blobUrl,
- (gltf) => {
- URL.revokeObjectURL(blobUrl);
- THREE.Cache.remove(blobUrl);
- THREE.Cache.add(assetId, gltf);
- setGltfScene(gltf.scene.clone());
- calculateBoundingBox(gltf.scene);
- logModelStatus(assetId, 'indexedDB-loaded');
- },
- undefined,
- (error) => {
- echo.error(`[IndexedDB] Error loading ${asset.modelName}:`);
- URL.revokeObjectURL(blobUrl);
- }
- );
- return;
- }
-
- // Fetch from Backend
- const modelUrl = `${url_Backend_dwinzo}/api/v2/AssetFile/${assetId}`;
- loader.load(
- modelUrl,
- (gltf: GLTF) => {
- fetch(modelUrl)
- .then((response) => response.blob())
- .then((modelBlob) => storeGLTF(assetId, modelBlob))
- .then(() => {
+ retrieveGLTF(assetId)
+ .then((indexedDBModel) => {
+ if (indexedDBModel) {
+ const blobUrl = URL.createObjectURL(indexedDBModel);
+ loader.load(
+ blobUrl,
+ (gltf) => {
+ URL.revokeObjectURL(blobUrl);
+ THREE.Cache.remove(blobUrl);
THREE.Cache.add(assetId, gltf);
setGltfScene(gltf.scene.clone());
calculateBoundingBox(gltf.scene);
- logModelStatus(assetId, 'backend-loaded');
- })
- .catch((error) => {
- console.error(
- `[Backend] Error storing/loading ${asset.modelName}:`,
- error
- );
- });
- },
- undefined,
- (error) => {
- echo.error(`[Backend] Error loading ${asset.modelName}:`);
+ logModelStatus(assetId, "indexedDB-loaded");
+ },
+ undefined,
+ () => {
+ echo.error(`[IndexedDB] Error loading ${asset.modelName}:`);
+ URL.revokeObjectURL(blobUrl);
+ }
+ );
+ return;
}
- );
- }).catch((err) => {
- console.error("Failed to load model:", asset.assetId, err);
- });
+
+ // Fetch from Backend
+ const modelUrl = `${url_Backend_dwinzo}/api/v2/AssetFile/${assetId}`;
+ loader.load(
+ modelUrl,
+ (gltf: GLTF) => {
+ fetch(modelUrl)
+ .then((response) => response.blob())
+ .then((modelBlob) => storeGLTF(assetId, modelBlob))
+ .then(() => {
+ THREE.Cache.add(assetId, gltf);
+ setGltfScene(gltf.scene.clone());
+ calculateBoundingBox(gltf.scene);
+ logModelStatus(assetId, "backend-loaded");
+ })
+ .catch((error) => {
+ console.error(`[Backend] Error storing/loading ${asset.modelName}:`, error);
+ });
+ },
+ undefined,
+ () => {
+ echo.error(`[Backend] Error loading ${asset.modelName}:`);
+ }
+ );
+ })
+ .catch((err) => {
+ console.error("Failed to load model:", asset.assetId, err);
+ });
}, []);
const { handleDblClick, handleClick, handlePointerOver, handlePointerOut, handleContextMenu } = useModelEventHandlers({ boundingBox, groupRef, asset });
@@ -164,7 +163,7 @@ function Model({ asset, isRendered, loader }: Readonly<{ asset: Asset; isRendere
return (
{isRendered ? (
<>
-
-
>
) : (
- <>
- {!isSelected &&
-
- }
- >
+ <>{!isSelected && }>
)}
- {isSelected &&
-
- }
+ {isSelected && }
>
)}
);
}
-export default Model;
\ No newline at end of file
+export default Model;
diff --git a/app/src/modules/builder/asset/models/models.tsx b/app/src/modules/builder/asset/models/models.tsx
index 78eacab..61be1b2 100644
--- a/app/src/modules/builder/asset/models/models.tsx
+++ b/app/src/modules/builder/asset/models/models.tsx
@@ -1,13 +1,13 @@
import { useEffect, useRef, useState } from "react";
import { useThree, useFrame } from "@react-three/fiber";
import { Group, Vector3 } from "three";
-import { CameraControls } from '@react-three/drei';
-import { useLimitDistance, useRenderDistance } from '../../../../store/builder/store';
-import { useSelectedAsset } from '../../../../store/simulation/useSimulationStore';
-import { useSceneContext } from '../../../scene/sceneContext';
+import { CameraControls } from "@react-three/drei";
+import { useLimitDistance, useRenderDistance } from "../../../../store/builder/store";
+import { useSelectedAsset } from "../../../../store/simulation/useSimulationStore";
+import { useSceneContext } from "../../../scene/sceneContext";
import { useBuilderStore } from "../../../../store/builder/useBuilderStore";
-import Model from './model/model';
+import Model from "./model/model";
import { GLTFLoader } from "three/examples/jsm/Addons";
const distanceWorker = new Worker(new URL("../../../../services/factoryBuilder/webWorkers/distanceWorker.js", import.meta.url));
@@ -15,7 +15,7 @@ const distanceWorker = new Worker(new URL("../../../../services/factoryBuilder/w
function Models({ loader }: { readonly loader: GLTFLoader }) {
const { controls, camera } = useThree();
const assetGroupRef = useRef(null);
- const { assetStore } = useSceneContext();
+ const { assetStore, layout } = useSceneContext();
const { assets } = assetStore();
const { selectedFloorAsset, setSelectedFloorAsset } = useBuilderStore();
const { selectedAsset, clearSelectedAsset } = useSelectedAsset();
@@ -40,13 +40,13 @@ function Models({ loader }: { readonly loader: GLTFLoader }) {
camera.getWorldPosition(cameraPos.current);
for (const asset of assets) {
const isRendered = renderMap[asset.modelUuid] ?? false;
- distanceWorker.postMessage({ modelUuid: asset.modelUuid, assetPosition: { x: asset.position[0], y: asset.position[1], z: asset.position[2], }, cameraPosition: cameraPos.current, limitDistance, renderDistance, isRendered, });
+ distanceWorker.postMessage({ modelUuid: asset.modelUuid, assetPosition: { x: asset.position[0], y: asset.position[1], z: asset.position[2] }, cameraPosition: cameraPos.current, limitDistance, renderDistance, isRendered });
}
});
return (
{
e.stopPropagation();
@@ -67,4 +67,4 @@ function Models({ loader }: { readonly loader: GLTFLoader }) {
);
}
-export default Models;
\ No newline at end of file
+export default Models;
diff --git a/app/src/modules/scene/camera/syncCam.tsx b/app/src/modules/scene/camera/syncCam.tsx
new file mode 100644
index 0000000..647ef28
--- /dev/null
+++ b/app/src/modules/scene/camera/syncCam.tsx
@@ -0,0 +1,32 @@
+import { useFrame, useThree } from "@react-three/fiber";
+import { useSceneContext } from "../sceneContext";
+import { CameraControls } from "@react-three/drei";
+import { useIsComparing } from "../../../store/builder/store";
+import useModuleStore from "../../../store/ui/useModuleStore";
+import { useComparisonProduct } from "../../../store/simulation/useSimulationStore";
+import { useSceneStore } from "../../../store/scene/useSceneStore";
+import { Vector3 } from "three";
+
+function SyncCam() {
+ const { layout } = useSceneContext();
+ const { controls } = useThree();
+ const { isComparing } = useIsComparing();
+ const { activeModule } = useModuleStore();
+ const { comparisonProduct } = useComparisonProduct();
+ const { setCamera, camState } = useSceneStore();
+
+ useFrame(() => {
+ if (layout === "Comparison Layout" && controls && camState) {
+ (controls as CameraControls).setLookAt(camState.position.x, camState.position.y, camState.position.z, camState.target.x, camState.target.y, camState.target.z, true);
+ }
+ if (layout === "Main Layout" && controls && isComparing && activeModule === "simulation" && comparisonProduct) {
+ const position = (controls as CameraControls).getPosition(new Vector3());
+ const target = (controls as CameraControls).getTarget(new Vector3());
+ setCamera(position, target);
+ }
+ });
+
+ return <>>;
+}
+
+export default SyncCam;
diff --git a/app/src/modules/scene/controls/controls.tsx b/app/src/modules/scene/controls/controls.tsx
index 3e34faf..942b7f1 100644
--- a/app/src/modules/scene/controls/controls.tsx
+++ b/app/src/modules/scene/controls/controls.tsx
@@ -2,7 +2,7 @@ import { CameraControls } from "@react-three/drei";
import { useRef, useEffect } from "react";
import { useThree } from "@react-three/fiber";
import * as THREE from "three";
-import * as CONSTANTS from '../../../types/world/worldConstants';
+import * as CONSTANTS from "../../../types/world/worldConstants";
import { useSocketStore, useToggleView, useResetCamera } from "../../../store/builder/store";
import CamMode from "../camera/camMode";
@@ -20,6 +20,7 @@ import { getUserData } from "../../../functions/getUserData";
import { getCameraApi } from "../../../services/factoryBuilder/camera/getCameraApi";
import { setCameraApi } from "../../../services/factoryBuilder/camera/setCameraApi";
import updateCamPosition from "../camera/functions/updateCameraPosition";
+import SyncCam from "../camera/syncCam";
export default function Controls() {
const controlsRef = useRef(null);
@@ -38,15 +39,17 @@ export default function Controls() {
}
if (!projectId) return;
- getCameraApi(projectId).then((data) => {
- if (data?.position && data?.target) {
- controlsRef.current?.setPosition(data.position.x, data.position.y, data.position.z);
- controlsRef.current?.setTarget(data.target.x, data.target.y, data.target.z);
- } else {
- controlsRef.current?.setPosition(...CONSTANTS.threeDimension.defaultPosition);
- controlsRef.current?.setTarget(...CONSTANTS.threeDimension.defaultTarget);
- }
- }).catch((error) => console.error("Failed to fetch camera data:", error));
+ getCameraApi(projectId)
+ .then((data) => {
+ if (data?.position && data?.target) {
+ controlsRef.current?.setPosition(data.position.x, data.position.y, data.position.z);
+ controlsRef.current?.setTarget(data.target.x, data.target.y, data.target.z);
+ } else {
+ controlsRef.current?.setPosition(...CONSTANTS.threeDimension.defaultPosition);
+ controlsRef.current?.setTarget(...CONSTANTS.threeDimension.defaultTarget);
+ }
+ })
+ .catch((error) => console.error("Failed to fetch camera data:", error));
}, [projectId]);
useEffect(() => {
@@ -56,12 +59,7 @@ export default function Controls() {
controlsRef.current?.rotateAzimuthTo(CONSTANTS.threeDimension.defaultAzimuth);
if (!socket?.connected) {
- setCameraApi(
- projectId,
- new THREE.Vector3(...CONSTANTS.threeDimension.defaultPosition),
- new THREE.Vector3(...CONSTANTS.threeDimension.defaultTarget),
- new THREE.Vector3(...CONSTANTS.threeDimension.defaultRotation),
- )
+ setCameraApi(projectId, new THREE.Vector3(...CONSTANTS.threeDimension.defaultPosition), new THREE.Vector3(...CONSTANTS.threeDimension.defaultTarget), new THREE.Vector3(...CONSTANTS.threeDimension.defaultRotation));
} else {
const camData = {
organization,
@@ -70,9 +68,9 @@ export default function Controls() {
target: new THREE.Vector3(...CONSTANTS.threeDimension.defaultTarget),
rotation: new THREE.Vector3(...CONSTANTS.threeDimension.defaultRotation),
socketId: socket.id,
- projectId
+ projectId,
};
- socket.emit('v1:Camera:set', camData)
+ socket.emit("v1:Camera:set", camData);
}
setResetCamera(false);
@@ -152,6 +150,7 @@ export default function Controls() {
+
@@ -165,7 +164,6 @@ export default function Controls() {
-
>
);
-}
\ No newline at end of file
+}
diff --git a/app/src/modules/scene/environment/shadow.tsx b/app/src/modules/scene/environment/shadow.tsx
index 03cf942..77df5ba 100644
--- a/app/src/modules/scene/environment/shadow.tsx
+++ b/app/src/modules/scene/environment/shadow.tsx
@@ -1,13 +1,7 @@
import { useRef, useEffect } from "react";
import { useThree } from "@react-three/fiber";
import * as THREE from "three";
-import {
- useAzimuth,
- useElevation,
- useShadows,
- useSunPosition,
- useTileDistance,
-} from "../../../store/builder/store";
+import { useAzimuth, useElevation, useShadows, useSunPosition, useTileDistance } from "../../../store/builder/store";
import * as CONSTANTS from "../../../types/world/worldConstants";
const shadowWorker = new Worker(new URL("../../../services/factoryBuilder/webWorkers/shadowWorker", import.meta.url));
@@ -67,31 +61,11 @@ export default function Shadows() {
{/* {(lightRef.current?.shadow) &&
} */}
-
+
-
+
-
+
>
);
diff --git a/app/src/store/builder/store.ts b/app/src/store/builder/store.ts
index 461fd77..e9eff60 100644
--- a/app/src/store/builder/store.ts
+++ b/app/src/store/builder/store.ts
@@ -8,12 +8,7 @@ type SocketStore = {
dashBoardSocket?: ReturnType | null;
projectSocket?: ReturnType | null;
threadSocket?: ReturnType | null;
- initializeSocket: (
- email?: string,
- organization?: string,
- token?: string,
- refreshToken?: string
- ) => void;
+ initializeSocket: (email?: string, organization?: string, token?: string, refreshToken?: string) => void;
disconnectSocket: () => void;
};
@@ -23,54 +18,34 @@ export const useSocketStore = create((set, get) => ({
dashBoardSocket: null,
projectSocket: null,
threadSocket: null,
- initializeSocket: (
- email?: string,
- organization?: string,
- token?: string,
- refreshToken?: string
- ) => {
+ initializeSocket: (email?: string, organization?: string, token?: string, refreshToken?: string) => {
const existingSocket = get().socket;
if (existingSocket) {
return;
}
- const socket = io(
- `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Builder_v1`,
- {
- reconnection: true,
- auth: { token, refreshToken },
- }
- );
+ const socket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Builder_v1`, {
+ reconnection: true,
+ auth: { token, refreshToken },
+ });
- const visualizationSocket = io(
- `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Visualization_v1`,
- {
- reconnection: true,
- auth: { token, refreshToken },
- }
- );
+ const visualizationSocket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Visualization_v1`, {
+ reconnection: true,
+ auth: { token, refreshToken },
+ });
- const dashBoardSocket = io(
- `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/dashboard`,
- {
- reconnection: true,
- auth: { token, refreshToken },
- }
- );
- const projectSocket = io(
- `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/project`,
- {
- reconnection: true,
- auth: { token, refreshToken },
- }
- );
- const threadSocket = io(
- `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/thread`,
- {
- reconnection: true,
- auth: { token, refreshToken },
- }
- );
+ const dashBoardSocket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/dashboard`, {
+ reconnection: true,
+ auth: { token, refreshToken },
+ });
+ const projectSocket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/project`, {
+ reconnection: true,
+ auth: { token, refreshToken },
+ });
+ const threadSocket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/thread`, {
+ reconnection: true,
+ auth: { token, refreshToken },
+ });
set({
socket,
@@ -154,8 +129,7 @@ export const useShadows = create((set: any) => ({
export const useSunPosition = create((set: any) => ({
sunPosition: { x: undefined, y: undefined, z: undefined },
- setSunPosition: (newSuntPosition: any) =>
- set({ sunPosition: newSuntPosition }),
+ setSunPosition: (newSuntPosition: any) => set({ sunPosition: newSuntPosition }),
}));
export const useProjectName = create((set: any) => ({
@@ -215,14 +189,12 @@ export const useRenameModeStore = create((set: any) => ({
export const useObjectPosition = create((set: any) => ({
objectPosition: { x: undefined, y: undefined, z: undefined },
- setObjectPosition: (newObjectPosition: any) =>
- set({ objectPosition: newObjectPosition }),
+ setObjectPosition: (newObjectPosition: any) => set({ objectPosition: newObjectPosition }),
}));
export const useObjectRotation = create((set: any) => ({
objectRotation: { x: undefined, y: undefined, z: undefined },
- setObjectRotation: (newObjectRotation: any) =>
- set({ objectRotation: newObjectRotation }),
+ setObjectRotation: (newObjectRotation: any) => set({ objectRotation: newObjectRotation }),
}));
export const useDrieTemp = create((set: any) => ({
@@ -234,16 +206,14 @@ 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: typeof callback === "function" ? callback(state.activeUsers) : callback,
})),
}));
export const useDrieUIValue = create((set: any) => ({
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) => ({
@@ -367,8 +337,7 @@ interface ShortcutStore {
export const useShortcutStore = create((set) => ({
showShortcuts: false,
setShowShortcuts: (value) => set({ showShortcuts: value }),
- toggleShortcuts: () =>
- set((state) => ({ showShortcuts: !state.showShortcuts })),
+ toggleShortcuts: () => set((state) => ({ showShortcuts: !state.showShortcuts })),
}));
export const useMachineCount = create((set: any) => ({
@@ -470,19 +439,18 @@ interface CompareStore {
export const useCompareStore = create((set) => ({
comparePopUp: false,
setComparePopUp: (value) => set({ comparePopUp: value }),
- toggleComparePopUp: () =>
- set((state) => ({ comparePopUp: !state.comparePopUp })),
+ toggleComparePopUp: () => set((state) => ({ comparePopUp: !state.comparePopUp })),
}));
// Save state store
-interface SaveVersionStore {
- isVersionSaved: boolean;
- setIsVersionSaved: (value: boolean) => void;
+interface IsComparingStore {
+ isComparing: boolean;
+ setIsComparing: (value: boolean) => void;
}
-export const useSaveVersion = create((set) => ({
- isVersionSaved: false,
- setIsVersionSaved: (value: boolean) => set({ isVersionSaved: value }),
+export const useIsComparing = create((set) => ({
+ isComparing: false,
+ setIsComparing: (value: boolean) => set({ isComparing: value }),
}));
interface ViewSceneState {
@@ -494,8 +462,7 @@ export const useViewSceneStore = create((set) => ({
viewSceneLabels: getInitialViewSceneLabels(),
setViewSceneLabels: (value) => {
set((state) => {
- const newValue =
- typeof value === "function" ? value(state.viewSceneLabels) : value;
+ const newValue = typeof value === "function" ? value(state.viewSceneLabels) : value;
// Store in localStorage manually
localStorage.setItem("viewSceneLabels", JSON.stringify(newValue));
@@ -558,4 +525,4 @@ export const useSelectedPath = create((set: any) => ({
export const useContextActionStore = create((set: any) => ({
contextAction: null,
setContextAction: (x: any) => set({ contextAction: x }),
-}));
\ No newline at end of file
+}));
diff --git a/app/src/store/scene/useSceneStore.ts b/app/src/store/scene/useSceneStore.ts
new file mode 100644
index 0000000..f0c452a
--- /dev/null
+++ b/app/src/store/scene/useSceneStore.ts
@@ -0,0 +1,27 @@
+import { create } from "zustand";
+import { immer } from "zustand/middleware/immer";
+import * as THREE from "three";
+
+type SceneStore = {
+ camState: {
+ position: THREE.Vector3;
+ target: THREE.Vector3;
+ };
+ setCamera: (pos: THREE.Vector3, target: THREE.Vector3) => void;
+};
+
+export const useSceneStore = create()(
+ immer((set) => ({
+ camState: {
+ position: new THREE.Vector3(0, 5, 10),
+ target: new THREE.Vector3(0, 0, 0),
+ },
+
+ setCamera: (pos, target) =>
+ set((state) => {
+ state.camState.position.copy(pos);
+
+ state.camState.target.copy(target);
+ }),
+ }))
+);
diff --git a/app/src/utils/shortcutkeys/handleShortcutKeys.ts b/app/src/utils/shortcutkeys/handleShortcutKeys.ts
index 6c00911..21d69eb 100644
--- a/app/src/utils/shortcutkeys/handleShortcutKeys.ts
+++ b/app/src/utils/shortcutkeys/handleShortcutKeys.ts
@@ -1,7 +1,7 @@
import React, { useEffect } from "react";
import useModuleStore, { useSubModuleStore, useThreeDStore } from "../../store/ui/useModuleStore";
import { usePlayerStore, useToggleStore } from "../../store/ui/useUIToggleStore";
-import useVersionHistoryVisibleStore, { useActiveSubTool, useActiveTool, useAddAction, useDfxUpload, useRenameModeStore, useSaveVersion, useSelectedComment, useShortcutStore, useToggleView, useToolMode, useViewSceneStore } from "../../store/builder/store";
+import useVersionHistoryVisibleStore, { useActiveSubTool, useActiveTool, useAddAction, useDfxUpload, useRenameModeStore, useIsComparing, useSelectedComment, useShortcutStore, useToggleView, useToolMode, useViewSceneStore } from "../../store/builder/store";
import useCameraModeStore, { usePlayButtonStore } from "../../store/ui/usePlayButtonStore";
import { detectModifierKeys } from "./detectModifierKeys";
import { useSelectedZoneStore } from "../../store/visualization/useZoneStore";
@@ -27,7 +27,7 @@ const KeyPressListener: React.FC = () => {
const { clearSelectedZone } = useSelectedZoneStore();
const { showShortcuts, setShowShortcuts } = useShortcutStore();
const { setWalkMode } = useCameraModeStore();
- const { setIsVersionSaved } = useSaveVersion();
+ const { setIsComparing } = useIsComparing();
const { isLogListVisible, setIsLogListVisible } = useLogger();
const { hidePlayer, setHidePlayer } = usePlayerStore();
const { setViewSceneLabels } = useViewSceneStore();
@@ -177,7 +177,7 @@ const KeyPressListener: React.FC = () => {
setIsPlaying(false);
clearSelectedZone();
setShowShortcuts(false);
- setIsVersionSaved(false);
+ setIsComparing(false);
clearComparisonProduct();
setIsLogListVisible(false);
setIsRenameMode(false);