Subversion Repositories Applications.gtt

Rev

Rev 60 | Blame | Compare with Previous | Last modification | View Log | RSS feed

<?php
/*
 * This work is hereby released into the Public Domain.
 * To view a copy of the public domain dedication,
 * visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
 * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
 *
 */
 
require_once dirname(__FILE__)."/../Graph.class.php";

abstract class awShape {
        
        /**
         * Is the shape hidden ?
         *
         * @var bool
         */
        protected $hide = FALSE;
        
        /**
         * Shape style
         *
         * @var int
         */
        public $style;
        
        /**
         * Shape thickness
         *
         * @var int
         */
        public $thickness;
        
        /**
         * Solid shape
         *
         * @var int
         */
        const SOLID = 1;
        
        /**
         * Dotted shape
         *
         * @var int
         */
        const DOTTED = 2;
        
        /**
         * Dashed shape
         *
         * @var int
         */
        const DASHED = 3;
        
        /**
         * Change shape style
         *
         * @param int $style Line style
         */
        public function setStyle($style) {
                $this->style = (int)$style;
        }
        
        /**
         * Return shape style
         *
         * @return int
         */
        public function getStyle() {
                return $this->style;
        }
        
        /**
         * Change shape thickness
         *
         * @param int $thickness Shape thickness in pixels
         */
        public function setThickness($thickness) {
                $this->thickness = (int)$thickness;
        }
        
        /**
         * Return shape thickness
         *
         * @return int
         */
        public function getThickness() {
                return $this->thickness;
        }
        
        /**
         * Hide the shape
         *
         * @param bool $hide
         */
        public function hide($hide) {
                $this->hide = (bool)$hide;
        }
        
        /**
         * Show the shape
         *
         * @param bool $shape
         */
        public function show($shape) {
                $this->hide = (bool)!$shape;
        }
        
        /**
         * Is the line hidden ?
         *
         * @return bool
         */
        public function isHidden() {
                return $this->hide;
        }
        
}

registerClass('Shape', TRUE);

/**
 * Describe a point
 *
 * @package Artichow
 */
class awPoint extends awShape {

        /**
         * X coord
         *
         * @var float
         */
        public $x;

        /**
         * Y coord
         *
         * @var float
         */
        public $y;
        
        /**
         * Build a new awpoint
         *
         * @param float $x
         * @param float $y
         */
        public function __construct($x, $y) {
        
                $this->setLocation($x, $y);
                
        }
        
        /**
         * Change X value
         *
         * @param float $x
         */
        public function setX($x) {
                $this->x = (float)$x;
        }
        
        /**
         * Change Y value
         *
         * @param float $y
         */
        public function setY($y) {
                $this->y = (float)$y;
        }
        
        /**
         * Change point location
         *
         * @param float $x
         * @param float $y
         */
        public function setLocation($x, $y) {
                $this->setX($x);
                $this->setY($y);
        }
        
        /**
         * Get point location
         *
         * @param array Point location
         */
        public function getLocation() {
                return array($this->x, $this->y);
        }
        
        /**
         * Get distance to another point
         *
         * @param awPoint $p A point
         * @return float
         */
        public function getDistance(awPoint $p) {
        
                return sqrt(pow($p->x - $this->x, 2) + pow($p->y - $this->y, 2));
        
        }
        
        /**
         * Move the point to another location
         *
         * @param Point A Point with the new awlocation
         */
        public function move($x, $y) {
        
                return new awPoint(
                        $this->x + $x,
                        $this->y + $y
                );
                
        }

}

registerClass('Point');
 

/**
 * Describe a line
 *
 * @package Artichow
 */
class awLine extends awShape {

        /**
         * Line first point
         *
         * @param Point
         */
        public $p1;

        /**
         * Line second point
         *
         * @param Point
         */
        public $p2;
        
        /**
         * The line slope (the m in y = mx + p)
         * 
         * @param float
         */
        private $slope;
        
        /**
         * The y-intercept value of the line (the p in y = mx + p)
         * 
         * @param float
         */
        private $origin;
        
        /**
         * Build a new awline
         *
         * @param awPoint $p1 First point
         * @param awPoint $p2 Second point
         * @param int $type Style of line (default to solid)
         * @param int $thickness Line thickness (default to 1)
         */
        public function __construct($p1 = NULL, $p2 = NULL, $type = awLine::SOLID, $thickness = 1) {
        
                $this->setLocation($p1, $p2);
                $this->setStyle($type);
                $this->setThickness($thickness);
                
        }
        
        /**
         * Build a line from 4 coords
         *
         * @param int $x1 Left position
         * @param int $y1 Top position
         * @param int $x2 Right position
         * @param int $y2 Bottom position
         */
        public static function build($x1, $y1, $x2, $y2) {
        
                return new awLine(
                        new awPoint($x1, $y1),
                        new awPoint($x2, $y2)
                );
        
        }
        
        /**
         * Change X values of the line
         *
         * @param int $x1 Begin value
         * @param int $x2 End value
         */
        public function setX($x1, $x2) {
                $this->p1->setX($x1);
                $this->p2->setX($x2);
                
                // Resets slope and origin values so they are
                // recalculated when and if needed.
                $this->slope = NULL;
                $this->origin = NULL;
        }
        
        /**
         * Change Y values of the line
         *
         * @param int $y1 Begin value
         * @param int $y2 End value
         */
        public function setY($y1, $y2) {
                $this->p1->setY($y1);
                $this->p2->setY($y2);
                
                // Resets slope and origin values so they are
                // recalculated when and if needed.
                $this->slope = NULL;
                $this->origin = NULL;
        }
        
        /**
         * Change line location
         *
         * @param awPoint $p1 First point
         * @param awPoint $p2 Second point
         */
        public function setLocation($p1, $p2) {
                if(is_null($p1) or $p1 instanceof awPoint) {
                        $this->p1 = $p1;
                }
                if(is_null($p2) or $p2 instanceof awPoint) {
                        $this->p2 = $p2;
                }
                
                // Resets slope and origin values so they are
                // recalculated when and if needed.
                $this->slope = NULL;
                $this->origin = NULL;
        }
        
        /**
         * Get line location
         *
         * @param array Line location
         */
        public function getLocation() {
                return array($this->p1, $this->p2);
        }
        
        /**
         * Get the line size
         *
         * @return float
         */
        public function getSize() {
        
                $square = pow($this->p2->x - $this->p1->x, 2) + pow($this->p2->y - $this->p1->y, 2);
                return sqrt($square);
        
        }
        
        /**
         * Calculate the line slope
         * 
         */
        private function calculateSlope() {
                if($this->isHorizontal()) {
                        $this->slope = 0;
                } else {
                        $slope = ($this->p1->y - $this->p2->y) / ($this->p1->x - $this->p2->x);
                        
                        $this->slope = $slope;
                }
        }
        
        /**
         * Calculate the y-intercept value of the line
         * 
         */
        private function calculateOrigin() {
                if($this->isHorizontal()) {
                        $this->origin = $this->p1->y; // Or p2->y
                } else {
                        $y1 = $this->p1->y;
                        $y2 = $this->p2->y;
                        $x1 = $this->p1->x;
                        $x2 = $this->p2->x;
                        
                        $origin = ($y2 * $x1 - $y1 * $x2) / ($x1 - $x2);
                        
                        $this->origin = $origin;
                }
        }
        
        /**
         * Calculate the slope and y-intercept value of the line
         * 
         */
        private function calculateEquation() {
                $this->calculateSlope();
                $this->calculateOrigin();
        }
        
        /**
         * Get the line slope value
         *
         * @return float
         */
        public function getSlope() {
                if($this->isVertical()) {
                        return NULL;
                } elseif($this->slope !== NULL) {
                        return $this->slope;
                } else {
                        $this->calculateSlope();
                        return $this->slope;
                }
        }
        
        /**
         * Get the line y-intercept value
         * 
         * @return float
         */
        public function getOrigin() {
                if($this->isVertical()) {
                        return NULL;
                } elseif($this->origin !== NULL) {
                        return $this->origin;
                } else {
                        $this->calculateOrigin();
                        return $this->origin;
                }
        }
        
        /**
         * Get the line equation
         * 
         * @return array An array containing the slope and y-intercept value of the line
         */
        public function getEquation() {
                $slope  = $this->getSlope();
                $origin = $this->getOrigin();
                
                return array($slope, $origin);
        }
        
        /**
         * Return the x coordinate of a point on the line
         * given its y coordinate.
         *
         * @param float $y The y coordinate of the Point
         * @return float $x The corresponding x coordinate
         */
        public function getXFrom($y) {
                $x = NULL;
                
                if($this->isVertical()) {
                        list($p, ) = $this->getLocation();
                        $x = $p->x;
                } else {
                        list($slope, $origin) = $this->getEquation();
                        
                        if($slope !== 0) {
                                $y = (float)$y;
                                $x = ($y - $origin) / $slope;
                        }
                }
                
                return $x;
        }
        
        /**
         * Return the y coordinate of a point on the line
         * given its x coordinate.
         *
         * @param float $x The x coordinate of the Point
         * @return float $y The corresponding y coordinate
         */
        public function getYFrom($x) {
                $y = NULL;
                
                if($this->isHorizontal()) {
                        list($p, ) = $this->getLocation();
                        $y = $p->y;
                } else {
                        list($slope, $origin) = $this->getEquation();
                        
                        if($slope !== NULL) {
                                $x = (float)$x;
                                $y = $slope * $x + $origin;
                        }
                }
                
                return $y;
        }
        
        /**
         * Test if the line can be considered as a point
         *
         * @return bool
         */
        public function isPoint() {
                return ($this->p1->x === $this->p2->x and $this->p1->y === $this->p2->y);
        }
        
        /**
         * Test if the line is a vertical line
         *
         * @return bool
         */
        public function isVertical() {
                return ($this->p1->x === $this->p2->x);
        }
        
        /**
         * Test if the line is an horizontal line
         *
         * @return bool
         */
        public function isHorizontal() {
                return ($this->p1->y === $this->p2->y);
        }
        
        /**
         * Returns TRUE if the line is going all the way from the top
         * to the bottom of the polygon surrounding box.
         * 
         * @param $polygon Polygon A Polygon object
         * @return bool
         */
        public function isTopToBottom(awPolygon $polygon) {
                list($xMin, $xMax) = $polygon->getBoxXRange();
                list($yMin, $yMax) = $polygon->getBoxYRange();
                
                if($this->isHorizontal()) {
                        return FALSE;
                } else {                        
                        if($this->p1->y < $this->p2->y) {
                                $top = $this->p1;
                                $bottom = $this->p2;
                        } else {
                                $top = $this->p2;
                                $bottom = $this->p1;
                        }
                        
                        return (
                                $this->isOnBoxTopSide($top, $xMin, $xMax, $yMin)
                                and
                                $this->isOnBoxBottomSide($bottom, $xMin, $xMax, $yMax)
                        );
                }
        }
        
        /**
         * Returns TRUE if the line is going all the way from the left side
         * to the right side of the polygon surrounding box.
         * 
         * @param $polygon Polygon A Polygon object
         * @return bool
         */
        public function isLeftToRight(awPolygon $polygon) {
                list($xMin, $xMax) = $polygon->getBoxXRange();
                list($yMin, $yMax) = $polygon->getBoxYRange();
                
                if($this->isVertical()) {
                        return FALSE;
                } else {
                        if($this->p1->x < $this->p2->x) {
                                $left = $this->p1;
                                $right = $this->p2;
                        } else {
                                $left = $this->p2;
                                $right = $this->p1;
                        }
                }
                
                return (
                        $this->isOnBoxLeftSide($left, $yMin, $yMax, $xMin)
                        and
                        $this->isOnBoxRightSide($right, $yMin, $yMax, $xMax)
                );
        }
        
        private function isOnBoxTopSide(awPoint $point, $xMin, $xMax, $yMin) {
                if(
                        $point->y === $yMin
                        and 
                        $point->x >= $xMin
                        and
                        $point->x <= $xMax
                ) {
                        return TRUE;
                } else {
                        return FALSE;
                }
        }

        private function isOnBoxBottomSide(awPoint $point, $xMin, $xMax, $yMax) {
                if(
                        $point->y === $yMax
                        and
                        $point->x >= $xMin
                        and
                        $point->x <= $xMax
                ) {
                        return TRUE;
                } else {
                        return FALSE;
                }
        }
        
        private function isOnBoxLeftSide(awPoint $point, $yMin, $yMax, $xMin) {
                if(
                        $point->x === $xMin
                        and 
                        $point->y >= $yMin
                        and 
                        $point->y <= $yMax
                ) {
                        return TRUE;
                } else {
                        return FALSE;
                }
        }
        
        private function isOnBoxRightSide(awPoint $point, $yMin, $yMax, $xMax) {
                if(
                        $point->x === $xMax
                        and 
                        $point->y >= $yMin
                        and 
                        $point->y <= $yMax
                ) {
                        return TRUE;
                } else {
                        return FALSE;
                }
        }
        
}

registerClass('Line');

/**
 * A vector is a type of line
 * The sense of the vector goes from $p1 to $p2.
 *
 * @package Artichow
 */
class awVector extends awLine {
        
        /**
         * Get vector angle in radians
         *
         * @return float
         */
        public function getAngle() {
        
                if($this->isPoint()) {
                        return 0.0;
                }
                
                $size = $this->getSize();
        
                $width = ($this->p2->x - $this->p1->x);
                $height = ($this->p2->y - $this->p1->y) * -1;
                
                if($width >= 0 and $height >= 0) {
                        return acos($width / $size);
                } else if($width <= 0 and $height >= 0) {
                        return acos($width / $size);
                } else {
                        $height *= -1;
                        if($width >= 0 and $height >= 0) {
                                return 2 * M_PI - acos($width / $size);
                        } else if($width <= 0 and $height >= 0) {
                                return 2 * M_PI - acos($width / $size);
                        }
                }
        
        }

}

registerClass('Vector');
 

/**
 * Describe a polygon
 *
 * @package Artichow
 */
class awPolygon extends awShape {

        /**
         * Polygon points
         *
         * @var array
         */
        protected $points = array();

        /**
         * Set a point in the polygon
         *
         * @param int $pos Point position
         * @param awPoint $point
         */
        public function set($pos, $point) {
                if(is_null($point) or $point instanceof awPoint) {
                        $this->points[$pos] = $point;
                }
        }
        
        /**
         * Add a point at the end of the polygon
         *
         * @param awPoint $point
         */
        public function append($point) {
                if(is_null($point) or $point instanceof awPoint) {
                        $this->points[] = $point;
                }
        }
        
        /**
         * Get a point at a position in the polygon
         *
         * @param int $pos Point position
         * @return Point
         */
        public function get($pos) {
                return $this->points[$pos];
        }
        
        /**
         * Count number of points in the polygon
         *
         * @return int
         */
        public function count() {
                return count($this->points);
        }
        
        /**
         * Returns all points in the polygon
         *
         * @return array
         */
        public function all() {
                return $this->points;
        }
        
        /**
         * Returns the different lines formed by the polygon vertices
         * 
         * @return array
         */
        public function getLines() {
                $lines = array();
                $count = $this->count();
        
                for($i = 0; $i < $count - 1; $i++) {
                        $lines[] = new Line($this->get($i), $this->get($i + 1));
                }
                
                // "Close" the polygon
                $lines[] = new Line($this->get($count - 1), $this->get(0));

                return $lines;
        }
        
        /**
         * Get the upper-left and lower-right points
         * of the bounding box around the polygon
         * 
         * @return array An array of two Point objects
         */
        public function getBoxPoints() {
                $count = $this->count();
                $x = $y = array();
                
                for($i = 0; $i < $count; $i++) {
                        $point = $this->get($i);
        
                        list($x[], $y[]) = $point->getLocation();
                }
                
                $upperLeft  = new Point(min($x), min($y));
                $lowerRight = new Point(max($x), max($y));
                
                return array($upperLeft, $lowerRight);
        }
        
        /**
         * Return the range of the polygon on the y axis,
         * i.e. the minimum and maximum y value of any point in the polygon
         * 
         * @return array
         */
        public function getBoxYRange() {
                list($p1, $p2) = $this->getBoxPoints();
        
                list(, $yMin) = $p1->getLocation();
                list(, $yMax) = $p2->getLocation();
                
                return array($yMin, $yMax);
        }
        
        /**
         * Return the range of the polygon on the x axis,
         * i.e. the minimum and maximum x value of any point in the polygon
         *
         * @return array
         */
        public function getBoxXRange() {
                list($p1, $p2) = $this->getBoxPoints();
        
                list($xMin, ) = $p1->getLocation();
                list($xMax, ) = $p2->getLocation();
                
                return array($xMin, $xMax);
        }

}

registerClass('Polygon');
?>