9
9
#include < filesystem>
10
10
#include < fstream>
11
11
#include < iterator>
12
+ #include < map>
13
+ #include < set>
14
+ #include < string>
12
15
13
16
namespace OpenSim {
14
17
15
18
XsensDataReader* XsensDataReader::clone () const {
16
19
return new XsensDataReader{*this };
17
20
}
18
21
19
- const std::map<std::string, std::set<std::string>> XsensDataReader::_accepted_headers = {
20
- {" accelerometer" , {" Acc_X" , " Acc_Y" , " Acc_Z" }},
21
- {" gyroscope" , {" Gyr_X" , " Gyr_Y" , " Gyr_Z" }},
22
- {" magnetometer" , {" Mag_X" , " Mag_Y" , " Mag_Z" }},
23
- {" rot_quaternion" , {" Quat_q0" , " Quat_q1" , " Quat_q2" , " Quat_q3" }},
24
- {" rot_euler" , {" Roll" , " Pitch" , " Yaw" }},
25
- {" rot_matrix" , {" Mat[1][1]" , " Mat[2][1]" , " Mat[3][1]" , " Mat[1][2]" ,
26
- " Mat[2][2]" , " Mat[3][2]" , " Mat[1][3]" ,
27
- " Mat[2][3]" , " Mat[3][3]" }}};
28
-
29
22
DataAdapter::OutputTables XsensDataReader::extendRead (
30
23
const std::string& folderName) const {
31
24
32
- std::vector<std::ifstream*> imuStreams;
25
+ // This encapsulates all the accepted headers and their groups
26
+ const static std::map<std::string, std::set<std::string>>
27
+ _accepted_headers = {{" accelerometer" , {" Acc_X" , " Acc_Y" , " Acc_Z" }},
28
+ {" gyroscope" , {" Gyr_X" , " Gyr_Y" , " Gyr_Z" }},
29
+ {" magnetometer" , {" Mag_X" , " Mag_Y" , " Mag_Z" }},
30
+ {" rot_quaternion" ,
31
+ {" Quat_q0" , " Quat_q1" , " Quat_q2" , " Quat_q3" }},
32
+ {" rot_euler" , {" Roll" , " Pitch" , " Yaw" }},
33
+ {" rot_matrix" ,
34
+ {" Mat[1][1]" , " Mat[2][1]" , " Mat[3][1]" , " Mat[1][2]" ,
35
+ " Mat[2][2]" , " Mat[3][2]" , " Mat[1][3]" ,
36
+ " Mat[2][3]" , " Mat[3][3]" }}};
37
+
38
+ std::vector<std::unique_ptr<std::ifstream>> imuStreams;
33
39
std::vector<std::string> labels;
34
40
// files specified by prefix + file name exist
35
41
double dataRate = _settings.get_sampling_rate ();
@@ -44,25 +50,18 @@ DataAdapter::OutputTables XsensDataReader::extendRead(
44
50
45
51
std::string prefix = _settings.get_trial_prefix ();
46
52
std::map<std::string, std::string> headersKeyValuePairs;
47
- // Map to store the headers and their column indices by group
48
- std::map<std::string, std::set<std::pair<std::string, size_t >>>
49
- presentGroupsWithColumnIndices;
50
-
51
53
std::map<std::string, size_t > h_map;
54
+
52
55
for (int index = 0 ; index < n_imus; ++index ) {
53
56
std::string prefix = _settings.get_trial_prefix ();
54
57
const ExperimentalSensor& nextItem =
55
58
_settings.get_ExperimentalSensors (index );
56
59
const std::filesystem::path fileName =
57
60
std::filesystem::path (folderName) /
58
61
(prefix + nextItem.getName () + extension);
59
- auto * nextStream = new std::ifstream{ fileName} ;
62
+ auto nextStream = std::make_unique<std:: ifstream>( fileName) ;
60
63
61
64
OPENSIM_THROW_IF (!nextStream->good (), FileDoesNotExist, fileName);
62
- // Add imu name to labels
63
- labels.push_back (nextItem.get_name_in_model ());
64
- // Add corresponding stream to imuStreams
65
- imuStreams.push_back (nextStream);
66
65
67
66
// Skip lines to get to data
68
67
std::string line;
@@ -90,58 +89,69 @@ DataAdapter::OutputTables XsensDataReader::extendRead(
90
89
// Find indices for Acc_{X,Y,Z}, Gyr_{X,Y,Z},
91
90
// Mag_{X,Y,Z}, Mat on first non-comment line
92
91
tokens = FileAdapter::tokenize (line, delimiter);
93
- // Process each word in the line (separated by spaces)
92
+ // Process each header in the line
94
93
for (auto & pair : _accepted_headers) {
95
94
const std::string& group = pair.first ;
96
95
const std::set<std::string>& headers = pair.second ;
97
96
for (const auto & header : headers) {
98
- int tokenIndex = find_index (tokens, header);
99
- if (tokenIndex != -1 ) {
100
- // Add the header with its column index to the map
101
- presentGroupsWithColumnIndices[group].insert (
102
- {header, tokenIndex});
103
- }
97
+ int tokenIndex = std::distance (tokens.begin (),
98
+ std::find (tokens.begin (), tokens.end (), header));
99
+ if (tokenIndex != -1 ) { h_map.insert ({header, tokenIndex}); }
104
100
}
105
101
}
106
- // Output the present header groups and their column indices
107
- // std::cout << "Present header groups with their column indices:"
108
- // << std::endl;
109
102
110
- for (const auto & group : presentGroupsWithColumnIndices) {
111
- // std::cout << group.first << ":" << std::endl;
112
- for (const auto & header : group.second ) {
113
- // std::cout << " " << header.first << " at column "
114
- // << header.second << std::endl;
115
- h_map.insert ({header.first , header.second });
116
- }
117
- }
118
103
// Count the total lines in the file
119
104
// TODO: make sure all the sensor files have the same number of lines
120
- std::ifstream lineCount{fileName};
121
- n_lines = std::count (std::istreambuf_iterator<char >(lineCount),
105
+ const int fp_pos = nextStream->tellg ();
106
+ // std::cout << "Current pos: " << fp_pos << std::endl;
107
+ // Count the number of lines
108
+ n_lines = std::count (std::istreambuf_iterator<char >(*nextStream),
122
109
std::istreambuf_iterator<char >(), ' \n ' );
110
+ // Rewind file pointer to after header
111
+ nextStream->seekg (fp_pos, std::ifstream::beg);
123
112
// std::cout << "Number of Lines: " << n_lines << std::endl;
113
+
114
+ // Add imu name to labels
115
+ labels.push_back (nextItem.get_name_in_model ());
116
+ // Add corresponding stream to imuStreams
117
+ imuStreams.push_back (std::move (nextStream));
124
118
}
125
119
// Compute data rate based on key/value pair if available
126
120
std::map<std::string, std::string>::iterator it =
127
121
headersKeyValuePairs.find (" Update Rate" );
128
122
if (it != headersKeyValuePairs.end ())
129
123
dataRate = OpenSim::IO::stod (it->second );
124
+ // Make sure that the specified header group has all required headers
125
+ auto is_group_complete =
126
+ [&](const std::string& group,
127
+ const std::map<std::string, std::set<std::string>>&
128
+ accepted_headers,
129
+ const std::map<std::string, size_t >& found_headers)
130
+ -> bool {
131
+ const auto & reqIt = accepted_headers.find (group);
132
+ if (reqIt == accepted_headers.end ()) return false ;
133
+ const auto & search_set = reqIt->second ;
134
+ return std::all_of (
135
+ search_set.begin (), search_set.end (), [&](const auto & p) {
136
+ return found_headers.find (p) != found_headers.end ();
137
+ });
138
+ };
130
139
// internally keep track of what data was found in input files
131
- bool foundLinearAccelerationData = is_group_complete (
132
- " accelerometer" , _accepted_headers, presentGroupsWithColumnIndices );
133
- bool foundMagneticHeadingData = is_group_complete (
134
- " magnetometer" , _accepted_headers, presentGroupsWithColumnIndices );
135
- bool foundAngularVelocityData = is_group_complete (
136
- " gyroscope" , _accepted_headers, presentGroupsWithColumnIndices );
137
- bool foundRotationData = is_group_complete (rotation_representation,
138
- _accepted_headers, presentGroupsWithColumnIndices );
140
+ bool foundLinearAccelerationData =
141
+ is_group_complete ( " accelerometer" , _accepted_headers, h_map );
142
+ bool foundMagneticHeadingData =
143
+ is_group_complete ( " magnetometer" , _accepted_headers, h_map );
144
+ bool foundAngularVelocityData =
145
+ is_group_complete ( " gyroscope" , _accepted_headers, h_map );
146
+ bool foundRotationData = is_group_complete (
147
+ rotation_representation, _accepted_headers, h_map );
139
148
// If no Orientation data is available we'll abort completely
140
- OPENSIM_THROW_IF (!foundRotationData,
141
- TableMissingHeader,
142
- " Rotation Data not found. Please ensure that the XsensDataReaderSettings match the file format being parsed!\n "
143
- " Attempted to parse with rotation format: \" " + rotation_representation_str + " \" "
144
- " and delimiter: \" " + delimiter + " \" " );
149
+ OPENSIM_THROW_IF (!foundRotationData, TableMissingHeader,
150
+ " Rotation Data not found. Please ensure that the "
151
+ " XsensDataReaderSettings match the file format being parsed!\n "
152
+ " Attempted to parse with rotation format: \" " +
153
+ rotation_representation_str + " \" and delimiter: \" " +
154
+ delimiter + " \" " );
145
155
146
156
// Will read data into pre-allocated Matrices in-memory rather than
147
157
// appendRow on the fly to avoid the overhead of
@@ -166,9 +176,7 @@ DataAdapter::OutputTables XsensDataReader::extendRead(
166
176
n_imus, SimTK::Vec3 (SimTK::NaN)};
167
177
// Cycle through the files collating values
168
178
int imu_index = 0 ;
169
- for (std::vector<std::ifstream*>::iterator it = imuStreams.begin ();
170
- it != imuStreams.end (); ++it, ++imu_index) {
171
- std::ifstream* nextStream = *it;
179
+ for (auto && nextStream : imuStreams) {
172
180
// parse gyro info from imuStream
173
181
std::vector<std::string> nextRow =
174
182
FileAdapter::getNextLine (*nextStream, delimiter + " \r " );
@@ -240,6 +248,7 @@ DataAdapter::OutputTables XsensDataReader::extendRead(
240
248
imu_rotation.convertRotationToQuaternion ();
241
249
}
242
250
}
251
+ imu_index++;
243
252
}
244
253
if (end_of_file) { break ; }
245
254
// append to the tables
@@ -275,34 +284,4 @@ DataAdapter::OutputTables XsensDataReader::extendRead(
275
284
return tables;
276
285
}
277
286
278
- bool XsensDataReader::is_group_complete (const std::string& group,
279
- const std::map<std::string, std::set<std::string>>&
280
- headers,
281
- const std::map<std::string, std::set<std::pair<std::string, size_t >>>&
282
- presentGroupsWithColumnIndices) {
283
- auto reqIt = headers.find (group);
284
- if (reqIt == headers.end ()) return false ;
285
-
286
- auto presIt = presentGroupsWithColumnIndices.find (group);
287
- if (presIt == presentGroupsWithColumnIndices.end ()) return false ;
288
-
289
- std::set<std::string> present;
290
- for (const auto & pair : presIt->second ) { present.insert (pair.first ); }
291
-
292
- for (const auto & header : reqIt->second ) {
293
- if (present.find (header) == present.end ()) { return false ; }
294
- }
295
-
296
- return true ;
297
- }
298
-
299
- int XsensDataReader::find_index (
300
- std::vector<std::string>& tokens, const std::string& keyToMatch) {
301
- int returnIndex = -1 ;
302
- std::vector<std::string>::iterator it =
303
- std::find (tokens.begin (), tokens.end (), keyToMatch);
304
- if (it != tokens.end ())
305
- returnIndex = static_cast <int >(std::distance (tokens.begin (), it));
306
- return returnIndex;
307
- }
308
287
} // namespace OpenSim
0 commit comments