# # PERL mapweaver module by gary68 # # # # # Copyright (C) 2011, Gerhard Schwanz # # This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 3 of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along with this program; if not, see # package mwFile ; use strict ; use warnings ; use mwConfig ; use mwMap ; use mwLabel ; use LWP::Simple ; use OSM::osm ; use vars qw($VERSION @ISA @EXPORT @EXPORT_OK); require Exporter ; @ISA = qw ( Exporter AutoLoader ) ; @EXPORT = qw ( readFile getNodePointers getWayPointers getRelationPointers ) ; my %lon ; my %lat ; my %memNodeTags ; my %memWayNodes ; my %memWayTags ; my %memRelationMembers ; my %memRelationTags ; my $overpassSource0 = "interpreter?data=node%5B%22name%22%3D%22NAME%22%5D%3Bout%20body%3B%0A" ; my $overpassSource1 = "interpreter?data=node%5B%22name%22%3D%22NEAR%22%5D%3Bnode%28around%3ADIST%29%5B%22name%22%3D%22NAME%22%5D%3Bout%3B" ; my $overpassSource3 = "interpreter?data=%28node%28BOTTOM%2CLEFT%2CTOP%2CRIGHT%29%3B%3C%3B%3E%3B%29%3Bout%20meta%3B" ; sub readFile { my ($nodeId, $nodeLon, $nodeLat, $nodeUser, $aRef1, @nodeTags) ; my ($wayId, $wayUser, $aRef2, @wayTags, @wayNodes) ; my ($relationId, $relationUser, @relationTags, @relationMembers) ; my %invalidWays ; my $osmName ; if (defined cv('in')) { $osmName = cv('in') ; } my $clipbbox = "" ; if (defined cv('clipbbox')) { $clipbbox = cv('clipbbox') ; } if ( cv('overpass') eq "1" ) { if ( cv('place') eq "" ) { die ("ERROR: option place not specified.\n") ; } my $overpassNear = cv('near') ; my $overpassDistance = cv('overpassdistance') ; my $overpassName = cv('place') ; my $overpassUrl1 = cv('overpassserver') . $overpassSource1 ; if ( cv('near') eq "" ) { $overpassUrl1 = cv('overpassserver') . $overpassSource0 ; } $overpassUrl1 =~ s/NEAR/$overpassNear/ ; $overpassUrl1 =~ s/DIST/$overpassDistance/ ; $overpassUrl1 =~ s/NAME/$overpassName/ ; if ( cv('debug') eq "1" ) { print "Overpass Query1: $overpassUrl1 ...\n" ; } print "Send Query 1 to overpass server..\n" ; my $result1 = get ( $overpassUrl1 ) ; if ( ! defined $result1 ) { die ("ERROR: bad overpass result!\n") ; } if ( cv('debug') eq "1" ) { print "\n$result1\n\n" ; } # get lon, lat my ($placeLon) = ( $result1 =~ /lon=\"([\d\.\-]+)/ ) ; my ($placeLat) = ( $result1 =~ /lat=\"([\d\.\-]+)/ ) ; if ((! defined $placeLon) or (! defined $placeLat)) { die ("ERROR: lon/lat could not be obtained from 1st overpass result.\n") ; } print "place $overpassName found:\n" ; print "lon= $placeLon\n" ; print "lat= $placeLat\n" ; # calc bbox my $overLeft = $placeLon - cv('lonrad')/(111.11 * cos ( $placeLat / 360 * 3.14 * 2 ) ) ; my $overRight = $placeLon + cv('lonrad')/(111.11 * cos ( $placeLat / 360 * 3.14 * 2 ) ) ; my $overTop = $placeLat + cv('latrad')/111.11 ; my $overBottom = $placeLat - cv('latrad')/111.11 ; my $overpassUrl2 = cv('overpassserver') . $overpassSource3 ; $overpassUrl2 =~ s/LEFT/$overLeft/ ; $overpassUrl2 =~ s/RIGHT/$overRight/ ; $overpassUrl2 =~ s/TOP/$overTop/ ; $overpassUrl2 =~ s/BOTTOM/$overBottom/ ; if ( cv('debug') eq "1" ) { print "Overpass Query2: $overpassUrl2\n" ; } print "Send Query 2 to overpass server..\n" ; my $result2 = get ( $overpassUrl2 ) ; if ( ! defined $result2 ) { die ("ERROR: bad overpass result!\n") ; } # save my $opFileName = "overpass.osm" ; open (my $overFile, ">", $opFileName) ; binmode($overFile, ":utf8") ; print $overFile $result2 ; close ( $overFile ) ; setConfigValue ('in', $opFileName) ; $osmName = $opFileName ; # setConfigValue ('place', '') ; $clipbbox = "$overLeft,$overBottom,$overRight,$overTop" ; if ( cv('debug') eq "1" ) { print "clipbox: $clipbbox\n" ; } } if ( grep /\.pbf/, $osmName ) { my $newName = $osmName ; $newName =~ s/\.pbf/\.osm/i ; # osmosis print "call osmosis to convert pbf file to osm file.\n" ; `osmosis --read-pbf $osmName --write-xml $newName` ; # change config $osmName = $newName ; setConfigValue ("in", $newName) ; } # -place given? look for place and call osmosis my $left ; my $right ; my $top ; my $bottom ; my $placeFound = 0 ; my $placeLon ; my $placeLat ; if ( ( cv('place') ne "") and (cv('overpass') ne "1" ) ) { my ($placeId) = ( cv('place') =~ /([\d]+)/); if (!defined $placeId) { $placeId = -999999999 ; } print "looking for place...\n" ; my $placeFileName = "" ; if ( cv('placeFile') ne "" ) { $placeFileName = cv('placeFile') ; } else { $placeFileName = cv('in') ; } openOsmFile ($placeFileName) ; ($nodeId, $nodeLon, $nodeLat, $nodeUser, $aRef1) = getNode2 () ; if ($nodeId != -1) { @nodeTags = @$aRef1 ; } my $place = cv ('place') ; while ( ($nodeId != -1) and ($placeFound == 0) ) { my $placeNode = 0 ; my $placeName = 0 ; foreach my $tag ( @nodeTags ) { if ($tag->[0] eq "place") { $placeNode = 1 ; } if ( ($tag->[0] eq "name") and (grep /$place/i, $tag->[1]) ){ $placeName = 1 ; } } if ( (($placeNode == 1) and ($placeName == 1)) or ($placeId == $nodeId) ) { $placeFound = 1 ; $placeLon = $nodeLon ; $placeLat = $nodeLat ; } ($nodeId, $nodeLon, $nodeLat, $nodeUser, $aRef1) = getNode2 () ; if ($nodeId != -1) { @nodeTags = @$aRef1 ; } } closeOsmFile() ; if ($placeFound == 1) { print "place $place found at " ; print "lon: $placeLon " ; print "lat: $placeLat\n" ; $left = $placeLon - cv('lonrad')/(111.11 * cos ( $placeLat / 360 * 3.14 * 2 ) ) ; $right = $placeLon + cv('lonrad')/(111.11 * cos ( $placeLat / 360 * 3.14 * 2 ) ) ; $top = $placeLat + cv('latrad')/111.11 ; $bottom = $placeLat - cv('latrad')/111.11 ; print "call osmosis...\n" ; if ( cv('cie') eq "0" ) { print "OSMOSIS STRING: --bounding-box completeWays=yes completeRelations=yes bottom=$bottom top=$top left=$left right=$right\n" ; `osmosis --read-xml $osmName --bounding-box completeWays=yes completeRelations=yes bottom=$bottom top=$top left=$left right=$right --write-xml ./temp.osm` ; } else { print "OSMOSIS STRING: --bounding-box clipIncompleteEntities=yes bottom=$bottom top=$top left=$left right=$right\n" ; `osmosis --read-xml $osmName --bounding-box clipIncompleteEntities=yes bottom=$bottom top=$top left=$left right=$right --write-xml ./temp.osm` ; } print "osmosis done.\n" ; $osmName = "./temp.osm" ; $clipbbox = "$left,$bottom,$right,$top" ; } else { print "ERROR: place $place not found.\n" ; die() ; } } my $srtmFileName = cv('srtm') ; if ( $srtmFileName ne "" ) { my $cmdX = "osmosis --read-xml $osmName --rx file=\"$srtmFileName\" --bounding-box completeWays=yes completeRelations=yes bottom=$bottom top=$top left=$left right=$right --merge --write-xml file=\"./temp2.osm\"" ; my $cmdP = "osmosis --read-xml $osmName --read-pbf file=\"$srtmFileName\" --bounding-box completeWays=yes completeRelations=yes bottom=$bottom top=$top left=$left right=$right --merge --write-xml file=\"./temp2.osm\"" ; my $cmd = "" ; if (grep /\.pbf/, $srtmFileName) { $cmd = $cmdP ; } else { $cmd = $cmdX ; } print "call osmosis to merge SRTM data...\n$cmd\n" ; `$cmd` ; $osmName = "temp2.osm" ; } # STORE DATA my $nr = 0 ; my $wr = 0 ; my $rr = 0 ; print "reading osm file...\n" ; openOsmFile ($osmName) ; ($nodeId, $nodeLon, $nodeLat, $nodeUser, $aRef1) = getNode2 () ; if ($nodeId != -1) { @nodeTags = @$aRef1 ; } while ($nodeId != -1) { $nr++ ; $lon{$nodeId} = $nodeLon ; $lat{$nodeId} = $nodeLat ; @{$memNodeTags{$nodeId}} = @nodeTags ; ($nodeId, $nodeLon, $nodeLat, $nodeUser, $aRef1) = getNode2 () ; if ($nodeId != -1) { @nodeTags = @$aRef1 ; } } ($wayId, $wayUser, $aRef1, $aRef2) = getWay2 () ; if ($wayId != -1) { @wayNodes = @$aRef1 ; @wayTags = @$aRef2 ; } while ($wayId != -1) { $wr++ ; if (scalar (@wayNodes) > 1) { @{$memWayTags{$wayId}} = @wayTags ; @{$memWayNodes{$wayId}} = @wayNodes ; foreach my $node (@wayNodes) { if (!defined $lon{$node}) { print " ERROR: way $wayId references node $node, which is not present!\n" ; } } } else { $invalidWays{$wayId} = 1 ; } ($wayId, $wayUser, $aRef1, $aRef2) = getWay2 () ; if ($wayId != -1) { @wayNodes = @$aRef1 ; @wayTags = @$aRef2 ; } } ($relationId, $relationUser, $aRef1, $aRef2) = getRelation () ; if ($relationId != -1) { @relationMembers = @$aRef1 ; @relationTags = @$aRef2 ; } while ($relationId != -1) { $rr++ ; @{$memRelationTags{$relationId}} = @relationTags ; @{$memRelationMembers{$relationId}} = @relationMembers ; foreach my $member (@relationMembers) { if ( ($member->[0] eq "node") and (!defined $lon{$member->[1]}) ) { print " ERROR: relation $relationId references node $member->[1] which is not present!\n" ; } if ( ($member->[0] eq "way") and (!defined $memWayNodes{$member->[1]} ) and (!defined $invalidWays{$member->[1]}) ) { print " ERROR: relation $relationId references way $member->[1] which is not present or invalid!\n" ; } } #next ($relationId, $relationUser, $aRef1, $aRef2) = getRelation () ; if ($relationId != -1) { @relationMembers = @$aRef1 ; @relationTags = @$aRef2 ; } } closeOsmFile () ; print "read: $nr nodes, $wr ways and $rr relations.\n\n" ; # calc area of pic and init graphics my $lonMin = 999 ; my $lonMax = -999 ; my $latMin = 999 ; my $latMax = -999 ; foreach my $key (keys %lon) { if ($lon{$key} > $lonMax) { $lonMax = $lon{$key} ; } if ($lon{$key} < $lonMin) { $lonMin = $lon{$key} ; } if ($lat{$key} > $latMax) { $latMax = $lat{$key} ; } if ($lat{$key} < $latMin) { $latMin = $lat{$key} ; } } # clip picture if desired if ($clipbbox ne "") { my ($bbLeft, $bbBottom, $bbRight, $bbTop) = ($clipbbox =~ /([\d\-\.]+),([\d\-\.]+),([\d\-\.]+),([\d\-\.]+)/ ) ; # print "$bbLeft, $bbBottom, $bbRight, $bbTop\n" ; if (($bbLeft > $lonMax) or ($bbLeft < $lonMin)) { print "WARNING -clipbox left parameter outside data.\n" ; } if (($bbRight > $lonMax) or ($bbRight < $lonMin)) { print "WARNING -clipbox right parameter outside data.\n" ; } if (($bbBottom > $latMax) or ($bbBottom < $latMin)) { print "WARNING -clipbox bottom parameter outside data.\n" ; } if (($bbTop > $latMax) or ($bbTop < $latMin)) { print "WARNING -clipbox top parameter outside data.\n" ; } $lonMin = $bbLeft ; $lonMax = $bbRight ; $latMin = $bbBottom ; $latMax = $bbTop ; } else { if (defined cv('clip')) { if ( (cv('clip') > 0) and (cv('clip') < 100) ) { my $clip = cv('clip') ; $clip = $clip / 100 ; $lonMin += ($lonMax-$lonMin) * $clip ; $lonMax -= ($lonMax-$lonMin) * $clip ; $latMin += ($latMax-$latMin) * $clip ; $latMax -= ($latMax-$latMin) * $clip ; } } } # pad picture if desired if (defined cv('pad')) { my $pad = cv('pad') ; if ( ($pad > 0) and ($pad < 100) ) { $pad = $pad / 100 ; $lonMin -= ($lonMax-$lonMin) * $pad ; $lonMax += ($lonMax-$lonMin) * $pad ; $latMin -= ($latMax-$latMin) * $pad ; $latMax += ($latMax-$latMin) * $pad ; } } my $size = cv('size') ; # calc pic size if ( cv('scaleSet') != 0 ) { my $dist = distance ($lonMin, $latMin, $lonMax, $latMin) ; my $width = $dist / cv('scaleSet') * 1000 * 100 / 2.54 ; # inches $size = int ($width * 300) ; } if ( cv('maxTargetSize') ne "" ) { my @a = split /,/, cv('maxTargetSize') ; my $targetWidth = $a[0] ; my $targetHeight = $a[1] ; # print "TS: $targetWidth, $targetHeight [cm]\n" ; my $distLon = distance ($lonMin, $latMin, $lonMax, $latMin) ; my $distLat = distance ($lonMin, $latMin, $lonMin, $latMax) ; # print "TS: $distLon, $distLat [km]\n" ; my $scaleLon = ($distLon * 1000 * 100) / $targetWidth ; my $scaleLat = ($distLat * 1000 * 100) / $targetHeight ; my $targetScale = int $scaleLon ; if ( $scaleLat > $targetScale ) { $targetScale = int $scaleLat ; } # print "TS: $targetScale [1:n]\n" ; my $width = $distLon / $targetScale * 1000 * 100 / 2.54 ; # inches $size = int ($width * 300) ; print "Map width now $size [px] due to maxTargetSize parameter\n" ; } mwMap::initGraph ($size, $lonMin, $latMin, $lonMax, $latMax) ; } sub getNodePointers { return ( \%lon, \%lat, \%memNodeTags) ; } sub getWayPointers { return ( \%memWayNodes, \%memWayTags) ; } sub getRelationPointers { return ( \%memRelationMembers, \%memRelationTags) ; } 1 ;