Merge remote-tracking branch 'origin/main-dev' into main-demo
This commit is contained in:
@@ -9,6 +9,7 @@ import { useParams } from "react-router-dom";
|
|||||||
import { getUserData } from "../../../../../functions/getUserData";
|
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 { handleAssetPositionSnap } from "./functions/handleAssetPositionSnap";
|
||||||
|
|
||||||
// import { setAssetsApi } from "../../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi";
|
// import { setAssetsApi } from "../../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi";
|
||||||
|
|
||||||
@@ -35,11 +36,16 @@ const DuplicationControls3D = ({
|
|||||||
const { selectedVersion } = selectedVersionStore();
|
const { selectedVersion } = selectedVersionStore();
|
||||||
const { userId, organization } = getUserData();
|
const { userId, organization } = getUserData();
|
||||||
|
|
||||||
|
const [keyEvent, setKeyEvent] = useState<"Ctrl" | "Shift" | "Ctrl+Shift" | "">("");
|
||||||
|
const [axisConstraint, setAxisConstraint] = useState<"x" | "z" | null>(null);
|
||||||
const [dragOffset, setDragOffset] = useState<THREE.Vector3 | null>(null);
|
const [dragOffset, setDragOffset] = useState<THREE.Vector3 | null>(null);
|
||||||
const [initialPositions, setInitialPositions] = useState<Record<string, THREE.Vector3>>({});
|
const [initialPositions, setInitialPositions] = useState<Record<string, THREE.Vector3>>({});
|
||||||
const [isDuplicating, setIsDuplicating] = useState(false);
|
const [isDuplicating, setIsDuplicating] = useState(false);
|
||||||
const mouseButtonsDown = useRef<{ left: boolean; right: boolean }>({ left: false, right: false, });
|
const mouseButtonsDown = useRef<{ left: boolean; right: boolean }>({ left: false, right: false, });
|
||||||
const { contextAction, setContextAction } = useContextActionStore()
|
const { contextAction, setContextAction } = useContextActionStore()
|
||||||
|
const fineMoveBaseRef = useRef<THREE.Vector3 | null>(null);
|
||||||
|
const lastPointerPositionRef = useRef<THREE.Vector3 | null>(null);
|
||||||
|
const wasShiftHeldRef = useRef(false);
|
||||||
|
|
||||||
const calculateDragOffset = useCallback((point: THREE.Object3D, hitPoint: THREE.Vector3) => {
|
const calculateDragOffset = useCallback((point: THREE.Object3D, hitPoint: THREE.Vector3) => {
|
||||||
const pointPosition = new THREE.Vector3().copy(point.position);
|
const pointPosition = new THREE.Vector3().copy(point.position);
|
||||||
@@ -85,11 +91,33 @@ const DuplicationControls3D = ({
|
|||||||
removeAsset(obj.userData.modelUuid);
|
removeAsset(obj.userData.modelUuid);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
setKeyEvent("");
|
||||||
};
|
};
|
||||||
|
|
||||||
const onKeyDown = (event: KeyboardEvent) => {
|
const onKeyDown = (event: KeyboardEvent) => {
|
||||||
const keyCombination = detectModifierKeys(event);
|
const keyCombination = detectModifierKeys(event);
|
||||||
|
|
||||||
|
if (isDuplicating && duplicatedObjects.length > 0) {
|
||||||
|
if (event.key.toLowerCase() === 'x') {
|
||||||
|
setAxisConstraint(prev => prev === 'x' ? null : 'x');
|
||||||
|
event.preventDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (event.key.toLowerCase() === 'z') {
|
||||||
|
setAxisConstraint(prev => prev === 'z' ? null : 'z');
|
||||||
|
event.preventDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyCombination !== keyEvent) {
|
||||||
|
if (keyCombination === "Ctrl" || keyCombination === "Ctrl+Shift" || keyCombination === "Shift") {
|
||||||
|
setKeyEvent(keyCombination);
|
||||||
|
} else {
|
||||||
|
setKeyEvent("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (keyCombination === "Ctrl+D" && movedObjects.length === 0 && rotatedObjects.length === 0) {
|
if (keyCombination === "Ctrl+D" && movedObjects.length === 0 && rotatedObjects.length === 0) {
|
||||||
duplicateSelection();
|
duplicateSelection();
|
||||||
}
|
}
|
||||||
@@ -102,11 +130,34 @@ const DuplicationControls3D = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onKeyUp = (event: KeyboardEvent) => {
|
||||||
|
const keyCombination = detectModifierKeys(event);
|
||||||
|
|
||||||
|
if (keyCombination === "") {
|
||||||
|
setKeyEvent("");
|
||||||
|
} else if (keyCombination === "Ctrl" || keyCombination === "Ctrl+Shift" || keyCombination === "Shift") {
|
||||||
|
setKeyEvent(keyCombination);
|
||||||
|
}
|
||||||
|
if (duplicatedObjects[0] && keyEvent !== "" && keyCombination === '') {
|
||||||
|
const intersectionPoint = new THREE.Vector3();
|
||||||
|
raycaster.setFromCamera(pointer, camera);
|
||||||
|
const hit = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
||||||
|
if (hit) {
|
||||||
|
const model = scene.getObjectByProperty("uuid", duplicatedObjects[0].userData.modelUuid);
|
||||||
|
if (model) {
|
||||||
|
const newOffset = calculateDragOffset(model, intersectionPoint);
|
||||||
|
setDragOffset(newOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (!toggleView) {
|
if (!toggleView) {
|
||||||
canvasElement.addEventListener("pointerdown", onPointerDown);
|
canvasElement.addEventListener("pointerdown", onPointerDown);
|
||||||
canvasElement.addEventListener("pointermove", onPointerMove);
|
canvasElement.addEventListener("pointermove", onPointerMove);
|
||||||
canvasElement.addEventListener("pointerup", onPointerUp);
|
canvasElement.addEventListener("pointerup", onPointerUp);
|
||||||
canvasElement.addEventListener("keydown", onKeyDown);
|
canvasElement.addEventListener("keydown", onKeyDown);
|
||||||
|
canvasElement.addEventListener("keyup", onKeyUp);
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
@@ -114,8 +165,9 @@ const DuplicationControls3D = ({
|
|||||||
canvasElement.removeEventListener("pointermove", onPointerMove);
|
canvasElement.removeEventListener("pointermove", onPointerMove);
|
||||||
canvasElement.removeEventListener("pointerup", onPointerUp);
|
canvasElement.removeEventListener("pointerup", onPointerUp);
|
||||||
canvasElement.removeEventListener("keydown", onKeyDown);
|
canvasElement.removeEventListener("keydown", onKeyDown);
|
||||||
|
canvasElement.addEventListener("keyup", onKeyUp);
|
||||||
};
|
};
|
||||||
}, [assets, camera, controls, scene, toggleView, selectedAssets, duplicatedObjects, movedObjects, socket, rotatedObjects]);
|
}, [assets, camera, controls, scene, toggleView, selectedAssets, duplicatedObjects, movedObjects, socket, rotatedObjects, keyEvent]);
|
||||||
|
|
||||||
useFrame(() => {
|
useFrame(() => {
|
||||||
if (!isDuplicating || duplicatedObjects.length === 0) return;
|
if (!isDuplicating || duplicatedObjects.length === 0) return;
|
||||||
@@ -135,7 +187,9 @@ const DuplicationControls3D = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (dragOffset) {
|
if (dragOffset) {
|
||||||
const adjustedHit = new THREE.Vector3().addVectors(intersectionPoint, dragOffset);
|
const rawBasePosition = new THREE.Vector3().addVectors(intersectionPoint, dragOffset);
|
||||||
|
const model = scene.getObjectByProperty("uuid", duplicatedObjects[0].userData.modelUuid);
|
||||||
|
const baseNewPosition = handleAssetPositionSnap({ rawBasePosition, intersectionPoint, model, axisConstraint, keyEvent, fineMoveBaseRef, lastPointerPositionRef, wasShiftHeldRef });
|
||||||
|
|
||||||
duplicatedObjects.forEach((duplicatedObject: THREE.Object3D) => {
|
duplicatedObjects.forEach((duplicatedObject: THREE.Object3D) => {
|
||||||
if (duplicatedObject.userData.modelUuid) {
|
if (duplicatedObject.userData.modelUuid) {
|
||||||
@@ -149,7 +203,7 @@ const DuplicationControls3D = ({
|
|||||||
);
|
);
|
||||||
const model = scene.getObjectByProperty("uuid", duplicatedObject.userData.modelUuid);
|
const model = scene.getObjectByProperty("uuid", duplicatedObject.userData.modelUuid);
|
||||||
|
|
||||||
const newPosition = new THREE.Vector3().addVectors(adjustedHit, relativeOffset);
|
const newPosition = new THREE.Vector3().addVectors(baseNewPosition, relativeOffset);
|
||||||
const positionArray: [number, number, number] = [newPosition.x, newPosition.y, newPosition.z];
|
const positionArray: [number, number, number] = [newPosition.x, newPosition.y, newPosition.z];
|
||||||
|
|
||||||
if (model) {
|
if (model) {
|
||||||
@@ -162,6 +216,21 @@ const DuplicationControls3D = ({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (duplicatedObjects.length > 0) {
|
||||||
|
const intersectionPoint = new THREE.Vector3();
|
||||||
|
raycaster.setFromCamera(pointer, camera);
|
||||||
|
const hit = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
||||||
|
if (hit) {
|
||||||
|
const model = scene.getObjectByProperty("uuid", duplicatedObjects[0].userData.modelUuid);
|
||||||
|
if (model) {
|
||||||
|
const newOffset = calculateDragOffset(model, intersectionPoint);
|
||||||
|
setDragOffset(newOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [axisConstraint, camera, duplicatedObjects])
|
||||||
|
|
||||||
const duplicateSelection = useCallback(() => {
|
const duplicateSelection = useCallback(() => {
|
||||||
if (selectedAssets.length > 0 && duplicatedObjects.length === 0) {
|
if (selectedAssets.length > 0 && duplicatedObjects.length === 0) {
|
||||||
const positions: Record<string, THREE.Vector3> = {};
|
const positions: Record<string, THREE.Vector3> = {};
|
||||||
@@ -593,6 +662,7 @@ const DuplicationControls3D = ({
|
|||||||
setSelectedAssets([]);
|
setSelectedAssets([]);
|
||||||
setIsDuplicating(false);
|
setIsDuplicating(false);
|
||||||
setDragOffset(null);
|
setDragOffset(null);
|
||||||
|
setAxisConstraint(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
import * as THREE from "three";
|
||||||
|
|
||||||
|
export function handleAssetPositionSnap({
|
||||||
|
rawBasePosition,
|
||||||
|
intersectionPoint,
|
||||||
|
model,
|
||||||
|
axisConstraint,
|
||||||
|
keyEvent,
|
||||||
|
fineMoveBaseRef,
|
||||||
|
lastPointerPositionRef,
|
||||||
|
wasShiftHeldRef
|
||||||
|
}: {
|
||||||
|
rawBasePosition: THREE.Vector3;
|
||||||
|
intersectionPoint: THREE.Vector3;
|
||||||
|
model: THREE.Object3D | undefined;
|
||||||
|
axisConstraint: "x" | "z" | null;
|
||||||
|
keyEvent: string;
|
||||||
|
fineMoveBaseRef: React.MutableRefObject<THREE.Vector3 | null>;
|
||||||
|
lastPointerPositionRef: React.MutableRefObject<THREE.Vector3 | null>;
|
||||||
|
wasShiftHeldRef: React.MutableRefObject<boolean>;
|
||||||
|
}): THREE.Vector3 {
|
||||||
|
const CTRL_DISTANCE = 0.5;
|
||||||
|
const SHIFT_DISTANCE = 0.05;
|
||||||
|
const CTRL_SHIFT_DISTANCE = 0.05;
|
||||||
|
|
||||||
|
const isShiftHeld = keyEvent.includes("Shift");
|
||||||
|
|
||||||
|
// Handle Shift toggle state
|
||||||
|
if (isShiftHeld !== wasShiftHeldRef.current && model) {
|
||||||
|
if (isShiftHeld) {
|
||||||
|
fineMoveBaseRef.current = model.position.clone();
|
||||||
|
lastPointerPositionRef.current = intersectionPoint.clone();
|
||||||
|
} else {
|
||||||
|
fineMoveBaseRef.current = null;
|
||||||
|
}
|
||||||
|
wasShiftHeldRef.current = isShiftHeld;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start from raw
|
||||||
|
let baseNewPosition = rawBasePosition.clone();
|
||||||
|
|
||||||
|
// Apply snapping / fine move
|
||||||
|
if (keyEvent === "Ctrl") {
|
||||||
|
baseNewPosition.set(
|
||||||
|
Math.round(baseNewPosition.x / CTRL_DISTANCE) * CTRL_DISTANCE,
|
||||||
|
baseNewPosition.y,
|
||||||
|
Math.round(baseNewPosition.z / CTRL_DISTANCE) * CTRL_DISTANCE
|
||||||
|
);
|
||||||
|
} else if (keyEvent === "Ctrl+Shift") {
|
||||||
|
if (isShiftHeld && fineMoveBaseRef.current && lastPointerPositionRef.current) {
|
||||||
|
const pointerDelta = new THREE.Vector3().subVectors(intersectionPoint, lastPointerPositionRef.current);
|
||||||
|
baseNewPosition = fineMoveBaseRef.current.clone().add(pointerDelta.multiplyScalar(SHIFT_DISTANCE));
|
||||||
|
}
|
||||||
|
baseNewPosition.set(
|
||||||
|
Math.round(baseNewPosition.x / CTRL_SHIFT_DISTANCE) * CTRL_SHIFT_DISTANCE,
|
||||||
|
baseNewPosition.y,
|
||||||
|
Math.round(baseNewPosition.z / CTRL_SHIFT_DISTANCE) * CTRL_SHIFT_DISTANCE
|
||||||
|
);
|
||||||
|
} else if (isShiftHeld && fineMoveBaseRef.current && lastPointerPositionRef.current) {
|
||||||
|
const pointerDelta = new THREE.Vector3().subVectors(intersectionPoint, lastPointerPositionRef.current);
|
||||||
|
baseNewPosition = fineMoveBaseRef.current.clone().add(pointerDelta.multiplyScalar(SHIFT_DISTANCE));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply axis constraint last
|
||||||
|
if (axisConstraint && model) {
|
||||||
|
const currentBasePosition = model.position.clone();
|
||||||
|
if (axisConstraint === 'x') {
|
||||||
|
baseNewPosition.set(baseNewPosition.x, currentBasePosition.y, currentBasePosition.z);
|
||||||
|
} else if (axisConstraint === 'z') {
|
||||||
|
baseNewPosition.set(currentBasePosition.x, currentBasePosition.y, baseNewPosition.z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return baseNewPosition;
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@ import { useContextActionStore, useSelectedAssets, useSocketStore, useToggleView
|
|||||||
import * as Types from "../../../../../types/world/worldTypes";
|
import * as Types from "../../../../../types/world/worldTypes";
|
||||||
import { detectModifierKeys } from "../../../../../utils/shortcutkeys/detectModifierKeys";
|
import { detectModifierKeys } from "../../../../../utils/shortcutkeys/detectModifierKeys";
|
||||||
import { upsertProductOrEventApi } from "../../../../../services/simulation/products/UpsertProductOrEventApi";
|
import { upsertProductOrEventApi } from "../../../../../services/simulation/products/UpsertProductOrEventApi";
|
||||||
import { snapControls } from "../../../../../utils/handleSnap";
|
import { handleAssetPositionSnap } from "./functions/handleAssetPositionSnap";
|
||||||
import DistanceFindingControls from "./distanceFindingControls";
|
import DistanceFindingControls from "./distanceFindingControls";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import { useProductContext } from "../../../../simulation/products/productContext";
|
import { useProductContext } from "../../../../simulation/products/productContext";
|
||||||
@@ -34,7 +34,6 @@ function MoveControls3D({
|
|||||||
const { selectedProductStore } = useProductContext();
|
const { selectedProductStore } = useProductContext();
|
||||||
const { selectedProduct } = selectedProductStore();
|
const { selectedProduct } = selectedProductStore();
|
||||||
const { socket } = useSocketStore();
|
const { socket } = useSocketStore();
|
||||||
const [keyEvent, setKeyEvent] = useState<"Ctrl" | "Shift" | "Ctrl+Shift" | "">("");
|
|
||||||
const { userId, organization } = getUserData();
|
const { userId, organization } = getUserData();
|
||||||
const { projectId } = useParams();
|
const { projectId } = useParams();
|
||||||
const { assetStore, eventStore, productStore, undoRedo3DStore } = useSceneContext();
|
const { assetStore, eventStore, productStore, undoRedo3DStore } = useSceneContext();
|
||||||
@@ -43,12 +42,17 @@ function MoveControls3D({
|
|||||||
const { selectedVersionStore } = useVersionContext();
|
const { selectedVersionStore } = useVersionContext();
|
||||||
const { selectedVersion } = selectedVersionStore();
|
const { selectedVersion } = selectedVersionStore();
|
||||||
|
|
||||||
|
const [keyEvent, setKeyEvent] = useState<"Ctrl" | "Shift" | "Ctrl+Shift" | "">("");
|
||||||
|
const [axisConstraint, setAxisConstraint] = useState<"x" | "z" | null>(null);
|
||||||
const [dragOffset, setDragOffset] = useState<THREE.Vector3 | null>(null);
|
const [dragOffset, setDragOffset] = useState<THREE.Vector3 | null>(null);
|
||||||
const [initialPositions, setInitialPositions] = useState<Record<string, THREE.Vector3>>({});
|
const [initialPositions, setInitialPositions] = useState<Record<string, THREE.Vector3>>({});
|
||||||
const [initialStates, setInitialStates] = useState<Record<string, { position: THREE.Vector3; rotation?: THREE.Euler; }>>({});
|
const [initialStates, setInitialStates] = useState<Record<string, { position: THREE.Vector3; rotation?: THREE.Euler; }>>({});
|
||||||
const [isMoving, setIsMoving] = useState(false);
|
const [isMoving, setIsMoving] = useState(false);
|
||||||
const mouseButtonsDown = useRef<{ left: boolean; right: boolean }>({ left: false, right: false, });
|
const mouseButtonsDown = useRef<{ left: boolean; right: boolean }>({ left: false, right: false, });
|
||||||
const { contextAction, setContextAction } = useContextActionStore()
|
const { contextAction, setContextAction } = useContextActionStore()
|
||||||
|
const fineMoveBaseRef = useRef<THREE.Vector3 | null>(null);
|
||||||
|
const lastPointerPositionRef = useRef<THREE.Vector3 | null>(null);
|
||||||
|
const wasShiftHeldRef = useRef(false);
|
||||||
|
|
||||||
const updateBackend = (
|
const updateBackend = (
|
||||||
productName: string,
|
productName: string,
|
||||||
@@ -85,10 +89,21 @@ function MoveControls3D({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onKeyUp = (event: KeyboardEvent) => {
|
const onKeyUp = (event: KeyboardEvent) => {
|
||||||
const isModifierKey = (!event.shiftKey && !event.ctrlKey);
|
const keyCombination = detectModifierKeys(event);
|
||||||
|
|
||||||
if (isModifierKey && keyEvent !== "") {
|
if (keyCombination === "") {
|
||||||
setKeyEvent("");
|
setKeyEvent("");
|
||||||
|
} else if (keyCombination === "Ctrl" || keyCombination === "Ctrl+Shift" || keyCombination === "Shift") {
|
||||||
|
setKeyEvent(keyCombination);
|
||||||
|
}
|
||||||
|
if (movedObjects[0]) {
|
||||||
|
const intersectionPoint = new THREE.Vector3();
|
||||||
|
raycaster.setFromCamera(pointer, camera);
|
||||||
|
const hit = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
||||||
|
if (hit) {
|
||||||
|
const newOffset = calculateDragOffset(movedObjects[0], intersectionPoint);
|
||||||
|
setDragOffset(newOffset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -113,7 +128,6 @@ function MoveControls3D({
|
|||||||
clearSelection();
|
clearSelection();
|
||||||
setMovedObjects([]);
|
setMovedObjects([]);
|
||||||
}
|
}
|
||||||
setKeyEvent("");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const onKeyDown = (event: KeyboardEvent) => {
|
const onKeyDown = (event: KeyboardEvent) => {
|
||||||
@@ -122,6 +136,19 @@ 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 (isMoving && movedObjects.length > 0) {
|
||||||
|
if (event.key.toLowerCase() === 'x') {
|
||||||
|
setAxisConstraint(prev => prev === 'x' ? null : 'x');
|
||||||
|
event.preventDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (event.key.toLowerCase() === 'z') {
|
||||||
|
setAxisConstraint(prev => prev === 'z' ? null : 'z');
|
||||||
|
event.preventDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (keyCombination !== keyEvent) {
|
if (keyCombination !== keyEvent) {
|
||||||
if (keyCombination === "Ctrl" || keyCombination === "Ctrl+Shift" || keyCombination === "Shift") {
|
if (keyCombination === "Ctrl" || keyCombination === "Ctrl+Shift" || keyCombination === "Shift") {
|
||||||
setKeyEvent(keyCombination);
|
setKeyEvent(keyCombination);
|
||||||
@@ -192,9 +219,22 @@ function MoveControls3D({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, 0)
|
setAxisConstraint(null);
|
||||||
|
}, 100)
|
||||||
}, [movedObjects, initialStates, updateAsset]);
|
}, [movedObjects, initialStates, updateAsset]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (movedObjects.length > 0) {
|
||||||
|
const intersectionPoint = new THREE.Vector3();
|
||||||
|
raycaster.setFromCamera(pointer, camera);
|
||||||
|
const hit = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
||||||
|
if (hit) {
|
||||||
|
const newOffset = calculateDragOffset(movedObjects[0], intersectionPoint);
|
||||||
|
setDragOffset(newOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [axisConstraint, camera, movedObjects])
|
||||||
|
|
||||||
useFrame(() => {
|
useFrame(() => {
|
||||||
if (!isMoving || movedObjects.length === 0) return;
|
if (!isMoving || movedObjects.length === 0) return;
|
||||||
|
|
||||||
@@ -213,20 +253,8 @@ function MoveControls3D({
|
|||||||
|
|
||||||
if (dragOffset) {
|
if (dragOffset) {
|
||||||
const rawBasePosition = new THREE.Vector3().addVectors(intersectionPoint, dragOffset);
|
const rawBasePosition = new THREE.Vector3().addVectors(intersectionPoint, dragOffset);
|
||||||
|
const model = movedObjects[0];
|
||||||
let moveDistance = keyEvent.includes("Shift") ? 0.05 : 1;
|
const baseNewPosition = handleAssetPositionSnap({ rawBasePosition, intersectionPoint, model, axisConstraint, keyEvent, fineMoveBaseRef, lastPointerPositionRef, wasShiftHeldRef });
|
||||||
|
|
||||||
const initialBasePosition = initialPositions[movedObjects[0].uuid];
|
|
||||||
const positionDifference = new THREE.Vector3().subVectors(rawBasePosition, initialBasePosition);
|
|
||||||
|
|
||||||
let adjustedDifference = positionDifference.multiplyScalar(moveDistance);
|
|
||||||
|
|
||||||
const baseNewPosition = new THREE.Vector3().addVectors(initialBasePosition, adjustedDifference);
|
|
||||||
|
|
||||||
if (keyEvent.includes("Ctrl")) {
|
|
||||||
baseNewPosition.x = snapControls(baseNewPosition.x, keyEvent);
|
|
||||||
baseNewPosition.z = snapControls(baseNewPosition.z, keyEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
movedObjects.forEach((movedAsset: THREE.Object3D) => {
|
movedObjects.forEach((movedAsset: THREE.Object3D) => {
|
||||||
if (movedAsset.userData.modelUuid) {
|
if (movedAsset.userData.modelUuid) {
|
||||||
@@ -430,6 +458,7 @@ function MoveControls3D({
|
|||||||
echo.success("Object moved!");
|
echo.success("Object moved!");
|
||||||
setIsMoving(false);
|
setIsMoving(false);
|
||||||
clearSelection();
|
clearSelection();
|
||||||
|
setAxisConstraint(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
const clearSelection = () => {
|
const clearSelection = () => {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { useProductContext } from "../../../products/productContext";
|
|||||||
import { useHumanEventManager } from "../../../human/eventManager/useHumanEventManager";
|
import { useHumanEventManager } from "../../../human/eventManager/useHumanEventManager";
|
||||||
|
|
||||||
export function useRetrieveHandler() {
|
export function useRetrieveHandler() {
|
||||||
const { materialStore, armBotStore, machineStore, vehicleStore, storageUnitStore, conveyorStore, craneStore, productStore, humanStore, assetStore } = useSceneContext();
|
const { materialStore, armBotStore, machineStore, vehicleStore, storageUnitStore, conveyorStore, craneStore, productStore, humanStore, assetStore, humanEventManagerRef } = useSceneContext();
|
||||||
const { selectedProductStore } = useProductContext();
|
const { selectedProductStore } = useProductContext();
|
||||||
const { addMaterial } = materialStore();
|
const { addMaterial } = materialStore();
|
||||||
const { getModelUuidByActionUuid, getPointUuidByActionUuid, getEventByModelUuid, getActionByUuid } = productStore();
|
const { getModelUuidByActionUuid, getPointUuidByActionUuid, getEventByModelUuid, getActionByUuid } = productStore();
|
||||||
@@ -464,11 +464,20 @@ export function useRetrieveHandler() {
|
|||||||
if (action && action.actionType === 'pickAndDrop' && !hasLock && !crane.isCarrying && !crane.isActive && crane.currentLoad < (action?.maxPickUpCount || 0)) {
|
if (action && action.actionType === 'pickAndDrop' && !hasLock && !crane.isCarrying && !crane.isActive && crane.currentLoad < (action?.maxPickUpCount || 0)) {
|
||||||
const material = getLastMaterial(storageUnit.modelUuid);
|
const material = getLastMaterial(storageUnit.modelUuid);
|
||||||
if (material) {
|
if (material) {
|
||||||
incrementCraneLoad(crane.modelUuid, 1);
|
if (action.triggers[0].triggeredAsset?.triggeredModel.modelUuid && action.triggers[0].triggeredAsset.triggeredAction?.actionUuid) {
|
||||||
addCurrentActionToCrane(crane.modelUuid, action.actionUuid, material.materialType, material.materialId);
|
const human = getEventByModelUuid(selectedProduct.productUuid, action.triggers[0].triggeredAsset.triggeredModel.modelUuid);
|
||||||
addCurrentMaterialToCrane(crane.modelUuid, material.materialType, material.materialId);
|
if (human && human.type === 'human') {
|
||||||
|
if (!monitoredHumansRef.current.has(human.modelUuid)) {
|
||||||
cranePickupLockRef.current.set(crane.modelUuid, true);
|
addHumanToMonitor(human.modelUuid, () => {
|
||||||
|
incrementCraneLoad(crane.modelUuid, 1);
|
||||||
|
addCurrentActionToCrane(crane.modelUuid, action.actionUuid, material.materialType, material.materialId);
|
||||||
|
addCurrentMaterialToCrane(crane.modelUuid, material.materialType, material.materialId);
|
||||||
|
cranePickupLockRef.current.set(crane.modelUuid, true);
|
||||||
|
}, action.triggers[0].triggeredAsset.triggeredAction?.actionUuid)
|
||||||
|
}
|
||||||
|
monitoredHumansRef.current.add(human.modelUuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (crane.isCarrying && crane.currentPhase === 'pickup-drop' && hasLock) {
|
} else if (crane.isCarrying && crane.currentPhase === 'pickup-drop' && hasLock) {
|
||||||
cranePickupLockRef.current.set(crane.modelUuid, false);
|
cranePickupLockRef.current.set(crane.modelUuid, false);
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ export function useHumanEventManager() {
|
|||||||
}, [isReset, isPlaying]);
|
}, [isReset, isPlaying]);
|
||||||
|
|
||||||
const addHumanToMonitor = (humanId: string, callback: () => void, actionUuid: string) => {
|
const addHumanToMonitor = (humanId: string, callback: () => void, actionUuid: string) => {
|
||||||
|
console.log('humanId: ', humanId);
|
||||||
const human = getHumanById(humanId);
|
const human = getHumanById(humanId);
|
||||||
const action = getActionByUuid(selectedProduct.productUuid, actionUuid);
|
const action = getActionByUuid(selectedProduct.productUuid, actionUuid);
|
||||||
if (!human || !action || (action.actionType !== 'assembly' && action.actionType !== 'worker' && action.actionType !== 'operator') || !humanEventManagerRef.current) return;
|
if (!human || !action || (action.actionType !== 'assembly' && action.actionType !== 'worker' && action.actionType !== 'operator') || !humanEventManagerRef.current) return;
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
export function snapControls(value: number, event: string): number {
|
|
||||||
const CTRL_DISTANCE = 1; // Snap to whole numbers when Ctrl is pressed
|
|
||||||
const SHIFT_DISTANCE = 0.01; // Snap to half-step increments when Shift is pressed
|
|
||||||
const CTRL_SHIFT_DISTANCE = 0.1; // Snap to fine increments when both Ctrl and Shift are pressed
|
|
||||||
|
|
||||||
switch (event) {
|
|
||||||
case "Ctrl":
|
|
||||||
return Math.round(value / CTRL_DISTANCE) * CTRL_DISTANCE;
|
|
||||||
|
|
||||||
case "Shift":
|
|
||||||
return Math.round(value / SHIFT_DISTANCE) * SHIFT_DISTANCE;
|
|
||||||
|
|
||||||
case "Ctrl+Shift":
|
|
||||||
const base = Math.floor(value / CTRL_DISTANCE) * CTRL_DISTANCE;
|
|
||||||
const offset =
|
|
||||||
Math.round((value - base) / CTRL_SHIFT_DISTANCE) * CTRL_SHIFT_DISTANCE;
|
|
||||||
return base + offset;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return value; // No snapping if no modifier key is pressed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -41,6 +41,7 @@ const KeyPressListener: React.FC = () => {
|
|||||||
const { toggleView, setToggleView } = useToggleView();
|
const { toggleView, setToggleView } = useToggleView();
|
||||||
const { setAddAction } = useAddAction();
|
const { setAddAction } = useAddAction();
|
||||||
const { setSelectedWallItem } = useSelectedWallItem();
|
const { setSelectedWallItem } = useSelectedWallItem();
|
||||||
|
const { selectedAssets } = useSelectedAssets();
|
||||||
const { setActiveTool } = useActiveTool();
|
const { setActiveTool } = useActiveTool();
|
||||||
const { clearSelectedZone } = useSelectedZoneStore();
|
const { clearSelectedZone } = useSelectedZoneStore();
|
||||||
const { showShortcuts, setShowShortcuts } = useShortcutStore();
|
const { showShortcuts, setShowShortcuts } = useShortcutStore();
|
||||||
@@ -84,7 +85,7 @@ const KeyPressListener: React.FC = () => {
|
|||||||
H: "free-hand",
|
H: "free-hand",
|
||||||
};
|
};
|
||||||
const tool = toolMap[key];
|
const tool = toolMap[key];
|
||||||
if (tool) {
|
if (tool && selectedAssets.length === 0) {
|
||||||
setActiveTool(tool);
|
setActiveTool(tool);
|
||||||
setActiveSubTool(tool);
|
setActiveSubTool(tool);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user