Files
Dwinzo_Demo/app/src/modules/builder/point/point.tsx

230 lines
10 KiB
TypeScript
Raw Normal View History

2025-06-10 15:28:23 +05:30
import * as THREE from 'three';
import * as Constants from '../../../types/world/worldConstants';
import { useRef, useState, useEffect, useMemo } from 'react';
2025-06-12 09:31:51 +05:30
import { useToolMode } from '../../../store/builder/store';
2025-06-10 15:28:23 +05:30
import { DragControls } from '@react-three/drei';
import { useThree } from '@react-three/fiber';
import { useBuilderStore } from '../../../store/builder/useBuilderStore';
import { usePointSnapping } from './helpers/usePointSnapping';
import { useWallStore } from '../../../store/builder/useWallStore';
import { deleteAisleApi } from '../../../services/factoryBuilder/aisle/deleteAisleApi';
import { useParams } from 'react-router-dom';
import { createAisleApi } from '../../../services/factoryBuilder/aisle/createAisleApi';
2025-06-23 09:37:53 +05:30
import { useVersionContext } from '../version/versionContext';
import { useSceneContext } from '../../scene/sceneContext';
2025-06-10 15:28:23 +05:30
function Point({ point }: { readonly point: Point }) {
const materialRef = useRef<THREE.ShaderMaterial>(null);
const { raycaster, camera, pointer } = useThree();
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
const [isHovered, setIsHovered] = useState(false);
const { toolMode } = useToolMode();
2025-06-23 09:37:53 +05:30
const { aisleStore } = useSceneContext();
const { setPosition: setAislePosition, removePoint: removeAislePoint, getAislesByPointId } = aisleStore();
2025-06-10 15:28:23 +05:30
const { setPosition: setWallPosition, removePoint: removeWallPoint } = useWallStore();
2025-06-23 09:37:53 +05:30
const { snapAislePoint, snapAisleAngle, snapWallPoint, snapWallAngle } = usePointSnapping({ uuid: point.pointUuid, pointType: point.pointType, position: point.position });
2025-06-10 15:28:23 +05:30
const { hoveredPoint, setHoveredPoint } = useBuilderStore();
2025-06-23 09:37:53 +05:30
const { selectedVersionStore } = useVersionContext();
const { selectedVersion } = selectedVersionStore();
2025-06-10 15:28:23 +05:30
const { projectId } = useParams();
const boxScale: [number, number, number] = Constants.pointConfig.boxScale;
const colors = getColor(point);
function getColor(point: Point) {
if (point.pointType === 'Aisle') {
return {
defaultInnerColor: Constants.pointConfig.defaultInnerColor,
defaultOuterColor: Constants.pointConfig.aisleOuterColor,
defaultDeleteColor: Constants.pointConfig.deleteColor,
}
} else if (point.pointType === 'Floor') {
return {
defaultInnerColor: Constants.pointConfig.defaultInnerColor,
defaultOuterColor: Constants.pointConfig.floorOuterColor,
defaultDeleteColor: Constants.pointConfig.deleteColor,
}
} else if (point.pointType === 'Wall') {
return {
defaultInnerColor: Constants.pointConfig.defaultInnerColor,
defaultOuterColor: Constants.pointConfig.wallOuterColor,
defaultDeleteColor: Constants.pointConfig.deleteColor,
}
} else if (point.pointType === 'Zone') {
return {
defaultInnerColor: Constants.pointConfig.defaultInnerColor,
defaultOuterColor: Constants.pointConfig.zoneOuterColor,
defaultDeleteColor: Constants.pointConfig.deleteColor,
}
} else {
return {
defaultInnerColor: Constants.pointConfig.defaultInnerColor,
defaultOuterColor: Constants.pointConfig.defaultOuterColor,
defaultDeleteColor: Constants.pointConfig.deleteColor,
}
}
}
useEffect(() => {
2025-06-12 09:31:51 +05:30
if (materialRef.current && (toolMode === 'move' || toolMode === '2D-Delete')) {
2025-06-10 15:28:23 +05:30
let innerColor;
let outerColor;
if (isHovered) {
2025-06-12 09:31:51 +05:30
innerColor = toolMode === '2D-Delete' ? colors.defaultDeleteColor : colors.defaultOuterColor;
outerColor = toolMode === '2D-Delete' ? colors.defaultDeleteColor : colors.defaultOuterColor;
2025-06-10 15:28:23 +05:30
} else {
innerColor = colors.defaultInnerColor;
outerColor = colors.defaultOuterColor;
}
materialRef.current.uniforms.uInnerColor.value.set(innerColor);
materialRef.current.uniforms.uOuterColor.value.set(outerColor);
materialRef.current.uniformsNeedUpdate = true;
} else if (materialRef.current && toolMode !== 'move') {
materialRef.current.uniforms.uInnerColor.value.set(colors.defaultInnerColor);
materialRef.current.uniforms.uOuterColor.value.set(colors.defaultOuterColor);
materialRef.current.uniformsNeedUpdate = true;
}
2025-06-12 09:31:51 +05:30
}, [isHovered, colors.defaultInnerColor, colors.defaultOuterColor, colors.defaultDeleteColor, toolMode]);
2025-06-10 15:28:23 +05:30
const uniforms = useMemo(() => ({
uOuterColor: { value: new THREE.Color(colors.defaultOuterColor) },
uInnerColor: { value: new THREE.Color(colors.defaultInnerColor) },
}), [colors.defaultInnerColor, colors.defaultOuterColor]);
const handleDrag = (point: Point) => {
if (toolMode === 'move' && isHovered) {
raycaster.setFromCamera(pointer, camera);
const intersectionPoint = new THREE.Vector3();
const position = raycaster.ray.intersectPlane(plane, intersectionPoint);
if (point.pointType === 'Aisle') {
if (position) {
const newPosition: [number, number, number] = [position.x, position.y, position.z];
2025-06-23 09:37:53 +05:30
const aisleSnappedPosition = snapAisleAngle(newPosition);
const finalSnappedPosition = snapAislePoint(aisleSnappedPosition.position);
2025-06-10 15:28:23 +05:30
setAislePosition(point.pointUuid, finalSnappedPosition.position);
}
} else if (point.pointType === 'Wall') {
if (position) {
const newPosition: [number, number, number] = [position.x, position.y, position.z];
2025-06-23 09:37:53 +05:30
const wallSnappedPosition = snapWallAngle(newPosition);
const finalSnappedPosition = snapWallPoint(wallSnappedPosition.position);
2025-06-10 15:28:23 +05:30
2025-06-23 09:37:53 +05:30
setWallPosition(point.pointUuid, finalSnappedPosition.position);
2025-06-10 15:28:23 +05:30
}
}
}
}
const handleDragEnd = (point: Point) => {
2025-06-12 09:31:51 +05:30
if (toolMode === '2D-Delete') return;
2025-06-10 15:28:23 +05:30
if (point.pointType === 'Aisle') {
const updatedAisles = getAislesByPointId(point.pointUuid);
if (updatedAisles.length > 0 && projectId) {
updatedAisles.forEach((updatedAisle) => {
2025-06-23 09:37:53 +05:30
createAisleApi(updatedAisle.aisleUuid, updatedAisle.points, updatedAisle.type, projectId, selectedVersion?.versionId || '')
2025-06-10 15:28:23 +05:30
})
}
} else if (point.pointType === 'Wall') {
// console.log('Wall after drag: ', point);
}
}
const handlePointClick = (point: Point) => {
2025-06-12 09:31:51 +05:30
if (toolMode === '2D-Delete') {
2025-06-10 15:28:23 +05:30
if (point.pointType === 'Aisle') {
const removedAisles = removeAislePoint(point.pointUuid);
if (removedAisles.length > 0) {
removedAisles.forEach(aisle => {
if (projectId)
2025-06-23 09:37:53 +05:30
deleteAisleApi(aisle.aisleUuid, projectId, selectedVersion?.versionId || '')
2025-06-10 15:28:23 +05:30
});
setHoveredPoint(null);
}
}
if (point.pointType === 'Wall') {
const removedAisles = removeWallPoint(point.pointUuid);
if (removedAisles.length > 0) {
setHoveredPoint(null);
}
}
}
}
useEffect(() => {
if (hoveredPoint && hoveredPoint.pointUuid !== point.pointUuid) {
setIsHovered(false);
}
}, [hoveredPoint])
if (!point) {
return null;
}
return (
<DragControls
axisLock='y'
autoTransform={false}
onDrag={() => { handleDrag(point) }}
onDragEnd={() => { handleDragEnd(point) }}
>
<mesh
key={point.pointUuid}
uuid={point.pointUuid}
name={`${point.pointType}-Point`}
position={new THREE.Vector3(...point.position)}
onClick={() => {
handlePointClick(point);
}}
onPointerOver={() => {
if (!hoveredPoint) {
setHoveredPoint(point);
setIsHovered(true)
}
}}
onPointerOut={() => {
2025-06-23 09:37:53 +05:30
if (hoveredPoint) {
2025-06-10 15:28:23 +05:30
setHoveredPoint(null);
}
setIsHovered(false)
}}
userData={point}
>
<boxGeometry args={boxScale} />
<shaderMaterial
ref={materialRef}
uniforms={uniforms}
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); // Inner square
} else {
gl_FragColor = vec4(uOuterColor, 1.0); // Border
}
}
`
}
/>
</mesh>
</DragControls>
);
}
export default Point;