Saya mengusulkan pendekatan yang hanya berulang ke generator geometri dan fungsi kustom.
Sebelum memulai, saya ingin menggarisbawahi bahwa saya akan memusatkan perhatian pada penjelasan tentang hal-hal minimal yang harus dilakukan untuk mereproduksi hasil yang diinginkan: ini berarti bahwa beberapa parameter kecil lainnya (seperti ukuran, lebar dan sebagainya) harus mudah disesuaikan oleh Anda untuk menyesuaikan kebutuhan Anda dengan lebih baik.
Oleh karena itu, solusi ini berfungsi baik untuk Sistem Referensi Geografis dan Proyeksi: sebagai berikut, saya berasumsi menggunakan CRS yang diproyeksikan (yaitu satuan pengukuran adalah meter), tetapi Anda dapat mengubahnya sesuai dengan CRS Anda.
Konteks
Mari kita asumsikan mulai dari layer vektor linestring ini yang mewakili kabel (label mewakili jumlah kabel yang tumpang tindih (bertepatan)):
Larutan
Pertama, pergi ke Layer Properties | Style
dan kemudian pilih Single symbol
penyaji.
Dari Symbol selector
dialog, pilih Geometry generator
tipe layer simbol dan Linestring / MultiLinestring
tipe geometri. Kemudian, klik pada Function Editor
tab:
Kemudian, klik New file
dan ketik draw_wires
sebagai nama fungsi baru:
Anda akan melihat bahwa fungsi baru telah dibuat dan terdaftar di sisi kiri dialog. Sekarang, klik pada nama fungsi dan ganti default @qgsfunction
dengan kode berikut (jangan lupa untuk menambahkan semua perpustakaan yang dilampirkan di sini):
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
Setelah Anda selesai melakukannya, klik Load
tombol dan Anda akan dapat melihat fungsi dari Custom
Menu Expression
dialog.
Sekarang, ketikkan ungkapan ini (lihat gambar di bawah ini sebagai referensi):
draw_wires(40, 0.3, $currentfeature, @layer_name)
Anda baru saja menjalankan fungsi yang mengatakan, dengan cara imajiner:
"Untuk layer saat ini ( @layer_name ) dan fitur saat ini ( $ currentfeature ), tampilkan kabel bersama-sama menggunakan pembukaan maksimum awal 40 derajat dan dengan perubahan arah pada jarak 0,3 kali panjang segmen saat ini."
Satu-satunya hal yang perlu Anda ubah adalah nilai dari dua parameter pertama seperti yang Anda inginkan, tetapi jelas dengan cara yang masuk akal (biarkan parameter fungsi lainnya sebagaimana disediakan).
Terakhir, klik Apply
tombol untuk menerapkan perubahan.
Anda akan melihat sesuatu seperti ini:
seperti yang diharapkan.
EDIT
Menurut permintaan spesifik yang diajukan oleh OP dalam komentar:
"Apakah mungkin untuk membuat pola ini hanya antara awal dan akhir setiap polyline alih-alih antara setiap vertex?"
Saya sedikit mengedit kode. Fungsi berikut harus mengembalikan hasil yang diharapkan:
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