356 lines
21 KiB
TypeScript
356 lines
21 KiB
TypeScript
import * as THREE from "three"
|
|
import { useEffect } from 'react'
|
|
import { getFloorAssets } from '../../../services/factoryBuilder/asset/floorAsset/getFloorItemsApi';
|
|
import { useLoadingProgress, useRenameModeStore, useSelectedFloorItem, useSelectedItem, useSocketStore } from '../../../store/builder/store';
|
|
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
|
|
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
|
|
import { FloorItems, RefMesh } from "../../../types/world/worldTypes";
|
|
import Models from "./models/models";
|
|
import useModuleStore from "../../../store/useModuleStore";
|
|
import { useThree } from "@react-three/fiber";
|
|
import { CameraControls } from "@react-three/drei";
|
|
import addAssetModel from "./functions/addAssetModel";
|
|
import { useParams } from "react-router-dom";
|
|
import { useLeftData, useTopData } from "../../../store/visualization/useZone3DWidgetStore";
|
|
import { getUserData } from "../../../functions/getUserData";
|
|
import { useSceneContext } from "../../scene/sceneContext";
|
|
import { useVersionContext } from "../version/versionContext";
|
|
|
|
const gltfLoaderWorker = new Worker(new URL("../../../services/factoryBuilder/webWorkers/gltfLoaderWorker.js", import.meta.url));
|
|
|
|
function AssetsGroup({ plane }: { readonly plane: RefMesh }) {
|
|
const { activeModule } = useModuleStore();
|
|
const { socket } = useSocketStore();
|
|
const { controls, gl, pointer, camera, raycaster, scene } = useThree();
|
|
const { setLoadingProgress } = useLoadingProgress();
|
|
const { assetStore, eventStore } = useSceneContext();
|
|
const { selectedVersionStore } = useVersionContext();
|
|
const { selectedVersion } = selectedVersionStore();
|
|
const { setAssets, addAsset, clearAssets } = assetStore();
|
|
const { addEvent, clearEvents } = eventStore();
|
|
const { setSelectedFloorItem } = useSelectedFloorItem();
|
|
const { selectedItem, setSelectedItem } = useSelectedItem();
|
|
const { projectId } = useParams();
|
|
const { isRenameMode, setIsRenameMode } = useRenameModeStore();
|
|
const { userId, organization } = getUserData();
|
|
const { setTop } = useTopData();
|
|
const { setLeft } = useLeftData();
|
|
|
|
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);
|
|
|
|
useEffect(() => {
|
|
if (!projectId || !selectedVersion) return;
|
|
|
|
clearEvents();
|
|
|
|
let totalAssets = 0;
|
|
let loadedAssets = 0;
|
|
|
|
const updateLoadingProgress = (progress: number) => {
|
|
if (progress < 100) {
|
|
setLoadingProgress(progress);
|
|
} else if (progress === 100) {
|
|
setTimeout(() => {
|
|
setLoadingProgress(100);
|
|
setTimeout(() => {
|
|
setLoadingProgress(0);
|
|
}, 1500);
|
|
}, 1000);
|
|
}
|
|
};
|
|
|
|
getFloorAssets(organization, projectId, selectedVersion?.versionId || '').then((data) => {
|
|
if (data && data.length > 0) {
|
|
const uniqueItems = (data as FloorItems).filter((item, index, self) => index === self.findIndex((t) => t.assetId === item.assetId));
|
|
totalAssets = uniqueItems.length;
|
|
if (totalAssets === 0) {
|
|
updateLoadingProgress(100);
|
|
return;
|
|
}
|
|
gltfLoaderWorker.postMessage({ floorItems: uniqueItems });
|
|
} else {
|
|
gltfLoaderWorker.postMessage({ floorItems: [] });
|
|
updateLoadingProgress(100);
|
|
clearAssets();
|
|
}
|
|
}).catch((err) => {
|
|
console.error(err);
|
|
})
|
|
|
|
gltfLoaderWorker.onmessage = async (event) => {
|
|
if (event.data.message === "gltfLoaded" && event.data.modelBlob) {
|
|
const blobUrl = URL.createObjectURL(event.data.modelBlob);
|
|
loader.load(blobUrl, (gltf) => {
|
|
URL.revokeObjectURL(blobUrl);
|
|
THREE.Cache.remove(blobUrl);
|
|
THREE.Cache.add(event.data.modelID, gltf);
|
|
|
|
loadedAssets++;
|
|
const progress = Math.round((loadedAssets / totalAssets) * 100);
|
|
updateLoadingProgress(progress);
|
|
|
|
if (loadedAssets === totalAssets) {
|
|
const assets: Asset[] = [];
|
|
getFloorAssets(organization, projectId, selectedVersion.versionId || '').then((data: FloorItems) => {
|
|
data.forEach((item) => {
|
|
if (item.eventData) {
|
|
assets.push({
|
|
modelUuid: item.modelUuid,
|
|
modelName: item.modelName,
|
|
assetId: item.assetId,
|
|
position: item.position,
|
|
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
|
isLocked: item.isLocked,
|
|
isCollidable: false,
|
|
isVisible: item.isVisible,
|
|
opacity: 1,
|
|
eventData: item.eventData
|
|
})
|
|
|
|
if (item.eventData.type === "Vehicle") {
|
|
const vehicleEvent: VehicleEventSchema = {
|
|
modelUuid: item.modelUuid,
|
|
modelName: item.modelName,
|
|
position: item.position,
|
|
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
|
state: "idle",
|
|
type: "vehicle",
|
|
speed: 1,
|
|
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: "travel",
|
|
unLoadDuration: 5,
|
|
loadCapacity: 1,
|
|
steeringAngle: 0,
|
|
pickUpPoint: null,
|
|
unLoadPoint: null,
|
|
paths: {
|
|
initPickup: [],
|
|
pickupDrop: [],
|
|
dropPickup: [],
|
|
},
|
|
triggers: []
|
|
}
|
|
}
|
|
};
|
|
addEvent(vehicleEvent);
|
|
} else if (item.eventData.type === "Conveyor") {
|
|
const ConveyorEvent: ConveyorEventSchema = {
|
|
modelUuid: item.modelUuid,
|
|
modelName: item.modelName,
|
|
position: item.position,
|
|
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
|
state: "idle",
|
|
type: "transfer",
|
|
speed: 1,
|
|
points: item.eventData.points?.map((point: any, index: number) => ({
|
|
uuid: point.uuid || THREE.MathUtils.generateUUID(),
|
|
position: [point.position[0], point.position[1], point.position[2]],
|
|
rotation: [point.rotation[0], point.rotation[1], point.rotation[2]],
|
|
action: {
|
|
actionUuid: THREE.MathUtils.generateUUID(),
|
|
actionName: `Action 1`,
|
|
actionType: 'default',
|
|
material: 'Default material',
|
|
delay: 0,
|
|
spawnInterval: 5,
|
|
spawnCount: 1,
|
|
triggers: []
|
|
}
|
|
})) || [],
|
|
};
|
|
addEvent(ConveyorEvent);
|
|
} else if (item.eventData.type === "StaticMachine") {
|
|
const machineEvent: MachineEventSchema = {
|
|
modelUuid: item.modelUuid,
|
|
modelName: item.modelName,
|
|
position: item.position,
|
|
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
|
state: "idle",
|
|
type: "machine",
|
|
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: "process",
|
|
processTime: 10,
|
|
swapMaterial: "Default Material",
|
|
triggers: []
|
|
}
|
|
}
|
|
};
|
|
addEvent(machineEvent);
|
|
} else if (item.eventData.type === "ArmBot") {
|
|
const roboticArmEvent: RoboticArmEventSchema = {
|
|
modelUuid: item.modelUuid,
|
|
modelName: item.modelName,
|
|
position: item.position,
|
|
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
|
state: "idle",
|
|
type: "roboticArm",
|
|
speed: 1,
|
|
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],
|
|
actions: [
|
|
{
|
|
actionUuid: THREE.MathUtils.generateUUID(),
|
|
actionName: "Action 1",
|
|
actionType: "pickAndPlace",
|
|
process: {
|
|
startPoint: null,
|
|
endPoint: null
|
|
},
|
|
triggers: []
|
|
}
|
|
]
|
|
}
|
|
};
|
|
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 if (item.eventData.type === 'Human') {
|
|
const humanEvent: HumanEventSchema = {
|
|
modelUuid: item.modelUuid,
|
|
modelName: item.modelName,
|
|
position: item.position,
|
|
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
|
state: "idle",
|
|
type: "human",
|
|
speed: 1,
|
|
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],
|
|
actions: [
|
|
{
|
|
actionUuid: THREE.MathUtils.generateUUID(),
|
|
actionName: "Action 1",
|
|
actionType: "worker",
|
|
loadCount: 1,
|
|
assemblyCount: 1,
|
|
loadCapacity: 1,
|
|
processTime: 10,
|
|
triggers: []
|
|
}
|
|
]
|
|
}
|
|
}
|
|
addEvent(humanEvent);
|
|
}
|
|
} else {
|
|
assets.push({
|
|
modelUuid: item.modelUuid,
|
|
modelName: item.modelName,
|
|
assetId: item.assetId,
|
|
position: item.position,
|
|
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
|
isLocked: item.isLocked,
|
|
isCollidable: false,
|
|
isVisible: item.isVisible,
|
|
opacity: 1,
|
|
})
|
|
}
|
|
})
|
|
setAssets(assets);
|
|
})
|
|
updateLoadingProgress(100);
|
|
}
|
|
});
|
|
}
|
|
};
|
|
}, [selectedVersion?.versionId]);
|
|
|
|
useEffect(() => {
|
|
const canvasElement = gl.domElement;
|
|
|
|
const onDrop = (event: DragEvent) => {
|
|
if (!event.dataTransfer?.files[0]) return;
|
|
|
|
if (selectedItem.id !== "" && event.dataTransfer?.files[0] && selectedItem.category !== 'Fenestration') {
|
|
|
|
pointer.x = (event.clientX / window.innerWidth) * 2 - 1;
|
|
pointer.y = -(event.clientY / window.innerHeight) * 2 + 1;
|
|
|
|
addAssetModel(scene, raycaster, camera, pointer, socket, selectedItem, setSelectedItem, addEvent, addAsset, plane, loader, selectedVersion, projectId, userId);
|
|
}
|
|
};
|
|
|
|
const onDragOver = (event: any) => {
|
|
event.preventDefault();
|
|
};
|
|
|
|
const onMouseMove = (evt: any) => {
|
|
if (!canvasElement) return;
|
|
const canvasRect = canvasElement.getBoundingClientRect();
|
|
const relativeX = evt.clientX - canvasRect.left;
|
|
const relativeY = evt.clientY - canvasRect.top;
|
|
if (!isRenameMode) {
|
|
setTop(relativeY);
|
|
setLeft(relativeX);
|
|
}
|
|
};
|
|
const onMouseUp = (evt: any) => {
|
|
setIsRenameMode(false);
|
|
}
|
|
|
|
if (activeModule === "builder") {
|
|
canvasElement.addEventListener("drop", onDrop);
|
|
canvasElement.addEventListener("dragover", onDragOver);
|
|
canvasElement.addEventListener("mousemove", onMouseMove);
|
|
canvasElement.addEventListener("mouseup", onMouseUp);
|
|
} else {
|
|
if ((controls as CameraControls)) {
|
|
const target = (controls as CameraControls).getTarget(new THREE.Vector3());
|
|
(controls as CameraControls).setTarget(target.x, 0, target.z, true);
|
|
setSelectedFloorItem(null);
|
|
}
|
|
}
|
|
|
|
return () => {
|
|
canvasElement.removeEventListener("drop", onDrop);
|
|
canvasElement.removeEventListener("dragover", onDragOver);
|
|
canvasElement.removeEventListener("mousemove", onMouseMove);
|
|
canvasElement.removeEventListener("mouseup", onMouseUp);
|
|
};
|
|
}, [selectedItem, camera, activeModule, controls, isRenameMode]);
|
|
|
|
return (
|
|
<Models loader={loader} />
|
|
)
|
|
}
|
|
|
|
export default AssetsGroup; |