[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