|
|
|
|
@@ -3,386 +3,340 @@ import * as Types from "../../../types/world/worldTypes";
|
|
|
|
|
import { useRef, useState, useEffect, useMemo } from "react";
|
|
|
|
|
import { Sphere, TransformControls } from "@react-three/drei";
|
|
|
|
|
import {
|
|
|
|
|
useEditingPoint,
|
|
|
|
|
useEyeDropMode,
|
|
|
|
|
useIsConnecting,
|
|
|
|
|
usePreviewPosition,
|
|
|
|
|
useRenderDistance,
|
|
|
|
|
useSelectedActionSphere,
|
|
|
|
|
useSelectedPath,
|
|
|
|
|
useSimulationStates,
|
|
|
|
|
useEditingPoint,
|
|
|
|
|
useEyeDropMode,
|
|
|
|
|
useIsConnecting,
|
|
|
|
|
usePreviewPosition,
|
|
|
|
|
useRenderDistance,
|
|
|
|
|
useSelectedActionSphere,
|
|
|
|
|
useSelectedPath,
|
|
|
|
|
useSimulationStates,
|
|
|
|
|
} from "../../../store/store";
|
|
|
|
|
import { useFrame, useThree } from "@react-three/fiber";
|
|
|
|
|
import { useSubModuleStore } from "../../../store/useModuleStore";
|
|
|
|
|
import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
|
|
|
|
|
import { setEventApi } from "../../../services/factoryBuilder/assest/floorAsset/setEventsApt";
|
|
|
|
|
|
|
|
|
|
function PathCreation({
|
|
|
|
|
pathsGroupRef,
|
|
|
|
|
}: {
|
|
|
|
|
pathsGroupRef: React.MutableRefObject<THREE.Group>;
|
|
|
|
|
}) {
|
|
|
|
|
const { isPlaying } = usePlayButtonStore();
|
|
|
|
|
const { renderDistance } = useRenderDistance();
|
|
|
|
|
const { setSubModule } = useSubModuleStore();
|
|
|
|
|
const { setSelectedActionSphere, selectedActionSphere } = useSelectedActionSphere();
|
|
|
|
|
const { eyeDropMode, setEyeDropMode } = useEyeDropMode();
|
|
|
|
|
const { editingPoint, setEditingPoint } = useEditingPoint();
|
|
|
|
|
const { previewPosition, setPreviewPosition } = usePreviewPosition();
|
|
|
|
|
const { raycaster, camera, pointer, gl } = useThree();
|
|
|
|
|
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
|
|
|
|
const { setSelectedPath } = useSelectedPath();
|
|
|
|
|
const { simulationStates, setSimulationStates } = useSimulationStates();
|
|
|
|
|
const { isConnecting } = useIsConnecting();
|
|
|
|
|
function PathCreation({ pathsGroupRef, }: { pathsGroupRef: React.MutableRefObject<THREE.Group>; }) {
|
|
|
|
|
const { isPlaying } = usePlayButtonStore();
|
|
|
|
|
const { renderDistance } = useRenderDistance();
|
|
|
|
|
const { setSubModule } = useSubModuleStore();
|
|
|
|
|
const { setSelectedActionSphere, selectedActionSphere } = useSelectedActionSphere();
|
|
|
|
|
const { eyeDropMode, setEyeDropMode } = useEyeDropMode();
|
|
|
|
|
const { editingPoint, setEditingPoint } = useEditingPoint();
|
|
|
|
|
const { previewPosition, setPreviewPosition } = usePreviewPosition();
|
|
|
|
|
const { raycaster, camera, pointer, gl } = useThree();
|
|
|
|
|
const { setSelectedPath } = useSelectedPath();
|
|
|
|
|
const { simulationStates, setSimulationStates } = useSimulationStates();
|
|
|
|
|
const { isConnecting } = useIsConnecting();
|
|
|
|
|
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
|
|
|
|
|
|
|
|
|
const groupRefs = useRef<{ [key: string]: THREE.Group }>({});
|
|
|
|
|
const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({});
|
|
|
|
|
const isMovingRef = useRef(false);
|
|
|
|
|
const transformRef = useRef<any>(null);
|
|
|
|
|
const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null);
|
|
|
|
|
const groupRefs = useRef<{ [key: string]: THREE.Group }>({});
|
|
|
|
|
const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({});
|
|
|
|
|
const isMovingRef = useRef(false);
|
|
|
|
|
const transformRef = useRef<any>(null);
|
|
|
|
|
const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
setTransformMode(null);
|
|
|
|
|
const handleKeyDown = (e: KeyboardEvent) => {
|
|
|
|
|
if (!selectedActionSphere) return;
|
|
|
|
|
if (e.key === "g") {
|
|
|
|
|
setTransformMode((prev) => (prev === "translate" ? null : "translate"));
|
|
|
|
|
}
|
|
|
|
|
if (e.key === "r") {
|
|
|
|
|
setTransformMode((prev) => (prev === "rotate" ? null : "rotate"));
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
setTransformMode(null);
|
|
|
|
|
const handleKeyDown = (e: KeyboardEvent) => {
|
|
|
|
|
if (!selectedActionSphere) return;
|
|
|
|
|
if (e.key === "g") {
|
|
|
|
|
setTransformMode((prev) => (prev === "translate" ? null : "translate"));
|
|
|
|
|
}
|
|
|
|
|
if (e.key === "r") {
|
|
|
|
|
setTransformMode((prev) => (prev === "rotate" ? null : "rotate"));
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
window.addEventListener("keydown", handleKeyDown);
|
|
|
|
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
|
|
|
}, [selectedActionSphere]);
|
|
|
|
|
window.addEventListener("keydown", handleKeyDown);
|
|
|
|
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
|
|
|
}, [selectedActionSphere]);
|
|
|
|
|
|
|
|
|
|
useFrame(() => {
|
|
|
|
|
Object.values(groupRefs.current).forEach((group) => {
|
|
|
|
|
if (group) {
|
|
|
|
|
const distance = new THREE.Vector3(
|
|
|
|
|
...group.position.toArray()
|
|
|
|
|
).distanceTo(camera.position);
|
|
|
|
|
group.visible = ((distance <= renderDistance) && !isPlaying);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
useFrame(() => {
|
|
|
|
|
Object.values(groupRefs.current).forEach((group) => {
|
|
|
|
|
if (group) {
|
|
|
|
|
const distance = new THREE.Vector3(
|
|
|
|
|
...group.position.toArray()
|
|
|
|
|
).distanceTo(camera.position);
|
|
|
|
|
group.visible = ((distance <= renderDistance) && !isPlaying);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const updateSimulationPaths = () => {
|
|
|
|
|
if (!selectedActionSphere) return;
|
|
|
|
|
const updateSimulationPaths = () => {
|
|
|
|
|
if (!selectedActionSphere) return;
|
|
|
|
|
|
|
|
|
|
const updatedPaths = simulationStates.map((path) => {
|
|
|
|
|
if (path.type === "Conveyor") {
|
|
|
|
|
return {
|
|
|
|
|
...path,
|
|
|
|
|
points: path.points.map((point) =>
|
|
|
|
|
point.uuid === selectedActionSphere.points.uuid
|
|
|
|
|
? {
|
|
|
|
|
...point,
|
|
|
|
|
position: [
|
|
|
|
|
selectedActionSphere.points.position.x,
|
|
|
|
|
selectedActionSphere.points.position.y,
|
|
|
|
|
selectedActionSphere.points.position.z,
|
|
|
|
|
],
|
|
|
|
|
rotation: [
|
|
|
|
|
selectedActionSphere.points.rotation.x,
|
|
|
|
|
selectedActionSphere.points.rotation.y,
|
|
|
|
|
selectedActionSphere.points.rotation.z,
|
|
|
|
|
],
|
|
|
|
|
}
|
|
|
|
|
: point
|
|
|
|
|
),
|
|
|
|
|
};
|
|
|
|
|
} else {
|
|
|
|
|
return path;
|
|
|
|
|
}
|
|
|
|
|
}) as Types.ConveyorEventsSchema[];
|
|
|
|
|
const updatedPaths = simulationStates.map((path) => {
|
|
|
|
|
if (path.type === "Conveyor") {
|
|
|
|
|
return {
|
|
|
|
|
...path,
|
|
|
|
|
points: path.points.map((point) =>
|
|
|
|
|
point.uuid === selectedActionSphere.points.uuid
|
|
|
|
|
? {
|
|
|
|
|
...point,
|
|
|
|
|
position: [
|
|
|
|
|
selectedActionSphere.points.position.x,
|
|
|
|
|
selectedActionSphere.points.position.y,
|
|
|
|
|
selectedActionSphere.points.position.z,
|
|
|
|
|
],
|
|
|
|
|
rotation: [
|
|
|
|
|
selectedActionSphere.points.rotation.x,
|
|
|
|
|
selectedActionSphere.points.rotation.y,
|
|
|
|
|
selectedActionSphere.points.rotation.z,
|
|
|
|
|
],
|
|
|
|
|
}
|
|
|
|
|
: point
|
|
|
|
|
),
|
|
|
|
|
};
|
|
|
|
|
} else {
|
|
|
|
|
return path;
|
|
|
|
|
}
|
|
|
|
|
}) as Types.ConveyorEventsSchema[];
|
|
|
|
|
|
|
|
|
|
const updatedPath = updatedPaths.find(
|
|
|
|
|
(path) =>
|
|
|
|
|
path.type === "Conveyor" &&
|
|
|
|
|
path.points.some(
|
|
|
|
|
(point) => point.uuid === selectedActionSphere.points.uuid
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
const updatedPath = updatedPaths.find(
|
|
|
|
|
(path) => path.type === "Conveyor" && path.points.some((point) => point.uuid === selectedActionSphere.points.uuid)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// console.log("Updated Path:", updatedPath);
|
|
|
|
|
// console.log("Updated Path:", updatedPath);
|
|
|
|
|
|
|
|
|
|
setSimulationStates(updatedPaths);
|
|
|
|
|
};
|
|
|
|
|
setSimulationStates(updatedPaths);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
useFrame(() => {
|
|
|
|
|
if (eyeDropMode) {
|
|
|
|
|
raycaster.setFromCamera(pointer, camera);
|
|
|
|
|
const intersectionPoint = new THREE.Vector3();
|
|
|
|
|
const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
|
|
|
|
useFrame(() => {
|
|
|
|
|
if (eyeDropMode) {
|
|
|
|
|
raycaster.setFromCamera(pointer, camera);
|
|
|
|
|
const intersectionPoint = new THREE.Vector3();
|
|
|
|
|
const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
|
|
|
|
|
|
|
|
|
if (point) {
|
|
|
|
|
setPreviewPosition({ x: point.x, y: point.z });
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
setPreviewPosition(null);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
if (point) {
|
|
|
|
|
setPreviewPosition({ x: point.x, y: point.z });
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
setPreviewPosition(null);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (!camera) return;
|
|
|
|
|
const canvasElement = gl.domElement;
|
|
|
|
|
canvasElement.tabIndex = 0;
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (!camera) return;
|
|
|
|
|
const canvasElement = gl.domElement;
|
|
|
|
|
canvasElement.tabIndex = 0;
|
|
|
|
|
|
|
|
|
|
const onPointerDown = () => {
|
|
|
|
|
isMovingRef.current = false;
|
|
|
|
|
};
|
|
|
|
|
const onPointerDown = () => {
|
|
|
|
|
isMovingRef.current = false;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const onPointerMove = () => {
|
|
|
|
|
isMovingRef.current = true;
|
|
|
|
|
};
|
|
|
|
|
const onPointerMove = () => {
|
|
|
|
|
isMovingRef.current = true;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const onPointerUp = (event: PointerEvent) => {
|
|
|
|
|
if (
|
|
|
|
|
!isMovingRef.current &&
|
|
|
|
|
eyeDropMode &&
|
|
|
|
|
event.button === 0 &&
|
|
|
|
|
previewPosition
|
|
|
|
|
) {
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
if (editingPoint) {
|
|
|
|
|
handlePointUpdate(editingPoint, previewPosition.x, previewPosition.y);
|
|
|
|
|
setEditingPoint(null);
|
|
|
|
|
setEyeDropMode(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
const onPointerUp = (event: PointerEvent) => {
|
|
|
|
|
if (
|
|
|
|
|
!isMovingRef.current &&
|
|
|
|
|
eyeDropMode &&
|
|
|
|
|
event.button === 0 &&
|
|
|
|
|
previewPosition
|
|
|
|
|
) {
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
if (editingPoint) {
|
|
|
|
|
handlePointUpdate(editingPoint, previewPosition.x, previewPosition.y);
|
|
|
|
|
setEditingPoint(null);
|
|
|
|
|
setEyeDropMode(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (eyeDropMode) {
|
|
|
|
|
canvasElement.addEventListener("pointerdown", onPointerDown);
|
|
|
|
|
canvasElement.addEventListener("pointermove", onPointerMove);
|
|
|
|
|
canvasElement.addEventListener("pointerup", onPointerUp);
|
|
|
|
|
}
|
|
|
|
|
if (eyeDropMode) {
|
|
|
|
|
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);
|
|
|
|
|
};
|
|
|
|
|
}, [eyeDropMode, editingPoint, previewPosition]);
|
|
|
|
|
return () => {
|
|
|
|
|
canvasElement.removeEventListener("pointerdown", onPointerDown);
|
|
|
|
|
canvasElement.removeEventListener("pointermove", onPointerMove);
|
|
|
|
|
canvasElement.removeEventListener("pointerup", onPointerUp);
|
|
|
|
|
};
|
|
|
|
|
}, [eyeDropMode, editingPoint, previewPosition]);
|
|
|
|
|
|
|
|
|
|
const updateBackend = async (updatedPath: Types.VehicleEventsSchema | undefined) => {
|
|
|
|
|
if (!updatedPath) return;
|
|
|
|
|
const email = localStorage.getItem("email");
|
|
|
|
|
const organization = email ? email.split("@")[1].split(".")[0] : "";
|
|
|
|
|
await setEventApi(
|
|
|
|
|
organization,
|
|
|
|
|
updatedPath.modeluuid,
|
|
|
|
|
{ type: "Vehicle", points: updatedPath.points }
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
const updateBackend = async (updatedPath: Types.VehicleEventsSchema | undefined) => {
|
|
|
|
|
if (!updatedPath) return;
|
|
|
|
|
const email = localStorage.getItem("email");
|
|
|
|
|
const organization = email ? email.split("@")[1].split(".")[0] : "";
|
|
|
|
|
await setEventApi(
|
|
|
|
|
organization,
|
|
|
|
|
updatedPath.modeluuid,
|
|
|
|
|
{ type: "Vehicle", points: updatedPath.points }
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const handlePointUpdate = (
|
|
|
|
|
pointType: "start" | "end",
|
|
|
|
|
x: number,
|
|
|
|
|
z: number
|
|
|
|
|
) => {
|
|
|
|
|
if (!selectedActionSphere?.points?.uuid) return;
|
|
|
|
|
const updatedPaths = simulationStates.map((path) => {
|
|
|
|
|
const handlePointUpdate = (pointType: "start" | "end", x: number, z: number) => {
|
|
|
|
|
if (!selectedActionSphere?.points?.uuid) return;
|
|
|
|
|
const updatedPaths = simulationStates.map((path) => {
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
path.type === "Vehicle" &&
|
|
|
|
|
path.points.uuid === selectedActionSphere.points.uuid
|
|
|
|
|
) {
|
|
|
|
|
return {
|
|
|
|
|
...path,
|
|
|
|
|
points: {
|
|
|
|
|
...path.points,
|
|
|
|
|
actions: {
|
|
|
|
|
...path.points.actions,
|
|
|
|
|
[pointType]: {
|
|
|
|
|
...path.points.actions[pointType],
|
|
|
|
|
x: x,
|
|
|
|
|
y: z,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
return path;
|
|
|
|
|
});
|
|
|
|
|
if (path.type === "Vehicle" && path.points.uuid === selectedActionSphere.points.uuid) {
|
|
|
|
|
return {
|
|
|
|
|
...path,
|
|
|
|
|
points: {
|
|
|
|
|
...path.points,
|
|
|
|
|
actions: {
|
|
|
|
|
...path.points.actions,
|
|
|
|
|
[pointType]: { ...path.points.actions[pointType], x: x, y: z, },
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
return path;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const updatedPath = updatedPaths.find(
|
|
|
|
|
(path): path is Types.VehicleEventsSchema =>
|
|
|
|
|
path.type === "Vehicle" &&
|
|
|
|
|
path.points.uuid === selectedActionSphere.points.uuid
|
|
|
|
|
);
|
|
|
|
|
updateBackend(updatedPath);
|
|
|
|
|
const updatedPath = updatedPaths.find((path): path is Types.VehicleEventsSchema => path.type === "Vehicle" && path.points.uuid === selectedActionSphere.points.uuid);
|
|
|
|
|
updateBackend(updatedPath);
|
|
|
|
|
|
|
|
|
|
setSimulationStates(updatedPaths);
|
|
|
|
|
};
|
|
|
|
|
setSimulationStates(updatedPaths);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<group visible={!isPlaying} name="simulation-simulationStates-group" ref={pathsGroupRef}>
|
|
|
|
|
{simulationStates.map((path) => {
|
|
|
|
|
if (path.type === "Conveyor") {
|
|
|
|
|
const points = path.points.map(
|
|
|
|
|
(point) => new THREE.Vector3(...point.position)
|
|
|
|
|
);
|
|
|
|
|
return (
|
|
|
|
|
<group visible={!isPlaying} name="simulation-simulationStates-group" ref={pathsGroupRef}>
|
|
|
|
|
{simulationStates.map((path) => {
|
|
|
|
|
if (path.type === "Conveyor") {
|
|
|
|
|
const points = path.points.map(
|
|
|
|
|
(point) => new THREE.Vector3(...point.position)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<group
|
|
|
|
|
name={`${path.modeluuid}-event-path`}
|
|
|
|
|
key={path.modeluuid}
|
|
|
|
|
ref={(el) => (groupRefs.current[path.modeluuid] = el!)}
|
|
|
|
|
position={path.position}
|
|
|
|
|
rotation={path.rotation}
|
|
|
|
|
onClick={(e) => {
|
|
|
|
|
if (isConnecting || eyeDropMode) return;
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
setSelectedPath({
|
|
|
|
|
path,
|
|
|
|
|
group: groupRefs.current[path.modeluuid],
|
|
|
|
|
});
|
|
|
|
|
setSelectedActionSphere(null);
|
|
|
|
|
setTransformMode(null);
|
|
|
|
|
setSubModule("mechanics");
|
|
|
|
|
}}
|
|
|
|
|
onPointerMissed={() => {
|
|
|
|
|
if (eyeDropMode) return;
|
|
|
|
|
setSelectedPath(null);
|
|
|
|
|
setSubModule("properties");
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{path.points.map((point, index) => (
|
|
|
|
|
<Sphere
|
|
|
|
|
key={point.uuid}
|
|
|
|
|
uuid={point.uuid}
|
|
|
|
|
position={point.position}
|
|
|
|
|
args={[0.15, 32, 32]}
|
|
|
|
|
name="events-sphere"
|
|
|
|
|
ref={(el) => (sphereRefs.current[point.uuid] = el!)}
|
|
|
|
|
onClick={(e) => {
|
|
|
|
|
if (isConnecting || eyeDropMode) return;
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
setSelectedActionSphere({
|
|
|
|
|
path,
|
|
|
|
|
points: sphereRefs.current[point.uuid],
|
|
|
|
|
});
|
|
|
|
|
setSubModule("mechanics");
|
|
|
|
|
setSelectedPath(null);
|
|
|
|
|
}}
|
|
|
|
|
userData={{ points, path }}
|
|
|
|
|
onPointerMissed={() => {
|
|
|
|
|
if (eyeDropMode) return;
|
|
|
|
|
setSubModule("properties");
|
|
|
|
|
setSelectedActionSphere(null);
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<meshStandardMaterial
|
|
|
|
|
color={
|
|
|
|
|
index === 0
|
|
|
|
|
? "orange"
|
|
|
|
|
: index === path.points.length - 1
|
|
|
|
|
? "blue"
|
|
|
|
|
: "green"
|
|
|
|
|
}
|
|
|
|
|
/>
|
|
|
|
|
</Sphere>
|
|
|
|
|
))}
|
|
|
|
|
return (
|
|
|
|
|
<group
|
|
|
|
|
name={`${path.modeluuid}-${path.type}-path`}
|
|
|
|
|
key={path.modeluuid}
|
|
|
|
|
ref={(el) => (groupRefs.current[path.modeluuid] = el!)}
|
|
|
|
|
position={path.position}
|
|
|
|
|
rotation={path.rotation}
|
|
|
|
|
onClick={(e) => {
|
|
|
|
|
if (isConnecting || eyeDropMode) return;
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
setSelectedPath({
|
|
|
|
|
path,
|
|
|
|
|
group: groupRefs.current[path.modeluuid],
|
|
|
|
|
});
|
|
|
|
|
setSelectedActionSphere(null);
|
|
|
|
|
setTransformMode(null);
|
|
|
|
|
setSubModule("mechanics");
|
|
|
|
|
}}
|
|
|
|
|
onPointerMissed={() => {
|
|
|
|
|
if (eyeDropMode) return;
|
|
|
|
|
setSelectedPath(null);
|
|
|
|
|
setSubModule("properties");
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{path.points.map((point, index) => (
|
|
|
|
|
<Sphere
|
|
|
|
|
key={point.uuid}
|
|
|
|
|
uuid={point.uuid}
|
|
|
|
|
position={point.position}
|
|
|
|
|
args={[0.15, 32, 32]}
|
|
|
|
|
name="events-sphere"
|
|
|
|
|
ref={(el) => (sphereRefs.current[point.uuid] = el!)}
|
|
|
|
|
onClick={(e) => {
|
|
|
|
|
if (isConnecting || eyeDropMode) return;
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
setSelectedActionSphere({
|
|
|
|
|
path,
|
|
|
|
|
points: sphereRefs.current[point.uuid],
|
|
|
|
|
});
|
|
|
|
|
setSubModule("mechanics");
|
|
|
|
|
setSelectedPath(null);
|
|
|
|
|
}}
|
|
|
|
|
userData={{ points, path }}
|
|
|
|
|
onPointerMissed={() => {
|
|
|
|
|
if (eyeDropMode) return;
|
|
|
|
|
setSubModule("properties");
|
|
|
|
|
setSelectedActionSphere(null);
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<meshStandardMaterial
|
|
|
|
|
color={index === 0 ? "orange" : index === path.points.length - 1 ? "blue" : "green"}
|
|
|
|
|
/>
|
|
|
|
|
</Sphere>
|
|
|
|
|
))}
|
|
|
|
|
|
|
|
|
|
{points.slice(0, -1).map((point, index) => {
|
|
|
|
|
const nextPoint = points[index + 1];
|
|
|
|
|
const segmentCurve = new THREE.CatmullRomCurve3([
|
|
|
|
|
point,
|
|
|
|
|
nextPoint,
|
|
|
|
|
]);
|
|
|
|
|
const tubeGeometry = new THREE.TubeGeometry(
|
|
|
|
|
segmentCurve,
|
|
|
|
|
20,
|
|
|
|
|
0.1,
|
|
|
|
|
16,
|
|
|
|
|
false
|
|
|
|
|
);
|
|
|
|
|
{points.slice(0, -1).map((point, index) => {
|
|
|
|
|
const nextPoint = points[index + 1];
|
|
|
|
|
const segmentCurve = new THREE.CatmullRomCurve3([point, nextPoint,]);
|
|
|
|
|
const tubeGeometry = new THREE.TubeGeometry(segmentCurve, 20, 0.1, 16, false);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<mesh
|
|
|
|
|
name="event-connection-tube"
|
|
|
|
|
key={`tube-${index}`}
|
|
|
|
|
geometry={tubeGeometry}
|
|
|
|
|
>
|
|
|
|
|
<meshStandardMaterial
|
|
|
|
|
transparent
|
|
|
|
|
opacity={0.9}
|
|
|
|
|
color="red"
|
|
|
|
|
/>
|
|
|
|
|
</mesh>
|
|
|
|
|
);
|
|
|
|
|
})}
|
|
|
|
|
</group>
|
|
|
|
|
);
|
|
|
|
|
} else if (path.type === "Vehicle") {
|
|
|
|
|
return (
|
|
|
|
|
<group
|
|
|
|
|
name={`${path.modeluuid}-vehicle-path`}
|
|
|
|
|
key={path.modeluuid}
|
|
|
|
|
ref={(el) => (groupRefs.current[path.modeluuid] = el!)}
|
|
|
|
|
position={path.position}
|
|
|
|
|
onClick={(e) => {
|
|
|
|
|
if (isConnecting || eyeDropMode) return;
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
setSelectedPath({
|
|
|
|
|
path,
|
|
|
|
|
group: groupRefs.current[path.modeluuid],
|
|
|
|
|
});
|
|
|
|
|
setSelectedActionSphere(null);
|
|
|
|
|
setTransformMode(null);
|
|
|
|
|
setSubModule("mechanics");
|
|
|
|
|
}}
|
|
|
|
|
onPointerMissed={() => {
|
|
|
|
|
if (eyeDropMode) return;
|
|
|
|
|
setSelectedPath(null);
|
|
|
|
|
setSubModule("properties");
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<Sphere
|
|
|
|
|
key={path.points.uuid}
|
|
|
|
|
uuid={path.points.uuid}
|
|
|
|
|
position={path.points.position}
|
|
|
|
|
args={[0.15, 32, 32]}
|
|
|
|
|
name="events-sphere"
|
|
|
|
|
ref={(el) => (sphereRefs.current[path.points.uuid] = el!)}
|
|
|
|
|
onClick={(e) => {
|
|
|
|
|
if (isConnecting || eyeDropMode) return;
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
setSelectedActionSphere({
|
|
|
|
|
path,
|
|
|
|
|
points: sphereRefs.current[path.points.uuid],
|
|
|
|
|
});
|
|
|
|
|
setSubModule("mechanics");
|
|
|
|
|
setSelectedPath(null);
|
|
|
|
|
}}
|
|
|
|
|
userData={{ points: path.points, path }}
|
|
|
|
|
onPointerMissed={() => {
|
|
|
|
|
if (eyeDropMode) return;
|
|
|
|
|
setSubModule("properties");
|
|
|
|
|
setSelectedActionSphere(null);
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<meshStandardMaterial color="purple" />
|
|
|
|
|
</Sphere>
|
|
|
|
|
</group>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
})}
|
|
|
|
|
return (
|
|
|
|
|
<mesh name="event-connection-tube" key={`tube-${index}`} geometry={tubeGeometry}>
|
|
|
|
|
<meshStandardMaterial transparent opacity={0.9} color="red" />
|
|
|
|
|
</mesh>
|
|
|
|
|
);
|
|
|
|
|
})}
|
|
|
|
|
</group>
|
|
|
|
|
);
|
|
|
|
|
} else if (path.type === "Vehicle" || path.type === "StaticMachine") {
|
|
|
|
|
return (
|
|
|
|
|
<group
|
|
|
|
|
name={`${path.modeluuid}-${path.type}-path`}
|
|
|
|
|
key={path.modeluuid}
|
|
|
|
|
ref={(el) => (groupRefs.current[path.modeluuid] = el!)}
|
|
|
|
|
position={path.position}
|
|
|
|
|
onClick={(e) => {
|
|
|
|
|
if (isConnecting || eyeDropMode) return;
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
setSelectedPath({
|
|
|
|
|
path,
|
|
|
|
|
group: groupRefs.current[path.modeluuid],
|
|
|
|
|
});
|
|
|
|
|
setSelectedActionSphere(null);
|
|
|
|
|
setTransformMode(null);
|
|
|
|
|
setSubModule("mechanics");
|
|
|
|
|
}}
|
|
|
|
|
onPointerMissed={() => {
|
|
|
|
|
if (eyeDropMode) return;
|
|
|
|
|
setSelectedPath(null);
|
|
|
|
|
setSubModule("properties");
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<Sphere
|
|
|
|
|
key={path.points.uuid}
|
|
|
|
|
uuid={path.points.uuid}
|
|
|
|
|
position={path.points.position}
|
|
|
|
|
args={[0.15, 32, 32]}
|
|
|
|
|
name="events-sphere"
|
|
|
|
|
ref={(el) => (sphereRefs.current[path.points.uuid] = el!)}
|
|
|
|
|
onClick={(e) => {
|
|
|
|
|
if (isConnecting || eyeDropMode) return;
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
setSelectedActionSphere({
|
|
|
|
|
path,
|
|
|
|
|
points: sphereRefs.current[path.points.uuid],
|
|
|
|
|
});
|
|
|
|
|
setSubModule("mechanics");
|
|
|
|
|
setSelectedPath(null);
|
|
|
|
|
}}
|
|
|
|
|
userData={{ points: path.points, path }}
|
|
|
|
|
onPointerMissed={() => {
|
|
|
|
|
if (eyeDropMode) return;
|
|
|
|
|
setSubModule("properties");
|
|
|
|
|
setSelectedActionSphere(null);
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<meshStandardMaterial color="purple" />
|
|
|
|
|
</Sphere>
|
|
|
|
|
</group>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
})}
|
|
|
|
|
|
|
|
|
|
{selectedActionSphere && transformMode && (
|
|
|
|
|
<TransformControls
|
|
|
|
|
ref={transformRef}
|
|
|
|
|
object={selectedActionSphere.points}
|
|
|
|
|
mode={transformMode}
|
|
|
|
|
onMouseUp={updateSimulationPaths}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
</group>
|
|
|
|
|
);
|
|
|
|
|
{selectedActionSphere && transformMode && (
|
|
|
|
|
<TransformControls
|
|
|
|
|
ref={transformRef}
|
|
|
|
|
object={selectedActionSphere.points}
|
|
|
|
|
mode={transformMode}
|
|
|
|
|
onMouseUp={updateSimulationPaths}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
</group>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default PathCreation;
|
|
|
|
|
|