distance.php 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. <?php
  2. //if(!$_GET['longitude'] || !$_GET['latitude']) exit('-1');
  3. // longitude 经度
  4. // latitude 维度
  5. class Convert{
  6. private $PI = 3.14159265358979324;
  7. private $x_pi = 0;
  8. public function __construct()
  9. {
  10. $this->x_pi = 3.14159265358979324 * 3000.0 / 180.0;
  11. }
  12. /**
  13. * 判断一个坐标是否在圆内
  14. * 思路:判断此点的经纬度到圆心的距离 然后和半径做比较
  15. * 如果此点刚好在圆上 则返回true
  16. * @param $point ['lng'=>'','lat'=>''] array指定点的坐标
  17. * @param $circle array ['center'=>['lng'=>'','lat'=>''],'radius'=>''] 中心点和半径
  18. */
  19. function is_point_in_circle($point, $circle){
  20. $distance = $this -> distance($point['lat'],$point['lng'],$circle['center']['lat'],$circle['center']['lng']);
  21. if($distance <= $circle['radius']){
  22. return true;
  23. }else{
  24. return false;
  25. }
  26. }
  27. /**
  28. * 计算两个点之间的距离
  29. * @param $latA 第一个点的纬度
  30. * @param $lonA 第一个点的经度
  31. * @param $latB 第二个点的纬度
  32. * @param $lonB 第二个点的经度
  33. * @return float
  34. */
  35. function distance($latA, $lonA, $latB, $lonB)
  36. {
  37. $earthR = 6371000.;
  38. $x = cos($latA * $this->PI / 180.) * cos($latB * $this->PI / 180.) * cos(($lonA - $lonB) * $this->PI / 180);
  39. $y = sin($latA * $this->PI / 180.) * sin($latB * $this->PI / 180.);
  40. $s = $x + $y;
  41. if ($s > 1) $s = 1;
  42. if ($s < -1) $s = -1;
  43. $alpha = acos($s);
  44. $distance = $alpha * $earthR;
  45. return $distance;
  46. }
  47. /**
  48. * 判断一个坐标是否在一个多边形内(由多个坐标围成的)
  49. * 基本思想是利用射线法,计算射线与多边形各边的交点,如果是偶数,则点在多边形外,否则
  50. * 在多边形内。还会考虑一些特殊情况,如点在多边形顶点上,点在多边形边上等特殊情况。
  51. * @param $point 指定点坐标
  52. * @param $pts 多边形坐标 顺时针方向
  53. */
  54. function is_point_in_polygon($point, $pts) {
  55. $N = count($pts);
  56. $boundOrVertex = true; //如果点位于多边形的顶点或边上,也算做点在多边形内,直接返回true
  57. $intersectCount = 0;//cross points count of x
  58. $precision = 2e-10; //浮点类型计算时候与0比较时候的容差
  59. $p1 = 0;//neighbour bound vertices
  60. $p2 = 0;
  61. $p = $point; //测试点
  62. $p1 = $pts[0];//left vertex
  63. for ($i = 1; $i <= $N; ++$i) {//check all rays
  64. // dump($p1);
  65. if ($p['lng'] == $p1['lng'] && $p['lat'] == $p1['lat']) {
  66. return $boundOrVertex;//p is an vertex
  67. }
  68. $p2 = $pts[$i % $N];//right vertex
  69. if ($p['lat'] < min($p1['lat'], $p2['lat']) || $p['lat'] > max($p1['lat'], $p2['lat'])) {//ray is outside of our interests
  70. $p1 = $p2;
  71. continue;//next ray left point
  72. }
  73. if ($p['lat'] > min($p1['lat'], $p2['lat']) && $p['lat'] < max($p1['lat'], $p2['lat'])) {//ray is crossing over by the algorithm (common part of)
  74. if($p['lng'] <= max($p1['lng'], $p2['lng'])){//x is before of ray
  75. if ($p1['lat'] == $p2['lat'] && $p['lng'] >= min($p1['lng'], $p2['lng'])) {//overlies on a horizontal ray
  76. return $boundOrVertex;
  77. }
  78. if ($p1['lng'] == $p2['lng']) {//ray is vertical
  79. if ($p1['lng'] == $p['lng']) {//overlies on a vertical ray
  80. return $boundOrVertex;
  81. } else {//before ray
  82. ++$intersectCount;
  83. }
  84. } else {//cross point on the left side
  85. $xinters = ($p['lat'] - $p1['lat']) * ($p2['lng'] - $p1['lng']) / ($p2['lat'] - $p1['lat']) + $p1['lng'];//cross point of lng
  86. if (abs($p['lng'] - $xinters) < $precision) {//overlies on a ray
  87. return $boundOrVertex;
  88. }
  89. if ($p['lng'] < $xinters) {//before ray
  90. ++$intersectCount;
  91. }
  92. }
  93. }
  94. } else {//special case when ray is crossing through the vertex
  95. if ($p['lat'] == $p2['lat'] && $p['lng'] <= $p2['lng']) {//p crossing over p2
  96. $p3 = $pts[($i+1) % $N]; //next vertex
  97. if ($p['lat'] >= min($p1['lat'], $p3['lat']) && $p['lat'] <= max($p1['lat'], $p3['lat'])) { //p.lat lies between p1.lat & p3.lat
  98. ++$intersectCount;
  99. } else {
  100. $intersectCount += 2;
  101. }
  102. }
  103. }
  104. $p1 = $p2;//next ray left point
  105. }
  106. if ($intersectCount % 2 == 0) {//偶数在多边形外
  107. return false;
  108. } else { //奇数在多边形内
  109. return true;
  110. }
  111. }
  112. }
  113. //$point = ['lng'=>$_GET['longitude'],'lat'=>$_GET['latitude']];
  114. /*$circle = [
  115. 'center'=>['lng'=>116.12637,'lat'=>40.114308],
  116. 'radius'=>46807.83038795571
  117. ];*/
  118. //$convert = new Convert();
  119. //$bool = $convert -> is_point_in_circle($point,$circle);
  120. //var_dump($bool);
  121. /*$pts = [
  122. ['lng'=>108.326212, 'lat'=>22.891039],
  123. ['lng'=>108.274757, 'lat'=>22.890107],
  124. ['lng'=>108.22359, 'lat'=>22.856143],
  125. ['lng'=>108.235304, 'lat'=>22.791654],
  126. ['lng'=>108.247449, 'lat'=>22.769528],
  127. ['lng'=>108.276697, 'lat'=>22.755665],
  128. ['lng'=>108.323769, 'lat'=>22.754065],
  129. ['lng'=>108.334189, 'lat'=>22.722067],
  130. ['lng'=>108.390531, 'lat'=>22.7332],
  131. ['lng'=>108.441986, 'lat'=>22.761664],
  132. ['lng'=>108.497609, 'lat'=>22.787922],
  133. ['lng'=>108.494375, 'lat'=>22.821637],
  134. ['lng'=>108.446441, 'lat'=>22.819638],
  135. ['lng'=>108.42711, 'lat'=>22.85128],
  136. ['lng'=>108.375295, 'lat'=>22.878187],
  137. ['lng'=>108.326217, 'lat'=>22.891035],
  138. ['lng'=>108.326203, 'lat'=>22.891039],
  139. ['lng'=>108.326203, 'lat'=>22.891039],
  140. ['lng'=>108.326203, 'lat'=>22.891039]
  141. ];*/
  142. //$point = ['lng'=>115.989864,'lat'=>39.973272];
  143. //$bool = $convert -> is_point_in_polygon($point,$pts);
  144. //var_dump($bool);