일관된 차원의 다각형을 mm 단위로 생성 하시겠습니까?


11

다각형으로 표시된 Solar Photovolatic 패널을 만드는 기능이 있습니다. 기본적으로 사용자가 다음 매개 변수를 지정할 수있는 사각형 격자를 만듭니다.

  • 길이
  • 수평 거리
  • 수직 거리

이 코드는 FeatureGridCreator 플러그인을 기반으로 하지만 다각형 측면에만 초점을 맞 춥니 다. 특히 큰 치수 (예 : 10m 길이 및 너비, 10m 수평 및 수직 거리)의 다각형을 만들 때 가장 효과적입니다.

그러나 나는 몇 가지 문제를 발견했다.

  1. 길이와 너비 모두 2m 미만의 치수에 다각형을 지정하면 다각형이 만들어지지 않습니다.

  2. 치수가 다른 다각형 (예 : 5m 길이 및 7m 너비)을 지정할 때 치수 측정 도구로 측정 할 때 치수가 동일하지 않았습니다 . 이들 치수에 대하여, 길이 및 폭은 각각 4m 및 6m 인 것으로 나타났다.

    길이와 너비가 다른 예

투영과 레이어에 모두 사용되는 CRS는 EPSG : 27700 이지만 이것이 문제가 될 것이라고 생각하지는 않았습니다.

그렇다면이 문제를 일으키는 원인이 무엇인지 아는 사람이 있습니까? 또한 코드를 개선하거나 더 나은 대안으로 대체 할 수있는 방법에 대한 제안에도 열려 있습니다.


다음은 Python 콘솔 에서 재생할 수있는 코드입니다 . 함수를 실행하기 전에 관련 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으로 나눌 때 반올림 오류로 인한 것 같습니다 (정수로 나눕니다. 이는 2보다 작은 숫자가 0을 제공하는 이유를 설명하고 모든 거리는 짝수 값으로 반올림됩니다)

float 나누기를 사용하여 정수 나누기를 변경해야합니다

l = length / 2000

해야한다

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

또는

l = float(length) / 2000

이는 양식에 의해 입력 된 정확한 치수를 제공하지만 원하는 경우 소포 크기를 1 미터로 반올림 할 수 있습니다.

l = float(length/1000) / 2

시작 좌표에서 반올림도 확인해야하지만이 반올림이 의도적인지 여부는 알 수 없습니다.

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

나는 이것이 내가 언급 한 문제를 해결했다고 생각한다 (아이 론적으로 새로운 문제가 발생하는 것을 보았지만 해결되었다고 생각한다). 이것을 계속 테스트하고 다시보고합니다. 많은 감사 :)
조셉

네, 귀하의 솔루션이 효과가 있다고 생각합니다. 다시 감사합니다;)
요셉

3

@radouxju 덕분에 다음은 수평 및 수직 거리가 0임을 고려한 최종 코드입니다.

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.