eos.class.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  1. <?php if ( ! defined( 'ABSPATH' ) ) exit;
  2. /**
  3. * Equation Operating System Classes.
  4. *
  5. * This class was created for the safe parsing of mathematical equations
  6. * in PHP. There is a need for a way to successfully parse equations
  7. * in PHP that do NOT require the use of `eval`. `eval` at its core
  8. * opens the system using it to so many security vulnerabilities it is oft
  9. * suggested /never/ to use it, and for good reason. This class set will
  10. * successfully take an equation, parse it, and provide solutions to the
  11. * developer. It is a safe way to evaluate expressions without putting
  12. * the system at risk.
  13. *
  14. * 2013/04 UPDATE:
  15. * - Moved to native class functions for PHP5
  16. * - Removed deprecated `eregi` calls to `preg_match`
  17. * - Updated to PHPDoc comment syntax
  18. * - Added Exception throwing instead of silent exits
  19. * - Added additional variable prefix of '$', '&' is still allowed as well
  20. * - Fixed small implied multiplication problem
  21. *
  22. * TODO:
  23. * - Add factorial support. (ie 5! = 120)
  24. *
  25. * @author Jon Lawrence <jlawrence11@gmail.com>
  26. * @copyright Copyright �2005-2013, Jon Lawrence
  27. * @license http://opensource.org/licenses/LGPL-2.1 LGPL 2.1 License
  28. * @package EOS
  29. * @version 2.0
  30. */
  31. //The following are defines for thrown exceptions
  32. /**
  33. * No matching Open/Close pair
  34. */
  35. define('EQEOS_E_NO_SET', 5500);
  36. /**
  37. * Division by 0
  38. */
  39. define('EQEOS_E_DIV_ZERO', 5501);
  40. /**
  41. * No Equation
  42. */
  43. define('EQEOS_E_NO_EQ', 5502);
  44. /**
  45. * No variable replacement available
  46. */
  47. define('EQEOS_E_NO_VAR', 5503);
  48. if(!defined('DEBUG'))
  49. define('DEBUG', false);
  50. //We use a stack class so we don't have to keep track of indices for an array
  51. // May eventually update to use `array_pop()` `end()` and `array_push()` instead
  52. // of this class.
  53. require_once "stack.class.php";
  54. /**
  55. * Equation Operating System (EOS) Parser
  56. *
  57. * An EOS that can safely parse equations from unknown sources returning
  58. * the calculated value of it. Can also handle solving equations with
  59. * variables, if the variables are defined (useful for the Graph creation
  60. * that the second and extended class in this file provides. {@see eqGraph})
  61. * This class was created for PHP4 in 2005, updated to fully PHP5 in 2013.
  62. *
  63. * @author Jon Lawrence <jlawrence11@gmail.com>
  64. * @copyright Copyright �2005-2013, Jon Lawrence
  65. * @license http://opensource.org/licenses/LGPL-2.1 LGPL 2.1 License
  66. * @package Math
  67. * @subpackage EOS
  68. * @version 2.0
  69. */
  70. class eqEOS {
  71. /**#@+
  72. *Private variables
  73. */
  74. private $postFix;
  75. private $inFix;
  76. /**#@-*/
  77. /**#@+
  78. * Protected variables
  79. */
  80. //What are opening and closing selectors
  81. protected $SEP = array('open' => array('(', '['), 'close' => array(')', ']'));
  82. //Top presedence following operator - not in use
  83. protected $SGL = array('!');
  84. //Order of operations arrays follow
  85. protected $ST = array('^');
  86. protected $ST1 = array('/', '*', '%');
  87. protected $ST2 = array('+', '-');
  88. //Allowed functions
  89. protected $FNC = array('sin', 'cos', 'tan', 'csc', 'sec', 'cot');
  90. /**#@-*/
  91. /**
  92. * Construct method
  93. *
  94. * Will initiate the class. If variable given, will assign to
  95. * internal variable to solve with this::solveIF() without needing
  96. * additional input. Initializing with a variable is not suggested.
  97. *
  98. * @see eqEOS::solveIF()
  99. * @param String $inFix Standard format equation
  100. */
  101. public function __construct($inFix = null) {
  102. $this->inFix = (isset($inFix)) ? $inFix : null;
  103. $this->postFix = array();
  104. }
  105. /**
  106. * Check Infix for opening closing pair matches.
  107. *
  108. * This function is meant to solely check to make sure every opening
  109. * statement has a matching closing one, and throws an exception if
  110. * it doesn't.
  111. *
  112. * @param String $infix Equation to check
  113. * @throws Exception if malformed.
  114. * @return Bool true if passes - throws an exception if not.
  115. */
  116. private function checkInfix($infix) {
  117. if(trim($infix) == "") {
  118. throw new Exception("No Equation given", EQEOS_E_NO_EQ);
  119. return false;
  120. }
  121. //Make sure we have the same number of '(' as we do ')'
  122. // and the same # of '[' as we do ']'
  123. if(substr_count($infix, '(') != substr_count($infix, ')')) {
  124. throw new Exception("Mismatched parenthesis in '{$infix}'", EQEOS_E_NO_SET);
  125. return false;
  126. } elseif(substr_count($infix, '[') != substr_count($infix, ']')) {
  127. throw new Exception("Mismatched brackets in '{$infix}'", EQEOS_E_NO_SET);
  128. return false;
  129. }
  130. $this->inFix = $infix;
  131. return true;
  132. }
  133. /**
  134. * Infix to Postfix
  135. *
  136. * Converts an infix (standard) equation to postfix (RPN) notation.
  137. * Sets the internal variable $this->postFix for the eqEOS::solvePF()
  138. * function to use.
  139. *
  140. * @link http://en.wikipedia.org/wiki/Infix_notation Infix Notation
  141. * @link http://en.wikipedia.org/wiki/Reverse_Polish_notation Reverse Polish Notation
  142. * @param String $infix A standard notation equation
  143. * @return Array Fully formed RPN Stack
  144. */
  145. public function in2post($infix = null) {
  146. // if an equation was not passed, use the one that was passed in the constructor
  147. $infix = (isset($infix)) ? $infix : $this->inFix;
  148. //check to make sure 'valid' equation
  149. $this->checkInfix($infix);
  150. $pf = array();
  151. $ops = new phpStack();
  152. $vars = new phpStack();
  153. // remove all white-space
  154. preg_replace("/\s/", "", $infix);
  155. // Create postfix array index
  156. $pfIndex = 0;
  157. //what was the last character? (useful for decerning between a sign for negation and subtraction)
  158. $lChar = '';
  159. //loop through all the characters and start doing stuff ^^
  160. for($i=0;$i<strlen($infix);$i++) {
  161. // pull out 1 character from the string
  162. $chr = substr($infix, $i, 1);
  163. // if the character is numerical
  164. if(preg_match('/[0-9.]/i', $chr)) {
  165. // if the previous character was not a '-' or a number
  166. if((!preg_match('/[0-9.]/i', $lChar) && ($lChar != "")) && (@$pf[$pfIndex]!="-"))
  167. $pfIndex++; // increase the index so as not to overlap anything
  168. // Add the number character to the array
  169. @$pf[$pfIndex] .= $chr;
  170. }
  171. // If the character opens a set e.g. '(' or '['
  172. elseif(in_array($chr, $this->SEP['open'])) {
  173. // if the last character was a number, place an assumed '*' on the stack
  174. if(preg_match('/[0-9.]/i', $lChar))
  175. $ops->push('*');
  176. $ops->push($chr);
  177. }
  178. // if the character closes a set e.g. ')' or ']'
  179. elseif(in_array($chr, $this->SEP['close'])) {
  180. // find what set it was i.e. matches ')' with '(' or ']' with '['
  181. $key = array_search($chr, $this->SEP['close']);
  182. // while the operator on the stack isn't the matching pair...pop it off
  183. while($ops->peek() != $this->SEP['open'][$key]) {
  184. $nchr = $ops->pop();
  185. if($nchr)
  186. $pf[++$pfIndex] = $nchr;
  187. else {
  188. throw new Exception("Error while searching for '". $this->SEP['open'][$key] ."' in '{$infix}'.", EQEOS_E_NO_SET);
  189. return false;
  190. }
  191. }
  192. $ops->pop();
  193. }
  194. // If a special operator that has precedence over everything else
  195. elseif(in_array($chr, $this->ST)) {
  196. $ops->push($chr);
  197. $pfIndex++;
  198. }
  199. // Any other operator other than '+' and '-'
  200. elseif(in_array($chr, $this->ST1)) {
  201. while(in_array($ops->peek(), $this->ST1) || in_array($ops->peek(), $this->ST))
  202. $pf[++$pfIndex] = $ops->pop();
  203. $ops->push($chr);
  204. $pfIndex++;
  205. }
  206. // if a '+' or '-'
  207. elseif(in_array($chr, $this->ST2)) {
  208. // if it is a '-' and the character before it was an operator or nothingness (e.g. it negates a number)
  209. if((in_array($lChar, array_merge($this->ST1, $this->ST2, $this->ST, $this->SEP['open'])) || $lChar=="") && $chr=="-") {
  210. // increase the index because there is no reason that it shouldn't..
  211. $pfIndex++;
  212. $pf[$pfIndex] = $chr;
  213. }
  214. // Otherwise it will function like a normal operator
  215. else {
  216. while(in_array($ops->peek(), array_merge($this->ST1, $this->ST2, $this->ST)))
  217. $pf[++$pfIndex] = $ops->pop();
  218. $ops->push($chr);
  219. $pfIndex++;
  220. }
  221. }
  222. // make sure we record this character to be refered to by the next one
  223. $lChar = $chr;
  224. }
  225. // if there is anything on the stack after we are done...add it to the back of the RPN array
  226. while(($tmp = $ops->pop()) !== false)
  227. $pf[++$pfIndex] = $tmp;
  228. // re-index the array at 0
  229. $pf = array_values($pf);
  230. // set the private variable for later use if needed
  231. $this->postFix = $pf;
  232. // return the RPN array in case developer wants to use it fro some insane reason (bug testing ;]
  233. return $pf;
  234. } //end function in2post
  235. /**
  236. * Solve Postfix (RPN)
  237. *
  238. * This function will solve a RPN array. Default action is to solve
  239. * the RPN array stored in the class from eqEOS::in2post(), can take
  240. * an array input to solve as well, though default action is prefered.
  241. *
  242. * @link http://en.wikipedia.org/wiki/Reverse_Polish_notation Postix Notation
  243. * @param Array $pfArray RPN formatted array. Optional.
  244. * @return Float Result of the operation.
  245. */
  246. public function solvePF($pfArray = null) {
  247. // if no RPN array is passed - use the one stored in the private var
  248. $pf = (!is_array($pfArray)) ? $this->postFix : $pfArray;
  249. // create our temporary function variables
  250. $temp = array();
  251. $tot = 0;
  252. $hold = 0;
  253. // Loop through each number/operator
  254. for($i=0;$i<count($pf); $i++) {
  255. // If the string isn't an operator, add it to the temp var as a holding place
  256. if(!in_array($pf[$i], array_merge($this->ST, $this->ST1, $this->ST2))) {
  257. $temp[$hold++] = $pf[$i];
  258. }
  259. // ...Otherwise perform the operator on the last two numbers
  260. else {
  261. switch ($pf[$i]) {
  262. case '+':
  263. @$temp[$hold-2] = $temp[$hold-2] + $temp[$hold-1];
  264. break;
  265. case '-':
  266. @$temp[$hold-2] = $temp[$hold-2] - $temp[$hold-1];
  267. break;
  268. case '*':
  269. @$temp[$hold-2] = $temp[$hold-2] * $temp[$hold-1];
  270. break;
  271. case '/':
  272. if($temp[$hold-1] == 0) {
  273. throw new Exception("Division by 0 on: '{$temp[$hold-2]} / {$temp[$hold-1]}' in {$this->inFix}", EQEOS_E_DIV_ZERO);
  274. return false;
  275. }
  276. @$temp[$hold-2] = $temp[$hold-2] / $temp[$hold-1];
  277. break;
  278. case '^':
  279. @$temp[$hold-2] = pow($temp[$hold-2], $temp[$hold-1]);
  280. break;
  281. case '%':
  282. if($temp[$hold-1] == 0) {
  283. throw new Exception("Division by 0 on: '{$temp[$hold-2]} % {$temp[$hold-1]}' in {$this->inFix}", EQEOS_E_DIV_ZERO);
  284. return false;
  285. }
  286. @$temp[$hold-2] = bcmod($temp[$hold-2], $temp[$hold-1]);
  287. break;
  288. }
  289. // Decrease the hold var to one above where the last number is
  290. $hold = $hold-1;
  291. }
  292. }
  293. // return the last number in the array
  294. return $temp[$hold-1];
  295. } //end function solvePF
  296. /**
  297. * Solve Infix (Standard) Notation Equation
  298. *
  299. * Will take a standard equation with optional variables and solve it. Variables
  300. * must begin with '&' will expand to allow variables to begin with '$' (TODO)
  301. * The variable array must be in the format of 'variable' => value. If
  302. * variable array is scalar (ie 5), all variables will be replaced with it.
  303. *
  304. * @param String $infix Standard Equation to solve
  305. * @param String|Array $vArray Variable replacement
  306. * @return Float Solved equation
  307. */
  308. function solveIF($infix, $vArray = null) {
  309. $infix = ($infix != "") ? $infix : $this->inFix;
  310. //Check to make sure a 'valid' expression
  311. $this->checkInfix($infix);
  312. $ops = new phpStack();
  313. $vars = new phpStack();
  314. //remove all white-space
  315. preg_replace("/\s/", "", $infix);
  316. if(DEBUG)
  317. $hand=fopen("eq.txt","a");
  318. //Find all the variables that were passed and replaces them
  319. while((preg_match('/(.){0,1}[&$]([a-zA-Z]+)(.){0,1}/', $infix, $match)) != 0) {
  320. //remove notices by defining if undefined.
  321. if(!isset($match[3])) {
  322. $match[3] = "";
  323. }
  324. if(DEBUG)
  325. fwrite($hand, "{$match[1]} || {$match[3]}\n");
  326. // Ensure that the variable has an operator or something of that sort in front and back - if it doesn't, add an implied '*'
  327. if((!in_array($match[1], array_merge($this->ST, $this->ST1, $this->ST2, $this->SEP['open'])) && $match[1] != "") || is_numeric($match[1])) //$this->SEP['close'] removed
  328. $front = "*";
  329. else
  330. $front = "";
  331. if((!in_array($match[3], array_merge($this->ST, $this->ST1, $this->ST2, $this->SEP['close'])) && $match[3] != "") || is_numeric($match[3])) //$this->SEP['open'] removed
  332. $back = "*";
  333. else
  334. $back = "";
  335. //Make sure that the variable does have a replacement
  336. if(!isset($vArray[$match[2]]) && (!is_array($vArray != "") && !is_numeric($vArray))) {
  337. throw new Exception("Variable replacement does not exist for '". substr($match[0], 1, -1) ."' in {$this->inFix}", EQEOS_E_NO_VAR);
  338. return false;
  339. } elseif(!isset($vArray[$match[2]]) && (!is_array($vArray != "") && is_numeric($vArray))) {
  340. $infix = str_replace($match[0], $match[1] . $front. $vArray. $back . $match[3], $infix);
  341. } elseif(isset($vArray[$match[2]])) {
  342. $infix = str_replace($match[0], $match[1] . $front. $vArray[$match[2]]. $back . $match[3], $infix);
  343. }
  344. }
  345. if(DEBUG)
  346. fwrite($hand, "$infix\n");
  347. // Finds all the 'functions' within the equation and calculates them
  348. // NOTE - when using function, only 1 set of paranthesis will be found, instead use brackets for sets within functions!!
  349. while((preg_match("/(". implode("|", $this->FNC) . ")\(([^\)\(]*(\([^\)]*\)[^\(\)]*)*[^\)\(]*)\)/", $infix, $match)) != 0) {
  350. $func = $this->solveIF($match[2]);
  351. switch($match[1]) {
  352. case "cos":
  353. $ans = cos($func);
  354. break;
  355. case "sin":
  356. $ans = sin($func);
  357. break;
  358. case "tan":
  359. $ans = tan($func);
  360. break;
  361. case "sec":
  362. $tmp = cos($func);
  363. if($tmp == 0) {
  364. throw new Exception("Division by 0 on: 'sec({$func}) = 1/cos({$func})' in {$this->inFix}", EQEOS_E_DIV_ZERO);
  365. return false;
  366. }
  367. $ans = 1/$tmp;
  368. break;
  369. case "csc":
  370. $tmp = sin($func);
  371. if($tmp == 0) {
  372. throw new Exception("Division by 0 on: 'csc({$func}) = 1/sin({$func})' in {$this->inFix}", EQEOS_E_DIV_ZERO);
  373. return false;
  374. }
  375. $ans = 1/$tmp;
  376. break;
  377. case "cot":
  378. $tmp = tan($func);
  379. if($tmp == 0) {
  380. throw new Exception("Division by 0 on: 'cot({$func}) = 1/tan({$func})' in {$this->inFix}", EQEOS_E_DIV_ZERO);
  381. return false;
  382. }
  383. $ans = 1/$tmp;
  384. break;
  385. default:
  386. break;
  387. }
  388. $infix = str_replace($match[0], $ans, $infix);
  389. }
  390. if(DEBUG)
  391. fclose($hand);
  392. return $this->solvePF($this->in2post($infix));
  393. } //end function solveIF
  394. } //end class 'eqEOS'
  395. // fun class that requires the GD libraries to give visual output to the user
  396. /* extends the eqEOS class so that it doesn't need to create it as a private var
  397. - and it extends the functionality of that class */
  398. /**
  399. * Equation Graph
  400. *
  401. * Fun class that requires the GD libraries to give visual output of an
  402. * equation to the user. Extends the eqEOS class.
  403. *
  404. * @author Jon Lawrence <jlawrence11@gmail.com>
  405. * @copyright Copyright �2005-2013 Jon Lawrence
  406. * @license http://opensource.org/licenses/LGPL-2.1 LGPL 2.1 License
  407. * @package Math
  408. * @subpackage EOS
  409. * @version 2.0
  410. */
  411. class eqGraph extends eqEOS {
  412. private $width;
  413. private $height;
  414. //GD Image reference
  415. private $image;
  416. /**
  417. * Constructor
  418. *
  419. * Sets up the Graph class with an image width and height defaults to
  420. * 640x480
  421. *
  422. * @param Integer $width Image width
  423. * @param Integer $height Image height
  424. */
  425. public function __construct($width=640, $height=480) {
  426. // default width and height equal to that of a poor monitor (in early 2000s)
  427. $this->width = $width;
  428. $this->height = $height;
  429. //initialize main class variables
  430. parent::__construct();
  431. } //end function eqGraph
  432. /**
  433. * Create GD Graph Image
  434. *
  435. * Creates a GD image based on the equation given with the parameters that are set
  436. *
  437. * @param String $eq Equation to use. Needs variable in equation to create graph, all variables are interpreted as 'x'
  438. * @param Integer $xLow Lower x-bound for graph
  439. * @param Integer $xHigh Upper x-bound for graph
  440. * @param Float $xStep Stepping points while solving, the lower, the better precision. Slow if lower than .01
  441. * @param Boolean $xyGrid Draw gridlines?
  442. * @param Boolean $yGuess Guess the upper/lower yBounds?
  443. * @param Integer $yLow Lower y-bound
  444. * @param Integer $yHigh Upper y-bound
  445. * @return Null
  446. */
  447. public function graph($eq, $xLow, $xHigh, $xStep, $xyGrid = false, $yGuess = true, $yLow=false, $yHigh=false) {
  448. //create our image and allocate the two colors
  449. $img = ImageCreate($this->width, $this->height);
  450. $white = ImageColorAllocate($img, 255, 255, 255);
  451. $black = ImageColorAllocate($img, 0, 0, 0);
  452. $grey = ImageColorAllocate($img, 220, 220, 220);
  453. $xStep = abs($xStep);
  454. //DEVELOPER, UNCOMMENT NEXT LINE IF WANTING TO PREVENT SLOW GRAPHS
  455. //$xStep = ($xStep > .01) ? $xStep : 0.01;
  456. if($xLow > $xHigh)
  457. list($xLow, $xHigh) = array($xHigh, $xLow); //swap function
  458. $xScale = $this->width/($xHigh-$xLow);
  459. $counter = 0;
  460. if(DEBUG) {
  461. $hand=fopen("eqgraph.txt","w");
  462. fwrite($hand, "$eq\n");
  463. }
  464. for($i=$xLow;$i<=$xHigh;$i+=$xStep) {
  465. $tester = sprintf("%10.3f",$i);
  466. if($tester == "-0.000") $i = 0;
  467. $y = $this->solveIF($eq, $i);
  468. //eval('$y='. str_replace('&x', $i, $eq).";"); /* used to debug my eqEOS class results */
  469. if(DEBUG) {
  470. $tmp1 = sprintf("y(%5.3f) = %10.3f\n", $i, $y);
  471. fwrite($hand, $tmp1);
  472. }
  473. // If developer asked us to find the upper and lower bounds for y...
  474. if($yGuess==true) {
  475. $yLow = ($yLow===false || ($y<$yLow)) ? $y : $yLow;
  476. $yHigh = ($yHigh===false || $y>$yHigh) ? $y : $yHigh;
  477. }
  478. $xVars[$counter] = $y;
  479. $counter++;
  480. }
  481. if(DEBUG)
  482. fclose($hand);
  483. // add 0.01 to each side so that if y is from 1 to 5, the lines at 1 and 5 are seen
  484. $yLow-=0.01;$yHigh+=0.01;
  485. //Now that we have all the variables stored...find the yScale
  486. $yScale = $this->height/(($yHigh)-($yLow));
  487. // if developer wanted a grid on the graph, add it now
  488. if($xyGrid==true) {
  489. for($i=ceil($yLow);$i<=floor($yHigh);$i++) {
  490. $i0 = abs($yHigh-$i);
  491. ImageLine($img, 0, $i0*$yScale, $this->width, $i0*$yScale, $grey);
  492. }
  493. for($i=ceil($xLow);$i<=floor($xHigh);$i++) {
  494. $i0 = abs($xLow-$i);
  495. ImageLine($img, $i0*$xScale, 0, $i0*$xScale, $this->height, $grey);
  496. }
  497. }
  498. //Now that we have the scales, let's see if we can draw an x/y-axis
  499. if($xLow <= 0 && $xHigh >= 0) {
  500. //the y-axis is within our range - draw it.
  501. $x0 = abs($xLow)*$xScale;
  502. ImageLine($img, $x0, 0, $x0, $this->height, $black);
  503. for($i=ceil($yLow);$i<=floor($yHigh);$i++) {
  504. $i0 = abs($yHigh-$i);
  505. ImageLine($img, $x0-3, $i0*$yScale, $x0+3, $i0*$yScale, $black);
  506. }
  507. }
  508. if($yLow <= 0 && $yHigh >= 0) {
  509. //the x-axis is within our range - draw it.
  510. $y0 = abs($yHigh)*$yScale;
  511. ImageLine($img, 0, $y0, $this->width, $y0, $black);
  512. for($i=ceil($xLow);$i<=floor($xHigh);$i++) {
  513. $i0 = abs($xLow-$i);
  514. ImageLine($img, $i0*$xScale, $y0-3, $i0*$xScale, $y0+3, $black);
  515. }
  516. }
  517. $counter=2;
  518. //now graph it all ;]
  519. for($i=$xLow+$xStep;$i<=$xHigh;$i+=$xStep) {
  520. $x1 = (abs($xLow - ($i - $xStep)))*$xScale;
  521. $y1 = (($xVars[$counter-1]<$yLow) || ($xVars[$counter-1] > $yHigh)) ? -1 : (abs($yHigh - $xVars[$counter-1]))*$yScale;
  522. $x2 = (abs($xLow - $i))*$xScale;
  523. $y2 = (($xVars[$counter]<$yLow) || ($xVars[$counter] > $yHigh)) ? -1 : (abs($yHigh - $xVars[$counter]))*$yScale;
  524. // if any of the y values were found to be off of the y-bounds, don't graph those connecting lines
  525. if($y1!=-1 && $y2!=-1)
  526. ImageLine($img, $x1, $y1, $x2, $y2, $black);
  527. $counter++;
  528. }
  529. $this->image = $img;
  530. } //end function 'graph'
  531. /**
  532. * Sends JPG to browser
  533. *
  534. * Sends a JPG image with proper header to output
  535. */
  536. public function outJPG() {
  537. header("Content-type: image/jpeg");
  538. ImageJpeg($this->image);
  539. }
  540. /**
  541. * Sends PNG to browser
  542. *
  543. * Sends a PNG image with proper header to output
  544. */
  545. function outPNG() {
  546. header("Content-type: image/png");
  547. ImagePng($this->image);
  548. }
  549. /**
  550. * Output GD Image
  551. *
  552. * Will give the developer the GD resource for the graph that
  553. * can be used to store the graph to the FS or other media
  554. *
  555. * @return Resource GD Image Resource
  556. */
  557. public function getImage() {
  558. return $this->image;
  559. }
  560. /**
  561. * Output GD Image
  562. *
  563. * Alias for eqGraph::getImage()
  564. *
  565. * @return Resource GD Image resource
  566. */
  567. public function outGD() {
  568. return $this->getImage();
  569. }
  570. } //end class 'eqGraph'
  571. ?>