Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
Magnus Alexander Strømseng committed Mar 19, 2024
2 parents 833b443 + e952540 commit d4c84ef
Show file tree
Hide file tree
Showing 4 changed files with 245 additions and 0 deletions.
6 changes: 6 additions & 0 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"luxon": "^3.4.4",
"next": "14.1.0",
"next-themes": "^0.2.1",
"node-geometry-library": "^1.2.6",
"ol": "^8.2.0",
"ol-ext": "^4.0.14",
"ol-mapbox-style": "^12.2.0",
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import Link from "next/link";
// Dynamic import because of leaflet and globe.gl ssr problem with next.js
import dynamic from "next/dynamic";
import SatelliteFetcher from "@/components/map/SatelliteFetcher";
import SatelliteDataTable from "@/components/satelliteData/SatelliteDataTable";

const MyCustomMap = dynamic(() => import("@/components/map/MyCustomMap"), {
ssr: false,
Expand Down Expand Up @@ -62,6 +63,8 @@ export default async function Home() {

return (
<main>
<SatelliteDataTable />

<SatelliteFetcher useExampleData={true} />

<MyCustomMap />
Expand Down
235 changes: 235 additions & 0 deletions frontend/src/components/satelliteData/SatelliteDataTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
// This component displays a table of satellite data including position and country
"use client";
import React, { useEffect, useState } from "react";
import { exampleData } from "../map/exampleSatData";
import { SatelliteData, mapRawDataToSatData } from "@/lib/mapHelpers";
import {
Table,
TableBody,
TableCaption,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import * as satellite from "satellite.js";
import { PolyUtil } from "node-geometry-library";
import globeData from "@components/map/githubglobe/files/globe-data.json";

const satellitesShown = 10; // Maximum number of satellites to display
const timeInterval = 1000; // Time interval for updating satellite positions in milliseconds

// Extends SatelliteData with calculated position properties
interface SatelliteDataWithPosition extends SatelliteData {
latitudeDeg: string;
longitudeDeg: string;
altitude: string;
velocity: string;
}

export default function SatelliteDataTable() {
const [satData, setSatData] = useState<SatelliteDataWithPosition[]>([]);

useEffect(() => {
// Updates satellite positions at specified intervals
const updateSatellitePositions = () => {
const updatedData = mapRawDataToSatData(exampleData)
.slice(0, satellitesShown)
.map((data) => {
const positionAndVelocity = satellite.propagate(
data.satrec,
new Date(),
);

if (
positionAndVelocity.position &&
typeof positionAndVelocity.position !== "boolean"
) {
const gmst = satellite.gstime(new Date()); // Calculates Greenwich Mean Sidereal Time
const positionGd = satellite.eciToGeodetic(
positionAndVelocity.position,
gmst,
);

// Extracts velocity from positionAndVelocity if it is not false
var velocityEci = positionAndVelocity.velocity;

if (typeof velocityEci !== "boolean") {
// Calculate the magnitude of the velocity vector if velocityEci is not false
var velocityMagnitude = Math.sqrt(
velocityEci.x * velocityEci.x +
velocityEci.y * velocityEci.y +
velocityEci.z * velocityEci.z,
);

// Convert velocity from kilometers per second (km/s) to kilometers per hour (km/h)
velocityMagnitude = velocityMagnitude * 3600;
} else {
// Set velocityMagnitude to NaN if velocityEci is false
velocityMagnitude = NaN;
}

// Converts geodetic position to readable format
const latitudeDeg = satellite.degreesLat(
positionGd.latitude,
);
const longitudeDeg = satellite.degreesLong(
positionGd.longitude,
);
const altitude = positionGd.height;

return {
...data,
latitudeDeg: latitudeDeg.toFixed(2),
longitudeDeg: longitudeDeg.toFixed(2),
altitude: altitude.toFixed(2),
velocity: velocityMagnitude.toFixed(0),
};
} else {
return {
...data,
latitudeDeg: "N/A",
longitudeDeg: "N/A",
altitude: "N/A",
velocity: "N/A",
};
}
});

setSatData(updatedData);
};

// Performs an initial update and sets the interval for further updates
updateSatellitePositions();
const intervalId = setInterval(() => {
updateSatellitePositions();
}, timeInterval);

// Cleans up the interval when the component unmounts
return () => clearInterval(intervalId);
}, []);

return (
<div className="m-10 flex w-full flex-col items-center justify-center">
<Table className="w-1/2">
<TableCaption>Satellite Data</TableCaption>
<TableHeader>
<TableRow>
<TableHead className="w-1/6">Satellite</TableHead>
<TableHead className="w-1/6">Latitude</TableHead>
<TableHead className="w-1/6">Longitude</TableHead>
<TableHead className="w-1/6">Altitude</TableHead>
<TableHead className="w-1/6">Velocity</TableHead>
<TableHead className="w-1/6">Country</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{satData.map((data, index) => {
let country = "Ocean"; // Default to Ocean if no country is found
globeData.features.forEach((countryFeature) => {
// Checks if the satellite is within a country's bounding box to reduce the number of polygons to check
const boundingBoxPoints = [
{
lat: countryFeature.bbox[1],
lng: countryFeature.bbox[0],
},
{
lat: countryFeature.bbox[3],
lng: countryFeature.bbox[0],
},
{
lat: countryFeature.bbox[3],
lng: countryFeature.bbox[2],
},
{
lat: countryFeature.bbox[1],
lng: countryFeature.bbox[2],
},
];

if (
PolyUtil.containsLocation(
{
lat: Number(data.latitudeDeg),
lng: Number(data.longitudeDeg),
},
boundingBoxPoints,
)
) {
// Handles polygons to accurately find the country
if (countryFeature.geometry.type == "Polygon") {
let boundingPolygon =
countryFeature.geometry.coordinates[0].map(
(coordinate) => ({
lat: Number(coordinate[1]),
lng: Number(coordinate[0]),
}),
);

if (
PolyUtil.containsLocation(
{
lat: Number(data.latitudeDeg),
lng: Number(data.longitudeDeg),
},
boundingPolygon,
)
) {
country =
countryFeature.properties.ADMIN;
}
} else if (
countryFeature.geometry.type ==
"MultiPolygon"
) {
// Loop through each polygon array in the MultiPolygon
const multiPolygon = countryFeature.geometry
.coordinates as number[][][][];
multiPolygon.forEach((polygon) => {
let boundingPolygon = polygon[0].map(
(coordinate) => ({
lat: Number(coordinate[1]),
lng: Number(coordinate[0]),
}),
);

if (
PolyUtil.containsLocation(
{
lat: Number(
data.latitudeDeg,
),
lng: Number(
data.longitudeDeg,
),
},
boundingPolygon,
)
) {
country =
countryFeature.properties.ADMIN;
}
});
}
}
});

return (
<TableRow key={index}>
<TableCell>{data.name}</TableCell>
<TableCell>{data.latitudeDeg}° N</TableCell>
<TableCell>{data.longitudeDeg}° E</TableCell>
<TableCell>
{(Number(data.altitude) * 10).toFixed(0)}{" "}
moh
</TableCell>
<TableCell>{data.velocity} km/h</TableCell>
<TableCell>{country}</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
</div>
);
}

0 comments on commit d4c84ef

Please sign in to comment.