added decal movement across the wall
This commit is contained in:
@@ -14,8 +14,8 @@ import { getUserData } from "../../../../functions/getUserData";
|
||||
const SelectedDecalProperties = () => {
|
||||
const { selectedDecal, setSelectedDecal } = useBuilderStore();
|
||||
const { wallStore, floorStore } = useSceneContext();
|
||||
const { updateDecal: updateDecalFromWall } = wallStore();
|
||||
const { updateDecal: updateDecalFromFloor } = floorStore();
|
||||
const { updateDecal: updateDecalInWall } = wallStore();
|
||||
const { updateDecal: updateDecalInFloor } = floorStore();
|
||||
const { userId, organization } = getUserData();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
@@ -68,10 +68,10 @@ const SelectedDecalProperties = () => {
|
||||
setSelectedDecal({ ...selectedDecal, decalData: updatedDecal });
|
||||
|
||||
if ('wallUuid' in selectedDecal.decalData.decalType) {
|
||||
const updatedWall = updateDecalFromWall(updatedDecal.decalUuid, updatedDecal);
|
||||
const updatedWall = updateDecalInWall(updatedDecal.decalUuid, updatedDecal);
|
||||
if (updatedWall) updateBackend(updatedWall);
|
||||
} else if ('floorUuid' in selectedDecal.decalData.decalType) {
|
||||
const updatedFloor = updateDecalFromFloor(updatedDecal.decalUuid, updatedDecal);
|
||||
const updatedFloor = updateDecalInFloor(updatedDecal.decalUuid, updatedDecal);
|
||||
if (updatedFloor) updateBackend(updatedFloor);
|
||||
}
|
||||
}
|
||||
@@ -82,10 +82,10 @@ const SelectedDecalProperties = () => {
|
||||
setSelectedDecal({ ...selectedDecal, decalData: updatedDecal });
|
||||
|
||||
if ('wallUuid' in selectedDecal.decalData.decalType) {
|
||||
const updatedWall = updateDecalFromWall(updatedDecal.decalUuid, updatedDecal);
|
||||
const updatedWall = updateDecalInWall(updatedDecal.decalUuid, updatedDecal);
|
||||
if (updatedWall) updateBackend(updatedWall);
|
||||
} else if ('floorUuid' in selectedDecal.decalData.decalType) {
|
||||
const updatedFloor = updateDecalFromFloor(updatedDecal.decalUuid, updatedDecal);
|
||||
const updatedFloor = updateDecalInFloor(updatedDecal.decalUuid, updatedDecal);
|
||||
if (updatedFloor) updateBackend(updatedFloor);
|
||||
}
|
||||
}
|
||||
@@ -96,10 +96,10 @@ const SelectedDecalProperties = () => {
|
||||
setSelectedDecal({ ...selectedDecal, decalData: updatedDecal });
|
||||
|
||||
if ('wallUuid' in selectedDecal.decalData.decalType) {
|
||||
const updatedWall = updateDecalFromWall(updatedDecal.decalUuid, updatedDecal);
|
||||
const updatedWall = updateDecalInWall(updatedDecal.decalUuid, updatedDecal);
|
||||
if (updatedWall) updateBackend(updatedWall);
|
||||
} else if ('floorUuid' in selectedDecal.decalData.decalType) {
|
||||
const updatedFloor = updateDecalFromFloor(updatedDecal.decalUuid, updatedDecal);
|
||||
const updatedFloor = updateDecalInFloor(updatedDecal.decalUuid, updatedDecal);
|
||||
if (updatedFloor) updateBackend(updatedFloor);
|
||||
}
|
||||
}
|
||||
@@ -120,10 +120,10 @@ const SelectedDecalProperties = () => {
|
||||
setSelectedDecal({ ...selectedDecal, decalData: updatedDecal });
|
||||
|
||||
if ("wallUuid" in selectedDecal.decalData.decalType) {
|
||||
const updatedWall = updateDecalFromWall(updatedDecal.decalUuid, updatedDecal);
|
||||
const updatedWall = updateDecalInWall(updatedDecal.decalUuid, updatedDecal);
|
||||
if (updatedWall) updateBackend(updatedWall);
|
||||
} else if ("floorUuid" in selectedDecal.decalData.decalType) {
|
||||
const updatedFloor = updateDecalFromFloor(updatedDecal.decalUuid, updatedDecal);
|
||||
const updatedFloor = updateDecalInFloor(updatedDecal.decalUuid, updatedDecal);
|
||||
if (updatedFloor) updateBackend(updatedFloor);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import * as THREE from 'three';
|
||||
import { Decal } from '@react-three/drei'
|
||||
import { useLoader } from '@react-three/fiber';
|
||||
import { CameraControls, Decal } from '@react-three/drei'
|
||||
import { useLoader, useThree } from '@react-three/fiber';
|
||||
import { useSocketStore, useToggleView, useToolMode } from '../../../store/builder/store';
|
||||
import { useBuilderStore } from '../../../store/builder/useBuilderStore';
|
||||
|
||||
import defaultMaterial from '../../../assets/textures/floor/wall-tex.png';
|
||||
import useModuleStore from '../../../store/useModuleStore';
|
||||
import { useSceneContext } from '../../scene/sceneContext';
|
||||
import { useEffect } from 'react';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { getUserData } from '../../../functions/getUserData';
|
||||
import { useVersionContext } from '../version/versionContext';
|
||||
import { useParams } from 'react-router-dom';
|
||||
@@ -18,8 +18,8 @@ import { useParams } from 'react-router-dom';
|
||||
function DecalInstance({ parent, visible = true, decal, zPosition = decal.decalPosition[2] }: { parent: Wall | Floor; visible?: boolean, decal: Decal, zPosition?: number }) {
|
||||
const { setSelectedWall, setSelectedFloor, selectedDecal, deletableDecal, setSelectedDecal, setDeletableDecal } = useBuilderStore();
|
||||
const { wallStore, floorStore } = useSceneContext();
|
||||
const { removeDecal: removeDecalFromWall } = wallStore();
|
||||
const { removeDecal: removeDecalFromFloor } = floorStore();
|
||||
const { removeDecal: removeDecalInWall, updateDecalPosition: updateDecalPositionInWall, getWallById } = wallStore();
|
||||
const { removeDecal: removeDecalInFloor } = floorStore();
|
||||
const { toolMode } = useToolMode();
|
||||
const { toggleView } = useToggleView();
|
||||
const { activeModule } = useModuleStore();
|
||||
@@ -30,6 +30,10 @@ function DecalInstance({ parent, visible = true, decal, zPosition = decal.decalP
|
||||
const { socket } = useSocketStore();
|
||||
const material = useLoader(THREE.TextureLoader, defaultMaterial);
|
||||
|
||||
const { raycaster, pointer, camera, scene, gl, controls } = useThree();
|
||||
const isDraggingRef = useRef(false);
|
||||
const dragOffsetRef = useRef<THREE.Vector3 | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!toggleView && activeModule === 'builder') {
|
||||
if (toolMode !== 'cursor') {
|
||||
@@ -44,9 +48,77 @@ function DecalInstance({ parent, visible = true, decal, zPosition = decal.decalP
|
||||
}
|
||||
}, [toggleView, toolMode, activeModule, selectedDecal, deletableDecal]);
|
||||
|
||||
useEffect(() => {
|
||||
const canvasElement = gl.domElement;
|
||||
|
||||
const handlePointerMove = (e: PointerEvent) => {
|
||||
if (!isDraggingRef.current || !selectedDecal || selectedDecal.decalData.decalUuid !== decal.decalUuid) return;
|
||||
|
||||
raycaster.setFromCamera(pointer, camera);
|
||||
const intersects = raycaster.intersectObjects(scene.children, true);
|
||||
|
||||
const wallIntersect = intersects.find(i => i.object.userData && 'wallUuid' in parent && i.object.userData.wallUuid === parent.wallUuid);
|
||||
|
||||
if (wallIntersect) {
|
||||
const point = wallIntersect.object.worldToLocal(wallIntersect.point.clone());
|
||||
|
||||
let offset = dragOffsetRef.current || new THREE.Vector3(0, 0, 0);
|
||||
|
||||
updateDecalPositionInWall(decal.decalUuid, [point.x + offset.x, point.y + offset.y, decal.decalPosition[2]]);
|
||||
}
|
||||
};
|
||||
|
||||
const handlePointerUp = (e: PointerEvent) => {
|
||||
if (controls) {
|
||||
(controls as CameraControls).enabled = true;
|
||||
}
|
||||
if (isDraggingRef.current) {
|
||||
isDraggingRef.current = false;
|
||||
dragOffsetRef.current = null;
|
||||
|
||||
if ('wallUuid' in parent) {
|
||||
setTimeout(() => {
|
||||
const updatedWall = getWallById(parent.wallUuid);
|
||||
|
||||
if (updatedWall) {
|
||||
if (projectId && 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);
|
||||
}
|
||||
}
|
||||
}, 0)
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
if (activeModule === 'builder' && !toggleView) {
|
||||
canvasElement.addEventListener('pointermove', handlePointerMove);
|
||||
canvasElement.addEventListener('pointerup', handlePointerUp);
|
||||
}
|
||||
|
||||
return () => {
|
||||
canvasElement.removeEventListener('pointermove', handlePointerMove);
|
||||
canvasElement.removeEventListener('pointerup', handlePointerUp);
|
||||
};
|
||||
}, [gl, camera, scene, raycaster, selectedDecal, decal, parent, activeModule, toggleView, projectId, selectedVersion, userId, organization, socket]);
|
||||
|
||||
const deleteDecal = (decalUuid: string, parent: Wall | Floor) => {
|
||||
if ('wallUuid' in parent) {
|
||||
const updatedWall = removeDecalFromWall(decalUuid);
|
||||
const updatedWall = removeDecalInWall(decalUuid);
|
||||
|
||||
if (projectId && updatedWall) {
|
||||
// API
|
||||
@@ -66,7 +138,7 @@ function DecalInstance({ parent, visible = true, decal, zPosition = decal.decalP
|
||||
socket.emit('v1:model-Wall:add', data);
|
||||
}
|
||||
} else if ('floorUuid' in parent) {
|
||||
const updatedFloor = removeDecalFromFloor(decalUuid);
|
||||
const updatedFloor = removeDecalInFloor(decalUuid);
|
||||
|
||||
if (projectId && updatedFloor) {
|
||||
// API
|
||||
@@ -96,6 +168,24 @@ function DecalInstance({ parent, visible = true, decal, zPosition = decal.decalP
|
||||
rotation={[0, 0, decal.decalRotation * (Math.PI / 180)]}
|
||||
scale={[decal.decalScale, decal.decalScale, 0.01]}
|
||||
userData={decal}
|
||||
onPointerDown={(e) => {
|
||||
if (visible && !toggleView && activeModule === 'builder') {
|
||||
if (e.object.userData.decalUuid && toolMode === 'cursor') {
|
||||
e.stopPropagation();
|
||||
isDraggingRef.current = true;
|
||||
if (controls) {
|
||||
(controls as CameraControls).enabled = false;
|
||||
}
|
||||
setSelectedDecal({ decalMesh: e.object, decalData: decal });
|
||||
setSelectedWall(null);
|
||||
setSelectedFloor(null);
|
||||
|
||||
const localIntersect = e.object.worldToLocal(e.point.clone());
|
||||
dragOffsetRef.current = new THREE.Vector3(decal.decalPosition[0] - localIntersect.x, decal.decalPosition[1] - localIntersect.y, 0);
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
||||
onClick={(e) => {
|
||||
if (visible && !toggleView && activeModule === 'builder') {
|
||||
if (e.object.userData.decalUuid) {
|
||||
|
||||
@@ -18,10 +18,10 @@ const calculateAssetTransformationOnWall = (
|
||||
|
||||
const projection = initialWallNormalized.clone().multiplyScalar(dotProduct);
|
||||
const perpendicular = new THREE.Vector3().subVectors(assetVector, projection);
|
||||
const distanceFromWall = perpendicular.length();
|
||||
const distanceInWall = perpendicular.length();
|
||||
|
||||
const crossProduct = new THREE.Vector3().crossVectors(initialWallNormalized, perpendicular).y;
|
||||
const signedDistance = distanceFromWall * (crossProduct >= 0 ? 1 : -1);
|
||||
const signedDistance = distanceInWall * (crossProduct >= 0 ? 1 : -1);
|
||||
|
||||
const percentage = Math.max(0, Math.min(1, dotProduct / initialWallLength));
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) {
|
||||
const { raycaster, pointer, camera, scene, controls, gl } = useThree();
|
||||
const { wallStore, wallAssetStore } = useSceneContext();
|
||||
const { walls, getWallById } = wallStore();
|
||||
const { updateWallAsset, removeWallAsset } = wallAssetStore();
|
||||
const { updateWallAsset, removeWallAsset, getWallAssetById } = wallAssetStore();
|
||||
const { toggleView } = useToggleView();
|
||||
const { activeTool } = useActiveTool();
|
||||
const { activeModule } = useModuleStore();
|
||||
@@ -116,33 +116,14 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) {
|
||||
const canvasElement = gl.domElement;
|
||||
|
||||
const onPointerUp = (e: PointerEvent) => {
|
||||
draggingRef.current = false;
|
||||
if (controls) {
|
||||
(controls as any).enabled = true;
|
||||
}
|
||||
if (draggingRef.current) {
|
||||
draggingRef.current = false;
|
||||
if (controls) {
|
||||
(controls as any).enabled = true;
|
||||
}
|
||||
|
||||
if (selectedWallAsset) {
|
||||
pointer.x = (e.clientX / window.innerWidth) * 2 - 1;
|
||||
pointer.y = -(e.clientY / window.innerHeight) * 2 + 1;
|
||||
|
||||
raycaster.setFromCamera(pointer, camera);
|
||||
const intersects = raycaster.intersectObjects(scene.children, true);
|
||||
const intersect = intersects.find((i: any) => i.object.name.includes('WallReference'));
|
||||
|
||||
if (intersect && intersect.object.userData.wallUuid && selectedWallAsset.userData.modelUuid === wallAsset.modelUuid) {
|
||||
const newPoint = closestPointOnLineSegment(
|
||||
new THREE.Vector3(intersect.point.x, 0, intersect.point.z),
|
||||
new THREE.Vector3(...intersect.object.userData.points[0].position),
|
||||
new THREE.Vector3(...intersect.object.userData.points[1].position)
|
||||
);
|
||||
|
||||
const wallRotation = intersect.object.rotation.clone();
|
||||
|
||||
const updatedWallAsset = updateWallAsset(wallAsset.modelUuid, {
|
||||
wallUuid: intersect.object.userData.wallUuid,
|
||||
position: [newPoint.x, wallAsset.wallAssetType === 'fixedMove' ? 0 : intersect.point.y, newPoint.z],
|
||||
rotation: [wallRotation.x, wallRotation.y, wallRotation.z],
|
||||
});
|
||||
if (selectedWallAsset) {
|
||||
const updatedWallAsset = getWallAssetById(wallAsset.modelUuid);
|
||||
|
||||
if (projectId && updatedWallAsset) {
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ interface WallStore {
|
||||
addDecal: (wallUuid: string, decal: Decal) => void;
|
||||
updateDecal: (decalUuid: string, decal: Decal) => Wall | undefined;
|
||||
removeDecal: (decalUuid: string) => Wall | undefined;
|
||||
updateDecalPosition: (decalUuid: string, position: [number, number, number]) => void;
|
||||
updateDecalPosition: (decalUuid: string, position: [number, number, number]) => Wall | undefined;
|
||||
updateDecalRotation: (decalUuid: string, rotation: number) => void;
|
||||
updateDecalScale: (decalUuid: string, scale: number) => void;
|
||||
|
||||
@@ -118,15 +118,20 @@ export const createWallStore = () => {
|
||||
return affectedWall;
|
||||
},
|
||||
|
||||
updateDecalPosition: (decalUuid, position) => set((state) => {
|
||||
for (const wall of state.walls) {
|
||||
const decal = wall.decals.find(d => d.decalUuid === decalUuid);
|
||||
if (decal) {
|
||||
decal.decalPosition = position;
|
||||
break;
|
||||
updateDecalPosition: (decalUuid, position) => {
|
||||
let affectedWall: Wall | undefined;
|
||||
set((state) => {
|
||||
for (const wall of state.walls) {
|
||||
const decal = wall.decals.find(d => d.decalUuid === decalUuid);
|
||||
if (decal) {
|
||||
decal.decalPosition = position;
|
||||
affectedWall = JSON.parse(JSON.stringify(wall));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
})
|
||||
return affectedWall;
|
||||
},
|
||||
|
||||
updateDecalRotation: (decalUuid, rotation) => set((state) => {
|
||||
for (const wall of state.walls) {
|
||||
|
||||
Reference in New Issue
Block a user