3

I want to generate a random coordinate that would display anywhere on the map. I've seen these two posts:

Generating random lat/long coordinates

And using this post for the JavaScript code: https://stackoverflow.com/questions/69221354/how-to-generate-random-longitude-and-latitude

And came up with the following:

function generateRandomLonLat() {
  return [Math.floor(Math.random() * 360) - 180, Math.round(Math.acos(2 * Math.random() - 1) * 180 / Math.PI) - 90];
}

But it also generates non-valid coordinates that are outside of the map.

Why?

5
  • 2
    What values of lat and long does it generate that are outside? Are you mixing lat and long at some point?
    – Spacedman
    Commented Oct 14 at 19:56
  • 1
    I'm assuming you're trying to perform the areal weighting that counteracts polar bias in random latitude generation. In this Answer I used the SQL expression (acos(1.0 - 2.0 * random()) * 2.0 - pi()) * 90.0 / pi()) to normalize the distribution by area. You'd need to port that PostgreSQL code to JavaScript.
    – Vince
    Commented Oct 14 at 20:18
  • thanks guys, I'm using OpenLayers map and trying to display a marker there. Also I just logged the result and noticed it's only producing integers and not floats 😅, yet still it works sometimes. An example value that it generates outside: [-2, -77]. I'm sorry I'm not familiar with the geographic part as I just followed some instructions. Could [-2, -77] be a valid point just maybe not visible on my map because of code error, or, it really is outside?
    – pileup
    Commented Oct 14 at 20:26
  • 2
    Web Mercator has its own limits, since the poles are infinitely far from the Equator, but neither {-2,-77} nor {-77,-2} (however you choose to order them) is invalid as a location in degrees.
    – Vince
    Commented Oct 14 at 20:36
  • @Vince thank you!
    – pileup
    Commented Oct 15 at 17:37

1 Answer 1

7
  • Your code is returning integers because you explicitly ask for them with Math.floor and Math.round.
  • Your code produces points in the bounds [-180, -90, 180, 90] which are valid lon, lat coordinates. However, the valid geodetic bounds for EPSG:3857 are [-180, -85.06, 180, 85.06], so you need to restrict the latitudes you generate.
  • You're generating lon, lat (X,Y). Make sure you are using them in the correct order expected by OpenLayers (i.e lon, lat not lat, lon)
  • You haven't shown your code that adds a marker to the map, but don't forget to project the point into EPSG 3857 .

These points are addressed by the code below:

function generateRandomLonLat() {
  return [
    (Math.random() * 360) - 180, 
    (Math.acos(2 * Math.random() - 1) * 170.12 / Math.PI) - 85.06
  ];
}

const LonLat = generateRandomLonLat();
const XY = ol.proj.fromLonLat(LonLat);

Runnable example (modified from https://jsfiddle.net/geocodezip/pzmh64jk/4/):

function generateRandomLonLat() {
  return [
    (Math.random() * 360) - 180, 
    (Math.acos(2 * Math.random() - 1) * 170.12 / Math.PI) - 85.06
  ];
}
const LonLat = generateRandomLonLat();
const XY = ol.proj.fromLonLat(LonLat);
console.log(LonLat);

const iconFeature = new ol.Feature({
  geometry: new ol.geom.Point(XY), 
  name: 'Random Point',
});

const map = new ol.Map({
  target: 'map',
  layers: [
    new ol.layer.Tile({ // TileLayer({
      source: new ol.source.OSM() // OSM()
    }),
    new ol.layer.Vector({ // VectorLayer({
      source: new ol.source.Vector({// VectorSource({
        features: [iconFeature]
      }),
      style: new ol.style.Style({ // Style({
        image: new ol.style.Icon({ // Icon({
          anchor: [0.5, 30],
          anchorXUnits: 'fraction',
          anchorYUnits: 'pixels',
          src: 'https://openlayers.org/en/v5.3.0/examples/data/icon.png' 
        })
      })
    })
  ],
  view: new ol.View({
    center: XY,
    zoom: 2
  })
});
html,
body {
  height: 100%;
  width: 100%;
  padding: 0px;
  margin: 0px;
}

.map {
  height: 90%;
  width: 100%;
}
<link rel="stylesheet" href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v6.4.3/css/ol.css" type="text/css">
<script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v6.4.3/build/ol.js"></script>
<title>OpenLayers example</title>
<div id="map" class="map"></div>

Although if you don't want the areal weighting of latitudes, your code would become:

function generateRandomLonLat() {
  return [
    (Math.random() * 360) - 180, 
    (Math.random() * 170.12) - 85.06
  ];
}

const LonLat = generateRandomLonLat();
const XY = ol.proj.fromLonLat(LonLat);

function generateRandomLonLat() {
  return [
    (Math.random() * 360) - 180, 
    (Math.random() * 170.12) - 85.06
  ];
}

const LonLat = generateRandomLonLat();
const XY = ol.proj.fromLonLat(LonLat);
console.log(LonLat);

const iconFeature = new ol.Feature({
  geometry: new ol.geom.Point(XY), 
  name: 'Random Point',
});

const map = new ol.Map({
  target: 'map',
  layers: [
    new ol.layer.Tile({ // TileLayer({
      source: new ol.source.OSM() // OSM()
    }),
    new ol.layer.Vector({ // VectorLayer({
      source: new ol.source.Vector({// VectorSource({
        features: [iconFeature]
      }),
      style: new ol.style.Style({ // Style({
        image: new ol.style.Icon({ // Icon({
          anchor: [0.5, 30],
          anchorXUnits: 'fraction',
          anchorYUnits: 'pixels',
          src: 'https://openlayers.org/en/v5.3.0/examples/data/icon.png' 
        })
      })
    })
  ],
  view: new ol.View({
    center: XY,
    zoom: 2
  })
});
html,
body {
  height: 100%;
  width: 100%;
  padding: 0px;
  margin: 0px;
}

.map {
  height: 90%;
  width: 100%;
}
<link rel="stylesheet" href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v6.4.3/css/ol.css" type="text/css">
<script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v6.4.3/build/ol.js"></script>
<title>OpenLayers example</title>
<div id="map" class="map"></div>

2
  • Wow your explanation was everything, and more. Thank you! It work mostly, however from some reason, some coordinates disappear, but much smaller frequency than before. Example coordinates that isn't showing on the map: [58.19509551870857,-44.98842842838366] or [147.3512294662313,-49.11396772200184]. Any idea why? I think I know - it isn't valid according to your rules, so maybe it's just an error in the JavaScript code?
    – pileup
    Commented Oct 15 at 17:41
  • I don't think there's an error, and they are definitely valid coordinates. As you know the latitudes are intentionally weighted toward lower latitudes, that's the "areal weighting that counteracts polar bias in random latitude generation" Vince referred to in a comment on your question. Restricting the latitude to valid EPSG:3857 bounds will likely increase that slightly. But I just ran the original snippet 4 times and got one -44.85 latitude, so they are still being returned. If you don't want the weighting, see edited answer.
    – user2856
    Commented Oct 16 at 0:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.