game/onyx2/include/jpgraph/jpgraph_plotband.php
Nigel dd61d3b66b
All checks were successful
continuous-integration/drone/push Build is passing
Ajout d'une étape de linting dans DroneCi (#3)
Corrige un doublons laissé par le rebase semi-manuel

Ajout d'une étape de linting dans DroneCi

Fix linting

Co-authored-by: Nigel Sheldon <nigelsheldon@live.fr>
Reviewed-on: https://gitea.nemunai.re/halo-battle/game/pulls/3
2020-11-21 18:54:32 +00:00

701 lines
21 KiB
PHP

<?php
//=======================================================================
// File: JPGRAPH_PLOTBAND.PHP
// Description: PHP4 Graph Plotting library. Extension module.
// Created: 2004-02-18
// Ver: $Id: jpgraph_plotband.php 781 2006-10-08 08:07:47Z ljp $
//
// Copyright (c) Aditus Consulting. All rights reserved.
//========================================================================
// Constants for types of static bands in plot area
DEFINE("BAND_RDIAG", 1); // Right diagonal lines
DEFINE("BAND_LDIAG", 2); // Left diagonal lines
DEFINE("BAND_SOLID", 3); // Solid one color
DEFINE("BAND_VLINE", 4); // Vertical lines
DEFINE("BAND_HLINE", 5); // Horizontal lines
DEFINE("BAND_3DPLANE", 6); // "3D" Plane
DEFINE("BAND_HVCROSS", 7); // Vertical/Hor crosses
DEFINE("BAND_DIAGCROSS", 8); // Diagonal crosses
// Utility class to hold coordinates for a rectangle
class Rectangle
{
public $x;
public $y;
public $w;
public $h;
public $xe;
public $ye;
public function Rectangle($aX, $aY, $aWidth, $aHeight)
{
$this->x=$aX;
$this->y=$aY;
$this->w=$aWidth;
$this->h=$aHeight;
$this->xe=$aX+$aWidth-1;
$this->ye=$aY+$aHeight-1;
}
}
//=====================================================================
// Class RectPattern
// Base class for pattern hierarchi that is used to display patterned
// bands on the graph. Any subclass that doesn't override Stroke()
// must at least implement method DoPattern($aImg) which is responsible
// for drawing the pattern onto the graph.
//=====================================================================
class RectPattern
{
protected $color;
protected $weight;
protected $rect=null;
protected $doframe=true;
protected $linespacing; // Line spacing in pixels
protected $iBackgroundColor=-1; // Default is no background fill
public function RectPattern($aColor, $aWeight=1)
{
$this->color = $aColor;
$this->weight = $aWeight;
}
public function SetBackground($aBackgroundColor)
{
$this->iBackgroundColor=$aBackgroundColor;
}
public function SetPos($aRect)
{
$this->rect = $aRect;
}
public function ShowFrame($aShow=true)
{
$this->doframe=$aShow;
}
public function SetDensity($aDens)
{
if ($aDens < 1 || $aDens > 100) {
JpGraphError::RaiseL(16001, $aDens);
}
//(" Desity for pattern must be between 1 and 100. (You tried $aDens)");
// 1% corresponds to linespacing=50
// 100 % corresponds to linespacing 1
$this->linespacing = floor(((100-$aDens)/100.0)*50)+1;
}
public function Stroke($aImg)
{
if ($this->rect == null) {
JpGraphError::RaiseL(16002);
}
//(" No positions specified for pattern.");
if (!(is_numeric($this->iBackgroundColor) && $this->iBackgroundColor==-1)) {
$aImg->SetColor($this->iBackgroundColor);
$aImg->FilledRectangle($this->rect->x, $this->rect->y, $this->rect->xe, $this->rect->ye);
}
$aImg->SetColor($this->color);
$aImg->SetLineWeight($this->weight);
// Virtual function implemented by subclass
$this->DoPattern($aImg);
// Frame around the pattern area
if ($this->doframe) {
$aImg->Rectangle($this->rect->x, $this->rect->y, $this->rect->xe, $this->rect->ye);
}
}
}
//=====================================================================
// Class RectPatternSolid
// Implements a solid band
//=====================================================================
class RectPatternSolid extends RectPattern
{
public function RectPatternSolid($aColor="black", $aWeight=1)
{
parent::RectPattern($aColor, $aWeight);
}
public function DoPattern($aImg)
{
$aImg->SetColor($this->color);
$aImg->FilledRectangle(
$this->rect->x,
$this->rect->y,
$this->rect->xe,
$this->rect->ye
);
}
}
//=====================================================================
// Class RectPatternHor
// Implements horizontal line pattern
//=====================================================================
class RectPatternHor extends RectPattern
{
public function RectPatternHor($aColor="black", $aWeight=1, $aLineSpacing=7)
{
parent::RectPattern($aColor, $aWeight);
$this->linespacing = $aLineSpacing;
}
public function DoPattern($aImg)
{
$x0 = $this->rect->x;
$x1 = $this->rect->xe;
$y = $this->rect->y;
while ($y < $this->rect->ye) {
$aImg->Line($x0, $y, $x1, $y);
$y += $this->linespacing;
}
}
}
//=====================================================================
// Class RectPatternVert
// Implements vertical line pattern
//=====================================================================
class RectPatternVert extends RectPattern
{
public function RectPatternVert($aColor="black", $aWeight=1, $aLineSpacing=7)
{
parent::RectPattern($aColor, $aWeight);
$this->linespacing = $aLineSpacing;
}
//--------------------
// Private methods
//
public function DoPattern($aImg)
{
$x = $this->rect->x;
$y0 = $this->rect->y;
$y1 = $this->rect->ye;
while ($x < $this->rect->xe) {
$aImg->Line($x, $y0, $x, $y1);
$x += $this->linespacing;
}
}
}
//=====================================================================
// Class RectPatternRDiag
// Implements right diagonal pattern
//=====================================================================
class RectPatternRDiag extends RectPattern
{
public function RectPatternRDiag($aColor="black", $aWeight=1, $aLineSpacing=12)
{
parent::RectPattern($aColor, $aWeight);
$this->linespacing = $aLineSpacing;
}
public function DoPattern($aImg)
{
// --------------------
// | / / / / /|
// |/ / / / / |
// | / / / / |
// --------------------
$xe = $this->rect->xe;
$ye = $this->rect->ye;
$x0 = $this->rect->x + round($this->linespacing/2);
$y0 = $this->rect->y;
$x1 = $this->rect->x;
$y1 = $this->rect->y + round($this->linespacing/2);
while ($x0<=$xe && $y1<=$ye) {
$aImg->Line($x0, $y0, $x1, $y1);
$x0 += $this->linespacing;
$y1 += $this->linespacing;
}
if ($xe-$x1 > $ye-$y0) {
// Width larger than height
$x1 = $this->rect->x + ($y1-$ye);
$y1 = $ye;
$y0 = $this->rect->y;
while ($x0 <= $xe) {
$aImg->Line($x0, $y0, $x1, $y1);
$x0 += $this->linespacing;
$x1 += $this->linespacing;
}
$y0=$this->rect->y + ($x0-$xe);
$x0=$xe;
} else {
// Height larger than width
$diff = $x0-$xe;
$y0 = $diff+$this->rect->y;
$x0 = $xe;
$x1 = $this->rect->x;
while ($y1 <= $ye) {
$aImg->Line($x0, $y0, $x1, $y1);
$y1 += $this->linespacing;
$y0 += $this->linespacing;
}
$diff = $y1-$ye;
$y1 = $ye;
$x1 = $diff + $this->rect->x;
}
while ($y0 <= $ye) {
$aImg->Line($x0, $y0, $x1, $y1);
$y0 += $this->linespacing;
$x1 += $this->linespacing;
}
}
}
//=====================================================================
// Class RectPatternLDiag
// Implements left diagonal pattern
//=====================================================================
class RectPatternLDiag extends RectPattern
{
public function RectPatternLDiag($aColor="black", $aWeight=1, $aLineSpacing=12)
{
$this->linespacing = $aLineSpacing;
parent::RectPattern($aColor, $aWeight);
}
public function DoPattern($aImg)
{
// --------------------
// |\ \ \ \ \ |
// | \ \ \ \ \|
// | \ \ \ \ |
// |------------------|
$xe = $this->rect->xe;
$ye = $this->rect->ye;
$x0 = $this->rect->x + round($this->linespacing/2);
$y0 = $this->rect->ye;
$x1 = $this->rect->x;
$y1 = $this->rect->ye - round($this->linespacing/2);
while ($x0<=$xe && $y1>=$this->rect->y) {
$aImg->Line($x0, $y0, $x1, $y1);
$x0 += $this->linespacing;
$y1 -= $this->linespacing;
}
if ($xe-$x1 > $ye-$this->rect->y) {
// Width larger than height
$x1 = $this->rect->x + ($this->rect->y-$y1);
$y0=$ye;
$y1=$this->rect->y;
while ($x0 <= $xe) {
$aImg->Line($x0, $y0, $x1, $y1);
$x0 += $this->linespacing;
$x1 += $this->linespacing;
}
$y0=$this->rect->ye - ($x0-$xe);
$x0=$xe;
} else {
// Height larger than width
$diff = $x0-$xe;
$y0 = $ye-$diff;
$x0 = $xe;
while ($y1 >= $this->rect->y) {
$aImg->Line($x0, $y0, $x1, $y1);
$y0 -= $this->linespacing;
$y1 -= $this->linespacing;
}
$diff = $this->rect->y - $y1;
$x1 = $this->rect->x + $diff;
$y1 = $this->rect->y;
}
while ($y0 >= $this->rect->y) {
$aImg->Line($x0, $y0, $x1, $y1);
$y0 -= $this->linespacing;
$x1 += $this->linespacing;
}
}
}
//=====================================================================
// Class RectPattern3DPlane
// Implements "3D" plane pattern
//=====================================================================
class RectPattern3DPlane extends RectPattern
{
private $alpha=50; // Parameter that specifies the distance
// to "simulated" horizon in pixel from the
// top of the band. Specifies how fast the lines
// converge.
public function RectPattern3DPlane($aColor="black", $aWeight=1)
{
parent::RectPattern($aColor, $aWeight);
$this->SetDensity(10); // Slightly larger default
}
public function SetHorizon($aHorizon)
{
$this->alpha=$aHorizon;
}
public function DoPattern($aImg)
{
// "Fake" a nice 3D grid-effect.
$x0 = $this->rect->x + $this->rect->w/2;
$y0 = $this->rect->y;
$x1 = $x0;
$y1 = $this->rect->ye;
$x0_right = $x0;
$x1_right = $x1;
// BTW "apa" means monkey in Swedish but is really a shortform for
// "alpha+a" which was the labels I used on paper when I derived the
// geometric to get the 3D perspective right.
// $apa is the height of the bounding rectangle plus the distance to the
// artifical horizon (alpha)
$apa = $this->rect->h + $this->alpha;
// Three cases and three loops
// 1) The endpoint of the line ends on the bottom line
// 2) The endpoint ends on the side
// 3) Horizontal lines
// Endpoint falls on bottom line
$middle=$this->rect->x + $this->rect->w/2;
$dist=$this->linespacing;
$factor=$this->alpha /($apa);
while ($x1>$this->rect->x) {
$aImg->Line($x0, $y0, $x1, $y1);
$aImg->Line($x0_right, $y0, $x1_right, $y1);
$x1 = $middle - $dist;
$x0 = $middle - $dist * $factor;
$x1_right = $middle + $dist;
$x0_right = $middle + $dist * $factor;
$dist += $this->linespacing;
}
// Endpoint falls on sides
$dist -= $this->linespacing;
$d=$this->rect->w/2;
$c = $apa - $d*$apa/$dist;
while ($x0>$this->rect->x) {
$aImg->Line($x0, $y0, $this->rect->x, $this->rect->ye-$c);
$aImg->Line($x0_right, $y0, $this->rect->xe, $this->rect->ye-$c);
$dist += $this->linespacing;
$x0 = $middle - $dist * $factor;
$x1 = $middle - $dist;
$x0_right = $middle + $dist * $factor;
$c = $apa - $d*$apa/$dist;
}
// Horizontal lines
// They need some serious consideration since they are a function
// of perspective depth (alpha) and density (linespacing)
$x0=$this->rect->x;
$x1=$this->rect->xe;
$y=$this->rect->ye;
// The first line is drawn directly. Makes the loop below slightly
// more readable.
$aImg->Line($x0, $y, $x1, $y);
$hls = $this->linespacing;
// A correction factor for vertical "brick" line spacing to account for
// a) the difference in number of pixels hor vs vert
// b) visual apperance to make the first layer of "bricks" look more
// square.
$vls = $this->linespacing*0.6;
$ds = $hls*($apa-$vls)/$apa;
// Get the slope for the "perspective line" going from bottom right
// corner to top left corner of the "first" brick.
// Uncomment the following lines if you want to get a visual understanding
// of what this helpline does. BTW this mimics the way you would get the
// perspective right when drawing on paper.
/*
$x0 = $middle;
$y0 = $this->rect->ye;
$len=floor(($this->rect->ye-$this->rect->y)/$vls);
$x1 = $middle+round($len*$ds);
$y1 = $this->rect->ye-$len*$vls;
$aImg->PushColor("red");
$aImg->Line($x0,$y0,$x1,$y1);
$aImg->PopColor();
*/
$y -= $vls;
$k=($this->rect->ye-($this->rect->ye-$vls))/($middle-($middle-$ds));
$dist = $hls;
while ($y>$this->rect->y) {
$aImg->Line($this->rect->x, $y, $this->rect->xe, $y);
$adj = $k*$dist/(1+$dist*$k/$apa);
if ($adj < 2) {
$adj=1;
}
$y = $this->rect->ye - round($adj);
$dist += $hls;
}
}
}
//=====================================================================
// Class RectPatternCross
// Vert/Hor crosses
//=====================================================================
class RectPatternCross extends RectPattern
{
private $vert=null;
private $hor=null;
public function RectPatternCross($aColor="black", $aWeight=1)
{
parent::RectPattern($aColor, $aWeight);
$this->vert = new RectPatternVert($aColor, $aWeight);
$this->hor = new RectPatternHor($aColor, $aWeight);
}
public function SetOrder($aDepth)
{
$this->vert->SetOrder($aDepth);
$this->hor->SetOrder($aDepth);
}
public function SetPos($aRect)
{
parent::SetPos($aRect);
$this->vert->SetPos($aRect);
$this->hor->SetPos($aRect);
}
public function SetDensity($aDens)
{
$this->vert->SetDensity($aDens);
$this->hor->SetDensity($aDens);
}
public function DoPattern($aImg)
{
$this->vert->DoPattern($aImg);
$this->hor->DoPattern($aImg);
}
}
//=====================================================================
// Class RectPatternDiagCross
// Vert/Hor crosses
//=====================================================================
class RectPatternDiagCross extends RectPattern
{
private $left=null;
private $right=null;
public function RectPatternDiagCross($aColor="black", $aWeight=1)
{
parent::RectPattern($aColor, $aWeight);
$this->right = new RectPatternRDiag($aColor, $aWeight);
$this->left = new RectPatternLDiag($aColor, $aWeight);
}
public function SetOrder($aDepth)
{
$this->left->SetOrder($aDepth);
$this->right->SetOrder($aDepth);
}
public function SetPos($aRect)
{
parent::SetPos($aRect);
$this->left->SetPos($aRect);
$this->right->SetPos($aRect);
}
public function SetDensity($aDens)
{
$this->left->SetDensity($aDens);
$this->right->SetDensity($aDens);
}
public function DoPattern($aImg)
{
$this->left->DoPattern($aImg);
$this->right->DoPattern($aImg);
}
}
//=====================================================================
// Class RectPatternFactory
// Factory class for rectangular pattern
//=====================================================================
class RectPatternFactory
{
public function RectPatternFactory()
{
// Empty
}
public function Create($aPattern, $aColor, $aWeight=1)
{
switch ($aPattern) {
case BAND_RDIAG:
$obj = new RectPatternRDiag($aColor, $aWeight);
break;
case BAND_LDIAG:
$obj = new RectPatternLDiag($aColor, $aWeight);
break;
case BAND_SOLID:
$obj = new RectPatternSolid($aColor, $aWeight);
break;
case BAND_VLINE:
$obj = new RectPatternVert($aColor, $aWeight);
break;
case BAND_HLINE:
$obj = new RectPatternHor($aColor, $aWeight);
break;
case BAND_3DPLANE:
$obj = new RectPattern3DPlane($aColor, $aWeight);
break;
case BAND_HVCROSS:
$obj = new RectPatternCross($aColor, $aWeight);
break;
case BAND_DIAGCROSS:
$obj = new RectPatternDiagCross($aColor, $aWeight);
break;
default:
JpGraphError::RaiseL(16003, $aPattern);
//(" Unknown pattern specification ($aPattern)");
}
return $obj;
}
}
//=====================================================================
// Class PlotBand
// Factory class which is used by the client.
// It is responsible for factoring the corresponding pattern
// concrete class.
//=====================================================================
class PlotBand
{
public $depth; // Determine if band should be over or under the plots
private $prect=null;
private $dir;
private $min;
private $max;
public function PlotBand($aDir, $aPattern, $aMin, $aMax, $aColor="black", $aWeight=1, $aDepth=DEPTH_BACK)
{
$f = new RectPatternFactory();
$this->prect = $f->Create($aPattern, $aColor, $aWeight);
if (is_numeric($aMin) && is_numeric($aMax) && ($aMin > $aMax)) {
JpGraphError::RaiseL(16004);
}
//('Min value for plotband is larger than specified max value. Please correct.');
$this->dir = $aDir;
$this->min = $aMin;
$this->max = $aMax;
$this->depth=$aDepth;
}
// Set position. aRect contains absolute image coordinates
public function SetPos($aRect)
{
assert($this->prect != null) ;
$this->prect->SetPos($aRect);
}
public function ShowFrame($aFlag=true)
{
$this->prect->ShowFrame($aFlag);
}
// Set z-order. In front of pplot or in the back
public function SetOrder($aDepth)
{
$this->depth=$aDepth;
}
public function SetDensity($aDens)
{
$this->prect->SetDensity($aDens);
}
public function GetDir()
{
return $this->dir;
}
public function GetMin()
{
return $this->min;
}
public function GetMax()
{
return $this->max;
}
public function PreStrokeAdjust($aGraph)
{
// Nothing to do
}
// Display band
public function Stroke($aImg, $aXScale, $aYScale)
{
assert($this->prect != null) ;
if ($this->dir == HORIZONTAL) {
if ($this->min === 'min') {
$this->min = $aYScale->GetMinVal();
}
if ($this->max === 'max') {
$this->max = $aYScale->GetMaxVal();
}
// Only draw the bar if it actually appears in the range
if ($this->min < $aYScale->GetMaxVal() && $this->max > $aYScale->GetMinVal()) {
// Trucate to limit of axis
$this->min = max($this->min, $aYScale->GetMinVal());
$this->max = min($this->max, $aYScale->GetMaxVal());
$x=$aXScale->scale_abs[0];
$y=$aYScale->Translate($this->max);
$width=$aXScale->scale_abs[1]-$aXScale->scale_abs[0]+1;
$height=abs($y-$aYScale->Translate($this->min))+1;
$this->prect->SetPos(new Rectangle($x, $y, $width, $height));
$this->prect->Stroke($aImg);
}
} else { // VERTICAL
if ($this->min === 'min') {
$this->min = $aXScale->GetMinVal();
}
if ($this->max === 'max') {
$this->max = $aXScale->GetMaxVal();
}
// Only draw the bar if it actually appears in the range
if ($this->min < $aXScale->GetMaxVal() && $this->max > $aXScale->GetMinVal()) {
// Trucate to limit of axis
$this->min = max($this->min, $aXScale->GetMinVal());
$this->max = min($this->max, $aXScale->GetMaxVal());
$y=$aYScale->scale_abs[1];
$x=$aXScale->Translate($this->min);
$height=abs($aYScale->scale_abs[1]-$aYScale->scale_abs[0]);
$width=abs($x-$aXScale->Translate($this->max));
$this->prect->SetPos(new Rectangle($x, $y, $width, $height));
$this->prect->Stroke($aImg);
}
}
}
}