zoukankan      html  css  js  c++  java
  • 百度地图js判断点是否在圆形区域内

    /**
    * Created by LEGION on 2018/10/11.
    */
    /**
    * @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; //返回总面积
    }

    })();//闭包结束
    //=======================================================
    <!DOCTYPE html>
    <html>
    <script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=Ys4Yh5eKiRbTuTtavay0gVithqviqBf7"></script>
    <script type="text/javascript" src="a.js"></script>
    <head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <script>
    //创建一个圆(坐标自己填)
    var circle = new BMap.Circle(new BMap.Point(112.595384,26.904631),1000,{fillColor:"blue", strokeWeight: 1 ,fillOpacity: 0.3, strokeOpacity: 0.3});
    //创建一个点(坐标自己填)
    var point = new BMap.Point(112.695384,26.904631); // 创建点坐标
    //判断点是否在圆形区域内
    if(BMapLib.GeoUtils.isPointInCircle(point,circle)){
    alert("该point 在 circle内");
    }else
    {
    alert("该point 不在 circle内");
    }
    </script>
    </head>
    <body>

    </body>
    </html>
  • 相关阅读:
    JMeter学习(二十三)关联
    最常用的DOS命令
    不同类型的操作系统
    分级存储管理的四大优点
    软件工程中数据库设计
    PPP(点对点协议(Point to Point Protocol)
    关键路径法
    什么是鲁棒性测试
    何为蠕虫病毒
    临界区
  • 原文地址:https://www.cnblogs.com/zhangzhiqin/p/9773980.html
Copyright © 2011-2022 走看看