1/*
2 * Copyright (c) 2014-2023 National Technology and Engineering
3 * Solutions of Sandia, LLC. Under the terms of Contract DE-NA0003525
4 * with National Technology and Engineering Solutions of Sandia, LLC,
5 * the U.S. Government retains certain rights in this software.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <tracktable/CommandLineFactories/AssemblerFromCommandLine.h>
32#include <tracktable/CommandLineFactories/PointReaderFromCommandLine.h>
33#include <tracktable/Domain/Terrestrial.h>
34
35#include <boost/timer/timer.hpp>
36
37#include <algorithm>
38#include <memory>
39#include <string>
40#include <vector>
41
42using TrajectoryT = tracktable::domain::terrestrial::trajectory_type;
43using PointT = typename TrajectoryT::point_type;
44using PointReaderT = tracktable::PointReader<PointT>;
45using PointReaderIteratorT = typename PointReaderT::iterator;
46using AssemblerT = tracktable::AssembleTrajectories<TrajectoryT, PointReaderIteratorT>;
47
48static constexpr auto helpmsg = R"(
49--------------------------------------------------------------------------------
50The findid example demonstrates:
51 - Using command line factories to read points and assemble trajectories
52 - Reading a list of ids from a file
53 - Searching trajectories for specific object ids
54
55Typical use:
56 ./assemble --input=/data/flights.tsv --idfile=/data/mapping_ids.txt
57
58Defaults assume a tab separated points file formatted as :
59
60OBJECTID TIMESTAMP LON LAT
61
62And an id file with a single object id per line.
63
64Default output is just a count of how many trajectories were found.
65--------------------------------------------------------------------------------)";
66
67int main(int _argc, char* _argv[]) {
68 // Set log level to reduce unecessary output
69 tracktable::set_log_level(tracktable::log::info);
70 // Create a basic command line option with boost
71 boost::program_options::options_description commandLineOptions;
72 // clang-format off
73 commandLineOptions.add_options()
74 ("help", "Print help") // And a command line option for output
75 ("idfile",
76 bpo::value<std::string>()->default_value("mapping-ids.txt"),
77 "file to read ids from")
78 ;
79 // clang-format on
80 // Reader factories, which add lots of command line options
81 tracktable::PointReaderFromCommandLine<PointT> readerFactory;
82 tracktable::AssemblerFromCommandLine<TrajectoryT> assemblerFactory;
83 readerFactory.addOptions(commandLineOptions);
84 assemblerFactory.addOptions(commandLineOptions);
85 /** Boost program options using a variable map to tie everything together.
86 * one parse will have a single variable map. We need to let the factories know
87 * about this variable map so they can pull information out of it */
88 auto vm = std::make_shared<boost::program_options::variables_map>();
89 readerFactory.setVariables(vm);
90 assemblerFactory.setVariables(vm);
91 // Parse the command lines, don't forget the 'notify' after
92 try {
93 boost::program_options::store(
94 boost::program_options::command_line_parser(_argc, _argv).options(commandLineOptions).run(), *vm);
95 boost::program_options::notify(*vm);
96 } catch (boost::program_options::error& e) {
97 std::cerr << helpmsg << "\n\n" << e.what() << "\n\n" << commandLineOptions << std::endl;
98 return 1;
99 }
100 /** Parsing will give an error of an incorrect option is used, but it won't
101 * display the help unless we tell it too */
102 if (vm->count("help") != 0) {
103 std::cerr << helpmsg << commandLineOptions << std::endl;
104 return 1;
105 }
106
107 // Create Point Reader and assembler
108 auto pointReader = readerFactory.createPointReader();
109 auto assembler = assemblerFactory.createAssembler(pointReader);
110
111 std::vector<std::shared_ptr<TrajectoryT>> trajectories = {};
112 {
113 std::cerr << "Assemble Trajectories" << std::endl;
114 boost::timer::auto_cpu_timer assembleTimer(std::cerr);
115 auto count = 0u;
116 std::cerr << std::right;
117 for (auto tIter = assembler->begin(); tIter != assembler->end(); ++tIter) {
118 std::cerr << "\b\b\b\b\b\b\b\b\b\b" << std::setw(10) // Using backspaces for in place counter
119 << count++;
120 trajectories.push_back(std::make_shared<TrajectoryT>(*tIter));
121 }
122 std::cerr << std::left << "\nStarting with " << trajectories.size() << " trajectories" << std::endl;
123 }
124
125 // Read ObjectIds from file
126 auto fileName = (*vm)["idfile"].as<std::string>();
127 std::vector<std::string> idList;
128 {
129 boost::timer::auto_cpu_timer searchTimer(std::cerr);
130 std::ifstream idFile(fileName);
131 if (!idFile.is_open()) {
132 std::cerr << "Could not open id file: " << fileName << std::endl;
133 }
134 std::string id;
135 while (std::getline(idFile, id)) {
136 std::cerr << id << std::endl;
137 idList.push_back(id);
138 }
139 std::sort(idList.begin(), idList.end());
140 std::cerr << idList.size() << " ids found" << std::endl;
141 }
142
143 // separate the trajectories based on whether they are on the id list.
144 std::vector<std::shared_ptr<TrajectoryT>> foundTrajectories;
145
146 /*Copy everything except where the lambda is true, this is an alternative to copy_if
147 think of remove_copy_if as dont_copy_if; It only copies if the function returns false*/
148 std::remove_copy_if(trajectories.begin(), trajectories.end(), std::back_inserter(foundTrajectories),
149 [&idList /*capture idList*/](const std::shared_ptr<TrajectoryT>& _t) {
150 // search idList for current object id
151 return !std::binary_search(idList.begin(), idList.end(), _t->object_id());
152 });
153
154 /*Remove the copied trajectories, remove_if shifts all unwanted entries to the end of vector and returns
155 an iterator to the first 'bad' element, erase takes that iterator and deletes everything after it, the
156 lambda is similar to that used above, but is missing the negation(!) and operating on a separate
157 vector*/
158 std::sort(foundTrajectories.begin(), foundTrajectories.end());
159 trajectories.erase(std::remove_if(trajectories.begin(), trajectories.end(),
160 [&foundTrajectories](const std::shared_ptr<TrajectoryT>& _t) {
161 return std::binary_search(foundTrajectories.begin(),
162 foundTrajectories.end(), _t);
163 }),
164 trajectories.end());
165
166 std::cout << "trajectories.size() = " << trajectories.size() << std::endl;
167 std::cout << "foundTrajectories.size() = " << foundTrajectories.size() << std::endl;
168
169 return 0;
170}