지오메트리 생성기와 사용자 정의 함수에만 반복되는 접근 방식을 제안합니다.
시작하기 전에 원하는 결과를 재현하기 위해 수행해야 할 최소한의 설명에주의를 기울일 것이라고 강조하고 싶습니다. 이는 다른 작은 매개 변수 (예 : 크기, 너비 등)를 쉽게 조정할 수 있음을 의미합니다. 당신의 요구를 더 잘 맞추기 위해.
따라서이 솔루션은 지리적 및 투영 기준 시스템 모두에서 작동합니다. 다음에서는 투영 된 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