Skip to content

Commit 10da09c

Browse files
committed
Add ExtractODPtsAlgorithm
1 parent 3017989 commit 10da09c

File tree

6 files changed

+169
-54
lines changed

6 files changed

+169
-54
lines changed

qgis_processing/createTrajectoriesAlgorithm.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,16 @@
44

55
sys.path.append("..")
66

7-
from .trajectoriesAlgorithm import TrajectoriesAlgorithm
7+
from .trajectoriesAlgorithm import TrajectoryManipulationAlgorithm
88

99

10-
class CreateTrajectoriesAlgorithm(TrajectoriesAlgorithm):
10+
class CreateTrajectoriesAlgorithm(TrajectoryManipulationAlgorithm):
1111
def __init__(self):
1212
super().__init__()
1313

1414
def name(self):
1515
return "create_trajectory"
1616

17-
def tr(self, text):
18-
return QCoreApplication.translate("create_trajectory", text)
19-
2017
def displayName(self):
2118
return self.tr("Create trajectories")
2219

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import sys
2+
3+
import shapely.wkt
4+
from shapely.geometry import Polygon
5+
6+
from qgis.PyQt.QtCore import QCoreApplication, QVariant
7+
from qgis.core import (
8+
QgsProcessingParameterExtent,
9+
QgsProcessingParameterVectorLayer,
10+
QgsProcessingParameterFeatureSink,
11+
QgsProcessing,
12+
QgsWkbTypes,
13+
QgsField,
14+
QgsFeatureSink,
15+
)
16+
from qgis.core import QgsMessageLog, Qgis
17+
18+
sys.path.append("..")
19+
20+
from .trajectoriesAlgorithm import TrajectoriesAlgorithm
21+
from .qgisUtils import feature_from_gdf_row
22+
23+
24+
class ExtractODPtsAlgorithm(TrajectoriesAlgorithm):
25+
ORIGIN_PTS = "ORIGIN_PTS"
26+
DESTINATIONS_PTS = "DESTINATIONS_PTS"
27+
28+
def __init__(self):
29+
super().__init__()
30+
31+
def initAlgorithm(self, config=None):
32+
super().initAlgorithm(config)
33+
self.addParameter(
34+
QgsProcessingParameterFeatureSink(
35+
name=self.ORIGIN_PTS,
36+
description=self.tr("Origin points"),
37+
type=QgsProcessing.TypeVectorPoint,
38+
)
39+
)
40+
self.addParameter(
41+
QgsProcessingParameterFeatureSink(
42+
name=self.DESTINATIONS_PTS,
43+
description=self.tr("Destination points"),
44+
type=QgsProcessing.TypeVectorPoint,
45+
)
46+
)
47+
48+
def group(self):
49+
return self.tr("Basic")
50+
51+
def groupId(self):
52+
return "TrajectoryBasic"
53+
54+
def name(self):
55+
return "extract_od_pts"
56+
57+
def displayName(self):
58+
return self.tr("Extract OD points")
59+
60+
def shortHelpString(self):
61+
return self.tr("<p>Extracts start and/or end points of trajectories.</p>")
62+
63+
def processAlgorithm(self, parameters, context, feedback):
64+
tc, crs = self.create_tc(parameters, context)
65+
66+
self.fields_pts = self.get_pt_fields(
67+
[
68+
QgsField(tc.get_speed_col(), QVariant.Double),
69+
QgsField(tc.get_direction_col(), QVariant.Double),
70+
],
71+
)
72+
(self.sink_orig, self.orig_pts) = self.parameterAsSink(
73+
parameters,
74+
self.ORIGIN_PTS,
75+
context,
76+
self.fields_pts,
77+
QgsWkbTypes.Point,
78+
crs,
79+
)
80+
(self.sink_dest, self.dest_pts) = self.parameterAsSink(
81+
parameters,
82+
self.DESTINATIONS_PTS,
83+
context,
84+
self.fields_pts,
85+
QgsWkbTypes.Point,
86+
crs,
87+
)
88+
89+
self.processTc(tc, parameters, context)
90+
91+
return {self.ORIGIN_PTS: self.orig_pts, self.DESTINATIONS_PTS: self.dest_pts}
92+
93+
def processTc(self, tc, parameters, context):
94+
try:
95+
gdf = tc.get_start_locations()
96+
except ValueError: # when the tc is empty
97+
return
98+
gdf = gdf.convert_dtypes()
99+
gdf[self.timestamp_field] = gdf["t"].astype(str)
100+
names = [field.name() for field in self.fields_pts]
101+
names.append("geometry")
102+
gdf = gdf[names]
103+
# QgsMessageLog.logMessage(str(gdf), "Trajectools", level=Qgis.Info )
104+
105+
for _, row in gdf.iterrows():
106+
f = feature_from_gdf_row(row)
107+
self.sink_orig.addFeature(f, QgsFeatureSink.FastInsert)
108+
109+
gdf = tc.get_end_locations()
110+
gdf = gdf.convert_dtypes()
111+
gdf[self.timestamp_field] = gdf["t"].astype(str)
112+
gdf = gdf[names]
113+
114+
for _, row in gdf.iterrows():
115+
f = feature_from_gdf_row(row)
116+
self.sink_dest.addFeature(f, QgsFeatureSink.FastInsert)

qgis_processing/overlayAlgorithm.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@
1111

1212
sys.path.append("..")
1313

14-
from .trajectoriesAlgorithm import TrajectoriesAlgorithm
14+
from .trajectoriesAlgorithm import TrajectoryManipulationAlgorithm
1515

1616

17-
class OverlayTrajectoriesAlgorithm(TrajectoriesAlgorithm):
17+
class OverlayTrajectoriesAlgorithm(TrajectoryManipulationAlgorithm):
1818
def __init__(self):
1919
super().__init__()
2020

@@ -42,9 +42,6 @@ def initAlgorithm(self, config=None):
4242
def name(self):
4343
return "clip_traj_extent"
4444

45-
def tr(self, text):
46-
return QCoreApplication.translate("clip_traj_extent", text)
47-
4845
def displayName(self):
4946
return self.tr("Clip trajectories by extent")
5047

@@ -90,9 +87,6 @@ def initAlgorithm(self, config=None):
9087
def name(self):
9188
return "clip_traj_vector"
9289

93-
def tr(self, text):
94-
return QCoreApplication.translate("clip_traj_vector", text)
95-
9690
def displayName(self):
9791
return self.tr("Clip trajectories by polygon layer")
9892

qgis_processing/splitTrajectoriesAlgorithm.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@
1111

1212
sys.path.append("..")
1313

14-
from .trajectoriesAlgorithm import TrajectoriesAlgorithm
14+
from .trajectoriesAlgorithm import TrajectoryManipulationAlgorithm
1515

1616

17-
class SplitTrajectoriesAlgorithm(TrajectoriesAlgorithm):
17+
class SplitTrajectoriesAlgorithm(TrajectoryManipulationAlgorithm):
1818
def __init__(self):
1919
super().__init__()
2020

qgis_processing/trajectoolsProvider.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
ClipTrajectoriesByExtentAlgorithm,
1919
ClipTrajectoriesByPolygonLayer,
2020
)
21+
from .extractPtsAlgorithm import ExtractODPtsAlgorithm
2122

2223
pluginPath = os.path.dirname(__file__)
2324

@@ -57,6 +58,7 @@ def getAlgs(self):
5758
StopSplitterAlgorithm(),
5859
ClipTrajectoriesByExtentAlgorithm(),
5960
ClipTrajectoriesByPolygonLayer(),
61+
ExtractODPtsAlgorithm(),
6062
]
6163
return algs
6264

qgis_processing/trajectoriesAlgorithm.py

Lines changed: 45 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,9 @@
3535

3636

3737
class TrajectoriesAlgorithm(QgsProcessingAlgorithm):
38-
# script parameters
3938
INPUT = "INPUT"
4039
TRAJ_ID_FIELD = "TRAJ_ID_FIELD"
4140
TIMESTAMP_FIELD = "TIME_FIELD"
42-
OUTPUT_PTS = "OUTPUT_PTS"
43-
OUTPUT_SEGS = "OUTPUT_SEGS"
44-
OUTPUT_TRAJS = "OUTPUT_TRAJS"
4541
SPEED_UNIT = "SPEED_UNIT"
4642

4743
def __init__(self):
@@ -51,7 +47,7 @@ def icon(self):
5147
return QIcon(os.path.join(pluginPath, "icons", "icon.png"))
5248

5349
def tr(self, text):
54-
return QCoreApplication.translate("split_traj", text)
50+
return QCoreApplication.translate("trajectools", text)
5551

5652
def helpUrl(self):
5753
return "https://github.com/movingpandas/processing-trajectory"
@@ -60,15 +56,13 @@ def createInstance(self):
6056
return type(self)()
6157

6258
def initAlgorithm(self, config=None):
63-
# input layer
6459
self.addParameter(
6560
QgsProcessingParameterFeatureSource(
6661
name=self.INPUT,
6762
description=self.tr("Input point layer"),
6863
types=[QgsProcessing.TypeVectorPoint],
6964
)
7065
)
71-
# fields
7266
self.addParameter(
7367
QgsProcessingParameterField(
7468
name=self.TRAJ_ID_FIELD,
@@ -99,23 +93,8 @@ def initAlgorithm(self, config=None):
9993
optional=False,
10094
)
10195
)
102-
# output layer
103-
self.addParameter(
104-
QgsProcessingParameterFeatureSink(
105-
name=self.OUTPUT_PTS,
106-
description=self.tr("Trajectory points"),
107-
type=QgsProcessing.TypeVectorPoint,
108-
)
109-
)
110-
self.addParameter(
111-
QgsProcessingParameterFeatureSink(
112-
name=self.OUTPUT_TRAJS,
113-
description=self.tr("Trajectories"),
114-
type=QgsProcessing.TypeVectorLine,
115-
)
116-
)
11796

118-
def processAlgorithm(self, parameters, context, feedback):
97+
def create_tc(self, parameters, context):
11998
self.input_layer = self.parameterAsSource(parameters, self.INPUT, context)
12099
self.traj_id_field = self.parameterAsFields(
121100
parameters, self.TRAJ_ID_FIELD, context
@@ -133,6 +112,49 @@ def processAlgorithm(self, parameters, context, feedback):
133112
)
134113
tc.add_speed(units=tuple(self.speed_units), overwrite=True)
135114
tc.add_direction(overwrite=True)
115+
return tc, crs
116+
117+
def get_pt_fields(self, fields_to_add=[]):
118+
fields = QgsFields()
119+
for field in self.input_layer.fields():
120+
if field.name() == "fid":
121+
continue
122+
elif field.name() == self.traj_id_field:
123+
# we need to make sure the ID field is String
124+
fields.append(QgsField(self.traj_id_field, QVariant.String))
125+
else:
126+
fields.append(field)
127+
for field in fields_to_add:
128+
i = fields.indexFromName(field.name())
129+
if i < 0:
130+
fields.append(field)
131+
return fields
132+
133+
134+
class TrajectoryManipulationAlgorithm(TrajectoriesAlgorithm):
135+
OUTPUT_PTS = "OUTPUT_PTS"
136+
OUTPUT_SEGS = "OUTPUT_SEGS"
137+
OUTPUT_TRAJS = "OUTPUT_TRAJS"
138+
139+
def initAlgorithm(self, config=None):
140+
super().initAlgorithm(config)
141+
self.addParameter(
142+
QgsProcessingParameterFeatureSink(
143+
name=self.OUTPUT_PTS,
144+
description=self.tr("Trajectory points"),
145+
type=QgsProcessing.TypeVectorPoint,
146+
)
147+
)
148+
self.addParameter(
149+
QgsProcessingParameterFeatureSink(
150+
name=self.OUTPUT_TRAJS,
151+
description=self.tr("Trajectories"),
152+
type=QgsProcessing.TypeVectorLine,
153+
)
154+
)
155+
156+
def processAlgorithm(self, parameters, context, feedback):
157+
tc, crs = self.create_tc(parameters, context)
136158

137159
self.fields_pts = self.get_pt_fields(
138160
[
@@ -173,22 +195,6 @@ def postProcessAlgorithm(self, context, feedback):
173195
traj_layer.loadNamedStyle(os.path.join(pluginPath, "styles", "traj.qml"))
174196
return {self.OUTPUT_PTS: self.dest_pts, self.OUTPUT_TRAJS: self.dest_trajs}
175197

176-
def get_pt_fields(self, fields_to_add=[]):
177-
fields = QgsFields()
178-
for field in self.input_layer.fields():
179-
if field.name() == "fid":
180-
continue
181-
elif field.name() == self.traj_id_field:
182-
# we need to make sure the ID field is String
183-
fields.append(QgsField(self.traj_id_field, QVariant.String))
184-
else:
185-
fields.append(field)
186-
for field in fields_to_add:
187-
i = fields.indexFromName(field.name())
188-
if i < 0:
189-
fields.append(field)
190-
return fields
191-
192198
def get_traj_fields(self):
193199
length_units = f"{self.speed_units[0]}"
194200
speed_units = f"{self.speed_units[0]}{self.speed_units[1]}"

0 commit comments

Comments
 (0)