/** * Read sto file. * * @param aFilename name of sto file. */ void MarkerData::readStoFile(const string& aFileName) { if (aFileName.empty()) throw Exception("MarkerData.readStoFile: ERROR- Marker file name is empty",__FILE__,__LINE__); // If the file was written by STOFileAdapter, make the file readable by // Storage. Calls below have no effect otherwise. std::string tmpFileName{"tmp.sto"}; bool versionChanged{revertToVersionNumber1(aFileName, tmpFileName)}; if(versionChanged) addNumRowsNumColumns(tmpFileName, aFileName); std::remove(tmpFileName.c_str()); Storage store(aFileName); // populate map between marker names and column numbers std::map<int, std::string> markerIndices; buildMarkerMap(store, markerIndices); if (markerIndices.size()==0){ throw Exception("MarkerData.readStoFile: ERROR- No markers were identified. Markers should appear on consecutive columns as Marker1.x Marker1.y Marker1.z Marker2.x... etc.",__FILE__,__LINE__); } std::map<int, std::string>::iterator iter; for (iter = markerIndices.begin(); iter != markerIndices.end(); iter++) { SimTK::String markerNameWithSuffix = iter->second; size_t dotIndex = SimTK::String::toLower(markerNameWithSuffix).find_last_of(".x"); SimTK::String candidateMarkerName = markerNameWithSuffix.substr(0, dotIndex-1); _markerNames.append(candidateMarkerName); } // use map to populate data for MarkerData header _numMarkers = (int) markerIndices.size(); _numFrames = store.getSize(); _firstFrameNumber = 1; _dataRate = 250; _cameraRate = 250; _originalDataRate = 250; _originalStartFrame = 1; _originalNumFrames = _numFrames; _fileName = aFileName; _units = Units(Units::Meters); double time; int sz = store.getSize(); for (int i=0; i < sz; i++){ StateVector* nextRow = store.getStateVector(i); time = nextRow->getTime(); int frameNum = i+1; MarkerFrame *frame = new MarkerFrame(_numMarkers, frameNum, time, _units); const Array<double>& rowData = nextRow->getData(); // Cycle through map and add Marker coordinates to the frame. Same order as header. for (iter = markerIndices.begin(); iter != markerIndices.end(); iter++) { int startIndex = iter->first; // startIndex includes time but data doesn't! frame->addMarker(SimTK::Vec3(rowData[startIndex-1], rowData[startIndex], rowData[startIndex+1])); } _frames.append(frame); } }
/** * Read TRC file. * * @param aFilename name of TRC file. * @param aSMD MarkerData object to hold the file contents */ void MarkerData::readTRCFile(const string& aFileName, MarkerData& aSMD) { ifstream in; string line, buffer; int frameNum, coordsRead; double time; SimTK::Vec3 coords; if (aFileName.empty()) throw Exception("MarkerData.readTRCFile: ERROR- Marker file name is empty",__FILE__,__LINE__); in.open(aFileName.c_str()); if (!in.good()) { string errorMessage; errorMessage = "Unable to open marker file " + aFileName; throw Exception(errorMessage); } readTRCFileHeader(in, aFileName, aSMD); /* read frame data */ while (getline(in, line)) { /* skip over any blank lines */ if (findFirstNonWhiteSpace(line) == -1) continue; if (aSMD._frames.getSize() == aSMD._numFrames) { #if 0 if (gUseGlobalMessages) { gErrorBuffer += "Extra data found at end of tracked marker file. "; gErrorBuffer += "Header declared only " + intToString(trc->header.numFrames) + " frames.\n"; } rc = smFileWarning; #endif break; } if (!readIntegerFromString(line, &frameNum)) { #if 0 if (gUseGlobalMessages) gErrorBuffer += "Could not read frame number in tracked marker file.\n"; rc = smFileError; goto cleanup; #endif } if (!readDoubleFromString(line, &time)) { #if 0 if (gUseGlobalMessages) gErrorBuffer += "Could not read time in tracked marker file.\n"; rc = smFileError; goto cleanup; #endif } MarkerFrame *frame = new MarkerFrame(aSMD._numMarkers, frameNum, time, aSMD._units); /* keep reading sets of coordinates until the end of the line is * reached. If more coordinates were read than there are markers, * return an error. */ coordsRead = 0; bool allowNaNs = true; while (readCoordinatesFromString(line, &coords[0], allowNaNs)) { if (coordsRead >= aSMD._numMarkers) { break; #if 0 // Don't return an error because many TRC files have extra data at the ends of rows if (gUseGlobalMessages) gErrorBuffer += "Extra data found in frame number " + intToString(frameNum) + " in tracked marker file.\n"; rc = smFileError; // delete the current markerCoordList because framesRead has not been incremented yet. delete [] f->markerCoordList; goto cleanup; #endif } if (coordsRead < aSMD._numMarkers) frame->addMarker(coords); coordsRead++; } if (coordsRead < aSMD._numMarkers) { #if 0 if (gUseGlobalMessages) gErrorBuffer += " Missing data in frame number " + intToString(frameNum) + " in tracked marker file.\n"; rc = smFileError; // delete the current markerCoordList because framesRead has not been incremented yet. delete [] f->markerCoordList; goto cleanup; #endif } aSMD._frames.append(frame); } if (aSMD._frames.getSize() < aSMD._numFrames) { #if 0 if (gUseGlobalMessages) gErrorBuffer += "Missing data in tracked marker file. Only " + intToString(framesRead) + " of " + intToString(trc->header.numFrames) + " frames found.\n"; rc = smFileError; goto cleanup; #endif aSMD._numFrames = aSMD._frames.getSize(); } /* If the user-defined frame numbers are not continguous from the first frame to the * last, reset them to a contiguous array. This is necessary because the user-defined * numbers are used to index the array of frames. */ if (aSMD._frames[aSMD._numFrames-1]->getFrameNumber() - aSMD._frames[0]->getFrameNumber() != aSMD._numFrames - 1) { int firstIndex = aSMD._frames[0]->getFrameNumber(); for (int i = 1; i < aSMD._numFrames; i++) aSMD._frames[i]->setFrameNumber(firstIndex + i); } #if 0 if (gUseGlobalMessages) { gMessage += "TRC file " + actualFileName + "\n\t" + intToString(trc->header.numFrames) + " frames\n\t" + intToString(trc->header.numMarkers) + " markers/frame\n"; gMessage += "Read " + intToString(framesRead) + " frames.\n"; } #endif //cleanup: in.close(); }