GisLineString.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. <?php
  2. /**
  3. * Handles actions related to GIS LINESTRING objects
  4. */
  5. declare(strict_types=1);
  6. namespace PhpMyAdmin\Gis;
  7. use TCPDF;
  8. use function count;
  9. use function hexdec;
  10. use function imagecolorallocate;
  11. use function imageline;
  12. use function imagestring;
  13. use function json_encode;
  14. use function mb_strlen;
  15. use function mb_substr;
  16. use function trim;
  17. /**
  18. * Handles actions related to GIS LINESTRING objects
  19. */
  20. class GisLineString extends GisGeometry
  21. {
  22. /** @var self */
  23. private static $instance;
  24. /**
  25. * A private constructor; prevents direct creation of object.
  26. *
  27. * @access private
  28. */
  29. private function __construct()
  30. {
  31. }
  32. /**
  33. * Returns the singleton.
  34. *
  35. * @return GisLineString the singleton
  36. *
  37. * @access public
  38. */
  39. public static function singleton()
  40. {
  41. if (! isset(self::$instance)) {
  42. self::$instance = new GisLineString();
  43. }
  44. return self::$instance;
  45. }
  46. /**
  47. * Scales each row.
  48. *
  49. * @param string $spatial spatial data of a row
  50. *
  51. * @return array an array containing the min, max values for x and y coordinates
  52. *
  53. * @access public
  54. */
  55. public function scaleRow($spatial)
  56. {
  57. // Trim to remove leading 'LINESTRING(' and trailing ')'
  58. $linestring
  59. = mb_substr(
  60. $spatial,
  61. 11,
  62. mb_strlen($spatial) - 12
  63. );
  64. return $this->setMinMax($linestring, []);
  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. *
  77. * @access public
  78. */
  79. public function prepareRowAsPng(
  80. $spatial,
  81. ?string $label,
  82. $line_color,
  83. array $scale_data,
  84. $image
  85. ) {
  86. // allocate colors
  87. $black = imagecolorallocate($image, 0, 0, 0);
  88. $red = hexdec(mb_substr($line_color, 1, 2));
  89. $green = hexdec(mb_substr($line_color, 3, 2));
  90. $blue = hexdec(mb_substr($line_color, 4, 2));
  91. $color = imagecolorallocate($image, $red, $green, $blue);
  92. // Trim to remove leading 'LINESTRING(' and trailing ')'
  93. $linesrting
  94. = mb_substr(
  95. $spatial,
  96. 11,
  97. mb_strlen($spatial) - 12
  98. );
  99. $points_arr = $this->extractPoints($linesrting, $scale_data);
  100. foreach ($points_arr as $point) {
  101. if (! isset($temp_point)) {
  102. $temp_point = $point;
  103. } else {
  104. // draw line section
  105. imageline(
  106. $image,
  107. (int) $temp_point[0],
  108. (int) $temp_point[1],
  109. (int) $point[0],
  110. (int) $point[1],
  111. $color
  112. );
  113. $temp_point = $point;
  114. }
  115. }
  116. // print label if applicable
  117. if (isset($label) && trim($label) != '') {
  118. imagestring(
  119. $image,
  120. 1,
  121. $points_arr[1][0],
  122. $points_arr[1][1],
  123. trim($label),
  124. $black
  125. );
  126. }
  127. return $image;
  128. }
  129. /**
  130. * Adds to the TCPDF instance, the data related to a row in the GIS dataset.
  131. *
  132. * @param string $spatial GIS LINESTRING object
  133. * @param string|null $label Label for the GIS LINESTRING object
  134. * @param string $line_color Color for the GIS LINESTRING object
  135. * @param array $scale_data Array containing data related to scaling
  136. * @param TCPDF $pdf TCPDF instance
  137. *
  138. * @return TCPDF the modified TCPDF instance
  139. *
  140. * @access public
  141. */
  142. public function prepareRowAsPdf($spatial, ?string $label, $line_color, array $scale_data, $pdf)
  143. {
  144. // allocate colors
  145. $red = hexdec(mb_substr($line_color, 1, 2));
  146. $green = hexdec(mb_substr($line_color, 3, 2));
  147. $blue = hexdec(mb_substr($line_color, 4, 2));
  148. $line = [
  149. 'width' => 1.5,
  150. 'color' => [
  151. $red,
  152. $green,
  153. $blue,
  154. ],
  155. ];
  156. // Trim to remove leading 'LINESTRING(' and trailing ')'
  157. $linesrting
  158. = mb_substr(
  159. $spatial,
  160. 11,
  161. mb_strlen($spatial) - 12
  162. );
  163. $points_arr = $this->extractPoints($linesrting, $scale_data);
  164. foreach ($points_arr as $point) {
  165. if (! isset($temp_point)) {
  166. $temp_point = $point;
  167. } else {
  168. // draw line section
  169. $pdf->Line(
  170. $temp_point[0],
  171. $temp_point[1],
  172. $point[0],
  173. $point[1],
  174. $line
  175. );
  176. $temp_point = $point;
  177. }
  178. }
  179. // print label
  180. if (isset($label) && trim($label) != '') {
  181. $pdf->SetXY($points_arr[1][0], $points_arr[1][1]);
  182. $pdf->SetFontSize(5);
  183. $pdf->Cell(0, 0, trim($label));
  184. }
  185. return $pdf;
  186. }
  187. /**
  188. * Prepares and returns the code related to a row in the GIS dataset as SVG.
  189. *
  190. * @param string $spatial GIS LINESTRING object
  191. * @param string $label Label for the GIS LINESTRING object
  192. * @param string $line_color Color for the GIS LINESTRING object
  193. * @param array $scale_data Array containing data related to scaling
  194. *
  195. * @return string the code related to a row in the GIS dataset
  196. *
  197. * @access public
  198. */
  199. public function prepareRowAsSvg($spatial, $label, $line_color, array $scale_data)
  200. {
  201. $line_options = [
  202. 'name' => $label,
  203. 'id' => $label . $this->getRandomId(),
  204. 'class' => 'linestring vector',
  205. 'fill' => 'none',
  206. 'stroke' => $line_color,
  207. 'stroke-width' => 2,
  208. ];
  209. // Trim to remove leading 'LINESTRING(' and trailing ')'
  210. $linesrting
  211. = mb_substr(
  212. $spatial,
  213. 11,
  214. mb_strlen($spatial) - 12
  215. );
  216. $points_arr = $this->extractPoints($linesrting, $scale_data);
  217. $row = '<polyline points="';
  218. foreach ($points_arr as $point) {
  219. $row .= $point[0] . ',' . $point[1] . ' ';
  220. }
  221. $row .= '"';
  222. foreach ($line_options as $option => $val) {
  223. $row .= ' ' . $option . '="' . trim((string) $val) . '"';
  224. }
  225. $row .= '/>';
  226. return $row;
  227. }
  228. /**
  229. * Prepares JavaScript related to a row in the GIS dataset
  230. * to visualize it with OpenLayers.
  231. *
  232. * @param string $spatial GIS LINESTRING object
  233. * @param int $srid Spatial reference ID
  234. * @param string $label Label for the GIS LINESTRING object
  235. * @param array $line_color Color for the GIS LINESTRING object
  236. * @param array $scale_data Array containing data related to scaling
  237. *
  238. * @return string JavaScript related to a row in the GIS dataset
  239. *
  240. * @access public
  241. */
  242. public function prepareRowAsOl($spatial, $srid, $label, $line_color, array $scale_data)
  243. {
  244. $stroke_style = [
  245. 'color' => $line_color,
  246. 'width' => 2,
  247. ];
  248. $result = 'var style = new ol.style.Style({'
  249. . 'stroke: new ol.style.Stroke(' . json_encode($stroke_style) . ')';
  250. if ($label) {
  251. $text_style = ['text' => $label];
  252. $result .= ', text: new ol.style.Text(' . json_encode($text_style) . ')';
  253. }
  254. $result .= '});';
  255. if ($srid == 0) {
  256. $srid = 4326;
  257. }
  258. $result .= $this->getBoundsForOl($srid, $scale_data);
  259. // Trim to remove leading 'LINESTRING(' and trailing ')'
  260. $linesrting
  261. = mb_substr(
  262. $spatial,
  263. 11,
  264. mb_strlen($spatial) - 12
  265. );
  266. $points_arr = $this->extractPoints($linesrting, null);
  267. return $result . 'var line = new ol.Feature({geometry: '
  268. . $this->getLineForOpenLayers($points_arr, $srid) . '});'
  269. . 'line.setStyle(style);'
  270. . 'vectorLayer.addFeature(line);';
  271. }
  272. /**
  273. * Generate the WKT with the set of parameters passed by the GIS editor.
  274. *
  275. * @param array $gis_data GIS data
  276. * @param int $index Index into the parameter object
  277. * @param string $empty Value for empty points
  278. *
  279. * @return string WKT with the set of parameters passed by the GIS editor
  280. *
  281. * @access public
  282. */
  283. public function generateWkt(array $gis_data, $index, $empty = '')
  284. {
  285. $no_of_points = $gis_data[$index]['LINESTRING']['no_of_points'] ?? 2;
  286. if ($no_of_points < 2) {
  287. $no_of_points = 2;
  288. }
  289. $wkt = 'LINESTRING(';
  290. for ($i = 0; $i < $no_of_points; $i++) {
  291. $wkt .= (isset($gis_data[$index]['LINESTRING'][$i]['x'])
  292. && trim((string) $gis_data[$index]['LINESTRING'][$i]['x']) != ''
  293. ? $gis_data[$index]['LINESTRING'][$i]['x'] : $empty)
  294. . ' ' . (isset($gis_data[$index]['LINESTRING'][$i]['y'])
  295. && trim((string) $gis_data[$index]['LINESTRING'][$i]['y']) != ''
  296. ? $gis_data[$index]['LINESTRING'][$i]['y'] : $empty) . ',';
  297. }
  298. $wkt
  299. = mb_substr(
  300. $wkt,
  301. 0,
  302. mb_strlen($wkt) - 1
  303. );
  304. return $wkt . ')';
  305. }
  306. /**
  307. * Generate parameters for the GIS data editor from the value of the GIS column.
  308. *
  309. * @param string $value of the GIS column
  310. * @param int $index of the geometry
  311. *
  312. * @return array params for the GIS data editor from the value of the GIS column
  313. *
  314. * @access public
  315. */
  316. public function generateParams($value, $index = -1)
  317. {
  318. $params = [];
  319. if ($index == -1) {
  320. $index = 0;
  321. $data = GisGeometry::generateParams($value);
  322. $params['srid'] = $data['srid'];
  323. $wkt = $data['wkt'];
  324. } else {
  325. $params[$index]['gis_type'] = 'LINESTRING';
  326. $wkt = $value;
  327. }
  328. // Trim to remove leading 'LINESTRING(' and trailing ')'
  329. $linestring
  330. = mb_substr(
  331. $wkt,
  332. 11,
  333. mb_strlen($wkt) - 12
  334. );
  335. $points_arr = $this->extractPoints($linestring, null);
  336. $no_of_points = count($points_arr);
  337. $params[$index]['LINESTRING']['no_of_points'] = $no_of_points;
  338. for ($i = 0; $i < $no_of_points; $i++) {
  339. $params[$index]['LINESTRING'][$i]['x'] = $points_arr[$i][0];
  340. $params[$index]['LINESTRING'][$i]['y'] = $points_arr[$i][1];
  341. }
  342. return $params;
  343. }
  344. }