Search code examples
javascriptalgorithmgeolocationcoordinates

Function/Script/Library to retrieve country name based on Lat and Long without Online APIS


I'm looking for a library/script/function or anything else for the next problem. I have a application which retrieve the Latitude and Longitude from Gps (Android). With Lat and Long, i want to return the country where those 2 values fit.

I want a library because i dont want to use any GOOGLE API or orther ip-info details, etc.

What i tried so far I have a file with all countries with the maximum border point coords. Example below

{
   "country": "Argentina",
   "north": -21.7813,
   "south": -55.0613,
   "west": -73.583,
   "east": -53.5918
},
{
    "country": "Falkland Islands",
    "north": -51.2407,
    "south": -52.3605,
    "west": -61.3452,
    "east": -57.7125
},

If i gave to Lat = -51.55 and Long = -60.00 ... The output is Argentina, because its the first entry in array. But the correct answer is Falkland Islands.

I tried to decrement actual Lat ( -51.55 ) - Falkland Island North( - 51.2407) to reach a number under 0 ... and make a lot of for...loops to get the closest number to 0. After that i tried to check for Long and West

for (const property in Object.entries(CountryCoords)) {
    if (CountryCoords[property]["south"] <= lat && lat <= CountryCoords[property]["north"]) {
      var ln = (CountryCoords[property]["north"] - lat); // 0
      if (ln < 5) {
        if (CountryCoords[property]["west"] <= long && long <= CountryCoords[property]["east"]) {
          var ol =  CountryCoords[property]["east"] - long;
          if (ol < 5) {
            // console.log(ln,ol, CountryCoords[property]["country"], ln, ol)
            return CountryCoords[property]["country"];
          }
        }
      }

    }
  }

But here is where i'm stuck cuz i dont know how to solve this algorithm and i tried since yesterday but i lack the brain to solve this...

*Think about some values are under 0 , and others are over 0.

Thanks


Solution

  • You don't need a library, you need a map. A vector map, preferably, because a simple bitmap one won't be of any help. Countries' bounding boxes are nice, but are just enough to filter out impossible results (no need to test Argentina if you're in Europe).

    You can do with a VMAP level 0 map (whole world map is easily found), it's splitted in 4 big zones for the whole world. The whole thing is around 400 MB, it's quite a good idea to store it in a database instead of using directly shapefiles. You can probably save a lot of space by removing unwanted data (rivers, forests, lakes, towns, ...) and keep ONLY countries boundaries.

    Once you get that done and prepared for your program, you'll have to solve the problem: "Having hundreds of georeferenced polygons, and a geographical position, in which polygon am I?" Once this is done, you'll get the country name as a simple entry of the polygon's metadata. You can easily get the data you need under 20 MB.

    Maybe you'll need a mathematical library at this step, but without an embedded, available map, you're stuck.

    NOTE: VMAP level 0 (a.k.a. "VMAP0") does not have a good precision. You may need to extend polygons and, maybe, return several country names when the position is close to a border. For example, it may be quite difficult to be able to return a valid name if you're in Monaco, Lichtenstein, or Andorra... Too smalls for a map as crude as VMAP0 is.

    For these polygon extensions, you may need a cartographic library. Another solution is to constantly extend your position to a circle (radius of at least 1 second), get 8 points on perimeter + center (N, NE, E, SE, S, SW, W, NW, center) and see which names are returned. A bit more CPU intensive at runtime than polygon extension (this can/should be done offline and you should store extended polygons directly in database), but it can saves you from getting a decent cartographic library and learn how to use it.

    Do not forget: map processing is an offline process, done one and ONLY time. Once you get the data, store that in any database you like (SQlite should be fine, even a simple structured file could be fine if you don't fear to load it into RAM).