Merge remote-tracking branch 'origin/main-dev' into main-demo
This commit is contained in:
@@ -44,9 +44,7 @@ function AssetsGroup({ plane }: { readonly plane: RefMesh }) {
|
|||||||
const loader = new GLTFLoader();
|
const loader = new GLTFLoader();
|
||||||
const dracoLoader = new DRACOLoader();
|
const dracoLoader = new DRACOLoader();
|
||||||
|
|
||||||
dracoLoader.setDecoderPath(
|
dracoLoader.setDecoderPath("https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/");
|
||||||
"https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/"
|
|
||||||
);
|
|
||||||
loader.setDRACOLoader(dracoLoader);
|
loader.setDRACOLoader(dracoLoader);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -1,20 +1,51 @@
|
|||||||
import { Box3, BoxGeometry, EdgesGeometry, Vector3 } from "three";
|
import { Line } from "@react-three/drei";
|
||||||
|
import { Box3, Vector3 } from "three";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
|
||||||
|
export const AssetBoundingBox = ({ name, boundingBox, color, lineWidth }: { name: string; boundingBox: Box3 | null; color: string; lineWidth: number; }) => {
|
||||||
|
const { points, size, center } = useMemo(() => {
|
||||||
|
if (!boundingBox) { return { points: [], center: new Vector3(), size: new Vector3(), }; }
|
||||||
|
|
||||||
|
const min = boundingBox.min;
|
||||||
|
const max = boundingBox.max;
|
||||||
|
const center = boundingBox.getCenter(new Vector3());
|
||||||
|
const size = boundingBox.getSize(new Vector3());
|
||||||
|
|
||||||
|
const edges: Array<[number, number, number]> = [
|
||||||
|
[min.x, min.y, min.z], [max.x, min.y, min.z],
|
||||||
|
[max.x, min.y, min.z], [max.x, max.y, min.z],
|
||||||
|
[max.x, max.y, min.z], [min.x, max.y, min.z],
|
||||||
|
[min.x, max.y, min.z], [min.x, min.y, min.z],
|
||||||
|
|
||||||
|
[min.x, min.y, max.z], [max.x, min.y, max.z],
|
||||||
|
[max.x, min.y, max.z], [max.x, max.y, max.z],
|
||||||
|
[max.x, max.y, max.z], [min.x, max.y, max.z],
|
||||||
|
[min.x, max.y, max.z], [min.x, min.y, max.z],
|
||||||
|
|
||||||
|
[min.x, min.y, min.z], [min.x, min.y, max.z],
|
||||||
|
[max.x, min.y, min.z], [max.x, min.y, max.z],
|
||||||
|
[max.x, max.y, min.z], [max.x, max.y, max.z],
|
||||||
|
[min.x, max.y, min.z], [min.x, max.y, max.z],
|
||||||
|
];
|
||||||
|
|
||||||
|
return { points: edges, center, size };
|
||||||
|
}, [boundingBox]);
|
||||||
|
|
||||||
export const AssetBoundingBox = ({ boundingBox }: { boundingBox: Box3 | null }) => {
|
|
||||||
if (!boundingBox) return null;
|
if (!boundingBox) return null;
|
||||||
|
|
||||||
const size = boundingBox.getSize(new Vector3());
|
|
||||||
const center = boundingBox.getCenter(new Vector3());
|
|
||||||
|
|
||||||
const boxGeometry = new BoxGeometry(size.x, size.y, size.z);
|
|
||||||
const edges = new EdgesGeometry(boxGeometry);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<group name='Asset FallBack'>
|
<group name={name}>
|
||||||
<lineSegments position={center}>
|
<Line
|
||||||
<bufferGeometry attach="geometry" {...edges} />
|
segments
|
||||||
<lineBasicMaterial depthWrite={false} attach="material" color="gray" linewidth={1} />
|
depthWrite={false}
|
||||||
</lineSegments>
|
points={points}
|
||||||
|
color={color}
|
||||||
|
lineWidth={lineWidth}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<mesh visible={false} position={center}>
|
||||||
|
<boxGeometry args={[size.x, size.y, size.z]} />
|
||||||
|
</mesh>
|
||||||
</group>
|
</group>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -4,7 +4,7 @@ import { retrieveGLTF, storeGLTF } from '../../../../../utils/indexDB/idbUtils';
|
|||||||
import { GLTF, GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
|
import { GLTF, GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
|
||||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
|
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
|
||||||
import { ThreeEvent, useFrame, useThree } from '@react-three/fiber';
|
import { ThreeEvent, useFrame, useThree } from '@react-three/fiber';
|
||||||
import { useActiveTool, useDeletableFloorItem, useLimitDistance, useRenderDistance, useSelectedFloorItem, useSocketStore, useToggleView, useToolMode } from '../../../../../store/builder/store';
|
import { useActiveTool, useDeletableFloorItem, useLimitDistance, useRenderDistance, useSelectedAssets, useSelectedFloorItem, useSocketStore, useToggleView, useToolMode } from '../../../../../store/builder/store';
|
||||||
import { AssetBoundingBox } from '../../functions/assetBoundingBox';
|
import { AssetBoundingBox } from '../../functions/assetBoundingBox';
|
||||||
import { CameraControls } from '@react-three/drei';
|
import { CameraControls } from '@react-three/drei';
|
||||||
import useModuleStore, { useSubModuleStore } from '../../../../../store/useModuleStore';
|
import useModuleStore, { useSubModuleStore } from '../../../../../store/useModuleStore';
|
||||||
@@ -22,6 +22,7 @@ import { getAssetIksApi } from '../../../../../services/simulation/ik/getAssetIK
|
|||||||
|
|
||||||
function Model({ asset }: { readonly asset: Asset }) {
|
function Model({ asset }: { readonly asset: Asset }) {
|
||||||
const url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
const url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||||
|
const savedTheme: string = localStorage.getItem("theme") || "light";
|
||||||
const { camera, controls, gl } = useThree();
|
const { camera, controls, gl } = useThree();
|
||||||
const { activeTool } = useActiveTool();
|
const { activeTool } = useActiveTool();
|
||||||
const { toolMode } = useToolMode();
|
const { toolMode } = useToolMode();
|
||||||
@@ -51,6 +52,7 @@ function Model({ asset }: { readonly asset: Asset }) {
|
|||||||
const [isRendered, setIsRendered] = useState(false);
|
const [isRendered, setIsRendered] = useState(false);
|
||||||
const [gltfScene, setGltfScene] = useState<GLTF["scene"] | null>(null);
|
const [gltfScene, setGltfScene] = useState<GLTF["scene"] | null>(null);
|
||||||
const [boundingBox, setBoundingBox] = useState<THREE.Box3 | null>(null);
|
const [boundingBox, setBoundingBox] = useState<THREE.Box3 | null>(null);
|
||||||
|
const [isSelected, setIsSelected] = useState(false);
|
||||||
const groupRef = useRef<THREE.Group>(null);
|
const groupRef = useRef<THREE.Group>(null);
|
||||||
const mixerRef = useRef<THREE.AnimationMixer>();
|
const mixerRef = useRef<THREE.AnimationMixer>();
|
||||||
const actions = useRef<{ [name: string]: THREE.AnimationAction }>({});
|
const actions = useRef<{ [name: string]: THREE.AnimationAction }>({});
|
||||||
@@ -62,6 +64,7 @@ function Model({ asset }: { readonly asset: Asset }) {
|
|||||||
const { selectedVersion } = selectedVersionStore();
|
const { selectedVersion } = selectedVersionStore();
|
||||||
const { userId, organization } = getUserData();
|
const { userId, organization } = getUserData();
|
||||||
const { projectId } = useParams();
|
const { projectId } = useParams();
|
||||||
|
const { selectedAssets } = useSelectedAssets();
|
||||||
|
|
||||||
const updateBackend = (
|
const updateBackend = (
|
||||||
productName: string,
|
productName: string,
|
||||||
@@ -456,6 +459,18 @@ function Model({ asset }: { readonly asset: Asset }) {
|
|||||||
|
|
||||||
}, [gl])
|
}, [gl])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedAssets.length > 0) {
|
||||||
|
if (selectedAssets.some((selectedAsset: THREE.Object3D) => selectedAsset.userData.modelUuid === asset.modelUuid)) {
|
||||||
|
setIsSelected(true);
|
||||||
|
} else {
|
||||||
|
setIsSelected(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setIsSelected(false);
|
||||||
|
}
|
||||||
|
}, [selectedAssets])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<group
|
<group
|
||||||
key={asset.modelUuid}
|
key={asset.modelUuid}
|
||||||
@@ -496,11 +511,16 @@ function Model({ asset }: { readonly asset: Asset }) {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{gltfScene && (
|
{gltfScene && (
|
||||||
isRendered ? (
|
<>
|
||||||
<primitive object={gltfScene} />
|
{isRendered ? (
|
||||||
) : (
|
<primitive object={gltfScene} />
|
||||||
<AssetBoundingBox boundingBox={boundingBox} />
|
) : (
|
||||||
)
|
<AssetBoundingBox name='Asset Fallback' boundingBox={boundingBox} color='gray' lineWidth={1} />
|
||||||
|
)}
|
||||||
|
{isSelected &&
|
||||||
|
<AssetBoundingBox name='Asset BBox' boundingBox={boundingBox} color={savedTheme === "dark" ? "#c4abf1" : "#6f42c1"} lineWidth={2.7} />
|
||||||
|
}
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</group>
|
</group>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -242,7 +242,7 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) {
|
|||||||
visible={wallAsset.isVisible}
|
visible={wallAsset.isVisible}
|
||||||
userData={wallAsset}
|
userData={wallAsset}
|
||||||
>
|
>
|
||||||
<Subtraction position={[center.x, center.y, center.z]} scale={[size.x, size.y, wall.wallThickness + 0.05]}>
|
<Subtraction position={[center.x, center.y, 0]} scale={[size.x, size.y, wall.wallThickness + 0.05]}>
|
||||||
<Geometry>
|
<Geometry>
|
||||||
<Base geometry={new THREE.BoxGeometry()} />
|
<Base geometry={new THREE.BoxGeometry()} />
|
||||||
</Geometry>
|
</Geometry>
|
||||||
@@ -265,7 +265,7 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) {
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
let currentObject = e.object as THREE.Object3D;
|
let currentObject = e.object as THREE.Object3D;
|
||||||
while (currentObject) {
|
while (currentObject) {
|
||||||
if (currentObject.name === "Scene") {
|
if (currentObject.userData.wallUuid) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
currentObject = currentObject.parent as THREE.Object3D;
|
currentObject = currentObject.parent as THREE.Object3D;
|
||||||
@@ -286,7 +286,7 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) {
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
let currentObject = e.object as THREE.Object3D;
|
let currentObject = e.object as THREE.Object3D;
|
||||||
while (currentObject) {
|
while (currentObject) {
|
||||||
if (currentObject.name === "Scene") {
|
if (currentObject.userData.wallUuid) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
currentObject = currentObject.parent as THREE.Object3D;
|
currentObject = currentObject.parent as THREE.Object3D;
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ function MoveControls2D({
|
|||||||
|
|
||||||
if (keyCombination === "G") {
|
if (keyCombination === "G") {
|
||||||
if (selectedPoints.length > 0) {
|
if (selectedPoints.length > 0) {
|
||||||
moveAssets();
|
movePoints();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,7 +164,7 @@ function MoveControls2D({
|
|||||||
return new THREE.Vector3().subVectors(pointPosition, hitPoint);
|
return new THREE.Vector3().subVectors(pointPosition, hitPoint);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const moveAssets = useCallback(() => {
|
const movePoints = useCallback(() => {
|
||||||
if (selectedPoints.length === 0) return;
|
if (selectedPoints.length === 0) return;
|
||||||
|
|
||||||
const states: Record<string, { position: THREE.Vector3; rotation?: THREE.Euler; }> = {};
|
const states: Record<string, { position: THREE.Vector3; rotation?: THREE.Euler; }> = {};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as THREE from "three";
|
import * as THREE from "three";
|
||||||
import { useEffect, useMemo } from "react";
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { useFrame, useThree } from "@react-three/fiber";
|
import { useFrame, useThree } from "@react-three/fiber";
|
||||||
import { SkeletonUtils } from "three-stdlib";
|
import { SkeletonUtils } from "three-stdlib";
|
||||||
import { useSelectedAssets, useSocketStore, useToggleView } from "../../../../../store/builder/store";
|
import { useSelectedAssets, useSocketStore, useToggleView } from "../../../../../store/builder/store";
|
||||||
@@ -10,20 +10,18 @@ import { getUserData } from "../../../../../functions/getUserData";
|
|||||||
import { useSceneContext } from "../../../sceneContext";
|
import { useSceneContext } from "../../../sceneContext";
|
||||||
import { useVersionContext } from "../../../../builder/version/versionContext";
|
import { useVersionContext } from "../../../../builder/version/versionContext";
|
||||||
|
|
||||||
// import { setAssetsApi } from '../../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi';
|
// import { setAssetsApi } from "../../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi";
|
||||||
|
|
||||||
const CopyPasteControls3D = ({
|
const CopyPasteControls3D = ({
|
||||||
copiedObjects,
|
copiedObjects,
|
||||||
setCopiedObjects,
|
setCopiedObjects,
|
||||||
pastedObjects,
|
pastedObjects,
|
||||||
setpastedObjects,
|
setpastedObjects,
|
||||||
selectionGroup,
|
|
||||||
setDuplicatedObjects,
|
setDuplicatedObjects,
|
||||||
movedObjects,
|
movedObjects,
|
||||||
setMovedObjects,
|
setMovedObjects,
|
||||||
rotatedObjects,
|
rotatedObjects,
|
||||||
setRotatedObjects,
|
setRotatedObjects,
|
||||||
boundingBoxRef
|
|
||||||
}: any) => {
|
}: any) => {
|
||||||
const { camera, controls, gl, scene, pointer, raycaster } = useThree();
|
const { camera, controls, gl, scene, pointer, raycaster } = useThree();
|
||||||
const { toggleView } = useToggleView();
|
const { toggleView } = useToggleView();
|
||||||
@@ -33,31 +31,67 @@ const CopyPasteControls3D = ({
|
|||||||
const { assetStore, eventStore } = useSceneContext();
|
const { assetStore, eventStore } = useSceneContext();
|
||||||
const { addEvent } = eventStore();
|
const { addEvent } = eventStore();
|
||||||
const { projectId } = useParams();
|
const { projectId } = useParams();
|
||||||
const { assets, addAsset } = assetStore();
|
const { assets, addAsset, setPosition, updateAsset, removeAsset, getAssetById } = assetStore();
|
||||||
const { selectedVersionStore } = useVersionContext();
|
const { selectedVersionStore } = useVersionContext();
|
||||||
const { selectedVersion } = selectedVersionStore();
|
const { selectedVersion } = selectedVersionStore();
|
||||||
const { userId, organization } = getUserData();
|
const { userId, organization } = getUserData();
|
||||||
|
|
||||||
|
const [isPasting, setIsPasting] = useState(false);
|
||||||
|
const [relativePositions, setRelativePositions] = useState<THREE.Vector3[]>([]);
|
||||||
|
const [centerOffset, setCenterOffset] = useState<THREE.Vector3 | null>(null);
|
||||||
|
const mouseButtonsDown = useRef<{ left: boolean; right: boolean }>({
|
||||||
|
left: false,
|
||||||
|
right: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const calculateRelativePositions = useCallback((objects: THREE.Object3D[]) => {
|
||||||
|
if (objects.length === 0) return { center: new THREE.Vector3(), relatives: [] };
|
||||||
|
|
||||||
|
const box = new THREE.Box3();
|
||||||
|
objects.forEach(obj => box.expandByObject(obj));
|
||||||
|
const center = new THREE.Vector3();
|
||||||
|
box.getCenter(center);
|
||||||
|
|
||||||
|
const relatives = objects.map(obj => {
|
||||||
|
const relativePos = new THREE.Vector3().subVectors(obj.position, center);
|
||||||
|
return relativePos;
|
||||||
|
});
|
||||||
|
|
||||||
|
return { center, relatives };
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!camera || !scene || toggleView) return;
|
if (!camera || !scene || toggleView) return;
|
||||||
const canvasElement = gl.domElement;
|
const canvasElement = gl.domElement;
|
||||||
canvasElement.tabIndex = 0;
|
canvasElement.tabIndex = 0;
|
||||||
|
|
||||||
let isMoving = false;
|
let isPointerMoving = false;
|
||||||
|
|
||||||
const onPointerDown = () => {
|
const onPointerDown = (event: PointerEvent) => {
|
||||||
isMoving = false;
|
isPointerMoving = false;
|
||||||
|
if (event.button === 0) mouseButtonsDown.current.left = true;
|
||||||
|
if (event.button === 2) mouseButtonsDown.current.right = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const onPointerMove = () => {
|
const onPointerMove = () => {
|
||||||
isMoving = true;
|
isPointerMoving = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const onPointerUp = (event: PointerEvent) => {
|
const onPointerUp = (event: PointerEvent) => {
|
||||||
if (!isMoving && pastedObjects.length > 0 && event.button === 0 && movedObjects.length === 0 && rotatedObjects.length === 0) {
|
if (event.button === 0) mouseButtonsDown.current.left = false;
|
||||||
|
if (event.button === 2) mouseButtonsDown.current.right = false;
|
||||||
|
|
||||||
|
if (!isPointerMoving && pastedObjects.length > 0 && event.button === 0) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
addPastedObjects();
|
addPastedObjects();
|
||||||
}
|
}
|
||||||
|
if (!isPointerMoving && pastedObjects.length > 0 && event.button === 2) {
|
||||||
|
event.preventDefault();
|
||||||
|
clearSelection();
|
||||||
|
pastedObjects.forEach((obj: THREE.Object3D) => {
|
||||||
|
removeAsset(obj.userData.modelUuid);
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onKeyDown = (event: KeyboardEvent) => {
|
const onKeyDown = (event: KeyboardEvent) => {
|
||||||
@@ -69,6 +103,13 @@ const CopyPasteControls3D = ({
|
|||||||
if (keyCombination === "Ctrl+V" && copiedObjects.length > 0 && pastedObjects.length === 0 && movedObjects.length === 0 && rotatedObjects.length === 0) {
|
if (keyCombination === "Ctrl+V" && copiedObjects.length > 0 && pastedObjects.length === 0 && movedObjects.length === 0 && rotatedObjects.length === 0) {
|
||||||
pasteCopiedObjects();
|
pasteCopiedObjects();
|
||||||
}
|
}
|
||||||
|
if (keyCombination === "ESCAPE" && pastedObjects.length > 0) {
|
||||||
|
event.preventDefault();
|
||||||
|
clearSelection();
|
||||||
|
pastedObjects.forEach((obj: THREE.Object3D) => {
|
||||||
|
removeAsset(obj.userData.modelUuid);
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!toggleView) {
|
if (!toggleView) {
|
||||||
@@ -84,27 +125,22 @@ const CopyPasteControls3D = ({
|
|||||||
canvasElement.removeEventListener("pointerup", onPointerUp);
|
canvasElement.removeEventListener("pointerup", onPointerUp);
|
||||||
canvasElement.removeEventListener("keydown", onKeyDown);
|
canvasElement.removeEventListener("keydown", onKeyDown);
|
||||||
};
|
};
|
||||||
|
|
||||||
}, [assets, camera, controls, scene, toggleView, selectedAssets, copiedObjects, pastedObjects, movedObjects, socket, rotatedObjects]);
|
}, [assets, camera, controls, scene, toggleView, selectedAssets, copiedObjects, pastedObjects, movedObjects, socket, rotatedObjects]);
|
||||||
|
|
||||||
useFrame(() => {
|
useFrame(() => {
|
||||||
if (pastedObjects.length > 0) {
|
if (!isPasting || pastedObjects.length === 0) return;
|
||||||
const intersectionPoint = new THREE.Vector3();
|
if (mouseButtonsDown.current.left || mouseButtonsDown.current.right) return;
|
||||||
raycaster.setFromCamera(pointer, camera);
|
|
||||||
const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
const intersectionPoint = new THREE.Vector3();
|
||||||
if (point) {
|
raycaster.setFromCamera(pointer, camera);
|
||||||
const position = new THREE.Vector3();
|
const hit = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
||||||
if (boundingBoxRef.current) {
|
|
||||||
boundingBoxRef.current?.getWorldPosition(position)
|
if (hit && centerOffset) {
|
||||||
selectionGroup.current.position.set(point.x - (position.x - selectionGroup.current.position.x), selectionGroup.current.position.y, point.z - (position.z - selectionGroup.current.position.z));
|
pastedObjects.forEach((pastedObject: THREE.Object3D, index: number) => {
|
||||||
} else {
|
const newPos = new THREE.Vector3().addVectors(hit, relativePositions[index]);
|
||||||
const box = new THREE.Box3();
|
setPosition(pastedObject.userData.modelUuid, [newPos.x, 0, newPos.z]);
|
||||||
pastedObjects.forEach((obj: THREE.Object3D) => box.expandByObject(obj.clone()));
|
});
|
||||||
const center = new THREE.Vector3();
|
|
||||||
box.getCenter(center);
|
|
||||||
selectionGroup.current.position.set(point.x - (center.x - selectionGroup.current.position.x), selectionGroup.current.position.y, point.z - (center.z - selectionGroup.current.position.z));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -122,31 +158,41 @@ const CopyPasteControls3D = ({
|
|||||||
|
|
||||||
const pasteCopiedObjects = () => {
|
const pasteCopiedObjects = () => {
|
||||||
if (copiedObjects.length > 0 && pastedObjects.length === 0) {
|
if (copiedObjects.length > 0 && pastedObjects.length === 0) {
|
||||||
const newClones = copiedObjects.map((obj: THREE.Object3D) => {
|
const { center, relatives } = calculateRelativePositions(copiedObjects);
|
||||||
const clone = obj.clone();
|
setRelativePositions(relatives);
|
||||||
clone.position.copy(obj.position);
|
|
||||||
|
const newPastedObjects = copiedObjects.map((obj: any) => {
|
||||||
|
const clone = SkeletonUtils.clone(obj);
|
||||||
|
clone.userData.modelUuid = THREE.MathUtils.generateUUID();
|
||||||
return clone;
|
return clone;
|
||||||
});
|
});
|
||||||
selectionGroup.current.add(...newClones);
|
|
||||||
setpastedObjects([...newClones]);
|
|
||||||
setSelectedAssets([...newClones]);
|
|
||||||
|
|
||||||
const intersectionPoint = new THREE.Vector3();
|
setpastedObjects(newPastedObjects);
|
||||||
|
|
||||||
raycaster.setFromCamera(pointer, camera);
|
raycaster.setFromCamera(pointer, camera);
|
||||||
const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
const intersectionPoint = new THREE.Vector3();
|
||||||
|
const hit = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
||||||
|
|
||||||
if (point) {
|
if (hit) {
|
||||||
const position = new THREE.Vector3();
|
const offset = new THREE.Vector3().subVectors(center, hit);
|
||||||
if (boundingBoxRef.current) {
|
setCenterOffset(offset);
|
||||||
boundingBoxRef.current?.getWorldPosition(position)
|
setIsPasting(true);
|
||||||
selectionGroup.current.position.set(point.x - (position.x - selectionGroup.current.position.x), selectionGroup.current.position.y, point.z - (position.z - selectionGroup.current.position.z));
|
|
||||||
} else {
|
newPastedObjects.forEach((obj: THREE.Object3D, index: number) => {
|
||||||
const box = new THREE.Box3();
|
const initialPos = new THREE.Vector3().addVectors(hit, relatives[index]);
|
||||||
newClones.forEach((obj: THREE.Object3D) => box.expandByObject(obj.clone()));
|
const asset: Asset = {
|
||||||
const center = new THREE.Vector3();
|
modelUuid: obj.userData.modelUuid,
|
||||||
box.getCenter(center);
|
modelName: obj.userData.modelName,
|
||||||
selectionGroup.current.position.set(point.x - (center.x - selectionGroup.current.position.x), selectionGroup.current.position.y, point.z - (center.z - selectionGroup.current.position.z));
|
assetId: obj.userData.assetId,
|
||||||
}
|
position: initialPos.toArray(),
|
||||||
|
rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z],
|
||||||
|
isLocked: false,
|
||||||
|
isVisible: true,
|
||||||
|
isCollidable: false,
|
||||||
|
opacity: 0.5,
|
||||||
|
};
|
||||||
|
addAsset(asset);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -154,33 +200,33 @@ const CopyPasteControls3D = ({
|
|||||||
const addPastedObjects = () => {
|
const addPastedObjects = () => {
|
||||||
if (pastedObjects.length === 0) return;
|
if (pastedObjects.length === 0) return;
|
||||||
|
|
||||||
pastedObjects.forEach(async (obj: THREE.Object3D) => {
|
pastedObjects.forEach(async (pastedAsset: THREE.Object3D) => {
|
||||||
if (obj) {
|
if (pastedAsset) {
|
||||||
const worldPosition = new THREE.Vector3();
|
const assetUuid = pastedAsset.userData.modelUuid;
|
||||||
obj.getWorldPosition(worldPosition);
|
const asset = getAssetById(assetUuid);
|
||||||
obj.position.copy(worldPosition);
|
if (!asset) return;
|
||||||
|
|
||||||
const newFloorItem: Types.FloorItemType = {
|
const newFloorItem: Types.FloorItemType = {
|
||||||
modelUuid: THREE.MathUtils.generateUUID(),
|
modelUuid: pastedAsset.userData.modelUuid,
|
||||||
modelName: obj.userData.modelName,
|
modelName: pastedAsset.userData.modelName,
|
||||||
assetId: obj.userData.assetId,
|
assetId: pastedAsset.userData.assetId,
|
||||||
position: [worldPosition.x, worldPosition.y, worldPosition.z],
|
position: asset.position,
|
||||||
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z, },
|
rotation: { x: asset.rotation[0], y: asset.rotation[1], z: asset.rotation[2] },
|
||||||
isLocked: false,
|
isLocked: false,
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
let updatedEventData = null;
|
let updatedEventData = null;
|
||||||
|
|
||||||
if (obj.userData.eventData) {
|
if (pastedAsset.userData.eventData) {
|
||||||
updatedEventData = JSON.parse(JSON.stringify(obj.userData.eventData));
|
updatedEventData = JSON.parse(JSON.stringify(pastedAsset.userData.eventData));
|
||||||
updatedEventData.modelUuid = newFloorItem.modelUuid;
|
updatedEventData.modelUuid = newFloorItem.modelUuid;
|
||||||
|
|
||||||
const eventData: any = {
|
const eventData: any = {
|
||||||
type: obj.userData.eventData.type,
|
type: pastedAsset.userData.eventData.type,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (obj.userData.eventData.type === "Conveyor") {
|
if (pastedAsset.userData.eventData.type === "Conveyor") {
|
||||||
const ConveyorEvent: ConveyorEventSchema = {
|
const ConveyorEvent: ConveyorEventSchema = {
|
||||||
modelUuid: newFloorItem.modelUuid,
|
modelUuid: newFloorItem.modelUuid,
|
||||||
modelName: newFloorItem.modelName,
|
modelName: newFloorItem.modelName,
|
||||||
@@ -212,7 +258,7 @@ const CopyPasteControls3D = ({
|
|||||||
rotation: point.rotation
|
rotation: point.rotation
|
||||||
}));
|
}));
|
||||||
|
|
||||||
} else if (obj.userData.eventData.type === "Vehicle") {
|
} else if (pastedAsset.userData.eventData.type === "Vehicle") {
|
||||||
const vehicleEvent: VehicleEventSchema = {
|
const vehicleEvent: VehicleEventSchema = {
|
||||||
modelUuid: newFloorItem.modelUuid,
|
modelUuid: newFloorItem.modelUuid,
|
||||||
modelName: newFloorItem.modelName,
|
modelName: newFloorItem.modelName,
|
||||||
@@ -250,7 +296,7 @@ const CopyPasteControls3D = ({
|
|||||||
rotation: vehicleEvent.point.rotation
|
rotation: vehicleEvent.point.rotation
|
||||||
};
|
};
|
||||||
|
|
||||||
} else if (obj.userData.eventData.type === "ArmBot") {
|
} else if (pastedAsset.userData.eventData.type === "ArmBot") {
|
||||||
const roboticArmEvent: RoboticArmEventSchema = {
|
const roboticArmEvent: RoboticArmEventSchema = {
|
||||||
modelUuid: newFloorItem.modelUuid,
|
modelUuid: newFloorItem.modelUuid,
|
||||||
modelName: newFloorItem.modelName,
|
modelName: newFloorItem.modelName,
|
||||||
@@ -284,7 +330,7 @@ const CopyPasteControls3D = ({
|
|||||||
rotation: roboticArmEvent.point.rotation
|
rotation: roboticArmEvent.point.rotation
|
||||||
};
|
};
|
||||||
|
|
||||||
} else if (obj.userData.eventData.type === "StaticMachine") {
|
} else if (pastedAsset.userData.eventData.type === "StaticMachine") {
|
||||||
const machineEvent: MachineEventSchema = {
|
const machineEvent: MachineEventSchema = {
|
||||||
modelUuid: newFloorItem.modelUuid,
|
modelUuid: newFloorItem.modelUuid,
|
||||||
modelName: newFloorItem.modelName,
|
modelName: newFloorItem.modelName,
|
||||||
@@ -312,7 +358,7 @@ const CopyPasteControls3D = ({
|
|||||||
position: machineEvent.point.position,
|
position: machineEvent.point.position,
|
||||||
rotation: machineEvent.point.rotation
|
rotation: machineEvent.point.rotation
|
||||||
};
|
};
|
||||||
} else if (obj.userData.eventData.type === "Storage") {
|
} else if (pastedAsset.userData.eventData.type === "Storage") {
|
||||||
const storageEvent: StorageEventSchema = {
|
const storageEvent: StorageEventSchema = {
|
||||||
modelUuid: newFloorItem.modelUuid,
|
modelUuid: newFloorItem.modelUuid,
|
||||||
modelName: newFloorItem.modelName,
|
modelName: newFloorItem.modelName,
|
||||||
@@ -339,7 +385,7 @@ const CopyPasteControls3D = ({
|
|||||||
position: storageEvent.point.position,
|
position: storageEvent.point.position,
|
||||||
rotation: storageEvent.point.rotation
|
rotation: storageEvent.point.rotation
|
||||||
};
|
};
|
||||||
} else if (obj.userData.eventData.type === "Human") {
|
} else if (pastedAsset.userData.eventData.type === "Human") {
|
||||||
const humanEvent: HumanEventSchema = {
|
const humanEvent: HumanEventSchema = {
|
||||||
modelUuid: newFloorItem.modelUuid,
|
modelUuid: newFloorItem.modelUuid,
|
||||||
modelName: newFloorItem.modelName,
|
modelName: newFloorItem.modelName,
|
||||||
@@ -374,20 +420,6 @@ const CopyPasteControls3D = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
newFloorItem.eventData = eventData;
|
newFloorItem.eventData = eventData;
|
||||||
//REST
|
|
||||||
|
|
||||||
// await setAssetsApi(
|
|
||||||
// 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 = {
|
const data = {
|
||||||
organization,
|
organization,
|
||||||
@@ -395,7 +427,7 @@ const CopyPasteControls3D = ({
|
|||||||
modelName: newFloorItem.modelName,
|
modelName: newFloorItem.modelName,
|
||||||
assetId: newFloorItem.assetId,
|
assetId: newFloorItem.assetId,
|
||||||
position: newFloorItem.position,
|
position: newFloorItem.position,
|
||||||
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
rotation: { x: pastedAsset.rotation.x, y: pastedAsset.rotation.y, z: pastedAsset.rotation.z },
|
||||||
isLocked: false,
|
isLocked: false,
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
socketId: socket.id,
|
socketId: socket.id,
|
||||||
@@ -405,15 +437,13 @@ const CopyPasteControls3D = ({
|
|||||||
projectId
|
projectId
|
||||||
};
|
};
|
||||||
|
|
||||||
// console.log('data: ', data);
|
//REST
|
||||||
socket.emit("v1:model-asset:add", data);
|
|
||||||
|
|
||||||
obj.userData = {
|
// await setAssetsApi(data);
|
||||||
name: newFloorItem.modelName,
|
|
||||||
modelId: newFloorItem.assetId,
|
//SOCKET
|
||||||
modelUuid: newFloorItem.modelUuid,
|
|
||||||
eventData: JSON.parse(JSON.stringify(eventData))
|
socket.emit("v1:model-asset:add", data);
|
||||||
};
|
|
||||||
|
|
||||||
const asset: Asset = {
|
const asset: Asset = {
|
||||||
modelUuid: data.modelUuid,
|
modelUuid: data.modelUuid,
|
||||||
@@ -426,33 +456,17 @@ const CopyPasteControls3D = ({
|
|||||||
isVisible: data.isVisible,
|
isVisible: data.isVisible,
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
eventData: data.eventData
|
eventData: data.eventData
|
||||||
}
|
};
|
||||||
|
|
||||||
addAsset(asset);
|
|
||||||
|
|
||||||
|
updateAsset(asset.modelUuid, asset);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
//REST
|
|
||||||
|
|
||||||
// await setAssetsApi(
|
|
||||||
// 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 = {
|
const data = {
|
||||||
organization,
|
organization,
|
||||||
modelUuid: newFloorItem.modelUuid,
|
modelUuid: newFloorItem.modelUuid,
|
||||||
modelName: newFloorItem.modelName,
|
modelName: newFloorItem.modelName,
|
||||||
assetId: newFloorItem.assetId,
|
assetId: newFloorItem.assetId,
|
||||||
position: newFloorItem.position,
|
position: newFloorItem.position,
|
||||||
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
rotation: { x: pastedAsset.rotation.x, y: pastedAsset.rotation.y, z: pastedAsset.rotation.z },
|
||||||
isLocked: false,
|
isLocked: false,
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
socketId: socket.id,
|
socketId: socket.id,
|
||||||
@@ -461,7 +475,6 @@ const CopyPasteControls3D = ({
|
|||||||
userId
|
userId
|
||||||
};
|
};
|
||||||
|
|
||||||
// console.log('data: ', data);
|
|
||||||
socket.emit("v1:model-asset:add", data);
|
socket.emit("v1:model-asset:add", data);
|
||||||
|
|
||||||
const asset: Asset = {
|
const asset: Asset = {
|
||||||
@@ -474,9 +487,9 @@ const CopyPasteControls3D = ({
|
|||||||
isCollidable: false,
|
isCollidable: false,
|
||||||
isVisible: data.isVisible,
|
isVisible: data.isVisible,
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
}
|
};
|
||||||
|
|
||||||
addAsset(asset);
|
updateAsset(asset.modelUuid, asset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -486,15 +499,14 @@ const CopyPasteControls3D = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const clearSelection = () => {
|
const clearSelection = () => {
|
||||||
selectionGroup.current.children = [];
|
|
||||||
selectionGroup.current.position.set(0, 0, 0);
|
|
||||||
selectionGroup.current.rotation.set(0, 0, 0);
|
|
||||||
setMovedObjects([]);
|
setMovedObjects([]);
|
||||||
setpastedObjects([]);
|
setpastedObjects([]);
|
||||||
setDuplicatedObjects([]);
|
setDuplicatedObjects([]);
|
||||||
setRotatedObjects([]);
|
setRotatedObjects([]);
|
||||||
setSelectedAssets([]);
|
setSelectedAssets([]);
|
||||||
}
|
setIsPasting(false);
|
||||||
|
setCenterOffset(null);
|
||||||
|
};
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as THREE from "three";
|
import * as THREE from "three";
|
||||||
import { useEffect, useMemo } from "react";
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { useFrame, useThree } from "@react-three/fiber";
|
import { useFrame, useThree } from "@react-three/fiber";
|
||||||
import { SkeletonUtils } from "three-stdlib";
|
import { SkeletonUtils } from "three-stdlib";
|
||||||
import { useSelectedAssets, useSocketStore, useToggleView } from "../../../../../store/builder/store";
|
import { useSelectedAssets, useSocketStore, useToggleView } from "../../../../../store/builder/store";
|
||||||
@@ -10,18 +10,16 @@ import { getUserData } from "../../../../../functions/getUserData";
|
|||||||
import { useSceneContext } from "../../../sceneContext";
|
import { useSceneContext } from "../../../sceneContext";
|
||||||
import { useVersionContext } from "../../../../builder/version/versionContext";
|
import { useVersionContext } from "../../../../builder/version/versionContext";
|
||||||
|
|
||||||
// import { setAssetsApi } from '../../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi';
|
// import { setAssetsApi } from "../../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi";
|
||||||
|
|
||||||
const DuplicationControls3D = ({
|
const DuplicationControls3D = ({
|
||||||
duplicatedObjects,
|
duplicatedObjects,
|
||||||
setDuplicatedObjects,
|
setDuplicatedObjects,
|
||||||
setpastedObjects,
|
setpastedObjects,
|
||||||
selectionGroup,
|
|
||||||
movedObjects,
|
movedObjects,
|
||||||
setMovedObjects,
|
setMovedObjects,
|
||||||
rotatedObjects,
|
rotatedObjects,
|
||||||
setRotatedObjects,
|
setRotatedObjects,
|
||||||
boundingBoxRef
|
|
||||||
}: any) => {
|
}: any) => {
|
||||||
const { camera, controls, gl, scene, pointer, raycaster } = useThree();
|
const { camera, controls, gl, scene, pointer, raycaster } = useThree();
|
||||||
const { toggleView } = useToggleView();
|
const { toggleView } = useToggleView();
|
||||||
@@ -31,39 +29,71 @@ const DuplicationControls3D = ({
|
|||||||
const { assetStore, eventStore } = useSceneContext();
|
const { assetStore, eventStore } = useSceneContext();
|
||||||
const { addEvent } = eventStore();
|
const { addEvent } = eventStore();
|
||||||
const { projectId } = useParams();
|
const { projectId } = useParams();
|
||||||
const { assets, addAsset } = assetStore();
|
const { assets, addAsset, setPosition, updateAsset, removeAsset, getAssetById } = assetStore();
|
||||||
const { selectedVersionStore } = useVersionContext();
|
const { selectedVersionStore } = useVersionContext();
|
||||||
const { selectedVersion } = selectedVersionStore();
|
const { selectedVersion } = selectedVersionStore();
|
||||||
const { userId, organization } = getUserData();
|
const { userId, organization } = getUserData();
|
||||||
|
|
||||||
|
const [dragOffset, setDragOffset] = useState<THREE.Vector3 | null>(null);
|
||||||
|
const [initialPositions, setInitialPositions] = useState<Record<string, THREE.Vector3>>({});
|
||||||
|
const [isDuplicating, setIsDuplicating] = useState(false);
|
||||||
|
const mouseButtonsDown = useRef<{ left: boolean; right: boolean }>({
|
||||||
|
left: false,
|
||||||
|
right: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const calculateDragOffset = useCallback((point: THREE.Vector3, hitPoint: THREE.Vector3) => {
|
||||||
|
const pointPosition = new THREE.Vector3().copy(point);
|
||||||
|
return new THREE.Vector3().subVectors(pointPosition, hitPoint);
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!camera || !scene || toggleView) return;
|
if (!camera || !scene || toggleView) return;
|
||||||
const canvasElement = gl.domElement;
|
const canvasElement = gl.domElement;
|
||||||
canvasElement.tabIndex = 0;
|
canvasElement.tabIndex = 0;
|
||||||
|
|
||||||
let isMoving = false;
|
let isPointerMoving = false;
|
||||||
|
|
||||||
const onPointerDown = () => {
|
const onPointerDown = (event: PointerEvent) => {
|
||||||
isMoving = false;
|
isPointerMoving = false;
|
||||||
|
if (event.button === 0) mouseButtonsDown.current.left = true;
|
||||||
|
if (event.button === 2) mouseButtonsDown.current.right = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const onPointerMove = () => {
|
const onPointerMove = () => {
|
||||||
isMoving = true;
|
isPointerMoving = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const onPointerUp = (event: PointerEvent) => {
|
const onPointerUp = (event: PointerEvent) => {
|
||||||
if (!isMoving && duplicatedObjects.length > 0 && event.button === 0 && movedObjects.length === 0 && rotatedObjects.length === 0) {
|
if (event.button === 0) mouseButtonsDown.current.left = false;
|
||||||
|
if (event.button === 2) mouseButtonsDown.current.right = false;
|
||||||
|
|
||||||
|
if (!isPointerMoving && duplicatedObjects.length > 0 && event.button === 0) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
addDuplicatedAssets();
|
addDuplicatedAssets();
|
||||||
}
|
}
|
||||||
|
if (!isPointerMoving && duplicatedObjects.length > 0 && event.button === 2) {
|
||||||
|
event.preventDefault();
|
||||||
|
clearSelection();
|
||||||
|
duplicatedObjects.forEach((obj: THREE.Object3D) => {
|
||||||
|
removeAsset(obj.userData.modelUuid);
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onKeyDown = (event: KeyboardEvent) => {
|
const onKeyDown = (event: KeyboardEvent) => {
|
||||||
const keyCombination = detectModifierKeys(event);
|
const keyCombination = detectModifierKeys(event);
|
||||||
|
|
||||||
if (keyCombination === "Ctrl+D" && selectedAssets.length > 0 && duplicatedObjects.length === 0 && movedObjects.length === 0 && rotatedObjects.length === 0) {
|
if (keyCombination === "Ctrl+D" && movedObjects.length === 0 && rotatedObjects.length === 0) {
|
||||||
duplicateSelection();
|
duplicateSelection();
|
||||||
}
|
}
|
||||||
|
if (keyCombination === "ESCAPE" && duplicatedObjects.length > 0) {
|
||||||
|
event.preventDefault();
|
||||||
|
clearSelection();
|
||||||
|
duplicatedObjects.forEach((obj: THREE.Object3D) => {
|
||||||
|
removeAsset(obj.userData.modelUuid);
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!toggleView) {
|
if (!toggleView) {
|
||||||
@@ -79,82 +109,125 @@ const DuplicationControls3D = ({
|
|||||||
canvasElement.removeEventListener("pointerup", onPointerUp);
|
canvasElement.removeEventListener("pointerup", onPointerUp);
|
||||||
canvasElement.removeEventListener("keydown", onKeyDown);
|
canvasElement.removeEventListener("keydown", onKeyDown);
|
||||||
};
|
};
|
||||||
|
|
||||||
}, [assets, camera, controls, scene, toggleView, selectedAssets, duplicatedObjects, movedObjects, socket, rotatedObjects]);
|
}, [assets, camera, controls, scene, toggleView, selectedAssets, duplicatedObjects, movedObjects, socket, rotatedObjects]);
|
||||||
|
|
||||||
useFrame(() => {
|
useFrame(() => {
|
||||||
if (duplicatedObjects.length > 0) {
|
if (!isDuplicating || duplicatedObjects.length === 0) return;
|
||||||
const intersectionPoint = new THREE.Vector3();
|
|
||||||
raycaster.setFromCamera(pointer, camera);
|
const intersectionPoint = new THREE.Vector3();
|
||||||
const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
raycaster.setFromCamera(pointer, camera);
|
||||||
if (point) {
|
const hit = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
||||||
const position = new THREE.Vector3();
|
|
||||||
if (boundingBoxRef.current) {
|
if (hit) {
|
||||||
boundingBoxRef.current?.getWorldPosition(position)
|
if (mouseButtonsDown.current.left || mouseButtonsDown.current.right) {
|
||||||
selectionGroup.current.position.set(point.x - (position.x - selectionGroup.current.position.x), selectionGroup.current.position.y, point.z - (position.z - selectionGroup.current.position.z));
|
const assetUuid = duplicatedObjects[0].userData.modelUuid;
|
||||||
} else {
|
const asset = getAssetById(assetUuid);
|
||||||
const box = new THREE.Box3();
|
if (!asset) return;
|
||||||
duplicatedObjects.forEach((obj: THREE.Object3D) => box.expandByObject(obj.clone()));
|
if (duplicatedObjects[0]) {
|
||||||
const center = new THREE.Vector3();
|
const newOffset = calculateDragOffset(new THREE.Vector3(...asset.position), intersectionPoint);
|
||||||
box.getCenter(center);
|
setDragOffset(newOffset);
|
||||||
selectionGroup.current.position.set(point.x - (center.x - selectionGroup.current.position.x), selectionGroup.current.position.y, point.z - (center.z - selectionGroup.current.position.z));
|
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dragOffset) {
|
||||||
|
const adjustedHit = new THREE.Vector3().addVectors(intersectionPoint, dragOffset);
|
||||||
|
|
||||||
|
duplicatedObjects.forEach((duplicatedObject: THREE.Object3D) => {
|
||||||
|
if (duplicatedObject.userData.modelUuid) {
|
||||||
|
const initialPosition = initialPositions[duplicatedObject.userData.modelUuid];
|
||||||
|
|
||||||
|
if (initialPosition) {
|
||||||
|
|
||||||
|
const relativeOffset = new THREE.Vector3().subVectors(
|
||||||
|
initialPosition,
|
||||||
|
initialPositions[duplicatedObjects[0].userData.modelUuid]
|
||||||
|
);
|
||||||
|
|
||||||
|
const newPosition = new THREE.Vector3().addVectors(adjustedHit, relativeOffset);
|
||||||
|
const positionArray: [number, number, number] = [newPosition.x, newPosition.y, newPosition.z];
|
||||||
|
|
||||||
|
setPosition(duplicatedObject.userData.modelUuid, positionArray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const duplicateSelection = () => {
|
const duplicateSelection = useCallback(() => {
|
||||||
if (selectedAssets.length > 0 && duplicatedObjects.length === 0) {
|
if (selectedAssets.length > 0 && duplicatedObjects.length === 0) {
|
||||||
const newClones = selectedAssets.map((asset: any) => {
|
const positions: Record<string, THREE.Vector3> = {};
|
||||||
const clone = SkeletonUtils.clone(asset);
|
|
||||||
clone.position.copy(asset.position);
|
const newDuplicatedObjects = selectedAssets.map((obj: any) => {
|
||||||
|
const clone = SkeletonUtils.clone(obj);
|
||||||
|
clone.userData.modelUuid = THREE.MathUtils.generateUUID();
|
||||||
|
positions[clone.userData.modelUuid] = new THREE.Vector3().copy(obj.position);
|
||||||
return clone;
|
return clone;
|
||||||
});
|
});
|
||||||
|
|
||||||
selectionGroup.current.add(...newClones);
|
setDuplicatedObjects(newDuplicatedObjects);
|
||||||
setDuplicatedObjects(newClones);
|
setInitialPositions(positions);
|
||||||
|
|
||||||
const intersectionPoint = new THREE.Vector3();
|
|
||||||
raycaster.setFromCamera(pointer, camera);
|
raycaster.setFromCamera(pointer, camera);
|
||||||
const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
const intersectionPoint = new THREE.Vector3();
|
||||||
|
const hit = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
||||||
|
|
||||||
if (point) {
|
if (hit) {
|
||||||
const position = new THREE.Vector3();
|
const offset = calculateDragOffset(selectedAssets[0].position, hit);
|
||||||
boundingBoxRef.current?.getWorldPosition(position)
|
setDragOffset(offset);
|
||||||
selectionGroup.current.position.set(point.x - (position.x - selectionGroup.current.position.x), selectionGroup.current.position.y, point.z - (position.z - selectionGroup.current.position.z));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setIsDuplicating(true);
|
||||||
|
|
||||||
|
newDuplicatedObjects.forEach((obj: THREE.Object3D) => {
|
||||||
|
const asset: Asset = {
|
||||||
|
modelUuid: obj.userData.modelUuid,
|
||||||
|
modelName: obj.userData.modelName,
|
||||||
|
assetId: obj.userData.assetId,
|
||||||
|
position: [obj.position.x, 0, obj.position.z],
|
||||||
|
rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z],
|
||||||
|
isLocked: false,
|
||||||
|
isVisible: true,
|
||||||
|
isCollidable: false,
|
||||||
|
opacity: 0.5,
|
||||||
|
};
|
||||||
|
addAsset(asset);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
}, [selectedAssets, duplicatedObjects]);
|
||||||
|
|
||||||
|
|
||||||
const addDuplicatedAssets = () => {
|
const addDuplicatedAssets = () => {
|
||||||
if (duplicatedObjects.length === 0) return;
|
if (duplicatedObjects.length === 0) return;
|
||||||
|
|
||||||
duplicatedObjects.forEach(async (obj: THREE.Object3D) => {
|
duplicatedObjects.forEach(async (duplicatedAsset: THREE.Object3D) => {
|
||||||
if (obj) {
|
if (duplicatedAsset) {
|
||||||
const worldPosition = new THREE.Vector3();
|
const assetUuid = duplicatedAsset.userData.modelUuid;
|
||||||
obj.getWorldPosition(worldPosition);
|
const asset = getAssetById(assetUuid);
|
||||||
obj.position.copy(worldPosition);
|
if (!asset) return;
|
||||||
|
|
||||||
const newFloorItem: Types.FloorItemType = {
|
const newFloorItem: Types.FloorItemType = {
|
||||||
modelUuid: THREE.MathUtils.generateUUID(),
|
modelUuid: duplicatedAsset.userData.modelUuid,
|
||||||
modelName: obj.userData.modelName,
|
modelName: duplicatedAsset.userData.modelName,
|
||||||
assetId: obj.userData.assetId,
|
assetId: duplicatedAsset.userData.assetId,
|
||||||
position: [worldPosition.x, worldPosition.y, worldPosition.z],
|
position: asset.position,
|
||||||
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z, },
|
rotation: { x: asset.rotation[0], y: asset.rotation[1], z: asset.rotation[2] },
|
||||||
isLocked: false,
|
isLocked: false,
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
let updatedEventData = null;
|
let updatedEventData = null;
|
||||||
if (obj.userData.eventData) {
|
|
||||||
updatedEventData = JSON.parse(JSON.stringify(obj.userData.eventData));
|
if (duplicatedAsset.userData.eventData) {
|
||||||
|
updatedEventData = JSON.parse(JSON.stringify(duplicatedAsset.userData.eventData));
|
||||||
updatedEventData.modelUuid = newFloorItem.modelUuid;
|
updatedEventData.modelUuid = newFloorItem.modelUuid;
|
||||||
|
|
||||||
const eventData: any = {
|
const eventData: any = {
|
||||||
type: obj.userData.eventData.type,
|
type: duplicatedAsset.userData.eventData.type,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (obj.userData.eventData.type === "Conveyor") {
|
if (duplicatedAsset.userData.eventData.type === "Conveyor") {
|
||||||
const ConveyorEvent: ConveyorEventSchema = {
|
const ConveyorEvent: ConveyorEventSchema = {
|
||||||
modelUuid: newFloorItem.modelUuid,
|
modelUuid: newFloorItem.modelUuid,
|
||||||
modelName: newFloorItem.modelName,
|
modelName: newFloorItem.modelName,
|
||||||
@@ -186,7 +259,7 @@ const DuplicationControls3D = ({
|
|||||||
rotation: point.rotation
|
rotation: point.rotation
|
||||||
}));
|
}));
|
||||||
|
|
||||||
} else if (obj.userData.eventData.type === "Vehicle") {
|
} else if (duplicatedAsset.userData.eventData.type === "Vehicle") {
|
||||||
const vehicleEvent: VehicleEventSchema = {
|
const vehicleEvent: VehicleEventSchema = {
|
||||||
modelUuid: newFloorItem.modelUuid,
|
modelUuid: newFloorItem.modelUuid,
|
||||||
modelName: newFloorItem.modelName,
|
modelName: newFloorItem.modelName,
|
||||||
@@ -224,7 +297,7 @@ const DuplicationControls3D = ({
|
|||||||
rotation: vehicleEvent.point.rotation
|
rotation: vehicleEvent.point.rotation
|
||||||
};
|
};
|
||||||
|
|
||||||
} else if (obj.userData.eventData.type === "ArmBot") {
|
} else if (duplicatedAsset.userData.eventData.type === "ArmBot") {
|
||||||
const roboticArmEvent: RoboticArmEventSchema = {
|
const roboticArmEvent: RoboticArmEventSchema = {
|
||||||
modelUuid: newFloorItem.modelUuid,
|
modelUuid: newFloorItem.modelUuid,
|
||||||
modelName: newFloorItem.modelName,
|
modelName: newFloorItem.modelName,
|
||||||
@@ -258,7 +331,7 @@ const DuplicationControls3D = ({
|
|||||||
rotation: roboticArmEvent.point.rotation
|
rotation: roboticArmEvent.point.rotation
|
||||||
};
|
};
|
||||||
|
|
||||||
} else if (obj.userData.eventData.type === "StaticMachine") {
|
} else if (duplicatedAsset.userData.eventData.type === "StaticMachine") {
|
||||||
const machineEvent: MachineEventSchema = {
|
const machineEvent: MachineEventSchema = {
|
||||||
modelUuid: newFloorItem.modelUuid,
|
modelUuid: newFloorItem.modelUuid,
|
||||||
modelName: newFloorItem.modelName,
|
modelName: newFloorItem.modelName,
|
||||||
@@ -286,7 +359,7 @@ const DuplicationControls3D = ({
|
|||||||
position: machineEvent.point.position,
|
position: machineEvent.point.position,
|
||||||
rotation: machineEvent.point.rotation
|
rotation: machineEvent.point.rotation
|
||||||
};
|
};
|
||||||
} else if (obj.userData.eventData.type === "Storage") {
|
} else if (duplicatedAsset.userData.eventData.type === "Storage") {
|
||||||
const storageEvent: StorageEventSchema = {
|
const storageEvent: StorageEventSchema = {
|
||||||
modelUuid: newFloorItem.modelUuid,
|
modelUuid: newFloorItem.modelUuid,
|
||||||
modelName: newFloorItem.modelName,
|
modelName: newFloorItem.modelName,
|
||||||
@@ -313,7 +386,7 @@ const DuplicationControls3D = ({
|
|||||||
position: storageEvent.point.position,
|
position: storageEvent.point.position,
|
||||||
rotation: storageEvent.point.rotation
|
rotation: storageEvent.point.rotation
|
||||||
};
|
};
|
||||||
} else if (obj.userData.eventData.type === "Human") {
|
} else if (duplicatedAsset.userData.eventData.type === "Human") {
|
||||||
const humanEvent: HumanEventSchema = {
|
const humanEvent: HumanEventSchema = {
|
||||||
modelUuid: newFloorItem.modelUuid,
|
modelUuid: newFloorItem.modelUuid,
|
||||||
modelName: newFloorItem.modelName,
|
modelName: newFloorItem.modelName,
|
||||||
@@ -349,38 +422,28 @@ const DuplicationControls3D = ({
|
|||||||
|
|
||||||
newFloorItem.eventData = eventData;
|
newFloorItem.eventData = eventData;
|
||||||
|
|
||||||
//REST
|
|
||||||
|
|
||||||
// await setAssetsApi(
|
|
||||||
// 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 = {
|
const data = {
|
||||||
organization,
|
organization,
|
||||||
modelUuid: newFloorItem.modelUuid,
|
modelUuid: newFloorItem.modelUuid,
|
||||||
modelName: newFloorItem.modelName,
|
modelName: newFloorItem.modelName,
|
||||||
assetId: newFloorItem.assetId,
|
assetId: newFloorItem.assetId,
|
||||||
position: newFloorItem.position,
|
position: newFloorItem.position,
|
||||||
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
rotation: { x: duplicatedAsset.rotation.x, y: duplicatedAsset.rotation.y, z: duplicatedAsset.rotation.z },
|
||||||
isLocked: false,
|
isLocked: false,
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
socketId: socket.id,
|
socketId: socket.id,
|
||||||
eventData: eventData,
|
eventData: eventData,
|
||||||
versionId: selectedVersion?.versionId || '',
|
versionId: selectedVersion?.versionId || '',
|
||||||
projectId,
|
userId,
|
||||||
userId
|
projectId
|
||||||
};
|
};
|
||||||
|
|
||||||
// console.log('data: ', data);
|
//REST
|
||||||
|
|
||||||
|
// await setAssetsApi(data);
|
||||||
|
|
||||||
|
//SOCKET
|
||||||
|
|
||||||
socket.emit("v1:model-asset:add", data);
|
socket.emit("v1:model-asset:add", data);
|
||||||
|
|
||||||
const asset: Asset = {
|
const asset: Asset = {
|
||||||
@@ -394,43 +457,25 @@ const DuplicationControls3D = ({
|
|||||||
isVisible: data.isVisible,
|
isVisible: data.isVisible,
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
eventData: data.eventData
|
eventData: data.eventData
|
||||||
}
|
};
|
||||||
|
|
||||||
addAsset(asset);
|
|
||||||
|
|
||||||
|
updateAsset(asset.modelUuid, asset);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
//REST
|
|
||||||
|
|
||||||
// await setAssetsApi(
|
|
||||||
// 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 = {
|
const data = {
|
||||||
organization,
|
organization,
|
||||||
modelUuid: newFloorItem.modelUuid,
|
modelUuid: newFloorItem.modelUuid,
|
||||||
modelName: newFloorItem.modelName,
|
modelName: newFloorItem.modelName,
|
||||||
assetId: newFloorItem.assetId,
|
assetId: newFloorItem.assetId,
|
||||||
position: newFloorItem.position,
|
position: newFloorItem.position,
|
||||||
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
rotation: { x: duplicatedAsset.rotation.x, y: duplicatedAsset.rotation.y, z: duplicatedAsset.rotation.z },
|
||||||
isLocked: false,
|
isLocked: false,
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
socketId: socket.id,
|
socketId: socket.id,
|
||||||
versionId: selectedVersion?.versionId || '',
|
versionId: selectedVersion?.versionId || '',
|
||||||
userId,
|
projectId,
|
||||||
projectId
|
userId
|
||||||
};
|
};
|
||||||
|
|
||||||
// console.log('data: ', data);/
|
|
||||||
socket.emit("v1:model-asset:add", data);
|
socket.emit("v1:model-asset:add", data);
|
||||||
|
|
||||||
const asset: Asset = {
|
const asset: Asset = {
|
||||||
@@ -443,27 +488,26 @@ const DuplicationControls3D = ({
|
|||||||
isCollidable: false,
|
isCollidable: false,
|
||||||
isVisible: data.isVisible,
|
isVisible: data.isVisible,
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
}
|
};
|
||||||
|
|
||||||
addAsset(asset);
|
updateAsset(asset.modelUuid, asset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
echo.success("Object duplicated!");
|
echo.success("Object duplicated!");
|
||||||
clearSelection();
|
clearSelection();
|
||||||
}
|
};
|
||||||
|
|
||||||
const clearSelection = () => {
|
const clearSelection = () => {
|
||||||
selectionGroup.current.children = [];
|
|
||||||
selectionGroup.current.position.set(0, 0, 0);
|
|
||||||
selectionGroup.current.rotation.set(0, 0, 0);
|
|
||||||
setMovedObjects([]);
|
setMovedObjects([]);
|
||||||
setpastedObjects([]);
|
setpastedObjects([]);
|
||||||
setDuplicatedObjects([]);
|
setDuplicatedObjects([]);
|
||||||
setRotatedObjects([]);
|
setRotatedObjects([]);
|
||||||
setSelectedAssets([]);
|
setSelectedAssets([]);
|
||||||
}
|
setIsDuplicating(false);
|
||||||
|
setDragOffset(null);
|
||||||
|
};
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as THREE from "three";
|
import * as THREE from "three";
|
||||||
import { useEffect, useMemo, useRef, useState } from "react";
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { useFrame, useThree } from "@react-three/fiber";
|
import { useFrame, useThree } from "@react-three/fiber";
|
||||||
import { useSelectedAssets, useSocketStore, useToggleView, } from "../../../../../store/builder/store";
|
import { useSelectedAssets, useSocketStore, useToggleView, } from "../../../../../store/builder/store";
|
||||||
import * as Types from "../../../../../types/world/worldTypes";
|
import * as Types from "../../../../../types/world/worldTypes";
|
||||||
@@ -22,7 +22,6 @@ function MoveControls3D({
|
|||||||
setpastedObjects,
|
setpastedObjects,
|
||||||
duplicatedObjects,
|
duplicatedObjects,
|
||||||
setDuplicatedObjects,
|
setDuplicatedObjects,
|
||||||
selectionGroup,
|
|
||||||
rotatedObjects,
|
rotatedObjects,
|
||||||
setRotatedObjects,
|
setRotatedObjects,
|
||||||
boundingBoxRef,
|
boundingBoxRef,
|
||||||
@@ -39,11 +38,19 @@ function MoveControls3D({
|
|||||||
const { userId, organization } = getUserData();
|
const { userId, organization } = getUserData();
|
||||||
const { projectId } = useParams();
|
const { projectId } = useParams();
|
||||||
const { assetStore, eventStore, productStore } = useSceneContext();
|
const { assetStore, eventStore, productStore } = useSceneContext();
|
||||||
const { updateAsset } = assetStore();
|
const { updateAsset, setPosition, getAssetById } = assetStore();
|
||||||
const AssetGroup = useRef<THREE.Group | undefined>(undefined);
|
|
||||||
const { selectedVersionStore } = useVersionContext();
|
const { selectedVersionStore } = useVersionContext();
|
||||||
const { selectedVersion } = selectedVersionStore();
|
const { selectedVersion } = selectedVersionStore();
|
||||||
|
|
||||||
|
const [dragOffset, setDragOffset] = useState<THREE.Vector3 | null>(null);
|
||||||
|
const [initialPositions, setInitialPositions] = useState<Record<string, THREE.Vector3>>({});
|
||||||
|
const [initialStates, setInitialStates] = useState<Record<string, { position: THREE.Vector3; rotation?: THREE.Euler; }>>({});
|
||||||
|
const [isMoving, setIsMoving] = useState(false);
|
||||||
|
const mouseButtonsDown = useRef<{ left: boolean; right: boolean }>({
|
||||||
|
left: false,
|
||||||
|
right: false,
|
||||||
|
});
|
||||||
|
|
||||||
const updateBackend = (
|
const updateBackend = (
|
||||||
productName: string,
|
productName: string,
|
||||||
productUuid: string,
|
productUuid: string,
|
||||||
@@ -65,22 +72,10 @@ function MoveControls3D({
|
|||||||
const canvasElement = gl.domElement;
|
const canvasElement = gl.domElement;
|
||||||
canvasElement.tabIndex = 0;
|
canvasElement.tabIndex = 0;
|
||||||
|
|
||||||
const itemsGroup: any = scene.getObjectByName("Asset Group");
|
let isPointerMoving = false;
|
||||||
AssetGroup.current = itemsGroup;
|
|
||||||
|
|
||||||
if (!AssetGroup.current) {
|
|
||||||
console.error("Asset Group not found in the scene.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let isMoving = false;
|
|
||||||
|
|
||||||
const onPointerDown = () => {
|
|
||||||
isMoving = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const onPointerMove = () => {
|
const onPointerMove = () => {
|
||||||
isMoving = true;
|
isPointerMoving = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const onKeyUp = (event: KeyboardEvent) => {
|
const onKeyUp = (event: KeyboardEvent) => {
|
||||||
@@ -91,21 +86,25 @@ function MoveControls3D({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onPointerDown = (event: PointerEvent) => {
|
||||||
|
isPointerMoving = false;
|
||||||
|
|
||||||
|
if (event.button === 0) mouseButtonsDown.current.left = true;
|
||||||
|
if (event.button === 2) mouseButtonsDown.current.right = true;
|
||||||
|
};
|
||||||
|
|
||||||
const onPointerUp = (event: PointerEvent) => {
|
const onPointerUp = (event: PointerEvent) => {
|
||||||
if (!isMoving && movedObjects.length > 0 && event.button === 0) {
|
if (event.button === 0) mouseButtonsDown.current.left = false;
|
||||||
|
if (event.button === 2) mouseButtonsDown.current.right = false;
|
||||||
|
|
||||||
|
if (!isPointerMoving && movedObjects.length > 0 && event.button === 0) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
placeMovedAssets();
|
placeMovedAssets();
|
||||||
}
|
}
|
||||||
if (!isMoving && movedObjects.length > 0 && event.button === 2) {
|
if (!isPointerMoving && movedObjects.length > 0 && event.button === 2) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
resetToInitialPositions();
|
||||||
clearSelection();
|
clearSelection();
|
||||||
movedObjects.forEach((asset: any) => {
|
|
||||||
if (AssetGroup.current) {
|
|
||||||
AssetGroup.current.attach(asset);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
setMovedObjects([]);
|
setMovedObjects([]);
|
||||||
}
|
}
|
||||||
setKeyEvent("");
|
setKeyEvent("");
|
||||||
@@ -117,10 +116,12 @@ function MoveControls3D({
|
|||||||
if (pastedObjects.length > 0 || duplicatedObjects.length > 0 || rotatedObjects.length > 0)
|
if (pastedObjects.length > 0 || duplicatedObjects.length > 0 || rotatedObjects.length > 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (keyCombination === "Ctrl" || keyCombination === "Ctrl+Shift" || keyCombination === "Shift") {
|
if (keyCombination !== keyEvent) {
|
||||||
setKeyEvent(keyCombination);
|
if (keyCombination === "Ctrl" || keyCombination === "Ctrl+Shift" || keyCombination === "Shift") {
|
||||||
} else {
|
setKeyEvent(keyCombination);
|
||||||
setKeyEvent("");
|
} else {
|
||||||
|
setKeyEvent("");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keyCombination === "G") {
|
if (keyCombination === "G") {
|
||||||
@@ -131,14 +132,8 @@ function MoveControls3D({
|
|||||||
|
|
||||||
if (keyCombination === "ESCAPE") {
|
if (keyCombination === "ESCAPE") {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
resetToInitialPositions();
|
||||||
clearSelection();
|
clearSelection();
|
||||||
movedObjects.forEach((asset: any) => {
|
|
||||||
if (AssetGroup.current) {
|
|
||||||
AssetGroup.current.attach(asset);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
setMovedObjects([]);
|
setMovedObjects([]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -158,118 +153,161 @@ function MoveControls3D({
|
|||||||
canvasElement.removeEventListener("keydown", onKeyDown);
|
canvasElement.removeEventListener("keydown", onKeyDown);
|
||||||
canvasElement?.removeEventListener("keyup", onKeyUp);
|
canvasElement?.removeEventListener("keyup", onKeyUp);
|
||||||
};
|
};
|
||||||
}, [camera, controls, scene, toggleView, selectedAssets, socket, pastedObjects, duplicatedObjects, movedObjects, rotatedObjects, keyEvent,]);
|
}, [camera, controls, scene, toggleView, selectedAssets, socket, pastedObjects, duplicatedObjects, movedObjects, rotatedObjects, keyEvent]);
|
||||||
|
|
||||||
let moveSpeed = keyEvent === "Ctrl" || "Ctrl+Shift" ? 1 : 0.25;
|
const calculateDragOffset = useCallback((point: THREE.Object3D, hitPoint: THREE.Vector3) => {
|
||||||
|
const pointPosition = new THREE.Vector3().copy(point.position);
|
||||||
|
return new THREE.Vector3().subVectors(pointPosition, hitPoint);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const resetToInitialPositions = useCallback(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
movedObjects.forEach((movedObject: THREE.Object3D) => {
|
||||||
|
if (movedObject.userData.modelUuid && initialStates[movedObject.uuid]) {
|
||||||
|
const initialState = initialStates[movedObject.uuid];
|
||||||
|
const positionArray: [number, number, number] = [
|
||||||
|
initialState.position.x,
|
||||||
|
initialState.position.y,
|
||||||
|
initialState.position.z
|
||||||
|
];
|
||||||
|
|
||||||
|
updateAsset(movedObject.userData.modelUuid, {
|
||||||
|
position: positionArray,
|
||||||
|
rotation: [
|
||||||
|
initialState.rotation?.x || 0,
|
||||||
|
initialState.rotation?.y || 0,
|
||||||
|
initialState.rotation?.z || 0
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
movedObject.position.copy(initialState.position);
|
||||||
|
if (initialState.rotation) {
|
||||||
|
movedObject.rotation.copy(initialState.rotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, 0)
|
||||||
|
}, [movedObjects, initialStates, updateAsset]);
|
||||||
|
|
||||||
useFrame(() => {
|
useFrame(() => {
|
||||||
if (movedObjects.length > 0) {
|
if (!isMoving || movedObjects.length === 0) return;
|
||||||
const intersectionPoint = new THREE.Vector3();
|
|
||||||
raycaster.setFromCamera(pointer, camera);
|
|
||||||
let point = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
|
||||||
const floorsGroup = scene.getObjectByName("Floors-Group") as Types.Group | null;
|
|
||||||
const floorChildren = floorsGroup?.children ?? [];
|
|
||||||
const floorIntersections = raycaster.intersectObjects([...floorChildren], true);
|
|
||||||
const intersectedFloor = floorIntersections.find((intersect) => intersect.object.name.includes("Floor"));
|
|
||||||
|
|
||||||
if (intersectedFloor && selectedAssets.length === 1) {
|
const intersectionPoint = new THREE.Vector3();
|
||||||
if (intersectedFloor.object.userData.floorUuid) {
|
raycaster.setFromCamera(pointer, camera);
|
||||||
point = new THREE.Vector3(intersectedFloor.point.x, intersectedFloor.object.userData.floorDepth, intersectedFloor.point.z);
|
const hit = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
||||||
|
|
||||||
|
if (hit) {
|
||||||
|
if (mouseButtonsDown.current.left || mouseButtonsDown.current.right) {
|
||||||
|
if (movedObjects[0]) {
|
||||||
|
const newOffset = calculateDragOffset(movedObjects[0], intersectionPoint);
|
||||||
|
setDragOffset(newOffset);
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (point) {
|
if (dragOffset) {
|
||||||
let targetX = point.x;
|
const rawBasePosition = new THREE.Vector3().addVectors(intersectionPoint, dragOffset);
|
||||||
let targetY = point.y;
|
|
||||||
let targetZ = point.z;
|
|
||||||
|
|
||||||
if (keyEvent === "Ctrl") {
|
let moveSpeed = keyEvent.includes("Shift") ? 0.05 : 1;
|
||||||
targetX = snapControls(targetX, "Ctrl");
|
|
||||||
targetZ = snapControls(targetZ, "Ctrl");
|
const initialBasePosition = initialPositions[movedObjects[0].uuid];
|
||||||
|
const positionDifference = new THREE.Vector3().subVectors(rawBasePosition, initialBasePosition);
|
||||||
|
|
||||||
|
const adjustedDifference = positionDifference.multiplyScalar(moveSpeed);
|
||||||
|
|
||||||
|
const baseNewPosition = new THREE.Vector3().addVectors(initialBasePosition, adjustedDifference);
|
||||||
|
|
||||||
|
if (keyEvent.includes("Ctrl")) {
|
||||||
|
baseNewPosition.x = snapControls(baseNewPosition.x, "Ctrl");
|
||||||
|
baseNewPosition.z = snapControls(baseNewPosition.z, "Ctrl");
|
||||||
}
|
}
|
||||||
|
|
||||||
// else if (keyEvent === "Ctrl+Shift") {
|
movedObjects.forEach((movedAsset: THREE.Object3D) => {
|
||||||
// targetX = snapControls(targetX, "Ctrl+Shift");
|
if (movedAsset.userData.modelUuid) {
|
||||||
// targetZ = snapControls(targetZ, "Ctrl+Shift");
|
const initialPosition = initialPositions[movedAsset.userData.modelUuid];
|
||||||
// } else if (keyEvent === "Shift") {
|
|
||||||
// targetX = snapControls(targetX, "Shift");
|
if (initialPosition) {
|
||||||
// targetZ = snapControls(targetZ, "Shift");
|
const relativeOffset = new THREE.Vector3().subVectors(
|
||||||
// } else {
|
initialPosition,
|
||||||
// }
|
initialPositions[movedObjects[0].uuid]
|
||||||
|
);
|
||||||
|
|
||||||
|
const newPosition = new THREE.Vector3().addVectors(baseNewPosition, relativeOffset);
|
||||||
|
const positionArray: [number, number, number] = [newPosition.x, newPosition.y, newPosition.z];
|
||||||
|
|
||||||
|
setPosition(movedAsset.userData.modelUuid, positionArray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const position = new THREE.Vector3();
|
const position = new THREE.Vector3();
|
||||||
|
|
||||||
if (boundingBoxRef.current) {
|
if (boundingBoxRef.current) {
|
||||||
boundingBoxRef.current.getWorldPosition(position);
|
boundingBoxRef.current.getWorldPosition(position);
|
||||||
selectionGroup.current.position.lerp(
|
|
||||||
new THREE.Vector3(
|
|
||||||
targetX - (position.x - selectionGroup.current.position.x),
|
|
||||||
targetY - (position.y - selectionGroup.current.position.y),
|
|
||||||
targetZ - (position.z - selectionGroup.current.position.z)
|
|
||||||
),
|
|
||||||
moveSpeed
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
const box = new THREE.Box3();
|
const box = new THREE.Box3();
|
||||||
movedObjects.forEach((obj: THREE.Object3D) =>
|
movedObjects.forEach((obj: THREE.Object3D) => box.expandByObject(obj));
|
||||||
box.expandByObject(obj)
|
|
||||||
);
|
|
||||||
const center = new THREE.Vector3();
|
const center = new THREE.Vector3();
|
||||||
box.getCenter(center);
|
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 moveAssets = () => {
|
||||||
setMovedObjects(selectedAssets);
|
const states: Record<string, { position: THREE.Vector3; rotation?: THREE.Euler; }> = {};
|
||||||
selectedAssets.forEach((asset: any) => {
|
const positions: Record<string, THREE.Vector3> = {};
|
||||||
selectionGroup.current.attach(asset);
|
|
||||||
|
selectedAssets.forEach((asset: THREE.Object3D) => {
|
||||||
|
states[asset.uuid] = {
|
||||||
|
position: new THREE.Vector3().copy(asset.position),
|
||||||
|
rotation: asset.rotation ? new THREE.Euler().copy(asset.rotation) : undefined
|
||||||
|
};
|
||||||
|
positions[asset.uuid] = new THREE.Vector3().copy(asset.position);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
setInitialStates(states);
|
||||||
|
setInitialPositions(positions);
|
||||||
|
|
||||||
|
raycaster.setFromCamera(pointer, camera);
|
||||||
|
const intersectionPoint = new THREE.Vector3();
|
||||||
|
const hit = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
||||||
|
|
||||||
|
if (hit && selectedAssets[0]) {
|
||||||
|
const offset = calculateDragOffset(selectedAssets[0], hit);
|
||||||
|
setDragOffset(offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
setMovedObjects(selectedAssets);
|
||||||
|
setIsMoving(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const placeMovedAssets = () => {
|
const placeMovedAssets = () => {
|
||||||
if (movedObjects.length === 0) return;
|
if (movedObjects.length === 0) return;
|
||||||
|
|
||||||
movedObjects.forEach(async (obj: THREE.Object3D) => {
|
movedObjects.forEach(async (movedAsset: THREE.Object3D) => {
|
||||||
if (obj && AssetGroup.current) {
|
if (movedAsset) {
|
||||||
let worldPosition = new THREE.Vector3();
|
const assetUuid = movedAsset.userData.modelUuid;
|
||||||
obj.getWorldPosition(worldPosition);
|
const asset = getAssetById(assetUuid);
|
||||||
|
if (!asset) return;
|
||||||
if (worldPosition.y < 0) {
|
|
||||||
worldPosition.y = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
selectionGroup.current.remove(obj);
|
|
||||||
obj.position.copy(worldPosition);
|
|
||||||
|
|
||||||
const newFloorItem: Types.FloorItemType = {
|
const newFloorItem: Types.FloorItemType = {
|
||||||
modelUuid: obj.userData.modelUuid,
|
modelUuid: movedAsset.userData.modelUuid,
|
||||||
modelName: obj.userData.modelName,
|
modelName: movedAsset.userData.modelName,
|
||||||
assetId: obj.userData.assetId,
|
assetId: movedAsset.userData.assetId,
|
||||||
position: [worldPosition.x, worldPosition.y, worldPosition.z],
|
position: asset.position,
|
||||||
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
rotation: { x: movedAsset.rotation.x, y: movedAsset.rotation.y, z: movedAsset.rotation.z },
|
||||||
isLocked: false,
|
isLocked: false,
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (obj.userData.eventData) {
|
if (movedAsset.userData.eventData) {
|
||||||
const eventData = eventStore.getState().getEventByModelUuid(obj.userData.modelUuid);
|
const eventData = eventStore.getState().getEventByModelUuid(movedAsset.userData.modelUuid);
|
||||||
const productData = productStore.getState().getEventByModelUuid(selectedProduct.productUuid, obj.userData.modelUuid);
|
const productData = productStore.getState().getEventByModelUuid(selectedProduct.productUuid, movedAsset.userData.modelUuid);
|
||||||
|
|
||||||
if (eventData) {
|
if (eventData) {
|
||||||
eventStore.getState().updateEvent(obj.userData.modelUuid, {
|
eventStore.getState().updateEvent(movedAsset.userData.modelUuid, {
|
||||||
position: [worldPosition.x, worldPosition.y, worldPosition.z],
|
position: asset.position,
|
||||||
rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z],
|
rotation: [movedAsset.rotation.x, movedAsset.rotation.y, movedAsset.rotation.z],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -278,10 +316,10 @@ function MoveControls3D({
|
|||||||
.getState()
|
.getState()
|
||||||
.updateEvent(
|
.updateEvent(
|
||||||
selectedProduct.productUuid,
|
selectedProduct.productUuid,
|
||||||
obj.userData.modelUuid,
|
movedAsset.userData.modelUuid,
|
||||||
{
|
{
|
||||||
position: [worldPosition.x, worldPosition.y, worldPosition.z],
|
position: asset.position,
|
||||||
rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z],
|
rotation: [movedAsset.rotation.x, movedAsset.rotation.y, movedAsset.rotation.z],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -298,33 +336,18 @@ function MoveControls3D({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateAsset(obj.userData.modelUuid, {
|
updateAsset(movedAsset.userData.modelUuid, {
|
||||||
position: [worldPosition.x, worldPosition.y, worldPosition.z],
|
position: asset.position,
|
||||||
rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z],
|
rotation: [movedAsset.rotation.x, movedAsset.rotation.y, movedAsset.rotation.z],
|
||||||
});
|
});
|
||||||
|
|
||||||
//REST
|
|
||||||
|
|
||||||
// await setAssetsApi(
|
|
||||||
// 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 = {
|
const data = {
|
||||||
organization,
|
organization,
|
||||||
modelUuid: newFloorItem.modelUuid,
|
modelUuid: newFloorItem.modelUuid,
|
||||||
modelName: newFloorItem.modelName,
|
modelName: newFloorItem.modelName,
|
||||||
assetId: newFloorItem.assetId,
|
assetId: newFloorItem.assetId,
|
||||||
position: newFloorItem.position,
|
position: newFloorItem.position,
|
||||||
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
rotation: { x: movedAsset.rotation.x, y: movedAsset.rotation.y, z: movedAsset.rotation.z },
|
||||||
isLocked: false,
|
isLocked: false,
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
socketId: socket.id,
|
socketId: socket.id,
|
||||||
@@ -333,22 +356,22 @@ function MoveControls3D({
|
|||||||
userId
|
userId
|
||||||
};
|
};
|
||||||
|
|
||||||
// console.log('data: ', data);
|
//REST
|
||||||
socket.emit("v1:model-asset:add", data);
|
|
||||||
|
|
||||||
AssetGroup.current.add(obj);
|
// await setAssetsApi(data);
|
||||||
|
|
||||||
|
//SOCKET
|
||||||
|
|
||||||
|
socket.emit("v1:model-asset:add", data);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
echo.success("Object moved!");
|
echo.success("Object moved!");
|
||||||
|
setIsMoving(false);
|
||||||
clearSelection();
|
clearSelection();
|
||||||
};
|
};
|
||||||
|
|
||||||
const clearSelection = () => {
|
const clearSelection = () => {
|
||||||
selectionGroup.current.children = [];
|
|
||||||
selectionGroup.current.position.set(0, 0, 0);
|
|
||||||
selectionGroup.current.rotation.set(0, 0, 0);
|
|
||||||
setpastedObjects([]);
|
setpastedObjects([]);
|
||||||
setDuplicatedObjects([]);
|
setDuplicatedObjects([]);
|
||||||
setMovedObjects([]);
|
setMovedObjects([]);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as THREE from "three";
|
import * as THREE from "three";
|
||||||
import { useEffect, useMemo, useRef } from "react";
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { useFrame, useThree } from "@react-three/fiber";
|
import { useFrame, useThree } from "@react-three/fiber";
|
||||||
import { useSelectedAssets, useSocketStore, useToggleView } from "../../../../../store/builder/store";
|
import { useSelectedAssets, useSocketStore, useToggleView } from "../../../../../store/builder/store";
|
||||||
import * as Types from "../../../../../types/world/worldTypes";
|
import * as Types from "../../../../../types/world/worldTypes";
|
||||||
@@ -20,11 +20,9 @@ function RotateControls3D({
|
|||||||
pastedObjects,
|
pastedObjects,
|
||||||
setpastedObjects,
|
setpastedObjects,
|
||||||
duplicatedObjects,
|
duplicatedObjects,
|
||||||
setDuplicatedObjects,
|
setDuplicatedObjects
|
||||||
selectionGroup
|
|
||||||
}: any) {
|
}: any) {
|
||||||
|
const { camera, gl, scene, pointer, raycaster } = useThree();
|
||||||
const { camera, controls, gl, scene, pointer, raycaster } = useThree();
|
|
||||||
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
||||||
|
|
||||||
const { toggleView } = useToggleView();
|
const { toggleView } = useToggleView();
|
||||||
@@ -36,26 +34,33 @@ function RotateControls3D({
|
|||||||
const { projectId } = useParams();
|
const { projectId } = useParams();
|
||||||
const { assetStore, eventStore, productStore } = useSceneContext();
|
const { assetStore, eventStore, productStore } = useSceneContext();
|
||||||
const { updateAsset } = assetStore();
|
const { updateAsset } = assetStore();
|
||||||
const AssetGroup = useRef<THREE.Group | undefined>(undefined);
|
|
||||||
const { selectedVersionStore } = useVersionContext();
|
const { selectedVersionStore } = useVersionContext();
|
||||||
const { selectedVersion } = selectedVersionStore();
|
const { selectedVersion } = selectedVersionStore();
|
||||||
|
|
||||||
const updateBackend = (
|
const [initialRotations, setInitialRotations] = useState<Record<string, THREE.Euler>>({});
|
||||||
|
const [initialPositions, setInitialPositions] = useState<Record<string, THREE.Vector3>>({});
|
||||||
|
const [isRotating, setIsRotating] = useState(false);
|
||||||
|
const prevPointerPosition = useRef<THREE.Vector2 | null>(null);
|
||||||
|
const rotationCenter = useRef<THREE.Vector3 | null>(null);
|
||||||
|
const mouseButtonsDown = useRef<{ left: boolean; right: boolean }>({
|
||||||
|
left: false,
|
||||||
|
right: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const updateBackend = useCallback((
|
||||||
productName: string,
|
productName: string,
|
||||||
productUuid: string,
|
productUuid: string,
|
||||||
projectId: string,
|
projectId: string,
|
||||||
eventData: EventsSchema
|
eventData: EventsSchema
|
||||||
) => {
|
) => {
|
||||||
upsertProductOrEventApi({
|
upsertProductOrEventApi({
|
||||||
productName: productName,
|
productName,
|
||||||
productUuid: productUuid,
|
productUuid,
|
||||||
projectId: projectId,
|
projectId,
|
||||||
eventDatas: eventData,
|
eventDatas: eventData,
|
||||||
versionId: selectedVersion?.versionId || '',
|
versionId: selectedVersion?.versionId || '',
|
||||||
})
|
});
|
||||||
}
|
}, [selectedVersion]);
|
||||||
|
|
||||||
const prevPointerPosition = useRef<THREE.Vector2 | null>(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!camera || !scene || toggleView) return;
|
if (!camera || !scene || toggleView) return;
|
||||||
@@ -63,45 +68,37 @@ function RotateControls3D({
|
|||||||
const canvasElement = gl.domElement;
|
const canvasElement = gl.domElement;
|
||||||
canvasElement.tabIndex = 0;
|
canvasElement.tabIndex = 0;
|
||||||
|
|
||||||
const itemsGroup: any = scene.getObjectByName("Asset Group");
|
let isPointerMoving = false;
|
||||||
AssetGroup.current = itemsGroup;
|
|
||||||
|
|
||||||
if (!AssetGroup.current) {
|
|
||||||
console.error("Asset Group not found in the scene.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let isMoving = false;
|
|
||||||
|
|
||||||
const onPointerDown = () => {
|
|
||||||
isMoving = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const onPointerMove = () => {
|
const onPointerMove = () => {
|
||||||
isMoving = true;
|
isPointerMoving = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onPointerDown = (event: PointerEvent) => {
|
||||||
|
isPointerMoving = false;
|
||||||
|
if (event.button === 0) mouseButtonsDown.current.left = true;
|
||||||
|
if (event.button === 2) mouseButtonsDown.current.right = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const onPointerUp = (event: PointerEvent) => {
|
const onPointerUp = (event: PointerEvent) => {
|
||||||
if (!isMoving && rotatedObjects.length > 0 && event.button === 0) {
|
if (event.button === 0) mouseButtonsDown.current.left = false;
|
||||||
|
if (event.button === 2) mouseButtonsDown.current.right = false;
|
||||||
|
|
||||||
|
if (!isPointerMoving && rotatedObjects.length > 0 && event.button === 0) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
placeRotatedAssets();
|
placeRotatedAssets();
|
||||||
}
|
}
|
||||||
if (!isMoving && rotatedObjects.length > 0 && event.button === 2) {
|
if (!isPointerMoving && rotatedObjects.length > 0 && event.button === 2) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
resetToInitialRotations();
|
||||||
clearSelection();
|
clearSelection();
|
||||||
rotatedObjects.forEach((asset: any) => {
|
|
||||||
if (AssetGroup.current) {
|
|
||||||
AssetGroup.current.attach(asset);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
setRotatedObjects([]);
|
setRotatedObjects([]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onKeyDown = (event: KeyboardEvent) => {
|
const onKeyDown = (event: KeyboardEvent) => {
|
||||||
if (pastedObjects.length > 0 || duplicatedObjects.length > 0 || movedObjects.length > 0) return;
|
if (pastedObjects.length > 0 || duplicatedObjects.length > 0 || movedObjects.length > 0) return;
|
||||||
|
|
||||||
if (event.key.toLowerCase() === "r") {
|
if (event.key.toLowerCase() === "r") {
|
||||||
if (selectedAssets.length > 0) {
|
if (selectedAssets.length > 0) {
|
||||||
rotateAssets();
|
rotateAssets();
|
||||||
@@ -109,15 +106,8 @@ function RotateControls3D({
|
|||||||
}
|
}
|
||||||
if (event.key.toLowerCase() === "escape") {
|
if (event.key.toLowerCase() === "escape") {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
resetToInitialRotations();
|
||||||
clearSelection();
|
clearSelection();
|
||||||
rotatedObjects.forEach((asset: any) => {
|
|
||||||
if (AssetGroup.current) {
|
|
||||||
AssetGroup.current.attach(asset);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
setRotatedObjects([]);
|
setRotatedObjects([]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -135,41 +125,85 @@ function RotateControls3D({
|
|||||||
canvasElement.removeEventListener("pointerup", onPointerUp);
|
canvasElement.removeEventListener("pointerup", onPointerUp);
|
||||||
canvasElement.removeEventListener("keydown", onKeyDown);
|
canvasElement.removeEventListener("keydown", onKeyDown);
|
||||||
};
|
};
|
||||||
}, [camera, controls, scene, toggleView, selectedAssets, socket, pastedObjects, duplicatedObjects, rotatedObjects, movedObjects]);
|
}, [camera, scene, toggleView, selectedAssets, rotatedObjects, pastedObjects, duplicatedObjects, movedObjects]);
|
||||||
|
|
||||||
|
const resetToInitialRotations = useCallback(() => {
|
||||||
|
rotatedObjects.forEach((obj: THREE.Object3D) => {
|
||||||
|
const uuid = obj.uuid;
|
||||||
|
if (obj.userData.modelUuid) {
|
||||||
|
const initialRotation = initialRotations[uuid];
|
||||||
|
const initialPosition = initialPositions[uuid];
|
||||||
|
|
||||||
|
if (initialRotation && initialPosition) {
|
||||||
|
const rotationArray: [number, number, number] = [initialRotation.x, initialRotation.y, initialRotation.z,];
|
||||||
|
const positionArray: [number, number, number] = [initialPosition.x, initialPosition.y, initialPosition.z,];
|
||||||
|
|
||||||
|
updateAsset(obj.userData.modelUuid, {
|
||||||
|
rotation: rotationArray,
|
||||||
|
position: positionArray,
|
||||||
|
});
|
||||||
|
|
||||||
|
obj.rotation.copy(initialRotation);
|
||||||
|
obj.position.copy(initialPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, [rotatedObjects, initialRotations, initialPositions, updateAsset]);
|
||||||
|
|
||||||
useFrame(() => {
|
useFrame(() => {
|
||||||
if (rotatedObjects.length > 0) {
|
if (!isRotating || rotatedObjects.length === 0) return;
|
||||||
const intersectionPoint = new THREE.Vector3();
|
|
||||||
raycaster.setFromCamera(pointer, camera);
|
|
||||||
const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
|
||||||
|
|
||||||
if (point && prevPointerPosition.current) {
|
const intersectionPoint = new THREE.Vector3();
|
||||||
const box = new THREE.Box3();
|
raycaster.setFromCamera(pointer, camera);
|
||||||
rotatedObjects.forEach((obj: THREE.Object3D) => box.expandByObject(obj));
|
const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
||||||
const center = new THREE.Vector3();
|
|
||||||
box.getCenter(center);
|
|
||||||
|
|
||||||
const delta = new THREE.Vector3().subVectors(point, center);
|
|
||||||
const prevPointerPosition3D = new THREE.Vector3(prevPointerPosition.current.x, 0, prevPointerPosition.current.y);
|
|
||||||
|
|
||||||
const angle = Math.atan2(delta.z, delta.x) - Math.atan2(prevPointerPosition3D.z - center.z, prevPointerPosition3D.x - center.x);
|
|
||||||
|
|
||||||
selectionGroup.current.rotation.y += -angle;
|
|
||||||
|
|
||||||
selectionGroup.current.position.sub(center);
|
|
||||||
selectionGroup.current.position.applyAxisAngle(new THREE.Vector3(0, 1, 0), -angle);
|
|
||||||
selectionGroup.current.position.add(center);
|
|
||||||
|
|
||||||
|
if (mouseButtonsDown.current.left || mouseButtonsDown.current.right) {
|
||||||
|
if (point) {
|
||||||
prevPointerPosition.current = new THREE.Vector2(point.x, point.z);
|
prevPointerPosition.current = new THREE.Vector2(point.x, point.z);
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (point && prevPointerPosition.current && rotationCenter.current) {
|
||||||
|
const center = rotationCenter.current;
|
||||||
|
|
||||||
|
const currentAngle = Math.atan2(point.z - center.z, point.x - center.x);
|
||||||
|
const prevAngle = Math.atan2(
|
||||||
|
prevPointerPosition.current.y - center.z,
|
||||||
|
prevPointerPosition.current.x - center.x
|
||||||
|
);
|
||||||
|
const angleDelta = prevAngle - currentAngle;
|
||||||
|
|
||||||
|
rotatedObjects.forEach((obj: THREE.Object3D) => {
|
||||||
|
if (obj.userData.modelUuid) {
|
||||||
|
const relativePos = new THREE.Vector3().subVectors(obj.position, center);
|
||||||
|
relativePos.applyAxisAngle(new THREE.Vector3(0, 1, 0), angleDelta);
|
||||||
|
obj.position.copy(center).add(relativePos);
|
||||||
|
obj.rotation.y += angleDelta;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
prevPointerPosition.current = new THREE.Vector2(point.x, point.z);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const rotateAssets = () => {
|
const rotateAssets = useCallback(() => {
|
||||||
|
const rotations: Record<string, THREE.Euler> = {};
|
||||||
|
const positions: Record<string, THREE.Vector3> = {};
|
||||||
|
|
||||||
const box = new THREE.Box3();
|
const box = new THREE.Box3();
|
||||||
selectedAssets.forEach((asset: any) => box.expandByObject(asset));
|
selectedAssets.forEach((obj: THREE.Object3D) => box.expandByObject(obj));
|
||||||
const center = new THREE.Vector3();
|
const center = new THREE.Vector3();
|
||||||
box.getCenter(center);
|
box.getCenter(center);
|
||||||
|
rotationCenter.current = center;
|
||||||
|
|
||||||
|
selectedAssets.forEach((obj: THREE.Object3D) => {
|
||||||
|
rotations[obj.uuid] = new THREE.Euler().copy(obj.rotation);
|
||||||
|
positions[obj.uuid] = new THREE.Vector3().copy(obj.position);
|
||||||
|
});
|
||||||
|
|
||||||
|
setInitialRotations(rotations);
|
||||||
|
setInitialPositions(positions);
|
||||||
|
|
||||||
const intersectionPoint = new THREE.Vector3();
|
const intersectionPoint = new THREE.Vector3();
|
||||||
raycaster.setFromCamera(pointer, camera);
|
raycaster.setFromCamera(pointer, camera);
|
||||||
@@ -179,56 +213,54 @@ function RotateControls3D({
|
|||||||
prevPointerPosition.current = new THREE.Vector2(point.x, point.z);
|
prevPointerPosition.current = new THREE.Vector2(point.x, point.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
selectedAssets.forEach((asset: any) => {
|
|
||||||
selectionGroup.current.attach(asset);
|
|
||||||
});
|
|
||||||
|
|
||||||
setRotatedObjects(selectedAssets);
|
setRotatedObjects(selectedAssets);
|
||||||
};
|
setIsRotating(true);
|
||||||
|
}, [selectedAssets, camera, pointer, raycaster, plane]);
|
||||||
|
|
||||||
const placeRotatedAssets = () => {
|
const placeRotatedAssets = useCallback(() => {
|
||||||
if (rotatedObjects.length === 0) return;
|
if (rotatedObjects.length === 0) return;
|
||||||
|
|
||||||
rotatedObjects.forEach(async (obj: THREE.Object3D) => {
|
rotatedObjects.forEach((obj: THREE.Object3D) => {
|
||||||
if (obj && AssetGroup.current) {
|
if (obj && obj.userData.modelUuid) {
|
||||||
const worldPosition = new THREE.Vector3();
|
const rotationArray: [number, number, number] = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
|
||||||
const worldQuaternion = new THREE.Quaternion();
|
|
||||||
|
|
||||||
obj.getWorldPosition(worldPosition);
|
const positionArray: [number, number, number] = [obj.position.x, obj.position.y, obj.position.z];
|
||||||
obj.getWorldQuaternion(worldQuaternion);
|
|
||||||
|
|
||||||
selectionGroup.current.remove(obj);
|
|
||||||
|
|
||||||
obj.position.copy(worldPosition);
|
|
||||||
obj.quaternion.copy(worldQuaternion);
|
|
||||||
|
|
||||||
const newFloorItem: Types.FloorItemType = {
|
const newFloorItem: Types.FloorItemType = {
|
||||||
modelUuid: obj.userData.modelUuid,
|
modelUuid: obj.userData.modelUuid,
|
||||||
modelName: obj.userData.modelName,
|
modelName: obj.userData.modelName,
|
||||||
assetId: obj.userData.assetId,
|
assetId: obj.userData.assetId,
|
||||||
position: [worldPosition.x, worldPosition.y, worldPosition.z],
|
position: positionArray,
|
||||||
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
||||||
isLocked: false,
|
isLocked: false,
|
||||||
isVisible: true
|
isVisible: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (obj.userData.eventData) {
|
if (obj.userData.eventData) {
|
||||||
const eventData = eventStore.getState().getEventByModelUuid(obj.userData.modelUuid);
|
const eventData = eventStore.getState().getEventByModelUuid(obj.userData.modelUuid);
|
||||||
const productData = productStore.getState().getEventByModelUuid(selectedProductStore.getState().selectedProduct.productUuid, obj.userData.modelUuid);
|
const productData = productStore.getState().getEventByModelUuid(
|
||||||
|
selectedProduct.productUuid,
|
||||||
|
obj.userData.modelUuid
|
||||||
|
);
|
||||||
|
|
||||||
if (eventData) {
|
if (eventData) {
|
||||||
eventStore.getState().updateEvent(obj.userData.modelUuid, {
|
eventStore.getState().updateEvent(obj.userData.modelUuid, {
|
||||||
position: [worldPosition.x, worldPosition.y, worldPosition.z],
|
position: positionArray,
|
||||||
rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z],
|
rotation: rotationArray,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
if (productData) {
|
|
||||||
const event = productStore.getState().updateEvent(selectedProductStore.getState().selectedProduct.productUuid, obj.userData.modelUuid, {
|
|
||||||
position: [worldPosition.x, worldPosition.y, worldPosition.z],
|
|
||||||
rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z],
|
|
||||||
})
|
|
||||||
|
|
||||||
if (event && organization) {
|
if (productData) {
|
||||||
|
const event = productStore.getState().updateEvent(
|
||||||
|
selectedProduct.productUuid,
|
||||||
|
obj.userData.modelUuid,
|
||||||
|
{
|
||||||
|
position: positionArray,
|
||||||
|
rotation: rotationArray,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (event) {
|
||||||
updateBackend(
|
updateBackend(
|
||||||
selectedProduct.productName,
|
selectedProduct.productName,
|
||||||
selectedProduct.productUuid,
|
selectedProduct.productUuid,
|
||||||
@@ -242,25 +274,10 @@ function RotateControls3D({
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateAsset(obj.userData.modelUuid, {
|
updateAsset(obj.userData.modelUuid, {
|
||||||
position: [worldPosition.x, worldPosition.y, worldPosition.z],
|
position: positionArray,
|
||||||
rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z],
|
rotation: rotationArray,
|
||||||
});
|
});
|
||||||
|
|
||||||
//REST
|
|
||||||
|
|
||||||
// await setAssetsApi(
|
|
||||||
// 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 = {
|
const data = {
|
||||||
organization,
|
organization,
|
||||||
modelUuid: newFloorItem.modelUuid,
|
modelUuid: newFloorItem.modelUuid,
|
||||||
@@ -276,29 +293,29 @@ function RotateControls3D({
|
|||||||
userId
|
userId
|
||||||
};
|
};
|
||||||
|
|
||||||
// console.log('data: ', data);
|
//REST
|
||||||
socket.emit("v1:model-asset:add", data);
|
|
||||||
|
|
||||||
AssetGroup.current.add(obj);
|
// await setAssetsApi(data);
|
||||||
|
|
||||||
|
//SOCKET
|
||||||
|
|
||||||
|
socket.emit("v1:model-asset:add", data);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
echo.success("Object rotated!");
|
|
||||||
|
|
||||||
|
setIsRotating(false);
|
||||||
clearSelection();
|
clearSelection();
|
||||||
}
|
}, [rotatedObjects, eventStore, productStore, selectedProduct, updateBackend, projectId, updateAsset, organization, socket, selectedVersion, userId]);
|
||||||
|
|
||||||
const clearSelection = () => {
|
const clearSelection = () => {
|
||||||
selectionGroup.current.children = [];
|
|
||||||
selectionGroup.current.position.set(0, 0, 0);
|
|
||||||
selectionGroup.current.rotation.set(0, 0, 0);
|
|
||||||
setpastedObjects([]);
|
setpastedObjects([]);
|
||||||
setDuplicatedObjects([]);
|
setDuplicatedObjects([]);
|
||||||
setMovedObjects([]);
|
setMovedObjects([]);
|
||||||
setRotatedObjects([]);
|
setRotatedObjects([]);
|
||||||
setSelectedAssets([]);
|
setSelectedAssets([]);
|
||||||
}
|
};
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default RotateControls3D
|
export default RotateControls3D;
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||||
import * as THREE from "three";
|
import * as THREE from "three";
|
||||||
import { useFrame, useThree } from "@react-three/fiber";
|
import { useThree } from "@react-three/fiber";
|
||||||
import { SelectionHelper } from "../selectionHelper";
|
import { SelectionHelper } from "../selectionHelper";
|
||||||
import { SelectionBox } from "three/examples/jsm/interactive/SelectionBox";
|
import { SelectionBox } from "three/examples/jsm/interactive/SelectionBox";
|
||||||
import * as Types from "../../../../../types/world/worldTypes";
|
|
||||||
|
|
||||||
import useModuleStore from "../../../../../store/useModuleStore";
|
import useModuleStore from "../../../../../store/useModuleStore";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
@@ -13,7 +12,6 @@ import { useVersionContext } from "../../../../builder/version/versionContext";
|
|||||||
import { useProductContext } from "../../../../simulation/products/productContext";
|
import { useProductContext } from "../../../../simulation/products/productContext";
|
||||||
import { useSelectedAssets, useSocketStore, useToggleView, useToolMode, } from "../../../../../store/builder/store";
|
import { useSelectedAssets, useSocketStore, useToggleView, useToolMode, } from "../../../../../store/builder/store";
|
||||||
import { upsertProductOrEventApi } from "../../../../../services/simulation/products/UpsertProductOrEventApi";
|
import { upsertProductOrEventApi } from "../../../../../services/simulation/products/UpsertProductOrEventApi";
|
||||||
import BoundingBox from "./boundingBoxHelper3D";
|
|
||||||
import DuplicationControls3D from "./duplicationControls3D";
|
import DuplicationControls3D from "./duplicationControls3D";
|
||||||
import CopyPasteControls3D from "./copyPasteControls3D";
|
import CopyPasteControls3D from "./copyPasteControls3D";
|
||||||
import MoveControls3D from "./moveControls3D";
|
import MoveControls3D from "./moveControls3D";
|
||||||
@@ -23,7 +21,6 @@ import RotateControls3D from "./rotateControls3D";
|
|||||||
|
|
||||||
const SelectionControls3D: React.FC = () => {
|
const SelectionControls3D: React.FC = () => {
|
||||||
const { camera, controls, gl, scene, raycaster, pointer } = useThree();
|
const { camera, controls, gl, scene, raycaster, pointer } = useThree();
|
||||||
const selectionGroup = useRef() as Types.RefGroup;
|
|
||||||
const { toggleView } = useToggleView();
|
const { toggleView } = useToggleView();
|
||||||
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
|
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
|
||||||
const [movedObjects, setMovedObjects] = useState<THREE.Object3D[]>([]);
|
const [movedObjects, setMovedObjects] = useState<THREE.Object3D[]>([]);
|
||||||
@@ -229,12 +226,6 @@ const SelectionControls3D: React.FC = () => {
|
|||||||
}
|
}
|
||||||
}, [activeModule, toolMode, toggleView]);
|
}, [activeModule, toolMode, toggleView]);
|
||||||
|
|
||||||
useFrame(() => {
|
|
||||||
if (pastedObjects.length === 0 && duplicatedObjects.length === 0 && movedObjects.length === 0 && rotatedObjects.length === 0) {
|
|
||||||
selectionGroup.current.position.set(0, 0, 0);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const selectAssets = useCallback(() => {
|
const selectAssets = useCallback(() => {
|
||||||
selectionBox.endPoint.set(pointer.x, pointer.y, 0);
|
selectionBox.endPoint.set(pointer.x, pointer.y, 0);
|
||||||
if (controls) (controls as any).enabled = true;
|
if (controls) (controls as any).enabled = true;
|
||||||
@@ -267,9 +258,6 @@ const SelectionControls3D: React.FC = () => {
|
|||||||
}, [selectionBox, pointer, controls, selectedAssets, setSelectedAssets]);
|
}, [selectionBox, pointer, controls, selectedAssets, setSelectedAssets]);
|
||||||
|
|
||||||
const clearSelection = () => {
|
const clearSelection = () => {
|
||||||
selectionGroup.current.children = [];
|
|
||||||
selectionGroup.current.position.set(0, 0, 0);
|
|
||||||
selectionGroup.current.rotation.set(0, 0, 0);
|
|
||||||
setpastedObjects([]);
|
setpastedObjects([]);
|
||||||
setDuplicatedObjects([]);
|
setDuplicatedObjects([]);
|
||||||
setSelectedAssets([]);
|
setSelectedAssets([]);
|
||||||
@@ -345,19 +333,13 @@ const SelectionControls3D: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<group name="SelectionGroup">
|
<MoveControls3D movedObjects={movedObjects} setMovedObjects={setMovedObjects} pastedObjects={pastedObjects} setpastedObjects={setpastedObjects} duplicatedObjects={duplicatedObjects} setDuplicatedObjects={setDuplicatedObjects} rotatedObjects={rotatedObjects} setRotatedObjects={setRotatedObjects} boundingBoxRef={boundingBoxRef} />
|
||||||
<group ref={selectionGroup} name="selectionAssetGroup">
|
|
||||||
<BoundingBox boundingBoxRef={boundingBoxRef} isPerAsset />
|
|
||||||
</group>
|
|
||||||
</group>
|
|
||||||
|
|
||||||
<MoveControls3D movedObjects={movedObjects} setMovedObjects={setMovedObjects} pastedObjects={pastedObjects} setpastedObjects={setpastedObjects} duplicatedObjects={duplicatedObjects} setDuplicatedObjects={setDuplicatedObjects} rotatedObjects={rotatedObjects} setRotatedObjects={setRotatedObjects} selectionGroup={selectionGroup} boundingBoxRef={boundingBoxRef} />
|
<RotateControls3D rotatedObjects={rotatedObjects} setRotatedObjects={setRotatedObjects} movedObjects={movedObjects} setMovedObjects={setMovedObjects} pastedObjects={pastedObjects} setpastedObjects={setpastedObjects} duplicatedObjects={duplicatedObjects} setDuplicatedObjects={setDuplicatedObjects} />
|
||||||
|
|
||||||
<RotateControls3D rotatedObjects={rotatedObjects} setRotatedObjects={setRotatedObjects} movedObjects={movedObjects} setMovedObjects={setMovedObjects} pastedObjects={pastedObjects} setpastedObjects={setpastedObjects} duplicatedObjects={duplicatedObjects} setDuplicatedObjects={setDuplicatedObjects} selectionGroup={selectionGroup} />
|
<DuplicationControls3D duplicatedObjects={duplicatedObjects} setDuplicatedObjects={setDuplicatedObjects} setpastedObjects={setpastedObjects} movedObjects={movedObjects} setMovedObjects={setMovedObjects} rotatedObjects={rotatedObjects} setRotatedObjects={setRotatedObjects} boundingBoxRef={boundingBoxRef} />
|
||||||
|
|
||||||
<DuplicationControls3D duplicatedObjects={duplicatedObjects} setDuplicatedObjects={setDuplicatedObjects} setpastedObjects={setpastedObjects} selectionGroup={selectionGroup} movedObjects={movedObjects} setMovedObjects={setMovedObjects} rotatedObjects={rotatedObjects} setRotatedObjects={setRotatedObjects} boundingBoxRef={boundingBoxRef} />
|
<CopyPasteControls3D copiedObjects={copiedObjects} setCopiedObjects={setCopiedObjects} pastedObjects={pastedObjects} setpastedObjects={setpastedObjects} setDuplicatedObjects={setDuplicatedObjects} movedObjects={movedObjects} setMovedObjects={setMovedObjects} rotatedObjects={rotatedObjects} setRotatedObjects={setRotatedObjects} boundingBoxRef={boundingBoxRef} />
|
||||||
|
|
||||||
<CopyPasteControls3D copiedObjects={copiedObjects} setCopiedObjects={setCopiedObjects} pastedObjects={pastedObjects} setpastedObjects={setpastedObjects} selectionGroup={selectionGroup} setDuplicatedObjects={setDuplicatedObjects} movedObjects={movedObjects} setMovedObjects={setMovedObjects} rotatedObjects={rotatedObjects} setRotatedObjects={setRotatedObjects} boundingBoxRef={boundingBoxRef} />
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export function useConveyorActions() {
|
|||||||
|
|
||||||
switch (action.actionType) {
|
switch (action.actionType) {
|
||||||
case 'default':
|
case 'default':
|
||||||
handleDefaultAction(action);
|
handleDefaultAction(action, materialId);
|
||||||
break;
|
break;
|
||||||
case 'spawn':
|
case 'spawn':
|
||||||
handleSpawnAction(action);
|
handleSpawnAction(action);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ export function useWorkerHandler() {
|
|||||||
const { getModelUuidByActionUuid } = productStore();
|
const { getModelUuidByActionUuid } = productStore();
|
||||||
const { selectedProductStore } = useProductContext();
|
const { selectedProductStore } = useProductContext();
|
||||||
const { selectedProduct } = selectedProductStore();
|
const { selectedProduct } = selectedProductStore();
|
||||||
const { incrementHumanLoad, incrementLoadCount, addCurrentMaterial, addCurrentAction } = humanStore();
|
const { incrementHumanLoad, addCurrentMaterial, addCurrentAction } = humanStore();
|
||||||
|
|
||||||
const workerLogStatus = (materialUuid: string, status: string) => {
|
const workerLogStatus = (materialUuid: string, status: string) => {
|
||||||
echo.info(`${materialUuid}, ${status}`);
|
echo.info(`${materialUuid}, ${status}`);
|
||||||
@@ -24,7 +24,6 @@ export function useWorkerHandler() {
|
|||||||
if (!modelUuid) return;
|
if (!modelUuid) return;
|
||||||
|
|
||||||
incrementHumanLoad(modelUuid, 1);
|
incrementHumanLoad(modelUuid, 1);
|
||||||
incrementLoadCount(modelUuid, 1);
|
|
||||||
addCurrentAction(modelUuid, action.actionUuid);
|
addCurrentAction(modelUuid, action.actionUuid);
|
||||||
addCurrentMaterial(modelUuid, material.materialType, material.materialId);
|
addCurrentMaterial(modelUuid, material.materialType, material.materialId);
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export function useRetrieveHandler() {
|
|||||||
const { getModelUuidByActionUuid, getPointUuidByActionUuid, getEventByModelUuid, getActionByUuid } = productStore();
|
const { getModelUuidByActionUuid, getPointUuidByActionUuid, getEventByModelUuid, getActionByUuid } = productStore();
|
||||||
const { getStorageUnitById, getLastMaterial, updateCurrentLoad, removeLastMaterial } = storageUnitStore();
|
const { getStorageUnitById, getLastMaterial, updateCurrentLoad, removeLastMaterial } = storageUnitStore();
|
||||||
const { getVehicleById, incrementVehicleLoad, addCurrentMaterial } = vehicleStore();
|
const { getVehicleById, incrementVehicleLoad, addCurrentMaterial } = vehicleStore();
|
||||||
const { getHumanById, incrementHumanLoad, incrementLoadCount, addCurrentMaterial: addCurrentMaterialToHuman } = humanStore();
|
const { getHumanById, incrementHumanLoad, addCurrentMaterial: addCurrentMaterialToHuman } = humanStore();
|
||||||
const { getAssetById, setCurrentAnimation } = assetStore();
|
const { getAssetById, setCurrentAnimation } = assetStore();
|
||||||
const { selectedProduct } = selectedProductStore();
|
const { selectedProduct } = selectedProductStore();
|
||||||
const { getArmBotById, addCurrentAction } = armBotStore();
|
const { getArmBotById, addCurrentAction } = armBotStore();
|
||||||
@@ -316,7 +316,6 @@ export function useRetrieveHandler() {
|
|||||||
removeLastMaterial(storageUnit.modelUuid);
|
removeLastMaterial(storageUnit.modelUuid);
|
||||||
updateCurrentLoad(storageUnit.modelUuid, -1);
|
updateCurrentLoad(storageUnit.modelUuid, -1);
|
||||||
incrementHumanLoad(human.modelUuid, 1);
|
incrementHumanLoad(human.modelUuid, 1);
|
||||||
incrementLoadCount(human.modelUuid, 1);
|
|
||||||
addCurrentMaterialToHuman(human.modelUuid, material.materialType, material.materialId);
|
addCurrentMaterialToHuman(human.modelUuid, material.materialType, material.materialId);
|
||||||
retrieveLogStatus(material.materialName, `is picked by ${human.modelName}`);
|
retrieveLogStatus(material.materialName, `is picked by ${human.modelName}`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,16 +6,21 @@ import { useProductContext } from '../../products/productContext';
|
|||||||
|
|
||||||
export function useHumanEventManager() {
|
export function useHumanEventManager() {
|
||||||
const { humanStore, productStore, assetStore } = useSceneContext();
|
const { humanStore, productStore, assetStore } = useSceneContext();
|
||||||
const { getHumanById, clearLoadCount, setCurrentPhase } = humanStore();
|
const { getHumanById, setCurrentPhase } = humanStore();
|
||||||
const { getAssetById } = assetStore();
|
const { getAssetById } = assetStore();
|
||||||
const { getActionByUuid } = productStore();
|
const { getActionByUuid } = productStore();
|
||||||
const { selectedProductStore } = useProductContext();
|
const { selectedProductStore } = useProductContext();
|
||||||
const { selectedProduct } = selectedProductStore();
|
const { selectedProduct } = selectedProductStore();
|
||||||
|
|
||||||
const callbacksRef = useRef<Map<string, (() => void)[]>>(new Map());
|
const stateRef = useRef({
|
||||||
const actionQueueRef = useRef<Map<string, { actionType: "worker" | "assembly", actionUuid: string }[]>>(new Map());
|
humanStates: new Map<string, {
|
||||||
const isCooldownRef = useRef<Map<string, boolean>>(new Map());
|
callbacks: (() => void)[],
|
||||||
const isMonitoringRef = useRef(false);
|
actionQueue: { actionType: "worker" | "assembly", actionUuid: string, actionName: string }[],
|
||||||
|
isCooldown: boolean
|
||||||
|
}>(),
|
||||||
|
callbackCounts: new Map<string, Map<string, number>>(),
|
||||||
|
isMonitoring: false
|
||||||
|
});
|
||||||
|
|
||||||
const { isPlaying } = usePlayButtonStore();
|
const { isPlaying } = usePlayButtonStore();
|
||||||
const { isPaused } = usePauseButtonStore();
|
const { isPaused } = usePauseButtonStore();
|
||||||
@@ -23,10 +28,9 @@ export function useHumanEventManager() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isReset) {
|
if (isReset) {
|
||||||
callbacksRef.current.clear();
|
stateRef.current.humanStates.clear();
|
||||||
actionQueueRef.current.clear();
|
stateRef.current.callbackCounts.clear();
|
||||||
isCooldownRef.current.clear();
|
stateRef.current.isMonitoring = false;
|
||||||
isMonitoringRef.current = false;
|
|
||||||
}
|
}
|
||||||
}, [isReset]);
|
}, [isReset]);
|
||||||
|
|
||||||
@@ -38,34 +42,64 @@ export function useHumanEventManager() {
|
|||||||
const actionType = action.actionType;
|
const actionType = action.actionType;
|
||||||
if (actionType !== "worker" && actionType !== "assembly") return;
|
if (actionType !== "worker" && actionType !== "assembly") return;
|
||||||
|
|
||||||
if (!callbacksRef.current.has(humanId)) {
|
if (!stateRef.current.callbackCounts.has(humanId)) {
|
||||||
callbacksRef.current.set(humanId, []);
|
stateRef.current.callbackCounts.set(humanId, new Map());
|
||||||
actionQueueRef.current.set(humanId, []);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
callbacksRef.current.get(humanId)!.push(callback);
|
const actionCounts = stateRef.current.callbackCounts.get(humanId)!;
|
||||||
actionQueueRef.current.get(humanId)!.push({ actionType, actionUuid });
|
if (!actionCounts.has(actionUuid)) {
|
||||||
|
actionCounts.set(actionUuid, 0);
|
||||||
|
}
|
||||||
|
|
||||||
isMonitoringRef.current = true;
|
const currentCount = actionCounts.get(actionUuid)!;
|
||||||
|
if (actionType === 'worker' && currentCount >= action.loadCount) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stateRef.current.humanStates.has(humanId)) {
|
||||||
|
stateRef.current.humanStates.set(humanId, {
|
||||||
|
callbacks: [],
|
||||||
|
actionQueue: [],
|
||||||
|
isCooldown: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const humanState = stateRef.current.humanStates.get(humanId)!;
|
||||||
|
humanState.callbacks.push(callback);
|
||||||
|
humanState.actionQueue.push({ actionType, actionUuid, actionName: action.actionName });
|
||||||
|
|
||||||
|
stateRef.current.isMonitoring = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const removeHumanFromMonitor = (humanId: string) => {
|
const removeHumanFromMonitor = (humanId: string) => {
|
||||||
callbacksRef.current.delete(humanId);
|
// stateRef.current.humanStates.delete(humanId);
|
||||||
actionQueueRef.current.delete(humanId);
|
|
||||||
isCooldownRef.current.delete(humanId);
|
|
||||||
|
|
||||||
if (callbacksRef.current.size === 0) {
|
if (stateRef.current.humanStates.size === 0) {
|
||||||
isMonitoringRef.current = false;
|
stateRef.current.isMonitoring = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getCallbackCount = (humanId: string, actionUuid: string) => {
|
||||||
|
if (!stateRef.current.callbackCounts.has(humanId)) return 0;
|
||||||
|
return stateRef.current.callbackCounts.get(humanId)!.get(actionUuid) || 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
const incrementCallbackCount = (humanId: string, actionUuid: string) => {
|
||||||
|
if (!stateRef.current.callbackCounts.has(humanId)) {
|
||||||
|
stateRef.current.callbackCounts.set(humanId, new Map());
|
||||||
|
}
|
||||||
|
const actionCounts = stateRef.current.callbackCounts.get(humanId)!;
|
||||||
|
const currentCount = actionCounts.get(actionUuid) || 0;
|
||||||
|
actionCounts.set(actionUuid, currentCount + 1);
|
||||||
|
};
|
||||||
|
|
||||||
useFrame(() => {
|
useFrame(() => {
|
||||||
if (!isMonitoringRef.current || !isPlaying || isPaused) return;
|
if (!stateRef.current.isMonitoring || !isPlaying || isPaused) return;
|
||||||
|
|
||||||
callbacksRef.current.forEach((queue, humanId) => {
|
stateRef.current.humanStates.forEach((humanState, humanId) => {
|
||||||
if (queue.length === 0 || isCooldownRef.current.get(humanId)) return;
|
if (humanState.callbacks.length === 0 || humanState.isCooldown) return;
|
||||||
|
|
||||||
const actionQueue = actionQueueRef.current.get(humanId);
|
const actionQueue = humanState.actionQueue;
|
||||||
if (!actionQueue || actionQueue.length === 0) return;
|
if (!actionQueue || actionQueue.length === 0) return;
|
||||||
|
|
||||||
const { actionType: expectedActionType, actionUuid } = actionQueue[0];
|
const { actionType: expectedActionType, actionUuid } = actionQueue[0];
|
||||||
@@ -75,11 +109,22 @@ export function useHumanEventManager() {
|
|||||||
|
|
||||||
if (!humanAsset || !human || !action || action.actionType !== expectedActionType) return;
|
if (!humanAsset || !human || !action || action.actionType !== expectedActionType) return;
|
||||||
|
|
||||||
let conditionMet = false;
|
const currentCount = getCallbackCount(humanId, actionUuid);
|
||||||
|
|
||||||
const currentAction = getActionByUuid(selectedProduct.productUuid, human.currentAction?.actionUuid || '') as HumanAction | undefined;
|
const currentAction = getActionByUuid(selectedProduct.productUuid, human.currentAction?.actionUuid || '') as HumanAction | undefined;
|
||||||
|
|
||||||
|
let conditionMet = false;
|
||||||
|
|
||||||
if (expectedActionType === "worker") {
|
if (expectedActionType === "worker") {
|
||||||
|
if (currentAction && currentAction.actionType === 'worker' && currentCount >= currentAction.loadCount) {
|
||||||
|
humanState.callbacks.shift();
|
||||||
|
actionQueue.shift();
|
||||||
|
if (humanState.callbacks.length === 0) {
|
||||||
|
removeHumanFromMonitor(humanId);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (currentAction && currentAction.actionType === 'worker') {
|
if (currentAction && currentAction.actionType === 'worker') {
|
||||||
conditionMet = (
|
conditionMet = (
|
||||||
!human.isActive &&
|
!human.isActive &&
|
||||||
@@ -88,15 +133,6 @@ export function useHumanEventManager() {
|
|||||||
human.currentLoad < currentAction.loadCapacity
|
human.currentLoad < currentAction.loadCapacity
|
||||||
);
|
);
|
||||||
|
|
||||||
if (human.totalLoadCount >= currentAction.loadCount && actionUuid === human.currentAction?.actionUuid) {
|
|
||||||
queue.shift();
|
|
||||||
actionQueue.shift();
|
|
||||||
if (queue.length === 0) {
|
|
||||||
removeHumanFromMonitor(humanId);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (conditionMet && actionUuid !== human.currentAction?.actionUuid) {
|
if (conditionMet && actionUuid !== human.currentAction?.actionUuid) {
|
||||||
setCurrentPhase(human.modelUuid, 'init');
|
setCurrentPhase(human.modelUuid, 'init');
|
||||||
}
|
}
|
||||||
@@ -104,8 +140,7 @@ export function useHumanEventManager() {
|
|||||||
conditionMet = (
|
conditionMet = (
|
||||||
!human.isActive &&
|
!human.isActive &&
|
||||||
human.state === "idle" &&
|
human.state === "idle" &&
|
||||||
humanAsset.animationState?.current === 'idle' &&
|
humanAsset.animationState?.current === 'idle'
|
||||||
human.currentLoad < action.loadCapacity
|
|
||||||
);
|
);
|
||||||
if (conditionMet && actionUuid !== human.currentAction?.actionUuid) {
|
if (conditionMet && actionUuid !== human.currentAction?.actionUuid) {
|
||||||
setCurrentPhase(human.modelUuid, 'init');
|
setCurrentPhase(human.modelUuid, 'init');
|
||||||
@@ -127,41 +162,31 @@ export function useHumanEventManager() {
|
|||||||
conditionMet = (
|
conditionMet = (
|
||||||
!human.isActive &&
|
!human.isActive &&
|
||||||
human.state === "idle" &&
|
human.state === "idle" &&
|
||||||
humanAsset.animationState?.current === 'idle' &&
|
humanAsset.animationState?.current === 'idle'
|
||||||
human.currentLoad < action.loadCapacity
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (conditionMet) {
|
|
||||||
clearLoadCount(human.modelUuid);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conditionMet) {
|
if (conditionMet) {
|
||||||
const callback = queue.shift();
|
const callback = humanState.callbacks.shift();
|
||||||
actionQueue.shift();
|
actionQueue.shift();
|
||||||
|
|
||||||
if (callback) callback();
|
if (callback) {
|
||||||
|
callback();
|
||||||
|
incrementCallbackCount(humanId, actionUuid);
|
||||||
|
}
|
||||||
|
|
||||||
if (queue.length === 0) {
|
if (humanState.callbacks.length === 0) {
|
||||||
removeHumanFromMonitor(humanId);
|
removeHumanFromMonitor(humanId);
|
||||||
} else {
|
} else {
|
||||||
isCooldownRef.current.set(humanId, true);
|
humanState.isCooldown = true;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
isCooldownRef.current.set(humanId, false);
|
humanState.isCooldown = false;
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, 0);
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
return () => {
|
|
||||||
callbacksRef.current.clear();
|
|
||||||
actionQueueRef.current.clear();
|
|
||||||
isCooldownRef.current.clear();
|
|
||||||
isMonitoringRef.current = false;
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
addHumanToMonitor,
|
addHumanToMonitor,
|
||||||
|
|||||||
@@ -478,8 +478,10 @@ export function useTriggerHandler() {
|
|||||||
if (toEvent?.type === 'transfer') {
|
if (toEvent?.type === 'transfer') {
|
||||||
// Vehicle to Transfer
|
// Vehicle to Transfer
|
||||||
if (materialId && trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint && trigger.triggeredAsset.triggeredAction) {
|
if (materialId && trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint && trigger.triggeredAsset.triggeredAction) {
|
||||||
|
const conveyor = getConveyorById(toEvent.modelUuid);
|
||||||
const material = getMaterialById(materialId);
|
const material = getMaterialById(materialId);
|
||||||
if (material) {
|
|
||||||
|
if (material && conveyor) {
|
||||||
const action = getActionByUuid(selectedProduct.productUuid, trigger.triggeredAsset.triggeredAction.actionUuid);
|
const action = getActionByUuid(selectedProduct.productUuid, trigger.triggeredAsset.triggeredAction.actionUuid);
|
||||||
|
|
||||||
setPreviousLocation(material.materialId, {
|
setPreviousLocation(material.materialId, {
|
||||||
@@ -494,23 +496,29 @@ export function useTriggerHandler() {
|
|||||||
actionUuid: trigger.triggeredAsset?.triggeredAction?.actionUuid,
|
actionUuid: trigger.triggeredAsset?.triggeredAction?.actionUuid,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
setIsPaused(materialId, false);
|
||||||
|
|
||||||
setIsVisible(materialId, true);
|
setIsVisible(materialId, true);
|
||||||
|
|
||||||
if (action &&
|
if (action &&
|
||||||
action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid &&
|
action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid &&
|
||||||
action.triggers[0]?.triggeredAsset?.triggeredPoint?.pointUuid
|
action.triggers[0]?.triggeredAsset?.triggeredPoint?.pointUuid
|
||||||
) {
|
) {
|
||||||
|
|
||||||
setNextLocation(material.materialId, {
|
setNextLocation(material.materialId, {
|
||||||
modelUuid: action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid,
|
modelUuid: action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || '',
|
||||||
pointUuid: action.triggers[0]?.triggeredAsset?.triggeredPoint?.pointUuid,
|
pointUuid: action.triggers[0]?.triggeredAsset?.triggeredPoint?.pointUuid || '',
|
||||||
});
|
});
|
||||||
|
|
||||||
handleAction(action, materialId);
|
addConveyorToMonitor(conveyor.modelUuid, () => {
|
||||||
}
|
|
||||||
|
|
||||||
|
setIsPaused(materialId, false);
|
||||||
|
|
||||||
|
handleAction(action, materialId);
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (toEvent?.type === 'vehicle') {
|
} else if (toEvent?.type === 'vehicle') {
|
||||||
// Vehicle to Vehicle
|
// Vehicle to Vehicle
|
||||||
|
|
||||||
@@ -539,7 +547,6 @@ export function useTriggerHandler() {
|
|||||||
|
|
||||||
setNextLocation(material.materialId, null);
|
setNextLocation(material.materialId, null);
|
||||||
|
|
||||||
|
|
||||||
if (action && armBot) {
|
if (action && armBot) {
|
||||||
|
|
||||||
if (armBot.isActive === false && armBot.state === 'idle') {
|
if (armBot.isActive === false && armBot.state === 'idle') {
|
||||||
@@ -1439,13 +1446,11 @@ export function useTriggerHandler() {
|
|||||||
const material = getMaterialById(materialId);
|
const material = getMaterialById(materialId);
|
||||||
if (material) {
|
if (material) {
|
||||||
|
|
||||||
setIsPaused(material.materialId, false);
|
setIsPaused(material.materialId, true);
|
||||||
|
|
||||||
const action = getActionByUuid(selectedProduct.productUuid, trigger.triggeredAsset.triggeredAction.actionUuid);
|
const action = getActionByUuid(selectedProduct.productUuid, trigger.triggeredAsset.triggeredAction.actionUuid);
|
||||||
const vehicle = getVehicleById(trigger.triggeredAsset?.triggeredModel.modelUuid);
|
const vehicle = getVehicleById(trigger.triggeredAsset?.triggeredModel.modelUuid);
|
||||||
|
|
||||||
setNextLocation(material.materialId, null);
|
|
||||||
|
|
||||||
if (action) {
|
if (action) {
|
||||||
|
|
||||||
if (vehicle) {
|
if (vehicle) {
|
||||||
@@ -1466,16 +1471,15 @@ export function useTriggerHandler() {
|
|||||||
actionUuid: trigger.triggeredAsset?.triggeredAction?.actionUuid,
|
actionUuid: trigger.triggeredAsset?.triggeredAction?.actionUuid,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
setNextLocation(material.materialId, null);
|
||||||
|
|
||||||
// Handle current action from vehicle
|
// Handle current action from vehicle
|
||||||
handleAction(action, materialId);
|
handleAction(action, materialId);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
setIsPaused(materialId, true);
|
|
||||||
|
|
||||||
addVehicleToMonitor(vehicle.modelUuid,
|
addVehicleToMonitor(vehicle.modelUuid,
|
||||||
() => {
|
() => {
|
||||||
setIsPaused(materialId, false);
|
|
||||||
setIsVisible(materialId, false);
|
setIsVisible(materialId, false);
|
||||||
|
|
||||||
setPreviousLocation(material.materialId, {
|
setPreviousLocation(material.materialId, {
|
||||||
@@ -1493,6 +1497,7 @@ export function useTriggerHandler() {
|
|||||||
setNextLocation(material.materialId, null);
|
setNextLocation(material.materialId, null);
|
||||||
|
|
||||||
// Handle current action from vehicle
|
// Handle current action from vehicle
|
||||||
|
console.log('action: ', action);
|
||||||
handleAction(action, materialId);
|
handleAction(action, materialId);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -325,7 +325,6 @@ function DraggableLineSegment({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onPointerMove = (e: ThreeEvent<PointerEvent>) => {
|
const onPointerMove = (e: ThreeEvent<PointerEvent>) => {
|
||||||
console.log('isAnyDragging: ', isAnyDragging);
|
|
||||||
if (isAnyDragging !== "line" || activeTool !== 'pen') return;
|
if (isAnyDragging !== "line" || activeTool !== 'pen') return;
|
||||||
|
|
||||||
const intersect = new THREE.Vector3();
|
const intersect = new THREE.Vector3();
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
|
|||||||
const { materialStore, armBotStore, conveyorStore, vehicleStore, storageUnitStore, humanStore, productStore, assetStore } = useSceneContext();
|
const { materialStore, armBotStore, conveyorStore, vehicleStore, storageUnitStore, humanStore, productStore, assetStore } = useSceneContext();
|
||||||
const { removeMaterial, setEndTime, setIsVisible } = materialStore();
|
const { removeMaterial, setEndTime, setIsVisible } = materialStore();
|
||||||
const { getStorageUnitById } = storageUnitStore();
|
const { getStorageUnitById } = storageUnitStore();
|
||||||
const { getHumanById, addCurrentAction, addCurrentMaterial, incrementHumanLoad , incrementLoadCount } = humanStore();
|
const { getHumanById, addCurrentAction, addCurrentMaterial, incrementHumanLoad } = humanStore();
|
||||||
const { getArmBotById } = armBotStore();
|
const { getArmBotById } = armBotStore();
|
||||||
const { getConveyorById } = conveyorStore();
|
const { getConveyorById } = conveyorStore();
|
||||||
const { triggerPointActions } = useTriggerHandler();
|
const { triggerPointActions } = useTriggerHandler();
|
||||||
@@ -302,7 +302,6 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
|
|||||||
setIsVisible(material.materialId, false);
|
setIsVisible(material.materialId, false);
|
||||||
addCurrentMaterial(humanId, material.materialType, material.materialId);
|
addCurrentMaterial(humanId, material.materialType, material.materialId);
|
||||||
incrementHumanLoad(humanId, 1);
|
incrementHumanLoad(humanId, 1);
|
||||||
incrementLoadCount(humanId, 1);
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,11 +27,6 @@ interface HumansStore {
|
|||||||
incrementHumanLoad: (modelUuid: string, incrementBy: number) => void;
|
incrementHumanLoad: (modelUuid: string, incrementBy: number) => void;
|
||||||
decrementHumanLoad: (modelUuid: string, decrementBy: number) => void;
|
decrementHumanLoad: (modelUuid: string, decrementBy: number) => void;
|
||||||
|
|
||||||
incrementLoadCount: (modelUuid: string, incrementBy: number) => void;
|
|
||||||
decrementLoadCount: (modelUuid: string, decrementBy: number) => void;
|
|
||||||
|
|
||||||
clearLoadCount: (modelUuid: string) => void;
|
|
||||||
|
|
||||||
addCurrentMaterial: (modelUuid: string, materialType: string, materialId: string) => void;
|
addCurrentMaterial: (modelUuid: string, materialType: string, materialId: string) => void;
|
||||||
setCurrentMaterials: (modelUuid: string, materials: { materialType: string; materialId: string }[]) => void;
|
setCurrentMaterials: (modelUuid: string, materials: { materialType: string; materialId: string }[]) => void;
|
||||||
removeLastMaterial: (modelUuid: string) => { materialType: string; materialId: string } | undefined;
|
removeLastMaterial: (modelUuid: string) => { materialType: string; materialId: string } | undefined;
|
||||||
@@ -65,7 +60,6 @@ export const createHumanStore = () => {
|
|||||||
isScheduled: false,
|
isScheduled: false,
|
||||||
idleTime: 0,
|
idleTime: 0,
|
||||||
activeTime: 0,
|
activeTime: 0,
|
||||||
totalLoadCount: 0,
|
|
||||||
currentLoad: 0,
|
currentLoad: 0,
|
||||||
currentMaterials: [],
|
currentMaterials: [],
|
||||||
distanceTraveled: 0
|
distanceTraveled: 0
|
||||||
@@ -182,33 +176,6 @@ export const createHumanStore = () => {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
incrementLoadCount: (modelUuid, incrementBy) => {
|
|
||||||
set((state) => {
|
|
||||||
const human = state.humans.find(h => h.modelUuid === modelUuid);
|
|
||||||
if (human) {
|
|
||||||
human.totalLoadCount += incrementBy;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
decrementLoadCount: (modelUuid, decrementBy) => {
|
|
||||||
set((state) => {
|
|
||||||
const human = state.humans.find(h => h.modelUuid === modelUuid);
|
|
||||||
if (human) {
|
|
||||||
human.totalLoadCount -= decrementBy;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
clearLoadCount: (modelUuid) => {
|
|
||||||
set((state) => {
|
|
||||||
const human = state.humans.find(h => h.modelUuid === modelUuid);
|
|
||||||
if (human) {
|
|
||||||
human.totalLoadCount = 0;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
addCurrentMaterial: (modelUuid, materialType, materialId) => {
|
addCurrentMaterial: (modelUuid, materialType, materialId) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const human = state.humans.find(h => h.modelUuid === modelUuid);
|
const human = state.humans.find(h => h.modelUuid === modelUuid);
|
||||||
|
|||||||
1
app/src/types/simulationTypes.d.ts
vendored
1
app/src/types/simulationTypes.d.ts
vendored
@@ -252,7 +252,6 @@ interface HumanStatus extends HumanEventSchema {
|
|||||||
isScheduled: boolean;
|
isScheduled: boolean;
|
||||||
idleTime: number;
|
idleTime: number;
|
||||||
activeTime: number;
|
activeTime: number;
|
||||||
totalLoadCount: number;
|
|
||||||
currentLoad: number;
|
currentLoad: number;
|
||||||
currentMaterials: { materialType: string; materialId: string; }[];
|
currentMaterials: { materialType: string; materialId: string; }[];
|
||||||
distanceTraveled: number;
|
distanceTraveled: number;
|
||||||
|
|||||||
Reference in New Issue
Block a user