Hiển thị thay đổi của các dòng chồng chéo trong QGIS?


10

Khi các điểm bị chồng chéo, có thuộc tính này cho phép tự động hiển thị rất nhiều điểm riêng biệt xung quanh vị trí của chúng, được gọi là 'Chuyển vị điểm'. Nhưng nó không hoạt động đối với các dòng, thậm chí vì vậy nó có vẻ khả thi về mặt khái niệm để đạt được điều tương tự:

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

Tôi hoàn toàn cần phải xem các dòng khác nhau mà trong thực tế là tất cả ở cùng một nơi (tôi đang làm việc trong mạng viễn thông). Cách duy nhất tôi thấy bây giờ là thực sự tạo ra các đường khác nhau như trong hình trên, do đó tạo ra các lỗi không gian.

Tôi đang sử dụng QGIS 2.14.


Tôi nghĩ rằng một cái gì đó có thể được thực hiện định kỳ để tạo kiểu. Là dòng ở giữa dòng bắt đầu? Sau đó, tôi thấy rằng bạn đã tạo ra một trong các dòng khác bằng cách sử dụng ba hình học khác nhau, vì vậy câu hỏi của tôi là nếu có một số quy tắc bổ sung cụ thể từ kết xuất chúng?
mgri

@mgri Tôi không chắc chắn để hiểu câu hỏi của bạn. Bức tranh được cung cấp là một ví dụ trong đó tôi đã vẽ năm dòng khác nhau để trình diễn. Trong thực tế, sẽ có nhiều hơn là 5 dòng này thực sự nằm ở vị trí của đường giữa (chúng là dây, vì vậy tất cả bị mắc kẹt trong cùng một vỏ bọc).
GuiOm Clair

1
Bạn cũng có thể kết xuất các dòng có độ dịch chuyển ("offset"), nhưng chúng sẽ không gặp nhau ở điểm bắt đầu và điểm kết thúc.
AndreJ

@AndreJ Vâng, và một vấn đề khác là nó sẽ hoạt động khá thủ công, nơi tôi sẽ cần một cái gì đó tự động hơn vì nó sẽ được sử dụng bởi nhiều người dùng.
GuiOm Clair

1
@GuiOmClair Theo hình ảnh đính kèm, tôi giả sử rằng bạn bắt đầu từ một dòng trùng nhau (ví dụ) bốn dòng khác và bạn cần tìm cách hiển thị chúng một cách riêng biệt, ngay cả khi chúng trùng nhau. Tôi chỉ nói rằng có thể tái tạo những gì được hiển thị trong hình ảnh đính kèm mà không cần phải tạo hình học mới (nhưng chỉ định kỳ theo các thuộc tính kiểu của lớp bắt đầu). Một cách khác sẽ là cách mà AndreJ đề xuất, nhưng có vẻ như nó không phù hợp với nhu cầu của bạn.
mgri

Câu trả lời:


12

Tôi đề xuất một cách tiếp cận chỉ lặp lại với một trình tạo hình học và một hàm tùy chỉnh.

Trước khi bắt đầu, tôi muốn nhấn mạnh rằng tôi sẽ tập trung chú ý vào phần giải thích những điều tối thiểu cần làm để tái tạo kết quả mong muốn: điều này có nghĩa là một số thông số nhỏ khác (như kích thước, chiều rộng, v.v.) nên được điều chỉnh dễ dàng bởi bạn để phù hợp hơn với nhu cầu của bạn.

Do đó, giải pháp này hoạt động cho cả Hệ thống tham chiếu địa lý và dự kiến: sau đây, tôi giả sử sử dụng CRS dự kiến ​​(nghĩa là đơn vị đo là mét), nhưng bạn có thể thay đổi chúng theo CRS của mình.


Bối cảnh

Giả sử bắt đầu từ lớp vectơ linestring này đại diện cho các dây (nhãn đại diện cho số lượng dây chồng chéo (trùng khớp):

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


Giải pháp

Đầu tiên, đi đến Layer Properties | Stylevà sau đó chọn Single symboltrình kết xuất.

Từ Symbol selectorhộp thoại, chọn Geometry generatorkiểu lớp biểu tượng và Linestring / MultiLinestringkiểu hình học. Sau đó, nhấp vào Function Editortab:

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

Sau đó, bấm vào New filevà gõ draw_wiresnhư tên của chức năng mới:

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

Bạn sẽ thấy rằng một chức năng mới đã được tạo và nó được liệt kê ở phía bên trái của hộp thoại. Bây giờ, nhấp vào tên của hàm và thay thế mặc định @qgsfunctionbằng mã sau đây (đừng quên thêm tất cả các thư viện được đính kèm tại đây):

from qgis.core import *
from qgis.gui import *
from math import sin, cos, radians

@qgsfunction(args='auto', group='Custom')
def draw_wires(angle, percentage, curr_feat, layer_name, feature, parent):

    def wires(polyline, new_angle, percentage):
        for x in range(0, len(polyline)-1):
            vertices = []
            first_point = polyline[x]
            second_point = polyline[x +1]
            seg = QgsGeometry.fromPolyline([first_point, second_point])
            len_feat = seg.length()
            frac_len = percentage * len_feat
            limb = frac_len/cos(radians(new_angle))
            tmp_azim = first_point.azimuth(second_point)
            angle_1 = radians(90 - (tmp_azim+new_angle))
            dist_x, dist_y = (limb * cos(angle_1), limb * sin(angle_1))
            point_1 = QgsPoint(first_point[0] + dist_x, first_point[1] + dist_y)
            angle_2 = radians(90 - (tmp_azim-new_angle))
            dist_x, dist_y = (limb * cos(angle_2), limb * sin(angle_2))
            point_2 = QgsPoint(second_point[0] - dist_x, second_point[1] - dist_y)
            tmp_azim = second_point.azimuth(first_point)
            angle_3 = radians(90 - (tmp_azim+new_angle))
            dist_x, dist_y = (limb * cos(angle_3), limb * sin(angle_3))
            point_3 = QgsPoint(second_point[0] + dist_x, second_point[1] + dist_y)
            angle_4 = radians(90 - (tmp_azim-new_angle))
            dist_x, dist_y = (limb * cos(angle_4), limb * sin(angle_4))
            point_4 = QgsPoint(first_point[0] - dist_x, first_point[1] - dist_y)
            vertices.extend([first_point, point_1, point_2, second_point, point_3, point_4, first_point])
            tempGeom = QgsGeometry.fromPolyline(vertices)
            num.append(tempGeom)
        return num


    layer = QgsMapLayerRegistry.instance().mapLayersByName(layer_name)[0]

    all_feats = {}
    index = QgsSpatialIndex()
    for ft in layer.getFeatures():
        index.insertFeature(ft)
        all_feats[ft.id()] = ft

    first = True

    tmp_geom = curr_feat.geometry()
    polyline = tmp_geom.asPolyline()
    idsList = index.intersects(tmp_geom.boundingBox())
    occurrences = 0
    for id in idsList:
        test_feat = all_feats[id]
        test_geom = test_feat.geometry()
        if tmp_geom.equals(test_geom):
            occurrences += 1
    if occurrences & 0x1:
        num = [tmp_geom]
    else:
        num = []

    rapp = occurrences/2
    i=2
    new_angle = angle

    while i <= occurrences:
        draw=wires(polyline, new_angle, percentage)
        i += 2
        new_angle -= new_angle/rapp
    first = True
    for h in num:
        if first:
            geom = QgsGeometry(h)
            first = False
        else:
            geom = geom.combine(h)
    return geom

Một khi bạn đã làm điều này, bấm vào Loadnút và bạn sẽ có thể thấy chức năng từ CustomMenu của Expressionhộp thoại.

Bây giờ, nhập biểu thức này (xem hình ảnh dưới đây để tham khảo):

draw_wires(40, 0.3, $currentfeature, @layer_name)

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

Bạn vừa chạy một chức năng đang nói, theo một cách tưởng tượng:

"Đối với lớp hiện tại ( @layer_name ) và tính năng hiện tại ( $ currentfeature ), hiển thị các dây với nhau bằng cách mở tối đa ban đầu 40 độ và thay đổi hướng ở khoảng cách 0,3 lần chiều dài của đoạn hiện tại."

Điều duy nhất bạn cần thay đổi là giá trị của hai tham số đầu tiên mà bạn muốn, nhưng rõ ràng là theo cách hợp lý (để lại các tham số chức năng khác như được cung cấp).

Cuối cùng, bấm vào Applynút để áp dụng các thay đổi.

Bạn sẽ thấy một cái gì đó như thế này:

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

như mong đợi.


BIÊN TẬP

Theo một yêu cầu cụ thể được OP đưa ra trong một bình luận:

"Có thể chỉ tạo mẫu này giữa đầu và cuối của mỗi đa tuyến thay vì giữa mỗi đỉnh không?"

Tôi hơi chỉnh sửa mã. Hàm sau sẽ trả về kết quả mong đợi:

from qgis.core import *
from qgis.gui import *
from math import sin, cos, radians

@qgsfunction(args='auto', group='Custom')
def draw_wires(angle, percentage, curr_feat, layer_name, feature, parent):

    def wires(polyline, new_angle, percentage):
        vertices = []
        len_feat = polyline.length()
        frac_len = percentage * len_feat
        limb = frac_len/cos(radians(new_angle))
        tmp_azim = first_point.azimuth(second_point)
        angle_1 = radians(90 - (tmp_azim+new_angle))
        dist_x, dist_y = (limb * cos(angle_1), limb * sin(angle_1))
        point_1 = QgsPoint(first_point[0] + dist_x, first_point[1] + dist_y)
        angle_2 = radians(90 - (tmp_azim-new_angle))
        dist_x, dist_y = (limb * cos(angle_2), limb * sin(angle_2))
        point_2 = QgsPoint(second_point[0] - dist_x, second_point[1] - dist_y)
        tmp_azim = second_point.azimuth(first_point)
        angle_3 = radians(90 - (tmp_azim+new_angle))
        dist_x, dist_y = (limb * cos(angle_3), limb * sin(angle_3))
        point_3 = QgsPoint(second_point[0] + dist_x, second_point[1] + dist_y)
        angle_4 = radians(90 - (tmp_azim-new_angle))
        dist_x, dist_y = (limb * cos(angle_4), limb * sin(angle_4))
        point_4 = QgsPoint(first_point[0] - dist_x, first_point[1] - dist_y)
        vertices.extend([first_point, point_1, point_2, second_point, point_3, point_4, first_point])
        tempGeom = QgsGeometry.fromPolyline(vertices)
        num.append(tempGeom)

    layer = QgsMapLayerRegistry.instance().mapLayersByName(layer_name)[0]

    all_feats = {}
    index = QgsSpatialIndex()
    for ft in layer.getFeatures():
        index.insertFeature(ft)
        all_feats[ft.id()] = ft
    first = True
    tmp_geom = curr_feat.geometry()
    coords = tmp_geom.asMultiPolyline()
    if coords:
        new_coords = [QgsPoint(x, y) for x, y in z for z in coords]
    else:
        coords = tmp_geom.asPolyline()
        new_coords = [QgsPoint(x, y) for x, y in coords]
    first_point = new_coords[0]
    second_point = new_coords[-1]
    polyline=QgsGeometry.fromPolyline([first_point, second_point])
    idsList = index.intersects(tmp_geom.boundingBox())
    occurrences = 0
    for id in idsList:
        test_feat = all_feats[id]
        test_geom = test_feat.geometry()
        if tmp_geom.equals(test_geom):
            occurrences += 1
    if occurrences & 0x1:
        num = [polyline]
    else:
        num = []

    rapp = occurrences/2
    i=2
    new_angle = angle

    while i <= occurrences:
        draw=wires(polyline, new_angle, percentage)
        i += 2
        new_angle -= new_angle/rapp
    first = True
    for h in num:
        if first:
            geom = QgsGeometry(h)
            first = False
        else:
            geom = geom.combine(h)
    return geom

Ồ Đó là một câu trả lời ấn tượng! Cảm ơn bạn rất nhiều vì đã dành thời gian này để tìm và chia sẻ nó. Tuy nhiên: 1. Tôi gặp sự cố khi áp dụng nó vào dữ liệu của mình (khi tôi áp dụng chức năng, các dòng biến mất), nhưng tôi đoán vấn đề xuất phát từ dữ liệu của tôi vì nó hoạt động trên một lớp tạm thời và 2. có thể tạo được không mô hình này chỉ giữa điểm đầu và điểm cuối của mỗi đa tuyến thay vì giữa mỗi đỉnh?
GuiOm Clair

@GuiOmClair các dòng biến mất vì có vấn đề với chức năng. Vấn đề không xuất phát từ việc sử dụng lớp tạm thời, nhưng nó có thể liên quan đến việc sử dụng hình học MultiLine thay vì hình học Line. Vui lòng, tải lớp trong QGIS và sau đó nhập hai dòng này vào Bảng điều khiển Python: layer=iface.activeLayer()và sau đó print layer.wkbType(). Bấm Run: giá trị của số in là gì?
mgri

Số này là 5 (có nghĩa là gì?)
GuiOm Clair

@GuiOmClair Điều đó có nghĩa là lớp của bạn là lớp MultiLineString, trong khi tôi cho rằng đó là lớp LineString (vì bạn không chỉ định nó). Đây không phải là một vấn đề và tôi sẽ chỉnh sửa mã ngay khi có thể (có thể vào ngày mai). Hơn nữa, tôi chỉ có thể kết xuất các dây giữa điểm đầu tiên và điểm cuối của mỗi tính năng (nhiều) dòng.
mgri

1
Có, các tính năng là các đường thẳng (vì chúng thường dễ quản lý và xuất khẩu hơn), vì vậy sẽ tốt hơn nếu xem xét độ dài thực của dây.
CliOm Clair
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.