Anton Berezin <tobez@tobez.org>
Copenhagen, November 2013
<?xml version="1.0" encoding="UTF-8"?>
<svg width="1024" height="768"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:attrib="http://www.carto.net/attrib/">
...
</svg>
<line x1="10" y1="10" x2="290" y2="290" style="stroke:#ff0000;stroke-width:5"/>
<rect x="30" y="30" width="240" height="90" style="fill:#a5bfdd"/>
<circle fill="#652d86" stroke="black" cx="180" cy="30" r="10"/>
<path style="fill:#0000ff;stroke-width:5;stroke:#ff0000"
d="M10 10 40 290 70 70 290 40 z" />
<path d="M 20 150 Q 150 250 280 150"
fill="none" style="stroke:#800000;stroke-width:5"/>
use Geo::ShapeFile;
my $name = shift;
my $g = Geo::ShapeFile->new("ne_110m_admin_0_countries");
for my $i (1..$g->shapes()) {
my $shape = $g->get_shp_record($i);
my %db = $g->get_dbf_record($i);
for my $part (1 .. $shape->num_parts) {
my @points = $shape->get_segments($part);
my @xy = map {
[$_->[0]{X}, $_->[0]{Y}]
} @points;
}
}
p[0][0]{X}, p[0][1]{X}==p[1][0]{X}, p[1][1]{X}==p[2][0]{X},
p[2][1]{X}==p[3][0]{X},...,p[N][1]{X}==p[0][0]{X}
It is Sjælland, by the way... ☺
use Geo::ShapeFile;
my $name = shift;
my $g = Geo::ShapeFile->new("ne_10m_populated_places");
for my $i (1..$g->shapes()) {
my %db = $g->get_dbf_record($i);
for my $n (qw(NAMEPAR NAMEASCII NAME GN_ASCII)) {
if ($name eq $db{$n}) {
my @n = ($name);
push @n, $db{ADM1NAME} if $db{ADM1NAME};
push @n, $db{ADM0NAME} if $db{ADM0NAME};
printf "%.2f %.2f: %s\n", $db{LATITUDE}, $db{LONGITUDE}, join ", ", @n;
last;
}
}
}
$ ./coord Copenhagen
55.68 12.56: Copenhagen, Hovedstaden, Denmark
$
$ ./coord Ashburn
$
"Ashburn, Virginia, unincorporated area in Loudoun County"
39°02′37″N 077°29′15″W <-- there
$ ./coord 'St. Petersburg'
27.77 -82.68: St. Petersburg, Florida, United States of America
59.94 30.32: St. Petersburg, City of St. Petersburg, Russia
$
$ ./coord London
37.13 -84.08: London, Kentucky, United States of America
42.97 -81.25: London, Ontario, Canada
51.50 -0.12: London, Westminster, United Kingdom
$
Even with a better resolution, it is still ugly:
use Geo::Proj4;
$from = Geo::Proj4->new("+proj=latlong +datum=NAD83");
$to = Geo::Proj4->new("+proj=aea +lat_1=35 +lat_2=40 +lon_0=12");
$p = $from->transform($to, [$lon, $lat]); # lon is "x", lat is "y"
# draw at $p->[0], $p->[1]
$ proj -lP
aea : Albers Equal Area
Conic Sph&Ell
lat_1= lat_2=
aeqd : Azimuthal Equidistant
Azi, Sph&Ell
lat_0 guam
airy : Airy
Misc Sph, no inv.
no_cut lat_b=
...etc...
Currently, 133 projections.
Minimizes distortion of shape and linear scale between standard parallels. Better suited for East-West landmasses.
+proj=laea +lat_0=55.71 +lon_0=10.73
Compare again with (LAT,LON) abomination.
+proj=aea +lat_1=29.5 +lat_2=45.5 +lon_0=-98
plus Canada plus Mexico
This is what was actually drawn on the previous slide.
use Math::Polygon::Clip;
my @clipped = polygon_fill_clip1(
[0,0,$width,$height],
@svg_points,
$svg_points[0]);
if (@clipped < @svg_points) {
@svg_points = @clipped;
}
$ ls -l usa*svg
-rw-r--r-- 1 tobez staff 7037 Nov 23 01:15 usa.svg
-rw-r--r-- 1 tobez staff 21965 Nov 23 01:15 usa-neib.svg
-rw-r--r-- 1 tobez staff 21204 Nov 23 01:15 usa-noclip.svg
-rw-r--r-- 1 tobez staff 9848 Nov 23 01:15 usa-clip.svg
# $svg_width, $svg_left, $svg_right are given
# $from and $to are projections
# $min_px, $min_py, $max_px, $max_py
# $lon and $lat are inputs
$svg_scale = $svg_width/($max_px - $min_px);
$svg_height = ($max_py-$min_py}) * $svg_scale;
$p = $from->transform($to, [$lon, $lat]);
($px, $py) = @$p;
$svg_x = $svg_left + ($px - $min_px) * $svg_scale;
$svg_y = $svg_top + ($max_py - $dy) * $svg_scale;
<div id="view_europe" class="map_view">
<embed id="svg_europe" src="europe.svg" type="image/svg+xml"/>
</div>
var e = svg.getElementById("Copenhagen_Stockholm");
if (max_utilization > 60) {
$(e).attr("style", "stroke:#ff3366;stroke-width:5");
}
function svg_init(svg_id) {
var svg_embed = document.getElementById(svg_id);
var svg = svg_embed.getSVGDocument();
if (svg && svg.getElementById("svg_here")) {
setup_svg(svg);
} else {
svg_embed.addEventListener("load", function() {
var svg = svg_embed.getSVGDocument();
setup_svg(svg);
}, false);
}
}
<rect id="svg_here" width="1" height="1" style="display:none;"/>
Dallas <-> Phoenix
Dallas <-> Los Angeles
Los Angeles <-> Phoenix
Dallas <-> Phoenix adjust -10
Dallas <-> Los Angeles adjust 20
Los Angeles <-> Phoenix adjust 5
my $d = $adjustment_value;
my $cx = ($x1+$x2)/2;
my $cy = ($y1+$y2)/2;
my $ml = ($y2-$y1)/($x2-$x1); # slope
my $mp = -1/$ml; # slope of the perpendicular
# Perpendicular vector of length $d
my $dx = $d/sqrt($mp*$mp + 1);
my $dy = $mp*$dx;
Spline control point calculation.
my $z0 = ($y2-$y1)*($cx + $dx - $x1) - ($x2-$x1)*($cy + $dy - $y1);
if ($z0 > 0) { # "+" is to the left
if ($d > 0) {
$x = $cx - $dx;
$y = $cy - $dy;
} else {
$x = $cx + $dx;
$y = $cy + $dy;
}
} else { # "-" is to the left
if ($d > 0) {
$x = $cx + $dx;
$y = $cy + $dy;
} else {
$x = $cx - $dx;
$y = $cy - $dy;
}
}
<svg xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 10 10">
<style type="text/css">
line{ stroke: #f00; stroke-width: 1px }
line:hover{ stroke: #0f0 }
</style>
<line x1="0" y1="5" x2="100" y2="6"/>
</svg>
The above works everywhere but in Firefox.