diff --git a/app/src/modules/scene/postProcessing/postProcessing.tsx b/app/src/modules/scene/postProcessing/postProcessing.tsx
index 6c2f8d6..7c6c719 100644
--- a/app/src/modules/scene/postProcessing/postProcessing.tsx
+++ b/app/src/modules/scene/postProcessing/postProcessing.tsx
@@ -6,7 +6,7 @@ import {
useSelectedFloorItem,
} from "../../../store/builder/store";
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 { useBuilderStore } from "../../../store/builder/useBuilderStore";
@@ -15,6 +15,7 @@ export default function PostProcessing() {
const { selectedWallItem } = useSelectedWallItem();
const { selectedFloorItem } = useSelectedFloorItem();
const { selectedEventSphere } = useSelectedEventSphere();
+ const { deletableEventSphere } = useDeletableEventSphere();
const { selectedAisle, selectedWall, selectedDecal, selectedFloor, selectedWallAsset, deletableWallAsset } = useBuilderStore();
function flattenChildren(children: any[]) {
@@ -56,6 +57,10 @@ export default function PostProcessing() {
// console.log('deletableWallAsset: ', deletableWallAsset);
}, [deletableWallAsset])
+ useEffect(() => {
+ // console.log('deletableEventSphere: ', deletableEventSphere);
+ }, [deletableEventSphere])
+
return (
)}
+ {deletableEventSphere && (
+
+ )}
);
}
diff --git a/app/src/modules/simulation/events/arrows/arrows.tsx b/app/src/modules/simulation/events/arrows/arrows.tsx
index 5b9d6fd..2053fe5 100644
--- a/app/src/modules/simulation/events/arrows/arrows.tsx
+++ b/app/src/modules/simulation/events/arrows/arrows.tsx
@@ -16,11 +16,11 @@ interface ConnectionLine {
}
export function Arrows({ connections }: { readonly connections: ConnectionLine[] }) {
- const [hoveredLineKey, setHoveredLineKey] = useState(null);
+ const [hoveredArrowTrigger, setHoveredArrowTrigger] = useState(null);
const groupRef = useRef(null);
const { scene } = useThree();
const { toolMode } = useToolMode();
- const { eventStore, productStore } = useSceneContext();
+ const { productStore } = useSceneContext();
const { removeTrigger } = productStore();
const { selectedVersionStore } = useVersionContext();
const { selectedVersion } = selectedVersionStore();
@@ -103,15 +103,15 @@ export function Arrows({ connections }: { readonly connections: ConnectionLine[]
return (
setHoveredLineKey(trigger.triggerUuid)}
- onPointerOut={() => setHoveredLineKey(null)}
+ onPointerOver={() => setHoveredArrowTrigger(trigger.triggerUuid)}
+ onPointerOut={() => setHoveredArrowTrigger(null)}
onClick={() => { removeConnection(trigger) }}
>
diff --git a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx
index bfdf49d..9fb27a9 100644
--- a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx
+++ b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx
@@ -1,38 +1,46 @@
import { useEffect, useRef, useState } from "react";
import * as THREE from "three";
import useModuleStore, { useSubModuleStore } from "../../../../../store/useModuleStore";
+import { useToolMode } from "../../../../../store/builder/store";
import { TransformControls } from "@react-three/drei";
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 { usePlayButtonStore } from "../../../../../store/usePlayButtonStore";
import { upsertProductOrEventApi } from "../../../../../services/simulation/products/UpsertProductOrEventApi";
import { useProductContext } from "../../../products/productContext";
import { useParams } from "react-router-dom";
-import { useToolMode } from "../../../../../store/builder/store";
import { useVersionContext } from "../../../../builder/version/versionContext";
import { useSceneContext } from "../../../../scene/sceneContext";
+import PointInstances from "../instances/pointInstances";
+
function PointsCreator() {
const { gl, raycaster, scene, pointer, camera } = useThree();
const { subModule } = useSubModuleStore();
+ const { toolMode } = useToolMode();
+ const { activeModule } = useModuleStore();
const { selectedProductStore } = useProductContext();
const { eventStore, productStore } = useSceneContext();
- const { events, getEventByModelUuid } = eventStore();
- const { getEventByModelUuid: getEventByModelUuidFromProduct, updatePoint: updatePointFromProduct, getEventByModelUuid: getEventByModelUuidFromProduct2, getPointByUuid: getPointByUuidFromProduct, getTriggersByTriggeredPointUuid, removeTrigger, removePoint } = productStore();
+ const { getEventByModelUuid } = eventStore();
+ const { getEventByModelUuid: getEventByModelUuidFromProduct, updatePoint: updatePointFromProduct, getPointByUuid: getPointByUuidFromProduct, getTriggersByTriggeredPointUuid, removeTrigger, removePoint } = productStore();
const { selectedProduct } = selectedProductStore();
- const { activeModule } = useModuleStore();
const transformRef = useRef(null);
const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null);
- const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({});
- const { selectedEventSphere, setSelectedEventSphere, clearSelectedEventSphere, } = useSelectedEventSphere();
+ const { selectedEventSphere, clearSelectedEventSphere, } = useSelectedEventSphere();
+ const { clearDeletableEventSphere } = useDeletableEventSphere();
const { setSelectedEventData, clearSelectedEventData } = useSelectedEventData();
const { isPlaying } = usePlayButtonStore();
- const { toolMode } = useToolMode();
const { selectedVersionStore } = useVersionContext();
const { selectedVersion } = selectedVersionStore();
const { projectId } = useParams();
+ useEffect(() => {
+ clearSelectedEventSphere();
+ clearSelectedEventData();
+ clearDeletableEventSphere();
+ }, [toolMode, activeModule])
+
const updateBackend = (
productName: string,
productUuid: string,
@@ -208,205 +216,7 @@ function PointsCreator() {
{activeModule === "simulation" && (
<>
- {events.map((event, index) => {
- const updatedEvent = selectedProduct.productUuid !== ''
- ? getEventByModelUuidFromProduct2(selectedProduct.productUuid, event.modelUuid)
- : null;
-
- const usedEvent = updatedEvent || event;
-
- if (usedEvent.type === "transfer") {
- return (
-
- {usedEvent.points.map((point, j) => (
- (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,
- }}
- >
-
-
-
- ))}
-
- );
- } else if (usedEvent.type === "vehicle") {
- const point = usedEvent.point;
- return (
-
- (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,
- }}
- >
-
-
-
-
- );
- } else if (usedEvent.type === "roboticArm") {
- const point = usedEvent.point;
- return (
-
- (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,
- }}
- >
-
-
-
-
- );
- } else if (usedEvent.type === "machine") {
- const point = usedEvent.point;
- return (
-
- (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,
- }}
- >
-
-
-
-
- );
- } else if (usedEvent.type === "storageUnit") {
- const point = usedEvent.point;
- return (
-
- (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,
- }}
- >
-
-
-
-
- );
- } else if (usedEvent.type === "human") {
- const point = usedEvent.point;
- return (
-
- (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,
- }}
- >
-
-
-
-
- );
- } else {
- return null;
- }
- })}
+
{selectedEventSphere && transformMode && (
diff --git a/app/src/modules/simulation/events/points/instances/instance/pointInstance.tsx b/app/src/modules/simulation/events/points/instances/instance/pointInstance.tsx
new file mode 100644
index 0000000..cfac4bb
--- /dev/null
+++ b/app/src/modules/simulation/events/points/instances/instance/pointInstance.tsx
@@ -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 {
+ point: {
+ uuid: string;
+ position: [number, number, number];
+ };
+ modelUuid: string;
+ color: string;
+}
+
+export default function PointInstance({
+ point,
+ modelUuid,
+ color,
+ ...meshProps
+}: PointInstanceProps) {
+ const ref = useRef(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 (
+ {
+ 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 }}
+ >
+
+
+
+ );
+}
diff --git a/app/src/modules/simulation/events/points/instances/pointInstances.tsx b/app/src/modules/simulation/events/points/instances/pointInstances.tsx
new file mode 100644
index 0000000..0b7ca60
--- /dev/null
+++ b/app/src/modules/simulation/events/points/instances/pointInstances.tsx
@@ -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 = {
+ 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 (
+
+ {points.map((point) => (
+
+ ))}
+
+ );
+ })}
+ >
+ );
+}
+
+export default PointInstances;
diff --git a/app/src/store/simulation/useSimulationStore.ts b/app/src/store/simulation/useSimulationStore.ts
index b6cd076..9742795 100644
--- a/app/src/store/simulation/useSimulationStore.ts
+++ b/app/src/store/simulation/useSimulationStore.ts
@@ -24,6 +24,28 @@ export const useSelectedEventSphere = create()(
}))
);
+interface DeletableEventSphereState {
+ deletableEventSphere: THREE.Mesh | null;
+ setDeletableEventSphere: (mesh: THREE.Mesh | null) => void;
+ clearDeletableEventSphere: () => void;
+}
+
+export const useDeletableEventSphere = create()(
+ immer((set) => ({
+ deletableEventSphere: null,
+ setDeletableEventSphere: (mesh) => {
+ set((state) => {
+ state.deletableEventSphere = mesh;
+ });
+ },
+ clearDeletableEventSphere: () => {
+ set((state) => {
+ state.deletableEventSphere = null;
+ });
+ },
+ }))
+);
+
interface SelectedEventDataState {
selectedEventData: { data: EventsSchema; selectedPoint: string } | undefined;
setSelectedEventData: (data: EventsSchema, selectedPoint: string) => void;