Refactor builder module and remove unused components

- Removed CalculateAreaGroup and computeArea function as they were no longer needed.
- Updated Floor2DInstance and Zone2DInstance to calculate area and centroid using new utility functions.
- Refactored WallInstances to include Floor2D rendering and improved area display.
- Cleaned up imports and ensured consistent formatting across files.
- Enhanced performance by memoizing calculations for area and centroid.
- Removed deprecated state management for rooms and version history visibility.
This commit is contained in:
2025-09-08 13:46:47 +05:30
parent f0d9cfe142
commit 23e7ba39e8
19 changed files with 562 additions and 645 deletions

View File

@@ -4,7 +4,7 @@ import { useLogger } from "../ui/log/LoggerContext";
import { GetLogIcon } from "./getLogIcons";
import { CurserLeftIcon, CurserMiddleIcon, CurserRightIcon } from "../icons/LogIcons";
import ShortcutHelper from "./shortcutHelper";
import useVersionHistoryVisibleStore, { useShortcutStore } from "../../store/builder/store";
import { useShortcutStore } from "../../store/builder/store";
import { usePlayButtonStore } from "../../store/ui/usePlayButtonStore";
import useModuleStore, { useSubModuleStore } from "../../store/ui/useModuleStore";
import { mouseActionHelper } from "../../utils/mouseUtils/mouseHelper";
@@ -12,123 +12,118 @@ import { useMouseNoteStore } from "../../store/ui/useUIToggleStore";
import { useSceneContext } from "../../modules/scene/sceneContext";
const Footer: React.FC = () => {
const { logs, setIsLogListVisible } = useLogger();
const lastLog = logs[logs.length - 1] || null;
const { logs, setIsLogListVisible } = useLogger();
const lastLog = logs[logs.length - 1] || null;
const { setActiveModule } = useModuleStore();
const { setSubModule } = useSubModuleStore();
const { setVersionHistoryVisible } = useVersionHistoryVisibleStore();
const { isPlaying } = usePlayButtonStore();
const { showShortcuts, setShowShortcuts } = useShortcutStore();
const { versionStore } = useSceneContext();
const { selectedVersion } = versionStore();
const { setActiveModule } = useModuleStore();
const { setSubModule } = useSubModuleStore();
const { isPlaying } = usePlayButtonStore();
const { showShortcuts, setShowShortcuts } = useShortcutStore();
const { versionStore } = useSceneContext();
const { selectedVersion, setVersionHistoryVisible } = versionStore();
const { Leftnote, Middlenote, Rightnote } = useMouseNoteStore();
const [isOnline, setIsOnline] = useState<boolean>(navigator.onLine);
const { Leftnote, Middlenote, Rightnote } = useMouseNoteStore();
const [isOnline, setIsOnline] = useState<boolean>(navigator.onLine);
// -------------------- Online/Offline Handlers --------------------
const handleOnline = useCallback(() => {
echo.success("You are back Online");
setIsOnline(true);
}, []);
// -------------------- Online/Offline Handlers --------------------
const handleOnline = useCallback(() => {
echo.success("You are back Online");
setIsOnline(true);
}, []);
const handleOffline = useCallback(() => {
echo.warn("Changes made now might not be saved");
echo.error("You are now Offline.");
setIsOnline(false);
}, []);
const handleOffline = useCallback(() => {
echo.warn("Changes made now might not be saved");
echo.error("You are now Offline.");
setIsOnline(false);
}, []);
useEffect(() => {
window.addEventListener("online", handleOnline);
window.addEventListener("offline", handleOffline);
return () => {
window.removeEventListener("online", handleOnline);
window.removeEventListener("offline", handleOffline);
};
}, [handleOnline, handleOffline]);
useEffect(() => {
window.addEventListener("online", handleOnline);
window.addEventListener("offline", handleOffline);
return () => {
window.removeEventListener("online", handleOnline);
window.removeEventListener("offline", handleOffline);
};
}, [handleOnline, handleOffline]);
// -------------------- Mouse Buttons --------------------
const mouseButtons = useMemo(
() => [
{ icon: <CurserLeftIcon />, label: Leftnote || "Pan", mouse: "left" },
{ icon: <CurserMiddleIcon />, label: Middlenote || "Scroll Zoom", mouse: "middle" },
{ icon: <CurserRightIcon />, label: Rightnote || "Orbit / Cancel action", mouse: "right" },
],
[Leftnote, Middlenote, Rightnote]
);
// -------------------- Mouse Buttons --------------------
const mouseButtons = useMemo(
() => [
{ icon: <CurserLeftIcon />, label: Leftnote || "Pan", mouse: "left" },
{ icon: <CurserMiddleIcon />, label: Middlenote || "Scroll Zoom", mouse: "middle" },
{ icon: <CurserRightIcon />, label: Rightnote || "Orbit / Cancel action", mouse: "right" },
],
[Leftnote, Middlenote, Rightnote]
);
// -------------------- Mouse Helper --------------------
useEffect(() => {
const cleanup = mouseActionHelper();
return () => cleanup();
}, []);
// -------------------- Mouse Helper --------------------
useEffect(() => {
const cleanup = mouseActionHelper();
return () => cleanup();
}, []);
return (
<div className="footer-container">
<div className="footer-wrapper">
{/* Mouse Button Info */}
<div className="selection-wrapper">
{mouseButtons.map(({ icon, label, mouse }) => (
<div className="selector-wrapper" key={mouse}>
<div className="icon">{icon}</div>
<div className="selector">{label}</div>
return (
<div className="footer-container">
<div className="footer-wrapper">
{/* Mouse Button Info */}
<div className="selection-wrapper">
{mouseButtons.map(({ icon, label, mouse }) => (
<div className="selector-wrapper" key={mouse}>
<div className="icon">{icon}</div>
<div className="selector">{label}</div>
</div>
))}
</div>
{/* Logs and Version */}
<div className="logs-wrapper">
<div className="bg-dummy left-top" />
<div className="bg-dummy right-bottom" />
<div className="log-container">
<button id="log-details-buttton" className={`logs-detail ${lastLog?.type ?? ""}`} onClick={() => setIsLogListVisible(true)}>
{lastLog ? (
<>
<span className="log-icon">{GetLogIcon(lastLog.type)}</span>
<span className="log-message">{lastLog.message}</span>
</>
) : (
"There are no logs to display at the moment."
)}
</button>
</div>
<div
className="version"
onClick={() => {
setVersionHistoryVisible(true);
setSubModule("properties");
setActiveModule("builder");
}}
>
{selectedVersion?.version ?? "v 0.0.0"}
<div className="icon">
<HelpIcon />
</div>
</div>
<div className={`wifi-connection ${isOnline ? "connected" : "disconnected"}`}>
<div className="icon">
<WifiIcon />
</div>
<div className="tooltip">{isOnline ? "Online" : "Offline"}</div>
</div>
</div>
</div>
))}
{/* Shortcut Helper */}
{!isPlaying && showShortcuts && (
<div className="shortcut-helper-overlay visible">
<ShortcutHelper setShowShortcuts={setShowShortcuts} />
</div>
)}
</div>
{/* Logs and Version */}
<div className="logs-wrapper">
<div className="bg-dummy left-top" />
<div className="bg-dummy right-bottom" />
<div className="log-container">
<button
id="log-details-buttton"
className={`logs-detail ${lastLog?.type ?? ""}`}
onClick={() => setIsLogListVisible(true)}
>
{lastLog ? (
<>
<span className="log-icon">{GetLogIcon(lastLog.type)}</span>
<span className="log-message">{lastLog.message}</span>
</>
) : (
"There are no logs to display at the moment."
)}
</button>
</div>
<div
className="version"
onClick={() => {
setVersionHistoryVisible(true);
setSubModule("properties");
setActiveModule("builder");
}}
>
{selectedVersion?.version ?? "v 0.0.0"}
<div className="icon">
<HelpIcon />
</div>
</div>
<div className={`wifi-connection ${isOnline ? "connected" : "disconnected"}`}>
<div className="icon">
<WifiIcon />
</div>
<div className="tooltip">{isOnline ? "Online" : "Offline"}</div>
</div>
</div>
</div>
{/* Shortcut Helper */}
{!isPlaying && showShortcuts && (
<div className="shortcut-helper-overlay visible">
<ShortcutHelper setShowShortcuts={setShowShortcuts} />
</div>
)}
</div>
);
);
};
export default Footer;

View File

@@ -1,13 +1,13 @@
import React, { useEffect, useState } from "react";
import Header from "./Header";
import useModuleStore, { useSubModuleStore } from "../../../store/ui/useModuleStore";
import { AnalysisIcon, FilePackageIcon, MechanicsIcon, PropertiesIcon, SimulationIcon, } from "../../icons/SimulationIcons";
import { AnalysisIcon, FilePackageIcon, MechanicsIcon, PropertiesIcon, SimulationIcon } from "../../icons/SimulationIcons";
import { useToggleStore } from "../../../store/ui/useUIToggleStore";
import Visualization from "./visualization/Visualization";
import Analysis from "./analysis/Analysis";
import Simulations from "./simulation/Simulations";
import useVersionHistoryVisibleStore, { useIsComparing, useToolMode } from "../../../store/builder/store";
import { useSelectedEventData, useSelectedEventSphere, } from "../../../store/simulation/useSimulationStore";
import { useIsComparing, useToolMode } from "../../../store/builder/store";
import { useSelectedEventData, useSelectedEventSphere } from "../../../store/simulation/useSimulationStore";
import { useBuilderStore } from "../../../store/builder/useBuilderStore";
import GlobalProperties from "./properties/GlobalProperties";
import AssetProperties from "./properties/AssetProperties";
@@ -22,6 +22,7 @@ import SelectedFloorProperties from "./properties/SelectedFloorProperties";
import SelectedDecalProperties from "./properties/SelectedDecalProperties";
import SelectedAisleProperties from "./properties/SelectedAisleProperties";
import ResourceManagement from "./resourceManagement/ResourceManagement";
import { useSceneContext } from "../../../modules/scene/sceneContext";
type DisplayComponent =
| "versionHistory"
@@ -51,7 +52,8 @@ const SideBarRight: React.FC = () => {
const { selectedWall, selectedFloor, selectedAisle, selectedFloorAsset } = useBuilderStore();
const { selectedEventData } = useSelectedEventData();
const { selectedEventSphere } = useSelectedEventSphere();
const { viewVersionHistory, setVersionHistoryVisible } = useVersionHistoryVisibleStore();
const { versionStore } = useSceneContext();
const { viewVersionHistory, setVersionHistoryVisible } = versionStore();
const { isComparing } = useIsComparing();
const [displayComponent, setDisplayComponent] = useState<DisplayComponent>("none");
@@ -207,8 +209,7 @@ const SideBarRight: React.FC = () => {
<>
<button
id="sidebar-action-list-properties"
className={`sidebar-action-list ${subModule === "properties" ? "active" : ""
}`}
className={`sidebar-action-list ${subModule === "properties" ? "active" : ""}`}
onClick={() => {
setSubModule("properties");
setVersionHistoryVisible(false);
@@ -224,8 +225,7 @@ const SideBarRight: React.FC = () => {
<>
<button
id="sidebar-action-list-simulation"
className={`sidebar-action-list ${subModule === "simulations" ? "active" : ""
}`}
className={`sidebar-action-list ${subModule === "simulations" ? "active" : ""}`}
onClick={() => {
setSubModule("simulations");
setVersionHistoryVisible(false);
@@ -236,8 +236,7 @@ const SideBarRight: React.FC = () => {
</button>
<button
id="sidebar-action-list-mechanics"
className={`sidebar-action-list ${subModule === "mechanics" ? "active" : ""
}`}
className={`sidebar-action-list ${subModule === "mechanics" ? "active" : ""}`}
onClick={() => {
setSubModule("mechanics");
setVersionHistoryVisible(false);
@@ -248,8 +247,7 @@ const SideBarRight: React.FC = () => {
</button>
<button
id="sidebar-action-list-analysis"
className={`sidebar-action-list ${subModule === "analysis" ? "active" : ""
}`}
className={`sidebar-action-list ${subModule === "analysis" ? "active" : ""}`}
onClick={() => {
setSubModule("analysis");
setVersionHistoryVisible(false);
@@ -261,23 +259,19 @@ const SideBarRight: React.FC = () => {
</>
)}
{(activeModule === "builder" ||
activeModule === "simulation") && (
<button
id="sidebar-action-list-properties"
className={`sidebar-action-list ${subModule === "resourceManagement" ? "active" : ""
}`}
onClick={() => {
setSubModule("resourceManagement");
setVersionHistoryVisible(false);
}}
>
<div className="tooltip">Resource Management</div>
<FilePackageIcon
isActive={subModule === "resourceManagement"}
/>
</button>
)}
{(activeModule === "builder" || activeModule === "simulation") && (
<button
id="sidebar-action-list-properties"
className={`sidebar-action-list ${subModule === "resourceManagement" ? "active" : ""}`}
onClick={() => {
setSubModule("resourceManagement");
setVersionHistoryVisible(false);
}}
>
<div className="tooltip">Resource Management</div>
<FilePackageIcon isActive={subModule === "resourceManagement"} />
</button>
)}
</div>
)}

View File

@@ -2,7 +2,6 @@ import { useParams } from "react-router-dom";
import { AddIcon, ArrowIcon, CloseIcon, KebabIcon, LocationIcon } from "../../../icons/ExportCommonIcons";
import { useSubModuleStore } from "../../../../store/ui/useModuleStore";
import { useSceneContext } from "../../../../modules/scene/sceneContext";
import useVersionHistoryVisibleStore from "../../../../store/builder/store";
import RenameInput from "../../../ui/inputs/RenameInput";
import { getVersionDataApi } from "../../../../services/factoryBuilder/versionControl/getVersionDataApi";
@@ -10,8 +9,7 @@ import { getVersionDataApi } from "../../../../services/factoryBuilder/versionCo
const VersionHistory = () => {
const { setSubModule } = useSubModuleStore();
const { versionStore } = useSceneContext();
const { setVersionHistoryVisible } = useVersionHistoryVisibleStore();
const { versionHistory, setCreateNewVersion, selectedVersion, setSelectedVersion } = versionStore();
const { versionHistory, setCreateNewVersion, selectedVersion, setSelectedVersion, setVersionHistoryVisible } = versionStore();
const { projectId } = useParams();
const addNewVersion = () => {
@@ -21,16 +19,16 @@ const VersionHistory = () => {
const handleSelectVersion = (version: Version) => {
if (!projectId) return;
getVersionDataApi(projectId, version.versionId).then((versionData) => {
setSelectedVersion(version);
}).catch((err) => {
echo.error(err);
})
getVersionDataApi(projectId, version.versionId)
.then((versionData) => {
setSelectedVersion(version);
})
.catch((err) => {
echo.error(err);
});
};
const handleVersionNameChange = (newName: string, versionId: string) => {
};
const handleVersionNameChange = (newName: string, versionId: string) => {};
return (
<div className="version-history-container">
@@ -38,11 +36,7 @@ const VersionHistory = () => {
<div className="version-history-header">
<div className="version-history-title">Version History</div>
<div className="version-history-icons">
<button
id="add-version"
className="icon add-icon"
onClick={addNewVersion}
>
<button id="add-version" className="icon add-icon" onClick={addNewVersion}>
<AddIcon />
</button>
<div id="version-kebab" className="icon kebab-icon">
@@ -64,9 +58,7 @@ const VersionHistory = () => {
{/* Shortcut Info */}
<div className="version-history-shortcut-info">
<div className="info-icon">i</div>
<div className="shortcut-text">
Press Ctrl + Alt + S to add to version history while editing
</div>
<div className="shortcut-text">Press Ctrl + Alt + S to add to version history while editing</div>
</div>
{/* Current Version Display */}
@@ -76,12 +68,8 @@ const VersionHistory = () => {
<LocationIcon />
</div>
<div className="location-details">
<div className="current-version">
Current Version ({selectedVersion.version})
</div>
<div className="saved-history-count">
{versionHistory.length} Saved History
</div>
<div className="current-version">Current Version ({selectedVersion.version})</div>
<div className="saved-history-count">{versionHistory.length} Saved History</div>
</div>
</div>
)}
@@ -93,16 +81,8 @@ const VersionHistory = () => {
) : (
versionHistory.map((version) => {
const key = `version-${version.versionId}`;
return (
<VersionHistoryItem
key={key}
version={version}
onSelect={handleSelectVersion}
onRename={handleVersionNameChange}
/>
);
return <VersionHistoryItem key={key} version={version} onSelect={handleSelectVersion} onRename={handleVersionNameChange} />;
})
)}
</div>
</div>
@@ -119,22 +99,14 @@ type VersionHistoryItemProps = {
const VersionHistoryItem: React.FC<VersionHistoryItemProps> = ({ version, onSelect, onRename }) => {
return (
<button
className="saved-version"
>
<div
className="version-name"
onClick={() => onSelect(version)}
>
<button className="saved-version">
<div className="version-name" onClick={() => onSelect(version)}>
v {version.version}
</div>
<div className="version-details">
<div className="details">
<span className="timestamp">
<RenameInput
value={version.versionName ? version.versionName : version.timeStamp}
onRename={(newName) => onRename(newName, version.versionId)}
/>
<RenameInput value={version.versionName ? version.versionName : version.timeStamp} onRename={(newName) => onRename(newName, version.versionId)} />
</span>
<span className="saved-by">
<div className="user-profile">{version.createdBy[0]}</div>

View File

@@ -1,104 +1,84 @@
import React from "react";
import useModuleStore from "../../store/ui/useModuleStore";
import {
BuilderIcon,
CartIcon,
SimulationIcon,
VisualizationIcon,
} from "../icons/ExportModuleIcons";
import {useToggleStore} from "../../store/ui/useUIToggleStore";
import useVersionStore from "../../store/builder/store";
import { BuilderIcon, CartIcon, SimulationIcon, VisualizationIcon } from "../icons/ExportModuleIcons";
import { useToggleStore } from "../../store/ui/useUIToggleStore";
import { useSceneContext } from "../../modules/scene/sceneContext";
const ModuleToggle: React.FC = () => {
const { activeModule, setActiveModule } = useModuleStore();
const { setToggleUI } = useToggleStore();
const { setVersionHistoryVisible } = useVersionStore();
const { activeModule, setActiveModule } = useModuleStore();
const { setToggleUI } = useToggleStore();
const { versionStore } = useSceneContext();
const { setVersionHistoryVisible } = versionStore();
return (
<div className="module-toggle-container">
<button
id={"builder"}
className={`module-list ${activeModule === "builder" ? "active" : ""}`}
onClick={() => {
setActiveModule("builder");
setVersionHistoryVisible(false);
setToggleUI(
localStorage.getItem("navBarUiLeft")
? localStorage.getItem("navBarUiLeft") === "true"
: true,
localStorage.getItem("navBarUiRight")
? localStorage.getItem("navBarUiRight") === "true"
: true
);
}}
>
<div className="icon">
<BuilderIcon isActive={activeModule === "builder"} />
return (
<div className="module-toggle-container">
<button
id={"builder"}
className={`module-list ${activeModule === "builder" ? "active" : ""}`}
onClick={() => {
setActiveModule("builder");
setVersionHistoryVisible(false);
setToggleUI(
localStorage.getItem("navBarUiLeft") ? localStorage.getItem("navBarUiLeft") === "true" : true,
localStorage.getItem("navBarUiRight") ? localStorage.getItem("navBarUiRight") === "true" : true
);
}}
>
<div className="icon">
<BuilderIcon isActive={activeModule === "builder"} />
</div>
<div className="module">Builder</div>
</button>
<button
id={"simulation"}
className={`module-list ${activeModule === "simulation" ? "active" : ""}`}
onClick={() => {
setActiveModule("simulation");
setVersionHistoryVisible(false);
setToggleUI(
localStorage.getItem("navBarUiLeft") ? localStorage.getItem("navBarUiLeft") === "true" : true,
localStorage.getItem("navBarUiRight") ? localStorage.getItem("navBarUiRight") === "true" : true
);
}}
>
<div className="icon">
<SimulationIcon isActive={activeModule === "simulation"} />
</div>
<div className="module">Simulation</div>
</button>
<button
id={"visualization"}
className={`module-list ${activeModule === "visualization" ? "active" : ""}`}
onClick={() => {
setActiveModule("visualization");
setVersionHistoryVisible(false);
setToggleUI(
localStorage.getItem("navBarUiLeft") ? localStorage.getItem("navBarUiLeft") === "true" : true,
localStorage.getItem("navBarUiRight") ? localStorage.getItem("navBarUiRight") === "true" : true
);
}}
>
<div className="icon">
<VisualizationIcon isActive={activeModule === "visualization"} />
</div>
<div className="module">Visualization</div>
</button>
<button
id={"market"}
className={`module-list ${activeModule === "market" ? "active" : ""}`}
onClick={() => {
setActiveModule("market");
setVersionHistoryVisible(false);
setToggleUI(false, false);
}}
>
<div className="icon">
<CartIcon isActive={activeModule === "market"} />
</div>
<div className="module">Market Place</div>
</button>
</div>
<div className="module">Builder</div>
</button>
<button
id={"simulation"}
className={`module-list ${
activeModule === "simulation" ? "active" : ""
}`}
onClick={() => {
setActiveModule("simulation");
setVersionHistoryVisible(false);
setToggleUI(
localStorage.getItem("navBarUiLeft")
? localStorage.getItem("navBarUiLeft") === "true"
: true,
localStorage.getItem("navBarUiRight")
? localStorage.getItem("navBarUiRight") === "true"
: true
);
}}
>
<div className="icon">
<SimulationIcon isActive={activeModule === "simulation"} />
</div>
<div className="module">Simulation</div>
</button>
<button
id={"visualization"}
className={`module-list ${
activeModule === "visualization" ? "active" : ""
}`}
onClick={() => {
setActiveModule("visualization");
setVersionHistoryVisible(false);
setToggleUI(
localStorage.getItem("navBarUiLeft")
? localStorage.getItem("navBarUiLeft") === "true"
: true,
localStorage.getItem("navBarUiRight")
? localStorage.getItem("navBarUiRight") === "true"
: true
);
}}
>
<div className="icon">
<VisualizationIcon isActive={activeModule === "visualization"} />
</div>
<div className="module">Visualization</div>
</button>
<button
id={"market"}
className={`module-list ${activeModule === "market" ? "active" : ""}`}
onClick={() => {
setActiveModule("market");
setVersionHistoryVisible(false);
setToggleUI(false, false);
}}
>
<div className="icon">
<CartIcon isActive={activeModule === "market"} />
</div>
<div className="module">Market Place</div>
</button>
</div>
);
);
};
export default ModuleToggle;

View File

@@ -2,7 +2,7 @@ import React, { useState } from "react";
import { useNavigate } from "react-router-dom";
import { ArrowIcon } from "../../icons/ExportCommonIcons";
import { toggleTheme } from "../../../utils/theme";
import useVersionHistoryVisibleStore, { useShortcutStore } from "../../../store/builder/store";
import { useShortcutStore } from "../../../store/builder/store";
import useModuleStore, { useSubModuleStore } from "../../../store/ui/useModuleStore";
import { useSceneContext } from "../../../modules/scene/sceneContext";
@@ -25,8 +25,7 @@ const MenuBar: React.FC<MenuBarProps> = ({ setOpenMenu }) => {
const [selectedItems, setSelectedItems] = useState<Record<string, boolean>>({});
const { versionStore } = useSceneContext();
const { setCreateNewVersion } = versionStore();
const { setVersionHistoryVisible } = useVersionHistoryVisibleStore();
const { setCreateNewVersion, setVersionHistoryVisible } = versionStore();
const { setActiveModule } = useModuleStore();
const { setSubModule } = useSubModuleStore();
const { showShortcuts, setShowShortcuts } = useShortcutStore();
@@ -79,7 +78,16 @@ const MenuBar: React.FC<MenuBarProps> = ({ setOpenMenu }) => {
{ label: "Import" },
{ label: "Close File" },
],
Edit: [{ label: "Undo", shortcut: "Ctrl + Z" }, { label: "Redo", shortcut: "Ctrl + Shift + Z" }, { label: "Undo History" }, { label: "Redo History" }, { label: "Find", shortcut: "Ctrl + F" }, { label: "Delete" }, { label: "Select by..." }, { label: "Keymap" }],
Edit: [
{ label: "Undo", shortcut: "Ctrl + Z" },
{ label: "Redo", shortcut: "Ctrl + Shift + Z" },
{ label: "Undo History" },
{ label: "Redo History" },
{ label: "Find", shortcut: "Ctrl + F" },
{ label: "Delete" },
{ label: "Select by..." },
{ label: "Keymap" },
],
View: [
{ label: "Grid" },
{
@@ -172,7 +180,13 @@ const MenuBar: React.FC<MenuBarProps> = ({ setOpenMenu }) => {
<div className="dropdown-menu">
{items.map((item) =>
item.submenu ? (
<button id={item.label} key={item.label} className="menu-item-container" onMouseEnter={() => setActiveSubMenu(item.label)} onMouseLeave={() => setActiveSubMenu(null)}>
<button
id={item.label}
key={item.label}
className="menu-item-container"
onMouseEnter={() => setActiveSubMenu(item.label)}
onMouseLeave={() => setActiveSubMenu(null)}
>
<div className="menu-item">
<span>{item.label}</span>
<span className="dropdown-icon">

View File

@@ -17,7 +17,6 @@ import SocketResponses from "../collaboration/socket/socketResponses.dev";
import Ground from "../scene/environment/ground";
import MeasurementTool from "../scene/tools/measurementTool";
import NavMesh from "../simulation/vehicle/navMesh/navMesh";
import CalculateAreaGroup from "./groups/calculateAreaGroup";
import LayoutImage from "./layout/layoutImage";
import AssetsGroup from "./asset/assetsGroup";
import DxfFile from "./dfx/LoadBlueprint";
@@ -51,8 +50,8 @@ export default function Builder() {
if (!toggleView) {
setHoveredLine(null);
setHoveredPoint(null);
state.gl.domElement.style.cursor = 'default';
setToolMode('cursor');
state.gl.domElement.style.cursor = "default";
setToolMode("cursor");
}
}, [toggleView]);
@@ -65,14 +64,14 @@ export default function Builder() {
setShadows(data.shadowVisibility);
setRenderDistance(data.renderDistance);
setLimitDistance(data.limitDistance);
})
});
}, [projectId]);
useFrame(() => {
if (csgRef.current && selectedWallAsset) {
csgRef.current.update();
}
})
});
return (
<>
@@ -82,13 +81,11 @@ export default function Builder() {
<AssetsGroup plane={plane} />
<mesh name='Walls-And-WallAssets-Group'>
<mesh name="Walls-And-WallAssets-Group">
<Geometry ref={csgRef} useGroups>
<WallGroup />
<WallAssetGroup />
</Geometry>
</mesh>
@@ -102,8 +99,6 @@ export default function Builder() {
<MeasurementTool />
<CalculateAreaGroup />
<NavMesh />
<DxfFile />

View File

@@ -1,50 +1,61 @@
import { useMemo } from 'react';
import { DoubleSide, Shape, Vector2 } from 'three';
import { Extrude } from '@react-three/drei';
import * as Constants from '../../../../../types/world/worldConstants';
import { useMemo } from "react";
import { DoubleSide, Shape, Vector2 } from "three";
import { Extrude, Html } from "@react-three/drei";
import * as Constants from "../../../../../types/world/worldConstants";
import getCenteroidPoint from "../../../functions/getCenteroid";
import getArea from "../../../functions/getArea";
function Floor2DInstance({ floor }: { readonly floor: Floor }) {
const savedTheme: string | null = localStorage.getItem("theme");
const points2D = useMemo(() => {
return floor.points.map((p) => new Vector2(parseFloat(p.position[0].toFixed(2)), parseFloat(p.position[2].toFixed(2))));
}, [floor]);
const shape = useMemo(() => {
const shape = new Shape();
const points = floor.points.map(p => new Vector2(p.position[0], p.position[2]));
if (points.length < 3) return null;
shape.moveTo(points[0].x, points[0].y);
for (let i = 1; i < points.length; i++) {
shape.lineTo(points[i].x, points[i].y);
shape.moveTo(points2D[0].x, points2D[0].y);
for (let i = 1; i < points2D.length; i++) {
shape.lineTo(points2D[i].x, points2D[i].y);
}
shape.lineTo(points2D[0].x, points2D[0].y);
return shape;
}, [floor]);
}, [points2D]);
const area = useMemo(() => getArea(points2D), [points2D]);
const centroid: [number, number, number] = useMemo(() => {
const center = getCenteroidPoint(points2D);
if (!center) return [0, Constants.floorConfig.height + 0.01, 0];
return [center.x, Constants.floorConfig.height + 0.01, center.y] as [number, number, number];
}, [points2D]);
if (!shape) return null;
const formattedArea = `${area.toFixed(2)}`;
return (
<mesh
castShadow
receiveShadow
name={`Floor-2D-${floor.floorUuid}`}
rotation={[Math.PI / 2, 0, 0]}
position={[0, 0, 0]}
userData={floor}
>
<Extrude
name={`Floor-${floor.floorUuid}`}
args={[shape, {
depth: Constants.floorConfig.height,
}]}
userData={floor}
>
<meshBasicMaterial
color={savedTheme === "dark" ? "#808080" : "#808080"}
side={DoubleSide}
transparent
opacity={0.4}
depthWrite={false}
/>
</Extrude>
</mesh>
<>
<mesh castShadow receiveShadow name={`Floor-2D-${floor.floorUuid}`} rotation={[Math.PI / 2, 0, 0]} position={[0, 0, 0]} userData={floor}>
<Extrude name={`Floor-${floor.floorUuid}`} args={[shape, { depth: Constants.floorConfig.height }]} userData={floor}>
<meshBasicMaterial
color={savedTheme === "dark" ? Constants.lineConfig.floorColor : Constants.lineConfig.floorColor}
side={DoubleSide}
transparent
opacity={0.4}
depthWrite={false}
/>
</Extrude>
</mesh>
<Html key={floor.floorUuid} position={centroid} wrapperClass="distance-text-wrapper" className="distance-text" zIndexRange={[1, 0]} prepend center sprite>
<div className="distance area">
{floor.floorName} ({formattedArea})
</div>
</Html>
</>
);
}
export default Floor2DInstance;
export default Floor2DInstance;

View File

@@ -1,14 +1,14 @@
import React, { useEffect, useMemo } from 'react';
import { Vector3 } from 'three';
import { Html } from '@react-three/drei';
import { useSceneContext } from '../../../scene/sceneContext';
import { useToggleView, useToolMode } from '../../../../store/builder/store';
import Line from '../../line/line';
import Point from '../../point/point';
import FloorInstance from './Instance/floorInstance';
import Floor2DInstance from './Instance/floor2DInstance';
import useModuleStore from '../../../../store/ui/useModuleStore';
import { useBuilderStore } from '../../../../store/builder/useBuilderStore';
import React, { useEffect, useMemo } from "react";
import { Vector3 } from "three";
import { Html } from "@react-three/drei";
import { useSceneContext } from "../../../scene/sceneContext";
import { useToggleView, useToolMode } from "../../../../store/builder/store";
import Line from "../../line/line";
import Point from "../../point/point";
import FloorInstance from "./Instance/floorInstance";
import Floor2DInstance from "./Instance/floor2DInstance";
import useModuleStore from "../../../../store/ui/useModuleStore";
import { useBuilderStore } from "../../../../store/builder/useBuilderStore";
function FloorInstances() {
const { floorStore } = useSceneContext();
@@ -20,11 +20,11 @@ function FloorInstances() {
useEffect(() => {
// console.log('floors: ', floors);
}, [floors])
}, [floors]);
useEffect(() => {
if (!toggleView && activeModule === 'builder') {
if (toolMode !== 'cursor') {
if (!toggleView && activeModule === "builder") {
if (toolMode !== "cursor") {
if (selectedFloor) setSelectedFloor(null);
}
} else if (selectedFloor) {
@@ -36,8 +36,8 @@ function FloorInstances() {
const points: Point[] = [];
const seenUuids = new Set<string>();
floors.forEach(floor => {
floor.points.forEach(point => {
floors.forEach((floor) => {
floor.points.forEach((point) => {
if (!seenUuids.has(point.pointUuid)) {
seenUuids.add(point.pointUuid);
points.push(point);
@@ -65,7 +65,7 @@ function FloorInstances() {
lines.push({
start: current,
end: next,
key: lineKey
key: lineKey,
});
}
}
@@ -76,9 +76,8 @@ function FloorInstances() {
return (
<>
{!toggleView && floors.length > 0 && (
<mesh name='Floors-Group'>
<mesh name="Floors-Group">
{floors.map((floor) => (
<FloorInstance key={floor.floorUuid} floor={floor} />
))}
@@ -86,7 +85,7 @@ function FloorInstances() {
)}
{toggleView && floors.length > 0 && (
<mesh name='Floors-2D-Group'>
<mesh name="Floors-2D-Group">
{floors.map((floor) => (
<Floor2DInstance key={floor.floorUuid} floor={floor} />
))}
@@ -95,14 +94,13 @@ function FloorInstances() {
{toggleView && (
<>
<group name='Floor-Points-Group'>
<group name="Floor-Points-Group">
{allPoints.map((point) => (
<Point key={point.pointUuid} point={point} />
))}
</group>
<group name='Floor-Lines-Group'>
<group name="Floor-Lines-Group">
{allLines.map(({ start, end, key }) => (
<Line key={key} points={[start, end]} />
))}
@@ -114,7 +112,7 @@ function FloorInstances() {
return (
<React.Fragment key={key}>
{toggleView &&
{toggleView && (
<Html
key={`${start.pointUuid}_${end.pointUuid}`}
userData={line}
@@ -125,24 +123,19 @@ function FloorInstances() {
prepend
sprite
>
<div
key={key}
className={`distance ${key}`}
>
<div key={key} className={`distance ${key}`}>
{distance.toFixed(2)} m
</div>
</Html>
}
)}
</React.Fragment>
)
);
})}
</group>
</>
)}
</>
)
);
}
export default FloorInstances;
export default FloorInstances;

View File

@@ -1,29 +0,0 @@
import { Vector2 } from "three";
export function computeArea(data: any, type: "zone" | "rooms" | "aisle"): any {
if (type === "zone") {
const points3D = data.map((p: any) => new Vector2(p[0], p[2]));
let area = 0;
for (let i = 0; i < points3D.length - 1; i++) {
const current = points3D[i];
const next = points3D[i + 1];
area += current.x * next.y - next.x * current.y;
}
return Math.abs(area) / 2;
}
if (type === "rooms") {
const points2D = data.coordinates.map(
(coordinate: any) =>
new Vector2(coordinate.position.x, coordinate.position.z)
);
let area = 0;
for (let i = 0; i < points2D.length - 1; i++) {
const current = points2D[i];
const next = points2D[i + 1];
area += current.x * next.y - next.x * current.y;
}
return Math.abs(area) / 2;
}
}

View File

@@ -0,0 +1,10 @@
import { Vector2 } from "three";
export default function getArea(points: Vector2[]): number {
let sum = 0;
for (let i = 0; i < points.length; i++) {
const j = (i + 1) % points.length;
sum += points[i].x * points[j].y - points[j].x * points[i].y;
}
return Math.abs(sum / 2);
}

View File

@@ -0,0 +1,48 @@
import { Vector2 } from "three";
export default function getCenteroidPoint(points: Vector2[]): Vector2 | null {
if (points.length < 3) return null;
let minZ = points[0].y;
let maxZ = points[0].y;
for (let i = 1; i < points.length; i++) {
minZ = Math.min(minZ, points[i].y);
maxZ = Math.max(maxZ, points[i].y);
}
const scanZ = minZ + (maxZ - minZ) * 0.51;
const intersections: number[] = [];
for (let i = 0; i < points.length; i++) {
const p1 = points[i];
const p2 = points[(i + 1) % points.length];
if (p1.y === p2.y) continue;
const [top, bottom] = p1.y > p2.y ? [p1, p2] : [p2, p1];
if (scanZ >= bottom.y && scanZ < top.y) {
const t = (scanZ - bottom.y) / (top.y - bottom.y);
const x = bottom.x + t * (top.x - bottom.x);
intersections.push(x);
}
}
intersections.sort((a, b) => a - b);
if (intersections.length >= 2) {
const x = (intersections[0] + intersections[1]) / 2;
return new Vector2(x, scanZ);
}
let x = 0,
z = 0;
for (const p of points) {
x += p.x;
z += p.y;
}
x /= points.length;
z /= points.length;
return new Vector2(x, z);
}

View File

@@ -1,106 +0,0 @@
import { useRoomsState, useToggleView } from "../../../store/builder/store";
import { computeArea } from "../functions/computeArea";
import { Html } from "@react-three/drei";
import * as CONSTANTS from "../../../types/world/worldConstants";
import * as turf from "@turf/turf";
import * as THREE from "three";
const CalculateAreaGroup = () => {
const { roomsState } = useRoomsState();
const { toggleView } = useToggleView();
const savedTheme: string | null = localStorage.getItem("theme");
return (
<group name="roomArea" visible={toggleView}>
<group name="roomFills" visible={toggleView}>
{roomsState.length > 0 &&
roomsState.flat().map((room: any, index: number) => {
const coordinates = room.coordinates;
if (!coordinates || coordinates.length < 3) return null;
const coords2D = coordinates.map((p: any) => new THREE.Vector2(p.position.x, p.position.z));
if (!coords2D[0].equals(coords2D[coords2D.length - 1])) {
coords2D.push(coords2D[0]);
}
const shape = new THREE.Shape(coords2D);
const extrudeSettings = {
depth: 0.01,
bevelEnabled: false,
};
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
geometry.rotateX(Math.PI / 2);
const material = new THREE.MeshBasicMaterial({
color: savedTheme === "dark" ? "#d2baff" : "#6f42c1",
side: THREE.DoubleSide,
transparent: true,
opacity: 0.4,
depthWrite: false,
});
return (
<group key={`roomFill-${index}`}>
<mesh
geometry={geometry}
material={material}
position={[0, 0.12, 0]}
/>
</group>
);
})}
</group>
{roomsState.length > 0 &&
roomsState.flat().map((room: any, index: number) => {
if (!toggleView) return null;
const coordinates = room.coordinates;
if (!coordinates || coordinates.length < 3) return null;
let coords2D = coordinates.map((p: any) => [p.position.x, p.position.z,]);
const first = coords2D[0];
const last = coords2D[coords2D.length - 1];
if (first[0] !== last[0] || first[1] !== last[1]) {
coords2D.push(first);
}
const polygon = turf.polygon([coords2D]);
const center2D = turf.center(polygon).geometry.coordinates;
const sumY = coordinates.reduce((sum: number, p: any) => sum + p.position.y, 0);
const avgY = sumY / coordinates.length;
const area = computeArea(room, "rooms");
const formattedArea = `${area.toFixed(2)}`;
const htmlPosition: [number, number, number] = [
center2D[0],
avgY + CONSTANTS.zoneConfig.height,
center2D[1],
];
return (
<Html
key={`${index}-${room.layer || index}`}
position={htmlPosition}
wrapperClass="distance-text-wrapper"
className="distance-text"
zIndexRange={[1, 0]}
prepend
center
sprite
>
<div className={`distance area line-${room.layer || index}`}>
Room ({formattedArea})
</div>
</Html>
);
})}
</group>
);
};
export default CalculateAreaGroup;

View File

@@ -1,19 +1,21 @@
import React, { useEffect, useMemo } from 'react';
import { DoubleSide, RepeatWrapping, Shape, SRGBColorSpace, TextureLoader, Vector2, Vector3 } from 'three';
import { Html, Extrude } from '@react-three/drei';
import { useLoader } from '@react-three/fiber';
import { useBuilderStore } from '../../../../store/builder/useBuilderStore';
import { useSceneContext } from '../../../scene/sceneContext';
import { useToggleView, useToolMode } 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';
import * as Constants from '../../../../types/world/worldConstants';
import React, { useEffect, useMemo } from "react";
import { DoubleSide, RepeatWrapping, Shape, SRGBColorSpace, TextureLoader, Vector2, Vector3 } from "three";
import { Html, Extrude } from "@react-three/drei";
import { useLoader } from "@react-three/fiber";
import { useBuilderStore } from "../../../../store/builder/useBuilderStore";
import { useSceneContext } from "../../../scene/sceneContext";
import { useToggleView, useToolMode } 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";
import * as Constants from "../../../../types/world/worldConstants";
import texturePath from "../../../../assets/textures/floor/white.png";
import texturePathDark from "../../../../assets/textures/floor/black.png";
import useModuleStore from '../../../../store/ui/useModuleStore';
import useModuleStore from "../../../../store/ui/useModuleStore";
import getCenteroidPoint from "../../functions/getCenteroid";
import getArea from "../../functions/getArea";
function WallInstances() {
const { wallStore } = useSceneContext();
@@ -26,11 +28,11 @@ function WallInstances() {
useEffect(() => {
// console.log('walls: ', walls);
}, [walls])
}, [walls]);
useEffect(() => {
if (!toggleView && activeModule === 'builder') {
if (toolMode !== 'cursor') {
if (!toggleView && activeModule === "builder") {
if (toolMode !== "cursor") {
if (selectedWall) setSelectedWall(null);
}
} else {
@@ -42,8 +44,8 @@ function WallInstances() {
const points: Point[] = [];
const seenUuids = new Set<string>();
walls.forEach(wall => {
wall.points.forEach(point => {
walls.forEach((wall) => {
wall.points.forEach((point) => {
if (!seenUuids.has(point.pointUuid)) {
seenUuids.add(point.pointUuid);
points.push(point);
@@ -62,9 +64,9 @@ function WallInstances() {
<WallInstance key={wall.wallUuid} wall={wall} />
))}
<group name='Wall-Floors-Group'>
<group name="Wall-Floors-Group">
{rooms.map((room, index) => (
<Floor key={index} room={room} />
<Floor3D key={index} room={room} />
))}
</group>
</>
@@ -72,14 +74,19 @@ function WallInstances() {
{toggleView && (
<>
<group name='Wall-Points-Group'>
<group name="Wall-Points-Group">
{allPoints.map((point) => (
<Point key={point.pointUuid} point={point} />
))}
</group>
<group name='Wall-Lines-Group'>
<group name="Wall-Floors-Group">
{rooms.map((room, index) => (
<Floor2D key={index} room={room} />
))}
</group>
<group name="Wall-Lines-Group">
{walls.map((wall) => (
<React.Fragment key={wall.wallUuid}>
<Line points={wall.points} />
@@ -91,8 +98,8 @@ function WallInstances() {
const distance = new Vector3(...wall.points[0].position).distanceTo(new Vector3(...wall.points[1].position));
return (
< React.Fragment key={wall.wallUuid}>
{toggleView &&
<React.Fragment key={wall.wallUuid}>
{toggleView && (
<Html
key={`${wall.points[0].pointUuid}_${wall.points[1].pointUuid}`}
userData={wall}
@@ -103,29 +110,25 @@ function WallInstances() {
prepend
sprite
>
<div
key={wall.wallUuid}
className={`distance ${wall.wallUuid}`}
>
<div key={wall.wallUuid} className={`distance ${wall.wallUuid}`}>
{distance.toFixed(2)} m
</div>
</Html>
}
)}
</React.Fragment>
)
);
})}
</group>
</>
)}
</>
)
);
}
export default WallInstances;
function Floor({ room }: { readonly room: Point[] }) {
const savedTheme: string | null = localStorage.getItem('theme');
function Floor3D({ room }: { readonly room: Point[] }) {
const savedTheme: string | null = localStorage.getItem("theme");
const textureScale = Constants.floorConfig.textureScale;
const floorTexture = useLoader(TextureLoader, savedTheme === "dark" ? texturePathDark : texturePath);
floorTexture.wrapS = floorTexture.wrapT = RepeatWrapping;
@@ -134,10 +137,12 @@ function Floor({ room }: { readonly room: Point[] }) {
const shape = useMemo(() => {
const shape = new Shape();
const points = room.map(p => new Vector2(p.position[0], p.position[2]));
const points = room.map((p) => new Vector2(p.position[0], p.position[2]));
if (points.length < 3) return null;
shape.moveTo(points[0].x, points[0].y);
points.forEach((pt) => { shape.lineTo(pt.x, pt.y); });
points.forEach((pt) => {
shape.lineTo(pt.x, pt.y);
});
return shape;
}, [room]);
@@ -145,15 +150,54 @@ function Floor({ room }: { readonly room: Point[] }) {
return (
<mesh name="Wall-Floor" rotation={[Math.PI / 2, 0, 0]}>
<Extrude
receiveShadow
castShadow
name="Wall-Floor"
args={[shape, { depth: Constants.floorConfig.height, bevelEnabled: false }]}
position={[0, 0, 0]}
>
<Extrude receiveShadow castShadow name="Wall-Floor" args={[shape, { depth: Constants.floorConfig.height, bevelEnabled: false }]} position={[0, 0, 0]}>
<meshStandardMaterial color={Constants.floorConfig.defaultColor} map={floorTexture} side={DoubleSide} />
</Extrude>
</mesh>
);
}
function Floor2D({ room }: { readonly room: Point[] }) {
const savedTheme: string | null = localStorage.getItem("theme");
const points2D = useMemo(() => {
return room.map((p) => new Vector2(parseFloat(p.position[0].toFixed(2)), parseFloat(p.position[2].toFixed(2))));
}, [room]);
const shape = useMemo(() => {
const shape = new Shape();
shape.moveTo(points2D[0].x, points2D[0].y);
for (let i = 1; i < points2D.length; i++) {
shape.lineTo(points2D[i].x, points2D[i].y);
}
shape.lineTo(points2D[0].x, points2D[0].y);
return shape;
}, [points2D]);
const area = useMemo(() => getArea(points2D), [points2D]);
const centroid: [number, number, number] = useMemo(() => {
const center = getCenteroidPoint(points2D);
if (!center) return [0, Constants.floorConfig.height + 0.01, 0];
return [center.x, Constants.floorConfig.height + 0.01, center.y] as [number, number, number];
}, [points2D]);
if (!shape) return null;
const formattedArea = `${area.toFixed(2)}`;
return (
<>
<mesh castShadow receiveShadow name="Wall-Floor" rotation={[Math.PI / 2, 0, 0]}>
<Extrude receiveShadow castShadow name="Wall-Floor" args={[shape, { depth: Constants.floorConfig.height }]} position={[0, 0, 0]}>
<meshBasicMaterial color={savedTheme === "dark" ? Constants.lineConfig.wallColor : Constants.lineConfig.wallColor} side={DoubleSide} transparent opacity={0.4} depthWrite={false} />
</Extrude>
</mesh>
<Html position={centroid} wrapperClass="distance-text-wrapper" className="distance-text" zIndexRange={[1, 0]} prepend center sprite>
<div className="distance area">({formattedArea})</div>
</Html>
</>
);
}

View File

@@ -1,50 +1,55 @@
import { useMemo } from 'react';
import { DoubleSide, Shape, Vector2 } from 'three';
import { Extrude } from '@react-three/drei';
import * as Constants from '../../../../../types/world/worldConstants';
import { useMemo } from "react";
import { DoubleSide, Shape, Vector2 } from "three";
import { Extrude, Html } from "@react-three/drei";
import * as Constants from "../../../../../types/world/worldConstants";
import getCenteroid from "../../../functions/getCenteroid";
import getArea from "../../../functions/getArea";
function Zone2DInstance({ zone }: { readonly zone: Zone }) {
const savedTheme: string | null = localStorage.getItem("theme");
const points2D = useMemo(() => {
return zone.points.map((p) => new Vector2(parseFloat(p.position[0].toFixed(2)), parseFloat(p.position[2].toFixed(2))));
}, [zone]);
const shape = useMemo(() => {
const shape = new Shape();
const points = zone.points.map(p => new Vector2(p.position[0], p.position[2]));
if (points.length < 3) return null;
shape.moveTo(points[0].x, points[0].y);
for (let i = 1; i < points.length; i++) {
shape.lineTo(points[i].x, points[i].y);
shape.moveTo(points2D[0].x, points2D[0].y);
for (let i = 1; i < points2D.length; i++) {
shape.lineTo(points2D[i].x, points2D[i].y);
}
shape.lineTo(points2D[0].x, points2D[0].y);
return shape;
}, [zone]);
}, [points2D]);
const area = useMemo(() => getArea(points2D), [points2D]);
const centroid: [number, number, number] = useMemo(() => {
const center = getCenteroid(points2D);
if (!center) return [0, Constants.floorConfig.height + 0.01, 0];
return [center.x, Constants.floorConfig.height + 0.01, center.y] as [number, number, number];
}, [points2D]);
if (!shape) return null;
const formattedArea = `${area.toFixed(2)}`;
return (
<mesh
castShadow
receiveShadow
name={`Zone-2D-${zone.zoneUuid}`}
rotation={[Math.PI / 2, 0, 0]}
position={[0, 0, 0]}
userData={zone}
>
<Extrude
name={`Zone-${zone.zoneUuid}`}
args={[shape, {
depth: Constants.floorConfig.height,
}]}
userData={zone}
>
<meshBasicMaterial
color={savedTheme === "dark" ? "#007BFF" : "#007BFF"}
side={DoubleSide}
transparent
opacity={0.4}
depthWrite={false}
/>
</Extrude>
</mesh>
<>
<mesh castShadow receiveShadow name={`Zone-2D-${zone.zoneUuid}`} rotation={[Math.PI / 2, 0, 0]} position={[0, 0, 0]} userData={zone}>
<Extrude name={`Zone-${zone.zoneUuid}`} args={[shape, { depth: Constants.floorConfig.height }]} userData={zone}>
<meshBasicMaterial color={savedTheme === "dark" ? Constants.lineConfig.zoneColor : Constants.lineConfig.zoneColor} side={DoubleSide} transparent opacity={0.4} depthWrite={false} />
</Extrude>
</mesh>
<Html key={zone.zoneUuid} position={centroid} wrapperClass="distance-text-wrapper" className="distance-text" zIndexRange={[1, 0]} prepend center sprite>
<div className="distance area">
{zone.zoneName} ({formattedArea})
</div>
</Html>
</>
);
}
export default Zone2DInstance;
export default Zone2DInstance;

View File

@@ -1,12 +1,12 @@
import React, { useEffect, useMemo } from 'react';
import { Vector3 } from 'three';
import { Html } from '@react-three/drei';
import { useSceneContext } from '../../../scene/sceneContext';
import { useToggleView } from '../../../../store/builder/store';
import Line from '../../line/line';
import Point from '../../point/point';
import ZoneInstance from './Instance/zoneInstance';
import Zone2DInstance from './Instance/zone2DInstance';
import React, { useEffect, useMemo } from "react";
import { Vector3 } from "three";
import { Html } from "@react-three/drei";
import { useSceneContext } from "../../../scene/sceneContext";
import { useToggleView } from "../../../../store/builder/store";
import Line from "../../line/line";
import Point from "../../point/point";
import ZoneInstance from "./Instance/zoneInstance";
import Zone2DInstance from "./Instance/zone2DInstance";
function ZoneInstances() {
const { zoneStore } = useSceneContext();
@@ -15,14 +15,14 @@ function ZoneInstances() {
useEffect(() => {
// console.log('zones: ', zones);
}, [zones])
}, [zones]);
const allPoints = useMemo(() => {
const points: Point[] = [];
const seenUuids = new Set<string>();
zones.forEach(zone => {
zone.points.forEach(point => {
zones.forEach((zone) => {
zone.points.forEach((point) => {
if (!seenUuids.has(point.pointUuid)) {
seenUuids.add(point.pointUuid);
points.push(point);
@@ -50,7 +50,7 @@ function ZoneInstances() {
lines.push({
start: current,
end: next,
key: lineKey
key: lineKey,
});
}
}
@@ -61,9 +61,8 @@ function ZoneInstances() {
return (
<>
{!toggleView && zones.length > 0 && (
<mesh name='Zones-Group'>
<mesh name="Zones-Group">
{zones.map((zone) => (
<ZoneInstance key={zone.zoneUuid} zone={zone} />
))}
@@ -71,7 +70,7 @@ function ZoneInstances() {
)}
{toggleView && zones.length > 0 && (
<mesh name='Zones-2D-Group'>
<mesh name="Zones-2D-Group">
{zones.map((zone) => (
<Zone2DInstance key={zone.zoneUuid} zone={zone} />
))}
@@ -80,14 +79,13 @@ function ZoneInstances() {
{toggleView && (
<>
<group name='Zone-Points-Group'>
<group name="Zone-Points-Group">
{allPoints.map((point) => (
<Point key={point.pointUuid} point={point} />
))}
</group>
<group name='Zone-Lines-Group'>
<group name="Zone-Lines-Group">
{allLines.map(({ start, end, key }) => (
<Line key={key} points={[start, end]} />
))}
@@ -99,7 +97,7 @@ function ZoneInstances() {
return (
<React.Fragment key={key}>
{toggleView &&
{toggleView && (
<Html
key={`${start.pointUuid}_${end.pointUuid}`}
userData={line}
@@ -110,23 +108,19 @@ function ZoneInstances() {
prepend
sprite
>
<div
key={key}
className={`distance ${key}`}
>
<div key={key} className={`distance ${key}`}>
{distance.toFixed(2)} m
</div>
</Html>
}
)}
</React.Fragment>
)
);
})}
</group>
</>
)}
</>
)
);
}
export default ZoneInstances
export default ZoneInstances;

View File

@@ -71,11 +71,6 @@ export const useToggleView = create<any>((set: any) => ({
setToggleView: (x: any) => set(() => ({ toggleView: x })),
}));
export const useRoomsState = create<any>((set: any) => ({
roomsState: [],
setRoomsState: (x: any) => set(() => ({ roomsState: x })),
}));
export const useSelectedItem = create<any>((set: any) => ({
selectedItem: {
name: "",
@@ -315,11 +310,6 @@ export const useTileDistance = create<any>((set: any) => ({
})),
}));
export const usePlayAgv = create<any>((set, get) => ({
PlayAgv: [],
setPlayAgv: (updateFn: (prev: any[]) => any[]) => set({ PlayAgv: updateFn(get().PlayAgv) }),
}));
// Define the Asset type
type Asset = {
id: string;
@@ -350,19 +340,6 @@ export const useResourceManagementId = create<ResourceManagementState>((set) =>
setResourceManagementId: (id: string) => set({ resourceManagementId: id }),
}));
// version visible hidden
interface VersionHistoryState {
viewVersionHistory: boolean;
setVersionHistoryVisible: (value: boolean) => void;
}
const useVersionHistoryVisibleStore = create<VersionHistoryState>((set) => ({
viewVersionHistory: false,
setVersionHistoryVisible: (value) => set({ viewVersionHistory: value }),
}));
export default useVersionHistoryVisibleStore;
interface ShortcutStore {
showShortcuts: boolean;
setShowShortcuts: (value: boolean) => void;

View File

@@ -1,14 +1,16 @@
import { create } from 'zustand';
import { immer } from 'zustand/middleware/immer';
import { create } from "zustand";
import { immer } from "zustand/middleware/immer";
interface VersionStore {
versionHistory: VersionHistory;
selectedVersion: Version | null;
viewVersionHistory: boolean;
createNewVersion: boolean;
setSelectedVersion: (version: Version) => void;
clearSelectedVersion: () => void;
setVersionHistoryVisible: (visibility: boolean) => void;
setCreateNewVersion: (createNewVersion: boolean) => void;
addVersion: (version: Version) => void;
@@ -26,6 +28,7 @@ export const createVersionStore = () => {
immer((set, get) => ({
versionHistory: [],
selectedVersion: null,
viewVersionHistory: false,
createNewVersion: false,
setSelectedVersion: (version) => {
@@ -40,30 +43,36 @@ export const createVersionStore = () => {
});
},
setVersionHistoryVisible: (visibility: boolean) => {
set((state) => {
state.viewVersionHistory = visibility;
});
},
setCreateNewVersion: (createNewVersion: boolean) => {
set((state) => {
state.createNewVersion = createNewVersion;
})
});
},
addVersion: (version: Version) => {
set((state) => {
state.versionHistory.unshift(version);
})
});
},
setVersions: (versions: Version[]) => {
set((state) => {
state.versionHistory = versions;
})
});
},
clearVersions: () => {
set((state) => {
state.versionHistory = [];
state.selectedVersion = null;
state.createNewVersion = false
})
state.createNewVersion = false;
});
},
setVersionName: (versionId: string, versionName: string) => {
@@ -72,7 +81,7 @@ export const createVersionStore = () => {
if (version) {
version.versionName = versionName;
}
})
});
},
updateVersion: (versionId: string, versionName: string, versionDescription: string) => {
@@ -82,16 +91,16 @@ export const createVersionStore = () => {
version.versionName = versionName;
version.versionDescription = versionDescription;
}
})
});
},
getVersionById: (versionId: string) => {
return get().versionHistory.find((v) => {
return v.versionId === versionId
})
}
return v.versionId === versionId;
});
},
}))
);
};
export type VersionStoreType = ReturnType<typeof createVersionStore>;
export type VersionStoreType = ReturnType<typeof createVersionStore>;

View File

@@ -202,7 +202,7 @@ export const firstPersonControls: Controls = {
leftSpeed: -0.1, // Speed of left movement
rightSpeed: 0.1, // Speed of right movement
walkSpeed: 1, // Walk speed
sprintSpeed: 4 // Sprint Speed
sprintSpeed: 4, // Sprint Speed
};
export const thirdPersonControls: ThirdPersonControls = {
@@ -359,7 +359,7 @@ export const roofConfig: RoofConfig = {
export const aisleConfig: AisleConfig = {
width: 0.1, // Width of the aisles
height: 0.01, // Height of the aisles
defaultColor: '#E2AC09', // Default color of the aisles
defaultColor: "#E2AC09", // Default color of the aisles
};
export const zoneConfig: ZoneConfig = {
@@ -384,4 +384,4 @@ export const distanceConfig: DistanceConfig = {
export const undoRedoConfig: undoRedoCount = {
undoRedoCount: 50,
}
};

View File

@@ -1,7 +1,19 @@
import React, { useEffect } from "react";
import useModuleStore, { useSubModuleStore, useThreeDStore } from "../../store/ui/useModuleStore";
import { usePlayerStore, useToggleStore } from "../../store/ui/useUIToggleStore";
import useVersionHistoryVisibleStore, { useActiveSubTool, useActiveTool, useAddAction, useDfxUpload, useRenameModeStore, useIsComparing, useSelectedComment, useShortcutStore, useToggleView, useToolMode, useViewSceneStore } from "../../store/builder/store";
import {
useActiveSubTool,
useActiveTool,
useAddAction,
useDfxUpload,
useRenameModeStore,
useIsComparing,
useSelectedComment,
useShortcutStore,
useToggleView,
useToolMode,
useViewSceneStore,
} from "../../store/builder/store";
import useCameraModeStore, { usePlayButtonStore } from "../../store/ui/usePlayButtonStore";
import { detectModifierKeys } from "./detectModifierKeys";
import { useSelectedZoneStore } from "../../store/visualization/useZoneStore";
@@ -33,8 +45,7 @@ const KeyPressListener: React.FC = () => {
const { setViewSceneLabels } = useViewSceneStore();
const { isRenameMode, setIsRenameMode } = useRenameModeStore();
const { selectedFloorAsset, setSelectedWallAsset } = useBuilderStore();
const { setCreateNewVersion } = versionStore();
const { setVersionHistoryVisible } = useVersionHistoryVisibleStore();
const { setCreateNewVersion, setVersionHistoryVisible } = versionStore();
const { setSelectedComment } = useSelectedComment();
const { setDfxUploaded } = useDfxUpload();
const isTextInput = (element: Element | null): boolean => element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element?.getAttribute("contenteditable") === "true";