This commit is contained in:
rafaeldpsilva
2025-12-10 14:57:34 +00:00
parent 84f5286126
commit b1ddf0c85e
102 changed files with 0 additions and 497175 deletions

View File

@@ -0,0 +1,111 @@
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import { useSimulation } from '../useSimulation';
export function useCameraControls(camera: THREE.Camera, renderer: THREE.WebGLRenderer) {
let controls: OrbitControls;
// Camera Motion State
let moveAnimating = false;
let moveStart: THREE.Vector3 | null = null;
let moveEnd: THREE.Vector3 | null = null;
let contStart: THREE.Vector3 | null = null;
let contEnd: THREE.Vector3 | null = null;
let moveProgress = 0;
const moveDuration = 0.2;
let moveStartTime = 0;
const { state } = useSimulation(); // Access global state
const initControls = () => {
controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = false;
controls.dampingFactor = 0.05;
controls.enableRotate = false;
controls.enablePan = true;
controls.enableZoom = false;
controls.screenSpacePanning = false; // Fix: Pan on XZ plane only
// Strictly match legacy controls.js
controls.mouseButtons = {
LEFT: THREE.MOUSE.PAN
} as any; // Cast to allow partial object if TS complains, or just because we are overriding defaults
controls.target.set(0, 0, 0);
// Scroll Listeners
controls.addEventListener('change', () => {
if (moveAnimating) return;
controls.target.y = 0;
camera.position.y = Math.min(camera.position.y, state.value.maxZoom || 120);
// This 'change' listener might fight with the zoom logic if not careful.
// But let's just stick to the requested change: Zoom Out limit.
});
renderer.domElement.addEventListener('wheel', (event: WheelEvent) => {
event.preventDefault();
if (!moveAnimating) {
const zoomAmount = state.value.zoomSensitivity || 5;
const maxZoom = state.value.maxZoom || 120; // Default fallback
// Calculate direction from target to camera (view vector)
const dir = new THREE.Vector3().subVectors(camera.position, controls.target).normalize();
let targetPos: THREE.Vector3 | null = null;
if (event.deltaY < 0) {
// Zoom Out: Move away from target
targetPos = camera.position.clone().add(dir.multiplyScalar(zoomAmount));
// Check Max Limit
if (targetPos.y > maxZoom) {
// Clamp to max zoom height, but keep angle (roughly, or just stop)
// Simple stop:
targetPos = null;
// Or precise clamping (complex math to find point on vector where y=maxZoom):
// y = y0 + t * dir.y => maxZoom = y0 + t * dir.y => t = (maxZoom - y0) / dir.y
// But simply ignoring the input if it exceeds is safer/smoother for now.
}
} else if (event.deltaY > 0) {
// Zoom In: Move towards target
targetPos = camera.position.clone().sub(dir.multiplyScalar(zoomAmount));
// Check Min Limit
if (targetPos.y < 10) {
targetPos = null;
}
}
if (targetPos) {
moveStart = camera.position.clone();
moveEnd = targetPos;
contStart = controls.target.clone();
contEnd = controls.target.clone(); // Target stays same
moveProgress = 0;
moveStartTime = performance.now() / 1000;
moveAnimating = true;
}
}
}, { passive: false });
};
const updateControls = () => {
// Animation
if (moveAnimating && moveStart && moveEnd && contStart && contEnd) {
const now = performance.now() / 1000;
moveProgress = Math.min((now - moveStartTime) / moveDuration, 1);
camera.position.lerpVectors(moveStart, moveEnd, moveProgress);
controls.target.lerpVectors(contStart, contEnd, moveProgress);
if (moveProgress >= 1) {
moveAnimating = false;
}
controls.update();
}
if (controls) controls.update();
};
return {
initControls,
updateControls,
getControls: () => controls
};
}