## ## The cuttlefish Visualization Tool. ## Copyright (C) 2006 The Regents of the University of California. ## ## This program is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License version 2 as published ## by the Free Software Foundation. ## ## 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, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## ## written by Bradley Huffaker ## ## documention by Joshua Polterock ## Bradley Huffaker ## Marina Fomenkova ## ## package Util; use GD; use Time::Local; require Exporter; @ISA = qw( Exporter ); @EXPORT = qw(LoadCodeRec String2Font Range2Units Range2UnitsLog CompressNumber ); @EXPORT_OK = qw(); use strict; sub LoadCodeRec { my ($filename) = @_; open (IN, "<$filename") || die("Unable to open code2rec:$filename:$!"); my %code2rec; my %cont2longlat; while () { chop; s/#.*//g; next unless (/[^\s]/); my ($code, $continent, $country, $state, $city, $lat, $long) = split /\t/; $code2rec{$code} = { "continent" => $continent, "country" => $country, "state" => $state, "city" => $city, "lat" => $lat, "long" => $long }; } close IN; return %code2rec; } my %string2font = %{{ "giant"=> gdGiantFont, "large" => gdLargeFont, "medium" => gdMediumBoldFont, "small" => gdSmallFont, "tiny" => gdTinyFont }}; sub String2Font { my ($string) = @_; return $string2font{$string}; } # # This code selects the ticks marks spacing that fits giving # font, with, min, and max. # sub Range2Units { # my ($range, $target, %value2unit) = @_; my ($hash) = @_; my $max = $hash->{max}; my $min = $hash->{min}; my $font_size = $hash->{font_size}; my $width = $hash->{width}; my $value2unit = $hash->{value2unit}; $value2unit = {} unless (defined $value2unit); my %value2unit = %$value2unit; my $compress = $hash->{"compress"}; my $side_by_side = $hash->{"side_by_side"}; my $range = $max - $min; my $unit; my $value; $range = 1 if ($range < 1); my @vals = reverse sort {$a<=>$b} keys %value2unit; if ($#vals < 0) { @vals = (1); } foreach my $index (0..$#vals) { my $val = $vals[$index]; if ($range >= 4*$val || $index == $#vals) { $value = $val; $unit = $value2unit{$value}; last; } } my $ten = 1; my @ones = (1,2,5); my $i = -1; my $last; my $current; my $range_value = int($range/$value); my $label_size = 1; if (defined $side_by_side) { $label_size = length($range_value)+1; } my $target = $font_size*$label_size; do { $i++; if ($i == $#ones+1) { $i = 0; $ten *= 10; } $last = $current; $current = $ones[$i]*$ten; $last = $current unless (defined $last); } while ($range_value > $current && $width*($current/$range_value) <= $target); $current = $range_value if ($current > $range_value); my $scaler = $current; my $total = 0; my @key_values; my $max_length = 0; do { my $val = $value*$total; push @key_values, [$total, $val]; $total += $scaler; } while ($total <= $range_value); if (defined $compress) { foreach my $index (0..$#key_values) { my $val = $key_values[$index][1] + $min; my $key = CompressNumber($val); $key_values[$index][0] = $key; $key_values[$index][1] = $val; } } my $max_length; foreach my $index (0..$#key_values) { my $key = CompressNumber($key_values[$index][0]); my $len = length($key); unless (defined $max_length) { $max_length = $len; } elsif ($len > $max_length) { $max_length = $len; } } my $label_length = (1+$font_size)*$max_length; return ($unit, $label_length, @key_values); } sub Range2UnitsLog { # my ($range, $target, %value2unit) = @_; my ($hash) = @_; my $max = $hash->{max}; my $min = $hash->{min}; my $font_size = $hash->{font_size}; my $width = $hash->{width}; my $value2unit = $hash->{value2unit}; $value2unit = {} unless (defined $value2unit); my %value2unit = %$value2unit; my $compress = $hash->{"compress"}; my $side_by_side = $hash->{"side_by_side"}; my %hash = %$hash; my $range = $max - $min; $hash{min} = 0; $hash{max} = log($range)/log(10); my ($unit, $label_length, @k_v) = Range2Units(\%hash); my @key_values; foreach my $k_v (@k_v) { my ($key, $value) = @$k_v; $value = 10**$value; foreach my $i (1..9) { my $v = $i*$value; if ($v < $max) { push @key_values, [$key, $i*$value]; } } } my $max_length; foreach my $index (0..$#key_values) { my $key = CompressNumber($key_values[$index][1]); my $len = length($key); unless (defined $max_length) { $max_length = $len; } elsif ($len > $max_length) { $max_length = $len; } } my $label_length = (1+$font_size)*$max_length; return ($unit, $label_length, @key_values); } sub CompressNumber { my ($sum) = @_; my %value2name = %{{ 10**3 => "k", 10**6 => "M", 10**9 => "G", 10**12 => "T", 10**15 => "P", 10**18 => "E", 10**21 => "Z", 10**24 => "Y" }}; ####################################### # Byte units. ####################################### #my %value2name = %{{ #2**10 => "K", #2**20 => "M", #2**30 => "G", #2**40 => "T", #2**50 => "P", #2**60 => "E", #2**70 => "Z", #2**80 => "Y" #}}; my $divider = 1; my $name; foreach my $value (reverse sort {$a<=>$b} keys %value2name) { if ($sum >= $value) { $name = $value2name{$value}; $divider = $value; last; } } my $val = $sum; if ($divider > 1) { $val = sprintf("%.2f",$sum/$divider); } $val =~ s/^(.{0,4}).*/$1/; my $val_name = $val.$name; return $val.$name; } ############################################################## # Time functions. ############################################################## sub Time2DatePretty { my ($time) = @_; my ($sec, $min, $hour, $day, $mon, $year, $wday) = gmtime($time); $mon++; $year += 1900; foreach my $value ($sec,$min,$hour,$day,$mon) { $value = "0".$value if ($value < 10); } my @days = qw(min tue wed thr fri sat sun); return "$year/$mon/$day $hour:$min:$sec ".$days[$wday]." GMT"; } sub Time2Date { my ($time) = @_; my ($sec, $min, $hour, $day, $mon, $year) = localtime($time); $day = "0".$day if ($day < 10); $mon++; $mon = "0".$mon if ($mon < 10); $year += 1900; return "$year$mon$day"; } sub Date2Time { my ($year, $mon, $day) = @_; if ($year =~ /^(\d{4})(\d\d)(\d\d)$/) { ($year, $mon, $day) = ($1, $2, $3); } my ($hour, $min, $sec) = ( 0,0,0 ); # return Time::Local::timegm($sec,$min,$hour,$day,$mon-1,$year); return Time::Local::timelocal($sec,$min,$hour,$day,$mon-1,$year); } 1;