Ignore:
Timestamp:
Apr 14, 2019, 2:31:40 PM (5 years ago)
Author:
roby
Message:
 
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/client/modules/Elezioni/grafici/jpgraph_pie3d.php

    r265 r267  
    11<?php
    22/*=======================================================================
    3  // File:        JPGRAPH_PIE3D.PHP
    4  // Description: 3D Pie plot extension for JpGraph
    5  // Created:     2001-03-24
    6  // Ver:         $Id: jpgraph_pie3d.php 1329 2009-06-20 19:23:30Z ljp $
    7  //
    8  // Copyright (c) Asial Corporation. All rights reserved.
    9  //========================================================================
    10  */
     3// File:        JPGRAPH_PIE3D.PHP
     4// Description: 3D Pie plot extension for JpGraph
     5// Created:     2001-03-24
     6// Ver:         $Id: jpgraph_pie3d.php 956 2007-11-17 13:19:20Z ljp $
     7//
     8// Copyright (c) Aditus Consulting. All rights reserved.
     9//========================================================================
     10*/
    1111
    1212//===================================================
    1313// CLASS PiePlot3D
    14 // Description: Plots a 3D pie with a specified projection
     14// Description: Plots a 3D pie with a specified projection 
    1515// angle between 20 and 70 degrees.
    1616//===================================================
    1717class PiePlot3D extends PiePlot {
    1818    private $labelhintcolor="red",$showlabelhint=true;
    19     private $angle=50;
     19    private $angle=50; 
    2020    private $edgecolor="", $edgeweight=1;
    2121    private $iThickness=false;
    22 
    23     //---------------
    24     // CONSTRUCTOR
    25     function __construct($data) {
    26         $this->radius = 0.5;
    27         $this->data = $data;
    28         $this->title = new Text("");
    29         $this->title->SetFont(FF_FONT1,FS_BOLD);
    30         $this->value = new DisplayValue();
    31         $this->value->Show();
    32         $this->value->SetFormat('%.0f%%');
    33     }
    34 
    35     //---------------
    36     // PUBLIC METHODS
    37 
     22       
     23//---------------
     24// CONSTRUCTOR
     25    function PiePlot3d($data) {
     26        $this->radius = 0.5;
     27        $this->data = $data;
     28        $this->title = new Text("");
     29        $this->title->SetFont(FF_FONT1,FS_BOLD);
     30        $this->value = new DisplayValue();
     31        $this->value->Show();
     32        $this->value->SetFormat('%.0f%%');
     33    }
     34
     35//---------------
     36// PUBLIC METHODS       
     37       
    3838    // Set label arrays
    3939    function SetLegends($aLegend) {
    40         $this->legends = array_reverse(array_slice($aLegend,0,count($this->data)));
     40        $this->legends = array_reverse(array_slice($aLegend,0,count($this->data)));
    4141    }
    4242
    4343    function SetSliceColors($aColors) {
    44         $this->setslicecolors = $aColors;
     44        $this->setslicecolors = $aColors;
    4545    }
    4646
    4747    function Legend($aGraph) {
    48         parent::Legend($aGraph);
    49         $aGraph->legend->txtcol = array_reverse($aGraph->legend->txtcol);
     48        parent::Legend($aGraph);
     49        $aGraph->legend->txtcol = array_reverse($aGraph->legend->txtcol);
    5050    }
    5151
    5252    function SetCSIMTargets($aTargets,$aAlts='',$aWinTargets='') {
    53         $this->csimtargets = $aTargets;
    54         $this->csimwintargets = $aWinTargets;
    55         $this->csimalts = $aAlts;
     53        $this->csimtargets = $aTargets;
     54        $this->csimwintargets = $aWinTargets;
     55        $this->csimalts = $aAlts;
    5656    }
    5757
     
    5959    // will be used to separate pie slices.
    6060    function SetEdge($aColor='black',$aWeight=1) {
    61         $this->edgecolor = $aColor;
    62         $this->edgeweight = $aWeight;
     61        $this->edgecolor = $aColor;
     62        $this->edgeweight = $aWeight;
     63    }
     64
     65    // Dummy function to make Pie3D behave in a similair way to 2D
     66    function ShowBorder($exterior=true,$interior=true) {
     67        JpGraphError::RaiseL(14001);
     68//('Pie3D::ShowBorder() . Deprecated function. Use Pie3D::SetEdge() to control the edges around slices.');
    6369    }
    6470
     
    6672    // Must be between 20 and 70 degrees
    6773    function SetAngle($a) {
    68         if( $a<5 || $a>90 ) {
    69             JpGraphError::RaiseL(14002);
    70             //("PiePlot3D::SetAngle() 3D Pie projection angle must be between 5 and 85 degrees.");
    71         }
    72         else {
    73             $this->angle = $a;
    74         }
     74        if( $a<5 || $a>90 )
     75            JpGraphError::RaiseL(14002);
     76//("PiePlot3D::SetAngle() 3D Pie projection angle must be between 5 and 85 degrees.");
     77        else
     78            $this->angle = $a;
    7579    }
    7680
    7781    function Add3DSliceToCSIM($i,$xc,$yc,$height,$width,$thick,$sa,$ea) {  //Slice number, ellipse centre (x,y), height, width, start angle, end angle
    7882
    79         $sa *= M_PI/180;
    80         $ea *= M_PI/180;
    81 
    82         //add coordinates of the centre to the map
    83         $coords = "$xc, $yc";
    84 
    85         //add coordinates of the first point on the arc to the map
    86         $xp = floor($width*cos($sa)/2+$xc);
    87         $yp = floor($yc-$height*sin($sa)/2);
    88         $coords.= ", $xp, $yp";
    89 
    90         //If on the front half, add the thickness offset
    91         if ($sa >= M_PI && $sa <= 2*M_PI*1.01) {
    92             $yp = floor($yp+$thick);
    93             $coords.= ", $xp, $yp";
    94         }
    95 
    96         //add coordinates every 0.2 radians
    97         $a=$sa+0.2;
    98         while ($a<$ea) {
    99             $xp = floor($width*cos($a)/2+$xc);
    100             if ($a >= M_PI && $a <= 2*M_PI*1.01) {
    101                 $yp = floor($yc-($height*sin($a)/2)+$thick);
    102             } else {
    103                 $yp = floor($yc-$height*sin($a)/2);
    104             }
    105             $coords.= ", $xp, $yp";
    106             $a += 0.2;
    107         }
    108 
    109         //Add the last point on the arc
    110         $xp = floor($width*cos($ea)/2+$xc);
    111         $yp = floor($yc-$height*sin($ea)/2);
    112 
    113 
    114         if ($ea >= M_PI && $ea <= 2*M_PI*1.01) {
    115             $coords.= ", $xp, ".floor($yp+$thick);
    116         }
    117         $coords.= ", $xp, $yp";
    118         $alt='';
    119 
    120         if( !empty($this->csimtargets[$i]) ) {
    121             $this->csimareas .= "<area shape=\"poly\" coords=\"$coords\" href=\"".$this->csimtargets[$i]."\"";
    122 
    123             if( !empty($this->csimwintargets[$i]) ) {
    124                 $this->csimareas .= " target=\"".$this->csimwintargets[$i]."\" ";
    125             }
    126             
    127             if( !empty($this->csimalts[$i]) ) {
    128                 $tmp=sprintf($this->csimalts[$i],$this->data[$i]);
    129                 $this->csimareas .= "alt=\"$tmp\" title=\"$tmp\" ";
    130             }
    131             $this->csimareas .=  " />\n";
    132         }
     83        $sa *= M_PI/180;
     84        $ea *= M_PI/180;
     85
     86        //add coordinates of the centre to the map
     87        $coords = "$xc, $yc";
     88
     89        //add coordinates of the first point on the arc to the map
     90        $xp = floor($width*cos($sa)/2+$xc);
     91        $yp = floor($yc-$height*sin($sa)/2);
     92        $coords.= ", $xp, $yp";
     93
     94        //If on the front half, add the thickness offset
     95        if ($sa >= M_PI && $sa <= 2*M_PI*1.01) {
     96            $yp = floor($yp+$thick);
     97            $coords.= ", $xp, $yp";
     98        }
     99               
     100        //add coordinates every 0.2 radians
     101        $a=$sa+0.2;
     102        while ($a<$ea) {
     103            $xp = floor($width*cos($a)/2+$xc);
     104            if ($a >= M_PI && $a <= 2*M_PI*1.01) {
     105                $yp = floor($yc-($height*sin($a)/2)+$thick);
     106            } else {
     107                $yp = floor($yc-$height*sin($a)/2);
     108            }
     109            $coords.= ", $xp, $yp";
     110            $a += 0.2;
     111        }
     112               
     113        //Add the last point on the arc
     114        $xp = floor($width*cos($ea)/2+$xc);
     115        $yp = floor($yc-$height*sin($ea)/2);
     116
     117
     118        if ($ea >= M_PI && $ea <= 2*M_PI*1.01) {
     119            $coords.= ", $xp, ".floor($yp+$thick);
     120        }
     121        $coords.= ", $xp, $yp";
     122        $alt='';
     123
     124        if( !empty($this->csimtargets[$i]) ) {
     125            $this->csimareas .= "<area shape=\"poly\" coords=\"$coords\" href=\"".$this->csimtargets[$i]."\"";
     126       
     127            if( !empty($this->csimwintargets[$i]) ) {
     128                $this->csimareas .= " target=\"".$this->csimwintargets[$i]."\" ";
     129            }
     130           
     131            if( !empty($this->csimalts[$i]) ) {                                                                         
     132                $tmp=sprintf($this->csimalts[$i],$this->data[$i]);
     133                $this->csimareas .= "alt=\"$tmp\" title=\"$tmp\" ";
     134            }
     135            $this->csimareas .=  " />\n";
     136        }
    133137
    134138    }
    135139
    136140    function SetLabels($aLabels,$aLblPosAdj="auto") {
    137         $this->labels = $aLabels;
    138         $this->ilabelposadj=$aLblPosAdj;
    139     }
    140 
    141 
     141        $this->labels = $aLabels;
     142        $this->ilabelposadj=$aLblPosAdj;
     143    }
     144
     145       
    142146    // Distance from the pie to the labels
    143147    function SetLabelMargin($m) {
    144         $this->value->SetMargin($m);
    145     }
    146 
     148        $this->value->SetMargin($m);
     149    }
     150       
    147151    // Show a thin line from the pie to the label for a specific slice
    148152    function ShowLabelHint($f=true) {
    149         $this->showlabelhint=$f;
    150     }
    151 
     153        $this->showlabelhint=$f;
     154    }
     155       
    152156    // Set color of hint line to label for each slice
    153157    function SetLabelHintColor($c) {
    154         $this->labelhintcolor=$c;
     158        $this->labelhintcolor=$c;
    155159    }
    156160
    157161    function SetHeight($aHeight) {
    158         $this->iThickness = $aHeight;
    159     }
    160 
    161 
    162     // Normalize Angle between 0-360
     162      $this->iThickness = $aHeight;
     163    }
     164
     165
     166// Normalize Angle between 0-360
    163167    function NormAngle($a) {
    164         // Normalize anle to 0 to 2M_PI
    165         //
    166         if( $a > 0 ) {
    167             while($a > 360) $a -= 360;
    168         }
    169         else {
    170             while($a < 0) $a += 360;
    171         }
    172         if( $a < 0 )
    173         $a = 360 + $a;
    174 
    175         if( $a == 360 ) $a=0;
    176         return $a;
    177     }
    178 
    179 
    180 
    181     // Draw one 3D pie slice at position ($xc,$yc) with height $z
     168        // Normalize anle to 0 to 2M_PI
     169        //
     170        if( $a > 0 ) {
     171            while($a > 360) $a -= 360;
     172        }
     173        else {
     174            while($a < 0) $a += 360;
     175        }
     176        if( $a < 0 )
     177            $a = 360 + $a;
     178
     179        if( $a == 360 ) $a=0;
     180        return $a;
     181    }
     182
     183   
     184
     185// Draw one 3D pie slice at position ($xc,$yc) with height $z
    182186    function Pie3DSlice($img,$xc,$yc,$w,$h,$sa,$ea,$z,$fillcolor,$shadow=0.65) {
    183 
    184         // Due to the way the 3D Pie algorithm works we are
    185         // guaranteed that any slice we get into this method
    186         // belongs to either the left or right side of the
    187         // pie ellipse. Hence, no slice will cross 90 or 270
    188         // point.
    189         if( ($sa < 90 && $ea > 90) || ( ($sa > 90 && $sa < 270) && $ea > 270) ) {
    190             JpGraphError::RaiseL(14003);//('Internal assertion failed. Pie3D::Pie3DSlice');
    191             exit(1);
    192         }
    193 
    194         $p[] = array();
    195 
    196         // Setup pre-calculated values
    197         $rsa = $sa/180*M_PI; // to Rad
    198         $rea = $ea/180*M_PI; // to Rad
    199         $sinsa = sin($rsa);
    200         $cossa = cos($rsa);
    201         $sinea = sin($rea);
    202         $cosea = cos($rea);
    203 
    204         // p[] is the points for the overall slice and
    205         // pt[] is the points for the top pie
    206 
    207         // Angular step when approximating the arc with a polygon train.
    208         $step = 0.05;
    209 
    210         if( $sa >= 270 ) {
    211             if( $ea > 360 || ($ea > 0 && $ea <= 90) ) {
    212                 if( $ea > 0 && $ea <= 90 ) {
    213                     // Adjust angle to simplify conditions in loops
    214                     $rea += 2*M_PI;
    215                 }
    216 
    217                 $p = array($xc,$yc,$xc,$yc+$z,
    218                 $xc+$w*$cossa,$z+$yc-$h*$sinsa);
    219                 $pt = array($xc,$yc,$xc+$w*$cossa,$yc-$h*$sinsa);
    220 
    221                 for( $a=$rsa; $a < 2*M_PI; $a += $step ) {
    222                     $tca = cos($a);
    223                     $tsa = sin($a);
    224                     $p[] = $xc+$w*$tca;
    225                     $p[] = $z+$yc-$h*$tsa;
    226                     $pt[] = $xc+$w*$tca;
    227                     $pt[] = $yc-$h*$tsa;
    228                 }
    229 
    230                 $pt[] = $xc+$w;
    231                 $pt[] = $yc;
    232 
    233                 $p[] = $xc+$w;
    234                 $p[] = $z+$yc;
    235                 $p[] = $xc+$w;
    236                 $p[] = $yc;
    237                 $p[] = $xc;
    238                 $p[] = $yc;
    239 
    240                 for( $a=2*M_PI+$step; $a < $rea; $a += $step ) {
    241                     $pt[] = $xc + $w*cos($a);
    242                     $pt[] = $yc - $h*sin($a);
    243                 }
    244 
    245                 $pt[] = $xc+$w*$cosea;
    246                 $pt[] = $yc-$h*$sinea;
    247                 $pt[] = $xc;
    248                 $pt[] = $yc;
    249 
    250             }
    251             else {
    252                 $p = array($xc,$yc,$xc,$yc+$z,
    253                 $xc+$w*$cossa,$z+$yc-$h*$sinsa);
    254                 $pt = array($xc,$yc,$xc+$w*$cossa,$yc-$h*$sinsa);
    255 
    256                 $rea = $rea == 0.0 ? 2*M_PI : $rea;
    257                 for( $a=$rsa; $a < $rea; $a += $step ) {
    258                     $tca = cos($a);
    259                     $tsa = sin($a);
    260                     $p[] = $xc+$w*$tca;
    261                     $p[] = $z+$yc-$h*$tsa;
    262                     $pt[] = $xc+$w*$tca;
    263                     $pt[] = $yc-$h*$tsa;
    264                 }
    265 
    266                 $pt[] = $xc+$w*$cosea;
    267                 $pt[] = $yc-$h*$sinea;
    268                 $pt[] = $xc;
    269                 $pt[] = $yc;
    270 
    271                 $p[] = $xc+$w*$cosea;
    272                 $p[] = $z+$yc-$h*$sinea;
    273                 $p[] = $xc+$w*$cosea;
    274                 $p[] = $yc-$h*$sinea;
    275                 $p[] = $xc;
    276                 $p[] = $yc;
    277             }
    278         }
    279         elseif( $sa >= 180 ) {
    280             $p = array($xc,$yc,$xc,$yc+$z,$xc+$w*$cosea,$z+$yc-$h*$sinea);
    281             $pt = array($xc,$yc,$xc+$w*$cosea,$yc-$h*$sinea);
    282 
    283             for( $a=$rea; $a>$rsa; $a -= $step ) {
    284                 $tca = cos($a);
    285                 $tsa = sin($a);
    286                 $p[] = $xc+$w*$tca;
    287                 $p[] = $z+$yc-$h*$tsa;
    288                 $pt[] = $xc+$w*$tca;
    289                 $pt[] = $yc-$h*$tsa;
    290             }
    291 
    292             $pt[] = $xc+$w*$cossa;
    293             $pt[] = $yc-$h*$sinsa;
    294             $pt[] = $xc;
    295             $pt[] = $yc;
    296 
    297             $p[] = $xc+$w*$cossa;
    298             $p[] = $z+$yc-$h*$sinsa;
    299             $p[] = $xc+$w*$cossa;
    300             $p[] = $yc-$h*$sinsa;
    301             $p[] = $xc;
    302             $p[] = $yc;
    303 
    304         }
    305         elseif( $sa >= 90 ) {
    306             if( $ea > 180 ) {
    307                 $p = array($xc,$yc,$xc,$yc+$z,$xc+$w*$cosea,$z+$yc-$h*$sinea);
    308                 $pt = array($xc,$yc,$xc+$w*$cosea,$yc-$h*$sinea);
    309 
    310                 for( $a=$rea; $a > M_PI; $a -= $step ) {
    311                     $tca = cos($a);
    312                     $tsa = sin($a);
    313                     $p[] = $xc+$w*$tca;
    314                     $p[] = $z + $yc - $h*$tsa;
    315                     $pt[] = $xc+$w*$tca;
    316                     $pt[] = $yc-$h*$tsa;
    317                 }
    318 
    319                 $p[] = $xc-$w;
    320                 $p[] = $z+$yc;
    321                 $p[] = $xc-$w;
    322                 $p[] = $yc;
    323                 $p[] = $xc;
    324                 $p[] = $yc;
    325 
    326                 $pt[] = $xc-$w;
    327                 $pt[] = $z+$yc;
    328                 $pt[] = $xc-$w;
    329                 $pt[] = $yc;
    330 
    331                 for( $a=M_PI-$step; $a > $rsa; $a -= $step ) {
    332                     $pt[] = $xc + $w*cos($a);
    333                     $pt[] = $yc - $h*sin($a);
    334                 }
    335 
    336                 $pt[] = $xc+$w*$cossa;
    337                 $pt[] = $yc-$h*$sinsa;
    338                 $pt[] = $xc;
    339                 $pt[] = $yc;
    340 
    341             }
    342             else { // $sa >= 90 && $ea <= 180
    343                 $p = array($xc,$yc,$xc,$yc+$z,
    344                 $xc+$w*$cosea,$z+$yc-$h*$sinea,
    345                 $xc+$w*$cosea,$yc-$h*$sinea,
    346                 $xc,$yc);
    347 
    348                 $pt = array($xc,$yc,$xc+$w*$cosea,$yc-$h*$sinea);
    349 
    350                 for( $a=$rea; $a>$rsa; $a -= $step ) {
    351                     $pt[] = $xc + $w*cos($a);
    352                     $pt[] = $yc - $h*sin($a);
    353                 }
    354 
    355                 $pt[] = $xc+$w*$cossa;
    356                 $pt[] = $yc-$h*$sinsa;
    357                 $pt[] = $xc;
    358                 $pt[] = $yc;
    359 
    360             }
    361         }
    362         else { // sa > 0 && ea < 90
    363 
    364             $p = array($xc,$yc,$xc,$yc+$z,
    365             $xc+$w*$cossa,$z+$yc-$h*$sinsa,
    366             $xc+$w*$cossa,$yc-$h*$sinsa,
    367             $xc,$yc);
    368 
    369             $pt = array($xc,$yc,$xc+$w*$cossa,$yc-$h*$sinsa);
    370 
    371             for( $a=$rsa; $a < $rea; $a += $step ) {
    372                 $pt[] = $xc + $w*cos($a);
    373                 $pt[] = $yc - $h*sin($a);
    374             }
    375 
    376             $pt[] = $xc+$w*$cosea;
    377             $pt[] = $yc-$h*$sinea;
    378             $pt[] = $xc;
    379             $pt[] = $yc;
    380         }
    381         
    382         $img->PushColor($fillcolor.":".$shadow);
    383         $img->FilledPolygon($p);
    384         $img->PopColor();
    385 
    386         $img->PushColor($fillcolor);
    387         $img->FilledPolygon($pt);
    388         $img->PopColor();
     187       
     188        // Due to the way the 3D Pie algorithm works we are
     189        // guaranteed that any slice we get into this method
     190        // belongs to either the left or right side of the
     191        // pie ellipse. Hence, no slice will cross 90 or 270
     192        // point.
     193        if( ($sa < 90 && $ea > 90) || ( ($sa > 90 && $sa < 270) && $ea > 270) ) {
     194            JpGraphError::RaiseL(14003);//('Internal assertion failed. Pie3D::Pie3DSlice');
     195            exit(1);
     196        }
     197
     198        $p[] = array();
     199
     200        // Setup pre-calculated values
     201        $rsa = $sa/180*M_PI;    // to Rad
     202        $rea = $ea/180*M_PI;    // to Rad
     203        $sinsa = sin($rsa);
     204        $cossa = cos($rsa);
     205        $sinea = sin($rea);
     206        $cosea = cos($rea);
     207
     208        // p[] is the points for the overall slice and
     209        // pt[] is the points for the top pie
     210
     211        // Angular step when approximating the arc with a polygon train.
     212        $step = 0.05;
     213
     214        if( $sa >= 270 ) {
     215            if( $ea > 360 || ($ea > 0 && $ea <= 90) ) {
     216                if( $ea > 0 && $ea <= 90 ) {
     217                    // Adjust angle to simplify conditions in loops
     218                    $rea += 2*M_PI;
     219                }
     220
     221                $p = array($xc,$yc,$xc,$yc+$z,
     222                           $xc+$w*$cossa,$z+$yc-$h*$sinsa);
     223                $pt = array($xc,$yc,$xc+$w*$cossa,$yc-$h*$sinsa);
     224
     225                for( $a=$rsa; $a < 2*M_PI; $a += $step ) {
     226                    $tca = cos($a);
     227                    $tsa = sin($a);
     228                    $p[] = $xc+$w*$tca;
     229                    $p[] = $z+$yc-$h*$tsa;
     230                    $pt[] = $xc+$w*$tca;
     231                    $pt[] = $yc-$h*$tsa;
     232                }
     233
     234                $pt[] = $xc+$w;
     235                $pt[] = $yc;
     236
     237                $p[] = $xc+$w;
     238                $p[] = $z+$yc;
     239                $p[] = $xc+$w;
     240                $p[] = $yc;
     241                $p[] = $xc;
     242                $p[] = $yc;
     243
     244                for( $a=2*M_PI+$step; $a < $rea; $a += $step ) {
     245                    $pt[] = $xc + $w*cos($a);
     246                    $pt[] = $yc - $h*sin($a);
     247                }
     248                   
     249                $pt[] = $xc+$w*$cosea;
     250                $pt[] = $yc-$h*$sinea;
     251                $pt[] = $xc;
     252                $pt[] = $yc;
     253
     254            }
     255            else {
     256                $p = array($xc,$yc,$xc,$yc+$z,
     257                           $xc+$w*$cossa,$z+$yc-$h*$sinsa);
     258                $pt = array($xc,$yc,$xc+$w*$cossa,$yc-$h*$sinsa);
     259                   
     260                $rea = $rea == 0.0 ? 2*M_PI : $rea;
     261                for( $a=$rsa; $a < $rea; $a += $step ) {
     262                    $tca = cos($a);
     263                    $tsa = sin($a);
     264                    $p[] = $xc+$w*$tca;
     265                    $p[] = $z+$yc-$h*$tsa;
     266                    $pt[] = $xc+$w*$tca;
     267                    $pt[] = $yc-$h*$tsa;
     268                }
     269
     270                $pt[] = $xc+$w*$cosea;
     271                $pt[] = $yc-$h*$sinea;
     272                $pt[] = $xc;
     273                $pt[] = $yc;
     274                   
     275                $p[] = $xc+$w*$cosea;
     276                $p[] = $z+$yc-$h*$sinea;
     277                $p[] = $xc+$w*$cosea;
     278                $p[] = $yc-$h*$sinea;
     279                $p[] = $xc;
     280                $p[] = $yc;
     281            }
     282        }
     283        elseif( $sa >= 180 ) {
     284            $p = array($xc,$yc,$xc,$yc+$z,$xc+$w*$cosea,$z+$yc-$h*$sinea);
     285            $pt = array($xc,$yc,$xc+$w*$cosea,$yc-$h*$sinea);
     286               
     287            for( $a=$rea; $a>$rsa; $a -= $step ) {
     288                $tca = cos($a);
     289                $tsa = sin($a);
     290                $p[] = $xc+$w*$tca;
     291                $p[] = $z+$yc-$h*$tsa;
     292                $pt[] = $xc+$w*$tca;
     293                $pt[] = $yc-$h*$tsa;
     294            }
     295
     296            $pt[] = $xc+$w*$cossa;
     297            $pt[] = $yc-$h*$sinsa;
     298            $pt[] = $xc;
     299            $pt[] = $yc;
     300               
     301            $p[] = $xc+$w*$cossa;
     302            $p[] = $z+$yc-$h*$sinsa;
     303            $p[] = $xc+$w*$cossa;
     304            $p[] = $yc-$h*$sinsa;
     305            $p[] = $xc;
     306            $p[] = $yc;
     307       
     308        }
     309        elseif( $sa >= 90 ) {
     310            if( $ea > 180 ) {
     311                $p = array($xc,$yc,$xc,$yc+$z,$xc+$w*$cosea,$z+$yc-$h*$sinea);
     312                $pt = array($xc,$yc,$xc+$w*$cosea,$yc-$h*$sinea);
     313
     314                for( $a=$rea; $a > M_PI; $a -= $step ) {
     315                    $tca = cos($a);
     316                    $tsa = sin($a);                 
     317                    $p[] = $xc+$w*$tca;
     318                    $p[] = $z + $yc - $h*$tsa;
     319                    $pt[] = $xc+$w*$tca;
     320                    $pt[] = $yc-$h*$tsa;
     321                }
     322
     323                $p[] = $xc-$w;
     324                $p[] = $z+$yc;
     325                $p[] = $xc-$w;
     326                $p[] = $yc;
     327                $p[] = $xc;
     328                $p[] = $yc;
     329
     330                $pt[] = $xc-$w;
     331                $pt[] = $z+$yc;
     332                $pt[] = $xc-$w;
     333                $pt[] = $yc;
     334
     335                for( $a=M_PI-$step; $a > $rsa; $a -= $step ) {
     336                    $pt[] = $xc + $w*cos($a);
     337                    $pt[] = $yc - $h*sin($a);
     338                }
     339
     340                $pt[] = $xc+$w*$cossa;
     341                $pt[] = $yc-$h*$sinsa;
     342                $pt[] = $xc;
     343                $pt[] = $yc;
     344
     345            }
     346            else { // $sa >= 90 && $ea <= 180
     347                $p = array($xc,$yc,$xc,$yc+$z,
     348                           $xc+$w*$cosea,$z+$yc-$h*$sinea,
     349                           $xc+$w*$cosea,$yc-$h*$sinea,
     350                           $xc,$yc);
     351
     352                $pt = array($xc,$yc,$xc+$w*$cosea,$yc-$h*$sinea);
     353
     354                for( $a=$rea; $a>$rsa; $a -= $step ) {
     355                    $pt[] = $xc + $w*cos($a);
     356                    $pt[] = $yc - $h*sin($a);
     357                }
     358
     359                $pt[] = $xc+$w*$cossa;
     360                $pt[] = $yc-$h*$sinsa;
     361                $pt[] = $xc;
     362                $pt[] = $yc;
     363
     364            }
     365        }
     366        else { // sa > 0 && ea < 90
     367
     368            $p = array($xc,$yc,$xc,$yc+$z,
     369                       $xc+$w*$cossa,$z+$yc-$h*$sinsa,
     370                       $xc+$w*$cossa,$yc-$h*$sinsa,
     371                       $xc,$yc);
     372
     373            $pt = array($xc,$yc,$xc+$w*$cossa,$yc-$h*$sinsa);
     374
     375            for( $a=$rsa; $a < $rea; $a += $step ) {
     376                $pt[] = $xc + $w*cos($a);
     377                $pt[] = $yc - $h*sin($a);
     378            }
     379
     380            $pt[] = $xc+$w*$cosea;
     381            $pt[] = $yc-$h*$sinea;
     382            $pt[] = $xc;
     383            $pt[] = $yc;
     384        }
     385           
     386        $img->PushColor($fillcolor.":".$shadow);
     387        $img->FilledPolygon($p);
     388        $img->PopColor();
     389
     390        $img->PushColor($fillcolor);
     391        $img->FilledPolygon($pt);
     392        $img->PopColor();
    389393    }
    390394
    391395    function SetStartAngle($aStart) {
    392         if( $aStart < 0 || $aStart > 360 ) {
    393             JpGraphError::RaiseL(14004);//('Slice start angle must be between 0 and 360 degrees.');
    394         }
    395         $this->startangle = $aStart;
    396     }
    397 
    398     // Draw a 3D Pie
     396        if( $aStart < 0 || $aStart > 360 ) {
     397            JpGraphError::RaiseL(14004);//('Slice start angle must be between 0 and 360 degrees.');
     398        }
     399        $this->startangle = $aStart;
     400    }
     401   
     402// Draw a 3D Pie
    399403    function Pie3D($aaoption,$img,$data,$colors,$xc,$yc,$d,$angle,$z,
    400                    $shadow=0.65,$startangle=0,$edgecolor="",$edgeweight=1) {
    401 
    402         //---------------------------------------------------------------------------
    403         // As usual the algorithm get more complicated than I originally
    404         // envisioned. I believe that this is as simple as it is possible
    405         // to do it with the features I want. It's a good exercise to start
    406         // thinking on how to do this to convince your self that all this
    407         // is really needed for the general case.
    408         //
    409         // The algorithm two draw 3D pies without "real 3D" is done in
    410         // two steps.
    411         // First imagine the pie cut in half through a thought line between
    412         // 12'a clock and 6'a clock. It now easy to imagine that we can plot
    413         // the individual slices for each half by starting with the topmost
    414         // pie slice and continue down to 6'a clock.
    415         //
    416         // In the algortithm this is done in three principal steps
    417         // Step 1. Do the knife cut to ensure by splitting slices that extends
    418         // over the cut line. This is done by splitting the original slices into
    419         // upto 3 subslices.
    420         // Step 2. Find the top slice for each half
    421         // Step 3. Draw the slices from top to bottom
    422         //
    423         // The thing that slightly complicates this scheme with all the
    424         // angle comparisons below is that we can have an arbitrary start
    425         // angle so we must take into account the different equivalence classes.
    426         // For the same reason we must walk through the angle array in a
    427         // modulo fashion.
    428         //
    429         // Limitations of algorithm:
    430         // * A small exploded slice which crosses the 270 degree point
    431         //   will get slightly nagged close to the center due to the fact that
    432         //   we print the slices in Z-order and that the slice left part
    433         //   get printed first and might get slightly nagged by a larger
    434         //   slice on the right side just before the right part of the small
    435         //   slice. Not a major problem though.
    436         //---------------------------------------------------------------------------
    437 
    438 
    439         // Determine the height of the ellippse which gives an
    440         // indication of the inclination angle
    441         $h = ($angle/90.0)*$d;
    442         $sum = 0;
    443         for($i=0; $i<count($data); ++$i ) {
    444             $sum += $data[$i];
    445         }
    446 
    447         // Special optimization
    448         if( $sum==0 ) return;
    449 
    450         if( $this->labeltype == 2 ) {
    451             $this->adjusted_data = $this->AdjPercentage($data);
    452         }
    453 
    454         // Setup the start
    455         $accsum = 0;
    456         $a = $startangle;
    457         $a = $this->NormAngle($a);
    458 
    459         //
    460         // Step 1 . Split all slices that crosses 90 or 270
    461         //
    462         $idx=0;
    463         $adjexplode=array();
    464         $numcolors = count($colors);
    465         for($i=0; $i<count($data); ++$i, ++$idx ) {
    466             $da = $data[$i]/$sum * 360;
    467 
    468             if( empty($this->explode_radius[$i]) ) {
    469                 $this->explode_radius[$i]=0;
    470             }
    471 
    472             $expscale=1;
    473             if( $aaoption == 1 ) {
    474                 $expscale=2;
    475             }
    476 
    477             $la = $a + $da/2;
    478             $explode = array( $xc + $this->explode_radius[$i]*cos($la*M_PI/180)*$expscale,
    479             $yc - $this->explode_radius[$i]*sin($la*M_PI/180) * ($h/$d) *$expscale );
    480             $adjexplode[$idx] = $explode;
    481             $labeldata[$i] = array($la,$explode[0],$explode[1]);
    482             $originalangles[$i] = array($a,$a+$da);
    483 
    484             $ne = $this->NormAngle($a+$da);
    485             if( $da <= 180 ) {
    486                 // If the slice size is <= 90 it can at maximum cut across
    487                 // one boundary (either 90 or 270) where it needs to be split
    488                 $split=-1; // no split
    489                 if( ($da<=90 && ($a <= 90 && $ne > 90)) ||
    490                 (($da <= 180 && $da >90)  && (($a < 90 || $a >= 270) && $ne > 90)) ) {
    491                     $split = 90;
    492                 }
    493                 elseif( ($da<=90 && ($a <= 270 && $ne > 270)) ||
    494                 (($da<=180 && $da>90) && ($a >= 90 && $a < 270 && ($a+$da) > 270 )) ) {
    495                     $split = 270;
    496                 }
    497                 if( $split > 0 ) { // split in two
    498                     $angles[$idx] = array($a,$split);
    499                     $adjcolors[$idx] = $colors[$i % $numcolors];
    500                     $adjexplode[$idx] = $explode;
    501                     $angles[++$idx] = array($split,$ne);
    502                     $adjcolors[$idx] = $colors[$i % $numcolors];
    503                     $adjexplode[$idx] = $explode;
    504                 }
    505                 else { // no split
    506                     $angles[$idx] = array($a,$ne);
    507                     $adjcolors[$idx] = $colors[$i  % $numcolors];
    508                     $adjexplode[$idx] = $explode;
    509                 }
    510             }
    511             else {
    512                 // da>180
    513                 // Slice may, depending on position, cross one or two
    514                 // bonudaries
    515 
    516                 if( $a < 90 )        $split = 90;
    517                 elseif( $a <= 270 )  $split = 270;
    518                 else                 $split = 90;
    519 
    520                 $angles[$idx] = array($a,$split);
    521                 $adjcolors[$idx] = $colors[$i % $numcolors];
    522                 $adjexplode[$idx] = $explode;
    523                 //if( $a+$da > 360-$split ) {
    524                 // For slices larger than 270 degrees we might cross
    525                 // another boundary as well. This means that we must
    526                 // split the slice further. The comparison gets a little
    527                 // bit complicated since we must take into accound that
    528                 // a pie might have a startangle >0 and hence a slice might
    529                 // wrap around the 0 angle.
    530                 // Three cases:
    531                 //  a) Slice starts before 90 and hence gets a split=90, but
    532                 //     we must also check if we need to split at 270
    533                 //  b) Slice starts after 90 but before 270 and slices
    534                 //     crosses 90 (after a wrap around of 0)
    535                 //  c) If start is > 270 (hence the firstr split is at 90)
    536                 //     and the slice is so large that it goes all the way
    537                 //     around 270.
    538                 if( ($a < 90 && ($a+$da > 270)) || ($a > 90 && $a<=270 && ($a+$da>360+90) ) || ($a > 270 && $this->NormAngle($a+$da)>270) ) {
    539                     $angles[++$idx] = array($split,360-$split);
    540                     $adjcolors[$idx] = $colors[$i % $numcolors];
    541                     $adjexplode[$idx] = $explode;
    542                     $angles[++$idx] = array(360-$split,$ne);
    543                     $adjcolors[$idx] = $colors[$i % $numcolors];
    544                     $adjexplode[$idx] = $explode;
    545                 }
    546                 else {
    547                     // Just a simple split to the previous decided
    548                     // angle.
    549                     $angles[++$idx] = array($split,$ne);
    550                     $adjcolors[$idx] = $colors[$i % $numcolors];
    551                     $adjexplode[$idx] = $explode;
    552                 }
    553             }
    554             $a += $da;
    555             $a = $this->NormAngle($a);
    556         }
    557 
    558         // Total number of slices
    559         $n = count($angles);
    560 
    561         for($i=0; $i<$n; ++$i) {
    562             list($dbgs,$dbge) = $angles[$i];
    563         }
    564 
    565         //
    566         // Step 2. Find start index (first pie that starts in upper left quadrant)
    567         //
    568         $minval = $angles[0][0];
    569         $min = 0;
    570         for( $i=0; $i<$n; ++$i ) {
    571             if( $angles[$i][0] < $minval ) {
    572                 $minval = $angles[$i][0];
    573                 $min = $i;
    574             }
    575         }
    576         $j = $min;
    577         $cnt = 0;
    578         while( $angles[$j][1] <= 90 ) {
    579             $j++;
    580             if( $j>=$n) {
    581                 $j=0;
    582             }
    583             if( $cnt > $n ) {
    584                 JpGraphError::RaiseL(14005);
    585                 //("Pie3D Internal error (#1). Trying to wrap twice when looking for start index");
    586             }
    587             ++$cnt;
    588         }
    589         $start = $j;
    590 
    591         //
    592         // Step 3. Print slices in z-order
    593         //
    594         $cnt = 0;
    595 
    596         // First stroke all the slices between 90 and 270 (left half circle)
    597         // counterclockwise
    598          
    599         while( $angles[$j][0] < 270  && $aaoption !== 2 ) {
    600 
    601             list($x,$y) = $adjexplode[$j];
    602 
    603             $this->Pie3DSlice($img,$x,$y,$d,$h,$angles[$j][0],$angles[$j][1],
    604             $z,$adjcolors[$j],$shadow);
    605 
    606             $last = array($x,$y,$j);
    607 
    608             $j++;
    609             if( $j >= $n ) $j=0;
    610             if( $cnt > $n ) {
    611                 JpGraphError::RaiseL(14006);
    612                 //("Pie3D Internal Error: Z-Sorting algorithm for 3D Pies is not working properly (2). Trying to wrap twice while stroking.");
    613             }
    614             ++$cnt;
    615         }
    616          
    617         $slice_left = $n-$cnt;
    618         $j=$start-1;
    619         if($j<0) $j=$n-1;
    620         $cnt = 0;
    621 
    622         // The stroke all slices from 90 to -90 (right half circle)
    623         // clockwise
    624         while( $cnt < $slice_left  && $aaoption !== 2 ) {
    625 
    626             list($x,$y) = $adjexplode[$j];
    627 
    628             $this->Pie3DSlice($img,$x,$y,$d,$h,$angles[$j][0],$angles[$j][1],
    629             $z,$adjcolors[$j],$shadow);
    630             $j--;
    631             if( $cnt > $n ) {
    632                 JpGraphError::RaiseL(14006);
    633                 //("Pie3D Internal Error: Z-Sorting algorithm for 3D Pies is not working properly (2). Trying to wrap twice while stroking.");
    634             }
    635             if($j<0) $j=$n-1;
    636             $cnt++;
    637         }
    638 
    639         // Now do a special thing. Stroke the last slice on the left
    640         // halfcircle one more time.  This is needed in the case where
    641         // the slice close to 270 have been exploded. In that case the
    642         // part of the slice close to the center of the pie might be
    643         // slightly nagged.
    644         if( $aaoption !== 2 )
    645         $this->Pie3DSlice($img,$last[0],$last[1],$d,$h,$angles[$last[2]][0],
    646         $angles[$last[2]][1],$z,$adjcolors[$last[2]],$shadow);
    647 
    648 
    649         if( $aaoption !== 1 ) {
    650             // Now print possible labels and add csim
    651             $this->value->ApplyFont($img);
    652             $margin = $img->GetFontHeight()/2 + $this->value->margin ;
    653             for($i=0; $i < count($data); ++$i ) {
    654                 $la = $labeldata[$i][0];
    655                 $x = $labeldata[$i][1] + cos($la*M_PI/180)*($d+$margin)*$this->ilabelposadj;
    656                 $y = $labeldata[$i][2] - sin($la*M_PI/180)*($h+$margin)*$this->ilabelposadj;
    657                 if( $this->ilabelposadj >= 1.0 ) {
    658                     if( $la > 180 && $la < 360 ) $y += $z;
    659                 }
    660                 if( $this->labeltype == 0 ) {
    661                     if( $sum > 0 ) $l = 100*$data[$i]/$sum;
    662                     else $l = 0;
    663                 }
    664                 elseif( $this->labeltype == 1 ) {
    665                     $l = $data[$i];
    666                 }
    667                 else {
    668                     $l = $this->adjusted_data[$i];
    669                 }
    670                 if( isset($this->labels[$i]) && is_string($this->labels[$i]) ) {
    671                     $l=sprintf($this->labels[$i],$l);
    672                 }
    673 
    674                 $this->StrokeLabels($l,$img,$labeldata[$i][0]*M_PI/180,$x,$y,$z);
    675                  
    676                 $this->Add3DSliceToCSIM($i,$labeldata[$i][1],$labeldata[$i][2],$h*2,$d*2,$z,
    677                 $originalangles[$i][0],$originalangles[$i][1]);
    678             }
    679         }
    680 
    681         //
    682         // Finally add potential lines in pie
    683         //
    684 
    685         if( $edgecolor=="" || $aaoption !== 0 ) return;
    686 
    687         $accsum = 0;
    688         $a = $startangle;
    689         $a = $this->NormAngle($a);
    690 
    691         $a *= M_PI/180.0;
    692 
    693         $idx=0;
    694         $img->PushColor($edgecolor);
    695         $img->SetLineWeight($edgeweight);
    696 
    697         $fulledge = true;
    698         for($i=0; $i < count($data) && $fulledge; ++$i ) {
    699             if( empty($this->explode_radius[$i]) ) {
    700                 $this->explode_radius[$i]=0;
    701             }
    702             if( $this->explode_radius[$i] > 0 ) {
    703                 $fulledge = false;
    704             }
    705         }
    706          
    707 
    708         for($i=0; $i < count($data); ++$i, ++$idx ) {
    709 
    710             $da = $data[$i]/$sum * 2*M_PI;
    711             $this->StrokeFullSliceFrame($img,$xc,$yc,$a,$a+$da,$d,$h,$z,$edgecolor,
    712             $this->explode_radius[$i],$fulledge);
    713             $a += $da;
    714         }
    715         $img->PopColor();
     404                   $shadow=0.65,$startangle=0,$edgecolor="",$edgeweight=1) {
     405
     406        //---------------------------------------------------------------------------
     407        // As usual the algorithm get more complicated than I originally
     408        // envisioned. I believe that this is as simple as it is possible
     409        // to do it with the features I want. It's a good exercise to start
     410        // thinking on how to do this to convince your self that all this
     411        // is really needed for the general case.
     412        //
     413        // The algorithm two draw 3D pies without "real 3D" is done in
     414        // two steps.
     415        // First imagine the pie cut in half through a thought line between
     416        // 12'a clock and 6'a clock. It now easy to imagine that we can plot
     417        // the individual slices for each half by starting with the topmost
     418        // pie slice and continue down to 6'a clock.
     419        //
     420        // In the algortithm this is done in three principal steps
     421        // Step 1. Do the knife cut to ensure by splitting slices that extends
     422        // over the cut line. This is done by splitting the original slices into
     423        // upto 3 subslices.
     424        // Step 2. Find the top slice for each half
     425        // Step 3. Draw the slices from top to bottom
     426        //
     427        // The thing that slightly complicates this scheme with all the
     428        // angle comparisons below is that we can have an arbitrary start
     429        // angle so we must take into account the different equivalence classes.
     430        // For the same reason we must walk through the angle array in a
     431        // modulo fashion.
     432        //
     433        // Limitations of algorithm:
     434        // * A small exploded slice which crosses the 270 degree point
     435        //   will get slightly nagged close to the center due to the fact that
     436        //   we print the slices in Z-order and that the slice left part
     437        //   get printed first and might get slightly nagged by a larger
     438        //   slice on the right side just before the right part of the small
     439        //   slice. Not a major problem though.
     440        //---------------------------------------------------------------------------
     441
     442   
     443        // Determine the height of the ellippse which gives an
     444        // indication of the inclination angle
     445        $h = ($angle/90.0)*$d;
     446        $sum = 0;
     447        for($i=0; $i<count($data); ++$i ) {
     448            $sum += $data[$i];
     449        }
     450       
     451        // Special optimization
     452        if( $sum==0 ) return;
     453
     454        if( $this->labeltype == 2 ) {
     455            $this->adjusted_data = $this->AdjPercentage($data);
     456        }
     457
     458        // Setup the start
     459        $accsum = 0;
     460        $a = $startangle;
     461        $a = $this->NormAngle($a);
     462
     463        //
     464        // Step 1 . Split all slices that crosses 90 or 270
     465        //
     466        $idx=0;
     467        $adjexplode=array();
     468        $numcolors = count($colors);
     469        for($i=0; $i<count($data); ++$i, ++$idx ) {
     470            $da = $data[$i]/$sum * 360;
     471
     472            if( empty($this->explode_radius[$i]) )
     473                $this->explode_radius[$i]=0;
     474
     475            $expscale=1;
     476            if( $aaoption == 1 )
     477                $expscale=2;
     478
     479            $la = $a + $da/2;
     480            $explode = array( $xc + $this->explode_radius[$i]*cos($la*M_PI/180)*$expscale,
     481                              $yc - $this->explode_radius[$i]*sin($la*M_PI/180) * ($h/$d) *$expscale );
     482            $adjexplode[$idx] = $explode;
     483            $labeldata[$i] = array($la,$explode[0],$explode[1]);
     484            $originalangles[$i] = array($a,$a+$da);
     485
     486            $ne = $this->NormAngle($a+$da);
     487            if( $da <= 180 ) {
     488                // If the slice size is <= 90 it can at maximum cut across
     489                // one boundary (either 90 or 270) where it needs to be split
     490                $split=-1; // no split
     491                if( ($da<=90 && ($a <= 90 && $ne > 90)) ||
     492                    (($da <= 180 && $da >90)  && (($a < 90 || $a >= 270) && $ne > 90)) ) {
     493                    $split = 90;
     494                }
     495                elseif( ($da<=90 && ($a <= 270 && $ne > 270)) ||
     496                        (($da<=180 && $da>90) && ($a >= 90 && $a < 270 && ($a+$da) > 270 )) ) {
     497                    $split = 270;
     498                }
     499                if( $split > 0 ) { // split in two
     500                    $angles[$idx] = array($a,$split);
     501                    $adjcolors[$idx] = $colors[$i % $numcolors];
     502                    $adjexplode[$idx] = $explode;
     503                    $angles[++$idx] = array($split,$ne);
     504                    $adjcolors[$idx] = $colors[$i % $numcolors];
     505                    $adjexplode[$idx] = $explode;
     506                }
     507                else { // no split
     508                    $angles[$idx] = array($a,$ne);
     509                    $adjcolors[$idx] = $colors[$i  % $numcolors];
     510                    $adjexplode[$idx] = $explode;       
     511                }
     512            }
     513            else {
     514                // da>180
     515                // Slice may, depending on position, cross one or two
     516                // bonudaries
     517
     518                if( $a < 90 )
     519                    $split = 90;
     520                elseif( $a <= 270 )
     521                    $split = 270;
     522                else
     523                    $split = 90;
     524
     525                $angles[$idx] = array($a,$split);
     526                $adjcolors[$idx] = $colors[$i % $numcolors];
     527                $adjexplode[$idx] = $explode;
     528                //if( $a+$da > 360-$split ) {
     529                // For slices larger than 270 degrees we might cross
     530                // another boundary as well. This means that we must
     531                // split the slice further. The comparison gets a little
     532                // bit complicated since we must take into accound that
     533                // a pie might have a startangle >0 and hence a slice might
     534                // wrap around the 0 angle.
     535                // Three cases:
     536                //  a) Slice starts before 90 and hence gets a split=90, but
     537                //     we must also check if we need to split at 270
     538                //  b) Slice starts after 90 but before 270 and slices
     539                //     crosses 90 (after a wrap around of 0)
     540                //  c) If start is > 270 (hence the firstr split is at 90)
     541                //     and the slice is so large that it goes all the way
     542                //     around 270.
     543                if( ($a < 90 && ($a+$da > 270)) ||
     544                    ($a > 90 && $a<=270 && ($a+$da>360+90) ) ||
     545                    ($a > 270 && $this->NormAngle($a+$da)>270) ) {
     546                    $angles[++$idx] = array($split,360-$split);
     547                    $adjcolors[$idx] = $colors[$i % $numcolors];
     548                    $adjexplode[$idx] = $explode;
     549                    $angles[++$idx] = array(360-$split,$ne);
     550                    $adjcolors[$idx] = $colors[$i % $numcolors];
     551                    $adjexplode[$idx] = $explode;
     552                }       
     553                else {
     554                    // Just a simple split to the previous decided
     555                    // angle.
     556                    $angles[++$idx] = array($split,$ne);
     557                    $adjcolors[$idx] = $colors[$i % $numcolors];
     558                    $adjexplode[$idx] = $explode;
     559                }
     560            }
     561            $a += $da;
     562            $a = $this->NormAngle($a);
     563        }
     564
     565        // Total number of slices
     566        $n = count($angles);
     567
     568        for($i=0; $i<$n; ++$i) {
     569            list($dbgs,$dbge) = $angles[$i];
     570        }
     571
     572        //
     573        // Step 2. Find start index (first pie that starts in upper left quadrant)
     574        //
     575        $minval = $angles[0][0];
     576        $min = 0;
     577        for( $i=0; $i<$n; ++$i ) {
     578            if( $angles[$i][0] < $minval ) {
     579                $minval = $angles[$i][0];
     580                $min = $i;
     581            }
     582        }
     583        $j = $min;
     584        $cnt = 0;
     585        while( $angles[$j][1] <= 90 ) {
     586            $j++;
     587            if( $j>=$n) {
     588                $j=0;
     589            }
     590            if( $cnt > $n ) {
     591                JpGraphError::RaiseL(14005);
     592//("Pie3D Internal error (#1). Trying to wrap twice when looking for start index");
     593            }
     594            ++$cnt;
     595        }
     596        $start = $j;
     597
     598        //
     599        // Step 3. Print slices in z-order
     600        //
     601        $cnt = 0;
     602       
     603        // First stroke all the slices between 90 and 270 (left half circle)
     604        // counterclockwise
     605           
     606        while( $angles[$j][0] < 270  && $aaoption !== 2 ) {
     607
     608            list($x,$y) = $adjexplode[$j];
     609
     610            $this->Pie3DSlice($img,$x,$y,$d,$h,$angles[$j][0],$angles[$j][1],
     611                              $z,$adjcolors[$j],$shadow);
     612       
     613            $last = array($x,$y,$j);
     614
     615            $j++;
     616            if( $j >= $n ) $j=0;
     617            if( $cnt > $n ) {
     618                JpGraphError::RaiseL(14006);
     619//("Pie3D Internal Error: Z-Sorting algorithm for 3D Pies is not working properly (2). Trying to wrap twice while stroking.");
     620            }
     621            ++$cnt;
     622        }
     623     
     624        $slice_left = $n-$cnt;
     625        $j=$start-1;
     626        if($j<0) $j=$n-1;
     627        $cnt = 0;
     628       
     629        // The stroke all slices from 90 to -90 (right half circle)
     630        // clockwise
     631        while( $cnt < $slice_left  && $aaoption !== 2 ) {
     632
     633            list($x,$y) = $adjexplode[$j];
     634
     635            $this->Pie3DSlice($img,$x,$y,$d,$h,$angles[$j][0],$angles[$j][1],
     636                              $z,$adjcolors[$j],$shadow);
     637            $j--;
     638            if( $cnt > $n ) {
     639                JpGraphError::RaiseL(14006);
     640//("Pie3D Internal Error: Z-Sorting algorithm for 3D Pies is not working properly (2). Trying to wrap twice while stroking.");
     641            }
     642            if($j<0) $j=$n-1;
     643            $cnt++;
     644        }
     645       
     646        // Now do a special thing. Stroke the last slice on the left
     647        // halfcircle one more time.  This is needed in the case where
     648        // the slice close to 270 have been exploded. In that case the
     649        // part of the slice close to the center of the pie might be
     650        // slightly nagged.
     651        if( $aaoption !== 2 )
     652            $this->Pie3DSlice($img,$last[0],$last[1],$d,$h,$angles[$last[2]][0],
     653                              $angles[$last[2]][1],$z,$adjcolors[$last[2]],$shadow);
     654
     655
     656        if( $aaoption !== 1 ) {
     657            // Now print possible labels and add csim
     658            $this->value->ApplyFont($img);
     659            $margin = $img->GetFontHeight()/2 + $this->value->margin ;
     660            for($i=0; $i < count($data); ++$i ) {
     661                $la = $labeldata[$i][0];
     662                $x = $labeldata[$i][1] + cos($la*M_PI/180)*($d+$margin)*$this->ilabelposadj;
     663                $y = $labeldata[$i][2] - sin($la*M_PI/180)*($h+$margin)*$this->ilabelposadj;
     664                if( $this->ilabelposadj >= 1.0 ) {
     665                    if( $la > 180 && $la < 360 ) $y += $z;
     666                }
     667                if( $this->labeltype == 0 ) {
     668                    if( $sum > 0 )
     669                        $l = 100*$data[$i]/$sum;
     670                    else
     671                        $l = 0;
     672                }
     673                elseif( $this->labeltype == 1 ) {
     674                    $l = $data[$i];
     675                }
     676                else {
     677                    $l = $this->adjusted_data[$i];
     678                }
     679                if( isset($this->labels[$i]) && is_string($this->labels[$i]) )
     680                    $l=sprintf($this->labels[$i],$l);
     681
     682                $this->StrokeLabels($l,$img,$labeldata[$i][0]*M_PI/180,$x,$y,$z);
     683           
     684                $this->Add3DSliceToCSIM($i,$labeldata[$i][1],$labeldata[$i][2],$h*2,$d*2,$z,
     685                                      $originalangles[$i][0],$originalangles[$i][1]);
     686            }   
     687        }
     688
     689        //
     690        // Finally add potential lines in pie
     691        //
     692
     693        if( $edgecolor=="" || $aaoption !== 0 ) return;
     694
     695        $accsum = 0;
     696        $a = $startangle;
     697        $a = $this->NormAngle($a);
     698
     699        $a *= M_PI/180.0;
     700
     701        $idx=0;
     702        $img->PushColor($edgecolor);
     703        $img->SetLineWeight($edgeweight);
     704       
     705        $fulledge = true;
     706        for($i=0; $i < count($data) && $fulledge; ++$i ) {
     707            if( empty($this->explode_radius[$i]) )
     708                $this->explode_radius[$i]=0;
     709            if( $this->explode_radius[$i] > 0 ) {
     710                $fulledge = false;
     711            }
     712        }
     713           
     714
     715        for($i=0; $i < count($data); ++$i, ++$idx ) {
     716
     717            $da = $data[$i]/$sum * 2*M_PI;
     718            $this->StrokeFullSliceFrame($img,$xc,$yc,$a,$a+$da,$d,$h,$z,$edgecolor,
     719                                        $this->explode_radius[$i],$fulledge);
     720            $a += $da;
     721        }
     722        $img->PopColor();
    716723    }
    717724
    718725    function StrokeFullSliceFrame($img,$xc,$yc,$sa,$ea,$w,$h,$z,$edgecolor,$exploderadius,$fulledge) {
    719         $step = 0.02;
    720 
    721         if( $exploderadius > 0 ) {
    722             $la = ($sa+$ea)/2;
    723             $xc += $exploderadius*cos($la);
    724             $yc -= $exploderadius*sin($la) * ($h/$w) ;
    725              
    726         }
    727 
    728         $p = array($xc,$yc,$xc+$w*cos($sa),$yc-$h*sin($sa));
    729 
    730         for($a=$sa; $a < $ea; $a += $step ) {
    731             $p[] = $xc + $w*cos($a);
    732             $p[] = $yc - $h*sin($a);
    733         }
    734 
    735         $p[] = $xc+$w*cos($ea);
    736         $p[] = $yc-$h*sin($ea);
    737         $p[] = $xc;
    738         $p[] = $yc;
    739 
    740         $img->SetColor($edgecolor);
    741         $img->Polygon($p);
    742 
    743         // Unfortunately we can't really draw the full edge around the whole of
    744         // of the slice if any of the slices are exploded. The reason is that
    745         // this algorithm is to simply. There are cases where the edges will
    746         // "overwrite" other slices when they have been exploded.
    747         // Doing the full, proper 3D hidden lines stiff is actually quite
    748         // tricky. So for exploded pies we only draw the top edge. Not perfect
    749         // but the "real" solution is much more complicated.
    750         if( $fulledge && !( $sa > 0 && $sa < M_PI && $ea < M_PI) ) {
    751 
    752             if($sa < M_PI && $ea > M_PI) {
    753                 $sa = M_PI;
    754             }
    755 
    756             if($sa < 2*M_PI && (($ea >= 2*M_PI) || ($ea > 0 && $ea < $sa ) ) ) {
    757                 $ea = 2*M_PI;
    758             }
    759 
    760             if( $sa >= M_PI && $ea <= 2*M_PI ) {
    761                 $p = array($xc + $w*cos($sa),$yc - $h*sin($sa),
    762                 $xc + $w*cos($sa),$z + $yc - $h*sin($sa));
    763 
    764                 for($a=$sa+$step; $a < $ea; $a += $step ) {
    765                     $p[] = $xc + $w*cos($a);
    766                     $p[] = $z + $yc - $h*sin($a);
    767                 }
    768                 $p[] = $xc + $w*cos($ea);
    769                 $p[] = $z + $yc - $h*sin($ea);
    770                 $p[] = $xc + $w*cos($ea);
    771                 $p[] = $yc - $h*sin($ea);
    772                 $img->SetColor($edgecolor);
    773                 $img->Polygon($p);
    774             }
    775         }
     726        $step = 0.02;
     727
     728        if( $exploderadius > 0 ) {
     729            $la = ($sa+$ea)/2;
     730            $xc += $exploderadius*cos($la);
     731            $yc -= $exploderadius*sin($la) * ($h/$w) ;
     732           
     733        }
     734
     735        $p = array($xc,$yc,$xc+$w*cos($sa),$yc-$h*sin($sa));
     736
     737        for($a=$sa; $a < $ea; $a += $step ) {
     738            $p[] = $xc + $w*cos($a);
     739            $p[] = $yc - $h*sin($a);
     740        }
     741
     742        $p[] = $xc+$w*cos($ea);
     743        $p[] = $yc-$h*sin($ea);
     744        $p[] = $xc;
     745        $p[] = $yc;
     746
     747        $img->SetColor($edgecolor);
     748        $img->Polygon($p);
     749
     750        // Unfortunately we can't really draw the full edge around the whole of
     751        // of the slice if any of the slices are exploded. The reason is that
     752        // this algorithm is to simply. There are cases where the edges will
     753        // "overwrite" other slices when they have been exploded.
     754        // Doing the full, proper 3D hidden lines stiff is actually quite
     755        // tricky. So for exploded pies we only draw the top edge. Not perfect
     756        // but the "real" solution is much more complicated.
     757        if( $fulledge && !( $sa > 0 && $sa < M_PI && $ea < M_PI) ) {
     758
     759            if($sa < M_PI && $ea > M_PI)
     760                $sa = M_PI;
     761 
     762            if($sa < 2*M_PI && (($ea >= 2*M_PI) || ($ea > 0 && $ea < $sa ) ) )
     763                $ea = 2*M_PI;
     764
     765            if( $sa >= M_PI && $ea <= 2*M_PI ) {
     766                $p = array($xc + $w*cos($sa),$yc - $h*sin($sa),
     767                           $xc + $w*cos($sa),$z + $yc - $h*sin($sa));
     768               
     769                for($a=$sa+$step; $a < $ea; $a += $step ) {
     770                    $p[] = $xc + $w*cos($a);
     771                    $p[] = $z + $yc - $h*sin($a);
     772                }
     773                $p[] = $xc + $w*cos($ea);
     774                $p[] = $z + $yc - $h*sin($ea);
     775                $p[] = $xc + $w*cos($ea);
     776                $p[] = $yc - $h*sin($ea);
     777                $img->SetColor($edgecolor);
     778                $img->Polygon($p);         
     779            }
     780        }
    776781    }
    777782
    778783    function Stroke($img,$aaoption=0) {
    779         $n = count($this->data);
    780 
    781         // If user hasn't set the colors use the theme array
    782         if( $this->setslicecolors==null ) {
    783             $colors = array_keys($img->rgb->rgb_table);
    784             sort($colors);
    785             $idx_a=$this->themearr[$this->theme];
    786             $ca = array();
    787             $m = count($idx_a);
    788             for($i=0; $i < $m; ++$i) {
    789                 $ca[$i] = $colors[$idx_a[$i]];
    790             }
    791             $ca = array_reverse(array_slice($ca,0,$n));
    792         }
    793         else {
    794             $ca = $this->setslicecolors;
    795         }
    796 
    797 
    798         if( $this->posx <= 1 && $this->posx > 0 ) {
    799             $xc = round($this->posx*$img->width);
    800         }
    801         else {
    802             $xc = $this->posx ;
    803         }
    804 
    805         if( $this->posy <= 1 && $this->posy > 0 ) {
    806             $yc = round($this->posy*$img->height);
    807         }
    808         else {
    809             $yc = $this->posy ;
    810         }
    811 
    812         if( $this->radius <= 1 ) {
    813             $width = floor($this->radius*min($img->width,$img->height));
    814             // Make sure that the pie doesn't overflow the image border
    815             // The 0.9 factor is simply an extra margin to leave some space
    816             // between the pie an the border of the image.
    817             $width = min($width,min($xc*0.9,($yc*90/$this->angle-$width/4)*0.9));
    818         }
    819         else {
    820             $width = $this->radius * ($aaoption === 1 ? 2 : 1 ) ;
    821         }
    822 
    823         // Add a sanity check for width
    824         if( $width < 1 ) {
    825             JpGraphError::RaiseL(14007);//("Width for 3D Pie is 0. Specify a size > 0");
    826         }
    827 
    828         // Establish a thickness. By default the thickness is a fifth of the
    829         // pie slice width (=pie radius) but since the perspective depends
    830         // on the inclination angle we use some heuristics to make the edge
    831         // slightly thicker the less the angle.
    832 
    833         // Has user specified an absolute thickness? In that case use
    834         // that instead
    835 
    836         if( $this->iThickness ) {
    837             $thick = $this->iThickness;
    838             $thick *= ($aaoption === 1 ? 2 : 1 );
    839         }
    840         else {
    841             $thick = $width/12;
    842         }
    843         $a = $this->angle;
    844        
    845         if( $a <= 30 ) $thick *= 1.6;
    846         elseif( $a <= 40 ) $thick *= 1.4;
    847         elseif( $a <= 50 ) $thick *= 1.2;
    848         elseif( $a <= 60 ) $thick *= 1.0;
    849         elseif( $a <= 70 ) $thick *= 0.8;
    850         elseif( $a <= 80 ) $thick *= 0.7;
    851         else $thick *= 0.6;
    852 
    853         $thick = floor($thick);
    854 
    855         if( $this->explode_all ) {
    856             for($i=0; $i < $n; ++$i)
    857                 $this->explode_radius[$i]=$this->explode_r;
    858         }
    859 
    860         $this->Pie3D($aaoption,$img,$this->data, $ca, $xc, $yc, $width, $this->angle,
    861         $thick, 0.65, $this->startangle, $this->edgecolor, $this->edgeweight);
    862 
    863         // Adjust title position
    864         if( $aaoption != 1 ) {
    865             $this->title->SetPos($xc,$yc-$this->title->GetFontHeight($img)-$width/2-$this->title->margin,         "center","bottom");
    866             $this->title->Stroke($img);
    867         }
    868     }
    869 
    870     //---------------
    871     // PRIVATE METHODS
     784        $n = count($this->data);
     785
     786        // If user hasn't set the colors use the theme array
     787        if( $this->setslicecolors==null ) {
     788            $colors = array_keys($img->rgb->rgb_table);
     789            sort($colors);     
     790            $idx_a=$this->themearr[$this->theme];       
     791            $ca = array();
     792            $m = count($idx_a);
     793            for($i=0; $i < $m; ++$i)
     794                $ca[$i] = $colors[$idx_a[$i]];
     795            $ca = array_reverse(array_slice($ca,0,$n));
     796        }
     797        else {
     798            $ca = $this->setslicecolors;
     799        }
     800       
     801
     802        if( $this->posx <= 1 && $this->posx > 0 )
     803            $xc = round($this->posx*$img->width);
     804        else
     805            $xc = $this->posx ;
     806       
     807        if( $this->posy <= 1 && $this->posy > 0 )
     808            $yc = round($this->posy*$img->height);
     809        else
     810            $yc = $this->posy ;
     811                       
     812        if( $this->radius <= 1 ) {
     813            $width = floor($this->radius*min($img->width,$img->height));
     814            // Make sure that the pie doesn't overflow the image border
     815            // The 0.9 factor is simply an extra margin to leave some space
     816            // between the pie an the border of the image.
     817            $width = min($width,min($xc*0.9,($yc*90/$this->angle-$width/4)*0.9));
     818        }
     819        else {
     820            $width = $this->radius * ($aaoption === 1 ? 2 : 1 ) ;
     821        }
     822
     823        // Add a sanity check for width
     824        if( $width < 1 ) {
     825            JpGraphError::RaiseL(14007);//("Width for 3D Pie is 0. Specify a size > 0");
     826        }
     827
     828        // Establish a thickness. By default the thickness is a fifth of the
     829        // pie slice width (=pie radius) but since the perspective depends
     830        // on the inclination angle we use some heuristics to make the edge
     831        // slightly thicker the less the angle.
     832       
     833        // Has user specified an absolute thickness? In that case use
     834        // that instead
     835
     836        if( $this->iThickness ) {
     837          $thick = $this->iThickness;
     838          $thick *= ($aaoption === 1 ? 2 : 1 );
     839        }
     840        else
     841          $thick = $width/12;
     842        $a = $this->angle;
     843        if( $a <= 30 ) $thick *= 1.6;
     844        elseif( $a <= 40 ) $thick *= 1.4;
     845        elseif( $a <= 50 ) $thick *= 1.2;
     846        elseif( $a <= 60 ) $thick *= 1.0;
     847        elseif( $a <= 70 ) $thick *= 0.8;
     848        elseif( $a <= 80 ) $thick *= 0.7;
     849        else $thick *= 0.6;
     850
     851        $thick = floor($thick);
     852
     853        if( $this->explode_all )
     854            for($i=0; $i < $n; ++$i)
     855                $this->explode_radius[$i]=$this->explode_r;
     856
     857        $this->Pie3D($aaoption,$img,$this->data, $ca, $xc, $yc, $width, $this->angle,
     858                     $thick, 0.65, $this->startangle, $this->edgecolor, $this->edgeweight);
     859
     860        // Adjust title position
     861        if( $aaoption != 1 ) {
     862            $this->title->SetPos($xc,$yc-$this->title->GetFontHeight($img)-$width/2-$this->title->margin,                             "center","bottom");
     863            $this->title->Stroke($img);
     864        }
     865    }
     866
     867//---------------
     868// PRIVATE METHODS     
    872869
    873870    // Position the labels of each slice
    874871    function StrokeLabels($label,$img,$a,$xp,$yp,$z) {
    875         $this->value->halign="left";
    876         $this->value->valign="top";
    877 
    878         // Position the axis title.
    879         // dx, dy is the offset from the top left corner of the bounding box that sorrounds the text
    880         // that intersects with the extension of the corresponding axis. The code looks a little
    881         // bit messy but this is really the only way of having a reasonable position of the
    882         // axis titles.
    883         $this->value->ApplyFont($img);
    884         $h=$img->GetTextHeight($label);
    885         // For numeric values the format of the display value
    886         // must be taken into account
    887         if( is_numeric($label) ) {
    888             if( $label >= 0 ) {
    889                 $w=$img->GetTextWidth(sprintf($this->value->format,$label));
    890             }
    891             else {
    892                 $w=$img->GetTextWidth(sprintf($this->value->negformat,$label));
    893             }
    894         }
    895         else {
    896             $w=$img->GetTextWidth($label);
    897         }
    898        
    899         while( $a > 2*M_PI ) {
    900             $a -= 2*M_PI;
    901         }
    902        
    903         if( $a>=7*M_PI/4 || $a <= M_PI/4 ) $dx=0;
    904         if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dx=($a-M_PI/4)*2/M_PI;
    905         if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dx=1;
    906         if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dx=(1-($a-M_PI*5/4)*2/M_PI);
    907 
    908         if( $a>=7*M_PI/4 ) $dy=(($a-M_PI)-3*M_PI/4)*2/M_PI;
    909         if( $a<=M_PI/4 ) $dy=(1-$a*2/M_PI);
    910         if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dy=1;
    911         if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dy=(1-($a-3*M_PI/4)*2/M_PI);
    912         if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dy=0;
    913 
    914         $x = round($xp-$dx*$w);
    915         $y = round($yp-$dy*$h);
    916 
    917         // Mark anchor point for debugging
    918         /*
    919         $img->SetColor('red');
    920         $img->Line($xp-10,$yp,$xp+10,$yp);
    921         $img->Line($xp,$yp-10,$xp,$yp+10);
    922         */
    923 
    924         $oldmargin = $this->value->margin;
    925         $this->value->margin=0;
    926         $this->value->Stroke($img,$label,$x,$y);
    927         $this->value->margin=$oldmargin;
    928 
    929     }
     872        $this->value->halign="left";
     873        $this->value->valign="top";
     874
     875        // Position the axis title.
     876        // dx, dy is the offset from the top left corner of the bounding box that sorrounds the text
     877        // that intersects with the extension of the corresponding axis. The code looks a little
     878        // bit messy but this is really the only way of having a reasonable position of the
     879        // axis titles.
     880        $this->value->ApplyFont($img);
     881        $h=$img->GetTextHeight($label);
     882        // For numeric values the format of the display value
     883        // must be taken into account
     884        if( is_numeric($label) ) {
     885            if( $label >= 0 )
     886                $w=$img->GetTextWidth(sprintf($this->value->format,$label));
     887            else
     888                $w=$img->GetTextWidth(sprintf($this->value->negformat,$label));
     889        }
     890        else
     891            $w=$img->GetTextWidth($label);
     892        while( $a > 2*M_PI ) $a -= 2*M_PI;
     893        if( $a>=7*M_PI/4 || $a <= M_PI/4 ) $dx=0;
     894        if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dx=($a-M_PI/4)*2/M_PI;
     895        if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dx=1;
     896        if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dx=(1-($a-M_PI*5/4)*2/M_PI);
     897               
     898        if( $a>=7*M_PI/4 ) $dy=(($a-M_PI)-3*M_PI/4)*2/M_PI;
     899        if( $a<=M_PI/4 ) $dy=(1-$a*2/M_PI);
     900        if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dy=1;
     901        if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dy=(1-($a-3*M_PI/4)*2/M_PI);
     902        if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dy=0;
     903       
     904        $x = round($xp-$dx*$w);
     905        $y = round($yp-$dy*$h);
     906
     907       
     908        // Mark anchor point for debugging
     909        /*
     910        $img->SetColor('red');
     911        $img->Line($xp-10,$yp,$xp+10,$yp);
     912        $img->Line($xp,$yp-10,$xp,$yp+10);
     913        */
     914        $oldmargin = $this->value->margin;
     915        $this->value->margin=0;
     916        $this->value->Stroke($img,$label,$x,$y);
     917        $this->value->margin=$oldmargin;
     918
     919    }   
    930920} // Class
    931921
Note: See TracChangeset for help on using the changeset viewer.