Refactor MoveControls and TransformControls for improved asset manipulation
- Cleaned up MoveControls component by removing unused variables and optimizing event handling. - Enhanced asset movement logic with better key event detection and state management. - Removed deprecated transform mode state from store. - Updated worldTypes to remove unnecessary positionY property. - Introduced TransformControls component for handling object transformations (translate/rotate) with proper state management and backend updates. - Implemented event handling for mouse actions and keyboard shortcuts to toggle transformation modes.
This commit is contained in:
parent
b1569e64ed
commit
ecab03c5f0
|
@ -234,14 +234,16 @@ const Assets: React.FC = () => {
|
||||||
alt={asset.filename}
|
alt={asset.filename}
|
||||||
className="asset-image"
|
className="asset-image"
|
||||||
onPointerDown={() => {
|
onPointerDown={() => {
|
||||||
setSelectedItem({
|
if (asset.category !== 'Feneration') {
|
||||||
name: asset.filename,
|
setSelectedItem({
|
||||||
id: asset.AssetID,
|
name: asset.filename,
|
||||||
type:
|
id: asset.AssetID,
|
||||||
asset.type === "undefined"
|
type:
|
||||||
? undefined
|
asset.type === "undefined"
|
||||||
: asset.type,
|
? undefined
|
||||||
});
|
: asset.type,
|
||||||
|
});
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div className="asset-name">
|
<div className="asset-name">
|
||||||
|
|
|
@ -29,7 +29,6 @@ import {
|
||||||
useSocketStore,
|
useSocketStore,
|
||||||
useToggleView,
|
useToggleView,
|
||||||
useToolMode,
|
useToolMode,
|
||||||
useTransformMode,
|
|
||||||
useActiveSubTool,
|
useActiveSubTool,
|
||||||
} from "../../store/store";
|
} from "../../store/store";
|
||||||
import useToggleStore from "../../store/useUIToggleStore";
|
import useToggleStore from "../../store/useUIToggleStore";
|
||||||
|
@ -61,7 +60,6 @@ const Tools: React.FC = () => {
|
||||||
const { setAddAction } = useAddAction();
|
const { setAddAction } = useAddAction();
|
||||||
const { setSelectedWallItem } = useSelectedWallItem();
|
const { setSelectedWallItem } = useSelectedWallItem();
|
||||||
|
|
||||||
const { setTransformMode } = useTransformMode();
|
|
||||||
const { setDeletePointOrLine } = useDeletePointOrLine();
|
const { setDeletePointOrLine } = useDeletePointOrLine();
|
||||||
const { setToolMode } = useToolMode();
|
const { setToolMode } = useToolMode();
|
||||||
const { activeTool, setActiveTool } = useActiveTool();
|
const { activeTool, setActiveTool } = useActiveTool();
|
||||||
|
@ -126,7 +124,6 @@ const Tools: React.FC = () => {
|
||||||
setToolMode(null);
|
setToolMode(null);
|
||||||
setDeleteTool(false);
|
setDeleteTool(false);
|
||||||
setAddAction(null);
|
setAddAction(null);
|
||||||
setTransformMode(null);
|
|
||||||
setDeletePointOrLine(false);
|
setDeletePointOrLine(false);
|
||||||
setRefTextUpdate((prevUpdate) => prevUpdate - 1);
|
setRefTextUpdate((prevUpdate) => prevUpdate - 1);
|
||||||
|
|
||||||
|
@ -134,20 +131,6 @@ const Tools: React.FC = () => {
|
||||||
case "cursor":
|
case "cursor":
|
||||||
if (toggleView) {
|
if (toggleView) {
|
||||||
setToolMode('move');
|
setToolMode('move');
|
||||||
} else {
|
|
||||||
setTransformMode("translate");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "Rotate":
|
|
||||||
if (!toggleView) {
|
|
||||||
setTransformMode("rotate");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "Scale":
|
|
||||||
if (!toggleView) {
|
|
||||||
setTransformMode("scale");
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -54,57 +54,57 @@ import NavMesh from "../simulation/vehicle/navMesh/navMesh";
|
||||||
import CalculateAreaGroup from "./groups/calculateAreaGroup";
|
import CalculateAreaGroup from "./groups/calculateAreaGroup";
|
||||||
|
|
||||||
export default function Builder() {
|
export default function Builder() {
|
||||||
const state = useThree<Types.ThreeState>(); // Importing the state from the useThree hook, which contains the scene, camera, and other Three.js elements.
|
const state = useThree<Types.ThreeState>(); // Importing the state from the useThree hook, which contains the scene, camera, and other Three.js elements.
|
||||||
const csg = useRef(); // Reference for CSG object, used for 3D modeling.
|
const csg = useRef(); // Reference for CSG object, used for 3D modeling.
|
||||||
const CSGGroup = useRef() as Types.RefMesh; // Reference to a group of CSG objects.
|
const CSGGroup = useRef() as Types.RefMesh; // Reference to a group of CSG objects.
|
||||||
const scene = useRef() as Types.RefScene; // Reference to the scene.
|
const scene = useRef() as Types.RefScene; // Reference to the scene.
|
||||||
const camera = useRef() as Types.RefCamera; // Reference to the camera object.
|
const camera = useRef() as Types.RefCamera; // Reference to the camera object.
|
||||||
const controls = useRef<any>(); // Reference to the controls object.
|
const controls = useRef<any>(); // Reference to the controls object.
|
||||||
const raycaster = useRef() as Types.RefRaycaster; // Reference for raycaster used for detecting objects being pointed at in the scene.
|
const raycaster = useRef() as Types.RefRaycaster; // Reference for raycaster used for detecting objects being pointed at in the scene.
|
||||||
const dragPointControls = useRef() as Types.RefDragControl; // Reference for drag point controls, an array for drag control.
|
const dragPointControls = useRef() as Types.RefDragControl; // Reference for drag point controls, an array for drag control.
|
||||||
|
|
||||||
// Assigning the scene and camera from the Three.js state to the references.
|
// Assigning the scene and camera from the Three.js state to the references.
|
||||||
|
|
||||||
scene.current = state.scene;
|
scene.current = state.scene;
|
||||||
camera.current = state.camera;
|
camera.current = state.camera;
|
||||||
controls.current = state.controls;
|
controls.current = state.controls;
|
||||||
raycaster.current = state.raycaster;
|
raycaster.current = state.raycaster;
|
||||||
|
|
||||||
const plane = useRef<THREE.Mesh>(null); // Reference for a plane object for raycaster reference.
|
const plane = useRef<THREE.Mesh>(null); // Reference for a plane object for raycaster reference.
|
||||||
const grid = useRef() as any; // Reference for a grid object for raycaster reference.
|
const grid = useRef() as any; // Reference for a grid object for raycaster reference.
|
||||||
const snappedPoint = useRef() as Types.RefVector3; // Reference for storing a snapped point at the (end = isSnapped) and (start = ispreSnapped) of the line.
|
const snappedPoint = useRef() as Types.RefVector3; // Reference for storing a snapped point at the (end = isSnapped) and (start = ispreSnapped) of the line.
|
||||||
const isSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (end).
|
const isSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (end).
|
||||||
const anglesnappedPoint = useRef() as Types.RefVector3; // Reference for storing an angle-snapped point when the line is in 90 degree etc...
|
const anglesnappedPoint = useRef() as Types.RefVector3; // Reference for storing an angle-snapped point when the line is in 90 degree etc...
|
||||||
const isAngleSnapped = useRef(false) as Types.RefBoolean; // Boolean to indicate if angle snapping is active.
|
const isAngleSnapped = useRef(false) as Types.RefBoolean; // Boolean to indicate if angle snapping is active.
|
||||||
const isSnappedUUID = useRef() as Types.RefString; // UUID reference to identify the snapped point.
|
const isSnappedUUID = useRef() as Types.RefString; // UUID reference to identify the snapped point.
|
||||||
const ispreSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (start).
|
const ispreSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (start).
|
||||||
const tempLoader = useRef() as Types.RefMesh; // Reference for a temporary loader for the floor items.
|
const tempLoader = useRef() as Types.RefMesh; // Reference for a temporary loader for the floor items.
|
||||||
const isTempLoader = useRef() as Types.RefBoolean; // Reference to check if a temporary loader is active.
|
const isTempLoader = useRef() as Types.RefBoolean; // Reference to check if a temporary loader is active.
|
||||||
const Tube = useRef() as Types.RefTubeGeometry; // Reference for tubes used for reference line creation and updation.
|
const Tube = useRef() as Types.RefTubeGeometry; // Reference for tubes used for reference line creation and updation.
|
||||||
const line = useRef([]) as Types.RefLine; // Reference for line which stores the current line that is being drawn.
|
const line = useRef([]) as Types.RefLine; // Reference for line which stores the current line that is being drawn.
|
||||||
const lines = useRef([]) as Types.RefLines; // Reference for lines which stores all the lines that are ever drawn.
|
const lines = useRef([]) as Types.RefLines; // Reference for lines which stores all the lines that are ever drawn.
|
||||||
const onlyFloorline = useRef<Types.OnlyFloorLine>([]); // Reference for floor lines which does not have walls or roof and have only floor used to store the current line that is being drawn.
|
const onlyFloorline = useRef<Types.OnlyFloorLine>([]); // Reference for floor lines which does not have walls or roof and have only floor used to store the current line that is being drawn.
|
||||||
const onlyFloorlines = useRef<Types.OnlyFloorLines>([]); // Reference for all the floor lines that are ever drawn.
|
const onlyFloorlines = useRef<Types.OnlyFloorLines>([]); // Reference for all the floor lines that are ever drawn.
|
||||||
const ReferenceLineMesh = useRef() as Types.RefMesh; // Reference for storing the mesh of the reference line for moving it during draw.
|
const ReferenceLineMesh = useRef() as Types.RefMesh; // Reference for storing the mesh of the reference line for moving it during draw.
|
||||||
const LineCreated = useRef(false) as Types.RefBoolean; // Boolean to track whether the reference line is created or not.
|
const LineCreated = useRef(false) as Types.RefBoolean; // Boolean to track whether the reference line is created or not.
|
||||||
const referencePole = useRef() as Types.RefMesh; // Reference for a pole that is used as the reference for the user to show where it is placed.
|
const referencePole = useRef() as Types.RefMesh; // Reference for a pole that is used as the reference for the user to show where it is placed.
|
||||||
const itemsGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the floor items (Gltf).
|
const itemsGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the floor items (Gltf).
|
||||||
const floorGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the roofs and the floors.
|
const floorGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the roofs and the floors.
|
||||||
const AttachedObject = useRef() as Types.RefMesh; // Reference for an object that is attached using dbl click for transform controls rotation.
|
const AttachedObject = useRef() as Types.RefMesh; // Reference for an object that is attached using dbl click for transform controls rotation.
|
||||||
const floorPlanGroup = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines group and the points group.
|
const floorPlanGroup = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines group and the points group.
|
||||||
const floorPlanGroupLine = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines that are drawn.
|
const floorPlanGroupLine = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines that are drawn.
|
||||||
const floorPlanGroupPoint = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the points that are created.
|
const floorPlanGroupPoint = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the points that are created.
|
||||||
const floorGroupAisle = useRef() as Types.RefGroup;
|
const floorGroupAisle = useRef() as Types.RefGroup;
|
||||||
const zoneGroup = useRef() as Types.RefGroup;
|
const zoneGroup = useRef() as Types.RefGroup;
|
||||||
const currentLayerPoint = useRef([]) as Types.RefMeshArray; // Reference for points that re in the current layer used to update the points in drag controls.
|
const currentLayerPoint = useRef([]) as Types.RefMeshArray; // Reference for points that re in the current layer used to update the points in drag controls.
|
||||||
const hoveredDeletablePoint = useRef() as Types.RefMesh; // Reference for the currently hovered point that can be deleted.
|
const hoveredDeletablePoint = useRef() as Types.RefMesh; // Reference for the currently hovered point that can be deleted.
|
||||||
const hoveredDeletableLine = useRef() as Types.RefMesh; // Reference for the currently hovered line that can be deleted.
|
const hoveredDeletableLine = useRef() as Types.RefMesh; // Reference for the currently hovered line that can be deleted.
|
||||||
const hoveredDeletableFloorItem = useRef() as Types.RefMesh; // Reference for the currently hovered floor item that can be deleted.
|
const hoveredDeletableFloorItem = useRef() as Types.RefMesh; // Reference for the currently hovered floor item that can be deleted.
|
||||||
const hoveredDeletableWallItem = useRef() as Types.RefMesh; // Reference for the currently hovered wall item that can be deleted.
|
const hoveredDeletableWallItem = useRef() as Types.RefMesh; // Reference for the currently hovered wall item that can be deleted.
|
||||||
const hoveredDeletablePillar = useRef() as Types.RefMesh; // Reference for the currently hovered pillar that can be deleted.
|
const hoveredDeletablePillar = useRef() as Types.RefMesh; // Reference for the currently hovered pillar that can be deleted.
|
||||||
const currentWallItem = useRef() as Types.RefMesh; // Reference for the currently selected wall item that can be scaled, dragged etc...
|
const currentWallItem = useRef() as Types.RefMesh; // Reference for the currently selected wall item that can be scaled, dragged etc...
|
||||||
|
|
||||||
const cursorPosition = new THREE.Vector3(); // 3D vector for storing the cursor position.
|
const cursorPosition = new THREE.Vector3(); // 3D vector for storing the cursor position.
|
||||||
|
|
||||||
const [selectedItemsIndex, setSelectedItemsIndex] = useState<Types.Number | null>(null); // State for tracking the index of the selected item.
|
const [selectedItemsIndex, setSelectedItemsIndex] = useState<Types.Number | null>(null); // State for tracking the index of the selected item.
|
||||||
const { activeLayer } = useActiveLayer(); // State that changes based on which layer the user chooses in Layers.jsx.
|
const { activeLayer } = useActiveLayer(); // State that changes based on which layer the user chooses in Layers.jsx.
|
||||||
|
@ -120,42 +120,39 @@ export default function Builder() {
|
||||||
const { setWalls } = useWalls();
|
const { setWalls } = useWalls();
|
||||||
const { refTextupdate, setRefTextUpdate } = useRefTextUpdate();
|
const { refTextupdate, setRefTextUpdate } = useRefTextUpdate();
|
||||||
|
|
||||||
// const loader = new GLTFLoader();
|
// const loader = new GLTFLoader();
|
||||||
// const dracoLoader = new DRACOLoader();
|
// const dracoLoader = new DRACOLoader();
|
||||||
|
|
||||||
// dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/');
|
// dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/');
|
||||||
// loader.setDRACOLoader(dracoLoader);
|
// loader.setDRACOLoader(dracoLoader);
|
||||||
|
|
||||||
////////// Assest Configuration Values //////////
|
////////// Assest Configuration Values //////////
|
||||||
|
|
||||||
const AssetConfigurations: Types.AssetConfigurations = {
|
const AssetConfigurations: Types.AssetConfigurations = {
|
||||||
arch: {
|
arch: {
|
||||||
modelUrl: arch,
|
modelUrl: arch,
|
||||||
scale: [0.75, 0.75, 0.75],
|
scale: [0.75, 0.75, 0.75],
|
||||||
csgscale: [2, 4, 0.5],
|
csgscale: [2, 4, 0.5],
|
||||||
csgposition: [0, 2, 0],
|
csgposition: [0, 2, 0],
|
||||||
positionY: () => 0,
|
type: "Fixed-Move",
|
||||||
type: "Fixed-Move",
|
},
|
||||||
},
|
door: {
|
||||||
door: {
|
modelUrl: door,
|
||||||
modelUrl: door,
|
scale: [0.75, 0.75, 0.75],
|
||||||
scale: [0.75, 0.75, 0.75],
|
csgscale: [2, 4, 0.5],
|
||||||
csgscale: [2, 4, 0.5],
|
csgposition: [0, 2, 0],
|
||||||
csgposition: [0, 2, 0],
|
type: "Fixed-Move",
|
||||||
positionY: () => 0,
|
},
|
||||||
type: "Fixed-Move",
|
window: {
|
||||||
},
|
modelUrl: Window,
|
||||||
window: {
|
scale: [0.75, 0.75, 0.75],
|
||||||
modelUrl: Window,
|
csgscale: [5, 3, 0.5],
|
||||||
scale: [0.75, 0.75, 0.75],
|
csgposition: [0, 1.5, 0],
|
||||||
csgscale: [5, 3, 0.5],
|
type: "Free-Move",
|
||||||
csgposition: [0, 1.5, 0],
|
},
|
||||||
positionY: (intersectionPoint) => intersectionPoint.point.y,
|
};
|
||||||
type: "Free-Move",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
////////// All Toggle's //////////
|
////////// All Toggle's //////////
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setRefTextUpdate((prevUpdate: number) => prevUpdate - 1);
|
setRefTextUpdate((prevUpdate: number) => prevUpdate - 1);
|
||||||
|
@ -177,167 +174,167 @@ export default function Builder() {
|
||||||
}
|
}
|
||||||
}, [toggleView]);
|
}, [toggleView]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
THREE.Cache.clear();
|
THREE.Cache.clear();
|
||||||
THREE.Cache.enabled = true;
|
THREE.Cache.enabled = true;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const email = localStorage.getItem("email");
|
const email = localStorage.getItem("email");
|
||||||
const organization = email!.split("@")[1].split(".")[0];
|
const organization = email!.split("@")[1].split(".")[0];
|
||||||
|
|
||||||
async function fetchVisibility() {
|
async function fetchVisibility() {
|
||||||
const visibility = await findEnvironment(
|
const visibility = await findEnvironment(
|
||||||
organization,
|
organization,
|
||||||
localStorage.getItem("userId")!
|
localStorage.getItem("userId")!
|
||||||
);
|
);
|
||||||
if (visibility) {
|
if (visibility) {
|
||||||
setRoofVisibility(visibility.roofVisibility);
|
setRoofVisibility(visibility.roofVisibility);
|
||||||
setWallVisibility(visibility.wallVisibility);
|
setWallVisibility(visibility.wallVisibility);
|
||||||
setShadows(visibility.shadowVisibility);
|
setShadows(visibility.shadowVisibility);
|
||||||
setRenderDistance(visibility.renderDistance);
|
setRenderDistance(visibility.renderDistance);
|
||||||
setLimitDistance(visibility.limitDistance);
|
setLimitDistance(visibility.limitDistance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fetchVisibility();
|
fetchVisibility();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
////////// UseFrame is Here //////////
|
////////// UseFrame is Here //////////
|
||||||
|
|
||||||
useFrame(() => {
|
useFrame(() => {
|
||||||
if (toolMode) {
|
if (toolMode) {
|
||||||
Draw(
|
Draw(
|
||||||
state,
|
state,
|
||||||
plane,
|
plane,
|
||||||
cursorPosition,
|
cursorPosition,
|
||||||
floorPlanGroupPoint,
|
floorPlanGroupPoint,
|
||||||
floorPlanGroupLine,
|
floorPlanGroupLine,
|
||||||
snappedPoint,
|
snappedPoint,
|
||||||
isSnapped,
|
isSnapped,
|
||||||
isSnappedUUID,
|
isSnappedUUID,
|
||||||
line,
|
line,
|
||||||
lines,
|
lines,
|
||||||
ispreSnapped,
|
ispreSnapped,
|
||||||
floorPlanGroup,
|
floorPlanGroup,
|
||||||
ReferenceLineMesh,
|
ReferenceLineMesh,
|
||||||
LineCreated,
|
LineCreated,
|
||||||
setRefTextUpdate,
|
setRefTextUpdate,
|
||||||
Tube,
|
Tube,
|
||||||
anglesnappedPoint,
|
anglesnappedPoint,
|
||||||
isAngleSnapped,
|
isAngleSnapped,
|
||||||
toolMode
|
toolMode
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
////////// Return //////////
|
////////// Return //////////
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Ground grid={grid} plane={plane} />
|
<Ground grid={grid} plane={plane} />
|
||||||
|
|
||||||
<DistanceText key={toggleView} />
|
<DistanceText key={toggleView} />
|
||||||
|
|
||||||
<ReferenceDistanceText
|
<ReferenceDistanceText
|
||||||
key={refTextupdate}
|
key={refTextupdate}
|
||||||
line={ReferenceLineMesh.current}
|
line={ReferenceLineMesh.current}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<SocketResponses
|
<SocketResponses
|
||||||
floorPlanGroup={floorPlanGroup}
|
floorPlanGroup={floorPlanGroup}
|
||||||
lines={lines}
|
lines={lines}
|
||||||
floorGroup={floorGroup}
|
floorGroup={floorGroup}
|
||||||
floorGroupAisle={floorGroupAisle}
|
floorGroupAisle={floorGroupAisle}
|
||||||
scene={scene}
|
scene={scene}
|
||||||
onlyFloorlines={onlyFloorlines}
|
onlyFloorlines={onlyFloorlines}
|
||||||
AssetConfigurations={AssetConfigurations}
|
AssetConfigurations={AssetConfigurations}
|
||||||
itemsGroup={itemsGroup}
|
itemsGroup={itemsGroup}
|
||||||
isTempLoader={isTempLoader}
|
isTempLoader={isTempLoader}
|
||||||
tempLoader={tempLoader}
|
tempLoader={tempLoader}
|
||||||
currentLayerPoint={currentLayerPoint}
|
currentLayerPoint={currentLayerPoint}
|
||||||
floorPlanGroupPoint={floorPlanGroupPoint}
|
floorPlanGroupPoint={floorPlanGroupPoint}
|
||||||
floorPlanGroupLine={floorPlanGroupLine}
|
floorPlanGroupLine={floorPlanGroupLine}
|
||||||
zoneGroup={zoneGroup}
|
zoneGroup={zoneGroup}
|
||||||
dragPointControls={dragPointControls}
|
dragPointControls={dragPointControls}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<WallsAndWallItems
|
<WallsAndWallItems
|
||||||
CSGGroup={CSGGroup}
|
CSGGroup={CSGGroup}
|
||||||
AssetConfigurations={AssetConfigurations}
|
AssetConfigurations={AssetConfigurations}
|
||||||
setSelectedItemsIndex={setSelectedItemsIndex}
|
setSelectedItemsIndex={setSelectedItemsIndex}
|
||||||
selectedItemsIndex={selectedItemsIndex}
|
selectedItemsIndex={selectedItemsIndex}
|
||||||
currentWallItem={currentWallItem}
|
currentWallItem={currentWallItem}
|
||||||
csg={csg}
|
csg={csg}
|
||||||
lines={lines}
|
lines={lines}
|
||||||
hoveredDeletableWallItem={hoveredDeletableWallItem}
|
hoveredDeletableWallItem={hoveredDeletableWallItem}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FloorItemsGroup
|
<FloorItemsGroup
|
||||||
itemsGroup={itemsGroup}
|
itemsGroup={itemsGroup}
|
||||||
hoveredDeletableFloorItem={hoveredDeletableFloorItem}
|
hoveredDeletableFloorItem={hoveredDeletableFloorItem}
|
||||||
AttachedObject={AttachedObject}
|
AttachedObject={AttachedObject}
|
||||||
floorGroup={floorGroup}
|
floorGroup={floorGroup}
|
||||||
tempLoader={tempLoader}
|
tempLoader={tempLoader}
|
||||||
isTempLoader={isTempLoader}
|
isTempLoader={isTempLoader}
|
||||||
plane={plane}
|
plane={plane}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FloorGroup
|
<FloorGroup
|
||||||
floorGroup={floorGroup}
|
floorGroup={floorGroup}
|
||||||
lines={lines}
|
lines={lines}
|
||||||
referencePole={referencePole}
|
referencePole={referencePole}
|
||||||
hoveredDeletablePillar={hoveredDeletablePillar}
|
hoveredDeletablePillar={hoveredDeletablePillar}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FloorPlanGroup
|
<FloorPlanGroup
|
||||||
floorPlanGroup={floorPlanGroup}
|
floorPlanGroup={floorPlanGroup}
|
||||||
floorPlanGroupLine={floorPlanGroupLine}
|
floorPlanGroupLine={floorPlanGroupLine}
|
||||||
floorPlanGroupPoint={floorPlanGroupPoint}
|
floorPlanGroupPoint={floorPlanGroupPoint}
|
||||||
floorGroup={floorGroup}
|
floorGroup={floorGroup}
|
||||||
currentLayerPoint={currentLayerPoint}
|
currentLayerPoint={currentLayerPoint}
|
||||||
dragPointControls={dragPointControls}
|
dragPointControls={dragPointControls}
|
||||||
hoveredDeletablePoint={hoveredDeletablePoint}
|
hoveredDeletablePoint={hoveredDeletablePoint}
|
||||||
hoveredDeletableLine={hoveredDeletableLine}
|
hoveredDeletableLine={hoveredDeletableLine}
|
||||||
plane={plane}
|
plane={plane}
|
||||||
line={line}
|
line={line}
|
||||||
lines={lines}
|
lines={lines}
|
||||||
onlyFloorline={onlyFloorline}
|
onlyFloorline={onlyFloorline}
|
||||||
onlyFloorlines={onlyFloorlines}
|
onlyFloorlines={onlyFloorlines}
|
||||||
ReferenceLineMesh={ReferenceLineMesh}
|
ReferenceLineMesh={ReferenceLineMesh}
|
||||||
LineCreated={LineCreated}
|
LineCreated={LineCreated}
|
||||||
isSnapped={isSnapped}
|
isSnapped={isSnapped}
|
||||||
ispreSnapped={ispreSnapped}
|
ispreSnapped={ispreSnapped}
|
||||||
snappedPoint={snappedPoint}
|
snappedPoint={snappedPoint}
|
||||||
isSnappedUUID={isSnappedUUID}
|
isSnappedUUID={isSnappedUUID}
|
||||||
isAngleSnapped={isAngleSnapped}
|
isAngleSnapped={isAngleSnapped}
|
||||||
anglesnappedPoint={anglesnappedPoint}
|
anglesnappedPoint={anglesnappedPoint}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ZoneGroup />
|
<ZoneGroup />
|
||||||
|
|
||||||
<FloorGroupAilse
|
<FloorGroupAilse
|
||||||
floorGroupAisle={floorGroupAisle}
|
floorGroupAisle={floorGroupAisle}
|
||||||
plane={plane}
|
plane={plane}
|
||||||
floorPlanGroupLine={floorPlanGroupLine}
|
floorPlanGroupLine={floorPlanGroupLine}
|
||||||
floorPlanGroupPoint={floorPlanGroupPoint}
|
floorPlanGroupPoint={floorPlanGroupPoint}
|
||||||
line={line}
|
line={line}
|
||||||
lines={lines}
|
lines={lines}
|
||||||
currentLayerPoint={currentLayerPoint}
|
currentLayerPoint={currentLayerPoint}
|
||||||
dragPointControls={dragPointControls}
|
dragPointControls={dragPointControls}
|
||||||
floorPlanGroup={floorPlanGroup}
|
floorPlanGroup={floorPlanGroup}
|
||||||
ReferenceLineMesh={ReferenceLineMesh}
|
ReferenceLineMesh={ReferenceLineMesh}
|
||||||
LineCreated={LineCreated}
|
LineCreated={LineCreated}
|
||||||
isSnapped={isSnapped}
|
isSnapped={isSnapped}
|
||||||
ispreSnapped={ispreSnapped}
|
ispreSnapped={ispreSnapped}
|
||||||
snappedPoint={snappedPoint}
|
snappedPoint={snappedPoint}
|
||||||
isSnappedUUID={isSnappedUUID}
|
isSnappedUUID={isSnappedUUID}
|
||||||
isAngleSnapped={isAngleSnapped}
|
isAngleSnapped={isAngleSnapped}
|
||||||
anglesnappedPoint={anglesnappedPoint}
|
anglesnappedPoint={anglesnappedPoint}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<MeasurementTool />
|
<MeasurementTool />
|
||||||
<CalculateAreaGroup />
|
<CalculateAreaGroup />
|
||||||
<NavMesh lines={lines} />
|
<NavMesh lines={lines} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,51 +4,51 @@ import { useDeleteTool } from "../../../store/store";
|
||||||
import { useRef } from "react";
|
import { useRef } from "react";
|
||||||
|
|
||||||
export interface CsgProps {
|
export interface CsgProps {
|
||||||
position: THREE.Vector3 | [number, number, number];
|
position: THREE.Vector3 | [number, number, number];
|
||||||
scale: THREE.Vector3 | [number, number, number];
|
scale: THREE.Vector3 | [number, number, number];
|
||||||
model: THREE.Object3D;
|
model: THREE.Object3D;
|
||||||
hoveredDeletableWallItem: { current: THREE.Mesh | null };
|
hoveredDeletableWallItem: { current: THREE.Mesh | null };
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Csg: React.FC<CsgProps> = (props) => {
|
export const Csg: React.FC<CsgProps> = (props) => {
|
||||||
const { deleteTool } = useDeleteTool();
|
const { deleteTool } = useDeleteTool();
|
||||||
const modelRef = useRef<THREE.Object3D>();
|
const modelRef = useRef<THREE.Object3D>();
|
||||||
const originalMaterials = useRef<Map<THREE.Mesh, THREE.Material>>(new Map());
|
const originalMaterials = useRef<Map<THREE.Mesh, THREE.Material>>(new Map());
|
||||||
|
|
||||||
const handleHover = (hovered: boolean, object: THREE.Mesh | null) => {
|
const handleHover = (hovered: boolean, object: THREE.Mesh | null) => {
|
||||||
if (modelRef.current && deleteTool) {
|
if (modelRef.current && deleteTool) {
|
||||||
modelRef.current.traverse((child) => {
|
modelRef.current.traverse((child) => {
|
||||||
if (child instanceof THREE.Mesh) {
|
if (child instanceof THREE.Mesh) {
|
||||||
if (!originalMaterials.current.has(child)) {
|
if (!originalMaterials.current.has(child)) {
|
||||||
originalMaterials.current.set(child, child.material);
|
originalMaterials.current.set(child, child.material);
|
||||||
}
|
}
|
||||||
child.material = child.material.clone();
|
child.material = child.material.clone();
|
||||||
child.material.color.set(hovered && deleteTool ? 0xff0000 : (originalMaterials.current.get(child) as any).color);
|
child.material.color.set(hovered && deleteTool ? 0xff0000 : (originalMaterials.current.get(child) as any).color);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
props.hoveredDeletableWallItem.current = hovered ? object : null;
|
||||||
}
|
};
|
||||||
props.hoveredDeletableWallItem.current = hovered ? object : null;
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Geometry>
|
|
||||||
<Subtraction {...props}>
|
|
||||||
<Geometry>
|
<Geometry>
|
||||||
<Base geometry={new THREE.BoxGeometry()} />
|
<Subtraction {...props}>
|
||||||
|
<Geometry>
|
||||||
|
<Base geometry={new THREE.BoxGeometry()} />
|
||||||
|
</Geometry>
|
||||||
|
</Subtraction>
|
||||||
|
<primitive
|
||||||
|
object={props.model}
|
||||||
|
ref={modelRef}
|
||||||
|
onPointerOver={(e: any) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
handleHover(true, e.object.parent);
|
||||||
|
}}
|
||||||
|
onPointerOut={(e: any) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
handleHover(false, null);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</Geometry>
|
</Geometry>
|
||||||
</Subtraction>
|
);
|
||||||
<primitive
|
|
||||||
object={props.model}
|
|
||||||
ref={modelRef}
|
|
||||||
onPointerOver={(e: any) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
handleHover(true, e.object.parent);
|
|
||||||
}}
|
|
||||||
onPointerOut={(e: any) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
handleHover(false, null);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Geometry>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -26,7 +26,6 @@ export default function addFloorToScene(
|
||||||
|
|
||||||
if (materialCache.has(materialKey)) {
|
if (materialCache.has(materialKey)) {
|
||||||
material = materialCache.get(materialKey) as THREE.Material;
|
material = materialCache.get(materialKey) as THREE.Material;
|
||||||
// } else {
|
|
||||||
} else {
|
} else {
|
||||||
const floorTexture = textureLoader.load(savedTheme === "dark" ? texturePathDark : texturePath);
|
const floorTexture = textureLoader.load(savedTheme === "dark" ? texturePathDark : texturePath);
|
||||||
// const floorTexture = textureLoader.load(texturePath);
|
// const floorTexture = textureLoader.load(texturePath);
|
||||||
|
|
|
@ -35,7 +35,7 @@ async function AddWallItems(
|
||||||
});
|
});
|
||||||
|
|
||||||
const config = AssetConfigurations[selected];
|
const config = AssetConfigurations[selected];
|
||||||
let positionY = typeof config.positionY === 'function' ? config.positionY(intersectionPoint) : config.positionY;
|
let positionY = config.type === 'Fixed-Move' ? 0 : intersectionPoint.point.y;
|
||||||
if (positionY === 0) {
|
if (positionY === 0) {
|
||||||
positionY = Math.floor(intersectionPoint.point.y / CONSTANTS.wallConfig.height) * CONSTANTS.wallConfig.height;
|
positionY = Math.floor(intersectionPoint.point.y / CONSTANTS.wallConfig.height) * CONSTANTS.wallConfig.height;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@ import {
|
||||||
useSelectedItem,
|
useSelectedItem,
|
||||||
useSocketStore,
|
useSocketStore,
|
||||||
useToggleView,
|
useToggleView,
|
||||||
useTransformMode,
|
|
||||||
} from "../../../store/store";
|
} from "../../../store/store";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import * as THREE from "three";
|
import * as THREE from "three";
|
||||||
|
@ -59,7 +58,6 @@ const FloorItemsGroup = ({
|
||||||
const { camMode } = useCamMode();
|
const { camMode } = useCamMode();
|
||||||
const { deleteTool } = useDeleteTool();
|
const { deleteTool } = useDeleteTool();
|
||||||
const { setDeletableFloorItem } = useDeletableFloorItem();
|
const { setDeletableFloorItem } = useDeletableFloorItem();
|
||||||
const { transformMode } = useTransformMode();
|
|
||||||
const { setSelectedFloorItem } = useSelectedFloorItem();
|
const { setSelectedFloorItem } = useSelectedFloorItem();
|
||||||
const { activeTool } = useActiveTool();
|
const { activeTool } = useActiveTool();
|
||||||
const { selectedItem, setSelectedItem } = useSelectedItem();
|
const { selectedItem, setSelectedItem } = useSelectedItem();
|
||||||
|
@ -257,9 +255,8 @@ const FloorItemsGroup = ({
|
||||||
socket
|
socket
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const Mode = transformMode;
|
|
||||||
|
|
||||||
if (Mode !== null || activeTool === "cursor") {
|
if (activeTool === "cursor") {
|
||||||
if (!itemsGroup.current) return;
|
if (!itemsGroup.current) return;
|
||||||
let intersects = raycaster.intersectObjects(
|
let intersects = raycaster.intersectObjects(
|
||||||
itemsGroup.current.children,
|
itemsGroup.current.children,
|
||||||
|
@ -296,9 +293,8 @@ const FloorItemsGroup = ({
|
||||||
isLeftMouseDown = false;
|
isLeftMouseDown = false;
|
||||||
if (drag) return;
|
if (drag) return;
|
||||||
|
|
||||||
const Mode = transformMode;
|
|
||||||
|
|
||||||
if (Mode !== null || activeTool === "cursor") {
|
if (activeTool === "cursor") {
|
||||||
if (!itemsGroup.current) return;
|
if (!itemsGroup.current) return;
|
||||||
let intersects = raycaster.intersectObjects(
|
let intersects = raycaster.intersectObjects(
|
||||||
itemsGroup.current.children,
|
itemsGroup.current.children,
|
||||||
|
@ -412,16 +408,7 @@ const FloorItemsGroup = ({
|
||||||
canvasElement.removeEventListener("drop", onDrop);
|
canvasElement.removeEventListener("drop", onDrop);
|
||||||
canvasElement.removeEventListener("dragover", onDragOver);
|
canvasElement.removeEventListener("dragover", onDragOver);
|
||||||
};
|
};
|
||||||
}, [
|
}, [deleteTool, controls, selectedItem, state.camera, state.pointer, activeTool, activeModule,]);
|
||||||
deleteTool,
|
|
||||||
transformMode,
|
|
||||||
controls,
|
|
||||||
selectedItem,
|
|
||||||
state.camera,
|
|
||||||
state.pointer,
|
|
||||||
activeTool,
|
|
||||||
activeModule,
|
|
||||||
]);
|
|
||||||
|
|
||||||
useFrame(() => {
|
useFrame(() => {
|
||||||
if (controls)
|
if (controls)
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import {
|
import {
|
||||||
useDeleteTool,
|
useDeleteTool,
|
||||||
useDeletePointOrLine,
|
useDeletePointOrLine,
|
||||||
useObjectPosition,
|
useObjectPosition,
|
||||||
useObjectRotation,
|
useObjectRotation,
|
||||||
useSelectedWallItem,
|
useSelectedWallItem,
|
||||||
useSocketStore,
|
useSocketStore,
|
||||||
useWallItems,
|
useWallItems,
|
||||||
} from "../../../store/store";
|
} from "../../../store/store";
|
||||||
import { Csg } from "../csg/csg";
|
import { Csg } from "../csg/csg";
|
||||||
import * as Types from "../../../types/world/worldTypes";
|
import * as Types from "../../../types/world/worldTypes";
|
||||||
|
@ -20,276 +20,276 @@ import AddWallItems from "../geomentries/walls/addWallItems";
|
||||||
import useModuleStore from "../../../store/useModuleStore";
|
import useModuleStore from "../../../store/useModuleStore";
|
||||||
|
|
||||||
const WallItemsGroup = ({
|
const WallItemsGroup = ({
|
||||||
currentWallItem,
|
currentWallItem,
|
||||||
AssetConfigurations,
|
AssetConfigurations,
|
||||||
hoveredDeletableWallItem,
|
hoveredDeletableWallItem,
|
||||||
selectedItemsIndex,
|
selectedItemsIndex,
|
||||||
setSelectedItemsIndex,
|
setSelectedItemsIndex,
|
||||||
CSGGroup,
|
CSGGroup,
|
||||||
}: any) => {
|
}: any) => {
|
||||||
const state = useThree();
|
const state = useThree();
|
||||||
const { socket } = useSocketStore();
|
const { socket } = useSocketStore();
|
||||||
const { pointer, camera, raycaster } = state;
|
const { pointer, camera, raycaster } = state;
|
||||||
const { deleteTool } = useDeleteTool();
|
const { deleteTool } = useDeleteTool();
|
||||||
const { wallItems, setWallItems } = useWallItems();
|
const { wallItems, setWallItems } = useWallItems();
|
||||||
const { setObjectPosition } = useObjectPosition();
|
const { setObjectPosition } = useObjectPosition();
|
||||||
const { setObjectRotation } = useObjectRotation();
|
const { setObjectRotation } = useObjectRotation();
|
||||||
const { deletePointOrLine } = useDeletePointOrLine();
|
const { deletePointOrLine } = useDeletePointOrLine();
|
||||||
const { setSelectedWallItem } = useSelectedWallItem();
|
const { setSelectedWallItem } = useSelectedWallItem();
|
||||||
const { activeModule } = useModuleStore();
|
const { activeModule } = useModuleStore();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Load Wall Items from the backend
|
// Load Wall Items from the backend
|
||||||
loadInitialWallItems(setWallItems, AssetConfigurations);
|
loadInitialWallItems(setWallItems, AssetConfigurations);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
////////// Update the Scale value changes in thewallItems State //////////
|
////////// Update the Scale value changes in thewallItems State //////////
|
||||||
|
|
||||||
////////// Update the Position value changes in the selected item //////////
|
////////// Update the Position value changes in the selected item //////////
|
||||||
|
|
||||||
////////// Update the Rotation value changes in the selected item //////////
|
////////// Update the Rotation value changes in the selected item //////////
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const canvasElement = state.gl.domElement;
|
const canvasElement = state.gl.domElement;
|
||||||
function handlePointerMove(e: any) {
|
function handlePointerMove(e: any) {
|
||||||
if (
|
if (
|
||||||
selectedItemsIndex !== null &&
|
selectedItemsIndex !== null &&
|
||||||
!deletePointOrLine &&
|
!deletePointOrLine &&
|
||||||
e.buttons === 1
|
e.buttons === 1
|
||||||
) {
|
) {
|
||||||
const Raycaster = state.raycaster;
|
const Raycaster = state.raycaster;
|
||||||
const intersects = Raycaster.intersectObjects(
|
const intersects = Raycaster.intersectObjects(
|
||||||
CSGGroup.current?.children[0].children!,
|
CSGGroup.current?.children[0].children!,
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
const Object = intersects.find((child) =>
|
const Object = intersects.find((child) =>
|
||||||
child.object.name.includes("WallRaycastReference")
|
child.object.name.includes("WallRaycastReference")
|
||||||
);
|
);
|
||||||
|
|
||||||
if (Object) {
|
if (Object) {
|
||||||
(state.controls as any)!.enabled = false;
|
(state.controls as any)!.enabled = false;
|
||||||
setWallItems((prevItems: any) => {
|
setWallItems((prevItems: any) => {
|
||||||
const updatedItems = [...prevItems];
|
const updatedItems = [...prevItems];
|
||||||
let position: [number, number, number] = [0, 0, 0];
|
let position: [number, number, number] = [0, 0, 0];
|
||||||
|
|
||||||
if (updatedItems[selectedItemsIndex].type === "Fixed-Move") {
|
if (updatedItems[selectedItemsIndex].type === "Fixed-Move") {
|
||||||
position = [
|
position = [
|
||||||
Object!.point.x,
|
Object!.point.x,
|
||||||
Math.floor(Object!.point.y / CONSTANTS.wallConfig.height) *
|
Math.floor(Object!.point.y / CONSTANTS.wallConfig.height) *
|
||||||
CONSTANTS.wallConfig.height,
|
CONSTANTS.wallConfig.height,
|
||||||
Object!.point.z,
|
Object!.point.z,
|
||||||
];
|
];
|
||||||
} else if (updatedItems[selectedItemsIndex].type === "Free-Move") {
|
} else if (updatedItems[selectedItemsIndex].type === "Free-Move") {
|
||||||
position = [Object!.point.x, Object!.point.y, Object!.point.z];
|
position = [Object!.point.x, Object!.point.y, Object!.point.z];
|
||||||
|
}
|
||||||
|
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
setObjectPosition(new THREE.Vector3(...position));
|
||||||
|
setObjectRotation({
|
||||||
|
x: THREE.MathUtils.radToDeg(Object!.object.rotation.x),
|
||||||
|
y: THREE.MathUtils.radToDeg(Object!.object.rotation.y),
|
||||||
|
z: THREE.MathUtils.radToDeg(Object!.object.rotation.z),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
updatedItems[selectedItemsIndex] = {
|
||||||
|
...updatedItems[selectedItemsIndex],
|
||||||
|
position: position,
|
||||||
|
quaternion:
|
||||||
|
Object!.object.quaternion.clone() as Types.QuaternionType,
|
||||||
|
};
|
||||||
|
|
||||||
|
return updatedItems;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
requestAnimationFrame(() => {
|
|
||||||
setObjectPosition(new THREE.Vector3(...position));
|
|
||||||
setObjectRotation({
|
|
||||||
x: THREE.MathUtils.radToDeg(Object!.object.rotation.x),
|
|
||||||
y: THREE.MathUtils.radToDeg(Object!.object.rotation.y),
|
|
||||||
z: THREE.MathUtils.radToDeg(Object!.object.rotation.z),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
updatedItems[selectedItemsIndex] = {
|
|
||||||
...updatedItems[selectedItemsIndex],
|
|
||||||
position: position,
|
|
||||||
quaternion:
|
|
||||||
Object!.object.quaternion.clone() as Types.QuaternionType,
|
|
||||||
};
|
|
||||||
|
|
||||||
return updatedItems;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handlePointerUp() {
|
async function handlePointerUp() {
|
||||||
const Raycaster = state.raycaster;
|
const Raycaster = state.raycaster;
|
||||||
const intersects = Raycaster.intersectObjects(
|
const intersects = Raycaster.intersectObjects(
|
||||||
CSGGroup.current?.children[0].children!,
|
CSGGroup.current?.children[0].children!,
|
||||||
true
|
true
|
||||||
);
|
|
||||||
const Object = intersects.find((child) =>
|
|
||||||
child.object.name.includes("WallRaycastReference")
|
|
||||||
);
|
|
||||||
if (Object) {
|
|
||||||
if (selectedItemsIndex !== null) {
|
|
||||||
let currentItem: any = null;
|
|
||||||
setWallItems((prevItems: any) => {
|
|
||||||
const updatedItems = [...prevItems];
|
|
||||||
const WallItemsForStorage = updatedItems.map((item) => {
|
|
||||||
const { model, ...rest } = item;
|
|
||||||
return {
|
|
||||||
...rest,
|
|
||||||
modelUuid: model?.uuid,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
currentItem = updatedItems[selectedItemsIndex];
|
|
||||||
localStorage.setItem(
|
|
||||||
"WallItems",
|
|
||||||
JSON.stringify(WallItemsForStorage)
|
|
||||||
);
|
);
|
||||||
return updatedItems;
|
const Object = intersects.find((child) =>
|
||||||
});
|
child.object.name.includes("WallRaycastReference")
|
||||||
|
);
|
||||||
|
if (Object) {
|
||||||
|
if (selectedItemsIndex !== null) {
|
||||||
|
let currentItem: any = null;
|
||||||
|
setWallItems((prevItems: any) => {
|
||||||
|
const updatedItems = [...prevItems];
|
||||||
|
const WallItemsForStorage = updatedItems.map((item) => {
|
||||||
|
const { model, ...rest } = item;
|
||||||
|
return {
|
||||||
|
...rest,
|
||||||
|
modelUuid: model?.uuid,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
setTimeout(async () => {
|
currentItem = updatedItems[selectedItemsIndex];
|
||||||
const email = localStorage.getItem("email");
|
localStorage.setItem(
|
||||||
const organization = email!.split("@")[1].split(".")[0];
|
"WallItems",
|
||||||
|
JSON.stringify(WallItemsForStorage)
|
||||||
|
);
|
||||||
|
return updatedItems;
|
||||||
|
});
|
||||||
|
|
||||||
//REST
|
setTimeout(async () => {
|
||||||
|
const email = localStorage.getItem("email");
|
||||||
|
const organization = email!.split("@")[1].split(".")[0];
|
||||||
|
|
||||||
// await setWallItem(
|
//REST
|
||||||
// organization,
|
|
||||||
// currentItem?.model?.uuid,
|
|
||||||
// currentItem.modelName,
|
|
||||||
// currentItem.type!,
|
|
||||||
// currentItem.csgposition!,
|
|
||||||
// currentItem.csgscale!,
|
|
||||||
// currentItem.position,
|
|
||||||
// currentItem.quaternion,
|
|
||||||
// currentItem.scale!,
|
|
||||||
// )
|
|
||||||
|
|
||||||
//SOCKET
|
// await setWallItem(
|
||||||
|
// organization,
|
||||||
|
// currentItem?.model?.uuid,
|
||||||
|
// currentItem.modelName,
|
||||||
|
// currentItem.type!,
|
||||||
|
// currentItem.csgposition!,
|
||||||
|
// currentItem.csgscale!,
|
||||||
|
// currentItem.position,
|
||||||
|
// currentItem.quaternion,
|
||||||
|
// currentItem.scale!,
|
||||||
|
// )
|
||||||
|
|
||||||
const data = {
|
//SOCKET
|
||||||
organization: organization,
|
|
||||||
modelUuid: currentItem.model?.uuid!,
|
|
||||||
modelName: currentItem.modelName!,
|
|
||||||
type: currentItem.type!,
|
|
||||||
csgposition: currentItem.csgposition!,
|
|
||||||
csgscale: currentItem.csgscale!,
|
|
||||||
position: currentItem.position!,
|
|
||||||
quaternion: currentItem.quaternion,
|
|
||||||
scale: currentItem.scale!,
|
|
||||||
socketId: socket.id,
|
|
||||||
};
|
|
||||||
|
|
||||||
socket.emit("v1:wallItems:set", data);
|
const data = {
|
||||||
}, 0);
|
organization: organization,
|
||||||
(state.controls as any)!.enabled = true;
|
modelUuid: currentItem.model?.uuid!,
|
||||||
|
modelName: currentItem.modelName!,
|
||||||
|
type: currentItem.type!,
|
||||||
|
csgposition: currentItem.csgposition!,
|
||||||
|
csgscale: currentItem.csgscale!,
|
||||||
|
position: currentItem.position!,
|
||||||
|
quaternion: currentItem.quaternion,
|
||||||
|
scale: currentItem.scale!,
|
||||||
|
socketId: socket.id,
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.emit("v1:wallItems:set", data);
|
||||||
|
}, 0);
|
||||||
|
(state.controls as any)!.enabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
canvasElement.addEventListener("pointermove", handlePointerMove);
|
canvasElement.addEventListener("pointermove", handlePointerMove);
|
||||||
canvasElement.addEventListener("pointerup", handlePointerUp);
|
canvasElement.addEventListener("pointerup", handlePointerUp);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
canvasElement.removeEventListener("pointermove", handlePointerMove);
|
canvasElement.removeEventListener("pointermove", handlePointerMove);
|
||||||
canvasElement.removeEventListener("pointerup", handlePointerUp);
|
canvasElement.removeEventListener("pointerup", handlePointerUp);
|
||||||
};
|
};
|
||||||
}, [selectedItemsIndex]);
|
}, [selectedItemsIndex]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const canvasElement = state.gl.domElement;
|
const canvasElement = state.gl.domElement;
|
||||||
let drag = false;
|
let drag = false;
|
||||||
let isLeftMouseDown = false;
|
let isLeftMouseDown = false;
|
||||||
|
|
||||||
const onMouseDown = (evt: any) => {
|
const onMouseDown = (evt: any) => {
|
||||||
if (evt.button === 0) {
|
if (evt.button === 0) {
|
||||||
isLeftMouseDown = true;
|
isLeftMouseDown = true;
|
||||||
drag = false;
|
drag = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onMouseUp = (evt: any) => {
|
const onMouseUp = (evt: any) => {
|
||||||
if (evt.button === 0) {
|
if (evt.button === 0) {
|
||||||
isLeftMouseDown = false;
|
isLeftMouseDown = false;
|
||||||
if (!drag && deleteTool && activeModule === "builder") {
|
if (!drag && deleteTool && activeModule === "builder") {
|
||||||
DeleteWallItems(
|
DeleteWallItems(
|
||||||
hoveredDeletableWallItem,
|
hoveredDeletableWallItem,
|
||||||
setWallItems,
|
setWallItems,
|
||||||
wallItems,
|
wallItems,
|
||||||
socket
|
socket
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onMouseMove = () => {
|
||||||
|
if (isLeftMouseDown) {
|
||||||
|
drag = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onDrop = (event: any) => {
|
||||||
|
if (!event.dataTransfer?.files[0]) return;
|
||||||
|
|
||||||
|
pointer.x = (event.clientX / window.innerWidth) * 2 - 1;
|
||||||
|
pointer.y = -(event.clientY / window.innerHeight) * 2 + 1;
|
||||||
|
raycaster.setFromCamera(pointer, camera);
|
||||||
|
|
||||||
|
if (AssetConfigurations[event.dataTransfer.files[0].name.split(".")[0]]) {
|
||||||
|
const selected = event.dataTransfer.files[0].name.split(".")[0];
|
||||||
|
|
||||||
|
if (AssetConfigurations[selected]?.type) {
|
||||||
|
AddWallItems(
|
||||||
|
selected,
|
||||||
|
raycaster,
|
||||||
|
CSGGroup,
|
||||||
|
AssetConfigurations,
|
||||||
|
setWallItems,
|
||||||
|
socket
|
||||||
|
);
|
||||||
|
}
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onDragOver = (event: any) => {
|
||||||
|
event.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
|
canvasElement.addEventListener("mousedown", onMouseDown);
|
||||||
|
canvasElement.addEventListener("mouseup", onMouseUp);
|
||||||
|
canvasElement.addEventListener("mousemove", onMouseMove);
|
||||||
|
canvasElement.addEventListener("drop", onDrop);
|
||||||
|
canvasElement.addEventListener("dragover", onDragOver);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
canvasElement.removeEventListener("mousedown", onMouseDown);
|
||||||
|
canvasElement.removeEventListener("mouseup", onMouseUp);
|
||||||
|
canvasElement.removeEventListener("mousemove", onMouseMove);
|
||||||
|
canvasElement.removeEventListener("drop", onDrop);
|
||||||
|
canvasElement.removeEventListener("dragover", onDragOver);
|
||||||
|
};
|
||||||
|
}, [deleteTool, wallItems]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (deleteTool && activeModule === "builder") {
|
||||||
|
handleMeshMissed(
|
||||||
|
currentWallItem,
|
||||||
|
setSelectedWallItem,
|
||||||
|
setSelectedItemsIndex
|
||||||
|
);
|
||||||
|
setSelectedWallItem(null);
|
||||||
|
setSelectedItemsIndex(null);
|
||||||
}
|
}
|
||||||
}
|
}, [deleteTool]);
|
||||||
};
|
|
||||||
|
|
||||||
const onMouseMove = () => {
|
return (
|
||||||
if (isLeftMouseDown) {
|
<>
|
||||||
drag = true;
|
{wallItems.map((item: Types.WallItem, index: number) => (
|
||||||
}
|
<group
|
||||||
};
|
key={index}
|
||||||
|
position={item.position}
|
||||||
const onDrop = (event: any) => {
|
quaternion={item.quaternion}
|
||||||
if (!event.dataTransfer?.files[0]) return;
|
scale={item.scale}
|
||||||
|
>
|
||||||
pointer.x = (event.clientX / window.innerWidth) * 2 - 1;
|
<Csg
|
||||||
pointer.y = -(event.clientY / window.innerHeight) * 2 + 1;
|
position={item.csgposition!}
|
||||||
raycaster.setFromCamera(pointer, camera);
|
scale={item.csgscale!}
|
||||||
|
model={item.model!}
|
||||||
if (AssetConfigurations[event.dataTransfer.files[0].name.split(".")[0]]) {
|
hoveredDeletableWallItem={hoveredDeletableWallItem}
|
||||||
const selected = event.dataTransfer.files[0].name.split(".")[0];
|
/>
|
||||||
|
</group>
|
||||||
if (AssetConfigurations[selected]?.type) {
|
))}
|
||||||
AddWallItems(
|
</>
|
||||||
selected,
|
);
|
||||||
raycaster,
|
|
||||||
CSGGroup,
|
|
||||||
AssetConfigurations,
|
|
||||||
setWallItems,
|
|
||||||
socket
|
|
||||||
);
|
|
||||||
}
|
|
||||||
event.preventDefault();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onDragOver = (event: any) => {
|
|
||||||
event.preventDefault();
|
|
||||||
};
|
|
||||||
|
|
||||||
canvasElement.addEventListener("mousedown", onMouseDown);
|
|
||||||
canvasElement.addEventListener("mouseup", onMouseUp);
|
|
||||||
canvasElement.addEventListener("mousemove", onMouseMove);
|
|
||||||
canvasElement.addEventListener("drop", onDrop);
|
|
||||||
canvasElement.addEventListener("dragover", onDragOver);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
canvasElement.removeEventListener("mousedown", onMouseDown);
|
|
||||||
canvasElement.removeEventListener("mouseup", onMouseUp);
|
|
||||||
canvasElement.removeEventListener("mousemove", onMouseMove);
|
|
||||||
canvasElement.removeEventListener("drop", onDrop);
|
|
||||||
canvasElement.removeEventListener("dragover", onDragOver);
|
|
||||||
};
|
|
||||||
}, [deleteTool, wallItems]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (deleteTool && activeModule === "builder") {
|
|
||||||
handleMeshMissed(
|
|
||||||
currentWallItem,
|
|
||||||
setSelectedWallItem,
|
|
||||||
setSelectedItemsIndex
|
|
||||||
);
|
|
||||||
setSelectedWallItem(null);
|
|
||||||
setSelectedItemsIndex(null);
|
|
||||||
}
|
|
||||||
}, [deleteTool]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{wallItems.map((item: Types.WallItem, index: number) => (
|
|
||||||
<group
|
|
||||||
key={index}
|
|
||||||
position={item.position}
|
|
||||||
quaternion={item.quaternion}
|
|
||||||
scale={item.scale}
|
|
||||||
>
|
|
||||||
<Csg
|
|
||||||
position={item.csgposition!}
|
|
||||||
scale={item.csgscale!}
|
|
||||||
model={item.model!}
|
|
||||||
hoveredDeletableWallItem={hoveredDeletableWallItem}
|
|
||||||
/>
|
|
||||||
</group>
|
|
||||||
))}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default WallItemsGroup;
|
export default WallItemsGroup;
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
import { Geometry } from "@react-three/csg";
|
import { Geometry } from "@react-three/csg";
|
||||||
import {
|
import {
|
||||||
useDeleteTool,
|
useDeleteTool,
|
||||||
useSelectedWallItem,
|
useSelectedWallItem,
|
||||||
useToggleView,
|
useToggleView,
|
||||||
useTransformMode,
|
useWallItems,
|
||||||
useWallItems,
|
useWalls,
|
||||||
useWalls,
|
|
||||||
} from "../../../store/store";
|
} from "../../../store/store";
|
||||||
import handleMeshDown from "../eventFunctions/handleMeshDown";
|
import handleMeshDown from "../eventFunctions/handleMeshDown";
|
||||||
import handleMeshMissed from "../eventFunctions/handleMeshMissed";
|
import handleMeshMissed from "../eventFunctions/handleMeshMissed";
|
||||||
|
@ -14,79 +13,65 @@ import WallItemsGroup from "./wallItemsGroup";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
|
|
||||||
const WallsAndWallItems = ({
|
const WallsAndWallItems = ({
|
||||||
CSGGroup,
|
CSGGroup,
|
||||||
AssetConfigurations,
|
AssetConfigurations,
|
||||||
setSelectedItemsIndex,
|
setSelectedItemsIndex,
|
||||||
selectedItemsIndex,
|
selectedItemsIndex,
|
||||||
currentWallItem,
|
currentWallItem,
|
||||||
csg,
|
csg,
|
||||||
lines,
|
lines,
|
||||||
hoveredDeletableWallItem,
|
hoveredDeletableWallItem,
|
||||||
}: any) => {
|
}: any) => {
|
||||||
const { walls } = useWalls();
|
const { walls } = useWalls();
|
||||||
const { wallItems } = useWallItems();
|
const { wallItems } = useWallItems();
|
||||||
const { toggleView } = useToggleView();
|
const { toggleView } = useToggleView();
|
||||||
const { deleteTool } = useDeleteTool();
|
const { deleteTool } = useDeleteTool();
|
||||||
const { transformMode } = useTransformMode();
|
const { setSelectedWallItem } = useSelectedWallItem();
|
||||||
const { setSelectedWallItem } = useSelectedWallItem();
|
|
||||||
|
|
||||||
useEffect(() => {
|
return (
|
||||||
if (transformMode === null) {
|
<mesh
|
||||||
if (!deleteTool) {
|
ref={CSGGroup as any}
|
||||||
handleMeshMissed(
|
name="Walls"
|
||||||
currentWallItem,
|
key={walls.length}
|
||||||
setSelectedWallItem,
|
receiveShadow
|
||||||
setSelectedItemsIndex
|
visible={!toggleView}
|
||||||
);
|
onClick={(event) => {
|
||||||
setSelectedWallItem(null);
|
if (!deleteTool) {
|
||||||
setSelectedItemsIndex(null);
|
handleMeshDown(
|
||||||
}
|
event,
|
||||||
}
|
currentWallItem,
|
||||||
}, [transformMode]);
|
setSelectedWallItem,
|
||||||
return (
|
setSelectedItemsIndex,
|
||||||
<mesh
|
wallItems,
|
||||||
ref={CSGGroup as any}
|
toggleView
|
||||||
name="Walls"
|
);
|
||||||
key={walls.length}
|
}
|
||||||
receiveShadow
|
}}
|
||||||
visible={!toggleView}
|
onPointerMissed={() => {
|
||||||
onClick={(event) => {
|
if (!deleteTool) {
|
||||||
if (!deleteTool && transformMode !== null) {
|
handleMeshMissed(
|
||||||
handleMeshDown(
|
currentWallItem,
|
||||||
event,
|
setSelectedWallItem,
|
||||||
currentWallItem,
|
setSelectedItemsIndex
|
||||||
setSelectedWallItem,
|
);
|
||||||
setSelectedItemsIndex,
|
setSelectedWallItem(null);
|
||||||
wallItems,
|
setSelectedItemsIndex(null);
|
||||||
toggleView
|
}
|
||||||
);
|
}}
|
||||||
}
|
>
|
||||||
}}
|
<Geometry ref={csg as any} computeVertexNormals useGroups>
|
||||||
onPointerMissed={() => {
|
<WallsMesh lines={lines} />
|
||||||
if (!deleteTool) {
|
<WallItemsGroup
|
||||||
handleMeshMissed(
|
currentWallItem={currentWallItem}
|
||||||
currentWallItem,
|
AssetConfigurations={AssetConfigurations}
|
||||||
setSelectedWallItem,
|
hoveredDeletableWallItem={hoveredDeletableWallItem}
|
||||||
setSelectedItemsIndex
|
selectedItemsIndex={selectedItemsIndex}
|
||||||
);
|
setSelectedItemsIndex={setSelectedItemsIndex}
|
||||||
setSelectedWallItem(null);
|
CSGGroup={CSGGroup}
|
||||||
setSelectedItemsIndex(null);
|
/>
|
||||||
}
|
</Geometry>
|
||||||
}}
|
</mesh>
|
||||||
>
|
);
|
||||||
<Geometry ref={csg as any} computeVertexNormals useGroups>
|
|
||||||
<WallsMesh lines={lines} />
|
|
||||||
<WallItemsGroup
|
|
||||||
currentWallItem={currentWallItem}
|
|
||||||
AssetConfigurations={AssetConfigurations}
|
|
||||||
hoveredDeletableWallItem={hoveredDeletableWallItem}
|
|
||||||
selectedItemsIndex={selectedItemsIndex}
|
|
||||||
setSelectedItemsIndex={setSelectedItemsIndex}
|
|
||||||
CSGGroup={CSGGroup}
|
|
||||||
/>
|
|
||||||
</Geometry>
|
|
||||||
</mesh>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default WallsAndWallItems;
|
export default WallsAndWallItems;
|
||||||
|
|
|
@ -15,63 +15,63 @@ import texturePath from "../../../assets/textures/floor/wall-tex.png";
|
||||||
const materialCache = new Map<string, THREE.Material>();
|
const materialCache = new Map<string, THREE.Material>();
|
||||||
|
|
||||||
const WallsMeshComponent = ({ lines }: any) => {
|
const WallsMeshComponent = ({ lines }: any) => {
|
||||||
const { walls, setWalls } = useWalls();
|
const { walls, setWalls } = useWalls();
|
||||||
const { updateScene, setUpdateScene } = useUpdateScene();
|
const { updateScene, setUpdateScene } = useUpdateScene();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (updateScene) {
|
if (updateScene) {
|
||||||
const email = localStorage.getItem("email");
|
const email = localStorage.getItem("email");
|
||||||
const organization = email!.split("@")[1].split(".")[0];
|
const organization = email!.split("@")[1].split(".")[0];
|
||||||
|
|
||||||
getLines(organization).then((data) => {
|
getLines(organization).then((data) => {
|
||||||
const Lines: Types.Lines = objectLinesToArray(data);
|
const Lines: Types.Lines = objectLinesToArray(data);
|
||||||
localStorage.setItem("Lines", JSON.stringify(Lines));
|
localStorage.setItem("Lines", JSON.stringify(Lines));
|
||||||
|
|
||||||
if (Lines) {
|
if (Lines) {
|
||||||
loadWalls(lines, setWalls);
|
loadWalls(lines, setWalls);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setUpdateScene(false);
|
||||||
}
|
}
|
||||||
});
|
}, [updateScene]);
|
||||||
setUpdateScene(false);
|
|
||||||
}
|
|
||||||
}, [updateScene]);
|
|
||||||
|
|
||||||
const textureLoader = new THREE.TextureLoader();
|
const textureLoader = new THREE.TextureLoader();
|
||||||
const wallTexture = textureLoader.load(texturePath);
|
const wallTexture = textureLoader.load(texturePath);
|
||||||
|
|
||||||
wallTexture.wrapS = wallTexture.wrapT = THREE.RepeatWrapping;
|
wallTexture.wrapS = wallTexture.wrapT = THREE.RepeatWrapping;
|
||||||
wallTexture.repeat.set(0.1, 0.1);
|
wallTexture.repeat.set(0.1, 0.1);
|
||||||
wallTexture.colorSpace = THREE.SRGBColorSpace;
|
wallTexture.colorSpace = THREE.SRGBColorSpace;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{walls.map((wall: Types.Wall, index: number) => (
|
{walls.map((wall: Types.Wall, index: number) => (
|
||||||
<mesh key={index} renderOrder={1}>
|
<mesh key={index} renderOrder={1}>
|
||||||
<Base
|
<Base
|
||||||
name={`Wall${index + 1}`}
|
name={`Wall${index + 1}`}
|
||||||
geometry={wall[0]}
|
geometry={wall[0]}
|
||||||
rotation={wall[1]}
|
rotation={wall[1]}
|
||||||
position={wall[2]}
|
position={wall[2]}
|
||||||
userData={{ WallType: wall[3], Layer: wall[4] }}
|
userData={{ WallType: wall[3], Layer: wall[4] }}
|
||||||
>
|
>
|
||||||
<meshStandardMaterial
|
<meshStandardMaterial
|
||||||
side={THREE.DoubleSide}
|
side={THREE.DoubleSide}
|
||||||
color={CONSTANTS.wallConfig.defaultColor}
|
color={CONSTANTS.wallConfig.defaultColor}
|
||||||
map={wallTexture}
|
map={wallTexture}
|
||||||
/>
|
/>
|
||||||
</Base>
|
</Base>
|
||||||
<mesh
|
<mesh
|
||||||
castShadow
|
castShadow
|
||||||
geometry={wall[0]}
|
geometry={wall[0]}
|
||||||
rotation={wall[1]}
|
rotation={wall[1]}
|
||||||
position={wall[2]}
|
position={wall[2]}
|
||||||
name={`WallRaycastReference_${index + 1}`}
|
name={`WallRaycastReference_${index + 1}`}
|
||||||
>
|
>
|
||||||
<MeshDiscardMaterial />
|
<MeshDiscardMaterial />
|
||||||
</mesh>
|
</mesh>
|
||||||
</mesh>
|
</mesh>
|
||||||
))}
|
))}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const WallsMesh = React.memo(WallsMeshComponent);
|
const WallsMesh = React.memo(WallsMeshComponent);
|
||||||
|
|
|
@ -10,6 +10,7 @@ import updateCamPosition from "../camera/updateCameraPosition";
|
||||||
import CamMode from "../camera/camMode";
|
import CamMode from "../camera/camMode";
|
||||||
import SwitchView from "../camera/switchView";
|
import SwitchView from "../camera/switchView";
|
||||||
import SelectionControls from "./selectionControls/selectionControls";
|
import SelectionControls from "./selectionControls/selectionControls";
|
||||||
|
import TransformControl from "./transformControls/transformControls";
|
||||||
|
|
||||||
export default function Controls() {
|
export default function Controls() {
|
||||||
const controlsRef = useRef<CameraControls>(null);
|
const controlsRef = useRef<CameraControls>(null);
|
||||||
|
@ -138,6 +139,8 @@ export default function Controls() {
|
||||||
|
|
||||||
<SelectionControls />
|
<SelectionControls />
|
||||||
|
|
||||||
|
<TransformControl />
|
||||||
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
|
@ -1,270 +1,270 @@
|
||||||
import React, { useRef } from "react";
|
import React, { useRef } from "react";
|
||||||
import {
|
import {
|
||||||
Vector3,
|
Vector3,
|
||||||
Raycaster,
|
Raycaster,
|
||||||
BufferGeometry,
|
BufferGeometry,
|
||||||
LineBasicMaterial,
|
LineBasicMaterial,
|
||||||
Line,
|
Line,
|
||||||
Mesh,
|
Mesh,
|
||||||
Group,
|
Group,
|
||||||
} from "three";
|
} from "three";
|
||||||
import { useThree, useFrame } from "@react-three/fiber";
|
import { useThree, useFrame } from "@react-three/fiber";
|
||||||
import { Html } from "@react-three/drei";
|
import { Html } from "@react-three/drei";
|
||||||
|
|
||||||
interface DistanceFindingControlsProps {
|
interface DistanceFindingControlsProps {
|
||||||
boundingBoxRef: React.RefObject<Mesh>;
|
boundingBoxRef: React.RefObject<Mesh>;
|
||||||
object: number;
|
object: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DistanceFindingControls = ({
|
const DistanceFindingControls = ({
|
||||||
boundingBoxRef,
|
boundingBoxRef,
|
||||||
object,
|
object,
|
||||||
}: DistanceFindingControlsProps) => {
|
}: DistanceFindingControlsProps) => {
|
||||||
const { camera, scene } = useThree();
|
const { camera, scene } = useThree();
|
||||||
|
|
||||||
// Refs for measurement lines
|
// Refs for measurement lines
|
||||||
const line1 = useRef<Line>(null);
|
const line1 = useRef<Line>(null);
|
||||||
const line2 = useRef<Line>(null);
|
const line2 = useRef<Line>(null);
|
||||||
const line3 = useRef<Line>(null);
|
const line3 = useRef<Line>(null);
|
||||||
const line4 = useRef<Line>(null);
|
const line4 = useRef<Line>(null);
|
||||||
const line5 = useRef<Line>(null);
|
const line5 = useRef<Line>(null);
|
||||||
|
|
||||||
// Refs for measurement text labels
|
// Refs for measurement text labels
|
||||||
const textPosX = useRef<Group>(null);
|
const textPosX = useRef<Group>(null);
|
||||||
const textNegX = useRef<Group>(null);
|
const textNegX = useRef<Group>(null);
|
||||||
const textPosZ = useRef<Group>(null);
|
const textPosZ = useRef<Group>(null);
|
||||||
const textNegZ = useRef<Group>(null);
|
const textNegZ = useRef<Group>(null);
|
||||||
const textPosY = useRef<Group>(null);
|
const textPosY = useRef<Group>(null);
|
||||||
|
|
||||||
// Store line geometries to avoid recreation
|
// Store line geometries to avoid recreation
|
||||||
const lineGeometries = useRef({
|
const lineGeometries = useRef({
|
||||||
posX: new BufferGeometry(),
|
posX: new BufferGeometry(),
|
||||||
negX: new BufferGeometry(),
|
negX: new BufferGeometry(),
|
||||||
posZ: new BufferGeometry(),
|
posZ: new BufferGeometry(),
|
||||||
negZ: new BufferGeometry(),
|
negZ: new BufferGeometry(),
|
||||||
posY: new BufferGeometry(),
|
posY: new BufferGeometry(),
|
||||||
});
|
});
|
||||||
|
|
||||||
useFrame(() => {
|
useFrame(() => {
|
||||||
if (!boundingBoxRef?.current) return;
|
if (!boundingBoxRef?.current) return;
|
||||||
|
|
||||||
boundingBoxRef.current.geometry.computeBoundingBox();
|
boundingBoxRef.current.geometry.computeBoundingBox();
|
||||||
const bbox = boundingBoxRef.current.geometry.boundingBox;
|
const bbox = boundingBoxRef.current.geometry.boundingBox;
|
||||||
|
|
||||||
if (!bbox) return;
|
if (!bbox) return;
|
||||||
|
|
||||||
const size = {
|
const size = {
|
||||||
x: bbox.max.x - bbox.min.x,
|
x: bbox.max.x - bbox.min.x,
|
||||||
y: bbox.max.y - bbox.min.y,
|
y: bbox.max.y - bbox.min.y,
|
||||||
z: bbox.max.z - bbox.min.z,
|
z: bbox.max.z - bbox.min.z,
|
||||||
|
};
|
||||||
|
|
||||||
|
const vec = boundingBoxRef.current?.getWorldPosition(new Vector3()).clone();
|
||||||
|
|
||||||
|
if (!vec) return;
|
||||||
|
updateLine({
|
||||||
|
line: line1.current,
|
||||||
|
geometry: lineGeometries.current.posX,
|
||||||
|
direction: new Vector3(1, 0, 0), // Positive X
|
||||||
|
angle: "pos",
|
||||||
|
mesh: textPosX,
|
||||||
|
vec,
|
||||||
|
size,
|
||||||
|
});
|
||||||
|
updateLine({
|
||||||
|
line: line2.current,
|
||||||
|
geometry: lineGeometries.current.negX,
|
||||||
|
direction: new Vector3(-1, 0, 0), // Negative X
|
||||||
|
angle: "neg",
|
||||||
|
mesh: textNegX,
|
||||||
|
vec,
|
||||||
|
size,
|
||||||
|
});
|
||||||
|
updateLine({
|
||||||
|
line: line3.current,
|
||||||
|
geometry: lineGeometries.current.posZ,
|
||||||
|
direction: new Vector3(0, 0, 1), // Positive Z
|
||||||
|
angle: "pos",
|
||||||
|
mesh: textPosZ,
|
||||||
|
vec,
|
||||||
|
size,
|
||||||
|
});
|
||||||
|
updateLine({
|
||||||
|
line: line4.current,
|
||||||
|
geometry: lineGeometries.current.negZ,
|
||||||
|
direction: new Vector3(0, 0, -1), // Negative Z
|
||||||
|
angle: "neg",
|
||||||
|
mesh: textNegZ,
|
||||||
|
vec,
|
||||||
|
size,
|
||||||
|
});
|
||||||
|
updateLine({
|
||||||
|
line: line5.current,
|
||||||
|
geometry: lineGeometries.current.posY,
|
||||||
|
direction: new Vector3(0, -1, 0), // Down (Y)
|
||||||
|
angle: "posY",
|
||||||
|
mesh: textPosY,
|
||||||
|
vec,
|
||||||
|
size,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const updateLine = ({
|
||||||
|
line,
|
||||||
|
geometry,
|
||||||
|
direction,
|
||||||
|
angle,
|
||||||
|
mesh,
|
||||||
|
vec,
|
||||||
|
size,
|
||||||
|
}: {
|
||||||
|
line: Line | null;
|
||||||
|
geometry: BufferGeometry;
|
||||||
|
direction: Vector3;
|
||||||
|
angle: string;
|
||||||
|
mesh: React.RefObject<Group>;
|
||||||
|
vec: Vector3;
|
||||||
|
size: { x: number; y: number; z: number };
|
||||||
|
}) => {
|
||||||
|
if (!line) return;
|
||||||
|
|
||||||
|
const points = [];
|
||||||
|
|
||||||
|
if (angle === "pos") {
|
||||||
|
points[0] = new Vector3(vec.x, vec.y, vec.z).add(
|
||||||
|
new Vector3((direction.x * size.x) / 2, 0, (direction.z * size.z) / 2)
|
||||||
|
);
|
||||||
|
} else if (angle === "neg") {
|
||||||
|
points[0] = new Vector3(vec.x, vec.y, vec.z).sub(
|
||||||
|
new Vector3((-direction.x * size.x) / 2, 0, (-direction.z * size.z) / 2)
|
||||||
|
);
|
||||||
|
} else if (angle === "posY") {
|
||||||
|
points[0] = new Vector3(vec.x, vec.y, vec.z).sub(
|
||||||
|
new Vector3(0, size.y / 2, 0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ray = new Raycaster();
|
||||||
|
if (camera) ray.camera = camera;
|
||||||
|
ray.set(new Vector3(vec.x, vec.y, vec.z), direction);
|
||||||
|
ray.params.Line.threshold = 0.1;
|
||||||
|
|
||||||
|
// Find intersection points
|
||||||
|
const wallsGroup = scene.children.find((val) =>
|
||||||
|
val?.name.includes("Walls")
|
||||||
|
);
|
||||||
|
const intersects = wallsGroup
|
||||||
|
? ray.intersectObjects([wallsGroup], true)
|
||||||
|
: [];
|
||||||
|
|
||||||
|
// Find intersection point
|
||||||
|
if (intersects[0]) {
|
||||||
|
for (const intersect of intersects) {
|
||||||
|
if (intersect.object.name.includes("Wall")) {
|
||||||
|
points[1] =
|
||||||
|
angle !== "posY" ? intersect.point : new Vector3(vec.x, 0, vec.z); // Floor
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update line geometry
|
||||||
|
if (points[1]) {
|
||||||
|
geometry.dispose();
|
||||||
|
geometry.setFromPoints([points[0], points[1]]);
|
||||||
|
line.geometry = geometry;
|
||||||
|
|
||||||
|
// Update measurement text
|
||||||
|
if (mesh?.current) {
|
||||||
|
geometry.computeBoundingSphere();
|
||||||
|
const center = geometry.boundingSphere?.center;
|
||||||
|
if (center) {
|
||||||
|
mesh.current.position.copy(center);
|
||||||
|
}
|
||||||
|
const label = document.getElementById(mesh.current.name);
|
||||||
|
if (label) {
|
||||||
|
label.innerText = `${points[0].distanceTo(points[1]).toFixed(2)}m`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// No intersection found - clear the line
|
||||||
|
geometry.dispose();
|
||||||
|
geometry.setFromPoints([new Vector3(), new Vector3()]);
|
||||||
|
line.geometry = geometry;
|
||||||
|
const label = document.getElementById(mesh?.current?.name ?? "");
|
||||||
|
if (label) label.innerText = "";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const vec = boundingBoxRef.current?.getWorldPosition(new Vector3()).clone();
|
const Material = new LineBasicMaterial({ color: "#d2baff" });
|
||||||
|
|
||||||
if (!vec) return;
|
return (
|
||||||
updateLine({
|
|
||||||
line: line1.current,
|
|
||||||
geometry: lineGeometries.current.posX,
|
|
||||||
direction: new Vector3(1, 0, 0), // Positive X
|
|
||||||
angle: "pos",
|
|
||||||
mesh: textPosX,
|
|
||||||
vec,
|
|
||||||
size,
|
|
||||||
});
|
|
||||||
updateLine({
|
|
||||||
line: line2.current,
|
|
||||||
geometry: lineGeometries.current.negX,
|
|
||||||
direction: new Vector3(-1, 0, 0), // Negative X
|
|
||||||
angle: "neg",
|
|
||||||
mesh: textNegX,
|
|
||||||
vec,
|
|
||||||
size,
|
|
||||||
});
|
|
||||||
updateLine({
|
|
||||||
line: line3.current,
|
|
||||||
geometry: lineGeometries.current.posZ,
|
|
||||||
direction: new Vector3(0, 0, 1), // Positive Z
|
|
||||||
angle: "pos",
|
|
||||||
mesh: textPosZ,
|
|
||||||
vec,
|
|
||||||
size,
|
|
||||||
});
|
|
||||||
updateLine({
|
|
||||||
line: line4.current,
|
|
||||||
geometry: lineGeometries.current.negZ,
|
|
||||||
direction: new Vector3(0, 0, -1), // Negative Z
|
|
||||||
angle: "neg",
|
|
||||||
mesh: textNegZ,
|
|
||||||
vec,
|
|
||||||
size,
|
|
||||||
});
|
|
||||||
updateLine({
|
|
||||||
line: line5.current,
|
|
||||||
geometry: lineGeometries.current.posY,
|
|
||||||
direction: new Vector3(0, -1, 0), // Down (Y)
|
|
||||||
angle: "posY",
|
|
||||||
mesh: textPosY,
|
|
||||||
vec,
|
|
||||||
size,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const updateLine = ({
|
|
||||||
line,
|
|
||||||
geometry,
|
|
||||||
direction,
|
|
||||||
angle,
|
|
||||||
mesh,
|
|
||||||
vec,
|
|
||||||
size,
|
|
||||||
}: {
|
|
||||||
line: Line | null;
|
|
||||||
geometry: BufferGeometry;
|
|
||||||
direction: Vector3;
|
|
||||||
angle: string;
|
|
||||||
mesh: React.RefObject<Group>;
|
|
||||||
vec: Vector3;
|
|
||||||
size: { x: number; y: number; z: number };
|
|
||||||
}) => {
|
|
||||||
if (!line) return;
|
|
||||||
|
|
||||||
const points = [];
|
|
||||||
|
|
||||||
if (angle === "pos") {
|
|
||||||
points[0] = new Vector3(vec.x, vec.y, vec.z).add(
|
|
||||||
new Vector3((direction.x * size.x) / 2, 0, (direction.z * size.z) / 2)
|
|
||||||
);
|
|
||||||
} else if (angle === "neg") {
|
|
||||||
points[0] = new Vector3(vec.x, vec.y, vec.z).sub(
|
|
||||||
new Vector3((-direction.x * size.x) / 2, 0, (-direction.z * size.z) / 2)
|
|
||||||
);
|
|
||||||
} else if (angle === "posY") {
|
|
||||||
points[0] = new Vector3(vec.x, vec.y, vec.z).sub(
|
|
||||||
new Vector3(0, size.y / 2, 0)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const ray = new Raycaster();
|
|
||||||
if (camera) ray.camera = camera;
|
|
||||||
ray.set(new Vector3(vec.x, vec.y, vec.z), direction);
|
|
||||||
ray.params.Line.threshold = 0.1;
|
|
||||||
|
|
||||||
// Find intersection points
|
|
||||||
const wallsGroup = scene.children.find((val) =>
|
|
||||||
val?.name.includes("Walls")
|
|
||||||
);
|
|
||||||
const intersects = wallsGroup
|
|
||||||
? ray.intersectObjects([wallsGroup], true)
|
|
||||||
: [];
|
|
||||||
|
|
||||||
// Find intersection point
|
|
||||||
if (intersects[0]) {
|
|
||||||
for (const intersect of intersects) {
|
|
||||||
if (intersect.object.name.includes("Wall")) {
|
|
||||||
points[1] =
|
|
||||||
angle !== "posY" ? intersect.point : new Vector3(vec.x, 0, vec.z); // Floor
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update line geometry
|
|
||||||
if (points[1]) {
|
|
||||||
geometry.dispose();
|
|
||||||
geometry.setFromPoints([points[0], points[1]]);
|
|
||||||
line.geometry = geometry;
|
|
||||||
|
|
||||||
// Update measurement text
|
|
||||||
if (mesh?.current) {
|
|
||||||
geometry.computeBoundingSphere();
|
|
||||||
const center = geometry.boundingSphere?.center;
|
|
||||||
if (center) {
|
|
||||||
mesh.current.position.copy(center);
|
|
||||||
}
|
|
||||||
const label = document.getElementById(mesh.current.name);
|
|
||||||
if (label) {
|
|
||||||
label.innerText = `${points[0].distanceTo(points[1]).toFixed(2)}m`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// No intersection found - clear the line
|
|
||||||
geometry.dispose();
|
|
||||||
geometry.setFromPoints([new Vector3(), new Vector3()]);
|
|
||||||
line.geometry = geometry;
|
|
||||||
const label = document.getElementById(mesh?.current?.name ?? "");
|
|
||||||
if (label) label.innerText = "";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const Material = new LineBasicMaterial({ color: "#d2baff" });
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{/* Measurement text labels */}
|
|
||||||
{boundingBoxRef.current && object > 0 && (
|
|
||||||
<>
|
<>
|
||||||
<group name="textPosX" ref={textPosX}>
|
{/* Measurement text labels */}
|
||||||
<Html
|
{boundingBoxRef.current && object > 0 && (
|
||||||
wrapperClass="distance-text-wrapper"
|
<>
|
||||||
className="distance-text"
|
<group name="textPosX" ref={textPosX}>
|
||||||
zIndexRange={[1, 0]}
|
<Html
|
||||||
style={{ pointerEvents: "none" }}
|
wrapperClass="distance-text-wrapper"
|
||||||
>
|
className="distance-text"
|
||||||
<div className="distance-label" id="textPosX"></div>
|
zIndexRange={[1, 0]}
|
||||||
</Html>
|
style={{ pointerEvents: "none" }}
|
||||||
</group>
|
>
|
||||||
<group name="textNegX" ref={textNegX}>
|
<div className="distance-label" id="textPosX"></div>
|
||||||
<Html
|
</Html>
|
||||||
wrapperClass="distance-text-wrapper"
|
</group>
|
||||||
className="distance-text"
|
<group name="textNegX" ref={textNegX}>
|
||||||
zIndexRange={[1, 0]}
|
<Html
|
||||||
style={{ pointerEvents: "none" }}
|
wrapperClass="distance-text-wrapper"
|
||||||
>
|
className="distance-text"
|
||||||
<div className="distance-label" id="textNegX"></div>
|
zIndexRange={[1, 0]}
|
||||||
</Html>
|
style={{ pointerEvents: "none" }}
|
||||||
</group>
|
>
|
||||||
<group name="textPosZ" ref={textPosZ}>
|
<div className="distance-label" id="textNegX"></div>
|
||||||
<Html
|
</Html>
|
||||||
wrapperClass="distance-text-wrapper"
|
</group>
|
||||||
className="distance-text"
|
<group name="textPosZ" ref={textPosZ}>
|
||||||
zIndexRange={[2, 0]}
|
<Html
|
||||||
style={{ pointerEvents: "none" }}
|
wrapperClass="distance-text-wrapper"
|
||||||
>
|
className="distance-text"
|
||||||
<div className="distance-label" id="textPosZ"></div>
|
zIndexRange={[2, 0]}
|
||||||
</Html>
|
style={{ pointerEvents: "none" }}
|
||||||
</group>
|
>
|
||||||
<group name="textNegZ" ref={textNegZ}>
|
<div className="distance-label" id="textPosZ"></div>
|
||||||
<Html
|
</Html>
|
||||||
wrapperClass="distance-text-wrapper"
|
</group>
|
||||||
className="distance-text"
|
<group name="textNegZ" ref={textNegZ}>
|
||||||
zIndexRange={[1, 0]}
|
<Html
|
||||||
style={{ pointerEvents: "none" }}
|
wrapperClass="distance-text-wrapper"
|
||||||
>
|
className="distance-text"
|
||||||
<div className="distance-label" id="textNegZ"></div>
|
zIndexRange={[1, 0]}
|
||||||
</Html>
|
style={{ pointerEvents: "none" }}
|
||||||
</group>
|
>
|
||||||
|
<div className="distance-label" id="textNegZ"></div>
|
||||||
|
</Html>
|
||||||
|
</group>
|
||||||
|
|
||||||
{/* Measurement lines */}
|
{/* Measurement lines */}
|
||||||
<primitive
|
<primitive
|
||||||
object={new Line(new BufferGeometry(), Material)}
|
object={new Line(new BufferGeometry(), Material)}
|
||||||
ref={line1}
|
ref={line1}
|
||||||
/>
|
/>
|
||||||
<primitive
|
<primitive
|
||||||
object={new Line(new BufferGeometry(), Material)}
|
object={new Line(new BufferGeometry(), Material)}
|
||||||
ref={line2}
|
ref={line2}
|
||||||
/>
|
/>
|
||||||
<primitive
|
<primitive
|
||||||
object={new Line(new BufferGeometry(), Material)}
|
object={new Line(new BufferGeometry(), Material)}
|
||||||
ref={line3}
|
ref={line3}
|
||||||
/>
|
/>
|
||||||
<primitive
|
<primitive
|
||||||
object={new Line(new BufferGeometry(), Material)}
|
object={new Line(new BufferGeometry(), Material)}
|
||||||
ref={line4}
|
ref={line4}
|
||||||
/>
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
);
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default DistanceFindingControls;
|
export default DistanceFindingControls;
|
||||||
|
|
|
@ -2,10 +2,10 @@ import * as THREE from "three";
|
||||||
import { useEffect, useMemo, useRef, useState } from "react";
|
import { useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { useFrame, useThree } from "@react-three/fiber";
|
import { useFrame, useThree } from "@react-three/fiber";
|
||||||
import {
|
import {
|
||||||
useFloorItems,
|
useFloorItems,
|
||||||
useSelectedAssets,
|
useSelectedAssets,
|
||||||
useSocketStore,
|
useSocketStore,
|
||||||
useToggleView,
|
useToggleView,
|
||||||
} from "../../../../store/store";
|
} from "../../../../store/store";
|
||||||
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
|
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
|
@ -19,370 +19,337 @@ import { snapControls } from "../../../../utils/handleSnap";
|
||||||
import DistanceFindingControls from "./distanceFindingControls";
|
import DistanceFindingControls from "./distanceFindingControls";
|
||||||
|
|
||||||
function MoveControls({
|
function MoveControls({
|
||||||
movedObjects,
|
|
||||||
setMovedObjects,
|
|
||||||
itemsGroupRef,
|
|
||||||
copiedObjects,
|
|
||||||
setCopiedObjects,
|
|
||||||
pastedObjects,
|
|
||||||
setpastedObjects,
|
|
||||||
duplicatedObjects,
|
|
||||||
setDuplicatedObjects,
|
|
||||||
selectionGroup,
|
|
||||||
rotatedObjects,
|
|
||||||
setRotatedObjects,
|
|
||||||
boundingBoxRef,
|
|
||||||
}: any) {
|
|
||||||
const { camera, controls, gl, scene, pointer, raycaster } = useThree();
|
|
||||||
const plane = useMemo(
|
|
||||||
() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0),
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
const { toggleView } = useToggleView();
|
|
||||||
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
|
|
||||||
const { selectedProduct } = useSelectedProduct();
|
|
||||||
const { floorItems, setFloorItems } = useFloorItems();
|
|
||||||
const { socket } = useSocketStore();
|
|
||||||
const itemsData = useRef<Types.FloorItems>([]);
|
|
||||||
const [keyEvent, setKeyEvent] = useState<
|
|
||||||
"Ctrl" | "Shift" | "Ctrl+Shift" | ""
|
|
||||||
>("");
|
|
||||||
const email = localStorage.getItem("email");
|
|
||||||
const organization = email!.split("@")[1].split(".")[0];
|
|
||||||
|
|
||||||
const updateBackend = (
|
|
||||||
productName: string,
|
|
||||||
productId: string,
|
|
||||||
organization: string,
|
|
||||||
eventData: EventsSchema
|
|
||||||
) => {
|
|
||||||
upsertProductOrEventApi({
|
|
||||||
productName: productName,
|
|
||||||
productId: productId,
|
|
||||||
organization: organization,
|
|
||||||
eventDatas: eventData,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!camera || !scene || toggleView || !itemsGroupRef.current) return;
|
|
||||||
|
|
||||||
const canvasElement = gl.domElement;
|
|
||||||
canvasElement.tabIndex = 0;
|
|
||||||
|
|
||||||
let isMoving = false;
|
|
||||||
|
|
||||||
const onPointerDown = () => {
|
|
||||||
isMoving = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const onPointerMove = () => {
|
|
||||||
isMoving = true;
|
|
||||||
};
|
|
||||||
const onKeyUp = (event: KeyboardEvent) => {
|
|
||||||
// When any modifier is released, reset snap
|
|
||||||
const isModifierKey = event.key === "Control" || event.key === "Shift";
|
|
||||||
|
|
||||||
if (isModifierKey) {
|
|
||||||
setKeyEvent("");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onPointerUp = (event: PointerEvent) => {
|
|
||||||
if (!isMoving && movedObjects.length > 0 && event.button === 0) {
|
|
||||||
event.preventDefault();
|
|
||||||
placeMovedAssets();
|
|
||||||
}
|
|
||||||
if (!isMoving && movedObjects.length > 0 && event.button === 2) {
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
clearSelection();
|
|
||||||
movedObjects.forEach((asset: any) => {
|
|
||||||
if (itemsGroupRef.current) {
|
|
||||||
itemsGroupRef.current.attach(asset);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
setFloorItems([...floorItems, ...itemsData.current]);
|
|
||||||
|
|
||||||
setMovedObjects([]);
|
|
||||||
itemsData.current = [];
|
|
||||||
}
|
|
||||||
setKeyEvent("");
|
|
||||||
};
|
|
||||||
|
|
||||||
const onKeyDown = (event: KeyboardEvent) => {
|
|
||||||
const keyCombination = detectModifierKeys(event);
|
|
||||||
|
|
||||||
if (
|
|
||||||
pastedObjects.length > 0 ||
|
|
||||||
duplicatedObjects.length > 0 ||
|
|
||||||
rotatedObjects.length > 0
|
|
||||||
)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (
|
|
||||||
keyCombination === "Ctrl" ||
|
|
||||||
keyCombination === "Ctrl+Shift" ||
|
|
||||||
keyCombination === "Shift"
|
|
||||||
) {
|
|
||||||
// update state here
|
|
||||||
setKeyEvent(keyCombination);
|
|
||||||
} else {
|
|
||||||
setKeyEvent("");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keyCombination === "G") {
|
|
||||||
if (selectedAssets.length > 0) {
|
|
||||||
moveAssets();
|
|
||||||
itemsData.current = floorItems.filter((item: { modelUuid: string }) =>
|
|
||||||
selectedAssets.some((asset: any) => asset.uuid === item.modelUuid)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keyCombination === "ESCAPE") {
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
clearSelection();
|
|
||||||
movedObjects.forEach((asset: any) => {
|
|
||||||
if (itemsGroupRef.current) {
|
|
||||||
itemsGroupRef.current.attach(asset);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
setFloorItems([...floorItems, ...itemsData.current]);
|
|
||||||
|
|
||||||
setMovedObjects([]);
|
|
||||||
itemsData.current = [];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!toggleView) {
|
|
||||||
canvasElement.addEventListener("pointerdown", onPointerDown);
|
|
||||||
canvasElement.addEventListener("pointermove", onPointerMove);
|
|
||||||
canvasElement.addEventListener("pointerup", onPointerUp);
|
|
||||||
canvasElement.addEventListener("keydown", onKeyDown);
|
|
||||||
canvasElement?.addEventListener("keyup", onKeyUp);
|
|
||||||
}
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
canvasElement.removeEventListener("pointerdown", onPointerDown);
|
|
||||||
canvasElement.removeEventListener("pointermove", onPointerMove);
|
|
||||||
canvasElement.removeEventListener("pointerup", onPointerUp);
|
|
||||||
canvasElement.removeEventListener("keydown", onKeyDown);
|
|
||||||
canvasElement?.removeEventListener("keyup", onKeyUp);
|
|
||||||
};
|
|
||||||
}, [
|
|
||||||
camera,
|
|
||||||
controls,
|
|
||||||
scene,
|
|
||||||
toggleView,
|
|
||||||
selectedAssets,
|
|
||||||
socket,
|
|
||||||
floorItems,
|
|
||||||
pastedObjects,
|
|
||||||
duplicatedObjects,
|
|
||||||
movedObjects,
|
movedObjects,
|
||||||
|
setMovedObjects,
|
||||||
|
itemsGroupRef,
|
||||||
|
pastedObjects,
|
||||||
|
setpastedObjects,
|
||||||
|
duplicatedObjects,
|
||||||
|
setDuplicatedObjects,
|
||||||
|
selectionGroup,
|
||||||
rotatedObjects,
|
rotatedObjects,
|
||||||
keyEvent,
|
setRotatedObjects,
|
||||||
]);
|
boundingBoxRef,
|
||||||
|
}: any) {
|
||||||
|
const { camera, controls, gl, scene, pointer, raycaster } = useThree();
|
||||||
|
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
||||||
|
|
||||||
let moveSpeed = keyEvent === "Ctrl" || "Ctrl+Shift" ? 1 : 0.25;
|
const { toggleView } = useToggleView();
|
||||||
|
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
|
||||||
|
const { selectedProduct } = useSelectedProduct();
|
||||||
|
const { floorItems, setFloorItems } = useFloorItems();
|
||||||
|
const { socket } = useSocketStore();
|
||||||
|
const itemsData = useRef<Types.FloorItems>([]);
|
||||||
|
const [keyEvent, setKeyEvent] = useState<"Ctrl" | "Shift" | "Ctrl+Shift" | "">("");
|
||||||
|
const email = localStorage.getItem("email");
|
||||||
|
const organization = email!.split("@")[1].split(".")[0];
|
||||||
|
|
||||||
useFrame(() => {
|
const updateBackend = (
|
||||||
if (movedObjects.length > 0) {
|
productName: string,
|
||||||
const intersectionPoint = new THREE.Vector3();
|
productId: string,
|
||||||
raycaster.setFromCamera(pointer, camera);
|
organization: string,
|
||||||
const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
eventData: EventsSchema
|
||||||
|
) => {
|
||||||
|
upsertProductOrEventApi({
|
||||||
|
productName: productName,
|
||||||
|
productId: productId,
|
||||||
|
organization: organization,
|
||||||
|
eventDatas: eventData,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
if (point) {
|
useEffect(() => {
|
||||||
let targetX = point.x;
|
if (!camera || !scene || toggleView || !itemsGroupRef.current) return;
|
||||||
let targetZ = point.z;
|
|
||||||
if (keyEvent === "Ctrl") {
|
|
||||||
targetX = snapControls(targetX, "Ctrl");
|
|
||||||
targetZ = snapControls(targetZ, "Ctrl");
|
|
||||||
}
|
|
||||||
// else if (keyEvent === "Ctrl+Shift") {
|
|
||||||
// targetX = snapControls(targetX, "Ctrl+Shift");
|
|
||||||
// targetZ = snapControls(targetZ, "Ctrl+Shift");
|
|
||||||
// } else if (keyEvent === "Shift") {
|
|
||||||
// targetX = snapControls(targetX, "Shift");
|
|
||||||
// targetZ = snapControls(targetZ, "Shift");
|
|
||||||
// } else {
|
|
||||||
// }
|
|
||||||
|
|
||||||
const position = new THREE.Vector3();
|
const canvasElement = gl.domElement;
|
||||||
|
canvasElement.tabIndex = 0;
|
||||||
|
|
||||||
if (boundingBoxRef.current) {
|
let isMoving = false;
|
||||||
boundingBoxRef.current.getWorldPosition(position);
|
|
||||||
selectionGroup.current.position.lerp(
|
|
||||||
new THREE.Vector3(
|
|
||||||
targetX - (position.x - selectionGroup.current.position.x),
|
|
||||||
selectionGroup.current.position.y,
|
|
||||||
targetZ - (position.z - selectionGroup.current.position.z)
|
|
||||||
),
|
|
||||||
moveSpeed
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
const box = new THREE.Box3();
|
|
||||||
movedObjects.forEach((obj: THREE.Object3D) =>
|
|
||||||
box.expandByObject(obj)
|
|
||||||
);
|
|
||||||
const center = new THREE.Vector3();
|
|
||||||
box.getCenter(center);
|
|
||||||
|
|
||||||
selectionGroup.current.position.lerp(
|
const onPointerDown = () => {
|
||||||
new THREE.Vector3(
|
isMoving = false;
|
||||||
targetX - (center.x - selectionGroup.current.position.x),
|
|
||||||
selectionGroup.current.position.y,
|
|
||||||
targetZ - (center.z - selectionGroup.current.position.z)
|
|
||||||
),
|
|
||||||
moveSpeed
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const moveAssets = () => {
|
|
||||||
const updatedItems = floorItems.filter(
|
|
||||||
(item: { modelUuid: string }) =>
|
|
||||||
!selectedAssets.some((asset: any) => asset.uuid === item.modelUuid)
|
|
||||||
);
|
|
||||||
setFloorItems(updatedItems);
|
|
||||||
setMovedObjects(selectedAssets);
|
|
||||||
selectedAssets.forEach((asset: any) => {
|
|
||||||
selectionGroup.current.attach(asset);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const placeMovedAssets = () => {
|
|
||||||
if (movedObjects.length === 0) return;
|
|
||||||
|
|
||||||
movedObjects.forEach(async (obj: THREE.Object3D) => {
|
|
||||||
const worldPosition = new THREE.Vector3();
|
|
||||||
obj.getWorldPosition(worldPosition);
|
|
||||||
|
|
||||||
selectionGroup.current.remove(obj);
|
|
||||||
obj.position.copy(worldPosition);
|
|
||||||
|
|
||||||
if (itemsGroupRef.current) {
|
|
||||||
const newFloorItem: Types.FloorItemType = {
|
|
||||||
modelUuid: obj.uuid,
|
|
||||||
modelName: obj.userData.name,
|
|
||||||
modelfileID: obj.userData.modelId,
|
|
||||||
position: [worldPosition.x, worldPosition.y, worldPosition.z],
|
|
||||||
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
|
||||||
isLocked: false,
|
|
||||||
isVisible: true,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (obj.userData.eventData) {
|
const onPointerMove = () => {
|
||||||
const eventData = useEventsStore
|
isMoving = true;
|
||||||
.getState()
|
};
|
||||||
.getEventByModelUuid(obj.userData.modelUuid);
|
|
||||||
const productData = useProductStore
|
|
||||||
.getState()
|
|
||||||
.getEventByModelUuid(
|
|
||||||
useSelectedProduct.getState().selectedProduct.productId,
|
|
||||||
obj.userData.modelUuid
|
|
||||||
);
|
|
||||||
|
|
||||||
if (eventData) {
|
const onKeyUp = (event: KeyboardEvent) => {
|
||||||
useEventsStore.getState().updateEvent(obj.userData.modelUuid, {
|
const isModifierKey = event.key === "Control" || event.key === "Shift";
|
||||||
position: [worldPosition.x, worldPosition.y, worldPosition.z],
|
|
||||||
rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (productData) {
|
|
||||||
const event = useProductStore
|
|
||||||
.getState()
|
|
||||||
.updateEvent(
|
|
||||||
useSelectedProduct.getState().selectedProduct.productId,
|
|
||||||
obj.userData.modelUuid,
|
|
||||||
{
|
|
||||||
position: [worldPosition.x, worldPosition.y, worldPosition.z],
|
|
||||||
rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z],
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (event) {
|
if (isModifierKey) {
|
||||||
updateBackend(
|
setKeyEvent("");
|
||||||
selectedProduct.productName,
|
}
|
||||||
selectedProduct.productId,
|
};
|
||||||
organization,
|
|
||||||
event
|
const onPointerUp = (event: PointerEvent) => {
|
||||||
);
|
if (!isMoving && movedObjects.length > 0 && event.button === 0) {
|
||||||
|
event.preventDefault();
|
||||||
|
placeMovedAssets();
|
||||||
|
}
|
||||||
|
if (!isMoving && movedObjects.length > 0 && event.button === 2) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
clearSelection();
|
||||||
|
movedObjects.forEach((asset: any) => {
|
||||||
|
if (itemsGroupRef.current) {
|
||||||
|
itemsGroupRef.current.attach(asset);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
setFloorItems([...floorItems, ...itemsData.current]);
|
||||||
|
|
||||||
|
setMovedObjects([]);
|
||||||
|
itemsData.current = [];
|
||||||
|
}
|
||||||
|
setKeyEvent("");
|
||||||
|
};
|
||||||
|
|
||||||
|
const onKeyDown = (event: KeyboardEvent) => {
|
||||||
|
const keyCombination = detectModifierKeys(event);
|
||||||
|
|
||||||
|
if (pastedObjects.length > 0 || duplicatedObjects.length > 0 || rotatedObjects.length > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (keyCombination === "Ctrl" || keyCombination === "Ctrl+Shift" || keyCombination === "Shift") {
|
||||||
|
setKeyEvent(keyCombination);
|
||||||
|
} else {
|
||||||
|
setKeyEvent("");
|
||||||
}
|
}
|
||||||
|
|
||||||
newFloorItem.eventData = eventData;
|
if (keyCombination === "G") {
|
||||||
}
|
if (selectedAssets.length > 0) {
|
||||||
}
|
moveAssets();
|
||||||
|
itemsData.current = floorItems.filter((item: { modelUuid: string }) =>
|
||||||
|
selectedAssets.some((asset: any) => asset.uuid === item.modelUuid)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setFloorItems((prevItems: Types.FloorItems) => {
|
if (keyCombination === "ESCAPE") {
|
||||||
const updatedItems = [...(prevItems || []), newFloorItem];
|
event.preventDefault();
|
||||||
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
|
|
||||||
return updatedItems;
|
|
||||||
});
|
|
||||||
|
|
||||||
//REST
|
clearSelection();
|
||||||
|
movedObjects.forEach((asset: any) => {
|
||||||
|
if (itemsGroupRef.current) {
|
||||||
|
itemsGroupRef.current.attach(asset);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// await setFloorItemApi(
|
setFloorItems([...floorItems, ...itemsData.current]);
|
||||||
// organization,
|
|
||||||
// obj.uuid,
|
|
||||||
// obj.userData.name,
|
|
||||||
// [worldPosition.x, worldPosition.y, worldPosition.z],
|
|
||||||
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
|
|
||||||
// obj.userData.modelId,
|
|
||||||
// false,
|
|
||||||
// true,
|
|
||||||
// );
|
|
||||||
|
|
||||||
//SOCKET
|
setMovedObjects([]);
|
||||||
|
itemsData.current = [];
|
||||||
const data = {
|
}
|
||||||
organization,
|
|
||||||
modelUuid: newFloorItem.modelUuid,
|
|
||||||
modelName: newFloorItem.modelName,
|
|
||||||
modelfileID: newFloorItem.modelfileID,
|
|
||||||
position: newFloorItem.position,
|
|
||||||
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
|
||||||
isLocked: false,
|
|
||||||
isVisible: true,
|
|
||||||
socketId: socket.id,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
socket.emit("v2:model-asset:add", data);
|
if (!toggleView) {
|
||||||
|
canvasElement.addEventListener("pointerdown", onPointerDown);
|
||||||
|
canvasElement.addEventListener("pointermove", onPointerMove);
|
||||||
|
canvasElement.addEventListener("pointerup", onPointerUp);
|
||||||
|
canvasElement.addEventListener("keydown", onKeyDown);
|
||||||
|
canvasElement?.addEventListener("keyup", onKeyUp);
|
||||||
|
}
|
||||||
|
|
||||||
itemsGroupRef.current.add(obj);
|
return () => {
|
||||||
}
|
canvasElement.removeEventListener("pointerdown", onPointerDown);
|
||||||
|
canvasElement.removeEventListener("pointermove", onPointerMove);
|
||||||
|
canvasElement.removeEventListener("pointerup", onPointerUp);
|
||||||
|
canvasElement.removeEventListener("keydown", onKeyDown);
|
||||||
|
canvasElement?.removeEventListener("keyup", onKeyUp);
|
||||||
|
};
|
||||||
|
}, [camera, controls, scene, toggleView, selectedAssets, socket, floorItems, pastedObjects, duplicatedObjects, movedObjects, rotatedObjects, keyEvent,]);
|
||||||
|
|
||||||
|
let moveSpeed = keyEvent === "Ctrl" || "Ctrl+Shift" ? 1 : 0.25;
|
||||||
|
|
||||||
|
useFrame(() => {
|
||||||
|
if (movedObjects.length > 0) {
|
||||||
|
const intersectionPoint = new THREE.Vector3();
|
||||||
|
raycaster.setFromCamera(pointer, camera);
|
||||||
|
const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
||||||
|
|
||||||
|
if (point) {
|
||||||
|
let targetX = point.x;
|
||||||
|
let targetZ = point.z;
|
||||||
|
|
||||||
|
if (keyEvent === "Ctrl") {
|
||||||
|
targetX = snapControls(targetX, "Ctrl");
|
||||||
|
targetZ = snapControls(targetZ, "Ctrl");
|
||||||
|
}
|
||||||
|
|
||||||
|
// else if (keyEvent === "Ctrl+Shift") {
|
||||||
|
// targetX = snapControls(targetX, "Ctrl+Shift");
|
||||||
|
// targetZ = snapControls(targetZ, "Ctrl+Shift");
|
||||||
|
// } else if (keyEvent === "Shift") {
|
||||||
|
// targetX = snapControls(targetX, "Shift");
|
||||||
|
// targetZ = snapControls(targetZ, "Shift");
|
||||||
|
// } else {
|
||||||
|
// }
|
||||||
|
|
||||||
|
const position = new THREE.Vector3();
|
||||||
|
|
||||||
|
if (boundingBoxRef.current) {
|
||||||
|
boundingBoxRef.current.getWorldPosition(position);
|
||||||
|
selectionGroup.current.position.lerp(
|
||||||
|
new THREE.Vector3(
|
||||||
|
targetX - (position.x - selectionGroup.current.position.x),
|
||||||
|
selectionGroup.current.position.y,
|
||||||
|
targetZ - (position.z - selectionGroup.current.position.z)
|
||||||
|
),
|
||||||
|
moveSpeed
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
const box = new THREE.Box3();
|
||||||
|
movedObjects.forEach((obj: THREE.Object3D) =>
|
||||||
|
box.expandByObject(obj)
|
||||||
|
);
|
||||||
|
const center = new THREE.Vector3();
|
||||||
|
box.getCenter(center);
|
||||||
|
|
||||||
|
selectionGroup.current.position.lerp(
|
||||||
|
new THREE.Vector3(
|
||||||
|
targetX - (center.x - selectionGroup.current.position.x),
|
||||||
|
selectionGroup.current.position.y,
|
||||||
|
targetZ - (center.z - selectionGroup.current.position.z)
|
||||||
|
),
|
||||||
|
moveSpeed
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
toast.success("Object moved!");
|
|
||||||
|
|
||||||
itemsData.current = [];
|
const moveAssets = () => {
|
||||||
clearSelection();
|
const updatedItems = floorItems.filter(
|
||||||
};
|
(item: { modelUuid: string }) =>
|
||||||
|
!selectedAssets.some((asset: any) => asset.uuid === item.modelUuid)
|
||||||
|
);
|
||||||
|
setFloorItems(updatedItems);
|
||||||
|
setMovedObjects(selectedAssets);
|
||||||
|
selectedAssets.forEach((asset: any) => {
|
||||||
|
selectionGroup.current.attach(asset);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const clearSelection = () => {
|
const placeMovedAssets = () => {
|
||||||
selectionGroup.current.children = [];
|
if (movedObjects.length === 0) return;
|
||||||
selectionGroup.current.position.set(0, 0, 0);
|
|
||||||
selectionGroup.current.rotation.set(0, 0, 0);
|
|
||||||
setpastedObjects([]);
|
|
||||||
setDuplicatedObjects([]);
|
|
||||||
setMovedObjects([]);
|
|
||||||
setRotatedObjects([]);
|
|
||||||
setSelectedAssets([]);
|
|
||||||
setKeyEvent("");
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
movedObjects.forEach(async (obj: THREE.Object3D) => {
|
||||||
<DistanceFindingControls
|
const worldPosition = new THREE.Vector3();
|
||||||
boundingBoxRef={boundingBoxRef}
|
obj.getWorldPosition(worldPosition);
|
||||||
object={movedObjects.length}
|
|
||||||
/>
|
selectionGroup.current.remove(obj);
|
||||||
);
|
obj.position.copy(worldPosition);
|
||||||
|
|
||||||
|
if (itemsGroupRef.current) {
|
||||||
|
const newFloorItem: Types.FloorItemType = {
|
||||||
|
modelUuid: obj.uuid,
|
||||||
|
modelName: obj.userData.name,
|
||||||
|
modelfileID: obj.userData.modelId,
|
||||||
|
position: [worldPosition.x, worldPosition.y, worldPosition.z],
|
||||||
|
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
||||||
|
isLocked: false,
|
||||||
|
isVisible: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (obj.userData.eventData) {
|
||||||
|
const eventData = useEventsStore.getState().getEventByModelUuid(obj.userData.modelUuid);
|
||||||
|
const productData = useProductStore.getState().getEventByModelUuid(selectedProduct.productId, obj.userData.modelUuid);
|
||||||
|
|
||||||
|
if (eventData) {
|
||||||
|
useEventsStore.getState().updateEvent(obj.userData.modelUuid, {
|
||||||
|
position: [worldPosition.x, worldPosition.y, worldPosition.z],
|
||||||
|
rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (productData) {
|
||||||
|
const event = useProductStore
|
||||||
|
.getState()
|
||||||
|
.updateEvent(
|
||||||
|
selectedProduct.productId,
|
||||||
|
obj.userData.modelUuid,
|
||||||
|
{
|
||||||
|
position: [worldPosition.x, worldPosition.y, worldPosition.z],
|
||||||
|
rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (event) {
|
||||||
|
updateBackend(
|
||||||
|
selectedProduct.productName,
|
||||||
|
selectedProduct.productId,
|
||||||
|
organization,
|
||||||
|
event
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
newFloorItem.eventData = eventData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setFloorItems((prevItems: Types.FloorItems) => {
|
||||||
|
const updatedItems = [...(prevItems || []), newFloorItem];
|
||||||
|
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
|
||||||
|
return updatedItems;
|
||||||
|
});
|
||||||
|
|
||||||
|
//REST
|
||||||
|
|
||||||
|
// await setFloorItemApi(
|
||||||
|
// organization,
|
||||||
|
// obj.uuid,
|
||||||
|
// obj.userData.name,
|
||||||
|
// [worldPosition.x, worldPosition.y, worldPosition.z],
|
||||||
|
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
|
||||||
|
// obj.userData.modelId,
|
||||||
|
// false,
|
||||||
|
// true,
|
||||||
|
// );
|
||||||
|
|
||||||
|
//SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
organization,
|
||||||
|
modelUuid: newFloorItem.modelUuid,
|
||||||
|
modelName: newFloorItem.modelName,
|
||||||
|
modelfileID: newFloorItem.modelfileID,
|
||||||
|
position: newFloorItem.position,
|
||||||
|
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
||||||
|
isLocked: false,
|
||||||
|
isVisible: true,
|
||||||
|
socketId: socket.id,
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.emit("v2:model-asset:add", data);
|
||||||
|
|
||||||
|
itemsGroupRef.current.add(obj);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
toast.success("Object moved!");
|
||||||
|
|
||||||
|
itemsData.current = [];
|
||||||
|
clearSelection();
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearSelection = () => {
|
||||||
|
selectionGroup.current.children = [];
|
||||||
|
selectionGroup.current.position.set(0, 0, 0);
|
||||||
|
selectionGroup.current.rotation.set(0, 0, 0);
|
||||||
|
setpastedObjects([]);
|
||||||
|
setDuplicatedObjects([]);
|
||||||
|
setMovedObjects([]);
|
||||||
|
setRotatedObjects([]);
|
||||||
|
setSelectedAssets([]);
|
||||||
|
setKeyEvent("");
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DistanceFindingControls
|
||||||
|
boundingBoxRef={boundingBoxRef}
|
||||||
|
object={movedObjects.length}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default MoveControls;
|
export default MoveControls;
|
||||||
|
|
|
@ -0,0 +1,206 @@
|
||||||
|
import { TransformControls } from "@react-three/drei";
|
||||||
|
import * as THREE from "three";
|
||||||
|
import { useSelectedFloorItem, useObjectPosition, useObjectRotation, useFloorItems, useActiveTool, useSocketStore } from "../../../../store/store";
|
||||||
|
import { useThree } from "@react-three/fiber";
|
||||||
|
|
||||||
|
import * as Types from '../../../../types/world/worldTypes';
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys";
|
||||||
|
import { useEventsStore } from "../../../../store/simulation/useEventsStore";
|
||||||
|
import { useProductStore } from "../../../../store/simulation/useProductStore";
|
||||||
|
import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore";
|
||||||
|
import { upsertProductOrEventApi } from "../../../../services/simulation/UpsertProductOrEventApi";
|
||||||
|
import { setFloorItemApi } from "../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi";
|
||||||
|
|
||||||
|
export default function TransformControl() {
|
||||||
|
const state = useThree();
|
||||||
|
const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null);
|
||||||
|
const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem();
|
||||||
|
const { setObjectPosition } = useObjectPosition();
|
||||||
|
const { setObjectRotation } = useObjectRotation();
|
||||||
|
const { setFloorItems } = useFloorItems();
|
||||||
|
const { activeTool } = useActiveTool();
|
||||||
|
const { socket } = useSocketStore();
|
||||||
|
const { selectedProduct } = useSelectedProduct();
|
||||||
|
|
||||||
|
const email = localStorage.getItem('email')
|
||||||
|
const organization = (email!.split("@")[1]).split(".")[0];
|
||||||
|
|
||||||
|
const updateBackend = (
|
||||||
|
productName: string,
|
||||||
|
productId: string,
|
||||||
|
organization: string,
|
||||||
|
eventData: EventsSchema
|
||||||
|
) => {
|
||||||
|
upsertProductOrEventApi({
|
||||||
|
productName: productName,
|
||||||
|
productId: productId,
|
||||||
|
organization: organization,
|
||||||
|
eventDatas: eventData,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleObjectChange() {
|
||||||
|
if (selectedFloorItem) {
|
||||||
|
setObjectPosition(selectedFloorItem.position);
|
||||||
|
setObjectRotation({
|
||||||
|
x: THREE.MathUtils.radToDeg(selectedFloorItem.rotation.x),
|
||||||
|
y: THREE.MathUtils.radToDeg(selectedFloorItem.rotation.y),
|
||||||
|
z: THREE.MathUtils.radToDeg(selectedFloorItem.rotation.z),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMouseUp() {
|
||||||
|
if (selectedFloorItem) {
|
||||||
|
setObjectPosition(selectedFloorItem.position);
|
||||||
|
setObjectRotation({
|
||||||
|
x: THREE.MathUtils.radToDeg(selectedFloorItem.rotation.x),
|
||||||
|
y: THREE.MathUtils.radToDeg(selectedFloorItem.rotation.y),
|
||||||
|
z: THREE.MathUtils.radToDeg(selectedFloorItem.rotation.z),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setFloorItems((prevItems: Types.FloorItems) => {
|
||||||
|
if (!prevItems) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let updatedItem: any = null;
|
||||||
|
const updatedItems = prevItems.map((item) => {
|
||||||
|
if (item.modelUuid === selectedFloorItem?.uuid) {
|
||||||
|
updatedItem = {
|
||||||
|
...item,
|
||||||
|
position: [selectedFloorItem.position.x, 0, selectedFloorItem.position.z] as [number, number, number],
|
||||||
|
rotation: { x: selectedFloorItem.rotation.x, y: selectedFloorItem.rotation.y, z: selectedFloorItem.rotation.z },
|
||||||
|
};
|
||||||
|
return updatedItem;
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
if (updatedItem && selectedFloorItem) {
|
||||||
|
if (updatedItem.eventData) {
|
||||||
|
const eventData = useEventsStore.getState().getEventByModelUuid(updatedItem.modelUuid);
|
||||||
|
const productData = useProductStore.getState().getEventByModelUuid(selectedProduct.productId, updatedItem.modelUuid);
|
||||||
|
|
||||||
|
if (eventData) {
|
||||||
|
useEventsStore.getState().updateEvent(updatedItem.modelUuid, {
|
||||||
|
position: [selectedFloorItem.position.x, 0, selectedFloorItem.position.z],
|
||||||
|
rotation: [selectedFloorItem.rotation.x, selectedFloorItem.rotation.y, selectedFloorItem.rotation.z],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (productData) {
|
||||||
|
const event = useProductStore
|
||||||
|
.getState()
|
||||||
|
.updateEvent(
|
||||||
|
selectedProduct.productId,
|
||||||
|
updatedItem.modelUuid,
|
||||||
|
{
|
||||||
|
position: [selectedFloorItem.position.x, 0, selectedFloorItem.position.z],
|
||||||
|
rotation: [selectedFloorItem.rotation.x, selectedFloorItem.rotation.y, selectedFloorItem.rotation.z],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (event) {
|
||||||
|
updateBackend(
|
||||||
|
selectedProduct.productName,
|
||||||
|
selectedProduct.productId,
|
||||||
|
organization,
|
||||||
|
event
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedItem.eventData = eventData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setFloorItems((prevItems: Types.FloorItems) => {
|
||||||
|
const updatedItems = [...(prevItems || []), updatedItem];
|
||||||
|
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
|
||||||
|
return updatedItems;
|
||||||
|
});
|
||||||
|
|
||||||
|
// REST
|
||||||
|
|
||||||
|
// setFloorItemApi(
|
||||||
|
// organization,
|
||||||
|
// updatedItem.modelUuid,
|
||||||
|
// updatedItem.modelName,
|
||||||
|
// updatedItem.modelfileid,
|
||||||
|
// [selectedFloorItem.position.x, 0, selectedFloorItem.position.z,],
|
||||||
|
// { "x": selectedFloorItem.rotation.x, "y": selectedFloorItem.rotation.y, "z": selectedFloorItem.rotation.z },
|
||||||
|
// false,
|
||||||
|
// true,
|
||||||
|
// );
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
organization: organization,
|
||||||
|
modelUuid: updatedItem.modelUuid,
|
||||||
|
modelName: updatedItem.modelName,
|
||||||
|
modelfileID: updatedItem.modelfileID,
|
||||||
|
position: [selectedFloorItem.position.x, 0, selectedFloorItem.position.z],
|
||||||
|
rotation: { "x": selectedFloorItem.rotation.x, "y": selectedFloorItem.rotation.y, "z": selectedFloorItem.rotation.z },
|
||||||
|
isLocked: false,
|
||||||
|
isVisible: true,
|
||||||
|
socketId: socket.id
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit("v2:model-asset:add", data);
|
||||||
|
}
|
||||||
|
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
|
||||||
|
return updatedItems;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleKeyDown = (e: KeyboardEvent) => {
|
||||||
|
const keyCombination = detectModifierKeys(e);
|
||||||
|
if (!selectedFloorItem) return;
|
||||||
|
if (keyCombination === "G") {
|
||||||
|
setTransformMode((prev) => (prev === "translate" ? null : "translate"));
|
||||||
|
}
|
||||||
|
if (keyCombination === "R") {
|
||||||
|
setTransformMode((prev) => (prev === "rotate" ? null : "rotate"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (selectedFloorItem) {
|
||||||
|
window.addEventListener("keydown", handleKeyDown);
|
||||||
|
} else {
|
||||||
|
setTransformMode(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener("keydown", handleKeyDown);
|
||||||
|
};
|
||||||
|
}, [selectedFloorItem]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (activeTool === "delete") {
|
||||||
|
if (state.controls) {
|
||||||
|
const target = (state.controls as any).getTarget(new THREE.Vector3());
|
||||||
|
(state.controls as any).setTarget(target.x, 0, target.z, true);
|
||||||
|
}
|
||||||
|
setSelectedFloorItem(null);
|
||||||
|
setObjectPosition({ x: undefined, y: undefined, z: undefined });
|
||||||
|
setObjectRotation({ x: undefined, y: undefined, z: undefined });
|
||||||
|
}
|
||||||
|
}, [activeTool]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{(selectedFloorItem && transformMode) &&
|
||||||
|
<TransformControls
|
||||||
|
showX={transformMode === "translate"}
|
||||||
|
showY={transformMode === "rotate"}
|
||||||
|
showZ={transformMode === "translate"}
|
||||||
|
object={selectedFloorItem}
|
||||||
|
mode={transformMode}
|
||||||
|
onObjectChange={handleObjectChange}
|
||||||
|
onMouseUp={handleMouseUp}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
|
@ -144,11 +144,6 @@ export const useMovePoint = create<any>((set: any) => ({
|
||||||
setMovePoint: (x: any) => set(() => ({ movePoint: x })),
|
setMovePoint: (x: any) => set(() => ({ movePoint: x })),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const useTransformMode = create<any>((set: any) => ({
|
|
||||||
transformMode: null,
|
|
||||||
setTransformMode: (x: any) => set(() => ({ transformMode: x })),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const useDeletePointOrLine = create<any>((set: any) => ({
|
export const useDeletePointOrLine = create<any>((set: any) => ({
|
||||||
deletePointOrLine: false,
|
deletePointOrLine: false,
|
||||||
setDeletePointOrLine: (x: any) => set(() => ({ deletePointOrLine: x })),
|
setDeletePointOrLine: (x: any) => set(() => ({ deletePointOrLine: x })),
|
||||||
|
|
|
@ -225,7 +225,6 @@ interface AssetConfiguration {
|
||||||
scale?: [number, number, number];
|
scale?: [number, number, number];
|
||||||
csgscale?: [number, number, number];
|
csgscale?: [number, number, number];
|
||||||
csgposition?: [number, number, number];
|
csgposition?: [number, number, number];
|
||||||
positionY?: (intersectionPoint: { point: THREE.Vector3 }) => number;
|
|
||||||
type?: "Fixed-Move" | "Free-Move";
|
type?: "Fixed-Move" | "Free-Move";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue