4

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)

Shapefile of Oriented Minimum Bounding Box

Figure 1: Shapefile of Oriented Minimum Bounding Box

Shapefile of Irregular Polygons 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:

enter image description here

intersection (
extend (
    make_line (
        centroid ($geometry), 
        project (
            centroid ($geometry), 
            25000, 
            radians("main_angle")
        )
    ),
    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:

enter image description here

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:

enter image description here

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.

enter image description here

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

10
  • 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
    – HansrajR
    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
    – Zoltan
    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.
    – HansrajR
    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/…
    – Zoltan
    Commented Jan 15, 2021 at 8:16

1 Answer 1

2

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' , 
                    radians ("angle"-90 ), 
                    radians ("angle" )
                )
            )
        ), 
    20,
    0
    )
)

enter image description here

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.

enter image description here

15
  • 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.
    – HansrajR
    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?
    – Babel
    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),
    – Babel
    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
    – HansrajR
    Commented Jan 15, 2021 at 13:05
  • 1
    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.
    – Babel
    Commented Jan 15, 2021 at 14:33

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.