J'ai une fonction qui crée des éoliennes représentées par des points. Essentiellement, il utilise le code des points aléatoires à l'intérieur de l' outil polygones (fixe) , mais avec quelques légères modifications.
L'objectif est de créer des points aléatoires à l'intérieur des polygones en tenant compte de la distance minimale spécifiée. Cela fonctionne très bien surtout avec des polygones qui ne sont pas proches les uns des autres (par exemple un seul polygone):
Cependant, si le polygone est proche ou adjacent à un autre polygone (par exemple, comme indiqué ci-dessous), les points de chaque polygone peuvent être dans la distance minimale comme indiqué en rouge:
Comment pourrais-je changer le code pour que ces points en rouge ne soient pas proches les uns des autres d'un polygone voisin?
Idéalement, je souhaite que plusieurs points soient remplacés par un seul:
Voici le code qui peut être reproduit dans la console Python , une couche polygonale doit être sélectionnée avec un CRS approprié avant d'exécuter la fonction:
import random
from PyQt4.QtCore import QVariant
def checkMinDistance(point, index, distance, points):
if distance == 0:
return True
neighbors = index.nearestNeighbor(point, 1)
if len(neighbors) == 0:
return True
if neighbors[0] in points:
np = points[neighbors[0]]
if np.sqrDist(point) < (distance * distance):
return False
return True
def generate_wind_turbines(spacing):
layer = iface.activeLayer()
crs = layer.crs()
# Memory layer
memory_lyr = QgsVectorLayer("Point?crs=epsg:" + unicode(crs.postgisSrid()) + "&index=yes", "Wind turbines for " + str(layer.name()), "memory")
QgsMapLayerRegistry.instance().addMapLayer(memory_lyr)
memory_lyr.startEditing()
provider = memory_lyr.dataProvider()
provider.addAttributes([QgsField("ID", QVariant.Int)])
# Variables
point_density = 0.0001
fid = 1
distance_area = QgsDistanceArea()
# List of features
fts = []
# Create points
for f in layer.getFeatures():
fGeom = QgsGeometry(f.geometry())
bbox = fGeom.boundingBox()
pointCount = int(round(point_density * distance_area.measure(fGeom)))
index = QgsSpatialIndex()
points = dict()
nPoints = 0
fid += 1
nIterations = 0
maxIterations = pointCount * 200
random.seed()
while nIterations < maxIterations and nPoints < pointCount:
rx = bbox.xMinimum() + bbox.width() * random.random()
ry = bbox.yMinimum() + bbox.height() * random.random()
pnt = QgsPoint(rx, ry)
geom = QgsGeometry.fromPoint(pnt)
if geom.within(fGeom) and checkMinDistance(pnt, index, spacing, points):
f = QgsFeature(nPoints)
f.setAttributes([fid])
f.setGeometry(geom)
fts.append(f)
index.insertFeature(f)
points[nPoints] = pnt
nPoints += 1
nIterations += 1
provider.addFeatures(fts)
memory_lyr.updateFields()
memory_lyr.commitChanges()
generate_wind_turbines(500)
Éditer:
La dissolution et / ou la conversion des polygones en parties uniques ne semble pas beaucoup aider car les points générés semblent toujours se situer dans la distance minimale.
Testé sur QGIS 2.18.3 .
la source
Réponses:
Vous devez changer deux choses pour que cela fonctionne. Cependant, vous n'obtiendrez pas le maximum d'éoliennes par zone. Pour cela, vous devrez exécuter quelques itérations pour chaque valeur et obtenir le nombre maximal de points.
J'ai déplacé le
index = QgsSpatialIndex()
etpoints = dict()
à l'extérieur de la boucle for. Le code ressemblerait à ceci:ÉDITER:
Joseph avait raison. mes changements ne fonctionnaient que pour une zone vraiment petite. J'ai testé et trouvé une nouvelle solution en déplaçant deux variables hors de la boucle for et en changeant la
pointCount
variable.Je l'ai testé à 500m et voici le résultat (deux essais différents):
la source
Une méthode pourrait être de créer une autre fonction qui effectue les opérations suivantes:
Voici la fonction que j'ai utilisée:
La fonction peut être exécutée immédiatement à la fin de la
generate_wind_turbines()
fonction en utilisant:Cela donne les résultats comme indiqué dans l'image de la question. Probablement pas la solution la plus efficace, mais elle semble fonctionner.
Quelques exemples où les points rouges sont ceux générés initialement et les points affichés comme des turbines avec une limite sont le résultat final:
generate_wind_turbines(500)
generate_wind_turbines(1000)
la source