EZC3D
ezc3d.cpp
Go to the documentation of this file.
1 #define EZC3D_API_EXPORTS
2 
10 #include "ezc3d.h"
11 #include "Header.h"
12 #include "Data.h"
13 #include "Parameters.h"
14 
15 
16 void ezc3d::removeTrailingSpaces(std::string& s){
17  // Remove the spaces at the end of the strings
18  for (int i = static_cast<int>(s.size()); i >= 0; --i)
19  if (s.size() > 0 && s[s.size()-1] == ' ')
20  s.pop_back();
21  else
22  break;
23 }
24 
25 std::string ezc3d::toUpper(const std::string &str){
26  std::string new_str = str;
27  std::transform(new_str.begin(), new_str.end(), new_str.begin(), ::toupper);
28  return new_str;
29 }
30 
32  _filePath(""),
33  m_nByteToRead_float(4*ezc3d::DATA_TYPE::BYTE),
34  m_nByteToReadMax_int(100)
35 {
36  c_float = new char[m_nByteToRead_float + 1];
37  c_float_tp = new char[m_nByteToRead_float + 1];
38  c_int = new char[m_nByteToReadMax_int + 1];
39  c_int_tp = new char[m_nByteToReadMax_int + 1];
40 
41  _header = std::shared_ptr<ezc3d::Header>(new ezc3d::Header());
42  _parameters = std::shared_ptr<ezc3d::ParametersNS::Parameters>(new ezc3d::ParametersNS::Parameters());
43  _data = std::shared_ptr<ezc3d::DataNS::Data>(new ezc3d::DataNS::Data());
44 }
45 
46 ezc3d::c3d::c3d(const std::string &filePath):
47  _filePath(filePath),
48  m_nByteToRead_float(4*ezc3d::DATA_TYPE::BYTE),
49  m_nByteToReadMax_int(100)
50 {
51  std::fstream stream(_filePath, std::ios::in | std::ios::binary);
52  c_float = new char[m_nByteToRead_float + 1];
53  c_float_tp = new char[m_nByteToRead_float + 1];
54  c_int = new char[m_nByteToReadMax_int + 1];
55  c_int_tp = new char[m_nByteToReadMax_int + 1];
56 
57  if (!stream.is_open())
58  throw std::ios_base::failure("Could not open the c3d file");
59 
60  // Read all the section
61  _header = std::shared_ptr<ezc3d::Header>(new ezc3d::Header(*this, stream));
62  _parameters = std::shared_ptr<ezc3d::ParametersNS::Parameters>(new ezc3d::ParametersNS::Parameters(*this, stream));
63 
64  // header may be inconsistent with the parameters, so it must be update to make sure sizes are consistent
65  updateHeader();
66 
67  // Now read the data
68  _data = std::shared_ptr<ezc3d::DataNS::Data>(new ezc3d::DataNS::Data(*this, stream));
69 
70  // Parameters and header may be inconsistent with data, so reprocess them if needed
72 
73  // Close the file
74  stream.close();
75 }
76 
78 {
79  delete c_float;
80  delete c_float_tp;
81  delete c_int;
82  delete c_int_tp;
83 }
84 
85 void ezc3d::c3d::print() const
86 {
87  header().print();
88  parameters().print();
89  data().print();
90 }
91 
92 void ezc3d::c3d::write(const std::string& filePath) const
93 {
94  std::fstream f(filePath, std::ios::out | std::ios::binary);
95 
96  // Write the header
97  std::streampos dataStartHeader;
98  header().write(f, dataStartHeader);
99 
100  // Write the parameters
101  // We must copy parameters since there is no way to make sure that the number of frames is not higher than 0xFFFF
102  ezc3d::ParametersNS::Parameters params(parameters());
103  int nFrames(this->parameters().group("POINT").parameter("FRAMES").valuesAsInt()[0]);
104  if (nFrames > 0xFFFF){
106  frames.set(-1);
107  params.group_nonConst("POINT").parameter(frames);
108  }
109  std::streampos dataStartParameters;
110  params.write(f, dataStartParameters);
111 
112  // Write the data start parameter in header and parameter sections
113  writeDataStart(f, dataStartHeader, DATA_TYPE::WORD);
114  writeDataStart(f, dataStartParameters, DATA_TYPE::BYTE);
115 
116  // Write the data
117  data().write(f);
118 
119  f.close();
120 }
121 
122 void ezc3d::c3d::resizeCharHolder(unsigned int nByteToRead)
123 {
124  delete[] c_int;
125  delete[] c_int_tp;
126  m_nByteToReadMax_int = nByteToRead;
127  c_int = new char[m_nByteToReadMax_int + 1];
128  c_int_tp = new char[m_nByteToReadMax_int + 1];
129 }
130 
131 void ezc3d::c3d::readFile(std::fstream &file, unsigned int nByteToRead, char * c, int nByteFromPrevious,
132  const std::ios_base::seekdir &pos)
133 {
134  if (pos != 1)
135  file.seekg (nByteFromPrevious, pos); // Move to number analogs
136  file.read (c, nByteToRead);
137  c[nByteToRead] = '\0'; // Make sure last char is NULL
138 }
139 
140 unsigned int ezc3d::c3d::hex2uint(const char * val, unsigned int len){
141  int ret(0);
142  for (unsigned int i = 0; i < len; i++)
143  ret |= static_cast<int>(static_cast<unsigned char>(val[i])) * static_cast<int>(pow(0x100, i));
144  return static_cast<unsigned int>(ret);
145 }
146 
147 int ezc3d::c3d::hex2int(const char * val, unsigned int len){
148  unsigned int tp(hex2uint(val, len));
149 
150  // convert to signed int
151  // Find max int value
152  unsigned int max(0);
153  for (unsigned int i=0; i<len; ++i)
154  max |= 0xFF * static_cast<unsigned int>(pow(0x100, i));
155 
156  // If the value is over uint_max / 2 then it is a negative number
157  int out;
158  if (tp > max / 2)
159  out = static_cast<int>(tp - max - 1);
160  else
161  out = static_cast<int>(tp);
162 
163  return out;
164 }
165 
166 void ezc3d::c3d::writeDataStart(std::fstream &f, const std::streampos &dataStartPosition, const DATA_TYPE& type) const
167 {
168  // Go back to data start blank space and write the current position (assuming current is the position of data!)
169  std::streampos dataPos = f.tellg();
170  f.seekg(dataStartPosition);
171  if (int(dataPos) % 512 > 0)
172  throw std::out_of_range("Something went wrong in the positioning of the pointer for writting the data. "
173  "Please report this error.");
174  int nBlocksToNext = int(dataPos)/512 + 1; // DATA_START is 1-based
175  f.write(reinterpret_cast<const char*>(&nBlocksToNext), type);
176  f.seekg(dataPos);
177 }
178 
179 int ezc3d::c3d::readInt(PROCESSOR_TYPE processorType, std::fstream &file, unsigned int nByteToRead, int nByteFromPrevious,
180  const std::ios_base::seekdir &pos)
181 {
182  if (nByteToRead > m_nByteToReadMax_int)
183  resizeCharHolder(nByteToRead);
184 
185  readFile(file, nByteToRead, c_int, nByteFromPrevious, pos);
186 
187  int out;
188  if (processorType == PROCESSOR_TYPE::MIPS){
189  // This is more or less good. Sometimes, it should not reverse...
190  for (size_t i=0; i<nByteToRead; ++i){
191  c_int_tp[i] = c_int[nByteToRead-1 - i];
192  }
193  c_int_tp[nByteToRead] = '\0';
194  out = hex2int(c_int_tp, nByteToRead);
195  } else {
196  // make sure it is an int and not an unsigned int
197  out = hex2int(c_int, nByteToRead);
198  }
199 
200  return out;
201 }
202 
203 size_t ezc3d::c3d::readUint(PROCESSOR_TYPE processorType, std::fstream &file, unsigned int nByteToRead, int nByteFromPrevious,
204  const std::ios_base::seekdir &pos)
205 {
206  if (nByteToRead > m_nByteToReadMax_int)
207  resizeCharHolder(nByteToRead);
208 
209  readFile(file, nByteToRead, c_int, nByteFromPrevious, pos);
210 
211  size_t out;
212  if (processorType == PROCESSOR_TYPE::MIPS){
213  // This is more or less good. Sometimes, it should not reverse...
214  for (size_t i=0; i<nByteToRead; ++i){
215  c_int_tp[i] = c_int[nByteToRead-1 - i];
216  }
217  c_int_tp[nByteToRead] = '\0';
218  // make sure it is an int and not an unsigned int
219  out = hex2uint(c_int_tp, nByteToRead);
220  } else {
221  // make sure it is an int and not an unsigned int
222  out = hex2uint(c_int, nByteToRead);
223  }
224 
225  return out;
226 }
227 
228 float ezc3d::c3d::readFloat(PROCESSOR_TYPE processorType, std::fstream &file, int nByteFromPrevious,
229  const std::ios_base::seekdir &pos)
230 {
231  readFile(file, m_nByteToRead_float, c_float, nByteFromPrevious, pos);
232  float out;
233  if (processorType == PROCESSOR_TYPE::INTEL) {
234  out = *reinterpret_cast<float*>(c_float);
235  } else if (processorType == PROCESSOR_TYPE::DEC){
236  c_float_tp[0] = c_float[2];
237  c_float_tp[1] = c_float[3];
238  c_float_tp[2] = c_float[0];
239  if (c_float[1] != 0)
240  c_float_tp[3] = c_float[1]-1;
241  else
242  c_float_tp[3] = c_float[1];
243  c_float_tp[4] = '\0';
244  out = *reinterpret_cast<float*>(c_float_tp);
245  } else if (processorType == PROCESSOR_TYPE::MIPS) {
246  for (unsigned int i=0; i<m_nByteToRead_float; ++i)
247  c_float_tp[i] = c_float[m_nByteToRead_float-1 - i];
248  c_float_tp[m_nByteToRead_float] = '\0';
249  out = *reinterpret_cast<float*>(c_float_tp);
250  } else {
251  throw std::runtime_error("Wrong type of processor for floating points");
252  }
253  return out;
254 }
255 
256 std::string ezc3d::c3d::readString(std::fstream &file, unsigned int nByteToRead, int nByteFromPrevious,
257  const std::ios_base::seekdir &pos)
258 {
259  if (nByteToRead > m_nByteToReadMax_int)
260  resizeCharHolder(nByteToRead);
261 
262  char* c = new char[nByteToRead + 1];
263  readFile(file, nByteToRead, c, nByteFromPrevious, pos);
264  std::string out(c);
265  delete[] c;
266  return out;
267 }
268 
269 void ezc3d::c3d::readParam(PROCESSOR_TYPE processorType, std::fstream &file, unsigned int dataLenghtInBytes, const std::vector<size_t> &dimension,
270  std::vector<int> &param_data, size_t currentIdx)
271 {
272  for (size_t i = 0; i < dimension[currentIdx]; ++i)
273  if (currentIdx == dimension.size()-1)
274  param_data.push_back (readInt(processorType, file, dataLenghtInBytes*ezc3d::DATA_TYPE::BYTE));
275  else
276  readParam(processorType, file, dataLenghtInBytes, dimension, param_data, currentIdx + 1);
277 }
278 
279 void ezc3d::c3d::readParam(PROCESSOR_TYPE processorType, std::fstream &file, const std::vector<size_t> &dimension,
280  std::vector<float> &param_data, size_t currentIdx)
281 {
282  for (size_t i = 0; i < dimension[currentIdx]; ++i)
283  if (currentIdx == dimension.size()-1)
284  param_data.push_back (readFloat(processorType, file));
285  else
286  readParam(processorType, file, dimension, param_data, currentIdx + 1);
287 }
288 
289 void ezc3d::c3d::readParam(std::fstream &file, const std::vector<size_t> &dimension,
290  std::vector<std::string> &param_data_string)
291 {
292  std::vector<std::string> param_data_string_tp;
293  _readMatrix(file, dimension, param_data_string_tp);
294 
295  // Vicon c3d stores text length on first dimension, I am not sure if
296  // this is a standard or a custom made stuff. I implemented it like that for now
297  if (dimension.size() == 1){
298  if (dimension[0] != 0) {
299  std::string tp;
300  for (size_t j = 0; j < dimension[0]; ++j)
301  tp += param_data_string_tp[j];
303  param_data_string.push_back(tp);
304  }
305  }
306  else
307  _dispatchMatrix(dimension, param_data_string_tp, param_data_string);
308 }
309 
310 size_t ezc3d::c3d::_dispatchMatrix(const std::vector<size_t> &dimension,
311  const std::vector<std::string> &param_data_in,
312  std::vector<std::string> &param_data_out, size_t idxInParam,
313  size_t currentIdx)
314 {
315  for (size_t i = 0; i < dimension[currentIdx]; ++i)
316  if (currentIdx == dimension.size()-1){
317  std::string tp;
318  for (size_t j = 0; j < dimension[0]; ++j){
319  tp += param_data_in[idxInParam];
320  ++idxInParam;
321  }
323  param_data_out.push_back(tp);
324  }
325  else
326  idxInParam = _dispatchMatrix(dimension, param_data_in, param_data_out, idxInParam, currentIdx + 1);
327  return idxInParam;
328 }
329 
330 void ezc3d::c3d::_readMatrix(std::fstream &file, const std::vector<size_t> &dimension,
331  std::vector<std::string> &param_data, size_t currentIdx)
332 {
333  for (size_t i = 0; i < dimension[currentIdx]; ++i)
334  if (currentIdx == dimension.size()-1)
335  param_data.push_back(readString(file, ezc3d::DATA_TYPE::BYTE));
336  else
337  _readMatrix(file, dimension, param_data, currentIdx + 1);
338 }
339 
341 {
342  return *_header;
343 }
344 
346 {
347  return *_parameters;
348 }
349 
351 {
352  return *_data;
353 }
354 
355 const std::vector<std::string> &ezc3d::c3d::pointNames() const
356 {
357  return parameters().group("POINT").parameter("LABELS").valuesAsString();
358 }
359 
360 size_t ezc3d::c3d::pointIdx(const std::string &pointName) const
361 {
362  const std::vector<std::string> &currentNames(pointNames());
363  for (size_t i = 0; i < currentNames.size(); ++i)
364  if (!currentNames[i].compare(pointName))
365  return i;
366  throw std::invalid_argument("ezc3d::pointIdx could not find " + pointName + " in the points data set.");
367 }
368 
369 const std::vector<std::string> &ezc3d::c3d::channelNames() const
370 {
371  return parameters().group("ANALOG").parameter("LABELS").valuesAsString();
372 }
373 
374 size_t ezc3d::c3d::channelIdx(const std::string &channelName) const
375 {
376  const std::vector<std::string> &currentNames(channelNames());
377  for (size_t i = 0; i < currentNames.size(); ++i)
378  if (!currentNames[i].compare(channelName))
379  return i;
380  throw std::invalid_argument("ezc3d::channelIdx could not find " + channelName +
381  " in the analogous data set");
382 }
383 
384 void ezc3d::c3d::parameter(const std::string &groupName, const ezc3d::ParametersNS::GroupNS::Parameter &p)
385 {
386  if (!p.name().compare("")){
387  throw std::invalid_argument("Parameter must have a name");
388  }
389 
390  size_t idx;
391  try {
392  idx = parameters().groupIdx(groupName);
393  } catch (std::invalid_argument) {
394  _parameters->group(ezc3d::ParametersNS::GroupNS::Group(groupName));
395  idx = parameters().groupIdx(groupName);
396  }
397 
398  _parameters->group_nonConst(idx).parameter(p);
399 
400  // Do a sanity check on the header if important stuff like number of frames or number of elements is changed
401  updateHeader();
402 }
403 
404 void ezc3d::c3d::lockGroup(const std::string &groupName)
405 {
406  _parameters->group_nonConst(groupName).lock();
407 }
408 
409 void ezc3d::c3d::unlockGroup(const std::string &groupName)
410 {
411  _parameters->group_nonConst(groupName).unlock();
412 }
413 
414 void ezc3d::c3d::frame(const ezc3d::DataNS::Frame &f, size_t idx)
415 {
416  // Make sure f.points().points() is the same as data.f[ANY].points()
417  size_t nPoints(static_cast<size_t>(parameters().group("POINT").parameter("USED").valuesAsInt()[0]));
418  if (nPoints != 0 && f.points().nbPoints() != nPoints)
419  throw std::runtime_error("Number of points in POINT:USED parameter must equal"
420  "the number of points sent in the frame");
421 
422  std::vector<std::string> labels(parameters().group("POINT").parameter("LABELS").valuesAsString());
423  for (size_t i=0; i<labels.size(); ++i)
424  try {
425  pointIdx(labels[i]);
426  } catch (std::invalid_argument) {
427  throw std::invalid_argument("All the points in the frame must appear in the POINT:LABELS parameter");
428  }
429 
430  if (f.points().nbPoints() > 0 && static_cast<double>(parameters().group("POINT").parameter("RATE").valuesAsFloat()[0]) == 0.0){
431  throw std::runtime_error("Point frame rate must be specified if you add some");
432  }
433  if (f.analogs().nbSubframes() > 0 && static_cast<double>(parameters().group("ANALOG").parameter("RATE").valuesAsFloat()[0]) == 0.0){
434  throw std::runtime_error("Analog frame rate must be specified if you add some");
435  }
436 
437  size_t nAnalogs(static_cast<size_t>(parameters().group("ANALOG").parameter("USED").valuesAsInt()[0]));
438  size_t subSize(f.analogs().nbSubframes());
439  if (subSize != 0){
440  size_t nChannel(f.analogs().subframe(0).nbChannels());
441  size_t nAnalogByFrames(header().nbAnalogByFrame());
442  if (!(nAnalogs==0 && nAnalogByFrames==0) && nChannel != nAnalogs )
443  throw std::runtime_error("Number of analogs in ANALOG:USED parameter must equal "
444  "the number of analogs sent in the frame");
445  }
446 
447  // Replace the jth frame
448  _data->frame(f, idx);
449  updateParameters();
450 }
451 
452 void ezc3d::c3d::point(const std::string &name){
453  if (data().nbFrames() > 0){
454  std::vector<ezc3d::DataNS::Frame> dummy_frames;
457  dummy_pts.point(emptyPoint);
458  ezc3d::DataNS::Frame frame;
459  frame.add(dummy_pts);
460  for (size_t f=0; f<data().nbFrames(); ++f)
461  dummy_frames.push_back(frame);
462  point(name, dummy_frames);
463  } else {
464  updateParameters({name});
465  }
466 }
467 
468 void ezc3d::c3d::point(const std::string& pointName, const std::vector<ezc3d::DataNS::Frame>& frames){
469  std::vector<std::string> names;
470  names.push_back(pointName);
471  point(names, frames);
472 }
473 
474 void ezc3d::c3d::point(const std::vector<std::string>& ptsNames, const std::vector<ezc3d::DataNS::Frame>& frames)
475 {
476  if (frames.size() == 0 || frames.size() != data().nbFrames())
477  throw std::invalid_argument("Size of the array of frames must equal the number of frames already "
478  "present in the data set");
479  if (frames[0].points().nbPoints() == 0)
480  throw std::invalid_argument("Points in the frames cannot be empty");
481 
482  const std::vector<std::string>& labels(pointNames());
483 
484  for (size_t idx = 0; idx<ptsNames.size(); ++idx){
485  for (size_t i=0; i<labels.size(); ++i)
486  if (!ptsNames[idx].compare(labels[i]))
487  throw std::invalid_argument("The point you try to create already exists in the data set");
488 
489  for (size_t f=0; f<data().nbFrames(); ++f)
490  _data->frame_nonConst(f).points_nonConst().point(frames[f].points().point(idx));
491  }
492  updateParameters(ptsNames);
493 }
494 
495 void ezc3d::c3d::analog(const std::string &name)
496 {
497  if (data().nbFrames() > 0){
498  std::vector<ezc3d::DataNS::Frame> dummy_frames;
499  ezc3d::DataNS::AnalogsNS::SubFrame dummy_subframes;
501  emptyChannel.data(0);
502  ezc3d::DataNS::Frame frame;
503  dummy_subframes.channel(emptyChannel);
504  for (size_t sf = 0; sf < header().nbAnalogByFrame(); ++sf)
505  frame.analogs_nonConst().subframe(dummy_subframes);
506  for (size_t f=0; f<data().nbFrames(); ++f)
507  dummy_frames.push_back(frame);
508  analog(name, dummy_frames);
509  } else {
510  updateParameters({}, {name});
511  }
512 }
513 
514 void ezc3d::c3d::analog(std::string channelName, const std::vector<ezc3d::DataNS::Frame> &frames)
515 {
516  std::vector<std::string> names;
517  names.push_back(channelName);
518  analog(names, frames);
519 }
520 
521 void ezc3d::c3d::analog(const std::vector<std::string> &chanNames, const std::vector<ezc3d::DataNS::Frame> &frames)
522 {
523  if (frames.size() != data().nbFrames())
524  throw std::invalid_argument("Size of the array of frames must equal the number of frames already "
525  "present in the data set");
526  if (frames[0].analogs().nbSubframes() != header().nbAnalogByFrame())
527  throw std::invalid_argument("Size of the subframes in the frames must equal the number of subframes "
528  "already present in the data set");
529  if (frames[0].analogs().subframe(0).nbChannels() == 0)
530  throw std::invalid_argument("Channels in the frame cannot be empty");
531 
532  const std::vector<std::string>& labels(channelNames());
533  for (size_t idx = 0; idx < chanNames.size(); ++idx){
534  for (size_t i=0; i<labels.size(); ++i)
535  if (!chanNames[idx].compare(labels[i]))
536  throw std::invalid_argument("The channel you try to create already exists in the data set");
537 
538  for (size_t f=0; f < data().nbFrames(); ++f){
539  for (size_t sf=0; sf < header().nbAnalogByFrame(); ++sf){
540  _data->frame_nonConst(f).analogs_nonConst().subframe_nonConst(sf).channel(frames[f].analogs().subframe(sf).channel(idx));
541  }
542  }
543  }
544  updateParameters({}, chanNames);
545 }
546 
548 {
549  // Parameter is always consider as the right value.
550  if (static_cast<size_t>(parameters().group("POINT").parameter("FRAMES").valuesAsInt()[0]) != header().nbFrames()){
551  // If there is a discrepancy between them, change the header, while keeping the firstFrame value
552  _header->lastFrame(static_cast<size_t>(parameters().group("POINT").parameter("FRAMES").valuesAsInt()[0]) + _header->firstFrame() - 1);
553  }
554  float pointRate(parameters().group("POINT").parameter("RATE").valuesAsFloat()[0]);
555  float buffer(10000); // For decimal truncature
556  if (static_cast<int>(pointRate*buffer) != static_cast<int>(header().frameRate()*buffer)){
557  _header->frameRate(pointRate);
558  }
559  if (static_cast<size_t>(parameters().group("POINT").parameter("USED").valuesAsInt()[0]) != header().nb3dPoints()){
560  _header->nb3dPoints(static_cast<size_t>(parameters().group("POINT").parameter("USED").valuesAsInt()[0]));
561  }
562 
563  // Compare the subframe with data when possible, otherwise go with the parameters
564  if (_data != nullptr && data().nbFrames() > 0 && data().frame(0).analogs().nbSubframes() != 0) {
565  if (data().frame(0).analogs().nbSubframes() != static_cast<size_t>(header().nbAnalogByFrame()))
566  _header->nbAnalogByFrame(data().frame(0).analogs().nbSubframes());
567  } else {
568  if (static_cast<size_t>(pointRate) == 0){
569  if (static_cast<size_t>(header().nbAnalogByFrame()) != 1)
570  _header->nbAnalogByFrame(1);
571  } else {
572  if (static_cast<size_t>(parameters().group("ANALOG").parameter("RATE").valuesAsFloat()[0] / pointRate) != static_cast<size_t>(header().nbAnalogByFrame()))
573  _header->nbAnalogByFrame(static_cast<size_t>(parameters().group("ANALOG").parameter("RATE").valuesAsFloat()[0] / pointRate));
574  }
575  }
576 
577  if (static_cast<size_t>(parameters().group("ANALOG").parameter("USED").valuesAsInt()[0]) != header().nbAnalogs())
578  _header->nbAnalogs(static_cast<size_t>(parameters().group("ANALOG").parameter("USED").valuesAsInt()[0]));
579 }
580 
581 void ezc3d::c3d::updateParameters(const std::vector<std::string> &newPoints, const std::vector<std::string> &newAnalogs)
582 {
583  // If frames has been added
584  ezc3d::ParametersNS::GroupNS::Group& grpPoint(_parameters->group_nonConst(parameters().groupIdx("POINT")));
585  size_t nFrames(data().nbFrames());
586  if (nFrames != static_cast<size_t>(grpPoint.parameter("FRAMES").valuesAsInt()[0])){
587  size_t idx(grpPoint.parameterIdx("FRAMES"));
588  grpPoint.parameter_nonConst(idx).set(nFrames);
589  }
590 
591  // If points has been added
592  size_t nPoints;
593  if (data().nbFrames() > 0)
594  nPoints = data().frame(0).points().nbPoints();
595  else
596  nPoints = parameters().group("POINT").parameter("LABELS").valuesAsString().size() + newPoints.size();
597  if (nPoints != static_cast<size_t>(grpPoint.parameter("USED").valuesAsInt()[0])){
598  grpPoint.parameter_nonConst("USED").set(nPoints);
599 
600  size_t idxLabels(grpPoint.parameterIdx("LABELS"));
601  size_t idxDescriptions(grpPoint.parameterIdx("DESCRIPTIONS"));
602  size_t idxUnits(grpPoint.parameterIdx("UNITS"));
603  std::vector<std::string> labels;
604  std::vector<std::string> descriptions;
605  std::vector<std::string> units;
606  std::vector<std::string> ptsNames(pointNames());
607  ptsNames.insert( ptsNames.end(), newPoints.begin(), newPoints.end() );
608  for (size_t i = 0; i < nPoints; ++i){
609  std::string name;
610  if (data().nbFrames() == 0){
611  if (i < parameters().group("POINT").parameter("LABELS").valuesAsString().size())
612  name = parameters().group("POINT").parameter("LABELS").valuesAsString()[i];
613  else
614  name = newPoints[i - parameters().group("POINT").parameter("LABELS").valuesAsString().size()];
615  } else {
616  name = ptsNames[i];
617  removeTrailingSpaces(name);
618  }
619  labels.push_back(name);
620  descriptions.push_back("");
621  units.push_back("mm");
622  }
623  grpPoint.parameter_nonConst(idxLabels).set(labels);
624  grpPoint.parameter_nonConst(idxDescriptions).set(descriptions);
625  grpPoint.parameter_nonConst(idxUnits).set(units);
626  }
627 
628  // If analogous data has been added
629  ezc3d::ParametersNS::GroupNS::Group& grpAnalog(_parameters->group_nonConst(parameters().groupIdx("ANALOG")));
630  size_t nAnalogs;
631  if (data().nbFrames() > 0){
632  if (data().frame(0).analogs().nbSubframes() > 0)
633  nAnalogs = data().frame(0).analogs().subframe(0).nbChannels();
634  else
635  nAnalogs = 0;
636  } else
637  nAnalogs = parameters().group("ANALOG").parameter("LABELS").valuesAsString().size() + newAnalogs.size();
638 
639  // Should always be greater than 0..., but we have to take in account Optotrak lazyness
640  if (parameters().group("ANALOG").nbParameters()){
641  if (nAnalogs != static_cast<size_t>(grpAnalog.parameter("USED").valuesAsInt()[0])){
642  grpAnalog.parameter_nonConst("USED").set(nAnalogs);
643 
644  size_t idxLabels(static_cast<size_t>(grpAnalog.parameterIdx("LABELS")));
645  size_t idxDescriptions(static_cast<size_t>(grpAnalog.parameterIdx("DESCRIPTIONS")));
646  std::vector<std::string> labels;
647  std::vector<std::string> descriptions;
648  std::vector<std::string> chanNames(channelNames());
649  chanNames.insert( chanNames.end(), newAnalogs.begin(), newAnalogs.end() );
650  for (size_t i = 0; i<nAnalogs; ++i){
651  std::string name;
652  if (data().nbFrames() == 0){
653  if (i < parameters().group("ANALOG").parameter("LABELS").valuesAsString().size())
654  name = parameters().group("ANALOG").parameter("LABELS").valuesAsString()[i];
655  else
656  name = newAnalogs[i-parameters().group("ANALOG").parameter("LABELS").valuesAsString().size()];
657  } else {
658  name = chanNames[i];
659  removeTrailingSpaces(name);
660  }
661  labels.push_back(name);
662  descriptions.push_back("");
663  }
664  grpAnalog.parameter_nonConst(idxLabels).set(labels);
665  grpAnalog.parameter_nonConst(idxDescriptions).set(descriptions);
666 
667  size_t idxScale(grpAnalog.parameterIdx("SCALE"));
668  std::vector<float> scales(grpAnalog.parameter(idxScale).valuesAsFloat());
669  for (size_t i = grpAnalog.parameter(idxScale).valuesAsFloat().size(); i < nAnalogs; ++i)
670  scales.push_back(1);
671  grpAnalog.parameter_nonConst(idxScale).set(scales);
672 
673  size_t idxOffset(grpAnalog.parameterIdx("OFFSET"));
674  std::vector<int> offset(grpAnalog.parameter(idxOffset).valuesAsInt());
675  for (size_t i = grpAnalog.parameter(idxOffset).valuesAsInt().size(); i < nAnalogs; ++i)
676  offset.push_back(0);
677  grpAnalog.parameter_nonConst(idxOffset).set(offset);
678 
679  size_t idxUnits(grpAnalog.parameterIdx("UNITS"));
680  std::vector<std::string> units(grpAnalog.parameter(idxUnits).valuesAsString());
681  for (size_t i = grpAnalog.parameter(idxUnits).valuesAsString().size(); i < nAnalogs; ++i)
682  units.push_back("V");
683  grpAnalog.parameter_nonConst(idxUnits).set(units);
684  }
685  }
686  updateHeader();
687 }
std::shared_ptr< ezc3d::DataNS::Data > _data
Pointer that holds the data of the C3D.
Definition: ezc3d.h:377
std::string _filePath
The file path if the C3D was opened from a file.
Definition: ezc3d.h:156
std::shared_ptr< ezc3d::Header > _header
Pointer that holds the header of the C3D.
Definition: ezc3d.h:375
size_t _dispatchMatrix(const std::vector< size_t > &dimension, const std::vector< std::string > &param_data_in, std::vector< std::string > &param_data_out, size_t idxInParam=0, size_t currentIdx=1)
Internal function to dispatch a string array to a matrix of strings.
Definition: ezc3d.cpp:310
void resizeCharHolder(unsigned int nByteToRead)
Resize the too small char to read.
Definition: ezc3d.cpp:122
void set(int data)
Set the integer scalar value for the parameter.
Definition: Parameter.cpp:258
float data() const
Get the value of the analog data.
Definition: Channel.cpp:33
Group holder of C3D parameters.
Definition: Parameters.h:16
int hex2int(const char *val, unsigned int len)
Convert an hexadecimal value to a integer.
Definition: ezc3d.cpp:147
size_t readUint(PROCESSOR_TYPE processorType, std::fstream &file, unsigned int nByteToRead, int nByteFromPrevious=0, const std::ios_base::seekdir &pos=std::ios::cur)
Read a unsigned integer of nByteToRead bytes at the position current + nByteFromPrevious from a file...
Definition: ezc3d.cpp:203
Points holder for C3D data 3D points data.
Definition: Points.h:16
const ezc3d::DataNS::Points3dNS::Points & points() const
Return a reference to all the points.
Definition: Frame.cpp:30
const ezc3d::DataNS::AnalogsNS::Analogs & analogs() const
Return a reference to all the analogs.
Definition: Frame.cpp:40
void point(const std::string &name)
Create a point to the data set of name name.
Definition: ezc3d.cpp:452
PROCESSOR_TYPE
The type of processor used to store the data.
Definition: ezc3d.h:85
Declaration of Header class.
void add(const ezc3d::DataNS::Frame &frame)
Add a frame by copying a sent frame.
Definition: Frame.cpp:50
void unlockGroup(const std::string &groupName)
Unlock a particular group named groupName.
Definition: ezc3d.cpp:409
c3d()
Create a valid minimalistic C3D structure.
Definition: ezc3d.cpp:31
Group of parameter of a C3D file.
Definition: Group.h:16
Declaration of data class.
void _readMatrix(std::fstream &file, const std::vector< size_t > &dimension, std::vector< std::string > &param_data, size_t currentIdx=0)
Internal function to read a string array to a matrix of strings.
Definition: ezc3d.cpp:330
void readParam(PROCESSOR_TYPE processorType, std::fstream &file, unsigned int dataLenghtInBytes, const std::vector< size_t > &dimension, std::vector< int > &param_data, size_t currentIdx=0)
Read a matrix of integer parameters of dimensions dimension with each integer of length dataLengthInB...
Definition: ezc3d.cpp:269
char * c_int_tp
Char to be used by the read function with the specific size of a int preventing to allocate it at eac...
Definition: ezc3d.h:195
Header of a C3D file.
Definition: Header.h:16
size_t nbPoints() const
Get the number of points.
Definition: Points.cpp:35
void parameter(const std::string &groupName, const ezc3d::ParametersNS::GroupNS::Parameter &parameter)
Add/replace a parameter to a group named groupName.
Definition: ezc3d.cpp:384
const ezc3d::DataNS::AnalogsNS::Channel & channel(size_t idx) const
Get a particular analog channel of index idx from the analogous data.
Definition: Subframe.cpp:41
Namespace ezc3d.
Definition: ezc3d.h:68
void print() const
Print the C3D by calling print method of header, parameter and data.
Definition: ezc3d.cpp:85
size_t nbChannels() const
Get the number of analog channels.
Definition: Subframe.cpp:31
const ezc3d::ParametersNS::GroupNS::Parameter & parameter(size_t idx) const
Get a particular parameter of index idx from the group.
Definition: Group.cpp:143
Subframe for the analogous data.
Definition: Subframe.h:16
const std::string & name() const
Get the name of the parameter.
Definition: Parameter.cpp:193
const ezc3d::DataNS::AnalogsNS::SubFrame & subframe(size_t idx) const
Get a particular subframe of index idx from the analogous data set.
Definition: Analogs.cpp:43
const std::vector< std::string > & pointNames() const
Get a reference to the names of the points.
Definition: ezc3d.cpp:355
char * c_int
Char to be used by the read function with the specific size of a int preventing to allocate it at eac...
Definition: ezc3d.h:194
ezc3d::DataNS::AnalogsNS::Analogs & analogs_nonConst() const
Return a reference to all the analogs in order to be modified by the caller.
Definition: Frame.cpp:45
Channel of an analogous data.
Definition: Channel.h:16
void updateHeader()
Update the header according to the parameters and the data.
Definition: ezc3d.cpp:547
virtual ~c3d()
Destroy the class properly.
Definition: ezc3d.cpp:77
size_t channelIdx(const std::string &channelName) const
Get the index of a analog channel in the subframe.
Definition: ezc3d.cpp:374
std::shared_ptr< ezc3d::ParametersNS::Parameters > _parameters
Pointer that holds the parameters of the C3D.
Definition: ezc3d.h:376
const ezc3d::Header & header() const
The header of the C3D.
Definition: ezc3d.cpp:340
const ezc3d::ParametersNS::Parameters & parameters() const
The parameters of the C3D.
Definition: ezc3d.cpp:345
void frame(const ezc3d::DataNS::Frame &frame, size_t idx=SIZE_MAX)
Add/replace a frame to the data set.
Definition: ezc3d.cpp:414
char * c_float_tp
Char to be used by the read function with the specific size of a float preventing to allocate it at e...
Definition: ezc3d.h:193
ezc3d::ParametersNS::GroupNS::Group & group_nonConst(size_t idx)
Get a particular group of index idx from the group holder in order to be modified by the caller...
Definition: Parameters.cpp:324
void analog(const std::string &name)
Create a channel of analog data to the data set of name name.
Definition: ezc3d.cpp:495
void lockGroup(const std::string &groupName)
Lock a particular group named groupName.
Definition: ezc3d.cpp:404
const std::vector< std::string > & channelNames() const
Get a reference to the names of the analog channels.
Definition: ezc3d.cpp:369
const std::vector< std::string > & valuesAsString() const
Return the vector of values of the parameter.
Definition: Parameter.cpp:357
Data of the C3D file.
Definition: Data.h:18
size_t pointIdx(const std::string &pointName) const
Get the index of a point in the points holder.
Definition: ezc3d.cpp:360
char * c_float
Char to be used by the read function with the specific size of a float preventing to allocate it at e...
Definition: ezc3d.h:192
Frame holder for C3D data.
Definition: Frame.h:17
void write(const std::string &filePath) const
Write the C3D to an opened file by calling write method of header, parameter and data.
Definition: ezc3d.cpp:92
std::string toUpper(const std::string &str)
Swap all characters of a string to capital letters.
Definition: ezc3d.cpp:25
Declaration of ezc3d class.
int readInt(PROCESSOR_TYPE processorType, std::fstream &file, unsigned int nByteToRead, int nByteFromPrevious=0, const std::ios_base::seekdir &pos=std::ios::cur)
Read an integer of nByteToRead bytes at the position current + nByteFromPrevious from a file...
Definition: ezc3d.cpp:179
const ezc3d::DataNS::Data & data() const
The points and analogous data of the C3D.
Definition: ezc3d.cpp:350
void readFile(std::fstream &file, unsigned int nByteToRead, char *c, int nByteFromPrevious=0, const std::ios_base::seekdir &pos=std::ios::cur)
The function that reads the file, it returns the value into a generic char pointer that must be pre-a...
Definition: ezc3d.cpp:131
void write(std::fstream &f, std::streampos &dataStartPosition) const
Write the groups to an opened file by calling the write method of all the groups. ...
Definition: Parameters.cpp:246
size_t nbSubframes() const
Get the number of subframes.
Definition: Analogs.cpp:33
unsigned int m_nByteToRead_float
Declaration of the size of a float.
Definition: ezc3d.h:196
std::string readString(std::fstream &file, unsigned int nByteToRead, int nByteFromPrevious=0, const std::ios_base::seekdir &pos=std::ios::cur)
Read a string (array of char of nByteToRead bytes) at the position current + nByteFromPrevious from a...
Definition: ezc3d.cpp:256
DATA_TYPE
Enum that describes the size of different types.
Definition: ezc3d.h:73
void writeDataStart(std::fstream &file, const std::streampos &dataStartPosition, const DATA_TYPE &type) const
Write the data_start parameter where demanded.
Definition: ezc3d.cpp:166
void removeTrailingSpaces(std::string &str)
Remove the spaces at the end of a string.
Definition: ezc3d.cpp:16
void updateParameters(const std::vector< std::string > &newPoints=std::vector< std::string >(), const std::vector< std::string > &newAnalogs=std::vector< std::string >())
Update parameters according to the data.
Definition: ezc3d.cpp:581
Parameter of a C3D file.
Definition: Parameter.h:16
unsigned int hex2uint(const char *val, unsigned int len)
Convert an hexadecimal value to an unsigned integer.
Definition: ezc3d.cpp:140
unsigned int m_nByteToReadMax_int
Declaration of the max size of a int.
Definition: ezc3d.h:197
const ezc3d::DataNS::Points3dNS::Point & point(size_t idx) const
Get a particular point of index idx from the 3D points data.
Definition: Points.cpp:40
Declaration of Parameters class.
float readFloat(PROCESSOR_TYPE processorType, std::fstream &file, int nByteFromPrevious=0, const std::ios_base::seekdir &pos=std::ios::cur)
Read a float at the position current + nByteFromPrevious from a file.
Definition: ezc3d.cpp:228