QGISで重複する線の表示をシフトしますか?


10

ポイントが重複している場合、「ポイントの変位」と呼ばれる、ポイントの周囲にそれらの多くを自動的に個別に表示できるようにするこのプロパティがあります。しかし、それはラインでは機能しません、それでも私はそのようなことを達成するためにかなり概念的に実現可能であるように見えます:

ここに画像の説明を入力してください

実際にはすべて同じ場所にあるさまざまな回線を確認する必要があります(私は通信ネットワークで作業しています)。現時点で私が見る唯一の方法は、上の図のように実際に異なる線を作成することであり、それにより空間的な間違いを引き起こします。

QGIS 2.14を使用しています。


スタイリングを繰り返して何かができると思います。真ん中のラインがスタートライン?次に、3つの異なるジオメトリを使用して他のラインをそれぞれ作成したことがわかりました。そのため、それらをレンダリングするための特定の追加ルールがあるかどうかを質問します。
mgri 2017年

@mgri私はあなたの質問を理解するのが確かではありません。写真は実演のために5本の線を引いた例です。実際には、これらの5本の線が実際に真ん中の線のスポットに実際にあることになります(これらはワイヤーなので、すべて同じ鞘に詰まっています)。
GuiOm Clair

1
ディスプレイスメント(「オフセット」)を使用してラインをレンダリングすることもできますが、開始点と終了点で交わることはありません。
AndreJ 2017年

@AndreJはい、そしてもう1つの問題は、それが多くのユーザーによって使用されるため、私がより自動的なものが必要になるかなり手動の操作になることです。
GuiOm Clair

1
@GuiOmClair添付の画像に続いて、他の4つのラインと(たとえば)オーバーラップする1つのラインから開始し、オーバーラップしている場合でもそれらを個別に表示する方法を見つける必要があると想定しました。添付画像に表示されているものを、新しいジオメトリを作成する必要なしに再現できる可能性があると述べました(ただし、開始レイヤーのスタイルプロパティのみを繰り返す)。別の方法としては、AndreJが提案した方法がありますが、ニーズに合わないようです。
mgri

回答:


12

ジオメトリジェネレータとカスタム関数にのみ再帰するアプローチを提案します。

開始する前に、目的の結果を再現するために行う最小限のことの説明に注意を集中することを強調します:これは、他のいくつかのマイナーパラメータ(サイズ、幅など)を簡単に調整できることを意味しますあなたのニーズによりよく適合するため。

したがって、このソリューションは地理参照システムと投影参照システムの両方で機能します。以下では、投影CRS(つまり、測定単位はメートル)を使用することを想定していますが、CRSに応じて変更できます。


環境

ワイヤーを表すこの折れ線ベクトルレイヤーから開始するとします(ラベルは重複する(一致する)ワイヤーの数を表します)。

ここに画像の説明を入力してください


解決

まず、に行きLayer Properties | StyleSingle 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倍の距離で方向を変えて、ワイヤーを一緒に表示します。」

変更する必要があるのは最初の2つのパラメーターの値だけですが、当然ながら妥当な方法です(他の関数パラメーターはそのままにしておきます)。

最後に、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関数に問題が発生したため、線が消えます。この問題は一時レイヤーの使用に起因するものではありませんが、ラインジオメトリではなくマルチラインジオメトリの使用に関連している可能性があります。、QGISでレイヤーをロードし、Pythonコンソールでこれらの2行を入力してください:layer=iface.activeLayer()当時とprint layer.wkbType()。クリックRun:印刷された数値の値はどれですか?
mgri 2017年

数は5(それはどういう意味ですか?)
GuiOm Clair

@GuiOmClairこれは、レイヤーがMultiLineStringレイヤーであることを意味しますが、(指定しなかったため)LineStringレイヤーであると想定しました。これは問題にならないので、できるだけ早く(多分明日)コードを適切に編集します。さらに、各(マルチ)ラインフィーチャの最初のポイントと最後のポイントの間のワイヤーのみをレンダリングできるはずです。
mgri 2017年

1
はい、機能は直線です(管理とエクスポートが一般に簡単であるため)。したがって、ワイヤーの実際の長さを考慮した方がよいでしょう。
GuiOm Clair
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.