I'm using OpenLayers with the EPSG 3857 Coordinate System and I want my polygon labels to be orientated along the longest side of the polygon.
The labels in OpenLayers are aligned horizontally by default but I can rotate them by passing a radian value. It goes clockwise on positive and counterclockwise on negative radian. So I need to calculate the correct radians.
First I iterate the points of a polygon and calculate the longest side. Then I determine my vector from one point to another by subtracting the x and y values and the unit vector in the direction of the x-axis. Now I calculate the scalar product and if it's zero then I know I have to rotate my labels by 90 degree or PI/2 for radian. This works fine I just add PI to flip the text so I can read it easier.
With if/else at the end I'm messing around to get the right angle but I'm not sure at this point because it works for the most polygons but not all of them.
What I'm missing here?
My math looks like this for each polygon:
var arrPoints = feature.getGeometry().getFlatCoordinates();
if (arrPoints.length >= 6) {
var x = 0;
var y = 1;
var longestSide = 0;
var longestSidePointFrom;
var longestSidePointTo;
for (var i = 4; i <= arrPoints.length; i += 2) {
var pointFrom = [arrPoints[i - 4], arrPoints[i - 3]];
var pointTo = [arrPoints[i - 2], arrPoints[i - 1]];
const xDiff = arrPoints[i - 4] - arrPoints[i - 2];
const yDiff = arrPoints[i - 3] - arrPoints[i - 1];
var distance = Math.sqrt(xDiff * xDiff + yDiff * yDiff);
if (distance > longestSide) {
longestSide = distance;
longestSidePointFrom = pointFrom;
longestSidePointTo = pointTo;
}
}
var vector = [longestSidePointFrom[x] - longestSidePointTo[x], longestSidePointFrom[y] - longestSidePointTo[y]];
var scalarProduct = vector[x] * 1 + vector[y] * 0;
if (scalarProduct == 0) {
return Math.PI + (Math.PI / 2);
} else {
var sumA = Math.pow(vector[x], 2) + Math.pow(vector[y], 2);
var sumB = Math.pow(1, 2) + Math.pow(0, 2);
var cosine = scalarProduct / (Math.sqrt(sumA) * Math.sqrt(sumB));
var radian = Math.acos(cosine);
if (radian > (Math.PI / 2)) {
radian = radian * -1 + (Math.PI)
} else {
radian = radian + 2 * Math.PI;
}
return radian;
}
}
EDIT:
Here are 4 Polygons. The green line indicates the longest side. As you can see the angle for number 1 is not correct:
Here are the coordinates for the shown polygons:
1)
0: 44.7879 1: 313.8661 2: 42.1537 3: 317.1012 4: 45.4705 5: 319.8012 6: 48.1048 7: 316.5661 8: 44.7879 9: 313.8661
2)
0: 42.458 1: 311.9045 2: 39.7923 3: 315.1779 4: 42.1537 5: 317.1012 6: 44.7879 7: 313.8661 8: 42.458 9: 311.9045
3)
0: 37.2561 1: 307.6731 2: 34.5923 3: 310.9445 4: 36.9185 5: 312.8382 6: 39.5832 7: 309.5648 8: 37.2561 9: 307.6731
4)
0: 29.4927 1: 301.3244 2: 26.8156 3: 304.6124 4: 30.0662 5: 307.259 6: 32.7309 7: 303.9856 8: 29.4927 9: 301.3244