Menghasilkan poligon berdimensi konsisten dalam satuan mm?

11

Saya memiliki fungsi yang membuat panel Solar Photovolatic direpresentasikan sebagai poligon. Pada dasarnya, ini menciptakan kotak persegi panjang di mana pengguna dapat menentukan parameter berikut:

  • Panjangnya
  • Lebar
  • Jarak horizontal
  • Jarak vertikal

Kode ini didasarkan pada plugin FeatureGridCreator tetapi berfokus hanya pada aspek poligon. Ini berfungsi dengan baik untuk sebagian besar, terutama ketika membuat poligon dengan dimensi besar (misalnya panjang dan lebar 10m; jarak horizontal dan vertikal 10m).

Tapi saya perhatikan beberapa masalah:

  1. Saat menentukan poligon untuk dimensi kurang dari 2m untuk panjang dan lebar, tidak ada poligon yang dibuat.

  2. Saat menentukan poligon dengan dimensi berbeda (mis. Panjang 5 m dan lebar 7 m), dimensi tidak sama ketika diukur dengan alat Garis Ukur . Untuk dimensi ini, panjang dan lebar masing-masing ditampilkan 4m dan 6m.

    Contoh panjang dan lebar yang berbeda

CRS yang digunakan untuk proyeksi dan layer adalah EPSG: 27700 meskipun saya tidak akan berpikir ini akan menjadi masalah.

Jadi, adakah yang tahu apa yang menyebabkan masalah ini? Saya juga terbuka untuk saran bagaimana kode dapat ditingkatkan atau bahkan diganti dengan alternatif yang lebih baik.


Berikut adalah kode yang dapat direproduksi dalam Konsol Python , lapisan poligon harus dipilih dengan CRS yang relevan sebelum menjalankan fungsi:

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)
Yusuf
sumber

Jawaban:

11

Algoritme Anda masuk akal, tetapi tampaknya masalah Anda disebabkan oleh kesalahan pembulatan ketika Anda membaginya pada tahun 2000 (bagi dengan bilangan bulat, yang menjelaskan mengapa angka yang lebih kecil dari dua memberi 0, dan semua jarak dibulatkan ke nilai genap)

Anda harus mengubah divisi integer dengan divisi float

l = length / 2000

seharusnya

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

atau

l = float(length) / 2000

Perhatikan bahwa ini memberi Anda dimensi persis yang dimasukkan oleh formulir, tetapi Anda bisa memutuskan untuk membulatkan ukuran parsel Anda pada satu meter jika Anda lebih suka:

l = float(length/1000) / 2

Perhatikan bahwa Anda juga harus memeriksa pembulatan di koordinat awal, tapi saya tidak tahu apakah pembulatan ini disengaja.

start_x = bbox.xMinimum() + float(distance_x) / 2
radouxju
sumber
Saya pikir ini telah menyelesaikan masalah yang saya sebutkan (ironisnya, saya memperhatikan beberapa masalah baru yang terjadi tetapi saya pikir mereka telah diselesaikan). Akan terus menguji ini lebih lanjut dan melaporkan kembali. Terima kasih banyak :)
Joseph
Yup, saya yakin solusi Anda telah berhasil. Terima kasih lagi;)
Joseph
3

Berkat @radouxju , berikut adalah kode terakhir yang juga memperhitungkan jarak horizontal dan vertikal menjadi nol:

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))

  • Menggunakan generate_pv_panels(5500, 5000, 20, 1):

    skenario 1


  • Menggunakan generate_pv_panels(5500, 5000, 20, 0):

    Skenario 2

Yusuf
sumber