mirror of
https://github.com/Xastir/Xastir
synced 2026-08-13 17:46:16 -04:00
Wheen I replaced the non-portable "#!/usr/bin/perl" with the portable "#!/usr/bin/env perl" I neglected the fact that some scripts have a -w or -W argument after the command. This can't work with env, and the correct approach is to put "use warnings;" in the script instead.
389 lines
11 KiB
Perl
Executable file
389 lines
11 KiB
Perl
Executable file
#!/usr/bin/env perl
|
|
use warnings;
|
|
|
|
#
|
|
# Written by Paul Lutt, KE7XT & Curt Mills, WE7U.
|
|
# Released to the public domain.
|
|
#
|
|
#
|
|
#
|
|
# Finds the different lat/long representations corresponding to the
|
|
# input numbers. A space is required between the degrees portion
|
|
# and the rest of the input. Writes out a log file containing APRS
|
|
# objects suitable for importing into Xastir, to graphically plot
|
|
# the locations of the objects. Now that Xastir has a server port
|
|
# we could directly inject them into the program via that route as
|
|
# well, but we currently don't do that.
|
|
#
|
|
# Converts between different lat/lon formats. Will also give UMS
|
|
# position if the lat/lon resides somewhere inside the Seattle area
|
|
# aeronautical map.
|
|
#
|
|
# UMS coordinates have been used in the past by King County, WA SAR.
|
|
# It can be useful for plotting positions on Green Trails maps and
|
|
# perhaps other maps. The maps must be 15' topo maps and marked in
|
|
# tenths of miles along the edge in order to make use of this
|
|
# coordinate system.
|
|
#
|
|
# Web pages which discuss UMS format:
|
|
# http://www.impulse.net/~mlynch/land_nav.html
|
|
# http://www.logicsouth.com/~lcoble/dir9/land_nav.htm
|
|
# http://www.aasar.org/training/academy/navigation.pdf
|
|
#
|
|
|
|
|
|
use lib "/usr/local/lib";
|
|
use Coordinate; # WE7U's Coordinate.pm module
|
|
|
|
|
|
# Get the username
|
|
$user = getlogin;
|
|
chomp $user;
|
|
$filename = "/var/tmp/PERMUTATIONS-$user.log";
|
|
|
|
|
|
sub convert {
|
|
|
|
# Snag the input
|
|
$_ = $_[0];
|
|
|
|
print "\n";
|
|
|
|
# If the first item has 2 digits and one character and there are
|
|
# three "words" in the input, we're starting with a UTM value.
|
|
if (/^\d\d[a-zA-Z]\s+\w+\s+\w+\s*$/) {
|
|
|
|
# printf("Found a UTM value\n");
|
|
|
|
# We'll convert it to the standard format first and then run
|
|
# through the rest of the code.
|
|
|
|
$zone = $_;
|
|
$easting = $_;
|
|
$northing = $_;
|
|
|
|
$zone =~ s/^(\d\d[a-zA-Z])\s+\w+\s+\w+\s*$/$1/;
|
|
$easting =~ s/^\d\d[a-zA-Z]\s+(\w+)\s+\w+\s*$/$1/;
|
|
$northing =~ s/^\d\d[a-zA-Z]\s+\w+\s+(\w+)\s*$/$1/;
|
|
|
|
if ($easting > 999999) {
|
|
printf("Easting value is too high!\n");
|
|
return;
|
|
}
|
|
|
|
$position->zone($zone);
|
|
$position->easting($easting);
|
|
$position->northing($northing);
|
|
|
|
# Convert to lat/lon values
|
|
$position->utm_to_lat_lon();
|
|
|
|
# printf("Calculated Lat, Long position(Lat, Long): %f %f\n",
|
|
# $position->latitude(),
|
|
# $position->longitude() );
|
|
|
|
$latitude = $position->latitude();
|
|
$longitude = $position->longitude();
|
|
|
|
$lat_dir = "N";
|
|
$long_dir = "E";
|
|
|
|
if ($latitude < 0.0) {
|
|
$latitude = abs($latitude);
|
|
$lat_dir = "S"
|
|
}
|
|
if ($longitude < 0.0) {
|
|
$longitude = abs($longitude);
|
|
$long_dir = "W";
|
|
}
|
|
|
|
|
|
# printf("%f%s %f%s\n", $latitude,$lat_dir,$longitude,$long_dir);
|
|
|
|
$_ = sprintf("%f%s %f%s",
|
|
$latitude,$lat_dir,$longitude,$long_dir);
|
|
|
|
}
|
|
|
|
# Look for lat/long value in the input
|
|
|
|
# Check for N/S/E/W characters in the input. Set the
|
|
# appropriate flags if found.
|
|
$lat_dir = "N";
|
|
$long_dir = "E";
|
|
if (/S/ || /s/) { $lat_dir = "S"; }
|
|
if (/W/ || /w/) { $long_dir = "W"; }
|
|
# Filter out these characters from the input
|
|
tr/nsewNSEW//d;
|
|
|
|
# Convert to DD MM SS format
|
|
($lat_deg, $lat_min, $lat_sec,
|
|
$long_deg, $long_min, $long_sec) = split(' ');
|
|
|
|
# Decimal Degrees?
|
|
if ($lat_deg =~ /\./) {
|
|
|
|
$long_deg = $lat_min; # Save long_degrees in proper place
|
|
|
|
$temp = $lat_deg;
|
|
$lat_deg = int $temp;
|
|
$lat_min = int ((abs($temp) * 60.0) % 60);
|
|
|
|
# Modulus converts to integers, so we bump up by 10 and then
|
|
# back down.
|
|
$lat_sec = (abs($temp) * 36000.0) % 600;
|
|
$lat_sec = $lat_sec / 10;
|
|
|
|
$temp = $long_deg;
|
|
|
|
$long_deg = int $temp;
|
|
$long_min = int ((abs($temp) * 60.0) % 60);
|
|
$long_sec = (abs($temp) * 36000.0) % 600;
|
|
$long_sec = $long_sec / 10;
|
|
}
|
|
# Decimal Minutes?
|
|
elsif ($lat_min =~ /\./) {
|
|
|
|
$long_min = $long_deg; # Save long_minutes in proper place
|
|
$long_deg = $lat_sec; # Save long_degrees in proper place
|
|
|
|
$temp = $lat_min;
|
|
$lat_min = int abs($temp);
|
|
$lat_sec = (abs($temp) * 60.0) % 60;
|
|
$lat_sec = $lat_sec / 10;
|
|
|
|
$temp = $long_min;
|
|
$long_min = int abs($temp);
|
|
$long_sec = (abs($temp) * 600.0) % 600;
|
|
$long_sec = $long_sec / 10;
|
|
}
|
|
# Decimal Seconds
|
|
else { # Already in DD MM SS format, don't convert
|
|
}
|
|
|
|
# Print out the three lat/long formats
|
|
printf(" Decimal Degrees: %8.5f%s %8.5f%s\n",
|
|
$lat_deg + ($lat_min/60.0) + ($lat_sec/3600.0), $lat_dir,
|
|
$long_deg + ($long_min/60.0) + ($long_sec/3600.0), $long_dir );
|
|
|
|
printf(" Degrees/Decimal Minutes: %02d %06.3f%s %02d %06.3f%s\n",
|
|
$lat_deg, $lat_min + ($lat_sec/60.0), $lat_dir,
|
|
$long_deg, $long_min + ($long_sec/60.0), $long_dir );
|
|
|
|
printf(" Degrees/Minutes/Dec. Seconds: %02d %02d %4.1f%s %02d %02d %4.1f%s\n",
|
|
$lat_deg, $lat_min, $lat_sec, $lat_dir,
|
|
$long_deg, $long_min, $long_sec, $long_dir);
|
|
|
|
# Dump out the coordinate in APRS Item format:
|
|
printf(FH "TEST>APRS:)%s!%02d%05.2f%s/%03d%05.2f%s/\n",
|
|
$_[1],
|
|
$lat_deg,
|
|
$lat_min + ($lat_sec/60.0),
|
|
$lat_dir,
|
|
$long_deg,
|
|
$long_min + ($long_sec/60.0),
|
|
$long_dir );
|
|
|
|
# Fill in the coordinate object with the current lat/lon.
|
|
# Assuming WGS84 datum
|
|
if ($lat_dir =~ /S/) {
|
|
$position->latitude( -( $lat_deg + ($lat_min/60.0) + ($lat_sec/3600.0) ) );
|
|
}
|
|
else {
|
|
$position->latitude( $lat_deg + ($lat_min/60.0) + ($lat_sec/3600.0) );
|
|
}
|
|
|
|
if ($long_dir =~ /W/) {
|
|
$position->longitude( -( $long_deg + ($long_min/60.0) + ($long_sec/3600.0) ) );
|
|
}
|
|
else {
|
|
$position->longitude( $long_deg + ($long_min/60.0) + ($long_sec/3600.0) );
|
|
}
|
|
|
|
#printf("%f %f\n",$position->latitude,$position->longitude);
|
|
|
|
$position->lat_lon_to_utm();
|
|
printf(" Universal Transverse Mercator: %s %07.0f %07.0f\n",
|
|
$position->zone(),
|
|
$position->easting(),
|
|
$position->northing() );
|
|
|
|
# Check whether the coordinates are within the SEA aeronautical
|
|
# map area
|
|
$lat_err = 0;
|
|
if ($lat_dir =~ /S/ ||
|
|
$lat_deg < 44 || $lat_deg > 49 ||
|
|
($lat_deg == 44 && ($lat_min < 30 || ($lat_min == 30 && $lat_sec == 0))) ||
|
|
($lat_deg == 49 && ($lat_min > 0 || $lat_sec > 0))) {
|
|
print " lat. out of range ";
|
|
$lat_err = 1;
|
|
}
|
|
|
|
$long_err = 0;
|
|
if ($long_dir =~ /E/ ||
|
|
$long_deg < 117 || $long_deg > 125 ||
|
|
($long_deg == 117 && ($long_min == 0 && $long_sec == 0)) ||
|
|
($long_deg == 125 && ($long_min > 0 || $long_sec > 0))) {
|
|
print " long. out of range";
|
|
$long_err = 1;
|
|
}
|
|
|
|
return if ( $lat_err || $long_err);
|
|
|
|
|
|
# Compute UMS coordinates
|
|
$y_sec = 3600 * ($lat_deg - 44) + 60 * $lat_min + $lat_sec;
|
|
$y_sec = 18000 - $y_sec;
|
|
|
|
$x_sec = 3600 * ($long_deg - 117) + 60 * $long_min + $long_sec;
|
|
$x_sec = 28800 - $x_sec;
|
|
|
|
$quad = 32 * int($y_sec / 900) + int($x_sec / 900) + 1;
|
|
|
|
# print "\tx_sec= $x_sec, y_sec= $y_sec, quad= $quad\n";
|
|
|
|
$y_subquad_offset = int($y_sec / 450);
|
|
$x_subquad_offset = int($x_sec / 450);
|
|
|
|
if (&even($x_subquad_offset) && &even($y_subquad_offset)) {
|
|
print " UMS (Green Trails Maps): SEA ${quad} A ";
|
|
printf "%02d", &s2m_x($x_sec - (450 * $x_subquad_offset));
|
|
printf "%02d\n", &s2m_y($y_sec - (450 * $y_subquad_offset));
|
|
} elsif (&odd($x_subquad_offset) && &even($y_subquad_offset)) {
|
|
print " UMS (Green Trails Maps): SEA ${quad} B ";
|
|
printf "%02d", &s2m_x(450 * ($x_subquad_offset + 1) - $x_sec);
|
|
printf "%02d\n", &s2m_y($y_sec - (450 * $y_subquad_offset));
|
|
} elsif (&even($x_subquad_offset) && &odd($y_subquad_offset)) {
|
|
print " UMS (Green Trails Maps): SEA ${quad} C ";
|
|
printf "%02d", &s2m_x($x_sec - (450 * $x_subquad_offset));
|
|
printf "%02d\n", &s2m_y(450 * ($y_subquad_offset + 1) - $y_sec);
|
|
} else {
|
|
print " UMS (Green Trails Maps): SEA ${quad} D ";
|
|
printf "%02d", &s2m_x(450 * ($x_subquad_offset + 1) - $x_sec);
|
|
printf "%02d\n", &s2m_y(450 * ($y_subquad_offset + 1) - $y_sec);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
sub even {
|
|
return (($_[0] & 1) == 0);
|
|
}
|
|
|
|
|
|
|
|
sub odd {
|
|
return (($_[0] & 1) == 1);
|
|
}
|
|
|
|
|
|
|
|
sub s2m_y {
|
|
return (int((0.1917966 * $_[0]) + 0.5));
|
|
}
|
|
|
|
|
|
|
|
sub s2m_x {
|
|
return (int((cos(($lat_deg + ($lat_min / 60.0) + ($lat_sec / 3600.0)) / 57.29578) * (0.1917966 * $_[0])) + 0.5));
|
|
}
|
|
|
|
|
|
|
|
##############
|
|
# Main Program
|
|
##############
|
|
|
|
open (FH, ">$filename") || die "Couldn't open file for writing:$!\n";
|
|
|
|
|
|
# Create new Coordinate object
|
|
$position = Coordinate->new();
|
|
|
|
|
|
$position->datum("WGS 84"); # Datum
|
|
|
|
|
|
print "\n";
|
|
print "Examples: 48 07228N 122 07228W\n";
|
|
print " 48 08N 122 07W\n";
|
|
print " 10U 0565264 5330343\n";
|
|
|
|
print "\nAPRS Items will be written to: $filename\n";
|
|
print "Enter a Lat/Long value or UTM value:\n";
|
|
|
|
|
|
# Snag the input
|
|
$input = <>;
|
|
|
|
# Get rid of whitespace at the beginning
|
|
$input =~ s/\s*//;
|
|
|
|
# UTM value?
|
|
if ($input =~ /^\d\d[a-zA-Z]\s+\w+\s+\w+\s*$/) {
|
|
|
|
$input2 = $input;
|
|
&convert($input2, "UTM");
|
|
|
|
print "\n";
|
|
|
|
# Swap Easting/Northing values and convert again. Leave the
|
|
# zone in it's original spot.
|
|
$input2 = $input;
|
|
$input2 =~ s/^(\d\d[a-zA-Z])\s+(\w+)\s+(\w+)\s*$/$1 $3 $2\n/;
|
|
|
|
print $input2;
|
|
&convert($input2, "UTM2");
|
|
}
|
|
# else must be lat/lon value
|
|
else {
|
|
|
|
# Need to break up the input into several possible formats,
|
|
# possibly including swapping lat/long pieces and plotting N/S
|
|
# and E/W variants.
|
|
|
|
# I'm going to assume that the user knows his/her approximate
|
|
# lat/lon, so they can input it in roughly the proper format to
|
|
# begin with. All that's left then is to determine which of the
|
|
# three lat/lon formats it's in.
|
|
|
|
# 48 07228N 122 07228W
|
|
|
|
$input =~ s/^(\w+)\s+(\d)(\w)\s+(\w+)\s+(\d)(\w)\s*$/$1 0$2$3 $4 0$5$6\n/;
|
|
|
|
# DD.DDD
|
|
$input2 = $input;
|
|
$input2 =~ s/^(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s*$/$1.$2 $3.$4\n/;
|
|
print $input2;
|
|
&convert($input2, "DD.DDD");
|
|
|
|
print "\n";
|
|
|
|
# DD MM.MMM
|
|
$input2 = $input;
|
|
$input2 =~ s/^(\w+)\s+(\d\d)(\w+)\s+(\w+)\s+(\d\d)(\w+)\s*$/$1 $2.$3 $4 $5.$6\n/;
|
|
$input2 =~ s/(\.N)/.00N/;
|
|
$input2 =~ s/(\.S)/.00S/;
|
|
$input2 =~ s/(\.E)/.00E/;
|
|
$input2 =~ s/(\.W)/.00W/;
|
|
print $input2;
|
|
&convert($input2, "DD MM.MM");
|
|
|
|
print "\n";
|
|
|
|
# DD MM SS.S
|
|
$input2 = $input;
|
|
$input2 =~ s/^(\w+)\s+(\d\d)(\w)\s+(\w+)\s+(\d\d)(\w)\s*$/$1 $2 00.$3 $4 $5 00.$6\n/;
|
|
$input2 =~ s/^(\w+)\s+(\d\d)(\d)(\w)\s+(\w+)\s+(\d\d)(\d)(\w)\s*$/$1 $2 $3.$4 $5 $6 $7.$8\n/;
|
|
$input2 =~ s/^(\w+)\s+(\d\d)(\d\d)(\w+)\s+(\w+)\s+(\d\d)(\d\d)(\w+)\s*$/$1 $2 $3.$4 $5 $6 $7.$8\n/;
|
|
$input2 =~ s/(\.N)/.0N/;
|
|
$input2 =~ s/(\.S)/.0S/;
|
|
$input2 =~ s/(\.E)/.0E/;
|
|
$input2 =~ s/(\.W)/.0W/;
|
|
$input2 =~ s/\s(\d)(\.\d)/ 0$1$2/g;
|
|
print $input2;
|
|
&convert($input2, "DD MM SS");
|
|
|
|
}
|
|
|
|
close(FH);
|