//------------------------------------------------------------------------- // Function to compare the level 1 start time (GPS SecOfWeek) with nav data times //------------------------------------------------------------------------- void NavigationSyncer::CompareLev1ToNavTimes(double first_scan_time) { const int numsecsperday=3600*24; //Get the level 1 start time in GPS sec of week double lev1starttime=GetSecOfWeek(acquisitiondate,ReplaceAllWith(&gpsstarttime,':',' '),dateformat); DEBUGPRINT("GPS Second of week for level1 start time: "<<lev1starttime) Logger::Log("Difference between start time from level-1 header file and start time from navigation: "+ToString(lev1starttime-first_scan_time)+" seconds."); if(fabs(lev1starttime-first_scan_time) > lev1firstscanmaxexpectedsize) { Logger::Warning("This time difference appears excessive: "+ToString(lev1starttime-first_scan_time)); } //Do some comparisons // if the end time of the nav data is greater than the start time from the lev1 header if(navfile->GetLine(navfile->GetNumEntries()-1)->time < lev1starttime) { throw "Error: The level-1 start time is after the end of the navigation data: nav end time: "+ToString(navfile->GetLine(navfile->GetNumEntries()-1)->time)+" lev 1 time: "+ToString(lev1starttime); } //Test if data is more than a day (of week) out from both start and end times of nav data if((fabs(navfile->GetLine(0)->time - lev1starttime) > numsecsperday )&&(fabs(navfile->GetLine(navfile->GetNumEntries()-1)->time - lev1starttime) > numsecsperday)) { throw "Error: The level-1 start time is on a different week day to both the navigation start time and end times"; } else if (fabs(navfile->GetLine(0)->time - lev1starttime) > numsecsperday) { Logger::Warning("The level-1 start time is on a different week day to the navigation start time."); } else if(fabs(navfile->GetLine(navfile->GetNumEntries()-1)->time - lev1starttime) > numsecsperday) { Logger::Warning("The level-1 start time is on a different week day to the navigation end time."); } }
//------------------------------------------------------------------------- // Function to tidy up strings when added to the header file // - makes {, -> { and ,} -> } //------------------------------------------------------------------------- std::string BinaryReader::TidyForHeader(std::string totidy,bool wrapinbraces) { std::string ret=totidy; //replace any ; with , unless string starts with ; - may be a comment if(ret.at(0)!=';') ret=ReplaceAllWith(&ret,";",",\n"); ret=ReplaceAllWith(&ret,"{,","{"); ret=ReplaceAllWith(&ret,"{\n,","{\n"); ret=ReplaceAllWith(&ret,",}","}"); ret=ReplaceAllWith(&ret,",\n}","\n}"); if(wrapinbraces) { if(ret.find("{")!=0) ret.insert(0,"{"); if(ret.rfind("}")!=ret.length()-1) ret.push_back('}'); } return ret; }
//------------------------------------------------------------------------- // NavigationSyncer constructor using nav file and lev1 file to set up //------------------------------------------------------------------------- NavigationSyncer::NavigationSyncer(std::string navfilename, std::string lev1filename) { //Set to NULL here anyway just to be safe - they should all be none-null by the end of this function nscans=0; time=NULL; navfile=NULL; hdrsync=0; framerate=0; NOSYNCINHDR=-999; lev1firstscanmaxexpectedsize=30; //30 seconds if(navfilename.compare("NULL")!=0) { //Create a new Specim nav file object navfile=new SpecimFileChooser(navfilename); //Read in the nav file to get the time syncs navfile->Reader(); } //Need to read in the level1 file hdr info to get nscans BinFile bilin(lev1filename); //Get the number of scan lines nscans=StringToUINT(bilin.FromHeader("lines")); DEBUGPRINT("Number of scans: "<<nscans) //Get the NavSync timing from the hdr try { hdrsync=StringToUINT(TrimWhitespace(bilin.FromHeader("NavSync Timing",1,"true")))/1000.0; } catch(std::string e) { if(e.compare(0,bilin.MissingHeaderItemError().length(),bilin.MissingHeaderItemError())==0) { //Set to a value that means "no value in header" hdrsync=NOSYNCINHDR; } else { throw e; } } DEBUGPRINT("Sync from header:"<<hdrsync) //Get the acquisition date of the data acquisitiondate=bilin.FromHeader("acquisition date"); //Remove the start of the date string acquisitiondate=TrimWhitespace(acquisitiondate.substr(acquisitiondate.find_first_of(':')+1)); //Get the date format string for leap seconds dateformat=bilin.FromHeader("acquisition date"); size_t startofdateformat=dateformat.find_first_of("DATE(")+5; size_t lengthofdateformat=dateformat.find_first_of("):")-startofdateformat; dateformat=dateformat.substr(startofdateformat,lengthofdateformat); DEBUGPRINT("Date: "<<acquisitiondate) //Get the start and stop times from the header to use in case no sync messages //found in the specim nav file gpsstarttime=bilin.FromHeader("GPS Start Time"); gpsstarttime=RemoveAllBut(gpsstarttime,"1234567890.:"); gpsstarttime=TrimWhitespace(ReplaceAllWith(&gpsstarttime,':',' ')); gpsstoptime=bilin.FromHeader("GPS Stop Time"); gpsstoptime=RemoveAllBut(gpsstoptime,"1234567890.:"); gpsstoptime=TrimWhitespace(ReplaceAllWith(&gpsstoptime,':',' ')); //Get the frame rate from the hdr framerate=StringToDouble(bilin.FromHeader("fps")); DEBUGPRINT("Frame rate from header:"<<framerate) if((framerate <= 0)||(framerate>100000)) { throw "Frame rate (fps) in hdr file seems erroneous - will only process for frame rates >0 and <100000."; } //Get the Processed_crop_start from the header file - this tells us if //nav for the full line or crop of the line is required std::string cropstart=bilin.FromHeader("y start"); if(cropstart.compare("")==0) { Logger::Warning("No y start found in level 1 header, if data was cropped in previous stages navigation may be wrongly synced."); //Set the time offset to 0 croptimeoffset=0; } else { //Convert to a double croptimeoffset=StringToDouble(cropstart); //Get the number of dropped scans that occurred in the crop prior to y start (if y start = 0 so will this) std::string prevdropscans=bilin.FromHeader("dropped scans before y start"); if(prevdropscans.compare("")==0) { Logger::Warning("No 'dropped scans before y start' found in level 1 header, if y start is non-zero navigation may be wrongly synced."); //Set the time offset to 0 prevdropscans="0"; } double previousdroppedscans=StringToDouble(prevdropscans); //Convert the sum of the frames (cropstart and prevdropscans) to a time offset to add onto start time croptimeoffset=(croptimeoffset + previousdroppedscans)/framerate; Logger::Log("Using cropped level-1 data - will add a time offset relating to number of lines cropped (y start + dropped scans values in hdr): "+ToString(croptimeoffset)); } //Close the level 1 file bilin.Close(); //Create the scan time array time=new double[nscans]; //Get the number of leap seconds for the data LeapSecond leap; leapseconds=leap.GetLeapSeconds(acquisitiondate,dateformat); DEBUGPRINT("Using leap seconds of:"<<leapseconds); }
//------------------------------------------------------------------------- // Function to get times for each scan line //------------------------------------------------------------------------- void NavigationSyncer::FindScanTimes() { //Get the time interval, in seconds, between scan lines //nscans should include ALL scans i.e. dropped scans too //A negative usersynctime means that it will use the hdr/nav files //to find the scan times, +ve means the first scan line will have time usersynctime double scanseparation= 1.0 /framerate; //Now need to find the time for the first scan line //To do this we need the time from the nav file when the sync occurred if(navfile!=NULL) // Use the nav/hdr files to find the sync message { //Check for single versus multiple time stamps bool persec=navfile->UsePerSecondForSync(); int syncrecord_index=0; //We need to test which of the sync messages is for this file - can look at GPS time of sync message //and select the one that is closest to the header start time double lev1starttime=GetSecOfWeek(acquisitiondate,ReplaceAllWith(&gpsstarttime,':',' '),dateformat); int mindiff=std::numeric_limits<int>::max(); // if(navfile->GetNumSyncs()==0) { throw "No sync messages found in Specim nav file."; } //Need to loop through all syncs to find the one closest to start time for(unsigned int vecindex=0;vecindex<navfile->GetNumSyncs();vecindex++) { if( abs(lev1starttime - navfile->GetGPSSync(vecindex)) < mindiff) { mindiff=abs(lev1starttime - navfile->GetGPSSync(vecindex)); syncrecord_index=vecindex; } } //Now have a second test here to make sure that the selected index is within X seconds //of the level 1 start time. This is hard coded below! if(mindiff > lev1firstscanmaxexpectedsize) { //Are there multiple sync messages? if((navfile->GetNumSyncs()>1)&&(persec==false)) { //Closest is still greater than "lev1firstscanmaxexpectedsize" seconds away - just list choices and let user select. Logger::Log("Multiple identical sync delay values in Specim nav file. None fall within the "+ToString(lev1firstscanmaxexpectedsize)+" seconds window of start time of level 1 file."); Logger::Log("Header start time: "+ToString(lev1starttime)+" sync delay value: "+ToString(hdrsync)+" ["+ToString(NOSYNCINHDR)+" means no header sync value]"); for(unsigned int vecindex=0;vecindex<navfile->GetNumSyncs();vecindex++) { //The value to add onto the hdr start time to get the "synced" time assuming the hdr start time is used as scan line 0 time double scntoff=(navfile->GetGPSSync(vecindex) -navfile->GetSyncDelay(vecindex)) - lev1starttime; Logger::Log("Sync message time: "+ToString(navfile->GetGPSSync(vecindex))+" Scantimeoffset value to use: "+ToString(scntoff)); } throw "Multiple possibilities for sync time. Try using one of the suggested values above as a -scantimeoffset and processing with -nonav"; } else if((navfile->GetNumSyncs()>1)&&(persec==true)) { //This is to be expected (more than 1 sync in file) //Should be closer to start time than lev1firstscanmaxexpectedsize though? Logger::Warning("Sync message found (per second) but greater than 'maximum expected size' of "+ToString(lev1firstscanmaxexpectedsize)+" seconds away from level1 start time."); } else { //Only 1 sync message but > lev1firstscanmaxexpectedsize seconds away - use with a warning Logger::Warning("1 Sync message found but greater than 'maximum expected size' of "+ToString(lev1firstscanmaxexpectedsize)+" seconds away from level1 start time."); } } //output a message for the sync index used if(persec==false) { Logger::Log("Using the sync message from index "+ToString(syncrecord_index)+" which probably means it is for flight line "+ToString(syncrecord_index)+" in this specim nav file (note these are referenced from 0 not 1)."); Logger::Log("Sync value: "+ToString(navfile->GetSyncDelay(syncrecord_index))); } else { Logger::Log("Using the per second sync messages in this specim nav file."); Logger::Log("First sync delay value: "+ToString(navfile->GetSyncDelay(0))); } //Get the GPS time of the (first?) sync message double gps_integer_time=navfile->GetGPSSync(syncrecord_index); //Subtract the sync message time double firstscantime=gps_integer_time - navfile->GetSyncDelay(syncrecord_index); //Add on the cropped start time offset - this is 0 if no cropping (at the start of the line) has taken place Logger::Log("Applying crop time offset of: "+ToString(croptimeoffset)); firstscantime=firstscantime + croptimeoffset; //Compare to start time of level-1 header - in GPS sec of week - to prevent data from a different weekday being used CompareLev1ToNavTimes(firstscantime); if(persec==false) { //Set the per scan times for(unsigned int i=0;i<nscans;i++) time[i]=firstscantime + i*scanseparation; } else { unsigned int thissyncframe=navfile->GetFrame(syncrecord_index); unsigned int nextsyncframe=navfile->GetFrame(syncrecord_index+1); //Set the per scan times for(unsigned int i=0;i<nscans;i++) { if((i<nextsyncframe)&&(i>=thissyncframe)) time[i]=firstscantime + (i-thissyncframe)*scanseparation; else if(i<thissyncframe) { //This case shouldn't occur unless there is a problem with the nav file or our understanding of it //So for the moment we will not handle it other than to exit throw "(Software Bug): Frame number is less than current sync message frame - will need to write code for this eventuallity."; } else { //need to update to new sync message try { syncrecord_index++; if(syncrecord_index+1 < navfile->GetNumSyncs()) { thissyncframe=navfile->GetFrame(syncrecord_index); nextsyncframe=navfile->GetFrame(syncrecord_index+1); } else { //Here we don't actually have a next sync message - so all following scans shall use previous PPS to sync to //adding on 1000 as an arbitrarily large number - this could essentially be anything > 1 nextsyncframe+=1000; //Decrease the syncrecord index back to what it was syncrecord_index--; } gps_integer_time=navfile->GetGPSSync(syncrecord_index); firstscantime=gps_integer_time - navfile->GetSyncDelay(syncrecord_index); firstscantime=firstscantime + croptimeoffset; } catch(...) { throw "Error in persecond syncing for each scantime - probably accessing past a bounded array. This is a coding bug - report it."; } time[i]=firstscantime + (i-thissyncframe)*scanseparation; } } } Logger::Log("First scan will have time: "+ToString(time[0])+". Last scan will have time: "+ToString(time[nscans-1])); } else //Use a user-specified value as the first scan time { double firstscantime=0; //Use the start time from the header file as the first scan time firstscantime=GetSecOfWeek(acquisitiondate,ReplaceAllWith(&gpsstarttime,':',' '),dateformat); Logger::Log("Using a first scan time of "+ToString(firstscantime)); //Add on the cropped start time offset - this is 0 if no cropping (at the start of the line) has taken place Logger::Log("Applying crop time offset of: "+ToString(croptimeoffset)); firstscantime=firstscantime + croptimeoffset; //Set the per scan times for(unsigned int i=0;i<nscans;i++) time[i]=firstscantime + i*scanseparation; DEBUGPRINT("First scan time: "<<time[0]<<" Last scan time: "<<time[nscans-1]); } }
//------------------------------------------------------------------------- // Function to read in the information from the header file and store in map // Keys are now converted to lowercase , Values are not converted //------------------------------------------------------------------------- int BinaryReader::ReadHeader() { //DEBUG statement DEBUGPRINT("Reading BIL Header file..."); //Open the header file //It is expected to be the same as filename(-'raw' + 'hdr') //std::string hdrfile=this->filename; //hdrfile.replace(this->filename.length() - 3, 3, "hdr"); std::string hdrfile; //Now try and open the file std::ifstream hdrin; int failcount=0,maxtypes=2; //Loop through the types of header file name to try and open until one works for(short int type=0;type<maxtypes;type++) { this->hdrfilename=GetHeaderFileName(type); hdrin.open(this->hdrfilename.c_str()); if(!hdrin.is_open()) { failcount++; //An error has occured //brinfo<<"An error has occurred opening the hdr file: "<<this->hdrfilename<<std::endl; continue; //return -1; } else break; } if(failcount==maxtypes) { //An error has occured brinfo<<"Unable to open a hdr file, does one exist?"<<std::endl; return -1; } else { //the hdr file has been opened successfully //Now search for the number of lines/samples/bands first std::string strbuffer;//buffer to hold lines from hdr file std::string strkey; //string for storing map key temporarally std::string strval; //string for storing map value temporarly bool multilineval=false; // bool to test if values are over multiple file lines while(!hdrin.eof()) { //get a line from the hdr file std::getline(hdrin,strbuffer); //std::cout<<strbuffer<<std::endl; //search for an equals if(strbuffer.find('=') != std::string::npos) { //An = has been found in this string if(strbuffer.find('{') != std::string::npos) { //A { has been found. This could mean that the value is on more than one line strkey=strbuffer.substr(0,strbuffer.find('=')); //can set key strval.assign(strbuffer.substr(strbuffer.find('=')+1)); //this is part of value //trim whitespace strkey=TrimWhitespace(strkey); strval=TrimWhitespace(strval); if(strbuffer.find('}')!=std::string::npos) // } also found on same line { //The value is only on one line this->Header[ToLowerCase(strkey)]=strval; strkey.clear(); strval.clear(); continue; } else multilineval=true;// value is spread over multiple lines of header file } else { //The value is only on this line //Split up string at equals strkey=strbuffer.substr(0,strbuffer.find('=')); strval=strbuffer.substr(strbuffer.find('=')+1); //trim whitespace strkey=TrimWhitespace(strkey); strval=TrimWhitespace(strval); this->Header[ToLowerCase(strkey)]=strval; strkey.clear(); strval.clear();//empty the string continue; } } else if(strbuffer.find('}') != std::string::npos) { //there is a }. This could mean that the end of a value has been reached //Check if found at the end of the line (whitespace removed) strbuffer=TrimWhitespace(strbuffer); if(strbuffer.find('}')==strbuffer.length()-1) { //At the end - get everything upto there as values - comma separates values strbuffer=ReplaceAllWith(&strbuffer,',',';'); strval=strval+";"+strbuffer; // add the string to the value string using ; as delimiter this->Header[ToLowerCase(strkey)]=strval; //add to the header map multilineval=false; //reset the bool strval.clear(); } else { //Not at the end - this is odd throw "Error. Problem with hdr file - contains data after '}' value: "+strbuffer; } } if((strbuffer.find('=') == std::string::npos) && (strbuffer.find('}') == std::string::npos)) // no = and no } { strbuffer=TrimWhitespace(strbuffer); //No = in this string if(multilineval==false)//For the moment will just pass this as the key AND value into the map { this->Header[strbuffer]=strbuffer; } else if(!strbuffer.empty()) { // 14/02/2011 TrimPunctuation and then remove commas and replace with ';' - this could be dangerous strbuffer=TrimPunctuation(strbuffer); strbuffer=ReplaceAllWith(&strbuffer,',',';'); strval=strval+";"+strbuffer; // add the string to the value string using ; as delimiter } } } //close the file hdrin.close(); hdrin.clear(); } return 1; }