1// SPDX-License-Identifier: GPL-2.0-only
2// Copyright (c) 2025-present FERS Contributors (see AUTHORS.md).
4import { useEffect, useMemo, useState } from 'react';
5import { Line } from '@react-three/drei';
6import { Vector3 } from 'three';
7import { invoke } from '@tauri-apps/api/core';
8import { useScenarioStore, Platform } from '@/stores/scenarioStore';
9import { fersColors } from '@/theme';
11const NUM_PATH_POINTS = 100; // The resolution of the rendered path line.
13// --- Type definitions for Tauri backend communication ---
14type InterpolationType = 'static' | 'linear' | 'cubic';
16interface InterpolatedPoint {
17 x: number; // Corresponds to ENU X -> Three.js X
18 y: number; // Corresponds to ENU Y -> Three.js -Z
19 z: number; // Corresponds to ENU Altitude -> Three.js Y
23 * A component that fetches and renders the interpolated motion path for a given platform.
24 * It communicates with the Tauri backend to compute the path using the libfers core.
25 * @param {object} props - The component props.
26 * @param {Platform} props.platform - The platform whose motion path should be rendered.
28export function MotionPathLine({ platform }: { platform: Platform }) {
29 const [pathPoints, setPathPoints] = useState<Vector3[] | null>(null);
30 const showError = useScenarioStore((state) => state.showError);
32 const { waypoints, interpolation } = platform.motionPath;
35 const fetchPath = async () => {
36 if (waypoints.length === 0) {
41 // For static or single-waypoint paths, no need to call the backend.
42 // A static object has no visible path.
43 if (interpolation === 'static' || waypoints.length < 2) {
49 // The frontend 'PositionWaypoint' has an 'altitude' field, which the
50 // Rust backend expects. The Rust `MotionWaypoint` struct will map this
51 // correctly to the C-API's 'z' field.
52 const points = await invoke<InterpolatedPoint[]>(
53 'get_interpolated_motion_path',
56 interpType: interpolation as InterpolationType,
57 numPoints: NUM_PATH_POINTS,
61 const vectors = points.map(
62 // ENU to Three.js coordinate system mapping:
63 // Backend X (East) -> Three.js X
64 // Backend Z (Up) -> Three.js Y
65 // Backend Y (North) -> Three.js -Z
66 (p) => new Vector3(p.x, p.z, -p.y)
68 setPathPoints(vectors);
71 error instanceof Error ? error.message : String(error);
73 `Failed to fetch motion path for platform ${platform.name}:`,
77 `Failed to get motion path for ${platform.name}: ${errorMessage}`
84 }, [waypoints, interpolation, platform.name, showError]);
86 const linePoints = useMemo(() => {
87 if (!pathPoints || pathPoints.length < 2) return undefined;
98 color={fersColors.physics.motionPath}