Merge remote-tracking branch 'origin/main-dev' into main-demo
This commit is contained in:
@@ -32,7 +32,7 @@ function Line({ points }: Readonly<LineProps>) {
|
|||||||
const { toolMode } = useToolMode();
|
const { toolMode } = useToolMode();
|
||||||
const { wallStore, floorStore, zoneStore, undoRedo2DStore } = useSceneContext();
|
const { wallStore, floorStore, zoneStore, undoRedo2DStore } = useSceneContext();
|
||||||
const { push2D } = undoRedo2DStore();
|
const { push2D } = undoRedo2DStore();
|
||||||
const { removeWallByPoints, setPosition: setWallPosition, getWallsByPointId } = wallStore();
|
const { removeWallByPoints, setPosition: setWallPosition, getWallByPoints, getConnectedWallsByWallId } = wallStore();
|
||||||
const { removeFloorByPoints, setPosition: setFloorPosition, getFloorsByPointId, getFloorsByPoints } = floorStore();
|
const { removeFloorByPoints, setPosition: setFloorPosition, getFloorsByPointId, getFloorsByPoints } = floorStore();
|
||||||
const { removeZoneByPoints, setPosition: setZonePosition, getZonesByPointId, getZonesByPoints } = zoneStore();
|
const { removeZoneByPoints, setPosition: setZonePosition, getZonesByPointId, getZonesByPoints } = zoneStore();
|
||||||
const { userId, organization } = getUserData();
|
const { userId, organization } = getUserData();
|
||||||
@@ -361,27 +361,31 @@ function Line({ points }: Readonly<LineProps>) {
|
|||||||
const offset = new THREE.Vector3().subVectors(midPoint, hit);
|
const offset = new THREE.Vector3().subVectors(midPoint, hit);
|
||||||
setDragOffset(offset);
|
setDragOffset(offset);
|
||||||
|
|
||||||
if (points[0].pointType === 'Wall') {
|
if (points[0].pointType === 'Wall' && points[1].pointType === 'Wall') {
|
||||||
const walls = getWallsByPointId(points[0].pointUuid);
|
const wall = getWallByPoints(points);
|
||||||
setInitialPositions({ walls });
|
if (wall) {
|
||||||
} else if (points[0].pointType === 'Floor') {
|
const walls = getConnectedWallsByWallId(wall.wallUuid, false);
|
||||||
|
setInitialPositions({ walls });
|
||||||
|
}
|
||||||
|
} else if (points[0].pointType === 'Floor' && points[0].pointType === 'Floor') {
|
||||||
const floors = getFloorsByPointId(points[0].pointUuid);
|
const floors = getFloorsByPointId(points[0].pointUuid);
|
||||||
setInitialPositions({ floors });
|
setInitialPositions({ floors });
|
||||||
} else if (points[0].pointType === 'Zone') {
|
} else if (points[0].pointType === 'Zone' && points[0].pointType === 'Zone') {
|
||||||
const zones = getZonesByPointId(points[0].pointUuid);
|
const zones = getZonesByPointId(points[0].pointUuid);
|
||||||
setInitialPositions({ zones });
|
setInitialPositions({ zones });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDragEnd = (points: [Point, Point]) => {
|
const handleDragEnd = (points: [Point, Point]) => {
|
||||||
if (toolMode !== 'move' || !dragOffset) return;
|
if (toolMode !== 'move' || !dragOffset) return;
|
||||||
handleCanvasCursors('default');
|
handleCanvasCursors('default');
|
||||||
setDragOffset(null);
|
setDragOffset(null);
|
||||||
|
|
||||||
if (points[0].pointType === 'Wall' && points[1].pointType === 'Wall') {
|
if (points[0].pointType === 'Wall' && points[1].pointType === 'Wall') {
|
||||||
const updatedWalls1 = getWallsByPointId(points[0].pointUuid);
|
const wall = getWallByPoints(points);
|
||||||
const updatedWalls2 = getWallsByPointId(points[1].pointUuid);
|
if (!wall) return;
|
||||||
const updatedWalls = [...updatedWalls1, ...updatedWalls2].filter((wall, index, self) => index === self.findIndex((w) => w.wallUuid === wall.wallUuid));
|
const updatedWalls = getConnectedWallsByWallId(wall.wallUuid, false);
|
||||||
|
|
||||||
if (updatedWalls.length > 0 && projectId) {
|
if (updatedWalls.length > 0 && projectId) {
|
||||||
updatedWalls.forEach(updatedWall => {
|
updatedWalls.forEach(updatedWall => {
|
||||||
|
|||||||
@@ -19,9 +19,12 @@ import { useSceneContext } from '../../scene/sceneContext';
|
|||||||
// import { deleteFloorApi } from '../../../services/factoryBuilder/floor/deleteFloorApi';
|
// import { deleteFloorApi } from '../../../services/factoryBuilder/floor/deleteFloorApi';
|
||||||
// import { upsertZoneApi } from '../../../services/factoryBuilder/zone/upsertZoneApi';
|
// import { upsertZoneApi } from '../../../services/factoryBuilder/zone/upsertZoneApi';
|
||||||
// import { deleteZoneApi } from '../../../services/factoryBuilder/zone/deleteZoneApi';
|
// import { deleteZoneApi } from '../../../services/factoryBuilder/zone/deleteZoneApi';
|
||||||
|
// import { upsertWallAssetApi } from '../../../services/factoryBuilder/asset/wallAsset/upsertWallAssetApi';
|
||||||
|
// import { deleteWallAssetApi } from '../../../services/factoryBuilder/asset/wallAsset/deleteWallAssetApi';
|
||||||
|
|
||||||
import { getUserData } from '../../../functions/getUserData';
|
import { getUserData } from '../../../functions/getUserData';
|
||||||
import { handleCanvasCursors } from '../../../utils/mouseUtils/handleCanvasCursors';
|
import { handleCanvasCursors } from '../../../utils/mouseUtils/handleCanvasCursors';
|
||||||
|
import { calculateAssetTransformationOnWall } from '../wallAsset/Instances/Instance/functions/calculateAssetTransformationOnWall';
|
||||||
|
|
||||||
function Point({ point }: { readonly point: Point }) {
|
function Point({ point }: { readonly point: Point }) {
|
||||||
const materialRef = useRef<THREE.ShaderMaterial>(null);
|
const materialRef = useRef<THREE.ShaderMaterial>(null);
|
||||||
@@ -32,12 +35,13 @@ function Point({ point }: { readonly point: Point }) {
|
|||||||
const [dragOffset, setDragOffset] = useState<THREE.Vector3 | null>(null);
|
const [dragOffset, setDragOffset] = useState<THREE.Vector3 | null>(null);
|
||||||
const { socket } = useSocketStore();
|
const { socket } = useSocketStore();
|
||||||
const { toolMode } = useToolMode();
|
const { toolMode } = useToolMode();
|
||||||
const { aisleStore, wallStore, floorStore, zoneStore, undoRedo2DStore } = useSceneContext();
|
const { aisleStore, wallStore, floorStore, zoneStore, undoRedo2DStore, wallAssetStore } = useSceneContext();
|
||||||
const { push2D } = undoRedo2DStore();
|
const { push2D } = undoRedo2DStore();
|
||||||
const { setPosition: setAislePosition, removePoint: removeAislePoint, getAislesByPointId } = aisleStore();
|
const { setPosition: setAislePosition, removePoint: removeAislePoint, getAislesByPointId } = aisleStore();
|
||||||
const { setPosition: setWallPosition, removePoint: removeWallPoint, getWallsByPointId } = wallStore();
|
const { setPosition: setWallPosition, removePoint: removeWallPoint, getWallsByPointId } = wallStore();
|
||||||
const { setPosition: setFloorPosition, removePoint: removeFloorPoint, getFloorsByPointId } = floorStore();
|
const { setPosition: setFloorPosition, removePoint: removeFloorPoint, getFloorsByPointId } = floorStore();
|
||||||
const { setPosition: setZonePosition, removePoint: removeZonePoint, getZonesByPointId } = zoneStore();
|
const { setPosition: setZonePosition, removePoint: removeZonePoint, getZonesByPointId } = zoneStore();
|
||||||
|
const { getWallAssetsByWall, updateWallAsset, removeWallAsset } = wallAssetStore();
|
||||||
const { snapAislePoint, snapAisleAngle, snapWallPoint, snapWallAngle, snapFloorPoint, snapFloorAngle, snapZonePoint, snapZoneAngle } = usePointSnapping({ uuid: point.pointUuid, pointType: point.pointType, position: point.position });
|
const { snapAislePoint, snapAisleAngle, snapWallPoint, snapWallAngle, snapFloorPoint, snapFloorAngle, snapZonePoint, snapZoneAngle } = usePointSnapping({ uuid: point.pointUuid, pointType: point.pointType, position: point.position });
|
||||||
const { hoveredPoint, hoveredLine, setHoveredPoint } = useBuilderStore();
|
const { hoveredPoint, hoveredLine, setHoveredPoint } = useBuilderStore();
|
||||||
const { selectedPoints } = useSelectedPoints();
|
const { selectedPoints } = useSelectedPoints();
|
||||||
@@ -226,6 +230,39 @@ function Point({ point }: { readonly point: Point }) {
|
|||||||
if (updatedWalls && updatedWalls.length > 0 && projectId) {
|
if (updatedWalls && updatedWalls.length > 0 && projectId) {
|
||||||
updatedWalls.forEach((updatedWall) => {
|
updatedWalls.forEach((updatedWall) => {
|
||||||
|
|
||||||
|
const initialWall = initialPositions.walls?.find(w => w.wallUuid === updatedWall.wallUuid);
|
||||||
|
|
||||||
|
if (initialWall) {
|
||||||
|
const assetsOnWall = getWallAssetsByWall(updatedWall.wallUuid);
|
||||||
|
|
||||||
|
assetsOnWall.forEach(asset => {
|
||||||
|
const { position, rotation } = calculateAssetTransformationOnWall(asset, initialWall, updatedWall);
|
||||||
|
|
||||||
|
const updatedWallAsset = updateWallAsset(asset.modelUuid, {
|
||||||
|
position: [position[0], asset.position[1], position[2]],
|
||||||
|
rotation: rotation
|
||||||
|
});
|
||||||
|
|
||||||
|
if (projectId && updatedWallAsset) {
|
||||||
|
// API
|
||||||
|
|
||||||
|
// upsertWallAssetApi(projectId, selectedVersion?.versionId || '', updatedWallAsset);
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
wallAssetData: updatedWallAsset,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:wall-asset:add', data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// API
|
// API
|
||||||
|
|
||||||
// upsertWallApi(projectId, selectedVersion?.versionId || '', updatedWall);
|
// upsertWallApi(projectId, selectedVersion?.versionId || '', updatedWall);
|
||||||
@@ -393,6 +430,33 @@ function Point({ point }: { readonly point: Point }) {
|
|||||||
if (removedWalls.length > 0) {
|
if (removedWalls.length > 0) {
|
||||||
setHoveredPoint(null);
|
setHoveredPoint(null);
|
||||||
removedWalls.forEach(wall => {
|
removedWalls.forEach(wall => {
|
||||||
|
const assetsOnWall = getWallAssetsByWall(wall.wallUuid);
|
||||||
|
|
||||||
|
assetsOnWall.forEach((asset) => {
|
||||||
|
if (projectId && asset) {
|
||||||
|
|
||||||
|
removeWallAsset(asset.modelUuid);
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// deleteWallAssetApi(projectId, selectedVersion?.versionId || '', asset.modelUuid, asset.wallUuid);
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
userId: userId,
|
||||||
|
organization: organization,
|
||||||
|
modelUuid: asset.modelUuid,
|
||||||
|
wallUuid: asset.wallUuid
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('v1:wall-asset:delete', data);
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
|
|
||||||
// API
|
// API
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import * as THREE from 'three';
|
||||||
|
|
||||||
|
const calculateAssetTransformationOnWall = (
|
||||||
|
asset: WallAsset,
|
||||||
|
initialWall: Wall,
|
||||||
|
newWall: Wall
|
||||||
|
): { position: [number, number, number], rotation: [number, number, number] } => {
|
||||||
|
const [initialStartPoint, initialEndPoint] = initialWall.points;
|
||||||
|
const [newStartPoint, newEndPoint] = newWall.points;
|
||||||
|
|
||||||
|
const initialWallVector = new THREE.Vector3(initialEndPoint.position[0] - initialStartPoint.position[0], 0, initialEndPoint.position[2] - initialStartPoint.position[2]);
|
||||||
|
|
||||||
|
const assetVector = new THREE.Vector3(asset.position[0] - initialStartPoint.position[0], 0, asset.position[2] - initialStartPoint.position[2]);
|
||||||
|
|
||||||
|
const initialWallLength = initialWallVector.length();
|
||||||
|
const initialWallNormalized = initialWallVector.normalize();
|
||||||
|
const dotProduct = assetVector.dot(initialWallNormalized);
|
||||||
|
|
||||||
|
const projection = initialWallNormalized.clone().multiplyScalar(dotProduct);
|
||||||
|
const perpendicular = new THREE.Vector3().subVectors(assetVector, projection);
|
||||||
|
const distanceFromWall = perpendicular.length();
|
||||||
|
|
||||||
|
const crossProduct = new THREE.Vector3().crossVectors(initialWallNormalized, perpendicular).y;
|
||||||
|
const signedDistance = distanceFromWall * (crossProduct >= 0 ? 1 : -1);
|
||||||
|
|
||||||
|
const percentage = Math.max(0, Math.min(1, dotProduct / initialWallLength));
|
||||||
|
|
||||||
|
const newWallVector = new THREE.Vector3(newEndPoint.position[0] - newStartPoint.position[0], 0, newEndPoint.position[2] - newStartPoint.position[2]);
|
||||||
|
|
||||||
|
const x = newStartPoint.position[0] + (newEndPoint.position[0] - newStartPoint.position[0]) * percentage;
|
||||||
|
const z = newStartPoint.position[2] + (newEndPoint.position[2] - newStartPoint.position[2]) * percentage;
|
||||||
|
|
||||||
|
const newWallNormal = new THREE.Vector3(-newWallVector.z, 0, newWallVector.x).normalize();
|
||||||
|
|
||||||
|
const offsetX = newWallNormal.x * signedDistance;
|
||||||
|
const offsetZ = newWallNormal.z * signedDistance;
|
||||||
|
|
||||||
|
const wallAngle = Math.atan2(newWallVector.z, newWallVector.x);
|
||||||
|
|
||||||
|
return {
|
||||||
|
position: [x + offsetX, asset.position[1], z + offsetZ],
|
||||||
|
rotation: [0, -wallAngle, 0]
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export { calculateAssetTransformationOnWall };
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { useSceneContext } from '../../../scene/sceneContext'
|
import { useSceneContext } from '../../../scene/sceneContext'
|
||||||
import { useToggleView } from '../../../../store/builder/store';
|
import { useToggleView } from '../../../../store/builder/store';
|
||||||
import WallAssetInstance from './Instances/wallAssetInstance';
|
import WallAssetInstance from './Instance/wallAssetInstance';
|
||||||
|
|
||||||
function WallAssetInstances() {
|
function WallAssetInstances() {
|
||||||
const { wallAssetStore } = useSceneContext();
|
const { wallAssetStore } = useSceneContext();
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { useVersionContext } from '../version/versionContext';
|
|||||||
import { getUserData } from '../../../functions/getUserData';
|
import { getUserData } from '../../../functions/getUserData';
|
||||||
import closestPointOnLineSegment from '../line/helpers/getClosestPointOnLineSegment';
|
import closestPointOnLineSegment from '../line/helpers/getClosestPointOnLineSegment';
|
||||||
|
|
||||||
import { upsertWallAssetApi } from '../../../services/factoryBuilder/asset/wallAsset/upsertWallAssetApi';
|
// import { upsertWallAssetApi } from '../../../services/factoryBuilder/asset/wallAsset/upsertWallAssetApi';
|
||||||
|
|
||||||
function WallAssetCreator() {
|
function WallAssetCreator() {
|
||||||
const { socket } = useSocketStore();
|
const { socket } = useSocketStore();
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ function MoveControls2D({
|
|||||||
const onPointerUp = (event: PointerEvent) => {
|
const onPointerUp = (event: PointerEvent) => {
|
||||||
if (!isMoving && movedObjects.length > 0 && event.button === 0) {
|
if (!isMoving && movedObjects.length > 0 && event.button === 0) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
placeMovedAssets();
|
placeMovedPoints();
|
||||||
}
|
}
|
||||||
if (!isMoving && movedObjects.length > 0 && event.button === 2) {
|
if (!isMoving && movedObjects.length > 0 && event.button === 2) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@@ -221,7 +221,7 @@ function MoveControls2D({
|
|||||||
}, 0)
|
}, 0)
|
||||||
};
|
};
|
||||||
|
|
||||||
const placeMovedAssets = () => {
|
const placeMovedPoints = () => {
|
||||||
if (movedObjects.length === 0) return;
|
if (movedObjects.length === 0) return;
|
||||||
|
|
||||||
const undoPoints: UndoRedo2DDataTypeSchema[] = [];
|
const undoPoints: UndoRedo2DDataTypeSchema[] = [];
|
||||||
@@ -262,11 +262,11 @@ function MoveControls2D({
|
|||||||
lineData: {
|
lineData: {
|
||||||
...updatedAisle,
|
...updatedAisle,
|
||||||
points: [
|
points: [
|
||||||
updatedAisle.points[0].pointUuid === point.pointUuid
|
initialStates[updatedAisle.points[0].pointUuid] ?
|
||||||
? { ...updatedAisle.points[0], position: [old.position.x, old.position.y, old.position.z] }
|
{ ...updatedAisle.points[0], position: initialStates[updatedAisle.points[0].pointUuid].position }
|
||||||
: updatedAisle.points[0],
|
: updatedAisle.points[0],
|
||||||
updatedAisle.points[1].pointUuid === point.pointUuid
|
initialStates[updatedAisle.points[1].pointUuid] ?
|
||||||
? { ...updatedAisle.points[1], position: [old.position.x, old.position.y, old.position.z] }
|
{ ...updatedAisle.points[1], position: initialStates[updatedAisle.points[1].pointUuid].position }
|
||||||
: updatedAisle.points[1]
|
: updatedAisle.points[1]
|
||||||
] as [Point, Point],
|
] as [Point, Point],
|
||||||
},
|
},
|
||||||
@@ -302,11 +302,11 @@ function MoveControls2D({
|
|||||||
lineData: {
|
lineData: {
|
||||||
...updatedWall,
|
...updatedWall,
|
||||||
points: [
|
points: [
|
||||||
updatedWall.points[0].pointUuid === point.pointUuid
|
initialStates[updatedWall.points[0].pointUuid] ?
|
||||||
? { ...updatedWall.points[0], position: [old.position.x, old.position.y, old.position.z] }
|
{ ...updatedWall.points[0], position: initialStates[updatedWall.points[0].pointUuid].position }
|
||||||
: updatedWall.points[0],
|
: updatedWall.points[0],
|
||||||
updatedWall.points[1].pointUuid === point.pointUuid
|
initialStates[updatedWall.points[1].pointUuid] ?
|
||||||
? { ...updatedWall.points[1], position: [old.position.x, old.position.y, old.position.z] }
|
{ ...updatedWall.points[1], position: initialStates[updatedWall.points[1].pointUuid].position }
|
||||||
: updatedWall.points[1]
|
: updatedWall.points[1]
|
||||||
] as [Point, Point],
|
] as [Point, Point],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ interface WallStore {
|
|||||||
getWallByPoints: (points: Point[]) => Wall | undefined;
|
getWallByPoints: (points: Point[]) => Wall | undefined;
|
||||||
getWallPointById: (uuid: string) => Point | undefined;
|
getWallPointById: (uuid: string) => Point | undefined;
|
||||||
getConnectedPoints: (uuid: string) => Point[];
|
getConnectedPoints: (uuid: string) => Point[];
|
||||||
|
getConnectedWallsByWallId: (wallUuid: string, skipSelf: boolean) => Wall[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createWallStore = () => {
|
export const createWallStore = () => {
|
||||||
@@ -178,7 +179,7 @@ export const createWallStore = () => {
|
|||||||
|
|
||||||
getWallsByPointId: (uuid) => {
|
getWallsByPointId: (uuid) => {
|
||||||
return get().walls.filter((a) => {
|
return get().walls.filter((a) => {
|
||||||
return a.points.some((p) => p.pointUuid === uuid);
|
return JSON.parse(JSON.stringify(a.points.some((p) => p.pointUuid === uuid)));
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -211,6 +212,19 @@ export const createWallStore = () => {
|
|||||||
}
|
}
|
||||||
return connected;
|
return connected;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getConnectedWallsByWallId: (wallUuid, skipSelf) => {
|
||||||
|
const wall = get().walls.find(w => w.wallUuid === wallUuid);
|
||||||
|
if (!wall) return [];
|
||||||
|
|
||||||
|
const pointUuids = wall.points.map(p => p.pointUuid);
|
||||||
|
|
||||||
|
return get().walls.filter(w => {
|
||||||
|
if (skipSelf && w.wallUuid === wallUuid) return false;
|
||||||
|
return w.points.some(p => pointUuids.includes(p.pointUuid));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
}))
|
}))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user