GisGeometryCollection.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * Handles actions related to GIS GEOMETRYCOLLECTION objects
  5. *
  6. * @package PhpMyAdmin-GIS
  7. */
  8. namespace PhpMyAdmin\Gis;
  9. use TCPDF;
  10. /**
  11. * Handles actions related to GIS GEOMETRYCOLLECTION objects
  12. *
  13. * @package PhpMyAdmin-GIS
  14. */
  15. class GisGeometryCollection extends GisGeometry
  16. {
  17. // Hold the singleton instance of the class
  18. private static $_instance;
  19. /**
  20. * A private constructor; prevents direct creation of object.
  21. *
  22. * @access private
  23. */
  24. private function __construct()
  25. {
  26. }
  27. /**
  28. * Returns the singleton.
  29. *
  30. * @return GisGeometryCollection the singleton
  31. * @access public
  32. */
  33. public static function singleton()
  34. {
  35. if (!isset(self::$_instance)) {
  36. $class = __CLASS__;
  37. self::$_instance = new $class;
  38. }
  39. return self::$_instance;
  40. }
  41. /**
  42. * Scales each row.
  43. *
  44. * @param string $spatial spatial data of a row
  45. *
  46. * @return array array containing the min, max values for x and y coordinates
  47. * @access public
  48. */
  49. public function scaleRow($spatial)
  50. {
  51. $min_max = array();
  52. // Trim to remove leading 'GEOMETRYCOLLECTION(' and trailing ')'
  53. $goem_col
  54. = mb_substr(
  55. $spatial,
  56. 19,
  57. mb_strlen($spatial) - 20
  58. );
  59. // Split the geometry collection object to get its constituents.
  60. $sub_parts = $this->_explodeGeomCol($goem_col);
  61. foreach ($sub_parts as $sub_part) {
  62. $type_pos = mb_strpos($sub_part, '(');
  63. if ($type_pos === false) {
  64. continue;
  65. }
  66. $type = mb_substr($sub_part, 0, $type_pos);
  67. $gis_obj = GisFactory::factory($type);
  68. if (!$gis_obj) {
  69. continue;
  70. }
  71. $scale_data = $gis_obj->scaleRow($sub_part);
  72. // Update minimum/maximum values for x and y coordinates.
  73. $c_maxX = (float)$scale_data['maxX'];
  74. if (!isset($min_max['maxX']) || $c_maxX > $min_max['maxX']) {
  75. $min_max['maxX'] = $c_maxX;
  76. }
  77. $c_minX = (float)$scale_data['minX'];
  78. if (!isset($min_max['minX']) || $c_minX < $min_max['minX']) {
  79. $min_max['minX'] = $c_minX;
  80. }
  81. $c_maxY = (float)$scale_data['maxY'];
  82. if (!isset($min_max['maxY']) || $c_maxY > $min_max['maxY']) {
  83. $min_max['maxY'] = $c_maxY;
  84. }
  85. $c_minY = (float)$scale_data['minY'];
  86. if (!isset($min_max['minY']) || $c_minY < $min_max['minY']) {
  87. $min_max['minY'] = $c_minY;
  88. }
  89. }
  90. return $min_max;
  91. }
  92. /**
  93. * Adds to the PNG image object, the data related to a row in the GIS dataset.
  94. *
  95. * @param string $spatial GIS GEOMETRYCOLLECTION object
  96. * @param string $label label for the GIS GEOMETRYCOLLECTION object
  97. * @param string $color color for the GIS GEOMETRYCOLLECTION object
  98. * @param array $scale_data array containing data related to scaling
  99. * @param object $image image object
  100. *
  101. * @return resource the modified image object
  102. * @access public
  103. */
  104. public function prepareRowAsPng($spatial, $label, $color, array $scale_data, $image)
  105. {
  106. // Trim to remove leading 'GEOMETRYCOLLECTION(' and trailing ')'
  107. $goem_col
  108. = mb_substr(
  109. $spatial,
  110. 19,
  111. mb_strlen($spatial) - 20
  112. );
  113. // Split the geometry collection object to get its constituents.
  114. $sub_parts = $this->_explodeGeomCol($goem_col);
  115. foreach ($sub_parts as $sub_part) {
  116. $type_pos = mb_strpos($sub_part, '(');
  117. if ($type_pos === false) {
  118. continue;
  119. }
  120. $type = mb_substr($sub_part, 0, $type_pos);
  121. $gis_obj = GisFactory::factory($type);
  122. if (!$gis_obj) {
  123. continue;
  124. }
  125. $image = $gis_obj->prepareRowAsPng(
  126. $sub_part,
  127. $label,
  128. $color,
  129. $scale_data,
  130. $image
  131. );
  132. }
  133. return $image;
  134. }
  135. /**
  136. * Adds to the TCPDF instance, the data related to a row in the GIS dataset.
  137. *
  138. * @param string $spatial GIS GEOMETRYCOLLECTION object
  139. * @param string $label label for the GIS GEOMETRYCOLLECTION object
  140. * @param string $color color for the GIS GEOMETRYCOLLECTION object
  141. * @param array $scale_data array containing data related to scaling
  142. * @param TCPDF $pdf TCPDF instance
  143. *
  144. * @return TCPDF the modified TCPDF instance
  145. * @access public
  146. */
  147. public function prepareRowAsPdf($spatial, $label, $color, array $scale_data, $pdf)
  148. {
  149. // Trim to remove leading 'GEOMETRYCOLLECTION(' and trailing ')'
  150. $goem_col
  151. = mb_substr(
  152. $spatial,
  153. 19,
  154. mb_strlen($spatial) - 20
  155. );
  156. // Split the geometry collection object to get its constituents.
  157. $sub_parts = $this->_explodeGeomCol($goem_col);
  158. foreach ($sub_parts as $sub_part) {
  159. $type_pos = mb_strpos($sub_part, '(');
  160. if ($type_pos === false) {
  161. continue;
  162. }
  163. $type = mb_substr($sub_part, 0, $type_pos);
  164. $gis_obj = GisFactory::factory($type);
  165. if (!$gis_obj) {
  166. continue;
  167. }
  168. $pdf = $gis_obj->prepareRowAsPdf(
  169. $sub_part,
  170. $label,
  171. $color,
  172. $scale_data,
  173. $pdf
  174. );
  175. }
  176. return $pdf;
  177. }
  178. /**
  179. * Prepares and returns the code related to a row in the GIS dataset as SVG.
  180. *
  181. * @param string $spatial GIS GEOMETRYCOLLECTION object
  182. * @param string $label label for the GIS GEOMETRYCOLLECTION object
  183. * @param string $color color for the GIS GEOMETRYCOLLECTION object
  184. * @param array $scale_data array containing data related to scaling
  185. *
  186. * @return string the code related to a row in the GIS dataset
  187. * @access public
  188. */
  189. public function prepareRowAsSvg($spatial, $label, $color, array $scale_data)
  190. {
  191. $row = '';
  192. // Trim to remove leading 'GEOMETRYCOLLECTION(' and trailing ')'
  193. $goem_col
  194. = mb_substr(
  195. $spatial,
  196. 19,
  197. mb_strlen($spatial) - 20
  198. );
  199. // Split the geometry collection object to get its constituents.
  200. $sub_parts = $this->_explodeGeomCol($goem_col);
  201. foreach ($sub_parts as $sub_part) {
  202. $type_pos = mb_strpos($sub_part, '(');
  203. if ($type_pos === false) {
  204. continue;
  205. }
  206. $type = mb_substr($sub_part, 0, $type_pos);
  207. $gis_obj = GisFactory::factory($type);
  208. if (!$gis_obj) {
  209. continue;
  210. }
  211. $row .= $gis_obj->prepareRowAsSvg(
  212. $sub_part,
  213. $label,
  214. $color,
  215. $scale_data
  216. );
  217. }
  218. return $row;
  219. }
  220. /**
  221. * Prepares JavaScript related to a row in the GIS dataset
  222. * to visualize it with OpenLayers.
  223. *
  224. * @param string $spatial GIS GEOMETRYCOLLECTION object
  225. * @param int $srid spatial reference ID
  226. * @param string $label label for the GIS GEOMETRYCOLLECTION object
  227. * @param string $color color for the GIS GEOMETRYCOLLECTION object
  228. * @param array $scale_data array containing data related to scaling
  229. *
  230. * @return string JavaScript related to a row in the GIS dataset
  231. * @access public
  232. */
  233. public function prepareRowAsOl($spatial, $srid, $label, $color, array $scale_data)
  234. {
  235. $row = '';
  236. // Trim to remove leading 'GEOMETRYCOLLECTION(' and trailing ')'
  237. $goem_col
  238. = mb_substr(
  239. $spatial,
  240. 19,
  241. mb_strlen($spatial) - 20
  242. );
  243. // Split the geometry collection object to get its constituents.
  244. $sub_parts = $this->_explodeGeomCol($goem_col);
  245. foreach ($sub_parts as $sub_part) {
  246. $type_pos = mb_strpos($sub_part, '(');
  247. if ($type_pos === false) {
  248. continue;
  249. }
  250. $type = mb_substr($sub_part, 0, $type_pos);
  251. $gis_obj = GisFactory::factory($type);
  252. if (!$gis_obj) {
  253. continue;
  254. }
  255. $row .= $gis_obj->prepareRowAsOl(
  256. $sub_part,
  257. $srid,
  258. $label,
  259. $color,
  260. $scale_data
  261. );
  262. }
  263. return $row;
  264. }
  265. /**
  266. * Splits the GEOMETRYCOLLECTION object and get its constituents.
  267. *
  268. * @param string $geom_col geometry collection string
  269. *
  270. * @return array the constituents of the geometry collection object
  271. * @access private
  272. */
  273. private function _explodeGeomCol($geom_col)
  274. {
  275. $sub_parts = array();
  276. $br_count = 0;
  277. $start = 0;
  278. $count = 0;
  279. foreach (str_split($geom_col) as $char) {
  280. if ($char == '(') {
  281. $br_count++;
  282. } elseif ($char == ')') {
  283. $br_count--;
  284. if ($br_count == 0) {
  285. $sub_parts[]
  286. = mb_substr(
  287. $geom_col,
  288. $start,
  289. ($count + 1 - $start)
  290. );
  291. $start = $count + 2;
  292. }
  293. }
  294. $count++;
  295. }
  296. return $sub_parts;
  297. }
  298. /**
  299. * Generates the WKT with the set of parameters passed by the GIS editor.
  300. *
  301. * @param array $gis_data GIS data
  302. * @param int $index index into the parameter object
  303. * @param string $empty value for empty points
  304. *
  305. * @return string WKT with the set of parameters passed by the GIS editor
  306. * @access public
  307. */
  308. public function generateWkt(array $gis_data, $index, $empty = '')
  309. {
  310. $geom_count = (isset($gis_data['GEOMETRYCOLLECTION']['geom_count']))
  311. ? $gis_data['GEOMETRYCOLLECTION']['geom_count'] : 1;
  312. $wkt = 'GEOMETRYCOLLECTION(';
  313. for ($i = 0; $i < $geom_count; $i++) {
  314. if (isset($gis_data[$i]['gis_type'])) {
  315. $type = $gis_data[$i]['gis_type'];
  316. $gis_obj = GisFactory::factory($type);
  317. if (!$gis_obj) {
  318. continue;
  319. }
  320. $wkt .= $gis_obj->generateWkt($gis_data, $i, $empty) . ',';
  321. }
  322. }
  323. if (isset($gis_data[0]['gis_type'])) {
  324. $wkt
  325. = mb_substr(
  326. $wkt,
  327. 0,
  328. mb_strlen($wkt) - 1
  329. );
  330. }
  331. $wkt .= ')';
  332. return $wkt;
  333. }
  334. /**
  335. * Generates parameters for the GIS data editor from the value of the GIS column.
  336. *
  337. * @param string $value of the GIS column
  338. *
  339. * @return array parameters for the GIS editor from the value of the GIS column
  340. * @access public
  341. */
  342. public function generateParams($value)
  343. {
  344. $params = array();
  345. $data = GisGeometry::generateParams($value);
  346. $params['srid'] = $data['srid'];
  347. $wkt = $data['wkt'];
  348. // Trim to remove leading 'GEOMETRYCOLLECTION(' and trailing ')'
  349. $goem_col
  350. = mb_substr(
  351. $wkt,
  352. 19,
  353. mb_strlen($wkt) - 20
  354. );
  355. // Split the geometry collection object to get its constituents.
  356. $sub_parts = $this->_explodeGeomCol($goem_col);
  357. $params['GEOMETRYCOLLECTION']['geom_count'] = count($sub_parts);
  358. $i = 0;
  359. foreach ($sub_parts as $sub_part) {
  360. $type_pos = mb_strpos($sub_part, '(');
  361. if ($type_pos === false) {
  362. continue;
  363. }
  364. $type = mb_substr($sub_part, 0, $type_pos);
  365. $gis_obj = GisFactory::factory($type);
  366. if (!$gis_obj) {
  367. continue;
  368. }
  369. $params = array_merge($params, $gis_obj->generateParams($sub_part, $i));
  370. $i++;
  371. }
  372. return $params;
  373. }
  374. }