อัลกอริธึมการเปลี่ยนแปลงขั้นต่ำของกล่องการเปลี่ยนแปลง


12

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

นี่คือรหัสของฉันจนถึงตอนนี้ ฉันได้ยุบรูปหลายเหลี่ยมทั้งหมดของฉันเป็นหนึ่งเดียว ฉันจะใช้เปลือกนูนเพื่อลดจุดยอด ฉันใส่จุดยอดทั้งหมดในรายการ - ไม่แน่ใจว่าจะช่วยได้หรือไม่

a = layer.getFeatures()
for feat in a:
    geom = feat.geometry()
a = geom.convexHull()
vertexId = QgsVertexId()
vertices = []
b = a.constGet().nextVertex(vertexId)
while b[0]:
    vertices.append(b[1])
    b = a.constGet().nextVertex(vertexId)

หมายเหตุ: ในบางจุดฉันจำเป็นต้องผ่านมุมของกล่อง ฉันใช้ QGIS 3 และจำเป็นต้องสร้างสิ่งนี้ใน Python เลเยอร์ 'เลเยอร์' มีหนึ่งเรขาคณิตรูปหลายเหลี่ยมที่ละลายของรูปหลายเหลี่ยมอื่น ๆ - อาจจะไม่จำเป็นต้องทำซ้ำเพื่อเข้าถึง ..

โปรดแจ้งให้เราทราบหากฉันจะส่งรายละเอียดเพิ่มเติม / ข้อมูล


3
นี่คืองานที่ตรงไปตรงมา หมุนจุดยอดของตัวเรือนูนโดยใช้สมการมาตรฐาน, stackoverflow.com/questions/20104611/…คำนวณ minX, minY เป็นต้นยกเลิกการสร้างและสร้างสี่เหลี่ยมผืนผ้า 4 คู่ xy
FelixIP

คำตอบ:


2

นี่คือรหัสที่สมบูรณ์ มันมีหลายบรรทัดมากเกินไป (มากกว่าที่ต้องการแน่นอน) แต่ใช้งานได้ ตอนนี้คุณสามารถทำความสะอาดได้ถ้าคุณชอบ

ในการกลับมาทำงานอัลกอริทึมคำนวณระยะทางสูงสุดระหว่างเส้นขนานที่มีความลาดชันที่กำหนดโดยพารามิเตอร์การหมุนและผ่านแม้ว่าจุด สำหรับแต่ละจุดจะมีการสร้างบรรทัด 'แนวนอน' และ 'แนวตั้ง' ชื่อนี้เป็นเพียงทิศทางตามที่กำหนดไว้ที่ตำแหน่ง 0 (การหมุน = 0) ดังนั้นสำหรับแต่ละจุดภายนอกจะมีการสร้าง 2 เส้นที่เป็นไปได้นี้จากนั้นซ้ำไปเรื่อย ๆ โพลิกอนจะถูกสร้างขึ้นโดยอิงจากภายนอก 4 ตัวหรือพูดอย่างอื่นโดยที่ระยะทางของเส้นคู่ขนานมีค่าสูงสุด

สิ่งหนึ่งที่สุดท้าย: มันถูกนำมาใช้ใน QGIS 3.8 กับหญ้า

ป้อนคำอธิบายรูปภาพที่นี่

from PyQt5.QtCore import *
from qgis.core import *
from qgis.gui import *
from processing.tools import *
from qgis.utils import iface
import qgis.utils, os, glob, processing, string, time, shutil, ogr

#PARAMETERS AND LAYERS
rotation = 45 #use any value between 0 and <90 #90 would make a mess

layer1 = iface.activeLayer() # Load the layer (from active)
crs = layer1.crs().authid() #get crs

#----------------------------------------------------------------------------------------
#LINE EQUATIONS
''' 
BASIC LINE EQUATIONS
y = ax + b
a = (y2 - y1) / (x2 - x1)
b = y1 - a * x1
Distance = (| a*x1 + b*y1 + c |) / (sqrt( a*a + b*b))# Function to find straight distance betweeen line and point 
'''
# slope from angle
def sfa (a):
    return round(math.tan(math.radians(a)),12) #round to avoid problems with horizontal and vertical

# angle from slope (not used)
def afs (s):
    return (math.atan(s) / math.pi) * 180

# Function to find distance 
def shortest_distance(x1, y1, a, b, c):    
    d = round(abs((a * x1 + b * y1 + c)) / (math.sqrt(a * a + b * b)) , 12)
    return d

# Function to find interception between lines
def cross(a1,b1,a2,b2):
    x = (b2-b1) / (a1-a2)
    y = a1 * x + b1
    return (x,y)

#----------------------------------------------------------------------------------------
# GET LIST OF POINTS TO ITERATE
# Calculate convexhull to reduce the iterations between point
# This avoid calculations on 'internal' points
# process of minimum bounding geometry convexHull
MBG = processing.run("qgis:minimumboundinggeometry", {'INPUT': layer1,'FIELD':None,'TYPE':3,'OUTPUT':'TEMPORARY_OUTPUT'})

# Get vertex of MBG
MBGp = processing.run("native:extractvertices", {'INPUT':MBG['OUTPUT'],'OUTPUT':'TEMPORARY_OUTPUT'})

plist = list(MBGp['OUTPUT'].getFeatures())

lp = list()
for p in plist:
    geom = p.geometry()
    a = geom.asPoint()
    point = (a[0],a[1])
    lp.append(point)

#----------------------------------------------------------------------------------------
# PROCESS
# compare hdist and v dist betweeen each pair of point and get the most distant lines
hdist_max = 0
vdist_max = 0
index = list(range(0,len(lp))) #iteration index
bl = ['ah1','bh1','av1','bv1','ah2','bh2','av2','bv2'] #polygon lines defined by 8 parameters see below

for i in index[:-1]:
    print('i'+str(i))
    for t in index[i+1:]:
        print('t'+str(t))

        x1 = lp[i][0] #; print('x1: {}', x1)
        y1 = lp[i][1] #; print('y1: {}', y1)
        x2 = lp[t][0] #; print('x2: {}', x2)
        y2 = lp[t][1] #; print('y2: {}', y2)

        #h1 equation
        ah1 = sfa(rotation)
        bh1 = y1 - ah1 * x1

        #v1 equation
        av1 = sfa(rotation + 90) #remember that just the horizontal is the reference at 0 rotation
        bv1 = y1 - av1 * x1 

        #h2 equation
        ah2 = sfa(rotation)
        bh2 = y2 - ah2 * x2

        #v2 equation
        av2 = sfa(rotation + 90) #remember that just the horizontal is the reference
        bv2 = y2 - av2 * x2 

        # H dist
        hdist = shortest_distance(x1, y1, ah2, -1, bh2)
        vdist = shortest_distance(x1, y1, av2, -1, bv2)

        if hdist > hdist_max:
            bl[0] = ah1
            bl[1] = bh1
            bl[4] = ah2
            bl[5] = bh2
            hdist_max = hdist #update max hdist
        if vdist > vdist_max:
            bl[2] = av1
            bl[3] = bv1
            bl[6] = av2
            bl[7] = bv2
            vdist_max = vdist #update max vdist

print("Max perpendicular distance betweeen 'horizontal lines' is",hdist_max, ' m')
print("Max perpendicular distance betweeen 'verticallines' is",vdist_max, ' m')

#------------------------------------------------------------------------------------------
# GET 4 COORDS FROM BOUNDINGLINES bl
# using the slope and intercept from boundinglines can we now calculate the 4 corners of the rotated polygon
H1V1 = cross(bl[0],bl[1],bl[2],bl[3]) # H1V1
H1V2 = cross(bl[0],bl[1],bl[6],bl[7]) # H1V2
H2V1 = cross(bl[4],bl[5],bl[2],bl[3]) # H2V1
H2V2 = cross(bl[4],bl[5],bl[6],bl[7]) # H2V2

# SORT POINTS CLOCKWISE AND CREATE QgsPointXY for polygon
clist = [H1V1,H1V2,H2V1,H2V2]
points=[]
points.append(sorted(clist, key=lambda e: (e[1], e[0]))[0]); clist.remove(points[0]) #minX and minY
points.append(sorted(clist, key=lambda e: (e[0], e[1]))[0]); clist.remove(points[1]) #minY and minX
points.append(sorted(clist, key=lambda e: (e[1]), reverse=True)[0]); clist.remove(points[2]) #maxY
points.append(clist[0]) #remaining
p=[]
for i in points:
    p.append(QgsPointXY(i[0],i[1]))
print('Coords of the polygon: ',p)

#------------------------------------------------------------------------------------------
#CREATE ROTATED BOUNDING BOX FROM THESE POINTS
layer = QgsVectorLayer(str('Polygon?crs='+crs), 'polygon' , 'memory')
prov = layer.dataProvider()
feat = QgsFeature()
feat.setGeometry(QgsGeometry.fromPolygonXY([p]))
prov.addFeatures([feat])
layer.updateExtents()
QgsProject.instance().addMapLayers([layer])
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.