Eu tenho uma função que cria turbinas eólicas representadas como pontos. Essencialmente, ele usa o código dos pontos Aleatórios dentro da ferramenta polígonos (fixos) , embora com algumas pequenas alterações.
O objetivo é criar pontos aleatórios dentro dos polígonos, levando em consideração a distância mínima especificada. Isso funciona muito bem, especialmente com polígonos que não estão próximos de outro (por exemplo, um único polígono):
No entanto, se o polígono estiver próximo ou adjacente a outro polígono (por exemplo, como mostrado abaixo), os pontos de cada polígono podem estar dentro da distância mínima, como mostrado em vermelho:
Como eu poderia mudar o código para que esses pontos em vermelho não fiquem próximos de outros de um polígono próximo?
Idealmente, gostaria que vários pontos fossem substituídos por um único ponto:
Aqui está o código que pode ser reproduzido no Python Console , uma camada de polígono deve ser selecionada com um CRS relevante antes de executar a função:
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)
Editar:
Dissolver e / ou converter os polígonos em peças únicas não parece ajudar muito, pois os pontos gerados ainda parecem estar dentro da distância mínima.
Testado no QGIS 2.18.3 .
fonte
Respostas:
Você precisa mudar duas coisas para que isso funcione. No entanto, você não obterá o máximo de turbinas eólicas por área. Para isso, você precisaria executar algumas iterações para cada valor e obter a contagem máxima de pontos.
Mudei o
index = QgsSpatialIndex()
epoints = dict()
fora do loop for. O código ficaria assim:EDITAR:
Joseph estava certo. minhas alterações funcionaram apenas em uma área muito pequena. Eu testei e encontrei uma nova solução movendo duas variáveis para fora do loop for e alterei a
pointCount
variável.Eu testei com 500m e este é o resultado (duas tentativas diferentes):
fonte
Um método pode ser criar outra função que faça o seguinte:
Esta é a função que eu usei:
A função pode ser executada imediatamente no final da
generate_wind_turbines()
função usando:Isso fornece os resultados, como mostrado na imagem na pergunta. Provavelmente não é a mais eficiente das soluções, mas parece funcionar.
Alguns exemplos em que os pontos vermelhos são os gerados inicialmente e os pontos exibidos como turbinas com um limite são o resultado final:
generate_wind_turbines(500)
generate_wind_turbines(1000)
fonte