Heuristic ranking analysis
[contractdashboard.git] / lib / pChart2.1.0 / class / pDraw.class.php
blob:a/lib/pChart2.1.0/class/pDraw.class.php -> blob:b/lib/pChart2.1.0/class/pDraw.class.php
--- a/lib/pChart2.1.0/class/pDraw.class.php
+++ b/lib/pChart2.1.0/class/pDraw.class.php
@@ -1,1 +1,4960 @@
-
+<?php

+ /*

+     pDraw - class extension with drawing methods

+

+     Version     : 2.1.0

+     Made by     : Jean-Damien POGOLOTTI

+     Last Update : 26/01/11

+

+     This file can be distributed under the license you can find at :

+

+                       http://www.pchart.net/license

+

+     You can find the whole class documentation on the pChart web site.

+ */

+

+ define("DIRECTION_VERTICAL"		, 690001);

+ define("DIRECTION_HORIZONTAL"		, 690002);

+

+ define("SCALE_POS_LEFTRIGHT"		, 690101);

+ define("SCALE_POS_TOPBOTTOM"		, 690102);

+

+ define("SCALE_MODE_FLOATING"		, 690201);

+ define("SCALE_MODE_START0"		, 690202);

+ define("SCALE_MODE_ADDALL"		, 690203);

+ define("SCALE_MODE_ADDALL_START0"	, 690204);

+ define("SCALE_MODE_MANUAL"		, 690205);

+

+ define("SCALE_SKIP_NONE"		, 690301);

+ define("SCALE_SKIP_SAME"		, 690302);

+ define("SCALE_SKIP_NUMBERS"		, 690303);

+

+ define("TEXT_ALIGN_TOPLEFT"		, 690401);

+ define("TEXT_ALIGN_TOPMIDDLE"		, 690402);

+ define("TEXT_ALIGN_TOPRIGHT"		, 690403);

+ define("TEXT_ALIGN_MIDDLELEFT"		, 690404);

+ define("TEXT_ALIGN_MIDDLEMIDDLE"	, 690405);

+ define("TEXT_ALIGN_MIDDLERIGHT"	, 690406);

+ define("TEXT_ALIGN_BOTTOMLEFT"		, 690407);

+ define("TEXT_ALIGN_BOTTOMMIDDLE"	, 690408);

+ define("TEXT_ALIGN_BOTTOMRIGHT"	, 690409);

+

+ define("POSITION_TOP"                  , 690501);

+ define("POSITION_BOTTOM"               , 690502);

+

+ define("LABEL_POS_LEFT"		, 690601);

+ define("LABEL_POS_CENTER"		, 690602);

+ define("LABEL_POS_RIGHT"		, 690603);

+ define("LABEL_POS_TOP"			, 690604);

+ define("LABEL_POS_BOTTOM"		, 690605);

+ define("LABEL_POS_INSIDE"		, 690606);

+ define("LABEL_POS_OUTSIDE"		, 690607);

+

+ define("ORIENTATION_HORIZONTAL"	, 690701);

+ define("ORIENTATION_VERTICAL"		, 690702);

+

+ define("LEGEND_NOBORDER"		, 690800);

+ define("LEGEND_BOX"			, 690801);

+ define("LEGEND_ROUND"			, 690802);

+

+ define("LEGEND_VERTICAL"		, 690901);

+ define("LEGEND_HORIZONTAL"		, 690902);

+

+ define("LEGEND_FAMILY_BOX"		, 691051);

+ define("LEGEND_FAMILY_CIRCLE"		, 691052);

+ define("LEGEND_FAMILY_LINE"		, 691053);

+

+ define("DISPLAY_AUTO"			, 691001);

+ define("DISPLAY_MANUAL"		, 691002);

+

+ define("LABELING_ALL"			, 691011);

+ define("LABELING_DIFFERENT"		, 691012);

+

+ define("BOUND_MIN"			, 691021);

+ define("BOUND_MAX"			, 691022);

+ define("BOUND_BOTH"			, 691023);

+

+ define("BOUND_LABEL_POS_TOP"		, 691031);

+ define("BOUND_LABEL_POS_BOTTOM"	, 691032);

+ define("BOUND_LABEL_POS_AUTO"		, 691033);

+

+ define("CAPTION_LEFT_TOP"		, 691041);

+ define("CAPTION_RIGHT_BOTTOM"		, 691042);

+

+ define("GRADIENT_SIMPLE"		, 691051);

+ define("GRADIENT_EFFECT_CAN"		, 691052);

+

+ define("PI"		, 3.14159265);

+ define("ALL"		, 69);

+ define("NONE"		, 31);

+ define("AUTO"		, 690000);

+ define("OUT_OF_SIGHT"	, -10000000000000);

+

+ class pDraw

+  {

+   /* Returns the number of drawable series */

+   function countDrawableSeries()

+    {

+     $Results = 0;

+     $Data = $this->DataSet->getData();

+

+     foreach($Data["Series"] as $SerieName => $Serie)

+      { if ( $Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"] ) { $Results++; } }

+

+     return($Results);

+    }

+

+   /* Fix box coordinates */

+   function fixBoxCoordinates($Xa,$Ya,$Xb,$Yb)

+    {

+     $X1 = min($Xa,$Xb); $Y1 = min($Ya,$Yb);

+     $X2 = max($Xa,$Xb); $Y2 = max($Ya,$Yb);

+

+     return(array($X1,$Y1,$X2,$Y2));

+    }

+

+   /* Draw a polygon */

+   function drawPolygon($Points,$Format="")

+    {

+     $R			= isset($Format["R"]) ? $Format["R"] : 0;

+     $G			= isset($Format["G"]) ? $Format["G"] : 0;

+     $B			= isset($Format["B"]) ? $Format["B"] : 0;

+     $Alpha		= isset($Format["Alpha"]) ? $Format["Alpha"] : 100;

+     $NoBorder		= isset($Format["NoBorder"]) ? $Format["NoBorder"] : FALSE;

+     $BorderR		= isset($Format["BorderR"]) ? $Format["BorderR"] : $R;

+     $BorderG		= isset($Format["BorderG"]) ? $Format["BorderG"] : $G;

+     $BorderB		= isset($Format["BorderB"]) ? $Format["BorderB"] : $B;

+     $BorderAlpha 	= isset($Format["Alpha"]) ? $Format["Alpha"] : $Alpha / 2;

+     $Surrounding	= isset($Format["Surrounding"]) ? $Format["Surrounding"] : NULL;

+     $SkipX		= isset($Format["SkipX"]) ? $Format["SkipX"] : OUT_OF_SIGHT;

+     $SkipY		= isset($Format["SkipY"]) ? $Format["SkipY"] : OUT_OF_SIGHT;

+

+     /* Calling the ImageFilledPolygon() function over the $Points array will round it */ 	

+     $Backup = $Points;

+

+     if ( $Surrounding != NULL ) { $BorderR = $R+$Surrounding; $BorderG = $G+$Surrounding; $BorderB = $B+$Surrounding; }

+

+     if ( $SkipX != OUT_OF_SIGHT ) { $SkipX = floor($SkipX); }

+     if ( $SkipY != OUT_OF_SIGHT ) { $SkipY = floor($SkipY); }

+

+     $RestoreShadow = $this->Shadow;

+     if ( $this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0 )

+      {

+       $this->Shadow = FALSE;

+       for($i=0;$i<=count($Points)-1;$i=$i+2)

+        { $Shadow[] = $Points[$i] + $this->ShadowX; $Shadow[] = $Points[$i+1] + $this->ShadowY; }

+       $this->drawPolygon($Shadow,array("R"=>$this->ShadowR,"G"=>$this->ShadowG,"B"=>$this->ShadowB,"Alpha"=>$this->Shadowa,"NoBorder"=>TRUE));

+      }

+

+     $FillColor = $this->allocateColor($this->Picture,$R,$G,$B,$Alpha);

+

+     if ( count($Points) >= 6 )

+      { ImageFilledPolygon($this->Picture,$Points,count($Points)/2,$FillColor); }

+

+     if ( !$NoBorder )

+      {

+       $Points = $Backup;

+

+       $BorderSettings = array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha);

+       for($i=0;$i<=count($Points)-1;$i=$i+2)

+        {

+         if ( isset($Points[$i+2]) )

+          {

+           if ( !($Points[$i] == $Points[$i+2] && $Points[$i] == $SkipX ) && !($Points[$i+1] == $Points[$i+3] && $Points[$i+1] == $SkipY ) )

+            $this->drawLine($Points[$i],$Points[$i+1],$Points[$i+2],$Points[$i+3],$BorderSettings);

+          }

+         else

+          {

+           if ( !($Points[$i] == $Points[0] && $Points[$i] == $SkipX ) && !($Points[$i+1] == $Points[1] && $Points[$i+1] == $SkipY ) )

+            $this->drawLine($Points[$i],$Points[$i+1],$Points[0],$Points[1],$BorderSettings);

+          }

+        }

+      }

+

+     $this->Shadow = $RestoreShadow;

+    }

+

+   /* Apply AALias correction to the rounded box boundaries */

+   function offsetCorrection($Value,$Mode)

+    {

+     $Value = round($Value,1);

+

+     if ( $Value == 0 && $Mode == 1 ) { return(.9); }

+     if ( $Value == 0 ) { return(0); }

+

+     if ( $Mode == 1) 

+      { if ( $Value == 1 ) { return(.9); }; if ( $Value == .1 ) { return(.9); }; if ( $Value == .2 ) { return(.8); }; if ( $Value == .3 ) { return(.8); }; if ( $Value == .4 ) { return(.7); }; if ( $Value == .5 ) { return(.5); }; if ( $Value == .6 ) { return(.8); }; if ( $Value == .7 ) { return(.7); }; if ( $Value == .8 ) { return(.6); }; if ( $Value == .9 ) { return(.9); }; }

+

+     if ( $Mode == 2) 

+      { if ( $Value == 1 ) { return(.9); }; if ( $Value == .1 ) { return(.1); }; if ( $Value == .2 ) { return(.2); }; if ( $Value == .3 ) { return(.3); }; if ( $Value == .4 ) { return(.4); }; if ( $Value == .5 ) { return(.5); }; if ( $Value == .6 ) { return(.8); }; if ( $Value == .7 ) { return(.7); }; if ( $Value == .8 ) { return(.8); }; if ( $Value == .9 ) { return(.9); }; }

+

+     if ( $Mode == 3) 

+      { if ( $Value == 1 ) { return(.1); }; if ( $Value == .1 ) { return(.1); }; if ( $Value == .2 ) { return(.2); }; if ( $Value == .3 ) { return(.3); }; if ( $Value == .4 ) { return(.4); }; if ( $Value == .5 ) { return(.9); }; if ( $Value == .6 ) { return(.6); }; if ( $Value == .7 ) { return(.7); }; if ( $Value == .8 ) { return(.4); }; if ( $Value == .9 ) { return(.5); }; }

+

+     if ( $Mode == 4) 

+      { if ( $Value == 1 ) { return(-1); }; if ( $Value == .1 ) { return(.1); }; if ( $Value == .2 ) { return(.2); }; if ( $Value == .3 ) { return(.3); }; if ( $Value == .4 ) { return(.1); }; if ( $Value == .5 ) { return(-.1); }; if ( $Value == .6 ) { return(.8); }; if ( $Value == .7 ) { return(.1); }; if ( $Value == .8 ) { return(.1); }; if ( $Value == .9 ) { return(.1); }; }

+    }

+

+   /* Draw a rectangle with rounded corners */

+   function drawRoundedRectangle($X1,$Y1,$X2,$Y2,$Radius,$Format="")

+    {

+     $R	    = isset($Format["R"]) ? $Format["R"] : 0;

+     $G	    = isset($Format["G"]) ? $Format["G"] : 0;

+     $B	    = isset($Format["B"]) ? $Format["B"] : 0;

+     $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100;

+

+     list($X1,$Y1,$X2,$Y2) = $this->fixBoxCoordinates($X1,$Y1,$X2,$Y2);

+

+     if ( $X2 - $X1 < $Radius ) { $Radius = floor((($X2-$X1))/2); }

+     if ( $Y2 - $Y1 < $Radius ) { $Radius = floor((($Y2-$Y1))/2); }

+

+     $Color = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"NoBorder"=>TRUE);

+

+     if ( $Radius <= 0 ) { $this->drawRectangle($X1,$Y1,$X2,$Y2,$Color); return(0); }

+

+     if ( $this->Antialias )

+      {

+       $this->drawLine($X1+$Radius,$Y1,$X2-$Radius,$Y1,$Color);

+       $this->drawLine($X2,$Y1+$Radius,$X2,$Y2-$Radius,$Color);

+       $this->drawLine($X2-$Radius,$Y2,$X1+$Radius,$Y2,$Color);

+       $this->drawLine($X1,$Y1+$Radius,$X1,$Y2-$Radius,$Color);

+      }

+     else

+      {

+       $Color = $this->allocateColor($this->Picture,$R,$G,$B,$Alpha);

+       imageline($this->Picture,$X1+$Radius,$Y1,$X2-$Radius,$Y1,$Color);

+       imageline($this->Picture,$X2,$Y1+$Radius,$X2,$Y2-$Radius,$Color);

+       imageline($this->Picture,$X2-$Radius,$Y2,$X1+$Radius,$Y2,$Color);

+       imageline($this->Picture,$X1,$Y1+$Radius,$X1,$Y2-$Radius,$Color);

+      }

+

+     $Step = 360 / (2 * PI * $Radius);

+     for($i=0;$i<=90;$i=$i+$Step)

+      {

+       $X = cos(($i+180)*PI/180) * $Radius + $X1 + $Radius;

+       $Y = sin(($i+180)*PI/180) * $Radius + $Y1 + $Radius;

+       $this->drawAntialiasPixel($X,$Y,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha));

+

+       $X = cos(($i+90)*PI/180) * $Radius + $X1 + $Radius;

+       $Y = sin(($i+90)*PI/180) * $Radius + $Y2 - $Radius;

+       $this->drawAntialiasPixel($X,$Y,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha));

+

+       $X = cos($i*PI/180) * $Radius + $X2 - $Radius;

+       $Y = sin($i*PI/180) * $Radius + $Y2 - $Radius;

+       $this->drawAntialiasPixel($X,$Y,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha));

+

+       $X = cos(($i+270)*PI/180) * $Radius + $X2 - $Radius;

+       $Y = sin(($i+270)*PI/180) * $Radius + $Y1 + $Radius;

+       $this->drawAntialiasPixel($X,$Y,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha));

+      }

+    }

+

+   /* Draw a rectangle with rounded corners */

+   function drawRoundedFilledRectangle($X1,$Y1,$X2,$Y2,$Radius,$Format="")

+    {

+     $R			= isset($Format["R"]) ? $Format["R"] : 0;

+     $G			= isset($Format["G"]) ? $Format["G"] : 0;

+     $B			= isset($Format["B"]) ? $Format["B"] : 0;

+     $BorderR		= isset($Format["BorderR"]) ? $Format["BorderR"] : -1;

+     $BorderG		= isset($Format["BorderG"]) ? $Format["BorderG"] : -1;

+     $BorderB		= isset($Format["BorderB"]) ? $Format["BorderB"] : -1;

+     $Alpha		= isset($Format["Alpha"]) ? $Format["Alpha"] : 100;

+     $Surrounding	= isset($Format["Surrounding"]) ? $Format["Surrounding"] : NULL;

+

+     if ( $Surrounding != NULL ) { $BorderR = $R+$Surrounding; $BorderG = $G+$Surrounding; $BorderB = $B+$Surrounding; }

+     if ( $BorderR == -1 ) { $BorderR = $R; $BorderG = $G; $BorderB = $B; }

+

+     list($X1,$Y1,$X2,$Y2) = $this->fixBoxCoordinates($X1,$Y1,$X2,$Y2);

+

+     if ( $X2 - $X1 < $Radius ) { $Radius = floor((($X2-$X1))/2); }

+     if ( $Y2 - $Y1 < $Radius ) { $Radius = floor((($Y2-$Y1))/2); }

+

+     $RestoreShadow = $this->Shadow;

+     if ( $this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0 )

+      {

+       $this->Shadow = FALSE;

+       $this->drawRoundedFilledRectangle($X1+$this->ShadowX,$Y1+$this->ShadowY,$X2+$this->ShadowX,$Y2+$this->ShadowY,$Radius,array("R"=>$this->ShadowR,"G"=>$this->ShadowG,"B"=>$this->ShadowB,"Alpha"=>$this->Shadowa));

+      }

+

+     $Color = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"NoBorder"=>TRUE);

+

+     if ( $Radius <= 0 ) { $this->drawFilledRectangle($X1,$Y1,$X2,$Y2,$Color); return(0); }

+

+     $YTop    = $Y1+$Radius;

+     $YBottom = $Y2-$Radius;

+

+     $Step = 360 / (2 * PI * $Radius);

+     $Positions = ""; $Radius--; $MinY = ""; $MaxY = "";

+     for($i=0;$i<=90;$i=$i+$Step)

+      {

+       $Xp1 = cos(($i+180)*PI/180) * $Radius + $X1 + $Radius;

+       $Xp2 = cos(((90-$i)+270)*PI/180) * $Radius + $X2 - $Radius;

+       $Yp  = floor(sin(($i+180)*PI/180) * $Radius + $YTop);

+       if ( $MinY == "" || $Yp > $MinY ) { $MinY = $Yp; }

+

+       if ( !isset($Positions[$Yp]) )

+        { $Positions[$Yp]["X1"] = $Xp1; $Positions[$Yp]["X2"] = $Xp2; }

+       else

+        { $Positions[$Yp]["X1"] = min($Positions[$Yp]["X1"],$Xp1); $Positions[$Yp]["X2"] = max($Positions[$Yp]["X2"],$Xp2); }

+

+       $Xp1 = cos(($i+90)*PI/180) * $Radius + $X1 + $Radius;

+       $Xp2 = cos((90-$i)*PI/180) * $Radius + $X2 - $Radius;

+       $Yp  = floor(sin(($i+90)*PI/180) * $Radius + $YBottom);

+       if ( $MaxY == "" || $Yp < $MaxY ) { $MaxY = $Yp; }

+

+       if ( !isset($Positions[$Yp]["Bottom"]) )

+        { $Positions[$Yp]["X1"] = $Xp1; $Positions[$Yp]["X2"] = $Xp2; }

+       else

+        { $Positions[$Yp]["X1"] = min($Positions[$Yp]["X1"],$Xp1); $Positions[$Yp]["X2"] = max($Positions[$Yp]["X2"],$Xp2); }

+      }

+

+     $ManualColor  = $this->allocateColor($this->Picture,$R,$G,$B,$Alpha);

+     foreach($Positions as $Yp => $Bounds)

+      {

+       $X1 = $Bounds["X1"]; $X1Dec = $this->getFirstDecimal($X1); if ( $X1Dec != 0 ) { $X1 = floor($X1)+1; }

+       $X2 = $Bounds["X2"]; $X2Dec = $this->getFirstDecimal($X2); if ( $X2Dec != 0 ) { $X2 = floor($X2)-1; }

+

+       imageline($this->Picture,$X1,$Yp,$X2,$Yp,$ManualColor);

+      }

+     $this->drawFilledRectangle($X1,$MinY+1,floor($X2),$MaxY-1,$Color);

+

+     $Radius++;

+     $this->drawRoundedRectangle($X1,$Y1,$X2+1,$Y2-1,$Radius,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$Alpha));

+

+     $this->Shadow = $RestoreShadow;

+    }

+

+   /* Draw a rectangle with rounded corners */

+   function drawRoundedFilledRectangle_deprecated($X1,$Y1,$X2,$Y2,$Radius,$Format="")

+    {

+     $R			= isset($Format["R"]) ? $Format["R"] : 0;

+     $G			= isset($Format["G"]) ? $Format["G"] : 0;

+     $B			= isset($Format["B"]) ? $Format["B"] : 0;

+     $BorderR		= isset($Format["BorderR"]) ? $Format["BorderR"] : -1;

+     $BorderG		= isset($Format["BorderG"]) ? $Format["BorderG"] : -1;

+     $BorderB		= isset($Format["BorderB"]) ? $Format["BorderB"] : -1;

+     $Alpha		= isset($Format["Alpha"]) ? $Format["Alpha"] : 100;

+     $Surrounding	= isset($Format["Surrounding"]) ? $Format["Surrounding"] : NULL;

+

+     if ( $Surrounding != NULL ) { $BorderR = $R+$Surrounding; $BorderG = $G+$Surrounding; $BorderB = $B+$Surrounding; }

+     if ( $BorderR == -1 ) { $BorderR = $R; $BorderG = $G; $BorderB = $B; }

+

+     list($X1,$Y1,$X2,$Y2) = $this->fixBoxCoordinates($X1,$Y1,$X2,$Y2);

+

+     if ( $X2 - $X1 < $Radius ) { $Radius = floor((($X2-$X1)+2)/2); }

+     if ( $Y2 - $Y1 < $Radius ) { $Radius = floor((($Y2-$Y1)+2)/2); }

+

+     $RestoreShadow = $this->Shadow;

+     if ( $this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0 )

+      {

+       $this->Shadow = FALSE;

+       $this->drawRoundedFilledRectangle($X1+$this->ShadowX,$Y1+$this->ShadowY,$X2+$this->ShadowX,$Y2+$this->ShadowY,$Radius,array("R"=>$this->ShadowR,"G"=>$this->ShadowG,"B"=>$this->ShadowB,"Alpha"=>$this->Shadowa));

+      }

+

+     if ( $this->getFirstDecimal($X2) >= 5 )  { $XOffset2 = 1; } else { $XOffset2 = 0; }

+     if ( $this->getFirstDecimal($X1) <= 5 )  { $XOffset1 = 1; } else { $XOffset1 = 0; }

+

+     if ( !$this->Antialias ) { $XOffset1 = 1; $XOffset2 = 1; }

+

+     $YTop    = floor($Y1+$Radius);

+     $YBottom = floor($Y2-$Radius);

+

+     $this->drawFilledRectangle($X1-$XOffset1,$YTop,$X2+$XOffset2,$YBottom,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"NoBorder"=>TRUE));

+

+     $Step = 360 / (2 * PI * $Radius);

+     $Color  = $this->allocateColor($this->Picture,$R,$G,$B,$Alpha);

+     $Color2 = $this->allocateColor($this->Picture,255,0,0,$Alpha);

+     $Drawn = "";

+

+     if ( $Alpha < 100 )  { $Drawn[$YTop] = FALSE; }

+     if ( $Alpha < 100 )  { $Drawn[$YBottom] = TRUE; }

+     

+     for($i=0;$i<=90;$i=$i+$Step)

+      {

+       $Xp1 = cos(($i+180)*PI/180) * $Radius + $X1 + $Radius;

+       $Xp2 = cos(((90-$i)+270)*PI/180) * $Radius + $X2 - $Radius;

+       $Yp  = sin(($i+180)*PI/180) * $Radius + $YTop;

+

+       if ( $this->getFirstDecimal($Xp1) > 5 )  { $XOffset1 = 1; } else { $XOffset1 = 0; }

+       if ( $this->getFirstDecimal($Xp2) > 5 )  { $XOffset2 = 1; } else { $XOffset2 = 0; }

+       if ( $this->getFirstDecimal($Yp) > 5 )  { $YOffset = 1; } else { $YOffset = 0; }

+

+       if ( !isset($Drawn[$Yp+$YOffset]) || $Alpha == 100 )

+        imageline($this->Picture,$Xp1+$XOffset1,$Yp+$YOffset,$Xp2+$XOffset2,$Yp+$YOffset,$Color);

+

+       $Drawn[$Yp+$YOffset] = $Xp2;

+

+       $Xp1 = cos(($i+90)*PI/180) * $Radius + $X1 + $Radius;

+       $Xp2 = cos((90-$i)*PI/180) * $Radius + $X2 - $Radius;

+       $Yp  = sin(($i+90)*PI/180) * $Radius + $YBottom;

+

+       if ( $this->getFirstDecimal($Xp1) > 7 )  { $XOffset1 = 1; } else { $XOffset1 = 0; }

+       if ( $this->getFirstDecimal($Xp2) > 7 )  { $XOffset2 = 1; } else { $XOffset2 = 0; }

+       if ( $this->getFirstDecimal($Yp) > 5 )  { $YOffset = 1; } else { $YOffset = 0; }

+

+       if ( !isset($Drawn[$Yp+$YOffset]) || $Alpha == 100 )

+        imageline($this->Picture,$Xp1+$XOffset1,$Yp+$YOffset,$Xp2+$XOffset2,$Yp+$YOffset,$Color);

+

+       $Drawn[$Yp+$YOffset] = $Xp2;

+      }

+

+     $this->drawRoundedRectangle($X1,$Y1,$X2,$Y2,$Radius,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$Alpha));

+

+     $this->Shadow = $RestoreShadow;

+    }

+

+   /* Draw a rectangle */

+   function drawRectangle($X1,$Y1,$X2,$Y2,$Format="")

+    {

+     $R		= isset($Format["R"]) ? $Format["R"] : 0;

+     $G		= isset($Format["G"]) ? $Format["G"] : 0;

+     $B		= isset($Format["B"]) ? $Format["B"] : 0;

+     $Alpha	= isset($Format["Alpha"]) ? $Format["Alpha"] : 100;

+     $Ticks	= isset($Format["Ticks"]) ? $Format["Ticks"] : NULL;

+     $NoAngle	= isset($Format["NoAngle"]) ? $Format["NoAngle"] : FALSE;

+

+     if ($X1 > $X2) { list($X1, $X2) = array($X2, $X1); }

+     if ($Y1 > $Y2) { list($Y1, $Y2) = array($Y2, $Y1); }

+

+     if ( $this->Antialias )

+      {

+       if ( $NoAngle )

+        {

+         $this->drawLine($X1+1,$Y1,$X2-1,$Y1,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks));

+         $this->drawLine($X2,$Y1+1,$X2,$Y2-1,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks));

+         $this->drawLine($X2-1,$Y2,$X1+1,$Y2,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks));

+         $this->drawLine($X1,$Y1+1,$X1,$Y2-1,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks));

+        }

+       else

+        {

+         $this->drawLine($X1+1,$Y1,$X2-1,$Y1,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks));

+         $this->drawLine($X2,$Y1,$X2,$Y2,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks));

+         $this->drawLine($X2-1,$Y2,$X1+1,$Y2,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks));

+         $this->drawLine($X1,$Y1,$X1,$Y2,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks));

+        }

+      }

+     else

+      {

+       $Color = $this->allocateColor($this->Picture,$R,$G,$B,$Alpha);

+       imagerectangle($this->Picture,$X1,$Y1,$X2,$Y2,$Color);

+      }

+    }

+

+   /* Draw a filled rectangle */

+   function drawFilledRectangle($X1,$Y1,$X2,$Y2,$Format="")

+    {

+     $R			= isset($Format["R"]) ? $Format["R"] : 0;

+     $G			= isset($Format["G"]) ? $Format["G"] : 0;

+     $B			= isset($Format["B"]) ? $Format["B"] : 0;

+     $Alpha		= isset($Format["Alpha"]) ? $Format["Alpha"] : 100;

+     $BorderR		= isset($Format["BorderR"]) ? $Format["BorderR"] : -1;

+     $BorderG		= isset($Format["BorderG"]) ? $Format["BorderG"] : -1;

+     $BorderB		= isset($Format["BorderB"]) ? $Format["BorderB"] : -1;

+     $BorderAlpha	= isset($Format["BorderAlpha"]) ? $Format["BorderAlpha"] : $Alpha;

+     $Surrounding	= isset($Format["Surrounding"]) ? $Format["Surrounding"] : NULL;

+     $Ticks		= isset($Format["Ticks"]) ? $Format["Ticks"] : NULL;

+     $NoAngle		= isset($Format["NoAngle"]) ? $Format["NoAngle"] : NULL;

+     $Dash		= isset($Format["Dash"]) ? $Format["Dash"] : FALSE;

+     $DashStep		= isset($Format["DashStep"]) ? $Format["DashStep"] : 4;

+     $DashR		= isset($Format["DashR"]) ? $Format["DashR"] : 0;

+     $DashG		= isset($Format["DashG"]) ? $Format["DashG"] : 0;

+     $DashB		= isset($Format["DashB"]) ? $Format["DashB"] : 0;

+     $NoBorder		= isset($Format["NoBorder"]) ? $Format["NoBorder"] : FALSE;

+

+     if ( $Surrounding != NULL ) { $BorderR = $R+$Surrounding; $BorderG = $G+$Surrounding; $BorderB = $B+$Surrounding; }

+

+     if ($X1 > $X2) { list($X1, $X2) = array($X2, $X1); }

+     if ($Y1 > $Y2) { list($Y1, $Y2) = array($Y2, $Y1); }

+

+     $RestoreShadow = $this->Shadow;

+     if ( $this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0 )

+      {

+       $this->Shadow = FALSE;

+       $this->drawFilledRectangle($X1+$this->ShadowX,$Y1+$this->ShadowY,$X2+$this->ShadowX,$Y2+$this->ShadowY,array("R"=>$this->ShadowR,"G"=>$this->ShadowG,"B"=>$this->ShadowB,"Alpha"=>$this->Shadowa,"Ticks"=>$Ticks,"NoAngle"=>$NoAngle));

+      }

+

+     $Color = $this->allocateColor($this->Picture,$R,$G,$B,$Alpha);

+     if ( $NoAngle )

+      {

+       imagefilledrectangle($this->Picture,ceil($X1)+1,ceil($Y1),floor($X2)-1,floor($Y2),$Color);

+       imageline($this->Picture,ceil($X1),ceil($Y1)+1,ceil($X1),floor($Y2)-1,$Color);

+       imageline($this->Picture,floor($X2),ceil($Y1)+1,floor($X2),floor($Y2)-1,$Color);

+      }

+     else

+      imagefilledrectangle($this->Picture,ceil($X1),ceil($Y1),floor($X2),floor($Y2),$Color);

+

+     if ( $Dash )

+      {

+       if ( $BorderR != -1 ) { $iX1=$X1+1; $iY1=$Y1+1; $iX2=$X2-1; $iY2=$Y2-1; } else { $iX1=$X1; $iY1=$Y1; $iX2=$X2; $iY2=$Y2; }

+

+       $Color = $this->allocateColor($this->Picture,$DashR,$DashG,$DashB,$Alpha);

+       $Y=$iY1-$DashStep;

+       for($X=$iX1; $X<=$iX2+($iY2-$iY1); $X=$X+$DashStep)

+        {

+         $Y=$Y+$DashStep;

+         if ( $X > $iX2 ) { $Xa = $X-($X-$iX2); $Ya = $iY1+($X-$iX2); } else { $Xa = $X; $Ya = $iY1; }

+         if ( $Y > $iY2 ) { $Xb = $iX1+($Y-$iY2); $Yb = $Y-($Y-$iY2); } else { $Xb = $iX1; $Yb = $Y; }

+         imageline($this->Picture,$Xa,$Ya,$Xb,$Yb,$Color);

+        }

+      }

+

+     if ( $this->Antialias && !$NoBorder )

+      {

+       if ( $X1 < ceil($X1) )

+        {

+         $AlphaA = $Alpha * (ceil($X1) - $X1);

+         $Color = $this->allocateColor($this->Picture,$R,$G,$B,$AlphaA);

+         imageline($this->Picture,ceil($X1)-1,ceil($Y1),ceil($X1)-1,floor($Y2),$Color);

+        }

+

+       if ( $Y1 < ceil($Y1) )

+        {

+         $AlphaA = $Alpha * (ceil($Y1) - $Y1);

+         $Color = $this->allocateColor($this->Picture,$R,$G,$B,$AlphaA);

+         imageline($this->Picture,ceil($X1),ceil($Y1)-1,floor($X2),ceil($Y1)-1,$Color);

+        }

+

+       if ( $X2 > floor($X2) )

+        {

+         $AlphaA = $Alpha * (.5-($X2 - floor($X2)));

+         $Color = $this->allocateColor($this->Picture,$R,$G,$B,$AlphaA);

+         imageline($this->Picture,floor($X2)+1,ceil($Y1),floor($X2)+1,floor($Y2),$Color);

+        } 

+

+       if ( $Y2 > floor($Y2) )

+        {

+         $AlphaA = $Alpha * (.5-($Y2 - floor($Y2)));

+         $Color = $this->allocateColor($this->Picture,$R,$G,$B,$AlphaA);

+         imageline($this->Picture,ceil($X1),floor($Y2)+1,floor($X2),floor($Y2)+1,$Color);

+        }

+      }

+

+     if ( $BorderR != -1 )

+      $this->drawRectangle($X1,$Y1,$X2,$Y2,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha,"Ticks"=>$Ticks,"NoAngle"=>$NoAngle));

+

+     $this->Shadow = $RestoreShadow;

+    }

+

+   /* Draw a rectangular marker of the specified size */

+   function drawRectangleMarker($X,$Y,$Format="")

+    {

+     $Size = isset($Format["Size"]) ? $Format["Size"] : 4;

+

+     $HalfSize = floor($Size/2);

+     $this->drawFilledRectangle($X-$HalfSize,$Y-$HalfSize,$X+$HalfSize,$Y+$HalfSize,$Format);

+    }

+

+   /* Drawn a spline based on the bezier function */

+   function drawSpline($Coordinates,$Format="")

+    {

+     $R		= isset($Format["R"]) ? $Format["R"] : 0;

+     $G		= isset($Format["G"]) ? $Format["G"] : 0;

+     $B		= isset($Format["B"]) ? $Format["B"] : 0;

+     $Alpha	= isset($Format["Alpha"]) ? $Format["Alpha"] : 100;

+     $Force	= isset($Format["Force"]) ? $Format["Force"] : 30;

+     $Forces	= isset($Format["Forces"]) ? $Format["Forces"] : NULL;

+     $ShowC	= isset($Format["ShowControl"]) ? $Format["ShowControl"] : FALSE;

+     $Ticks	= isset($Format["Ticks"]) ? $Format["Ticks"] : NULL;

+     $PathOnly	= isset($Format["PathOnly"]) ? $Format["PathOnly"] : FALSE;

+     $Weight	= isset($Format["Weight"]) ? $Format["Weight"] : NULL;

+

+     $Cpt = NULL; $Mode = NULL; $Result = "";

+     for($i=1;$i<=count($Coordinates)-1;$i++)

+      {

+       $X1 = $Coordinates[$i-1][0]; $Y1 = $Coordinates[$i-1][1];

+       $X2 = $Coordinates[$i][0];   $Y2 = $Coordinates[$i][1];

+

+       if ( $Forces != NULL ) { $Force = $Forces[$i]; }

+

+       /* First segment */

+       if ( $i == 1 )

+        { $Xv1 = $X1; $Yv1 = $Y1; }

+       else

+        {

+         $Angle1 = $this->getAngle($XLast,$YLast,$X1,$Y1);

+         $Angle2 = $this->getAngle($X1,$Y1,$X2,$Y2);

+         $XOff = cos($Angle2 * PI / 180) * $Force + $X1;

+         $YOff = sin($Angle2 * PI / 180) * $Force + $Y1;

+

+         $Xv1 = cos($Angle1 * PI / 180) * $Force + $XOff;

+         $Yv1 = sin($Angle1 * PI / 180) * $Force + $YOff;

+        }

+

+       /* Last segment */

+       if ( $i == count($Coordinates)-1 )

+        { $Xv2 = $X2; $Yv2 = $Y2; }

+       else

+        {

+         $Angle1 = $this->getAngle($X2,$Y2,$Coordinates[$i+1][0],$Coordinates[$i+1][1]);

+         $Angle2 = $this->getAngle($X1,$Y1,$X2,$Y2);

+         $XOff = cos(($Angle2+180) * PI / 180) * $Force + $X2;

+         $YOff = sin(($Angle2+180) * PI / 180) * $Force + $Y2;

+

+         $Xv2 = cos(($Angle1+180) * PI / 180) * $Force + $XOff;

+         $Yv2 = sin(($Angle1+180) * PI / 180) * $Force + $YOff;

+        }

+

+       $Path = $this->drawBezier($X1,$Y1,$X2,$Y2,$Xv1,$Yv1,$Xv2,$Yv2,$Format);

+       if ($PathOnly) { $Result[] = $Path; }

+

+       $XLast = $X1; $YLast = $Y1;

+      }

+

+     return($Result);

+    }

+

+   /* Draw a bezier curve with two controls points */

+   function drawBezier($X1,$Y1,$X2,$Y2,$Xv1,$Yv1,$Xv2,$Yv2,$Format="")

+    {

+     $R		= isset($Format["R"]) ? $Format["R"] : 0;

+     $G		= isset($Format["G"]) ? $Format["G"] : 0;

+     $B		= isset($Format["B"]) ? $Format["B"] : 0;

+     $Alpha	= isset($Format["Alpha"]) ? $Format["Alpha"] : 100;

+     $ShowC	= isset($Format["ShowControl"]) ? $Format["ShowControl"] : FALSE;

+     $Segments	= isset($Format["Segments"]) ? $Format["Segments"] : NULL;

+     $Ticks	= isset($Format["Ticks"]) ? $Format["Ticks"] : NULL;

+     $NoDraw    = isset($Format["NoDraw"]) ? $Format["NoDraw"] : FALSE;

+     $PathOnly  = isset($Format["PathOnly"]) ? $Format["PathOnly"] : FALSE;

+     $Weight    = isset($Format["Weight"]) ? $Format["Weight"] : NULL;

+     $DrawArrow		= isset($Format["DrawArrow"]) ? $Format["DrawArrow"] : FALSE;

+     $ArrowSize		= isset($Format["ArrowSize"]) ? $Format["ArrowSize"] : 10;

+     $ArrowRatio	= isset($Format["ArrowRatio"]) ? $Format["ArrowRatio"] : .5;

+     $ArrowTwoHeads	= isset($Format["ArrowTwoHeads"]) ? $Format["ArrowTwoHeads"] : FALSE;

+

+     if ( $Segments == NULL )

+      {

+       $Length    = $this->getLength($X1,$Y1,$X2,$Y2);

+       $Precision = ($Length*125)/1000;

+      }

+     else

+      $Precision = $Segments;

+

+     $P[0]["X"] = $X1;  $P[0]["Y"] = $Y1;

+     $P[1]["X"] = $Xv1; $P[1]["Y"] = $Yv1;

+     $P[2]["X"] = $Xv2; $P[2]["Y"] = $Yv2;

+     $P[3]["X"] = $X2;  $P[3]["Y"] = $Y2;

+

+     /* Compute the bezier points */

+     $Q = ""; $ID = 0; $Path = "";

+     for($i=0;$i<=$Precision;$i=$i+1)

+      {

+       $u = $i / $Precision;

+

+       $C    = "";

+       $C[0] = (1 - $u) * (1 - $u) * (1 - $u);

+       $C[1] = ($u * 3) * (1 - $u) * (1 - $u);

+       $C[2] = 3 * $u * $u * (1 - $u);

+       $C[3] = $u * $u * $u;

+

+       for($j=0;$j<=3;$j++)

+        {

+         if ( !isset($Q[$ID]) ) { $Q[$ID] = ""; }

+         if ( !isset($Q[$ID]["X"]) ) { $Q[$ID]["X"] = 0; }

+         if ( !isset($Q[$ID]["Y"]) ) { $Q[$ID]["Y"] = 0; }

+

+         $Q[$ID]["X"] = $Q[$ID]["X"] + $P[$j]["X"] * $C[$j];

+         $Q[$ID]["Y"] = $Q[$ID]["Y"] + $P[$j]["Y"] * $C[$j];

+        }

+       $ID++;

+      }        

+     $Q[$ID]["X"] = $X2; $Q[$ID]["Y"] = $Y2;

+

+     if ( !$NoDraw )

+      {

+       /* Display the control points */

+       if ( $ShowC && !$PathOnly )

+        {

+         $Xv1 = floor($Xv1); $Yv1 = floor($Yv1); $Xv2 = floor($Xv2); $Yv2 = floor($Yv2);

+

+         $this->drawLine($X1,$Y1,$X2,$Y2,array("R"=>0,"G"=>0,"B"=>0,"Alpha"=>30));

+

+         $MyMarkerSettings = array("R"=>255,"G"=>0,"B"=>0,"BorderR"=>255,"BorderB"=>255,"BorderG"=>255,"Size"=>4);

+         $this->drawRectangleMarker($Xv1,$Yv1,$MyMarkerSettings);

+         $this->drawText($Xv1+4,$Yv1,"v1");

+         $MyMarkerSettings = array("R"=>0,"G"=>0,"B"=>255,"BorderR"=>255,"BorderB"=>255,"BorderG"=>255,"Size"=>4);

+         $this->drawRectangleMarker($Xv2,$Yv2,$MyMarkerSettings);

+         $this->drawText($Xv2+4,$Yv2,"v2");

+        }

+

+       /* Draw the bezier */

+       $LastX = NULL; $LastY = NULL; $Cpt = NULL; $Mode = NULL; $ArrowS = NULL;

+       foreach ($Q as $Key => $Point)

+        {

+         $X = $Point["X"]; $Y = $Point["Y"];

+

+         /* Get the first segment */

+         if ( $ArrowS == NULL && $LastX != NULL && $LastY != NULL )

+          { $ArrowS["X2"] = $LastX; $ArrowS["Y2"] = $LastY; $ArrowS["X1"] = $X; $ArrowS["Y1"] = $Y; }

+

+         if ( $LastX != NULL && $LastY != NULL && !$PathOnly)

+          list($Cpt,$Mode) = $this->drawLine($LastX,$LastY,$X,$Y,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks,"Cpt"=>$Cpt,"Mode"=>$Mode,"Weight"=>$Weight));

+

+         /* Get the last segment */

+         $ArrowE["X1"] = $LastX; $ArrowE["Y1"] = $LastY; $ArrowE["X2"] = $X; $ArrowE["Y2"] = $Y;

+

+         $LastX = $X; $LastY = $Y;

+        }

+

+       if ( $DrawArrow && !$PathOnly )

+        {

+         $ArrowSettings = array("FillR"=>$R,"FillG"=>$G,"FillB"=>$B,"Alpha"=>$Alpha,"Size"=>$ArrowSize,"Ratio"=>$ArrowRatio);

+         if ( $ArrowTwoHeads )

+