From 2b17d32a67da98ee649b787cef27fb1a1fe15171 Mon Sep 17 00:00:00 2001 From: Corey Shields Date: Sat, 13 Feb 2021 14:55:09 -0500 Subject: [PATCH] Replace gpredict.js with satellite.js package.json: Add satellite.js dependency Signed-off-by: Fabian P. Schmidt Move to satellite.js in map, drop satellite footprint Signed-off-by: Fabian P. Schmidt Remove gpredict.js dependency Signed-off-by: Fabian P. Schmidt Replace gpredict.js with satellite.js Builds on the work of kerel-fs in !596 and #440, implements satellite.js for core TLE and SGP4 handling, deprecating and removing gpredict.js fixes #440 does NOT fix #204 Signed-off-by: Corey Shields --- db/base/views.py | 9 +- db/static/js/map.js | 153 ++++++++++++++++++++----------- db/templates/base/satellite.html | 3 +- package-lock.json | 64 ++++++++++++- package.json | 6 +- 5 files changed, 172 insertions(+), 63 deletions(-) diff --git a/db/base/views.py b/db/base/views.py index dc87393..d233f16 100644 --- a/db/base/views.py +++ b/db/base/views.py @@ -13,7 +13,7 @@ from django.core.exceptions import ObjectDoesNotExist from django.core.paginator import Paginator from django.db import OperationalError from django.db.models import Count, Max, Prefetch, Q -from django.http import HttpResponse, JsonResponse +from django.http import HttpResponse, HttpResponseServerError, JsonResponse from django.shortcuts import get_object_or_404, redirect, render from django.urls import reverse from django.utils import timezone @@ -332,8 +332,11 @@ def recent_decoded_cnt(request, norad): :returns: JSON of point counts as JsonResponse """ - results = read_influx(norad) - return JsonResponse(results, safe=False) + if settings.USE_INFLUX: + results = read_influx(norad) + return JsonResponse(results, safe=False) + + return HttpResponseServerError() class TransmitterCreateView(LoginRequiredMixin, BSModalCreateView): diff --git a/db/static/js/map.js b/db/static/js/map.js index 42e69b1..13a9ab6 100644 --- a/db/static/js/map.js +++ b/db/static/js/map.js @@ -1,121 +1,169 @@ -/*global mapboxgl Sat_t gtk_sat_data_read_sat predict_calc julian_date Geodetic_t radians xkmper de2ra asin sin cos arccos degrees pio2 pi fabs */ +/*global mapboxgl satellite */ $(document).ready(function() { 'use strict'; - var name = $('div#map').data('name'); + var sin = Math.sin; + var cos = Math.cos; + var fabs = Math.abs; + var acos = Math.acos; + var asin = Math.asin; + + var pi = Math.pi; + var earthRadius = 6.378135E3; /* Earth radius km */ + var de2ra = 1.74532925E-2; /* Degrees to Radians */ + var pio2 =1.5707963267949; /* Pi/2 */ + var tle1 = $('div#map').data('tle1'); var tle2 = $('div#map').data('tle2'); var mapboxtoken = $('div#map').data('mapboxtoken'); mapboxgl.accessToken = mapboxtoken; - // Load satellite orbit data from TLE - var sat = new Sat_t(); - gtk_sat_data_read_sat([name, tle1, tle2], sat); + /* Returns angle in radians from arg id degrees */ + function radians(arg) { + return (arg * de2ra); + } + /* Returns angle in degrees from arg in rads */ + function degrees(arg) { + return (arg / de2ra); + } - function get_orbits(sat) { - // NOTE: This function has side effects (alters sat)! + /** brief Arccosine implementation. + * + * Returns a value between zero and two pi. + * Borrowed from gsat 0.9 by Xavier Crehueras, EB3CZS. + * Optimized by Alexandru Csete. + */ + function arccos(x, y) { + if (x && y) { + if (y > 0.0) { + return Math.acos(x / y); + } + else if (y < 0.0) { + return pi + Math.acos(x / y); + } + } + + return 0.0; + } + + function get_orbits(satrec, t) { + /** + * Calculate 300 orbital points with 60 second increments, starting at epoch t + * + * @return {Array} Array that contains Arrays of geodetic (lon, lat) pairs in degrees + */ // Number of positions to compute - var COUNT = 300; + const COUNT = 300; // Interval in ms between positions to compute - var STEP = 60*1000; + const STEP = 60*1000; // Create satellite orbit var current_orbit = []; var all_orbits = []; - var t = new Date(); - var previous = 0; for ( var i = 0; i < COUNT; i++) { - predict_calc(sat, (0,0), julian_date(t)); + const coords = calc_geodetic_coords(satrec, t) ; - if (Math.abs(sat.ssplon - previous) > 180) { - // orbit crossing -PI, PI + if (Math.abs(coords['lon'] - previous) > 180) { + // Satellite passed the 180th meridian. + // Save last orbital point and + // start new Array for the next orbit + current_orbit.push([coords['lon']+360, coords['lat']]); all_orbits.push(current_orbit); current_orbit = []; } - current_orbit.push([sat.ssplon, sat.ssplat]); - previous = sat.ssplon; + current_orbit.push([coords['lon'], coords['lat']]); + previous = coords['lon']; // Increase time for next point t.setTime(t.getTime() + STEP); } - return all_orbits; } - function get_range_circle(sat_ssplat, sat_ssplon, sat_footprint) { - // NOTE: This function has side effects (alters sat)! + function calc_geodetic_coords(satrec, t) { + const positionAndVelocity = satellite.propagate(satrec, t); + const gmst = satellite.gstime(t); + const positionEci = positionAndVelocity.position; + const positionGd = satellite.eciToGeodetic(positionEci, gmst); + const longitude = satellite.degreesLong(positionGd.longitude); + const latitude = satellite.degreesLat(positionGd.latitude); - var azi; - // var msx, msy, ssx, ssy; - var ssplat, + return {'lon': longitude, + 'lat': latitude, + 'height': positionGd.height}; + } + + function get_range_circle(current_coords) { + // first we have to calculate the footprint + var footprint = 12756.33 * acos (earthRadius / (earthRadius+current_coords.height)); + + var azi, + ssplat, ssplon, beta, azimuth, num, dem; - // var rangelon, rangelat, mlon; - - var geo = new Geodetic_t(); /* Range circle calculations. * Borrowed from gsat 0.9.0 by Xavier Crehueras, EB3CZS * who borrowed from John Magliacane, KD2BD. * Optimized by Alexandru Csete and William J Beksi. */ - ssplat = radians(sat_ssplat); - ssplon = radians(sat_ssplon); - beta = (0.5 * sat_footprint) / xkmper; + ssplat = radians(current_coords.lat); + ssplon = radians(current_coords.lon); + beta = (0.5 * footprint) / earthRadius; var points = []; + var lat = 0.0; + var lon = 0.0; for (azi = 0; azi < 360; azi += 5) { azimuth = de2ra * azi; - geo.lat = asin(sin(ssplat) * cos(beta) + cos(azimuth) * sin(beta) + lat = asin(sin(ssplat) * cos(beta) + cos(azimuth) * sin(beta) * cos(ssplat)); - num = cos(beta) - (sin(ssplat) * sin(geo.lat)); - dem = cos(ssplat) * cos(geo.lat); + num = cos(beta) - (sin(ssplat) * sin(lat)); + dem = cos(ssplat) * cos(lat); if (azi == 0 && (beta > pio2 - ssplat)) { - geo.lon = ssplon + pi; + lon = ssplon + pi; } else if (azi == 180 && (beta > pio2 + ssplat)) { - geo.lon = ssplon + pi; + lon = ssplon + pi; } else if (fabs(num / dem) > 1.0) { - geo.lon = ssplon; + lon = ssplon; } else { if ((180 - azi) >= 0) { - geo.lon = ssplon - arccos(num, dem); + lon = ssplon - arccos(num, dem); } else { - geo.lon = ssplon + arccos(num, dem); + lon = ssplon + arccos(num, dem); } } - - points.push([degrees(geo.lon), degrees(geo.lat)]); + points.push([degrees(lon), degrees(lat)]); } return points; } - function get_location(sat) { - // NOTE: This function has side effects (alters sat)! - var now = new Date(); - predict_calc(sat, (0, 0), julian_date(now)); + // Load satellite orbit data from TLE + var satrec = satellite.twoline2satrec(tle1, tle2); - return [sat.ssplon, sat.ssplat]; - } - // Calculate orbits, footprint and current satellite location - var sat_location = get_location(sat); - var footprint = get_range_circle(sat.ssplat, sat.ssplon, sat.footprint); - var all_orbits = get_orbits(sat); + // Calculate orbits and current satellite location + const now = new Date(); + var current_coords = calc_geodetic_coords(satrec, now); + var sat_location = [current_coords.lon, current_coords.lat]; + var footprint = get_range_circle(current_coords); + + var all_orbits = get_orbits(satrec, now); var map = new mapboxgl.Map({ container: 'map', @@ -211,13 +259,12 @@ $(document).ready(function() { }); function update_map() { - // Recalculate footprint and current satellite location - sat_location = get_location(sat); - footprint = get_range_circle(sat.ssplat, sat.ssplon, sat.footprint); - + // Recalculate current satellite location + current_coords = calc_geodetic_coords(satrec, new Date()); + sat_location = [current_coords.lon, current_coords.lat]; + footprint = get_range_circle(current_coords); location_data.features[0].geometry.coordinates = sat_location; footprint_data.features[0].geometry.coordinates = [footprint]; - map.getSource('sat_location').setData(location_data); map.getSource('sat_footprint').setData(footprint_data); } diff --git a/db/templates/base/satellite.html b/db/templates/base/satellite.html index 029dd9f..a4548bc 100644 --- a/db/templates/base/satellite.html +++ b/db/templates/base/satellite.html @@ -604,10 +604,11 @@ - {% if showmap %} + + {% endif %} {% endblock %} diff --git a/package-lock.json b/package-lock.json index 7dd560a..af1ce89 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1486,6 +1486,11 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" }, + "complex.js": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/complex.js/-/complex.js-2.0.11.tgz", + "integrity": "sha512-6IArJLApNtdg1P1dFtn3dnyzoZBEF0MwMnrfF1exSBRpZYoy4yieMkpZhQDC0uwctw48vii0CFVyHfpgZ/DfGw==" + }, "component-emitter": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", @@ -2154,6 +2159,11 @@ } } }, + "decimal.js": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.1.tgz", + "integrity": "sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw==" + }, "decode-uri-component": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", @@ -2528,6 +2538,11 @@ "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", "dev": true }, + "escape-latex": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/escape-latex/-/escape-latex-1.2.0.tgz", + "integrity": "sha512-nV5aVWW1K0wEiUIEdZ4erkGGH8mDxGyxSeqPzRNtWP7ataw+/olFObw7hujFWlVjNsaDFw5VZ5NzVSIqRgfTiw==" + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -3235,6 +3250,11 @@ "for-in": "^1.0.1" } }, + "fraction.js": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.0.13.tgz", + "integrity": "sha512-E1fz2Xs9ltlUp+qbiyx9wmt2n9dRzPsS11Jtdb8D2o+cC7wr9xkkKsVKJuBX0ST+LVS+LhLO+SbLJNtfWcJvXA==" + }, "fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", @@ -3489,10 +3509,6 @@ "minimist": "^1.2.5" } }, - "gpredict.js": { - "version": "github:kerel-fs/gpredict.js#611b18c073a66449c39e712017fbdcbc73972f2c", - "from": "github:kerel-fs/gpredict.js" - }, "graceful-fs": { "version": "4.2.4", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", @@ -4266,6 +4282,11 @@ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "dev": true }, + "javascript-natural-sort": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz", + "integrity": "sha1-+eIwPUUH9tdDVac2ZNFED7Wg71k=" + }, "jquery": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.5.1.tgz", @@ -4699,6 +4720,21 @@ } } }, + "mathjs": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/mathjs/-/mathjs-9.2.0.tgz", + "integrity": "sha512-R2fQxaOmyifxgP4+c59dnfLwpKI1KYHdnT5lLwDuHIZvgyGb71M8ay6kTJTEv9rG04pduqvX4tbBUoG5ypTF8A==", + "requires": { + "complex.js": "^2.0.11", + "decimal.js": "^10.2.1", + "escape-latex": "^1.2.0", + "fraction.js": "^4.0.13", + "javascript-natural-sort": "^0.7.1", + "seedrandom": "^3.0.5", + "tiny-emitter": "^2.1.0", + "typed-function": "^2.0.0" + } + }, "mathml-tag-names": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz", @@ -6094,6 +6130,11 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "satellite.js": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/satellite.js/-/satellite.js-4.1.3.tgz", + "integrity": "sha512-l65XHxmT4n31DSGQy/jnu/sLfKn42g862h1p9NyalOEYCpEsplFAqUIT4+euK0AByizZML2Zkjbl0HWI79KC0A==" + }, "sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", @@ -6113,6 +6154,11 @@ "get-assigned-identifiers": "^1.1.0" } }, + "seedrandom": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz", + "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==" + }, "select2": { "version": "4.0.13", "resolved": "https://registry.npmjs.org/select2/-/select2-4.0.13.tgz", @@ -7019,6 +7065,11 @@ "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=", "dev": true }, + "tiny-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", + "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==" + }, "tiny-inflate": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", @@ -7150,6 +7201,11 @@ "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", "dev": true }, + "typed-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/typed-function/-/typed-function-2.0.0.tgz", + "integrity": "sha512-Hhy1Iwo/e4AtLZNK10ewVVcP2UEs408DS35ubP825w/YgSBK1KVLwALvvIG4yX75QJrxjCpcWkzkVRB0BwwYlA==" + }, "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", diff --git a/package.json b/package.json index a3f359e..000e6d7 100644 --- a/package.json +++ b/package.json @@ -19,17 +19,19 @@ "admin-lte": "^3.0", "d3": "^6.3.0", "flot": "^4.2.1", - "gpredict.js": "github:kerel-fs/gpredict.js", "mapbox-gl": "^2.0.0", + "mathjs": "^9.2.0", + "satellite.js": "^4.1.3", "swagger-ui-dist": "^3.39.0" }, "assets": [ "admin-lte/**/*", "d3/dist/d3.min.js", "flot/dist/**/*", - "gpredict.js/dist/gpredict.min.js", "mapbox-gl/dist/mapbox-gl.css", "mapbox-gl/dist/mapbox-gl.js", + "mathjs/lib/browser/math.js", + "satellite.js/dist/satellite.min.js", "swagger-ui-dist/swagger-ui.css", "swagger-ui-dist/swagger-ui-bundle.js" ]