From ac4eb642eafa3260eed4b47cb0534a4d7a8e3a24 Mon Sep 17 00:00:00 2001 From: Mark Jessop Date: Sun, 11 Aug 2019 00:09:34 +0930 Subject: [PATCH] Initial work to get bearing on the map. --- chasemapper/bearings.py | 3 +- static/js/bearings.js | 257 ++++++++++++++++++++++++++++++++++++++++ templates/index.html | 80 ++++++++++++- 3 files changed, 338 insertions(+), 2 deletions(-) create mode 100644 static/js/bearings.js diff --git a/chasemapper/bearings.py b/chasemapper/bearings.py index 9de3c2b..f9f3554 100644 --- a/chasemapper/bearings.py +++ b/chasemapper/bearings.py @@ -226,7 +226,8 @@ class Bearings(object): # Now we need to update the web clients on what has changed. _client_update = { 'add': _new_bearing, - 'remove': _removal_list + 'remove': _removal_list, + 'server_timestamp': time.time() } self.sio.emit('bearing_change', _client_update, namespace='/chasemapper') diff --git a/static/js/bearings.js b/static/js/bearings.js new file mode 100644 index 0000000..83048af --- /dev/null +++ b/static/js/bearings.js @@ -0,0 +1,257 @@ +// +// Project Horus - Browser-Based Chase Mapper - Bearing Handlers +// +// Copyright (C) 2019 Mark Jessop +// Released under GNU GPL v3 or later +// + +var bearing_store = {}; + +var bearings_on = true; +var bearings_only_mode = false; + + +var bearing_confidence_threshold = 50.0; +var bearing_max_age = 20*60.0; + +var bearing_length = 10000; +var bearing_weight = 0.5; +var bearing_color = "#000000"; +var bearing_max_opacity = 0.8; +var bearing_min_opacity = 0.1; + +// Store for the latest server timestamp. +// Start out with just our own local timestamp. +var latest_server_timestamp = Date.now()/1000.0; + + +function updateBearingSettings(){ + // Update bearing settings, but do *not* redraw. + bearing_weight = parseFloat($('#bearingWeight').val()); + bearing_length = parseFloat($('#bearingLength').val())*1000; + bearing_confidence_threshold = parseFloat($('#bearingConfidenceThreshold').val()); + bearing_max_age = parseFloat($('#bearingMaximumAge').val())*60.0; + bearing_min_opacity = parseFloat($('#bearingMinOpacity').val()); + bearing_max_opacity = parseFloat($('#bearingMaxOpacity').val()); + var _bearing_color = $('#bearingColorSelect').val(); + var _bearing_custom_color = $('#bearingCustomColor').val(); + + if(_bearing_color == "red"){ + bearing_color = "#FF0000"; + } else if (_bearing_color == "black"){ + bearing_color = "#000000"; + } else if (_bearing_color == "blue"){ + bearing_color = "#0000FF"; + } else if (_bearing_color == "green"){ + bearing__color = "#00FF00"; + } else if (_bearing_color == "custom"){ + bearing_color = _ring_custom_color; + } +} + +function destroyAllBearings(){ + $.each(bearing_store, function(key, value) { + bearing_store[key].line.remove(); + }); + + bearing_store = {}; +} + + +function addBearing(timestamp, bearing){ + + bearing_store[timestamp] = bearing; + + // Calculate the end position. + var _end = calculateDestination(L.latLng([bearing_store[timestamp].lat, bearing_store[timestamp].lon]), bearing_store[timestamp].true_bearing, bearing_length); + + var _opacity = calculateBearingOpacity(timestamp); + + // Create the PolyLine + bearing_store[timestamp].line = L.polyline( + [[bearing_store[timestamp].lat, bearing_store[timestamp].lon],_end],{ + color: bearing_color, + weight: bearing_weight, + opacity: _opacity + }); + + if (bearing_store[timestamp].confidence > bearing_confidence_threshold){ + bearing_store[timestamp].line.addTo(map); + } +} + + +function removeBearings(timestamps){ + // Remove bearings from a supplied list + timestamps.forEach(function (item, index){ + if(bearing_store.hasOwnProperty(item)){ + bearing_store[item].line.remove(); + delete bearing_store[item]; + } + }); + +} + + +function restyleBearings(){ + // Update the bearing settings. + updateBearingSettings(); + + + $.each(bearing_store, function(key, value) { + // Calculate the end position. + var _opacity = calculateBearingOpacity(key); + + // Create the PolyLine + bearing_store[key].line.setStyle({ + color: bearing_color, + weight: bearing_weight, + opacity: _opacity + }); + + }); +} + + +function redrawBearings(){ + // Update the bearing settings. + updateBearingSettings(); + + + $.each(bearing_store, function(key, value) { + // Remove bearing from map. + bearing_store[key].line.remove(); + + // Calculate the end position. + var _end = calculateDestination(L.latLng([bearing_store[key].lat, bearing_store[key].lon]), bearing_store[key].true_bearing, bearing_length); + var _opacity = calculateBearingOpacity(key); + + console.log(_opacity); + + // Create the PolyLine + bearing_store[key].line = L.polyline( + [[bearing_store[key].lat, bearing_store[key].lon],_end],{ + color: bearing_color, + weight: bearing_weight, + opacity: _opacity + }); + + if (bearing_store[key].confidence > bearing_confidence_threshold){ + bearing_store[key].line.addTo(map); + } + + }); +} + + +function initialiseBearings(){ + + // Destroy all existing bearings + destroyAllBearings(); + + // Update the bearing settings. + updateBearingSettings(); + + // Request the bearings from the client. + $.ajax({ + url: "/get_bearings", + dataType: 'json', + async: true, + success: function(data) { + + $.each(data, function(key, value) { + addBearing(key, value); + }); + } + }); + +} + + +function bearingUpdate(data){ + // Remove any bearings that have been requested. + removeBearings(data.remove); + addBearing(data.add.timestamp, data.add); +} + + +function toggleBearingsOnlyMode(){ + // Enable-disable bearing only mode, which hides the summary and telemetry displays + + // Grab the bearing-only-mode settings. + var _bearings_only_enabled = document.getElementById("bearingsOnlyMode").checked; + + + if ((_bearings_only_enabled == true) && (bearings_only_mode == false)){ + // The user had just enabled the bearings_only_mode, so hide things that are not relevant. + + $("#summary_table").hide(); + $("#telem_table_btn").hide(); + $("#telem_table").hide(); + + bearings_only_mode = true; + + + } else if ((_bearings_only_enabled == false) && (bearings_only_mode == true)){ + // Un-hide balloon stuff + + $("#summary_table").show(); + $("#telem_table_btn").show(); + $("#telem_table").show(); + + bearings_only_mode = false; + + } +} + + +/** + Returns the point that is a distance and heading away from + the given origin point. + @param {L.LatLng} latlng: origin point + @param {float}: heading in degrees, clockwise from 0 degrees north. + @param {float}: distance in meters + @returns {L.latLng} the destination point. + Many thanks to Chris Veness at http://www.movable-type.co.uk/scripts/latlong.html + for a great reference and examples. + + Source: https://makinacorpus.github.io/Leaflet.GeometryUtil/leaflet.geometryutil.js.html#line712 +*/ +function calculateDestination(latlng, heading, distance) { + heading = (heading + 360) % 360; + var rad = Math.PI / 180, + radInv = 180 / Math.PI, + R = 6378137, // approximation of Earth's radius + lon1 = latlng.lng * rad, + lat1 = latlng.lat * rad, + rheading = heading * rad, + sinLat1 = Math.sin(lat1), + cosLat1 = Math.cos(lat1), + cosDistR = Math.cos(distance / R), + sinDistR = Math.sin(distance / R), + lat2 = Math.asin(sinLat1 * cosDistR + cosLat1 * + sinDistR * Math.cos(rheading)), + lon2 = lon1 + Math.atan2(Math.sin(rheading) * sinDistR * + cosLat1, cosDistR - sinLat1 * Math.sin(lat2)); + lon2 = lon2 * radInv; + lon2 = lon2 > 180 ? lon2 - 360 : lon2 < -180 ? lon2 + 360 : lon2; + return L.latLng([lat2 * radInv, lon2]); +} + + +function calculateBearingOpacity(bearing_timestamp){ + if(bearing_timestamp > latest_server_timestamp){ + return bearing_max_opacity; + }else if((latest_server_timestamp - bearing_timestamp) > bearing_max_age){ + return 0.0; + }else{ + // Calculate an appropriate opacity. + var _opacity = bearing_max_opacity - (latest_server_timestamp - bearing_timestamp)/bearing_max_age; + + if (_opacity < bearing_min_opacity){ + _opacity = bearing_min_opacity; + } + return _opacity + } + +} diff --git a/templates/index.html b/templates/index.html index da049b2..7421fb1 100644 --- a/templates/index.html +++ b/templates/index.html @@ -40,6 +40,7 @@ + @@ -355,6 +356,9 @@ } }); + // Initialise bearings + initialiseBearings(); + // Telemetry event handler. // We will get one of these mesages with every new balloon position @@ -372,6 +376,11 @@ handlePrediction(data); }); + socket.on('bearing_change', function(data){ + bearingUpdate(data); + }); + + $("#downloadModel").click(function(){ socket.emit('download_model', {data: 'plzkthx'}); }); @@ -494,7 +503,20 @@ if(document.getElementById("showOtherCars").checked){ get_habitat_vehicles(); } - }, habitat_update_rate); + }, habitat_update_rate); + + + window.setInterval(function(){ + $.ajax({ + url: "/server_time", + dataType: 'json', + async: true, + success: function(data) { + latest_server_time = data; + restyleBearings(); + } + }); + },10000); }); @@ -651,6 +673,62 @@ +
+ Enable Bearings +
+ +
+ Bearing-Only Mode +
+ +
+ Confidence Threshold
+
+ +
+ Maximum Age (min)
+
+ +
+ Show Stationary Bearings +
+ + +
+
+
+
+
+
+ +

Bearing Style

+
+ Bearing Length (km)
+
+
+ Bearing Weight (px)
+
+
+ Bearing Min Opacity
+
+
+ Bearing Max Opacity
+
+
+ Bearing Color + +
+
+
+ Custom Color
+
+