kopia lustrzana https://github.com/magicbug/Cloudlog
Added distanceplotting. Fixes #384.
rodzic
0628e3bdb3
commit
e6c788a131
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
class Distances extends CI_Controller {
|
||||
|
||||
function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->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);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
<?php
|
||||
if (!defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
class Distances_model extends CI_Model
|
||||
{
|
||||
function __construct()
|
||||
{
|
||||
// Call the Model constructor
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
function get_distances($postdata)
|
||||
{
|
||||
$CI =& get_instance();
|
||||
$CI->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);
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
<div class="container">
|
||||
|
||||
<br>
|
||||
|
||||
<h2><?php echo $page_title; ?></h2>
|
||||
|
||||
<div id="distances_div">
|
||||
<form class="form-inline">
|
||||
<label class="my-1 mr-2" for="gridsquare_bands">Band Selection</label>
|
||||
<select class="custom-select my-1 mr-sm-2" id="distplot_bands">
|
||||
<option value="sat">SAT</option>
|
||||
</select>
|
||||
<button id="plot" type="button" name="plot" class="btn btn-success btn-primary" onclick="distPlot(this.form)">Plot</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
|
@ -897,6 +897,121 @@ $(document).ready(function(){
|
|||
});
|
||||
<?php } ?>
|
||||
|
||||
</script>
|
||||
<?php } ?>
|
||||
|
||||
<?php if ($this->uri->segment(1) == "distances") { ?>
|
||||
<script src="https://code.highcharts.com/stock/highstock.js"></script>
|
||||
<script>
|
||||
|
||||
var bands_available = <?php echo $bands_available; ?>;
|
||||
|
||||
$.each(bands_available, function(key, value) {
|
||||
$('#distplot_bands')
|
||||
.append($("<option></option>")
|
||||
.attr("value",value)
|
||||
.text(value));
|
||||
});
|
||||
|
||||
var num = "<?php echo $this->uri->segment(3);?>";
|
||||
$("#distplot_bands option").each(function(){
|
||||
if($(this).val()==num){ // EDITED THIS LINE
|
||||
$(this).attr("selected","selected");
|
||||
}
|
||||
});
|
||||
|
||||
function distPlot(form) {
|
||||
$(".alert").remove();
|
||||
var baseURL= "<?php echo base_url();?>";
|
||||
$.ajax({
|
||||
url: baseURL+'index.php/distances/get_distances',
|
||||
type: 'post',
|
||||
data: {'locator': 'JP50HP', 'band': form.distplot_bands.value},
|
||||
success: function(tmp) {
|
||||
if (tmp.ok == 'OK') {
|
||||
if (!($('#information').length > 0))
|
||||
$("#distances_div").append('<div id="information"></div><div id="graphcontainer" style="height: 600px; margin: 0 auto"></div>');
|
||||
var options = {
|
||||
chart: {
|
||||
type: 'column',
|
||||
zoomType: 'xy',
|
||||
renderTo: 'graphcontainer'
|
||||
},
|
||||
title: {
|
||||
text: 'Mode distribution'
|
||||
},
|
||||
xAxis: {
|
||||
categories: [],
|
||||
crosshair: true,
|
||||
type: "category",
|
||||
min:0,
|
||||
max:100
|
||||
|
||||
},
|
||||
yAxis: {
|
||||
title: {
|
||||
text: '# QSOes'
|
||||
}
|
||||
},
|
||||
navigator: {
|
||||
enabled: true,
|
||||
xAxis: {
|
||||
labels: {
|
||||
formatter: function() {
|
||||
return this.value * '50' + ' km';
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
rangeSelector: {
|
||||
selected: 1
|
||||
},
|
||||
tooltip: {
|
||||
formatter: function () {
|
||||
if(this.point) {
|
||||
return "Distance: " + options.xAxis.categories[this.point.x] +
|
||||
"<br />Callsign(s) worked (max 5 shown): " + myComments[this.point.x] +
|
||||
"<br />Number of qsoes: <strong>" + series.data[this.point.x] + "</strong>";
|
||||
}
|
||||
}
|
||||
},
|
||||
series: []
|
||||
};
|
||||
var myComments=[];
|
||||
|
||||
var series = {
|
||||
data: [],
|
||||
showInNavigator: true
|
||||
};
|
||||
|
||||
$.each(tmp.qsodata, function(){
|
||||
myComments.push(this.calls);
|
||||
options.xAxis.categories.push(this.dist);
|
||||
series.name = 'Number of qsoes';
|
||||
series.data.push(this.count);
|
||||
|
||||
});
|
||||
|
||||
options.series.push(series);
|
||||
|
||||
$('#information').html(tmp.qrb.Qsoes + " contacts were plotted.<br /> Your longest contact was " + tmp.qrb.Callsign
|
||||
+ " in locator "+ tmp.qrb.Grid
|
||||
+" and the distance was "
|
||||
+tmp.qrb.Distance +"km.");
|
||||
|
||||
var chart = new Highcharts.Chart(options);
|
||||
}
|
||||
else {
|
||||
if (($('#information').length > 0)) {
|
||||
$("#information").remove();
|
||||
$("#graphcontainer").remove();
|
||||
}
|
||||
$("#distances_div").append('<div class="alert alert-danger" role="alert"><a href="#" class="close" data-dismiss="alert" aria-label="close">×</a>' + tmp.Error + '</div>');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
<?php } ?>
|
||||
|
||||
|
|
|
@ -68,6 +68,8 @@
|
|||
<a class="dropdown-item" href="<?php echo site_url('statistics');?>" title="Statistics">Statistics</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="<?php echo site_url('gridsquares');?>" title="Gridsquares">Gridsquares</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="<?php echo site_url('distances');?>" title="Distances">Distances worked</a>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue