@@ -74,12 +74,9 @@ sub get_area_centre {
74
74
$centre_lat + ($lat_degrees_high / 2);
75
75
}
76
76
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 = (
83
80
18 => 0.597164,
84
81
17 => 1.194329,
85
82
16 => 2.388657,
@@ -97,7 +94,12 @@ sub get_area_zoom {
97
94
4 => 9783.939621,
98
95
3 => 19567.879241,
99
96
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;
101
103
die " bad zoom $zoom " if not exists $metres_per_pixel_at_equator {$zoom };
102
104
my $cosine = cos (deg2rad($centre_lat ));
103
105
my $metres_per_pixel
@@ -107,6 +109,31 @@ sub get_area_zoom {
107
109
return get_area_centre $centre_lat , $centre_lon , $metres_wide , $metres_high ;
108
110
}
109
111
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
+
110
137
# Simplistic interface to parse the XML data and return the nodes.
111
138
# Each one is returned as a hashref with id, lat, lon, and tags.
112
139
# If a given tag appears twice then the values are concatenated with ;.
0 commit comments