use DBI;
use POSIX qw(strftime mktime);
use Pg::hstore;
+use JSON;
# Par. 0: Level on which this gets printed
# Par. 1: Text
return $res;
}
-# Helper functions for the CGI variant. Taken from the openstreetmap-Wiki.
+# Helper functions for the CGI variant. Taken from the openstreetmap-Wiki,
+# which in turn is almost a direct copy of a GPL'd script included in (amongst
+# others) the mapnik sourcecode. -> GPL code
use Math::Trig;
-sub Project {
+sub Project($$$) {
my ($X, $Y, $Zoom) = @_;
my $Unit = 1 / (2 ** $Zoom);
my $relY1 = $Y * $Unit;
my $relY2 = $relY1 + $Unit;
-
- # note: $LimitY = ProjectF(degrees(atan(sinh(pi)))) = log(sinh(pi)+cosh(pi)) = pi
- # note: degrees(atan(sinh(pi))) = 85.051128..
- #my $LimitY = ProjectF(85.0511);
-
- # so stay simple and more accurate
my $LimitY = pi;
my $RangeY = 2 * $LimitY;
$relY1 = $LimitY - $RangeY * $relY1;
my $Long1 = -180 + $X * $Unit;
return ($Lat2, $Long1, $Lat1, $Long1 + $Unit); # S,W,N,E
}
-sub ProjectMercToLat($){
- my $MercY = shift;
- return rad2deg(atan(sinh($MercY)));
+sub ProjectMercToLat($) {
+ return rad2deg(atan(sinh($_[0])));
}
-sub ProjectF
-{
- my $Lat = shift;
- $Lat = deg2rad($Lat);
- my $Y = log(tan($Lat) + sec($Lat));
- return $Y;
+sub ProjectF($) {
+ $Lat = deg2rad($_[0]);
+ return (log(tan($Lat) + sec($Lat)));
}
+# ----- end of copied helper functions -----
# print that drops whitespace when not in verbose mode.
sub printwows($) {
if (defined($ENV{'REQUEST_URI'})) {
$iscgi = 1;
- print("Content-type: application/json\n");
+ print("Content-type: application/json; charset=utf-8\n");
print("Access-Control-Allow-Origin: *\n");
print("Cache-Control: public, max-age=3600\n");
print("\n");
$ty1 = $dbh->selectrow_array("select ST_Y(ST_transform(ST_GeomFromText('POINT($x1 $y1)', 4326), 900913))");
$tx2 = $dbh->selectrow_array("select ST_X(ST_transform(ST_GeomFromText('POINT($x2 $y2)', 4326), 900913))");
$ty2 = $dbh->selectrow_array("select ST_Y(ST_transform(ST_GeomFromText('POINT($x2 $y2)', 4326), 900913))");
+# Why do crappy perl libraries always insist on using an "Object Oriented" interface
+# for things where this does not make any sense at all?
+my $crappyjsonoo = JSON->new()->latin1(); # Note: has to be latin1 instead of utf8
+# for now, because the strings we get from the DB are WTF8, but are not marked
+# as such. Therefore, we must not tell the JSON module to do utf8(), because
+# otherwise it would encode the WTF8 twice.
+# This will change with DBI::Pg modules >3 where UTF8 is properly handled.
+if ($verblev > 0) {
+ $crappyjsonoo = $crappyjsonoo->pretty();
+}
my $cntr = 0;
if ($iscgi == 0) {
print("// Note: this file has been autogenerated by $0\n");
}
my $sth2 = $dbh->prepare("select ST_X(points) as x, ST_Y(points) as y"
. " from (select ST_astext((ST_dumppoints(ST_transform(?, 4326))).geom) as points) as points");
+ my $sth4 = $dbh->prepare("select (ST_dumprings(?)).geom as rings");
while ($row = $sth->fetchrow_hashref()) {
if ($xtable eq 'planet_osm_polygon1') {
my $hassubparts = $dbh->selectrow_array("select count(*)"
- . " from planet_osm_line"
- . " where ((tags->'building:part') is not null)"
- . " and (ST_Covers(" . $dbh->quote($row->{'way'}) . ", way) = true)");
+ . " from planet_osm_line"
+ . " where ((tags->'building:part') is not null)"
+ . " and (ST_Covers(" . $dbh->quote($row->{'way'}) . ", way) = true)");
# The subparts usually cover the whole building, so we do NOT draw the
# whole building but only the subparts.
if ($hassubparts > 0) { next; }
$hstoredec = Pg::hstore::decode($row->{'tags'});
}
my $levels = fetchlastofhr(1, $hstoredec, 'levels', 'building:levels');
- my $height = fetchlastofhr($height, $hstoredec, 'height', 'building:height');
- unless ($height =~ m/^[0-9.]+$/) { undef($height); }
+ my $height = fetchlastofhr(undef, $hstoredec, 'height', 'building:height');
+ unless ((defined($height)) && ($height =~ m/^[0-9.]+$/)) {
+ undef($height);
+ }
my $minlevel = fetchlastofhr(0, $hstoredec,
'min_levels', 'building:min_levels', 'min_level', 'building:min_level');
- my $minheight = fetchlastofhr($minheight, $hstoredec, 'min_height', 'building:min_height');
- unless ($minheight =~ m/^[0-9.]+$/) { undef($minheight); }
+ my $minheight = fetchlastofhr(undef, $hstoredec, 'min_height', 'building:min_height');
+ unless ((defined($minheight)) && ($minheight =~ m/^[0-9.]+$/)) {
+ undef($minheight);
+ }
+ my $shape = fetchlastofhr(undef, $hstoredec, 'building:shape');
+ my $material = fetchlastofhr(undef, $hstoredec,
+ 'building:material', 'building:facade:material', 'building:cladding');
my $wallcolor = fetchlastofhr(undef, $hstoredec, 'building:color', 'building:colour');
my $roofcolor = fetchlastofhr(undef, $hstoredec,
'roof:color', 'roof:colour', 'building:roof:color', 'building:roof:colour');
my $roofshape = fetchlastofhr(undef, $hstoredec, 'roof:shape', 'building:roof:shape');
my $roofheight = fetchlastofhr(undef, $hstoredec, 'roof:height', 'building:roof:height');
+ unless ((defined($roofheight)) && ($roofheight =~ m/^[0-9.]+$/)) {
+ undef($roofheight);
+ }
my $roofmaterial = fetchlastofhr(undef, $hstoredec, 'roof:material', 'building:roof:material');
if ($cntr != 0) {
printwows(",\n");
}
$cntr++;
- printwows(" {\n");
- printwows(" \"type\": \"Feature\",\n");
- if (defined($row->{'osm_id'})) {
- printwows(" \"id\": " . $row->{'osm_id'} . ",\n");
- } else {
- printwows(" \"id\": $cntr,\n");
- }
+ my $jso = { "type" => "Feature" };
+ $jso->{'id'} = (defined($row->{'osm_id'}) ? $row->{'osm_id'} : $cntr);
if (defined($row->{'name'})) {
- $row->{'name'} =~ s/"//g;
- printwows(" \"name\": \"" . $row->{'name'} . "\",\n");
+ $jso->{'name'} = $row->{'name'};
}
- printwows(" \"geometry\": {\n");
- printwows(" \"type\": \"Polygon\",\n");
- printwows(" \"coordinates\": [[\n");
- unless ($sth2->execute($row->{'way'})) {
- print(STDERR "Sorry, decoding the way data exploded.\n");
- exit(1);
- }
- my ($onex, $oney);
- my $firstcoord = 1;
- while (($onex, $oney) = $sth2->fetchrow_array()) {
- if ($firstcoord == 1) {
- $firstcoord = 0;
+ my @waystodecode = ();
+ {
+ local $sth4->{'PrintError'}; # We're fully aware that the execute can
+ local $sth4->{'PrintWarn'}; # fail, no need to spam about it.
+ if ($sth4->execute($row->{'way'})) {
+ while ((my $nxtway) = $sth4->fetchrow_array()) {
+ push(@waystodecode, $nxtway);
+ }
} else {
- printwows(",\n");
+ push(@waystodecode, $row->{'way'});
+ }
+ }
+ my @geomarr2 = ();
+ foreach my $nxtway (@waystodecode) {
+ unless ($sth2->execute($nxtway)) {
+ print(STDERR "Sorry, decoding the way data exploded.\n");
+ exit(1);
}
- printwows(sprintf(" [ %.5f, %.5f ]", $onex, $oney));
+ my ($onex, $oney);
+ my @geomarr1 = ();
+ while (($onex, $oney) = $sth2->fetchrow_array()) {
+ my @onecoord = ( sprintf("%.5f", $onex), sprintf("%.5f", $oney));
+ push (@geomarr1, \@onecoord);
+ }
+ push(@geomarr2, \@geomarr1);
+ $sth2->finish();
}
- printwows("\n");
- printwows(" ]]\n");
- printwows(" },\n");
- printwows(" \"properties\": {\n");
+ my $geomhsh = { "type" => "Polygon",
+ "coordinates" => \@geomarr2 };
+ $jso->{'geometry'} = $geomhsh;
+ my $prophsh = { };
if (defined($height)) {
- printwows(" \"height\": $height,\n");
+ $prophsh->{'height'} = $height;
}
if (defined($minheight)) {
- printwows(" \"minHeight\": $minheight,\n");
+ $prophsh->{'minHeight'} = $minheight;
}
if (defined($levels)) {
- printwows(" \"levels\": $levels,\n");
+ $prophsh->{'levels'} = $levels;
}
if (defined($minlevel)) {
- printwows(" \"minLevel\": $minlevel,\n");
+ $prophsh->{'minLevel'} = $minlevel;
+ }
+ if (defined($shape)) {
+ $prophsh->{'shape'} = $shape;
+ }
+ if (defined($material)) {
+ $prophsh->{'material'} = $material;
}
if (defined($wallcolor)) {
- printwows(" \"wallColor\": \"$wallcolor\",\n");
+ $prophsh->{'wallColor'} = $wallcolor;
}
if (defined($roofcolor)) {
- $roofcolor =~ s/"//g;
- printwows(" \"roofColor\": \"$roofcolor\",\n");
+ $prophsh->{'roofColor'} = $roofcolor;
}
if (defined($roofshape)) {
- $roofshape =~ s/"//g;
if ($roofshape eq 'pyramidal') { $roofshape = 'pyramid'; }
- printwows(" \"roofShape\": \"$roofshape\",\n");
+ $prophsh->{'roofShape'} = $roofshape;
}
if (defined($roofmaterial)) {
- $roofshape =~ s/"//g;
- printwows(" \"roofMaterial\": \"$roofmaterial\",\n");
+ $prophsh->{'roofMaterial'} = $roofmaterial;
}
if (defined($roofheight)) {
- $roofheight = sprintf("%.1f", $roofheight);
- printwows(" \"roofHeight\": \"$roofheight\",\n");
+ $prophsh->{'roofHeight'} = $roofheight;
}
- # this line is completely useless, but we need it to guarantee JSON has
- # no trailing comma. osmbuildings will accept JSON with trailing commas
- # just fine when you give it static, but NOT when requesting it dynamically.
- printwows(" \"K9\": \"\"\n");
- printwows(" }\n");
- printwows(" }");
+ $jso->{'properties'} = $prophsh;
+ # Now dump it all.
+ print($crappyjsonoo->encode($jso));
}
- $sth2->finish();
- undef($sth2);
+ $sth4->finish();
+ undef($sth4);
$sth->finish();
undef($sth);
}