GeoUtils, * 基于Baidu Map API 1.2。 * * @author Baidu Map Api">
 | 注册
请输入搜索内容

热门搜索

Java Linux MySQL PHP JavaScript Hibernate jQuery Nginx
jopen
10年前发布

百度地图API 判断点是否在圆形内

 /**     * @fileoverview GeoUtils类提供若干几何算法,用来帮助用户判断点与矩形、     * 圆形、多边形线、多边形面的关系,并提供计算折线长度和多边形的面积的公式。      * 主入口类是<a href="symbols/BMapLib.GeoUtils.html">GeoUtils</a>,     * 基于Baidu Map API 1.2。     *     * @author Baidu Map Api Group      * @version 1.2     */     /**     * @namespace BMap的所有library类均放在BMapLib命名空间下    */   var BMapLib = window.BMapLib = BMapLib || {};   (function() {          /**        * 地球半径        */       var EARTHRADIUS = 6370996.81;          /**         * @exports GeoUtils as BMapLib.GeoUtils         */       var GeoUtils =       /**        * GeoUtils类,静态类,勿需实例化即可使用        * @class GeoUtils类的<b>入口</b>。        * 该类提供的都是静态方法,勿需实例化即可使用。             */       BMapLib.GeoUtils = function(){         }         /**        * 判断点是否在矩形内        * @param {Point} point 点对象        * @param {Bounds} bounds 矩形边界对象        * @returns {Boolean} 点在矩形内返回true,否则返回false        */       GeoUtils.isPointInRect = function(point, bounds){           //检查类型是否正确           if (!(point instanceof BMap.Point) ||                !(bounds instanceof BMap.Bounds)) {               return false;           }           var sw = bounds.getSouthWest(); //西南脚点           var ne = bounds.getNorthEast(); //东北脚点           return (point.lng >= sw.lng && point.lng <= ne.lng && point.lat >= sw.lat && point.lat <= ne.lat);       }         /**        * 判断点是否在圆形内        * @param {Point} point 点对象        * @param {Circle} circle 圆形对象        * @returns {Boolean} 点在圆形内返回true,否则返回false        */       GeoUtils.isPointInCircle = function(point, circle){           //检查类型是否正确           if (!(point instanceof BMap.Point) ||                !(circle instanceof BMap.Circle)) {               return false;           }             //point与圆心距离小于圆形半径,则点在圆内,否则在圆外           var c = circle.getCenter();           var r = circle.getRadius();             var dis = GeoUtils.getDistance(point, c);           if(dis <= r){               return true;           } else {               return false;           }       }         /**        * 判断点是否在折线上        * @param {Point} point 点对象        * @param {Polyline} polyline 折线对象        * @returns {Boolean} 点在折线上返回true,否则返回false        */       GeoUtils.isPointOnPolyline = function(point, polyline){           //检查类型           if(!(point instanceof BMap.Point) ||               !(polyline instanceof BMap.Polyline)){               return false;           }             //首先判断点是否在线的外包矩形内,如果在,则进一步判断,否则返回false           var lineBounds = polyline.getBounds();           if(!this.isPointInRect(point, lineBounds)){               return false;           }             //判断点是否在线段上,设点为Q,线段为P1P2 ,           //判断点Q在该线段上的依据是:( Q - P1 ) × ( P2 - P1 ) = 0,且 Q 在以 P1,P2为对角顶点的矩形内           var pts = polyline.getPath();           for(var i = 0; i < pts.length - 1; i++){              var curPt = pts[i];              var nextPt = pts[i + 1];              //首先判断point是否在curPt和nextPt之间,即:此判断该点是否在该线段的外包矩形内              if (point.lng >= Math.min(curPt.lng, nextPt.lng) && point.lng <= Math.max(curPt.lng, nextPt.lng) &&                  point.lat >= Math.min(curPt.lat, nextPt.lat) && point.lat <= Math.max(curPt.lat, nextPt.lat)){                  //判断点是否在直线上公式                  var precision = (curPt.lng - point.lng) * (nextPt.lat - point.lat) -                       (nextPt.lng - point.lng) * (curPt.lat - point.lat);                                  if(precision < 2e-10 && precision > -2e-10){//实质判断是否接近0                      return true;                  }                              }          }            return false;      }        /**       * 判断点是否多边形内       * @param {Point} point 点对象       * @param {Polyline} polygon 多边形对象       * @returns {Boolean} 点在多边形内返回true,否则返回false       */      GeoUtils.isPointInPolygon = function(point, polygon){          //检查类型          if(!(point instanceof BMap.Point) ||              !(polygon instanceof BMap.Polygon)){              return false;          }            //首先判断点是否在多边形的外包矩形内,如果在,则进一步判断,否则返回false          var polygonBounds = polygon.getBounds();          if(!this.isPointInRect(point, polygonBounds)){              return false;          }            var pts = polygon.getPath();//获取多边形点            //下述代码来源:http://paulbourke.net/geometry/insidepoly/,进行了部分修改          //基本思想是利用射线法,计算射线与多边形各边的交点,如果是偶数,则点在多边形外,否则          //在多边形内。还会考虑一些特殊情况,如点在多边形顶点上,点在多边形边上等特殊情况。            var N = pts.length;          var boundOrVertex = true; //如果点位于多边形的顶点或边上,也算做点在多边形内,直接返回true          var intersectCount = 0;//cross points count of x           var precision = 2e-10; //浮点类型计算时候与0比较时候的容差          var p1, p2;//neighbour bound vertices          var p = point; //测试点            p1 = pts[0];//left vertex                  for(var i = 1; i <= N; ++i){//check all rays                          if(p.equals(p1)){                  return boundOrVertex;//p is an vertex              }                p2 = pts[i % N];//right vertex                          if(p.lat < Math.min(p1.lat, p2.lat) || p.lat > Math.max(p1.lat, p2.lat)){//ray is outside of our interests                                  p1 = p2;                   continue;//next ray left point              }                if(p.lat > Math.min(p1.lat, p2.lat) && p.lat < Math.max(p1.lat, p2.lat)){//ray is crossing over by the algorithm (common part of)                  if(p.lng <= Math.max(p1.lng, p2.lng)){//x is before of ray                                          if(p1.lat == p2.lat && p.lng >= Math.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                                                  var xinters = (p.lat - p1.lat) * (p2.lng - p1.lng) / (p2.lat - p1.lat) + p1.lng;//cross point of lng                                                  if(Math.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                                          var p3 = pts[(i+1) % N]; //next vertex                                          if(p.lat >= Math.min(p1.lat, p3.lat) && p.lat <= Math.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 {degree} Number 度            * @returns {Number} 弧度       */      GeoUtils.degreeToRad =  function(degree){          return Math.PI * degree/180;          }        /**       * 将弧度转化为度       * @param {radian} Number 弧度            * @returns {Number} 度       */      GeoUtils.radToDegree = function(rad){          return (180 * rad) / Math.PI;             }        /**       * 将v值限定在a,b之间,纬度使用       */      function _getRange(v, a, b){          if(a != null){            v = Math.max(v, a);          }          if(b != null){            v = Math.min(v, b);          }          return v;      }        /**       * 将v值限定在a,b之间,经度使用       */      function _getLoop(v, a, b){          while( v > b){            v -= b - a          }          while(v < a){            v += b - a          }          return v;      }        /**       * 计算两点之间的距离,两点坐标必须为经纬度       * @param {point1} Point 点对象       * @param {point2} Point 点对象       * @returns {Number} 两点之间距离,单位为米       */      GeoUtils.getDistance = function(point1, point2){          //判断类型          if(!(point1 instanceof BMap.Point) ||              !(point2 instanceof BMap.Point)){              return 0;          }            point1.lng = _getLoop(point1.lng, -180, 180);          point1.lat = _getRange(point1.lat, -74, 74);          point2.lng = _getLoop(point2.lng, -180, 180);          point2.lat = _getRange(point2.lat, -74, 74);            var x1, x2, y1, y2;          x1 = GeoUtils.degreeToRad(point1.lng);          y1 = GeoUtils.degreeToRad(point1.lat);          x2 = GeoUtils.degreeToRad(point2.lng);          y2 = GeoUtils.degreeToRad(point2.lat);            return EARTHRADIUS * Math.acos((Math.sin(y1) * Math.sin(y2) + Math.cos(y1) * Math.cos(y2) * Math.cos(x2 - x1)));          }        /**       * 计算折线或者点数组的长度       * @param {Polyline|Array<Point>} polyline 折线对象或者点数组       * @returns {Number} 折线或点数组对应的长度       */      GeoUtils.getPolylineDistance = function(polyline){          //检查类型          if(polyline instanceof BMap.Polyline ||               polyline instanceof Array){              //将polyline统一为数组              var pts;              if(polyline instanceof BMap.Polyline){                  pts = polyline.getPath();              } else {                  pts = polyline;              }                if(pts.length < 2){//小于2个点,返回0                  return 0;              }                //遍历所有线段将其相加,计算整条线段的长度              var totalDis = 0;              for(var i =0; i < pts.length - 1; i++){                  var curPt = pts[i];                  var nextPt = pts[i + 1]                  var dis = GeoUtils.getDistance(curPt, nextPt);                  totalDis += dis;              }                return totalDis;            } else {              return 0;          }      }        /**       * 计算多边形面或点数组构建图形的面积,注意:坐标类型只能是经纬度,且不适合计算自相交多边形的面积       * @param {Polygon|Array<Point>} polygon 多边形面对象或者点数组       * @returns {Number} 多边形面或点数组构成图形的面积       */      GeoUtils.getPolygonArea = function(polygon){          //检查类型          if(!(polygon instanceof BMap.Polygon) &&              !(polygon instanceof Array)){              return 0;          }          var pts;          if(polygon instanceof BMap.Polygon){              pts = polygon.getPath();          }else{              pts = polygon;              }            if(pts.length < 3){//小于3个顶点,不能构建面              return 0;          }            var totalArea = 0;//初始化总面积          var LowX = 0.0;          var LowY = 0.0;          var MiddleX = 0.0;          var MiddleY = 0.0;          var HighX = 0.0;          var HighY = 0.0;          var AM = 0.0;          var BM = 0.0;          var CM = 0.0;          var AL = 0.0;          var BL = 0.0;          var CL = 0.0;          var AH = 0.0;          var BH = 0.0;          var CH = 0.0;          var CoefficientL = 0.0;          var CoefficientH = 0.0;          var ALtangent = 0.0;          var BLtangent = 0.0;          var CLtangent = 0.0;          var AHtangent = 0.0;          var BHtangent = 0.0;          var CHtangent = 0.0;          var ANormalLine = 0.0;          var BNormalLine = 0.0;          var CNormalLine = 0.0;          var OrientationValue = 0.0;          var AngleCos = 0.0;          var Sum1 = 0.0;          var Sum2 = 0.0;          var Count2 = 0;          var Count1 = 0;          var Sum = 0.0;          var Radius = EARTHRADIUS; //6378137.0,WGS84椭球半径           var Count = pts.length;                  for (var i = 0; i < Count; i++) {              if (i == 0) {                  LowX = pts[Count - 1].lng * Math.PI / 180;                  LowY = pts[Count - 1].lat * Math.PI / 180;                  MiddleX = pts[0].lng * Math.PI / 180;                  MiddleY = pts[0].lat * Math.PI / 180;                  HighX = pts[1].lng * Math.PI / 180;                  HighY = pts[1].lat * Math.PI / 180;              }              else if (i == Count - 1) {                  LowX = pts[Count - 2].lng * Math.PI / 180;                  LowY = pts[Count - 2].lat * Math.PI / 180;                  MiddleX = pts[Count - 1].lng * Math.PI / 180;                  MiddleY = pts[Count - 1].lat * Math.PI / 180;                  HighX = pts[0].lng * Math.PI / 180;                  HighY = pts[0].lat * Math.PI / 180;              }              else {                  LowX = pts[i - 1].lng * Math.PI / 180;                  LowY = pts[i - 1].lat * Math.PI / 180;                  MiddleX = pts[i].lng * Math.PI / 180;                  MiddleY = pts[i].lat * Math.PI / 180;                  HighX = pts[i + 1].lng * Math.PI / 180;                  HighY = pts[i + 1].lat * Math.PI / 180;              }              AM = Math.cos(MiddleY) * Math.cos(MiddleX);              BM = Math.cos(MiddleY) * Math.sin(MiddleX);              CM = Math.sin(MiddleY);              AL = Math.cos(LowY) * Math.cos(LowX);              BL = Math.cos(LowY) * Math.sin(LowX);              CL = Math.sin(LowY);              AH = Math.cos(HighY) * Math.cos(HighX);              BH = Math.cos(HighY) * Math.sin(HighX);              CH = Math.sin(HighY);              CoefficientL = (AM * AM + BM * BM + CM * CM) / (AM * AL + BM * BL + CM * CL);              CoefficientH = (AM * AM + BM * BM + CM * CM) / (AM * AH + BM * BH + CM * CH);              ALtangent = CoefficientL * AL - AM;              BLtangent = CoefficientL * BL - BM;              CLtangent = CoefficientL * CL - CM;              AHtangent = CoefficientH * AH - AM;              BHtangent = CoefficientH * BH - BM;              CHtangent = CoefficientH * CH - CM;              AngleCos = (AHtangent * ALtangent + BHtangent * BLtangent + CHtangent * CLtangent) / (Math.sqrt(AHtangent * AHtangent + BHtangent * BHtangent + CHtangent * CHtangent) * Math.sqrt(ALtangent * ALtangent + BLtangent * BLtangent + CLtangent * CLtangent));              AngleCos = Math.acos(AngleCos);                          ANormalLine = BHtangent * CLtangent - CHtangent * BLtangent;              BNormalLine = 0 - (AHtangent * CLtangent - CHtangent * ALtangent);              CNormalLine = AHtangent * BLtangent - BHtangent * ALtangent;              if (AM != 0)                  OrientationValue = ANormalLine / AM;              else if (BM != 0)                  OrientationValue = BNormalLine / BM;              else                  OrientationValue = CNormalLine / CM;              if (OrientationValue > 0) {                  Sum1 += AngleCos;                  Count1++;              }              else {                  Sum2 += AngleCos;                  Count2++;              }          }                  var tempSum1, tempSum2;          tempSum1 = Sum1 + (2 * Math.PI * Count2 - Sum2);          tempSum2 = (2 * Math.PI * Count1 - Sum1) + Sum2;          if (Sum1 > Sum2) {              if ((tempSum1 - (Count - 2) * Math.PI) < 1)                  Sum = tempSum1;              else                  Sum = tempSum2;          }          else {              if ((tempSum2 - (Count - 2) * Math.PI) < 1)                  Sum = tempSum2;              else                  Sum = tempSum1;          }          totalArea = (Sum - (Count - 2) * Math.PI) * Radius * Radius;            return totalArea; //返回总面积      }    })();//闭包结束

使用方法:
var point = new BMap.Point(x,y)  var circle = new BMap.Circle(mPoint,1000,{fillColor:"blue", strokeWeight: 1 ,fillOpacity: 0.3, strokeOpacity: 0.3});    if(BMapLib.GeoUtils.isPointInCircle(point,circle)){      alert("该point在circle内");  }

链接: GeoUtils.js
作者: itmyhome