![]() ![]() |
weathermap |
Subversion Repositories: |
Compare with Previous - Blame - Download
<?php// PHP Weathermap 0.97a// Copyright Howard Jones, 2005-2010 howie@thingy.com// http://www.network-weathermap.com/// Released under the GNU Public License// Utility functions// Check for GD & PNG support This is just in here so that both the editor and CLI can use it without the need for another filefunction module_checks(){if (!extension_loaded('gd')){warn ("\n\nNo image (gd) extension is loaded. This is required by weathermap. [WMWARN20]\n\n");warn ("\nrun check.php to check PHP requirements.\n\n");return (FALSE);}if (!function_exists('imagecreatefrompng')){warn ("Your GD php module doesn't support PNG format. [WMWARN21]\n");warn ("\nrun check.php to check PHP requirements.\n\n");return (FALSE);}if (!function_exists('imagecreatetruecolor')){warn ("Your GD php module doesn't support truecolor. [WMWARN22]\n");warn ("\nrun check.php to check PHP requirements.\n\n");return (FALSE);}if (!function_exists('imagecopyresampled')){warn ("Your GD php module doesn't support thumbnail creation (imagecopyresampled). [WMWARN23]\n");}return (TRUE);}function debug($string){global $weathermap_debugging;global $weathermap_map;global $weathermap_debug_suppress;if ($weathermap_debugging){$calling_fn = "";if(function_exists("debug_backtrace")){$bt = debug_backtrace();$index = 1;# $class = (isset($bt[$index]['class']) ? $bt[$index]['class'] : '');$function = (isset($bt[$index]['function']) ? $bt[$index]['function'] : '');$index = 0;$file = (isset($bt[$index]['file']) ? basename($bt[$index]['file']) : '');$line = (isset($bt[$index]['line']) ? $bt[$index]['line'] : '');$calling_fn = " [$function@$file:$line]";if(is_array($weathermap_debug_suppress) && in_array(strtolower($function),$weathermap_debug_suppress)) return;}// use Cacti's debug log, if we are running from the pollerif (function_exists('debug_log_insert') && (!function_exists('show_editor_startpage'))){ cacti_log("DEBUG:$calling_fn " . ($weathermap_map==''?'':$weathermap_map.": ") . rtrim($string), true, "WEATHERMAP"); }else{$stderr=fopen('php://stderr', 'w');fwrite($stderr, "DEBUG:$calling_fn " . ($weathermap_map==''?'':$weathermap_map.": ") . $string);fclose ($stderr);// mostly this is overkill, but it's sometimes useful (mainly in the editor)if(1==0){$log=fopen('debug.log', 'a');fwrite($log, "DEBUG:$calling_fn " . ($weathermap_map==''?'':$weathermap_map.": ") . $string);fclose ($log);}}}}function warn($string,$notice_only=FALSE){global $weathermap_map;global $weathermap_warncount;$message = "";if(!$notice_only){$weathermap_warncount++;$message .= "WARNING: ";}$message .= ($weathermap_map==''?'':$weathermap_map.": ") . rtrim($string);// use Cacti's debug log, if we are running from the pollerif (function_exists('cacti_log') && (!function_exists('show_editor_startpage'))){ cacti_log($message, true, "WEATHERMAP"); }else{$stderr=fopen('php://stderr', 'w');fwrite($stderr, $message."\n");fclose ($stderr);}}function js_escape($str, $wrap=TRUE){$str=str_replace('\\', '\\\\', $str);$str=str_replace('"', '\\"', $str);if($wrap) $str='"' . $str . '"';return ($str);}function mysprintf($format,$value,$kilo=1000){$output = "";debug("mysprintf: $format $value\n");if(preg_match("/%(\d*\.?\d*)k/",$format,$matches)){$spec = $matches[1];$places = 2;if($spec !=''){preg_match("/(\d*)\.?(\d*)/",$spec,$matches);if($matches[2] != '') $places=$matches[2];// we don't really need the justification (pre-.) part...}debug("KMGT formatting $value with $spec.\n");$result = nice_scalar($value, $kilo, $places);$output = preg_replace("/%".$spec."k/",$format,$result);}else{debug("Falling through to standard sprintf\n");$output = sprintf($format,$value);}return $output;}// ParseString is based on code from:// http://www.webscriptexpert.com/Php/Space-Separated%20Tag%20Parser/function ParseString($input){$output = array(); // Array of Output$cPhraseQuote = null; // Record of the quote that opened the current phrase$sPhrase = null; // Temp storage for the current phrase we are building// Define some constants$sTokens = " \t"; // Space, Tab$sQuotes = "'\""; // Single and Double Quotes// Start the State Machinedo{// Get the next token, which may be the first$sToken = isset($sToken)? strtok($sTokens) : strtok($input, $sTokens);// Are there more tokens?if ($sToken === false){// Ensure that the last phrase is marked as ended$cPhraseQuote = null;}else{// Are we within a phrase or not?if ($cPhraseQuote !== null){// Will the current token end the phrase?if (substr($sToken, -1, 1) === $cPhraseQuote){// Trim the last character and add to the current phrase, with a single leading space if necessaryif (strlen($sToken) > 1) $sPhrase .= ((strlen($sPhrase) > 0)? ' ' : null) . substr($sToken, 0, -1);$cPhraseQuote = null;}else{// If not, add the token to the phrase, with a single leading space if necessary$sPhrase .= ((strlen($sPhrase) > 0)? ' ' : null) . $sToken;}}else{// Will the current token start a phrase?if (strpos($sQuotes, $sToken[0]) !== false){// Will the current token end the phrase?if ((strlen($sToken) > 1) && ($sToken[0] === substr($sToken, -1, 1))){// The current token begins AND ends the phrase, trim the quotes$sPhrase = substr($sToken, 1, -1);}else{// Remove the leading quote$sPhrase = substr($sToken, 1);$cPhraseQuote = $sToken[0];}}else$sPhrase = $sToken;}}// If, at this point, we are not within a phrase, the prepared phrase is complete and can be added to the arrayif (($cPhraseQuote === null) && ($sPhrase != null)){$output[] = $sPhrase;$sPhrase = null;}}while ($sToken !== false); // Stop when we receive FALSE from strtok()return $output;}// wrapper around imagecolorallocate to try and re-use palette slots where possiblefunction myimagecolorallocate($image, $red, $green, $blue){// it's possible that we're being called early - just return straight away, in that caseif(!isset($image)) return(-1);$existing=imagecolorexact($image, $red, $green, $blue);if ($existing > -1)return $existing;return (imagecolorallocate($image, $red, $green, $blue));}function screenshotify($input){$tmp = $input;$tmp = preg_replace("/\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/","127.0.0.1",$tmp);$tmp = preg_replace("/([A-Za-z]{3,})/e","str_repeat('x',strlen('\\1'))",$tmp);return($tmp);}function render_colour($col){if (($col[0] == -1) && ($col[1] == -1) && ($col[1] == -1)) { return 'none'; }else if (($col[0] == -2) && ($col[1] == -2) && ($col[1] == -2)) { return 'copy'; }else if (($col[0] == -3) && ($col[1] == -3) && ($col[1] == -3)) { return 'contrast'; }else { return sprintf("%d %d %d", $col[0], $col[1], $col[2]); }}// take the same set of points that imagepolygon does, but don't close the shapefunction imagepolyline($image, $points, $npoints, $color){for ($i=0; $i < ($npoints - 1); $i++){imageline($image, $points[$i * 2], $points[$i * 2 + 1], $points[$i * 2 + 2], $points[$i * 2 + 3],$color);}}// draw a filled round-cornered rectanglefunction imagefilledroundedrectangle($image , $x1 , $y1 , $x2 , $y2 , $radius, $color){imagefilledrectangle($image, $x1,$y1+$radius, $x2,$y2-$radius, $color);imagefilledrectangle($image, $x1+$radius,$y1, $x2-$radius,$y2, $color);imagefilledarc($image, $x1+$radius, $y1+$radius, $radius*2, $radius*2, 0, 360, $color, IMG_ARC_PIE);imagefilledarc($image, $x2-$radius, $y1+$radius, $radius*2, $radius*2, 0, 360, $color, IMG_ARC_PIE);imagefilledarc($image, $x1+$radius, $y2-$radius, $radius*2, $radius*2, 0, 360, $color, IMG_ARC_PIE);imagefilledarc($image, $x2-$radius, $y2-$radius, $radius*2, $radius*2, 0, 360, $color, IMG_ARC_PIE);# bool imagefilledarc ( resource $image , int $cx , int $cy , int $width , int $height , int $start , int $end , int $color , int $style )}// draw a round-cornered rectanglefunction imageroundedrectangle( $image , $x1 , $y1 , $x2 , $y2 , $radius, $color ){imageline($image, $x1+$radius, $y1, $x2-$radius, $y1, $color);imageline($image, $x1+$radius, $y2, $x2-$radius, $y2, $color);imageline($image, $x1, $y1+$radius, $x1, $y2-$radius, $color);imageline($image, $x2, $y1+$radius, $x2, $y2-$radius, $color);imagearc($image, $x1+$radius, $y1+$radius, $radius*2, $radius*2, 180, 270, $color);imagearc($image, $x2-$radius, $y1+$radius, $radius*2, $radius*2, 270, 360, $color);imagearc($image, $x1+$radius, $y2-$radius, $radius*2, $radius*2, 90, 180, $color);imagearc($image, $x2-$radius, $y2-$radius, $radius*2, $radius*2, 0, 90, $color);}function imagecreatefromfile($filename){$bgimage=NULL;$formats = imagetypes();if (is_readable($filename)){list($width, $height, $type, $attr) = getimagesize($filename);switch($type){case IMAGETYPE_GIF:if(imagetypes() & IMG_GIF){$bgimage=imagecreatefromgif($filename);}else{warn("Image file $filename is GIF, but GIF is not supported by your GD library. [WMIMG01]\n");}break;case IMAGETYPE_JPEG:if(imagetypes() & IMG_JPEG){$bgimage=imagecreatefromjpeg($filename);}else{warn("Image file $filename is JPEG, but JPEG is not supported by your GD library. [WMIMG02]\n");}break;case IMAGETYPE_PNG:if(imagetypes() & IMG_PNG){$bgimage=imagecreatefrompng($filename);}else{warn("Image file $filename is PNG, but PNG is not supported by your GD library. [WMIMG03]\n");}break;default:warn("Image file $filename wasn't recognised (type=$type). Check format is supported by your GD library. [WMIMG04]\n");break;}}else{warn("Image file $filename is unreadable. Check permissions. [WMIMG05]\n");}return $bgimage;}// taken from here:// http://www.php.net/manual/en/function.imagefilter.php#62395// ( with some bugfixes and changes)//// Much nicer colorization than imagefilter does, AND no special requirements.// Preserves white, black and transparency.//function imagecolorize($im, $r, $g, $b){//We will create a monochromatic palette based on//the input color//which will go from black to white//Input color luminosity: this is equivalent to the//position of the input color in the monochromatic//palette$lum_inp = round(255 * ($r + $g + $b) / 765); //765=255*3//We fill the palette entry with the input color at its//corresponding position$pal[$lum_inp]['r'] = $r;$pal[$lum_inp]['g'] = $g;$pal[$lum_inp]['b'] = $b;//Now we complete the palette, first we'll do it to//the black,and then to the white.//FROM input to black//===================//how many colors between black and input$steps_to_black = $lum_inp;//The step size for each componentif ($steps_to_black){$step_size_red = $r / $steps_to_black;$step_size_green = $g / $steps_to_black;$step_size_blue = $b / $steps_to_black;}for ($i = $steps_to_black; $i >= 0; $i--){$pal[$steps_to_black - $i]['r'] = $r - round($step_size_red * $i);$pal[$steps_to_black - $i]['g'] = $g - round($step_size_green * $i);$pal[$steps_to_black - $i]['b'] = $b - round($step_size_blue * $i);}//From input to white://===================//how many colors between input and white$steps_to_white = 255 - $lum_inp;if ($steps_to_white){$step_size_red = (255 - $r) / $steps_to_white;$step_size_green = (255 - $g) / $steps_to_white;$step_size_blue = (255 - $b) / $steps_to_white;}else$step_size_red = $step_size_green = $step_size_blue = 0;//The step size for each componentfor ($i = ($lum_inp + 1); $i <= 255; $i++){$pal[$i]['r'] = $r + round($step_size_red * ($i - $lum_inp));$pal[$i]['g'] = $g + round($step_size_green * ($i - $lum_inp));$pal[$i]['b'] = $b + round($step_size_blue * ($i - $lum_inp));}//--- End of palette creation//Now,let's change the original palette into the one we//createdfor ($c = 0; $c < imagecolorstotal($im); $c++){$col = imagecolorsforindex($im, $c);$lum_src = round(255 * ($col['red'] + $col['green'] + $col['blue']) / 765);$col_out = $pal[$lum_src];# printf("%d (%d,%d,%d) -> %d -> (%d,%d,%d)\n", $c,# $col['red'], $col['green'], $col['blue'],# $lum_src,# $col_out['r'], $col_out['g'], $col_out['b']# );imagecolorset($im, $c, $col_out['r'], $col_out['g'], $col_out['b']);}return($im);}// find the point where a line from x1,y1 through x2,y2 crosses another line through x3,y3 and x4,y4// (the point might not be between those points, but beyond them)// - doesn't handle parallel lines. In our case we will never get them.// - make sure we remove colinear points, or this will not be true!function line_crossing($x1,$y1,$x2,$y2, $x3,$y3,$x4,$y4){// First, check that the slope isn't infinite.// if it is, tweak it to be merely hugeif($x1 != $x2) { $slope1 = ($y2-$y1)/($x2-$x1); }else { $slope1 = 1e10; debug("Slope1 is infinite.\n");}if($x3 != $x4) { $slope2 = ($y4-$y3)/($x4-$x3); }else { $slope2 = 1e10; debug("Slope2 is infinite.\n");}$a1 = $slope1;$a2 = $slope2;$b1 = -1;$b2 = -1;$c1 = ($y1 - $slope1 * $x1 );$c2 = ($y3 - $slope2 * $x3 );$det_inv = 1/($a1*$b2 - $a2*$b1);$xi = (($b1*$c2 - $b2*$c1)*$det_inv);$yi = (($a2*$c1 - $a1*$c2)*$det_inv);return(array($xi,$yi));}// rotate a list of points around cx,cy by an angle in radians, IN PLACEfunction RotateAboutPoint(&$points, $cx,$cy, $angle=0){$npoints = count($points)/2;for($i=0;$i<$npoints;$i++){$ox = $points[$i*2] - $cx;$oy = $points[$i*2+1] - $cy;$rx = $ox * cos($angle) - $oy*sin($angle);$ry = $oy * cos($angle) + $ox*sin($angle);$points[$i*2] = $rx + $cx;$points[$i*2+1] = $ry + $cy;}}// calculate the points for a span of the curve. We pass in the distance so far, and the array index, so that// the chunk of array generated by this function can be array_merged with existing points from before.// Considering how many array functions there are, PHP has horrible list support// Each point is a 3-tuple - x,y,distance - which is used later to figure out where the 25%, 50% marks are on the curvefunction calculate_catmull_rom_span($startn, $startdistance, $numsteps, $x0, $y0, $x1, $y1, $x2, $y2, $x3, $y3){$Ap_x=-$x0 + 3 * $x1 - 3 * $x2 + $x3;$Bp_x=2 * $x0 - 5 * $x1 + 4 * $x2 - $x3;$Cp_x=-$x0 + $x2;$Dp_x=2 * $x1;$Ap_y=-$y0 + 3 * $y1 - 3 * $y2 + $y3;$Bp_y=2 * $y0 - 5 * $y1 + 4 * $y2 - $y3;$Cp_y=-$y0 + $y2;$Dp_y=2 * $y1;$d=2;$n=$startn;$distance=$startdistance;$lx=$x0;$ly=$y0;$allpoints[]=array($x0,$y0,$distance);for ($i=0; $i <= $numsteps; $i++){$t=$i / $numsteps;$t2=$t * $t;$t3=$t2 * $t;$x=(($Ap_x * $t3) + ($Bp_x * $t2) + ($Cp_x * $t) + $Dp_x) / $d;$y=(($Ap_y * $t3) + ($Bp_y * $t2) + ($Cp_y * $t) + $Dp_y) / $d;if ($i > 0){$step=sqrt((($x - $lx) * ($x - $lx)) + (($y - $ly) * ($y - $ly)));$distance=$distance + $step;$allpoints[$n]=array($x,$y,$distance);$n++;}$lx=$x;$ly=$y;}return array($allpoints, $distance, $n);}function find_distance_coords(&$pointarray,$distance){// We find the nearest lower point for each distance,// then linearly interpolate to get a more accurate point// this saves having quite so many points-per-curve$index=find_distance($pointarray, $distance);$ratio=($distance - $pointarray[$index][2]) / ($pointarray[$index + 1][2] - $pointarray[$index][2]);$x = $pointarray[$index][0] + $ratio * ($pointarray[$index + 1][0] - $pointarray[$index][0]);$y = $pointarray[$index][1] + $ratio * ($pointarray[$index + 1][1] - $pointarray[$index][1]);return(array($x,$y,$index));}function find_distance_coords_angle(&$pointarray,$distance){// This is the point we needlist($x,$y,$index) = find_distance_coords($pointarray,$distance);// now to find one either side of it, to get a line to find the angle of$left = $index;$right = $left+1;$max = count($pointarray)-1;// if we're right up against the last point, then step backwards oneif($right>=$max){$left--;$right--;}# if($left<=0) { $left = 0; }$x1 = $pointarray[$left][0];$y1 = $pointarray[$left][1];$x2 = $pointarray[$right][0];$y2 = $pointarray[$right][1];$dx = $x2 - $x1;$dy = $y2 - $y1;$angle = rad2deg(atan2(-$dy,$dx));return(array($x,$y,$index,$angle));}// return the index of the point either at (unlikely) or just before the target distance// we will linearly interpolate afterwards to get a true point - pointarray is an array of 3-tuples produced by the function abovefunction find_distance(&$pointarray, $distance){$left=0;$right=count($pointarray) - 1;if ($left == $right)return ($left);// if the distance is zero, there's no need to search (and it doesn't work anyway)if($distance==0) return($left);// if it's a point past the end of the line, then just return the end of the line// Weathermap should *never* ask for this, anywayif ($pointarray[$right][2] < $distance) { return ($right); }// if somehow we have a 0-length curve, then don't try and search, just give up// in a somewhat predictable mannerif ($pointarray[$left][2] == $pointarray[$right][2]) { return ($left); }while ($left <= $right){$mid=floor(($left + $right) / 2);if (($pointarray[$mid][2] < $distance) && ($pointarray[$mid + 1][2] >= $distance)) { return $mid; }if ($distance <= $pointarray[$mid][2]) { $right=$mid - 1; }else { $left=$mid + 1; }}print "FELL THROUGH\n";die ("Howie's crappy binary search is wrong after all.\n");}// Give a list of key points, calculate a curve through them// return value is an array of triples (x,y,distance)function calc_curve(&$in_xarray, &$in_yarray,$pointsperspan = 32){// search through the point list, for consecutive duplicate points// (most common case will be a straight link with both NODEs at the same place, I think)// strip those out, because they'll break the binary search/centre-point stuff$last_x=NULL;$last_y=NULL;for ($i=0; $i < count($in_xarray); $i++){if (($in_xarray[$i] == $last_x) && ($in_yarray[$i] == $last_y)) { debug("Dumping useless duplicate point on curve\n"); }else{$xarray[]=$in_xarray[$i];$yarray[]=$in_yarray[$i];}$last_x=$in_xarray[$i];$last_y=$in_yarray[$i];}// only proceed if we still have at least two points!if(count($xarray) <= 1){warn ("Arrow not drawn, as it's 1-dimensional.\n");return (array(NULL, NULL, NULL, NULL));}// duplicate the first and last points, so that all points are drawn// (C-R normally would draw from x[1] to x[n-1]array_unshift($xarray, $xarray[0]);array_unshift($yarray, $yarray[0]);$x=array_pop($xarray);$y=array_pop($yarray);array_push($xarray, $x);array_push($xarray, $x);array_push($yarray, $y);array_push($yarray, $y);$npoints=count($xarray);$curvepoints=array();// add in the very first point manually (the calc function skips this one to avoid duplicates, which mess up the distance stuff)$curvepoints[]=array($xarray[0],$yarray[0],0);$np=0;$distance=0;for ($i=0; $i < ($npoints - 3); $i++){list($newpoints,$distance,$np)=calculate_catmull_rom_span($np, $distance, $pointsperspan, $xarray[$i],$yarray[$i], $xarray[$i + 1], $yarray[$i + 1], $xarray[$i + 2],$yarray[$i + 2], $xarray[$i + 3], $yarray[$i + 3]);$curvepoints=$curvepoints + $newpoints;}return ($curvepoints);}// Give a list of key points, calculate a "curve" through them// return value is an array of triples (x,y,distance)// this is here to mirror the real 'curve' version when we're using angled VIAs// it means that all the stuff that expects an array of points with distances won't be upset.function calc_straight(&$in_xarray, &$in_yarray,$pointsperspan = 12){// search through the point list, for consecutive duplicate points// (most common case will be a straight link with both NODEs at the same place, I think)// strip those out, because they'll break the binary search/centre-point stuff$last_x=NULL;$last_y=NULL;for ($i=0; $i < count($in_xarray); $i++){if (($in_xarray[$i] == $last_x) && ($in_yarray[$i] == $last_y)) { debug("Dumping useless duplicate point on curve\n"); }else{$xarray[]=$in_xarray[$i];$yarray[]=$in_yarray[$i];}$last_x=$in_xarray[$i];$last_y=$in_yarray[$i];}// only proceed if we still have at least two points!if(count($xarray) <= 1){warn ("Arrow not drawn, as it's 1-dimensional.\n");return (array(NULL, NULL, NULL, NULL));}$npoints=count($xarray);$curvepoints=array();$np=0;$distance=0;for ($i=0; $i < ($npoints -1); $i++){// still subdivide the straight line, becuase other stuff makes assumptions about// how often there is a point - at least find_distance_coords_angle breaks$newdistance = sqrt( pow($xarray[$i+1] - $xarray[$i],2) + pow($yarray[$i+1] - $yarray[$i],2) );$dx = ($xarray[$i+1] - $xarray[$i])/$pointsperspan;$dy = ($yarray[$i+1] - $yarray[$i])/$pointsperspan;$dd = $newdistance/$pointsperspan;for($j=0; $j< $pointsperspan; $j++){$x = $xarray[$i]+$j*$dx;$y = $yarray[$i]+$j*$dy;$d = $distance + $j*$dd;$curvepoints[] = array($x,$y,$d);$np++;}$distance += $newdistance;}$curvepoints[] = array($xarray[$npoints-1],$yarray[$npoints-1],$distance);# print_r($curvepoints);return ($curvepoints);}function calc_arrowsize($width,&$map,$linkname){$arrowlengthfactor=4;$arrowwidthfactor=2;// this is so I can use it in some test code - sorry!if($map !== NULL){if ($map->links[$linkname]->arrowstyle == 'compact'){$arrowlengthfactor=1;$arrowwidthfactor=1;}if (preg_match('/(\d+) (\d+)/', $map->links[$linkname]->arrowstyle, $matches)){$arrowlengthfactor=$matches[1];$arrowwidthfactor=$matches[2];}}$arrowsize = $width * $arrowlengthfactor;$arrowwidth = $width * $arrowwidthfactor;return( array($arrowsize,$arrowwidth) );}function draw_straight($image, &$curvepoints, $widths, $outlinecolour, $fillcolours, $linkname, &$map,$q2_percent=50, $unidirectional=FALSE){$totaldistance = $curvepoints[count($curvepoints)-1][DISTANCE];if($unidirectional){$halfway = $totaldistance;$dirs = array(OUT);$q2_percent = 100;$halfway = $totaldistance * ($q2_percent/100);list($halfway_x,$halfway_y,$halfwayindex) = find_distance_coords($curvepoints,$halfway);$spine[OUT] = $curvepoints;}else{// we'll split the spine in half here.# $q2_percent = 50;$halfway = $totaldistance * ($q2_percent/100);$dirs = array(OUT,IN);# $dirs = array(IN);list($halfway_x,$halfway_y,$halfwayindex) = find_distance_coords($curvepoints,$halfway);# print "Midpoint is: $totaldistance $halfway $halfwayindex $halfway_x,$halfway_y\n";$spine[OUT] = array();$spine[IN] = array();$npoints = count($curvepoints)-1;for($i=0; $i<=$halfwayindex; $i++){$spine[OUT] []= $curvepoints[$i];}// finally, add the actual midpoint$spine[OUT] []= array($halfway_x,$halfway_y, $halfway);// and then from the end to the middle for the other arrowfor($i=$npoints; $i>$halfwayindex; $i--){// copy the original spine, but reversing the distance calculation$spine[IN] []= array($curvepoints[$i][X], $curvepoints[$i][Y], $totaldistance - $curvepoints[$i][DISTANCE]);}// finally, add the actual midpoint$spine[IN] []= array($halfway_x,$halfway_y, $totaldistance - $halfway);}# wm_draw_marker_box($image,$map->selected, $halfway_x, $halfway_y );// now we have two seperate spines, with distances, so that the arrowhead is the end of each.// (or one, if it's unidir)// so we can loop along the spine for each one as a seperate entity// we calculate the arrow size up here, so that we can decide on the// minimum length for a link. The arrowheads are the limiting factor.list( $arrowsize[IN], $arrowwidth[IN] ) = calc_arrowsize( $widths[IN], $map, $linkname );list( $arrowsize[OUT], $arrowwidth[OUT] ) = calc_arrowsize( $widths[OUT], $map, $linkname );// the 1.2 here is empirical. It ought to be 1 in theory.// in practice, a link this short is useless anyway, especially with bwlabels.$minimumlength = 1.2*($arrowsize[IN]+$arrowsize[OUT]);foreach ($dirs as $dir){# draw_spine($image, $spine[$dir],$map->selected);#draw_spine_chain($image, $spine[$dir],$map->selected,3);#print "=================\n$linkname/$dir\n";#dump_spine($spine[$dir]);$n = count($spine[$dir]) - 1;$l = $spine[$dir][$n][DISTANCE];#print "L=$l N=$n\n";// loop increment, start point, width, labelpos, fillcolour, outlinecolour, commentpos$arrowsettings = array(+1, 0, $widths[$dir], 0, $fillcolours[$dir], $outlinecolour, 5);# print "Line is $n points to a distance of $l\n";if($l < $minimumlength){warn("Skipping too-short line.\n");}else{$arrow_d = $l - $arrowsize[$dir];# print "LENGTHS $l $arrow_d ".$arrowsize[$dir]."\n";list($pre_mid_x,$pre_mid_y,$pre_midindex) = find_distance_coords($spine[$dir], $arrow_d);# print "POS $pre_mid_x,$pre_mid_y $pre_midindex\n";$out = array_slice($spine[$dir], 0, $pre_midindex);$out []= array($pre_mid_x, $pre_mid_y, $arrow_d);# wm_draw_marker_diamond($image, $map->selected, $pre_mid_x, $pre_mid_y, 5);# imagearc($image,$pre_mid_x, $pre_mid_y ,15,15,0,360,$map->selected);# imagearc($image,$spine[$dir][$pre_midindex+1][X],$spine[$dir][$pre_midindex+1][Y],20,20,0,360,$map->selected);# imagearc($image,$spine[$dir][$pre_midindex][X],$spine[$dir][$pre_midindex][Y],20,20,0,360,$map->selected);#imagearc($image,$pre_mid_x,$pre_mid_y,20,20,0,360,$map->selected);#imagearc($image,$spine[$dir][$pre_midindex][X],$spine[$dir][$pre_midindex][Y],12,12,0,360,$map->selected);$spine[$dir] = $out;$adx=($halfway_x - $pre_mid_x);$ady=($halfway_y - $pre_mid_y);$ll=sqrt(($adx * $adx) + ($ady * $ady));$anx = $ady / $ll;$any = -$adx / $ll;$ax1 = $pre_mid_x + $widths[$dir] * $anx;$ay1 = $pre_mid_y + $widths[$dir] * $any;$ax2 = $pre_mid_x + $arrowwidth[$dir] * $anx;$ay2 = $pre_mid_y + $arrowwidth[$dir] * $any;$ax3 = $halfway_x;$ay3 = $halfway_y;$ax5 = $pre_mid_x - $widths[$dir] * $anx;$ay5 = $pre_mid_y - $widths[$dir] * $any;$ax4 = $pre_mid_x - $arrowwidth[$dir] * $anx;$ay4 = $pre_mid_y - $arrowwidth[$dir] * $any;# draw_spine($image,$spine[$dir],$map->selected);$simple = simplify_spine($spine[$dir]);$newn = count($simple);# draw_spine($image,$simple,$map->selected);# print "Simplified to $newn points\n";# if($draw_skeleton) draw_spine_chain($im,$simple,$blue, 12);# draw_spine_chain($image,$simple,$map->selected, 12);# draw_spine_chain($image,$spine[$dir],$map->selected, 10);# draw_spine_chain($image,$simple,$map->selected, 12);# draw_spine($image,$simple,$map->selected);// now do the actual drawing....$numpoints=0;$numrpoints=0;$finalpoints = array();$reversepoints = array();$finalpoints[] = $simple[0][X];$finalpoints[] = $simple[0][Y];$numpoints++;$reversepoints[] = $simple[0][X];$reversepoints[] = $simple[0][Y];$numrpoints++;// before the main loop, add in the jump out to the corners// if this is the first step, then we need to go from the middle to the outside edge first// ( the loop may not run, but these corners are required)$i = 0;$v1 = new Vector($simple[$i+1][X] - $simple[$i][X], $simple[$i+1][Y] - $simple[$i][Y]);$n1 = $v1->get_normal();$finalpoints[] = $simple[$i][X] + $n1->dx*$widths[$dir];$finalpoints[] = $simple[$i][Y] + $n1->dy*$widths[$dir];$numpoints++;$reversepoints[] = $simple[$i][X] - $n1->dx*$widths[$dir];$reversepoints[] = $simple[$i][Y] - $n1->dy*$widths[$dir];$numrpoints++;$max_start = count($simple)-2;# print "max_start is $max_start\n";for ($i=0; $i <$max_start; $i++){$v1 = new Vector($simple[$i+1][X] - $simple[$i][X], $simple[$i+1][Y] - $simple[$i][Y]);$v2 = new Vector($simple[$i+2][X] - $simple[$i+1][X], $simple[$i+2][Y] - $simple[$i+1][Y]);$n1 = $v1->get_normal();$n2 = $v2->get_normal();$capping = FALSE;// figure out the angle between the lines - for very sharp turns, we should do something special// (actually, their normals, but the angle is the same and we need the normals later)$angle = rad2deg(atan2($n2->dy,$n2->dx) - atan2($n1->dy,$n1->dx));if($angle > 180) $angle -= 360;if($angle < -180) $angle += 360;if(abs($angle)>169){$capping = TRUE;# print "Would cap. ($angle)\n";}// $capping = FALSE; // override that for now// now figure out the geometry for where the next corners arelist($xi1,$yi1) = line_crossing( $simple[$i][X] + $n1->dx * $widths[$dir], $simple[$i][Y] + $n1->dy * $widths[$dir],$simple[$i+1][X] + $n1->dx * $widths[$dir], $simple[$i+1][Y] + $n1->dy * $widths[$dir],$simple[$i+1][X] + $n2->dx * $widths[$dir], $simple[$i+1][Y] + $n2->dy * $widths[$dir],$simple[$i+2][X] + $n2->dx * $widths[$dir], $simple[$i+2][Y] + $n2->dy * $widths[$dir]);list($xi2,$yi2) = line_crossing( $simple[$i][X] - $n1->dx * $widths[$dir], $simple[$i][Y] - $n1->dy * $widths[$dir],$simple[$i+1][X] - $n1->dx * $widths[$dir], $simple[$i+1][Y] - $n1->dy * $widths[$dir],$simple[$i+1][X] - $n2->dx * $widths[$dir], $simple[$i+1][Y] - $n2->dy * $widths[$dir],$simple[$i+2][X] - $n2->dx * $widths[$dir], $simple[$i+2][Y] - $n2->dy * $widths[$dir]);if(!$capping){$finalpoints[] = $xi1;$finalpoints[] = $yi1;$numpoints++;$reversepoints[] = $xi2;$reversepoints[] = $yi2;$numrpoints++;}else{// in here, we need to decide which is the 'outside' of the corner,// because that's what we flatten. The inside of the corner is left alone.// - depending on the relative angle between the two segments, it could// be either one of these points.list($xi3,$yi3) = line_crossing( $simple[$i][X] + $n1->dx*$widths[$dir], $simple[$i][Y] + $n1->dy*$widths[$dir],$simple[$i+1][X] + $n1->dx*$widths[$dir], $simple[$i+1][Y] + $n1->dy*$widths[$dir],$simple[$i+1][X] - $n2->dx*$widths[$dir], $simple[$i+1][Y] - $n2->dy*$widths[$dir],$simple[$i+2][X] - $n2->dx*$widths[$dir], $simple[$i+2][Y] - $n2->dy*$widths[$dir]);list($xi4,$yi4) = line_crossing( $simple[$i][X] - $n1->dx*$widths[$dir], $simple[$i][Y] - $n1->dy*$widths[$dir],$simple[$i+1][X] - $n1->dx*$widths[$dir], $simple[$i+1][Y] - $n1->dy*$widths[$dir],$simple[$i+1][X] + $n2->dx*$widths[$dir], $simple[$i+1][Y] + $n2->dy*$widths[$dir],$simple[$i+2][X] + $n2->dx*$widths[$dir], $simple[$i+2][Y] + $n2->dy*$widths[$dir]);if($angle < 0){$finalpoints[] = $xi3;$finalpoints[] = $yi3;$numpoints++;$finalpoints[] = $xi4;$finalpoints[] = $yi4;$numpoints++;$reversepoints[] = $xi2;$reversepoints[] = $yi2;$numrpoints++;}else{$reversepoints[] = $xi4;$reversepoints[] = $yi4;$numrpoints++;$reversepoints[] = $xi3;$reversepoints[] = $yi3;$numrpoints++;$finalpoints[] = $xi1;$finalpoints[] = $yi1;$numpoints++;}}}// at this end, we add the arrowhead$finalpoints[] = $ax1;$finalpoints[] = $ay1;$finalpoints[] = $ax2;$finalpoints[] = $ay2;$finalpoints[] = $ax3;$finalpoints[] = $ay3;$finalpoints[] = $ax4;$finalpoints[] = $ay4;$finalpoints[] = $ax5;$finalpoints[] = $ay5;$numpoints += 5;// combine the forwards and backwards paths, to make a complete loopfor($i=($numrpoints-1)*2; $i>=0; $i-=2){$x = $reversepoints[$i];$y = $reversepoints[$i+1];$finalpoints[] = $x;$finalpoints[] = $y;$numpoints++;}// $finalpoints[] contains a complete outline of the line at this stageif (!is_null($fillcolours[$dir])){wimagefilledpolygon($image, $finalpoints, count($finalpoints) / 2, $arrowsettings[4]);}else{debug("Not drawing $linkname ($dir) fill because there is no fill colour\n");}$areaname = "LINK:L" . $map->links[$linkname]->id . ":$dir";$map->imap->addArea("Polygon", $areaname, '', $finalpoints);debug ("Adding Poly imagemap for $areaname\n");if (!is_null($outlinecolour)){wimagepolygon($image, $finalpoints, count($finalpoints) / 2, $arrowsettings[5]);}else{debug("Not drawing $linkname ($dir) outline because there is no outline colour\n");}}}}// top-level function that takes a two lists to define some points, and draws a weathermap link// - this takes care of all the extras, like arrowheads, and where to put the bandwidth labels// curvepoints is an array of the points the curve passes through// width is the link width (the actual width is twice this)// outlinecolour is a GD colour reference// fillcolours is an array of two more colour references, one for the out, and one for the in spansfunction draw_curve($image, &$curvepoints, $widths, $outlinecolour, $fillcolours, $linkname, &$map,$q2_percent=50, $unidirectional=FALSE){// now we have a 'spine' - all the central points for this curve.// time to flesh it out to the right width, and figure out where to draw arrows and bandwidth boxes...// get the full length of the curve from the last point$totaldistance = $curvepoints[count($curvepoints)-1][2];// find where the in and out arrows will join (normally halfway point)$halfway = $totaldistance * ($q2_percent/100);$dirs = array(OUT,IN);// for a unidirectional map, we just ignore the second half (direction = -1)if($unidirectional){$halfway = $totaldistance;$dirs = array(OUT);}// loop increment, start point, width, labelpos, fillcolour, outlinecolour, commentpos$arrowsettings[OUT] = array(+1, 0, $widths[OUT], 0, $fillcolours[OUT], $outlinecolour, 5);$arrowsettings[IN] = array(-1, count($curvepoints) - 1, $widths[IN], 0, $fillcolours[IN], $outlinecolour, 95);// we calculate the arrow size up here, so that we can decide on the// minimum length for a link. The arrowheads are the limiting factor.list($arrowsize[IN],$arrowwidth[IN]) = calc_arrowsize($widths[IN], $map, $linkname);list($arrowsize[OUT],$arrowwidth[OUT]) = calc_arrowsize($widths[OUT], $map, $linkname);// the 1.2 here is empirical. It ought to be 1 in theory.// in practice, a link this short is useless anyway, especially with bwlabels.$minimumlength = 1.2*($arrowsize[IN]+$arrowsize[OUT]);# warn("$linkname: Total: $totaldistance $arrowsize $arrowwidth $minimumlength\n");if($totaldistance <= $minimumlength){warn("Skipping drawing very short link ($linkname). Impossible to draw! Try changing WIDTH or ARROWSTYLE? [WMWARN01]\n");return;}list($halfway_x,$halfway_y,$halfwayindex) = find_distance_coords($curvepoints,$halfway);// loop over direction here// direction is 1.0 for the first half (forwards through the pointlist), and -1.0 for the second half (backwards from the end)// - used as a multiplier on anything that looks forwards or backwards through the listforeach ($dirs as $dir){$direction = $arrowsettings[$dir][0];// $width = $widths[$dir];// this is the last index before the arrowhead startslist($pre_mid_x,$pre_mid_y,$pre_midindex) = find_distance_coords($curvepoints,$halfway - $direction * $arrowsize[$dir]);$there_points=array();$back_points=array();$arrowpoints=array();# if ($direction < 0) { $start=count($curvepoints) - 1; }# else { $start=0; }$start = $arrowsettings[$dir][1];for ($i=$start; $i != $pre_midindex; $i+=$direction){// for each point on the spine, produce two points normal to it's direction,// each is $width away from the spine, but we build up the two lists in the opposite order,// so that when they are joined together, we get one continuous line$dx=$curvepoints[$i + $direction][0] - $curvepoints[$i][0];$dy=$curvepoints[$i + $direction][1] - $curvepoints[$i][1];$l=sqrt(($dx * $dx) + ($dy * $dy));$nx=$dy / $l;$ny=-$dx / $l;$there_points[]=$curvepoints[$i][0] + $direction * $widths[$dir] * $nx;$there_points[]=$curvepoints[$i][1] + $direction * $widths[$dir] * $ny;$back_points[]=$curvepoints[$i][0] - $direction * $widths[$dir] * $nx;$back_points[]=$curvepoints[$i][1] - $direction * $widths[$dir] * $ny;}// all the normal line is done, now lets add an arrowhead on$adx=($halfway_x - $pre_mid_x);$ady=($halfway_y - $pre_mid_y);$l=sqrt(($adx * $adx) + ($ady * $ady));$anx=$ady / $l;$any=-$adx / $l;$there_points[]=$pre_mid_x + $direction * $widths[$dir] * $anx;$there_points[]=$pre_mid_y + $direction * $widths[$dir] * $any;$there_points[]=$pre_mid_x + $direction * $arrowwidth[$dir] * $anx;$there_points[]=$pre_mid_y + $direction * $arrowwidth[$dir] * $any;$there_points[]=$halfway_x;$there_points[]=$halfway_y;$there_points[]=$pre_mid_x - $direction * $arrowwidth[$dir] * $anx;$there_points[]=$pre_mid_y - $direction * $arrowwidth[$dir] * $any;$there_points[]=$pre_mid_x - $direction * $widths[$dir] * $anx;$there_points[]=$pre_mid_y - $direction * $widths[$dir] * $any;// all points done, now combine the lists, and produce the final result.$metapts = "";$y=array_pop($back_points);$x=array_pop($back_points);do{$metapts .= " $x $y";$there_points[]=$x;$there_points[]=$y;$y=array_pop($back_points);$x=array_pop($back_points);} while (!is_null($y));$arrayindex=1;if ($direction < 0) $arrayindex=0;if (!is_null($fillcolours[$arrayindex])){wimagefilledpolygon($image, $there_points, count($there_points) / 2, $arrowsettings[$dir][4]);}else{debug("Not drawing $linkname ($dir) fill because there is no fill colour\n");}# $areaname = "LINK:" . $linkname. ":$dir";$areaname = "LINK:L" . $map->links[$linkname]->id . ":$dir";$map->imap->addArea("Polygon", $areaname, '', $there_points);debug ("Adding Poly imagemap for $areaname\n");if (!is_null($outlinecolour)){wimagepolygon($image, $there_points, count($there_points) / 2, $arrowsettings[$dir][5]);}else{debug("Not drawing $linkname ($dir) outline because there is no outline colour\n");}}}// Take a spine, and strip out all the points that are co-linear with the points either side of themfunction simplify_spine(&$input, $epsilon=1e-10){$output = array();$output []= $input[0];$n=1;$c = count($input)-2;$skip=0;for($n=1; $n<=$c; $n++){$x = $input[$n][X];$y = $input[$n][Y];// figure out the area of the triangle formed by this point, and the one before and after$a = abs($input[$n-1][X] * ( $input[$n][Y] - $input[$n+1][Y] )+ $input[$n][X] * ( $input[$n+1][Y] - $input[$n-1][Y] )+ $input[$n+1][X] * ( $input[$n-1][Y] - $input[$n][Y] ) );# print "$n $x,$y $a";if ( $a > $epsilon)// if(1==1){$output []= $input[$n];# print " KEEP";}else{// ignore n$skip++;# print " SKIP";}# print "\n";}debug("Skipped $skip points of $c\n");# print "------------------------\n";$output []= $input[$c+1];return $output;}function unformat_number($instring, $kilo = 1000){$matches=0;$number=0;if (preg_match("/([0-9\.]+)(M|G|K|T|m|u)/", $instring, $matches)){$number=floatval($matches[1]);if ($matches[2] == 'K') { $number=$number * $kilo; }if ($matches[2] == 'M') { $number=$number * $kilo * $kilo; }if ($matches[2] == 'G') { $number=$number * $kilo * $kilo * $kilo; }if ($matches[2] == 'T') { $number=$number * $kilo * $kilo * $kilo * $kilo; }// new, for absolute datastyle. Think seconds.if ($matches[2] == 'm') { $number=$number / $kilo; }if ($matches[2] == 'u') { $number=$number / ($kilo * $kilo); }}else { $number=floatval($instring); }return ($number);}// given a compass-point, and a width & height, return a tuple of the x,y offsetsfunction calc_offset($offsetstring, $width, $height){if(preg_match("/^([-+]?\d+):([-+]?\d+)$/",$offsetstring,$matches)){debug("Numeric Offset found\n");return(array($matches[1],$matches[2]));}elseif(preg_match("/(NE|SE|NW|SW|N|S|E|W|C)(\d+)?$/i",$offsetstring,$matches)){$multiply = 1;if( isset($matches[2] ) ){$multiply = intval($matches[2])/100;debug("Percentage compass offset: multiply by $multiply");}$height = $height * $multiply;$width = $width * $multiply;switch (strtoupper($matches[1])){case 'N':return (array(0, -$height / 2));break;case 'S':return (array(0, $height / 2));break;case 'E':return (array(+$width / 2, 0));break;case 'W':return (array(-$width / 2, 0));break;case 'NW':return (array(-$width / 2, -$height / 2));break;case 'NE':return (array($width / 2, -$height / 2));break;case 'SW':return (array(-$width / 2, $height / 2));break;case 'SE':return (array($width / 2, $height / 2));break;case 'C':default:return (array(0, 0));break;}}elseif( preg_match("/(-?\d+)r(\d+)$/i",$offsetstring,$matches) ){$angle = intval($matches[1]);$distance = intval($matches[2]);$x = $distance * sin(deg2rad($angle));$y = - $distance * cos(deg2rad($angle));return (array($x,$y));}else{warn("Got a position offset that didn't make sense ($offsetstring).");return (array(0, 0));}}// These next two are based on perl's Number::Format module// by William R. Ward, chopped down to just what I neededfunction format_number($number, $precision = 2, $trailing_zeroes = 0){$sign=1;if ($number < 0){$number=abs($number);$sign=-1;}$number=round($number, $precision);$integer=intval($number);if (strlen($integer) < strlen($number)) { $decimal=substr($number, strlen($integer) + 1); }if (!isset($decimal)) { $decimal=''; }$integer=$sign * $integer;if ($decimal == '') { return ($integer); }else { return ($integer . "." . $decimal); }}function nice_bandwidth($number, $kilo = 1000,$decimals=1,$below_one=TRUE){$suffix='';if ($number == 0)return '0';$mega=$kilo * $kilo;$giga=$mega * $kilo;$tera=$giga * $kilo;$milli = 1/$kilo;$micro = 1/$mega;$nano = 1/$giga;if ($number >= $tera){$number/=$tera;$suffix="T";}elseif ($number >= $giga){$number/=$giga;$suffix="G";}elseif ($number >= $mega){$number/=$mega;$suffix="M";}elseif ($number >= $kilo){$number/=$kilo;$suffix="K";}elseif ($number >= 1){$number = $number;$suffix="";}elseif (($below_one==TRUE) && ($number >= $milli)){$number/=$milli;$suffix="m";}elseif (($below_one==TRUE) && ($number >= $micro)){$number/=$micro;$suffix="u";}elseif (($below_one==TRUE) && ($number >= $nano)){$number/=$nano;$suffix="n";}$result=format_number($number, $decimals) . $suffix;return ($result);}function nice_scalar($number, $kilo = 1000, $decimals=1){$suffix = '';$prefix = '';if ($number == 0)return '0';if($number < 0){$number = -$number;$prefix = '-';}$mega=$kilo * $kilo;$giga=$mega * $kilo;$tera=$giga * $kilo;if ($number > $tera){$number/=$tera;$suffix="T";}elseif ($number > $giga){$number/=$giga;$suffix="G";}elseif ($number > $mega){$number/=$mega;$suffix="M";}elseif ($number > $kilo){$number/=$kilo;$suffix="K";}elseif ($number > 1){$number = $number;$suffix="";}elseif ($number < (1 / ($kilo))){$number=$number * $mega;$suffix="u";}elseif ($number < 1){$number=$number * $kilo;$suffix="m";}$result = $prefix . format_number($number, $decimals) . $suffix;return ($result);}// ***********************************************// we use enough points in various places to make it worth a small class to save some variable-pairs.class Point{var $x, $y;function Point($x=0,$y=0){$this->x = $x;$this->y = $y;}}// similarly for 2D vectorsclass Vector{var $dx, $dy;function Vector($dx=0,$dy=0){$this->dx = $dx;$this->dy = $dy;}function get_normal(){$len = $this->length();$nx1 = $this->dy / $len;$ny1 = -$this->dx / $len;return( new Vector($nx1, $ny1));}function normalise(){$len = $this->length();$this->dx = $this->dx/$len;$this->dy = $this->dy/$len;}function length(){return( sqrt(($this->dx)*($this->dx) + ($this->dy)*($this->dy)) );}}class Colour{var $r,$g,$b, $alpha;// take in an existing value and create a Colour object for itfunction Colour(){if(func_num_args() == 3) # a set of 3 colours{$this->r = func_get_arg(0); # r$this->g = func_get_arg(1); # g$this->b = func_get_arg(2); # b#print "3 args";#print $this->as_string()."--";}if( (func_num_args() == 1) && gettype(func_get_arg(0))=='array' ) # an array of 3 colours{#print "1 args";$ary = func_get_arg(0);$this->r = $ary[0];$this->g = $ary[1];$this->b = $ary[2];}}// Is this a transparent/none colour?function is_real(){if($this->r >= 0 && $this->g >=0 && $this->b >= 0){return true;}else{return false;}}// Is this a transparent/none colour?function is_none(){if($this->r == -1 && $this->g == -1 && $this->b == -1){return true;}else{return false;}}// Is this a contrast colour?function is_contrast(){if($this->r == -3 && $this->g == -3 && $this->b == -3){return true;}else{return false;}}// Is this a copy colour?function is_copy(){if($this->r == -2 && $this->g == -2 && $this->b == -2){return true;}else{return false;}}// allocate a colour in the appropriate image context// - things like scale colours are used in multiple images now (the scale, several nodes, the main map...)function gdallocate($image_ref){if($this->is_none()){return NULL;}else{return(myimagecolorallocate($image_ref, $this->r, $this->g, $this->b));}}// based on an idea from: http://www.bennadel.com/index.cfm?dax=blog:902.viewfunction contrast_ary(){if( (($this->r + $this->g + $this->b) > 500)|| ($this->g > 140)){return( array(0,0,0) );}else{return( array(255,255,255) );}}function contrast(){return( new Colour($this->contrast_ary() ) );}// make a printable version, for debugging// - optionally take a format string, so we can use it for other things (like WriteConfig, or hex in stylesheets)function as_string($format = "RGB(%d,%d,%d)"){return (sprintf($format, $this->r, $this->g, $this->b));}function as_config(){return $this->as_string("%d %d %d");}function as_html(){if($this->is_real()){return $this->as_string("#%02x%02x%02x");}else{return "";}}}// A series of wrapper functions around all the GD function calls// - I added these in so I could make a 'metafile' easily of all the// drawing commands for a map. I have a basic Perl-Cairo script that makes// anti-aliased maps from these, using Cairo instead of GD.function metadump($string, $truncate=FALSE){// comment this line to get a metafile for this mapreturn;if($truncate){$fd = fopen("metadump.txt","w+");}else{$fd = fopen("metadump.txt","a");}fputs($fd,$string."\n");fclose($fd);}function metacolour(&$col){return ($col['red1']." ".$col['green1']." ".$col['blue1']);}function wimagecreate($width,$height){metadump("NEWIMAGE $width $height");return(imagecreate($width,$height));}function wimagefilledrectangle( $image ,$x1, $y1, $x2, $y2, $color ){if ($color===NULL) return;$col = imagecolorsforindex($image, $color);$r = $col['red']; $g = $col['green']; $b = $col['blue']; $a = $col['alpha'];$r = $r/255; $g=$g/255; $b=$b/255; $a=(127-$a)/127;metadump("FRECT $x1 $y1 $x2 $y2 $r $g $b $a");return(imagefilledrectangle( $image ,$x1, $y1, $x2, $y2, $color ));}function wimagerectangle( $image ,$x1, $y1, $x2, $y2, $color ){if ($color===NULL) return;$col = imagecolorsforindex($image, $color);$r = $col['red']; $g = $col['green']; $b = $col['blue']; $a = $col['alpha'];$r = $r/255; $g=$g/255; $b=$b/255; $a=(127-$a)/127;metadump("RECT $x1 $y1 $x2 $y2 $r $g $b $a");return(imagerectangle( $image ,$x1, $y1, $x2, $y2, $color ));}function wimagepolygon($image, $points, $num_points, $color){if ($color===NULL) return;$col = imagecolorsforindex($image, $color);$r = $col['red']; $g = $col['green']; $b = $col['blue']; $a = $col['alpha'];$r = $r/255; $g=$g/255; $b=$b/255; $a=(127-$a)/127;$pts = "";for ($i=0; $i < $num_points; $i++){$pts .= $points[$i * 2]." ";$pts .= $points[$i * 2+1]." ";}metadump("POLY $num_points ".$pts." $r $g $b $a");return(imagepolygon($image, $points, $num_points, $color));}function wimagefilledpolygon($image, $points, $num_points, $color){if ($color===NULL) return;$col = imagecolorsforindex($image, $color);$r = $col['red']; $g = $col['green']; $b = $col['blue']; $a = $col['alpha'];$r = $r/255; $g=$g/255; $b=$b/255; $a=(127-$a)/127;$pts = "";for ($i=0; $i < $num_points; $i++){$pts .= $points[$i * 2]." ";$pts .= $points[$i * 2+1]." ";}metadump("FPOLY $num_points ".$pts." $r $g $b $a");return(imagefilledpolygon($image, $points, $num_points, $color));}function wimagecreatetruecolor($width, $height){metadump("BLANKIMAGE $width $height");return imagecreatetruecolor($width,$height);}function wimagettftext($image, $size, $angle, $x, $y, $color, $file, $string){if ($color===NULL) return;$col = imagecolorsforindex($image, $color);$r = $col['red']; $g = $col['green']; $b = $col['blue']; $a = $col['alpha'];$r = $r/255; $g=$g/255; $b=$b/255; $a=(127-$a)/127;metadump("TEXT $x $y $angle $size $file $r $g $b $a $string");return(imagettftext($image, $size, $angle, $x, $y, $color, $file, $string));}function wm_draw_marker_diamond($im, $col, $x, $y, $size=10){$points = array();$points []= $x-$size;$points []= $y;$points []= $x;$points []= $y-$size;$points []= $x+$size;$points []= $y;$points []= $x;$points []= $y+$size;$num_points = 4;imagepolygon($im, $points, $num_points, $col);}function wm_draw_marker_box($im, $col, $x, $y, $size=10){$points = array();$points []= $x-$size;$points []= $y-$size;$points []= $x+$size;$points []= $y-$size;$points []= $x+$size;$points []= $y+$size;$points []= $x-$size;$points []= $y+$size;$num_points = 4;imagepolygon($im, $points, $num_points, $col);}function wm_draw_marker_circle($im, $col, $x, $y, $size=10){imagearc($im,$x, $y ,$size,$size,0,360,$col);}function draw_spine_chain($im,$spine,$col, $size=10){$newn = count($spine);for ($i=0; $i < $newn; $i++){imagearc($im,$spine[$i][X],$spine[$i][Y],$size,$size,0,360,$col);}}function dump_spine($spine){print "===============\n";for($i=0; $i<count($spine); $i++){printf (" %3d: %d,%d (%d)\n", $i, $spine[$i][X], $spine[$i][Y], $spine[$i][DISTANCE] );}print "===============\n";}function draw_spine($im, $spine,$col){$max_i = count($spine)-1;for ($i=0; $i <$max_i; $i++){imageline($im,$spine[$i][X],$spine[$i][Y],$spine[$i+1][X],$spine[$i+1][Y],$col);}}// vim:ts=4:sw=4:?>