Skip to content

Commit 29dec83

Browse files
committed
bbox_to_zoom: convert bounding box back to (lat,lon,zoom) for map link.
1 parent 1726f48 commit 29dec83

File tree

1 file changed

+34
-7
lines changed

1 file changed

+34
-7
lines changed

OSM.pm

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,9 @@ sub get_area_centre {
7474
$centre_lat + ($lat_degrees_high / 2);
7575
}
7676

77-
sub get_area_zoom {
78-
my ($centre_lat, $centre_lon, $zoom, $screen_width, $screen_height) = @_;
79-
$screen_width //= 1000;
80-
$screen_height //= 1000;
81-
82-
my %metres_per_pixel_at_equator = (
77+
use constant DEFAULT_SCREEN_WIDTH => 1000;
78+
use constant DEFAULT_SCREEN_HEIGHT => 1000;
79+
my %metres_per_pixel_at_equator = (
8380
18 => 0.597164,
8481
17 => 1.194329,
8582
16 => 2.388657,
@@ -97,7 +94,12 @@ sub get_area_zoom {
9794
4 => 9783.939621,
9895
3 => 19567.879241,
9996
2 => 39135.758482,
100-
);
97+
);
98+
99+
sub get_area_zoom {
100+
my ($centre_lat, $centre_lon, $zoom, $screen_width, $screen_height) = @_;
101+
$screen_width //= DEFAULT_SCREEN_WIDTH;
102+
$screen_height //= DEFAULT_SCREEN_HEIGHT;
101103
die "bad zoom $zoom" if not exists $metres_per_pixel_at_equator{$zoom};
102104
my $cosine = cos(deg2rad($centre_lat));
103105
my $metres_per_pixel
@@ -107,6 +109,31 @@ sub get_area_zoom {
107109
return get_area_centre $centre_lat, $centre_lon, $metres_wide, $metres_high;
108110
}
109111

112+
sub bbox_to_zoom {
113+
my ($left, $bottom, $right, $top, $screen_width, $screen_height) = @_;
114+
$screen_width //= DEFAULT_SCREEN_WIDTH;
115+
$screen_height //= DEFAULT_SCREEN_HEIGHT;
116+
117+
# Find the width and height of the area in metres.
118+
my $centre_lat = ($bottom + $top) / 2;
119+
my $centre_lon = ($left + $right) / 2;
120+
my $width = ($right - $left) * one_degree_lon($centre_lat, $centre_lon);
121+
my $height = ($top - $bottom) * one_degree_lat($centre_lat, $centre_lon);
122+
123+
# Pick the highest zoom level that covers the whole area.
124+
my $cosine = cos(deg2rad($centre_lat));
125+
foreach my $zoom (reverse sort { $a <=> $b }
126+
keys %metres_per_pixel_at_equator) {
127+
my $m = $metres_per_pixel_at_equator{$zoom};
128+
my $metres_per_pixel = $m / $cosine;
129+
if ($screen_width * $metres_per_pixel >= $width
130+
and $screen_height * $metres_per_pixel >= $height) {
131+
return ($centre_lat, $centre_lon, $zoom);
132+
}
133+
}
134+
die 'no zoom area big enough';
135+
}
136+
110137
# Simplistic interface to parse the XML data and return the nodes.
111138
# Each one is returned as a hashref with id, lat, lon, and tags.
112139
# If a given tag appears twice then the values are concatenated with ;.

0 commit comments

Comments
 (0)