Blog

Draw Cube

<?php

/**
 * draw_cube
 *
 * Draw a 3d cube.
 *
 * @version 0.8
 * @author Contributors at eXorithm
 * @link /algorithm/view/draw_cube Listing at eXorithm
 * @link /algorithm/history/draw_cube History at eXorithm
 * @license /home/show/license
 *
 * @param number $image_size Size of the resulting image.
 * @param number $degree_x Degrees to rotate around the x axis.
 * @param number $degree_y Degrees to rotate around the y axis.
 * @param number $degree_z Degrees to rotate around the z axis.
 * @param number $vdist Distance to vanishing point.
 * @param number $dist Distance from origin. This number should not be less than 0 (or else you will be inside the cube!)
 * @param string $vertex_color (hex color code) Color of the vertices of the cube.
 * @param string $face_color (hex color code) Color of the face of the cube.
 * @param bool $wireframe Display as a wireframe (face color will be ignored).
 * @param bool $dashes Display "hidden" lines as dashes (only if wireframe is not selected).
 * @param bool $rainbow Instead of using the face color, draw each side a different color.
 * @return resource GD image
 */
function draw_cube($image_size=400,$degree_x=35,$degree_y=35,$degree_z=0,$vdist=800,$dist=100,$vertex_color='0000ff',$face_color='ff0000',$wireframe=false,$dashes=false,$rainbow=false)
{
	$degree_x = $degree_x % 360;
	$degree_y = $degree_y % 360;
	$degree_z = $degree_z % 360;
	
	// construct the cube polygons
	$size = 400; // the size is arbitrary
	
	$x1=$size/2;
	$x0=-($size/2);
	$y1=$size/2;
	$y0=-($size/2);
	$z1=$size/2;
	$z0=-($size/2);
	
	$sides = array();
	
	$sides[] = array($x0,$y0,$z0, $x0,$y0,$z1, $x0,$y1,$z1, $x0,$y1,$z0);
	$sides[] = array($x1,$y0,$z0, $x1,$y0,$z1, $x1,$y1,$z1, $x1,$y1,$z0);
	
	$sides[] = array($x0,$y0,$z0, $x0,$y0,$z1, $x1,$y0,$z1, $x1,$y0,$z0);
	$sides[] = array($x0,$y1,$z0, $x0,$y1,$z1, $x1,$y1,$z1, $x1,$y1,$z0);
	
	$sides[] = array($x0,$y0,$z0, $x0,$y1,$z0, $x1,$y1,$z0, $x1,$y0,$z0);
	$sides[] = array($x0,$y0,$z1, $x0,$y1,$z1, $x1,$y1,$z1, $x1,$y0,$z1);
	
	// project each of the 6 polygons that makes up the cube
	for ($i=0; $i<count($sides); $i++) {
		$points[] = project_polygon($sides[$i], $degree_x, $degree_y, $degree_z, 0, 0, 0, $vdist+($size/2), $dist+($size/2), true);
	}
	
	// scale the image somewhat
	$scale = $image_size/($size*1.8);
	
	if ($rainbow) {
		$face_color = array('ff0000', '00d000', 'ffff00', 'a000a0', '0000ff', 'FF8040');
	}
	
	return render_polygons($points, $vertex_color, $face_color, $wireframe, $dashes, $image_size, $scale);
}

/**
 * project_polygon
 *
 * Project a the points of a 3d polygon onto a flat 2d surface (the screen).
 *
 * @version 0.5
 * @author Contributors at eXorithm
 * @link /algorithm/view/project_polygon Listing at eXorithm
 * @link /algorithm/history/project_polygon History at eXorithm
 * @license /home/show/license
 *
 * @param array $points Points of the polygon, in the form x1, y1, z1, x2, y2, z2, etc.
 * @param number $degree_x Degrees to rotate around the x axis.
 * @param number $degree_y Degrees to rotate around the y axis.
 * @param number $degree_z Degrees to rotate around the z axis.
 * @param number $center_x Location to center the view on.
 * @param number $center_y Location to center the view on.
 * @param number $center_z Location to center the view on.
 * @param number $dist1 Distance from viewer to screen (distance to vanishing point).
 * @param number $dist2 Distance from screen to object.
 * @param bool $include_z Return the z (distance) parameter for each point as well.
 * @return mixed
 */
function project_polygon($points=array(0=>'-1',1=>'-1',2=>'0',3=>'-1',4=>'1',5=>'0',6=>'1',7=>'1',8=>'0',9=>'1',10=>'-1',11=>'0'),$degree_x=45,$degree_y=45,$degree_z=45,$center_x=0,$center_y=0,$center_z=0,$dist1=5,$dist2=2,$include_z=false)
{
	// check points
	if ((count($points)%3)!=0) {
		throw new Exception('The points must be a list like x1, y1, z1, x2, y2, z2, etc. The number of points therefore must be divisible by three.');
	}
	
	$degree_x = deg2rad($degree_x);
	$degree_y = deg2rad($degree_y);
	$degree_z = deg2rad($degree_z);
	
	$cosx = cos($degree_x);
	$sinx = sin($degree_x);
	$cosy = cos($degree_y);
	$siny = sin($degree_y);
	$cosz = cos($degree_z);
	$sinz = sin($degree_z);
	
	$array = array();
	
	for ($i=0;$i<count($points);$i=$i+3) {
		$x0 = $points[$i]-$center_x;
		$y0 = $points[$i+1]-$center_y;
		$z0 = $points[$i+2]-$center_z;
		
		$x1 = $cosy*($sinz*$y0 + $cosz*$x0) - $siny*$z0;
		$y1 = $sinx*($cosy*$z0 + $siny*($sinz*$y0 + $cosz*$x0)) + $cosx*($cosz*$y0 - $sinz*$x0);
		$z1 = $cosx*($cosy*$z0 + $siny*($sinz*$y0 + $cosz*$x0)) - $sinx*($cosz*$y0 - $sinz*$x0);
	
		$x2 = $x1*$dist1/($z1+$dist1+$dist2);
		$y2 = $y1*$dist1/($z1+$dist1+$dist2);
		$z2 = $z1*$dist1/($z1+$dist1+$dist2);
	
		$array[] = $x2;
		$array[] = $y2;
		if ($include_z) $array[] = $z2;
	}
	
	return $array;
}

/**
 * render_polygons
 *
 * Helper function to render polygons to the screen with a number of options.
 *
 * @version 0.5
 * @author Contributors at eXorithm
 * @link /algorithm/view/render_polygons Listing at eXorithm
 * @link /algorithm/history/render_polygons History at eXorithm
 * @license /home/show/license
 *
 * @param array $polygons Multi-dimensional array. Each element will be an array of points (x1, y1, z1, x2, y2, z2, etc).
 * @param string $vertex_color (hex color code) Color of the vertices of the polygons.
 * @param string $face_color (hex color code) Color of the faces of the polygons.
 * @param bool $wireframe Display as a wireframe (face color will be ignored).
 * @param bool $dashes Display "hidden" vertices as dashes (only if wireframe is not selected).
 * @param number $image_size Size of the resulting image.
 * @param number $scale Scale factor. Set to 0 to auto-scale (fill the image).
 * @return resource GD image
 */
function render_polygons($polygons=array(0=>array(0=>-100,1=>-100,2=>1,3=>0,4=>100,5=>1,6=>100,7=>-100,8=>1)),$vertex_color='000000',$face_color='ffd700',$wireframe=false,$dashes=false,$image_size=300,$scale=1)
{
	foreach ($polygons as $polygon) {
		if (!is_array($polygon)) {
			throw new Exception('Each polygon must be a list.');
		} else if ((count($polygon)%3)!=0) {
			throw new Exception('Each polygon must be a list like x1, y1, z1, x2, y2, z2, etc. The number of points therefore must be divisible by three.');
		}
	}
	
	if (is_array($vertex_color)) {
		if (count($vertex_color) != count($polygons)) {
			throw new Exception('If vertex colors is an array, it must contain the same number of colors as the number of polygons.');
		}
	}
	
	if (is_array($face_color)) {
		if (count($face_color) != count($polygons)) {
			throw new Exception('If face colors is an array, it must contain the same number of colors as the number of polygons.');
		}
	}
	
	// if scale=0 then we auto-scale
	if ($scale==0) {
		$max = 0;
		for ($i=0; $i<count($polygons); $i++) {
			for ($j=0; $j<count($polygons[$i]); $j=$j+3) {  
				if (abs($polygons[$i][$j])>$max)
					$max = abs($polygons[$i][$j]);
				if (abs($polygons[$i][$j+1])>$max)
					$max = abs($polygons[$i][$j+1]);
			}
		}
		if ($max>0)
			$scale = ($image_size-2)/($max*2);
	}
	
	// the polygon arrays (x,y,z) must be converted into shapes (x,y)
	$shapes = array();
	$z_max = array();
	
	for ($i=0; $i<count($polygons); $i++) {
		$max = $polygons[$i][2];
		for ($j=0; $j<count($polygons[$i]); $j=$j+3) {  
			$x = $polygons[$i][$j];
			$y = $polygons[$i][$j+1];
			
			// map each x,y coord to a screen position
			$x = round($image_size/2 + $x*$scale);
			$y = round($image_size/2 - $y*$scale);
			
			$shapes[$i][$j] = $x;
			$shapes[$i][$j+1] = $y;
			
			// keep track of the maximum z-value for each shape
			if ($polygons[$i][$j+2]>$max)
				$max = $polygons[$i][$j+2];
		}
		$shapes[$i] = array_values($shapes[$i]);
		$z_max[$i] = $max;
	}
	
	// create a blank image
	$image = image_create_alpha($image_size, $image_size);
	
	// create the colors
	if (!is_array($vertex_color))
		$vertex_color = array_fill(0, count($polygons), $vertex_color);
	if (!is_array($face_color))
		$face_color = array_fill(0, count($polygons), $face_color);
	
	// painter's algorithm - draw farther polygons first
	array_multisort($z_max, SORT_DESC, $shapes, $face_color, $vertex_color);
	
	// draw the polygons
	for ($i=0; $i<count($shapes); $i++) {
		$v_color = allocate_color($image, $vertex_color[$i]);
		$f_color = allocate_color($image, $face_color[$i]);
		if (!$wireframe) {
			imagefilledpolygon($image, $shapes[$i], count($shapes[$i])/2, $f_color);
		}
		imagepolygon($image, $shapes[$i], count($shapes[$i])/2, $v_color);
	}
	
	// draw dashes - BUGGY
	if ($dashes) {
		for ($i=0; $i<count($shapes); $i++) {
			$v_color = allocate_color($image, $vertex_color[$i]);
			$style = array($v_color, IMG_COLOR_TRANSPARENT, IMG_COLOR_TRANSPARENT, IMG_COLOR_TRANSPARENT, IMG_COLOR_TRANSPARENT);
			imagesetstyle($image, $style);
			imagepolygon($image, $shapes[$i], count($shapes[$i])/2, IMG_COLOR_STYLED);
		}
	}
	
	return $image;
}

/**
 * image_create_alpha
 *
 * Helper function to create a new blank image with transparency.
 *
 * @version 0.1
 * @author Contributors at eXorithm
 * @link /algorithm/view/image_create_alpha Listing at eXorithm
 * @link /algorithm/history/image_create_alpha History at eXorithm
 * @license /home/show/license
 *
 * @param mixed $width 
 * @param mixed $height 
 * @return resource GD image
 */
function image_create_alpha($width='',$height='')
{
	// Create a normal image and apply required settings
	$img = imagecreatetruecolor($width, $height);
	imagealphablending($img, false);
	imagesavealpha($img, true);
	
	// Apply the transparent background
	$trans = imagecolorallocatealpha($img, 0, 0, 0, 127);
	for ($x = 0; $x < $width; $x++)
	{
		for ($y = 0; $y < $height; $y++)
		{
			imagesetpixel($img, $x, $y, $trans);
		}
	}
	
	return $img;
}

/**
 * allocate_color
 *
 * Helper function to allocate a color to an image. Color should be a 6-character hex string.
 *
 * @version 0.2
 * @author Contributors at eXorithm
 * @link /algorithm/view/allocate_color Listing at eXorithm
 * @link /algorithm/history/allocate_color History at eXorithm
 * @license /home/show/license
 *
 * @param resource $image (GD image) The image that will have the color allocated to it.
 * @param string $color (hex color code) The color to allocate to the image.
 * @param mixed $transparency The level of transparency from 0 to 127.
 * @return mixed
 */
function allocate_color($image=null,$color='268597',$transparency='0')
{
	if (preg_match('/[0-9ABCDEF]{6}/i', $color)==0) {
		throw new Exception("Invalid color code.");
	}
	if ($transparency<0 || $transparency>127) {
		throw new Exception("Invalid transparency.");
	}
	
	$r  = hexdec(substr($color, 0, 2));
	$g  = hexdec(substr($color, 2, 2));
	$b  = hexdec(substr($color, 4, 2));
	if ($transparency>127) $transparency = 127;
	
	if ($transparency<=0)
		return imagecolorallocate($image, $r, $g, $b);
	else
		return imagecolorallocatealpha($image, $r, $g, $b, $transparency);
}

?>

eXorithm – Execute Algorithm: View / Run Algorithm distance_on_earth

function distance_on_earth ($point1$point2
{
  $radius = 6371; // average radius of the earth in km
  
  $lat1 = deg2rad$point1'latitude']);
  $lat2 = deg2rad ($point2'latitude']);
  $long1 = deg2rad ($point1'longitude']);
  $long2 = deg2rad ($point2'longitude']);
  
  return $radius * acossin$lat1)*sin$lat2) + cos$lat1)*cos$lat2) * cos$long2$long1));

eXorithm – Execute Algorithm: View / Run Algorithm fibonacci_recurse

function fibonacci_recurse ($n
{
  if ($n == 0) {
    return 0;
  }
  elseif ($n == 1 || $n == -1) {
    return 1;
  }
  
  if$n > 0) {
    $tot = fibonacci_recurse$n-1) + fibonacci_recurse$n-2);
  }
  else {
    $tot = fibonacci_recurse$n+2) - fibonacci_recurse$n+1);
  }
  
  return $tot
} 

eXorithm – Execute Algorithm: View / Run Algorithm round_corners

function round_corners ($image$radius$color$transparency
{
  $width = imagesx$image);
  $height = imagesy$image);
  
  $image2 = imagecreatetruecolor$width$height);
  
  imagesavealpha$image2, true);
  imagealphablending$image2, false);
  
  imagecopy$image2$image, 0, 0, 0, 0, $width$height);
  
  
  
  $full_color = allocate_color$image2$color$transparency);
  
  // loop 4 times, for each corner...
  for ($left=0;$left<=1;$left++) {
    for ($top=0;$top<=1;$top++) {
      
      $start_x = $left * ($width$radius);
      $start_y = $top * ($height$radius);
      $end_x = $start_x$radius
      $end_y = $start_y$radius
      
      $radius_origin_x = $left * ($start_x-1) + (!$left) * $end_x
      $radius_origin_y = $top * ($start_y-1) + (!$top) * $end_y
      
      for ($x$start_x$x$end_x$x++) {
        for ($y$start_y$y$end_y$y++) {
          $dist = sqrtpow$x$radius_origin_x,2)+pow$y$radius_origin_y,2));
          
          if ($dist>($radius+1)) {
            imagesetpixel$image2$x$y$full_color);
          } else {
            if ($dist$radius) {
              $pct = 1-($dist$radius);
              $color2 = antialias_pixel$image2$x$y$full_color$pct);
              imagesetpixel$image2$x$y$color2);
            }
          }
        }
      }
      
    }
  }
  
  return $image2

eXorithm – Execute Algorithm: Embed Algorithm hailstone


Embed This Algorithm

This page will help you embed the algorithm hailstone on a page on your own website. Just configure the inputs, then click the generate button to get a snippet of code you can paste onto your site. You have two options.

  1. You can embed the entire form. Users will be able to enter their own arguments, and will need to press the run button to execute the algorithm.
  2. You can add only the output of the algorithm to your website. There will be no argument inputs or run button.
number Argument info
Embed the form Embed only the output

eXorithm – Execute Algorithm: View / Run Algorithm date_difference

function date_difference ($date1, $date2
{
  $seconds = abs$date2$date1);
  $text = ""
  
  $weeks = floor$seconds/(7*24*60*60));
  if ($weeks>0) $text .= "$weeks weeks, "
  $seconds = $seconds - ($weeks * 7*24*60*60);
  
  $days = floor$seconds/(24*60*60));
  if ($days>0) $text .= "$days days, "
  $seconds = $seconds - ($days * 24*60*60);
  
  $hours = floor$seconds/(60*60));
  if ($hours>0) $text .= "$hours hours, "
  $seconds = $seconds - ($hours * 60*60);
  
  $minutes = floor$seconds/(60));
  if ($minutes>0) $text .= "$minutes minutes, "
  $seconds = $seconds - ($minutes *60);
  
  $text .= "$seconds seconds"
    
  return $text
}Â