This PHP program demonstrates how to draw a graph of function of the form y = f(x) with the Graphics Draw, GD, library.
<?php
class CGraphYEqFX {
// The range of x and y values displayed as [LowX, LowY, HighX, HighY]
private $mdaRange = [0.0, 0.0, 0.0, 0.0];
// The GD image object
private $mqImage;
private $mqaBkgdColor = array('R' => 0xFF, 'G' => 0xFF, 'B' => 0xFF);
private $mqaAxisColor = array('R' => 0xC0, 'G' => 0xC0, 'B' => 0xC0);
private $mqaGridColor = array('R' => 0xF8, 'G' => 0xF8, 'B' => 0xF8);
private $mqaGraphColor = array('R' => 0x00, 'G' => 0xFF, 'B' => 0x00);
private $mqaAsymColor = array('R' => 0xE8, 'G' => 0xE8, 'B' => 0xE8);
public function __construct($iImgW, $iImH, $dLRX, $dLRY, $dHRX, $dHRY) {
$this->mqImage = ImageCreateTrueColor($iImgW, $iImH);
$this->mdaRange[0] = $dLRX;
$this->mdaRange[1] = $dLRY;
$this->mdaRange[2] = $dHRX;
$this->mdaRange[3] = $dHRY;
}
public function __destruct() {
Header("Content-type: image/png");
ImagePNG($this->mqImage);
ImageDestroy($this->mqImage);
}
public function SetRangeX($dLow, $dHigh) {
$this->mdaRange[0] = $dLow;
$this->mdaRange[2] = $dHigh;
}
public function SetRangeY($dLow, $dHigh) {
$this->mdaRange[1] = $dLow;
$this->mdaRange[3] = $dHigh;
}
public function DrawGridLines($dDeltaX, $dDeltaY) {
$qBkgdColor = ImageColorExactAlpha($this->mqImage, $this->mqaBkgdColor['R'], $this->mqaBkgdColor['G'], $this->mqaBkgdColor['B'], 0);
ImageFill($this->mqImage, 0, 0, $qBkgdColor);
$iWidth = ImageSX($this->mqImage);
$iHeight = ImageSY($this->mqImage);
// Draw the vertical lines
$qaPosAlphaX = $this->GetGridAlphaSamples($iWidth, $dDeltaX, $this->mdaRange[0], $this->mdaRange[2]);
$iSize = count($qaPosAlphaX);
for($j = 1; $j < $iSize; ++$j) {
$qPixel = ImageColorExactAlpha($this->mqImage, $this->mqaGridColor['R'], $this->mqaGridColor['G'], $this->mqaGridColor['B'], $qaPosAlphaX[$j][1]);
for ($i = 0; $i < $iHeight; ++$i) {
ImageSetPixel($this->mqImage, $qaPosAlphaX[$j][0], $i, $qPixel);
}
}
// Draw the horizontal lines
$qaPosAlphaY = $this->GetGridAlphaSamples($iHeight, $dDeltaY, $this->mdaRange[1], $this->mdaRange[3], true);
$iSize = count($qaPosAlphaY);
for($j = 1; $j < $iSize; ++$j) {
$qPixel = ImageColorExactAlpha($this->mqImage, $this->mqaGridColor['R'], $this->mqaGridColor['G'], $this->mqaGridColor['B'], $qaPosAlphaY[$j][1]);
for ($i = 0; $i < $iWidth; ++$i) {
ImageSetPixel($this->mqImage, $i, $qaPosAlphaY[$j][0], $qPixel);
}
}
// Draw the axes last so that they write over the grid lines
// Draw the vertical axis (y-axis)
if ($qaPosAlphaX[0] != null) {
foreach($qaPosAlphaX[0] as &$qPosAlphaX) {
$qPixel = ImageColorExactAlpha($this->mqImage, $this->mqaAxisColor['R'], $this->mqaAxisColor['G'], $this->mqaAxisColor['B'], $qPosAlphaX[1]);
for ($i = 0; $i < $iHeight; ++$i) {
ImageSetPixel($this->mqImage, $qPosAlphaX[0], $i, $qPixel);
}
}
}
// Draw the horizontal axis (x-axis)
if ($qaPosAlphaY[0] != null) {
foreach($qaPosAlphaY[0] as &$qPosAlphaY) {
$qPixel = ImageColorExactAlpha($this->mqImage, $this->mqaAxisColor['R'], $this->mqaAxisColor['G'], $this->mqaAxisColor['B'], $qPosAlphaY[1]);
for ($i = 0; $i < $iWidth; ++$i) {
ImageSetPixel($this->mqImage, $i, $qPosAlphaY[0], $qPixel);
}
}
}
}
// This function is used to get the alpha values for drawing grid lines along an axis
// These are stored as [$pixel locations, alpha values] for coloring lines
// At the zero index, the values are are stored for drawing the axis at the zero value
private function GetGridAlphaSamples($iPixels, $dDeltaPerLine, $dLow, $dHigh, $dReverse = false) {
$qaPosAlpha = [null];
$dDelta = $dHigh - $dLow;
$dLeastLine = (floor($dLow/$dDeltaPerLine) + 1.0)*$dDeltaPerLine;
for ($dLine = $dLeastLine; $dLine <= $dHigh; $dLine += $dDeltaPerLine) {
$dPixelLineLoc = ($dReverse ? (($dHigh - $dLine)/$dDelta)*$iPixels : (($dLine - $dLow)/$dDelta)*$iPixels);
// Pixel locations are at half pixel locations: Index 0 is at .5
// If we are in [.5,1.5), we want the pixels at index 0 and 1
$iFirstPixel = floor($dPixelLineLoc - .5);
$iLastpixel = (($iFirstPixel + 1) < $iPixels - 1) ? ($iFirstPixel + 1) : ($iPixels - 1);
$iFirstPixel = ($iFirstPixel >= 0) ? $iFirstPixel : 0;
$bIsAxis = (abs($dLine) < $dDeltaPerLine/2);
for ($iPixel = $iFirstPixel; $iPixel <= $iLastpixel; ++$iPixel) {
$dPixelDistance = abs($dPixelLineLoc - ($iPixel + .5));
$dFill = pow($dPixelDistance, 1.0);
if ($bIsAxis) {
$qaPosAlpha[0][] = [$iPixel, (127 - 127*$dFill)];
} else {
$qaPosAlpha[] = [$iPixel, (127 - 127*$dFill)];
}
}
}
return $qaPosAlpha;
}
public function GraphFunction($sFunction) {
// There are three spaces: Function, Image, Pixel. Pixel and Image are the same, but pixels must be offset by a half unit and Y is upside-down.
// Function to Image (FnX, FnY) => (ImX, ImY) : ImX = ((FnX - FnLowX)/FnDeltaX)*ImWidth, ImY = ((FnHighY - FnY)/FnDeltaY)*ImHeight
// Image To Function (ImX, ImY) => (FnX, FnY) : FnX = FnLowX + (ImX/ImWidth)*FnDeltaX, FnY = FnHighY - (ImY/ImHeight)*FnDeltaY
// Pixel to Image (PxX, PxY) => (ImX, ImY) : ImX = PxX + .5, ImY = PxY + .5
// Image to Pixel (ImX, ImY) => (PxX, PxY) : PxX = floor(ImX), PxY = floor(ImY)
$iImWidth = ImageSX($this->mqImage);
$iImHeight = ImageSY($this->mqImage);
// An array for holding all of the geometric information for the algorithm
// The three points Prev, Curr, and Next are the locations of the function values for the nearby pixel columns in image space
// The two vectors are from one point to the next and are stored as unit vectors with a magnitude
// Format [PrevX, PrevY, V1X, V1Y, V1Mag, CurrX, CurrY, V2X, V2Y, V2Mag, NextX, NextY]
$daA = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0];
// The min and max y values are the min and max pixel values of each line segment between the points
// MinPix1Y, MaxPix1Y, MinPix2Y, MaxPix2Y
$diM = [0, 0, 0, 0];
$daR = $this->mdaRange;
$daI = [(float)$iImWidth, (float)$iImHeight];
// Assign the first and second points and associated values. These are at the previous and current pixel locations: -.5 and .5
$daA[0] = -.5;
// Convert the x value from image space to function space. Apply the function to get the y value. Then convert the y back to image space.
$daA[1] = ( ($daR[3] - $sFunction($daR[0] + ($daA[0]/$daI[0])*($daR[2]-$daR[0])) )/($daR[3] - $daR[1]) )*$daI[1];
$daA[5] = .5;
$daA[6] = ( ($daR[3] - $sFunction($daR[0] + ($daA[5]/$daI[0])*($daR[2]-$daR[0])) )/($daR[3] - $daR[1]) )*$daI[1];
// Calculate the vector between the first two points
$daA[2] = $daA[5] - $daA[0];
$daA[3] = $daA[6] - $daA[1];
$daA[4] = sqrt($daA[2]*$daA[2] + $daA[3]*$daA[3]);
$daA[2] /= $daA[4];
$daA[3] /= $daA[4];
// Calculate the min and max Y as pixels
if ($daA[1] > $daA[6]) {
$diM[0] = floor($daA[6] + .5*(($daA[2] < 0) ? $daA[2] : -$daA[2])); // Min - only half of the perp unit vector y is added
$diM[1] = ceil($daA[1] + .5*(($daA[2] > 0) ? $daA[2] : -$daA[2])); // Max
} else {
$diM[0] = floor($daA[1] + .5*(($daA[2] < 0) ? $daA[2] : -$daA[2])); // Min
$diM[1] = ceil($daA[6] + .5*(($daA[2] > 0) ? $daA[2] : -$daA[2])); // Max
}
// Clamp the pixel values to the range 0 to height - 1. If the max is less than 0, set it to -1 so that no pixels are drawn. Ditto for Min > height - 1
$diM[0] = ($diM[0] < 0) ? 0 : (($diM[0] > $iImHeight - 1) ? $iImHeight : $diM[0]);
$diM[1] = ($diM[1] > $iImHeight - 1) ? $iImHeight - 1 : (($diM[1] < 0) ? -1 : $diM[1]);
// Calculate the value at each horizontal pixel
for ($iPxX = 0; $iPxX < $iImWidth; ++$iPxX) {
$daA[10] = $iPxX + 1.5;
$daA[11] = ( ($daR[3] - $sFunction($daR[0] + ($daA[10]/$daI[0])*($daR[2]-$daR[0])) )/($daR[3] - $daR[1]) )*$daI[1];
// Calculate the vector between the first two points
$daA[7] = $daA[10] - $daA[5];
$daA[8] = $daA[11] - $daA[6];
$daA[9] = sqrt($daA[7]*$daA[7] + $daA[8]*$daA[8]);
$daA[7] /= $daA[9];
$daA[8] /= $daA[9];
// Calculate the min and max Y as pixels
if ($daA[6] > $daA[11]) {
$diM[2] = floor($daA[11] + .5*(($daA[7] < 0) ? $daA[7] : -$daA[7])); // Min - only half of the perp unit vector y is added
$diM[3] = ceil($daA[6] + .5*(($daA[7] > 0) ? $daA[7] : -$daA[7])); // Max
} else {
$diM[2] = floor($daA[6] + .5*(($daA[7] < 0) ? $daA[7] : -$daA[7])); // Min
$diM[3] = ceil($daA[11] + .5*(($daA[7] > 0) ? $daA[7] : -$daA[7])); // Max
}
$diM[2] = ($diM[2] < 0) ? 0 : (($diM[2] > $iImHeight - 1) ? $iImHeight : $diM[2]);
$diM[3] = ($diM[3] > $iImHeight - 1) ? $iImHeight - 1 : (($diM[3] < 0) ? -1 : $diM[3]);
// Get the overall min and max
$iPxMinY = ($diM[0] < $diM[2]) ? $diM[0] : $diM[2];
$iPxMaxY = ($diM[1] > $diM[3]) ? $diM[1] : $diM[3];
// Get a position of the corner of the each line segment P + .5*PerpV where Perp = (y, -x)
$daLC = [$daA[0] + .5*$daA[3], $daA[1] - .5*$daA[2], $daA[5] + .5*$daA[8], $daA[6] - .5*$daA[7]];
// This is for graphing veertical asymtotes
if ($iPxMinY == 0 && $iPxMaxY == $iImHeight - 1) {
for ($iPxY = $iPxMinY; $iPxY <= $iPxMaxY; $iPxY += 12) {
$qPixel = ImageColorExactAlpha($this->mqImage, 0, 0, 0, 96);
ImageSetPixel($this->mqImage, $iPxX, $iPxY, $qPixel);
ImageSetPixel($this->mqImage, $iPxX, $iPxY + 1, $qPixel);
ImageSetPixel($this->mqImage, $iPxX, $iPxY + 2, $qPixel);
ImageSetPixel($this->mqImage, $iPxX, $iPxY + 3, $qPixel);
}
} else {
// Run from Min Y to Max Y to color the pixels of the current column
for ($iPxY = $iPxMinY; $iPxY <= $iPxMaxY; ++$iPxY) {
$dWeight = 0.0;
for ($dOX = .1; $dOX < 1.0; $dOX += .2) { // .1, .3, .5, .7, .9
// The x-coordinate in the line segment space. Subtract off the line segment corner point
$daLX = [$iPxX + $dOX - $daLC[0], $iPxX + $dOX - $daLC[2]];
for ($dOY = .1; $dOY < 1.0; $dOY += .2) {
$daLY = [$iPxY + $dOY - $daLC[1], $iPxY + $dOY - $daLC[3]];
// Get the projections of the line segment point onto the vectors and perps
$dProj = $daLX[0]*$daA[2] + $daLY[0]*$daA[3];
$dPerp = $daLY[0]*$daA[2] - $daLX[0]*$daA[3];
if ($dProj >= 0.0 && $dProj <= $daA[4] && $dPerp >= 0.0 && $dPerp <= 1.0) {
$dWeight += .04;
} else {
$dProj = $daLX[1]*$daA[7] + $daLY[1]*$daA[8];
$dPerp = $daLY[1]*$daA[7] - $daLX[1]*$daA[8];
if ($dProj >= 0.0 && $dProj <= $daA[9] && $dPerp >= 0.0 && $dPerp <= 1.0) {
$dWeight += .04;
}
}
}
}
if ($dWeight > 0.0) {
$qPixel = ImageColorExactAlpha($this->mqImage, $this->mqaGraphColor['R'], $this->mqaGraphColor['G'], $this->mqaGraphColor['B'],
(127 - 127*pow($dWeight,1.5)));
ImageSetPixel($this->mqImage, $iPxX, $iPxY, $qPixel);
}
}
}
// Update the pixels, vector, and min and max y
$daA[0] = $daA[5];
$daA[1] = $daA[6];
$daA[2] = $daA[7];
$daA[3] = $daA[8];
$daA[4] = $daA[9];
$daA[5] = $daA[10];
$daA[6] = $daA[11];
$diM[0] = $diM[2];
$diM[1] = $diM[3];
}
}
}
$qGraph = new CGraphYEqFX(800, 800, -2*M_PI, -2*M_PI, 2*M_PI, 2*M_PI);
$qGraph->DrawGridLines(M_PI/8, M_PI/8);
$qGraph->GraphFunction('tan');
?>
© 20072025 XoaX.net LLC. All rights reserved.