7
7
8
8
from qgis .PyQt .QtCore import QCoreApplication , QVariant
9
9
from qgis .PyQt .QtGui import QIcon
10
- from qgis .core import (QgsField ,QgsFields ,
10
+ from qgis .core import (QgsField , QgsFields ,
11
11
QgsGeometry ,
12
12
QgsFeature ,
13
13
QgsFeatureSink ,
@@ -37,48 +37,24 @@ class SplitTrajectoriesAlgorithm(QgsProcessingAlgorithm):
37
37
INPUT = 'INPUT'
38
38
TRAJ_ID_FIELD = 'OBJECT_ID_FIELD'
39
39
TIMESTAMP_FIELD = 'TIMESTAMP_FIELD'
40
- TIMESTAMP_FORMAT = 'TIMESTAMP_FORMAT'
41
40
OUTPUT_PTS = 'OUTPUT_PTS'
42
41
OUTPUT_SEGS = 'OUTPUT_SEGS'
43
42
OUTPUT_TRAJS = 'OUTPUT_TRAJS'
44
- SPLIT_MODE = 'SPLIT_MODE'
45
- SPLIT_MODE_OPTIONS = ["observation gap" , "year" , "month" , "day" , "hour" , ]
46
- TIME_GAP = 'TIME_GAP'
47
43
48
44
def __init__ (self ):
49
45
super ().__init__ ()
50
46
51
- def name (self ):
52
- return "split"
53
-
54
47
def icon (self ):
55
48
return QIcon (os .path .join (pluginPath , "icons" , "icon.png" ))
56
-
49
+
57
50
def tr (self , text ):
58
- return QCoreApplication .translate ("split " , text )
59
-
60
- def displayName (self ):
51
+ return QCoreApplication .translate ("split_traj " , text )
52
+
53
+ def group (self ):
61
54
return self .tr ("Split trajectories" )
62
55
63
- #def group(self):
64
- # return self.tr("Basic")
65
-
66
- #def groupId(self):
67
- # return "TrajectoryBasic"
68
-
69
- def shortHelpString (self ):
70
- return self .tr (
71
- "<p>Splits trajectories into subtrajectories using one of the "
72
- "following supported modes: </p>"
73
- "<p><b>Observation gap: </b>"
74
- "splits whenever there is a gap in the observations "
75
- "(for supported time gap formats see: https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.to_timedelta.html)</p>"
76
- "<p><b>Temporal (year, month, day, hour): </b>"
77
- "splits using regular time intervals "
78
- "(time gap parameter will be ignored)</p>"
79
- "<p>For more information on trajectory splitters see: "
80
- "https://movingpandas.readthedocs.io/en/main/trajectorysplitter.html</p>"
81
- )
56
+ def groupId (self ):
57
+ return "split_trajectories"
82
58
83
59
def helpUrl (self ):
84
60
return "https://github.com/movingpandas/processing-trajectory"
@@ -108,23 +84,7 @@ def initAlgorithm(self, config=None):
108
84
parentLayerParameterName = self .INPUT ,
109
85
type = QgsProcessingParameterField .Any ,
110
86
allowMultiple = False ,
111
- optional = False ))
112
- self .addParameter (QgsProcessingParameterString (
113
- name = self .TIMESTAMP_FORMAT ,
114
- description = self .tr ("Timestamp format" ),
115
- defaultValue = "%Y-%m-%d %H:%M:%S+00" ,
116
- optional = False ))
117
- self .addParameter (QgsProcessingParameterEnum (
118
- name = self .SPLIT_MODE ,
119
- description = self .tr ("Splitting mode" ),
120
- defaultValue = "day" ,
121
- options = self .SPLIT_MODE_OPTIONS ,
122
- optional = False ))
123
- self .addParameter (QgsProcessingParameterString (
124
- name = self .TIME_GAP ,
125
- description = self .tr ("Time gap (timedelta, e.g. 1 hours, 15 minutes)" ),
126
- defaultValue = "1 hours" ,
127
- optional = True ))
87
+ optional = False ))
128
88
# output layer
129
89
self .addParameter (QgsProcessingParameterFeatureSink (
130
90
name = self .OUTPUT_PTS ,
@@ -140,11 +100,6 @@ def processAlgorithm(self, parameters, context, feedback):
140
100
self .traj_id_field = self .parameterAsFields (parameters , self .TRAJ_ID_FIELD , context )[0 ]
141
101
self .timestamp_field = self .parameterAsFields (parameters , self .TIMESTAMP_FIELD , context )[0 ]
142
102
143
- timestamp_format = self .parameterAsString (parameters , self .TIMESTAMP_FORMAT , context )
144
- split_mode = self .parameterAsInt (parameters , self .SPLIT_MODE , context )
145
- split_mode = self .SPLIT_MODE_OPTIONS [split_mode ]
146
- time_gap = self .parameterAsString (parameters , self .TIME_GAP , context )
147
-
148
103
crs = self .input_layer .sourceCrs ()
149
104
150
105
self .fields_pts = get_pt_fields (self .input_layer , self .traj_id_field )
@@ -155,34 +110,97 @@ def processAlgorithm(self, parameters, context, feedback):
155
110
(self .sink_trajs , self .dest_trajs ) = self .parameterAsSink (
156
111
parameters , self .OUTPUT_TRAJS , context , self .fields_trajs , QgsWkbTypes .LineStringM , crs )
157
112
158
- tc = tc_from_pt_layer (self .input_layer , self .timestamp_field , self .traj_id_field , timestamp_format )
113
+ tc = tc_from_pt_layer (self .input_layer , self .timestamp_field , self .traj_id_field ) # , timestamp_format)
159
114
160
- if split_mode == "observation gap" :
161
- self .split_on_gaps (time_gap , tc )
162
- else :
163
- self .split_temporally (split_mode , tc )
115
+ self .split (tc , parameters , context )
164
116
165
117
return {self .OUTPUT_PTS : self .dest_pts , self .OUTPUT_TRAJS : self .dest_trajs }
118
+
119
+ def split (self , tc , parameters , context ):
120
+ pass # needs to be implemented by each splitter
166
121
167
122
def postProcessAlgorithm (self , context , feedback ):
168
123
processed_layer = QgsProcessingUtils .mapLayerFromString (self .dest_pts , context )
169
124
processed_layer .loadNamedStyle (os .path .join (pluginPath , "styles" , "pts.qml" ))
170
125
return {self .OUTPUT_PTS : self .dest_pts , self .OUTPUT_TRAJS : self .dest_trajs }
171
126
172
- def split_on_gaps (self , time_gap , tc ):
173
- time_gap = pd .Timedelta (time_gap ).to_pytimedelta ()
127
+
128
+ class SplitObservationGapAlgorithm (SplitTrajectoriesAlgorithm ):
129
+ TIME_GAP = 'TIME_GAP'
130
+
131
+ def __init__ (self ):
132
+ super ().__init__ ()
133
+
134
+ def initAlgorithm (self , config = None ):
135
+ super ().initAlgorithm (config )
136
+ self .addParameter (QgsProcessingParameterString (
137
+ name = self .TIME_GAP ,
138
+ description = self .tr ("Time gap (timedelta, e.g. 1 hours, 15 minutes)" ),
139
+ defaultValue = "1 hours" ,
140
+ optional = True ))
141
+
142
+ def name (self ):
143
+ return "split_gap"
144
+
145
+ def displayName (self ):
146
+ return self .tr ("Split trajectories at observation gaps" )
147
+
148
+ def shortHelpString (self ):
149
+ return self .tr (
150
+ "<p>Splits trajectories into subtrajectories "
151
+ "whenever there is a gap in the observations "
152
+ "(for supported time gap formats see: "
153
+ "https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.to_timedelta.html)</p>"
154
+ "<p>For more information on trajectory splitters see: "
155
+ "https://movingpandas.readthedocs.io/en/main/trajectorysplitter.html</p>"
156
+ )
157
+
158
+ def split (self , tc , parameters , context ):
159
+ time_gap = self .parameterAsString (parameters , self .TIME_GAP , context )
174
160
for traj in tc .trajectories :
175
161
splits = ObservationGapSplitter (traj ).split (gap = time_gap )
176
162
tc_to_sink (splits , self .sink_pts , self .fields_pts , self .timestamp_field )
177
163
for split in splits :
178
164
traj_to_sink (split , self .sink_trajs )
179
165
180
- def split_temporally (self , split_mode , tc ):
166
+
167
+ class SplitTemporallyAlgorithm (SplitTrajectoriesAlgorithm ):
168
+ SPLIT_MODE = 'SPLIT_MODE'
169
+ SPLIT_MODE_OPTIONS = ["year" , "month" , "day" , "hour" , ]
170
+
171
+ def __init__ (self ):
172
+ super ().__init__ ()
173
+
174
+ def initAlgorithm (self , config = None ):
175
+ super ().initAlgorithm (config )
176
+ self .addParameter (QgsProcessingParameterEnum (
177
+ name = self .SPLIT_MODE ,
178
+ description = self .tr ("Splitting mode" ),
179
+ defaultValue = "day" ,
180
+ options = self .SPLIT_MODE_OPTIONS ,
181
+ optional = False ))
182
+
183
+ def name (self ):
184
+ return "split_temporally"
185
+
186
+ def displayName (self ):
187
+ return self .tr ("Split trajectories at time intervals" )
188
+
189
+ def shortHelpString (self ):
190
+ return self .tr (
191
+ "<p>Splits trajectories into subtrajectories "
192
+ "using regular time intervals (year, month, day, hour): </p>"
193
+ "<p>For more information on trajectory splitters see: "
194
+ "https://movingpandas.readthedocs.io/en/main/trajectorysplitter.html</p>"
195
+ )
196
+
197
+ def split (self , tc , parameters , context ):
198
+ split_mode = self .parameterAsInt (parameters , self .SPLIT_MODE , context )
199
+ split_mode = self .SPLIT_MODE_OPTIONS [split_mode ]
181
200
for traj in tc .trajectories :
182
201
splits = TemporalSplitter (traj ).split (mode = split_mode )
183
202
tc_to_sink (splits , self .sink_pts , self .fields_pts , self .timestamp_field )
184
203
for split in splits :
185
- traj_to_sink (split , self .sink_trajs )
186
-
187
-
204
+ traj_to_sink (split , self .sink_trajs )
205
+
188
206
0 commit comments