void ScreenCalibrator::readOptitrackSampleFile(const char* fileName,bool flipZ) { /* Open the CSV input file: */ IO::TokenSource tok(Vrui::openFile(fileName)); tok.setPunctuation(",\n"); tok.setQuotes("\""); tok.skipWs(); /* Read all point records from the file: */ double lastTimeStamp=-Math::Constants<double>::min; Point::AffineCombiner pac; unsigned int numPoints=0; unsigned int line=1; while(!tok.eof()) { /* Read a point record: */ /* Read the marker index: */ int markerIndex=atoi(tok.readNextToken()); if(strcmp(tok.readNextToken(),",")!=0) Misc::throwStdErr("readOptitrackSampleFile: missing comma in line %u",line); /* Read the sample timestamp: */ double timeStamp=atof(tok.readNextToken()); /* Read the point position: */ Point p; for(int i=0;i<3;++i) { if(strcmp(tok.readNextToken(),",")!=0) Misc::throwStdErr("readOptitrackSampleFile: missing comma in line %u",line); p[i]=Scalar(atof(tok.readNextToken())); } if(flipZ) { /* Invert the z component to flip to a right-handed coordinate system: */ p[2]=-p[2]; } if(strcmp(tok.readNextToken(),"\n")!=0) Misc::throwStdErr("readOptitrackSampleFile: overlong point record in line %u",line); /* Check if the point record is valid: */ if(markerIndex==1) { /* Check if this record started a new sampling sequence: */ if(timeStamp>=lastTimeStamp+5.0) { /* Get the current average point position and reset the accumulator: */ if(numPoints>0) { trackingPoints.push_back(pac.getPoint()); pac.reset(); numPoints=0; } } /* Add the point to the current accumulator: */ pac.addPoint(p); ++numPoints; lastTimeStamp=timeStamp; } ++line; } /* Get the last average point position: */ if(numPoints>0) trackingPoints.push_back(pac.getPoint()); /* Cull duplicate points from the point list: */ size_t numDupes=cullDuplicates(trackingPoints,Scalar(0.05)); if(numDupes>0) std::cout<<"ScreenCalibrator::readOptitrackSampleFile: "<<numDupes<<" duplicate points culled from input file"<<std::endl; }