now with cgi-mode and lots of other improvements.
[osmrrze.git] / scripts / osmbuildings-json-generator.pl
CommitLineData
d58b8e00
MPM
1#!/usr/bin/perl -w
2
3# Our database
4$dbname = 'osm';
5
6# Default verbosity level? Can be increased with -v, decreased with -q
7$verblev = 0;
8
9# The area which we cover
10$x1 = 11.01;
11$y1 = 49.56;
12$x2 = 11.04;
13$y2 = 49.58;
14
15# There should be no need to touch anything below this line.
16# ---------------------------------------------------------------------------
17
18use DBI;
19use POSIX qw(strftime mktime);
20use Pg::hstore;
21
22# Par. 0: Level on which this gets printed
23# Par. 1: Text
24sub printlev($$) {
25 unless (defined($printlev_atbeginofline)) { $printlev_atbeginofline = 1; }
26 if ($verblev >= $_[0]) {
27 if ($printlev_atbeginofline) {
28 print(strftime("[%Y%m%d-%H%M%S] ", localtime(time())));
29 }
30 print($_[1]);
31 if ($_[1] =~ m/\n$/) {
32 $printlev_atbeginofline = 1;
33 } else {
34 $printlev_atbeginofline = 0;
35 }
36 }
37}
38
39# Par. 0: default value to return if nothing is defined
40# Par. 1: the hashref containing our variables.
41# Par. 2: variables to query. The LAST one that exists will be returned.
42sub fetchlastofhr($$@) {
43 my $res; my $hr; my @vns;
44 ($res, $hr, @vns) = @_;
45 for (my $i = 0; $i < @vns; $i++) {
46 my $vn = $vns[$i];
47 if (defined($hr->{$vn})) {
48 $res = $hr->{$vn};
49 }
50 }
51 return $res;
52}
53
9de6d037
MPM
54# Helper functions for the CGI variant. Taken from the openstreetmap-Wiki.
55use Math::Trig;
56sub Project {
57 my ($X, $Y, $Zoom) = @_;
58 my $Unit = 1 / (2 ** $Zoom);
59 my $relY1 = $Y * $Unit;
60 my $relY2 = $relY1 + $Unit;
61
62 # note: $LimitY = ProjectF(degrees(atan(sinh(pi)))) = log(sinh(pi)+cosh(pi)) = pi
63 # note: degrees(atan(sinh(pi))) = 85.051128..
64 #my $LimitY = ProjectF(85.0511);
65
66 # so stay simple and more accurate
67 my $LimitY = pi;
68 my $RangeY = 2 * $LimitY;
69 $relY1 = $LimitY - $RangeY * $relY1;
70 $relY2 = $LimitY - $RangeY * $relY2;
71 my $Lat1 = ProjectMercToLat($relY1);
72 my $Lat2 = ProjectMercToLat($relY2);
73 $Unit = 360 / (2 ** $Zoom);
74 my $Long1 = -180 + $X * $Unit;
75 return ($Lat2, $Long1, $Lat1, $Long1 + $Unit); # S,W,N,E
76}
77sub ProjectMercToLat($){
78 my $MercY = shift;
79 return rad2deg(atan(sinh($MercY)));
80}
81sub ProjectF
82{
83 my $Lat = shift;
84 $Lat = deg2rad($Lat);
85 my $Y = log(tan($Lat) + sec($Lat));
86 return $Y;
87}
88
d58b8e00
MPM
89# ----------------------------------------------------------------------------
90# main()
91# ----------------------------------------------------------------------------
92
9de6d037
MPM
93$iscgi = 0;
94
d58b8e00
MPM
95# Parse commandline
96foreach $a (@ARGV) {
97 if ($a eq '-q') {
98 $verblev--;
99 } elsif ($a eq '-v') {
100 $verblev++;
9de6d037
MPM
101 } elsif ($a eq '--cgi') {
102 $iscgi = 1;
d58b8e00
MPM
103 } else {
104 print("Unknown parameter: $a\n");
105 print("Syntax: $0 [-q] [-v]\n");
106 print(" -q decreases verbosity, -v increases verbosity.\n");
107 exit(1);
108 }
109}
110
9de6d037
MPM
111if (defined($ENV{'REQUEST_URI'})) {
112 $iscgi = 1;
113 print("Content-type: application/json\n\n");
114 unless ($ENV{'REQUEST_URI'} =~ m!(\d+)/(\d+)/(\d+)\.json$!) {
115 print("{\n\"_comment\": \"Sorry, query parameters not understood.\"\n}\n");
116 exit(0);
117 }
118 my $cgiz = int($1); my $cgix = int($2); my $cgiy = int($3);
119 #print("DEBUG: z=$cgiz x=$cgix y=$cgiy\n");
120 if ($cgiz < 15) {
121 print("{\n\"_comment\": \"No data will be returned at this zoom level.\"\n}\n");
122 }
123 ($y1, $x1, $y2, $x2) = Project($cgix, $cgiy, $cgiz);
124 #print("DEBUG: mapped to ($x1 $y1) ($x2 $y2)\n");
125}
126
d58b8e00
MPM
127unless ($dbh = DBI->connect("dbi:Pg:dbname=$dbname","","")) {
128 print(STDERR "Failed to open database. Please try again later.\n"); exit(1);
129}
130
131$tx1 = $dbh->selectrow_array("select ST_X(ST_transform(ST_GeomFromText('POINT($x1 $y1)', 4326), 900913))");
132$ty1 = $dbh->selectrow_array("select ST_Y(ST_transform(ST_GeomFromText('POINT($x1 $y1)', 4326), 900913))");
133$tx2 = $dbh->selectrow_array("select ST_X(ST_transform(ST_GeomFromText('POINT($x2 $y2)', 4326), 900913))");
134$ty2 = $dbh->selectrow_array("select ST_Y(ST_transform(ST_GeomFromText('POINT($x2 $y2)', 4326), 900913))");
135my $cntr = 0;
9de6d037
MPM
136if ($iscgi == 0) {
137 print("// Note: this file has been autogenerated by $0\n");
138 print("var FAUGeoJSON = {\n");
139} else {
140 print("{\n");
141}
d58b8e00
MPM
142print(" \"type\": \"FeatureCollection\",\n");
143print(" \"features\": [\n");
9de6d037
MPM
144foreach $xtable ('planet_osm_polygon1', 'planet_osm_polygon2', 'planet_osm_line') { # 'planet_osm_polygon', 'planet_osm_line'
145 my $querypart1 = " ((tags->'building:part') is not null)";
146 my $table = 'planet_osm_polygon';
147 if ($xtable eq 'planet_osm_polygon1') {
148 $querypart1 = " (building is not null)";
149 } elsif ($xtable eq 'planet_osm_line') {
150 $table = $xtable;
151 }
152 # Note: && in this case is the postgis operator for 'bounding box overlaps'.
d58b8e00 153 my $sth = $dbh->prepare("select osm_id, way, building, 'tower:type', name, tags"
9de6d037
MPM
154 . " from $table where $querypart1"
155 . " and (way && ST_MakeEnvelope($tx1, $ty1, $tx2, $ty2))");
d58b8e00 156 unless ($sth->execute()) {
9de6d037 157 print(STDERR "Sorry, database query blew up.!\n");
d58b8e00
MPM
158 exit(1);
159 }
160 my $sth2 = $dbh->prepare("select ST_X(points) as x, ST_Y(points) as y"
161 . " from (select ST_astext((ST_dumppoints(ST_transform(?, 4326))).geom) as points) as points");
162 while ($row = $sth->fetchrow_hashref()) {
9de6d037
MPM
163 if ($xtable eq 'planet_osm_polygon1') {
164 my $hassubparts = $dbh->selectrow_array("select count(*)"
165 . " from planet_osm_line"
166 . " where ((tags->'building:part') is not null)"
167 . " and (ST_Covers(" . $dbh->quote($row->{'way'}) . ", way) = true)");
168 # The subparts usually cover the whole building, so we do NOT draw the
169 # whole building but only the subparts.
170 if ($hassubparts > 0) { next; }
171 }
d58b8e00
MPM
172 my $hstoredec;
173 if (defined($row->{'tags'})) {
174 $hstoredec = Pg::hstore::decode($row->{'tags'});
175 }
9de6d037
MPM
176 my $levels = fetchlastofhr(1, $hstoredec, 'levels', 'building:levels');
177 my $height = fetchlastofhr($height, $hstoredec, 'height', 'building:height');
178 unless ($height =~ m/^[0-9.]+$/) { undef($height); }
179 my $minlevel = fetchlastofhr(0, $hstoredec,
180 'min_levels', 'building:min_levels', 'min_level', 'building:min_level');
181 my $minheight = fetchlastofhr($minheight, $hstoredec, 'min_height', 'building:min_height');
182 unless ($minheight =~ m/^[0-9.]+$/) { undef($minheight); }
d58b8e00
MPM
183 my $wallcolor = fetchlastofhr(undef, $hstoredec, 'building:color', 'building:colour');
184 my $roofcolor = fetchlastofhr(undef, $hstoredec,
185 'roof:color', 'roof:colour', 'building:roof:color', 'building:roof:colour');
186 my $roofshape = fetchlastofhr(undef, $hstoredec, 'roof:shape', 'building:roof:shape');
187 my $roofheight = fetchlastofhr(undef, $hstoredec, 'roof:height', 'building:roof:height');
9de6d037
MPM
188 if ($cntr != 0) {
189 print(",\n");
190 }
d58b8e00
MPM
191 $cntr++;
192 print(" {\n");
193 print(" \"type\": \"Feature\",\n");
9de6d037
MPM
194 if (defined($row->{'osm_id'})) {
195 print(" \"id\": " . $row->{'osm_id'} . ",\n");
196 } else {
197 print(" \"id\": $cntr,\n");
198 }
199 if (defined($row->{'name'})) {
200 $row->{'name'} =~ s/"//g;
201 print(" \"name\": \"" . $row->{'name'} . "\",\n");
202 }
d58b8e00
MPM
203 print(" \"geometry\": {\n");
204 print(" \"type\": \"Polygon\",\n");
205 print(" \"coordinates\": [[\n");
206 unless ($sth2->execute($row->{'way'})) {
207 print(STDERR "Sorry, decoding the way data exploded.\n");
208 exit(1);
209 }
210 my ($onex, $oney);
9de6d037 211 my $firstcoord = 1;
d58b8e00 212 while (($onex, $oney) = $sth2->fetchrow_array()) {
9de6d037
MPM
213 if ($firstcoord == 1) {
214 $firstcoord = 0;
215 } else {
216 print(",\n");
217 }
218 printf(" [ %.5f, %.5f ]", $onex, $oney);
d58b8e00 219 }
9de6d037 220 print("\n");
d58b8e00
MPM
221 print(" ]]\n");
222 print(" },\n");
223 print(" \"properties\": {\n");
9de6d037
MPM
224 if (defined($height)) {
225 print(" \"height\": $height,\n");
226 }
227 if (defined($min_height)) {
228 print(" \"min_height\": $minheight,\n");
229 }
230 if (defined($levels)) {
231 print(" \"levels\": $levels,\n");
232 }
233 if (defined($minlevel)) {
234 print(" \"minLevel\": $minlevel,\n");
235 }
d58b8e00
MPM
236 if (defined($wallcolor)) {
237 print(" \"wallColor\": \"$wallcolor\",\n");
238 }
239 if (defined($roofcolor)) {
9de6d037 240 $roofcolor =~ s/"//g;
d58b8e00
MPM
241 print(" \"roofColor\": \"$roofcolor\",\n");
242 }
243 if (defined($roofshape)) {
9de6d037 244 $roofshape =~ s/"//g;
d58b8e00
MPM
245 print(" \"roofShape\": \"$roofshape\",\n");
246 }
247 if (defined($roofheight)) {
248 $roofheight = sprintf("%.1f", $roofheight);
249 print(" \"roofHeight\": \"$roofheight\",\n");
250 }
9de6d037 251 print(" \"dummy\": \"void\"\n");
d58b8e00 252 print(" }\n");
9de6d037 253 print(" }");
d58b8e00
MPM
254 }
255 $sth2->finish();
256 undef($sth2);
257 $sth->finish();
258 undef($sth);
259}
9de6d037
MPM
260print("\n ]\n");
261if ($iscgi == 0) {
262 print("};\n");
263} else {
264 print("}\n");
265}
This page took 0.074898 seconds and 4 git commands to generate.