Minimum Sınırlayıcı Kutu Algoritmasını Değiştirin


12

Minimum sınırlama kutusuna benzer bir algoritma oluşturmaya çalışıyorum (yine de böyle bir şey arıyor olabilir). Bu durumda açı bir parametre olarak geçirilecek ve açı verildiğinde tüm noktalarımı / poligonları kapsayan en küçük dikdörtgene ihtiyacım var. Şimdiye kadar benim düşüncem, noktalarımın merkezini (centroid algoritması) bulmak ve oradan parametre açısı ile aynı açıya sahip iki paralel çizgi ve onlara dik iki çizgi daha oluşturmaktır. Daha sonra yinelemeyi kullanarak bu çizgileri tüm noktaları içerene kadar dışarıya (zıt yönlerde) hareket ettirin. Ayrıca kesin minimum sınırlayıcı kutu olması gerekmez, yaklaşık çalışır (her yineleme adımının boyutuna bağlı olacağını düşünüyorum).

İşte benim kodum şu ana kadar. Tüm çokgenlerimi bir tanesine çözdüm. Daha sonra köşeleri azaltmak için dışbükey bir gövde alıyorum. Daha sonra tüm köşeleri bir listeye koydum - bunun henüz yardımcı olup olmadığından emin değilim ...

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)

Notlar: Bir noktada kutunun açısını geçmem gerekiyor. QGIS 3 kullanıyorum ve bunu Python'da yaratmam gerekiyor. Katman 'katman' bir geometriye, diğer tüm çokgenlerin çözünmüş poligonuna sahiptir - belki ona erişmek için yineleme gerekmez.

Daha fazla bilgi / bilgi iletmem gerekiyorsa lütfen bize bildirin.


3
Bu basit bir iştir. Dışbükey gövdenin köşelerini standart denklemler, stackoverflow.com/questions/20104611/… kullanarak döndürün MinX, minY vb. Hesaplayın. 4 xy çiftli dikdörtgeni açın ve oluşturun.
FelixIP

Yanıtlar:


2

İşte tam kod. Çok fazla satır içeriyor (gerekenden çok daha fazla) ama işe yarıyor. Şimdi isterseniz temizleyebilirsiniz.

Özgeçmişte algoritma, döndürme parametresi tarafından tanımlanan eğime sahip olan ve noktalar üzerinden geçen paralel çizgiler arasındaki maksimum mesafeyi hesaplar. Her nokta için bir 'yatay' ve 'dikey' çizgi oluşturulacaktır. Bu adlar 0 konumunda tanımlandıkları için yalnızca yönlendiricidir (döndürme = 0). Böylece, her bir dış nokta için bu 2 olası çizgi oluşturulacak ve daha sonra, yinelemeli olarak, poligon 4 dışa dayalı olarak oluşturulacak veya başka bir şekilde, paralel çizgilerin mesafesinin maksimum olduğu söylenecektir.

Son bir şey: QGIS 3.8'de çim ile kullanılmak üzere üretilmiştir.

resim açıklamasını buraya girin

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])
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.