任意多边形坐标范围判断(重写自百度地图js文件)

<?php
/**
 *
 * @author Administrator
 *
 */
class MapTools {
	public static function model() {
		return new MapTools ();
	}
	
	/**
	 * 判断点是否在矩形内
	 *
	 * @param
	 *        	{Point} point 点对象
	 * @param
	 *        	{Bounds} bounds 矩形边界对象
	 * @return s {Boolean} 点在矩形内返回true,否则返回false
	 */
	function isPointInRect($point, $bounds) {
		// 西南脚点
		$sw = $bounds ['sw'];
		// 东北脚点
		$ne = $bounds ['ne'];
		return ($point ['lng'] >= $sw ['lng'] && $point ['lat'] >= $sw ['lat'] && $point ['lng'] <= $ne ['lng'] && $point ['lat'] <= $ne ['lat']);
	}
	
	/**
	 * 返回一个多边形的最小外矩形(西南点和东北点的坐标)
	 *
	 * @param array $polygon        	
	 */
	function getBoundsByPolygon($polygon) {
		$least_lng = $polygon [0] ['lng'];
		$least_lat = $polygon [0] ['lat'];
		$largest_lng = $polygon [0] ['lng'];
		$largest_lat = $polygon [0] ['lat'];
		foreach ( $polygon as $point ) {
			if ($point ['lng'] < $least_lng) {
				$least_lng = $point ['lng'];
			}
			if ($point ['lat'] < $least_lat) {
				$least_lat = $point ['lat'];
			}
			if ($point ['lng'] > $largest_lng) {
				$largest_lng = $point ['lng'];
			}
			if ($point ['lat'] > $largest_lat) {
				$largest_lat = $point ['lat'];
			}
		}
		return array (
				'sw' => array (
						'lng' => $least_lng,
						'lat' => $least_lat 
				),
				'ne' => array (
						'lng' => $largest_lng,
						'lat' => $largest_lat 
				) 
		);
	}
	
	/**
	 * 判断点是否在多边形内
	 *
	 * @param unknown_type $point        	
	 * @param unknown_type $polygon        	
	 * @return boolean
	 */
	function isPointInPolygon($point, $polygon) {
		if (empty ( $polygon )) {
			return false;
		}
		// 首先判断点是否在多边形的外包矩形内,如果在,则进一步判断,否则返回false
		// 可以通过绘制矩形时,补充多边形的中心进行计算处理.
		$polygonBounds = $this->getBoundsByPolygon ( $polygon );
		if (! $this->isPointInRect ( $point, $polygonBounds )) {
			return false;
		}
		$pts = $polygon;
		// 获取多边形点
		
		// 下述代码来源:http://paulbourke.net/geometry/insidepoly/,进行了部分修改
		// 基本思想是利用射线法,计算射线与多边形各边的交点,如果是偶数,则点在多边形外,否则
		// 在多边形内。还会考虑一些特殊情况,如点在多边形顶点上,点在多边形边上等特殊情况。
		
		$N = count ( $pts );
		$boundOrVertex = true;
		// 如果点位于多边形的顶点或边上,也算做点在多边形内,直接返回true
		$intersectCount = 0;
		// cross points count of x
		$precision = 2e-10;
		// 浮点类型计算时候与0比较时候的容差
		$p1 = $p2 = null;
		// neighbour bound vertices
		$p = $point;
		// 测试点
		
		$p1 = $pts [0];
		// left vertex
		for($i = 1; $i <= $N; ++ $i) {
			// check all rays
			if ($p ['lng'] == $p1 ['lng'] && $p ['lat'] == $p1 ['lat']) {
				return $boundOrVertex;
				// p is an vertex
			}
			$p2 = $pts [$i % $N];
			// right vertex
			if ($p ['lat'] < min ( $p1 ['lat'], $p2 ['lat'] ) || $p ['lat'] > max ( $p1 ['lat'], $p2 ['lat'] )) {
				// ray
				// is
				// outside
				// of
				// our
				// interests
				$p1 = $p2;
				continue;
				// next ray left point
			}
			
			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)
				if ($p ['lng'] <= max ( $p1 ['lng'], $p2 ['lng'] )) {
					// x is before of
					// ray
					if ($p1 ['lat'] == $p2 ['lat'] && $p ['lng'] >= min ( $p1 ['lng'], $p2 ['lng'] )) {
						// overlies
						// on
						// a
						// horizontal
						// ray
						return $boundOrVertex;
					}
					
					if ($p1 ['lng'] == $p2 ['lng']) {
						// ray is vertical
						if ($p1 ['lng'] == $p ['lng']) {
							// overlies on a vertical ray
							return $boundOrVertex;
						} else {
							// before ray
							++ $intersectCount;
						}
					} else {
						// cross point on the left side
						$xinters = ($p ['lat'] - $p1 ['lat']) * ($p2 ['lng'] - $p1 ['lng']) / ($p2 ['lat'] - $p1 ['lat']) + $p1 ['lng'];
						// cross
						// point
						// of
						// lng
						if (abs ( $p ['lng'] - $xinters ) < $precision) {
							// overlies on
							// a ray
							return $boundOrVertex;
						}
						
						if ($p ['lng'] < $xinters) {
							// before ray
							++ $intersectCount;
						}
					}
				}
			} else { // special case when ray is crossing through the vertex
				if ($p ['lat'] == $p2 ['lat'] && $p ['lng'] <= $p2 ['lng']) {
					// p crossing
					// over
					// p2
					$p3 = $pts [($i + 1) % $N];
					// next vertex
					if ($p ['lat'] >= min ( $p1 ['lat'], $p3 ['lat'] ) && $p ['lat'] <= max ( $p1 ['lat'], $p3 ['lat'] )) {
						// p.lat
						// lies
						// between
						// p1.lat
						// &
						// p3.lat
						++ $intersectCount;
					} else {
						$intersectCount += 2;
					}
				}
			}
			$p1 = $p2;
			// next ray left point
		}
		
		if ($intersectCount % 2 == 0) {
			// 偶数在多边形外
			return false;
		} else {
			// 奇数在多边形内
			return true;
		}
	}
	/**
	 * 签名校验
	 *
	 * @param unknown $ak        	
	 * @param unknown $sk        	
	 * @param unknown $url        	
	 * @param unknown $querystring_arrays        	
	 * @param string $method        	
	 * @return string
	 */
	function caculateAKSN($ak, $sk, $url, $querystring_arrays, $method = 'GET') {
		if ($method === 'POST') {
			ksort ( $querystring_arrays );
		}
		$querystring = http_build_query ( $querystring_arrays );
		return md5 ( urlencode ( $url . '?' . $querystring . $sk ) );
	}
	/**
	 * 通过地址返回坐标
	 *
	 * @param string $address_name        	
	 * @return mixed|boolean
	 */
	function getLocationByAddress($address_name) {
		// API控制台申请得到的ak(此处ak值仅供验证参考使用)
		$ak = 'xxxxxxxxxxxxxx';
		// 应用类型为for server, 请求校验方式为sn校验方式时,系统会自动生成sk,可以在应用配置-设置中选择Security
		// Key显示进行查看(此处sk值仅供验证参考使用)
		$sk = 'xxxxxxxxxxxxxxxxx';
		// 以Geocoding服务为例,地理编码的请求url,参数待填
		$url = "http://api.map.baidu.com/geocoder/v2/?address=%s&output=%s&ak=%s&sn=%s";
		// get请求uri前缀
		$uri = '/place/v2/search';
		// 地理编码的请求output参数
		$output = 'json';
		$pois = '0';
		$query = $address_name;
		$region = '全国';
		$scope = 1;
		$querystring_arrays = array (
				'query' => $query,
				'output' => $output,
				'ak' => $ak,
				'scope' => $scope,
				'region' => $region 
		);
		$url = "http://api.map.baidu.com/place/v2/search?query=%s&output=%s&ak=%s&sn=%s&scope=%s&region=%s";
		// 调用sn计算函数,默认get请求
		$sn = $this->caculateAKSN ( $ak, $sk, $uri, $querystring_arrays );
		// 请求参数中有中文、特殊字符等需要进行urlencode,确保请求串与sn对应
		$target = sprintf ( $url, urlencode ( $query ), $output, $ak, $sn, $scope, urlencode ( $region ) );
		// 输出计算得到的sn
		// echo "sn: $sn \n";
		// 输出完整请求的url(仅供参考验证,故不能正常访问服务)
		// echo "url: $target \n";
		$content = file_get_contents ( $target );
		$content = json_decode ( $content, true );
		if ($content ['status'] == 0 && isset ( $content ['results'] ) && ! empty ( $content ['results'] ) && isset ( $content ['results'] [0] ['location'] ) && ! empty ( $content ['results'] [0] ['location'] )) {
			// var_export ( $content );
			return $content ['results'] [0] ['location'];
		}
		return false;
	}
	public function getAddressByLocation($longitude, $latitude) {
		$url = "http://api.map.baidu.com/geocoder/v2/?ak=thT0201pFtgt3VApRT2mhlA6mmpQUnWQ&location={$latitude},{$longitude}&output=json";
		$ch = curl_init ( $url );
		curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, true );
		// 获取数据返回
		curl_setopt ( $ch, CURLOPT_BINARYTRANSFER, true );
		// 在启用
		// CURLOPT_RETURNTRANSFER
		// 时候将获取数据返回
		$output = curl_exec ( $ch );
		$arr = json_decode ( $output, true );
		if (! $arr || $arr ['status'] || ! isset ( $arr ['result'] ))
			return false;
		return $arr ['result'] ['formatted_address'];
	}
}

3

发表评论

电子邮件地址不会被公开。 必填项已用*标注