กำลังสร้างรูปหลายเหลี่ยมแบบสม่ำเสมอในหน่วยมิลลิเมตรหรือไม่


11

ฉันมีฟังก์ชั่นที่สร้างแผงเซลล์แสงอาทิตย์ Photovolatic ที่แสดงเป็นรูปหลายเหลี่ยม โดยพื้นฐานแล้วมันจะสร้างกริดสี่เหลี่ยมที่ผู้ใช้สามารถระบุพารามิเตอร์ต่อไปนี้:

  • ความยาว
  • ความกว้าง
  • ระยะทางแนวนอน
  • ระยะทางแนวตั้ง

รหัสนี้เป็นไปตามปลั๊กอินFeatureGridCreatorแต่เน้นเฉพาะในรูปหลายเหลี่ยม ใช้ได้ดีกับส่วนใหญ่โดยเฉพาะเมื่อสร้างรูปหลายเหลี่ยมที่มีขนาดใหญ่ (เช่นความยาวและความกว้าง 10 ม. ระยะทางแนวนอนและแนวตั้ง 10 ม.)

แต่ฉันสังเกตเห็นสองประเด็น:

  1. เมื่อระบุรูปหลายเหลี่ยมสำหรับขนาดที่น้อยกว่า 2 เมตรสำหรับทั้งความยาวและความกว้างจะไม่สร้างรูปหลายเหลี่ยม

  2. เมื่อระบุรูปหลายเหลี่ยมที่มีขนาดต่างกัน (เช่นความยาว 5 ม. และความกว้าง 7 ม.) ขนาดนั้นไม่เหมือนกันเมื่อวัดด้วยเครื่องมือวัดเส้น สำหรับมิติเหล่านี้ความยาวและความกว้างถูกแสดงเป็น 4m และ 6m ตามลำดับ

    ตัวอย่างความยาวและความกว้างต่างกัน

CRS ที่ใช้สำหรับการฉายภาพและเลเยอร์คือEPSG: 27700แม้ว่าฉันจะไม่คิดว่ามันจะเป็นปัญหา

ดังนั้นใครบ้างมีความคิดใด ๆ ที่อาจทำให้เกิดปัญหาเหล่านี้ ฉันยังเปิดให้คำแนะนำเกี่ยวกับวิธีการปรับปรุงรหัสหรือแทนที่ด้วยทางเลือกที่ดีกว่า


นี่คือรหัสที่สามารถทำซ้ำได้ในPython Consoleต้องเลือกเลเยอร์รูปหลายเหลี่ยมด้วย CRS ที่เกี่ยวข้องก่อนเรียกใช้ฟังก์ชัน:

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)

คำตอบ:


11

อัลกอริทึมของคุณสมเหตุสมผล แต่ดูเหมือนว่าปัญหาของคุณเกิดจากข้อผิดพลาดในการปัดเศษเมื่อคุณหารด้วย 2000 (หารด้วยจำนวนเต็มซึ่งอธิบายว่าทำไมตัวเลขที่เล็กกว่าสองให้ 0 เป็น 0 และระยะทางทั้งหมดจะถูกปัดเศษเป็นค่าคู่)

คุณควรเปลี่ยนการหารด้วยจำนวนเต็มลอย

l = length / 2000

ควรจะเป็น

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

หรือ

l = float(length) / 2000

โปรดทราบว่าสิ่งนี้จะให้ขนาดที่แน่นอนที่คุณป้อนโดยแบบฟอร์ม แต่คุณสามารถตัดสินใจที่จะปัดเศษขนาดของพัสดุของคุณที่หนึ่งเมตรหากคุณต้องการ:

l = float(length/1000) / 2

โปรดทราบว่าคุณควรตรวจสอบการปัดเศษที่พิกัดเริ่มต้นด้วย แต่ฉันไม่รู้ว่าการปัดเศษนี้มีจุดประสงค์หรือไม่

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

ฉันคิดว่าสิ่งนี้ได้แก้ไขปัญหาที่ฉันกล่าวถึง (อย่างแดกดันฉันสังเกตเห็นปัญหาใหม่ที่เกิดขึ้น แต่คิดว่าพวกเขาได้รับการแก้ไข) จะดำเนินการทดสอบนี้ต่อไปและรายงานกลับ ขอบคุณมาก :)
โจเซฟ

ใช่ฉันเชื่อว่าทางออกของคุณได้ผล ขอบคุณอีกครั้ง;)
โจเซฟ

3

ขอบคุณ@radouxjuนี่คือรหัสสุดท้ายที่คำนึงถึงระยะทางแนวนอนและแนวตั้งที่เป็นศูนย์ด้วย:

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

  • การใช้generate_pv_panels(5500, 5000, 20, 1):

    สถานการณ์ 1


  • การใช้generate_pv_panels(5500, 5000, 20, 0):

    สถานการณ์ที่ 2

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.