5

I have polygons (blue) divided by lines (yellow) that are (more or less) parallel to the height contour lines. I want to calculate the height and width (i.e. bounding box) of the blue polygons in direction of the slope, i.e. perpendicular and parallel to the slope (represented by yellow line).

Judging from the name, the tool "oriented minimum bounding rectangle" sounded promising, but the orientation cannot be modified; it is always choosen in a way that minimizes the area of the polygon.

Is there a way to create a bounding box oriented in a specific direction, i.e. parallel to a line?

In below image, you see the "randomly" oriented bounding rectangles in magenta vs. sketched in dark green the result I would like (to ultimately calculate width and height of the polygon). In below image, you see the "randomly" oriented bounding rectangles in magenta vs. sketched in dark green the result I would like (to ultimately calculate width and height of the polygon).

1
  • The programmatic way would be to rotate the feature by the desired angle of the custom oriented bbox, create an axis aligned bbox, then rotate back both. Someone surely can translate that into an expression...
    – geozelot
    May 10 at 11:03

1 Answer 1

7
Credit to @geozelot for the concept

This expression is an implementation of geozelot's comment.

Breakdown of the expression
  • find the mean azimuth of all sequential pairs of vertices of all contour lines that intersect with each of the original polygons (perhaps median is a more appropriate statistic)
  • use that value to rotate the polygon
  • create an axis-aligned bounding box of the rotated polygon
  • rotate the bounding box back using the negative of the mean azimuth

To clarify, the rotation angle is calculated per polygon, it is not a global value.

Geometry by Expression tool settings

The expression can be used in the Geometry by Expression tool, using the polygon layer as the input layer, and Polygon as the Output geometry type.

enter image description here

Expression
with_variable(
    'center',                   
    centroid(bounds($geometry)),                         -- get the center point of the bouding box of the original polygon to use as the anchor point for rotation
    with_variable(
        'inter', 
        intersection(                                    -- get the intersection of the contour with the original polygon
            @geometry, 
            aggregate('contours', 'collect', @geometry)  -- change 'contours' for the name of your contours layer
        ),

        with_variable('nodes', nodes_to_points(@inter),
            
            with_variable('mean_azi',
                array_mean(                              -- get the mean azimuth of all the contour vertices that intersect with the original polygon
                    array_foreach(generate_series(1, num_geometries(@nodes)),
                        
                        azimuth(
                            geometry_n(@nodes, @element),
                            geometry_n(@nodes, @element - 1)
                        )
                    )
                ),
                
                rotate(                                  -- rotate the axis-aligned bounding box back to the mean azimuth of the intersecting contour
                    bounds(                              -- create the axis-aligned bounding box
                        rotate(                          -- rotate the polygon by the mean azimuth of the intersecting contour
                            $geometry,
                            degrees(@mean_azi),
                            @center                      -- rotate around the center of the bounding box of the original geometry
                        )
                    ),
                    degrees(-@mean_azi),                 -- negative angle to rotate back to starting angle
                    @center
                )
            )
        )
    )
)
Result

The red dotted outline is the generated bounding box, the solid blue outline is the oriented bounding box for comparison. The white points are the vertices used to obtain the mean azimuth of the contour segments.

enter image description here

4
  • 1
    *1 neat take on the intersecting mean slope!
    – geozelot
    May 10 at 13:31
  • It's not perfect, without some testing I am not 100% sure of the order of the nodes. It probably means that the last node of the first line will be paired with the first node of the second line, skewing the average azimuth - which is why I wonder if median is more appropriate. It could perhaps also be simplified to use only the first and last nodes of the intersecting lines, but that would be sensitive to outlying points. I will do some checks and refine the expression when I have some time.
    – Matt
    May 10 at 21:00
  • thanks for this great script! unfortunately for me it doesn't work right away. Just to make sure I'm using it right: As input I define my polygons and I need a second layer "countours" that contains the height contours (polylines) (or change the code respectively to the layername that contains my contours).
    – Honeybear
    May 15 at 21:22
  • You are right, yes. Does the expression builder in the Geometry by Expression tool show an error or do you see an error message when the tool has run?
    – Matt
    May 18 at 5:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.