You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

93 lines
3.6 KiB

6 years ago
6 years ago
  1. <?php
  2. namespace p3k\geo;
  3. //RamerDouglasPeucker
  4. //Reduces the number of points on a polyline by removing those that are closer to the line
  5. //than the distance $epsilon.
  6. //The polyline is provided as an array of arrays, where each internal array is one point on the polyline,
  7. //specified by easting (x-coordinate) with key "0" and northing (y-coordinate) with key "1".
  8. //It is assumed that the coordinates and distance $epsilon are given in the same units.
  9. //The result is returned as an array in a similar format.
  10. //Each point returned in the result array will retain all its original data, including its E and N
  11. //values along with any others.
  12. function ramerDouglasPeucker($pointList, $epsilon)
  13. {
  14. if(count($pointList) == 0)
  15. return array();
  16. // Find the point with the maximum distance
  17. $dmax = 0;
  18. $index = 0;
  19. $totalPoints = count($pointList);
  20. for ($i = 1; $i < ($totalPoints - 1); $i++)
  21. {
  22. $d = perpendicularDistance($pointList[$i][0], $pointList[$i][1],
  23. $pointList[0][0], $pointList[0][1],
  24. $pointList[$totalPoints-1][0], $pointList[$totalPoints-1][1]);
  25. if ($d > $dmax)
  26. {
  27. $index = $i;
  28. $dmax = $d;
  29. }
  30. }
  31. $resultList = array();
  32. // If max distance is greater than epsilon, recursively simplify
  33. if ($dmax >= $epsilon)
  34. {
  35. // Recursive call
  36. $recResults1 = ramerDouglasPeucker(array_slice($pointList, 0, $index + 1), $epsilon);
  37. $recResults2 = ramerDouglasPeucker(array_slice($pointList, $index, $totalPoints - $index), $epsilon);
  38. // Build the result list
  39. $resultList = array_merge(array_slice($recResults1, 0, count($recResults1) - 1),
  40. array_slice($recResults2, 0, count($recResults2)));
  41. }
  42. else
  43. {
  44. $resultList = array($pointList[0], $pointList[$totalPoints-1]);
  45. }
  46. // Return the result
  47. return $resultList;
  48. }
  49. // http://www.loughrigg.org/rdp/
  50. //The author has placed this work in the Public Domain, thereby relinquishing all copyrights.
  51. //You may use, modify, republish, sell or give away this work without prior consent.
  52. //This implementation comes with no warranty or guarantee of fitness for any purpose.
  53. //=========================================================================
  54. //An implementation of the Ramer-Douglas-Peucker algorithm for reducing
  55. //the number of points on a polyline
  56. //see http://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm
  57. //=========================================================================
  58. //Finds the perpendicular distance from a point to a straight line.
  59. //The coordinates of the point are specified as $ptX and $ptY.
  60. //The line passes through points l1 and l2, specified respectively with their
  61. //coordinates $l1x and $l1y, and $l2x and $l2y
  62. function perpendicularDistance($ptX, $ptY, $l1x, $l1y, $l2x, $l2y)
  63. {
  64. $result = 0;
  65. if ($l2x == $l1x)
  66. {
  67. //vertical lines - treat this case specially to avoid divide by zero
  68. $result = abs($ptX - $l2x);
  69. }
  70. else
  71. {
  72. $slope = (($l2y-$l1y) / ($l2x-$l1x));
  73. $passThroughY = (0-$l1x)*$slope + $l1y;
  74. $result = (abs(($slope * $ptX) - $ptY + $passThroughY)) / (sqrt($slope*$slope + 1));
  75. }
  76. return $result;
  77. }
  78. // Calculate the Great Circle distance between two points, in meters
  79. function gc_distance($lat1, $lng1, $lat2, $lng2) {
  80. return ( 6378100 * acos( cos( deg2rad($lat1) ) * cos( deg2rad($lat2) ) * cos( deg2rad($lng2) - deg2rad($lng1) ) + sin( deg2rad($lat1) ) * sin( deg2rad($lat2) ) ) );
  81. }