#!/usr/bin/perl # # Produces Partiview files for an map of a large network (e.g. internet, grid, planetlab) # superimposed on the earth. # # perl earthgraph.pl RADIUS NODEFILE idindex latindex longindex labindex [EDGEFILE idindex1 idindex2 colorindex weightindex] # # RADIUS is the radius of the sphere of earth on which you are superimposing the network graph. # File formats: # nodefile can have several columns, which must include (first index is 1) # idindex : column where unique node id is # latindex : column with node's latitude # longindex : column with node's longitude # labindex : column with node's label (can be same as idindex - and if no label wanted, just say 0 at command line) # edgefile can have several columns, which has these columns: # idindex1 : column with unique node id of one end of the edge # idindex2 : column with unique node id of the other end of the edge # colorindex : column with some feature to be used for weight # weightindex : column with some feature to be used for weight # # e.g. perl earthgraph.pl 24.5 nodes.txt 2 3 4 2 all.to.all.1s 1 2 4 3 # e.g. perl earthgraph.pl 24.5 nodes.txt 1 3 4 2 128.app.links.txt (you dont have to put 1 2 3 4 at the end) # # Makes the height of the lines proportional to bandwidth # # Dinoj Surendran dinoj@cs.uchicago.edu 08/04/04 $radius = $ARGV[0]; $nodefile = $ARGV[1]; @tmp = split /[\.]+/, $nodefile; $outfile = $tmp[0]; $outfile =~ s/\.speck//g; $idindex = $ARGV[2]; $latindex = $ARGV[3]; $longindex = $ARGV[4]; $labindex = $ARGV[5]; $hasedges = 0; $id1index=1; $id2index=2; $colorindex=3; $weightindex=4; open (NODES, "$nodefile"); if ($#ARGV >= 6) { $hasedges = 1; $edgefile = $ARGV[6]; if ($#ARGV>=7) { $id1index = $ARGV[7];} if ($#ARGV>=8) { $id2index = $ARGV[8];} if ($#ARGV>=9) { $colorindex = $ARGV[9];} if ($#ARGV>=10){ $widthindex = $ARGV[10];} } $NUMWIDTHS = 20; $NUMCOLORS = 10; if ($hasedges == 1) { @tmp = split /[\.]+/, $edgefile; $outfile = $outfile."_".$tmp[0]; } open (OUTNODES,">".$outfile.".speck"); print OUTNODES "datavar 0 txnum\ntexturevar txnum\ntexture -M 1 halo.sgi\n"; open (OUTLABEL,">".$outfile.".label"); if (1 == $hasedges) { open (OUTEDGES,">".$outfile."_edges.speck"); } my %nodex, %nodey, %nodez; while ($line = ) { @tmp = split /[\n\t\ ]+/, $line; $start=0; while (($start <= $#tmp) & (length($tmp[$start])==0)) {$start++;} $id = $tmp[$start+$idindex-1]; # rem perl indexing start at 0, not 1 $id =~ s/\ //g; $label = $tmp[$start+$labindex-1]; $lat = $tmp[$start+$latindex-1]; $long = $tmp[$start+$longindex-1]; $lat = 3.141592/180.0 * $lat; $long = 3.141592/180.0 * $long; $x = -$radius*cos($lat)*cos($long); $y = $radius*sin($lat); $z = $radius*cos($lat)*sin($long); $nodex{$id} = $x; $nodey{$id} = $y; $nodez{$id} = $z; # print "(1)$id (2)$lat (3)$long $x $y $z\n"; printf OUTNODES ("%0.10f %0.10f %0.10f 1 # $label \n", $x, $y, $z); printf OUTLABEL ("%0.10f %0.10f %0.10f text $label\n", $x, $y, $z); } if (1 == $hasedges) { my @colors; open (EDGES, "$edgefile"); open (EDGECOLORS, ">colors_$edgefile.dat"); my $maxcolor = -1e20; my $mincolor = 1e20; my $maxwidth = -1e20; my $minwidth = 1e20; while ($line = ) { @tmp = split /[\n\t\ ]+/, $line; $start=0; while (($start <= $#tmp) & (length($tmp[$start])==0)) {$start++;} $color = $tmp[$start+$colorindex-1]; if ($color > $maxcolor) {$maxcolor = $color;} if ($color < $mincolor) {$mincolor = $color;} print EDGECOLORS "$color\n"; $width = $tmp[$start+$widthindex-1]; if ($width > $maxwidth) {$maxwidth = $width;} if ($width < $minwidth) {$minwidth = $width;} } print "mincolor = $mincolor, maxcolor = $maxcolor\n"; print "minwidth = $minwidth, maxwidth = $maxwidth\n"; close (EDGES); open (EDGES, "$edgefile"); while ($line = ) { @tmp = split /[\n\t\ ]+/, $line; $start=0; while (($start <= $#tmp) & (length($tmp[$start])==0)) {$start++;} $id1 = $tmp[$start+$id1index-1]; # rem perl indexing start at 0, not 1 $id2 = $tmp[$start+$id2index-1]; $color = $tmp[$start+$colorindex-1]; $width = $tmp[$start+$widthindex-1]; $id1 =~ s/[\ ]+//g; $id2 =~ s/[\ ]+//g; if ((exists $nodex{$id1}) & (exists $nodex{$id2})) { $x1 = $nodex{$id1}; $y1 = $nodey{$id1}; $z1 = $nodez{$id1}; $x2 = $nodex{$id2}; $y2 = $nodey{$id2}; $z2 = $nodez{$id2}; $color_discretized = 1 + 1.0 * $NUMCOLORS * ($color - $mincolor) / ($maxcolor - $mincolor); $highest_point = $radius * (1+ (($width - $minwidth) / ($maxwidth - $minwidth))); # highest point of this link $edgelength = sqrt ( ($x1-$x2)^2 + ($y1-$y2)^2 + ($z1-$z2)^2 ); if ($edgelength < ($radius / 50)) { for ($j=0; $j<=$width_discretized; $j++) { printf OUTEDGES " mesh -c %d -s wire {\n1 2\n $x1 $y1 $z1\n $x2 $y2 $z2\n}\n", $color_discretized; } } else { $tstep = 0.02; for ($t = 0; $t < 1-$tstep; $t = $t+$tstep) { $radius_eventual = $radius + ($highest_point-$radius)*2*min($t,1-$t); # how high you're going to be now # print "$t\n"; $a1 = $x1 + $t*($x2-$x1); $b1 = $y1 + $t*($y2-$y1); $c1 = $z1 + $t*($z2-$z1); $radius_chord = sqrt ($a1*$a1 + $b1*$b1 + $c1*$c1); # distance of this point from center of earth, if a straight line chord was drawn between the point's start and end $a1 = $a1 * $radius_eventual/ $radius_chord; $b1 = $b1 * $radius_eventual/ $radius_chord; $c1 = $c1 * $radius_eventual/ $radius_chord; $a2 = $x1 + ($t+$tstep)*($x2-$x1); $b2 = $y1 + ($t+$tstep)*($y2-$y1); $c2 = $z1 + ($t+$tstep)*($z2-$z1); $radius_chord = sqrt ($a2*$a2 + $b2*$b2 + $c2*$c2); $radius_eventual = $radius + ($highest_point-$radius)*2*min($t+$tstep,1-$t-$tstep); # how high you're going to be now $a2 = $a2 * $radius_eventual/ $radius_chord; $b2 = $b2 * $radius_eventual/ $radius_chord; $c2 = $c2 * $radius_eventual/ $radius_chord; for ($j=0; $j<=3; $j++) # draw each edges thrice to make it more visible { printf OUTEDGES " mesh -c %d -s wire {\n1 2\n ", $color_discretized; printf OUTEDGES " %0.10f %0.10f %0.10f \n", $a1, $b1, $c1; printf OUTEDGES " %0.10f %0.10f %0.10f \n", $a2, $b2, $c2; printf OUTEDGES "}\n"; } } } } @colors[1+$#colors] = $color; } } sub min { my ($a,$b) = @_; if ($a<$b) {return $a;} return $b; }