12 votos

¿Generación de polígonos siempre acotado en unidades de mm?

Tengo una función que crea Solar Photovolatic paneles representado como los polígonos. En esencia, se crea una cuadrícula rectangular donde el usuario puede especificar el siguientes parámetros:

  • Longitud
  • Ancho
  • Distancia Horizontal
  • Distancia Vertical

El código está basado en el plugin FeatureGridCreator pero centrándose únicamente en el polígono de aspecto. Funciona bien para la mayoría, especialmente a la hora de crear polígonos con grandes dimensiones (por ejemplo, 10 m de longitud y anchura; 10m distancias horizontal y vertical).

Pero me di cuenta un par de cuestiones:

  1. Cuando la especificación de los polígonos para las dimensiones de menos de 2m de longitud y anchura, no de los polígonos que fueron creados.

  2. Cuando la especificación de los polígonos con diferentes dimensiones (por ejemplo, de 5m de longitud y 7 metros de ancho), las dimensiones no eran los mismos cuando se mide con la Medida de la Línea de la herramienta. Para estas dimensiones, la longitud y la anchura se muestra para ser 4m y 6m respectivamente.

    Example of differing length and width

El CRS utiliza tanto para la proyección y la capa es EPSG:27700 aunque yo no hubiera pensado que esto sería un problema.

Así que ¿alguien tiene alguna idea de lo que podría ser la causa de estos problemas? También estoy abierto a sugerencias en cuanto a cómo el código podría ser mejorado o incluso sustituido con una mejor alternativa.


Aquí está el código que se puede reproducir en la Consola de Python, una capa de polígono debe ser seleccionado con un relevante CRS antes de ejecutar la función:

from PyQt4.QtCore import QVariant
from math import ceil

def generate_pv_panels(length, width, distance_x, distance_y):
    # Define layer properties
    layer = iface.activeLayer()
    crs = layer.crs()
    memory_lyr = QgsVectorLayer("Polygon?crs=epsg:" + unicode(crs.postgisSrid()) + "&index=yes", "PV panels for " + str(layer.name()), "memory")
    QgsMapLayerRegistry.instance().addMapLayer(memory_lyr)
    memory_lyr.startEditing()
    provider = memory_lyr.dataProvider()
    provider.addAttributes([QgsField("ID", QVariant.Int)])
    fid = 0
    start_x = 0
    start_y = 0
    # Ensure polygons are not created 'within each other'
    if distance_x < (length / 1000):
        distance_x = (length / 1000)
    if distance_y < (width / 1000):
        distance_y = (width / 1000)
    fts = []
    for f in layer.getFeatures():
        fid += 1
        bbox = f.geometry().boundingBox()
        start_x = bbox.xMinimum() + float(distance_x / 2)
        start_y = bbox.yMinimum() + float(distance_y / 2)
        for row in range(0, int(ceil(bbox.height() / distance_y))):
            for column in range(0, int(ceil(bbox.width() / distance_x))):
                fet = QgsFeature()
                geom_type = pv_panel_size(length, width, start_x, start_y)
                if f.geometry().contains(geom_type):
                    fet.setGeometry(geom_type)
                    fet.setAttributes([fid])
                    fts.append(fet)
                start_x += distance_x + (length / 1000)
            start_x = bbox.xMinimum() + float(distance_x / 2)
            start_y += distance_y + (width / 1000)
    provider.addFeatures(fts)
    memory_lyr.updateFields()
    memory_lyr.commitChanges()

def pv_panel_size(length, width, x, y):
    # Length & width measured in mm; x & y measured in m
    l = length / 2000
    w = width / 2000
    return QgsGeometry.fromRect(QgsRectangle(x - l, y - w, x + l, y + w))

generate_pv_panels(10000, 10000, 100, 100)

11voto

xenny Puntos 670

Su algoritmo tiene sentido, pero parece que tu problema es debido a un error de redondeo cuando se divide por el año 2000 (dividir por entero, lo que explica por qué un número menor que dos da 0, y las distancias son redondeadas incluso valores)

Usted debe cambiar la división de enteros con un flotador de la división de

l = length / 2000

debe ser

l = length / 2000. # the . makes sure that you divide by a decimal value

o

l = float(length) / 2000

Tenga en cuenta que esto le da a usted las dimensiones exactas entró por la forma, pero usted puede decidir ronda el tamaño de sus parcelas a un metro si se prefiere:

l = float(length/1000) / 2

Tenga en cuenta que usted debe también comprobar el redondeo al inicio de las coordenadas, pero no sé si este redondeo es a propósito.

start_x = bbox.xMinimum() + float(distance_x) / 2

3voto

Mue Puntos 2469

Gracias a @radouxju, aquí está el código final que también tiene en cuenta las distancias horizontal y vertical es cero:

from PyQt4.QtCore import QVariant
from math import ceil

def generate_pv_panels(length, width, distance_x, distance_y):
    # Define layer properties
    layer = iface.activeLayer()
    crs = layer.crs()
    memory_lyr = QgsVectorLayer("Polygon?crs=epsg:" + unicode(crs.postgisSrid()) + "&index=yes", "PV panels for " + str(layer.name()), "memory")
    QgsMapLayerRegistry.instance().addMapLayer(memory_lyr)
    memory_lyr.startEditing()
    provider = memory_lyr.dataProvider()
    provider.addAttributes([QgsField("ID", QVariant.Int)])
    # Define variables
    fid = 0
    start_x = 0
    start_y = 0
    state_x = False
    state_y = False
    # Ensure polygons are not created 'within each other' if distance is zero;
    # Instead they will align on the bounding box
    if distance_x == 0:
        distance_x = (length / 1000)
        state_x = True
    if distance_y == 0:
        distance_y = (width / 1000)
        state_y = True
    fts = []
    for f in layer.getFeatures():
        fid += 1
        bbox = f.geometry().boundingBox()
        start_x = bbox.xMinimum() + float(distance_x / 2)
        start_y = bbox.yMinimum() + float(distance_y / 2)
        for row in range(0, int(ceil(bbox.height() / distance_y))):
            for column in range(0, int(ceil(bbox.width() / distance_x))):
                fet = QgsFeature()
                geom_type = pv_panel_size(length, width, start_x, start_y)
                if f.geometry().contains(geom_type):
                    fet.setGeometry(geom_type)
                    fet.setAttributes([fid])
                    fts.append(fet)
                if state_x == False:
                    start_x += distance_x + (length / 1000)
                else:
                    start_x += distance_x
            start_x = bbox.xMinimum() + float(distance_x / 2)
            if state_y == False:
                start_y += distance_y + (width / 1000)
            else:
                start_y += distance_y
    provider.addFeatures(fts)
    memory_lyr.updateFields()
    memory_lyr.commitChanges()

def pv_panel_size(length, width, x, y):
    # Length & width measured in mm; x & y measured in m
    l = float(length) / 2000
    w = float(width) / 2000
    return QgsGeometry.fromRect(QgsRectangle(x - l, y - w, x + l, y + w))

  • El uso de generate_pv_panels(5500, 5000, 20, 1):

    Scenario 1


  • El uso de generate_pv_panels(5500, 5000, 20, 0):

    Scenario 2

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X