Skip to content

Commit 7c6fcb2

Browse files
committed
Add StopSplitterAlgorithm
1 parent 8effb12 commit 7c6fcb2

9 files changed

+420
-442
lines changed

__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
"""
44
***************************************************************************
5-
trajectoryProviderPlugin.py
5+
trajectoolsProviderPlugin.py
66
---------------------
77
Date : December 2023
88
Copyright : (C) 2023 by Anita Graser
@@ -25,7 +25,7 @@
2525

2626
__revision__ = '$Format:%H$'
2727

28-
from .qgis_processing.trajectoryProviderPlugin import TrajectoryProviderPlugin
28+
from .qgis_processing.trajectoolsProviderPlugin import TrajectoryProviderPlugin
2929

3030

3131
def classFactory(iface):
Lines changed: 26 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -1,172 +1,60 @@
1-
# -*- coding: utf-8 -*-
2-
import os
3-
import sys
1+
import sys
42

53
from qgis.PyQt.QtCore import QCoreApplication, QVariant
6-
from qgis.PyQt.QtGui import QIcon
7-
8-
from qgis.core import (QgsField, QgsFields, QgsPointXY,
9-
QgsGeometry,
10-
QgsFeature,
11-
QgsFeatureSink,
12-
QgsFeatureRequest,
13-
QgsProcessing,
14-
QgsProcessingAlgorithm,
15-
QgsProcessingParameterFeatureSource,
16-
QgsProcessingParameterString,
17-
QgsProcessingParameterField,
18-
QgsProcessingParameterNumber,
19-
QgsProcessingParameterBoolean,
20-
QgsProcessingParameterFeatureSink,
21-
QgsProcessingParameterEnum,
22-
QgsWkbTypes,
23-
QgsProcessingUtils
24-
)
4+
from qgis.core import (
5+
QgsField,
6+
QgsGeometry,
7+
QgsFeature,
8+
QgsFeatureSink,
9+
QgsProcessingParameterString,
10+
QgsWkbTypes,
11+
)
2512

2613
sys.path.append("..")
2714

28-
from .qgisUtils import tc_from_pt_layer, tc_to_sink, get_pt_fields, get_traj_fields
29-
30-
pluginPath = os.path.dirname(__file__)
15+
from .qgisUtils import tc_to_sink, traj_to_sink
16+
from .trajectoriesAlgorithm import TrajectoriesAlgorithm
3117

3218

33-
class CreateTrajectoriesAlgorithm(QgsProcessingAlgorithm):
34-
# script parameters
35-
INPUT = 'INPUT'
36-
TRAJ_ID_FIELD = 'OBJECT_ID_FIELD'
37-
TIMESTAMP_FIELD = 'TIMESTAMP_FIELD'
38-
TIMESTAMP_FORMAT = 'TIMESTAMP_FORMAT'
39-
OUTPUT_PTS = 'OUTPUT_PTS'
40-
OUTPUT_SEGS = 'OUTPUT_SEGS'
41-
OUTPUT_TRAJS = 'OUTPUT_TRAJS'
42-
SPEED_UNIT = 'SPEED_UNIT'
19+
class CreateTrajectoriesAlgorithm(TrajectoriesAlgorithm):
20+
SPEED_UNIT = "SPEED_UNIT"
4321

4422
def __init__(self):
4523
super().__init__()
4624

4725
def name(self):
4826
return "create_trajectory"
4927

50-
def icon(self):
51-
return QIcon(os.path.join(pluginPath, "icons", "icon.png"))
52-
5328
def tr(self, text):
5429
return QCoreApplication.translate("create_trajectory", text)
5530

5631
def displayName(self):
5732
return self.tr("Create trajectories")
5833

59-
#def group(self):
60-
# return self.tr("Basic")
34+
def group(self):
35+
return self.tr("Basic")
6136

62-
#def groupId(self):
63-
# return "TrajectoryBasic"
37+
def groupId(self):
38+
return "TrajectoryBasic"
6439

6540
def shortHelpString(self):
6641
return self.tr(
67-
"<p>Creates a trajectory point layers with speed and direction information "
42+
"<p>Creates a trajectory point layers with speed and direction information "
6843
"as well as a trajectory line layer.</p>"
69-
"<p><b>Speed</b> is calculated based on the input layer CRS information and "
70-
"converted to the desired speed units. For more info on the supported units, "
71-
"see https://movingpandas.org/units</p>"
72-
"<p><b>Direction</b> is calculated between consecutive locations. Direction "
44+
"<p><b>Speed</b> is calculated based on the input layer CRS information and "
45+
"converted to the desired speed units. For more info on the supported units, "
46+
"see https://movingpandas.org/units</p>"
47+
"<p><b>Direction</b> is calculated between consecutive locations. Direction "
7348
"values are in degrees, starting North turning clockwise.</p>"
74-
)
49+
)
7550

7651
def helpUrl(self):
7752
return "https://movingpandas.org/units"
7853

7954
def createInstance(self):
8055
return type(self)()
8156

82-
def initAlgorithm(self, config=None):
83-
# input layer
84-
self.addParameter(QgsProcessingParameterFeatureSource(
85-
name=self.INPUT,
86-
description=self.tr("Input point layer"),
87-
types=[QgsProcessing.TypeVectorPoint]))
88-
# fields
89-
self.addParameter(QgsProcessingParameterField(
90-
name=self.TRAJ_ID_FIELD,
91-
description=self.tr("Trajectory ID field"),
92-
defaultValue="trajectory_id",
93-
parentLayerParameterName=self.INPUT,
94-
type=QgsProcessingParameterField.Any,
95-
allowMultiple=False,
96-
optional=False))
97-
self.addParameter(QgsProcessingParameterField(
98-
name=self.TIMESTAMP_FIELD,
99-
description=self.tr("Timestamp field"),
100-
defaultValue="t",
101-
parentLayerParameterName=self.INPUT,
102-
type=QgsProcessingParameterField.Any,
103-
allowMultiple=False,
104-
optional=False))
105-
# self.addParameter(QgsProcessingParameterString(
106-
# name=self.TIMESTAMP_FORMAT,
107-
# description=self.tr("Timestamp format (e.g. %Y-%m-%d %H:%M:%S)"),
108-
# #defaultValue="%Y-%m-%d %H:%M:%S+00",
109-
# optional=True))
110-
self.addParameter(QgsProcessingParameterString(
111-
name=self.SPEED_UNIT,
112-
description=self.tr("Speed units (e.g. km/h, m/s)"),
113-
defaultValue="km/h",
114-
optional=False))
115-
# output layer
116-
self.addParameter(QgsProcessingParameterFeatureSink(
117-
name=self.OUTPUT_PTS,
118-
description=self.tr("Trajectory points"),
119-
type=QgsProcessing.TypeVectorPoint))
120-
self.addParameter(QgsProcessingParameterFeatureSink(
121-
name=self.OUTPUT_TRAJS,
122-
description=self.tr("Trajectories"),
123-
type=QgsProcessing.TypeVectorLine))
124-
125-
def processAlgorithm(self, parameters, context, feedback):
126-
self.input_layer = self.parameterAsSource(parameters, self.INPUT, context)
127-
self.traj_id_field = self.parameterAsFields(parameters, self.TRAJ_ID_FIELD, context)[0]
128-
self.timestamp_field = self.parameterAsFields(parameters, self.TIMESTAMP_FIELD, context)[0]
129-
#timestamp_format = self.parameterAsString(parameters, self.TIMESTAMP_FORMAT, context)
130-
speed_units = self.parameterAsString(parameters, self.SPEED_UNIT, context).split("/")
131-
132-
tc = tc_from_pt_layer(self.input_layer, self.timestamp_field, self.traj_id_field)# , timestamp_format)
133-
tc.add_speed(units=tuple(speed_units), overwrite=True)
134-
tc.add_direction(overwrite=True)
135-
136-
self.dest_pts = self.create_points(parameters, context, tc)
137-
self.dest_trajs = self.create_trajectories(parameters, context, tc)
138-
139-
return {self.OUTPUT_PTS: self.dest_pts, self.OUTPUT_TRAJS: self.dest_trajs}
140-
141-
def postProcessAlgorithm(self, context, feedback):
142-
processed_layer = QgsProcessingUtils.mapLayerFromString(self.dest_pts, context)
143-
processed_layer.loadNamedStyle(os.path.join(pluginPath, "styles", "pts.qml"))
144-
return {self.OUTPUT_PTS: self.dest_pts, self.OUTPUT_TRAJS: self.dest_trajs}
145-
146-
def create_points(self, parameters, context, tc):
147-
fields_pts = get_pt_fields(self.input_layer, self.traj_id_field)
148-
fields_pts.append(QgsField(tc.get_speed_col(), QVariant.Double))
149-
fields_pts.append(QgsField(tc.get_direction_col(), QVariant.Double))
150-
crs = self.input_layer.sourceCrs()
151-
152-
(sink, dest) = self.parameterAsSink(
153-
parameters, self.OUTPUT_PTS, context, fields_pts, QgsWkbTypes.Point, crs)
154-
155-
tc_to_sink(tc, sink, fields_pts, self.timestamp_field)
156-
return dest
157-
158-
def create_trajectories(self, parameters, context, tc):
159-
output_fields_lines = get_traj_fields(self.input_layer, self.traj_id_field)
160-
crs = self.input_layer.sourceCrs()
161-
162-
(sink, dest) = self.parameterAsSink(
163-
parameters, self.OUTPUT_TRAJS, context, output_fields_lines, QgsWkbTypes.LineStringM, crs)
164-
57+
def processTc(self, tc, parameters, context):
58+
tc_to_sink(tc, self.sink_pts, self.fields_pts, self.timestamp_field)
16559
for traj in tc.trajectories:
166-
line = QgsGeometry.fromWkt(traj.to_linestringm_wkt())
167-
f = QgsFeature()
168-
f.setGeometry(line)
169-
f.setAttributes([traj.id])
170-
sink.addFeature(f, QgsFeatureSink.FastInsert)
171-
return dest
172-
60+
traj_to_sink(traj, self.sink_trajs)

qgis_processing/qgisUtils.py

Lines changed: 25 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,4 @@
1-
# -*- coding: utf-8 -*-
2-
3-
"""
4-
***************************************************************************
5-
qgisUtils.py
6-
---------------------
7-
Date : December 2018
8-
Copyright : (C) 2018 by Anita Graser
9-
Email : anitagraser@gmx.at
10-
***************************************************************************
11-
* *
12-
* This program is free software; you can redistribute it and/or modify *
13-
* it under the terms of the GNU General Public License as published by *
14-
* the Free Software Foundation; either version 2 of the License, or *
15-
* (at your option) any later version. *
16-
* *
17-
***************************************************************************
18-
"""
19-
20-
import sys
1+
import sys
212
import pandas as pd
223
from geopandas import GeoDataFrame
234
from PyQt5 import QtCore
@@ -28,11 +9,20 @@
289
sys.path.append("..")
2910

3011
from movingpandas import TrajectoryCollection
31-
from qgis.core import QgsFeature, QgsGeometry, QgsPointXY, QgsFeatureSink, QgsFields, QgsField
12+
from qgis.core import (
13+
QgsFeature,
14+
QgsGeometry,
15+
QgsPointXY,
16+
QgsFeatureSink,
17+
QgsFields,
18+
QgsField,
19+
)
3220
from qgis.PyQt.QtCore import QVariant
3321

3422

35-
def trajectories_from_qgis_point_layer(layer, time_field_name, trajectory_id_field, time_format):
23+
def trajectories_from_qgis_point_layer(
24+
layer, time_field_name, trajectory_id_field, time_format
25+
):
3626
# TODO: remove
3727
return tc_from_pt_layer(layer, time_field_name, trajectory_id_field, time_format)
3828

@@ -45,14 +35,19 @@ def tc_from_pt_layer(layer, time_field_name, trajectory_id_field):
4535
for i, a in enumerate(feature.attributes()):
4636
my_dict[names[i]] = a
4737
pt = feature.geometry().asPoint()
48-
my_dict['geom_x'] = pt.x()
49-
my_dict['geom_y'] = pt.y()
38+
my_dict["geom_x"] = pt.x()
39+
my_dict["geom_y"] = pt.y()
5040
data.append(my_dict)
51-
df = pd.DataFrame(data)
52-
crs = CRS(int(layer.sourceCrs().geographicCrsAuthId().split(':')[1]))
41+
df = pd.DataFrame(data)
42+
crs = CRS(int(layer.sourceCrs().geographicCrsAuthId().split(":")[1]))
5343
tc = TrajectoryCollection(
54-
df, traj_id_col=trajectory_id_field,
55-
x='geom_x', y='geom_y', t=time_field_name, crs=crs)
44+
df,
45+
traj_id_col=trajectory_id_field,
46+
x="geom_x",
47+
y="geom_y",
48+
t=time_field_name,
49+
crs=crs,
50+
)
5651
return tc
5752

5853

@@ -67,34 +62,17 @@ def tc_to_sink(tc, sink, fields, timestamp_field):
6762
gdf = tc.to_point_gdf()
6863
gdf[timestamp_field] = gdf.index.astype(str)
6964
names = [field.name() for field in fields]
70-
names.append('geometry')
65+
names.append("geometry")
7166
gdf = gdf[names]
7267

7368
for _, row in gdf.iterrows():
7469
f = feature_from_gdf_row(row)
7570
sink.addFeature(f, QgsFeatureSink.FastInsert)
7671

72+
7773
def traj_to_sink(traj, sink):
7874
line = QgsGeometry.fromWkt(traj.to_linestringm_wkt())
7975
f = QgsFeature()
8076
f.setGeometry(line)
8177
f.setAttributes([traj.id])
8278
sink.addFeature(f, QgsFeatureSink.FastInsert)
83-
84-
def get_pt_fields(input_layer, traj_id_field):
85-
fields = QgsFields()
86-
for field in input_layer.fields():
87-
if field.name() == "fid":
88-
continue
89-
elif field.name() == traj_id_field: # we need to make sure the ID field is String
90-
fields.append(QgsField(traj_id_field, QVariant.String))
91-
else:
92-
fields.append(field)
93-
return fields
94-
95-
def get_traj_fields(input_layer, traj_id_field):
96-
fields = QgsFields()
97-
fields.append(QgsField(traj_id_field, QVariant.String))
98-
return fields
99-
100-

0 commit comments

Comments
 (0)