Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <?php
- //-----Functions
- function dot($u,$v){ //// u and v are 2 vectors
- return $u[0] * $v[0] + $u[1] * $v[1] + $u[2] * $v[2];
- }
- function norm($v){
- return sqrt(dot($v,$v));
- }
- function subvect($x, $y){
- $r = array(3);
- $r[0] = $x[0] - $y[0];
- $r[1] = $x[1] - $y[1];
- $r[2] = $x[2] - $y[2];
- return $r;
- }
- function dist($u, $v){
- return norm(subvect($u,$v));
- }
- function dist3DSegment($line1, $line2){ //$line1 and $line2 are two line segments, each with two defining points. (x1, y1, z1)-(x2, y2, z2)
- $eplison = 0.0000001; //Grrr... wrote 'epsilon' everywhere because of this.
- $u = array(3);
- $v = array(3);
- $w = array(3);
- $u[0] = $line1["x2"] - $line1["x1"];
- $u[1] = $line1["y2"] - $line1["y1"];
- $u[2] = $line1["z2"] - $line1["z1"];
- $v[0] = $line2["x2"] - $line2["x1"];
- $v[1] = $line2["y2"] - $line2["y1"];
- $v[2] = $line2["z2"] - $line2["z1"];
- $w[0] = $line1["x2"] - $line2["x1"];
- $w[1] = $line1["y2"] - $line2["y1"];
- $w[2] = $line1["z2"] - $line2["z1"];
- $a = dot($u, $u);
- $b = dot($u, $v);
- $c = dot($v, $v);
- $d = dot($u, $w);
- $e = dot($v, $w);
- $D = ($a*$c) - ($b*$b);
- // compute the line parameters of the two closest points
- if($D < $eplison){
- $sN = 0.0;
- $sD = 1.0;
- $tN = $e;
- $tD = $c;
- }else{ // get the closest points on the infinite lines
- $sN = ($b*$e - $c*$d);
- $tN = ($a*$e - $b*$d);
- if ($sN < 0.0){ // sc < 0 => the s=0 edge is visible
- $sN = 0.0;
- $tN = $e;
- $tD = $c;
- }else if ($sN > $sD){ // sc > 1 => the s=1 edge is visible
- $sN = $sD;
- $tN = $e + $b;
- $tD = $c;
- }
- }
- if($tN < 0.0){ // tc < 0 => the t=0 edge is visible
- $tN = 0.0;
- // recompute sc for this edge
- if ((-1*$d) < 0.0){
- $sN = 0.0;
- }else if ((-1*$d) > $a){
- $sN = $sD;
- }else{
- $sN = (-1*$d);
- $sD = $a;
- }
- }
- else if ($tN > $tD) { // tc > 1 => the t=1 edge is visible
- $tN = $tD;
- // recompute sc for this edge
- if (((-1*$d) + $b) < 0.0){
- $sN = 0;
- }else if (((-1*$d) + $b) > $a){
- $sN = $sD;
- }else {
- $sN = ((-1*$d) + $b);
- $sD = $a;
- }
- }
- // finally do the division to get sc and tc
- if (abs($sN) < $epsilon){
- $sc = 0.0;
- }else $sc = $sN / $sD;
- if (abs($tN) < $epsilon){
- $tc = 0.0;
- }else $tc = $tN / $tD;
- // get the difference of the two closest points
- $dP = array(3);
- $dP[0] = $w[0] + ($sc * $u[0]) - ($tc * $v[0]); // = S1(sc) - S2(tc)
- $dP[1] = $w[1] + ($sc * $u[1]) - ($tc * $v[1]);
- $dP[2] = $w[2] + ($sc * $u[2]) - ($tc * $v[2]);
- return norm($dP); // return the closest distance
- }
- //-----Being main program
- $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.
- //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.
- $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)
- $line1 = array("x1" => -60, "y1" => 60, "z1" => 40, "x2" => 60, "y2" => -60, "z2" => 40); //my input line
- $projScr = array("x1" => -200, "y1" => 100, "z1" => 30, "x2" => 200, "y2" => -100, "z2" => 30); //dimensions and location of the screen.
- $OriPos = array("x" => 0, "y" => 0, "z" => 0); //origin position is the position that is being used for the projector.
- $totalTests = abs(($projScr['y1'] - $projScr['y2']) * ($projScr['x1'] - $projScr['x2'])); //how many pixel tests are to be run
- $curPy = $projScr['y1']; //pre-loop definitions (not entirely necessary)
- $curPx = $projScr['x1']; //pre-loop definitions (not entirely necessary)
- for($i = 0; $i < $totalTests; $i++){
- if($i > 0) $curPx++;
- if($curPx == 0){ $testPx = 1;}else{$testPx = $curPx;}
- 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.)
- $curPz = $projScr['z1']; //'Current Position Z' is constant as I haven't concerned myself with changing the angle of the screen, yet.
- $k = abs($maxDrawDist / $curPz); //MAX DRAW DIST MAKES THE RAY LONGER. xD
- $Longz = $curPz * $k; //MAKES EVERYTHING IN THE SAME RATIO
- $Longx = $curPx * $k; //MAKES EVERYTHING IN THE SAME RATIO
- $Longy = $curPy * $k; //MAKES EVERYTHING IN THE SAME RATIO
- $line2 = array("x1" => $curPx, "y1" => $curPy, "z1" => $curPz, "x2" => $Longx, "y2" => $Longy, "z2" => $Longz);
- $dist = dist3DSegment($line1, $line2);
- //Rainbows n' stuff
- if($amountOfRainbows > 0){
- if($dist < 0.0001) $dist = 0.0001;
- $intensity[$i] = abs(floor( (1785 * $amountOfRainbows) / $dist));
- }else{
- if($dist < 1) $dist = 1;
- $intensity[$i] = abs(floor(255 / $dist));
- }
- }
- //-----Start writing file (THIS BIT OF THE CODE IS SIMPLY A FILE PRINTER, NOTHING INTERESTING TO SEE HERE)
- unlink("image.ppm"); //file that we will be editting, we are are delteing the file so we have a clean file to work on
- $fh = fopen("image.ppm", 'a+'); //creates the image file that we will be editting and opens the file for appending
- $width = abs($projScr['x1'] - $projScr['x2']);
- $height = abs($projScr['y1'] - $projScr['y2']);
- $startWrite = "P3\n# image.ppm\n".$width." ".$height."\n255\n";
- fwrite($fh, $startWrite);
- $CurPx = 0;
- foreach($intensity as $spec){
- $CurPx++;
- if($CurPx%5 == 0){ //Checks if it has to make a new line (max line length in PPM files is 70 characters)
- $Nl = "\n";
- }else{
- $Nl = " ";
- }
- //Creating lighting and colouring for individual pixels.
- if($amountOfRainbows > 0){
- //if($spec > (1785 * $amountOfRainbows) ) $spec = (1785 * $amountOfRainbows); //THIS LINE ISN'T VERY IMPORTANT WHEN USING MODULUS IN THE NEXT LINE
- if($spec%1785 == 0 && $spec != 0){
- $spec = $spec%1785;
- }
- //----MAKING A RAINBOW (WITH SOME EXPERT RAINBOW MAPPING, THIS OCCURS)
- $modulus = intval($spec)%255;
- if($modulus == 0){ $modulus = 255;}
- 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.
- if(intval($spec) > 255 && intval($spec) <= 510){ $red = 255; $green = 0; $blue = $modulus;}
- if(intval($spec) > 510 && intval($spec) <= 765){ $red = 255 - $modulus; $green = 0; $blue = 255;}
- if(intval($spec) > 765 && intval($spec) <= 1020){ $red = 0; $green = $modulus; $blue = 255;}
- if(intval($spec) > 1020 && intval($spec) <= 1275){ $red = 0; $green = 255; $blue = 255 - $modulus;}
- if(intval($spec) > 1275 && intval($spec) <= 1530){ $red = $modulus; $green = 255; $blue = 0;}
- if(intval($spec) > 1530 && intval($spec) <= 1785){ $red = 255; $green = 255 - $modulus; $blue = 0;}
- //----END MAKING RAINBOW
- $pad = ""; //RED CHANEL
- $dots = 3 - strlen($red);
- for($i = 0; $i < $dots; $i++){ //The padding is so the file is written correcting. Zeros must be included.
- $pad = $pad."0";
- }
- $red = $pad.$red;
- $pad = ""; //GREEN CHANNEL
- $dots = 3 - strlen($green);
- for($i = 0; $i < $dots; $i++){
- $pad = $pad."0";
- }
- $green = $pad.$green;
- $pad = ""; //BLUE CHANNEL
- $dots = 3 - strlen($blue);
- for($i = 0; $i < $dots; $i++){
- $pad = $pad."0";
- }
- $blue = $pad.$blue;
- $write = $red." ".$green." ".$blue.$Nl;
- fwrite($fh, $write);
- }else{ //IF NO RAINBOWS
- if($spec > 255) $spec = 255;
- $pad = "";
- $dots = 3 - strlen($spec);
- for($i = 0; $i < $dots; $i++){
- $pad = $pad."0";
- }
- $spec = $pad.$spec;
- $write = $spec." ".$spec." ".$spec.$Nl;
- fwrite($fh, $write);
- }
- }
- fclose($fh);
- ?>
Advertisement
Add Comment
Please, Sign In to add comment