GisMultiLineString.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * Handles actions related to GIS MULTILINESTRING objects
  5. *
  6. * @package PhpMyAdmin-GIS
  7. */
  8. declare(strict_types=1);
  9. namespace PhpMyAdmin\Gis;
  10. use TCPDF;
  11. /**
  12. * Handles actions related to GIS MULTILINESTRING objects
  13. *
  14. * @package PhpMyAdmin-GIS
  15. */
  16. class GisMultiLineString extends GisGeometry
  17. {
  18. // Hold the singleton instance of the class
  19. private static $_instance;
  20. /**
  21. * A private constructor; prevents direct creation of object.
  22. *
  23. * @access private
  24. */
  25. private function __construct()
  26. {
  27. }
  28. /**
  29. * Returns the singleton.
  30. *
  31. * @return GisMultiLineString the singleton
  32. * @access public
  33. */
  34. public static function singleton()
  35. {
  36. if (! isset(self::$_instance)) {
  37. self::$_instance = new GisMultiLineString();
  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 an array containing the min, max values for x and y coordinates
  47. * @access public
  48. */
  49. public function scaleRow($spatial)
  50. {
  51. $min_max = [];
  52. // Trim to remove leading 'MULTILINESTRING((' and trailing '))'
  53. $multilinestirng
  54. = mb_substr(
  55. $spatial,
  56. 17,
  57. mb_strlen($spatial) - 19
  58. );
  59. // Separate each linestring
  60. $linestirngs = explode("),(", $multilinestirng);
  61. foreach ($linestirngs as $linestring) {
  62. $min_max = $this->setMinMax($linestring, $min_max);
  63. }
  64. return $min_max;
  65. }
  66. /**
  67. * Adds to the PNG image object, the data related to a row in the GIS dataset.
  68. *
  69. * @param string $spatial GIS POLYGON object
  70. * @param string|null $label Label for the GIS POLYGON object
  71. * @param string $line_color Color for the GIS POLYGON object
  72. * @param array $scale_data Array containing data related to scaling
  73. * @param resource $image Image object
  74. *
  75. * @return resource the modified image object
  76. * @access public
  77. */
  78. public function prepareRowAsPng(
  79. $spatial,
  80. ?string $label,
  81. $line_color,
  82. array $scale_data,
  83. $image
  84. ) {
  85. // allocate colors
  86. $black = imagecolorallocate($image, 0, 0, 0);
  87. $red = hexdec(mb_substr($line_color, 1, 2));
  88. $green = hexdec(mb_substr($line_color, 3, 2));
  89. $blue = hexdec(mb_substr($line_color, 4, 2));
  90. $color = imagecolorallocate($image, $red, $green, $blue);
  91. // Trim to remove leading 'MULTILINESTRING((' and trailing '))'
  92. $multilinestirng
  93. = mb_substr(
  94. $spatial,
  95. 17,
  96. mb_strlen($spatial) - 19
  97. );
  98. // Separate each linestring
  99. $linestirngs = explode("),(", $multilinestirng);
  100. $first_line = true;
  101. foreach ($linestirngs as $linestring) {
  102. $points_arr = $this->extractPoints($linestring, $scale_data);
  103. foreach ($points_arr as $point) {
  104. if (! isset($temp_point)) {
  105. $temp_point = $point;
  106. } else {
  107. // draw line section
  108. imageline(
  109. $image,
  110. $temp_point[0],
  111. $temp_point[1],
  112. $point[0],
  113. $point[1],
  114. $color
  115. );
  116. $temp_point = $point;
  117. }
  118. }
  119. unset($temp_point);
  120. // print label if applicable
  121. if (isset($label) && trim($label) != '' && $first_line) {
  122. imagestring(
  123. $image,
  124. 1,
  125. $points_arr[1][0],
  126. $points_arr[1][1],
  127. trim($label),
  128. $black
  129. );
  130. }
  131. $first_line = false;
  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 MULTILINESTRING object
  139. * @param string|null $label Label for the GIS MULTILINESTRING object
  140. * @param string $line_color Color for the GIS MULTILINESTRING 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, ?string $label, $line_color, array $scale_data, $pdf)
  148. {
  149. // allocate colors
  150. $red = hexdec(mb_substr($line_color, 1, 2));
  151. $green = hexdec(mb_substr($line_color, 3, 2));
  152. $blue = hexdec(mb_substr($line_color, 4, 2));
  153. $line = [
  154. 'width' => 1.5,
  155. 'color' => [
  156. $red,
  157. $green,
  158. $blue,
  159. ],
  160. ];
  161. // Trim to remove leading 'MULTILINESTRING((' and trailing '))'
  162. $multilinestirng
  163. = mb_substr(
  164. $spatial,
  165. 17,
  166. mb_strlen($spatial) - 19
  167. );
  168. // Separate each linestring
  169. $linestirngs = explode("),(", $multilinestirng);
  170. $first_line = true;
  171. foreach ($linestirngs as $linestring) {
  172. $points_arr = $this->extractPoints($linestring, $scale_data);
  173. foreach ($points_arr as $point) {
  174. if (! isset($temp_point)) {
  175. $temp_point = $point;
  176. } else {
  177. // draw line section
  178. $pdf->Line(
  179. $temp_point[0],
  180. $temp_point[1],
  181. $point[0],
  182. $point[1],
  183. $line
  184. );
  185. $temp_point = $point;
  186. }
  187. }
  188. unset($temp_point);
  189. // print label
  190. if (isset($label) && trim($label) != '' && $first_line) {
  191. $pdf->SetXY($points_arr[1][0], $points_arr[1][1]);
  192. $pdf->SetFontSize(5);
  193. $pdf->Cell(0, 0, trim($label));
  194. }
  195. $first_line = false;
  196. }
  197. return $pdf;
  198. }
  199. /**
  200. * Prepares and returns the code related to a row in the GIS dataset as SVG.
  201. *
  202. * @param string $spatial GIS MULTILINESTRING object
  203. * @param string $label Label for the GIS MULTILINESTRING object
  204. * @param string $line_color Color for the GIS MULTILINESTRING object
  205. * @param array $scale_data Array containing data related to scaling
  206. *
  207. * @return string the code related to a row in the GIS dataset
  208. * @access public
  209. */
  210. public function prepareRowAsSvg($spatial, $label, $line_color, array $scale_data)
  211. {
  212. $line_options = [
  213. 'name' => $label,
  214. 'class' => 'linestring vector',
  215. 'fill' => 'none',
  216. 'stroke' => $line_color,
  217. 'stroke-width' => 2,
  218. ];
  219. // Trim to remove leading 'MULTILINESTRING((' and trailing '))'
  220. $multilinestirng
  221. = mb_substr(
  222. $spatial,
  223. 17,
  224. mb_strlen($spatial) - 19
  225. );
  226. // Separate each linestring
  227. $linestirngs = explode("),(", $multilinestirng);
  228. $row = '';
  229. foreach ($linestirngs as $linestring) {
  230. $points_arr = $this->extractPoints($linestring, $scale_data);
  231. $row .= '<polyline points="';
  232. foreach ($points_arr as $point) {
  233. $row .= $point[0] . ',' . $point[1] . ' ';
  234. }
  235. $row .= '"';
  236. $line_options['id'] = $label . mt_rand();
  237. foreach ($line_options as $option => $val) {
  238. $row .= ' ' . $option . '="' . trim((string) $val) . '"';
  239. }
  240. $row .= '/>';
  241. }
  242. return $row;
  243. }
  244. /**
  245. * Prepares JavaScript related to a row in the GIS dataset
  246. * to visualize it with OpenLayers.
  247. *
  248. * @param string $spatial GIS MULTILINESTRING object
  249. * @param int $srid Spatial reference ID
  250. * @param string $label Label for the GIS MULTILINESTRING object
  251. * @param string $line_color Color for the GIS MULTILINESTRING object
  252. * @param array $scale_data Array containing data related to scaling
  253. *
  254. * @return string JavaScript related to a row in the GIS dataset
  255. * @access public
  256. */
  257. public function prepareRowAsOl($spatial, $srid, $label, $line_color, array $scale_data)
  258. {
  259. $style_options = [
  260. 'strokeColor' => $line_color,
  261. 'strokeWidth' => 2,
  262. 'label' => $label,
  263. 'fontSize' => 10,
  264. ];
  265. if ($srid == 0) {
  266. $srid = 4326;
  267. }
  268. $row = $this->getBoundsForOl($srid, $scale_data);
  269. // Trim to remove leading 'MULTILINESTRING((' and trailing '))'
  270. $multilinestirng
  271. = mb_substr(
  272. $spatial,
  273. 17,
  274. mb_strlen($spatial) - 19
  275. );
  276. // Separate each linestring
  277. $linestirngs = explode("),(", $multilinestirng);
  278. $row .= 'vectorLayer.addFeatures(new OpenLayers.Feature.Vector('
  279. . 'new OpenLayers.Geometry.MultiLineString('
  280. . $this->getLineArrayForOpenLayers($linestirngs, $srid)
  281. . '), null, ' . json_encode($style_options) . '));';
  282. return $row;
  283. }
  284. /**
  285. * Generate the WKT with the set of parameters passed by the GIS editor.
  286. *
  287. * @param array $gis_data GIS data
  288. * @param int $index Index into the parameter object
  289. * @param string $empty Value for empty points
  290. *
  291. * @return string WKT with the set of parameters passed by the GIS editor
  292. * @access public
  293. */
  294. public function generateWkt(array $gis_data, $index, $empty = '')
  295. {
  296. $data_row = $gis_data[$index]['MULTILINESTRING'];
  297. $no_of_lines = isset($data_row['no_of_lines'])
  298. ? $data_row['no_of_lines'] : 1;
  299. if ($no_of_lines < 1) {
  300. $no_of_lines = 1;
  301. }
  302. $wkt = 'MULTILINESTRING(';
  303. for ($i = 0; $i < $no_of_lines; $i++) {
  304. $no_of_points = isset($data_row[$i]['no_of_points'])
  305. ? $data_row[$i]['no_of_points'] : 2;
  306. if ($no_of_points < 2) {
  307. $no_of_points = 2;
  308. }
  309. $wkt .= '(';
  310. for ($j = 0; $j < $no_of_points; $j++) {
  311. $wkt .= ((isset($data_row[$i][$j]['x'])
  312. && trim((string) $data_row[$i][$j]['x']) != '')
  313. ? $data_row[$i][$j]['x'] : $empty)
  314. . ' ' . ((isset($data_row[$i][$j]['y'])
  315. && trim((string) $data_row[$i][$j]['y']) != '')
  316. ? $data_row[$i][$j]['y'] : $empty) . ',';
  317. }
  318. $wkt
  319. = mb_substr(
  320. $wkt,
  321. 0,
  322. mb_strlen($wkt) - 1
  323. );
  324. $wkt .= '),';
  325. }
  326. $wkt
  327. = mb_substr(
  328. $wkt,
  329. 0,
  330. mb_strlen($wkt) - 1
  331. );
  332. $wkt .= ')';
  333. return $wkt;
  334. }
  335. /**
  336. * Generate the WKT for the data from ESRI shape files.
  337. *
  338. * @param array $row_data GIS data
  339. *
  340. * @return string the WKT for the data from ESRI shape files
  341. * @access public
  342. */
  343. public function getShape(array $row_data)
  344. {
  345. $wkt = 'MULTILINESTRING(';
  346. for ($i = 0; $i < $row_data['numparts']; $i++) {
  347. $wkt .= '(';
  348. foreach ($row_data['parts'][$i]['points'] as $point) {
  349. $wkt .= $point['x'] . ' ' . $point['y'] . ',';
  350. }
  351. $wkt
  352. = mb_substr(
  353. $wkt,
  354. 0,
  355. mb_strlen($wkt) - 1
  356. );
  357. $wkt .= '),';
  358. }
  359. $wkt
  360. = mb_substr(
  361. $wkt,
  362. 0,
  363. mb_strlen($wkt) - 1
  364. );
  365. $wkt .= ')';
  366. return $wkt;
  367. }
  368. /**
  369. * Generate parameters for the GIS data editor from the value of the GIS column.
  370. *
  371. * @param string $value Value of the GIS column
  372. * @param int $index Index of the geometry
  373. *
  374. * @return array params for the GIS data editor from the value of the GIS column
  375. * @access public
  376. */
  377. public function generateParams($value, $index = -1)
  378. {
  379. $params = [];
  380. if ($index == -1) {
  381. $index = 0;
  382. $data = GisGeometry::generateParams($value);
  383. $params['srid'] = $data['srid'];
  384. $wkt = $data['wkt'];
  385. } else {
  386. $params[$index]['gis_type'] = 'MULTILINESTRING';
  387. $wkt = $value;
  388. }
  389. // Trim to remove leading 'MULTILINESTRING((' and trailing '))'
  390. $multilinestirng
  391. = mb_substr(
  392. $wkt,
  393. 17,
  394. mb_strlen($wkt) - 19
  395. );
  396. // Separate each linestring
  397. $linestirngs = explode("),(", $multilinestirng);
  398. $params[$index]['MULTILINESTRING']['no_of_lines'] = count($linestirngs);
  399. $j = 0;
  400. foreach ($linestirngs as $linestring) {
  401. $points_arr = $this->extractPoints($linestring, null);
  402. $no_of_points = count($points_arr);
  403. $params[$index]['MULTILINESTRING'][$j]['no_of_points'] = $no_of_points;
  404. for ($i = 0; $i < $no_of_points; $i++) {
  405. $params[$index]['MULTILINESTRING'][$j][$i]['x'] = $points_arr[$i][0];
  406. $params[$index]['MULTILINESTRING'][$j][$i]['y'] = $points_arr[$i][1];
  407. }
  408. $j++;
  409. }
  410. return $params;
  411. }
  412. }