Merge remote-tracking branch 'origin/main-dev' into dev-collaboration
This commit is contained in:
@@ -42,7 +42,6 @@ const SidePannel: React.FC<SidePannelProps> = ({ setActiveTab, activeTab }) => {
|
||||
const projectId = generateProjectId();
|
||||
useSocketStore.getState().initializeSocket(email, organization, token);
|
||||
|
||||
|
||||
//API for creating new Project
|
||||
// const project = await createProject(
|
||||
// projectId,
|
||||
@@ -50,18 +49,16 @@ const SidePannel: React.FC<SidePannelProps> = ({ setActiveTab, activeTab }) => {
|
||||
// savedTheme === "dark" ? darkThemeImage : lightThemeImage,
|
||||
// organization
|
||||
// );
|
||||
// console.log('Created project: ', project);
|
||||
|
||||
const addProject = {
|
||||
userId,
|
||||
thumbnail: savedTheme === "dark" ? darkThemeImage : lightThemeImage,
|
||||
organization: organization,
|
||||
projectUuid: projectId,
|
||||
};
|
||||
// console.log("projectSocket: ", projectSocket);
|
||||
|
||||
if (projectSocket) {
|
||||
// console.log('addProject: ', addProject);
|
||||
const handleResponse = (data: any) => {
|
||||
// console.log('Project add response:', data);
|
||||
if (data.message === "Project created successfully") {
|
||||
setLoadingProgress(1)
|
||||
navigate(`/${data.data.projectId}`);
|
||||
@@ -70,7 +67,6 @@ const SidePannel: React.FC<SidePannelProps> = ({ setActiveTab, activeTab }) => {
|
||||
};
|
||||
projectSocket.on("v1-project:response:add", handleResponse);
|
||||
|
||||
// console.log('addProject: ', addProject);
|
||||
projectSocket.emit("v1:project:add", addProject);
|
||||
} else {
|
||||
console.error("Socket is not connected.");
|
||||
|
||||
@@ -23,12 +23,14 @@ import {
|
||||
useSelectedEventSphere,
|
||||
} from "../../../store/simulation/useSimulationStore";
|
||||
import GlobalProperties from "./properties/GlobalProperties";
|
||||
import AsstePropertiies from "./properties/AssetProperties";
|
||||
import AssetProperties from "./properties/AssetProperties";
|
||||
import ZoneProperties from "./properties/ZoneProperties";
|
||||
import EventProperties from "./properties/eventProperties/EventProperties";
|
||||
import VersionHistory from "./versionHisory/VersionHistory";
|
||||
import AisleProperties from "./properties/AisleProperties";
|
||||
import WallProperties from "./properties/eventProperties/WallProperties";
|
||||
import WallProperties from "./properties/WallProperties";
|
||||
import { useBuilderStore } from "../../../store/builder/useBuilderStore";
|
||||
import SelectedWallProperties from "./properties/SelectedWallProperties";
|
||||
|
||||
const SideBarRight: React.FC = () => {
|
||||
const { activeModule } = useModuleStore();
|
||||
@@ -36,6 +38,7 @@ const SideBarRight: React.FC = () => {
|
||||
const { toolMode } = useToolMode();
|
||||
const { subModule, setSubModule } = useSubModuleStore();
|
||||
const { selectedFloorItem } = useSelectedFloorItem();
|
||||
const { selectedWall } = useBuilderStore();
|
||||
const { selectedEventData } = useSelectedEventData();
|
||||
const { selectedEventSphere } = useSelectedEventSphere();
|
||||
const { viewVersionHistory, setVersionHistoryVisible } = useVersionHistoryVisibleStore();
|
||||
@@ -143,7 +146,8 @@ const SideBarRight: React.FC = () => {
|
||||
{!viewVersionHistory &&
|
||||
subModule === "properties" &&
|
||||
activeModule !== "visualization" &&
|
||||
!selectedFloorItem && (
|
||||
!selectedFloorItem &&
|
||||
!selectedWall && (
|
||||
<div className="sidebar-right-container">
|
||||
<div className="sidebar-right-content-container">
|
||||
{(() => {
|
||||
@@ -158,13 +162,26 @@ const SideBarRight: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!viewVersionHistory &&
|
||||
subModule === "properties" &&
|
||||
activeModule !== "visualization" &&
|
||||
selectedFloorItem && (
|
||||
<div className="sidebar-right-container">
|
||||
<div className="sidebar-right-content-container">
|
||||
<AsstePropertiies />
|
||||
<AssetProperties />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!viewVersionHistory &&
|
||||
subModule === "properties" &&
|
||||
activeModule !== "visualization" &&
|
||||
!selectedFloorItem &&
|
||||
selectedWall && (
|
||||
<div className="sidebar-right-container">
|
||||
<div className="sidebar-right-content-container">
|
||||
<SelectedWallProperties />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@@ -178,6 +195,7 @@ const SideBarRight: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* simulation */}
|
||||
{!isVersionSaved &&
|
||||
!viewVersionHistory &&
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
import { useState } from "react";
|
||||
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
|
||||
|
||||
import defaultTexture from '../../../../assets/textures/floor/wall-tex.png';
|
||||
import wallTexture1 from '../../../../assets/textures/floor/factory wall texture.jpg';
|
||||
|
||||
import { useBuilderStore } from "../../../../store/builder/useBuilderStore";
|
||||
import { useSceneContext } from "../../../../modules/scene/sceneContext";
|
||||
|
||||
const SelectedWallProperties = () => {
|
||||
const { selectedWall } = useBuilderStore();
|
||||
const { wallStore } = useSceneContext();
|
||||
const { getWallById, updateWall } = wallStore();
|
||||
|
||||
const [activeSide, setActiveSide] = useState<"side1" | "side2">("side1");
|
||||
|
||||
const materials = [
|
||||
{ texture: defaultTexture, textureId: "Default Material", textureName: "Default Material" },
|
||||
{ texture: wallTexture1, textureId: "Material 1", textureName: "Grunge Concrete Wall" }
|
||||
];
|
||||
|
||||
const wall = selectedWall ? getWallById(selectedWall.userData.wallUuid) : null;
|
||||
|
||||
const handleHeightChange = (val: string) => {
|
||||
const height = parseFloat(val);
|
||||
if (!isNaN(height) && wall) {
|
||||
updateWall(wall.wallUuid, { wallHeight: height });
|
||||
}
|
||||
};
|
||||
|
||||
const handleThicknessChange = (val: string) => {
|
||||
const thickness = parseFloat(val);
|
||||
if (!isNaN(thickness) && wall) {
|
||||
updateWall(wall.wallUuid, { wallThickness: thickness });
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelectMaterial = (material: { textureId: string; textureName: string }) => {
|
||||
if (!wall) return;
|
||||
|
||||
const updated = (activeSide === "side1" ? { insideMaterial: material.textureId } : { outsideMaterial: material.textureId })
|
||||
|
||||
updateWall(wall.wallUuid, updated);
|
||||
};
|
||||
|
||||
if (!wall) return null;
|
||||
|
||||
const selectedMaterials = {
|
||||
side1: {
|
||||
texture: materials.find((material) => material.textureId === wall.insideMaterial)?.texture || 'Unknown',
|
||||
textureId: materials.find((material) => material.textureId === wall.insideMaterial)?.textureId || 'Unknown',
|
||||
textureName: materials.find((material) => material.textureId === wall.insideMaterial)?.textureName || 'Unknown'
|
||||
},
|
||||
side2: {
|
||||
texture: materials.find((material) => material.textureId === wall.outsideMaterial)?.texture || 'Unknown',
|
||||
textureId: materials.find((material) => material.textureId === wall.outsideMaterial)?.textureId || 'Unknown',
|
||||
textureName: materials.find((material) => material.textureId === wall.outsideMaterial)?.textureName || 'Unknown'
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="wall-properties-container">
|
||||
<section className="wall-properties-section">
|
||||
<div className="header">Wall</div>
|
||||
<div className="wall-properties">
|
||||
<InputWithDropDown
|
||||
label="Height"
|
||||
value={`${wall.wallHeight}`}
|
||||
onChange={handleHeightChange}
|
||||
/>
|
||||
<InputWithDropDown
|
||||
label="Thickness"
|
||||
value={`${wall.wallThickness}`}
|
||||
onChange={handleThicknessChange}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
<section>
|
||||
<div className="header-wrapper">
|
||||
<div className="header">Materials</div>
|
||||
</div>
|
||||
|
||||
<div className="material-preview">
|
||||
<div className="sides-wrapper">
|
||||
{(["side1", "side2"] as const).map((side) => (
|
||||
<button
|
||||
key={side}
|
||||
className={`side-wrapper ${activeSide === side ? "active" : ""}`}
|
||||
onClick={() => setActiveSide(side)}
|
||||
>
|
||||
<div className="label">Side {side === "side1" ? 1 : 2}</div>
|
||||
<div className="texture-image">
|
||||
<img
|
||||
draggable={false}
|
||||
src={selectedMaterials[side].texture}
|
||||
alt={selectedMaterials[side].textureName}
|
||||
/>
|
||||
</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="preview">
|
||||
<img
|
||||
draggable={false}
|
||||
src={selectedMaterials[activeSide].texture}
|
||||
alt={selectedMaterials[activeSide].textureName}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="materials">
|
||||
<div className="material-container">
|
||||
{materials.map((material, index) => {
|
||||
const isSelected = selectedMaterials[activeSide].textureId === material.textureId;
|
||||
|
||||
return (
|
||||
<button
|
||||
className={`material-wrapper ${isSelected ? "selectedMaterial" : ""}`}
|
||||
key={`${material.textureName}_${index}`}
|
||||
onClick={() => handleSelectMaterial(material)}
|
||||
>
|
||||
<div className="material-property">
|
||||
<div className="material-image">
|
||||
<img
|
||||
draggable={false}
|
||||
src={material.texture}
|
||||
alt={material.textureName}
|
||||
/>
|
||||
</div>
|
||||
<div className="material-name">{material.textureName}</div>
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SelectedWallProperties;
|
||||
@@ -1,11 +1,12 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import InputWithDropDown from "../../../../ui/inputs/InputWithDropDown";
|
||||
import { AddIcon, RemoveIcon } from "../../../../icons/ExportCommonIcons";
|
||||
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
|
||||
|
||||
// Texture Imports
|
||||
import wallTexture1 from "../../../../../assets/image/wallTextures/wallTexture.png";
|
||||
import defaultTexture from "../../../../../assets/image/wallTextures/defaultTexture.jpg";
|
||||
import { useBuilderStore } from "../../../../../store/builder/useBuilderStore";
|
||||
|
||||
import defaultTexture from '../../../../assets/textures/floor/wall-tex.png';
|
||||
import wallTexture1 from '../../../../assets/textures/floor/factory wall texture.jpg';
|
||||
|
||||
import { useBuilderStore } from "../../../../store/builder/useBuilderStore";
|
||||
|
||||
// Define Material type
|
||||
type Material = {
|
||||
@@ -58,14 +59,6 @@ const WallProperties = () => {
|
||||
setWallThickness(parseFloat(newValue));
|
||||
};
|
||||
|
||||
const handleAddMaterial = () => {
|
||||
const newMaterial: Material = {
|
||||
texture: defaultMaterial.texture,
|
||||
textureName: `Material ${materials.length + 1}`,
|
||||
};
|
||||
setMaterials([...materials, newMaterial]);
|
||||
};
|
||||
|
||||
const handleSelectMaterial = (material: Material) => {
|
||||
setSelectedMaterials((prev) => ({
|
||||
...prev,
|
||||
@@ -73,46 +66,26 @@ const WallProperties = () => {
|
||||
}));
|
||||
};
|
||||
|
||||
const handleRemoveMaterial = (index: number) => {
|
||||
const removedTexture = materials[index].texture;
|
||||
|
||||
const updatedMaterials = materials.filter((_, i) => i !== index);
|
||||
const newMaterials = updatedMaterials.length === 0 ? [defaultMaterial] : updatedMaterials;
|
||||
setMaterials(newMaterials);
|
||||
|
||||
setSelectedMaterials((prev) => {
|
||||
const updated = { ...prev };
|
||||
["side1", "side2"].forEach((side) => {
|
||||
if (updated[side as "side1" | "side2"]?.texture === removedTexture) {
|
||||
updated[side as "side1" | "side2"] = defaultMaterial;
|
||||
}
|
||||
});
|
||||
return updated;
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="wall-properties-container">
|
||||
<div className="header">Wall</div>
|
||||
<div className="wall-properties">
|
||||
<InputWithDropDown
|
||||
label="Height"
|
||||
value={`${wallHeight}`}
|
||||
onChange={(val) => handleHeightChange(val)}
|
||||
/>
|
||||
<InputWithDropDown
|
||||
label="Thickness"
|
||||
value={`${wallThickness}`}
|
||||
onChange={(val) => handleThicknessChange(val)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<section className="wall-properties-section">
|
||||
<div className="header">Wall</div>
|
||||
<div className="wall-properties">
|
||||
<InputWithDropDown
|
||||
label="Height"
|
||||
value={`${wallHeight}`}
|
||||
onChange={(val) => handleHeightChange(val)}
|
||||
/>
|
||||
<InputWithDropDown
|
||||
label="Thickness"
|
||||
value={`${wallThickness}`}
|
||||
onChange={(val) => handleThicknessChange(val)}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
<section>
|
||||
<div className="header-wrapper">
|
||||
<div className="header">Materials</div>
|
||||
<button className="addMaterial" onClick={handleAddMaterial}>
|
||||
<AddIcon />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="material-preview">
|
||||
@@ -185,15 +158,6 @@ const WallProperties = () => {
|
||||
</div>
|
||||
<div className="material-name">{material.textureName}</div>
|
||||
</div>
|
||||
<button
|
||||
className="delete-material"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleRemoveMaterial(index);
|
||||
}}
|
||||
>
|
||||
<RemoveIcon />
|
||||
</button>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
@@ -91,16 +91,7 @@ const BarChartInput = (props: Props) => {
|
||||
duration: inputDuration,
|
||||
}
|
||||
}
|
||||
// const adding3dWidget = {
|
||||
// organization: organization,
|
||||
// widget: newWidget,
|
||||
// zoneUuid: selectedZone.zoneUuid,
|
||||
// projectId, userId
|
||||
// };
|
||||
// if (visualizationSocket) {
|
||||
// visualizationSocket.emit("v1:viz-3D-widget:add", adding3dWidget);
|
||||
|
||||
// }
|
||||
|
||||
let response = await addingWidgets(selectedZone.zoneUuid, organization, newWidget, projectId, selectedVersion?.versionId || "");
|
||||
|
||||
|
||||
|
||||
@@ -210,15 +210,7 @@ const LineGrapInput = (props: Props) => {
|
||||
}
|
||||
}
|
||||
|
||||
// const adding3dWidget = {
|
||||
// organization: organization,
|
||||
// widget: newWidget,
|
||||
// zoneUuid: selectedZone.zoneUuid,
|
||||
// projectId, userId
|
||||
// };
|
||||
// if (visualizationSocket) {
|
||||
// visualizationSocket.emit("v1:viz-3D-widget:add", adding3dWidget);
|
||||
// }
|
||||
|
||||
let response = await addingWidgets(selectedZone.zoneUuid, organization, newWidget, projectId, selectedVersion?.versionId || "");
|
||||
|
||||
if (response.message === "Widget updated successfully") {
|
||||
|
||||
@@ -94,15 +94,7 @@ const PieChartInput = (props: Props) => {
|
||||
duration: inputDuration,
|
||||
},
|
||||
}
|
||||
// const adding3dWidget = {
|
||||
// organization: organization,
|
||||
// widget: newWidget,
|
||||
// zoneUuid: selectedZone.zoneUuid,
|
||||
// projectId, userId
|
||||
// };
|
||||
// if (visualizationSocket) {
|
||||
// visualizationSocket.emit("v1:viz-3D-widget:add", adding3dWidget);
|
||||
// }
|
||||
|
||||
|
||||
let response = await addingWidgets(selectedZone.zoneUuid, organization, newWidget, projectId, selectedVersion?.versionId || "");
|
||||
|
||||
|
||||
@@ -93,15 +93,7 @@ const Progress1Input = (props: Props) => {
|
||||
duration: inputDuration,
|
||||
},
|
||||
}
|
||||
// const adding3dWidget = {
|
||||
// organization: organization,
|
||||
// widget: newWidget,
|
||||
// zoneUuid: selectedZone.zoneUuid,
|
||||
// projectId, userId
|
||||
// };
|
||||
// if (visualizationSocket) {
|
||||
// visualizationSocket.emit("v1:viz-3D-widget:add", adding3dWidget);
|
||||
// }
|
||||
|
||||
let response = await addingWidgets(selectedZone.zoneUuid, organization, newWidget, projectId, selectedVersion?.versionId || "");
|
||||
|
||||
if (response.message === "Widget updated successfully") {
|
||||
|
||||
@@ -94,16 +94,6 @@ const Progress2Input = (props: Props) => {
|
||||
}
|
||||
}
|
||||
|
||||
// const adding3dWidget = {
|
||||
// organization: organization,
|
||||
// widget: newWidget,
|
||||
// zoneUuid: selectedZone.zoneUuid,
|
||||
// projectId, userId
|
||||
// };
|
||||
// if (visualizationSocket) {
|
||||
// visualizationSocket.emit("v1:viz-3D-widget:add", adding3dWidget);
|
||||
// }
|
||||
|
||||
let response = await addingWidgets(selectedZone.zoneUuid, organization, newWidget, projectId, selectedVersion?.versionId || "");
|
||||
|
||||
if (response.message === "Widget updated successfully") {
|
||||
|
||||
@@ -38,15 +38,15 @@ const Widget2InputCard3D = (props: Props) => {
|
||||
setLoading(true);
|
||||
const response = await axios.get(`http://${iotApiUrl}/floatinput`);
|
||||
if (response.status === 200) {
|
||||
// console.log("dropdown data:", response.data);
|
||||
//
|
||||
setDropDownData(response.data);
|
||||
setLoading(false);
|
||||
} else {
|
||||
// console.log("Unexpected response:", response);
|
||||
//
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch zone data");
|
||||
console.error("There was an error!", error);
|
||||
|
||||
}
|
||||
};
|
||||
fetchZoneData();
|
||||
@@ -55,14 +55,14 @@ const Widget2InputCard3D = (props: Props) => {
|
||||
useEffect(() => {
|
||||
const fetchSavedInputes = async () => {
|
||||
if (selectedChartId.id !== "") {
|
||||
let response = await get3dWidgetInput(selectedChartId.id, organization)
|
||||
console.log('response: ', response);
|
||||
let response = await get3dWidgetInput(selectedChartId.id, organization, projectId, selectedVersion?.versionId || "")
|
||||
|
||||
if (response) {
|
||||
setSelections(response.data.Data.measurements);
|
||||
setDuration(response.data.Data.duration);
|
||||
setWidgetName(response.data.widgetName);
|
||||
setSelections(response.Datastructure.measurements);
|
||||
setDuration(response.Datastructure.duration);
|
||||
setWidgetName(response.widgetName);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@@ -81,44 +81,61 @@ const Widget2InputCard3D = (props: Props) => {
|
||||
inputDuration: any,
|
||||
inputName: any
|
||||
) => {
|
||||
// let newWidget = {
|
||||
// id: selectedChartId.id,
|
||||
// widgetName: inputName,
|
||||
// Data: {
|
||||
// measurements: inputMeasurement,
|
||||
// duration: inputDuration,
|
||||
// },
|
||||
// }
|
||||
|
||||
// let response = await adding3dWidgets(selectedZone.zoneUuid, organization, newWidget,projectId, selectedVersion?.versionId || "")
|
||||
// console.log('response: ', response);
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget3d/save`,
|
||||
{
|
||||
organization,
|
||||
zoneUuid: selectedZone.zoneUuid,
|
||||
widget: {
|
||||
id: selectedChartId.id,
|
||||
widgetName: inputName,
|
||||
Data: {
|
||||
measurements: inputMeasurement,
|
||||
duration: inputDuration,
|
||||
},
|
||||
},
|
||||
} as any
|
||||
);
|
||||
if (response.status === 200) {
|
||||
return true;
|
||||
} else {
|
||||
// console.log("Unexpected response:", response);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to send input");
|
||||
console.error("There was an error!", error);
|
||||
return false;
|
||||
let newWidget = {
|
||||
id: selectedChartId.id,
|
||||
widgetName: inputName,
|
||||
Data: {
|
||||
measurements: inputMeasurement,
|
||||
duration: inputDuration,
|
||||
},
|
||||
}
|
||||
|
||||
let response = await adding3dWidgets(selectedZone.zoneUuid, organization, newWidget, projectId, selectedVersion?.versionId || "")
|
||||
|
||||
if (response.message === "widget update successfully") {
|
||||
return true;
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
// try {
|
||||
// const response = await axios.post(
|
||||
// `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget3d/save`,
|
||||
// {
|
||||
// headers: {
|
||||
// Authorization: "Bearer <access_token>",
|
||||
// "Content-Type": "application/json",
|
||||
// token: localStorage.getItem("token") || "",
|
||||
// refresh_token: localStorage.getItem("refreshToken") || "",
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// organization,
|
||||
// zoneUuid: selectedZone.zoneUuid,
|
||||
// widget: {
|
||||
// id: selectedChartId.id,
|
||||
// widgetName: inputName,
|
||||
// Data: {
|
||||
// measurements: inputMeasurement,
|
||||
// duration: inputDuration,
|
||||
// },
|
||||
// },
|
||||
// projectId: projectId,
|
||||
// versionId: selectedVersion?.versionId || ""
|
||||
// } as any,
|
||||
|
||||
// );
|
||||
//
|
||||
// if (response.status === 200) {
|
||||
// return true;
|
||||
// } else {
|
||||
// //
|
||||
// return false;
|
||||
// }
|
||||
// } catch (error) {
|
||||
// echo.error("Failed to send input");
|
||||
//
|
||||
// return false;
|
||||
// }
|
||||
};
|
||||
|
||||
const handleSelect = async (
|
||||
@@ -133,7 +150,7 @@ const Widget2InputCard3D = (props: Props) => {
|
||||
newSelections[inputKey] = selectedData;
|
||||
}
|
||||
// setMeasurements(newSelections); // Update Zustand store
|
||||
// console.log(newSelections);
|
||||
//
|
||||
if (await sendInputes(newSelections, duration, widgetName)) {
|
||||
setSelections(newSelections);
|
||||
}
|
||||
@@ -150,7 +167,7 @@ const Widget2InputCard3D = (props: Props) => {
|
||||
};
|
||||
|
||||
const handleNameChange = async (name: any) => {
|
||||
// console.log("name change requested", name);
|
||||
//
|
||||
|
||||
if (await sendInputes(selections, duration, name)) {
|
||||
setWidgetName(name);
|
||||
|
||||
@@ -36,15 +36,15 @@ const Widget3InputCard3D = () => {
|
||||
setLoading(true);
|
||||
const response = await axios.get(`http://${iotApiUrl}/getinput`);
|
||||
if (response.status === 200) {
|
||||
// console.log("dropdown data:", response.data);
|
||||
//
|
||||
setDropDownData(response.data);
|
||||
setLoading(false);
|
||||
} else {
|
||||
// console.log("Unexpected response:", response);
|
||||
//
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch zone data");
|
||||
console.error("There was an error!", error);
|
||||
|
||||
}
|
||||
};
|
||||
fetchZoneData();
|
||||
@@ -53,12 +53,12 @@ const Widget3InputCard3D = () => {
|
||||
useEffect(() => {
|
||||
const fetchSavedInputes = async () => {
|
||||
if (selectedChartId.id !== "") {
|
||||
let response = await get3dWidgetInput(selectedChartId.id, organization)
|
||||
console.log('response: ', response);
|
||||
let response = await get3dWidgetInput(selectedChartId.id, organization, projectId, selectedVersion?.versionId || "")
|
||||
|
||||
if (response) {
|
||||
setSelections(response.data.Data.measurements);
|
||||
setDuration(response.data.Data.duration);
|
||||
setWidgetName(response.data.widgetName);
|
||||
setSelections(response.Datastructure.measurements);
|
||||
setDuration(response.Datastructure.duration);
|
||||
setWidgetName(response.widgetName);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -79,45 +79,61 @@ const Widget3InputCard3D = () => {
|
||||
inputName: any
|
||||
) => {
|
||||
|
||||
// let newWidget = {
|
||||
// id: selectedChartId.id,
|
||||
// widgetName: inputName,
|
||||
// Data: {
|
||||
// measurements: inputMeasurement,
|
||||
// duration: inputDuration,
|
||||
// },
|
||||
// }
|
||||
|
||||
// let response = await adding3dWidgets(selectedZone.zoneUuid, organization, newWidget, projectId, selectedVersion?.versionId || "")
|
||||
// console.log('response: ', response);
|
||||
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget3d/save`,
|
||||
{
|
||||
organization,
|
||||
zoneUuid: selectedZone.zoneUuid,
|
||||
widget: {
|
||||
id: selectedChartId.id,
|
||||
widgetName: inputName,
|
||||
Data: {
|
||||
measurements: inputMeasurement,
|
||||
duration: inputDuration,
|
||||
},
|
||||
},
|
||||
} as any
|
||||
);
|
||||
if (response.status === 200) {
|
||||
return true;
|
||||
} else {
|
||||
// console.log("Unexpected response:", response);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to send input");
|
||||
console.error("There was an error!", error);
|
||||
return false;
|
||||
let newWidget = {
|
||||
id: selectedChartId.id,
|
||||
widgetName: inputName,
|
||||
Data: {
|
||||
measurements: inputMeasurement,
|
||||
duration: inputDuration,
|
||||
},
|
||||
}
|
||||
|
||||
let response = await adding3dWidgets(selectedZone.zoneUuid, organization, newWidget, projectId, selectedVersion?.versionId || "")
|
||||
|
||||
if (response.message === "widget update successfully") {
|
||||
return true;
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
|
||||
// try {
|
||||
// const response = await axios.post(
|
||||
// `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget3d/save`,
|
||||
// {
|
||||
// headers: {
|
||||
// Authorization: "Bearer <access_token>",
|
||||
// "Content-Type": "application/json",
|
||||
// token: localStorage.getItem("token") || "",
|
||||
// refresh_token: localStorage.getItem("refreshToken") || "",
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// organization,
|
||||
// zoneUuid: selectedZone.zoneUuid,
|
||||
// widget: {
|
||||
// id: selectedChartId.id,
|
||||
// widgetName: inputName,
|
||||
// Data: {
|
||||
// measurements: inputMeasurement,
|
||||
// duration: inputDuration,
|
||||
// },
|
||||
// },
|
||||
// projectId: projectId,
|
||||
// versionId: selectedVersion?.versionId || ""
|
||||
// } as any
|
||||
// );
|
||||
//
|
||||
// if (response.status === 200) {
|
||||
// return true;
|
||||
// } else {
|
||||
// //
|
||||
// return false;
|
||||
// }
|
||||
// } catch (error) {
|
||||
// echo.error("Failed to send input");
|
||||
//
|
||||
// return false;
|
||||
// }
|
||||
};
|
||||
|
||||
const handleSelect = async (
|
||||
@@ -132,7 +148,7 @@ const Widget3InputCard3D = () => {
|
||||
newSelections[inputKey] = selectedData;
|
||||
}
|
||||
// setMeasurements(newSelections); // Update Zustand store
|
||||
// console.log(newSelections);
|
||||
//
|
||||
if (await sendInputes(newSelections, duration, widgetName)) {
|
||||
setSelections(newSelections);
|
||||
}
|
||||
@@ -145,7 +161,7 @@ const Widget3InputCard3D = () => {
|
||||
};
|
||||
|
||||
const handleNameChange = async (name: any) => {
|
||||
// console.log("name change requested", name);
|
||||
//
|
||||
|
||||
if (await sendInputes(selections, duration, name)) {
|
||||
setWidgetName(name);
|
||||
|
||||
@@ -38,15 +38,15 @@ const Widget4InputCard3D = (props: Props) => {
|
||||
setLoading(true);
|
||||
const response = await axios.get(`http://${iotApiUrl}/floatinput`);
|
||||
if (response.status === 200) {
|
||||
// console.log("dropdown data:", response.data);
|
||||
//
|
||||
setDropDownData(response.data);
|
||||
setLoading(false);
|
||||
} else {
|
||||
// console.log("Unexpected response:", response);
|
||||
//
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch zone data");
|
||||
console.error("There was an error!", error);
|
||||
|
||||
}
|
||||
};
|
||||
fetchZoneData();
|
||||
@@ -55,14 +55,17 @@ const Widget4InputCard3D = (props: Props) => {
|
||||
useEffect(() => {
|
||||
const fetchSavedInputes = async () => {
|
||||
if (selectedChartId.id !== "") {
|
||||
let response = await get3dWidgetInput(selectedChartId.id, organization)
|
||||
console.log('response: ', response);
|
||||
|
||||
|
||||
|
||||
let response = await get3dWidgetInput(selectedChartId.id, organization, projectId, selectedVersion?.versionId || "")
|
||||
|
||||
if (response) {
|
||||
setSelections(response.data.Data.measurements);
|
||||
setDuration(response.data.Data.duration);
|
||||
setWidgetName(response.data.widgetName);
|
||||
setSelections(response.Datastructure.measurements);
|
||||
setDuration(response.Datastructure.duration);
|
||||
setWidgetName(response.widgetName);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@@ -81,44 +84,61 @@ const Widget4InputCard3D = (props: Props) => {
|
||||
inputDuration: any,
|
||||
inputName: any
|
||||
) => {
|
||||
// let newWidget = {
|
||||
// id: selectedChartId.id,
|
||||
// widgetName: inputName,
|
||||
// Data: {
|
||||
// measurements: inputMeasurement,
|
||||
// duration: inputDuration,
|
||||
// },
|
||||
// }
|
||||
|
||||
// let response = await adding3dWidgets(selectedZone.zoneUuid, organization, newWidget, projectId, selectedVersion?.versionId || "")
|
||||
// console.log('response: ', response);
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget3d/save`,
|
||||
{
|
||||
organization,
|
||||
zoneUuid: selectedZone.zoneUuid,
|
||||
widget: {
|
||||
id: selectedChartId.id,
|
||||
widgetName: inputName,
|
||||
Data: {
|
||||
measurements: inputMeasurement,
|
||||
duration: inputDuration,
|
||||
},
|
||||
},
|
||||
} as any
|
||||
);
|
||||
if (response.status === 200) {
|
||||
return true;
|
||||
} else {
|
||||
// console.log("Unexpected response:", response);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to send input");
|
||||
console.error("There was an error!", error);
|
||||
return false;
|
||||
let newWidget = {
|
||||
id: selectedChartId.id,
|
||||
widgetName: inputName,
|
||||
Data: {
|
||||
measurements: inputMeasurement,
|
||||
duration: inputDuration,
|
||||
},
|
||||
}
|
||||
|
||||
let response = await adding3dWidgets(selectedZone.zoneUuid, organization, newWidget, projectId, selectedVersion?.versionId || "")
|
||||
|
||||
if (response.message === "widget update successfully") {
|
||||
return true;
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
//
|
||||
// try {
|
||||
// const response = await axios.post(
|
||||
// `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget3d/save`,
|
||||
// {
|
||||
// headers: {
|
||||
// Authorization: "Bearer <access_token>",
|
||||
// "Content-Type": "application/json",
|
||||
// token: localStorage.getItem("token") || "",
|
||||
// refresh_token: localStorage.getItem("refreshToken") || "",
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// organization,
|
||||
// zoneUuid: selectedZone.zoneUuid,
|
||||
// widget: {
|
||||
// id: selectedChartId.id,
|
||||
// widgetName: inputName,
|
||||
// Data: {
|
||||
// measurements: inputMeasurement,
|
||||
// duration: inputDuration,
|
||||
// },
|
||||
// },
|
||||
// projectId: projectId,
|
||||
// versionId: selectedVersion?.versionId || ""
|
||||
// } as any
|
||||
// );
|
||||
//
|
||||
// if (response.status === 200) {
|
||||
// return true;
|
||||
// } else {
|
||||
// //
|
||||
// return false;
|
||||
// }
|
||||
// } catch (error) {
|
||||
// echo.error("Failed to send input");
|
||||
//
|
||||
// return false;
|
||||
// }
|
||||
};
|
||||
|
||||
const handleSelect = async (
|
||||
@@ -133,7 +153,7 @@ const Widget4InputCard3D = (props: Props) => {
|
||||
newSelections[inputKey] = selectedData;
|
||||
}
|
||||
// setMeasurements(newSelections); // Update Zustand store
|
||||
// console.log(newSelections);
|
||||
//
|
||||
if (await sendInputes(newSelections, duration, widgetName)) {
|
||||
setSelections(newSelections);
|
||||
}
|
||||
@@ -150,7 +170,7 @@ const Widget4InputCard3D = (props: Props) => {
|
||||
};
|
||||
|
||||
const handleNameChange = async (name: any) => {
|
||||
console.log("name change requested", name);
|
||||
|
||||
|
||||
if (await sendInputes(selections, duration, name)) {
|
||||
setWidgetName(name);
|
||||
|
||||
48
app/src/modules/builder/Decal/decalInstance.tsx
Normal file
48
app/src/modules/builder/Decal/decalInstance.tsx
Normal file
@@ -0,0 +1,48 @@
|
||||
import * as THREE from 'three';
|
||||
import { Decal } from '@react-three/drei'
|
||||
import { useLoader } from '@react-three/fiber';
|
||||
import { useToggleView } from '../../../store/builder/store';
|
||||
import { useBuilderStore } from '../../../store/builder/useBuilderStore';
|
||||
|
||||
import defaultMaterial from '../../../assets/textures/floor/wall-tex.png';
|
||||
import useModuleStore from '../../../store/useModuleStore';
|
||||
|
||||
function DecalInstance({ visible = true, decal }: { visible?: boolean, decal: Decal }) {
|
||||
const { setSelectedWall, selectedDecal, setSelectedDecal } = useBuilderStore();
|
||||
const { togglView } = useToggleView();
|
||||
const { activeModule } = useModuleStore();
|
||||
const material = useLoader(THREE.TextureLoader, defaultMaterial);
|
||||
|
||||
return (
|
||||
<Decal
|
||||
// debug
|
||||
visible={visible}
|
||||
position={decal.decalPosition}
|
||||
rotation={[0, 0, decal.decalRotation]}
|
||||
scale={[decal.decalScale, decal.decalScale, 0.01]}
|
||||
userData={decal}
|
||||
onClick={(e) => {
|
||||
if (visible && !togglView && activeModule === 'builder') {
|
||||
if (e.object.userData.decalUuid) {
|
||||
setSelectedDecal(e.object);
|
||||
setSelectedWall(null);
|
||||
}
|
||||
}
|
||||
}}
|
||||
onPointerMissed={() => {
|
||||
if (selectedDecal && selectedDecal.userData.decalUuid === decal.decalUuid) {
|
||||
setSelectedDecal(null);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<meshBasicMaterial
|
||||
map={material}
|
||||
side={THREE.DoubleSide}
|
||||
polygonOffset
|
||||
polygonOffsetFactor={-1}
|
||||
/>
|
||||
</Decal>
|
||||
)
|
||||
}
|
||||
|
||||
export default DecalInstance
|
||||
@@ -79,6 +79,7 @@ const DxfFile = ({
|
||||
userId
|
||||
}
|
||||
|
||||
console.log('input: ', input);
|
||||
socket.emit('v1:Line:create', input);
|
||||
|
||||
})
|
||||
|
||||
@@ -158,6 +158,7 @@ async function drawOnlyFloor(
|
||||
userId,
|
||||
};
|
||||
|
||||
console.log('input: ', input);
|
||||
socket.emit("v1:Line:create", input);
|
||||
|
||||
setNewLines([newLines[0], newLines[1], line.current]);
|
||||
@@ -248,6 +249,7 @@ async function drawOnlyFloor(
|
||||
userId,
|
||||
};
|
||||
|
||||
console.log('input: ', input);
|
||||
socket.emit("v1:Line:create", input);
|
||||
|
||||
setNewLines([line.current]);
|
||||
|
||||
@@ -14,232 +14,205 @@ import { Socket } from "socket.io-client";
|
||||
import { getUserData } from "../../../../functions/getUserData";
|
||||
|
||||
async function drawWall(
|
||||
raycaster: THREE.Raycaster,
|
||||
plane: Types.RefMesh,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
snappedPoint: Types.RefVector3,
|
||||
isSnapped: Types.RefBoolean,
|
||||
isSnappedUUID: Types.RefString,
|
||||
line: Types.RefLine,
|
||||
ispreSnapped: Types.RefBoolean,
|
||||
anglesnappedPoint: Types.RefVector3,
|
||||
isAngleSnapped: Types.RefBoolean,
|
||||
lines: Types.RefLines,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
floorPlanGroup: Types.RefGroup,
|
||||
ReferenceLineMesh: Types.RefMesh,
|
||||
LineCreated: Types.RefBoolean,
|
||||
currentLayerPoint: Types.RefMeshArray,
|
||||
dragPointControls: Types.RefDragControl,
|
||||
setNewLines: any,
|
||||
setDeletedLines: any,
|
||||
activeLayer: Types.Number,
|
||||
socket: Socket<any>,
|
||||
projectId?: string,
|
||||
versionId?: string,
|
||||
raycaster: THREE.Raycaster,
|
||||
plane: Types.RefMesh,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
snappedPoint: Types.RefVector3,
|
||||
isSnapped: Types.RefBoolean,
|
||||
isSnappedUUID: Types.RefString,
|
||||
line: Types.RefLine,
|
||||
ispreSnapped: Types.RefBoolean,
|
||||
anglesnappedPoint: Types.RefVector3,
|
||||
isAngleSnapped: Types.RefBoolean,
|
||||
lines: Types.RefLines,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
floorPlanGroup: Types.RefGroup,
|
||||
ReferenceLineMesh: Types.RefMesh,
|
||||
LineCreated: Types.RefBoolean,
|
||||
currentLayerPoint: Types.RefMeshArray,
|
||||
dragPointControls: Types.RefDragControl,
|
||||
setNewLines: any,
|
||||
setDeletedLines: any,
|
||||
activeLayer: Types.Number,
|
||||
socket: Socket<any>,
|
||||
projectId?: string,
|
||||
versionId?: string,
|
||||
): Promise<void> {
|
||||
const { userId, organization, email } = getUserData();
|
||||
////////// Creating lines Based on the positions clicked //////////
|
||||
const { userId, organization } = getUserData();
|
||||
////////// Creating lines Based on the positions clicked //////////
|
||||
|
||||
////////// Allows the user lines that represents walls and roof, floor if forms a polygon //////////
|
||||
////////// Allows the user lines that represents walls and roof, floor if forms a polygon //////////
|
||||
|
||||
if (!plane.current) return;
|
||||
let intersects = raycaster.intersectObject(plane.current, true);
|
||||
if (!plane.current) return;
|
||||
let intersects = raycaster.intersectObject(plane.current, true);
|
||||
|
||||
let intersectsLines = raycaster.intersectObjects(
|
||||
floorPlanGroupLine.current.children,
|
||||
true
|
||||
);
|
||||
let intersectsPoint = raycaster.intersectObjects(
|
||||
floorPlanGroupPoint.current.children,
|
||||
true
|
||||
);
|
||||
let intersectsLines = raycaster.intersectObjects(floorPlanGroupLine.current.children, true);
|
||||
let intersectsPoint = raycaster.intersectObjects(floorPlanGroupPoint.current.children, true);
|
||||
|
||||
const VisibleintersectsPoint = intersectsPoint.find(
|
||||
(intersect) => intersect.object.visible
|
||||
);
|
||||
const visibleIntersect = intersectsLines.find(
|
||||
(intersect) =>
|
||||
intersect.object.visible &&
|
||||
intersect.object.name !== CONSTANTS.lineConfig.referenceName &&
|
||||
intersect.object.userData.linePoints[0][3] ===
|
||||
CONSTANTS.lineConfig.wallName
|
||||
);
|
||||
const VisibleintersectsPoint = intersectsPoint.find((intersect) => intersect.object.visible);
|
||||
const visibleIntersect = intersectsLines.find(
|
||||
(intersect) =>
|
||||
intersect.object.visible &&
|
||||
intersect.object.name !== CONSTANTS.lineConfig.referenceName &&
|
||||
intersect.object.userData.linePoints[0][3] ===
|
||||
CONSTANTS.lineConfig.wallName
|
||||
);
|
||||
|
||||
if (
|
||||
(intersectsPoint.length === 0 || VisibleintersectsPoint === undefined) &&
|
||||
intersectsLines.length > 0 &&
|
||||
!isSnapped.current &&
|
||||
!ispreSnapped.current
|
||||
) {
|
||||
////////// Clicked on a preexisting Line //////////
|
||||
if ((intersectsPoint.length === 0 || VisibleintersectsPoint === undefined) && intersectsLines.length > 0 && !isSnapped.current && !ispreSnapped.current) {
|
||||
////////// Clicked on a preexisting Line //////////
|
||||
|
||||
if (visibleIntersect && intersects) {
|
||||
let IntersectsPoint = new THREE.Vector3(
|
||||
intersects[0].point.x,
|
||||
0.01,
|
||||
intersects[0].point.z
|
||||
);
|
||||
if (visibleIntersect && intersects) {
|
||||
let IntersectsPoint = new THREE.Vector3(intersects[0].point.x, 0.01, intersects[0].point.z);
|
||||
|
||||
if (isAngleSnapped.current && anglesnappedPoint.current) {
|
||||
IntersectsPoint = anglesnappedPoint.current;
|
||||
}
|
||||
if (visibleIntersect.object instanceof THREE.Mesh) {
|
||||
const ThroughPoint =
|
||||
visibleIntersect.object.geometry.parameters.path.getPoints(
|
||||
CONSTANTS.lineConfig.lineIntersectionPoints
|
||||
);
|
||||
let intersectionPoint = getClosestIntersection(
|
||||
ThroughPoint,
|
||||
IntersectsPoint
|
||||
);
|
||||
if (isAngleSnapped.current && anglesnappedPoint.current) {
|
||||
IntersectsPoint = anglesnappedPoint.current;
|
||||
}
|
||||
if (visibleIntersect.object instanceof THREE.Mesh) {
|
||||
const ThroughPoint = visibleIntersect.object.geometry.parameters.path.getPoints(CONSTANTS.lineConfig.lineIntersectionPoints);
|
||||
let intersectionPoint = getClosestIntersection(ThroughPoint, IntersectsPoint);
|
||||
|
||||
if (intersectionPoint) {
|
||||
const newLines = splitLine(
|
||||
visibleIntersect,
|
||||
intersectionPoint,
|
||||
currentLayerPoint,
|
||||
floorPlanGroupPoint,
|
||||
dragPointControls,
|
||||
isSnappedUUID,
|
||||
lines,
|
||||
setDeletedLines,
|
||||
floorPlanGroupLine,
|
||||
socket,
|
||||
CONSTANTS.pointConfig.wallOuterColor,
|
||||
CONSTANTS.lineConfig.wallColor,
|
||||
CONSTANTS.lineConfig.wallName,
|
||||
projectId,
|
||||
versionId
|
||||
);
|
||||
setNewLines([newLines[0], newLines[1]]);
|
||||
if (intersectionPoint) {
|
||||
const newLines = splitLine(
|
||||
visibleIntersect,
|
||||
intersectionPoint,
|
||||
currentLayerPoint,
|
||||
floorPlanGroupPoint,
|
||||
dragPointControls,
|
||||
isSnappedUUID,
|
||||
lines,
|
||||
setDeletedLines,
|
||||
floorPlanGroupLine,
|
||||
socket,
|
||||
CONSTANTS.pointConfig.wallOuterColor,
|
||||
CONSTANTS.lineConfig.wallColor,
|
||||
CONSTANTS.lineConfig.wallName,
|
||||
projectId,
|
||||
versionId
|
||||
);
|
||||
setNewLines([newLines[0], newLines[1]]);
|
||||
|
||||
(line.current as Types.Line).push([
|
||||
new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z),
|
||||
isSnappedUUID.current!,
|
||||
activeLayer,
|
||||
CONSTANTS.lineConfig.wallName,
|
||||
]);
|
||||
(line.current as Types.Line).push([
|
||||
new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z),
|
||||
isSnappedUUID.current!,
|
||||
activeLayer,
|
||||
CONSTANTS.lineConfig.wallName,
|
||||
]);
|
||||
|
||||
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
|
||||
const data = arrayLineToObject(line.current as Types.Line);
|
||||
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
|
||||
const data = arrayLineToObject(line.current as Types.Line);
|
||||
|
||||
//REST
|
||||
//REST
|
||||
|
||||
// setLine(organization, data.layer!, data.line!, data.type!);
|
||||
// setLine(organization, data.layer!, data.line!, data.type!);
|
||||
|
||||
//SOCKET
|
||||
//SOCKET
|
||||
|
||||
const input = {
|
||||
organization,
|
||||
layer: data.layer,
|
||||
line: data.line,
|
||||
type: data.type,
|
||||
socketId: socket.id,
|
||||
versionId,
|
||||
projectId,
|
||||
userId,
|
||||
};
|
||||
const input = {
|
||||
organization,
|
||||
layer: data.layer,
|
||||
line: data.line,
|
||||
type: data.type,
|
||||
socketId: socket.id,
|
||||
versionId,
|
||||
projectId,
|
||||
userId,
|
||||
};
|
||||
|
||||
socket.emit("v1:Line:create", input);
|
||||
socket.emit("v1:Line:create", input);
|
||||
|
||||
setNewLines([newLines[0], newLines[1], line.current]);
|
||||
lines.current.push(line.current as Types.Line);
|
||||
addLineToScene(
|
||||
line.current[0][0],
|
||||
line.current[1][0],
|
||||
CONSTANTS.lineConfig.wallColor,
|
||||
line.current,
|
||||
floorPlanGroupLine
|
||||
);
|
||||
let lastPoint = line.current[line.current.length - 1];
|
||||
line.current = [lastPoint];
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
setNewLines([newLines[0], newLines[1], line.current]);
|
||||
lines.current.push(line.current as Types.Line);
|
||||
addLineToScene(
|
||||
line.current[0][0],
|
||||
line.current[1][0],
|
||||
CONSTANTS.lineConfig.wallColor,
|
||||
line.current,
|
||||
floorPlanGroupLine
|
||||
);
|
||||
let lastPoint = line.current[line.current.length - 1];
|
||||
line.current = [lastPoint];
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (intersects && intersects.length > 0) {
|
||||
////////// Clicked on a emply place or a point //////////
|
||||
if (intersects && intersects.length > 0) {
|
||||
////////// Clicked on a emply place or a point //////////
|
||||
|
||||
let intersectionPoint = intersects[0].point;
|
||||
let intersectionPoint = intersects[0].point;
|
||||
|
||||
if (
|
||||
isAngleSnapped.current &&
|
||||
line.current.length > 0 &&
|
||||
anglesnappedPoint.current
|
||||
) {
|
||||
intersectionPoint = anglesnappedPoint.current;
|
||||
}
|
||||
if (isSnapped.current && line.current.length > 0 && snappedPoint.current) {
|
||||
intersectionPoint = snappedPoint.current;
|
||||
}
|
||||
if (ispreSnapped.current && snappedPoint.current) {
|
||||
intersectionPoint = snappedPoint.current;
|
||||
}
|
||||
if (isAngleSnapped.current && line.current.length > 0 && anglesnappedPoint.current) {
|
||||
intersectionPoint = anglesnappedPoint.current;
|
||||
}
|
||||
if (isSnapped.current && line.current.length > 0 && snappedPoint.current) {
|
||||
intersectionPoint = snappedPoint.current;
|
||||
}
|
||||
if (ispreSnapped.current && snappedPoint.current) {
|
||||
intersectionPoint = snappedPoint.current;
|
||||
}
|
||||
|
||||
if (!isSnapped.current && !ispreSnapped.current) {
|
||||
addPointToScene(
|
||||
intersectionPoint,
|
||||
CONSTANTS.pointConfig.wallOuterColor,
|
||||
currentLayerPoint,
|
||||
floorPlanGroupPoint,
|
||||
dragPointControls,
|
||||
isSnappedUUID,
|
||||
CONSTANTS.lineConfig.wallName
|
||||
);
|
||||
} else {
|
||||
ispreSnapped.current = false;
|
||||
isSnapped.current = false;
|
||||
}
|
||||
if (!isSnapped.current && !ispreSnapped.current) {
|
||||
addPointToScene(
|
||||
intersectionPoint,
|
||||
CONSTANTS.pointConfig.wallOuterColor,
|
||||
currentLayerPoint,
|
||||
floorPlanGroupPoint,
|
||||
dragPointControls,
|
||||
isSnappedUUID,
|
||||
CONSTANTS.lineConfig.wallName
|
||||
);
|
||||
} else {
|
||||
ispreSnapped.current = false;
|
||||
isSnapped.current = false;
|
||||
}
|
||||
|
||||
(line.current as Types.Line).push([
|
||||
new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z),
|
||||
isSnappedUUID.current!,
|
||||
activeLayer,
|
||||
CONSTANTS.lineConfig.wallName,
|
||||
]);
|
||||
(line.current as Types.Line).push([
|
||||
new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z),
|
||||
isSnappedUUID.current!,
|
||||
activeLayer,
|
||||
CONSTANTS.lineConfig.wallName,
|
||||
]);
|
||||
|
||||
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
|
||||
const data = arrayLineToObject(line.current as Types.Line);
|
||||
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
|
||||
const data = arrayLineToObject(line.current as Types.Line);
|
||||
|
||||
//REST
|
||||
//REST
|
||||
|
||||
// setLine(organization, data.layer!, data.line!, data.type!);
|
||||
// setLine(organization, data.layer!, data.line!, data.type!);
|
||||
|
||||
//SOCKET
|
||||
//SOCKET
|
||||
|
||||
const input = {
|
||||
organization,
|
||||
layer: data.layer,
|
||||
line: data.line,
|
||||
type: data.type,
|
||||
socketId: socket.id,
|
||||
versionId,
|
||||
projectId,
|
||||
userId,
|
||||
};
|
||||
const input = {
|
||||
organization,
|
||||
layer: data.layer,
|
||||
line: data.line,
|
||||
type: data.type,
|
||||
socketId: socket.id,
|
||||
versionId,
|
||||
projectId,
|
||||
userId,
|
||||
};
|
||||
|
||||
socket.emit("v1:Line:create", input);
|
||||
socket.emit("v1:Line:create", input);
|
||||
|
||||
setNewLines([line.current]);
|
||||
lines.current.push(line.current as Types.Line);
|
||||
addLineToScene(
|
||||
line.current[0][0],
|
||||
line.current[1][0],
|
||||
CONSTANTS.lineConfig.wallColor,
|
||||
line.current,
|
||||
floorPlanGroupLine
|
||||
);
|
||||
let lastPoint = line.current[line.current.length - 1];
|
||||
line.current = [lastPoint];
|
||||
}
|
||||
if (isSnapped.current) {
|
||||
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
|
||||
}
|
||||
}
|
||||
setNewLines([line.current]);
|
||||
lines.current.push(line.current as Types.Line);
|
||||
addLineToScene(
|
||||
line.current[0][0],
|
||||
line.current[1][0],
|
||||
CONSTANTS.lineConfig.wallColor,
|
||||
line.current,
|
||||
floorPlanGroupLine
|
||||
);
|
||||
let lastPoint = line.current[line.current.length - 1];
|
||||
line.current = [lastPoint];
|
||||
}
|
||||
if (isSnapped.current) {
|
||||
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default drawWall;
|
||||
|
||||
@@ -107,6 +107,7 @@ function splitLine(
|
||||
userId,
|
||||
};
|
||||
|
||||
console.log('input1: ', input1);
|
||||
socket.emit("v1:Line:create", input1);
|
||||
|
||||
//REST
|
||||
@@ -126,6 +127,7 @@ function splitLine(
|
||||
userId,
|
||||
};
|
||||
|
||||
console.log('input2: ', input2);
|
||||
socket.emit("v1:Line:create", input2);
|
||||
|
||||
lines.current.push(newLine1, newLine2);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import * as THREE from 'three';
|
||||
import { useThree } from '@react-three/fiber';
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import * as Constants from '../../../types/world/worldConstants';
|
||||
import { DragControls, Tube } from '@react-three/drei';
|
||||
import { useToolMode } from '../../../store/builder/store';
|
||||
import { useBuilderStore } from '../../../store/builder/useBuilderStore';
|
||||
import { useWallStore } from '../../../store/builder/useWallStore';
|
||||
import { useThree } from '@react-three/fiber';
|
||||
import { useSceneContext } from '../../scene/sceneContext';
|
||||
import * as Constants from '../../../types/world/worldConstants';
|
||||
|
||||
interface LineProps {
|
||||
points: [Point, Point];
|
||||
@@ -17,7 +17,8 @@ function Line({ points }: Readonly<LineProps>) {
|
||||
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
||||
const [isDeletable, setIsDeletable] = useState(false);
|
||||
const { toolMode } = useToolMode();
|
||||
const { removeWallByPoints, setPosition } = useWallStore();
|
||||
const { wallStore } = useSceneContext();
|
||||
const { removeWallByPoints, setPosition } = wallStore();
|
||||
const [dragOffset, setDragOffset] = useState<THREE.Vector3 | null>(null);
|
||||
const { hoveredLine, setHoveredLine, hoveredPoint } = useBuilderStore();
|
||||
|
||||
@@ -79,6 +80,7 @@ function Line({ points }: Readonly<LineProps>) {
|
||||
if (toolMode === '2D-Delete') {
|
||||
if (points[0].pointType === 'Wall' && points[1].pointType === 'Wall') {
|
||||
removeWallByPoints(points);
|
||||
setHoveredLine(null);
|
||||
}
|
||||
gl.domElement.style.cursor = 'default';
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import * as THREE from 'three';
|
||||
import { useCallback } from 'react';
|
||||
import { useWallStore } from '../../../../store/builder/useWallStore';
|
||||
import { useSceneContext } from '../../../scene/sceneContext';
|
||||
|
||||
const POINT_SNAP_THRESHOLD = 0.5; // Distance threshold for snapping in meters
|
||||
@@ -12,9 +11,9 @@ const ANGLE_SNAP_DISTANCE_THRESHOLD = 0.5; // Distance threshold for snapping i
|
||||
const CAN_ANGLE_SNAP = true; // Whether snapping is enabled or not
|
||||
|
||||
export const usePointSnapping = (currentPoint: { uuid: string, pointType: string, position: [number, number, number] } | null) => {
|
||||
const { aisleStore } = useSceneContext();
|
||||
const { aisleStore, wallStore } = useSceneContext();
|
||||
const { aisles, getConnectedPoints: getConnectedAislePoints } = aisleStore();
|
||||
const { walls, getConnectedPoints: getConnectedWallPoints } = useWallStore();
|
||||
const { walls, getConnectedPoints: getConnectedWallPoints } = wallStore();
|
||||
|
||||
// Wall Snapping
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import { DragControls } from '@react-three/drei';
|
||||
import { useThree } from '@react-three/fiber';
|
||||
import { useBuilderStore } from '../../../store/builder/useBuilderStore';
|
||||
import { usePointSnapping } from './helpers/usePointSnapping';
|
||||
import { useWallStore } from '../../../store/builder/useWallStore';
|
||||
import { deleteAisleApi } from '../../../services/factoryBuilder/aisle/deleteAisleApi';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { createAisleApi } from '../../../services/factoryBuilder/aisle/createAisleApi';
|
||||
@@ -20,9 +19,9 @@ function Point({ point }: { readonly point: Point }) {
|
||||
const [isHovered, setIsHovered] = useState(false);
|
||||
const [dragOffset, setDragOffset] = useState<THREE.Vector3 | null>(null);
|
||||
const { toolMode } = useToolMode();
|
||||
const { aisleStore } = useSceneContext();
|
||||
const { aisleStore, wallStore } = useSceneContext();
|
||||
const { setPosition: setAislePosition, removePoint: removeAislePoint, getAislesByPointId } = aisleStore();
|
||||
const { setPosition: setWallPosition, removePoint: removeWallPoint } = useWallStore();
|
||||
const { setPosition: setWallPosition, removePoint: removeWallPoint } = wallStore();
|
||||
const { snapAislePoint, snapAisleAngle, snapWallPoint, snapWallAngle } = usePointSnapping({ uuid: point.pointUuid, pointType: point.pointType, position: point.position });
|
||||
const { hoveredPoint, setHoveredPoint } = useBuilderStore();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
@@ -31,6 +30,10 @@ function Point({ point }: { readonly point: Point }) {
|
||||
const boxScale: [number, number, number] = Constants.pointConfig.boxScale;
|
||||
const colors = getColor(point);
|
||||
|
||||
useEffect(() => {
|
||||
gl.domElement.style.cursor = 'default';
|
||||
}, [toolMode])
|
||||
|
||||
function getColor(point: Point) {
|
||||
if (point.pointType === 'Aisle') {
|
||||
return {
|
||||
|
||||
@@ -1,18 +1,26 @@
|
||||
import * as THREE from 'three';
|
||||
import { Base } from '@react-three/csg';
|
||||
import { useMemo, useRef, useState } from 'react';
|
||||
import * as Constants from '../../../../../types/world/worldConstants';
|
||||
import { Decal, MeshDiscardMaterial } from '@react-three/drei';
|
||||
import { useFrame, useThree } from '@react-three/fiber';
|
||||
|
||||
import defaultMaterial from '../../../../../assets/textures/floor/wall-tex.png';
|
||||
import material1 from '../../../../../assets/textures/floor/factory wall texture.jpg';
|
||||
import { useWallStore } from '../../../../../store/builder/useWallStore';
|
||||
|
||||
import useModuleStore from '../../../../../store/useModuleStore';
|
||||
import { useSceneContext } from '../../../../scene/sceneContext';
|
||||
import { useWallClassification } from './helpers/useWallClassification';
|
||||
import { useFrame, useThree } from '@react-three/fiber';
|
||||
import { useWallVisibility } from '../../../../../store/builder/store';
|
||||
import { Decal } from '@react-three/drei';
|
||||
import { Base } from '@react-three/csg';
|
||||
import { useToggleView, useWallVisibility } from '../../../../../store/builder/store';
|
||||
import { useBuilderStore } from '../../../../../store/builder/useBuilderStore';
|
||||
import * as Constants from '../../../../../types/world/worldConstants';
|
||||
import DecalInstance from '../../../Decal/decalInstance';
|
||||
|
||||
function Wall({ wall }: { readonly wall: Wall }) {
|
||||
const { walls } = useWallStore();
|
||||
const { wallStore } = useSceneContext();
|
||||
const { walls, addDecal } = wallStore();
|
||||
const { selectedWall, setSelectedWall, setSelectedDecal } = useBuilderStore();
|
||||
const { togglView } = useToggleView();
|
||||
const { activeModule } = useModuleStore();
|
||||
const { camera } = useThree();
|
||||
const { wallVisibility } = useWallVisibility();
|
||||
const { getWallType, isWallFlipped } = useWallClassification(walls);
|
||||
@@ -67,7 +75,7 @@ function Wall({ wall }: { readonly wall: Wall }) {
|
||||
new THREE.MeshStandardMaterial({
|
||||
color: Constants.wallConfig.defaultColor,
|
||||
side: THREE.DoubleSide,
|
||||
map: wall.outsideMaterial === 'Default Material`' ? defaultWallTexture : material1WallTexture,
|
||||
map: wall.outsideMaterial === 'Default Material' ? defaultWallTexture : material1WallTexture,
|
||||
}),
|
||||
];
|
||||
}, [defaultWallTexture, material1WallTexture, wall]);
|
||||
@@ -100,29 +108,52 @@ function Wall({ wall }: { readonly wall: Wall }) {
|
||||
geometry={geometry}
|
||||
position={[centerX, centerY, centerZ]}
|
||||
rotation={[0, -angle, 0]}
|
||||
userData={wall}
|
||||
>
|
||||
{materials.map((material, index) => (
|
||||
<primitive key={index} visible={visible} object={material} attach={`material-${index}`} />
|
||||
))}
|
||||
|
||||
{wall.decals.map((decal) => {
|
||||
return (
|
||||
<Decal
|
||||
// debug
|
||||
position={[decal.decalPosition[0], decal.decalPosition[1], wall.wallThickness / 2]}
|
||||
rotation={[0, 0, decal.decalRotation]}
|
||||
scale={[decal.decalScale, decal.decalScale, 0.001]}
|
||||
>
|
||||
<meshBasicMaterial
|
||||
map={material1WallTexture}
|
||||
side={THREE.DoubleSide}
|
||||
polygonOffset
|
||||
polygonOffsetFactor={-1}
|
||||
/>
|
||||
</Decal>
|
||||
)
|
||||
})}
|
||||
</Base>
|
||||
<mesh
|
||||
castShadow
|
||||
geometry={geometry}
|
||||
position={[centerX, centerY, centerZ]}
|
||||
rotation={[0, -angle, 0]}
|
||||
userData={wall}
|
||||
name={`WallReference_${wall.wallUuid}`}
|
||||
onClick={(e) => {
|
||||
if (visible && !togglView && activeModule === 'builder') {
|
||||
if (e.object.userData.wallUuid) {
|
||||
setSelectedWall(e.object);
|
||||
setSelectedDecal(null);
|
||||
|
||||
if (wall.decals.length > 0) return;
|
||||
const decal: Decal = {
|
||||
decalUuid: THREE.MathUtils.generateUUID(),
|
||||
decalName: 'Decal',
|
||||
decalId: 'Default Decal',
|
||||
decalPosition: [0, 0, wall.wallThickness / 2 + 0.001],
|
||||
decalRotation: 0,
|
||||
decalScale: 1,
|
||||
decalType: { type: 'Wall', wallUuid: wall.wallUuid }
|
||||
}
|
||||
addDecal(wall.wallUuid, decal);
|
||||
|
||||
}
|
||||
}
|
||||
}}
|
||||
onPointerMissed={() => {
|
||||
if (selectedWall && selectedWall.userData.wallUuid === wall.wallUuid) {
|
||||
setSelectedWall(null);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<MeshDiscardMaterial />
|
||||
|
||||
{wall.decals.map((decal) => (
|
||||
<DecalInstance visible={visible} key={decal.decalUuid} decal={decal} />
|
||||
))}
|
||||
</mesh>
|
||||
</mesh>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,9 +2,10 @@ import React, { useEffect, useMemo } from 'react';
|
||||
import { DoubleSide, RepeatWrapping, Shape, SRGBColorSpace, TextureLoader, Vector2, Vector3 } from 'three';
|
||||
import { Geometry } from '@react-three/csg';
|
||||
import { Html, Extrude } from '@react-three/drei';
|
||||
import { useWallStore } from '../../../../store/builder/useWallStore'
|
||||
import { useWallClassification } from './instance/helpers/useWallClassification';
|
||||
import { useLoader } from '@react-three/fiber';
|
||||
import { useSceneContext } from '../../../scene/sceneContext';
|
||||
import { useToggleView } from '../../../../store/builder/store';
|
||||
import { useWallClassification } from './instance/helpers/useWallClassification';
|
||||
import Line from '../../line/line';
|
||||
import Point from '../../point/point';
|
||||
import WallInstance from './instance/wallInstance';
|
||||
@@ -12,10 +13,10 @@ import * as Constants from '../../../../types/world/worldConstants';
|
||||
|
||||
import texturePath from "../../../../assets/textures/floor/white.png";
|
||||
import texturePathDark from "../../../../assets/textures/floor/black.png";
|
||||
import { useLoader } from '@react-three/fiber';
|
||||
|
||||
function WallInstances() {
|
||||
const { walls } = useWallStore();
|
||||
const { wallStore } = useSceneContext();
|
||||
const { walls } = wallStore();
|
||||
const { rooms } = useWallClassification(walls)
|
||||
const { toggleView } = useToggleView();
|
||||
|
||||
@@ -41,7 +42,7 @@ function WallInstances() {
|
||||
|
||||
return (
|
||||
<>
|
||||
{!toggleView && (
|
||||
{!toggleView && walls.length > 1 && (
|
||||
<>
|
||||
<mesh name='Walls-Group'>
|
||||
<Geometry useGroups>
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { useThree } from '@react-three/fiber';
|
||||
import { useActiveLayer, useSocketStore, useToggleView, useToolMode } from '../../../../store/builder/store';
|
||||
import * as Constants from '../../../../types/world/worldConstants';
|
||||
import { useWallStore } from '../../../../store/builder/useWallStore';
|
||||
import { useSceneContext } from '../../../scene/sceneContext';
|
||||
import { useBuilderStore } from '../../../../store/builder/useBuilderStore';
|
||||
import ReferencePoint from '../../point/reference/referencePoint';
|
||||
import ReferenceWall from './referenceWall';
|
||||
@@ -16,7 +16,8 @@ function WallCreator() {
|
||||
const { toolMode } = useToolMode();
|
||||
const { activeLayer } = useActiveLayer();
|
||||
const { socket } = useSocketStore();
|
||||
const { addWall, getWallPointById, removeWall, getWallByPoints } = useWallStore();
|
||||
const { wallStore } = useSceneContext();
|
||||
const { addWall, getWallPointById, removeWall, getWallByPoints } = wallStore();
|
||||
const drag = useRef(false);
|
||||
const isLeftMouseDown = useRef(false);
|
||||
const { wallThickness, wallHeight, insideMaterial, outsideMaterial, snappedPosition, snappedPoint } = useBuilderStore();
|
||||
|
||||
@@ -1,7 +1,22 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useToggleView } from '../../../store/builder/store'
|
||||
import { useBuilderStore } from '../../../store/builder/useBuilderStore';
|
||||
import WallCreator from './wallCreator/wallCreator'
|
||||
import WallInstances from './Instances/wallInstances'
|
||||
import useModuleStore from '../../../store/useModuleStore';
|
||||
|
||||
function WallGroup() {
|
||||
const { togglView } = useToggleView();
|
||||
const { setSelectedWall, setSelectedDecal } = useBuilderStore();
|
||||
const { activeModule } = useModuleStore();
|
||||
|
||||
useEffect(() => {
|
||||
if (togglView || activeModule !== 'builder') {
|
||||
setSelectedWall(null);
|
||||
setSelectedDecal(null);
|
||||
}
|
||||
}, [togglView, activeModule])
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ export default function PostProcessing() {
|
||||
const { selectedWallItem } = useSelectedWallItem();
|
||||
const { selectedFloorItem } = useSelectedFloorItem();
|
||||
const { selectedEventSphere } = useSelectedEventSphere();
|
||||
const { selectedAisle } = useBuilderStore();
|
||||
const { selectedAisle, selectedWall, selectedDecal } = useBuilderStore();
|
||||
|
||||
function flattenChildren(children: any[]) {
|
||||
const allChildren: any[] = [];
|
||||
@@ -40,6 +40,10 @@ export default function PostProcessing() {
|
||||
// console.log('selectedAisle: ', selectedAisle);
|
||||
}, [selectedAisle])
|
||||
|
||||
useEffect(() => {
|
||||
// console.log('selectedWall: ', selectedWall);
|
||||
}, [selectedWall])
|
||||
|
||||
return (
|
||||
<EffectComposer autoClear={false}>
|
||||
<N8AO
|
||||
@@ -66,6 +70,36 @@ export default function PostProcessing() {
|
||||
xRay={false}
|
||||
/>
|
||||
)}
|
||||
{selectedWall && (
|
||||
<Outline
|
||||
selection={selectedWall}
|
||||
selectionLayer={10}
|
||||
width={2000}
|
||||
blendFunction={BlendFunction.ALPHA}
|
||||
edgeStrength={5}
|
||||
resolutionScale={2}
|
||||
pulseSpeed={0}
|
||||
visibleEdgeColor={CONSTANTS.outlineConfig.assetSelectColor}
|
||||
hiddenEdgeColor={CONSTANTS.outlineConfig.assetSelectColor}
|
||||
blur={true}
|
||||
xRay={true}
|
||||
/>
|
||||
)}
|
||||
{selectedDecal && (
|
||||
<Outline
|
||||
selection={selectedDecal}
|
||||
selectionLayer={10}
|
||||
width={2000}
|
||||
blendFunction={BlendFunction.ALPHA}
|
||||
edgeStrength={5}
|
||||
resolutionScale={2}
|
||||
pulseSpeed={0}
|
||||
visibleEdgeColor={CONSTANTS.outlineConfig.assetSelectColor}
|
||||
hiddenEdgeColor={CONSTANTS.outlineConfig.assetSelectColor}
|
||||
blur={true}
|
||||
xRay={true}
|
||||
/>
|
||||
)}
|
||||
{deletableFloorItem && (
|
||||
<Outline
|
||||
selection={flattenChildren(deletableFloorItem.children)}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import { createContext, useContext, useMemo } from 'react';
|
||||
|
||||
import { createAssetStore, AssetStoreType } from '../../store/builder/useAssetStore';
|
||||
import { createWallAssetStore, WallAssetStoreType } from '../../store/builder/useWallAssetStore';
|
||||
import { createWallStore, WallStoreType } from '../../store/builder/useWallStore';
|
||||
import { createAisleStore, AisleStoreType } from '../../store/builder/useAisleStore';
|
||||
import { createZoneStore, ZoneStoreType } from '../../store/builder/useZoneStore';
|
||||
import { createFloorStore, FloorStoreType } from '../../store/builder/useFloorStore';
|
||||
|
||||
import { createEventStore, EventStoreType } from '../../store/simulation/useEventsStore';
|
||||
import { createProductStore, ProductStoreType } from '../../store/simulation/useProductStore';
|
||||
@@ -16,7 +20,11 @@ import { createStorageUnitStore, StorageUnitStoreType } from '../../store/simula
|
||||
type SceneContextValue = {
|
||||
|
||||
assetStore: AssetStoreType,
|
||||
wallAssetStore: WallAssetStoreType,
|
||||
wallStore: WallStoreType,
|
||||
aisleStore: AisleStoreType,
|
||||
zoneStore: ZoneStoreType,
|
||||
floorStore: FloorStoreType,
|
||||
|
||||
eventStore: EventStoreType,
|
||||
productStore: ProductStoreType,
|
||||
@@ -44,7 +52,11 @@ export function SceneProvider({
|
||||
}) {
|
||||
|
||||
const assetStore = useMemo(() => createAssetStore(), []);
|
||||
const wallAssetStore = useMemo(() => createWallAssetStore(), []);
|
||||
const wallStore = useMemo(() => createWallStore(), []);
|
||||
const aisleStore = useMemo(() => createAisleStore(), []);
|
||||
const zoneStore = useMemo(() => createZoneStore(), []);
|
||||
const floorStore = useMemo(() => createFloorStore(), []);
|
||||
|
||||
const eventStore = useMemo(() => createEventStore(), []);
|
||||
const productStore = useMemo(() => createProductStore(), []);
|
||||
@@ -58,7 +70,11 @@ export function SceneProvider({
|
||||
|
||||
const clearStores = useMemo(() => () => {
|
||||
assetStore.getState().clearAssets();
|
||||
wallAssetStore.getState().clearWallAssets();
|
||||
wallStore.getState().clearWalls();
|
||||
aisleStore.getState().clearAisles();
|
||||
zoneStore.getState().clearZones();
|
||||
floorStore.getState().clearFloors();
|
||||
eventStore.getState().clearEvents();
|
||||
productStore.getState().clearProducts();
|
||||
materialStore.getState().clearMaterials();
|
||||
@@ -67,12 +83,16 @@ export function SceneProvider({
|
||||
conveyorStore.getState().clearConveyors();
|
||||
vehicleStore.getState().clearVehicles();
|
||||
storageUnitStore.getState().clearStorageUnits();
|
||||
}, [assetStore, aisleStore, eventStore, productStore, materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore]);
|
||||
}, [assetStore, wallAssetStore, wallStore, aisleStore, zoneStore, floorStore, eventStore, productStore, materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore]);
|
||||
|
||||
const contextValue = useMemo(() => (
|
||||
{
|
||||
assetStore,
|
||||
wallAssetStore,
|
||||
wallStore,
|
||||
aisleStore,
|
||||
zoneStore,
|
||||
floorStore,
|
||||
eventStore,
|
||||
productStore,
|
||||
materialStore,
|
||||
@@ -84,7 +104,7 @@ export function SceneProvider({
|
||||
clearStores,
|
||||
layout
|
||||
}
|
||||
), [assetStore, aisleStore, eventStore, productStore, materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, clearStores, layout]);
|
||||
), [assetStore, wallAssetStore, wallStore, aisleStore, zoneStore, floorStore, eventStore, productStore, materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, clearStores, layout]);
|
||||
|
||||
return (
|
||||
<SceneContext.Provider value={contextValue}>
|
||||
|
||||
@@ -106,17 +106,17 @@ export default function Dropped3dWidgets() {
|
||||
const hasEntered = { current: false };
|
||||
|
||||
const handleDragEnter = (event: DragEvent) => {
|
||||
console.log("dragEnter");
|
||||
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
if (hasEntered.current || !widgetSelect.startsWith("ui")) return;
|
||||
console.log('hasEntered.current : ', hasEntered.current );
|
||||
|
||||
hasEntered.current = true;
|
||||
|
||||
const group1 = scene.getObjectByName("itemsGroup");
|
||||
console.log('group1: ', group1);
|
||||
if (!group1) return;
|
||||
// const group1 = scene.getObjectByName("itemsGroup");
|
||||
//
|
||||
// if (!group1) return;
|
||||
|
||||
const rect = canvasElement.getBoundingClientRect();
|
||||
mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
|
||||
@@ -139,7 +139,7 @@ export default function Dropped3dWidgets() {
|
||||
intersect.object.type !== "GridHelper"
|
||||
);
|
||||
|
||||
console.log('intersects: ', intersects);
|
||||
|
||||
if (intersects.length > 0) {
|
||||
const { x, y, z } = intersects[0].point;
|
||||
const newWidget: WidgetData = {
|
||||
@@ -238,10 +238,11 @@ export default function Dropped3dWidgets() {
|
||||
organization,
|
||||
widget: newWidget,
|
||||
zoneUuid: selectedZone.zoneUuid,
|
||||
version: selectedVersion?.versionId || '',
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
projectId,
|
||||
userId
|
||||
};
|
||||
|
||||
|
||||
if (visualizationSocket) {
|
||||
visualizationSocket.emit("v1:viz-3D-widget:add", add3dWidget);
|
||||
@@ -276,7 +277,7 @@ export default function Dropped3dWidgets() {
|
||||
const widgetToDuplicate = activeZoneWidgets.find(
|
||||
(w: WidgetData) => w.id === rightClickSelected
|
||||
);
|
||||
console.log("3d widget to duplecate", widgetToDuplicate);
|
||||
|
||||
|
||||
if (!widgetToDuplicate) return;
|
||||
const newWidget: any = {
|
||||
@@ -301,6 +302,7 @@ export default function Dropped3dWidgets() {
|
||||
projectId,
|
||||
userId
|
||||
};
|
||||
|
||||
if (visualizationSocket) {
|
||||
visualizationSocket.emit("v1:viz-3D-widget:add", adding3dWidget);
|
||||
}
|
||||
@@ -470,20 +472,20 @@ export default function Dropped3dWidgets() {
|
||||
}
|
||||
|
||||
// if (rightSelect === "Vertical Move") {
|
||||
// // console.log('rightSelect: ', rightSelect);
|
||||
// //
|
||||
|
||||
// // console.log('floorPlanesVertical: ', floorPlanesVertical);
|
||||
// // console.log('planeIntersect.current: ', planeIntersect.current);
|
||||
// //
|
||||
// //
|
||||
// // const intersect = raycaster.ray.intersectPlane(
|
||||
// // floorPlanesVertical,
|
||||
// // planeIntersect.current
|
||||
// // );
|
||||
// // console.log('intersect: ', intersect);
|
||||
// //
|
||||
|
||||
// let intersect = event.clientY
|
||||
|
||||
// if (intersect && typeof intersectcontextmenu === "number") {
|
||||
// console.log('intersect: ', intersect);
|
||||
//
|
||||
// const diff = intersect - intersectcontextmenu;
|
||||
// const unclampedY = selectedWidget.position[1] + diff;
|
||||
// const newY = Math.max(0, unclampedY); // Prevent going below floor (y=0)
|
||||
@@ -495,7 +497,7 @@ export default function Dropped3dWidgets() {
|
||||
// newY,
|
||||
// selectedWidget.position[2],
|
||||
// ];
|
||||
// console.log('newPosition: ', newPosition);
|
||||
//
|
||||
|
||||
|
||||
// updateWidgetPosition(selectedzoneUuid, rightClickSelected, newPosition);
|
||||
|
||||
@@ -18,6 +18,8 @@ import { useWidgetStore } from "../../../../../store/useWidgetStore";
|
||||
import useChartStore from "../../../../../store/visualization/useChartStore";
|
||||
import { getUserData } from "../../../../../functions/getUserData";
|
||||
import { get3dWidgetInput } from "../../../../../services/visulization/zone/get3dWidgetInput";
|
||||
import { useVersionContext } from "../../../../builder/version/versionContext";
|
||||
import { useParams } from "react-router-dom";
|
||||
|
||||
// Register ChartJS components
|
||||
ChartJS.register(
|
||||
@@ -70,6 +72,9 @@ const ProductionCapacity: React.FC<ProductionCapacityProps> = ({
|
||||
});
|
||||
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||
const { userName, userId, organization, email } = getUserData();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { projectId } = useParams()
|
||||
// Chart data for a week
|
||||
const defaultChartData = {
|
||||
labels: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], // Days of the week
|
||||
@@ -171,12 +176,15 @@ const ProductionCapacity: React.FC<ProductionCapacityProps> = ({
|
||||
|
||||
const fetchSavedInputes = async () => {
|
||||
if (id !== "") {
|
||||
let response = await get3dWidgetInput(id, organization)
|
||||
console.log('response: ', response);
|
||||
let response = await get3dWidgetInput(id, organization, projectId, selectedVersion?.versionId || "")
|
||||
|
||||
if (response.message === "Widget not found") {
|
||||
return
|
||||
}
|
||||
if (response) {
|
||||
setmeasurements(response.data.Data.measurements);
|
||||
setDuration(response.data.Data.duration);
|
||||
setName(response.data.widgetName);
|
||||
setmeasurements(response.Datastructure.measurements);
|
||||
setDuration(response.Datastructure.duration);
|
||||
setName(response.widgetName);
|
||||
}
|
||||
// try {
|
||||
// const response = await axios.get(
|
||||
@@ -215,7 +223,7 @@ const ProductionCapacity: React.FC<ProductionCapacityProps> = ({
|
||||
scale={scale}
|
||||
rotation={rotation}
|
||||
// class
|
||||
wrapperClass="pointer-none"
|
||||
// wrapperClass="pointer-none"
|
||||
// other
|
||||
transform
|
||||
zIndexRange={[1, 0]}
|
||||
|
||||
@@ -19,6 +19,8 @@ import useChartStore from "../../../../../store/visualization/useChartStore";
|
||||
import { WavyIcon } from "../../../../../components/icons/3dChartIcons";
|
||||
import { getUserData } from "../../../../../functions/getUserData";
|
||||
import { get3dWidgetInput } from "../../../../../services/visulization/zone/get3dWidgetInput";
|
||||
import { useVersionContext } from "../../../../builder/version/versionContext";
|
||||
import { useParams } from "react-router-dom";
|
||||
|
||||
// Register Chart.js components
|
||||
ChartJS.register(
|
||||
@@ -79,6 +81,9 @@ const ReturnOfInvestment: React.FC<ReturnOfInvestmentProps> = ({
|
||||
datasets: [],
|
||||
});
|
||||
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { projectId } = useParams()
|
||||
const { userName, userId, organization, email } = getUserData();
|
||||
// Improved sample data for the smooth curve graph (single day)
|
||||
const graphData: ChartData<"line"> = {
|
||||
@@ -200,8 +205,11 @@ const ReturnOfInvestment: React.FC<ReturnOfInvestmentProps> = ({
|
||||
|
||||
const fetchSavedInputes = async () => {
|
||||
if (id !== "") {
|
||||
let response = await get3dWidgetInput(id, organization)
|
||||
console.log('response: ', response);
|
||||
let response = await get3dWidgetInput(id, organization, projectId, selectedVersion?.versionId || "")
|
||||
|
||||
if (response.message === "Widget not found") {
|
||||
return
|
||||
}
|
||||
if (response) {
|
||||
setmeasurements(response.data.Data.measurements);
|
||||
setDuration(response.data.Data.duration);
|
||||
@@ -216,11 +224,11 @@ const ReturnOfInvestment: React.FC<ReturnOfInvestmentProps> = ({
|
||||
// setDuration(response.data.Data.duration);
|
||||
// setName(response.data.widgetName);
|
||||
// } else {
|
||||
// // console.log("Unexpected response:", response);
|
||||
// //
|
||||
// }
|
||||
// } catch (error) {
|
||||
// echo.error("Failed to fetch saved inputs");
|
||||
// console.error("There was an error!", error);
|
||||
//
|
||||
// }
|
||||
}
|
||||
};
|
||||
|
||||
@@ -7,6 +7,8 @@ import { useWidgetStore } from "../../../../../store/useWidgetStore";
|
||||
import useChartStore from "../../../../../store/visualization/useChartStore";
|
||||
import { getUserData } from "../../../../../functions/getUserData";
|
||||
import { get3dWidgetInput } from "../../../../../services/visulization/zone/get3dWidgetInput";
|
||||
import { useVersionContext } from "../../../../builder/version/versionContext";
|
||||
import { useParams } from "react-router-dom";
|
||||
|
||||
// import image from "../../../../assets/image/temp/image.png";
|
||||
interface StateWorkingProps {
|
||||
@@ -41,6 +43,9 @@ const StateWorking: React.FC<StateWorkingProps> = ({
|
||||
const [datas, setDatas] = useState<any>({});
|
||||
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||
const { userName, userId, organization, email } = getUserData();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { projectId } = useParams()
|
||||
// const datas = [
|
||||
// { key: "Oil Tank:", value: "24/341" },
|
||||
// { key: "Oil Refin:", value: 36.023 },
|
||||
@@ -78,12 +83,15 @@ const StateWorking: React.FC<StateWorkingProps> = ({
|
||||
|
||||
const fetchSavedInputes = async () => {
|
||||
if (id !== "") {
|
||||
let response = await get3dWidgetInput(id, organization)
|
||||
console.log('response: ', response);
|
||||
let response = await get3dWidgetInput(id, organization, projectId, selectedVersion?.versionId || "")
|
||||
|
||||
if (response.message === "Widget not found") {
|
||||
return
|
||||
}
|
||||
if (response) {
|
||||
setmeasurements(response.data.Data.measurements);
|
||||
setDuration(response.data.Data.duration);
|
||||
setName(response.data.widgetName);
|
||||
setmeasurements(response.Datastructure.measurements);
|
||||
setDuration(response.Datastructure.duration);
|
||||
setName(response.widgetName);
|
||||
}
|
||||
// try {
|
||||
// const response = await axios.get(
|
||||
@@ -94,17 +102,17 @@ const StateWorking: React.FC<StateWorkingProps> = ({
|
||||
// setDuration(response.data.Data.duration);
|
||||
// setName(response.data.widgetName);
|
||||
// } else {
|
||||
// // console.log("Unexpected response:", response);
|
||||
// //
|
||||
// }
|
||||
// } catch (error) {
|
||||
// echo.error("Failed to fetch saved inputs");
|
||||
// console.error("There was an error!", error);
|
||||
//
|
||||
// }
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchSavedInputes();
|
||||
// fetchSavedInputes();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -21,6 +21,8 @@ import useChartStore from "../../../../../store/visualization/useChartStore";
|
||||
import { ThroughputIcon } from "../../../../../components/icons/3dChartIcons";
|
||||
import { getUserData } from "../../../../../functions/getUserData";
|
||||
import { get3dWidgetInput } from "../../../../../services/visulization/zone/get3dWidgetInput";
|
||||
import { useVersionContext } from "../../../../builder/version/versionContext";
|
||||
import { useParams } from "react-router-dom";
|
||||
|
||||
// Register Chart.js components
|
||||
ChartJS.register(
|
||||
@@ -83,6 +85,9 @@ const Throughput: React.FC<ThroughputProps> = ({
|
||||
});
|
||||
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||
const { userName, userId, organization, email } = getUserData();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { projectId } = useParams()
|
||||
|
||||
|
||||
|
||||
@@ -180,12 +185,15 @@ const Throughput: React.FC<ThroughputProps> = ({
|
||||
|
||||
const fetchSavedInputes = async () => {
|
||||
if (id !== "") {
|
||||
let response = await get3dWidgetInput(id, organization)
|
||||
console.log('response: ', response);
|
||||
let response = await get3dWidgetInput(id, organization, projectId, selectedVersion?.versionId || "")
|
||||
|
||||
if (response.message === "Widget not found") {
|
||||
return
|
||||
}
|
||||
if (response) {
|
||||
setmeasurements(response.data.Data.measurements);
|
||||
setDuration(response.data.Data.duration);
|
||||
setName(response.data.widgetName);
|
||||
setmeasurements(response.Datastructure.measurements);
|
||||
setDuration(response.Datastructure.duration);
|
||||
setName(response.widgetName);
|
||||
}
|
||||
// try {
|
||||
// const response = await axios.get(
|
||||
@@ -196,17 +204,17 @@ const Throughput: React.FC<ThroughputProps> = ({
|
||||
// setDuration(response.data.Data.duration);
|
||||
// setName(response.data.widgetName);
|
||||
// } else {
|
||||
// // console.log("Unexpected response:", response);
|
||||
// //
|
||||
// }
|
||||
// } catch (error) {
|
||||
// echo.error("Failed to fetch saved inputs");
|
||||
// console.error("There was an error!", error);
|
||||
//
|
||||
// }
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchSavedInputes();
|
||||
// fetchSavedInputes();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -6,8 +6,10 @@ export const adding3dWidgets = async (
|
||||
widget: {},
|
||||
projectId?: string,
|
||||
versionId?: string
|
||||
|
||||
|
||||
) => {
|
||||
|
||||
|
||||
try {
|
||||
const response = await fetch(`${url_Backend_dwinzo}/api/V1/widget3d/save`, {
|
||||
method: "POST",
|
||||
@@ -20,15 +22,16 @@ export const adding3dWidgets = async (
|
||||
body: JSON.stringify({ organization, zoneUuid, widget, projectId, versionId }),
|
||||
});
|
||||
|
||||
|
||||
const newAccessToken = response.headers.get("x-access-token");
|
||||
if (newAccessToken) {
|
||||
//console.log("New token received:", newAccessToken);
|
||||
//
|
||||
localStorage.setItem("token", newAccessToken);
|
||||
}
|
||||
|
||||
|
||||
if (!response.ok) {
|
||||
console.error("Failed to add 3dwidget in the zone");
|
||||
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
@@ -36,9 +39,9 @@ export const adding3dWidgets = async (
|
||||
} catch (error) {
|
||||
echo.error("Failed to add 3d widget");
|
||||
if (error instanceof Error) {
|
||||
console.log(error.message);
|
||||
|
||||
} else {
|
||||
console.log("An unknown error occurred");
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2,9 +2,13 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_UR
|
||||
|
||||
|
||||
export const get3dWidgetInput = async (chartId: string, organization: string, projectId?: string, versionId?: string) => {
|
||||
|
||||
|
||||
|
||||
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${url_Backend_dwinzo}/api/v2/widget3D/${chartId}/${organization}`,
|
||||
`${url_Backend_dwinzo}/api/V1/widget3dData/${chartId}/${projectId}/${versionId}`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
@@ -15,9 +19,10 @@ export const get3dWidgetInput = async (chartId: string, organization: string, pr
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const newAccessToken = response.headers.get("x-access-token");
|
||||
if (newAccessToken) {
|
||||
//console.log("New token received:", newAccessToken);
|
||||
//
|
||||
localStorage.setItem("token", newAccessToken);
|
||||
}
|
||||
|
||||
@@ -25,10 +30,10 @@ export const get3dWidgetInput = async (chartId: string, organization: string, pr
|
||||
throw new Error("Failed to fetch zoneDatas");
|
||||
}
|
||||
const result = await response.json();
|
||||
console.log('result: ', result);
|
||||
|
||||
return result;
|
||||
} catch (error: any) {
|
||||
echo.error("Failed to fetch 2d widget data");
|
||||
console.log(error.message);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@@ -3,74 +3,64 @@ import { create } from 'zustand';
|
||||
import { immer } from 'zustand/middleware/immer';
|
||||
|
||||
interface BuilderState {
|
||||
// Common properties
|
||||
|
||||
// Point & Line Interaction
|
||||
hoveredPoint: Point | null;
|
||||
snappedPoint: Point | null;
|
||||
snappedPosition: [number, number, number] | null;
|
||||
|
||||
hoveredLine: [Point, Point] | null;
|
||||
|
||||
// Wall
|
||||
|
||||
// Wall Settings
|
||||
selectedWall: Object3D | null;
|
||||
wallThickness: number;
|
||||
wallHeight: number;
|
||||
outsideMaterial: string;
|
||||
insideMaterial: string;
|
||||
|
||||
setWallThickness: (thickness: number) => void;
|
||||
setWallHeight: (height: number) => void;
|
||||
setWallMaterial: (material: string, side: 'inside' | 'outside') => void;
|
||||
|
||||
// Aisle
|
||||
// Decal Settings
|
||||
selectedDecal: Object3D | null;
|
||||
|
||||
// Aisle General
|
||||
selectedAisle: Object3D | null;
|
||||
|
||||
aisleType: AisleTypes;
|
||||
aisleWidth: number;
|
||||
aisleColor: AisleColors;
|
||||
|
||||
// Dashed aisle properties
|
||||
// Aisle Specific Styles
|
||||
dashLength: number;
|
||||
gapLength: number;
|
||||
|
||||
// Dotted aisle properties
|
||||
dotRadius: number;
|
||||
|
||||
// Arrows aisle properties
|
||||
aisleLength: number;
|
||||
|
||||
// Junction aisle properties
|
||||
isFlipped: boolean;
|
||||
|
||||
// Setters for common properties
|
||||
|
||||
// Setters - Point/Line
|
||||
setHoveredPoint: (point: Point | null) => void;
|
||||
setSnappedPoint: (point: Point | null) => void;
|
||||
setSnappedPosition: (position: [number, number, number] | null) => void;
|
||||
|
||||
setHoveredLine: (line: [Point, Point] | null) => void;
|
||||
|
||||
setSelectedAisle: (aisle: Object3D | null) => void;
|
||||
// Setters - Wall
|
||||
setSelectedWall: (wall: Object3D | null) => void;
|
||||
setWallThickness: (thickness: number) => void;
|
||||
setWallHeight: (height: number) => void;
|
||||
setWallMaterial: (material: string, side: 'inside' | 'outside') => void;
|
||||
|
||||
// Setters - Decal
|
||||
setSelectedDecal: (decal: Object3D | null) => void;
|
||||
|
||||
// Setters - Aisle General
|
||||
setSelectedAisle: (aisle: Object3D | null) => void;
|
||||
setAisleType: (type: AisleTypes) => void;
|
||||
setAisleWidth: (width: number) => void;
|
||||
setAisleColor: (color: AisleColors) => void;
|
||||
|
||||
// Setters for dashed aisle
|
||||
// Setters - Aisle Specific
|
||||
setDashLength: (length: number) => void;
|
||||
setGapLength: (length: number) => void;
|
||||
|
||||
// Setters for dotted aisle
|
||||
setDotRadius: (radius: number) => void;
|
||||
|
||||
// Setters for arrows aisle
|
||||
setAisleLength: (length: number) => void;
|
||||
|
||||
// Setters for junction aisle
|
||||
setIsFlipped: (isFlipped: boolean) => void;
|
||||
|
||||
// Batch setters
|
||||
// Batch Setters
|
||||
setDashedAisleProperties: (width: number, dashLength: number, gapLength: number) => void;
|
||||
setDottedAisleProperties: (width: number, dotRadius: number, gapLength: number) => void;
|
||||
setArrowsAisleProperties: (width: number, aisleLength: number, gapLength: number) => void;
|
||||
@@ -79,20 +69,64 @@ interface BuilderState {
|
||||
|
||||
export const useBuilderStore = create<BuilderState>()(
|
||||
immer((set) => ({
|
||||
// Default values
|
||||
|
||||
// === Defaults ===
|
||||
hoveredPoint: null,
|
||||
snappedPoint: null,
|
||||
snappedPosition: null,
|
||||
|
||||
hoveredLine: null,
|
||||
|
||||
// Wall
|
||||
|
||||
selectedWall: null,
|
||||
wallThickness: 0.5,
|
||||
wallHeight: 7,
|
||||
outsideMaterial: 'Default Material',
|
||||
insideMaterial: 'Default Material',
|
||||
insideMaterial: 'Material 1',
|
||||
|
||||
selectedDecal: null,
|
||||
|
||||
selectedAisle: null,
|
||||
aisleType: 'solid-aisle',
|
||||
aisleWidth: 0.1,
|
||||
aisleColor: 'yellow',
|
||||
|
||||
dashLength: 0.5,
|
||||
gapLength: 0.3,
|
||||
dotRadius: 0.1,
|
||||
aisleLength: 0.6,
|
||||
isFlipped: false,
|
||||
|
||||
// === Setters: Point/Line ===
|
||||
|
||||
setHoveredPoint: (point: Point | null) => {
|
||||
set((state) => {
|
||||
state.hoveredPoint = point;
|
||||
});
|
||||
},
|
||||
|
||||
setSnappedPoint: (point: Point | null) => {
|
||||
set((state) => {
|
||||
state.snappedPoint = point;
|
||||
});
|
||||
},
|
||||
|
||||
setSnappedPosition: (position: [number, number, number] | null) => {
|
||||
set((state) => {
|
||||
state.snappedPosition = position;
|
||||
});
|
||||
},
|
||||
|
||||
setHoveredLine: (line: [Point, Point] | null) => {
|
||||
set((state) => {
|
||||
state.hoveredLine = line;
|
||||
})
|
||||
},
|
||||
|
||||
// === Setters: Wall ===
|
||||
|
||||
setSelectedWall: (wall: Object3D | null) => {
|
||||
set((state) => {
|
||||
state.selectedWall = wall;
|
||||
})
|
||||
},
|
||||
|
||||
setWallThickness: (thickness: number) => {
|
||||
set((state) => {
|
||||
@@ -113,44 +147,15 @@ export const useBuilderStore = create<BuilderState>()(
|
||||
});
|
||||
},
|
||||
|
||||
// Aisle
|
||||
// === Setters: Decal ===
|
||||
|
||||
selectedAisle: null,
|
||||
|
||||
aisleType: 'solid-aisle',
|
||||
aisleWidth: 0.1,
|
||||
aisleColor: 'yellow',
|
||||
dashLength: 0.5,
|
||||
gapLength: 0.3,
|
||||
dotRadius: 0.1,
|
||||
aisleLength: 0.6,
|
||||
isFlipped: false,
|
||||
|
||||
// Individual setters
|
||||
|
||||
setHoveredPoint: (point: Point | null) => {
|
||||
setSelectedDecal: (decal: Object3D | null) => {
|
||||
set((state) => {
|
||||
state.hoveredPoint = point;
|
||||
});
|
||||
},
|
||||
|
||||
setHoveredLine: (line: [Point, Point] | null) => {
|
||||
set((state) => {
|
||||
state.hoveredLine = line;
|
||||
state.selectedDecal = decal;
|
||||
})
|
||||
},
|
||||
|
||||
setSnappedPoint: (point: Point | null) => {
|
||||
set((state) => {
|
||||
state.snappedPoint = point;
|
||||
});
|
||||
},
|
||||
|
||||
setSnappedPosition: (position: [number, number, number] | null) => {
|
||||
set((state) => {
|
||||
state.snappedPosition = position;
|
||||
});
|
||||
},
|
||||
// === Setters: Aisle General ===
|
||||
|
||||
setSelectedAisle: (aisle: Object3D | null) => {
|
||||
set((state) => {
|
||||
@@ -163,73 +168,78 @@ export const useBuilderStore = create<BuilderState>()(
|
||||
state.aisleType = type;
|
||||
});
|
||||
},
|
||||
|
||||
setAisleWidth: (width) => {
|
||||
set((state) => {
|
||||
state.aisleWidth = width;
|
||||
});
|
||||
},
|
||||
|
||||
setAisleColor: (color) => {
|
||||
set((state) => {
|
||||
state.aisleColor = color;
|
||||
});
|
||||
},
|
||||
|
||||
// === Setters: Aisle Specific ===
|
||||
|
||||
setDashLength: (length) => {
|
||||
set((state) => {
|
||||
state.dashLength = length;
|
||||
});
|
||||
},
|
||||
|
||||
setGapLength: (length) => {
|
||||
set((state) => {
|
||||
state.gapLength = length;
|
||||
});
|
||||
},
|
||||
|
||||
setDotRadius: (radius) => {
|
||||
set((state) => {
|
||||
state.dotRadius = radius;
|
||||
});
|
||||
},
|
||||
|
||||
setAisleLength: (length) => {
|
||||
set((state) => {
|
||||
state.aisleLength = length;
|
||||
});
|
||||
},
|
||||
|
||||
setIsFlipped: (isFlipped) => {
|
||||
set((state) => {
|
||||
state.isFlipped = isFlipped;
|
||||
});
|
||||
},
|
||||
|
||||
// Batch setters
|
||||
setDashedAisleProperties: (width, dashLength, gapLength) => {
|
||||
set((state) => {
|
||||
state.aisleType = 'dashed-aisle';
|
||||
state.aisleWidth = width;
|
||||
state.dashLength = dashLength;
|
||||
state.gapLength = gapLength;
|
||||
});
|
||||
},
|
||||
setDottedAisleProperties: (width, dotRadius, gapLength) => {
|
||||
set((state) => {
|
||||
state.aisleType = 'dotted-aisle';
|
||||
state.aisleWidth = width;
|
||||
state.dotRadius = dotRadius;
|
||||
state.gapLength = gapLength;
|
||||
});
|
||||
},
|
||||
setArrowsAisleProperties: (width, aisleLength, gapLength) => {
|
||||
set((state) => {
|
||||
state.aisleType = 'arrows-aisle';
|
||||
state.aisleWidth = width;
|
||||
state.aisleLength = aisleLength;
|
||||
state.gapLength = gapLength;
|
||||
});
|
||||
},
|
||||
setAisleProperties: (type, width, color) => {
|
||||
set((state) => {
|
||||
state.aisleType = type;
|
||||
state.aisleWidth = width;
|
||||
state.aisleColor = color;
|
||||
});
|
||||
}
|
||||
// === Batch Setters ===
|
||||
|
||||
setDashedAisleProperties: (width, dashLength, gapLength) => set((state) => {
|
||||
state.aisleType = 'dashed-aisle';
|
||||
state.aisleWidth = width;
|
||||
state.dashLength = dashLength;
|
||||
state.gapLength = gapLength;
|
||||
}),
|
||||
|
||||
setDottedAisleProperties: (width, dotRadius, gapLength) => set((state) => {
|
||||
state.aisleType = 'dotted-aisle';
|
||||
state.aisleWidth = width;
|
||||
state.dotRadius = dotRadius;
|
||||
state.gapLength = gapLength;
|
||||
}),
|
||||
|
||||
setArrowsAisleProperties: (width, aisleLength, gapLength) => set((state) => {
|
||||
state.aisleType = 'arrows-aisle';
|
||||
state.aisleWidth = width;
|
||||
state.aisleLength = aisleLength;
|
||||
state.gapLength = gapLength;
|
||||
}),
|
||||
|
||||
setAisleProperties: (type, width, color) => set((state) => {
|
||||
state.aisleType = type;
|
||||
state.aisleWidth = width;
|
||||
state.aisleColor = color;
|
||||
})
|
||||
}))
|
||||
);
|
||||
);
|
||||
|
||||
90
app/src/store/builder/useFloorStore.ts
Normal file
90
app/src/store/builder/useFloorStore.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
import { create } from 'zustand';
|
||||
import { immer } from 'zustand/middleware/immer';
|
||||
|
||||
interface FloorStore {
|
||||
floors: Floor[];
|
||||
setFloors: (floors: Floor[]) => void;
|
||||
addFloor: (floor: Floor) => void;
|
||||
updateFloor: (uuid: string, updated: Partial<Floor>) => void;
|
||||
removeFloor: (uuid: string) => void;
|
||||
removePointFromFloors: (pointUuid: string) => void;
|
||||
clearFloors: () => void;
|
||||
setIsBeveled: (uuid: string, isBeveled: boolean) => void;
|
||||
setBevelStrength: (uuid: string, strength: number) => void;
|
||||
setDepth: (uuid: string, depth: number) => void;
|
||||
setMaterial: (uuid: string, sideMaterial: string, topMaterial: string) => void;
|
||||
|
||||
getFloorById: (uuid: string) => Floor | undefined;
|
||||
}
|
||||
|
||||
export const createFloorStore = () => {
|
||||
return create<FloorStore>()(
|
||||
immer((set, get) => ({
|
||||
floors: [],
|
||||
|
||||
setFloors: (floors) => set(state => {
|
||||
state.floors = floors;
|
||||
}),
|
||||
|
||||
addFloor: (floor) => set(state => {
|
||||
state.floors.push(floor);
|
||||
}),
|
||||
|
||||
updateFloor: (uuid, updated) => set(state => {
|
||||
const floor = state.floors.find(f => f.floorUuid === uuid);
|
||||
if (floor) {
|
||||
Object.assign(floor, updated);
|
||||
}
|
||||
}),
|
||||
|
||||
removeFloor: (uuid) => set(state => {
|
||||
state.floors = state.floors.filter(f => f.floorUuid !== uuid);
|
||||
}),
|
||||
|
||||
removePointFromFloors: (pointUuid) => set(state => {
|
||||
for (const floor of state.floors) {
|
||||
floor.points = floor.points.filter(p => p.pointUuid !== pointUuid);
|
||||
}
|
||||
}),
|
||||
|
||||
clearFloors: () => set(state => {
|
||||
state.floors = [];
|
||||
}),
|
||||
|
||||
setIsBeveled: (uuid, isBeveled) => set(state => {
|
||||
const floor = state.floors.find(f => f.floorUuid === uuid);
|
||||
if (floor) {
|
||||
floor.isBeveled = isBeveled;
|
||||
}
|
||||
}),
|
||||
|
||||
setBevelStrength: (uuid, strength) => set(state => {
|
||||
const floor = state.floors.find(f => f.floorUuid === uuid);
|
||||
if (floor) {
|
||||
floor.bevelStrength = strength;
|
||||
}
|
||||
}),
|
||||
|
||||
setDepth: (uuid, depth) => set(state => {
|
||||
const floor = state.floors.find(f => f.floorUuid === uuid);
|
||||
if (floor) {
|
||||
floor.floorDepth = depth;
|
||||
}
|
||||
}),
|
||||
|
||||
setMaterial: (uuid, sideMaterial, topMaterial) => set(state => {
|
||||
const floor = state.floors.find(f => f.floorUuid === uuid);
|
||||
if (floor) {
|
||||
floor.sideMaterial = sideMaterial;
|
||||
floor.topMaterial = topMaterial;
|
||||
}
|
||||
}),
|
||||
|
||||
getFloorById: (uuid) => {
|
||||
return get().floors.find(f => f.floorUuid === uuid);
|
||||
},
|
||||
}))
|
||||
);
|
||||
};
|
||||
|
||||
export type FloorStoreType = ReturnType<typeof createFloorStore>;
|
||||
82
app/src/store/builder/useWallAssetStore.ts
Normal file
82
app/src/store/builder/useWallAssetStore.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import { create } from 'zustand';
|
||||
import { immer } from 'zustand/middleware/immer';
|
||||
|
||||
interface WallAssetStore {
|
||||
wallAssets: WallAsset[];
|
||||
setWallAssets: (assets: WallAsset[]) => void;
|
||||
addWallAsset: (asset: WallAsset) => void;
|
||||
updateWallAsset: (uuid: string, updated: Partial<WallAsset>) => void;
|
||||
removeWallAsset: (uuid: string) => void;
|
||||
clearWallAssets: () => void;
|
||||
|
||||
setVisibility: (uuid: string, isVisible: boolean) => void;
|
||||
setLock: (uuid: string, isLocked: boolean) => void;
|
||||
setOpacity: (uuid: string, opacity: number) => void;
|
||||
|
||||
getWallAssetById: (uuid: string) => WallAsset | undefined;
|
||||
getAssetsByWall: (wallUuid: string) => WallAsset[];
|
||||
}
|
||||
|
||||
export const createWallAssetStore = () => {
|
||||
return create<WallAssetStore>()(
|
||||
immer((set, get) => ({
|
||||
wallAssets: [],
|
||||
|
||||
setWallAssets: (assets) => set(state => {
|
||||
state.wallAssets = assets;
|
||||
}),
|
||||
|
||||
addWallAsset: (asset) => set(state => {
|
||||
state.wallAssets.push(asset);
|
||||
}),
|
||||
|
||||
updateWallAsset: (uuid, updated) => set(state => {
|
||||
const asset = state.wallAssets.find(a => a.modelUuid === uuid);
|
||||
if (asset) {
|
||||
Object.assign(asset, updated);
|
||||
}
|
||||
}),
|
||||
|
||||
removeWallAsset: (uuid) => set(state => {
|
||||
state.wallAssets = state.wallAssets.filter(a => a.modelUuid !== uuid);
|
||||
}),
|
||||
|
||||
clearWallAssets: () => {
|
||||
set(state => {
|
||||
state.wallAssets = [];
|
||||
})
|
||||
},
|
||||
|
||||
setVisibility: (uuid, isVisible) => set(state => {
|
||||
const asset = state.wallAssets.find(a => a.modelUuid === uuid);
|
||||
if (asset) {
|
||||
asset.isVisible = isVisible;
|
||||
}
|
||||
}),
|
||||
|
||||
setLock: (uuid, isLocked) => set(state => {
|
||||
const asset = state.wallAssets.find(a => a.modelUuid === uuid);
|
||||
if (asset) {
|
||||
asset.isLocked = isLocked;
|
||||
}
|
||||
}),
|
||||
|
||||
setOpacity: (uuid, opacity) => set(state => {
|
||||
const asset = state.wallAssets.find(a => a.modelUuid === uuid);
|
||||
if (asset) {
|
||||
asset.opacity = opacity;
|
||||
}
|
||||
}),
|
||||
|
||||
getWallAssetById: (uuid) => {
|
||||
return get().wallAssets.find(a => a.modelUuid === uuid);
|
||||
},
|
||||
|
||||
getAssetsByWall: (wallUuid) => {
|
||||
return get().wallAssets.filter(a => a.wallUuid === wallUuid);
|
||||
},
|
||||
}))
|
||||
);
|
||||
};
|
||||
|
||||
export type WallAssetStoreType = ReturnType<typeof createWallAssetStore>;
|
||||
211
app/src/store/builder/useWallStore.ts
Normal file
211
app/src/store/builder/useWallStore.ts
Normal file
@@ -0,0 +1,211 @@
|
||||
import { create } from 'zustand';
|
||||
import { immer } from 'zustand/middleware/immer';
|
||||
|
||||
interface WallStore {
|
||||
walls: Wall[];
|
||||
setWalls: (walls: Wall[]) => void;
|
||||
addWall: (wall: Wall) => void;
|
||||
updateWall: (uuid: string, updated: Partial<Wall>) => void;
|
||||
removeWall: (uuid: string) => void;
|
||||
clearWalls: () => void;
|
||||
removeWallByPoints: (Points: [Point, Point]) => Wall | undefined;
|
||||
addDecal: (wallUuid: string, decal: Decal) => void;
|
||||
updateDecal: (decalUuid: string, decal: Decal) => void;
|
||||
removeDecal: (decalUuid: string) => void;
|
||||
updateDecalPosition: (decalUuid: string, position: [number, number, number]) => void;
|
||||
updateDecalRotation: (decalUuid: string, rotation: number) => void;
|
||||
updateDecalScale: (decalUuid: string, scale: number) => void;
|
||||
|
||||
removePoint: (pointUuid: string) => Wall[];
|
||||
setPosition: (pointUuid: string, position: [number, number, number]) => void;
|
||||
setLayer: (pointUuid: string, layer: number) => void;
|
||||
|
||||
getWallById: (uuid: string) => Wall | undefined;
|
||||
getWallByPointId: (uuid: string) => Wall | undefined;
|
||||
getWallByPoints: (points: Point[]) => Wall | undefined;
|
||||
getWallPointById: (uuid: string) => Point | undefined;
|
||||
getConnectedPoints: (uuid: string) => Point[];
|
||||
}
|
||||
|
||||
export const createWallStore = () => {
|
||||
return create<WallStore>()(
|
||||
immer((set, get) => ({
|
||||
walls: [],
|
||||
|
||||
setWalls: (walls) => set((state) => {
|
||||
state.walls = walls;
|
||||
}),
|
||||
|
||||
addWall: (wall) => set((state) => {
|
||||
state.walls.push(wall);
|
||||
}),
|
||||
|
||||
updateWall: (uuid, updated) => set((state) => {
|
||||
const wall = state.walls.find(w => w.wallUuid === uuid);
|
||||
if (wall) {
|
||||
Object.assign(wall, updated);
|
||||
}
|
||||
}),
|
||||
|
||||
removeWall: (uuid) => set((state) => {
|
||||
state.walls = state.walls.filter(w => w.wallUuid !== uuid);
|
||||
}),
|
||||
|
||||
clearWalls: () => {
|
||||
set((state) => {
|
||||
state.walls = [];
|
||||
})
|
||||
},
|
||||
|
||||
removeWallByPoints: (points) => {
|
||||
let removedWall: Wall | undefined;
|
||||
const [pointA, pointB] = points;
|
||||
|
||||
set((state) => {
|
||||
state.walls = state.walls.filter(wall => {
|
||||
const wallPoints = wall.points.map(p => p.pointUuid);
|
||||
const hasBothPoints = wallPoints.includes(pointA.pointUuid) && wallPoints.includes(pointB.pointUuid);
|
||||
|
||||
if (hasBothPoints) {
|
||||
removedWall = JSON.parse(JSON.stringify(wall));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
});
|
||||
|
||||
return removedWall;
|
||||
},
|
||||
|
||||
addDecal: (wallUuid, decal) => set((state) => {
|
||||
const wallToUpdate = state.walls.find(w => w.wallUuid === wallUuid);
|
||||
if (wallToUpdate) {
|
||||
wallToUpdate.decals.push(decal);
|
||||
}
|
||||
}),
|
||||
|
||||
updateDecal: (decalUuid, decal) => set((state) => {
|
||||
for (const wall of state.walls) {
|
||||
const decalToUpdate = wall.decals.find(d => d.decalUuid === decalUuid);
|
||||
if (decalToUpdate) {
|
||||
Object.assign(decalToUpdate, decal);
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
removeDecal: (decalUuid) => set((state) => {
|
||||
for (const wall of state.walls) {
|
||||
wall.decals = wall.decals.filter(d => d.decalUuid !== decalUuid);
|
||||
}
|
||||
}),
|
||||
|
||||
updateDecalPosition: (decalUuid, position) => set((state) => {
|
||||
for (const wall of state.walls) {
|
||||
const decal = wall.decals.find(d => d.decalUuid === decalUuid);
|
||||
if (decal) {
|
||||
decal.decalPosition = position;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
updateDecalRotation: (decalUuid, rotation) => set((state) => {
|
||||
for (const wall of state.walls) {
|
||||
const decal = wall.decals.find(d => d.decalUuid === decalUuid);
|
||||
if (decal) {
|
||||
decal.decalRotation = rotation;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
updateDecalScale: (decalUuid, scale) => set((state) => {
|
||||
for (const wall of state.walls) {
|
||||
const decal = wall.decals.find(d => d.decalUuid === decalUuid);
|
||||
if (decal) {
|
||||
decal.decalScale = scale;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
removePoint: (pointUuid) => {
|
||||
const removedWalls: Wall[] = [];
|
||||
set((state) => {
|
||||
state.walls = state.walls.filter((wall) => {
|
||||
const hasPoint = wall.points.some(p => p.pointUuid === pointUuid);
|
||||
if (hasPoint) {
|
||||
removedWalls.push(JSON.parse(JSON.stringify(wall)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
});
|
||||
return removedWalls;
|
||||
},
|
||||
|
||||
setPosition: (pointUuid, position) => set((state) => {
|
||||
for (const wall of state.walls) {
|
||||
const point = wall.points.find(p => p.pointUuid === pointUuid);
|
||||
if (point) {
|
||||
point.position = position;
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
setLayer: (pointUuid, layer) => set((state) => {
|
||||
for (const wall of state.walls) {
|
||||
const point = wall.points.find(p => p.pointUuid === pointUuid);
|
||||
if (point) {
|
||||
point.layer = layer;
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
getWallById: (uuid) => {
|
||||
return get().walls.find(w => w.wallUuid === uuid);
|
||||
},
|
||||
|
||||
getWallByPointId: (uuid) => {
|
||||
for (const wall of get().walls) {
|
||||
if (wall.points.some(p => p.pointUuid === uuid)) {
|
||||
return wall;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
|
||||
getWallByPoints: (point) => {
|
||||
for (const wall of get().walls) {
|
||||
if (((wall.points[0].pointUuid === point[0].pointUuid) || (wall.points[1].pointUuid === point[0].pointUuid)) &&
|
||||
((wall.points[0].pointUuid === point[1].pointUuid) || (wall.points[1].pointUuid === point[1].pointUuid))) {
|
||||
return wall;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
|
||||
getWallPointById: (uuid) => {
|
||||
for (const wall of get().walls) {
|
||||
const point = wall.points.find(p => p.pointUuid === uuid);
|
||||
if (point) return point;
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
|
||||
getConnectedPoints: (uuid) => {
|
||||
const connected: Point[] = [];
|
||||
for (const wall of get().walls) {
|
||||
for (const point of wall.points) {
|
||||
if (point.pointUuid === uuid) {
|
||||
connected.push(...wall.points.filter(p => p.pointUuid !== uuid));
|
||||
}
|
||||
}
|
||||
}
|
||||
return connected;
|
||||
},
|
||||
}))
|
||||
)
|
||||
}
|
||||
|
||||
export type WallStoreType = ReturnType<typeof createWallStore>;
|
||||
@@ -1,200 +0,0 @@
|
||||
import { create } from 'zustand';
|
||||
import { immer } from 'zustand/middleware/immer';
|
||||
|
||||
interface WallStore {
|
||||
walls: Wall[];
|
||||
setWalls: (walls: Wall[]) => void;
|
||||
addWall: (wall: Wall) => void;
|
||||
updateWall: (uuid: string, updated: Partial<Wall>) => void;
|
||||
removeWall: (uuid: string) => void;
|
||||
removeWallByPoints: (Points: [Point, Point]) => Wall | undefined;
|
||||
addDecal: (wallUuid: string, decal: Decal) => void;
|
||||
updateDecal: (decalUuid: string, decal: Decal) => void;
|
||||
removeDecal: (decalUuid: string) => void;
|
||||
updateDecalPosition: (decalUuid: string, position: [number, number, number]) => void;
|
||||
updateDecalRotation: (decalUuid: string, rotation: number) => void;
|
||||
updateDecalScale: (decalUuid: string, scale: number) => void;
|
||||
|
||||
removePoint: (pointUuid: string) => Wall[];
|
||||
setPosition: (pointUuid: string, position: [number, number, number]) => void;
|
||||
setLayer: (pointUuid: string, layer: number) => void;
|
||||
|
||||
getWallById: (uuid: string) => Wall | undefined;
|
||||
getWallByPointId: (uuid: string) => Wall | undefined;
|
||||
getWallByPoints: (points: Point[]) => Wall | undefined;
|
||||
getWallPointById: (uuid: string) => Point | undefined;
|
||||
getConnectedPoints: (uuid: string) => Point[];
|
||||
}
|
||||
|
||||
export const useWallStore = create<WallStore>()(
|
||||
immer((set, get) => ({
|
||||
walls: [],
|
||||
|
||||
setWalls: (walls) => set((state) => {
|
||||
state.walls = walls;
|
||||
}),
|
||||
|
||||
addWall: (wall) => set((state) => {
|
||||
state.walls.push(wall);
|
||||
}),
|
||||
|
||||
updateWall: (uuid, updated) => set((state) => {
|
||||
const wall = state.walls.find(w => w.wallUuid === uuid);
|
||||
if (wall) {
|
||||
Object.assign(wall, updated);
|
||||
}
|
||||
}),
|
||||
|
||||
removeWall: (uuid) => set((state) => {
|
||||
state.walls = state.walls.filter(w => w.wallUuid !== uuid);
|
||||
}),
|
||||
|
||||
removeWallByPoints: (points) => {
|
||||
let removedWall: Wall | undefined;
|
||||
const [pointA, pointB] = points;
|
||||
|
||||
set((state) => {
|
||||
state.walls = state.walls.filter(wall => {
|
||||
const wallPoints = wall.points.map(p => p.pointUuid);
|
||||
const hasBothPoints = wallPoints.includes(pointA.pointUuid) && wallPoints.includes(pointB.pointUuid);
|
||||
|
||||
if (hasBothPoints) {
|
||||
removedWall = JSON.parse(JSON.stringify(wall));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
});
|
||||
|
||||
return removedWall;
|
||||
},
|
||||
|
||||
addDecal: (wallUuid, decal) => set((state) => {
|
||||
const wallToUpdate = state.walls.find(w => w.wallUuid === wallUuid);
|
||||
if (wallToUpdate) {
|
||||
wallToUpdate.decals.push(decal);
|
||||
}
|
||||
}),
|
||||
|
||||
updateDecal: (decalUuid, decal) => set((state) => {
|
||||
for (const wall of state.walls) {
|
||||
const decalToUpdate = wall.decals.find(d => d.decalUuid === decalUuid);
|
||||
if (decalToUpdate) {
|
||||
Object.assign(decalToUpdate, decal);
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
removeDecal: (decalUuid) => set((state) => {
|
||||
for (const wall of state.walls) {
|
||||
wall.decals = wall.decals.filter(d => d.decalUuid !== decalUuid);
|
||||
}
|
||||
}),
|
||||
|
||||
updateDecalPosition: (decalUuid, position) => set((state) => {
|
||||
for (const wall of state.walls) {
|
||||
const decal = wall.decals.find(d => d.decalUuid === decalUuid);
|
||||
if (decal) {
|
||||
decal.decalPosition = position;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
updateDecalRotation: (decalUuid, rotation) => set((state) => {
|
||||
for (const wall of state.walls) {
|
||||
const decal = wall.decals.find(d => d.decalUuid === decalUuid);
|
||||
if (decal) {
|
||||
decal.decalRotation = rotation;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
updateDecalScale: (decalUuid, scale) => set((state) => {
|
||||
for (const wall of state.walls) {
|
||||
const decal = wall.decals.find(d => d.decalUuid === decalUuid);
|
||||
if (decal) {
|
||||
decal.decalScale = scale;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
removePoint: (pointUuid) => {
|
||||
const removedWalls: Wall[] = [];
|
||||
set((state) => {
|
||||
state.walls = state.walls.filter((wall) => {
|
||||
const hasPoint = wall.points.some(p => p.pointUuid === pointUuid);
|
||||
if (hasPoint) {
|
||||
removedWalls.push(JSON.parse(JSON.stringify(wall)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
});
|
||||
return removedWalls;
|
||||
},
|
||||
|
||||
setPosition: (pointUuid, position) => set((state) => {
|
||||
for (const wall of state.walls) {
|
||||
const point = wall.points.find(p => p.pointUuid === pointUuid);
|
||||
if (point) {
|
||||
point.position = position;
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
setLayer: (pointUuid, layer) => set((state) => {
|
||||
for (const wall of state.walls) {
|
||||
const point = wall.points.find(p => p.pointUuid === pointUuid);
|
||||
if (point) {
|
||||
point.layer = layer;
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
getWallById: (uuid) => {
|
||||
return get().walls.find(w => w.wallUuid === uuid);
|
||||
},
|
||||
|
||||
getWallByPointId: (uuid) => {
|
||||
for (const wall of get().walls) {
|
||||
if (wall.points.some(p => p.pointUuid === uuid)) {
|
||||
return wall;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
|
||||
getWallByPoints: (point) => {
|
||||
for (const wall of get().walls) {
|
||||
if (((wall.points[0].pointUuid === point[0].pointUuid) || (wall.points[1].pointUuid === point[0].pointUuid)) &&
|
||||
((wall.points[0].pointUuid === point[1].pointUuid) || (wall.points[1].pointUuid === point[1].pointUuid))) {
|
||||
return wall;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
|
||||
getWallPointById: (uuid) => {
|
||||
for (const wall of get().walls) {
|
||||
const point = wall.points.find(p => p.pointUuid === uuid);
|
||||
if (point) return point;
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
|
||||
getConnectedPoints: (uuid) => {
|
||||
const connected: Point[] = [];
|
||||
for (const wall of get().walls) {
|
||||
for (const point of wall.points) {
|
||||
if (point.pointUuid === uuid) {
|
||||
connected.push(...wall.points.filter(p => p.pointUuid !== uuid));
|
||||
}
|
||||
}
|
||||
}
|
||||
return connected;
|
||||
},
|
||||
}))
|
||||
);
|
||||
74
app/src/store/builder/useZoneStore.ts
Normal file
74
app/src/store/builder/useZoneStore.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { create } from 'zustand';
|
||||
import { immer } from 'zustand/middleware/immer';
|
||||
|
||||
interface ZoneStore {
|
||||
zones: Zone[];
|
||||
setZones: (zones: Zone[]) => void;
|
||||
addZone: (zone: Zone) => void;
|
||||
updateZone: (uuid: string, updated: Partial<Zone>) => void;
|
||||
removeZone: (uuid: string) => void;
|
||||
removePointFromZones: (pointUuid: string) => void;
|
||||
clearZones: () => void;
|
||||
setViewPort: (uuid: string, position: [number, number, number], target: [number, number, number]) => void;
|
||||
setColor: (uuid: string, color: string) => void;
|
||||
|
||||
getZoneById: (uuid: string) => Zone | undefined;
|
||||
}
|
||||
|
||||
export const createZoneStore = () => {
|
||||
return create<ZoneStore>()(
|
||||
immer((set, get) => ({
|
||||
zones: [],
|
||||
|
||||
setZones: (zones) => set(state => {
|
||||
state.zones = zones;
|
||||
}),
|
||||
|
||||
addZone: (zone) => set(state => {
|
||||
state.zones.push(zone);
|
||||
}),
|
||||
|
||||
updateZone: (uuid, updated) => set(state => {
|
||||
const zone = state.zones.find(z => z.zoneUuid === uuid);
|
||||
if (zone) {
|
||||
Object.assign(zone, updated);
|
||||
}
|
||||
}),
|
||||
|
||||
removeZone: (uuid) => set(state => {
|
||||
state.zones = state.zones.filter(z => z.zoneUuid !== uuid);
|
||||
}),
|
||||
|
||||
removePointFromZones: (pointUuid) => set(state => {
|
||||
for (const zone of state.zones) {
|
||||
zone.points = zone.points.filter(p => p.pointUuid !== pointUuid);
|
||||
}
|
||||
}),
|
||||
|
||||
clearZones: () => set(state => {
|
||||
state.zones = [];
|
||||
}),
|
||||
|
||||
setViewPort: (uuid, position, target) => set(state => {
|
||||
const zone = state.zones.find(z => z.zoneUuid === uuid);
|
||||
if (zone) {
|
||||
zone.viewPortPosition = position;
|
||||
zone.viewPortTarget = target;
|
||||
}
|
||||
}),
|
||||
|
||||
setColor: (uuid, color) => set(state => {
|
||||
const zone = state.zones.find(z => z.zoneUuid === uuid);
|
||||
if (zone) {
|
||||
zone.zoneColor = color;
|
||||
}
|
||||
}),
|
||||
|
||||
getZoneById: (uuid) => {
|
||||
return get().zones.find(z => z.zoneUuid === uuid);
|
||||
},
|
||||
}))
|
||||
);
|
||||
};
|
||||
|
||||
export type ZoneStoreType = ReturnType<typeof createZoneStore>;
|
||||
@@ -1657,8 +1657,13 @@
|
||||
|
||||
.sidebar-right-wrapper {
|
||||
.wall-properties-container {
|
||||
.wall-properties-section{
|
||||
padding: 14px;
|
||||
padding-bottom: 0;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.header {
|
||||
color: var(--background-color-button);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.wall-properties {
|
||||
@@ -1692,7 +1697,7 @@
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
background: var(--Grays-Gray-6, #f2f2f7);
|
||||
background: var(--background-color-secondary);
|
||||
padding: 18px 25px;
|
||||
|
||||
.sides-wrapper {
|
||||
@@ -1736,8 +1741,10 @@
|
||||
}
|
||||
|
||||
.preview {
|
||||
width: 90%;
|
||||
width: 100%;
|
||||
height: 111px;
|
||||
border-radius: 20px;
|
||||
overflow: hidden;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
@@ -1750,7 +1757,8 @@
|
||||
.materials {
|
||||
max-height: 250px;
|
||||
overflow: auto;
|
||||
margin-bottom: 6px;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 16px;
|
||||
padding: 0 12px;
|
||||
|
||||
.material-container {
|
||||
|
||||
60
app/src/types/builderTypes.d.ts
vendored
60
app/src/types/builderTypes.d.ts
vendored
@@ -10,6 +10,7 @@ interface Version {
|
||||
|
||||
type VersionHistory = Version[];
|
||||
|
||||
|
||||
// Asset
|
||||
|
||||
interface Asset {
|
||||
@@ -45,6 +46,22 @@ interface Asset {
|
||||
type Assets = Asset[];
|
||||
|
||||
|
||||
// Wall-Asset
|
||||
|
||||
interface WallAsset {
|
||||
modelUuid: string;
|
||||
modelName: string;
|
||||
assetId: string;
|
||||
wallUuid: string;
|
||||
position: [number, number, number];
|
||||
isLocked: boolean;
|
||||
isVisible: boolean;
|
||||
opacity: number;
|
||||
}
|
||||
|
||||
type WallAssets = WallAsset[];
|
||||
|
||||
|
||||
// Point
|
||||
|
||||
type PointTypes = 'Aisle' | 'Wall' | 'Floor' | 'Zone';
|
||||
@@ -63,11 +80,22 @@ interface Decal {
|
||||
decalUuid: string;
|
||||
decalName: string;
|
||||
decalId: string;
|
||||
decalType: WallDecal | FloorDecal;
|
||||
decalPosition: [number, number, number];
|
||||
decalRotation: number;
|
||||
decalScale: number;
|
||||
}
|
||||
|
||||
interface WallDecal {
|
||||
type: 'Wall';
|
||||
wallUuid: string;
|
||||
}
|
||||
|
||||
interface FloorDecal {
|
||||
type: 'Floor';
|
||||
floorUuid: string;
|
||||
}
|
||||
|
||||
interface Wall {
|
||||
wallUuid: string;
|
||||
points: [Point, Point];
|
||||
@@ -75,12 +103,42 @@ interface Wall {
|
||||
insideMaterial: string;
|
||||
wallThickness: number;
|
||||
wallHeight: number;
|
||||
decals: Decal[]
|
||||
decals: Decal[];
|
||||
}
|
||||
|
||||
type Walls = Wall[];
|
||||
|
||||
|
||||
// Floor
|
||||
|
||||
interface Floor {
|
||||
floorUuid: string;
|
||||
points: Point[];
|
||||
sideMaterial: string;
|
||||
topMaterial: string;
|
||||
floorDepth: number;
|
||||
isBeveled: boolean;
|
||||
bevelStrength: number;
|
||||
decals: Decal[];
|
||||
}
|
||||
|
||||
type Floors = Floor[];
|
||||
|
||||
|
||||
// Zone
|
||||
|
||||
interface Zone {
|
||||
zoneUuid: string;
|
||||
zoneName: string;
|
||||
zoneColor: string;
|
||||
points: Point[];
|
||||
viewPortTarget: [number, number, number];
|
||||
viewPortPosition: [number, number, number];
|
||||
}
|
||||
|
||||
type Zones = Zone[];
|
||||
|
||||
|
||||
// Aisle
|
||||
|
||||
type AisleTypes = 'solid-aisle' | 'dashed-aisle' | 'stripped-aisle' | 'dotted-aisle' | 'arrow-aisle' | 'arrows-aisle' | 'arc-aisle' | 'circle-aisle' | 'junction-aisle';
|
||||
|
||||
Reference in New Issue
Block a user