Source for file GraphicsGD.php
Documentation is available at GraphicsGD.php
* Description: Class with all Chart drawing methods.
* @copyright (c) 1995-2010 by Steema Software SL. All Rights Reserved. <info@steema.com>
* @link http://www.steema.com
private $iZoomText= false;
private $xCenterOffset= 0;
private $yCenterOffset= 0;
private $rotationCenter= null;
private static $NUMCIRCLEPOINTS = 64;
public static $DARKCOLORQUANTITY = 64;
private static $DARKERCOLORQUANTITY = 128;
function __get( $property ) {
$method = "get{$property}";
function __set ( $property,$value ) {
$method = "set{$property}";
return $this->$method($value);
* Creates a new Graphics object
// $this->colorPalette = Theme::getSkyBluesPalette();
$this->rotationCenter = new Point3D();
$this->iPoints = array();
if ($this->chart != null) {
$this->setAspect($this->chart->getAspect());
/**************************************************************************
* Drawing methods............ *
**************************************************************************/
* Paints the image in rectangle r.
* @param transparent boolean
public function draw($r, $image, $mode, $shapeBorders, $transparent) {
imageAlphaBlending($image, false);
imageSaveAlpha($image, true);
//Get the sizes of both pix
$sourcefile_width= imagesx($this->img);
$sourcefile_height= imagesy($this->img);
$image_width= imagesx($image);
$image_height= imagesy($image);
$dest_x = ( $sourcefile_width / 2 ) - ( $image_width / 2 );
$dest_y = ( $sourcefile_height / 2 ) - ( $image_height / 2 );
imagecopy($this->img, $image, $dest_x, $dest_y, 0, 0,
$image_width, $image_height);
imagecopy($this->img, $image, $dest_x, $dest_y, 0, 0,
$image_width, $image_height);
imagecopyresized($this->img, $image,$dest_x, $dest_y, 0, 0,
$sourcefile_width, $sourcefile_height,
$image_width, $image_height);
if (($shapeBorders->getTopLeft()->getBorderRound() > 0) || ($shapeBorders->getBottomLeft()->getBorderRound() > 0) ||
($shapeBorders->getTopRight()->getBorderRound() > 0) || ($shapeBorders->getBottomRight()->getBorderRound() > 0)) {
* Draws a line with an arrow head of ArrowWidth and ArrowHeight dimensions
public function arrow($filled, $fromPoint, $toPoint,
$headWidth, $headHeight, $z) {
$dx = $toPoint->getX() - $fromPoint->getX();
$dy = $fromPoint->getY() - $toPoint->getY();
$l = sqrt($dx * $dx + $dy * $dy);
if ($l > 0) { // if at least one pixel...
(int) $tmpHoriz = $headWidth;
$xb = $toPoint->getX() * $a->cosA - $toPoint->getY() * $a->sinA;
$yb = $toPoint->getX() * $a->sinA + $toPoint->getY() * $a->cosA;
$a->y = $yb - $tmpHoriz * 0.5;
$a->y = $yb + $tmpHoriz * 0.5;
$tmpHoriz4 = $tmpHoriz * 0.25;
$a->y = $yb - $tmpHoriz4;
$a->y = $yb + $tmpHoriz4;
$a->x = $fromPoint->x * $a->cosA - $fromPoint->y * $a->sinA;
$a->y = $yb - $tmpHoriz4;
$a->y = $yb + $tmpHoriz4;
$tmp = Array($ph, $pg, $pe, $pc, $this->calc3DPoint($toPoint->getX(),$toPoint->getY(),
* Draws Bezier splines for the Point array p at displacement z
$this->internalBezier($z, true, $p);
* Draws Bezier splines for the Point array p
$this->internalBezier(0, false, $p);
private function internalBezier($z, $is3D, $points) {
$this->moveToXYZ($points[0]->x, $points[0]->y, $z);
$this->drawBezier($is3D, $z, $points, 2);
$this->drawBezier($is3D, $z, $points, $t);
} while (!($t > sizeof($points) - 1));
private function drawBezier($is3D, $z, $points, $first) {
$p1 = $points[$first - 2];
$p2 = $points[$first - 1];
for ($t = 1; $t < 32; $t++ ) {
$p = new TeePoint((int) ($p1->x * $mum12 + 2 * $p2->x * $mum1 * $mu +
(int) ($p1->y * $mum12 + 2 * $p2->y * $mum1 * $mu +
* Calculates and returns the XY position in pixels of the XYZ 3D
* Can be used when custom drawing using 3D XYZ coordinates are returned
return new TeePoint(($this->iZoomFactor * ($x - $this->xCenter +
($this->iOrthoX * $z))) + $this->xCenterOffset,
($this->iZoomFactor * ($y - $this->yCenter - ($this->iOrthoY *
$z))) + $this->yCenterOffset);
$zz = $z * $this->c2 - $x * $this->s2;
$tmp = $this->iZoomFactor;
$tmp /= (1 + $this->iZoomPerspec * ($zz * $this->c1 + $y * $this->s1));
return new TeePoint( (($x * $this->c2 + $z * $this->s2) * $tmp) + $this->xCenterOffset,
(($y * $this->c1 - $zz * $this->s1) * $tmp) + $this->yCenterOffset);
* Calculates and returns the XY position as double of the XYZ 3D
* Can be used when custom drawing using 3D XYZ coordinates are returned
return new PointDouble((int) ($this->iZoomFactor * ($x - $this->xCenter + ($this->iOrthoX * $z))) +
(int) ($this->iZoomFactor * ($y - $this->yCenter - ($this->iOrthoY * $z))) +
$zz = $z * $this->c2 - $x * $this->s2;
$tmp = $this->iZoomFactor;
$tmp /= (1 + $this->iZoomPerspec * ($zz * $this->c1 + $y * $this->s1));
return new PointDouble((int) (($x * $this->c2 + $z * $this->s2) * $tmp) + $this->xCenterOffset,
(int) (($y * $this->c1 - $zz * $this->s1) * $tmp) + $this->yCenterOffset);
* Calculates and returns the XY position in pixels of the point p Z 3D
* Can be used when custom drawing using 3D XYZ coordinates are returned
return $this->calc3DPos($source->getX(), $source->getY(), $source- getZ());
* Calculates and returns the XY position in pixels of the point p Z 3D
* Can be used when custom drawing using 3D XYZ coordinates are returned
return $this->calc3DPos($source->getX(), $source->getY(), $z);
* Calculates and returns the XY position in pixels of the point p with
* Z = 0 3D coordinate.<br>
* Can be used when custom drawing using 3D XYZ coordinates are returned
return $this->calc3DPos($source->x, $source->y, 0);
$PERSPECFACTOR = 1.0 / 150.0;
$perspec = $this->aspect->getPerspective();
$this->iPerspec = ($perspec > 0);
$this->iZoomPerspec = $this->iZoomFactor * $perspec * $PERSPECFACTOR / $tmp;
if (!$this->aspect->getOrthogonal()) {
$rx = - $this->aspect->getElevation();
$ry = - $this->aspect->getRotation();
$rz = $this->aspect->getTilt();
$this->c2s3 = $this->c2 * $this->s3;
$this->c2c3 = max(1E-5, $this->c2 * $this->c3);
$this->tempXX = max(1E-5, $this->s1 * $this->s2 * $this->s3 + $this->c1 * $this->c3);
$this->tempYX = ($this->c3 * $this->s1 * $this->s2 - $this->c1 * $this->s3);
$this->tempXZ = ($this->c1 * $this->s2 * $this->s3 - $this->c3 * $this->s1);
$this->tempYZ = ($this->c1 * $this->c3 * $this->s2 + $this->s1 * $this->s3);
if (!$this->rectClip== null)
$x = $this->rectClip->getX();
$y = $this->rectClip->getY();
imagecopymerge($this->tmpImg, $this->img,$x,$y,$x,$y,
$this->rectClip->getWidth(),$this->rectClip->getHeight(),100);
imagecopy($this->img,$this->tmpImg,0,0,0,0,imagesx($this->img),imagesy($this->img));
if (!$this->polygonClip== null)
* Creates a Windows GDI clipping region and selects it into
* TChart.<!-- -->Canvas device context handle.<br>
$this->rectClip->x= $left;
$this->rectClip->width= $right- $left;
$this->rectClip->height= $bottom- $top;
$this->tmpImg = imagecreatetruecolor(imagesx($this->img), imagesy($this->img));
// Converts to Transparent image
imagesavealpha($this->tmpImg, true);
/* TODO Re-check if required
$trans_colour = imagecolorallocatealpha($this->tmpImg, 0, 0, 0, 127);
imagefill($this->tmpImg, 0, 0, $trans_colour);
imagecopy($this->tmpImg,$this->img,0,0,0,0,imagesx($this->img),imagesy($this->img));
* Creates a Windows GDI clipping region and selects it into
* TChart.<!-- -->Canvas device context handle.<br>
* @param polygonPoints - Array of TeePoints
$this->polygonClip= Array();
$this->polygonClip= $polygonPoiints;
* Paints a cone with Cone Percent.<br>
* Use <br>ONLY with OPENGL</b>.<br>
* This parameter varies the apex size
* as a percentage of the base.<br>
* @param vertical boolean
* @param darkSides boolean
* @param conePercent int varies the apex size as a percentage of the base.
public function cone($vertical, $r, $z0, $z1, $darkSides, $conePercent= 0) {
$this->internalCylinder($vertical, $r, $z0, $z1, $darkSides, $conePercent);
* Draws cylinder toggle Boolean for vertical or horizontal cylinder.
* @param vertical boolean
* @param darkSides boolean
public function cylinder($vertical, $r, $z0, $z1, $darkSides) {
$this->internalCylinder($vertical, $r, $z0, $z1, $darkSides, 100);
private function internalCylinder($vertical, $r, $z0, $z1, $dark3D, $conePercent) {
$NUMCYLINDERSIDES = 16; // 256
$STEP = 2.0 * M_PI / $NUMCYLINDERSIDES;
$STEPCOLOR = 256 / $NUMCYLINDERSIDES; // 512
$oldColor = $this->brush->getColor();
(int) $zRadius = ($z1 - $z0) / 2;
(int) $tmpMidZ = ($z1 + $z0) / 2;
(int) $radius = ($r->getRight() - $r->x) / 2;
(int) $tmpMid = ($r->getRight() + $r->x) / 2;
(int) $tmpSize = abs($r->getBottom() - $r->y);
for ($t = 0; $t < $NUMCYLINDERSIDES; $t++ ) {
(double) $tmpSin = sin(($t - 3) * $STEP);
(double) $tmpCos = cos(($t - 3) * $STEP);
if ($r->y < $r->getBottom()) {
$poly[$t]->y = $r->getBottom();
$tmpPoly[1] = $this->calc3DPoint($poly[0]->x, $poly[0]->y + $tmpSize, $poly[0]->z);
$tmpSin = sin((1 - 4) * $STEP);
$tmpCos = cos((1 - 4) * $STEP);
$tmpPoly[0] = $this->calc3DPoint($poly[0]->x,$poly[0]->y,$poly[0]->z);
for ($t = 1; $t < $NUMCYLINDERSIDES; $t++ ) {
$tmpPoly[2] = $this->calc3DPoint($poly[$t]->x, $poly[$t]->y + $tmpSize,
$tmpSin = sin(($t - 3) * $STEP);
$tmpCos = cos(($t - 3) * $STEP);
$tmpPoly[3] = $this->calc3DPoint($poly[$t]->x,$poly[$t]->y,$poly[$t]->z);
$tmp = ($tmpPoly[0]->x - $tmpPoly[2]->x + $tmpPoly[1]->x -
$p = Array($tmpPoly[0], $tmpPoly[1], $tmpPoly[2], $tmpPoly[3]);
$tmpPoly[0] = $tmpPoly[3];
$tmpPoly[1] = $tmpPoly[2];
$radius = ($r->getBottom() - $r->y) / 2;
$tmpMid = ($r->getBottom() + $r->y) / 2;
$tmpSize = $r->getRight() - $r->X;
for ($t = 0; $t < $NUMCYLINDERSIDES; $t++ ) {
$tmpSin = sin(($t - 4) * $STEP);
$tmpCos = cos(($t - 4) * $STEP);
if ($r->x < $r->getRight()) {
$poly[$t]->x = $r->getRight();
$tmpSize = abs($r->getRight() - $r->x);
$tmpPoly[1] = $this->calc3DPoint($poly[0]->x - $tmpSize, $poly[0]->y, $poly[0]->z);
$tmpSin = sin( - 4 * $STEP);
$tmpCos = cos( - 4 * $STEP);
$tmpPoly[0] = $this->calc3DPoint($poly[0]->x,$poly[0]->y,$poly[0]->z);
for ($t = 1; $t < $NUMCYLINDERSIDES; $t++ ) {
$tmpPoly[2] = $this->calc3DPoint($poly[$t]->x - $tmpSize, $poly[$t]->y,
$tmpSin = sin(($t - 4) * $STEP);
$tmpCos = cos(($t - 4) * $STEP);
$tmpPoly[3] = $this->calc3DPoint($poly[$t]->x,$poly[$t]->y,$poly[$t]->z);
$tmp = ($tmpPoly[0]->y - $tmpPoly[2]->y + $tmpPoly[1]->y -
$p = Array($tmpPoly[0], $tmpPoly[1], $tmpPoly[2], $tmpPoly[3]);
$tmpPoly[0] = $tmpPoly[3];
$tmpPoly[1] = $tmpPoly[2];
for ($t = 0; $t < $NUMCYLINDERSIDES; $t++ ) {
$tmpPoly[$t] = $this->calc3DPoint($poly[$t]->x,$poly[$t]->y,$poly[$t]->z);
$oc = array(0xFF & ($oc >> 0x10), 0xFF & ($oc >> 0x8), 0xFF & $oc);
$ic = array(0xFF & ($ic >> 0x10), 0xFF & ($ic >> 0x8), 0xFF & $ic);
$c0 = ($oc[0] - $ic[0]) / $w;
$c1 = ($oc[1] - $ic[1]) / $w;
$c2 = ($oc[2] - $ic[2]) / $w;
$r = $oc[0] - floor($i * $c0);
$g = $oc[1] - floor($i * $c1);
$b = $oc[2] - floor($i * $c2);
$c = imagecolorallocate($image, $r, $g, $b);
imagefilledellipse($image, $cx, $cy, $w- $i, $h- $j, $c);
if($i >= $w && $j >= $h){
$oc = array(0xFF & ($oc >> 0x10), 0xFF & ($oc >> 0x8), 0xFF & $oc);
$ic = array(0xFF & ($ic >> 0x10), 0xFF & ($ic >> 0x8), 0xFF & $ic);
$c0 = ($oc[0] - $ic[0]) / $w;
$c1 = ($oc[1] - $ic[1]) / $w;
$c2 = ($oc[2] - $ic[2]) / $w;
$r = $oc[0] - floor($i * $c0);
$g = $oc[1] - floor($i * $c1);
$b = $oc[2] - floor($i * $c2);
$t = $ot - floor($i * $ct);
$c = imagecolorallocatealpha($image, $r, $g, $b, $t);
imageellipse($image, $cx, $cy, $w- $i, $h- $j, $c);
if($i >= $w && $j >= $h){
private function clipToRight($rect, $minZ, $maxZ) {
$p[0] = $this->calc3DPoint($rect->x, $rect->getBottom(), $minZ);
$pb = $this->calc3DPoint($rect->getRight(), $rect->y, $minZ);
$p[2] = ($pb->getY() < $pa->getY()) ? $pb : $pa;
$p[3] = $this->calc3DPoint($rect->getRight(), $rect->y, $maxZ);
$pc = $this->calc3DPoint($rect->getRight(), $rect->getBottom(), $maxZ);
$pd = $this->calc3DPoint($rect->getRight(), $rect->y, $minZ);
$p[4] = ($pd->getX() > $pc->getX()) ? $pd : $pc;
$p[5] = $this->calc3DPoint($rect->getRight(), $rect->getBottom(), $minZ);
if ($p[5]->getX() < $p[0]->getX()) {
$p[0]->setX($p[5]->getX());
if ($pd->getY() < $p[0]->getY()) {
$p[0]->setY($pd->getY());
$c1 = imagecolorallocate($this->img, $this->getBrush()->getColor()->red,
private function clipToLeft($rect, $minZ, $maxZ) {
$c1 = imagecolorallocate($this->img, $this->getBrush()->getColor()->red,
clippolygon imagepolygon($this->img, array (
$this->calc3DPoint($rect->x, $rect->getBottom(), $minZ),
$this->calc3DPoint($rect->x, $rect->getBottom(), $maxZ),
$this->calc3DPoint($rect->x, $rect->y, $maxZ),
$this->calc3DPoint($rect->getRight(), $rect->y, $maxZ),
$this->calc3DPoint($rect->getRight(), $rect->y, $minZ),
$this->calc3DPoint($rect->getRight(), $rect->getBottom(), $minZ)),
public function cuber ($rect, $z0, $z1, $darkSides) {
$this->cube($rect->getLeft(), $rect->getTop(), $rect->getRight(), $rect->getBottom(), $z0, $z1, $darkSides);
* Draws a Cube with Dark Sides.
* @param darkSides boolean
public function cube($left, $top, $right, $bottom, $z0, $z1, $darkSides) {
$oldColor = $this->brush->getColor();
$this->iPoints[3] = $this->calc3DPoint($left, $bottom, $z0);
if ($this->culling() > 0) {
$this->polygonFour(); // front-side
$this->iPoints[0] = $this->calc3DPos($left, $top, $z1);
$this->iPoints[1] = $this->calc3DPos($right, $top, $z1);
$this->iPoints[2] = $this->calc3DPos($right, $bottom, $z1);
$this->iPoints[3] = $this->calc3DPos($left, $bottom, $z1);
$this->polygonFour(); // back-side
$this->iPoints[2] = $this->calc3DPos($right, $bottom, $z1);
if ($this->culling() > 0) {
$this->polygonFour(); // left-side
$this->iPoints[1] = $this->calc3DPos($left, $top, $z1);
$this->iPoints[2] = $this->calc3DPos($left, $bottom, $z1);
$this->iPoints[3] = $this->calc3DPos($left, $bottom, $z0);
$tmp = ($this->iPoints[3]->getX() - $this->iPoints[0]->getX()) *
($this->iPoints[1]->getY() - $this->iPoints[0]->getY()) -
($this->iPoints[1]->getX() - $this->iPoints[0]->getX()) *
($this->iPoints[3]->getY() - $this->iPoints[0]->getY());
$this->polygonFour(); // right-side
$this->iPoints[3] = $this->calc3DPos($left, $top, $z1);
$tmp = ($p0->getX() - $p1->getX()) * ($p3->getY() - $p1->getY()) -
($p3->getX() - $p1->getX()) * ($p0->getY() - $p1->getY());
$this->polygonFour(); // top-side
$this->iPoints[0] = $this->calc3DPos($left, $bottom, $z0);
$this->iPoints[2] = $this->calc3DPos($right, $bottom, $z1);
$this->iPoints[1] = $this->calc3DPos($left, $bottom, $z1);
if ($this->culling() < 0) {
$this->brush->setColor($oldColor);
* Creates a cubic Windows GDI clipping region.
public function clipCube($rect, $minZ, $maxZ) {
if ($this->aspect->getElevation() == 270) {
if (($this->aspect->getRotation() == 270) ||
($this->aspect->getRotation() == 360)) {
$tmpLT = $this->calc3DPoint($rect->x, $rect->y, $minZ);
$tmpRB = $this->calc3DPoint($rect->getRight(), $rect->y, $maxZ);
$this->clipRectangle($tmpLT->x, $tmpLT->y, $tmpRB->x, $tmpRB->y);
if ($this->aspect->getOrthoAngle() > 90) {
$this->clipToLeft($rect, $minZ, $maxZ);
$this->clipToRight($rect, $minZ, $maxZ);
if ($this->aspect->getRotation() >= 270) {
$this->clipToRight($rect, $minZ, $maxZ);
$this->clipRectangle($rect->x + 1, $rect->y + 1, $rect->getRight() - 1,
private function culling() {
return (($this->iPoints[3]->getX() - $this->iPoints[2]->getX()) * ($this->iPoints[1]->getY() -
$this->iPoints[2]->getY())) - (($this->iPoints[1]->getX() - $this->iPoints[2]->getX()) *
($this->iPoints[3]->getY() - $this->iPoints[2]->getY()));
* Creates and initialize the image
// Converts to Transparent image
imagesavealpha($this->img, true);
/* Check if following line must be added for round borders
$trans_colour = imagecolorallocatealpha($this->img, 0, 0, 0, 127);
imagefill($this->img, 0, 0, $trans_colour);
$this->textColor = new Color(0, 0, 0);
private function doBevelRect($rect, $a, $b) {
$topRight = new TeePoint($rect->getRight() - 1, $rect->y);
$bottomLeft = new TeePoint($rect->x, $rect->getBottom() - 1);
$bottomRight = new TeePoint($rect->getRight() - 1, $rect->getBottom() - 1);
$this->___line($a, $rect->getLocation(), $topRight);
$this->___line($a, $rect->getLocation(), $bottomLeft);
$this->___line($b, $bottomLeft, $bottomRight);
$this->___line($b, $bottomRight, $topRight);
public function doRev() {
$black = imagecolorallocate($this->img, 150, 150, 150);
$x = imagesx($this->img);
$y = imagesy($this->img)- 6;
$text = "EVALUATION VERSION";
imagefttext($this->img, 25, 45, 25, $y+ 3, $black, $font_file, $text);
* Draws an Ellipse bounding Rectangle r.
$this->ellipse($r->getX(), $r->getY(), $r->getRight(), $r->getBottom());
* Ellipse bounding Rectangle r at z depth.
$this->ellipse($r->getX(), $r->getY(), $r->getRight(), $r->getBottom(), $z);
$this->transparentEllipse($p0->getX(), $p0->getY(), $p1->getX(), $p1->getY());
* Ellipse bounding Rect (X1,Y1,X2,Y2) at Z position at angle.
public function ellipse($x1, $y1, $x2, $y2, $z= 0, $angle= 0) {
// TODO - Here draw directly the ellipse with p1 and p2 $this->ellipsePoints($p1, $p2);
for ($t = 0; $t < 3; $t++ ) {
$xCenter = ($x2 + $x1) * 0.5;
$yCenter = ($y2 + $y1) * 0.5;
$xRadius = ($x2 - $x1) * 0.5;
$yRadius = ($y2 - $y1) * 0.5;
$tmpPiStep = 2 * M_PI / (self::$NUMCIRCLEPOINTS - 1);
// initial rotation (rotation matrix elements)
$tmpSinAngle = sin($angle);
$tmpCosAngle = cos($angle);
for ($t = 0; $t < self::$NUMCIRCLEPOINTS; $t++ ) {
$tmpSin = sin($t * $tmpPiStep);
$tmpCos = cos($t * $tmpPiStep);
$tmpX = $xRadius * $tmpSin;
$tmpY = $yRadius * $tmpCos;
( - $tmpX * $tmpSinAngle +
$old = $this->getPen()->getVisible();
$this->getPen()->setVisible(false);
for ($t = 1; $t < self::$NUMCIRCLEPOINTS; $t++ ) {
// has to be in loop because the Polygon
// transforms the positions from 3d to 2d in each pass
$this->polygonz($z, $points);
// close it up with polygon from last to first
$points[1] = $p[self::$NUMCIRCLEPOINTS - 1];
$this->polygonz($z, $points);
$this->getPen()->setVisible($old);
if ($this->getPen()->getVisible()) {
$color = imagecolorallocate($this->img, $this->getBrush()->getColor()->red,
// updates x,y,width,height to be used in imagefilledellipse correctly
if ($this->brush->getVisible()) {
imagefilledellipse($this->img,$x1,$y1,$tmpWidth,$tmpHeight,$color);
if ($this->getPen()->getVisible()) {
// Gets the pen color and style (dot , dashed, ...)
$penColorStyle = $this->getPenColorStyle();
imagesetstyle($this->img, $penColorStyle);
// Assign the pen width for the image
imagesetthickness ( $this->img, $this->pen->getWidth());
for ($i= 0;$i<= $this->pen->getWidth();$i++ )
imageellipse($this->img,$x1,$y1,$tmpWidth+ $i,$tmpHeight+ $i,IMG_COLOR_STYLED);
$this->ellipse($p0->getX(), $p0->getY(), $p1->getX(), $p1->getY());
* Ellipse bounding rectangle r with Z offset at angle.
$this->ellipse($r->getX(), $r->getY(), $r->getWidth(),
$r->getHeight(), $z, $angle); // $r->getRight(), $r->getBottom(), $z, $angle);
* Determines the Font Height to be used for outputted text when using the
$tmpAngle = $this->aspect->getOrthoAngle();
$tmpAngle = 180 - $tmpAngle;
$tmpSin = sin($this->aspect->getOrthoAngle() *
$tmpCos = cos($this->aspect->getOrthoAngle() *
$this->iOrthoY = ($tmpCos < 0.01) ? 1 : $tmpSin / $tmpCos;
$this->iZoomFactor = 0.01 * $this->aspect->getZoom();
$this->iZoomText = $this->aspect->getZoomText();
$this->brush->_applyDark($c, $quantity);
* @param integer line start (X)
* @param integer line start (Y)
* @param integer line end (X)
* @param integer line end (Y)
* @param Color line color
* @param integer line width
function line($x1, $y1, $x2, $y2, $color= null, $width = - 1)
$color = imagecolorallocate($this->img, $this->pen->getColor()->red,
$this->pen->getColor()->green,
$this->pen->getColor()->blue);
imageantialias($this->img,false);
// Gets the pen color and style (dot , dashed, ...)
$penColorStyle = $this->getPenColorStyle();
imagesetstyle($this->img, $penColorStyle);
// Assign the pen width for the image
$width = $this->pen->getWidth();
// imageantialias($this->img,true);
imagesetthickness ($this->img, $width);
// imageantialias($this->img,true);
imagesetthickness ($this->img, $width);
imageline($this->img, $x1, $y1, $x2, $y2, IMG_COLOR_STYLED);
// imageantialias($this->img,false);
imageantialias($this->img,true);
* Draws a Line between co-ordinates with z depth offset.
public function _line($x0, $y0, $x1, $y1, $z= 0) {
* Draws a Line between point p0 and point p1.
* @param p0 Point is origin xy
* @param p1 Point is destination xy
public function __line($p0, $p1) {
$this->line($p0->getX(), $p0->getY(), $p1->getX(), $p1->getY());
$this->moveToXY($p1->getX(),$p1->getY()); // review
* Draws a Line between point p0 and point p1 using specific pen.
* @param pen ChartPen id the pen used
* @param p0 Point is origin xy
* @param p1 Point is destination xy
public function ___line($pen, $p0, $p1) {
// Gets the pen color and style (dot , dashed, ...)
$penColorStyle = $this->getPenColorStyle();
imagesetstyle($this->img, $penColorStyle);
// Assign the pen width for the image
imagesetthickness ( $this->img, $this->pen->getWidth());
imageline($this->img, $p0->getX(),$p0->getY(),$p1->getX(),$p1->getY(),
* Draws a line to Point with z depth offset.
public function lineTo($p, $z) {
$this->___lineTo($p->getX(), $p->getY(), $z);
* Draws a line to Point with z = 0 depth offset.
* Draws line from present position to end co-ordinates with z depth offset.
* Draws a Line to 3D Point.
* Draws line from present position to end co-ordinates with z depth offset.
* Sets the value of PenPos to x and y co-ordinates before calling LineTo.
* Sets the value of PenPos to Point p before calling LineTo.
$this->moveToXY($p->getX(), $p->getY());
* Sets the value of PenPos to x, y and z co-ordinates before calling
* Sets the value of PenPos to Point p with z depth offset before calling
$p2 = $this->calc3DPos($p->getX(), $p->getY(), $z);
* Sets the value of PenPos to 3D Point p before calling LineTo.
* Draws a Line from (X,Y,Z0) to (X,Y,Z1).
public function zLine($x, $y, $z0, $z1) {
$c1 = imagecolorallocatealpha($this->img, $this->pen->getColor()->red,
$this->pen->getColor()->green,
$this->pen->getColor()->blue,
$this->pen->getColor()->alpha);
imagesetthickness ( $this->img, $this->pen->getWidth());
imageline($this->img, $p1->getX(),$p1->getY(),$p2->getX(),$p2->getY(),$c1);
* Draws a Horizontal at z depth position.
$c1 = imagecolorallocatealpha($this->img, $this->pen->getColor()->red,
$this->pen->getColor()->green,
$this->pen->getColor()->blue,
$this->pen->getColor()->alpha);
// Gets the pen color and style (dot , dashed, ...)
$penColorStyle = $this->getPenColorStyle();
// WORKAROUND for legend symbol when series lines and legend custom position true
imagesetstyle($this->img, $penColorStyle);
// Assign the pen width for the image
// if ($this->getPen()->getWidth()>1)
imagesetthickness ( $this->img, $this->pen->getWidth());
// TODO review - workaround for legend symbol when series lines and legend custom position true
imageline($this->img, $p1->getX(),$p1->getY(),$p2->getX(),$p2->getY(),IMG_COLOR_STYLED);
imageline($this->img, $p1->getX(),$p1->getY(),$p2->getX(),$p2->getY(),$c1);
* Draws a Vertical Line from (X,Top) to (X,Bottom) at z depth position.
// Assign the pen width for the image
imagesetthickness ( $this->img, $this->pen->getWidth());
// Gets the pen color and style (dot , dashed, ...)
$penColorStyle = $this->getPenColorStyle();
imagesetstyle($this->img, $penColorStyle);
imageline($this->img, $p1->getX(),$p1->getY(),$p2->getX(),$p2->getY(),
* Draw a filled gray box with thick borders and darker corners.
* @param integer top left coordinate (x)
* @param integer top left coordinate (y)
* @param integer bottom right coordinate (x)
* @param integer bottom right coordinate (y)
* @param Color edge color
* @param Color corner color
public function outlinedBox($x1, $y1, $x2, $y2, $color0, $color1) {
if ($this->brush->getVisible()) {
if ($this->getBrush()->getGradient()->getVisible()== true) {
$colA = array($this->getBrush()->getGradient()->getStartColor()->getRed(),
$this->getBrush()->getGradient()->getStartColor()->getGreen(),
$this->getBrush()->getGradient()->getStartColor()->getBlue());
$colB = array($this->getBrush()->getGradient()->getEndColor()->getRed(),
$this->getBrush()->getGradient()->getEndColor()->getGreen(),
$this->getBrush()->getGradient()->getEndColor()->getBlue());
$penWidth= $this->getPen()->getWidth();
$x1+ $penWidth, $y1+ $penWidth,
imagefilledrectangle($this->img, $x1, $y1, $x2, $y2, $color0->getColor($this->img));
imagerectangle($this->img, $x1, $y1, $x1 + 1, $y1 + 1, $color1->getColor($this->img));
imagerectangle($this->img, $x2 - 1, $y1, $x2, $y1 + 1, $color1->getColor($this->img));
imagerectangle($this->img, $x1, $y2 - 1, $x1 + 1, $y2, $color1->getColor($this->img));
imagerectangle($this->img, $x2 - 1, $y2 - 1, $x2, $y2, $color1->getColor($this->img));
public function paintBevel($bevel, $rect, $width, $one, $two) {
$a = new ChartPen(null,$one);
$this->doBevelRect($rect, $a, $b);
* Draws a 3D Pie slice using start Angle and end Angle and donut percent.
* @param startAngle double
* @param darkSides boolean
* @param drawSides boolean
* @param donutPercent int
/* public function pie($xCenter, $yCenter, $xRadius, $yRadius, $z0,
$z1, $startAngle, $endAngle, $darkSides, $drawSides, $donutPercent=0) {
if ($this->pie3D == null) {
$this->pie3D = new Pie3D($this);
$this->pie3D->pie($xCenter, $yCenter, $xRadius, $yRadius, $z0, $z1, $startAngle,
$endAngle, $darkSides, $drawSides, $donutPercent);
public function pie($xCenter, $yCenter, $xOffset, $yOffset, $xRadius,
$yRadius, $z0, $z1, $startAngle, $endAngle,
$darkSides, $drawSides, $donutPercent,
$bevelPercent, $edgeStyle, $last/*, Shadow shadow*/)
if ($this->pie3D == null) {
$this->pie3D = new Pie3D($this);
$this->pie3D->pie( $xCenter + $xOffset, $yCenter - $yOffset, $xRadius, $yRadius, $z0, $z1,
$startAngle, $endAngle, $darkSides, $drawSides,
$donutPercent, $bevelPercent, $edgeStyle, $last);
* Draws a vertical or horizontal Pyramid with optional dark shaded sides.
* @param vertical boolean
* @param darkSides boolean
public function pyramidRect($vertical, $r, $z0, $z1, $darkSides) {
$this->pyramid($vertical, $r->x, $r->y, $r->getRight(), $r->getBottom(), $z0, $z1,
* Draws a vertical or horizontal Pyramid with optional dark shaded sides.
* @param vertical boolean
* @param darkSides boolean
public function pyramid($vertical, $left, $top, $right, $bottom, $z0, $z1, $darkSides) {
$pTop = $this->calc3DPoint(($left + $right) / 2, $top, ($z0 + $z1) / 2);
$tmpArray = Array($p0, $pTop, $p1);
$tmpArray = Array($p0, $pTop, $p2);
$tmpArray = Array($p1, $pTop, $p3);
if (($top < $bottom) && ($p2->y < $pTop->y)) {
$tmpArray = Array($pTop, $p2, $p3);
$this->rectangleY($left, $bottom, $right, $z0, $z1);
$pTop = $this->calc3DPoint($right, ($top + $bottom) / 2, ($z0 + $z1) / 2);
$tmpArray = Array($p0, $pTop, $p1);
$tmpArray = Array($p0, $pTop, $p2);
$this->rectangleZ($left, $top, $bottom, $z0, $z1);
* Sets / returns the color used to fill spaces when displaying text
* or filling with brushes of different style other than bsSolid.<br>
* Brush.Visible must be set to true.
return $this->brush->getColor();
$this->brush->setColor($value);
* Draws a pyramid with a truncated apex of variable thickness.
public function pyramidTrunc($r, $startZ, $endZ, $truncX, $truncZ) {
$p = new InternalPyramidTrunc();
* Draws a polygon (Point p1, Point p2) at Z depth offset.
public function plane($p1, $p2, $z0, $z1) {
$this->iPoints[0] = $this->calc3DPos($p1->getX(), $p1->getY(), $z0);
$this->iPoints[1] = $this->calc3DPos($p2->getX(), $p2->getY(), $z0);
$this->iPoints[2] = $this->calc3DPos($p2->getX(), $p2->getY(), $z1);
$this->iPoints[3] = $this->calc3DPos($p1->getX(), $p1->getY(), $z1);
* Draws a polygon (Point p1, Point p2, Point p3, Point p4) at Z depth
public function _plane($p1, $p2, $p3, $p4, $z) {
$this->iPoints[0] = $this->calc3DPos($p1->getX(), $p1->getY(), $z);
$this->iPoints[1] = $this->calc3DPos($p2->getX(), $p2->getY(), $z);
$this->iPoints[2] = $this->calc3DPos($p3->getX(), $p3->getY(), $z);
$this->iPoints[3] = $this->calc3DPos($p4->getX(), $p4->getY(), $z);
* Draws a polygon of four points.
$this->iPoints[0] = $this->calc3DPoint($p[0]->x, $p[0]->y, $z0);
$this->iPoints[1] = $this->calc3DPoint($p[1]->x, $p[1]->y, $z0);
$this->iPoints[2] = $this->calc3DPoint($p[2]->x, $p[2]->y, $z1);
$this->iPoints[3] = $this->calc3DPoint($p[3]->x, $p[3]->y, $z1);
if ($this->brush->getVisible()) {
$c1 = imagecolorallocatealpha($this->img, $this->getBrush()->getColor()->red,
$p1 = imagecolorallocatealpha($this->img, $this->getPen()->getColor()->red,
$this->getPen()->getColor()->green,
$this->getPen()->getColor()->blue,
$this->getPen()->getTransparency());
for ($tt= 0;$tt < sizeof($points); $tt++ ) {
$tmpTeePointDouble = $points[$tt];
$tmpX= $tmpTeePointDouble->getX();
$tmpY= $tmpTeePointDouble->getY();
if (count($tmpArray2) >= 3) {
imageantialias($this->img,true);
imagefilledpolygon($this->img, $tmpArray2, count($tmpArray2)/ 2, $c1);
imageantialias($this->img,false);
if ($this->getPen()->getVisible()) {
// Gets the pen color and style (dot , dashed, ...)
$penColorStyle = $this->getPenColorStyle();
imagesetstyle($this->img, $penColorStyle);
// Assign the pen width for the image
imagesetthickness ( $this->img, $this->pen->getWidth());
if (count($tmpArray2) >= 3) {
imageantialias($this->img,true);
imagepolygon($this->img, $tmpArray2, count($tmpArray2)/ 2, $p1);
imageantialias($this->img,false);
* Draws a polygon with z position offset.
for ($t = 0; $t < sizeof($p); $t++ ) {
$p[$t] = $this->calc3DPoint($p[$t]->getX(),$p[$t]->getY(), $z);
$p = Array($p0, $p1, $p2);
if ($this->brush->getVisible()) {
$c1 = imagecolorallocatealpha($this->img, $this->getBrush()->getColor()->red,
$p1 = imagecolorallocatealpha($this->img, $this->getPen()->getColor()->red,
$this->getPen()->getColor()->green,
$this->getPen()->getColor()->blue,
$this->getPen()->getTransparency());
$tmpX= $tmpTeePoint->getX();
$tmpY= $tmpTeePoint->getY();
if (count($tmpArray2) >= 3) {
imageantialias($this->img,true);
imagefilledpolygon($this->img, $tmpArray2, count($tmpArray2)/ 2, $c1);
imageantialias($this->img,false);
if ($this->getPen()->getVisible()) {
// Gets the pen color and style (dot , dashed, ...)
$penColorStyle = $this->getPenColorStyle();
imagesetstyle($this->img, $penColorStyle);
// Assign the pen width for the image
imagesetthickness ( $this->img, $this->pen->getWidth());
if (count($tmpArray2) >= 3) {
imageantialias($this->img,true);
imagepolygon($this->img, $tmpArray2, count($tmpArray2)/ 2, $p1);
imageantialias($this->img,false);
private function polygonFour() {
if ($this->brush->getVisible()) {
$c1 = imagecolorallocatealpha($this->img, $this->getBrush()->getColor()->red,
$p1 = imagecolorallocatealpha($this->img, $this->getPen()->getColor()->red,
$this->getPen()->getColor()->green,
$this->getPen()->getColor()->blue,
$this->getPen()->getTransparency());
for ($tt= 0;$tt < count($this->iPoints); $tt++ ) {
$tmpTeePoint = $this->iPoints[$tt];
$tmpX= $tmpTeePoint->getX();
$tmpY= $tmpTeePoint->getY();
if (count($tmpArray2) >= 3) {
imageantialias($this->img,true);
imagefilledpolygon($this->img, $tmpArray2, count($tmpArray2)/ 2, $c1);
imageantialias($this->img,false);
if ($this->getPen()->getVisible()) {
// Gets the pen color and style (dot , dashed, ...)
$penColorStyle = $this->getPenColorStyle();
imagesetstyle($this->img, $penColorStyle);
// Assign the pen width for the image
imagesetthickness ( $this->img, $this->pen->getWidth());
if (count($tmpArray2) >= 3) {
imageantialias($this->img,true);
imagepolygon($this->img, $tmpArray2, count($tmpArray2)/ 2, $p1);
imageantialias($this->img,false);
* Draws a series of line segments to join point array p at z displacement.
$tmpP = Array(); //new Point[l];
for ($t = 0; $t < $l; $t++ ) {
$tmpP[$t] = $this->calc3DPoint($p[$t]->getX(),$p[$t]->getY(), $z);
for ($t = 1; $t < $l; $t++ ) {
$this->line($tmpP[$t - 1]->getX(),$tmpP[$t - 1]->getY(),
$tmpP[$t]->getX(),$tmpP[$t]->getY());
* @param integer text coordinate (x)
* @param integer text coordinate (y)
* @param Color text color
* @param string text value
* @param string font file name
* @param bitfield text alignment
public function printText($img, $px, $py, $text, $align = - 1) {
$color = $font->getBrush()->getColor();
$fontFileName = $font->getName();
$fontSize = $font->getFontSize();
$textWidth = $this->textWidth($text); // $lrx - $llx;
$textHeight = $this->textHeight($text); // $fontSize; // $lry - $ury;
/*if (in_array (StringAlignment::$VERTICAL_TOP_ALIGN, $align)) {
imagettftext($img, $fontSize, $angle, $px, $py, $color->getColor($img),
* Print text centered horizontally on the image.
* @param integer text coordinate (y)
* @param Color text color
* @param string text value
* @param string font file name
public function printCentered($img, $py, $color, $text, $fontFileName) {
$this->printText($img, imagesx($img) / 2, $py, $color, $text, $fontFileName,
* Print text in diagonal.
* @param integer text coordinate (x)
* @param integer text coordinate (y)
* @param Color text color
* @param string text value
$fontSize = $font->getFontSize();
$fontFileName = $font->getName();
$color = $font->getBrush()->getColor(); // $this->textColor;
list ($lx, $ly, $rx, $ry) = imageftbbox($fontSize, 0, $fontFileName,
strtoupper($text), array("linespacing" => $lineSpacing));
imagettftext($img, $fontSize, $angle, $px, $py, $color->getColor($img),
* Internal use. Calculates the projection co-ordinates for rectangle
* @param maxDepth int is the max shape depth
* @param r Rectangle is the projected shape rectangle
$this->xCenterOffset = $this->xCenter + $this->aspect->getHorizOffset();
$this->yCenterOffset = $this->yCenter + $this->aspect->getVertOffset();
$c1 = imagecolorallocatealpha($this->img, $this->getBrush()->getColor()->red,
if ($this->getBrush()->getGradient()->getVisible()== true) {
$colA = array($this->getBrush()->getGradient()->getStartColor()->getRed(),
$this->getBrush()->getGradient()->getStartColor()->getGreen(),
$this->getBrush()->getGradient()->getStartColor()->getBlue());
$colB = array($this->getBrush()->getGradient()->getEndColor()->getRed(),
$this->getBrush()->getGradient()->getEndColor()->getGreen(),
$this->getBrush()->getGradient()->getEndColor()->getBlue());
$penWidth= $this->getPen()->getWidth();
$rect->getX()+ $penWidth, $rect->getY()+ $penWidth,
$rect->getRight()- $penWidth, $rect->getHeight()- $penWidth+ $rect->getY(),
imagefilledrectangle($this->img, $rect->x, $rect->y, $rect->getRight(),
$rect->getBottom(), $c1);
/* TODO Gradient - post the code into the shape..
if ($this->getBrush()->getGradient()->getVisible()==true) {
$this->getBrush()->getGradient()->fill($this->img,
$this->getBrush()->getGradient()->getDirection(),
$this->getBrush()->getGradient()->getStartColor(),
$this->getBrush()->getGradient()->getEndColor());
if ($this->getPen()->getVisible()) {
// Gets the pen color and style (dot , dashed, ...)
$penColorStyle = $this->getPenColorStyle();
imagesetstyle($this->img, $penColorStyle);
// Assign the pen width for the image
imagesetthickness ( $this->img, $this->pen->getWidth());
imagerectangle($this->img, $rect->x, $rect->y, $rect->getRight(),
$rect->getBottom(), IMG_COLOR_STYLED);
public function _rectangle($x, $y, $width, $height) {
* Horizontal Rectangle from Left to Right, from Z0 to Z1 position,
public function rectangleZ($left, $top, $bottom, $z0, $z1) {
$this->iPoints[0] = $this->calc3DPos($left, $top, $z0);
$this->iPoints[1] = $this->calc3DPos($left, $top, $z1);
$this->iPoints[2] = $this->calc3DPos($left, $bottom, $z1);
$this->iPoints[3] = $this->calc3DPos($left, $bottom, $z0);
$this->iPoints[0] = $this->calc3DPos($r->x, $r->y, $z);
$this->iPoints[1] = $this->calc3DPos($r->getRight(), $r->y, $z);
$this->iPoints[2] = $this->calc3DPos($r->getRight(), $r->getBottom(), $z);
$this->iPoints[3] = $this->calc3DPos($r->x, $r->getBottom(), $z);
* Horizontal Rectangle from Left to Right, from Z0 to Z1 position,
public function rectangleY($left, $top, $right, $z0, $z1) {
$this->iPoints[0] = $this->calc3DPos($left, $top, $z0);
$this->iPoints[1] = $this->calc3DPos($right, $top, $z0);
$this->iPoints[2] = $this->calc3DPos($right, $top, $z1);
$this->iPoints[3] = $this->calc3DPos($left, $top, $z1);
// With this function you will draw rounded corners rectangles with transparent colors.
// Empty (not filled) figures are allowed too!!
$color = imagecolorallocate($this->img, $this->getBrush()->getColor()->red,
imagefilledrectangle($this->img, $x1+ $radius, $y1, $x2- $radius, $y2, $color);
imagefilledrectangle($this->img, $x1, $y1+ $radius, $x1+ $radius- 1, $y2- $radius, $color);
imagefilledrectangle($this->img, $x2- $radius+ 1, $y1+ $radius, $x2, $y2- $radius, $color);
imagefilledarc($this->img,$x1+ $radius, $y1+ $radius, $radius* 2, $radius* 2, 180 , 270, $color, IMG_ARC_PIE);
imagefilledarc($this->img,$x2- $radius, $y1+ $radius, $radius* 2, $radius* 2, 270 , 360, $color, IMG_ARC_PIE);
imagefilledarc($this->img,$x1+ $radius, $y2- $radius, $radius* 2, $radius* 2, 90 , 180, $color, IMG_ARC_PIE);
imagefilledarc($this->img,$x2- $radius, $y2- $radius, $radius* 2, $radius* 2, 360 , 90, $color, IMG_ARC_PIE);
imageline($this->img, $x1+ $radius, $y1, $x2- $radius, $y1, $color);
imageline($this->img, $x1+ $radius, $y2, $x2- $radius, $y2, $color);
imageline($this->img, $x1, $y1+ $radius, $x1, $y2- $radius, $color);
imageline($this->img, $x2, $y1+ $radius, $x2, $y2- $radius, $color);
imagearc($this->img,$x1+ $radius, $y1+ $radius, $radius* 2, $radius* 2, 180 , 270, $color);
imagearc($this->img,$x2- $radius, $y1+ $radius, $radius* 2, $radius* 2, 270 , 360, $color);
imagearc($this->img,$x1+ $radius, $y2- $radius, $radius* 2, $radius* 2, 90 , 180, $color);
imagearc($this->img,$x2- $radius, $y2- $radius, $radius* 2, $radius* 2, 360 , 90, $color);
$sourcefile_width= imagesx($this->img);
$sourcefile_height= imagesy($this->img);
$background = imagecreatetruecolor($sourcefile_width,$sourcefile_height);
$backcolor = new Color(0,0,0,127); // transparent
$forecolor = new Color(0,0,0,127); // transparent
if ($shapeBorders->getTopLeft()->getBorderRound() > 0) {
$endsize= $shapeBorders->getTopLeft()->getBorderRound();;
imagecopymerge($background, $this->img, 0, 0, 0, 0, $sourcefile_width, $sourcefile_height, 100);
$startx= $sourcefile_width* 2- 1;
$starty= $sourcefile_height* 2- 1;
$im_temp = imagecreatetruecolor($startx,$starty);
imagecopyresampled($im_temp, $background, 0, 0, 0, 0, $startx, $starty, $sourcefile_width, $sourcefile_height);
$bg = imagecolorallocate($im_temp,$backcolor->red,$backcolor->green, $backcolor->blue);
$fg = imagecolorallocate($im_temp,$forecolor->red,$forecolor->green, $forecolor->blue);
imagearc($im_temp, $startsize, $startsize, $arcsize, $arcsize, 180,270,$fg);
imagefilltoborder($im_temp,0,0,$fg,$bg);
imagecopyresampled($this->img, $im_temp, 0, 0, 0, 0, $sourcefile_width,$sourcefile_height,$startx, $starty);
if ($shapeBorders->getBottomLeft()->getBorderRound() > 0) {
$endsize= $shapeBorders->getBottomLeft()->getBorderRound();;
imagecopymerge($background, $this->img, 0, 0, 0, 0, $sourcefile_width, $sourcefile_height, 100);
$startx= $sourcefile_width* 2- 1;
$starty= $sourcefile_height* 2- 1;
$im_temp = imagecreatetruecolor($startx,$starty);
imagecopyresampled($im_temp, $background, 0, 0, 0, 0, $startx, $starty, $sourcefile_width, $sourcefile_height);
$bg = imagecolorallocate($im_temp,$backcolor->red,$backcolor->green, $backcolor->blue);
$fg = imagecolorallocate($im_temp,$forecolor->red,$forecolor->green, $forecolor->blue);
imagearc($im_temp, $startsize, $starty- $startsize,$arcsize, $arcsize, 90,180,$fg);
imagefilltoborder($im_temp,0,$starty,$fg,$bg);
imagecopyresampled($this->img, $im_temp, 0, 0, 0, 0, $sourcefile_width,$sourcefile_height,$startx, $starty);
if ($shapeBorders->getTopRight()->getBorderRound() > 0) {
$endsize= $shapeBorders->getTopRight()->getBorderRound();;
imagecopymerge($background, $this->img, 0, 0, 0, 0, $sourcefile_width, $sourcefile_height, 100);
$startx= $sourcefile_width* 2- 1;
$starty= $sourcefile_height* 2- 1;
$im_temp = imagecreatetruecolor($startx,$starty);
imagecopyresampled($im_temp, $background, 0, 0, 0, 0, $startx, $starty, $sourcefile_width, $sourcefile_height);
$bg = imagecolorallocate($im_temp,$backcolor->red,$backcolor->green, $backcolor->blue);
$fg = imagecolorallocate($im_temp,$forecolor->red,$forecolor->green, $forecolor->blue);
imagearc($im_temp, $startx- $startsize, $startsize,$arcsize, $arcsize, 270,360,$fg);
imagefilltoborder($im_temp,$startx,0,$fg,$bg);
imagecopyresampled($this->img, $im_temp, 0, 0, 0, 0, $sourcefile_width,$sourcefile_height,$startx, $starty);
if ($shapeBorders->getBottomRight()->getBorderRound() > 0) {
$endsize= $shapeBorders->getBottomRight()->getBorderRound();;
imagecopymerge($background, $this->img, 0, 0, 0, 0, $sourcefile_width, $sourcefile_height, 100);
$startx= $sourcefile_width* 2- 1;
$starty= $sourcefile_height* 2- 1;
$im_temp = imagecreatetruecolor($startx,$starty);
imagecopyresampled($im_temp, $background, 0, 0, 0, 0, $startx, $starty, $sourcefile_width, $sourcefile_height);
$bg = imagecolorallocate($im_temp,$backcolor->red,$backcolor->green, $backcolor->blue);
$fg = imagecolorallocate($im_temp,$forecolor->red,$forecolor->green, $forecolor->blue);
imagearc($im_temp, $startx- $startsize, $starty- $startsize,$arcsize, $arcsize, 0,90,$fg);
imagefilltoborder($im_temp,$startx,$starty,$fg,$bg);
imagecopyresampled($this->img, $im_temp, 0, 0, 0, 0, $sourcefile_width,$sourcefile_height,$startx, $starty);
imagedestroy($background);
* Draws a triangle (point p0, pointp1, pointp2) at Z position.
public function triangle($p0, $p1, $p2, $z= 0) {
$p0 = $this->calc3DPoint($p0->getX(), $p0->getY(), $z);
$p1 = $this->calc3DPoint($p1->getX(), $p1->getY(), $z);
$p2 = $this->calc3DPoint($p2->getX(), $p2->getY(), $z);
public function arc($x1,$y1,$x2,$y2,$startAngle, $sweepAngle,$filled= 0) {
$color = imagecolorallocate($this->img, $this->getBrush()->getColor()->red,
imagefilledarc($this->img,$x1, $y1, $x2- $x1, $y2- $y1, $startAngle , $endAngle, $color, IMG_ARC_PIE);
imagearc($this->img,$x1, $y1, $x2- $x1, $y2- $y1, $startAngle, $endAngle, $color);
* Draws a rotated text String at the specified x,y and z coordinates with
* the RotDegree rotation angle.<br>
* RotDegree values must be between 0 and 360.<br>
* The string is drawn on the Chart Drawing Canvas.
* @param rotDegree double
public function rotateLabel($x, $y, $z, $text, $rotDegree) {
// TODO - z param is not considred at the moment
* Draws a rotated text String at the specified Point x,y coordinates with
* the RotDegree rotation angle.<br>
* RotDegree values must be between 0 and 360.<br>
* The string is drawn on the Chart Drawing Canvas.
* @param rotDegree double
$this->rotateLabel($p->getX(), $p->getY(), $text, $rotDegree);
$tmpCenter = $r->center();
$tmpRect->offset( - $tmpCenter->x, - $tmpCenter->y);
$result[0] = $this->rotatePoint($tmpRect->x, $tmpRect->y, $tmpCenter, $tmpCos, $tmpSin);
$result[1] = $this->rotatePoint($tmpRect->getRight(), $tmpRect->y, $tmpCenter,
$result[2] = $this->rotatePoint($tmpRect->getRight(), $tmpRect->getBottom(),
$result[3] = $this->rotatePoint($tmpRect->x, $tmpRect->getBottom(), $tmpCenter,
private function rotatePoint($ax, $ay, $tmpCenter, $tmpCos, $tmpSin) {
$p->x = $tmpCenter->x + (int) ($ax * $tmpCos + $ay * $tmpSin);
$p->y = $tmpCenter->y + (int) ( - $ax * $tmpSin + $ay * $tmpCos);
for ($t = 0; $t < $length; $t++ ) {
$result[$t] = $source[$t];
* Displays the 2D non-rotated label at the specified X Y screen
* Text is outputted to the correct internal drawing Graphics2D. <br>
* The X and Y coordinates must be valid and fit inside the Chart
* rectangle. It uses the current drawing Font attributes. <br>
* Writes text at the named x and y co-ordinates.
public function textOut($x, $y, $z, $text, $align=- 1) {
if (($this->iZoomText) && ($this->iZoomFactor != -1)) {
(double) $old = $this->font->getDrawingFont()->getSize();
(int) $tmp = (int) max(1, $this->iZoomFactor * $old);
$this->font->setSize($tmp);
if ($f->shouldDrawShadow()) {
$this->drawString(x + s.getWidth(), y + s.getHeight(), text, s.getBrush());
$this->printText($this->img, $x, $y, $text, $align); //, $f->getBrush());
* Returns the vertical text size in pixels of ChartFont f.
* @return int Height in pixels of ChartFont f.
return imagefontheight($f->getFontSize());
* Returns the horizontal text size in pixels of ChartFont f.
* @return int Width in pixels of ChartFont f.
list ($llx, $lly, $lrx, $lry, $urx, $ury, $ulx, $uly) = imageftbbox($f->getFontSize(),
0, $f->getName(), strtoupper($text), array("linespacing" => $lineSpacing));
* Returns the vertical size in pixels of the text String.
* @return int Height in pixels of the text String.
* Calculates the boundary points of the convex hull of a set of 2D xy
// find pivot point, which is known to be on the hull
// point with lowest y - if there are multiple, point with highest x
$tmpubound = $ubound - 1;
for ($lIndex = $lbound; $lIndex <= $ubound; $lIndex++ ) {
if ($p[$lIndex]->getY() == $lminY) {
if ($p[$lIndex]->getX() > $lmaxX) {
$lmaxX = $p[$lIndex]->getX();
} else if ($p[$lIndex]->getY() < $lminY) {
$lminY = $p[$lIndex]->getY();
$lmaxX = $p[$lIndex]->getX();
// put pivot into seperate variable and remove from array
$lPivot = $p[$lpivotIndex];
$p[$lpivotIndex] = $p[$ubound];
// calculate angle to pivot for each point in the array
// quicker to calculate dot product of point with a horizontal comparison vector
$langles = Array(); // Array of doubles
//double[] langles = new double[tmpubound + 1];
for ($lindex = 0; $lindex <= $tmpubound; $lindex++ ) {
$lvx = $lPivot->getX() - $p[$lindex]->getX();
$lvy = $lPivot->getY() - $p[$lindex]->getY();
// reduce to a unit-vector - length 1
$tmp = sqrt($lvx * $lvx + $lvy * $lvy);
$langles[$lindex] = ($tmp == 0) ? 0.0 : $lvx / $tmp;
// sort the points by angle
self::quickSortAngle($p, $langles, 0, $tmpubound);
// step through array to remove points that are not part of the convex hull
// assign points behind and infront of current point
$lInFront = ($t == $tmpubound) ? $lPivot : $p[$t + 1];
// work out if we are making a right or left turn using vector product
$lrightturn = (($lBehind->getX() - $p[$t]->getX()) * ($lInFront->getY() - $p[$t]->getY())) -
(($lInFront->getX() - $p[$t]->getX()) * ($lBehind->getY() - $p[$t]->getY())) < 0;
// remove point from convex hull
for ($i = $t; $i < $tmphigh; $i++ ) {
$tmpubound = $tmphigh - 1;
$t-- ; // backtrack to previous point
} while ($t != $tmpubound);
// add pivot back into points array
$p[$tmpubound] = $lPivot;
* Sort an array of points by angles.
static private function quickSortAngle($p, $angles, $low, $high) {
$midangle = $angles[($lo + $hi) / 2];
while ($angles[$lo] < $midangle) {
} while ($angles[$hi] > $midangle) {
$angles[$lo] = $angles[$hi];
// perform quicksorts on subsections
self::quickSortAngle($p, $angles, $low, $hi);
self::quickSortAngle($p, $angles, $lo, $high);
/**************************************************************************
* Gets and Sets methods..... *
**************************************************************************/
private function setAspect($value) {
$this->is3D = $this->aspect->getView3D();
$this->isOrtho = $this->aspect->getOrthogonal();
* Determines the kind of brush used to fill the Canvas draw rectangle
* The Brush.Visible method must be set to true.
* Determines the kind of brush used to fill the Canvas draw rectangle
* The Brush.Visible method must be set to true.
* @param value ChartBrush
* Returns a color from global ColorPalette array variable.
return $this->colorPalette[$index % sizeof($this->colorPalette)];
* Specifies a color from global ColorPalette array variable.
$this->colorPalette= $palette;
//$colorPalette = Array(); //sizeof($palette.length)];
/* for ($t = 0; $t < sizeof($palette); $t++) {
$this->colorPalette[$t] = $palette[$t];
$this->getChart()->doBaseInvalidate();
return sizeof($this->colorPalette);
* Determines the Font for outputted text when using the Drawing Canvas.
* Determines the Font for outputted text when using the Drawing Canvas.
$this->font->assign($value);
* Defines the Height of the Font in pixels.
$this->GraphicsGD= $value;
* Gets / Sets the alignment used when displaying text using TextOut or TextOut3D.
* @param value StringAlignment
* Indicates the kind of pen used to draw Canvas lines.
* Determines the kind of pen used to draw Canvas lines.
public function setPen($value) {
$this->pen->assign($value);
private function getPenColorStyle() {
$penColor = imagecolorallocatealpha($this->img,
$this->pen->getColor()->red,
$this->pen->getColor()->green,
$this->pen->getColor()->blue,
$this->pen->getColor()->alpha);
switch ($this->pen->getStyle()) {
return array($penColor,IMG_COLOR_TRANSPARENT);
return array($penColor,$penColor,IMG_COLOR_TRANSPARENT,IMG_COLOR_TRANSPARENT,IMG_COLOR_TRANSPARENT);
return array($penColor,$penColor,IMG_COLOR_TRANSPARENT,$penColor);
return array($penColor,$penColor,IMG_COLOR_TRANSPARENT,$penColor,IMG_COLOR_TRANSPARENT,$penColor);
default: // SOLID value 0
* Sets the Pixel location (using X,Y,Z) of the centre of rotation for use
* with the Aspect Rotation and Elevation properties.<br>
return $this->rotationCenter;
* Returns the bounding rectangle for a given array of XY points.
$r = new Rectangle($p[0]->getX(), $p[0]->getY(), 0, 0);
for ($t = 1; $t < $num; $t++ ) {
if ($p[$t]->getX() < $r->getX()) {
$r->setX($p[$t]->getX());
if ($p[$t]->getX() > $r->getRight()) {
$r->setWidth($p[$t]->getX() - $r->getX());
if ($p[$t]->getY() < $r->getY()) {
$r->setY($p[$t]->getY());
if ($p[$t]->getY() > $r->getBottom()) {
$r->setHeight($p[$t]->getY() - $r->getY());
* Obsolete. Please use Rectangle.<!-- -->Contains method.
return $rect->contains($x, $y);
* Returns true if point P is inside the vert triangle of x0y0, midxY1,
* Returns true if point P is inside the horizontal triangle.
/// Returns point "ATo" minus ADist pixels from AFrom point.
if ($To->getX() != $From->getX())
$angle = atan2($To->getY() - $From->getY(), $To->getX() - $From->getX());
if ($To->getY() < $From->getY()) $py += $distance;
* Returns true if point P is inside the ellipse bounded by Left, Top,
* Returns true if point P is inside the ellipse bounded by Rect.
$tmpWidth = (int) sqr($tmp->getX() - $rect->getX());
$tmpHeight = (int) sqr($tmp->getY() - $rect->getY());
return ($tmpWidth != 0) && ($tmpHeight != 0) &&
((sqr($p->getX() - $tmp->getX()) / $tmpWidth) +
(sqr($p->getY() - $tmp->getY()) / $tmpHeight) <= 1
* Returns true if point P is inside Poly polygon.
for ($i = 0; $i <= $tmp; $i++ ) {
if ((((($poly[$i]->getY() <= $p->getY()) && ($p->getY() < $poly[$j]->getY())) ||
(($poly[$j]->getY() <= $p->getY()) && ($p->getY() < $poly[$i]->getY()))) &&
($p->getX() < ($poly[$j]->getX() - $poly[$i]->getX()) * ($p->getY() - $poly[$i]->getY())
/ ($poly[$j]->getY() - $poly[$i]->getY()) + $poly[$i]->getX()))) {
return $this->iZoomFactor;
$this->iZoomFactor = $value;
* The X coordinate of the pixel location of the center of the 3D
* The origin of the pixel coordinate system is in the top left corner of
* Specifies the X coordinate of the pixel location of the center of the 3D
* The origin of the pixel coordinate system is in the top left corner of
* The Y coordinate of the pixel location of the center of the 3D
* The origin of the pixel coordinate system is in the top left corner of
* Specifies the Y coordinate of the pixel location of the center of the 3D
* The origin of the pixel coordinate system is in the top left corner of
* Returns a valid Windows Brush Style from anpalette of many possible
$patternPalette = Array (
return $patternPalette[$index % sizeof($patternPalette)];
* The anti-alias mode for the Graphics Pen when Custom drawing.<br>
* AntiAlias - Specifies antialiased rendering.<br>
* Default - Specifies the default mode.<br>
* HighQuality - Specifies high quality, low speed rendering.
* HighSpeed - Specifies high speed, low quality rendering.<br>
* Invalid - Specifies an invalid mode. <br>
* Sets the anti-alias mode for the Graphics Pen when Custom drawing.<br>
* AntiAlias - Specifies antialiased rendering.<br>
* Default - Specifies the default mode.<br>
* HighQuality - Specifies high quality, low speed rendering.
* HighSpeed - Specifies high speed, low quality rendering.<br>
* Invalid - Specifies an invalid mode. <br>
static private function internalGetSupports3DText() {
* Returns if Canvas supports 3D Text or not.
return self::internalGetSupports3DText();
* Returns if Canvas can do rotation and elevation of more than 90 degree.
($r->getX() + $r->getRight()) / 2,
($r->y + $r->getBottom()) / 2
$radians = (M_PI * $degrees) / 180.0;
$radiusH = $rectBounds->getWidth() / 2.0;
$radiusV = $rectBounds->getHeight() / 2.0;
$tmpX = $centrePoint->getX() + $radiusH * cos($radians);
$tmpY = $centrePoint->getY() + $radiusV * sin($radians);
$tmpY = $centrePoint->getY() - $radiusV * sin($radians);
$tmpPoint = $this->calc3DPos($tmpX,$tmpY,$zPos);
return $this->imageReflection;
$this->imageReflection= $value;
* Converts the Color parameter to a darker color.<br>
* The HowMuch parameter indicates the quantity of dark increment.
* It is used by Bar Series and Pie Series to calculate the right color to
* draw Bar sides and Pie 3D zones.
static public function applyDark($c, $howMuch) {
return $c->applyDark($howMuch);
$rH = 50; // Reflection height
$tr = 30; // Starting transparency
$div = 1; // Size of the divider line
$li = imagecreatetruecolor($w, 1);
$bgc = imagecolorallocate($li, 255, 255, 255); // Background color
imagefilledrectangle($li, 0, 0, $w, 1, $bgc);
$bg = imagecreatetruecolor($w, $rH);
$wh = imagecolorallocate($im,255,255,255);
$im = imagerotate($im, - 180, $wh);
imagecopyresampled($bg, $im, 0, 0, 0, 0, $w, $h, $w, $h);
$bg = imagecreatetruecolor($w, $rH);
for ($x = 0; $x < $w; $x++ ) {
imagecopy($bg, $im, $x, 0, $w- $x, 0, 1, $rH);
for($i= 0; $i<= $rH; $i++ ){
imagecopymerge($im, $li, 0, $i, 0, 0, $w, 1, $tr);
imagecopymerge($im, $li, 0, 0, 0, 0, $w, $div, 100); // Divider
* Returns the height, in pixels, of the Chart Panel.<br>
* It should be used when using Canvas methods to draw relative to the
* <b>Note:</B> You should <b>NOT</b> use TChart.Height.
return 1050; // TODO GET SCREEN WIDTH AND HEIGHT
* Returns the width, in pixels, of the Chart Panel.
return 1680; // TODO GET SCREEN WIDTH AND HEIGHT
/*****************************************************************************
*****************************************************************************/
private $tmpXRadius, $tmpYRadius;
private $z0DonutRect; // Rect
private $z1DonutRect; // Rect
private $z0BevelRect; // Rect
private $z1BevelRect; // Rect
private $middle0; // PointDouble
private $middle1; // PointDouble
private $start0; // PointDouble
private $end0; // PointDouble
private $start1; // PointDouble
private $end1; // PointDouble
private $startD0; // PointDouble
private $endD0; // PointDouble
private $startD1; // PointDouble
private $endD1; // PointDouble
private $startB0; // PointDouble
private $endB0; // PointDouble
private $startB1; // PointDouble
private $endB1; // PointDouble
private $ilist; // PointDouble[0];
public function Pie3D($graphics) {
$this->g->internalApplyDark($this->oldColor, 32);
$c1 = imagecolorallocate($this->g->img, $this->g->getBrush()->getColor()->red,
$this->g->getBrush()->getColor()->green,
$this->g->getBrush()->getColor()->blue);
$p1 = imagecolorallocate($this->g->img, $this->g->getPen()->getColor()->red,
$this->g->getPen()->getColor()->green,
$this->g->getPen()->getColor()->blue);
$tmpArray= $this->g->sliceArray($this->points3D, 2 * $tt);
for ($tt= 0;$tt < count($tmpArray); $tt++ ) {
$tmpTeePoint = $tmpArray[$tt];
$tmpX= $tmpTeePoint->getX();
$tmpY= $tmpTeePoint->getY();
if (count($tmpArray2) >= 3) {
imageantialias($this->g->img,true);
imagefilledpolygon($this->g->img, $tmpArray2, count($tmpArray2)/ 2, $c1);
imagepolygon($this->g->img, $tmpArray2, count($tmpArray2)/ 2, $p1);
imageantialias($this->g->img,false);
private function calcCenter($angle, $z) {
$tmpX = $this->center->x + MathUtils::round($this->tmpXRadius * $tmpCos);
$tmpY = $this->center->y - MathUtils::round($this->tmpYRadius * $tmpSin);
return $this->g->calc3DPos($tmpX, $tmpY, $z);
return $this->g->calc3DPos($this->center->getX(), $this->center->getY(), $z);
private function finishSide($angle, $z) {
$this->g->iPoints[3] = $this->calcCenter($angle, $z);
$this->g->internalApplyDark($this->oldColor, 32);
private function redimArray($count, $index, $points)
for ($i= $index;$i< (sizeof($points)+ $index);$i++ )
$tmpArr[$i] = $points[$loc];
private function addToList($point)
// /*PointDouble[]*/ $tmpList=$this->redimArray(sizeof($this->ilist)+1,0,$this->ilist);
//$tmpList[sizeof($tmpList)-1]=$point;
//$this->ilist = $tmpList;
$this->ilist[sizeof($this->ilist)] = $point;
public function pointD($rect, $angle, $z)
return $this->g->pointFromCircle($rect, $angle, $z);
public function pie($xCenter, $yCenter,
$xRadius, $yRadius, $z0, $z1, $startAngle,
$endAngle, $darkSides, $drawSides, $donutPercent= 0,
$bevelPercent= 0, $edgeStyle= 0, $last= false /*, Shadow shadow*/)
$left0 = $tmpP->getX() - $xRadius;
$right0 = $tmpP->getX() + $xRadius;
$top0 = $tmpP->getY() - $yRadius;
$bottom0 = $tmpP->getY() + $yRadius;
$this->z1Rect = Rectangle::fromLTRB($this->z0Rect->getLeft(), $this->z0Rect->getTop()+ $this->zPos,
$this->z0Rect->getRight(), $this->z0Rect->getBottom()+ $this->zPos);
$this->iDrawSides = $drawSides;
$this->iStartAngle = (int) MathUtils::round(($startAngle * 180.0) / M_PI );
$this->iEndAngle = (int) MathUtils::round(($endAngle * 180.0) / M_PI );
if ($this->iEndAngle < $this->iStartAngle)
if ($this->g->getBrush()->getSolid())
$this->oldColor = $this->g->getBrush()->getColor();
$this->oldColor = $this->g->getBackColor();
$shadowColor = Color::fromArgb(0, 0, 0, 0); //Utils::getEmptyColor();
if (shadow!=null && shadow.Visible)
shadowColor = shadow.Brush.Color;
$this->drawEntirePie = $this->g->getBrush()->getTransparency() > 0 && $this->g->getChart()->getAspect()->getView3D();
$tmpXRadius = $donutPercent * $xRadius * 0.01;
$tmpYRadius = $donutPercent * $yRadius * 0.01;
$this->z1DonutRect = Rectangle::fromLTRB($this->z0DonutRect->getLeft(), $this->z0DonutRect->getTop()+ $this->zPos,
$this->z0DonutRect->getRight(), $this->z0DonutRect->getBottom()+ $this->zPos);
$this->startD0 = $this->pointD($this->z0DonutRect, $this->iStartAngle, $this->zPos);
$this->endD0 = $this->pointD($this->z0DonutRect, $this->iEndAngle, $this->zPos);
$this->startD1 = $this->pointD($this->z1DonutRect, $this->iStartAngle, $this->zPos);
$this->endD1 = $this->pointD($this->z1DonutRect, $this->iEndAngle, $this->zPos);
$bevelAmount = $bevelPercent * $this->zPos * 0.01;
$left0 = (int) MathUtils::round($tmpP->getX() - ($xRadius - $bevelAmount));
$right0 = (int) MathUtils::round($tmpP->getX() + ($xRadius - $bevelAmount));
$top0 = (int) MathUtils::round($tmpP->getY() - ($yRadius - $bevelAmount));
$bottom0 = (int) MathUtils::round($tmpP->getY() + ($yRadius - $bevelAmount));
$this->z0Rect->getRight(),
//z1BevelRect.Offset(0.0, bevelAmount);
$this->startB0 = $this->pointD($this->z0BevelRect, $this->iStartAngle, $this->zPos);
$this->endB0 = $this->pointD($this->z0BevelRect, $this->iEndAngle, $this->zPos);
$this->startB1 = $this->pointD($this->z1BevelRect, $this->iStartAngle, $this->zPos);
$this->endB1 = $this->pointD($this->z1BevelRect, $this->iEndAngle, $this->zPos);
$this->middle0 = $this->g->calc3DPosDouble($tmpP->getX(), $tmpP->getY(), $this->zPos, true);
$this->middle1 = $this->g->calc3DPosDouble($tmpP->getX(), $tmpP->getY() + $this->zPos, $this->zPos, true);
$this->start0 = $this->pointD($this->z0Rect, $this->iStartAngle, $this->zPos);
$this->end0 = $this->pointD($this->z0Rect, $this->iEndAngle, $this->zPos);
$this->start1 = $this->pointD($this->z1Rect, $this->iStartAngle, $this->zPos);
$this->end1 = $this->pointD($this->z1Rect, $this->iEndAngle, $this->zPos);
$this->sweepAngle = $this->iEndAngle - $this->iStartAngle;
$this->drawBottom($this->iStartAngle, $this->iEndAngle);
$invisiblePen = !$this->g->getPen()->getVisible(); //g.getPen().getColor() == oldColor;
$this->g->internalApplyDark($this->oldColor, 32);
$this->g->getPen()->setColor($c);
$this->drawSides($this->iStartAngle, $this->iEndAngle);
if ($this->g->getBrush()->getSolid())
$this->g->getBrush()->setColor($this->oldColor);
$this->g->setBackColor($this->oldColor);
$this->g->getPen()->setColor($this->oldColor);
$this->drawTop($this->iStartAngle, $this->iEndAngle);
$this->drawLighting($edgeStyle,$last);
private function drawSides($startAng, $endAng)
if ($this->end0->getX() > $this->middle0->getX())
if ($this->start0->getX() < $this->middle0->getX())
$this->drawBack($startAng, $endAng);
$this->drawFront($startAng, $endAng);
if ($this->sweepAngle > 180)
$this->drawBack($startAng, $endAng);
$this->drawFront($startAng, $endAng);
$this->drawBack($startAng, $endAng);
$this->drawFront($startAng, $endAng);
if ($this->start0->getX() < $this->middle0->getX())
if ($this->sweepAngle > 180)
$this->drawBack($startAng, $endAng);
$this->drawFront($startAng, $endAng);
$this->drawBack($startAng, $endAng);
$this->drawFront($startAng, $endAng);
if ($this->sweepAngle > 180)
$this->drawBack($startAng, $endAng);
$this->drawFront($startAng, $endAng);
$this->drawBack($startAng, $endAng);
$this->drawFront($startAng, $endAng);
private function drawBack($startAng, $endAng)
$doDrawBack = $this->isDonut;
//$this->ilist[0]=new PointDouble();
if (!$this->drawEntirePie && $doDrawBack &&
$this->start0->getY() > $this->middle0->getY() &&
$this->end0->getY() > $this->middle0->getY() &&
for ($i = $startAng; $i <= $endAng; $i= $i + 0.25)
$this->addToList($this->pointD($this->z0DonutRect, $i, $this->zPos));
for ($i = $endAng; $i >= $startAng; $i= $i - 0.25)
$this->addToList($this->pointD($this->z1DonutRect, $i, $this->zPos));
private function drawFront($startAng, $endAng)
if ((!$this->drawEntirePie &&
$this->start0->getY() < $this->middle0->getY() &&
$this->end0->getY() < $this->middle0->getY()
&& $this->sweepAngle < 180))
$this->drawBevel($startAng, $endAng);
//$this->ilist[0]=new PointDouble();
$tmpStartAng = $startAng;
while ($tmpEndAng < - 360)
while ($tmpStartAng > 360)
while ($tmpStartAng < - 360)
$tmpEndAng = 360 + $tmpEndAng;
$tmpStartAng = 360 + $tmpStartAng;
if ($this->start0->getY() > $this->middle0->getY() &&
$this->end0->getY() < $this->middle0->getY()) //right
if ($this->drawEntirePie)
for ($i = 0; $i <= $tmpEndAng; $i= $i + 0.25) {
$this->addToList($this->pointD($this->z1BevelRect, $i, $this->zPos));
for ($i = 0; $i <= $tmpEndAng; $i= $i + 0.25) {
$this->addToList($this->pointD($this->z0Rect, $i, $this->zPos));
for ($i = $tmpEndAng; $i >= 0; $i= $i - 0.25) {
$this->addToList($this->pointD($this->z1Rect, $i, $this->zPos));
for ($i = 360; $i >= $tmpStartAng; $i= $i - 0.25) {
$this->addToList($this->pointD($this->z1Rect, $i, $this->zPos));
for ($i = $tmpStartAng; $i <= 360; $i= $i + 0.25) {
$this->addToList($this->pointD($this->z1BevelRect, $i, $this->zPos));
for ($i = $tmpStartAng; $i <= 360; $i= $i + 0.25) {
$this->addToList($this->pointD($this->z0Rect, $i, $this->zPos));
$this->drawBevel($tmpStartAng, $tmpEndAng);
else if ($this->start0->getY() < $this->middle0->getY() && $this->end0->getY() > $this->middle0->getY()) //left
if ($this->drawEntirePie) {
for ($i = 180; $i >= $tmpStartAng; $i= $i - 0.25) {
$this->addToList($this->pointD($this->z1BevelRect, $i, $this->zPos));
for ($i = 180; $i >= $tmpStartAng; $i= $i - 0.25) {
$this->addToList($this->pointD($this->z0Rect, $i, $this->zPos));
for ($i = $tmpStartAng; $i <= 180; $i= $i + 0.25) {
$this->addToList($this->pointD($this->z1Rect, $i, $this->zPos));
for ($i = 180; $i <= $tmpEndAng; $i= $i + 0.25) {
$this->addToList($this->pointD($this->z1Rect, $i, $this->zPos));
for ($i = $tmpEndAng; $i >= 180; $i= $i - 0.25) {
$this->addToList($this->pointD($this->z1BevelRect, $i, $this->zPos));
for ($i = $tmpEndAng; $i >= 180; $i= $i - 0.25) {
$this->addToList($this->pointD($this->z0Rect, $i, $this->zPos));
$this->drawBevel($tmpStartAng, $tmpEndAng);
else if ($this->start0->getY() >= $this->middle0->getY() &&
$this->end0->getY() > $this->middle0->getY() &&
$this->sweepAngle > 180) //front
for ($i = 180; $i >= 0; $i= $i - 0.25) {
$this->addToList($this->pointD($this->z1BevelRect, $i, $this->zPos));
for ($i = 180; $i >= 0; $i= $i - 0.25) {
$this->addToList($this->pointD($this->z0Rect, $i, $this->zPos));
for ($i = 0; $i <= 180; $i= $i + 0.25) {
$this->addToList($this->pointD($this->z1Rect, $i, $this->zPos));
for ($i = $tmpEndAng; $i >= 180; $i= $i - 0.25) {
$this->addToList($this->pointD($this->z1Rect, $i, $this->zPos));
for ($i = 180; $i <= $tmpEndAng; $i= $i + 0.25) {
$this->addToList($this->pointD($this->z1BevelRect, $i, $this->zPos));
for ($i = 180; $i <= $tmpEndAng; $i= $i + 0.25) {
$this->addToList($this->pointD($this->z0Rect, $i, $this->zPos));
for ($i = 360; $i >= $tmpStartAng; $i= $i - 0.25) {
$this->addToList($this->pointD($this->z1Rect, $i, $this->zPos));
for ($i = $tmpStartAng; $i <= 360; $i= $i + 0.25) {
$this->addToList($this->pointD($this->z1BevelRect, $i, $this->zPos));
for ($i = $tmpStartAng; $i <= 360; $i= $i + 0.25) {
$this->addToList($this->pointD($this->z0Rect, $i, $this->zPos));
$this->drawBevel($tmpStartAng, $tmpEndAng, true);
if ($tmpEndAng < $tmpStartAng) {
for ($i = $tmpStartAng; $i <= $tmpEndAng; $i= $i + 0.25) {
$this->addToList($this->pointD($this->z1BevelRect, $i, $this->zPos));
for ($i = $tmpStartAng; $i <= $tmpEndAng; $i= $i + 0.25) {
$this->addToList($this->pointD($this->z0Rect, $i, $this->zPos));
for ($i = $tmpEndAng; $i >= $tmpStartAng; $i= $i - 0.25) {
$this->addToList($this->pointD($this->z1Rect, $i, $this->zPos));
$this->drawBevel($tmpStartAng, $tmpEndAng);
private function drawLeft()
if ($this->sweepAngle < 360 && ($this->drawEntirePie || $this->iDrawSides))
// $this->ilist[0]=new PointDouble();
$this->addToList($this->endD0);
$this->addToList($this->endB0);
$this->addToList($this->endB1);
$this->addToList($this->end1);
$this->addToList($this->endD1);
$this->g->iPointDoubles[0] = $this->endD0;
$this->g->iPointDoubles[1] = $this->end0;
$this->g->iPointDoubles[2] = $this->end1;
$this->g->iPointDoubles[3] = $this->endD1;
$this->g->polygonFourDouble();
$this->addToList($this->middle0);
$this->addToList($this->endB0);
$this->addToList($this->endB1);
$this->addToList($this->end1);
$this->addToList($this->middle1);
$this->g->iPointDoubles[0] = $this->middle0;
$this->g->iPointDoubles[1] = $this->end0;
$this->g->iPointDoubles[2] = $this->end1;
$this->g->iPointDoubles[3] = $this->middle1;
$this->g->polygonFourDouble();
private function drawLighting($edgeStyle, $last)
if ($this->gradientBrush == null) {
$this->gradientBrush = new ChartBrush($this->g->getChart());
$oldPenVisible = $this->g->getPen()->getVisible();
$this->g->getPen()->setVisible(false);
$this->g->setBrush($this->gradientBrush);
$this->doFlatGradient($this->zPos);
$this->doCurvedGradient($this->zPos);
$this->g->getPen()->setVisible($oldPenVisible);
private function drawRight()
if ($this->sweepAngle < 360 && ($this->drawEntirePie || $this->iDrawSides))
// $this->ilist[0]= new PointDouble();
$this->addToList($this->startD0);
$this->addToList($this->startB0);
$this->addToList($this->startB1);
$this->addToList($this->start1);
$this->addToList($this->startD1);
$this->g->iPointDoubles[0] = $this->startD0;
$this->g->iPointDoubles[1] = $this->start0;
$this->g->iPointDoubles[2] = $this->start1;
$this->g->iPointDoubles[3] = $this->startD1;
$this->g->polygonFourDouble();
$this->addToList($this->middle0);
$this->addToList($this->startB0);
$this->addToList($this->startB1);
$this->addToList($this->start1);
$this->addToList($this->middle1);
$this->g->iPointDoubles[0] = $this->middle0;
$this->g->iPointDoubles[1] = $this->start0;
$this->g->iPointDoubles[2] = $this->start1;
$this->g->iPointDoubles[3] = $this->middle1;
$this->g->polygonFourDouble();
private function drawBevel($startAng, $endAng, $split= false)
$tmpStartAng = $startAng;
$oldPenVisible = $this->g->getPen()->getVisible();
$this->g->getPen()->setVisible(false);
for ($i = 180; $i >= 0; $i= $i - 0.25) {
$this->addToList($this->pointD($this->z0BevelRect, $i, $this->zPos));
for ($i = 0; $i <= 180; $i= $i + 0.25) {
$this->addToList($this->pointD($this->z1BevelRect, $i, $this->zPos));
for ($i = $tmpEndAng; $i >= 180; $i= $i - 0.25) {
$this->addToList($this->pointD($this->z1BevelRect, $i, $this->zPos));
for ($i = 180; $i <= $tmpEndAng; $i= $i + 0.25) {
$this->addToList($this->pointD($this->z0BevelRect, $i, $this->zPos));
for ($i = 360; $i >= $tmpStartAng; $i= $i - 0.25) {
$this->addToList($this->pointD($this->z1BevelRect, $i, $this->zPos));
for ($i = $tmpStartAng; $i <= 360; $i= $i + 0.25) {
$this->addToList($this->pointD($this->z0BevelRect, $i, $this->zPos));
$this->g->getPen()->setVisible($this->oldPenVisible);
if ($tmpEndAng < $tmpStartAng) {
for ($i = $tmpStartAng; $i <= $tmpEndAng; $i= $i + 0.25) {
$this->addToList($this->pointD($this->z0BevelRect, $i, $this->zPos));
for ($i = $tmpEndAng; $i >= $tmpStartAng; $i= $i - 0.25) {
$this->addToList($this->pointD($this->z1BevelRect, $i, $this->zPos));
private function drawTop($startAng, $endAng)
// $this->ilist[0]=new PointDouble();
if ($this->sweepAngle < 360 && !$this->isDonut)
$this->addToList($this->middle0);
for ($i = $startAng; $i <= $endAng; $i= $i + 0.25)
$this->addToList($this->pointD($this->z0BevelRect, $i, $this->zPos));
for ($i = $startAng; $i <= $endAng; $i= $i + 0.25)
$this->addToList($this->pointD($this->z0Rect, $i, $this->zPos));
for ($i = $endAng; $i >= $startAng; $i= $i - 0.25)
$this->addToList($this->pointD($this->z0DonutRect, $i, $this->zPos));
if ($this->sweepAngle < 360 && !$this->isDonut)
$this->addToList($this->middle0);
private function drawBottom($startAng, $endAng)
if ($this->drawEntirePie)
if ($this->sweepAngle < 360 && !$this->isDonut)
$this->addToList($this->middle1);
for ($i = $startAng; $i <= $endAng; $i= $i + 0.25)
$this->addToList($this->pointD($this->z1Rect, $i, $this->zPos));
for ($i = $endAng; $i >= $startAng; $i= $i - 0.25)
$this->addToList($this->pointD($this->z1DonutRect, $i, $this->zPos));
if ($this->sweepAngle < 360 && !$this->isDonut)
$this->addToList($this->middle1);
private function drawPoints()
if (sizeof($this->ilist) > 0) {
$this->g->polygon($this->ilist);
private function doTopGradient($zDepth)
$this->g->getPen()->setVisible(false);
for ($i = 0; $i <= 360; $i= $i + 0.25)
$this->addToList($this->pointD($this->z0BevelRect, $i, $zDepth));
$this->gradientBrush->getGradient()->setVisible(true);
$this->gradientBrush->getGradient()->setStartColor(new Color(255,255,255,140));
$this->gradientBrush->getGradient()->setEndColor(new Color(255,255,0));
/* TODO Check which better
$this->gradientBrush->getGradient()->setDirection(GradientDirection::$RADIAL);
$this->gradientBrush->getGradient()->setRadialX((int)-MathUtils::round($this->z0BevelRect->getWidth() / 4));
$this->gradientBrush->getGradient()->setRadialY((int)-MathUtils::round($this->z0BevelRect->getHeight() / 3 ));
$this->gradientBrush->getGradient()->setCustomTargetPolygon(PointDouble::roundPointArray($shape));
$this->addToList($this->middle0);
for ($i = $this->iStartAngle; $i <= $this->iEndAngle; $i= $i + 0.25) {
$this->addToList($this->pointD($this->z0BevelRect, $i, $zDepth));
for ($i = $this->iEndAngle; $i >= $this->iStartAngle; $i= $i - 0.25) {
$this->addToList($this->pointD($this->z0DonutRect, $i, $zDepth));
$this->g->setBrush($this->gradientBrush);
if (sizeof($this->ilist)> 3) {
$this->g->polygon($this->ilist);
private function doFlatGradient($zDepth)
$this->doTopGradient($zDepth);
if (($this->iStartAngle <= 295 && $this->iEndAngle >= 335)
|| ($this->iStartAngle >= 295 && $this->iStartAngle <= 335)
|| ($this->iEndAngle >= 295 && $this->iEndAngle <= 335))
// $this->ilist[0]=new PointDouble();
for ($i = 295; $i <= 335; $i= $i + 0.25) {
$this->addToList($this->pointD($this->z1BevelRect, $i, $zDepth));
for ($i = 335; $i >= 295; $i= $i - 0.25) {
$this->addToList($this->pointD($this->z0BevelRect, $i, $zDepth));
$this->gradientBrush->getGradient()->setVisible(true);
$this->gradientBrush->getGradient()->setStartColor(new Color(255,255,255,0));
// TODO $this->gradientBrush->getGradient()->setMiddleColor(Color::fromArgb(160, 255, 255, 255));
// TODO $this->gradientBrush->getGradient()->setUseMiddle(true);
$this->gradientBrush->getGradient()->setEndColor(new Color(255,255,255,0));
// TODO $this->gradientBrush->getGradient()->setDirection(GradientDirection::$FORWARDDIAGONAL);
//gradientBrush.getGradient().setAngle(0);
$this->gradientBrush->getGradient()->setCustomTargetPolygon(PointDouble::roundPointArray($shape));
if ($this->iStartAngle <= 295 && $this->iEndAngle >= 335) {
elseif ($this->iStartAngle >= 295 && $this->iStartAngle <= 335) {
$start = $this->iStartAngle;
elseif ($this->iEndAngle >= 295 && $this->iEndAngle <= 335) {
for ($i = $start; $i <= $end; $i= $i + 0.25) {
$this->addToList($this->pointD($this->z1BevelRect, $i, $zDepth));
for ($i = $end; $i >= $start; $i= $i - 0.25) {
$this->addToList($this->pointD($this->z0BevelRect, $i, $zDepth));
$this->g->setBrush($this->gradientBrush);
$this->g->polygon($this->ilist);
private function doCurvedGradient($zDepth)
$this->doTopGradient($zDepth);
if ((iStartAngle <= 295 && iEndAngle >= 335)
|| (iStartAngle >= 295 && iStartAngle <= 335)
|| (iEndAngle >= 295 && iEndAngle <= 335))
for ($i = 295; $i <= 335; $i= $i + 0.25) {
$this->addToList($this->pointD($this->z1BevelRect, $i, $zDepth));
for ($i = 335; $i >= 295; $i= $i - 0.25) {
$this->addToList($this->pointD($this->z0BevelRect, $i, $zDepth));
// TODO $this->gradientBrush->getGradient()->setRadialX(0);
// TODO $this->gradientBrush->getGradient()->setRadialY(0);
$this->gradientBrush->getGradient()->setVisible(true);
// TODO Remove the following 2 lines
$this->gradientBrush->getGradient()->setStartColor(new Color(255,255,255,255));
$this->gradientBrush->getGradient()->setEndColor(new Color(255,255,255,0));
// TODO $this->gradientBrush->getGradient()->setDirection(GradientDirection::$RADIAL);
// TODO $this->gradientBrush->getGradient()->setAngle(135);
$this->gradientBrush->getGradient()->setDirection('vertical'); // ellipse
if ($this->iStartAngle <= 295 && $this->iEndAngle >= 335) {
elseif ($this->iStartAngle >= 295 && $this->iStartAngle <= 335) {
$start = $this->iStartAngle;
elseif ($this->iEndAngle >= 295 && $this->iEndAngle <= 335) {
for ($i = $start; $i <= $end; $i= $i + 0.25) {
$this->addToList($this->pointD($this->z1BevelRect, $i, $zDepth));
for ($i = $end; $i >= $start; $i= $i - 0.25) {
$this->addToList($this->pointD($this->z0BevelRect, $i, $zDepth));
$this->g->setBrush($this->gradientBrush);
$this->g->polygon($this->ilist);
|