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'); ?>
© 20072024 XoaX.net LLC. All rights reserved.