#! /usr/bin/perl -T use strict; use CGI qw/param/; use constant PI => 4 * atan2(1, 1); sub degrees_to_radians { return $_[0] * PI / 180; } sub radians_to_degrees { return $_[0] * 180 / PI; } sub safe_whole_number { ( defined $_[0] && $_[0] =~ /(\d+)/ && substr $1, 0, 32 ) || 0; } # .5 ln( (1 + sin t) / (1 - sin t) ) sub mercator { my $s = sin(degrees_to_radians($_[0])); return radians_to_degrees(.5 * log((1 + $s) / (1 - $s))); } # arcsin((e^2x - 1)/(e^2x + 1)) sub inverse_mercator { my $e = exp(2 * degrees_to_radians($_[0])); $e = ($e - 1)/($e + 1); return radians_to_degrees(atan2($e, sqrt(1 - $e * $e))); } my $x = safe_whole_number param('x'); my $y = safe_whole_number param('y'); my $zoom = safe_whole_number param('zoom'); my $d = 2 ** $zoom; my $lon_extent = 360/$d; my $merclat_extent = 360/$d; # (lat1, lon0) is upper left of tile my $l = 180 - $y * $merclat_extent; my $lat1 = inverse_mercator $l; my $lon0 = $x * $lon_extent - 180; my $lat0 = inverse_mercator $l - $merclat_extent; my $lon1 = $lon0 + $lon_extent; # tiles are 256 x 256 # draw a rectangle indented one pixel on each side # mark the edges with the latitude and longitude use GD; my $im = new GD::Image(256, 256); $im->colorAllocateAlpha(255, 255, 255, 127); # transparent background my $fg = $im->colorAllocateAlpha(0, 0, 0, 0); $im->string(gdSmallFont, 10, 128, $lon0, $fg); $im->string(gdSmallFont, 190, 128, $lon1, $fg); $im->string(gdSmallFont, 100, 10, $lat1, $fg); $im->string(gdSmallFont, 100, 220, $lat0, $fg); $im->string(gdSmallFont, 30, 60, 'x=' . $x . ' y=' . $y . ' zoom=' . $zoom, 1); my $a0 = 1; my $a1 = 254; $im->line($a0, $a0, $a0, $a1, 1); $im->line($a0, $a1, $a1, $a1, 1); $im->line($a1, $a1, $a1, $a0, 1); $im->line($a1, $a0, $a0, $a0, 1); print "Content-Type: image/png\n\n", $im->png;