2

I'm currently trying to create a series of subplots within a larger plot, but outside of a nesting smaller plot, and am having trouble with it. This is the code I'm working from. I've also added a picture of what I'm trying to get at the bottom.

Learning QGIS=group
input_layer=vector
size=number 15
subplotsize=number 2
subplots=number 4
squares=output vector
minisquares=output vector
from qgis.core import *
from processing.tools.vector import VectorWriter
import random
# get the input layer and its fields
my_layer = processing.getObject(input_layer)
fields = my_layer.dataProvider().fields()
#get the input layer and its fields
my_layer2 = processing.getObject(input_layer)
fields2 = my_layer2.dataProvider().fields()
# create the output vector writer with the same fields
writer = VectorWriter(squares, None, fields, QGis.WKBPolygon, my_layer.crs())
writer2 = VectorWriter(minisquares, None, fields2, QGis. WKBPolygon, my_layer2.crs())
# create output features
feat = QgsFeature()
feat2 = QgsFeature()
sx=subplots
sps=subplotsize/2
for input_feature in my_layer.getFeatures():
    # copy attributes from the input point feature
    attributes = input_feature.attributes()
    feat.setAttributes(attributes)
    # create square polygons
    point = input_feature.geometry().asPoint()
    xmin = point.x() - size/2
    ymin = point.y() - size/2 
    for tx in range(0, sx):
        px=random.uniform(1, 10) - 5 + point.x()
        py=random.uniform(1, 10) - 5 + point.y()
        print px, py 
        square = QgsRectangle(px-sps, py-sps, px+sps, py+sps)
        feat2.setGeometry(QgsGeometry.fromRect(square))
        writer2.addFeature(feat2)
    square = QgsRectangle(xmin,ymin,xmin+size,ymin+size)
    feat.setGeometry(QgsGeometry.fromRect(square))
    writer.addFeature(feat)
del writer

I know this is probably a basic question, but I'm new to coding and all I've managed to do is move around the coordinates of the subplots.

enter image description here

PolyGeo
  • 65,136
  • 29
  • 109
  • 338

1 Answers1

1

I have a working example which uses the python console in QGIS.

Assuming the input plots are circles or regular sided squares.

It takes 5 variables:

  • innerlayer [Inner geometry (nesting smaller plot)]
  • outerlayer [Inner geometry (larger plot)]
  • points [number of seed points/outputs polygons to generate]
  • buf_dist [distance to buffer | radius/width of output polygons]
  • circle [True or False; whether to output circles]

To run, edit the variables and paste the code into the python console in QGIS. Tested for QGIS 2.8.2

import random
from PyQt4.QtCore import QVariant

layer=iface.activeLayer()
innerlayer=QgsVectorLayer('C://temp//InnerShp.shp', 'InnerShp', 'ogr')
outerlayer=QgsVectorLayer('C://temp//OuterShp.shp', 'OuterShp', 'ogr')
crs = layer.crs().toWkt()

points = 15 # set as you want
buf_dist = 100
circle = True

#aad layers to viewer
QgsMapLayerRegistry.instance().addMapLayer(outerlayer)
QgsMapLayerRegistry.instance().addMapLayer(innerlayer)

# Create the output layer
outLayer = QgsVectorLayer('Point?crs='+ crs, 'random_points' , 'memory')
prov = outLayer.dataProvider()
prov.addAttributes([QgsField('ID', QVariant.Int, '', 10, 0)])
outLayer.updateFields()


ext=outerlayer.extent()
xmin = ext.xMinimum()
xmax = ext.xMaximum()
ymin = ext.yMinimum()
ymax = ext.yMaximum()



first = True
for feat in outerlayer.getFeatures():
    if first:
        outFeat = QgsFeature()
        outGeom = QgsGeometry(feat.geometry())
        first = False
    else:
        outGeom = outGeom.combine(feat.geometry())

outFeat.setGeometry(outGeom)

first = True
for infeat in innerlayer.getFeatures():
    if first:
        innerFeat = QgsFeature()
        innerGeom = QgsGeometry(infeat.geometry())
        first = False
    else:
        innerGeom = innerGeom.combine(infeat.geometry())

innerFeat.setGeometry(innerGeom)

id = 0
p = 1
while p <= points:
    x_coord = random.uniform(xmin, xmax)
    y_coord = random.uniform(ymin, ymax)
    pt = QgsPoint(x_coord, y_coord)
    tmp_geom = QgsGeometry.fromPoint(pt)
    if tmp_geom.intersects(outFeat.geometry()) and not tmp_geom.intersects(innerFeat.geometry()):
        outGeom = QgsFeature()
        outGeom.setGeometry(tmp_geom)
        outGeom.setAttributes([id])
        prov.addFeatures([outGeom])
        id += 1
        p += 1

# Add the layer to the Layers panel
QgsMapLayerRegistry.instance().addMapLayer(outLayer)

layer = iface.activeLayer()

feats = [ feat for feat in layer.getFeatures() ]

epsg = layer.crs().postgisSrid()

uri = "Polygon?crs=epsg:" + str(epsg) + "&field=id:integer""&index=yes"

if not circle:
    mem_layer = QgsVectorLayer(uri,
                               'square_buffer',
                               'memory')
    prov = mem_layer.dataProvider()
    for i, feat in enumerate(feats):
        new_feat = QgsFeature()
        new_feat.setAttributes([i])
        tmp_feat = feat.geometry().buffer(buf_dist, -1).boundingBox().asWktPolygon()
        new_feat.setGeometry(QgsGeometry.fromWkt(tmp_feat))
        prov.addFeatures([new_feat])
    QgsMapLayerRegistry.instance().addMapLayer(mem_layer)

if circle:
    mem_layer_circle = QgsVectorLayer(uri,
                               'round_buffer',
                               'memory')
    provcircle = mem_layer_circle.dataProvider()
    for i, feat in enumerate(feats):
        new_feat = QgsFeature()
        new_feat.setAttributes([i])
        tmp_feat = feat.geometry().buffer(buf_dist, 20).asPolygon()
        new_feat.setGeometry(QgsGeometry.fromPolygon(tmp_feat))
        provcircle.addFeatures([new_feat])    
    QgsMapLayerRegistry.instance().addMapLayer(mem_layer_circle)

Example Outputs:

enter image description here

Work adapted from these questions:

Cushen
  • 2,928
  • 13
  • 15