<?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®ion=%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']; } }