diff --git a/app/src/modules/builder/builder.tsx b/app/src/modules/builder/builder.tsx
index 2a09bef..3f37de9 100644
--- a/app/src/modules/builder/builder.tsx
+++ b/app/src/modules/builder/builder.tsx
@@ -280,7 +280,7 @@ export default function Builder() {
plane={plane}
/>
-
+ {/* */}
diff --git a/app/src/modules/builder/geomentries/walls/loadWalls.ts b/app/src/modules/builder/geomentries/walls/loadWalls.ts
index d594e5a..14d72c4 100644
--- a/app/src/modules/builder/geomentries/walls/loadWalls.ts
+++ b/app/src/modules/builder/geomentries/walls/loadWalls.ts
@@ -121,9 +121,20 @@ async function loadWalls(
}
});
setWalls(Walls);
- }else{
+ } 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
\ No newline at end of file
diff --git a/app/src/modules/builder/groups/floorPlanGroup.tsx b/app/src/modules/builder/groups/floorPlanGroup.tsx
index 6859f74..74f0783 100644
--- a/app/src/modules/builder/groups/floorPlanGroup.tsx
+++ b/app/src/modules/builder/groups/floorPlanGroup.tsx
@@ -157,7 +157,7 @@ const FloorPlanGroup = ({ floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoin
}
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);
+ drawWall(raycaster, plane, floorPlanGroupPoint, snappedPoint, isSnapped, isSnappedUUID, line, ispreSnapped, anglesnappedPoint, isAngleSnapped, lines, floorPlanGroupLine, floorPlanGroup, ReferenceLineMesh, LineCreated, currentLayerPoint, dragPointControls, setNewLines, setDeletedLines, activeLayer, socket);
}
if (toolMode === "Floor") {
diff --git a/app/src/modules/builder/point/point.tsx b/app/src/modules/builder/point/point.tsx
index 0a79e7e..a2d17cd 100644
--- a/app/src/modules/builder/point/point.tsx
+++ b/app/src/modules/builder/point/point.tsx
@@ -8,6 +8,7 @@ import { useThree } from '@react-three/fiber';
import { useBuilderStore } from '../../../store/builder/useBuilderStore';
import { usePointSnapping } from './helpers/usePointSnapping';
import { useAislePointSnapping } from './helpers/useAisleDragSnap';
+import { useWallStore } from '../../../store/builder/useWallStore';
function Point({ point }: { readonly point: Point }) {
const materialRef = useRef(null);
@@ -15,7 +16,8 @@ function Point({ point }: { readonly point: Point }) {
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
const [isHovered, setIsHovered] = useState(false);
const { toolMode } = useToolMode();
- const { setPosition, removePoint } = useAisleStore();
+ const { setPosition: setAislePosition, removePoint: removeAislePoint } = useAisleStore();
+ const { setPosition: setWallPosition, removePoint: removeWallPoint } = useWallStore();
const { snapPosition } = useAislePointSnapping(point);
const { checkSnapForAisle } = usePointSnapping({ uuid: point.pointUuid, pointType: point.pointType, position: point.position });
const { hoveredPoint, setHoveredPoint } = useBuilderStore();
@@ -95,7 +97,13 @@ function Point({ point }: { readonly point: Point }) {
const aisleSnappedPosition = snapPosition(newPosition);
const finalSnappedPosition = checkSnapForAisle(aisleSnappedPosition.position);
- setPosition(point.pointUuid, finalSnappedPosition.position);
+ setAislePosition(point.pointUuid, finalSnappedPosition.position);
+ }
+ } else if (point.pointType === 'Wall') {
+ if (position) {
+ const newPosition: [number, number, number] = [position.x, position.y, position.z];
+
+ setWallPosition(point.pointUuid, newPosition);
}
}
}
@@ -109,7 +117,7 @@ function Point({ point }: { readonly point: Point }) {
const handlePointClick = (point: Point) => {
if (deletePointOrLine) {
if (point.pointType === 'Aisle') {
- const removedAisles = removePoint(point.pointUuid);
+ const removedAisles = removeAislePoint(point.pointUuid);
if (removedAisles.length > 0) {
setHoveredPoint(null);
}
diff --git a/app/src/modules/builder/wall/Instances/instance/helpers/useWallClassification.ts b/app/src/modules/builder/wall/Instances/instance/helpers/useWallClassification.ts
new file mode 100644
index 0000000..0e11aff
--- /dev/null
+++ b/app/src/modules/builder/wall/Instances/instance/helpers/useWallClassification.ts
@@ -0,0 +1,176 @@
+import { useMemo } from 'react';
+import * as THREE from 'three';
+import * as turf from '@turf/turf';
+
+export function useWallClassification(walls: Walls) {
+ // Find all rooms from the given walls
+ const findRooms = () => {
+ if (walls.length < 3) return [];
+
+ const pointMap = new Map();
+ const connections = new Map();
+
+ // Build connection graph
+ walls.forEach(wall => {
+ const [p1, p2] = wall.points;
+ if (!pointMap.has(p1.pointUuid)) pointMap.set(p1.pointUuid, p1);
+ if (!pointMap.has(p2.pointUuid)) pointMap.set(p2.pointUuid, p2);
+
+ if (!connections.has(p1.pointUuid)) connections.set(p1.pointUuid, []);
+ if (!connections.has(p2.pointUuid)) connections.set(p2.pointUuid, []);
+
+ connections.get(p1.pointUuid)?.push(p2.pointUuid);
+ connections.get(p2.pointUuid)?.push(p1.pointUuid);
+ });
+ console.log('connections: ', connections);
+
+ const visited = new Set();
+ const rooms: Point[][] = [];
+
+ // Modified DFS to find all possible cycles
+ const findAllCycles = (current: string, path: string[]) => {
+ visited.add(current);
+ path.push(current);
+
+ const neighbors = connections.get(current) || [];
+ for (const neighbor of neighbors) {
+ if (path.length > 2 && neighbor === path[0]) {
+ // Found a cycle (potential room)
+ const roomPoints = [...path, neighbor].map(uuid => pointMap.get(uuid)!);
+
+ // Check if this room is valid and not already found
+ if (isValidRoom(roomPoints) && !roomAlreadyExists(rooms, roomPoints)) {
+ rooms.push(roomPoints);
+ }
+ continue;
+ }
+
+ if (!path.includes(neighbor)) {
+ findAllCycles(neighbor, [...path]);
+ }
+ }
+ };
+
+ // Start from each point to find all possible cycles
+ for (const [pointUuid] of connections) {
+ if (!visited.has(pointUuid)) {
+ findAllCycles(pointUuid, []);
+ }
+ }
+
+ return rooms;
+ };
+
+ // Helper function to check if room is valid
+ const isValidRoom = (roomPoints: Point[]) => {
+ if (roomPoints.length < 4) return false;
+ const coordinates = roomPoints.map(p => [p.position[0], p.position[2]]);
+ const polygon = turf.polygon([coordinates]);
+ return turf.booleanValid(polygon);
+ };
+
+ // Helper function to check for duplicate rooms
+ const roomAlreadyExists = (existingRooms: Point[][], newRoom: Point[]) => {
+ const newRoomIds = newRoom.map(p => p.pointUuid).sort().join('-');
+ return existingRooms.some(room => {
+ const roomIds = room.map(p => p.pointUuid).sort().join('-');
+ return roomIds === newRoomIds;
+ });
+ };
+
+ const rooms = useMemo(() => findRooms(), [walls]);
+
+ // Modified to track all rooms a wall belongs to
+ const getWallOrientation = (wall: Wall) => {
+ const [p1, p2] = wall.points;
+ const orientations: Array<{ isOutsideFacing: boolean }> = [];
+
+ for (const room of rooms) {
+ for (let i = 0; i < room.length - 1; i++) {
+ const roomP1 = room[i];
+ const roomP2 = room[i + 1];
+
+ // Check both directions
+ if ((p1.pointUuid === roomP1.pointUuid && p2.pointUuid === roomP2.pointUuid) ||
+ (p1.pointUuid === roomP2.pointUuid && p2.pointUuid === roomP1.pointUuid)) {
+
+ const roomPoints = room.map(p => new THREE.Vector3(p.position[0], 0, p.position[2]));
+ const centroid = new THREE.Vector3();
+ roomPoints.forEach(p => centroid.add(p));
+ centroid.divideScalar(roomPoints.length);
+
+ const wallVector = new THREE.Vector3(
+ p2.position[0] - p1.position[0],
+ 0,
+ p2.position[2] - p1.position[2]
+ );
+
+ // Normal depends on wall direction
+ let normal = new THREE.Vector3(-wallVector.z, 0, wallVector.x).normalize();
+ if (p1.pointUuid === roomP2.pointUuid) {
+ normal = new THREE.Vector3(wallVector.z, 0, -wallVector.x).normalize();
+ }
+
+ const testPoint = new THREE.Vector3(
+ (p1.position[0] + p2.position[0]) / 2 + normal.x,
+ 0,
+ (p1.position[2] + p2.position[2]) / 2 + normal.z
+ );
+
+ const pointInside = turf.booleanPointInPolygon(
+ turf.point([testPoint.x, testPoint.z]),
+ turf.polygon([room.map(p => [p.position[0], p.position[2]])])
+ );
+
+ orientations.push({
+ isOutsideFacing: !pointInside
+ });
+ }
+ }
+ }
+
+ return {
+ isRoomWall: orientations.length > 0,
+ orientations // Now tracks all orientations for walls in multiple rooms
+ };
+ };
+
+ const getWallMaterialSide = (wall: Wall) => {
+ const orientation = getWallOrientation(wall);
+
+ if (!orientation.isRoomWall) {
+ return { front: 'inside', back: 'inside' }; // Both sides same for segment walls
+ }
+
+ // For walls in multiple rooms, we need to determine which side faces which room
+ if (orientation.orientations.length === 2) {
+ // Wall is between two rooms - one side faces each room's interior
+ return {
+ front: 'inside',
+ back: 'inside'
+ };
+ } else if (orientation.orientations.length === 1) {
+ // Wall is part of only one room (exterior wall)
+ return orientation.orientations[0].isOutsideFacing
+ ? { front: 'outside', back: 'inside' }
+ : { front: 'inside', back: 'outside' };
+ }
+
+ // Default case (shouldn't normally happen)
+ return { front: 'inside', back: 'inside' };
+ };
+
+ // Rest of the functions remain the same
+ const getWallType = (wall: Wall) => getWallOrientation(wall).isRoomWall ? 'room' : 'segment';
+ const isRoomWall = (wall: Wall) => getWallOrientation(wall).isRoomWall;
+ const isSegmentWall = (wall: Wall) => !getWallOrientation(wall).isRoomWall;
+
+ return {
+ rooms,
+ getWallType,
+ isRoomWall,
+ isSegmentWall,
+ getWallMaterialSide,
+ findRooms,
+ };
+}
\ No newline at end of file
diff --git a/app/src/modules/builder/wall/Instances/instance/helpers/useWallGeometry.ts b/app/src/modules/builder/wall/Instances/instance/helpers/useWallGeometry.ts
new file mode 100644
index 0000000..29341d6
--- /dev/null
+++ b/app/src/modules/builder/wall/Instances/instance/helpers/useWallGeometry.ts
@@ -0,0 +1,64 @@
+import * as THREE from 'three';
+import { useMemo } from 'react';
+
+function useWallGeometry(wallLength: number, wallHeight: number, wallThickness: number) {
+ return useMemo(() => {
+ const geometry = new THREE.BufferGeometry();
+
+ const halfLength = wallLength / 2;
+ const halfThickness = wallThickness / 2;
+ const height = wallHeight;
+
+ const vertices = [
+ -halfLength, -height / 2, halfThickness,
+ -halfLength, height / 2, halfThickness,
+ halfLength, height / 2, halfThickness,
+ halfLength, -height / 2, halfThickness,
+ -halfLength, -height / 2, -halfThickness,
+ -halfLength, height / 2, -halfThickness,
+ halfLength, height / 2, -halfThickness,
+ halfLength, -height / 2, -halfThickness,
+ -halfLength, height / 2, halfThickness,
+ -halfLength, height / 2, -halfThickness,
+ halfLength, height / 2, -halfThickness,
+ halfLength, height / 2, halfThickness,
+ -halfLength, -height / 2, halfThickness,
+ -halfLength, -height / 2, -halfThickness,
+ halfLength, -height / 2, -halfThickness,
+ halfLength, -height / 2, halfThickness,
+ ];
+
+ const indices = [
+ 0, 1, 2, 0, 2, 3,
+ 4, 6, 5, 4, 7, 6,
+ 0, 4, 5, 0, 5, 1,
+ 3, 2, 6, 3, 6, 7,
+ 8, 9, 10, 8, 10, 11,
+ 12, 14, 13, 12, 15, 14
+ ];
+
+ geometry.setIndex(indices);
+ geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
+ geometry.setAttribute('uv', new THREE.Float32BufferAttribute([
+ 0, 0, 0, 1, 1, 1, 1, 0,
+ 0, 0, 0, 1, 1, 1, 1, 0,
+ 0, 0, 0, 1, 1, 1, 1, 0,
+ 0, 0, 0, 1, 1, 1, 1, 0,
+ 0, 0, 0, 1, 1, 1, 1, 0,
+ 0, 0, 0, 1, 1, 1, 1, 0
+ ], 2));
+
+ geometry.computeVertexNormals();
+
+ geometry.addGroup(0, 6, 0); // Front
+ geometry.addGroup(6, 6, 1); // Back
+ geometry.addGroup(12, 6, 2); // Left
+ geometry.addGroup(18, 6, 3); // Right
+ geometry.addGroup(24, 6, 4); // Top
+ geometry.addGroup(30, 6, 5); // Bottom
+
+ return geometry;
+ }, [wallLength, wallHeight, wallThickness]);
+}
+
+export default useWallGeometry;
\ No newline at end of file
diff --git a/app/src/modules/builder/wall/Instances/instance/wall.tsx b/app/src/modules/builder/wall/Instances/instance/wall.tsx
new file mode 100644
index 0000000..1dea961
--- /dev/null
+++ b/app/src/modules/builder/wall/Instances/instance/wall.tsx
@@ -0,0 +1,92 @@
+import * as THREE from 'three';
+import { useMemo } from 'react';
+import * as Constants from '../../../../../types/world/worldConstants';
+
+import insideMaterial from '../../../../../assets/textures/floor/wall-tex.png';
+import outsideMaterial from '../../../../../assets/textures/floor/factory wall texture.jpg';
+import useWallGeometry from './helpers/useWallGeometry';
+import { useWallStore } from '../../../../../store/builder/useWallStore';
+import { useWallClassification } from './helpers/useWallClassification';
+
+function Wall({ wall }: { readonly wall: Wall }) {
+ const { walls } = useWallStore();
+ const { getWallMaterialSide, isRoomWall, rooms } = useWallClassification(walls);
+ console.log('rooms: ', rooms);
+ const materialSide = getWallMaterialSide(wall);
+ const [startPoint, endPoint] = wall.points;
+
+ const startX = startPoint.position[0];
+ const startZ = startPoint.position[2];
+ const endX = endPoint.position[0];
+ const endZ = endPoint.position[2];
+
+ const wallLength = Math.sqrt((endX - startX) ** 2 + (endZ - startZ) ** 2);
+ const angle = Math.atan2(endZ - startZ, endX - startX);
+
+ const centerX = (startX + endX) / 2;
+ const centerZ = (startZ + endZ) / 2;
+ const centerY = wall.wallHeight / 2;
+
+ const textureLoader = new THREE.TextureLoader();
+
+ const [insideWallTexture, outsideWallTexture] = useMemo(() => {
+ const inside = textureLoader.load(insideMaterial);
+ inside.wrapS = inside.wrapT = THREE.RepeatWrapping;
+ inside.repeat.set(wallLength / 10, wall.wallHeight / 10);
+ inside.colorSpace = THREE.SRGBColorSpace;
+
+ const outside = textureLoader.load(outsideMaterial);
+ outside.wrapS = outside.wrapT = THREE.RepeatWrapping;
+ outside.repeat.set(wallLength / 10, wall.wallHeight / 10);
+ outside.colorSpace = THREE.SRGBColorSpace;
+
+ return [inside, outside];
+ }, [wallLength, wall.wallHeight, textureLoader]);
+
+ const materials = useMemo(() => {
+ // For segment walls (not in a room), use inside material on both sides
+ const frontMaterial = isRoomWall(wall)
+ ? (materialSide.front === 'inside' ? insideWallTexture : outsideWallTexture)
+ : insideWallTexture;
+
+ const backMaterial = isRoomWall(wall)
+ ? (materialSide.back === 'inside' ? insideWallTexture : outsideWallTexture)
+ : insideWallTexture;
+
+ return [
+ new THREE.MeshStandardMaterial({
+ color: Constants.wallConfig.defaultColor,
+ side: THREE.DoubleSide,
+ map: frontMaterial
+ }),
+ new THREE.MeshStandardMaterial({
+ color: Constants.wallConfig.defaultColor,
+ side: THREE.DoubleSide,
+ map: backMaterial
+ }),
+ new THREE.MeshStandardMaterial({ color: Constants.wallConfig.defaultColor, side: THREE.DoubleSide }), // Left
+ new THREE.MeshStandardMaterial({ color: Constants.wallConfig.defaultColor, side: THREE.DoubleSide }), // Right
+ new THREE.MeshStandardMaterial({ color: Constants.wallConfig.defaultColor, side: THREE.DoubleSide }), // Top
+ new THREE.MeshStandardMaterial({ color: Constants.wallConfig.defaultColor, side: THREE.DoubleSide }) // Bottom
+ ];
+ }, [insideWallTexture, outsideWallTexture, materialSide, isRoomWall, wall]);
+
+ const geometry = useWallGeometry(wallLength, wall.wallHeight, wall.wallThickness);
+
+ return (
+
+
+ {materials.map((material, index) => (
+
+ ))}
+
+
+ );
+}
+
+export default Wall;
\ No newline at end of file
diff --git a/app/src/modules/builder/wall/Instances/instance/wallInstance.tsx b/app/src/modules/builder/wall/Instances/instance/wallInstance.tsx
index f31f3c2..53b6ecd 100644
--- a/app/src/modules/builder/wall/Instances/instance/wallInstance.tsx
+++ b/app/src/modules/builder/wall/Instances/instance/wallInstance.tsx
@@ -1,18 +1,13 @@
-import Line from '../../../line/line'
-import Point from '../../../point/point';
-import { useToggleView } from '../../../../../store/builder/store';
+import { useToggleView } from "../../../../../store/builder/store";
+import Wall from "./wall"
function WallInstance({ wall }: { readonly wall: Wall }) {
const { toggleView } = useToggleView();
return (
<>
- {toggleView && (
- <>
-
-
-
- >
+ {!toggleView && (
+
)}
>
)
diff --git a/app/src/modules/builder/wall/Instances/wallInstances.tsx b/app/src/modules/builder/wall/Instances/wallInstances.tsx
index b9c5499..41beaa0 100644
--- a/app/src/modules/builder/wall/Instances/wallInstances.tsx
+++ b/app/src/modules/builder/wall/Instances/wallInstances.tsx
@@ -1,9 +1,14 @@
-import { useEffect } from 'react';
+import React, { useEffect } from 'react';
import { useWallStore } from '../../../../store/builder/useWallStore'
import WallInstance from './instance/wallInstance';
+import Line from '../../line/line';
+import Point from '../../point/point';
+import { useToggleView } from '../../../../store/builder/store';
+import { Geometry } from '@react-three/csg';
function WallInstances() {
const { walls } = useWallStore();
+ const { toggleView } = useToggleView();
useEffect(() => {
// console.log('walls: ', walls);
@@ -11,9 +16,25 @@ function WallInstances() {
return (
<>
- {walls.map((wall) => (
-
- ))}
+
+
+ {walls.map((wall) => (
+
+ ))}
+
+
+
+ {toggleView && (
+ <>
+ {walls.map((wall) => (
+
+
+
+
+
+ ))}
+ >
+ )}
>
)
}
diff --git a/app/src/store/builder/useBuilderStore.ts b/app/src/store/builder/useBuilderStore.ts
index 29f1753..245bf1d 100644
--- a/app/src/store/builder/useBuilderStore.ts
+++ b/app/src/store/builder/useBuilderStore.ts
@@ -80,7 +80,7 @@ export const useBuilderStore = create()(
// Wall
- wallThickness: 2,
+ wallThickness: 0.1,
wallHeight: 7,
setWallThickness: (thickness: number) => {