Friday 30 March 2018

Programming Maps with Perl

So far in my map making endeavors I have done quite a bit with Google Maps, made some introductory strides into Google Fusion Tables, and done a bit of dabbling with QGIS.  Let's be clear I am only just making some baby steps into map making, and having a really great time doing it!  All of these tools will require more and investigation on my part.  Another tool that probably not many people think about is programming directly with a language like Perl or Python.  I'm an old guy so I'll use the former.

A neat thing about maps is that a couple of the most common map formats are in XML.  This includes both GPX and KML.  And languages like perl and python have libraries for parsing and using XML files.  I've never done any XML programming in the past so this was all new to me - but a bit of googling and I found enough information to get me going.

One of the things I like to do with the google maps I make is for points like put-ins, campsites, and portage points, I like to include the GPS coordinates in the description of the point.  This is because for some reason google shows the coordinates to the person making the map, but once shared out to others it does not display them to 3rd parties.  The easiest way I found to make this information available in my maps is to include the coordinates in the description.  Until now this involved me manually editing every single point within the google map editor, and copying the coordinates then pasting them into the description.  You develop a certain rhythm for it and with that you can burn through a few hundred points in 10 minutes or so, but that is really prone to human error, and does not scale well.  What happens when a few hundred becomes a few thousand?

That's when you need to learn to parse and process the data files with something like perl or python.

In my initial google searches I came across a short tutorial using the perl library called XML::Simple.  It is true that after doing more searching I found another article which gave a whole bunch of good reasons why you would not want to use that particular library, but it did work well for my purpose and was easy to use.  I've discovered that the more popular and more useful library for Perl is XML::LibXML, and I've started playing around with it as well.

To install a perl module on Linux use the cpan command like this :

sudo cpan XML::Simple

It will do a bunch of things and the voila you'll have your library.  If you've never used cpan before it will ask you a bunch of questions, one of the first of which will be whether you want it to make as many decisions as possible.  I strongly recommend that unless you really know what you are doing.
Here is a quick little XML::Simple program that allowed me to take a file contaning the coordinates for all the campsites in my Magnetawan map, and quickly re-write it to include the GPS coordinates in the description. I'm sure more knowledgeable programmers may look at this an just about faint, but it works.


#!/usr/bin/perl

use strict;
use warnings;
use XML::Simple;
use Data::Dumper;

my $myFile = XMLin('MagnetawanCampsitesApprox001.kml');

foreach my $folder (@{$myFile->{Document}->{Folder}->{Placemark}})  {
 my ( $mylong, $mylat )  = split(/,/, $folder->{Point}->{coordinates} );
 my $mylongs = sprintf( "%2.7f", $mylong );
 my $mylats = sprintf( "%2.7f", $mylat );
 $folder->{Point}->{description} = join(',', $mylats, $mylongs );

 print "<Placemark>" . "\n";
 print "<name/>" . "\n";
 print "<description>" . $folder->{Point}->{description} . "</description>" . "\n";
 print "<Point>" . "\n";
 print "<coordinates>" . "\n";
 print $folder->{Point}->{coordinates} . ",0\n";
 print "</coordinates>" . "\n";
 print "</Point>" . "\n";
 print "</Placemark>" . "\n";
}

Here is what the original file looked like :


<Document id="root_doc">
<Schema name="MagnetawanCampsitesApprox001" id="MagnetawanCampsitesApprox001">
 <SimpleField name="Id" type="int"></SimpleField>
</Schema>
<Folder><name>MagnetawanCampsitesApprox001</name>
  <Placemark>
      <Point><coordinates>-80.161677887514188,45.973490779652913</coordinates></Point>
  </Placemark>
  <Placemark>
      <Point><coordinates>-80.219481417320253,45.891271829550952</coordinates></Point>
  </Placemark>
  <Placemark>
      <Point><coordinates>-80.236157754462411,45.886300236317801</coordinates></Point>
  </Placemark>
</Folder>
</Document>
For the programmers amongst you there is nothing earthshattering here of course, and maybe there are other ways to do this with the likes of QGIS. But it works for me.
Another thing I found it useful for is stripping out the ExtendedData fields from the data I've obtained. The way I make my google maps involves a lot of importing, manual changes within the google map editor, then exporting for manual processing of the raw data files like above, and re-importing. I've found that google does not do a very good job of preserving the integrity of the ExtendedData fields when doing this, and it seems to repeatedly rewrite those fields into the description field, even though it does preserve ExtendedData as well. Luckily for me there is nothing within the ExtendedData that is really all that useful to me. So far, at least. So removing it is no big deal.

No comments:

Post a Comment