import * as React from 'react' import { QuadraticBezierCurve3, Vector3 } from 'three' import { Line2 } from 'three-stdlib' import { Line, LineProps } from './Line' import { Object3DNode } from '@react-three/fiber' import { ForwardRefComponent } from '../helpers/ts-utils' type Props = Omit & { start: Vector3 | [number, number, number] end: Vector3 | [number, number, number] mid?: Vector3 | [number, number, number] segments?: number } export type Line2Props = Object3DNode & { setPoints: ( start: Vector3 | [number, number, number], end: Vector3 | [number, number, number], mid: Vector3 | [number, number, number] ) => void } const v = /* @__PURE__ */ new Vector3() export const QuadraticBezierLine: ForwardRefComponent = /* @__PURE__ */ React.forwardRef< Line2Props, Props >(function QuadraticBezierLine({ start = [0, 0, 0], end = [0, 0, 0], mid, segments = 20, ...rest }, forwardref) { const ref = React.useRef(null!) React.useImperativeHandle(forwardref, () => ref.current) const [curve] = React.useState(() => new QuadraticBezierCurve3(undefined as any, undefined as any, undefined as any)) const getPoints = React.useCallback((start, end, mid, segments = 20) => { if (start instanceof Vector3) curve.v0.copy(start) else curve.v0.set(...(start as [number, number, number])) if (end instanceof Vector3) curve.v2.copy(end) else curve.v2.set(...(end as [number, number, number])) if (mid instanceof Vector3) { curve.v1.copy(mid) } else if (Array.isArray(mid)) { curve.v1.set(...(mid as [number, number, number])) } else { curve.v1.copy( curve.v0 .clone() .add(curve.v2.clone().sub(curve.v0)) .add(v.set(0, curve.v0.y - curve.v2.y, 0)) ) } return curve.getPoints(segments) }, []) React.useLayoutEffect(() => { ref.current.setPoints = ( start: Vector3 | [number, number, number], end: Vector3 | [number, number, number], mid: Vector3 | [number, number, number] ) => { const points = getPoints(start, end, mid) if (ref.current.geometry) ref.current.geometry.setPositions(points.map((p) => p.toArray()).flat()) } }, []) const points = React.useMemo(() => getPoints(start, end, mid, segments), [start, end, mid, segments]) return })