https://t.me/RX1948
Server : Apache
System : Linux s1230 5.15.0-139-generic #149~20.04.1 SMP Tue Jul 14 11:21:49 UTC 2026 x86_64
User : p141464 ( 418825)
PHP Version : 7.4.33.12
Disable Function : NONE
Directory :  /html/KMU-CSR-PLANER/wp-content/plugins/matomo/app/vendor/szymach/c-pchart/src/Chart/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /html/KMU-CSR-PLANER/wp-content/plugins/matomo/app/vendor/szymach/c-pchart/src/Chart/Pie.php
<?php

namespace CpChart\Chart;

use CpChart\Data;
use CpChart\Image;
/**
 *  Pie - class to draw pie charts
 *
 *  Version     : 2.1.4
 *  Made by     : Jean-Damien POGOLOTTI
 *  Last Update : 19/01/2014
 *
 *  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.
 */
class Pie
{
    /**
     * @var Image
     */
    public $pChartObject;
    /**
     * @var Data
     */
    public $pDataObject;
    /**
     * @var array
     */
    public $LabelPos = [];
    /**
     * @param Image $pChartObject
     * @param Data $pDataObject
     */
    public function __construct(Image $pChartObject, Data $pDataObject)
    {
        $this->pChartObject = $pChartObject;
        $this->pDataObject = $pDataObject;
    }
    /**
     * Draw a pie chart
     * @param int $X
     * @param int $Y
     * @param array $Format
     * @return int
     */
    public function draw2DPie($X, $Y, array $Format = [])
    {
        $Radius = isset($Format["Radius"]) ? $Format["Radius"] : 60;
        $Precision = isset($Format["Precision"]) ? $Format["Precision"] : 0;
        $DataGapAngle = isset($Format["DataGapAngle"]) ? $Format["DataGapAngle"] : 0;
        $DataGapRadius = isset($Format["DataGapRadius"]) ? $Format["DataGapRadius"] : 0;
        $SecondPass = isset($Format["SecondPass"]) ? $Format["SecondPass"] : \true;
        $Border = isset($Format["Border"]) ? $Format["Border"] : \false;
        $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : 255;
        $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : 255;
        $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : 255;
        $Shadow = isset($Format["Shadow"]) ? $Format["Shadow"] : \false;
        $DrawLabels = isset($Format["DrawLabels"]) ? $Format["DrawLabels"] : \false;
        $LabelStacked = isset($Format["LabelStacked"]) ? $Format["LabelStacked"] : \false;
        $LabelColor = isset($Format["LabelColor"]) ? $Format["LabelColor"] : PIE_LABEL_COLOR_MANUAL;
        $LabelR = isset($Format["LabelR"]) ? $Format["LabelR"] : 0;
        $LabelG = isset($Format["LabelG"]) ? $Format["LabelG"] : 0;
        $LabelB = isset($Format["LabelB"]) ? $Format["LabelB"] : 0;
        $LabelAlpha = isset($Format["LabelAlpha"]) ? $Format["LabelAlpha"] : 100;
        $WriteValues = isset($Format["WriteValues"]) ? $Format["WriteValues"] : null;
        $ValuePosition = isset($Format["ValuePosition"]) ? $Format["ValuePosition"] : PIE_VALUE_OUTSIDE;
        $ValuePadding = isset($Format["ValuePadding"]) ? $Format["ValuePadding"] : 15;
        $ValueSuffix = isset($Format["ValueSuffix"]) ? $Format["ValueSuffix"] : "";
        $ValueR = isset($Format["ValueR"]) ? $Format["ValueR"] : 255;
        $ValueG = isset($Format["ValueG"]) ? $Format["ValueG"] : 255;
        $ValueB = isset($Format["ValueB"]) ? $Format["ValueB"] : 255;
        $ValueAlpha = isset($Format["ValueAlpha"]) ? $Format["ValueAlpha"] : 100;
        $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : \false;
        $Data = $this->pDataObject->getData();
        $Palette = $this->pDataObject->getPalette();
        /* Do we have an abscissa serie defined? */
        if ($Data["Abscissa"] == "") {
            return PIE_NO_ABSCISSA;
        }
        /* Try to find the data serie */
        $DataSerie = null;
        foreach (array_keys($Data["Series"]) as $SerieName) {
            if ($SerieName != $Data["Abscissa"]) {
                $DataSerie = $SerieName;
            }
        }
        /* Do we have data to compute? */
        if (!$DataSerie) {
            return PIE_NO_DATASERIE;
        }
        /* Remove unused data */
        list($Data, $Palette) = $this->clean0Values($Data, $Palette, $DataSerie, $Data["Abscissa"]);
        /* Compute the pie sum */
        $SerieSum = $this->pDataObject->getSum($DataSerie);
        /* Do we have data to draw? */
        if ($SerieSum == 0) {
            return PIE_SUMISNULL;
        }
        /* Dump the real number of data to draw */
        $Values = [];
        foreach ($Data["Series"][$DataSerie]["Data"] as $Key => $Value) {
            if ($Value != 0) {
                $Values[] = $Value;
            }
        }
        /* Compute the wasted angular space between series */
        if (count($Values) == 1) {
            $WastedAngular = 0;
        } else {
            $WastedAngular = count($Values) * $DataGapAngle;
        }
        /* Compute the scale */
        $ScaleFactor = (360 - $WastedAngular) / $SerieSum;
        $RestoreShadow = $this->pChartObject->Shadow;
        if ($this->pChartObject->Shadow) {
            $this->pChartObject->Shadow = \false;
            $ShadowFormat = $Format;
            $ShadowFormat["Shadow"] = \true;
            $this->draw2DPie($X + $this->pChartObject->ShadowX, $Y + $this->pChartObject->ShadowY, $ShadowFormat);
        }
        /* Draw the polygon pie elements */
        $Step = 360 / (2 * PI * $Radius);
        $Offset = 0;
        $ID = 0;
        foreach ($Values as $Key => $Value) {
            if ($Shadow) {
                $Settings = ["R" => $this->pChartObject->ShadowR, "G" => $this->pChartObject->ShadowG, "B" => $this->pChartObject->ShadowB, "Alpha" => $this->pChartObject->Shadowa];
            } else {
                if (!isset($Palette[$ID]["R"])) {
                    $Color = $this->pChartObject->getRandomColor();
                    $Palette[$ID] = $Color;
                    $this->pDataObject->savePalette($ID, $Color);
                }
                $Settings = ["R" => $Palette[$ID]["R"], "G" => $Palette[$ID]["G"], "B" => $Palette[$ID]["B"], "Alpha" => $Palette[$ID]["Alpha"]];
            }
            if (!$SecondPass && !$Shadow) {
                if (!$Border) {
                    $Settings["Surrounding"] = 10;
                } else {
                    $Settings["BorderR"] = $BorderR;
                    $Settings["BorderG"] = $BorderG;
                    $Settings["BorderB"] = $BorderB;
                }
            }
            $EndAngle = $Offset + $Value * $ScaleFactor;
            if ($EndAngle > 360) {
                $EndAngle = 360;
            }
            $Angle = ($EndAngle - $Offset) / 2 + $Offset;
            if ($DataGapAngle == 0) {
                $X0 = $X;
                $Y0 = $Y;
            } else {
                $X0 = cos(($Angle - 90) * PI / 180) * $DataGapRadius + $X;
                $Y0 = sin(($Angle - 90) * PI / 180) * $DataGapRadius + $Y;
            }
            $Plots = [$X0, $Y0];
            for ($i = $Offset; $i <= $EndAngle; $i = $i + $Step) {
                $Xc = cos(($i - 90) * PI / 180) * $Radius + $X;
                $Yc = sin(($i - 90) * PI / 180) * $Radius + $Y;
                if ($SecondPass && $i < 90) {
                    $Yc++;
                }
                if ($SecondPass && ($i > 180 && $i < 270)) {
                    $Xc++;
                }
                if ($SecondPass && $i >= 270) {
                    $Xc++;
                    $Yc++;
                }
                $Plots[] = $Xc;
                $Plots[] = $Yc;
            }
            $this->pChartObject->drawPolygon($Plots, $Settings);
            if ($RecordImageMap && !$Shadow) {
                $this->pChartObject->addToImageMap("POLY", $this->arraySerialize($Plots), $this->pChartObject->toHTMLColor($Palette[$ID]["R"], $Palette[$ID]["G"], $Palette[$ID]["B"]), $Data["Series"][$Data["Abscissa"]]["Data"][$Key], $Value);
            }
            if ($DrawLabels && !$Shadow && !$SecondPass) {
                if ($LabelColor == PIE_LABEL_COLOR_AUTO) {
                    $Settings = ["FillR" => $Palette[$ID]["R"], "FillG" => $Palette[$ID]["G"], "FillB" => $Palette[$ID]["B"], "Alpha" => $Palette[$ID]["Alpha"]];
                } else {
                    $Settings = ["FillR" => $LabelR, "FillG" => $LabelG, "FillB" => $LabelB, "Alpha" => $LabelAlpha];
                }
                $Angle = ($EndAngle - $Offset) / 2 + $Offset;
                $Xc = cos(($Angle - 90) * PI / 180) * $Radius + $X;
                $Yc = sin(($Angle - 90) * PI / 180) * $Radius + $Y;
                $Label = $Data["Series"][$Data["Abscissa"]]["Data"][$Key];
                if ($LabelStacked) {
                    $this->writePieLabel($Xc, $Yc, $Label, $Angle, $Settings, \true, $X, $Y, $Radius);
                } else {
                    $this->writePieLabel($Xc, $Yc, $Label, $Angle, $Settings, \false);
                }
            }
            $Offset = $i + $DataGapAngle;
            $ID++;
        }
        /* Second pass to smooth the angles */
        if ($SecondPass) {
            $Step = 360 / (2 * PI * $Radius);
            $Offset = 0;
            $ID = 0;
            foreach ($Values as $Key => $Value) {
                $FirstPoint = \true;
                if ($Shadow) {
                    $Settings = ["R" => $this->pChartObject->ShadowR, "G" => $this->pChartObject->ShadowG, "B" => $this->pChartObject->ShadowB, "Alpha" => $this->pChartObject->Shadowa];
                } else {
                    if ($Border) {
                        $Settings = ["R" => $BorderR, "G" => $BorderG, "B" => $BorderB];
                    } else {
                        $Settings = ["R" => $Palette[$ID]["R"], "G" => $Palette[$ID]["G"], "B" => $Palette[$ID]["B"], "Alpha" => $Palette[$ID]["Alpha"]];
                    }
                }
                $EndAngle = $Offset + $Value * $ScaleFactor;
                if ($EndAngle > 360) {
                    $EndAngle = 360;
                }
                if ($DataGapAngle == 0) {
                    $X0 = $X;
                    $Y0 = $Y;
                } else {
                    $Angle = ($EndAngle - $Offset) / 2 + $Offset;
                    $X0 = cos(($Angle - 90) * PI / 180) * $DataGapRadius + $X;
                    $Y0 = sin(($Angle - 90) * PI / 180) * $DataGapRadius + $Y;
                }
                $Plots[] = $X0;
                $Plots[] = $Y0;
                for ($i = $Offset; $i <= $EndAngle; $i = $i + $Step) {
                    $Xc = cos(($i - 90) * PI / 180) * $Radius + $X;
                    $Yc = sin(($i - 90) * PI / 180) * $Radius + $Y;
                    if ($FirstPoint) {
                        $this->pChartObject->drawLine($Xc, $Yc, $X0, $Y0, $Settings);
                        $FirstPoint = \false;
                    }
                    $this->pChartObject->drawAntialiasPixel($Xc, $Yc, $Settings);
                }
                $this->pChartObject->drawLine($Xc, $Yc, $X0, $Y0, $Settings);
                if ($DrawLabels && !$Shadow) {
                    if ($LabelColor == PIE_LABEL_COLOR_AUTO) {
                        $Settings = ["FillR" => $Palette[$ID]["R"], "FillG" => $Palette[$ID]["G"], "FillB" => $Palette[$ID]["B"], "Alpha" => $Palette[$ID]["Alpha"]];
                    } else {
                        $Settings = ["FillR" => $LabelR, "FillG" => $LabelG, "FillB" => $LabelB, "Alpha" => $LabelAlpha];
                    }
                    $Angle = ($EndAngle - $Offset) / 2 + $Offset;
                    $Xc = cos(($Angle - 90) * PI / 180) * $Radius + $X;
                    $Yc = sin(($Angle - 90) * PI / 180) * $Radius + $Y;
                    $Label = $Data["Series"][$Data["Abscissa"]]["Data"][$Key];
                    if ($LabelStacked) {
                        $this->writePieLabel($Xc, $Yc, $Label, $Angle, $Settings, \true, $X, $Y, $Radius);
                    } else {
                        $this->writePieLabel($Xc, $Yc, $Label, $Angle, $Settings, \false);
                    }
                }
                $Offset = $i + $DataGapAngle;
                $ID++;
            }
        }
        if ($WriteValues != null && !$Shadow) {
            $Step = 360 / (2 * PI * $Radius);
            $Offset = 0;
            $ID = count($Values) - 1;
            $Settings = ["Align" => TEXT_ALIGN_MIDDLEMIDDLE, "R" => $ValueR, "G" => $ValueG, "B" => $ValueB, "Alpha" => $ValueAlpha];
            foreach ($Values as $Key => $Value) {
                $EndAngle = $Value * $ScaleFactor + $Offset;
                if ((int) $EndAngle > 360) {
                    $EndAngle = 0;
                }
                $Angle = ($EndAngle - $Offset) / 2 + $Offset;
                if ($ValuePosition == PIE_VALUE_OUTSIDE) {
                    $Xc = cos(($Angle - 90) * PI / 180) * ($Radius + $ValuePadding) + $X;
                    $Yc = sin(($Angle - 90) * PI / 180) * ($Radius + $ValuePadding) + $Y;
                } else {
                    $Xc = cos(($Angle - 90) * PI / 180) * $Radius / 2 + $X;
                    $Yc = sin(($Angle - 90) * PI / 180) * $Radius / 2 + $Y;
                }
                if ($WriteValues == PIE_VALUE_PERCENTAGE) {
                    $Display = round(100 / $SerieSum * $Value, $Precision) . "%";
                } elseif ($WriteValues == PIE_VALUE_NATURAL) {
                    $Display = $Value . $ValueSuffix;
                }
                $this->pChartObject->drawText($Xc, $Yc, $Display, $Settings);
                $Offset = $EndAngle + $DataGapAngle;
                $ID--;
            }
        }
        if ($DrawLabels && $LabelStacked) {
            $this->writeShiftedLabels();
        }
        $this->pChartObject->Shadow = $RestoreShadow;
        return PIE_RENDERED;
    }
    /**
     * Draw a 3D pie chart
     * @param int $X
     * @param int $Y
     * @param array $Format
     * @return int
     */
    public function draw3DPie($X, $Y, array $Format = [])
    {
        /* Rendering layout */
        $Radius = isset($Format["Radius"]) ? $Format["Radius"] : 80;
        $Precision = isset($Format["Precision"]) ? $Format["Precision"] : 0;
        $SkewFactor = isset($Format["SkewFactor"]) ? $Format["SkewFactor"] : 0.5;
        $SliceHeight = isset($Format["SliceHeight"]) ? $Format["SliceHeight"] : 20;
        $DataGapAngle = isset($Format["DataGapAngle"]) ? $Format["DataGapAngle"] : 0;
        $DataGapRadius = isset($Format["DataGapRadius"]) ? $Format["DataGapRadius"] : 0;
        $SecondPass = isset($Format["SecondPass"]) ? $Format["SecondPass"] : \true;
        $Border = isset($Format["Border"]) ? $Format["Border"] : \false;
        $Shadow = isset($Format["Shadow"]) ? $Format["Shadow"] : \false;
        $DrawLabels = isset($Format["DrawLabels"]) ? $Format["DrawLabels"] : \false;
        $LabelStacked = isset($Format["LabelStacked"]) ? $Format["LabelStacked"] : \false;
        $LabelColor = isset($Format["LabelColor"]) ? $Format["LabelColor"] : PIE_LABEL_COLOR_MANUAL;
        $LabelR = isset($Format["LabelR"]) ? $Format["LabelR"] : 0;
        $LabelG = isset($Format["LabelG"]) ? $Format["LabelG"] : 0;
        $LabelB = isset($Format["LabelB"]) ? $Format["LabelB"] : 0;
        $LabelAlpha = isset($Format["LabelAlpha"]) ? $Format["LabelAlpha"] : 100;
        $WriteValues = isset($Format["WriteValues"]) ? $Format["WriteValues"] : null;
        //PIE_VALUE_PERCENTAGE
        $ValuePosition = isset($Format["ValuePosition"]) ? $Format["ValuePosition"] : PIE_VALUE_INSIDE;
        $ValuePadding = isset($Format["ValuePadding"]) ? $Format["ValuePadding"] : 15;
        $ValueSuffix = isset($Format["ValueSuffix"]) ? $Format["ValueSuffix"] : "";
        $ValueR = isset($Format["ValueR"]) ? $Format["ValueR"] : 255;
        $ValueG = isset($Format["ValueG"]) ? $Format["ValueG"] : 255;
        $ValueB = isset($Format["ValueB"]) ? $Format["ValueB"] : 255;
        $ValueAlpha = isset($Format["ValueAlpha"]) ? $Format["ValueAlpha"] : 100;
        $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : \false;
        /* Error correction for overlaying rounded corners */
        if ($SkewFactor < 0.5) {
            $SkewFactor = 0.5;
        }
        /* Data Processing */
        $Data = $this->pDataObject->getData();
        $Palette = $this->pDataObject->getPalette();
        /* Do we have an abscissa serie defined? */
        if ($Data["Abscissa"] == "") {
            return PIE_NO_ABSCISSA;
        }
        /* Try to find the data serie */
        $DataSerie = null;
        foreach ($Data["Series"] as $SerieName => $SerieData) {
            if ($SerieName != $Data["Abscissa"]) {
                $DataSerie = $SerieName;
            }
        }
        /* Do we have data to compute? */
        if (!$DataSerie) {
            return PIE_NO_DATASERIE;
        }
        /* Remove unused data */
        list($Data, $Palette) = $this->clean0Values($Data, $Palette, $DataSerie, $Data["Abscissa"]);
        /* Compute the pie sum */
        $SerieSum = $this->pDataObject->getSum($DataSerie);
        /* Do we have data to draw? */
        if ($SerieSum == 0) {
            return PIE_SUMISNULL;
        }
        /* Dump the real number of data to draw */
        $Values = [];
        foreach ($Data["Series"][$DataSerie]["Data"] as $Key => $Value) {
            if ($Value != 0) {
                $Values[] = $Value;
            }
        }
        /* Compute the wasted angular space between series */
        if (count($Values) == 1) {
            $WastedAngular = 0;
        } else {
            $WastedAngular = count($Values) * $DataGapAngle;
        }
        /* Compute the scale */
        $ScaleFactor = (360 - $WastedAngular) / $SerieSum;
        $RestoreShadow = $this->pChartObject->Shadow;
        if ($this->pChartObject->Shadow) {
            $this->pChartObject->Shadow = \false;
        }
        /* Draw the polygon pie elements */
        $Step = 360 / (2 * PI * $Radius);
        $Offset = 360;
        $ID = count($Values) - 1;
        $Values = array_reverse($Values);
        $Slice = 0;
        $Slices = [];
        $SliceColors = [];
        $Visible = [];
        $SliceAngle = [];
        foreach ($Values as $Key => $Value) {
            if (!isset($Palette[$ID]["R"])) {
                $Color = $this->pChartObject->getRandomColor();
                $Palette[$ID] = $Color;
                $this->pDataObject->savePalette($ID, $Color);
            }
            $Settings = ["R" => $Palette[$ID]["R"], "G" => $Palette[$ID]["G"], "B" => $Palette[$ID]["B"], "Alpha" => $Palette[$ID]["Alpha"]];
            $SliceColors[$Slice] = $Settings;
            $StartAngle = $Offset;
            $EndAngle = $Offset - $Value * $ScaleFactor;
            if ($EndAngle < 0) {
                $EndAngle = 0;
            }
            if ($StartAngle > 180) {
                $Visible[$Slice]["Start"] = \true;
            } else {
                $Visible[$Slice]["Start"] = \true;
            }
            if ($EndAngle < 180) {
                $Visible[$Slice]["End"] = \false;
            } else {
                $Visible[$Slice]["End"] = \true;
            }
            if ($DataGapAngle == 0) {
                $X0 = $X;
                $Y0 = $Y;
            } else {
                $Angle = ($EndAngle - $Offset) / 2 + $Offset;
                $X0 = cos(($Angle - 90) * PI / 180) * $DataGapRadius + $X;
                $Y0 = sin(($Angle - 90) * PI / 180) * $DataGapRadius * $SkewFactor + $Y;
            }
            $Slices[$Slice][] = $X0;
            $Slices[$Slice][] = $Y0;
            $SliceAngle[$Slice][] = 0;
            for ($i = $Offset; $i >= $EndAngle; $i = $i - $Step) {
                $Xc = cos(($i - 90) * PI / 180) * $Radius + $X;
                $Yc = sin(($i - 90) * PI / 180) * $Radius * $SkewFactor + $Y;
                if (($SecondPass || $RestoreShadow) && $i < 90) {
                    $Yc++;
                }
                if (($SecondPass || $RestoreShadow) && ($i > 90 && $i < 180)) {
                    $Xc++;
                }
                if (($SecondPass || $RestoreShadow) && ($i > 180 && $i < 270)) {
                    $Xc++;
                }
                if (($SecondPass || $RestoreShadow) && $i >= 270) {
                    $Xc++;
                    $Yc++;
                }
                $Slices[$Slice][] = $Xc;
                $Slices[$Slice][] = $Yc;
                $SliceAngle[$Slice][] = $i;
            }
            $Offset = $i - $DataGapAngle;
            $ID--;
            $Slice++;
        }
        /* Draw the bottom shadow if needed */
        if ($RestoreShadow && ($this->pChartObject->ShadowX != 0 || $this->pChartObject->ShadowY != 0)) {
            foreach ($Slices as $SliceID => $Plots) {
                $ShadowPie = [];
                for ($i = 0; $i < count($Plots); $i = $i + 2) {
                    $ShadowPie[] = $Plots[$i] + $this->pChartObject->ShadowX;
                    $ShadowPie[] = $Plots[$i + 1] + $this->pChartObject->ShadowY;
                }
                $Settings = ["R" => $this->pChartObject->ShadowR, "G" => $this->pChartObject->ShadowG, "B" => $this->pChartObject->ShadowB, "Alpha" => $this->pChartObject->Shadowa, "NoBorder" => \true];
                $this->pChartObject->drawPolygon($ShadowPie, $Settings);
            }
            $Step = 360 / (2 * PI * $Radius);
            $Offset = 360;
            foreach ($Values as $Key => $Value) {
                $EndAngle = $Offset - $Value * $ScaleFactor;
                if ($EndAngle < 0) {
                    $EndAngle = 0;
                }
                for ($i = $Offset; $i >= $EndAngle; $i = $i - $Step) {
                    $Xc = cos(($i - 90) * PI / 180) * $Radius + $X + $this->pChartObject->ShadowX;
                    $Yc = sin(($i - 90) * PI / 180) * $Radius * $SkewFactor + $Y + $this->pChartObject->ShadowY;
                    $this->pChartObject->drawAntialiasPixel($Xc, $Yc, $Settings);
                }
                $Offset = $i - $DataGapAngle;
                $ID--;
            }
        }
        /* Draw the bottom pie splice */
        foreach ($Slices as $SliceID => $Plots) {
            $Settings = $SliceColors[$SliceID];
            $Settings["NoBorder"] = \true;
            $this->pChartObject->drawPolygon($Plots, $Settings);
            if ($SecondPass) {
                $Settings = $SliceColors[$SliceID];
                if ($Border) {
                    $Settings["R"] += 30;
                    $Settings["G"] += 30;
                    $Settings["B"] += 30;
                }
                /* Empty error handling */
                if (isset($SliceAngle[$SliceID][1])) {
                    $Angle = $SliceAngle[$SliceID][1];
                    $Xc = cos(($Angle - 90) * PI / 180) * $Radius + $X;
                    $Yc = sin(($Angle - 90) * PI / 180) * $Radius * $SkewFactor + $Y;
                    $this->pChartObject->drawLine($Plots[0], $Plots[1], $Xc, $Yc, $Settings);
                    $Angle = $SliceAngle[$SliceID][count($SliceAngle[$SliceID]) - 1];
                    $Xc = cos(($Angle - 90) * PI / 180) * $Radius + $X;
                    $Yc = sin(($Angle - 90) * PI / 180) * $Radius * $SkewFactor + $Y;
                    $this->pChartObject->drawLine($Plots[0], $Plots[1], $Xc, $Yc, $Settings);
                }
            }
        }
        /* Draw the two vertical edges */
        $Slices = array_reverse($Slices);
        $SliceColors = array_reverse($SliceColors);
        foreach ($Slices as $SliceID => $Plots) {
            $Settings = $SliceColors[$SliceID];
            $Settings["R"] += 10;
            $Settings["G"] += 10;
            $Settings["B"] += 10;
            $Settings["NoBorder"] = \true;
            /* Empty error handling */
            if ($Visible[$SliceID]["Start"] && isset($Plots[2])) {
                $this->pChartObject->drawLine($Plots[2], $Plots[3], $Plots[2], $Plots[3] - $SliceHeight, ["R" => $Settings["R"], "G" => $Settings["G"], "B" => $Settings["B"]]);
                $Border = [];
                $Border[] = $Plots[0];
                $Border[] = $Plots[1];
                $Border[] = $Plots[0];
                $Border[] = $Plots[1] - $SliceHeight;
                $Border[] = $Plots[2];
                $Border[] = $Plots[3] - $SliceHeight;
                $Border[] = $Plots[2];
                $Border[] = $Plots[3];
                $this->pChartObject->drawPolygon($Border, $Settings);
            }
        }
        $Slices = array_reverse($Slices);
        $SliceColors = array_reverse($SliceColors);
        foreach ($Slices as $SliceID => $Plots) {
            $Settings = $SliceColors[$SliceID];
            $Settings["R"] += 10;
            $Settings["G"] += 10;
            $Settings["B"] += 10;
            $Settings["NoBorder"] = \true;
            if ($Visible[$SliceID]["End"]) {
                $this->pChartObject->drawLine($Plots[count($Plots) - 2], $Plots[count($Plots) - 1], $Plots[count($Plots) - 2], $Plots[count($Plots) - 1] - $SliceHeight, ["R" => $Settings["R"], "G" => $Settings["G"], "B" => $Settings["B"]]);
                $Border = [];
                $Border[] = $Plots[0];
                $Border[] = $Plots[1];
                $Border[] = $Plots[0];
                $Border[] = $Plots[1] - $SliceHeight;
                $Border[] = $Plots[count($Plots) - 2];
                $Border[] = $Plots[count($Plots) - 1] - $SliceHeight;
                $Border[] = $Plots[count($Plots) - 2];
                $Border[] = $Plots[count($Plots) - 1];
                $this->pChartObject->drawPolygon($Border, $Settings);
            }
        }
        /* Draw the rounded edges */
        foreach ($Slices as $SliceID => $Plots) {
            $Settings = $SliceColors[$SliceID];
            $Settings["R"] += 10;
            $Settings["G"] += 10;
            $Settings["B"] += 10;
            $Settings["NoBorder"] = \true;
            for ($j = 2; $j < count($Plots) - 2; $j = $j + 2) {
                $Angle = $SliceAngle[$SliceID][$j / 2];
                if ($Angle < 270 && $Angle > 90) {
                    $Border = [];
                    $Border[] = $Plots[$j];
                    $Border[] = $Plots[$j + 1];
                    $Border[] = $Plots[$j + 2];
                    $Border[] = $Plots[$j + 3];
                    $Border[] = $Plots[$j + 2];
                    $Border[] = $Plots[$j + 3] - $SliceHeight;
                    $Border[] = $Plots[$j];
                    $Border[] = $Plots[$j + 1] - $SliceHeight;
                    $this->pChartObject->drawPolygon($Border, $Settings);
                }
            }
            if ($SecondPass) {
                $Settings = $SliceColors[$SliceID];
                if (count($Border)) {
                    $Settings["R"] += 30;
                    $Settings["G"] += 30;
                    $Settings["B"] += 30;
                }
                /* Empty error handling */
                if (isset($SliceAngle[$SliceID][1])) {
                    $Angle = $SliceAngle[$SliceID][1];
                    if ($Angle < 270 && $Angle > 90) {
                        $Xc = cos(($Angle - 90) * PI / 180) * $Radius + $X;
                        $Yc = sin(($Angle - 90) * PI / 180) * $Radius * $SkewFactor + $Y;
                        $this->pChartObject->drawLine($Xc, $Yc, $Xc, $Yc - $SliceHeight, $Settings);
                    }
                }
                $Angle = $SliceAngle[$SliceID][count($SliceAngle[$SliceID]) - 1];
                if ($Angle < 270 && $Angle > 90) {
                    $Xc = cos(($Angle - 90) * PI / 180) * $Radius + $X;
                    $Yc = sin(($Angle - 90) * PI / 180) * $Radius * $SkewFactor + $Y;
                    $this->pChartObject->drawLine($Xc, $Yc, $Xc, $Yc - $SliceHeight, $Settings);
                }
                if (isset($SliceAngle[$SliceID][1]) && $SliceAngle[$SliceID][1] > 270 && $SliceAngle[$SliceID][count($SliceAngle[$SliceID]) - 1] < 270) {
                    $Xc = cos((270 - 90) * PI / 180) * $Radius + $X;
                    $Yc = sin((270 - 90) * PI / 180) * $Radius * $SkewFactor + $Y;
                    $this->pChartObject->drawLine($Xc, $Yc, $Xc, $Yc - $SliceHeight, $Settings);
                }
                if (isset($SliceAngle[$SliceID][1]) && $SliceAngle[$SliceID][1] > 90 && $SliceAngle[$SliceID][count($SliceAngle[$SliceID]) - 1] < 90) {
                    $Xc = cos(0 * PI / 180) * $Radius + $X;
                    $Yc = sin(0 * PI / 180) * $Radius * $SkewFactor + $Y;
                    $this->pChartObject->drawLine($Xc, $Yc, $Xc, $Yc - $SliceHeight, $Settings);
                }
            }
        }
        /* Draw the top splice */
        foreach ($Slices as $SliceID => $Plots) {
            $Settings = $SliceColors[$SliceID];
            $Settings["R"] += 20;
            $Settings["G"] += 20;
            $Settings["B"] += 20;
            $Top = [];
            for ($j = 0; $j < count($Plots); $j = $j + 2) {
                $Top[] = $Plots[$j];
                $Top[] = $Plots[$j + 1] - $SliceHeight;
            }
            $this->pChartObject->drawPolygon($Top, $Settings);
            if ($RecordImageMap && !$Shadow) {
                $this->pChartObject->addToImageMap("POLY", $this->arraySerialize($Top), $this->pChartObject->toHTMLColor($Settings["R"], $Settings["G"], $Settings["B"]), $Data["Series"][$Data["Abscissa"]]["Data"][count($Slices) - $SliceID - 1], $Values[$SliceID]);
            }
        }
        /* Second pass to smooth the angles */
        if ($SecondPass) {
            $Step = 360 / (2 * PI * $Radius);
            $Offset = 360;
            $ID = count($Values) - 1;
            foreach ($Values as $Key => $Value) {
                $FirstPoint = \true;
                if ($Shadow) {
                    $Settings = ["R" => $this->pChartObject->ShadowR, "G" => $this->pChartObject->ShadowG, "B" => $this->pChartObject->ShadowB, "Alpha" => $this->pChartObject->Shadowa];
                } else {
                    if ($Border) {
                        $Settings = ["R" => $Palette[$ID]["R"] + 30, "G" => $Palette[$ID]["G"] + 30, "B" => $Palette[$ID]["B"] + 30, "Alpha" => $Palette[$ID]["Alpha"]];
                    } else {
                        $Settings = ["R" => $Palette[$ID]["R"], "G" => $Palette[$ID]["G"], "B" => $Palette[$ID]["B"], "Alpha" => $Palette[$ID]["Alpha"]];
                    }
                }
                $EndAngle = $Offset - $Value * $ScaleFactor;
                if ($EndAngle < 0) {
                    $EndAngle = 0;
                }
                if ($DataGapAngle == 0) {
                    $X0 = $X;
                    $Y0 = $Y - $SliceHeight;
                } else {
                    $Angle = ($EndAngle - $Offset) / 2 + $Offset;
                    $X0 = cos(($Angle - 90) * PI / 180) * $DataGapRadius + $X;
                    $Y0 = sin(($Angle - 90) * PI / 180) * $DataGapRadius * $SkewFactor + $Y - $SliceHeight;
                }
                $Plots[] = $X0;
                $Plots[] = $Y0;
                for ($i = $Offset; $i >= $EndAngle; $i = $i - $Step) {
                    $Xc = cos(($i - 90) * PI / 180) * $Radius + $X;
                    $Yc = sin(($i - 90) * PI / 180) * $Radius * $SkewFactor + $Y - $SliceHeight;
                    if ($FirstPoint) {
                        $this->pChartObject->drawLine($Xc, $Yc, $X0, $Y0, $Settings);
                        $FirstPoint = \false;
                    }
                    $this->pChartObject->drawAntialiasPixel($Xc, $Yc, $Settings);
                    if ($i < 270 && $i > 90) {
                        $this->pChartObject->drawAntialiasPixel($Xc, $Yc + $SliceHeight, $Settings);
                    }
                }
                $this->pChartObject->drawLine($Xc, $Yc, $X0, $Y0, $Settings);
                $Offset = $i - $DataGapAngle;
                $ID--;
            }
        }
        if ($WriteValues != null) {
            $Step = 360 / (2 * PI * $Radius);
            $Offset = 360;
            $ID = count($Values) - 1;
            $Settings = ["Align" => TEXT_ALIGN_MIDDLEMIDDLE, "R" => $ValueR, "G" => $ValueG, "B" => $ValueB, "Alpha" => $ValueAlpha];
            foreach ($Values as $Key => $Value) {
                $EndAngle = $Offset - $Value * $ScaleFactor;
                if ($EndAngle < 0) {
                    $EndAngle = 0;
                }
                $Angle = ($EndAngle - $Offset) / 2 + $Offset;
                if ($ValuePosition == PIE_VALUE_OUTSIDE) {
                    $Xc = cos(($Angle - 90) * PI / 180) * ($Radius + $ValuePadding) + $X;
                    $Yc = sin(($Angle - 90) * PI / 180) * ($Radius * $SkewFactor + $ValuePadding) + $Y - $SliceHeight;
                } else {
                    $Xc = cos(($Angle - 90) * PI / 180) * $Radius / 2 + $X;
                    $Yc = sin(($Angle - 90) * PI / 180) * ($Radius * $SkewFactor) / 2 + $Y - $SliceHeight;
                }
                if ($WriteValues == PIE_VALUE_PERCENTAGE) {
                    $Display = round(100 / $SerieSum * $Value, $Precision) . "%";
                } elseif ($WriteValues == PIE_VALUE_NATURAL) {
                    $Display = $Value . $ValueSuffix;
                }
                $this->pChartObject->drawText($Xc, $Yc, $Display, $Settings);
                $Offset = $EndAngle - $DataGapAngle;
                $ID--;
            }
        }
        if ($DrawLabels) {
            $Step = 360 / (2 * PI * $Radius);
            $Offset = 360;
            $ID = count($Values) - 1;
            foreach ($Values as $Key => $Value) {
                if ($LabelColor == PIE_LABEL_COLOR_AUTO) {
                    $Settings = ["FillR" => $Palette[$ID]["R"], "FillG" => $Palette[$ID]["G"], "FillB" => $Palette[$ID]["B"], "Alpha" => $Palette[$ID]["Alpha"]];
                } else {
                    $Settings = ["FillR" => $LabelR, "FillG" => $LabelG, "FillB" => $LabelB, "Alpha" => $LabelAlpha];
                }
                $EndAngle = $Offset - $Value * $ScaleFactor;
                if ($EndAngle < 0) {
                    $EndAngle = 0;
                }
                $Angle = ($EndAngle - $Offset) / 2 + $Offset;
                $Xc = cos(($Angle - 90) * PI / 180) * $Radius + $X;
                $Yc = sin(($Angle - 90) * PI / 180) * $Radius * $SkewFactor + $Y - $SliceHeight;
                if (isset($Data["Series"][$Data["Abscissa"]]["Data"][$ID])) {
                    $Label = $Data["Series"][$Data["Abscissa"]]["Data"][$ID];
                    if ($LabelStacked) {
                        $this->writePieLabel($Xc, $Yc, $Label, $Angle, $Settings, \true, $X, $Y, $Radius, \true);
                    } else {
                        $this->writePieLabel($Xc, $Yc, $Label, $Angle, $Settings, \false);
                    }
                }
                $Offset = $EndAngle - $DataGapAngle;
                $ID--;
            }
        }
        if ($DrawLabels && $LabelStacked) {
            $this->writeShiftedLabels();
        }
        $this->pChartObject->Shadow = $RestoreShadow;
        return PIE_RENDERED;
    }
    /**
     * Draw the legend of pie chart
     * @param int $X
     * @param int $Y
     * @param array $Format
     * @return int
     */
    public function drawPieLegend($X, $Y, array $Format = [])
    {
        $FontName = isset($Format["FontName"]) ? $Format["FontName"] : $this->pChartObject->FontName;
        $FontSize = isset($Format["FontSize"]) ? $Format["FontSize"] : $this->pChartObject->FontSize;
        $FontR = isset($Format["FontR"]) ? $Format["FontR"] : $this->pChartObject->FontColorR;
        $FontG = isset($Format["FontG"]) ? $Format["FontG"] : $this->pChartObject->FontColorG;
        $FontB = isset($Format["FontB"]) ? $Format["FontB"] : $this->pChartObject->FontColorB;
        $BoxSize = isset($Format["BoxSize"]) ? $Format["BoxSize"] : 5;
        $Margin = isset($Format["Margin"]) ? $Format["Margin"] : 5;
        $R = isset($Format["R"]) ? $Format["R"] : 200;
        $G = isset($Format["G"]) ? $Format["G"] : 200;
        $B = isset($Format["B"]) ? $Format["B"] : 200;
        $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100;
        $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : 255;
        $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : 255;
        $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : 255;
        $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : null;
        $Style = isset($Format["Style"]) ? $Format["Style"] : LEGEND_ROUND;
        $Mode = isset($Format["Mode"]) ? $Format["Mode"] : LEGEND_VERTICAL;
        if ($Surrounding != null) {
            $BorderR = $R + $Surrounding;
            $BorderG = $G + $Surrounding;
            $BorderB = $B + $Surrounding;
        }
        $YStep = max($this->pChartObject->FontSize, $BoxSize) + 5;
        $XStep = $BoxSize + 5;
        /* Data Processing */
        $Data = $this->pDataObject->getData();
        $Palette = $this->pDataObject->getPalette();
        /* Do we have an abscissa serie defined? */
        if ($Data["Abscissa"] == "") {
            return PIE_NO_ABSCISSA;
        }
        $Boundaries = [];
        $Boundaries["L"] = $X;
        $Boundaries["T"] = $Y;
        $Boundaries["R"] = 0;
        $Boundaries["B"] = 0;
        $vY = $Y;
        $vX = $X;
        foreach ($Data["Series"][$Data["Abscissa"]]["Data"] as $Key => $Value) {
            $BoxArray = $this->pChartObject->getTextBox($vX + $BoxSize + 4, $vY + $BoxSize / 2, $FontName, $FontSize, 0, $Value);
            if ($Mode == LEGEND_VERTICAL) {
                if ($Boundaries["T"] > $BoxArray[2]["Y"] + $BoxSize / 2) {
                    $Boundaries["T"] = $BoxArray[2]["Y"] + $BoxSize / 2;
                }
                if ($Boundaries["R"] < $BoxArray[1]["X"] + 2) {
                    $Boundaries["R"] = $BoxArray[1]["X"] + 2;
                }
                if ($Boundaries["B"] < $BoxArray[1]["Y"] + 2 + $BoxSize / 2) {
                    $Boundaries["B"] = $BoxArray[1]["Y"] + 2 + $BoxSize / 2;
                }
                $vY = $vY + $YStep;
            } elseif ($Mode == LEGEND_HORIZONTAL) {
                if ($Boundaries["T"] > $BoxArray[2]["Y"] + $BoxSize / 2) {
                    $Boundaries["T"] = $BoxArray[2]["Y"] + $BoxSize / 2;
                }
                if ($Boundaries["R"] < $BoxArray[1]["X"] + 2) {
                    $Boundaries["R"] = $BoxArray[1]["X"] + 2;
                }
                if ($Boundaries["B"] < $BoxArray[1]["Y"] + 2 + $BoxSize / 2) {
                    $Boundaries["B"] = $BoxArray[1]["Y"] + 2 + $BoxSize / 2;
                }
                $vX = $Boundaries["R"] + $XStep;
            }
        }
        $vY = $vY - $YStep;
        $vX = $vX - $XStep;
        $TopOffset = $Y - $Boundaries["T"];
        if ($Boundaries["B"] - ($vY + $BoxSize) < $TopOffset) {
            $Boundaries["B"] = $vY + $BoxSize + $TopOffset;
        }
        if ($Style == LEGEND_ROUND) {
            $this->pChartObject->drawRoundedFilledRectangle($Boundaries["L"] - $Margin, $Boundaries["T"] - $Margin, $Boundaries["R"] + $Margin, $Boundaries["B"] + $Margin, $Margin, ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha, "BorderR" => $BorderR, "BorderG" => $BorderG, "BorderB" => $BorderB]);
        } elseif ($Style == LEGEND_BOX) {
            $this->pChartObject->drawFilledRectangle($Boundaries["L"] - $Margin, $Boundaries["T"] - $Margin, $Boundaries["R"] + $Margin, $Boundaries["B"] + $Margin, ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha, "BorderR" => $BorderR, "BorderG" => $BorderG, "BorderB" => $BorderB]);
        }
        $RestoreShadow = $this->pChartObject->Shadow;
        $this->pChartObject->Shadow = \false;
        foreach ($Data["Series"][$Data["Abscissa"]]["Data"] as $Key => $Value) {
            $R = $Palette[$Key]["R"];
            $G = $Palette[$Key]["G"];
            $B = $Palette[$Key]["B"];
            $this->pChartObject->drawFilledRectangle($X + 1, $Y + 1, $X + $BoxSize + 1, $Y + $BoxSize + 1, ["R" => 0, "G" => 0, "B" => 0, "Alpha" => 20]);
            $this->pChartObject->drawFilledRectangle($X, $Y, $X + $BoxSize, $Y + $BoxSize, ["R" => $R, "G" => $G, "B" => $B, "Surrounding" => 20]);
            if ($Mode == LEGEND_VERTICAL) {
                $this->pChartObject->drawText($X + $BoxSize + 4, $Y + $BoxSize / 2, $Value, ["R" => $FontR, "G" => $FontG, "B" => $FontB, "Align" => TEXT_ALIGN_MIDDLELEFT, "FontName" => $FontName, "FontSize" => $FontSize]);
                $Y = $Y + $YStep;
            } elseif ($Mode == LEGEND_HORIZONTAL) {
                $BoxArray = $this->pChartObject->drawText($X + $BoxSize + 4, $Y + $BoxSize / 2, $Value, ["R" => $FontR, "G" => $FontG, "B" => $FontB, "Align" => TEXT_ALIGN_MIDDLELEFT, "FontName" => $FontName, "FontSize" => $FontSize]);
                $X = $BoxArray[1]["X"] + 2 + $XStep;
            }
        }
        $this->pChartObject->Shadow = $RestoreShadow;
    }
    /**
     * Set the color of the specified slice
     * @param mixed $SliceID
     * @param array $Format
     */
    public function setSliceColor($SliceID, array $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;
        $this->pDataObject->Palette[$SliceID]["R"] = $R;
        $this->pDataObject->Palette[$SliceID]["G"] = $G;
        $this->pDataObject->Palette[$SliceID]["B"] = $B;
        $this->pDataObject->Palette[$SliceID]["Alpha"] = $Alpha;
    }
    /**
     * Internally used compute the label positions
     * @param int $X
     * @param int $Y
     * @param string $Label
     * @param int|float $Angle
     * @param array $Settings
     * @param boolean $Stacked
     * @param int $Xc
     * @param int $Yc
     * @param int $Radius
     * @param boolean $Reversed
     */
    public function writePieLabel($X, $Y, $Label, $Angle, $Settings, $Stacked, $Xc = 0, $Yc = 0, $Radius = 0, $Reversed = \false)
    {
        $LabelOffset = 30;
        $FontName = $this->pChartObject->FontName;
        $FontSize = $this->pChartObject->FontSize;
        if (!$Stacked) {
            $Settings["Angle"] = 360 - $Angle;
            $Settings["Length"] = 25;
            $Settings["Size"] = 8;
            $this->pChartObject->drawArrowLabel($X, $Y, " " . $Label . " ", $Settings);
        } else {
            $X2 = cos(deg2rad($Angle - 90)) * 20 + $X;
            $Y2 = sin(deg2rad($Angle - 90)) * 20 + $Y;
            $TxtPos = $this->pChartObject->getTextBox($X, $Y, $FontName, $FontSize, 0, $Label);
            $Height = $TxtPos[0]["Y"] - $TxtPos[2]["Y"];
            $YTop = $Y2 - $Height / 2 - 2;
            $YBottom = $Y2 + $Height / 2 + 2;
            if (count($this->LabelPos)) {
                $Done = \false;
                foreach ($this->LabelPos as $Key => $Settings) {
                    if (!$Done) {
                        $yTopAboveTopBelowBottom = $YTop >= $Settings["YTop"] && $YTop <= $Settings["YBottom"];
                        $yBottomAboveTopBelowBottom = $YBottom >= $Settings["YTop"] && $YBottom <= $Settings["YBottom"];
                        if ($Angle <= 90 && ($yTopAboveTopBelowBottom || $yBottomAboveTopBelowBottom)) {
                            $this->shift(0, 180, -($Height + 2), $Reversed);
                            $Done = \true;
                        }
                        if ($Angle > 90 && $Angle <= 180 && ($yTopAboveTopBelowBottom || $yBottomAboveTopBelowBottom)) {
                            $this->shift(0, 180, -($Height + 2), $Reversed);
                            $Done = \true;
                        }
                        if ($Angle > 180 && $Angle <= 270 && ($yTopAboveTopBelowBottom || $yBottomAboveTopBelowBottom)) {
                            $this->shift(180, 360, $Height + 2, $Reversed);
                            $Done = \true;
                        }
                        if ($Angle > 270 && $Angle <= 360 && ($yTopAboveTopBelowBottom || $yBottomAboveTopBelowBottom)) {
                            $this->shift(180, 360, $Height + 2, $Reversed);
                            $Done = \true;
                        }
                    }
                }
            }
            $LabelSettings = ["YTop" => $YTop, "YBottom" => $YBottom, "Label" => $Label, "Angle" => $Angle, "X1" => $X, "Y1" => $Y, "X2" => $X2, "Y2" => $Y2];
            if ($Angle <= 180) {
                $LabelSettings["X3"] = $Xc + $Radius + $LabelOffset;
            }
            if ($Angle > 180) {
                $LabelSettings["X3"] = $Xc - $Radius - $LabelOffset;
            }
            $this->LabelPos[] = $LabelSettings;
        }
    }
    /**
     * Internally used to shift label positions
     * @param int $StartAngle
     * @param int $EndAngle
     * @param int $Offset
     * @param boolean $Reversed
     */
    public function shift($StartAngle, $EndAngle, $Offset, $Reversed)
    {
        if ($Reversed) {
            $Offset = -$Offset;
        }
        foreach ($this->LabelPos as $Key => $Settings) {
            if ($Settings["Angle"] > $StartAngle && $Settings["Angle"] <= $EndAngle) {
                $this->LabelPos[$Key]["YTop"] = $Settings["YTop"] + $Offset;
                $this->LabelPos[$Key]["YBottom"] = $Settings["YBottom"] + $Offset;
                $this->LabelPos[$Key]["Y2"] = $Settings["Y2"] + $Offset;
            }
        }
    }
    /**
     * Internally used to write the re-computed labels
     * @return null|int
     */
    public function writeShiftedLabels()
    {
        if (!count($this->LabelPos)) {
            return 0;
        }
        foreach ($this->LabelPos as $Settings) {
            $X1 = $Settings["X1"];
            $Y1 = $Settings["Y1"];
            $X2 = $Settings["X2"];
            $Y2 = $Settings["Y2"];
            $X3 = $Settings["X3"];
            $Angle = $Settings["Angle"];
            $Label = $Settings["Label"];
            $this->pChartObject->drawArrow($X2, $Y2, $X1, $Y1, ["Size" => 8]);
            if ($Angle <= 180) {
                $this->pChartObject->drawLine($X2, $Y2, $X3, $Y2);
                $this->pChartObject->drawText($X3 + 2, $Y2, $Label, ["Align" => TEXT_ALIGN_MIDDLELEFT]);
            } else {
                $this->pChartObject->drawLine($X2, $Y2, $X3, $Y2);
                $this->pChartObject->drawText($X3 - 2, $Y2, $Label, ["Align" => TEXT_ALIGN_MIDDLERIGHT]);
            }
        }
    }
    /**
     * Draw a ring chart
     * @param int $X
     * @param int $Y
     * @param array $Format
     * @return int
     */
    public function draw2DRing($X, $Y, array $Format = [])
    {
        $OuterRadius = isset($Format["Radius"]) ? $Format["Radius"] : 60;
        // For compatibility
        $OuterRadius = isset($Format["OuterRadius"]) ? $Format["OuterRadius"] : $OuterRadius;
        $Precision = isset($Format["Precision"]) ? $Format["Precision"] : 0;
        $InnerRadius = isset($Format["InnerRadius"]) ? $Format["InnerRadius"] : 30;
        $Border = isset($Format["Border"]) ? $Format["Border"] : \false;
        $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : 255;
        $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : 255;
        $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : 255;
        $BorderAlpha = isset($Format["BorderAlpha"]) ? $Format["BorderAlpha"] : 100;
        $Shadow = isset($Format["Shadow"]) ? $Format["Shadow"] : \false;
        $DrawLabels = isset($Format["DrawLabels"]) ? $Format["DrawLabels"] : \false;
        $LabelStacked = isset($Format["LabelStacked"]) ? $Format["LabelStacked"] : \false;
        $LabelColor = isset($Format["LabelColor"]) ? $Format["LabelColor"] : PIE_LABEL_COLOR_MANUAL;
        $LabelR = isset($Format["LabelR"]) ? $Format["LabelR"] : 0;
        $LabelG = isset($Format["LabelG"]) ? $Format["LabelG"] : 0;
        $LabelB = isset($Format["LabelB"]) ? $Format["LabelB"] : 0;
        $LabelAlpha = isset($Format["LabelAlpha"]) ? $Format["LabelAlpha"] : 100;
        $WriteValues = isset($Format["WriteValues"]) ? $Format["WriteValues"] : null;
        //PIE_VALUE_PERCENTAGE
        $ValuePadding = isset($Format["ValuePadding"]) ? $Format["ValuePadding"] : 5;
        $ValuePosition = isset($Format["ValuePosition"]) ? $Format["ValuePosition"] : PIE_VALUE_OUTSIDE;
        $ValueSuffix = isset($Format["ValueSuffix"]) ? $Format["ValueSuffix"] : "";
        $ValueR = isset($Format["ValueR"]) ? $Format["ValueR"] : 255;
        $ValueG = isset($Format["ValueG"]) ? $Format["ValueG"] : 255;
        $ValueB = isset($Format["ValueB"]) ? $Format["ValueB"] : 255;
        $ValueAlpha = isset($Format["ValueAlpha"]) ? $Format["ValueAlpha"] : 100;
        $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : \false;
        /* Data Processing */
        $Data = $this->pDataObject->getData();
        $Palette = $this->pDataObject->getPalette();
        /* Do we have an abscissa serie defined? */
        if ($Data["Abscissa"] == "") {
            return PIE_NO_ABSCISSA;
        }
        /* Try to find the data serie */
        $DataSerie = null;
        foreach ($Data["Series"] as $SerieName => $SerieData) {
            if ($SerieName != $Data["Abscissa"]) {
                $DataSerie = $SerieName;
            }
        }
        /* Do we have data to compute? */
        if (!$DataSerie) {
            return PIE_NO_DATASERIE;
        }
        /* Remove unused data */
        list($Data, $Palette) = $this->clean0Values($Data, $Palette, $DataSerie, $Data["Abscissa"]);
        /* Compute the pie sum */
        $SerieSum = $this->pDataObject->getSum($DataSerie);
        /* Do we have data to draw? */
        if ($SerieSum == 0) {
            return PIE_SUMISNULL;
        }
        /* Dump the real number of data to draw */
        $Values = [];
        foreach ($Data["Series"][$DataSerie]["Data"] as $Key => $Value) {
            if ($Value != 0) {
                $Values[] = $Value;
            }
        }
        /* Compute the wasted angular space between series */
        if (count($Values) == 1) {
            $WastedAngular = 0;
        } else {
            $WastedAngular = 0;
        }
        // count($Values)
        /* Compute the scale */
        $ScaleFactor = (360 - $WastedAngular) / $SerieSum;
        $RestoreShadow = $this->pChartObject->Shadow;
        if ($this->pChartObject->Shadow) {
            $this->pChartObject->Shadow = \false;
            $ShadowFormat = $Format;
            $ShadowFormat["Shadow"] = \true;
            $this->draw2DRing($X + $this->pChartObject->ShadowX, $Y + $this->pChartObject->ShadowY, $ShadowFormat);
        }
        /* Draw the polygon pie elements */
        $Step = 360 / (2 * PI * $OuterRadius);
        $Offset = 0;
        $ID = 0;
        foreach ($Values as $Key => $Value) {
            if ($Shadow) {
                $Settings = ["R" => $this->pChartObject->ShadowR, "G" => $this->pChartObject->ShadowG, "B" => $this->pChartObject->ShadowB, "Alpha" => $this->pChartObject->Shadowa];
                $BorderColor = $Settings;
            } else {
                if (!isset($Palette[$ID]["R"])) {
                    $Color = $this->pChartObject->getRandomColor();
                    $Palette[$ID] = $Color;
                    $this->pDataObject->savePalette($ID, $Color);
                }
                $Settings = ["R" => $Palette[$ID]["R"], "G" => $Palette[$ID]["G"], "B" => $Palette[$ID]["B"], "Alpha" => $Palette[$ID]["Alpha"]];
                if ($Border) {
                    $BorderColor = ["R" => $BorderR, "G" => $BorderG, "B" => $BorderB, "Alpha" => $BorderAlpha];
                } else {
                    $BorderColor = $Settings;
                }
            }
            $Plots = [];
            $Boundaries = [];
            $AAPixels = [];
            $EndAngle = $Offset + $Value * $ScaleFactor;
            if ($EndAngle > 360) {
                $EndAngle = 360;
            }
            for ($i = $Offset; $i <= $EndAngle; $i = $i + $Step) {
                $Xc = cos(($i - 90) * PI / 180) * $OuterRadius + $X;
                $Yc = sin(($i - 90) * PI / 180) * $OuterRadius + $Y;
                if (!isset($Boundaries[0]["X1"])) {
                    $Boundaries[0]["X1"] = $Xc;
                    $Boundaries[0]["Y1"] = $Yc;
                }
                $AAPixels[] = [$Xc, $Yc];
                if ($i < 90) {
                    $Yc++;
                }
                if ($i > 180 && $i < 270) {
                    $Xc++;
                }
                if ($i >= 270) {
                    $Xc++;
                    $Yc++;
                }
                $Plots[] = $Xc;
                $Plots[] = $Yc;
            }
            $Boundaries[1]["X1"] = $Xc;
            $Boundaries[1]["Y1"] = $Yc;
            $Lasti = $EndAngle;
            for ($i = $EndAngle; $i >= $Offset; $i = $i - $Step) {
                $Xc = cos(($i - 90) * PI / 180) * ($InnerRadius - 1) + $X;
                $Yc = sin(($i - 90) * PI / 180) * ($InnerRadius - 1) + $Y;
                if (!isset($Boundaries[1]["X2"])) {
                    $Boundaries[1]["X2"] = $Xc;
                    $Boundaries[1]["Y2"] = $Yc;
                }
                $AAPixels[] = [$Xc, $Yc];
                $Xc = cos(($i - 90) * PI / 180) * $InnerRadius + $X;
                $Yc = sin(($i - 90) * PI / 180) * $InnerRadius + $Y;
                if ($i < 90) {
                    $Yc++;
                }
                if ($i > 180 && $i < 270) {
                    $Xc++;
                }
                if ($i >= 270) {
                    $Xc++;
                    $Yc++;
                }
                $Plots[] = $Xc;
                $Plots[] = $Yc;
            }
            $Boundaries[0]["X2"] = $Xc;
            $Boundaries[0]["Y2"] = $Yc;
            /* Draw the polygon */
            $this->pChartObject->drawPolygon($Plots, $Settings);
            if ($RecordImageMap && !$Shadow) {
                $this->pChartObject->addToImageMap("POLY", $this->arraySerialize($Plots), $this->pChartObject->toHTMLColor($Palette[$ID]["R"], $Palette[$ID]["G"], $Palette[$ID]["B"]), $Data["Series"][$Data["Abscissa"]]["Data"][$Key], $Value);
            }
            /* Smooth the edges using AA */
            foreach ($AAPixels as $Pos) {
                $this->pChartObject->drawAntialiasPixel($Pos[0], $Pos[1], $BorderColor);
            }
            $this->pChartObject->drawLine($Boundaries[0]["X1"], $Boundaries[0]["Y1"], $Boundaries[0]["X2"], $Boundaries[0]["Y2"], $BorderColor);
            $this->pChartObject->drawLine($Boundaries[1]["X1"], $Boundaries[1]["Y1"], $Boundaries[1]["X2"], $Boundaries[1]["Y2"], $BorderColor);
            if ($DrawLabels && !$Shadow) {
                if ($LabelColor == PIE_LABEL_COLOR_AUTO) {
                    $Settings = ["FillR" => $Palette[$ID]["R"], "FillG" => $Palette[$ID]["G"], "FillB" => $Palette[$ID]["B"], "Alpha" => $Palette[$ID]["Alpha"]];
                } else {
                    $Settings = ["FillR" => $LabelR, "FillG" => $LabelG, "FillB" => $LabelB, "Alpha" => $LabelAlpha];
                }
                $Angle = ($EndAngle - $Offset) / 2 + $Offset;
                $Xc = cos(($Angle - 90) * PI / 180) * $OuterRadius + $X;
                $Yc = sin(($Angle - 90) * PI / 180) * $OuterRadius + $Y;
                $Label = $Data["Series"][$Data["Abscissa"]]["Data"][$Key];
                if ($LabelStacked) {
                    $this->writePieLabel($Xc, $Yc, $Label, $Angle, $Settings, \true, $X, $Y, $OuterRadius);
                } else {
                    $this->writePieLabel($Xc, $Yc, $Label, $Angle, $Settings, \false);
                }
            }
            $Offset = $Lasti;
            $ID++;
        }
        if ($DrawLabels && $LabelStacked) {
            $this->writeShiftedLabels();
        }
        if ($WriteValues && !$Shadow) {
            $Step = 360 / (2 * PI * $OuterRadius);
            $Offset = 0;
            foreach ($Values as $Key => $Value) {
                $EndAngle = $Offset + $Value * $ScaleFactor;
                if ($EndAngle > 360) {
                    $EndAngle = 360;
                }
                $Angle = $Offset + $Value * $ScaleFactor / 2;
                if ($ValuePosition == PIE_VALUE_OUTSIDE) {
                    $Xc = cos(($Angle - 90) * PI / 180) * ($OuterRadius + $ValuePadding) + $X;
                    $Yc = sin(($Angle - 90) * PI / 180) * ($OuterRadius + $ValuePadding) + $Y;
                    if ($Angle >= 0 && $Angle <= 90) {
                        $Align = TEXT_ALIGN_BOTTOMLEFT;
                    }
                    if ($Angle > 90 && $Angle <= 180) {
                        $Align = TEXT_ALIGN_TOPLEFT;
                    }
                    if ($Angle > 180 && $Angle <= 270) {
                        $Align = TEXT_ALIGN_TOPRIGHT;
                    }
                    if ($Angle > 270) {
                        $Align = TEXT_ALIGN_BOTTOMRIGHT;
                    }
                } else {
                    $Xc = cos(($Angle - 90) * PI / 180) * (($OuterRadius - $InnerRadius) / 2 + $InnerRadius) + $X;
                    $Yc = sin(($Angle - 90) * PI / 180) * (($OuterRadius - $InnerRadius) / 2 + $InnerRadius) + $Y;
                    $Align = TEXT_ALIGN_MIDDLEMIDDLE;
                }
                if ($WriteValues == PIE_VALUE_PERCENTAGE) {
                    $Display = round(100 / $SerieSum * $Value, $Precision) . "%";
                } elseif ($WriteValues == PIE_VALUE_NATURAL) {
                    $Display = $Value . $ValueSuffix;
                } else {
                    $Display = "";
                }
                $this->pChartObject->drawText($Xc, $Yc, $Display, ["Align" => $Align, "R" => $ValueR, "G" => $ValueG, "B" => $ValueB]);
                $Offset = $EndAngle;
            }
        }
        $this->pChartObject->Shadow = $RestoreShadow;
        return PIE_RENDERED;
    }
    /**
     * Draw a 3D ring chart
     * @param int $X
     * @param int $Y
     * @param array $Format
     * @return int
     */
    public function draw3DRing($X, $Y, array $Format = [])
    {
        $OuterRadius = isset($Format["OuterRadius"]) ? $Format["OuterRadius"] : 100;
        $Precision = isset($Format["Precision"]) ? $Format["Precision"] : 0;
        $InnerRadius = isset($Format["InnerRadius"]) ? $Format["InnerRadius"] : 30;
        $SkewFactor = isset($Format["SkewFactor"]) ? $Format["SkewFactor"] : 0.6;
        $SliceHeight = isset($Format["SliceHeight"]) ? $Format["SliceHeight"] : 10;
        $DataGapAngle = isset($Format["DataGapAngle"]) ? $Format["DataGapAngle"] : 10;
        $DataGapRadius = isset($Format["DataGapRadius"]) ? $Format["DataGapRadius"] : 10;
        $Border = isset($Format["Border"]) ? $Format["Border"] : \false;
        $Shadow = isset($Format["Shadow"]) ? $Format["Shadow"] : \false;
        $DrawLabels = isset($Format["DrawLabels"]) ? $Format["DrawLabels"] : \false;
        $LabelStacked = isset($Format["LabelStacked"]) ? $Format["LabelStacked"] : \false;
        $LabelColor = isset($Format["LabelColor"]) ? $Format["LabelColor"] : PIE_LABEL_COLOR_MANUAL;
        $LabelR = isset($Format["LabelR"]) ? $Format["LabelR"] : 0;
        $LabelG = isset($Format["LabelG"]) ? $Format["LabelG"] : 0;
        $LabelB = isset($Format["LabelB"]) ? $Format["LabelB"] : 0;
        $LabelAlpha = isset($Format["LabelAlpha"]) ? $Format["LabelAlpha"] : 100;
        $Cf = isset($Format["Cf"]) ? $Format["Cf"] : 20;
        $WriteValues = isset($Format["WriteValues"]) ? $Format["WriteValues"] : PIE_VALUE_NATURAL;
        $ValuePadding = isset($Format["ValuePadding"]) ? $Format["ValuePadding"] : $SliceHeight + 15;
        $ValuePosition = isset($Format["ValuePosition"]) ? $Format["ValuePosition"] : PIE_VALUE_OUTSIDE;
        $ValueSuffix = isset($Format["ValueSuffix"]) ? $Format["ValueSuffix"] : "";
        $ValueR = isset($Format["ValueR"]) ? $Format["ValueR"] : 255;
        $ValueG = isset($Format["ValueG"]) ? $Format["ValueG"] : 255;
        $ValueB = isset($Format["ValueB"]) ? $Format["ValueB"] : 255;
        $ValueAlpha = isset($Format["ValueAlpha"]) ? $Format["ValueAlpha"] : 100;
        $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : \false;
        /* Error correction for overlaying rounded corners */
        if ($SkewFactor < 0.5) {
            $SkewFactor = 0.5;
        }
        /* Data Processing */
        $Data = $this->pDataObject->getData();
        $Palette = $this->pDataObject->getPalette();
        /* Do we have an abscissa serie defined? */
        if ($Data["Abscissa"] == "") {
            return PIE_NO_ABSCISSA;
        }
        /* Try to find the data serie */
        $DataSerie = null;
        foreach ($Data["Series"] as $SerieName => $SerieData) {
            if ($SerieName != $Data["Abscissa"]) {
                $DataSerie = $SerieName;
            }
        }
        /* Do we have data to compute? */
        if (!$DataSerie) {
            return PIE_NO_DATASERIE;
        }
        /* Remove unused data */
        list($Data, $Palette) = $this->clean0Values($Data, $Palette, $DataSerie, $Data["Abscissa"]);
        /* Compute the pie sum */
        $SerieSum = $this->pDataObject->getSum($DataSerie);
        /* Do we have data to draw? */
        if ($SerieSum == 0) {
            return PIE_SUMISNULL;
        }
        /* Dump the real number of data to draw */
        $Values = [];
        foreach ($Data["Series"][$DataSerie]["Data"] as $Key => $Value) {
            if ($Value != 0) {
                $Values[] = $Value;
            }
        }
        /* Compute the wasted angular space between series */
        if (count($Values) == 1) {
            $WastedAngular = 0;
        } else {
            $WastedAngular = count($Values) * $DataGapAngle;
        }
        /* Compute the scale */
        $ScaleFactor = (360 - $WastedAngular) / $SerieSum;
        $RestoreShadow = $this->pChartObject->Shadow;
        if ($this->pChartObject->Shadow) {
            $this->pChartObject->Shadow = \false;
        }
        /* Draw the polygon ring elements */
        $Offset = 360;
        $ID = count($Values) - 1;
        $Values = array_reverse($Values);
        $Slice = 0;
        $Slices = [];
        $SliceColors = [];
        $Visible = [];
        $SliceAngle = [];
        foreach ($Values as $Key => $Value) {
            if (!isset($Palette[$ID]["R"])) {
                $Color = $this->pChartObject->getRandomColor();
                $Palette[$ID] = $Color;
                $this->pDataObject->savePalette($ID, $Color);
            }
            $Settings = ["R" => $Palette[$ID]["R"], "G" => $Palette[$ID]["G"], "B" => $Palette[$ID]["B"], "Alpha" => $Palette[$ID]["Alpha"]];
            $SliceColors[$Slice] = $Settings;
            $StartAngle = $Offset;
            $EndAngle = $Offset - $Value * $ScaleFactor;
            if ($EndAngle < 0) {
                $EndAngle = 0;
            }
            if ($StartAngle > 180) {
                $Visible[$Slice]["Start"] = \true;
            } else {
                $Visible[$Slice]["Start"] = \true;
            }
            if ($EndAngle < 180) {
                $Visible[$Slice]["End"] = \false;
            } else {
                $Visible[$Slice]["End"] = \true;
            }
            $Step = 360 / (2 * PI * $OuterRadius) / 2;
            $OutX1 = VOID;
            $OutY1 = VOID;
            for ($i = $Offset; $i >= $EndAngle; $i = $i - $Step) {
                $Xc = cos(($i - 90) * PI / 180) * ($OuterRadius + $DataGapRadius - 2) + $X;
                $Yc = sin(($i - 90) * PI / 180) * ($OuterRadius + $DataGapRadius - 2) * $SkewFactor + $Y;
                $Slices[$Slice]["AA"][] = [$Xc, $Yc];
                $Xc = cos(($i - 90) * PI / 180) * ($OuterRadius + $DataGapRadius - 1) + $X;
                $Yc = sin(($i - 90) * PI / 180) * ($OuterRadius + $DataGapRadius - 1) * $SkewFactor + $Y;
                $Slices[$Slice]["AA"][] = [$Xc, $Yc];
                $Xc = cos(($i - 90) * PI / 180) * ($OuterRadius + $DataGapRadius) + $X;
                $Yc = sin(($i - 90) * PI / 180) * ($OuterRadius + $DataGapRadius) * $SkewFactor + $Y;
                $this->pChartObject->drawAntialiasPixel($Xc, $Yc, $Settings);
                if ($OutX1 == VOID) {
                    $OutX1 = $Xc;
                    $OutY1 = $Yc;
                }
                if ($i < 90) {
                    $Yc++;
                }
                if ($i > 90 && $i < 180) {
                    $Xc++;
                }
                if ($i > 180 && $i < 270) {
                    $Xc++;
                }
                if ($i >= 270) {
                    $Xc++;
                    $Yc++;
                }
                $Slices[$Slice]["BottomPoly"][] = floor($Xc);
                $Slices[$Slice]["BottomPoly"][] = floor($Yc);
                $Slices[$Slice]["TopPoly"][] = floor($Xc);
                $Slices[$Slice]["TopPoly"][] = floor($Yc) - $SliceHeight;
                $Slices[$Slice]["Angle"][] = $i;
            }
            $OutX2 = $Xc;
            $OutY2 = $Yc;
            $Slices[$Slice]["Angle"][] = VOID;
            $Lasti = $i;
            $Step = 360 / (2 * PI * $InnerRadius) / 2;
            $InX1 = VOID;
            $InY1 = VOID;
            for ($i = $EndAngle; $i <= $Offset; $i = $i + $Step) {
                $Xc = cos(($i - 90) * PI / 180) * ($InnerRadius + $DataGapRadius - 1) + $X;
                $Yc = sin(($i - 90) * PI / 180) * ($InnerRadius + $DataGapRadius - 1) * $SkewFactor + $Y;
                $Slices[$Slice]["AA"][] = [$Xc, $Yc];
                $Xc = cos(($i - 90) * PI / 180) * ($InnerRadius + $DataGapRadius) + $X;
                $Yc = sin(($i - 90) * PI / 180) * ($InnerRadius + $DataGapRadius) * $SkewFactor + $Y;
                $Slices[$Slice]["AA"][] = [$Xc, $Yc];
                if ($InX1 == VOID) {
                    $InX1 = $Xc;
                    $InY1 = $Yc;
                }
                if ($i < 90) {
                    $Yc++;
                }
                if ($i > 90 && $i < 180) {
                    $Xc++;
                }
                if ($i > 180 && $i < 270) {
                    $Xc++;
                }
                if ($i >= 270) {
                    $Xc++;
                    $Yc++;
                }
                $Slices[$Slice]["BottomPoly"][] = floor($Xc);
                $Slices[$Slice]["BottomPoly"][] = floor($Yc);
                $Slices[$Slice]["TopPoly"][] = floor($Xc);
                $Slices[$Slice]["TopPoly"][] = floor($Yc) - $SliceHeight;
                $Slices[$Slice]["Angle"][] = $i;
            }
            $InX2 = $Xc;
            $InY2 = $Yc;
            $Slices[$Slice]["InX1"] = $InX1;
            $Slices[$Slice]["InY1"] = $InY1;
            $Slices[$Slice]["InX2"] = $InX2;
            $Slices[$Slice]["InY2"] = $InY2;
            $Slices[$Slice]["OutX1"] = $OutX1;
            $Slices[$Slice]["OutY1"] = $OutY1;
            $Slices[$Slice]["OutX2"] = $OutX2;
            $Slices[$Slice]["OutY2"] = $OutY2;
            $Offset = $Lasti - $DataGapAngle;
            $ID--;
            $Slice++;
        }
        /* Draw the bottom pie splice */
        foreach ($Slices as $SliceID => $Plots) {
            $Settings = $SliceColors[$SliceID];
            $Settings["NoBorder"] = \true;
            $this->pChartObject->drawPolygon($Plots["BottomPoly"], $Settings);
            foreach ($Plots["AA"] as $Key => $Pos) {
                $this->pChartObject->drawAntialiasPixel($Pos[0], $Pos[1], $Settings);
            }
            $this->pChartObject->drawLine($Plots["InX1"], $Plots["InY1"], $Plots["OutX2"], $Plots["OutY2"], $Settings);
            $this->pChartObject->drawLine($Plots["InX2"], $Plots["InY2"], $Plots["OutX1"], $Plots["OutY1"], $Settings);
        }
        $Slices = array_reverse($Slices);
        $SliceColors = array_reverse($SliceColors);
        /* Draw the vertical edges (semi-visible) */
        foreach ($Slices as $SliceID => $Plots) {
            $Settings = $SliceColors[$SliceID];
            $Settings["NoBorder"] = \true;
            $Settings["R"] = $Settings["R"] + $Cf;
            $Settings["G"] = $Settings["G"] + $Cf;
            $Settings["B"] = $Settings["B"] + $Cf;
            $StartAngle = $Plots["Angle"][0];
            foreach ($Plots["Angle"] as $Key => $Angle) {
                if ($Angle == VOID) {
                    $EndAngle = $Plots["Angle"][$Key - 1];
                }
            }
            if ($StartAngle >= 270 || $StartAngle <= 90) {
                $this->pChartObject->drawLine($Plots["OutX1"], $Plots["OutY1"], $Plots["OutX1"], $Plots["OutY1"] - $SliceHeight, $Settings);
            }
            if ($StartAngle >= 270 || $StartAngle <= 90) {
                $this->pChartObject->drawLine($Plots["OutX2"], $Plots["OutY2"], $Plots["OutX2"], $Plots["OutY2"] - $SliceHeight, $Settings);
            }
            $this->pChartObject->drawLine($Plots["InX1"], $Plots["InY1"], $Plots["InX1"], $Plots["InY1"] - $SliceHeight, $Settings);
            $this->pChartObject->drawLine($Plots["InX2"], $Plots["InY2"], $Plots["InX2"], $Plots["InY2"] - $SliceHeight, $Settings);
        }
        /* Draw the inner vertical slices */
        foreach ($Slices as $SliceID => $Plots) {
            $Settings = $SliceColors[$SliceID];
            $Settings["NoBorder"] = \true;
            $Settings["R"] = $Settings["R"] + $Cf;
            $Settings["G"] = $Settings["G"] + $Cf;
            $Settings["B"] = $Settings["B"] + $Cf;
            $Outer = \true;
            $Inner = \false;
            $InnerPlotsA = [];
            $InnerPlotsB = [];
            foreach ($Plots["Angle"] as $ID => $Angle) {
                if ($Angle == VOID) {
                    $Outer = \false;
                    $Inner = \true;
                } elseif ($Inner && ($Angle < 90 || $Angle > 270) && isset($Plots["BottomPoly"][$ID * 2])) {
                    $Xo = $Plots["BottomPoly"][$ID * 2];
                    $Yo = $Plots["BottomPoly"][$ID * 2 + 1];
                    $InnerPlotsA[] = $Xo;
                    $InnerPlotsA[] = $Yo;
                    $InnerPlotsB[] = $Xo;
                    $InnerPlotsB[] = $Yo - $SliceHeight;
                }
            }
            if (count($InnerPlotsA)) {
                $InnerPlots = array_merge($InnerPlotsA, $this->arrayReverse($InnerPlotsB));
                $this->pChartObject->drawPolygon($InnerPlots, $Settings);
            }
        }
        /* Draw the splice top and left poly */
        foreach ($Slices as $SliceID => $Plots) {
            $Settings = $SliceColors[$SliceID];
            $Settings["NoBorder"] = \true;
            $Settings["R"] = $Settings["R"] + $Cf * 1.5;
            $Settings["G"] = $Settings["G"] + $Cf * 1.5;
            $Settings["B"] = $Settings["B"] + $Cf * 1.5;
            $StartAngle = $Plots["Angle"][0];
            foreach ($Plots["Angle"] as $Key => $Angle) {
                if ($Angle == VOID) {
                    $EndAngle = $Plots["Angle"][$Key - 1];
                }
            }
            if ($StartAngle < 180) {
                $Points = [];
                $Points[] = $Plots["InX2"];
                $Points[] = $Plots["InY2"];
                $Points[] = $Plots["InX2"];
                $Points[] = $Plots["InY2"] - $SliceHeight;
                $Points[] = $Plots["OutX1"];
                $Points[] = $Plots["OutY1"] - $SliceHeight;
                $Points[] = $Plots["OutX1"];
                $Points[] = $Plots["OutY1"];
                $this->pChartObject->drawPolygon($Points, $Settings);
            }
            if ($EndAngle > 180) {
                $Points = [];
                $Points[] = $Plots["InX1"];
                $Points[] = $Plots["InY1"];
                $Points[] = $Plots["InX1"];
                $Points[] = $Plots["InY1"] - $SliceHeight;
                $Points[] = $Plots["OutX2"];
                $Points[] = $Plots["OutY2"] - $SliceHeight;
                $Points[] = $Plots["OutX2"];
                $Points[] = $Plots["OutY2"];
                $this->pChartObject->drawPolygon($Points, $Settings);
            }
        }
        /* Draw the vertical edges (visible) */
        foreach ($Slices as $SliceID => $Plots) {
            $Settings = $SliceColors[$SliceID];
            $Settings["NoBorder"] = \true;
            $Settings["R"] = $Settings["R"] + $Cf;
            $Settings["G"] = $Settings["G"] + $Cf;
            $Settings["B"] = $Settings["B"] + $Cf;
            $StartAngle = $Plots["Angle"][0];
            foreach ($Plots["Angle"] as $Key => $Angle) {
                if ($Angle == VOID) {
                    $EndAngle = $Plots["Angle"][$Key - 1];
                }
            }
            if ($StartAngle <= 270 && $StartAngle >= 90) {
                $this->pChartObject->drawLine($Plots["OutX1"], $Plots["OutY1"], $Plots["OutX1"], $Plots["OutY1"] - $SliceHeight, $Settings);
            }
            if ($EndAngle <= 270 && $EndAngle >= 90) {
                $this->pChartObject->drawLine($Plots["OutX2"], $Plots["OutY2"], $Plots["OutX2"], $Plots["OutY2"] - $SliceHeight, $Settings);
            }
        }
        /* Draw the outer vertical slices */
        foreach ($Slices as $SliceID => $Plots) {
            $Settings = $SliceColors[$SliceID];
            $Settings["NoBorder"] = \true;
            $Settings["R"] = $Settings["R"] + $Cf;
            $Settings["G"] = $Settings["G"] + $Cf;
            $Settings["B"] = $Settings["B"] + $Cf;
            $Outer = \true;
            $Inner = \false;
            $OuterPlotsA = [];
            $OuterPlotsB = [];
            $InnerPlotsA = [];
            $InnerPlotsB = [];
            foreach ($Plots["Angle"] as $ID => $Angle) {
                if ($Angle == VOID) {
                    $Outer = \false;
                    $Inner = \true;
                } elseif ($Outer && ($Angle > 90 && $Angle < 270) && isset($Plots["BottomPoly"][$ID * 2])) {
                    $Xo = $Plots["BottomPoly"][$ID * 2];
                    $Yo = $Plots["BottomPoly"][$ID * 2 + 1];
                    $OuterPlotsA[] = $Xo;
                    $OuterPlotsA[] = $Yo;
                    $OuterPlotsB[] = $Xo;
                    $OuterPlotsB[] = $Yo - $SliceHeight;
                }
            }
            if (count($OuterPlotsA)) {
                $OuterPlots = array_merge($OuterPlotsA, $this->arrayReverse($OuterPlotsB));
                $this->pChartObject->drawPolygon($OuterPlots, $Settings);
            }
        }
        $Slices = array_reverse($Slices);
        $SliceColors = array_reverse($SliceColors);
        /* Draw the top pie splice */
        foreach ($Slices as $SliceID => $Plots) {
            $Settings = $SliceColors[$SliceID];
            $Settings["NoBorder"] = \true;
            $Settings["R"] = $Settings["R"] + $Cf * 2;
            $Settings["G"] = $Settings["G"] + $Cf * 2;
            $Settings["B"] = $Settings["B"] + $Cf * 2;
            $this->pChartObject->drawPolygon($Plots["TopPoly"], $Settings);
            if ($RecordImageMap) {
                $this->pChartObject->addToImageMap("POLY", $this->arraySerialize($Plots["TopPoly"]), $this->pChartObject->toHTMLColor($Settings["R"], $Settings["G"], $Settings["B"]), $Data["Series"][$Data["Abscissa"]]["Data"][$SliceID], $Data["Series"][$DataSerie]["Data"][count($Slices) - $SliceID - 1]);
            }
            foreach ($Plots["AA"] as $Key => $Pos) {
                $this->pChartObject->drawAntialiasPixel($Pos[0], $Pos[1] - $SliceHeight, $Settings);
            }
            $this->pChartObject->drawLine($Plots["InX1"], $Plots["InY1"] - $SliceHeight, $Plots["OutX2"], $Plots["OutY2"] - $SliceHeight, $Settings);
            $this->pChartObject->drawLine($Plots["InX2"], $Plots["InY2"] - $SliceHeight, $Plots["OutX1"], $Plots["OutY1"] - $SliceHeight, $Settings);
        }
        if ($DrawLabels) {
            $Offset = 360;
            foreach ($Values as $Key => $Value) {
                $StartAngle = $Offset;
                $EndAngle = $Offset - $Value * $ScaleFactor;
                if ($EndAngle < 0) {
                    $EndAngle = 0;
                }
                if ($LabelColor == PIE_LABEL_COLOR_AUTO) {
                    $Settings = ["FillR" => $Palette[$ID]["R"], "FillG" => $Palette[$ID]["G"], "FillB" => $Palette[$ID]["B"], "Alpha" => $Palette[$ID]["Alpha"]];
                } else {
                    $Settings = ["FillR" => $LabelR, "FillG" => $LabelG, "FillB" => $LabelB, "Alpha" => $LabelAlpha];
                }
                $Angle = ($EndAngle - $Offset) / 2 + $Offset;
                $Xc = cos(($Angle - 90) * PI / 180) * ($OuterRadius + $DataGapRadius) + $X;
                $Yc = sin(($Angle - 90) * PI / 180) * ($OuterRadius + $DataGapRadius) * $SkewFactor + $Y;
                $Label = "";
                if ($WriteValues == PIE_VALUE_PERCENTAGE) {
                    $Label = round(100 / $SerieSum * $Value, $Precision) . "%";
                } elseif ($WriteValues == PIE_VALUE_NATURAL) {
                    $Label = $Data["Series"][$Data["Abscissa"]]["Data"][$Key];
                }
                if ($LabelStacked) {
                    $this->writePieLabel($Xc, $Yc - $SliceHeight, $Label, $Angle, $Settings, \true, $X, $Y, $OuterRadius);
                } else {
                    $this->writePieLabel($Xc, $Yc - $SliceHeight, $Label, $Angle, $Settings, \false);
                }
                $Offset = $EndAngle - $DataGapAngle;
                $ID--;
                $Slice++;
            }
        }
        if ($DrawLabels && $LabelStacked) {
            $this->writeShiftedLabels();
        }
        $this->pChartObject->Shadow = $RestoreShadow;
        return PIE_RENDERED;
    }
    /**
     * Serialize an array
     * @param array $Data
     * @return string
     */
    public function arraySerialize(array $Data)
    {
        $Result = "";
        foreach ($Data as $Value) {
            if ($Result == "") {
                $Result = floor($Value);
            } else {
                $Result = $Result . "," . floor($Value);
            }
        }
        return $Result;
    }
    /**
     * Reverse an array
     * @param array $Plots
     * @return array
     */
    public function arrayReverse(array $Plots)
    {
        $Result = [];
        for ($i = count($Plots) - 1; $i >= 0; $i = $i - 2) {
            $Result[] = $Plots[$i - 1];
            $Result[] = $Plots[$i];
        }
        return $Result;
    }
    /**
     * Remove unused series & values
     * @param array $Data
     * @param array $Palette
     * @param string $DataSerie
     * @param string $AbscissaSerie
     * @return array
     */
    public function clean0Values(array $Data, array $Palette, $DataSerie, $AbscissaSerie)
    {
        $NewPalette = [];
        $NewData = [];
        $NewAbscissa = [];
        /* Remove unused series */
        foreach (array_keys($Data["Series"]) as $SerieName) {
            if ($SerieName != $DataSerie && $SerieName != $AbscissaSerie) {
                unset($Data["Series"][$SerieName]);
            }
        }
        /* Remove null values */
        foreach ($Data["Series"][$DataSerie]["Data"] as $Key => $Value) {
            if ($Value != 0) {
                $NewData[] = $Value;
                $NewAbscissa[] = $Data["Series"][$AbscissaSerie]["Data"][$Key];
                if (isset($Palette[$Key])) {
                    $NewPalette[] = $Palette[$Key];
                }
            }
        }
        $Data["Series"][$DataSerie]["Data"] = $NewData;
        $Data["Series"][$AbscissaSerie]["Data"] = $NewAbscissa;
        return [$Data, $NewPalette];
    }
}

https://t.me/RX1948 - 2025