-
Notifications
You must be signed in to change notification settings - Fork 0
/
geometrically_fixed_algorithm.py
244 lines (182 loc) · 10.9 KB
/
geometrically_fixed_algorithm.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# -*- coding: utf-8 -*-
"""
/***************************************************************************
illini_drainage_tools
A QGIS plugin
Performs Specific Draiange Related Tasks and Analysis on a Site
Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
-------------------
begin : 2022-03-15
copyright : (C) 2022 by FALASY Anamelechi
email : fvw.services@gmail.com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
"""
__author__ = 'FALASY Anamelechi'
__date__ = '2022-03-15'
__copyright__ = '(C) 2022 by FALASY Anamelechi'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'
import os, math
import inspect
from qgis.PyQt.QtGui import QIcon
from qgis.core import QgsProcessing
from qgis.core import QgsProcessingAlgorithm
from qgis.core import QgsProcessingMultiStepFeedback
from qgis.core import QgsProcessingParameterRasterLayer
from qgis.core import QgsProcessingParameterFeatureSource
from qgis.core import QgsProcessingParameterFeatureSink
from qgis.core import QgsProcessingParameterBoolean
from qgis.core import QgsProcessingParameterVectorLayer
from qgis.core import QgsProcessingParameterNumber
from qgis.core import QgsProcessingParameterField
from qgis.core import QgsProcessingParameterVectorDestination
from qgis.core import QgsProcessingLayerPostProcessorInterface
import processing
from PyQt5 import QtWidgets
from qgis.PyQt.QtCore import QCoreApplication, QVariant
from qgis.core import *
from collections import Counter
import time
import numpy as np
class GeometricallyFixedAlgorithm(QgsProcessingAlgorithm):
def tr(self, string):
return QCoreApplication.translate('Processing', string)
def createInstance(self):
return GeometricallyFixedAlgorithm()
def name(self):
return 'e. Hydraulic Network Fixer'
def displayName(self):
return self.tr(self.name())
def group(self):
return self.tr(self.groupId())
def groupId(self):
return ''
def icon(self):
cmd_folder = os.path.split(inspect.getfile(inspect.currentframe()))[0]
icon = QIcon(os.path.join(os.path.join(cmd_folder, 'logo.png')))
return icon
def shortHelpString(self):
return self.tr( """This tool is used to clean up a a proposed line layer from its global properties in space to have an exploded line segments of topologically-sound and connected geometry for building tile networks.
Workflow:
1. Select a Vector Line layer of either a Simple or Complex Layout of Mains and Submains
2. Carefully examine the tile layout and Make a Decision as to whether to Adjust the "Start or End Distances" for each line segment or not. Default value is encouraged except otherwise.
3. Select a desired Coordinate Reference System for displaying the generated points
4. Save the output file (optional)
5. Click on \"Run\"
The script will give out an output.
Use this output with "Routine F" to create a topologically sound tile network.
The help link in the Graphical User Interface (GUI) provides more information about the plugin.
""")
def helpUrl(self):
return "https://publish.illinois.edu/illinoisdrainageguide/files/2022/06/PublicAccess.pdf"
def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterVectorLayer('VectorLineLayer', 'Proposed Tile Lines', types=[QgsProcessing.TypeVectorLine], defaultValue=None))
self.addParameter(QgsProcessingParameterNumber('StartPoints', 'Extend Starting Lines', type=QgsProcessingParameterNumber.Double, maxValue=100.0, defaultValue=5.00))
self.addParameter(QgsProcessingParameterNumber('EndPoints', 'Extend Ending Lines', type=QgsProcessingParameterNumber.Double, maxValue=100.0, defaultValue=5.00))
self.addParameter(QgsProcessingParameterCrs('CRS', 'Coordinate Reference System', defaultValue='EPSG:3435'))
self.addParameter(QgsProcessingParameterVectorDestination('LineFixes', 'Topologically-Sound Network', type=QgsProcessing.TypeVectorAnyGeometry, createByDefault=True, defaultValue=None))
def processAlgorithm(self, parameters, context, feedback):
# Adjusts Lines
adjustlines_params = processing.run('native:extendlines',
{'INPUT': parameters['VectorLineLayer'], 'START_DISTANCE':parameters['StartPoints'], 'END_DISTANCE':parameters['EndPoints'], 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT},
context=context, feedback=feedback, is_child_algorithm=True) #1
results_a = adjustlines_params['OUTPUT']
# MultiPart To SingleParts
singleparts_params = processing.run('native:multiparttosingleparts',
{'INPUT': results_a, 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT},
context=context, feedback=feedback, is_child_algorithm=True) #2
results_b = singleparts_params['OUTPUT']
# Dissolve Line Split lines by maximum length
dissolve_params = processing.run('native:dissolve',
{'INPUT': results_b, 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT},
context=context, feedback=feedback, is_child_algorithm=True) #3
results_c = dissolve_params['OUTPUT']
# Extract Vertices
vertices_params = processing.run('native:extractvertices',
{'INPUT': results_c, 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT},
context=context, feedback=feedback, is_child_algorithm=True) #4
results_d = vertices_params['OUTPUT']
# Add X/Y Fields
addxy_params = processing.run('native:addxyfields',
{'INPUT': results_d, 'CRS': parameters['CRS'], 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT},
context=context, feedback=feedback, is_child_algorithm=True) #5
results_e = addxy_params['OUTPUT']
# Snap Geometries to Layers
snap_params = processing.run('native:snapgeometries',
{'INPUT': results_e, 'REFERENCE_LAYER': results_e, 'TOLERANCE': 10, 'BEHAVIOR': 0, 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT},
context=context, feedback=feedback, is_child_algorithm=True) #6
results_f = snap_params['OUTPUT']
# Convert Points To Path
topath_params = processing.run('native:pointstopath',
{'INPUT': results_f, 'ORDER_EXPRESSION': 'vertex_part_index', 'GROUP_EXPRESSION': 'vertex_part', 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT},
context=context, feedback=feedback, is_child_algorithm=True) #7
results_g = topath_params['OUTPUT']
# Fix Line Geometries
linefix_params = processing.run('native:fixgeometries',
{'INPUT': results_g, 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT},
context=context, feedback=feedback, is_child_algorithm=True) #8
results_h = linefix_params['OUTPUT']
# Add Geometry Attributes
geoattributes_params = processing.run('qgis:exportaddgeometrycolumns',
{'INPUT': results_h, 'CALC_METHOD': 0, 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT},
context=context, feedback=feedback, is_child_algorithm=True) #9
results_i = geoattributes_params['OUTPUT']
# Explode Line Segments
explode_params = processing.run('native:explodelines',
{'INPUT': results_i, 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT},
context=context, feedback=feedback, is_child_algorithm=True) #10
results_j = explode_params['OUTPUT']
# Remove Null Geometries
removenull_params = processing.run('native:removenullgeometries',
{'INPUT': results_j, 'REMOVE_EMPTY': True, 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT},
context=context, feedback=feedback, is_child_algorithm=True) #11
results_k = removenull_params['OUTPUT']
# Validate Attribute Checks
valid_params = processing.run('qgis:checkvalidity',
{'INPUT_LAYER': results_k,
'METHOD': 2,
'IGNORE_RING_SELF_INTERSECTION': False,
'INVALID_OUTPUT': QgsProcessing.TEMPORARY_OUTPUT,
'ERROR_OUTPUT': QgsProcessing.TEMPORARY_OUTPUT,
'VALID_OUTPUT': QgsProcessing.TEMPORARY_OUTPUT},
context=context, feedback=feedback, is_child_algorithm=True) #12
results_l = valid_params['VALID_OUTPUT']
# Field calculator
calc_params = processing.run('native:fieldcalculator',
{'FIELD_LENGTH': 10,
'FIELD_NAME': 'ID',
'FIELD_PRECISION': 0,
'FIELD_TYPE': 1,
'FORMULA': '$id',
'INPUT': results_l,
'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT},
context=context, feedback=feedback, is_child_algorithm=True) #13
results_m = calc_params['OUTPUT']
# Final Retained Fields of Interest
fields_params = processing.run('native:retainfields',
{"INPUT": results_m, "FIELDS": ['vertex_part', 'begin', 'end', 'ID'], "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT},
context=context, feedback=feedback, is_child_algorithm=True) #14
results_n = fields_params['OUTPUT']
# Fix Line Geometries
final_params = processing.run('native:fixgeometries',
{'INPUT': results_n, 'OUTPUT': parameters['LineFixes']},
context=context, feedback=feedback, is_child_algorithm=True) #15
results_o = final_params['OUTPUT']
global renamer
renamer = Renamer('Topologically-Sound Network')
context.layerToLoadOnCompletionDetails(results_o).setPostProcessor(renamer)
return {'LineFixes': results_o}
class Renamer(QgsProcessingLayerPostProcessorInterface):
def __init__(self, layer_name):
self.name = layer_name
super().__init__()
def postProcessLayer(self, layer, context, feedback):
layer.setName(self.name)