New file |
0,0 → 1,832 |
<?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'); |
?> |