forked from rebillar/site-accueil-insa
414 lines
15 KiB
PHP
414 lines
15 KiB
PHP
<?php
|
|
|
|
namespace CpChart\Chart;
|
|
|
|
use CpChart\Image;
|
|
|
|
/**
|
|
* Surface - 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.
|
|
*/
|
|
class Surface
|
|
{
|
|
/**
|
|
* @var Image
|
|
*/
|
|
public $pChartObject;
|
|
|
|
/**
|
|
* @var int
|
|
*/
|
|
public $GridSizeX;
|
|
|
|
/**
|
|
* @var int
|
|
*/
|
|
public $GridSizeY;
|
|
|
|
/**
|
|
* @var array
|
|
*/
|
|
public $Points = [];
|
|
|
|
/**
|
|
* @param Image $pChartObject
|
|
*/
|
|
public function __construct(Image $pChartObject)
|
|
{
|
|
$this->pChartObject = $pChartObject;
|
|
}
|
|
|
|
/**
|
|
* Define the grid size and initialise the 2D matrix
|
|
* @param int $XSize
|
|
* @param int $YSize
|
|
*/
|
|
public 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
|
|
* @param int $X
|
|
* @param int $Y
|
|
* @param int|float $Value
|
|
* @param boolean $Force
|
|
* @return null
|
|
*/
|
|
public 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
|
|
* @param array $Format
|
|
* @return null|int
|
|
*/
|
|
public function writeXLabels(array $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 = [$Label];
|
|
}
|
|
|
|
$X0 = $this->pChartObject->GraphAreaX1;
|
|
$XSize = ($this->pChartObject->GraphAreaX2 - $this->pChartObject->GraphAreaX1) / ($this->GridSizeX + 1);
|
|
|
|
$Settings = ["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
|
|
* @param array $Format
|
|
* @return type
|
|
*/
|
|
public function writeYLabels(array $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 = [$Label];
|
|
}
|
|
|
|
$Y0 = $this->pChartObject->GraphAreaY1;
|
|
$YSize = ($this->pChartObject->GraphAreaY2 - $this->pChartObject->GraphAreaY1) / ($this->GridSizeY + 1);
|
|
|
|
$Settings = ["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
|
|
* @param int|float $Threshold
|
|
* @param array $Format
|
|
*/
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Draw the surface chart
|
|
* @param array $Format
|
|
*/
|
|
public function drawSurface(array $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 = ["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
|
|
*/
|
|
public 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 $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
|
|
* @param int $Xp
|
|
* @param int $Yp
|
|
* @return int
|
|
*/
|
|
public 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;
|
|
}
|
|
}
|