Search code examples
javascriptopenlayersturfjs

Trying to add a Feature of a Polygon ( square, or rectangle ) on OpenLayers with predefined width and heigth


I'm trying to programmatically add a feature with a geometry of a square or a rectangle polygon in OpenLayers with the help of turfjs to get the correct dimensions. Giving the same width and height, it should draw a square with an area of width^2, but I'm getting a a figure that is a rectangle. The idea is for some user to give the starting point and the dimensions in meters he wants for the polygon, and of course if he puts the same width and height he should see a square on the map.

const startingPoint = [-8, 37]; // lng, lat
const width = 1000; // meters
const height = 1000; // meters
const widthDeg = turf.convertLength(width, "meters", "degrees"); // 0.00899320363724538
const heightDeg = turf.convertLength(height, "meters", "degrees"); // 0.00899320363724538
const lng = startingPoint[0];
const lat = startingPoint[1];
const coordinates = [
            [lng, lat], // [-8, 37 ]
            [lng, lat + heightDeg], // [-8, 37.008993203637246 ]
            [lng + widthDeg, lat + heightDeg], // [-7.991006796362755, 37.008993203637246 ]
            [lng + widthDeg, lat], // [-7.991006796362755, 37 ]
            [lng, lat],// [-8, 37 ]
        ];
const poly = new Polygon([coordinates]);
const feature = new Feature(poly);
this._vectorSource?.addFeature(feature);

console.log("distance1", turf.distance([lng, lat], [lng, lat + heightDeg], { units: "meters" })); // output: 1000
console.log("distance2", turf.distance([lng, lat + heightDeg], [lng + widthDeg, lat + heightDeg], { units: "meters" })); // output: 799
console.log("area", turf.area(turf.polygon([coordinates]))); // output: 798588.2760202035

console.log("geometry", this._vectorSource?.getFeatures()[0].getGeometry()?.getExtent());
        // output: [ -8, 37, -7.991006796362755, 37.008993203637246]

This is what I get enter image description here

So I did some more investigation and I came up with this

const startingPoint = [-8, 37]; // lng, lat
const width = 1000; // meters
const height = 1000; // meters
const widthDeg = turf.convertLength(width, "meters", "degrees") / Math.cos((startingPoint[1] * Math.PI) / 180); // 0.011260710955255207
const heightDeg = turf.convertLength(height, "meters", "degrees"); // 0.00899320363724538
const lng = startingPoint[0];
const lat = startingPoint[1];
const coordinates = [
            [lng, lat], // [-8, 37 ]
            [lng, lat + heightDeg], // [-8, 37.008993203637246 ]
            [lng + widthDeg, lat + heightDeg], // [-7.988739289044744, 37.008993203637246 ]
            [lng + widthDeg, lat], // [-7.988739289044744, 37 ]
            [lng, lat], // [-8, 37 ]
        ];
const poly = new Polygon([coordinates]);
const feature = new Feature(poly);
this._vectorSource?.addFeature(feature);

console.log("distance1", turf.distance([lng, lat], [lng, lat + heightDeg], { units: "meters" })); // output: 1000
console.log(
            "distance2",
            turf.distance([lng, lat + heightDeg], [lng + widthDeg, lat + heightDeg], { units: "meters" })
        ); // output: 999.85
console.log("area", turf.area(turf.polygon([coordinates]))); // output: 999941

console.log("geometry", this._vectorSource?.getFeatures()[0].getGeometry()?.getExtent());
        // output: [ -8, 37, -7.988739289044744, 37.008993203637246]

And like that I get this enter image description here

So is the second solution the correct one?


Solution

  • The second method is correct.

    The shortest (great circle) distance between two points on a parallel is more direct than following the parallel which explains why turf.distance returns a slightly shorter distance than expected.