10

I have a polygon layer with multiple polygon features drawn on it.

I need a tool that will draw a bounding box around each polygon feature individually. Right now everything I try in the tool box draws a single bounding box that encompasses all the polygon features. Is there such a tool?

2
  • 1
    @BERA You nailed it! (Please see bkg73123's comment to Cushen)
    – Kazuhito
    Commented Jul 4, 2018 at 14:49
  • Thank you so much! I was using the Bounding Box tool but it was giving me one big box. The iterate function didn't do it either. I had to do the multipart to singlepart tool first and then run the Bounding Box tool without iterate to get the results I needed. NOW I am trying to take the Bounding Boxes it created and Buffer them, but I need them to Buffer like they would a Line with the Flat end cap style. Should I create a new thread for this question or continue it here? When I try and buffer the bounding boxes it buffers them in all direction even if I select Flat end cap style. Thank you! –
    – bkg73123
    Commented Jul 4, 2018 at 19:12

6 Answers 6

19

In the Processing Toolbox (Processing Tab > Toolbox or Ctrl+Alt+T) you will find a tool called Bounding boxes. This will achieve what you want.

enter image description here

If your layer contains some multipart features you might want to run the Multipart to singleparts first (Depending on what output you want.)

Input > Output: enter image description here

7
  • You need to use the iterate tool (click on the green arrow) to get a bounding box for each polygon.
    – ahmadhanb
    Commented Jul 4, 2018 at 6:07
  • 1
    Are you sure? I'm running QGIS version 3.0.0-Girona and that is not the case, this tool creates a bounding box for each feature in an input layer.
    – Cushen
    Commented Jul 4, 2018 at 6:10
  • If the OP needs a separate feature for each bounding box, then clicking on the green arrow will give what he wants.
    – ahmadhanb
    Commented Jul 4, 2018 at 6:17
  • 1
    That is what the tool does, please try it locally, I have tested it.
    – Cushen
    Commented Jul 4, 2018 at 6:27
  • 1
    Thank you so much! I was using the Bounding Box tool but it was giving me one big box. The iterate function didn't do it either. I had to do the multipart to singlepart tool first and then run the Bounding Box tool without iterate to get the results I needed. NOW I am trying to take the Bounding Boxes it created and Buffer them, but I need them to Buffer like they would a Line with the Flat end cap style. Should I create a new thread for this question or continue it here? When I try and buffer the bounding boxes it buffers them in all direction even if I select Flat end cap style. Thank you!
    – bkg73123
    Commented Jul 4, 2018 at 13:33
7

If you want to have a separate feature class for each bounding box, you need to use the iterate tool (click on the green arrow) to get a bounding box for each polygon.

enter image description here

Without using the iterator, you will get all bounding boxes in one fearture class:

enter image description here

But using the iterator (the green arrow) will produce a bounding box for each polygon individually as a new feature class:

enter image description here

3

There is a possibility using a "Virtual Layer" through Layer > Add Layer > Add/Edit Virtual Layer...

Let's assume there is a polygon layer called 'test' with its corresponding attribute tables, see image below.

input

With the following query, it is possible to get the bounding box for each feature in the source layer.

SELECT id,
       ST_Envelope(geometry) AS geom,
       ST_AsText(ST_Envelope(geometry)) AS geom_text,
       -- XMIN,YMIN,XMAX,YMAX
       x_min(ST_Envelope(geometry)) || ',' ||
       y_min(ST_Envelope(geometry)) || ',' ||
       x_max(ST_Envelope(geometry)) || ',' ||
       y_max(ST_Envelope(geometry)) AS bbox
FROM "test"

The output polygon layer (grey) with its attribute table will look like

result

3

Here is a solution using python

def boundingbox(shp_dir, out_dir, obj_file, epsg='4326'):
    save_name = 0
    obj = glob.glob(obj_file + '/*.shp')[0]
    df = gpd.read_file(obj)
    # iterrate through verticies to find min and max of y and x
    for vertex in df.geometry:
        x, y = vertex.exterior.coords.xy
        xmin = min(x)
        xmax = max(x)
        ymin = min(y)
        ymax = max(y)

        # Create rectangle points
        upper_left = (xmin, ymax)
        upper_right = (xmax, ymax)
        lower_left = (xmin, ymin)
        lower_right = (xmax, ymin)

        # save shapefile containing one bounding box shape
        w = shapefile.Writer(shp_dir + str(save_name) + '.shp')
        w.field("name", "C")  # pyshp needs at least one field
        w.poly([[lower_left, lower_right, upper_right, upper_left]])  # generate bbox polygon
        w.record('bbox')
        w.close()

        # generate .PRJ file
        crs_wkt = 'epsg: ' + epsg
        prj = open(shp_dir + str(save_name) + '.prj', "w")
        prj.write(crs_wkt)
        prj.close()

        save_name = save_name + 1

    shapefiles = glob.glob(shp_dir + '/' + '/*.shp')
    gdf = pandas.concat([
        gpd.read_file(shp)
        for shp in shapefiles
    ]).pipe(gpd.GeoDataFrame)
    gdf.crs = ('epsg:4326')
    gdf.to_file(out_dir + '/' + 'merged.shp')

3

Here is a basic PyQGIS solution without external libraries:

layer = iface.activeLayer()
newlayer = QgsVectorLayer("Polygon?crs={}&index=yes".format(layer.crs().authid()), "BoundingBoxes", "memory")

with edit(newlayer):
    newlayer.dataProvider().addAttributes(layer.fields()) # copy the fields to the outputlayer
    newlayer.updateFields() # save the changes
    for feat in layer.getFeatures(): # iterate over inputlayer
        bbox = feat.geometry().boundingBox() # get the Boundingbox as QgsRectangle
        bbox_geom = QgsGeometry.fromRect(bbox) # Turn the QgsRectangle into QgsGeometry
        outfeat = QgsFeature() # Create a new feature
        outfeat.setAttributes(feat.attributes()) # copy the attributes to the outputlayer
        outfeat.setGeometry(bbox_geom) # set the geometry of the outputfeature to the bbox of the inputfeature
        newlayer.dataProvider().addFeature(outfeat) # add the feature to the outputlayer
        
QgsProject.instance().addMapLayer(newlayer)

It copies the features from the inputlayer 1 to 1 with all attributes and uses the inputfeatures boundingbox as geometry.

2

To add a solution using QGIS expressions with Geometry generator or Geometry by expression (see here for differences) - use this expression:

bounds ($geometry)

Initial polygons in orange, boundin boxes created with geometry generator in blue: enter image description here

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.