Skip to content

Commit c080a6f

Browse files
committed
Bugfix: min_duration and max_speed in trajectory filter
1 parent 7afeff6 commit c080a6f

File tree

1 file changed

+59
-12
lines changed

1 file changed

+59
-12
lines changed

src/dsf/mdt/TrajectoryCollection.cpp

Lines changed: 59 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
#include <tbb/parallel_for_each.h>
1010
#include <tbb/concurrent_set.h>
1111

12+
static constexpr std::time_t SECONDS_IN_MINUTE = 60;
13+
static constexpr std::time_t SECONDS_IN_HOUR = 3600;
14+
1215
namespace dsf::mdt {
1316
TrajectoryCollection::TrajectoryCollection(
1417
std::unordered_map<
@@ -22,11 +25,12 @@ namespace dsf::mdt {
2225
auto const& lats = std::get<std::vector<double>>(dataframe.at("lat"));
2326
auto const& lons = std::get<std::vector<double>>(dataframe.at("lon"));
2427

28+
auto const bbox_set =
29+
!(bbox[0] == 0.0 && bbox[1] == 0.0 && bbox[2] == 0.0 && bbox[3] == 0.0);
30+
2531
for (std::size_t i = 0; i < uids.size(); ++i) {
2632
auto const point = dsf::geometry::Point(lons[i], lats[i]);
2733
// If bbox is the default-initialized array (all zeros) we treat it as unset.
28-
bool bbox_set =
29-
!(bbox[0] == 0.0 && bbox[1] == 0.0 && bbox[2] == 0.0 && bbox[3] == 0.0);
3034
if (bbox_set && (point.x() < bbox[0] || point.x() > bbox[2] ||
3135
point.y() < bbox[1] || point.y() > bbox[3])) {
3236
continue;
@@ -86,11 +90,38 @@ namespace dsf::mdt {
8690
tbb::concurrent_set<Id> to_remove;
8791
tbb::concurrent_set<Id> to_split;
8892

93+
// Returns true if speed between two points is below max_speed_kph
94+
auto check_max_speed = [](PointsCluster const& currentCluster,
95+
PointsCluster const& previousCluster,
96+
double const max_speed_kph) {
97+
auto const distance_km = dsf::geometry::haversine_km(currentCluster.centroid(),
98+
previousCluster.centroid());
99+
auto const current_time =
100+
(currentCluster.lastTimestamp() + currentCluster.firstTimestamp()) * 0.5;
101+
auto const previous_time =
102+
(previousCluster.lastTimestamp() + previousCluster.firstTimestamp()) * 0.5;
103+
if (current_time <= previous_time) {
104+
spdlog::warn(
105+
"Non-increasing timestamps detected. Skipping speed check for these points.");
106+
return true;
107+
}
108+
auto const speed_kph =
109+
(distance_km * SECONDS_IN_HOUR) / (current_time - previous_time);
110+
return speed_kph <= max_speed_kph;
111+
};
112+
// Returns true if cluster duration is below min_duration_min
113+
auto check_min_duration = [](dsf::mdt::PointsCluster const& cluster,
114+
std::time_t const min_duration_min) {
115+
return cluster.duration() < min_duration_min * SECONDS_IN_MINUTE;
116+
};
117+
89118
tbb::parallel_for_each(
90119
m_trajectories.begin(),
91120
m_trajectories.end(),
92121
[&to_remove,
93122
&to_split,
123+
check_max_speed,
124+
check_min_duration,
94125
min_points_per_trajectory,
95126
cluster_radius_km,
96127
max_speed_kph,
@@ -110,14 +141,21 @@ namespace dsf::mdt {
110141
to_remove.insert(uid);
111142
return;
112143
}
113-
if (!min_duration_min.has_value()) {
114-
return;
115-
}
116-
for (auto const& cluster : trajectory.points()) {
117-
if (cluster.duration() < min_duration_min.value() * 60) {
144+
auto const& points{trajectory.points()};
145+
for (std::size_t i = 0; i < points.size(); ++i) {
146+
auto const& currentCluster = points[i];
147+
if (min_duration_min.has_value() &&
148+
!check_min_duration(currentCluster, min_duration_min.value())) {
118149
to_split.insert(uid);
119150
return;
120151
}
152+
if (i > 0) {
153+
auto const& previousCluster = points[i - 1];
154+
if (!check_max_speed(currentCluster, previousCluster, max_speed_kph)) {
155+
to_split.insert(uid);
156+
return;
157+
}
158+
}
121159
}
122160
});
123161

@@ -143,16 +181,25 @@ namespace dsf::mdt {
143181
trajectories.clear();
144182

145183
Trajectory newTrajectory;
146-
for (auto const& cluster : originalTrajectory.points()) {
147-
newTrajectory.addCluster(cluster);
148-
if (cluster.duration() < min_duration_min.value() * 60) {
149-
continue;
184+
auto const& points{originalTrajectory.points()};
185+
for (size_t i = 0; i < points.size(); ++i) {
186+
auto const& currentCluster = points[i];
187+
newTrajectory.addCluster(currentCluster);
188+
189+
bool bShouldSplit = false;
190+
191+
if (i > 0) {
192+
auto const& previousCluster = points[i - 1];
193+
bShouldSplit = !check_max_speed(currentCluster, previousCluster, max_speed_kph);
194+
}
195+
if (min_duration_min.has_value() && !bShouldSplit) {
196+
bShouldSplit = !check_min_duration(currentCluster, min_duration_min.value());
150197
}
151198
// Cluster meets minimum duration - finalize current trajectory and start a new one
152199
if (!newTrajectory.empty()) {
153200
trajectories.emplace_back(std::move(newTrajectory));
154201
newTrajectory = Trajectory();
155-
newTrajectory.addCluster(cluster);
202+
newTrajectory.addCluster(currentCluster);
156203
}
157204
}
158205
if (newTrajectory.size() > 1) {

0 commit comments

Comments
 (0)