added flip controls to asset and added in context menu too
This commit is contained in:
@@ -5,7 +5,6 @@ import {
|
||||
DeleteIcon,
|
||||
DublicateIcon,
|
||||
FlipXAxisIcon,
|
||||
FlipZAxisIcon,
|
||||
FocusIcon,
|
||||
GroupIcon,
|
||||
ModifiersIcon,
|
||||
@@ -21,8 +20,8 @@ import {
|
||||
type VisibilityKey =
|
||||
| "rename"
|
||||
| "focus"
|
||||
| "flipX"
|
||||
| "flipZ"
|
||||
| "flip"
|
||||
| "flipIndividual"
|
||||
| "move"
|
||||
| "rotate"
|
||||
| "duplicate"
|
||||
@@ -39,8 +38,8 @@ type ContextMenuProps = {
|
||||
visibility: Record<Exclude<VisibilityKey, "transform" | "groupArray">, boolean>;
|
||||
onRename: () => void;
|
||||
onFocus: () => void;
|
||||
onFlipX: () => void;
|
||||
onFlipZ: () => void;
|
||||
onFlip: () => void;
|
||||
onFlipIndividual: () => void;
|
||||
onMove: () => void;
|
||||
onRotate: () => void;
|
||||
onDuplicate: () => void;
|
||||
@@ -61,7 +60,7 @@ type MenuItem = {
|
||||
children?: MenuItem[];
|
||||
};
|
||||
|
||||
const ContextMenu: React.FC<ContextMenuProps> = ({ visibility, onRename, onFocus, onFlipX, onFlipZ, onMove, onRotate, onDuplicate, onCopy, onPaste, onGroup, onArray, onDelete }) => {
|
||||
const ContextMenu: React.FC<ContextMenuProps> = ({ visibility, onRename, onFocus, onFlip, onFlipIndividual, onMove, onRotate, onDuplicate, onCopy, onPaste, onGroup, onArray, onDelete }) => {
|
||||
const items: MenuItem[] = [
|
||||
{
|
||||
key: "rename",
|
||||
@@ -78,16 +77,16 @@ const ContextMenu: React.FC<ContextMenuProps> = ({ visibility, onRename, onFocus
|
||||
onClick: onFocus,
|
||||
},
|
||||
{
|
||||
key: "flipX",
|
||||
label: "Flip to X axis",
|
||||
key: "flip",
|
||||
label: "Flip",
|
||||
icon: <FlipXAxisIcon />,
|
||||
onClick: onFlipX,
|
||||
onClick: onFlip,
|
||||
},
|
||||
{
|
||||
key: "flipZ",
|
||||
label: "Flip to Z axis",
|
||||
icon: <FlipZAxisIcon />,
|
||||
onClick: onFlipZ,
|
||||
key: "flipIndividual",
|
||||
label: "Flip Individual",
|
||||
icon: <FlipXAxisIcon />,
|
||||
onClick: onFlipIndividual,
|
||||
},
|
||||
{
|
||||
key: "transform",
|
||||
|
||||
@@ -1,16 +1,309 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import * as THREE from "three";
|
||||
import { useContextActionStore } from "../../../../store/builder/store";
|
||||
import { useSceneContext } from "../../sceneContext";
|
||||
import { useSocketStore } from "../../../../store/socket/useSocketStore";
|
||||
import { getUserData } from "../../../../functions/getUserData";
|
||||
import useAssetResponseHandler from "../../../collaboration/responseHandler/useAssetResponseHandler";
|
||||
import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi";
|
||||
import { setAssetsApi } from "../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi";
|
||||
|
||||
function ScaleControls3D() {
|
||||
const { assetStore, eventStore, productStore, versionStore, undoRedo3DStore } = useSceneContext();
|
||||
const { push3D } = undoRedo3DStore();
|
||||
const { selectedAssets, getAssetById } = assetStore();
|
||||
const { contextAction, setContextAction } = useContextActionStore();
|
||||
const { updateAssetInScene } = useAssetResponseHandler();
|
||||
const { projectId } = useParams();
|
||||
const { builderSocket } = useSocketStore();
|
||||
const { userId, organization } = getUserData();
|
||||
const { selectedVersion } = versionStore();
|
||||
|
||||
useEffect(() => {
|
||||
if (contextAction === "") {
|
||||
if (contextAction === "flipAsset") {
|
||||
flip();
|
||||
setContextAction(null);
|
||||
} else if (contextAction === "flipAssetIndividual") {
|
||||
flipIndividual();
|
||||
setContextAction(null);
|
||||
}
|
||||
}, [contextAction]);
|
||||
|
||||
return <></>;
|
||||
const normalizeAngle = (angle: number) => {
|
||||
const twoPI = Math.PI * 2;
|
||||
return ((angle % twoPI) + twoPI) % twoPI;
|
||||
};
|
||||
|
||||
const updateBackend = (productName: string, productUuid: string, projectId: string, eventData: any) => {
|
||||
upsertProductOrEventApi({
|
||||
productName: productName,
|
||||
productUuid: productUuid,
|
||||
projectId: projectId,
|
||||
eventDatas: eventData,
|
||||
versionId: selectedVersion?.versionId || "",
|
||||
});
|
||||
};
|
||||
|
||||
const handleAssetUpdate = async (modelUuid: string, newPosition: [number, number, number], newRotation: [number, number, number]) => {
|
||||
const asset = getAssetById(modelUuid);
|
||||
if (!asset) return;
|
||||
|
||||
const updatedAsset: Asset = {
|
||||
modelUuid: asset.modelUuid,
|
||||
modelName: asset.modelName,
|
||||
assetId: asset.assetId,
|
||||
position: newPosition,
|
||||
rotation: newRotation,
|
||||
scale: asset.scale,
|
||||
isCollidable: true,
|
||||
opacity: 1,
|
||||
isLocked: false,
|
||||
isVisible: true,
|
||||
};
|
||||
|
||||
if (asset.eventData) {
|
||||
const eventData = eventStore.getState().getEventByModelUuid(modelUuid);
|
||||
const productData = productStore.getState().getEventByModelUuid(productStore.getState().selectedProduct.productUuid, modelUuid);
|
||||
|
||||
if (eventData) {
|
||||
eventStore.getState().updateEvent(modelUuid, {
|
||||
position: newPosition,
|
||||
rotation: newRotation,
|
||||
});
|
||||
}
|
||||
|
||||
if (productData) {
|
||||
const event = productStore.getState().updateEvent(productStore.getState().selectedProduct.productUuid, modelUuid, {
|
||||
position: newPosition,
|
||||
rotation: newRotation,
|
||||
});
|
||||
|
||||
if (event) {
|
||||
updateBackend(productStore.getState().selectedProduct.productName, productStore.getState().selectedProduct.productUuid, projectId || "", event);
|
||||
}
|
||||
|
||||
updatedAsset.eventData = eventData;
|
||||
}
|
||||
}
|
||||
|
||||
if (!builderSocket?.connected) {
|
||||
setAssetsApi({
|
||||
modelUuid: updatedAsset.modelUuid,
|
||||
modelName: updatedAsset.modelName,
|
||||
assetId: updatedAsset.assetId,
|
||||
position: updatedAsset.position,
|
||||
rotation: updatedAsset.rotation,
|
||||
scale: updatedAsset.scale,
|
||||
isLocked: false,
|
||||
isVisible: true,
|
||||
versionId: selectedVersion?.versionId || "",
|
||||
projectId: projectId || "",
|
||||
})
|
||||
.then((data) => {
|
||||
if (!data.message || !data.data) {
|
||||
echo.error(`Error flipping asset: ${updatedAsset.modelName}`);
|
||||
return;
|
||||
}
|
||||
if (data.message === "Model updated successfully" && data.data) {
|
||||
const model = {
|
||||
modelUuid: data.data.modelUuid,
|
||||
modelName: data.data.modelName,
|
||||
assetId: data.data.assetId,
|
||||
position: data.data.position,
|
||||
rotation: data.data.rotation,
|
||||
scale: data.data.scale,
|
||||
isLocked: data.data.isLocked,
|
||||
isCollidable: true,
|
||||
isVisible: data.data.isVisible,
|
||||
opacity: 1,
|
||||
eventData: data.data.eventData,
|
||||
};
|
||||
|
||||
updateAssetInScene(model, () => {
|
||||
echo.info(`Flipped asset: ${model.modelName}`);
|
||||
});
|
||||
} else {
|
||||
echo.error(`Error flipping asset: ${updatedAsset.modelName}`);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
echo.error(`Error flipping asset: ${updatedAsset.modelName}`);
|
||||
});
|
||||
} else {
|
||||
const data = {
|
||||
organization,
|
||||
modelUuid: updatedAsset.modelUuid,
|
||||
modelName: updatedAsset.modelName,
|
||||
assetId: updatedAsset.assetId,
|
||||
position: updatedAsset.position,
|
||||
rotation: updatedAsset.rotation,
|
||||
scale: updatedAsset.scale,
|
||||
isLocked: false,
|
||||
isVisible: true,
|
||||
socketId: builderSocket?.id,
|
||||
versionId: selectedVersion?.versionId || "",
|
||||
projectId,
|
||||
userId,
|
||||
};
|
||||
|
||||
builderSocket.emit("v1:model-asset:add", data);
|
||||
}
|
||||
};
|
||||
|
||||
const flip = () => {
|
||||
if (!selectedAssets.length) return;
|
||||
|
||||
const undoActions: UndoRedo3DAction[] = [];
|
||||
const assetUpdates: AssetData[] = [];
|
||||
|
||||
if (selectedAssets.length === 1) {
|
||||
const obj = selectedAssets[0];
|
||||
const { modelUuid, rotation, position } = obj.userData;
|
||||
const originalPosition: [number, number, number] = position || [0, 0, 0];
|
||||
const originalRotation: [number, number, number] = rotation || [0, 0, 0];
|
||||
const newRotY = normalizeAngle((originalRotation?.[1] || 0) + Math.PI);
|
||||
|
||||
const newRotation: [number, number, number] = [0, newRotY, 0];
|
||||
|
||||
const asset = getAssetById(modelUuid);
|
||||
if (asset) {
|
||||
assetUpdates.push({
|
||||
type: "Asset",
|
||||
assetData: {
|
||||
...asset,
|
||||
position: originalPosition,
|
||||
rotation: originalRotation,
|
||||
},
|
||||
newData: {
|
||||
...asset,
|
||||
position: originalPosition,
|
||||
rotation: newRotation,
|
||||
},
|
||||
timeStap: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
|
||||
handleAssetUpdate(modelUuid, originalPosition, newRotation);
|
||||
} else {
|
||||
const bbox = new THREE.Box3();
|
||||
selectedAssets.forEach((obj) => bbox.expandByObject(obj));
|
||||
const pivot = new THREE.Vector3();
|
||||
bbox.getCenter(pivot);
|
||||
|
||||
selectedAssets.forEach((obj) => {
|
||||
const { modelUuid, position, rotation } = obj.userData;
|
||||
const originalPosition: [number, number, number] = position || [0, 0, 0];
|
||||
const originalRotation: [number, number, number] = rotation || [0, 0, 0];
|
||||
const pos = new THREE.Vector3(...originalPosition);
|
||||
|
||||
pos.x = 2 * pivot.x - pos.x;
|
||||
const newRotY = normalizeAngle(originalRotation[1] + Math.PI);
|
||||
const newPosition: [number, number, number] = [pos.x, pos.y, pos.z];
|
||||
const newRotation: [number, number, number] = [0, newRotY, 0];
|
||||
|
||||
const asset = getAssetById(modelUuid);
|
||||
if (asset) {
|
||||
assetUpdates.push({
|
||||
type: "Asset",
|
||||
assetData: {
|
||||
...asset,
|
||||
position: originalPosition,
|
||||
rotation: originalRotation,
|
||||
},
|
||||
newData: {
|
||||
...asset,
|
||||
position: newPosition,
|
||||
rotation: newRotation,
|
||||
},
|
||||
timeStap: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
|
||||
handleAssetUpdate(modelUuid, newPosition, newRotation);
|
||||
});
|
||||
}
|
||||
|
||||
if (assetUpdates.length > 0) {
|
||||
if (assetUpdates.length === 1) {
|
||||
undoActions.push({
|
||||
module: "builder",
|
||||
actionType: "Asset-Update",
|
||||
asset: assetUpdates[0],
|
||||
});
|
||||
} else {
|
||||
undoActions.push({
|
||||
module: "builder",
|
||||
actionType: "Assets-Update",
|
||||
assets: assetUpdates,
|
||||
});
|
||||
}
|
||||
|
||||
push3D({
|
||||
type: "Scene",
|
||||
actions: undoActions,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const flipIndividual = () => {
|
||||
if (!selectedAssets.length) return;
|
||||
|
||||
const undoActions: UndoRedo3DAction[] = [];
|
||||
const assetUpdates: AssetData[] = [];
|
||||
|
||||
selectedAssets.forEach((obj) => {
|
||||
const { modelUuid, position, rotation } = obj.userData;
|
||||
const originalPosition: [number, number, number] = position || [0, 0, 0];
|
||||
const originalRotation: [number, number, number] = rotation || [0, 0, 0];
|
||||
|
||||
const newRotY = normalizeAngle(originalRotation[1] + Math.PI);
|
||||
const newRotation: [number, number, number] = [0, newRotY, 0];
|
||||
|
||||
const asset = getAssetById(modelUuid);
|
||||
if (asset) {
|
||||
assetUpdates.push({
|
||||
type: "Asset",
|
||||
assetData: {
|
||||
...asset,
|
||||
position: originalPosition,
|
||||
rotation: originalRotation,
|
||||
},
|
||||
newData: {
|
||||
...asset,
|
||||
position: originalPosition,
|
||||
rotation: newRotation,
|
||||
},
|
||||
timeStap: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
|
||||
handleAssetUpdate(modelUuid, position, newRotation);
|
||||
});
|
||||
|
||||
if (assetUpdates.length > 0) {
|
||||
if (assetUpdates.length === 1) {
|
||||
undoActions.push({
|
||||
module: "builder",
|
||||
actionType: "Asset-Update",
|
||||
asset: assetUpdates[0],
|
||||
});
|
||||
} else {
|
||||
undoActions.push({
|
||||
module: "builder",
|
||||
actionType: "Assets-Update",
|
||||
assets: assetUpdates,
|
||||
});
|
||||
}
|
||||
|
||||
push3D({
|
||||
type: "Scene",
|
||||
actions: undoActions,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export default ScaleControls3D;
|
||||
|
||||
@@ -12,8 +12,8 @@ function ContextControls() {
|
||||
const [visibility, setVisibility] = useState({
|
||||
rename: true,
|
||||
focus: true,
|
||||
flipX: true,
|
||||
flipZ: true,
|
||||
flip: true,
|
||||
flipIndividual: false,
|
||||
move: true,
|
||||
rotate: true,
|
||||
duplicate: true,
|
||||
@@ -25,6 +25,7 @@ function ContextControls() {
|
||||
delete: true,
|
||||
});
|
||||
const [menuPosition, setMenuPosition] = useState({ x: 0, y: 0 });
|
||||
|
||||
const { toggleView } = useToggleView();
|
||||
const { activeModule } = useModuleStore();
|
||||
const { toolMode } = useToolMode();
|
||||
@@ -40,8 +41,8 @@ function ContextControls() {
|
||||
setVisibility({
|
||||
rename: true,
|
||||
focus: true,
|
||||
flipX: true,
|
||||
flipZ: true,
|
||||
flip: true,
|
||||
flipIndividual: false,
|
||||
move: true,
|
||||
rotate: true,
|
||||
duplicate: true,
|
||||
@@ -56,8 +57,8 @@ function ContextControls() {
|
||||
setVisibility({
|
||||
rename: false,
|
||||
focus: true,
|
||||
flipX: true,
|
||||
flipZ: true,
|
||||
flip: true,
|
||||
flipIndividual: true,
|
||||
move: true,
|
||||
rotate: true,
|
||||
duplicate: true,
|
||||
@@ -72,8 +73,8 @@ function ContextControls() {
|
||||
setVisibility({
|
||||
rename: false,
|
||||
focus: false,
|
||||
flipX: false,
|
||||
flipZ: false,
|
||||
flip: false,
|
||||
flipIndividual: false,
|
||||
move: false,
|
||||
rotate: false,
|
||||
duplicate: false,
|
||||
@@ -88,8 +89,8 @@ function ContextControls() {
|
||||
setVisibility({
|
||||
rename: false,
|
||||
focus: false,
|
||||
flipX: false,
|
||||
flipZ: false,
|
||||
flip: false,
|
||||
flipIndividual: false,
|
||||
move: false,
|
||||
rotate: false,
|
||||
duplicate: false,
|
||||
@@ -130,23 +131,18 @@ function ContextControls() {
|
||||
const handleContextClick = (event: MouseEvent) => {
|
||||
event.preventDefault();
|
||||
if (rightDrag.current) return;
|
||||
if (selectedAssets.length > 0) {
|
||||
setMenuPosition({ x: event.clientX - gl.domElement.width / 2, y: event.clientY - gl.domElement.height / 2 });
|
||||
setTimeout(() => {
|
||||
setCanRender(true);
|
||||
}, 0);
|
||||
|
||||
if (controls) {
|
||||
(controls as CameraControls).enabled = false;
|
||||
}
|
||||
} else {
|
||||
setMenuPosition({ x: event.clientX - gl.domElement.width / 2, y: event.clientY - gl.domElement.height / 2 });
|
||||
setTimeout(() => {
|
||||
setCanRender(true);
|
||||
}, 0);
|
||||
if (controls) {
|
||||
(controls as CameraControls).enabled = true;
|
||||
}
|
||||
setMenuPosition({
|
||||
x: event.clientX - gl.domElement.width / 2,
|
||||
y: event.clientY - gl.domElement.height / 2,
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
setCanRender(true);
|
||||
}, 0);
|
||||
|
||||
if (controls) {
|
||||
(controls as CameraControls).enabled = selectedAssets.length === 0;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -181,59 +177,53 @@ function ContextControls() {
|
||||
|
||||
const handleAssetRename = () => {
|
||||
setCanRender(false);
|
||||
if (controls) {
|
||||
(controls as CameraControls).enabled = true;
|
||||
}
|
||||
if (controls) (controls as CameraControls).enabled = true;
|
||||
setContextAction("renameAsset");
|
||||
setIsRenameMode(true);
|
||||
};
|
||||
const handleAssetFocus = () => {
|
||||
setCanRender(false);
|
||||
if (controls) {
|
||||
(controls as CameraControls).enabled = true;
|
||||
}
|
||||
if (controls) (controls as CameraControls).enabled = true;
|
||||
setContextAction("focusAsset");
|
||||
};
|
||||
const handleAssetFlip = () => {
|
||||
setCanRender(false);
|
||||
if (controls) (controls as CameraControls).enabled = true;
|
||||
setContextAction("flipAsset");
|
||||
};
|
||||
const handleAssetFlipIndividual = () => {
|
||||
setCanRender(false);
|
||||
if (controls) (controls as CameraControls).enabled = true;
|
||||
setContextAction("flipAssetIndividual");
|
||||
};
|
||||
const handleAssetMove = () => {
|
||||
setCanRender(false);
|
||||
if (controls) {
|
||||
(controls as CameraControls).enabled = true;
|
||||
}
|
||||
if (controls) (controls as CameraControls).enabled = true;
|
||||
setContextAction("moveAsset");
|
||||
};
|
||||
const handleAssetRotate = () => {
|
||||
setCanRender(false);
|
||||
if (controls) {
|
||||
(controls as CameraControls).enabled = true;
|
||||
}
|
||||
if (controls) (controls as CameraControls).enabled = true;
|
||||
setContextAction("rotateAsset");
|
||||
};
|
||||
const handleAssetCopy = () => {
|
||||
setCanRender(false);
|
||||
if (controls) {
|
||||
(controls as CameraControls).enabled = true;
|
||||
}
|
||||
if (controls) (controls as CameraControls).enabled = true;
|
||||
setContextAction("copyAsset");
|
||||
};
|
||||
const handleAssetPaste = () => {
|
||||
setCanRender(false);
|
||||
if (controls) {
|
||||
(controls as CameraControls).enabled = true;
|
||||
}
|
||||
if (controls) (controls as CameraControls).enabled = true;
|
||||
setContextAction("pasteAsset");
|
||||
};
|
||||
const handleAssetDelete = () => {
|
||||
setCanRender(false);
|
||||
if (controls) {
|
||||
(controls as CameraControls).enabled = true;
|
||||
}
|
||||
if (controls) (controls as CameraControls).enabled = true;
|
||||
setContextAction("deleteAsset");
|
||||
};
|
||||
const handleAssetDuplicate = () => {
|
||||
setCanRender(false);
|
||||
if (controls) {
|
||||
(controls as CameraControls).enabled = true;
|
||||
}
|
||||
if (controls) (controls as CameraControls).enabled = true;
|
||||
setContextAction("duplicateAsset");
|
||||
};
|
||||
|
||||
@@ -251,18 +241,18 @@ function ContextControls() {
|
||||
>
|
||||
<ContextMenu
|
||||
visibility={visibility}
|
||||
onRename={() => handleAssetRename()}
|
||||
onFocus={() => handleAssetFocus()}
|
||||
onFlipX={() => console.log("Flip to X")}
|
||||
onFlipZ={() => console.log("Flip to Z")}
|
||||
onMove={() => handleAssetMove()}
|
||||
onRotate={() => handleAssetRotate()}
|
||||
onDuplicate={() => handleAssetDuplicate()}
|
||||
onCopy={() => handleAssetCopy()}
|
||||
onPaste={() => handleAssetPaste()}
|
||||
onRename={handleAssetRename}
|
||||
onFocus={handleAssetFocus}
|
||||
onFlip={handleAssetFlip}
|
||||
onFlipIndividual={handleAssetFlipIndividual}
|
||||
onMove={handleAssetMove}
|
||||
onRotate={handleAssetRotate}
|
||||
onDuplicate={handleAssetDuplicate}
|
||||
onCopy={handleAssetCopy}
|
||||
onPaste={handleAssetPaste}
|
||||
onGroup={() => console.log("Group")}
|
||||
onArray={() => console.log("Array")}
|
||||
onDelete={() => handleAssetDelete()}
|
||||
onDelete={handleAssetDelete}
|
||||
/>
|
||||
</Html>
|
||||
</ScreenSpace>
|
||||
|
||||
@@ -10,12 +10,6 @@ import { getUserData } from "../../../../../functions/getUserData";
|
||||
import { useSceneContext } from "../../../sceneContext";
|
||||
import { useContextActionStore, useToggleView, useToolMode } from "../../../../../store/builder/store";
|
||||
import { useSocketStore } from "../../../../../store/socket/useSocketStore";
|
||||
import DuplicationControls3D from "../../assetControls/duplicationControls3D";
|
||||
import CutCopyPasteControls3D from "../../assetControls/cutCopyPasteControls3D";
|
||||
import MoveControls3D from "../../assetControls/moveControls3D";
|
||||
import RotateControls3D from "../../assetControls/rotateControls3D";
|
||||
import TransformControls3D from "../../assetControls/transformControls3D";
|
||||
import ScaleControls3D from "../../assetControls/scaleControls3D";
|
||||
import { useBuilderStore } from "../../../../../store/builder/useBuilderStore";
|
||||
import useAssetResponseHandler from "../../../../collaboration/responseHandler/useAssetResponseHandler";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user