29
29
import os
30
30
from datetime import datetime
31
31
32
- from qgis .PyQt .QtCore import QVariant
33
- from qgis .core import (QgsApplication ,
34
- QgsFeature ,
32
+ from qgis .core import (QgsFeature ,
35
33
QgsFeatureSink ,
36
34
QgsFields ,
37
35
QgsField ,
38
36
QgsGeometry ,
39
37
QgsDistanceArea ,
40
- QgsProject ,
38
+ QgsPointXY ,
39
+ QgsLineString ,
41
40
QgsWkbTypes ,
42
- QgsProcessingUtils )
41
+ QgsFeatureRequest ,
42
+ QgsProcessingParameterFeatureSource ,
43
+ QgsProcessingParameterField ,
44
+ QgsProcessingParameterString ,
45
+ QgsProcessing ,
46
+ QgsProcessingParameterFeatureSink ,
47
+ QgsProcessingParameterFolderDestination )
43
48
44
49
from processing .algs .qgis .QgisAlgorithm import QgisAlgorithm
45
- from processing .core .parameters import ParameterVector
46
- from processing .core .parameters import ParameterTableField
47
- from processing .core .parameters import ParameterString
48
- from processing .core .outputs import OutputVector
49
- from processing .core .outputs import OutputDirectory
50
- from processing .tools import dataobjects
51
50
52
51
53
52
class PointsToPaths (QgisAlgorithm ):
54
53
55
- VECTOR = 'VECTOR '
54
+ INPUT = 'INPUT '
56
55
GROUP_FIELD = 'GROUP_FIELD'
57
56
ORDER_FIELD = 'ORDER_FIELD'
58
57
DATE_FORMAT = 'DATE_FORMAT'
59
- #GAP_PERIOD = 'GAP_PERIOD'
60
- OUTPUT_LINES = 'OUTPUT_LINES'
61
- OUTPUT_TEXT = 'OUTPUT_TEXT'
58
+ OUTPUT = 'OUTPUT'
59
+ OUTPUT_TEXT_DIR = 'OUTPUT_TEXT_DIR'
62
60
63
61
def group (self ):
64
62
return self .tr ('Vector creation tools' )
65
63
66
64
def __init__ (self ):
67
65
super ().__init__ ()
68
66
67
+ def tags (self ):
68
+ return self .tr ('join,points,lines,connect' ).split (',' )
69
+
69
70
def initAlgorithm (self , config = None ):
70
- self .addParameter (ParameterVector (self .VECTOR ,
71
- self .tr ('Input point layer' ), [dataobjects . TYPE_VECTOR_POINT ]))
72
- self .addParameter (ParameterTableField (self .GROUP_FIELD ,
73
- self .tr ('Group field' ), self .VECTOR ))
74
- self .addParameter (ParameterTableField (self .ORDER_FIELD ,
75
- self .tr ('Order field' ), self .VECTOR ))
76
- self .addParameter (ParameterString (self .DATE_FORMAT ,
77
- self .tr ('Date format (if order field is DateTime)' ), '' , optional = True ))
78
- #self.addParameter(ParameterNumber(
79
- # self.GAP_PERIOD,
80
- # 'Gap period (if order field is DateTime)', 0, 60, 0) )
81
- self . addOutput ( OutputVector ( self . OUTPUT_LINES , self . tr ( 'Paths' ), datatype = [ dataobjects . TYPE_VECTOR_LINE ]) )
82
- self .addOutput ( OutputDirectory ( self . OUTPUT_TEXT , self . tr ( 'Directory' )) )
71
+ self .addParameter (QgsProcessingParameterFeatureSource (self .INPUT ,
72
+ self .tr ('Input point layer' ), [QgsProcessing . TypeVectorPoint ]))
73
+ self .addParameter (QgsProcessingParameterField (self .ORDER_FIELD ,
74
+ self .tr ('Order field' ), parentLayerParameterName = self .INPUT ))
75
+ self .addParameter (QgsProcessingParameterField (self .GROUP_FIELD ,
76
+ self .tr ('Group field' ), parentLayerParameterName = self .INPUT , optional = True ))
77
+ self .addParameter (QgsProcessingParameterString (self .DATE_FORMAT ,
78
+ self .tr ('Date format (if order field is DateTime)' ), optional = True ))
79
+
80
+ self . addParameter ( QgsProcessingParameterFeatureSink ( self . OUTPUT , self .tr ( 'Paths' ), QgsProcessing . TypeVectorLine ))
81
+ output_dir_param = QgsProcessingParameterFolderDestination ( self . OUTPUT_TEXT_DIR , self . tr ( 'Directory for text output' ), optional = True )
82
+ output_dir_param . setCreateByDefault ( False )
83
+ self .addParameter ( output_dir_param )
83
84
84
85
def name (self ):
85
86
return 'pointstopath'
@@ -88,29 +89,58 @@ def displayName(self):
88
89
return self .tr ('Points to path' )
89
90
90
91
def processAlgorithm (self , parameters , context , feedback ):
91
- layer = QgsProcessingUtils .mapLayerFromString (self .getParameterValue (self .VECTOR ), context )
92
- groupField = self .getParameterValue (self .GROUP_FIELD )
93
- orderField = self .getParameterValue (self .ORDER_FIELD )
94
- dateFormat = str (self .getParameterValue (self .DATE_FORMAT ))
95
- #gap = int(self.getParameterValue(self.GAP_PERIOD))
96
- dirName = self .getOutputValue (self .OUTPUT_TEXT )
92
+ source = self .parameterAsSource (parameters , self .INPUT , context )
93
+ group_field_name = self .parameterAsString (parameters , self .GROUP_FIELD , context )
94
+ order_field_name = self .parameterAsString (parameters , self .ORDER_FIELD , context )
95
+ date_format = self .parameterAsString (parameters , self .DATE_FORMAT , context )
96
+ text_dir = self .parameterAsString (parameters , self .OUTPUT_TEXT_DIR , context )
97
+
98
+ group_field_index = source .fields ().lookupField (group_field_name )
99
+ order_field_index = source .fields ().lookupField (order_field_name )
100
+
101
+ if group_field_index >= 0 :
102
+ group_field_def = source .fields ().at (group_field_index )
103
+ else :
104
+ group_field_def = None
105
+ order_field_def = source .fields ().at (order_field_index )
97
106
98
107
fields = QgsFields ()
99
- fields .append (QgsField ('group' , QVariant .String , '' , 254 , 0 ))
100
- fields .append (QgsField ('begin' , QVariant .String , '' , 254 , 0 ))
101
- fields .append (QgsField ('end' , QVariant .String , '' , 254 , 0 ))
102
- writer = self .getOutputFromName (self .OUTPUT_LINES ).getVectorWriter (fields , QgsWkbTypes .LineString , layer .crs (),
103
- context )
108
+ if group_field_def is not None :
109
+ fields .append (group_field_def )
110
+ begin_field = QgsField (order_field_def )
111
+ begin_field .setName ('begin' )
112
+ fields .append (begin_field )
113
+ end_field = QgsField (order_field_def )
114
+ end_field .setName ('end' )
115
+ fields .append (end_field )
116
+
117
+ output_wkb = QgsWkbTypes .LineString
118
+ if QgsWkbTypes .hasM (source .wkbType ()):
119
+ output_wkb = QgsWkbTypes .addM (output_wkb )
120
+ if QgsWkbTypes .hasZ (source .wkbType ()):
121
+ output_wkb = QgsWkbTypes .addZ (output_wkb )
122
+
123
+ (sink , dest_id ) = self .parameterAsSink (parameters , self .OUTPUT , context ,
124
+ fields , output_wkb , source .sourceCrs ())
104
125
105
126
points = dict ()
106
- features = QgsProcessingUtils .getFeatures (layer , context )
107
- total = 100.0 / layer .featureCount () if layer .featureCount () else 0
127
+ features = source .getFeatures (QgsFeatureRequest (). setSubsetOfAttributes ([ group_field_index , order_field_index ]) )
128
+ total = 100.0 / source .featureCount () if source .featureCount () else 0
108
129
for current , f in enumerate (features ):
109
- point = f .geometry ().asPoint ()
110
- group = f [groupField ]
111
- order = f [orderField ]
112
- if dateFormat != '' :
113
- order = datetime .strptime (str (order ), dateFormat )
130
+ if feedback .isCanceled ():
131
+ break
132
+
133
+ if not f .hasGeometry ():
134
+ continue
135
+
136
+ point = f .geometry ().geometry ().clone ()
137
+ if group_field_index >= 0 :
138
+ group = f .attributes ()[group_field_index ]
139
+ else :
140
+ group = 1
141
+ order = f .attributes ()[order_field_index ]
142
+ if date_format != '' :
143
+ order = datetime .strptime (str (order ), date_format )
114
144
if group in points :
115
145
points [group ].append ((order , point ))
116
146
else :
@@ -121,46 +151,45 @@ def processAlgorithm(self, parameters, context, feedback):
121
151
feedback .setProgress (0 )
122
152
123
153
da = QgsDistanceArea ()
124
- da .setSourceCrs (layer .sourceCrs ())
154
+ da .setSourceCrs (source .sourceCrs ())
125
155
da .setEllipsoid (context .project ().ellipsoid ())
126
156
127
157
current = 0
128
158
total = 100.0 / len (points ) if points else 1
129
159
for group , vertices in list (points .items ()):
160
+ if feedback .isCanceled ():
161
+ break
162
+
130
163
vertices .sort ()
131
164
f = QgsFeature ()
132
- f .initAttributes (len (fields ))
133
- f .setFields (fields )
134
- f ['group' ] = group
135
- f ['begin' ] = vertices [0 ][0 ]
136
- f ['end' ] = vertices [- 1 ][0 ]
137
-
138
- fileName = os .path .join (dirName , '%s.txt' % group )
139
-
140
- with open (fileName , 'w' ) as fl :
141
- fl .write ('angle=Azimuth\n ' )
142
- fl .write ('heading=Coordinate_System\n ' )
143
- fl .write ('dist_units=Default\n ' )
144
-
145
- line = []
146
- i = 0
147
- for node in vertices :
148
- line .append (node [1 ])
149
-
150
- if i == 0 :
151
- fl .write ('startAt=%f;%f;90\n ' % (node [1 ].x (), node [1 ].y ()))
152
- fl .write ('survey=Polygonal\n ' )
153
- fl .write ('[data]\n ' )
154
- else :
155
- angle = line [i - 1 ].azimuth (line [i ])
156
- distance = da .measureLine (line [i - 1 ], line [i ])
157
- fl .write ('%f;%f;90\n ' % (angle , distance ))
158
-
159
- i += 1
160
-
161
- f .setGeometry (QgsGeometry .fromPolyline (line ))
162
- writer .addFeature (f , QgsFeatureSink .FastInsert )
165
+ attributes = []
166
+ if group_field_index >= 0 :
167
+ attributes .append (group )
168
+ attributes .extend ([vertices [0 ][0 ], vertices [- 1 ][0 ]])
169
+ f .setAttributes (attributes )
170
+ line = [node [1 ] for node in vertices ]
171
+
172
+ if text_dir :
173
+ fileName = os .path .join (text_dir , '%s.txt' % group )
174
+
175
+ with open (fileName , 'w' ) as fl :
176
+ fl .write ('angle=Azimuth\n ' )
177
+ fl .write ('heading=Coordinate_System\n ' )
178
+ fl .write ('dist_units=Default\n ' )
179
+
180
+ for i in range (len (line )):
181
+ if i == 0 :
182
+ fl .write ('startAt=%f;%f;90\n ' % (line [i ].x (), line [i ].y ()))
183
+ fl .write ('survey=Polygonal\n ' )
184
+ fl .write ('[data]\n ' )
185
+ else :
186
+ angle = line [i - 1 ].azimuth (line [i ])
187
+ distance = da .measureLine (QgsPointXY (line [i - 1 ]), QgsPointXY (line [i ]))
188
+ fl .write ('%f;%f;90\n ' % (angle , distance ))
189
+
190
+ f .setGeometry (QgsGeometry (QgsLineString (line )))
191
+ sink .addFeature (f , QgsFeatureSink .FastInsert )
163
192
current += 1
164
193
feedback .setProgress (int (current * total ))
165
194
166
- del writer
195
+ return { self . OUTPUT : dest_id }
0 commit comments