fix(webpub): the Distance column was empty for every QSO logged here
Nothing computes a distance when a QSO is logged. The DISTANCE field is only ever filled by an ADIF import that carried one, so publishing it straight gave an empty column to anyone whose log was made in OpsLog — which is everyone who reported it. It falls back to the two locators, which are on the QSO already. A stored distance still wins: it came from the log that recorded the contact, which knew more than two four-character squares do. No grids means an empty cell, not a zero — an empty cell is honest, a zero is a claim. Rounded to whole kilometres. The squares are tens of kilometres across and a decimal would assert an accuracy nobody has. The geometry moved to internal/geo on the way. It lived in package main, which internal packages cannot import, so the PSK Reporter watcher already had its maths injected from main and this would have been a third copy. A bearing that disagrees with itself between two panels is a fault nobody reports, because each screen looks perfectly plausible on its own.
This commit is contained in:
@@ -33,6 +33,7 @@ import (
|
||||
|
||||
"github.com/jlaffaye/ftp"
|
||||
|
||||
"hamlog/internal/geo"
|
||||
"hamlog/internal/qso"
|
||||
)
|
||||
|
||||
@@ -93,6 +94,26 @@ func flt(p *float64) string {
|
||||
return strconv.FormatFloat(*p, 'f', -1, 64)
|
||||
}
|
||||
|
||||
// distanceKm is the path length for the Distance column.
|
||||
//
|
||||
// The stored DISTANCE field is only ever filled by an ADIF import that carried
|
||||
// one — OpsLog does not compute it when logging — so publishing it straight gave
|
||||
// an empty column for every QSO made here, which is how this was reported.
|
||||
//
|
||||
// So it falls back to the two locators, which are on the QSO already. Rounded to
|
||||
// whole kilometres: the grids are squares tens of kilometres across, and a
|
||||
// decimal on a figure that imprecise claims an accuracy nobody has.
|
||||
func distanceKm(q *qso.QSO) string {
|
||||
if q.Distance != nil && *q.Distance > 0 {
|
||||
return flt(q.Distance)
|
||||
}
|
||||
km, ok := geo.DistanceBetweenGrids(q.MyGrid, q.Grid)
|
||||
if !ok || km <= 0 {
|
||||
return ""
|
||||
}
|
||||
return strconv.FormatFloat(km, 'f', 0, 64)
|
||||
}
|
||||
|
||||
func stamp(t time.Time) string {
|
||||
if t.IsZero() {
|
||||
return ""
|
||||
@@ -218,7 +239,7 @@ var Columns = []Column{
|
||||
{"my_sig_info", "My sig info", "My station", func(q *qso.QSO) string { return q.MySIGInfo }},
|
||||
{"wwff_ref", "WWFF", "Awards", func(q *qso.QSO) string { return q.WWFFRef }},
|
||||
{"my_wwff_ref", "My wwff ref", "My station", func(q *qso.QSO) string { return q.MyWWFFRef }},
|
||||
{"distance", "Distance", "Location", func(q *qso.QSO) string { return flt(q.Distance) }},
|
||||
{"distance", "Distance", "Location", distanceKm},
|
||||
{"rx_pwr", "RX pwr", "QSO", func(q *qso.QSO) string { return flt(q.RXPower) }},
|
||||
{"a_index", "A", "QSO", func(q *qso.QSO) string { return flt(q.AIndex) }},
|
||||
{"k_index", "K", "QSO", func(q *qso.QSO) string { return flt(q.KIndex) }},
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package webpub
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"hamlog/internal/qso"
|
||||
)
|
||||
|
||||
// The Distance column was published empty for every QSO logged in OpsLog: the
|
||||
// stored DISTANCE field is only ever filled by an ADIF import that carried one,
|
||||
// and nothing computes it when logging. It falls back to the two locators.
|
||||
func TestDistanceFallsBackToTheGrids(t *testing.T) {
|
||||
// JN36 (French Alps) to IO91 (southern England): a few hundred kilometres.
|
||||
got := distanceKm(&qso.QSO{MyGrid: "JN36DG", Grid: "IO91"})
|
||||
if got == "" {
|
||||
t.Fatal("no distance from two perfectly good locators")
|
||||
}
|
||||
if got == "0" {
|
||||
t.Errorf("distance = %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
// A stored distance wins: it came from the log that recorded the QSO, which knew
|
||||
// more than two four-character squares do.
|
||||
func TestStoredDistanceWins(t *testing.T) {
|
||||
d := 1234.0
|
||||
if got := distanceKm(&qso.QSO{Distance: &d, MyGrid: "JN36", Grid: "IO91"}); got != "1234" {
|
||||
t.Errorf("distance = %q, want the stored 1234", got)
|
||||
}
|
||||
}
|
||||
|
||||
// No grids, no invention. An empty cell is honest; a zero is a claim.
|
||||
func TestNoGridsNoDistance(t *testing.T) {
|
||||
for _, q := range []qso.QSO{{}, {MyGrid: "JN36"}, {Grid: "IO91"}, {MyGrid: "??", Grid: "IO91"}} {
|
||||
if got := distanceKm(&q); got != "" {
|
||||
t.Errorf("distance(%+v) = %q, want empty", q, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user