From e6c788a1316b51d3b9f5834df6ba246acec764e4 Mon Sep 17 00:00:00 2001 From: AndreasK79 Date: Tue, 18 Feb 2020 10:49:27 +0100 Subject: [PATCH] Added distanceplotting. Fixes #384. --- application/controllers/Distances.php | 50 ++++++ application/models/Distances_model.php | 158 ++++++++++++++++++ application/models/Stations.php | 14 ++ application/views/distances/index.php | 17 ++ application/views/interface_assets/footer.php | 115 +++++++++++++ application/views/interface_assets/header.php | 2 + 6 files changed, 356 insertions(+) create mode 100644 application/controllers/Distances.php create mode 100644 application/models/Distances_model.php create mode 100644 application/views/distances/index.php diff --git a/application/controllers/Distances.php b/application/controllers/Distances.php new file mode 100644 index 00000000..d0c4b950 --- /dev/null +++ b/application/controllers/Distances.php @@ -0,0 +1,50 @@ +load->model('user_model'); + if(!$this->user_model->authorize(2)) { $this->session->set_flashdata('notice', 'You\'re not allowed to do that!'); redirect('dashboard'); } + } + + public function index() + { + // Render Page + $data['page_title'] = "Distances worked"; + + function js_str($s) + { + return '"' . addcslashes($s, "\0..\37\"\\") . '"'; + } + + function js_array($array) + { + $temp = array_map('js_str', $array); + return '[' . implode(',', $temp) . ']'; + } + + $data['bands_available'] = js_array($this->config->item('bands_available')); + + $this->load->view('interface_assets/header', $data); + $this->load->view('distances/index'); + $this->load->view('interface_assets/footer'); + } + + public function get_distances(){ + // POST data + $postData = $this->input->post(); + + //load model + $this->load->model('Distances_model'); + + // get data + $data = $this->Distances_model->get_distances($postData); + + return json_encode($data); + } + +} \ No newline at end of file diff --git a/application/models/Distances_model.php b/application/models/Distances_model.php new file mode 100644 index 00000000..c8025898 --- /dev/null +++ b/application/models/Distances_model.php @@ -0,0 +1,158 @@ +load->model('Stations'); + $station_id = $CI->Stations->find_active(); + $station_gridsquare = $CI->Stations->find_gridsquare(); + $gridsquare = explode(',', $station_gridsquare); // We need to convert to an array, since a user can enter several gridsquares + + $this->db->select('col_call callsign, col_gridsquare grid'); + $this->db->where('LENGTH(col_gridsquare) >', 0); + + if ($postdata['band'] == 'sat') { + $this->db->where('col_prop_mode', $postdata['band']); + } + else { + $this->db->where('col_band', $postdata['band']); + } + + $dataarrayata = $this->db->get($this->config->item('table_name')); + $this->plot($dataarrayata->result_array(), $gridsquare); + } + + // This functions takes query result from the database and extracts grids from the qso, + // then calculates distance between homelocator and locator given in qso. + // It builds an array, which has 50km intervals, then inputs each length into the correct spot + // The function returns a json-encoded array. + function plot($qsoArray, $gridsquare) { + $stationgrid = strtoupper($gridsquare[0]); // We use only the first entered gridsquare from the active profile + if (strlen($stationgrid) == 4) $stationgrid .= 'MM'; // adding center of grid if only 4 digits are specified + + if (!$this->valid_locator($stationgrid)) { + header('Content-Type: application/json'); + echo json_encode(array('Error' => 'Error. There is a problem with the gridsquare set in your profile!')); + } + else { + // Making the array we will use for plotting, we save occurrences of the length of each qso in the array + $j = 0; + for ($i = 0; $j < 20000; $i++) { + $dataarray[$i]['dist'] = $j . 'km - ' . ($j + 50) . 'km'; + $dataarray[$i]['count'] = 0; + $dataarray[$i]['calls'] = ''; + $dataarray[$i]['callcount'] = 0; + $j += 50; + } + + $qrb = array ( // Used for storing the QSO with the longest QRB + 'Callsign' => '', + 'Grid' => '', + 'Distance' => '', + 'Qsoes' => '', + 'Grids' => '' + ); + + foreach ($qsoArray as $qso) { + $qrb['Qsoes']++; // Counts up number of qsoes + $bearingdistance = $this->bearing_dist($stationgrid, $qso['grid']); // Calculates distance based on grids + $arrayplacement = $bearingdistance / 50; // Resolution is 50, calculates where to put result in array + if ($bearingdistance > $qrb['Distance']) { // Saves the longest QSO + $qrb['Distance'] = $bearingdistance; + $qrb['Callsign'] = $qso['callsign']; + $qrb['Grid'] = $qso['grid']; + } + $dataarray[$arrayplacement]['count']++; // Used for counting total qsoes plotted + if ($dataarray[$arrayplacement]['callcount'] < 5) { // Used for tooltip in graph, set limit to 5 calls shown + if ($dataarray[$arrayplacement]['callcount'] > 0) { + $dataarray[$arrayplacement]['calls'] .= ', '; + } + $dataarray[$arrayplacement]['calls'] .= $qso['callsign']; + $dataarray[$arrayplacement]['callcount']++; + } + } + + if (!$qrb['Qsoes'] == 0) { // We have a result :) + header('Content-Type: application/json'); + $data['ok'] = 'OK'; + $data['qrb'] = $qrb; + $data['qsodata'] = $dataarray; + echo json_encode($data); + } + else { + header('Content-Type: application/json'); + echo json_encode(array('Error' => 'No qsoes to plot found')); + } + } + } + + /* + * Checks the validity of the locator + * Input: locator + * Returns: bool + */ + function valid_locator ($loc) { + $regex = '^[A-R]{2}[0-9]{2}[A-X]{2}$'; + if (preg_match("%{$regex}%i", $loc)) { + return true; + } + else { + return false; + } + } + + /* + * Converts locator to latitude and longitude + * Input: locator + * Returns: array with longitude and latitude + */ + function loc_to_latlon ($loc) { + /* lat */ + $l[0] = + (ord(substr($loc, 1, 1))-65) * 10 - 90 + + (ord(substr($loc, 3, 1))-48) + + (ord(substr($loc, 5, 1))-65) / 24 + 1/48; + $l[0] = $this->deg_to_rad($l[0]); + /* lon */ + $l[1] = + (ord(substr($loc, 0, 1))-65) * 20 - 180 + + (ord(substr($loc, 2, 1))-48) * 2 + + (ord(substr($loc, 4, 1))-65) / 12 + 1/24; + $l[1] = $this->deg_to_rad($l[1]); + + return $l; + } + + function deg_to_rad ($deg) { + return (M_PI * $deg/180); + } + + function bearing_dist($loc1, $loc2) { + $loc1 = strtoupper($loc1); + $loc2 = strtoupper($loc2); + + if (strlen($loc1) == 4) $loc1 .= 'MM'; + if (strlen($loc2) == 4) $loc2 .= 'MM'; + + if (!$this->valid_locator($loc1) || !$this->valid_locator($loc2)) { + return 0; + } + + $l1 = $this->loc_to_latlon($loc1); + $l2 = $this->loc_to_latlon($loc2); + + $co = cos($l1[1] - $l2[1]) * cos($l1[0]) * cos($l2[0]) + sin($l1[0]) * sin($l2[0]); + $ca = atan2(sqrt(1 - $co*$co), $co); + + return round(6371*$ca); + } +} \ No newline at end of file diff --git a/application/models/Stations.php b/application/models/Stations.php index 8a24849d..f48d3b8d 100644 --- a/application/models/Stations.php +++ b/application/models/Stations.php @@ -121,6 +121,20 @@ class Stations extends CI_Model { } else { return "0"; } + } + + public function find_gridsquare() { + $this->db->where('station_active', 1); + $query = $this->db->get('station_profile'); + + if($query->num_rows() >= 1) { + foreach ($query->result() as $row) + { + return $row->station_gridsquare; + } + } else { + return "0"; + } } public function reassign($id) { diff --git a/application/views/distances/index.php b/application/views/distances/index.php new file mode 100644 index 00000000..97ec574a --- /dev/null +++ b/application/views/distances/index.php @@ -0,0 +1,17 @@ +
+ +
+ +

+ +
+
+ + + +
+
+ +
\ No newline at end of file diff --git a/application/views/interface_assets/footer.php b/application/views/interface_assets/footer.php index 43239d2f..f3abec7e 100644 --- a/application/views/interface_assets/footer.php +++ b/application/views/interface_assets/footer.php @@ -897,6 +897,121 @@ $(document).ready(function(){ }); + + + +uri->segment(1) == "distances") { ?> + + diff --git a/application/views/interface_assets/header.php b/application/views/interface_assets/header.php index d3744b9f..e5f8d336 100644 --- a/application/views/interface_assets/header.php +++ b/application/views/interface_assets/header.php @@ -68,6 +68,8 @@ Statistics Gridsquares + + Distances worked