Enhance builder functionality by implementing drag-and-drop for lines and points, adding hover effects, and improving wall distance display in the UI.
This commit is contained in:
@@ -48,14 +48,11 @@ function AisleInstances() {
|
|||||||
|
|
||||||
{toggleView &&
|
{toggleView &&
|
||||||
<Html
|
<Html
|
||||||
// data
|
|
||||||
key={`${aisle.points[0].pointUuid}_${aisle.points[1].pointUuid}`}
|
key={`${aisle.points[0].pointUuid}_${aisle.points[1].pointUuid}`}
|
||||||
userData={aisle}
|
userData={aisle}
|
||||||
position={[textPosition.x, 1, textPosition.z]}
|
position={[textPosition.x, 1, textPosition.z]}
|
||||||
// class
|
|
||||||
wrapperClass="distance-text-wrapper"
|
wrapperClass="distance-text-wrapper"
|
||||||
className="distance-text"
|
className="distance-text"
|
||||||
// other
|
|
||||||
zIndexRange={[1, 0]}
|
zIndexRange={[1, 0]}
|
||||||
prepend
|
prepend
|
||||||
sprite
|
sprite
|
||||||
@@ -68,7 +65,6 @@ function AisleInstances() {
|
|||||||
</div>
|
</div>
|
||||||
</Html>
|
</Html>
|
||||||
}
|
}
|
||||||
|
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ export default function Builder() {
|
|||||||
const { setWalls } = useWalls();
|
const { setWalls } = useWalls();
|
||||||
const { refTextupdate, setRefTextUpdate } = useRefTextUpdate();
|
const { refTextupdate, setRefTextUpdate } = useRefTextUpdate();
|
||||||
const { projectId } = useParams();
|
const { projectId } = useParams();
|
||||||
const { setHoveredPoint } = useBuilderStore();
|
const { setHoveredPoint, setHoveredLine } = useBuilderStore();
|
||||||
const { userId, organization } = getUserData();
|
const { userId, organization } = getUserData();
|
||||||
|
|
||||||
// const loader = new GLTFLoader();
|
// const loader = new GLTFLoader();
|
||||||
@@ -127,7 +127,9 @@ export default function Builder() {
|
|||||||
dragPointControls
|
dragPointControls
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
setHoveredLine(null);
|
||||||
setHoveredPoint(null);
|
setHoveredPoint(null);
|
||||||
|
state.gl.domElement.style.cursor = 'default';
|
||||||
setToolMode('cursor');
|
setToolMode('cursor');
|
||||||
loadWalls(lines, setWalls);
|
loadWalls(lines, setWalls);
|
||||||
setUpdateScene(true);
|
setUpdateScene(true);
|
||||||
|
|||||||
@@ -384,13 +384,7 @@ const ZoneGroup: React.FC = () => {
|
|||||||
drag = true;
|
drag = true;
|
||||||
}
|
}
|
||||||
raycaster.setFromCamera(pointer, camera);
|
raycaster.setFromCamera(pointer, camera);
|
||||||
const intersects = raycaster.intersectObjects(groupsRef.current.children, true);
|
|
||||||
|
|
||||||
if (intersects.length > 0 && intersects[0].object.name.includes("point")) {
|
|
||||||
gl.domElement.style.cursor = toolMode === "move" ? "pointer" : "default";
|
|
||||||
} else {
|
|
||||||
gl.domElement.style.cursor = "default";
|
|
||||||
}
|
|
||||||
if (isDragging && draggedSphere) {
|
if (isDragging && draggedSphere) {
|
||||||
raycaster.setFromCamera(pointer, camera);
|
raycaster.setFromCamera(pointer, camera);
|
||||||
const intersectionPoint = new THREE.Vector3();
|
const intersectionPoint = new THREE.Vector3();
|
||||||
|
|||||||
@@ -1,13 +1,26 @@
|
|||||||
import * as THREE from 'three';
|
import * as THREE from 'three';
|
||||||
import { useMemo } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import * as Constants from '../../../types/world/worldConstants';
|
import * as Constants from '../../../types/world/worldConstants';
|
||||||
import { Tube } from '@react-three/drei';
|
import { DragControls, Tube } from '@react-three/drei';
|
||||||
|
import { useToolMode } from '../../../store/builder/store';
|
||||||
|
import { useBuilderStore } from '../../../store/builder/useBuilderStore';
|
||||||
|
import { useWallStore } from '../../../store/builder/useWallStore';
|
||||||
|
import { useThree } from '@react-three/fiber';
|
||||||
|
|
||||||
interface LineProps {
|
interface LineProps {
|
||||||
points: [Point, Point];
|
points: [Point, Point];
|
||||||
}
|
}
|
||||||
|
|
||||||
function Line({ points }: Readonly<LineProps>) {
|
function Line({ points }: Readonly<LineProps>) {
|
||||||
|
const [isHovered, setIsHovered] = useState(false);
|
||||||
|
const { raycaster, camera, pointer, gl } = useThree();
|
||||||
|
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
||||||
|
const [isDeletable, setIsDeletable] = useState(false);
|
||||||
|
const { toolMode } = useToolMode();
|
||||||
|
const { removeWallByPoints, setPosition } = useWallStore();
|
||||||
|
const [dragOffset, setDragOffset] = useState<THREE.Vector3 | null>(null);
|
||||||
|
const { hoveredLine, setHoveredLine, hoveredPoint } = useBuilderStore();
|
||||||
|
|
||||||
const path = useMemo(() => {
|
const path = useMemo(() => {
|
||||||
const [start, end] = points.map(p => new THREE.Vector3(...p.position));
|
const [start, end] = points.map(p => new THREE.Vector3(...p.position));
|
||||||
return new THREE.LineCurve3(start, end);
|
return new THREE.LineCurve3(start, end);
|
||||||
@@ -44,16 +57,119 @@ function Line({ points }: Readonly<LineProps>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (toolMode === '2D-Delete') {
|
||||||
|
if (isHovered && !hoveredPoint) {
|
||||||
|
setIsDeletable(true);
|
||||||
|
} else {
|
||||||
|
setIsDeletable(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setIsDeletable(false);
|
||||||
|
}
|
||||||
|
}, [isHovered, colors.defaultLineColor, colors.defaultDeleteColor, toolMode, hoveredPoint]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (hoveredLine && (hoveredLine[0].pointUuid !== points[0].pointUuid || hoveredLine[1].pointUuid !== points[1].pointUuid)) {
|
||||||
|
setIsHovered(false);
|
||||||
|
}
|
||||||
|
}, [hoveredLine])
|
||||||
|
|
||||||
|
const handlePointClick = (points: [Point, Point]) => {
|
||||||
|
if (toolMode === '2D-Delete') {
|
||||||
|
if (points[0].pointType === 'Wall' && points[1].pointType === 'Wall') {
|
||||||
|
removeWallByPoints(points);
|
||||||
|
}
|
||||||
|
gl.domElement.style.cursor = 'default';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDrag = (points: [Point, Point]) => {
|
||||||
|
if (toolMode === 'move' && isHovered && dragOffset) {
|
||||||
|
raycaster.setFromCamera(pointer, camera);
|
||||||
|
const intersectionPoint = new THREE.Vector3();
|
||||||
|
const hit = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
||||||
|
|
||||||
|
if (hit) {
|
||||||
|
gl.domElement.style.cursor = 'move';
|
||||||
|
const positionWithOffset = new THREE.Vector3().addVectors(hit, dragOffset);
|
||||||
|
|
||||||
|
const start = new THREE.Vector3(...points[0].position);
|
||||||
|
const end = new THREE.Vector3(...points[1].position);
|
||||||
|
const midPoint = new THREE.Vector3().addVectors(start, end).multiplyScalar(0.5);
|
||||||
|
|
||||||
|
const delta = new THREE.Vector3().subVectors(positionWithOffset, midPoint);
|
||||||
|
|
||||||
|
const newStart = new THREE.Vector3().addVectors(start, delta);
|
||||||
|
const newEnd = new THREE.Vector3().addVectors(end, delta);
|
||||||
|
|
||||||
|
setPosition(points[0].pointUuid, [newStart.x, newStart.y, newStart.z]);
|
||||||
|
setPosition(points[1].pointUuid, [newEnd.x, newEnd.y, newEnd.z]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDragStart = (points: [Point, Point]) => {
|
||||||
|
raycaster.setFromCamera(pointer, camera);
|
||||||
|
const intersectionPoint = new THREE.Vector3();
|
||||||
|
const hit = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
||||||
|
|
||||||
|
if (hit && !hoveredPoint) {
|
||||||
|
const start = new THREE.Vector3(...points[0].position);
|
||||||
|
const end = new THREE.Vector3(...points[1].position);
|
||||||
|
const midPoint = new THREE.Vector3().addVectors(start, end).multiplyScalar(0.5);
|
||||||
|
|
||||||
|
const offset = new THREE.Vector3().subVectors(midPoint, hit);
|
||||||
|
setDragOffset(offset);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDragEnd = (points: [Point, Point]) => {
|
||||||
|
gl.domElement.style.cursor = 'default';
|
||||||
|
setDragOffset(null);
|
||||||
|
if (toolMode !== 'move') return;
|
||||||
|
if (points[0].pointType === 'Wall' && points[1].pointType === 'Wall') {
|
||||||
|
// console.log('Wall after drag: ', points);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<DragControls
|
||||||
|
axisLock="y"
|
||||||
|
autoTransform={false}
|
||||||
|
onDragStart={() => handleDragStart(points)}
|
||||||
|
onDrag={() => handleDrag(points)}
|
||||||
|
onDragEnd={() => handleDragEnd(points)}
|
||||||
|
>
|
||||||
<Tube
|
<Tube
|
||||||
name={`${points[0].pointType}-Line`}
|
name={`${points[0].pointType}-Line`}
|
||||||
key={`${points[0].pointUuid}-${points[1].pointUuid}`}
|
key={`${points[0].pointUuid}-${points[1].pointUuid}`}
|
||||||
uuid={`${points[0].pointUuid}-${points[1].pointUuid}`}
|
uuid={`${points[0].pointUuid}-${points[1].pointUuid}`}
|
||||||
userData={{ points, path }}
|
userData={{ points, path }}
|
||||||
args={[path, Constants.lineConfig.tubularSegments, Constants.lineConfig.radius, Constants.lineConfig.radialSegments, false]}
|
args={[path, Constants.lineConfig.tubularSegments, Constants.lineConfig.radius, Constants.lineConfig.radialSegments, false]}
|
||||||
|
onClick={() => {
|
||||||
|
handlePointClick(points);
|
||||||
|
}}
|
||||||
|
onPointerOver={() => {
|
||||||
|
if (!hoveredLine) {
|
||||||
|
setHoveredLine(points);
|
||||||
|
setIsHovered(true)
|
||||||
|
if (toolMode === 'move' && !hoveredPoint) {
|
||||||
|
gl.domElement.style.cursor = 'pointer';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onPointerOut={() => {
|
||||||
|
if (hoveredLine) {
|
||||||
|
setHoveredLine(null);
|
||||||
|
gl.domElement.style.cursor = 'default';
|
||||||
|
}
|
||||||
|
setIsHovered(false)
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<meshStandardMaterial color={colors.defaultLineColor} />
|
<meshStandardMaterial color={isDeletable ? colors.defaultDeleteColor : colors.defaultLineColor} />
|
||||||
</Tube>
|
</Tube>
|
||||||
|
</DragControls >
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,9 +15,10 @@ import { useSceneContext } from '../../scene/sceneContext';
|
|||||||
|
|
||||||
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 } = 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 { toolMode } = useToolMode();
|
const { toolMode } = useToolMode();
|
||||||
const { aisleStore } = useSceneContext();
|
const { aisleStore } = useSceneContext();
|
||||||
const { setPosition: setAislePosition, removePoint: removeAislePoint, getAislesByPointId } = aisleStore();
|
const { setPosition: setAislePosition, removePoint: removeAislePoint, getAislesByPointId } = aisleStore();
|
||||||
@@ -91,33 +92,45 @@ function Point({ point }: { readonly point: Point }) {
|
|||||||
}), [colors.defaultInnerColor, colors.defaultOuterColor]);
|
}), [colors.defaultInnerColor, colors.defaultOuterColor]);
|
||||||
|
|
||||||
const handleDrag = (point: Point) => {
|
const handleDrag = (point: Point) => {
|
||||||
if (toolMode === 'move' && isHovered) {
|
if (toolMode === 'move' && isHovered && dragOffset) {
|
||||||
raycaster.setFromCamera(pointer, camera);
|
raycaster.setFromCamera(pointer, camera);
|
||||||
const intersectionPoint = new THREE.Vector3();
|
const intersectionPoint = new THREE.Vector3();
|
||||||
const position = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
const hit = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
||||||
|
|
||||||
|
if (hit) {
|
||||||
|
gl.domElement.style.cursor = 'move';
|
||||||
|
const positionWithOffset = new THREE.Vector3().addVectors(hit, dragOffset);
|
||||||
|
const newPosition: [number, number, number] = [positionWithOffset.x, positionWithOffset.y, positionWithOffset.z];
|
||||||
|
|
||||||
if (point.pointType === 'Aisle') {
|
if (point.pointType === 'Aisle') {
|
||||||
if (position) {
|
const aisleSnapped = snapAisleAngle(newPosition);
|
||||||
const newPosition: [number, number, number] = [position.x, position.y, position.z];
|
const finalSnapped = snapAislePoint(aisleSnapped.position);
|
||||||
const aisleSnappedPosition = snapAisleAngle(newPosition);
|
setAislePosition(point.pointUuid, finalSnapped.position);
|
||||||
const finalSnappedPosition = snapAislePoint(aisleSnappedPosition.position);
|
|
||||||
|
|
||||||
setAislePosition(point.pointUuid, finalSnappedPosition.position);
|
|
||||||
|
|
||||||
}
|
|
||||||
} else if (point.pointType === 'Wall') {
|
} else if (point.pointType === 'Wall') {
|
||||||
if (position) {
|
const wallSnapped = snapWallAngle(newPosition);
|
||||||
const newPosition: [number, number, number] = [position.x, position.y, position.z];
|
const finalSnapped = snapWallPoint(wallSnapped.position);
|
||||||
const wallSnappedPosition = snapWallAngle(newPosition);
|
setWallPosition(point.pointUuid, finalSnapped.position);
|
||||||
const finalSnappedPosition = snapWallPoint(wallSnappedPosition.position);
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
setWallPosition(point.pointUuid, finalSnappedPosition.position);
|
const handleDragStart = (point: Point) => {
|
||||||
}
|
raycaster.setFromCamera(pointer, camera);
|
||||||
}
|
const intersectionPoint = new THREE.Vector3();
|
||||||
}
|
const hit = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
||||||
|
|
||||||
|
if (hit) {
|
||||||
|
const currentPosition = new THREE.Vector3(...point.position);
|
||||||
|
const offset = new THREE.Vector3().subVectors(currentPosition, hit);
|
||||||
|
setDragOffset(offset);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleDragEnd = (point: Point) => {
|
const handleDragEnd = (point: Point) => {
|
||||||
if (toolMode === '2D-Delete') return;
|
gl.domElement.style.cursor = 'default';
|
||||||
|
setDragOffset(null);
|
||||||
|
if (toolMode !== 'move') return;
|
||||||
if (point.pointType === 'Aisle') {
|
if (point.pointType === 'Aisle') {
|
||||||
const updatedAisles = getAislesByPointId(point.pointUuid);
|
const updatedAisles = getAislesByPointId(point.pointUuid);
|
||||||
if (updatedAisles.length > 0 && projectId) {
|
if (updatedAisles.length > 0 && projectId) {
|
||||||
@@ -148,6 +161,7 @@ function Point({ point }: { readonly point: Point }) {
|
|||||||
setHoveredPoint(null);
|
setHoveredPoint(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
gl.domElement.style.cursor = 'default';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,8 +179,9 @@ function Point({ point }: { readonly point: Point }) {
|
|||||||
<DragControls
|
<DragControls
|
||||||
axisLock='y'
|
axisLock='y'
|
||||||
autoTransform={false}
|
autoTransform={false}
|
||||||
onDrag={() => { handleDrag(point) }}
|
onDragStart={() => handleDragStart(point)}
|
||||||
onDragEnd={() => { handleDragEnd(point) }}
|
onDrag={() => handleDrag(point)}
|
||||||
|
onDragEnd={() => handleDragEnd(point)}
|
||||||
>
|
>
|
||||||
<mesh
|
<mesh
|
||||||
key={point.pointUuid}
|
key={point.pointUuid}
|
||||||
@@ -179,12 +194,16 @@ function Point({ point }: { readonly point: Point }) {
|
|||||||
onPointerOver={() => {
|
onPointerOver={() => {
|
||||||
if (!hoveredPoint) {
|
if (!hoveredPoint) {
|
||||||
setHoveredPoint(point);
|
setHoveredPoint(point);
|
||||||
setIsHovered(true)
|
setIsHovered(true);
|
||||||
|
if (toolMode === 'move') {
|
||||||
|
gl.domElement.style.cursor = 'pointer';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onPointerOut={() => {
|
onPointerOut={() => {
|
||||||
if (hoveredPoint) {
|
if (hoveredPoint) {
|
||||||
setHoveredPoint(null);
|
setHoveredPoint(null);
|
||||||
|
gl.domElement.style.cursor = 'default';
|
||||||
}
|
}
|
||||||
setIsHovered(false)
|
setIsHovered(false)
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import React, { useEffect, useMemo, useRef } from 'react';
|
import React, { useEffect, useMemo } from 'react';
|
||||||
import { useWallStore } from '../../../../store/builder/useWallStore'
|
import { useWallStore } from '../../../../store/builder/useWallStore'
|
||||||
import WallInstance from './instance/wallInstance';
|
import WallInstance from './instance/wallInstance';
|
||||||
import Line from '../../line/line';
|
import Line from '../../line/line';
|
||||||
import Point from '../../point/point';
|
import Point from '../../point/point';
|
||||||
import { useToggleView } from '../../../../store/builder/store';
|
import { useToggleView } from '../../../../store/builder/store';
|
||||||
import { Geometry } from '@react-three/csg';
|
import { Geometry } from '@react-three/csg';
|
||||||
|
import { Vector3 } from 'three';
|
||||||
|
import { Html } from '@react-three/drei';
|
||||||
|
|
||||||
function WallInstances() {
|
function WallInstances() {
|
||||||
const { walls } = useWallStore();
|
const { walls } = useWallStore();
|
||||||
@@ -34,21 +36,12 @@ function WallInstances() {
|
|||||||
<>
|
<>
|
||||||
|
|
||||||
{!toggleView && (
|
{!toggleView && (
|
||||||
|
|
||||||
<mesh name='Walls-Group'>
|
<mesh name='Walls-Group'>
|
||||||
{/* <Base name="base" geometry={box} scale={[3, 3, 3]} /> */}
|
|
||||||
|
|
||||||
<Geometry useGroups>
|
<Geometry useGroups>
|
||||||
{walls.map((wall) => (
|
{walls.map((wall) => (
|
||||||
<WallInstance key={wall.wallUuid} wall={wall} />
|
<WallInstance key={wall.wallUuid} wall={wall} />
|
||||||
))}
|
))}
|
||||||
</Geometry>
|
</Geometry>
|
||||||
|
|
||||||
{/* <Subtraction rotation={[0, Math.PI / 2, 0]} position={[-1.425, -0.45, 0]} scale={[1, 3, 1]}>
|
|
||||||
<Geometry>
|
|
||||||
<Base geometry={box} />
|
|
||||||
</Geometry>
|
|
||||||
</Subtraction> */}
|
|
||||||
</mesh>
|
</mesh>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -61,11 +54,42 @@ function WallInstances() {
|
|||||||
</group>
|
</group>
|
||||||
|
|
||||||
<group name='Wall-Lines-Group'>
|
<group name='Wall-Lines-Group'>
|
||||||
|
|
||||||
{walls.map((wall) => (
|
{walls.map((wall) => (
|
||||||
<React.Fragment key={wall.wallUuid}>
|
<React.Fragment key={wall.wallUuid}>
|
||||||
<Line points={wall.points} />
|
<Line points={wall.points} />
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
|
{walls.map((wall) => {
|
||||||
|
const textPosition = new Vector3().addVectors(new Vector3(...wall.points[0].position), new Vector3(...wall.points[1].position)).divideScalar(2);
|
||||||
|
const distance = new Vector3(...wall.points[0].position).distanceTo(new Vector3(...wall.points[1].position));
|
||||||
|
|
||||||
|
return (
|
||||||
|
< React.Fragment key={wall.wallUuid}>
|
||||||
|
{toggleView &&
|
||||||
|
<Html
|
||||||
|
key={`${wall.points[0].pointUuid}_${wall.points[1].pointUuid}`}
|
||||||
|
userData={wall}
|
||||||
|
position={[textPosition.x, 1, textPosition.z]}
|
||||||
|
wrapperClass="distance-text-wrapper"
|
||||||
|
className="distance-text"
|
||||||
|
zIndexRange={[1, 0]}
|
||||||
|
prepend
|
||||||
|
sprite
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
key={wall.wallUuid}
|
||||||
|
className={`distance ${wall.wallUuid}`}
|
||||||
|
>
|
||||||
|
{distance.toFixed(2)} m
|
||||||
|
</div>
|
||||||
|
</Html>
|
||||||
|
}
|
||||||
|
</React.Fragment>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
|
||||||
</group>
|
</group>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ interface BuilderState {
|
|||||||
snappedPoint: Point | null;
|
snappedPoint: Point | null;
|
||||||
snappedPosition: [number, number, number] | null;
|
snappedPosition: [number, number, number] | null;
|
||||||
|
|
||||||
|
hoveredLine: [Point, Point] | null;
|
||||||
|
|
||||||
// Wall
|
// Wall
|
||||||
|
|
||||||
wallThickness: number;
|
wallThickness: number;
|
||||||
@@ -47,6 +49,8 @@ interface BuilderState {
|
|||||||
setSnappedPoint: (point: Point | null) => void;
|
setSnappedPoint: (point: Point | null) => void;
|
||||||
setSnappedPosition: (position: [number, number, number] | null) => void;
|
setSnappedPosition: (position: [number, number, number] | null) => void;
|
||||||
|
|
||||||
|
setHoveredLine: (line: [Point, Point] | null) => void;
|
||||||
|
|
||||||
setSelectedAisle: (aisle: Object3D | null) => void;
|
setSelectedAisle: (aisle: Object3D | null) => void;
|
||||||
|
|
||||||
setAisleType: (type: AisleTypes) => void;
|
setAisleType: (type: AisleTypes) => void;
|
||||||
@@ -81,6 +85,8 @@ export const useBuilderStore = create<BuilderState>()(
|
|||||||
snappedPoint: null,
|
snappedPoint: null,
|
||||||
snappedPosition: null,
|
snappedPosition: null,
|
||||||
|
|
||||||
|
hoveredLine: null,
|
||||||
|
|
||||||
// Wall
|
// Wall
|
||||||
|
|
||||||
wallThickness: 0.5,
|
wallThickness: 0.5,
|
||||||
@@ -128,6 +134,12 @@ export const useBuilderStore = create<BuilderState>()(
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setHoveredLine: (line: [Point, Point] | null) => {
|
||||||
|
set((state) => {
|
||||||
|
state.hoveredLine = line;
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
setSnappedPoint: (point: Point | null) => {
|
setSnappedPoint: (point: Point | null) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
state.snappedPoint = point;
|
state.snappedPoint = point;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ interface WallStore {
|
|||||||
addWall: (wall: Wall) => void;
|
addWall: (wall: Wall) => void;
|
||||||
updateWall: (uuid: string, updated: Partial<Wall>) => void;
|
updateWall: (uuid: string, updated: Partial<Wall>) => void;
|
||||||
removeWall: (uuid: string) => void;
|
removeWall: (uuid: string) => void;
|
||||||
|
removeWallByPoints: (Points: [Point, Point]) => Wall | undefined;
|
||||||
addDecal: (wallUuid: string, decal: Decal) => void;
|
addDecal: (wallUuid: string, decal: Decal) => void;
|
||||||
updateDecal: (decalUuid: string, decal: Decal) => void;
|
updateDecal: (decalUuid: string, decal: Decal) => void;
|
||||||
removeDecal: (decalUuid: string) => void;
|
removeDecal: (decalUuid: string) => void;
|
||||||
@@ -48,6 +49,26 @@ export const useWallStore = create<WallStore>()(
|
|||||||
state.walls = state.walls.filter(w => w.wallUuid !== uuid);
|
state.walls = state.walls.filter(w => w.wallUuid !== uuid);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
removeWallByPoints: (points) => {
|
||||||
|
let removedWall: Wall | undefined;
|
||||||
|
const [pointA, pointB] = points;
|
||||||
|
|
||||||
|
set((state) => {
|
||||||
|
state.walls = state.walls.filter(wall => {
|
||||||
|
const wallPoints = wall.points.map(p => p.pointUuid);
|
||||||
|
const hasBothPoints = wallPoints.includes(pointA.pointUuid) && wallPoints.includes(pointB.pointUuid);
|
||||||
|
|
||||||
|
if (hasBothPoints) {
|
||||||
|
removedWall = JSON.parse(JSON.stringify(wall));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return removedWall;
|
||||||
|
},
|
||||||
|
|
||||||
addDecal: (wallUuid, decal) => set((state) => {
|
addDecal: (wallUuid, decal) => set((state) => {
|
||||||
const wallToUpdate = state.walls.find(w => w.wallUuid === wallUuid);
|
const wallToUpdate = state.walls.find(w => w.wallUuid === wallUuid);
|
||||||
if (wallToUpdate) {
|
if (wallToUpdate) {
|
||||||
|
|||||||
Reference in New Issue
Block a user