เลื่อนการแสดงบรรทัดที่ทับซ้อนกันใน QGIS หรือไม่


10

เมื่อจุดทับซ้อนกันมีคุณสมบัตินี้ที่อนุญาตให้แสดงล็อตของพวกเขาแยกกันโดยรอบโดยรอบที่พวกเขาเรียกว่า 'การกำจัดจุด' แต่มันใช้ไม่ได้กับบทละครดังนั้นสำหรับฉันแล้วมันค่อนข้างเป็นไปได้ในเชิงแนวคิดเพื่อให้บรรลุถึงสิ่งที่ต้องการ:

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

ฉันต้องการเห็นเส้นที่แตกต่างกันซึ่งในความเป็นจริงล้วนอยู่ในที่เดียวกัน (ฉันกำลังทำงานในเครือข่ายโทรคมนาคม) วิธีเดียวที่ฉันเห็นในตอนนี้คือการสร้างเส้นที่แตกต่างกันอย่างในภาพด้านบนดังนั้นจึงสร้างข้อผิดพลาดเชิงพื้นที่

ฉันใช้ QGIS 2.14


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

@ mgri ฉันไม่แน่ใจว่าจะเข้าใจคำถามของคุณหรือไม่ รูปภาพที่ให้ไว้เป็นตัวอย่างที่ฉันวาดห้าบรรทัดที่แตกต่างกันเพื่อการสาธิต ในความเป็นจริงมันจะยิ่งกว่าที่ 5 สายเหล่านี้ในความเป็นจริงแน่นอนในจุดที่อยู่ตรงกลาง (พวกเขาเป็นสายดังนั้นทั้งหมดติดอยู่ในฝักเดียวกัน)
GuiOm Clair

1
คุณสามารถเรนเดอร์บรรทัดด้วยการกำจัด ("ออฟเซ็ต") ได้เช่นกัน แต่จะไม่ตรงตามจุดเริ่มต้นและจุดสิ้นสุด
AndreJ

@ AndreJ ใช่แล้วและอีกปัญหาหนึ่งก็คือการใช้งานแบบแมนนวลซึ่งฉันต้องการบางสิ่งที่อัตโนมัติมากกว่าเนื่องจากผู้ใช้หลายคนใช้มัน
GuiOm Clair

1
@GuiOmClair ตามภาพที่แนบมาฉันคิดว่าคุณเริ่มจากหนึ่งบรรทัดที่ทับซ้อนกัน (ตัวอย่าง) สี่บรรทัดอื่น ๆ และคุณจำเป็นต้องหาวิธีในการแสดงแยกต่างหากแม้ว่าจะทับซ้อนกัน ฉันเพิ่งบอกว่ามันเป็นไปได้ที่จะทำซ้ำสิ่งที่แสดงในภาพที่แนบมาโดยไม่จำเป็นต้องสร้างรูปทรงเรขาคณิตใหม่ (แต่จะเกิดขึ้นกับคุณสมบัติสไตล์ของเลเยอร์เริ่มต้นเท่านั้น) จะเป็นอีกวิธีหนึ่งที่ AndreJ เสนอ แต่ดูเหมือนจะไม่เหมาะกับความต้องการของคุณ
mgri

คำตอบ:


12

ฉันเสนอวิธีการที่เกิดขึ้นเฉพาะกับเครื่องกำเนิดเรขาคณิตและฟังก์ชันที่กำหนดเอง

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

ดังนั้นวิธีแก้ปัญหานี้ใช้ได้ทั้งกับระบบอ้างอิงทางภูมิศาสตร์และที่คาดการณ์ไว้: ในสิ่งต่อไปนี้ฉันคาดว่าจะใช้ CRS ที่คาดการณ์ไว้ (เช่นหน่วยวัดเป็นเมตร) แต่คุณสามารถเปลี่ยนได้ตาม CRS ของคุณ


บริบท

สมมติว่าเริ่มจากเลเยอร์เวกเตอร์ที่เปล่งแสงแทนเส้นลวด (ฉลากแสดงจำนวนสายไฟที่ทับซ้อนกัน (บังเอิญ)):

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


สารละลาย

ขั้นแรกไปที่Layer Properties | Styleแล้วเลือกSingle symbolโหมดแสดงภาพ

จากSymbol selectorช่องโต้ตอบให้เลือกGeometry generatorประเภทเลเยอร์สัญลักษณ์และLinestring / MultiLinestringประเภทรูปทรงเรขาคณิต จากนั้นคลิกที่Function Editorแท็บ:

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

จากนั้นคลิกที่New fileและพิมพ์draw_wiresเป็นชื่อของฟังก์ชั่นใหม่:

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

คุณจะเห็นว่ามีการสร้างฟังก์ชั่นใหม่และมีรายการอยู่ทางด้านซ้ายของกล่องโต้ตอบ ตอนนี้คลิกที่ชื่อของฟังก์ชั่นและแทนที่ค่าเริ่มต้น@qgsfunctionด้วยรหัสต่อไปนี้ (อย่าลืมที่จะเพิ่มห้องสมุดทั้งหมดที่แนบมาที่นี่):

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

เมื่อคุณทำสิ่งนี้เสร็จแล้วให้คลิกที่Loadปุ่มและคุณจะสามารถเห็นฟังก์ชั่นจากCustomเมนูของExpressionกล่องโต้ตอบ

ตอนนี้ให้พิมพ์นิพจน์นี้ (ดูภาพด้านล่างเป็นการอ้างอิง):

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

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

คุณเพิ่งใช้งานฟังก์ชั่นที่กำลังพูดอยู่ในจินตนาการ:

"สำหรับเลเยอร์ปัจจุบัน ( @layer_name ) และฟีเจอร์ปัจจุบัน ( $ currentfeature ) แสดงสายเข้าด้วยกันโดยใช้การเปิดสูงสุดครั้งแรก 40 องศาและเปลี่ยนทิศทางในระยะ 0.3 เท่าของความยาวของเซกเมนต์ปัจจุบัน"

สิ่งเดียวที่คุณต้องเปลี่ยนคือค่าของสองพารามิเตอร์แรกตามที่คุณต้องการ แต่เห็นได้ชัดในวิธีที่เหมาะสม (ปล่อยพารามิเตอร์ฟังก์ชันอื่นตามที่ให้ไว้)

ในที่สุดคลิกที่Applyปุ่มเพื่อใช้การเปลี่ยนแปลง

คุณจะเห็นสิ่งนี้:

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

อย่างที่คาดไว้.


แก้ไข

ตามคำขอเฉพาะที่ยกขึ้นโดย OP ในความคิดเห็น:

"เป็นไปได้ไหมที่จะสร้างรูปแบบนี้เฉพาะระหว่างจุดเริ่มต้นและจุดสิ้นสุดของแต่ละรูปหลายเส้นแทนที่จะเป็นจุดกึ่งกลางแต่ละจุด?

ฉันแก้ไขรหัสเล็กน้อย ฟังก์ชันต่อไปนี้ควรส่งคืนผลลัพธ์ที่คาดหวัง:

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

ว้าว! นั่นเป็นคำตอบที่น่าประทับใจ! ขอบคุณมากที่สละเวลาเพื่อค้นหาและแบ่งปัน อย่างไรก็ตาม: 1. ฉันมีปัญหาในการใช้กับข้อมูลของฉัน (เมื่อฉันใช้ฟังก์ชั่น, เส้นหายไป) แต่ฉันเดาว่าปัญหามาจากข้อมูลของฉันเพราะมันทำงานบนเลเยอร์ชั่วคราวและ 2. มันจะเป็นไปได้ที่จะสร้าง รูปแบบนี้เฉพาะระหว่างจุดเริ่มต้นและจุดสิ้นสุดของแต่ละรูปหลายเส้นแทนที่จะเป็นระหว่างจุดยอดแต่ละจุด
GuiOm Clair

@GuiOmClair บรรทัดหายไปเพราะมีบางอย่างผิดปกติกับฟังก์ชัน ปัญหาไม่ได้มาจากการใช้เลเยอร์ชั่วคราว แต่อาจเกี่ยวข้องกับการใช้รูปทรงเรขาคณิตของ MultiLine แทนรูปทรงเรขาคณิตของเส้น โปรดโหลดชั้นใน QGIS แล้วพิมพ์ทั้งสองสายในคอนโซลหลาม: แล้วlayer=iface.activeLayer() print layer.wkbType()คลิกRun: ค่าใดของหมายเลขที่พิมพ์
mgri

จำนวนคือ 5 (หมายความว่าอย่างไร)
GuiOm Clair

@GuiOmClair หมายความว่าเลเยอร์ของคุณเป็นเลเยอร์ MultiLineString ในขณะที่ฉันถือว่าเป็นเลเยอร์ LineString (เนื่องจากคุณไม่ได้ระบุ) นี่จะไม่เป็นปัญหาและฉันจะแก้ไขรหัสให้ถูกต้องทันทีที่ฉันทำได้ นอกจากนี้ฉันควรจะสามารถแสดงสายได้เฉพาะระหว่างจุดแรกและจุดสุดท้ายของคุณลักษณะแต่ละบรรทัด (หลายจุด)
mgri

1
ใช่คุณสมบัติเป็นเส้นตรง (เนื่องจากโดยทั่วไปง่ายต่อการจัดการและส่งออก) ดังนั้นจะเป็นการดีกว่าหากพิจารณาความยาวของสายไฟจริง
GuiOm Clair
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.