Conversion of Maidenhead to approx. location

main
Michał Rudowicz 2022-05-15 09:33:38 +02:00
rodzic ee7b194b78
commit 2a5843af1f
5 zmienionych plików z 91 dodań i 55 usunięć

Wyświetl plik

@ -19,11 +19,11 @@
namespace Hamlocator {
public class Application : Adw.Application {
private Location location;
private LocationToMaidenhead l2m;
private MaidenheadConverter mc;
public Application () {
Object (application_id: "eu.fl9.hamlocator", flags: ApplicationFlags.FLAGS_NONE);
l2m = new LocationToMaidenhead();
mc = new MaidenheadConverter();
}
construct {
@ -58,7 +58,7 @@ namespace Hamlocator {
win.SetLabel("unable to\nget location");
win.SetDetails(@"Reason:\n$(pos.err)");
} else {
win.SetLabel(l2m.get_locator(pos.loc));
win.SetLabel(mc.location_to_maidenhead(pos.loc));
win.SetDetails(@"lat: $(pos.loc.latitude)°\nlon: $(pos.loc.longitude)°");
}
win.SetRefreshButtonEnabled(true);

Wyświetl plik

@ -3,14 +3,13 @@
// https://metacpan.org/release/MEH/Ham-Locator-0.1000/source/lib/Ham/Locator.pm
namespace Hamlocator {
public class LocationToMaidenhead : Object {
private string l2m;
public class MaidenheadConverter : Object {
private const char[] L2M = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};
private const double[] M2L_MULTIPLIERS = {10.0, 1.0, 1.0/24.0, 1.0/240.0, 1.0/5760.0};
public LocationToMaidenhead() {
this.l2m = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
}
public MaidenheadConverter() {}
public string get_locator(GClue.Location pos) {
public string location_to_maidenhead(GClue.Location pos) {
double lat = pos.latitude + 90;
double lon = pos.longitude + 180;
@ -18,7 +17,7 @@ namespace Hamlocator {
double lat1 = (lat / 10);
double lon1 = (lon / 20);
string loc1 = @"$(this.l2m[Math.lround(Math.floor(lon1))])$(this.l2m[Math.lround(Math.floor(lat1))])";
string loc1 = @"$(L2M[Math.lround(Math.floor(lon1))])$(L2M[Math.lround(Math.floor(lat1))])";
// Square
double lat2 = 10 * (lat1 - Math.floor(lat1));
@ -30,9 +29,40 @@ namespace Hamlocator {
double lat3 = 24 * (lat2 - Math.floor(lat2));
double lon3 = 24 * (lon2 - Math.floor(lon2));
string loc3 = @"$(this.l2m[Math.lround(Math.floor(lon3))])$(this.l2m[Math.lround(Math.floor(lat3))])".down();
string loc3 = @"$(L2M[Math.lround(Math.floor(lon3))])$(L2M[Math.lround(Math.floor(lat3))])".down();
return @"$loc1$loc2$loc3";
}
public GClue.Location? maidenhead_to_location(string locator) {
double lat = 0.0;
double lon = 0.0;
if (locator.length % 2 != 0) {
warning("Locator needs to be of even length");
return null;
}
long i = 0; // where we are in the locator
long mult_i = 0; // which multiplier are we currently using
var upLocator = locator.up();
while (i < upLocator.length) {
// letters
lon += (upLocator[i++] - 'A') * 2.0 * M2L_MULTIPLIERS[mult_i];
lat += (upLocator[i++] - 'A') * M2L_MULTIPLIERS[mult_i];
mult_i++;
if (i >= upLocator.length) { break; }
// numbers
lon += (upLocator[i++] - '0') * 2.0 * M2L_MULTIPLIERS[mult_i];
lat += (upLocator[i++] - '0') * M2L_MULTIPLIERS[mult_i];
mult_i++;
}
// move to the center of the box
mult_i--;
lon += 0.5 * 2.0 * M2L_MULTIPLIERS[mult_i];
lat += 0.5 * M2L_MULTIPLIERS[mult_i];
return new SimpleLocation((lat - 90.0), (lon - 180.0));
}
}
}

Wyświetl plik

@ -2,14 +2,14 @@ hamlocator_sources = [
'window.vala',
'application.vala',
'location.vala',
'maidenhead.vala'
'maidenhead.vala',
'simple_location.vala'
]
test_sources = [
'tests' / 'main.vala',
'tests' / 'testcase.vala',
'tests' / 'maidenhead_tests.vala',
'tests' / 'fake_geoclue_location.vala'
]
hamlocator_deps = [

Wyświetl plik

@ -1,37 +1,37 @@
public class FakeGeoclueLocation : GLib.Object, GClue.Location {
public class SimpleLocation : GLib.Object, GClue.Location {
private double lat;
private double lon;
public FakeGeoclueLocation(double lat, double lon) {
public SimpleLocation(double lat, double lon) {
this.lat = lat;
this.lon = lon;
}
public override double accuracy {
public override double accuracy {
get { return double.NAN; }
set { assert(false); }
}
public override double altitude {
public override double altitude {
get { return double.NAN; }
set { assert(false); }
}
public override string description { owned
public override string description { owned
get { return ""; }
set { assert(false); }
}
public override double heading {
public override double heading {
get { return double.NAN; }
set { assert(false); }
}
public override double latitude {
public override double latitude {
get { return this.lat; }
set { assert(false); }
}
public override double longitude {
public override double longitude {
get { return this.lon; }
set { assert(false); }
}
public override double speed {
public override double speed {
get { return double.NAN; }
set { assert(false); }
}

Wyświetl plik

@ -1,45 +1,51 @@
public class MaidenheadTests : TestCase {
public MaidenheadTests() {
base("Maidenhead Tests");
add_test_location(0.0, 0.0, "JJ00aa");
add_test_location(90.0, 0.0, "JS00aa");
add_test_location(0.0, 180.0, "SJ00aa");
add_test_location(90.0, 180.0, "SS00aa");
add_test_location(-90.0, 0.0, "JA00aa");
add_test_location(0.0, -180.0, "AJ00aa");
add_test_location(-90.0, -180.0, "AA00aa");
add_test_location(90.0, -180.0, "AS00aa");
add_test_location(-90.0, 180.0, "SA00aa");
add_test_maidenhead(0.0, 0.0, "JJ00aa");
add_test_maidenhead(90.0, 0.0, "JS00aa");
add_test_maidenhead(0.0, 180.0, "SJ00aa");
add_test_maidenhead(90.0, 180.0, "SS00aa");
add_test_maidenhead(-90.0, 0.0, "JA00aa");
add_test_maidenhead(0.0, -180.0, "AJ00aa");
add_test_maidenhead(-90.0, -180.0, "AA00aa");
add_test_maidenhead(90.0, -180.0, "AS00aa");
add_test_maidenhead(-90.0, 180.0, "SA00aa");
add_test_location(51.0, 17.0, "JO80lx");
add_test_location(51.1, 17.1, "JO81nc");
add_test_location(51.2, 17.2, "JO81oe");
add_test_location(51.3, 17.3, "JO81ph");
add_test_location(51.4, 17.4, "JO81qj");
add_test_location(51.5, 17.5, "JO81sm");
add_test_location(51.6, 17.6, "JO81to");
add_test_location(51.7, 17.7, "JO81uq");
add_test_location(51.8, 17.8, "JO81vt");
add_test_location(51.9, 17.9, "JO81wv");
add_test_location(51.99, 17.99, "JO81xx");
add_test_maidenhead(51.0, 17.0, "JO80lx");
add_test_maidenhead(51.1, 17.1, "JO81nc");
add_test_maidenhead(51.2, 17.2, "JO81oe");
add_test_maidenhead(51.3, 17.3, "JO81ph");
add_test_maidenhead(51.4, 17.4, "JO81qj");
add_test_maidenhead(51.5, 17.5, "JO81sm");
add_test_maidenhead(51.6, 17.6, "JO81to");
add_test_maidenhead(51.7, 17.7, "JO81uq");
add_test_maidenhead(51.8, 17.8, "JO81vt");
add_test_maidenhead(51.9, 17.9, "JO81wv");
add_test_maidenhead(51.99, 17.99, "JO81xx");
add_test_location(51.1205, 17.0261, "JO81mc");
add_test_location(37.1104, -5.4932, "IM77gc");
add_test_location(-30.5377, 22.8516, "KF19kl");
add_test_location(-27.4613, -65.0391, "FG72lm");
add_test_location(-24.6168, 136.4063, "PG85ej");
add_test_maidenhead(51.1205, 17.0261, "JO81mc");
add_test_maidenhead(37.1104, -5.4932, "IM77gc");
add_test_maidenhead(-30.5377, 22.8516, "KF19kl");
add_test_maidenhead(-27.4613, -65.0391, "FG72lm");
add_test_maidenhead(-24.6168, 136.4063, "PG85ej");
}
protected Hamlocator.LocationToMaidenhead tested;
protected Hamlocator.MaidenheadConverter tested;
public override void set_up() {
this.tested = new Hamlocator.LocationToMaidenhead();
this.tested = new Hamlocator.MaidenheadConverter();
}
public void add_test_location(double lat, double lon, string expected) {
add_test (@"Expect location lat:$lat lon:$lon to be $expected", () => {
GClue.Location pos = new FakeGeoclueLocation(lat, lon);
assert_cmpstr(this.tested.get_locator(pos), EQ, expected);
public void add_test_maidenhead(double lat, double lon, string locator) {
add_test (@"Expect location lat:$lat lon:$lon to be $locator", () => {
GClue.Location pos = new SimpleLocation(lat, lon);
assert_cmpstr(this.tested.location_to_maidenhead(pos), EQ, locator);
});
add_test (@"Expect location at $locator to be approx. lat:$lat lon:$lon", () => {
GClue.Location pos = this.tested.maidenhead_to_location(locator);
assert_nonnull(pos);
assert_cmpfloat_with_epsilon(pos.latitude, lat, (1.0/24.0));
assert_cmpfloat_with_epsilon(pos.longitude, lon, (2.0/24.0));
});
}
}