Reputation: 3022
I have an array of location objects with GPS locations tied to the objects. I am wanting to filter through the array based on the users current location and compare the distance between the user location and location objects.
I have a current function that accomplishes this, but I know this is not efficient. I would prefer to filter the array than to create a temp variable and assign the temp variable to the array every time.
//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;
}
I currently have the locations checking for a distance of 5 miles.
Any help would be appreciated.
Upvotes: 0
Views: 999
Reputation: 1312
I recommend using a WebWorker so that the main UI thread isn't blocked for extended periods and a given event inspired search/filter can be interrupted of supplemented with more recent data: -
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;
}
Upvotes: 0
Reputation: 339816
don't store your lat/long values as strings - convert then to floating point at the earliest possible opportunity
separate out your Haversine calculation into its own function
consider using the Cosine variant of Haversine, and omitting the final acos
step
refactor constant expressions outside of the loop
consider pre-calculating the radian equivalents for latitude and longitude
See also Quicker way to calculate geographic distance between two points
Upvotes: 1