ClarkeRubber

PHP project - Line segment projection.

Jul 1st, 2011
143
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 8.12 KB | None | 0 0
  1. <?php
  2. //-----Functions
  3. function dot($u,$v){                                //// u and v are 2 vectors
  4.   return $u[0] * $v[0] + $u[1] * $v[1] + $u[2] * $v[2];
  5. }
  6.  
  7. function norm($v){
  8.   return sqrt(dot($v,$v));
  9. }
  10.  
  11. function subvect($x, $y){
  12.   $r = array(3);
  13.   $r[0] = $x[0] - $y[0];
  14.   $r[1] = $x[1] - $y[1];
  15.   $r[2] = $x[2] - $y[2];
  16.   return $r;
  17. }
  18.  
  19. function dist($u, $v){
  20.   return norm(subvect($u,$v));
  21. }
  22.  
  23.  function dist3DSegment($line1, $line2){ //$line1 and $line2 are two line segments, each with two defining points. (x1, y1, z1)-(x2, y2, z2)
  24.   $eplison =  0.0000001; //Grrr... wrote 'epsilon' everywhere because of this.
  25.  
  26.   $u = array(3);
  27.   $v = array(3);
  28.   $w = array(3);
  29.  
  30.   $u[0] = $line1["x2"] - $line1["x1"];
  31.   $u[1] = $line1["y2"] - $line1["y1"];
  32.   $u[2] = $line1["z2"] - $line1["z1"];
  33.  
  34.   $v[0] = $line2["x2"] - $line2["x1"];
  35.   $v[1] = $line2["y2"] - $line2["y1"];
  36.   $v[2] = $line2["z2"] - $line2["z1"];
  37.  
  38.   $w[0] = $line1["x2"] - $line2["x1"];
  39.   $w[1] = $line1["y2"] - $line2["y1"];
  40.   $w[2] = $line1["z2"] - $line2["z1"];
  41.  
  42.   $a = dot($u, $u);
  43.   $b = dot($u, $v);
  44.   $c = dot($v, $v);
  45.   $d = dot($u, $w);
  46.   $e = dot($v, $w);
  47.   $D = ($a*$c) - ($b*$b);
  48.  
  49.   // compute the line parameters of the two closest points
  50.   if($D < $eplison){
  51.     $sN = 0.0;
  52.     $sD = 1.0;
  53.     $tN = $e;
  54.     $tD = $c;
  55.   }else{ // get the closest points on the infinite lines
  56.     $sN = ($b*$e - $c*$d);
  57.     $tN = ($a*$e - $b*$d);
  58.       if ($sN < 0.0){       // sc < 0 => the s=0 edge is visible
  59.         $sN = 0.0;
  60.         $tN = $e;
  61.         $tD = $c;
  62.       }else if ($sN > $sD){  // sc > 1 => the s=1 edge is visible
  63.         $sN = $sD;
  64.         $tN = $e + $b;
  65.         $tD = $c;
  66.       }
  67.   }
  68.  
  69.   if($tN < 0.0){           // tc < 0 => the t=0 edge is visible
  70.     $tN = 0.0;
  71.     // recompute sc for this edge
  72.     if ((-1*$d) < 0.0){
  73.       $sN = 0.0;
  74.     }else if ((-1*$d) > $a){
  75.       $sN = $sD;
  76.     }else{
  77.       $sN = (-1*$d);
  78.       $sD = $a;
  79.     }
  80.   }
  81.    
  82.     else if ($tN > $tD) {      // tc > 1 => the t=1 edge is visible
  83.         $tN = $tD;
  84.         // recompute sc for this edge
  85.         if (((-1*$d) + $b) < 0.0){
  86.           $sN = 0;
  87.         }else if (((-1*$d) + $b) > $a){
  88.           $sN = $sD;
  89.         }else {
  90.           $sN = ((-1*$d) + $b);
  91.           $sD = $a;
  92.         }
  93.     }
  94.     // finally do the division to get sc and tc
  95.     if (abs($sN) < $epsilon){
  96.     $sc = 0.0;
  97.     }else $sc = $sN / $sD;
  98.     if (abs($tN) < $epsilon){
  99.     $tc = 0.0;
  100.     }else $tc = $tN / $tD;
  101.    
  102.  // get the difference of the two closest points
  103.     $dP = array(3);
  104.     $dP[0] = $w[0] + ($sc * $u[0]) - ($tc * $v[0]);  // = S1(sc) - S2(tc)
  105.     $dP[1] = $w[1] + ($sc * $u[1]) - ($tc * $v[1]);
  106.     $dP[2] = $w[2] + ($sc * $u[2]) - ($tc * $v[2]);
  107.  
  108.     return norm($dP);   // return the closest distance
  109. }
  110.  
  111. //-----Being main program
  112.  
  113. $maxDrawDist = 40; //Max draw dist is the maximum Z distance that will be made observable. This is required as the test 'rays' are no longer rays, but line segments.
  114. //For some reason, I have to set maxDrawDist to the same distance as the farthest Z value of the line I am trying to project. It seems that this value bisects the line.
  115. $amountOfRainbows = 1; //SET TO ZERO IF YOU DON'T WANT ANY RAINBOWS!!! (Seems to only be able to make one rainbow at the moment, I'll look into this later)
  116.  
  117. $line1 = array("x1" => -60, "y1" => 60, "z1" => 40, "x2" => 60, "y2" => -60, "z2" => 40); //my input line
  118. $projScr = array("x1" => -200, "y1" => 100, "z1" => 30, "x2" => 200, "y2" => -100, "z2" => 30); //dimensions and location of the screen.
  119. $OriPos = array("x" => 0, "y" => 0, "z" => 0); //origin position is the position that is being used for the projector.
  120.  
  121. $totalTests = abs(($projScr['y1'] - $projScr['y2']) * ($projScr['x1'] - $projScr['x2'])); //how many pixel tests are to be run
  122. $curPy = $projScr['y1']; //pre-loop definitions (not entirely necessary)
  123. $curPx = $projScr['x1']; //pre-loop definitions (not entirely necessary)
  124.  
  125. for($i = 0; $i < $totalTests; $i++){
  126.   if($i > 0) $curPx++;
  127.   if($curPx == 0){ $testPx = 1;}else{$testPx = $curPx;}
  128.   if($testPx%(abs($projScr['x2'])) == 0 && $i > 0){ $curPx = $projScr['x1']; $curPy += -1;} //if at the end of the line, move to the next row (Y+1) (super-dooper ugly line of code, but I decided I want to write it in one line and that's final.)
  129.   $curPz = $projScr['z1']; //'Current Position Z' is constant as I haven't concerned myself with changing the angle of the screen, yet.
  130.  
  131.   $k = abs($maxDrawDist / $curPz); //MAX DRAW DIST MAKES THE RAY LONGER. xD
  132.   $Longz = $curPz * $k; //MAKES EVERYTHING IN THE SAME RATIO
  133.   $Longx = $curPx * $k; //MAKES EVERYTHING IN THE SAME RATIO
  134.   $Longy = $curPy * $k; //MAKES EVERYTHING IN THE SAME RATIO
  135.  
  136.   $line2 = array("x1" => $curPx, "y1" => $curPy, "z1" => $curPz, "x2" => $Longx, "y2" => $Longy, "z2" => $Longz);
  137.  
  138.   $dist = dist3DSegment($line1, $line2);
  139.  
  140.   //Rainbows n' stuff
  141.   if($amountOfRainbows > 0){
  142.     if($dist < 0.0001) $dist = 0.0001;
  143.     $intensity[$i] = abs(floor( (1785 * $amountOfRainbows) / $dist));
  144.   }else{
  145.     if($dist < 1) $dist = 1;
  146.     $intensity[$i] = abs(floor(255 / $dist));
  147.   }
  148. }
  149.  
  150. //-----Start writing file (THIS BIT OF THE CODE IS SIMPLY A FILE PRINTER, NOTHING INTERESTING TO SEE HERE)
  151.  
  152. unlink("image.ppm"); //file that we will be editting, we are are delteing the file so we have a clean file to work on
  153. $fh = fopen("image.ppm", 'a+'); //creates the image file that we will be editting and opens the file for appending
  154.  
  155. $width = abs($projScr['x1'] - $projScr['x2']);
  156. $height = abs($projScr['y1'] - $projScr['y2']);
  157.  
  158. $startWrite = "P3\n# image.ppm\n".$width." ".$height."\n255\n";
  159. fwrite($fh, $startWrite);
  160.  
  161. $CurPx = 0;
  162. foreach($intensity as $spec){
  163.     $CurPx++;
  164.     if($CurPx%5 == 0){ //Checks if it has to make a new line (max line length in PPM files is 70 characters)
  165.         $Nl = "\n";
  166.     }else{
  167.         $Nl = " ";
  168.     }
  169.    
  170.     //Creating lighting and colouring for individual pixels.
  171.   if($amountOfRainbows > 0){
  172.     //if($spec > (1785 * $amountOfRainbows) ) $spec = (1785 * $amountOfRainbows); //THIS LINE ISN'T VERY IMPORTANT WHEN USING MODULUS IN THE NEXT LINE
  173.     if($spec%1785 == 0 && $spec != 0){
  174.       $spec = $spec%1785;
  175.       }
  176.       //----MAKING A RAINBOW (WITH SOME EXPERT RAINBOW MAPPING, THIS OCCURS)
  177.    
  178.       $modulus = intval($spec)%255;
  179.       if($modulus == 0){ $modulus = 255;}
  180.    
  181.       if(intval($spec) <= 255){ $red = 255; $green = 0; $blue = 0;} //Using rainbows to see different shades of black isn't very useful, because if distance is large, it will all appear the same shade of red.
  182.       if(intval($spec) > 255 && intval($spec) <= 510){ $red = 255; $green = 0; $blue = $modulus;}
  183.       if(intval($spec) > 510 && intval($spec) <= 765){ $red = 255 - $modulus; $green = 0; $blue = 255;}
  184.       if(intval($spec) > 765 && intval($spec) <= 1020){ $red = 0; $green = $modulus; $blue = 255;}
  185.       if(intval($spec) > 1020 && intval($spec) <= 1275){ $red = 0; $green = 255; $blue = 255 - $modulus;}
  186.       if(intval($spec) > 1275 && intval($spec) <= 1530){ $red = $modulus; $green = 255; $blue = 0;}
  187.       if(intval($spec) > 1530 && intval($spec) <= 1785){ $red = 255; $green = 255 - $modulus; $blue = 0;}
  188.  
  189.       //----END MAKING RAINBOW
  190.    
  191.       $pad = ""; //RED CHANEL
  192.       $dots = 3 - strlen($red);
  193.       for($i = 0; $i < $dots; $i++){ //The padding is so the file is written correcting. Zeros must be included.
  194.         $pad = $pad."0";
  195.       }
  196.       $red = $pad.$red;
  197.    
  198.       $pad = ""; //GREEN CHANNEL
  199.       $dots = 3 - strlen($green);
  200.       for($i = 0; $i < $dots; $i++){
  201.         $pad = $pad."0";
  202.       }
  203.       $green = $pad.$green;
  204.    
  205.       $pad = ""; //BLUE CHANNEL
  206.       $dots = 3 - strlen($blue);
  207.       for($i = 0; $i < $dots; $i++){
  208.         $pad = $pad."0";
  209.       }
  210.       $blue = $pad.$blue;
  211.    
  212.       $write = $red." ".$green." ".$blue.$Nl;
  213.       fwrite($fh, $write);
  214.     }else{ //IF NO RAINBOWS
  215.       if($spec > 255) $spec = 255;
  216.       $pad = "";
  217.       $dots = 3 - strlen($spec);
  218.       for($i = 0; $i < $dots; $i++){
  219.         $pad = $pad."0";
  220.       }
  221.       $spec = $pad.$spec;
  222.       $write = $spec." ".$spec." ".$spec.$Nl;
  223.       fwrite($fh, $write);
  224.     }
  225. }
  226. fclose($fh);
  227. ?>
Advertisement
Add Comment
Please, Sign In to add comment