मैं एक दृष्टिकोण का प्रस्ताव करता हूं जो केवल एक ज्यामिति जनरेटर और एक कस्टम फ़ंक्शन के लिए पुनरावृत्ति करता है।
शुरू करने से पहले, मैं यह रेखांकित करना चाहता हूं कि मैं वांछित परिणाम को पुन: पेश करने के लिए न्यूनतम चीजों की व्याख्या पर ध्यान केंद्रित करूंगा: इसका मतलब है कि कुछ अन्य मामूली पैरामीटर (जैसे आकार, चौड़ाई और इतने पर) आसानी से आपके द्वारा समायोजित किए जाने चाहिए। अपनी आवश्यकताओं के लिए बेहतर फिटिंग के लिए।
इसलिए, यह समाधान भौगोलिक और अनुमानित संदर्भ प्रणालियों के लिए काम करता है: निम्नलिखित में, मैंने अनुमान लगाया सीआरएस (यानी माप की इकाइयां मीटर हैं) का उपयोग करने के लिए मान लिया, लेकिन आप उन्हें अपने सीआरएस के अनुसार बदल सकते हैं।
प्रसंग
आइए तारों को दर्शाने वाली इस लिनेस्ट्रिंग वेक्टर परत से शुरू करें (लेबल अतिव्यापी (संयोग) तारों की संख्या का प्रतिनिधित्व करते हैं):
समाधान
सबसे पहले, पर जाएँ 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)
आपने केवल एक फ़ंक्शन चलाया है, जो एक काल्पनिक तरीके से कह रहा है:
"वर्तमान परत ( @ लेयर_नाम ) और वर्तमान सुविधा ( $ करंट ) के लिए, 40 डिग्री के प्रारंभिक अधिकतम उपयोग के साथ तारों को प्रदर्शित करें और वर्तमान खंड की लंबाई के 0.3 गुना की दूरी पर दिशा में परिवर्तन के साथ।"
केवल एक चीज जिसे आपको बदलने की आवश्यकता है, वह पहले दो मापदंडों का मान है जैसा आप चाहते हैं, लेकिन स्पष्ट रूप से एक उचित तरीके से (अन्य फ़ंक्शन मापदंडों को प्रदान किए गए तरीके से छोड़ दें)।
अंत में, Apply
परिवर्तनों को लागू करने के लिए बटन पर क्लिक करें ।
आपको कुछ इस तरह दिखाई देगा:
जैसा सोचा था।
संपादित करें
एक टिप्पणी में ओपी द्वारा उठाए गए एक विशिष्ट अनुरोध के अनुसार:
"क्या यह पैटर्न प्रत्येक वर्टेक्स के बीच के बजाय प्रत्येक पॉलीलाइन की शुरुआत और अंत के बीच बनाना संभव होगा?"
मैंने कोड को थोड़ा संपादित किया। निम्नलिखित फ़ंक्शन को अपेक्षित परिणाम वापस करना चाहिए:
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