【问题标题】:Filter though object array based on distance between GPS locations(javascript)根据 GPS 位置之间的距离过滤对象数组(javascript)
【发布时间】:2019-03-28 14:54:29
【问题描述】:

我有一组位置对象,其中 GPS 位置与这些对象相关联。我想根据用户当前位置过滤数组并比较用户位置和位置对象之间的距离。

我有一个当前功能可以完成此操作,但我知道这效率不高。我宁愿过滤数组而不是创建一个临时变量并将临时变量分配给数组。

//sample data
public getLocation = [
    {
			"ID": "1",
			"Name": "Test Location 1",
			"Lat": "32.16347467",
			"Lon": "-103.67178545"
		}, {
			"ID": "2",
			"Name": "Test Location 2",
			"Lat": "32.16347451",
			"Lon": "-103.67178544"
		}, {
			"ID": "3",
			"Name": "Test Location 3",
			"Lat": "32.13559815",
			"Lon": "-103.67544362"
		}, {
			"ID": "4",
			"Name": "Test Location 4",
			"Lat": "32.40144407",
			"Lon": "-103.13168477"
		}, {
			"ID": "5",
			"Name": "Test Location ",
			"Lat": "32.14557039",
			"Lon": "-103.67011361",
		}
  ]

grabLocation(){
     this.platform.ready().then(() => {
     this.geolocation.getCurrentPosition().then((resp) => {
         this.userLocation = [parseFloat(resp.coords.latitude.toFixed(4)),parseFloat(resp.coords.longitude.toFixed(4))];
         this.userLocation = [resp.coords.latitude,resp.coords.longitude];
         var getLocation
         getLocation = this.asyncLocations.grabUserLoc(this.userLocation[0],this.userLocation[1]);
         console.log(getLocation);
       }).catch((error) => {
         this.presentToast(error);
       });
     });
   }
//asyncLocations.ts
grabUserLoc(lat,lon){
    var tempLocation= [];

    for(let i=0;i<this.getLocation.length;i++){
      if((this.getLocation[i]['Lat']!="") && this.getLocation[i]['Lon']!=""){
     
        let R = 6371;// km
        let RinM = (R*0.621371);
        let Lat1 = (parseFloat(lat.toFixed(5)));
        let Lon1 = (parseFloat(lon.toFixed(5)));
        let Lat2 = (parseFloat(this.getLocation[i]['Lat']));
        let Lon2 = (parseFloat(this.getLocation[i]['Lon']));
        let dLat = this.toRad(Lat2-Lat1);
        let dLon = this.toRad(Lon2-Lon1);
        let RLat1 = this.toRad(Lat1);
        let RLat2 = this.toRad(Lat2);
        let a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(RLat1) * Math.cos(RLat2);
        let c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
        //let d = R * c;
        let e = RinM * c;
        if(e < 5){
          tempLocation.push(this.getLocation[i]);
         }
       }
    }
    this.getLocation = tempLocation;
    return this.getLocation;
}

// Converts numeric degrees to radians
toRad(Value)
{
  return Value * Math.PI / 180;
}

我目前的位置检查距离为 5 英里。

任何帮助将不胜感激。

【问题讨论】:

  • 由于您没有指出代码不起作用,这听起来更像是您需要code review
  • 我投票结束这个问题,因为它要求代码审查
  • 谢谢!我会在那里尝试。我假设该网站可以帮助解决我的问题
  • 是的,这个站点通常是针对不工作的代码 - 另一个站点是针对工作但需要改进的代码。不过,也请参阅下面我的答案中的链接。
  • 好的,我会注意的。谢谢!我会的!

标签: javascript arrays geolocation ionic3


【解决方案1】:
  1. 不要将您的 lat/long 值存储为字符串 - 尽早转换为浮点数

  2. 将您的 Haversine 计算分离到它自己的函数中

  3. 考虑使用Haversine 的余弦变体,并省略最后的acos 步骤

  4. 在循环外重构常量表达式

  5. 考虑预先计算纬度和经度的弧度当量

另见Quicker way to calculate geographic distance between two points

【讨论】:

  • 谢谢你。只是好奇 1,在地理位置上我已经得到了一个数字。我删除了 parseFloat(),我相信这可以解决那里的问题。
  • 还有一个关于 3 的问题。我对你给我的链接有点困惑。我只是想确保我分配了正确的变量。
【解决方案2】:

我建议使用 WebWorker,这样主 UI 线程就不会被长时间阻塞,并且可以中断给定的受事件启发的搜索/过滤器,或者补充更新的数据:-

importScripts("Tier3Toolbox.js");

var currVintage = 0;
var inBounds = false;
var facFilter = [];
var imageProlog = "<div style='height:5em; width:5em; display:inline-block;vertical-align:middle;'>" +
                  "<img style='height:100%; width: 100%; max-height:100%; max-width:100%' src='";
var imageEpilog = "' ></div>";
var facilityTable, lineBreak;

self.addEventListener('message', function(e) 
{
  var data = e.data;
  switch (data.cmd) {
    case 'init':
      initThread(data.load);
      break;
    case 'initFilter':
      for (var i=0; i<data.filterTable.length; i++) {
        facFilter[data.filterTable[i].locTypeId] = {'icon':data.filterTable[i].icon};
      }
      break;
    case 'filter':
      facFilter = [];
      for (var i=0; i<data.filterTable.length; i++) {
        if (data.filterTable[i].facSelected)
          facFilter[data.filterTable[i].locTypeId] = {'icon':data.filterTable[i].icon};
      }
      break;
    case 'search':
      var searchVintage = ++currVintage;
      var tableSearch = new searcher(searchVintage, data);
      break;
    case 'reset':
      reset();
      self.postMessage({'reset': true});
      break;
    case 'stop':
      self.postMessage({'success' : true});
      self.close(); 
      break;
    default:
      self.postMessage({'success' : false, 'msg' : data.msg});
  };
}, false);

function initThread(msg) 
{
    facilityTable = JSON.parse(msg);
    reset();

    self.postMessage({'success' : true, 
                      'cnt'     : facilityTable.length
                    });     
}   

function reset() 
{
    for (var i=0; i<facilityTable.length; i++) {
        facilityTable[i].visible=false
    }
    currVintage = 0;
}   

function searcher(searchVintage, msg)
{
    var myVintage = searchVintage;
    var facIndex  = -1;
    var msg       = msg;

    var checkLoop = function()
    {
        if (myVintage != currVintage)
            return;

        if (++facIndex == facilityTable.length)
            return;

        inBounds = geoFencer.call(this, msg);

        if (inBounds) {
            var facMatch = 0;
            var bubbleHTML = "";
            for (var i=0; i<facilityTable[facIndex].facilities.length; i++){
                var currFac = facilityTable[facIndex].facilities[i];
                if (facFilter[currFac.locTypeId] != undefined) {
                    if (facMatch != 0) {
                        lineBreak = (facMatch / 3);
                        if (lineBreak == lineBreak.toFixed(0)) {
                            bubbleHTML += "<br />";
                        }
                    }
                    facMatch++;
                    bubbleHTML += imageProlog + facFilter[currFac.locTypeId].icon + imageEpilog;

                }
            }
            if (facMatch == 0) {
                inBounds = false;
            }
        }

        if (inBounds != facilityTable[facIndex].visible) {
            self.postMessage({'match'       : inBounds,
                              'facIndex'    : facIndex,
                              'scopeVintage': msg.scopeVintage,
                              'bubbleHTML'  : bubbleHTML,
                              'success'     : true
                            }); 
            facilityTable[facIndex].visible = inBounds;
        }

        setTimeout(checkLoop,0);
    }

    var circleCheck = function(msg) 
    {
        var diff = Tier3Toolbox.calculateDistance(
                        msg.centerLat,
                        msg.centerLng,
                        facilityTable[facIndex].searchLat,
                        facilityTable[facIndex].searchLng);

        if (msg.radius > diff)
            return true;        

        return false;
    }

    var rectangleCheck = function(msg) 
    {
        if (facilityTable[facIndex].searchLat > msg.SWLat &&
            facilityTable[facIndex].searchLat < msg.NELat &&
            facilityTable[facIndex].searchLng > msg.SWLng &&
            facilityTable[facIndex].searchLng < msg.NELng)
            return true;        

        return false;
    }

    var GEOFENCER = [circleCheck,rectangleCheck];
    var geoFencer = GEOFENCER[msg.checker];

    setTimeout(checkLoop,0);
    return this;
}

【讨论】:

    猜你喜欢
    • 2016-11-24
    • 1970-01-01
    • 2015-02-17
    • 1970-01-01
    • 1970-01-01
    • 2021-06-09
    • 2016-10-28
    • 2018-06-17
    • 2019-09-11
    相关资源
    最近更新 更多