1

I would like to provide an option to draw a circle of a fixed radius in meters.

My problem is that if I enter 5 meters, I'm getting 4.99 meters if pass the LineString to sphere.getLength.

My code so far:

// 'center' comes from MapBrowserEvent<PointerEvent>.coordinate()
const forceRadius = 5;

const pointRes = getPointResolution(map.getView().getProjection(), 1, center);
const mapUnit = forceRadius / pointRes;
const radiusLineString = [center, [center[0] + mapUnit, center[1]]];

....

const geometry = new LineString(radiusLineString);
const radiusInMeter = getLength(geometry).toPrecision(3) + ' m'

How do I fix this?

3
  • 1
    At 5 meters that appears to be a limitation of the haversine length formula, as distances both ways along a meridian, and along a parallel all return approximately 4.99441. With a larger radius codesandbox.io/s/flight-animation-forked-yw1zc following a parallel is not the shortest route to a point east or west of the center, and as circle geometry does not reflect differences in point resolution within the radius there will be a considerable difference between the true distances to the northern and southern edges of the drawn circle.
    – Mike
    Sep 6, 2021 at 16:44
  • So I have no other option beside to "fake" my measuring details? It's confusing for the user if he enter 5 meters and get 4,99?
    – BR75
    Sep 6, 2021 at 17:50
  • 1
    It is not surprising that haversine distance calculations are not accurate to 1 centimeter. For short distances where such accuracy is needed it would be better to multiply the projected distance by the point resolution as point resolution would not change significantly over that radius unless you very close to one of the poles. For longer distances (kilometers) haversine calculations will be the most accurate method.
    – Mike
    Sep 6, 2021 at 18:15

2 Answers 2

1

On possible solution would be to use turf.destination method from turf.js library to calculate the second point:

var point1 = turf.point(ol.proj.toLonLat(center));
var point2 = turf.destination(point1, (0.001 * forceRadius), 90);

var coord1 = center;
var coord2 = ol.proj.fromLonLat(turf.getCoord(point2));

var geometry = new ol.geom.LineString([coord1, coord2]);
var radiusInMeter = ol.sphere.getLength(geometry);

In this case the resulting radiusInMeter is 5.000000000030424.

2
  • Thanks, I get the same result if I multiplicate the caluclated point resolution by the projected distance like mike suggested.
    – BR75
    Sep 7, 2021 at 21:08
  • 1
    @R.Kut Then it might be useful for somebody with the same question/problem, if you publish this as a possible solution. It's definitely simpler then having to use turf.js.
    – TomazicM
    Sep 8, 2021 at 8:54
1

Possible Solution:

const forceRadius = 5;
const pointRes = getPointResolution(map.getView().getProjection(), 1, center);
const mapUnit = forceRadius / pointRes;
const radius = [center, [center[0] + mapUnit, center[1]]];

const geometry = new LineString(radius);
const lengthInMeter = geometry.getLength() * pointRes;

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.