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(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 ( ); }