# Calculating dominant angle of a polygon in QGIS without main_angle function

How can I calculate dominant angle of a polygon in QGIS without main_angle function?

I have a shapefile of Oriented Minimum Bounding Box rectangles (accessible from the following link: https://drive.google.com/drive/folders/1Xr_0Apg9s7s0daevIUctWTr0-WCABC83?usp=sharing) produced by using as Input Layer a shapefile of irregular polygons (accessible from the following link: https://drive.google.com/drive/folders/1BKp5VbR1aMAzCObGprvqeL0WSMqpTX32?usp=sharing)

Figure 1: Shapefile of Oriented Minimum Bounding Box

Figure 2: Shapefile of Irregular Polygons

I need to find the main_angle of every polygon in the Oriented Minimum Bounding Box layer.

I used the main_angle function available in QGIS 3.16 onwards.

main_angle function returns the main angle of a geometry.

However, when I constructed centerlines using the centroid of the polygons (in this case rectangles) and main_angle values computed using the main_angle function in QGIS with the following expression:

``````intersection (
extend (
make_line (
centroid (\$geometry),
project (
centroid (\$geometry),
25000,
)
),
25000,
0
),
\$geometry
``````

)

Main_angle of the polygons computed with main_angle function is not at all times

the angle of longest collection of segments as in the image below encircled below:

What expression can be used such that main_angle is always the angle of longest segment of the Oriented Minimum Bounding Box in a project whereby main angle of every Oriented Minimum Bounding Box is the determining factor of accuracy of end results.

I found this comment from the following link: https://georezo.net/forum/viewtopic.php?id=119435

You need an expression dependent on the height and width data:

The end result I am seeking is the overall orientation of all ploygons collectively as illustrated in the image below from the Line Direction Tool QGIS plugin. By unfortunately provides no values.

I used XLSTAT to use Principal Component Analysis but did not achieve conculsive results. Computed results and report is accessible from following link: https://drive.google.com/drive/folders/1CHDfJ9poD8tk-KQLmRV8NbilZCyGtTs5?usp=sharing

• Which polygon in that file is it? And how did you create those lines? Commented Jan 14, 2021 at 18:08
• The folder contains shapefile of the polygons. In the attribute table, the main_angle field is calculated using main_angle function in QGIS 3.16. The line is drawn using centroid of each polygon and the main angle. main_angle Returns the main angle of a geometry (clockwise, in degrees from North), which represents the angle of the oriented minimal bounding rectangle which completely covers the geometry Commented Jan 14, 2021 at 18:16
• You may use principal component analysis (PCA). Scikit-learn Python package has a PCA function. See: doc.ic.ac.uk/~dfg/ProbabilisticInference/old_IDAPILecture14.pdf Commented Jan 15, 2021 at 7:38
• @Zoltan The final results I am seeking is the average main angle of orientation of the polygons collectively which visually approximates to 30 degrees. Commented Jan 15, 2021 at 7:50
• The first eigenvector gives the direction of the first principal direction. See: scikit-learn.org/stable/auto_examples/cross_decomposition/… Commented Jan 15, 2021 at 8:16

I inspected your data, the solution is based on that. First, create a new field `longest` that evaluates which side of your rectangle is the longest, `width` or `height`. Use this expression in the field calculator: `if ( "width" > "height" , 'width', 'height')`.

Than you can create the centerline using this expression with `Geometry generator` or `Geometry by expression` as you already have a field `angle` in your data that, depending on which one is the longest side, can be used to create what you want:

``````intersection (
\$geometry,
extend (
make_line (
centroid (\$geometry),
project (
centroid ( \$geometry ),
20,
if  (
"longest" =  'width' ,
)
)
),
20,
0
)
)
``````

If you want to get the mean value for the angle (azimuth) of all these lines, create a new layer `centerline` using `Geometry by expression` with the expression from above. On this line layer, create a new field `azimuth` using `field calculator` that calculates the angle of each line with this expression:

``````degrees (
azimuth (
start_point (\$geometry),
end_point (\$geometry)
)
)
``````

Now, you can use `Menu Vector / Analysis tools / Basic statistics for fields` on the `centerline` layer and setting the field `azimuth` as input (see screenshot below). The mean value for all centerlines, calculated with your data and according to this tool is `39.470817687074835`.

• With the Rose Diagram and visually, the main orientation of all polygons collectively can be seen to be in specific range which approximates to around 30 degrees. Can an additional filter be added to force (override "width" > "height" , 'width', 'height') such that all centerlines are drawn with respect to the collective orientation of all polygons. A suggestion can be a rotation of 90 degrees based on a condition. Commented Jan 15, 2021 at 12:07
• Of course you can use any custom value for the angle. Just paste this value in the expression instead of `"angle"` - see the result here: i.sstatic.net/UsH9G.png - is that the result you're looking for? Commented Jan 15, 2021 at 12:52
• Sorry, correction to my last comment: if you use a fixed value (e.g. 30 degrees), you should not use the `-90` part of the expression - you could replace the whole `if` clause by `radians (30)` (or, alternatively, just delete the `9` from `90` , thus: `radians ("angle"-0),` Commented Jan 15, 2021 at 13:03
• In the sent image, the lines are oriented in the overall direction of all polygons collectively, but are no more centerlines. I meant to say a filter to draw centerlines overriding the deciding factor width > height and width < height. The decision factor is which centerline would be closest to the overall orientation of all polygons collectively Commented Jan 15, 2021 at 13:05
• So you want one of two possible centerlines per rectangle. With centerlines you mean lines passing through the Midpoints, not the corners: surfandcode.in/2014/10/rectangle-centerlines-part-01.html - Right? To apply this: in the expression in my answer above, replace the condition in the `if`-clause from now `"longest" = 'width'` with: `"angle" >30 and "angle"<120`. Than you get the following result (red lines): i.sstatic.net/8ioDs.png Is this what you want? If not, it would help if you would draw on my screenshot to indicate how the lines should look. Commented Jan 15, 2021 at 14:33