I'm trying to create a circle with a specific on-the-ground radius in OpenLayers v5. But I do not seem to understand how to create it with a specific unit of measure such as meters, miles, etc. The radius argument in the constructor appears to be some non-specified map unit, as noted in this issue, which is concluded with using the getMetersPerUnit
method from the projection. However, everytime this method is called, it always seems to return 1. I've also looked at doing something with the METERS_PER_UNIT
export in the projection library, but again, the value for meters is 1.
My drawing tries to give a good starting point that's based on the current view's extent. The previous work used 1/8th the lateral distance of the current view.
function getRoundedEigthedDistanceBetweenPoints(coordinateA, coordinateB) {
/**
* Distance between bottom right and left corners in meters
* We want 1/8 of the distance, rounded to nearest 10?
* Why? /shrug ♂️
*/
return (getDistanceBetweenPoints(coordinateA, coordinateB) / 8 / 10) * 10;
}
/**
* @link https://stackoverflow.com/a/28454386/168005
* @param coordA
* @param coordB
*/
function getDistanceBetweenPoints(coordA, coordB) {
return (new LineString([coordA, coordB]).getLength() * 100) / 100;
}
const [minX, _, maxX, __] = map.getView().calculateExtent();
// Since all I want is a straight line, I just give it the minX and maxX values, and zero out the "Y"s.
const startingDistance = getRoundedEigthedDistanceBetweenPoints([minX, 0], [maxX, 0]);
Given the above, I was presuming the result of this startingDistance
was in meters. But if I compare my circles's values to a normal LineString length, the numbers are off quite a bit.
The problem gets worse when I try to change the radius later from user input, because I was thinking I was working in meters (clearly that's not true), so I convert the values provided down to meters and set it directly as the radius.
enum Units {
Meters = "m",
Miles = "mi",
Kilometers = "km",
Feet = "ft",
}
const METERS_PER_FEET = 0.3048;
const FEET_PER_MILE = 5280;
const METERS_PER_KILO = 1000;
function convertFeetToMeters(feet) {
return feet * METERS_PER_FEET;
}
function convertMilesToMeters(miles) {
return miles * METERS_PER_MILE;
}
function convertMetersToKilometers(meters) {
return meters / METERS_PER_KILO;
}
function convertUnitToMeters(unit: Units, value: number) {
switch (unit) {
case Units.Feet:
return convertFeetToMeters(value);
case Units.Miles:
return convertMilesToMeters(value);
case Units.Kilometers:
return convertKilometersToMeters(value);
default:
return value;
}
}
function updateFeature({ type, feature, unit, value }) {
/**
* Mutably make the change
*/
if (type === "radius" || type === "unit") {
// Take in the units listed in the UI and convert the value, respectively.
const computedRadius = convertUnitToMeters(unit.value, parseFloat(value));
feature.getGeometry().setRadius(computedRadius);
}
}
I know there's this whole Web Mercator distortion business, and using something like getLength
from the ol/sphere
module will convert the radius out of an already created circle, but what about setting the radius of a circle? Is there a tool available for that?