added new human ui
This commit is contained in:
BIN
app/src/assets/gltf-glb/ui/human-ui-assembly.glb
Normal file
BIN
app/src/assets/gltf-glb/ui/human-ui-assembly.glb
Normal file
Binary file not shown.
BIN
app/src/assets/gltf-glb/ui/human-ui-green.glb
Normal file
BIN
app/src/assets/gltf-glb/ui/human-ui-green.glb
Normal file
Binary file not shown.
BIN
app/src/assets/gltf-glb/ui/human-ui-orange.glb
Normal file
BIN
app/src/assets/gltf-glb/ui/human-ui-orange.glb
Normal file
Binary file not shown.
@@ -17,6 +17,7 @@ import { useSceneContext } from '../../../../scene/sceneContext';
|
||||
import { useVersionContext } from '../../../version/versionContext';
|
||||
import { SkeletonUtils } from 'three-stdlib';
|
||||
import { useAnimationPlaySpeed } from '../../../../../store/usePlayButtonStore';
|
||||
import { upsertProductOrEventApi } from '../../../../../services/simulation/products/UpsertProductOrEventApi';
|
||||
|
||||
function Model({ asset }: { readonly asset: Asset }) {
|
||||
const { camera, controls, gl } = useThree();
|
||||
@@ -55,6 +56,21 @@ function Model({ asset }: { readonly asset: Asset }) {
|
||||
const blendFactor = useRef(0);
|
||||
const blendDuration = 0.5;
|
||||
|
||||
const updateBackend = (
|
||||
productName: string,
|
||||
productUuid: string,
|
||||
projectId: string,
|
||||
eventData: EventsSchema
|
||||
) => {
|
||||
upsertProductOrEventApi({
|
||||
productName: productName,
|
||||
productUuid: productUuid,
|
||||
projectId: projectId,
|
||||
eventDatas: eventData,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setDeletableFloorItem(null);
|
||||
if (selectedFloorItem === null || selectedFloorItem.modelUuid !== asset.modelUuid) {
|
||||
@@ -217,7 +233,16 @@ function Model({ asset }: { readonly asset: Asset }) {
|
||||
const response = socket.emit('v1:model-asset:delete', data)
|
||||
|
||||
eventStore.getState().removeEvent(asset.modelUuid);
|
||||
productStore.getState().deleteEvent(asset.modelUuid);
|
||||
const updatedEvents = productStore.getState().deleteEvent(asset.modelUuid);
|
||||
|
||||
updatedEvents.forEach((event) => {
|
||||
updateBackend(
|
||||
selectedProduct.productName,
|
||||
selectedProduct.productUuid,
|
||||
projectId || '',
|
||||
event
|
||||
);
|
||||
})
|
||||
|
||||
if (response) {
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import * as THREE from "three";
|
||||
import { useEffect, useMemo } from "react";
|
||||
import { useFrame, useThree } from "@react-three/fiber";
|
||||
import { SkeletonUtils } from "three-stdlib";
|
||||
import { useSelectedAssets, useSocketStore, useToggleView } from "../../../../store/builder/store";
|
||||
// import { setAssetsApi } from '../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi';
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys";
|
||||
import { useParams } from "react-router-dom";
|
||||
@@ -10,6 +10,8 @@ import { getUserData } from "../../../../functions/getUserData";
|
||||
import { useSceneContext } from "../../sceneContext";
|
||||
import { useVersionContext } from "../../../builder/version/versionContext";
|
||||
|
||||
// import { setAssetsApi } from '../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi';
|
||||
|
||||
const CopyPasteControls = ({
|
||||
copiedObjects,
|
||||
setCopiedObjects,
|
||||
@@ -109,7 +111,7 @@ const CopyPasteControls = ({
|
||||
const copySelection = () => {
|
||||
if (selectedAssets.length > 0) {
|
||||
const newClones = selectedAssets.map((asset: any) => {
|
||||
const clone = asset.clone();
|
||||
const clone = SkeletonUtils.clone(asset);
|
||||
clone.position.copy(asset.position);
|
||||
return clone;
|
||||
});
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import * as THREE from "three";
|
||||
import { useEffect, useMemo } from "react";
|
||||
import { useFrame, useThree } from "@react-three/fiber";
|
||||
import { SkeletonUtils } from "three-stdlib";
|
||||
import { useSelectedAssets, useSocketStore, useToggleView } from "../../../../store/builder/store";
|
||||
// import { setAssetsApi } from '../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi';
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys";
|
||||
import { useParams } from "react-router-dom";
|
||||
@@ -10,6 +10,8 @@ import { getUserData } from "../../../../functions/getUserData";
|
||||
import { useSceneContext } from "../../sceneContext";
|
||||
import { useVersionContext } from "../../../builder/version/versionContext";
|
||||
|
||||
// import { setAssetsApi } from '../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi';
|
||||
|
||||
const DuplicationControls = ({
|
||||
duplicatedObjects,
|
||||
setDuplicatedObjects,
|
||||
@@ -104,7 +106,7 @@ const DuplicationControls = ({
|
||||
const duplicateSelection = () => {
|
||||
if (selectedAssets.length > 0 && duplicatedObjects.length === 0) {
|
||||
const newClones = selectedAssets.map((asset: any) => {
|
||||
const clone = asset.clone();
|
||||
const clone = SkeletonUtils.clone(asset);
|
||||
clone.position.copy(asset.position);
|
||||
return clone;
|
||||
});
|
||||
|
||||
@@ -17,6 +17,8 @@ import { useParams } from "react-router-dom";
|
||||
import { getUserData } from "../../../../functions/getUserData";
|
||||
import { useSceneContext } from "../../sceneContext";
|
||||
import { useVersionContext } from "../../../builder/version/versionContext";
|
||||
import { useProductContext } from "../../../simulation/products/productContext";
|
||||
import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi";
|
||||
|
||||
const SelectionControls: React.FC = () => {
|
||||
const { camera, controls, gl, scene, raycaster, pointer } = useThree();
|
||||
@@ -37,6 +39,8 @@ const SelectionControls: React.FC = () => {
|
||||
const { toolMode } = useToolMode();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { selectedProduct } = selectedProductStore();
|
||||
const { projectId } = useParams();
|
||||
|
||||
const isDragging = useRef(false);
|
||||
@@ -48,6 +52,21 @@ const SelectionControls: React.FC = () => {
|
||||
const isShiftSelecting = useRef(false);
|
||||
const { userId, organization } = getUserData();
|
||||
|
||||
const updateBackend = (
|
||||
productName: string,
|
||||
productUuid: string,
|
||||
projectId: string,
|
||||
eventData: EventsSchema
|
||||
) => {
|
||||
upsertProductOrEventApi({
|
||||
productName: productName,
|
||||
productUuid: productUuid,
|
||||
projectId: projectId,
|
||||
eventDatas: eventData,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!camera || !scene || toggleView) return;
|
||||
|
||||
@@ -284,7 +303,16 @@ const SelectionControls: React.FC = () => {
|
||||
const response = socket.emit("v1:model-asset:delete", data);
|
||||
|
||||
eventStore.getState().removeEvent(selectedMesh.uuid);
|
||||
productStore.getState().deleteEvent(selectedMesh.uuid);
|
||||
const updatedEvents = productStore.getState().deleteEvent(selectedMesh.uuid);
|
||||
|
||||
updatedEvents.forEach((event) => {
|
||||
updateBackend(
|
||||
selectedProduct.productName,
|
||||
selectedProduct.productUuid,
|
||||
projectId || '',
|
||||
event
|
||||
);
|
||||
})
|
||||
|
||||
if (response) {
|
||||
|
||||
|
||||
@@ -253,6 +253,9 @@ function HumanInstance({ human }: { human: HumanStatus }) {
|
||||
|
||||
function startUnloadingProcess() {
|
||||
const humanAsset = getAssetById(human.modelUuid);
|
||||
if (humanAsset?.animationState?.current !== 'drop') {
|
||||
setCurrentAnimation(human.modelUuid, 'drop', true, false, false);
|
||||
}
|
||||
if (humanAsset?.animationState?.current === 'drop' && humanAsset?.animationState?.isCompleted) {
|
||||
if (human.point.action.triggers.length > 0) {
|
||||
const trigger = getTriggerByUuid(selectedProduct.productUuid, human.point.action.triggers[0]?.triggerUuid);
|
||||
|
||||
@@ -4,11 +4,11 @@ import { useFrame, useThree } from '@react-three/fiber';
|
||||
import { useIsDragging, useIsRotating, useSelectedAction, useSelectedEventSphere } from '../../../../../store/simulation/useSimulationStore';
|
||||
import { useProductContext } from '../../../products/productContext';
|
||||
import { useSceneContext } from '../../../../scene/sceneContext';
|
||||
import { Group, Plane, Vector3 } from 'three';
|
||||
import { Group, Plane, Vector2, Vector3 } from 'three';
|
||||
import { useVersionContext } from '../../../../builder/version/versionContext';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import startPoint from "../../../../../assets/gltf-glb/ui/arrow_green.glb";
|
||||
import startEnd from "../../../../../assets/gltf-glb/ui/arrow_red.glb";
|
||||
import startPoint from "../../../../../assets/gltf-glb/ui/human-ui-green.glb";
|
||||
import startEnd from "../../../../../assets/gltf-glb/ui/human-ui-orange.glb";
|
||||
import { upsertProductOrEventApi } from '../../../../../services/simulation/products/UpsertProductOrEventApi';
|
||||
|
||||
function HumanUi() {
|
||||
@@ -18,7 +18,7 @@ function HumanUi() {
|
||||
const endMarker = useRef<Group>(null);
|
||||
const outerGroup = useRef<Group>(null);
|
||||
const prevMousePos = useRef({ x: 0, y: 0 });
|
||||
const { controls, raycaster } = useThree();
|
||||
const { controls, raycaster, camera } = useThree();
|
||||
const { selectedEventSphere } = useSelectedEventSphere();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { humanStore, productStore } = useSceneContext();
|
||||
@@ -27,11 +27,12 @@ function HumanUi() {
|
||||
const { updateEvent } = productStore();
|
||||
const [startPosition, setStartPosition] = useState<[number, number, number]>([0, 1, 0]);
|
||||
const [endPosition, setEndPosition] = useState<[number, number, number]>([0, 1, 0]);
|
||||
const [startRotation, setStartRotation] = useState<[number, number, number]>([0, 0, 0]);
|
||||
const [startRotation, setStartRotation] = useState<[number, number, number]>([0, Math.PI, 0]);
|
||||
const [endRotation, setEndRotation] = useState<[number, number, number]>([0, 0, 0]);
|
||||
const { isDragging, setIsDragging } = useIsDragging();
|
||||
const { isRotating, setIsRotating } = useIsRotating();
|
||||
const plane = useRef(new Plane(new Vector3(0, 1, 0), 0));
|
||||
const dragOffset = useRef(new Vector3());
|
||||
|
||||
const [selectedHumanData, setSelectedHumanData] = useState<{
|
||||
position: [number, number, number];
|
||||
@@ -74,15 +75,15 @@ function HumanUi() {
|
||||
if (action.pickUpPoint?.position && outerGroup.current) {
|
||||
const worldPos = new Vector3(...action.pickUpPoint.position);
|
||||
const localPosition = outerGroup.current.worldToLocal(worldPos.clone());
|
||||
setStartPosition([localPosition.x, 0.5, localPosition.z]);
|
||||
setStartPosition([localPosition.x, 1, localPosition.z]);
|
||||
setStartRotation(action.pickUpPoint.rotation || [0, 0, 0]);
|
||||
}
|
||||
|
||||
if (action.dropPoint?.position && outerGroup.current) {
|
||||
const worldPos = new Vector3(...action.dropPoint.position);
|
||||
const localPosition = outerGroup.current.worldToLocal(worldPos.clone());
|
||||
setEndPosition([localPosition.x, 0.5, localPosition.z]);
|
||||
setEndRotation(action.dropPoint.rotation || [0, 0, 0]);
|
||||
setEndPosition([localPosition.x, 1, localPosition.z]);
|
||||
setEndRotation(action.dropPoint.rotation || [0, Math.PI, 0]);
|
||||
}
|
||||
}, [selectedEventSphere, outerGroup.current, selectedAction, humans]);
|
||||
|
||||
@@ -91,20 +92,39 @@ function HumanUi() {
|
||||
state: "start" | "end",
|
||||
rotation: "start" | "end"
|
||||
) => {
|
||||
if (e.object.name === "handle") {
|
||||
e.stopPropagation();
|
||||
const intersection = new Vector3();
|
||||
const pointer = new Vector2((e.clientX / window.innerWidth) * 2 - 1, -(e.clientY / window.innerHeight) * 2 + 1);
|
||||
raycaster.setFromCamera(pointer, camera);
|
||||
const intersects = raycaster.ray.intersectPlane(plane.current, intersection);
|
||||
|
||||
if (e.object.parent.name === "handle") {
|
||||
const normalizedX = (e.clientX / window.innerWidth) * 2 - 1;
|
||||
const normalizedY = -(e.clientY / window.innerHeight) * 2 + 1;
|
||||
prevMousePos.current = { x: normalizedX, y: normalizedY };
|
||||
setIsRotating(rotation);
|
||||
if (controls) (controls as any).enabled = false;
|
||||
setIsDragging(null);
|
||||
} else {
|
||||
setIsDragging(state);
|
||||
setIsRotating(null);
|
||||
if (controls) (controls as any).enabled = false;
|
||||
}
|
||||
|
||||
if (intersects) {
|
||||
let localPoint: Vector3 | null = null;
|
||||
if (outerGroup.current) {
|
||||
localPoint = outerGroup.current.worldToLocal(intersection.clone());
|
||||
}
|
||||
const marker = state === "start" ? startMarker.current : endMarker.current;
|
||||
if (marker && localPoint) {
|
||||
const markerPos = new Vector3().copy(marker.position);
|
||||
dragOffset.current.copy(markerPos.sub(localPoint));
|
||||
}
|
||||
}
|
||||
|
||||
if (controls) (controls as any).enabled = false;
|
||||
};
|
||||
|
||||
|
||||
const handlePointerUp = () => {
|
||||
(controls as any).enabled = true;
|
||||
setIsDragging(null);
|
||||
@@ -159,16 +179,15 @@ function HumanUi() {
|
||||
useFrame(() => {
|
||||
if (!isDragging || !plane.current || !raycaster || !outerGroup.current) return;
|
||||
const intersectPoint = new Vector3();
|
||||
const intersects = raycaster.ray.intersectPlane(
|
||||
plane.current,
|
||||
intersectPoint
|
||||
);
|
||||
const intersects = raycaster.ray.intersectPlane(plane.current, intersectPoint);
|
||||
if (!intersects) return;
|
||||
const localPoint = outerGroup?.current.worldToLocal(intersectPoint.clone());
|
||||
|
||||
const localPoint = outerGroup.current.worldToLocal(intersectPoint.clone()).add(dragOffset.current);
|
||||
|
||||
if (isDragging === "start") {
|
||||
setStartPosition([localPoint.x, 0.5, localPoint.z]);
|
||||
setStartPosition([localPoint.x, 1, localPoint.z]);
|
||||
} else if (isDragging === "end") {
|
||||
setEndPosition([localPoint.x, 0.5, localPoint.z]);
|
||||
setEndPosition([localPoint.x, 1, localPoint.z]);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -177,7 +196,7 @@ function HumanUi() {
|
||||
const currentPointerX = state.pointer.x;
|
||||
const deltaX = currentPointerX - prevMousePos.current.x;
|
||||
prevMousePos.current.x = currentPointerX;
|
||||
const marker =isRotating === "start" ? startMarker.current : endMarker.current;
|
||||
const marker = isRotating === "start" ? startMarker.current : endMarker.current;
|
||||
if (marker) {
|
||||
const rotationSpeed = 10;
|
||||
marker.rotation.y += deltaX * rotationSpeed;
|
||||
@@ -220,6 +239,7 @@ function HumanUi() {
|
||||
<group
|
||||
position={selectedHumanData.position}
|
||||
ref={outerGroup}
|
||||
rotation={[0, Math.PI, 0]}
|
||||
>
|
||||
<primitive
|
||||
name="startMarker"
|
||||
|
||||
@@ -14,7 +14,7 @@ type ProductsStore = {
|
||||
// Event-level actions
|
||||
addEvent: (productUuid: string, event: EventsSchema) => void;
|
||||
removeEvent: (productUuid: string, modelUuid: string) => void;
|
||||
deleteEvent: (modelUuid: string) => void;
|
||||
deleteEvent: (modelUuid: string) => EventsSchema[];
|
||||
updateEvent: (productUuid: string, modelUuid: string, updates: Partial<EventsSchema>) => EventsSchema | undefined;
|
||||
|
||||
// Point-level actions
|
||||
@@ -145,11 +145,93 @@ export const createProductStore = () => {
|
||||
},
|
||||
|
||||
deleteEvent: (modelUuid) => {
|
||||
let updatedEvents: EventsSchema[] = [];
|
||||
set((state) => {
|
||||
const actionsToDelete = new Set<string>();
|
||||
|
||||
for (const product of state.products) {
|
||||
product.eventDatas = product.eventDatas.filter(e => 'modelUuid' in e && e.modelUuid !== modelUuid);
|
||||
const eventIndex = product.eventDatas.findIndex(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
||||
if (eventIndex !== -1) {
|
||||
const event = product.eventDatas[eventIndex];
|
||||
|
||||
if ('points' in event) {
|
||||
for (const point of (event as ConveyorEventSchema).points) {
|
||||
if (point.action) {
|
||||
actionsToDelete.add(point.action.actionUuid);
|
||||
}
|
||||
}
|
||||
} else if ('point' in event) {
|
||||
const point = (event as any).point;
|
||||
if ('action' in point && point.action) {
|
||||
actionsToDelete.add(point.action.actionUuid);
|
||||
} else if ('actions' in point) {
|
||||
for (const action of point.actions) {
|
||||
actionsToDelete.add(action.actionUuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
product.eventDatas.splice(eventIndex, 1);
|
||||
}
|
||||
}
|
||||
|
||||
for (const product of state.products) {
|
||||
for (const event of product.eventDatas) {
|
||||
let eventModified = false;
|
||||
|
||||
if ('points' in event) {
|
||||
for (const point of (event as ConveyorEventSchema).points) {
|
||||
if (point.action?.triggers) {
|
||||
const originalLength = point.action.triggers.length;
|
||||
point.action.triggers = point.action.triggers.filter(trigger => {
|
||||
return !(
|
||||
(trigger.triggeredAsset?.triggeredModel?.modelUuid === modelUuid) ||
|
||||
(actionsToDelete.has(trigger.triggeredAsset?.triggeredAction?.actionUuid || ''))
|
||||
);
|
||||
});
|
||||
if (point.action.triggers.length !== originalLength) {
|
||||
eventModified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if ('point' in event) {
|
||||
const point = (event as any).point;
|
||||
if ('action' in point && point.action?.triggers) {
|
||||
const originalLength = point.action.triggers.length;
|
||||
point.action.triggers = point.action.triggers.filter((trigger: TriggerSchema) => {
|
||||
return !(
|
||||
(trigger.triggeredAsset?.triggeredModel?.modelUuid === modelUuid) ||
|
||||
(actionsToDelete.has(trigger.triggeredAsset?.triggeredAction?.actionUuid || ''))
|
||||
);
|
||||
});
|
||||
if (point.action.triggers.length !== originalLength) {
|
||||
eventModified = true;
|
||||
}
|
||||
} else if ('actions' in point) {
|
||||
for (const action of point.actions) {
|
||||
if (action.triggers) {
|
||||
const originalLength = action.triggers.length;
|
||||
action.triggers = action.triggers.filter((trigger: TriggerSchema) => {
|
||||
return !(
|
||||
(trigger.triggeredAsset?.triggeredModel?.modelUuid === modelUuid) ||
|
||||
(actionsToDelete.has(trigger.triggeredAsset?.triggeredAction?.actionUuid || ''))
|
||||
);
|
||||
});
|
||||
if (action.triggers.length !== originalLength) {
|
||||
eventModified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (eventModified) {
|
||||
updatedEvents.push(JSON.parse(JSON.stringify(event)));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return updatedEvents;
|
||||
},
|
||||
|
||||
updateEvent: (productUuid, modelUuid, updates) => {
|
||||
|
||||
Reference in New Issue
Block a user