QGIS'de çakışan çizgilerin gösterimi kaydırılıyor mu?


10

Noktalar üst üste bindiğinde, 'Nokta yer değiştirme' adı verilen bir çok parçayı bulundukları yerde otomatik olarak ayrı ayrı görüntülemeye izin veren bu özellik vardır. Ancak çizgiler için işe yaramaz, bu yüzden bana böyle bir şey elde etmek için oldukça kavramsal olarak uygulanabilir gibi görünüyor:

resim açıklamasını buraya girin

Gerçekte hepsi aynı yerde olan farklı hatları görmem gerek (Telekomünikasyon ağında çalışıyorum). Şimdilik gördüğüm tek yol yukarıdaki resimde olduğu gibi gerçekten farklı çizgiler oluşturmak, böylece mekansal hatalar yaratmak.

QGIS 2.14 kullanıyorum.


Sanırım stil için tekrar eden bir şey yapılabilir. Ortadaki çizgi başlangıç ​​çizgisi mi? Sonra, diğer çizgilerin her birini üç farklı geometri kullanarak oluşturduğunuzu görüyorum, bu yüzden sorum şu, bunları oluştururken bazı ek kurallar olup olmadığı?
mgri

@mgri Sorunuzu anladığımdan emin değilim. Sağlanan resim, gösteri uğruna beş farklı çizgi çizdiğim bir örnektir. Gerçekte, bu 5 çizginin aslında orta olanın yerinde olması daha fazla olurdu (teller, bu yüzden hepsi aynı kılıfta sıkışmış).
GuiOm Clair

1
Yer değiştirme ("ofset") içeren satırlar da oluşturabilirsiniz, ancak başlangıç ​​ve bitiş noktalarında toplanmazlar.
AndreJ

@AndreJ Evet ve başka bir sorun, birçok kullanıcı tarafından kullanılacağı için daha otomatik bir şeye ihtiyaç duyacağım oldukça manuel bir işlem olacaktır.
GuiOm Clair

1
@GuiOmClair Ekli görüntüyü takiben, diğer dört satırla çakışan bir satırdan başladığınızı ve örneğin üst üste gelseler bile bunları ayrı ayrı görüntülemek için bir yol bulmanız gerektiğini varsaydım. Sadece yeni geometriler yaratmaya gerek kalmadan ekli görüntüde görüntülenen şeyleri çoğaltmanın mümkün olabileceğini söyledim (ancak sadece başlangıç ​​katmanının stil özelliklerine tekrarlanan). Başka bir yol AndreJ tarafından önerilen yol olabilir, ancak görünüşe göre ihtiyaçlarınıza uymuyor.
mgri

Yanıtlar:


12

Sadece bir geometri üreticisine ve özel bir işleve benzeyen bir yaklaşım öneriyorum.

Başlamadan önce, istenen sonucu yeniden üretmek için yapılacak minimum şeylerin açıklamasına dikkat çekeceğimin altını çizmek istiyorum: bu, bazı diğer küçük parametrelerin (boyutlar, genişlikler vb.) Sizin tarafınızdan kolayca ayarlanması gerektiği anlamına gelir. ihtiyaçlarınızı daha iyi karşılamak için.

Bu nedenle, bu çözüm hem Coğrafi hem de Öngörülen Referans Sistemleri için çalışır: aşağıda, yansıtılan bir CRS (yani ölçüm birimleri metredir) kullandığımı varsaydım, ancak bunları CRS'nize göre değiştirebilirsiniz.


bağlam

Kabloları temsil eden bu linestring vektör katmanından başlayalım (etiketler çakışan (çakışan) tellerin sayısını temsil eder):

resim açıklamasını buraya girin


Çözüm

İlk olarak, oluşturucuyu Layer Properties | Styleseçin ve ardından seçin Single symbol.

Gönderen Symbol selectordiyalog, bir seçim Geometry generatorsembol katman türü olarak ve Linestring / MultiLinestringgeometri türü olarak. Ardından, Function Editorsekmeyi tıklayın:

resim açıklamasını buraya girin

Ardından tıklayın New fileve draw_wiresyeni işlevin adı olarak yazın:

resim açıklamasını buraya girin

Yeni bir işlevin oluşturulduğunu ve iletişim kutusunun sol tarafında listelendiğini göreceksiniz. Şimdi, işlevin adını tıklayın ve varsayılanı @qgsfunctionaşağıdaki kodla değiştirin (buraya eklenen tüm kitaplıkları eklemeyi unutmayın):

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

Bunu yaptıktan sonra, Loaddüğmeye tıklayın , işlevi iletişim kutusunun CustomMenüsünden görebileceksiniz Expression.

Şimdi bu ifadeyi yazın (aşağıdaki resme referans olarak bakın):

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

resim açıklamasını buraya girin

Sadece hayali bir şekilde söyleyen bir işlevi çalıştırdınız:

"Geçerli katman ( @layer_name ) ve geçerli özellik ( $ currentfeature ) için, 40 derecelik bir başlangıç ​​maksimum açıklığı kullanarak ve geçerli segmentin uzunluğunun 0,3 katı mesafede bir yön değişikliği ile kabloları birlikte görüntüleyin."

Değiştirmeniz gereken tek şey, ilk iki parametrenin değerini istediğiniz gibi, ancak açıkça makul bir şekilde (diğer işlev parametrelerini sağlandığı gibi bırakın).

Son olarak, Applydeğişiklikleri uygulamak için düğmeye tıklayın.

Bunun gibi bir şey göreceksiniz:

resim açıklamasını buraya girin

beklenildiği gibi.


DÜZENLE

OP tarafından bir yorumda dile getirilen belirli bir talebe göre:

"Bu kalıbı, her köşe noktası yerine her bir çoklu çizginin başlangıcı ve bitişi arasında oluşturmak mümkün müdür?"

Kodu biraz düzenledim. Aşağıdaki işlev beklenen sonucu döndürmelidir:

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

Vaov! Bu etkileyici bir cevap! Bu zamanı bulup paylaşmak için zaman ayırdığınız için çok teşekkür ederiz. Ancak: 1. Verilerimi uygulamada sorun yaşıyorum (işlevi uyguladığımda, satırlar kayboluyor), ancak sanırım sorun geçici bir katman üzerinde çalıştığından verilerimden geliyor ve 2. oluşturmak mümkün mü bu patern her köşe çizgisi yerine her bir çoklu çizginin başlangıcı ve bitişi arasında mıdır?
GuiOm Clair

@GuiOmClair çizgiler kaybolur, çünkü fonksiyonda bir şeyler ters gider. Sorun geçici katman kullanımından kaynaklanmıyor, ancak Çizgi geometrileri yerine MultiLine geometrilerinin kullanılmasıyla ilgili olabilir. Lütfen katmanı QGIS'e yükleyin ve sonra bu iki satırı Python Konsoluna yazın: layer=iface.activeLayer()ve sonra print layer.wkbType(). Tıklama Run: yazdırılan sayının değeri nedir?
mgri

Sayı
5'tir

@GuiOmClair Tablonuzun bir MultiLineString katmanı olduğu anlamına gelir, bununla birlikte bir LineString katmanı olduğunu varsaydım (siz belirtmediğiniz için). Bu bir sorun olmaz ve en kısa zamanda (belki yarın) kodu düzgün bir şekilde düzenleyeceğim. Ayrıca, kabloları yalnızca (çoklu) her özelliğin ilk ve son noktası arasında oluşturabilmeliyim.
mgri

1
Evet, özellikler düz çizgilerdir (genellikle yönetilmesi ve dışa aktarılması daha kolay olduğundan), bu nedenle tellerin gerçek uzunluğu göz önüne alındığında daha iyi olur.
GuiOm Clair
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.