Merge branch 'main' into simulation
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
import React from "react";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import App from "./app";
|
||||
|
||||
test("renders learn react link", () => {
|
||||
render(<App />);
|
||||
const linkElement = screen.getByText(/learn react/i);
|
||||
expect(linkElement).toBeInTheDocument();
|
||||
});
|
||||
import React from "react";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import App from "./app";
|
||||
|
||||
test("renders learn react link", () => {
|
||||
render(<App />);
|
||||
const linkElement = screen.getByText(/learn react/i);
|
||||
expect(linkElement).toBeInTheDocument();
|
||||
});
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
import React from "react";
|
||||
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
|
||||
import Dashboard from "./pages/Dashboard";
|
||||
import Project from "./pages/Project";
|
||||
import UserAuth from "./pages/UserAuth";
|
||||
import ToastProvider from "./components/templates/ToastProvider";
|
||||
import "./styles/main.scss"
|
||||
|
||||
const App: React.FC = () => {
|
||||
return (
|
||||
<ToastProvider>
|
||||
<Router>
|
||||
<Routes>
|
||||
<Route
|
||||
path="/"
|
||||
element={<UserAuth />}
|
||||
/>
|
||||
<Route path="/dashboard" element={<Dashboard />} />
|
||||
<Route path="/project" element={<Project />} />
|
||||
</Routes>
|
||||
</Router>
|
||||
</ToastProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
import React from "react";
|
||||
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
|
||||
import Dashboard from "./pages/Dashboard";
|
||||
import Project from "./pages/Project";
|
||||
import UserAuth from "./pages/UserAuth";
|
||||
import ToastProvider from "./components/templates/ToastProvider";
|
||||
import "./styles/main.scss"
|
||||
|
||||
const App: React.FC = () => {
|
||||
return (
|
||||
<ToastProvider>
|
||||
<Router>
|
||||
<Routes>
|
||||
<Route
|
||||
path="/"
|
||||
element={<UserAuth />}
|
||||
/>
|
||||
<Route path="/dashboard" element={<Dashboard />} />
|
||||
<Route path="/project" element={<Project />} />
|
||||
</Routes>
|
||||
</Router>
|
||||
</ToastProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,160 +1,160 @@
|
||||
export function CleanPannel() {
|
||||
return (
|
||||
<svg
|
||||
width="12"
|
||||
height="12"
|
||||
viewBox="0 0 12 12"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g clipPath="url(#clip0_1782_1158)">
|
||||
<path d="M12 0H0V12H12V0Z" fill="white" fillOpacity="0.01" />
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M5 1.47852H7V3.47853H10.75V5.47853H1.25V3.47853H5V1.47852Z"
|
||||
stroke="#2B3344"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path d="M2 10H10V5.5H2V10Z" stroke="#2B3344" strokeLinejoin="round" />
|
||||
<path
|
||||
d="M4 9.97439V8.47852"
|
||||
stroke="#2B3344"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M6 9.97461V8.47461"
|
||||
stroke="#2B3344"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M8 9.97439V8.47852"
|
||||
stroke="#2B3344"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M3 10H9"
|
||||
stroke="#2B3344"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_1782_1158">
|
||||
<rect width="12" height="12" fill="white" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export function EyeIcon({ fill }: { fill?: string }) {
|
||||
return (
|
||||
<svg
|
||||
width="14"
|
||||
height="15"
|
||||
viewBox="0 0 14 15"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M8.75047 7.4375C8.75047 8.40402 7.967 9.1875 7.00047 9.1875C6.034 9.1875 5.25049 8.40402 5.25049 7.4375C5.25049 6.47097 6.034 5.6875 7.00047 5.6875C7.967 5.6875 8.75047 6.47097 8.75047 7.4375Z"
|
||||
stroke={fill}
|
||||
strokeOpacity="1"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M7.00086 3.35419C4.3889 3.35419 2.1779 5.07087 1.43457 7.43752C2.17789 9.80416 4.3889 11.5209 7.00086 11.5209C9.6128 11.5209 11.8238 9.80416 12.5671 7.43752C11.8238 5.07088 9.6128 3.35419 7.00086 3.35419Z"
|
||||
stroke={fill}
|
||||
strokeOpacity="1"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export function LockIcon({ fill }: { fill?: string }) {
|
||||
return (
|
||||
<svg
|
||||
width="14"
|
||||
height="15"
|
||||
viewBox="0 0 14 15"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M4.0835 6.28763C4.35849 6.27083 4.69751 6.27083 5.1335 6.27083H8.86683C9.30281 6.27083 9.64185 6.27083 9.91683 6.28763M4.0835 6.28763C3.74031 6.30857 3.49683 6.35571 3.28901 6.46158C2.95973 6.62935 2.69201 6.89704 2.52423 7.22633C2.3335 7.60072 2.3335 8.09072 2.3335 9.07083V9.8875C2.3335 10.8676 2.3335 11.3576 2.52423 11.732C2.69201 12.0613 2.95973 12.329 3.28901 12.4967C3.66336 12.6875 4.1534 12.6875 5.1335 12.6875H8.86683C9.84695 12.6875 10.3369 12.6875 10.7113 12.4967C11.0406 12.329 11.3083 12.0613 11.4761 11.732C11.6668 11.3576 11.6668 10.8676 11.6668 9.8875V9.07083C11.6668 8.09072 11.6668 7.60072 11.4761 7.22633C11.3083 6.89704 11.0406 6.62935 10.7113 6.46158C10.5035 6.35571 10.26 6.30857 9.91683 6.28763M4.0835 6.28763V5.10417C4.0835 3.49334 5.38933 2.1875 7.00016 2.1875C8.61098 2.1875 9.91683 3.49334 9.91683 5.10417V6.28763"
|
||||
stroke={fill}
|
||||
strokeOpacity="1"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
export function StockIncreseIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="9"
|
||||
height="9"
|
||||
viewBox="0 0 9 9"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g clip-path="url(#clip0_3050_69519)">
|
||||
<path
|
||||
d="M7.80766 6.99219H1.17811C0.752382 6.99219 0.407227 7.33734 0.407227 7.76307C0.407227 8.18879 0.752382 8.53395 1.17811 8.53395H7.80766C8.23339 8.53395 8.57854 8.18879 8.57854 7.76307C8.57854 7.33733 8.23339 6.99219 7.80766 6.99219Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M2.05066 6.50215C2.47639 6.50215 2.82154 6.15699 2.82154 5.73127V2.7865C2.82154 2.36078 2.47639 2.01562 2.05066 2.01562C1.62494 2.01562 1.27979 2.36078 1.27979 2.7865V5.73127C1.27977 6.15699 1.62494 6.50215 2.05066 6.50215Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M4.49598 6.49421C4.9217 6.49421 5.26686 6.14905 5.26686 5.72333V1.80213C5.26686 1.37641 4.9217 1.03125 4.49598 1.03125C4.07025 1.03125 3.7251 1.37641 3.7251 1.80213V5.72333C3.7251 6.14905 4.07023 6.49421 4.49598 6.49421Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M6.92957 6.50192C7.35529 6.50192 7.70042 6.15677 7.70042 5.73104V0.83338C7.70046 0.407655 7.35532 0.0625 6.92957 0.0625C6.50385 0.0625 6.15869 0.407655 6.15869 0.83338V5.73103C6.15869 6.15677 6.50385 6.50192 6.92957 6.50192Z"
|
||||
fill="white"
|
||||
/>
|
||||
</g>
|
||||
<rect
|
||||
x="0.27293"
|
||||
y="0.066387"
|
||||
width="8.45313"
|
||||
height="8.45313"
|
||||
stroke="url(#paint0_linear_3050_69519)"
|
||||
strokeWidth="0.0233989"
|
||||
/>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id="paint0_linear_3050_69519"
|
||||
x1="4.4995"
|
||||
y1="0.0546875"
|
||||
x2="4.4995"
|
||||
y2="8.53122"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#31B2B9" />
|
||||
<stop offset="1" stop-color="#FBD8B8" />
|
||||
</linearGradient>
|
||||
<clipPath id="clip0_3050_69519">
|
||||
<rect
|
||||
x="0.26123"
|
||||
y="0.0546875"
|
||||
width="8.47653"
|
||||
height="8.47653"
|
||||
fill="white"
|
||||
/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
export function CleanPannel() {
|
||||
return (
|
||||
<svg
|
||||
width="12"
|
||||
height="12"
|
||||
viewBox="0 0 12 12"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g clipPath="url(#clip0_1782_1158)">
|
||||
<path d="M12 0H0V12H12V0Z" fill="white" fillOpacity="0.01" />
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M5 1.47852H7V3.47853H10.75V5.47853H1.25V3.47853H5V1.47852Z"
|
||||
stroke="#2B3344"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path d="M2 10H10V5.5H2V10Z" stroke="#2B3344" strokeLinejoin="round" />
|
||||
<path
|
||||
d="M4 9.97439V8.47852"
|
||||
stroke="#2B3344"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M6 9.97461V8.47461"
|
||||
stroke="#2B3344"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M8 9.97439V8.47852"
|
||||
stroke="#2B3344"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M3 10H9"
|
||||
stroke="#2B3344"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_1782_1158">
|
||||
<rect width="12" height="12" fill="white" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export function EyeIcon({ fill }: { fill?: string }) {
|
||||
return (
|
||||
<svg
|
||||
width="14"
|
||||
height="15"
|
||||
viewBox="0 0 14 15"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M8.75047 7.4375C8.75047 8.40402 7.967 9.1875 7.00047 9.1875C6.034 9.1875 5.25049 8.40402 5.25049 7.4375C5.25049 6.47097 6.034 5.6875 7.00047 5.6875C7.967 5.6875 8.75047 6.47097 8.75047 7.4375Z"
|
||||
stroke={fill}
|
||||
strokeOpacity="1"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M7.00086 3.35419C4.3889 3.35419 2.1779 5.07087 1.43457 7.43752C2.17789 9.80416 4.3889 11.5209 7.00086 11.5209C9.6128 11.5209 11.8238 9.80416 12.5671 7.43752C11.8238 5.07088 9.6128 3.35419 7.00086 3.35419Z"
|
||||
stroke={fill}
|
||||
strokeOpacity="1"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export function LockIcon({ fill }: { fill?: string }) {
|
||||
return (
|
||||
<svg
|
||||
width="14"
|
||||
height="15"
|
||||
viewBox="0 0 14 15"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M4.0835 6.28763C4.35849 6.27083 4.69751 6.27083 5.1335 6.27083H8.86683C9.30281 6.27083 9.64185 6.27083 9.91683 6.28763M4.0835 6.28763C3.74031 6.30857 3.49683 6.35571 3.28901 6.46158C2.95973 6.62935 2.69201 6.89704 2.52423 7.22633C2.3335 7.60072 2.3335 8.09072 2.3335 9.07083V9.8875C2.3335 10.8676 2.3335 11.3576 2.52423 11.732C2.69201 12.0613 2.95973 12.329 3.28901 12.4967C3.66336 12.6875 4.1534 12.6875 5.1335 12.6875H8.86683C9.84695 12.6875 10.3369 12.6875 10.7113 12.4967C11.0406 12.329 11.3083 12.0613 11.4761 11.732C11.6668 11.3576 11.6668 10.8676 11.6668 9.8875V9.07083C11.6668 8.09072 11.6668 7.60072 11.4761 7.22633C11.3083 6.89704 11.0406 6.62935 10.7113 6.46158C10.5035 6.35571 10.26 6.30857 9.91683 6.28763M4.0835 6.28763V5.10417C4.0835 3.49334 5.38933 2.1875 7.00016 2.1875C8.61098 2.1875 9.91683 3.49334 9.91683 5.10417V6.28763"
|
||||
stroke={fill}
|
||||
strokeOpacity="1"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
export function StockIncreseIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="9"
|
||||
height="9"
|
||||
viewBox="0 0 9 9"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g clipPath="url(#clip0_3050_69519)">
|
||||
<path
|
||||
d="M7.80766 6.99219H1.17811C0.752382 6.99219 0.407227 7.33734 0.407227 7.76307C0.407227 8.18879 0.752382 8.53395 1.17811 8.53395H7.80766C8.23339 8.53395 8.57854 8.18879 8.57854 7.76307C8.57854 7.33733 8.23339 6.99219 7.80766 6.99219Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M2.05066 6.50215C2.47639 6.50215 2.82154 6.15699 2.82154 5.73127V2.7865C2.82154 2.36078 2.47639 2.01562 2.05066 2.01562C1.62494 2.01562 1.27979 2.36078 1.27979 2.7865V5.73127C1.27977 6.15699 1.62494 6.50215 2.05066 6.50215Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M4.49598 6.49421C4.9217 6.49421 5.26686 6.14905 5.26686 5.72333V1.80213C5.26686 1.37641 4.9217 1.03125 4.49598 1.03125C4.07025 1.03125 3.7251 1.37641 3.7251 1.80213V5.72333C3.7251 6.14905 4.07023 6.49421 4.49598 6.49421Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M6.92957 6.50192C7.35529 6.50192 7.70042 6.15677 7.70042 5.73104V0.83338C7.70046 0.407655 7.35532 0.0625 6.92957 0.0625C6.50385 0.0625 6.15869 0.407655 6.15869 0.83338V5.73103C6.15869 6.15677 6.50385 6.50192 6.92957 6.50192Z"
|
||||
fill="white"
|
||||
/>
|
||||
</g>
|
||||
<rect
|
||||
x="0.27293"
|
||||
y="0.066387"
|
||||
width="8.45313"
|
||||
height="8.45313"
|
||||
stroke="url(#paint0_linear_3050_69519)"
|
||||
strokeWidth="0.0233989"
|
||||
/>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id="paint0_linear_3050_69519"
|
||||
x1="4.4995"
|
||||
y1="0.0546875"
|
||||
x2="4.4995"
|
||||
y2="8.53122"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopColor="#31B2B9" />
|
||||
<stop offset="1" stopColor="#FBD8B8" />
|
||||
</linearGradient>
|
||||
<clipPath id="clip0_3050_69519">
|
||||
<rect
|
||||
x="0.26123"
|
||||
y="0.0546875"
|
||||
width="8.47653"
|
||||
height="8.47653"
|
||||
fill="white"
|
||||
/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,9 +3,12 @@ import { ToggleSidebarIcon } from "../../icons/HeaderIcons";
|
||||
import { LogoIcon } from "../../icons/Logo";
|
||||
import FileMenu from "../../ui/FileMenu";
|
||||
import useToggleStore from "../../../store/useUIToggleStore";
|
||||
import useModuleStore from "../../../store/useModuleStore";
|
||||
|
||||
const Header: React.FC = () => {
|
||||
const { toggleUI, setToggleUI } = useToggleStore();
|
||||
const { activeModule } = useModuleStore();
|
||||
|
||||
return (
|
||||
<div className="header-container">
|
||||
<div className="header-content">
|
||||
@@ -19,7 +22,7 @@ const Header: React.FC = () => {
|
||||
<div
|
||||
className={`toggle-sidebar-ui-button ${!toggleUI ? "active" : ""}`}
|
||||
onClick={() => {
|
||||
setToggleUI(!toggleUI);
|
||||
if (activeModule !== "market") setToggleUI(!toggleUI);
|
||||
}}
|
||||
>
|
||||
<ToggleSidebarIcon />
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import Header from "./Header";
|
||||
import useModuleStore, { useSubModuleStore } from "../../../store/useModuleStore";
|
||||
import useModuleStore, {
|
||||
useSubModuleStore,
|
||||
} from "../../../store/useModuleStore";
|
||||
import {
|
||||
AnalysisIcon,
|
||||
MechanicsIcon,
|
||||
@@ -15,6 +17,7 @@ import AsstePropertiies from "./properties/AssetProperties";
|
||||
import Analysis from "./analysis/Analysis";
|
||||
import Simulations from "./simulation/Simulations";
|
||||
import { useSelectedActionSphere } from "../../../store/store";
|
||||
import ZoneProperties from "./properties/ZoneProperties";
|
||||
|
||||
const SideBarRight: React.FC = () => {
|
||||
const { activeModule } = useModuleStore();
|
||||
@@ -24,7 +27,8 @@ const SideBarRight: React.FC = () => {
|
||||
|
||||
// Reset subModule whenever activeModule changes
|
||||
useEffect(() => {
|
||||
setSubModule("properties");
|
||||
if (activeModule !== "simulation") setSubModule("properties");
|
||||
if (activeModule === "simulation") setSubModule("mechanics");
|
||||
}, [activeModule]);
|
||||
|
||||
return (
|
||||
@@ -32,32 +36,38 @@ const SideBarRight: React.FC = () => {
|
||||
<Header />
|
||||
{toggleUI && (
|
||||
<div className="sidebar-actions-container">
|
||||
<div
|
||||
className={`sidebar-action-list ${subModule === "properties" ? "active" : ""
|
||||
{/* {activeModule === "builder" && ( */}
|
||||
<div
|
||||
className={`sidebar-action-list ${
|
||||
subModule === "properties" ? "active" : ""
|
||||
}`}
|
||||
onClick={() => setSubModule("properties")}
|
||||
>
|
||||
<PropertiesIcon isActive={subModule === "properties"} />
|
||||
</div>
|
||||
onClick={() => setSubModule("properties")}
|
||||
>
|
||||
<PropertiesIcon isActive={subModule === "properties"} />
|
||||
</div>
|
||||
{/* )} */}
|
||||
{activeModule === "simulation" && (
|
||||
<>
|
||||
<div
|
||||
className={`sidebar-action-list ${subModule === "mechanics" ? "active" : ""
|
||||
}`}
|
||||
className={`sidebar-action-list ${
|
||||
subModule === "mechanics" ? "active" : ""
|
||||
}`}
|
||||
onClick={() => setSubModule("mechanics")}
|
||||
>
|
||||
<MechanicsIcon isActive={subModule === "mechanics"} />
|
||||
</div>
|
||||
<div
|
||||
className={`sidebar-action-list ${subModule === "simulations" ? "active" : ""
|
||||
}`}
|
||||
className={`sidebar-action-list ${
|
||||
subModule === "simulations" ? "active" : ""
|
||||
}`}
|
||||
onClick={() => setSubModule("simulations")}
|
||||
>
|
||||
<SimulationIcon isActive={subModule === "simulations"} />
|
||||
</div>
|
||||
<div
|
||||
className={`sidebar-action-list ${subModule === "analysis" ? "active" : ""
|
||||
}`}
|
||||
className={`sidebar-action-list ${
|
||||
subModule === "analysis" ? "active" : ""
|
||||
}`}
|
||||
onClick={() => setSubModule("analysis")}
|
||||
>
|
||||
<AnalysisIcon isActive={subModule === "analysis"} />
|
||||
@@ -73,6 +83,7 @@ const SideBarRight: React.FC = () => {
|
||||
<div className="sidebar-right-container">
|
||||
<div className="sidebar-right-content-container">
|
||||
<GlobalProperties />
|
||||
{/* <ZoneProperties /> */}
|
||||
{/* <AsstePropertiies /> */}
|
||||
</div>
|
||||
</div>
|
||||
@@ -82,17 +93,17 @@ const SideBarRight: React.FC = () => {
|
||||
|
||||
{toggleUI && activeModule === "simulation" && (
|
||||
<>
|
||||
{(subModule === "mechanics" && selectedActionSphere) && (
|
||||
{subModule === "mechanics" && selectedActionSphere && (
|
||||
<div className="sidebar-right-container">
|
||||
<div className="sidebar-right-content-container">
|
||||
<MachineMechanics />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{(subModule === "mechanics" && !selectedActionSphere) && (
|
||||
{subModule === "mechanics" && !selectedActionSphere && (
|
||||
<div className="sidebar-right-container">
|
||||
<div className="sidebar-right-content-container">
|
||||
{/* <MachineMechanics /> */}
|
||||
<MachineMechanics />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
import React from "react";
|
||||
import { EyeDroperIcon } from "../../../icons/ExportCommonIcons";
|
||||
|
||||
interface PositionInputProps {
|
||||
onChange: (value: string) => void; // Callback for value change
|
||||
header: string;
|
||||
placeholder?: string; // Optional placeholder
|
||||
type?: string; // Input type (e.g., text, number, email)
|
||||
}
|
||||
|
||||
const Vector3Input: React.FC<PositionInputProps> = ({
|
||||
onChange,
|
||||
header,
|
||||
placeholder = "Enter value", // Default placeholder
|
||||
type = "number", // Default type
|
||||
}) => {
|
||||
return (
|
||||
<div className="custom-input-container">
|
||||
<div className="header">
|
||||
{header}{" "}
|
||||
<div className="eyedrop-button">
|
||||
<EyeDroperIcon isActive={false} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="inputs-container">
|
||||
<div className="input-container">
|
||||
<div className="custom-input-label">X : </div>
|
||||
<input
|
||||
className="custom-input-field"
|
||||
type={type}
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
placeholder={placeholder}
|
||||
/>
|
||||
</div>
|
||||
<div className="input-container">
|
||||
<div className="custom-input-label">Y : </div>
|
||||
<input
|
||||
className="custom-input-field"
|
||||
type={type}
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
placeholder={placeholder}
|
||||
min={0}
|
||||
/>
|
||||
</div>
|
||||
<div className="input-container">
|
||||
<div className="custom-input-label">Z : </div>
|
||||
<input
|
||||
className="custom-input-field"
|
||||
type={type}
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
placeholder={placeholder}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Vector3Input;
|
||||
@@ -14,8 +14,8 @@ import EyeDropInput from "../../../ui/inputs/EyeDropInput";
|
||||
import { useSelectedActionSphere } from "../../../../store/store";
|
||||
|
||||
const MachineMechanics: React.FC = () => {
|
||||
const { selectedActionSphere, setSelectedActionSphere } = useSelectedActionSphere();
|
||||
console.log('selectedActionSphere: ', selectedActionSphere);
|
||||
const { selectedActionSphere } = useSelectedActionSphere();
|
||||
console.log("selectedActionSphere: ", selectedActionSphere);
|
||||
const [actionList, setActionList] = useState<string[]>([]);
|
||||
const [triggerList, setTriggerList] = useState<string[]>([]);
|
||||
const [selectedItem, setSelectedItem] = useState<{
|
||||
@@ -71,7 +71,9 @@ const MachineMechanics: React.FC = () => {
|
||||
|
||||
return (
|
||||
<div className="machine-mechanics-container">
|
||||
<div className="machine-mechanics-header">{selectedActionSphere.path.modelName}</div>
|
||||
<div className="machine-mechanics-header">
|
||||
{selectedActionSphere?.path?.modelName || "path name not found"}
|
||||
</div>
|
||||
{/* <div className="process-list-container">
|
||||
<div className="label">Process:</div>
|
||||
<RegularDropDown
|
||||
@@ -100,11 +102,12 @@ const MachineMechanics: React.FC = () => {
|
||||
{actionList.map((action, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`list-item ${selectedItem?.type === "action" &&
|
||||
className={`list-item ${
|
||||
selectedItem?.type === "action" &&
|
||||
selectedItem.name === action
|
||||
? "active"
|
||||
: ""
|
||||
}`}
|
||||
? "active"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
<div
|
||||
className="value"
|
||||
@@ -146,11 +149,12 @@ const MachineMechanics: React.FC = () => {
|
||||
{triggerList.map((trigger, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`list-item ${selectedItem?.type === "trigger" &&
|
||||
className={`list-item ${
|
||||
selectedItem?.type === "trigger" &&
|
||||
selectedItem.name === trigger
|
||||
? "active"
|
||||
: ""
|
||||
}`}
|
||||
? "active"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
<div
|
||||
className="value"
|
||||
@@ -188,7 +192,7 @@ const MachineMechanics: React.FC = () => {
|
||||
label="Speed"
|
||||
value=""
|
||||
activeOption=".mm"
|
||||
onChange={() => { }}
|
||||
onChange={() => {}}
|
||||
/>
|
||||
<EyeDropInput />
|
||||
</>
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import React from "react";
|
||||
import RenameInput from "../../../ui/inputs/RenameInput";
|
||||
import Vector3Input from "../customInput/Vector3Input";
|
||||
|
||||
const ZoneProperties = () => {
|
||||
return (
|
||||
<div className="zone-properties-container">
|
||||
<div className="header">
|
||||
<RenameInput value="Selected Zone Name" />
|
||||
</div>
|
||||
<Vector3Input onChange={()=>{}} header="Target"/>
|
||||
<Vector3Input onChange={()=>{}} header="Position"/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ZoneProperties;
|
||||
@@ -28,7 +28,7 @@ const DropList: React.FC<DropListProps> = ({ val }) => {
|
||||
}}
|
||||
>
|
||||
{val.pathName}
|
||||
<div className="arrow-container">
|
||||
<div className={`arrow-container${openDrop ? " active" : ""}`}>
|
||||
<ArrowIcon />
|
||||
</div>
|
||||
</div>
|
||||
@@ -87,8 +87,9 @@ const Simulations: React.FC = () => {
|
||||
{productsList.map((action, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`list-item ${selectedItem === action ? "active" : ""
|
||||
}`}
|
||||
className={`list-item ${
|
||||
selectedItem === action ? "active" : ""
|
||||
}`}
|
||||
>
|
||||
<div
|
||||
className="value"
|
||||
|
||||
@@ -6,15 +6,20 @@ import {
|
||||
SimulationIcon,
|
||||
VisualizationIcon,
|
||||
} from "../icons/ExportModuleIcons";
|
||||
import useToggleStore from "../../store/useUIToggleStore";
|
||||
|
||||
const ModuleToggle: React.FC = () => {
|
||||
const { activeModule, setActiveModule } = useModuleStore();
|
||||
const { setToggleUI } = useToggleStore();
|
||||
|
||||
return (
|
||||
<div className="module-toggle-container">
|
||||
<div
|
||||
className={`module-list ${activeModule === "builder" && "active"}`}
|
||||
onClick={() => setActiveModule("builder")}
|
||||
onClick={() => {
|
||||
setActiveModule("builder");
|
||||
setToggleUI(true);
|
||||
}}
|
||||
>
|
||||
<div className="icon">
|
||||
<BuilderIcon isActive={activeModule === "builder"} />
|
||||
@@ -23,7 +28,10 @@ const ModuleToggle: React.FC = () => {
|
||||
</div>
|
||||
<div
|
||||
className={`module-list ${activeModule === "simulation" && "active"}`}
|
||||
onClick={() => setActiveModule("simulation")}
|
||||
onClick={() => {
|
||||
setActiveModule("simulation");
|
||||
setToggleUI(true);
|
||||
}}
|
||||
>
|
||||
<div className="icon">
|
||||
<SimulationIcon isActive={activeModule === "simulation"} />
|
||||
@@ -34,7 +42,10 @@ const ModuleToggle: React.FC = () => {
|
||||
className={`module-list ${
|
||||
activeModule === "visualization" && "active"
|
||||
}`}
|
||||
onClick={() => setActiveModule("visualization")}
|
||||
onClick={() => {
|
||||
setActiveModule("visualization");
|
||||
setToggleUI(true);
|
||||
}}
|
||||
>
|
||||
<div className="icon">
|
||||
<VisualizationIcon isActive={activeModule === "visualization"} />
|
||||
@@ -42,10 +53,11 @@ const ModuleToggle: React.FC = () => {
|
||||
<div className="module">Visualization</div>
|
||||
</div>
|
||||
<div
|
||||
className={`module-list ${
|
||||
activeModule === "market" && "active"
|
||||
}`}
|
||||
onClick={() => setActiveModule("market")}
|
||||
className={`module-list ${activeModule === "market" && "active"}`}
|
||||
onClick={() => {
|
||||
setActiveModule("market");
|
||||
setToggleUI(false);
|
||||
}}
|
||||
>
|
||||
<div className="icon">
|
||||
<CartIcon isActive={activeModule === "market"} />
|
||||
|
||||
@@ -1,94 +1,94 @@
|
||||
import { useMemo } from "react";
|
||||
|
||||
import { Bar } from "react-chartjs-2";
|
||||
|
||||
interface ChartComponentProps {
|
||||
type: any;
|
||||
title: string;
|
||||
fontFamily?: string;
|
||||
fontSize?: string;
|
||||
fontWeight?: "Light" | "Regular" | "Bold";
|
||||
data: any;
|
||||
}
|
||||
|
||||
const LineGraphComponent = ({
|
||||
title,
|
||||
fontFamily,
|
||||
fontSize,
|
||||
fontWeight = "Regular",
|
||||
}: ChartComponentProps) => {
|
||||
// Memoize Font Weight Mapping
|
||||
const chartFontWeightMap = useMemo(
|
||||
() => ({
|
||||
Light: "lighter" as const,
|
||||
Regular: "normal" as const,
|
||||
Bold: "bold" as const,
|
||||
}),
|
||||
[]
|
||||
);
|
||||
|
||||
// Parse and Memoize Font Size
|
||||
const fontSizeValue = useMemo(
|
||||
() => (fontSize ? parseInt(fontSize) : 12),
|
||||
[fontSize]
|
||||
);
|
||||
|
||||
// Determine and Memoize Font Weight
|
||||
const fontWeightValue = useMemo(
|
||||
() => chartFontWeightMap[fontWeight],
|
||||
[fontWeight, chartFontWeightMap]
|
||||
);
|
||||
|
||||
// Memoize Chart Font Style
|
||||
const chartFontStyle = useMemo(
|
||||
() => ({
|
||||
family: fontFamily || "Arial",
|
||||
size: fontSizeValue,
|
||||
weight: fontWeightValue,
|
||||
}),
|
||||
[fontFamily, fontSizeValue, fontWeightValue]
|
||||
);
|
||||
|
||||
const options = useMemo(
|
||||
() => ({
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
plugins: {
|
||||
title: {
|
||||
display: true,
|
||||
text: title,
|
||||
font: chartFontStyle,
|
||||
},
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
scales: {
|
||||
x: {
|
||||
ticks: {
|
||||
display: false, // This hides the x-axis labels
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
[title, chartFontStyle]
|
||||
);
|
||||
|
||||
const chartData = {
|
||||
labels: ["January", "February", "March", "April", "May", "June", "July"],
|
||||
datasets: [
|
||||
{
|
||||
label: "My First Dataset",
|
||||
data: [65, 59, 80, 81, 56, 55, 40],
|
||||
backgroundColor: "#6f42c1",
|
||||
borderColor: "#ffffff",
|
||||
borderWidth: 2,
|
||||
fill: false,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
return <Bar data={chartData} options={options} />;
|
||||
};
|
||||
|
||||
export default LineGraphComponent;
|
||||
import { useMemo } from "react";
|
||||
|
||||
import { Bar } from "react-chartjs-2";
|
||||
|
||||
interface ChartComponentProps {
|
||||
type: any;
|
||||
title: string;
|
||||
fontFamily?: string;
|
||||
fontSize?: string;
|
||||
fontWeight?: "Light" | "Regular" | "Bold";
|
||||
data: any;
|
||||
}
|
||||
|
||||
const LineGraphComponent = ({
|
||||
title,
|
||||
fontFamily,
|
||||
fontSize,
|
||||
fontWeight = "Regular",
|
||||
}: ChartComponentProps) => {
|
||||
// Memoize Font Weight Mapping
|
||||
const chartFontWeightMap = useMemo(
|
||||
() => ({
|
||||
Light: "lighter" as const,
|
||||
Regular: "normal" as const,
|
||||
Bold: "bold" as const,
|
||||
}),
|
||||
[]
|
||||
);
|
||||
|
||||
// Parse and Memoize Font Size
|
||||
const fontSizeValue = useMemo(
|
||||
() => (fontSize ? parseInt(fontSize) : 12),
|
||||
[fontSize]
|
||||
);
|
||||
|
||||
// Determine and Memoize Font Weight
|
||||
const fontWeightValue = useMemo(
|
||||
() => chartFontWeightMap[fontWeight],
|
||||
[fontWeight, chartFontWeightMap]
|
||||
);
|
||||
|
||||
// Memoize Chart Font Style
|
||||
const chartFontStyle = useMemo(
|
||||
() => ({
|
||||
family: fontFamily || "Arial",
|
||||
size: fontSizeValue,
|
||||
weight: fontWeightValue,
|
||||
}),
|
||||
[fontFamily, fontSizeValue, fontWeightValue]
|
||||
);
|
||||
|
||||
const options = useMemo(
|
||||
() => ({
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
plugins: {
|
||||
title: {
|
||||
display: true,
|
||||
text: title,
|
||||
font: chartFontStyle,
|
||||
},
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
scales: {
|
||||
x: {
|
||||
ticks: {
|
||||
display: false, // This hides the x-axis labels
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
[title, chartFontStyle]
|
||||
);
|
||||
|
||||
const chartData = {
|
||||
labels: ["January", "February", "March", "April", "May", "June", "July"],
|
||||
datasets: [
|
||||
{
|
||||
label: "My First Dataset",
|
||||
data: [65, 59, 80, 81, 56, 55, 40],
|
||||
backgroundColor: "#6f42c1",
|
||||
borderColor: "#ffffff",
|
||||
borderWidth: 2,
|
||||
fill: false,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
return <Bar data={chartData} options={options} />;
|
||||
};
|
||||
|
||||
export default LineGraphComponent;
|
||||
|
||||
@@ -1,93 +1,93 @@
|
||||
import { useMemo } from "react";
|
||||
import { Line } from "react-chartjs-2";
|
||||
|
||||
interface ChartComponentProps {
|
||||
type: any;
|
||||
title: string;
|
||||
fontFamily?: string;
|
||||
fontSize?: string;
|
||||
fontWeight?: "Light" | "Regular" | "Bold";
|
||||
data: any;
|
||||
}
|
||||
|
||||
const LineGraphComponent = ({
|
||||
title,
|
||||
fontFamily,
|
||||
fontSize,
|
||||
fontWeight = "Regular",
|
||||
}: ChartComponentProps) => {
|
||||
// Memoize Font Weight Mapping
|
||||
const chartFontWeightMap = useMemo(
|
||||
() => ({
|
||||
Light: "lighter" as const,
|
||||
Regular: "normal" as const,
|
||||
Bold: "bold" as const,
|
||||
}),
|
||||
[]
|
||||
);
|
||||
|
||||
// Parse and Memoize Font Size
|
||||
const fontSizeValue = useMemo(
|
||||
() => (fontSize ? parseInt(fontSize) : 12),
|
||||
[fontSize]
|
||||
);
|
||||
|
||||
// Determine and Memoize Font Weight
|
||||
const fontWeightValue = useMemo(
|
||||
() => chartFontWeightMap[fontWeight],
|
||||
[fontWeight, chartFontWeightMap]
|
||||
);
|
||||
|
||||
// Memoize Chart Font Style
|
||||
const chartFontStyle = useMemo(
|
||||
() => ({
|
||||
family: fontFamily || "Arial",
|
||||
size: fontSizeValue,
|
||||
weight: fontWeightValue,
|
||||
}),
|
||||
[fontFamily, fontSizeValue, fontWeightValue]
|
||||
);
|
||||
|
||||
const options = useMemo(
|
||||
() => ({
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
plugins: {
|
||||
title: {
|
||||
display: true,
|
||||
text: title,
|
||||
font: chartFontStyle,
|
||||
},
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
scales: {
|
||||
x: {
|
||||
ticks: {
|
||||
display: false, // This hides the x-axis labels
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
[title, chartFontStyle]
|
||||
);
|
||||
|
||||
const chartData = {
|
||||
labels: ["January", "February", "March", "April", "May", "June", "July"],
|
||||
datasets: [
|
||||
{
|
||||
label: "My First Dataset",
|
||||
data: [65, 59, 80, 81, 56, 55, 40],
|
||||
backgroundColor: "#6f42c1", // Updated to #6f42c1 (Purple)
|
||||
borderColor: "#ffffff", // Keeping border color white
|
||||
borderWidth: 2,
|
||||
fill: false,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
return <Line data={chartData} options={options} />;
|
||||
};
|
||||
|
||||
export default LineGraphComponent;
|
||||
import { useMemo } from "react";
|
||||
import { Line } from "react-chartjs-2";
|
||||
|
||||
interface ChartComponentProps {
|
||||
type: any;
|
||||
title: string;
|
||||
fontFamily?: string;
|
||||
fontSize?: string;
|
||||
fontWeight?: "Light" | "Regular" | "Bold";
|
||||
data: any;
|
||||
}
|
||||
|
||||
const LineGraphComponent = ({
|
||||
title,
|
||||
fontFamily,
|
||||
fontSize,
|
||||
fontWeight = "Regular",
|
||||
}: ChartComponentProps) => {
|
||||
// Memoize Font Weight Mapping
|
||||
const chartFontWeightMap = useMemo(
|
||||
() => ({
|
||||
Light: "lighter" as const,
|
||||
Regular: "normal" as const,
|
||||
Bold: "bold" as const,
|
||||
}),
|
||||
[]
|
||||
);
|
||||
|
||||
// Parse and Memoize Font Size
|
||||
const fontSizeValue = useMemo(
|
||||
() => (fontSize ? parseInt(fontSize) : 12),
|
||||
[fontSize]
|
||||
);
|
||||
|
||||
// Determine and Memoize Font Weight
|
||||
const fontWeightValue = useMemo(
|
||||
() => chartFontWeightMap[fontWeight],
|
||||
[fontWeight, chartFontWeightMap]
|
||||
);
|
||||
|
||||
// Memoize Chart Font Style
|
||||
const chartFontStyle = useMemo(
|
||||
() => ({
|
||||
family: fontFamily || "Arial",
|
||||
size: fontSizeValue,
|
||||
weight: fontWeightValue,
|
||||
}),
|
||||
[fontFamily, fontSizeValue, fontWeightValue]
|
||||
);
|
||||
|
||||
const options = useMemo(
|
||||
() => ({
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
plugins: {
|
||||
title: {
|
||||
display: true,
|
||||
text: title,
|
||||
font: chartFontStyle,
|
||||
},
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
scales: {
|
||||
x: {
|
||||
ticks: {
|
||||
display: false, // This hides the x-axis labels
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
[title, chartFontStyle]
|
||||
);
|
||||
|
||||
const chartData = {
|
||||
labels: ["January", "February", "March", "April", "May", "June", "July"],
|
||||
datasets: [
|
||||
{
|
||||
label: "My First Dataset",
|
||||
data: [65, 59, 80, 81, 56, 55, 40],
|
||||
backgroundColor: "#6f42c1", // Updated to #6f42c1 (Purple)
|
||||
borderColor: "#ffffff", // Keeping border color white
|
||||
borderWidth: 2,
|
||||
fill: false,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
return <Line data={chartData} options={options} />;
|
||||
};
|
||||
|
||||
export default LineGraphComponent;
|
||||
|
||||
@@ -1,91 +1,91 @@
|
||||
import { useMemo } from "react";
|
||||
import { Pie } from "react-chartjs-2";
|
||||
|
||||
interface ChartComponentProps {
|
||||
type: any;
|
||||
title: string;
|
||||
fontFamily?: string;
|
||||
fontSize?: string;
|
||||
fontWeight?: "Light" | "Regular" | "Bold";
|
||||
data: any;
|
||||
}
|
||||
|
||||
const PieChartComponent = ({
|
||||
title,
|
||||
fontFamily,
|
||||
fontSize,
|
||||
fontWeight = "Regular",
|
||||
}: ChartComponentProps) => {
|
||||
// Memoize Font Weight Mapping
|
||||
const chartFontWeightMap = useMemo(
|
||||
() => ({
|
||||
Light: "lighter" as const,
|
||||
Regular: "normal" as const,
|
||||
Bold: "bold" as const,
|
||||
}),
|
||||
[]
|
||||
);
|
||||
|
||||
// Parse and Memoize Font Size
|
||||
const fontSizeValue = useMemo(
|
||||
() => (fontSize ? parseInt(fontSize) : 12),
|
||||
[fontSize]
|
||||
);
|
||||
|
||||
// Determine and Memoize Font Weight
|
||||
const fontWeightValue = useMemo(
|
||||
() => chartFontWeightMap[fontWeight],
|
||||
[fontWeight, chartFontWeightMap]
|
||||
);
|
||||
|
||||
// Memoize Chart Font Style
|
||||
const chartFontStyle = useMemo(
|
||||
() => ({
|
||||
family: fontFamily || "Arial",
|
||||
size: fontSizeValue,
|
||||
weight: fontWeightValue,
|
||||
}),
|
||||
[fontFamily, fontSizeValue, fontWeightValue]
|
||||
);
|
||||
|
||||
// Access the CSS variable for the primary accent color
|
||||
const accentColor = getComputedStyle(document.documentElement)
|
||||
.getPropertyValue("--accent-color")
|
||||
.trim();
|
||||
|
||||
console.log("accentColor: ", accentColor);
|
||||
const options = useMemo(
|
||||
() => ({
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
plugins: {
|
||||
title: {
|
||||
display: true,
|
||||
text: title,
|
||||
font: chartFontStyle,
|
||||
},
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
}),
|
||||
[title, chartFontStyle]
|
||||
);
|
||||
|
||||
const chartData = {
|
||||
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
|
||||
datasets: [
|
||||
{
|
||||
label: "Dataset",
|
||||
data: [12, 19, 3, 5, 2, 3],
|
||||
backgroundColor: ["#6f42c1"],
|
||||
borderColor: "#ffffff",
|
||||
borderWidth: 2,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
return <Pie data={chartData} options={options} />;
|
||||
};
|
||||
|
||||
export default PieChartComponent;
|
||||
import { useMemo } from "react";
|
||||
import { Pie } from "react-chartjs-2";
|
||||
|
||||
interface ChartComponentProps {
|
||||
type: any;
|
||||
title: string;
|
||||
fontFamily?: string;
|
||||
fontSize?: string;
|
||||
fontWeight?: "Light" | "Regular" | "Bold";
|
||||
data: any;
|
||||
}
|
||||
|
||||
const PieChartComponent = ({
|
||||
title,
|
||||
fontFamily,
|
||||
fontSize,
|
||||
fontWeight = "Regular",
|
||||
}: ChartComponentProps) => {
|
||||
// Memoize Font Weight Mapping
|
||||
const chartFontWeightMap = useMemo(
|
||||
() => ({
|
||||
Light: "lighter" as const,
|
||||
Regular: "normal" as const,
|
||||
Bold: "bold" as const,
|
||||
}),
|
||||
[]
|
||||
);
|
||||
|
||||
// Parse and Memoize Font Size
|
||||
const fontSizeValue = useMemo(
|
||||
() => (fontSize ? parseInt(fontSize) : 12),
|
||||
[fontSize]
|
||||
);
|
||||
|
||||
// Determine and Memoize Font Weight
|
||||
const fontWeightValue = useMemo(
|
||||
() => chartFontWeightMap[fontWeight],
|
||||
[fontWeight, chartFontWeightMap]
|
||||
);
|
||||
|
||||
// Memoize Chart Font Style
|
||||
const chartFontStyle = useMemo(
|
||||
() => ({
|
||||
family: fontFamily || "Arial",
|
||||
size: fontSizeValue,
|
||||
weight: fontWeightValue,
|
||||
}),
|
||||
[fontFamily, fontSizeValue, fontWeightValue]
|
||||
);
|
||||
|
||||
// Access the CSS variable for the primary accent color
|
||||
const accentColor = getComputedStyle(document.documentElement)
|
||||
.getPropertyValue("--accent-color")
|
||||
.trim();
|
||||
|
||||
console.log("accentColor: ", accentColor);
|
||||
const options = useMemo(
|
||||
() => ({
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
plugins: {
|
||||
title: {
|
||||
display: true,
|
||||
text: title,
|
||||
font: chartFontStyle,
|
||||
},
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
}),
|
||||
[title, chartFontStyle]
|
||||
);
|
||||
|
||||
const chartData = {
|
||||
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
|
||||
datasets: [
|
||||
{
|
||||
label: "Dataset",
|
||||
data: [12, 19, 3, 5, 2, 3],
|
||||
backgroundColor: ["#6f42c1"],
|
||||
borderColor: "#ffffff",
|
||||
borderWidth: 2,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
return <Pie data={chartData} options={options} />;
|
||||
};
|
||||
|
||||
export default PieChartComponent;
|
||||
|
||||
@@ -1,192 +1,192 @@
|
||||
import React from "react";
|
||||
import {
|
||||
CleanPannel,
|
||||
EyeIcon,
|
||||
LockIcon,
|
||||
} from "../../icons/RealTimeVisulationIcons";
|
||||
|
||||
// Define the type for `Side`
|
||||
type Side = "top" | "bottom" | "left" | "right";
|
||||
|
||||
// Define the type for the props passed to the Buttons component
|
||||
interface ButtonsProps {
|
||||
selectedZone: {
|
||||
zoneName: string;
|
||||
activeSides: Side[];
|
||||
panelOrder: Side[];
|
||||
lockedPanels: Side[];
|
||||
widgets: {
|
||||
id: string;
|
||||
type: string;
|
||||
title: string;
|
||||
panel: Side;
|
||||
data: any;
|
||||
}[];
|
||||
};
|
||||
setSelectedZone: React.Dispatch<
|
||||
React.SetStateAction<{
|
||||
zoneName: string;
|
||||
activeSides: Side[];
|
||||
panelOrder: Side[];
|
||||
lockedPanels: Side[];
|
||||
widgets: {
|
||||
id: string;
|
||||
type: string;
|
||||
title: string;
|
||||
panel: Side;
|
||||
data: any;
|
||||
}[];
|
||||
}>
|
||||
>;
|
||||
hiddenPanels: Side[]; // Add this prop for hidden panels
|
||||
setHiddenPanels: React.Dispatch<React.SetStateAction<Side[]>>; // Add this prop for updating hidden panels
|
||||
}
|
||||
|
||||
const AddButtons: React.FC<ButtonsProps> = ({
|
||||
selectedZone,
|
||||
setSelectedZone,
|
||||
setHiddenPanels,
|
||||
hiddenPanels,
|
||||
}) => {
|
||||
// Local state to track hidden panels
|
||||
|
||||
// Function to toggle lock/unlock a panel
|
||||
const toggleLockPanel = (side: Side) => {
|
||||
const newLockedPanels = selectedZone.lockedPanels.includes(side)
|
||||
? selectedZone.lockedPanels.filter((panel) => panel !== side)
|
||||
: [...selectedZone.lockedPanels, side];
|
||||
|
||||
const updatedZone = {
|
||||
...selectedZone,
|
||||
lockedPanels: newLockedPanels,
|
||||
};
|
||||
|
||||
// Update the selectedZone state
|
||||
setSelectedZone(updatedZone);
|
||||
};
|
||||
|
||||
// Function to toggle visibility of a panel
|
||||
const toggleVisibility = (side: Side) => {
|
||||
const isHidden = hiddenPanels.includes(side);
|
||||
if (isHidden) {
|
||||
// If the panel is already hidden, remove it from the hiddenPanels array
|
||||
setHiddenPanels(hiddenPanels.filter((panel) => panel !== side));
|
||||
} else {
|
||||
// If the panel is visible, add it to the hiddenPanels array
|
||||
setHiddenPanels([...hiddenPanels, side]);
|
||||
}
|
||||
};
|
||||
|
||||
// Function to clean all widgets from a panel
|
||||
const cleanPanel = (side: Side) => {
|
||||
const cleanedWidgets = selectedZone.widgets.filter(
|
||||
(widget) => widget.panel !== side
|
||||
);
|
||||
|
||||
const updatedZone = {
|
||||
...selectedZone,
|
||||
widgets: cleanedWidgets,
|
||||
};
|
||||
|
||||
// Update the selectedZone state
|
||||
setSelectedZone(updatedZone);
|
||||
};
|
||||
|
||||
// Function to handle "+" button click
|
||||
const handlePlusButtonClick = (side: Side) => {
|
||||
if (selectedZone.activeSides.includes(side)) {
|
||||
// If the panel is already active, remove all widgets and close the panel
|
||||
const cleanedWidgets = selectedZone.widgets.filter(
|
||||
(widget) => widget.panel !== side
|
||||
);
|
||||
const newActiveSides = selectedZone.activeSides.filter((s) => s !== side);
|
||||
|
||||
const updatedZone = {
|
||||
...selectedZone,
|
||||
widgets: cleanedWidgets,
|
||||
activeSides: newActiveSides,
|
||||
panelOrder: newActiveSides,
|
||||
};
|
||||
|
||||
// Update the selectedZone state
|
||||
setSelectedZone(updatedZone);
|
||||
} else {
|
||||
// If the panel is not active, activate it
|
||||
const newActiveSides = [...selectedZone.activeSides, side];
|
||||
|
||||
const updatedZone = {
|
||||
...selectedZone,
|
||||
activeSides: newActiveSides,
|
||||
panelOrder: newActiveSides,
|
||||
};
|
||||
|
||||
// Update the selectedZone state
|
||||
setSelectedZone(updatedZone);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
{(["top", "right", "bottom", "left"] as Side[]).map((side) => (
|
||||
<div key={side} className={`side-button-container ${side}`}>
|
||||
{/* "+" Button */}
|
||||
<button
|
||||
className={`side-button ${side}`}
|
||||
onClick={() => handlePlusButtonClick(side)}
|
||||
title={
|
||||
selectedZone.activeSides.includes(side)
|
||||
? `Remove all items and close ${side} panel`
|
||||
: `Activate ${side} panel`
|
||||
}
|
||||
>
|
||||
+
|
||||
</button>
|
||||
|
||||
{/* Extra Buttons */}
|
||||
{selectedZone.activeSides.includes(side) && (
|
||||
<div className="extra-Bs">
|
||||
{/* Hide Panel */}
|
||||
<div
|
||||
className={`icon ${
|
||||
hiddenPanels.includes(side) ? "active" : ""
|
||||
}`}
|
||||
title={
|
||||
hiddenPanels.includes(side) ? "Show Panel" : "Hide Panel"
|
||||
}
|
||||
onClick={() => toggleVisibility(side)}
|
||||
>
|
||||
<EyeIcon />
|
||||
</div>
|
||||
|
||||
{/* Clean Panel */}
|
||||
<div
|
||||
className="icon"
|
||||
title="Clean Panel"
|
||||
onClick={() => cleanPanel(side)}
|
||||
>
|
||||
<CleanPannel />
|
||||
</div>
|
||||
|
||||
{/* Lock/Unlock Panel */}
|
||||
<div
|
||||
className={`icon ${
|
||||
selectedZone.lockedPanels.includes(side) ? "active" : ""
|
||||
}`}
|
||||
title={
|
||||
selectedZone.lockedPanels.includes(side)
|
||||
? "Unlock Panel"
|
||||
: "Lock Panel"
|
||||
}
|
||||
onClick={() => toggleLockPanel(side)}
|
||||
>
|
||||
<LockIcon />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddButtons;
|
||||
import React from "react";
|
||||
import {
|
||||
CleanPannel,
|
||||
EyeIcon,
|
||||
LockIcon,
|
||||
} from "../../icons/RealTimeVisulationIcons";
|
||||
|
||||
// Define the type for `Side`
|
||||
type Side = "top" | "bottom" | "left" | "right";
|
||||
|
||||
// Define the type for the props passed to the Buttons component
|
||||
interface ButtonsProps {
|
||||
selectedZone: {
|
||||
zoneName: string;
|
||||
activeSides: Side[];
|
||||
panelOrder: Side[];
|
||||
lockedPanels: Side[];
|
||||
widgets: {
|
||||
id: string;
|
||||
type: string;
|
||||
title: string;
|
||||
panel: Side;
|
||||
data: any;
|
||||
}[];
|
||||
};
|
||||
setSelectedZone: React.Dispatch<
|
||||
React.SetStateAction<{
|
||||
zoneName: string;
|
||||
activeSides: Side[];
|
||||
panelOrder: Side[];
|
||||
lockedPanels: Side[];
|
||||
widgets: {
|
||||
id: string;
|
||||
type: string;
|
||||
title: string;
|
||||
panel: Side;
|
||||
data: any;
|
||||
}[];
|
||||
}>
|
||||
>;
|
||||
hiddenPanels: Side[]; // Add this prop for hidden panels
|
||||
setHiddenPanels: React.Dispatch<React.SetStateAction<Side[]>>; // Add this prop for updating hidden panels
|
||||
}
|
||||
|
||||
const AddButtons: React.FC<ButtonsProps> = ({
|
||||
selectedZone,
|
||||
setSelectedZone,
|
||||
setHiddenPanels,
|
||||
hiddenPanels,
|
||||
}) => {
|
||||
// Local state to track hidden panels
|
||||
|
||||
// Function to toggle lock/unlock a panel
|
||||
const toggleLockPanel = (side: Side) => {
|
||||
const newLockedPanels = selectedZone.lockedPanels.includes(side)
|
||||
? selectedZone.lockedPanels.filter((panel) => panel !== side)
|
||||
: [...selectedZone.lockedPanels, side];
|
||||
|
||||
const updatedZone = {
|
||||
...selectedZone,
|
||||
lockedPanels: newLockedPanels,
|
||||
};
|
||||
|
||||
// Update the selectedZone state
|
||||
setSelectedZone(updatedZone);
|
||||
};
|
||||
|
||||
// Function to toggle visibility of a panel
|
||||
const toggleVisibility = (side: Side) => {
|
||||
const isHidden = hiddenPanels.includes(side);
|
||||
if (isHidden) {
|
||||
// If the panel is already hidden, remove it from the hiddenPanels array
|
||||
setHiddenPanels(hiddenPanels.filter((panel) => panel !== side));
|
||||
} else {
|
||||
// If the panel is visible, add it to the hiddenPanels array
|
||||
setHiddenPanels([...hiddenPanels, side]);
|
||||
}
|
||||
};
|
||||
|
||||
// Function to clean all widgets from a panel
|
||||
const cleanPanel = (side: Side) => {
|
||||
const cleanedWidgets = selectedZone.widgets.filter(
|
||||
(widget) => widget.panel !== side
|
||||
);
|
||||
|
||||
const updatedZone = {
|
||||
...selectedZone,
|
||||
widgets: cleanedWidgets,
|
||||
};
|
||||
|
||||
// Update the selectedZone state
|
||||
setSelectedZone(updatedZone);
|
||||
};
|
||||
|
||||
// Function to handle "+" button click
|
||||
const handlePlusButtonClick = (side: Side) => {
|
||||
if (selectedZone.activeSides.includes(side)) {
|
||||
// If the panel is already active, remove all widgets and close the panel
|
||||
const cleanedWidgets = selectedZone.widgets.filter(
|
||||
(widget) => widget.panel !== side
|
||||
);
|
||||
const newActiveSides = selectedZone.activeSides.filter((s) => s !== side);
|
||||
|
||||
const updatedZone = {
|
||||
...selectedZone,
|
||||
widgets: cleanedWidgets,
|
||||
activeSides: newActiveSides,
|
||||
panelOrder: newActiveSides,
|
||||
};
|
||||
|
||||
// Update the selectedZone state
|
||||
setSelectedZone(updatedZone);
|
||||
} else {
|
||||
// If the panel is not active, activate it
|
||||
const newActiveSides = [...selectedZone.activeSides, side];
|
||||
|
||||
const updatedZone = {
|
||||
...selectedZone,
|
||||
activeSides: newActiveSides,
|
||||
panelOrder: newActiveSides,
|
||||
};
|
||||
|
||||
// Update the selectedZone state
|
||||
setSelectedZone(updatedZone);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
{(["top", "right", "bottom", "left"] as Side[]).map((side) => (
|
||||
<div key={side} className={`side-button-container ${side}`}>
|
||||
{/* "+" Button */}
|
||||
<button
|
||||
className={`side-button ${side}`}
|
||||
onClick={() => handlePlusButtonClick(side)}
|
||||
title={
|
||||
selectedZone.activeSides.includes(side)
|
||||
? `Remove all items and close ${side} panel`
|
||||
: `Activate ${side} panel`
|
||||
}
|
||||
>
|
||||
+
|
||||
</button>
|
||||
|
||||
{/* Extra Buttons */}
|
||||
{selectedZone.activeSides.includes(side) && (
|
||||
<div className="extra-Bs">
|
||||
{/* Hide Panel */}
|
||||
<div
|
||||
className={`icon ${
|
||||
hiddenPanels.includes(side) ? "active" : ""
|
||||
}`}
|
||||
title={
|
||||
hiddenPanels.includes(side) ? "Show Panel" : "Hide Panel"
|
||||
}
|
||||
onClick={() => toggleVisibility(side)}
|
||||
>
|
||||
<EyeIcon />
|
||||
</div>
|
||||
|
||||
{/* Clean Panel */}
|
||||
<div
|
||||
className="icon"
|
||||
title="Clean Panel"
|
||||
onClick={() => cleanPanel(side)}
|
||||
>
|
||||
<CleanPannel />
|
||||
</div>
|
||||
|
||||
{/* Lock/Unlock Panel */}
|
||||
<div
|
||||
className={`icon ${
|
||||
selectedZone.lockedPanels.includes(side) ? "active" : ""
|
||||
}`}
|
||||
title={
|
||||
selectedZone.lockedPanels.includes(side)
|
||||
? "Unlock Panel"
|
||||
: "Lock Panel"
|
||||
}
|
||||
onClick={() => toggleLockPanel(side)}
|
||||
>
|
||||
<LockIcon />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddButtons;
|
||||
|
||||
@@ -1,179 +1,179 @@
|
||||
import React, { useEffect, useRef } from "react";
|
||||
import { Widget } from "../../../store/useWidgetStore";
|
||||
|
||||
// Define the type for `Side`
|
||||
type Side = "top" | "bottom" | "left" | "right";
|
||||
|
||||
interface DisplayZoneProps {
|
||||
zonesData: {
|
||||
[key: string]: {
|
||||
activeSides: Side[];
|
||||
panelOrder: Side[];
|
||||
lockedPanels: Side[];
|
||||
widgets: Widget[];
|
||||
};
|
||||
};
|
||||
selectedZone: {
|
||||
zoneName: string;
|
||||
activeSides: Side[];
|
||||
panelOrder: Side[];
|
||||
lockedPanels: Side[];
|
||||
widgets: {
|
||||
id: string;
|
||||
type: string;
|
||||
title: string;
|
||||
panel: Side;
|
||||
data: any;
|
||||
}[];
|
||||
};
|
||||
setSelectedZone: React.Dispatch<
|
||||
React.SetStateAction<{
|
||||
zoneName: string;
|
||||
activeSides: Side[];
|
||||
panelOrder: Side[];
|
||||
lockedPanels: Side[];
|
||||
widgets: {
|
||||
id: string;
|
||||
type: string;
|
||||
title: string;
|
||||
panel: Side;
|
||||
data: any;
|
||||
}[];
|
||||
}>
|
||||
>;
|
||||
}
|
||||
|
||||
const DisplayZone: React.FC<DisplayZoneProps> = ({
|
||||
zonesData,
|
||||
selectedZone,
|
||||
setSelectedZone,
|
||||
}) => {
|
||||
// Ref for the container element
|
||||
const containerRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
// Example state for selectedOption and options (adjust based on your actual use case)
|
||||
const [selectedOption, setSelectedOption] = React.useState<string | null>(
|
||||
null
|
||||
);
|
||||
// console.log('setSelectedOption: ', setSelectedOption);
|
||||
const [options, setOptions] = React.useState<string[]>([]);
|
||||
// console.log('setOptions: ', setOptions);
|
||||
|
||||
// Scroll to the selected option when it changes
|
||||
useEffect(() => {
|
||||
const container = containerRef.current;
|
||||
|
||||
if (container && selectedOption) {
|
||||
// Handle scrolling to the selected option
|
||||
const index = options.findIndex((option) => {
|
||||
const formattedOption = formatOptionName(option);
|
||||
const selectedFormattedOption =
|
||||
selectedOption?.split("_")[1] || selectedOption;
|
||||
return formattedOption === selectedFormattedOption;
|
||||
});
|
||||
|
||||
if (index !== -1) {
|
||||
const optionElement = container.children[index] as HTMLElement;
|
||||
if (optionElement) {
|
||||
optionElement.scrollIntoView({
|
||||
behavior: "smooth",
|
||||
block: "nearest",
|
||||
inline: "center",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [selectedOption, options]);
|
||||
|
||||
useEffect(() => {
|
||||
const container = containerRef.current;
|
||||
|
||||
const handleWheel = (event: WheelEvent) => {
|
||||
event.preventDefault();
|
||||
if (container) {
|
||||
container.scrollBy({
|
||||
left: event.deltaY * 2, // Adjust the multiplier for faster scrolling
|
||||
behavior: "smooth",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
let isDragging = false;
|
||||
let startX: number;
|
||||
let scrollLeft: number;
|
||||
|
||||
const handleMouseDown = (event: MouseEvent) => {
|
||||
isDragging = true;
|
||||
startX = event.pageX - (container?.offsetLeft || 0);
|
||||
scrollLeft = container?.scrollLeft || 0;
|
||||
};
|
||||
|
||||
const handleMouseMove = (event: MouseEvent) => {
|
||||
if (!isDragging || !container) return;
|
||||
event.preventDefault();
|
||||
const x = event.pageX - (container.offsetLeft || 0);
|
||||
const walk = (x - startX) * 2; // Adjust the multiplier for faster dragging
|
||||
container.scrollLeft = scrollLeft - walk;
|
||||
};
|
||||
|
||||
const handleMouseUp = () => {
|
||||
isDragging = false;
|
||||
};
|
||||
|
||||
const handleMouseLeave = () => {
|
||||
isDragging = false;
|
||||
};
|
||||
|
||||
if (container) {
|
||||
container.addEventListener("wheel", handleWheel, { passive: false });
|
||||
container.addEventListener("mousedown", handleMouseDown);
|
||||
container.addEventListener("mousemove", handleMouseMove);
|
||||
container.addEventListener("mouseup", handleMouseUp);
|
||||
container.addEventListener("mouseleave", handleMouseLeave);
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (container) {
|
||||
container.removeEventListener("wheel", handleWheel);
|
||||
container.removeEventListener("mousedown", handleMouseDown);
|
||||
container.removeEventListener("mousemove", handleMouseMove);
|
||||
container.removeEventListener("mouseup", handleMouseUp);
|
||||
container.removeEventListener("mouseleave", handleMouseLeave);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Helper function to format option names (customize as needed)
|
||||
const formatOptionName = (option: string): string => {
|
||||
// Replace underscores with spaces and capitalize the first letter
|
||||
return option.replace(/_/g, " ").replace(/^\w/, (c) => c.toUpperCase());
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={containerRef}
|
||||
className={`zoon-wrapper ${
|
||||
selectedZone.activeSides.includes("bottom") && "bottom"
|
||||
}`}
|
||||
>
|
||||
{Object.keys(zonesData).map((zoneName, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`zone ${
|
||||
selectedZone.zoneName === zoneName ? "active" : ""
|
||||
}`}
|
||||
onClick={() => {
|
||||
setSelectedZone({
|
||||
zoneName,
|
||||
...zonesData[zoneName],
|
||||
});
|
||||
}}
|
||||
>
|
||||
{zoneName}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
import React, { useEffect, useRef } from "react";
|
||||
import { Widget } from "../../../store/useWidgetStore";
|
||||
|
||||
// Define the type for `Side`
|
||||
type Side = "top" | "bottom" | "left" | "right";
|
||||
|
||||
interface DisplayZoneProps {
|
||||
zonesData: {
|
||||
[key: string]: {
|
||||
activeSides: Side[];
|
||||
panelOrder: Side[];
|
||||
lockedPanels: Side[];
|
||||
widgets: Widget[];
|
||||
};
|
||||
};
|
||||
selectedZone: {
|
||||
zoneName: string;
|
||||
activeSides: Side[];
|
||||
panelOrder: Side[];
|
||||
lockedPanels: Side[];
|
||||
widgets: {
|
||||
id: string;
|
||||
type: string;
|
||||
title: string;
|
||||
panel: Side;
|
||||
data: any;
|
||||
}[];
|
||||
};
|
||||
setSelectedZone: React.Dispatch<
|
||||
React.SetStateAction<{
|
||||
zoneName: string;
|
||||
activeSides: Side[];
|
||||
panelOrder: Side[];
|
||||
lockedPanels: Side[];
|
||||
widgets: {
|
||||
id: string;
|
||||
type: string;
|
||||
title: string;
|
||||
panel: Side;
|
||||
data: any;
|
||||
}[];
|
||||
}>
|
||||
>;
|
||||
}
|
||||
|
||||
const DisplayZone: React.FC<DisplayZoneProps> = ({
|
||||
zonesData,
|
||||
selectedZone,
|
||||
setSelectedZone,
|
||||
}) => {
|
||||
// Ref for the container element
|
||||
const containerRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
// Example state for selectedOption and options (adjust based on your actual use case)
|
||||
const [selectedOption, setSelectedOption] = React.useState<string | null>(
|
||||
null
|
||||
);
|
||||
// console.log('setSelectedOption: ', setSelectedOption);
|
||||
const [options, setOptions] = React.useState<string[]>([]);
|
||||
// console.log('setOptions: ', setOptions);
|
||||
|
||||
// Scroll to the selected option when it changes
|
||||
useEffect(() => {
|
||||
const container = containerRef.current;
|
||||
|
||||
if (container && selectedOption) {
|
||||
// Handle scrolling to the selected option
|
||||
const index = options.findIndex((option) => {
|
||||
const formattedOption = formatOptionName(option);
|
||||
const selectedFormattedOption =
|
||||
selectedOption?.split("_")[1] || selectedOption;
|
||||
return formattedOption === selectedFormattedOption;
|
||||
});
|
||||
|
||||
if (index !== -1) {
|
||||
const optionElement = container.children[index] as HTMLElement;
|
||||
if (optionElement) {
|
||||
optionElement.scrollIntoView({
|
||||
behavior: "smooth",
|
||||
block: "nearest",
|
||||
inline: "center",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [selectedOption, options]);
|
||||
|
||||
useEffect(() => {
|
||||
const container = containerRef.current;
|
||||
|
||||
const handleWheel = (event: WheelEvent) => {
|
||||
event.preventDefault();
|
||||
if (container) {
|
||||
container.scrollBy({
|
||||
left: event.deltaY * 2, // Adjust the multiplier for faster scrolling
|
||||
behavior: "smooth",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
let isDragging = false;
|
||||
let startX: number;
|
||||
let scrollLeft: number;
|
||||
|
||||
const handleMouseDown = (event: MouseEvent) => {
|
||||
isDragging = true;
|
||||
startX = event.pageX - (container?.offsetLeft || 0);
|
||||
scrollLeft = container?.scrollLeft || 0;
|
||||
};
|
||||
|
||||
const handleMouseMove = (event: MouseEvent) => {
|
||||
if (!isDragging || !container) return;
|
||||
event.preventDefault();
|
||||
const x = event.pageX - (container.offsetLeft || 0);
|
||||
const walk = (x - startX) * 2; // Adjust the multiplier for faster dragging
|
||||
container.scrollLeft = scrollLeft - walk;
|
||||
};
|
||||
|
||||
const handleMouseUp = () => {
|
||||
isDragging = false;
|
||||
};
|
||||
|
||||
const handleMouseLeave = () => {
|
||||
isDragging = false;
|
||||
};
|
||||
|
||||
if (container) {
|
||||
container.addEventListener("wheel", handleWheel, { passive: false });
|
||||
container.addEventListener("mousedown", handleMouseDown);
|
||||
container.addEventListener("mousemove", handleMouseMove);
|
||||
container.addEventListener("mouseup", handleMouseUp);
|
||||
container.addEventListener("mouseleave", handleMouseLeave);
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (container) {
|
||||
container.removeEventListener("wheel", handleWheel);
|
||||
container.removeEventListener("mousedown", handleMouseDown);
|
||||
container.removeEventListener("mousemove", handleMouseMove);
|
||||
container.removeEventListener("mouseup", handleMouseUp);
|
||||
container.removeEventListener("mouseleave", handleMouseLeave);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Helper function to format option names (customize as needed)
|
||||
const formatOptionName = (option: string): string => {
|
||||
// Replace underscores with spaces and capitalize the first letter
|
||||
return option.replace(/_/g, " ").replace(/^\w/, (c) => c.toUpperCase());
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={containerRef}
|
||||
className={`zoon-wrapper ${
|
||||
selectedZone.activeSides.includes("bottom") && "bottom"
|
||||
}`}
|
||||
>
|
||||
{Object.keys(zonesData).map((zoneName, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`zone ${
|
||||
selectedZone.zoneName === zoneName ? "active" : ""
|
||||
}`}
|
||||
onClick={() => {
|
||||
setSelectedZone({
|
||||
zoneName,
|
||||
...zonesData[zoneName],
|
||||
});
|
||||
}}
|
||||
>
|
||||
{zoneName}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DisplayZone;
|
||||
@@ -1,82 +1,82 @@
|
||||
import { useWidgetStore } from "../../../store/useWidgetStore";
|
||||
import PieGraphComponent from "../charts/PieGraphComponent";
|
||||
import BarGraphComponent from "../charts/BarGraphComponent";
|
||||
import LineGraphComponent from "../charts/LineGraphComponent";
|
||||
|
||||
export const DraggableWidget = ({ widget }: { widget: any }) => {
|
||||
const { selectedChartId, setSelectedChartId } = useWidgetStore();
|
||||
|
||||
const handlePointerDown = () => {
|
||||
if (selectedChartId?.id !== widget.id) {
|
||||
setSelectedChartId(widget);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
key={widget.id}
|
||||
className={`chart-container ${
|
||||
selectedChartId?.id === widget.id && "activeChart"
|
||||
}`}
|
||||
onPointerDown={handlePointerDown}
|
||||
>
|
||||
{widget.type === "progress" ? (
|
||||
// <ProgressCard title={widget.title} data={widget.data} />
|
||||
<></>
|
||||
) : (
|
||||
<>
|
||||
{widget.type === "line" && (
|
||||
<LineGraphComponent
|
||||
type={widget.type}
|
||||
title={widget.title}
|
||||
fontSize={widget.fontSize}
|
||||
fontWeight={widget.fontWeight}
|
||||
data={{
|
||||
measurements: [
|
||||
{ name: "testDevice", fields: "powerConsumption" },
|
||||
{ name: "furnace", fields: "powerConsumption" },
|
||||
],
|
||||
interval: 1000,
|
||||
duration: "1h",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{widget.type === "bar" && (
|
||||
<BarGraphComponent
|
||||
type={widget.type}
|
||||
title={widget.title}
|
||||
fontSize={widget.fontSize}
|
||||
fontWeight={widget.fontWeight}
|
||||
data={{
|
||||
measurements: [
|
||||
{ name: "testDevice", fields: "powerConsumption" },
|
||||
{ name: "furnace", fields: "powerConsumption" },
|
||||
],
|
||||
interval: 1000,
|
||||
duration: "1h",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{widget.type === "pie" && (
|
||||
<PieGraphComponent
|
||||
type={widget.type}
|
||||
title={widget.title}
|
||||
fontSize={widget.fontSize}
|
||||
fontWeight={widget.fontWeight}
|
||||
data={{
|
||||
measurements: [
|
||||
{ name: "testDevice", fields: "powerConsumption" },
|
||||
{ name: "furnace", fields: "powerConsumption" },
|
||||
],
|
||||
interval: 1000,
|
||||
duration: "1h",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
import { useWidgetStore } from "../../../store/useWidgetStore";
|
||||
import PieGraphComponent from "../charts/PieGraphComponent";
|
||||
import BarGraphComponent from "../charts/BarGraphComponent";
|
||||
import LineGraphComponent from "../charts/LineGraphComponent";
|
||||
|
||||
export const DraggableWidget = ({ widget }: { widget: any }) => {
|
||||
const { selectedChartId, setSelectedChartId } = useWidgetStore();
|
||||
|
||||
const handlePointerDown = () => {
|
||||
if (selectedChartId?.id !== widget.id) {
|
||||
setSelectedChartId(widget);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
key={widget.id}
|
||||
className={`chart-container ${
|
||||
selectedChartId?.id === widget.id && "activeChart"
|
||||
}`}
|
||||
onPointerDown={handlePointerDown}
|
||||
>
|
||||
{widget.type === "progress" ? (
|
||||
// <ProgressCard title={widget.title} data={widget.data} />
|
||||
<></>
|
||||
) : (
|
||||
<>
|
||||
{widget.type === "line" && (
|
||||
<LineGraphComponent
|
||||
type={widget.type}
|
||||
title={widget.title}
|
||||
fontSize={widget.fontSize}
|
||||
fontWeight={widget.fontWeight}
|
||||
data={{
|
||||
measurements: [
|
||||
{ name: "testDevice", fields: "powerConsumption" },
|
||||
{ name: "furnace", fields: "powerConsumption" },
|
||||
],
|
||||
interval: 1000,
|
||||
duration: "1h",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{widget.type === "bar" && (
|
||||
<BarGraphComponent
|
||||
type={widget.type}
|
||||
title={widget.title}
|
||||
fontSize={widget.fontSize}
|
||||
fontWeight={widget.fontWeight}
|
||||
data={{
|
||||
measurements: [
|
||||
{ name: "testDevice", fields: "powerConsumption" },
|
||||
{ name: "furnace", fields: "powerConsumption" },
|
||||
],
|
||||
interval: 1000,
|
||||
duration: "1h",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{widget.type === "pie" && (
|
||||
<PieGraphComponent
|
||||
type={widget.type}
|
||||
title={widget.title}
|
||||
fontSize={widget.fontSize}
|
||||
fontWeight={widget.fontWeight}
|
||||
data={{
|
||||
measurements: [
|
||||
{ name: "testDevice", fields: "powerConsumption" },
|
||||
{ name: "furnace", fields: "powerConsumption" },
|
||||
],
|
||||
interval: 1000,
|
||||
duration: "1h",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,203 +1,203 @@
|
||||
import React, { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useWidgetStore } from "../../../store/useWidgetStore";
|
||||
import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
|
||||
import { DraggableWidget } from "./DraggableWidget";
|
||||
|
||||
type Side = "top" | "bottom" | "left" | "right";
|
||||
|
||||
interface Widget {
|
||||
id: string;
|
||||
type: string;
|
||||
title: string;
|
||||
panel: Side;
|
||||
data: any;
|
||||
}
|
||||
|
||||
interface PanelProps {
|
||||
selectedZone: {
|
||||
zoneName: string;
|
||||
activeSides: Side[];
|
||||
panelOrder: Side[];
|
||||
lockedPanels: Side[];
|
||||
widgets: Widget[];
|
||||
};
|
||||
setSelectedZone: React.Dispatch<
|
||||
React.SetStateAction<{
|
||||
zoneName: string;
|
||||
activeSides: Side[];
|
||||
panelOrder: Side[];
|
||||
lockedPanels: Side[];
|
||||
widgets: Widget[];
|
||||
}>
|
||||
>;
|
||||
}
|
||||
|
||||
const generateUniqueId = () =>
|
||||
`${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
||||
|
||||
const Panel: React.FC<PanelProps> = ({ selectedZone, setSelectedZone }) => {
|
||||
const panelRefs = useRef<{ [side in Side]?: HTMLDivElement }>({});
|
||||
const [panelDimensions, setPanelDimensions] = useState<{
|
||||
[side in Side]?: { width: number; height: number };
|
||||
}>({});
|
||||
|
||||
const getPanelStyle = useMemo(
|
||||
() => (side: Side) => {
|
||||
const currentIndex = selectedZone.panelOrder.indexOf(side);
|
||||
const previousPanels = selectedZone.panelOrder.slice(0, currentIndex);
|
||||
const leftActive = previousPanels.includes("left");
|
||||
const rightActive = previousPanels.includes("right");
|
||||
const topActive = previousPanels.includes("top");
|
||||
const bottomActive = previousPanels.includes("bottom");
|
||||
|
||||
switch (side) {
|
||||
case "top":
|
||||
case "bottom":
|
||||
return {
|
||||
width: `calc(100% - ${
|
||||
(leftActive ? 204 : 0) + (rightActive ? 204 : 0)
|
||||
}px)`,
|
||||
left: leftActive ? "204px" : "0",
|
||||
right: rightActive ? "204px" : "0",
|
||||
[side]: "0",
|
||||
height: "200px",
|
||||
};
|
||||
case "left":
|
||||
case "right":
|
||||
return {
|
||||
height: `calc(100% - ${
|
||||
(topActive ? 204 : 0) + (bottomActive ? 204 : 0)
|
||||
}px)`,
|
||||
top: topActive ? "204px" : "0",
|
||||
bottom: bottomActive ? "204px" : "0",
|
||||
[side]: "0",
|
||||
width: "200px",
|
||||
};
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
},
|
||||
[selectedZone.panelOrder]
|
||||
);
|
||||
|
||||
const handleDrop = (e: React.DragEvent, panel: Side) => {
|
||||
e.preventDefault();
|
||||
const { draggedAsset } = useWidgetStore.getState();
|
||||
|
||||
if (!draggedAsset) return;
|
||||
if (isPanelLocked(panel)) return;
|
||||
|
||||
const currentWidgetsCount = getCurrentWidgetCount(panel);
|
||||
const maxCapacity = calculatePanelCapacity(panel);
|
||||
|
||||
if (currentWidgetsCount >= maxCapacity) return;
|
||||
|
||||
addWidgetToPanel(draggedAsset, panel);
|
||||
};
|
||||
|
||||
// Helper functions
|
||||
const isPanelLocked = (panel: Side) =>
|
||||
selectedZone.lockedPanels.includes(panel);
|
||||
|
||||
const getCurrentWidgetCount = (panel: Side) =>
|
||||
selectedZone.widgets.filter(w => w.panel === panel).length;
|
||||
|
||||
const calculatePanelCapacity = (panel: Side) => {
|
||||
const CHART_WIDTH = 200;
|
||||
const CHART_HEIGHT = 200;
|
||||
const FALLBACK_HORIZONTAL_CAPACITY = 5;
|
||||
const FALLBACK_VERTICAL_CAPACITY = 3;
|
||||
|
||||
const dimensions = panelDimensions[panel];
|
||||
if (!dimensions) {
|
||||
return panel === "top" || panel === "bottom"
|
||||
? FALLBACK_HORIZONTAL_CAPACITY
|
||||
: FALLBACK_VERTICAL_CAPACITY;
|
||||
}
|
||||
|
||||
return panel === "top" || panel === "bottom"
|
||||
? Math.floor(dimensions.width / CHART_WIDTH)
|
||||
: Math.floor(dimensions.height / CHART_HEIGHT);
|
||||
};
|
||||
|
||||
const addWidgetToPanel = (asset: any, panel: Side) => {
|
||||
const newWidget = {
|
||||
...asset,
|
||||
id: generateUniqueId(),
|
||||
panel,
|
||||
};
|
||||
|
||||
setSelectedZone(prev => ({
|
||||
...prev,
|
||||
widgets: [...prev.widgets, newWidget]
|
||||
}));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const observers: ResizeObserver[] = [];
|
||||
const currentPanelRefs = panelRefs.current;
|
||||
|
||||
selectedZone.activeSides.forEach((side) => {
|
||||
const element = currentPanelRefs[side];
|
||||
if (element) {
|
||||
const observer = new ResizeObserver((entries) => {
|
||||
for (const entry of entries) {
|
||||
const { width, height } = entry.contentRect;
|
||||
setPanelDimensions((prev) => ({
|
||||
...prev,
|
||||
[side]: { width, height },
|
||||
}));
|
||||
}
|
||||
});
|
||||
observer.observe(element);
|
||||
observers.push(observer);
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
observers.forEach((observer) => observer.disconnect());
|
||||
};
|
||||
}, [selectedZone.activeSides]);
|
||||
|
||||
const { isPlaying } = usePlayButtonStore();
|
||||
|
||||
return (
|
||||
<>
|
||||
{selectedZone.activeSides.map((side) => (
|
||||
<div
|
||||
key={side}
|
||||
className={`panel ${side}-panel absolute ${isPlaying && ""}`}
|
||||
style={getPanelStyle(side)}
|
||||
onDrop={(e) => handleDrop(e, side)}
|
||||
onDragOver={(e) => e.preventDefault()}
|
||||
ref={(el) => {
|
||||
if (el) {
|
||||
panelRefs.current[side] = el;
|
||||
} else {
|
||||
delete panelRefs.current[side];
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className={`panel-content ${isPlaying && "fullScreen"}`}
|
||||
style={{
|
||||
pointerEvents: selectedZone.lockedPanels.includes(side)
|
||||
? "none"
|
||||
: "auto",
|
||||
opacity: selectedZone.lockedPanels.includes(side) ? "0.8" : "1",
|
||||
}}
|
||||
>
|
||||
<>{}</>
|
||||
{selectedZone.widgets
|
||||
.filter((w) => w.panel === side)
|
||||
.map((widget) => (
|
||||
<DraggableWidget widget={widget} key={widget.id} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Panel;
|
||||
import React, { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useWidgetStore } from "../../../store/useWidgetStore";
|
||||
import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
|
||||
import { DraggableWidget } from "./DraggableWidget";
|
||||
|
||||
type Side = "top" | "bottom" | "left" | "right";
|
||||
|
||||
interface Widget {
|
||||
id: string;
|
||||
type: string;
|
||||
title: string;
|
||||
panel: Side;
|
||||
data: any;
|
||||
}
|
||||
|
||||
interface PanelProps {
|
||||
selectedZone: {
|
||||
zoneName: string;
|
||||
activeSides: Side[];
|
||||
panelOrder: Side[];
|
||||
lockedPanels: Side[];
|
||||
widgets: Widget[];
|
||||
};
|
||||
setSelectedZone: React.Dispatch<
|
||||
React.SetStateAction<{
|
||||
zoneName: string;
|
||||
activeSides: Side[];
|
||||
panelOrder: Side[];
|
||||
lockedPanels: Side[];
|
||||
widgets: Widget[];
|
||||
}>
|
||||
>;
|
||||
}
|
||||
|
||||
const generateUniqueId = () =>
|
||||
`${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
||||
|
||||
const Panel: React.FC<PanelProps> = ({ selectedZone, setSelectedZone }) => {
|
||||
const panelRefs = useRef<{ [side in Side]?: HTMLDivElement }>({});
|
||||
const [panelDimensions, setPanelDimensions] = useState<{
|
||||
[side in Side]?: { width: number; height: number };
|
||||
}>({});
|
||||
|
||||
const getPanelStyle = useMemo(
|
||||
() => (side: Side) => {
|
||||
const currentIndex = selectedZone.panelOrder.indexOf(side);
|
||||
const previousPanels = selectedZone.panelOrder.slice(0, currentIndex);
|
||||
const leftActive = previousPanels.includes("left");
|
||||
const rightActive = previousPanels.includes("right");
|
||||
const topActive = previousPanels.includes("top");
|
||||
const bottomActive = previousPanels.includes("bottom");
|
||||
|
||||
switch (side) {
|
||||
case "top":
|
||||
case "bottom":
|
||||
return {
|
||||
width: `calc(100% - ${
|
||||
(leftActive ? 204 : 0) + (rightActive ? 204 : 0)
|
||||
}px)`,
|
||||
left: leftActive ? "204px" : "0",
|
||||
right: rightActive ? "204px" : "0",
|
||||
[side]: "0",
|
||||
height: "200px",
|
||||
};
|
||||
case "left":
|
||||
case "right":
|
||||
return {
|
||||
height: `calc(100% - ${
|
||||
(topActive ? 204 : 0) + (bottomActive ? 204 : 0)
|
||||
}px)`,
|
||||
top: topActive ? "204px" : "0",
|
||||
bottom: bottomActive ? "204px" : "0",
|
||||
[side]: "0",
|
||||
width: "200px",
|
||||
};
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
},
|
||||
[selectedZone.panelOrder]
|
||||
);
|
||||
|
||||
const handleDrop = (e: React.DragEvent, panel: Side) => {
|
||||
e.preventDefault();
|
||||
const { draggedAsset } = useWidgetStore.getState();
|
||||
|
||||
if (!draggedAsset) return;
|
||||
if (isPanelLocked(panel)) return;
|
||||
|
||||
const currentWidgetsCount = getCurrentWidgetCount(panel);
|
||||
const maxCapacity = calculatePanelCapacity(panel);
|
||||
|
||||
if (currentWidgetsCount >= maxCapacity) return;
|
||||
|
||||
addWidgetToPanel(draggedAsset, panel);
|
||||
};
|
||||
|
||||
// Helper functions
|
||||
const isPanelLocked = (panel: Side) =>
|
||||
selectedZone.lockedPanels.includes(panel);
|
||||
|
||||
const getCurrentWidgetCount = (panel: Side) =>
|
||||
selectedZone.widgets.filter(w => w.panel === panel).length;
|
||||
|
||||
const calculatePanelCapacity = (panel: Side) => {
|
||||
const CHART_WIDTH = 200;
|
||||
const CHART_HEIGHT = 200;
|
||||
const FALLBACK_HORIZONTAL_CAPACITY = 5;
|
||||
const FALLBACK_VERTICAL_CAPACITY = 3;
|
||||
|
||||
const dimensions = panelDimensions[panel];
|
||||
if (!dimensions) {
|
||||
return panel === "top" || panel === "bottom"
|
||||
? FALLBACK_HORIZONTAL_CAPACITY
|
||||
: FALLBACK_VERTICAL_CAPACITY;
|
||||
}
|
||||
|
||||
return panel === "top" || panel === "bottom"
|
||||
? Math.floor(dimensions.width / CHART_WIDTH)
|
||||
: Math.floor(dimensions.height / CHART_HEIGHT);
|
||||
};
|
||||
|
||||
const addWidgetToPanel = (asset: any, panel: Side) => {
|
||||
const newWidget = {
|
||||
...asset,
|
||||
id: generateUniqueId(),
|
||||
panel,
|
||||
};
|
||||
|
||||
setSelectedZone(prev => ({
|
||||
...prev,
|
||||
widgets: [...prev.widgets, newWidget]
|
||||
}));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const observers: ResizeObserver[] = [];
|
||||
const currentPanelRefs = panelRefs.current;
|
||||
|
||||
selectedZone.activeSides.forEach((side) => {
|
||||
const element = currentPanelRefs[side];
|
||||
if (element) {
|
||||
const observer = new ResizeObserver((entries) => {
|
||||
for (const entry of entries) {
|
||||
const { width, height } = entry.contentRect;
|
||||
setPanelDimensions((prev) => ({
|
||||
...prev,
|
||||
[side]: { width, height },
|
||||
}));
|
||||
}
|
||||
});
|
||||
observer.observe(element);
|
||||
observers.push(observer);
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
observers.forEach((observer) => observer.disconnect());
|
||||
};
|
||||
}, [selectedZone.activeSides]);
|
||||
|
||||
const { isPlaying } = usePlayButtonStore();
|
||||
|
||||
return (
|
||||
<>
|
||||
{selectedZone.activeSides.map((side) => (
|
||||
<div
|
||||
key={side}
|
||||
className={`panel ${side}-panel absolute ${isPlaying && ""}`}
|
||||
style={getPanelStyle(side)}
|
||||
onDrop={(e) => handleDrop(e, side)}
|
||||
onDragOver={(e) => e.preventDefault()}
|
||||
ref={(el) => {
|
||||
if (el) {
|
||||
panelRefs.current[side] = el;
|
||||
} else {
|
||||
delete panelRefs.current[side];
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className={`panel-content ${isPlaying && "fullScreen"}`}
|
||||
style={{
|
||||
pointerEvents: selectedZone.lockedPanels.includes(side)
|
||||
? "none"
|
||||
: "auto",
|
||||
opacity: selectedZone.lockedPanels.includes(side) ? "0.8" : "1",
|
||||
}}
|
||||
>
|
||||
<>{}</>
|
||||
{selectedZone.widgets
|
||||
.filter((w) => w.panel === side)
|
||||
.map((widget) => (
|
||||
<DraggableWidget widget={widget} key={widget.id} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Panel;
|
||||
|
||||
@@ -1,103 +1,122 @@
|
||||
import React, { useEffect, useState, useRef } from "react";
|
||||
import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
|
||||
import Panel from "./Panel";
|
||||
import AddButtons from "./AddButtons";
|
||||
import { useSelectedZoneStore } from "../../../store/useZoneStore";
|
||||
import DisplayZone from "./DisplayZone";
|
||||
|
||||
type Side = "top" | "bottom" | "left" | "right";
|
||||
|
||||
interface Widget {
|
||||
id: string;
|
||||
type: string;
|
||||
title: string;
|
||||
panel: Side;
|
||||
data: any;
|
||||
}
|
||||
|
||||
const RealTimeVisulization: React.FC = () => {
|
||||
const [hiddenPanels, setHiddenPanels] = React.useState<Side[]>([]);
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const [zonesData, setZonesData] = useState<{
|
||||
[key: string]: {
|
||||
activeSides: Side[];
|
||||
panelOrder: Side[];
|
||||
lockedPanels: Side[];
|
||||
widgets: Widget[];
|
||||
};
|
||||
}>({
|
||||
"Manufacturing unit": {
|
||||
activeSides: [],
|
||||
panelOrder: [],
|
||||
lockedPanels: [],
|
||||
widgets: [],
|
||||
},
|
||||
"Assembly unit": {
|
||||
activeSides: [],
|
||||
panelOrder: [],
|
||||
lockedPanels: [],
|
||||
widgets: [],
|
||||
},
|
||||
"Packing unit": {
|
||||
activeSides: [],
|
||||
panelOrder: [],
|
||||
lockedPanels: [],
|
||||
widgets: [],
|
||||
},
|
||||
Warehouse: {
|
||||
activeSides: [],
|
||||
panelOrder: [],
|
||||
lockedPanels: [],
|
||||
widgets: [],
|
||||
},
|
||||
Inventory: {
|
||||
activeSides: [],
|
||||
panelOrder: [],
|
||||
lockedPanels: [],
|
||||
widgets: [],
|
||||
},
|
||||
});
|
||||
|
||||
const { isPlaying } = usePlayButtonStore();
|
||||
|
||||
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
|
||||
useEffect(() => {
|
||||
setZonesData((prev) => ({
|
||||
...prev,
|
||||
[selectedZone.zoneName]: selectedZone,
|
||||
}));
|
||||
}, [selectedZone]);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={containerRef}
|
||||
id="real-time-vis-canvas"
|
||||
className="realTime-viz canvas"
|
||||
style={{
|
||||
height: isPlaying ? "100vh" : "",
|
||||
width: isPlaying ? "100%" : "",
|
||||
left: isPlaying ? "0%" : "",
|
||||
}}
|
||||
>
|
||||
<DisplayZone
|
||||
zonesData={zonesData}
|
||||
selectedZone={selectedZone}
|
||||
setSelectedZone={setSelectedZone}
|
||||
/>
|
||||
|
||||
{!isPlaying && (
|
||||
<AddButtons
|
||||
hiddenPanels={hiddenPanels}
|
||||
setHiddenPanels={setHiddenPanels}
|
||||
selectedZone={selectedZone}
|
||||
setSelectedZone={setSelectedZone}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Panel selectedZone={selectedZone} setSelectedZone={setSelectedZone} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default RealTimeVisulization;
|
||||
|
||||
import React, { useEffect, useState, useRef } from "react";
|
||||
import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
|
||||
import Panel from "./Panel";
|
||||
import AddButtons from "./AddButtons";
|
||||
import { useSelectedZoneStore } from "../../../store/useZoneStore";
|
||||
import DisplayZone from "./DisplayZone";
|
||||
import Scene from "../../../modules/scene/scene";
|
||||
import useModuleStore from "../../../store/useModuleStore";
|
||||
|
||||
type Side = "top" | "bottom" | "left" | "right";
|
||||
|
||||
interface Widget {
|
||||
id: string;
|
||||
type: string;
|
||||
title: string;
|
||||
panel: Side;
|
||||
data: any;
|
||||
}
|
||||
|
||||
const RealTimeVisulization: React.FC = () => {
|
||||
const [hiddenPanels, setHiddenPanels] = React.useState<Side[]>([]);
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const [zonesData, setZonesData] = useState<{
|
||||
[key: string]: {
|
||||
activeSides: Side[];
|
||||
panelOrder: Side[];
|
||||
lockedPanels: Side[];
|
||||
widgets: Widget[];
|
||||
};
|
||||
}>({
|
||||
"Manufacturing unit": {
|
||||
activeSides: [],
|
||||
panelOrder: [],
|
||||
lockedPanels: [],
|
||||
widgets: [],
|
||||
},
|
||||
"Assembly unit": {
|
||||
activeSides: [],
|
||||
panelOrder: [],
|
||||
lockedPanels: [],
|
||||
widgets: [],
|
||||
},
|
||||
"Packing unit": {
|
||||
activeSides: [],
|
||||
panelOrder: [],
|
||||
lockedPanels: [],
|
||||
widgets: [],
|
||||
},
|
||||
Warehouse: {
|
||||
activeSides: [],
|
||||
panelOrder: [],
|
||||
lockedPanels: [],
|
||||
widgets: [],
|
||||
},
|
||||
Inventory: {
|
||||
activeSides: [],
|
||||
panelOrder: [],
|
||||
lockedPanels: [],
|
||||
widgets: [],
|
||||
},
|
||||
});
|
||||
|
||||
const { isPlaying } = usePlayButtonStore();
|
||||
const { activeModule } = useModuleStore();
|
||||
|
||||
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
|
||||
useEffect(() => {
|
||||
setZonesData((prev) => ({
|
||||
...prev,
|
||||
[selectedZone.zoneName]: selectedZone,
|
||||
}));
|
||||
}, [selectedZone]);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={containerRef}
|
||||
id="real-time-vis-canvas"
|
||||
className="realTime-viz canvas"
|
||||
style={{
|
||||
height: isPlaying || activeModule !== "visualization" ? "100vh" : "",
|
||||
width: isPlaying || activeModule !== "visualization" ? "100vw" : "",
|
||||
left: isPlaying || activeModule !== "visualization" ? "0%" : "",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="scene-container"
|
||||
style={{
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
borderRadius: isPlaying || activeModule !== "visualization" ? "" : "6px",
|
||||
}}
|
||||
>
|
||||
<Scene />
|
||||
</div>
|
||||
{activeModule === "visualization" && (
|
||||
<>
|
||||
<DisplayZone
|
||||
zonesData={zonesData}
|
||||
selectedZone={selectedZone}
|
||||
setSelectedZone={setSelectedZone}
|
||||
/>
|
||||
|
||||
{!isPlaying && (
|
||||
<AddButtons
|
||||
hiddenPanels={hiddenPanels}
|
||||
setHiddenPanels={setHiddenPanels}
|
||||
selectedZone={selectedZone}
|
||||
setSelectedZone={setSelectedZone}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Panel
|
||||
selectedZone={selectedZone}
|
||||
setSelectedZone={setSelectedZone}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default RealTimeVisulization;
|
||||
|
||||
@@ -1,76 +1,76 @@
|
||||
import React, { useState } from "react";
|
||||
import RenameInput from "./RenameInput";
|
||||
|
||||
type InputWithDropDownProps = {
|
||||
label: string;
|
||||
value: string;
|
||||
options?: string[]; // Array of dropdown options
|
||||
activeOption?: string; // The currently active dropdown option
|
||||
onClick?: () => void;
|
||||
onChange: (newValue: string) => void;
|
||||
editableLabel?: boolean;
|
||||
};
|
||||
|
||||
const InputWithDropDown: React.FC<InputWithDropDownProps> = ({
|
||||
label,
|
||||
value,
|
||||
options,
|
||||
activeOption,
|
||||
onClick,
|
||||
onChange,
|
||||
editableLabel = false,
|
||||
}) => {
|
||||
const separatedWords = label
|
||||
.split(/(?=[A-Z])/)
|
||||
.map((word) => word.trim())
|
||||
.toString();
|
||||
|
||||
const [openDropdown, setOpenDropdown] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="value-field-container">
|
||||
{editableLabel ? (
|
||||
<RenameInput value={label} />
|
||||
) : (
|
||||
<label htmlFor={separatedWords} className="label">
|
||||
{label}
|
||||
</label>
|
||||
)}
|
||||
<div className="input default" id={separatedWords}>
|
||||
<input
|
||||
type="text"
|
||||
defaultValue={value}
|
||||
onChange={(e) => {
|
||||
onChange(e.target.value);
|
||||
}}
|
||||
/>
|
||||
|
||||
{activeOption && (
|
||||
<div
|
||||
className="dropdown"
|
||||
onClick={() => {
|
||||
setOpenDropdown(true);
|
||||
}}
|
||||
>
|
||||
<div className="active-option">{activeOption}</div>
|
||||
{options && openDropdown && (
|
||||
<div className="dropdown-options-list">
|
||||
{options.map((option, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={"dropdown-option"}
|
||||
onClick={onClick}
|
||||
>
|
||||
{option}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default InputWithDropDown;
|
||||
import React, { useState } from "react";
|
||||
import RenameInput from "./RenameInput";
|
||||
|
||||
type InputWithDropDownProps = {
|
||||
label: string;
|
||||
value: string;
|
||||
options?: string[]; // Array of dropdown options
|
||||
activeOption?: string; // The currently active dropdown option
|
||||
onClick?: () => void;
|
||||
onChange: (newValue: string) => void;
|
||||
editableLabel?: boolean;
|
||||
};
|
||||
|
||||
const InputWithDropDown: React.FC<InputWithDropDownProps> = ({
|
||||
label,
|
||||
value,
|
||||
options,
|
||||
activeOption,
|
||||
onClick,
|
||||
onChange,
|
||||
editableLabel = false,
|
||||
}) => {
|
||||
const separatedWords = label
|
||||
.split(/(?=[A-Z])/)
|
||||
.map((word) => word.trim())
|
||||
.toString();
|
||||
|
||||
const [openDropdown, setOpenDropdown] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="value-field-container">
|
||||
{editableLabel ? (
|
||||
<RenameInput value={label} />
|
||||
) : (
|
||||
<label htmlFor={separatedWords} className="label">
|
||||
{label}
|
||||
</label>
|
||||
)}
|
||||
<div className="input default" id={separatedWords}>
|
||||
<input
|
||||
type="text"
|
||||
defaultValue={value}
|
||||
onChange={(e) => {
|
||||
onChange(e.target.value);
|
||||
}}
|
||||
/>
|
||||
|
||||
{activeOption && (
|
||||
<div
|
||||
className="dropdown"
|
||||
onClick={() => {
|
||||
setOpenDropdown(true);
|
||||
}}
|
||||
>
|
||||
<div className="active-option">{activeOption}</div>
|
||||
{options && openDropdown && (
|
||||
<div className="dropdown-options-list">
|
||||
{options.map((option, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={"dropdown-option"}
|
||||
onClick={onClick}
|
||||
>
|
||||
{option}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default InputWithDropDown;
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
import React, { useState } from "react";
|
||||
import RegularDropDown from "./RegularDropDown";
|
||||
|
||||
type LabledDropdownProps = {
|
||||
defaultOption: string; // Initial active option
|
||||
options: string[]; // Array of dropdown options
|
||||
};
|
||||
|
||||
const LabledDropdown: React.FC<LabledDropdownProps> = ({ defaultOption, options }) => {
|
||||
const [activeOption, setActiveOption] = useState(defaultOption); // State for active option
|
||||
|
||||
const handleSelect = (option: string) => {
|
||||
setActiveOption(option); // Update the active option state
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="value-field-container">
|
||||
<div className="label">Type</div>
|
||||
<RegularDropDown
|
||||
header={activeOption} // Display the current active option
|
||||
options={options} // Use the options from props
|
||||
onSelect={handleSelect} // Handle option selection
|
||||
search = {false}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default LabledDropdown;
|
||||
import React, { useState } from "react";
|
||||
import RegularDropDown from "./RegularDropDown";
|
||||
|
||||
type LabledDropdownProps = {
|
||||
defaultOption: string; // Initial active option
|
||||
options: string[]; // Array of dropdown options
|
||||
};
|
||||
|
||||
const LabledDropdown: React.FC<LabledDropdownProps> = ({ defaultOption, options }) => {
|
||||
const [activeOption, setActiveOption] = useState(defaultOption); // State for active option
|
||||
|
||||
const handleSelect = (option: string) => {
|
||||
setActiveOption(option); // Update the active option state
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="value-field-container">
|
||||
<div className="label">Type</div>
|
||||
<RegularDropDown
|
||||
header={activeOption} // Display the current active option
|
||||
options={options} // Use the options from props
|
||||
onSelect={handleSelect} // Handle option selection
|
||||
search = {false}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default LabledDropdown;
|
||||
|
||||
@@ -1,141 +1,141 @@
|
||||
import React, { useState, useRef, useEffect } from "react";
|
||||
|
||||
// Dropdown Item Component
|
||||
const DropdownItem = ({
|
||||
label,
|
||||
href,
|
||||
onClick,
|
||||
}: {
|
||||
label: string;
|
||||
href?: string;
|
||||
onClick?: () => void;
|
||||
}) => (
|
||||
<a
|
||||
href={href || "#"}
|
||||
className="dropdown-item"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
onClick?.();
|
||||
}}
|
||||
>
|
||||
{label}
|
||||
</a>
|
||||
);
|
||||
|
||||
// Nested Dropdown Component
|
||||
const NestedDropdown = ({
|
||||
label,
|
||||
children,
|
||||
onSelect,
|
||||
}: {
|
||||
label: string;
|
||||
children: React.ReactNode;
|
||||
onSelect: (selectedLabel: string) => void;
|
||||
}) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="nested-dropdown">
|
||||
{/* Dropdown Trigger */}
|
||||
<div
|
||||
className={`dropdown-trigger ${open ? "open" : ""}`}
|
||||
onClick={() => setOpen(!open)} // Toggle submenu on click
|
||||
>
|
||||
{label} <span className="icon">{open ? "▼" : "▶"}</span>
|
||||
</div>
|
||||
|
||||
{/* Submenu */}
|
||||
{open && (
|
||||
<div className="submenu">
|
||||
{React.Children.map(children, (child) => {
|
||||
if (React.isValidElement(child)) {
|
||||
// Clone the element and pass the `onSelect` prop only if it's expected
|
||||
return React.cloneElement(child as React.ReactElement<any>, { onSelect });
|
||||
}
|
||||
return child; // Return non-element children as-is
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// Recursive Function to Render Nested Data
|
||||
const renderNestedData = (
|
||||
data: Record<string, any>,
|
||||
onSelect: (selectedLabel: string) => void
|
||||
) => {
|
||||
return Object.entries(data).map(([key, value]) => {
|
||||
if (typeof value === "object" && !Array.isArray(value)) {
|
||||
// If the value is an object, render it as a nested dropdown
|
||||
return (
|
||||
<NestedDropdown key={key} label={key} onSelect={onSelect}>
|
||||
{renderNestedData(value, onSelect)}
|
||||
</NestedDropdown>
|
||||
);
|
||||
} else if (Array.isArray(value)) {
|
||||
// If the value is an array, render each item as a dropdown item
|
||||
return value.map((item, index) => (
|
||||
<DropdownItem key={index} label={item} onClick={() => onSelect(item)} />
|
||||
));
|
||||
} else {
|
||||
// If the value is a simple string, render it as a dropdown item
|
||||
return (
|
||||
<DropdownItem key={key} label={value} onClick={() => onSelect(value)} />
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Main Multi-Level Dropdown Component
|
||||
const MultiLevelDropdown = ({ data }: { data: Record<string, any> }) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [selectedLabel, setSelectedLabel] = useState("Dropdown trigger");
|
||||
const dropdownRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// Handle outer click to close the dropdown
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
if (
|
||||
dropdownRef.current &&
|
||||
!dropdownRef.current.contains(event.target as Node)
|
||||
) {
|
||||
setOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener("mousedown", handleClickOutside);
|
||||
return () => {
|
||||
document.removeEventListener("mousedown", handleClickOutside);
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Handle selection of an item
|
||||
const handleSelect = (selectedLabel: string) => {
|
||||
setSelectedLabel(selectedLabel); // Update the dropdown trigger text
|
||||
setOpen(false); // Close the dropdown
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="multi-level-dropdown" ref={dropdownRef}>
|
||||
{/* Dropdown Trigger Button */}
|
||||
<button
|
||||
className={`dropdown-button ${open ? "open" : ""}`}
|
||||
onClick={() => setOpen(!open)} // Toggle main menu on click
|
||||
>
|
||||
{selectedLabel} <span className="icon">▾</span>
|
||||
</button>
|
||||
|
||||
{/* Dropdown Menu */}
|
||||
{open && (
|
||||
<div className="dropdown-menu">
|
||||
<div className="dropdown-content">
|
||||
{renderNestedData(data, handleSelect)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
import React, { useState, useRef, useEffect } from "react";
|
||||
|
||||
// Dropdown Item Component
|
||||
const DropdownItem = ({
|
||||
label,
|
||||
href,
|
||||
onClick,
|
||||
}: {
|
||||
label: string;
|
||||
href?: string;
|
||||
onClick?: () => void;
|
||||
}) => (
|
||||
<a
|
||||
href={href || "#"}
|
||||
className="dropdown-item"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
onClick?.();
|
||||
}}
|
||||
>
|
||||
{label}
|
||||
</a>
|
||||
);
|
||||
|
||||
// Nested Dropdown Component
|
||||
const NestedDropdown = ({
|
||||
label,
|
||||
children,
|
||||
onSelect,
|
||||
}: {
|
||||
label: string;
|
||||
children: React.ReactNode;
|
||||
onSelect: (selectedLabel: string) => void;
|
||||
}) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="nested-dropdown">
|
||||
{/* Dropdown Trigger */}
|
||||
<div
|
||||
className={`dropdown-trigger ${open ? "open" : ""}`}
|
||||
onClick={() => setOpen(!open)} // Toggle submenu on click
|
||||
>
|
||||
{label} <span className="icon">{open ? "▼" : "▶"}</span>
|
||||
</div>
|
||||
|
||||
{/* Submenu */}
|
||||
{open && (
|
||||
<div className="submenu">
|
||||
{React.Children.map(children, (child) => {
|
||||
if (React.isValidElement(child)) {
|
||||
// Clone the element and pass the `onSelect` prop only if it's expected
|
||||
return React.cloneElement(child as React.ReactElement<any>, { onSelect });
|
||||
}
|
||||
return child; // Return non-element children as-is
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// Recursive Function to Render Nested Data
|
||||
const renderNestedData = (
|
||||
data: Record<string, any>,
|
||||
onSelect: (selectedLabel: string) => void
|
||||
) => {
|
||||
return Object.entries(data).map(([key, value]) => {
|
||||
if (typeof value === "object" && !Array.isArray(value)) {
|
||||
// If the value is an object, render it as a nested dropdown
|
||||
return (
|
||||
<NestedDropdown key={key} label={key} onSelect={onSelect}>
|
||||
{renderNestedData(value, onSelect)}
|
||||
</NestedDropdown>
|
||||
);
|
||||
} else if (Array.isArray(value)) {
|
||||
// If the value is an array, render each item as a dropdown item
|
||||
return value.map((item, index) => (
|
||||
<DropdownItem key={index} label={item} onClick={() => onSelect(item)} />
|
||||
));
|
||||
} else {
|
||||
// If the value is a simple string, render it as a dropdown item
|
||||
return (
|
||||
<DropdownItem key={key} label={value} onClick={() => onSelect(value)} />
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Main Multi-Level Dropdown Component
|
||||
const MultiLevelDropdown = ({ data }: { data: Record<string, any> }) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [selectedLabel, setSelectedLabel] = useState("Dropdown trigger");
|
||||
const dropdownRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// Handle outer click to close the dropdown
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
if (
|
||||
dropdownRef.current &&
|
||||
!dropdownRef.current.contains(event.target as Node)
|
||||
) {
|
||||
setOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener("mousedown", handleClickOutside);
|
||||
return () => {
|
||||
document.removeEventListener("mousedown", handleClickOutside);
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Handle selection of an item
|
||||
const handleSelect = (selectedLabel: string) => {
|
||||
setSelectedLabel(selectedLabel); // Update the dropdown trigger text
|
||||
setOpen(false); // Close the dropdown
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="multi-level-dropdown" ref={dropdownRef}>
|
||||
{/* Dropdown Trigger Button */}
|
||||
<button
|
||||
className={`dropdown-button ${open ? "open" : ""}`}
|
||||
onClick={() => setOpen(!open)} // Toggle main menu on click
|
||||
>
|
||||
{selectedLabel} <span className="icon">▾</span>
|
||||
</button>
|
||||
|
||||
{/* Dropdown Menu */}
|
||||
{open && (
|
||||
<div className="dropdown-menu">
|
||||
<div className="dropdown-content">
|
||||
{renderNestedData(data, handleSelect)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default MultiLevelDropdown;
|
||||
@@ -1,127 +1,127 @@
|
||||
import React, { useState, useEffect, useRef } from "react";
|
||||
|
||||
interface DropdownProps {
|
||||
header: string;
|
||||
options: string[];
|
||||
onSelect: (option: string) => void;
|
||||
search?: boolean;
|
||||
onClick?: () => void;
|
||||
onChange?: () => void;
|
||||
}
|
||||
|
||||
const RegularDropDown: React.FC<DropdownProps> = ({
|
||||
header,
|
||||
options,
|
||||
onSelect,
|
||||
search = true,
|
||||
onClick,
|
||||
onChange,
|
||||
}) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [selectedOption, setSelectedOption] = useState<string | null>(null);
|
||||
const [searchTerm, setSearchTerm] = useState(""); // State to store search term
|
||||
const [filteredOptions, setFilteredOptions] = useState<string[]>(options); // State for filtered options
|
||||
const dropdownRef = useRef<HTMLDivElement>(null); // Ref for the dropdown container
|
||||
|
||||
// Reset selectedOption when the dropdown closes
|
||||
useEffect(() => {
|
||||
if (!isOpen) {
|
||||
setSelectedOption(null);
|
||||
setSearchTerm(""); // Clear the search term when the dropdown closes
|
||||
setFilteredOptions(options); // Reset filtered options when the dropdown closes
|
||||
}
|
||||
}, [isOpen, options]);
|
||||
|
||||
// Reset selectedOption when the header prop changes
|
||||
useEffect(() => {
|
||||
setSelectedOption(null);
|
||||
setSearchTerm(""); // Reset search term if header changes
|
||||
setFilteredOptions(options); // Reset options if header changes
|
||||
}, [header, options]);
|
||||
|
||||
// Close dropdown if clicked outside
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
if (
|
||||
dropdownRef.current &&
|
||||
!dropdownRef.current.contains(event.target as Node)
|
||||
) {
|
||||
setIsOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener("click", handleClickOutside);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener("click", handleClickOutside);
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Toggle the dropdown
|
||||
const toggleDropdown = () => {
|
||||
setIsOpen((prev) => !prev);
|
||||
};
|
||||
|
||||
// Handle option selection
|
||||
const handleOptionClick = (option: string) => {
|
||||
setSelectedOption(option);
|
||||
onSelect(option);
|
||||
setIsOpen(false);
|
||||
};
|
||||
|
||||
// Handle search input change
|
||||
const handleSearchChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const term = event.target.value;
|
||||
setSearchTerm(term);
|
||||
|
||||
// Filter options based on the search term
|
||||
const filtered = options.filter((option) =>
|
||||
option.toLowerCase().includes(term.toLowerCase())
|
||||
);
|
||||
setFilteredOptions(filtered);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="regularDropdown-container" ref={dropdownRef}>
|
||||
{/* Dropdown Header */}
|
||||
<div className="dropdown-header flex-sb" onClick={toggleDropdown}>
|
||||
<div className="key">{selectedOption || header}</div>
|
||||
<div className="icon">▾</div>
|
||||
</div>
|
||||
|
||||
{/* Dropdown Options */}
|
||||
{isOpen && (
|
||||
<div className="dropdown-options">
|
||||
{/* Search Bar */}
|
||||
{search && (
|
||||
<div className="dropdown-search">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search..."
|
||||
value={searchTerm}
|
||||
onChange={handleSearchChange}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Filtered Options */}
|
||||
{filteredOptions.length > 0 ? (
|
||||
filteredOptions.map((option, index) => (
|
||||
<div
|
||||
className="option"
|
||||
key={index}
|
||||
onClick={() => handleOptionClick(option)}
|
||||
>
|
||||
{option}
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<div className="no-options">No options found</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default RegularDropDown;
|
||||
import React, { useState, useEffect, useRef } from "react";
|
||||
|
||||
interface DropdownProps {
|
||||
header: string;
|
||||
options: string[];
|
||||
onSelect: (option: string) => void;
|
||||
search?: boolean;
|
||||
onClick?: () => void;
|
||||
onChange?: () => void;
|
||||
}
|
||||
|
||||
const RegularDropDown: React.FC<DropdownProps> = ({
|
||||
header,
|
||||
options,
|
||||
onSelect,
|
||||
search = true,
|
||||
onClick,
|
||||
onChange,
|
||||
}) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [selectedOption, setSelectedOption] = useState<string | null>(null);
|
||||
const [searchTerm, setSearchTerm] = useState(""); // State to store search term
|
||||
const [filteredOptions, setFilteredOptions] = useState<string[]>(options); // State for filtered options
|
||||
const dropdownRef = useRef<HTMLDivElement>(null); // Ref for the dropdown container
|
||||
|
||||
// Reset selectedOption when the dropdown closes
|
||||
useEffect(() => {
|
||||
if (!isOpen) {
|
||||
setSelectedOption(null);
|
||||
setSearchTerm(""); // Clear the search term when the dropdown closes
|
||||
setFilteredOptions(options); // Reset filtered options when the dropdown closes
|
||||
}
|
||||
}, [isOpen, options]);
|
||||
|
||||
// Reset selectedOption when the header prop changes
|
||||
useEffect(() => {
|
||||
setSelectedOption(null);
|
||||
setSearchTerm(""); // Reset search term if header changes
|
||||
setFilteredOptions(options); // Reset options if header changes
|
||||
}, [header, options]);
|
||||
|
||||
// Close dropdown if clicked outside
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
if (
|
||||
dropdownRef.current &&
|
||||
!dropdownRef.current.contains(event.target as Node)
|
||||
) {
|
||||
setIsOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener("click", handleClickOutside);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener("click", handleClickOutside);
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Toggle the dropdown
|
||||
const toggleDropdown = () => {
|
||||
setIsOpen((prev) => !prev);
|
||||
};
|
||||
|
||||
// Handle option selection
|
||||
const handleOptionClick = (option: string) => {
|
||||
setSelectedOption(option);
|
||||
onSelect(option);
|
||||
setIsOpen(false);
|
||||
};
|
||||
|
||||
// Handle search input change
|
||||
const handleSearchChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const term = event.target.value;
|
||||
setSearchTerm(term);
|
||||
|
||||
// Filter options based on the search term
|
||||
const filtered = options.filter((option) =>
|
||||
option.toLowerCase().includes(term.toLowerCase())
|
||||
);
|
||||
setFilteredOptions(filtered);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="regularDropdown-container" ref={dropdownRef}>
|
||||
{/* Dropdown Header */}
|
||||
<div className="dropdown-header flex-sb" onClick={toggleDropdown}>
|
||||
<div className="key">{selectedOption || header}</div>
|
||||
<div className="icon">▾</div>
|
||||
</div>
|
||||
|
||||
{/* Dropdown Options */}
|
||||
{isOpen && (
|
||||
<div className="dropdown-options">
|
||||
{/* Search Bar */}
|
||||
{search && (
|
||||
<div className="dropdown-search">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search..."
|
||||
value={searchTerm}
|
||||
onChange={handleSearchChange}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Filtered Options */}
|
||||
{filteredOptions.length > 0 ? (
|
||||
filteredOptions.map((option, index) => (
|
||||
<div
|
||||
className="option"
|
||||
key={index}
|
||||
onClick={() => handleOptionClick(option)}
|
||||
>
|
||||
{option}
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<div className="no-options">No options found</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default RegularDropDown;
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
export const handleResize = (
|
||||
e: React.MouseEvent<HTMLDivElement>,
|
||||
containerRef: React.RefObject<HTMLDivElement | null>
|
||||
) => {
|
||||
if (!containerRef.current) return; // Ensure containerRef is not null
|
||||
const startY = e.clientY;
|
||||
const startHeight = containerRef.current.offsetHeight;
|
||||
|
||||
const onMouseMove = (moveEvent: MouseEvent) => {
|
||||
const newHeight = Math.max(
|
||||
120,
|
||||
Math.min(400, startHeight + moveEvent.clientY - startY)
|
||||
);
|
||||
containerRef.current!.style.height = `${newHeight}px`;
|
||||
};
|
||||
|
||||
const onMouseUp = () => {
|
||||
document.removeEventListener("mousemove", onMouseMove);
|
||||
document.removeEventListener("mouseup", onMouseUp);
|
||||
};
|
||||
|
||||
document.addEventListener("mousemove", onMouseMove);
|
||||
document.addEventListener("mouseup", onMouseUp);
|
||||
};
|
||||
export const handleResize = (
|
||||
e: React.MouseEvent<HTMLDivElement>,
|
||||
containerRef: React.RefObject<HTMLDivElement | null>
|
||||
) => {
|
||||
if (!containerRef.current) return; // Ensure containerRef is not null
|
||||
const startY = e.clientY;
|
||||
const startHeight = containerRef.current.offsetHeight;
|
||||
|
||||
const onMouseMove = (moveEvent: MouseEvent) => {
|
||||
const newHeight = Math.max(
|
||||
120,
|
||||
Math.min(400, startHeight + moveEvent.clientY - startY)
|
||||
);
|
||||
containerRef.current!.style.height = `${newHeight}px`;
|
||||
};
|
||||
|
||||
const onMouseUp = () => {
|
||||
document.removeEventListener("mousemove", onMouseMove);
|
||||
document.removeEventListener("mouseup", onMouseUp);
|
||||
};
|
||||
|
||||
document.addEventListener("mousemove", onMouseMove);
|
||||
document.addEventListener("mouseup", onMouseUp);
|
||||
};
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
||||
sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||
monospace;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
||||
sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||
monospace;
|
||||
}
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import './index.css';
|
||||
import App from './app';
|
||||
import reportWebVitals from './reportWebVitals';
|
||||
|
||||
const root = ReactDOM.createRoot(
|
||||
document.getElementById('root') as HTMLElement
|
||||
);
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>
|
||||
);
|
||||
|
||||
// If you want to start measuring performance in your app, pass a function
|
||||
// to log results (for example: reportWebVitals(console.log))
|
||||
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
|
||||
reportWebVitals();
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import './index.css';
|
||||
import App from './app';
|
||||
import reportWebVitals from './reportWebVitals';
|
||||
|
||||
const root = ReactDOM.createRoot(
|
||||
document.getElementById('root') as HTMLElement
|
||||
);
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>
|
||||
);
|
||||
|
||||
// If you want to start measuring performance in your app, pass a function
|
||||
// to log results (for example: reportWebVitals(console.log))
|
||||
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
|
||||
reportWebVitals();
|
||||
|
||||
@@ -1,54 +1,54 @@
|
||||
import * as THREE from "three";
|
||||
import { Geometry, Base, Subtraction } from "@react-three/csg";
|
||||
import { useDeleteModels } from "../../../store/store";
|
||||
import { useRef } from "react";
|
||||
|
||||
export interface CsgProps {
|
||||
position: THREE.Vector3 | [number, number, number];
|
||||
scale: THREE.Vector3 | [number, number, number];
|
||||
model: THREE.Object3D;
|
||||
hoveredDeletableWallItem: { current: THREE.Mesh | null };
|
||||
}
|
||||
|
||||
export const Csg: React.FC<CsgProps> = (props) => {
|
||||
const { deleteModels } = useDeleteModels();
|
||||
const modelRef = useRef<THREE.Object3D>();
|
||||
const originalMaterials = useRef<Map<THREE.Mesh, THREE.Material>>(new Map());
|
||||
|
||||
const handleHover = (hovered: boolean, object: THREE.Mesh | null) => {
|
||||
if (modelRef.current && deleteModels) {
|
||||
modelRef.current.traverse((child) => {
|
||||
if (child instanceof THREE.Mesh) {
|
||||
if (!originalMaterials.current.has(child)) {
|
||||
originalMaterials.current.set(child, child.material);
|
||||
}
|
||||
child.material = child.material.clone();
|
||||
child.material.color.set(hovered && deleteModels ? 0xff0000 : (originalMaterials.current.get(child) as any).color);
|
||||
}
|
||||
});
|
||||
}
|
||||
props.hoveredDeletableWallItem.current = hovered ? object : null;
|
||||
};
|
||||
|
||||
return (
|
||||
<Geometry>
|
||||
<Subtraction {...props}>
|
||||
<Geometry>
|
||||
<Base geometry={new THREE.BoxGeometry()} />
|
||||
</Geometry>
|
||||
</Subtraction>
|
||||
<primitive
|
||||
object={props.model}
|
||||
ref={modelRef}
|
||||
onPointerOver={(e: any) => {
|
||||
e.stopPropagation();
|
||||
handleHover(true, e.object.parent);
|
||||
}}
|
||||
onPointerOut={(e: any) => {
|
||||
e.stopPropagation();
|
||||
handleHover(false, null);
|
||||
}}
|
||||
/>
|
||||
</Geometry>
|
||||
);
|
||||
};
|
||||
import * as THREE from "three";
|
||||
import { Geometry, Base, Subtraction } from "@react-three/csg";
|
||||
import { useDeleteModels } from "../../../store/store";
|
||||
import { useRef } from "react";
|
||||
|
||||
export interface CsgProps {
|
||||
position: THREE.Vector3 | [number, number, number];
|
||||
scale: THREE.Vector3 | [number, number, number];
|
||||
model: THREE.Object3D;
|
||||
hoveredDeletableWallItem: { current: THREE.Mesh | null };
|
||||
}
|
||||
|
||||
export const Csg: React.FC<CsgProps> = (props) => {
|
||||
const { deleteModels } = useDeleteModels();
|
||||
const modelRef = useRef<THREE.Object3D>();
|
||||
const originalMaterials = useRef<Map<THREE.Mesh, THREE.Material>>(new Map());
|
||||
|
||||
const handleHover = (hovered: boolean, object: THREE.Mesh | null) => {
|
||||
if (modelRef.current && deleteModels) {
|
||||
modelRef.current.traverse((child) => {
|
||||
if (child instanceof THREE.Mesh) {
|
||||
if (!originalMaterials.current.has(child)) {
|
||||
originalMaterials.current.set(child, child.material);
|
||||
}
|
||||
child.material = child.material.clone();
|
||||
child.material.color.set(hovered && deleteModels ? 0xff0000 : (originalMaterials.current.get(child) as any).color);
|
||||
}
|
||||
});
|
||||
}
|
||||
props.hoveredDeletableWallItem.current = hovered ? object : null;
|
||||
};
|
||||
|
||||
return (
|
||||
<Geometry>
|
||||
<Subtraction {...props}>
|
||||
<Geometry>
|
||||
<Base geometry={new THREE.BoxGeometry()} />
|
||||
</Geometry>
|
||||
</Subtraction>
|
||||
<primitive
|
||||
object={props.model}
|
||||
ref={modelRef}
|
||||
onPointerOver={(e: any) => {
|
||||
e.stopPropagation();
|
||||
handleHover(true, e.object.parent);
|
||||
}}
|
||||
onPointerOut={(e: any) => {
|
||||
e.stopPropagation();
|
||||
handleHover(false, null);
|
||||
}}
|
||||
/>
|
||||
</Geometry>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,80 +1,80 @@
|
||||
import * as THREE from 'three';
|
||||
import { DragControls } from 'three/examples/jsm/controls/DragControls';
|
||||
import * as CONSTANTS from '../../../types/world/worldConstants';
|
||||
import DragPoint from '../geomentries/points/dragPoint';
|
||||
|
||||
import * as Types from "../../../types/world/worldTypes";
|
||||
// import { updatePoint } from '../../../services/factoryBuilder/lines/updatePointApi';
|
||||
import { Socket } from 'socket.io-client';
|
||||
|
||||
export default async function addDragControl(
|
||||
dragPointControls: Types.RefDragControl,
|
||||
currentLayerPoint: Types.RefMeshArray,
|
||||
state: Types.ThreeState,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
lines: Types.RefLines,
|
||||
onlyFloorlines: Types.RefOnlyFloorLines,
|
||||
socket: Socket<any>
|
||||
) {
|
||||
|
||||
////////// Dragging Point and also change the size to indicate during hover //////////
|
||||
|
||||
dragPointControls.current = new DragControls(currentLayerPoint.current, state.camera, state.gl.domElement);
|
||||
dragPointControls.current.enabled = false;
|
||||
|
||||
dragPointControls.current.addEventListener('drag', function (event) {
|
||||
const object = event.object;
|
||||
if (object.visible) {
|
||||
(state.controls as any).enabled = false;
|
||||
DragPoint(event as any, floorPlanGroupPoint, floorPlanGroupLine, state.scene, lines, onlyFloorlines)
|
||||
} else {
|
||||
(state.controls as any).enabled = true;
|
||||
}
|
||||
});
|
||||
|
||||
dragPointControls.current.addEventListener('dragstart', function (event) {
|
||||
});
|
||||
|
||||
dragPointControls.current.addEventListener('dragend', async function (event) {
|
||||
if (!dragPointControls.current) return;
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
//REST
|
||||
|
||||
// await updatePoint(
|
||||
// organization,
|
||||
// { "x": event.object.position.x, "y": 0.01, "z": event.object.position.z },
|
||||
// event.object.uuid,
|
||||
// )
|
||||
|
||||
//SOCKET
|
||||
|
||||
const data = {
|
||||
organization: organization,
|
||||
position: { "x": event.object.position.x, "y": 0.01, "z": event.object.position.z },
|
||||
uuid: event.object.uuid,
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
socket.emit('v1:Line:update', data);
|
||||
|
||||
if (state.controls) {
|
||||
(state.controls as any).enabled = true;
|
||||
}
|
||||
});
|
||||
|
||||
dragPointControls.current.addEventListener('hoveron', function (event: any) {
|
||||
if ((event.object as Types.Mesh).name === "point") {
|
||||
event.object.material.uniforms.uInnerColor.value.set(event.object.userData.color)
|
||||
}
|
||||
});
|
||||
|
||||
dragPointControls.current.addEventListener('hoveroff', function (event: any) {
|
||||
if ((event.object as Types.Mesh).name === "point") {
|
||||
event.object.material.uniforms.uInnerColor.value.set(new THREE.Color(CONSTANTS.pointConfig.defaultInnerColor))
|
||||
}
|
||||
});
|
||||
|
||||
import * as THREE from 'three';
|
||||
import { DragControls } from 'three/examples/jsm/controls/DragControls';
|
||||
import * as CONSTANTS from '../../../types/world/worldConstants';
|
||||
import DragPoint from '../geomentries/points/dragPoint';
|
||||
|
||||
import * as Types from "../../../types/world/worldTypes";
|
||||
// import { updatePoint } from '../../../services/factoryBuilder/lines/updatePointApi';
|
||||
import { Socket } from 'socket.io-client';
|
||||
|
||||
export default async function addDragControl(
|
||||
dragPointControls: Types.RefDragControl,
|
||||
currentLayerPoint: Types.RefMeshArray,
|
||||
state: Types.ThreeState,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
lines: Types.RefLines,
|
||||
onlyFloorlines: Types.RefOnlyFloorLines,
|
||||
socket: Socket<any>
|
||||
) {
|
||||
|
||||
////////// Dragging Point and also change the size to indicate during hover //////////
|
||||
|
||||
dragPointControls.current = new DragControls(currentLayerPoint.current, state.camera, state.gl.domElement);
|
||||
dragPointControls.current.enabled = false;
|
||||
|
||||
dragPointControls.current.addEventListener('drag', function (event) {
|
||||
const object = event.object;
|
||||
if (object.visible) {
|
||||
(state.controls as any).enabled = false;
|
||||
DragPoint(event as any, floorPlanGroupPoint, floorPlanGroupLine, state.scene, lines, onlyFloorlines)
|
||||
} else {
|
||||
(state.controls as any).enabled = true;
|
||||
}
|
||||
});
|
||||
|
||||
dragPointControls.current.addEventListener('dragstart', function (event) {
|
||||
});
|
||||
|
||||
dragPointControls.current.addEventListener('dragend', async function (event) {
|
||||
if (!dragPointControls.current) return;
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
//REST
|
||||
|
||||
// await updatePoint(
|
||||
// organization,
|
||||
// { "x": event.object.position.x, "y": 0.01, "z": event.object.position.z },
|
||||
// event.object.uuid,
|
||||
// )
|
||||
|
||||
//SOCKET
|
||||
|
||||
const data = {
|
||||
organization: organization,
|
||||
position: { "x": event.object.position.x, "y": 0.01, "z": event.object.position.z },
|
||||
uuid: event.object.uuid,
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
socket.emit('v1:Line:update', data);
|
||||
|
||||
if (state.controls) {
|
||||
(state.controls as any).enabled = true;
|
||||
}
|
||||
});
|
||||
|
||||
dragPointControls.current.addEventListener('hoveron', function (event: any) {
|
||||
if ((event.object as Types.Mesh).name === "point") {
|
||||
event.object.material.uniforms.uInnerColor.value.set(event.object.userData.color)
|
||||
}
|
||||
});
|
||||
|
||||
dragPointControls.current.addEventListener('hoveroff', function (event: any) {
|
||||
if ((event.object as Types.Mesh).name === "point") {
|
||||
event.object.material.uniforms.uInnerColor.value.set(new THREE.Color(CONSTANTS.pointConfig.defaultInnerColor))
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
import * as Types from "../../../types/world/worldTypes";
|
||||
|
||||
export default function handleContextMenu(
|
||||
menuVisible: Types.Boolean,
|
||||
setMenuVisible: Types.BooleanState
|
||||
): void {
|
||||
// setMenuVisible(true)
|
||||
import * as Types from "../../../types/world/worldTypes";
|
||||
|
||||
export default function handleContextMenu(
|
||||
menuVisible: Types.Boolean,
|
||||
setMenuVisible: Types.BooleanState
|
||||
): void {
|
||||
// setMenuVisible(true)
|
||||
}
|
||||
@@ -1,64 +1,64 @@
|
||||
import * as THREE from 'three';
|
||||
|
||||
import * as Types from "../../../types/world/worldTypes";
|
||||
|
||||
function handleMeshDown(
|
||||
event: Types.MeshEvent,
|
||||
currentWallItem: Types.RefMesh,
|
||||
setSelectedWallItem: Types.setSelectedWallItemSetState,
|
||||
setSelectedItemsIndex: Types.setSelectedItemsIndexSetState,
|
||||
wallItems: Types.wallItems,
|
||||
toggleView: Types.Boolean
|
||||
): void {
|
||||
|
||||
////////// To select which of the Wall item and CSG is selected to be dragged //////////
|
||||
|
||||
if (!toggleView) {
|
||||
if (currentWallItem.current) {
|
||||
currentWallItem.current.children.forEach((child) => {
|
||||
if ((child as THREE.Mesh).isMesh && child.name !== "CSG_REF") {
|
||||
const material = (child as THREE.Mesh).material;
|
||||
if (Array.isArray(material)) {
|
||||
material.forEach(mat => {
|
||||
if (mat instanceof THREE.MeshStandardMaterial) {
|
||||
mat.emissive = new THREE.Color("black");
|
||||
}
|
||||
});
|
||||
} else if (material instanceof THREE.MeshStandardMaterial) {
|
||||
material.emissive = new THREE.Color("black");
|
||||
}
|
||||
}
|
||||
});
|
||||
currentWallItem.current = null;
|
||||
setSelectedWallItem(null);
|
||||
setSelectedItemsIndex(null);
|
||||
}
|
||||
|
||||
if (event.intersections.length > 0) {
|
||||
const clickedIndex = wallItems.findIndex((item) => item.model === event.intersections[0]?.object?.parent?.parent);
|
||||
if (clickedIndex !== -1) {
|
||||
setSelectedItemsIndex(clickedIndex);
|
||||
const wallItemModel = wallItems[clickedIndex]?.model;
|
||||
if (wallItemModel && wallItemModel.parent && wallItemModel.parent.parent) {
|
||||
currentWallItem.current = (wallItemModel.parent.parent.children[0]?.children[1]?.children[0] as Types.Mesh) || null;
|
||||
setSelectedWallItem(wallItemModel.parent);
|
||||
// currentWallItem.current?.children.forEach((child) => {
|
||||
// if ((child as THREE.Mesh).isMesh && child.name !== "CSG_REF") {
|
||||
// const material = (child as THREE.Mesh).material;
|
||||
// if (Array.isArray(material)) {
|
||||
// material.forEach(mat => {
|
||||
// if (mat instanceof THREE.MeshStandardMaterial) {
|
||||
// mat.emissive = new THREE.Color("green");
|
||||
// }
|
||||
// });
|
||||
// } else if (material instanceof THREE.MeshStandardMaterial) {
|
||||
// material.emissive = new THREE.Color("green");
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
export default handleMeshDown;
|
||||
import * as THREE from 'three';
|
||||
|
||||
import * as Types from "../../../types/world/worldTypes";
|
||||
|
||||
function handleMeshDown(
|
||||
event: Types.MeshEvent,
|
||||
currentWallItem: Types.RefMesh,
|
||||
setSelectedWallItem: Types.setSelectedWallItemSetState,
|
||||
setSelectedItemsIndex: Types.setSelectedItemsIndexSetState,
|
||||
wallItems: Types.wallItems,
|
||||
toggleView: Types.Boolean
|
||||
): void {
|
||||
|
||||
////////// To select which of the Wall item and CSG is selected to be dragged //////////
|
||||
|
||||
if (!toggleView) {
|
||||
if (currentWallItem.current) {
|
||||
currentWallItem.current.children.forEach((child) => {
|
||||
if ((child as THREE.Mesh).isMesh && child.name !== "CSG_REF") {
|
||||
const material = (child as THREE.Mesh).material;
|
||||
if (Array.isArray(material)) {
|
||||
material.forEach(mat => {
|
||||
if (mat instanceof THREE.MeshStandardMaterial) {
|
||||
mat.emissive = new THREE.Color("black");
|
||||
}
|
||||
});
|
||||
} else if (material instanceof THREE.MeshStandardMaterial) {
|
||||
material.emissive = new THREE.Color("black");
|
||||
}
|
||||
}
|
||||
});
|
||||
currentWallItem.current = null;
|
||||
setSelectedWallItem(null);
|
||||
setSelectedItemsIndex(null);
|
||||
}
|
||||
|
||||
if (event.intersections.length > 0) {
|
||||
const clickedIndex = wallItems.findIndex((item) => item.model === event.intersections[0]?.object?.parent?.parent);
|
||||
if (clickedIndex !== -1) {
|
||||
setSelectedItemsIndex(clickedIndex);
|
||||
const wallItemModel = wallItems[clickedIndex]?.model;
|
||||
if (wallItemModel && wallItemModel.parent && wallItemModel.parent.parent) {
|
||||
currentWallItem.current = (wallItemModel.parent.parent.children[0]?.children[1]?.children[0] as Types.Mesh) || null;
|
||||
setSelectedWallItem(wallItemModel.parent);
|
||||
// currentWallItem.current?.children.forEach((child) => {
|
||||
// if ((child as THREE.Mesh).isMesh && child.name !== "CSG_REF") {
|
||||
// const material = (child as THREE.Mesh).material;
|
||||
// if (Array.isArray(material)) {
|
||||
// material.forEach(mat => {
|
||||
// if (mat instanceof THREE.MeshStandardMaterial) {
|
||||
// mat.emissive = new THREE.Color("green");
|
||||
// }
|
||||
// });
|
||||
// } else if (material instanceof THREE.MeshStandardMaterial) {
|
||||
// material.emissive = new THREE.Color("green");
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
export default handleMeshDown;
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
import * as THREE from 'three';
|
||||
import * as Types from "../../../types/world/worldTypes";
|
||||
|
||||
function handleMeshMissed(
|
||||
currentWallItem: Types.RefMesh,
|
||||
setSelectedWallItem: Types.setSelectedWallItemSetState,
|
||||
setSelectedItemsIndex: Types.setSelectedItemsIndexSetState
|
||||
): void {
|
||||
|
||||
////////// If an item is selected and then clicked outside other than the selected object, this runs and removes the color of the selected object and sets setSelectedWallItem and setSelectedItemsIndex as null //////////
|
||||
|
||||
if (currentWallItem.current) {
|
||||
currentWallItem.current.children.forEach((child) => {
|
||||
if ((child as THREE.Mesh).isMesh && child.name !== "CSG_REF") {
|
||||
const material = (child as THREE.Mesh).material;
|
||||
|
||||
if (Array.isArray(material)) {
|
||||
material.forEach(mat => {
|
||||
if (mat instanceof THREE.MeshStandardMaterial) {
|
||||
mat.emissive = new THREE.Color("black");
|
||||
}
|
||||
});
|
||||
} else if (material instanceof THREE.MeshStandardMaterial) {
|
||||
material.emissive = new THREE.Color("black");
|
||||
}
|
||||
}
|
||||
});
|
||||
currentWallItem.current = null;
|
||||
setSelectedWallItem(null);
|
||||
setSelectedItemsIndex(null);
|
||||
}
|
||||
}
|
||||
|
||||
export default handleMeshMissed;
|
||||
import * as THREE from 'three';
|
||||
import * as Types from "../../../types/world/worldTypes";
|
||||
|
||||
function handleMeshMissed(
|
||||
currentWallItem: Types.RefMesh,
|
||||
setSelectedWallItem: Types.setSelectedWallItemSetState,
|
||||
setSelectedItemsIndex: Types.setSelectedItemsIndexSetState
|
||||
): void {
|
||||
|
||||
////////// If an item is selected and then clicked outside other than the selected object, this runs and removes the color of the selected object and sets setSelectedWallItem and setSelectedItemsIndex as null //////////
|
||||
|
||||
if (currentWallItem.current) {
|
||||
currentWallItem.current.children.forEach((child) => {
|
||||
if ((child as THREE.Mesh).isMesh && child.name !== "CSG_REF") {
|
||||
const material = (child as THREE.Mesh).material;
|
||||
|
||||
if (Array.isArray(material)) {
|
||||
material.forEach(mat => {
|
||||
if (mat instanceof THREE.MeshStandardMaterial) {
|
||||
mat.emissive = new THREE.Color("black");
|
||||
}
|
||||
});
|
||||
} else if (material instanceof THREE.MeshStandardMaterial) {
|
||||
material.emissive = new THREE.Color("black");
|
||||
}
|
||||
}
|
||||
});
|
||||
currentWallItem.current = null;
|
||||
setSelectedWallItem(null);
|
||||
setSelectedItemsIndex(null);
|
||||
}
|
||||
}
|
||||
|
||||
export default handleMeshMissed;
|
||||
|
||||
@@ -1,87 +1,87 @@
|
||||
import * as THREE from 'three';
|
||||
import * as CONSTANTS from '../../../types/world/worldConstants';
|
||||
import * as Types from "../../../types/world/worldTypes";
|
||||
|
||||
function DeletableLineorPoint(
|
||||
state: Types.ThreeState,
|
||||
plane: Types.RefMesh,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
hoveredDeletableLine: Types.RefMesh,
|
||||
hoveredDeletablePoint: Types.RefMesh
|
||||
): void {
|
||||
|
||||
////////// Altering the color of the hovered line or point during the deletion time //////////
|
||||
|
||||
if (!plane.current) return;
|
||||
let intersects = state.raycaster.intersectObject(plane.current, true);
|
||||
|
||||
let visibleIntersectLines;
|
||||
if (floorPlanGroupLine.current) { visibleIntersectLines = state.raycaster?.intersectObjects(floorPlanGroupLine.current.children, true); }
|
||||
const visibleIntersectLine = visibleIntersectLines?.find(intersect => intersect.object.visible) as THREE.Line | undefined || null;
|
||||
|
||||
let visibleIntersectPoints;
|
||||
if (floorPlanGroupPoint.current) {
|
||||
visibleIntersectPoints = state.raycaster?.intersectObjects(floorPlanGroupPoint.current.children, true);
|
||||
}
|
||||
const visibleIntersectPoint = visibleIntersectPoints?.find(intersect => intersect.object.visible) as THREE.Mesh | undefined;
|
||||
|
||||
function getLineColor(lineType: string | undefined): string {
|
||||
switch (lineType) {
|
||||
case CONSTANTS.lineConfig.wallName: return CONSTANTS.lineConfig.wallColor;
|
||||
case CONSTANTS.lineConfig.floorName: return CONSTANTS.lineConfig.floorColor;
|
||||
case CONSTANTS.lineConfig.aisleName: return CONSTANTS.lineConfig.aisleColor;
|
||||
default: return CONSTANTS.lineConfig.defaultColor;
|
||||
}
|
||||
}
|
||||
|
||||
if (intersects.length > 0) {
|
||||
if (visibleIntersectPoint) {
|
||||
if (hoveredDeletableLine.current) {
|
||||
const lineType = hoveredDeletableLine.current.userData.linePoints[1]?.[3];
|
||||
const color = getLineColor(lineType);
|
||||
(hoveredDeletableLine.current.material as THREE.MeshBasicMaterial).color = new THREE.Color(color);
|
||||
hoveredDeletableLine.current = null;
|
||||
}
|
||||
|
||||
hoveredDeletablePoint.current = (visibleIntersectPoint as any).object;
|
||||
(hoveredDeletablePoint.current as any).material.uniforms.uInnerColor.value.set(new THREE.Color("red"));
|
||||
(hoveredDeletablePoint.current as any).material.uniforms.uColor.value.set(new THREE.Color("red"));
|
||||
// (hoveredDeletablePoint.current as THREE.Mesh).scale.set(1.5, 1.5, 1.5);
|
||||
} else if (hoveredDeletablePoint.current) {
|
||||
(hoveredDeletablePoint.current as any).material.uniforms.uInnerColor.value.set(CONSTANTS.pointConfig.defaultInnerColor);
|
||||
(hoveredDeletablePoint.current as any).material.uniforms.uColor.value.set((hoveredDeletablePoint.current as any).userData.color);
|
||||
// hoveredDeletablePoint.current.scale.set(1, 1, 1);
|
||||
hoveredDeletablePoint.current = null;
|
||||
}
|
||||
|
||||
if (visibleIntersectLine && !visibleIntersectPoint) {
|
||||
if (hoveredDeletableLine.current) {
|
||||
const lineType = hoveredDeletableLine.current.userData.linePoints[1]?.[3];
|
||||
const color = getLineColor(lineType);
|
||||
(hoveredDeletableLine.current.material as THREE.MeshBasicMaterial).color = new THREE.Color(color);
|
||||
hoveredDeletableLine.current = null;
|
||||
}
|
||||
|
||||
if (hoveredDeletablePoint.current) {
|
||||
(hoveredDeletablePoint.current as any).material.uniforms.uInnerColor.value.set(CONSTANTS.pointConfig.defaultInnerColor);
|
||||
(hoveredDeletablePoint.current as any).material.uniforms.uColor.value.set((hoveredDeletablePoint.current as any).userData.color);
|
||||
// hoveredDeletablePoint.current.scale.set(1, 1, 1);
|
||||
hoveredDeletablePoint.current = null;
|
||||
}
|
||||
|
||||
hoveredDeletableLine.current = (visibleIntersectLine as any).object;
|
||||
if (hoveredDeletableLine.current) {
|
||||
(hoveredDeletableLine.current.material as THREE.MeshBasicMaterial).color = new THREE.Color("red");
|
||||
}
|
||||
} else if (hoveredDeletableLine.current) {
|
||||
const lineType = hoveredDeletableLine.current.userData.linePoints[1]?.[3];
|
||||
const color = getLineColor(lineType);
|
||||
(hoveredDeletableLine.current.material as THREE.MeshBasicMaterial).color = new THREE.Color(color);
|
||||
hoveredDeletableLine.current = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default DeletableLineorPoint;
|
||||
import * as THREE from 'three';
|
||||
import * as CONSTANTS from '../../../types/world/worldConstants';
|
||||
import * as Types from "../../../types/world/worldTypes";
|
||||
|
||||
function DeletableLineorPoint(
|
||||
state: Types.ThreeState,
|
||||
plane: Types.RefMesh,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
hoveredDeletableLine: Types.RefMesh,
|
||||
hoveredDeletablePoint: Types.RefMesh
|
||||
): void {
|
||||
|
||||
////////// Altering the color of the hovered line or point during the deletion time //////////
|
||||
|
||||
if (!plane.current) return;
|
||||
let intersects = state.raycaster.intersectObject(plane.current, true);
|
||||
|
||||
let visibleIntersectLines;
|
||||
if (floorPlanGroupLine.current) { visibleIntersectLines = state.raycaster?.intersectObjects(floorPlanGroupLine.current.children, true); }
|
||||
const visibleIntersectLine = visibleIntersectLines?.find(intersect => intersect.object.visible) as THREE.Line | undefined || null;
|
||||
|
||||
let visibleIntersectPoints;
|
||||
if (floorPlanGroupPoint.current) {
|
||||
visibleIntersectPoints = state.raycaster?.intersectObjects(floorPlanGroupPoint.current.children, true);
|
||||
}
|
||||
const visibleIntersectPoint = visibleIntersectPoints?.find(intersect => intersect.object.visible) as THREE.Mesh | undefined;
|
||||
|
||||
function getLineColor(lineType: string | undefined): string {
|
||||
switch (lineType) {
|
||||
case CONSTANTS.lineConfig.wallName: return CONSTANTS.lineConfig.wallColor;
|
||||
case CONSTANTS.lineConfig.floorName: return CONSTANTS.lineConfig.floorColor;
|
||||
case CONSTANTS.lineConfig.aisleName: return CONSTANTS.lineConfig.aisleColor;
|
||||
default: return CONSTANTS.lineConfig.defaultColor;
|
||||
}
|
||||
}
|
||||
|
||||
if (intersects.length > 0) {
|
||||
if (visibleIntersectPoint) {
|
||||
if (hoveredDeletableLine.current) {
|
||||
const lineType = hoveredDeletableLine.current.userData.linePoints[1]?.[3];
|
||||
const color = getLineColor(lineType);
|
||||
(hoveredDeletableLine.current.material as THREE.MeshBasicMaterial).color = new THREE.Color(color);
|
||||
hoveredDeletableLine.current = null;
|
||||
}
|
||||
|
||||
hoveredDeletablePoint.current = (visibleIntersectPoint as any).object;
|
||||
(hoveredDeletablePoint.current as any).material.uniforms.uInnerColor.value.set(new THREE.Color("red"));
|
||||
(hoveredDeletablePoint.current as any).material.uniforms.uColor.value.set(new THREE.Color("red"));
|
||||
// (hoveredDeletablePoint.current as THREE.Mesh).scale.set(1.5, 1.5, 1.5);
|
||||
} else if (hoveredDeletablePoint.current) {
|
||||
(hoveredDeletablePoint.current as any).material.uniforms.uInnerColor.value.set(CONSTANTS.pointConfig.defaultInnerColor);
|
||||
(hoveredDeletablePoint.current as any).material.uniforms.uColor.value.set((hoveredDeletablePoint.current as any).userData.color);
|
||||
// hoveredDeletablePoint.current.scale.set(1, 1, 1);
|
||||
hoveredDeletablePoint.current = null;
|
||||
}
|
||||
|
||||
if (visibleIntersectLine && !visibleIntersectPoint) {
|
||||
if (hoveredDeletableLine.current) {
|
||||
const lineType = hoveredDeletableLine.current.userData.linePoints[1]?.[3];
|
||||
const color = getLineColor(lineType);
|
||||
(hoveredDeletableLine.current.material as THREE.MeshBasicMaterial).color = new THREE.Color(color);
|
||||
hoveredDeletableLine.current = null;
|
||||
}
|
||||
|
||||
if (hoveredDeletablePoint.current) {
|
||||
(hoveredDeletablePoint.current as any).material.uniforms.uInnerColor.value.set(CONSTANTS.pointConfig.defaultInnerColor);
|
||||
(hoveredDeletablePoint.current as any).material.uniforms.uColor.value.set((hoveredDeletablePoint.current as any).userData.color);
|
||||
// hoveredDeletablePoint.current.scale.set(1, 1, 1);
|
||||
hoveredDeletablePoint.current = null;
|
||||
}
|
||||
|
||||
hoveredDeletableLine.current = (visibleIntersectLine as any).object;
|
||||
if (hoveredDeletableLine.current) {
|
||||
(hoveredDeletableLine.current.material as THREE.MeshBasicMaterial).color = new THREE.Color("red");
|
||||
}
|
||||
} else if (hoveredDeletableLine.current) {
|
||||
const lineType = hoveredDeletableLine.current.userData.linePoints[1]?.[3];
|
||||
const color = getLineColor(lineType);
|
||||
(hoveredDeletableLine.current.material as THREE.MeshBasicMaterial).color = new THREE.Color(color);
|
||||
hoveredDeletableLine.current = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default DeletableLineorPoint;
|
||||
|
||||
@@ -1,97 +1,97 @@
|
||||
import * as Types from "../../../types/world/worldTypes";
|
||||
import * as CONSTANTS from '../../../types/world/worldConstants';
|
||||
import createAndMoveReferenceLine from "../geomentries/lines/createAndMoveReferenceLine";
|
||||
|
||||
async function Draw(
|
||||
state: Types.ThreeState,
|
||||
plane: Types.RefMesh,
|
||||
cursorPosition: Types.Vector3,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
snappedPoint: Types.RefVector3,
|
||||
isSnapped: Types.RefBoolean,
|
||||
isSnappedUUID: Types.RefString,
|
||||
line: Types.RefLine,
|
||||
lines: Types.RefLines,
|
||||
ispreSnapped: Types.RefBoolean,
|
||||
floorPlanGroup: Types.RefGroup,
|
||||
ReferenceLineMesh: Types.RefMesh,
|
||||
LineCreated: Types.RefBoolean,
|
||||
setRefTextUpdate: Types.NumberIncrementState,
|
||||
Tube: Types.RefTubeGeometry,
|
||||
anglesnappedPoint: Types.RefVector3,
|
||||
isAngleSnapped: Types.RefBoolean,
|
||||
toolMode: Types.String,
|
||||
): Promise<void> {
|
||||
|
||||
////////// Snapping the cursor during the drawing time and also changing the color of the intersected lines //////////
|
||||
|
||||
if (!plane.current) return;
|
||||
const intersects = state.raycaster.intersectObject(plane.current, true);
|
||||
|
||||
if (intersects.length > 0 && (toolMode === "Wall" || toolMode === "Aisle" || toolMode === "Floor")) {
|
||||
const intersectionPoint = intersects[0].point;
|
||||
cursorPosition.copy(intersectionPoint);
|
||||
const snapThreshold = 1;
|
||||
|
||||
if (line.current.length === 0) {
|
||||
for (const point of floorPlanGroupPoint.current.children) {
|
||||
const pointType = point.userData.type;
|
||||
|
||||
const canSnap =
|
||||
((toolMode === "Wall") && (pointType === CONSTANTS.lineConfig.wallName || pointType === CONSTANTS.lineConfig.floorName)) ||
|
||||
((toolMode === "Floor") && (pointType === CONSTANTS.lineConfig.wallName || pointType === CONSTANTS.lineConfig.floorName)) ||
|
||||
((toolMode === "Aisle") && pointType === CONSTANTS.lineConfig.aisleName);;
|
||||
|
||||
if (canSnap && cursorPosition.distanceTo(point.position) < snapThreshold + 0.5 && point.visible) {
|
||||
cursorPosition.copy(point.position);
|
||||
snappedPoint.current = point.position;
|
||||
ispreSnapped.current = true;
|
||||
isSnapped.current = false;
|
||||
isSnappedUUID.current = point.uuid;
|
||||
break;
|
||||
} else {
|
||||
ispreSnapped.current = false;
|
||||
}
|
||||
}
|
||||
} else if (line.current.length > 0 && line.current[0]) {
|
||||
for (const point of floorPlanGroupPoint.current.children) {
|
||||
const pointType = point.userData.type;
|
||||
|
||||
let canSnap =
|
||||
((toolMode === "Wall") && (pointType === CONSTANTS.lineConfig.wallName || pointType === CONSTANTS.lineConfig.floorName)) ||
|
||||
((toolMode === "Floor") && (pointType === CONSTANTS.lineConfig.wallName || pointType === CONSTANTS.lineConfig.floorName)) ||
|
||||
((toolMode === "Aisle") && pointType === CONSTANTS.lineConfig.aisleName);
|
||||
|
||||
if (canSnap && cursorPosition.distanceTo(point.position) < snapThreshold && point.visible) {
|
||||
cursorPosition.copy(point.position);
|
||||
snappedPoint.current = point.position;
|
||||
isSnapped.current = true;
|
||||
ispreSnapped.current = false;
|
||||
isSnappedUUID.current = point.uuid;
|
||||
break;
|
||||
} else {
|
||||
isSnapped.current = false;
|
||||
}
|
||||
}
|
||||
|
||||
createAndMoveReferenceLine(
|
||||
line.current[0][0],
|
||||
cursorPosition,
|
||||
isSnapped,
|
||||
ispreSnapped,
|
||||
line,
|
||||
setRefTextUpdate,
|
||||
floorPlanGroup,
|
||||
ReferenceLineMesh,
|
||||
LineCreated,
|
||||
Tube,
|
||||
anglesnappedPoint,
|
||||
isAngleSnapped
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
import * as Types from "../../../types/world/worldTypes";
|
||||
import * as CONSTANTS from '../../../types/world/worldConstants';
|
||||
import createAndMoveReferenceLine from "../geomentries/lines/createAndMoveReferenceLine";
|
||||
|
||||
async function Draw(
|
||||
state: Types.ThreeState,
|
||||
plane: Types.RefMesh,
|
||||
cursorPosition: Types.Vector3,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
snappedPoint: Types.RefVector3,
|
||||
isSnapped: Types.RefBoolean,
|
||||
isSnappedUUID: Types.RefString,
|
||||
line: Types.RefLine,
|
||||
lines: Types.RefLines,
|
||||
ispreSnapped: Types.RefBoolean,
|
||||
floorPlanGroup: Types.RefGroup,
|
||||
ReferenceLineMesh: Types.RefMesh,
|
||||
LineCreated: Types.RefBoolean,
|
||||
setRefTextUpdate: Types.NumberIncrementState,
|
||||
Tube: Types.RefTubeGeometry,
|
||||
anglesnappedPoint: Types.RefVector3,
|
||||
isAngleSnapped: Types.RefBoolean,
|
||||
toolMode: Types.String,
|
||||
): Promise<void> {
|
||||
|
||||
////////// Snapping the cursor during the drawing time and also changing the color of the intersected lines //////////
|
||||
|
||||
if (!plane.current) return;
|
||||
const intersects = state.raycaster.intersectObject(plane.current, true);
|
||||
|
||||
if (intersects.length > 0 && (toolMode === "Wall" || toolMode === "Aisle" || toolMode === "Floor")) {
|
||||
const intersectionPoint = intersects[0].point;
|
||||
cursorPosition.copy(intersectionPoint);
|
||||
const snapThreshold = 1;
|
||||
|
||||
if (line.current.length === 0) {
|
||||
for (const point of floorPlanGroupPoint.current.children) {
|
||||
const pointType = point.userData.type;
|
||||
|
||||
const canSnap =
|
||||
((toolMode === "Wall") && (pointType === CONSTANTS.lineConfig.wallName || pointType === CONSTANTS.lineConfig.floorName)) ||
|
||||
((toolMode === "Floor") && (pointType === CONSTANTS.lineConfig.wallName || pointType === CONSTANTS.lineConfig.floorName)) ||
|
||||
((toolMode === "Aisle") && pointType === CONSTANTS.lineConfig.aisleName);;
|
||||
|
||||
if (canSnap && cursorPosition.distanceTo(point.position) < snapThreshold + 0.5 && point.visible) {
|
||||
cursorPosition.copy(point.position);
|
||||
snappedPoint.current = point.position;
|
||||
ispreSnapped.current = true;
|
||||
isSnapped.current = false;
|
||||
isSnappedUUID.current = point.uuid;
|
||||
break;
|
||||
} else {
|
||||
ispreSnapped.current = false;
|
||||
}
|
||||
}
|
||||
} else if (line.current.length > 0 && line.current[0]) {
|
||||
for (const point of floorPlanGroupPoint.current.children) {
|
||||
const pointType = point.userData.type;
|
||||
|
||||
let canSnap =
|
||||
((toolMode === "Wall") && (pointType === CONSTANTS.lineConfig.wallName || pointType === CONSTANTS.lineConfig.floorName)) ||
|
||||
((toolMode === "Floor") && (pointType === CONSTANTS.lineConfig.wallName || pointType === CONSTANTS.lineConfig.floorName)) ||
|
||||
((toolMode === "Aisle") && pointType === CONSTANTS.lineConfig.aisleName);
|
||||
|
||||
if (canSnap && cursorPosition.distanceTo(point.position) < snapThreshold && point.visible) {
|
||||
cursorPosition.copy(point.position);
|
||||
snappedPoint.current = point.position;
|
||||
isSnapped.current = true;
|
||||
ispreSnapped.current = false;
|
||||
isSnappedUUID.current = point.uuid;
|
||||
break;
|
||||
} else {
|
||||
isSnapped.current = false;
|
||||
}
|
||||
}
|
||||
|
||||
createAndMoveReferenceLine(
|
||||
line.current[0][0],
|
||||
cursorPosition,
|
||||
isSnapped,
|
||||
ispreSnapped,
|
||||
line,
|
||||
setRefTextUpdate,
|
||||
floorPlanGroup,
|
||||
ReferenceLineMesh,
|
||||
LineCreated,
|
||||
Tube,
|
||||
anglesnappedPoint,
|
||||
isAngleSnapped
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Draw;
|
||||
@@ -1,56 +1,56 @@
|
||||
import * as THREE from 'three';
|
||||
import * as Types from '../../../../types/world/worldTypes';
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
|
||||
export default async function addAisleToScene(
|
||||
aisle: Types.Line,
|
||||
floorGroupAisle: Types.RefGroup,
|
||||
): Promise<void> {
|
||||
if (aisle.length >= 2 && aisle[0] && aisle[1]) {
|
||||
const start: Types.Vector3 = aisle[0][0];
|
||||
const end: Types.Vector3 = aisle[1][0];
|
||||
|
||||
const direction = new THREE.Vector3(
|
||||
end.x - start.x,
|
||||
end.y - start.y,
|
||||
end.z - start.z
|
||||
).normalize();
|
||||
|
||||
const perp = new THREE.Vector3(-direction.z, 0, direction.x).normalize();
|
||||
const offsetDistance = CONSTANTS.aisleConfig.width;
|
||||
|
||||
const leftStart = new THREE.Vector3().copy(start).addScaledVector(perp, offsetDistance);
|
||||
const rightStart = new THREE.Vector3().copy(start).addScaledVector(perp, -offsetDistance);
|
||||
const leftEnd = new THREE.Vector3().copy(end).addScaledVector(perp, offsetDistance);
|
||||
const rightEnd = new THREE.Vector3().copy(end).addScaledVector(perp, -offsetDistance);
|
||||
|
||||
const stripShape = new THREE.Shape();
|
||||
stripShape.moveTo(leftStart.x, leftStart.z);
|
||||
stripShape.lineTo(leftEnd.x, leftEnd.z);
|
||||
stripShape.lineTo(rightEnd.x, rightEnd.z);
|
||||
stripShape.lineTo(rightStart.x, rightStart.z);
|
||||
stripShape.lineTo(leftStart.x, leftStart.z);
|
||||
|
||||
const extrudeSettings = {
|
||||
depth: CONSTANTS.aisleConfig.height,
|
||||
bevelEnabled: false,
|
||||
};
|
||||
|
||||
const stripGeometry = new THREE.ExtrudeGeometry(stripShape, extrudeSettings);
|
||||
const stripMaterial = new THREE.MeshStandardMaterial({
|
||||
color: CONSTANTS.aisleConfig.defaultColor,
|
||||
polygonOffset: true,
|
||||
polygonOffsetFactor: -1,
|
||||
polygonOffsetUnits: -1,
|
||||
});
|
||||
|
||||
const stripMesh = new THREE.Mesh(stripGeometry, stripMaterial);
|
||||
stripMesh.receiveShadow = true;
|
||||
stripMesh.castShadow = true;
|
||||
|
||||
stripMesh.position.y = (aisle[0][2] - 1) * CONSTANTS.wallConfig.height + 0.01;
|
||||
stripMesh.rotateX(Math.PI / 2);
|
||||
|
||||
floorGroupAisle.current.add(stripMesh);
|
||||
}
|
||||
}
|
||||
import * as THREE from 'three';
|
||||
import * as Types from '../../../../types/world/worldTypes';
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
|
||||
export default async function addAisleToScene(
|
||||
aisle: Types.Line,
|
||||
floorGroupAisle: Types.RefGroup,
|
||||
): Promise<void> {
|
||||
if (aisle.length >= 2 && aisle[0] && aisle[1]) {
|
||||
const start: Types.Vector3 = aisle[0][0];
|
||||
const end: Types.Vector3 = aisle[1][0];
|
||||
|
||||
const direction = new THREE.Vector3(
|
||||
end.x - start.x,
|
||||
end.y - start.y,
|
||||
end.z - start.z
|
||||
).normalize();
|
||||
|
||||
const perp = new THREE.Vector3(-direction.z, 0, direction.x).normalize();
|
||||
const offsetDistance = CONSTANTS.aisleConfig.width;
|
||||
|
||||
const leftStart = new THREE.Vector3().copy(start).addScaledVector(perp, offsetDistance);
|
||||
const rightStart = new THREE.Vector3().copy(start).addScaledVector(perp, -offsetDistance);
|
||||
const leftEnd = new THREE.Vector3().copy(end).addScaledVector(perp, offsetDistance);
|
||||
const rightEnd = new THREE.Vector3().copy(end).addScaledVector(perp, -offsetDistance);
|
||||
|
||||
const stripShape = new THREE.Shape();
|
||||
stripShape.moveTo(leftStart.x, leftStart.z);
|
||||
stripShape.lineTo(leftEnd.x, leftEnd.z);
|
||||
stripShape.lineTo(rightEnd.x, rightEnd.z);
|
||||
stripShape.lineTo(rightStart.x, rightStart.z);
|
||||
stripShape.lineTo(leftStart.x, leftStart.z);
|
||||
|
||||
const extrudeSettings = {
|
||||
depth: CONSTANTS.aisleConfig.height,
|
||||
bevelEnabled: false,
|
||||
};
|
||||
|
||||
const stripGeometry = new THREE.ExtrudeGeometry(stripShape, extrudeSettings);
|
||||
const stripMaterial = new THREE.MeshStandardMaterial({
|
||||
color: CONSTANTS.aisleConfig.defaultColor,
|
||||
polygonOffset: true,
|
||||
polygonOffsetFactor: -1,
|
||||
polygonOffsetUnits: -1,
|
||||
});
|
||||
|
||||
const stripMesh = new THREE.Mesh(stripGeometry, stripMaterial);
|
||||
stripMesh.receiveShadow = true;
|
||||
stripMesh.castShadow = true;
|
||||
|
||||
stripMesh.position.y = (aisle[0][2] - 1) * CONSTANTS.wallConfig.height + 0.01;
|
||||
stripMesh.rotateX(Math.PI / 2);
|
||||
|
||||
floorGroupAisle.current.add(stripMesh);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import * as Types from '../../../../types/world/worldTypes';
|
||||
import addAisleToScene from './addAilseToScene';
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
|
||||
export default async function loadAisles(
|
||||
lines: Types.RefLines,
|
||||
floorGroupAisle: Types.RefGroup
|
||||
) {
|
||||
// console.log('lines: ', lines.current[0][0][0]);
|
||||
if (!floorGroupAisle.current) return
|
||||
floorGroupAisle.current.children = [];
|
||||
const aisles = lines.current.filter((line) => line[0][3] && line[1][3] === CONSTANTS.lineConfig.aisleName);
|
||||
|
||||
if (aisles.length > 0) {
|
||||
aisles.forEach((aisle: Types.Line) => {
|
||||
addAisleToScene(aisle, floorGroupAisle)
|
||||
})
|
||||
}
|
||||
import * as Types from '../../../../types/world/worldTypes';
|
||||
import addAisleToScene from './addAilseToScene';
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
|
||||
export default async function loadAisles(
|
||||
lines: Types.RefLines,
|
||||
floorGroupAisle: Types.RefGroup
|
||||
) {
|
||||
// console.log('lines: ', lines.current[0][0][0]);
|
||||
if (!floorGroupAisle.current) return
|
||||
floorGroupAisle.current.children = [];
|
||||
const aisles = lines.current.filter((line) => line[0][3] && line[1][3] === CONSTANTS.lineConfig.aisleName);
|
||||
|
||||
if (aisles.length > 0) {
|
||||
aisles.forEach((aisle: Types.Line) => {
|
||||
addAisleToScene(aisle, floorGroupAisle)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,186 +1,186 @@
|
||||
import * as THREE from 'three';
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
|
||||
import gsap from 'gsap';
|
||||
import { toast } from 'react-toastify';
|
||||
import TempLoader from './tempLoader';
|
||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import { retrieveGLTF, storeGLTF } from '../../../../utils/indexDB/idbUtils';
|
||||
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
|
||||
import { Socket } from 'socket.io-client';
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
|
||||
async function addAssetModel(
|
||||
raycaster: THREE.Raycaster,
|
||||
camera: THREE.Camera,
|
||||
pointer: THREE.Vector2,
|
||||
floorGroup: Types.RefGroup,
|
||||
setFloorItems: Types.setFloorItemSetState,
|
||||
itemsGroup: Types.RefGroup,
|
||||
isTempLoader: Types.RefBoolean,
|
||||
tempLoader: Types.RefMesh,
|
||||
socket: Socket<any>,
|
||||
selectedItem: any,
|
||||
setSelectedItem: any,
|
||||
plane: Types.RefMesh,
|
||||
): Promise<void> {
|
||||
|
||||
////////// Load Floor GLtf's and set the positions, rotation, type etc. in state and store in localstorage //////////
|
||||
|
||||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||
|
||||
try {
|
||||
isTempLoader.current = true;
|
||||
const loader = new GLTFLoader();
|
||||
const dracoLoader = new DRACOLoader();
|
||||
|
||||
dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/');
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
raycaster.setFromCamera(pointer, camera);
|
||||
const floorIntersections = raycaster.intersectObjects(floorGroup.current.children, true);
|
||||
const intersectedFloor = floorIntersections.find(intersect => intersect.object.name.includes("Floor"));
|
||||
|
||||
const planeIntersections = raycaster.intersectObject(plane.current!, true);
|
||||
const intersectedPlane = planeIntersections[0];
|
||||
|
||||
let intersectPoint: THREE.Vector3 | null = null;
|
||||
|
||||
if (intersectedFloor && intersectedPlane) {
|
||||
intersectPoint = intersectedFloor.distance < intersectedPlane.distance ? (new THREE.Vector3(intersectedFloor.point.x, Math.round(intersectedFloor.point.y), intersectedFloor.point.z)) : (new THREE.Vector3(intersectedPlane.point.x, 0, intersectedPlane.point.z));
|
||||
} else if (intersectedFloor) {
|
||||
intersectPoint = new THREE.Vector3(intersectedFloor.point.x, Math.round(intersectedFloor.point.y), intersectedFloor.point.z);
|
||||
} else if (intersectedPlane) {
|
||||
intersectPoint = new THREE.Vector3(intersectedPlane.point.x, 0, intersectedPlane.point.z);
|
||||
}
|
||||
|
||||
if (intersectPoint) {
|
||||
if (intersectPoint.y < 0) {
|
||||
intersectPoint = new THREE.Vector3(intersectPoint.x, 0, intersectPoint.z);
|
||||
}
|
||||
const cachedModel = THREE.Cache.get(selectedItem.id);
|
||||
if (cachedModel) {
|
||||
// console.log(`[Cache] Fetching ${selectedItem.name}`);
|
||||
handleModelLoad(cachedModel, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, socket);
|
||||
return;
|
||||
} else {
|
||||
const cachedModelBlob = await retrieveGLTF(selectedItem.id);
|
||||
|
||||
if (cachedModelBlob) {
|
||||
// console.log(`Added ${selectedItem.name} from indexDB`);
|
||||
|
||||
const blobUrl = URL.createObjectURL(cachedModelBlob);
|
||||
loader.load(blobUrl, (gltf) => {
|
||||
URL.revokeObjectURL(blobUrl);
|
||||
THREE.Cache.remove(blobUrl);
|
||||
THREE.Cache.add(selectedItem.id, gltf);
|
||||
handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, socket);
|
||||
},
|
||||
() => {
|
||||
TempLoader(intersectPoint!, isTempLoader, tempLoader, itemsGroup);
|
||||
});
|
||||
} else {
|
||||
// console.log(`Added ${selectedItem.name} from Backend`);
|
||||
|
||||
loader.load(`${url_Backend_dwinzo}/api/v1/AssetFile/${selectedItem.id}`, async (gltf) => {
|
||||
const modelBlob = await fetch(`${url_Backend_dwinzo}/api/v1/AssetFile/${selectedItem.id}`).then((res) => res.blob());
|
||||
await storeGLTF(selectedItem.id, modelBlob);
|
||||
THREE.Cache.add(selectedItem.id, gltf);
|
||||
await handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, socket);
|
||||
},
|
||||
() => {
|
||||
TempLoader(intersectPoint!, isTempLoader, tempLoader, itemsGroup);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching asset model:', error);
|
||||
} finally {
|
||||
setSelectedItem({});
|
||||
}
|
||||
}
|
||||
|
||||
async function handleModelLoad(
|
||||
gltf: any,
|
||||
intersectPoint: THREE.Vector3,
|
||||
selectedItem: any,
|
||||
itemsGroup: Types.RefGroup,
|
||||
tempLoader: Types.RefMesh,
|
||||
isTempLoader: Types.RefBoolean,
|
||||
setFloorItems: Types.setFloorItemSetState,
|
||||
socket: Socket<any>
|
||||
) {
|
||||
const model = gltf.scene.clone();
|
||||
model.userData = { name: selectedItem.name, modelId: selectedItem.id };
|
||||
model.position.set(intersectPoint!.x, 3 + intersectPoint!.y, intersectPoint!.z);
|
||||
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
|
||||
|
||||
model.traverse((child: any) => {
|
||||
if (child) {
|
||||
child.castShadow = true;
|
||||
child.receiveShadow = true;
|
||||
}
|
||||
});
|
||||
|
||||
itemsGroup.current.add(model);
|
||||
if (tempLoader.current) {
|
||||
(<any>tempLoader.current.material).dispose();
|
||||
(<any>tempLoader.current.geometry).dispose();
|
||||
itemsGroup.current.remove(tempLoader.current);
|
||||
tempLoader.current = undefined;
|
||||
}
|
||||
|
||||
const newFloorItem: Types.FloorItemType = {
|
||||
modeluuid: model.uuid,
|
||||
modelname: selectedItem.name,
|
||||
modelfileID: selectedItem.id,
|
||||
position: [intersectPoint!.x, intersectPoint!.y, intersectPoint!.z],
|
||||
rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z, },
|
||||
isLocked: false,
|
||||
isVisible: true
|
||||
};
|
||||
|
||||
setFloorItems((prevItems) => {
|
||||
const updatedItems = [...(prevItems || []), newFloorItem];
|
||||
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
|
||||
return updatedItems;
|
||||
});
|
||||
|
||||
const email = localStorage.getItem("email");
|
||||
const organization = email ? email.split("@")[1].split(".")[0] : "default";
|
||||
|
||||
//REST
|
||||
|
||||
// await setFloorItemApi(
|
||||
// organization,
|
||||
// newFloorItem.modeluuid,
|
||||
// newFloorItem.modelname,
|
||||
// newFloorItem.position,
|
||||
// { "x": model.rotation.x, "y": model.rotation.y, "z": model.rotation.z },
|
||||
// newFloorItem.modelfileID!,
|
||||
// false,
|
||||
// true,
|
||||
// );
|
||||
|
||||
//SOCKET
|
||||
|
||||
const data = {
|
||||
organization,
|
||||
modeluuid: newFloorItem.modeluuid,
|
||||
modelname: newFloorItem.modelname,
|
||||
modelfileID: newFloorItem.modelfileID,
|
||||
position: newFloorItem.position,
|
||||
rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
|
||||
isLocked: false,
|
||||
isVisible: true,
|
||||
socketId: socket.id,
|
||||
};
|
||||
|
||||
socket.emit("v1:FloorItems:set", data);
|
||||
|
||||
gsap.to(model.position, { y: newFloorItem.position[1], duration: 1.5, ease: "power2.out" });
|
||||
gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: "power2.out", onComplete: () => { toast.success("Model Added!"); } });
|
||||
}
|
||||
|
||||
export default addAssetModel;
|
||||
import * as THREE from 'three';
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
|
||||
import gsap from 'gsap';
|
||||
import { toast } from 'react-toastify';
|
||||
import TempLoader from './tempLoader';
|
||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import { retrieveGLTF, storeGLTF } from '../../../../utils/indexDB/idbUtils';
|
||||
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
|
||||
import { Socket } from 'socket.io-client';
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
|
||||
async function addAssetModel(
|
||||
raycaster: THREE.Raycaster,
|
||||
camera: THREE.Camera,
|
||||
pointer: THREE.Vector2,
|
||||
floorGroup: Types.RefGroup,
|
||||
setFloorItems: Types.setFloorItemSetState,
|
||||
itemsGroup: Types.RefGroup,
|
||||
isTempLoader: Types.RefBoolean,
|
||||
tempLoader: Types.RefMesh,
|
||||
socket: Socket<any>,
|
||||
selectedItem: any,
|
||||
setSelectedItem: any,
|
||||
plane: Types.RefMesh,
|
||||
): Promise<void> {
|
||||
|
||||
////////// Load Floor GLtf's and set the positions, rotation, type etc. in state and store in localstorage //////////
|
||||
|
||||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||
|
||||
try {
|
||||
isTempLoader.current = true;
|
||||
const loader = new GLTFLoader();
|
||||
const dracoLoader = new DRACOLoader();
|
||||
|
||||
dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/');
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
raycaster.setFromCamera(pointer, camera);
|
||||
const floorIntersections = raycaster.intersectObjects(floorGroup.current.children, true);
|
||||
const intersectedFloor = floorIntersections.find(intersect => intersect.object.name.includes("Floor"));
|
||||
|
||||
const planeIntersections = raycaster.intersectObject(plane.current!, true);
|
||||
const intersectedPlane = planeIntersections[0];
|
||||
|
||||
let intersectPoint: THREE.Vector3 | null = null;
|
||||
|
||||
if (intersectedFloor && intersectedPlane) {
|
||||
intersectPoint = intersectedFloor.distance < intersectedPlane.distance ? (new THREE.Vector3(intersectedFloor.point.x, Math.round(intersectedFloor.point.y), intersectedFloor.point.z)) : (new THREE.Vector3(intersectedPlane.point.x, 0, intersectedPlane.point.z));
|
||||
} else if (intersectedFloor) {
|
||||
intersectPoint = new THREE.Vector3(intersectedFloor.point.x, Math.round(intersectedFloor.point.y), intersectedFloor.point.z);
|
||||
} else if (intersectedPlane) {
|
||||
intersectPoint = new THREE.Vector3(intersectedPlane.point.x, 0, intersectedPlane.point.z);
|
||||
}
|
||||
|
||||
if (intersectPoint) {
|
||||
if (intersectPoint.y < 0) {
|
||||
intersectPoint = new THREE.Vector3(intersectPoint.x, 0, intersectPoint.z);
|
||||
}
|
||||
const cachedModel = THREE.Cache.get(selectedItem.id);
|
||||
if (cachedModel) {
|
||||
// console.log(`[Cache] Fetching ${selectedItem.name}`);
|
||||
handleModelLoad(cachedModel, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, socket);
|
||||
return;
|
||||
} else {
|
||||
const cachedModelBlob = await retrieveGLTF(selectedItem.id);
|
||||
|
||||
if (cachedModelBlob) {
|
||||
// console.log(`Added ${selectedItem.name} from indexDB`);
|
||||
|
||||
const blobUrl = URL.createObjectURL(cachedModelBlob);
|
||||
loader.load(blobUrl, (gltf) => {
|
||||
URL.revokeObjectURL(blobUrl);
|
||||
THREE.Cache.remove(blobUrl);
|
||||
THREE.Cache.add(selectedItem.id, gltf);
|
||||
handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, socket);
|
||||
},
|
||||
() => {
|
||||
TempLoader(intersectPoint!, isTempLoader, tempLoader, itemsGroup);
|
||||
});
|
||||
} else {
|
||||
// console.log(`Added ${selectedItem.name} from Backend`);
|
||||
|
||||
loader.load(`${url_Backend_dwinzo}/api/v1/AssetFile/${selectedItem.id}`, async (gltf) => {
|
||||
const modelBlob = await fetch(`${url_Backend_dwinzo}/api/v1/AssetFile/${selectedItem.id}`).then((res) => res.blob());
|
||||
await storeGLTF(selectedItem.id, modelBlob);
|
||||
THREE.Cache.add(selectedItem.id, gltf);
|
||||
await handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, socket);
|
||||
},
|
||||
() => {
|
||||
TempLoader(intersectPoint!, isTempLoader, tempLoader, itemsGroup);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching asset model:', error);
|
||||
} finally {
|
||||
setSelectedItem({});
|
||||
}
|
||||
}
|
||||
|
||||
async function handleModelLoad(
|
||||
gltf: any,
|
||||
intersectPoint: THREE.Vector3,
|
||||
selectedItem: any,
|
||||
itemsGroup: Types.RefGroup,
|
||||
tempLoader: Types.RefMesh,
|
||||
isTempLoader: Types.RefBoolean,
|
||||
setFloorItems: Types.setFloorItemSetState,
|
||||
socket: Socket<any>
|
||||
) {
|
||||
const model = gltf.scene.clone();
|
||||
model.userData = { name: selectedItem.name, modelId: selectedItem.id };
|
||||
model.position.set(intersectPoint!.x, 3 + intersectPoint!.y, intersectPoint!.z);
|
||||
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
|
||||
|
||||
model.traverse((child: any) => {
|
||||
if (child) {
|
||||
child.castShadow = true;
|
||||
child.receiveShadow = true;
|
||||
}
|
||||
});
|
||||
|
||||
itemsGroup.current.add(model);
|
||||
if (tempLoader.current) {
|
||||
(<any>tempLoader.current.material).dispose();
|
||||
(<any>tempLoader.current.geometry).dispose();
|
||||
itemsGroup.current.remove(tempLoader.current);
|
||||
tempLoader.current = undefined;
|
||||
}
|
||||
|
||||
const newFloorItem: Types.FloorItemType = {
|
||||
modeluuid: model.uuid,
|
||||
modelname: selectedItem.name,
|
||||
modelfileID: selectedItem.id,
|
||||
position: [intersectPoint!.x, intersectPoint!.y, intersectPoint!.z],
|
||||
rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z, },
|
||||
isLocked: false,
|
||||
isVisible: true
|
||||
};
|
||||
|
||||
setFloorItems((prevItems) => {
|
||||
const updatedItems = [...(prevItems || []), newFloorItem];
|
||||
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
|
||||
return updatedItems;
|
||||
});
|
||||
|
||||
const email = localStorage.getItem("email");
|
||||
const organization = email ? email.split("@")[1].split(".")[0] : "default";
|
||||
|
||||
//REST
|
||||
|
||||
// await setFloorItemApi(
|
||||
// organization,
|
||||
// newFloorItem.modeluuid,
|
||||
// newFloorItem.modelname,
|
||||
// newFloorItem.position,
|
||||
// { "x": model.rotation.x, "y": model.rotation.y, "z": model.rotation.z },
|
||||
// newFloorItem.modelfileID!,
|
||||
// false,
|
||||
// true,
|
||||
// );
|
||||
|
||||
//SOCKET
|
||||
|
||||
const data = {
|
||||
organization,
|
||||
modeluuid: newFloorItem.modeluuid,
|
||||
modelname: newFloorItem.modelname,
|
||||
modelfileID: newFloorItem.modelfileID,
|
||||
position: newFloorItem.position,
|
||||
rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
|
||||
isLocked: false,
|
||||
isVisible: true,
|
||||
socketId: socket.id,
|
||||
};
|
||||
|
||||
socket.emit("v1:FloorItems:set", data);
|
||||
|
||||
gsap.to(model.position, { y: newFloorItem.position[1], duration: 1.5, ease: "power2.out" });
|
||||
gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: "power2.out", onComplete: () => { toast.success("Model Added!"); } });
|
||||
}
|
||||
|
||||
export default addAssetModel;
|
||||
|
||||
@@ -1,153 +1,153 @@
|
||||
import * as THREE from "three";
|
||||
import gsap from "gsap";
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
|
||||
import { initializeDB, retrieveGLTF, storeGLTF } from "../../../../utils/indexDB/idbUtils";
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||
let currentTaskId = 0; // Track the active task
|
||||
let activePromises = new Map<number, boolean>(); // Map to track task progress
|
||||
|
||||
export default async function assetManager(
|
||||
data: any,
|
||||
itemsGroup: Types.RefGroup,
|
||||
loader: GLTFLoader,
|
||||
) {
|
||||
const taskId = ++currentTaskId; // Increment taskId for each call
|
||||
activePromises.set(taskId, true); // Mark task as active
|
||||
|
||||
// console.log("Received message from worker:", data);
|
||||
|
||||
if (data.toRemove.length > 0) {
|
||||
data.toRemove.forEach((uuid: string) => {
|
||||
const item = itemsGroup.current.getObjectByProperty("uuid", uuid);
|
||||
if (item) {
|
||||
// Traverse and dispose of resources
|
||||
// item.traverse((child: THREE.Object3D) => {
|
||||
// if (child instanceof THREE.Mesh) {
|
||||
// if (child.geometry) child.geometry.dispose();
|
||||
// if (Array.isArray(child.material)) {
|
||||
// child.material.forEach((material) => {
|
||||
// if (material.map) material.map.dispose();
|
||||
// material.dispose();
|
||||
// });
|
||||
// } else if (child.material) {
|
||||
// if (child.material.map) child.material.map.dispose();
|
||||
// child.material.dispose();
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
// Remove the object from the scene
|
||||
itemsGroup.current.remove(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (data.toAdd.length > 0) {
|
||||
await initializeDB();
|
||||
|
||||
for (const item of data.toAdd) {
|
||||
if (!activePromises.get(taskId)) return; // Stop processing if task is canceled
|
||||
|
||||
await new Promise<void>(async (resolve) => {
|
||||
const modelUrl = `${url_Backend_dwinzo}/api/v1/AssetFile/${item.modelfileID!}`;
|
||||
|
||||
// Check Three.js Cache
|
||||
const cachedModel = THREE.Cache.get(item.modelfileID!);
|
||||
if (cachedModel) {
|
||||
// console.log(`[Cache] Fetching ${item.modelname}`);
|
||||
processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, resolve);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check IndexedDB
|
||||
const indexedDBModel = await retrieveGLTF(item.modelfileID!);
|
||||
if (indexedDBModel) {
|
||||
// console.log(`[IndexedDB] Fetching ${item.modelname}`);
|
||||
const blobUrl = URL.createObjectURL(indexedDBModel);
|
||||
loader.load(
|
||||
blobUrl,
|
||||
(gltf) => {
|
||||
URL.revokeObjectURL(blobUrl);
|
||||
THREE.Cache.remove(blobUrl);
|
||||
THREE.Cache.add(item.modelfileID!, gltf); // Add to cache
|
||||
processLoadedModel(gltf.scene.clone(), item, itemsGroup, resolve);
|
||||
},
|
||||
undefined,
|
||||
(error) => {
|
||||
toast.error(`[IndexedDB] Error loading ${item.modelname}:`);
|
||||
resolve();
|
||||
}
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch from Backend
|
||||
// console.log(`[Backend] Fetching ${item.modelname}`);
|
||||
loader.load(
|
||||
modelUrl,
|
||||
async (gltf) => {
|
||||
const modelBlob = await fetch(modelUrl).then((res) => res.blob());
|
||||
await storeGLTF(item.modelfileID!, modelBlob); // Store in IndexedDB
|
||||
THREE.Cache.add(item.modelfileID!, gltf); // Add to cache
|
||||
processLoadedModel(gltf.scene.clone(), item, itemsGroup, resolve);
|
||||
},
|
||||
undefined,
|
||||
(error) => {
|
||||
toast.error(`[Backend] Error loading ${item.modelname}:`);
|
||||
resolve();
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function processLoadedModel(
|
||||
gltf: any,
|
||||
item: Types.FloorItemType,
|
||||
itemsGroup: Types.RefGroup,
|
||||
resolve: () => void
|
||||
) {
|
||||
if (!activePromises.get(taskId)) return; // Stop processing if task is canceled
|
||||
|
||||
const existingModel = itemsGroup.current.getObjectByProperty("uuid", item.modeluuid);
|
||||
if (existingModel) {
|
||||
// console.log(`Model ${item.modelname} already exists in the scene.`);
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
const model = gltf;
|
||||
model.uuid = item.modeluuid;
|
||||
model.userData = { name: item.modelname, modelId: item.modelfileID };
|
||||
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
|
||||
model.position.set(...item.position);
|
||||
model.rotation.set(item.rotation.x, item.rotation.y, item.rotation.z);
|
||||
|
||||
model.traverse((child: any) => {
|
||||
if (child.isMesh) {
|
||||
// Clone the material to ensure changes are independent
|
||||
// child.material = child.material.clone();
|
||||
|
||||
child.castShadow = true;
|
||||
child.receiveShadow = true;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
itemsGroup?.current?.add(model);
|
||||
|
||||
gsap.to(model.position, { y: item.position[1], duration: 1.5, ease: "power2.out" });
|
||||
gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 0.5, ease: "power2.out", onStart: resolve, });
|
||||
}
|
||||
}
|
||||
|
||||
activePromises.delete(taskId); // Mark task as complete
|
||||
}
|
||||
|
||||
// Cancel ongoing task when new call arrives
|
||||
export function cancelOngoingTasks() {
|
||||
activePromises.clear(); // Clear all ongoing tasks
|
||||
}
|
||||
import * as THREE from "three";
|
||||
import gsap from "gsap";
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
|
||||
import { initializeDB, retrieveGLTF, storeGLTF } from "../../../../utils/indexDB/idbUtils";
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||
let currentTaskId = 0; // Track the active task
|
||||
let activePromises = new Map<number, boolean>(); // Map to track task progress
|
||||
|
||||
export default async function assetManager(
|
||||
data: any,
|
||||
itemsGroup: Types.RefGroup,
|
||||
loader: GLTFLoader,
|
||||
) {
|
||||
const taskId = ++currentTaskId; // Increment taskId for each call
|
||||
activePromises.set(taskId, true); // Mark task as active
|
||||
|
||||
// console.log("Received message from worker:", data);
|
||||
|
||||
if (data.toRemove.length > 0) {
|
||||
data.toRemove.forEach((uuid: string) => {
|
||||
const item = itemsGroup.current.getObjectByProperty("uuid", uuid);
|
||||
if (item) {
|
||||
// Traverse and dispose of resources
|
||||
// item.traverse((child: THREE.Object3D) => {
|
||||
// if (child instanceof THREE.Mesh) {
|
||||
// if (child.geometry) child.geometry.dispose();
|
||||
// if (Array.isArray(child.material)) {
|
||||
// child.material.forEach((material) => {
|
||||
// if (material.map) material.map.dispose();
|
||||
// material.dispose();
|
||||
// });
|
||||
// } else if (child.material) {
|
||||
// if (child.material.map) child.material.map.dispose();
|
||||
// child.material.dispose();
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
// Remove the object from the scene
|
||||
itemsGroup.current.remove(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (data.toAdd.length > 0) {
|
||||
await initializeDB();
|
||||
|
||||
for (const item of data.toAdd) {
|
||||
if (!activePromises.get(taskId)) return; // Stop processing if task is canceled
|
||||
|
||||
await new Promise<void>(async (resolve) => {
|
||||
const modelUrl = `${url_Backend_dwinzo}/api/v1/AssetFile/${item.modelfileID!}`;
|
||||
|
||||
// Check Three.js Cache
|
||||
const cachedModel = THREE.Cache.get(item.modelfileID!);
|
||||
if (cachedModel) {
|
||||
// console.log(`[Cache] Fetching ${item.modelname}`);
|
||||
processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, resolve);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check IndexedDB
|
||||
const indexedDBModel = await retrieveGLTF(item.modelfileID!);
|
||||
if (indexedDBModel) {
|
||||
// console.log(`[IndexedDB] Fetching ${item.modelname}`);
|
||||
const blobUrl = URL.createObjectURL(indexedDBModel);
|
||||
loader.load(
|
||||
blobUrl,
|
||||
(gltf) => {
|
||||
URL.revokeObjectURL(blobUrl);
|
||||
THREE.Cache.remove(blobUrl);
|
||||
THREE.Cache.add(item.modelfileID!, gltf); // Add to cache
|
||||
processLoadedModel(gltf.scene.clone(), item, itemsGroup, resolve);
|
||||
},
|
||||
undefined,
|
||||
(error) => {
|
||||
toast.error(`[IndexedDB] Error loading ${item.modelname}:`);
|
||||
resolve();
|
||||
}
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch from Backend
|
||||
// console.log(`[Backend] Fetching ${item.modelname}`);
|
||||
loader.load(
|
||||
modelUrl,
|
||||
async (gltf) => {
|
||||
const modelBlob = await fetch(modelUrl).then((res) => res.blob());
|
||||
await storeGLTF(item.modelfileID!, modelBlob); // Store in IndexedDB
|
||||
THREE.Cache.add(item.modelfileID!, gltf); // Add to cache
|
||||
processLoadedModel(gltf.scene.clone(), item, itemsGroup, resolve);
|
||||
},
|
||||
undefined,
|
||||
(error) => {
|
||||
toast.error(`[Backend] Error loading ${item.modelname}:`);
|
||||
resolve();
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function processLoadedModel(
|
||||
gltf: any,
|
||||
item: Types.FloorItemType,
|
||||
itemsGroup: Types.RefGroup,
|
||||
resolve: () => void
|
||||
) {
|
||||
if (!activePromises.get(taskId)) return; // Stop processing if task is canceled
|
||||
|
||||
const existingModel = itemsGroup.current.getObjectByProperty("uuid", item.modeluuid);
|
||||
if (existingModel) {
|
||||
// console.log(`Model ${item.modelname} already exists in the scene.`);
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
const model = gltf;
|
||||
model.uuid = item.modeluuid;
|
||||
model.userData = { name: item.modelname, modelId: item.modelfileID };
|
||||
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
|
||||
model.position.set(...item.position);
|
||||
model.rotation.set(item.rotation.x, item.rotation.y, item.rotation.z);
|
||||
|
||||
model.traverse((child: any) => {
|
||||
if (child.isMesh) {
|
||||
// Clone the material to ensure changes are independent
|
||||
// child.material = child.material.clone();
|
||||
|
||||
child.castShadow = true;
|
||||
child.receiveShadow = true;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
itemsGroup?.current?.add(model);
|
||||
|
||||
gsap.to(model.position, { y: item.position[1], duration: 1.5, ease: "power2.out" });
|
||||
gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 0.5, ease: "power2.out", onStart: resolve, });
|
||||
}
|
||||
}
|
||||
|
||||
activePromises.delete(taskId); // Mark task as complete
|
||||
}
|
||||
|
||||
// Cancel ongoing task when new call arrives
|
||||
export function cancelOngoingTasks() {
|
||||
activePromises.clear(); // Clear all ongoing tasks
|
||||
}
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
let lastUpdateTime = 0;
|
||||
|
||||
export default function assetVisibility(
|
||||
itemsGroup: Types.RefGroup,
|
||||
cameraPosition: Types.Vector3,
|
||||
renderDistance: Types.Number,
|
||||
throttleTime = 100
|
||||
): void {
|
||||
const now = performance.now();
|
||||
if (now - lastUpdateTime < throttleTime) return;
|
||||
lastUpdateTime = now;
|
||||
|
||||
if (!itemsGroup?.current || !cameraPosition) return;
|
||||
|
||||
itemsGroup.current.children.forEach((child) => {
|
||||
const Distance = cameraPosition.distanceTo(child.position);
|
||||
if (Distance <= renderDistance) {
|
||||
child.visible = true;
|
||||
} else {
|
||||
child.visible = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
let lastUpdateTime = 0;
|
||||
|
||||
export default function assetVisibility(
|
||||
itemsGroup: Types.RefGroup,
|
||||
cameraPosition: Types.Vector3,
|
||||
renderDistance: Types.Number,
|
||||
throttleTime = 100
|
||||
): void {
|
||||
const now = performance.now();
|
||||
if (now - lastUpdateTime < throttleTime) return;
|
||||
lastUpdateTime = now;
|
||||
|
||||
if (!itemsGroup?.current || !cameraPosition) return;
|
||||
|
||||
itemsGroup.current.children.forEach((child) => {
|
||||
const Distance = cameraPosition.distanceTo(child.position);
|
||||
if (Distance <= renderDistance) {
|
||||
child.visible = true;
|
||||
} else {
|
||||
child.visible = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,43 +1,43 @@
|
||||
import * as THREE from 'three';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function DeletableHoveredFloorItems(
|
||||
state: Types.ThreeState,
|
||||
itemsGroup: Types.RefGroup,
|
||||
hoveredDeletableFloorItem: Types.RefMesh,
|
||||
setDeletableFloorItem: any
|
||||
): void {
|
||||
|
||||
////////// Altering the color of the hovered GLTF item during the Deletion time //////////
|
||||
|
||||
state.raycaster.setFromCamera(state.pointer, state.camera);
|
||||
const intersects = state.raycaster.intersectObjects(itemsGroup.current.children, true);
|
||||
|
||||
if (intersects.length > 0) {
|
||||
if (intersects[0].object.name === "Pole") {
|
||||
return;
|
||||
}
|
||||
if (hoveredDeletableFloorItem.current) {
|
||||
hoveredDeletableFloorItem.current = undefined;
|
||||
setDeletableFloorItem(null);
|
||||
}
|
||||
let currentObject = intersects[0].object;
|
||||
|
||||
while (currentObject) {
|
||||
if (currentObject.name === "Scene") {
|
||||
hoveredDeletableFloorItem.current = currentObject as THREE.Mesh;
|
||||
setDeletableFloorItem(currentObject);
|
||||
break;
|
||||
}
|
||||
currentObject = currentObject.parent as THREE.Object3D;
|
||||
}
|
||||
} else {
|
||||
if (hoveredDeletableFloorItem.current) {
|
||||
hoveredDeletableFloorItem.current = undefined;
|
||||
setDeletableFloorItem(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default DeletableHoveredFloorItems;
|
||||
import * as THREE from 'three';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function DeletableHoveredFloorItems(
|
||||
state: Types.ThreeState,
|
||||
itemsGroup: Types.RefGroup,
|
||||
hoveredDeletableFloorItem: Types.RefMesh,
|
||||
setDeletableFloorItem: any
|
||||
): void {
|
||||
|
||||
////////// Altering the color of the hovered GLTF item during the Deletion time //////////
|
||||
|
||||
state.raycaster.setFromCamera(state.pointer, state.camera);
|
||||
const intersects = state.raycaster.intersectObjects(itemsGroup.current.children, true);
|
||||
|
||||
if (intersects.length > 0) {
|
||||
if (intersects[0].object.name === "Pole") {
|
||||
return;
|
||||
}
|
||||
if (hoveredDeletableFloorItem.current) {
|
||||
hoveredDeletableFloorItem.current = undefined;
|
||||
setDeletableFloorItem(null);
|
||||
}
|
||||
let currentObject = intersects[0].object;
|
||||
|
||||
while (currentObject) {
|
||||
if (currentObject.name === "Scene") {
|
||||
hoveredDeletableFloorItem.current = currentObject as THREE.Mesh;
|
||||
setDeletableFloorItem(currentObject);
|
||||
break;
|
||||
}
|
||||
currentObject = currentObject.parent as THREE.Object3D;
|
||||
}
|
||||
} else {
|
||||
if (hoveredDeletableFloorItem.current) {
|
||||
hoveredDeletableFloorItem.current = undefined;
|
||||
setDeletableFloorItem(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default DeletableHoveredFloorItems;
|
||||
|
||||
@@ -1,82 +1,82 @@
|
||||
import { toast } from 'react-toastify';
|
||||
import * as THREE from 'three';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import { getFloorItems } from '../../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi';
|
||||
// import { deleteFloorItem } from '../../../../services/factoryBuilder/assest/floorAsset/deleteFloorItemApi';
|
||||
import { Socket } from 'socket.io-client';
|
||||
|
||||
async function DeleteFloorItems(
|
||||
itemsGroup: Types.RefGroup,
|
||||
hoveredDeletableFloorItem: Types.RefMesh,
|
||||
setFloorItems: Types.setFloorItemSetState,
|
||||
socket: Socket<any>
|
||||
): Promise<void> {
|
||||
|
||||
////////// Deleting the hovered Floor GLTF from the scene (itemsGroup.current) and from the floorItems and also update it in the localstorage //////////
|
||||
|
||||
if (hoveredDeletableFloorItem.current) {
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
const items = await getFloorItems(organization);
|
||||
const removedItem = items.find(
|
||||
(item: { modeluuid: string }) => item.modeluuid === hoveredDeletableFloorItem.current?.uuid
|
||||
);
|
||||
|
||||
if (!removedItem) {
|
||||
return
|
||||
}
|
||||
|
||||
//REST
|
||||
|
||||
// const response = await deleteFloorItem(organization, removedItem.modeluuid, removedItem.modelname);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const data = {
|
||||
organization: organization,
|
||||
modeluuid: removedItem.modeluuid,
|
||||
modelname: removedItem.modelname,
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
const response = socket.emit('v1:FloorItems:delete', data)
|
||||
|
||||
if (response) {
|
||||
const updatedItems = items.filter(
|
||||
(item: { modeluuid: string }) => item.modeluuid !== hoveredDeletableFloorItem.current?.uuid
|
||||
);
|
||||
|
||||
const storedItems = JSON.parse(localStorage.getItem("FloorItems") || '[]');
|
||||
const updatedStoredItems = storedItems.filter((item: { modeluuid: string }) => item.modeluuid !== hoveredDeletableFloorItem.current?.uuid);
|
||||
localStorage.setItem("FloorItems", JSON.stringify(updatedStoredItems));
|
||||
|
||||
if (hoveredDeletableFloorItem.current) {
|
||||
// Traverse and dispose of resources
|
||||
hoveredDeletableFloorItem.current.traverse((child: THREE.Object3D) => {
|
||||
if (child instanceof THREE.Mesh) {
|
||||
if (child.geometry) child.geometry.dispose();
|
||||
if (Array.isArray(child.material)) {
|
||||
child.material.forEach((material) => {
|
||||
if (material.map) material.map.dispose();
|
||||
material.dispose();
|
||||
});
|
||||
} else if (child.material) {
|
||||
if (child.material.map) child.material.map.dispose();
|
||||
child.material.dispose();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Remove the object from the scene
|
||||
itemsGroup.current.remove(hoveredDeletableFloorItem.current);
|
||||
}
|
||||
setFloorItems(updatedItems);
|
||||
toast.success("Model Removed!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default DeleteFloorItems;
|
||||
import { toast } from 'react-toastify';
|
||||
import * as THREE from 'three';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import { getFloorItems } from '../../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi';
|
||||
// import { deleteFloorItem } from '../../../../services/factoryBuilder/assest/floorAsset/deleteFloorItemApi';
|
||||
import { Socket } from 'socket.io-client';
|
||||
|
||||
async function DeleteFloorItems(
|
||||
itemsGroup: Types.RefGroup,
|
||||
hoveredDeletableFloorItem: Types.RefMesh,
|
||||
setFloorItems: Types.setFloorItemSetState,
|
||||
socket: Socket<any>
|
||||
): Promise<void> {
|
||||
|
||||
////////// Deleting the hovered Floor GLTF from the scene (itemsGroup.current) and from the floorItems and also update it in the localstorage //////////
|
||||
|
||||
if (hoveredDeletableFloorItem.current) {
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
const items = await getFloorItems(organization);
|
||||
const removedItem = items.find(
|
||||
(item: { modeluuid: string }) => item.modeluuid === hoveredDeletableFloorItem.current?.uuid
|
||||
);
|
||||
|
||||
if (!removedItem) {
|
||||
return
|
||||
}
|
||||
|
||||
//REST
|
||||
|
||||
// const response = await deleteFloorItem(organization, removedItem.modeluuid, removedItem.modelname);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const data = {
|
||||
organization: organization,
|
||||
modeluuid: removedItem.modeluuid,
|
||||
modelname: removedItem.modelname,
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
const response = socket.emit('v1:FloorItems:delete', data)
|
||||
|
||||
if (response) {
|
||||
const updatedItems = items.filter(
|
||||
(item: { modeluuid: string }) => item.modeluuid !== hoveredDeletableFloorItem.current?.uuid
|
||||
);
|
||||
|
||||
const storedItems = JSON.parse(localStorage.getItem("FloorItems") || '[]');
|
||||
const updatedStoredItems = storedItems.filter((item: { modeluuid: string }) => item.modeluuid !== hoveredDeletableFloorItem.current?.uuid);
|
||||
localStorage.setItem("FloorItems", JSON.stringify(updatedStoredItems));
|
||||
|
||||
if (hoveredDeletableFloorItem.current) {
|
||||
// Traverse and dispose of resources
|
||||
hoveredDeletableFloorItem.current.traverse((child: THREE.Object3D) => {
|
||||
if (child instanceof THREE.Mesh) {
|
||||
if (child.geometry) child.geometry.dispose();
|
||||
if (Array.isArray(child.material)) {
|
||||
child.material.forEach((material) => {
|
||||
if (material.map) material.map.dispose();
|
||||
material.dispose();
|
||||
});
|
||||
} else if (child.material) {
|
||||
if (child.material.map) child.material.map.dispose();
|
||||
child.material.dispose();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Remove the object from the scene
|
||||
itemsGroup.current.remove(hoveredDeletableFloorItem.current);
|
||||
}
|
||||
setFloorItems(updatedItems);
|
||||
toast.success("Model Removed!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default DeleteFloorItems;
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
import * as THREE from 'three';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function TempLoader(
|
||||
intersectPoint: Types.Vector3,
|
||||
isTempLoader: Types.RefBoolean,
|
||||
tempLoader: Types.RefMesh,
|
||||
itemsGroup: Types.RefGroup
|
||||
): void {
|
||||
|
||||
////////// Temporary Loader that indicates the gltf is being loaded //////////
|
||||
|
||||
////////// Bug: Can't Load More than one TempLoader if done, it won't leave the scene //////////
|
||||
|
||||
if (tempLoader.current) {
|
||||
itemsGroup.current.remove(tempLoader.current);
|
||||
}
|
||||
if (isTempLoader.current) {
|
||||
const cubeGeometry = new THREE.BoxGeometry(1, 1, 1);
|
||||
const cubeMaterial = new THREE.MeshBasicMaterial({ color: "white" });
|
||||
tempLoader.current = new THREE.Mesh(cubeGeometry, cubeMaterial);
|
||||
tempLoader.current.position.set(intersectPoint.x, 0.5 + intersectPoint.y, intersectPoint.z);
|
||||
itemsGroup.current.add(tempLoader.current);
|
||||
isTempLoader.current = false;
|
||||
}
|
||||
}
|
||||
|
||||
export default TempLoader;
|
||||
import * as THREE from 'three';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function TempLoader(
|
||||
intersectPoint: Types.Vector3,
|
||||
isTempLoader: Types.RefBoolean,
|
||||
tempLoader: Types.RefMesh,
|
||||
itemsGroup: Types.RefGroup
|
||||
): void {
|
||||
|
||||
////////// Temporary Loader that indicates the gltf is being loaded //////////
|
||||
|
||||
////////// Bug: Can't Load More than one TempLoader if done, it won't leave the scene //////////
|
||||
|
||||
if (tempLoader.current) {
|
||||
itemsGroup.current.remove(tempLoader.current);
|
||||
}
|
||||
if (isTempLoader.current) {
|
||||
const cubeGeometry = new THREE.BoxGeometry(1, 1, 1);
|
||||
const cubeMaterial = new THREE.MeshBasicMaterial({ color: "white" });
|
||||
tempLoader.current = new THREE.Mesh(cubeGeometry, cubeMaterial);
|
||||
tempLoader.current.position.set(intersectPoint.x, 0.5 + intersectPoint.y, intersectPoint.z);
|
||||
itemsGroup.current.add(tempLoader.current);
|
||||
isTempLoader.current = false;
|
||||
}
|
||||
}
|
||||
|
||||
export default TempLoader;
|
||||
|
||||
@@ -1,64 +1,64 @@
|
||||
import * as THREE from 'three';
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import * as CONSTANTS from "../../../../types/world/worldConstants";
|
||||
|
||||
import texturePath from "../../../../assets/textures/floor/concreteFloorWorn001Diff2k.jpg";
|
||||
import normalPath from "../../../../assets/textures/floor/concreteFloorWorn001NorGl2k.jpg";
|
||||
|
||||
// Cache for materials
|
||||
const materialCache = new Map<string, THREE.Material>();
|
||||
|
||||
export default function addFloorToScene(
|
||||
shape: THREE.Shape,
|
||||
layer: number,
|
||||
floorGroup: Types.RefGroup,
|
||||
userData: any,
|
||||
) {
|
||||
const textureLoader = new THREE.TextureLoader();
|
||||
|
||||
const textureScale = CONSTANTS.floorConfig.textureScale;
|
||||
|
||||
const materialKey = `floorMaterial_${textureScale}`;
|
||||
|
||||
let material: THREE.Material;
|
||||
|
||||
if (materialCache.has(materialKey)) {
|
||||
material = materialCache.get(materialKey) as THREE.Material;
|
||||
} else {
|
||||
const floorTexture = textureLoader.load(texturePath);
|
||||
const normalMap = textureLoader.load(normalPath);
|
||||
|
||||
floorTexture.wrapS = floorTexture.wrapT = THREE.RepeatWrapping;
|
||||
floorTexture.repeat.set(textureScale, textureScale);
|
||||
floorTexture.colorSpace = THREE.SRGBColorSpace;
|
||||
|
||||
normalMap.wrapS = normalMap.wrapT = THREE.RepeatWrapping;
|
||||
normalMap.repeat.set(textureScale, textureScale);
|
||||
|
||||
material = new THREE.MeshStandardMaterial({
|
||||
map: floorTexture,
|
||||
normalMap: normalMap,
|
||||
side: THREE.DoubleSide,
|
||||
});
|
||||
|
||||
materialCache.set(materialKey, material);
|
||||
}
|
||||
|
||||
const extrudeSettings = {
|
||||
depth: CONSTANTS.floorConfig.height,
|
||||
bevelEnabled: false,
|
||||
};
|
||||
|
||||
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
|
||||
const mesh = new THREE.Mesh(geometry, material);
|
||||
|
||||
mesh.receiveShadow = true;
|
||||
mesh.position.y = layer;
|
||||
mesh.rotateX(Math.PI / 2);
|
||||
mesh.name = `Floor_Layer_${layer}`;
|
||||
|
||||
// Store UUIDs for debugging or future processing
|
||||
mesh.userData.uuids = userData;
|
||||
|
||||
floorGroup.current.add(mesh);
|
||||
}
|
||||
import * as THREE from 'three';
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import * as CONSTANTS from "../../../../types/world/worldConstants";
|
||||
|
||||
import texturePath from "../../../../assets/textures/floor/concreteFloorWorn001Diff2k.jpg";
|
||||
import normalPath from "../../../../assets/textures/floor/concreteFloorWorn001NorGl2k.jpg";
|
||||
|
||||
// Cache for materials
|
||||
const materialCache = new Map<string, THREE.Material>();
|
||||
|
||||
export default function addFloorToScene(
|
||||
shape: THREE.Shape,
|
||||
layer: number,
|
||||
floorGroup: Types.RefGroup,
|
||||
userData: any,
|
||||
) {
|
||||
const textureLoader = new THREE.TextureLoader();
|
||||
|
||||
const textureScale = CONSTANTS.floorConfig.textureScale;
|
||||
|
||||
const materialKey = `floorMaterial_${textureScale}`;
|
||||
|
||||
let material: THREE.Material;
|
||||
|
||||
if (materialCache.has(materialKey)) {
|
||||
material = materialCache.get(materialKey) as THREE.Material;
|
||||
} else {
|
||||
const floorTexture = textureLoader.load(texturePath);
|
||||
const normalMap = textureLoader.load(normalPath);
|
||||
|
||||
floorTexture.wrapS = floorTexture.wrapT = THREE.RepeatWrapping;
|
||||
floorTexture.repeat.set(textureScale, textureScale);
|
||||
floorTexture.colorSpace = THREE.SRGBColorSpace;
|
||||
|
||||
normalMap.wrapS = normalMap.wrapT = THREE.RepeatWrapping;
|
||||
normalMap.repeat.set(textureScale, textureScale);
|
||||
|
||||
material = new THREE.MeshStandardMaterial({
|
||||
map: floorTexture,
|
||||
normalMap: normalMap,
|
||||
side: THREE.DoubleSide,
|
||||
});
|
||||
|
||||
materialCache.set(materialKey, material);
|
||||
}
|
||||
|
||||
const extrudeSettings = {
|
||||
depth: CONSTANTS.floorConfig.height,
|
||||
bevelEnabled: false,
|
||||
};
|
||||
|
||||
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
|
||||
const mesh = new THREE.Mesh(geometry, material);
|
||||
|
||||
mesh.receiveShadow = true;
|
||||
mesh.position.y = layer;
|
||||
mesh.rotateX(Math.PI / 2);
|
||||
mesh.name = `Floor_Layer_${layer}`;
|
||||
|
||||
// Store UUIDs for debugging or future processing
|
||||
mesh.userData.uuids = userData;
|
||||
|
||||
floorGroup.current.add(mesh);
|
||||
}
|
||||
|
||||
@@ -1,179 +1,179 @@
|
||||
import * as THREE from 'three';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
|
||||
import addPointToScene from '../points/addPointToScene';
|
||||
import addLineToScene from '../lines/addLineToScene';
|
||||
import splitLine from '../lines/splitLine';
|
||||
import removeReferenceLine from '../lines/removeReferenceLine';
|
||||
import getClosestIntersection from '../lines/getClosestIntersection';
|
||||
import arrayLineToObject from '../lines/lineConvertions/arrayLineToObject';
|
||||
// import { setLine } from '../../../../services/factoryBuilder/lines/setLineApi';
|
||||
import { Socket } from 'socket.io-client';
|
||||
|
||||
async function drawOnlyFloor(
|
||||
raycaster: THREE.Raycaster,
|
||||
state: Types.ThreeState,
|
||||
camera: THREE.Camera,
|
||||
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,
|
||||
onlyFloorline: Types.RefOnlyFloorLine,
|
||||
onlyFloorlines: Types.RefOnlyFloorLines,
|
||||
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>
|
||||
): Promise<void> {
|
||||
|
||||
////////// Creating lines Based on the positions clicked //////////
|
||||
|
||||
if (!plane.current) return
|
||||
const intersects = raycaster.intersectObject(plane.current, true);
|
||||
const intersectsLines = raycaster.intersectObjects(floorPlanGroupLine.current.children, true);
|
||||
const 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);
|
||||
|
||||
if ((intersectsPoint.length === 0 || VisibleintersectsPoint === undefined) && intersectsLines.length > 0 && !isSnapped.current && !ispreSnapped.current) {
|
||||
|
||||
////////// Clicked on a preexisting Line //////////
|
||||
|
||||
if (visibleIntersect && (intersectsLines[0].object.userData.linePoints[0][3] === CONSTANTS.lineConfig.floorName || intersectsLines[0].object.userData.linePoints[0][3] === CONSTANTS.lineConfig.wallName)) {
|
||||
let pointColor, lineColor;
|
||||
if (intersectsLines[0].object.userData.linePoints[0][3] === CONSTANTS.lineConfig.wallName) {
|
||||
pointColor = CONSTANTS.pointConfig.wallOuterColor;
|
||||
lineColor = CONSTANTS.lineConfig.wallColor;
|
||||
} else {
|
||||
pointColor = CONSTANTS.pointConfig.floorOuterColor;
|
||||
lineColor = CONSTANTS.lineConfig.floorColor;
|
||||
}
|
||||
let IntersectsPoint = new THREE.Vector3(intersects[0].point.x, 0.01, intersects[0].point.z);
|
||||
if (isAngleSnapped.current && line.current.length > 0 && 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, pointColor, lineColor, intersectsLines[0].object.userData.linePoints[0][3]);
|
||||
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.floorName]);
|
||||
|
||||
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
|
||||
lines.current.push(line.current as Types.Line);
|
||||
const data = arrayLineToObject(line.current as Types.Line);
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
//REST
|
||||
|
||||
// setLine(organization, data.layer!, data.line!, data.type!);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const input = {
|
||||
organization: organization,
|
||||
layer: data.layer,
|
||||
line: data.line,
|
||||
type: data.type,
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
socket.emit('v1:Line:create', input);
|
||||
|
||||
setNewLines([newLines[0], newLines[1], line.current]);
|
||||
onlyFloorline.current.push(line.current as Types.Line);
|
||||
onlyFloorlines.current.push(onlyFloorline.current);
|
||||
onlyFloorline.current = [];
|
||||
|
||||
addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.lineConfig.floorColor, line.current, floorPlanGroupLine);
|
||||
|
||||
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (intersects.length > 0 && intersectsLines.length === 0) {
|
||||
|
||||
////////// Clicked on an empty place or a 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 (!isSnapped.current && !ispreSnapped.current) {
|
||||
addPointToScene(intersectionPoint, CONSTANTS.pointConfig.floorOuterColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, isSnappedUUID, CONSTANTS.lineConfig.floorName);
|
||||
} 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.floorName]);
|
||||
|
||||
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
|
||||
onlyFloorline.current.push(line.current as Types.Line);
|
||||
lines.current.push(line.current as Types.Line);
|
||||
const data = arrayLineToObject(line.current as Types.Line);
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
//REST
|
||||
|
||||
// setLine(organization, data.layer!, data.line!, data.type!);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const input = {
|
||||
organization: organization,
|
||||
layer: data.layer,
|
||||
line: data.line,
|
||||
type: data.type,
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
socket.emit('v1:Line:create', input);
|
||||
|
||||
setNewLines([line.current]);
|
||||
addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.lineConfig.floorColor, line.current, floorPlanGroupLine);
|
||||
const lastPoint = line.current[line.current.length - 1];
|
||||
line.current = [lastPoint];
|
||||
}
|
||||
if (isSnapped.current) { ////////// Add this to stop the drawing mode after snapping //////////
|
||||
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
|
||||
onlyFloorlines.current.push(onlyFloorline.current);
|
||||
onlyFloorline.current = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
import * as THREE from 'three';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
|
||||
import addPointToScene from '../points/addPointToScene';
|
||||
import addLineToScene from '../lines/addLineToScene';
|
||||
import splitLine from '../lines/splitLine';
|
||||
import removeReferenceLine from '../lines/removeReferenceLine';
|
||||
import getClosestIntersection from '../lines/getClosestIntersection';
|
||||
import arrayLineToObject from '../lines/lineConvertions/arrayLineToObject';
|
||||
// import { setLine } from '../../../../services/factoryBuilder/lines/setLineApi';
|
||||
import { Socket } from 'socket.io-client';
|
||||
|
||||
async function drawOnlyFloor(
|
||||
raycaster: THREE.Raycaster,
|
||||
state: Types.ThreeState,
|
||||
camera: THREE.Camera,
|
||||
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,
|
||||
onlyFloorline: Types.RefOnlyFloorLine,
|
||||
onlyFloorlines: Types.RefOnlyFloorLines,
|
||||
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>
|
||||
): Promise<void> {
|
||||
|
||||
////////// Creating lines Based on the positions clicked //////////
|
||||
|
||||
if (!plane.current) return
|
||||
const intersects = raycaster.intersectObject(plane.current, true);
|
||||
const intersectsLines = raycaster.intersectObjects(floorPlanGroupLine.current.children, true);
|
||||
const 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);
|
||||
|
||||
if ((intersectsPoint.length === 0 || VisibleintersectsPoint === undefined) && intersectsLines.length > 0 && !isSnapped.current && !ispreSnapped.current) {
|
||||
|
||||
////////// Clicked on a preexisting Line //////////
|
||||
|
||||
if (visibleIntersect && (intersectsLines[0].object.userData.linePoints[0][3] === CONSTANTS.lineConfig.floorName || intersectsLines[0].object.userData.linePoints[0][3] === CONSTANTS.lineConfig.wallName)) {
|
||||
let pointColor, lineColor;
|
||||
if (intersectsLines[0].object.userData.linePoints[0][3] === CONSTANTS.lineConfig.wallName) {
|
||||
pointColor = CONSTANTS.pointConfig.wallOuterColor;
|
||||
lineColor = CONSTANTS.lineConfig.wallColor;
|
||||
} else {
|
||||
pointColor = CONSTANTS.pointConfig.floorOuterColor;
|
||||
lineColor = CONSTANTS.lineConfig.floorColor;
|
||||
}
|
||||
let IntersectsPoint = new THREE.Vector3(intersects[0].point.x, 0.01, intersects[0].point.z);
|
||||
if (isAngleSnapped.current && line.current.length > 0 && 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, pointColor, lineColor, intersectsLines[0].object.userData.linePoints[0][3]);
|
||||
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.floorName]);
|
||||
|
||||
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
|
||||
lines.current.push(line.current as Types.Line);
|
||||
const data = arrayLineToObject(line.current as Types.Line);
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
//REST
|
||||
|
||||
// setLine(organization, data.layer!, data.line!, data.type!);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const input = {
|
||||
organization: organization,
|
||||
layer: data.layer,
|
||||
line: data.line,
|
||||
type: data.type,
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
socket.emit('v1:Line:create', input);
|
||||
|
||||
setNewLines([newLines[0], newLines[1], line.current]);
|
||||
onlyFloorline.current.push(line.current as Types.Line);
|
||||
onlyFloorlines.current.push(onlyFloorline.current);
|
||||
onlyFloorline.current = [];
|
||||
|
||||
addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.lineConfig.floorColor, line.current, floorPlanGroupLine);
|
||||
|
||||
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (intersects.length > 0 && intersectsLines.length === 0) {
|
||||
|
||||
////////// Clicked on an empty place or a 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 (!isSnapped.current && !ispreSnapped.current) {
|
||||
addPointToScene(intersectionPoint, CONSTANTS.pointConfig.floorOuterColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, isSnappedUUID, CONSTANTS.lineConfig.floorName);
|
||||
} 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.floorName]);
|
||||
|
||||
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
|
||||
onlyFloorline.current.push(line.current as Types.Line);
|
||||
lines.current.push(line.current as Types.Line);
|
||||
const data = arrayLineToObject(line.current as Types.Line);
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
//REST
|
||||
|
||||
// setLine(organization, data.layer!, data.line!, data.type!);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const input = {
|
||||
organization: organization,
|
||||
layer: data.layer,
|
||||
line: data.line,
|
||||
type: data.type,
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
socket.emit('v1:Line:create', input);
|
||||
|
||||
setNewLines([line.current]);
|
||||
addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.lineConfig.floorColor, line.current, floorPlanGroupLine);
|
||||
const lastPoint = line.current[line.current.length - 1];
|
||||
line.current = [lastPoint];
|
||||
}
|
||||
if (isSnapped.current) { ////////// Add this to stop the drawing mode after snapping //////////
|
||||
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
|
||||
onlyFloorlines.current.push(onlyFloorline.current);
|
||||
onlyFloorline.current = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default drawOnlyFloor;
|
||||
@@ -1,50 +1,50 @@
|
||||
import * as THREE from 'three';
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
import addRoofToScene from '../roofs/addRoofToScene';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import loadOnlyFloors from './loadOnlyFloors';
|
||||
import addFloorToScene from './addFloorToScene';
|
||||
import getRoomsFromLines from '../lines/getRoomsFromLines';
|
||||
|
||||
async function loadFloor(
|
||||
lines: Types.RefLines,
|
||||
floorGroup: Types.RefGroup,
|
||||
): Promise<void> {
|
||||
|
||||
if (!floorGroup.current) return;
|
||||
|
||||
floorGroup.current.children = [];
|
||||
|
||||
if (lines.current.length > 2) {
|
||||
const linesByLayer = lines.current.reduce((acc: { [key: number]: any[] }, pair) => {
|
||||
const layer = pair[0][2];
|
||||
if (!acc[layer]) acc[layer] = [];
|
||||
acc[layer].push(pair);
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
for (const layer in linesByLayer) {
|
||||
// Only Floor Polygons
|
||||
loadOnlyFloors(floorGroup, linesByLayer, layer);
|
||||
|
||||
const rooms: Types.Rooms = await getRoomsFromLines({ current: linesByLayer[layer] });
|
||||
|
||||
rooms.forEach(({ coordinates: room, layer }) => {
|
||||
const userData = room.map(point => point.uuid);
|
||||
const shape = new THREE.Shape();
|
||||
shape.moveTo(room[0].position.x, room[0].position.z);
|
||||
room.forEach(point => shape.lineTo(point.position.x, point.position.z));
|
||||
shape.closePath();
|
||||
|
||||
// Floor Polygons
|
||||
addFloorToScene(shape, (layer - 1) * CONSTANTS.wallConfig.height, floorGroup, userData);
|
||||
|
||||
// Roof Polygons
|
||||
addRoofToScene(shape, (layer - 1) * CONSTANTS.wallConfig.height, userData, floorGroup);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default loadFloor;
|
||||
import * as THREE from 'three';
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
import addRoofToScene from '../roofs/addRoofToScene';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import loadOnlyFloors from './loadOnlyFloors';
|
||||
import addFloorToScene from './addFloorToScene';
|
||||
import getRoomsFromLines from '../lines/getRoomsFromLines';
|
||||
|
||||
async function loadFloor(
|
||||
lines: Types.RefLines,
|
||||
floorGroup: Types.RefGroup,
|
||||
): Promise<void> {
|
||||
|
||||
if (!floorGroup.current) return;
|
||||
|
||||
floorGroup.current.children = [];
|
||||
|
||||
if (lines.current.length > 2) {
|
||||
const linesByLayer = lines.current.reduce((acc: { [key: number]: any[] }, pair) => {
|
||||
const layer = pair[0][2];
|
||||
if (!acc[layer]) acc[layer] = [];
|
||||
acc[layer].push(pair);
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
for (const layer in linesByLayer) {
|
||||
// Only Floor Polygons
|
||||
loadOnlyFloors(floorGroup, linesByLayer, layer);
|
||||
|
||||
const rooms: Types.Rooms = await getRoomsFromLines({ current: linesByLayer[layer] });
|
||||
|
||||
rooms.forEach(({ coordinates: room, layer }) => {
|
||||
const userData = room.map(point => point.uuid);
|
||||
const shape = new THREE.Shape();
|
||||
shape.moveTo(room[0].position.x, room[0].position.z);
|
||||
room.forEach(point => shape.lineTo(point.position.x, point.position.z));
|
||||
shape.closePath();
|
||||
|
||||
// Floor Polygons
|
||||
addFloorToScene(shape, (layer - 1) * CONSTANTS.wallConfig.height, floorGroup, userData);
|
||||
|
||||
// Roof Polygons
|
||||
addRoofToScene(shape, (layer - 1) * CONSTANTS.wallConfig.height, userData, floorGroup);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default loadFloor;
|
||||
|
||||
@@ -1,183 +1,183 @@
|
||||
import * as THREE from 'three';
|
||||
import * as turf from '@turf/turf';
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function loadOnlyFloors(
|
||||
floorGroup: Types.RefGroup,
|
||||
linesByLayer: any,
|
||||
layer: any,
|
||||
): void {
|
||||
|
||||
////////// Creating polygon floor based on the onlyFloorlines.current which does not add roof to it, The lines are still stored in Lines.current as well //////////
|
||||
|
||||
let floorsInLayer = linesByLayer[layer];
|
||||
floorsInLayer = floorsInLayer.filter((line: any) => line[0][3] && line[1][3] === CONSTANTS.lineConfig.floorName);
|
||||
const floorResult = floorsInLayer.map((pair: [THREE.Vector3, string, number, string][]) =>
|
||||
pair.map((point) => ({
|
||||
position: [point[0].x, point[0].z],
|
||||
uuid: point[1]
|
||||
}))
|
||||
);
|
||||
const FloorLineFeatures = floorResult.map((line: any) => turf.lineString(line.map((p: any) => p.position)));
|
||||
|
||||
function identifyPolygonsAndConnectedLines(FloorLineFeatures: any) {
|
||||
const floorpolygons = [];
|
||||
const connectedLines = [];
|
||||
const unprocessedLines = [...FloorLineFeatures]; // Copy the features
|
||||
|
||||
while (unprocessedLines.length > 0) {
|
||||
const currentLine = unprocessedLines.pop();
|
||||
const coordinates = currentLine.geometry.coordinates;
|
||||
|
||||
// Check if the line is closed (forms a polygon)
|
||||
if (
|
||||
coordinates[0][0] === coordinates[coordinates.length - 1][0] &&
|
||||
coordinates[0][1] === coordinates[coordinates.length - 1][1]
|
||||
) {
|
||||
floorpolygons.push(turf.polygon([coordinates])); // Add as a polygon
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if the line connects to another line
|
||||
let connected = false;
|
||||
for (let i = unprocessedLines.length - 1; i >= 0; i--) {
|
||||
const otherCoordinates = unprocessedLines[i].geometry.coordinates;
|
||||
|
||||
// Check if lines share a start or end point
|
||||
if (
|
||||
coordinates[0][0] === otherCoordinates[otherCoordinates.length - 1][0] &&
|
||||
coordinates[0][1] === otherCoordinates[otherCoordinates.length - 1][1]
|
||||
) {
|
||||
// Merge lines
|
||||
const mergedCoordinates = [...otherCoordinates, ...coordinates.slice(1)];
|
||||
unprocessedLines[i] = turf.lineString(mergedCoordinates);
|
||||
connected = true;
|
||||
break;
|
||||
} else if (
|
||||
coordinates[coordinates.length - 1][0] === otherCoordinates[0][0] &&
|
||||
coordinates[coordinates.length - 1][1] === otherCoordinates[0][1]
|
||||
) {
|
||||
// Merge lines
|
||||
const mergedCoordinates = [...coordinates, ...otherCoordinates.slice(1)];
|
||||
unprocessedLines[i] = turf.lineString(mergedCoordinates);
|
||||
connected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!connected) {
|
||||
connectedLines.push(currentLine); // Add unconnected line as-is
|
||||
}
|
||||
}
|
||||
|
||||
return { floorpolygons, connectedLines };
|
||||
}
|
||||
|
||||
const { floorpolygons, connectedLines } = identifyPolygonsAndConnectedLines(FloorLineFeatures);
|
||||
|
||||
function convertConnectedLinesToPolygons(connectedLines: any) {
|
||||
return connectedLines.map((line: any) => {
|
||||
const coordinates = line.geometry.coordinates;
|
||||
|
||||
// If the line has more than two points, close the polygon
|
||||
if (coordinates.length > 2) {
|
||||
const firstPoint = coordinates[0];
|
||||
const lastPoint = coordinates[coordinates.length - 1];
|
||||
|
||||
// Check if already closed; if not, close it
|
||||
if (firstPoint[0] !== lastPoint[0] || firstPoint[1] !== lastPoint[1]) {
|
||||
coordinates.push(firstPoint);
|
||||
}
|
||||
|
||||
// Convert the closed line into a polygon
|
||||
return turf.polygon([coordinates]);
|
||||
}
|
||||
|
||||
// If not enough points for a polygon, return the line unchanged
|
||||
return line;
|
||||
});
|
||||
}
|
||||
|
||||
const convertedConnectedPolygons = convertConnectedLinesToPolygons(connectedLines);
|
||||
|
||||
if (convertedConnectedPolygons.length > 0) {
|
||||
const validPolygons = convertedConnectedPolygons.filter(
|
||||
(polygon: any) => polygon.geometry?.type === "Polygon"
|
||||
);
|
||||
|
||||
if (validPolygons.length > 0) {
|
||||
floorpolygons.push(...validPolygons);
|
||||
}
|
||||
}
|
||||
|
||||
function convertPolygonsToOriginalFormat(floorpolygons: any, originalLines: [THREE.Vector3, string, number, string][][]) {
|
||||
return floorpolygons.map((polygon: any) => {
|
||||
const coordinates = polygon.geometry.coordinates[0]; // Extract the coordinates array (assume it's a single polygon)
|
||||
|
||||
// Map each coordinate back to its original structure
|
||||
const mappedPoints = coordinates.map((coord: [number, number]) => {
|
||||
const [x, z] = coord;
|
||||
|
||||
// Find the original point matching this coordinate
|
||||
const originalPoint = originalLines.flat().find(([point]) => point.x === x && point.z === z);
|
||||
|
||||
if (!originalPoint) {
|
||||
throw new Error(`Original point for coordinate [${x}, ${z}] not found.`);
|
||||
}
|
||||
|
||||
return originalPoint;
|
||||
});
|
||||
|
||||
// Create pairs of consecutive points
|
||||
const pairs: typeof originalLines = [];
|
||||
for (let i = 0; i < mappedPoints.length - 1; i++) {
|
||||
pairs.push([mappedPoints[i], mappedPoints[i + 1]]);
|
||||
}
|
||||
|
||||
return pairs;
|
||||
});
|
||||
}
|
||||
|
||||
const convertedFloorPolygons: Types.OnlyFloorLines = convertPolygonsToOriginalFormat(floorpolygons, floorsInLayer);
|
||||
|
||||
convertedFloorPolygons.forEach((floor) => {
|
||||
const points: THREE.Vector3[] = [];
|
||||
|
||||
floor.forEach((lineSegment) => {
|
||||
const startPoint = lineSegment[0][0];
|
||||
points.push(new THREE.Vector3(startPoint.x, startPoint.y, startPoint.z));
|
||||
});
|
||||
|
||||
const lastLine = floor[floor.length - 1];
|
||||
const endPoint = lastLine[1][0];
|
||||
points.push(new THREE.Vector3(endPoint.x, endPoint.y, endPoint.z));
|
||||
|
||||
const shape = new THREE.Shape();
|
||||
shape.moveTo(points[0].x, points[0].z);
|
||||
|
||||
points.forEach(point => shape.lineTo(point.x, point.z));
|
||||
shape.closePath();
|
||||
|
||||
const extrudeSettings = {
|
||||
depth: CONSTANTS.floorConfig.height,
|
||||
bevelEnabled: false
|
||||
};
|
||||
|
||||
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
|
||||
const material = new THREE.MeshStandardMaterial({ color: CONSTANTS.floorConfig.defaultColor, side: THREE.DoubleSide });
|
||||
const mesh = new THREE.Mesh(geometry, material);
|
||||
|
||||
mesh.castShadow = true;
|
||||
mesh.receiveShadow = true;
|
||||
|
||||
mesh.position.y = (floor[0][0][2] - 1) * CONSTANTS.wallConfig.height + 0.03;
|
||||
mesh.rotateX(Math.PI / 2);
|
||||
mesh.name = `Only_Floor_Line_${floor[0][0][2]}`;
|
||||
|
||||
mesh.userData = floor;
|
||||
floorGroup?.current?.add(mesh);
|
||||
});
|
||||
}
|
||||
|
||||
export default loadOnlyFloors;
|
||||
import * as THREE from 'three';
|
||||
import * as turf from '@turf/turf';
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function loadOnlyFloors(
|
||||
floorGroup: Types.RefGroup,
|
||||
linesByLayer: any,
|
||||
layer: any,
|
||||
): void {
|
||||
|
||||
////////// Creating polygon floor based on the onlyFloorlines.current which does not add roof to it, The lines are still stored in Lines.current as well //////////
|
||||
|
||||
let floorsInLayer = linesByLayer[layer];
|
||||
floorsInLayer = floorsInLayer.filter((line: any) => line[0][3] && line[1][3] === CONSTANTS.lineConfig.floorName);
|
||||
const floorResult = floorsInLayer.map((pair: [THREE.Vector3, string, number, string][]) =>
|
||||
pair.map((point) => ({
|
||||
position: [point[0].x, point[0].z],
|
||||
uuid: point[1]
|
||||
}))
|
||||
);
|
||||
const FloorLineFeatures = floorResult.map((line: any) => turf.lineString(line.map((p: any) => p.position)));
|
||||
|
||||
function identifyPolygonsAndConnectedLines(FloorLineFeatures: any) {
|
||||
const floorpolygons = [];
|
||||
const connectedLines = [];
|
||||
const unprocessedLines = [...FloorLineFeatures]; // Copy the features
|
||||
|
||||
while (unprocessedLines.length > 0) {
|
||||
const currentLine = unprocessedLines.pop();
|
||||
const coordinates = currentLine.geometry.coordinates;
|
||||
|
||||
// Check if the line is closed (forms a polygon)
|
||||
if (
|
||||
coordinates[0][0] === coordinates[coordinates.length - 1][0] &&
|
||||
coordinates[0][1] === coordinates[coordinates.length - 1][1]
|
||||
) {
|
||||
floorpolygons.push(turf.polygon([coordinates])); // Add as a polygon
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if the line connects to another line
|
||||
let connected = false;
|
||||
for (let i = unprocessedLines.length - 1; i >= 0; i--) {
|
||||
const otherCoordinates = unprocessedLines[i].geometry.coordinates;
|
||||
|
||||
// Check if lines share a start or end point
|
||||
if (
|
||||
coordinates[0][0] === otherCoordinates[otherCoordinates.length - 1][0] &&
|
||||
coordinates[0][1] === otherCoordinates[otherCoordinates.length - 1][1]
|
||||
) {
|
||||
// Merge lines
|
||||
const mergedCoordinates = [...otherCoordinates, ...coordinates.slice(1)];
|
||||
unprocessedLines[i] = turf.lineString(mergedCoordinates);
|
||||
connected = true;
|
||||
break;
|
||||
} else if (
|
||||
coordinates[coordinates.length - 1][0] === otherCoordinates[0][0] &&
|
||||
coordinates[coordinates.length - 1][1] === otherCoordinates[0][1]
|
||||
) {
|
||||
// Merge lines
|
||||
const mergedCoordinates = [...coordinates, ...otherCoordinates.slice(1)];
|
||||
unprocessedLines[i] = turf.lineString(mergedCoordinates);
|
||||
connected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!connected) {
|
||||
connectedLines.push(currentLine); // Add unconnected line as-is
|
||||
}
|
||||
}
|
||||
|
||||
return { floorpolygons, connectedLines };
|
||||
}
|
||||
|
||||
const { floorpolygons, connectedLines } = identifyPolygonsAndConnectedLines(FloorLineFeatures);
|
||||
|
||||
function convertConnectedLinesToPolygons(connectedLines: any) {
|
||||
return connectedLines.map((line: any) => {
|
||||
const coordinates = line.geometry.coordinates;
|
||||
|
||||
// If the line has more than two points, close the polygon
|
||||
if (coordinates.length > 2) {
|
||||
const firstPoint = coordinates[0];
|
||||
const lastPoint = coordinates[coordinates.length - 1];
|
||||
|
||||
// Check if already closed; if not, close it
|
||||
if (firstPoint[0] !== lastPoint[0] || firstPoint[1] !== lastPoint[1]) {
|
||||
coordinates.push(firstPoint);
|
||||
}
|
||||
|
||||
// Convert the closed line into a polygon
|
||||
return turf.polygon([coordinates]);
|
||||
}
|
||||
|
||||
// If not enough points for a polygon, return the line unchanged
|
||||
return line;
|
||||
});
|
||||
}
|
||||
|
||||
const convertedConnectedPolygons = convertConnectedLinesToPolygons(connectedLines);
|
||||
|
||||
if (convertedConnectedPolygons.length > 0) {
|
||||
const validPolygons = convertedConnectedPolygons.filter(
|
||||
(polygon: any) => polygon.geometry?.type === "Polygon"
|
||||
);
|
||||
|
||||
if (validPolygons.length > 0) {
|
||||
floorpolygons.push(...validPolygons);
|
||||
}
|
||||
}
|
||||
|
||||
function convertPolygonsToOriginalFormat(floorpolygons: any, originalLines: [THREE.Vector3, string, number, string][][]) {
|
||||
return floorpolygons.map((polygon: any) => {
|
||||
const coordinates = polygon.geometry.coordinates[0]; // Extract the coordinates array (assume it's a single polygon)
|
||||
|
||||
// Map each coordinate back to its original structure
|
||||
const mappedPoints = coordinates.map((coord: [number, number]) => {
|
||||
const [x, z] = coord;
|
||||
|
||||
// Find the original point matching this coordinate
|
||||
const originalPoint = originalLines.flat().find(([point]) => point.x === x && point.z === z);
|
||||
|
||||
if (!originalPoint) {
|
||||
throw new Error(`Original point for coordinate [${x}, ${z}] not found.`);
|
||||
}
|
||||
|
||||
return originalPoint;
|
||||
});
|
||||
|
||||
// Create pairs of consecutive points
|
||||
const pairs: typeof originalLines = [];
|
||||
for (let i = 0; i < mappedPoints.length - 1; i++) {
|
||||
pairs.push([mappedPoints[i], mappedPoints[i + 1]]);
|
||||
}
|
||||
|
||||
return pairs;
|
||||
});
|
||||
}
|
||||
|
||||
const convertedFloorPolygons: Types.OnlyFloorLines = convertPolygonsToOriginalFormat(floorpolygons, floorsInLayer);
|
||||
|
||||
convertedFloorPolygons.forEach((floor) => {
|
||||
const points: THREE.Vector3[] = [];
|
||||
|
||||
floor.forEach((lineSegment) => {
|
||||
const startPoint = lineSegment[0][0];
|
||||
points.push(new THREE.Vector3(startPoint.x, startPoint.y, startPoint.z));
|
||||
});
|
||||
|
||||
const lastLine = floor[floor.length - 1];
|
||||
const endPoint = lastLine[1][0];
|
||||
points.push(new THREE.Vector3(endPoint.x, endPoint.y, endPoint.z));
|
||||
|
||||
const shape = new THREE.Shape();
|
||||
shape.moveTo(points[0].x, points[0].z);
|
||||
|
||||
points.forEach(point => shape.lineTo(point.x, point.z));
|
||||
shape.closePath();
|
||||
|
||||
const extrudeSettings = {
|
||||
depth: CONSTANTS.floorConfig.height,
|
||||
bevelEnabled: false
|
||||
};
|
||||
|
||||
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
|
||||
const material = new THREE.MeshStandardMaterial({ color: CONSTANTS.floorConfig.defaultColor, side: THREE.DoubleSide });
|
||||
const mesh = new THREE.Mesh(geometry, material);
|
||||
|
||||
mesh.castShadow = true;
|
||||
mesh.receiveShadow = true;
|
||||
|
||||
mesh.position.y = (floor[0][0][2] - 1) * CONSTANTS.wallConfig.height + 0.03;
|
||||
mesh.rotateX(Math.PI / 2);
|
||||
mesh.name = `Only_Floor_Line_${floor[0][0][2]}`;
|
||||
|
||||
mesh.userData = floor;
|
||||
floorGroup?.current?.add(mesh);
|
||||
});
|
||||
}
|
||||
|
||||
export default loadOnlyFloors;
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function updateFloorLines(
|
||||
onlyFloorlines: Types.RefOnlyFloorLines,
|
||||
DragedPoint: Types.Mesh | { uuid: string, position: Types.Vector3 }
|
||||
): void {
|
||||
|
||||
////////// Update onlyFloorlines.current if it contains the dragged point //////////
|
||||
|
||||
onlyFloorlines.current.forEach((floorline) => {
|
||||
floorline.forEach((line) => {
|
||||
line.forEach((point) => {
|
||||
const [position, uuid] = point;
|
||||
if (uuid === DragedPoint.uuid) {
|
||||
position.x = DragedPoint.position.x;
|
||||
position.y = 0.01;
|
||||
position.z = DragedPoint.position.z;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export default updateFloorLines;
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function updateFloorLines(
|
||||
onlyFloorlines: Types.RefOnlyFloorLines,
|
||||
DragedPoint: Types.Mesh | { uuid: string, position: Types.Vector3 }
|
||||
): void {
|
||||
|
||||
////////// Update onlyFloorlines.current if it contains the dragged point //////////
|
||||
|
||||
onlyFloorlines.current.forEach((floorline) => {
|
||||
floorline.forEach((line) => {
|
||||
line.forEach((point) => {
|
||||
const [position, uuid] = point;
|
||||
if (uuid === DragedPoint.uuid) {
|
||||
position.x = DragedPoint.position.x;
|
||||
position.y = 0.01;
|
||||
position.z = DragedPoint.position.z;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export default updateFloorLines;
|
||||
|
||||
@@ -1,89 +1,89 @@
|
||||
import { toast } from 'react-toastify';
|
||||
import RemoveConnectedLines from '../lines/removeConnectedLines';
|
||||
|
||||
import * as Types from '../../../../types/world/worldTypes';
|
||||
import { Socket } from 'socket.io-client';
|
||||
// import { deleteLayer } from '../../../../services/factoryBuilder/lines/deleteLayerApi';
|
||||
|
||||
async function DeleteLayer(
|
||||
removedLayer: Types.Number,
|
||||
lines: Types.RefLines,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
onlyFloorlines: Types.RefOnlyFloorLines,
|
||||
floorGroup: Types.RefGroup,
|
||||
setDeletedLines: any,
|
||||
setRemovedLayer: Types.setRemoveLayerSetState,
|
||||
socket: Socket<any>
|
||||
): Promise<void> {
|
||||
|
||||
////////// Remove the Lines from the lines.current based on the removed layer and rearrange the layer number that are higher than the removed layer //////////
|
||||
|
||||
const removedLines: Types.Lines = lines.current.filter(line => line[0][2] === removedLayer);
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
//REST
|
||||
|
||||
// await deleteLayer(organization, removedLayer);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const data = {
|
||||
organization: organization,
|
||||
layer: removedLayer,
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
socket.emit('v1:Line:delete:layer', data);
|
||||
|
||||
////////// Remove Points and lines from the removed layer //////////
|
||||
|
||||
removedLines.forEach((line) => {
|
||||
line.forEach((removedPoint) => {
|
||||
RemoveConnectedLines(removedPoint[1], floorPlanGroupLine, floorPlanGroupPoint, setDeletedLines, lines);
|
||||
});
|
||||
});
|
||||
|
||||
////////// Update the remaining lines layer values in the userData and in lines.current //////////
|
||||
|
||||
let remaining = lines.current.filter(line => line[0][2] !== removedLayer);
|
||||
let updatedLines: Types.Lines = [];
|
||||
remaining.forEach(line => {
|
||||
let newLines: Types.Line = [...line];
|
||||
if (newLines[0][2] > removedLayer) {
|
||||
newLines[0][2] -= 1;
|
||||
newLines[1][2] -= 1;
|
||||
}
|
||||
|
||||
const matchingLine = floorPlanGroupLine.current.children.find(l => l.userData.linePoints[0][1] === line[0][1] && l.userData.linePoints[1][1] === line[1][1]);
|
||||
if (matchingLine) {
|
||||
const updatedUserData = matchingLine.userData;
|
||||
updatedUserData.linePoints[0][2] = newLines[0][2];
|
||||
updatedUserData.linePoints[1][2] = newLines[1][2];
|
||||
}
|
||||
updatedLines.push(newLines);
|
||||
});
|
||||
|
||||
lines.current = updatedLines;
|
||||
localStorage.setItem("Lines", JSON.stringify(lines.current));
|
||||
|
||||
////////// Also remove OnlyFloorLines and update it in localstorage //////////
|
||||
|
||||
onlyFloorlines.current = onlyFloorlines.current.filter((floor) => {
|
||||
return floor[0][0][2] !== removedLayer;
|
||||
});
|
||||
const meshToRemove: any = floorGroup.current?.children.find((mesh) =>
|
||||
mesh.name === `Only_Floor_Line_${removedLayer}`
|
||||
);
|
||||
if (meshToRemove) {
|
||||
(<any>meshToRemove.material).dispose();
|
||||
(<any>meshToRemove.geometry).dispose();
|
||||
floorGroup.current?.remove(meshToRemove);
|
||||
}
|
||||
|
||||
toast.success("Layer Removed!");
|
||||
setRemovedLayer(null);
|
||||
}
|
||||
export default DeleteLayer;
|
||||
import { toast } from 'react-toastify';
|
||||
import RemoveConnectedLines from '../lines/removeConnectedLines';
|
||||
|
||||
import * as Types from '../../../../types/world/worldTypes';
|
||||
import { Socket } from 'socket.io-client';
|
||||
// import { deleteLayer } from '../../../../services/factoryBuilder/lines/deleteLayerApi';
|
||||
|
||||
async function DeleteLayer(
|
||||
removedLayer: Types.Number,
|
||||
lines: Types.RefLines,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
onlyFloorlines: Types.RefOnlyFloorLines,
|
||||
floorGroup: Types.RefGroup,
|
||||
setDeletedLines: any,
|
||||
setRemovedLayer: Types.setRemoveLayerSetState,
|
||||
socket: Socket<any>
|
||||
): Promise<void> {
|
||||
|
||||
////////// Remove the Lines from the lines.current based on the removed layer and rearrange the layer number that are higher than the removed layer //////////
|
||||
|
||||
const removedLines: Types.Lines = lines.current.filter(line => line[0][2] === removedLayer);
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
//REST
|
||||
|
||||
// await deleteLayer(organization, removedLayer);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const data = {
|
||||
organization: organization,
|
||||
layer: removedLayer,
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
socket.emit('v1:Line:delete:layer', data);
|
||||
|
||||
////////// Remove Points and lines from the removed layer //////////
|
||||
|
||||
removedLines.forEach((line) => {
|
||||
line.forEach((removedPoint) => {
|
||||
RemoveConnectedLines(removedPoint[1], floorPlanGroupLine, floorPlanGroupPoint, setDeletedLines, lines);
|
||||
});
|
||||
});
|
||||
|
||||
////////// Update the remaining lines layer values in the userData and in lines.current //////////
|
||||
|
||||
let remaining = lines.current.filter(line => line[0][2] !== removedLayer);
|
||||
let updatedLines: Types.Lines = [];
|
||||
remaining.forEach(line => {
|
||||
let newLines: Types.Line = [...line];
|
||||
if (newLines[0][2] > removedLayer) {
|
||||
newLines[0][2] -= 1;
|
||||
newLines[1][2] -= 1;
|
||||
}
|
||||
|
||||
const matchingLine = floorPlanGroupLine.current.children.find(l => l.userData.linePoints[0][1] === line[0][1] && l.userData.linePoints[1][1] === line[1][1]);
|
||||
if (matchingLine) {
|
||||
const updatedUserData = matchingLine.userData;
|
||||
updatedUserData.linePoints[0][2] = newLines[0][2];
|
||||
updatedUserData.linePoints[1][2] = newLines[1][2];
|
||||
}
|
||||
updatedLines.push(newLines);
|
||||
});
|
||||
|
||||
lines.current = updatedLines;
|
||||
localStorage.setItem("Lines", JSON.stringify(lines.current));
|
||||
|
||||
////////// Also remove OnlyFloorLines and update it in localstorage //////////
|
||||
|
||||
onlyFloorlines.current = onlyFloorlines.current.filter((floor) => {
|
||||
return floor[0][0][2] !== removedLayer;
|
||||
});
|
||||
const meshToRemove: any = floorGroup.current?.children.find((mesh) =>
|
||||
mesh.name === `Only_Floor_Line_${removedLayer}`
|
||||
);
|
||||
if (meshToRemove) {
|
||||
(<any>meshToRemove.material).dispose();
|
||||
(<any>meshToRemove.geometry).dispose();
|
||||
floorGroup.current?.remove(meshToRemove);
|
||||
}
|
||||
|
||||
toast.success("Layer Removed!");
|
||||
setRemovedLayer(null);
|
||||
}
|
||||
export default DeleteLayer;
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function Layer2DVisibility(
|
||||
activeLayer: Types.Number,
|
||||
floorPlanGroup: Types.RefGroup,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
currentLayerPoint: Types.RefMeshArray,
|
||||
dragPointControls: Types.RefDragControl
|
||||
): void {
|
||||
|
||||
if (floorPlanGroup.current && dragPointControls.current) {
|
||||
currentLayerPoint.current = [];
|
||||
floorPlanGroupLine.current.children.forEach((line) => {
|
||||
const linePoints = line.userData.linePoints;
|
||||
|
||||
const point1 = floorPlanGroupPoint.current.getObjectByProperty('uuid', linePoints[0][1]) as Types.Mesh;
|
||||
const point2 = floorPlanGroupPoint.current.getObjectByProperty('uuid', linePoints[1][1]) as Types.Mesh;
|
||||
|
||||
if (linePoints[0][2] !== activeLayer && linePoints[1][2] !== activeLayer) {
|
||||
point1.visible = false;
|
||||
point2.visible = false;
|
||||
line.visible = false;
|
||||
} else {
|
||||
point1.visible = true;
|
||||
point2.visible = true;
|
||||
line.visible = true;
|
||||
currentLayerPoint.current.push(point1, point2);
|
||||
}
|
||||
});
|
||||
dragPointControls.current!.objects = currentLayerPoint.current;
|
||||
}
|
||||
}
|
||||
|
||||
export default Layer2DVisibility;
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function Layer2DVisibility(
|
||||
activeLayer: Types.Number,
|
||||
floorPlanGroup: Types.RefGroup,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
currentLayerPoint: Types.RefMeshArray,
|
||||
dragPointControls: Types.RefDragControl
|
||||
): void {
|
||||
|
||||
if (floorPlanGroup.current && dragPointControls.current) {
|
||||
currentLayerPoint.current = [];
|
||||
floorPlanGroupLine.current.children.forEach((line) => {
|
||||
const linePoints = line.userData.linePoints;
|
||||
|
||||
const point1 = floorPlanGroupPoint.current.getObjectByProperty('uuid', linePoints[0][1]) as Types.Mesh;
|
||||
const point2 = floorPlanGroupPoint.current.getObjectByProperty('uuid', linePoints[1][1]) as Types.Mesh;
|
||||
|
||||
if (linePoints[0][2] !== activeLayer && linePoints[1][2] !== activeLayer) {
|
||||
point1.visible = false;
|
||||
point2.visible = false;
|
||||
line.visible = false;
|
||||
} else {
|
||||
point1.visible = true;
|
||||
point2.visible = true;
|
||||
line.visible = true;
|
||||
currentLayerPoint.current.push(point1, point2);
|
||||
}
|
||||
});
|
||||
dragPointControls.current!.objects = currentLayerPoint.current;
|
||||
}
|
||||
}
|
||||
|
||||
export default Layer2DVisibility;
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import * as THREE from "three";
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function addLineToScene(
|
||||
start: Types.Vector3,
|
||||
end: Types.Vector3,
|
||||
colour: Types.Color,
|
||||
userData: Types.UserData,
|
||||
floorPlanGroupLine: Types.RefGroup
|
||||
): void {
|
||||
|
||||
////////// A function that creates and adds lines based on the start, end, and colour from the params, Also adds the userData in the mesh userData //////////
|
||||
|
||||
const path = new THREE.CatmullRomCurve3([start, end]);
|
||||
const geometry = new THREE.TubeGeometry(path, CONSTANTS.lineConfig.tubularSegments, CONSTANTS.lineConfig.radius, CONSTANTS.lineConfig.radialSegments, false);
|
||||
const material = new THREE.MeshBasicMaterial({ color: colour });
|
||||
const mesh = new THREE.Mesh(geometry, material);
|
||||
floorPlanGroupLine.current.add(mesh);
|
||||
|
||||
mesh.userData.linePoints = userData;
|
||||
}
|
||||
|
||||
export default addLineToScene;
|
||||
import * as THREE from "three";
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function addLineToScene(
|
||||
start: Types.Vector3,
|
||||
end: Types.Vector3,
|
||||
colour: Types.Color,
|
||||
userData: Types.UserData,
|
||||
floorPlanGroupLine: Types.RefGroup
|
||||
): void {
|
||||
|
||||
////////// A function that creates and adds lines based on the start, end, and colour from the params, Also adds the userData in the mesh userData //////////
|
||||
|
||||
const path = new THREE.CatmullRomCurve3([start, end]);
|
||||
const geometry = new THREE.TubeGeometry(path, CONSTANTS.lineConfig.tubularSegments, CONSTANTS.lineConfig.radius, CONSTANTS.lineConfig.radialSegments, false);
|
||||
const material = new THREE.MeshBasicMaterial({ color: colour });
|
||||
const mesh = new THREE.Mesh(geometry, material);
|
||||
floorPlanGroupLine.current.add(mesh);
|
||||
|
||||
mesh.userData.linePoints = userData;
|
||||
}
|
||||
|
||||
export default addLineToScene;
|
||||
|
||||
@@ -1,98 +1,98 @@
|
||||
import * as THREE from "three";
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function createAndMoveReferenceLine(
|
||||
point: Types.Vector3,
|
||||
cursorPosition: Types.Vector3,
|
||||
isSnapped: Types.RefBoolean,
|
||||
ispreSnapped: Types.RefBoolean,
|
||||
line: Types.RefLine,
|
||||
setRefTextUpdate: Types.NumberIncrementState,
|
||||
floorPlanGroup: Types.RefGroup,
|
||||
ReferenceLineMesh: Types.RefMesh,
|
||||
LineCreated: Types.RefBoolean,
|
||||
Tube: Types.RefTubeGeometry,
|
||||
anglesnappedPoint: Types.RefVector3,
|
||||
isAngleSnapped: Types.RefBoolean
|
||||
): void {
|
||||
|
||||
////////// Creating new and maintaining the old reference line and also snap the reference line based on its angle //////////
|
||||
|
||||
const startPoint = point;
|
||||
|
||||
const dx = cursorPosition.x - startPoint.x;
|
||||
const dz = cursorPosition.z - startPoint.z;
|
||||
let angle = Math.atan2(dz, dx);
|
||||
|
||||
angle = (angle * 180) / Math.PI;
|
||||
angle = (angle + 360) % 360;
|
||||
|
||||
const snapAngles = [0, 90, 180, 270, 360];
|
||||
const snapThreshold = 2.5;
|
||||
|
||||
const closestSnapAngle = snapAngles.reduce((prev, curr) =>
|
||||
Math.abs(curr - angle) < Math.abs(prev - angle) ? curr : prev
|
||||
);
|
||||
|
||||
if (!isSnapped.current && !ispreSnapped.current && line.current.length > 0) {
|
||||
if (Math.abs(closestSnapAngle - angle) <= snapThreshold) {
|
||||
const snappedAngleRad = (closestSnapAngle * Math.PI) / 180;
|
||||
const distance = Math.sqrt(dx * dx + dz * dz);
|
||||
const snappedX = startPoint.x + distance * Math.cos(snappedAngleRad);
|
||||
const snappedZ = startPoint.z + distance * Math.sin(snappedAngleRad);
|
||||
|
||||
if (
|
||||
cursorPosition.distanceTo(
|
||||
new THREE.Vector3(snappedX, 0.01, snappedZ)
|
||||
) < 2
|
||||
) {
|
||||
cursorPosition.set(snappedX, 0.01, snappedZ);
|
||||
isAngleSnapped.current = true;
|
||||
anglesnappedPoint.current = new THREE.Vector3(
|
||||
snappedX,
|
||||
0.01,
|
||||
snappedZ
|
||||
);
|
||||
} else {
|
||||
isAngleSnapped.current = false;
|
||||
anglesnappedPoint.current = null;
|
||||
}
|
||||
} else {
|
||||
isAngleSnapped.current = false;
|
||||
anglesnappedPoint.current = null;
|
||||
}
|
||||
} else {
|
||||
isAngleSnapped.current = false;
|
||||
anglesnappedPoint.current = null;
|
||||
}
|
||||
|
||||
if (!LineCreated.current) {
|
||||
setRefTextUpdate((prevUpdate) => prevUpdate - 1);
|
||||
const path = new THREE.LineCurve3(startPoint, cursorPosition);
|
||||
Tube.current = new THREE.TubeGeometry(path, CONSTANTS.lineConfig.tubularSegments, CONSTANTS.lineConfig.radius, CONSTANTS.lineConfig.radialSegments, false);
|
||||
const material = new THREE.MeshBasicMaterial({ color: CONSTANTS.lineConfig.helperColor });
|
||||
ReferenceLineMesh.current = new THREE.Mesh(Tube.current, material);
|
||||
ReferenceLineMesh.current.name = CONSTANTS.lineConfig.referenceName;
|
||||
ReferenceLineMesh.current.userData = {
|
||||
linePoints: { startPoint, cursorPosition },
|
||||
};
|
||||
floorPlanGroup.current?.add(ReferenceLineMesh.current);
|
||||
LineCreated.current = true;
|
||||
} else {
|
||||
if (ReferenceLineMesh.current) {
|
||||
const path = new THREE.LineCurve3(startPoint, new THREE.Vector3(cursorPosition.x, 0.01, cursorPosition.z));
|
||||
Tube.current = new THREE.TubeGeometry(path, CONSTANTS.lineConfig.tubularSegments, CONSTANTS.lineConfig.radius, CONSTANTS.lineConfig.radialSegments, false);
|
||||
|
||||
if (ReferenceLineMesh.current) {
|
||||
ReferenceLineMesh.current.userData = {
|
||||
linePoints: { startPoint, cursorPosition },
|
||||
};
|
||||
ReferenceLineMesh.current.geometry.dispose();
|
||||
ReferenceLineMesh.current.geometry = Tube.current;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default createAndMoveReferenceLine;
|
||||
import * as THREE from "three";
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function createAndMoveReferenceLine(
|
||||
point: Types.Vector3,
|
||||
cursorPosition: Types.Vector3,
|
||||
isSnapped: Types.RefBoolean,
|
||||
ispreSnapped: Types.RefBoolean,
|
||||
line: Types.RefLine,
|
||||
setRefTextUpdate: Types.NumberIncrementState,
|
||||
floorPlanGroup: Types.RefGroup,
|
||||
ReferenceLineMesh: Types.RefMesh,
|
||||
LineCreated: Types.RefBoolean,
|
||||
Tube: Types.RefTubeGeometry,
|
||||
anglesnappedPoint: Types.RefVector3,
|
||||
isAngleSnapped: Types.RefBoolean
|
||||
): void {
|
||||
|
||||
////////// Creating new and maintaining the old reference line and also snap the reference line based on its angle //////////
|
||||
|
||||
const startPoint = point;
|
||||
|
||||
const dx = cursorPosition.x - startPoint.x;
|
||||
const dz = cursorPosition.z - startPoint.z;
|
||||
let angle = Math.atan2(dz, dx);
|
||||
|
||||
angle = (angle * 180) / Math.PI;
|
||||
angle = (angle + 360) % 360;
|
||||
|
||||
const snapAngles = [0, 90, 180, 270, 360];
|
||||
const snapThreshold = 2.5;
|
||||
|
||||
const closestSnapAngle = snapAngles.reduce((prev, curr) =>
|
||||
Math.abs(curr - angle) < Math.abs(prev - angle) ? curr : prev
|
||||
);
|
||||
|
||||
if (!isSnapped.current && !ispreSnapped.current && line.current.length > 0) {
|
||||
if (Math.abs(closestSnapAngle - angle) <= snapThreshold) {
|
||||
const snappedAngleRad = (closestSnapAngle * Math.PI) / 180;
|
||||
const distance = Math.sqrt(dx * dx + dz * dz);
|
||||
const snappedX = startPoint.x + distance * Math.cos(snappedAngleRad);
|
||||
const snappedZ = startPoint.z + distance * Math.sin(snappedAngleRad);
|
||||
|
||||
if (
|
||||
cursorPosition.distanceTo(
|
||||
new THREE.Vector3(snappedX, 0.01, snappedZ)
|
||||
) < 2
|
||||
) {
|
||||
cursorPosition.set(snappedX, 0.01, snappedZ);
|
||||
isAngleSnapped.current = true;
|
||||
anglesnappedPoint.current = new THREE.Vector3(
|
||||
snappedX,
|
||||
0.01,
|
||||
snappedZ
|
||||
);
|
||||
} else {
|
||||
isAngleSnapped.current = false;
|
||||
anglesnappedPoint.current = null;
|
||||
}
|
||||
} else {
|
||||
isAngleSnapped.current = false;
|
||||
anglesnappedPoint.current = null;
|
||||
}
|
||||
} else {
|
||||
isAngleSnapped.current = false;
|
||||
anglesnappedPoint.current = null;
|
||||
}
|
||||
|
||||
if (!LineCreated.current) {
|
||||
setRefTextUpdate((prevUpdate) => prevUpdate - 1);
|
||||
const path = new THREE.LineCurve3(startPoint, cursorPosition);
|
||||
Tube.current = new THREE.TubeGeometry(path, CONSTANTS.lineConfig.tubularSegments, CONSTANTS.lineConfig.radius, CONSTANTS.lineConfig.radialSegments, false);
|
||||
const material = new THREE.MeshBasicMaterial({ color: CONSTANTS.lineConfig.helperColor });
|
||||
ReferenceLineMesh.current = new THREE.Mesh(Tube.current, material);
|
||||
ReferenceLineMesh.current.name = CONSTANTS.lineConfig.referenceName;
|
||||
ReferenceLineMesh.current.userData = {
|
||||
linePoints: { startPoint, cursorPosition },
|
||||
};
|
||||
floorPlanGroup.current?.add(ReferenceLineMesh.current);
|
||||
LineCreated.current = true;
|
||||
} else {
|
||||
if (ReferenceLineMesh.current) {
|
||||
const path = new THREE.LineCurve3(startPoint, new THREE.Vector3(cursorPosition.x, 0.01, cursorPosition.z));
|
||||
Tube.current = new THREE.TubeGeometry(path, CONSTANTS.lineConfig.tubularSegments, CONSTANTS.lineConfig.radius, CONSTANTS.lineConfig.radialSegments, false);
|
||||
|
||||
if (ReferenceLineMesh.current) {
|
||||
ReferenceLineMesh.current.userData = {
|
||||
linePoints: { startPoint, cursorPosition },
|
||||
};
|
||||
ReferenceLineMesh.current.geometry.dispose();
|
||||
ReferenceLineMesh.current.geometry = Tube.current;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default createAndMoveReferenceLine;
|
||||
|
||||
@@ -1,88 +1,88 @@
|
||||
import { Socket } from "socket.io-client";
|
||||
// import { deleteLineApi } from "../../../../services/factoryBuilder/lines/deleteLineApi";
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
function deleteLine(
|
||||
hoveredDeletableLine: Types.RefMesh,
|
||||
onlyFloorlines: Types.RefOnlyFloorLines,
|
||||
lines: Types.RefLines,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
setDeletedLines: any,
|
||||
socket: Socket<any>
|
||||
): void {
|
||||
|
||||
////////// Deleting a line and the points if they are not connected to any other line //////////
|
||||
|
||||
if (!hoveredDeletableLine.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
const linePoints = hoveredDeletableLine.current.userData.linePoints;
|
||||
const connectedpoints = [linePoints[0][1], linePoints[1][1]];
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
//REST
|
||||
|
||||
// deleteLineApi(
|
||||
// organization,
|
||||
// [
|
||||
// { "uuid": linePoints[0][1] },
|
||||
// { "uuid": linePoints[1][1] }
|
||||
// ]
|
||||
// )
|
||||
|
||||
//SOCKET
|
||||
|
||||
const data = {
|
||||
organization: organization,
|
||||
line: [
|
||||
{ "uuid": linePoints[0][1] },
|
||||
{ "uuid": linePoints[1][1] }
|
||||
],
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
socket.emit('v1:Line:delete', data);
|
||||
|
||||
|
||||
onlyFloorlines.current = onlyFloorlines.current.map(floorline =>
|
||||
floorline.filter(line => line[0][1] !== connectedpoints[0] && line[1][1] !== connectedpoints[1])
|
||||
).filter(floorline => floorline.length > 0);
|
||||
|
||||
lines.current = lines.current.filter(item => item !== linePoints);
|
||||
(<any>hoveredDeletableLine.current.material).dispose();
|
||||
(<any>hoveredDeletableLine.current.geometry).dispose();
|
||||
floorPlanGroupLine.current.remove(hoveredDeletableLine.current);
|
||||
setDeletedLines([linePoints]);
|
||||
|
||||
connectedpoints.forEach((pointUUID) => {
|
||||
let isConnected = false;
|
||||
floorPlanGroupLine.current.children.forEach((line) => {
|
||||
const linePoints = line.userData.linePoints;
|
||||
const uuid1 = linePoints[0][1];
|
||||
const uuid2 = linePoints[1][1];
|
||||
if (uuid1 === pointUUID || uuid2 === pointUUID) {
|
||||
isConnected = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (!isConnected) {
|
||||
floorPlanGroupPoint.current.children.forEach((point: any) => {
|
||||
if (point.uuid === pointUUID) {
|
||||
(<any>point.material).dispose();
|
||||
(<any>point.geometry).dispose();
|
||||
floorPlanGroupPoint.current.remove(point);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
toast.success("Line Removed!");
|
||||
}
|
||||
|
||||
export default deleteLine;
|
||||
import { Socket } from "socket.io-client";
|
||||
// import { deleteLineApi } from "../../../../services/factoryBuilder/lines/deleteLineApi";
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
function deleteLine(
|
||||
hoveredDeletableLine: Types.RefMesh,
|
||||
onlyFloorlines: Types.RefOnlyFloorLines,
|
||||
lines: Types.RefLines,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
setDeletedLines: any,
|
||||
socket: Socket<any>
|
||||
): void {
|
||||
|
||||
////////// Deleting a line and the points if they are not connected to any other line //////////
|
||||
|
||||
if (!hoveredDeletableLine.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
const linePoints = hoveredDeletableLine.current.userData.linePoints;
|
||||
const connectedpoints = [linePoints[0][1], linePoints[1][1]];
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
//REST
|
||||
|
||||
// deleteLineApi(
|
||||
// organization,
|
||||
// [
|
||||
// { "uuid": linePoints[0][1] },
|
||||
// { "uuid": linePoints[1][1] }
|
||||
// ]
|
||||
// )
|
||||
|
||||
//SOCKET
|
||||
|
||||
const data = {
|
||||
organization: organization,
|
||||
line: [
|
||||
{ "uuid": linePoints[0][1] },
|
||||
{ "uuid": linePoints[1][1] }
|
||||
],
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
socket.emit('v1:Line:delete', data);
|
||||
|
||||
|
||||
onlyFloorlines.current = onlyFloorlines.current.map(floorline =>
|
||||
floorline.filter(line => line[0][1] !== connectedpoints[0] && line[1][1] !== connectedpoints[1])
|
||||
).filter(floorline => floorline.length > 0);
|
||||
|
||||
lines.current = lines.current.filter(item => item !== linePoints);
|
||||
(<any>hoveredDeletableLine.current.material).dispose();
|
||||
(<any>hoveredDeletableLine.current.geometry).dispose();
|
||||
floorPlanGroupLine.current.remove(hoveredDeletableLine.current);
|
||||
setDeletedLines([linePoints]);
|
||||
|
||||
connectedpoints.forEach((pointUUID) => {
|
||||
let isConnected = false;
|
||||
floorPlanGroupLine.current.children.forEach((line) => {
|
||||
const linePoints = line.userData.linePoints;
|
||||
const uuid1 = linePoints[0][1];
|
||||
const uuid2 = linePoints[1][1];
|
||||
if (uuid1 === pointUUID || uuid2 === pointUUID) {
|
||||
isConnected = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (!isConnected) {
|
||||
floorPlanGroupPoint.current.children.forEach((point: any) => {
|
||||
if (point.uuid === pointUUID) {
|
||||
(<any>point.material).dispose();
|
||||
(<any>point.geometry).dispose();
|
||||
floorPlanGroupPoint.current.remove(point);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
toast.success("Line Removed!");
|
||||
}
|
||||
|
||||
export default deleteLine;
|
||||
|
||||
@@ -1,90 +1,90 @@
|
||||
import { useEffect, useState } from "react"
|
||||
import { getLines } from "../../../../services/factoryBuilder/lines/getLinesApi";
|
||||
import * as THREE from "three";
|
||||
import { useActiveLayer, useDeletedLines, useNewLines, useToggleView } from "../../../../store/store";
|
||||
import objectLinesToArray from "./lineConvertions/objectLinesToArray";
|
||||
import { Html } from "@react-three/drei";
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
const DistanceText = () => {
|
||||
const [lines, setLines] = useState<{ distance: string; position: THREE.Vector3; userData: Types.Line; layer: string }[]>([]);
|
||||
const { activeLayer } = useActiveLayer();
|
||||
const { toggleView } = useToggleView();
|
||||
const { newLines, setNewLines } = useNewLines();
|
||||
const { deletedLines, setDeletedLines } = useDeletedLines();
|
||||
|
||||
useEffect(() => {
|
||||
const email = localStorage.getItem('email')
|
||||
if (!email) return;
|
||||
const organization = (email.split("@")[1]).split(".")[0];
|
||||
|
||||
getLines(organization).then((data) => {
|
||||
data = objectLinesToArray(data);
|
||||
|
||||
const lines = data.filter((line: Types.Line) => line[0][2] === activeLayer)
|
||||
.map((line: Types.Line) => {
|
||||
const point1 = new THREE.Vector3(line[0][0].x, line[0][0].y, line[0][0].z);
|
||||
const point2 = new THREE.Vector3(line[1][0].x, line[1][0].y, line[1][0].z);
|
||||
const distance = point1.distanceTo(point2);
|
||||
const midpoint = new THREE.Vector3().addVectors(point1, point2).divideScalar(2);
|
||||
return {
|
||||
distance: distance.toFixed(1),
|
||||
position: midpoint,
|
||||
userData: line,
|
||||
layer: activeLayer,
|
||||
};
|
||||
});
|
||||
setLines(lines)
|
||||
})
|
||||
}, [activeLayer])
|
||||
|
||||
useEffect(() => {
|
||||
if (newLines.length > 0) {
|
||||
if (newLines[0][0][2] !== activeLayer) return;
|
||||
const newLinesData = newLines.map((line: Types.Line) => {
|
||||
const point1 = new THREE.Vector3(line[0][0].x, line[0][0].y, line[0][0].z);
|
||||
const point2 = new THREE.Vector3(line[1][0].x, line[1][0].y, line[1][0].z);
|
||||
const distance = point1.distanceTo(point2);
|
||||
const midpoint = new THREE.Vector3().addVectors(point1, point2).divideScalar(2);
|
||||
|
||||
return {
|
||||
distance: distance.toFixed(1),
|
||||
position: midpoint,
|
||||
userData: line,
|
||||
layer: activeLayer,
|
||||
};
|
||||
});
|
||||
setLines((prevLines) => [...prevLines, ...newLinesData]);
|
||||
setNewLines([]);
|
||||
}
|
||||
}, [newLines, activeLayer]);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if ((deletedLines as Types.Lines).length > 0) {
|
||||
setLines((prevLines) =>
|
||||
prevLines.filter(
|
||||
(line) => !deletedLines.some((deletedLine: any) => deletedLine[0][1] === line.userData[0][1] && deletedLine[1][1] === line.userData[1][1])
|
||||
)
|
||||
);
|
||||
setDeletedLines([]);
|
||||
}
|
||||
}, [deletedLines]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{toggleView && (
|
||||
<group name='Distance_Text'>
|
||||
{lines.map((text) => (
|
||||
<Html key={`${text.userData[0][1]}_${text.userData[1][1]}`} transform sprite userData={text.userData} scale={5} position={[text.position.x, 1, text.position.z]} style={{ pointerEvents: 'none' }} >
|
||||
<div key={`${text.userData[0][1]}_${text.userData[1][1]}`} className={`Distance line-${text.userData[0][1]}_${text.userData[1][1]}_${text.layer}`} >{text.distance} m</div>
|
||||
</Html>
|
||||
))}
|
||||
</group>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
import { useEffect, useState } from "react"
|
||||
import { getLines } from "../../../../services/factoryBuilder/lines/getLinesApi";
|
||||
import * as THREE from "three";
|
||||
import { useActiveLayer, useDeletedLines, useNewLines, useToggleView } from "../../../../store/store";
|
||||
import objectLinesToArray from "./lineConvertions/objectLinesToArray";
|
||||
import { Html } from "@react-three/drei";
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
const DistanceText = () => {
|
||||
const [lines, setLines] = useState<{ distance: string; position: THREE.Vector3; userData: Types.Line; layer: string }[]>([]);
|
||||
const { activeLayer } = useActiveLayer();
|
||||
const { toggleView } = useToggleView();
|
||||
const { newLines, setNewLines } = useNewLines();
|
||||
const { deletedLines, setDeletedLines } = useDeletedLines();
|
||||
|
||||
useEffect(() => {
|
||||
const email = localStorage.getItem('email')
|
||||
if (!email) return;
|
||||
const organization = (email.split("@")[1]).split(".")[0];
|
||||
|
||||
getLines(organization).then((data) => {
|
||||
data = objectLinesToArray(data);
|
||||
|
||||
const lines = data.filter((line: Types.Line) => line[0][2] === activeLayer)
|
||||
.map((line: Types.Line) => {
|
||||
const point1 = new THREE.Vector3(line[0][0].x, line[0][0].y, line[0][0].z);
|
||||
const point2 = new THREE.Vector3(line[1][0].x, line[1][0].y, line[1][0].z);
|
||||
const distance = point1.distanceTo(point2);
|
||||
const midpoint = new THREE.Vector3().addVectors(point1, point2).divideScalar(2);
|
||||
return {
|
||||
distance: distance.toFixed(1),
|
||||
position: midpoint,
|
||||
userData: line,
|
||||
layer: activeLayer,
|
||||
};
|
||||
});
|
||||
setLines(lines)
|
||||
})
|
||||
}, [activeLayer])
|
||||
|
||||
useEffect(() => {
|
||||
if (newLines.length > 0) {
|
||||
if (newLines[0][0][2] !== activeLayer) return;
|
||||
const newLinesData = newLines.map((line: Types.Line) => {
|
||||
const point1 = new THREE.Vector3(line[0][0].x, line[0][0].y, line[0][0].z);
|
||||
const point2 = new THREE.Vector3(line[1][0].x, line[1][0].y, line[1][0].z);
|
||||
const distance = point1.distanceTo(point2);
|
||||
const midpoint = new THREE.Vector3().addVectors(point1, point2).divideScalar(2);
|
||||
|
||||
return {
|
||||
distance: distance.toFixed(1),
|
||||
position: midpoint,
|
||||
userData: line,
|
||||
layer: activeLayer,
|
||||
};
|
||||
});
|
||||
setLines((prevLines) => [...prevLines, ...newLinesData]);
|
||||
setNewLines([]);
|
||||
}
|
||||
}, [newLines, activeLayer]);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if ((deletedLines as Types.Lines).length > 0) {
|
||||
setLines((prevLines) =>
|
||||
prevLines.filter(
|
||||
(line) => !deletedLines.some((deletedLine: any) => deletedLine[0][1] === line.userData[0][1] && deletedLine[1][1] === line.userData[1][1])
|
||||
)
|
||||
);
|
||||
setDeletedLines([]);
|
||||
}
|
||||
}, [deletedLines]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{toggleView && (
|
||||
<group name='Distance_Text'>
|
||||
{lines.map((text) => (
|
||||
<Html key={`${text.userData[0][1]}_${text.userData[1][1]}`} transform sprite userData={text.userData} scale={5} position={[text.position.x, 1, text.position.z]} style={{ pointerEvents: 'none' }} >
|
||||
<div key={`${text.userData[0][1]}_${text.userData[1][1]}`} className={`Distance line-${text.userData[0][1]}_${text.userData[1][1]}_${text.layer}`} >{text.distance} m</div>
|
||||
</Html>
|
||||
))}
|
||||
</group>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
export default DistanceText;
|
||||
@@ -1,167 +1,167 @@
|
||||
import * as THREE from 'three';
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
|
||||
import addPointToScene from '../points/addPointToScene';
|
||||
import addLineToScene from './addLineToScene';
|
||||
import splitLine from './splitLine';
|
||||
import removeReferenceLine from './removeReferenceLine';
|
||||
import getClosestIntersection from './getClosestIntersection';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import arrayLineToObject from './lineConvertions/arrayLineToObject';
|
||||
// import { setLine } from '../../../../services/factoryBuilder/lines/setLineApi';
|
||||
import { Socket } from 'socket.io-client';
|
||||
|
||||
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>
|
||||
): Promise<void> {
|
||||
|
||||
////////// Creating lines Based on the positions clicked //////////
|
||||
|
||||
////////// 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);
|
||||
|
||||
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);
|
||||
|
||||
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 (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);
|
||||
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,]);
|
||||
|
||||
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
|
||||
const data = arrayLineToObject(line.current as Types.Line);
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
//REST
|
||||
|
||||
// setLine(organization, data.layer!, data.line!, data.type!);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const input = {
|
||||
organization: organization,
|
||||
layer: data.layer,
|
||||
line: data.line,
|
||||
type: data.type,
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (intersects && intersects.length > 0) {
|
||||
|
||||
////////// Clicked on a emply place or a 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 (!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,]);
|
||||
|
||||
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
|
||||
const data = arrayLineToObject(line.current as Types.Line);
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
//REST
|
||||
|
||||
// setLine(organization, data.layer!, data.line!, data.type!);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const input = {
|
||||
organization: organization,
|
||||
layer: data.layer,
|
||||
line: data.line,
|
||||
type: data.type,
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default drawWall;
|
||||
import * as THREE from 'three';
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
|
||||
import addPointToScene from '../points/addPointToScene';
|
||||
import addLineToScene from './addLineToScene';
|
||||
import splitLine from './splitLine';
|
||||
import removeReferenceLine from './removeReferenceLine';
|
||||
import getClosestIntersection from './getClosestIntersection';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import arrayLineToObject from './lineConvertions/arrayLineToObject';
|
||||
// import { setLine } from '../../../../services/factoryBuilder/lines/setLineApi';
|
||||
import { Socket } from 'socket.io-client';
|
||||
|
||||
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>
|
||||
): Promise<void> {
|
||||
|
||||
////////// Creating lines Based on the positions clicked //////////
|
||||
|
||||
////////// 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);
|
||||
|
||||
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);
|
||||
|
||||
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 (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);
|
||||
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,]);
|
||||
|
||||
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
|
||||
const data = arrayLineToObject(line.current as Types.Line);
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
//REST
|
||||
|
||||
// setLine(organization, data.layer!, data.line!, data.type!);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const input = {
|
||||
organization: organization,
|
||||
layer: data.layer,
|
||||
line: data.line,
|
||||
type: data.type,
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (intersects && intersects.length > 0) {
|
||||
|
||||
////////// Clicked on a emply place or a 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 (!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,]);
|
||||
|
||||
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
|
||||
const data = arrayLineToObject(line.current as Types.Line);
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
//REST
|
||||
|
||||
// setLine(organization, data.layer!, data.line!, data.type!);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const input = {
|
||||
organization: organization,
|
||||
layer: data.layer,
|
||||
line: data.line,
|
||||
type: data.type,
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default drawWall;
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
import * as THREE from 'three';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function getClosestIntersection(
|
||||
intersects: Types.Vector3Array,
|
||||
point: Types.Vector3
|
||||
): Types.Vector3 | null {
|
||||
|
||||
////////// A function that finds which point is closest from the intersects points that is given, Used in finding which point in a line is closest when clicked on a line during drawing //////////
|
||||
|
||||
let closestNewPoint: THREE.Vector3 | null = null;
|
||||
let minDistance = Infinity;
|
||||
|
||||
for (const intersect of intersects) {
|
||||
const distance = point.distanceTo(intersect);
|
||||
if (distance < minDistance) {
|
||||
minDistance = distance;
|
||||
closestNewPoint = intersect;
|
||||
}
|
||||
}
|
||||
|
||||
return closestNewPoint;
|
||||
}
|
||||
|
||||
export default getClosestIntersection;
|
||||
import * as THREE from 'three';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function getClosestIntersection(
|
||||
intersects: Types.Vector3Array,
|
||||
point: Types.Vector3
|
||||
): Types.Vector3 | null {
|
||||
|
||||
////////// A function that finds which point is closest from the intersects points that is given, Used in finding which point in a line is closest when clicked on a line during drawing //////////
|
||||
|
||||
let closestNewPoint: THREE.Vector3 | null = null;
|
||||
let minDistance = Infinity;
|
||||
|
||||
for (const intersect of intersects) {
|
||||
const distance = point.distanceTo(intersect);
|
||||
if (distance < minDistance) {
|
||||
minDistance = distance;
|
||||
closestNewPoint = intersect;
|
||||
}
|
||||
}
|
||||
|
||||
return closestNewPoint;
|
||||
}
|
||||
|
||||
export default getClosestIntersection;
|
||||
|
||||
@@ -1,86 +1,86 @@
|
||||
import * as THREE from 'three';
|
||||
import * as turf from '@turf/turf';
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
async function getRoomsFromLines(lines: Types.RefLines) {
|
||||
const rooms: Types.Rooms = [];
|
||||
|
||||
if (lines.current.length > 2) {
|
||||
const linesByLayer = lines.current.reduce((acc: { [key: number]: any[] }, pair) => {
|
||||
const layer = pair[0][2];
|
||||
if (!acc[layer]) acc[layer] = [];
|
||||
acc[layer].push(pair);
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
////////// Use turf.polygonize to create polygons from the line points //////////
|
||||
|
||||
for (const layer in linesByLayer) {
|
||||
|
||||
let linesInLayer = linesByLayer[layer];
|
||||
linesInLayer = linesInLayer.filter(line => line[0][3] && line[1][3] === CONSTANTS.lineConfig.wallName);
|
||||
const result = linesInLayer.map((pair: [THREE.Vector3, string, number, string][]) =>
|
||||
pair.map((point) => ({
|
||||
position: [point[0].x, point[0].z],
|
||||
uuid: point[1]
|
||||
}))
|
||||
);
|
||||
const lineFeatures = result.map(line => turf.lineString(line.map(p => p.position)));
|
||||
const polygons = turf.polygonize(turf.featureCollection(lineFeatures));
|
||||
|
||||
let union: any[] = [];
|
||||
|
||||
polygons.features.forEach((feature) => {
|
||||
union.push(feature);
|
||||
});
|
||||
|
||||
if (union.length > 1) {
|
||||
const unionResult = turf.union(turf.featureCollection(union));
|
||||
if (unionResult?.geometry.type === "MultiPolygon") {
|
||||
unionResult?.geometry.coordinates.forEach((poly) => {
|
||||
const Coordinates = poly[0].map(([x, z]) => {
|
||||
const matchingPoint = result.flat().find(r =>
|
||||
r.position[0].toFixed(10) === x.toFixed(10) &&
|
||||
r.position[1].toFixed(10) === z.toFixed(10)
|
||||
);
|
||||
return {
|
||||
position: new THREE.Vector3(x, 0, z),
|
||||
uuid: matchingPoint ? matchingPoint.uuid : ''
|
||||
};
|
||||
});
|
||||
rooms.push({ coordinates: Coordinates.reverse(), layer: parseInt(layer) });
|
||||
});
|
||||
} else if (unionResult?.geometry.type === "Polygon") {
|
||||
const Coordinates = unionResult?.geometry.coordinates[0].map(([x, z]) => {
|
||||
const matchingPoint = result.flat().find(r =>
|
||||
r.position[0].toFixed(10) === x.toFixed(10) &&
|
||||
r.position[1].toFixed(10) === z.toFixed(10)
|
||||
);
|
||||
return {
|
||||
position: new THREE.Vector3(x, 0, z),
|
||||
uuid: matchingPoint ? matchingPoint.uuid : ''
|
||||
};
|
||||
});
|
||||
rooms.push({ coordinates: Coordinates.reverse(), layer: parseInt(layer) });
|
||||
}
|
||||
} else if (union.length === 1) {
|
||||
const Coordinates = union[0].geometry.coordinates[0].map(([x, z]: [number, number]) => {
|
||||
const matchingPoint = result.flat().find(r =>
|
||||
r.position[0].toFixed(10) === x.toFixed(10) &&
|
||||
r.position[1].toFixed(10) === z.toFixed(10)
|
||||
);
|
||||
return {
|
||||
position: new THREE.Vector3(x, 0, z),
|
||||
uuid: matchingPoint ? matchingPoint.uuid : ''
|
||||
};
|
||||
});
|
||||
rooms.push({ coordinates: Coordinates, layer: parseInt(layer) });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rooms;
|
||||
}
|
||||
|
||||
export default getRoomsFromLines;
|
||||
import * as THREE from 'three';
|
||||
import * as turf from '@turf/turf';
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
async function getRoomsFromLines(lines: Types.RefLines) {
|
||||
const rooms: Types.Rooms = [];
|
||||
|
||||
if (lines.current.length > 2) {
|
||||
const linesByLayer = lines.current.reduce((acc: { [key: number]: any[] }, pair) => {
|
||||
const layer = pair[0][2];
|
||||
if (!acc[layer]) acc[layer] = [];
|
||||
acc[layer].push(pair);
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
////////// Use turf.polygonize to create polygons from the line points //////////
|
||||
|
||||
for (const layer in linesByLayer) {
|
||||
|
||||
let linesInLayer = linesByLayer[layer];
|
||||
linesInLayer = linesInLayer.filter(line => line[0][3] && line[1][3] === CONSTANTS.lineConfig.wallName);
|
||||
const result = linesInLayer.map((pair: [THREE.Vector3, string, number, string][]) =>
|
||||
pair.map((point) => ({
|
||||
position: [point[0].x, point[0].z],
|
||||
uuid: point[1]
|
||||
}))
|
||||
);
|
||||
const lineFeatures = result.map(line => turf.lineString(line.map(p => p.position)));
|
||||
const polygons = turf.polygonize(turf.featureCollection(lineFeatures));
|
||||
|
||||
let union: any[] = [];
|
||||
|
||||
polygons.features.forEach((feature) => {
|
||||
union.push(feature);
|
||||
});
|
||||
|
||||
if (union.length > 1) {
|
||||
const unionResult = turf.union(turf.featureCollection(union));
|
||||
if (unionResult?.geometry.type === "MultiPolygon") {
|
||||
unionResult?.geometry.coordinates.forEach((poly) => {
|
||||
const Coordinates = poly[0].map(([x, z]) => {
|
||||
const matchingPoint = result.flat().find(r =>
|
||||
r.position[0].toFixed(10) === x.toFixed(10) &&
|
||||
r.position[1].toFixed(10) === z.toFixed(10)
|
||||
);
|
||||
return {
|
||||
position: new THREE.Vector3(x, 0, z),
|
||||
uuid: matchingPoint ? matchingPoint.uuid : ''
|
||||
};
|
||||
});
|
||||
rooms.push({ coordinates: Coordinates.reverse(), layer: parseInt(layer) });
|
||||
});
|
||||
} else if (unionResult?.geometry.type === "Polygon") {
|
||||
const Coordinates = unionResult?.geometry.coordinates[0].map(([x, z]) => {
|
||||
const matchingPoint = result.flat().find(r =>
|
||||
r.position[0].toFixed(10) === x.toFixed(10) &&
|
||||
r.position[1].toFixed(10) === z.toFixed(10)
|
||||
);
|
||||
return {
|
||||
position: new THREE.Vector3(x, 0, z),
|
||||
uuid: matchingPoint ? matchingPoint.uuid : ''
|
||||
};
|
||||
});
|
||||
rooms.push({ coordinates: Coordinates.reverse(), layer: parseInt(layer) });
|
||||
}
|
||||
} else if (union.length === 1) {
|
||||
const Coordinates = union[0].geometry.coordinates[0].map(([x, z]: [number, number]) => {
|
||||
const matchingPoint = result.flat().find(r =>
|
||||
r.position[0].toFixed(10) === x.toFixed(10) &&
|
||||
r.position[1].toFixed(10) === z.toFixed(10)
|
||||
);
|
||||
return {
|
||||
position: new THREE.Vector3(x, 0, z),
|
||||
uuid: matchingPoint ? matchingPoint.uuid : ''
|
||||
};
|
||||
});
|
||||
rooms.push({ coordinates: Coordinates, layer: parseInt(layer) });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rooms;
|
||||
}
|
||||
|
||||
export default getRoomsFromLines;
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import * as Types from "../../../../../types/world/worldTypes";
|
||||
|
||||
export default function arrayLineToObject(array: Types.Line) {
|
||||
if (!Array.isArray(array)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// Extract common properties from the first point
|
||||
const commonLayer = array[0][2];
|
||||
const commonType = array[0][3];
|
||||
|
||||
// Map points into a structured format
|
||||
const line = array.map(([position, uuid]) => ({
|
||||
position,
|
||||
uuid,
|
||||
}));
|
||||
|
||||
// Create the final structured object
|
||||
return {
|
||||
layer: commonLayer,
|
||||
type: commonType,
|
||||
line,
|
||||
};
|
||||
import * as Types from "../../../../../types/world/worldTypes";
|
||||
|
||||
export default function arrayLineToObject(array: Types.Line) {
|
||||
if (!Array.isArray(array)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// Extract common properties from the first point
|
||||
const commonLayer = array[0][2];
|
||||
const commonType = array[0][3];
|
||||
|
||||
// Map points into a structured format
|
||||
const line = array.map(([position, uuid]) => ({
|
||||
position,
|
||||
uuid,
|
||||
}));
|
||||
|
||||
// Create the final structured object
|
||||
return {
|
||||
layer: commonLayer,
|
||||
type: commonType,
|
||||
line,
|
||||
};
|
||||
}
|
||||
@@ -1,30 +1,30 @@
|
||||
import * as Types from "../../../../../types/world/worldTypes";
|
||||
|
||||
export default function arrayLinesToObject(array: Array<Types.Line>) {
|
||||
if (!Array.isArray(array)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return array.map((lineArray) => {
|
||||
if (!Array.isArray(lineArray)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Extract common properties from the first point
|
||||
const commonLayer = lineArray[0][2];
|
||||
const commonType = lineArray[0][3];
|
||||
|
||||
// Map points into a structured format
|
||||
const line = lineArray.map(([position, uuid]) => ({
|
||||
position,
|
||||
uuid,
|
||||
}));
|
||||
|
||||
// Create the final structured object
|
||||
return {
|
||||
layer: commonLayer,
|
||||
type: commonType,
|
||||
line,
|
||||
};
|
||||
}).filter((item) => item !== null); // Filter out invalid entries
|
||||
}
|
||||
import * as Types from "../../../../../types/world/worldTypes";
|
||||
|
||||
export default function arrayLinesToObject(array: Array<Types.Line>) {
|
||||
if (!Array.isArray(array)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return array.map((lineArray) => {
|
||||
if (!Array.isArray(lineArray)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Extract common properties from the first point
|
||||
const commonLayer = lineArray[0][2];
|
||||
const commonType = lineArray[0][3];
|
||||
|
||||
// Map points into a structured format
|
||||
const line = lineArray.map(([position, uuid]) => ({
|
||||
position,
|
||||
uuid,
|
||||
}));
|
||||
|
||||
// Create the final structured object
|
||||
return {
|
||||
layer: commonLayer,
|
||||
type: commonType,
|
||||
line,
|
||||
};
|
||||
}).filter((item) => item !== null); // Filter out invalid entries
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import * as THREE from 'three';
|
||||
|
||||
export default function objectLineToArray(structuredObject: any) {
|
||||
if (!structuredObject || !structuredObject.line) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Destructure common properties
|
||||
const { layer, type, line } = structuredObject;
|
||||
|
||||
// Map points back to the original array format
|
||||
return line.map(({ position, uuid }: any) => [new THREE.Vector3(position.x, position.y, position.z), uuid, layer, type]);
|
||||
import * as THREE from 'three';
|
||||
|
||||
export default function objectLineToArray(structuredObject: any) {
|
||||
if (!structuredObject || !structuredObject.line) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Destructure common properties
|
||||
const { layer, type, line } = structuredObject;
|
||||
|
||||
// Map points back to the original array format
|
||||
return line.map(({ position, uuid }: any) => [new THREE.Vector3(position.x, position.y, position.z), uuid, layer, type]);
|
||||
}
|
||||
@@ -1,20 +1,20 @@
|
||||
import * as THREE from 'three';
|
||||
|
||||
export default function objectLinesToArray(structuredObjects: any): any {
|
||||
if (!Array.isArray(structuredObjects)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return structuredObjects.map((structuredObject) => {
|
||||
if (!structuredObject || !structuredObject.line) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const { layer, type, line } = structuredObject;
|
||||
|
||||
return line.map(({ position, uuid }: any) => {
|
||||
const vector = new THREE.Vector3(position.x, position.y, position.z);
|
||||
return [vector, uuid, layer, type];
|
||||
});
|
||||
});
|
||||
}
|
||||
import * as THREE from 'three';
|
||||
|
||||
export default function objectLinesToArray(structuredObjects: any): any {
|
||||
if (!Array.isArray(structuredObjects)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return structuredObjects.map((structuredObject) => {
|
||||
if (!structuredObject || !structuredObject.line) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const { layer, type, line } = structuredObject;
|
||||
|
||||
return line.map(({ position, uuid }: any) => {
|
||||
const vector = new THREE.Vector3(position.x, position.y, position.z);
|
||||
return [vector, uuid, layer, type];
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,48 +1,48 @@
|
||||
import * as THREE from 'three';
|
||||
import { Html } from '@react-three/drei';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useActiveLayer } from '../../../../store/store';
|
||||
|
||||
const ReferenceDistanceText = ({ line }: { line: any }) => {
|
||||
interface TextState {
|
||||
distance: string;
|
||||
position: THREE.Vector3;
|
||||
userData: any;
|
||||
layer: any;
|
||||
}
|
||||
|
||||
const [text, setTexts] = useState<TextState | null>(null);
|
||||
const { activeLayer } = useActiveLayer();
|
||||
|
||||
useEffect(() => {
|
||||
if (line) {
|
||||
if (line.parent === null) {
|
||||
setTexts(null);
|
||||
return;
|
||||
}
|
||||
const distance = line.userData.linePoints.cursorPosition.distanceTo(line.userData.linePoints.startPoint);
|
||||
const midpoint = new THREE.Vector3().addVectors(line.userData.linePoints.cursorPosition, line.userData.linePoints.startPoint).divideScalar(2);
|
||||
const newTexts = {
|
||||
distance: distance.toFixed(1),
|
||||
position: midpoint,
|
||||
userData: line,
|
||||
layer: activeLayer
|
||||
};
|
||||
setTexts(newTexts);
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<group name='Reference_Distance_Text'>
|
||||
<mesh>
|
||||
{text !== null &&
|
||||
< Html transform sprite key={text.distance} userData={text.userData} scale={5} position={[text.position.x, 1, text.position.z]} style={{ pointerEvents: 'none' }}>
|
||||
<div className={`Reference_Distance line-${text.userData.userData}`}>{text.distance} m</div>
|
||||
</Html>
|
||||
}
|
||||
</mesh>
|
||||
</group >
|
||||
);
|
||||
};
|
||||
|
||||
import * as THREE from 'three';
|
||||
import { Html } from '@react-three/drei';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useActiveLayer } from '../../../../store/store';
|
||||
|
||||
const ReferenceDistanceText = ({ line }: { line: any }) => {
|
||||
interface TextState {
|
||||
distance: string;
|
||||
position: THREE.Vector3;
|
||||
userData: any;
|
||||
layer: any;
|
||||
}
|
||||
|
||||
const [text, setTexts] = useState<TextState | null>(null);
|
||||
const { activeLayer } = useActiveLayer();
|
||||
|
||||
useEffect(() => {
|
||||
if (line) {
|
||||
if (line.parent === null) {
|
||||
setTexts(null);
|
||||
return;
|
||||
}
|
||||
const distance = line.userData.linePoints.cursorPosition.distanceTo(line.userData.linePoints.startPoint);
|
||||
const midpoint = new THREE.Vector3().addVectors(line.userData.linePoints.cursorPosition, line.userData.linePoints.startPoint).divideScalar(2);
|
||||
const newTexts = {
|
||||
distance: distance.toFixed(1),
|
||||
position: midpoint,
|
||||
userData: line,
|
||||
layer: activeLayer
|
||||
};
|
||||
setTexts(newTexts);
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<group name='Reference_Distance_Text'>
|
||||
<mesh>
|
||||
{text !== null &&
|
||||
< Html transform sprite key={text.distance} userData={text.userData} scale={5} position={[text.position.x, 1, text.position.z]} style={{ pointerEvents: 'none' }}>
|
||||
<div className={`Reference_Distance line-${text.userData.userData}`}>{text.distance} m</div>
|
||||
</Html>
|
||||
}
|
||||
</mesh>
|
||||
</group >
|
||||
);
|
||||
};
|
||||
|
||||
export default ReferenceDistanceText;
|
||||
@@ -1,66 +1,66 @@
|
||||
import * as THREE from 'three';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function RemoveConnectedLines(
|
||||
DeletedPointUUID: Types.String,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
setDeletedLines: any,
|
||||
lines: Types.RefLines,
|
||||
): void {
|
||||
|
||||
////////// Check if any and how many lines are connected to the deleted point //////////
|
||||
|
||||
const removableLines: THREE.Mesh[] = [];
|
||||
const connectedpoints: string[] = [];
|
||||
|
||||
const removedLinePoints: [number, string, number][][] = []; // Array to hold linePoints of removed lines
|
||||
|
||||
floorPlanGroupLine.current.children.forEach((line) => {
|
||||
const linePoints = line.userData.linePoints as [number, string, number][];
|
||||
const uuid1 = linePoints[0][1];
|
||||
const uuid2 = linePoints[1][1];
|
||||
|
||||
if (uuid1 === DeletedPointUUID || uuid2 === DeletedPointUUID) {
|
||||
connectedpoints.push(uuid1 === DeletedPointUUID ? uuid2 : uuid1);
|
||||
removableLines.push(line as THREE.Mesh);
|
||||
removedLinePoints.push(linePoints);
|
||||
}
|
||||
});
|
||||
|
||||
if (removableLines.length > 0) {
|
||||
removableLines.forEach((line) => {
|
||||
lines.current = lines.current.filter(item => item !== line.userData.linePoints);
|
||||
(<any>line.material).dispose();
|
||||
(<any>line.geometry).dispose();
|
||||
floorPlanGroupLine.current.remove(line);
|
||||
});
|
||||
}
|
||||
setDeletedLines(removedLinePoints)
|
||||
|
||||
////////// Check and Remove point that are no longer connected to any lines //////////
|
||||
|
||||
connectedpoints.forEach((pointUUID) => {
|
||||
let isConnected = false;
|
||||
floorPlanGroupLine.current.children.forEach((line) => {
|
||||
const linePoints = line.userData.linePoints as [number, string, number][];
|
||||
const uuid1 = linePoints[0][1];
|
||||
const uuid2 = linePoints[1][1];
|
||||
if (uuid1 === pointUUID || uuid2 === pointUUID) {
|
||||
isConnected = true;
|
||||
}
|
||||
});
|
||||
if (!isConnected) {
|
||||
floorPlanGroupPoint.current.children.forEach((point: any) => {
|
||||
if (point.uuid === pointUUID) {
|
||||
(<any>point.material).dispose();
|
||||
(<any>point.geometry).dispose();
|
||||
floorPlanGroupPoint.current.remove(point);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default RemoveConnectedLines;
|
||||
import * as THREE from 'three';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function RemoveConnectedLines(
|
||||
DeletedPointUUID: Types.String,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
setDeletedLines: any,
|
||||
lines: Types.RefLines,
|
||||
): void {
|
||||
|
||||
////////// Check if any and how many lines are connected to the deleted point //////////
|
||||
|
||||
const removableLines: THREE.Mesh[] = [];
|
||||
const connectedpoints: string[] = [];
|
||||
|
||||
const removedLinePoints: [number, string, number][][] = []; // Array to hold linePoints of removed lines
|
||||
|
||||
floorPlanGroupLine.current.children.forEach((line) => {
|
||||
const linePoints = line.userData.linePoints as [number, string, number][];
|
||||
const uuid1 = linePoints[0][1];
|
||||
const uuid2 = linePoints[1][1];
|
||||
|
||||
if (uuid1 === DeletedPointUUID || uuid2 === DeletedPointUUID) {
|
||||
connectedpoints.push(uuid1 === DeletedPointUUID ? uuid2 : uuid1);
|
||||
removableLines.push(line as THREE.Mesh);
|
||||
removedLinePoints.push(linePoints);
|
||||
}
|
||||
});
|
||||
|
||||
if (removableLines.length > 0) {
|
||||
removableLines.forEach((line) => {
|
||||
lines.current = lines.current.filter(item => item !== line.userData.linePoints);
|
||||
(<any>line.material).dispose();
|
||||
(<any>line.geometry).dispose();
|
||||
floorPlanGroupLine.current.remove(line);
|
||||
});
|
||||
}
|
||||
setDeletedLines(removedLinePoints)
|
||||
|
||||
////////// Check and Remove point that are no longer connected to any lines //////////
|
||||
|
||||
connectedpoints.forEach((pointUUID) => {
|
||||
let isConnected = false;
|
||||
floorPlanGroupLine.current.children.forEach((line) => {
|
||||
const linePoints = line.userData.linePoints as [number, string, number][];
|
||||
const uuid1 = linePoints[0][1];
|
||||
const uuid2 = linePoints[1][1];
|
||||
if (uuid1 === pointUUID || uuid2 === pointUUID) {
|
||||
isConnected = true;
|
||||
}
|
||||
});
|
||||
if (!isConnected) {
|
||||
floorPlanGroupPoint.current.children.forEach((point: any) => {
|
||||
if (point.uuid === pointUUID) {
|
||||
(<any>point.material).dispose();
|
||||
(<any>point.geometry).dispose();
|
||||
floorPlanGroupPoint.current.remove(point);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default RemoveConnectedLines;
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function removeReferenceLine(
|
||||
floorPlanGroup: Types.RefGroup,
|
||||
ReferenceLineMesh: Types.RefMesh,
|
||||
LineCreated: Types.RefBoolean,
|
||||
line: Types.RefLine
|
||||
): void {
|
||||
|
||||
////////// Removes Dangling reference line if the draw mode is ended or any other case //////////
|
||||
|
||||
line.current = [];
|
||||
if (ReferenceLineMesh.current) {
|
||||
(<any>ReferenceLineMesh.current.material).dispose();
|
||||
(<any>ReferenceLineMesh.current.geometry).dispose();
|
||||
floorPlanGroup.current.remove(ReferenceLineMesh.current);
|
||||
LineCreated.current = false;
|
||||
ReferenceLineMesh.current = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function removeReferenceLine(
|
||||
floorPlanGroup: Types.RefGroup,
|
||||
ReferenceLineMesh: Types.RefMesh,
|
||||
LineCreated: Types.RefBoolean,
|
||||
line: Types.RefLine
|
||||
): void {
|
||||
|
||||
////////// Removes Dangling reference line if the draw mode is ended or any other case //////////
|
||||
|
||||
line.current = [];
|
||||
if (ReferenceLineMesh.current) {
|
||||
(<any>ReferenceLineMesh.current.material).dispose();
|
||||
(<any>ReferenceLineMesh.current.geometry).dispose();
|
||||
floorPlanGroup.current.remove(ReferenceLineMesh.current);
|
||||
LineCreated.current = false;
|
||||
ReferenceLineMesh.current = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export default removeReferenceLine;
|
||||
@@ -1,124 +1,124 @@
|
||||
import * as THREE from 'three';
|
||||
|
||||
import addLineToScene from './addLineToScene';
|
||||
import addPointToScene from '../points/addPointToScene';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import arrayLineToObject from '../lines/lineConvertions/arrayLineToObject';
|
||||
import { Socket } from 'socket.io-client';
|
||||
// import { deleteLineApi } from '../../../../services/factoryBuilder/lines/deleteLineApi';
|
||||
// import { setLine } from '../../../../services/factoryBuilder/lines/setLineApi';
|
||||
|
||||
function splitLine(
|
||||
visibleIntersect: Types.IntersectionEvent,
|
||||
intersectionPoint: Types.Vector3,
|
||||
currentLayerPoint: Types.RefMeshArray,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
dragPointControls: Types.RefDragControl,
|
||||
isSnappedUUID: Types.RefString,
|
||||
lines: Types.RefLines,
|
||||
setDeletedLines: any,
|
||||
floorPlanGroupLine: { current: THREE.Group },
|
||||
socket: Socket<any>,
|
||||
pointColor: Types.String,
|
||||
lineColor: Types.String,
|
||||
lineType: Types.String,
|
||||
): [Types.Line, Types.Line] {
|
||||
|
||||
////////// Removing the clicked line and splitting it with the clicked position adding a new point and two new lines //////////
|
||||
|
||||
|
||||
((visibleIntersect.object as any).material).dispose();
|
||||
((visibleIntersect.object as any).geometry).dispose();
|
||||
floorPlanGroupLine.current.remove(visibleIntersect.object);
|
||||
setDeletedLines([visibleIntersect.object.userData.linePoints]);
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
//REST
|
||||
|
||||
// deleteLineApi(
|
||||
// organization,
|
||||
// [
|
||||
// { "uuid": visibleIntersect.object.userData.linePoints[0][1] },
|
||||
// { "uuid": visibleIntersect.object.userData.linePoints[1][1] }
|
||||
// ]
|
||||
// )
|
||||
|
||||
//SOCKET
|
||||
|
||||
|
||||
const data = {
|
||||
organization: organization,
|
||||
line: [
|
||||
{ "uuid": visibleIntersect.object.userData.linePoints[0][1] },
|
||||
{ "uuid": visibleIntersect.object.userData.linePoints[1][1] }
|
||||
],
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
socket.emit('v1:Line:delete', data);
|
||||
|
||||
const point = addPointToScene(intersectionPoint, pointColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, isSnappedUUID, lineType);
|
||||
|
||||
const oldLinePoints = visibleIntersect.object.userData.linePoints;
|
||||
lines.current = lines.current.filter(item => item !== oldLinePoints);
|
||||
|
||||
const clickedPoint: Types.Point = [
|
||||
new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z),
|
||||
point.uuid,
|
||||
oldLinePoints[0][2],
|
||||
lineType
|
||||
];
|
||||
|
||||
const start = oldLinePoints[0];
|
||||
const end = oldLinePoints[1];
|
||||
|
||||
const newLine1: Types.Line = [start, clickedPoint];
|
||||
const newLine2: Types.Line = [clickedPoint, end];
|
||||
|
||||
const line1 = arrayLineToObject(newLine1);
|
||||
const line2 = arrayLineToObject(newLine2);
|
||||
|
||||
//REST
|
||||
|
||||
// setLine(organization, line1.layer!, line1.line!, line1.type!);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const input1 = {
|
||||
organization: organization,
|
||||
layer: line1.layer,
|
||||
line: line1.line,
|
||||
type: line1.type,
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
socket.emit('v1:Line:create', input1);
|
||||
|
||||
//REST
|
||||
|
||||
// setLine(organization, line2.layer!, line2.line!, line2.type!);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const input2 = {
|
||||
organization: organization,
|
||||
layer: line2.layer,
|
||||
line: line2.line,
|
||||
type: line2.type,
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
socket.emit('v1:Line:create', input2);
|
||||
|
||||
lines.current.push(newLine1, newLine2);
|
||||
|
||||
addLineToScene(newLine1[0][0], newLine1[1][0], lineColor, newLine1, floorPlanGroupLine);
|
||||
addLineToScene(newLine2[0][0], newLine2[1][0], lineColor, newLine2, floorPlanGroupLine);
|
||||
|
||||
return [newLine1, newLine2];
|
||||
}
|
||||
|
||||
export default splitLine;
|
||||
import * as THREE from 'three';
|
||||
|
||||
import addLineToScene from './addLineToScene';
|
||||
import addPointToScene from '../points/addPointToScene';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import arrayLineToObject from '../lines/lineConvertions/arrayLineToObject';
|
||||
import { Socket } from 'socket.io-client';
|
||||
// import { deleteLineApi } from '../../../../services/factoryBuilder/lines/deleteLineApi';
|
||||
// import { setLine } from '../../../../services/factoryBuilder/lines/setLineApi';
|
||||
|
||||
function splitLine(
|
||||
visibleIntersect: Types.IntersectionEvent,
|
||||
intersectionPoint: Types.Vector3,
|
||||
currentLayerPoint: Types.RefMeshArray,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
dragPointControls: Types.RefDragControl,
|
||||
isSnappedUUID: Types.RefString,
|
||||
lines: Types.RefLines,
|
||||
setDeletedLines: any,
|
||||
floorPlanGroupLine: { current: THREE.Group },
|
||||
socket: Socket<any>,
|
||||
pointColor: Types.String,
|
||||
lineColor: Types.String,
|
||||
lineType: Types.String,
|
||||
): [Types.Line, Types.Line] {
|
||||
|
||||
////////// Removing the clicked line and splitting it with the clicked position adding a new point and two new lines //////////
|
||||
|
||||
|
||||
((visibleIntersect.object as any).material).dispose();
|
||||
((visibleIntersect.object as any).geometry).dispose();
|
||||
floorPlanGroupLine.current.remove(visibleIntersect.object);
|
||||
setDeletedLines([visibleIntersect.object.userData.linePoints]);
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
//REST
|
||||
|
||||
// deleteLineApi(
|
||||
// organization,
|
||||
// [
|
||||
// { "uuid": visibleIntersect.object.userData.linePoints[0][1] },
|
||||
// { "uuid": visibleIntersect.object.userData.linePoints[1][1] }
|
||||
// ]
|
||||
// )
|
||||
|
||||
//SOCKET
|
||||
|
||||
|
||||
const data = {
|
||||
organization: organization,
|
||||
line: [
|
||||
{ "uuid": visibleIntersect.object.userData.linePoints[0][1] },
|
||||
{ "uuid": visibleIntersect.object.userData.linePoints[1][1] }
|
||||
],
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
socket.emit('v1:Line:delete', data);
|
||||
|
||||
const point = addPointToScene(intersectionPoint, pointColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, isSnappedUUID, lineType);
|
||||
|
||||
const oldLinePoints = visibleIntersect.object.userData.linePoints;
|
||||
lines.current = lines.current.filter(item => item !== oldLinePoints);
|
||||
|
||||
const clickedPoint: Types.Point = [
|
||||
new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z),
|
||||
point.uuid,
|
||||
oldLinePoints[0][2],
|
||||
lineType
|
||||
];
|
||||
|
||||
const start = oldLinePoints[0];
|
||||
const end = oldLinePoints[1];
|
||||
|
||||
const newLine1: Types.Line = [start, clickedPoint];
|
||||
const newLine2: Types.Line = [clickedPoint, end];
|
||||
|
||||
const line1 = arrayLineToObject(newLine1);
|
||||
const line2 = arrayLineToObject(newLine2);
|
||||
|
||||
//REST
|
||||
|
||||
// setLine(organization, line1.layer!, line1.line!, line1.type!);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const input1 = {
|
||||
organization: organization,
|
||||
layer: line1.layer,
|
||||
line: line1.line,
|
||||
type: line1.type,
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
socket.emit('v1:Line:create', input1);
|
||||
|
||||
//REST
|
||||
|
||||
// setLine(organization, line2.layer!, line2.line!, line2.type!);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const input2 = {
|
||||
organization: organization,
|
||||
layer: line2.layer,
|
||||
line: line2.line,
|
||||
type: line2.type,
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
socket.emit('v1:Line:create', input2);
|
||||
|
||||
lines.current.push(newLine1, newLine2);
|
||||
|
||||
addLineToScene(newLine1[0][0], newLine1[1][0], lineColor, newLine1, floorPlanGroupLine);
|
||||
addLineToScene(newLine2[0][0], newLine2[1][0], lineColor, newLine2, floorPlanGroupLine);
|
||||
|
||||
return [newLine1, newLine2];
|
||||
}
|
||||
|
||||
export default splitLine;
|
||||
|
||||
@@ -1,42 +1,42 @@
|
||||
import * as THREE from 'three';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function updateDistanceText(
|
||||
scene: THREE.Scene,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
affectedLines: Types.NumberArray
|
||||
): void {
|
||||
|
||||
////////// Updating the Distance Texts of the lines that are affected during drag //////////
|
||||
|
||||
const DistanceGroup = scene.children.find((child) => child.name === "Distance_Text") as THREE.Group;
|
||||
|
||||
affectedLines.forEach((lineIndex) => {
|
||||
const mesh = floorPlanGroupLine.current.children[lineIndex] as THREE.Mesh;
|
||||
const linePoints = mesh.userData.linePoints;
|
||||
|
||||
if (linePoints) {
|
||||
const distance = linePoints[0][0].distanceTo(linePoints[1][0]).toFixed(1);
|
||||
const position = new THREE.Vector3().addVectors(linePoints[0][0], linePoints[1][0]).divideScalar(2);
|
||||
|
||||
if (!DistanceGroup || !linePoints) {
|
||||
return
|
||||
}
|
||||
|
||||
DistanceGroup.children.forEach((text) => {
|
||||
const textMesh = text as THREE.Mesh;
|
||||
if (textMesh.userData[0][1] === linePoints[0][1] && textMesh.userData[1][1] === linePoints[1][1]) {
|
||||
textMesh.position.set(position.x, 1, position.z);
|
||||
const className = `Distance line-${textMesh.userData[0][1]}_${textMesh.userData[1][1]}_${linePoints[0][2]}`;
|
||||
const element = document.getElementsByClassName(className)[0] as HTMLElement;
|
||||
if (element) {
|
||||
element.innerHTML = `${distance} m`;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default updateDistanceText;
|
||||
import * as THREE from 'three';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function updateDistanceText(
|
||||
scene: THREE.Scene,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
affectedLines: Types.NumberArray
|
||||
): void {
|
||||
|
||||
////////// Updating the Distance Texts of the lines that are affected during drag //////////
|
||||
|
||||
const DistanceGroup = scene.children.find((child) => child.name === "Distance_Text") as THREE.Group;
|
||||
|
||||
affectedLines.forEach((lineIndex) => {
|
||||
const mesh = floorPlanGroupLine.current.children[lineIndex] as THREE.Mesh;
|
||||
const linePoints = mesh.userData.linePoints;
|
||||
|
||||
if (linePoints) {
|
||||
const distance = linePoints[0][0].distanceTo(linePoints[1][0]).toFixed(1);
|
||||
const position = new THREE.Vector3().addVectors(linePoints[0][0], linePoints[1][0]).divideScalar(2);
|
||||
|
||||
if (!DistanceGroup || !linePoints) {
|
||||
return
|
||||
}
|
||||
|
||||
DistanceGroup.children.forEach((text) => {
|
||||
const textMesh = text as THREE.Mesh;
|
||||
if (textMesh.userData[0][1] === linePoints[0][1] && textMesh.userData[1][1] === linePoints[1][1]) {
|
||||
textMesh.position.set(position.x, 1, position.z);
|
||||
const className = `Distance line-${textMesh.userData[0][1]}_${textMesh.userData[1][1]}_${linePoints[0][2]}`;
|
||||
const element = document.getElementsByClassName(className)[0] as HTMLElement;
|
||||
if (element) {
|
||||
element.innerHTML = `${distance} m`;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default updateDistanceText;
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import * as THREE from 'three';
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
|
||||
function updateLines(
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
affectedLines: Types.NumberArray
|
||||
): void {
|
||||
|
||||
////////// Updating the positions for the affected lines only based on the updated positions //////////
|
||||
|
||||
affectedLines.forEach((lineIndex) => {
|
||||
const mesh = floorPlanGroupLine.current.children[lineIndex] as Types.Mesh;
|
||||
const linePoints = mesh.userData.linePoints as Types.Line;
|
||||
if (linePoints) {
|
||||
const newPositions = linePoints.map(([pos]) => pos);
|
||||
const newPath = new THREE.CatmullRomCurve3(newPositions);
|
||||
mesh.geometry.dispose();
|
||||
mesh.geometry = new THREE.TubeGeometry(newPath, CONSTANTS.lineConfig.tubularSegments, CONSTANTS.lineConfig.radius, CONSTANTS.lineConfig.radialSegments, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
import * as THREE from 'three';
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
|
||||
function updateLines(
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
affectedLines: Types.NumberArray
|
||||
): void {
|
||||
|
||||
////////// Updating the positions for the affected lines only based on the updated positions //////////
|
||||
|
||||
affectedLines.forEach((lineIndex) => {
|
||||
const mesh = floorPlanGroupLine.current.children[lineIndex] as Types.Mesh;
|
||||
const linePoints = mesh.userData.linePoints as Types.Line;
|
||||
if (linePoints) {
|
||||
const newPositions = linePoints.map(([pos]) => pos);
|
||||
const newPath = new THREE.CatmullRomCurve3(newPositions);
|
||||
mesh.geometry.dispose();
|
||||
mesh.geometry = new THREE.TubeGeometry(newPath, CONSTANTS.lineConfig.tubularSegments, CONSTANTS.lineConfig.radius, CONSTANTS.lineConfig.radialSegments, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default updateLines;
|
||||
@@ -1,32 +1,32 @@
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function updateLinesPositions(
|
||||
DragedPoint: Types.Mesh | { uuid: string, position: Types.Vector3 },
|
||||
lines: Types.RefLines
|
||||
): Types.NumberArray {
|
||||
|
||||
////////// Updating the lines position based on the dragged point's position //////////
|
||||
|
||||
const objectUUID = DragedPoint.uuid;
|
||||
const affectedLines: Types.NumberArray = [];
|
||||
|
||||
lines.current.forEach((line, index) => {
|
||||
let lineUpdated = false;
|
||||
line.forEach((point) => {
|
||||
const [position, uuid] = point;
|
||||
if (uuid === objectUUID) {
|
||||
position.x = DragedPoint.position.x;
|
||||
position.y = 0.01;
|
||||
position.z = DragedPoint.position.z;
|
||||
lineUpdated = true;
|
||||
}
|
||||
});
|
||||
if (lineUpdated) {
|
||||
affectedLines.push(index);
|
||||
}
|
||||
});
|
||||
|
||||
return affectedLines;
|
||||
}
|
||||
|
||||
export default updateLinesPositions;
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function updateLinesPositions(
|
||||
DragedPoint: Types.Mesh | { uuid: string, position: Types.Vector3 },
|
||||
lines: Types.RefLines
|
||||
): Types.NumberArray {
|
||||
|
||||
////////// Updating the lines position based on the dragged point's position //////////
|
||||
|
||||
const objectUUID = DragedPoint.uuid;
|
||||
const affectedLines: Types.NumberArray = [];
|
||||
|
||||
lines.current.forEach((line, index) => {
|
||||
let lineUpdated = false;
|
||||
line.forEach((point) => {
|
||||
const [position, uuid] = point;
|
||||
if (uuid === objectUUID) {
|
||||
position.x = DragedPoint.position.x;
|
||||
position.y = 0.01;
|
||||
position.z = DragedPoint.position.z;
|
||||
lineUpdated = true;
|
||||
}
|
||||
});
|
||||
if (lineUpdated) {
|
||||
affectedLines.push(index);
|
||||
}
|
||||
});
|
||||
|
||||
return affectedLines;
|
||||
}
|
||||
|
||||
export default updateLinesPositions;
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import * as THREE from 'three';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function vectorizeLinesCurrent(
|
||||
lines: Types.Lines
|
||||
): Types.Lines {
|
||||
|
||||
////////// Storing a vector3 array in localstorage makes the prototype functions go puff. This function brings back the prototype functions by creating it again //////////
|
||||
|
||||
return lines.map((line) => {
|
||||
const p1: Types.Point = [new THREE.Vector3(line[0][0].x, line[0][0].y, line[0][0].z), line[0][1], line[0][2], line[0][3],];
|
||||
const p2: Types.Point = [new THREE.Vector3(line[1][0].x, line[1][0].y, line[1][0].z), line[1][1], line[0][2], line[1][3],];
|
||||
return [p1, p2];
|
||||
});
|
||||
}
|
||||
|
||||
export default vectorizeLinesCurrent;
|
||||
import * as THREE from 'three';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function vectorizeLinesCurrent(
|
||||
lines: Types.Lines
|
||||
): Types.Lines {
|
||||
|
||||
////////// Storing a vector3 array in localstorage makes the prototype functions go puff. This function brings back the prototype functions by creating it again //////////
|
||||
|
||||
return lines.map((line) => {
|
||||
const p1: Types.Point = [new THREE.Vector3(line[0][0].x, line[0][0].y, line[0][0].z), line[0][1], line[0][2], line[0][3],];
|
||||
const p2: Types.Point = [new THREE.Vector3(line[1][0].x, line[1][0].y, line[1][0].z), line[1][1], line[0][2], line[1][3],];
|
||||
return [p1, p2];
|
||||
});
|
||||
}
|
||||
|
||||
export default vectorizeLinesCurrent;
|
||||
|
||||
@@ -1,54 +1,54 @@
|
||||
import * as THREE from 'three';
|
||||
import updateReferencePolesheight from './updateReferencePolesheight';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function addAndUpdateReferencePillar(
|
||||
raycaster: THREE.Raycaster,
|
||||
floorGroup: Types.RefGroup,
|
||||
referencePole: Types.RefMesh
|
||||
): void {
|
||||
|
||||
////////// Find Pillars position and scale based on the pointer interaction //////////
|
||||
|
||||
let Roofs = raycaster.intersectObjects(floorGroup.current.children, true);
|
||||
const intersected = Roofs.find(intersect => intersect.object.name.includes("Roof") || intersect.object.name.includes("Floor"));
|
||||
|
||||
if (intersected) {
|
||||
const intersectionPoint = intersected.point;
|
||||
raycaster.ray.origin.copy(intersectionPoint);
|
||||
raycaster.ray.direction.set(0, -1, 0);
|
||||
const belowIntersections = raycaster.intersectObjects(floorGroup.current.children, true);
|
||||
const validIntersections = belowIntersections.filter(intersect => intersect.object.name.includes("Floor"));
|
||||
|
||||
let distance: Types.Number;
|
||||
|
||||
if (validIntersections.length > 1) {
|
||||
let valid = validIntersections.find(intersectedBelow => intersected.point.distanceTo(intersectedBelow.point) > 3);
|
||||
if (valid) {
|
||||
updateReferencePolesheight(intersectionPoint, valid.distance, referencePole, floorGroup);
|
||||
} else {
|
||||
const belowPoint = new THREE.Vector3(intersectionPoint.x, 0, intersectionPoint.z);
|
||||
distance = intersected.point.distanceTo(belowPoint);
|
||||
if (distance > 3) {
|
||||
updateReferencePolesheight(intersectionPoint, distance, referencePole, floorGroup);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const belowPoint = new THREE.Vector3(intersectionPoint.x, 0, intersectionPoint.z);
|
||||
distance = intersected.point.distanceTo(belowPoint);
|
||||
if (distance > 3) {
|
||||
updateReferencePolesheight(intersectionPoint, distance, referencePole, floorGroup);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (referencePole.current) {
|
||||
(<any>referencePole.current.material).dispose();
|
||||
(<any>referencePole.current.geometry).dispose();
|
||||
floorGroup.current.remove(referencePole.current);
|
||||
referencePole.current = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default addAndUpdateReferencePillar;
|
||||
import * as THREE from 'three';
|
||||
import updateReferencePolesheight from './updateReferencePolesheight';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function addAndUpdateReferencePillar(
|
||||
raycaster: THREE.Raycaster,
|
||||
floorGroup: Types.RefGroup,
|
||||
referencePole: Types.RefMesh
|
||||
): void {
|
||||
|
||||
////////// Find Pillars position and scale based on the pointer interaction //////////
|
||||
|
||||
let Roofs = raycaster.intersectObjects(floorGroup.current.children, true);
|
||||
const intersected = Roofs.find(intersect => intersect.object.name.includes("Roof") || intersect.object.name.includes("Floor"));
|
||||
|
||||
if (intersected) {
|
||||
const intersectionPoint = intersected.point;
|
||||
raycaster.ray.origin.copy(intersectionPoint);
|
||||
raycaster.ray.direction.set(0, -1, 0);
|
||||
const belowIntersections = raycaster.intersectObjects(floorGroup.current.children, true);
|
||||
const validIntersections = belowIntersections.filter(intersect => intersect.object.name.includes("Floor"));
|
||||
|
||||
let distance: Types.Number;
|
||||
|
||||
if (validIntersections.length > 1) {
|
||||
let valid = validIntersections.find(intersectedBelow => intersected.point.distanceTo(intersectedBelow.point) > 3);
|
||||
if (valid) {
|
||||
updateReferencePolesheight(intersectionPoint, valid.distance, referencePole, floorGroup);
|
||||
} else {
|
||||
const belowPoint = new THREE.Vector3(intersectionPoint.x, 0, intersectionPoint.z);
|
||||
distance = intersected.point.distanceTo(belowPoint);
|
||||
if (distance > 3) {
|
||||
updateReferencePolesheight(intersectionPoint, distance, referencePole, floorGroup);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const belowPoint = new THREE.Vector3(intersectionPoint.x, 0, intersectionPoint.z);
|
||||
distance = intersected.point.distanceTo(belowPoint);
|
||||
if (distance > 3) {
|
||||
updateReferencePolesheight(intersectionPoint, distance, referencePole, floorGroup);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (referencePole.current) {
|
||||
(<any>referencePole.current.material).dispose();
|
||||
(<any>referencePole.current.geometry).dispose();
|
||||
floorGroup.current.remove(referencePole.current);
|
||||
referencePole.current = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default addAndUpdateReferencePillar;
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import * as THREE from 'three';
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function addPillar(
|
||||
referencePole: Types.RefMesh,
|
||||
floorGroup: Types.RefGroup
|
||||
): void {
|
||||
|
||||
////////// Add Pillars to the scene based on the reference. current poles position and scale //////////
|
||||
|
||||
if (referencePole.current) {
|
||||
let pole: THREE.Mesh;
|
||||
const geometry = referencePole.current.userData.geometry.clone();
|
||||
const material = new THREE.MeshStandardMaterial({ color: CONSTANTS.columnConfig.defaultColor });
|
||||
pole = new THREE.Mesh(geometry, material);
|
||||
pole.rotateX(Math.PI / 2);
|
||||
pole.name = "Pole";
|
||||
pole.position.set(referencePole.current.userData.position.x, referencePole.current.userData.position.y, referencePole.current.userData.position.z);
|
||||
floorGroup.current.add(pole);
|
||||
}
|
||||
}
|
||||
|
||||
import * as THREE from 'three';
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function addPillar(
|
||||
referencePole: Types.RefMesh,
|
||||
floorGroup: Types.RefGroup
|
||||
): void {
|
||||
|
||||
////////// Add Pillars to the scene based on the reference. current poles position and scale //////////
|
||||
|
||||
if (referencePole.current) {
|
||||
let pole: THREE.Mesh;
|
||||
const geometry = referencePole.current.userData.geometry.clone();
|
||||
const material = new THREE.MeshStandardMaterial({ color: CONSTANTS.columnConfig.defaultColor });
|
||||
pole = new THREE.Mesh(geometry, material);
|
||||
pole.rotateX(Math.PI / 2);
|
||||
pole.name = "Pole";
|
||||
pole.position.set(referencePole.current.userData.position.x, referencePole.current.userData.position.y, referencePole.current.userData.position.z);
|
||||
floorGroup.current.add(pole);
|
||||
}
|
||||
}
|
||||
|
||||
export default addPillar;
|
||||
@@ -1,34 +1,34 @@
|
||||
import * as THREE from 'three';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function DeletableHoveredPillar(
|
||||
state: Types.ThreeState,
|
||||
floorGroup: Types.RefGroup,
|
||||
hoveredDeletablePillar: Types.RefMesh
|
||||
): void {
|
||||
|
||||
////////// Altering the color of the hovered Pillar during the Deletion time //////////
|
||||
|
||||
const intersects = state.raycaster.intersectObjects(floorGroup.current.children, true);
|
||||
const poleIntersect = intersects.find(intersect => intersect.object.name === "Pole");
|
||||
|
||||
if (poleIntersect) {
|
||||
if (poleIntersect.object.name !== "Pole") {
|
||||
return;
|
||||
}
|
||||
if (hoveredDeletablePillar.current) {
|
||||
(hoveredDeletablePillar.current.material as THREE.MeshStandardMaterial).emissive = new THREE.Color("black");
|
||||
hoveredDeletablePillar.current = undefined;
|
||||
}
|
||||
hoveredDeletablePillar.current = poleIntersect.object as THREE.Mesh; // Type assertion
|
||||
(hoveredDeletablePillar.current.material as THREE.MeshStandardMaterial).emissive = new THREE.Color("red");
|
||||
} else {
|
||||
if (hoveredDeletablePillar.current) {
|
||||
(hoveredDeletablePillar.current.material as THREE.MeshStandardMaterial).emissive = new THREE.Color("black");
|
||||
hoveredDeletablePillar.current = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
import * as THREE from 'three';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function DeletableHoveredPillar(
|
||||
state: Types.ThreeState,
|
||||
floorGroup: Types.RefGroup,
|
||||
hoveredDeletablePillar: Types.RefMesh
|
||||
): void {
|
||||
|
||||
////////// Altering the color of the hovered Pillar during the Deletion time //////////
|
||||
|
||||
const intersects = state.raycaster.intersectObjects(floorGroup.current.children, true);
|
||||
const poleIntersect = intersects.find(intersect => intersect.object.name === "Pole");
|
||||
|
||||
if (poleIntersect) {
|
||||
if (poleIntersect.object.name !== "Pole") {
|
||||
return;
|
||||
}
|
||||
if (hoveredDeletablePillar.current) {
|
||||
(hoveredDeletablePillar.current.material as THREE.MeshStandardMaterial).emissive = new THREE.Color("black");
|
||||
hoveredDeletablePillar.current = undefined;
|
||||
}
|
||||
hoveredDeletablePillar.current = poleIntersect.object as THREE.Mesh; // Type assertion
|
||||
(hoveredDeletablePillar.current.material as THREE.MeshStandardMaterial).emissive = new THREE.Color("red");
|
||||
} else {
|
||||
if (hoveredDeletablePillar.current) {
|
||||
(hoveredDeletablePillar.current.material as THREE.MeshStandardMaterial).emissive = new THREE.Color("black");
|
||||
hoveredDeletablePillar.current = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default DeletableHoveredPillar;
|
||||
@@ -1,21 +1,21 @@
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function DeletePillar(
|
||||
hoveredDeletablePillar: Types.RefMesh,
|
||||
floorGroup: Types.RefGroup
|
||||
): void {
|
||||
|
||||
////////// Deleting the hovered Pillar from the itemsGroup //////////
|
||||
|
||||
if (hoveredDeletablePillar.current) {
|
||||
(<any>hoveredDeletablePillar.current.material).dispose();
|
||||
(<any>hoveredDeletablePillar.current.geometry).dispose();
|
||||
floorGroup.current.remove(hoveredDeletablePillar.current);
|
||||
toast.success("Pillar Removed!");
|
||||
hoveredDeletablePillar.current = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export default DeletePillar;
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function DeletePillar(
|
||||
hoveredDeletablePillar: Types.RefMesh,
|
||||
floorGroup: Types.RefGroup
|
||||
): void {
|
||||
|
||||
////////// Deleting the hovered Pillar from the itemsGroup //////////
|
||||
|
||||
if (hoveredDeletablePillar.current) {
|
||||
(<any>hoveredDeletablePillar.current.material).dispose();
|
||||
(<any>hoveredDeletablePillar.current.geometry).dispose();
|
||||
floorGroup.current.remove(hoveredDeletablePillar.current);
|
||||
toast.success("Pillar Removed!");
|
||||
hoveredDeletablePillar.current = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export default DeletePillar;
|
||||
|
||||
@@ -1,40 +1,40 @@
|
||||
import * as THREE from 'three';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function updateReferencePolesheight(
|
||||
intersectionPoint: Types.Vector3,
|
||||
distance: Types.Number,
|
||||
referencePole: Types.RefMesh,
|
||||
floorGroup: Types.RefGroup
|
||||
): void {
|
||||
|
||||
////////// Add a Reference Pillar and update its position and scale based on the pointer interaction //////////
|
||||
|
||||
if (referencePole.current) {
|
||||
(<any>referencePole.current.material).dispose();
|
||||
(<any>referencePole.current.geometry).dispose();
|
||||
floorGroup.current.remove(referencePole.current);
|
||||
referencePole.current.geometry.dispose();
|
||||
}
|
||||
|
||||
const shape = new THREE.Shape();
|
||||
shape.moveTo(0.5, 0);
|
||||
shape.absarc(0, 0, 0.5, 0, 2 * Math.PI, false);
|
||||
|
||||
const extrudeSettings = {
|
||||
depth: distance,
|
||||
bevelEnabled: false,
|
||||
};
|
||||
|
||||
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
|
||||
const material = new THREE.MeshBasicMaterial({ color: "green", transparent: true, opacity: 0.5 });
|
||||
referencePole.current = new THREE.Mesh(geometry, material);
|
||||
referencePole.current.rotateX(Math.PI / 2);
|
||||
referencePole.current.position.set(intersectionPoint.x, intersectionPoint.y - 0.01, intersectionPoint.z);
|
||||
referencePole.current.userData = { geometry: geometry, distance: distance, position: { x: intersectionPoint.x, y: intersectionPoint.y - 0.01, z: intersectionPoint.z } };
|
||||
|
||||
floorGroup.current.add(referencePole.current);
|
||||
}
|
||||
|
||||
export default updateReferencePolesheight;
|
||||
import * as THREE from 'three';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function updateReferencePolesheight(
|
||||
intersectionPoint: Types.Vector3,
|
||||
distance: Types.Number,
|
||||
referencePole: Types.RefMesh,
|
||||
floorGroup: Types.RefGroup
|
||||
): void {
|
||||
|
||||
////////// Add a Reference Pillar and update its position and scale based on the pointer interaction //////////
|
||||
|
||||
if (referencePole.current) {
|
||||
(<any>referencePole.current.material).dispose();
|
||||
(<any>referencePole.current.geometry).dispose();
|
||||
floorGroup.current.remove(referencePole.current);
|
||||
referencePole.current.geometry.dispose();
|
||||
}
|
||||
|
||||
const shape = new THREE.Shape();
|
||||
shape.moveTo(0.5, 0);
|
||||
shape.absarc(0, 0, 0.5, 0, 2 * Math.PI, false);
|
||||
|
||||
const extrudeSettings = {
|
||||
depth: distance,
|
||||
bevelEnabled: false,
|
||||
};
|
||||
|
||||
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
|
||||
const material = new THREE.MeshBasicMaterial({ color: "green", transparent: true, opacity: 0.5 });
|
||||
referencePole.current = new THREE.Mesh(geometry, material);
|
||||
referencePole.current.rotateX(Math.PI / 2);
|
||||
referencePole.current.position.set(intersectionPoint.x, intersectionPoint.y - 0.01, intersectionPoint.z);
|
||||
referencePole.current.userData = { geometry: geometry, distance: distance, position: { x: intersectionPoint.x, y: intersectionPoint.y - 0.01, z: intersectionPoint.z } };
|
||||
|
||||
floorGroup.current.add(referencePole.current);
|
||||
}
|
||||
|
||||
export default updateReferencePolesheight;
|
||||
|
||||
@@ -1,65 +1,65 @@
|
||||
import * as THREE from 'three';
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function addPointToScene(
|
||||
position: Types.Vector3,
|
||||
colour: Types.Color,
|
||||
currentLayerPoint: Types.RefMeshArray,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
dragPointControls: Types.RefDragControl | undefined,
|
||||
uuid: Types.RefString | undefined,
|
||||
Type: Types.String
|
||||
): Types.Mesh {
|
||||
|
||||
////////// A function that creates and adds a cube (point) with an outline based on the position and colour given as params, It also updates the drag controls objects and sets the box uuid in uuid.current //////////
|
||||
|
||||
const geometry = new THREE.BoxGeometry(...CONSTANTS.pointConfig.boxScale);
|
||||
const material = new THREE.ShaderMaterial({
|
||||
uniforms: {
|
||||
uColor: { value: new THREE.Color(colour) }, // Blue color for the border
|
||||
uInnerColor: { value: new THREE.Color(CONSTANTS.pointConfig.defaultInnerColor) }, // White color for the inner square
|
||||
},
|
||||
vertexShader: `
|
||||
varying vec2 vUv;
|
||||
|
||||
void main() {
|
||||
vUv = uv;
|
||||
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
||||
}
|
||||
`,
|
||||
fragmentShader: `
|
||||
varying vec2 vUv;
|
||||
uniform vec3 uColor;
|
||||
uniform vec3 uInnerColor;
|
||||
|
||||
void main() {
|
||||
// Define the size of the white square as a proportion of the face
|
||||
float borderThickness = 0.2; // Adjust this value for border thickness
|
||||
if (vUv.x > borderThickness && vUv.x < 1.0 - borderThickness &&
|
||||
vUv.y > borderThickness && vUv.y < 1.0 - borderThickness) {
|
||||
gl_FragColor = vec4(uInnerColor, 1.0); // White inner square
|
||||
} else {
|
||||
gl_FragColor = vec4(uColor, 1.0); // Blue border
|
||||
}
|
||||
}
|
||||
`,
|
||||
});
|
||||
const point = new THREE.Mesh(geometry, material);
|
||||
point.name = "point";
|
||||
point.userData = { type: Type, color: colour };
|
||||
point.position.set(position.x, 0.01, position.z);
|
||||
|
||||
currentLayerPoint.current.push(point);
|
||||
floorPlanGroupPoint.current.add(point);
|
||||
if (uuid) {
|
||||
uuid.current = point.uuid;
|
||||
}
|
||||
if (dragPointControls) {
|
||||
dragPointControls.current!.objects = currentLayerPoint.current;
|
||||
}
|
||||
|
||||
return point;
|
||||
}
|
||||
|
||||
export default addPointToScene;
|
||||
import * as THREE from 'three';
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function addPointToScene(
|
||||
position: Types.Vector3,
|
||||
colour: Types.Color,
|
||||
currentLayerPoint: Types.RefMeshArray,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
dragPointControls: Types.RefDragControl | undefined,
|
||||
uuid: Types.RefString | undefined,
|
||||
Type: Types.String
|
||||
): Types.Mesh {
|
||||
|
||||
////////// A function that creates and adds a cube (point) with an outline based on the position and colour given as params, It also updates the drag controls objects and sets the box uuid in uuid.current //////////
|
||||
|
||||
const geometry = new THREE.BoxGeometry(...CONSTANTS.pointConfig.boxScale);
|
||||
const material = new THREE.ShaderMaterial({
|
||||
uniforms: {
|
||||
uColor: { value: new THREE.Color(colour) }, // Blue color for the border
|
||||
uInnerColor: { value: new THREE.Color(CONSTANTS.pointConfig.defaultInnerColor) }, // White color for the inner square
|
||||
},
|
||||
vertexShader: `
|
||||
varying vec2 vUv;
|
||||
|
||||
void main() {
|
||||
vUv = uv;
|
||||
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
||||
}
|
||||
`,
|
||||
fragmentShader: `
|
||||
varying vec2 vUv;
|
||||
uniform vec3 uColor;
|
||||
uniform vec3 uInnerColor;
|
||||
|
||||
void main() {
|
||||
// Define the size of the white square as a proportion of the face
|
||||
float borderThickness = 0.2; // Adjust this value for border thickness
|
||||
if (vUv.x > borderThickness && vUv.x < 1.0 - borderThickness &&
|
||||
vUv.y > borderThickness && vUv.y < 1.0 - borderThickness) {
|
||||
gl_FragColor = vec4(uInnerColor, 1.0); // White inner square
|
||||
} else {
|
||||
gl_FragColor = vec4(uColor, 1.0); // Blue border
|
||||
}
|
||||
}
|
||||
`,
|
||||
});
|
||||
const point = new THREE.Mesh(geometry, material);
|
||||
point.name = "point";
|
||||
point.userData = { type: Type, color: colour };
|
||||
point.position.set(position.x, 0.01, position.z);
|
||||
|
||||
currentLayerPoint.current.push(point);
|
||||
floorPlanGroupPoint.current.add(point);
|
||||
if (uuid) {
|
||||
uuid.current = point.uuid;
|
||||
}
|
||||
if (dragPointControls) {
|
||||
dragPointControls.current!.objects = currentLayerPoint.current;
|
||||
}
|
||||
|
||||
return point;
|
||||
}
|
||||
|
||||
export default addPointToScene;
|
||||
|
||||
@@ -1,57 +1,57 @@
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
import RemoveConnectedLines from "../lines/removeConnectedLines";
|
||||
// import { deletePointApi } from "../../../../services/factoryBuilder/lines/deletePointApi";
|
||||
import { Socket } from "socket.io-client";
|
||||
|
||||
function deletePoint(
|
||||
hoveredDeletablePoint: Types.RefMesh,
|
||||
onlyFloorlines: Types.RefOnlyFloorLines,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
lines: Types.RefLines,
|
||||
setDeletedLines: any,
|
||||
socket: Socket<any>
|
||||
): void {
|
||||
////////// Deleting a Point and the lines that are connected to it //////////
|
||||
|
||||
if (!hoveredDeletablePoint.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
(<any>hoveredDeletablePoint.current.material).dispose();
|
||||
(<any>hoveredDeletablePoint.current.geometry).dispose();
|
||||
floorPlanGroupPoint.current.remove(hoveredDeletablePoint.current);
|
||||
const DeletedPointUUID = hoveredDeletablePoint.current.uuid;
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
//REST
|
||||
|
||||
// deletePointApi(organization, DeletedPointUUID);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const data = {
|
||||
organization: organization,
|
||||
uuid: DeletedPointUUID,
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
socket.emit('v1:Line:delete:point', data);
|
||||
|
||||
////////// Update onlyFloorlines.current to remove references to the deleted point //////////
|
||||
|
||||
onlyFloorlines.current = onlyFloorlines.current.map(floorline =>
|
||||
floorline.filter(line => line[0][1] !== DeletedPointUUID && line[1][1] !== DeletedPointUUID)
|
||||
).filter(floorline => floorline.length > 0);
|
||||
|
||||
RemoveConnectedLines(DeletedPointUUID, floorPlanGroupLine, floorPlanGroupPoint, setDeletedLines, lines);
|
||||
|
||||
toast.success("Point Removed!");
|
||||
}
|
||||
|
||||
export default deletePoint;
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
import RemoveConnectedLines from "../lines/removeConnectedLines";
|
||||
// import { deletePointApi } from "../../../../services/factoryBuilder/lines/deletePointApi";
|
||||
import { Socket } from "socket.io-client";
|
||||
|
||||
function deletePoint(
|
||||
hoveredDeletablePoint: Types.RefMesh,
|
||||
onlyFloorlines: Types.RefOnlyFloorLines,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
lines: Types.RefLines,
|
||||
setDeletedLines: any,
|
||||
socket: Socket<any>
|
||||
): void {
|
||||
////////// Deleting a Point and the lines that are connected to it //////////
|
||||
|
||||
if (!hoveredDeletablePoint.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
(<any>hoveredDeletablePoint.current.material).dispose();
|
||||
(<any>hoveredDeletablePoint.current.geometry).dispose();
|
||||
floorPlanGroupPoint.current.remove(hoveredDeletablePoint.current);
|
||||
const DeletedPointUUID = hoveredDeletablePoint.current.uuid;
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
//REST
|
||||
|
||||
// deletePointApi(organization, DeletedPointUUID);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const data = {
|
||||
organization: organization,
|
||||
uuid: DeletedPointUUID,
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
socket.emit('v1:Line:delete:point', data);
|
||||
|
||||
////////// Update onlyFloorlines.current to remove references to the deleted point //////////
|
||||
|
||||
onlyFloorlines.current = onlyFloorlines.current.map(floorline =>
|
||||
floorline.filter(line => line[0][1] !== DeletedPointUUID && line[1][1] !== DeletedPointUUID)
|
||||
).filter(floorline => floorline.length > 0);
|
||||
|
||||
RemoveConnectedLines(DeletedPointUUID, floorPlanGroupLine, floorPlanGroupPoint, setDeletedLines, lines);
|
||||
|
||||
toast.success("Point Removed!");
|
||||
}
|
||||
|
||||
export default deletePoint;
|
||||
|
||||
@@ -1,44 +1,44 @@
|
||||
import * as THREE from "three";
|
||||
import * as Types from "../../../../types/world/worldTypes"
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
|
||||
import updateLinesPositions from "../lines/updateLinesPositions";
|
||||
import updateLines from "../lines/updateLines";
|
||||
import updateDistanceText from "../lines/updateDistanceText";
|
||||
import updateFloorLines from "../floors/updateFloorLines";
|
||||
|
||||
function DragPoint(
|
||||
event: Types.IntersectionEvent,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
scene: THREE.Scene,
|
||||
lines: Types.RefLines,
|
||||
onlyFloorlines: Types.RefOnlyFloorLines
|
||||
): void {
|
||||
|
||||
////////// Calling the line updation of the affected lines and Snapping of the point during the drag //////////
|
||||
|
||||
const snapThreshold = CONSTANTS.pointConfig.snappingThreshold;
|
||||
const DragedPoint = event.object as Types.Mesh;
|
||||
|
||||
floorPlanGroupPoint.current.children.forEach((point) => {
|
||||
let canSnap =
|
||||
((DragedPoint.userData.type === CONSTANTS.lineConfig.wallName) && (point.userData.type === CONSTANTS.lineConfig.wallName || point.userData.type === CONSTANTS.lineConfig.floorName)) ||
|
||||
((DragedPoint.userData.type === CONSTANTS.lineConfig.floorName) && (point.userData.type === CONSTANTS.lineConfig.wallName || point.userData.type === CONSTANTS.lineConfig.floorName)) ||
|
||||
((DragedPoint.userData.type === CONSTANTS.lineConfig.aisleName) && point.userData.type === CONSTANTS.lineConfig.aisleName);
|
||||
if (canSnap && point.uuid !== DragedPoint.uuid && point.visible) {
|
||||
const distance = DragedPoint.position.distanceTo(point.position);
|
||||
if (distance < snapThreshold) {
|
||||
DragedPoint.position.copy(point.position);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const affectedLines = updateLinesPositions(DragedPoint, lines);
|
||||
|
||||
updateLines(floorPlanGroupLine, affectedLines);
|
||||
updateDistanceText(scene, floorPlanGroupLine, affectedLines);
|
||||
updateFloorLines(onlyFloorlines, DragedPoint);
|
||||
}
|
||||
|
||||
import * as THREE from "three";
|
||||
import * as Types from "../../../../types/world/worldTypes"
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
|
||||
import updateLinesPositions from "../lines/updateLinesPositions";
|
||||
import updateLines from "../lines/updateLines";
|
||||
import updateDistanceText from "../lines/updateDistanceText";
|
||||
import updateFloorLines from "../floors/updateFloorLines";
|
||||
|
||||
function DragPoint(
|
||||
event: Types.IntersectionEvent,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
scene: THREE.Scene,
|
||||
lines: Types.RefLines,
|
||||
onlyFloorlines: Types.RefOnlyFloorLines
|
||||
): void {
|
||||
|
||||
////////// Calling the line updation of the affected lines and Snapping of the point during the drag //////////
|
||||
|
||||
const snapThreshold = CONSTANTS.pointConfig.snappingThreshold;
|
||||
const DragedPoint = event.object as Types.Mesh;
|
||||
|
||||
floorPlanGroupPoint.current.children.forEach((point) => {
|
||||
let canSnap =
|
||||
((DragedPoint.userData.type === CONSTANTS.lineConfig.wallName) && (point.userData.type === CONSTANTS.lineConfig.wallName || point.userData.type === CONSTANTS.lineConfig.floorName)) ||
|
||||
((DragedPoint.userData.type === CONSTANTS.lineConfig.floorName) && (point.userData.type === CONSTANTS.lineConfig.wallName || point.userData.type === CONSTANTS.lineConfig.floorName)) ||
|
||||
((DragedPoint.userData.type === CONSTANTS.lineConfig.aisleName) && point.userData.type === CONSTANTS.lineConfig.aisleName);
|
||||
if (canSnap && point.uuid !== DragedPoint.uuid && point.visible) {
|
||||
const distance = DragedPoint.position.distanceTo(point.position);
|
||||
if (distance < snapThreshold) {
|
||||
DragedPoint.position.copy(point.position);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const affectedLines = updateLinesPositions(DragedPoint, lines);
|
||||
|
||||
updateLines(floorPlanGroupLine, affectedLines);
|
||||
updateDistanceText(scene, floorPlanGroupLine, affectedLines);
|
||||
updateFloorLines(onlyFloorlines, DragedPoint);
|
||||
}
|
||||
|
||||
export default DragPoint;
|
||||
@@ -1,37 +1,37 @@
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function removeSoloPoint(
|
||||
line: Types.RefLine,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
floorPlanGroupPoint: Types.RefGroup
|
||||
): void {
|
||||
|
||||
////////// Remove the point if there is only one point and if it is not connected to any other line and also the reference line //////////
|
||||
|
||||
if (line.current[0]) {
|
||||
const pointUUID = line.current[0][1];
|
||||
let isConnected = false;
|
||||
|
||||
floorPlanGroupLine.current.children.forEach((line) => {
|
||||
const linePoints = line.userData.linePoints;
|
||||
const uuid1 = linePoints[0][1];
|
||||
const uuid2 = linePoints[1][1];
|
||||
if (uuid1 === pointUUID || uuid2 === pointUUID) {
|
||||
isConnected = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (!isConnected) {
|
||||
floorPlanGroupPoint.current.children.forEach((point: any) => {
|
||||
if (point.uuid === pointUUID) {
|
||||
(<any>point.material).dispose();
|
||||
(<any>point.geometry).dispose();
|
||||
floorPlanGroupPoint.current.remove(point);
|
||||
}
|
||||
});
|
||||
}
|
||||
line.current = [];
|
||||
}
|
||||
}
|
||||
|
||||
export default removeSoloPoint;
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function removeSoloPoint(
|
||||
line: Types.RefLine,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
floorPlanGroupPoint: Types.RefGroup
|
||||
): void {
|
||||
|
||||
////////// Remove the point if there is only one point and if it is not connected to any other line and also the reference line //////////
|
||||
|
||||
if (line.current[0]) {
|
||||
const pointUUID = line.current[0][1];
|
||||
let isConnected = false;
|
||||
|
||||
floorPlanGroupLine.current.children.forEach((line) => {
|
||||
const linePoints = line.userData.linePoints;
|
||||
const uuid1 = linePoints[0][1];
|
||||
const uuid2 = linePoints[1][1];
|
||||
if (uuid1 === pointUUID || uuid2 === pointUUID) {
|
||||
isConnected = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (!isConnected) {
|
||||
floorPlanGroupPoint.current.children.forEach((point: any) => {
|
||||
if (point.uuid === pointUUID) {
|
||||
(<any>point.material).dispose();
|
||||
(<any>point.geometry).dispose();
|
||||
floorPlanGroupPoint.current.remove(point);
|
||||
}
|
||||
});
|
||||
}
|
||||
line.current = [];
|
||||
}
|
||||
}
|
||||
|
||||
export default removeSoloPoint;
|
||||
|
||||
@@ -1,32 +1,32 @@
|
||||
import * as THREE from 'three';
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function addRoofToScene(
|
||||
shape: Types.Shape,
|
||||
floor: Types.Number,
|
||||
userData: Types.UserData,
|
||||
floorGroup: Types.RefGroup
|
||||
): void {
|
||||
|
||||
////////// Creating a Polygon roof from the shape of the Polygon floor //////////
|
||||
|
||||
const extrudeSettings: THREE.ExtrudeGeometryOptions = {
|
||||
depth: CONSTANTS.roofConfig.height,
|
||||
bevelEnabled: false
|
||||
};
|
||||
|
||||
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
|
||||
const material = new THREE.MeshStandardMaterial({ color: CONSTANTS.roofConfig.defaultColor, side: THREE.DoubleSide, transparent: true, depthWrite: false });
|
||||
const mesh = new THREE.Mesh(geometry, material);
|
||||
mesh.position.y = CONSTANTS.wallConfig.height + floor;
|
||||
mesh.castShadow = true;
|
||||
mesh.receiveShadow = true;
|
||||
mesh.rotateX(Math.PI / 2);
|
||||
mesh.userData.uuids = userData;
|
||||
mesh.name = `Roof_Layer_${(floor / CONSTANTS.wallConfig.height) + 1}`;
|
||||
|
||||
floorGroup.current.add(mesh);
|
||||
}
|
||||
|
||||
export default addRoofToScene;
|
||||
import * as THREE from 'three';
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function addRoofToScene(
|
||||
shape: Types.Shape,
|
||||
floor: Types.Number,
|
||||
userData: Types.UserData,
|
||||
floorGroup: Types.RefGroup
|
||||
): void {
|
||||
|
||||
////////// Creating a Polygon roof from the shape of the Polygon floor //////////
|
||||
|
||||
const extrudeSettings: THREE.ExtrudeGeometryOptions = {
|
||||
depth: CONSTANTS.roofConfig.height,
|
||||
bevelEnabled: false
|
||||
};
|
||||
|
||||
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
|
||||
const material = new THREE.MeshStandardMaterial({ color: CONSTANTS.roofConfig.defaultColor, side: THREE.DoubleSide, transparent: true, depthWrite: false });
|
||||
const mesh = new THREE.Mesh(geometry, material);
|
||||
mesh.position.y = CONSTANTS.wallConfig.height + floor;
|
||||
mesh.castShadow = true;
|
||||
mesh.receiveShadow = true;
|
||||
mesh.rotateX(Math.PI / 2);
|
||||
mesh.userData.uuids = userData;
|
||||
mesh.name = `Roof_Layer_${(floor / CONSTANTS.wallConfig.height) + 1}`;
|
||||
|
||||
floorGroup.current.add(mesh);
|
||||
}
|
||||
|
||||
export default addRoofToScene;
|
||||
|
||||
@@ -1,47 +1,47 @@
|
||||
import * as THREE from 'three';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function hideRoof(
|
||||
visibility: Types.Boolean,
|
||||
floorGroup: Types.RefGroup,
|
||||
camera: THREE.Camera
|
||||
): void {
|
||||
|
||||
////////// Toggles the visibility of the roof based on the camera position and the Roof visibility button on UI //////////
|
||||
|
||||
const v = new THREE.Vector3();
|
||||
const u = new THREE.Vector3();
|
||||
|
||||
if (visibility === true && floorGroup.current) {
|
||||
for (const child of floorGroup.current.children) {
|
||||
if (child.name.includes("Roof")) {
|
||||
const roofChild = child as Types.Mesh;
|
||||
roofChild.getWorldDirection(v);
|
||||
camera?.getWorldDirection(u);
|
||||
if (roofChild.material) {
|
||||
const materials = Array.isArray(roofChild.material) ? roofChild.material : [roofChild.material];
|
||||
materials.forEach(material => {
|
||||
material.visible = v.dot(u) < 0.25;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (floorGroup.current) {
|
||||
for (const child of floorGroup.current.children) {
|
||||
if (child.name.includes("Roof")) {
|
||||
const roofChild = child as Types.Mesh;
|
||||
if (roofChild.material) {
|
||||
const materials = Array.isArray(roofChild.material) ? roofChild.material : [roofChild.material];
|
||||
materials.forEach(material => {
|
||||
material.visible = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default hideRoof;
|
||||
import * as THREE from 'three';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function hideRoof(
|
||||
visibility: Types.Boolean,
|
||||
floorGroup: Types.RefGroup,
|
||||
camera: THREE.Camera
|
||||
): void {
|
||||
|
||||
////////// Toggles the visibility of the roof based on the camera position and the Roof visibility button on UI //////////
|
||||
|
||||
const v = new THREE.Vector3();
|
||||
const u = new THREE.Vector3();
|
||||
|
||||
if (visibility === true && floorGroup.current) {
|
||||
for (const child of floorGroup.current.children) {
|
||||
if (child.name.includes("Roof")) {
|
||||
const roofChild = child as Types.Mesh;
|
||||
roofChild.getWorldDirection(v);
|
||||
camera?.getWorldDirection(u);
|
||||
if (roofChild.material) {
|
||||
const materials = Array.isArray(roofChild.material) ? roofChild.material : [roofChild.material];
|
||||
materials.forEach(material => {
|
||||
material.visible = v.dot(u) < 0.25;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (floorGroup.current) {
|
||||
for (const child of floorGroup.current.children) {
|
||||
if (child.name.includes("Roof")) {
|
||||
const roofChild = child as Types.Mesh;
|
||||
if (roofChild.material) {
|
||||
const materials = Array.isArray(roofChild.material) ? roofChild.material : [roofChild.material];
|
||||
materials.forEach(material => {
|
||||
material.visible = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default hideRoof;
|
||||
|
||||
@@ -1,108 +1,108 @@
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
import * as THREE from 'three';
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
// import { setWallItem } from '../../../../services/factoryBuilder/assest/wallAsset/setWallItemApi';
|
||||
import { Socket } from 'socket.io-client';
|
||||
|
||||
async function AddWallItems(
|
||||
selected: Types.String,
|
||||
raycaster: THREE.Raycaster,
|
||||
CSGGroup: Types.RefMesh,
|
||||
AssetConfigurations: Types.AssetConfigurations,
|
||||
setWallItems: Types.setWallItemSetState,
|
||||
socket: Socket<any>
|
||||
): Promise<void> {
|
||||
|
||||
////////// Load Wall GLtf's and set the positions, rotation, type etc. in state and store in localstorage //////////
|
||||
|
||||
let intersects = raycaster?.intersectObject(CSGGroup.current!, true);
|
||||
const wallRaycastIntersection = intersects?.find((child) => child.object.name.includes("WallRaycastReference"));
|
||||
|
||||
if (wallRaycastIntersection) {
|
||||
const intersectionPoint = wallRaycastIntersection;
|
||||
const loader = new GLTFLoader();
|
||||
loader.load(AssetConfigurations[selected].modelUrl, async (gltf) => {
|
||||
const model = gltf.scene;
|
||||
model.userData = { wall: intersectionPoint.object.parent };
|
||||
model.children[0].children.forEach((child) => {
|
||||
if (child.name !== "CSG_REF") {
|
||||
child.castShadow = true;
|
||||
child.receiveShadow = true;
|
||||
}
|
||||
});
|
||||
|
||||
const config = AssetConfigurations[selected];
|
||||
let positionY = typeof config.positionY === 'function' ? config.positionY(intersectionPoint) : config.positionY;
|
||||
if (positionY === 0) {
|
||||
positionY = Math.floor(intersectionPoint.point.y / CONSTANTS.wallConfig.height) * CONSTANTS.wallConfig.height;
|
||||
}
|
||||
|
||||
const newWallItem = {
|
||||
type: config.type,
|
||||
model: model,
|
||||
modelname: selected,
|
||||
scale: config.scale,
|
||||
csgscale: config.csgscale,
|
||||
csgposition: config.csgposition,
|
||||
position: [intersectionPoint.point.x, positionY, intersectionPoint.point.z] as [number, number, number],
|
||||
quaternion: intersectionPoint.object.quaternion.clone() as Types.QuaternionType
|
||||
};
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
//REST
|
||||
|
||||
// await setWallItem(
|
||||
// organization,
|
||||
// model.uuid,
|
||||
// newWallItem.modelname,
|
||||
// newWallItem.type!,
|
||||
// newWallItem.csgposition!,
|
||||
// newWallItem.csgscale!,
|
||||
// newWallItem.position,
|
||||
// newWallItem.quaternion,
|
||||
// newWallItem.scale!,
|
||||
// )
|
||||
|
||||
//SOCKET
|
||||
|
||||
const data = {
|
||||
organization: organization,
|
||||
modeluuid: model.uuid,
|
||||
modelname: newWallItem.modelname,
|
||||
type: newWallItem.type!,
|
||||
csgposition: newWallItem.csgposition!,
|
||||
csgscale: newWallItem.csgscale!,
|
||||
position: newWallItem.position,
|
||||
quaternion: newWallItem.quaternion,
|
||||
scale: newWallItem.scale!,
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
socket.emit('v1:wallItems:set', data);
|
||||
|
||||
setWallItems((prevItems) => {
|
||||
const updatedItems = [...prevItems, newWallItem];
|
||||
|
||||
const WallItemsForStorage = updatedItems.map(item => {
|
||||
const { model, ...rest } = item;
|
||||
return {
|
||||
...rest,
|
||||
modeluuid: model?.uuid,
|
||||
};
|
||||
});
|
||||
|
||||
localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage));
|
||||
toast.success("Model Added!");
|
||||
|
||||
return updatedItems;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default AddWallItems;
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
import * as THREE from 'three';
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
// import { setWallItem } from '../../../../services/factoryBuilder/assest/wallAsset/setWallItemApi';
|
||||
import { Socket } from 'socket.io-client';
|
||||
|
||||
async function AddWallItems(
|
||||
selected: Types.String,
|
||||
raycaster: THREE.Raycaster,
|
||||
CSGGroup: Types.RefMesh,
|
||||
AssetConfigurations: Types.AssetConfigurations,
|
||||
setWallItems: Types.setWallItemSetState,
|
||||
socket: Socket<any>
|
||||
): Promise<void> {
|
||||
|
||||
////////// Load Wall GLtf's and set the positions, rotation, type etc. in state and store in localstorage //////////
|
||||
|
||||
let intersects = raycaster?.intersectObject(CSGGroup.current!, true);
|
||||
const wallRaycastIntersection = intersects?.find((child) => child.object.name.includes("WallRaycastReference"));
|
||||
|
||||
if (wallRaycastIntersection) {
|
||||
const intersectionPoint = wallRaycastIntersection;
|
||||
const loader = new GLTFLoader();
|
||||
loader.load(AssetConfigurations[selected].modelUrl, async (gltf) => {
|
||||
const model = gltf.scene;
|
||||
model.userData = { wall: intersectionPoint.object.parent };
|
||||
model.children[0].children.forEach((child) => {
|
||||
if (child.name !== "CSG_REF") {
|
||||
child.castShadow = true;
|
||||
child.receiveShadow = true;
|
||||
}
|
||||
});
|
||||
|
||||
const config = AssetConfigurations[selected];
|
||||
let positionY = typeof config.positionY === 'function' ? config.positionY(intersectionPoint) : config.positionY;
|
||||
if (positionY === 0) {
|
||||
positionY = Math.floor(intersectionPoint.point.y / CONSTANTS.wallConfig.height) * CONSTANTS.wallConfig.height;
|
||||
}
|
||||
|
||||
const newWallItem = {
|
||||
type: config.type,
|
||||
model: model,
|
||||
modelname: selected,
|
||||
scale: config.scale,
|
||||
csgscale: config.csgscale,
|
||||
csgposition: config.csgposition,
|
||||
position: [intersectionPoint.point.x, positionY, intersectionPoint.point.z] as [number, number, number],
|
||||
quaternion: intersectionPoint.object.quaternion.clone() as Types.QuaternionType
|
||||
};
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
//REST
|
||||
|
||||
// await setWallItem(
|
||||
// organization,
|
||||
// model.uuid,
|
||||
// newWallItem.modelname,
|
||||
// newWallItem.type!,
|
||||
// newWallItem.csgposition!,
|
||||
// newWallItem.csgscale!,
|
||||
// newWallItem.position,
|
||||
// newWallItem.quaternion,
|
||||
// newWallItem.scale!,
|
||||
// )
|
||||
|
||||
//SOCKET
|
||||
|
||||
const data = {
|
||||
organization: organization,
|
||||
modeluuid: model.uuid,
|
||||
modelname: newWallItem.modelname,
|
||||
type: newWallItem.type!,
|
||||
csgposition: newWallItem.csgposition!,
|
||||
csgscale: newWallItem.csgscale!,
|
||||
position: newWallItem.position,
|
||||
quaternion: newWallItem.quaternion,
|
||||
scale: newWallItem.scale!,
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
socket.emit('v1:wallItems:set', data);
|
||||
|
||||
setWallItems((prevItems) => {
|
||||
const updatedItems = [...prevItems, newWallItem];
|
||||
|
||||
const WallItemsForStorage = updatedItems.map(item => {
|
||||
const { model, ...rest } = item;
|
||||
return {
|
||||
...rest,
|
||||
modeluuid: model?.uuid,
|
||||
};
|
||||
});
|
||||
|
||||
localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage));
|
||||
toast.success("Model Added!");
|
||||
|
||||
return updatedItems;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default AddWallItems;
|
||||
|
||||
@@ -1,59 +1,59 @@
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
// import { deleteWallItem } from '../../../../services/factoryBuilder/assest/wallAsset/deleteWallItemApi';
|
||||
import { Socket } from 'socket.io-client';
|
||||
|
||||
function DeleteWallItems(
|
||||
hoveredDeletableWallItem: Types.RefMesh,
|
||||
setWallItems: Types.setWallItemSetState,
|
||||
wallItems: Types.wallItems,
|
||||
socket: Socket<any>
|
||||
): void {
|
||||
|
||||
////////// Deleting the hovered Wall GLTF from thewallItems and also update it in the localstorage //////////
|
||||
|
||||
if (hoveredDeletableWallItem.current && hoveredDeletableWallItem.current.parent) {
|
||||
setWallItems([]);
|
||||
let WallItemsRef = wallItems;
|
||||
const removedItem = WallItemsRef.find((item) => item.model?.uuid === hoveredDeletableWallItem.current?.parent?.uuid);
|
||||
const Items = WallItemsRef.filter((item) => item.model?.uuid !== hoveredDeletableWallItem.current?.parent?.uuid);
|
||||
|
||||
setTimeout(async () => {
|
||||
WallItemsRef = Items;
|
||||
setWallItems(WallItemsRef);
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
//REST
|
||||
|
||||
// await deleteWallItem(organization, removedItem?.model?.uuid!, removedItem?.modelname!)
|
||||
|
||||
//SOCKET
|
||||
|
||||
const data = {
|
||||
organization: organization,
|
||||
modeluuid: removedItem?.model?.uuid!,
|
||||
modelname: removedItem?.modelname!,
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
socket.emit('v1:wallItems:delete', data);
|
||||
|
||||
const WallItemsForStorage = WallItemsRef.map(item => {
|
||||
const { model, ...rest } = item;
|
||||
return {
|
||||
...rest,
|
||||
modeluuid: model?.uuid,
|
||||
};
|
||||
});
|
||||
|
||||
localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage));
|
||||
toast.success("Model Removed!");
|
||||
hoveredDeletableWallItem.current = null;
|
||||
}, 50);
|
||||
}
|
||||
}
|
||||
|
||||
export default DeleteWallItems;
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
// import { deleteWallItem } from '../../../../services/factoryBuilder/assest/wallAsset/deleteWallItemApi';
|
||||
import { Socket } from 'socket.io-client';
|
||||
|
||||
function DeleteWallItems(
|
||||
hoveredDeletableWallItem: Types.RefMesh,
|
||||
setWallItems: Types.setWallItemSetState,
|
||||
wallItems: Types.wallItems,
|
||||
socket: Socket<any>
|
||||
): void {
|
||||
|
||||
////////// Deleting the hovered Wall GLTF from thewallItems and also update it in the localstorage //////////
|
||||
|
||||
if (hoveredDeletableWallItem.current && hoveredDeletableWallItem.current.parent) {
|
||||
setWallItems([]);
|
||||
let WallItemsRef = wallItems;
|
||||
const removedItem = WallItemsRef.find((item) => item.model?.uuid === hoveredDeletableWallItem.current?.parent?.uuid);
|
||||
const Items = WallItemsRef.filter((item) => item.model?.uuid !== hoveredDeletableWallItem.current?.parent?.uuid);
|
||||
|
||||
setTimeout(async () => {
|
||||
WallItemsRef = Items;
|
||||
setWallItems(WallItemsRef);
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
//REST
|
||||
|
||||
// await deleteWallItem(organization, removedItem?.model?.uuid!, removedItem?.modelname!)
|
||||
|
||||
//SOCKET
|
||||
|
||||
const data = {
|
||||
organization: organization,
|
||||
modeluuid: removedItem?.model?.uuid!,
|
||||
modelname: removedItem?.modelname!,
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
socket.emit('v1:wallItems:delete', data);
|
||||
|
||||
const WallItemsForStorage = WallItemsRef.map(item => {
|
||||
const { model, ...rest } = item;
|
||||
return {
|
||||
...rest,
|
||||
modeluuid: model?.uuid,
|
||||
};
|
||||
});
|
||||
|
||||
localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage));
|
||||
toast.success("Model Removed!");
|
||||
hoveredDeletableWallItem.current = null;
|
||||
}, 50);
|
||||
}
|
||||
}
|
||||
|
||||
export default DeleteWallItems;
|
||||
|
||||
@@ -1,45 +1,45 @@
|
||||
import * as THREE from 'three';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function hideWalls(
|
||||
visibility: Types.Boolean,
|
||||
scene: THREE.Scene,
|
||||
camera: THREE.Camera
|
||||
): void {
|
||||
|
||||
////////// Altering the visibility of the Walls when the world direction of the wall is facing the camera //////////
|
||||
|
||||
const v = new THREE.Vector3();
|
||||
const u = new THREE.Vector3();
|
||||
|
||||
if (visibility === true) {
|
||||
for (const children of scene.children) {
|
||||
if (children.name === "Walls" && children.children[0]?.children.length > 0) {
|
||||
children.children[0].children.forEach((child: any) => {
|
||||
if (child.children[0]?.userData.WallType === "RoomWall") {
|
||||
child.children[0].getWorldDirection(v);
|
||||
camera.getWorldDirection(u);
|
||||
if (child.children[0].material) {
|
||||
child.children[0].material.visible = (2 * v.dot(u)) >= -0.5;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (const children of scene.children) {
|
||||
if (children.name === "Walls" && children.children[0]?.children.length > 0) {
|
||||
children.children[0].children.forEach((child: any) => {
|
||||
if (child.children[0]?.userData.WallType === "RoomWall") {
|
||||
if (child.children[0].material) {
|
||||
child.children[0].material.visible = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default hideWalls;
|
||||
import * as THREE from 'three';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function hideWalls(
|
||||
visibility: Types.Boolean,
|
||||
scene: THREE.Scene,
|
||||
camera: THREE.Camera
|
||||
): void {
|
||||
|
||||
////////// Altering the visibility of the Walls when the world direction of the wall is facing the camera //////////
|
||||
|
||||
const v = new THREE.Vector3();
|
||||
const u = new THREE.Vector3();
|
||||
|
||||
if (visibility === true) {
|
||||
for (const children of scene.children) {
|
||||
if (children.name === "Walls" && children.children[0]?.children.length > 0) {
|
||||
children.children[0].children.forEach((child: any) => {
|
||||
if (child.children[0]?.userData.WallType === "RoomWall") {
|
||||
child.children[0].getWorldDirection(v);
|
||||
camera.getWorldDirection(u);
|
||||
if (child.children[0].material) {
|
||||
child.children[0].material.visible = (2 * v.dot(u)) >= -0.5;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (const children of scene.children) {
|
||||
if (children.name === "Walls" && children.children[0]?.children.length > 0) {
|
||||
children.children[0].children.forEach((child: any) => {
|
||||
if (child.children[0]?.userData.WallType === "RoomWall") {
|
||||
if (child.children[0].material) {
|
||||
child.children[0].material.visible = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default hideWalls;
|
||||
|
||||
@@ -1,129 +1,129 @@
|
||||
import * as THREE from 'three';
|
||||
import * as turf from '@turf/turf';
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import getRoomsFromLines from '../lines/getRoomsFromLines';
|
||||
|
||||
async function loadWalls(
|
||||
lines: Types.RefLines,
|
||||
setWalls: any,
|
||||
): Promise<void> {
|
||||
////////// Removes the old walls if any, Checks if there is any overlapping in lines if any updates it , starts function that creates floor and roof //////////
|
||||
|
||||
const Walls: Types.Walls = [];
|
||||
const Rooms: Types.Rooms = [];
|
||||
|
||||
localStorage.setItem("Lines", JSON.stringify(lines.current));
|
||||
|
||||
if (lines.current.length > 1) {
|
||||
|
||||
////////// Add Walls that are forming a room //////////
|
||||
|
||||
const wallSet = new Set<string>();
|
||||
|
||||
const rooms: Types.Rooms = await getRoomsFromLines(lines);
|
||||
Rooms.push(...rooms);
|
||||
|
||||
Rooms.forEach(({ coordinates: room, layer }) => {
|
||||
for (let i = 0; i < room.length - 1; i++) {
|
||||
const uuid1 = room[i].uuid;
|
||||
const uuid2 = room[(i + 1) % room.length].uuid;
|
||||
const wallId = `${uuid1}_${uuid2}`;
|
||||
|
||||
if (!wallSet.has(wallId)) {
|
||||
const p1 = room[i].position;
|
||||
const p2 = room[(i + 1) % room.length].position;
|
||||
|
||||
const shape = new THREE.Shape();
|
||||
shape.moveTo(0, 0);
|
||||
shape.lineTo(0, CONSTANTS.wallConfig.height);
|
||||
shape.lineTo(p2.distanceTo(p1), CONSTANTS.wallConfig.height);
|
||||
shape.lineTo(p2.distanceTo(p1), 0);
|
||||
shape.lineTo(0, 0);
|
||||
|
||||
const extrudeSettings = {
|
||||
depth: CONSTANTS.wallConfig.width,
|
||||
bevelEnabled: false
|
||||
};
|
||||
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
|
||||
const angle = Math.atan2(p2.z - p1.z, p2.x - p1.x);
|
||||
Walls.push([geometry, [0, -angle, 0], [p1.x, (layer - 1) * CONSTANTS.wallConfig.height, p1.z], "RoomWall", layer]);
|
||||
|
||||
wallSet.add(wallId);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
////////// Add Walls that are not forming any room //////////
|
||||
|
||||
lines.current.forEach(line => {
|
||||
if (line[0][3] && line[1][3] !== CONSTANTS.lineConfig.wallName) {
|
||||
return;
|
||||
}
|
||||
const [uuid1, uuid2] = line.map(point => point[1]);
|
||||
let isInRoom = false;
|
||||
const lineLayer = line[0][2];
|
||||
|
||||
for (let room of Rooms) {
|
||||
const roomLayer = room.layer;
|
||||
if (roomLayer !== lineLayer) continue;
|
||||
for (let i = 0; i < room.coordinates.length - 1; i++) {
|
||||
const roomUuid1 = room.coordinates[i].uuid;
|
||||
const roomUuid2 = room.coordinates[(i + 1) % room.coordinates.length].uuid;
|
||||
if (
|
||||
(uuid1 === roomUuid1 && uuid2 === roomUuid2) ||
|
||||
(uuid1 === roomUuid2 && uuid2 === roomUuid1)
|
||||
) {
|
||||
isInRoom = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isInRoom) break;
|
||||
}
|
||||
|
||||
if (!isInRoom) {
|
||||
const p1 = new THREE.Vector3(line[0][0].x, 0, line[0][0].z);
|
||||
const p2 = new THREE.Vector3(line[1][0].x, 0, line[1][0].z);
|
||||
|
||||
let isCollinear = false;
|
||||
for (let room of Rooms) {
|
||||
if (room.layer !== lineLayer) continue;
|
||||
for (let i = 0; i < room.coordinates.length - 1; i++) {
|
||||
const roomP1 = room.coordinates[i].position;
|
||||
const roomP2 = room.coordinates[(i + 1) % room.coordinates.length].position;
|
||||
const lineFeature = turf.lineString([[p1.x, p1.z], [p2.x, p2.z]]);
|
||||
const roomFeature = turf.lineString([[roomP1.x, roomP1.z], [roomP2.x, roomP2.z]]);
|
||||
if (turf.booleanOverlap(lineFeature, roomFeature)) {
|
||||
isCollinear = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isCollinear) break;
|
||||
}
|
||||
|
||||
if (!isCollinear) {
|
||||
const shape = new THREE.Shape();
|
||||
shape.moveTo(0, 0);
|
||||
shape.lineTo(0, CONSTANTS.wallConfig.height);
|
||||
shape.lineTo(p2.distanceTo(p1), CONSTANTS.wallConfig.height);
|
||||
shape.lineTo(p2.distanceTo(p1), 0);
|
||||
shape.lineTo(0, 0);
|
||||
|
||||
const extrudeSettings = {
|
||||
depth: CONSTANTS.wallConfig.width,
|
||||
bevelEnabled: false
|
||||
};
|
||||
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
|
||||
const angle = Math.atan2(p2.z - p1.z, p2.x - p1.x);
|
||||
Walls.push([geometry, [0, -angle, 0], [p1.x, (lineLayer - 1) * CONSTANTS.wallConfig.height, p1.z], "SegmentWall", lineLayer]);
|
||||
}
|
||||
}
|
||||
});
|
||||
setWalls(Walls);
|
||||
}else{
|
||||
setWalls([]);
|
||||
}
|
||||
}
|
||||
|
||||
export default loadWalls;
|
||||
import * as THREE from 'three';
|
||||
import * as turf from '@turf/turf';
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import getRoomsFromLines from '../lines/getRoomsFromLines';
|
||||
|
||||
async function loadWalls(
|
||||
lines: Types.RefLines,
|
||||
setWalls: any,
|
||||
): Promise<void> {
|
||||
////////// Removes the old walls if any, Checks if there is any overlapping in lines if any updates it , starts function that creates floor and roof //////////
|
||||
|
||||
const Walls: Types.Walls = [];
|
||||
const Rooms: Types.Rooms = [];
|
||||
|
||||
localStorage.setItem("Lines", JSON.stringify(lines.current));
|
||||
|
||||
if (lines.current.length > 1) {
|
||||
|
||||
////////// Add Walls that are forming a room //////////
|
||||
|
||||
const wallSet = new Set<string>();
|
||||
|
||||
const rooms: Types.Rooms = await getRoomsFromLines(lines);
|
||||
Rooms.push(...rooms);
|
||||
|
||||
Rooms.forEach(({ coordinates: room, layer }) => {
|
||||
for (let i = 0; i < room.length - 1; i++) {
|
||||
const uuid1 = room[i].uuid;
|
||||
const uuid2 = room[(i + 1) % room.length].uuid;
|
||||
const wallId = `${uuid1}_${uuid2}`;
|
||||
|
||||
if (!wallSet.has(wallId)) {
|
||||
const p1 = room[i].position;
|
||||
const p2 = room[(i + 1) % room.length].position;
|
||||
|
||||
const shape = new THREE.Shape();
|
||||
shape.moveTo(0, 0);
|
||||
shape.lineTo(0, CONSTANTS.wallConfig.height);
|
||||
shape.lineTo(p2.distanceTo(p1), CONSTANTS.wallConfig.height);
|
||||
shape.lineTo(p2.distanceTo(p1), 0);
|
||||
shape.lineTo(0, 0);
|
||||
|
||||
const extrudeSettings = {
|
||||
depth: CONSTANTS.wallConfig.width,
|
||||
bevelEnabled: false
|
||||
};
|
||||
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
|
||||
const angle = Math.atan2(p2.z - p1.z, p2.x - p1.x);
|
||||
Walls.push([geometry, [0, -angle, 0], [p1.x, (layer - 1) * CONSTANTS.wallConfig.height, p1.z], "RoomWall", layer]);
|
||||
|
||||
wallSet.add(wallId);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
////////// Add Walls that are not forming any room //////////
|
||||
|
||||
lines.current.forEach(line => {
|
||||
if (line[0][3] && line[1][3] !== CONSTANTS.lineConfig.wallName) {
|
||||
return;
|
||||
}
|
||||
const [uuid1, uuid2] = line.map(point => point[1]);
|
||||
let isInRoom = false;
|
||||
const lineLayer = line[0][2];
|
||||
|
||||
for (let room of Rooms) {
|
||||
const roomLayer = room.layer;
|
||||
if (roomLayer !== lineLayer) continue;
|
||||
for (let i = 0; i < room.coordinates.length - 1; i++) {
|
||||
const roomUuid1 = room.coordinates[i].uuid;
|
||||
const roomUuid2 = room.coordinates[(i + 1) % room.coordinates.length].uuid;
|
||||
if (
|
||||
(uuid1 === roomUuid1 && uuid2 === roomUuid2) ||
|
||||
(uuid1 === roomUuid2 && uuid2 === roomUuid1)
|
||||
) {
|
||||
isInRoom = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isInRoom) break;
|
||||
}
|
||||
|
||||
if (!isInRoom) {
|
||||
const p1 = new THREE.Vector3(line[0][0].x, 0, line[0][0].z);
|
||||
const p2 = new THREE.Vector3(line[1][0].x, 0, line[1][0].z);
|
||||
|
||||
let isCollinear = false;
|
||||
for (let room of Rooms) {
|
||||
if (room.layer !== lineLayer) continue;
|
||||
for (let i = 0; i < room.coordinates.length - 1; i++) {
|
||||
const roomP1 = room.coordinates[i].position;
|
||||
const roomP2 = room.coordinates[(i + 1) % room.coordinates.length].position;
|
||||
const lineFeature = turf.lineString([[p1.x, p1.z], [p2.x, p2.z]]);
|
||||
const roomFeature = turf.lineString([[roomP1.x, roomP1.z], [roomP2.x, roomP2.z]]);
|
||||
if (turf.booleanOverlap(lineFeature, roomFeature)) {
|
||||
isCollinear = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isCollinear) break;
|
||||
}
|
||||
|
||||
if (!isCollinear) {
|
||||
const shape = new THREE.Shape();
|
||||
shape.moveTo(0, 0);
|
||||
shape.lineTo(0, CONSTANTS.wallConfig.height);
|
||||
shape.lineTo(p2.distanceTo(p1), CONSTANTS.wallConfig.height);
|
||||
shape.lineTo(p2.distanceTo(p1), 0);
|
||||
shape.lineTo(0, 0);
|
||||
|
||||
const extrudeSettings = {
|
||||
depth: CONSTANTS.wallConfig.width,
|
||||
bevelEnabled: false
|
||||
};
|
||||
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
|
||||
const angle = Math.atan2(p2.z - p1.z, p2.x - p1.x);
|
||||
Walls.push([geometry, [0, -angle, 0], [p1.x, (lineLayer - 1) * CONSTANTS.wallConfig.height, p1.z], "SegmentWall", lineLayer]);
|
||||
}
|
||||
}
|
||||
});
|
||||
setWalls(Walls);
|
||||
}else{
|
||||
setWalls([]);
|
||||
}
|
||||
}
|
||||
|
||||
export default loadWalls;
|
||||
|
||||
@@ -1,50 +1,50 @@
|
||||
import * as THREE from 'three';
|
||||
import * as Types from '../../../../types/world/worldTypes';
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
|
||||
const baseMaterial = new THREE.ShaderMaterial({
|
||||
side: THREE.DoubleSide,
|
||||
vertexShader: `
|
||||
varying vec2 vUv;
|
||||
void main(){
|
||||
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
||||
vUv = uv;
|
||||
}
|
||||
`,
|
||||
fragmentShader: `
|
||||
varying vec2 vUv;
|
||||
uniform vec3 uColor;
|
||||
void main(){
|
||||
float alpha = 1.0 - vUv.y;
|
||||
gl_FragColor = vec4(uColor, alpha);
|
||||
}
|
||||
`,
|
||||
uniforms: {
|
||||
uColor: { value: new THREE.Color(CONSTANTS.zoneConfig.defaultColor) },
|
||||
},
|
||||
transparent: true,
|
||||
});
|
||||
|
||||
export default function addZonesToScene(
|
||||
line: Types.Line,
|
||||
floorGroupZone: Types.RefGroup,
|
||||
color: THREE.Color
|
||||
) {
|
||||
const point1 = line[0][0];
|
||||
const point2 = line[1][0];
|
||||
|
||||
const length = (new THREE.Vector3(point2.x, point2.y, point2.z)).distanceTo(new THREE.Vector3(point1.x, point1.y, point1.z));
|
||||
const angle = Math.atan2(point2.z - point1.z, point2.x - point1.x);
|
||||
|
||||
const geometry = new THREE.PlaneGeometry(length, 10);
|
||||
|
||||
const material = baseMaterial.clone();
|
||||
material.uniforms.uColor.value.set(color.r, color.g, color.b);
|
||||
|
||||
const mesh = new THREE.Mesh(geometry, material);
|
||||
|
||||
mesh.position.set((point1.x + point2.x) / 2, ((line[0][2] - 1) * CONSTANTS.wallConfig.height) + 5, (point1.z + point2.z) / 2);
|
||||
mesh.rotation.y = -angle;
|
||||
|
||||
floorGroupZone.current.add(mesh);
|
||||
}
|
||||
import * as THREE from 'three';
|
||||
import * as Types from '../../../../types/world/worldTypes';
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
|
||||
const baseMaterial = new THREE.ShaderMaterial({
|
||||
side: THREE.DoubleSide,
|
||||
vertexShader: `
|
||||
varying vec2 vUv;
|
||||
void main(){
|
||||
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
||||
vUv = uv;
|
||||
}
|
||||
`,
|
||||
fragmentShader: `
|
||||
varying vec2 vUv;
|
||||
uniform vec3 uColor;
|
||||
void main(){
|
||||
float alpha = 1.0 - vUv.y;
|
||||
gl_FragColor = vec4(uColor, alpha);
|
||||
}
|
||||
`,
|
||||
uniforms: {
|
||||
uColor: { value: new THREE.Color(CONSTANTS.zoneConfig.defaultColor) },
|
||||
},
|
||||
transparent: true,
|
||||
});
|
||||
|
||||
export default function addZonesToScene(
|
||||
line: Types.Line,
|
||||
floorGroupZone: Types.RefGroup,
|
||||
color: THREE.Color
|
||||
) {
|
||||
const point1 = line[0][0];
|
||||
const point2 = line[1][0];
|
||||
|
||||
const length = (new THREE.Vector3(point2.x, point2.y, point2.z)).distanceTo(new THREE.Vector3(point1.x, point1.y, point1.z));
|
||||
const angle = Math.atan2(point2.z - point1.z, point2.x - point1.x);
|
||||
|
||||
const geometry = new THREE.PlaneGeometry(length, 10);
|
||||
|
||||
const material = baseMaterial.clone();
|
||||
material.uniforms.uColor.value.set(color.r, color.g, color.b);
|
||||
|
||||
const mesh = new THREE.Mesh(geometry, material);
|
||||
|
||||
mesh.position.set((point1.x + point2.x) / 2, ((line[0][2] - 1) * CONSTANTS.wallConfig.height) + 5, (point1.z + point2.z) / 2);
|
||||
mesh.rotation.y = -angle;
|
||||
|
||||
floorGroupZone.current.add(mesh);
|
||||
}
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import * as Types from '../../../../types/world/worldTypes';
|
||||
import * as THREE from 'three';
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
import addZonesToScene from './addZonesToScene';
|
||||
|
||||
export default function loadZones(
|
||||
lines: Types.RefLines,
|
||||
floorGroupZone: Types.RefGroup
|
||||
) {
|
||||
if (!floorGroupZone.current) return
|
||||
floorGroupZone.current.children = [];
|
||||
const zones = lines.current.filter((line) => line[0][3] && line[1][3] === CONSTANTS.lineConfig.zoneName);
|
||||
|
||||
if (zones.length > 0) {
|
||||
zones.forEach((zone: Types.Line) => {
|
||||
addZonesToScene(zone, floorGroupZone, new THREE.Color(CONSTANTS.zoneConfig.color))
|
||||
})
|
||||
}
|
||||
import * as Types from '../../../../types/world/worldTypes';
|
||||
import * as THREE from 'three';
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
import addZonesToScene from './addZonesToScene';
|
||||
|
||||
export default function loadZones(
|
||||
lines: Types.RefLines,
|
||||
floorGroupZone: Types.RefGroup
|
||||
) {
|
||||
if (!floorGroupZone.current) return
|
||||
floorGroupZone.current.children = [];
|
||||
const zones = lines.current.filter((line) => line[0][3] && line[1][3] === CONSTANTS.lineConfig.zoneName);
|
||||
|
||||
if (zones.length > 0) {
|
||||
zones.forEach((zone: Types.Line) => {
|
||||
addZonesToScene(zone, floorGroupZone, new THREE.Color(CONSTANTS.zoneConfig.color))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,101 +1,101 @@
|
||||
import { useFrame, useThree } from "@react-three/fiber";
|
||||
import { useAddAction, useDeleteModels, useRoofVisibility, useToggleView, useWallVisibility, useUpdateScene } from "../../../store/store";
|
||||
import hideRoof from "../geomentries/roofs/hideRoof";
|
||||
import hideWalls from "../geomentries/walls/hideWalls";
|
||||
import addAndUpdateReferencePillar from "../geomentries/pillars/addAndUpdateReferencePillar";
|
||||
import { useEffect } from "react";
|
||||
import addPillar from "../geomentries/pillars/addPillar";
|
||||
import DeletePillar from "../geomentries/pillars/deletePillar";
|
||||
import DeletableHoveredPillar from "../geomentries/pillars/deletableHoveredPillar";
|
||||
import loadFloor from "../geomentries/floors/loadFloor";
|
||||
|
||||
const FloorGroup = ({ floorGroup, lines, referencePole, hoveredDeletablePillar }: any) => {
|
||||
const state = useThree();
|
||||
const { roofVisibility, setRoofVisibility } = useRoofVisibility();
|
||||
const { wallVisibility, setWallVisibility } = useWallVisibility();
|
||||
const { toggleView, setToggleView } = useToggleView();
|
||||
const { scene, camera, pointer, raycaster, gl } = useThree();
|
||||
const { addAction, setAddAction } = useAddAction();
|
||||
const { deleteModels, setDeleteModels } = useDeleteModels();
|
||||
const { updateScene, setUpdateScene } = useUpdateScene();
|
||||
|
||||
useEffect(() => {
|
||||
if (updateScene) {
|
||||
loadFloor(lines, floorGroup);
|
||||
setUpdateScene(false);
|
||||
}
|
||||
}, [updateScene])
|
||||
|
||||
useEffect(() => {
|
||||
if (!addAction) {
|
||||
if (referencePole.current) {
|
||||
(referencePole.current as any).material.dispose();
|
||||
(referencePole.current.geometry as any).dispose();
|
||||
floorGroup.current.remove(referencePole.current);
|
||||
referencePole.current = undefined;
|
||||
}
|
||||
}
|
||||
}, [addAction]);
|
||||
|
||||
useEffect(() => {
|
||||
const canvasElement = gl.domElement;
|
||||
let drag = false;
|
||||
let isLeftMouseDown = false;
|
||||
|
||||
const onMouseDown = (evt: any) => {
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown = true;
|
||||
drag = false;
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseUp = (evt: any) => {
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown = false;
|
||||
if (!drag) {
|
||||
if (addAction === "pillar") {
|
||||
addPillar(referencePole, floorGroup);
|
||||
}
|
||||
if (deleteModels) {
|
||||
DeletePillar(hoveredDeletablePillar, floorGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseMove = () => {
|
||||
if (isLeftMouseDown) {
|
||||
drag = true;
|
||||
}
|
||||
};
|
||||
|
||||
canvasElement.addEventListener("mousedown", onMouseDown);
|
||||
canvasElement.addEventListener("mouseup", onMouseUp);
|
||||
canvasElement.addEventListener("mousemove", onMouseMove);
|
||||
|
||||
return () => {
|
||||
canvasElement.removeEventListener("mousedown", onMouseDown);
|
||||
canvasElement.removeEventListener("mouseup", onMouseUp);
|
||||
canvasElement.removeEventListener("mousemove", onMouseMove);
|
||||
};
|
||||
}, [deleteModels, addAction])
|
||||
|
||||
useFrame(() => {
|
||||
hideRoof(roofVisibility, floorGroup, camera);
|
||||
hideWalls(wallVisibility, scene, camera);
|
||||
|
||||
if (addAction === "pillar") {
|
||||
addAndUpdateReferencePillar(raycaster, floorGroup, referencePole);
|
||||
}
|
||||
if (deleteModels) {
|
||||
DeletableHoveredPillar(state, floorGroup, hoveredDeletablePillar);
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
<group ref={floorGroup} visible={!toggleView} name="floorGroup">
|
||||
</group>
|
||||
)
|
||||
}
|
||||
|
||||
import { useFrame, useThree } from "@react-three/fiber";
|
||||
import { useAddAction, useDeleteModels, useRoofVisibility, useToggleView, useWallVisibility, useUpdateScene } from "../../../store/store";
|
||||
import hideRoof from "../geomentries/roofs/hideRoof";
|
||||
import hideWalls from "../geomentries/walls/hideWalls";
|
||||
import addAndUpdateReferencePillar from "../geomentries/pillars/addAndUpdateReferencePillar";
|
||||
import { useEffect } from "react";
|
||||
import addPillar from "../geomentries/pillars/addPillar";
|
||||
import DeletePillar from "../geomentries/pillars/deletePillar";
|
||||
import DeletableHoveredPillar from "../geomentries/pillars/deletableHoveredPillar";
|
||||
import loadFloor from "../geomentries/floors/loadFloor";
|
||||
|
||||
const FloorGroup = ({ floorGroup, lines, referencePole, hoveredDeletablePillar }: any) => {
|
||||
const state = useThree();
|
||||
const { roofVisibility, setRoofVisibility } = useRoofVisibility();
|
||||
const { wallVisibility, setWallVisibility } = useWallVisibility();
|
||||
const { toggleView, setToggleView } = useToggleView();
|
||||
const { scene, camera, pointer, raycaster, gl } = useThree();
|
||||
const { addAction, setAddAction } = useAddAction();
|
||||
const { deleteModels, setDeleteModels } = useDeleteModels();
|
||||
const { updateScene, setUpdateScene } = useUpdateScene();
|
||||
|
||||
useEffect(() => {
|
||||
if (updateScene) {
|
||||
loadFloor(lines, floorGroup);
|
||||
setUpdateScene(false);
|
||||
}
|
||||
}, [updateScene])
|
||||
|
||||
useEffect(() => {
|
||||
if (!addAction) {
|
||||
if (referencePole.current) {
|
||||
(referencePole.current as any).material.dispose();
|
||||
(referencePole.current.geometry as any).dispose();
|
||||
floorGroup.current.remove(referencePole.current);
|
||||
referencePole.current = undefined;
|
||||
}
|
||||
}
|
||||
}, [addAction]);
|
||||
|
||||
useEffect(() => {
|
||||
const canvasElement = gl.domElement;
|
||||
let drag = false;
|
||||
let isLeftMouseDown = false;
|
||||
|
||||
const onMouseDown = (evt: any) => {
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown = true;
|
||||
drag = false;
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseUp = (evt: any) => {
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown = false;
|
||||
if (!drag) {
|
||||
if (addAction === "pillar") {
|
||||
addPillar(referencePole, floorGroup);
|
||||
}
|
||||
if (deleteModels) {
|
||||
DeletePillar(hoveredDeletablePillar, floorGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseMove = () => {
|
||||
if (isLeftMouseDown) {
|
||||
drag = true;
|
||||
}
|
||||
};
|
||||
|
||||
canvasElement.addEventListener("mousedown", onMouseDown);
|
||||
canvasElement.addEventListener("mouseup", onMouseUp);
|
||||
canvasElement.addEventListener("mousemove", onMouseMove);
|
||||
|
||||
return () => {
|
||||
canvasElement.removeEventListener("mousedown", onMouseDown);
|
||||
canvasElement.removeEventListener("mouseup", onMouseUp);
|
||||
canvasElement.removeEventListener("mousemove", onMouseMove);
|
||||
};
|
||||
}, [deleteModels, addAction])
|
||||
|
||||
useFrame(() => {
|
||||
hideRoof(roofVisibility, floorGroup, camera);
|
||||
hideWalls(wallVisibility, scene, camera);
|
||||
|
||||
if (addAction === "pillar") {
|
||||
addAndUpdateReferencePillar(raycaster, floorGroup, referencePole);
|
||||
}
|
||||
if (deleteModels) {
|
||||
DeletableHoveredPillar(state, floorGroup, hoveredDeletablePillar);
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
<group ref={floorGroup} visible={!toggleView} name="floorGroup">
|
||||
</group>
|
||||
)
|
||||
}
|
||||
|
||||
export default FloorGroup;
|
||||
@@ -1,245 +1,245 @@
|
||||
import * as THREE from 'three';
|
||||
import * as Types from '../../../types/world/worldTypes';
|
||||
import * as CONSTANTS from '../../../types/world/worldConstants';
|
||||
import { useThree } from "@react-three/fiber";
|
||||
import { useToggleView, useActiveLayer, useSocketStore, useDeletePointOrLine, useMovePoint, useUpdateScene, useNewLines, useToolMode } from "../../../store/store";
|
||||
import { useEffect } from "react";
|
||||
import removeSoloPoint from "../geomentries/points/removeSoloPoint";
|
||||
import removeReferenceLine from "../geomentries/lines/removeReferenceLine";
|
||||
import getClosestIntersection from "../geomentries/lines/getClosestIntersection";
|
||||
import addPointToScene from "../geomentries/points/addPointToScene";
|
||||
import arrayLineToObject from '../geomentries/lines/lineConvertions/arrayLineToObject';
|
||||
import addLineToScene from "../geomentries/lines/addLineToScene";
|
||||
import loadAisles from '../geomentries/aisles/loadAisles';
|
||||
|
||||
|
||||
const FloorGroupAilse = ({ floorGroupAisle, plane, floorPlanGroupLine, floorPlanGroupPoint, line, lines, currentLayerPoint, dragPointControls, floorPlanGroup, ReferenceLineMesh, LineCreated, isSnapped, ispreSnapped, snappedPoint, isSnappedUUID, isAngleSnapped, anglesnappedPoint }: any) => {
|
||||
const { toggleView, setToggleView } = useToggleView();
|
||||
const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine();
|
||||
const { toolMode, setToolMode } = useToolMode();
|
||||
const { movePoint, setMovePoint } = useMovePoint();
|
||||
const { socket } = useSocketStore();
|
||||
const { activeLayer } = useActiveLayer();
|
||||
const { gl, raycaster, camera, pointer } = useThree();
|
||||
const { updateScene, setUpdateScene } = useUpdateScene();
|
||||
const { newLines, setNewLines } = useNewLines();
|
||||
|
||||
useEffect(() => {
|
||||
if (updateScene) {
|
||||
loadAisles(lines, floorGroupAisle);
|
||||
setUpdateScene(false);
|
||||
}
|
||||
}, [updateScene])
|
||||
|
||||
useEffect(() => {
|
||||
if (toolMode === "Aisle") {
|
||||
setDeletePointOrLine(false);
|
||||
setMovePoint(false);
|
||||
} else {
|
||||
removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint);
|
||||
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
|
||||
}
|
||||
}, [toolMode]);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
const canvasElement = gl.domElement;
|
||||
|
||||
let drag = false;
|
||||
let isLeftMouseDown = false;
|
||||
|
||||
const onMouseDown = (evt: any) => {
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown = true;
|
||||
drag = false;
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseUp = (evt: any) => {
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown = false;
|
||||
}
|
||||
}
|
||||
|
||||
const onMouseMove = () => {
|
||||
if (isLeftMouseDown) {
|
||||
drag = true;
|
||||
}
|
||||
};
|
||||
|
||||
const onContextMenu = (e: any) => {
|
||||
e.preventDefault();
|
||||
if (toolMode === "Aisle") {
|
||||
removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint);
|
||||
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseClick = (evt: any) => {
|
||||
if (!plane.current || drag) return;
|
||||
|
||||
const intersects = raycaster.intersectObject(plane.current, true);
|
||||
let intersectionPoint = intersects[0].point;
|
||||
const points = floorPlanGroupPoint.current?.children ?? [];
|
||||
const intersectsPoint = raycaster.intersectObjects(points, true).find(intersect => intersect.object.visible);
|
||||
let intersectsLines: any = raycaster.intersectObjects(floorPlanGroupLine.current.children, true);
|
||||
|
||||
|
||||
if (intersectsLines.length > 0 && intersects && intersects.length > 0 && !intersectsPoint) {
|
||||
const lineType = intersectsLines[0].object.userData.linePoints[0][3];
|
||||
if (lineType === CONSTANTS.lineConfig.aisleName) {
|
||||
// console.log("intersected a aisle line");
|
||||
const ThroughPoint = (intersectsLines[0].object.geometry.parameters.path).getPoints(CONSTANTS.lineConfig.lineIntersectionPoints);
|
||||
let intersection = getClosestIntersection(ThroughPoint, intersectionPoint);
|
||||
if (!intersection) return;
|
||||
const point = addPointToScene(intersection, CONSTANTS.pointConfig.aisleOuterColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, undefined, CONSTANTS.lineConfig.aisleName);
|
||||
(line.current as Types.Line).push([new THREE.Vector3(intersection.x, 0.01, intersection.z), point.uuid, activeLayer, CONSTANTS.lineConfig.aisleName,]);
|
||||
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
|
||||
lines.current.push(line.current as Types.Line);
|
||||
|
||||
const data = arrayLineToObject(line.current as Types.Line);
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
//REST
|
||||
|
||||
// setLine(organization, data.layer!, data.line!, data.type!);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const input = {
|
||||
organization: organization,
|
||||
layer: data.layer,
|
||||
line: data.line,
|
||||
type: data.type,
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
socket.emit('v1:Line:create', input);
|
||||
|
||||
setNewLines([line.current]);
|
||||
|
||||
addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.pointConfig.aisleOuterColor, line.current, floorPlanGroupLine);
|
||||
let lastPoint = line.current[line.current.length - 1];
|
||||
line.current = [lastPoint];
|
||||
}
|
||||
}
|
||||
} else if (intersectsPoint && intersects && intersects.length > 0) {
|
||||
if (intersectsPoint.object.userData.type === CONSTANTS.lineConfig.aisleName) {
|
||||
// console.log("intersected a aisle point");
|
||||
intersectionPoint = intersectsPoint.object.position;
|
||||
(line.current as Types.Line).push([new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), intersectsPoint.object.uuid, activeLayer, CONSTANTS.lineConfig.aisleName,]);
|
||||
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
|
||||
lines.current.push(line.current as Types.Line);
|
||||
|
||||
const data = arrayLineToObject(line.current as Types.Line);
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
//REST
|
||||
|
||||
// setLine(organization, data.layer!, data.line!, data.type!);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const input = {
|
||||
organization: organization,
|
||||
layer: data.layer,
|
||||
line: data.line,
|
||||
type: data.type,
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
socket.emit('v1:Line:create', input);
|
||||
|
||||
setNewLines([line.current]);
|
||||
|
||||
addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.pointConfig.aisleOuterColor, line.current, floorPlanGroupLine);
|
||||
let lastPoint = line.current[line.current.length - 1];
|
||||
line.current = [lastPoint];
|
||||
ispreSnapped.current = false;
|
||||
isSnapped.current = false;
|
||||
}
|
||||
}
|
||||
} else if (intersects && intersects.length > 0) {
|
||||
// console.log("intersected a empty area");
|
||||
let uuid: string = "";
|
||||
if (isAngleSnapped.current && anglesnappedPoint.current && line.current.length > 0) {
|
||||
intersectionPoint = anglesnappedPoint.current;
|
||||
const point = addPointToScene(intersectionPoint, CONSTANTS.pointConfig.aisleOuterColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, undefined, CONSTANTS.lineConfig.aisleName);
|
||||
uuid = point.uuid;
|
||||
} else if (isSnapped.current && snappedPoint.current && line.current.length > 0) {
|
||||
intersectionPoint = snappedPoint.current;
|
||||
uuid = isSnappedUUID.current!;
|
||||
} else if (ispreSnapped.current && snappedPoint.current) {
|
||||
intersectionPoint = snappedPoint.current;
|
||||
uuid = isSnappedUUID.current!;
|
||||
} else {
|
||||
const point = addPointToScene(intersectionPoint, CONSTANTS.pointConfig.aisleOuterColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, undefined, CONSTANTS.lineConfig.aisleName);
|
||||
uuid = point.uuid;
|
||||
}
|
||||
(line.current as Types.Line).push([new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), uuid, activeLayer, CONSTANTS.lineConfig.aisleName,]);
|
||||
|
||||
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
|
||||
lines.current.push(line.current as Types.Line);
|
||||
|
||||
const data = arrayLineToObject(line.current as Types.Line);
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
//REST
|
||||
|
||||
// setLine(organization, data.layer!, data.line!, data.type!);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const input = {
|
||||
organization: organization,
|
||||
layer: data.layer,
|
||||
line: data.line,
|
||||
type: data.type,
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
socket.emit('v1:Line:create', input);
|
||||
|
||||
setNewLines([line.current]);
|
||||
|
||||
addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.pointConfig.aisleOuterColor, line.current, floorPlanGroupLine);
|
||||
let lastPoint = line.current[line.current.length - 1];
|
||||
line.current = [lastPoint];
|
||||
ispreSnapped.current = false;
|
||||
isSnapped.current = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (toolMode === 'Aisle') {
|
||||
canvasElement.addEventListener("mousedown", onMouseDown);
|
||||
canvasElement.addEventListener("mouseup", onMouseUp);
|
||||
canvasElement.addEventListener("mousemove", onMouseMove);
|
||||
canvasElement.addEventListener("click", onMouseClick);
|
||||
canvasElement.addEventListener("contextmenu", onContextMenu);
|
||||
}
|
||||
|
||||
return () => {
|
||||
canvasElement.removeEventListener("mousedown", onMouseDown);
|
||||
canvasElement.removeEventListener("mouseup", onMouseUp);
|
||||
canvasElement.removeEventListener("mousemove", onMouseMove);
|
||||
canvasElement.removeEventListener("click", onMouseClick);
|
||||
canvasElement.removeEventListener("contextmenu", onContextMenu);
|
||||
};
|
||||
}, [toolMode])
|
||||
|
||||
|
||||
return (
|
||||
<group ref={floorGroupAisle} visible={!toggleView} name="floorGroupAisle">
|
||||
</group>
|
||||
)
|
||||
}
|
||||
|
||||
import * as THREE from 'three';
|
||||
import * as Types from '../../../types/world/worldTypes';
|
||||
import * as CONSTANTS from '../../../types/world/worldConstants';
|
||||
import { useThree } from "@react-three/fiber";
|
||||
import { useToggleView, useActiveLayer, useSocketStore, useDeletePointOrLine, useMovePoint, useUpdateScene, useNewLines, useToolMode } from "../../../store/store";
|
||||
import { useEffect } from "react";
|
||||
import removeSoloPoint from "../geomentries/points/removeSoloPoint";
|
||||
import removeReferenceLine from "../geomentries/lines/removeReferenceLine";
|
||||
import getClosestIntersection from "../geomentries/lines/getClosestIntersection";
|
||||
import addPointToScene from "../geomentries/points/addPointToScene";
|
||||
import arrayLineToObject from '../geomentries/lines/lineConvertions/arrayLineToObject';
|
||||
import addLineToScene from "../geomentries/lines/addLineToScene";
|
||||
import loadAisles from '../geomentries/aisles/loadAisles';
|
||||
|
||||
|
||||
const FloorGroupAilse = ({ floorGroupAisle, plane, floorPlanGroupLine, floorPlanGroupPoint, line, lines, currentLayerPoint, dragPointControls, floorPlanGroup, ReferenceLineMesh, LineCreated, isSnapped, ispreSnapped, snappedPoint, isSnappedUUID, isAngleSnapped, anglesnappedPoint }: any) => {
|
||||
const { toggleView, setToggleView } = useToggleView();
|
||||
const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine();
|
||||
const { toolMode, setToolMode } = useToolMode();
|
||||
const { movePoint, setMovePoint } = useMovePoint();
|
||||
const { socket } = useSocketStore();
|
||||
const { activeLayer } = useActiveLayer();
|
||||
const { gl, raycaster, camera, pointer } = useThree();
|
||||
const { updateScene, setUpdateScene } = useUpdateScene();
|
||||
const { newLines, setNewLines } = useNewLines();
|
||||
|
||||
useEffect(() => {
|
||||
if (updateScene) {
|
||||
loadAisles(lines, floorGroupAisle);
|
||||
setUpdateScene(false);
|
||||
}
|
||||
}, [updateScene])
|
||||
|
||||
useEffect(() => {
|
||||
if (toolMode === "Aisle") {
|
||||
setDeletePointOrLine(false);
|
||||
setMovePoint(false);
|
||||
} else {
|
||||
removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint);
|
||||
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
|
||||
}
|
||||
}, [toolMode]);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
const canvasElement = gl.domElement;
|
||||
|
||||
let drag = false;
|
||||
let isLeftMouseDown = false;
|
||||
|
||||
const onMouseDown = (evt: any) => {
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown = true;
|
||||
drag = false;
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseUp = (evt: any) => {
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown = false;
|
||||
}
|
||||
}
|
||||
|
||||
const onMouseMove = () => {
|
||||
if (isLeftMouseDown) {
|
||||
drag = true;
|
||||
}
|
||||
};
|
||||
|
||||
const onContextMenu = (e: any) => {
|
||||
e.preventDefault();
|
||||
if (toolMode === "Aisle") {
|
||||
removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint);
|
||||
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseClick = (evt: any) => {
|
||||
if (!plane.current || drag) return;
|
||||
|
||||
const intersects = raycaster.intersectObject(plane.current, true);
|
||||
let intersectionPoint = intersects[0].point;
|
||||
const points = floorPlanGroupPoint.current?.children ?? [];
|
||||
const intersectsPoint = raycaster.intersectObjects(points, true).find(intersect => intersect.object.visible);
|
||||
let intersectsLines: any = raycaster.intersectObjects(floorPlanGroupLine.current.children, true);
|
||||
|
||||
|
||||
if (intersectsLines.length > 0 && intersects && intersects.length > 0 && !intersectsPoint) {
|
||||
const lineType = intersectsLines[0].object.userData.linePoints[0][3];
|
||||
if (lineType === CONSTANTS.lineConfig.aisleName) {
|
||||
// console.log("intersected a aisle line");
|
||||
const ThroughPoint = (intersectsLines[0].object.geometry.parameters.path).getPoints(CONSTANTS.lineConfig.lineIntersectionPoints);
|
||||
let intersection = getClosestIntersection(ThroughPoint, intersectionPoint);
|
||||
if (!intersection) return;
|
||||
const point = addPointToScene(intersection, CONSTANTS.pointConfig.aisleOuterColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, undefined, CONSTANTS.lineConfig.aisleName);
|
||||
(line.current as Types.Line).push([new THREE.Vector3(intersection.x, 0.01, intersection.z), point.uuid, activeLayer, CONSTANTS.lineConfig.aisleName,]);
|
||||
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
|
||||
lines.current.push(line.current as Types.Line);
|
||||
|
||||
const data = arrayLineToObject(line.current as Types.Line);
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
//REST
|
||||
|
||||
// setLine(organization, data.layer!, data.line!, data.type!);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const input = {
|
||||
organization: organization,
|
||||
layer: data.layer,
|
||||
line: data.line,
|
||||
type: data.type,
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
socket.emit('v1:Line:create', input);
|
||||
|
||||
setNewLines([line.current]);
|
||||
|
||||
addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.pointConfig.aisleOuterColor, line.current, floorPlanGroupLine);
|
||||
let lastPoint = line.current[line.current.length - 1];
|
||||
line.current = [lastPoint];
|
||||
}
|
||||
}
|
||||
} else if (intersectsPoint && intersects && intersects.length > 0) {
|
||||
if (intersectsPoint.object.userData.type === CONSTANTS.lineConfig.aisleName) {
|
||||
// console.log("intersected a aisle point");
|
||||
intersectionPoint = intersectsPoint.object.position;
|
||||
(line.current as Types.Line).push([new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), intersectsPoint.object.uuid, activeLayer, CONSTANTS.lineConfig.aisleName,]);
|
||||
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
|
||||
lines.current.push(line.current as Types.Line);
|
||||
|
||||
const data = arrayLineToObject(line.current as Types.Line);
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
//REST
|
||||
|
||||
// setLine(organization, data.layer!, data.line!, data.type!);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const input = {
|
||||
organization: organization,
|
||||
layer: data.layer,
|
||||
line: data.line,
|
||||
type: data.type,
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
socket.emit('v1:Line:create', input);
|
||||
|
||||
setNewLines([line.current]);
|
||||
|
||||
addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.pointConfig.aisleOuterColor, line.current, floorPlanGroupLine);
|
||||
let lastPoint = line.current[line.current.length - 1];
|
||||
line.current = [lastPoint];
|
||||
ispreSnapped.current = false;
|
||||
isSnapped.current = false;
|
||||
}
|
||||
}
|
||||
} else if (intersects && intersects.length > 0) {
|
||||
// console.log("intersected a empty area");
|
||||
let uuid: string = "";
|
||||
if (isAngleSnapped.current && anglesnappedPoint.current && line.current.length > 0) {
|
||||
intersectionPoint = anglesnappedPoint.current;
|
||||
const point = addPointToScene(intersectionPoint, CONSTANTS.pointConfig.aisleOuterColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, undefined, CONSTANTS.lineConfig.aisleName);
|
||||
uuid = point.uuid;
|
||||
} else if (isSnapped.current && snappedPoint.current && line.current.length > 0) {
|
||||
intersectionPoint = snappedPoint.current;
|
||||
uuid = isSnappedUUID.current!;
|
||||
} else if (ispreSnapped.current && snappedPoint.current) {
|
||||
intersectionPoint = snappedPoint.current;
|
||||
uuid = isSnappedUUID.current!;
|
||||
} else {
|
||||
const point = addPointToScene(intersectionPoint, CONSTANTS.pointConfig.aisleOuterColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, undefined, CONSTANTS.lineConfig.aisleName);
|
||||
uuid = point.uuid;
|
||||
}
|
||||
(line.current as Types.Line).push([new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), uuid, activeLayer, CONSTANTS.lineConfig.aisleName,]);
|
||||
|
||||
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
|
||||
lines.current.push(line.current as Types.Line);
|
||||
|
||||
const data = arrayLineToObject(line.current as Types.Line);
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
//REST
|
||||
|
||||
// setLine(organization, data.layer!, data.line!, data.type!);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const input = {
|
||||
organization: organization,
|
||||
layer: data.layer,
|
||||
line: data.line,
|
||||
type: data.type,
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
socket.emit('v1:Line:create', input);
|
||||
|
||||
setNewLines([line.current]);
|
||||
|
||||
addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.pointConfig.aisleOuterColor, line.current, floorPlanGroupLine);
|
||||
let lastPoint = line.current[line.current.length - 1];
|
||||
line.current = [lastPoint];
|
||||
ispreSnapped.current = false;
|
||||
isSnapped.current = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (toolMode === 'Aisle') {
|
||||
canvasElement.addEventListener("mousedown", onMouseDown);
|
||||
canvasElement.addEventListener("mouseup", onMouseUp);
|
||||
canvasElement.addEventListener("mousemove", onMouseMove);
|
||||
canvasElement.addEventListener("click", onMouseClick);
|
||||
canvasElement.addEventListener("contextmenu", onContextMenu);
|
||||
}
|
||||
|
||||
return () => {
|
||||
canvasElement.removeEventListener("mousedown", onMouseDown);
|
||||
canvasElement.removeEventListener("mouseup", onMouseUp);
|
||||
canvasElement.removeEventListener("mousemove", onMouseMove);
|
||||
canvasElement.removeEventListener("click", onMouseClick);
|
||||
canvasElement.removeEventListener("contextmenu", onContextMenu);
|
||||
};
|
||||
}, [toolMode])
|
||||
|
||||
|
||||
return (
|
||||
<group ref={floorGroupAisle} visible={!toggleView} name="floorGroupAisle">
|
||||
</group>
|
||||
)
|
||||
}
|
||||
|
||||
export default FloorGroupAilse;
|
||||
@@ -1,292 +1,292 @@
|
||||
import { useFrame, useThree } from "@react-three/fiber";
|
||||
import { useActiveTool, useCamMode, useDeletableFloorItem, useDeleteModels, useFloorItems, useRenderDistance, useselectedFloorItem, useSelectedItem, useSocketStore, useToggleView, useTransformMode } from "../../../store/store";
|
||||
import assetVisibility from "../geomentries/assets/assetVisibility";
|
||||
import { useEffect } from "react";
|
||||
import * as THREE from "three";
|
||||
import * as Types from "../../../types/world/worldTypes";
|
||||
import assetManager, { cancelOngoingTasks } from "../geomentries/assets/assetManager";
|
||||
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
|
||||
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
|
||||
import DeletableHoveredFloorItems from "../geomentries/assets/deletableHoveredFloorItems";
|
||||
import DeleteFloorItems from "../geomentries/assets/deleteFloorItems";
|
||||
import loadInitialFloorItems from "../../scene/IntialLoad/loadInitialFloorItems";
|
||||
import addAssetModel from "../geomentries/assets/addAssetModel";
|
||||
// import { getFloorItems } from "../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi";
|
||||
// import { retrieveGLTF } from "../../../utils/indexDB/idbUtils";
|
||||
const assetManagerWorker = new Worker(new URL('../../../services/factoryBuilder/webWorkers/assetManagerWorker.js', import.meta.url));
|
||||
// const gltfLoaderWorker = new Worker(new URL('../../../services/factoryBuilder/webWorkers/gltfLoaderWorker.js', import.meta.url));
|
||||
|
||||
const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject, floorGroup, tempLoader, isTempLoader, plane }: any) => {
|
||||
const state: Types.ThreeState = useThree();
|
||||
const { raycaster, camera, controls, pointer }: any = state;
|
||||
const { renderDistance, setRenderDistance } = useRenderDistance();
|
||||
const { toggleView, setToggleView } = useToggleView();
|
||||
const { floorItems, setFloorItems } = useFloorItems();
|
||||
const { camMode, setCamMode } = useCamMode();
|
||||
const { deleteModels, setDeleteModels } = useDeleteModels();
|
||||
const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem();
|
||||
const { transformMode, setTransformMode } = useTransformMode();
|
||||
const { selectedFloorItem, setselectedFloorItem } = useselectedFloorItem();
|
||||
const { activeTool, setActiveTool } = useActiveTool();
|
||||
const { selectedItem, setSelectedItem } = useSelectedItem();
|
||||
const { socket } = useSocketStore();
|
||||
|
||||
const loader = new GLTFLoader();
|
||||
const dracoLoader = new DRACOLoader();
|
||||
|
||||
dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/');
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
useEffect(() => {
|
||||
// Load initial floor items
|
||||
|
||||
// const email = localStorage.getItem('email');
|
||||
// const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
// getFloorItems(organization).then((data) => {
|
||||
// gltfLoaderWorker.postMessage({ FloorItems: data })
|
||||
// })
|
||||
|
||||
// gltfLoaderWorker.onmessage = async (event) => {
|
||||
// if (event.data.message === "gltfLoaded" && event.data.modelBlob) {
|
||||
// const blobUrl = URL.createObjectURL(event.data.modelBlob);
|
||||
|
||||
// loader.load(blobUrl, (gltf) => {
|
||||
// URL.revokeObjectURL(blobUrl);
|
||||
// THREE.Cache.remove(blobUrl);
|
||||
// THREE.Cache.add(event.data.modelID, gltf);
|
||||
// });
|
||||
|
||||
// } else if (event.data.message === "done") {
|
||||
// loadInitialFloorItems(itemsGroup, setFloorItems);
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
loadInitialFloorItems(itemsGroup, setFloorItems);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
assetManagerWorker.onmessage = async (event) => {
|
||||
cancelOngoingTasks(); // Cancel the ongoing process
|
||||
await assetManager(event.data, itemsGroup, loader);
|
||||
};
|
||||
}, [assetManagerWorker]);
|
||||
|
||||
useEffect(() => {
|
||||
if (toggleView) return
|
||||
|
||||
const uuids: string[] = [];
|
||||
itemsGroup.current?.children.forEach((child: any) => {
|
||||
uuids.push(child.uuid);
|
||||
});
|
||||
const cameraPosition = state.camera.position;
|
||||
|
||||
assetManagerWorker.postMessage({ floorItems, cameraPosition, uuids, renderDistance });
|
||||
}, [camMode, renderDistance]);
|
||||
|
||||
useEffect(() => {
|
||||
const controls: any = state.controls;
|
||||
const camera: any = state.camera;
|
||||
|
||||
if (controls) {
|
||||
let intervalId: NodeJS.Timeout | null = null;
|
||||
|
||||
const handleChange = () => {
|
||||
if (toggleView) return
|
||||
|
||||
const uuids: string[] = [];
|
||||
itemsGroup.current?.children.forEach((child: any) => {
|
||||
uuids.push(child.uuid);
|
||||
});
|
||||
const cameraPosition = camera.position;
|
||||
|
||||
assetManagerWorker.postMessage({ floorItems, cameraPosition, uuids, renderDistance });
|
||||
};
|
||||
|
||||
const startInterval = () => {
|
||||
if (!intervalId) {
|
||||
intervalId = setInterval(handleChange, 50);
|
||||
}
|
||||
};
|
||||
|
||||
const stopInterval = () => {
|
||||
handleChange();
|
||||
if (intervalId) {
|
||||
clearInterval(intervalId);
|
||||
intervalId = null;
|
||||
}
|
||||
};
|
||||
|
||||
controls.addEventListener('rest', handleChange);
|
||||
controls.addEventListener('rest', stopInterval);
|
||||
controls.addEventListener('control', startInterval);
|
||||
controls.addEventListener('controlend', stopInterval);
|
||||
|
||||
return () => {
|
||||
controls.removeEventListener('rest', handleChange);
|
||||
controls.removeEventListener('rest', stopInterval);
|
||||
controls.removeEventListener('control', startInterval);
|
||||
controls.removeEventListener('controlend', stopInterval);
|
||||
if (intervalId) {
|
||||
clearInterval(intervalId);
|
||||
}
|
||||
};
|
||||
}
|
||||
}, [state.controls, floorItems, toggleView, renderDistance]);
|
||||
|
||||
useEffect(() => {
|
||||
const canvasElement = state.gl.domElement;
|
||||
let drag = false;
|
||||
let isLeftMouseDown = false;
|
||||
|
||||
const onMouseDown = (evt: any) => {
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown = true;
|
||||
drag = false;
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseMove = () => {
|
||||
if (isLeftMouseDown) {
|
||||
drag = true;
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseUp = async (evt: any) => {
|
||||
if (controls) {
|
||||
(controls as any).enabled = true;
|
||||
}
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown = false;
|
||||
if (drag) return;
|
||||
|
||||
if (deleteModels) {
|
||||
DeleteFloorItems(itemsGroup, hoveredDeletableFloorItem, setFloorItems, socket);
|
||||
}
|
||||
const Mode = transformMode;
|
||||
|
||||
if (Mode !== null || activeTool === "Cursor") {
|
||||
if (!itemsGroup.current) return;
|
||||
let intersects = raycaster.intersectObjects(itemsGroup.current.children, true);
|
||||
if (intersects.length > 0 && intersects[0]?.object?.parent?.parent?.position && intersects[0]?.object?.parent?.parent?.scale && intersects[0]?.object?.parent?.parent?.rotation) {
|
||||
// let currentObject = intersects[0].object;
|
||||
|
||||
// while (currentObject) {
|
||||
// if (currentObject.name === "Scene") {
|
||||
// break;
|
||||
// }
|
||||
// currentObject = currentObject.parent as THREE.Object3D;
|
||||
// }
|
||||
// if (currentObject) {
|
||||
// AttachedObject.current = currentObject as any;
|
||||
// setselectedFloorItem(AttachedObject.current!);
|
||||
// }
|
||||
} else {
|
||||
const target = controls.getTarget(new THREE.Vector3());
|
||||
await controls.setTarget(target.x, 0, target.z, true);
|
||||
setselectedFloorItem(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onDblClick = async (evt: any) => {
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown = false;
|
||||
if (drag) return;
|
||||
|
||||
const Mode = transformMode;
|
||||
|
||||
if (Mode !== null || activeTool === "Cursor") {
|
||||
if (!itemsGroup.current) return;
|
||||
let intersects = raycaster.intersectObjects(itemsGroup.current.children, true);
|
||||
if (intersects.length > 0 && intersects[0]?.object?.parent?.parent?.position && intersects[0]?.object?.parent?.parent?.scale && intersects[0]?.object?.parent?.parent?.rotation) {
|
||||
let currentObject = intersects[0].object;
|
||||
|
||||
while (currentObject) {
|
||||
if (currentObject.name === "Scene") {
|
||||
break;
|
||||
}
|
||||
currentObject = currentObject.parent as THREE.Object3D;
|
||||
}
|
||||
if (currentObject) {
|
||||
AttachedObject.current = currentObject as any;
|
||||
// controls.fitToSphere(AttachedObject.current!, true);
|
||||
|
||||
const bbox = new THREE.Box3().setFromObject(AttachedObject.current);
|
||||
const size = bbox.getSize(new THREE.Vector3());
|
||||
const center = bbox.getCenter(new THREE.Vector3());
|
||||
|
||||
const front = new THREE.Vector3(0, 0, 1);
|
||||
AttachedObject.current.localToWorld(front);
|
||||
front.sub(AttachedObject.current.position).normalize();
|
||||
|
||||
const distance = Math.max(size.x, size.y, size.z) * 2;
|
||||
const newPosition = center.clone().addScaledVector(front, distance);
|
||||
|
||||
controls.setPosition(newPosition.x, newPosition.y, newPosition.z, true);
|
||||
controls.setTarget(center.x, center.y, center.z, true);
|
||||
controls.fitToBox(AttachedObject.current!, true, { cover: true, paddingTop: 5, paddingLeft: 5, paddingBottom: 5, paddingRight: 5 });
|
||||
|
||||
setselectedFloorItem(AttachedObject.current!);
|
||||
}
|
||||
} else {
|
||||
const target = controls.getTarget(new THREE.Vector3());
|
||||
await controls.setTarget(target.x, 0, target.z, true);
|
||||
setselectedFloorItem(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const onDrop = (event: any) => {
|
||||
|
||||
if (!event.dataTransfer?.files[0]) return;
|
||||
|
||||
if (selectedItem.id !== "" && event.dataTransfer?.files[0]) {
|
||||
addAssetModel(raycaster, state.camera, state.pointer, floorGroup, setFloorItems, itemsGroup, isTempLoader, tempLoader, socket, selectedItem, setSelectedItem, plane);
|
||||
}
|
||||
}
|
||||
|
||||
const onDragOver = (event: any) => {
|
||||
event.preventDefault();
|
||||
};
|
||||
|
||||
canvasElement.addEventListener("mousedown", onMouseDown);
|
||||
canvasElement.addEventListener("mouseup", onMouseUp);
|
||||
canvasElement.addEventListener("mousemove", onMouseMove);
|
||||
canvasElement.addEventListener("dblclick", onDblClick);
|
||||
canvasElement.addEventListener("drop", onDrop);
|
||||
canvasElement.addEventListener("dragover", onDragOver);
|
||||
|
||||
return () => {
|
||||
canvasElement.removeEventListener("mousedown", onMouseDown);
|
||||
canvasElement.removeEventListener("mouseup", onMouseUp);
|
||||
canvasElement.removeEventListener("mousemove", onMouseMove);
|
||||
canvasElement.removeEventListener("dblclick", onDblClick);
|
||||
canvasElement.removeEventListener("drop", onDrop);
|
||||
canvasElement.removeEventListener("dragover", onDragOver);
|
||||
};
|
||||
}, [deleteModels, transformMode, controls, selectedItem, state.camera, state.pointer, activeTool]);
|
||||
|
||||
useFrame(() => {
|
||||
if (controls)
|
||||
assetVisibility(itemsGroup, state.camera.position, renderDistance);
|
||||
if (deleteModels) {
|
||||
DeletableHoveredFloorItems(state, itemsGroup, hoveredDeletableFloorItem, setDeletableFloorItem);
|
||||
} else if (!deleteModels) {
|
||||
if (hoveredDeletableFloorItem.current) {
|
||||
hoveredDeletableFloorItem.current = undefined;
|
||||
setDeletableFloorItem(null);
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
<group ref={itemsGroup} name="itemsGroup">
|
||||
</group>
|
||||
)
|
||||
}
|
||||
|
||||
import { useFrame, useThree } from "@react-three/fiber";
|
||||
import { useActiveTool, useCamMode, useDeletableFloorItem, useDeleteModels, useFloorItems, useRenderDistance, useselectedFloorItem, useSelectedItem, useSocketStore, useToggleView, useTransformMode } from "../../../store/store";
|
||||
import assetVisibility from "../geomentries/assets/assetVisibility";
|
||||
import { useEffect } from "react";
|
||||
import * as THREE from "three";
|
||||
import * as Types from "../../../types/world/worldTypes";
|
||||
import assetManager, { cancelOngoingTasks } from "../geomentries/assets/assetManager";
|
||||
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
|
||||
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
|
||||
import DeletableHoveredFloorItems from "../geomentries/assets/deletableHoveredFloorItems";
|
||||
import DeleteFloorItems from "../geomentries/assets/deleteFloorItems";
|
||||
import loadInitialFloorItems from "../../scene/IntialLoad/loadInitialFloorItems";
|
||||
import addAssetModel from "../geomentries/assets/addAssetModel";
|
||||
// import { getFloorItems } from "../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi";
|
||||
// import { retrieveGLTF } from "../../../utils/indexDB/idbUtils";
|
||||
const assetManagerWorker = new Worker(new URL('../../../services/factoryBuilder/webWorkers/assetManagerWorker.js', import.meta.url));
|
||||
// const gltfLoaderWorker = new Worker(new URL('../../../services/factoryBuilder/webWorkers/gltfLoaderWorker.js', import.meta.url));
|
||||
|
||||
const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject, floorGroup, tempLoader, isTempLoader, plane }: any) => {
|
||||
const state: Types.ThreeState = useThree();
|
||||
const { raycaster, camera, controls, pointer }: any = state;
|
||||
const { renderDistance, setRenderDistance } = useRenderDistance();
|
||||
const { toggleView, setToggleView } = useToggleView();
|
||||
const { floorItems, setFloorItems } = useFloorItems();
|
||||
const { camMode, setCamMode } = useCamMode();
|
||||
const { deleteModels, setDeleteModels } = useDeleteModels();
|
||||
const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem();
|
||||
const { transformMode, setTransformMode } = useTransformMode();
|
||||
const { selectedFloorItem, setselectedFloorItem } = useselectedFloorItem();
|
||||
const { activeTool, setActiveTool } = useActiveTool();
|
||||
const { selectedItem, setSelectedItem } = useSelectedItem();
|
||||
const { socket } = useSocketStore();
|
||||
|
||||
const loader = new GLTFLoader();
|
||||
const dracoLoader = new DRACOLoader();
|
||||
|
||||
dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/');
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
useEffect(() => {
|
||||
// Load initial floor items
|
||||
|
||||
// const email = localStorage.getItem('email');
|
||||
// const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
// getFloorItems(organization).then((data) => {
|
||||
// gltfLoaderWorker.postMessage({ FloorItems: data })
|
||||
// })
|
||||
|
||||
// gltfLoaderWorker.onmessage = async (event) => {
|
||||
// if (event.data.message === "gltfLoaded" && event.data.modelBlob) {
|
||||
// const blobUrl = URL.createObjectURL(event.data.modelBlob);
|
||||
|
||||
// loader.load(blobUrl, (gltf) => {
|
||||
// URL.revokeObjectURL(blobUrl);
|
||||
// THREE.Cache.remove(blobUrl);
|
||||
// THREE.Cache.add(event.data.modelID, gltf);
|
||||
// });
|
||||
|
||||
// } else if (event.data.message === "done") {
|
||||
// loadInitialFloorItems(itemsGroup, setFloorItems);
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
loadInitialFloorItems(itemsGroup, setFloorItems);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
assetManagerWorker.onmessage = async (event) => {
|
||||
cancelOngoingTasks(); // Cancel the ongoing process
|
||||
await assetManager(event.data, itemsGroup, loader);
|
||||
};
|
||||
}, [assetManagerWorker]);
|
||||
|
||||
useEffect(() => {
|
||||
if (toggleView) return
|
||||
|
||||
const uuids: string[] = [];
|
||||
itemsGroup.current?.children.forEach((child: any) => {
|
||||
uuids.push(child.uuid);
|
||||
});
|
||||
const cameraPosition = state.camera.position;
|
||||
|
||||
assetManagerWorker.postMessage({ floorItems, cameraPosition, uuids, renderDistance });
|
||||
}, [camMode, renderDistance]);
|
||||
|
||||
useEffect(() => {
|
||||
const controls: any = state.controls;
|
||||
const camera: any = state.camera;
|
||||
|
||||
if (controls) {
|
||||
let intervalId: NodeJS.Timeout | null = null;
|
||||
|
||||
const handleChange = () => {
|
||||
if (toggleView) return
|
||||
|
||||
const uuids: string[] = [];
|
||||
itemsGroup.current?.children.forEach((child: any) => {
|
||||
uuids.push(child.uuid);
|
||||
});
|
||||
const cameraPosition = camera.position;
|
||||
|
||||
assetManagerWorker.postMessage({ floorItems, cameraPosition, uuids, renderDistance });
|
||||
};
|
||||
|
||||
const startInterval = () => {
|
||||
if (!intervalId) {
|
||||
intervalId = setInterval(handleChange, 50);
|
||||
}
|
||||
};
|
||||
|
||||
const stopInterval = () => {
|
||||
handleChange();
|
||||
if (intervalId) {
|
||||
clearInterval(intervalId);
|
||||
intervalId = null;
|
||||
}
|
||||
};
|
||||
|
||||
controls.addEventListener('rest', handleChange);
|
||||
controls.addEventListener('rest', stopInterval);
|
||||
controls.addEventListener('control', startInterval);
|
||||
controls.addEventListener('controlend', stopInterval);
|
||||
|
||||
return () => {
|
||||
controls.removeEventListener('rest', handleChange);
|
||||
controls.removeEventListener('rest', stopInterval);
|
||||
controls.removeEventListener('control', startInterval);
|
||||
controls.removeEventListener('controlend', stopInterval);
|
||||
if (intervalId) {
|
||||
clearInterval(intervalId);
|
||||
}
|
||||
};
|
||||
}
|
||||
}, [state.controls, floorItems, toggleView, renderDistance]);
|
||||
|
||||
useEffect(() => {
|
||||
const canvasElement = state.gl.domElement;
|
||||
let drag = false;
|
||||
let isLeftMouseDown = false;
|
||||
|
||||
const onMouseDown = (evt: any) => {
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown = true;
|
||||
drag = false;
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseMove = () => {
|
||||
if (isLeftMouseDown) {
|
||||
drag = true;
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseUp = async (evt: any) => {
|
||||
if (controls) {
|
||||
(controls as any).enabled = true;
|
||||
}
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown = false;
|
||||
if (drag) return;
|
||||
|
||||
if (deleteModels) {
|
||||
DeleteFloorItems(itemsGroup, hoveredDeletableFloorItem, setFloorItems, socket);
|
||||
}
|
||||
const Mode = transformMode;
|
||||
|
||||
if (Mode !== null || activeTool === "Cursor") {
|
||||
if (!itemsGroup.current) return;
|
||||
let intersects = raycaster.intersectObjects(itemsGroup.current.children, true);
|
||||
if (intersects.length > 0 && intersects[0]?.object?.parent?.parent?.position && intersects[0]?.object?.parent?.parent?.scale && intersects[0]?.object?.parent?.parent?.rotation) {
|
||||
// let currentObject = intersects[0].object;
|
||||
|
||||
// while (currentObject) {
|
||||
// if (currentObject.name === "Scene") {
|
||||
// break;
|
||||
// }
|
||||
// currentObject = currentObject.parent as THREE.Object3D;
|
||||
// }
|
||||
// if (currentObject) {
|
||||
// AttachedObject.current = currentObject as any;
|
||||
// setselectedFloorItem(AttachedObject.current!);
|
||||
// }
|
||||
} else {
|
||||
const target = controls.getTarget(new THREE.Vector3());
|
||||
await controls.setTarget(target.x, 0, target.z, true);
|
||||
setselectedFloorItem(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onDblClick = async (evt: any) => {
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown = false;
|
||||
if (drag) return;
|
||||
|
||||
const Mode = transformMode;
|
||||
|
||||
if (Mode !== null || activeTool === "Cursor") {
|
||||
if (!itemsGroup.current) return;
|
||||
let intersects = raycaster.intersectObjects(itemsGroup.current.children, true);
|
||||
if (intersects.length > 0 && intersects[0]?.object?.parent?.parent?.position && intersects[0]?.object?.parent?.parent?.scale && intersects[0]?.object?.parent?.parent?.rotation) {
|
||||
let currentObject = intersects[0].object;
|
||||
|
||||
while (currentObject) {
|
||||
if (currentObject.name === "Scene") {
|
||||
break;
|
||||
}
|
||||
currentObject = currentObject.parent as THREE.Object3D;
|
||||
}
|
||||
if (currentObject) {
|
||||
AttachedObject.current = currentObject as any;
|
||||
// controls.fitToSphere(AttachedObject.current!, true);
|
||||
|
||||
const bbox = new THREE.Box3().setFromObject(AttachedObject.current);
|
||||
const size = bbox.getSize(new THREE.Vector3());
|
||||
const center = bbox.getCenter(new THREE.Vector3());
|
||||
|
||||
const front = new THREE.Vector3(0, 0, 1);
|
||||
AttachedObject.current.localToWorld(front);
|
||||
front.sub(AttachedObject.current.position).normalize();
|
||||
|
||||
const distance = Math.max(size.x, size.y, size.z) * 2;
|
||||
const newPosition = center.clone().addScaledVector(front, distance);
|
||||
|
||||
controls.setPosition(newPosition.x, newPosition.y, newPosition.z, true);
|
||||
controls.setTarget(center.x, center.y, center.z, true);
|
||||
controls.fitToBox(AttachedObject.current!, true, { cover: true, paddingTop: 5, paddingLeft: 5, paddingBottom: 5, paddingRight: 5 });
|
||||
|
||||
setselectedFloorItem(AttachedObject.current!);
|
||||
}
|
||||
} else {
|
||||
const target = controls.getTarget(new THREE.Vector3());
|
||||
await controls.setTarget(target.x, 0, target.z, true);
|
||||
setselectedFloorItem(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const onDrop = (event: any) => {
|
||||
|
||||
if (!event.dataTransfer?.files[0]) return;
|
||||
|
||||
if (selectedItem.id !== "" && event.dataTransfer?.files[0]) {
|
||||
addAssetModel(raycaster, state.camera, state.pointer, floorGroup, setFloorItems, itemsGroup, isTempLoader, tempLoader, socket, selectedItem, setSelectedItem, plane);
|
||||
}
|
||||
}
|
||||
|
||||
const onDragOver = (event: any) => {
|
||||
event.preventDefault();
|
||||
};
|
||||
|
||||
canvasElement.addEventListener("mousedown", onMouseDown);
|
||||
canvasElement.addEventListener("mouseup", onMouseUp);
|
||||
canvasElement.addEventListener("mousemove", onMouseMove);
|
||||
canvasElement.addEventListener("dblclick", onDblClick);
|
||||
canvasElement.addEventListener("drop", onDrop);
|
||||
canvasElement.addEventListener("dragover", onDragOver);
|
||||
|
||||
return () => {
|
||||
canvasElement.removeEventListener("mousedown", onMouseDown);
|
||||
canvasElement.removeEventListener("mouseup", onMouseUp);
|
||||
canvasElement.removeEventListener("mousemove", onMouseMove);
|
||||
canvasElement.removeEventListener("dblclick", onDblClick);
|
||||
canvasElement.removeEventListener("drop", onDrop);
|
||||
canvasElement.removeEventListener("dragover", onDragOver);
|
||||
};
|
||||
}, [deleteModels, transformMode, controls, selectedItem, state.camera, state.pointer, activeTool]);
|
||||
|
||||
useFrame(() => {
|
||||
if (controls)
|
||||
assetVisibility(itemsGroup, state.camera.position, renderDistance);
|
||||
if (deleteModels) {
|
||||
DeletableHoveredFloorItems(state, itemsGroup, hoveredDeletableFloorItem, setDeletableFloorItem);
|
||||
} else if (!deleteModels) {
|
||||
if (hoveredDeletableFloorItem.current) {
|
||||
hoveredDeletableFloorItem.current = undefined;
|
||||
setDeletableFloorItem(null);
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
<group ref={itemsGroup} name="itemsGroup">
|
||||
</group>
|
||||
)
|
||||
}
|
||||
|
||||
export default FloorItemsGroup;
|
||||
@@ -1,197 +1,197 @@
|
||||
import { useEffect } from "react";
|
||||
import * as Types from '../../../types/world/worldTypes';
|
||||
import { useActiveLayer, useDeletedLines, useDeletePointOrLine, useToolMode, useMovePoint, useNewLines, useRemovedLayer, useSocketStore, useToggleView, useUpdateScene } from "../../../store/store";
|
||||
import Layer2DVisibility from "../geomentries/layers/layer2DVisibility";
|
||||
import { useFrame, useThree } from "@react-three/fiber";
|
||||
import DeletableLineorPoint from "../functions/deletableLineOrPoint";
|
||||
import removeSoloPoint from "../geomentries/points/removeSoloPoint";
|
||||
import removeReferenceLine from "../geomentries/lines/removeReferenceLine";
|
||||
import DeleteLayer from "../geomentries/layers/deleteLayer";
|
||||
import { getLines } from "../../../services/factoryBuilder/lines/getLinesApi";
|
||||
import objectLinesToArray from "../geomentries/lines/lineConvertions/objectLinesToArray";
|
||||
import loadInitialPoint from "../../scene/IntialLoad/loadInitialPoint";
|
||||
import loadInitialLine from "../../scene/IntialLoad/loadInitialLine";
|
||||
import deletePoint from "../geomentries/points/deletePoint";
|
||||
import deleteLine from "../geomentries/lines/deleteLine";
|
||||
import drawWall from "../geomentries/lines/drawWall";
|
||||
import drawOnlyFloor from "../geomentries/floors/drawOnlyFloor";
|
||||
import addDragControl from "../eventDeclaration/dragControlDeclaration";
|
||||
|
||||
|
||||
const FloorPlanGroup = ({ floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoint, floorGroup, currentLayerPoint, dragPointControls, hoveredDeletablePoint, hoveredDeletableLine, plane, line, lines, onlyFloorline, onlyFloorlines, ReferenceLineMesh, LineCreated, isSnapped, ispreSnapped, snappedPoint, isSnappedUUID, isAngleSnapped, anglesnappedPoint }: any) => {
|
||||
const state = useThree();
|
||||
const { scene, camera, gl, raycaster, controls } = state;
|
||||
const { activeLayer, setActiveLayer } = useActiveLayer();
|
||||
const { toggleView, setToggleView } = useToggleView();
|
||||
const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine();
|
||||
const { toolMode, setToolMode } = useToolMode();
|
||||
const { movePoint, setMovePoint } = useMovePoint();
|
||||
const { removedLayer, setRemovedLayer } = useRemovedLayer();
|
||||
const { updateScene, setUpdateScene } = useUpdateScene();
|
||||
const { newLines, setNewLines } = useNewLines();
|
||||
const { deletedLines, setDeletedLines } = useDeletedLines();
|
||||
const { socket } = useSocketStore();
|
||||
|
||||
useEffect(() => {
|
||||
addDragControl(dragPointControls, currentLayerPoint, state, floorPlanGroupPoint, floorPlanGroupLine, lines, onlyFloorlines, socket);
|
||||
}, [state]);
|
||||
|
||||
useEffect(() => {
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
// Load data from localStorage if available
|
||||
getLines(organization).then((data) => {
|
||||
|
||||
const Lines: Types.Lines = objectLinesToArray(data);
|
||||
|
||||
// const data = localStorage.getItem("Lines");
|
||||
|
||||
if (Lines) {
|
||||
lines.current = Lines;
|
||||
loadInitialPoint(lines, floorPlanGroupPoint, currentLayerPoint, dragPointControls);
|
||||
loadInitialLine(floorPlanGroupLine, lines);
|
||||
setUpdateScene(true);
|
||||
}
|
||||
})
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!toggleView) {
|
||||
removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint);
|
||||
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
|
||||
}
|
||||
}, [toggleView]);
|
||||
|
||||
useEffect(() => {
|
||||
if (toolMode === "Wall" || toolMode === "Floor") {
|
||||
setDeletePointOrLine(false);
|
||||
setMovePoint(false);
|
||||
} else {
|
||||
removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint);
|
||||
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
|
||||
}
|
||||
}, [toolMode]);
|
||||
|
||||
useEffect(() => {
|
||||
if (movePoint) {
|
||||
setToolMode(null);
|
||||
setDeletePointOrLine(false);
|
||||
if (dragPointControls.current) {
|
||||
dragPointControls.current.enabled = true;
|
||||
}
|
||||
} else {
|
||||
if (dragPointControls.current) {
|
||||
dragPointControls.current.enabled = false;
|
||||
}
|
||||
}
|
||||
}, [movePoint, toolMode]);
|
||||
|
||||
useEffect(() => {
|
||||
if (deletePointOrLine) {
|
||||
setToolMode(null);
|
||||
setMovePoint(false);
|
||||
}
|
||||
}, [deletePointOrLine]);
|
||||
|
||||
useEffect(() => {
|
||||
Layer2DVisibility(activeLayer, floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoint, currentLayerPoint, dragPointControls);
|
||||
}, [activeLayer]);
|
||||
|
||||
useEffect(() => {
|
||||
if (removedLayer !== null) {
|
||||
DeleteLayer(removedLayer, lines, floorPlanGroupLine, floorPlanGroupPoint, onlyFloorlines, floorGroup, setDeletedLines, setRemovedLayer, socket);
|
||||
}
|
||||
}, [removedLayer]);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
const canvasElement = gl.domElement;
|
||||
|
||||
let drag = false;
|
||||
let isLeftMouseDown = false;
|
||||
|
||||
const onMouseDown = (evt: any) => {
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown = true;
|
||||
drag = false;
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseUp = (evt: any) => {
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown = false;
|
||||
}
|
||||
if (controls) {
|
||||
(controls as any).enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
const onMouseMove = () => {
|
||||
if (isLeftMouseDown) {
|
||||
drag = true;
|
||||
}
|
||||
};
|
||||
|
||||
const onContextMenu = (e: any) => {
|
||||
e.preventDefault();
|
||||
if (toolMode === "Wall" || toolMode === "Floor") {
|
||||
removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint);
|
||||
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseClick = (evt: any) => {
|
||||
if (!plane.current || drag) return;
|
||||
|
||||
if (deletePointOrLine) {
|
||||
if (hoveredDeletablePoint.current !== null) {
|
||||
deletePoint(hoveredDeletablePoint, onlyFloorlines, floorPlanGroupPoint, floorPlanGroupLine, lines, setDeletedLines, socket);
|
||||
}
|
||||
if (hoveredDeletableLine.current !== null) {
|
||||
deleteLine(hoveredDeletableLine, onlyFloorlines, lines, floorPlanGroupLine, floorPlanGroupPoint, setDeletedLines, socket);
|
||||
}
|
||||
}
|
||||
|
||||
if (toolMode === "Wall") {
|
||||
drawWall(raycaster, plane, floorPlanGroupPoint, snappedPoint, isSnapped, isSnappedUUID, line, ispreSnapped, anglesnappedPoint, isAngleSnapped, lines, floorPlanGroupLine, floorPlanGroup, ReferenceLineMesh, LineCreated, currentLayerPoint, dragPointControls, setNewLines, setDeletedLines, activeLayer, socket);
|
||||
}
|
||||
|
||||
if (toolMode === "Floor") {
|
||||
drawOnlyFloor(raycaster, state, camera, plane, floorPlanGroupPoint, snappedPoint, isSnapped, isSnappedUUID, line, ispreSnapped, anglesnappedPoint, isAngleSnapped, onlyFloorline, onlyFloorlines, lines, floorPlanGroupLine, floorPlanGroup, ReferenceLineMesh, LineCreated, currentLayerPoint, dragPointControls, setNewLines, setDeletedLines, activeLayer, socket);
|
||||
}
|
||||
}
|
||||
|
||||
if (deletePointOrLine || toolMode === "Wall" || toolMode === "Floor") {
|
||||
canvasElement.addEventListener("mousedown", onMouseDown);
|
||||
canvasElement.addEventListener("mouseup", onMouseUp);
|
||||
canvasElement.addEventListener("mousemove", onMouseMove);
|
||||
canvasElement.addEventListener("click", onMouseClick);
|
||||
canvasElement.addEventListener("contextmenu", onContextMenu);
|
||||
}
|
||||
|
||||
return () => {
|
||||
canvasElement.removeEventListener("mousedown", onMouseDown);
|
||||
canvasElement.removeEventListener("mouseup", onMouseUp);
|
||||
canvasElement.removeEventListener("mousemove", onMouseMove);
|
||||
canvasElement.removeEventListener("click", onMouseClick);
|
||||
canvasElement.removeEventListener("contextmenu", onContextMenu);
|
||||
};
|
||||
}, [deletePointOrLine, toolMode, activeLayer])
|
||||
|
||||
|
||||
useFrame(() => {
|
||||
if (deletePointOrLine) {
|
||||
DeletableLineorPoint(state, plane, floorPlanGroupLine, floorPlanGroupPoint, hoveredDeletableLine, hoveredDeletablePoint);
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
<group ref={floorPlanGroup} visible={toggleView} name="floorPlanGroup">
|
||||
<group ref={floorPlanGroupLine} name="floorPlanGroupLine"></group>
|
||||
<group ref={floorPlanGroupPoint} name="floorPlanGroupPoint"></group>
|
||||
</group>
|
||||
)
|
||||
}
|
||||
|
||||
import { useEffect } from "react";
|
||||
import * as Types from '../../../types/world/worldTypes';
|
||||
import { useActiveLayer, useDeletedLines, useDeletePointOrLine, useToolMode, useMovePoint, useNewLines, useRemovedLayer, useSocketStore, useToggleView, useUpdateScene } from "../../../store/store";
|
||||
import Layer2DVisibility from "../geomentries/layers/layer2DVisibility";
|
||||
import { useFrame, useThree } from "@react-three/fiber";
|
||||
import DeletableLineorPoint from "../functions/deletableLineOrPoint";
|
||||
import removeSoloPoint from "../geomentries/points/removeSoloPoint";
|
||||
import removeReferenceLine from "../geomentries/lines/removeReferenceLine";
|
||||
import DeleteLayer from "../geomentries/layers/deleteLayer";
|
||||
import { getLines } from "../../../services/factoryBuilder/lines/getLinesApi";
|
||||
import objectLinesToArray from "../geomentries/lines/lineConvertions/objectLinesToArray";
|
||||
import loadInitialPoint from "../../scene/IntialLoad/loadInitialPoint";
|
||||
import loadInitialLine from "../../scene/IntialLoad/loadInitialLine";
|
||||
import deletePoint from "../geomentries/points/deletePoint";
|
||||
import deleteLine from "../geomentries/lines/deleteLine";
|
||||
import drawWall from "../geomentries/lines/drawWall";
|
||||
import drawOnlyFloor from "../geomentries/floors/drawOnlyFloor";
|
||||
import addDragControl from "../eventDeclaration/dragControlDeclaration";
|
||||
|
||||
|
||||
const FloorPlanGroup = ({ floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoint, floorGroup, currentLayerPoint, dragPointControls, hoveredDeletablePoint, hoveredDeletableLine, plane, line, lines, onlyFloorline, onlyFloorlines, ReferenceLineMesh, LineCreated, isSnapped, ispreSnapped, snappedPoint, isSnappedUUID, isAngleSnapped, anglesnappedPoint }: any) => {
|
||||
const state = useThree();
|
||||
const { scene, camera, gl, raycaster, controls } = state;
|
||||
const { activeLayer, setActiveLayer } = useActiveLayer();
|
||||
const { toggleView, setToggleView } = useToggleView();
|
||||
const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine();
|
||||
const { toolMode, setToolMode } = useToolMode();
|
||||
const { movePoint, setMovePoint } = useMovePoint();
|
||||
const { removedLayer, setRemovedLayer } = useRemovedLayer();
|
||||
const { updateScene, setUpdateScene } = useUpdateScene();
|
||||
const { newLines, setNewLines } = useNewLines();
|
||||
const { deletedLines, setDeletedLines } = useDeletedLines();
|
||||
const { socket } = useSocketStore();
|
||||
|
||||
useEffect(() => {
|
||||
addDragControl(dragPointControls, currentLayerPoint, state, floorPlanGroupPoint, floorPlanGroupLine, lines, onlyFloorlines, socket);
|
||||
}, [state]);
|
||||
|
||||
useEffect(() => {
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
// Load data from localStorage if available
|
||||
getLines(organization).then((data) => {
|
||||
|
||||
const Lines: Types.Lines = objectLinesToArray(data);
|
||||
|
||||
// const data = localStorage.getItem("Lines");
|
||||
|
||||
if (Lines) {
|
||||
lines.current = Lines;
|
||||
loadInitialPoint(lines, floorPlanGroupPoint, currentLayerPoint, dragPointControls);
|
||||
loadInitialLine(floorPlanGroupLine, lines);
|
||||
setUpdateScene(true);
|
||||
}
|
||||
})
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!toggleView) {
|
||||
removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint);
|
||||
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
|
||||
}
|
||||
}, [toggleView]);
|
||||
|
||||
useEffect(() => {
|
||||
if (toolMode === "Wall" || toolMode === "Floor") {
|
||||
setDeletePointOrLine(false);
|
||||
setMovePoint(false);
|
||||
} else {
|
||||
removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint);
|
||||
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
|
||||
}
|
||||
}, [toolMode]);
|
||||
|
||||
useEffect(() => {
|
||||
if (movePoint) {
|
||||
setToolMode(null);
|
||||
setDeletePointOrLine(false);
|
||||
if (dragPointControls.current) {
|
||||
dragPointControls.current.enabled = true;
|
||||
}
|
||||
} else {
|
||||
if (dragPointControls.current) {
|
||||
dragPointControls.current.enabled = false;
|
||||
}
|
||||
}
|
||||
}, [movePoint, toolMode]);
|
||||
|
||||
useEffect(() => {
|
||||
if (deletePointOrLine) {
|
||||
setToolMode(null);
|
||||
setMovePoint(false);
|
||||
}
|
||||
}, [deletePointOrLine]);
|
||||
|
||||
useEffect(() => {
|
||||
Layer2DVisibility(activeLayer, floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoint, currentLayerPoint, dragPointControls);
|
||||
}, [activeLayer]);
|
||||
|
||||
useEffect(() => {
|
||||
if (removedLayer !== null) {
|
||||
DeleteLayer(removedLayer, lines, floorPlanGroupLine, floorPlanGroupPoint, onlyFloorlines, floorGroup, setDeletedLines, setRemovedLayer, socket);
|
||||
}
|
||||
}, [removedLayer]);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
const canvasElement = gl.domElement;
|
||||
|
||||
let drag = false;
|
||||
let isLeftMouseDown = false;
|
||||
|
||||
const onMouseDown = (evt: any) => {
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown = true;
|
||||
drag = false;
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseUp = (evt: any) => {
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown = false;
|
||||
}
|
||||
if (controls) {
|
||||
(controls as any).enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
const onMouseMove = () => {
|
||||
if (isLeftMouseDown) {
|
||||
drag = true;
|
||||
}
|
||||
};
|
||||
|
||||
const onContextMenu = (e: any) => {
|
||||
e.preventDefault();
|
||||
if (toolMode === "Wall" || toolMode === "Floor") {
|
||||
removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint);
|
||||
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseClick = (evt: any) => {
|
||||
if (!plane.current || drag) return;
|
||||
|
||||
if (deletePointOrLine) {
|
||||
if (hoveredDeletablePoint.current !== null) {
|
||||
deletePoint(hoveredDeletablePoint, onlyFloorlines, floorPlanGroupPoint, floorPlanGroupLine, lines, setDeletedLines, socket);
|
||||
}
|
||||
if (hoveredDeletableLine.current !== null) {
|
||||
deleteLine(hoveredDeletableLine, onlyFloorlines, lines, floorPlanGroupLine, floorPlanGroupPoint, setDeletedLines, socket);
|
||||
}
|
||||
}
|
||||
|
||||
if (toolMode === "Wall") {
|
||||
drawWall(raycaster, plane, floorPlanGroupPoint, snappedPoint, isSnapped, isSnappedUUID, line, ispreSnapped, anglesnappedPoint, isAngleSnapped, lines, floorPlanGroupLine, floorPlanGroup, ReferenceLineMesh, LineCreated, currentLayerPoint, dragPointControls, setNewLines, setDeletedLines, activeLayer, socket);
|
||||
}
|
||||
|
||||
if (toolMode === "Floor") {
|
||||
drawOnlyFloor(raycaster, state, camera, plane, floorPlanGroupPoint, snappedPoint, isSnapped, isSnappedUUID, line, ispreSnapped, anglesnappedPoint, isAngleSnapped, onlyFloorline, onlyFloorlines, lines, floorPlanGroupLine, floorPlanGroup, ReferenceLineMesh, LineCreated, currentLayerPoint, dragPointControls, setNewLines, setDeletedLines, activeLayer, socket);
|
||||
}
|
||||
}
|
||||
|
||||
if (deletePointOrLine || toolMode === "Wall" || toolMode === "Floor") {
|
||||
canvasElement.addEventListener("mousedown", onMouseDown);
|
||||
canvasElement.addEventListener("mouseup", onMouseUp);
|
||||
canvasElement.addEventListener("mousemove", onMouseMove);
|
||||
canvasElement.addEventListener("click", onMouseClick);
|
||||
canvasElement.addEventListener("contextmenu", onContextMenu);
|
||||
}
|
||||
|
||||
return () => {
|
||||
canvasElement.removeEventListener("mousedown", onMouseDown);
|
||||
canvasElement.removeEventListener("mouseup", onMouseUp);
|
||||
canvasElement.removeEventListener("mousemove", onMouseMove);
|
||||
canvasElement.removeEventListener("click", onMouseClick);
|
||||
canvasElement.removeEventListener("contextmenu", onContextMenu);
|
||||
};
|
||||
}, [deletePointOrLine, toolMode, activeLayer])
|
||||
|
||||
|
||||
useFrame(() => {
|
||||
if (deletePointOrLine) {
|
||||
DeletableLineorPoint(state, plane, floorPlanGroupLine, floorPlanGroupPoint, hoveredDeletableLine, hoveredDeletablePoint);
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
<group ref={floorPlanGroup} visible={toggleView} name="floorPlanGroup">
|
||||
<group ref={floorPlanGroupLine} name="floorPlanGroupLine"></group>
|
||||
<group ref={floorPlanGroupPoint} name="floorPlanGroupPoint"></group>
|
||||
</group>
|
||||
)
|
||||
}
|
||||
|
||||
export default FloorPlanGroup;
|
||||
@@ -1,289 +1,289 @@
|
||||
import { useEffect } from "react";
|
||||
import { useDeleteModels, useDeletePointOrLine, useObjectPosition, useObjectRotation, useObjectScale, useSelectedWallItem, useSocketStore, useWallItems } from "../../../store/store";
|
||||
import { Csg } from "../csg/csg";
|
||||
import * as Types from "../../../types/world/worldTypes";
|
||||
import * as CONSTANTS from "../../../types/world/worldConstants";
|
||||
import * as THREE from "three";
|
||||
import { useThree } from "@react-three/fiber";
|
||||
import handleMeshMissed from "../eventFunctions/handleMeshMissed";
|
||||
import DeleteWallItems from "../geomentries/walls/deleteWallItems";
|
||||
import loadInitialWallItems from "../../scene/IntialLoad/loadInitialWallItems";
|
||||
import AddWallItems from "../geomentries/walls/addWallItems";
|
||||
|
||||
|
||||
const WallItemsGroup = ({ currentWallItem, AssetConfigurations, hoveredDeletableWallItem, selectedItemsIndex, setSelectedItemsIndex, CSGGroup }: any) => {
|
||||
const { deleteModels, setDeleteModels } = useDeleteModels();
|
||||
const { wallItems, setWallItems } = useWallItems();
|
||||
const { objectPosition, setObjectPosition } = useObjectPosition();
|
||||
const { objectScale, setObjectScale } = useObjectScale();
|
||||
const { objectRotation, setObjectRotation } = useObjectRotation();
|
||||
const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine();
|
||||
const { selectedWallItem, setSelectedWallItem } = useSelectedWallItem();
|
||||
const { socket } = useSocketStore();
|
||||
const state = useThree();
|
||||
const { pointer, camera, raycaster } = state;
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
// Load Wall Items from the backend
|
||||
loadInitialWallItems(setWallItems, AssetConfigurations);
|
||||
}, []);
|
||||
|
||||
|
||||
////////// Update the Scale value changes in thewallItems State //////////
|
||||
|
||||
////////// Update the Position value changes in the selected item //////////
|
||||
|
||||
////////// Update the Rotation value changes in the selected item //////////
|
||||
|
||||
useEffect(() => {
|
||||
if (objectScale.x && objectScale.y && objectScale.z) {
|
||||
let ScaledWallItems: Types.wallItems = [];
|
||||
wallItems.forEach((items: any) => {
|
||||
if (items.model?.uuid === currentWallItem.current?.parent?.uuid) {
|
||||
items.scale = [objectScale.x, objectScale.y, objectScale.z];
|
||||
}
|
||||
ScaledWallItems.push(items);
|
||||
});
|
||||
setWallItems(ScaledWallItems);
|
||||
}
|
||||
}, [objectScale]);
|
||||
|
||||
useEffect(() => {
|
||||
if (objectPosition.x && objectPosition.y && objectPosition.z) {
|
||||
let ScaledWallItems: Types.wallItems = [];
|
||||
wallItems.forEach((items: any) => {
|
||||
if (items.model?.uuid === currentWallItem.current?.parent?.uuid) {
|
||||
items.position = [objectPosition.x, objectPosition.y, objectPosition.z];
|
||||
}
|
||||
ScaledWallItems.push(items);
|
||||
});
|
||||
setWallItems(ScaledWallItems);
|
||||
}
|
||||
}, [objectPosition]);
|
||||
|
||||
useEffect(() => {
|
||||
if (objectRotation.x && objectRotation.y && objectRotation.z) {
|
||||
let ScaledWallItems: Types.wallItems = [];
|
||||
wallItems.forEach((items: any) => {
|
||||
if (items.model?.uuid === currentWallItem.current?.parent?.uuid) {
|
||||
const radiansX = objectRotation.x * (Math.PI / 180);
|
||||
const radiansY = objectRotation.y * (Math.PI / 180);
|
||||
const radiansZ = objectRotation.z * (Math.PI / 180);
|
||||
const quaternion = new THREE.Quaternion().setFromEuler(
|
||||
new THREE.Euler(radiansX, radiansY, radiansZ)
|
||||
);
|
||||
items.quaternion = [quaternion.x, quaternion.y, quaternion.z, quaternion.w];
|
||||
}
|
||||
ScaledWallItems.push(items);
|
||||
});
|
||||
setWallItems(ScaledWallItems);
|
||||
}
|
||||
}, [objectRotation]);
|
||||
|
||||
useEffect(() => {
|
||||
const canvasElement = state.gl.domElement;
|
||||
function handlePointerMove(e: any) {
|
||||
if (selectedItemsIndex !== null && !deletePointOrLine && e.buttons === 1) {
|
||||
const Raycaster = state.raycaster;
|
||||
const intersects = Raycaster.intersectObjects(CSGGroup.current?.children[0].children!, true);
|
||||
const Object = intersects.find((child) => child.object.name.includes("WallRaycastReference"));
|
||||
|
||||
if (Object) {
|
||||
(state.controls as any)!.enabled = false;
|
||||
setWallItems((prevItems: any) => {
|
||||
const updatedItems = [...prevItems];
|
||||
let position: [number, number, number] = [0, 0, 0];
|
||||
|
||||
if (updatedItems[selectedItemsIndex].type === "Fixed-Move") {
|
||||
position = [Object!.point.x, Math.floor(Object!.point.y / CONSTANTS.wallConfig.height) * CONSTANTS.wallConfig.height, Object!.point.z];
|
||||
} else if (updatedItems[selectedItemsIndex].type === "Free-Move") {
|
||||
position = [Object!.point.x, Object!.point.y, Object!.point.z];
|
||||
}
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
setObjectPosition(new THREE.Vector3(...position));
|
||||
setObjectRotation({
|
||||
x: THREE.MathUtils.radToDeg(Object!.object.rotation.x),
|
||||
y: THREE.MathUtils.radToDeg(Object!.object.rotation.y),
|
||||
z: THREE.MathUtils.radToDeg(Object!.object.rotation.z),
|
||||
});
|
||||
});
|
||||
|
||||
updatedItems[selectedItemsIndex] = {
|
||||
...updatedItems[selectedItemsIndex],
|
||||
position: position,
|
||||
quaternion: Object!.object.quaternion.clone() as Types.QuaternionType,
|
||||
};
|
||||
|
||||
return updatedItems;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function handlePointerUp() {
|
||||
const Raycaster = state.raycaster;
|
||||
const intersects = Raycaster.intersectObjects(CSGGroup.current?.children[0].children!, true);
|
||||
const Object = intersects.find((child) => child.object.name.includes("WallRaycastReference"));
|
||||
if (Object) {
|
||||
if (selectedItemsIndex !== null) {
|
||||
let currentItem: any = null;
|
||||
setWallItems((prevItems: any) => {
|
||||
const updatedItems = [...prevItems];
|
||||
const WallItemsForStorage = updatedItems.map((item) => {
|
||||
const { model, ...rest } = item;
|
||||
return {
|
||||
...rest,
|
||||
modeluuid: model?.uuid,
|
||||
};
|
||||
});
|
||||
|
||||
currentItem = updatedItems[selectedItemsIndex];
|
||||
localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage));
|
||||
return updatedItems;
|
||||
});
|
||||
|
||||
setTimeout(async () => {
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
//REST
|
||||
|
||||
// await setWallItem(
|
||||
// organization,
|
||||
// currentItem?.model?.uuid,
|
||||
// currentItem.modelname,
|
||||
// currentItem.type!,
|
||||
// currentItem.csgposition!,
|
||||
// currentItem.csgscale!,
|
||||
// currentItem.position,
|
||||
// currentItem.quaternion,
|
||||
// currentItem.scale!,
|
||||
// )
|
||||
|
||||
//SOCKET
|
||||
|
||||
const data = {
|
||||
organization: organization,
|
||||
modeluuid: currentItem.model?.uuid!,
|
||||
modelname: currentItem.modelname!,
|
||||
type: currentItem.type!,
|
||||
csgposition: currentItem.csgposition!,
|
||||
csgscale: currentItem.csgscale!,
|
||||
position: currentItem.position!,
|
||||
quaternion: currentItem.quaternion,
|
||||
scale: currentItem.scale!,
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
socket.emit('v1:wallItems:set', data);
|
||||
}, 0);
|
||||
(state.controls as any)!.enabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
canvasElement.addEventListener("pointermove", handlePointerMove);
|
||||
canvasElement.addEventListener("pointerup", handlePointerUp);
|
||||
|
||||
return () => {
|
||||
canvasElement.removeEventListener("pointermove", handlePointerMove);
|
||||
canvasElement.removeEventListener("pointerup", handlePointerUp);
|
||||
};
|
||||
}, [selectedItemsIndex]);
|
||||
|
||||
useEffect(() => {
|
||||
const canvasElement = state.gl.domElement;
|
||||
let drag = false;
|
||||
let isLeftMouseDown = false;
|
||||
|
||||
const onMouseDown = (evt: any) => {
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown = true;
|
||||
drag = false;
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseUp = (evt: any) => {
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown = false;
|
||||
if (!drag && deleteModels) {
|
||||
DeleteWallItems(hoveredDeletableWallItem, setWallItems, wallItems, socket);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseMove = () => {
|
||||
if (isLeftMouseDown) {
|
||||
drag = true;
|
||||
}
|
||||
};
|
||||
|
||||
const onDrop = (event: any) => {
|
||||
|
||||
if (!event.dataTransfer?.files[0]) return
|
||||
pointer.x = (event.clientX / window.innerWidth) * 2 - 1;
|
||||
pointer.y = -(event.clientY / window.innerHeight) * 2 + 1;
|
||||
raycaster.setFromCamera(pointer, camera);
|
||||
|
||||
if (AssetConfigurations[(event.dataTransfer.files[0].name.split('.'))[0]]) {
|
||||
const selected = (event.dataTransfer.files[0].name.split('.'))[0];
|
||||
|
||||
if (AssetConfigurations[selected]?.type) {
|
||||
AddWallItems(selected, raycaster, CSGGroup, AssetConfigurations, setWallItems, socket);
|
||||
}
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
const onDragOver = (event: any) => {
|
||||
event.preventDefault();
|
||||
};
|
||||
|
||||
canvasElement.addEventListener("mousedown", onMouseDown);
|
||||
canvasElement.addEventListener("mouseup", onMouseUp);
|
||||
canvasElement.addEventListener("mousemove", onMouseMove);
|
||||
canvasElement.addEventListener("drop", onDrop);
|
||||
canvasElement.addEventListener("dragover", onDragOver);
|
||||
|
||||
return () => {
|
||||
canvasElement.removeEventListener("mousedown", onMouseDown);
|
||||
canvasElement.removeEventListener("mouseup", onMouseUp);
|
||||
canvasElement.removeEventListener("mousemove", onMouseMove);
|
||||
canvasElement.removeEventListener("drop", onDrop);
|
||||
canvasElement.removeEventListener("dragover", onDragOver);
|
||||
};
|
||||
}, [deleteModels, wallItems])
|
||||
|
||||
useEffect(() => {
|
||||
if (deleteModels) {
|
||||
handleMeshMissed(currentWallItem, setSelectedWallItem, setSelectedItemsIndex);
|
||||
setSelectedWallItem(null);
|
||||
setSelectedItemsIndex(null);
|
||||
}
|
||||
}, [deleteModels])
|
||||
|
||||
return (
|
||||
<>
|
||||
{wallItems.map((item: Types.WallItem, index: number) => (
|
||||
<group
|
||||
key={index}
|
||||
position={item.position}
|
||||
quaternion={item.quaternion}
|
||||
scale={item.scale}
|
||||
>
|
||||
<Csg
|
||||
position={item.csgposition!}
|
||||
scale={item.csgscale!}
|
||||
model={item.model!}
|
||||
hoveredDeletableWallItem={hoveredDeletableWallItem}
|
||||
/>
|
||||
</group>
|
||||
))}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
import { useEffect } from "react";
|
||||
import { useDeleteModels, useDeletePointOrLine, useObjectPosition, useObjectRotation, useObjectScale, useSelectedWallItem, useSocketStore, useWallItems } from "../../../store/store";
|
||||
import { Csg } from "../csg/csg";
|
||||
import * as Types from "../../../types/world/worldTypes";
|
||||
import * as CONSTANTS from "../../../types/world/worldConstants";
|
||||
import * as THREE from "three";
|
||||
import { useThree } from "@react-three/fiber";
|
||||
import handleMeshMissed from "../eventFunctions/handleMeshMissed";
|
||||
import DeleteWallItems from "../geomentries/walls/deleteWallItems";
|
||||
import loadInitialWallItems from "../../scene/IntialLoad/loadInitialWallItems";
|
||||
import AddWallItems from "../geomentries/walls/addWallItems";
|
||||
|
||||
|
||||
const WallItemsGroup = ({ currentWallItem, AssetConfigurations, hoveredDeletableWallItem, selectedItemsIndex, setSelectedItemsIndex, CSGGroup }: any) => {
|
||||
const { deleteModels, setDeleteModels } = useDeleteModels();
|
||||
const { wallItems, setWallItems } = useWallItems();
|
||||
const { objectPosition, setObjectPosition } = useObjectPosition();
|
||||
const { objectScale, setObjectScale } = useObjectScale();
|
||||
const { objectRotation, setObjectRotation } = useObjectRotation();
|
||||
const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine();
|
||||
const { selectedWallItem, setSelectedWallItem } = useSelectedWallItem();
|
||||
const { socket } = useSocketStore();
|
||||
const state = useThree();
|
||||
const { pointer, camera, raycaster } = state;
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
// Load Wall Items from the backend
|
||||
loadInitialWallItems(setWallItems, AssetConfigurations);
|
||||
}, []);
|
||||
|
||||
|
||||
////////// Update the Scale value changes in thewallItems State //////////
|
||||
|
||||
////////// Update the Position value changes in the selected item //////////
|
||||
|
||||
////////// Update the Rotation value changes in the selected item //////////
|
||||
|
||||
useEffect(() => {
|
||||
if (objectScale.x && objectScale.y && objectScale.z) {
|
||||
let ScaledWallItems: Types.wallItems = [];
|
||||
wallItems.forEach((items: any) => {
|
||||
if (items.model?.uuid === currentWallItem.current?.parent?.uuid) {
|
||||
items.scale = [objectScale.x, objectScale.y, objectScale.z];
|
||||
}
|
||||
ScaledWallItems.push(items);
|
||||
});
|
||||
setWallItems(ScaledWallItems);
|
||||
}
|
||||
}, [objectScale]);
|
||||
|
||||
useEffect(() => {
|
||||
if (objectPosition.x && objectPosition.y && objectPosition.z) {
|
||||
let ScaledWallItems: Types.wallItems = [];
|
||||
wallItems.forEach((items: any) => {
|
||||
if (items.model?.uuid === currentWallItem.current?.parent?.uuid) {
|
||||
items.position = [objectPosition.x, objectPosition.y, objectPosition.z];
|
||||
}
|
||||
ScaledWallItems.push(items);
|
||||
});
|
||||
setWallItems(ScaledWallItems);
|
||||
}
|
||||
}, [objectPosition]);
|
||||
|
||||
useEffect(() => {
|
||||
if (objectRotation.x && objectRotation.y && objectRotation.z) {
|
||||
let ScaledWallItems: Types.wallItems = [];
|
||||
wallItems.forEach((items: any) => {
|
||||
if (items.model?.uuid === currentWallItem.current?.parent?.uuid) {
|
||||
const radiansX = objectRotation.x * (Math.PI / 180);
|
||||
const radiansY = objectRotation.y * (Math.PI / 180);
|
||||
const radiansZ = objectRotation.z * (Math.PI / 180);
|
||||
const quaternion = new THREE.Quaternion().setFromEuler(
|
||||
new THREE.Euler(radiansX, radiansY, radiansZ)
|
||||
);
|
||||
items.quaternion = [quaternion.x, quaternion.y, quaternion.z, quaternion.w];
|
||||
}
|
||||
ScaledWallItems.push(items);
|
||||
});
|
||||
setWallItems(ScaledWallItems);
|
||||
}
|
||||
}, [objectRotation]);
|
||||
|
||||
useEffect(() => {
|
||||
const canvasElement = state.gl.domElement;
|
||||
function handlePointerMove(e: any) {
|
||||
if (selectedItemsIndex !== null && !deletePointOrLine && e.buttons === 1) {
|
||||
const Raycaster = state.raycaster;
|
||||
const intersects = Raycaster.intersectObjects(CSGGroup.current?.children[0].children!, true);
|
||||
const Object = intersects.find((child) => child.object.name.includes("WallRaycastReference"));
|
||||
|
||||
if (Object) {
|
||||
(state.controls as any)!.enabled = false;
|
||||
setWallItems((prevItems: any) => {
|
||||
const updatedItems = [...prevItems];
|
||||
let position: [number, number, number] = [0, 0, 0];
|
||||
|
||||
if (updatedItems[selectedItemsIndex].type === "Fixed-Move") {
|
||||
position = [Object!.point.x, Math.floor(Object!.point.y / CONSTANTS.wallConfig.height) * CONSTANTS.wallConfig.height, Object!.point.z];
|
||||
} else if (updatedItems[selectedItemsIndex].type === "Free-Move") {
|
||||
position = [Object!.point.x, Object!.point.y, Object!.point.z];
|
||||
}
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
setObjectPosition(new THREE.Vector3(...position));
|
||||
setObjectRotation({
|
||||
x: THREE.MathUtils.radToDeg(Object!.object.rotation.x),
|
||||
y: THREE.MathUtils.radToDeg(Object!.object.rotation.y),
|
||||
z: THREE.MathUtils.radToDeg(Object!.object.rotation.z),
|
||||
});
|
||||
});
|
||||
|
||||
updatedItems[selectedItemsIndex] = {
|
||||
...updatedItems[selectedItemsIndex],
|
||||
position: position,
|
||||
quaternion: Object!.object.quaternion.clone() as Types.QuaternionType,
|
||||
};
|
||||
|
||||
return updatedItems;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function handlePointerUp() {
|
||||
const Raycaster = state.raycaster;
|
||||
const intersects = Raycaster.intersectObjects(CSGGroup.current?.children[0].children!, true);
|
||||
const Object = intersects.find((child) => child.object.name.includes("WallRaycastReference"));
|
||||
if (Object) {
|
||||
if (selectedItemsIndex !== null) {
|
||||
let currentItem: any = null;
|
||||
setWallItems((prevItems: any) => {
|
||||
const updatedItems = [...prevItems];
|
||||
const WallItemsForStorage = updatedItems.map((item) => {
|
||||
const { model, ...rest } = item;
|
||||
return {
|
||||
...rest,
|
||||
modeluuid: model?.uuid,
|
||||
};
|
||||
});
|
||||
|
||||
currentItem = updatedItems[selectedItemsIndex];
|
||||
localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage));
|
||||
return updatedItems;
|
||||
});
|
||||
|
||||
setTimeout(async () => {
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
//REST
|
||||
|
||||
// await setWallItem(
|
||||
// organization,
|
||||
// currentItem?.model?.uuid,
|
||||
// currentItem.modelname,
|
||||
// currentItem.type!,
|
||||
// currentItem.csgposition!,
|
||||
// currentItem.csgscale!,
|
||||
// currentItem.position,
|
||||
// currentItem.quaternion,
|
||||
// currentItem.scale!,
|
||||
// )
|
||||
|
||||
//SOCKET
|
||||
|
||||
const data = {
|
||||
organization: organization,
|
||||
modeluuid: currentItem.model?.uuid!,
|
||||
modelname: currentItem.modelname!,
|
||||
type: currentItem.type!,
|
||||
csgposition: currentItem.csgposition!,
|
||||
csgscale: currentItem.csgscale!,
|
||||
position: currentItem.position!,
|
||||
quaternion: currentItem.quaternion,
|
||||
scale: currentItem.scale!,
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
socket.emit('v1:wallItems:set', data);
|
||||
}, 0);
|
||||
(state.controls as any)!.enabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
canvasElement.addEventListener("pointermove", handlePointerMove);
|
||||
canvasElement.addEventListener("pointerup", handlePointerUp);
|
||||
|
||||
return () => {
|
||||
canvasElement.removeEventListener("pointermove", handlePointerMove);
|
||||
canvasElement.removeEventListener("pointerup", handlePointerUp);
|
||||
};
|
||||
}, [selectedItemsIndex]);
|
||||
|
||||
useEffect(() => {
|
||||
const canvasElement = state.gl.domElement;
|
||||
let drag = false;
|
||||
let isLeftMouseDown = false;
|
||||
|
||||
const onMouseDown = (evt: any) => {
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown = true;
|
||||
drag = false;
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseUp = (evt: any) => {
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown = false;
|
||||
if (!drag && deleteModels) {
|
||||
DeleteWallItems(hoveredDeletableWallItem, setWallItems, wallItems, socket);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseMove = () => {
|
||||
if (isLeftMouseDown) {
|
||||
drag = true;
|
||||
}
|
||||
};
|
||||
|
||||
const onDrop = (event: any) => {
|
||||
|
||||
if (!event.dataTransfer?.files[0]) return
|
||||
pointer.x = (event.clientX / window.innerWidth) * 2 - 1;
|
||||
pointer.y = -(event.clientY / window.innerHeight) * 2 + 1;
|
||||
raycaster.setFromCamera(pointer, camera);
|
||||
|
||||
if (AssetConfigurations[(event.dataTransfer.files[0].name.split('.'))[0]]) {
|
||||
const selected = (event.dataTransfer.files[0].name.split('.'))[0];
|
||||
|
||||
if (AssetConfigurations[selected]?.type) {
|
||||
AddWallItems(selected, raycaster, CSGGroup, AssetConfigurations, setWallItems, socket);
|
||||
}
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
const onDragOver = (event: any) => {
|
||||
event.preventDefault();
|
||||
};
|
||||
|
||||
canvasElement.addEventListener("mousedown", onMouseDown);
|
||||
canvasElement.addEventListener("mouseup", onMouseUp);
|
||||
canvasElement.addEventListener("mousemove", onMouseMove);
|
||||
canvasElement.addEventListener("drop", onDrop);
|
||||
canvasElement.addEventListener("dragover", onDragOver);
|
||||
|
||||
return () => {
|
||||
canvasElement.removeEventListener("mousedown", onMouseDown);
|
||||
canvasElement.removeEventListener("mouseup", onMouseUp);
|
||||
canvasElement.removeEventListener("mousemove", onMouseMove);
|
||||
canvasElement.removeEventListener("drop", onDrop);
|
||||
canvasElement.removeEventListener("dragover", onDragOver);
|
||||
};
|
||||
}, [deleteModels, wallItems])
|
||||
|
||||
useEffect(() => {
|
||||
if (deleteModels) {
|
||||
handleMeshMissed(currentWallItem, setSelectedWallItem, setSelectedItemsIndex);
|
||||
setSelectedWallItem(null);
|
||||
setSelectedItemsIndex(null);
|
||||
}
|
||||
}, [deleteModels])
|
||||
|
||||
return (
|
||||
<>
|
||||
{wallItems.map((item: Types.WallItem, index: number) => (
|
||||
<group
|
||||
key={index}
|
||||
position={item.position}
|
||||
quaternion={item.quaternion}
|
||||
scale={item.scale}
|
||||
>
|
||||
<Csg
|
||||
position={item.csgposition!}
|
||||
scale={item.csgscale!}
|
||||
model={item.model!}
|
||||
hoveredDeletableWallItem={hoveredDeletableWallItem}
|
||||
/>
|
||||
</group>
|
||||
))}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default WallItemsGroup;
|
||||
@@ -1,56 +1,56 @@
|
||||
import { Geometry } from "@react-three/csg";
|
||||
import { useDeleteModels, useSelectedWallItem, useToggleView, useTransformMode, useWallItems, useWalls } from "../../../store/store";
|
||||
import handleMeshDown from "../eventFunctions/handleMeshDown";
|
||||
import handleMeshMissed from "../eventFunctions/handleMeshMissed";
|
||||
import WallsMesh from "./wallsMesh";
|
||||
import WallItemsGroup from "./wallItemsGroup";
|
||||
import { useEffect } from "react";
|
||||
|
||||
|
||||
const WallsAndWallItems = ({ CSGGroup, AssetConfigurations, setSelectedItemsIndex, selectedItemsIndex, currentWallItem, csg, lines, hoveredDeletableWallItem }: any) => {
|
||||
const { walls, setWalls } = useWalls();
|
||||
const { wallItems, setWallItems } = useWallItems();
|
||||
const { toggleView, setToggleView } = useToggleView();
|
||||
const { deleteModels, setDeleteModels } = useDeleteModels();
|
||||
const { transformMode, setTransformMode } = useTransformMode();
|
||||
const { selectedWallItem, setSelectedWallItem } = useSelectedWallItem();
|
||||
|
||||
useEffect(() => {
|
||||
if (transformMode === null) {
|
||||
if (!deleteModels) {
|
||||
handleMeshMissed(currentWallItem, setSelectedWallItem, setSelectedItemsIndex);
|
||||
setSelectedWallItem(null);
|
||||
setSelectedItemsIndex(null);
|
||||
}
|
||||
}
|
||||
}, [transformMode])
|
||||
|
||||
return (
|
||||
<mesh
|
||||
ref={CSGGroup as any}
|
||||
name="Walls"
|
||||
key={walls.length}
|
||||
receiveShadow
|
||||
visible={!toggleView}
|
||||
onClick={(event) => {
|
||||
if (!deleteModels && transformMode !== null) {
|
||||
handleMeshDown(event, currentWallItem, setSelectedWallItem, setSelectedItemsIndex, wallItems, toggleView);
|
||||
}
|
||||
}}
|
||||
onPointerMissed={() => {
|
||||
if (!deleteModels) {
|
||||
handleMeshMissed(currentWallItem, setSelectedWallItem, setSelectedItemsIndex);
|
||||
setSelectedWallItem(null);
|
||||
setSelectedItemsIndex(null);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Geometry ref={csg as any} computeVertexNormals useGroups>
|
||||
<WallsMesh lines={lines} />
|
||||
<WallItemsGroup currentWallItem={currentWallItem} AssetConfigurations={AssetConfigurations} hoveredDeletableWallItem={hoveredDeletableWallItem} selectedItemsIndex={selectedItemsIndex} setSelectedItemsIndex={setSelectedItemsIndex} CSGGroup={CSGGroup} />
|
||||
</Geometry>
|
||||
</mesh>
|
||||
)
|
||||
}
|
||||
|
||||
import { Geometry } from "@react-three/csg";
|
||||
import { useDeleteModels, useSelectedWallItem, useToggleView, useTransformMode, useWallItems, useWalls } from "../../../store/store";
|
||||
import handleMeshDown from "../eventFunctions/handleMeshDown";
|
||||
import handleMeshMissed from "../eventFunctions/handleMeshMissed";
|
||||
import WallsMesh from "./wallsMesh";
|
||||
import WallItemsGroup from "./wallItemsGroup";
|
||||
import { useEffect } from "react";
|
||||
|
||||
|
||||
const WallsAndWallItems = ({ CSGGroup, AssetConfigurations, setSelectedItemsIndex, selectedItemsIndex, currentWallItem, csg, lines, hoveredDeletableWallItem }: any) => {
|
||||
const { walls, setWalls } = useWalls();
|
||||
const { wallItems, setWallItems } = useWallItems();
|
||||
const { toggleView, setToggleView } = useToggleView();
|
||||
const { deleteModels, setDeleteModels } = useDeleteModels();
|
||||
const { transformMode, setTransformMode } = useTransformMode();
|
||||
const { selectedWallItem, setSelectedWallItem } = useSelectedWallItem();
|
||||
|
||||
useEffect(() => {
|
||||
if (transformMode === null) {
|
||||
if (!deleteModels) {
|
||||
handleMeshMissed(currentWallItem, setSelectedWallItem, setSelectedItemsIndex);
|
||||
setSelectedWallItem(null);
|
||||
setSelectedItemsIndex(null);
|
||||
}
|
||||
}
|
||||
}, [transformMode])
|
||||
|
||||
return (
|
||||
<mesh
|
||||
ref={CSGGroup as any}
|
||||
name="Walls"
|
||||
key={walls.length}
|
||||
receiveShadow
|
||||
visible={!toggleView}
|
||||
onClick={(event) => {
|
||||
if (!deleteModels && transformMode !== null) {
|
||||
handleMeshDown(event, currentWallItem, setSelectedWallItem, setSelectedItemsIndex, wallItems, toggleView);
|
||||
}
|
||||
}}
|
||||
onPointerMissed={() => {
|
||||
if (!deleteModels) {
|
||||
handleMeshMissed(currentWallItem, setSelectedWallItem, setSelectedItemsIndex);
|
||||
setSelectedWallItem(null);
|
||||
setSelectedItemsIndex(null);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Geometry ref={csg as any} computeVertexNormals useGroups>
|
||||
<WallsMesh lines={lines} />
|
||||
<WallItemsGroup currentWallItem={currentWallItem} AssetConfigurations={AssetConfigurations} hoveredDeletableWallItem={hoveredDeletableWallItem} selectedItemsIndex={selectedItemsIndex} setSelectedItemsIndex={setSelectedItemsIndex} CSGGroup={CSGGroup} />
|
||||
</Geometry>
|
||||
</mesh>
|
||||
)
|
||||
}
|
||||
|
||||
export default WallsAndWallItems;
|
||||
@@ -1,65 +1,65 @@
|
||||
import * as THREE from 'three';
|
||||
import * as Types from '../../../types/world/worldTypes';
|
||||
import * as CONSTANTS from '../../../types/world/worldConstants';
|
||||
import { Base } from '@react-three/csg';
|
||||
import { MeshDiscardMaterial } from '@react-three/drei';
|
||||
import { useUpdateScene, useWalls } from '../../../store/store';
|
||||
import { useEffect } from 'react';
|
||||
import { getLines } from '../../../services/factoryBuilder/lines/getLinesApi';
|
||||
import objectLinesToArray from '../geomentries/lines/lineConvertions/objectLinesToArray';
|
||||
import loadWalls from '../geomentries/walls/loadWalls';
|
||||
|
||||
const WallsMesh = ({ lines }: any) => {
|
||||
const { walls, setWalls } = useWalls();
|
||||
const { updateScene, setUpdateScene } = useUpdateScene();
|
||||
|
||||
useEffect(() => {
|
||||
if (updateScene) {
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
getLines(organization).then((data) => {
|
||||
const Lines: Types.Lines = objectLinesToArray(data);
|
||||
localStorage.setItem("Lines", JSON.stringify(Lines));
|
||||
|
||||
if (Lines) {
|
||||
loadWalls(lines, setWalls);
|
||||
}
|
||||
})
|
||||
setUpdateScene(false);
|
||||
}
|
||||
}, [updateScene])
|
||||
|
||||
return (
|
||||
<>
|
||||
{walls.map((wall: Types.Wall, index: number) => (
|
||||
<mesh key={index}>
|
||||
<Base
|
||||
name={`Wall${index + 1}`}
|
||||
geometry={wall[0]}
|
||||
rotation={wall[1]}
|
||||
position={wall[2]}
|
||||
userData={{ WallType: wall[3], Layer: wall[4] }}
|
||||
>
|
||||
<meshStandardMaterial
|
||||
side={THREE.DoubleSide}
|
||||
color={CONSTANTS.wallConfig.defaultColor}
|
||||
/>
|
||||
</Base>
|
||||
<mesh
|
||||
castShadow
|
||||
geometry={wall[0]}
|
||||
rotation={wall[1]}
|
||||
position={wall[2]}
|
||||
name={`WallRaycastReference_${index + 1}`}
|
||||
>
|
||||
<MeshDiscardMaterial />
|
||||
</mesh>
|
||||
</mesh>
|
||||
))}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
import * as THREE from 'three';
|
||||
import * as Types from '../../../types/world/worldTypes';
|
||||
import * as CONSTANTS from '../../../types/world/worldConstants';
|
||||
import { Base } from '@react-three/csg';
|
||||
import { MeshDiscardMaterial } from '@react-three/drei';
|
||||
import { useUpdateScene, useWalls } from '../../../store/store';
|
||||
import { useEffect } from 'react';
|
||||
import { getLines } from '../../../services/factoryBuilder/lines/getLinesApi';
|
||||
import objectLinesToArray from '../geomentries/lines/lineConvertions/objectLinesToArray';
|
||||
import loadWalls from '../geomentries/walls/loadWalls';
|
||||
|
||||
const WallsMesh = ({ lines }: any) => {
|
||||
const { walls, setWalls } = useWalls();
|
||||
const { updateScene, setUpdateScene } = useUpdateScene();
|
||||
|
||||
useEffect(() => {
|
||||
if (updateScene) {
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
getLines(organization).then((data) => {
|
||||
const Lines: Types.Lines = objectLinesToArray(data);
|
||||
localStorage.setItem("Lines", JSON.stringify(Lines));
|
||||
|
||||
if (Lines) {
|
||||
loadWalls(lines, setWalls);
|
||||
}
|
||||
})
|
||||
setUpdateScene(false);
|
||||
}
|
||||
}, [updateScene])
|
||||
|
||||
return (
|
||||
<>
|
||||
{walls.map((wall: Types.Wall, index: number) => (
|
||||
<mesh key={index}>
|
||||
<Base
|
||||
name={`Wall${index + 1}`}
|
||||
geometry={wall[0]}
|
||||
rotation={wall[1]}
|
||||
position={wall[2]}
|
||||
userData={{ WallType: wall[3], Layer: wall[4] }}
|
||||
>
|
||||
<meshStandardMaterial
|
||||
side={THREE.DoubleSide}
|
||||
color={CONSTANTS.wallConfig.defaultColor}
|
||||
/>
|
||||
</Base>
|
||||
<mesh
|
||||
castShadow
|
||||
geometry={wall[0]}
|
||||
rotation={wall[1]}
|
||||
position={wall[2]}
|
||||
name={`WallRaycastReference_${index + 1}`}
|
||||
>
|
||||
<MeshDiscardMaterial />
|
||||
</mesh>
|
||||
</mesh>
|
||||
))}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default WallsMesh;
|
||||
@@ -1,245 +1,245 @@
|
||||
import { useEffect } from "react";
|
||||
import * as THREE from 'three';
|
||||
import * as Types from '../../../types/world/worldTypes';
|
||||
import * as CONSTANTS from "../../../types/world/worldConstants";
|
||||
import { useActiveLayer, useSocketStore, useDeleteModels, useDeletePointOrLine, useMovePoint, useToggleView, useUpdateScene, useNewLines, useToolMode } from "../../../store/store";
|
||||
import { useThree } from "@react-three/fiber";
|
||||
import arrayLineToObject from "../geomentries/lines/lineConvertions/arrayLineToObject";
|
||||
import addPointToScene from "../geomentries/points/addPointToScene";
|
||||
import addLineToScene from "../geomentries/lines/addLineToScene";
|
||||
import removeSoloPoint from "../geomentries/points/removeSoloPoint";
|
||||
import removeReferenceLine from "../geomentries/lines/removeReferenceLine";
|
||||
import getClosestIntersection from "../geomentries/lines/getClosestIntersection";
|
||||
import loadZones from "../geomentries/zones/loadZones";
|
||||
|
||||
const ZoneGroup = ({ zoneGroup, plane, floorPlanGroupLine, floorPlanGroupPoint, line, lines, currentLayerPoint, dragPointControls, floorPlanGroup, ReferenceLineMesh, LineCreated, isSnapped, ispreSnapped, snappedPoint, isSnappedUUID, isAngleSnapped, anglesnappedPoint }: any) => {
|
||||
const { toggleView, setToggleView } = useToggleView();
|
||||
const { deleteModels, setDeleteModels } = useDeleteModels();
|
||||
const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine();
|
||||
const { toolMode, setToolMode } = useToolMode();
|
||||
const { movePoint, setMovePoint } = useMovePoint();
|
||||
const { socket } = useSocketStore();
|
||||
const { activeLayer } = useActiveLayer();
|
||||
const { gl, raycaster, camera, pointer } = useThree();
|
||||
const { updateScene, setUpdateScene } = useUpdateScene();
|
||||
const { newLines, setNewLines } = useNewLines();
|
||||
|
||||
useEffect(() => {
|
||||
if (updateScene) {
|
||||
loadZones(lines, zoneGroup);
|
||||
setUpdateScene(false);
|
||||
}
|
||||
}, [updateScene])
|
||||
|
||||
useEffect(() => {
|
||||
if (toolMode === "Zone") {
|
||||
setDeletePointOrLine(false);
|
||||
setMovePoint(false);
|
||||
setDeleteModels(false);
|
||||
} else {
|
||||
removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint);
|
||||
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
|
||||
}
|
||||
}, [toolMode])
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
const canvasElement = gl.domElement;
|
||||
|
||||
let drag = false;
|
||||
let isLeftMouseDown = false;
|
||||
|
||||
const onMouseDown = (evt: any) => {
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown = true;
|
||||
drag = false;
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseUp = (evt: any) => {
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown = false;
|
||||
}
|
||||
}
|
||||
|
||||
const onMouseMove = () => {
|
||||
if (isLeftMouseDown) {
|
||||
drag = true;
|
||||
}
|
||||
};
|
||||
|
||||
const onContextMenu = (e: any) => {
|
||||
e.preventDefault();
|
||||
if (toolMode === "Zone") {
|
||||
removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint);
|
||||
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseClick = (evt: any) => {
|
||||
if (!plane.current || drag) return;
|
||||
const intersects = raycaster.intersectObject(plane.current, true);
|
||||
let intersectionPoint = intersects[0].point;
|
||||
const points = floorPlanGroupPoint.current?.children ?? [];
|
||||
const intersectsPoint = raycaster.intersectObjects(points, true).find(intersect => intersect.object.visible);
|
||||
let intersectsLines: any = raycaster.intersectObjects(floorPlanGroupLine.current.children, true);
|
||||
|
||||
if (intersectsLines.length > 0 && intersects && intersects.length > 0 && !intersectsPoint) {
|
||||
const lineType = intersectsLines[0].object.userData.linePoints[0][3];
|
||||
if (lineType === CONSTANTS.lineConfig.zoneName) {
|
||||
// console.log("intersected a zone line");
|
||||
|
||||
const ThroughPoint = (intersectsLines[0].object.geometry.parameters.path).getPoints(300);
|
||||
let intersection = getClosestIntersection(ThroughPoint, intersectionPoint);
|
||||
if (!intersection) return;
|
||||
const point = addPointToScene(intersection, CONSTANTS.pointConfig.zoneOuterColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, undefined, CONSTANTS.lineConfig.zoneName);
|
||||
(line.current as Types.Line).push([new THREE.Vector3(intersection.x, 0.01, intersection.z), point.uuid, activeLayer, CONSTANTS.lineConfig.zoneName,]);
|
||||
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
|
||||
lines.current.push(line.current as Types.Line);
|
||||
|
||||
const data = arrayLineToObject(line.current as Types.Line);
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
//REST
|
||||
|
||||
// setLine(organization, data.layer!, data.line!, data.type!);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const input = {
|
||||
organization: organization,
|
||||
layer: data.layer,
|
||||
line: data.line,
|
||||
type: data.type,
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
socket.emit('v1:Line:create', input);
|
||||
|
||||
setNewLines([line.current]);
|
||||
|
||||
addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.lineConfig.zoneColor, line.current, floorPlanGroupLine);
|
||||
let lastPoint = line.current[line.current.length - 1];
|
||||
line.current = [lastPoint];
|
||||
}
|
||||
}
|
||||
} else if (intersectsPoint && intersects && intersects.length > 0) {
|
||||
if (intersectsPoint.object.userData.type === CONSTANTS.lineConfig.zoneName) {
|
||||
// console.log("intersected a zone point");
|
||||
|
||||
intersectionPoint = intersectsPoint.object.position;
|
||||
(line.current as Types.Line).push([new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), intersectsPoint.object.uuid, activeLayer, CONSTANTS.lineConfig.zoneName]);
|
||||
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
|
||||
lines.current.push(line.current as Types.Line);
|
||||
|
||||
const data = arrayLineToObject(line.current as Types.Line);
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
//REST
|
||||
|
||||
// setLine(organization, data.layer!, data.line!, data.type!);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const input = {
|
||||
organization: organization,
|
||||
layer: data.layer,
|
||||
line: data.line,
|
||||
type: data.type,
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
socket.emit('v1:Line:create', input);
|
||||
|
||||
setNewLines([line.current]);
|
||||
|
||||
addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.lineConfig.zoneColor, line.current, floorPlanGroupLine);
|
||||
let lastPoint = line.current[line.current.length - 1];
|
||||
line.current = [lastPoint];
|
||||
ispreSnapped.current = false;
|
||||
isSnapped.current = false;
|
||||
}
|
||||
}
|
||||
} else if (intersects && intersects.length > 0) {
|
||||
// console.log("intersected a empty area");
|
||||
|
||||
let uuid: string = "";
|
||||
if (isAngleSnapped.current && anglesnappedPoint.current && line.current.length > 0) {
|
||||
intersectionPoint = anglesnappedPoint.current;
|
||||
const point = addPointToScene(intersectionPoint, CONSTANTS.pointConfig.zoneOuterColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, undefined, CONSTANTS.lineConfig.zoneName);
|
||||
uuid = point.uuid;
|
||||
} else if (isSnapped.current && snappedPoint.current && line.current.length > 0) {
|
||||
intersectionPoint = snappedPoint.current;
|
||||
uuid = isSnappedUUID.current!;
|
||||
} else if (ispreSnapped.current && snappedPoint.current) {
|
||||
intersectionPoint = snappedPoint.current;
|
||||
uuid = isSnappedUUID.current!;
|
||||
} else {
|
||||
const point = addPointToScene(intersectionPoint, CONSTANTS.pointConfig.zoneOuterColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, undefined, CONSTANTS.lineConfig.zoneName);
|
||||
uuid = point.uuid;
|
||||
}
|
||||
|
||||
(line.current as Types.Line).push([new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), uuid, activeLayer, CONSTANTS.lineConfig.zoneName]);
|
||||
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
|
||||
lines.current.push(line.current as Types.Line);
|
||||
|
||||
const data = arrayLineToObject(line.current as Types.Line);
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
//REST
|
||||
|
||||
// setLine(organization, data.layer!, data.line!, data.type!);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const input = {
|
||||
organization: organization,
|
||||
layer: data.layer,
|
||||
line: data.line,
|
||||
type: data.type,
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
socket.emit('v1:Line:create', input);
|
||||
|
||||
setNewLines([line.current]);
|
||||
|
||||
addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.lineConfig.zoneColor, line.current, floorPlanGroupLine);
|
||||
let lastPoint = line.current[line.current.length - 1];
|
||||
line.current = [lastPoint];
|
||||
ispreSnapped.current = false;
|
||||
isSnapped.current = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (toolMode === 'Zone') {
|
||||
canvasElement.addEventListener("mousedown", onMouseDown);
|
||||
canvasElement.addEventListener("mouseup", onMouseUp);
|
||||
canvasElement.addEventListener("mousemove", onMouseMove);
|
||||
canvasElement.addEventListener("click", onMouseClick);
|
||||
canvasElement.addEventListener("contextmenu", onContextMenu);
|
||||
}
|
||||
|
||||
return () => {
|
||||
canvasElement.removeEventListener("mousedown", onMouseDown);
|
||||
canvasElement.removeEventListener("mouseup", onMouseUp);
|
||||
canvasElement.removeEventListener("mousemove", onMouseMove);
|
||||
canvasElement.removeEventListener("click", onMouseClick);
|
||||
canvasElement.removeEventListener("contextmenu", onContextMenu);
|
||||
};
|
||||
}, [toolMode])
|
||||
|
||||
return (
|
||||
<group ref={zoneGroup} visible={!toggleView} name="zoneGroup">
|
||||
</group>
|
||||
)
|
||||
}
|
||||
|
||||
import { useEffect } from "react";
|
||||
import * as THREE from 'three';
|
||||
import * as Types from '../../../types/world/worldTypes';
|
||||
import * as CONSTANTS from "../../../types/world/worldConstants";
|
||||
import { useActiveLayer, useSocketStore, useDeleteModels, useDeletePointOrLine, useMovePoint, useToggleView, useUpdateScene, useNewLines, useToolMode } from "../../../store/store";
|
||||
import { useThree } from "@react-three/fiber";
|
||||
import arrayLineToObject from "../geomentries/lines/lineConvertions/arrayLineToObject";
|
||||
import addPointToScene from "../geomentries/points/addPointToScene";
|
||||
import addLineToScene from "../geomentries/lines/addLineToScene";
|
||||
import removeSoloPoint from "../geomentries/points/removeSoloPoint";
|
||||
import removeReferenceLine from "../geomentries/lines/removeReferenceLine";
|
||||
import getClosestIntersection from "../geomentries/lines/getClosestIntersection";
|
||||
import loadZones from "../geomentries/zones/loadZones";
|
||||
|
||||
const ZoneGroup = ({ zoneGroup, plane, floorPlanGroupLine, floorPlanGroupPoint, line, lines, currentLayerPoint, dragPointControls, floorPlanGroup, ReferenceLineMesh, LineCreated, isSnapped, ispreSnapped, snappedPoint, isSnappedUUID, isAngleSnapped, anglesnappedPoint }: any) => {
|
||||
const { toggleView, setToggleView } = useToggleView();
|
||||
const { deleteModels, setDeleteModels } = useDeleteModels();
|
||||
const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine();
|
||||
const { toolMode, setToolMode } = useToolMode();
|
||||
const { movePoint, setMovePoint } = useMovePoint();
|
||||
const { socket } = useSocketStore();
|
||||
const { activeLayer } = useActiveLayer();
|
||||
const { gl, raycaster, camera, pointer } = useThree();
|
||||
const { updateScene, setUpdateScene } = useUpdateScene();
|
||||
const { newLines, setNewLines } = useNewLines();
|
||||
|
||||
useEffect(() => {
|
||||
if (updateScene) {
|
||||
loadZones(lines, zoneGroup);
|
||||
setUpdateScene(false);
|
||||
}
|
||||
}, [updateScene])
|
||||
|
||||
useEffect(() => {
|
||||
if (toolMode === "Zone") {
|
||||
setDeletePointOrLine(false);
|
||||
setMovePoint(false);
|
||||
setDeleteModels(false);
|
||||
} else {
|
||||
removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint);
|
||||
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
|
||||
}
|
||||
}, [toolMode])
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
const canvasElement = gl.domElement;
|
||||
|
||||
let drag = false;
|
||||
let isLeftMouseDown = false;
|
||||
|
||||
const onMouseDown = (evt: any) => {
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown = true;
|
||||
drag = false;
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseUp = (evt: any) => {
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown = false;
|
||||
}
|
||||
}
|
||||
|
||||
const onMouseMove = () => {
|
||||
if (isLeftMouseDown) {
|
||||
drag = true;
|
||||
}
|
||||
};
|
||||
|
||||
const onContextMenu = (e: any) => {
|
||||
e.preventDefault();
|
||||
if (toolMode === "Zone") {
|
||||
removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint);
|
||||
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseClick = (evt: any) => {
|
||||
if (!plane.current || drag) return;
|
||||
const intersects = raycaster.intersectObject(plane.current, true);
|
||||
let intersectionPoint = intersects[0].point;
|
||||
const points = floorPlanGroupPoint.current?.children ?? [];
|
||||
const intersectsPoint = raycaster.intersectObjects(points, true).find(intersect => intersect.object.visible);
|
||||
let intersectsLines: any = raycaster.intersectObjects(floorPlanGroupLine.current.children, true);
|
||||
|
||||
if (intersectsLines.length > 0 && intersects && intersects.length > 0 && !intersectsPoint) {
|
||||
const lineType = intersectsLines[0].object.userData.linePoints[0][3];
|
||||
if (lineType === CONSTANTS.lineConfig.zoneName) {
|
||||
// console.log("intersected a zone line");
|
||||
|
||||
const ThroughPoint = (intersectsLines[0].object.geometry.parameters.path).getPoints(300);
|
||||
let intersection = getClosestIntersection(ThroughPoint, intersectionPoint);
|
||||
if (!intersection) return;
|
||||
const point = addPointToScene(intersection, CONSTANTS.pointConfig.zoneOuterColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, undefined, CONSTANTS.lineConfig.zoneName);
|
||||
(line.current as Types.Line).push([new THREE.Vector3(intersection.x, 0.01, intersection.z), point.uuid, activeLayer, CONSTANTS.lineConfig.zoneName,]);
|
||||
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
|
||||
lines.current.push(line.current as Types.Line);
|
||||
|
||||
const data = arrayLineToObject(line.current as Types.Line);
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
//REST
|
||||
|
||||
// setLine(organization, data.layer!, data.line!, data.type!);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const input = {
|
||||
organization: organization,
|
||||
layer: data.layer,
|
||||
line: data.line,
|
||||
type: data.type,
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
socket.emit('v1:Line:create', input);
|
||||
|
||||
setNewLines([line.current]);
|
||||
|
||||
addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.lineConfig.zoneColor, line.current, floorPlanGroupLine);
|
||||
let lastPoint = line.current[line.current.length - 1];
|
||||
line.current = [lastPoint];
|
||||
}
|
||||
}
|
||||
} else if (intersectsPoint && intersects && intersects.length > 0) {
|
||||
if (intersectsPoint.object.userData.type === CONSTANTS.lineConfig.zoneName) {
|
||||
// console.log("intersected a zone point");
|
||||
|
||||
intersectionPoint = intersectsPoint.object.position;
|
||||
(line.current as Types.Line).push([new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), intersectsPoint.object.uuid, activeLayer, CONSTANTS.lineConfig.zoneName]);
|
||||
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
|
||||
lines.current.push(line.current as Types.Line);
|
||||
|
||||
const data = arrayLineToObject(line.current as Types.Line);
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
//REST
|
||||
|
||||
// setLine(organization, data.layer!, data.line!, data.type!);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const input = {
|
||||
organization: organization,
|
||||
layer: data.layer,
|
||||
line: data.line,
|
||||
type: data.type,
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
socket.emit('v1:Line:create', input);
|
||||
|
||||
setNewLines([line.current]);
|
||||
|
||||
addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.lineConfig.zoneColor, line.current, floorPlanGroupLine);
|
||||
let lastPoint = line.current[line.current.length - 1];
|
||||
line.current = [lastPoint];
|
||||
ispreSnapped.current = false;
|
||||
isSnapped.current = false;
|
||||
}
|
||||
}
|
||||
} else if (intersects && intersects.length > 0) {
|
||||
// console.log("intersected a empty area");
|
||||
|
||||
let uuid: string = "";
|
||||
if (isAngleSnapped.current && anglesnappedPoint.current && line.current.length > 0) {
|
||||
intersectionPoint = anglesnappedPoint.current;
|
||||
const point = addPointToScene(intersectionPoint, CONSTANTS.pointConfig.zoneOuterColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, undefined, CONSTANTS.lineConfig.zoneName);
|
||||
uuid = point.uuid;
|
||||
} else if (isSnapped.current && snappedPoint.current && line.current.length > 0) {
|
||||
intersectionPoint = snappedPoint.current;
|
||||
uuid = isSnappedUUID.current!;
|
||||
} else if (ispreSnapped.current && snappedPoint.current) {
|
||||
intersectionPoint = snappedPoint.current;
|
||||
uuid = isSnappedUUID.current!;
|
||||
} else {
|
||||
const point = addPointToScene(intersectionPoint, CONSTANTS.pointConfig.zoneOuterColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, undefined, CONSTANTS.lineConfig.zoneName);
|
||||
uuid = point.uuid;
|
||||
}
|
||||
|
||||
(line.current as Types.Line).push([new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), uuid, activeLayer, CONSTANTS.lineConfig.zoneName]);
|
||||
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
|
||||
lines.current.push(line.current as Types.Line);
|
||||
|
||||
const data = arrayLineToObject(line.current as Types.Line);
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
//REST
|
||||
|
||||
// setLine(organization, data.layer!, data.line!, data.type!);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const input = {
|
||||
organization: organization,
|
||||
layer: data.layer,
|
||||
line: data.line,
|
||||
type: data.type,
|
||||
socketId: socket.id
|
||||
}
|
||||
|
||||
socket.emit('v1:Line:create', input);
|
||||
|
||||
setNewLines([line.current]);
|
||||
|
||||
addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.lineConfig.zoneColor, line.current, floorPlanGroupLine);
|
||||
let lastPoint = line.current[line.current.length - 1];
|
||||
line.current = [lastPoint];
|
||||
ispreSnapped.current = false;
|
||||
isSnapped.current = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (toolMode === 'Zone') {
|
||||
canvasElement.addEventListener("mousedown", onMouseDown);
|
||||
canvasElement.addEventListener("mouseup", onMouseUp);
|
||||
canvasElement.addEventListener("mousemove", onMouseMove);
|
||||
canvasElement.addEventListener("click", onMouseClick);
|
||||
canvasElement.addEventListener("contextmenu", onContextMenu);
|
||||
}
|
||||
|
||||
return () => {
|
||||
canvasElement.removeEventListener("mousedown", onMouseDown);
|
||||
canvasElement.removeEventListener("mouseup", onMouseUp);
|
||||
canvasElement.removeEventListener("mousemove", onMouseMove);
|
||||
canvasElement.removeEventListener("click", onMouseClick);
|
||||
canvasElement.removeEventListener("contextmenu", onContextMenu);
|
||||
};
|
||||
}, [toolMode])
|
||||
|
||||
return (
|
||||
<group ref={zoneGroup} visible={!toggleView} name="zoneGroup">
|
||||
</group>
|
||||
)
|
||||
}
|
||||
|
||||
export default ZoneGroup;
|
||||
@@ -1,142 +1,142 @@
|
||||
import * as THREE from 'three';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { useFrame } from '@react-three/fiber';
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
|
||||
import camModel from '../../assets/gltf-glb/camera face 2.gltf';
|
||||
import getActiveUsersData from '../../services/factoryBuilder/collab/getActiveUsers';
|
||||
import { useActiveUsers, useSocketStore } from '../../store/store';
|
||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Text, Html } from '@react-three/drei';
|
||||
import CollabUserIcon from './collabUserIcon';
|
||||
import image from '../../assets/image/userImage.png';
|
||||
|
||||
|
||||
const CamModelsGroup = () => {
|
||||
let navigate = useNavigate();
|
||||
const groupRef = useRef<THREE.Group>(null);
|
||||
const email = localStorage.getItem('email');
|
||||
const { activeUsers, setActiveUsers } = useActiveUsers();
|
||||
const { socket } = useSocketStore();
|
||||
const loader = new GLTFLoader();
|
||||
const dracoLoader = new DRACOLoader();
|
||||
const [cams, setCams] = useState<any[]>([]);
|
||||
const [models, setModels] = useState<Record<string, { targetPosition: THREE.Vector3; targetRotation: THREE.Euler }>>({});
|
||||
|
||||
dracoLoader.setDecoderPath('three/examples/jsm/libs/draco/gltf/');
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
useEffect(() => {
|
||||
if (!email) {
|
||||
navigate('/');
|
||||
}
|
||||
if (!socket) return;
|
||||
const organization = email!.split('@')[1].split('.')[0];
|
||||
|
||||
socket.on('userConnectRespones', (data: any) => {
|
||||
if (!groupRef.current) return;
|
||||
if (data.data.userData.email === email) return
|
||||
if (socket.id === data.socketId || organization !== data.organization) return;
|
||||
|
||||
const model = groupRef.current.getObjectByProperty('uuid', data.data.userData._id);
|
||||
if (model) {
|
||||
groupRef.current.remove(model);
|
||||
}
|
||||
loader.load(camModel, (gltf) => {
|
||||
const newModel = gltf.scene.clone();
|
||||
newModel.uuid = data.data.userData._id;
|
||||
newModel.position.set(data.data.position.x, data.data.position.y, data.data.position.z);
|
||||
newModel.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z);
|
||||
newModel.userData = data.data.userData;
|
||||
setCams((prev) => [...prev, newModel]);
|
||||
setActiveUsers([...activeUsers, data.data.userData]);
|
||||
});
|
||||
});
|
||||
|
||||
socket.on('userDisConnectRespones', (data: any) => {
|
||||
if (!groupRef.current) return;
|
||||
if (socket.id === data.socketId || organization !== data.organization) return;
|
||||
|
||||
setCams((prev) => prev.filter((cam) => cam.uuid !== data.data.userData._id));
|
||||
setActiveUsers(activeUsers.filter((user: any) => user._id !== data.data.userData._id));
|
||||
});
|
||||
|
||||
socket.on('cameraUpdateResponse', (data: any) => {
|
||||
if (!groupRef.current || socket.id === data.socketId || organization !== data.organization) return;
|
||||
|
||||
setModels((prev) => ({
|
||||
...prev,
|
||||
[data.data.userId]: {
|
||||
targetPosition: new THREE.Vector3(data.data.position.x, data.data.position.y, data.data.position.z),
|
||||
targetRotation: new THREE.Euler(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z),
|
||||
},
|
||||
}));
|
||||
});
|
||||
|
||||
return () => {
|
||||
socket.off('userConnectRespones');
|
||||
socket.off('userDisConnectRespones');
|
||||
socket.off('cameraUpdateResponse');
|
||||
};
|
||||
}, [socket]);
|
||||
|
||||
useFrame(() => {
|
||||
if (!groupRef.current) return;
|
||||
Object.keys(models).forEach((uuid) => {
|
||||
const model = groupRef.current!.getObjectByProperty('uuid', uuid);
|
||||
if (!model) return;
|
||||
|
||||
const { targetPosition, targetRotation } = models[uuid];
|
||||
model.position.lerp(targetPosition, 0.1);
|
||||
model.rotation.x = THREE.MathUtils.lerp(model.rotation.x, targetRotation.x, 0.1);
|
||||
model.rotation.y = THREE.MathUtils.lerp(model.rotation.y, targetRotation.y, 0.1);
|
||||
model.rotation.z = THREE.MathUtils.lerp(model.rotation.z, targetRotation.z, 0.1);
|
||||
});
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!groupRef.current) return;
|
||||
const organization = email!.split('@')[1].split('.')[0];
|
||||
getActiveUsersData(organization).then((data) => {
|
||||
const filteredData = data.cameraDatas.filter((camera: any) => camera.userData.email !== email);
|
||||
if (filteredData.length > 0) {
|
||||
loader.load(camModel, (gltf) => {
|
||||
const newCams = filteredData.map((cam: any) => {
|
||||
const newModel = gltf.scene.clone();
|
||||
newModel.uuid = cam.userData._id;
|
||||
newModel.position.set(cam.position.x, cam.position.y, cam.position.z);
|
||||
newModel.rotation.set(cam.rotation.x, cam.rotation.y, cam.rotation.z);
|
||||
newModel.userData = cam.userData;
|
||||
setActiveUsers([...activeUsers, cam.userData]);
|
||||
return newModel;
|
||||
});
|
||||
setCams((prev) => [...prev, ...newCams]);
|
||||
});
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<group ref={groupRef} name="Cam-Model-Group">
|
||||
{cams.map((cam, index) => (
|
||||
<primitive key={index} object={cam} >
|
||||
<Html
|
||||
as="div"
|
||||
center
|
||||
zIndexRange={[1, 0]}
|
||||
sprite
|
||||
style={{
|
||||
color: "white",
|
||||
textAlign: "center",
|
||||
fontFamily: "Arial, sans-serif",
|
||||
}}
|
||||
position={[-0.015, 0, 0.7]}>
|
||||
<CollabUserIcon color={"#ff0000"} userImage={image} userName={cam.userData.userName} />
|
||||
</Html>
|
||||
</primitive>
|
||||
))}
|
||||
</group>
|
||||
);
|
||||
};
|
||||
|
||||
export default CamModelsGroup;
|
||||
import * as THREE from 'three';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { useFrame } from '@react-three/fiber';
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
|
||||
import camModel from '../../assets/gltf-glb/camera face 2.gltf';
|
||||
import getActiveUsersData from '../../services/factoryBuilder/collab/getActiveUsers';
|
||||
import { useActiveUsers, useSocketStore } from '../../store/store';
|
||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Text, Html } from '@react-three/drei';
|
||||
import CollabUserIcon from './collabUserIcon';
|
||||
import image from '../../assets/image/userImage.png';
|
||||
|
||||
|
||||
const CamModelsGroup = () => {
|
||||
let navigate = useNavigate();
|
||||
const groupRef = useRef<THREE.Group>(null);
|
||||
const email = localStorage.getItem('email');
|
||||
const { activeUsers, setActiveUsers } = useActiveUsers();
|
||||
const { socket } = useSocketStore();
|
||||
const loader = new GLTFLoader();
|
||||
const dracoLoader = new DRACOLoader();
|
||||
const [cams, setCams] = useState<any[]>([]);
|
||||
const [models, setModels] = useState<Record<string, { targetPosition: THREE.Vector3; targetRotation: THREE.Euler }>>({});
|
||||
|
||||
dracoLoader.setDecoderPath('three/examples/jsm/libs/draco/gltf/');
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
useEffect(() => {
|
||||
if (!email) {
|
||||
navigate('/');
|
||||
}
|
||||
if (!socket) return;
|
||||
const organization = email!.split('@')[1].split('.')[0];
|
||||
|
||||
socket.on('userConnectRespones', (data: any) => {
|
||||
if (!groupRef.current) return;
|
||||
if (data.data.userData.email === email) return
|
||||
if (socket.id === data.socketId || organization !== data.organization) return;
|
||||
|
||||
const model = groupRef.current.getObjectByProperty('uuid', data.data.userData._id);
|
||||
if (model) {
|
||||
groupRef.current.remove(model);
|
||||
}
|
||||
loader.load(camModel, (gltf) => {
|
||||
const newModel = gltf.scene.clone();
|
||||
newModel.uuid = data.data.userData._id;
|
||||
newModel.position.set(data.data.position.x, data.data.position.y, data.data.position.z);
|
||||
newModel.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z);
|
||||
newModel.userData = data.data.userData;
|
||||
setCams((prev) => [...prev, newModel]);
|
||||
setActiveUsers([...activeUsers, data.data.userData]);
|
||||
});
|
||||
});
|
||||
|
||||
socket.on('userDisConnectRespones', (data: any) => {
|
||||
if (!groupRef.current) return;
|
||||
if (socket.id === data.socketId || organization !== data.organization) return;
|
||||
|
||||
setCams((prev) => prev.filter((cam) => cam.uuid !== data.data.userData._id));
|
||||
setActiveUsers(activeUsers.filter((user: any) => user._id !== data.data.userData._id));
|
||||
});
|
||||
|
||||
socket.on('cameraUpdateResponse', (data: any) => {
|
||||
if (!groupRef.current || socket.id === data.socketId || organization !== data.organization) return;
|
||||
|
||||
setModels((prev) => ({
|
||||
...prev,
|
||||
[data.data.userId]: {
|
||||
targetPosition: new THREE.Vector3(data.data.position.x, data.data.position.y, data.data.position.z),
|
||||
targetRotation: new THREE.Euler(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z),
|
||||
},
|
||||
}));
|
||||
});
|
||||
|
||||
return () => {
|
||||
socket.off('userConnectRespones');
|
||||
socket.off('userDisConnectRespones');
|
||||
socket.off('cameraUpdateResponse');
|
||||
};
|
||||
}, [socket]);
|
||||
|
||||
useFrame(() => {
|
||||
if (!groupRef.current) return;
|
||||
Object.keys(models).forEach((uuid) => {
|
||||
const model = groupRef.current!.getObjectByProperty('uuid', uuid);
|
||||
if (!model) return;
|
||||
|
||||
const { targetPosition, targetRotation } = models[uuid];
|
||||
model.position.lerp(targetPosition, 0.1);
|
||||
model.rotation.x = THREE.MathUtils.lerp(model.rotation.x, targetRotation.x, 0.1);
|
||||
model.rotation.y = THREE.MathUtils.lerp(model.rotation.y, targetRotation.y, 0.1);
|
||||
model.rotation.z = THREE.MathUtils.lerp(model.rotation.z, targetRotation.z, 0.1);
|
||||
});
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!groupRef.current) return;
|
||||
const organization = email!.split('@')[1].split('.')[0];
|
||||
getActiveUsersData(organization).then((data) => {
|
||||
const filteredData = data.cameraDatas.filter((camera: any) => camera.userData.email !== email);
|
||||
if (filteredData.length > 0) {
|
||||
loader.load(camModel, (gltf) => {
|
||||
const newCams = filteredData.map((cam: any) => {
|
||||
const newModel = gltf.scene.clone();
|
||||
newModel.uuid = cam.userData._id;
|
||||
newModel.position.set(cam.position.x, cam.position.y, cam.position.z);
|
||||
newModel.rotation.set(cam.rotation.x, cam.rotation.y, cam.rotation.z);
|
||||
newModel.userData = cam.userData;
|
||||
setActiveUsers([...activeUsers, cam.userData]);
|
||||
return newModel;
|
||||
});
|
||||
setCams((prev) => [...prev, ...newCams]);
|
||||
});
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<group ref={groupRef} name="Cam-Model-Group">
|
||||
{cams.map((cam, index) => (
|
||||
<primitive key={index} object={cam} >
|
||||
<Html
|
||||
as="div"
|
||||
center
|
||||
zIndexRange={[1, 0]}
|
||||
sprite
|
||||
style={{
|
||||
color: "white",
|
||||
textAlign: "center",
|
||||
fontFamily: "Arial, sans-serif",
|
||||
}}
|
||||
position={[-0.015, 0, 0.7]}>
|
||||
<CollabUserIcon color={"#ff0000"} userImage={image} userName={cam.userData.userName} />
|
||||
</Html>
|
||||
</primitive>
|
||||
))}
|
||||
</group>
|
||||
);
|
||||
};
|
||||
|
||||
export default CamModelsGroup;
|
||||
|
||||
@@ -1,53 +1,53 @@
|
||||
import React from "react";
|
||||
|
||||
interface CollabUserIconProps {
|
||||
color: string;
|
||||
userImage: string;
|
||||
userName: string;
|
||||
}
|
||||
|
||||
const CollabUserIcon: React.FC<CollabUserIconProps> = ({
|
||||
color,
|
||||
userImage,
|
||||
userName,
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
flexDirection: "column",
|
||||
gap: "6px",
|
||||
// transform:"translate(-20%, 0%)",
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src={userImage}
|
||||
alt={userName}
|
||||
style={{
|
||||
width: "30px",
|
||||
height: "30px",
|
||||
outline: `2px solid ${color}`,
|
||||
borderRadius: "50%",
|
||||
objectFit: 'cover'
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
padding: "3px 5px",
|
||||
backgroundColor: color,
|
||||
borderRadius: "6px",
|
||||
color: "white",
|
||||
fontSize: "14px",
|
||||
fontWeight: 400
|
||||
}}
|
||||
>
|
||||
{userName}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CollabUserIcon;
|
||||
import React from "react";
|
||||
|
||||
interface CollabUserIconProps {
|
||||
color: string;
|
||||
userImage: string;
|
||||
userName: string;
|
||||
}
|
||||
|
||||
const CollabUserIcon: React.FC<CollabUserIconProps> = ({
|
||||
color,
|
||||
userImage,
|
||||
userName,
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
flexDirection: "column",
|
||||
gap: "6px",
|
||||
// transform:"translate(-20%, 0%)",
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src={userImage}
|
||||
alt={userName}
|
||||
style={{
|
||||
width: "30px",
|
||||
height: "30px",
|
||||
outline: `2px solid ${color}`,
|
||||
borderRadius: "50%",
|
||||
objectFit: 'cover'
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
padding: "3px 5px",
|
||||
backgroundColor: color,
|
||||
borderRadius: "6px",
|
||||
color: "white",
|
||||
fontSize: "14px",
|
||||
fontWeight: 400
|
||||
}}
|
||||
>
|
||||
{userName}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CollabUserIcon;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,202 +1,202 @@
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
|
||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
|
||||
import gsap from 'gsap';
|
||||
import * as THREE from 'three';
|
||||
import * as CONSTANTS from '../../../types/world/worldConstants';
|
||||
import { toast } from 'react-toastify';
|
||||
import * as Types from "../../../types/world/worldTypes";
|
||||
import { getFloorItems } from '../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi';
|
||||
import { initializeDB, retrieveGLTF, storeGLTF } from '../../../utils/indexDB/idbUtils';
|
||||
import { getCamera } from '../../../services/factoryBuilder/camera/getCameraApi';
|
||||
|
||||
async function loadInitialFloorItems(
|
||||
itemsGroup: Types.RefGroup,
|
||||
setFloorItems: Types.setFloorItemSetState
|
||||
): Promise<void> {
|
||||
if (!itemsGroup.current) return;
|
||||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||
const email = localStorage.getItem('email');
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
const items = await getFloorItems(organization);
|
||||
localStorage.setItem("FloorItems", JSON.stringify(items));
|
||||
await initializeDB();
|
||||
|
||||
if (items) {
|
||||
const storedFloorItems: Types.FloorItems = items;
|
||||
const loader = new GLTFLoader();
|
||||
const dracoLoader = new DRACOLoader();
|
||||
|
||||
dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/');
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
let modelsLoaded = 0;
|
||||
const modelsToLoad = storedFloorItems.length;
|
||||
|
||||
const camData = await getCamera(organization, localStorage.getItem('userId')!);
|
||||
let storedPosition;
|
||||
if (camData && camData.position) {
|
||||
storedPosition = camData?.position;
|
||||
} else {
|
||||
storedPosition = new THREE.Vector3(0, 40, 30);
|
||||
}
|
||||
if (!storedPosition) return;
|
||||
const cameraPosition = new THREE.Vector3(storedPosition.x, storedPosition.y, storedPosition.z);
|
||||
|
||||
storedFloorItems.sort((a, b) => {
|
||||
const aPosition = new THREE.Vector3(a.position[0], a.position[1], a.position[2]);
|
||||
const bPosition = new THREE.Vector3(b.position[0], b.position[1], b.position[2]);
|
||||
return cameraPosition.distanceTo(aPosition) - cameraPosition.distanceTo(bPosition);
|
||||
});
|
||||
|
||||
for (const item of storedFloorItems) {
|
||||
if (!item.modelfileID) return;
|
||||
const itemPosition = new THREE.Vector3(item.position[0], item.position[1], item.position[2]);
|
||||
let storedPosition;
|
||||
if (localStorage.getItem("cameraPosition")) {
|
||||
storedPosition = JSON.parse(localStorage.getItem("cameraPosition")!);
|
||||
} else {
|
||||
storedPosition = new THREE.Vector3(0, 40, 30);
|
||||
}
|
||||
|
||||
const cameraPosition = new THREE.Vector3(storedPosition.x, storedPosition.y, storedPosition.z);
|
||||
|
||||
if (cameraPosition.distanceTo(itemPosition) < 50) {
|
||||
await new Promise<void>(async (resolve) => {
|
||||
|
||||
// Check Three.js Cache
|
||||
const cachedModel = THREE.Cache.get(item.modelfileID!);
|
||||
if (cachedModel) {
|
||||
// console.log(`[Cache] Fetching ${item.modelname}`);
|
||||
processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, setFloorItems);
|
||||
modelsLoaded++;
|
||||
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check IndexedDB
|
||||
const indexedDBModel = await retrieveGLTF(item.modelfileID!);
|
||||
if (indexedDBModel) {
|
||||
// console.log(`[IndexedDB] Fetching ${item.modelname}`);
|
||||
const blobUrl = URL.createObjectURL(indexedDBModel);
|
||||
loader.load(
|
||||
blobUrl,
|
||||
(gltf) => {
|
||||
URL.revokeObjectURL(blobUrl);
|
||||
THREE.Cache.remove(blobUrl);
|
||||
THREE.Cache.add(item.modelfileID!, gltf);
|
||||
processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems);
|
||||
modelsLoaded++;
|
||||
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
|
||||
},
|
||||
undefined,
|
||||
(error) => {
|
||||
toast.error(`[IndexedDB] Error loading ${item.modelname}:`);
|
||||
URL.revokeObjectURL(blobUrl);
|
||||
resolve();
|
||||
}
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch from Backend
|
||||
// console.log(`[Backend] Fetching ${item.modelname}`);
|
||||
const modelUrl = `${url_Backend_dwinzo}/api/v1/AssetFile/${item.modelfileID!}`;
|
||||
loader.load(
|
||||
modelUrl,
|
||||
async (gltf) => {
|
||||
const modelBlob = await fetch(modelUrl).then((res) => res.blob());
|
||||
await storeGLTF(item.modelfileID!, modelBlob);
|
||||
THREE.Cache.add(item.modelfileID!, gltf);
|
||||
processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems);
|
||||
modelsLoaded++;
|
||||
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
|
||||
},
|
||||
undefined,
|
||||
(error) => {
|
||||
toast.error(`[Backend] Error loading ${item.modelname}:`);
|
||||
resolve();
|
||||
}
|
||||
);
|
||||
});
|
||||
} else {
|
||||
// console.log(`Item ${item.modelname} is not near`);
|
||||
setFloorItems((prevItems) => [
|
||||
...(prevItems || []),
|
||||
{
|
||||
modeluuid: item.modeluuid,
|
||||
modelname: item.modelname,
|
||||
position: item.position,
|
||||
rotation: item.rotation,
|
||||
modelfileID: item.modelfileID,
|
||||
isLocked: item.isLocked,
|
||||
isVisible: item.isVisible,
|
||||
},
|
||||
]);
|
||||
modelsLoaded++;
|
||||
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, () => { });
|
||||
}
|
||||
}
|
||||
|
||||
// Dispose loader after all models
|
||||
dracoLoader.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function processLoadedModel(
|
||||
gltf: any,
|
||||
item: Types.FloorItemType,
|
||||
itemsGroup: Types.RefGroup,
|
||||
setFloorItems: Types.setFloorItemSetState
|
||||
) {
|
||||
const model = gltf;
|
||||
model.uuid = item.modeluuid;
|
||||
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
|
||||
model.userData = { name: item.modelname, modelId: item.modelfileID };
|
||||
model.position.set(...item.position);
|
||||
model.rotation.set(item.rotation.x, item.rotation.y, item.rotation.z);
|
||||
|
||||
model.traverse((child: any) => {
|
||||
if (child.isMesh) {
|
||||
// Clone the material to ensure changes are independent
|
||||
// child.material = child.material.clone();
|
||||
|
||||
child.castShadow = true;
|
||||
child.receiveShadow = true;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
itemsGroup?.current?.add(model);
|
||||
setFloorItems((prevItems) => [
|
||||
...(prevItems || []),
|
||||
{
|
||||
modeluuid: item.modeluuid,
|
||||
modelname: item.modelname,
|
||||
position: item.position,
|
||||
rotation: item.rotation,
|
||||
modelfileID: item.modelfileID,
|
||||
isLocked: item.isLocked,
|
||||
isVisible: item.isVisible,
|
||||
},
|
||||
]);
|
||||
|
||||
gsap.to(model.position, { y: item.position[1], duration: 1.5, ease: 'power2.out' });
|
||||
gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: 'power2.out' });
|
||||
}
|
||||
|
||||
function checkLoadingCompletion(
|
||||
modelsLoaded: number,
|
||||
modelsToLoad: number,
|
||||
dracoLoader: DRACOLoader,
|
||||
resolve: () => void
|
||||
) {
|
||||
if (modelsLoaded === modelsToLoad) {
|
||||
toast.success("Models Loaded!");
|
||||
dracoLoader.dispose();
|
||||
}
|
||||
resolve();
|
||||
}
|
||||
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
|
||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
|
||||
import gsap from 'gsap';
|
||||
import * as THREE from 'three';
|
||||
import * as CONSTANTS from '../../../types/world/worldConstants';
|
||||
import { toast } from 'react-toastify';
|
||||
import * as Types from "../../../types/world/worldTypes";
|
||||
import { getFloorItems } from '../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi';
|
||||
import { initializeDB, retrieveGLTF, storeGLTF } from '../../../utils/indexDB/idbUtils';
|
||||
import { getCamera } from '../../../services/factoryBuilder/camera/getCameraApi';
|
||||
|
||||
async function loadInitialFloorItems(
|
||||
itemsGroup: Types.RefGroup,
|
||||
setFloorItems: Types.setFloorItemSetState
|
||||
): Promise<void> {
|
||||
if (!itemsGroup.current) return;
|
||||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||
const email = localStorage.getItem('email');
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
const items = await getFloorItems(organization);
|
||||
localStorage.setItem("FloorItems", JSON.stringify(items));
|
||||
await initializeDB();
|
||||
|
||||
if (items) {
|
||||
const storedFloorItems: Types.FloorItems = items;
|
||||
const loader = new GLTFLoader();
|
||||
const dracoLoader = new DRACOLoader();
|
||||
|
||||
dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/');
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
let modelsLoaded = 0;
|
||||
const modelsToLoad = storedFloorItems.length;
|
||||
|
||||
const camData = await getCamera(organization, localStorage.getItem('userId')!);
|
||||
let storedPosition;
|
||||
if (camData && camData.position) {
|
||||
storedPosition = camData?.position;
|
||||
} else {
|
||||
storedPosition = new THREE.Vector3(0, 40, 30);
|
||||
}
|
||||
if (!storedPosition) return;
|
||||
const cameraPosition = new THREE.Vector3(storedPosition.x, storedPosition.y, storedPosition.z);
|
||||
|
||||
storedFloorItems.sort((a, b) => {
|
||||
const aPosition = new THREE.Vector3(a.position[0], a.position[1], a.position[2]);
|
||||
const bPosition = new THREE.Vector3(b.position[0], b.position[1], b.position[2]);
|
||||
return cameraPosition.distanceTo(aPosition) - cameraPosition.distanceTo(bPosition);
|
||||
});
|
||||
|
||||
for (const item of storedFloorItems) {
|
||||
if (!item.modelfileID) return;
|
||||
const itemPosition = new THREE.Vector3(item.position[0], item.position[1], item.position[2]);
|
||||
let storedPosition;
|
||||
if (localStorage.getItem("cameraPosition")) {
|
||||
storedPosition = JSON.parse(localStorage.getItem("cameraPosition")!);
|
||||
} else {
|
||||
storedPosition = new THREE.Vector3(0, 40, 30);
|
||||
}
|
||||
|
||||
const cameraPosition = new THREE.Vector3(storedPosition.x, storedPosition.y, storedPosition.z);
|
||||
|
||||
if (cameraPosition.distanceTo(itemPosition) < 50) {
|
||||
await new Promise<void>(async (resolve) => {
|
||||
|
||||
// Check Three.js Cache
|
||||
const cachedModel = THREE.Cache.get(item.modelfileID!);
|
||||
if (cachedModel) {
|
||||
// console.log(`[Cache] Fetching ${item.modelname}`);
|
||||
processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, setFloorItems);
|
||||
modelsLoaded++;
|
||||
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check IndexedDB
|
||||
const indexedDBModel = await retrieveGLTF(item.modelfileID!);
|
||||
if (indexedDBModel) {
|
||||
// console.log(`[IndexedDB] Fetching ${item.modelname}`);
|
||||
const blobUrl = URL.createObjectURL(indexedDBModel);
|
||||
loader.load(
|
||||
blobUrl,
|
||||
(gltf) => {
|
||||
URL.revokeObjectURL(blobUrl);
|
||||
THREE.Cache.remove(blobUrl);
|
||||
THREE.Cache.add(item.modelfileID!, gltf);
|
||||
processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems);
|
||||
modelsLoaded++;
|
||||
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
|
||||
},
|
||||
undefined,
|
||||
(error) => {
|
||||
toast.error(`[IndexedDB] Error loading ${item.modelname}:`);
|
||||
URL.revokeObjectURL(blobUrl);
|
||||
resolve();
|
||||
}
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch from Backend
|
||||
// console.log(`[Backend] Fetching ${item.modelname}`);
|
||||
const modelUrl = `${url_Backend_dwinzo}/api/v1/AssetFile/${item.modelfileID!}`;
|
||||
loader.load(
|
||||
modelUrl,
|
||||
async (gltf) => {
|
||||
const modelBlob = await fetch(modelUrl).then((res) => res.blob());
|
||||
await storeGLTF(item.modelfileID!, modelBlob);
|
||||
THREE.Cache.add(item.modelfileID!, gltf);
|
||||
processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems);
|
||||
modelsLoaded++;
|
||||
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
|
||||
},
|
||||
undefined,
|
||||
(error) => {
|
||||
toast.error(`[Backend] Error loading ${item.modelname}:`);
|
||||
resolve();
|
||||
}
|
||||
);
|
||||
});
|
||||
} else {
|
||||
// console.log(`Item ${item.modelname} is not near`);
|
||||
setFloorItems((prevItems) => [
|
||||
...(prevItems || []),
|
||||
{
|
||||
modeluuid: item.modeluuid,
|
||||
modelname: item.modelname,
|
||||
position: item.position,
|
||||
rotation: item.rotation,
|
||||
modelfileID: item.modelfileID,
|
||||
isLocked: item.isLocked,
|
||||
isVisible: item.isVisible,
|
||||
},
|
||||
]);
|
||||
modelsLoaded++;
|
||||
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, () => { });
|
||||
}
|
||||
}
|
||||
|
||||
// Dispose loader after all models
|
||||
dracoLoader.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function processLoadedModel(
|
||||
gltf: any,
|
||||
item: Types.FloorItemType,
|
||||
itemsGroup: Types.RefGroup,
|
||||
setFloorItems: Types.setFloorItemSetState
|
||||
) {
|
||||
const model = gltf;
|
||||
model.uuid = item.modeluuid;
|
||||
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
|
||||
model.userData = { name: item.modelname, modelId: item.modelfileID };
|
||||
model.position.set(...item.position);
|
||||
model.rotation.set(item.rotation.x, item.rotation.y, item.rotation.z);
|
||||
|
||||
model.traverse((child: any) => {
|
||||
if (child.isMesh) {
|
||||
// Clone the material to ensure changes are independent
|
||||
// child.material = child.material.clone();
|
||||
|
||||
child.castShadow = true;
|
||||
child.receiveShadow = true;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
itemsGroup?.current?.add(model);
|
||||
setFloorItems((prevItems) => [
|
||||
...(prevItems || []),
|
||||
{
|
||||
modeluuid: item.modeluuid,
|
||||
modelname: item.modelname,
|
||||
position: item.position,
|
||||
rotation: item.rotation,
|
||||
modelfileID: item.modelfileID,
|
||||
isLocked: item.isLocked,
|
||||
isVisible: item.isVisible,
|
||||
},
|
||||
]);
|
||||
|
||||
gsap.to(model.position, { y: item.position[1], duration: 1.5, ease: 'power2.out' });
|
||||
gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: 'power2.out' });
|
||||
}
|
||||
|
||||
function checkLoadingCompletion(
|
||||
modelsLoaded: number,
|
||||
modelsToLoad: number,
|
||||
dracoLoader: DRACOLoader,
|
||||
resolve: () => void
|
||||
) {
|
||||
if (modelsLoaded === modelsToLoad) {
|
||||
toast.success("Models Loaded!");
|
||||
dracoLoader.dispose();
|
||||
}
|
||||
resolve();
|
||||
}
|
||||
|
||||
export default loadInitialFloorItems;
|
||||
@@ -1,30 +1,30 @@
|
||||
import addLineToScene from '../../builder/geomentries/lines/addLineToScene';
|
||||
import * as CONSTANTS from '../../../types/world/worldConstants';
|
||||
import * as Types from "../../../types/world/worldTypes";
|
||||
|
||||
function loadInitialLine(
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
lines: Types.RefLines
|
||||
): void {
|
||||
|
||||
if (!floorPlanGroupLine.current) return
|
||||
|
||||
////////// Load the Lines initially if there are any //////////
|
||||
|
||||
floorPlanGroupLine.current.children = [];
|
||||
lines.current.forEach((line) => {
|
||||
let colour;
|
||||
if (line[0][3] && line[1][3] === CONSTANTS.lineConfig.wallName) {
|
||||
colour = CONSTANTS.lineConfig.wallColor;
|
||||
} else if (line[0][3] && line[1][3] === CONSTANTS.lineConfig.floorName) {
|
||||
colour = CONSTANTS.lineConfig.floorColor;
|
||||
} else if (line[0][3] && line[1][3] === CONSTANTS.lineConfig.aisleName) {
|
||||
colour = CONSTANTS.lineConfig.aisleColor;
|
||||
}
|
||||
if (colour) {
|
||||
addLineToScene(line[0][0], line[1][0], colour, line, floorPlanGroupLine);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default loadInitialLine;
|
||||
import addLineToScene from '../../builder/geomentries/lines/addLineToScene';
|
||||
import * as CONSTANTS from '../../../types/world/worldConstants';
|
||||
import * as Types from "../../../types/world/worldTypes";
|
||||
|
||||
function loadInitialLine(
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
lines: Types.RefLines
|
||||
): void {
|
||||
|
||||
if (!floorPlanGroupLine.current) return
|
||||
|
||||
////////// Load the Lines initially if there are any //////////
|
||||
|
||||
floorPlanGroupLine.current.children = [];
|
||||
lines.current.forEach((line) => {
|
||||
let colour;
|
||||
if (line[0][3] && line[1][3] === CONSTANTS.lineConfig.wallName) {
|
||||
colour = CONSTANTS.lineConfig.wallColor;
|
||||
} else if (line[0][3] && line[1][3] === CONSTANTS.lineConfig.floorName) {
|
||||
colour = CONSTANTS.lineConfig.floorColor;
|
||||
} else if (line[0][3] && line[1][3] === CONSTANTS.lineConfig.aisleName) {
|
||||
colour = CONSTANTS.lineConfig.aisleColor;
|
||||
}
|
||||
if (colour) {
|
||||
addLineToScene(line[0][0], line[1][0], colour, line, floorPlanGroupLine);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default loadInitialLine;
|
||||
|
||||
@@ -1,87 +1,87 @@
|
||||
import * as THREE from 'three';
|
||||
|
||||
import * as CONSTANTS from '../../../types/world/worldConstants';
|
||||
import * as Types from "../../../types/world/worldTypes";
|
||||
|
||||
////////// Load the Boxes initially if there are any //////////
|
||||
|
||||
function loadInitialPoint(
|
||||
lines: Types.RefLines,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
currentLayerPoint: Types.RefMeshArray,
|
||||
dragPointControls: Types.RefDragControl
|
||||
): void {
|
||||
|
||||
if (!floorPlanGroupPoint.current) return
|
||||
|
||||
floorPlanGroupPoint.current.children = [];
|
||||
currentLayerPoint.current = [];
|
||||
lines.current.forEach((line) => {
|
||||
const colour = getPointColor(line[0][3]);
|
||||
line.forEach((pointData) => {
|
||||
const [point, id] = pointData;
|
||||
|
||||
/////////// Check if a box with this id already exists //////////
|
||||
|
||||
const existingBox = floorPlanGroupPoint.current?.getObjectByProperty('uuid', id);
|
||||
if (existingBox) {
|
||||
return;
|
||||
}
|
||||
|
||||
const geometry = new THREE.BoxGeometry(...CONSTANTS.pointConfig.boxScale);
|
||||
const material = new THREE.ShaderMaterial({
|
||||
uniforms: {
|
||||
uColor: { value: new THREE.Color(colour) }, // Blue color for the border
|
||||
uInnerColor: { value: new THREE.Color(CONSTANTS.pointConfig.defaultInnerColor) }, // White color for the inner square
|
||||
},
|
||||
vertexShader: `
|
||||
varying vec2 vUv;
|
||||
|
||||
void main() {
|
||||
vUv = uv;
|
||||
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
||||
}
|
||||
`,
|
||||
fragmentShader: `
|
||||
varying vec2 vUv;
|
||||
uniform vec3 uColor;
|
||||
uniform vec3 uInnerColor;
|
||||
|
||||
void main() {
|
||||
// Define the size of the white square as a proportion of the face
|
||||
float borderThickness = 0.2; // Adjust this value for border thickness
|
||||
if (vUv.x > borderThickness && vUv.x < 1.0 - borderThickness &&
|
||||
vUv.y > borderThickness && vUv.y < 1.0 - borderThickness) {
|
||||
gl_FragColor = vec4(uInnerColor, 1.0); // White inner square
|
||||
} else {
|
||||
gl_FragColor = vec4(uColor, 1.0); // Blue border
|
||||
}
|
||||
}
|
||||
`,
|
||||
});
|
||||
const box = new THREE.Mesh(geometry, material);
|
||||
box.name = "point";
|
||||
box.uuid = id;
|
||||
box.userData = { type: line[0][3], color: colour };
|
||||
box.position.set(point.x, point.y, point.z);
|
||||
currentLayerPoint.current.push(box);
|
||||
|
||||
floorPlanGroupPoint.current?.add(box);
|
||||
});
|
||||
});
|
||||
|
||||
function getPointColor(lineType: string | undefined): string {
|
||||
switch (lineType) {
|
||||
case CONSTANTS.lineConfig.wallName: return CONSTANTS.pointConfig.wallOuterColor;
|
||||
case CONSTANTS.lineConfig.floorName: return CONSTANTS.pointConfig.floorOuterColor;
|
||||
case CONSTANTS.lineConfig.aisleName: return CONSTANTS.pointConfig.aisleOuterColor;
|
||||
default: return CONSTANTS.pointConfig.defaultOuterColor;
|
||||
}
|
||||
}
|
||||
|
||||
if (dragPointControls.current) {
|
||||
dragPointControls.current!.objects = currentLayerPoint.current;
|
||||
}
|
||||
}
|
||||
|
||||
export default loadInitialPoint;
|
||||
import * as THREE from 'three';
|
||||
|
||||
import * as CONSTANTS from '../../../types/world/worldConstants';
|
||||
import * as Types from "../../../types/world/worldTypes";
|
||||
|
||||
////////// Load the Boxes initially if there are any //////////
|
||||
|
||||
function loadInitialPoint(
|
||||
lines: Types.RefLines,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
currentLayerPoint: Types.RefMeshArray,
|
||||
dragPointControls: Types.RefDragControl
|
||||
): void {
|
||||
|
||||
if (!floorPlanGroupPoint.current) return
|
||||
|
||||
floorPlanGroupPoint.current.children = [];
|
||||
currentLayerPoint.current = [];
|
||||
lines.current.forEach((line) => {
|
||||
const colour = getPointColor(line[0][3]);
|
||||
line.forEach((pointData) => {
|
||||
const [point, id] = pointData;
|
||||
|
||||
/////////// Check if a box with this id already exists //////////
|
||||
|
||||
const existingBox = floorPlanGroupPoint.current?.getObjectByProperty('uuid', id);
|
||||
if (existingBox) {
|
||||
return;
|
||||
}
|
||||
|
||||
const geometry = new THREE.BoxGeometry(...CONSTANTS.pointConfig.boxScale);
|
||||
const material = new THREE.ShaderMaterial({
|
||||
uniforms: {
|
||||
uColor: { value: new THREE.Color(colour) }, // Blue color for the border
|
||||
uInnerColor: { value: new THREE.Color(CONSTANTS.pointConfig.defaultInnerColor) }, // White color for the inner square
|
||||
},
|
||||
vertexShader: `
|
||||
varying vec2 vUv;
|
||||
|
||||
void main() {
|
||||
vUv = uv;
|
||||
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
||||
}
|
||||
`,
|
||||
fragmentShader: `
|
||||
varying vec2 vUv;
|
||||
uniform vec3 uColor;
|
||||
uniform vec3 uInnerColor;
|
||||
|
||||
void main() {
|
||||
// Define the size of the white square as a proportion of the face
|
||||
float borderThickness = 0.2; // Adjust this value for border thickness
|
||||
if (vUv.x > borderThickness && vUv.x < 1.0 - borderThickness &&
|
||||
vUv.y > borderThickness && vUv.y < 1.0 - borderThickness) {
|
||||
gl_FragColor = vec4(uInnerColor, 1.0); // White inner square
|
||||
} else {
|
||||
gl_FragColor = vec4(uColor, 1.0); // Blue border
|
||||
}
|
||||
}
|
||||
`,
|
||||
});
|
||||
const box = new THREE.Mesh(geometry, material);
|
||||
box.name = "point";
|
||||
box.uuid = id;
|
||||
box.userData = { type: line[0][3], color: colour };
|
||||
box.position.set(point.x, point.y, point.z);
|
||||
currentLayerPoint.current.push(box);
|
||||
|
||||
floorPlanGroupPoint.current?.add(box);
|
||||
});
|
||||
});
|
||||
|
||||
function getPointColor(lineType: string | undefined): string {
|
||||
switch (lineType) {
|
||||
case CONSTANTS.lineConfig.wallName: return CONSTANTS.pointConfig.wallOuterColor;
|
||||
case CONSTANTS.lineConfig.floorName: return CONSTANTS.pointConfig.floorOuterColor;
|
||||
case CONSTANTS.lineConfig.aisleName: return CONSTANTS.pointConfig.aisleOuterColor;
|
||||
default: return CONSTANTS.pointConfig.defaultOuterColor;
|
||||
}
|
||||
}
|
||||
|
||||
if (dragPointControls.current) {
|
||||
dragPointControls.current!.objects = currentLayerPoint.current;
|
||||
}
|
||||
}
|
||||
|
||||
export default loadInitialPoint;
|
||||
|
||||
@@ -1,54 +1,54 @@
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
|
||||
|
||||
import * as Types from "../../../types/world/worldTypes";
|
||||
import { getWallItems } from '../../../services/factoryBuilder/assest/wallAsset/getWallItemsApi';
|
||||
|
||||
////////// Load the Wall Items's intially of there is any //////////
|
||||
|
||||
async function loadInitialWallItems(
|
||||
setWallItems: Types.setWallItemSetState,
|
||||
AssetConfigurations: Types.AssetConfigurations
|
||||
): Promise<void> {
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
const items = await getWallItems(organization);
|
||||
|
||||
localStorage.setItem("WallItems", JSON.stringify(items));
|
||||
if (items.length > 0) {
|
||||
const storedWallItems: Types.wallItems = items;
|
||||
|
||||
const loadedWallItems = await Promise.all(storedWallItems.map(async (item) => {
|
||||
const loader = new GLTFLoader();
|
||||
return new Promise<Types.WallItem>((resolve) => {
|
||||
loader.load(AssetConfigurations[item.modelname!].modelUrl, (gltf) => {
|
||||
const model = gltf.scene;
|
||||
model.uuid = item.modeluuid!;
|
||||
|
||||
model.children[0].children.forEach((child: any) => {
|
||||
if (child.name !== "CSG_REF") {
|
||||
child.castShadow = true;
|
||||
child.receiveShadow = true;
|
||||
}
|
||||
});
|
||||
|
||||
resolve({
|
||||
type: item.type,
|
||||
model: model,
|
||||
modelname: item.modelname,
|
||||
scale: item.scale,
|
||||
csgscale: item.csgscale,
|
||||
csgposition: item.csgposition,
|
||||
position: item.position,
|
||||
quaternion: item.quaternion,
|
||||
});
|
||||
});
|
||||
});
|
||||
}));
|
||||
|
||||
setWallItems(loadedWallItems);
|
||||
}
|
||||
}
|
||||
|
||||
export default loadInitialWallItems;
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
|
||||
|
||||
import * as Types from "../../../types/world/worldTypes";
|
||||
import { getWallItems } from '../../../services/factoryBuilder/assest/wallAsset/getWallItemsApi';
|
||||
|
||||
////////// Load the Wall Items's intially of there is any //////////
|
||||
|
||||
async function loadInitialWallItems(
|
||||
setWallItems: Types.setWallItemSetState,
|
||||
AssetConfigurations: Types.AssetConfigurations
|
||||
): Promise<void> {
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
const items = await getWallItems(organization);
|
||||
|
||||
localStorage.setItem("WallItems", JSON.stringify(items));
|
||||
if (items.length > 0) {
|
||||
const storedWallItems: Types.wallItems = items;
|
||||
|
||||
const loadedWallItems = await Promise.all(storedWallItems.map(async (item) => {
|
||||
const loader = new GLTFLoader();
|
||||
return new Promise<Types.WallItem>((resolve) => {
|
||||
loader.load(AssetConfigurations[item.modelname!].modelUrl, (gltf) => {
|
||||
const model = gltf.scene;
|
||||
model.uuid = item.modeluuid!;
|
||||
|
||||
model.children[0].children.forEach((child: any) => {
|
||||
if (child.name !== "CSG_REF") {
|
||||
child.castShadow = true;
|
||||
child.receiveShadow = true;
|
||||
}
|
||||
});
|
||||
|
||||
resolve({
|
||||
type: item.type,
|
||||
model: model,
|
||||
modelname: item.modelname,
|
||||
scale: item.scale,
|
||||
csgscale: item.csgscale,
|
||||
csgposition: item.csgposition,
|
||||
position: item.position,
|
||||
quaternion: item.quaternion,
|
||||
});
|
||||
});
|
||||
});
|
||||
}));
|
||||
|
||||
setWallItems(loadedWallItems);
|
||||
}
|
||||
}
|
||||
|
||||
export default loadInitialWallItems;
|
||||
|
||||
@@ -1,89 +1,89 @@
|
||||
import { useFrame, useThree } from '@react-three/fiber';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import * as CONSTANTS from '../../../types/world/worldConstants';
|
||||
import { useCamMode, useToggleView } from '../../../store/store';
|
||||
import { useKeyboardControls } from '@react-three/drei';
|
||||
import switchToThirdPerson from './switchToThirdPerson';
|
||||
import switchToFirstPerson from './switchToFirstPerson';
|
||||
|
||||
const CamMode: React.FC = () => {
|
||||
const { camMode, setCamMode } = useCamMode();
|
||||
const [, get] = useKeyboardControls()
|
||||
const [isTransitioning, setIsTransitioning] = useState(false);
|
||||
const state: any = useThree();
|
||||
const { toggleView } = useToggleView();
|
||||
|
||||
useEffect(() => {
|
||||
const handlePointerLockChange = async () => {
|
||||
if (document.pointerLockElement && !toggleView) {
|
||||
// console.log('Pointer is locked');
|
||||
} else {
|
||||
// console.log('Pointer is unlocked');
|
||||
if (camMode === "FirstPerson" && !toggleView) {
|
||||
setCamMode("ThirdPerson");
|
||||
await switchToThirdPerson(state.controls, state.camera);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('pointerlockchange', handlePointerLockChange);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('pointerlockchange', handlePointerLockChange);
|
||||
};
|
||||
}, [camMode, toggleView, setCamMode, state.controls, state.camera]);
|
||||
|
||||
useEffect(() => {
|
||||
const handleKeyPress = async (event: any) => {
|
||||
if (!state.controls) return;
|
||||
|
||||
if (event.key === "/" && !isTransitioning && !toggleView) {
|
||||
setIsTransitioning(true);
|
||||
state.controls.mouseButtons.left = CONSTANTS.controlsTransition.leftMouse;
|
||||
state.controls.mouseButtons.right = CONSTANTS.controlsTransition.rightMouse;
|
||||
state.controls.mouseButtons.wheel = CONSTANTS.controlsTransition.wheelMouse;
|
||||
state.controls.mouseButtons.middle = CONSTANTS.controlsTransition.middleMouse;
|
||||
|
||||
if (camMode === 'ThirdPerson') {
|
||||
setCamMode("FirstPerson");
|
||||
await switchToFirstPerson(state.controls, state.camera);
|
||||
} else if (camMode === "FirstPerson") {
|
||||
setCamMode("ThirdPerson");
|
||||
await switchToThirdPerson(state.controls, state.camera);
|
||||
}
|
||||
|
||||
setIsTransitioning(false);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("keydown", handleKeyPress);
|
||||
return () => {
|
||||
window.removeEventListener("keydown", handleKeyPress);
|
||||
};
|
||||
}, [camMode, isTransitioning, toggleView, state.controls, state.camera, setCamMode]);
|
||||
|
||||
useFrame(() => {
|
||||
const { forward, backward, left, right } = get();
|
||||
if (!state.controls) return
|
||||
if (!state.controls || camMode === "ThirdPerson" || !document.pointerLockElement) return;
|
||||
|
||||
if (forward) {
|
||||
state.controls.forward(CONSTANTS.firstPersonControls.forwardSpeed, true)
|
||||
}
|
||||
if (backward) {
|
||||
state.controls.forward(CONSTANTS.firstPersonControls.backwardSpeed, true)
|
||||
}
|
||||
if (left) {
|
||||
state.controls.truck(CONSTANTS.firstPersonControls.leftSpeed, 0, true)
|
||||
}
|
||||
if (right) {
|
||||
state.controls.truck(CONSTANTS.firstPersonControls.rightSpeed, 0, true)
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<></>
|
||||
);
|
||||
};
|
||||
|
||||
import { useFrame, useThree } from '@react-three/fiber';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import * as CONSTANTS from '../../../types/world/worldConstants';
|
||||
import { useCamMode, useToggleView } from '../../../store/store';
|
||||
import { useKeyboardControls } from '@react-three/drei';
|
||||
import switchToThirdPerson from './switchToThirdPerson';
|
||||
import switchToFirstPerson from './switchToFirstPerson';
|
||||
|
||||
const CamMode: React.FC = () => {
|
||||
const { camMode, setCamMode } = useCamMode();
|
||||
const [, get] = useKeyboardControls()
|
||||
const [isTransitioning, setIsTransitioning] = useState(false);
|
||||
const state: any = useThree();
|
||||
const { toggleView } = useToggleView();
|
||||
|
||||
useEffect(() => {
|
||||
const handlePointerLockChange = async () => {
|
||||
if (document.pointerLockElement && !toggleView) {
|
||||
// console.log('Pointer is locked');
|
||||
} else {
|
||||
// console.log('Pointer is unlocked');
|
||||
if (camMode === "FirstPerson" && !toggleView) {
|
||||
setCamMode("ThirdPerson");
|
||||
await switchToThirdPerson(state.controls, state.camera);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('pointerlockchange', handlePointerLockChange);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('pointerlockchange', handlePointerLockChange);
|
||||
};
|
||||
}, [camMode, toggleView, setCamMode, state.controls, state.camera]);
|
||||
|
||||
useEffect(() => {
|
||||
const handleKeyPress = async (event: any) => {
|
||||
if (!state.controls) return;
|
||||
|
||||
if (event.key === "/" && !isTransitioning && !toggleView) {
|
||||
setIsTransitioning(true);
|
||||
state.controls.mouseButtons.left = CONSTANTS.controlsTransition.leftMouse;
|
||||
state.controls.mouseButtons.right = CONSTANTS.controlsTransition.rightMouse;
|
||||
state.controls.mouseButtons.wheel = CONSTANTS.controlsTransition.wheelMouse;
|
||||
state.controls.mouseButtons.middle = CONSTANTS.controlsTransition.middleMouse;
|
||||
|
||||
if (camMode === 'ThirdPerson') {
|
||||
setCamMode("FirstPerson");
|
||||
await switchToFirstPerson(state.controls, state.camera);
|
||||
} else if (camMode === "FirstPerson") {
|
||||
setCamMode("ThirdPerson");
|
||||
await switchToThirdPerson(state.controls, state.camera);
|
||||
}
|
||||
|
||||
setIsTransitioning(false);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("keydown", handleKeyPress);
|
||||
return () => {
|
||||
window.removeEventListener("keydown", handleKeyPress);
|
||||
};
|
||||
}, [camMode, isTransitioning, toggleView, state.controls, state.camera, setCamMode]);
|
||||
|
||||
useFrame(() => {
|
||||
const { forward, backward, left, right } = get();
|
||||
if (!state.controls) return
|
||||
if (!state.controls || camMode === "ThirdPerson" || !document.pointerLockElement) return;
|
||||
|
||||
if (forward) {
|
||||
state.controls.forward(CONSTANTS.firstPersonControls.forwardSpeed, true)
|
||||
}
|
||||
if (backward) {
|
||||
state.controls.forward(CONSTANTS.firstPersonControls.backwardSpeed, true)
|
||||
}
|
||||
if (left) {
|
||||
state.controls.truck(CONSTANTS.firstPersonControls.leftSpeed, 0, true)
|
||||
}
|
||||
if (right) {
|
||||
state.controls.truck(CONSTANTS.firstPersonControls.rightSpeed, 0, true)
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<></>
|
||||
);
|
||||
};
|
||||
|
||||
export default CamMode;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user