ConvertHandler.php 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: Mead
  5. * Date: 2019/8/31
  6. * Time: 2:42 PM
  7. */
  8. namespace App\Handlers;
  9. use Illuminate\Support\Facades\Log;
  10. /**
  11. * Created by PhpStorm.
  12. * User: 申大侠
  13. * Date: 2018/7/11
  14. * Time: 9:19
  15. */
  16. class ConvertHandler
  17. {
  18. private $PI = 3.14159265358979324;
  19. private $x_pi = 0;
  20. public function __construct()
  21. {
  22. $this->x_pi = 3.14159265358979324 * 3000.0 / 180.0;
  23. }
  24. /**
  25. * 判断一个坐标是否在圆内
  26. * 思路:判断此点的经纬度到圆心的距离 然后和半径做比较
  27. * 如果此点刚好在圆上 则返回true
  28. * @param $point ['longitude'=>'','latitude'=>''] array指定点的坐标
  29. * @param $circle array ['center'=>['longitude'=>'','latitude'=>''],'radius'=>''] 中心点和半径
  30. */
  31. function is_point_in_circle($point, $circle)
  32. {
  33. // Log::info($circle);
  34. // $circle['center']['latitude'] = json_decode($circle['center'])[1];
  35. // $circle['center']['longitude'] = json_decode($circle['center'])[0];
  36. // Log::info($circle);
  37. $data = json_decode($circle['center']);
  38. // Log::info($data);
  39. $center['lat'] = $data[1];
  40. $center['lng'] = $data[0];
  41. $distance = $this->distance($point['latitude'], $point['longitude'], $center['lat'], $center['lng']);
  42. if ($distance <= $circle['radius']) {
  43. return true;
  44. } else {
  45. return false;
  46. }
  47. }
  48. /**
  49. * 计算两个点之间的距离
  50. * @return float
  51. */
  52. function distance($latitudeA, $lonA, $latitudeB, $lonB)
  53. {
  54. $earthR = 6371000.;
  55. $x = cos($latitudeA * $this->PI / 180.) * cos($latitudeB * $this->PI / 180.) * cos(($lonA - $lonB) * $this->PI / 180);
  56. $y = sin($latitudeA * $this->PI / 180.) * sin($latitudeB * $this->PI / 180.);
  57. $s = $x + $y;
  58. if ($s > 1) $s = 1;
  59. if ($s < -1) $s = -1;
  60. $alpha = acos($s);
  61. $distance = $alpha * $earthR;
  62. return $distance;
  63. }
  64. /**
  65. * 判断一个坐标是否在一个多边形内(由多个坐标围成的)
  66. * 基本思想是利用射线法,计算射线与多边形各边的交点,如果是偶数,则点在多边形外,否则
  67. * 在多边形内。还会考虑一些特殊情况,如点在多边形顶点上,点在多边形边上等特殊情况。
  68. *
  69. */
  70. function is_point_in_polygon($point, $pts)
  71. {
  72. $pts = json_decode($pts);
  73. // Log::info($pts);
  74. $dataPts = [];
  75. foreach ($pts as $v){
  76. $itemData['longitude'] = $v[0];
  77. $itemData['latitude'] = $v[1];
  78. $dataPts[] = $itemData;
  79. }
  80. $pts = $dataPts;
  81. // Log::info($pts);
  82. $N = count($pts);
  83. $boundOrVertex = true; //如果点位于多边形的顶点或边上,也算做点在多边形内,直接返回true
  84. $intersectCount = 0;//cross points count of x
  85. $precision = 2e-10; //浮点类型计算时候与0比较时候的容差
  86. $p1 = 0;//neighbour bound vertices
  87. $p2 = 0;
  88. $p = $point; //测试点
  89. $p1 = $pts[0];//left vertex
  90. for ($i = 1; $i <= $N; ++$i) {//check all rays
  91. // dump($p1);
  92. if ($p['longitude'] == $p1['longitude'] && $p['latitude'] == $p1['latitude']) {
  93. return $boundOrVertex;//p is an vertex
  94. }
  95. $p2 = $pts[$i % $N];//right vertex
  96. if ($p['latitude'] < min($p1['latitude'], $p2['latitude']) || $p['latitude'] > max($p1['latitude'], $p2['latitude'])) {//ray is outside of our interests
  97. $p1 = $p2;
  98. continue;//next ray left point
  99. }
  100. if ($p['latitude'] > min($p1['latitude'], $p2['latitude']) && $p['latitude'] < max($p1['latitude'], $p2['latitude'])) {//ray is crossing over by the algorithm (common part of)
  101. if ($p['longitude'] <= max($p1['longitude'], $p2['longitude'])) {//x is before of ray
  102. if ($p1['latitude'] == $p2['latitude'] && $p['longitude'] >= min($p1['longitude'], $p2['longitude'])) {//overlies on a horizontal ray
  103. return $boundOrVertex;
  104. }
  105. if ($p1['longitude'] == $p2['longitude']) {//ray is vertical
  106. if ($p1['longitude'] == $p['longitude']) {//overlies on a vertical ray
  107. return $boundOrVertex;
  108. } else {//before ray
  109. ++$intersectCount;
  110. }
  111. } else {//cross point on the left side
  112. $xinters = ($p['latitude'] - $p1['latitude']) * ($p2['longitude'] - $p1['longitude']) / ($p2['latitude'] - $p1['latitude']) + $p1['longitude'];//cross point of longitude
  113. if (abs($p['longitude'] - $xinters) < $precision) {//overlies on a ray
  114. return $boundOrVertex;
  115. }
  116. if ($p['longitude'] < $xinters) {//before ray
  117. ++$intersectCount;
  118. }
  119. }
  120. }
  121. } else {//special case when ray is crossing through the vertex
  122. if ($p['latitude'] == $p2['latitude'] && $p['longitude'] <= $p2['longitude']) {//p crossing over p2
  123. $p3 = $pts[($i + 1) % $N]; //next vertex
  124. if ($p['latitude'] >= min($p1['latitude'], $p3['latitude']) && $p['latitude'] <= max($p1['latitude'], $p3['latitude'])) { //p.latitude lies between p1.latitude & p3.latitude
  125. ++$intersectCount;
  126. } else {
  127. $intersectCount += 2;
  128. }
  129. }
  130. }
  131. $p1 = $p2;//next ray left point
  132. }
  133. if ($intersectCount % 2 == 0) {//偶数在多边形外
  134. return false;
  135. } else { //奇数在多边形内
  136. return true;
  137. }
  138. }
  139. function is_point_in_polygon_lat_lng($point, $pts)
  140. {
  141. $pts = json_decode($pts,true);
  142. // Log::info($pts);
  143. $dataPts = [];
  144. foreach ($pts as $v){
  145. $itemData['longitude'] = $v['lng'];
  146. $itemData['latitude'] = $v['lat'];
  147. $dataPts[] = $itemData;
  148. }
  149. $pts = $dataPts;
  150. Log::info($pts);
  151. $N = count($pts);
  152. $boundOrVertex = true; //如果点位于多边形的顶点或边上,也算做点在多边形内,直接返回true
  153. $intersectCount = 0;//cross points count of x
  154. $precision = 2e-10; //浮点类型计算时候与0比较时候的容差
  155. $p1 = 0;//neighbour bound vertices
  156. $p2 = 0;
  157. $point['longitude'] = $point['lng'];
  158. $point['latitude'] = $point['lat'];
  159. $p = $point; //测试点
  160. $p1 = $pts[0];//left vertex
  161. for ($i = 1; $i <= $N; ++$i) {//check all rays
  162. // dump($p1);
  163. if ($p['longitude'] == $p1['longitude'] && $p['latitude'] == $p1['latitude']) {
  164. return $boundOrVertex;//p is an vertex
  165. }
  166. $p2 = $pts[$i % $N];//right vertex
  167. if ($p['latitude'] < min($p1['latitude'], $p2['latitude']) || $p['latitude'] > max($p1['latitude'], $p2['latitude'])) {//ray is outside of our interests
  168. $p1 = $p2;
  169. continue;//next ray left point
  170. }
  171. if ($p['latitude'] > min($p1['latitude'], $p2['latitude']) && $p['latitude'] < max($p1['latitude'], $p2['latitude'])) {//ray is crossing over by the algorithm (common part of)
  172. if ($p['longitude'] <= max($p1['longitude'], $p2['longitude'])) {//x is before of ray
  173. if ($p1['latitude'] == $p2['latitude'] && $p['longitude'] >= min($p1['longitude'], $p2['longitude'])) {//overlies on a horizontal ray
  174. return $boundOrVertex;
  175. }
  176. if ($p1['longitude'] == $p2['longitude']) {//ray is vertical
  177. if ($p1['longitude'] == $p['longitude']) {//overlies on a vertical ray
  178. return $boundOrVertex;
  179. } else {//before ray
  180. ++$intersectCount;
  181. }
  182. } else {//cross point on the left side
  183. $xinters = ($p['latitude'] - $p1['latitude']) * ($p2['longitude'] - $p1['longitude']) / ($p2['latitude'] - $p1['latitude']) + $p1['longitude'];//cross point of longitude
  184. if (abs($p['longitude'] - $xinters) < $precision) {//overlies on a ray
  185. return $boundOrVertex;
  186. }
  187. if ($p['longitude'] < $xinters) {//before ray
  188. ++$intersectCount;
  189. }
  190. }
  191. }
  192. } else {//special case when ray is crossing through the vertex
  193. if ($p['latitude'] == $p2['latitude'] && $p['longitude'] <= $p2['longitude']) {//p crossing over p2
  194. $p3 = $pts[($i + 1) % $N]; //next vertex
  195. if ($p['latitude'] >= min($p1['latitude'], $p3['latitude']) && $p['latitude'] <= max($p1['latitude'], $p3['latitude'])) { //p.latitude lies between p1.latitude & p3.latitude
  196. ++$intersectCount;
  197. } else {
  198. $intersectCount += 2;
  199. }
  200. }
  201. }
  202. $p1 = $p2;//next ray left point
  203. }
  204. if ($intersectCount % 2 == 0) {//偶数在多边形外
  205. return false;
  206. } else { //奇数在多边形内
  207. return true;
  208. }
  209. }
  210. }