Pierre Béland reminded the Canadian OSM group of the GeoBase WMS, which has all the NRN road names in it. Here’s my neighbourhood’s OpenStreetMap data with the road names overlaid.
we can has street names
quite a bit of work to do in Toronto
Looking at the OSM Inspector for Toronto, there are still a lot of nodes that need to be remapped (or OpenStreetMap users that need to be advised) when the big licence change comes.
(and yes, I blogged this just so I’d remember the link for OSM Inspector.)
Not really getting the Azimuthal Equidistant projection right
All I really wanted to do is make a map like this:
This is an Azimuthal Equidistant projection, with me at the centre (of course) and the rest of the world spread out in a fan by distance and bearing. It’s somewhat surprising to find that South Africa is almost directly east of Toronto, and New Zealand to the southwest.
If I had a directional antenna and a rotor, this map would show me where I would have to point the antenna to contact that part of the world. I can’t rotate my dipole (unless I commit some unauthorized local plate tectonics) so I’m stuck with where my antenna transmits and receives best.
The above map was made with AZ_PROJ, a PostScript program of some complexity for plotting world maps for radio use. The instructions for installing and running AZ_PROJ are complex and slightly dated. I got the above output running it through Ghostscript like this:
gs -sDEVICE=pdfwrite -sOutputFile=va3pid_world.pdf az_ini.ps -- az_proj.ps world.wdb
The format of the az_ini.ps file is complex, and I’m glad I’m an old PS hacker to be able to make head or tail of it.
For all its user-hostility, AZ_PROJ is powerful. Here’s a version of the map I wanted all along:
This shows my furthest QSO in each of the 16 compass directions. (You might note that North is empty: my furthest contact in that direction is some 13km away, whether by lack of folks in that sector or dodginess of my antenna.) Contrast that with my Mercator QSO map, and you’ll see that Azimuthal Equidistant is a much better projection for this application.
To show how radically different the world looks to different people, here’s the world according to my mate Rob in Hamilton, NZ:
I’d been trying to use OGR to transform arbitrary shapefiles into this projection. For maps entirely contained within the same hemisphere (so having extent less than ±90° in any cardinal direction), this works:
ogr2ogr -t_srs "+proj=aeqd +lat_0=43.7308 +lon_0=-79.2647" out.shp in.shp
The lat_0 and lon_0 parameters are just where you want the centre of the map to be. Things get a bit odd if you try to plot the whole world:
The antipodes get plotted underneath, and everything looks messed up. I may have to take my question to GIS – Stack Exchange to see if I can find an answer. Still, for all its wrongness, you can make something pretty, like my whole world Maidenhead locator grid projected this way turns into a rose:

binning by angle
I was trying to sort a series of polar coordinates by compass direction: everything in the N sector, then NNE, NE, ENE, E, … This is trickier than it looks, since the North sector includes angles between 348.75° and 11.25°.
It’s easier to think of the problem instead of being one of N bins centred on 0°, but rather one of 2N bins starting at 0°. Then, all one needs to do is shift everything round by one of these half bins (so +1, modulo 2N), then divide the number of bins back to the number we want. Done!
Here’s some code to do it. It may look like C-like pseudocode, but it’s real live AWK:
function bin(angle,nbins){
return int(((int(angle/(360.0/(nbins*2)))+1)%(nbins*2))/2);
}
You probably want the angles to be between 0..360°. But you knew that.
APRS is go!
Automatic Packet Reporting System — APRS — is rather clever. It’s a way of reporting position, status or messages via the amateur radio 2m band. Data is relayed via digipeaters, and routed to/from the internet APRS-IS system to any user worldwide.
It’s a little fiddly to set up, even with a very polished (read: $$) handheld radio like the Kenwood TH-D72A. I’m a bit disappointed that the purported SiRFstar III GPS in this radio takes forever to get a lock, but it’s a nice radio despite this.
The screenshot above shows aprs.fi‘s tracking of my handheld (VA3PID-7) last night as I walked to Toronto Mappy Hour.
Drawing Eggs
When designing wind farms, you need to keep the turbines a certain distance apart from one another. If you don’t, the wakes from the turbines reduce efficiency, and the turbulence can reduce the warranted life of the machine. Typically, a manufacturer might specify a minimum downwind separation of 5 diameters, and a crosswind separation of 3 diameters. It’s an easy check with a buffer overlap, but these buffers are elliptical, which not all GIS packages can draw.
Take, for example, the following three points designated as (completely made-up) wind turbine locations:
name XCOORD YCOORD 1 557186.675000 4757125.590000 2 557447.931000 4756968.690000 3 557664.999000 4756817.810000
These look quite far apart, even if you were using large, 100+m diameter wind turbines:
But if we have a wind direction of 210°, downwind/crosswind separation of 5D & 3D respectively, and a 101m diameter rotor, it’s not so good:
Turbines 2 & 3 are too close together; the ellipses shouldn’t touch.
As awk is the only scripting language I have on my work computer, I wrote the script that generates the buffer shapefile in awk. The script calls Frank’s Shapefile C Library utilities to actually make the shapefile. Here’s the code:
#!/bin/awk -f
# draw an ellipse based on turbine location to generate
# for WTG separation buffer
# scruss - 2011-09-27
# assumes that stdin has three columns:
# 1 - label
# 2 - x coordinate
# 3 - y coordinate
# variables:
# diameter = rotor diameter
# cross = crosswind separation, diameters
# down = downwind separation, diameters
# wind = prevailing wind direction
# base = base for shape file name
BEGIN {
OFMT="%.1f";
CONVFMT="%.1f";
OFS=" ";
if (diameter < 0) {
print "diameter must be set";
exit;
}
if (cross < 0) {
print "cross must be set";
exit;
}
if (down < 0) {
print "down must be set";
exit;
}
if (down < cross) {
print "down must be greater than cross";
exit;
}
if (wind < 0) {
print "wind must be set";
exit;
}
if (base ~ /^$/) {
print "base must be a string";
exit;
}
pi = 3.141592654; # I know, I know ...
# calc cartesian angle from wind bearing, in radians
beta = ((450 - wind)%360) * pi/180;
# output shapelib tools init commands
print "dbfcreate " base " -s name 40";
print "shpcreate " base " polygon";
}
# for every line
{
name=$1;
x=$2;
y=$3;
major = diameter * down/2;
minor = diameter * cross/2;
first="";
points="";
maxn=36;
for (i=0; i<maxn; i++) {
alpha = (i * (360/maxn)) * pi/180;
x1 = x + major * cos(alpha) * cos(beta) - minor * sin(alpha) * sin(beta);
y1 = y + major * cos(alpha) * sin(beta) + minor * sin(alpha) * cos(beta);
if (i == 0) { # store the first point
first= x1 " " y1;
}
points = points " " x1 " " y1;
}
points = points " " first;
print "dbfadd " base ".dbf " name;
print "shpadd " base, points;
}
awk is charmingly odd in that you can specify variable on the command line. Here’s how I called it, with the above coordinates as input:
awk -v diameter=101 -v cross=3 -v down=5 -v wind=210 -v base="fakewtg-ellipse" -f separation.awk
Pipe the output through a shell, and there are your ellipses.
#mapfail
… or “トロント動物園“, as we locals purportedly call it. The This place has unverified edits legend is a bit of a giveaway. Looks like there’s been some messing about with Google Map Maker, which isn’t always the best tool for the job.
Ham Radio log to interactive OpenStreetMap
You might notice that there’s now a Ham Radio QSO Map lurking on the front page. Thanks to the WordPress OpenStreetMap plugin (which I’ve slightly abused before). Here’s a small piece of Perl which will take your ADIF log and convert it to a WP-OSM marker file.
Note that this program assumes you’ve downloaded your log from QRZ.com, as it requires the locator field for both inbound and outbound stations.
#!/usr/bin/perl -w
# adif2osm - convert ADIF log to OSM map file
# scruss.com / VA3PID - 2011/06/19
use strict;
use constant MARKERDIR =>
'http://glaikit.org/wp-content/plugins/osm/icons/';
use constant QRZURL => 'http://qrz.com/db/';
sub maidenhead2latlong;
my ( $temp, @results ) = '';
### Fast forward past header
while (<>) {
last if m/<eoh>\s+$/;
}
### While there are records remaining...
while (<>) {
$temp .= $_;
### Process if end of record tag reached
if (m/<eor>\s+$/i) {
my %hash;
$temp =~ s/\n//g;
$temp =~ s/<eoh>.*//i;
$temp =~ s/<eor>.*//i;
my @arr = split( '<', $temp );
foreach (@arr) {
next if (/^$/);
my ( $key, $val ) = split( '>', $_ );
$key =~ s/:.*$//;
$hash{ lc($key) } = $val unless ( $key eq '' );
}
push @results, \%hash;
$temp = '';
}
}
# generate OSM plugin file
my @data = ();
my ( $mygrid, $station_callsign ) = '';
# output header
print
join( "\t", qw/lat lon title description icon iconSize iconOffset/ ),
"\n";
foreach (@results) {
next unless ( exists( $_->{gridsquare} ) && exists( $_->{call} ) );
$mygrid = $_->{my_gridsquare}
if ( exists( $_->{my_gridsquare} ) );
$station_callsign = $_->{station_callsign}
if ( exists( $_->{station_callsign} ) );
push @data, $_->{freq} . ' MHz' if ( exists( $_->{freq} ) );
$data[$#data] .= ' (' . $_->{band} . ')' if ( exists( $_->{band} ) );
push @data, $_->{mode} if ( exists( $_->{mode} ) );
push @data, $_->{qso_date} . ' ' . $_->{time_on} . 'Z'
if ( exists( $_->{qso_date} ) && exists( $_->{time_on} ) );
my ( $lat, $long ) = maidenhead2latlong( $_->{gridsquare} );
print join( "\t",
$lat,
$long,
'<a href="' . QRZURL . $_->{call} . '">' . $_->{call} . '</a>',
join( ' - ', @data ),
MARKERDIR . 'wpttemp-green.png',
'0,-24' ),
"\n";
@data = ();
}
# show home station last, so it's on top
my ( $lat, $long ) = maidenhead2latlong($mygrid);
print join( "\t",
$lat,
$long,
'<a href="'
. QRZURL
. $station_callsign . '">'
. $station_callsign . '</a>',
'Home Station',
MARKERDIR . 'wpttemp-red.png',
'0,-24' ),
"\n";
exit;
sub maidenhead2latlong {
# convert a Maidenhead Grid location (eg FN03ir)
# to decimal degrees
# this code could be cleaner/shorter/clearer
my @locator =
split( //, uc(shift) ); # convert arg to upper case array
my $lat = 0;
my $long = 0;
my $latdiv = 0;
my $longdiv = 0;
my @divisors = ( 72000, 36000, 7200, 3600, 300, 150 )
; # long,lat field size in seconds
my $max = ( $#locator > $#divisors ) ? $#divisors : $#locator;
for ( my $i = 0 ; $i <= $max ; $i++ ) {
if ( int( $i / 2 ) % 2 ) { # numeric
if ( $i % 2 ) { # lat
$latdiv = $divisors[$i]; # save for later
$lat += $locator[$i] * $latdiv;
}
else { # long
$longdiv = $divisors[$i];
$long += $locator[$i] * $longdiv;
}
}
else { # alpha
my $val = ord( $locator[$i] ) - ord('A');
if ( $i % 2 ) { # lat
$latdiv = $divisors[$i]; # save for later
$lat += $val * $latdiv;
}
else { # long
$longdiv = $divisors[$i];
$long += $val * $longdiv;
}
}
}
$lat += ( $latdiv / 2 ); # location of centre of square
$long += ( $longdiv / 2 );
return ( ( $lat / 3600 ) - 90, ( $long / 3600 ) - 180 );
}
You’ll need to update MARKERDIR to reflect your own WP-OSM installation. Mine might move, so if you don’t change it, and you don’t get markers, please don’t blame me.
The basic code to include a map is like this:
You’ll need to change the marker_file URL, too.
Note that, while this script generates links into the QRZ callsign database, it doesn’t hit that site unless you click a link.
Bixi comes to Toronto!
BIXI Toronto is (nearly) here!
Here are the proposed station locations: Bixi_Toronto_shp.zip (Shapefile) or Bixi_Toronto-kml_csv.zip (KML and CSV).
More radio amateur grid squares
After yesterday’s post, I went a bit nuts with working out the whole amateur radio grid locator thing (not that I’m currently likely to use it, though). I’d hoped to provide a shapefile of the entire world, but that would be too big for the format’s 2GB file size limit.
What I can give you, though, is:
- A Perl program that will generate a shapefile of an entire Maidenhead grid field, down to the subsquare level: make_grid.pl. You’ll need Geo::Shapelib to make this work. 324 (= 182) of these files would cover the whole world, and at 8MB or so a pop, things get unwieldy quickly.
- A Google Earth KML file covering the whole world in 20° by 10° grid fields: Maidenhead_Locator_World_Grid. (If you’re feeling nerdy, here it is in Shapefile format: Maidenhead_Locator_World_Grid-shp).
If anyone would like their grid square in Google Earth format, let me know.
