. */ /* */ /* ----------------------------------------------------------------------- */ /* */ /* (C) Copyright 2007 */ /* Andrew Que */ /* ð|> */ /*=========================================================================*/ /** * Used for clipping a line in a define square * *

* This unit was constructed mostly from an example in Wikipedia, which * had the following credit: *

* "Mark S. Sobkow, Paul Pospisil and Yee-Hong Yang. A Fast Two- * Dimensional Line Clipping Algorithm via Line Encoding//Computer & * Graphics, Vol. 11, No. 4, pp. 459-467, 1987." *

* The port to PHP was done by Andrew Que * * @package XY_Plot * @author Andrew Que ({@link http://www.DrQue.net/}) * @copyright Copyright (c) 2007, Andrew Que * @license http://opensource.org/licenses/gpl-license.php GNU Public License * */ /** * Implementation of the Fast-Clipping algorithm. * * This is a class, but acts more like a function. The reason * implementation is done this way is because of the sub-functions that * need access to the local variables. */ class ClipLine { /**#@+ @ignore */ public $x; public $y; public $xx; public $yy; public $X_Min; public $Y_Min; public $X_Max; public $Y_Max; /**#@-*/ /** * Constructor * @param x Left corner of line * @param y Top corner of line * @param xx Right corner of line * @param yy Bottom corner of line * @param X_Min Left edge of frame * @param Y_Min Top edge of frame * @param X_Max Right edge of frame * @param Y_Max Bottom edge of frame */ public function __construct ( &$x , &$y , &$xx , &$yy , $X_Min , $Y_Min , $X_Max , $Y_Max ) { // Set local variables $this->x = &$x; $this->y = &$y; $this->xx = &$xx; $this->yy = &$yy; $this->X_Min = &$X_Min; $this->Y_Min = &$Y_Min; $this->X_Max = &$X_Max; $this->Y_Max = &$Y_Max; // Clip the line $this->Clip(); } //------------------------------------------------------ // Clipping function // (There is one clipping function for each of the 8 areas) //------------------------------------------------------ /** * Start top */ private function clipStartTop() { $DeltaX = $this->xx - $this->x; $DeltaY = $this->yy - $this->y; $this->x += $DeltaX * ( $this->Y_Min - $this->y ) / $DeltaY; $this->y = $this->Y_Min; } /** * Start bottom */ private function clipStartBottom() { $DeltaX = $this->xx - $this->x; $DeltaY = $this->yy - $this->y; $this->x += $DeltaX * ( $this->Y_Max - $this->y ) / $DeltaY; $this->y = $this->Y_Max; } /** * Start right */ private function clipStartRight() { $DeltaX = $this->xx - $this->x; $DeltaY = $this->yy - $this->y; $this->y += $DeltaY * ( $this->X_Max - $this->x ) / $DeltaX; $this->x = $this->X_Max; } /** * Start left */ private function clipStartLeft() { $DeltaX = $this->xx - $this->x; $DeltaY = $this->yy - $this->y; $this->y += $DeltaY * ( $this->X_Min - $this->x ) / $DeltaX; $this->x = $this->X_Min; } /** * End top */ private function clipEndTop() { $DeltaX = $this->xx - $this->x; $DeltaY = $this->yy - $this->y; $this->xx += $DeltaX * ( $this->Y_Min - $this->yy ) / $DeltaY; $this->yy = $this->Y_Min; } /** * End bottom */ private function clipEndBottom() { $DeltaX = $this->xx - $this->x; $DeltaY = $this->yy - $this->y; $this->xx += $DeltaX * ( $this->Y_Max - $this->yy ) / $DeltaY; $this->yy = $this->Y_Max; } /** * End right */ private function clipEndRight() { $DeltaX = $this->xx - $this->x; $DeltaY = $this->yy - $this->y; $this->yy += $DeltaY * ( $this->X_Max - $this->xx ) / $DeltaX; $this->xx = $this->X_Max; } /** * End Left */ private function clipEndLeft() { $DeltaX = $this->xx - $this->x; $DeltaY = $this->yy - $this->y; $this->yy += $DeltaY * ( $this->X_Min - $this->xx ) / $DeltaX; $this->xx = $this->X_Min; } /** * Main body of clipping function * * This function does all the clipping work */ private function Clip() { $LineCode = 0; // Figure out which sides clip if ( $this->y < $this->Y_Min ) $LineCode |= 0x80; // BIT8 else if ( $this->y > $this->Y_Max ) $LineCode |= 0x40; // BIT7 if ( $this->x > $this->X_Max ) $LineCode |= 0x20; // BIT6 else if ( $this->x < $this->X_Min ) $LineCode |= 0x10; // BIT5 if ( $this->yy < $this->Y_Min ) $LineCode |= 0x08; // BIT4 else if ( $this->yy > $this->Y_Max ) $LineCode |= 0x04; // BIT3 if ( $this->xx > $this->X_Max ) $LineCode |= 0x02; // BIT2 else if ( $this->xx < $this->X_Min ) $LineCode |= 0x01; // BIT1 // Completely out of bounds? (i.e. not visible on screen) if ( ( ( $LineCode & ( 0x80 | 0x08 ) ) == ( 0x80 | 0x08 ) ) || ( ( $LineCode & ( 0x40 | 0x04 ) ) == ( 0x40 | 0x04 ) ) || ( ( $LineCode & ( 0x20 | 0x02 ) ) == ( 0x20 | 0x02 ) ) || ( ( $LineCode & ( 0x10 | 0x01 ) ) == ( 0x10 | 0x01 ) ) ) { $this->x = $this->y = $this->xx = $this->yy = 0; return; } // 9 - 8 - A // | | | // 1 - 0 - 2 // | | | // 5 - 4 - 6 switch ( $LineCode ) { //------------------------------ // Center //------------------------------ case 0x00: { // Line is perfect, no clipping needed break; } case 0x01: { $this->clipEndLeft(); break; } case 0x02: { $this->clipEndRight(); break; } case 0x04: { $this->clipEndBottom(); break; } case 0x05: { $this->clipEndLeft(); if ( $this->yy > $this->Y_Max ) $this->clipEndBottom(); break; } case 0x06: { $this->clipEndRight(); if ( $this->yy > $this->Y_Max ) $this->clipEndBottom(); break; } case 0x08: { $this->clipEndTop(); break; } case 0x09: { $this->clipEndLeft(); if ( $this->yy < $this->Y_Min ) $this->clipEndTop(); break; } case 0x0A: { $this->clipEndRight(); if ( $this->yy < $this->Y_Min ) $this->clipEndTop(); break; } //------------------------------ // Left //------------------------------ case 0x10: { $this->clipStartLeft(); break; } case 0x12: { $this->clipStartLeft(); $this->clipEndRight(); break; } case 0x14: { $this->clipStartLeft(); if ( $this->y > $this->Y_Max ) break; $this->clipEndBottom(); break; } case 0x16: { $this->clipStartLeft(); if ( $this->y > $this->Y_Max ) break; $this->clipEndBottom(); if ( $this->xx > $this->X_Max ) $this->clipEndRight(); break; } case 0x18: { $this->clipStartLeft(); if ( $this->y < $this->Y_Min ) break; $this->clipEndTop(); break; } case 0x1A: { $this->clipStartLeft(); if ( $this->y < $this->Y_Min ) break; $this->clipEndTop(); if ( $this->xx > $this->X_Max ) $this->clipEndRight(); break; } //------------------------------ // Right //------------------------------ case 0x20: { $this->clipStartRight(); break; } case 0x21: { $this->clipStartRight(); $this->clipEndLeft(); break; } case 0x24: { $this->clipStartRight(); if ( $this->y > $this->Y_Max ) break; $this->clipEndBottom(); break; } case 0x25: { $this->clipStartRight(); if ( $this->y > $this->Y_Max ) break; $this->clipEndBottom(); if ( $this->xx < $this->X_Min ) $this->clipEndLeft(); break; } case 0x28: { $this->clipStartRight(); if ( $this->y < $this->Y_Min ) break; $this->clipEndTop(); break; } case 0x29: { $this->clipStartRight(); if ( $this->y < $this->Y_Min ) break; $this->clipEndTop(); if ( $this->xx < $this->X_Min ) $this->clipEndLeft(); break; } //------------------------------ // Bottom //------------------------------ case 0x40: { $this->clipStartBottom(); break; } case 0x41: { $this->clipStartBottom(); if ( $this->x < $this->X_Min ) break; $this->clipEndLeft(); if ( $this->yy > $this->Y_Max ) $this->clipEndBottom(); break; } case 0x42: { $this->clipStartBottom(); if ( $this->x > $this->X_Max ) break; $this->clipEndRight(); break; } case 0x48: { $this->clipStartBottom(); $this->clipEndTop(); break; } case 0x49: { $this->clipStartBottom(); if ( $this->x < $this->X_Min ) break; $this->clipEndLeft(); if ( $this->yy < $this->Y_Min ) $this->clipEndTop(); break; } case 0x4A: { $this->clipStartBottom(); if ( $this->x > $this->X_Max ) break; $this->clipEndRight(); if ( $this->yy < $this->Y_Min ) $this->clipEndTop(); break; } //------------------------------ // Bottom-left //------------------------------ case 0x50: { $this->clipStartLeft(); if ( $this->y > $this->Y_Max ) $this->clipStartBottom(); break; } case 0x52: { $this->clipEndRight(); if ( $this->yy > $this->Y_Max ) break; $this->clipStartBottom(); if ( $this->x < $this->X_Min ) $this->clipStartLeft(); break; } case 0x58: { $this->clipEndTop(); if ( $this->xx < $this->X_Min ) break; $this->clipStartBottom(); if ( $this->x < $this->X_Min ) $this->clipStartLeft(); break; } case 0x5A: { $this->clipStartLeft(); if ( $this->y < $this->Y_Min ) break; $this->clipEndRight(); if ( $this->yy > $this->Y_Max ) break; if ( $this->y > $this->Y_Max ) $this->clipStartBottom(); if ( $this->yy < $this->Y_Min ) $this->clipEndTop(); break; } //------------------------------ // Bottom-right //------------------------------ case 0x60: { $this->clipStartRight(); if ( $this->y > $this->Y_Max ) $this->clipStartBottom(); break; } case 0x61: { $this->clipEndLeft(); if ( $this->yy > $this->Y_Max ) break; $this->clipStartBottom(); if ( $this->x > $this->X_Max ) $this->clipStartRight(); break; } case 0x68: { $this->clipEndTop(); if ( $this->xx > $this->X_Max ) break; $this->clipStartRight(); if ( $this->y > $this->Y_Max ) $this->clipStartBottom(); break; } case 0x69: { $this->clipEndLeft(); if ( $this->yy > $this->Y_Max ) break; $this->clipStartRight(); if ( $this->y < $this->Y_Min ) break; if ( $this->yy < $this->Y_Min ) $this->clipEndTop(); if ( $this->y > $this->Y_Max ) $this->clipStartBottom(); break; } //------------------------------ // Top //------------------------------ case 0x80: { $this->clipStartTop(); break; } case 0x81: { $this->clipStartTop(); if ( $this->x < $this->X_Min ) break; $this->clipEndLeft(); break; } case 0x82: { $this->clipStartTop(); if ( $this->x > $this->X_Max ) break; $this->clipEndRight(); break; } case 0x84: { $this->clipStartTop(); $this->clipEndBottom(); break; } case 0x85: { $this->clipStartTop(); if ( $this->x < $this->X_Min ) break; $this->clipEndLeft(); if ( $this->yy > $this->Y_Max ) $this->clipEndBottom(); break; } case 0x86: { $this->clipStartTop(); if ( $this->x > $this->X_Max ) break; $this->clipEndRight(); if ( $this->yy > $this->Y_Max ) $this->clipEndBottom(); break; } //------------------------------ // Top-left //------------------------------ case 0x90: { $this->clipStartLeft(); if ( $this->y < $this->Y_Min ) $this->clipStartTop(); break; } case 0x92: { $this->clipEndRight(); if ( $this->yy < $this->Y_Min ) break; $this->clipStartTop(); if ( $this->x < $this->X_Min ) $this->clipStartLeft(); break; } case 0x94: { $this->clipEndBottom(); if ( $this->xx < $this->X_Min ) break; $this->clipStartLeft(); if ( $this->y < $this->Y_Min ) $this->clipStartTop(); break; } case 0x96: { $this->clipStartLeft(); if ( $this->y > $this->Y_Max ) break; $this->clipEndRight(); if ( $this->yy < $this->Y_Min ) break; if ( $this->y < $this->Y_Min ) $this->clipStartTop(); if ( $this->yy > $this->Y_Max ) $this->clipEndBottom(); break; } //------------------------------ // Top-right //------------------------------ case 0xA0: { $this->clipStartRight(); if ( $this->y < $this->Y_Min ) $this->clipStartTop(); break; } case 0xA1: { $this->clipEndLeft(); if ( $this->yy < $this->Y_Min ) break; $this->clipStartTop(); if ( $this->x > $this->X_Max ) $this->clipStartRight(); break; } case 0xA4: { $this->clipEndBottom(); if ( $this->xx > $this->X_Max ) break; $this->clipStartRight(); if ( $this->y < $this->Y_Min ) $this->clipStartTop(); break; } case 0xA5: { $this->clipEndLeft(); if ( $this->yy < $this->Y_Min ) break; $this->clipStartRight(); if ( $this->y > $this->Y_Max ) break; if ( $this->yy > $this->Y_Max ) $this->clipEndBottom(); if ( $this->y < $this->Y_Min ) $this->clipStartTop(); break; } } // Round result $this->x = round( $this->x ); $this->y = round( $this->y ); $this->xx = round( $this->xx ); $this->yy = round( $this->yy ); } } /** * Clip line * *

* This will take the corners of a line segment and clip them in a define * area. *

* Examples of use: * * $x = 5; * $y = 8; * $xx = 70; * $yy = 65; * ClipLine( * $x , $y , $xx , $yy , * 10 , 10 , 50 , 50 ); * *

* In this example, the values in $x, $y, * $xx, $yy will be adjusted so they are within * the (10,10) (50,50) window. * @param x Left corner of line * @param y Top corner of line * @param xx Right corner of line * @param yy Bottom corner of line * @param X_Min Left edge of frame * @param Y_Min Top edge of frame * @param X_Max Right edge of frame * @param Y_Max Bottom edge of frame * @return x, y, xx, yy are all modified (if necessary) */ function ClipLine( &$x , &$y , &$xx , &$yy , $X_Min , $Y_Min , $X_Max , $Y_Max ) { // All of the work is done simply by creating a clip class $Clip = new ClipLine ( $x , $y , $xx , $yy , $X_Min , $Y_Min , $X_Max , $Y_Max ); } /** * Draw clipped line * *

* Draw a line that has been clipped into the specified image. *

* Examples of use: * * DrawClippedLine( * $Image , * 5 , 8 , 70 , 65 , * 10 , 10 , 50 , 50 , * $Black ); * * In this example, a line will be drawn onto $Image clipped * within the window (10,10) (50,50). * @param image Image to draw line on * @param x Left corner of line * @param y Top corner of line * @param xx Right corner of line * @param yy Bottom corner of line * @param X_Min Left edge of frame * @param Y_Min Top edge of frame * @param X_Max Right edge of frame * @param Y_Max Bottom edge of frame * @param Color Color of line */ function DrawClippedLine( $Image , $x , $y , $xx , $yy , $X_Min , $Y_Min , $X_Max , $Y_Max , $Color ) { // Clip this line ClipLine( $x , $y , $xx , $yy , $X_Min , $Y_Min , $X_Max , $Y_Max ); // Draw the results imageline( $Image , $x , $y , $xx , $yy , $Color ); } // "Those who dream by day are cognizant of many things which escape those // who dream only by night." - Edgar Allan Poe ?>