refactor: Integrate aisle point snapping into Point component and enhance snapping logic
This commit is contained in:
parent
5254bbd8df
commit
a2a068a732
|
@ -1,61 +1,74 @@
|
|||
import { useCallback, useMemo } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
import * as THREE from 'three';
|
||||
import { useAisleStore } from '../../../../store/builder/useAisleStore';
|
||||
|
||||
const SNAP_THRESHOLD = 0.5; // Distance threshold for snapping in meters
|
||||
const SNAP_STRENGTH = 0.2; // How strongly the point snaps (0-1)
|
||||
const SNAP_DISTANCE_THRESHOLD = 0.5; // Distance threshold for snapping in meters
|
||||
|
||||
const CAN_SNAP = true; // Whether snapping is enabled or not
|
||||
|
||||
export function useAislePointSnapping(point: Point) {
|
||||
const { getConnectedPoints } = useAisleStore();
|
||||
|
||||
// Find all points connected to the current point via aisles
|
||||
const connectedPoints = useMemo(() => {
|
||||
return getConnectedPoints(point.uuid);
|
||||
}, [point.uuid]);
|
||||
const snapPosition = useCallback((newPosition: [number, number, number]): {
|
||||
position: [number, number, number],
|
||||
isSnapped: boolean,
|
||||
snapSources: THREE.Vector3[]
|
||||
} => {
|
||||
if (!CAN_SNAP) return { position: newPosition, isSnapped: false, snapSources: [] };
|
||||
|
||||
// Snapping function
|
||||
const snapPosition = useCallback((newPosition: [number, number, number]): [number, number, number] => {
|
||||
if (connectedPoints.length === 0) return newPosition;
|
||||
|
||||
const newPos = new THREE.Vector3(...newPosition);
|
||||
let snappedX = newPos.x;
|
||||
let snappedZ = newPos.z;
|
||||
let snapCount = 0;
|
||||
|
||||
// Check against all connected points
|
||||
connectedPoints.forEach(connectedPoint => {
|
||||
const connectedPos = new THREE.Vector3(...connectedPoint.position);
|
||||
|
||||
// Check X axis
|
||||
if (Math.abs(newPos.x - connectedPos.x) < SNAP_THRESHOLD) {
|
||||
// Apply soft snapping (lerp)
|
||||
snappedX = THREE.MathUtils.lerp(
|
||||
newPos.x,
|
||||
connectedPos.x,
|
||||
SNAP_STRENGTH
|
||||
);
|
||||
snapCount++;
|
||||
}
|
||||
|
||||
// Check Z axis
|
||||
if (Math.abs(newPos.z - connectedPos.z) < SNAP_THRESHOLD) {
|
||||
// Apply soft snapping (lerp)
|
||||
snappedZ = THREE.MathUtils.lerp(
|
||||
newPos.z,
|
||||
connectedPos.z,
|
||||
SNAP_STRENGTH
|
||||
);
|
||||
snapCount++;
|
||||
}
|
||||
});
|
||||
|
||||
// Only return snapped position if we actually snapped to something
|
||||
if (snapCount > 0) {
|
||||
return [snappedX, newPos.y, snappedZ];
|
||||
const connectedPoints = getConnectedPoints(point.uuid);
|
||||
if (connectedPoints.length === 0) {
|
||||
return {
|
||||
position: newPosition,
|
||||
isSnapped: false,
|
||||
snapSources: []
|
||||
};
|
||||
}
|
||||
|
||||
return newPosition;
|
||||
}, [connectedPoints]);
|
||||
const newPos = new THREE.Vector3(...newPosition);
|
||||
let closestX: { pos: THREE.Vector3, dist: number } | null = null;
|
||||
let closestZ: { pos: THREE.Vector3, dist: number } | null = null;
|
||||
|
||||
for (const connectedPoint of connectedPoints) {
|
||||
const cPos = new THREE.Vector3(...connectedPoint.position);
|
||||
|
||||
const xDist = Math.abs(newPos.x - cPos.x);
|
||||
const zDist = Math.abs(newPos.z - cPos.z);
|
||||
|
||||
if (xDist < SNAP_DISTANCE_THRESHOLD) {
|
||||
if (!closestX || xDist < closestX.dist) {
|
||||
closestX = { pos: cPos, dist: xDist };
|
||||
}
|
||||
}
|
||||
|
||||
if (zDist < SNAP_DISTANCE_THRESHOLD) {
|
||||
if (!closestZ || zDist < closestZ.dist) {
|
||||
closestZ = { pos: cPos, dist: zDist };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const snappedPos = newPos.clone();
|
||||
const snapSources: THREE.Vector3[] = [];
|
||||
|
||||
if (closestX) {
|
||||
snappedPos.x = closestX.pos.x;
|
||||
snapSources.push(closestX.pos.clone());
|
||||
}
|
||||
|
||||
if (closestZ) {
|
||||
snappedPos.z = closestZ.pos.z;
|
||||
snapSources.push(closestZ.pos.clone());
|
||||
}
|
||||
|
||||
const isSnapped = snapSources.length > 0;
|
||||
|
||||
return {
|
||||
position: [snappedPos.x, snappedPos.y, snappedPos.z],
|
||||
isSnapped,
|
||||
snapSources
|
||||
};
|
||||
}, [point.uuid, getConnectedPoints]);
|
||||
|
||||
return { snapPosition };
|
||||
}
|
|
@ -7,6 +7,7 @@ import { useAisleStore } from '../../../store/builder/useAisleStore';
|
|||
import { useThree } from '@react-three/fiber';
|
||||
import { useBuilderStore } from '../../../store/builder/useBuilderStore';
|
||||
import { usePointSnapping } from './helpers/usePointSnapping';
|
||||
import { useAislePointSnapping } from './helpers/useAisleDragSnap';
|
||||
|
||||
function Point({ point }: { readonly point: Point }) {
|
||||
const materialRef = useRef<THREE.ShaderMaterial>(null);
|
||||
|
@ -15,6 +16,7 @@ function Point({ point }: { readonly point: Point }) {
|
|||
const [isHovered, setIsHovered] = useState(false);
|
||||
const { toolMode } = useToolMode();
|
||||
const { setPosition, removePoint } = useAisleStore();
|
||||
const { snapPosition } = useAislePointSnapping(point);
|
||||
const { checkSnapForAisle } = usePointSnapping({ uuid: point.uuid, pointType: point.pointType, position: point.position });
|
||||
const { hoveredPoint, setHoveredPoint } = useBuilderStore();
|
||||
const { deletePointOrLine } = useDeletePointOrLine();
|
||||
|
@ -58,9 +60,10 @@ function Point({ point }: { readonly point: Point }) {
|
|||
if (point.pointType === 'Aisle') {
|
||||
if (position) {
|
||||
const newPosition: [number, number, number] = [position.x, position.y, position.z];
|
||||
const snappedPosition = checkSnapForAisle(newPosition);
|
||||
const aisleSnappedPosition = snapPosition(newPosition);
|
||||
const finalSnappedPosition = checkSnapForAisle(aisleSnappedPosition.position);
|
||||
|
||||
setPosition(point.uuid, snappedPosition.position);
|
||||
setPosition(point.uuid, finalSnappedPosition.position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -193,6 +193,7 @@ export const useAisleStore = create<AisleStore>()(
|
|||
}
|
||||
}
|
||||
}
|
||||
console.log('connected: ', connected);
|
||||
return connected;
|
||||
},
|
||||
|
||||
|
|
Loading…
Reference in New Issue