Refactor AssetProperties layout, enhance PositionInput component with optional properties, and implement new asset event fetching logic
This commit is contained in:
parent
dd03216393
commit
6e4c8282c5
|
@ -1,23 +1,32 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { EyeDroperIcon } from "../../../icons/ExportCommonIcons";
|
||||||
|
|
||||||
interface PositionInputProps {
|
interface PositionInputProps {
|
||||||
|
label?: string; // Optional label for the input
|
||||||
onChange: (value: string) => void; // Callback for value change
|
onChange: (value: string) => void; // Callback for value change
|
||||||
placeholder?: string; // Optional placeholder
|
placeholder?: string; // Optional placeholder
|
||||||
type?: string; // Input type (e.g., text, number, email)
|
type?: string; // Input type (e.g., text, number, email)
|
||||||
value1?: number;
|
value1?: number;
|
||||||
value2?: number;
|
value2?: number;
|
||||||
|
disabled?: boolean; // Optional disabled property
|
||||||
|
isEyedrop?: boolean; // Optional eyedrop property
|
||||||
|
handleEyeDropClick?: () => void; // Optional function for eye drop click
|
||||||
}
|
}
|
||||||
|
|
||||||
const PositionInput: React.FC<PositionInputProps> = ({
|
const PositionInput: React.FC<PositionInputProps> = ({
|
||||||
onChange,
|
onChange,
|
||||||
|
label = "Position", // Default label
|
||||||
placeholder = "Enter value", // Default placeholder
|
placeholder = "Enter value", // Default placeholder
|
||||||
type = "number", // Default type
|
type = "number", // Default type
|
||||||
value1 = "number",
|
value1 = "number",
|
||||||
value2 = "number",
|
value2 = "number",
|
||||||
|
disabled = false, // Default disabled value
|
||||||
|
isEyedrop = false, // Default isEyedrop value
|
||||||
|
handleEyeDropClick = () => { }, // Default function for eye drop click
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<div className="custom-input-container">
|
<div className="custom-input-container">
|
||||||
<div className="header">Position</div>
|
<div className="header">{label}</div>
|
||||||
<div className="inputs-container">
|
<div className="inputs-container">
|
||||||
<div className="input-container">
|
<div className="input-container">
|
||||||
<div className="custom-input-label">X : </div>
|
<div className="custom-input-label">X : </div>
|
||||||
|
@ -26,7 +35,8 @@ const PositionInput: React.FC<PositionInputProps> = ({
|
||||||
type={type}
|
type={type}
|
||||||
onChange={(e) => onChange(e.target.value)}
|
onChange={(e) => onChange(e.target.value)}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
value={value2}
|
value={value1}
|
||||||
|
disabled={disabled} // Apply disabled prop
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="input-container">
|
<div className="input-container">
|
||||||
|
@ -36,10 +46,16 @@ const PositionInput: React.FC<PositionInputProps> = ({
|
||||||
type={type}
|
type={type}
|
||||||
onChange={(e) => onChange(e.target.value)}
|
onChange={(e) => onChange(e.target.value)}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
value={value1}
|
value={value2}
|
||||||
|
disabled={disabled} // Apply disabled prop
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{isEyedrop && (
|
||||||
|
<div className="eye-picker-button" onClick={handleEyeDropClick}>
|
||||||
|
<EyeDroperIcon isActive={false} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
import React, { useRef, useMemo } from "react";
|
import React, { useRef, useMemo } from "react";
|
||||||
import { InfoIcon } from "../../../icons/ExportCommonIcons";
|
import { InfoIcon } from "../../../icons/ExportCommonIcons";
|
||||||
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
|
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
|
||||||
import { useSelectedActionSphere, useSimulationPaths } from "../../../../store/store";
|
import { useEditingPoint, useEyeDropMode, usePreviewPosition, useSelectedActionSphere, useSimulationPaths } from "../../../../store/store";
|
||||||
import * as Types from '../../../../types/world/worldTypes';
|
import * as Types from '../../../../types/world/worldTypes';
|
||||||
import LabledDropdown from "../../../ui/inputs/LabledDropdown";
|
import PositionInput from "../customInput/PositionInputs";
|
||||||
|
|
||||||
const VehicleMechanics: React.FC = () => {
|
const VehicleMechanics: React.FC = () => {
|
||||||
const { selectedActionSphere } = useSelectedActionSphere();
|
const { selectedActionSphere } = useSelectedActionSphere();
|
||||||
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
||||||
|
const { eyeDropMode, setEyeDropMode } = useEyeDropMode();
|
||||||
|
const { editingPoint, setEditingPoint } = useEditingPoint();
|
||||||
|
const { previewPosition, setPreviewPosition } = usePreviewPosition();
|
||||||
|
|
||||||
const propertiesContainerRef = useRef<HTMLDivElement>(null);
|
const propertiesContainerRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
@ -59,12 +62,10 @@ const VehicleMechanics: React.FC = () => {
|
||||||
setSimulationPaths(updatedPaths);
|
setSimulationPaths(updatedPaths);
|
||||||
}, [selectedActionSphere?.point?.uuid, simulationPaths, setSimulationPaths]);
|
}, [selectedActionSphere?.point?.uuid, simulationPaths, setSimulationPaths]);
|
||||||
|
|
||||||
const handleStartPointChange = React.useCallback((uuid: string) => {
|
const handleStartPointChange = React.useCallback((position: { x: number, y: number }) => {
|
||||||
handleActionUpdate({ start: uuid });
|
|
||||||
}, [handleActionUpdate]);
|
}, [handleActionUpdate]);
|
||||||
|
|
||||||
const handleEndPointChange = React.useCallback((uuid: string) => {
|
const handleEndPointChange = React.useCallback((position: { x: number, y: number }) => {
|
||||||
handleActionUpdate({ end: uuid });
|
|
||||||
}, [handleActionUpdate]);
|
}, [handleActionUpdate]);
|
||||||
|
|
||||||
const handleHitCountChange = React.useCallback((hitCount: number) => {
|
const handleHitCountChange = React.useCallback((hitCount: number) => {
|
||||||
|
@ -94,6 +95,16 @@ const VehicleMechanics: React.FC = () => {
|
||||||
setSimulationPaths(updatedPaths);
|
setSimulationPaths(updatedPaths);
|
||||||
}, [selectedActionSphere?.point?.uuid, simulationPaths, setSimulationPaths]);
|
}, [selectedActionSphere?.point?.uuid, simulationPaths, setSimulationPaths]);
|
||||||
|
|
||||||
|
const handleStartEyeDropClick = () => {
|
||||||
|
setEditingPoint('start');
|
||||||
|
setEyeDropMode(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleEndEyeDropClick = () => {
|
||||||
|
setEditingPoint('end');
|
||||||
|
setEyeDropMode(true);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="machine-mechanics-container" key={selectedPoint?.uuid}>
|
<div className="machine-mechanics-container" key={selectedPoint?.uuid}>
|
||||||
<div className="machine-mechanics-header">
|
<div className="machine-mechanics-header">
|
||||||
|
@ -106,20 +117,49 @@ const VehicleMechanics: React.FC = () => {
|
||||||
|
|
||||||
{selectedPoint && (
|
{selectedPoint && (
|
||||||
<>
|
<>
|
||||||
<LabledDropdown
|
<PositionInput
|
||||||
key={`start-${selectedPoint.uuid}`}
|
|
||||||
label="Start Point"
|
label="Start Point"
|
||||||
defaultOption={selectedPoint.actions.start || "Select start point"}
|
onChange={() => { }}
|
||||||
options={connectedPointUuids}
|
disabled={true}
|
||||||
onSelect={handleStartPointChange}
|
value1={
|
||||||
|
editingPoint === 'start' && previewPosition
|
||||||
|
? parseFloat(previewPosition.x.toFixed(4))
|
||||||
|
: selectedPoint.actions.start && 'x' in selectedPoint.actions.start
|
||||||
|
? parseFloat(selectedPoint.actions.start.x.toFixed(4))
|
||||||
|
: 0
|
||||||
|
}
|
||||||
|
value2={
|
||||||
|
editingPoint === 'start' && previewPosition
|
||||||
|
? parseFloat(previewPosition.y.toFixed(4))
|
||||||
|
: selectedPoint.actions.start && 'y' in selectedPoint.actions.start
|
||||||
|
? parseFloat(selectedPoint.actions.start.y.toFixed(4))
|
||||||
|
: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
isEyedrop={true}
|
||||||
|
handleEyeDropClick={handleStartEyeDropClick}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<LabledDropdown
|
<PositionInput
|
||||||
key={`end-${selectedPoint.uuid}`}
|
|
||||||
label="End Point"
|
label="End Point"
|
||||||
defaultOption={selectedPoint.actions.end || "Select end point"}
|
onChange={() => { }}
|
||||||
options={connectedPointUuids}
|
disabled={true}
|
||||||
onSelect={handleEndPointChange}
|
value1={
|
||||||
|
editingPoint === 'end' && previewPosition
|
||||||
|
? parseFloat(previewPosition.x.toFixed(4))
|
||||||
|
: selectedPoint.actions.end && 'x' in selectedPoint.actions.end
|
||||||
|
? parseFloat(selectedPoint.actions.end.x.toFixed(4))
|
||||||
|
: 0
|
||||||
|
}
|
||||||
|
value2={
|
||||||
|
editingPoint === 'end' && previewPosition
|
||||||
|
? parseFloat(previewPosition.y.toFixed(4))
|
||||||
|
: selectedPoint.actions.end && 'y' in selectedPoint.actions.end
|
||||||
|
? parseFloat(selectedPoint.actions.end.y.toFixed(4))
|
||||||
|
: 0
|
||||||
|
}
|
||||||
|
isEyedrop={true}
|
||||||
|
handleEyeDropClick={handleEndEyeDropClick}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<InputWithDropDown
|
<InputWithDropDown
|
||||||
|
|
|
@ -55,8 +55,6 @@ const AssetProperties: React.FC = () => {
|
||||||
{/* Name */}
|
{/* Name */}
|
||||||
<div className="header">{selectedFloorItem.userData.name}</div>
|
<div className="header">{selectedFloorItem.userData.name}</div>
|
||||||
|
|
||||||
<div className="split"></div>
|
|
||||||
|
|
||||||
<PositionInput
|
<PositionInput
|
||||||
onChange={() => {}}
|
onChange={() => {}}
|
||||||
value1={xValue.toFixed(5)}
|
value1={xValue.toFixed(5)}
|
||||||
|
|
|
@ -42,6 +42,8 @@ const SelectionControls: React.FC = () => {
|
||||||
itemsGroupRef.current = itemsGroup;
|
itemsGroupRef.current = itemsGroup;
|
||||||
|
|
||||||
let isSelecting = false;
|
let isSelecting = false;
|
||||||
|
let isRightClick = false;
|
||||||
|
let rightClickMoved = false;
|
||||||
let isCtrlSelecting = false;
|
let isCtrlSelecting = false;
|
||||||
|
|
||||||
const helper = new SelectionHelper(gl);
|
const helper = new SelectionHelper(gl);
|
||||||
|
@ -52,16 +54,23 @@ const SelectionControls: React.FC = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const onPointerDown = (event: PointerEvent) => {
|
const onPointerDown = (event: PointerEvent) => {
|
||||||
if (event.button !== 0) return
|
if (event.button === 2) {
|
||||||
isSelecting = false;
|
isRightClick = true;
|
||||||
isCtrlSelecting = event.ctrlKey;
|
rightClickMoved = false;
|
||||||
if (event.ctrlKey && duplicatedObjects.length === 0) {
|
} else if (event.button === 0) {
|
||||||
if (controls) (controls as any).enabled = false;
|
isSelecting = false;
|
||||||
selectionBox.startPoint.set(pointer.x, pointer.y, 0);
|
isCtrlSelecting = event.ctrlKey;
|
||||||
|
if (event.ctrlKey && duplicatedObjects.length === 0) {
|
||||||
|
if (controls) (controls as any).enabled = false;
|
||||||
|
selectionBox.startPoint.set(pointer.x, pointer.y, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onPointerMove = (event: PointerEvent) => {
|
const onPointerMove = (event: PointerEvent) => {
|
||||||
|
if (isRightClick) {
|
||||||
|
rightClickMoved = true;
|
||||||
|
}
|
||||||
isSelecting = true;
|
isSelecting = true;
|
||||||
if (helper.isDown && event.ctrlKey && duplicatedObjects.length === 0 && isCtrlSelecting) {
|
if (helper.isDown && event.ctrlKey && duplicatedObjects.length === 0 && isCtrlSelecting) {
|
||||||
selectionBox.endPoint.set(pointer.x, pointer.y, 0);
|
selectionBox.endPoint.set(pointer.x, pointer.y, 0);
|
||||||
|
@ -69,6 +78,14 @@ const SelectionControls: React.FC = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const onPointerUp = (event: PointerEvent) => {
|
const onPointerUp = (event: PointerEvent) => {
|
||||||
|
if (event.button === 2) {
|
||||||
|
isRightClick = false;
|
||||||
|
if (!rightClickMoved) {
|
||||||
|
clearSelection();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (isSelecting && isCtrlSelecting) {
|
if (isSelecting && isCtrlSelecting) {
|
||||||
isCtrlSelecting = false;
|
isCtrlSelecting = false;
|
||||||
isSelecting = false;
|
isSelecting = false;
|
||||||
|
@ -94,10 +111,13 @@ const SelectionControls: React.FC = () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const onContextMenu = (event: MouseEvent) => {
|
const onContextMenu = (event: MouseEvent) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
clearSelection();
|
if (!rightClickMoved) {
|
||||||
}
|
clearSelection();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (!toggleView && activeModule === "builder") {
|
if (!toggleView && activeModule === "builder") {
|
||||||
helper.enabled = true;
|
helper.enabled = true;
|
||||||
|
|
|
@ -2,16 +2,22 @@ import { useFloorItems, useSimulationPaths } from '../../../store/store';
|
||||||
import * as THREE from 'three';
|
import * as THREE from 'three';
|
||||||
import * as Types from '../../../types/world/worldTypes';
|
import * as Types from '../../../types/world/worldTypes';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
import { getAssetEventType } from '../../../services/simulation/getAssetEventType';
|
||||||
|
|
||||||
function Behaviour() {
|
function Behaviour() {
|
||||||
const { setSimulationPaths } = useSimulationPaths();
|
const { setSimulationPaths } = useSimulationPaths();
|
||||||
const { floorItems } = useFloorItems();
|
const { floorItems } = useFloorItems();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
const email = localStorage.getItem('email')
|
||||||
|
const organization = (email!.split("@")[1]).split(".")[0];
|
||||||
const newPaths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[] = [];
|
const newPaths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[] = [];
|
||||||
|
|
||||||
floorItems.forEach((item: Types.FloorItemType) => {
|
floorItems.forEach((item: Types.FloorItemType) => {
|
||||||
if (item.modelfileID === "672a090f80d91ac979f4d0bd") {
|
if (item.modelfileID === "672a090f80d91ac979f4d0bd") {
|
||||||
|
// getAssetEventType(item.modelfileID, organization).then((res) => {
|
||||||
|
// console.log('res: ', res);
|
||||||
|
// });
|
||||||
const point1Position = new THREE.Vector3(0, 0.85, 2.2);
|
const point1Position = new THREE.Vector3(0, 0.85, 2.2);
|
||||||
const middlePointPosition = new THREE.Vector3(0, 0.85, 0);
|
const middlePointPosition = new THREE.Vector3(0, 0.85, 0);
|
||||||
const point2Position = new THREE.Vector3(0, 0.85, -2.2);
|
const point2Position = new THREE.Vector3(0, 0.85, -2.2);
|
||||||
|
@ -67,7 +73,7 @@ function Behaviour() {
|
||||||
point: {
|
point: {
|
||||||
uuid: pointUUID,
|
uuid: pointUUID,
|
||||||
position: [pointPosition.x, pointPosition.y, pointPosition.z],
|
position: [pointPosition.x, pointPosition.y, pointPosition.z],
|
||||||
actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Start', start: '', hitCount: 1, end: '', buffer: 0 },
|
actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Start', start: {}, hitCount: 1, end: {}, buffer: 0 },
|
||||||
connections: { source: { pathUUID: item.modeluuid, pointUUID: pointUUID }, targets: [] },
|
connections: { source: { pathUUID: item.modeluuid, pointUUID: pointUUID }, targets: [] },
|
||||||
speed: 2,
|
speed: 2,
|
||||||
},
|
},
|
||||||
|
|
|
@ -96,24 +96,16 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||||
};
|
};
|
||||||
const existingTargets = path.point.connections.targets || [];
|
const existingTargets = path.point.connections.targets || [];
|
||||||
|
|
||||||
// Check if we're trying to add a connection to a Conveyor
|
// Check if target is a Conveyor
|
||||||
const toPath = simulationPaths.find(p => p.modeluuid === toPathUUID);
|
const toPath = simulationPaths.find(p => p.modeluuid === toPathUUID);
|
||||||
const isConnectingToConveyor = toPath?.type === 'Conveyor';
|
if (toPath?.type !== 'Conveyor') {
|
||||||
|
console.log("Vehicle can only connect to Conveyors");
|
||||||
// Count existing connections
|
|
||||||
if (existingTargets.length >= 2) {
|
|
||||||
console.log("Vehicle can have maximum 2 connections");
|
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we already have a Conveyor connection and trying to add another
|
// Check if already has a connection
|
||||||
const hasConveyorConnection = existingTargets.some(target => {
|
if (existingTargets.length >= 1) {
|
||||||
const targetPath = simulationPaths.find(p => p.modeluuid === target.pathUUID);
|
console.log("Vehicle can have only one connection");
|
||||||
return targetPath?.type === 'Conveyor';
|
|
||||||
});
|
|
||||||
|
|
||||||
if (hasConveyorConnection && isConnectingToConveyor) {
|
|
||||||
console.log("Vehicle can only have one connection to a Conveyor");
|
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,24 +133,16 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||||
};
|
};
|
||||||
const existingTargets = path.point.connections.targets || [];
|
const existingTargets = path.point.connections.targets || [];
|
||||||
|
|
||||||
// Check if we're receiving a connection from a Conveyor
|
// Check if source is a Conveyor
|
||||||
const fromPath = simulationPaths.find(p => p.modeluuid === fromPathUUID);
|
const fromPath = simulationPaths.find(p => p.modeluuid === fromPathUUID);
|
||||||
const isConnectingFromConveyor = fromPath?.type === 'Conveyor';
|
if (fromPath?.type !== 'Conveyor') {
|
||||||
|
console.log("Vehicle can only connect to Conveyors");
|
||||||
// Count existing connections
|
|
||||||
if (existingTargets.length >= 2) {
|
|
||||||
console.log("Vehicle can have maximum 2 connections");
|
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we already have a Conveyor connection and trying to add another
|
// Check if already has a connection
|
||||||
const hasConveyorConnection = existingTargets.some(target => {
|
if (existingTargets.length >= 1) {
|
||||||
const targetPath = simulationPaths.find(p => p.modeluuid === target.pathUUID);
|
console.log("Vehicle can have only one connection");
|
||||||
return targetPath?.type === 'Conveyor';
|
|
||||||
});
|
|
||||||
|
|
||||||
if (hasConveyorConnection && isConnectingFromConveyor) {
|
|
||||||
console.log("Vehicle can only have one connection to a Conveyor");
|
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,6 +196,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||||
drag = true;
|
drag = true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onContextMenu = (evt: MouseEvent) => {
|
const onContextMenu = (evt: MouseEvent) => {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
if (drag || evt.button === 0) return;
|
if (drag || evt.button === 0) return;
|
||||||
|
@ -282,7 +267,16 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For Vehicles, skip the "already connected" check since they can have multiple connections
|
// For Vehicles, check if they're already connected to anything
|
||||||
|
if (intersected.userData.path.type === 'Vehicle') {
|
||||||
|
const vehicleConnections = intersected.userData.path.point.connections.targets.length;
|
||||||
|
if (vehicleConnections >= 1) {
|
||||||
|
console.log("Vehicle can only have one connection");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For non-Vehicle paths, check if already connected
|
||||||
if (intersected.userData.path.type !== 'Vehicle') {
|
if (intersected.userData.path.type !== 'Vehicle') {
|
||||||
const isAlreadyConnected = simulationPaths.some(path => {
|
const isAlreadyConnected = simulationPaths.some(path => {
|
||||||
if (path.type === 'Conveyor') {
|
if (path.type === 'Conveyor') {
|
||||||
|
@ -300,48 +294,14 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check vehicle connection limits
|
|
||||||
const checkVehicleConnections = (pathUUID: string) => {
|
|
||||||
const path = simulationPaths.find(p => p.modeluuid === pathUUID);
|
|
||||||
if (path?.type === 'Vehicle') {
|
|
||||||
return path.point.connections.targets.length >= 2;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (firstSelected) {
|
if (firstSelected) {
|
||||||
// Check if either selected point is from a Vehicle with max connections
|
// Check if trying to connect Vehicle to non-Conveyor
|
||||||
if (checkVehicleConnections(firstSelected.pathUUID) ||
|
if ((firstPath?.type === 'Vehicle' && secondPath?.type !== 'Conveyor') ||
|
||||||
checkVehicleConnections(pathUUID)) {
|
(secondPath?.type === 'Vehicle' && firstPath?.type !== 'Conveyor')) {
|
||||||
console.log("Vehicle already has maximum connections");
|
console.log("Vehicle can only connect to Conveyors");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we're trying to add a second Conveyor connection to a Vehicle
|
|
||||||
if (firstPath?.type === 'Vehicle' && secondPath?.type === 'Conveyor') {
|
|
||||||
const hasConveyorConnection = firstPath.point.connections.targets.some(target => {
|
|
||||||
const targetPath = simulationPaths.find(p => p.modeluuid === target.pathUUID);
|
|
||||||
return targetPath?.type === 'Conveyor';
|
|
||||||
});
|
|
||||||
|
|
||||||
if (hasConveyorConnection) {
|
|
||||||
console.log("Vehicle can only have one connection to a Conveyor");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (secondPath?.type === 'Vehicle' && firstPath?.type === 'Conveyor') {
|
|
||||||
const hasConveyorConnection = secondPath.point.connections.targets.some(target => {
|
|
||||||
const targetPath = simulationPaths.find(p => p.modeluuid === target.pathUUID);
|
|
||||||
return targetPath?.type === 'Conveyor';
|
|
||||||
});
|
|
||||||
|
|
||||||
if (hasConveyorConnection) {
|
|
||||||
console.log("Vehicle can only have one connection to a Conveyor");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prevent same-path connections
|
// Prevent same-path connections
|
||||||
if (firstSelected.pathUUID === pathUUID) {
|
if (firstSelected.pathUUID === pathUUID) {
|
||||||
console.log("Cannot connect spheres on the same path.");
|
console.log("Cannot connect spheres on the same path.");
|
||||||
|
@ -478,28 +438,19 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Check vehicle connection limits
|
// Check vehicle connection rules
|
||||||
const isVehicleAtMaxConnections = pathData.type === 'Vehicle' &&
|
const isVehicleAtMaxConnections = pathData.type === 'Vehicle' &&
|
||||||
pathData.point.connections.targets.length >= 2;
|
pathData.point.connections.targets.length >= 1;
|
||||||
|
const isVehicleConnectingToNonConveyor =
|
||||||
const isVehicleConveyorConflict =
|
(firstPath?.type === 'Vehicle' && secondPath?.type !== 'Conveyor') ||
|
||||||
(firstPath?.type === 'Vehicle' && secondPath?.type === 'Conveyor' &&
|
(secondPath?.type === 'Vehicle' && firstPath?.type !== 'Conveyor');
|
||||||
firstPath.point.connections.targets.some(t => {
|
|
||||||
const targetPath = simulationPaths.find(p => p.modeluuid === t.pathUUID);
|
|
||||||
return targetPath?.type === 'Conveyor';
|
|
||||||
})) ||
|
|
||||||
(secondPath?.type === 'Vehicle' && firstPath?.type === 'Conveyor' &&
|
|
||||||
secondPath.point.connections.targets.some(t => {
|
|
||||||
const targetPath = simulationPaths.find(p => p.modeluuid === t.pathUUID);
|
|
||||||
return targetPath?.type === 'Conveyor';
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!isDuplicateConnection &&
|
!isDuplicateConnection &&
|
||||||
!isVehicleToVehicle &&
|
!isVehicleToVehicle &&
|
||||||
!isNonVehicleAlreadyConnected &&
|
!isNonVehicleAlreadyConnected &&
|
||||||
!isVehicleAtMaxConnections &&
|
!isVehicleAtMaxConnections &&
|
||||||
!isVehicleConveyorConflict &&
|
!isVehicleConnectingToNonConveyor &&
|
||||||
firstSelected.sphereUUID !== sphereUUID &&
|
firstSelected.sphereUUID !== sphereUUID &&
|
||||||
firstSelected.pathUUID !== pathUUID &&
|
firstSelected.pathUUID !== pathUUID &&
|
||||||
(firstSelected.isCorner || isConnectable)
|
(firstSelected.isCorner || isConnectable)
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import * as THREE from 'three';
|
import * as THREE from 'three';
|
||||||
import * as Types from '../../../types/world/worldTypes';
|
import * as Types from '../../../types/world/worldTypes';
|
||||||
import { useRef, useState, useEffect } from 'react';
|
import { useRef, useState, useEffect, useMemo } from 'react';
|
||||||
import { Sphere, TransformControls } from '@react-three/drei';
|
import { Sphere, TransformControls } from '@react-three/drei';
|
||||||
import { useIsConnecting, useRenderDistance, useSelectedActionSphere, useSelectedPath, useSimulationPaths } from '../../../store/store';
|
import { useEditingPoint, useEyeDropMode, useIsConnecting, usePreviewPosition, useRenderDistance, useSelectedActionSphere, useSelectedPath, useSimulationPaths } from '../../../store/store';
|
||||||
import { useFrame, useThree } from '@react-three/fiber';
|
import { useFrame, useThree } from '@react-three/fiber';
|
||||||
import { useSubModuleStore } from '../../../store/useModuleStore';
|
import { useSubModuleStore } from '../../../store/useModuleStore';
|
||||||
|
|
||||||
|
@ -10,13 +10,18 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject
|
||||||
const { renderDistance } = useRenderDistance();
|
const { renderDistance } = useRenderDistance();
|
||||||
const { setSubModule } = useSubModuleStore();
|
const { setSubModule } = useSubModuleStore();
|
||||||
const { setSelectedActionSphere, selectedActionSphere } = useSelectedActionSphere();
|
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 { setSelectedPath } = useSelectedPath();
|
||||||
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
||||||
const { isConnecting } = useIsConnecting();
|
const { isConnecting } = useIsConnecting();
|
||||||
const { camera } = useThree();
|
|
||||||
|
|
||||||
const groupRefs = useRef<{ [key: string]: THREE.Group }>({});
|
const groupRefs = useRef<{ [key: string]: THREE.Group }>({});
|
||||||
const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({});
|
const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({});
|
||||||
|
const isMovingRef = useRef(false);
|
||||||
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);
|
||||||
|
|
||||||
|
@ -77,6 +82,83 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject
|
||||||
setSimulationPaths(updatedPaths);
|
setSimulationPaths(updatedPaths);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!camera) return;
|
||||||
|
const canvasElement = gl.domElement;
|
||||||
|
canvasElement.tabIndex = 0;
|
||||||
|
|
||||||
|
|
||||||
|
const onPointerDown = () => {
|
||||||
|
isMovingRef.current = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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]);
|
||||||
|
|
||||||
|
const handlePointUpdate = (pointType: 'start' | 'end', x: number, z: number) => {
|
||||||
|
if (!selectedActionSphere?.point?.uuid) return;
|
||||||
|
|
||||||
|
const updatedPaths = simulationPaths.map((path) => {
|
||||||
|
if (path.type === "Vehicle" && path.point.uuid === selectedActionSphere.point.uuid) {
|
||||||
|
return {
|
||||||
|
...path,
|
||||||
|
point: {
|
||||||
|
...path.point,
|
||||||
|
actions: {
|
||||||
|
...path.point.actions,
|
||||||
|
[pointType]: {
|
||||||
|
...path.point.actions[pointType],
|
||||||
|
x: x,
|
||||||
|
y: z
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
});
|
||||||
|
|
||||||
|
setSimulationPaths(updatedPaths);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<group name='simulation-simulationPaths-group' ref={pathsGroupRef}>
|
<group name='simulation-simulationPaths-group' ref={pathsGroupRef}>
|
||||||
|
@ -92,7 +174,7 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject
|
||||||
position={path.assetPosition}
|
position={path.assetPosition}
|
||||||
rotation={path.assetRotation}
|
rotation={path.assetRotation}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
if (isConnecting) return;
|
if (isConnecting || eyeDropMode) return;
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setSelectedPath({ path, group: groupRefs.current[path.modeluuid] });
|
setSelectedPath({ path, group: groupRefs.current[path.modeluuid] });
|
||||||
setSelectedActionSphere(null);
|
setSelectedActionSphere(null);
|
||||||
|
@ -100,6 +182,7 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject
|
||||||
setSubModule('mechanics');
|
setSubModule('mechanics');
|
||||||
}}
|
}}
|
||||||
onPointerMissed={() => {
|
onPointerMissed={() => {
|
||||||
|
if (eyeDropMode) return;
|
||||||
setSelectedPath(null);
|
setSelectedPath(null);
|
||||||
setSubModule('properties');
|
setSubModule('properties');
|
||||||
}}
|
}}
|
||||||
|
@ -113,7 +196,7 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject
|
||||||
name='events-sphere'
|
name='events-sphere'
|
||||||
ref={el => (sphereRefs.current[point.uuid] = el!)}
|
ref={el => (sphereRefs.current[point.uuid] = el!)}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
if (isConnecting) return;
|
if (isConnecting || eyeDropMode) return;
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setSelectedActionSphere({
|
setSelectedActionSphere({
|
||||||
path,
|
path,
|
||||||
|
@ -124,6 +207,7 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject
|
||||||
}}
|
}}
|
||||||
userData={{ point, path }}
|
userData={{ point, path }}
|
||||||
onPointerMissed={() => {
|
onPointerMissed={() => {
|
||||||
|
if (eyeDropMode) return;
|
||||||
setSubModule('properties');
|
setSubModule('properties');
|
||||||
setSelectedActionSphere(null);
|
setSelectedActionSphere(null);
|
||||||
}}
|
}}
|
||||||
|
@ -155,7 +239,7 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject
|
||||||
ref={el => (groupRefs.current[path.modeluuid] = el!)}
|
ref={el => (groupRefs.current[path.modeluuid] = el!)}
|
||||||
position={path.assetPosition}
|
position={path.assetPosition}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
if (isConnecting) return;
|
if (isConnecting || eyeDropMode) return;
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setSelectedPath({ path, group: groupRefs.current[path.modeluuid] });
|
setSelectedPath({ path, group: groupRefs.current[path.modeluuid] });
|
||||||
setSelectedActionSphere(null);
|
setSelectedActionSphere(null);
|
||||||
|
@ -163,6 +247,7 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject
|
||||||
setSubModule('mechanics');
|
setSubModule('mechanics');
|
||||||
}}
|
}}
|
||||||
onPointerMissed={() => {
|
onPointerMissed={() => {
|
||||||
|
if (eyeDropMode) return;
|
||||||
setSelectedPath(null);
|
setSelectedPath(null);
|
||||||
setSubModule('properties');
|
setSubModule('properties');
|
||||||
}}
|
}}
|
||||||
|
@ -175,7 +260,7 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject
|
||||||
name='events-sphere'
|
name='events-sphere'
|
||||||
ref={el => (sphereRefs.current[path.point.uuid] = el!)}
|
ref={el => (sphereRefs.current[path.point.uuid] = el!)}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
if (isConnecting) return;
|
if (isConnecting || eyeDropMode) return;
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setSelectedActionSphere({
|
setSelectedActionSphere({
|
||||||
path,
|
path,
|
||||||
|
@ -186,6 +271,7 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject
|
||||||
}}
|
}}
|
||||||
userData={{ point: path.point, path }}
|
userData={{ point: path.point, path }}
|
||||||
onPointerMissed={() => {
|
onPointerMissed={() => {
|
||||||
|
if (eyeDropMode) return;
|
||||||
setSubModule('properties');
|
setSubModule('properties');
|
||||||
setSelectedActionSphere(null);
|
setSelectedActionSphere(null);
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { useState, useEffect, useRef } from 'react';
|
import { useState, useEffect, useRef, useMemo } from 'react';
|
||||||
import { useSelectedActionSphere, useSelectedPath, useSimulationPaths } from '../../store/store';
|
import { useSelectedActionSphere, useSelectedPath, useSimulationPaths } from '../../store/store';
|
||||||
import { useThree } from '@react-three/fiber';
|
|
||||||
import * as THREE from 'three';
|
import * as THREE from 'three';
|
||||||
import Behaviour from './behaviour/behaviour';
|
import Behaviour from './behaviour/behaviour';
|
||||||
import PathCreation from './path/pathCreation';
|
import PathCreation from './path/pathCreation';
|
||||||
|
@ -29,9 +28,10 @@ function Simulation() {
|
||||||
// }
|
// }
|
||||||
// }, [selectedPath]);
|
// }, [selectedPath]);
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Behaviour/>
|
<Behaviour />
|
||||||
{activeModule === 'simulation' && (
|
{activeModule === 'simulation' && (
|
||||||
<>
|
<>
|
||||||
<PathCreation pathsGroupRef={pathsGroupRef} />
|
<PathCreation pathsGroupRef={pathsGroupRef} />
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
let url_Backend_dwinzo = `http://${process.env.REACT_APP_TEST}`;
|
||||||
|
|
||||||
|
export const getAssetEventType = async (modelId: string, organization: string) => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${url_Backend_dwinzo}/api/v2/pointData/${modelId}/${organization}`, {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error("Failed to fetch model event type");
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
console.log('result: ', result);
|
||||||
|
return result;
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
throw new Error(error.message);
|
||||||
|
} else {
|
||||||
|
throw new Error("An unknown error occurred");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
|
@ -348,10 +348,30 @@ export const useStartSimulation = create<any>((set: any) => ({
|
||||||
startSimulation: false,
|
startSimulation: false,
|
||||||
setStartSimulation: (x: any) => set({ startSimulation: x }),
|
setStartSimulation: (x: any) => set({ startSimulation: x }),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
export const useEyeDropMode = create<any>((set: any) => ({
|
||||||
|
eyeDropMode: false,
|
||||||
|
setEyeDropMode: (x: any) => set({ eyeDropMode: x }),
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const useEditingPoint = create<any>((set: any) => ({
|
||||||
|
editingPoint: false,
|
||||||
|
setEditingPoint: (x: any) => set({ editingPoint: x }),
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const usePreviewPosition = create<{
|
||||||
|
previewPosition: { x: number; y: number } | null;
|
||||||
|
setPreviewPosition: (position: { x: number; y: number } | null) => void;
|
||||||
|
}>((set) => ({
|
||||||
|
previewPosition: null,
|
||||||
|
setPreviewPosition: (position) => set({ previewPosition: position }),
|
||||||
|
}));
|
||||||
|
|
||||||
export const usezoneTarget = create<any>((set: any) => ({
|
export const usezoneTarget = create<any>((set: any) => ({
|
||||||
zoneTarget: [],
|
zoneTarget: [],
|
||||||
setZoneTarget: (x: any) => set({ zoneTarget: x }),
|
setZoneTarget: (x: any) => set({ zoneTarget: x }),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const usezonePosition = create<any>((set: any) => ({
|
export const usezonePosition = create<any>((set: any) => ({
|
||||||
zonePosition: [],
|
zonePosition: [],
|
||||||
setZonePosition: (x: any) => set({ zonePosition: x }),
|
setZonePosition: (x: any) => set({ zonePosition: x }),
|
||||||
|
@ -371,6 +391,7 @@ export const useAsset3dWidget = create<any>((set: any) => ({
|
||||||
widgetSelect: "",
|
widgetSelect: "",
|
||||||
setWidgetSelect: (x: any) => set({ widgetSelect: x }),
|
setWidgetSelect: (x: any) => set({ widgetSelect: x }),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const useWidgetSubOption = create<any>((set: any) => ({
|
export const useWidgetSubOption = create<any>((set: any) => ({
|
||||||
widgetSubOption: "2D",
|
widgetSubOption: "2D",
|
||||||
setWidgetSubOption: (x: any) => set({ widgetSubOption: x }),
|
setWidgetSubOption: (x: any) => set({ widgetSubOption: x }),
|
||||||
|
|
|
@ -310,7 +310,7 @@ interface VehicleEventsSchema {
|
||||||
point: {
|
point: {
|
||||||
uuid: string;
|
uuid: string;
|
||||||
position: [number, number, number];
|
position: [number, number, number];
|
||||||
actions: { uuid: string; name: string; type: string; start: string, hitCount: number, end: string, buffer: number };
|
actions: { uuid: string; name: string; type: string; start: { x: number, y: number } | {}, hitCount: number, end: { x: number, y: number } | {}, buffer: number };
|
||||||
connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] };
|
connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] };
|
||||||
speed: number;
|
speed: number;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue