PageRenderTime 63ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/plugins/stats/images/phplot/phplot.php

https://github.com/xong/rexsearch
PHP | 5338 lines | 3148 code | 684 blank | 1506 comment | 755 complexity | dc202a8d08392ca09306badf7e537cd3 MD5 | raw file
Possible License(s): LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /* $Id: phplot.php,v 1.167 2009/12/23 22:37:47 lbayuk Exp $ */
  3. /*
  4. * PHPLOT Version 5.1.0
  5. *
  6. * A PHP class for creating scientific and business charts
  7. * Visit http://sourceforge.net/projects/phplot/
  8. * for PHPlot documentation, downloads, and discussions.
  9. * ---------------------------------------------------------------------
  10. * Copyright (C) 1998-2009 Afan Ottenheimer
  11. *
  12. * This is free software; you can redistribute it and/or
  13. * modify it under the terms of the GNU Lesser General Public
  14. * License as published by the Free Software Foundation;
  15. * version 2.1 of the License.
  16. *
  17. * This software is distributed in the hope that it will be useful,
  18. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  20. * Lesser General Public License for more details.
  21. *
  22. * You should have received a copy of the GNU Lesser General Public
  23. * License along with this software; if not, write to the Free Software
  24. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  25. * ---------------------------------------------------------------------
  26. *
  27. * Co-author and maintainer (2003-2005)
  28. * Miguel de Benito Delgado <nonick AT vodafone DOT es>
  29. *
  30. * Maintainer (2006-present)
  31. * <lbayuk AT users DOT sourceforge DOT net>
  32. *
  33. * Requires PHP 5.2.x or later. (PHP 4 is unsupported as of Jan 2008)
  34. */
  35. class PHPlot {
  36. /* Declare class variables which are initialized to static values. Many more class variables
  37. * are used, defined as needed, but are unset by default.
  38. * All these are declared as public. While it is tempting to make them private or protected, this
  39. * is avoided for two reasons. First, it will break existing code, since all member variables
  40. * were public in PHP4 and who knows what internal variables people used. Second, it makes
  41. * testing harder and less effective. Nevertheless, your code should not modify these.
  42. */
  43. public $is_inline = FALSE; // FALSE = Sends headers, TRUE = sends just raw image data
  44. public $browser_cache = FALSE; // FALSE = Sends headers for browser to not cache the image,
  45. // (only if is_inline = FALSE also)
  46. public $print_image = TRUE; // DrawGraph calls PrintImage. See SetPrintImage
  47. public $background_done = FALSE; // TRUE after background image is drawn once
  48. public $safe_margin = 5; // Extra margin used in several places, in pixels
  49. public $x_axis_position = ''; // Where to draw both axis (world coordinates),
  50. public $y_axis_position = ''; // leave blank for X axis at 0 and Y axis at left of plot.
  51. public $xscale_type = 'linear'; // linear, log
  52. public $yscale_type = 'linear';
  53. //Fonts
  54. public $use_ttf = FALSE; // Use True Type Fonts by default?
  55. public $ttf_path = '.'; // Default path to look in for TT Fonts.
  56. public $default_ttfont = 'benjamingothic.ttf';
  57. public $line_spacing = 4; // Controls line spacing of multi-line labels
  58. // Label angles: 0 or 90 degrees for fixed fonts, any for TTF
  59. public $x_label_angle = 0; // For X tick labels
  60. // public $x_data_label_angle; // For X data labels; defaults to x_label_angle - see CheckLabels()
  61. public $y_label_angle = 0; // For Y tick labels
  62. public $y_data_label_angle = 0; // For Y data labels
  63. //Formats
  64. public $file_format = 'png';
  65. public $output_file = ''; // For output to a file instead of stdout
  66. //Data
  67. public $data_type = 'text-data'; // text-data, data-data-error, data-data, text-data-single
  68. public $plot_type= 'linepoints'; // bars, lines, linepoints, area, points, pie, thinbarline, squared
  69. public $label_scale_position = 0.5; // Shifts data labels in pie charts. 1 = top, 0 = bottom
  70. public $group_frac_width = 0.7; // Bars use this fraction (0 to 1) of a group's space
  71. public $bar_extra_space = 0.5; // Number of extra bar's worth of space in a group
  72. public $bar_width_adjust = 1; // 1 = bars of normal width, must be > 0
  73. // Titles
  74. public $title_txt = '';
  75. public $x_title_txt = '';
  76. public $x_title_pos = 'none'; // plotdown, plotup, both, none
  77. public $y_title_txt = '';
  78. public $y_title_pos = 'none'; // plotleft, plotright, both, none
  79. //Labels
  80. // There are two types of labels in PHPlot:
  81. // Tick labels: they follow the grid, next to ticks in axis.
  82. // they are drawn at grid drawing time, by DrawXTicks() and DrawYTicks()
  83. // Data labels: they follow the data points, and can be placed on the axis or the plot (x/y)
  84. // they are drawn at graph plotting time, by Draw*DataLabel(), called by DrawLines(), etc.
  85. // Draw*DataLabel() also draws H/V lines to datapoints depending on draw_*_data_label_lines
  86. // Tick Labels
  87. // x_tick_label_pos and x_data_label_pos are not initialized, because PHPlot needs
  88. // to determine if they were defaulted or set by the user. See CheckLabels().
  89. // public $x_tick_label_pos = 'plotdown'; // plotdown, plotup, both, xaxis, none
  90. public $y_tick_label_pos = 'plotleft'; // plotleft, plotright, both, yaxis, none
  91. // Data Labels:
  92. // public $x_data_label_pos = 'plotdown'; // plotdown, plotup, both, plot, all, none
  93. public $y_data_label_pos = 'none'; // plotleft, plotright, both, plot, all, plotin, none
  94. public $draw_x_data_label_lines = FALSE; // Draw a line from the data point to the axis?
  95. // Label format controls: (for tick, data and plot labels)
  96. // Unset by default, these array members are used as needed for 'x' (x tick labels), 'xd' (x data
  97. // labels), 'y' (y tick labels), and 'yd' (y data labels).
  98. // type, precision, prefix, suffix, time_format, printf_format, custom_callback, custom_arg.
  99. // These replace the former: x_label_type, x_time_format, x_precision (similar for y), data_units_text.
  100. public $label_format = array('x' => array(), 'xd' => array(), 'y' => array(), 'yd' => array());
  101. // data_units_text is retained for backward compatibility, because there was never a function
  102. // to set it. Use the 'suffix' argument to Set[XY]LabelType instead.
  103. public $data_units_text = ''; // Units text for 'data' labels (i.e: '¤', '$', etc.)
  104. // Legend
  105. public $legend = ''; // An array with legend titles
  106. // These variables are unset to take default values:
  107. // public $legend_x_pos; // User-specified upper left coordinates of legend box
  108. // public $legend_y_pos;
  109. // public $legend_xy_world; // If set, legend_x/y_pos are world coords, else pixel coords
  110. // public $legend_text_align; // left or right, Unset means right
  111. // public $legend_colorbox_align; // left, right, or none; Unset means same as text_align
  112. //Ticks
  113. public $x_tick_length = 5; // tick length in pixels for upper/lower axis
  114. public $y_tick_length = 5; // tick length in pixels for left/right axis
  115. public $x_tick_cross = 3; // ticks cross x axis this many pixels
  116. public $y_tick_cross = 3; // ticks cross y axis this many pixels
  117. public $x_tick_pos = 'plotdown'; // plotdown, plotup, both, xaxis, none
  118. public $y_tick_pos = 'plotleft'; // plotright, plotleft, both, yaxis, none
  119. public $num_x_ticks = '';
  120. public $num_y_ticks = '';
  121. public $x_tick_inc = ''; // Set num_x_ticks or x_tick_inc, not both.
  122. public $y_tick_inc = ''; // Set num_y_ticks or y_tick_inc, not both.
  123. public $skip_top_tick = FALSE;
  124. public $skip_bottom_tick = FALSE;
  125. public $skip_left_tick = FALSE;
  126. public $skip_right_tick = FALSE;
  127. //Grid Formatting
  128. public $draw_x_grid = FALSE;
  129. public $draw_y_grid = TRUE;
  130. public $dashed_grid = TRUE;
  131. public $grid_at_foreground = FALSE; // Chooses whether to draw the grid below or above the graph
  132. //Colors and styles (all colors can be array (R,G,B) or named color)
  133. public $color_array = 'small'; // 'small', 'large' or array (define your own colors)
  134. // See rgb.inc.php and SetRGBArray()
  135. public $i_border = array(194, 194, 194);
  136. public $plot_bg_color = 'white';
  137. public $bg_color = 'white';
  138. public $label_color = 'black';
  139. public $text_color = 'black';
  140. public $grid_color = 'black';
  141. public $light_grid_color = 'gray';
  142. public $tick_color = 'black';
  143. public $title_color = 'black';
  144. public $default_colors = array( // The default colors for data and error bars
  145. 'SkyBlue', 'green', 'orange', 'blue', 'red', 'DarkGreen', 'purple', 'peru',
  146. 'cyan', 'salmon', 'SlateBlue', 'YellowGreen', 'magenta', 'aquamarine1', 'gold', 'violet');
  147. // data_colors and error_bar_colors are initialized to default_colors by SetDefaultStyles.
  148. // public $data_colors; // Data colors
  149. // public $error_bar_colors; // Error bar colors
  150. // data_border_colors is initialized to black by SetDefaultStyles.
  151. // public $data_border_colors; // Data border colors
  152. public $line_widths = 1; // single value or array
  153. public $line_styles = array('solid', 'solid', 'dashed'); // single value or array
  154. public $dashed_style = '2-4'; // colored dots-transparent dots
  155. public $point_sizes = array(6); // Array of sizes for points. See CheckPointParams()
  156. public $point_shapes = array( // Array of point shapes. See SetPointShapes() and DrawDot()
  157. 'diamond', 'dot', 'delta', 'home', 'yield', 'box', 'circle', 'up', 'down', 'cross'
  158. );
  159. public $error_bar_size = 5; // right and left size of tee
  160. public $error_bar_shape = 'tee'; // 'tee' or 'line'
  161. public $error_bar_line_width = 1; // single value (or array TODO)
  162. public $plot_border_type = 'sides'; // left, sides, none, full
  163. public $image_border_type = 'none'; // 'raised', 'plain', 'none'
  164. public $shading = 5; // 0 for no shading, > 0 is size of shadows in pixels
  165. public $draw_plot_area_background = FALSE;
  166. public $draw_broken_lines = FALSE; // Tells not to draw lines for missing Y data.
  167. //Miscellaneous
  168. public $callbacks = array( // Valid callback reasons (see SetCallBack)
  169. 'draw_setup' => NULL,
  170. 'draw_image_background' => NULL,
  171. 'draw_plotarea_background' => NULL,
  172. 'draw_titles' => NULL,
  173. 'draw_axes' => NULL,
  174. 'draw_graph' => NULL,
  175. 'draw_border' => NULL,
  176. 'draw_legend' => NULL,
  177. 'draw_all' => NULL,
  178. 'debug_textbox' => NULL, // For testing/debugging text box alignment
  179. 'debug_scale' => NULL, // For testing/debugging scale setup
  180. );
  181. //////////////////////////////////////////////////////
  182. //BEGIN CODE
  183. //////////////////////////////////////////////////////
  184. /*!
  185. * Constructor: Setup img resource, colors and size of the image, and font sizes.
  186. *
  187. * \param which_width int Image width in pixels.
  188. * \param which_height int Image height in pixels.
  189. * \param which_output_file string Filename for output.
  190. * \param which_input_file string Path to a file to be used as background.
  191. */
  192. function PHPlot($which_width=600, $which_height=400, $which_output_file=NULL, $which_input_file=NULL)
  193. {
  194. $this->SetRGBArray($this->color_array);
  195. if ($which_output_file)
  196. $this->SetOutputFile($which_output_file);
  197. if ($which_input_file)
  198. $this->SetInputFile($which_input_file);
  199. else {
  200. $this->image_width = $which_width;
  201. $this->image_height = $which_height;
  202. $this->img = ImageCreate($this->image_width, $this->image_height);
  203. if (! $this->img)
  204. return $this->PrintError('PHPlot(): Could not create image resource.');
  205. }
  206. $this->SetDefaultStyles();
  207. $this->SetDefaultFonts();
  208. }
  209. /*!
  210. * Reads an image file. Stores width and height, and returns the image
  211. * resource. On error, calls PrintError and returns False.
  212. * This is used by the constructor via SetInputFile, and by tile_img().
  213. */
  214. protected function GetImage($image_filename, &$width, &$height)
  215. {
  216. $error = '';
  217. $size = getimagesize($image_filename);
  218. if (!$size) {
  219. $error = "Unable to query image file $image_filename";
  220. } else {
  221. $image_type = $size[2];
  222. switch($image_type) {
  223. case IMAGETYPE_GIF:
  224. $img = @ ImageCreateFromGIF ($image_filename);
  225. break;
  226. case IMAGETYPE_PNG:
  227. $img = @ ImageCreateFromPNG ($image_filename);
  228. break;
  229. case IMAGETYPE_JPEG:
  230. $img = @ ImageCreateFromJPEG ($image_filename);
  231. break;
  232. default:
  233. $error = "Unknown image type ($image_type) for image file $image_filename";
  234. break;
  235. }
  236. }
  237. if (empty($error) && !$img) {
  238. # getimagesize is OK, but GD won't read it. Maybe unsupported format.
  239. $error = "Failed to read image file $image_filename";
  240. }
  241. if (!empty($error)) {
  242. return $this->PrintError("GetImage(): $error");
  243. }
  244. $width = $size[0];
  245. $height = $size[1];
  246. return $img;
  247. }
  248. /*!
  249. * Selects an input file to be used as background for the whole graph.
  250. * This resets the graph size to the image's size.
  251. * Note: This is used by the constructor. It is deprecated for direct use.
  252. */
  253. function SetInputFile($which_input_file)
  254. {
  255. $im = $this->GetImage($which_input_file, $this->image_width, $this->image_height);
  256. if (!$im)
  257. return FALSE; // GetImage already produced an error message.
  258. // Deallocate any resources previously allocated
  259. if (isset($this->img))
  260. imagedestroy($this->img);
  261. $this->img = $im;
  262. // Do not overwrite the input file with the background color.
  263. $this->background_done = TRUE;
  264. return TRUE;
  265. }
  266. /////////////////////////////////////////////
  267. ////////////// COLORS
  268. /////////////////////////////////////////////
  269. /*!
  270. * Returns an index to a color passed in as anything (string, hex, rgb)
  271. *
  272. * \param which_color * Color (can be '#AABBCC', 'Colorname', or array(r,g,b))
  273. * Returns a GD color index (integer >= 0), or NULL on error.
  274. */
  275. function SetIndexColor($which_color)
  276. {
  277. list ($r, $g, $b) = $this->SetRGBColor($which_color); //Translate to RGB
  278. if (!isset($r)) return NULL;
  279. return ImageColorResolve($this->img, $r, $g, $b);
  280. }
  281. /*!
  282. * Returns an index to a slightly darker color than the one requested.
  283. * Returns a GD color index (integer >= 0), or NULL on error.
  284. */
  285. protected function SetIndexDarkColor($which_color)
  286. {
  287. list ($r, $g, $b) = $this->SetRGBColor($which_color);
  288. if (!isset($r)) return NULL;
  289. $r = max(0, $r - 0x30);
  290. $g = max(0, $g - 0x30);
  291. $b = max(0, $b - 0x30);
  292. return ImageColorResolve($this->img, $r, $g, $b);
  293. }
  294. /*!
  295. * Sets/reverts all colors and styles to their defaults.
  296. */
  297. protected function SetDefaultStyles()
  298. {
  299. /* Some of the Set*() functions use default values when they get no parameters. */
  300. $this->SetDefaultDashedStyle($this->dashed_style);
  301. $this->SetImageBorderColor($this->i_border);
  302. $this->SetPlotBgColor($this->plot_bg_color);
  303. $this->SetBackgroundColor($this->bg_color);
  304. $this->SetLabelColor($this->label_color);
  305. $this->SetTextColor($this->text_color);
  306. $this->SetGridColor($this->grid_color);
  307. $this->SetLightGridColor($this->light_grid_color);
  308. $this->SetTickColor($this->tick_color);
  309. $this->SetTitleColor($this->title_color);
  310. $this->SetDataColors();
  311. $this->SetErrorBarColors();
  312. $this->SetDataBorderColors();
  313. return TRUE;
  314. }
  315. /*
  316. *
  317. */
  318. function SetBackgroundColor($which_color)
  319. {
  320. $this->bg_color= $which_color;
  321. $this->ndx_bg_color= $this->SetIndexColor($this->bg_color);
  322. return isset($this->ndx_bg_color);
  323. }
  324. /*
  325. *
  326. */
  327. function SetPlotBgColor($which_color)
  328. {
  329. $this->plot_bg_color= $which_color;
  330. $this->ndx_plot_bg_color= $this->SetIndexColor($this->plot_bg_color);
  331. return isset($this->ndx_plot_bg_color);
  332. }
  333. /*
  334. *
  335. */
  336. function SetTitleColor($which_color)
  337. {
  338. $this->title_color= $which_color;
  339. $this->ndx_title_color= $this->SetIndexColor($this->title_color);
  340. return isset($this->ndx_title_color);
  341. }
  342. /*
  343. *
  344. */
  345. function SetTickColor ($which_color)
  346. {
  347. $this->tick_color= $which_color;
  348. $this->ndx_tick_color= $this->SetIndexColor($this->tick_color);
  349. return isset($this->ndx_tick_color);
  350. }
  351. /*
  352. * Do not use. Use SetTitleColor instead.
  353. */
  354. function SetLabelColor ($which_color)
  355. {
  356. $this->label_color = $which_color;
  357. $this->ndx_title_color= $this->SetIndexColor($this->label_color);
  358. return isset($this->ndx_title_color);
  359. }
  360. /*
  361. *
  362. */
  363. function SetTextColor ($which_color)
  364. {
  365. $this->text_color= $which_color;
  366. $this->ndx_text_color= $this->SetIndexColor($this->text_color);
  367. return isset($this->ndx_text_color);
  368. }
  369. /*
  370. *
  371. */
  372. function SetLightGridColor ($which_color)
  373. {
  374. $this->light_grid_color= $which_color;
  375. $this->ndx_light_grid_color= $this->SetIndexColor($this->light_grid_color);
  376. return isset($this->ndx_light_grid_color);
  377. }
  378. /*
  379. *
  380. */
  381. function SetGridColor ($which_color)
  382. {
  383. $this->grid_color = $which_color;
  384. $this->ndx_grid_color= $this->SetIndexColor($this->grid_color);
  385. return isset($this->ndx_grid_color);
  386. }
  387. /*
  388. *
  389. */
  390. function SetImageBorderColor($which_color)
  391. {
  392. $this->i_border = $which_color;
  393. $this->ndx_i_border = $this->SetIndexColor($this->i_border);
  394. $this->ndx_i_border_dark = $this->SetIndexDarkColor($this->i_border);
  395. return isset($this->ndx_i_border);
  396. }
  397. /*
  398. *
  399. */
  400. function SetTransparentColor($which_color)
  401. {
  402. $ndx = $this->SetIndexColor($which_color);
  403. if (!isset($ndx))
  404. return FALSE;
  405. ImageColorTransparent($this->img, $ndx);
  406. return TRUE;
  407. }
  408. /*!
  409. * Sets the array of colors to be used. It can be user defined, a small predefined one
  410. * or a large one included from 'rgb.inc.php'.
  411. *
  412. * \param which_color_array If an array, the used as color array. If a string can
  413. * be one of 'small' or 'large'.
  414. */
  415. function SetRGBArray ($which_color_array)
  416. {
  417. if ( is_array($which_color_array) ) { // User defined array
  418. $this->rgb_array = $which_color_array;
  419. return TRUE;
  420. } elseif ($which_color_array == 'small') { // Small predefined color array
  421. $this->rgb_array = array(
  422. 'white' => array(255, 255, 255),
  423. 'snow' => array(255, 250, 250),
  424. 'PeachPuff' => array(255, 218, 185),
  425. 'ivory' => array(255, 255, 240),
  426. 'lavender' => array(230, 230, 250),
  427. 'black' => array( 0, 0, 0),
  428. 'DimGrey' => array(105, 105, 105),
  429. 'gray' => array(190, 190, 190),
  430. 'grey' => array(190, 190, 190),
  431. 'navy' => array( 0, 0, 128),
  432. 'SlateBlue' => array(106, 90, 205),
  433. 'blue' => array( 0, 0, 255),
  434. 'SkyBlue' => array(135, 206, 235),
  435. 'cyan' => array( 0, 255, 255),
  436. 'DarkGreen' => array( 0, 100, 0),
  437. 'green' => array( 0, 255, 0),
  438. 'YellowGreen' => array(154, 205, 50),
  439. 'yellow' => array(255, 255, 0),
  440. 'orange' => array(255, 165, 0),
  441. 'gold' => array(255, 215, 0),
  442. 'peru' => array(205, 133, 63),
  443. 'beige' => array(245, 245, 220),
  444. 'wheat' => array(245, 222, 179),
  445. 'tan' => array(210, 180, 140),
  446. 'brown' => array(165, 42, 42),
  447. 'salmon' => array(250, 128, 114),
  448. 'red' => array(255, 0, 0),
  449. 'pink' => array(255, 192, 203),
  450. 'maroon' => array(176, 48, 96),
  451. 'magenta' => array(255, 0, 255),
  452. 'violet' => array(238, 130, 238),
  453. 'plum' => array(221, 160, 221),
  454. 'orchid' => array(218, 112, 214),
  455. 'purple' => array(160, 32, 240),
  456. 'azure1' => array(240, 255, 255),
  457. 'aquamarine1' => array(127, 255, 212)
  458. );
  459. return TRUE;
  460. } elseif ($which_color_array === 'large') { // Large color array
  461. if (!@include('rgb.inc.php')) {
  462. return $this->PrintError("SetRGBArray(): Large color map could not be loaded\n"
  463. . "from 'rgb.inc.php'.");
  464. }
  465. $this->rgb_array = $ColorArray;
  466. } else { // Default to black and white only.
  467. $this->rgb_array = array('white' => array(255, 255, 255), 'black' => array(0, 0, 0));
  468. }
  469. return TRUE;
  470. }
  471. /*!
  472. * Returns an array in R, G, B format 0-255
  473. *
  474. * \param color_asked array(R,G,B) or string (named color or '#AABBCC')
  475. * Note: This method should be 'protected', but is called from test script(s).
  476. */
  477. function SetRGBColor($color_asked)
  478. {
  479. if (empty($color_asked)) {
  480. $ret_val = array(0, 0, 0);
  481. } elseif (count($color_asked) == 3 ) { // already array of 3 rgb
  482. $ret_val = $color_asked;
  483. } elseif ($color_asked[0] == '#') { // Hex RGB notation #RRGGBB
  484. $ret_val = array(hexdec(substr($color_asked, 1, 2)),
  485. hexdec(substr($color_asked, 3, 2)),
  486. hexdec(substr($color_asked, 5, 2)));
  487. } elseif (isset($this->rgb_array[$color_asked])) { // Color by name
  488. $ret_val = $this->rgb_array[$color_asked];
  489. } else {
  490. return $this->PrintError("SetRGBColor(): Color '$color_asked' is not valid.");
  491. }
  492. return $ret_val;
  493. }
  494. /*!
  495. * Sets the colors for the data.
  496. * Cases are:
  497. * SetDataColors(array(...)) : Use the supplied array as the color map.
  498. * SetDataColors(colorname) : Use an array of just colorname as the color map.
  499. * SetDataColors() or SetDataColors(NULL) : Load default color map if no color map is already set.
  500. * SetDataColors('') or SetDataColors(False) : Load default color map (even if one is already set).
  501. */
  502. function SetDataColors($which_data = NULL, $which_border = NULL)
  503. {
  504. if (is_array($which_data)) {
  505. $this->data_colors = $which_data; // Use supplied array
  506. } elseif (!empty($which_data)) {
  507. $this->data_colors = array($which_data); // Use supplied single color
  508. } elseif (empty($this->data_colors) || !is_null($which_data)) {
  509. $this->data_colors = $this->default_colors; // Use default color array
  510. } // Else do nothing: which_data is NULL or missing and a color array is already set.
  511. $i = 0;
  512. foreach ($this->data_colors as $col) {
  513. $ndx = $this->SetIndexColor($col);
  514. if (!isset($ndx))
  515. return FALSE;
  516. $this->ndx_data_colors[$i] = $ndx;
  517. $this->ndx_data_dark_colors[$i] = $this->SetIndexDarkColor($col);
  518. $i++;
  519. }
  520. // For past compatibility:
  521. return $this->SetDataBorderColors($which_border);
  522. } // function SetDataColors()
  523. /*!
  524. * Set the colors for the bars and stacked bars outlines.
  525. * Argument usage is similar to SetDataColors(), except the default is just black.
  526. */
  527. function SetDataBorderColors($which_br = NULL)
  528. {
  529. if (is_array($which_br)) {
  530. $this->data_border_colors = $which_br; // Use supplied array
  531. } elseif (!empty($which_br)) {
  532. $this->data_border_colors = array($which_br); // Use supplied single color
  533. } elseif (empty($this->data_border_colors) || !is_null($which_br)) {
  534. $this->data_border_colors = array('black'); // Use default
  535. } // Else do nothing: which_br is NULL or missing and a color array is already set.
  536. $i = 0;
  537. foreach($this->data_border_colors as $col) {
  538. $ndx = $this->SetIndexColor($col);
  539. if (!isset($ndx))
  540. return FALSE;
  541. $this->ndx_data_border_colors[$i] = $ndx;
  542. $i++;
  543. }
  544. return TRUE;
  545. } // function SetDataBorderColors()
  546. /*!
  547. * Sets the colors for the data error bars.
  548. * Argument usage is the same as SetDataColors().
  549. */
  550. function SetErrorBarColors($which_err = NULL)
  551. {
  552. if (is_array($which_err)) {
  553. $this->error_bar_colors = $which_err; // Use supplied array
  554. } elseif (!empty($which_err)) {
  555. $this->error_bar_colors = array($which_err); // Use supplied single color
  556. } elseif (empty($this->error_bar_colors) || !is_null($which_err)) {
  557. $this->error_bar_colors = $this->default_colors; // Use default color array
  558. } // Else do nothing: which_err is NULL or missing and a color array is already set.
  559. $i = 0;
  560. foreach($this->error_bar_colors as $col) {
  561. $ndx = $this->SetIndexColor($col);
  562. if (!isset($ndx))
  563. return FALSE;
  564. $this->ndx_error_bar_colors[$i] = $ndx;
  565. $i++;
  566. }
  567. return TRUE;
  568. } // function SetErrorBarColors()
  569. /*!
  570. * Sets the default dashed style.
  571. * \param which_style A string specifying order of colored and transparent dots,
  572. * i.e: '4-3' means 4 colored, 3 transparent;
  573. * '2-3-1-2' means 2 colored, 3 transparent, 1 colored, 2 transparent.
  574. */
  575. function SetDefaultDashedStyle($which_style)
  576. {
  577. // String: "numcol-numtrans-numcol-numtrans..."
  578. $asked = explode('-', $which_style);
  579. if (count($asked) < 2) {
  580. return $this->PrintError("SetDefaultDashedStyle(): Wrong parameter '$which_style'.");
  581. }
  582. // Build the string to be eval()uated later by SetDashedStyle()
  583. $this->default_dashed_style = 'array( ';
  584. $t = 0;
  585. foreach($asked as $s) {
  586. if ($t % 2 == 0) {
  587. $this->default_dashed_style .= str_repeat('$which_ndxcol,', $s);
  588. } else {
  589. $this->default_dashed_style .= str_repeat('IMG_COLOR_TRANSPARENT,', $s);
  590. }
  591. $t++;
  592. }
  593. // Remove trailing comma and add closing parenthesis
  594. $this->default_dashed_style = substr($this->default_dashed_style, 0, -1);
  595. $this->default_dashed_style .= ')';
  596. return TRUE;
  597. }
  598. /*!
  599. * Sets the style before drawing a dashed line. Defaults to $this->default_dashed_style
  600. * \param which_ndxcol Color index to be used.
  601. */
  602. protected function SetDashedStyle($which_ndxcol)
  603. {
  604. // See SetDefaultDashedStyle() to understand this.
  605. eval ("\$style = $this->default_dashed_style;");
  606. return imagesetstyle($this->img, $style);
  607. }
  608. /*!
  609. * Sets line widths on a per-line basis.
  610. */
  611. function SetLineWidths($which_lw=NULL)
  612. {
  613. if (is_null($which_lw)) {
  614. // Do nothing, use default value.
  615. } else if (is_array($which_lw)) {
  616. // Did we get an array with line widths?
  617. $this->line_widths = $which_lw;
  618. } else {
  619. $this->line_widths = array($which_lw);
  620. }
  621. return TRUE;
  622. }
  623. /*!
  624. *
  625. */
  626. function SetLineStyles($which_ls=NULL)
  627. {
  628. if (is_null($which_ls)) {
  629. // Do nothing, use default value.
  630. } else if ( is_array($which_ls)) {
  631. // Did we get an array with line styles?
  632. $this->line_styles = $which_ls;
  633. } else {
  634. $this->line_styles = ($which_ls) ? array($which_ls) : array('solid');
  635. }
  636. return TRUE;
  637. }
  638. /////////////////////////////////////////////
  639. ////////////// TEXT and FONTS
  640. /////////////////////////////////////////////
  641. /*!
  642. * Controls the line spacing of multi-line labels.
  643. * For GD text, this is the number of pixels between lines.
  644. * For TTF text, it controls line spacing in proportion to the normal
  645. * spacing defined by the font.
  646. */
  647. function SetLineSpacing($which_spc)
  648. {
  649. $this->line_spacing = $which_spc;
  650. return TRUE;
  651. }
  652. /*!
  653. * Select the default font type to use.
  654. * $which_ttf : True to default to TrueType, False to default to GD (fixed) fonts.
  655. * This also resets all font settings to the defaults.
  656. */
  657. function SetUseTTF($which_ttf)
  658. {
  659. $this->use_ttf = $which_ttf;
  660. return $this->SetDefaultFonts();
  661. }
  662. /*!
  663. * Sets the directory name to look into for TrueType fonts.
  664. */
  665. function SetTTFPath($which_path)
  666. {
  667. // Maybe someone needs really dynamic config. He'll need this:
  668. // clearstatcache();
  669. if (is_dir($which_path) && is_readable($which_path)) {
  670. $this->ttf_path = $which_path;
  671. return TRUE;
  672. }
  673. return $this->PrintError("SetTTFPath(): $which_path is not a valid path.");
  674. }
  675. /*!
  676. * Sets the default TrueType font and updates all fonts to that.
  677. * The default font might be a full path, or relative to the TTFPath,
  678. * so let SetFont check that it exists.
  679. * Side effects: Enables use of TrueType fonts as the default font type,
  680. * and resets all font settings.
  681. */
  682. function SetDefaultTTFont($which_font)
  683. {
  684. $this->default_ttfont = $which_font;
  685. return $this->SetUseTTF(TRUE);
  686. }
  687. /*!
  688. * Sets fonts to their defaults
  689. */
  690. protected function SetDefaultFonts()
  691. {
  692. // TTF:
  693. if ($this->use_ttf) {
  694. return $this->SetFont('generic', '', 8)
  695. && $this->SetFont('title', '', 14)
  696. && $this->SetFont('legend', '', 8)
  697. && $this->SetFont('x_label', '', 6)
  698. && $this->SetFont('y_label', '', 6)
  699. && $this->SetFont('x_title', '', 10)
  700. && $this->SetFont('y_title', '', 10);
  701. }
  702. // Fixed GD Fonts:
  703. return $this->SetFont('generic', 2)
  704. && $this->SetFont('title', 5)
  705. && $this->SetFont('legend', 2)
  706. && $this->SetFont('x_label', 1)
  707. && $this->SetFont('y_label', 1)
  708. && $this->SetFont('x_title', 3)
  709. && $this->SetFont('y_title', 3);
  710. }
  711. /*
  712. * Select a fixed (GD) font for an element.
  713. * This allows using a fixed font, even with SetUseTTF(True).
  714. * $which_elem : The element whose font is to be changed.
  715. * One of: title legend generic x_label y_label x_title y_title
  716. * $which_font : A GD font number 1-5
  717. * $which_spacing (optional) : Line spacing factor
  718. */
  719. function SetFontGD($which_elem, $which_font, $which_spacing = NULL)
  720. {
  721. if ($which_font < 1 || 5 < $which_font) {
  722. return $this->PrintError(__FUNCTION__ . ': Font size must be 1, 2, 3, 4 or 5');
  723. }
  724. if (!$this->CheckOption($which_elem,
  725. 'generic, title, legend, x_label, y_label, x_title, y_title',
  726. __FUNCTION__)) {
  727. return FALSE;
  728. }
  729. # Store the font parameters: name/size, char cell height and width.
  730. $this->fonts[$which_elem] = array('ttf' => FALSE,
  731. 'font' => $which_font,
  732. 'height' => ImageFontHeight($which_font),
  733. 'width' => ImageFontWidth($which_font),
  734. 'line_spacing' => $which_spacing);
  735. return TRUE;
  736. }
  737. /*
  738. * Select a TrueType font for an element.
  739. * This allows using a TrueType font, even with SetUseTTF(False).
  740. * $which_elem : The element whose font is to be changed.
  741. * One of: title legend generic x_label y_label x_title y_title
  742. * $which_font : A TrueType font filename or pathname.
  743. * $which_size : Font point size.
  744. * $which_spacing (optional) : Line spacing factor
  745. */
  746. function SetFontTTF($which_elem, $which_font, $which_size = 12, $which_spacing = NULL)
  747. {
  748. if (!$this->CheckOption($which_elem,
  749. 'generic, title, legend, x_label, y_label, x_title, y_title',
  750. __FUNCTION__)) {
  751. return FALSE;
  752. }
  753. # Empty font name means use the default font.
  754. if (empty($which_font))
  755. $which_font = $this->default_ttfont;
  756. $path = $which_font;
  757. # First try the font name directly, if not then try with path.
  758. if (!is_file($path) || !is_readable($path)) {
  759. $path = $this->ttf_path . DIRECTORY_SEPARATOR . $which_font;
  760. if (!is_file($path) || !is_readable($path)) {
  761. return $this->PrintError(__FUNCTION__ . ": Can't find TrueType font $which_font");
  762. }
  763. }
  764. # Calculate the font height and inherent line spacing. TrueType fonts have this information
  765. # internally, but PHP/GD has no way to directly access it. So get the bounding box size of
  766. # an upper-case character without descenders, and the baseline-to-baseline height.
  767. # Note: In practice, $which_size = $height, maybe +/-1 . But which_size is in points,
  768. # and height is in pixels, and someday GD may be able to tell the difference.
  769. # The character width is saved too, but not used by the normal text drawing routines - it
  770. # isn't necessarily a fixed-space font. It is used in DrawLegend.
  771. $bbox = ImageTTFBBox($which_size, 0, $path, "E");
  772. $height = $bbox[1] - $bbox[5];
  773. $width = $bbox[2] - $bbox[0];
  774. $bbox = ImageTTFBBox($which_size, 0, $path, "E\nE");
  775. $spacing = $bbox[1] - $bbox[5] - 2 * $height;
  776. # Store the font parameters:
  777. $this->fonts[$which_elem] = array('ttf' => TRUE,
  778. 'font' => $path,
  779. 'size' => $which_size,
  780. 'height' => $height,
  781. 'width' => $width,
  782. 'spacing' => $spacing,
  783. 'line_spacing' => $which_spacing);
  784. return TRUE;
  785. }
  786. /*
  787. * Select Fixed/TrueType font for an element. Which type of font is
  788. * selected depends on the $use_ttf class variable (see SetUseTTF()).
  789. * Before PHPlot supported mixing font types, only this function and
  790. * SetUseTTF were available to select an overall font type, but now
  791. * SetFontGD() and SetFontTTF() can be used for mixing font types.
  792. * $which_elem : The element whose font is to be changed.
  793. * One of: title legend generic x_label y_label x_title y_title
  794. * $which_font : A number 1-5 for fixed fonts, or a TrueType font.
  795. * $which_size : Ignored for Fixed fonts, point size for TrueType.
  796. * $which_spacing (optional) : Line spacing factor
  797. */
  798. function SetFont($which_elem, $which_font, $which_size = 12, $line_spacing = NULL)
  799. {
  800. if ($this->use_ttf)
  801. return $this->SetFontTTF($which_elem, $which_font, $which_size, $line_spacing);
  802. return $this->SetFontGD($which_elem, $which_font, $line_spacing);
  803. }
  804. /*
  805. * Return the inter-line spacing for a font.
  806. * This is an internal function, used by ProcessText* and DrawLegend.
  807. * $font : A font array variable.
  808. * Returns: Spacing, in pixels, between text lines.
  809. */
  810. protected function GetLineSpacing($font)
  811. {
  812. # Use the per-font line spacing preference, if set, else the global value:
  813. if (isset($font['line_spacing']))
  814. $line_spacing = $font['line_spacing'];
  815. else
  816. $line_spacing = $this->line_spacing;
  817. # For GD fonts, that is the spacing in pixels.
  818. # For TTF, adjust based on the 'natural' font spacing (see SetFontTTF):
  819. if ($font['ttf']) {
  820. $line_spacing = (int)($line_spacing * $font['spacing'] / 6.0);
  821. }
  822. return $line_spacing;
  823. }
  824. /*!
  825. * Text drawing and sizing functions:
  826. * ProcessText is meant for use only by DrawText and SizeText.
  827. * ProcessText(True, ...) - Draw a block of text
  828. * ProcessText(False, ...) - Just return ($width, $height) of
  829. * the orthogonal bounding box containing the text.
  830. * ProcessText is further split into separate functions for GD and TTF
  831. * text, due to the size of the code.
  832. *
  833. * Horizontal and vertical alignment are relative to the drawing. That is:
  834. * vertical text (90 deg) gets centered along Y position with
  835. * v_align = 'center', and adjusted to the right of X position with
  836. * h_align = 'right'. Another way to look at this is to say
  837. * that text rotation happens first, then alignment.
  838. *
  839. * Original multiple lines code submitted by Remi Ricard.
  840. * Original vertical code submitted by Marlin Viss.
  841. *
  842. * Text routines rewritten by ljb to fix alignment and position problems.
  843. * Here is my explanation and notes. More information and pictures will be
  844. * placed in the PHPlot Reference Manual.
  845. *
  846. * + Process TTF text one line at a time, not as a block. (See below)
  847. * + Flipped top vs bottom vertical alignment. The usual interpretation
  848. * is: bottom align means bottom of the text is at the specified Y
  849. * coordinate. For some reason, PHPlot did left/right the correct way,
  850. * but had top/bottom reversed. I fixed it, and left the default valign
  851. * argument as bottom, but the meaning of the default value changed.
  852. *
  853. * For GD font text, only single-line text is handled by GD, and the
  854. * basepoint is the upper left corner of each text line.
  855. * For TTF text, multi-line text could be handled by GD, with the text
  856. * basepoint at the lower left corner of the first line of text.
  857. * (Behavior of TTF drawing routines on multi-line text is not documented.)
  858. * But you cannot do left/center/right alignment on each line that way,
  859. * or proper line spacing.
  860. * Therefore, for either text type, we have to break up the text into
  861. * lines and position each line independently.
  862. *
  863. * There are 9 alignment modes: Horizontal = left, center, or right, and
  864. * Vertical = top, center, or bottom. Alignment is interpreted relative to
  865. * the image, not as the text is read. This makes sense when you consider
  866. * for example X axis labels. They need to be centered below the marks
  867. * (center, top alignment) regardless of the text angle.
  868. * 'Bottom' alignment really means baseline alignment.
  869. *
  870. * GD font text is supported (by libgd) at 0 degrees and 90 degrees only.
  871. * Multi-line or single line text works with any of the 9 alignment modes.
  872. *
  873. * TTF text can be at any angle. The 9 alignment modes work for all angles,
  874. * but the results might not be what you expect for multi-line text. See
  875. * the PHPlot Reference Manual for pictures and details. In short, alignment
  876. * applies to the orthogonal (aligned with X and Y axes) bounding box that
  877. * contains the text, and to each line in the multi-line text box. Since
  878. * alignment is relative to the image, 45 degree multi-line text aligns
  879. * differently from 46 degree text.
  880. *
  881. * Note that PHPlot allows multi-line text for the 3 titles, and they
  882. * are only drawn at 0 degrees (main and X titles) or 90 degrees (Y title).
  883. * Data labels can also be multi-line, and they can be drawn at any angle.
  884. * -ljb 2007-11-03
  885. *
  886. */
  887. /*
  888. * ProcessTextGD() - Draw or size GD fixed-font text.
  889. * This is intended for use only by ProcessText().
  890. * $draw_it : True to draw the text, False to just return the orthogonal width and height.
  891. * $font : PHPlot font array (with 'ttf' = False) - see SetFontGD()
  892. * $angle : Text angle in degrees. GD only supports 0 and 90. We treat >= 45 as 90, else 0.
  893. * $x, $y : Reference point for the text (ignored if !$draw_it)
  894. * $color : GD color index to use for drawing the text (ignored if !$draw_it)
  895. * $text : The text to draw or size. Put a newline between lines.
  896. * $h_factor : Horizontal alignment factor: 0(left), .5(center), or 1(right) (ignored if !$draw_it)
  897. * $v_factor : Vertical alignment factor: 0(top), .5(center), or 1(bottom) (ignored if !$draw_it)
  898. * Returns: True, if drawing text, or an array of ($width, $height) if not.
  899. */
  900. protected function ProcessTextGD($draw_it, $font, $angle, $x, $y, $color, $text, $h_factor, $v_factor)
  901. {
  902. # Extract font parameters:
  903. $font_number = $font['font'];
  904. $font_width = $font['width'];
  905. $font_height = $font['height'];
  906. $line_spacing = $this->GetLineSpacing($font);
  907. # Break up the text into lines, trim whitespace, find longest line.
  908. # Save the lines and length for drawing below.
  909. $longest = 0;
  910. foreach (explode("\n", $text) as $each_line) {
  911. $lines[] = $line = trim($each_line);
  912. $line_lens[] = $line_len = strlen($line);
  913. if ($line_len > $longest) $longest = $line_len;
  914. }
  915. $n_lines = count($lines);
  916. # Width, height are based on font size and longest line, line count respectively.
  917. # These are relative to the text angle.
  918. $total_width = $longest * $font_width;
  919. $total_height = $n_lines * $font_height + ($n_lines - 1) * $line_spacing;
  920. if (!$draw_it) {
  921. if ($angle < 45) return array($total_width, $total_height);
  922. return array($total_height, $total_width);
  923. }
  924. $interline_step = $font_height + $line_spacing; // Line-to-line step
  925. if ($angle >= 45) {
  926. // Vertical text (90 degrees):
  927. // (Remember the alignment convention with vertical text)
  928. // For 90 degree text, alignment factors change like this:
  929. $temp = $v_factor;
  930. $v_factor = $h_factor;
  931. $h_factor = 1 - $temp;
  932. $draw_func = 'ImageStringUp';
  933. // Rotation matrix "R" for 90 degrees (with Y pointing down):
  934. $r00 = 0; $r01 = 1;
  935. $r10 = -1; $r11 = 0;
  936. } else {
  937. // Horizontal text (0 degrees):
  938. $draw_func = 'ImageString';
  939. // Rotation matrix "R" for 0 degrees:
  940. $r00 = 1; $r01 = 0;
  941. $r10 = 0; $r11 = 1;
  942. }
  943. // Adjust for vertical alignment (horizontal text) or horizontal alignment (vertical text):
  944. $factor = (int)($total_height * $v_factor);
  945. $xpos = $x - $r01 * $factor;
  946. $ypos = $y - $r11 * $factor;
  947. # Debug callback provides the bounding box:
  948. if ($this->GetCallback('debug_textbox')) {
  949. if ($angle >= 45) {
  950. $bbox_width = $total_height;
  951. $bbox_height = $total_width;
  952. $px = $xpos;
  953. $py = $ypos - (1 - $h_factor) * $total_width;
  954. } else {
  955. $bbox_width = $total_width;
  956. $bbox_height = $total_height;
  957. $px = $xpos - $h_factor * $total_width;
  958. $py = $ypos;
  959. }
  960. $this->DoCallback('debug_textbox', $px, $py, $bbox_width, $bbox_height);
  961. }
  962. for ($i = 0; $i < $n_lines; $i++) {
  963. // Adjust for alignment of this line within the text block:
  964. $factor = (int)($line_lens[$i] * $font_width * $h_factor);
  965. $x = $xpos - $r00 * $factor;
  966. $y = $ypos - $r10 * $factor;
  967. // Call ImageString or ImageStringUp:
  968. $draw_func($this->img, $font_number, $x, $y, $lines[$i], $color);
  969. // Step to the next line of text. This is a rotation of (x=0, y=interline_spacing)
  970. $xpos += $r01 * $interline_step;
  971. $ypos += $r11 * $interline_step;
  972. }
  973. return TRUE;
  974. }
  975. /*
  976. * ProcessTextTTF() - Draw or size TTF text.
  977. * This is intended for use only by ProcessText().
  978. * $draw_it : True to draw the text, False to just return the orthogonal width and height.
  979. * $font : PHPlot font array (with 'ttf' = True) - see SetFontTTF()
  980. * $angle : Text angle in degrees.
  981. * $x, $y : Reference point for the text (ignored if !$draw_it)
  982. * $color : GD color index to use for drawing the text (ignored if !$draw_it)
  983. * $text : The text to draw or size. Put a newline between lines.
  984. * $h_factor : Horizontal alignment factor: 0(left), .5(center), or 1(right) (ignored if !$draw_it)
  985. * $v_factor : Vertical alignment factor: 0(top), .5(center), or 1(bottom) (ignored if !$draw_it)
  986. * Returns: True, if drawing text, or an array of ($width, $height) if not.
  987. */
  988. protected function ProcessTextTTF($draw_it, $font, $angle, $x, $y, $color, $text, $h_factor, $v_factor)
  989. {
  990. # Extract font parameters (see SetFontTTF):
  991. $font_file = $font['font'];
  992. $font_size = $font['size'];
  993. $font_height = $font['height'];
  994. $line_spacing = $this->GetLineSpacing($font);
  995. # Break up the text into lines, trim whitespace.
  996. # Calculate the total width and height of the text box at 0 degrees.
  997. # Save the trimmed lines and their widths for later when drawing.
  998. # To get uniform spacing, don't use the actual line heights.
  999. # Total height = Font-specific line heights plus inter-line spacing.
  1000. # Total width = width of widest line.
  1001. # Last Line Descent is the offset from the bottom to the text baseline.
  1002. # Note: For some reason, ImageTTFBBox uses (-1,-1) as the reference point.
  1003. # So 1+bbox[1] is the baseline to bottom distance.
  1004. $total_width = 0;
  1005. $lastline_descent = 0;
  1006. foreach (explode("\n", $text) as $each_line) {
  1007. $lines[] = $line = trim($each_line);
  1008. $bbox = ImageTTFBBox($font_size, 0, $font_file, $line);
  1009. $line_widths[] = $width = $bbox[2] - $bbox[0];
  1010. if ($width > $total_width) $total_width = $width;
  1011. $lastline_descent = 1 + $bbox[1];
  1012. }
  1013. $n_lines = count($lines);
  1014. $total_height = $n_lines * $font_height + ($n_lines - 1) * $line_spacing;
  1015. # Calculate the rotation matrix for the text's angle. Remember that GD points Y down,
  1016. # so the sin() terms change sign.
  1017. $theta = deg2rad($angle);
  1018. $cos_t = cos($theta);
  1019. $sin_t = sin($theta);
  1020. $r00 = $cos_t; $r01 = $sin_t;
  1021. $r10 = -$sin_t; $r11 = $cos_t;
  1022. # Make a bounding box of the right size, with upper left corner at (0,0).
  1023. # By convention, the point order is: LL, LR, UR, UL.
  1024. # Note this is still working with the text at 0 degrees.
  1025. # When sizing text (SizeText), use the overall size with descenders.
  1026. # This tells the caller how much room to leave for the text.
  1027. # When drawing text (DrawText), use the size without descenders - that
  1028. # is, down to the baseline. This is for accurate positioning.
  1029. $b[0] = 0;
  1030. if ($draw_it) {
  1031. $b[1] = $total_height;
  1032. } else {
  1033. $b[1] = $total_height + $lastline_descent;
  1034. }
  1035. $b[2] = $total_width; $b[3] = $b[1];
  1036. $b[4] = $total_width; $b[5] = 0;
  1037. $b[6] = 0; $b[7] = 0;
  1038. # Rotate the bounding box, then offset to the reference point:
  1039. for ($i = 0; $i < 8; $i += 2) {
  1040. $x_b = $b[$i];
  1041. $y_b = $b[$i+1];
  1042. $c[$i] = $x + $r00 * $x_b + $r01 * $y_b;
  1043. $c[$i+1] = $y + $r10 * $x_b + $r11 * $y_b;
  1044. }
  1045. # Get an orthogonal (aligned with X and Y axes) bounding box around it, by
  1046. # finding the min and max X and Y:
  1047. $bbox_ref_x = $bbox_max_x = $c[0];
  1048. $bbox_ref_y = $bbox_max_y = $c[1];
  1049. for ($i = 2; $i < 8; $i += 2) {
  1050. $x_b = $c[$i];
  1051. if ($x_b < $bbox_ref_x) $bbox_ref_x = $x_b;
  1052. elseif ($bbox_max_x < $x_b) $bbox_max_x = $x_b;
  1053. $y_b = $c[$i+1];
  1054. if ($y_b < $bbox…

Large files files are truncated, but you can click here to view the full file