Skip to content

Commit a18cfc7

Browse files
committed
use efficient methods to delete trkpts in track filter.
1 parent 9bf15c6 commit a18cfc7

File tree

2 files changed

+91
-97
lines changed

2 files changed

+91
-97
lines changed

trackfilter.cc

Lines changed: 90 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
static constexpr bool TRACKF_DBG = false;
2424

25+
#include <algorithm> // for for_each
2526
#include <cassert> // for assert
2627
#include <cmath> // for nan
2728
#include <cstdio> // for printf
@@ -195,10 +196,6 @@ void TrackFilter::trackfilter_fill_track_list_cb(const route_head* track) /* ca
195196
fatal(FatalMsg() << "track: name option is an invalid expression.");
196197
}
197198
if (!regex.match(track->rte_name).hasMatch()) {
198-
foreach (Waypoint* wpt, track->waypoint_list) {
199-
track_del_wpt(const_cast<route_head*>(track), wpt);
200-
delete wpt;
201-
}
202199
track_del_head(const_cast<route_head*>(track));
203200
return;
204201
}
@@ -329,11 +326,20 @@ void TrackFilter::trackfilter_pack()
329326

330327
route_head* master = track_list.first();
331328

329+
if (!master->waypoint_list.empty()) {
330+
std::for_each(std::next(master->waypoint_list.cbegin()), master->waypoint_list.cend(),
331+
[](Waypoint* wpt)->void {wpt->wpt_flags.new_trkseg = 0;});
332+
}
333+
332334
while (track_list.size() > 1) {
333335
route_head* curr = track_list.takeAt(1);
334336

335-
foreach (Waypoint* wpt, curr->waypoint_list) {
336-
track_del_wpt(curr, wpt);
337+
// Steal all the waypoints
338+
WaypointList curr_wpts;
339+
track_swap_wpts(curr, curr_wpts);
340+
// And add them to the master
341+
foreach (Waypoint* wpt, curr_wpts) {
342+
wpt->wpt_flags.new_trkseg = 0;
337343
track_add_wpt(master, wpt);
338344
}
339345
track_del_head(curr);
@@ -357,15 +363,16 @@ void TrackFilter::trackfilter_merge()
357363
auto it = track_list.begin();
358364
while (it != track_list.end()) { /* put all points into temp buffer */
359365
route_head* track = *it;
360-
foreach (Waypoint* wpt, track->waypoint_list) {
361-
track_del_wpt(track, wpt); /* copies any new_trkseg flag forward, and clears new_trkseg flag. */
366+
// steal all the wpts
367+
WaypointList wpts;
368+
track_swap_wpts(track, wpts);
369+
// add them to the buff or delete them
370+
foreach (Waypoint* wpt, wpts) {
362371
if (wpt->creation_time.isValid()) {
363372
// we will put the merged points in one track segment,
364373
// as it isn't clear how track segments in the original tracks
365374
// should relate to the merged track.
366-
// track_del_wpt cleared new_trkseg flag for wpt.
367-
// track_add_wpt will set new_trkseg for the first point
368-
// added to a track.
375+
wpt->wpt_flags.new_trkseg = 0;
369376
buff.append(wpt);
370377
} else {
371378
delete wpt;
@@ -416,16 +423,13 @@ void TrackFilter::trackfilter_split()
416423
fatal(MYNAME "-split: Cannot split more than one track, please pack (or merge) before!\n");
417424
} else if (!track_list.isEmpty()) {
418425
route_head* master = track_list.first();
419-
int count = master->rte_waypt_ct();
426+
if (master->rte_waypt_ct() <= 1) {
427+
return;
428+
}
420429

421-
int i, j;
422430
double interval = -1; /* seconds */
423431
double distance = -1; /* meters */
424432

425-
if (count <= 1) {
426-
return;
427-
}
428-
429433
/* check additional options */
430434

431435
opt_interval = (opt_split && (strlen(opt_split) > 0) && (0 != strcmp(opt_split, TRACKFILTER_SPLIT_OPTION)));
@@ -495,36 +499,41 @@ void TrackFilter::trackfilter_split()
495499
}
496500
}
497501

498-
QList<Waypoint*> buff;
502+
// steal all the waypoints
503+
WaypointList buff;
504+
track_swap_wpts(master, buff);
505+
assert(!buff.empty()); // enforced above
499506

500-
foreach (Waypoint* wpt, master->waypoint_list) {
501-
buff.append(wpt);
502-
}
507+
trackfilter_split_init_rte_name(master, buff.front()->GetCreationTime());
503508

504-
trackfilter_split_init_rte_name(master, buff.at(0)->GetCreationTime());
509+
route_head* curr = master; /* will be reset by first new track */
505510

506-
route_head* curr = nullptr; /* will be set by first new track */
511+
// add the first waypoint to the first track
512+
track_add_wpt(curr, buff.front());
513+
// and add subsequent waypoints to the first track or a new track
514+
for (auto prev_it = buff.cbegin(), it = std::next(buff.cbegin()); it != buff.cend(); ++prev_it, ++it) {
515+
Waypoint* prev_wpt = *prev_it;
516+
Waypoint* wpt = *it;
507517

508-
for (i=0, j=1; j<count; i++, j++) {
509518
bool new_track_flag;
510519

511520
if ((opt_interval == 0) && (opt_distance == 0)) {
512-
// FIXME: This whole function needs to be reconsidered for arbitrary time.
513-
new_track_flag = buff.at(i)->GetCreationTime().toLocalTime().date() !=
514-
buff.at(j)->GetCreationTime().toLocalTime().date();
521+
// FIXME: This whole function needs to be reconsidered for arbitrary time.
522+
new_track_flag = prev_wpt->GetCreationTime().toLocalTime().date() !=
523+
wpt->GetCreationTime().toLocalTime().date();
515524
if constexpr(TRACKF_DBG) {
516525
if (new_track_flag) {
517-
printf(MYNAME ": new day %s\n", qPrintable(buff.at(j)->GetCreationTime().toLocalTime().date().toString(Qt::ISODate)));
526+
printf(MYNAME ": new day %s\n", qPrintable(wpt->GetCreationTime().toLocalTime().date().toString(Qt::ISODate)));
518527
}
519528
}
520529
} else {
521530
new_track_flag = true;
522531

523532
if (distance > 0) {
524-
double rt1 = RAD(buff.at(i)->latitude);
525-
double rn1 = RAD(buff.at(i)->longitude);
526-
double rt2 = RAD(buff.at(j)->latitude);
527-
double rn2 = RAD(buff.at(j)->longitude);
533+
double rt1 = RAD(prev_wpt->latitude);
534+
double rn1 = RAD(prev_wpt->longitude);
535+
double rt2 = RAD(wpt->latitude);
536+
double rn2 = RAD(wpt->longitude);
528537
double curdist = gcdist(rt1, rn1, rt2, rn2);
529538
curdist = radtometers(curdist);
530539
if (curdist <= distance) {
@@ -535,7 +544,7 @@ void TrackFilter::trackfilter_split()
535544
}
536545

537546
if (interval > 0) {
538-
double tr_interval = 0.001 * buff.at(i)->GetCreationTime().msecsTo(buff.at(j)->GetCreationTime());
547+
double tr_interval = 0.001 * prev_wpt->GetCreationTime().msecsTo(wpt->GetCreationTime());
539548
if (tr_interval <= interval) {
540549
new_track_flag = false;
541550
} else if constexpr(TRACKF_DBG) {
@@ -549,14 +558,12 @@ void TrackFilter::trackfilter_split()
549558
printf(MYNAME ": splitting new track\n");
550559
}
551560
curr = new route_head;
552-
trackfilter_split_init_rte_name(curr, buff.at(j)->GetCreationTime());
561+
trackfilter_split_init_rte_name(curr, wpt->GetCreationTime());
553562
track_add_head(curr);
554563
track_list.append(curr);
555564
}
556-
if (curr != nullptr) {
557-
track_del_wpt(master, buff.at(j));
558-
track_add_wpt(curr, buff.at(j));
559-
}
565+
wpt->wpt_flags.new_trkseg = 0;
566+
track_add_wpt(curr, wpt);
560567
}
561568
}
562569
}
@@ -728,10 +735,11 @@ void TrackFilter::trackfilter_range()
728735
}
729736

730737
if (!inside) {
731-
track_del_wpt(track, wpt);
732-
delete wpt;
738+
wpt->wpt_flags.marked_for_deletion = 1;
733739
}
734740
}
741+
// delete marked wpts
742+
track_del_marked_wpts(track);
735743

736744
if (track->rte_waypt_empty()) {
737745
track_del_head(track);
@@ -756,12 +764,17 @@ void TrackFilter::trackfilter_seg2trk()
756764
QList<route_head*> new_track_list;
757765
for (auto* src : qAsConst(track_list)) {
758766
new_track_list.append(src);
759-
route_head* dest = nullptr;
767+
route_head* dest = src;
760768
route_head* insert_point = src;
761769
int trk_seg_num = 1;
762770
bool first = true;
763771

764-
foreach (Waypoint* wpt, src->waypoint_list) {
772+
// steal all the waypoints from the src
773+
WaypointList src_wpts;
774+
track_swap_wpts(src, src_wpts);
775+
776+
// and add them back to the original or a new route_head.
777+
foreach (Waypoint* wpt, src_wpts) {
765778
if (wpt->wpt_flags.new_trkseg && !first) {
766779

767780
dest = new route_head;
@@ -778,18 +791,7 @@ void TrackFilter::trackfilter_seg2trk()
778791
new_track_list.append(dest);
779792
}
780793

781-
/* If we found a track separator, transfer from original to
782-
* new track. We have to reset new_trkseg temporarily to
783-
* prevent track_del_wpt() from copying it to the next track
784-
* point.
785-
*/
786-
if (dest) {
787-
unsigned orig_new_trkseg = wpt->wpt_flags.new_trkseg;
788-
wpt->wpt_flags.new_trkseg = 0;
789-
track_del_wpt(src, wpt);
790-
wpt->wpt_flags.new_trkseg = orig_new_trkseg;
791-
track_add_wpt(dest, wpt);
792-
}
794+
track_add_wpt(dest, wpt);
793795
first = false;
794796
}
795797
}
@@ -809,13 +811,12 @@ void TrackFilter::trackfilter_trk2seg()
809811
while (track_list.size() > 1) {
810812
route_head* curr = track_list.takeAt(1);
811813

814+
// steal all the wpts
815+
WaypointList curr_wpts;
816+
track_swap_wpts(curr, curr_wpts);
817+
// and add them to the master
812818
bool first = true;
813-
foreach (Waypoint* wpt, curr->waypoint_list) {
814-
815-
unsigned orig_new_trkseg = wpt->wpt_flags.new_trkseg;
816-
wpt->wpt_flags.new_trkseg = 0;
817-
track_del_wpt(curr, wpt);
818-
wpt->wpt_flags.new_trkseg = orig_new_trkseg;
819+
foreach (Waypoint* wpt, curr_wpts) {
819820
track_add_wpt(master, wpt);
820821
if (first) {
821822
wpt->wpt_flags.new_trkseg = 1;
@@ -888,18 +889,11 @@ void TrackFilter::trackfilter_faketime()
888889

889890
bool TrackFilter::trackfilter_points_are_same(const Waypoint* wpta, const Waypoint* wptb)
890891
{
891-
// We use a simpler (non great circle) test for lat/lon here as this
892-
// is used for keeping the 'bookends' of non-moving points.
893-
//
894-
// Latitude spacing is about 27 feet per .00001 degree.
895-
// Longitude spacing varies, but the reality is that anything closer
896-
// than 27 feet does little but clutter the output.
897-
// As this is about the limit of consumer grade GPS, it seems a
898-
// reasonable tradeoff.
899-
900892
return
901-
std::abs(wpta->latitude - wptb->latitude) < .00001 &&
902-
std::abs(wpta->longitude - wptb->longitude) < .00001 &&
893+
radtometers(gcdist(RAD(wpta->latitude),
894+
RAD(wpta->longitude),
895+
RAD(wptb->latitude),
896+
RAD(wptb->longitude))) < kDistanceLimit &&
903897
std::abs(wpta->altitude - wptb->altitude) < 20 &&
904898
wpta->courses_equal(*wptb) &&
905899
wpta->speeds_equal(*wptb) &&
@@ -911,46 +905,45 @@ bool TrackFilter::trackfilter_points_are_same(const Waypoint* wpta, const Waypoi
911905
void TrackFilter::trackfilter_segment_head(const route_head* rte)
912906
{
913907
double avg_dist = 0;
914-
int index = 0;
915908
Waypoint* prev_wpt = nullptr;
916-
// Consider tossing trackpoints closer than this in radians.
917-
// (Empirically determined; It's a few dozen feet.)
918-
const double ktoo_close = 0.000005;
919909

920-
const auto wptlist = rte->waypoint_list; // track_del_wpt will modify rte->waypoint_list
910+
const auto wptlist = rte->waypoint_list;
921911
for (auto it = wptlist.cbegin(); it != wptlist.cend(); ++it) {
922912
auto* wpt = *it;
923-
if (index > 0) {
924-
double cur_dist = gcdist(RAD(prev_wpt->latitude),
925-
RAD(prev_wpt->longitude),
926-
RAD(wpt->latitude),
927-
RAD(wpt->longitude));
928-
// Denoise points that are on top of each other.
929-
if (avg_dist == 0) {
930-
avg_dist = cur_dist;
931-
}
932-
933-
if (cur_dist < ktoo_close) {
934-
if (wpt != wptlist.back()) {
935-
auto* next_wpt = *std::next(it);
913+
if (it != wptlist.cbegin()) {
914+
double cur_dist = radtometers(gcdist(RAD(prev_wpt->latitude),
915+
RAD(prev_wpt->longitude),
916+
RAD(wpt->latitude),
917+
RAD(wpt->longitude)));
918+
919+
// Denoise points that are on top of each other,
920+
// keeping the first and last of the group.
921+
if (cur_dist < kDistanceLimit) {
922+
if (auto next_it = std::next(it); next_it != wptlist.cend()) {
923+
auto* next_wpt = *next_it;
936924
if (trackfilter_points_are_same(prev_wpt, wpt) &&
937925
trackfilter_points_are_same(wpt, next_wpt)) {
938-
track_del_wpt(const_cast<route_head*>(rte), wpt);
939-
delete wpt;
940-
continue;
926+
wpt->wpt_flags.marked_for_deletion = 1;
927+
continue; // without updating prev_wpt, the first in the group.
941928
}
942929
}
943930
}
944-
if (cur_dist > .001 && cur_dist > 1.2* avg_dist) {
945-
avg_dist = cur_dist = 0;
931+
932+
if (avg_dist == 0) {
933+
avg_dist = cur_dist;
934+
}
935+
936+
if (cur_dist > 6378.14 && cur_dist > 1.2 * avg_dist) {
937+
avg_dist = 0;
946938
wpt->wpt_flags.new_trkseg = 1;
939+
} else {
940+
// Update weighted moving average;
941+
avg_dist = (cur_dist + 4.0 * avg_dist) / 5.0;
947942
}
948-
// Update weighted moving average;
949-
avg_dist = (cur_dist + 4.0 * avg_dist) / 5.0;
950943
}
951944
prev_wpt = wpt;
952-
index++;
953945
}
946+
track_del_marked_wpts(const_cast<route_head*>(rte));
954947
}
955948

956949
/*******************************************************************************

trackfilter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ class TrackFilter:public Filter
5656

5757
/* Constants */
5858

59+
static constexpr double kDistanceLimit = 1.11319; // for points to be considered the same, meters.
5960
static constexpr char TRACKFILTER_PACK_OPTION[] = "pack";
6061
static constexpr char TRACKFILTER_SPLIT_OPTION[] = "split";
6162
static constexpr char TRACKFILTER_SDIST_OPTION[] = "sdistance";

0 commit comments

Comments
 (0)