upstream pull + signIn/Up
This commit is contained in:
@@ -1,190 +1,190 @@
|
||||
import * as THREE from 'three';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { useThree, useFrame } from '@react-three/fiber';
|
||||
import { useToolMode } from '../../../store/store';
|
||||
import { Html } from '@react-three/drei';
|
||||
|
||||
const MeasurementTool = () => {
|
||||
const { gl, raycaster, pointer, camera, scene } = useThree();
|
||||
const { toolMode } = useToolMode();
|
||||
|
||||
const [points, setPoints] = useState<THREE.Vector3[]>([]);
|
||||
const [tubeGeometry, setTubeGeometry] = useState<THREE.TubeGeometry | null>(null);
|
||||
const groupRef = useRef<THREE.Group>(null);
|
||||
const [startConePosition, setStartConePosition] = useState<THREE.Vector3 | null>(null);
|
||||
const [endConePosition, setEndConePosition] = useState<THREE.Vector3 | null>(null);
|
||||
const [startConeQuaternion, setStartConeQuaternion] = useState(new THREE.Quaternion());
|
||||
const [endConeQuaternion, setEndConeQuaternion] = useState(new THREE.Quaternion());
|
||||
const [coneSize, setConeSize] = useState({ radius: 0.2, height: 0.5 });
|
||||
|
||||
|
||||
const MIN_RADIUS = 0.001, MAX_RADIUS = 0.1;
|
||||
const MIN_CONE_RADIUS = 0.01, MAX_CONE_RADIUS = 0.4;
|
||||
const MIN_CONE_HEIGHT = 0.035, MAX_CONE_HEIGHT = 2.0;
|
||||
|
||||
useEffect(() => {
|
||||
const canvasElement = gl.domElement;
|
||||
let drag = false;
|
||||
let isLeftMouseDown = false;
|
||||
|
||||
const onMouseDown = () => {
|
||||
isLeftMouseDown = true;
|
||||
drag = false;
|
||||
};
|
||||
|
||||
const onMouseUp = (evt: any) => {
|
||||
isLeftMouseDown = false;
|
||||
if (evt.button === 0 && !drag) {
|
||||
raycaster.setFromCamera(pointer, camera);
|
||||
const intersects = raycaster.intersectObjects(scene.children, true).filter(intersect => !intersect.object.name.includes("Roof") && !intersect.object.name.includes("MeasurementReference") && !(intersect.object.type === "GridHelper"));
|
||||
|
||||
if (intersects.length > 0) {
|
||||
const intersectionPoint = intersects[0].point.clone();
|
||||
if (points.length < 2) {
|
||||
setPoints([...points, intersectionPoint]);
|
||||
} else {
|
||||
setPoints([intersectionPoint]);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseMove = () => {
|
||||
if (isLeftMouseDown) drag = true;
|
||||
};
|
||||
|
||||
const onContextMenu = (evt: any) => {
|
||||
evt.preventDefault();
|
||||
if (!drag) {
|
||||
evt.preventDefault();
|
||||
setPoints([]);
|
||||
setTubeGeometry(null);
|
||||
}
|
||||
};
|
||||
|
||||
if (toolMode === "MeasurementScale") {
|
||||
canvasElement.addEventListener("pointerdown", onMouseDown);
|
||||
canvasElement.addEventListener("pointermove", onMouseMove);
|
||||
canvasElement.addEventListener("pointerup", onMouseUp);
|
||||
canvasElement.addEventListener("contextmenu", onContextMenu);
|
||||
} else {
|
||||
resetMeasurement();
|
||||
setPoints([]);
|
||||
}
|
||||
|
||||
return () => {
|
||||
canvasElement.removeEventListener("pointerdown", onMouseDown);
|
||||
canvasElement.removeEventListener("pointermove", onMouseMove);
|
||||
canvasElement.removeEventListener("pointerup", onMouseUp);
|
||||
canvasElement.removeEventListener("contextmenu", onContextMenu);
|
||||
};
|
||||
}, [toolMode, camera, raycaster, pointer, scene, points]);
|
||||
|
||||
useFrame(() => {
|
||||
if (points.length === 1) {
|
||||
raycaster.setFromCamera(pointer, camera);
|
||||
const intersects = raycaster.intersectObjects(scene.children, true).filter(intersect => !intersect.object.name.includes("Roof") && !intersect.object.name.includes("MeasurementReference") && !(intersect.object.type === "GridHelper"));
|
||||
|
||||
if (intersects.length > 0) {
|
||||
updateMeasurement(points[0], intersects[0].point);
|
||||
}
|
||||
} else if (points.length === 2) {
|
||||
updateMeasurement(points[0], points[1]);
|
||||
} else {
|
||||
resetMeasurement();
|
||||
}
|
||||
});
|
||||
|
||||
const updateMeasurement = (start: THREE.Vector3, end: THREE.Vector3) => {
|
||||
const distance = start.distanceTo(end);
|
||||
|
||||
const radius = THREE.MathUtils.clamp(distance * 0.02, MIN_RADIUS, MAX_RADIUS);
|
||||
const coneRadius = THREE.MathUtils.clamp(distance * 0.05, MIN_CONE_RADIUS, MAX_CONE_RADIUS);
|
||||
const coneHeight = THREE.MathUtils.clamp(distance * 0.2, MIN_CONE_HEIGHT, MAX_CONE_HEIGHT);
|
||||
|
||||
setConeSize({ radius: coneRadius, height: coneHeight });
|
||||
|
||||
const direction = new THREE.Vector3().subVectors(end, start).normalize();
|
||||
|
||||
const offset = direction.clone().multiplyScalar(coneHeight * 0.5);
|
||||
|
||||
let tubeStart = start.clone().add(offset);
|
||||
let tubeEnd = end.clone().sub(offset);
|
||||
|
||||
tubeStart.y = Math.max(tubeStart.y, 0);
|
||||
tubeEnd.y = Math.max(tubeEnd.y, 0);
|
||||
|
||||
const curve = new THREE.CatmullRomCurve3([tubeStart, tubeEnd]);
|
||||
setTubeGeometry(new THREE.TubeGeometry(curve, 20, radius, 8, false));
|
||||
|
||||
setStartConePosition(tubeStart);
|
||||
setEndConePosition(tubeEnd);
|
||||
setStartConeQuaternion(getArrowOrientation(start, end));
|
||||
setEndConeQuaternion(getArrowOrientation(end, start));
|
||||
};
|
||||
|
||||
const resetMeasurement = () => {
|
||||
setTubeGeometry(null);
|
||||
setStartConePosition(null);
|
||||
setEndConePosition(null);
|
||||
};
|
||||
|
||||
const getArrowOrientation = (start: THREE.Vector3, end: THREE.Vector3) => {
|
||||
const direction = new THREE.Vector3().subVectors(end, start).normalize().negate();
|
||||
const quaternion = new THREE.Quaternion();
|
||||
quaternion.setFromUnitVectors(new THREE.Vector3(0, 1, 0), direction);
|
||||
return quaternion;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (points.length === 2) {
|
||||
console.log(points[0].distanceTo(points[1]));
|
||||
}
|
||||
}, [points])
|
||||
|
||||
return (
|
||||
<group ref={groupRef} name="MeasurementGroup">
|
||||
{startConePosition && (
|
||||
<mesh name='MeasurementReference' position={startConePosition} quaternion={startConeQuaternion}>
|
||||
<coneGeometry args={[coneSize.radius, coneSize.height, 16]} />
|
||||
<meshBasicMaterial color="yellow" />
|
||||
</mesh>
|
||||
)}
|
||||
{endConePosition && (
|
||||
<mesh name='MeasurementReference' position={endConePosition} quaternion={endConeQuaternion}>
|
||||
<coneGeometry args={[coneSize.radius, coneSize.height, 16]} />
|
||||
<meshBasicMaterial color="yellow" />
|
||||
</mesh>
|
||||
)}
|
||||
{tubeGeometry && (
|
||||
<mesh name='MeasurementReference' geometry={tubeGeometry}>
|
||||
<meshBasicMaterial color="yellow" />
|
||||
</mesh>
|
||||
)}
|
||||
|
||||
{startConePosition && endConePosition && (
|
||||
<Html
|
||||
as="div"
|
||||
center
|
||||
zIndexRange={[1, 0]}
|
||||
style={{
|
||||
padding: "10px",
|
||||
color: "white",
|
||||
borderRadius: "8px",
|
||||
textAlign: "center",
|
||||
fontFamily: "Arial, sans-serif",
|
||||
}}
|
||||
transform
|
||||
sprite
|
||||
scale={THREE.MathUtils.clamp(startConePosition.distanceTo(endConePosition) * 0.25, 0, 10)}
|
||||
position={[(startConePosition.x + endConePosition.x) / 2, (startConePosition.y + endConePosition.y) / 2, (startConePosition.z + endConePosition.z) / 2]}
|
||||
>
|
||||
<div style={{ color: "black" }} >{startConePosition.distanceTo(endConePosition).toFixed(2)} m</div>
|
||||
</Html>
|
||||
)}
|
||||
</group>
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
export default MeasurementTool;
|
||||
import * as THREE from 'three';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { useThree, useFrame } from '@react-three/fiber';
|
||||
import { useToolMode } from '../../../store/store';
|
||||
import { Html } from '@react-three/drei';
|
||||
|
||||
const MeasurementTool = () => {
|
||||
const { gl, raycaster, pointer, camera, scene } = useThree();
|
||||
const { toolMode } = useToolMode();
|
||||
|
||||
const [points, setPoints] = useState<THREE.Vector3[]>([]);
|
||||
const [tubeGeometry, setTubeGeometry] = useState<THREE.TubeGeometry | null>(null);
|
||||
const groupRef = useRef<THREE.Group>(null);
|
||||
const [startConePosition, setStartConePosition] = useState<THREE.Vector3 | null>(null);
|
||||
const [endConePosition, setEndConePosition] = useState<THREE.Vector3 | null>(null);
|
||||
const [startConeQuaternion, setStartConeQuaternion] = useState(new THREE.Quaternion());
|
||||
const [endConeQuaternion, setEndConeQuaternion] = useState(new THREE.Quaternion());
|
||||
const [coneSize, setConeSize] = useState({ radius: 0.2, height: 0.5 });
|
||||
|
||||
|
||||
const MIN_RADIUS = 0.001, MAX_RADIUS = 0.1;
|
||||
const MIN_CONE_RADIUS = 0.01, MAX_CONE_RADIUS = 0.4;
|
||||
const MIN_CONE_HEIGHT = 0.035, MAX_CONE_HEIGHT = 2.0;
|
||||
|
||||
useEffect(() => {
|
||||
const canvasElement = gl.domElement;
|
||||
let drag = false;
|
||||
let isLeftMouseDown = false;
|
||||
|
||||
const onMouseDown = () => {
|
||||
isLeftMouseDown = true;
|
||||
drag = false;
|
||||
};
|
||||
|
||||
const onMouseUp = (evt: any) => {
|
||||
isLeftMouseDown = false;
|
||||
if (evt.button === 0 && !drag) {
|
||||
raycaster.setFromCamera(pointer, camera);
|
||||
const intersects = raycaster.intersectObjects(scene.children, true).filter(intersect => !intersect.object.name.includes("Roof") && !intersect.object.name.includes("MeasurementReference") && !(intersect.object.type === "GridHelper"));
|
||||
|
||||
if (intersects.length > 0) {
|
||||
const intersectionPoint = intersects[0].point.clone();
|
||||
if (points.length < 2) {
|
||||
setPoints([...points, intersectionPoint]);
|
||||
} else {
|
||||
setPoints([intersectionPoint]);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseMove = () => {
|
||||
if (isLeftMouseDown) drag = true;
|
||||
};
|
||||
|
||||
const onContextMenu = (evt: any) => {
|
||||
evt.preventDefault();
|
||||
if (!drag) {
|
||||
evt.preventDefault();
|
||||
setPoints([]);
|
||||
setTubeGeometry(null);
|
||||
}
|
||||
};
|
||||
|
||||
if (toolMode === "MeasurementScale") {
|
||||
canvasElement.addEventListener("pointerdown", onMouseDown);
|
||||
canvasElement.addEventListener("pointermove", onMouseMove);
|
||||
canvasElement.addEventListener("pointerup", onMouseUp);
|
||||
canvasElement.addEventListener("contextmenu", onContextMenu);
|
||||
} else {
|
||||
resetMeasurement();
|
||||
setPoints([]);
|
||||
}
|
||||
|
||||
return () => {
|
||||
canvasElement.removeEventListener("pointerdown", onMouseDown);
|
||||
canvasElement.removeEventListener("pointermove", onMouseMove);
|
||||
canvasElement.removeEventListener("pointerup", onMouseUp);
|
||||
canvasElement.removeEventListener("contextmenu", onContextMenu);
|
||||
};
|
||||
}, [toolMode, camera, raycaster, pointer, scene, points]);
|
||||
|
||||
useFrame(() => {
|
||||
if (points.length === 1) {
|
||||
raycaster.setFromCamera(pointer, camera);
|
||||
const intersects = raycaster.intersectObjects(scene.children, true).filter(intersect => !intersect.object.name.includes("Roof") && !intersect.object.name.includes("MeasurementReference") && !(intersect.object.type === "GridHelper"));
|
||||
|
||||
if (intersects.length > 0) {
|
||||
updateMeasurement(points[0], intersects[0].point);
|
||||
}
|
||||
} else if (points.length === 2) {
|
||||
updateMeasurement(points[0], points[1]);
|
||||
} else {
|
||||
resetMeasurement();
|
||||
}
|
||||
});
|
||||
|
||||
const updateMeasurement = (start: THREE.Vector3, end: THREE.Vector3) => {
|
||||
const distance = start.distanceTo(end);
|
||||
|
||||
const radius = THREE.MathUtils.clamp(distance * 0.02, MIN_RADIUS, MAX_RADIUS);
|
||||
const coneRadius = THREE.MathUtils.clamp(distance * 0.05, MIN_CONE_RADIUS, MAX_CONE_RADIUS);
|
||||
const coneHeight = THREE.MathUtils.clamp(distance * 0.2, MIN_CONE_HEIGHT, MAX_CONE_HEIGHT);
|
||||
|
||||
setConeSize({ radius: coneRadius, height: coneHeight });
|
||||
|
||||
const direction = new THREE.Vector3().subVectors(end, start).normalize();
|
||||
|
||||
const offset = direction.clone().multiplyScalar(coneHeight * 0.5);
|
||||
|
||||
let tubeStart = start.clone().add(offset);
|
||||
let tubeEnd = end.clone().sub(offset);
|
||||
|
||||
tubeStart.y = Math.max(tubeStart.y, 0);
|
||||
tubeEnd.y = Math.max(tubeEnd.y, 0);
|
||||
|
||||
const curve = new THREE.CatmullRomCurve3([tubeStart, tubeEnd]);
|
||||
setTubeGeometry(new THREE.TubeGeometry(curve, 20, radius, 8, false));
|
||||
|
||||
setStartConePosition(tubeStart);
|
||||
setEndConePosition(tubeEnd);
|
||||
setStartConeQuaternion(getArrowOrientation(start, end));
|
||||
setEndConeQuaternion(getArrowOrientation(end, start));
|
||||
};
|
||||
|
||||
const resetMeasurement = () => {
|
||||
setTubeGeometry(null);
|
||||
setStartConePosition(null);
|
||||
setEndConePosition(null);
|
||||
};
|
||||
|
||||
const getArrowOrientation = (start: THREE.Vector3, end: THREE.Vector3) => {
|
||||
const direction = new THREE.Vector3().subVectors(end, start).normalize().negate();
|
||||
const quaternion = new THREE.Quaternion();
|
||||
quaternion.setFromUnitVectors(new THREE.Vector3(0, 1, 0), direction);
|
||||
return quaternion;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (points.length === 2) {
|
||||
console.log(points[0].distanceTo(points[1]));
|
||||
}
|
||||
}, [points])
|
||||
|
||||
return (
|
||||
<group ref={groupRef} name="MeasurementGroup">
|
||||
{startConePosition && (
|
||||
<mesh name='MeasurementReference' position={startConePosition} quaternion={startConeQuaternion}>
|
||||
<coneGeometry args={[coneSize.radius, coneSize.height, 16]} />
|
||||
<meshBasicMaterial color="yellow" />
|
||||
</mesh>
|
||||
)}
|
||||
{endConePosition && (
|
||||
<mesh name='MeasurementReference' position={endConePosition} quaternion={endConeQuaternion}>
|
||||
<coneGeometry args={[coneSize.radius, coneSize.height, 16]} />
|
||||
<meshBasicMaterial color="yellow" />
|
||||
</mesh>
|
||||
)}
|
||||
{tubeGeometry && (
|
||||
<mesh name='MeasurementReference' geometry={tubeGeometry}>
|
||||
<meshBasicMaterial color="yellow" />
|
||||
</mesh>
|
||||
)}
|
||||
|
||||
{startConePosition && endConePosition && (
|
||||
<Html
|
||||
as="div"
|
||||
center
|
||||
zIndexRange={[1, 0]}
|
||||
style={{
|
||||
padding: "10px",
|
||||
color: "white",
|
||||
borderRadius: "8px",
|
||||
textAlign: "center",
|
||||
fontFamily: "Arial, sans-serif",
|
||||
}}
|
||||
transform
|
||||
sprite
|
||||
scale={THREE.MathUtils.clamp(startConePosition.distanceTo(endConePosition) * 0.25, 0, 10)}
|
||||
position={[(startConePosition.x + endConePosition.x) / 2, (startConePosition.y + endConePosition.y) / 2, (startConePosition.z + endConePosition.z) / 2]}
|
||||
>
|
||||
<div style={{ color: "black" }} >{startConePosition.distanceTo(endConePosition).toFixed(2)} m</div>
|
||||
</Html>
|
||||
)}
|
||||
</group>
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
export default MeasurementTool;
|
||||
|
||||
Reference in New Issue
Block a user