Draw a bezier curve with two controls points
@param int $X1
@param int $Y1
@param int $X2
@param int $Y2
@param int $Xv1
@param int $Yv1
@param int $Xv2
@param int $Yv2
@param array $Format
@return array
195860
public function drawBezier($X1, $Y1, $X2, $Y2, $Xv1, $Yv1, $Xv2, $Yv2, 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;
        $ShowC = isset($Format["ShowControl"]) ? $Format["ShowControl"] : false;
        $Segments = isset($Format["Segments"]) ? $Format["Segments"] : null;
        $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : null;
        $NoDraw = isset($Format["NoDraw"]) ? $Format["NoDraw"] : false;
        $PathOnly = isset($Format["PathOnly"]) ? $Format["PathOnly"] : false;
        $Weight = isset($Format["Weight"]) ? $Format["Weight"] : null;
        $DrawArrow = isset($Format["DrawArrow"]) ? $Format["DrawArrow"] : false;
        $ArrowSize = isset($Format["ArrowSize"]) ? $Format["ArrowSize"] : 10;
        $ArrowRatio = isset($Format["ArrowRatio"]) ? $Format["ArrowRatio"] : .5;
        $ArrowTwoHeads = isset($Format["ArrowTwoHeads"]) ? $Format["ArrowTwoHeads"] : false;

        if ($Segments == null) {
            $Length = $this->getLength($X1, $Y1, $X2, $Y2);
            $Precision = ($Length * 125) / 1000;
        } else {
            $Precision = $Segments;
        }
        $P[0]["X"] = $X1;
        $P[0]["Y"] = $Y1;
        $P[1]["X"] = $Xv1;
        $P[1]["Y"] = $Yv1;
        $P[2]["X"] = $Xv2;
        $P[2]["Y"] = $Yv2;
        $P[3]["X"] = $X2;
        $P[3]["Y"] = $Y2;

        /* Compute the bezier points */
        $Q = [];
        $ID = 0;
        for ($i = 0; $i <= $Precision; $i = $i + 1) {
            $u = $i / $Precision;

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

            for ($j = 0; $j <= 3; $j++) {
                if (!isset($Q[$ID])) {
                    $Q[$ID] = [];
                }
                if (!isset($Q[$ID]["X"])) {
                    $Q[$ID]["X"] = 0;
                }
                if (!isset($Q[$ID]["Y"])) {
                    $Q[$ID]["Y"] = 0;
                }

                $Q[$ID]["X"] = $Q[$ID]["X"] + $P[$j]["X"] * $C[$j];
                $Q[$ID]["Y"] = $Q[$ID]["Y"] + $P[$j]["Y"] * $C[$j];
            }
            $ID++;
        }
        $Q[$ID]["X"] = $X2;
        $Q[$ID]["Y"] = $Y2;

        if (!$NoDraw) {
            /* Display the control points */
            if ($ShowC && !$PathOnly) {
                $Xv1 = floor($Xv1);
                $Yv1 = floor($Yv1);
                $Xv2 = floor($Xv2);
                $Yv2 = floor($Yv2);

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

                $MyMarkerSettings = [
                    "R" => 255,
                    "G" => 0,
                    "B" => 0,
                    "BorderR" => 255,
                    "BorderB" => 255,
                    "BorderG" => 255,
                    "Size" => 4
                ];
                $this->drawRectangleMarker($Xv1, $Yv1, $MyMarkerSettings);
                $this->drawText($Xv1 + 4, $Yv1, "v1");
                $MyMarkerSettings = [
                    "R" => 0,
                    "G" => 0,
                    "B" => 255,
                    "BorderR" => 255,
                    "BorderB" => 255,
                    "BorderG" => 255,
                    "Size" => 4
                ];
                $this->drawRectangleMarker($Xv2, $Yv2, $MyMarkerSettings);
                $this->drawText($Xv2 + 4, $Yv2, "v2");
            }

            /* Draw the bezier */
            $LastX = null;
            $LastY = null;
            $Cpt = null;
            $Mode = null;
            $ArrowS = [];
            foreach ($Q as $Point) {
                $X = $Point["X"];
                $Y = $Point["Y"];

                /* Get the first segment */
                if (!count($ArrowS) && $LastX != null && $LastY != null) {
                    $ArrowS["X2"] = $LastX;
                    $ArrowS["Y2"] = $LastY;
                    $ArrowS["X1"] = $X;
                    $ArrowS["Y1"] = $Y;
                }

                if ($LastX != null && $LastY != null && !$PathOnly) {
                    list($Cpt, $Mode) = $this->drawLine(
                        $LastX,
                        $LastY,
                        $X,
                        $Y,
                        [
                            "R" => $R,
                            "G" => $G,
                            "B" => $B,
                            "Alpha" => $Alpha,
                            "Ticks" => $Ticks,
                            "Cpt" => $Cpt,
                            "Mode" => $Mode,
                            "Weight" => $Weight
                        ]
                    );
                }
                /* Get the last segment */
                $ArrowE["X1"] = $LastX;
                $ArrowE["Y1"] = $LastY;
                $ArrowE["X2"] = $X;
                $ArrowE["Y2"] = $Y;

                $LastX = $X;
                $LastY = $Y;
            }

            if ($DrawArrow && !$PathOnly) {
                $ArrowSettings = [
                    "FillR" => $R,
                    "FillG" => $G,
                    "FillB" => $B,
                    "Alpha" => $Alpha,
                    "Size" => $ArrowSize,
                    "Ratio" => $ArrowRatio
                ];
                if ($ArrowTwoHeads) {
                    $this->drawArrow($ArrowS["X1"], $ArrowS["Y1"], $ArrowS["X2"], $ArrowS["Y2"], $ArrowSettings);
                }
                $this->drawArrow($ArrowE["X1"], $ArrowE["Y1"], $ArrowE["X2"], $ArrowE["Y2"], $ArrowSettings);
            }
        }
        return $Q;
    }
459743
public function drawXThresholdArea($Value1, $Value2, array $Format = [])
    {
        $R = isset($Format["R"]) ? $Format["R"] : 255;
        $G = isset($Format["G"]) ? $Format["G"] : 0;
        $B = isset($Format["B"]) ? $Format["B"] : 0;
        $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 20;
        $Border = isset($Format["Border"]) ? $Format["Border"] : true;
        $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : $R;
        $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : $G;
        $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : $B;
        $BorderAlpha = isset($Format["BorderAlpha"]) ? $Format["BorderAlpha"] : $Alpha + 20;
        $BorderTicks = isset($Format["BorderTicks"]) ? $Format["BorderTicks"] : 2;
        $AreaName = isset($Format["AreaName"]) ? $Format["AreaName"] : null;
        $NameAngle = isset($Format["NameAngle"]) ? $Format["NameAngle"] : ZONE_NAME_ANGLE_AUTO;
        $NameR = isset($Format["NameR"]) ? $Format["NameR"] : 255;
        $NameG = isset($Format["NameG"]) ? $Format["NameG"] : 255;
        $NameB = isset($Format["NameB"]) ? $Format["NameB"] : 255;
        $NameAlpha = isset($Format["NameAlpha"]) ? $Format["NameAlpha"] : 100;
        $DisableShadowOnArea = isset($Format["DisableShadowOnArea"]) ? $Format["DisableShadowOnArea"] : true;

        $RestoreShadow = $this->Shadow;
        if ($DisableShadowOnArea && $this->Shadow) {
            $this->Shadow = false;
        }

        if ($BorderAlpha > 100) {
            $BorderAlpha = 100;
        }

        $Data = $this->DataSet->getData();
        $XScale = $this->scaleGetXSettings();

        if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) {
            $XStep = (($this->GraphAreaX2 - $this->GraphAreaX1) - $XScale[0] * 2) / $XScale[1];
            $XPos1 = $this->GraphAreaX1 + $XScale[0] + $XStep * $Value1;
            $XPos2 = $this->GraphAreaX1 + $XScale[0] + $XStep * $Value2;
            $YPos1 = $this->GraphAreaY1 + $Data["YMargin"];
            $YPos2 = $this->GraphAreaY2 - $Data["YMargin"];

            if ($XPos1 < $this->GraphAreaX1 + $XScale[0]) {
                $XPos1 = $this->GraphAreaX1 + $XScale[0];
            }
            if ($XPos1 > $this->GraphAreaX2 - $XScale[0]) {
                $XPos1 = $this->GraphAreaX2 - $XScale[0];
            }
            if ($XPos2 < $this->GraphAreaX1 + $XScale[0]) {
                $XPos2 = $this->GraphAreaX1 + $XScale[0];
            }
            if ($XPos2 > $this->GraphAreaX2 - $XScale[0]) {
                $XPos2 = $this->GraphAreaX2 - $XScale[0];
            }

            $this->drawFilledRectangle(
                $XPos1,
                $YPos1,
                $XPos2,
                $YPos2,
                ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha]
            );

            if ($Border) {
                $this->drawLine(
                    $XPos1,
                    $YPos1,
                    $XPos1,
                    $YPos2,
                    [
                        "R" => $BorderR,
                        "G" => $BorderG,
                        "B" => $BorderB,
                        "Alpha" => $BorderAlpha,
                        "Ticks" => $BorderTicks
                    ]
                );
                $this->drawLine(
                    $XPos2,
                    $YPos1,
                    $XPos2,
                    $YPos2,
                    [
                        "R" => $BorderR,
                        "G" => $BorderG,
                        "B" => $BorderB,
                        "Alpha" => $BorderAlpha,
                        "Ticks" => $BorderTicks
                    ]
                );
            }

            if ($AreaName != null) {
                $XPos = ($XPos2 - $XPos1) / 2 + $XPos1;
                $YPos = ($YPos2 - $YPos1) / 2 + $YPos1;

                if ($NameAngle == ZONE_NAME_ANGLE_AUTO) {
                    $TxtPos = $this->getTextBox(
                        $XPos,
                        $YPos,
                        $this->FontName,
                        $this->FontSize,
                        0,
                        $AreaName
                    );
                    $TxtWidth = $TxtPos[1]["X"] - $TxtPos[0]["X"];
                    $NameAngle = 90;
                    if (abs($XPos2 - $XPos1) > $TxtWidth) {
                        $NameAngle = 0;
                    }
                }
                $this->Shadow = $RestoreShadow;
                $this->drawText(
                    $XPos,
                    $YPos,
                    $AreaName,
                    [
                        "R" => $NameR,
                        "G" => $NameG,
                        "B" => $NameB,
                        "Alpha" => $NameAlpha,
                        "Angle" => $NameAngle,
                        "Align" => TEXT_ALIGN_MIDDLEMIDDLE
                    ]
                );
                if ($DisableShadowOnArea) {
                    $this->Shadow = false;
                }
            }

            $this->Shadow = $RestoreShadow;
            return ["X1" => $XPos1, "X2" => $XPos2];
        } elseif ($Data["Orientation"] == SCALE_POS_TOPBOTTOM) {
            $XStep = (($this->GraphAreaY2 - $this->GraphAreaY1) - $XScale[0] * 2) / $XScale[1];
            $XPos1 = $this->GraphAreaY1 + $XScale[0] + $XStep * $Value1;
            $XPos2 = $this->GraphAreaY1 + $XScale[0] + $XStep * $Value2;
            $YPos1 = $this->GraphAreaX1 + $Data["YMargin"];
            $YPos2 = $this->GraphAreaX2 - $Data["YMargin"];

            if ($XPos1 < $this->GraphAreaY1 + $XScale[0]) {
                $XPos1 = $this->GraphAreaY1 + $XScale[0];
            }
            if ($XPos1 > $this->GraphAreaY2 - $XScale[0]) {
                $XPos1 = $this->GraphAreaY2 - $XScale[0];
            }
            if ($XPos2 < $this->GraphAreaY1 + $XScale[0]) {
                $XPos2 = $this->GraphAreaY1 + $XScale[0];
            }
            if ($XPos2 > $this->GraphAreaY2 - $XScale[0]) {
                $XPos2 = $this->GraphAreaY2 - $XScale[0];
            }

            $this->drawFilledRectangle(
                $YPos1,
                $XPos1,
                $YPos2,
                $XPos2,
                ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha]
            );

            if ($Border) {
                $this->drawLine(
                    $YPos1,
                    $XPos1,
                    $YPos2,
                    $XPos1,
                    [
                        "R" => $BorderR,
                        "G" => $BorderG,
                        "B" => $BorderB,
                        "Alpha" => $BorderAlpha,
                        "Ticks" => $BorderTicks
                    ]
                );
                $this->drawLine(
                    $YPos1,
                    $XPos2,
                    $YPos2,
                    $XPos2,
                    [
                        "R" => $BorderR,
                        "G" => $BorderG,
                        "B" => $BorderB,
                        "Alpha" => $BorderAlpha,
                        "Ticks" => $BorderTicks
                    ]
                );
            }

            if ($AreaName != null) {
                $XPos = ($XPos2 - $XPos1) / 2 + $XPos1;
                $YPos = ($YPos2 - $YPos1) / 2 + $YPos1;

                $this->Shadow = $RestoreShadow;
                $this->drawText(
                    $YPos,
                    $XPos,
                    $AreaName,
                    [
                        "R" => $NameR,
                        "G" => $NameG,
                        "B" => $NameB,
                        "Alpha" => $NameAlpha,
                        "Angle" => 0,
                        "Align" => TEXT_ALIGN_MIDDLEMIDDLE
                    ]
                );
                if ($DisableShadowOnArea) {
                    $this->Shadow = false;
                }
            }

            $this->Shadow = $RestoreShadow;
            return ["X1" => $XPos1, "X2" => $XPos2];
        }
    }
435292
def pt_on_bezier_curve(P=[(0.0, 0.0)], t=0.5):
    '''
    '''
    assert isinstance(P, list)
    assert len(P) > 0
    for p in P:
        assert isinstance(p, tuple)
        for i in p:
            assert len(p) > 1
            assert isinstance(i, float)
    assert isinstance(t, float)
    assert 0 <= t <= 1
    
    O = len(P) - 1 # Order of curve

    # Recurse down the orders calculating the next set of control points until
    #   there is only one left, which is the point we want.
    Q = P
    while O > 0:
        Q = [pt_between_pts(Q[l], Q[l+1], t) for l in range(O)]
        O -= 1
    
    assert len(Q) == 1
    return Q[0]
367057
public function drawAntialiasPixel($X, $Y, 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;

        if ($X < 0 || $Y < 0 || $X >= $this->XSize || $Y >= $this->YSize) {
            return -1;
        }

        if ($R < 0) {
            $R = 0;
        } if ($R > 255) {
            $R = 255;
        }
        if ($G < 0) {
            $G = 0;
        } if ($G > 255) {
            $G = 255;
        }
        if ($B < 0) {
            $B = 0;
        } if ($B > 255) {
            $B = 255;
        }

        if (!$this->Antialias) {
            if ($this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0) {
                $ShadowColor = $this->allocateColor(
                    $this->Picture,
                    $this->ShadowR,
                    $this->ShadowG,
                    $this->ShadowB,
                    $this->Shadowa
                );
                imagesetpixel($this->Picture, $X + $this->ShadowX, $Y + $this->ShadowY, $ShadowColor);
            }

            $PlotColor = $this->allocateColor($this->Picture, $R, $G, $B, $Alpha);
            imagesetpixel($this->Picture, $X, $Y, $PlotColor);

            return 0;
        }

        $Xi = floor($X);
        $Yi = floor($Y);

        if ($Xi == $X && $Yi == $Y) {
            if ($Alpha == 100) {
                $this->drawAlphaPixel($X, $Y, 100, $R, $G, $B);
            } else {
                $this->drawAlphaPixel($X, $Y, $Alpha, $R, $G, $B);
            }
        } else {
            $Alpha1 = (((1 - ($X - floor($X))) * (1 - ($Y - floor($Y))) * 100) / 100) * $Alpha;
            if ($Alpha1 > $this->AntialiasQuality) {
                $this->drawAlphaPixel($Xi, $Yi, $Alpha1, $R, $G, $B);
            }

            $Alpha2 = ((($X - floor($X)) * (1 - ($Y - floor($Y))) * 100) / 100) * $Alpha;
            if ($Alpha2 > $this->AntialiasQuality) {
                $this->drawAlphaPixel($Xi + 1, $Yi, $Alpha2, $R, $G, $B);
            }

            $Alpha3 = (((1 - ($X - floor($X))) * ($Y - floor($Y)) * 100) / 100) * $Alpha;
            if ($Alpha3 > $this->AntialiasQuality) {
                $this->drawAlphaPixel($Xi, $Yi + 1, $Alpha3, $R, $G, $B);
            }

            $Alpha4 = ((($X - floor($X)) * ($Y - floor($Y)) * 100) / 100) * $Alpha;
            if ($Alpha4 > $this->AntialiasQuality) {
                $this->drawAlphaPixel($Xi + 1, $Yi + 1, $Alpha4, $R, $G, $B);
            }
        }
    }
515354
public function crop($x1, $y1, $x2, $y2)
    {
        if ($x2 < $x1) {
            list($x1, $x2) = array($x2, $x1);
        }
        if ($y2 < $y1) {
            list($y1, $y2) = array($y2, $y1);
        }

        $crop_width = $x2 - $x1;
        $crop_height = $y2 - $y1;

        $new = imagecreatetruecolor($crop_width, $crop_height);

        if (empty($new)) {
            throw new UnexpectedValueException('Failed to create an image identifier');
        }

        imagealphablending($new, false);
        imagesavealpha($new, true);

        if (!imagecopyresampled($new, $this->image, 0, 0, $x1, $y1, $crop_width, $crop_height, $crop_width, $crop_height)) {
            throw new UnexpectedValueException('Failed to copy and resize part of an image with resampling');
        }

        $this->image = $new;
        $this->width = $crop_width;
        $this->height = $crop_height;

        return $this;
    }
376455
def line_xy(x1, y1, x2, y2, draw)
      use_cairo do |cc|
        cc.move_to(x1, y1)
        cc.line_to(x2, y2)
        cc.fancy_stroke(draw)
      end
    end
990959
function line($x1, $y1, $x2, $y2) {
    $this->objects[$this->currentContents]['c'] .= sprintf("\n%.3F %.3F m %.3F %.3F l S", $x1, $y1, $x2, $y2);
  }
808123
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;
    }
890984
public function drawAreaMirror($X, $Y, $Width, $Height, array $Format = [])
    {
        $StartAlpha = isset($Format["StartAlpha"]) ? $Format["StartAlpha"] : 80;
        $EndAlpha = isset($Format["EndAlpha"]) ? $Format["EndAlpha"] : 0;

        $AlphaStep = ($StartAlpha - $EndAlpha) / $Height;

        $Picture = imagecreatetruecolor($this->XSize, $this->YSize);
        imagecopy($Picture, $this->Picture, 0, 0, 0, 0, $this->XSize, $this->YSize);

        for ($i = 1; $i <= $Height; $i++) {
            if ($Y + ($i - 1) < $this->YSize && $Y - $i > 0) {
                imagecopymerge(
                    $Picture,
                    $this->Picture,
                    $X,
                    $Y + ($i - 1),
                    $X,
                    $Y - $i,
                    $Width,
                    1,
                    $StartAlpha - $AlphaStep * $i
                );
            }
        }

        imagecopy($this->Picture, $Picture, 0, 0, 0, 0, $this->XSize, $this->YSize);
    }
977180
public /*internal*/ function draw($im, $x1, $y1, $x2, $y2) {
        $x = 0;
        $y = 0;

        $fontDimension = $this->font->getDimension();

        if ($this->position === self::POSITION_TOP || $this->position === self::POSITION_BOTTOM) {
            if ($this->position === self::POSITION_TOP) {
                $y = $y1 - $this->spacing - $fontDimension[1];
            } elseif ($this->position === self::POSITION_BOTTOM) {
                $y = $y2 + $this->spacing;
            }

            if ($this->alignment === self::ALIGN_CENTER) {
                $x = ($x2 - $x1) / 2 + $x1 - $fontDimension[0] / 2 + $this->offset;
            } elseif ($this->alignment === self::ALIGN_LEFT)  {
                $x = $x1 + $this->offset;
            } else {
                $x = $x2 + $this->offset - $fontDimension[0];
            }
        } else {
            if ($this->position === self::POSITION_LEFT) {
                $x = $x1 - $this->spacing - $fontDimension[0];
            } elseif ($this->position === self::POSITION_RIGHT) {
                $x = $x2 + $this->spacing;
            }

            if ($this->alignment === self::ALIGN_CENTER) {
                $y = ($y2 - $y1) / 2 + $y1 - $fontDimension[1] / 2 + $this->offset;
            } elseif ($this->alignment === self::ALIGN_TOP)  {
                $y = $y1 + $this->offset;
            } else {
                $y = $y2 + $this->offset - $fontDimension[1];
            }
        }

        $this->font->setText($this->text);
        $this->font->draw($im, $x, $y);
    }
963715
public function drawArrowLabel($X1, $Y1, $Text, array $Format = [])
    {
        $FillR = isset($Format["FillR"]) ? $Format["FillR"] : 0;
        $FillG = isset($Format["FillG"]) ? $Format["FillG"] : 0;
        $FillB = isset($Format["FillB"]) ? $Format["FillB"] : 0;
        $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : $FillR;
        $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : $FillG;
        $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : $FillB;
        $FontName = isset($Format["FontName"]) ? $this->loadFont($Format["FontName"], 'fonts') : $this->FontName;
        $FontSize = isset($Format["FontSize"]) ? $Format["FontSize"] : $this->FontSize;
        $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100;
        $Length = isset($Format["Length"]) ? $Format["Length"] : 50;
        $Angle = isset($Format["Angle"]) ? $Format["Angle"] : 315;
        $Size = isset($Format["Size"]) ? $Format["Size"] : 10;
        $Position = isset($Format["Position"]) ? $Format["Position"] : POSITION_TOP;
        $RoundPos = isset($Format["RoundPos"]) ? $Format["RoundPos"] : false;
        $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : null;

        $Angle = $Angle % 360;

        $X2 = sin(($Angle + 180) * PI / 180) * $Length + $X1;
        $Y2 = cos(($Angle + 180) * PI / 180) * $Length + $Y1;

        if ($RoundPos && $Angle > 0 && $Angle < 180) {
            $Y2 = ceil($Y2);
        }
        if ($RoundPos && $Angle > 180) {
            $Y2 = floor($Y2);
        }

        $this->drawArrow($X2, $Y2, $X1, $Y1, $Format);

        $Size = imagettfbbox($FontSize, 0, $FontName, $Text);
        $TxtWidth = max(abs($Size[2] - $Size[0]), abs($Size[0] - $Size[6]));

        if ($Angle > 0 && $Angle < 180) {
            $this->drawLine(
                $X2,
                $Y2,
                $X2 - $TxtWidth,
                $Y2,
                ["R" => $BorderR, "G" => $BorderG, "B" => $BorderB, "Alpha" => $Alpha, "Ticks" => $Ticks]
            );
            if ($Position == POSITION_TOP) {
                $this->drawText(
                    $X2,
                    $Y2 - 2,
                    $Text,
                    [
                        "R" => $BorderR,
                        "G" => $BorderG,
                        "B" => $BorderB,
                        "Alpha" => $Alpha,
                        "Align" => TEXT_ALIGN_BOTTOMRIGHT
                    ]
                );
            } else {
                $this->drawText(
                    $X2,
                    $Y2 + 4,
                    $Text,
                    [
                        "R" => $BorderR,
                        "G" => $BorderG,
                        "B" => $BorderB,
                        "Alpha" => $Alpha,
                        "Align" => TEXT_ALIGN_TOPRIGHT
                    ]
                );
            }
        } else {
            $this->drawLine(
                $X2,
                $Y2,
                $X2 + $TxtWidth,
                $Y2,
                ["R" => $BorderR, "G" => $BorderG, "B" => $BorderB, "Alpha" => $Alpha, "Ticks" => $Ticks]
            );
            if ($Position == POSITION_TOP) {
                $this->drawText(
                    $X2,
                    $Y2 - 2,
                    $Text,
                    ["R" => $BorderR, "G" => $BorderG, "B" => $BorderB, "Alpha" => $Alpha]
                );
            } else {
                $this->drawText(
                    $X2,
                    $Y2 + 4,
                    $Text,
                    [
                        "R" => $BorderR,
                        "G" => $BorderG,
                        "B" => $BorderB,
                        "Alpha" => $Alpha,
                        "Align" => TEXT_ALIGN_TOPLEFT
                    ]
                );
            }
        }
    }
1026730
public function drawScatterBestFit(array $Format = [])
    {
        $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : 0;

        $Data = $this->pDataObject->getData();

        foreach ($Data["ScatterSeries"] as $Key => $Series) {
            if ($Series["isDrawable"] == true) {
                $SerieX = $Series["X"];
                $SerieXAxis = $Data["Series"][$SerieX]["Axis"];
                $SerieY = $Series["Y"];
                $SerieYAxis = $Data["Series"][$SerieY]["Axis"];

                $Color = [
                    "R" => $Series["Color"]["R"],
                    "G" => $Series["Color"]["G"],
                    "B" => $Series["Color"]["B"],
                    "Alpha" => $Series["Color"]["Alpha"]
                ];
                $Color["Ticks"] = $Ticks;

                $PosArrayX = $Data["Series"][$Series["X"]]["Data"];
                $PosArrayY = $Data["Series"][$Series["Y"]]["Data"];

                $Sxy = 0;
                $Sx = 0;
                $Sy = 0;
                $Sxx = 0;
                foreach ($PosArrayX as $Key => $Value) {
                    $X = $Value;
                    $Y = $PosArrayY[$Key];

                    $Sxy = $Sxy + $X * $Y;
                    $Sx = $Sx + $X;
                    $Sy = $Sy + $Y;
                    $Sxx = $Sxx + $X * $X;
                }

                $n = count($PosArrayX);

                if ((($n * $Sxx) == ($Sx * $Sx))) {
                    $X1 = $this->getPosArray($Data["Axis"][$SerieXAxis]["ScaleMin"], $SerieXAxis);
                    $X2 = $X1;
                    $Y1 = $this->pChartObject->GraphAreaY1;
                    $Y2 = $this->pChartObject->GraphAreaY2;
                } else {
                    $M = (($n * $Sxy) - ($Sx * $Sy)) / (($n * $Sxx) - ($Sx * $Sx));
                    $B = (($Sy) - ($M * $Sx)) / ($n);

                    $X1 = $this->getPosArray($Data["Axis"][$SerieXAxis]["ScaleMin"], $SerieXAxis);
                    $Y1 = $this->getPosArray($M * $Data["Axis"][$SerieXAxis]["ScaleMin"] + $B, $SerieYAxis);
                    $X2 = $this->getPosArray($Data["Axis"][$SerieXAxis]["ScaleMax"], $SerieXAxis);
                    $Y2 = $this->getPosArray($M * $Data["Axis"][$SerieXAxis]["ScaleMax"] + $B, $SerieYAxis);

                    $RealM = -($Y2 - $Y1) / ($X2 - $X1);

                    if ($Y1 < $this->pChartObject->GraphAreaY1) {
                        $X1 = $X1 + ($this->pChartObject->GraphAreaY1 - $Y1 / $RealM);
                        $Y1 = $this->pChartObject->GraphAreaY1;
                    }
                    if ($Y1 > $this->pChartObject->GraphAreaY2) {
                        $X1 = $X1 + ($Y1 - $this->pChartObject->GraphAreaY2) / $RealM;
                        $Y1 = $this->pChartObject->GraphAreaY2;
                    }
                    if ($Y2 < $this->pChartObject->GraphAreaY1) {
                        $X2 = $X2 - ($this->pChartObject->GraphAreaY1 - $Y2) / $RealM;
                        $Y2 = $this->pChartObject->GraphAreaY1;
                    }
                    if ($Y2 > $this->pChartObject->GraphAreaY2) {
                        $X2 = $X2 - ($Y2 - $this->pChartObject->GraphAreaY2) / $RealM;
                        $Y2 = $this->pChartObject->GraphAreaY2;
                    }
                }

                $this->pChartObject->drawLine($X1, $Y1, $X2, $Y2, $Color);
            }
        }
    }
638655
void bezierTo(Point2D controlPoint1, Point2D controlPoint2, Point2D endPoint) {
		m_impl.bezierTo(controlPoint1, controlPoint2, endPoint);
	}
159889
function curve( $x0, $y0, $x1, $y1, $x2, $y2, $x3, $y3 )
    {
        // in the current line style, draw a bezier curve from (x0,y0) to (x3,y3) using the other two points
        // as the control points for the curve.
        $this->objects[$this->currentContents]['c'].="\n".sprintf('%.3F',$x0).' '.sprintf('%.3F',$y0).' m '.sprintf('%.3F',$x1).' '.sprintf('%.3F',$y1);
        $this->objects[$this->currentContents]['c'].= ' '.sprintf('%.3F',$x2).' '.sprintf('%.3F',$y2).' '.sprintf('%.3F',$x3).' '.sprintf('%.3F',$y3).' c S';
    }
461710
public function drawContour($Threshold, 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;
        $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : 3;
        $Padding = isset($Format["Padding"]) ? $Format["Padding"] : 0;

        $X0 = $this->pChartObject->GraphAreaX1;
        $Y0 = $this->pChartObject->GraphAreaY1;
        $XSize = ($this->pChartObject->GraphAreaX2 - $this->pChartObject->GraphAreaX1) / ($this->GridSizeX + 1);
        $YSize = ($this->pChartObject->GraphAreaY2 - $this->pChartObject->GraphAreaY1) / ($this->GridSizeY + 1);

        $Color = ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha, "Ticks" => $Ticks];

        for ($X = 0; $X <= $this->GridSizeX; $X++) {
            for ($Y = 0; $Y <= $this->GridSizeY; $Y++) {
                $Value = $this->Points[$X][$Y];

                if ($Value != UNKNOWN && $Value != IGNORED && $Value >= $Threshold) {
                    $X1 = floor($X0 + $X * $XSize) + $Padding;
                    $Y1 = floor($Y0 + $Y * $YSize) + $Padding;
                    $X2 = floor($X0 + $X * $XSize + $XSize);
                    $Y2 = floor($Y0 + $Y * $YSize + $YSize);

                    if ($X > 0 && $this->Points[$X - 1][$Y] != UNKNOWN
                        && $this->Points[$X - 1][$Y] != IGNORED
                        && $this->Points[$X - 1][$Y] < $Threshold
                    ) {
                        $this->pChartObject->drawLine($X1, $Y1, $X1, $Y2, $Color);
                    }
                    if ($Y > 0 && $this->Points[$X][$Y - 1] != UNKNOWN
                        && $this->Points[$X][$Y - 1] != IGNORED
                        && $this->Points[$X][$Y - 1] < $Threshold
                    ) {
                        $this->pChartObject->drawLine($X1, $Y1, $X2, $Y1, $Color);
                    }
                    if ($X < $this->GridSizeX
                        && $this->Points[$X + 1][$Y] != UNKNOWN
                        && $this->Points[$X + 1][$Y] != IGNORED
                        && $this->Points[$X + 1][$Y] < $Threshold
                    ) {
                        $this->pChartObject->drawLine($X2, $Y1, $X2, $Y2, $Color);
                    }
                    if ($Y < $this->GridSizeY
                        && $this->Points[$X][$Y + 1] != UNKNOWN
                        && $this->Points[$X][$Y + 1] != IGNORED
                        && $this->Points[$X][$Y + 1] < $Threshold
                    ) {
                        $this->pChartObject->drawLine($X1, $Y2, $X2, $Y2, $Color);
                    }
                }
            }
        }
    }
382821
public function drawGradientArea($X1, $Y1, $X2, $Y2, $Direction, array $Format = [])
    {
        $StartR = isset($Format["StartR"]) ? $Format["StartR"] : 90;
        $StartG = isset($Format["StartG"]) ? $Format["StartG"] : 90;
        $StartB = isset($Format["StartB"]) ? $Format["StartB"] : 90;
        $EndR = isset($Format["EndR"]) ? $Format["EndR"] : 0;
        $EndG = isset($Format["EndG"]) ? $Format["EndG"] : 0;
        $EndB = isset($Format["EndB"]) ? $Format["EndB"] : 0;
        $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100;
        $Levels = isset($Format["Levels"]) ? $Format["Levels"] : null;

        $Shadow = $this->Shadow;
        $this->Shadow = false;

        if ($StartR == $EndR && $StartG == $EndG && $StartB == $EndB) {
            $this->drawFilledRectangle(
                $X1,
                $Y1,
                $X2,
                $Y2,
                ["R" => $StartR, "G" => $StartG, "B" => $StartB, "Alpha" => $Alpha]
            );
            return 0;
        }

        if ($Levels != null) {
            $EndR = $StartR + $Levels;
            $EndG = $StartG + $Levels;
            $EndB = $StartB + $Levels;
        }

        if ($X1 > $X2) {
            list($X1, $X2) = [$X2, $X1];
        }
        if ($Y1 > $Y2) {
            list($Y1, $Y2) = [$Y2, $Y1];
        }

        if ($Direction == DIRECTION_VERTICAL) {
            $Width = abs($Y2 - $Y1);
        }
        if ($Direction == DIRECTION_HORIZONTAL) {
            $Width = abs($X2 - $X1);
        }

        $Step = max(abs($EndR - $StartR), abs($EndG - $StartG), abs($EndB - $StartB));
        $StepSize = $Width / $Step;
        $RStep = ($EndR - $StartR) / $Step;
        $GStep = ($EndG - $StartG) / $Step;
        $BStep = ($EndB - $StartB) / $Step;

        $R = $StartR;
        $G = $StartG;
        $B = $StartB;
        switch ($Direction) {
            case DIRECTION_VERTICAL:
                $StartY = $Y1;
                $EndY = floor($Y2) + 1;
                $LastY2 = $StartY;
                for ($i = 0; $i <= $Step; $i++) {
                    $Y2 = floor($StartY + ($i * $StepSize));

                    if ($Y2 > $EndY) {
                        $Y2 = $EndY;
                    }
                    if (($Y1 != $Y2 && $Y1 < $Y2) || $Y2 == $EndY) {
                        $Color = ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha];
                        $this->drawFilledRectangle($X1, $Y1, $X2, $Y2, $Color);
                        $LastY2 = max($LastY2, $Y2);
                        $Y1 = $Y2 + 1;
                    }
                    $R = $R + $RStep;
                    $G = $G + $GStep;
                    $B = $B + $BStep;
                }
                if ($LastY2 < $EndY && isset($Color)) {
                    for ($i = $LastY2 + 1; $i <= $EndY; $i++) {
                        $this->drawLine($X1, $i, $X2, $i, $Color);
                    }
                }
                break;

            case DIRECTION_HORIZONTAL:
                $StartX = $X1;
                $EndX = $X2;
                for ($i = 0; $i <= $Step; $i++) {
                    $X2 = floor($StartX + ($i * $StepSize));

                    if ($X2 > $EndX) {
                        $X2 = $EndX;
                    }
                    if (($X1 != $X2 && $X1 < $X2) || $X2 == $EndX) {
                        $Color = ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha];
                        $this->drawFilledRectangle($X1, $Y1, $X2, $Y2, $Color);
                        $X1 = $X2 + 1;
                    }
                    $R = $R + $RStep;
                    $G = $G + $GStep;
                    $B = $B + $BStep;
                }
                if ($X2 < $EndX && isset($Color)) {
                    $this->drawFilledRectangle($X2, $Y1, $EndX, $Y2, $Color);
                }
                break;
        }

        $this->Shadow = $Shadow;
    }
1008823
public function drawZoneChart($SerieA, $SerieB, array $Format = [])
    {
        $AxisID = isset($Format["AxisID"]) ? $Format["AxisID"] : 0;
        $LineR = isset($Format["LineR"]) ? $Format["LineR"] : 150;
        $LineG = isset($Format["LineG"]) ? $Format["LineG"] : 150;
        $LineB = isset($Format["LineB"]) ? $Format["LineB"] : 150;
        $LineAlpha = isset($Format["LineAlpha"]) ? $Format["LineAlpha"] : 50;
        $LineTicks = isset($Format["LineTicks"]) ? $Format["LineTicks"] : 1;
        $AreaR = isset($Format["AreaR"]) ? $Format["AreaR"] : 150;
        $AreaG = isset($Format["AreaG"]) ? $Format["AreaG"] : 150;
        $AreaB = isset($Format["AreaB"]) ? $Format["AreaB"] : 150;
        $AreaAlpha = isset($Format["AreaAlpha"]) ? $Format["AreaAlpha"] : 5;

        $this->LastChartLayout = CHART_LAST_LAYOUT_REGULAR;

        $Data = $this->DataSet->getData();
        if (!isset($Data["Series"][$SerieA]["Data"])
            || !isset($Data["Series"][$SerieB]["Data"])
        ) {
            return 0;
        }
        $SerieAData = $Data["Series"][$SerieA]["Data"];
        $SerieBData = $Data["Series"][$SerieB]["Data"];

        list($XMargin, $XDivs) = $this->scaleGetXSettings();

        $Mode = $Data["Axis"][$AxisID]["Display"];
        $Format = $Data["Axis"][$AxisID]["Format"];

        $PosArrayA = $this->scaleComputeY($SerieAData, ["AxisID" => $AxisID]);
        $PosArrayB = $this->scaleComputeY($SerieBData, ["AxisID" => $AxisID]);
        if (count($PosArrayA) != count($PosArrayB)) {
            return 0;
        }

        if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) {
            if ($XDivs == 0) {
                $XStep = ($this->GraphAreaX2 - $this->GraphAreaX1) / 4;
            } else {
                $XStep = ($this->GraphAreaX2 - $this->GraphAreaX1 - $XMargin * 2) / $XDivs;
            }
            $X = $this->GraphAreaX1 + $XMargin;
            $LastX = null;
            $LastY = null;

            $LastY1 = null;
            $LastY2 = null;
            $BoundsA = [];
            $BoundsB = [];
            foreach ($PosArrayA as $Key => $Y1) {
                $Y2 = $PosArrayB[$Key];

                $BoundsA[] = $X;
                $BoundsA[] = $Y1;
                $BoundsB[] = $X;
                $BoundsB[] = $Y2;

                $LastX = $X;
                $LastY1 = $Y1;
                $LastY2 = $Y2;

                $X = $X + $XStep;
            }
            $Bounds = array_merge($BoundsA, $this->reversePlots($BoundsB));
            $this->drawPolygonChart(
                $Bounds,
                [
                    "R" => $AreaR,
                    "G" => $AreaG,
                    "B" => $AreaB,
                    "Alpha" => $AreaAlpha
                ]
            );

            for ($i = 0; $i <= count($BoundsA) - 4; $i = $i + 2) {
                $this->drawLine(
                    $BoundsA[$i],
                    $BoundsA[$i + 1],
                    $BoundsA[$i + 2],
                    $BoundsA[$i + 3],
                    [
                        "R" => $LineR,
                        "G" => $LineG,
                        "B" => $LineB,
                        "Alpha" => $LineAlpha,
                        "Ticks" => $LineTicks
                    ]
                );
                $this->drawLine(
                    $BoundsB[$i],
                    $BoundsB[$i + 1],
                    $BoundsB[$i + 2],
                    $BoundsB[$i + 3],
                    [
                        "R" => $LineR,
                        "G" => $LineG,
                        "B" => $LineB,
                        "Alpha" => $LineAlpha,
                        "Ticks" => $LineTicks
                    ]
                );
            }
        } else {
            if ($XDivs == 0) {
                $YStep = ($this->GraphAreaY2 - $this->GraphAreaY1) / 4;
            } else {
                $YStep = ($this->GraphAreaY2 - $this->GraphAreaY1 - $XMargin * 2) / $XDivs;
            }
            $Y = $this->GraphAreaY1 + $XMargin;
            $LastX = null;
            $LastY = null;

            $LastX1 = null;
            $LastX2 = null;
            $BoundsA = [];
            $BoundsB = [];
            foreach ($PosArrayA as $Key => $X1) {
                $X2 = $PosArrayB[$Key];

                $BoundsA[] = $X1;
                $BoundsA[] = $Y;
                $BoundsB[] = $X2;
                $BoundsB[] = $Y;

                $LastY = $Y;
                $LastX1 = $X1;
                $LastX2 = $X2;

                $Y = $Y + $YStep;
            }
            $Bounds = array_merge($BoundsA, $this->reversePlots($BoundsB));
            $this->drawPolygonChart(
                $Bounds,
                ["R" => $AreaR, "G" => $AreaG, "B" => $AreaB, "Alpha" => $AreaAlpha]
            );

            for ($i = 0; $i <= count($BoundsA) - 4; $i = $i + 2) {
                $this->drawLine(
                    $BoundsA[$i],
                    $BoundsA[$i + 1],
                    $BoundsA[$i + 2],
                    $BoundsA[$i + 3],
                    [
                        "R" => $LineR,
                        "G" => $LineG,
                        "B" => $LineB,
                        "Alpha" => $LineAlpha,
                        "Ticks" => $LineTicks
                    ]
                );
                $this->drawLine(
                    $BoundsB[$i],
                    $BoundsB[$i + 1],
                    $BoundsB[$i + 2],
                    $BoundsB[$i + 3],
                    [
                        "R" => $LineR,
                        "G" => $LineG,
                        "B" => $LineB,
                        "Alpha" => $LineAlpha,
                        "Ticks" => $LineTicks
                    ]
                );
            }
        }
    }