208 lines
5.8 KiB
TypeScript
208 lines
5.8 KiB
TypeScript
import { writable } from "svelte/store"
|
|
import type { LatLngExpression } from "leaflet";
|
|
import L from "leaflet";
|
|
|
|
import { getCsrfToken } from "./auth";
|
|
|
|
|
|
interface TrajectoryPoint {
|
|
altitude: number;
|
|
datetime: string;
|
|
latitude: number;
|
|
longitude: number;
|
|
}
|
|
|
|
interface PredictionStage {
|
|
stage: string;
|
|
trajectory: TrajectoryPoint[];
|
|
}
|
|
|
|
interface ParsedPrediction {
|
|
flight_path: [number, number, number][];
|
|
launch: {
|
|
latlng: LatLngExpression;
|
|
datetime: Date;
|
|
};
|
|
burst: {
|
|
latlng: LatLngExpression;
|
|
datetime: Date;
|
|
};
|
|
landing: {
|
|
latlng: LatLngExpression;
|
|
datetime: Date;
|
|
};
|
|
profile: string;
|
|
flight_time: number;
|
|
}
|
|
|
|
|
|
export const latestPrediction = writable({
|
|
metadata: {
|
|
complete_datetime: "",
|
|
start_datetime: ""
|
|
},
|
|
prediction: [
|
|
{
|
|
stage: "",
|
|
trajectory: [
|
|
{
|
|
altitude: 0.0,
|
|
datetime: "",
|
|
latitude: 0.0,
|
|
longitude: 0.0
|
|
}
|
|
]
|
|
}
|
|
]
|
|
});
|
|
|
|
export const latestPredictionParsed = writable({} as ParsedPrediction);
|
|
|
|
function getLatestDataset() {
|
|
const now = new Date();
|
|
const hours = now.getUTCHours();
|
|
const minutes = now.getUTCMinutes();
|
|
const seconds = now.getUTCSeconds();
|
|
|
|
// Round down to the nearest 6-hour interval
|
|
const roundedHours = Math.floor(hours / 6) * 6;
|
|
const roundedDate = new Date(now);
|
|
roundedDate.setUTCHours(roundedHours, 0, 0, 0);
|
|
|
|
// Subtract 6 hours to account for the lag
|
|
roundedDate.setUTCHours(roundedDate.getUTCHours() - 6);
|
|
|
|
return roundedDate.toISOString();
|
|
}
|
|
|
|
function formatLaunchDateTime(dateObj: string | Date, timeStr: string): string {
|
|
// Ensure date is a Date object
|
|
const date = new Date(dateObj);
|
|
|
|
// Extract date components
|
|
const year = date.getFullYear();
|
|
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
const day = String(date.getDate()).padStart(2, '0');
|
|
|
|
// Format time (ensure it has seconds)
|
|
let formattedTime = timeStr;
|
|
if (timeStr.split(':').length === 2) {
|
|
formattedTime += ':00'; // Add seconds if missing
|
|
}
|
|
|
|
// Combine into ISO string
|
|
const isoString = new Date(`${year}-${month}-${day}T${formattedTime}Z`).toISOString();
|
|
|
|
return isoString;
|
|
}
|
|
|
|
export const getForecast = async (flightParameters: Record<string, any>, startDate: string, startTime: string): Promise<void> => {
|
|
const launch_datetime = formatLaunchDateTime(startDate, startTime);
|
|
|
|
// Create request object
|
|
flightParameters.dataset = getLatestDataset();
|
|
flightParameters.launch_datetime = launch_datetime;
|
|
|
|
console.log("Sending request:", flightParameters);
|
|
|
|
try {
|
|
// Example POST request - replace with your actual API endpoint
|
|
const csrfToken = await getCsrfToken();
|
|
if (!csrfToken) {
|
|
throw new Error('CSRF token not found');
|
|
}
|
|
|
|
const response = await fetch('http://localhost:8000/api/predictions', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-CSRFToken': csrfToken
|
|
},
|
|
body: JSON.stringify(flightParameters),
|
|
credentials: 'include'
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
console.log("Forecast response:", data);
|
|
|
|
latestPrediction.set(data.result);
|
|
latestPredictionParsed.set(parsePrediction(data.result.prediction));
|
|
|
|
alert("Forecast request successful!");
|
|
// Handle the response data as needed
|
|
} catch (error) {
|
|
console.error("Error sending forecast request:", error);
|
|
alert("Error getting forecast: " + error);
|
|
}
|
|
};
|
|
|
|
export function parsePrediction(prediction: PredictionStage[]): ParsedPrediction {
|
|
const flight_path: [number, number, number][] = [];
|
|
const launch: { latlng: LatLngExpression; datetime: Date } = {} as any;
|
|
const burst: { latlng: LatLngExpression; datetime: Date } = {} as any;
|
|
const landing: { latlng: LatLngExpression; datetime: Date } = {} as any;
|
|
|
|
const ascent = prediction[0].trajectory;
|
|
const descent = prediction[1].trajectory;
|
|
|
|
// Add the ascent track to the flight path array.
|
|
ascent.forEach((item) => {
|
|
let lon = item.longitude;
|
|
if (lon > 180.0) {
|
|
lon -= 360.0;
|
|
}
|
|
|
|
flight_path.push([item.latitude, lon, item.altitude]);
|
|
});
|
|
|
|
// Add the descent track to the flight path array.
|
|
descent.forEach((item) => {
|
|
let lon = item.longitude;
|
|
if (lon > 180.0) {
|
|
lon -= 360.0;
|
|
}
|
|
|
|
flight_path.push([item.latitude, lon, item.altitude]);
|
|
});
|
|
|
|
// Populate the launch, burst, and landing points
|
|
const launchObj = ascent[0];
|
|
let lon = launchObj.longitude;
|
|
if (lon > 180.0) {
|
|
lon -= 360.0;
|
|
}
|
|
launch.latlng = L.latLng([launchObj.latitude, lon, launchObj.altitude]);
|
|
launch.datetime = new Date(launchObj.datetime);
|
|
|
|
const burstObj = descent[0];
|
|
lon = burstObj.longitude;
|
|
if (lon > 180.0) {
|
|
lon -= 360.0;
|
|
}
|
|
burst.latlng = L.latLng([burstObj.latitude, lon, burstObj.altitude]);
|
|
burst.datetime = new Date(burstObj.datetime);
|
|
|
|
const landingObj = descent[descent.length - 1];
|
|
lon = landingObj.longitude;
|
|
if (lon > 180.0) {
|
|
lon -= 360.0;
|
|
}
|
|
landing.latlng = L.latLng([landingObj.latitude, lon, landingObj.altitude]);
|
|
landing.datetime = new Date(landingObj.datetime);
|
|
|
|
const profile = prediction[1].stage === "descent" ? "standard_profile" : "float_profile";
|
|
const flight_time = (new Date(landing.datetime).getTime() - new Date(launch.datetime).getTime()) / 1000;
|
|
|
|
return {
|
|
flight_path,
|
|
launch,
|
|
burst,
|
|
landing,
|
|
profile,
|
|
flight_time,
|
|
};
|
|
}
|