[Gridmap] Added country grids

This commit is contained in:
Andreas Kristiansen
2025-10-18 19:36:17 +02:00
parent 6be185b29e
commit 0ba4c8bd9c
9 changed files with 200 additions and 55 deletions

View File

@@ -22,7 +22,7 @@ $config['migration_enabled'] = TRUE;
|
*/
$config['migration_version'] = 260;
$config['migration_version'] = 261;
/*
|--------------------------------------------------------------------------

View File

@@ -20,6 +20,7 @@ class Gridmap extends CI_Controller {
$data['bands'] = $this->bands->get_worked_bands();
$data['orbits'] = $this->bands->get_worked_orbits();
$data['sats_available'] = $this->bands->get_worked_sats();
$data['countries'] = $this->gridmap_model->get_countries();
$data['user_default_band'] = $this->session->userdata('user_default_band');
$data['user_default_confirmation'] = $this->session->userdata('user_default_confirmation');
@@ -60,8 +61,12 @@ class Gridmap extends CI_Controller {
$sat = $this->input->post('sat', TRUE);
$orbit = $this->input->post('orbit', TRUE);
$propagation = $this->input->post('propagation', TRUE);
$dxcc = $this->input->post('dxcc', TRUE);
$this->load->model('gridmap_model');
$data['grids'] = $this->gridmap_model->get_grids_for_country($dxcc);
$data['grid_count'] = count($data['grids']);
$array_grid_2char = array();
$array_grid_4char = array();
$array_grid_6char = array();
@@ -78,7 +83,7 @@ class Gridmap extends CI_Controller {
$grid_4char_confirmed = "";
$grid_6char_confirmed = "";
$query = $this->gridmap_model->get_band_confirmed($band, $mode, $qsl, $lotw, $eqsl, $qrz, $sat, $orbit, $propagation);
$query = $this->gridmap_model->get_band_confirmed($band, $mode, $qsl, $lotw, $eqsl, $qrz, $sat, $orbit, $propagation, $dxcc);
if ($query && $query->num_rows() > 0) {
foreach ($query->result() as $row) {
@@ -105,7 +110,7 @@ class Gridmap extends CI_Controller {
}
}
$query = $this->gridmap_model->get_band($band, $mode, $qsl, $lotw, $eqsl, $qrz, $sat, $orbit, $propagation);
$query = $this->gridmap_model->get_band($band, $mode, $qsl, $lotw, $eqsl, $qrz, $sat, $orbit, $propagation, $dxcc);
if ($query && $query->num_rows() > 0) {
foreach ($query->result() as $row) {
@@ -132,7 +137,7 @@ class Gridmap extends CI_Controller {
}
}
}
$query_vucc = $this->gridmap_model->get_band_worked_vucc_squares($band, $mode, $qsl, $lotw, $eqsl, $qrz, $sat, $orbit, $propagation);
$query_vucc = $this->gridmap_model->get_band_worked_vucc_squares($band, $mode, $qsl, $lotw, $eqsl, $qrz, $sat, $orbit, $propagation, $dxcc);
if ($query_vucc && $query_vucc->num_rows() > 0) {
foreach ($query_vucc->result() as $row) {
@@ -157,7 +162,7 @@ class Gridmap extends CI_Controller {
}
// // Confirmed Squares
$query_vucc = $this->gridmap_model->get_band_confirmed_vucc_squares($band, $mode, $qsl, $lotw, $eqsl, $qrz, $sat, $orbit, $propagation);
$query_vucc = $this->gridmap_model->get_band_confirmed_vucc_squares($band, $mode, $qsl, $lotw, $eqsl, $qrz, $sat, $orbit, $propagation, $dxcc);
if ($query_vucc && $query_vucc->num_rows() > 0) {
foreach ($query_vucc->result() as $row) {

View File

@@ -704,5 +704,10 @@ class Update extends CI_Controller {
$this->load->model('Update_model');
$this->Update_model->update_check();
}
public function update_vucc_grids() {
$this->load->model('Update_model');
$this->Update_model->update_vucc_grids();
}
}
?>

View File

@@ -0,0 +1,36 @@
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
/*
Create table vuccgrids for use in Gridmap country filtering
*/
class Migration_add_grid_country extends CI_Migration {
public function up()
{
$sql = "CREATE TABLE IF NOT EXISTS vuccgrids (
id INT AUTO_INCREMENT PRIMARY KEY,
adif INT NOT NULL,
gridsquare VARCHAR(8) NOT NULL,
UNIQUE KEY uq_adif_grid (adif, gridsquare)
);";
$this->dbtry($sql);
}
public function down()
{
$sql = "DROP TABLE IF EXISTS vuccgrids;";
$this->dbtry($sql);
}
function dbtry($what) {
try {
$this->db->query($what);
} catch (Exception $e) {
log_message("error", "Something gone wrong while altering a table: ".$e." // Executing: ".$this->db->last_query());
}
}
}

View File

@@ -2,11 +2,9 @@
class Gridmap_model extends CI_Model {
function get_band_confirmed($band, $mode, $qsl, $lotw, $eqsl, $qrz, $sat, $orbit, $propagation, $logbooks_locations_array = NULL) {
if ($logbooks_locations_array == NULL) {
$this->load->model('logbooks_model');
$logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook'));
}
function get_band_confirmed($band, $mode, $qsl, $lotw, $eqsl, $qrz, $sat, $orbit, $propagation, $dxcc) {
$this->load->model('logbooks_model');
$logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook'));
if (!$logbooks_locations_array) {
return null;
@@ -63,17 +61,24 @@ class Gridmap_model extends CI_Model {
$binding[] = $orbit;
}
if ($dxcc != 'All') {
$gridsql = 'select gridsquare from vuccgrids where adif = ?';
$gridquery = $this->db->query($gridsql, array($dxcc));
$gridarray = array_column($gridquery->result_array(), 'gridsquare'); // ✅ extract values
if (!empty($gridarray)) {
$sql .= ' AND substring(COL_GRIDSQUARE,1,4) IN (\'' . implode("','", $gridarray) . '\')';
}
}
$sql .= $this->addQslToQuery($qsl, $lotw, $eqsl, $qrz);
return $this->db->query($sql, $binding);
}
function get_band($band, $mode, $qsl, $lotw, $eqsl, $qrz, $sat, $orbit, $propagation, $logbooks_locations_array = NULL) {
if ($logbooks_locations_array == NULL) {
$this->load->model('logbooks_model');
$logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook'));
}
function get_band($band, $mode, $qsl, $lotw, $eqsl, $qrz, $sat, $orbit, $propagation, $dxcc) {
$this->load->model('logbooks_model');
$logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook'));
if (!$logbooks_locations_array) {
return null;
@@ -130,15 +135,22 @@ class Gridmap_model extends CI_Model {
$binding[] = $orbit;
}
if ($dxcc != 'All') {
$gridsql = 'select gridsquare from vuccgrids where adif = ?';
$gridquery = $this->db->query($gridsql, array($dxcc));
$gridarray = array_column($gridquery->result_array(), 'gridsquare'); // ✅ extract values
if (!empty($gridarray)) {
$sql .= ' AND substring(COL_GRIDSQUARE,1,4) IN (\'' . implode("','", $gridarray) . '\')';
}
}
return $this->db->query($sql, $binding);
}
function get_band_worked_vucc_squares($band, $mode, $qsl, $lotw, $eqsl, $qrz, $sat, $orbit, $propagation, $logbooks_locations_array = NULL) {
if ($logbooks_locations_array == NULL) {
$this->load->model('logbooks_model');
$logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook'));
}
function get_band_worked_vucc_squares($band, $mode, $qsl, $lotw, $eqsl, $qrz, $sat, $orbit, $propagation, $dxcc) {
$this->load->model('logbooks_model');
$logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook'));
if (!$logbooks_locations_array) {
return null;
@@ -198,18 +210,14 @@ class Gridmap_model extends CI_Model {
return $this->db->query($sql, $binding);
}
function get_band_confirmed_vucc_squares($band, $mode, $qsl, $lotw, $eqsl, $qrz, $sat, $orbit, $propagation, $logbooks_locations_array = NULL) {
if ($logbooks_locations_array == NULL) {
$this->load->model('logbooks_model');
$logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook'));
}
function get_band_confirmed_vucc_squares($band, $mode, $qsl, $lotw, $eqsl, $qrz, $sat, $orbit, $propagation, $dxcc) {
$this->load->model('logbooks_model');
$logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook'));
if (!$logbooks_locations_array) {
return null;
}
$location_list = "'".implode("','",$logbooks_locations_array)."'";
$binding = [];
@@ -300,7 +308,7 @@ class Gridmap_model extends CI_Model {
* Get's the worked modes from the log
*/
function get_worked_modes() {
$this->load->model('logbooks_model');
$logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook'));
@@ -331,4 +339,19 @@ class Gridmap_model extends CI_Model {
return $results;
}
function get_countries() {
$sql = 'SELECT distinct vuccgrids.adif, dxcc_entities.name, dxcc_entities.prefix from vuccgrids join dxcc_entities on vuccgrids.adif = dxcc_entities.adif
where name is not null and name != "" order by prefix';
return $this->db->query($sql);
}
function get_grids_for_country($dxcc) {
$gridsql = 'select gridsquare from vuccgrids where adif = ?';
$gridquery = $this->db->query($gridsql, array($dxcc));
$gridarray = array_column($gridquery->result_array(), 'gridsquare');
return $gridarray;
}
}

View File

@@ -625,4 +625,47 @@ class Update_model extends CI_Model {
return $result;
}
function update_vucc_grids() {
// set the last run in cron table for the correct cron id
$this->load->model('cron_model');
$this->cron_model->set_last_run($this->router->class . '_' . $this->router->method);
// $url = 'https://sourceforge.net/p/trustedqsl/tqsl/ci/master/plain/apps/vuccgrids.dat';
$url = 'https://sourceforge.net/p/trustedqsl/tqsl/ci/master/tree/apps/vuccgrids.dat?format=raw';
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
$response = curl_exec($curl);
$xml = @simplexml_load_string($response);
if ($xml === false) {
die("Failed to parse XML.");
}
// Truncate the table first
$this->db->query("TRUNCATE TABLE vuccgrids;");
// Loop through <vucc> elements
foreach ($xml->vucc as $vucc) {
$adif = (int)$vucc['entity']; // assuming "entity" attribute is ADIF
$grid = strtoupper(trim((string)$vucc['grid']));
if ($adif > 0 && $grid !== '') {
// Insert with duplicate handling
$sql = "INSERT INTO vuccgrids (adif, gridsquare)
VALUES (?, ?)
ON DUPLICATE KEY UPDATE id = id";
$this->db->query($sql, [$adif, $grid]);
}
}
curl_close($curl);
return;
}
}

View File

@@ -108,6 +108,18 @@
?>
</select>
</div>
<?php if(count($countries->result()) > 0) { ?>
<label class="col-md-2" for="country">Country</label>
<div class="col-sm-3">
<select class="form-select form-select-sm" id="dxcc">
<option value="All"><?= __("All") ?></option>
<?php foreach($countries->result() as $country_option) {
echo '<option value="' . $country_option->adif . '"';
echo '>' . $country_option->prefix . ' - ' . ucwords(strtolower($country_option->name)). '</option>' . "\n";
} ?>
</select>
</div>
<?php } ?>
</div>
<div class="row mb-2">

View File

@@ -86,13 +86,22 @@ L.Maidenhead = L.LayerGroup.extend({
this.addLayer(L.rectangle(bounds, {className: 'grid-rectangle', color: this.options.color, weight: 1, fill:false, interactive: false}));
}
} else {
if (zoom < 3 || zoom > 5) {
this.addLayer(L.rectangle(bounds, {className: 'grid-rectangle', color: this.options.color, weight: 1, fill:false, interactive: false}));
if (grids.includes(locator) && grids !== '') {
var rect = L.rectangle(bounds, {className: 'grid-rectangle grid-unworked', color: 'rgba(0,0,0, 0.3)', weight: 1, fillOpacity: 0.15, fill:true, interactive: false});
this.addLayer(rect);
this.addLayer(this._getLabel(lon+unit-(unit/lcor),lat+(unit/2)+(unit/lcor*c)));
}
if (grids == '') {
if (zoom < 3 || zoom > 5) { // Controls if grid lines are shown according to zoom level
this.addLayer(L.rectangle(bounds, {className: 'grid-rectangle', color: this.options.color, weight: 1, fill:false, interactive: false}));
}
}
}
// This one shows all grids, not just the worked/confirmed
if (zoom < 3 || zoom > 5) {
this.addLayer(this._getLabel(lon+unit-(unit/lcor),lat+(unit/2)+(unit/lcor*c)));
if (grids == '') {
if (zoom < 3 || zoom > 5) {
this.addLayer(this._getLabel(lon+unit-(unit/lcor),lat+(unit/2)+(unit/lcor*c)));
}
}
}
}
@@ -134,6 +143,7 @@ L.Maidenhead = L.LayerGroup.extend({
} else {
title = '<span class="grid-text-unworked" style="cursor: default;"><font style="color:'+this.options.color+'; font-size:'+size+'; font-weight: 900; ">' + locator + '</font></span>';
}
}
var myIcon = L.divIcon({className: 'my-div-icon', html: title});
var marker = L.marker([lat,lon], {icon: myIcon}, clickable=false);
@@ -183,12 +193,7 @@ L.Maidenhead = L.LayerGroup.extend({
var title_size = new Array(0, 10, 12, 16, 20, 26, 26, 16, 24, 36, 12, 14, 20, 36, 60, 12, 20, 36, 60, 12, 24);
var zoom = map.getZoom();
var size = title_size[zoom]+'px';
if(grid_four.includes(locator) || grid_four_confirmed.includes(locator) || grid_two.includes(locator) || grid_two_confirmed.includes(locator)) {
var title = '<span class="grid-text-worked" style="cursor: default;"><font style="color:'+this.options.color+'; font-size:'+size+'; font-weight: 900; ">' + this._getLocator2(lon,lat) + '</font></span>';
} else {
var title = '<span class="grid-text-unworked" style="cursor: default;"><font style="color:'+this.options.color+'; font-size:'+size+'; font-weight: 900; ">' + this._getLocator2(lon,lat) + '</font></span>';
}
var title = '<span class="grid-text" style="cursor: default;"><font style="color:'+this.options.color+'; font-size:'+size+'; font-weight: 900; ">' + this._getLocator2(lon,lat) + '</font></span>';
var myIcon = L.divIcon({className: 'my-div-icon', html: title});
var marker = L.marker([lat,lon], {icon: myIcon}, clickable=false);
return marker;

View File

@@ -79,7 +79,8 @@ function gridPlot(form, visitor=true) {
qrz: $("#qrz").is(":checked"),
sat: $("#sat").val(),
orbit: $("#orbits").val(),
propagation: $('#propagation').val()
propagation: $('#propagation').val(),
dxcc: $('#dxcc').val(),
},
success: function (data) {
$('.cohidden').show();
@@ -93,7 +94,9 @@ function gridPlot(form, visitor=true) {
grid_two_confirmed = data.grid_2char_confirmed;
grid_four_confirmed = data.grid_4char_confirmed;
grid_six_confirmed = data.grid_6char_confirmed;
plot(visitor, grid_two, grid_four, grid_six, grid_two_confirmed, grid_four_confirmed, grid_six_confirmed);
grids = data.grids;
grid_max = data.grid_count;
plot(visitor, grid_two, grid_four, grid_six, grid_two_confirmed, grid_four_confirmed, grid_six_confirmed, grids, grid_max);
},
error: function (data) {
@@ -104,7 +107,7 @@ function gridPlot(form, visitor=true) {
};
}
function plot(visitor, grid_two, grid_four, grid_six, grid_two_confirmed, grid_four_confirmed, grid_six_confirmed) {
function plot(visitor, grid_two, grid_four, grid_six, grid_two_confirmed, grid_four_confirmed, grid_six_confirmed, grids, grid_max) {
var layer = L.tileLayer(jslayer, {
maxZoom: 12,
attribution: jsattribution,
@@ -135,18 +138,31 @@ function plot(visitor, grid_two, grid_four, grid_six, grid_two_confirmed, grid_f
/*Legend specific*/
var legend = L.control({ position: "topright" });
legend.onAdd = function(map) {
var div = L.DomUtil.create("div", "legend");
div.innerHTML += "<h4>" + gridsquares_gridsquares + "</h4>";
div.innerHTML += '<i style="background: green"></i><span>' + gridsquares_gridsquares_confirmed + ' ('+grid_four_confirmed.length+')</span><br>';
div.innerHTML += '<i style="background: red"></i><span>' + gridsquares_gridsquares_not_confirmed + ' ('+(grid_four.length - grid_four_confirmed.length)+')</span><br>';
div.innerHTML += '<i></i><span>' + gridsquares_gridsquares_total_worked + ' ('+grid_four.length+')</span><br>';
div.innerHTML += "<h4>" + gridsquares_fields + "</h4>";
div.innerHTML += '<i style="background: green"></i><span>' + gridsquares_fields_confirmed + ' ('+grid_two_confirmed.length+')</span><br>';
div.innerHTML += '<i style="background: red"></i><span>' + gridsquares_fields_not_confirmed + ' ('+(grid_two.length - grid_two_confirmed.length)+')</span><br>';
div.innerHTML += '<i></i><span>' + gridsquares_fields_total_worked + ' ('+grid_two.length+')</span><br>';
return div;
};
if (grids != '') {
legend.onAdd = function(map) {
let div = L.DomUtil.create("div", "legend");
html = "<table border=\"0\">";
html += '<i style="background: green"></i><span>' + gridsquares_gridsquares_confirmed + ' ('+grid_four_confirmed.length+')</span><br>';
html += '<i style="background: red"></i><span>' + gridsquares_gridsquares_not_confirmed + ' ('+(grid_four.length - grid_four_confirmed.length)+')</span><br>';
html += '<tr><td><i style="background: #ffd757"></i><span>' + gridsquares_gridsquares_total_worked + ' ('+(Math.round((grid_four.length / grid_max) * 10000) / 100)+'%):</span></td><td style=\"padding-left: 1em; text-align: right;\"><span>'+(grid_four.length)+' / '+grid_max+'</span></td></tr>';
html += "</table>";
div.innerHTML = html;
return div;
};
} else {
legend.onAdd = function(map) {
let div = L.DomUtil.create("div", "legend");
div.innerHTML += "<h4>" + gridsquares_gridsquares + "</h4>";
div.innerHTML += '<i style="background: green"></i><span>' + gridsquares_gridsquares_confirmed + ' ('+grid_four_confirmed.length+')</span><br>';
div.innerHTML += '<i style="background: red"></i><span>' + gridsquares_gridsquares_not_confirmed + ' ('+(grid_four.length - grid_four_confirmed.length)+')</span><br>';
div.innerHTML += '<i></i><span>' + gridsquares_gridsquares_total_worked + ' ('+grid_four.length+')</span><br>';
div.innerHTML += "<h4>Fields</h4>";
div.innerHTML += '<i style="background: green"></i><span>Fields confirmed ('+grid_two_confirmed.length+')</span><br>';
div.innerHTML += '<i style="background: red"></i><span>Fields not confirmed ('+(grid_two.length - grid_two_confirmed.length)+')</span><br>';
div.innerHTML += '<i></i><span>Total fields worked ('+grid_two.length+')</span><br>';
return div;
};
}
legend.addTo(map);