Merge remote-tracking branch 'origin/dev-simulation/human' into main-demo
This commit is contained in:
@@ -18,19 +18,22 @@ import { useVersionContext } from '../../../version/versionContext';
|
|||||||
import { SkeletonUtils } from 'three-stdlib';
|
import { SkeletonUtils } from 'three-stdlib';
|
||||||
import { useAnimationPlaySpeed } from '../../../../../store/usePlayButtonStore';
|
import { useAnimationPlaySpeed } from '../../../../../store/usePlayButtonStore';
|
||||||
import { upsertProductOrEventApi } from '../../../../../services/simulation/products/UpsertProductOrEventApi';
|
import { upsertProductOrEventApi } from '../../../../../services/simulation/products/UpsertProductOrEventApi';
|
||||||
|
import { getAssetIksApi } from '../../../../../services/simulation/ik/getAssetIKs';
|
||||||
|
|
||||||
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 { camera, controls, gl } = useThree();
|
const { camera, controls, gl } = useThree();
|
||||||
const { activeTool } = useActiveTool();
|
const { activeTool } = useActiveTool();
|
||||||
|
const { toolMode } = useToolMode();
|
||||||
const { toggleView } = useToggleView();
|
const { toggleView } = useToggleView();
|
||||||
const { subModule } = useSubModuleStore();
|
const { subModule } = useSubModuleStore();
|
||||||
const { activeModule } = useModuleStore();
|
const { activeModule } = useModuleStore();
|
||||||
const { speed } = useAnimationPlaySpeed();
|
const { speed } = useAnimationPlaySpeed();
|
||||||
const { assetStore, eventStore, productStore } = useSceneContext();
|
const { assetStore, eventStore, productStore } = useSceneContext();
|
||||||
const { removeAsset, setAnimations, resetAnimation, setAnimationComplete, setCurrentAnimation: setAnmationAnimation } = assetStore();
|
const { removeAsset, setAnimations, resetAnimation, setAnimationComplete } = assetStore();
|
||||||
const { setTop } = useTopData();
|
const { setTop } = useTopData();
|
||||||
const { setLeft } = useLeftData();
|
const { setLeft } = useLeftData();
|
||||||
const { getIsEventInProduct } = productStore();
|
const { getIsEventInProduct, addPoint } = productStore();
|
||||||
const { getEventByModelUuid } = eventStore();
|
const { getEventByModelUuid } = eventStore();
|
||||||
const { selectedProductStore } = useProductContext();
|
const { selectedProductStore } = useProductContext();
|
||||||
const { selectedProduct } = selectedProductStore();
|
const { selectedProduct } = selectedProductStore();
|
||||||
@@ -40,21 +43,24 @@ function Model({ asset }: { readonly asset: Asset }) {
|
|||||||
const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem();
|
const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem();
|
||||||
const { limitDistance } = useLimitDistance();
|
const { limitDistance } = useLimitDistance();
|
||||||
const { renderDistance } = useRenderDistance();
|
const { renderDistance } = useRenderDistance();
|
||||||
|
const leftDrag = useRef(false);
|
||||||
|
const isLeftMouseDown = useRef(false);
|
||||||
|
const rightDrag = useRef(false);
|
||||||
|
const isRightMouseDown = useRef(false);
|
||||||
const [isRendered, setIsRendered] = useState(false);
|
const [isRendered, setIsRendered] = useState(false);
|
||||||
const url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
|
||||||
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 groupRef = useRef<THREE.Group>(null);
|
const groupRef = useRef<THREE.Group>(null);
|
||||||
const { toolMode } = useToolMode();
|
|
||||||
const { selectedVersionStore } = useVersionContext();
|
|
||||||
const { selectedVersion } = selectedVersionStore();
|
|
||||||
const { projectId } = useParams();
|
|
||||||
const { userId, organization } = getUserData();
|
|
||||||
const mixerRef = useRef<THREE.AnimationMixer>();
|
const mixerRef = useRef<THREE.AnimationMixer>();
|
||||||
const actions = useRef<{ [name: string]: THREE.AnimationAction }>({});
|
const actions = useRef<{ [name: string]: THREE.AnimationAction }>({});
|
||||||
const [previousAnimation, setPreviousAnimation] = useState<string | null>(null);
|
const [previousAnimation, setPreviousAnimation] = useState<string | null>(null);
|
||||||
|
const [ikData, setIkData] = useState<any>();
|
||||||
const blendFactor = useRef(0);
|
const blendFactor = useRef(0);
|
||||||
const blendDuration = 0.5;
|
const blendDuration = 0.5;
|
||||||
|
const { selectedVersionStore } = useVersionContext();
|
||||||
|
const { selectedVersion } = selectedVersionStore();
|
||||||
|
const { userId, organization } = getUserData();
|
||||||
|
const { projectId } = useParams();
|
||||||
|
|
||||||
const updateBackend = (
|
const updateBackend = (
|
||||||
productName: string,
|
productName: string,
|
||||||
@@ -71,6 +77,16 @@ function Model({ asset }: { readonly asset: Asset }) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!ikData && asset.eventData && asset.eventData.type === 'ArmBot') {
|
||||||
|
getAssetIksApi(asset.assetId).then((data) => {
|
||||||
|
if (data.iks) {
|
||||||
|
setIkData(data.iks);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, [asset.modelUuid, ikData])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setDeletableFloorItem(null);
|
setDeletableFloorItem(null);
|
||||||
if (selectedFloorItem === null || selectedFloorItem.userData.modelUuid !== asset.modelUuid) {
|
if (selectedFloorItem === null || selectedFloorItem.userData.modelUuid !== asset.modelUuid) {
|
||||||
@@ -217,7 +233,8 @@ function Model({ asset }: { readonly asset: Asset }) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleClick = (asset: Asset) => {
|
const handleClick = (evt: ThreeEvent<MouseEvent>, asset: Asset) => {
|
||||||
|
if (leftDrag.current || toggleView) return;
|
||||||
if (activeTool === 'delete' && deletableFloorItem && deletableFloorItem.uuid === asset.modelUuid) {
|
if (activeTool === 'delete' && deletableFloorItem && deletableFloorItem.uuid === asset.modelUuid) {
|
||||||
|
|
||||||
//REST
|
//REST
|
||||||
@@ -257,6 +274,40 @@ function Model({ asset }: { readonly asset: Asset }) {
|
|||||||
echo.success("Model Removed!");
|
echo.success("Model Removed!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else if (activeModule === 'simulation' && subModule === "simulations" && activeTool === 'pen') {
|
||||||
|
if (asset.eventData && asset.eventData.type === 'Conveyor') {
|
||||||
|
const intersectedPoint = evt.point;
|
||||||
|
const localPosition = groupRef.current?.worldToLocal(intersectedPoint.clone());
|
||||||
|
if (localPosition) {
|
||||||
|
const conveyorPoint: ConveyorPointSchema = {
|
||||||
|
uuid: THREE.MathUtils.generateUUID(),
|
||||||
|
position: [localPosition?.x, localPosition?.y, localPosition?.z],
|
||||||
|
rotation: [0, 0, 0],
|
||||||
|
action: {
|
||||||
|
actionUuid: THREE.MathUtils.generateUUID(),
|
||||||
|
actionName: `Action 1`,
|
||||||
|
actionType: 'default',
|
||||||
|
material: 'Default Material',
|
||||||
|
delay: 0,
|
||||||
|
spawnInterval: 5,
|
||||||
|
spawnCount: 1,
|
||||||
|
triggers: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const event = addPoint(selectedProduct.productUuid, asset.modelUuid, conveyorPoint);
|
||||||
|
|
||||||
|
if (event) {
|
||||||
|
updateBackend(
|
||||||
|
selectedProduct.productName,
|
||||||
|
selectedProduct.productUuid,
|
||||||
|
projectId || '',
|
||||||
|
event
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,13 +321,14 @@ function Model({ asset }: { readonly asset: Asset }) {
|
|||||||
}
|
}
|
||||||
}, [activeTool, activeModule, deletableFloorItem]);
|
}, [activeTool, activeModule, deletableFloorItem]);
|
||||||
|
|
||||||
const handlePointerOut = useCallback((asset: Asset) => {
|
const handlePointerOut = useCallback((evt: ThreeEvent<MouseEvent>, asset: Asset) => {
|
||||||
if (activeTool === "delete" && deletableFloorItem && deletableFloorItem.uuid === asset.modelUuid) {
|
if (evt.intersections.length === 0 && activeTool === "delete" && deletableFloorItem && deletableFloorItem.uuid === asset.modelUuid) {
|
||||||
setDeletableFloorItem(null);
|
setDeletableFloorItem(null);
|
||||||
}
|
}
|
||||||
}, [activeTool, deletableFloorItem]);
|
}, [activeTool, deletableFloorItem]);
|
||||||
|
|
||||||
const handleContextMenu = (asset: Asset, evt: ThreeEvent<MouseEvent>) => {
|
const handleContextMenu = (asset: Asset, evt: ThreeEvent<MouseEvent>) => {
|
||||||
|
if (rightDrag.current || toggleView) return;
|
||||||
if (activeTool === "cursor" && subModule === 'simulations') {
|
if (activeTool === "cursor" && subModule === 'simulations') {
|
||||||
if (asset.modelUuid) {
|
if (asset.modelUuid) {
|
||||||
const canvasElement = gl.domElement;
|
const canvasElement = gl.domElement;
|
||||||
@@ -358,6 +410,50 @@ function Model({ asset }: { readonly asset: Asset }) {
|
|||||||
};
|
};
|
||||||
}, [asset.animationState?.current, asset.animationState?.isPlaying]);
|
}, [asset.animationState?.current, asset.animationState?.isPlaying]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const canvasElement = gl.domElement;
|
||||||
|
|
||||||
|
const onPointerDown = (evt: any) => {
|
||||||
|
if (evt.button === 0) {
|
||||||
|
isLeftMouseDown.current = true;
|
||||||
|
leftDrag.current = false;
|
||||||
|
}
|
||||||
|
if (evt.button === 2) {
|
||||||
|
isRightMouseDown.current = true;
|
||||||
|
rightDrag.current = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onPointerMove = () => {
|
||||||
|
if (isLeftMouseDown.current) {
|
||||||
|
leftDrag.current = true;
|
||||||
|
}
|
||||||
|
if (isRightMouseDown.current) {
|
||||||
|
rightDrag.current = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onPointerUp = (evt: any) => {
|
||||||
|
if (evt.button === 0) {
|
||||||
|
isLeftMouseDown.current = false;
|
||||||
|
}
|
||||||
|
if (evt.button === 2) {
|
||||||
|
isRightMouseDown.current = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
canvasElement.addEventListener('pointerdown', onPointerDown);
|
||||||
|
canvasElement.addEventListener('pointermove', onPointerMove);
|
||||||
|
canvasElement.addEventListener('pointerup', onPointerUp);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
canvasElement.removeEventListener('pointerdown', onPointerDown);
|
||||||
|
canvasElement.removeEventListener('pointermove', onPointerMove);
|
||||||
|
canvasElement.removeEventListener('pointerup', onPointerUp);
|
||||||
|
}
|
||||||
|
|
||||||
|
}, [gl])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<group
|
<group
|
||||||
key={asset.modelUuid}
|
key={asset.modelUuid}
|
||||||
@@ -369,27 +465,27 @@ function Model({ asset }: { readonly asset: Asset }) {
|
|||||||
visible={asset.isVisible}
|
visible={asset.isVisible}
|
||||||
userData={asset}
|
userData={asset}
|
||||||
onDoubleClick={(e) => {
|
onDoubleClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
if (!toggleView) {
|
if (!toggleView) {
|
||||||
e.stopPropagation();
|
|
||||||
handleDblClick(asset);
|
handleDblClick(asset);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
if (!toggleView) {
|
if (!toggleView) {
|
||||||
e.stopPropagation();
|
handleClick(e, asset);
|
||||||
handleClick(asset);
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onPointerEnter={(e) => {
|
onPointerOver={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
if (!toggleView) {
|
if (!toggleView) {
|
||||||
e.stopPropagation();
|
|
||||||
handlePointerOver(asset);
|
handlePointerOver(asset);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onPointerOut={(e) => {
|
onPointerLeave={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
if (!toggleView) {
|
if (!toggleView) {
|
||||||
e.stopPropagation();
|
handlePointerOut(e, asset);
|
||||||
handlePointerOut(asset);
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onContextMenu={(e) => {
|
onContextMenu={(e) => {
|
||||||
@@ -404,7 +500,7 @@ function Model({ asset }: { readonly asset: Asset }) {
|
|||||||
<AssetBoundingBox boundingBox={boundingBox} />
|
<AssetBoundingBox boundingBox={boundingBox} />
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
</group >
|
</group>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as THREE from 'three';
|
import * as THREE from 'three';
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { useThree } from '@react-three/fiber';
|
import { ThreeEvent, useThree } from '@react-three/fiber';
|
||||||
import { Base, Geometry, Subtraction } from '@react-three/csg';
|
import { Base, Geometry, Subtraction } from '@react-three/csg';
|
||||||
import { retrieveGLTF, storeGLTF } from '../../../../../utils/indexDB/idbUtils';
|
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';
|
||||||
@@ -14,8 +14,8 @@ import { useVersionContext } from '../../../version/versionContext';
|
|||||||
import { getUserData } from '../../../../../functions/getUserData';
|
import { getUserData } from '../../../../../functions/getUserData';
|
||||||
import closestPointOnLineSegment from '../../../line/helpers/getClosestPointOnLineSegment';
|
import closestPointOnLineSegment from '../../../line/helpers/getClosestPointOnLineSegment';
|
||||||
|
|
||||||
import { upsertWallAssetApi } from '../../../../../services/factoryBuilder/asset/wallAsset/upsertWallAssetApi';
|
// import { upsertWallAssetApi } from '../../../../../services/factoryBuilder/asset/wallAsset/upsertWallAssetApi';
|
||||||
import { deleteWallAssetApi } from '../../../../../services/factoryBuilder/asset/wallAsset/deleteWallAssetApi';
|
// import { deleteWallAssetApi } from '../../../../../services/factoryBuilder/asset/wallAsset/deleteWallAssetApi';
|
||||||
|
|
||||||
function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) {
|
function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) {
|
||||||
const url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
const url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||||
@@ -219,8 +219,8 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) {
|
|||||||
}
|
}
|
||||||
}, [activeTool, activeModule, deletableWallAsset]);
|
}, [activeTool, activeModule, deletableWallAsset]);
|
||||||
|
|
||||||
const handlePointerOut = useCallback((wallAsset: WallAsset) => {
|
const handlePointerOut = useCallback((evt: ThreeEvent<MouseEvent>, wallAsset: WallAsset) => {
|
||||||
if (activeTool === "delete" && deletableWallAsset && deletableWallAsset.userData.modelUuid === wallAsset.modelUuid) {
|
if (evt.intersections.length === 0 && activeTool === "delete" && deletableWallAsset && deletableWallAsset.userData.modelUuid === wallAsset.modelUuid) {
|
||||||
setDeletableWallAsset(null);
|
setDeletableWallAsset(null);
|
||||||
}
|
}
|
||||||
}, [activeTool, deletableWallAsset]);
|
}, [activeTool, deletableWallAsset]);
|
||||||
@@ -281,7 +281,7 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) {
|
|||||||
setSelectedWallAsset(null);
|
setSelectedWallAsset(null);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onPointerEnter={(e) => {
|
onPointerOver={(e) => {
|
||||||
if (!toggleView) {
|
if (!toggleView) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
let currentObject = e.object as THREE.Object3D;
|
let currentObject = e.object as THREE.Object3D;
|
||||||
@@ -294,10 +294,10 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) {
|
|||||||
handlePointerOver(wallAsset, currentObject);
|
handlePointerOver(wallAsset, currentObject);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onPointerOut={(e) => {
|
onPointerLeave={(e) => {
|
||||||
if (!toggleView) {
|
if (!toggleView) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
handlePointerOut(wallAsset);
|
handlePointerOut(e, wallAsset);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
userData={wallAsset}
|
userData={wallAsset}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {
|
|||||||
useSelectedFloorItem,
|
useSelectedFloorItem,
|
||||||
} from "../../../store/builder/store";
|
} from "../../../store/builder/store";
|
||||||
import * as CONSTANTS from "../../../types/world/worldConstants";
|
import * as CONSTANTS from "../../../types/world/worldConstants";
|
||||||
import { useSelectedEventSphere } from "../../../store/simulation/useSimulationStore";
|
import { useDeletableEventSphere, useSelectedEventSphere } from "../../../store/simulation/useSimulationStore";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { useBuilderStore } from "../../../store/builder/useBuilderStore";
|
import { useBuilderStore } from "../../../store/builder/useBuilderStore";
|
||||||
|
|
||||||
@@ -15,6 +15,7 @@ export default function PostProcessing() {
|
|||||||
const { selectedWallItem } = useSelectedWallItem();
|
const { selectedWallItem } = useSelectedWallItem();
|
||||||
const { selectedFloorItem } = useSelectedFloorItem();
|
const { selectedFloorItem } = useSelectedFloorItem();
|
||||||
const { selectedEventSphere } = useSelectedEventSphere();
|
const { selectedEventSphere } = useSelectedEventSphere();
|
||||||
|
const { deletableEventSphere } = useDeletableEventSphere();
|
||||||
const { selectedAisle, selectedWall, selectedDecal, selectedFloor, selectedWallAsset, deletableWallAsset } = useBuilderStore();
|
const { selectedAisle, selectedWall, selectedDecal, selectedFloor, selectedWallAsset, deletableWallAsset } = useBuilderStore();
|
||||||
|
|
||||||
function flattenChildren(children: any[]) {
|
function flattenChildren(children: any[]) {
|
||||||
@@ -56,6 +57,10 @@ export default function PostProcessing() {
|
|||||||
// console.log('deletableWallAsset: ', deletableWallAsset);
|
// console.log('deletableWallAsset: ', deletableWallAsset);
|
||||||
}, [deletableWallAsset])
|
}, [deletableWallAsset])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// console.log('deletableEventSphere: ', deletableEventSphere);
|
||||||
|
}, [deletableEventSphere])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<EffectComposer autoClear={false}>
|
<EffectComposer autoClear={false}>
|
||||||
<N8AO
|
<N8AO
|
||||||
@@ -217,6 +222,21 @@ export default function PostProcessing() {
|
|||||||
xRay={true}
|
xRay={true}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{deletableEventSphere && (
|
||||||
|
<Outline
|
||||||
|
selection={[deletableEventSphere]}
|
||||||
|
selectionLayer={10}
|
||||||
|
width={1000}
|
||||||
|
blendFunction={BlendFunction.ALPHA}
|
||||||
|
edgeStrength={10}
|
||||||
|
resolutionScale={2}
|
||||||
|
pulseSpeed={0}
|
||||||
|
visibleEdgeColor={CONSTANTS.outlineConfig.assetDeleteColor}
|
||||||
|
hiddenEdgeColor={CONSTANTS.outlineConfig.assetDeleteColor}
|
||||||
|
blur={true}
|
||||||
|
xRay={true}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</EffectComposer>
|
</EffectComposer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,11 +16,11 @@ interface ConnectionLine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function Arrows({ connections }: { readonly connections: ConnectionLine[] }) {
|
export function Arrows({ connections }: { readonly connections: ConnectionLine[] }) {
|
||||||
const [hoveredLineKey, setHoveredLineKey] = useState<string | null>(null);
|
const [hoveredArrowTrigger, setHoveredArrowTrigger] = useState<string | null>(null);
|
||||||
const groupRef = useRef<THREE.Group>(null);
|
const groupRef = useRef<THREE.Group>(null);
|
||||||
const { scene } = useThree();
|
const { scene } = useThree();
|
||||||
const { toolMode } = useToolMode();
|
const { toolMode } = useToolMode();
|
||||||
const { eventStore, productStore } = useSceneContext();
|
const { productStore } = useSceneContext();
|
||||||
const { removeTrigger } = productStore();
|
const { removeTrigger } = productStore();
|
||||||
const { selectedVersionStore } = useVersionContext();
|
const { selectedVersionStore } = useVersionContext();
|
||||||
const { selectedVersion } = selectedVersionStore();
|
const { selectedVersion } = selectedVersionStore();
|
||||||
@@ -103,15 +103,15 @@ export function Arrows({ connections }: { readonly connections: ConnectionLine[]
|
|||||||
return (
|
return (
|
||||||
<group
|
<group
|
||||||
key={key}
|
key={key}
|
||||||
onPointerOver={() => setHoveredLineKey(trigger.triggerUuid)}
|
onPointerOver={() => setHoveredArrowTrigger(trigger.triggerUuid)}
|
||||||
onPointerOut={() => setHoveredLineKey(null)}
|
onPointerOut={() => setHoveredArrowTrigger(null)}
|
||||||
onClick={() => { removeConnection(trigger) }}
|
onClick={() => { removeConnection(trigger) }}
|
||||||
>
|
>
|
||||||
<mesh
|
<mesh
|
||||||
geometry={shaftGeometry}
|
geometry={shaftGeometry}
|
||||||
>
|
>
|
||||||
<meshStandardMaterial
|
<meshStandardMaterial
|
||||||
color={toolMode === '3D-Delete' && hoveredLineKey === trigger.triggerUuid ? "red" : "#42a5f5"}
|
color={toolMode === '3D-Delete' && hoveredArrowTrigger === trigger.triggerUuid ? "red" : "#42a5f5"}
|
||||||
/>
|
/>
|
||||||
</mesh>
|
</mesh>
|
||||||
<mesh
|
<mesh
|
||||||
@@ -120,7 +120,7 @@ export function Arrows({ connections }: { readonly connections: ConnectionLine[]
|
|||||||
geometry={headGeometry}
|
geometry={headGeometry}
|
||||||
>
|
>
|
||||||
<meshStandardMaterial
|
<meshStandardMaterial
|
||||||
color={toolMode === '3D-Delete' && hoveredLineKey === trigger.triggerUuid ? "red" : "#42a5f5"}
|
color={toolMode === '3D-Delete' && hoveredArrowTrigger === trigger.triggerUuid ? "red" : "#42a5f5"}
|
||||||
/>
|
/>
|
||||||
</mesh>
|
</mesh>
|
||||||
</group>
|
</group>
|
||||||
|
|||||||
@@ -1,38 +1,46 @@
|
|||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import * as THREE from "three";
|
import * as THREE from "three";
|
||||||
import useModuleStore, { useSubModuleStore } from "../../../../../store/useModuleStore";
|
import useModuleStore, { useSubModuleStore } from "../../../../../store/useModuleStore";
|
||||||
|
import { useToolMode } from "../../../../../store/builder/store";
|
||||||
import { TransformControls } from "@react-three/drei";
|
import { TransformControls } from "@react-three/drei";
|
||||||
import { detectModifierKeys } from "../../../../../utils/shortcutkeys/detectModifierKeys";
|
import { detectModifierKeys } from "../../../../../utils/shortcutkeys/detectModifierKeys";
|
||||||
import { useSelectedEventSphere, useSelectedEventData, } from "../../../../../store/simulation/useSimulationStore";
|
import { useSelectedEventSphere, useSelectedEventData, useDeletableEventSphere } from "../../../../../store/simulation/useSimulationStore";
|
||||||
import { useThree } from "@react-three/fiber";
|
import { useThree } from "@react-three/fiber";
|
||||||
import { usePlayButtonStore } from "../../../../../store/usePlayButtonStore";
|
import { usePlayButtonStore } from "../../../../../store/usePlayButtonStore";
|
||||||
import { upsertProductOrEventApi } from "../../../../../services/simulation/products/UpsertProductOrEventApi";
|
import { upsertProductOrEventApi } from "../../../../../services/simulation/products/UpsertProductOrEventApi";
|
||||||
import { useProductContext } from "../../../products/productContext";
|
import { useProductContext } from "../../../products/productContext";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import { useToolMode } from "../../../../../store/builder/store";
|
|
||||||
import { useVersionContext } from "../../../../builder/version/versionContext";
|
import { useVersionContext } from "../../../../builder/version/versionContext";
|
||||||
import { useSceneContext } from "../../../../scene/sceneContext";
|
import { useSceneContext } from "../../../../scene/sceneContext";
|
||||||
|
|
||||||
|
import PointInstances from "../instances/pointInstances";
|
||||||
|
|
||||||
function PointsCreator() {
|
function PointsCreator() {
|
||||||
const { gl, raycaster, scene, pointer, camera } = useThree();
|
const { gl, raycaster, scene, pointer, camera } = useThree();
|
||||||
const { subModule } = useSubModuleStore();
|
const { subModule } = useSubModuleStore();
|
||||||
|
const { toolMode } = useToolMode();
|
||||||
|
const { activeModule } = useModuleStore();
|
||||||
const { selectedProductStore } = useProductContext();
|
const { selectedProductStore } = useProductContext();
|
||||||
const { eventStore, productStore } = useSceneContext();
|
const { eventStore, productStore } = useSceneContext();
|
||||||
const { events, updatePoint, getPointByUuid, getEventByModelUuid } = eventStore();
|
const { getEventByModelUuid } = eventStore();
|
||||||
const { getEventByModelUuid: getEventByModelUuidFromProduct, updatePoint: updatePointFromProduct, getEventByModelUuid: getEventByModelUuidFromProduct2, getPointByUuid: getPointByUuidFromProduct } = productStore();
|
const { getEventByModelUuid: getEventByModelUuidFromProduct, updatePoint: updatePointFromProduct, getPointByUuid: getPointByUuidFromProduct, getTriggersByTriggeredPointUuid, removeTrigger, removePoint } = productStore();
|
||||||
const { selectedProduct } = selectedProductStore();
|
const { selectedProduct } = selectedProductStore();
|
||||||
const { activeModule } = useModuleStore();
|
|
||||||
const transformRef = useRef<any>(null);
|
const transformRef = useRef<any>(null);
|
||||||
const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null);
|
const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null);
|
||||||
const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({});
|
const { selectedEventSphere, clearSelectedEventSphere, } = useSelectedEventSphere();
|
||||||
const { selectedEventSphere, setSelectedEventSphere, clearSelectedEventSphere, } = useSelectedEventSphere();
|
const { clearDeletableEventSphere } = useDeletableEventSphere();
|
||||||
const { setSelectedEventData, clearSelectedEventData } = useSelectedEventData();
|
const { setSelectedEventData, clearSelectedEventData } = useSelectedEventData();
|
||||||
const { isPlaying } = usePlayButtonStore();
|
const { isPlaying } = usePlayButtonStore();
|
||||||
const { toolMode } = useToolMode();
|
|
||||||
const { selectedVersionStore } = useVersionContext();
|
const { selectedVersionStore } = useVersionContext();
|
||||||
const { selectedVersion } = selectedVersionStore();
|
const { selectedVersion } = selectedVersionStore();
|
||||||
const { projectId } = useParams();
|
const { projectId } = useParams();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
clearSelectedEventSphere();
|
||||||
|
clearSelectedEventData();
|
||||||
|
clearDeletableEventSphere();
|
||||||
|
}, [toolMode, activeModule])
|
||||||
|
|
||||||
const updateBackend = (
|
const updateBackend = (
|
||||||
productName: string,
|
productName: string,
|
||||||
productUuid: string,
|
productUuid: string,
|
||||||
@@ -75,65 +83,87 @@ function PointsCreator() {
|
|||||||
if (keyCombination === "R") {
|
if (keyCombination === "R") {
|
||||||
setTransformMode((prev) => (prev === "rotate" ? null : "rotate"));
|
setTransformMode((prev) => (prev === "rotate" ? null : "rotate"));
|
||||||
}
|
}
|
||||||
|
if (keyCombination === 'DELETE') {
|
||||||
|
deletePointfromConveyor(selectedEventSphere);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
window.addEventListener("keydown", handleKeyDown);
|
window.addEventListener("keydown", handleKeyDown);
|
||||||
return () => window.removeEventListener("keydown", handleKeyDown);
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
||||||
}, [selectedEventSphere]);
|
}, [selectedEventSphere]);
|
||||||
|
|
||||||
const updatePointToState = (selectedEventSphere: THREE.Mesh) => {
|
const deletePointfromConveyor = (selectedEventSphere: THREE.Mesh) => {
|
||||||
let point: PointsScheme = JSON.parse(
|
const eventModel = getEventByModelUuidFromProduct(selectedProduct.productUuid, selectedEventSphere.userData.modelUuid);
|
||||||
JSON.stringify(
|
if (!eventModel || eventModel.type !== 'transfer' || eventModel.points.length < 2) return;
|
||||||
getPointByUuid(
|
|
||||||
selectedEventSphere.userData.modelUuid,
|
|
||||||
selectedEventSphere.userData.pointUuid
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
if (point) {
|
|
||||||
point.position = [
|
|
||||||
selectedEventSphere.position.x,
|
|
||||||
selectedEventSphere.position.y,
|
|
||||||
selectedEventSphere.position.z,
|
|
||||||
];
|
|
||||||
point.rotation = [
|
|
||||||
selectedEventSphere.rotation.x,
|
|
||||||
selectedEventSphere.rotation.y,
|
|
||||||
selectedEventSphere.rotation.z,
|
|
||||||
];
|
|
||||||
|
|
||||||
const event = getEventByModelUuidFromProduct(selectedProduct.productUuid, selectedEventSphere.userData.modelUuid);
|
const triggers = getTriggersByTriggeredPointUuid(selectedProduct.productUuid, selectedEventSphere.userData.pointUuid);
|
||||||
|
|
||||||
if (event && selectedProduct.productUuid !== '') {
|
const updatedEvents: EventsSchema[] = [];
|
||||||
|
if (triggers.length > 0) {
|
||||||
|
triggers.map((trigger) => {
|
||||||
|
const event = removeTrigger(selectedProduct.productUuid, trigger.triggerUuid);
|
||||||
|
if (event) {
|
||||||
|
updatedEvents.push(event);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const updatedPoint = JSON.parse(
|
const event = removePoint(selectedProduct.productUuid, selectedEventSphere.userData.modelUuid, selectedEventSphere.userData.pointUuid)
|
||||||
JSON.stringify(
|
|
||||||
getPointByUuidFromProduct(selectedProduct.productUuid, selectedEventSphere.userData.modelUuid, selectedEventSphere.userData.pointUuid)
|
if (event) {
|
||||||
)
|
updatedEvents.push(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updatedEvents.length > 0) {
|
||||||
|
updatedEvents.map((updatedEvent) => {
|
||||||
|
updateBackend(
|
||||||
|
selectedProduct.productName,
|
||||||
|
selectedProduct.productUuid,
|
||||||
|
projectId || '',
|
||||||
|
updatedEvent
|
||||||
);
|
);
|
||||||
if (updatedPoint) {
|
})
|
||||||
updatedPoint.position = point.position;
|
}
|
||||||
updatedPoint.rotation = point.rotation;
|
}
|
||||||
|
|
||||||
const updatedEvent = updatePointFromProduct(
|
const updatePointToState = (selectedEventSphere: THREE.Mesh) => {
|
||||||
|
const position = [
|
||||||
|
selectedEventSphere.position.x,
|
||||||
|
selectedEventSphere.position.y,
|
||||||
|
selectedEventSphere.position.z,
|
||||||
|
];
|
||||||
|
const rotation = [
|
||||||
|
selectedEventSphere.rotation.x,
|
||||||
|
selectedEventSphere.rotation.y,
|
||||||
|
selectedEventSphere.rotation.z,
|
||||||
|
];
|
||||||
|
|
||||||
|
const event = getEventByModelUuidFromProduct(selectedProduct.productUuid, selectedEventSphere.userData.modelUuid);
|
||||||
|
|
||||||
|
if (event && selectedProduct.productUuid !== '') {
|
||||||
|
|
||||||
|
const updatedPoint = JSON.parse(
|
||||||
|
JSON.stringify(
|
||||||
|
getPointByUuidFromProduct(selectedProduct.productUuid, selectedEventSphere.userData.modelUuid, selectedEventSphere.userData.pointUuid)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
if (updatedPoint) {
|
||||||
|
updatedPoint.position = position;
|
||||||
|
updatedPoint.rotation = rotation;
|
||||||
|
|
||||||
|
const updatedEvent = updatePointFromProduct(
|
||||||
|
selectedProduct.productUuid,
|
||||||
|
selectedEventSphere.userData.modelUuid,
|
||||||
|
selectedEventSphere.userData.pointUuid,
|
||||||
|
updatedPoint
|
||||||
|
)
|
||||||
|
if (updatedEvent) {
|
||||||
|
updateBackend(
|
||||||
|
selectedProduct.productName,
|
||||||
selectedProduct.productUuid,
|
selectedProduct.productUuid,
|
||||||
selectedEventSphere.userData.modelUuid,
|
projectId || '',
|
||||||
selectedEventSphere.userData.pointUuid,
|
updatedEvent
|
||||||
updatedPoint
|
);
|
||||||
)
|
|
||||||
if (updatedEvent) {
|
|
||||||
updatePoint(
|
|
||||||
selectedEventSphere.userData.modelUuid,
|
|
||||||
selectedEventSphere.userData.pointUuid,
|
|
||||||
point
|
|
||||||
)
|
|
||||||
updateBackend(
|
|
||||||
selectedProduct.productName,
|
|
||||||
selectedProduct.productUuid,
|
|
||||||
projectId || '',
|
|
||||||
updatedEvent
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -153,9 +183,7 @@ function PointsCreator() {
|
|||||||
const onMouseUp = () => {
|
const onMouseUp = () => {
|
||||||
if (selectedEventSphere && !drag) {
|
if (selectedEventSphere && !drag) {
|
||||||
raycaster.setFromCamera(pointer, camera);
|
raycaster.setFromCamera(pointer, camera);
|
||||||
const intersects = raycaster
|
const intersects = raycaster.intersectObjects(scene.children, true).filter((intersect) => intersect.object.name === "Event-Sphere");
|
||||||
.intersectObjects(scene.children, true)
|
|
||||||
.filter((intersect) => intersect.object.name === "Event-Sphere");
|
|
||||||
if (intersects.length === 0) {
|
if (intersects.length === 0) {
|
||||||
clearSelectedEventSphere();
|
clearSelectedEventSphere();
|
||||||
setTransformMode(null);
|
setTransformMode(null);
|
||||||
@@ -188,205 +216,7 @@ function PointsCreator() {
|
|||||||
{activeModule === "simulation" && (
|
{activeModule === "simulation" && (
|
||||||
<>
|
<>
|
||||||
<group name="EventPointsGroup" visible={!isPlaying}>
|
<group name="EventPointsGroup" visible={!isPlaying}>
|
||||||
{events.map((event, index) => {
|
<PointInstances />
|
||||||
const updatedEvent = selectedProduct.productUuid !== ''
|
|
||||||
? getEventByModelUuidFromProduct2(selectedProduct.productUuid, event.modelUuid)
|
|
||||||
: null;
|
|
||||||
|
|
||||||
const usedEvent = updatedEvent || event;
|
|
||||||
|
|
||||||
if (usedEvent.type === "transfer") {
|
|
||||||
return (
|
|
||||||
<group
|
|
||||||
key={`${index}-${usedEvent.modelUuid}`}
|
|
||||||
position={usedEvent.position}
|
|
||||||
rotation={usedEvent.rotation}
|
|
||||||
>
|
|
||||||
{usedEvent.points.map((point, j) => (
|
|
||||||
<mesh
|
|
||||||
name="Event-Sphere"
|
|
||||||
uuid={point.uuid}
|
|
||||||
ref={(el) => (sphereRefs.current[point.uuid] = el!)}
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
if (toolMode === 'cursor') {
|
|
||||||
setSelectedEventSphere(
|
|
||||||
sphereRefs.current[point.uuid]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
key={`${index}-${point.uuid}`}
|
|
||||||
position={new THREE.Vector3(...point.position)}
|
|
||||||
userData={{
|
|
||||||
modelUuid: usedEvent.modelUuid,
|
|
||||||
pointUuid: point.uuid,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<sphereGeometry args={[0.1, 16, 16]} />
|
|
||||||
<meshStandardMaterial color="orange" />
|
|
||||||
</mesh>
|
|
||||||
))}
|
|
||||||
</group>
|
|
||||||
);
|
|
||||||
} else if (usedEvent.type === "vehicle") {
|
|
||||||
const point = usedEvent.point;
|
|
||||||
return (
|
|
||||||
<group
|
|
||||||
key={`${index}-${usedEvent.modelUuid}`}
|
|
||||||
position={usedEvent.position}
|
|
||||||
rotation={usedEvent.rotation}
|
|
||||||
>
|
|
||||||
<mesh
|
|
||||||
name="Event-Sphere"
|
|
||||||
uuid={point.uuid}
|
|
||||||
ref={(el) => (sphereRefs.current[point.uuid] = el!)}
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
if (toolMode === 'cursor') {
|
|
||||||
setSelectedEventSphere(
|
|
||||||
sphereRefs.current[point.uuid]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
position={new THREE.Vector3(...point.position)}
|
|
||||||
userData={{
|
|
||||||
modelUuid: usedEvent.modelUuid,
|
|
||||||
pointUuid: point.uuid,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<sphereGeometry args={[0.1, 16, 16]} />
|
|
||||||
<meshStandardMaterial color="blue" />
|
|
||||||
</mesh>
|
|
||||||
</group>
|
|
||||||
);
|
|
||||||
} else if (usedEvent.type === "roboticArm") {
|
|
||||||
const point = usedEvent.point;
|
|
||||||
return (
|
|
||||||
<group
|
|
||||||
key={`${index}-${usedEvent.modelUuid}`}
|
|
||||||
position={usedEvent.position}
|
|
||||||
rotation={usedEvent.rotation}
|
|
||||||
>
|
|
||||||
<mesh
|
|
||||||
name="Event-Sphere"
|
|
||||||
uuid={point.uuid}
|
|
||||||
ref={(el) => (sphereRefs.current[point.uuid] = el!)}
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
if (toolMode === 'cursor') {
|
|
||||||
setSelectedEventSphere(
|
|
||||||
sphereRefs.current[point.uuid]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
position={new THREE.Vector3(...point.position)}
|
|
||||||
userData={{
|
|
||||||
modelUuid: usedEvent.modelUuid,
|
|
||||||
pointUuid: point.uuid,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<sphereGeometry args={[0.1, 16, 16]} />
|
|
||||||
<meshStandardMaterial color="green" />
|
|
||||||
</mesh>
|
|
||||||
</group>
|
|
||||||
);
|
|
||||||
} else if (usedEvent.type === "machine") {
|
|
||||||
const point = usedEvent.point;
|
|
||||||
return (
|
|
||||||
<group
|
|
||||||
key={`${index}-${usedEvent.modelUuid}`}
|
|
||||||
position={usedEvent.position}
|
|
||||||
rotation={usedEvent.rotation}
|
|
||||||
>
|
|
||||||
<mesh
|
|
||||||
name="Event-Sphere"
|
|
||||||
uuid={point.uuid}
|
|
||||||
ref={(el) => (sphereRefs.current[point.uuid] = el!)}
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
if (toolMode === 'cursor') {
|
|
||||||
setSelectedEventSphere(
|
|
||||||
sphereRefs.current[point.uuid]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
position={new THREE.Vector3(...point.position)}
|
|
||||||
userData={{
|
|
||||||
modelUuid: usedEvent.modelUuid,
|
|
||||||
pointUuid: point.uuid,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<sphereGeometry args={[0.1, 16, 16]} />
|
|
||||||
<meshStandardMaterial color="purple" />
|
|
||||||
</mesh>
|
|
||||||
</group>
|
|
||||||
);
|
|
||||||
} else if (usedEvent.type === "storageUnit") {
|
|
||||||
const point = usedEvent.point;
|
|
||||||
return (
|
|
||||||
<group
|
|
||||||
key={`${index}-${usedEvent.modelUuid}`}
|
|
||||||
position={usedEvent.position}
|
|
||||||
rotation={usedEvent.rotation}
|
|
||||||
>
|
|
||||||
<mesh
|
|
||||||
name="Event-Sphere"
|
|
||||||
uuid={point.uuid}
|
|
||||||
ref={(el) => (sphereRefs.current[point.uuid] = el!)}
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
if (toolMode === 'cursor') {
|
|
||||||
setSelectedEventSphere(
|
|
||||||
sphereRefs.current[point.uuid]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
position={new THREE.Vector3(...point.position)}
|
|
||||||
userData={{
|
|
||||||
modelUuid: usedEvent.modelUuid,
|
|
||||||
pointUuid: point.uuid,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<sphereGeometry args={[0.1, 16, 16]} />
|
|
||||||
<meshStandardMaterial color="red" />
|
|
||||||
</mesh>
|
|
||||||
</group>
|
|
||||||
);
|
|
||||||
} else if (usedEvent.type === "human") {
|
|
||||||
const point = usedEvent.point;
|
|
||||||
return (
|
|
||||||
<group
|
|
||||||
key={`${index}-${usedEvent.modelUuid}`}
|
|
||||||
position={usedEvent.position}
|
|
||||||
rotation={usedEvent.rotation}
|
|
||||||
>
|
|
||||||
<mesh
|
|
||||||
name="Event-Sphere"
|
|
||||||
uuid={point.uuid}
|
|
||||||
ref={(el) => (sphereRefs.current[point.uuid] = el!)}
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
if (toolMode === 'cursor') {
|
|
||||||
setSelectedEventSphere(
|
|
||||||
sphereRefs.current[point.uuid]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
position={new THREE.Vector3(...point.position)}
|
|
||||||
userData={{
|
|
||||||
modelUuid: usedEvent.modelUuid,
|
|
||||||
pointUuid: point.uuid,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<sphereGeometry args={[0.1, 16, 16]} />
|
|
||||||
<meshStandardMaterial color="white" />
|
|
||||||
</mesh>
|
|
||||||
</group>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
})}
|
|
||||||
</group>
|
</group>
|
||||||
|
|
||||||
{selectedEventSphere && transformMode && (
|
{selectedEventSphere && transformMode && (
|
||||||
|
|||||||
@@ -0,0 +1,121 @@
|
|||||||
|
import * as THREE from "three";
|
||||||
|
import { MeshProps } from "@react-three/fiber";
|
||||||
|
import { useRef } from "react";
|
||||||
|
import { useToolMode } from "../../../../../../store/builder/store";
|
||||||
|
import { useDeletableEventSphere, useSelectedEventSphere } from "../../../../../../store/simulation/useSimulationStore";
|
||||||
|
import { useSceneContext } from "../../../../../scene/sceneContext";
|
||||||
|
import { useProductContext } from "../../../../products/productContext";
|
||||||
|
import { useVersionContext } from "../../../../../builder/version/versionContext";
|
||||||
|
import { useParams } from "react-router-dom";
|
||||||
|
import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi";
|
||||||
|
|
||||||
|
interface PointInstanceProps extends Omit<MeshProps, 'ref'> {
|
||||||
|
point: {
|
||||||
|
uuid: string;
|
||||||
|
position: [number, number, number];
|
||||||
|
};
|
||||||
|
modelUuid: string;
|
||||||
|
color: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function PointInstance({
|
||||||
|
point,
|
||||||
|
modelUuid,
|
||||||
|
color,
|
||||||
|
...meshProps
|
||||||
|
}: PointInstanceProps) {
|
||||||
|
const ref = useRef<THREE.Mesh>(null);
|
||||||
|
const { setSelectedEventSphere } = useSelectedEventSphere();
|
||||||
|
const { deletableEventSphere, setDeletableEventSphere, clearDeletableEventSphere } = useDeletableEventSphere();
|
||||||
|
const { toolMode } = useToolMode();
|
||||||
|
const { productStore } = useSceneContext();
|
||||||
|
const { getEventByModelUuid, getTriggersByTriggeredPointUuid, removeTrigger, removePoint } = productStore();
|
||||||
|
const { selectedProductStore } = useProductContext();
|
||||||
|
const { selectedProduct } = selectedProductStore();
|
||||||
|
const { selectedVersionStore } = useVersionContext();
|
||||||
|
const { selectedVersion } = selectedVersionStore();
|
||||||
|
const { projectId } = useParams();
|
||||||
|
|
||||||
|
const updateBackend = (
|
||||||
|
productName: string,
|
||||||
|
productUuid: string,
|
||||||
|
projectId: string,
|
||||||
|
eventData: EventsSchema
|
||||||
|
) => {
|
||||||
|
upsertProductOrEventApi({
|
||||||
|
productName: productName,
|
||||||
|
productUuid: productUuid,
|
||||||
|
projectId: projectId,
|
||||||
|
eventDatas: eventData,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleEventPointDelete = () => {
|
||||||
|
const eventModel = getEventByModelUuid(selectedProduct.productUuid, modelUuid);
|
||||||
|
if (!eventModel || eventModel.type !== 'transfer' || eventModel.points.length < 2) return;
|
||||||
|
|
||||||
|
const triggers = getTriggersByTriggeredPointUuid(selectedProduct.productUuid, point.uuid);
|
||||||
|
|
||||||
|
const updatedEvents: EventsSchema[] = [];
|
||||||
|
if (triggers.length > 0) {
|
||||||
|
triggers.map((trigger) => {
|
||||||
|
const event = removeTrigger(selectedProduct.productUuid, trigger.triggerUuid);
|
||||||
|
if (event) {
|
||||||
|
updatedEvents.push(event);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const event = removePoint(selectedProduct.productUuid, modelUuid, point.uuid)
|
||||||
|
|
||||||
|
if (event) {
|
||||||
|
updatedEvents.push(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updatedEvents.length > 0) {
|
||||||
|
updatedEvents.map((updatedEvent) => {
|
||||||
|
updateBackend(
|
||||||
|
selectedProduct.productName,
|
||||||
|
selectedProduct.productUuid,
|
||||||
|
projectId || '',
|
||||||
|
updatedEvent
|
||||||
|
);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<mesh
|
||||||
|
{...meshProps}
|
||||||
|
ref={ref}
|
||||||
|
name="Event-Sphere"
|
||||||
|
uuid={point.uuid}
|
||||||
|
position={new THREE.Vector3(...point.position)}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
if (toolMode === 'cursor') {
|
||||||
|
setSelectedEventSphere(ref.current);
|
||||||
|
} else if (toolMode === '3D-Delete') {
|
||||||
|
handleEventPointDelete()
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onPointerOver={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
if (toolMode === '3D-Delete' && (!deletableEventSphere || deletableEventSphere.uuid !== point.uuid)) {
|
||||||
|
setDeletableEventSphere(ref.current);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onPointerOut={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
if (toolMode === '3D-Delete' && deletableEventSphere && deletableEventSphere.uuid === point.uuid) {
|
||||||
|
clearDeletableEventSphere();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
userData={{ modelUuid, pointUuid: point.uuid }}
|
||||||
|
>
|
||||||
|
<sphereGeometry args={[0.1, 16, 16]} />
|
||||||
|
<meshStandardMaterial color={color} />
|
||||||
|
</mesh>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import { useProductContext } from "../../../products/productContext";
|
||||||
|
import { useSceneContext } from "../../../../scene/sceneContext";
|
||||||
|
|
||||||
|
import PointInstance from "./instance/pointInstance";
|
||||||
|
|
||||||
|
function PointInstances() {
|
||||||
|
const { selectedProductStore } = useProductContext();
|
||||||
|
const { selectedProduct } = selectedProductStore();
|
||||||
|
|
||||||
|
const { eventStore, productStore } = useSceneContext();
|
||||||
|
const { events } = eventStore();
|
||||||
|
const { getEventByModelUuid } = productStore();
|
||||||
|
|
||||||
|
const colorByType: Record<string, string> = {
|
||||||
|
transfer: "orange",
|
||||||
|
vehicle: "blue",
|
||||||
|
roboticArm: "green",
|
||||||
|
machine: "purple",
|
||||||
|
storageUnit: "red",
|
||||||
|
human: "white",
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{events.map((event, index) => {
|
||||||
|
const updatedEvent = selectedProduct.productUuid !== '' ? getEventByModelUuid(selectedProduct.productUuid, event.modelUuid) : null;
|
||||||
|
|
||||||
|
const usedEvent = updatedEvent || event;
|
||||||
|
const color = colorByType[usedEvent.type];
|
||||||
|
|
||||||
|
if (!color) return null;
|
||||||
|
|
||||||
|
const points = usedEvent.type === "transfer" ? usedEvent.points : [usedEvent.point];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<group
|
||||||
|
key={`${index}-${usedEvent.modelUuid}`}
|
||||||
|
position={usedEvent.position}
|
||||||
|
rotation={usedEvent.rotation}
|
||||||
|
>
|
||||||
|
{points.map((point) => (
|
||||||
|
<PointInstance
|
||||||
|
key={point.uuid}
|
||||||
|
point={point}
|
||||||
|
modelUuid={usedEvent.modelUuid}
|
||||||
|
color={color}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</group>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PointInstances;
|
||||||
@@ -54,9 +54,16 @@ export function useHumanEventManager() {
|
|||||||
|
|
||||||
callbacksRef.current.forEach(({ humanId, callback }) => {
|
callbacksRef.current.forEach(({ humanId, callback }) => {
|
||||||
const human = getHumanById(humanId);
|
const human = getHumanById(humanId);
|
||||||
if (human && human.isActive === false && human.state === 'idle' && human.isPicking && human.currentLoad < human.point.action.loadCapacity) {
|
if (human?.point.action.actionType === 'worker') {
|
||||||
callback();
|
if (human && human.isActive === false && human.state === 'idle' && human.isPicking && human.currentLoad < human.point.action.loadCapacity) {
|
||||||
removeHumanFromMonitor(humanId); // Remove after triggering
|
callback();
|
||||||
|
removeHumanFromMonitor(humanId); // Remove after triggering
|
||||||
|
}
|
||||||
|
} else if (human?.point.action.actionType === 'assembly') {
|
||||||
|
if (human && human.isActive === false && human.state === 'idle') {
|
||||||
|
callback();
|
||||||
|
removeHumanFromMonitor(humanId); // Remove after triggering
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -212,7 +212,6 @@ function RoboticArmInstance({ armBot }: { readonly armBot: ArmBotStatus }) {
|
|||||||
}
|
}
|
||||||
}, [isReset, isPlaying])
|
}, [isReset, isPlaying])
|
||||||
|
|
||||||
|
|
||||||
function animate(currentTime: number) {
|
function animate(currentTime: number) {
|
||||||
if (previousTimeRef.current === null) {
|
if (previousTimeRef.current === null) {
|
||||||
previousTimeRef.current = currentTime;
|
previousTimeRef.current = currentTime;
|
||||||
|
|||||||
36
app/src/services/simulation/ik/getAssetIKs.ts
Normal file
36
app/src/services/simulation/ik/getAssetIKs.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||||
|
|
||||||
|
export const getAssetIksApi = async (assetId: string) => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(
|
||||||
|
`${url_Backend_dwinzo}/api/v2/getAssetIks/${assetId}`,
|
||||||
|
{
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer <access_token>",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
token: localStorage.getItem("token") || "",
|
||||||
|
refresh_token: localStorage.getItem("refreshToken") || "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const newAccessToken = response.headers.get("x-access-token");
|
||||||
|
if (newAccessToken) {
|
||||||
|
localStorage.setItem("token", newAccessToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
console.error("Failed to fetch assetIks");
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
return result;
|
||||||
|
} catch (error) {
|
||||||
|
echo.error("Failed to get assetIks");
|
||||||
|
if (error instanceof Error) {
|
||||||
|
console.log(error.message);
|
||||||
|
} else {
|
||||||
|
console.log("An unknown error occurred");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -18,8 +18,8 @@ type ProductsStore = {
|
|||||||
updateEvent: (productUuid: string, modelUuid: string, updates: Partial<EventsSchema>) => EventsSchema | undefined;
|
updateEvent: (productUuid: string, modelUuid: string, updates: Partial<EventsSchema>) => EventsSchema | undefined;
|
||||||
|
|
||||||
// Point-level actions
|
// Point-level actions
|
||||||
addPoint: (productUuid: string, modelUuid: string, point: ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema | HumanPointSchema) => void;
|
addPoint: (productUuid: string, modelUuid: string, point: ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema | HumanPointSchema) => EventsSchema | undefined;
|
||||||
removePoint: (productUuid: string, modelUuid: string, pointUuid: string) => void;
|
removePoint: (productUuid: string, modelUuid: string, pointUuid: string) => EventsSchema | undefined;
|
||||||
updatePoint: (
|
updatePoint: (
|
||||||
productUuid: string,
|
productUuid: string,
|
||||||
modelUuid: string,
|
modelUuid: string,
|
||||||
@@ -72,6 +72,7 @@ type ProductsStore = {
|
|||||||
getModelUuidByActionUuid: (productUuid: string, actionUuid: string) => (string) | undefined;
|
getModelUuidByActionUuid: (productUuid: string, actionUuid: string) => (string) | undefined;
|
||||||
getPointUuidByActionUuid: (productUuid: string, actionUuid: string) => (string) | undefined;
|
getPointUuidByActionUuid: (productUuid: string, actionUuid: string) => (string) | undefined;
|
||||||
getTriggerByUuid: (productUuid: string, triggerUuid: string) => TriggerSchema | undefined;
|
getTriggerByUuid: (productUuid: string, triggerUuid: string) => TriggerSchema | undefined;
|
||||||
|
getTriggersByTriggeredPointUuid: (productUuid: string, triggeredPointUuid: string) => TriggerSchema[];
|
||||||
getIsEventInProduct: (productUuid: string, modelUuid: string) => boolean;
|
getIsEventInProduct: (productUuid: string, modelUuid: string) => boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -251,6 +252,7 @@ export const createProductStore = () => {
|
|||||||
|
|
||||||
// Point-level actions
|
// Point-level actions
|
||||||
addPoint: (productUuid, modelUuid, point) => {
|
addPoint: (productUuid, modelUuid, point) => {
|
||||||
|
let updatedEvent: EventsSchema | undefined = undefined;
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const product = state.products.find(p => p.productUuid === productUuid);
|
const product = state.products.find(p => p.productUuid === productUuid);
|
||||||
if (product) {
|
if (product) {
|
||||||
@@ -259,29 +261,35 @@ export const createProductStore = () => {
|
|||||||
const existingPoint = (event as ConveyorEventSchema).points.find(p => p.uuid === point.uuid);
|
const existingPoint = (event as ConveyorEventSchema).points.find(p => p.uuid === point.uuid);
|
||||||
if (!existingPoint) {
|
if (!existingPoint) {
|
||||||
(event as ConveyorEventSchema).points.push(point as ConveyorPointSchema);
|
(event as ConveyorEventSchema).points.push(point as ConveyorPointSchema);
|
||||||
|
updatedEvent = JSON.parse(JSON.stringify(event));
|
||||||
}
|
}
|
||||||
} else if (event && 'point' in event) {
|
} else if (event && 'point' in event) {
|
||||||
const existingPoint = (event as any).point?.uuid === point.uuid;
|
const existingPoint = (event as any).point?.uuid === point.uuid;
|
||||||
if (!existingPoint) {
|
if (!existingPoint) {
|
||||||
(event as VehicleEventSchema | RoboticArmEventSchema | MachineEventSchema | StorageEventSchema).point = point as any;
|
(event as VehicleEventSchema | RoboticArmEventSchema | MachineEventSchema | StorageEventSchema).point = point as any;
|
||||||
|
updatedEvent = JSON.parse(JSON.stringify(event));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
return updatedEvent;
|
||||||
},
|
},
|
||||||
|
|
||||||
removePoint: (productUuid, modelUuid, pointUuid) => {
|
removePoint: (productUuid, modelUuid, pointUuid) => {
|
||||||
|
let updatedEvent: EventsSchema | undefined = undefined;
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const product = state.products.find(p => p.productUuid === productUuid);
|
const product = state.products.find(p => p.productUuid === productUuid);
|
||||||
if (product) {
|
if (product) {
|
||||||
const event = product.eventDatas.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
const event = product.eventDatas.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
||||||
if (event && 'points' in event) {
|
if (event && 'points' in event) {
|
||||||
(event as ConveyorEventSchema).points = (event as ConveyorEventSchema).points.filter(p => p.uuid !== pointUuid);
|
(event as ConveyorEventSchema).points = (event as ConveyorEventSchema).points.filter(p => p.uuid !== pointUuid);
|
||||||
|
updatedEvent = JSON.parse(JSON.stringify(event));
|
||||||
} else if (event && 'point' in event && (event as any).point.uuid === pointUuid) {
|
} else if (event && 'point' in event && (event as any).point.uuid === pointUuid) {
|
||||||
// For events with single point, we can't remove it, only reset to empty
|
// For events with single point, we can't remove it, only reset to empty
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
return updatedEvent;
|
||||||
},
|
},
|
||||||
|
|
||||||
updatePoint: (productUuid, modelUuid, pointUuid, updates) => {
|
updatePoint: (productUuid, modelUuid, pointUuid, updates) => {
|
||||||
@@ -881,6 +889,48 @@ export const createProductStore = () => {
|
|||||||
return undefined;
|
return undefined;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getTriggersByTriggeredPointUuid: (productUuid, triggeredPointUuid) => {
|
||||||
|
const product = get().products.find(p => p.productUuid === productUuid);
|
||||||
|
if (!product) return [];
|
||||||
|
|
||||||
|
const triggers: TriggerSchema[] = [];
|
||||||
|
|
||||||
|
for (const event of product.eventDatas) {
|
||||||
|
if ('points' in event) {
|
||||||
|
for (const point of (event as ConveyorEventSchema).points) {
|
||||||
|
if (point.action?.triggers) {
|
||||||
|
for (const trigger of point.action.triggers) {
|
||||||
|
if (trigger.triggeredAsset?.triggeredPoint?.pointUuid === triggeredPointUuid) {
|
||||||
|
triggers.push(trigger);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if ('point' in event) {
|
||||||
|
const point = (event as any).point;
|
||||||
|
if ('action' in point && point.action?.triggers) {
|
||||||
|
for (const trigger of point.action.triggers) {
|
||||||
|
if (trigger.triggeredAsset?.triggeredPoint?.pointUuid === triggeredPointUuid) {
|
||||||
|
triggers.push(trigger);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if ('actions' in point) {
|
||||||
|
for (const action of point.actions) {
|
||||||
|
if (action.triggers) {
|
||||||
|
for (const trigger of action.triggers) {
|
||||||
|
if (trigger.triggeredAsset?.triggeredPoint?.pointUuid === triggeredPointUuid) {
|
||||||
|
triggers.push(trigger);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return triggers;
|
||||||
|
},
|
||||||
|
|
||||||
getIsEventInProduct: (productUuid, modelUuid) => {
|
getIsEventInProduct: (productUuid, modelUuid) => {
|
||||||
const product = get().getProductById(productUuid);
|
const product = get().getProductById(productUuid);
|
||||||
if (!product) return false;
|
if (!product) return false;
|
||||||
|
|||||||
@@ -24,6 +24,28 @@ export const useSelectedEventSphere = create<SelectedEventSphereState>()(
|
|||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
interface DeletableEventSphereState {
|
||||||
|
deletableEventSphere: THREE.Mesh | null;
|
||||||
|
setDeletableEventSphere: (mesh: THREE.Mesh | null) => void;
|
||||||
|
clearDeletableEventSphere: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useDeletableEventSphere = create<DeletableEventSphereState>()(
|
||||||
|
immer((set) => ({
|
||||||
|
deletableEventSphere: null,
|
||||||
|
setDeletableEventSphere: (mesh) => {
|
||||||
|
set((state) => {
|
||||||
|
state.deletableEventSphere = mesh;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
clearDeletableEventSphere: () => {
|
||||||
|
set((state) => {
|
||||||
|
state.deletableEventSphere = null;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
|
||||||
interface SelectedEventDataState {
|
interface SelectedEventDataState {
|
||||||
selectedEventData: { data: EventsSchema; selectedPoint: string } | undefined;
|
selectedEventData: { data: EventsSchema; selectedPoint: string } | undefined;
|
||||||
setSelectedEventData: (data: EventsSchema, selectedPoint: string) => void;
|
setSelectedEventData: (data: EventsSchema, selectedPoint: string) => void;
|
||||||
|
|||||||
Reference in New Issue
Block a user