Files
Dwinzo_Demo/app/src/modules/simulation/vehicle/preDefinedPath/lineSegment.tsx

88 lines
2.6 KiB
TypeScript
Raw Normal View History

2025-08-13 15:24:32 +05:30
import { Line } from "@react-three/drei";
import { useThree } from "@react-three/fiber";
import { useEffect, useMemo, useRef } from "react";
import { CubicBezierCurve3, LineCurve3, Plane, Vector3 } from "three";
export default function LineSegment({
index,
createdPoints,
updatePoints,
insertPoint,
}: {
index: number;
createdPoints: any[]; // Array of points with position, isCurved, handleA, handleB
updatePoints: (i0: number, p0: Vector3, i1: number, p1: Vector3) => void;
insertPoint?: (index: number, point: Vector3) => void;
}) {
const { gl, raycaster, camera, controls } = useThree();
const plane = new Plane(new Vector3(0, 1, 0), 0);
const dragStart = useRef<Vector3 | null>(null);
// ======== Curve or Line Points ========
const curvePoints = useMemo(() => {
if (!createdPoints || index + 1 >= createdPoints.length) return [];
const current = createdPoints[index];
const next = createdPoints[index + 1];
const starts = new Vector3(...current.position);
const ends = new Vector3(...next.position);
const useCurve =
(current.isCurved && current.handleB) || (next.isCurved && next.handleA);
const hB = current.handleB ? new Vector3(...current.handleB) : starts;
const hA = next.handleA ? new Vector3(...next.handleA) : ends;
const curve = useCurve
? new CubicBezierCurve3(starts, hB, hA, ends)
: new LineCurve3(starts, ends);
return curve.getPoints(useCurve ? 100 : 2);
}, [createdPoints, index]);
// ======== Events ========
const onPointerUp = () => {
dragStart.current = null;
gl.domElement.style.cursor = "default";
if (controls) (controls as any).enabled = true;
};
const onClickLine = () => {
const intersection = new Vector3();
if (raycaster.ray.intersectPlane(plane, intersection)) {
const start = new Vector3(...createdPoints[index].position);
const end = new Vector3(...createdPoints[index + 1].position);
const segLen = start.distanceTo(end);
const distToStart = start.distanceTo(intersection);
const distToEnd = end.distanceTo(intersection);
if (
distToStart > 0.01 &&
distToEnd > 0.01 &&
distToStart + distToEnd <= segLen + 0.01
) {
insertPoint?.(index + 1, intersection);
}
}
};
useEffect(() => {
gl.domElement.addEventListener("pointerup", onPointerUp);
return () => {
gl.domElement.removeEventListener("pointerup", onPointerUp);
};
}, []);
// ======== Render ========
return (
<Line
points={curvePoints}
color="purple"
lineWidth={2}
onPointerDown={onClickLine}
onPointerUp={onPointerUp}
/>
);
}