cube-parameters
Version:
A sophisticated 3D model viewer built with React, TypeScript, and Three.js, featuring advanced visualization tools, measurement capabilities, and lighting controls.
76 lines (61 loc) • 2.68 kB
text/typescript
import { useState, useCallback, useRef } from 'react';
import * as THREE from 'three';
import { getIntersectionPoint } from '../utils/raycastUtils';
import { createMeasurementGroup, updatePreviewLine, clearPreviewLine } from '../utils/objectCreators';
export const useMeasureTool = (
renderer: THREE.WebGLRenderer | null,
camera: THREE.PerspectiveCamera | null,
scene: THREE.Scene | null,
onMeasureCreate?: (start: THREE.Vector3, end: THREE.Vector3) => void,
onObjectSelect?: (object: THREE.Object3D | null) => void
) => {
const measureStartPoint = useRef<THREE.Vector3 | null>(null);
const previewLineRef = useRef<THREE.Line | null>(null);
const handleClick = useCallback((event: MouseEvent) => {
if (!renderer || !camera || !scene || event.button !== 0) return;
const intersectionPoint = getIntersectionPoint(event.clientX, event.clientY, renderer, camera, scene);
if (intersectionPoint) {
if (!measureStartPoint.current) {
// First click - start measurement
measureStartPoint.current = intersectionPoint.clone();
} else {
// Second click - complete measurement
const startPoint = measureStartPoint.current;
const endPoint = intersectionPoint;
const measurementGroup = createMeasurementGroup(startPoint, endPoint, scene);
previewLineRef.current = clearPreviewLine(previewLineRef.current, scene);
if (onMeasureCreate) {
onMeasureCreate(startPoint, endPoint);
}
if (onObjectSelect) {
onObjectSelect(measurementGroup);
}
measureStartPoint.current = null;
}
}
}, [renderer, camera, scene, onMeasureCreate, onObjectSelect]);
const handleMouseMove = useCallback((event: MouseEvent) => {
if (!renderer || !camera || !scene || !measureStartPoint.current) return;
const currentPoint = getIntersectionPoint(event.clientX, event.clientY, renderer, camera, scene);
if (currentPoint) {
previewLineRef.current = updatePreviewLine(measureStartPoint.current, currentPoint, scene, previewLineRef.current);
}
}, [renderer, camera, scene]);
const handleRightClick = useCallback(() => {
if (measureStartPoint.current && scene) {
measureStartPoint.current = null;
previewLineRef.current = clearPreviewLine(previewLineRef.current, scene);
}
}, [scene]);
const cleanup = useCallback(() => {
if (scene && previewLineRef.current) {
previewLineRef.current = clearPreviewLine(previewLineRef.current, scene);
}
}, [scene]);
return {
handleClick,
handleMouseMove,
handleRightClick,
cleanup
};
};