최소 경계 상자 알고리즘 변경


12

최소 경계 상자와 비슷한 알고리즘을 만들려고합니다. (아무것도 보이지 않을 수도 있습니다). 이 경우 각도는 매개 변수로 전달되며 각도가 주어지면 모든 점 / 다각형을 덮는 가장 작은 사각형이 필요합니다. 지금까지 내 생각의 선은 내 점의 중심 (중심 알고리즘)을 찾고 거기에서 매개 변수 각도와 동일한 각도로 두 개의 평행선을 만들고 두 개의 선을 수직으로 만듭니다. 그런 다음 반복을 사용하여 모든 점을 포함 할 때까지이 선을 반대 방향으로 바깥쪽으로 이동합니다. 또한 정확한 최소 경계 상자 일 필요는 없으며 대략적인 작업입니다 (각 반복 단계의 크기에 달려 있다고 생각합니다).

지금까지 내 코드는 다음과 같습니다. 이미 모든 다각형을 하나로 녹였습니다. 그런 다음 볼록 껍질을 잡고 정점을 줄입니다. 그런 다음 모든 정점을 목록에 넣습니다. 아직 도움이되는지 확실하지 않습니다 ...

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을 사용하고 있는데 이것을 파이썬으로 만들어야합니다. 레이어 'layer'에는 하나의 지오메트리가 있으며 다른 모든 폴리곤의 해체 된 폴리곤은 액세스 할 때 반복이 필요하지 않을 수 있습니다.

자세한 내용 / 정보를 전달해야하는지 알려주십시오.


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.