[aprssig] Nuvi 350 full - a Perl solution
Arne Stahre
sm6vyf at gatugarden.com
Sat Oct 24 09:41:20 EDT 2009
Here's a Perl solution to trim the nuvi/Garmin/gpx/current.gpx file.
This program is just a quick hack; sparingly tested (I haven't tried the
output an a Nüvi - yet).
The first version using XML::LibXML in Linux couldn't be run directly
in ActivePerl in Vista. So I tried XML::Simple too - and this works for
both. The LibXML-version is included, but commented out.
Change MYDATA for your needs and run the program by typing, in a
terminal/DOS-prompt, something like
perl gpxcut.pl in.gpx
or, to save the output,
perl gpxcut.pl in.gpx > out.gpx
You can verify the output's XML by, e.g., open it in Firefox.
For Windows I'm using ActivePerl, which you can get here:
http://www.activestate.com/activeperl/ .
Enjoy!
SM6VYF/Arne
-----------------------------------
#!/usr/bin/perl -w
# 24.X.09 SM6VYF/Arne
#use XML::LibXML;
use XML::Simple;
use strict;
# lat & lon for ref. point (dec. deg. N/E positive) and distance in km.
my @MYDATA = (57.726663, 11.774787, 52);
BEGIN { $::pi = 4 * atan2(1,1); }
sub degrees_to_radians {
return $_[0] * $::pi / 180.0;
}
sub radians_to_degrees {
return $_[0] * 180.0 / $::pi;
}
sub acos {
my($x) = @_;
die "bad acos argument ($x)\n" if (abs($x) > 1.0);
return atan2(sqrt(1 - $x * $x), $x);
}
sub great_circle {
my ($lat1, $long1, $lat2, $long2) = @_;
# Approx. radius of Earth in km.
# True radius varies from 6357km (polar) to 6378km (equatorial).
my $earth_radius = 6367.000;
$lat1 = degrees_to_radians($lat1);
$long1 = degrees_to_radians($long1);
$lat2 = degrees_to_radians($lat2);
$long2 = degrees_to_radians($long2);
my $dlon = $long2 - $long1;
my $dlat = $lat2 - $lat1;
my $a = (sin($dlat / 2)) ** 2
+ cos($lat1) * cos($lat2) * (sin($dlon / 2)) ** 2;
my $d = 2 * atan2(sqrt($a), sqrt(1 - $a));
my $dist = $earth_radius * $d;
return (0, 0) if ($dist == 0); # Home!
my $heading = acos((sin($lat2) - sin($lat1) * cos($d))
/ (sin($d) * cos($lat1)));
if (sin($long2 - $long1) < 0) {
$heading = 2 * $::pi - $heading;
}
$heading = radians_to_degrees($heading);
return ($dist, $heading);
}
sub inside {
my ($lat, $lon, $mylat, $mylon, $distance) = @_;
my ($dist, $heading) = great_circle($lat, $lon, $mylat, $mylon);
return $dist <= $distance;
}
# sub select_wpts {
# my ($filename, $mylat, $mylon, $distance) = @_;
# if (my $parser = XML::LibXML->new()) {
# my $doc = $parser->parse_file($filename);
# my @metadatas = $doc->getElementsByTagName('metadata');
# foreach my $metadata (@metadatas) {
# print " " . $metadata->toString . "\n ";
# }
# my @wpts = $doc->getElementsByTagName('wpt');
# foreach my $wpt (@wpts) {
# if (inside($wpt->getAttribute('lat'), $wpt->getAttribute('lon'),
# $mylat, $mylon, $distance)) {
# my $name = $wpt->getElementsByTagName('name');
# print $wpt->toString() . "\n ";
# }
# }
# }
# }
sub select_wpts {
my ($filename, $mylat, $mylon, $distance) = @_;
my $doc = XMLin($filename);
foreach my $name (keys(%{$doc->{wpt}})) {
if (inside(${$doc->{wpt}}{$name}{lat}, ${$doc->{wpt}}{$name}{lon},
$mylat, $mylon, $distance)) {
my $lat = ${$doc->{wpt}}{$name}{lat};
my $lon = ${$doc->{wpt}}{$name}{lon};
my $cmt = ${$doc->{wpt}}{$name}{cmt};
my $sym = ${$doc->{wpt}}{$name}{sym};
print <<_EOT_;
<wpt lat="$lat" lon="$lon">
<name>$name</name>
<cmt>$cmt</cmt>
<sym>$sym</sym>
</wpt>
_EOT_
}
}
}
print <<_EOT_;
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<gpx
xmlns="http://www.topografix.com/GPX/1/1"
xmlns:gpxx="http://www.garmin.com/xmlschemas/GpxExtensions/v3"
creator="nüvi 350"
version="1.1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.topografix.com/GPX/1/1
http://www.topografix.com/GPX/1/1/gpx.xsd
http://www.garmin.com/xmlschemas/GpxExtensions/v3
http://www.garmin.com/xmlschemas/GpxExtensions/v3/GpxExtensionsv3.xsd">
_EOT_
select_wpts($ARGV[0], @MYDATA);
print <<_EOT_;
</gpx>
_EOT_
More information about the aprssig
mailing list