You are here

pSurface.class.php in Visitors 7

Same filename and directory in other branches
  1. 7.2 pChart/class/pSurface.class.php

File

pChart/class/pSurface.class.php
View source
<?php

/*
    pSurface - class to draw surface 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.
*/
define("UNKNOWN", 0.123456789);
define("IGNORED", -1);
define("LABEL_POSITION_LEFT", 880001);
define("LABEL_POSITION_RIGHT", 880002);
define("LABEL_POSITION_TOP", 880003);
define("LABEL_POSITION_BOTTOM", 880004);

/* pStock class definition */
class pSurface {
  var $pChartObject;
  var $GridSizeX;
  var $GridSizeY;
  var $Points;

  /* Class creator */
  function pSurface($pChartObject) {
    $this->pChartObject = $pChartObject;
    $this->GridSize = 10;
    $this->Points = "";
  }

  /* Define the grid size and initialise the 2D matrix */
  function setGrid($XSize = 10, $YSize = 10) {
    for ($X = 0; $X <= $XSize; $X++) {
      for ($Y = 0; $Y <= $YSize; $Y++) {
        $this->Points[$X][$Y] = UNKNOWN;
      }
    }
    $this->GridSizeX = $XSize;
    $this->GridSizeY = $YSize;
  }

  /* Add a point on the grid */
  function addPoint($X, $Y, $Value, $Force = TRUE) {
    if ($X < 0 || $X > $this->GridSizeX) {
      return 0;
    }
    if ($Y < 0 || $Y > $this->GridSizeY) {
      return 0;
    }
    if ($this->Points[$X][$Y] == UNKNOWN || $Force) {
      $this->Points[$X][$Y] = $Value;
    }
    elseif ($this->Points[$X][$Y] == UNKNOWN) {
      $this->Points[$X][$Y] = $Value;
    }
    else {
      $this->Points[$X][$Y] = ($this->Points[$X][$Y] + $Value) / 2;
    }
  }

  /* Write the X labels */
  function writeXLabels($Format = "") {
    $R = isset($Format["R"]) ? $Format["R"] : $this->pChartObject->FontColorR;
    $G = isset($Format["G"]) ? $Format["G"] : $this->pChartObject->FontColorG;
    $B = isset($Format["B"]) ? $Format["B"] : $this->pChartObject->FontColorB;
    $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : $this->pChartObject->FontColorA;
    $Angle = isset($Format["Angle"]) ? $Format["Angle"] : 0;
    $Padding = isset($Format["Padding"]) ? $Format["Padding"] : 5;
    $Position = isset($Format["Position"]) ? $Format["Position"] : LABEL_POSITION_TOP;
    $Labels = isset($Format["Labels"]) ? $Format["Labels"] : NULL;
    $CountOffset = isset($Format["CountOffset"]) ? $Format["CountOffset"] : 0;
    if ($Labels != NULL && !is_array($Labels)) {
      $Label = $Labels;
      $Labels = "";
      $Labels[] = $Label;
    }
    $X0 = $this->pChartObject->GraphAreaX1;
    $XSize = ($this->pChartObject->GraphAreaX2 - $this->pChartObject->GraphAreaX1) / ($this->GridSizeX + 1);
    $Settings = array(
      "Angle" => $Angle,
      "R" => $R,
      "G" => $G,
      "B" => $B,
      "Alpha" => $Alpha,
    );
    if ($Position == LABEL_POSITION_TOP) {
      $YPos = $this->pChartObject->GraphAreaY1 - $Padding;
      if ($Angle == 0) {
        $Settings["Align"] = TEXT_ALIGN_BOTTOMMIDDLE;
      }
      if ($Angle != 0) {
        $Settings["Align"] = TEXT_ALIGN_MIDDLELEFT;
      }
    }
    elseif ($Position == LABEL_POSITION_BOTTOM) {
      $YPos = $this->pChartObject->GraphAreaY2 + $Padding;
      if ($Angle == 0) {
        $Settings["Align"] = TEXT_ALIGN_TOPMIDDLE;
      }
      if ($Angle != 0) {
        $Settings["Align"] = TEXT_ALIGN_MIDDLERIGHT;
      }
    }
    else {
      return -1;
    }
    for ($X = 0; $X <= $this->GridSizeX; $X++) {
      $XPos = floor($X0 + $X * $XSize + $XSize / 2);
      if ($Labels == NULL || !isset($Labels[$X])) {
        $Value = $X + $CountOffset;
      }
      else {
        $Value = $Labels[$X];
      }
      $this->pChartObject
        ->drawText($XPos, $YPos, $Value, $Settings);
    }
  }

  /* Write the Y labels */
  function writeYLabels($Format = "") {
    $R = isset($Format["R"]) ? $Format["R"] : $this->pChartObject->FontColorR;
    $G = isset($Format["G"]) ? $Format["G"] : $this->pChartObject->FontColorG;
    $B = isset($Format["B"]) ? $Format["B"] : $this->pChartObject->FontColorB;
    $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : $this->pChartObject->FontColorA;
    $Angle = isset($Format["Angle"]) ? $Format["Angle"] : 0;
    $Padding = isset($Format["Padding"]) ? $Format["Padding"] : 5;
    $Position = isset($Format["Position"]) ? $Format["Position"] : LABEL_POSITION_LEFT;
    $Labels = isset($Format["Labels"]) ? $Format["Labels"] : NULL;
    $CountOffset = isset($Format["CountOffset"]) ? $Format["CountOffset"] : 0;
    if ($Labels != NULL && !is_array($Labels)) {
      $Label = $Labels;
      $Labels = "";
      $Labels[] = $Label;
    }
    $Y0 = $this->pChartObject->GraphAreaY1;
    $YSize = ($this->pChartObject->GraphAreaY2 - $this->pChartObject->GraphAreaY1) / ($this->GridSizeY + 1);
    $Settings = array(
      "Angle" => $Angle,
      "R" => $R,
      "G" => $G,
      "B" => $B,
      "Alpha" => $Alpha,
    );
    if ($Position == LABEL_POSITION_LEFT) {
      $XPos = $this->pChartObject->GraphAreaX1 - $Padding;
      $Settings["Align"] = TEXT_ALIGN_MIDDLERIGHT;
    }
    elseif ($Position == LABEL_POSITION_RIGHT) {
      $XPos = $this->pChartObject->GraphAreaX2 + $Padding;
      $Settings["Align"] = TEXT_ALIGN_MIDDLELEFT;
    }
    else {
      return -1;
    }
    for ($Y = 0; $Y <= $this->GridSizeY; $Y++) {
      $YPos = floor($Y0 + $Y * $YSize + $YSize / 2);
      if ($Labels == NULL || !isset($Labels[$Y])) {
        $Value = $Y + $CountOffset;
      }
      else {
        $Value = $Labels[$Y];
      }
      $this->pChartObject
        ->drawText($XPos, $YPos, $Value, $Settings);
    }
  }

  /* Draw the area arround the specified Threshold */
  function drawContour($Threshold, $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 = array(
      "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);
          }
        }
      }
    }
  }

  /* Draw the surface chart */
  function drawSurface($Format = "") {
    $Palette = isset($Format["Palette"]) ? $Format["Palette"] : NULL;
    $ShadeR1 = isset($Format["ShadeR1"]) ? $Format["ShadeR1"] : 77;
    $ShadeG1 = isset($Format["ShadeG1"]) ? $Format["ShadeG1"] : 205;
    $ShadeB1 = isset($Format["ShadeB1"]) ? $Format["ShadeB1"] : 21;
    $ShadeA1 = isset($Format["ShadeA1"]) ? $Format["ShadeA1"] : 40;
    $ShadeR2 = isset($Format["ShadeR2"]) ? $Format["ShadeR2"] : 227;
    $ShadeG2 = isset($Format["ShadeG2"]) ? $Format["ShadeG2"] : 135;
    $ShadeB2 = isset($Format["ShadeB2"]) ? $Format["ShadeB2"] : 61;
    $ShadeA2 = isset($Format["ShadeA2"]) ? $Format["ShadeA2"] : 100;
    $Border = isset($Format["Border"]) ? $Format["Border"] : FALSE;
    $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : 0;
    $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : 0;
    $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : 0;
    $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : -1;
    $Padding = isset($Format["Padding"]) ? $Format["Padding"] : 1;
    $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);
    for ($X = 0; $X <= $this->GridSizeX; $X++) {
      for ($Y = 0; $Y <= $this->GridSizeY; $Y++) {
        $Value = $this->Points[$X][$Y];
        if ($Value != UNKNOWN && $Value != IGNORED) {
          $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 ($Palette != NULL) {
            if (isset($Palette[$Value]) && isset($Palette[$Value]["R"])) {
              $R = $Palette[$Value]["R"];
            }
            else {
              $R = 0;
            }
            if (isset($Palette[$Value]) && isset($Palette[$Value]["G"])) {
              $G = $Palette[$Value]["G"];
            }
            else {
              $G = 0;
            }
            if (isset($Palette[$Value]) && isset($Palette[$Value]["B"])) {
              $B = $Palette[$Value]["B"];
            }
            else {
              $B = 0;
            }
            if (isset($Palette[$Value]) && isset($Palette[$Value]["Alpha"])) {
              $Alpha = $Palette[$Value]["Alpha"];
            }
            else {
              $Alpha = 1000;
            }
          }
          else {
            $R = ($ShadeR2 - $ShadeR1) / 100 * $Value + $ShadeR1;
            $G = ($ShadeG2 - $ShadeG1) / 100 * $Value + $ShadeG1;
            $B = ($ShadeB2 - $ShadeB1) / 100 * $Value + $ShadeB1;
            $Alpha = ($ShadeA2 - $ShadeA1) / 100 * $Value + $ShadeA1;
          }
          $Settings = array(
            "R" => $R,
            "G" => $G,
            "B" => $B,
            "Alpha" => $Alpha,
          );
          if ($Border) {
            $Settings["BorderR"] = $BorderR;
            $Settings["BorderG"] = $BorderG;
            $Settings["BorderB"] = $BorderB;
          }
          if ($Surrounding != -1) {
            $Settings["BorderR"] = $R + $Surrounding;
            $Settings["BorderG"] = $G + $Surrounding;
            $Settings["BorderB"] = $B + $Surrounding;
          }
          $this->pChartObject
            ->drawFilledRectangle($X1, $Y1, $X2 - 1, $Y2 - 1, $Settings);
        }
      }
    }
  }

  /* Compute the missing points */
  function computeMissing() {
    $Missing = "";
    for ($X = 0; $X <= $this->GridSizeX; $X++) {
      for ($Y = 0; $Y <= $this->GridSizeY; $Y++) {
        if ($this->Points[$X][$Y] == UNKNOWN) {
          $Missing[] = $X . "," . $Y;
        }
      }
    }
    shuffle($Missing);
    foreach ($Missing as $Key => $Pos) {
      $Pos = preg_split("/,/", $Pos);
      $X = $Pos[0];
      $Y = $Pos[1];
      if ($this->Points[$X][$Y] == UNKNOWN) {
        $NearestNeighbor = $this
          ->getNearestNeighbor($X, $Y);
        $Value = 0;
        $Points = 0;
        for ($Xi = $X - $NearestNeighbor; $Xi <= $X + $NearestNeighbor; $Xi++) {
          for ($Yi = $Y - $NearestNeighbor; $Yi <= $Y + $NearestNeighbor; $Yi++) {
            if ($Xi >= 0 && $Yi >= 0 && $Xi <= $this->GridSizeX && $Yi <= $this->GridSizeY && $this->Points[$Xi][$Yi] != UNKNOWN && $this->Points[$Xi][$Yi] != IGNORED) {
              $Value = $Value + $this->Points[$Xi][$Yi];
              $Points++;
            }
          }
        }
        if ($Points != 0) {
          $this->Points[$X][$Y] = $Value / $Points;
        }
      }
    }
  }

  /* Return the nearest Neighbor distance of a point */
  function getNearestNeighbor($Xp, $Yp) {
    $Nearest = UNKNOWN;
    for ($X = 0; $X <= $this->GridSizeX; $X++) {
      for ($Y = 0; $Y <= $this->GridSizeY; $Y++) {
        if ($this->Points[$X][$Y] != UNKNOWN && $this->Points[$X][$Y] != IGNORED) {
          $DistanceX = max($Xp, $X) - min($Xp, $X);
          $DistanceY = max($Yp, $Y) - min($Yp, $Y);
          $Distance = max($DistanceX, $DistanceY);
          if ($Distance < $Nearest || $Nearest == UNKNOWN) {
            $Nearest = $Distance;
          }
        }
      }
    }
    return $Nearest;
  }

}