fix(qth): correct Maidenhead boundaries and longitude wrapping
A full-domain round-trip probe found three related boundary bugs.
1. Exact positive limits wrapped the square/subsquare terms to zero
positionToQth clamped only the A-R field index. At +90 latitude / +180
longitude the field saturated at R, but all later terms used modulo and wrapped
to square 0 / subsquare a:
(90, 180) -> RR00aa00 -> (80.002083, 160.004167)
error: -9.998 deg latitude, -19.996 deg longitude
The existing test incorrectly asserted RR00aa00 and had therefore fossilised
the defect. Clamp shifted coordinates just inside the half-open upper bound so
the limits land in the final cell RR99xx99.
2. isValidPosition allowed longitude through +360
Maidenhead covers -180..180, but 181..360 was accepted and produced plausible
locators that decoded 20-200 degrees away:
lon 181 -> decoded 161.004167 (error -19.996)
lon 270 -> decoded 170.004167 (error -99.996)
lon 360 -> decoded 160.004167 (error -199.996)
Restrict the converter contract to -180..180.
3. Locator validation allowed S-X as field letters
The first pair has 18 fields A-R, while only the later subsquare pairs use
A-X. The shared [A-X]{2} regex accepted SS00aa / XX99xx and decoded them past
the poles (up to lat 149.98, lon 299.96). Use A-R for the field pair.
The SettingsRepo caller had a separate wrapping bug that masked part of this:
it mapped longitude>180 by subtracting 180 (270 -> +90, wrong hemisphere)
instead of modulo 360 (270 -> -90). Fix that at the writer too.
Verification:
- standalone JVM sweep: 519,841 points, old code had 1,441 large-error points
with max drift 9.997917 deg lat / 19.995833 deg lon
- new Kotlin regression sweep requires every 8-char round trip <=0.01 deg
- QthConverterTest BUILD SUCCESSFUL
- full :core:domain:test + :core:data:compileReleaseKotlin BUILD SUCCESSFUL
This commit is contained in:
1 parent
7d7abeb31e
commit
d5230b3bc6
3 files changed
+68
-6
No files matched your search
@@ -181,7 +181,10 @@ class SettingsRepo(
|
||||
}
|
||||
|
||||
override fun setStationPosition(latitude: Double, longitude: Double, altitude: Double): Boolean {
|
||||
val newLongitude = if (longitude > 180.0) longitude - 180 else longitude
|
||||
// Wrap an out-of-range longitude into -180..180. Subtracting 180 (the
|
||||
// previous behaviour) mapped 270 to +90 instead of -90, i.e. the wrong
|
||||
// hemisphere, and 360 to +180 instead of 0.
|
||||
val newLongitude = ((longitude + 180.0).mod(360.0)) - 180.0
|
||||
val locator = positionToQth(latitude, newLongitude) ?: return false
|
||||
setStationPosition(latitude, newLongitude, altitude, locator)
|
||||
return true
|
||||
|
||||
Reference in new issue
Block a user