判断一个点是否在某个区域内。百度,高德,腾讯都能用。(php版)

举报
lxw1844912514 发表于 2022/03/27 02:21:52 2022/03/27
【摘要】 <?php // *** 配置文件(表示区域的三维数组)其内的点,必须按顺时针方向依次给出! $area = array( // 天通苑店 0 => array( array('x'=>116.38295, 'y'=>40.09416), array('x'=>116.44037,...

    
  1. <?php
  2. // *** 配置文件(表示区域的三维数组)其内的点,必须按顺时针方向依次给出!
  3. $area = array(
  4. // 天通苑店
  5. 0 => array(
  6. array('x'=>116.38295, 'y'=>40.09416),
  7. array('x'=>116.44037, 'y'=>40.095898),
  8. array('x'=>116.448275,'y'=>40.083313),
  9. array('x'=>116.448455,'y'=>40.050818),
  10. array('x'=>116.448275,'y'=>40.038307),
  11. array('x'=>116.441448,'y'=>40.038418),
  12. array('x'=>116.436058,'y'=>40.038804),
  13. array('x'=>116.417302,'y'=>40.039136),
  14. array('x'=>116.414822,'y'=>40.039384),
  15. array('x'=>116.412738,'y'=>40.039329),
  16. array('x'=>116.407672,'y'=>40.039329),
  17. array('x'=>116.388628,'y'=>40.085162),
  18. array('x'=>116.383633,'y'=>40.084997)
  19. ),
  20. //亚运村
  21. 1 => array(
  22. array('x'=>116.358804,'y'=>40.028474),
  23. array('x'=>116.41608, 'y'=>40.02875),
  24. array('x'=>116.41723, 'y'=>40.038915),
  25. array('x'=>116.447988,'y'=>40.037921),
  26. array('x'=>116.447844,'y'=>40.026761),
  27. array('x'=>116.455821,'y'=>40.024164),
  28. array('x'=>116.446281,'y'=>39.994736),
  29. array('x'=>116.443532,'y'=>39.995372),
  30. array('x'=>116.376267,'y'=>39.993493),
  31. array('x'=>116.375908,'y'=>40.000015),
  32. array('x'=>116.372027,'y'=>39.999904),
  33. array('x'=>116.371452,'y'=>40.007366),
  34. array('x'=>116.359451,'y'=>40.006758)
  35. ),
  36. //望京店
  37. 2 => array(
  38. array('x'=>116.46387, 'y'=>40.021125),
  39. array('x'=>116.484495,'y'=>40.020462),
  40. array('x'=>116.515684,'y'=>39.995151),
  41. array('x'=>116.51519, 'y'=>39.976137),
  42. array('x'=>116.491906,'y'=>39.972985),
  43. array('x'=>116.476239,'y'=>39.977298),
  44. array('x'=>116.467472,'y'=>39.96917),
  45. array('x'=>116.443325,'y'=>39.984817),
  46. array('x'=>116.449506,'y'=>39.993109),
  47. array('x'=>116.446357,'y'=>39.994736),
  48. array('x'=>116.456037,'y'=>40.024109)
  49. ),
  50. //大悦城店
  51. 3 => array(
  52. array('x'=>116.496424,'y'=>39.96253),
  53. array('x'=>116.479527,'y'=>39.975491),
  54. array('x'=>116.492921,'y'=>39.972491),
  55. array('x'=>116.508533,'y'=>39.974454),
  56. array('x'=>116.535231,'y'=>39.980225),
  57. array('x'=>116.553485,'y'=>39.975691),
  58. array('x'=>116.564624,'y'=>39.975028),
  59. array('x'=>116.571307,'y'=>39.972097),
  60. array('x'=>116.571666,'y'=>39.946989),
  61. array('x'=>116.547736,'y'=>39.947763),
  62. array('x'=>116.549245,'y'=>39.936755),
  63. array('x'=>116.564624,'y'=>39.937142),
  64. array('x'=>116.569367,'y'=>39.92995),
  65. array('x'=>116.570085,'y'=>39.915175),
  66. array('x'=>116.496424,'y'=>39.914843)
  67. ),
  68. //北洼路
  69. 4 => array(
  70. array('x'=>116.24763, 'y'=>39.978677),
  71. array('x'=>116.280975,'y'=>39.976244),
  72. array('x'=>116.322872,'y'=>39.991226),
  73. array('x'=>116.323231,'y'=>39.986859),
  74. array('x'=>116.339975,'y'=>39.986859),
  75. array('x'=>116.340263,'y'=>39.982215),
  76. array('x'=>116.346443,'y'=>39.98216),
  77. array('x'=>116.354492,'y'=>39.963415),
  78. array('x'=>116.361822,'y'=>39.963637),
  79. array('x'=>116.362397,'y'=>39.957664),
  80. array('x'=>116.37792, 'y'=>39.958106),
  81. array('x'=>116.37138, 'y'=>39.929728),
  82. array('x'=>116.367068,'y'=>39.929341),
  83. array('x'=>116.366637,'y'=>39.924361),
  84. array('x'=>116.37138, 'y'=>39.924361),
  85. array('x'=>116.369655,'y'=>39.913626),
  86. array('x'=>116.362325,'y'=>39.912962),
  87. array('x'=>116.363188,'y'=>39.903774),
  88. array('x'=>116.317194,'y'=>39.902999),
  89. array('x'=>116.259415,'y'=>39.902778)
  90. ),
  91. //安贞店
  92. 5 => array(
  93. array('x'=>116.372171,'y'=>39.993161),
  94. array('x'=>116.443676,'y'=>39.994985),
  95. array('x'=>116.448419,'y'=>39.993548),
  96. array('x'=>116.43807, 'y'=>39.97735),
  97. array('x'=>116.438789,'y'=>39.9656),
  98. array('x'=>116.440298,'y'=>39.955839),
  99. array('x'=>116.42262, 'y'=>39.955673),
  100. array('x'=>116.378531,'y'=>39.954815),
  101. array('x'=>116.377704,'y'=>39.963941),
  102. array('x'=>116.368003,'y'=>39.96383),
  103. array('x'=>116.367679,'y'=>39.973341),
  104. array('x'=>116.361247,'y'=>39.973479),
  105. array('x'=>116.360529,'y'=>39.987025),
  106. array('x'=>116.37235, 'y'=>39.987716)
  107. ),
  108. //三元桥
  109. 6 => array(
  110. array('x'=>116.283706,'y'=>40.114137 ),
  111. array('x'=>116.354995,'y'=>40.121613 ),
  112. array('x'=>116.369081,'y'=>40.114661 ),
  113. array('x'=>116.37871, 'y'=>40.114772 ),
  114. array('x'=>116.380435,'y'=>40.106826 ),
  115. array('x'=>116.385897,'y'=>40.107543 ),
  116. array('x'=>116.389346,'y'=>40.07782 ),
  117. array('x'=>116.370949,'y'=>40.075998 ),
  118. array('x'=>116.37174, 'y'=>40.05739 ),
  119. array('x'=>116.325746,'y'=>40.042643 )
  120. ),
  121. //团结湖
  122. 7 => array(
  123. array('x'=>116.43189, 'y'=>39.955341),
  124. array('x'=>116.440316,'y'=>39.955396),
  125. array('x'=>116.438394,'y'=>39.977225),
  126. array('x'=>116.442849,'y'=>39.984116),
  127. array('x'=>116.467876,'y'=>39.969194),
  128. array('x'=>116.476608,'y'=>39.976797),
  129. array('x'=>116.494969,'y'=>39.963637),
  130. array('x'=>116.496999,'y'=>39.914179),
  131. array('x'=>116.433902,'y'=>39.914511)
  132. ),
  133. //劲松店
  134. 8 => array(
  135. array('x'=>116.4053, 'y'=>39.90632 ),
  136. array('x'=>116.495418,'y'=>39.911412 ),
  137. array('x'=>116.495418,'y'=>39.87709 ),
  138. array('x'=>116.491322,'y'=>39.854717 ),
  139. array('x'=>116.462432,'y'=>39.851892 ),
  140. array('x'=>116.421362,'y'=>39.852141 ),
  141. array('x'=>116.420895,'y'=>39.863412 ),
  142. array('x'=>116.406809,'y'=>39.863412 ),
  143. array('x'=>116.406881,'y'=>39.863357 )
  144. ),
  145. //黄村店
  146. 9 => array(
  147. array('x'=>116.280184,'y'=>39.776406 ),
  148. array('x'=>116.314751,'y'=>39.788383 ),
  149. array('x'=>116.337586,'y'=>39.805041 ),
  150. array('x'=>116.353252,'y'=>39.804487 ),
  151. array('x'=>116.356001,'y'=>39.794703 ),
  152. array('x'=>116.364912,'y'=>39.799138 ),
  153. array('x'=>116.367787,'y'=>39.783836 ),
  154. array('x'=>116.378495,'y'=>39.781507 ),
  155. array('x'=>116.383094,'y'=>39.766479 ),
  156. array('x'=>116.388628,'y'=>39.76426 ),
  157. array('x'=>116.387478,'y'=>39.749616 ),
  158. array('x'=>116.383238,'y'=>39.748507 ),
  159. array('x'=>116.385178,'y'=>39.728255 ),
  160. array('x'=>116.352408,'y'=>39.727423 ),
  161. array('x'=>116.335592,'y'=>39.705888 ),
  162. array('x'=>116.301726,'y'=>39.697727 )
  163. )
  164. );
  165. /*
  166. *** 配置文件(表示区域的三维数组)其内的点,必须按顺时针方向依次给出!
  167. *** 确定一点是否在一区域(多边形)内:
  168. 1:过这一点(x0, y0),画一水平线(y=y0),与多边形的所有边进行交点判断。
  169. 2:获取交点集(其中不含多边形的顶点)
  170. 3:若该点(x0, y0)的左侧和右侧交点个数均为奇数个,则该点在区域(多边形)内。否则:不在。
  171. *** 返回结果:
  172. return === false : 点不在区域内
  173. return 0, 1, 2, 3 ... 点所在的区域编号(配置文件中的区域编号。)
  174. *** Author : Guojunzhou / Eric
  175. *** Main : php20141104@163.com
  176. */
  177. class Area{
  178. // 一个表示区域的三维数组
  179. protected $config = null;
  180. // 包含每个区域的四边形
  181. protected $rectangles = null;
  182. // 每个区域(多边形)的所有边
  183. protected $lines = null;
  184. // 要判断的点的x, y坐标
  185. protected $_x = null;
  186. protected $_y = null;
  187. public function __construct($config){
  188. $this->config = $config;
  189. $this->initRectangles();
  190. $this->initLines();
  191. }
  192. /*
  193. 获取包含每个配送区域的四边形
  194. */
  195. private function initRectangles(){
  196. foreach ($this->config as $k => $v) {
  197. $this->rectangles[$k]['minX'] = $this->getMinXInEachConfig($k);
  198. $this->rectangles[$k]['minY'] = $this->getMinYInEachConfig($k);
  199. $this->rectangles[$k]['maxX'] = $this->getMaxXInEachConfig($k);
  200. $this->rectangles[$k]['maxY'] = $this->getMaxYInEachConfig($k);
  201. }
  202. }
  203. /*
  204. 初始化每个区域(多边形)的边(线段:直线的一部分【限制x或者y坐标范围】)
  205. n 个顶点构成的多边形,有 n-1 条边
  206. */
  207. private function initLines(){
  208. foreach ($this->config as $k => $v) {
  209. $pointNum = count($v); // 区域的顶点个数
  210. $lineNum = $pointNum - 1; // 区域的边条数
  211. for($i=0; $i<$lineNum; $i++){
  212. // y=kx+b : k
  213. if($this->config[$k][$i]['x'] - $this->config[$k][$i+1]['x'] == 0) $this->lines[$k][$i]['k'] = 0;
  214. else $this->lines[$k][$i]['k'] =
  215. ($this->config[$k][$i]['y'] - $this->config[$k][$i+1]['y'])/($this->config[$k][$i]['x'] - $this->config[$k][$i+1]['x']);
  216. // y=kx+b : b
  217. $this->lines[$k][$i]['b'] = $this->config[$k][$i+1]['y'] - $this->lines[$k][$i]['k'] * $this->config[$k][$i+1]['x'];
  218. $this->lines[$k][$i]['lx'] = min($this->config[$k][$i]['x'], $this->config[$k][$i+1]['x']);
  219. $this->lines[$k][$i]['rx'] = max($this->config[$k][$i]['x'], $this->config[$k][$i+1]['x']);
  220. }
  221. $pointNum-=1;
  222. if($this->config[$k][$pointNum]['x'] - $this->config[$k][0]['x'] == 0) $this->lines[$k][$pointNum]['k'] = 0;
  223. else $this->lines[$k][$pointNum]['k'] =
  224. ($this->config[$k][$pointNum]['y'] - $this->config[$k][0]['y'])/($this->config[$k][$pointNum]['x'] - $this->config[$k][0]['x']);
  225. // y=kx+b : b
  226. $this->lines[$k][$pointNum]['b'] = $this->config[$k][0]['y'] - $this->lines[$k][$pointNum]['k'] * $this->config[$k][0]['x'];
  227. $this->lines[$k][$pointNum]['lx'] = min($this->config[$k][$pointNum]['x'], $this->config[$k][0]['x']);
  228. $this->lines[$k][$pointNum]['rx'] = max($this->config[$k][$pointNum]['x'], $this->config[$k][0]['x']);
  229. }
  230. }
  231. /*
  232. 获取一组坐标中,x坐标最小值
  233. */
  234. private function getMinXInEachConfig($index){
  235. $minX = 200;
  236. foreach ($this->config[$index] as $k => $v) {
  237. if($v['x'] < $minX){
  238. $minX = $v['x'];
  239. }
  240. }
  241. return $minX;
  242. }
  243. /*
  244. 获取一组坐标中,y坐标最小值
  245. */
  246. private function getMinYInEachConfig($index){
  247. $minY = 200;
  248. foreach ($this->config[$index] as $k => $v) {
  249. if($v['y'] < $minY){
  250. $minY = $v['y'];
  251. }
  252. }
  253. return $minY;
  254. }
  255. /*
  256. 获取一组坐标中,x坐标最大值
  257. */
  258. public function getMaxXInEachConfig($index){
  259. $maxX = 0;
  260. foreach ($this->config[$index] as $k => $v) {
  261. if($v['x'] > $maxX){
  262. $maxX = $v['x'];
  263. }
  264. }
  265. return $maxX;
  266. }
  267. /*
  268. 获取一组坐标中,y坐标最大值
  269. */
  270. public function getMaxYInEachConfig($index){
  271. $maxY = 0;
  272. foreach ($this->config[$index] as $k => $v) {
  273. if($v['y'] > $maxY){
  274. $maxY = $v['y'];
  275. }
  276. }
  277. return $maxY;
  278. }
  279. /*
  280. 获取 y=y0 与特定区域的所有边的交点,并去除和顶点重复的,再将交点分为左和右两部分
  281. */
  282. private function getCrossPointInCertainConfig($index){
  283. $crossPoint = null;
  284. foreach ($this->lines[$index] as $k => $v) {
  285. if($v['k'] == 0) return true;
  286. $x0 = ($this->_y - $v['b']) / $v['k']; // 交点x坐标
  287. if($x0 == $this->_x) return true; // 点在边上
  288. if($x0 > $v['lx'] && $x0 < $v['rx']){
  289. if($x0 < $this->_x) $crossPoint['left'][] = $x0;
  290. if($x0 > $this->_x) $crossPoint['right'][] = $x0;
  291. }
  292. }
  293. return $crossPoint;
  294. }
  295. /*
  296. 检测一个点,是否在区域内
  297. 返回结果:
  298. return === false : 点不在区域内
  299. return 0, 1, 2, 3 ... 点所在的区域编号(配置文件中的区域编号。)
  300. */
  301. public function checkPoint($x, $y){
  302. $this->_x = $x;
  303. $this->_y = $y;
  304. $contain = null;
  305. foreach ($this->rectangles as $k => $v) {
  306. if($x > $v['maxX'] || $x < $v['minX'] || $y > $v['maxY'] || $y < $v['minY']){
  307. continue;
  308. }else{
  309. $contain = $k;
  310. break;
  311. }
  312. }
  313. if($contain === null) return false;
  314. $crossPoint = $this->getCrossPointInCertainConfig($contain);
  315. if($crossPoint === true) return $contain;
  316. if(count($crossPoint['left'])%2 == 1 && count($crossPoint['right'])%2 == 1) return $contain;
  317. return false;
  318. }
  319. }
  320. $area = new Area($area);
  321. var_dump($area->checkPoint(116.531748,39.944229));
  322. ?>

  

https://blog.csdn.net/u014290054/article/details/47418065

文章来源: blog.csdn.net,作者:lxw1844912514,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/lxw1844912514/article/details/100028556

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。