Locate the closest point among a set of coordinates to a specified point

I have a situation where I have an object that contains latitude and longitude attributes. My goal is to find the closest match in an array of similar objects by considering both latitude and longitude.

obj = {latitude: 55.87, longitude: 4.20}

[
  {
    "latitude": 55.85,
    "longitude": 4.22
  },
  {
    "latitude": 55.89,
    "longitude": 4.16
  },
  {
    "latitude": 55.88,
    "longitude": -4.24
  }
]

My objective is to determine the index of the array that is the closest match to the object.

Answer №1

One method to calculate the spherical distance between two points is by using the Haversine formula. This can be achieved by implementing the formula in Javascript and utilizing the Array prototype reduce method:

const haversine = ({longitude: lonA, latitude: latA}, {longitude: lonB, latitude: latB}) => {
        const {PI, sin, cos, atan2} = Math,
              r = PI/180,
              R = 6371,
              deltaLat = (latB - latA)*r,
              deltaLon = (lonB - lonA)*r,
              a = sin(deltaLat / 2)**2 + cos(cos(latB*r)*latA*r) * sin(deltaLon /2)**2,
              c = 2 * atan2(a**0.5, (1 - a)**0.5),
              d = R * c
        return d
      },
      
      obj = {latitude: 55.87, longitude: 4.20},

      arr = [{"latitude":55.85,"longitude":4.22},{"latitude":55.89,"longitude":4.16},{"latitude":55.88,"longitude":-4.24}],
      
      {closest} = arr.reduce((r,o) => {
        const distance = haversine(o, obj)
        distance < r.minDistance || !r.closest &&
        (r.closest = o, r.minDistance = distance)
        return r
      }, {closest: null, minDistance: null})
      
console.log(closest)
.as-console-wrapper{min-height:100%;}

Answer №2

If you want to achieve this using JavaScript, you can utilize the following code snippet

export class ContentComponent implements OnInit {

  compareTo: any = { latitude: 55.87, longitude: 4.20 };
  data: Array<any> = [
    {
      "latitude": 55.85,
      "longitude": 4.22
    },
    {
      "latitude": 55.89,
      "longitude": 4.16
    },
    {
      "latitude": 55.88,
      "longitude": -4.24
    }
  ];

  // data filtered
  filteredData: Array<any> = [];

  constructor() { }

  ngOnInit() {
    
    var tmpData: Array<any> = [];

    this.data.forEach(x => {
      var res = this.computeDistance(x.latitude, x.longitude, this.compareTo.latitude, this.compareTo.longitude, "K");
      tmpData.push({ distance: res, obj: x });
    });

    tmpData.sort((a, b) => a.distance - b.distance);
    tmpData.forEach(x => this.filteredData.push(x.obj));
    
  }

  computeDistance(lat1, lon1, lat2, lon2, unit) {
    if ((lat1 == lat2) && (lon1 == lon2)) {
      return 0;
    }
    else {
      var radlat1 = Math.PI * lat1/180;
      var radlat2 = Math.PI * lat2/180;
      var theta = lon1-lon2;
      var radtheta = Math.PI * theta/180;
      var dist = Math.sin(radlat1) * Math.sin(radlat2) + Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta);
      if (dist > 1) {
        dist = 1;
      }
      dist = Math.acos(dist);
      dist = dist * 180/Math.PI;
      dist = dist * 60 * 1.1515;
      if (unit=="K") { dist = dist * 1.609344 }
      if (unit=="N") { dist = dist * 0.8684 }
      return dist;
    }
  }
}

Answer №3

To retrieve the index, utilize the code snippet below. The approach emulates the pattern established by @Meadow.

let points = [{
        "latitude": 55.85,
        "longitude": 4.22
      },
      {
        "latitude": 55.89,
        "longitude": 4.16
      },
      {
        "latitude": 55.88,
        "longitude": -4.24
      },
      {
        "latitude": 55.86,
        "longitude": 4.21
      }
    ];
    let allDistance:any = [];

    points.forEach((x,index)=> {
      var res = this.getDistance(x.latitude, x.longitude, 55.87, 4.20, "km");
      allDistance.push({ distance: res, obj: x,index: index});
    });

    allDistance.sort((a, b) => a.distance - b.distance);
    console.log("Index:"+allDistance[0].index);  
    console.log(allDistance);   

Custom Distance Calculation Function:

  getDistance(markerLat: any, markerLon: any, sourceLat: any, sourceLng: any,unit): any {
    var radlat1 = Math.PI * sourceLat / 180;
    var radlat2 = Math.PI * markerLat / 180;
    var theta = sourceLng - markerLon;
    var radtheta = Math.PI * theta / 180;
    var dist = Math.sin(radlat1) * Math.sin(radlat2) + Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta);
    if (dist > 1) {
      dist = 1;
    }
    dist = Math.acos(dist);
    dist = dist * 180 / Math.PI;
    dist = dist * 60 * 1.1515;
    dist = dist * 1.609344;
    if (unit != 'mi') {
      return isNaN(dist) ? 0 : dist;
    }
    return isNaN(dist * 0.62137) ? 0 : dist * 0.62137;
  }

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is it possible to substitute a one-line jQuery.load() with a fetch() function that achieves the same result?

I am currently working on a page where I utilize a single line of jQuery code: $('#id').load('/url'); This line allows me to load a fragment into a specific place in the DOM. However, I am now considering reducing my reliance on jQuer ...

There seems to be an issue with the functionality of ChartJS when used

Currently working on a project that involves creating a chart using chartjs.org. I have retrieved data from my database in a PHP document and saved it into a JSON file: print json_encode($result->fetch_all()); The resulting data looks like this: [["1 ...

Loading times for the Polymer Project are sluggish

The website design is very appealing. However, it seems to be loading quite slowly even on Google's servers. Is there a way to speed up the initial load time of the Polymer site? Additionally, there are numerous HTTP requests being made; is there a wa ...

employing rowspan functionality within a JavaScript application

How can I achieve a table layout where the first two columns are fixed for only one row and the remaining rows are repeated 7 times? Additionally, is there a way to make the bottom border of the last row thicker? Check out the expected table for reference. ...

Retrieve the value of a field from a Formik form integrated with Material UI

I've been working on a way to disable a checkbox group depending on the selected value of a radio group. I took inspiration from the technique outlined in the final section of the Formik tutorial. Using React context has definitely helped clean up the ...

A clever JavaScript function generator encapsulated within an instant function nested within a jQuery ready statement

This code snippet features an immediate function enclosed within a jQuery ready function. $((function(_this) { return function() { document.write('called!'); }; })(this)); I am puzzled by where the resultant function ...

If you don't get the correct response from the $.ajax success function

I am utilizing the $.ajax function to retrieve content, however I am encountering an issue when attempting to display special tags from it. The data appears to be missing! This is how I am currently handling it: $(document).ready(function(){ $("button") ...

What type of technology is typically utilized in creating functional platforms such as goDaddy, wix, and other web design websites?

I am currently working on a web development project that aims to allow users to edit webpages without needing any coding knowledge. Users with authorization will be able to modify not only the text but also various HTML tags on the page, similar to platfor ...

Utilizing Electron and jQuery to incorporate a loading animated GIF into a newly opened window, where the animation pauses

I am working on an electron project that involves opening a new window with an index.html file. In this newly opened window, I have included an animated.gif in the body section. <!doctype html> <html lang="en> <head> <meta charset ...

Is it considered fashionable to utilize HTML5 data attributes in conjunction with JavaScript?

Currently, I am utilizing HTML5 data attributes to save information such as the targeted DOM element and to initialize events using jQuery's delegation method. An example of this would be: <a href="#" data-target="#target" data-action="/update"> ...

How can I bring the toolbar to the forefront of the page in an Angular/HTML environment?

I am currently facing an issue with bringing the toolbar to the forefront of the page. When I scroll down, the elements on the page end up covering the toolbar which is not the desired behavior. Below is the CSS code for the toolbar: .maintoolbar.mat-tool ...

The text field is unable to receive input by clicking a button, only registering values when physically typed into the field

I have three text fields with buttons to increment or decrement the value, and a final text field that displays the calculation of the values in each field. Everything is functioning correctly, however, the issue arises when I try to add values using the ...

Creating spec.ts files for components by hand: A guide

Currently, I am facing an issue where the automatic generation of spec.ts files has been disabled by the developers when they created the components. To address this, I manually created the spec.ts files by copying over an existing one into each component, ...

Does adding the Angular bootstrap script at the end of the body tag impact webpage speed more than using ng-app on the body tag?

In the past, we had placed ng-app on the body tag which led to problems with dependency injection when multiple modules were being used on the same webpage. This required module creators to be aware of the existing app and inject their app into it. We are ...

How can you prevent specific dates from being selected in an Angular Datepicker?

Is there a way to exclude Monday from the "mat-datepicker" component? I've tried implementing the following code in my class component: dateFilter = (_date: any) =>{ let day = _date.getDay(); console.log(day); return day != 1; ...

What is the best way to transform a JSON array into a string?

Is there a way to convert an array into a string using php? Check out the sample array below: { "result": "success", "message": [ { "date_insert": "2017-01-28 20:14:51", "date_update": "2017-01-28 20:15:11", ...

What steps need to be taken in VSCode to import React using IntelliSense?

When I press Enter in that image, nothing seems to occur. I believed IntelliSense would automatically insert import React from 'react'; at the beginning of the file. https://i.stack.imgur.com/7HxAf.png ...

The issue arises when using multiple route files in Route.js, as it hinders the ability to incorporate additional functions within the

After breaking down Route.js into multiple controllers, I'm stuck on why I can't add an extra function to block permissions for viewing the page. // route.js module.exports = function(app, passport) { app.use('/profile&apos ...

When the user clicks on the element, swap out the current image tag

Is it possible to replace the <img src> code in a textarea with image URLs when a button is clicked? <textarea> <img src="https://example.com/image1.gif" alt="image1" /></a> <img src="https://example.com/image2.gif" alt="ima ...

Transmit information from an Angular application to a Spring Boot server using a POST request

Attempting to send JSON data from a frontend Angular project to a Spring Boot backend for the first time. Limited experience with both technologies and unsure if the HTTP POST method in Angular is incorrect, or if the backend isn't receiving the expec ...