#!/usr/bin/perl -w # NAME: osm2ac3dd.pl # AIM: Search for a 'way' id in an osm file, and generate an AC3D .ac file of the building model use strict; use warnings; use File::Basename; # split path ($name,$dir,$ext) = fileparse($file [, qr/\.[^.]*/] ) use Data::Dumper; use Math::Trig qw(great_circle_distance great_circle_destination great_circle_bearing deg2rad rad2deg); use LWP::Simple; use Cwd; my $os = $^O; my $perl_dir = '/home/geoff/bin'; my $PATH_SEP = '/'; my $temp_dir = '/tmp'; if ($os =~ /win/i) { $perl_dir = 'C:\GTools\perl'; $temp_dir = $perl_dir; $PATH_SEP = "\\"; } unshift(@INC, $perl_dir); require 'lib_utils.pl' or die "Unable to load 'lib_utils.pl' Check paths in \@INC...\n"; # log file stuff our ($LF); my $pgmname = $0; if ($pgmname =~ /(\\|\/)/) { my @tmpsp = split(/(\\|\/)/,$pgmname); $pgmname = $tmpsp[-1]; } my $outfile = $temp_dir.$PATH_SEP."temp.$pgmname.txt"; open_log($outfile); # user variables my $VERS = "0.0.1 2013-05-14"; my $load_log = 0; my $in_file = ''; my $verbosity = 0; my $out_file = ''; my $start_line = 0; my $end_line = 0; my $max_lines = 0; my $node_id = ''; my $way_id = ''; my $latitude = ''; my $longitude = ''; my $user_lat = 0; my $user_lon = 0; my $closedway = 1; my $nodecount = 0; my $wayxml = ''; my $height = 100; # 20; my $modelname = "Building"; my $roofshape = 2; my @way = (); my $out_xml = $temp_dir.$PATH_SEP."temp.building.osm"; # constants my $pi = 3.14159265358979323846; # ### DEBUG ### my $debug_on = 1; my $def_out = $temp_dir.$PATH_SEP."temp.building.ac"; my $def_file = 'C:\GTools\perl\piccatwr.osm'; ##my $def_file = 'D:\SAVES\OSM\australia.osm'; #my $def_nid = 14988821; my $def_wid = 101917220; # Piccadilly Tower, Sydney - 32 storey, this est abt 100m height # osm xml # # # plus 8 more # # # a 32-story building ### program variables my @warnings = (); my $cwd = cwd(); sub VERB1() { return $verbosity >= 1; } sub VERB2() { return $verbosity >= 2; } sub VERB5() { return $verbosity >= 5; } sub VERB9() { return $verbosity >= 9; } sub show_warnings($) { my ($val) = @_; if (@warnings) { prt( "\nGot ".scalar @warnings." WARNINGS...\n" ); foreach my $itm (@warnings) { prt("$itm\n"); } prt("\n"); } else { prt( "\nNo warnings issued.\n\n" ) if (VERB9()); } } sub pgm_exit($$) { my ($val,$msg) = @_; if (length($msg)) { $msg .= "\n" if (!($msg =~ /\n$/)); prt($msg); } show_warnings($val); close_log($outfile,$load_log); exit($val); } sub prtw($) { my ($tx) = shift; $tx =~ s/\n$//; prt("$tx\n"); push(@warnings,$tx); } sub rad2m { my ($rad) = @_; return $rad * 6377997; } sub m2rad { my ($m) = @_; return $m / 6377997; } my $infile; sub getline() { my $line = <$infile>; return if ( !$line ); return $line; } sub get_nd_ids($) { my $ra = shift; my $inf = $in_file; if (! open($infile, "<$inf") ) { pgm_exit(1,"ERROR: Unable to open file [$inf]\n"); } my ($line,$id,$lat,$lon,$lnn,$fnd,$blen); $blen = scalar @{$ra}; my %h = (); # hmmmm, seems can have DUPLICATED node ids foreach $id (@{$ra}) { $h{$id} = 1; } my $cnt = scalar keys(%h); prt("Processing [$inf] for $cnt nd ids... ($blen)\n"); $blen = 0; $lnn = 0; $| = 1; # turn OFF stdout buffering while ($line = getline()) { $lnn++; if (($lnn % 100000) == 0) { prt("."); $blen++; if ($blen >= 100) { prt("\n"); $blen = 0; } } if ($line =~ //) { $id = $1; if (defined $h{$id}) { ###my ($lat,$lon) = $line =~ /lat=[\'\"]([0-9\-\.]+)[\'\"] lon=[\'\"]([0-9\-\.]+)[\'\"]/gis; $fnd = 0; if ($line =~ /lat=[\'\"]([0-9\-\.]+)[\'\"]/gis) { $lat = $1; $fnd += 1; } if ($line =~ /lon=[\'\"]([0-9\-\.]+)[\'\"]/gis) { $lon = $1; $fnd += 2; } $way[$nodecount]->{'node'} = $id; $way[$nodecount]->{'lat'} = $lat; $way[$nodecount]->{'lon'} = $lon; $way[$nodecount]->{'x'} = 0; $way[$nodecount]->{'y'} = 0; $nodecount++; prt("\n") if ($blen); prt("$nodecount of $cnt: $id $lat $lon \n"); #if $verbose; $blen = 0; $h{$id} = $fnd; if ($nodecount >= $cnt) { prt("Found all nodes, at line $. in file\n"); last; } } } } close($infile); prt("\n") if ($blen); foreach $id (keys %h) { $blen = $h{$id}; if ($blen != 3) { prt("Seems missed node id [$id]? ($blen)\n"); } } prt("Done get nds...\n"); return \@way; } sub get_way_nd_ids($) { my $ra = shift; # \@waylines $wayxml = join("\n",@{$ra}); prt("\nWay lines\n"); prt("$wayxml\n"); my %ndids = (); foreach ($wayxml=~/nd ref=[\'\"]([0-9]+)[\'\"]/gis) { $ndids{$_ } = 1; } return \%ndids; } sub process_way_lines($) { my $ra = shift; # \@waylines my $wayxml = join("\n",@{$ra}); prt("\nWay lines\n"); prt("$wayxml\n"); my @ndids = (); foreach ($wayxml=~/nd ref=[\'\"]([0-9]+)[\'\"]/gis) { push( @ndids,$_ ); } if (! @ndids) { prt("Failed to get and nd ids!\n"); return; } get_nd_ids(\@ndids); ##prt(Dumper(@way)); prt("\n"); my ($i,$max,$reflat,$reflon,$lat,$lon); if ($user_lat) { $reflat = $latitude; } else { $reflat = $way[0]->{'lat'}; } if ($user_lon) { $reflon = $longitude; } else { $reflon = $way[0]->{'lon'}; } $max = scalar @way; prt("Reference lat [$reflat], lon [$reflon], applied to $max waypoints...\n"); # Process data structure #if ($way[0]->{'node'}!=$way[$max]->{'node'}) { # Work around!! Consider all ways "closed", even if they are not!! $closedway = 1; # $closedway=0; # carp "This is not a closed way"; # exit 1; #} else { # $closedway=1; #}; for ($i = 0; $i < $max; $i++) { $lon = $way[$i]->{'lon'}; $lat = $way[$i]->{'lat'}; if (($lon == $reflon) && ($lat == $reflat)) { $way[$i]->{'x'} = 0; $way[$i]->{'y'} = 0; } else { my $distancerad = great_circle_distance(deg2rad($reflon),deg2rad(90-$reflat) ,deg2rad($lon),deg2rad(90-$lat)); my $bearingrad = great_circle_bearing(deg2rad($reflon),deg2rad(90-$reflat) ,deg2rad($lon),deg2rad(90-$lat)); my $distancem = &rad2m($distancerad); $way[$i]->{'x'} = $distancem * cos($bearingrad); $way[$i]->{'y'} = $distancem * sin($bearingrad); } prt("Way ".($i+1).": x=".$way[$i]->{'x'}.", y=".$way[$i]->{'y'}."\n"); # if $verbose; } } # Get osm building data from way sub getosmdata { my ($wayheight) = $wayxml =~ /tag k=\"height\" v=[\'\"]([0-9]+)[\'\"]/gis; my ($waylevels) = $wayxml =~ /tag k=\"building:levels\" v=[\'\"]([0-9]+)[\'\"]/gis; my ($wayroofshape) = $wayxml =~ /tag k=\"building:roof:shape\" v=[\'\"]([0-9]+)[\'\"]/gis; # No height given, number of floors maybe? #if ($wayheight == "") { if ((!defined $wayheight || (length($wayheight) == 0))&& (defined $waylevels && length($waylevels))) { # NO way height, but have waylevels, then $wayheight = $waylevels * 3; # One floor is roughly 3m } # Use given/estimated height #if ($wayheight != "") { if (defined $wayheight && length($wayheight)) { $height = $wayheight; } else { # Fall back to default height, with randomly an extra level $height = $height + int(rand(2))*3; } #if ($wayroofshape != "") { if (defined $wayroofshape && length($wayroofshape)) { $roofshape = $wayroofshape; } elsif ($height < 25) { # Estimate roof shape $roofshape = 2; } if (!defined $waylevels || (length($waylevels) == 0)) { $waylevels = int($height / 3); } return ($height,$waylevels,$roofshape); } sub get_ac3d_info() { my ($i,$max,$reflat,$reflon,$lat,$lon); my ($levels,$walltexture,$rooftexture,$node); my @side = (); my ($tc,$bl,$br,$tl,$tr); my @roofvert = (); my ($roofheight,$roofvert); my ($surfaces,$sidenum,$wall); my ($texturex,$texturey); my ($texturescalex,$texturescaley); if ($user_lat) { $reflat = $latitude; } else { $reflat = $way[0]->{'lat'}; } if ($user_lon) { $reflon = $longitude; } else { $reflon = $way[0]->{'lon'}; } $max = scalar @way; prt("Reference lat [$reflat], lon [$reflon], applied to $max waypoints...\n"); # Process data structure #if ($way[0]->{'node'}!=$way[$max]->{'node'}) { # Work around!! Consider all ways "closed", even if they are not!! $closedway = 1; # $closedway=0; # carp "This is not a closed way"; # exit 1; #} else { # $closedway=1; #}; for ($i = 0; $i < $max; $i++) { $lon = $way[$i]->{'lon'}; $lat = $way[$i]->{'lat'}; if (($lon == $reflon) && ($lat == $reflat)) { $way[$i]->{'x'} = 0; $way[$i]->{'y'} = 0; } else { my $distancerad = great_circle_distance(deg2rad($reflon),deg2rad(90-$reflat) ,deg2rad($lon),deg2rad(90-$lat)); my $bearingrad = great_circle_bearing(deg2rad($reflon),deg2rad(90-$reflat) ,deg2rad($lon),deg2rad(90-$lat)); my $distancem = &rad2m($distancerad); $way[$i]->{'x'} = $distancem * cos($bearingrad); $way[$i]->{'y'} = $distancem * sin($bearingrad); } prt("Way ".($i+1).": x=".$way[$i]->{'x'}.", y=".$way[$i]->{'y'}."\n"); # if $verbose; } # got all x,y points relative points ($height,$levels,$roofshape) = getosmdata(); # Number of vertices my $totalverts; my $layerverts; if ($closedway == 1) { $totalverts = (@way -1) * 2; $layerverts = @way - 1; } else { $totalverts = (@way) * 2; $layerverts = (@way); } # Disable gable roof for models with more than 4 corners. if (($roofshape == 2) and ($totalverts != 8 )) { $roofshape = 0; } # Textures if ($roofshape == 2) { $walltexture = "wall.png"; } else { $walltexture = "flat".int(rand(3)).".png"; } $rooftexture = "roof.png"; my $ac3d = ''; $ac3d .= "AC3Db\n"; $ac3d .= "MATERIAL \"DefaultWhite\" rgb 1 1 1 amb 1 1 1 emis 0 0 0 spec 0.5 0.5 0.5 shi 64 trans 0\n"; $ac3d .= "MATERIAL \"Roof\" rgb 1 1 1 amb 1 1 1 emis 0 0 0 spec 0.5 0.5 0.5 shi 64 trans 0\n"; $ac3d .= "OBJECT world\n"; $ac3d .= "kids 1\n"; $ac3d .= "OBJECT group\n"; $ac3d .= "name \"".$modelname."\"\n"; if ($roofshape == 2) { $ac3d .= "kids 2\n"; } else { $ac3d .= "kids 1\n"; } $ac3d .= "OBJECT poly\n"; $ac3d .= "name \"Walls\"\n"; $ac3d .= "texture \"".$walltexture."\"\n"; $ac3d .= "texrep 1 1\n"; if ($roofshape == 0) { $ac3d .= "numvert ".$totalverts."\n"; } else { $ac3d .= "numvert ".($totalverts+2)."\n"; } for ( $node = 0; $node < $layerverts; $node++ ) { $ac3d .= $way[$node]->{'x'}." $height ".$way[$node]->{'y'}."\n"; } for ( $node = 0; $node < $layerverts; $node++ ) { $ac3d .= $way[$node]->{'x'}." -5 ".$way[$node]->{'y'}."\n"; } $side[0] = sqrt((abs($way[1]->{'x'}-$way[0]->{'x'})) ** 2+(abs($way[1]->{'y'}-$way[0]->{'y'})) ** 2); $side[1] = sqrt((abs($way[1]->{'x'}-$way[2]->{'x'})) ** 2+(abs($way[1]->{'y'}-$way[2]->{'y'})) ** 2); if ($roofshape == 2) { # Calculate length of two sides, to propose a roof orientation #$side[0] = sqrt((abs($way[1]->{'x'}-$way[0]->{'x'})) ** 2+(abs($way[1]->{'y'}-$way[0]->{'y'})) ** 2); #$side[1] = sqrt((abs($way[1]->{'x'}-$way[2]->{'x'})) ** 2+(abs($way[1]->{'y'}-$way[2]->{'y'})) ** 2); # Two vertices for the roof, location depends on roof orientation $roofheight = (2/3)*$side[$side[0] > $side[1]]; if ($side[0] < $side[1]) { $roofvert[0] = (($way[0]->{'x'}+$way[1]->{'x'})/2)." ".($height+$roofheight)." ".(($way[0]->{'y'}+$way[1]->{'y'})/2)."\n"; $roofvert[1] = (($way[2]->{'x'}+$way[3]->{'x'})/2)." ".($height+$roofheight)." ".(($way[2]->{'y'}+$way[3]->{'y'})/2)."\n"; } else { $roofvert[0] = (($way[1]->{'x'}+$way[2]->{'x'})/2)." ".($height+$roofheight)." ".(($way[1]->{'y'}+$way[2]->{'y'})/2)."\n"; $roofvert[1] = (($way[3]->{'x'}+$way[0]->{'x'})/2)." ".($height+$roofheight)." ".(($way[3]->{'y'}+$way[0]->{'y'})/2)."\n"; } $ac3d .= $roofvert[0]; $ac3d .= $roofvert[1]; $surfaces = $layerverts + 2; $ac3d .= "numsurf ".$surfaces."\n"; } else { # Generate roof poly if ($closedway == 1) { $surfaces = $layerverts + 1; $ac3d .= "numsurf ".$surfaces."\n"; $ac3d .= "SURF 0x20\n"; $ac3d .= "mat 1\n"; $ac3d .= "refs ".($layerverts-1)."\n"; for ($node = $max-1; $node > 0; $node--) { $ac3d .= $node ." 0 0\n"; } } else { $surfaces = $layerverts - 1; $ac3d .= "numsurf ".$surfaces."\n"; } } # Generate walls $sidenum = 0; for ( $wall = 0; $wall < $layerverts; $wall++ ) { $ac3d .= "SURF 0x20\n"; $ac3d .= "mat 0\n"; $ac3d .= "refs 4\n"; # Special case for final wall if (($wall == ($layerverts-1)) && ($closedway == 1)) { $tl = 0; $tr = $max - 1; $bl = $max; $br = (2*$max)-1; } else { $tr = $wall; $tl = $wall + 1; $br = $wall + $layerverts; $bl = $wall + $layerverts+1; } # calculate texture scales (how often should the texture repeat?) # one texture is 3m high and wide $texturex = 6; $texturey = 6; #if ($levels == "") { if (!defined $levels || (length($levels) == 0)) { if ($roofshape == 2) { $texturescaley = ($height + 5) / $texturey; } else { $texturescaley = ($height + 5) / 3 / 2 / 10; } } else { if ($roofshape == 2) { $texturescaley = $levels / 2 / 2; } else { $texturescaley = $levels / 2 / 10; } } $texturescalex = $side[$sidenum] / 2 / $texturex; if ($sidenum == 1) { $sidenum = 0; } else { $sidenum++; } $ac3d .= $tr." -".$texturescalex." 0\n"; $ac3d .= $tl." ".$texturescalex." 0\n"; $ac3d .= $bl." ".$texturescalex." -".$texturescaley."\n"; $ac3d .= $br." -".$texturescalex." -".$texturescaley."\n"; } # Vertical end faces of the triangle roof if ($roofshape == 2) { $texturescaley = $roofheight / $texturey; $texturescalex = $side[($side[0] < $side[1])] / 2 / $texturex; for ($node = 0; $node < 2; $node++) { $bl = 1 + (2*$node) + ($side[0] > $side[1]); $br = 2 * $node + ($side[0] > $side[1]); $tc = ($totalverts) + $node; if ($bl > 3) { $bl = 0; } if ($br > 3) { $br = 0; } $ac3d .= "SURF 0x20\n"; $ac3d .= "mat 0\n"; $ac3d .= "refs 3\n"; $ac3d .= $bl." ".$texturescalex." 0\n"; $ac3d .= $br." ".$texturescalex." 0\n"; $ac3d .= $tc." 0 ".$texturescaley."\n"; } $ac3d .= "kids 0\n"; $ac3d .= "OBJECT poly\n"; $ac3d .= "name \"Roof\"\n"; $ac3d .= "texture \"roof.png\"\n"; $ac3d .= "texrep 1 1\n"; $ac3d .= "numvert 6\n"; for ( $node = 0; $node < $layerverts; $node++ ) { $ac3d .= $way[$node]->{'x'}." $height ".$way[$node]->{'y'}."\n"; } # Two vertices for the roof $ac3d .= $roofvert[0]; $ac3d .= $roofvert[1]; $ac3d .= "numsurf 2\n"; $texturescaley = $roofheight / $texturey; $texturescalex = $side[($side[0] < $side[1])] / 4 / $texturex; # Actual roof, exists of two faces for ($node = 0; $node < 2; $node++) { $bl = (2*$node) + ($side[0] > $side[1]); $br = $bl - 1; $tl = 5 - $node; $tr = 5 - 1 + $node; if ($bl > 3) { $bl = $bl-3; } if ($br > 3) { $br = $br-3; } if ($bl < 0) { $bl = $bl+4; } if ($br < 0) { $br = $br+4; } $ac3d .= "SURF 0x20\n"; $ac3d .= "mat 1\n"; $ac3d .= "refs 4\n"; $ac3d .= $bl." ".$texturescalex." 0\n"; $ac3d .= $br." -".$texturescalex." 0\n"; $ac3d .= $tl." -".$texturescalex." 1\n"; $ac3d .= $tr." ".$texturescalex." 1\n"; } $ac3d .= "kids 0\n"; } else { $ac3d .= "kids 0\n"; } write2file($ac3d,$out_file); prt("Written AC3D to [$out_file]\n"); } sub dump_osm_xml($$) { my ($rwa,$rna) = @_; # \@waylines,\@nodelines my $txt = "\n"; $txt .= "\n"; $txt .= join("\n",@{$rna})."\n"; $txt .= join("\n",@{$rwa})."\n"; $txt .= "\n"; write2file($txt,$out_xml); prt("Written osm xml to [$out_xml]\n"); } sub process_in_file($) { my ($inf) = @_; prt("Openning [$inf]...\n"); if (! open($infile, "<$inf") ) { pgm_exit(1,"ERROR: Unable to open file [$inf]\n"); } prt("Processing [$inf]...\n"); my ($line,$inc,$lnn,$lncnt,$id,$inway); $lnn = 0; $lncnt = 0; $inway = 0; my $blen = 0; my @waylines = (); my @nodelines = (); my $got_first = 0; my $first_node_pos = 0; my $first_node_line = 0; $| = 1; # turn OFF stdout buffering while ($line = getline()) { chomp $line; $lnn++; if (($lnn % 100000) == 0) { prt("."); $blen++; if ($blen >= 100) { prt("\n"); $blen = 0; } } next if (($start_line > 0)&&($lnn < $start_line)); last if (($end_line > 0)&&($lnn > $end_line)); last if (($max_lines > 0)&& ($lncnt > $max_lines)); $lncnt++; if ($inway) { push(@waylines,$line); if ($line =~ /<\/way>/) { last; } } elsif ($line =~ //) { $id = $1; if ($id == $way_id) { push(@waylines,$line); $inway = 1; prt("\n") if ($blen); prt("$lnn: Found [$line]\n"); $blen = 0; } } elsif (!$got_first && ($line =~ //)) { $id = $1; $got_first = 1; $first_node_pos = tell($infile); if ($first_node_pos > (length($line) + 1)) { $first_node_pos -= (length($line) + 1); } $first_node_line = $lnn - 1; prt("\n") if ($blen); $blen = 0; prt("Found first node $id at line $lnn, offset $first_node_pos\n"); } } prt("$lnn: [$line]\n") if ($line); prt("Processed $lnn lines... "); if ($start_line > 0) { prt("starting at $start_line... "); } if (($end_line > 0)&&($lnn > $end_line)) { prt("ending due end line "); } elsif (($max_lines > 0)&& ($lncnt > $max_lines)) { prt("ending due max lines $lncnt..."); } prt("\n"); if (@waylines) { $end_line = $lnn; ###process_way_lines(\@waylines); my ($cnt,$fnd,$lat,$lon); my $rwids = get_way_nd_ids(\@waylines); my @arr = sort keys(%{$rwids}); $cnt = scalar @arr; prt("Seeking $cnt node ids [".join(",",@arr)."]\n from getline $., line $lnn onwards...\n"); $blen = 0; while ($cnt && ($line = getline())) { chomp $line; $lnn++; if (($lnn % 100000) == 0) { prt("."); $blen++; if ($blen >= 100) { prt("\n"); $blen = 0; } } if ($line =~ //) { $id = $1; if (defined ${$rwids}{$id}) { push(@nodelines,$line); $fnd = 0; if ($line =~ /lat=[\'\"]([0-9\-\.]+)[\'\"]/gis) { $lat = $1; $fnd += 1; } if ($line =~ /lon=[\'\"]([0-9\-\.]+)[\'\"]/gis) { $lon = $1; $fnd += 2; } $way[$nodecount]->{'node'} = $id; $way[$nodecount]->{'lat'} = $lat; $way[$nodecount]->{'lon'} = $lon; $way[$nodecount]->{'x'} = 0; $way[$nodecount]->{'y'} = 0; $nodecount++; prt("\n") if ($blen); prt("$nodecount of $cnt: $id $lat $lon \n"); #if $verbose; ${$rwids}{$id} = $fnd; $blen = 0; if ($nodecount >= $cnt) { prt("Found all nodes, by getline $., line $lnn in file\n"); last; } } } } if ($nodecount < $cnt) { $lnn = $first_node_line; prt("\n") if ($blen); prt("Seek to first node pos $first_node_pos, line $lnn...\n"); seek($infile,$first_node_pos,0); # put file back to pos of first node $blen = 0; while ($cnt && ($line = getline())) { chomp $line; $lnn++; if (($lnn % 100000) == 0) { prt("."); $blen++; if ($blen >= 100) { prt("\n"); $blen = 0; } } if ($line =~ //) { $id = $1; if (defined ${$rwids}{$id}) { push(@nodelines,$line); $fnd = 0; if ($line =~ /lat=[\'\"]([0-9\-\.]+)[\'\"]/gis) { $lat = $1; $fnd += 1; } if ($line =~ /lon=[\'\"]([0-9\-\.]+)[\'\"]/gis) { $lon = $1; $fnd += 2; } $way[$nodecount]->{'node'} = $id; $way[$nodecount]->{'lat'} = $lat; $way[$nodecount]->{'lon'} = $lon; $way[$nodecount]->{'x'} = 0; $way[$nodecount]->{'y'} = 0; $nodecount++; prt("\n") if ($blen); prt("$nodecount of $cnt: $id $lat $lon \n"); #if $verbose; ${$rwids}{$id} = $fnd; $blen = 0; if ($nodecount >= $cnt) { prt("Found all nodes, by getline $. (line $lnn) in file\n"); last; } } } if ($lnn > $end_line) { prtw("WARNING: Reached end line $end_line before finding all! $nodecount of $cnt\n"); last; } } } close($infile); get_ac3d_info() if ($nodecount); dump_osm_xml(\@waylines,\@nodelines); } else { close($infile); } } sub getwayfromapi($) { my $wayid = shift; my $wayxml = get("http://api.openstreetmap.org/api/0.6/way/$wayid"); return $wayxml; } sub getnodefromapi($) { my $nodeid = shift; my $nodexml = get("http://api.openstreetmap.org/api/0.6/node/$nodeid"); return $nodexml; } sub use_osm_api() { my $wayxml = getwayfromapi($way_id); if (!defined $wayxml || (length($wayxml) == 0)) { prt("Failed to get way id [$way_id]!\n"); return; } my @waylines = split("\n",$wayxml); my $rwids = get_way_nd_ids(\@waylines); my @arr = sort keys(%{$rwids}); my $cnt = scalar @arr; prt("Seeking $cnt node ids [".join(",",@arr)."] from api...\n"); my ($id,$nodexml,$fnd,$line,$lat,$lon); my @nodelines = (); foreach $id (@arr) { $nodexml = getnodefromapi($id); if (!defined $nodexml || (length($nodexml) == 0)) { prt("Failed to get node id [$id]!\n"); } else { push(@nodelines,$nodexml); $line = $nodexml; $fnd = 0; $lat = 0; $lon = 0; if ($line =~ /lat=[\'\"]([0-9\-\.]+)[\'\"]/gis) { $lat = $1; $fnd += 1; } if ($line =~ /lon=[\'\"]([0-9\-\.]+)[\'\"]/gis) { $lon = $1; $fnd += 2; } $way[$nodecount]->{'node'} = $id; $way[$nodecount]->{'lat'} = $lat; $way[$nodecount]->{'lon'} = $lon; $way[$nodecount]->{'x'} = 0; $way[$nodecount]->{'y'} = 0; $nodecount++; prt("$nodecount of $cnt: $id $lat $lon \n"); #if $verbose; ${$rwids}{$id} = $fnd; } } get_ac3d_info() if ($nodecount); dump_osm_xml(\@waylines,\@nodelines); } ######################################### ### MAIN ### parse_args(@ARGV); if (length($in_file)) { process_in_file($in_file); } else { use_osm_api(); } pgm_exit(0,""); ######################################## sub need_arg { my ($arg,@av) = @_; pgm_exit(1,"ERROR: [$arg] must have a following argument!\n") if (!@av); } sub parse_args { my (@av) = @_; my ($arg,$sarg); while (@av) { $arg = $av[0]; if ($arg =~ /^-/) { $sarg = substr($arg,1); $sarg = substr($sarg,1) while ($sarg =~ /^-/); if (($sarg =~ /^h/i)||($sarg eq '?')) { give_help(); pgm_exit(0,"Help exit(0)"); } elsif ($sarg =~ /^v/) { if ($sarg =~ /^v.*(\d+)$/) { $verbosity = $1; } else { while ($sarg =~ /^v/) { $verbosity++; $sarg = substr($sarg,1); } } prt("Verbosity = $verbosity\n") if (VERB1()); } elsif ($sarg =~ /^l/) { if ($sarg =~ /^ll/) { $load_log = 2; } else { $load_log = 1; } prt("Set to load log at end. ($load_log)\n") if (VERB1()); } elsif ($sarg =~ /^o/) { need_arg(@av); shift @av; $sarg = $av[0]; $out_file = $sarg; prt("Set out file to [$out_file].\n") if (VERB1()); } elsif ($sarg =~ /^s/) { need_arg(@av); shift @av; $sarg = $av[0]; if ($sarg =~ /^\d+$/) { $start_line = $sarg; prt("Set start line to [$start_line].\n") if (VERB1()); } else { pgm_exit(1,"ERROR: -s must be followed by a NUMBER! Not [$sarg]\n"); } } elsif ($sarg =~ /^e/) { need_arg(@av); shift @av; $sarg = $av[0]; if ($sarg =~ /^\d+$/) { $end_line = $sarg; prt("Set end line to [$end_line].\n") if (VERB1()); } else { pgm_exit(1,"ERROR: -e must be followed by a NUMBER! Not [$sarg]\n"); } } elsif ($sarg =~ /^m/) { need_arg(@av); shift @av; $sarg = $av[0]; if ($sarg =~ /^\d+$/) { $max_lines = $sarg; prt("Set maximum lines to [$max_lines].\n") if (VERB1()); } else { pgm_exit(1,"ERROR: -m must be followed by a NUMBER! Not [$sarg]\n"); } } elsif ($sarg =~ /^n/) { need_arg(@av); shift @av; $sarg = $av[0]; if ($sarg =~ /^\d+$/) { $node_id = $sarg; prt("Set node id to [$node_id].\n") if (VERB1()); } else { pgm_exit(1,"ERROR: -n must be followed by a NUMBER! Not [$sarg]\n"); } } elsif ($sarg =~ /^w/) { need_arg(@av); shift @av; $sarg = $av[0]; if ($sarg =~ /^\d+$/) { $way_id = $sarg; prt("Set way id to [$way_id].\n") if (VERB1()); } else { pgm_exit(1,"ERROR: -w must be followed by a NUMBER! Not [$sarg]\n"); } } else { pgm_exit(1,"ERROR: Invalid argument [$arg]! Try -?\n"); } } else { $in_file = $arg; prt("Set input to [$in_file]\n") if (VERB1()); } shift @av; } if ($debug_on) { prtw("WARNING: DEBUG is ON!\n"); if (length($in_file) == 0) { $in_file = $def_file; prt("Set DEFAULT input to [$in_file]\n"); } #if (length($node_id) == 0) { # $node_id = $def_nid; # prt("Set DEFAULT node id to [$node_id]\n"); #} if (length($way_id) == 0) { $way_id = $def_wid; prt("Set DEFAULT way id to [$way_id]\n"); } } if (length($in_file) == 0) { pgm_exit(1,"ERROR: No input files found in command!\n"); } if (! -f $in_file) { pgm_exit(1,"ERROR: Unable to find in file [$in_file]! Check name, location...\n"); } if ((length($node_id) == 0)&&(length($way_id) == 0)) { pgm_exit(1,"ERROR: No way or node id given in command!\n"); } if (length($out_file) == 0) { $out_file = $def_out; prt("Set DEFAULT out file to [$out_file]\n"); } } sub give_help { prt("$pgmname: version $VERS\n"); prt("Usage: $pgmname [options] in-file\n"); prt("Options:\n"); prt(" --help (-h or -?) = This help, and exit 0.\n"); prt(" --verb[n] (-v) = Bump [or set] verbosity. def=$verbosity\n"); prt(" --load (-l) = Load LOG at end. ($outfile)\n"); prt(" --out (-o) = Write output to this file.\n"); } # eof - template.pl