Thuật toán giới hạn hộp tối thiểu thay đổi


12

Tôi đang cố gắng tạo ra một thuật toán tương tự như hộp giới hạn tối thiểu (mặc dù nó có thể trông không giống như nó). Trong trường hợp này, góc sẽ được truyền dưới dạng tham số và được cho góc tôi cần hình chữ nhật nhỏ nhất bao gồm tất cả các điểm / đa giác của tôi. Cho đến nay, dòng suy nghĩ của tôi là tìm trung tâm các điểm của tôi (thuật toán centroid) và từ đó tạo ra hai đường thẳng song song có cùng góc với góc paramter và hai đường thẳng vuông góc với chúng. Sau đó, sử dụng phép lặp di chuyển các dòng này ra ngoài (theo hướng ngược lại) cho đến khi chúng chứa tất cả các điểm. Cũng không phải là hộp giới hạn tối thiểu chính xác, các tác phẩm gần đúng (tôi đoán sẽ phụ thuộc vào kích thước của mỗi bước lặp).

Đây là mã của tôi cho đến nay. Tôi đã hòa tan tất cả các đa giác của tôi thành một. Sau đó tôi lấy một thân tàu lồi để giảm các đỉnh. Sau đó tôi đặt tất cả các đỉnh trong một danh sách - không chắc điều này có giúp được không ...

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)

Ghi chú: Tại một số điểm tôi cần phải vượt qua góc của hộp. Tôi đang sử dụng QGIS 3 và cần tạo cái này bằng Python. Lớp 'lớp' có một hình học, đa giác hòa tan của tất cả các đa giác khác - có thể không cần lặp lại để truy cập vào nó ..

Xin vui lòng cho tôi biết nếu tôi nên chuyển thêm chi tiết / thông tin.


3
Đây là nhiệm vụ thẳng về phía trước. Xoay các đỉnh của thân lồi bằng các phương trình tiêu chuẩn, stackoverflow.com/questions/20104611/ Cáp Tính toán minX, minY, v.v. Hủy bỏ và tạo hình chữ nhật gồm 4 cặp xy.
FelixIP

Câu trả lời:


2

Đây là mã hoàn chỉnh. Nó chứa quá nhiều dòng (chắc chắn nhiều hơn mức cần thiết) nhưng nó hoạt động. Bây giờ bạn có thể làm sạch nó nếu bạn muốn.

Trong sơ yếu lý lịch, thuật toán tính toán các đường song song betweeen khoảng cách tối đa có độ dốc được xác định bởi tham số xoay và vượt qua các điểm. Đối với mỗi điểm sẽ được tạo một đường 'ngang' và 'dọc'. Tên này chỉ mang tính định hướng vì chúng được xác định tại vị trí 0 (rotation = 0). Vì vậy, đối với mỗi điểm bên ngoài sẽ được tạo 2 đường thẳng rõ ràng này và sau đó, lặp lại, poligon sẽ được tạo dựa trên 4 điểm bên ngoài, hoặc nói theo cách khác, trong đó khoảng cách của các đường song song là tối đa.

Một điều cuối cùng: nó được tạo ra để sử dụng trong QGIS 3.8 với cỏ.

nhập mô tả hình ảnh ở đây

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])
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.