QGIS에서 겹치는 선의 표시를 바꾸고 있습니까?


10

점이 겹칠 때이 속성이 있는데,이 점은 '포인트 변위'라고하는 지점 주변에 많은 점을 자동으로 표시 할 수 있습니다. 그러나 그것은 라인에서 작동하지 않습니다. 그래서도 이와 같은 것을 달성하기 위해 개념적으로 실현 가능합니다.

여기에 이미지 설명을 입력하십시오

나는 실제로는 모두 같은 장소에있는 다른 라인을 볼 필요가 있습니다 (원거리 통신 네트워킹에서 일하고 있습니다). 내가 지금 볼 수있는 유일한 방법은 위의 그림과 같이 실제로 다른 선을 만들어 공간적 실수를 만드는 것입니다.

QGIS 2.14를 사용하고 있습니다.


나는 스타일링에 반복적으로 뭔가를 할 수 있다고 생각합니다. 중간에있는 줄이 출발 선입니까? 그런 다음 세 가지 다른 형상을 사용하여 다른 선을 각각 만들었으므로 렌더링에 대한 특정 추가 규칙이 있는지 궁금합니다.
mgri

@ mgri 나는 당신의 질문을 이해하지 못합니다. 제공된 그림은 데모를 위해 5 개의 다른 선을 그린 예입니다. 실제로이 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.