zoukankan      html  css  js  c++  java
  • 推断一个点是否在某个区域内。百度,高德,腾讯都能用。(php版)

    <?php
    	// *** 配置文件(表示区域的三维数组)其内的点。必须按顺时针方向依次给出。
    	$area = array(
    		// 天通苑店
    		0 => array(
    			array('x'=>116.38295, 'y'=>40.09416),
    			array('x'=>116.44037, 'y'=>40.095898),
    			array('x'=>116.448275,'y'=>40.083313),
    			array('x'=>116.448455,'y'=>40.050818),
    			array('x'=>116.448275,'y'=>40.038307),
    			array('x'=>116.441448,'y'=>40.038418),
    			array('x'=>116.436058,'y'=>40.038804),
    			array('x'=>116.417302,'y'=>40.039136),
    			array('x'=>116.414822,'y'=>40.039384),
    			array('x'=>116.412738,'y'=>40.039329),
    			array('x'=>116.407672,'y'=>40.039329),
    			array('x'=>116.388628,'y'=>40.085162),
    			array('x'=>116.383633,'y'=>40.084997)
    		),
    		//亚运村
    		1 => array(
    			array('x'=>116.358804,'y'=>40.028474),
    			array('x'=>116.41608, 'y'=>40.02875),
    			array('x'=>116.41723, 'y'=>40.038915),
    			array('x'=>116.447988,'y'=>40.037921),
    			array('x'=>116.447844,'y'=>40.026761),
    			array('x'=>116.455821,'y'=>40.024164),
    			array('x'=>116.446281,'y'=>39.994736),
    			array('x'=>116.443532,'y'=>39.995372),
    			array('x'=>116.376267,'y'=>39.993493),
    			array('x'=>116.375908,'y'=>40.000015),
    			array('x'=>116.372027,'y'=>39.999904),
    			array('x'=>116.371452,'y'=>40.007366),
    			array('x'=>116.359451,'y'=>40.006758)
    		),
    		//望京店
    		2 => array(
    			array('x'=>116.46387, 'y'=>40.021125),
    			array('x'=>116.484495,'y'=>40.020462),
    			array('x'=>116.515684,'y'=>39.995151),
    			array('x'=>116.51519, 'y'=>39.976137),
    			array('x'=>116.491906,'y'=>39.972985),
    			array('x'=>116.476239,'y'=>39.977298),
    			array('x'=>116.467472,'y'=>39.96917),
    			array('x'=>116.443325,'y'=>39.984817),
    			array('x'=>116.449506,'y'=>39.993109),
    			array('x'=>116.446357,'y'=>39.994736),
    			array('x'=>116.456037,'y'=>40.024109)
    		),
    		//大悦城店
    		3 => array(
    			array('x'=>116.496424,'y'=>39.96253),
    			array('x'=>116.479527,'y'=>39.975491),
    			array('x'=>116.492921,'y'=>39.972491),
    			array('x'=>116.508533,'y'=>39.974454),
    			array('x'=>116.535231,'y'=>39.980225),
    			array('x'=>116.553485,'y'=>39.975691),
    			array('x'=>116.564624,'y'=>39.975028),
    			array('x'=>116.571307,'y'=>39.972097),
    			array('x'=>116.571666,'y'=>39.946989),
    			array('x'=>116.547736,'y'=>39.947763),
    			array('x'=>116.549245,'y'=>39.936755),
    			array('x'=>116.564624,'y'=>39.937142),
    			array('x'=>116.569367,'y'=>39.92995),
    			array('x'=>116.570085,'y'=>39.915175),
    			array('x'=>116.496424,'y'=>39.914843)
    		),
    		//北洼路
    		4 => array(
    			array('x'=>116.24763, 'y'=>39.978677),
    			array('x'=>116.280975,'y'=>39.976244),
    			array('x'=>116.322872,'y'=>39.991226),
    			array('x'=>116.323231,'y'=>39.986859),
    			array('x'=>116.339975,'y'=>39.986859),
    			array('x'=>116.340263,'y'=>39.982215),
    			array('x'=>116.346443,'y'=>39.98216),
    			array('x'=>116.354492,'y'=>39.963415),
    			array('x'=>116.361822,'y'=>39.963637),
    			array('x'=>116.362397,'y'=>39.957664),
    			array('x'=>116.37792, 'y'=>39.958106),
    			array('x'=>116.37138, 'y'=>39.929728),
    			array('x'=>116.367068,'y'=>39.929341),
    			array('x'=>116.366637,'y'=>39.924361),
    			array('x'=>116.37138, 'y'=>39.924361),
    			array('x'=>116.369655,'y'=>39.913626),
    			array('x'=>116.362325,'y'=>39.912962),
    			array('x'=>116.363188,'y'=>39.903774),
    			array('x'=>116.317194,'y'=>39.902999),
    			array('x'=>116.259415,'y'=>39.902778)
    		),
    		//安贞店
    		5 => array(
    			array('x'=>116.372171,'y'=>39.993161),
    			array('x'=>116.443676,'y'=>39.994985),
    			array('x'=>116.448419,'y'=>39.993548),
    			array('x'=>116.43807, 'y'=>39.97735),
    			array('x'=>116.438789,'y'=>39.9656),
    			array('x'=>116.440298,'y'=>39.955839),
    			array('x'=>116.42262, 'y'=>39.955673),
    			array('x'=>116.378531,'y'=>39.954815),
    			array('x'=>116.377704,'y'=>39.963941),
    			array('x'=>116.368003,'y'=>39.96383),
    			array('x'=>116.367679,'y'=>39.973341),
    			array('x'=>116.361247,'y'=>39.973479),
    			array('x'=>116.360529,'y'=>39.987025),
    			array('x'=>116.37235, 'y'=>39.987716)  
    		),
    		//三元桥
    		6 => array(
    			array('x'=>116.283706,'y'=>40.114137  ),    
    			array('x'=>116.354995,'y'=>40.121613  ),    
    			array('x'=>116.369081,'y'=>40.114661  ),    
    			array('x'=>116.37871, 'y'=>40.114772  ),   
    			array('x'=>116.380435,'y'=>40.106826  ),    
    			array('x'=>116.385897,'y'=>40.107543  ),    
    			array('x'=>116.389346,'y'=>40.07782   ),   
    			array('x'=>116.370949,'y'=>40.075998  ),    
    			array('x'=>116.37174, 'y'=>40.05739   ),  
    			array('x'=>116.325746,'y'=>40.042643  )  
    		),
    		//团结湖
    		7 => array(
    			array('x'=>116.43189, 'y'=>39.955341),
    			array('x'=>116.440316,'y'=>39.955396),
    			array('x'=>116.438394,'y'=>39.977225),
    			array('x'=>116.442849,'y'=>39.984116),
    			array('x'=>116.467876,'y'=>39.969194),
    			array('x'=>116.476608,'y'=>39.976797),
    			array('x'=>116.494969,'y'=>39.963637),
    			array('x'=>116.496999,'y'=>39.914179),
    			array('x'=>116.433902,'y'=>39.914511)
    		),
    		//劲松店
    		8 => array(
    			array('x'=>116.4053,  'y'=>39.90632  ),
    			array('x'=>116.495418,'y'=>39.911412 ),   
    			array('x'=>116.495418,'y'=>39.87709  ),  
    			array('x'=>116.491322,'y'=>39.854717 ),   
    			array('x'=>116.462432,'y'=>39.851892 ),   
    			array('x'=>116.421362,'y'=>39.852141 ),   
    			array('x'=>116.420895,'y'=>39.863412 ),   
    			array('x'=>116.406809,'y'=>39.863412 ),   
    			array('x'=>116.406881,'y'=>39.863357 )  
    		),
    		//黄村店
    		9 => array(
    			array('x'=>116.280184,'y'=>39.776406 ),  
    			array('x'=>116.314751,'y'=>39.788383 ),  
    			array('x'=>116.337586,'y'=>39.805041 ),  
    			array('x'=>116.353252,'y'=>39.804487 ),  
    			array('x'=>116.356001,'y'=>39.794703 ),  
    			array('x'=>116.364912,'y'=>39.799138 ),  
    			array('x'=>116.367787,'y'=>39.783836 ),  
    			array('x'=>116.378495,'y'=>39.781507 ),  
    			array('x'=>116.383094,'y'=>39.766479 ),  
    			array('x'=>116.388628,'y'=>39.76426  ), 
    			array('x'=>116.387478,'y'=>39.749616 ),  
    			array('x'=>116.383238,'y'=>39.748507 ),  
    			array('x'=>116.385178,'y'=>39.728255 ),  
    			array('x'=>116.352408,'y'=>39.727423 ),  
    			array('x'=>116.335592,'y'=>39.705888 ),  
    			array('x'=>116.301726,'y'=>39.697727 )  
    		)
    	);
    /*
    	*** 配置文件(表示区域的三维数组)其内的点,必须按顺时针方向依次给出!

    *** 确定一点是否在一区域(多边形)内: 1:过这一点(x0, y0),画一水平线(y=y0),与多边形的全部边进行交点推断。 2:获取交点集(当中不含多边形的顶点) 3:若该点(x0, y0)的左側和右側交点个数均为奇数个。则该点在区域(多边形)内。否则:不在。 *** 返回结果: return === false : 点不在区域内 return 0, 1, 2, 3 ... 点所在的区域编号(配置文件里的区域编号。) *** Author : Guojunzhou / Eric *** Main : php20141104@163.com */ class Area{ // 一个表示区域的三维数组 protected $config = null; // 包括每一个区域的四边形 protected $rectangles = null; // 每一个区域(多边形)的全部边 protected $lines = null; // 要推断的点的x, y坐标 protected $_x = null; protected $_y = null; public function __construct($config){ $this->config = $config; $this->initRectangles(); $this->initLines(); } /* 获取包括每一个配送区域的四边形 */ private function initRectangles(){ foreach ($this->config as $k => $v) { $this->rectangles[$k]['minX'] = $this->getMinXInEachConfig($k); $this->rectangles[$k]['minY'] = $this->getMinYInEachConfig($k); $this->rectangles[$k]['maxX'] = $this->getMaxXInEachConfig($k); $this->rectangles[$k]['maxY'] = $this->getMaxYInEachConfig($k); } } /* 初始化每一个区域(多边形)的边(线段:直线的一部分【限制x或者y坐标范围】) n 个顶点构成的多边形,有 n-1 条边 */ private function initLines(){ foreach ($this->config as $k => $v) { $pointNum = count($v); // 区域的顶点个数 $lineNum = $pointNum - 1; // 区域的边条数 for($i=0; $i<$lineNum; $i++){ // y=kx+b : k if($this->config[$k][$i]['x'] - $this->config[$k][$i+1]['x'] == 0) $this->lines[$k][$i]['k'] = 0; else $this->lines[$k][$i]['k'] = ($this->config[$k][$i]['y'] - $this->config[$k][$i+1]['y'])/($this->config[$k][$i]['x'] - $this->config[$k][$i+1]['x']); // y=kx+b : b $this->lines[$k][$i]['b'] = $this->config[$k][$i+1]['y'] - $this->lines[$k][$i]['k'] * $this->config[$k][$i+1]['x']; $this->lines[$k][$i]['lx'] = min($this->config[$k][$i]['x'], $this->config[$k][$i+1]['x']); $this->lines[$k][$i]['rx'] = max($this->config[$k][$i]['x'], $this->config[$k][$i+1]['x']); } $pointNum-=1; if($this->config[$k][$pointNum]['x'] - $this->config[$k][0]['x'] == 0) $this->lines[$k][$pointNum]['k'] = 0; else $this->lines[$k][$pointNum]['k'] = ($this->config[$k][$pointNum]['y'] - $this->config[$k][0]['y'])/($this->config[$k][$pointNum]['x'] - $this->config[$k][0]['x']); // y=kx+b : b $this->lines[$k][$pointNum]['b'] = $this->config[$k][0]['y'] - $this->lines[$k][$pointNum]['k'] * $this->config[$k][0]['x']; $this->lines[$k][$pointNum]['lx'] = min($this->config[$k][$pointNum]['x'], $this->config[$k][0]['x']); $this->lines[$k][$pointNum]['rx'] = max($this->config[$k][$pointNum]['x'], $this->config[$k][0]['x']); } } /* 获取一组坐标中,x坐标最小值 */ private function getMinXInEachConfig($index){ $minX = 200; foreach ($this->config[$index] as $k => $v) { if($v['x'] < $minX){ $minX = $v['x']; } } return $minX; } /* 获取一组坐标中,y坐标最小值 */ private function getMinYInEachConfig($index){ $minY = 200; foreach ($this->config[$index] as $k => $v) { if($v['y'] < $minY){ $minY = $v['y']; } } return $minY; } /* 获取一组坐标中,x坐标最大值 */ public function getMaxXInEachConfig($index){ $maxX = 0; foreach ($this->config[$index] as $k => $v) { if($v['x'] > $maxX){ $maxX = $v['x']; } } return $maxX; } /* 获取一组坐标中,y坐标最大值 */ public function getMaxYInEachConfig($index){ $maxY = 0; foreach ($this->config[$index] as $k => $v) { if($v['y'] > $maxY){ $maxY = $v['y']; } } return $maxY; } /* 获取 y=y0 与特定区域的全部边的交点,并去除和顶点反复的,再将交点分为左和右两部分 */ private function getCrossPointInCertainConfig($index){ $crossPoint = null; foreach ($this->lines[$index] as $k => $v) { if($v['k'] == 0) return true; $x0 = ($this->_y - $v['b']) / $v['k']; // 交点x坐标 if($x0 == $this->_x) return true; // 点在边上 if($x0 > $v['lx'] && $x0 < $v['rx']){ if($x0 < $this->_x) $crossPoint['left'][] = $x0; if($x0 > $this->_x) $crossPoint['right'][] = $x0; } } return $crossPoint; } /* 检測一个点,是否在区域内 返回结果: return === false : 点不在区域内 return 0, 1, 2, 3 ... 点所在的区域编号(配置文件里的区域编号。) */ public function checkPoint($x, $y){ $this->_x = $x; $this->_y = $y; $contain = null; foreach ($this->rectangles as $k => $v) { if($x > $v['maxX'] || $x < $v['minX'] || $y > $v['maxY'] || $y < $v['minY']){ continue; }else{ $contain = $k; break; } } if($contain === null) return false; $crossPoint = $this->getCrossPointInCertainConfig($contain); if($crossPoint === true) return $contain; if(count($crossPoint['left'])%2 == 1 && count($crossPoint['right'])%2 == 1) return $contain; return false; } } $area = new Area($area); var_dump($area->checkPoint(116.531748,39.944229)); ?>



  • 相关阅读:
    Codeforces Round #649 (Div. 2) D. Ehab's Last Corollary
    Educational Codeforces Round 89 (Rated for Div. 2) E. Two Arrays
    Educational Codeforces Round 89 (Rated for Div. 2) D. Two Divisors
    Codeforces Round #647 (Div. 2) E. Johnny and Grandmaster
    Codeforces Round #647 (Div. 2) F. Johnny and Megan's Necklace
    Codeforces Round #648 (Div. 2) G. Secure Password
    Codeforces Round #646 (Div. 2) F. Rotating Substrings
    C++STL常见用法
    各类学习慕课(不定期更新
    高阶等差数列
  • 原文地址:https://www.cnblogs.com/jhcelue/p/6919892.html
Copyright © 2011-2022 走看看