Merge remote-tracking branch 'origin/dev-r3f-wall' into dev-refactor
This commit is contained in:
@@ -33,7 +33,7 @@ import {
|
|||||||
import { useProductContext } from "../../../modules/simulation/products/productContext";
|
import { useProductContext } from "../../../modules/simulation/products/productContext";
|
||||||
import RegularDropDown from "../../ui/inputs/RegularDropDown";
|
import RegularDropDown from "../../ui/inputs/RegularDropDown";
|
||||||
import RenameTooltip from "../../ui/features/RenameTooltip";
|
import RenameTooltip from "../../ui/features/RenameTooltip";
|
||||||
import { setAssetsApi } from "../../../services/factoryBuilder/assest/floorAsset/setAssetsApi";
|
import { setAssetsApi } from "../../../services/factoryBuilder/asset/floorAsset/setAssetsApi";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import { useSceneContext } from "../../../modules/scene/sceneContext";
|
import { useSceneContext } from "../../../modules/scene/sceneContext";
|
||||||
import { useVersionHistoryStore } from "../../../store/builder/useVersionHistoryStore";
|
import { useVersionHistoryStore } from "../../../store/builder/useVersionHistoryStore";
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import Search from "../../ui/inputs/Search";
|
import Search from "../../ui/inputs/Search";
|
||||||
import { getCategoryAsset } from "../../../services/factoryBuilder/assest/assets/getCategoryAsset";
|
import { getCategoryAsset } from "../../../services/factoryBuilder/asset/assets/getCategoryAsset";
|
||||||
import { fetchAssets } from "../../../services/marketplace/fetchAssets";
|
import { fetchAssets } from "../../../services/marketplace/fetchAssets";
|
||||||
import { useSelectedItem } from "../../../store/builder/store";
|
import { useSelectedItem } from "../../../store/builder/store";
|
||||||
|
|
||||||
|
|||||||
@@ -1,27 +1,28 @@
|
|||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import Header from "./Header";
|
import Header from "./Header";
|
||||||
import useModuleStore, {
|
import useModuleStore, {
|
||||||
useSubModuleStore,
|
useSubModuleStore,
|
||||||
} from "../../../store/useModuleStore";
|
} from "../../../store/useModuleStore";
|
||||||
import {
|
import {
|
||||||
AnalysisIcon,
|
AnalysisIcon,
|
||||||
MechanicsIcon,
|
MechanicsIcon,
|
||||||
PropertiesIcon,
|
PropertiesIcon,
|
||||||
SimulationIcon,
|
SimulationIcon,
|
||||||
} from "../../icons/SimulationIcons";
|
} from "../../icons/SimulationIcons";
|
||||||
import { useToggleStore } from "../../../store/useUIToggleStore";
|
import { useToggleStore } from "../../../store/useUIToggleStore";
|
||||||
import Visualization from "./visualization/Visualization";
|
import Visualization from "./visualization/Visualization";
|
||||||
import Analysis from "./analysis/Analysis";
|
import Analysis from "./analysis/Analysis";
|
||||||
import Simulations from "./simulation/Simulations";
|
import Simulations from "./simulation/Simulations";
|
||||||
import useVersionHistoryVisibleStore, {
|
import useVersionHistoryVisibleStore, {
|
||||||
useSaveVersion,
|
useSaveVersion,
|
||||||
useSelectedFloorItem,
|
useSelectedFloorItem,
|
||||||
useToolMode,
|
useToolMode,
|
||||||
} from "../../../store/builder/store";
|
} from "../../../store/builder/store";
|
||||||
import {
|
import {
|
||||||
useSelectedEventData,
|
useSelectedEventData,
|
||||||
useSelectedEventSphere,
|
useSelectedEventSphere,
|
||||||
} from "../../../store/simulation/useSimulationStore";
|
} from "../../../store/simulation/useSimulationStore";
|
||||||
|
import { useBuilderStore } from "../../../store/builder/useBuilderStore";
|
||||||
import GlobalProperties from "./properties/GlobalProperties";
|
import GlobalProperties from "./properties/GlobalProperties";
|
||||||
import AssetProperties from "./properties/AssetProperties";
|
import AssetProperties from "./properties/AssetProperties";
|
||||||
import ZoneProperties from "./properties/ZoneProperties";
|
import ZoneProperties from "./properties/ZoneProperties";
|
||||||
@@ -29,215 +30,227 @@ import EventProperties from "./properties/eventProperties/EventProperties";
|
|||||||
import VersionHistory from "./versionHisory/VersionHistory";
|
import VersionHistory from "./versionHisory/VersionHistory";
|
||||||
import AisleProperties from "./properties/AisleProperties";
|
import AisleProperties from "./properties/AisleProperties";
|
||||||
import WallProperties from "./properties/WallProperties";
|
import WallProperties from "./properties/WallProperties";
|
||||||
import { useBuilderStore } from "../../../store/builder/useBuilderStore";
|
import FloorProperties from "./properties/FloorProperties";
|
||||||
import SelectedWallProperties from "./properties/SelectedWallProperties";
|
import SelectedWallProperties from "./properties/SelectedWallProperties";
|
||||||
import { useSceneContext } from "../../../modules/scene/sceneContext";
|
import SelectedFloorProperties from "./properties/SelectedFloorProperties";
|
||||||
|
|
||||||
const SideBarRight: React.FC = () => {
|
const SideBarRight: React.FC = () => {
|
||||||
const { activeModule } = useModuleStore();
|
const { activeModule } = useModuleStore();
|
||||||
const { toggleUIRight } = useToggleStore();
|
const { toggleUIRight } = useToggleStore();
|
||||||
const { toolMode } = useToolMode();
|
const { toolMode } = useToolMode();
|
||||||
const { subModule, setSubModule } = useSubModuleStore();
|
const { subModule, setSubModule } = useSubModuleStore();
|
||||||
const { selectedFloorItem } = useSelectedFloorItem();
|
const { selectedFloorItem } = useSelectedFloorItem();
|
||||||
|
const { selectedWall, selectedFloor, selectedAisle } = useBuilderStore();
|
||||||
|
const { selectedEventData } = useSelectedEventData();
|
||||||
|
const { selectedEventSphere } = useSelectedEventSphere();
|
||||||
|
const { viewVersionHistory, setVersionHistoryVisible } = useVersionHistoryVisibleStore();
|
||||||
|
const { isVersionSaved } = useSaveVersion();
|
||||||
|
|
||||||
const { selectedWall } = useBuilderStore();
|
// Reset activeList whenever activeModule changes
|
||||||
const { selectedEventData } = useSelectedEventData();
|
useEffect(() => {
|
||||||
const { selectedEventSphere } = useSelectedEventSphere();
|
if (activeModule !== "simulation") setSubModule("properties");
|
||||||
const { viewVersionHistory, setVersionHistoryVisible } = useVersionHistoryVisibleStore();
|
if (activeModule === "simulation") setSubModule("simulations");
|
||||||
const { isVersionSaved } = useSaveVersion();
|
}, [activeModule, setSubModule]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (
|
||||||
|
activeModule !== "mechanics" &&
|
||||||
|
selectedEventData &&
|
||||||
|
selectedEventSphere
|
||||||
|
) {
|
||||||
|
setSubModule("mechanics");
|
||||||
|
} else if (!selectedEventData && !selectedEventSphere) {
|
||||||
|
if (activeModule === "simulation") {
|
||||||
|
setSubModule("simulations");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (activeModule !== "simulation") {
|
||||||
|
setSubModule("properties");
|
||||||
|
}
|
||||||
|
}, [activeModule, selectedEventData, selectedEventSphere, setSubModule]);
|
||||||
|
|
||||||
|
return (
|
||||||
// Reset activeList whenever activeModule changes
|
<div
|
||||||
useEffect(() => {
|
className={`sidebar-right-wrapper ${toggleUIRight && (!isVersionSaved || activeModule !== "simulation") ? "open" : "closed"
|
||||||
if (activeModule !== "simulation") setSubModule("properties");
|
}`}
|
||||||
if (activeModule === "simulation") setSubModule("simulations");
|
>
|
||||||
}, [activeModule, setSubModule]);
|
<Header />
|
||||||
|
{toggleUIRight && (
|
||||||
useEffect(() => {
|
|
||||||
if (
|
|
||||||
activeModule !== "mechanics" &&
|
|
||||||
selectedEventData &&
|
|
||||||
selectedEventSphere
|
|
||||||
) {
|
|
||||||
setSubModule("mechanics");
|
|
||||||
} else if (!selectedEventData && !selectedEventSphere) {
|
|
||||||
if (activeModule === "simulation") {
|
|
||||||
setSubModule("simulations");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (activeModule !== "simulation") {
|
|
||||||
setSubModule("properties");
|
|
||||||
}
|
|
||||||
}, [activeModule, selectedEventData, selectedEventSphere, setSubModule]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={`sidebar-right-wrapper ${toggleUIRight && (!isVersionSaved || activeModule !== "simulation") ? "open" : "closed"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<Header />
|
|
||||||
{toggleUIRight && (
|
|
||||||
<>
|
|
||||||
{!isVersionSaved && (
|
|
||||||
<div className="sidebar-actions-container">
|
|
||||||
{activeModule !== "simulation" && (
|
|
||||||
<button
|
|
||||||
id="sidebar-action-list-properties"
|
|
||||||
className={`sidebar-action-list ${subModule === "properties" ? "active" : ""
|
|
||||||
}`}
|
|
||||||
onClick={() => {
|
|
||||||
setSubModule("properties");
|
|
||||||
setVersionHistoryVisible(false);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className="tooltip">properties</div>
|
|
||||||
<PropertiesIcon isActive={subModule === "properties"} />
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
{activeModule === "simulation" && (
|
|
||||||
<>
|
<>
|
||||||
<button
|
{!isVersionSaved && (
|
||||||
id="sidebar-action-list-simulation"
|
<div className="sidebar-actions-container">
|
||||||
className={`sidebar-action-list ${subModule === "simulations" ? "active" : ""
|
{activeModule !== "simulation" && (
|
||||||
}`}
|
<button
|
||||||
onClick={() => {
|
id="sidebar-action-list-properties"
|
||||||
setSubModule("simulations");
|
className={`sidebar-action-list ${subModule === "properties" ? "active" : ""
|
||||||
setVersionHistoryVisible(false);
|
}`}
|
||||||
}}
|
onClick={() => {
|
||||||
>
|
setSubModule("properties");
|
||||||
<div className="tooltip">simulations</div>
|
setVersionHistoryVisible(false);
|
||||||
<SimulationIcon isActive={subModule === "simulations"} />
|
}}
|
||||||
</button>
|
>
|
||||||
<button
|
<div className="tooltip">properties</div>
|
||||||
id="sidebar-action-list-mechanics"
|
<PropertiesIcon isActive={subModule === "properties"} />
|
||||||
className={`sidebar-action-list ${subModule === "mechanics" ? "active" : ""
|
</button>
|
||||||
}`}
|
)}
|
||||||
onClick={() => {
|
{activeModule === "simulation" && (
|
||||||
setSubModule("mechanics");
|
<>
|
||||||
setVersionHistoryVisible(false);
|
<button
|
||||||
}}
|
id="sidebar-action-list-simulation"
|
||||||
>
|
className={`sidebar-action-list ${subModule === "simulations" ? "active" : ""
|
||||||
<div className="tooltip">mechanics</div>
|
}`}
|
||||||
<MechanicsIcon isActive={subModule === "mechanics"} />
|
onClick={() => {
|
||||||
</button>
|
setSubModule("simulations");
|
||||||
<button
|
setVersionHistoryVisible(false);
|
||||||
id="sidebar-action-list-analysis"
|
}}
|
||||||
className={`sidebar-action-list ${subModule === "analysis" ? "active" : ""
|
>
|
||||||
}`}
|
<div className="tooltip">simulations</div>
|
||||||
onClick={() => {
|
<SimulationIcon isActive={subModule === "simulations"} />
|
||||||
setSubModule("analysis");
|
</button>
|
||||||
setVersionHistoryVisible(false);
|
<button
|
||||||
}}
|
id="sidebar-action-list-mechanics"
|
||||||
>
|
className={`sidebar-action-list ${subModule === "mechanics" ? "active" : ""
|
||||||
<div className="tooltip">analysis</div>
|
}`}
|
||||||
<AnalysisIcon isActive={subModule === "analysis"} />
|
onClick={() => {
|
||||||
</button>
|
setSubModule("mechanics");
|
||||||
|
setVersionHistoryVisible(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="tooltip">mechanics</div>
|
||||||
|
<MechanicsIcon isActive={subModule === "mechanics"} />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
id="sidebar-action-list-analysis"
|
||||||
|
className={`sidebar-action-list ${subModule === "analysis" ? "active" : ""
|
||||||
|
}`}
|
||||||
|
onClick={() => {
|
||||||
|
setSubModule("analysis");
|
||||||
|
setVersionHistoryVisible(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="tooltip">analysis</div>
|
||||||
|
<AnalysisIcon isActive={subModule === "analysis"} />
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{viewVersionHistory && (
|
||||||
|
<div className="sidebar-right-container">
|
||||||
|
<div className="sidebar-right-content-container">
|
||||||
|
<VersionHistory />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* process builder */}
|
||||||
|
{!viewVersionHistory &&
|
||||||
|
subModule === "properties" &&
|
||||||
|
activeModule !== "visualization" &&
|
||||||
|
!selectedFloorItem &&
|
||||||
|
!selectedFloor &&
|
||||||
|
!selectedWall && (
|
||||||
|
<div className="sidebar-right-container">
|
||||||
|
<div className="sidebar-right-content-container">
|
||||||
|
{(() => {
|
||||||
|
if (toolMode === "Aisle") {
|
||||||
|
return <AisleProperties />;
|
||||||
|
} else if (toolMode === "Wall") {
|
||||||
|
return <WallProperties />;
|
||||||
|
} else if (toolMode === "Floor") {
|
||||||
|
return <FloorProperties />;
|
||||||
|
} else {
|
||||||
|
return <GlobalProperties />;
|
||||||
|
}
|
||||||
|
})()}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!viewVersionHistory &&
|
||||||
|
subModule === "properties" &&
|
||||||
|
activeModule !== "visualization" &&
|
||||||
|
selectedFloorItem && (
|
||||||
|
<div className="sidebar-right-container">
|
||||||
|
<div className="sidebar-right-content-container">
|
||||||
|
<AssetProperties />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!viewVersionHistory &&
|
||||||
|
subModule === "properties" &&
|
||||||
|
activeModule !== "visualization" &&
|
||||||
|
!selectedFloorItem &&
|
||||||
|
!selectedFloor &&
|
||||||
|
!selectedAisle &&
|
||||||
|
selectedWall && (
|
||||||
|
<div className="sidebar-right-container">
|
||||||
|
<div className="sidebar-right-content-container">
|
||||||
|
<SelectedWallProperties />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!viewVersionHistory &&
|
||||||
|
subModule === "properties" &&
|
||||||
|
activeModule !== "visualization" &&
|
||||||
|
!selectedFloorItem &&
|
||||||
|
!selectedWall &&
|
||||||
|
!selectedAisle &&
|
||||||
|
selectedFloor && (
|
||||||
|
<div className="sidebar-right-container">
|
||||||
|
<div className="sidebar-right-content-container">
|
||||||
|
<SelectedFloorProperties />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!viewVersionHistory &&
|
||||||
|
subModule === "zoneProperties" &&
|
||||||
|
(activeModule === "builder" || activeModule === "simulation") && (
|
||||||
|
<div className="sidebar-right-container">
|
||||||
|
<div className="sidebar-right-content-container">
|
||||||
|
<ZoneProperties />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* simulation */}
|
||||||
|
{!isVersionSaved &&
|
||||||
|
!viewVersionHistory &&
|
||||||
|
activeModule === "simulation" && (
|
||||||
|
<>
|
||||||
|
{subModule === "simulations" && (
|
||||||
|
<div className="sidebar-right-container">
|
||||||
|
<div className="sidebar-right-content-container">
|
||||||
|
<Simulations />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{subModule === "mechanics" && (
|
||||||
|
<div className="sidebar-right-container">
|
||||||
|
<div className="sidebar-right-content-container">
|
||||||
|
<EventProperties />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{subModule === "analysis" && (
|
||||||
|
<div className="sidebar-right-container">
|
||||||
|
<div className="sidebar-right-content-container">
|
||||||
|
<Analysis />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{/* realtime visualization */}
|
||||||
|
{activeModule === "visualization" && <Visualization />}
|
||||||
</>
|
</>
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{viewVersionHistory && (
|
|
||||||
<div className="sidebar-right-container">
|
|
||||||
<div className="sidebar-right-content-container">
|
|
||||||
<VersionHistory />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{/* process builder */}
|
|
||||||
{!viewVersionHistory &&
|
|
||||||
subModule === "properties" &&
|
|
||||||
activeModule !== "visualization" &&
|
|
||||||
!selectedFloorItem &&
|
|
||||||
!selectedWall && (
|
|
||||||
<div className="sidebar-right-container">
|
|
||||||
<div className="sidebar-right-content-container">
|
|
||||||
{(() => {
|
|
||||||
if (toolMode === "Aisle") {
|
|
||||||
return <AisleProperties />;
|
|
||||||
} else if (toolMode === "Wall") {
|
|
||||||
return <WallProperties />;
|
|
||||||
} else {
|
|
||||||
return <GlobalProperties />;
|
|
||||||
}
|
|
||||||
})()}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
|
</div>
|
||||||
{!viewVersionHistory &&
|
);
|
||||||
subModule === "properties" &&
|
|
||||||
activeModule !== "visualization" &&
|
|
||||||
selectedFloorItem && (
|
|
||||||
<div className="sidebar-right-container">
|
|
||||||
<div className="sidebar-right-content-container">
|
|
||||||
<AssetProperties />
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{!viewVersionHistory &&
|
|
||||||
subModule === "properties" &&
|
|
||||||
activeModule !== "visualization" &&
|
|
||||||
!selectedFloorItem &&
|
|
||||||
selectedWall && (
|
|
||||||
<div className="sidebar-right-container">
|
|
||||||
<div className="sidebar-right-content-container">
|
|
||||||
<SelectedWallProperties />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{!viewVersionHistory &&
|
|
||||||
subModule === "zoneProperties" &&
|
|
||||||
(activeModule === "builder" || activeModule === "simulation") && (
|
|
||||||
<div className="sidebar-right-container">
|
|
||||||
<div className="sidebar-right-content-container">
|
|
||||||
<ZoneProperties />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* simulation */}
|
|
||||||
{!isVersionSaved &&
|
|
||||||
!viewVersionHistory &&
|
|
||||||
activeModule === "simulation" && (
|
|
||||||
<>
|
|
||||||
{subModule === "simulations" && (
|
|
||||||
<div className="sidebar-right-container">
|
|
||||||
<div className="sidebar-right-content-container">
|
|
||||||
<Simulations />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{subModule === "mechanics" && (
|
|
||||||
<div className="sidebar-right-container">
|
|
||||||
<div className="sidebar-right-content-container">
|
|
||||||
<EventProperties />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{subModule === "analysis" && (
|
|
||||||
<div className="sidebar-right-container">
|
|
||||||
<div className="sidebar-right-content-container">
|
|
||||||
<Analysis />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* realtime visualization */}
|
|
||||||
{activeModule === "visualization" && <Visualization />}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SideBarRight;
|
export default SideBarRight;
|
||||||
|
|||||||
@@ -0,0 +1,171 @@
|
|||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import InputToggle from "../../../ui/inputs/InputToggle";
|
||||||
|
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
|
||||||
|
|
||||||
|
import defaultTexture from '../../../../assets/textures/floor/white.png';
|
||||||
|
import flootTexture1 from '../../../../assets/textures/floor/factory wall texture.jpg';
|
||||||
|
|
||||||
|
import { useBuilderStore } from "../../../../store/builder/useBuilderStore";
|
||||||
|
|
||||||
|
type Material = {
|
||||||
|
texture: string;
|
||||||
|
textureId: string;
|
||||||
|
textureName: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const materials = [
|
||||||
|
{ texture: defaultTexture, textureId: "Default Material", textureName: "Default Material" },
|
||||||
|
{ texture: flootTexture1, textureId: "Material 1", textureName: "Grunge Concrete Wall" }
|
||||||
|
];
|
||||||
|
|
||||||
|
const FloorProperties = () => {
|
||||||
|
const { floorDepth, isBeveled, topMaterial, sideMaterial, bevelStrength, setFloorDepth, setIsBeveled, setBevelStrength, setFloorMaterial } = useBuilderStore();
|
||||||
|
|
||||||
|
const [activeSurface, setActiveSurface] = useState<"top" | "side">("top");
|
||||||
|
|
||||||
|
const [selectedMaterials, setSelectedMaterials] = useState<{ top: Material | null; side: Material | null; }>({ top: null, side: null, });
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setSelectedMaterials({
|
||||||
|
top: materials.find((mat) => mat.textureId === topMaterial) || null,
|
||||||
|
side: materials.find((mat) => mat.textureId === sideMaterial) || null,
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleDepthChange = (val: string) => {
|
||||||
|
setFloorDepth(parseFloat(val));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleIsBevelChange = (val: boolean) => {
|
||||||
|
setIsBeveled(val);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleBevelChange = (val: string) => {
|
||||||
|
setBevelStrength(parseFloat(val));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSelectMaterial = (material: Material) => {
|
||||||
|
setSelectedMaterials((prev) => ({
|
||||||
|
...prev,
|
||||||
|
[activeSurface]: material,
|
||||||
|
}));
|
||||||
|
setFloorMaterial(material.textureId, activeSurface);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="wall-properties-container">
|
||||||
|
<section className="wall-properties-section">
|
||||||
|
<div className="header">Floor</div>
|
||||||
|
<div className="wall-properties">
|
||||||
|
<InputWithDropDown
|
||||||
|
label="Depth"
|
||||||
|
value={`${floorDepth}`}
|
||||||
|
min={0.1}
|
||||||
|
max={10}
|
||||||
|
step={0.1}
|
||||||
|
onChange={handleDepthChange}
|
||||||
|
/>
|
||||||
|
<InputToggle
|
||||||
|
value={isBeveled}
|
||||||
|
label="Beveled"
|
||||||
|
inputKey=""
|
||||||
|
onClick={() => handleIsBevelChange(!isBeveled)}
|
||||||
|
/>
|
||||||
|
<InputWithDropDown
|
||||||
|
label="Bevel Strength"
|
||||||
|
value={`${bevelStrength}`}
|
||||||
|
min={1}
|
||||||
|
max={10}
|
||||||
|
step={1}
|
||||||
|
onChange={handleBevelChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<div className="header-wrapper">
|
||||||
|
<div className="header">Materials</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="material-preview">
|
||||||
|
<div className="sides-wrapper">
|
||||||
|
<button
|
||||||
|
className={`side-wrapper ${activeSurface === "top" ? "active" : ""}`}
|
||||||
|
onClick={() => setActiveSurface("top")}
|
||||||
|
>
|
||||||
|
<div className="label">Top</div>
|
||||||
|
<div className="texture-image">
|
||||||
|
{selectedMaterials.top && (
|
||||||
|
<img
|
||||||
|
draggable={false}
|
||||||
|
src={selectedMaterials.top.texture}
|
||||||
|
alt={selectedMaterials.top.textureName}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
className={`side-wrapper ${activeSurface === "side" ? "active" : ""}`}
|
||||||
|
onClick={() => setActiveSurface("side")}
|
||||||
|
>
|
||||||
|
<div className="label">Side</div>
|
||||||
|
<div className="texture-image">
|
||||||
|
{selectedMaterials.side && (
|
||||||
|
<img
|
||||||
|
draggable={false}
|
||||||
|
src={selectedMaterials.side.texture}
|
||||||
|
alt={selectedMaterials.side.textureName}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="preview">
|
||||||
|
{selectedMaterials[activeSurface] && (
|
||||||
|
<img
|
||||||
|
draggable={false}
|
||||||
|
src={selectedMaterials[activeSurface]!.texture}
|
||||||
|
alt={selectedMaterials[activeSurface]!.textureName}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="materials">
|
||||||
|
{materials.length === 0 ? (
|
||||||
|
<div className="no-materials">No materials added yet.</div>
|
||||||
|
) : (
|
||||||
|
<div className="material-container">
|
||||||
|
{materials.map((material, index) => {
|
||||||
|
const isSelected = selectedMaterials[activeSurface]?.texture === material.texture;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
className={`material-wrapper ${isSelected ? "selectedMaterial" : ""}`}
|
||||||
|
key={`${material.textureName}_${index}`}
|
||||||
|
onClick={() => handleSelectMaterial(material)}
|
||||||
|
>
|
||||||
|
<div className="material-property">
|
||||||
|
<div className="material-image">
|
||||||
|
<img
|
||||||
|
draggable={false}
|
||||||
|
src={material.texture}
|
||||||
|
alt={material.textureName}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="material-name">{material.textureName}</div>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FloorProperties;
|
||||||
@@ -0,0 +1,250 @@
|
|||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
|
||||||
|
import InputToggle from "../../../ui/inputs/InputToggle";
|
||||||
|
|
||||||
|
import defaultTexture from '../../../../assets/textures/floor/white.png';
|
||||||
|
import floorTexture1 from '../../../../assets/textures/floor/factory wall texture.jpg';
|
||||||
|
|
||||||
|
import { useBuilderStore } from "../../../../store/builder/useBuilderStore";
|
||||||
|
import { useSceneContext } from "../../../../modules/scene/sceneContext";
|
||||||
|
import { useVersionContext } from "../../../../modules/builder/version/versionContext";
|
||||||
|
import { useParams } from "react-router-dom";
|
||||||
|
import { getUserData } from "../../../../functions/getUserData";
|
||||||
|
import { useSocketStore } from "../../../../store/builder/store";
|
||||||
|
|
||||||
|
// import { upsertFloorApi } from "../../../../services/factoryBuilder/floor/upsertFloorApi";
|
||||||
|
|
||||||
|
const SelectedFloorProperties = () => {
|
||||||
|
const [depth, setDepth] = useState("");
|
||||||
|
const [isBeveled, setIsBeveled] = useState(false);
|
||||||
|
const [bevelStrength, setBevelStrength] = useState("");
|
||||||
|
const { selectedFloor } = useBuilderStore();
|
||||||
|
const { floorStore } = useSceneContext();
|
||||||
|
const { selectedVersionStore } = useVersionContext();
|
||||||
|
const { selectedVersion } = selectedVersionStore();
|
||||||
|
const { socket } = useSocketStore();
|
||||||
|
const { userId, organization } = getUserData();
|
||||||
|
const { projectId } = useParams();
|
||||||
|
const { getFloorById, updateFloor } = floorStore();
|
||||||
|
|
||||||
|
const [activeSurface, setActiveSurface] = useState<"top" | "side">("top");
|
||||||
|
|
||||||
|
const materials = [
|
||||||
|
{ texture: defaultTexture, textureId: "Default Material", textureName: "Default Material" },
|
||||||
|
{ texture: floorTexture1, textureId: "Material 1", textureName: "Grunge Concrete" }
|
||||||
|
];
|
||||||
|
|
||||||
|
const floor = selectedFloor ? getFloorById(selectedFloor.userData.floorUuid) : null;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (floor) {
|
||||||
|
setDepth(floor.floorDepth.toString());
|
||||||
|
setIsBeveled(floor.isBeveled);
|
||||||
|
setBevelStrength(floor.bevelStrength.toString());
|
||||||
|
}
|
||||||
|
}, [floor]);
|
||||||
|
|
||||||
|
const handleDepthChange = (val: string) => {
|
||||||
|
setDepth(val);
|
||||||
|
const parsed = parseFloat(val);
|
||||||
|
if (!isNaN(parsed) && floor) {
|
||||||
|
const updatedFloor = updateFloor(floor.floorUuid, { floorDepth: parsed });
|
||||||
|
if (projectId) {
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// upsertFloorApi(projectId, selectedVersion?.versionId || '', floor);
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
floorData: updatedFloor,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:model-Floor:add', data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleBevelChange = (val: string) => {
|
||||||
|
setBevelStrength(val);
|
||||||
|
const parsed = parseFloat(val);
|
||||||
|
if (!isNaN(parsed) && floor) {
|
||||||
|
const updatedFloor = updateFloor(floor.floorUuid, { bevelStrength: parsed });
|
||||||
|
if (projectId) {
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// upsertFloorApi(projectId, selectedVersion?.versionId || '', floor);
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
floorData: updatedFloor,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:model-Floor:add', data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleIsBeveledToggle = () => {
|
||||||
|
setIsBeveled(!isBeveled);
|
||||||
|
if (!floor) return;
|
||||||
|
const updatedFloor = updateFloor(floor.floorUuid, { isBeveled: !floor.isBeveled });
|
||||||
|
if (projectId) {
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// upsertFloorApi(projectId, selectedVersion?.versionId || '', floor);
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
floorData: updatedFloor,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:model-Floor:add', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSelectMaterial = (material: { textureId: string; textureName: string }) => {
|
||||||
|
if (!floor) return;
|
||||||
|
const key = activeSurface === "top" ? "topMaterial" : "sideMaterial";
|
||||||
|
const updatedFloor = updateFloor(floor.floorUuid, { [key]: material.textureId });
|
||||||
|
if (projectId) {
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// upsertFloorApi(projectId, selectedVersion?.versionId || '', floor);
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
floorData: updatedFloor,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:model-Floor:add', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!floor) return null;
|
||||||
|
|
||||||
|
const selectedMaterials = {
|
||||||
|
top: materials.find((m) => m.textureId === floor.topMaterial) ?? materials[0],
|
||||||
|
side: materials.find((m) => m.textureId === floor.sideMaterial) ?? materials[0],
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="wall-properties-container">
|
||||||
|
<section className="wall-properties-section">
|
||||||
|
<div className="header">Floor</div>
|
||||||
|
<div className="wall-properties">
|
||||||
|
<InputWithDropDown
|
||||||
|
label="Depth"
|
||||||
|
value={depth}
|
||||||
|
min={0.1}
|
||||||
|
max={10}
|
||||||
|
step={0.1}
|
||||||
|
onChange={handleDepthChange}
|
||||||
|
/>
|
||||||
|
<InputToggle
|
||||||
|
label="Beveled"
|
||||||
|
inputKey="isBeveled"
|
||||||
|
value={isBeveled}
|
||||||
|
onClick={handleIsBeveledToggle}
|
||||||
|
/>
|
||||||
|
<InputWithDropDown
|
||||||
|
label="Bevel Strength"
|
||||||
|
value={bevelStrength}
|
||||||
|
min={1}
|
||||||
|
max={10}
|
||||||
|
step={1}
|
||||||
|
onChange={handleBevelChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<div className="header-wrapper">
|
||||||
|
<div className="header">Materials</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="material-preview">
|
||||||
|
<div className="sides-wrapper">
|
||||||
|
{(["top", "side"] as const).map((surface) => (
|
||||||
|
<button
|
||||||
|
key={surface}
|
||||||
|
className={`side-wrapper ${activeSurface === surface ? "active" : ""}`}
|
||||||
|
onClick={() => setActiveSurface(surface)}
|
||||||
|
>
|
||||||
|
<div className="label">{surface === "top" ? "Top" : "Side"}</div>
|
||||||
|
<div className="texture-image">
|
||||||
|
<img
|
||||||
|
draggable={false}
|
||||||
|
src={selectedMaterials[surface].texture}
|
||||||
|
alt={selectedMaterials[surface].textureName}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="preview">
|
||||||
|
<img
|
||||||
|
draggable={false}
|
||||||
|
src={selectedMaterials[activeSurface].texture}
|
||||||
|
alt={selectedMaterials[activeSurface].textureName}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="materials">
|
||||||
|
<div className="material-container">
|
||||||
|
{materials.map((material, index) => {
|
||||||
|
const isSelected = selectedMaterials[activeSurface].textureId === material.textureId;
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
className={`material-wrapper ${isSelected ? "selectedMaterial" : ""}`}
|
||||||
|
key={`${material.textureName}_${index}`}
|
||||||
|
onClick={() => handleSelectMaterial(material)}
|
||||||
|
>
|
||||||
|
<div className="material-property">
|
||||||
|
<div className="material-image">
|
||||||
|
<img
|
||||||
|
draggable={false}
|
||||||
|
src={material.texture}
|
||||||
|
alt={material.textureName}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="material-name">{material.textureName}</div>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SelectedFloorProperties;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
|
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
|
||||||
|
|
||||||
import defaultTexture from '../../../../assets/textures/floor/wall-tex.png';
|
import defaultTexture from '../../../../assets/textures/floor/wall-tex.png';
|
||||||
@@ -6,10 +6,23 @@ import wallTexture1 from '../../../../assets/textures/floor/factory wall texture
|
|||||||
|
|
||||||
import { useBuilderStore } from "../../../../store/builder/useBuilderStore";
|
import { useBuilderStore } from "../../../../store/builder/useBuilderStore";
|
||||||
import { useSceneContext } from "../../../../modules/scene/sceneContext";
|
import { useSceneContext } from "../../../../modules/scene/sceneContext";
|
||||||
|
import { useVersionContext } from "../../../../modules/builder/version/versionContext";
|
||||||
|
import { useParams } from "react-router-dom";
|
||||||
|
import { getUserData } from "../../../../functions/getUserData";
|
||||||
|
import { useSocketStore } from "../../../../store/builder/store";
|
||||||
|
|
||||||
|
// import { upsertWallApi } from "../../../../services/factoryBuilder/wall/upsertWallApi";
|
||||||
|
|
||||||
const SelectedWallProperties = () => {
|
const SelectedWallProperties = () => {
|
||||||
|
const [height, setHeight] = useState("");
|
||||||
|
const [thickness, setThickness] = useState("");
|
||||||
const { selectedWall } = useBuilderStore();
|
const { selectedWall } = useBuilderStore();
|
||||||
const { wallStore } = useSceneContext();
|
const { wallStore } = useSceneContext();
|
||||||
|
const { selectedVersionStore } = useVersionContext();
|
||||||
|
const { selectedVersion } = selectedVersionStore();
|
||||||
|
const { socket } = useSocketStore();
|
||||||
|
const { userId, organization } = getUserData();
|
||||||
|
const { projectId } = useParams();
|
||||||
const { getWallById, updateWall } = wallStore();
|
const { getWallById, updateWall } = wallStore();
|
||||||
|
|
||||||
const [activeSide, setActiveSide] = useState<"side1" | "side2">("side1");
|
const [activeSide, setActiveSide] = useState<"side1" | "side2">("side1");
|
||||||
@@ -21,17 +34,62 @@ const SelectedWallProperties = () => {
|
|||||||
|
|
||||||
const wall = selectedWall ? getWallById(selectedWall.userData.wallUuid) : null;
|
const wall = selectedWall ? getWallById(selectedWall.userData.wallUuid) : null;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (wall) {
|
||||||
|
setHeight(wall.wallHeight.toString());
|
||||||
|
setThickness(wall.wallThickness.toString());
|
||||||
|
}
|
||||||
|
}, [wall, selectedWall]);
|
||||||
|
|
||||||
const handleHeightChange = (val: string) => {
|
const handleHeightChange = (val: string) => {
|
||||||
|
setHeight(val);
|
||||||
const height = parseFloat(val);
|
const height = parseFloat(val);
|
||||||
if (!isNaN(height) && wall) {
|
if (!isNaN(height) && wall) {
|
||||||
updateWall(wall.wallUuid, { wallHeight: height });
|
const updatedWall = updateWall(wall.wallUuid, { wallHeight: height });
|
||||||
|
if (updatedWall && projectId) {
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// upsertWallApi(projectId, selectedVersion?.versionId || '', updatedWall);
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
wallData: updatedWall,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:model-Wall:add', data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleThicknessChange = (val: string) => {
|
const handleThicknessChange = (val: string) => {
|
||||||
|
setThickness(val);
|
||||||
const thickness = parseFloat(val);
|
const thickness = parseFloat(val);
|
||||||
if (!isNaN(thickness) && wall) {
|
if (!isNaN(thickness) && wall) {
|
||||||
updateWall(wall.wallUuid, { wallThickness: thickness });
|
const updatedWall = updateWall(wall.wallUuid, { wallThickness: thickness });
|
||||||
|
if (updatedWall && projectId) {
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// upsertWallApi(projectId, selectedVersion?.versionId || '', updatedWall);
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
wallData: updatedWall,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:model-Wall:add', data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -39,23 +97,32 @@ const SelectedWallProperties = () => {
|
|||||||
if (!wall) return;
|
if (!wall) return;
|
||||||
|
|
||||||
const updated = (activeSide === "side1" ? { insideMaterial: material.textureId } : { outsideMaterial: material.textureId })
|
const updated = (activeSide === "side1" ? { insideMaterial: material.textureId } : { outsideMaterial: material.textureId })
|
||||||
|
const updatedWall = updateWall(wall.wallUuid, updated);
|
||||||
|
if (updatedWall && projectId) {
|
||||||
|
|
||||||
updateWall(wall.wallUuid, updated);
|
// API
|
||||||
|
|
||||||
|
// upsertWallApi(projectId, selectedVersion?.versionId || '', updatedWall);
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
wallData: updatedWall,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:model-Wall:add', data);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!wall) return null;
|
if (!wall) return null;
|
||||||
|
|
||||||
const selectedMaterials = {
|
const selectedMaterials = {
|
||||||
side1: {
|
side1: materials.find((m) => m.textureId === wall.insideMaterial) ?? materials[0],
|
||||||
texture: materials.find((material) => material.textureId === wall.insideMaterial)?.texture || 'Unknown',
|
side2: materials.find((m) => m.textureId === wall.outsideMaterial) ?? materials[0]
|
||||||
textureId: materials.find((material) => material.textureId === wall.insideMaterial)?.textureId || 'Unknown',
|
|
||||||
textureName: materials.find((material) => material.textureId === wall.insideMaterial)?.textureName || 'Unknown'
|
|
||||||
},
|
|
||||||
side2: {
|
|
||||||
texture: materials.find((material) => material.textureId === wall.outsideMaterial)?.texture || 'Unknown',
|
|
||||||
textureId: materials.find((material) => material.textureId === wall.outsideMaterial)?.textureId || 'Unknown',
|
|
||||||
textureName: materials.find((material) => material.textureId === wall.outsideMaterial)?.textureName || 'Unknown'
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -65,12 +132,18 @@ const SelectedWallProperties = () => {
|
|||||||
<div className="wall-properties">
|
<div className="wall-properties">
|
||||||
<InputWithDropDown
|
<InputWithDropDown
|
||||||
label="Height"
|
label="Height"
|
||||||
value={`${wall.wallHeight}`}
|
value={height}
|
||||||
|
min={1}
|
||||||
|
max={25}
|
||||||
|
step={1}
|
||||||
onChange={handleHeightChange}
|
onChange={handleHeightChange}
|
||||||
/>
|
/>
|
||||||
<InputWithDropDown
|
<InputWithDropDown
|
||||||
label="Thickness"
|
label="Thickness"
|
||||||
value={`${wall.wallThickness}`}
|
value={thickness}
|
||||||
|
min={0.1}
|
||||||
|
max={2}
|
||||||
|
step={0.1}
|
||||||
onChange={handleThicknessChange}
|
onChange={handleThicknessChange}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -10,163 +10,158 @@ import { useBuilderStore } from "../../../../store/builder/useBuilderStore";
|
|||||||
|
|
||||||
// Define Material type
|
// Define Material type
|
||||||
type Material = {
|
type Material = {
|
||||||
texture: string;
|
texture: string;
|
||||||
textureName: string;
|
textureId: string;
|
||||||
|
textureName: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Default and initial materials
|
const materials = [
|
||||||
const defaultMaterial: Material = {
|
{ texture: defaultTexture, textureId: "Default Material", textureName: "Default Material" },
|
||||||
texture: defaultTexture,
|
{ texture: wallTexture1, textureId: "Material 1", textureName: "Grunge Concrete Wall" }
|
||||||
textureName: "Default Material",
|
];
|
||||||
};
|
|
||||||
|
|
||||||
const initialMaterial: Material = {
|
|
||||||
texture: wallTexture1,
|
|
||||||
textureName: "Grunge Concrete Wall",
|
|
||||||
};
|
|
||||||
|
|
||||||
const WallProperties = () => {
|
const WallProperties = () => {
|
||||||
const { wallHeight, wallThickness, setWallHeight, setWallThickness } = useBuilderStore();
|
const { wallHeight, wallThickness, insideMaterial, outsideMaterial, setWallHeight, setWallThickness } = useBuilderStore();
|
||||||
|
|
||||||
const [activeSide, setActiveSide] = useState<"side1" | "side2">("side1");
|
const [activeSide, setActiveSide] = useState<"side1" | "side2">("side1");
|
||||||
|
|
||||||
const [materials, setMaterials] = useState<Material[]>([
|
const [selectedMaterials, setSelectedMaterials] = useState<{
|
||||||
defaultMaterial,
|
side1: Material | null;
|
||||||
initialMaterial,
|
side2: Material | null;
|
||||||
]);
|
}>({
|
||||||
|
side1: null,
|
||||||
const [selectedMaterials, setSelectedMaterials] = useState<{
|
side2: null,
|
||||||
side1: Material | null;
|
|
||||||
side2: Material | null;
|
|
||||||
}>({
|
|
||||||
side1: null,
|
|
||||||
side2: null,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Set default material initially for both sides
|
|
||||||
useEffect(() => {
|
|
||||||
setSelectedMaterials({
|
|
||||||
side1: defaultMaterial,
|
|
||||||
side2: defaultMaterial,
|
|
||||||
});
|
});
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleHeightChange = (newValue: string) => {
|
useEffect(() => {
|
||||||
setWallHeight(parseFloat(newValue));
|
setSelectedMaterials({
|
||||||
};
|
side1: materials.find((mat) => mat.textureId === outsideMaterial) || null,
|
||||||
|
side2: materials.find((mat) => mat.textureId === insideMaterial) || null,
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
const handleThicknessChange = (newValue: string) => {
|
const handleHeightChange = (newValue: string) => {
|
||||||
setWallThickness(parseFloat(newValue));
|
setWallHeight(parseFloat(newValue));
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSelectMaterial = (material: Material) => {
|
const handleThicknessChange = (newValue: string) => {
|
||||||
setSelectedMaterials((prev) => ({
|
setWallThickness(parseFloat(newValue));
|
||||||
...prev,
|
};
|
||||||
[activeSide]: material,
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
const handleSelectMaterial = (material: Material) => {
|
||||||
<div className="wall-properties-container">
|
setSelectedMaterials((prev) => ({
|
||||||
<section className="wall-properties-section">
|
...prev,
|
||||||
<div className="header">Wall</div>
|
[activeSide]: material,
|
||||||
<div className="wall-properties">
|
}));
|
||||||
<InputWithDropDown
|
};
|
||||||
label="Height"
|
|
||||||
value={`${wallHeight}`}
|
|
||||||
onChange={(val) => handleHeightChange(val)}
|
|
||||||
/>
|
|
||||||
<InputWithDropDown
|
|
||||||
label="Thickness"
|
|
||||||
value={`${wallThickness}`}
|
|
||||||
onChange={(val) => handleThicknessChange(val)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<div className="header-wrapper">
|
|
||||||
<div className="header">Materials</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="material-preview">
|
return (
|
||||||
<div className="sides-wrapper">
|
<div className="wall-properties-container">
|
||||||
<button
|
<section className="wall-properties-section">
|
||||||
className={`side-wrapper ${activeSide === "side1" ? "active" : ""}`}
|
<div className="header">Wall</div>
|
||||||
onClick={() => setActiveSide("side1")}
|
<div className="wall-properties">
|
||||||
>
|
<InputWithDropDown
|
||||||
<div className="label">Side 1</div>
|
label="Height"
|
||||||
<div className="texture-image">
|
value={`${wallHeight}`}
|
||||||
{selectedMaterials.side1 && (
|
min={1}
|
||||||
<img
|
max={25}
|
||||||
draggable={false}
|
step={1}
|
||||||
src={selectedMaterials.side1.texture}
|
onChange={(val) => handleHeightChange(val)}
|
||||||
alt={selectedMaterials.side1.textureName}
|
/>
|
||||||
/>
|
<InputWithDropDown
|
||||||
)}
|
label="Thickness"
|
||||||
</div>
|
value={`${wallThickness}`}
|
||||||
</button>
|
min={0.1}
|
||||||
|
max={2}
|
||||||
|
step={0.1}
|
||||||
|
onChange={(val) => handleThicknessChange(val)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<div className="header-wrapper">
|
||||||
|
<div className="header">Materials</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<button
|
<div className="material-preview">
|
||||||
className={`side-wrapper ${activeSide === "side2" ? "active" : ""}`}
|
<div className="sides-wrapper">
|
||||||
onClick={() => setActiveSide("side2")}
|
<button
|
||||||
>
|
className={`side-wrapper ${activeSide === "side1" ? "active" : ""}`}
|
||||||
<div className="label">Side 2</div>
|
onClick={() => setActiveSide("side1")}
|
||||||
<div className="texture-image">
|
>
|
||||||
{selectedMaterials.side2 && (
|
<div className="label">Side 1</div>
|
||||||
<img
|
<div className="texture-image">
|
||||||
draggable={false}
|
{selectedMaterials.side1 && (
|
||||||
src={selectedMaterials.side2.texture}
|
<img
|
||||||
alt={selectedMaterials.side2.textureName}
|
draggable={false}
|
||||||
/>
|
src={selectedMaterials.side1.texture}
|
||||||
)}
|
alt={selectedMaterials.side1.textureName}
|
||||||
</div>
|
/>
|
||||||
</button>
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
</button>
|
||||||
|
|
||||||
<div className="preview">
|
<button
|
||||||
{selectedMaterials[activeSide] && (
|
className={`side-wrapper ${activeSide === "side2" ? "active" : ""}`}
|
||||||
<img
|
onClick={() => setActiveSide("side2")}
|
||||||
draggable={false}
|
>
|
||||||
src={selectedMaterials[activeSide]!.texture}
|
<div className="label">Side 2</div>
|
||||||
alt={selectedMaterials[activeSide]!.textureName}
|
<div className="texture-image">
|
||||||
/>
|
{selectedMaterials.side2 && (
|
||||||
)}
|
<img
|
||||||
</div>
|
draggable={false}
|
||||||
</div>
|
src={selectedMaterials.side2.texture}
|
||||||
|
alt={selectedMaterials.side2.textureName}
|
||||||
<div className="materials">
|
/>
|
||||||
{materials.length === 0 ? (
|
)}
|
||||||
<div className="no-materials">No materials added yet.</div>
|
</div>
|
||||||
) : (
|
</button>
|
||||||
<div className="material-container">
|
|
||||||
{materials.map((material, index) => {
|
|
||||||
const isSelected = selectedMaterials[activeSide]?.texture === material.texture;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<button
|
|
||||||
className={`material-wrapper ${isSelected ? "selectedMaterial" : ""}`}
|
|
||||||
key={`${material.textureName}_${index}`}
|
|
||||||
onClick={() => handleSelectMaterial(material)}
|
|
||||||
>
|
|
||||||
<div className="material-property">
|
|
||||||
<div className="material-image">
|
|
||||||
<img
|
|
||||||
draggable={false}
|
|
||||||
src={material.texture}
|
|
||||||
alt={material.textureName}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="material-name">{material.textureName}</div>
|
|
||||||
</div>
|
</div>
|
||||||
</button>
|
|
||||||
);
|
<div className="preview">
|
||||||
})}
|
{selectedMaterials[activeSide] && (
|
||||||
</div>
|
<img
|
||||||
)}
|
draggable={false}
|
||||||
|
src={selectedMaterials[activeSide]!.texture}
|
||||||
|
alt={selectedMaterials[activeSide]!.textureName}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="materials">
|
||||||
|
{materials.length === 0 ? (
|
||||||
|
<div className="no-materials">No materials added yet.</div>
|
||||||
|
) : (
|
||||||
|
<div className="material-container">
|
||||||
|
{materials.map((material, index) => {
|
||||||
|
const isSelected = selectedMaterials[activeSide]?.texture === material.texture;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
className={`material-wrapper ${isSelected ? "selectedMaterial" : ""}`}
|
||||||
|
key={`${material.textureName}_${index}`}
|
||||||
|
onClick={() => handleSelectMaterial(material)}
|
||||||
|
>
|
||||||
|
<div className="material-property">
|
||||||
|
<div className="material-image">
|
||||||
|
<img
|
||||||
|
draggable={false}
|
||||||
|
src={material.texture}
|
||||||
|
alt={material.textureName}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="material-name">{material.textureName}</div>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
);
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default WallProperties;
|
export default WallProperties;
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import {
|
|||||||
useZones,
|
useZones,
|
||||||
} from "../../../store/builder/store";
|
} from "../../../store/builder/store";
|
||||||
import { zoneCameraUpdate } from "../../../services/visulization/zone/zoneCameraUpdation";
|
import { zoneCameraUpdate } from "../../../services/visulization/zone/zoneCameraUpdation";
|
||||||
import { setAssetsApi } from "../../../services/factoryBuilder/assest/floorAsset/setAssetsApi";
|
import { setAssetsApi } from "../../../services/factoryBuilder/asset/floorAsset/setAssetsApi";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import { getUserData } from "../../../functions/getUserData";
|
import { getUserData } from "../../../functions/getUserData";
|
||||||
import { useSceneContext } from "../../../modules/scene/sceneContext";
|
import { useSceneContext } from "../../../modules/scene/sceneContext";
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import { useBuilderStore } from '../../../store/builder/useBuilderStore';
|
|||||||
import defaultMaterial from '../../../assets/textures/floor/wall-tex.png';
|
import defaultMaterial from '../../../assets/textures/floor/wall-tex.png';
|
||||||
import useModuleStore from '../../../store/useModuleStore';
|
import useModuleStore from '../../../store/useModuleStore';
|
||||||
|
|
||||||
function DecalInstance({ visible = true, decal }: { visible?: boolean, decal: Decal }) {
|
function DecalInstance({ visible = true, decal, zPosition = decal.decalPosition[2] }: { visible?: boolean, decal: Decal, zPosition?: number }) {
|
||||||
const { setSelectedWall, selectedDecal, setSelectedDecal } = useBuilderStore();
|
const { setSelectedWall, setSelectedFloor, selectedDecal, setSelectedDecal } = useBuilderStore();
|
||||||
const { togglView } = useToggleView();
|
const { togglView } = useToggleView();
|
||||||
const { activeModule } = useModuleStore();
|
const { activeModule } = useModuleStore();
|
||||||
const material = useLoader(THREE.TextureLoader, defaultMaterial);
|
const material = useLoader(THREE.TextureLoader, defaultMaterial);
|
||||||
@@ -17,15 +17,17 @@ function DecalInstance({ visible = true, decal }: { visible?: boolean, decal: De
|
|||||||
<Decal
|
<Decal
|
||||||
// debug
|
// debug
|
||||||
visible={visible}
|
visible={visible}
|
||||||
position={decal.decalPosition}
|
position={[decal.decalPosition[0], decal.decalPosition[1], zPosition]}
|
||||||
rotation={[0, 0, decal.decalRotation]}
|
rotation={[0, 0, decal.decalRotation]}
|
||||||
scale={[decal.decalScale, decal.decalScale, 0.01]}
|
scale={[decal.decalScale, decal.decalScale, 0.01]}
|
||||||
userData={decal}
|
userData={decal}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
if (visible && !togglView && activeModule === 'builder') {
|
if (visible && !togglView && activeModule === 'builder') {
|
||||||
if (e.object.userData.decalUuid) {
|
if (e.object.userData.decalUuid) {
|
||||||
|
e.stopPropagation();
|
||||||
setSelectedDecal(e.object);
|
setSelectedDecal(e.object);
|
||||||
setSelectedWall(null);
|
setSelectedWall(null);
|
||||||
|
setSelectedFloor(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
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 +0,0 @@
|
|||||||
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: {
|
|
||||||
uOuterColor: { 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 uOuterColor;
|
|
||||||
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(uOuterColor, 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,110 +1,110 @@
|
|||||||
import { GLTF, GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
|
// import { GLTF, GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
|
||||||
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
|
// import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
|
||||||
import * as THREE from "three";
|
// import * as THREE from "three";
|
||||||
import * as Types from "../../../types/world/worldTypes";
|
// import * as Types from "../../../types/world/worldTypes";
|
||||||
import { getWallItems } from "../../../services/factoryBuilder/assest/wallAsset/getWallItemsApi";
|
// import { getWallItems } from "../../../services/factoryBuilder/asset/wallAsset/getWallItemsApi";
|
||||||
import { retrieveGLTF, storeGLTF } from "../../../utils/indexDB/idbUtils";
|
// import { retrieveGLTF, storeGLTF } from "../../../utils/indexDB/idbUtils";
|
||||||
import { getUserData } from "../../../functions/getUserData";
|
// import { getUserData } from "../../../functions/getUserData";
|
||||||
|
|
||||||
async function loadInitialWallItems(
|
// async function loadInitialWallItems(
|
||||||
setWallItems: Types.setWallItemSetState,
|
// setWallItems: Types.setWallItemSetState,
|
||||||
projectId?: string,
|
// projectId?: string,
|
||||||
versionId?: string
|
// versionId?: string
|
||||||
): Promise<void> {
|
// ): Promise<void> {
|
||||||
if (!projectId || !versionId) return;
|
// if (!projectId || !versionId) return;
|
||||||
try {
|
// try {
|
||||||
const { organization, email } = getUserData();
|
// const { organization, email } = getUserData();
|
||||||
|
|
||||||
if (!email) {
|
// if (!email) {
|
||||||
console.error("No email found in localStorage");
|
// console.error("No email found in localStorage");
|
||||||
}
|
// }
|
||||||
|
|
||||||
const items = await getWallItems(organization, projectId, versionId);
|
// const items = await getWallItems(organization, projectId, versionId);
|
||||||
|
|
||||||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
// let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||||
|
|
||||||
if (!items || items.length === 0) {
|
// if (!items || items.length === 0) {
|
||||||
localStorage.removeItem("WallItems");
|
// localStorage.removeItem("WallItems");
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
localStorage.setItem("WallItems", JSON.stringify(items));
|
// localStorage.setItem("WallItems", JSON.stringify(items));
|
||||||
|
|
||||||
const loader = new GLTFLoader();
|
// const loader = new GLTFLoader();
|
||||||
const dracoLoader = new DRACOLoader();
|
// const dracoLoader = new DRACOLoader();
|
||||||
dracoLoader.setDecoderPath(
|
// dracoLoader.setDecoderPath(
|
||||||
"https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/"
|
// "https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/"
|
||||||
);
|
// );
|
||||||
loader.setDRACOLoader(dracoLoader);
|
// loader.setDRACOLoader(dracoLoader);
|
||||||
|
|
||||||
const loadedWallItems = await Promise.all(
|
// const loadedWallItems = await Promise.all(
|
||||||
items.map(async (item: Types.WallItem) => {
|
// items.map(async (item: Types.WallItem) => {
|
||||||
// Check THREE.js cache first
|
// // Check THREE.js cache first
|
||||||
const cachedModel = THREE.Cache.get(item.assetId!);
|
// const cachedModel = THREE.Cache.get(item.assetId!);
|
||||||
if (cachedModel) {
|
// if (cachedModel) {
|
||||||
return processModel(cachedModel, item);
|
// return processModel(cachedModel, item);
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Check IndexedDB cache
|
// // Check IndexedDB cache
|
||||||
const cachedModelBlob = await retrieveGLTF(item.assetId!);
|
// const cachedModelBlob = await retrieveGLTF(item.assetId!);
|
||||||
if (cachedModelBlob) {
|
// if (cachedModelBlob) {
|
||||||
const blobUrl = URL.createObjectURL(cachedModelBlob);
|
// const blobUrl = URL.createObjectURL(cachedModelBlob);
|
||||||
return new Promise<Types.WallItem>((resolve) => {
|
// return new Promise<Types.WallItem>((resolve) => {
|
||||||
loader.load(blobUrl, (gltf) => {
|
// loader.load(blobUrl, (gltf) => {
|
||||||
URL.revokeObjectURL(blobUrl);
|
// URL.revokeObjectURL(blobUrl);
|
||||||
THREE.Cache.add(item.assetId!, gltf);
|
// THREE.Cache.add(item.assetId!, gltf);
|
||||||
resolve(processModel(gltf, item));
|
// resolve(processModel(gltf, item));
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Load from original URL if not cached
|
// // Load from original URL if not cached
|
||||||
const modelUrl = `${url_Backend_dwinzo}/api/v2/AssetFile/${item.assetId!}`;
|
// const modelUrl = `${url_Backend_dwinzo}/api/v2/AssetFile/${item.assetId!}`;
|
||||||
return new Promise<Types.WallItem>((resolve) => {
|
// return new Promise<Types.WallItem>((resolve) => {
|
||||||
loader.load(modelUrl, async (gltf) => {
|
// loader.load(modelUrl, async (gltf) => {
|
||||||
try {
|
// try {
|
||||||
// Cache the model
|
// // Cache the model
|
||||||
const modelBlob = await fetch(modelUrl).then((res) => res.blob());
|
// const modelBlob = await fetch(modelUrl).then((res) => res.blob());
|
||||||
await storeGLTF(item.assetId!, modelBlob);
|
// await storeGLTF(item.assetId!, modelBlob);
|
||||||
THREE.Cache.add(item.assetId!, gltf);
|
// THREE.Cache.add(item.assetId!, gltf);
|
||||||
resolve(processModel(gltf, item));
|
// resolve(processModel(gltf, item));
|
||||||
} catch (error) {
|
// } catch (error) {
|
||||||
console.error("Failed to cache model:", error);
|
// console.error("Failed to cache model:", error);
|
||||||
resolve(processModel(gltf, item));
|
// resolve(processModel(gltf, item));
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
})
|
// })
|
||||||
);
|
// );
|
||||||
|
|
||||||
setWallItems(loadedWallItems);
|
// setWallItems(loadedWallItems);
|
||||||
} catch (error) {
|
// } catch (error) {
|
||||||
console.error("Failed to load wall items:", error);
|
// console.error("Failed to load wall items:", error);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
function processModel(gltf: GLTF, item: Types.WallItem): Types.WallItem {
|
// function processModel(gltf: GLTF, item: Types.WallItem): Types.WallItem {
|
||||||
const model = gltf.scene.clone();
|
// const model = gltf.scene.clone();
|
||||||
model.uuid = item.modelUuid!;
|
// model.uuid = item.modelUuid!;
|
||||||
|
|
||||||
model.children[0]?.children?.forEach((child: THREE.Object3D) => {
|
// model.children[0]?.children?.forEach((child: THREE.Object3D) => {
|
||||||
if (child.name !== "CSG_REF") {
|
// if (child.name !== "CSG_REF") {
|
||||||
child.castShadow = true;
|
// child.castShadow = true;
|
||||||
child.receiveShadow = true;
|
// child.receiveShadow = true;
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
|
|
||||||
return {
|
// return {
|
||||||
type: item.type,
|
// type: item.type,
|
||||||
model: model,
|
// model: model,
|
||||||
modelName: item.modelName,
|
// modelName: item.modelName,
|
||||||
assetId: item.assetId,
|
// assetId: item.assetId,
|
||||||
scale: item.scale,
|
// scale: item.scale,
|
||||||
csgscale: item.csgscale,
|
// csgscale: item.csgscale,
|
||||||
csgposition: item.csgposition,
|
// csgposition: item.csgposition,
|
||||||
position: item.position,
|
// position: item.position,
|
||||||
quaternion: item.quaternion,
|
// quaternion: item.quaternion,
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
|
|
||||||
export default loadInitialWallItems;
|
// export default loadInitialWallItems;
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ function ArcAisle({ aisle }: { readonly aisle: Aisle }) {
|
|||||||
position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]}
|
position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]}
|
||||||
rotation={[Math.PI / 2, 0, 0]}
|
rotation={[Math.PI / 2, 0, 0]}
|
||||||
userData={aisle}
|
userData={aisle}
|
||||||
onClick={handleClick}
|
onDoubleClick={handleClick}
|
||||||
onPointerMissed={() => {
|
onPointerMissed={() => {
|
||||||
setSelectedAisle(null);
|
setSelectedAisle(null);
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ function ArrowAisle({ aisle }: { readonly aisle: Aisle }) {
|
|||||||
position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]}
|
position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]}
|
||||||
rotation={[Math.PI / 2, 0, 0]}
|
rotation={[Math.PI / 2, 0, 0]}
|
||||||
userData={aisle}
|
userData={aisle}
|
||||||
onClick={handleClick}
|
onDoubleClick={handleClick}
|
||||||
onPointerMissed={() => {
|
onPointerMissed={() => {
|
||||||
setSelectedAisle(null);
|
setSelectedAisle(null);
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ function ArrowsAisle({ aisle }: { readonly aisle: Aisle }) {
|
|||||||
position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]}
|
position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]}
|
||||||
rotation={[Math.PI / 2, 0, 0]}
|
rotation={[Math.PI / 2, 0, 0]}
|
||||||
userData={aisle}
|
userData={aisle}
|
||||||
onClick={handleClick}
|
onDoubleClick={handleClick}
|
||||||
onPointerMissed={() => {
|
onPointerMissed={() => {
|
||||||
setSelectedAisle(null);
|
setSelectedAisle(null);
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ function CircleAisle({ aisle }: { readonly aisle: Aisle }) {
|
|||||||
position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]}
|
position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]}
|
||||||
rotation={[Math.PI / 2, 0, 0]}
|
rotation={[Math.PI / 2, 0, 0]}
|
||||||
userData={aisle}
|
userData={aisle}
|
||||||
onClick={handleClick}
|
onDoubleClick={handleClick}
|
||||||
onPointerMissed={() => {
|
onPointerMissed={() => {
|
||||||
setSelectedAisle(null);
|
setSelectedAisle(null);
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ function DashedAisle({ aisle }: { readonly aisle: Aisle }) {
|
|||||||
position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]}
|
position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]}
|
||||||
rotation={[Math.PI / 2, 0, 0]}
|
rotation={[Math.PI / 2, 0, 0]}
|
||||||
userData={aisle}
|
userData={aisle}
|
||||||
onClick={handleClick}
|
onDoubleClick={handleClick}
|
||||||
onPointerMissed={() => {
|
onPointerMissed={() => {
|
||||||
setSelectedAisle(null);
|
setSelectedAisle(null);
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ function DottedAisle({ aisle }: { readonly aisle: Aisle }) {
|
|||||||
position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]}
|
position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]}
|
||||||
rotation={[Math.PI / 2, 0, 0]}
|
rotation={[Math.PI / 2, 0, 0]}
|
||||||
userData={aisle}
|
userData={aisle}
|
||||||
onClick={handleClick}
|
onDoubleClick={handleClick}
|
||||||
onPointerMissed={() => {
|
onPointerMissed={() => {
|
||||||
setSelectedAisle(null);
|
setSelectedAisle(null);
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ function JunctionAisle({ aisle }: { readonly aisle: Aisle }) {
|
|||||||
position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]}
|
position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]}
|
||||||
rotation={[Math.PI / 2, 0, 0]}
|
rotation={[Math.PI / 2, 0, 0]}
|
||||||
userData={aisle}
|
userData={aisle}
|
||||||
onClick={handleClick}
|
onDoubleClick={handleClick}
|
||||||
onPointerMissed={() => {
|
onPointerMissed={() => {
|
||||||
setSelectedAisle(null);
|
setSelectedAisle(null);
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ function SolidAisle({ aisle }: { readonly aisle: Aisle }) {
|
|||||||
position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]}
|
position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]}
|
||||||
rotation={[Math.PI / 2, 0, 0]}
|
rotation={[Math.PI / 2, 0, 0]}
|
||||||
userData={aisle}
|
userData={aisle}
|
||||||
onClick={handleClick}
|
onDoubleClick={handleClick}
|
||||||
onPointerMissed={() => {
|
onPointerMissed={() => {
|
||||||
setSelectedAisle(null);
|
setSelectedAisle(null);
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -2,13 +2,13 @@ import * as THREE from 'three'
|
|||||||
import { useEffect, useMemo, useRef, useState } from 'react'
|
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||||
import { useThree } from '@react-three/fiber';
|
import { useThree } from '@react-three/fiber';
|
||||||
import { useActiveLayer, useSocketStore, useToggleView, useToolMode } from '../../../../store/builder/store';
|
import { useActiveLayer, useSocketStore, useToggleView, useToolMode } from '../../../../store/builder/store';
|
||||||
import ReferenceAisle from './referenceAisle';
|
|
||||||
import { useBuilderStore } from '../../../../store/builder/useBuilderStore';
|
import { useBuilderStore } from '../../../../store/builder/useBuilderStore';
|
||||||
import ReferencePoint from '../../point/reference/referencePoint';
|
import { upsertAisleApi } from '../../../../services/factoryBuilder/aisle/upsertAisleApi';
|
||||||
import { createAisleApi } from '../../../../services/factoryBuilder/aisle/createAisleApi';
|
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import { useVersionContext } from '../../version/versionContext';
|
import { useVersionContext } from '../../version/versionContext';
|
||||||
import { useSceneContext } from '../../../scene/sceneContext';
|
import { useSceneContext } from '../../../scene/sceneContext';
|
||||||
|
import ReferenceAisle from './referenceAisle';
|
||||||
|
import ReferencePoint from '../../point/reference/referencePoint';
|
||||||
|
|
||||||
function AisleCreator() {
|
function AisleCreator() {
|
||||||
const { scene, camera, raycaster, gl, pointer } = useThree();
|
const { scene, camera, raycaster, gl, pointer } = useThree();
|
||||||
@@ -74,6 +74,8 @@ function AisleCreator() {
|
|||||||
newPoint.layer = snappedPoint.layer;
|
newPoint.layer = snappedPoint.layer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (snappedPoint && snappedPoint.pointUuid === tempPoints[0]?.pointUuid) { return }
|
||||||
|
|
||||||
if (snappedPosition && !snappedPoint) {
|
if (snappedPosition && !snappedPoint) {
|
||||||
newPoint.position = snappedPosition;
|
newPoint.position = snappedPosition;
|
||||||
}
|
}
|
||||||
@@ -104,7 +106,7 @@ function AisleCreator() {
|
|||||||
};
|
};
|
||||||
addAisle(aisle);
|
addAisle(aisle);
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||||
}
|
}
|
||||||
setTempPoints([newPoint]);
|
setTempPoints([newPoint]);
|
||||||
}
|
}
|
||||||
@@ -127,7 +129,7 @@ function AisleCreator() {
|
|||||||
};
|
};
|
||||||
addAisle(aisle);
|
addAisle(aisle);
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||||
}
|
}
|
||||||
setTempPoints([newPoint]);
|
setTempPoints([newPoint]);
|
||||||
}
|
}
|
||||||
@@ -149,7 +151,7 @@ function AisleCreator() {
|
|||||||
};
|
};
|
||||||
addAisle(aisle);
|
addAisle(aisle);
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||||
}
|
}
|
||||||
setTempPoints([newPoint]);
|
setTempPoints([newPoint]);
|
||||||
}
|
}
|
||||||
@@ -170,7 +172,7 @@ function AisleCreator() {
|
|||||||
};
|
};
|
||||||
addAisle(aisle);
|
addAisle(aisle);
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||||
}
|
}
|
||||||
setTempPoints([newPoint]);
|
setTempPoints([newPoint]);
|
||||||
}
|
}
|
||||||
@@ -193,7 +195,7 @@ function AisleCreator() {
|
|||||||
};
|
};
|
||||||
addAisle(aisle);
|
addAisle(aisle);
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||||
}
|
}
|
||||||
setTempPoints([newPoint]);
|
setTempPoints([newPoint]);
|
||||||
}
|
}
|
||||||
@@ -215,7 +217,7 @@ function AisleCreator() {
|
|||||||
};
|
};
|
||||||
addAisle(aisle);
|
addAisle(aisle);
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||||
}
|
}
|
||||||
setTempPoints([newPoint]);
|
setTempPoints([newPoint]);
|
||||||
}
|
}
|
||||||
@@ -236,7 +238,7 @@ function AisleCreator() {
|
|||||||
};
|
};
|
||||||
addAisle(aisle);
|
addAisle(aisle);
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||||
}
|
}
|
||||||
setTempPoints([newPoint]);
|
setTempPoints([newPoint]);
|
||||||
}
|
}
|
||||||
@@ -258,7 +260,7 @@ function AisleCreator() {
|
|||||||
};
|
};
|
||||||
addAisle(aisle);
|
addAisle(aisle);
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||||
}
|
}
|
||||||
setTempPoints([newPoint]);
|
setTempPoints([newPoint]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ function ReferenceAisle({ tempPoints }: Readonly<ReferenceAisleProps>) {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTempAisle(null);
|
setTempAisle(null);
|
||||||
}, [toolMode, toggleView, tempPoints.length, aisleType, aisleWidth, aisleColor]);
|
}, [toolMode, toggleView, tempPoints.length, aisleType, aisleWidth, aisleColor, activeLayer]);
|
||||||
|
|
||||||
if (!tempAisle) return null;
|
if (!tempAisle) return null;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as THREE from "three"
|
import * as THREE from "three"
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import { getFloorAssets } from '../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi';
|
import { getFloorAssets } from '../../../services/factoryBuilder/asset/floorAsset/getFloorItemsApi';
|
||||||
import { useLoadingProgress, useRenameModeStore, useSelectedFloorItem, useSelectedItem, useSocketStore } from '../../../store/builder/store';
|
import { useLoadingProgress, useRenameModeStore, useSelectedFloorItem, useSelectedItem, useSocketStore } from '../../../store/builder/store';
|
||||||
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
|
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
|
||||||
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
|
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
|
||||||
@@ -23,10 +23,10 @@ const gltfLoaderWorker = new Worker(
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
function AssetsGroup({ floorGroup, plane }: { readonly floorGroup: RefGroup, readonly plane: RefMesh }) {
|
function AssetsGroup({ plane }: { readonly plane: RefMesh }) {
|
||||||
const { activeModule } = useModuleStore();
|
const { activeModule } = useModuleStore();
|
||||||
const { socket } = useSocketStore();
|
const { socket } = useSocketStore();
|
||||||
const { controls, gl, pointer, camera, raycaster } = useThree();
|
const { controls, gl, pointer, camera, raycaster, scene } = useThree();
|
||||||
const { setLoadingProgress } = useLoadingProgress();
|
const { setLoadingProgress } = useLoadingProgress();
|
||||||
const { assetStore, eventStore } = useSceneContext();
|
const { assetStore, eventStore } = useSceneContext();
|
||||||
const { selectedVersionStore } = useVersionContext();
|
const { selectedVersionStore } = useVersionContext();
|
||||||
@@ -269,7 +269,7 @@ function AssetsGroup({ floorGroup, plane }: { readonly floorGroup: RefGroup, rea
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const canvasElement = gl.domElement;
|
const canvasElement = gl.domElement;
|
||||||
|
|
||||||
const onDrop = (event: any) => {
|
const onDrop = (event: DragEvent) => {
|
||||||
if (!event.dataTransfer?.files[0]) return;
|
if (!event.dataTransfer?.files[0]) return;
|
||||||
|
|
||||||
if (selectedItem.id !== "" && event.dataTransfer?.files[0] && selectedItem.category !== 'Fenestration') {
|
if (selectedItem.id !== "" && event.dataTransfer?.files[0] && selectedItem.category !== 'Fenestration') {
|
||||||
@@ -277,7 +277,7 @@ function AssetsGroup({ floorGroup, plane }: { readonly floorGroup: RefGroup, rea
|
|||||||
pointer.x = (event.clientX / window.innerWidth) * 2 - 1;
|
pointer.x = (event.clientX / window.innerWidth) * 2 - 1;
|
||||||
pointer.y = -(event.clientY / window.innerHeight) * 2 + 1;
|
pointer.y = -(event.clientY / window.innerHeight) * 2 + 1;
|
||||||
|
|
||||||
addAssetModel(raycaster, camera, pointer, floorGroup, socket, selectedItem, setSelectedItem, addEvent, addAsset, plane, selectedVersion, projectId, userId);
|
addAssetModel(scene, raycaster, camera, pointer, socket, selectedItem, setSelectedItem, addEvent, addAsset, plane, selectedVersion, projectId, userId);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -3,496 +3,445 @@ import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
|
|||||||
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
|
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
|
||||||
import * as Types from "../../../../types/world/worldTypes";
|
import * as Types from "../../../../types/world/worldTypes";
|
||||||
import { retrieveGLTF, storeGLTF } from "../../../../utils/indexDB/idbUtils";
|
import { retrieveGLTF, storeGLTF } from "../../../../utils/indexDB/idbUtils";
|
||||||
// import { setAssetsApi } from '../../../../services/factoryBuilder/assest/floorAsset/setAssetsApi';
|
// import { setAssetsApi } from '../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi';
|
||||||
import { Socket } from "socket.io-client";
|
import { Socket } from "socket.io-client";
|
||||||
import * as CONSTANTS from "../../../../types/world/worldConstants";
|
import * as CONSTANTS from "../../../../types/world/worldConstants";
|
||||||
import PointsCalculator from "../../../simulation/events/points/functions/pointsCalculator";
|
import PointsCalculator from "../../../simulation/events/points/functions/pointsCalculator";
|
||||||
import { getUserData } from "../../../../functions/getUserData";
|
import { getUserData } from "../../../../functions/getUserData";
|
||||||
|
|
||||||
async function addAssetModel(
|
async function addAssetModel(
|
||||||
raycaster: THREE.Raycaster,
|
scene: THREE.Scene,
|
||||||
camera: THREE.Camera,
|
raycaster: THREE.Raycaster,
|
||||||
pointer: THREE.Vector2,
|
camera: THREE.Camera,
|
||||||
floorGroup: Types.RefGroup,
|
pointer: THREE.Vector2,
|
||||||
socket: Socket<any>,
|
socket: Socket<any>,
|
||||||
selectedItem: any,
|
selectedItem: any,
|
||||||
setSelectedItem: any,
|
setSelectedItem: any,
|
||||||
addEvent: (event: EventsSchema) => void,
|
addEvent: (event: EventsSchema) => void,
|
||||||
addAsset: (asset: Asset) => void,
|
addAsset: (asset: Asset) => void,
|
||||||
plane: Types.RefMesh,
|
plane: Types.RefMesh,
|
||||||
selectedVersion?: Version | null,
|
selectedVersion?: Version | null,
|
||||||
projectId?: string,
|
projectId?: string,
|
||||||
userId?: string
|
userId?: string
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
////////// Load Floor GLtf's and set the positions, rotation, type etc. in state and store in localstorage //////////
|
////////// 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}`;
|
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const loader = new GLTFLoader();
|
const loader = new GLTFLoader();
|
||||||
const dracoLoader = new DRACOLoader();
|
const dracoLoader = new DRACOLoader();
|
||||||
|
|
||||||
dracoLoader.setDecoderPath(
|
dracoLoader.setDecoderPath("https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/");
|
||||||
"https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/"
|
loader.setDRACOLoader(dracoLoader);
|
||||||
);
|
|
||||||
loader.setDRACOLoader(dracoLoader);
|
|
||||||
|
|
||||||
raycaster.setFromCamera(pointer, camera);
|
raycaster.setFromCamera(pointer, camera);
|
||||||
const floorIntersections = raycaster.intersectObjects(
|
const wallFloorsGroup = scene.getObjectByName("Walls-Floors-Group") as Types.Group | null;
|
||||||
floorGroup.current.children,
|
const floorsGroup = scene.getObjectByName("Floors-Group") as Types.Group | null;
|
||||||
true
|
const floorChildren = floorsGroup?.children ?? [];
|
||||||
);
|
const wallFloorChildren = wallFloorsGroup?.children ?? [];
|
||||||
const intersectedFloor = floorIntersections.find((intersect) =>
|
const floorIntersections = raycaster.intersectObjects([...floorChildren, ...wallFloorChildren], true);
|
||||||
intersect.object.name.includes("Floor")
|
const intersectedFloor = floorIntersections.find((intersect) => intersect.object.name.includes("Floor"));
|
||||||
);
|
|
||||||
|
|
||||||
const planeIntersections = raycaster.intersectObject(plane.current!, true);
|
const planeIntersections = raycaster.intersectObject(plane.current!, true);
|
||||||
const intersectedPlane = planeIntersections[0];
|
const intersectedPlane = planeIntersections[0];
|
||||||
|
|
||||||
let intersectPoint: THREE.Vector3 | null = null;
|
let intersectPoint: THREE.Vector3 | null = null;
|
||||||
|
|
||||||
if (intersectedFloor && intersectedPlane) {
|
if (intersectedFloor && intersectedPlane) {
|
||||||
intersectPoint =
|
// intersectPoint = intersectedFloor.distance < intersectedPlane.distance ?
|
||||||
intersectedFloor.distance < intersectedPlane.distance
|
// new THREE.Vector3(intersectedFloor.point.x, Math.round(intersectedFloor.point.y), intersectedFloor.point.z)
|
||||||
? new THREE.Vector3(
|
// : new THREE.Vector3(intersectedPlane.point.x, 0, intersectedPlane.point.z);
|
||||||
intersectedFloor.point.x,
|
if (intersectedFloor.distance < intersectedPlane.distance) {
|
||||||
Math.round(intersectedFloor.point.y),
|
if (intersectedFloor.object.userData.floorUuid) {
|
||||||
intersectedFloor.point.z
|
intersectPoint = new THREE.Vector3(intersectedFloor.point.x, intersectedFloor.object.userData.floorDepth, intersectedFloor.point.z);
|
||||||
)
|
} else {
|
||||||
: new THREE.Vector3(
|
intersectPoint = new THREE.Vector3(intersectedFloor.point.x, 0, intersectedFloor.point.z);
|
||||||
intersectedPlane.point.x,
|
}
|
||||||
0,
|
} else {
|
||||||
intersectedPlane.point.z
|
intersectPoint = 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) {
|
|
||||||
handleModelLoad(
|
|
||||||
cachedModel,
|
|
||||||
intersectPoint!,
|
|
||||||
selectedItem,
|
|
||||||
addEvent,
|
|
||||||
addAsset,
|
|
||||||
socket,
|
|
||||||
selectedVersion?.versionId || '',
|
|
||||||
projectId,
|
|
||||||
userId
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
const cachedModelBlob = await retrieveGLTF(selectedItem.id);
|
|
||||||
if (cachedModelBlob) {
|
|
||||||
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,
|
|
||||||
addEvent,
|
|
||||||
addAsset,
|
|
||||||
socket,
|
|
||||||
selectedVersion?.versionId || '',
|
|
||||||
projectId,
|
|
||||||
userId
|
|
||||||
);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
loader.load(
|
|
||||||
`${url_Backend_dwinzo}/api/v2/AssetFile/${selectedItem.id}`,
|
|
||||||
async (gltf) => {
|
|
||||||
const modelBlob = await fetch(
|
|
||||||
`${url_Backend_dwinzo}/api/v2/AssetFile/${selectedItem.id}`
|
|
||||||
).then((res) => res.blob());
|
|
||||||
await storeGLTF(selectedItem.id, modelBlob);
|
|
||||||
THREE.Cache.add(selectedItem.id, gltf);
|
|
||||||
await handleModelLoad(
|
|
||||||
gltf,
|
|
||||||
intersectPoint!,
|
|
||||||
selectedItem,
|
|
||||||
addEvent,
|
|
||||||
addAsset,
|
|
||||||
socket,
|
|
||||||
selectedVersion?.versionId || '',
|
|
||||||
projectId,
|
|
||||||
userId
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
);
|
} 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) {
|
||||||
|
handleModelLoad(cachedModel, intersectPoint!, selectedItem, addEvent, addAsset, socket, selectedVersion?.versionId || '', projectId, userId);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
const cachedModelBlob = await retrieveGLTF(selectedItem.id);
|
||||||
|
if (cachedModelBlob) {
|
||||||
|
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, addEvent, addAsset, socket, selectedVersion?.versionId || '', projectId, userId);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
loader.load(`${url_Backend_dwinzo}/api/v2/AssetFile/${selectedItem.id}`,
|
||||||
|
async (gltf) => {
|
||||||
|
const modelBlob = await fetch(`${url_Backend_dwinzo}/api/v2/AssetFile/${selectedItem.id}`).then((res) => res.blob());
|
||||||
|
await storeGLTF(selectedItem.id, modelBlob);
|
||||||
|
THREE.Cache.add(selectedItem.id, gltf);
|
||||||
|
await handleModelLoad(gltf, intersectPoint!, selectedItem, addEvent, addAsset, socket, selectedVersion?.versionId || '', projectId, userId);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
echo.error("Failed to add asset");
|
||||||
|
} finally {
|
||||||
|
setSelectedItem({});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
|
||||||
echo.error("Failed to add asset");
|
|
||||||
} finally {
|
|
||||||
setSelectedItem({});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleModelLoad(
|
async function handleModelLoad(
|
||||||
gltf: any,
|
gltf: any,
|
||||||
intersectPoint: THREE.Vector3,
|
intersectPoint: THREE.Vector3,
|
||||||
selectedItem: any,
|
selectedItem: any,
|
||||||
addEvent: (event: EventsSchema) => void,
|
addEvent: (event: EventsSchema) => void,
|
||||||
addAsset: (asset: Asset) => void,
|
addAsset: (asset: Asset) => void,
|
||||||
socket: Socket<any>,
|
socket: Socket<any>,
|
||||||
versionId: string,
|
versionId: string,
|
||||||
projectId?: string,
|
projectId?: string,
|
||||||
userId?: string
|
userId?: string
|
||||||
) {
|
) {
|
||||||
const { organization } = getUserData();
|
const { organization } = getUserData();
|
||||||
const model = gltf.scene.clone();
|
const model = gltf.scene.clone();
|
||||||
model.userData = {
|
model.userData = {
|
||||||
name: selectedItem.name,
|
name: selectedItem.name,
|
||||||
modelId: selectedItem.id,
|
modelId: selectedItem.id,
|
||||||
modelUuid: model.uuid,
|
modelUuid: model.uuid,
|
||||||
};
|
|
||||||
model.position.set(intersectPoint!.x, intersectPoint!.y, intersectPoint!.z);
|
|
||||||
model.scale.set(...CONSTANTS.assetConfig.defaultScaleAfterGsap);
|
|
||||||
|
|
||||||
model.traverse((child: any) => {
|
|
||||||
if (child) {
|
|
||||||
child.castShadow = true;
|
|
||||||
child.receiveShadow = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const newFloorItem: Asset = {
|
|
||||||
modelUuid: model.uuid,
|
|
||||||
modelName: selectedItem.name,
|
|
||||||
assetId: selectedItem.id,
|
|
||||||
position: [intersectPoint!.x, intersectPoint!.y, intersectPoint!.z],
|
|
||||||
rotation: [0, 0, 0],
|
|
||||||
isLocked: false,
|
|
||||||
isVisible: true,
|
|
||||||
isCollidable: false,
|
|
||||||
opacity: 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// API
|
|
||||||
|
|
||||||
// await setAssetsApi(
|
|
||||||
// organization,
|
|
||||||
// newFloorItem.modelUuid,
|
|
||||||
// newFloorItem.modelName,
|
|
||||||
// newFloorItem.assetId,
|
|
||||||
// newFloorItem.position,
|
|
||||||
// { x: 0, y: 0, z: 0 },
|
|
||||||
// false,
|
|
||||||
// true,
|
|
||||||
// );
|
|
||||||
|
|
||||||
// SOCKET
|
|
||||||
|
|
||||||
if (selectedItem.type) {
|
|
||||||
const data = PointsCalculator(
|
|
||||||
selectedItem.type,
|
|
||||||
gltf.scene.clone(),
|
|
||||||
new THREE.Vector3(...model.rotation)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!data || !data.points) return;
|
|
||||||
|
|
||||||
const eventData: any = {
|
|
||||||
type: selectedItem.type,
|
|
||||||
};
|
};
|
||||||
|
model.position.set(intersectPoint!.x, intersectPoint!.y, intersectPoint!.z);
|
||||||
|
model.scale.set(...CONSTANTS.assetConfig.defaultScaleAfterGsap);
|
||||||
|
|
||||||
if (selectedItem.type === "Conveyor") {
|
model.traverse((child: any) => {
|
||||||
const ConveyorEvent: ConveyorEventSchema = {
|
if (child) {
|
||||||
modelUuid: newFloorItem.modelUuid,
|
child.castShadow = true;
|
||||||
modelName: newFloorItem.modelName,
|
child.receiveShadow = true;
|
||||||
position: newFloorItem.position,
|
|
||||||
rotation: newFloorItem.rotation,
|
|
||||||
state: "idle",
|
|
||||||
type: "transfer",
|
|
||||||
speed: 1,
|
|
||||||
points: data.points.map((point: THREE.Vector3, index: number) => {
|
|
||||||
const triggers: TriggerSchema[] = [];
|
|
||||||
|
|
||||||
if (data.points && index < data.points.length - 1) {
|
|
||||||
triggers.push({
|
|
||||||
triggerUuid: THREE.MathUtils.generateUUID(),
|
|
||||||
triggerName: `Trigger 1`,
|
|
||||||
triggerType: "onComplete",
|
|
||||||
delay: 0,
|
|
||||||
triggeredAsset: {
|
|
||||||
triggeredModel: {
|
|
||||||
modelName: newFloorItem.modelName,
|
|
||||||
modelUuid: newFloorItem.modelUuid,
|
|
||||||
},
|
|
||||||
triggeredPoint: {
|
|
||||||
pointName: `Point`,
|
|
||||||
pointUuid: "",
|
|
||||||
},
|
|
||||||
triggeredAction: {
|
|
||||||
actionName: `Action 1`,
|
|
||||||
actionUuid: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
uuid: THREE.MathUtils.generateUUID(),
|
|
||||||
position: [point.x, point.y, point.z],
|
|
||||||
rotation: [0, 0, 0],
|
|
||||||
action: {
|
|
||||||
actionUuid: THREE.MathUtils.generateUUID(),
|
|
||||||
actionName: `Action 1`,
|
|
||||||
actionType: "default",
|
|
||||||
material: "Default Material",
|
|
||||||
delay: 0,
|
|
||||||
spawnInterval: 5,
|
|
||||||
spawnCount: 1,
|
|
||||||
triggers: triggers,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
|
|
||||||
for (let i = 0; i < ConveyorEvent.points.length - 1; i++) {
|
|
||||||
const currentPoint = ConveyorEvent.points[i];
|
|
||||||
const nextPoint = ConveyorEvent.points[i + 1];
|
|
||||||
|
|
||||||
if (currentPoint.action.triggers.length > 0) {
|
|
||||||
currentPoint.action.triggers[0].triggeredAsset!.triggeredPoint!.pointUuid =
|
|
||||||
nextPoint.uuid;
|
|
||||||
currentPoint.action.triggers[0].triggeredAsset!.triggeredAction!.actionUuid =
|
|
||||||
nextPoint.action.actionUuid;
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
addEvent(ConveyorEvent);
|
|
||||||
eventData.points = ConveyorEvent.points.map((point) => ({
|
const newFloorItem: Asset = {
|
||||||
uuid: point.uuid,
|
modelUuid: model.uuid,
|
||||||
position: point.position,
|
modelName: selectedItem.name,
|
||||||
rotation: point.rotation,
|
assetId: selectedItem.id,
|
||||||
}));
|
position: [intersectPoint!.x, intersectPoint!.y, intersectPoint!.z],
|
||||||
} else if (selectedItem.type === "Vehicle") {
|
rotation: [0, 0, 0],
|
||||||
const vehicleEvent: VehicleEventSchema = {
|
isLocked: false,
|
||||||
modelUuid: newFloorItem.modelUuid,
|
isVisible: true,
|
||||||
modelName: newFloorItem.modelName,
|
isCollidable: false,
|
||||||
position: newFloorItem.position,
|
opacity: 1,
|
||||||
rotation: newFloorItem.rotation,
|
};
|
||||||
state: "idle",
|
|
||||||
type: "vehicle",
|
|
||||||
speed: 1,
|
// API
|
||||||
point: {
|
|
||||||
uuid: THREE.MathUtils.generateUUID(),
|
// await setAssetsApi(
|
||||||
position: [data.points[0].x, data.points[0].y, data.points[0].z],
|
// organization,
|
||||||
rotation: [0, 0, 0],
|
// newFloorItem.modelUuid,
|
||||||
action: {
|
// newFloorItem.modelName,
|
||||||
actionUuid: THREE.MathUtils.generateUUID(),
|
// newFloorItem.assetId,
|
||||||
actionName: "Action 1",
|
// newFloorItem.position,
|
||||||
actionType: "travel",
|
// { x: 0, y: 0, z: 0 },
|
||||||
unLoadDuration: 5,
|
// false,
|
||||||
loadCapacity: 1,
|
// true,
|
||||||
steeringAngle: 0,
|
// );
|
||||||
pickUpPoint: null,
|
|
||||||
unLoadPoint: null,
|
// SOCKET
|
||||||
triggers: [],
|
|
||||||
},
|
if (selectedItem.type) {
|
||||||
},
|
const data = PointsCalculator(
|
||||||
};
|
selectedItem.type,
|
||||||
addEvent(vehicleEvent);
|
gltf.scene.clone(),
|
||||||
eventData.point = {
|
new THREE.Vector3(...model.rotation)
|
||||||
uuid: vehicleEvent.point.uuid,
|
);
|
||||||
position: vehicleEvent.point.position,
|
|
||||||
rotation: vehicleEvent.point.rotation,
|
if (!data || !data.points) return;
|
||||||
};
|
|
||||||
} else if (selectedItem.type === "ArmBot") {
|
const eventData: any = { type: selectedItem.type, };
|
||||||
const roboticArmEvent: RoboticArmEventSchema = {
|
|
||||||
modelUuid: newFloorItem.modelUuid,
|
if (selectedItem.type === "Conveyor") {
|
||||||
modelName: newFloorItem.modelName,
|
const ConveyorEvent: ConveyorEventSchema = {
|
||||||
position: newFloorItem.position,
|
modelUuid: newFloorItem.modelUuid,
|
||||||
rotation: newFloorItem.rotation,
|
modelName: newFloorItem.modelName,
|
||||||
state: "idle",
|
position: newFloorItem.position,
|
||||||
type: "roboticArm",
|
rotation: newFloorItem.rotation,
|
||||||
speed: 1,
|
state: "idle",
|
||||||
point: {
|
type: "transfer",
|
||||||
uuid: THREE.MathUtils.generateUUID(),
|
speed: 1,
|
||||||
position: [data.points[0].x, data.points[0].y, data.points[0].z],
|
points: data.points.map((point: THREE.Vector3, index: number) => {
|
||||||
rotation: [0, 0, 0],
|
const triggers: TriggerSchema[] = [];
|
||||||
actions: [
|
|
||||||
{
|
if (data.points && index < data.points.length - 1) {
|
||||||
actionUuid: THREE.MathUtils.generateUUID(),
|
triggers.push({
|
||||||
actionName: "Action 1",
|
triggerUuid: THREE.MathUtils.generateUUID(),
|
||||||
actionType: "pickAndPlace",
|
triggerName: `Trigger 1`,
|
||||||
process: {
|
triggerType: "onComplete",
|
||||||
startPoint: null,
|
delay: 0,
|
||||||
endPoint: null,
|
triggeredAsset: {
|
||||||
},
|
triggeredModel: {
|
||||||
triggers: [],
|
modelName: newFloorItem.modelName,
|
||||||
|
modelUuid: newFloorItem.modelUuid,
|
||||||
|
},
|
||||||
|
triggeredPoint: {
|
||||||
|
pointName: `Point`,
|
||||||
|
pointUuid: "",
|
||||||
|
},
|
||||||
|
triggeredAction: {
|
||||||
|
actionName: `Action 1`,
|
||||||
|
actionUuid: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
uuid: THREE.MathUtils.generateUUID(),
|
||||||
|
position: [point.x, point.y, point.z],
|
||||||
|
rotation: [0, 0, 0],
|
||||||
|
action: {
|
||||||
|
actionUuid: THREE.MathUtils.generateUUID(),
|
||||||
|
actionName: `Action 1`,
|
||||||
|
actionType: "default",
|
||||||
|
material: "Default Material",
|
||||||
|
delay: 0,
|
||||||
|
spawnInterval: 5,
|
||||||
|
spawnCount: 1,
|
||||||
|
triggers: triggers,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
for (let i = 0; i < ConveyorEvent.points.length - 1; i++) {
|
||||||
|
const currentPoint = ConveyorEvent.points[i];
|
||||||
|
const nextPoint = ConveyorEvent.points[i + 1];
|
||||||
|
|
||||||
|
if (currentPoint.action.triggers.length > 0) {
|
||||||
|
currentPoint.action.triggers[0].triggeredAsset!.triggeredPoint!.pointUuid = nextPoint.uuid;
|
||||||
|
currentPoint.action.triggers[0].triggeredAsset!.triggeredAction!.actionUuid = nextPoint.action.actionUuid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
addEvent(ConveyorEvent);
|
||||||
|
eventData.points = ConveyorEvent.points.map((point) => ({
|
||||||
|
uuid: point.uuid,
|
||||||
|
position: point.position,
|
||||||
|
rotation: point.rotation,
|
||||||
|
}));
|
||||||
|
} else if (selectedItem.type === "Vehicle") {
|
||||||
|
const vehicleEvent: VehicleEventSchema = {
|
||||||
|
modelUuid: newFloorItem.modelUuid,
|
||||||
|
modelName: newFloorItem.modelName,
|
||||||
|
position: newFloorItem.position,
|
||||||
|
rotation: newFloorItem.rotation,
|
||||||
|
state: "idle",
|
||||||
|
type: "vehicle",
|
||||||
|
speed: 1,
|
||||||
|
point: {
|
||||||
|
uuid: THREE.MathUtils.generateUUID(),
|
||||||
|
position: [data.points[0].x, data.points[0].y, data.points[0].z],
|
||||||
|
rotation: [0, 0, 0],
|
||||||
|
action: {
|
||||||
|
actionUuid: THREE.MathUtils.generateUUID(),
|
||||||
|
actionName: "Action 1",
|
||||||
|
actionType: "travel",
|
||||||
|
unLoadDuration: 5,
|
||||||
|
loadCapacity: 1,
|
||||||
|
steeringAngle: 0,
|
||||||
|
pickUpPoint: null,
|
||||||
|
unLoadPoint: null,
|
||||||
|
triggers: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
addEvent(vehicleEvent);
|
||||||
|
eventData.point = {
|
||||||
|
uuid: vehicleEvent.point.uuid,
|
||||||
|
position: vehicleEvent.point.position,
|
||||||
|
rotation: vehicleEvent.point.rotation,
|
||||||
|
};
|
||||||
|
} else if (selectedItem.type === "ArmBot") {
|
||||||
|
const roboticArmEvent: RoboticArmEventSchema = {
|
||||||
|
modelUuid: newFloorItem.modelUuid,
|
||||||
|
modelName: newFloorItem.modelName,
|
||||||
|
position: newFloorItem.position,
|
||||||
|
rotation: newFloorItem.rotation,
|
||||||
|
state: "idle",
|
||||||
|
type: "roboticArm",
|
||||||
|
speed: 1,
|
||||||
|
point: {
|
||||||
|
uuid: THREE.MathUtils.generateUUID(),
|
||||||
|
position: [data.points[0].x, data.points[0].y, data.points[0].z],
|
||||||
|
rotation: [0, 0, 0],
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
actionUuid: THREE.MathUtils.generateUUID(),
|
||||||
|
actionName: "Action 1",
|
||||||
|
actionType: "pickAndPlace",
|
||||||
|
process: {
|
||||||
|
startPoint: null,
|
||||||
|
endPoint: null,
|
||||||
|
},
|
||||||
|
triggers: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
addEvent(roboticArmEvent);
|
||||||
|
eventData.point = {
|
||||||
|
uuid: roboticArmEvent.point.uuid,
|
||||||
|
position: roboticArmEvent.point.position,
|
||||||
|
rotation: roboticArmEvent.point.rotation,
|
||||||
|
};
|
||||||
|
} else if (selectedItem.type === "StaticMachine") {
|
||||||
|
const machineEvent: MachineEventSchema = {
|
||||||
|
modelUuid: newFloorItem.modelUuid,
|
||||||
|
modelName: newFloorItem.modelName,
|
||||||
|
position: newFloorItem.position,
|
||||||
|
rotation: newFloorItem.rotation,
|
||||||
|
state: "idle",
|
||||||
|
type: "machine",
|
||||||
|
point: {
|
||||||
|
uuid: THREE.MathUtils.generateUUID(),
|
||||||
|
position: [data.points[0].x, data.points[0].y, data.points[0].z],
|
||||||
|
rotation: [0, 0, 0],
|
||||||
|
action: {
|
||||||
|
actionUuid: THREE.MathUtils.generateUUID(),
|
||||||
|
actionName: "Action 1",
|
||||||
|
actionType: "process",
|
||||||
|
processTime: 10,
|
||||||
|
swapMaterial: "Default Material",
|
||||||
|
triggers: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
addEvent(machineEvent);
|
||||||
|
eventData.point = {
|
||||||
|
uuid: machineEvent.point.uuid,
|
||||||
|
position: machineEvent.point.position,
|
||||||
|
rotation: machineEvent.point.rotation,
|
||||||
|
};
|
||||||
|
} else if (selectedItem.type === "Storage") {
|
||||||
|
const storageEvent: StorageEventSchema = {
|
||||||
|
modelUuid: newFloorItem.modelUuid,
|
||||||
|
modelName: newFloorItem.modelName,
|
||||||
|
position: newFloorItem.position,
|
||||||
|
rotation: newFloorItem.rotation,
|
||||||
|
state: "idle",
|
||||||
|
type: "storageUnit",
|
||||||
|
point: {
|
||||||
|
uuid: THREE.MathUtils.generateUUID(),
|
||||||
|
position: [data.points[0].x, data.points[0].y, data.points[0].z],
|
||||||
|
rotation: [0, 0, 0],
|
||||||
|
action: {
|
||||||
|
actionUuid: THREE.MathUtils.generateUUID(),
|
||||||
|
actionName: "Action 1",
|
||||||
|
actionType: "store",
|
||||||
|
storageCapacity: 10,
|
||||||
|
triggers: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
addEvent(storageEvent);
|
||||||
|
eventData.point = {
|
||||||
|
uuid: storageEvent.point.uuid,
|
||||||
|
position: storageEvent.point.position,
|
||||||
|
rotation: storageEvent.point.rotation,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const completeData = {
|
||||||
|
organization,
|
||||||
|
modelUuid: newFloorItem.modelUuid,
|
||||||
|
modelName: newFloorItem.modelName,
|
||||||
|
assetId: newFloorItem.assetId,
|
||||||
|
position: newFloorItem.position,
|
||||||
|
rotation: {
|
||||||
|
x: model.rotation.x,
|
||||||
|
y: model.rotation.y,
|
||||||
|
z: model.rotation.z,
|
||||||
},
|
},
|
||||||
],
|
isLocked: false,
|
||||||
},
|
isVisible: true,
|
||||||
};
|
socketId: socket.id,
|
||||||
addEvent(roboticArmEvent);
|
eventData: eventData,
|
||||||
eventData.point = {
|
versionId: versionId,
|
||||||
uuid: roboticArmEvent.point.uuid,
|
projectId: projectId,
|
||||||
position: roboticArmEvent.point.position,
|
userId: userId,
|
||||||
rotation: roboticArmEvent.point.rotation,
|
};
|
||||||
};
|
|
||||||
} else if (selectedItem.type === "StaticMachine") {
|
socket.emit("v1:model-asset:add", completeData);
|
||||||
const machineEvent: MachineEventSchema = {
|
|
||||||
modelUuid: newFloorItem.modelUuid,
|
const asset: Asset = {
|
||||||
modelName: newFloorItem.modelName,
|
modelUuid: completeData.modelUuid,
|
||||||
position: newFloorItem.position,
|
modelName: completeData.modelName,
|
||||||
rotation: newFloorItem.rotation,
|
assetId: completeData.assetId,
|
||||||
state: "idle",
|
position: completeData.position,
|
||||||
type: "machine",
|
rotation: [
|
||||||
point: {
|
completeData.rotation.x,
|
||||||
uuid: THREE.MathUtils.generateUUID(),
|
completeData.rotation.y,
|
||||||
position: [data.points[0].x, data.points[0].y, data.points[0].z],
|
completeData.rotation.z,
|
||||||
rotation: [0, 0, 0],
|
] as [number, number, number],
|
||||||
action: {
|
isLocked: completeData.isLocked,
|
||||||
actionUuid: THREE.MathUtils.generateUUID(),
|
isCollidable: false,
|
||||||
actionName: "Action 1",
|
isVisible: completeData.isVisible,
|
||||||
actionType: "process",
|
opacity: 1,
|
||||||
processTime: 10,
|
eventData: completeData.eventData,
|
||||||
swapMaterial: "Default Material",
|
};
|
||||||
triggers: [],
|
|
||||||
},
|
addAsset(asset);
|
||||||
},
|
} else {
|
||||||
};
|
const data = {
|
||||||
addEvent(machineEvent);
|
organization,
|
||||||
eventData.point = {
|
modelUuid: newFloorItem.modelUuid,
|
||||||
uuid: machineEvent.point.uuid,
|
modelName: newFloorItem.modelName,
|
||||||
position: machineEvent.point.position,
|
assetId: newFloorItem.assetId,
|
||||||
rotation: machineEvent.point.rotation,
|
position: newFloorItem.position,
|
||||||
};
|
rotation: {
|
||||||
} else if (selectedItem.type === "Storage") {
|
x: model.rotation.x,
|
||||||
const storageEvent: StorageEventSchema = {
|
y: model.rotation.y,
|
||||||
modelUuid: newFloorItem.modelUuid,
|
z: model.rotation.z,
|
||||||
modelName: newFloorItem.modelName,
|
},
|
||||||
position: newFloorItem.position,
|
isLocked: false,
|
||||||
rotation: newFloorItem.rotation,
|
isVisible: true,
|
||||||
state: "idle",
|
socketId: socket.id,
|
||||||
type: "storageUnit",
|
versionId: versionId,
|
||||||
point: {
|
projectId: projectId,
|
||||||
uuid: THREE.MathUtils.generateUUID(),
|
userId: userId,
|
||||||
position: [data.points[0].x, data.points[0].y, data.points[0].z],
|
};
|
||||||
rotation: [0, 0, 0],
|
|
||||||
action: {
|
socket.emit("v1:model-asset:add", data);
|
||||||
actionUuid: THREE.MathUtils.generateUUID(),
|
|
||||||
actionName: "Action 1",
|
const asset = {
|
||||||
actionType: "store",
|
modelUuid: data.modelUuid,
|
||||||
storageCapacity: 10,
|
modelName: data.modelName,
|
||||||
triggers: [],
|
assetId: data.assetId,
|
||||||
},
|
position: data.position,
|
||||||
},
|
rotation: [data.rotation.x, data.rotation.y, data.rotation.z] as [
|
||||||
};
|
number,
|
||||||
addEvent(storageEvent);
|
number,
|
||||||
eventData.point = {
|
number
|
||||||
uuid: storageEvent.point.uuid,
|
],
|
||||||
position: storageEvent.point.position,
|
isLocked: data.isLocked,
|
||||||
rotation: storageEvent.point.rotation,
|
isCollidable: false,
|
||||||
};
|
isVisible: data.isVisible,
|
||||||
|
opacity: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
addAsset(asset);
|
||||||
}
|
}
|
||||||
|
|
||||||
const completeData = {
|
|
||||||
organization,
|
|
||||||
modelUuid: newFloorItem.modelUuid,
|
|
||||||
modelName: newFloorItem.modelName,
|
|
||||||
assetId: newFloorItem.assetId,
|
|
||||||
position: newFloorItem.position,
|
|
||||||
rotation: {
|
|
||||||
x: model.rotation.x,
|
|
||||||
y: model.rotation.y,
|
|
||||||
z: model.rotation.z,
|
|
||||||
},
|
|
||||||
isLocked: false,
|
|
||||||
isVisible: true,
|
|
||||||
socketId: socket.id,
|
|
||||||
eventData: eventData,
|
|
||||||
versionId: versionId,
|
|
||||||
projectId: projectId,
|
|
||||||
userId: userId,
|
|
||||||
};
|
|
||||||
|
|
||||||
socket.emit("v1:model-asset:add", completeData);
|
|
||||||
|
|
||||||
const asset: Asset = {
|
|
||||||
modelUuid: completeData.modelUuid,
|
|
||||||
modelName: completeData.modelName,
|
|
||||||
assetId: completeData.assetId,
|
|
||||||
position: completeData.position,
|
|
||||||
rotation: [
|
|
||||||
completeData.rotation.x,
|
|
||||||
completeData.rotation.y,
|
|
||||||
completeData.rotation.z,
|
|
||||||
] as [number, number, number],
|
|
||||||
isLocked: completeData.isLocked,
|
|
||||||
isCollidable: false,
|
|
||||||
isVisible: completeData.isVisible,
|
|
||||||
opacity: 1,
|
|
||||||
eventData: completeData.eventData,
|
|
||||||
};
|
|
||||||
|
|
||||||
addAsset(asset);
|
|
||||||
} else {
|
|
||||||
const data = {
|
|
||||||
organization,
|
|
||||||
modelUuid: newFloorItem.modelUuid,
|
|
||||||
modelName: newFloorItem.modelName,
|
|
||||||
assetId: newFloorItem.assetId,
|
|
||||||
position: newFloorItem.position,
|
|
||||||
rotation: {
|
|
||||||
x: model.rotation.x,
|
|
||||||
y: model.rotation.y,
|
|
||||||
z: model.rotation.z,
|
|
||||||
},
|
|
||||||
isLocked: false,
|
|
||||||
isVisible: true,
|
|
||||||
socketId: socket.id,
|
|
||||||
versionId: versionId,
|
|
||||||
projectId: projectId,
|
|
||||||
userId: userId,
|
|
||||||
};
|
|
||||||
|
|
||||||
socket.emit("v1:model-asset:add", data);
|
|
||||||
|
|
||||||
const asset = {
|
|
||||||
modelUuid: data.modelUuid,
|
|
||||||
modelName: data.modelName,
|
|
||||||
assetId: data.assetId,
|
|
||||||
position: data.position,
|
|
||||||
rotation: [data.rotation.x, data.rotation.y, data.rotation.z] as [
|
|
||||||
number,
|
|
||||||
number,
|
|
||||||
number
|
|
||||||
],
|
|
||||||
isLocked: data.isLocked,
|
|
||||||
isCollidable: false,
|
|
||||||
isVisible: data.isVisible,
|
|
||||||
opacity: 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
addAsset(asset);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default addAssetModel;
|
export default addAssetModel;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { retrieveGLTF, storeGLTF } from '../../../../../utils/indexDB/idbUtils';
|
|||||||
import { GLTF, GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
|
import { GLTF, GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
|
||||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
|
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
|
||||||
import { ThreeEvent, useFrame, useThree } from '@react-three/fiber';
|
import { ThreeEvent, useFrame, useThree } from '@react-three/fiber';
|
||||||
import { useActiveTool, useDeletableFloorItem, useRenderDistance, useSelectedFloorItem, useSocketStore, useToggleView, useToolMode } from '../../../../../store/builder/store';
|
import { useActiveTool, useDeletableFloorItem, useLimitDistance, useRenderDistance, useSelectedFloorItem, useSocketStore, useToggleView, useToolMode } from '../../../../../store/builder/store';
|
||||||
import { AssetBoundingBox } from '../../functions/assetBoundingBox';
|
import { AssetBoundingBox } from '../../functions/assetBoundingBox';
|
||||||
import { CameraControls, Html } from '@react-three/drei';
|
import { CameraControls, Html } from '@react-three/drei';
|
||||||
import useModuleStore, { useSubModuleStore } from '../../../../../store/useModuleStore';
|
import useModuleStore, { useSubModuleStore } from '../../../../../store/useModuleStore';
|
||||||
@@ -34,6 +34,7 @@ function Model({ asset }: { readonly asset: Asset }) {
|
|||||||
const { socket } = useSocketStore();
|
const { socket } = useSocketStore();
|
||||||
const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem();
|
const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem();
|
||||||
const { setSelectedFloorItem } = useSelectedFloorItem();
|
const { setSelectedFloorItem } = useSelectedFloorItem();
|
||||||
|
const { limitDistance } = useLimitDistance();
|
||||||
const { renderDistance } = useRenderDistance();
|
const { renderDistance } = useRenderDistance();
|
||||||
const [isRendered, setIsRendered] = useState(false);
|
const [isRendered, setIsRendered] = useState(false);
|
||||||
const url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
const url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||||
@@ -162,10 +163,16 @@ function Model({ asset }: { readonly asset: Asset }) {
|
|||||||
|
|
||||||
useFrame(() => {
|
useFrame(() => {
|
||||||
const assetPosition = new THREE.Vector3(...asset.position);
|
const assetPosition = new THREE.Vector3(...asset.position);
|
||||||
if (!isRendered && assetPosition.distanceTo(camera.position) <= renderDistance) {
|
if (limitDistance) {
|
||||||
setIsRendered(true);
|
if (!isRendered && assetPosition.distanceTo(camera.position) <= renderDistance) {
|
||||||
} else if (isRendered && assetPosition.distanceTo(camera.position) > renderDistance) {
|
setIsRendered(true);
|
||||||
setIsRendered(false);
|
} else if (isRendered && assetPosition.distanceTo(camera.position) > renderDistance) {
|
||||||
|
setIsRendered(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!isRendered) {
|
||||||
|
setIsRendered(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,139 +1,68 @@
|
|||||||
////////// Three and React Three Fiber Imports //////////
|
////////// Three and React Three Fiber Imports //////////
|
||||||
|
|
||||||
import * as THREE from "three";
|
import * as THREE from "three";
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef } from "react";
|
||||||
import { useThree, useFrame } from "@react-three/fiber";
|
import { useFrame, useThree } from "@react-three/fiber";
|
||||||
|
import { Geometry } from "@react-three/csg";
|
||||||
////////// Component Imports //////////
|
|
||||||
|
|
||||||
import DistanceText from "./geomentries/lines/distanceText/distanceText";
|
|
||||||
import ReferenceDistanceText from "./geomentries/lines/distanceText/referenceDistanceText";
|
|
||||||
|
|
||||||
////////// Zustand State Imports //////////
|
////////// Zustand State Imports //////////
|
||||||
|
|
||||||
import {
|
import {
|
||||||
useToggleView,
|
useToggleView,
|
||||||
useActiveLayer,
|
|
||||||
useWallVisibility,
|
useWallVisibility,
|
||||||
useRoofVisibility,
|
useRoofVisibility,
|
||||||
useShadows,
|
useShadows,
|
||||||
useUpdateScene,
|
|
||||||
useWalls,
|
|
||||||
useToolMode,
|
useToolMode,
|
||||||
useRefTextUpdate,
|
|
||||||
useRenderDistance,
|
useRenderDistance,
|
||||||
useLimitDistance,
|
useLimitDistance,
|
||||||
} from "../../store/builder/store";
|
} from "../../store/builder/store";
|
||||||
|
|
||||||
////////// 3D Function Imports //////////
|
////////// 3D Function Imports //////////
|
||||||
|
|
||||||
import loadWalls from "./geomentries/walls/loadWalls";
|
|
||||||
|
|
||||||
import * as Types from "../../types/world/worldTypes";
|
import * as Types from "../../types/world/worldTypes";
|
||||||
|
|
||||||
import SocketResponses from "../collaboration/socket/socketResponses.dev";
|
import SocketResponses from "../collaboration/socket/socketResponses.dev";
|
||||||
import FloorPlanGroup from "./groups/floorPlanGroup";
|
|
||||||
import FloorGroup from "./groups/floorGroup";
|
|
||||||
import Draw from "./functions/draw";
|
|
||||||
import WallsAndWallItems from "./groups/wallsAndWallItems";
|
|
||||||
import Ground from "../scene/environment/ground";
|
import Ground from "../scene/environment/ground";
|
||||||
import { findEnvironment } from "../../services/factoryBuilder/environment/findEnvironment";
|
import { findEnvironment } from "../../services/factoryBuilder/environment/findEnvironment";
|
||||||
import Layer2DVisibility from "./geomentries/layers/layer2DVisibility";
|
|
||||||
import ZoneGroup from "./groups/zoneGroup";
|
|
||||||
import MeasurementTool from "../scene/tools/measurementTool";
|
import MeasurementTool from "../scene/tools/measurementTool";
|
||||||
import NavMesh from "../simulation/vehicle/navMesh/navMesh";
|
import NavMesh from "../simulation/vehicle/navMesh/navMesh";
|
||||||
import CalculateAreaGroup from "./groups/calculateAreaGroup";
|
import CalculateAreaGroup from "./groups/calculateAreaGroup";
|
||||||
import LayoutImage from "./layout/layoutImage";
|
import LayoutImage from "./layout/layoutImage";
|
||||||
import AssetsGroup from "./asset/assetsGroup";
|
import AssetsGroup from "./asset/assetsGroup";
|
||||||
import { Bvh } from "@react-three/drei";
|
|
||||||
import DxfFile from "./dfx/LoadBlueprint";
|
import DxfFile from "./dfx/LoadBlueprint";
|
||||||
import { useParams } from "react-router-dom";
|
|
||||||
import AislesGroup from "./aisle/aislesGroup";
|
import AislesGroup from "./aisle/aislesGroup";
|
||||||
import WallGroup from "./wall/wallGroup";
|
import WallGroup from "./wall/wallGroup";
|
||||||
|
import FloorGroup from "./floor/floorGroup";
|
||||||
|
import ZoneGroup from "./zone/zoneGroup";
|
||||||
|
|
||||||
|
import { useParams } from "react-router-dom";
|
||||||
import { useBuilderStore } from "../../store/builder/useBuilderStore";
|
import { useBuilderStore } from "../../store/builder/useBuilderStore";
|
||||||
import { getUserData } from "../../functions/getUserData";
|
import { getUserData } from "../../functions/getUserData";
|
||||||
|
import WallAssetGroup from "./wallAsset/wallAssetGroup";
|
||||||
|
|
||||||
export default function Builder() {
|
export default function Builder() {
|
||||||
const state = useThree<Types.ThreeState>(); // Importing the state from the useThree hook, which contains the scene, camera, and other Three.js elements.
|
const state = useThree<Types.ThreeState>();
|
||||||
const csg = useRef(); // Reference for CSG object, used for 3D modeling.
|
const plane = useRef<THREE.Mesh>(null);
|
||||||
const CSGGroup = useRef() as Types.RefMesh; // Reference to a group of CSG objects.
|
const csgRef = useRef<any>(null);
|
||||||
const scene = useRef() as Types.RefScene; // Reference to the scene.
|
|
||||||
const dragPointControls = useRef() as Types.RefDragControl; // Reference for drag point controls, an array for drag control.
|
|
||||||
|
|
||||||
// Assigning the scene and camera from the Three.js state to the references.
|
const { toggleView } = useToggleView();
|
||||||
|
const { setToolMode } = useToolMode();
|
||||||
const plane = useRef<THREE.Mesh>(null); // Reference for a plane object for raycaster reference.
|
|
||||||
const grid = useRef() as any; // Reference for a grid object for raycaster reference.
|
|
||||||
const snappedPoint = useRef() as Types.RefVector3; // Reference for storing a snapped point at the (end = isSnapped) and (start = ispreSnapped) of the line.
|
|
||||||
const isSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (end).
|
|
||||||
const anglesnappedPoint = useRef() as Types.RefVector3; // Reference for storing an angle-snapped point when the line is in 90 degree etc...
|
|
||||||
const isAngleSnapped = useRef(false) as Types.RefBoolean; // Boolean to indicate if angle snapping is active.
|
|
||||||
const isSnappedUUID = useRef() as Types.RefString; // UUID reference to identify the snapped point.
|
|
||||||
const ispreSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (start).
|
|
||||||
const Tube = useRef() as Types.RefTubeGeometry; // Reference for tubes used for reference line creation and updation.
|
|
||||||
const line = useRef([]) as Types.RefLine; // Reference for line which stores the current line that is being drawn.
|
|
||||||
const lines = useRef([]) as Types.RefLines; // Reference for lines which stores all the lines that are ever drawn.
|
|
||||||
const onlyFloorline = useRef<Types.OnlyFloorLine>([]); // Reference for floor lines which does not have walls or roof and have only floor used to store the current line that is being drawn.
|
|
||||||
const onlyFloorlines = useRef<Types.OnlyFloorLines>([]); // Reference for all the floor lines that are ever drawn.
|
|
||||||
const ReferenceLineMesh = useRef() as Types.RefMesh; // Reference for storing the mesh of the reference line for moving it during draw.
|
|
||||||
const LineCreated = useRef(false) as Types.RefBoolean; // Boolean to track whether the reference line is created or not.
|
|
||||||
const referencePole = useRef() as Types.RefMesh; // Reference for a pole that is used as the reference for the user to show where it is placed.
|
|
||||||
const floorGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the roofs and the floors.
|
|
||||||
const floorPlanGroup = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines group and the points group.
|
|
||||||
const floorPlanGroupLine = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines that are drawn.
|
|
||||||
const floorPlanGroupPoint = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the points that are created.
|
|
||||||
const currentLayerPoint = useRef([]) as Types.RefMeshArray; // Reference for points that re in the current layer used to update the points in drag controls.
|
|
||||||
const hoveredDeletablePoint = useRef() as Types.RefMesh; // Reference for the currently hovered point that can be deleted.
|
|
||||||
const hoveredDeletableLine = useRef() as Types.RefMesh; // Reference for the currently hovered line that can be deleted.
|
|
||||||
const hoveredDeletableWallItem = useRef() as Types.RefMesh; // Reference for the currently hovered wall item that can be deleted.
|
|
||||||
const hoveredDeletablePillar = useRef() as Types.RefMesh; // Reference for the currently hovered pillar that can be deleted.
|
|
||||||
const currentWallItem = useRef() as Types.RefMesh; // Reference for the currently selected wall item that can be scaled, dragged etc...
|
|
||||||
|
|
||||||
const cursorPosition = new THREE.Vector3(); // 3D vector for storing the cursor position.
|
|
||||||
|
|
||||||
const [selectedItemsIndex, setSelectedItemsIndex] = useState<Types.Number | null>(null); // State for tracking the index of the selected item.
|
|
||||||
const { activeLayer } = useActiveLayer(); // State that changes based on which layer the user chooses in Layers.jsx.
|
|
||||||
const { toggleView } = useToggleView(); // State for toggling between 2D and 3D.
|
|
||||||
const { toolMode, setToolMode } = useToolMode();
|
|
||||||
const { setRoofVisibility } = useRoofVisibility();
|
const { setRoofVisibility } = useRoofVisibility();
|
||||||
const { setWallVisibility } = useWallVisibility();
|
const { setWallVisibility } = useWallVisibility();
|
||||||
const { setShadows } = useShadows();
|
const { setShadows } = useShadows();
|
||||||
const { setRenderDistance } = useRenderDistance();
|
const { setRenderDistance } = useRenderDistance();
|
||||||
const { setLimitDistance } = useLimitDistance();
|
const { setLimitDistance } = useLimitDistance();
|
||||||
const { setUpdateScene } = useUpdateScene();
|
|
||||||
const { setWalls } = useWalls();
|
|
||||||
const { refTextupdate, setRefTextUpdate } = useRefTextUpdate();
|
|
||||||
const { projectId } = useParams();
|
const { projectId } = useParams();
|
||||||
const { setHoveredPoint, setHoveredLine } = useBuilderStore();
|
const { setHoveredPoint, setHoveredLine } = useBuilderStore();
|
||||||
const { userId, organization } = getUserData();
|
const { userId, organization } = getUserData();
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
////////// All Toggle's //////////
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setRefTextUpdate((prevUpdate: number) => prevUpdate - 1);
|
if (!toggleView) {
|
||||||
if (toggleView) {
|
|
||||||
Layer2DVisibility(
|
|
||||||
activeLayer,
|
|
||||||
floorPlanGroup,
|
|
||||||
floorPlanGroupLine,
|
|
||||||
floorPlanGroupPoint,
|
|
||||||
currentLayerPoint,
|
|
||||||
dragPointControls
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
setHoveredLine(null);
|
setHoveredLine(null);
|
||||||
setHoveredPoint(null);
|
setHoveredPoint(null);
|
||||||
state.gl.domElement.style.cursor = 'default';
|
state.gl.domElement.style.cursor = 'default';
|
||||||
setToolMode('cursor');
|
setToolMode('cursor');
|
||||||
loadWalls(lines, setWalls);
|
|
||||||
setUpdateScene(true);
|
|
||||||
line.current = [];
|
|
||||||
}
|
}
|
||||||
}, [toggleView]);
|
}, [toggleView]);
|
||||||
|
|
||||||
@@ -152,131 +81,45 @@ export default function Builder() {
|
|||||||
fetchVisibility();
|
fetchVisibility();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
////////// UseFrame is Here //////////
|
|
||||||
|
|
||||||
useFrame(() => {
|
useFrame(() => {
|
||||||
if (toolMode) {
|
if (csgRef.current) {
|
||||||
Draw(
|
csgRef.current.update();
|
||||||
state,
|
|
||||||
plane,
|
|
||||||
cursorPosition,
|
|
||||||
floorPlanGroupPoint,
|
|
||||||
snappedPoint,
|
|
||||||
isSnapped,
|
|
||||||
isSnappedUUID,
|
|
||||||
line,
|
|
||||||
ispreSnapped,
|
|
||||||
floorPlanGroup,
|
|
||||||
ReferenceLineMesh,
|
|
||||||
LineCreated,
|
|
||||||
setRefTextUpdate,
|
|
||||||
Tube,
|
|
||||||
anglesnappedPoint,
|
|
||||||
isAngleSnapped,
|
|
||||||
toolMode
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
////////// Return //////////
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Ground grid={grid} plane={plane} />
|
<Ground plane={plane} />
|
||||||
|
|
||||||
<Bvh firstHitOnly>
|
<SocketResponses />
|
||||||
<DistanceText key={toggleView} />
|
|
||||||
</Bvh>
|
|
||||||
|
|
||||||
<ReferenceDistanceText
|
<AssetsGroup plane={plane} />
|
||||||
key={refTextupdate}
|
|
||||||
line={ReferenceLineMesh.current}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Bvh firstHitOnly>
|
<mesh name='Walls-And-WallAssets-Group'>
|
||||||
<SocketResponses
|
<Geometry ref={csgRef} useGroups>
|
||||||
floorPlanGroup={floorPlanGroup}
|
|
||||||
lines={lines}
|
|
||||||
floorGroup={floorGroup}
|
|
||||||
scene={scene}
|
|
||||||
onlyFloorlines={onlyFloorlines}
|
|
||||||
currentLayerPoint={currentLayerPoint}
|
|
||||||
floorPlanGroupPoint={floorPlanGroupPoint}
|
|
||||||
floorPlanGroupLine={floorPlanGroupLine}
|
|
||||||
dragPointControls={dragPointControls}
|
|
||||||
/>
|
|
||||||
</Bvh>
|
|
||||||
|
|
||||||
<WallsAndWallItems
|
<WallGroup />
|
||||||
CSGGroup={CSGGroup}
|
|
||||||
setSelectedItemsIndex={setSelectedItemsIndex}
|
|
||||||
selectedItemsIndex={selectedItemsIndex}
|
|
||||||
currentWallItem={currentWallItem}
|
|
||||||
csg={csg}
|
|
||||||
lines={lines}
|
|
||||||
hoveredDeletableWallItem={hoveredDeletableWallItem}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Bvh firstHitOnly>
|
<WallAssetGroup />
|
||||||
|
|
||||||
<FloorGroup
|
</Geometry>
|
||||||
floorGroup={floorGroup}
|
</mesh>
|
||||||
lines={lines}
|
|
||||||
referencePole={referencePole}
|
|
||||||
hoveredDeletablePillar={hoveredDeletablePillar}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<FloorPlanGroup
|
<AislesGroup />
|
||||||
floorPlanGroup={floorPlanGroup}
|
|
||||||
floorPlanGroupLine={floorPlanGroupLine}
|
|
||||||
floorPlanGroupPoint={floorPlanGroupPoint}
|
|
||||||
floorGroup={floorGroup}
|
|
||||||
currentLayerPoint={currentLayerPoint}
|
|
||||||
dragPointControls={dragPointControls}
|
|
||||||
hoveredDeletablePoint={hoveredDeletablePoint}
|
|
||||||
hoveredDeletableLine={hoveredDeletableLine}
|
|
||||||
plane={plane}
|
|
||||||
line={line}
|
|
||||||
lines={lines}
|
|
||||||
onlyFloorline={onlyFloorline}
|
|
||||||
onlyFloorlines={onlyFloorlines}
|
|
||||||
ReferenceLineMesh={ReferenceLineMesh}
|
|
||||||
LineCreated={LineCreated}
|
|
||||||
isSnapped={isSnapped}
|
|
||||||
ispreSnapped={ispreSnapped}
|
|
||||||
snappedPoint={snappedPoint}
|
|
||||||
isSnappedUUID={isSnappedUUID}
|
|
||||||
isAngleSnapped={isAngleSnapped}
|
|
||||||
anglesnappedPoint={anglesnappedPoint}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<ZoneGroup />
|
<FloorGroup />
|
||||||
|
|
||||||
<AssetsGroup
|
<ZoneGroup />
|
||||||
floorGroup={floorGroup}
|
|
||||||
plane={plane}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<AislesGroup />
|
<MeasurementTool />
|
||||||
|
|
||||||
<MeasurementTool />
|
<CalculateAreaGroup />
|
||||||
|
|
||||||
<CalculateAreaGroup />
|
<NavMesh />
|
||||||
|
|
||||||
<NavMesh lines={lines} />
|
<DxfFile />
|
||||||
|
|
||||||
<DxfFile
|
<LayoutImage />
|
||||||
lines={lines}
|
|
||||||
dragPointControls={dragPointControls}
|
|
||||||
currentLayerPoint={currentLayerPoint}
|
|
||||||
floorPlanGroupLine={floorPlanGroupLine}
|
|
||||||
floorPlanGroupPoint={floorPlanGroupPoint}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<LayoutImage />
|
|
||||||
</Bvh>
|
|
||||||
|
|
||||||
{/* <WallGroup /> */}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,40 +1,21 @@
|
|||||||
import { useEffect, useRef } from 'react';
|
import { useEffect, useRef } from 'react';
|
||||||
import { useDfxUpload, useSocketStore, useToggleView, useUpdateScene } from '../../../store/builder/store';
|
import { useDfxUpload, useSocketStore, useToggleView, useUpdateScene } from '../../../store/builder/store';
|
||||||
import { LineBasicMaterial, Line } from 'three';
|
import { LineBasicMaterial, Line } from 'three';
|
||||||
import loadInitialPoint from '../IntialLoad/loadInitialPoint';
|
|
||||||
import loadInitialLine from '../IntialLoad/loadInitialLine';
|
|
||||||
import { TransformControls } from '@react-three/drei';
|
import { TransformControls } from '@react-three/drei';
|
||||||
import { getWallPointsFromBlueprint } from './functions/getWallPointsFromBlueprint';
|
import { getWallPointsFromBlueprint } from './functions/getWallPointsFromBlueprint';
|
||||||
import * as Types from '../../../types/world/worldTypes';
|
import * as Types from '../../../types/world/worldTypes';
|
||||||
import arrayLineToObject from '../geomentries/lines/lineConvertions/arrayLineToObject';
|
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import { getUserData } from '../../../functions/getUserData';
|
import { getUserData } from '../../../functions/getUserData';
|
||||||
import { useVersionContext } from '../version/versionContext';
|
import { useVersionContext } from '../version/versionContext';
|
||||||
|
|
||||||
// Interface defining the props for the DxfFile component
|
|
||||||
interface DxfFileProps {
|
|
||||||
lines: Types.RefLines; // Reference to lines in the DXF file
|
|
||||||
floorPlanGroupPoint: Types.RefGroup; // Reference to floor plan points group
|
|
||||||
dragPointControls: Types.RefDragControl; // Reference to drag controls
|
|
||||||
floorPlanGroupLine: Types.RefGroup; // Reference to floor plan lines group
|
|
||||||
currentLayerPoint: Types.RefMeshArray; // Reference to current layer points
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DxfFile component handles the rendering and manipulation of DXf file data in a 3D scene.
|
* DxfFile component handles the rendering and manipulation of DXf file data in a 3D scene.
|
||||||
* It processes the DXF data to create points and lines representing walls and allows
|
* It processes the DXF data to create points and lines representing walls and allows
|
||||||
* transformation controls for interactive editing.
|
* transformation controls for interactive editing.
|
||||||
*/
|
*/
|
||||||
const DxfFile = ({
|
const DxfFile = () => {
|
||||||
floorPlanGroupPoint,
|
|
||||||
currentLayerPoint,
|
|
||||||
dragPointControls,
|
|
||||||
floorPlanGroupLine,
|
|
||||||
lines,
|
|
||||||
}: DxfFileProps) => {
|
|
||||||
// State management hooks
|
// State management hooks
|
||||||
const { dfxuploaded, dfxWallGenerate, setObjValue, objValue } = useDfxUpload();
|
const { dfxuploaded, dfxWallGenerate, setObjValue, objValue } = useDfxUpload();
|
||||||
const { setUpdateScene } = useUpdateScene();
|
|
||||||
const { toggleView } = useToggleView();
|
const { toggleView } = useToggleView();
|
||||||
const { socket } = useSocketStore();
|
const { socket } = useSocketStore();
|
||||||
const { selectedVersionStore } = useVersionContext();
|
const { selectedVersionStore } = useVersionContext();
|
||||||
@@ -50,55 +31,34 @@ const DxfFile = ({
|
|||||||
* Loads initial points and lines from the DXF data and updates the scene.
|
* Loads initial points and lines from the DXF data and updates the scene.
|
||||||
*/
|
*/
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (
|
if (dfxWallGenerate) {
|
||||||
dfxWallGenerate &&
|
|
||||||
dragPointControls &&
|
|
||||||
floorPlanGroupPoint &&
|
|
||||||
currentLayerPoint &&
|
|
||||||
floorPlanGroupLine
|
|
||||||
) {
|
|
||||||
// Store generated lines in ref
|
// Store generated lines in ref
|
||||||
lines.current.push(...dfxWallGenerate);
|
// lines.current.push(...dfxWallGenerate);
|
||||||
dfxWallGenerate.map((line: any) => {
|
// dfxWallGenerate.map((line: any) => {
|
||||||
const lineData = arrayLineToObject(line as Types.Line);
|
// const lineData = arrayLineToObject(line as Types.Line);
|
||||||
|
|
||||||
//REST
|
// //REST
|
||||||
|
|
||||||
// setLine(organization, lineData.layer!, lineData.line!, lineData.type!);
|
// // setLine(organization, lineData.layer!, lineData.line!, lineData.type!);
|
||||||
|
|
||||||
//SOCKET
|
// //SOCKET
|
||||||
|
|
||||||
const input = {
|
// const input = {
|
||||||
organization,
|
// organization,
|
||||||
layer: lineData.layer,
|
// layer: lineData.layer,
|
||||||
line: lineData.line,
|
// line: lineData.line,
|
||||||
type: lineData.type,
|
// type: lineData.type,
|
||||||
socketId: socket.id,
|
// socketId: socket.id,
|
||||||
versionId: selectedVersion?.versionId || '',
|
// versionId: selectedVersion?.versionId || '',
|
||||||
projectId,
|
// projectId,
|
||||||
userId
|
// userId
|
||||||
}
|
// }
|
||||||
|
|
||||||
console.log('input: ', input);
|
// socket.emit('v1:Line:create', input);
|
||||||
socket.emit('v1:Line:create', input);
|
|
||||||
|
|
||||||
})
|
// })
|
||||||
|
|
||||||
// Load initial points and lines from DXF data
|
|
||||||
loadInitialPoint(lines, floorPlanGroupPoint, currentLayerPoint, dragPointControls);
|
|
||||||
loadInitialLine(floorPlanGroupLine, lines);
|
|
||||||
|
|
||||||
// Trigger scene update
|
|
||||||
setUpdateScene(true);
|
|
||||||
}
|
}
|
||||||
}, [
|
}, [dfxWallGenerate]);
|
||||||
lines,
|
|
||||||
floorPlanGroupLine,
|
|
||||||
floorPlanGroupPoint,
|
|
||||||
currentLayerPoint,
|
|
||||||
dragPointControls,
|
|
||||||
dfxWallGenerate,
|
|
||||||
]);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles transformation changes for individual lines.
|
* Handles transformation changes for individual lines.
|
||||||
|
|||||||
@@ -1,100 +0,0 @@
|
|||||||
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";
|
|
||||||
import { getUserData } from "../../../functions/getUserData";
|
|
||||||
|
|
||||||
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>,
|
|
||||||
projectId?: string,
|
|
||||||
versionId?: string
|
|
||||||
) {
|
|
||||||
////////// 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;
|
|
||||||
const { userId, organization, email } = getUserData();
|
|
||||||
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;
|
|
||||||
|
|
||||||
//REST
|
|
||||||
|
|
||||||
// await updatePoint(
|
|
||||||
// organization,
|
|
||||||
// { "x": event.object.position.x, "y": 0.01, "z": event.object.position.z },
|
|
||||||
// event.object.uuid,
|
|
||||||
// )
|
|
||||||
|
|
||||||
//SOCKET
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
organization,
|
|
||||||
position: {
|
|
||||||
x: event.object.position.x,
|
|
||||||
y: 0.01,
|
|
||||||
z: event.object.position.z,
|
|
||||||
},
|
|
||||||
uuid: event.object.uuid,
|
|
||||||
socketId: socket.id,
|
|
||||||
versionId,
|
|
||||||
projectId,
|
|
||||||
userId,
|
|
||||||
};
|
|
||||||
|
|
||||||
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 +0,0 @@
|
|||||||
import * as Types from "../../../types/world/worldTypes";
|
|
||||||
|
|
||||||
export default function handleContextMenu(
|
|
||||||
menuVisible: Types.Boolean,
|
|
||||||
setMenuVisible: Types.BooleanState
|
|
||||||
): void {
|
|
||||||
// setMenuVisible(true)
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
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) {
|
|
||||||
if (event.object) {
|
|
||||||
const wallItemModel = event.object;
|
|
||||||
let currentObject = wallItemModel as THREE.Object3D;
|
|
||||||
while (currentObject) {
|
|
||||||
if (currentObject.name === "Scene") {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
currentObject = currentObject.parent as THREE.Object3D;
|
|
||||||
}
|
|
||||||
if (!currentObject) return;
|
|
||||||
const clickedIndex = wallItems.findIndex((item) => item.model?.uuid === currentObject.uuid);
|
|
||||||
if (clickedIndex !== -1) {
|
|
||||||
setSelectedItemsIndex(clickedIndex);
|
|
||||||
const wallItemModel = wallItems[clickedIndex]?.model;
|
|
||||||
if (wallItemModel) {
|
|
||||||
setSelectedWallItem(wallItemModel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export default handleMeshDown;
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
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;
|
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import { useMemo } from 'react';
|
||||||
|
import { DoubleSide, Shape, Vector2 } from 'three';
|
||||||
|
import { Extrude } from '@react-three/drei';
|
||||||
|
import * as Constants from '../../../../../types/world/worldConstants';
|
||||||
|
|
||||||
|
function Floor2DInstance({ floor }: { floor: Floor }) {
|
||||||
|
const savedTheme: string | null = localStorage.getItem("theme");
|
||||||
|
|
||||||
|
const shape = useMemo(() => {
|
||||||
|
const shape = new Shape();
|
||||||
|
const points = floor.points.map(p => new Vector2(p.position[0], p.position[2]));
|
||||||
|
if (points.length < 3) return null;
|
||||||
|
shape.moveTo(points[0].x, points[0].y);
|
||||||
|
for (let i = 1; i < points.length; i++) {
|
||||||
|
shape.lineTo(points[i].x, points[i].y);
|
||||||
|
}
|
||||||
|
return shape;
|
||||||
|
}, [floor]);
|
||||||
|
|
||||||
|
if (!shape) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<mesh
|
||||||
|
castShadow
|
||||||
|
receiveShadow
|
||||||
|
name={`Floor-2D-${floor.floorUuid}`}
|
||||||
|
rotation={[Math.PI / 2, 0, 0]}
|
||||||
|
position={[0, 0, 0]}
|
||||||
|
userData={floor}
|
||||||
|
>
|
||||||
|
<Extrude
|
||||||
|
name={`Floor-${floor.floorUuid}`}
|
||||||
|
args={[shape, {
|
||||||
|
depth: Constants.floorConfig.height,
|
||||||
|
}]}
|
||||||
|
userData={floor}
|
||||||
|
>
|
||||||
|
<meshBasicMaterial
|
||||||
|
color={savedTheme === "dark" ? "#808080" : "#808080"}
|
||||||
|
side={DoubleSide}
|
||||||
|
transparent
|
||||||
|
opacity={0.4}
|
||||||
|
depthWrite={false}
|
||||||
|
/>
|
||||||
|
</Extrude>
|
||||||
|
</mesh>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Floor2DInstance;
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
import { useMemo } from 'react';
|
||||||
|
import { Shape, Vector2, DoubleSide, TextureLoader, RepeatWrapping, SRGBColorSpace } from 'three';
|
||||||
|
import { useLoader } from '@react-three/fiber';
|
||||||
|
import { Extrude } from '@react-three/drei';
|
||||||
|
import useModuleStore from '../../../../../store/useModuleStore';
|
||||||
|
import { useBuilderStore } from '../../../../../store/builder/useBuilderStore';
|
||||||
|
import { useToggleView } from '../../../../../store/builder/store';
|
||||||
|
import * as Constants from '../../../../../types/world/worldConstants';
|
||||||
|
|
||||||
|
import texturePath from "../../../../../assets/textures/floor/white.png";
|
||||||
|
import texturePathDark from "../../../../../assets/textures/floor/black.png";
|
||||||
|
import material1 from '../../../../../assets/textures/floor/factory wall texture.jpg';
|
||||||
|
|
||||||
|
function FloorInstance({ floor }: { floor: Floor }) {
|
||||||
|
const { togglView } = useToggleView();
|
||||||
|
const { activeModule } = useModuleStore();
|
||||||
|
const { selectedFloor, setSelectedFloor, setSelectedDecal } = useBuilderStore();
|
||||||
|
const savedTheme = localStorage.getItem('theme');
|
||||||
|
|
||||||
|
const materials: Record<string, string> = {
|
||||||
|
"Default Material": savedTheme === "dark" ? texturePathDark : texturePath,
|
||||||
|
"Material 1": savedTheme === "dark" ? material1 : material1,
|
||||||
|
};
|
||||||
|
|
||||||
|
const shape = useMemo(() => {
|
||||||
|
const shape = new Shape();
|
||||||
|
const points = floor.points.map(p => new Vector2(p.position[0], p.position[2]));
|
||||||
|
if (points.length < 3) return null;
|
||||||
|
shape.moveTo(points[0].x, points[0].y);
|
||||||
|
for (let i = 1; i < points.length; i++) {
|
||||||
|
shape.lineTo(points[i].x, points[i].y);
|
||||||
|
}
|
||||||
|
return shape;
|
||||||
|
}, [floor]);
|
||||||
|
|
||||||
|
const textureScale = Constants.floorConfig.textureScale;
|
||||||
|
|
||||||
|
const [topTexture, sideTexture] = useLoader(
|
||||||
|
TextureLoader,
|
||||||
|
[
|
||||||
|
materials[floor.topMaterial] || materials['Default Material'],
|
||||||
|
materials[floor.sideMaterial] || materials['Default Material']
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!materials[floor.topMaterial] || !materials[floor.sideMaterial]) return null;
|
||||||
|
|
||||||
|
[topTexture, sideTexture].forEach(tex => {
|
||||||
|
tex.wrapS = tex.wrapT = RepeatWrapping;
|
||||||
|
tex.repeat.set(textureScale, textureScale);
|
||||||
|
tex.colorSpace = SRGBColorSpace;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!shape) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<mesh
|
||||||
|
castShadow
|
||||||
|
receiveShadow
|
||||||
|
name={`Floor-${floor.floorUuid}`}
|
||||||
|
rotation={[Math.PI / 2, 0, 0]}
|
||||||
|
position={[0, !floor.isBeveled ? (floor.floorDepth - 0.1) : (floor.floorDepth - 0.2), 0]}
|
||||||
|
userData={floor}
|
||||||
|
onDoubleClick={(e) => {
|
||||||
|
if (!togglView && activeModule === 'builder') {
|
||||||
|
if (e.object.userData.floorUuid) {
|
||||||
|
e.stopPropagation();
|
||||||
|
setSelectedFloor(e.object);
|
||||||
|
setSelectedDecal(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onPointerMissed={() => {
|
||||||
|
if (selectedFloor && selectedFloor.userData.floorUuid === floor.floorUuid) {
|
||||||
|
setSelectedFloor(null);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Extrude
|
||||||
|
name={`Floor-${floor.floorUuid}`}
|
||||||
|
args={[shape, {
|
||||||
|
depth: !floor.isBeveled ? floor.floorDepth : (floor.floorDepth - 0.1),
|
||||||
|
bevelEnabled: floor.isBeveled,
|
||||||
|
bevelSegments: floor.bevelStrength,
|
||||||
|
bevelOffset: -0.1,
|
||||||
|
bevelSize: 0.1,
|
||||||
|
bevelThickness: 0.1,
|
||||||
|
}]}
|
||||||
|
userData={floor}
|
||||||
|
>
|
||||||
|
<meshStandardMaterial
|
||||||
|
attach="material-0"
|
||||||
|
color={Constants.floorConfig.defaultColor}
|
||||||
|
map={topTexture}
|
||||||
|
side={DoubleSide}
|
||||||
|
/>
|
||||||
|
<meshStandardMaterial
|
||||||
|
attach="material-1"
|
||||||
|
color={Constants.floorConfig.defaultColor}
|
||||||
|
map={sideTexture}
|
||||||
|
side={DoubleSide}
|
||||||
|
/>
|
||||||
|
</Extrude>
|
||||||
|
</mesh>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FloorInstance;
|
||||||
133
app/src/modules/builder/floor/Instances/floorInstances.tsx
Normal file
133
app/src/modules/builder/floor/Instances/floorInstances.tsx
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
import React, { useEffect, useMemo } from 'react';
|
||||||
|
import { Vector3 } from 'three';
|
||||||
|
import { Html } from '@react-three/drei';
|
||||||
|
import { useSceneContext } from '../../../scene/sceneContext';
|
||||||
|
import { useToggleView } from '../../../../store/builder/store';
|
||||||
|
import Line from '../../line/line';
|
||||||
|
import Point from '../../point/point';
|
||||||
|
import FloorInstance from './Instance/floorInstance';
|
||||||
|
import Floor2DInstance from './Instance/floor2DInstance';
|
||||||
|
|
||||||
|
function FloorInstances() {
|
||||||
|
const { floorStore } = useSceneContext();
|
||||||
|
const { floors } = floorStore();
|
||||||
|
const { toggleView } = useToggleView();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// console.log('floors: ', floors);
|
||||||
|
}, [floors])
|
||||||
|
|
||||||
|
const allPoints = useMemo(() => {
|
||||||
|
const points: Point[] = [];
|
||||||
|
const seenUuids = new Set<string>();
|
||||||
|
|
||||||
|
floors.forEach(floor => {
|
||||||
|
floor.points.forEach(point => {
|
||||||
|
if (!seenUuids.has(point.pointUuid)) {
|
||||||
|
seenUuids.add(point.pointUuid);
|
||||||
|
points.push(point);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return points;
|
||||||
|
}, [floors]);
|
||||||
|
|
||||||
|
const allLines = useMemo(() => {
|
||||||
|
const lines: { start: Point; end: Point; key: string }[] = [];
|
||||||
|
const seenUuids = new Set<string>();
|
||||||
|
|
||||||
|
floors.forEach((floor) => {
|
||||||
|
const points = floor.points;
|
||||||
|
if (points.length < 2) return;
|
||||||
|
|
||||||
|
for (let i = 0; i < points.length; i++) {
|
||||||
|
const current = points[i];
|
||||||
|
const next = points[(i + 1) % points.length];
|
||||||
|
const lineKey = `${current.pointUuid}-${next.pointUuid}`;
|
||||||
|
if (current.pointUuid !== next.pointUuid && !seenUuids.has(lineKey)) {
|
||||||
|
seenUuids.add(lineKey);
|
||||||
|
lines.push({
|
||||||
|
start: current,
|
||||||
|
end: next,
|
||||||
|
key: lineKey
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return lines;
|
||||||
|
}, [floors]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
{!toggleView && floors.length > 0 && (
|
||||||
|
<mesh name='Floors-Group'>
|
||||||
|
{floors.map((floor) => (
|
||||||
|
<FloorInstance key={floor.floorUuid} floor={floor} />
|
||||||
|
))}
|
||||||
|
</mesh>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{toggleView && floors.length > 0 && (
|
||||||
|
<mesh name='Floors-2D-Group'>
|
||||||
|
{floors.map((floor) => (
|
||||||
|
<Floor2DInstance key={floor.floorUuid} floor={floor} />
|
||||||
|
))}
|
||||||
|
</mesh>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{toggleView && (
|
||||||
|
<>
|
||||||
|
<group name='Floor-Points-Group'>
|
||||||
|
{allPoints.map((point) => (
|
||||||
|
<Point key={point.pointUuid} point={point} />
|
||||||
|
))}
|
||||||
|
</group>
|
||||||
|
|
||||||
|
<group name='Floor-Lines-Group'>
|
||||||
|
|
||||||
|
{allLines.map(({ start, end, key }) => (
|
||||||
|
<Line key={key} points={[start, end]} />
|
||||||
|
))}
|
||||||
|
|
||||||
|
{allLines.map((line) => {
|
||||||
|
const { start, end, key } = line;
|
||||||
|
const textPosition = new Vector3().addVectors(new Vector3(...start.position), new Vector3(...end.position)).divideScalar(2);
|
||||||
|
const distance = new Vector3(...start.position).distanceTo(new Vector3(...end.position));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment key={key}>
|
||||||
|
{toggleView &&
|
||||||
|
<Html
|
||||||
|
key={`${start.pointUuid}_${end.pointUuid}`}
|
||||||
|
userData={line}
|
||||||
|
position={[textPosition.x, 1, textPosition.z]}
|
||||||
|
wrapperClass="distance-text-wrapper"
|
||||||
|
className="distance-text"
|
||||||
|
zIndexRange={[1, 0]}
|
||||||
|
prepend
|
||||||
|
sprite
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
key={key}
|
||||||
|
className={`distance ${key}`}
|
||||||
|
>
|
||||||
|
{distance.toFixed(2)} m
|
||||||
|
</div>
|
||||||
|
</Html>
|
||||||
|
}
|
||||||
|
</React.Fragment>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
|
||||||
|
</group>
|
||||||
|
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FloorInstances;
|
||||||
267
app/src/modules/builder/floor/floorCreator/floorCreator.tsx
Normal file
267
app/src/modules/builder/floor/floorCreator/floorCreator.tsx
Normal file
@@ -0,0 +1,267 @@
|
|||||||
|
import * as THREE from 'three'
|
||||||
|
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||||
|
import { useThree } from '@react-three/fiber';
|
||||||
|
import { useActiveLayer, useSocketStore, useToggleView, useToolMode } from '../../../../store/builder/store';
|
||||||
|
import { useSceneContext } from '../../../scene/sceneContext';
|
||||||
|
import { useBuilderStore } from '../../../../store/builder/useBuilderStore';
|
||||||
|
import { useParams } from 'react-router-dom';
|
||||||
|
import { useVersionContext } from '../../version/versionContext';
|
||||||
|
import { getUserData } from '../../../../functions/getUserData';
|
||||||
|
import ReferencePoint from '../../point/reference/referencePoint';
|
||||||
|
import ReferenceFloor from './referenceFloor';
|
||||||
|
|
||||||
|
// import { upsertFloorApi } from '../../../../services/factoryBuilder/floor/upsertFloorApi';
|
||||||
|
|
||||||
|
function FloorCreator() {
|
||||||
|
const { scene, camera, raycaster, gl, pointer } = useThree();
|
||||||
|
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
||||||
|
const { toggleView } = useToggleView();
|
||||||
|
const { toolMode } = useToolMode();
|
||||||
|
const { activeLayer } = useActiveLayer();
|
||||||
|
const { socket } = useSocketStore();
|
||||||
|
const { floorStore } = useSceneContext();
|
||||||
|
const { addFloor, getFloorPointById, getFloorByPoints } = floorStore();
|
||||||
|
const drag = useRef(false);
|
||||||
|
const isLeftMouseDown = useRef(false);
|
||||||
|
const { selectedVersionStore } = useVersionContext();
|
||||||
|
const { selectedVersion } = selectedVersionStore();
|
||||||
|
const { userId, organization } = getUserData();
|
||||||
|
const { projectId } = useParams();
|
||||||
|
|
||||||
|
const [tempPoints, setTempPoints] = useState<Point[]>([]);
|
||||||
|
const [isCreating, setIsCreating] = useState(false);
|
||||||
|
const { floorDepth, isBeveled, bevelStrength, sideMaterial, topMaterial, snappedPosition, snappedPoint, setSnappedPoint, setSnappedPosition } = useBuilderStore();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const canvasElement = gl.domElement;
|
||||||
|
|
||||||
|
const onMouseDown = (evt: any) => {
|
||||||
|
if (evt.button === 0) {
|
||||||
|
isLeftMouseDown.current = true;
|
||||||
|
drag.current = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onMouseUp = (evt: any) => {
|
||||||
|
if (evt.button === 0) {
|
||||||
|
isLeftMouseDown.current = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onMouseMove = () => {
|
||||||
|
if (isLeftMouseDown) {
|
||||||
|
drag.current = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onMouseClick = () => {
|
||||||
|
if (drag.current || !toggleView) return;
|
||||||
|
|
||||||
|
raycaster.setFromCamera(pointer, camera);
|
||||||
|
const intersectionPoint = new THREE.Vector3();
|
||||||
|
let position = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
||||||
|
if (!position) return;
|
||||||
|
|
||||||
|
const pointIntersects = raycaster.intersectObjects(scene.children).find((intersect) => intersect.object.name === 'Floor-Point');
|
||||||
|
|
||||||
|
// const floorIntersect = raycaster.intersectObjects(scene.children).find((intersect) => intersect.object.name === 'Floor-Line');
|
||||||
|
|
||||||
|
// if (floorIntersect && !pointIntersects) {
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
const newPoint: Point = {
|
||||||
|
pointUuid: THREE.MathUtils.generateUUID(),
|
||||||
|
pointType: 'Floor',
|
||||||
|
position: [position.x, position.y, position.z],
|
||||||
|
layer: activeLayer
|
||||||
|
};
|
||||||
|
|
||||||
|
if (snappedPosition && snappedPoint) {
|
||||||
|
newPoint.pointUuid = snappedPoint.pointUuid;
|
||||||
|
newPoint.position = snappedPosition;
|
||||||
|
newPoint.layer = snappedPoint.layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (snappedPoint && snappedPoint.pointUuid === tempPoints[tempPoints.length - 1]?.pointUuid) { return }
|
||||||
|
|
||||||
|
if (snappedPosition && !snappedPoint) {
|
||||||
|
newPoint.position = snappedPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tempPoints.length > 2 && isCreating && snappedPoint && snappedPoint.pointUuid === tempPoints[0].pointUuid) {
|
||||||
|
const floor: Floor = {
|
||||||
|
floorUuid: THREE.MathUtils.generateUUID(),
|
||||||
|
floorName: "Floor",
|
||||||
|
points: tempPoints,
|
||||||
|
topMaterial,
|
||||||
|
sideMaterial,
|
||||||
|
floorDepth,
|
||||||
|
isBeveled,
|
||||||
|
bevelStrength,
|
||||||
|
decals: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
addFloor(floor);
|
||||||
|
if (projectId) {
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// upsertFloorApi(projectId, selectedVersion?.versionId || '', floor);
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
floorData: floor,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:model-Floor:add', data);
|
||||||
|
|
||||||
|
}
|
||||||
|
setTempPoints([]);
|
||||||
|
setIsCreating(false);
|
||||||
|
} else if (isCreating && snappedPoint && !tempPoints.some(p => p.pointUuid === snappedPoint.pointUuid)) {
|
||||||
|
setTempPoints(prev => [...prev, newPoint]);
|
||||||
|
setIsCreating(true);
|
||||||
|
} else if (pointIntersects) {
|
||||||
|
if (tempPoints.length > 2 && isCreating && pointIntersects.object.uuid === tempPoints[0].pointUuid) {
|
||||||
|
const floor: Floor = {
|
||||||
|
floorUuid: THREE.MathUtils.generateUUID(),
|
||||||
|
floorName: "Floor",
|
||||||
|
points: tempPoints,
|
||||||
|
topMaterial,
|
||||||
|
sideMaterial,
|
||||||
|
floorDepth,
|
||||||
|
isBeveled,
|
||||||
|
bevelStrength,
|
||||||
|
decals: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
addFloor(floor);
|
||||||
|
if (projectId) {
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// upsertFloorApi(projectId, selectedVersion?.versionId || '', floor);
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
floorData: floor,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:model-Floor:add', data);
|
||||||
|
|
||||||
|
}
|
||||||
|
setTempPoints([]);
|
||||||
|
setIsCreating(false);
|
||||||
|
} else if (tempPoints.length === 0 || (tempPoints.length > 1 && !tempPoints.slice(1).some(p => p.pointUuid === pointIntersects.object.uuid))) {
|
||||||
|
tempPoints.push(pointIntersects.object.userData as Point);
|
||||||
|
setIsCreating(true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setTempPoints(prev => [...prev, newPoint]);
|
||||||
|
setIsCreating(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const onContext = (event: any) => {
|
||||||
|
event.preventDefault();
|
||||||
|
if (isCreating) {
|
||||||
|
if (tempPoints.length >= 3) {
|
||||||
|
const floor: Floor = {
|
||||||
|
floorUuid: THREE.MathUtils.generateUUID(),
|
||||||
|
floorName: "Floor",
|
||||||
|
points: tempPoints,
|
||||||
|
topMaterial,
|
||||||
|
sideMaterial,
|
||||||
|
floorDepth,
|
||||||
|
isBeveled,
|
||||||
|
bevelStrength,
|
||||||
|
decals: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
addFloor(floor);
|
||||||
|
if (projectId) {
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// upsertFloorApi(projectId, selectedVersion?.versionId || '', floor);
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
floorData: floor,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:model-Floor:add', data);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setTempPoints([]);
|
||||||
|
setIsCreating(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (toolMode === "Floor" && toggleView) {
|
||||||
|
if (tempPoints.length === 0) {
|
||||||
|
setSnappedPosition(null);
|
||||||
|
setSnappedPoint(null);
|
||||||
|
}
|
||||||
|
canvasElement.addEventListener("mousedown", onMouseDown);
|
||||||
|
canvasElement.addEventListener("mouseup", onMouseUp);
|
||||||
|
canvasElement.addEventListener("mousemove", onMouseMove);
|
||||||
|
canvasElement.addEventListener("click", onMouseClick);
|
||||||
|
canvasElement.addEventListener("contextmenu", onContext);
|
||||||
|
} else {
|
||||||
|
setTempPoints([]);
|
||||||
|
setIsCreating(false);
|
||||||
|
canvasElement.removeEventListener("mousedown", onMouseDown);
|
||||||
|
canvasElement.removeEventListener("mouseup", onMouseUp);
|
||||||
|
canvasElement.removeEventListener("mousemove", onMouseMove);
|
||||||
|
canvasElement.removeEventListener("click", onMouseClick);
|
||||||
|
canvasElement.removeEventListener("contextmenu", onContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
canvasElement.removeEventListener("mousedown", onMouseDown);
|
||||||
|
canvasElement.removeEventListener("mouseup", onMouseUp);
|
||||||
|
canvasElement.removeEventListener("mousemove", onMouseMove);
|
||||||
|
canvasElement.removeEventListener("click", onMouseClick);
|
||||||
|
canvasElement.removeEventListener("contextmenu", onContext);
|
||||||
|
};
|
||||||
|
}, [gl, camera, scene, raycaster, pointer, plane, toggleView, toolMode, activeLayer, socket, tempPoints, isCreating, addFloor, getFloorPointById, getFloorByPoints, floorDepth, isBeveled, bevelStrength, sideMaterial, topMaterial, snappedPosition, snappedPoint]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{toggleView &&
|
||||||
|
<>
|
||||||
|
<group name='Floor-Reference-Points-Group'>
|
||||||
|
{tempPoints.map((point) => (
|
||||||
|
<ReferencePoint key={point.pointUuid} point={point} />
|
||||||
|
))}
|
||||||
|
</group>
|
||||||
|
|
||||||
|
{tempPoints.length > 0 &&
|
||||||
|
<ReferenceFloor tempPoints={tempPoints} />
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FloorCreator
|
||||||
165
app/src/modules/builder/floor/floorCreator/referenceFloor.tsx
Normal file
165
app/src/modules/builder/floor/floorCreator/referenceFloor.tsx
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
import { useEffect, useRef, useState, useMemo } from 'react';
|
||||||
|
import * as THREE from 'three';
|
||||||
|
import { useFrame, useThree } from '@react-three/fiber';
|
||||||
|
import { Extrude, Html } from '@react-three/drei';
|
||||||
|
import { useBuilderStore } from '../../../../store/builder/useBuilderStore';
|
||||||
|
import { useActiveLayer, useToolMode, useToggleView } from '../../../../store/builder/store';
|
||||||
|
import { useDirectionalSnapping } from '../../point/helpers/useDirectionalSnapping';
|
||||||
|
import { usePointSnapping } from '../../point/helpers/usePointSnapping';
|
||||||
|
import ReferenceLine from '../../line/reference/referenceLine';
|
||||||
|
|
||||||
|
interface ReferenceFloorProps {
|
||||||
|
tempPoints: Point[];
|
||||||
|
}
|
||||||
|
|
||||||
|
function ReferenceFloor({ tempPoints }: Readonly<ReferenceFloorProps>) {
|
||||||
|
const { floorDepth, isBeveled, bevelStrength, setSnappedPosition, setSnappedPoint } = useBuilderStore();
|
||||||
|
const { pointer, raycaster, camera } = useThree();
|
||||||
|
const { toolMode } = useToolMode();
|
||||||
|
const { toggleView } = useToggleView();
|
||||||
|
const { activeLayer } = useActiveLayer();
|
||||||
|
const plane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0);
|
||||||
|
const finalPosition = useRef<[number, number, number] | null>(null);
|
||||||
|
|
||||||
|
const [tempFloor, setTempFloor] = useState<Floor | null>(null);
|
||||||
|
const [currentPosition, setCurrentPosition] = useState<[number, number, number]>(tempPoints[0]?.position);
|
||||||
|
|
||||||
|
const directionalSnap = useDirectionalSnapping(currentPosition, tempPoints[tempPoints.length - 1]?.position || null);
|
||||||
|
const { snapFloorPoint } = usePointSnapping({ uuid: 'temp-Floor', pointType: 'Floor', position: directionalSnap.position || [0, 0, 0], });
|
||||||
|
|
||||||
|
useFrame(() => {
|
||||||
|
if (toolMode === 'Floor' && toggleView && tempPoints.length > 0) {
|
||||||
|
raycaster.setFromCamera(pointer, camera);
|
||||||
|
const intersectionPoint = new THREE.Vector3();
|
||||||
|
raycaster.ray.intersectPlane(plane, intersectionPoint);
|
||||||
|
|
||||||
|
setCurrentPosition([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z]);
|
||||||
|
|
||||||
|
if (!intersectionPoint) return;
|
||||||
|
const snapped = snapFloorPoint([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z], tempPoints.length > 2 ? [tempPoints[0]] : []);
|
||||||
|
|
||||||
|
if (snapped.isSnapped && snapped.snappedPoint) {
|
||||||
|
finalPosition.current = snapped.position;
|
||||||
|
setSnappedPosition(snapped.position);
|
||||||
|
setSnappedPoint(snapped.snappedPoint);
|
||||||
|
} else if (directionalSnap.isSnapped) {
|
||||||
|
finalPosition.current = directionalSnap.position;
|
||||||
|
setSnappedPosition(directionalSnap.position);
|
||||||
|
setSnappedPoint(null);
|
||||||
|
} else {
|
||||||
|
finalPosition.current = [intersectionPoint.x, intersectionPoint.y, intersectionPoint.z];
|
||||||
|
setSnappedPosition(null);
|
||||||
|
setSnappedPoint(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!finalPosition.current) return;
|
||||||
|
|
||||||
|
const floorPoints: Point[] = [
|
||||||
|
...tempPoints,
|
||||||
|
{
|
||||||
|
pointUuid: 'temp-point',
|
||||||
|
pointType: 'Floor',
|
||||||
|
position: finalPosition.current,
|
||||||
|
layer: activeLayer,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
setTempFloor({
|
||||||
|
floorUuid: 'temp-floor',
|
||||||
|
floorName: 'temp-floor',
|
||||||
|
points: floorPoints,
|
||||||
|
topMaterial: 'default',
|
||||||
|
sideMaterial: 'default',
|
||||||
|
floorDepth,
|
||||||
|
bevelStrength,
|
||||||
|
isBeveled,
|
||||||
|
decals: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
} else if (tempFloor !== null) {
|
||||||
|
setTempFloor(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setTempFloor(null);
|
||||||
|
}, [toolMode, toggleView, tempPoints.length, floorDepth, bevelStrength, isBeveled, activeLayer]);
|
||||||
|
|
||||||
|
const allLines = useMemo(() => {
|
||||||
|
if (!tempFloor || tempFloor.points.length < 2) return [];
|
||||||
|
|
||||||
|
const lines: [Point, Point][] = [];
|
||||||
|
const pts = tempFloor.points;
|
||||||
|
|
||||||
|
for (let i = 0; i < pts.length - 1; i++) {
|
||||||
|
lines.push([pts[i], pts[i + 1]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines;
|
||||||
|
}, [tempFloor]);
|
||||||
|
|
||||||
|
if (!tempFloor) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<group name="Floor-Reference-Group">
|
||||||
|
{allLines.map(([p1, p2], idx) => {
|
||||||
|
const v1 = new THREE.Vector3(...p1.position);
|
||||||
|
const v2 = new THREE.Vector3(...p2.position);
|
||||||
|
const mid = new THREE.Vector3().addVectors(v1, v2).multiplyScalar(0.5);
|
||||||
|
const dist = v1.distanceTo(v2);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<group key={`${p1.pointUuid}-${p2.pointUuid}`}>
|
||||||
|
<ReferenceLine points={[p1, p2]} />
|
||||||
|
{toggleView && (
|
||||||
|
<Html
|
||||||
|
position={[mid.x, 1, mid.z]}
|
||||||
|
wrapperClass="distance-text-wrapper"
|
||||||
|
className="distance-text"
|
||||||
|
zIndexRange={[1, 0]}
|
||||||
|
prepend
|
||||||
|
sprite
|
||||||
|
>
|
||||||
|
<div className={`distance ref-line-${idx}`}>{dist.toFixed(2)} m</div>
|
||||||
|
</Html>
|
||||||
|
)}
|
||||||
|
</group>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
|
||||||
|
{tempPoints.length >= 3 && (
|
||||||
|
<Floor floor={tempFloor.points} />
|
||||||
|
)}
|
||||||
|
</group>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ReferenceFloor;
|
||||||
|
|
||||||
|
|
||||||
|
function Floor({ floor }: { floor: Point[] }) {
|
||||||
|
const savedTheme: string | null = localStorage.getItem('theme');
|
||||||
|
|
||||||
|
const shape = useMemo(() => {
|
||||||
|
const shape = new THREE.Shape();
|
||||||
|
const points = floor.map(p => new THREE.Vector2(p.position[0], p.position[2]));
|
||||||
|
if (points.length < 3) return null;
|
||||||
|
shape.moveTo(points[0].x, points[0].y);
|
||||||
|
points.forEach((pt) => { shape.lineTo(pt.x, pt.y); });
|
||||||
|
return shape;
|
||||||
|
}, [floor]);
|
||||||
|
|
||||||
|
if (!shape) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<group name="Wall-Floor" rotation={[Math.PI / 2, 0, 0]}>
|
||||||
|
<Extrude
|
||||||
|
args={[shape, { depth: 0.001, bevelEnabled: false }]}
|
||||||
|
position={[0, 0, 0]}
|
||||||
|
receiveShadow
|
||||||
|
>
|
||||||
|
<meshStandardMaterial color={savedTheme === "dark" ? "#808080" : "#808080"} depthWrite={false} transparent opacity={0.3} side={THREE.DoubleSide} />
|
||||||
|
</Extrude>
|
||||||
|
</group>
|
||||||
|
);
|
||||||
|
}
|
||||||
55
app/src/modules/builder/floor/floorGroup.tsx
Normal file
55
app/src/modules/builder/floor/floorGroup.tsx
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import { useEffect } from 'react';
|
||||||
|
import { useActiveTool, useToggleView } from '../../../store/builder/store'
|
||||||
|
import { useBuilderStore } from '../../../store/builder/useBuilderStore';
|
||||||
|
import { useVersionContext } from '../version/versionContext';
|
||||||
|
import { useSceneContext } from '../../scene/sceneContext';
|
||||||
|
import { useParams } from 'react-router-dom';
|
||||||
|
import useModuleStore from '../../../store/useModuleStore';
|
||||||
|
import FloorCreator from './floorCreator/floorCreator';
|
||||||
|
import FloorInstances from './Instances/floorInstances';
|
||||||
|
import { getFloorsApi } from '../../../services/factoryBuilder/floor/getFloorsApi';
|
||||||
|
|
||||||
|
function FloorGroup() {
|
||||||
|
const { togglView } = useToggleView();
|
||||||
|
const { setSelectedFloor, setSelectedDecal } = useBuilderStore();
|
||||||
|
const { activeModule } = useModuleStore();
|
||||||
|
const { activeTool } = useActiveTool();
|
||||||
|
const { selectedVersionStore } = useVersionContext();
|
||||||
|
const { selectedVersion } = selectedVersionStore();
|
||||||
|
const { floorStore } = useSceneContext();
|
||||||
|
const { setFloors } = floorStore();
|
||||||
|
const { projectId } = useParams();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (togglView || activeModule !== 'builder') {
|
||||||
|
setSelectedFloor(null);
|
||||||
|
setSelectedDecal(null);
|
||||||
|
}
|
||||||
|
}, [togglView, activeModule, activeTool])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (projectId && selectedVersion) {
|
||||||
|
getFloorsApi(projectId, selectedVersion?.versionId || '').then((floors) => {
|
||||||
|
if (floors && floors.length > 0) {
|
||||||
|
setFloors(floors);
|
||||||
|
} else {
|
||||||
|
setFloors([]);
|
||||||
|
}
|
||||||
|
}).catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, [projectId, selectedVersion?.versionId])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
<FloorCreator />
|
||||||
|
|
||||||
|
<FloorInstances />
|
||||||
|
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FloorGroup
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
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.uOuterColor.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.uOuterColor.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.uOuterColor.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,93 +0,0 @@
|
|||||||
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,
|
|
||||||
snappedPoint: Types.RefVector3,
|
|
||||||
isSnapped: Types.RefBoolean,
|
|
||||||
isSnappedUUID: Types.RefString,
|
|
||||||
line: Types.RefLine,
|
|
||||||
ispreSnapped: Types.RefBoolean,
|
|
||||||
floorPlanGroup: Types.RefGroup,
|
|
||||||
ReferenceLineMesh: Types.RefMesh,
|
|
||||||
LineCreated: Types.RefBoolean,
|
|
||||||
setRefTextUpdate: any,
|
|
||||||
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 === "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))
|
|
||||||
|
|
||||||
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))
|
|
||||||
|
|
||||||
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,62 +0,0 @@
|
|||||||
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/white.png";
|
|
||||||
import texturePathDark from "../../../../assets/textures/floor/black.png";
|
|
||||||
|
|
||||||
// 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 savedTheme: string | null = localStorage.getItem('theme');
|
|
||||||
|
|
||||||
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(savedTheme === "dark" ? texturePathDark : texturePath);
|
|
||||||
// const floorTexture = textureLoader.load(texturePath);
|
|
||||||
|
|
||||||
floorTexture.wrapS = floorTexture.wrapT = THREE.RepeatWrapping;
|
|
||||||
floorTexture.repeat.set(textureScale, textureScale);
|
|
||||||
floorTexture.colorSpace = THREE.SRGBColorSpace;
|
|
||||||
|
|
||||||
material = new THREE.MeshStandardMaterial({
|
|
||||||
map: floorTexture,
|
|
||||||
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) * CONSTANTS.wallConfig.height;
|
|
||||||
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,275 +0,0 @@
|
|||||||
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";
|
|
||||||
import { getUserData } from "../../../../functions/getUserData";
|
|
||||||
|
|
||||||
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>,
|
|
||||||
projectId?: string,
|
|
||||||
versionId?: string,
|
|
||||||
): Promise<void> {
|
|
||||||
////////// Creating lines Based on the positions clicked //////////
|
|
||||||
|
|
||||||
if (!plane.current) return;
|
|
||||||
const { userId, organization, email } = getUserData();
|
|
||||||
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],
|
|
||||||
projectId
|
|
||||||
);
|
|
||||||
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);
|
|
||||||
|
|
||||||
//REST
|
|
||||||
|
|
||||||
// setLine(organization, data.layer!, data.line!, data.type!);
|
|
||||||
|
|
||||||
//SOCKET
|
|
||||||
|
|
||||||
const input = {
|
|
||||||
organization,
|
|
||||||
layer: data.layer,
|
|
||||||
line: data.line,
|
|
||||||
type: data.type,
|
|
||||||
socketId: socket.id,
|
|
||||||
projectId,
|
|
||||||
versionId,
|
|
||||||
userId,
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log('input: ', input);
|
|
||||||
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);
|
|
||||||
|
|
||||||
//REST
|
|
||||||
|
|
||||||
// setLine(organization, data.layer!, data.line!, data.type!);
|
|
||||||
|
|
||||||
//SOCKET
|
|
||||||
|
|
||||||
const input = {
|
|
||||||
organization,
|
|
||||||
layer: data.layer,
|
|
||||||
line: data.line,
|
|
||||||
type: data.type,
|
|
||||||
socketId: socket.id,
|
|
||||||
versionId,
|
|
||||||
projectId,
|
|
||||||
userId,
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log('input: ', input);
|
|
||||||
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 +0,0 @@
|
|||||||
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 +0,0 @@
|
|||||||
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) {
|
|
||||||
console.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;
|
|
||||||
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 +0,0 @@
|
|||||||
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,104 +0,0 @@
|
|||||||
import { toast } from "react-toastify";
|
|
||||||
import RemoveConnectedLines from "../lines/removeConnectedLines";
|
|
||||||
|
|
||||||
import * as Types from "../../../../types/world/worldTypes";
|
|
||||||
import { Socket } from "socket.io-client";
|
|
||||||
import { getUserData } from "../../../../functions/getUserData";
|
|
||||||
// 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>,
|
|
||||||
projectId?: string,
|
|
||||||
versionId?: string,
|
|
||||||
): 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 { userId, organization } = getUserData();
|
|
||||||
|
|
||||||
//REST
|
|
||||||
|
|
||||||
// await deleteLayer(organization, removedLayer);
|
|
||||||
|
|
||||||
//SOCKET
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
organization,
|
|
||||||
layer: removedLayer,
|
|
||||||
socketId: socket.id,
|
|
||||||
versionId,
|
|
||||||
projectId,
|
|
||||||
userId,
|
|
||||||
};
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
echo.success("Layer Removed!");
|
|
||||||
setRemovedLayer(null);
|
|
||||||
}
|
|
||||||
export default DeleteLayer;
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
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 +0,0 @@
|
|||||||
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 +0,0 @@
|
|||||||
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,92 +0,0 @@
|
|||||||
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";
|
|
||||||
import { getUserData } from "../../../../functions/getUserData";
|
|
||||||
|
|
||||||
function deleteLine(
|
|
||||||
hoveredDeletableLine: Types.RefMesh,
|
|
||||||
onlyFloorlines: Types.RefOnlyFloorLines,
|
|
||||||
lines: Types.RefLines,
|
|
||||||
floorPlanGroupLine: Types.RefGroup,
|
|
||||||
floorPlanGroupPoint: Types.RefGroup,
|
|
||||||
setDeletedLines: any,
|
|
||||||
socket: Socket<any>,
|
|
||||||
projectId?: string,
|
|
||||||
versionId?: string,
|
|
||||||
): void {
|
|
||||||
const { userId, organization, email } = getUserData();
|
|
||||||
////////// 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]];
|
|
||||||
|
|
||||||
//REST
|
|
||||||
|
|
||||||
// deleteLineApi(
|
|
||||||
// organization,
|
|
||||||
// [
|
|
||||||
// { "uuid": linePoints[0][1] },
|
|
||||||
// { "uuid": linePoints[1][1] }
|
|
||||||
// ]
|
|
||||||
// )
|
|
||||||
|
|
||||||
//SOCKET
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
organization,
|
|
||||||
line: [{ uuid: linePoints[0][1] }, { uuid: linePoints[1][1] }],
|
|
||||||
socketId: socket.id,
|
|
||||||
versionId,
|
|
||||||
projectId,
|
|
||||||
userId,
|
|
||||||
};
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
echo.success("Line Removed!");
|
|
||||||
}
|
|
||||||
|
|
||||||
export default deleteLine;
|
|
||||||
@@ -1,226 +0,0 @@
|
|||||||
import { useEffect, useState } from "react";
|
|
||||||
import { getLines } from "../../../../../services/factoryBuilder/lines/getLinesApi";
|
|
||||||
import * as THREE from "three";
|
|
||||||
import {
|
|
||||||
useActiveLayer,
|
|
||||||
useDeletedLines,
|
|
||||||
useNewLines,
|
|
||||||
useRoomsState,
|
|
||||||
useToggleView,
|
|
||||||
} from "../../../../../store/builder/store";
|
|
||||||
import objectLinesToArray from "../lineConvertions/objectLinesToArray";
|
|
||||||
import { Html } from "@react-three/drei";
|
|
||||||
import { Vector2 } from "three";
|
|
||||||
import * as Types from "../../../../../types/world/worldTypes";
|
|
||||||
import getRoomsFromLines from "../getRoomsFromLines";
|
|
||||||
import * as turf from '@turf/turf';
|
|
||||||
import { useParams } from "react-router-dom";
|
|
||||||
import { getUserData } from "../../../../../functions/getUserData";
|
|
||||||
import { useVersionContext } from "../../../version/versionContext";
|
|
||||||
|
|
||||||
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();
|
|
||||||
const [linesState, setLinesState] = useState<Types.Lines>([]);
|
|
||||||
const { roomsState, setRoomsState } = useRoomsState();
|
|
||||||
const { selectedVersionStore } = useVersionContext();
|
|
||||||
const { selectedVersion } = selectedVersionStore();
|
|
||||||
const { projectId } = useParams();
|
|
||||||
const { organization, email } = getUserData();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
|
|
||||||
if (linesState.length === 0) return;
|
|
||||||
const getLines = async () => {
|
|
||||||
const points3D = linesState.map(line => {
|
|
||||||
const startPoint = line[0][0]; // First point of each wall line
|
|
||||||
return [startPoint.x, 0, startPoint.z];
|
|
||||||
});
|
|
||||||
|
|
||||||
// Ensure the polygon is closed
|
|
||||||
if (
|
|
||||||
points3D[0][0] !== points3D[points3D.length - 1][0] ||
|
|
||||||
points3D[0][1] !== points3D[points3D.length - 1][1]
|
|
||||||
) {
|
|
||||||
points3D.push(points3D[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert to 2D for turf (x, z)
|
|
||||||
const coords2D = points3D.map(p => [p[0], p[1]]);
|
|
||||||
|
|
||||||
const projected = points3D.map((p: any) => new Vector2(p[0], p[1]));
|
|
||||||
|
|
||||||
// Shoelace formula for 2D polygon
|
|
||||||
let area = 0;
|
|
||||||
const n = projected.length;
|
|
||||||
for (let i = 0; i < n - 1; i++) {
|
|
||||||
const curr = projected[i];
|
|
||||||
const next = projected[i + 1];
|
|
||||||
area += curr.x * next.y - next.x * curr.y;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// return Math.abs(area) / 2;
|
|
||||||
|
|
||||||
// Build polygon and compute area
|
|
||||||
// const polygon = turf.polygon([coords2D]);
|
|
||||||
// const area = turf.area(polygon);
|
|
||||||
// const area = computeAreaFrom3DPoints(coords2D)
|
|
||||||
|
|
||||||
//
|
|
||||||
if (lines.length > 2) {
|
|
||||||
const linesByLayer = linesState.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) {
|
|
||||||
const rooms: Types.Rooms = await getRoomsFromLines({ current: linesByLayer[layer] });
|
|
||||||
setRoomsState(rooms)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
getLines();
|
|
||||||
}, [linesState, roomsState])
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!email || !selectedVersion) return;
|
|
||||||
|
|
||||||
getLines(organization, projectId, selectedVersion?.versionId || '').then((data) => {
|
|
||||||
data = objectLinesToArray(data);
|
|
||||||
setLinesState(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, selectedVersion?.versionId]);
|
|
||||||
|
|
||||||
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]);
|
|
||||||
setLinesState((prevLines) => [...prevLines, ...newLines]);
|
|
||||||
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]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
setLinesState(prev =>
|
|
||||||
prev.filter(line =>
|
|
||||||
!(deletedLines as Types.Lines).some(
|
|
||||||
deleted =>
|
|
||||||
line[0][1] === deleted[0][1] && line[1][1] === deleted[1][1]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
setDeletedLines([]);
|
|
||||||
setRoomsState([])
|
|
||||||
}
|
|
||||||
}, [deletedLines]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{toggleView && (
|
|
||||||
<group name="Distance_Text">
|
|
||||||
{lines.map((text) => (
|
|
||||||
<Html
|
|
||||||
// data
|
|
||||||
key={`${text.userData[0][1]}_${text.userData[1][1]}`}
|
|
||||||
userData={text.userData}
|
|
||||||
position={[text.position.x, 1, text.position.z]}
|
|
||||||
// class
|
|
||||||
wrapperClass="distance-text-wrapper"
|
|
||||||
className="distance-text"
|
|
||||||
// other
|
|
||||||
zIndexRange={[1, 0]}
|
|
||||||
prepend
|
|
||||||
sprite
|
|
||||||
>
|
|
||||||
<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,71 +0,0 @@
|
|||||||
import * as THREE from "three";
|
|
||||||
import { Html } from "@react-three/drei";
|
|
||||||
import { useState, useEffect } from "react";
|
|
||||||
import { useActiveLayer } from "../../../../../store/builder/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
|
|
||||||
// data
|
|
||||||
key={text.distance}
|
|
||||||
userData={text.userData}
|
|
||||||
position={[text.position.x, 1, text.position.z]}
|
|
||||||
// class
|
|
||||||
wrapperClass="distance-text-wrapper"
|
|
||||||
className="distance-text"
|
|
||||||
// other
|
|
||||||
zIndexRange={[1, 0]}
|
|
||||||
prepend
|
|
||||||
sprite
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className={`Reference_Distance line-${text.userData.userData}`}
|
|
||||||
>
|
|
||||||
{text.distance} m
|
|
||||||
</div>
|
|
||||||
</Html>
|
|
||||||
)}
|
|
||||||
</mesh>
|
|
||||||
</group>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ReferenceDistanceText;
|
|
||||||
@@ -1,331 +0,0 @@
|
|||||||
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";
|
|
||||||
import { getUserData } from "../../../../functions/getUserData";
|
|
||||||
import * as Y from 'yjs';
|
|
||||||
import { generateUniqueId } from "../../../../functions/generateUniqueId";
|
|
||||||
|
|
||||||
async function drawWall(
|
|
||||||
raycaster: THREE.Raycaster,
|
|
||||||
plane: Types.RefMesh,
|
|
||||||
floorPlanGroupPoint: Types.RefGroup,
|
|
||||||
snappedPoint: Types.RefVector3,
|
|
||||||
isSnapped: Types.RefBoolean,
|
|
||||||
isSnappedUUID: Types.RefString,
|
|
||||||
line: Types.RefLine,
|
|
||||||
ispreSnapped: Types.RefBoolean,
|
|
||||||
anglesnappedPoint: Types.RefVector3,
|
|
||||||
isAngleSnapped: Types.RefBoolean,
|
|
||||||
lines: Types.RefLines,
|
|
||||||
floorPlanGroupLine: Types.RefGroup,
|
|
||||||
floorPlanGroup: Types.RefGroup,
|
|
||||||
ReferenceLineMesh: Types.RefMesh,
|
|
||||||
LineCreated: Types.RefBoolean,
|
|
||||||
currentLayerPoint: Types.RefMeshArray,
|
|
||||||
dragPointControls: Types.RefDragControl,
|
|
||||||
setNewLines: any,
|
|
||||||
setDeletedLines: any,
|
|
||||||
activeLayer: Types.Number,
|
|
||||||
socket: Socket<any>,
|
|
||||||
projectId?: string,
|
|
||||||
versionId?: string,
|
|
||||||
ydoc?: any
|
|
||||||
): Promise<void> {
|
|
||||||
const { userId, organization } = getUserData();
|
|
||||||
////////// Creating lines Based on the positions clicked //////////
|
|
||||||
|
|
||||||
////////// Allows the user lines that represents walls and roof, floor if forms a polygon //////////
|
|
||||||
|
|
||||||
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,
|
|
||||||
projectId,
|
|
||||||
versionId
|
|
||||||
);
|
|
||||||
setNewLines([newLines[0], newLines[1]]);
|
|
||||||
|
|
||||||
(line.current as Types.Line).push([
|
|
||||||
new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z),
|
|
||||||
isSnappedUUID.current!,
|
|
||||||
activeLayer,
|
|
||||||
CONSTANTS.lineConfig.wallName,
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
|
|
||||||
const data = arrayLineToObject(line.current as Types.Line);
|
|
||||||
|
|
||||||
//REST
|
|
||||||
|
|
||||||
// setLine(organization, data.layer!, data.line!, data.type!);
|
|
||||||
|
|
||||||
//SOCKET
|
|
||||||
|
|
||||||
const input = {
|
|
||||||
organization,
|
|
||||||
layer: data.layer,
|
|
||||||
line: data.line,
|
|
||||||
type: data.type,
|
|
||||||
socketId: socket.id,
|
|
||||||
versionId,
|
|
||||||
projectId,
|
|
||||||
userId,
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log('input: ', input);
|
|
||||||
socket.emit("v1:Line-collab:create", input);
|
|
||||||
|
|
||||||
// ✅ Add to Yjs map (will auto-sync to other clients)
|
|
||||||
const yLine = new Y.Map();
|
|
||||||
yLine.set("organization", organization);
|
|
||||||
yLine.set("layer", data.layer);
|
|
||||||
yLine.set("type", data.type);
|
|
||||||
yLine.set("line", data.line)
|
|
||||||
yLine.set("socketId", socket.id)
|
|
||||||
yLine.set("projectId", projectId);
|
|
||||||
yLine.set("versionId", versionId);
|
|
||||||
yLine.set("userId", userId);
|
|
||||||
|
|
||||||
const yLineArray = new Y.Array();
|
|
||||||
if (!data.line) return
|
|
||||||
for (const point of data.line) {
|
|
||||||
const yPoint = new Y.Map();
|
|
||||||
yPoint.set("uuid", point.uuid);
|
|
||||||
if (point.position) {
|
|
||||||
yPoint.set("position", new Y.Map([
|
|
||||||
["x", point.position.x],
|
|
||||||
["y", point.position.y],
|
|
||||||
["z", point.position.z],
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
yLineArray.push([yPoint]);
|
|
||||||
}
|
|
||||||
yLine.set("line", yLineArray);
|
|
||||||
|
|
||||||
const lineMap = ydoc.getMap("lines");
|
|
||||||
lineMap.observe((event: any) => {
|
|
||||||
console.log('event: ', event);
|
|
||||||
console.log("Map changed!", event.changes.keys);
|
|
||||||
});
|
|
||||||
|
|
||||||
const lineId = crypto.randomUUID(); // Or use backend _id if available
|
|
||||||
lineMap.set(lineId, yLine); // 👈 triggers Yjs update event
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
// //REST
|
|
||||||
|
|
||||||
// // setLine(organization, data.layer!, data.line!, data.type!);
|
|
||||||
|
|
||||||
// //SOCKET
|
|
||||||
|
|
||||||
// const input = {
|
|
||||||
// organization,
|
|
||||||
// layer: data.layer,
|
|
||||||
// line: data.line,
|
|
||||||
// type: data.type,
|
|
||||||
// socketId: socket.id,
|
|
||||||
// versionId,
|
|
||||||
// projectId,
|
|
||||||
// userId,
|
|
||||||
// };
|
|
||||||
|
|
||||||
// console.log('input: ', input);
|
|
||||||
// socket.emit("v1:Line-collab: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 (line.current.length >= 2 && line.current[0] && line.current[1]) {
|
|
||||||
const data = arrayLineToObject(line.current as Types.Line);
|
|
||||||
|
|
||||||
// ✅ Prepare input for socket.emit (your backend)
|
|
||||||
const input = {
|
|
||||||
organization,
|
|
||||||
layer: data.layer,
|
|
||||||
line: data.line,
|
|
||||||
type: data.type,
|
|
||||||
socketId: socket.id,
|
|
||||||
versionId,
|
|
||||||
projectId,
|
|
||||||
userId,
|
|
||||||
};
|
|
||||||
|
|
||||||
// ✅ Emit to backend
|
|
||||||
socket.emit("v1:Line-collab:create", input);
|
|
||||||
|
|
||||||
// ✅ Add to Yjs map (will auto-sync to other clients)
|
|
||||||
const yLine = new Y.Map();
|
|
||||||
yLine.set("organization", organization);
|
|
||||||
yLine.set("layer", data.layer);
|
|
||||||
yLine.set("type", data.type);
|
|
||||||
yLine.set("line", data.line)
|
|
||||||
yLine.set("socketId", socket.id)
|
|
||||||
yLine.set("projectId", projectId);
|
|
||||||
yLine.set("versionId", versionId);
|
|
||||||
yLine.set("userId", userId);
|
|
||||||
|
|
||||||
const yLineArray = new Y.Array();
|
|
||||||
if (!data.line) return
|
|
||||||
for (const point of data.line) {
|
|
||||||
const yPoint = new Y.Map();
|
|
||||||
yPoint.set("uuid", point.uuid);
|
|
||||||
if (point.position) {
|
|
||||||
yPoint.set("position", new Y.Map([
|
|
||||||
["x", point.position.x],
|
|
||||||
["y", point.position.y],
|
|
||||||
["z", point.position.z],
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
yLineArray.push([yPoint]);
|
|
||||||
}
|
|
||||||
yLine.set("line", yLineArray);
|
|
||||||
|
|
||||||
const lineMap = ydoc.getMap("lines");
|
|
||||||
lineMap.observe((event: any) => {
|
|
||||||
console.log('event: ', event);
|
|
||||||
console.log("Map changed!", event.changes.keys);
|
|
||||||
});
|
|
||||||
|
|
||||||
const lineId = generateUniqueId(); // Or use backend _id if available
|
|
||||||
lineMap.set(lineId, yLine); // 👈 triggers Yjs update event
|
|
||||||
|
|
||||||
// ✅ Scene + local updates
|
|
||||||
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
|
|
||||||
);
|
|
||||||
|
|
||||||
const lastPoint = line.current[line.current.length - 1];
|
|
||||||
line.current = [lastPoint];
|
|
||||||
}
|
|
||||||
if (isSnapped.current) {
|
|
||||||
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default drawWall;
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
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 +0,0 @@
|
|||||||
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 +0,0 @@
|
|||||||
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 +0,0 @@
|
|||||||
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 +0,0 @@
|
|||||||
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,66 +0,0 @@
|
|||||||
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 +0,0 @@
|
|||||||
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,153 +0,0 @@
|
|||||||
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 { getUserData } from "../../../../functions/getUserData";
|
|
||||||
// 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,
|
|
||||||
projectId?: string,
|
|
||||||
versionId?: string,
|
|
||||||
): [Types.Line, Types.Line] {
|
|
||||||
////////// Removing the clicked line and splitting it with the clicked position adding a new point and two new lines //////////
|
|
||||||
|
|
||||||
const { userId, organization, email } = getUserData();
|
|
||||||
(visibleIntersect.object as any).material.dispose();
|
|
||||||
(visibleIntersect.object as any).geometry.dispose();
|
|
||||||
floorPlanGroupLine.current.remove(visibleIntersect.object);
|
|
||||||
setDeletedLines([visibleIntersect.object.userData.linePoints]);
|
|
||||||
|
|
||||||
//REST
|
|
||||||
|
|
||||||
// deleteLineApi(
|
|
||||||
// organization,
|
|
||||||
// [
|
|
||||||
// { "uuid": visibleIntersect.object.userData.linePoints[0][1] },
|
|
||||||
// { "uuid": visibleIntersect.object.userData.linePoints[1][1] }
|
|
||||||
// ]
|
|
||||||
// )
|
|
||||||
|
|
||||||
//SOCKET
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
organization,
|
|
||||||
line: [
|
|
||||||
{ uuid: visibleIntersect.object.userData.linePoints[0][1] },
|
|
||||||
{ uuid: visibleIntersect.object.userData.linePoints[1][1] },
|
|
||||||
],
|
|
||||||
socketId: socket.id,
|
|
||||||
versionId,
|
|
||||||
projectId,
|
|
||||||
userId,
|
|
||||||
};
|
|
||||||
|
|
||||||
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,
|
|
||||||
layer: line1.layer,
|
|
||||||
line: line1.line,
|
|
||||||
type: line1.type,
|
|
||||||
socketId: socket.id,
|
|
||||||
versionId,
|
|
||||||
projectId,
|
|
||||||
userId,
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log('input1: ', input1);
|
|
||||||
socket.emit("v1:Line:create", input1);
|
|
||||||
|
|
||||||
//REST
|
|
||||||
|
|
||||||
// setLine(organization, line2.layer!, line2.line!, line2.type!);
|
|
||||||
|
|
||||||
//SOCKET
|
|
||||||
|
|
||||||
const input2 = {
|
|
||||||
organization,
|
|
||||||
layer: line2.layer,
|
|
||||||
line: line2.line,
|
|
||||||
type: line2.type,
|
|
||||||
socketId: socket.id,
|
|
||||||
versionId,
|
|
||||||
projectId,
|
|
||||||
userId,
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log('input2: ', input2);
|
|
||||||
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 +0,0 @@
|
|||||||
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.getObjectByName('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 +0,0 @@
|
|||||||
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 +0,0 @@
|
|||||||
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 +0,0 @@
|
|||||||
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 +0,0 @@
|
|||||||
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 +0,0 @@
|
|||||||
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 +0,0 @@
|
|||||||
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 +0,0 @@
|
|||||||
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);
|
|
||||||
echo.success("Pillar Removed!");
|
|
||||||
hoveredDeletablePillar.current = undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default DeletePillar;
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
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 +0,0 @@
|
|||||||
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: {
|
|
||||||
uOuterColor: { 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 uOuterColor;
|
|
||||||
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(uOuterColor, 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,72 +0,0 @@
|
|||||||
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";
|
|
||||||
import { getUserData } from "../../../../functions/getUserData";
|
|
||||||
|
|
||||||
function deletePoint(
|
|
||||||
hoveredDeletablePoint: Types.RefMesh,
|
|
||||||
onlyFloorlines: Types.RefOnlyFloorLines,
|
|
||||||
floorPlanGroupPoint: Types.RefGroup,
|
|
||||||
floorPlanGroupLine: Types.RefGroup,
|
|
||||||
lines: Types.RefLines,
|
|
||||||
setDeletedLines: any,
|
|
||||||
socket: Socket<any>,
|
|
||||||
projectId?: string,
|
|
||||||
versionId?: string,
|
|
||||||
): void {
|
|
||||||
////////// Deleting a Point and the lines that are connected to it //////////
|
|
||||||
|
|
||||||
if (!hoveredDeletablePoint.current) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const { userId, organization, email } = getUserData();
|
|
||||||
(<any>hoveredDeletablePoint.current.material).dispose();
|
|
||||||
(<any>hoveredDeletablePoint.current.geometry).dispose();
|
|
||||||
floorPlanGroupPoint.current.remove(hoveredDeletablePoint.current);
|
|
||||||
const DeletedPointUUID = hoveredDeletablePoint.current.uuid;
|
|
||||||
|
|
||||||
//REST
|
|
||||||
|
|
||||||
// deletePointApi(organization, DeletedPointUUID);
|
|
||||||
|
|
||||||
//SOCKET
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
organization,
|
|
||||||
uuid: DeletedPointUUID,
|
|
||||||
socketId: socket.id,
|
|
||||||
versionId,
|
|
||||||
projectId,
|
|
||||||
userId,
|
|
||||||
};
|
|
||||||
|
|
||||||
// console.log('data: ', data);
|
|
||||||
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
|
|
||||||
);
|
|
||||||
|
|
||||||
echo.success("Point Removed!");
|
|
||||||
}
|
|
||||||
|
|
||||||
export default deletePoint;
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
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 +0,0 @@
|
|||||||
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 +0,0 @@
|
|||||||
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 });
|
|
||||||
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 +0,0 @@
|
|||||||
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,164 +0,0 @@
|
|||||||
import { GLTF, 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 { Socket } from "socket.io-client";
|
|
||||||
import { retrieveGLTF, storeGLTF } from "../../../../utils/indexDB/idbUtils";
|
|
||||||
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
|
|
||||||
import { getUserData } from "../../../../functions/getUserData";
|
|
||||||
|
|
||||||
async function AddWallItems(
|
|
||||||
selected: any,
|
|
||||||
raycaster: THREE.Raycaster,
|
|
||||||
CSGGroup: Types.RefMesh,
|
|
||||||
setWallItems: Types.setWallItemSetState,
|
|
||||||
socket: Socket<any>,
|
|
||||||
projectId?: string,
|
|
||||||
versionId?: string
|
|
||||||
): Promise<void> {
|
|
||||||
|
|
||||||
const { userId, organization } = getUserData();
|
|
||||||
let intersects = raycaster?.intersectObject(CSGGroup.current!, true);
|
|
||||||
const wallRaycastIntersection = intersects?.find((child) =>
|
|
||||||
child.object.name.includes("WallRaycastReference")
|
|
||||||
);
|
|
||||||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
|
||||||
|
|
||||||
if (!wallRaycastIntersection) return;
|
|
||||||
|
|
||||||
const intersectionPoint = wallRaycastIntersection;
|
|
||||||
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);
|
|
||||||
|
|
||||||
// Check THREE.js cache first
|
|
||||||
const cachedModel = THREE.Cache.get(selected.id);
|
|
||||||
if (cachedModel) {
|
|
||||||
handleModelLoad(cachedModel);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check IndexedDB cache
|
|
||||||
const cachedModelBlob = await retrieveGLTF(selected.id);
|
|
||||||
if (cachedModelBlob) {
|
|
||||||
const blobUrl = URL.createObjectURL(cachedModelBlob);
|
|
||||||
loader.load(blobUrl, (gltf) => {
|
|
||||||
URL.revokeObjectURL(blobUrl);
|
|
||||||
THREE.Cache.remove(blobUrl);
|
|
||||||
THREE.Cache.add(selected.id, gltf);
|
|
||||||
handleModelLoad(gltf);
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load from backend if not in any cache
|
|
||||||
loader.load(
|
|
||||||
`${url_Backend_dwinzo}/api/v2/AssetFile/${selected.id}`,
|
|
||||||
async (gltf) => {
|
|
||||||
try {
|
|
||||||
const modelBlob = await fetch(
|
|
||||||
`${url_Backend_dwinzo}/api/v2/AssetFile/${selected.id}`
|
|
||||||
).then((res) => res.blob());
|
|
||||||
await storeGLTF(selected.id, modelBlob);
|
|
||||||
THREE.Cache.add(selected.id, gltf);
|
|
||||||
await handleModelLoad(gltf);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Failed to cache model:", error);
|
|
||||||
handleModelLoad(gltf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
async function handleModelLoad(gltf: GLTF) {
|
|
||||||
const model = gltf.scene.clone();
|
|
||||||
model.userData = { wall: intersectionPoint.object.parent };
|
|
||||||
|
|
||||||
model.children[0].children.forEach((child) => {
|
|
||||||
if (child.name !== "CSG_REF") {
|
|
||||||
child.castShadow = true;
|
|
||||||
child.receiveShadow = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const boundingBox = new THREE.Box3().setFromObject(model);
|
|
||||||
const size = new THREE.Vector3();
|
|
||||||
boundingBox.getSize(size);
|
|
||||||
|
|
||||||
const csgscale = [size.x, size.y, size.z] as [number, number, number];
|
|
||||||
|
|
||||||
const center = new THREE.Vector3();
|
|
||||||
boundingBox.getCenter(center);
|
|
||||||
const csgposition = [center.x, center.y, center.z] as [
|
|
||||||
number,
|
|
||||||
number,
|
|
||||||
number
|
|
||||||
];
|
|
||||||
|
|
||||||
let positionY =
|
|
||||||
selected.subCategory === "fixed-move" ? 0 : intersectionPoint.point.y;
|
|
||||||
if (positionY === 0) {
|
|
||||||
positionY =
|
|
||||||
Math.floor(intersectionPoint.point.y / CONSTANTS.wallConfig.height) *
|
|
||||||
CONSTANTS.wallConfig.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
const newWallItem = {
|
|
||||||
type: selected.subCategory,
|
|
||||||
model: model,
|
|
||||||
modelName: selected.name,
|
|
||||||
assetId: selected.id,
|
|
||||||
scale: [1, 1, 1] as [number, number, number],
|
|
||||||
csgscale: csgscale,
|
|
||||||
csgposition: csgposition,
|
|
||||||
position: [
|
|
||||||
intersectionPoint.point.x,
|
|
||||||
positionY,
|
|
||||||
intersectionPoint.point.z,
|
|
||||||
] as [number, number, number],
|
|
||||||
quaternion:
|
|
||||||
intersectionPoint.object.quaternion.clone() as Types.QuaternionType,
|
|
||||||
};
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
organization,
|
|
||||||
modelUuid: model.uuid,
|
|
||||||
modelName: newWallItem.modelName,
|
|
||||||
assetId: selected.id,
|
|
||||||
type: selected.subCategory,
|
|
||||||
csgposition: newWallItem.csgposition,
|
|
||||||
csgscale: newWallItem.csgscale,
|
|
||||||
position: newWallItem.position,
|
|
||||||
quaternion: newWallItem.quaternion,
|
|
||||||
scale: newWallItem.scale,
|
|
||||||
socketId: socket.id,
|
|
||||||
versionId,
|
|
||||||
projectId,
|
|
||||||
userId,
|
|
||||||
};
|
|
||||||
|
|
||||||
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));
|
|
||||||
echo.success("Model Added!");
|
|
||||||
return updatedItems;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default AddWallItems;
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
import { getUserData } from "../../../../functions/getUserData";
|
|
||||||
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>,
|
|
||||||
projectId?: string,
|
|
||||||
versionId? : string,
|
|
||||||
): void {
|
|
||||||
////////// Deleting the hovered Wall GLTF from thewallItems and also update it in the localstorage //////////
|
|
||||||
const { userId, organization, email } = getUserData();
|
|
||||||
if (hoveredDeletableWallItem.current && hoveredDeletableWallItem.current) {
|
|
||||||
setWallItems([]);
|
|
||||||
let WallItemsRef = wallItems;
|
|
||||||
const removedItem = WallItemsRef.find(
|
|
||||||
(item) => item.model?.uuid === hoveredDeletableWallItem.current?.uuid
|
|
||||||
);
|
|
||||||
const Items = WallItemsRef.filter(
|
|
||||||
(item) => item.model?.uuid !== hoveredDeletableWallItem.current?.uuid
|
|
||||||
);
|
|
||||||
|
|
||||||
setTimeout(async () => {
|
|
||||||
WallItemsRef = Items;
|
|
||||||
setWallItems(WallItemsRef);
|
|
||||||
|
|
||||||
//REST
|
|
||||||
|
|
||||||
// await deleteWallItem(organization, removedItem?.model?.uuid!, removedItem?.modelName!)
|
|
||||||
|
|
||||||
//SOCKET
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
organization,
|
|
||||||
modelUuid: removedItem?.model?.uuid!,
|
|
||||||
modelName: removedItem?.modelName!,
|
|
||||||
socketId: socket.id,
|
|
||||||
projectId,
|
|
||||||
versionId,
|
|
||||||
userId,
|
|
||||||
};
|
|
||||||
|
|
||||||
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));
|
|
||||||
hoveredDeletableWallItem.current = null;
|
|
||||||
}, 50);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default DeleteWallItems;
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
import * as THREE from 'three';
|
|
||||||
import * as Types from "../../../../types/world/worldTypes";
|
|
||||||
|
|
||||||
function hideWalls(
|
|
||||||
visibility: Types.Boolean,
|
|
||||||
scene: THREE.Scene,
|
|
||||||
camera: THREE.Camera
|
|
||||||
): void {
|
|
||||||
const wallNormal = new THREE.Vector3();
|
|
||||||
const cameraToWall = new THREE.Vector3();
|
|
||||||
const cameraDirection = 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") {
|
|
||||||
const wallMesh = child.children[0];
|
|
||||||
wallMesh.getWorldDirection(wallNormal);
|
|
||||||
cameraToWall.copy(wallMesh.position).sub(camera.position).normalize();
|
|
||||||
camera.getWorldDirection(cameraDirection);
|
|
||||||
const isFacingCamera = wallNormal.dot(cameraToWall) > 0;
|
|
||||||
const isInFrontOfCamera = cameraDirection.dot(cameraToWall) > -0.3;
|
|
||||||
|
|
||||||
if (wallMesh.material) {
|
|
||||||
wallMesh.material.visible = isFacingCamera && isInFrontOfCamera;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} 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" && child.children[0].material) {
|
|
||||||
child.children[0].material.visible = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default hideWalls;
|
|
||||||
@@ -1,140 +0,0 @@
|
|||||||
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;
|
|
||||||
|
|
||||||
|
|
||||||
// A----- B----- C
|
|
||||||
// | | |
|
|
||||||
// | | |
|
|
||||||
// | | |
|
|
||||||
// F----- E----- D
|
|
||||||
|
|
||||||
// 1. A -> B, B -> C, C -> D, D -> E, E -> F, F -> A, B -> E
|
|
||||||
|
|
||||||
// 2. E -> F, F -> A, A -> B, B -> E, E -> D, D -> C, C -> B
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
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 uOuterColor;
|
|
||||||
void main(){
|
|
||||||
float alpha = 1.0 - vUv.y;
|
|
||||||
gl_FragColor = vec4(uOuterColor, alpha);
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
uniforms: {
|
|
||||||
uOuterColor: { 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.uOuterColor.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 +0,0 @@
|
|||||||
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,127 +0,0 @@
|
|||||||
import { useFrame, useThree } from "@react-three/fiber";
|
|
||||||
import {
|
|
||||||
useAddAction,
|
|
||||||
useRoofVisibility,
|
|
||||||
useToggleView,
|
|
||||||
useWallVisibility,
|
|
||||||
useUpdateScene,
|
|
||||||
useRenameModeStore,
|
|
||||||
useToolMode,
|
|
||||||
} from "../../../store/builder/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";
|
|
||||||
import { useLeftData, useTopData } from "../../../store/visualization/useZone3DWidgetStore";
|
|
||||||
|
|
||||||
const FloorGroup = ({
|
|
||||||
floorGroup,
|
|
||||||
lines,
|
|
||||||
referencePole,
|
|
||||||
hoveredDeletablePillar,
|
|
||||||
}: any) => {
|
|
||||||
const state = useThree();
|
|
||||||
const { roofVisibility } = useRoofVisibility();
|
|
||||||
const { wallVisibility } = useWallVisibility();
|
|
||||||
const { toggleView } = useToggleView();
|
|
||||||
const { scene, camera, raycaster, gl } = useThree();
|
|
||||||
const { addAction } = useAddAction();
|
|
||||||
const { toolMode } = useToolMode();
|
|
||||||
const { updateScene, setUpdateScene } = useUpdateScene();
|
|
||||||
const { setTop } = useTopData();
|
|
||||||
const { setLeft } = useLeftData();
|
|
||||||
const { isRenameMode, setIsRenameMode } = useRenameModeStore();
|
|
||||||
|
|
||||||
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) => {
|
|
||||||
setIsRenameMode(false);
|
|
||||||
if (evt.button === 0) {
|
|
||||||
isLeftMouseDown = false;
|
|
||||||
if (!drag) {
|
|
||||||
if (addAction === "pillar") {
|
|
||||||
addPillar(referencePole, floorGroup);
|
|
||||||
}
|
|
||||||
if (toolMode === '3D-Delete') {
|
|
||||||
DeletePillar(hoveredDeletablePillar, floorGroup);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onMouseMove = (evt: any) => {
|
|
||||||
if (!canvasElement) return;
|
|
||||||
const canvasRect = canvasElement.getBoundingClientRect();
|
|
||||||
const relativeX = evt.clientX - canvasRect.left;
|
|
||||||
const relativeY = evt.clientY - canvasRect.top;
|
|
||||||
// if (!isRenameMode) {
|
|
||||||
// setTop(relativeY);
|
|
||||||
// setLeft(relativeX);
|
|
||||||
// }
|
|
||||||
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);
|
|
||||||
};
|
|
||||||
}, [toolMode, addAction, isRenameMode]);
|
|
||||||
|
|
||||||
useFrame(() => {
|
|
||||||
hideRoof(roofVisibility, floorGroup, camera);
|
|
||||||
hideWalls(wallVisibility, scene, camera);
|
|
||||||
|
|
||||||
if (addAction === "pillar") {
|
|
||||||
addAndUpdateReferencePillar(raycaster, floorGroup, referencePole);
|
|
||||||
}
|
|
||||||
if (toolMode === '3D-Delete') {
|
|
||||||
DeletableHoveredPillar(state, floorGroup, hoveredDeletablePillar);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<group ref={floorGroup} visible={!toggleView} name="floorGroup"></group>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default FloorGroup;
|
|
||||||
@@ -1,193 +0,0 @@
|
|||||||
import { useEffect } from "react";
|
|
||||||
import * as Types from '../../../types/world/worldTypes';
|
|
||||||
import { useActiveLayer, useDeletedLines, useToolMode, useNewLines, useRemovedLayer, useSocketStore, useToggleView, useUpdateScene } from "../../../store/builder/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 "../IntialLoad/loadInitialPoint";
|
|
||||||
import loadInitialLine from "../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";
|
|
||||||
import { useParams } from "react-router-dom";
|
|
||||||
import { getUserData } from "../../../functions/getUserData";
|
|
||||||
import { useVersionContext } from "../version/versionContext";
|
|
||||||
|
|
||||||
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 { camera, gl, raycaster, controls } = state;
|
|
||||||
const { activeLayer } = useActiveLayer();
|
|
||||||
const { toggleView } = useToggleView();
|
|
||||||
const { toolMode } = useToolMode();
|
|
||||||
const { removedLayer, setRemovedLayer } = useRemovedLayer();
|
|
||||||
const { setUpdateScene } = useUpdateScene();
|
|
||||||
const { setNewLines } = useNewLines();
|
|
||||||
const { setDeletedLines } = useDeletedLines();
|
|
||||||
const { socket } = useSocketStore();
|
|
||||||
const { ydoc } = useSocketStore();
|
|
||||||
const { selectedVersionStore } = useVersionContext();
|
|
||||||
const { selectedVersion } = selectedVersionStore();
|
|
||||||
const { projectId } = useParams();
|
|
||||||
const { organization } = getUserData();
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (toolMode === 'move') {
|
|
||||||
addDragControl(dragPointControls, currentLayerPoint, state, floorPlanGroupPoint, floorPlanGroupLine, lines, onlyFloorlines, socket, projectId, selectedVersion?.versionId || '',);
|
|
||||||
}
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
if (dragPointControls.current) {
|
|
||||||
dragPointControls.current.enabled = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}, [toolMode, state]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!selectedVersion) return;
|
|
||||||
|
|
||||||
getLines(organization, projectId, selectedVersion?.versionId || '').then((data) => {
|
|
||||||
|
|
||||||
const Lines: Types.Lines = objectLinesToArray(data);
|
|
||||||
|
|
||||||
if (Lines) {
|
|
||||||
lines.current = Lines;
|
|
||||||
loadInitialPoint(lines, floorPlanGroupPoint, currentLayerPoint, dragPointControls);
|
|
||||||
loadInitialLine(floorPlanGroupLine, lines);
|
|
||||||
setUpdateScene(true);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}, [selectedVersion?.versionId]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!toggleView) {
|
|
||||||
removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint);
|
|
||||||
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
|
|
||||||
}
|
|
||||||
}, [toggleView]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint);
|
|
||||||
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
|
|
||||||
}, [toolMode]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (toolMode === 'move' && toggleView) {
|
|
||||||
if (dragPointControls.current) {
|
|
||||||
dragPointControls.current.enabled = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (dragPointControls.current) {
|
|
||||||
dragPointControls.current.enabled = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [toolMode, toggleView, state]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
Layer2DVisibility(activeLayer, floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoint, currentLayerPoint, dragPointControls);
|
|
||||||
}, [activeLayer]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (removedLayer !== null) {
|
|
||||||
DeleteLayer(removedLayer, lines, floorPlanGroupLine, floorPlanGroupPoint, onlyFloorlines, floorGroup, setDeletedLines, setRemovedLayer, socket, projectId, selectedVersion?.versionId || '',);
|
|
||||||
}
|
|
||||||
}, [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 (toolMode === "2D-Delete") {
|
|
||||||
if (hoveredDeletablePoint.current !== null) {
|
|
||||||
deletePoint(hoveredDeletablePoint, onlyFloorlines, floorPlanGroupPoint, floorPlanGroupLine, lines, setDeletedLines, socket, projectId, selectedVersion?.versionId || '',);
|
|
||||||
}
|
|
||||||
if (hoveredDeletableLine.current !== null) {
|
|
||||||
deleteLine(hoveredDeletableLine, onlyFloorlines, lines, floorPlanGroupLine, floorPlanGroupPoint, setDeletedLines, socket, projectId, selectedVersion?.versionId || '',);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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, projectId, selectedVersion?.versionId || '', ydoc);
|
|
||||||
}
|
|
||||||
|
|
||||||
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, projectId, selectedVersion?.versionId || '',);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (toolMode === "2D-Delete" || 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);
|
|
||||||
};
|
|
||||||
}, [toolMode, activeLayer])
|
|
||||||
|
|
||||||
|
|
||||||
useFrame(() => {
|
|
||||||
if (toolMode === '2D-Delete') {
|
|
||||||
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,291 +1,291 @@
|
|||||||
import { useEffect } from "react";
|
// import { useEffect } from "react";
|
||||||
import {
|
// import {
|
||||||
useObjectPosition,
|
// useObjectPosition,
|
||||||
useObjectRotation,
|
// useObjectRotation,
|
||||||
useSelectedWallItem,
|
// useSelectedWallItem,
|
||||||
useSocketStore,
|
// useSocketStore,
|
||||||
useWallItems,
|
// useWallItems,
|
||||||
useSelectedItem,
|
// useSelectedItem,
|
||||||
useToolMode,
|
// useToolMode,
|
||||||
} from "../../../store/builder/store";
|
// } from "../../../store/builder/store";
|
||||||
import { Csg } from "../csg/csg";
|
// import { Csg } from "../csg/csg";
|
||||||
import * as Types from "../../../types/world/worldTypes";
|
// import * as Types from "../../../types/world/worldTypes";
|
||||||
import * as CONSTANTS from "../../../types/world/worldConstants";
|
// import * as CONSTANTS from "../../../types/world/worldConstants";
|
||||||
import * as THREE from "three";
|
// import * as THREE from "three";
|
||||||
import { useThree } from "@react-three/fiber";
|
// import { useThree } from "@react-three/fiber";
|
||||||
import handleMeshMissed from "../eventFunctions/handleMeshMissed";
|
// import handleMeshMissed from "../eventFunctions/handleMeshMissed";
|
||||||
import DeleteWallItems from "../geomentries/walls/deleteWallItems";
|
// import DeleteWallItems from "../geomentries/walls/deleteWallItems";
|
||||||
import loadInitialWallItems from "../IntialLoad/loadInitialWallItems";
|
// import loadInitialWallItems from "../IntialLoad/loadInitialWallItems";
|
||||||
import AddWallItems from "../geomentries/walls/addWallItems";
|
// import AddWallItems from "../geomentries/walls/addWallItems";
|
||||||
import useModuleStore from "../../../store/useModuleStore";
|
// import useModuleStore from "../../../store/useModuleStore";
|
||||||
import { useParams } from "react-router-dom";
|
// import { useParams } from "react-router-dom";
|
||||||
import { getUserData } from "../../../functions/getUserData";
|
// import { getUserData } from "../../../functions/getUserData";
|
||||||
import { useVersionContext } from "../version/versionContext";
|
// import { useVersionContext } from "../version/versionContext";
|
||||||
|
|
||||||
const WallItemsGroup = ({
|
// const WallItemsGroup = ({
|
||||||
currentWallItem,
|
// currentWallItem,
|
||||||
hoveredDeletableWallItem,
|
// hoveredDeletableWallItem,
|
||||||
selectedItemsIndex,
|
// selectedItemsIndex,
|
||||||
setSelectedItemsIndex,
|
// setSelectedItemsIndex,
|
||||||
CSGGroup,
|
// CSGGroup,
|
||||||
}: any) => {
|
// }: any) => {
|
||||||
const state = useThree();
|
// const state = useThree();
|
||||||
const { socket } = useSocketStore();
|
// const { socket } = useSocketStore();
|
||||||
const { pointer, camera, raycaster } = state;
|
// const { pointer, camera, raycaster } = state;
|
||||||
const { toolMode } = useToolMode();
|
// const { toolMode } = useToolMode();
|
||||||
const { wallItems, setWallItems } = useWallItems();
|
// const { wallItems, setWallItems } = useWallItems();
|
||||||
const { setObjectPosition } = useObjectPosition();
|
// const { setObjectPosition } = useObjectPosition();
|
||||||
const { setObjectRotation } = useObjectRotation();
|
// const { setObjectRotation } = useObjectRotation();
|
||||||
const { setSelectedWallItem } = useSelectedWallItem();
|
// const { setSelectedWallItem } = useSelectedWallItem();
|
||||||
const { activeModule } = useModuleStore();
|
// const { activeModule } = useModuleStore();
|
||||||
const { selectedItem } = useSelectedItem();
|
// const { selectedItem } = useSelectedItem();
|
||||||
const { selectedVersionStore } = useVersionContext();
|
// const { selectedVersionStore } = useVersionContext();
|
||||||
const { selectedVersion } = selectedVersionStore();
|
// const { selectedVersion } = selectedVersionStore();
|
||||||
const { projectId } = useParams();
|
// const { projectId } = useParams();
|
||||||
const { userId, organization } = getUserData();
|
// const { userId, organization } = getUserData();
|
||||||
|
|
||||||
useEffect(() => {
|
// useEffect(() => {
|
||||||
// Load Wall Items from the backend
|
// // Load Wall Items from the backend
|
||||||
if (!projectId || !selectedVersion) return;
|
// if (!projectId || !selectedVersion) return;
|
||||||
loadInitialWallItems(setWallItems, projectId, selectedVersion?.versionId);
|
// loadInitialWallItems(setWallItems, projectId, selectedVersion?.versionId);
|
||||||
}, [selectedVersion?.versionId]);
|
// }, [selectedVersion?.versionId]);
|
||||||
|
|
||||||
////////// Update the Position value changes in the selected item //////////
|
// ////////// Update the Position value changes in the selected item //////////
|
||||||
|
|
||||||
useEffect(() => {
|
// useEffect(() => {
|
||||||
const canvasElement = state.gl.domElement;
|
// const canvasElement = state.gl.domElement;
|
||||||
function handlePointerMove(e: any) {
|
// function handlePointerMove(e: any) {
|
||||||
if (selectedItemsIndex !== null && toolMode === 'cursor' && e.buttons === 1) {
|
// if (selectedItemsIndex !== null && toolMode === 'cursor' && e.buttons === 1) {
|
||||||
const Raycaster = state.raycaster;
|
// const Raycaster = state.raycaster;
|
||||||
const intersects = Raycaster.intersectObjects(CSGGroup.current?.children[0].children!, true);
|
// const intersects = Raycaster.intersectObjects(CSGGroup.current?.children[0].children!, true);
|
||||||
const Object = intersects.find((child) => child.object.name.includes("WallRaycastReference"));
|
// const Object = intersects.find((child) => child.object.name.includes("WallRaycastReference"));
|
||||||
|
|
||||||
if (Object) {
|
// if (Object) {
|
||||||
(state.controls as any)!.enabled = false;
|
// (state.controls as any)!.enabled = false;
|
||||||
setWallItems((prevItems: any) => {
|
// setWallItems((prevItems: any) => {
|
||||||
const updatedItems = [...prevItems];
|
// const updatedItems = [...prevItems];
|
||||||
let position: [number, number, number] = [0, 0, 0];
|
// let position: [number, number, number] = [0, 0, 0];
|
||||||
|
|
||||||
if (updatedItems[selectedItemsIndex].type === "fixed-move") {
|
// if (updatedItems[selectedItemsIndex].type === "fixed-move") {
|
||||||
position = [
|
// position = [
|
||||||
Object!.point.x,
|
// Object!.point.x,
|
||||||
Math.floor(Object!.point.y / CONSTANTS.wallConfig.height) *
|
// Math.floor(Object!.point.y / CONSTANTS.wallConfig.height) *
|
||||||
CONSTANTS.wallConfig.height,
|
// CONSTANTS.wallConfig.height,
|
||||||
Object!.point.z,
|
// Object!.point.z,
|
||||||
];
|
// ];
|
||||||
} else if (updatedItems[selectedItemsIndex].type === "free-move") {
|
// } else if (updatedItems[selectedItemsIndex].type === "free-move") {
|
||||||
position = [Object!.point.x, Object!.point.y, Object!.point.z];
|
// position = [Object!.point.x, Object!.point.y, Object!.point.z];
|
||||||
}
|
// }
|
||||||
|
|
||||||
requestAnimationFrame(() => {
|
// requestAnimationFrame(() => {
|
||||||
setObjectPosition(new THREE.Vector3(...position));
|
// setObjectPosition(new THREE.Vector3(...position));
|
||||||
setObjectRotation({
|
// setObjectRotation({
|
||||||
x: THREE.MathUtils.radToDeg(Object!.object.rotation.x),
|
// x: THREE.MathUtils.radToDeg(Object!.object.rotation.x),
|
||||||
y: THREE.MathUtils.radToDeg(Object!.object.rotation.y),
|
// y: THREE.MathUtils.radToDeg(Object!.object.rotation.y),
|
||||||
z: THREE.MathUtils.radToDeg(Object!.object.rotation.z),
|
// z: THREE.MathUtils.radToDeg(Object!.object.rotation.z),
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
|
|
||||||
updatedItems[selectedItemsIndex] = {
|
// updatedItems[selectedItemsIndex] = {
|
||||||
...updatedItems[selectedItemsIndex],
|
// ...updatedItems[selectedItemsIndex],
|
||||||
position: position,
|
// position: position,
|
||||||
quaternion: Object!.object.quaternion.clone() as Types.QuaternionType,
|
// quaternion: Object!.object.quaternion.clone() as Types.QuaternionType,
|
||||||
};
|
// };
|
||||||
|
|
||||||
return updatedItems;
|
// return updatedItems;
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
async function handlePointerUp() {
|
// async function handlePointerUp() {
|
||||||
const Raycaster = state.raycaster;
|
// const Raycaster = state.raycaster;
|
||||||
const intersects = Raycaster.intersectObjects(
|
// const intersects = Raycaster.intersectObjects(
|
||||||
CSGGroup.current?.children[0].children!,
|
// CSGGroup.current?.children[0].children!,
|
||||||
true
|
// true
|
||||||
);
|
// );
|
||||||
const Object = intersects.find((child) =>
|
// const Object = intersects.find((child) =>
|
||||||
child.object.name.includes("WallRaycastReference")
|
// child.object.name.includes("WallRaycastReference")
|
||||||
);
|
// );
|
||||||
if (Object) {
|
// if (Object) {
|
||||||
if (selectedItemsIndex !== null) {
|
// if (selectedItemsIndex !== null) {
|
||||||
let currentItem: any = null;
|
// let currentItem: any = null;
|
||||||
setWallItems((prevItems: any) => {
|
// setWallItems((prevItems: any) => {
|
||||||
const updatedItems = [...prevItems];
|
// const updatedItems = [...prevItems];
|
||||||
const WallItemsForStorage = updatedItems.map((item) => {
|
// const WallItemsForStorage = updatedItems.map((item) => {
|
||||||
const { model, ...rest } = item;
|
// const { model, ...rest } = item;
|
||||||
return {
|
// return {
|
||||||
...rest,
|
// ...rest,
|
||||||
modelUuid: model?.uuid,
|
// modelUuid: model?.uuid,
|
||||||
};
|
// };
|
||||||
});
|
// });
|
||||||
|
|
||||||
currentItem = updatedItems[selectedItemsIndex];
|
// currentItem = updatedItems[selectedItemsIndex];
|
||||||
localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage));
|
// localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage));
|
||||||
return updatedItems;
|
// return updatedItems;
|
||||||
});
|
// });
|
||||||
|
|
||||||
setTimeout(async () => {
|
// setTimeout(async () => {
|
||||||
|
|
||||||
//REST
|
// //REST
|
||||||
|
|
||||||
// await setWallItem(
|
// // await setWallItem(
|
||||||
// organization,
|
// // organization,
|
||||||
// currentItem?.model?.uuid,
|
// // currentItem?.model?.uuid,
|
||||||
// currentItem.modelName,
|
// // currentItem.modelName,
|
||||||
// currentItem.assetId,
|
// // currentItem.assetId,
|
||||||
// currentItem.type!,
|
// // currentItem.type!,
|
||||||
// currentItem.csgposition!,
|
// // currentItem.csgposition!,
|
||||||
// currentItem.csgscale!,
|
// // currentItem.csgscale!,
|
||||||
// currentItem.position,
|
// // currentItem.position,
|
||||||
// currentItem.quaternion,
|
// // currentItem.quaternion,
|
||||||
// currentItem.scale!,
|
// // currentItem.scale!,
|
||||||
// )
|
// // )
|
||||||
|
|
||||||
//SOCKET
|
// //SOCKET
|
||||||
|
|
||||||
const data = {
|
// const data = {
|
||||||
organization,
|
// organization,
|
||||||
modelUuid: currentItem.model?.uuid!,
|
// modelUuid: currentItem.model?.uuid!,
|
||||||
assetId: currentItem.assetId,
|
// assetId: currentItem.assetId,
|
||||||
modelName: currentItem.modelName!,
|
// modelName: currentItem.modelName!,
|
||||||
type: currentItem.type!,
|
// type: currentItem.type!,
|
||||||
csgposition: currentItem.csgposition!,
|
// csgposition: currentItem.csgposition!,
|
||||||
csgscale: currentItem.csgscale!,
|
// csgscale: currentItem.csgscale!,
|
||||||
position: currentItem.position!,
|
// position: currentItem.position!,
|
||||||
quaternion: currentItem.quaternion,
|
// quaternion: currentItem.quaternion,
|
||||||
scale: currentItem.scale!,
|
// scale: currentItem.scale!,
|
||||||
socketId: socket.id,
|
// socketId: socket.id,
|
||||||
versionId: selectedVersion?.versionId || '',
|
// versionId: selectedVersion?.versionId || '',
|
||||||
projectId,
|
// projectId,
|
||||||
userId
|
// userId
|
||||||
};
|
// };
|
||||||
|
|
||||||
// console.log('data: ', data);
|
// // console.log('data: ', data);
|
||||||
socket.emit("v1:wallItems:set", data);
|
// socket.emit("v1:wallItems:set", data);
|
||||||
}, 0);
|
// }, 0);
|
||||||
(state.controls as any)!.enabled = true;
|
// (state.controls as any)!.enabled = true;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
canvasElement.addEventListener("pointermove", handlePointerMove);
|
// canvasElement.addEventListener("pointermove", handlePointerMove);
|
||||||
canvasElement.addEventListener("pointerup", handlePointerUp);
|
// canvasElement.addEventListener("pointerup", handlePointerUp);
|
||||||
|
|
||||||
return () => {
|
// return () => {
|
||||||
canvasElement.removeEventListener("pointermove", handlePointerMove);
|
// canvasElement.removeEventListener("pointermove", handlePointerMove);
|
||||||
canvasElement.removeEventListener("pointerup", handlePointerUp);
|
// canvasElement.removeEventListener("pointerup", handlePointerUp);
|
||||||
};
|
// };
|
||||||
}, [selectedItemsIndex, selectedVersion?.versionId]);
|
// }, [selectedItemsIndex, selectedVersion?.versionId]);
|
||||||
|
|
||||||
useEffect(() => {
|
// useEffect(() => {
|
||||||
const canvasElement = state.gl.domElement;
|
// const canvasElement = state.gl.domElement;
|
||||||
let drag = false;
|
// let drag = false;
|
||||||
let isLeftMouseDown = false;
|
// let isLeftMouseDown = false;
|
||||||
|
|
||||||
const onMouseDown = (evt: any) => {
|
// const onMouseDown = (evt: any) => {
|
||||||
if (evt.button === 0) {
|
// if (evt.button === 0) {
|
||||||
isLeftMouseDown = true;
|
// isLeftMouseDown = true;
|
||||||
drag = false;
|
// drag = false;
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
|
|
||||||
const onMouseUp = (evt: any) => {
|
// const onMouseUp = (evt: any) => {
|
||||||
if (evt.button === 0) {
|
// if (evt.button === 0) {
|
||||||
isLeftMouseDown = false;
|
// isLeftMouseDown = false;
|
||||||
if (!drag && toolMode === '3D-Delete' && activeModule === "builder") {
|
// if (!drag && toolMode === '3D-Delete' && activeModule === "builder") {
|
||||||
DeleteWallItems(
|
// DeleteWallItems(
|
||||||
hoveredDeletableWallItem,
|
// hoveredDeletableWallItem,
|
||||||
setWallItems,
|
// setWallItems,
|
||||||
wallItems,
|
// wallItems,
|
||||||
socket,
|
// socket,
|
||||||
projectId,
|
// projectId,
|
||||||
selectedVersion?.versionId || '',
|
// selectedVersion?.versionId || '',
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
|
|
||||||
const onMouseMove = () => {
|
// const onMouseMove = () => {
|
||||||
if (isLeftMouseDown) {
|
// if (isLeftMouseDown) {
|
||||||
drag = true;
|
// drag = true;
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
|
|
||||||
const onDrop = (event: any) => {
|
// const onDrop = (event: any) => {
|
||||||
if (selectedItem.category !== 'Fenestration') return;
|
// if (selectedItem.category !== 'Fenestration') return;
|
||||||
|
|
||||||
pointer.x = (event.clientX / window.innerWidth) * 2 - 1;
|
// pointer.x = (event.clientX / window.innerWidth) * 2 - 1;
|
||||||
pointer.y = -(event.clientY / window.innerHeight) * 2 + 1;
|
// pointer.y = -(event.clientY / window.innerHeight) * 2 + 1;
|
||||||
|
|
||||||
raycaster.setFromCamera(pointer, camera);
|
// raycaster.setFromCamera(pointer, camera);
|
||||||
|
|
||||||
if (selectedItem.id && selectedVersion && projectId) {
|
// if (selectedItem.id && selectedVersion && projectId) {
|
||||||
if (selectedItem.subCategory) {
|
// if (selectedItem.subCategory) {
|
||||||
AddWallItems(
|
// AddWallItems(
|
||||||
selectedItem,
|
// selectedItem,
|
||||||
raycaster,
|
// raycaster,
|
||||||
CSGGroup,
|
// CSGGroup,
|
||||||
setWallItems,
|
// setWallItems,
|
||||||
socket,
|
// socket,
|
||||||
projectId,
|
// projectId,
|
||||||
selectedVersion?.versionId || '',
|
// selectedVersion?.versionId || '',
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
event.preventDefault();
|
// event.preventDefault();
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
|
|
||||||
const onDragOver = (event: any) => {
|
// const onDragOver = (event: any) => {
|
||||||
event.preventDefault();
|
// event.preventDefault();
|
||||||
};
|
// };
|
||||||
|
|
||||||
canvasElement.addEventListener("mousedown", onMouseDown);
|
// canvasElement.addEventListener("mousedown", onMouseDown);
|
||||||
canvasElement.addEventListener("mouseup", onMouseUp);
|
// canvasElement.addEventListener("mouseup", onMouseUp);
|
||||||
canvasElement.addEventListener("mousemove", onMouseMove);
|
// canvasElement.addEventListener("mousemove", onMouseMove);
|
||||||
canvasElement.addEventListener("drop", onDrop);
|
// canvasElement.addEventListener("drop", onDrop);
|
||||||
canvasElement.addEventListener("dragover", onDragOver);
|
// canvasElement.addEventListener("dragover", onDragOver);
|
||||||
|
|
||||||
return () => {
|
// return () => {
|
||||||
canvasElement.removeEventListener("mousedown", onMouseDown);
|
// canvasElement.removeEventListener("mousedown", onMouseDown);
|
||||||
canvasElement.removeEventListener("mouseup", onMouseUp);
|
// canvasElement.removeEventListener("mouseup", onMouseUp);
|
||||||
canvasElement.removeEventListener("mousemove", onMouseMove);
|
// canvasElement.removeEventListener("mousemove", onMouseMove);
|
||||||
canvasElement.removeEventListener("drop", onDrop);
|
// canvasElement.removeEventListener("drop", onDrop);
|
||||||
canvasElement.removeEventListener("dragover", onDragOver);
|
// canvasElement.removeEventListener("dragover", onDragOver);
|
||||||
};
|
// };
|
||||||
}, [toolMode, wallItems, selectedItem, camera, selectedVersion?.versionId]);
|
// }, [toolMode, wallItems, selectedItem, camera, selectedVersion?.versionId]);
|
||||||
|
|
||||||
useEffect(() => {
|
// useEffect(() => {
|
||||||
if (toolMode && activeModule === "builder") {
|
// if (toolMode && activeModule === "builder") {
|
||||||
handleMeshMissed(
|
// handleMeshMissed(
|
||||||
currentWallItem,
|
// currentWallItem,
|
||||||
setSelectedWallItem,
|
// setSelectedWallItem,
|
||||||
setSelectedItemsIndex
|
// setSelectedItemsIndex
|
||||||
);
|
// );
|
||||||
setSelectedWallItem(null);
|
// setSelectedWallItem(null);
|
||||||
setSelectedItemsIndex(null);
|
// setSelectedItemsIndex(null);
|
||||||
}
|
// }
|
||||||
}, [toolMode]);
|
// }, [toolMode]);
|
||||||
|
|
||||||
return (
|
// return (
|
||||||
<>
|
// <>
|
||||||
{wallItems.map((item: Types.WallItem, index: number) => (
|
// {wallItems.map((item: Types.WallItem, index: number) => (
|
||||||
<group
|
// <group
|
||||||
key={index}
|
// key={index}
|
||||||
position={item.position}
|
// position={item.position}
|
||||||
quaternion={item.quaternion}
|
// quaternion={item.quaternion}
|
||||||
scale={item.scale}
|
// scale={item.scale}
|
||||||
>
|
// >
|
||||||
<Csg
|
// <Csg
|
||||||
position={item.csgposition!}
|
// position={item.csgposition!}
|
||||||
scale={item.csgscale!}
|
// scale={item.csgscale!}
|
||||||
model={item.model!}
|
// model={item.model!}
|
||||||
hoveredDeletableWallItem={hoveredDeletableWallItem}
|
// hoveredDeletableWallItem={hoveredDeletableWallItem}
|
||||||
/>
|
// />
|
||||||
</group>
|
// </group>
|
||||||
))}
|
// ))}
|
||||||
</>
|
// </>
|
||||||
);
|
// );
|
||||||
};
|
// };
|
||||||
|
|
||||||
export default WallItemsGroup;
|
// export default WallItemsGroup;
|
||||||
|
|||||||
@@ -1,74 +1,74 @@
|
|||||||
import { Geometry } from "@react-three/csg";
|
// import { Geometry } from "@react-three/csg";
|
||||||
import {
|
// import {
|
||||||
useSelectedWallItem,
|
// useSelectedWallItem,
|
||||||
useToggleView,
|
// useToggleView,
|
||||||
useToolMode,
|
// useToolMode,
|
||||||
useWallItems,
|
// useWallItems,
|
||||||
useWalls,
|
// useWalls,
|
||||||
} from "../../../store/builder/store";
|
// } from "../../../store/builder/store";
|
||||||
import handleMeshDown from "../eventFunctions/handleMeshDown";
|
// import handleMeshDown from "../eventFunctions/handleMeshDown";
|
||||||
import handleMeshMissed from "../eventFunctions/handleMeshMissed";
|
// import handleMeshMissed from "../eventFunctions/handleMeshMissed";
|
||||||
import WallsMesh from "./wallsMesh";
|
// import WallsMesh from "./wallsMesh";
|
||||||
import WallItemsGroup from "./wallItemsGroup";
|
// import WallItemsGroup from "./wallItemsGroup";
|
||||||
|
|
||||||
const WallsAndWallItems = ({
|
// const WallsAndWallItems = ({
|
||||||
CSGGroup,
|
// CSGGroup,
|
||||||
setSelectedItemsIndex,
|
// setSelectedItemsIndex,
|
||||||
selectedItemsIndex,
|
// selectedItemsIndex,
|
||||||
currentWallItem,
|
// currentWallItem,
|
||||||
csg,
|
// csg,
|
||||||
lines,
|
// lines,
|
||||||
hoveredDeletableWallItem,
|
// hoveredDeletableWallItem,
|
||||||
}: any) => {
|
// }: any) => {
|
||||||
const { walls } = useWalls();
|
// const { walls } = useWalls();
|
||||||
const { wallItems } = useWallItems();
|
// const { wallItems } = useWallItems();
|
||||||
const { toggleView } = useToggleView();
|
// const { toggleView } = useToggleView();
|
||||||
const { toolMode } = useToolMode();
|
// const { toolMode } = useToolMode();
|
||||||
const { setSelectedWallItem } = useSelectedWallItem();
|
// const { setSelectedWallItem } = useSelectedWallItem();
|
||||||
|
|
||||||
return (
|
// return (
|
||||||
<mesh
|
// <mesh
|
||||||
ref={CSGGroup as any}
|
// ref={CSGGroup as any}
|
||||||
name="Walls"
|
// name="Walls"
|
||||||
key={walls.length}
|
// key={walls.length}
|
||||||
receiveShadow
|
// receiveShadow
|
||||||
visible={!toggleView}
|
// visible={!toggleView}
|
||||||
onClick={(event) => {
|
// onClick={(event) => {
|
||||||
if (toolMode === "cursor") {
|
// if (toolMode === "cursor") {
|
||||||
handleMeshDown(
|
// handleMeshDown(
|
||||||
event,
|
// event,
|
||||||
currentWallItem,
|
// currentWallItem,
|
||||||
setSelectedWallItem,
|
// setSelectedWallItem,
|
||||||
setSelectedItemsIndex,
|
// setSelectedItemsIndex,
|
||||||
wallItems,
|
// wallItems,
|
||||||
toggleView
|
// toggleView
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
}}
|
// }}
|
||||||
onPointerMissed={() => {
|
// onPointerMissed={() => {
|
||||||
if (toolMode === "cursor") {
|
// if (toolMode === "cursor") {
|
||||||
handleMeshMissed(
|
// handleMeshMissed(
|
||||||
currentWallItem,
|
// currentWallItem,
|
||||||
setSelectedWallItem,
|
// setSelectedWallItem,
|
||||||
setSelectedItemsIndex
|
// setSelectedItemsIndex
|
||||||
);
|
// );
|
||||||
setSelectedWallItem(null);
|
// setSelectedWallItem(null);
|
||||||
setSelectedItemsIndex(null);
|
// setSelectedItemsIndex(null);
|
||||||
}
|
// }
|
||||||
}}
|
// }}
|
||||||
>
|
// >
|
||||||
<Geometry ref={csg as any} computeVertexNormals useGroups>
|
// <Geometry ref={csg as any} computeVertexNormals useGroups>
|
||||||
<WallsMesh lines={lines} />
|
// <WallsMesh lines={lines} />
|
||||||
<WallItemsGroup
|
// <WallItemsGroup
|
||||||
currentWallItem={currentWallItem}
|
// currentWallItem={currentWallItem}
|
||||||
hoveredDeletableWallItem={hoveredDeletableWallItem}
|
// hoveredDeletableWallItem={hoveredDeletableWallItem}
|
||||||
selectedItemsIndex={selectedItemsIndex}
|
// selectedItemsIndex={selectedItemsIndex}
|
||||||
setSelectedItemsIndex={setSelectedItemsIndex}
|
// setSelectedItemsIndex={setSelectedItemsIndex}
|
||||||
CSGGroup={CSGGroup}
|
// CSGGroup={CSGGroup}
|
||||||
/>
|
// />
|
||||||
</Geometry>
|
// </Geometry>
|
||||||
</mesh>
|
// </mesh>
|
||||||
);
|
// );
|
||||||
};
|
// };
|
||||||
|
|
||||||
export default WallsAndWallItems;
|
// export default WallsAndWallItems;
|
||||||
|
|||||||
@@ -1,82 +1,82 @@
|
|||||||
import * as THREE from "three";
|
// import * as THREE from "three";
|
||||||
import * as Types from "../../../types/world/worldTypes";
|
// import * as Types from "../../../types/world/worldTypes";
|
||||||
import * as CONSTANTS from "../../../types/world/worldConstants";
|
// import * as CONSTANTS from "../../../types/world/worldConstants";
|
||||||
import { Base } from "@react-three/csg";
|
// import { Base } from "@react-three/csg";
|
||||||
import { MeshDiscardMaterial } from "@react-three/drei";
|
// import { MeshDiscardMaterial } from "@react-three/drei";
|
||||||
import { useUpdateScene, useWalls } from "../../../store/builder/store";
|
// import { useUpdateScene, useWalls } from "../../../store/builder/store";
|
||||||
import React, { useEffect } from "react";
|
// import React, { useEffect } from "react";
|
||||||
import { getLines } from "../../../services/factoryBuilder/lines/getLinesApi";
|
// import { getLines } from "../../../services/factoryBuilder/lines/getLinesApi";
|
||||||
import objectLinesToArray from "../geomentries/lines/lineConvertions/objectLinesToArray";
|
// import objectLinesToArray from "../geomentries/lines/lineConvertions/objectLinesToArray";
|
||||||
import loadWalls from "../geomentries/walls/loadWalls";
|
// import loadWalls from "../geomentries/walls/loadWalls";
|
||||||
import texturePath from "../../../assets/textures/floor/wall-tex.png";
|
// import texturePath from "../../../assets/textures/floor/wall-tex.png";
|
||||||
import { useParams } from "react-router-dom";
|
// import { useParams } from "react-router-dom";
|
||||||
import { getUserData } from "../../../functions/getUserData";
|
// import { getUserData } from "../../../functions/getUserData";
|
||||||
import { useVersionContext } from "../version/versionContext";
|
// import { useVersionContext } from "../version/versionContext";
|
||||||
|
|
||||||
const WallsMeshComponent = ({ lines }: any) => {
|
// const WallsMeshComponent = ({ lines }: any) => {
|
||||||
const { walls, setWalls } = useWalls();
|
// const { walls, setWalls } = useWalls();
|
||||||
const { updateScene, setUpdateScene } = useUpdateScene();
|
// const { updateScene, setUpdateScene } = useUpdateScene();
|
||||||
const { projectId } = useParams();
|
// const { projectId } = useParams();
|
||||||
const { selectedVersionStore } = useVersionContext();
|
// const { selectedVersionStore } = useVersionContext();
|
||||||
const { selectedVersion } = selectedVersionStore();
|
// const { selectedVersion } = selectedVersionStore();
|
||||||
const { organization } = getUserData();
|
// const { organization } = getUserData();
|
||||||
|
|
||||||
useEffect(() => {
|
// useEffect(() => {
|
||||||
if (updateScene) {
|
// if (updateScene) {
|
||||||
if (!selectedVersion) {
|
// if (!selectedVersion) {
|
||||||
setUpdateScene(false);
|
// setUpdateScene(false);
|
||||||
return;
|
// return;
|
||||||
};
|
// };
|
||||||
getLines(organization, projectId, selectedVersion?.versionId || '').then((data) => {
|
// getLines(organization, projectId, selectedVersion?.versionId || '').then((data) => {
|
||||||
const Lines: Types.Lines = objectLinesToArray(data);
|
// const Lines: Types.Lines = objectLinesToArray(data);
|
||||||
localStorage.setItem("Lines", JSON.stringify(Lines));
|
// localStorage.setItem("Lines", JSON.stringify(Lines));
|
||||||
|
|
||||||
if (Lines) {
|
// if (Lines) {
|
||||||
loadWalls(lines, setWalls);
|
// loadWalls(lines, setWalls);
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
setUpdateScene(false);
|
// setUpdateScene(false);
|
||||||
}
|
// }
|
||||||
}, [updateScene, selectedVersion?.versionId]);
|
// }, [updateScene, selectedVersion?.versionId]);
|
||||||
|
|
||||||
const textureLoader = new THREE.TextureLoader();
|
// const textureLoader = new THREE.TextureLoader();
|
||||||
const wallTexture = textureLoader.load(texturePath);
|
// const wallTexture = textureLoader.load(texturePath);
|
||||||
|
|
||||||
wallTexture.wrapS = wallTexture.wrapT = THREE.RepeatWrapping;
|
// wallTexture.wrapS = wallTexture.wrapT = THREE.RepeatWrapping;
|
||||||
wallTexture.repeat.set(0.1, 0.1);
|
// wallTexture.repeat.set(0.1, 0.1);
|
||||||
wallTexture.colorSpace = THREE.SRGBColorSpace;
|
// wallTexture.colorSpace = THREE.SRGBColorSpace;
|
||||||
|
|
||||||
return (
|
// return (
|
||||||
<>
|
// <>
|
||||||
{walls.map((wall: Types.Wall, index: number) => (
|
// {walls.map((wall: Types.Wall, index: number) => (
|
||||||
<mesh key={index} renderOrder={1}>
|
// <mesh key={index} renderOrder={1}>
|
||||||
<Base
|
// <Base
|
||||||
name={`Wall${index + 1}`}
|
// name={`Wall${index + 1}`}
|
||||||
geometry={wall[0]}
|
// geometry={wall[0]}
|
||||||
rotation={wall[1]}
|
// rotation={wall[1]}
|
||||||
position={wall[2]}
|
// position={wall[2]}
|
||||||
userData={{ WallType: wall[3], Layer: wall[4] }}
|
// userData={{ WallType: wall[3], Layer: wall[4] }}
|
||||||
>
|
// >
|
||||||
<meshStandardMaterial
|
// <meshStandardMaterial
|
||||||
side={THREE.DoubleSide}
|
// side={THREE.DoubleSide}
|
||||||
color={CONSTANTS.wallConfig.defaultColor}
|
// color={CONSTANTS.wallConfig.defaultColor}
|
||||||
map={wallTexture}
|
// map={wallTexture}
|
||||||
/>
|
// />
|
||||||
</Base>
|
// </Base>
|
||||||
<mesh
|
// <mesh
|
||||||
castShadow
|
// castShadow
|
||||||
geometry={wall[0]}
|
// geometry={wall[0]}
|
||||||
rotation={wall[1]}
|
// rotation={wall[1]}
|
||||||
position={wall[2]}
|
// position={wall[2]}
|
||||||
name={`WallRaycastReference_${index + 1}`}
|
// name={`WallRaycastReference_${index + 1}`}
|
||||||
>
|
// >
|
||||||
<MeshDiscardMaterial />
|
// <MeshDiscardMaterial />
|
||||||
</mesh>
|
// </mesh>
|
||||||
</mesh>
|
// </mesh>
|
||||||
))}
|
// ))}
|
||||||
</>
|
// </>
|
||||||
);
|
// );
|
||||||
};
|
// };
|
||||||
|
|
||||||
const WallsMesh = React.memo(WallsMeshComponent);
|
// const WallsMesh = React.memo(WallsMeshComponent);
|
||||||
export default WallsMesh;
|
// export default WallsMesh;
|
||||||
|
|||||||
@@ -1,651 +0,0 @@
|
|||||||
import React, { useState, useEffect, useMemo, useRef } from "react";
|
|
||||||
import { Html, Line, Sphere } from "@react-three/drei";
|
|
||||||
import { useThree, useFrame } from "@react-three/fiber";
|
|
||||||
import * as THREE from "three";
|
|
||||||
import {
|
|
||||||
useActiveLayer,
|
|
||||||
useSocketStore,
|
|
||||||
useToggleView,
|
|
||||||
useToolMode,
|
|
||||||
useRemovedLayer,
|
|
||||||
useZones,
|
|
||||||
useZonePoints,
|
|
||||||
} from "../../../store/builder/store";
|
|
||||||
import { getZonesApi } from "../../../services/factoryBuilder/zones/getZonesApi";
|
|
||||||
|
|
||||||
import * as CONSTANTS from "../../../types/world/worldConstants";
|
|
||||||
import * as turf from "@turf/turf";
|
|
||||||
import { computeArea } from "../functions/computeArea";
|
|
||||||
import { useSelectedZoneStore } from "../../../store/visualization/useZoneStore";
|
|
||||||
import { useParams } from "react-router-dom";
|
|
||||||
import { getUserData } from "../../../functions/getUserData";
|
|
||||||
import { useVersionContext } from "../version/versionContext";
|
|
||||||
|
|
||||||
const ZoneGroup: React.FC = () => {
|
|
||||||
const { camera, pointer, gl, raycaster, scene, controls } = useThree();
|
|
||||||
const [startPoint, setStartPoint] = useState<THREE.Vector3 | null>(null);
|
|
||||||
const [endPoint, setEndPoint] = useState<THREE.Vector3 | null>(null);
|
|
||||||
const { zones, setZones } = useZones();
|
|
||||||
const { zonePoints, setZonePoints } = useZonePoints();
|
|
||||||
const [isDragging, setIsDragging] = useState(false);
|
|
||||||
const { selectedZone } = useSelectedZoneStore();
|
|
||||||
const [draggedSphere, setDraggedSphere] = useState<THREE.Vector3 | null>(null);
|
|
||||||
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
|
||||||
const { toggleView } = useToggleView();
|
|
||||||
const { removedLayer, setRemovedLayer } = useRemovedLayer();
|
|
||||||
const { toolMode } = useToolMode();
|
|
||||||
const { activeLayer } = useActiveLayer();
|
|
||||||
const { socket } = useSocketStore();
|
|
||||||
const { selectedVersionStore } = useVersionContext();
|
|
||||||
const { selectedVersion } = selectedVersionStore();
|
|
||||||
const { projectId } = useParams();
|
|
||||||
const { userId, organization } = getUserData();
|
|
||||||
|
|
||||||
const groupsRef = useRef<any>();
|
|
||||||
|
|
||||||
const zoneMaterial = useMemo(
|
|
||||||
() =>
|
|
||||||
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 uOuterColor;
|
|
||||||
void main(){
|
|
||||||
float alpha = 1.0 - vUv.y;
|
|
||||||
gl_FragColor = vec4(uOuterColor, alpha);
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
uniforms: {
|
|
||||||
uOuterColor: { value: new THREE.Color(CONSTANTS.zoneConfig.color) },
|
|
||||||
},
|
|
||||||
transparent: true,
|
|
||||||
depthWrite: false,
|
|
||||||
}),
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!selectedVersion) return;
|
|
||||||
getZonesApi(organization, projectId, selectedVersion?.versionId || '').then((data) => {
|
|
||||||
if (data && data.length > 0) {
|
|
||||||
const fetchedZones = data.map((zone: any) => ({
|
|
||||||
zoneUuid: zone.zoneUuid,
|
|
||||||
zoneName: zone.zoneName,
|
|
||||||
points: zone.points,
|
|
||||||
viewPortCenter: zone.viewPortCenter,
|
|
||||||
viewPortposition: zone.viewPortposition,
|
|
||||||
layer: zone.layer,
|
|
||||||
}));
|
|
||||||
|
|
||||||
setZones(fetchedZones);
|
|
||||||
|
|
||||||
const fetchedPoints = data.flatMap((zone: any) =>
|
|
||||||
zone.points.slice(0, 4).map((point: [number, number, number]) => new THREE.Vector3(...point))
|
|
||||||
);
|
|
||||||
|
|
||||||
setZonePoints(fetchedPoints);
|
|
||||||
} else {
|
|
||||||
setZones([]);
|
|
||||||
}
|
|
||||||
}).catch((err) => {
|
|
||||||
console.error(err);
|
|
||||||
})
|
|
||||||
}, [selectedVersion?.versionId]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
localStorage.setItem("zones", JSON.stringify(zones));
|
|
||||||
}, [zones]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (removedLayer) {
|
|
||||||
const updatedZones = zones.filter((zone: any) => zone.layer !== removedLayer);
|
|
||||||
setZones(updatedZones);
|
|
||||||
|
|
||||||
const updatedzonePoints = zonePoints.filter((_: any, index: any) => {
|
|
||||||
const zoneIndex = Math.floor(index / 4);
|
|
||||||
return zones[zoneIndex]?.layer !== removedLayer;
|
|
||||||
});
|
|
||||||
setZonePoints(updatedzonePoints);
|
|
||||||
|
|
||||||
zones.filter((zone: any) => zone.layer === removedLayer).forEach((zone: any) => { deleteZoneFromBackend(zone.zoneUuid); });
|
|
||||||
|
|
||||||
setRemovedLayer(null);
|
|
||||||
}
|
|
||||||
}, [removedLayer]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (toolMode !== "Zone") {
|
|
||||||
setStartPoint(null);
|
|
||||||
setEndPoint(null);
|
|
||||||
}
|
|
||||||
if (!toggleView) {
|
|
||||||
setStartPoint(null);
|
|
||||||
setEndPoint(null);
|
|
||||||
}
|
|
||||||
}, [toolMode, toggleView]);
|
|
||||||
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
const addZoneToBackend = async (zone: {
|
|
||||||
zoneUuid: string;
|
|
||||||
zoneName: string;
|
|
||||||
points: [number, number, number][];
|
|
||||||
layer: string;
|
|
||||||
}) => {
|
|
||||||
|
|
||||||
const calculateCenter = (points: number[][]) => {
|
|
||||||
if (!points || points.length === 0) return null;
|
|
||||||
|
|
||||||
let sumX = 0, sumY = 0, sumZ = 0;
|
|
||||||
const numPoints = points.length;
|
|
||||||
|
|
||||||
points.forEach(([x, y, z]) => {
|
|
||||||
sumX += x;
|
|
||||||
sumY += y;
|
|
||||||
sumZ += z;
|
|
||||||
});
|
|
||||||
|
|
||||||
return [sumX / numPoints, sumY / numPoints, sumZ / numPoints] as [
|
|
||||||
number,
|
|
||||||
number,
|
|
||||||
number
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
const target: [number, number, number] | null = calculateCenter(zone.points);
|
|
||||||
if (!target || zone.points.length < 4) return;
|
|
||||||
const position = [target[0], 10, target[2]];
|
|
||||||
|
|
||||||
const input = {
|
|
||||||
userId: userId,
|
|
||||||
versionId: selectedVersion?.versionId || '',
|
|
||||||
projectId,
|
|
||||||
organization,
|
|
||||||
zoneData: {
|
|
||||||
zoneName: zone.zoneName,
|
|
||||||
zoneUuid: zone.zoneUuid,
|
|
||||||
points: zone.points,
|
|
||||||
viewPortCenter: target,
|
|
||||||
viewPortposition: position,
|
|
||||||
layer: zone.layer,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
socket.emit("v1:zone:set", input);
|
|
||||||
};
|
|
||||||
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
const updateZoneToBackend = async (zone: {
|
|
||||||
zoneUuid: string;
|
|
||||||
zoneName: string;
|
|
||||||
points: [number, number, number][];
|
|
||||||
layer: string;
|
|
||||||
}) => {
|
|
||||||
|
|
||||||
const calculateCenter = (points: number[][]) => {
|
|
||||||
if (!points || points.length === 0) return null;
|
|
||||||
|
|
||||||
let sumX = 0, sumY = 0, sumZ = 0;
|
|
||||||
const numPoints = points.length;
|
|
||||||
|
|
||||||
points.forEach(([x, y, z]) => {
|
|
||||||
sumX += x;
|
|
||||||
sumY += y;
|
|
||||||
sumZ += z;
|
|
||||||
});
|
|
||||||
|
|
||||||
return [sumX / numPoints, sumY / numPoints, sumZ / numPoints] as [
|
|
||||||
number,
|
|
||||||
number,
|
|
||||||
number
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
const target: [number, number, number] | null = calculateCenter(zone.points);
|
|
||||||
if (!target || zone.points.length < 4) return;
|
|
||||||
const position = [target[0], 10, target[2]];
|
|
||||||
|
|
||||||
const input = {
|
|
||||||
userId: userId,
|
|
||||||
versionId: selectedVersion?.versionId || '',
|
|
||||||
projectId,
|
|
||||||
organization,
|
|
||||||
zoneData: {
|
|
||||||
zoneName: zone.zoneName,
|
|
||||||
zoneUuid: zone.zoneUuid,
|
|
||||||
points: zone.points,
|
|
||||||
viewPortCenter: target,
|
|
||||||
viewPortposition: position,
|
|
||||||
layer: zone.layer,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
socket.emit("v1:zone:set", input);
|
|
||||||
};
|
|
||||||
|
|
||||||
const deleteZoneFromBackend = async (zoneUuid: string) => {
|
|
||||||
|
|
||||||
const input = {
|
|
||||||
userId: userId,
|
|
||||||
versionId: selectedVersion?.versionId || '',
|
|
||||||
projectId,
|
|
||||||
organization,
|
|
||||||
zoneUuid: zoneUuid,
|
|
||||||
};
|
|
||||||
|
|
||||||
socket.emit("v1:zone:delete", input);
|
|
||||||
};
|
|
||||||
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
const handleDeleteZone = (zoneUuid: string) => {
|
|
||||||
const updatedZones = zones.filter((zone: any) => zone.zoneUuid !== zoneUuid);
|
|
||||||
setZones(updatedZones);
|
|
||||||
|
|
||||||
const zoneIndex = zones.findIndex((zone: any) => zone.zoneUuid === zoneUuid);
|
|
||||||
if (zoneIndex !== -1) {
|
|
||||||
const zonePointsToRemove = zonePoints.slice(zoneIndex * 4, zoneIndex * 4 + 4);
|
|
||||||
zonePointsToRemove.forEach((point: any) => groupsRef.current.remove(point));
|
|
||||||
const updatedzonePoints = zonePoints.filter((_: any, index: any) => index < zoneIndex * 4 || index >= zoneIndex * 4 + 4);
|
|
||||||
setZonePoints(updatedzonePoints);
|
|
||||||
}
|
|
||||||
deleteZoneFromBackend(zoneUuid);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!camera || !toggleView) return;
|
|
||||||
const canvasElement = gl.domElement;
|
|
||||||
|
|
||||||
let drag = false;
|
|
||||||
let isLeftMouseDown = false;
|
|
||||||
|
|
||||||
const onMouseDown = (evt: any) => {
|
|
||||||
if (evt.button === 0) {
|
|
||||||
isLeftMouseDown = true;
|
|
||||||
drag = false;
|
|
||||||
|
|
||||||
raycaster.setFromCamera(pointer, camera);
|
|
||||||
const intersects = raycaster.intersectObjects(groupsRef.current.children, true);
|
|
||||||
|
|
||||||
if (intersects.length > 0 && toolMode === "move") {
|
|
||||||
const clickedObject = intersects[0].object;
|
|
||||||
const sphereIndex = zonePoints.findIndex((point: any) =>
|
|
||||||
point.equals(clickedObject.position)
|
|
||||||
);
|
|
||||||
if (sphereIndex !== -1) {
|
|
||||||
(controls as any).enabled = false;
|
|
||||||
setDraggedSphere(zonePoints[sphereIndex]);
|
|
||||||
setIsDragging(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onMouseUp = (evt: any) => {
|
|
||||||
if (evt.button === 0 && !drag && !isDragging && toolMode === 'Zone') {
|
|
||||||
isLeftMouseDown = false;
|
|
||||||
|
|
||||||
if (!startPoint) {
|
|
||||||
raycaster.setFromCamera(pointer, camera);
|
|
||||||
const intersectionPoint = new THREE.Vector3();
|
|
||||||
const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
|
||||||
if (point) {
|
|
||||||
setStartPoint(point);
|
|
||||||
setEndPoint(null);
|
|
||||||
}
|
|
||||||
} else if (startPoint) {
|
|
||||||
raycaster.setFromCamera(pointer, camera);
|
|
||||||
const intersectionPoint = new THREE.Vector3();
|
|
||||||
const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
|
||||||
if (!point) return;
|
|
||||||
|
|
||||||
const points = [
|
|
||||||
[startPoint.x, 0.15, startPoint.z],
|
|
||||||
[point.x, 0.15, startPoint.z],
|
|
||||||
[point.x, 0.15, point.z],
|
|
||||||
[startPoint.x, 0.15, point.z],
|
|
||||||
[startPoint.x, 0.15, startPoint.z],
|
|
||||||
] as [number, number, number][];
|
|
||||||
|
|
||||||
const zoneName = `Zone ${zones.length + 1}`;
|
|
||||||
const zoneUuid = THREE.MathUtils.generateUUID();
|
|
||||||
const newZone = {
|
|
||||||
zoneUuid,
|
|
||||||
zoneName,
|
|
||||||
points: points,
|
|
||||||
layer: activeLayer,
|
|
||||||
};
|
|
||||||
|
|
||||||
const newZones = [...zones, newZone];
|
|
||||||
|
|
||||||
setZones(newZones);
|
|
||||||
|
|
||||||
const newzonePoints = [
|
|
||||||
new THREE.Vector3(startPoint.x, 0.15, startPoint.z),
|
|
||||||
new THREE.Vector3(point.x, 0.15, startPoint.z),
|
|
||||||
new THREE.Vector3(point.x, 0.15, point.z),
|
|
||||||
new THREE.Vector3(startPoint.x, 0.15, point.z),
|
|
||||||
];
|
|
||||||
|
|
||||||
const updatedZonePoints = [...zonePoints, ...newzonePoints];
|
|
||||||
setZonePoints(updatedZonePoints);
|
|
||||||
|
|
||||||
addZoneToBackend(newZone);
|
|
||||||
setStartPoint(null);
|
|
||||||
setEndPoint(null);
|
|
||||||
}
|
|
||||||
} else if (evt.button === 0 && !drag && !isDragging && toolMode === '2D-Delete') {
|
|
||||||
raycaster.setFromCamera(pointer, camera);
|
|
||||||
const intersects = raycaster.intersectObjects(
|
|
||||||
groupsRef.current.children,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|
||||||
if (intersects.length > 0) {
|
|
||||||
const clickedObject = intersects[0].object;
|
|
||||||
|
|
||||||
const sphereIndex = zonePoints.findIndex((point: any) =>
|
|
||||||
point.equals(clickedObject.position)
|
|
||||||
);
|
|
||||||
if (sphereIndex !== -1) {
|
|
||||||
const zoneIndex = Math.floor(sphereIndex / 4);
|
|
||||||
const zoneUuid = zones[zoneIndex].zoneUuid;
|
|
||||||
handleDeleteZone(zoneUuid);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (evt.button === 0) {
|
|
||||||
if (isDragging && draggedSphere) {
|
|
||||||
setIsDragging(false);
|
|
||||||
setDraggedSphere(null);
|
|
||||||
|
|
||||||
const sphereIndex = zonePoints.findIndex((point: any) => point === draggedSphere);
|
|
||||||
if (sphereIndex !== -1) {
|
|
||||||
const zoneIndex = Math.floor(sphereIndex / 4);
|
|
||||||
|
|
||||||
if (zoneIndex !== -1 && zones[zoneIndex]) {
|
|
||||||
updateZoneToBackend(zones[zoneIndex]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onMouseMove = () => {
|
|
||||||
if (!groupsRef.current) return;
|
|
||||||
if (isLeftMouseDown) {
|
|
||||||
drag = true;
|
|
||||||
}
|
|
||||||
raycaster.setFromCamera(pointer, camera);
|
|
||||||
|
|
||||||
if (isDragging && draggedSphere) {
|
|
||||||
raycaster.setFromCamera(pointer, camera);
|
|
||||||
const intersectionPoint = new THREE.Vector3();
|
|
||||||
const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
|
||||||
if (point) {
|
|
||||||
draggedSphere.set(point.x, 0.15, point.z);
|
|
||||||
|
|
||||||
const sphereIndex = zonePoints.findIndex((point: any) => point === draggedSphere);
|
|
||||||
if (sphereIndex !== -1) {
|
|
||||||
const zoneIndex = Math.floor(sphereIndex / 4);
|
|
||||||
const cornerIndex = sphereIndex % 4;
|
|
||||||
|
|
||||||
const updatedZones = zones.map((zone: any, index: number) => {
|
|
||||||
if (index === zoneIndex) {
|
|
||||||
const updatedPoints = [...zone.points];
|
|
||||||
updatedPoints[cornerIndex] = [point.x, 0.15, point.z];
|
|
||||||
updatedPoints[4] = updatedPoints[0];
|
|
||||||
return { ...zone, points: updatedPoints };
|
|
||||||
}
|
|
||||||
return zone;
|
|
||||||
});
|
|
||||||
|
|
||||||
setZones(updatedZones);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onContext = (event: any) => {
|
|
||||||
event.preventDefault();
|
|
||||||
setStartPoint(null);
|
|
||||||
setEndPoint(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (toolMode === "Zone" || toolMode === '2D-Delete' || toolMode === "move") {
|
|
||||||
canvasElement.addEventListener("mousedown", onMouseDown);
|
|
||||||
canvasElement.addEventListener("mouseup", onMouseUp);
|
|
||||||
canvasElement.addEventListener("mousemove", onMouseMove);
|
|
||||||
canvasElement.addEventListener("contextmenu", onContext);
|
|
||||||
}
|
|
||||||
return () => {
|
|
||||||
canvasElement.removeEventListener("mousedown", onMouseDown);
|
|
||||||
canvasElement.removeEventListener("mouseup", onMouseUp);
|
|
||||||
canvasElement.removeEventListener("mousemove", onMouseMove);
|
|
||||||
canvasElement.removeEventListener("contextmenu", onContext);
|
|
||||||
};
|
|
||||||
}, [gl, camera, startPoint, toggleView, scene, toolMode, zones, isDragging, zonePoints, draggedSphere, activeLayer, raycaster, pointer, controls, plane, setZones, setZonePoints, addZoneToBackend, handleDeleteZone, updateZoneToBackend, selectedVersion?.versionId]);
|
|
||||||
|
|
||||||
useFrame(() => {
|
|
||||||
if (!startPoint) return;
|
|
||||||
raycaster.setFromCamera(pointer, camera);
|
|
||||||
const intersectionPoint = new THREE.Vector3();
|
|
||||||
const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
|
||||||
if (point) {
|
|
||||||
setEndPoint(point);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<group ref={groupsRef} name="zoneGroup">
|
|
||||||
<group name="zones" visible={!toggleView}>
|
|
||||||
{zones.map((zone: any) => (
|
|
||||||
<group
|
|
||||||
key={zone.zoneUuid}
|
|
||||||
name={zone.zoneName}
|
|
||||||
visible={zone.zoneUuid === selectedZone.zoneUuid}
|
|
||||||
>
|
|
||||||
{zone.points
|
|
||||||
.slice(0, -1)
|
|
||||||
.map((point: [number, number, number], index: number) => {
|
|
||||||
const nextPoint = zone.points[index + 1];
|
|
||||||
|
|
||||||
const point1 = new THREE.Vector3(point[0], point[1], point[2]);
|
|
||||||
const point2 = new THREE.Vector3(
|
|
||||||
nextPoint[0],
|
|
||||||
nextPoint[1],
|
|
||||||
nextPoint[2]
|
|
||||||
);
|
|
||||||
|
|
||||||
const planeWidth = point1.distanceTo(point2);
|
|
||||||
const planeHeight = CONSTANTS.zoneConfig.height;
|
|
||||||
|
|
||||||
const midpoint = new THREE.Vector3(
|
|
||||||
(point1.x + point2.x) / 2,
|
|
||||||
CONSTANTS.zoneConfig.height / 2 +
|
|
||||||
(zone.layer - 1) * CONSTANTS.zoneConfig.height,
|
|
||||||
(point1.z + point2.z) / 2
|
|
||||||
);
|
|
||||||
|
|
||||||
const angle = Math.atan2(
|
|
||||||
point2.z - point1.z,
|
|
||||||
point2.x - point1.x
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<mesh
|
|
||||||
key={index}
|
|
||||||
position={midpoint}
|
|
||||||
rotation={[0, -angle, 0]}
|
|
||||||
>
|
|
||||||
<planeGeometry args={[planeWidth, planeHeight]} />
|
|
||||||
<primitive
|
|
||||||
object={zoneMaterial.clone()}
|
|
||||||
attach="material"
|
|
||||||
/>
|
|
||||||
</mesh>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
{!toggleView &&
|
|
||||||
(() => {
|
|
||||||
const points3D = zone.points || [];
|
|
||||||
const coords2D = points3D.map((p: any) => [p[0], p[2]]);
|
|
||||||
|
|
||||||
// Ensure the polygon is closed
|
|
||||||
if (
|
|
||||||
coords2D.length >= 4 &&
|
|
||||||
(coords2D[0][0] !== coords2D[coords2D.length - 1][0] ||
|
|
||||||
coords2D[0][1] !== coords2D[coords2D.length - 1][1])
|
|
||||||
) {
|
|
||||||
coords2D.push(coords2D[0]);
|
|
||||||
}
|
|
||||||
if (coords2D.length < 4) return null;
|
|
||||||
|
|
||||||
const polygon = turf.polygon([coords2D]);
|
|
||||||
const center2D = turf.center(polygon).geometry.coordinates;
|
|
||||||
|
|
||||||
// Calculate the average Y value
|
|
||||||
const sumY = points3D.reduce(
|
|
||||||
(sum: number, p: any) => sum + p[1],
|
|
||||||
0
|
|
||||||
);
|
|
||||||
const avgY = points3D.length > 0 ? sumY / points3D.length : 0;
|
|
||||||
|
|
||||||
const htmlPosition: [number, number, number] = [
|
|
||||||
center2D[0],
|
|
||||||
avgY + (CONSTANTS.zoneConfig.height || 0) + 1.5,
|
|
||||||
center2D[1],
|
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Html
|
|
||||||
// data
|
|
||||||
key={zone.zoneUuid}
|
|
||||||
position={htmlPosition}
|
|
||||||
// class
|
|
||||||
className="zone-name-wrapper"
|
|
||||||
// others
|
|
||||||
center
|
|
||||||
>
|
|
||||||
<div className="zone-name">{zone.zoneName}</div>
|
|
||||||
</Html>
|
|
||||||
);
|
|
||||||
})()}
|
|
||||||
</group>
|
|
||||||
))}
|
|
||||||
</group>
|
|
||||||
<group name="zoneLines" visible={toggleView}>
|
|
||||||
{zones
|
|
||||||
.filter((zone: any) => zone.layer === activeLayer)
|
|
||||||
.map((zone: any) => (
|
|
||||||
<Line
|
|
||||||
key={zone.zoneUuid}
|
|
||||||
points={zone.points}
|
|
||||||
color="#007BFF"
|
|
||||||
lineWidth={3}
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
if (toolMode === '2D-Delete') {
|
|
||||||
handleDeleteZone(zone.zoneUuid);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</group>
|
|
||||||
<group name="zoneArea" visible={toggleView}>
|
|
||||||
{zones.map((zone: any, index: any) => {
|
|
||||||
if (!toggleView) return null;
|
|
||||||
const points3D = zone.points;
|
|
||||||
const coords2D = points3D.map((p: any) => [p[0], p[2]]);
|
|
||||||
|
|
||||||
if (
|
|
||||||
coords2D.length < 4 ||
|
|
||||||
coords2D[0][0] !== coords2D[coords2D.length - 1][0] ||
|
|
||||||
coords2D[0][1] !== coords2D[coords2D.length - 1][1]
|
|
||||||
) {
|
|
||||||
coords2D.push(coords2D[0]);
|
|
||||||
}
|
|
||||||
if (coords2D.length < 4) return null;
|
|
||||||
|
|
||||||
const polygon = turf.polygon([coords2D]);
|
|
||||||
const center2D = turf.center(polygon).geometry.coordinates;
|
|
||||||
|
|
||||||
const sumY = points3D.reduce((sum: number, p: any) => sum + p[1], 0);
|
|
||||||
const avgY = sumY / points3D.length;
|
|
||||||
|
|
||||||
const area = computeArea(points3D, "zone");
|
|
||||||
const formattedArea = `${area.toFixed(2)} m²`;
|
|
||||||
|
|
||||||
const htmlPosition: [number, number, number] = [
|
|
||||||
center2D[0],
|
|
||||||
avgY + CONSTANTS.zoneConfig.height,
|
|
||||||
center2D[1],
|
|
||||||
];
|
|
||||||
return (
|
|
||||||
<Html
|
|
||||||
// data
|
|
||||||
key={`${index}-${zone}`}
|
|
||||||
position={htmlPosition}
|
|
||||||
// class
|
|
||||||
wrapperClass="distance-text-wrapper"
|
|
||||||
className="distance-text"
|
|
||||||
// other
|
|
||||||
zIndexRange={[1, 0]}
|
|
||||||
prepend
|
|
||||||
center
|
|
||||||
sprite
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className={`distance area line-${zone}`}
|
|
||||||
key={`${index}-${zone}`}
|
|
||||||
>
|
|
||||||
{zone.zoneName} ({formattedArea})
|
|
||||||
</div>
|
|
||||||
</Html>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</group>
|
|
||||||
|
|
||||||
<group name="zonePoints" visible={toggleView}>
|
|
||||||
{zones
|
|
||||||
.filter((zone: any) => zone.layer === activeLayer)
|
|
||||||
.flatMap((zone: any) =>
|
|
||||||
zone.points.slice(0, 4).map((point: any, pointIndex: number) => (
|
|
||||||
<Sphere
|
|
||||||
key={`${zone.zoneUuid}-point-${pointIndex}`}
|
|
||||||
position={new THREE.Vector3(...point)}
|
|
||||||
args={[0.3, 16, 16]}
|
|
||||||
name={`point-${zone.zoneUuid}-${pointIndex}`}
|
|
||||||
>
|
|
||||||
<meshBasicMaterial color="red" />
|
|
||||||
</Sphere>
|
|
||||||
))
|
|
||||||
)}
|
|
||||||
</group>
|
|
||||||
<group name="tempGroup" visible={toggleView}>
|
|
||||||
{startPoint && endPoint && (
|
|
||||||
<Line
|
|
||||||
points={[
|
|
||||||
[startPoint.x, 0.15, startPoint.z],
|
|
||||||
[endPoint.x, 0.15, startPoint.z],
|
|
||||||
[endPoint.x, 0.15, endPoint.z],
|
|
||||||
[startPoint.x, 0.15, endPoint.z],
|
|
||||||
[startPoint.x, 0.15, startPoint.z],
|
|
||||||
]}
|
|
||||||
color="#C164FF"
|
|
||||||
lineWidth={3}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</group>
|
|
||||||
</group>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ZoneGroup;
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { Vector3 } from "three";
|
||||||
|
|
||||||
|
export default function closestPointOnLineSegment(p: Vector3, a: Vector3, b: Vector3) {
|
||||||
|
const ab = new Vector3().subVectors(b, a);
|
||||||
|
const ap = new Vector3().subVectors(p, a);
|
||||||
|
|
||||||
|
const abLengthSq = ab.lengthSq();
|
||||||
|
const dot = ap.dot(ab);
|
||||||
|
const t = Math.max(0, Math.min(1, dot / abLengthSq));
|
||||||
|
|
||||||
|
return new Vector3().copy(a).add(ab.multiplyScalar(t));
|
||||||
|
}
|
||||||
@@ -2,10 +2,20 @@ import * as THREE from 'three';
|
|||||||
import { useThree } from '@react-three/fiber';
|
import { useThree } from '@react-three/fiber';
|
||||||
import { useEffect, useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import { DragControls, Tube } from '@react-three/drei';
|
import { DragControls, Tube } from '@react-three/drei';
|
||||||
import { useToolMode } from '../../../store/builder/store';
|
import { useSocketStore, useToolMode } from '../../../store/builder/store';
|
||||||
import { useBuilderStore } from '../../../store/builder/useBuilderStore';
|
import { useBuilderStore } from '../../../store/builder/useBuilderStore';
|
||||||
import { useSceneContext } from '../../scene/sceneContext';
|
import { useSceneContext } from '../../scene/sceneContext';
|
||||||
import * as Constants from '../../../types/world/worldConstants';
|
import * as Constants from '../../../types/world/worldConstants';
|
||||||
|
import { useVersionContext } from '../version/versionContext';
|
||||||
|
import { useParams } from 'react-router-dom';
|
||||||
|
import { getUserData } from '../../../functions/getUserData';
|
||||||
|
|
||||||
|
// import { upsertWallApi } from '../../../services/factoryBuilder/wall/upsertWallApi';
|
||||||
|
// import { deleteWallApi } from '../../../services/factoryBuilder/wall/deleteWallApi';
|
||||||
|
// import { upsertFloorApi } from '../../../services/factoryBuilder/floor/upsertFloorApi';
|
||||||
|
// import { deleteFloorApi } from '../../../services/factoryBuilder/floor/deleteFloorApi';
|
||||||
|
// import { deleteZoneApi } from '../../../services/factoryBuilder/zone/deleteZoneApi';
|
||||||
|
// import { upsertZoneApi } from '../../../services/factoryBuilder/zone/upsertZoneApi';
|
||||||
|
|
||||||
interface LineProps {
|
interface LineProps {
|
||||||
points: [Point, Point];
|
points: [Point, Point];
|
||||||
@@ -16,9 +26,16 @@ function Line({ points }: Readonly<LineProps>) {
|
|||||||
const { raycaster, camera, pointer, gl } = useThree();
|
const { raycaster, camera, pointer, gl } = useThree();
|
||||||
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
||||||
const [isDeletable, setIsDeletable] = useState(false);
|
const [isDeletable, setIsDeletable] = useState(false);
|
||||||
|
const { socket } = useSocketStore();
|
||||||
const { toolMode } = useToolMode();
|
const { toolMode } = useToolMode();
|
||||||
const { wallStore } = useSceneContext();
|
const { wallStore, floorStore, zoneStore } = useSceneContext();
|
||||||
const { removeWallByPoints, setPosition } = wallStore();
|
const { removeWallByPoints, setPosition: setWallPosition, getWallsByPointId } = wallStore();
|
||||||
|
const { removeFloorByPoints, setPosition: setFloorPosition, getFloorsByPointId } = floorStore();
|
||||||
|
const { removeZoneByPoints, setPosition: setZonePosition, getZonesByPointId } = zoneStore();
|
||||||
|
const { userId, organization } = getUserData();
|
||||||
|
const { selectedVersionStore } = useVersionContext();
|
||||||
|
const { selectedVersion } = selectedVersionStore();
|
||||||
|
const { projectId } = useParams();
|
||||||
const [dragOffset, setDragOffset] = useState<THREE.Vector3 | null>(null);
|
const [dragOffset, setDragOffset] = useState<THREE.Vector3 | null>(null);
|
||||||
const { hoveredLine, setHoveredLine, hoveredPoint } = useBuilderStore();
|
const { hoveredLine, setHoveredLine, hoveredPoint } = useBuilderStore();
|
||||||
|
|
||||||
@@ -79,9 +96,123 @@ function Line({ points }: Readonly<LineProps>) {
|
|||||||
const handlePointClick = (points: [Point, Point]) => {
|
const handlePointClick = (points: [Point, Point]) => {
|
||||||
if (toolMode === '2D-Delete') {
|
if (toolMode === '2D-Delete') {
|
||||||
if (points[0].pointType === 'Wall' && points[1].pointType === 'Wall') {
|
if (points[0].pointType === 'Wall' && points[1].pointType === 'Wall') {
|
||||||
removeWallByPoints(points);
|
const removedWall = removeWallByPoints(points);
|
||||||
|
if (removedWall && projectId) {
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// deleteWallApi(projectId, selectedVersion?.versionId || '', removedWall.wallUuid);
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
wallUuid: removedWall.wallUuid,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:model-Wall:delete', data);
|
||||||
|
}
|
||||||
setHoveredLine(null);
|
setHoveredLine(null);
|
||||||
}
|
}
|
||||||
|
if (points[0].pointType === 'Floor' && points[1].pointType === 'Floor') {
|
||||||
|
const { removedFloors, updatedFloors } = removeFloorByPoints(points);
|
||||||
|
if (removedFloors.length > 0) {
|
||||||
|
removedFloors.forEach(floor => {
|
||||||
|
if (projectId) {
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// deleteFloorApi(projectId, selectedVersion?.versionId || '', floor.floorUuid);
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
floorUuid: floor.floorUuid,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:model-Floor:delete', data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (updatedFloors.length > 0) {
|
||||||
|
updatedFloors.forEach(floor => {
|
||||||
|
if (projectId) {
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// upsertFloorApi(projectId, selectedVersion?.versionId || '', floor);
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
floorData: floor,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:model-Floor:add', data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setHoveredLine(null);
|
||||||
|
}
|
||||||
|
if (points[0].pointType === 'Zone' && points[1].pointType === 'Zone') {
|
||||||
|
const { removedZones, updatedZones } = removeZoneByPoints(points);
|
||||||
|
if (removedZones.length > 0) {
|
||||||
|
removedZones.forEach(zone => {
|
||||||
|
if (projectId) {
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// deleteZoneApi(projectId, selectedVersion?.versionId || '', zone.zoneUuid);
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
zoneUuid: zone.zoneUuid,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:zone:delete', data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (updatedZones.length > 0) {
|
||||||
|
updatedZones.forEach(zone => {
|
||||||
|
if (projectId) {
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// upsertZoneApi(projectId, selectedVersion?.versionId || '', zone);
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
zoneData: zone,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:zone:add', data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
gl.domElement.style.cursor = 'default';
|
gl.domElement.style.cursor = 'default';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -105,8 +236,18 @@ function Line({ points }: Readonly<LineProps>) {
|
|||||||
const newStart = new THREE.Vector3().addVectors(start, delta);
|
const newStart = new THREE.Vector3().addVectors(start, delta);
|
||||||
const newEnd = new THREE.Vector3().addVectors(end, delta);
|
const newEnd = new THREE.Vector3().addVectors(end, delta);
|
||||||
|
|
||||||
setPosition(points[0].pointUuid, [newStart.x, newStart.y, newStart.z]);
|
if (points[0].pointType === 'Wall' && points[1].pointType === 'Wall') {
|
||||||
setPosition(points[1].pointUuid, [newEnd.x, newEnd.y, newEnd.z]);
|
setWallPosition(points[0].pointUuid, [newStart.x, newStart.y, newStart.z]);
|
||||||
|
setWallPosition(points[1].pointUuid, [newEnd.x, newEnd.y, newEnd.z]);
|
||||||
|
}
|
||||||
|
if (points[0].pointType === 'Floor' && points[1].pointType === 'Floor') {
|
||||||
|
setFloorPosition(points[0].pointUuid, [newStart.x, newStart.y, newStart.z]);
|
||||||
|
setFloorPosition(points[1].pointUuid, [newEnd.x, newEnd.y, newEnd.z]);
|
||||||
|
}
|
||||||
|
if (points[0].pointType === 'Zone' && points[1].pointType === 'Zone') {
|
||||||
|
setZonePosition(points[0].pointUuid, [newStart.x, newStart.y, newStart.z]);
|
||||||
|
setZonePosition(points[1].pointUuid, [newEnd.x, newEnd.y, newEnd.z]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -127,11 +268,90 @@ function Line({ points }: Readonly<LineProps>) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleDragEnd = (points: [Point, Point]) => {
|
const handleDragEnd = (points: [Point, Point]) => {
|
||||||
|
if (toolMode !== 'move' || !dragOffset) return;
|
||||||
gl.domElement.style.cursor = 'default';
|
gl.domElement.style.cursor = 'default';
|
||||||
setDragOffset(null);
|
setDragOffset(null);
|
||||||
if (toolMode !== 'move') return;
|
|
||||||
if (points[0].pointType === 'Wall' && points[1].pointType === 'Wall') {
|
if (points[0].pointType === 'Wall' && points[1].pointType === 'Wall') {
|
||||||
// console.log('Wall after drag: ', points);
|
const updatedWalls1 = getWallsByPointId(points[0].pointUuid);
|
||||||
|
const updatedWalls2 = getWallsByPointId(points[1].pointUuid);
|
||||||
|
const updatedWalls = [...updatedWalls1, ...updatedWalls2].filter((wall, index, self) => index === self.findIndex((w) => w.wallUuid === wall.wallUuid));
|
||||||
|
|
||||||
|
if (updatedWalls.length > 0 && projectId) {
|
||||||
|
updatedWalls.forEach(updatedWall => {
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// upsertWallApi(projectId, selectedVersion?.versionId || '', updatedWall).catch((error) => {
|
||||||
|
// console.error('Error updating wall:', error);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
wallData: updatedWall,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:model-Wall:add', data);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else if (points[0].pointType === 'Floor' && points[1].pointType === 'Floor') {
|
||||||
|
const updatedFloors1 = getFloorsByPointId(points[0].pointUuid);
|
||||||
|
const updatedFloors2 = getFloorsByPointId(points[1].pointUuid);
|
||||||
|
const updatedFloors = [...updatedFloors1, ...updatedFloors2].filter((floor, index, self) => index === self.findIndex((f) => f.floorUuid === floor.floorUuid));
|
||||||
|
|
||||||
|
if (updatedFloors.length > 0 && projectId) {
|
||||||
|
updatedFloors.forEach(updatedFloor => {
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// upsertFloorApi(projectId, selectedVersion?.versionId || '', updatedFloor).catch((error) => {
|
||||||
|
// console.error('Error updating floor:', error);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
floorData: updatedFloor,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:model-Floor:add', data);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else if (points[0].pointType === 'Zone' && points[1].pointType === 'Zone') {
|
||||||
|
const updatedZones1 = getZonesByPointId(points[0].pointUuid);
|
||||||
|
const updatedZones2 = getZonesByPointId(points[1].pointUuid);
|
||||||
|
const updatedZones = [...updatedZones1, ...updatedZones2].filter((zone, index, self) => index === self.findIndex((z) => z.zoneUuid === zone.zoneUuid));
|
||||||
|
|
||||||
|
if (updatedZones.length > 0 && projectId) {
|
||||||
|
updatedZones.forEach(updatedZone => {
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// upsertZoneApi(projectId, selectedVersion?.versionId || '', updatedZone).catch((error) => {
|
||||||
|
// console.error('Error updating zone:', error);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
zoneData: updatedZone,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:zone:add', data);
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +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;
|
||||||
24
app/src/modules/builder/pillars/addPillar.ts
Normal file
24
app/src/modules/builder/pillars/addPillar.ts
Normal file
@@ -0,0 +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);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// export default addPillar;
|
||||||
34
app/src/modules/builder/pillars/deletableHoveredPillar.ts
Normal file
34
app/src/modules/builder/pillars/deletableHoveredPillar.ts
Normal file
@@ -0,0 +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;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// export default DeletableHoveredPillar;
|
||||||
21
app/src/modules/builder/pillars/deletePillar.ts
Normal file
21
app/src/modules/builder/pillars/deletePillar.ts
Normal file
@@ -0,0 +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);
|
||||||
|
// echo.success("Pillar Removed!");
|
||||||
|
// hoveredDeletablePillar.current = undefined;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// export default DeletePillar;
|
||||||
@@ -0,0 +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;
|
||||||
@@ -11,9 +11,11 @@ const ANGLE_SNAP_DISTANCE_THRESHOLD = 0.5; // Distance threshold for snapping i
|
|||||||
const CAN_ANGLE_SNAP = true; // Whether snapping is enabled or not
|
const CAN_ANGLE_SNAP = true; // Whether snapping is enabled or not
|
||||||
|
|
||||||
export const usePointSnapping = (currentPoint: { uuid: string, pointType: string, position: [number, number, number] } | null) => {
|
export const usePointSnapping = (currentPoint: { uuid: string, pointType: string, position: [number, number, number] } | null) => {
|
||||||
const { aisleStore, wallStore } = useSceneContext();
|
const { aisleStore, wallStore, floorStore, zoneStore } = useSceneContext();
|
||||||
const { aisles, getConnectedPoints: getConnectedAislePoints } = aisleStore();
|
const { aisles, getConnectedPoints: getConnectedAislePoints } = aisleStore();
|
||||||
const { walls, getConnectedPoints: getConnectedWallPoints } = wallStore();
|
const { walls, getConnectedPoints: getConnectedWallPoints } = wallStore();
|
||||||
|
const { floors, getConnectedPoints: getConnectedFloorPoints } = floorStore();
|
||||||
|
const { zones, getConnectedPoints: getConnectedZonePoints } = zoneStore();
|
||||||
|
|
||||||
// Wall Snapping
|
// Wall Snapping
|
||||||
|
|
||||||
@@ -24,10 +26,13 @@ export const usePointSnapping = (currentPoint: { uuid: string, pointType: string
|
|||||||
);
|
);
|
||||||
}, [walls, currentPoint]);
|
}, [walls, currentPoint]);
|
||||||
|
|
||||||
const snapWallPoint = useCallback((position: [number, number, number]) => {
|
const snapWallPoint = useCallback((position: [number, number, number], tempPoints?: Point) => {
|
||||||
if (!currentPoint || !CAN_POINT_SNAP) return { position: position, isSnapped: false, snappedPoint: null };
|
if (!currentPoint || !CAN_POINT_SNAP) return { position: position, isSnapped: false, snappedPoint: null };
|
||||||
|
|
||||||
const otherPoints = getAllOtherWallPoints();
|
const otherPoints = getAllOtherWallPoints();
|
||||||
|
if (tempPoints) {
|
||||||
|
otherPoints.push(tempPoints);
|
||||||
|
}
|
||||||
const currentVec = new THREE.Vector3(...position);
|
const currentVec = new THREE.Vector3(...position);
|
||||||
for (const point of otherPoints) {
|
for (const point of otherPoints) {
|
||||||
const pointVec = new THREE.Vector3(...point.position);
|
const pointVec = new THREE.Vector3(...point.position);
|
||||||
@@ -187,10 +192,188 @@ export const usePointSnapping = (currentPoint: { uuid: string, pointType: string
|
|||||||
};
|
};
|
||||||
}, [currentPoint, getConnectedAislePoints]);
|
}, [currentPoint, getConnectedAislePoints]);
|
||||||
|
|
||||||
|
// Floor Snapping
|
||||||
|
|
||||||
|
const getAllOtherFloorPoints = useCallback(() => {
|
||||||
|
if (!currentPoint) return [];
|
||||||
|
|
||||||
|
return floors.flatMap(floor =>
|
||||||
|
floor.points.filter(point => point.pointUuid !== currentPoint.uuid)
|
||||||
|
);
|
||||||
|
}, [floors, currentPoint]);
|
||||||
|
|
||||||
|
const snapFloorPoint = useCallback((position: [number, number, number], tempPoints?: Point[] | []) => {
|
||||||
|
if (!currentPoint || !CAN_POINT_SNAP) return { position: position, isSnapped: false, snappedPoint: null };
|
||||||
|
|
||||||
|
let otherPoints = getAllOtherFloorPoints();
|
||||||
|
if (tempPoints) {
|
||||||
|
otherPoints = [...otherPoints, ...tempPoints];
|
||||||
|
}
|
||||||
|
const currentVec = new THREE.Vector3(...position);
|
||||||
|
|
||||||
|
for (const point of otherPoints) {
|
||||||
|
const pointVec = new THREE.Vector3(...point.position);
|
||||||
|
const distance = currentVec.distanceTo(pointVec);
|
||||||
|
|
||||||
|
if (distance <= POINT_SNAP_THRESHOLD && currentPoint.pointType === 'Floor') {
|
||||||
|
return { position: point.position, isSnapped: true, snappedPoint: point };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { position: position, isSnapped: false, snappedPoint: null };
|
||||||
|
}, [currentPoint, getAllOtherFloorPoints]);
|
||||||
|
|
||||||
|
const snapFloorAngle = useCallback((newPosition: [number, number, number]): {
|
||||||
|
position: [number, number, number],
|
||||||
|
isSnapped: boolean,
|
||||||
|
snapSources: THREE.Vector3[]
|
||||||
|
} => {
|
||||||
|
if (!currentPoint || !CAN_ANGLE_SNAP) return { position: newPosition, isSnapped: false, snapSources: [] };
|
||||||
|
|
||||||
|
const connectedPoints = getConnectedFloorPoints(currentPoint.uuid);
|
||||||
|
if (connectedPoints.length === 0) {
|
||||||
|
return { position: newPosition, isSnapped: false, snapSources: [] };
|
||||||
|
}
|
||||||
|
|
||||||
|
const newPos = new THREE.Vector3(...newPosition);
|
||||||
|
let closestX: { pos: THREE.Vector3, dist: number } | null = null;
|
||||||
|
let closestZ: { pos: THREE.Vector3, dist: number } | null = null;
|
||||||
|
|
||||||
|
for (const connectedPoint of connectedPoints) {
|
||||||
|
const cPos = new THREE.Vector3(...connectedPoint.position);
|
||||||
|
const xDist = Math.abs(newPos.x - cPos.x);
|
||||||
|
const zDist = Math.abs(newPos.z - cPos.z);
|
||||||
|
|
||||||
|
if (xDist < ANGLE_SNAP_DISTANCE_THRESHOLD) {
|
||||||
|
if (!closestX || xDist < closestX.dist) {
|
||||||
|
closestX = { pos: cPos, dist: xDist };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zDist < ANGLE_SNAP_DISTANCE_THRESHOLD) {
|
||||||
|
if (!closestZ || zDist < closestZ.dist) {
|
||||||
|
closestZ = { pos: cPos, dist: zDist };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const snappedPos = newPos.clone();
|
||||||
|
const snapSources: THREE.Vector3[] = [];
|
||||||
|
|
||||||
|
if (closestX) {
|
||||||
|
snappedPos.x = closestX.pos.x;
|
||||||
|
snapSources.push(closestX.pos.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (closestZ) {
|
||||||
|
snappedPos.z = closestZ.pos.z;
|
||||||
|
snapSources.push(closestZ.pos.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
const isSnapped = snapSources.length > 0;
|
||||||
|
|
||||||
|
return {
|
||||||
|
position: [snappedPos.x, snappedPos.y, snappedPos.z],
|
||||||
|
isSnapped,
|
||||||
|
snapSources
|
||||||
|
};
|
||||||
|
}, [currentPoint, getConnectedFloorPoints]);
|
||||||
|
|
||||||
|
// Zone Snapping
|
||||||
|
|
||||||
|
const getAllOtherZonePoints = useCallback(() => {
|
||||||
|
if (!currentPoint) return [];
|
||||||
|
|
||||||
|
return zones.flatMap(zone =>
|
||||||
|
zone.points.filter(point => point.pointUuid !== currentPoint.uuid)
|
||||||
|
);
|
||||||
|
}, [zones, currentPoint]);
|
||||||
|
|
||||||
|
const snapZonePoint = useCallback((position: [number, number, number], tempPoints?: Point[] | []) => {
|
||||||
|
if (!currentPoint || !CAN_POINT_SNAP) return { position: position, isSnapped: false, snappedPoint: null };
|
||||||
|
|
||||||
|
let otherPoints = getAllOtherZonePoints();
|
||||||
|
if (tempPoints) {
|
||||||
|
otherPoints = [...otherPoints, ...tempPoints];
|
||||||
|
}
|
||||||
|
const currentVec = new THREE.Vector3(...position);
|
||||||
|
|
||||||
|
for (const point of otherPoints) {
|
||||||
|
const pointVec = new THREE.Vector3(...point.position);
|
||||||
|
const distance = currentVec.distanceTo(pointVec);
|
||||||
|
|
||||||
|
if (distance <= POINT_SNAP_THRESHOLD && currentPoint.pointType === 'Zone') {
|
||||||
|
return { position: point.position, isSnapped: true, snappedPoint: point };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { position: position, isSnapped: false, snappedPoint: null };
|
||||||
|
}, [currentPoint, getAllOtherZonePoints]);
|
||||||
|
|
||||||
|
const snapZoneAngle = useCallback((newPosition: [number, number, number]): {
|
||||||
|
position: [number, number, number],
|
||||||
|
isSnapped: boolean,
|
||||||
|
snapSources: THREE.Vector3[]
|
||||||
|
} => {
|
||||||
|
if (!currentPoint || !CAN_ANGLE_SNAP) return { position: newPosition, isSnapped: false, snapSources: [] };
|
||||||
|
|
||||||
|
const connectedPoints = getConnectedZonePoints(currentPoint.uuid);
|
||||||
|
if (connectedPoints.length === 0) {
|
||||||
|
return { position: newPosition, isSnapped: false, snapSources: [] };
|
||||||
|
}
|
||||||
|
|
||||||
|
const newPos = new THREE.Vector3(...newPosition);
|
||||||
|
let closestX: { pos: THREE.Vector3, dist: number } | null = null;
|
||||||
|
let closestZ: { pos: THREE.Vector3, dist: number } | null = null;
|
||||||
|
|
||||||
|
for (const connectedPoint of connectedPoints) {
|
||||||
|
const cPos = new THREE.Vector3(...connectedPoint.position);
|
||||||
|
const xDist = Math.abs(newPos.x - cPos.x);
|
||||||
|
const zDist = Math.abs(newPos.z - cPos.z);
|
||||||
|
|
||||||
|
if (xDist < ANGLE_SNAP_DISTANCE_THRESHOLD) {
|
||||||
|
if (!closestX || xDist < closestX.dist) {
|
||||||
|
closestX = { pos: cPos, dist: xDist };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zDist < ANGLE_SNAP_DISTANCE_THRESHOLD) {
|
||||||
|
if (!closestZ || zDist < closestZ.dist) {
|
||||||
|
closestZ = { pos: cPos, dist: zDist };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const snappedPos = newPos.clone();
|
||||||
|
const snapSources: THREE.Vector3[] = [];
|
||||||
|
|
||||||
|
if (closestX) {
|
||||||
|
snappedPos.x = closestX.pos.x;
|
||||||
|
snapSources.push(closestX.pos.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (closestZ) {
|
||||||
|
snappedPos.z = closestZ.pos.z;
|
||||||
|
snapSources.push(closestZ.pos.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
const isSnapped = snapSources.length > 0;
|
||||||
|
|
||||||
|
return {
|
||||||
|
position: [snappedPos.x, snappedPos.y, snappedPos.z],
|
||||||
|
isSnapped,
|
||||||
|
snapSources
|
||||||
|
};
|
||||||
|
}, [currentPoint, getConnectedZonePoints]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
snapAislePoint,
|
snapAislePoint,
|
||||||
snapAisleAngle,
|
snapAisleAngle,
|
||||||
snapWallPoint,
|
snapWallPoint,
|
||||||
snapWallAngle,
|
snapWallAngle,
|
||||||
|
snapFloorPoint,
|
||||||
|
snapFloorAngle,
|
||||||
|
snapZonePoint,
|
||||||
|
snapZoneAngle,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -1,29 +1,42 @@
|
|||||||
import * as THREE from 'three';
|
import * as THREE from 'three';
|
||||||
import * as Constants from '../../../types/world/worldConstants';
|
import * as Constants from '../../../types/world/worldConstants';
|
||||||
import { useRef, useState, useEffect, useMemo } from 'react';
|
import { useRef, useState, useEffect, useMemo } from 'react';
|
||||||
import { useToolMode } from '../../../store/builder/store';
|
import { useSocketStore, useToolMode } from '../../../store/builder/store';
|
||||||
import { DragControls } from '@react-three/drei';
|
import { DragControls } from '@react-three/drei';
|
||||||
import { useThree } from '@react-three/fiber';
|
import { useThree } from '@react-three/fiber';
|
||||||
import { useBuilderStore } from '../../../store/builder/useBuilderStore';
|
import { useBuilderStore } from '../../../store/builder/useBuilderStore';
|
||||||
import { usePointSnapping } from './helpers/usePointSnapping';
|
import { usePointSnapping } from './helpers/usePointSnapping';
|
||||||
import { deleteAisleApi } from '../../../services/factoryBuilder/aisle/deleteAisleApi';
|
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import { createAisleApi } from '../../../services/factoryBuilder/aisle/createAisleApi';
|
|
||||||
import { useVersionContext } from '../version/versionContext';
|
import { useVersionContext } from '../version/versionContext';
|
||||||
import { useSceneContext } from '../../scene/sceneContext';
|
import { useSceneContext } from '../../scene/sceneContext';
|
||||||
|
|
||||||
|
import { upsertAisleApi } from '../../../services/factoryBuilder/aisle/upsertAisleApi';
|
||||||
|
import { deleteAisleApi } from '../../../services/factoryBuilder/aisle/deleteAisleApi';
|
||||||
|
// import { upsertWallApi } from '../../../services/factoryBuilder/wall/upsertWallApi';
|
||||||
|
// import { deleteWallApi } from '../../../services/factoryBuilder/wall/deleteWallApi';
|
||||||
|
// import { upsertFloorApi } from '../../../services/factoryBuilder/floor/upsertFloorApi';
|
||||||
|
// import { deleteFloorApi } from '../../../services/factoryBuilder/floor/deleteFloorApi';
|
||||||
|
// import { upsertZoneApi } from '../../../services/factoryBuilder/zone/upsertZoneApi';
|
||||||
|
// import { deleteZoneApi } from '../../../services/factoryBuilder/zone/deleteZoneApi';
|
||||||
|
|
||||||
|
import { getUserData } from '../../../functions/getUserData';
|
||||||
|
|
||||||
function Point({ point }: { readonly point: Point }) {
|
function Point({ point }: { readonly point: Point }) {
|
||||||
const materialRef = useRef<THREE.ShaderMaterial>(null);
|
const materialRef = useRef<THREE.ShaderMaterial>(null);
|
||||||
const { raycaster, camera, pointer, gl } = useThree();
|
const { raycaster, camera, pointer, gl } = useThree();
|
||||||
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
||||||
const [isHovered, setIsHovered] = useState(false);
|
const [isHovered, setIsHovered] = useState(false);
|
||||||
const [dragOffset, setDragOffset] = useState<THREE.Vector3 | null>(null);
|
const [dragOffset, setDragOffset] = useState<THREE.Vector3 | null>(null);
|
||||||
|
const { socket } = useSocketStore();
|
||||||
const { toolMode } = useToolMode();
|
const { toolMode } = useToolMode();
|
||||||
const { aisleStore, wallStore } = useSceneContext();
|
const { aisleStore, wallStore, floorStore, zoneStore } = useSceneContext();
|
||||||
const { setPosition: setAislePosition, removePoint: removeAislePoint, getAislesByPointId } = aisleStore();
|
const { setPosition: setAislePosition, removePoint: removeAislePoint, getAislesByPointId } = aisleStore();
|
||||||
const { setPosition: setWallPosition, removePoint: removeWallPoint } = wallStore();
|
const { setPosition: setWallPosition, removePoint: removeWallPoint, getWallsByPointId } = wallStore();
|
||||||
const { snapAislePoint, snapAisleAngle, snapWallPoint, snapWallAngle } = usePointSnapping({ uuid: point.pointUuid, pointType: point.pointType, position: point.position });
|
const { setPosition: setFloorPosition, removePoint: removeFloorPoint, getFloorsByPointId } = floorStore();
|
||||||
|
const { setPosition: setZonePosition, removePoint: removeZonePoint, getZonesByPointId } = zoneStore();
|
||||||
|
const { snapAislePoint, snapAisleAngle, snapWallPoint, snapWallAngle, snapFloorPoint, snapFloorAngle, snapZonePoint, snapZoneAngle } = usePointSnapping({ uuid: point.pointUuid, pointType: point.pointType, position: point.position });
|
||||||
const { hoveredPoint, setHoveredPoint } = useBuilderStore();
|
const { hoveredPoint, setHoveredPoint } = useBuilderStore();
|
||||||
|
const { userId, organization } = getUserData();
|
||||||
const { selectedVersionStore } = useVersionContext();
|
const { selectedVersionStore } = useVersionContext();
|
||||||
const { selectedVersion } = selectedVersionStore();
|
const { selectedVersion } = selectedVersionStore();
|
||||||
const { projectId } = useParams();
|
const { projectId } = useParams();
|
||||||
@@ -113,6 +126,14 @@ function Point({ point }: { readonly point: Point }) {
|
|||||||
const wallSnapped = snapWallAngle(newPosition);
|
const wallSnapped = snapWallAngle(newPosition);
|
||||||
const finalSnapped = snapWallPoint(wallSnapped.position);
|
const finalSnapped = snapWallPoint(wallSnapped.position);
|
||||||
setWallPosition(point.pointUuid, finalSnapped.position);
|
setWallPosition(point.pointUuid, finalSnapped.position);
|
||||||
|
} else if (point.pointType === 'Floor') {
|
||||||
|
const floorSnapped = snapFloorAngle(newPosition);
|
||||||
|
const finalSnapped = snapFloorPoint(floorSnapped.position);
|
||||||
|
setFloorPosition(point.pointUuid, finalSnapped.position);
|
||||||
|
} else if (point.pointType === 'Zone') {
|
||||||
|
const zoneSnapped = snapZoneAngle(newPosition);
|
||||||
|
const finalSnapped = snapZonePoint(zoneSnapped.position);
|
||||||
|
setZonePosition(point.pointUuid, finalSnapped.position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -138,11 +159,75 @@ function Point({ point }: { readonly point: Point }) {
|
|||||||
const updatedAisles = getAislesByPointId(point.pointUuid);
|
const updatedAisles = getAislesByPointId(point.pointUuid);
|
||||||
if (updatedAisles.length > 0 && projectId) {
|
if (updatedAisles.length > 0 && projectId) {
|
||||||
updatedAisles.forEach((updatedAisle) => {
|
updatedAisles.forEach((updatedAisle) => {
|
||||||
createAisleApi(updatedAisle.aisleUuid, updatedAisle.points, updatedAisle.type, projectId, selectedVersion?.versionId || '')
|
upsertAisleApi(updatedAisle.aisleUuid, updatedAisle.points, updatedAisle.type, projectId, selectedVersion?.versionId || '')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else if (point.pointType === 'Wall') {
|
} else if (point.pointType === 'Wall') {
|
||||||
// console.log('Wall after drag: ', point);
|
const updatedWalls = getWallsByPointId(point.pointUuid);
|
||||||
|
if (updatedWalls && updatedWalls.length > 0 && projectId) {
|
||||||
|
updatedWalls.forEach((updatedWall) => {
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// upsertWallApi(projectId, selectedVersion?.versionId || '', updatedWall);
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
wallData: updatedWall,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:model-Wall:add', data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (point.pointType === 'Floor') {
|
||||||
|
const updatedFloors = getFloorsByPointId(point.pointUuid);
|
||||||
|
if (updatedFloors && updatedFloors.length > 0 && projectId) {
|
||||||
|
updatedFloors.forEach((updatedFloor) => {
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// upsertFloorApi(projectId, selectedVersion?.versionId || '', updatedFloor);
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
floorData: updatedFloor,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:model-Floor:add', data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (point.pointType === 'Zone') {
|
||||||
|
const updatedZones = getZonesByPointId(point.pointUuid);
|
||||||
|
if (updatedZones && updatedZones.length > 0 && projectId) {
|
||||||
|
updatedZones.forEach((updatedZone) => {
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// upsertZoneApi(projectId, selectedVersion?.versionId || '', updatedZone);
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
zoneData: updatedZone,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:zone:add', data);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,16 +237,133 @@ function Point({ point }: { readonly point: Point }) {
|
|||||||
const removedAisles = removeAislePoint(point.pointUuid);
|
const removedAisles = removeAislePoint(point.pointUuid);
|
||||||
if (removedAisles.length > 0) {
|
if (removedAisles.length > 0) {
|
||||||
removedAisles.forEach(aisle => {
|
removedAisles.forEach(aisle => {
|
||||||
if (projectId)
|
if (projectId) {
|
||||||
deleteAisleApi(aisle.aisleUuid, projectId, selectedVersion?.versionId || '')
|
deleteAisleApi(aisle.aisleUuid, projectId, selectedVersion?.versionId || '')
|
||||||
|
}
|
||||||
});
|
});
|
||||||
setHoveredPoint(null);
|
setHoveredPoint(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (point.pointType === 'Wall') {
|
if (point.pointType === 'Wall') {
|
||||||
const removedAisles = removeWallPoint(point.pointUuid);
|
const removedWalls = removeWallPoint(point.pointUuid);
|
||||||
if (removedAisles.length > 0) {
|
if (removedWalls.length > 0) {
|
||||||
setHoveredPoint(null);
|
setHoveredPoint(null);
|
||||||
|
removedWalls.forEach(wall => {
|
||||||
|
if (projectId) {
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// deleteWallApi(projectId, selectedVersion?.versionId || '', wall.wallUuid);
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
wallUuid: wall.wallUuid,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:model-Wall:delete', data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (point.pointType === 'Floor') {
|
||||||
|
const { removedFloors, updatedFloors } = removeFloorPoint(point.pointUuid);
|
||||||
|
setHoveredPoint(null);
|
||||||
|
if (removedFloors.length > 0) {
|
||||||
|
removedFloors.forEach(floor => {
|
||||||
|
if (projectId) {
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// deleteFloorApi(projectId, selectedVersion?.versionId || '', floor.floorUuid);
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
floorUuid: floor.floorUuid,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:model-Floor:delete', data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (updatedFloors.length > 0) {
|
||||||
|
updatedFloors.forEach(floor => {
|
||||||
|
if (projectId) {
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// upsertFloorApi(projectId, selectedVersion?.versionId || '', floor);
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
floorData: floor,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:model-Floor:add', data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (point.pointType === 'Zone') {
|
||||||
|
const { removedZones, updatedZones } = removeZonePoint(point.pointUuid);
|
||||||
|
setHoveredPoint(null);
|
||||||
|
if (removedZones.length > 0) {
|
||||||
|
removedZones.forEach(zone => {
|
||||||
|
if (projectId) {
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// deleteZoneApi(projectId, selectedVersion?.versionId || '', zone.zoneUuid);
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
zoneUuid: zone.zoneUuid,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:zone:delete', data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (updatedZones.length > 0) {
|
||||||
|
updatedZones.forEach(zone => {
|
||||||
|
if (projectId) {
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// upsertZoneApi(projectId, selectedVersion?.versionId || '', zone);
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
zoneData: zone,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:zone:add', data);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gl.domElement.style.cursor = 'default';
|
gl.domElement.style.cursor = 'default';
|
||||||
|
|||||||
@@ -21,9 +21,17 @@ function ReferencePoint({ point }: { readonly point: Point }) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const pointName = point.pointType === 'Wall' ? 'Wall-Point' :
|
||||||
|
point.pointType === 'Floor' ? 'Floor-Point' :
|
||||||
|
point.pointType === 'Aisle' ? 'Aisle-Point' :
|
||||||
|
point.pointType === 'Zone' ? 'Zone-Point' : 'Point';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<mesh
|
<mesh
|
||||||
position={new THREE.Vector3(...point.position)}
|
position={new THREE.Vector3(...point.position)}
|
||||||
|
name={pointName}
|
||||||
|
uuid={point.pointUuid}
|
||||||
|
userData={point}
|
||||||
>
|
>
|
||||||
<boxGeometry args={boxScale} />
|
<boxGeometry args={boxScale} />
|
||||||
<shaderMaterial
|
<shaderMaterial
|
||||||
|
|||||||
@@ -85,9 +85,12 @@ export function useWallClassification(walls: Walls) {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const allCoords = mergedLineStrings.flatMap(ls => ls.geometry.coordinates);
|
||||||
|
const uniqueCoords = Array.from(new Set(allCoords.map(coord => coord.join(','))));
|
||||||
|
if (uniqueCoords.length < 4) return [];
|
||||||
|
|
||||||
const lineStrings = turf.featureCollection(mergedLineStrings);
|
const lineStrings = turf.featureCollection(mergedLineStrings);
|
||||||
|
|
||||||
// Now polygonize merged line strings
|
|
||||||
const polygons = turf.polygonize(lineStrings);
|
const polygons = turf.polygonize(lineStrings);
|
||||||
|
|
||||||
const rooms: Point[][] = [];
|
const rooms: Point[][] = [];
|
||||||
|
|||||||
@@ -1,20 +1,21 @@
|
|||||||
import * as THREE from 'three';
|
import * as THREE from 'three';
|
||||||
import { Base } from '@react-three/csg';
|
import { Base } from '@react-three/csg';
|
||||||
import { useMemo, useRef, useState } from 'react';
|
import { useMemo, useRef, useState } from 'react';
|
||||||
import { Decal, MeshDiscardMaterial } from '@react-three/drei';
|
import { MeshDiscardMaterial } from '@react-three/drei';
|
||||||
import { useFrame, useThree } from '@react-three/fiber';
|
import { useFrame, useThree } from '@react-three/fiber';
|
||||||
|
|
||||||
import defaultMaterial from '../../../../../assets/textures/floor/wall-tex.png';
|
|
||||||
import material1 from '../../../../../assets/textures/floor/factory wall texture.jpg';
|
|
||||||
|
|
||||||
import useModuleStore from '../../../../../store/useModuleStore';
|
import useModuleStore from '../../../../../store/useModuleStore';
|
||||||
import { useSceneContext } from '../../../../scene/sceneContext';
|
import { useSceneContext } from '../../../../scene/sceneContext';
|
||||||
import { useWallClassification } from './helpers/useWallClassification';
|
import { useWallClassification } from './helpers/useWallClassification';
|
||||||
import { useToggleView, useWallVisibility } from '../../../../../store/builder/store';
|
import { useToggleView, useWallVisibility } from '../../../../../store/builder/store';
|
||||||
import { useBuilderStore } from '../../../../../store/builder/useBuilderStore';
|
import { useBuilderStore } from '../../../../../store/builder/useBuilderStore';
|
||||||
import * as Constants from '../../../../../types/world/worldConstants';
|
import * as Constants from '../../../../../types/world/worldConstants';
|
||||||
|
|
||||||
import DecalInstance from '../../../Decal/decalInstance';
|
import DecalInstance from '../../../Decal/decalInstance';
|
||||||
|
|
||||||
|
import defaultMaterial from '../../../../../assets/textures/floor/wall-tex.png';
|
||||||
|
import material1 from '../../../../../assets/textures/floor/factory wall texture.jpg';
|
||||||
|
|
||||||
|
|
||||||
function Wall({ wall }: { readonly wall: Wall }) {
|
function Wall({ wall }: { readonly wall: Wall }) {
|
||||||
const { wallStore } = useSceneContext();
|
const { wallStore } = useSceneContext();
|
||||||
const { walls, addDecal } = wallStore();
|
const { walls, addDecal } = wallStore();
|
||||||
@@ -116,14 +117,16 @@ function Wall({ wall }: { readonly wall: Wall }) {
|
|||||||
</Base>
|
</Base>
|
||||||
<mesh
|
<mesh
|
||||||
castShadow
|
castShadow
|
||||||
|
receiveShadow
|
||||||
geometry={geometry}
|
geometry={geometry}
|
||||||
position={[centerX, centerY, centerZ]}
|
position={[centerX, centerY, centerZ]}
|
||||||
rotation={[0, -angle, 0]}
|
rotation={[0, -angle, 0]}
|
||||||
userData={wall}
|
userData={wall}
|
||||||
name={`WallReference_${wall.wallUuid}`}
|
name={`WallReference_${wall.wallUuid}`}
|
||||||
onClick={(e) => {
|
onDoubleClick={(e) => {
|
||||||
if (visible && !togglView && activeModule === 'builder') {
|
if (visible && !togglView && activeModule === 'builder') {
|
||||||
if (e.object.userData.wallUuid) {
|
if (e.object.userData.wallUuid) {
|
||||||
|
e.stopPropagation();
|
||||||
setSelectedWall(e.object);
|
setSelectedWall(e.object);
|
||||||
setSelectedDecal(null);
|
setSelectedDecal(null);
|
||||||
|
|
||||||
@@ -151,7 +154,7 @@ function Wall({ wall }: { readonly wall: Wall }) {
|
|||||||
<MeshDiscardMaterial />
|
<MeshDiscardMaterial />
|
||||||
|
|
||||||
{wall.decals.map((decal) => (
|
{wall.decals.map((decal) => (
|
||||||
<DecalInstance visible={visible} key={decal.decalUuid} decal={decal} />
|
<DecalInstance zPosition={wall.wallThickness / 2 + 0.001} visible={visible} key={decal.decalUuid} decal={decal} />
|
||||||
))}
|
))}
|
||||||
</mesh>
|
</mesh>
|
||||||
</mesh>
|
</mesh>
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user