PageRenderTime 48ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/libs/PEAR/Image/Graph/Tool.php

https://github.com/mhoegh/MyGeoCloud
PHP | 291 lines | 139 code | 28 blank | 124 comment | 30 complexity | e954b0befc268fd99e86afe96c349a1d MD5 | raw file
  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3. /**
  4. * Image_Graph - Main class for the graph creation.
  5. *
  6. * PHP versions 4 and 5
  7. *
  8. * LICENSE: This library is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU Lesser General Public License as published by
  10. * the Free Software Foundation; either version 2.1 of the License, or (at your
  11. * option) any later version. This library is distributed in the hope that it
  12. * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
  13. * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
  14. * General Public License for more details. You should have received a copy of
  15. * the GNU Lesser General Public License along with this library; if not, write
  16. * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  17. * 02111-1307 USA
  18. *
  19. * @category Images
  20. * @package Image_Graph
  21. * @author Jesper Veggerby <pear.nosey@veggerby.dk>
  22. * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen
  23. * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
  24. * @version CVS: $Id: Tool.php,v 1.3 2009/10/14 06:53:44 mhoegh Exp $
  25. * @link http://pear.php.net/package/Image_Graph
  26. */
  27. /**
  28. * This class contains a set of tool-functions.
  29. *
  30. * These functions are all to be called statically
  31. *
  32. * @category Images
  33. * @package Image_Graph
  34. * @author Jesper Veggerby <pear.nosey@veggerby.dk>
  35. * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen
  36. * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
  37. * @version Release: @package_version@
  38. * @link http://pear.php.net/package/Image_Graph
  39. */
  40. class Image_Graph_Tool
  41. {
  42. /**
  43. * Return the average of 2 points
  44. *
  45. * @param double P1 1st point
  46. * @param double P2 2nd point
  47. * @return double The average of P1 and P2
  48. * @static
  49. */
  50. function mid($p1, $p2)
  51. {
  52. return ($p1 + $p2) / 2;
  53. }
  54. /**
  55. * Mirrors P1 in P2 by a amount of Factor
  56. *
  57. * @param double $p1 1st point, point to mirror
  58. * @param double $o2 2nd point, mirror point
  59. * @param double $factor Mirror factor, 0 returns $p2, 1 returns a pure
  60. * mirror, ie $p1 on the exact other side of $p2
  61. * @return double $p1 mirrored in $p2 by Factor
  62. * @static
  63. */
  64. function mirror($p1, $p2, $factor = 1)
  65. {
  66. return $p2 + $factor * ($p2 - $p1);
  67. }
  68. /**
  69. * Calculates a Bezier control point, this function must be called for BOTH
  70. * X and Y coordinates (will it work for 3D coordinates!?)
  71. *
  72. * @param double $p1 1st point
  73. * @param double $p2 Point to
  74. * @param double $factor Mirror factor, 0 returns P2, 1 returns a pure
  75. * mirror, i.e. P1 on the exact other side of P2
  76. * @return double P1 mirrored in P2 by Factor
  77. * @static
  78. */
  79. function controlPoint($p1, $p2, $factor, $smoothFactor = 0.75)
  80. {
  81. $sa = Image_Graph_Tool::mirror($p1, $p2, $smoothFactor);
  82. $sb = Image_Graph_Tool::mid($p2, $sa);
  83. $m = Image_Graph_Tool::mid($p2, $factor);
  84. $pC = Image_Graph_Tool::mid($sb, $m);
  85. return $pC;
  86. }
  87. /**
  88. * Calculates a Bezier point, this function must be called for BOTH X and Y
  89. * coordinates (will it work for 3D coordinates!?)
  90. *
  91. * @param double $t A position between $p2 and $p3, value between 0 and 1
  92. * @param double $p1 Point to use for calculating control points
  93. * @param double $p2 Point 1 to calculate bezier curve between
  94. * @param double $p3 Point 2 to calculate bezier curve between
  95. * @param double $p4 Point to use for calculating control points
  96. * @return double The bezier value of the point t between $p2 and $p3 using
  97. * $p1 and $p4 to calculate control points
  98. * @static
  99. */
  100. function bezier($t, $p1, $p2, $p3, $p4)
  101. {
  102. // (1-t)^3*p1 + 3*(1-t)^2*t*p2 + 3*(1-t)*t^2*p3 + t^3*p4
  103. return pow(1 - $t, 3) * $p1 +
  104. 3 * pow(1 - $t, 2) * $t * $p2 +
  105. 3 * (1 - $t) * pow($t, 2) * $p3 +
  106. pow($t, 3) * $p4;
  107. }
  108. /**
  109. * For a given point (x,y) return a point rotated by a given angle aroung the center (xy,yc)
  110. *
  111. * @param int $x x coordinate of the point to rotate
  112. * @param int $y y coordinate of the point to rotate
  113. * @param int $xc x coordinate of the center of the rotation
  114. * @param int $yc y coordinate of the center of the rotation
  115. * @param int $angle angle of the rotation
  116. * @return array the coordinate of the new point
  117. * @static
  118. */
  119. function rotate($x, $y, $xc, $yc, $angle)
  120. {
  121. $cos = cos(deg2rad($angle));
  122. $sin = sin(deg2rad($angle));
  123. $xr= $x - $xc;
  124. $yr= $y - $yc;
  125. $x1= $xc + $cos * $xr - $sin * $yr;
  126. $y1= $yc + $sin * $xr + $cos * $yr;
  127. return array((int) $x1,(int) $y1);
  128. }
  129. /**
  130. * If a number is close 0 zero (i.e. 0 within $decimal decimals) it is rounded down to zero
  131. *
  132. * @param double $value The value to round
  133. * @param int $decimal The number of decimals
  134. * @return double The value or zero if "close enough" to zero
  135. * @static
  136. */
  137. function close2zero($value, $decimal)
  138. {
  139. if (abs($value) < pow(10, -$decimal)) {
  140. return 0;
  141. }
  142. else {
  143. return $value;
  144. }
  145. }
  146. /**
  147. * Calculate the dimensions and center point (of gravity) for an arc
  148. *
  149. * @param int $v1 The angle at which the arc starts
  150. * @param int $v2 The angle at which the arc ends
  151. * @return array An array with the dimensions in a fraction of a circle width radius 1 'rx', 'ry' and the
  152. * center point of gravity ('cx', 'cy')
  153. * @static
  154. */
  155. function calculateArcDimensionAndCenter($v1, $v2)
  156. {
  157. // $v2 always larger than $v1
  158. $r1x = Image_Graph_Tool::close2zero(cos(deg2rad($v1)), 3);
  159. $r2x = Image_Graph_Tool::close2zero(cos(deg2rad($v2)), 3);
  160. $r1y = Image_Graph_Tool::close2zero(sin(deg2rad($v1)), 3);
  161. $r2y = Image_Graph_Tool::close2zero(sin(deg2rad($v2)), 3);
  162. // $rx = how many percent of the x-diameter of the entire ellipse does the arc x-diameter occupy: 1 entire width, 0 no width
  163. // $cx = at what percentage of the diameter does the center lie
  164. // if the arc passes through 0/360 degrees the "highest" of r1x and r2x is replaced by 1!
  165. if ((($v1 <= 0) && ($v2 >= 0)) || (($v1 <= 360) && ($v2 >= 360))) {
  166. $r1x = min($r1x, $r2x);
  167. $r2x = 1;
  168. }
  169. // if the arc passes through 180 degrees the "lowest" of r1x and r2x is replaced by -1!
  170. if ((($v1 <= 180) && ($v2 >= 180)) || (($v1 <= 540) && ($v2 >= 540))) {
  171. $r1x = max($r1x, $r2x);
  172. $r2x = -1;
  173. }
  174. if ($r1x >= 0) { // start between [270; 360] or [0; 90]
  175. if ($r2x >= 0) {
  176. $rx = max($r1x, $r2x) / 2;
  177. $cx = 0; // center lies 0 percent along this "vector"
  178. }
  179. else {
  180. $rx = abs($r1x - $r2x) / 2;
  181. $cx = abs($r2x / 2) / $rx;
  182. }
  183. }
  184. else { // start between ]90; 270[
  185. if ($r2x < 0) {
  186. $rx = max(abs($r1x), abs($r2x)) / 2;
  187. $cx = $rx;
  188. }
  189. else {
  190. $rx = abs($r1x - $r2x) / 2;
  191. $cx = abs($r1x / 2) / $rx;
  192. }
  193. }
  194. // $ry = how many percent of the y-diameter of the entire ellipse does the arc y-diameter occupy: 1 entire, 0 none
  195. // $cy = at what percentage of the y-diameter does the center lie
  196. // if the arc passes through 90 degrees the "lowest" of r1x and r2x is replaced by -1!
  197. if ((($v1 <= 90) && ($v2 >= 90)) || (($v1 <= 450) && ($v2 >= 450))) {
  198. $r1y = min($r1y, $r2y);
  199. $r2y = 1;
  200. }
  201. // if the arc passes through 270 degrees the "highest" of r1y and r2y is replaced by -1!
  202. if ((($v1 <= 270) && ($v2 >= 270)) || (($v1 <= 630) && ($v2 >= 630))) {
  203. $r1y = max($r1y, $r2y);
  204. $r2y = -1;
  205. }
  206. if ($r1y >= 0) { // start between [0; 180]
  207. if ($r2y >= 0) {
  208. $ry = max($r1y, $r2y) / 2;
  209. $cy = 0; // center lies 0 percent along this "vector"
  210. }
  211. else {
  212. $ry = abs($r1y - $r2y) / 2;
  213. $cy = abs($r2y / 2) / $ry;
  214. }
  215. }
  216. else { // start between ]180; 360[
  217. if ($r2y < 0) {
  218. $ry = max(abs($r1y), abs($r2y)) / 2;
  219. $cy = $ry;
  220. }
  221. else {
  222. $ry = abs($r1y - $r2y) / 2;
  223. $cy = abs($r1y / 2) / $ry;
  224. }
  225. }
  226. return array(
  227. 'rx' => $rx,
  228. 'cx' => $cx,
  229. 'ry' => $ry,
  230. 'cy' => $cy
  231. );
  232. }
  233. /**
  234. * Calculate linear regression on a dataset
  235. * @param array $data The data to calculate regression upon
  236. * @return array The slope and intersection of the "best-fit" line
  237. * @static
  238. */
  239. function calculateLinearRegression(&$data)
  240. {
  241. $sumX = 0;
  242. $sumY = 0;
  243. foreach ($data as $point) {
  244. $sumX += $point['X'];
  245. $sumY += $point['Y'];
  246. }
  247. $meanX = $sumX / count($data);
  248. $meanY = $sumY / count($data);
  249. $sumXX = 0;
  250. $sumYY = 0;
  251. $sumXY = 0;
  252. foreach ($data as $point) {
  253. $sumXX += ($point['X'] - $meanX) * ($point['X'] - $meanX);
  254. $sumYY += ($point['Y'] - $meanY) * ($point['Y'] - $meanY);
  255. $sumXY += ($point['X'] - $meanX) * ($point['Y'] - $meanY);
  256. }
  257. $result = array();
  258. $result['slope'] = ($sumXY / $sumXX);
  259. $result['intersection'] = $meanY - ($result['slope'] * $meanX);
  260. return $result;
  261. }
  262. }
  263. ?>