//**************************************************************** /** @class FitsDumper @brief Dumps contents of fits tables to stdout or a file */ //**************************************************************** #include "Configuration.h" #include #include #include //#define PLOTTING_PLEASE #ifdef PLOTTING_PLEASE #include #include #include #include #include #include #include #include #include #include "Time.h" #endif using namespace std; class MyColumn : public CCfits::Column { public: const string &comment() const { return CCfits::Column::comment(); } long width() const {//the width() method seems to be buggy (or empty ?) as it always return 1... redo it ourselves. string inter = format(); inter = inter.substr(0, inter.size()-1); return atoi(inter.c_str()); } }; #ifdef PLOTTING_PLEASE class TimeScaleDraw: public QwtScaleDraw { public: virtual QwtText label(double v) const { Time t(v); string time = t.GetAsStr("%H:%M:%S%F"); while (time[time.size()-1] == '0' && time.size() > 2) { time = time.substr(0, time.size()-1); } return QwtText(time.c_str()); } }; #endif class FitsDumper { public: FitsDumper(); ~FitsDumper(); private: CCfits::FITS *fFile; /// FITS pointer CCfits::Table *fTable; /// Table pointer map fColMap; /// map between the column names and their CCfits objects // Convert CCfits::ValueType into a human readable string string ValueTypeToStr(CCfits::ValueType type) const; // Convert CCfits::ValueType into a number of associated bytes int ValueTypeToSize(CCfits::ValueType type) const; /// Calculate the buffer size required to read a row of the fits table, as well as the offsets to each column vector CalculateOffsets() const; template T PtrToValue(const unsigned char* &ptr) const; // template // double PtrToDouble(const unsigned char *ptr) const; // double PtrToDouble(const unsigned char *ptr, CCfits::ValueType type) const; /// Write a single row of the selected data int WriteRow(ostream &, const vector &, const vector &, unsigned char *, const vector >&) const; bool OpenFile(const string &); /// Open a file bool OpenTable(const string &); /// Open a table /// Lists all columns of an open file void List(); void ListHeader(); void ListKeywords(ostream &); bool separateColumnsFromRanges(const vector& list, vector >& ranges, vector& listNamesOnly); /// Perform the dumping, based on the current dump list bool Dump(const string &, const vector &list, int); ///Display the selected columns values VS time #ifdef PLOTTING_PLEASE int doCurvesDisplay( const vector &list, const string& tableName); #endif // bool Plot(const vector &list); public: ///Configures the fitsLoader from the config file and/or command arguments. int ExecConfig(Configuration& conf); }; // -------------------------------------------------------------------------- // //! Constructor //! @param out //! the ostream where to redirect the outputs // FitsDumper::FitsDumper() : fFile(0), fTable(0) { } // -------------------------------------------------------------------------- // //! Destructor // FitsDumper::~FitsDumper() { if (fFile) delete fFile; } string FitsDumper::ValueTypeToStr(CCfits::ValueType type) const { switch (type) { case CCfits::Tbyte: return "uint8_t"; case CCfits::Tushort: return "uint16_t"; case CCfits::Tshort: return "int16_t"; case CCfits::Tuint: return "uint32_t"; case CCfits::Tint: return "int32_t"; case CCfits::Tulong: return "uint32_t"; case CCfits::Tlong: return "int32_t"; case CCfits::Tlonglong: return "int64_t"; case CCfits::Tfloat: return "float"; case CCfits::Tdouble: return "double"; default: return "unknwown"; } } int FitsDumper::ValueTypeToSize(CCfits::ValueType type) const { switch (type) { case CCfits::Tbyte: return sizeof(uint8_t); case CCfits::Tushort: case CCfits::Tshort: return sizeof(uint16_t); case CCfits::Tuint: case CCfits::Tint: case CCfits::Tulong: case CCfits::Tlong: return sizeof(uint32_t); case CCfits::Tlonglong: return sizeof(uint64_t); case CCfits::Tfloat: return sizeof(float); case CCfits::Tdouble: return sizeof(double); default: return 0; } } template T FitsDumper::PtrToValue(const unsigned char* &ptr) const { T t; reverse_copy(ptr, ptr+sizeof(T), reinterpret_cast(&t)); ptr += sizeof(T); return t; } /* template double FitsDumper::PtrToDouble(const unsigned char *ptr) const { T t; reverse_copy(ptr, ptr+sizeof(T), reinterpret_cast(&t)); return t; } double FitsDumper::PtrToDouble(const unsigned char *ptr, CCfits::ValueType type) const { switch (type) { case CCfits::Tbyte: return PtrToDouble (ptr); case CCfits::Tushort: return PtrToDouble(ptr); case CCfits::Tuint: case CCfits::Tulong: return PtrToDouble(ptr); case CCfits::Tshort: return PtrToDouble (ptr); case CCfits::Tint: case CCfits::Tlong: return PtrToDouble (ptr); case CCfits::Tlonglong: return PtrToDouble (ptr); case CCfits::Tfloat: return PtrToDouble (ptr); case CCfits::Tdouble: return PtrToDouble (ptr); default: throw runtime_error("Data type not implemented yet."); } } */ // -------------------------------------------------------------------------- // //! Writes a single row of the selected FITS data to the output file. //! //! Data type \b not yet implemented: //! CCfits::Tnull, CCfits::Tbit, CCfits::Tlogical, CCfits::Tstring, //! CCfits::Tcomplex, CCfits::Tdblcomplex, CCfits::VTbit, //! CCfits::VTbyte, CCfits::VTlogical, CCfits::VTushort, //! CCfits::VTshort, CCfits::VTuint, CCfits::VTint, CCfits::VTulong, //! CCfits::VTlong, CCfits::VTlonglong, CCfits::VTfloat, //! CCfits::VTdouble, CCfits::VTcomplex, CCfits::VTdblcomplex //! //! @param offsets //! a vector containing the offsets to the columns (in bytes) //! @param targetFile //! the ofstream where to write to //! @param fitsBuffer //! the memory were the row has been loaded by cfitsio // int FitsDumper::WriteRow(ostream &out, const vector &list, const vector &offsets, unsigned char* fitsBuffer, const vector >& ranges) const { int cnt = 0; vector >::const_iterator jt = ranges.begin(); for (vector::const_iterator it=list.begin(); it!=list.end(); it++, jt++) { if (jt == ranges.end()) { cout << "ERROR: END OF RANGE POINTER REACHED" << endl; return false; } const MyColumn *col = *it; // CCfits starts counting at 1 not 0 const int offset = offsets[col->index()-1]; // Get the pointer to the array which we are supposed to print const unsigned char *ptr = fitsBuffer + offset; // Loop over all array entries int sizeToSkip = 0; switch (col->type()) { case CCfits::Tbyte: sizeToSkip = sizeof(uint8_t); break; case CCfits::Tushort: sizeToSkip = sizeof(uint16_t); break; case CCfits::Tuint: case CCfits::Tulong: sizeToSkip = sizeof(uint32_t); break; case CCfits::Tshort: sizeToSkip = sizeof(int16_t); break; case CCfits::Tint: case CCfits::Tlong: sizeToSkip = sizeof(int32_t); break; case CCfits::Tlonglong: sizeToSkip = sizeof(int64_t); break; case CCfits::Tfloat: sizeToSkip = sizeof(float); break; case CCfits::Tdouble: sizeToSkip = sizeof(double); break; default: cerr << "Data type not implemented yet." << endl; return 0; } ptr += sizeToSkip*jt->first; for (int width=jt->first; widthsecond; width++) { switch (col->type()) { case CCfits::Tbyte: out << PtrToValue (ptr); break; case CCfits::Tushort: out << PtrToValue(ptr); break; case CCfits::Tuint: case CCfits::Tulong: out << PtrToValue(ptr); break; case CCfits::Tshort: out << PtrToValue (ptr); break; case CCfits::Tint: case CCfits::Tlong: out << PtrToValue (ptr); break; case CCfits::Tlonglong: out << PtrToValue (ptr); break; case CCfits::Tfloat: out << PtrToValue (ptr); break; case CCfits::Tdouble: out << PtrToValue (ptr); break; default: cerr << "Data type not implemented yet." << endl; return 0; } out << " "; cnt++; } } if (cnt>0) out << endl; if (out.fail()) { cerr << "ERROR - writing output: " << strerror(errno) << endl; return -1; } return cnt; } // -------------------------------------------------------------------------- // //! Calculates the required buffer size for reading one row of the current //! table. Also calculates the offsets to all the columns // vector FitsDumper::CalculateOffsets() const { map sizes; for (map::const_iterator it=fColMap.begin(); it!=fColMap.end(); it++) { const int &width = it->second->width(); const int &idx = it->second->index(); const int size = ValueTypeToSize(it->second->type()); if (size==0) { cerr << "Data type " << (int)it->second->type() << " not implemented yet." << endl; return vector(); } //cout << "data size: " << size << " width: " << width << " index: " << idx << endl; int realwidth = (width == 0)? 1 : width; sizes[idx] = size*realwidth; } //calculate the offsets in the vector. vector result(1, 0); int size = 0; int idx = 0; for (map::const_iterator it=sizes.begin(); it!=sizes.end(); it++) { size += it->second; result.push_back(size); if (it->first == ++idx) continue; cerr << "Expected index " << idx << ", but found " << it->first << endl; return vector(); } return result; } // -------------------------------------------------------------------------- // //! Loads the fits file based on the current parameters // bool FitsDumper::OpenFile(const string &filename) { if (fFile) delete fFile; ostringstream str; try { fFile = new CCfits::FITS(filename); } catch (CCfits::FitsException e) { cerr << "Could not open FITS file " << filename << " reason: " << e.message() << endl; return false; } return true; } bool FitsDumper::OpenTable(const string &tablename) { if (!fFile) { cerr << "No file open." << endl; return false; } const multimap< string, CCfits::ExtHDU * > extMap = fFile->extension(); if (extMap.find(tablename) == extMap.end()) { cerr << "Table '" << tablename << "' not found." << endl; return false; } fTable = dynamic_cast(extMap.find(tablename)->second); if (!fTable) { cerr << "Object '" << tablename << "' returned not a CCfits::Table." << endl; return false; } map& tCols = fTable->column(); for (map::const_iterator it = tCols.begin(); it != tCols.end(); it++) { fColMap.insert(make_pair(it->first, static_cast(it->second))); } // fColMap = fTable->column(); fTable->makeThisCurrent(); fTable->getComments(); fTable->getHistory(); fTable->readAllKeys(); return true; } void FitsDumper::List() { if (!fFile) { cerr << "No file open." << endl; return; } cout << "\nFile: " << fFile->name() << "\n"; const multimap< string, CCfits::ExtHDU * > extMap = fFile->extension(); for (std::multimap::const_iterator it=extMap.begin(); it != extMap.end(); it++) { CCfits::Table *table = dynamic_cast(extMap.find(it->first)->second); table->makeThisCurrent(); table->readData(); cout << " " << it->first << " [" << table->rows() << "]\n"; const map &cols = table->column(); // for (map::const_iterator id = cols.begin(); ib != cols.end(); ib++) // { // TFORM // } for (map::const_iterator ic=cols.begin(); ic != cols.end(); ic++) { const MyColumn *col = static_cast(ic->second); cout << " " << col->name() << "[" ; if (col->width() == 0) cout << 1; else cout << col->width(); cout << "] * " << col->scale() << " (" << col->unit() << ":" << ValueTypeToStr(col->type())<< ") " << col->comment() << "\n"; /* inline size_t Column::repeat () const inline bool Column::varLength () const inline double Column::zero () const inline const String& Column::display () const inline const String& Column::dimen () const inline const String& Column::TBCOL () inline const String& Column::TTYPE () inline const String& Column::TFORM () inline const String& Column::TDISP () inline const String& Column::TZERO () inline const String& Column::TDIM () inline const String& Column::TNULL () inline const String& Column::TLMIN () inline const String& Column::TLMAX () inline const String& Column::TDMAX () inline const String& Column::TDMIN () */ } cout << '\n'; } cout << flush; } class MyKeyword : public CCfits::Keyword { public: CCfits::ValueType keytype() const { return CCfits::Keyword::keytype(); } }; void FitsDumper::ListKeywords(ostream &out) { map keys = fTable->keyWord(); for (map::const_iterator it=keys.begin(); it!=keys.end(); it++) { string str; double d; int l; const MyKeyword *kw = static_cast(it->second); kw->keytype(); out << "## " << setw(8) << kw->name() << " = " << setw(10); if (kw->keytype()==16) out << ("'"+kw->value(str)+"'"); if (kw->keytype()==31) out << kw->value(l); if (kw->keytype()==82) out << kw->value(d); out << " / " << kw->comment() << endl; } } void FitsDumper::ListHeader() { if (!fTable) { cerr << "No table open." << endl; return; } cout << "\nTable: " << fTable->name() << " (rows=" << fTable->rows() << ")\n"; if (!fTable->comment().empty()) cout << "Comment: \t" << fTable->comment() << '\n'; if (!fTable->history().empty()) cout << "History: \t" << fTable->history() << '\n'; ListKeywords(cout); cout << endl; } bool FitsDumper::separateColumnsFromRanges(const vector& list, vector >& ranges, vector& listNamesOnly) { for (vector::const_iterator it=list.begin(); it!=list.end(); it++) { string columnNameOnly = *it; unsigned long bracketIndex0 = columnNameOnly.find_first_of('['); unsigned long bracketIndex1 = columnNameOnly.find_first_of(']'); unsigned long colonIndex = columnNameOnly.find_first_of(':'); // cout << bracketIndex0 << " " << bracketIndex1 << " " << colonIndex << endl; int columnStart = -1; int columnEnd = -1; if (bracketIndex0 != string::npos) {//there is a range given. Extract the range if (colonIndex != string::npos) {//we have a range here columnStart = atoi(columnNameOnly.substr(bracketIndex0+1, colonIndex-(bracketIndex0+1)).c_str()); columnEnd = atoi(columnNameOnly.substr(colonIndex+1, bracketIndex1-(colonIndex+1)).c_str()); columnEnd++; } else {//only a single index there columnStart = atoi(columnNameOnly.substr(bracketIndex0+1, bracketIndex1 - (bracketIndex0+1)).c_str()); columnEnd = columnStart+1; // cout << "Cstart " << columnStart << " end: " << columnEnd << endl; } columnNameOnly = columnNameOnly.substr(0, bracketIndex0); } if (fColMap.find(columnNameOnly) == fColMap.end()) { cerr << "ERROR - Column '" << columnNameOnly << "' not found in table." << endl; return false; } // cout << "The column name is: " << columnNameOnly << endl; MyColumn *cCol = static_cast(fColMap.find(columnNameOnly)->second); if (bracketIndex0 == string::npos) {//no range given: use the full range ranges.push_back(make_pair(0, cCol->width())); columnStart = 0; columnEnd = 1; } else {//use the range extracted earlier if (columnStart < 0) { cerr << "ERROR - Start range for column " << columnNameOnly << " is less than zero (" << columnStart << "). Aborting" << endl; return false; } if (columnEnd>1 && columnEnd > cCol->width()) { cerr << "ERROR - End range for column " << columnNameOnly << " is greater than the last element (" << cCol->width() << " vs " << columnEnd << "). Aborting" << endl; return false; } ranges.push_back(make_pair(columnStart, columnEnd)); } // cout << "Will be exporting from " << columnStart << " to " << columnEnd-1 << " for column " << columnNameOnly << endl; listNamesOnly.push_back(columnNameOnly); } return true; } // -------------------------------------------------------------------------- // //! Perform the actual dump, based on the current parameters // bool FitsDumper::Dump(const string &filename, const vector &list, int precision) { //first of all, let's separate the columns from their ranges and check that the requested columns are indeed part of the file vector > ranges; vector listNamesOnly; if (!separateColumnsFromRanges(list, ranges, listNamesOnly)) { cerr << "Something went wrong while extracting the columns names from parameters. Aborting" << endl; return false; } // FIXME: Maybe do this when opening a table? const vector offsets = CalculateOffsets(); // for (int i=0;iname() << '\n'; if (!fTable->comment().empty()) out << "## Comment: \t" << fTable->comment() << '\n'; if (!fTable->history().empty()) out << "## History: \t" << fTable->history() << '\n'; out << "## NumRows: \t" << fTable->rows() << '\n'; out << "## --------------------------------------------------------------------------\n"; ListKeywords(out); out << "## --------------------------------------------------------------------------\n"; out << "#\n"; //vector >::const_iterator rangesIt = ranges.begin(); //the above is soooo yesterday ;) let's try the new auto feature of c++0x auto rangesIt = ranges.begin(); for (vector::const_iterator it=listNamesOnly.begin(); it!=listNamesOnly.end(); it++, rangesIt++) { const MyColumn *col = static_cast(fTable->column()[*it]); if (rangesIt->first != 0 || rangesIt->second != col->width()) { out << "#"; for (int i=rangesIt->first; isecond; i++) out << " " << col->name() << "[" << i << "]"; out << ": " << col->unit(); } else out << "# " << col->name() << "[" << col->width() << "]: " << col->unit(); if (!col->comment().empty()) out << " (" <comment() << ")"; out << '\n'; } out << "#" << endl; // Loop over all columns in our list of requested columns vector columns; for (vector::const_iterator it=listNamesOnly.begin(); it!=listNamesOnly.end(); it++) { MyColumn *cCol = static_cast(fColMap.find(*it)->second); columns.push_back(cCol); } const int size = offsets[offsets.size()-1]; unsigned char* fitsBuffer = new unsigned char[size]; int status = 0; int endIndex = (fColMap.find("Time") == fColMap.end()) ? fTable->rows()-1 : fTable->rows(); for (int i=1; i<=endIndex; i++) { fits_read_tblbytes(fFile->fitsPointer(), i, 1, size, fitsBuffer, &status); if (status) { char text[30];//max length of cfitsio error strings (from doc) fits_get_errstatus(status, text); cerr << "Reading row " << i << " failed: " << text << " (fits_insert_rows,rc=" << status << ")" << endl; break; } if (WriteRow(out, columns, offsets, fitsBuffer, ranges)<0) { status=1; break; } } delete[] fitsBuffer; return status==0; } // -------------------------------------------------------------------------- // //! Perform the actual dump, based on the current parameters // /* bool FitsDumper::Plot(const vector &list) { for (vector::const_iterator it=list.begin(); it!=list.end(); it++) if (fColMap.find(*it) == fColMap.end()) { cerr << "WARNING - Column '" << *it << "' not found in table." << endl; return false; } // FIXME: Maybe do this when opening a table? const vector offsets = CalculateOffsets(); if (offsets.size()==0) return false; // Loop over all columns in our list of requested columns const CCfits::Column *col[3] = { list.size()>0 ? fColMap.find(list[0])->second : 0, list.size()>1 ? fColMap.find(list[1])->second : 0, list.size()>2 ? fColMap.find(list[2])->second : 0 }; const int size = offsets[offsets.size()-1]; unsigned char* fitsBuffer = new unsigned char[size]; const int idx = 0; // CCfits starts counting at 1 not 0 const size_t pos[3] = { col[0] ? offsets[col[0]->index()-1] + idx*col[0]->width()*ValueTypeToSize(col[0]->type()) : 0, col[1] ? offsets[col[1]->index()-1] + idx*col[1]->width()*ValueTypeToSize(col[1]->type()) : 0, col[2] ? offsets[col[2]->index()-1] + idx*col[2]->width()*ValueTypeToSize(col[2]->type()) : 0 }; int status = 0; for (int i=1; i<=fTable->rows(); i++) { fits_read_tblbytes(fFile->fitsPointer(), i, 1, size, fitsBuffer, &status); if (status) { cerr << "An error occurred while reading fits row #" << i << " error code: " << status << endl; break; } try { const double x[3] = { col[0] ? PtrToDouble(fitsBuffer+pos[0], col[0]->type()) : 0, col[1] ? PtrToDouble(fitsBuffer+pos[1], col[1]->type()) : 0, col[2] ? PtrToDouble(fitsBuffer+pos[2], col[2]->type()) : 0 }; } catch (const runtime_error &e) { cerr << e.what() << endl; status=1; break; } } delete[] fitsBuffer; return status==0; } */ // -------------------------------------------------------------------------- // //! Retrieves the configuration parameters //! @param conf //! the configuration object // int FitsDumper::ExecConfig(Configuration& conf) { if (conf.Has("fitsfile")) { if (!OpenFile(conf.Get("fitsfile"))) return -1; } if (conf.Get("list")) List(); if (conf.Has("tablename")) { if (!OpenTable(conf.Get("tablename"))) return -1; } #ifdef PLOTTING_PLEASE if (conf.Get("graph")) { if (!conf.Has("col")) { cout << "Please specify the columns that should be dumped as arguments. Aborting" << endl; return 0; } doCurvesDisplay(conf.Get>("col"), conf.Get("tablename")); return 1; } #endif if (conf.Get("header")) ListHeader(); if (conf.Get("header") || conf.Get("list")) return 1; if (conf.Has("outfile")) { if (!conf.Has("col")) { cout << "Please specify the columns that should be dumped as arguments. Aborting" << endl; return 0; } if (!Dump(conf.Get("outfile"), conf.Get>("col"), conf.Get("precision"))) return -1; } return 0; } void PrintUsage() { cout << "fitsdump is a tool to dump data from a FITS table as ascii.\n" "\n" "Usage: fitsdump [OPTIONS] fitsfile col col ... \n" " or: fitsdump [OPTIONS]\n"; cout << endl; } void PrintHelp() { // } #ifdef PLOTTING_PLEASE int FitsDumper::doCurvesDisplay( const vector &list, const string& tableName) { //first of all, let's separate the columns from their ranges and check that the requested columns are indeed part of the file vector > ranges; vector listNamesOnly; if (!separateColumnsFromRanges(list, ranges, listNamesOnly)) { cerr << "Something went wrong while extracting the columns names from parameters. Aborting" << endl; return false; } vector curvesNames; stringstream str; for (auto it=ranges.begin(), jt=listNamesOnly.begin(); it != ranges.end(); it++, jt++) { for (int i=it->first; isecond;i++) { str.str(""); str << *jt << "[" << i << "]"; curvesNames.push_back(str.str()); } } char* handle = new char[17]; sprintf(handle,"FitsDump Display"); // Qt::HANDLE h = *handle;//NULL int argc = 1; char ** argv = &handle; QApplication a(argc, argv); QwtPlot* plot = new QwtPlot(); QwtPlotGrid* grid = new QwtPlotGrid; grid->enableX(false); grid->enableY(true); grid->enableXMin(false); grid->enableYMin(false); grid->setMajPen(QPen(Qt::black, 0, Qt::DotLine)); grid->attach(plot); plot->setAutoReplot(true); string title = tableName; plot->setAxisScaleDraw( QwtPlot::xBottom, new TimeScaleDraw()); QWidget window; QHBoxLayout* layout = new QHBoxLayout(&window); layout->setContentsMargins(0,0,0,0); layout->addWidget(plot); QwtPlotZoomer zoom(plot->canvas()); zoom.setRubberBandPen(QPen(Qt::gray, 2, Qt::DotLine)); zoom.setTrackerPen(QPen(Qt::gray)); int totalSize = 0; for (unsigned int i=0;i curves(totalSize); int ii=0; for (auto it = curves.begin(), jt=curvesNames.begin(); it != curves.end(); it++, jt++) { *it = new QwtPlotCurve(jt->c_str()); switch (ii%6) { case 0: (*it)->setPen(QColor(255,0,0)); break; case 1: (*it)->setPen(QColor(0,255,0)); break; case 2: (*it)->setPen(QColor(0,0,255)); break; case 3: (*it)->setPen(QColor(255,255,0)); break; case 4: (*it)->setPen(QColor(0,255,255)); break; case 5: (*it)->setPen(QColor(255,0,255)); break; default: (*it)->setPen(QColor(0,0,0)); }; ii++; (*it)->setStyle(QwtPlotCurve::Lines); (*it)->attach(plot); } plot->insertLegend(new QwtLegend(), QwtPlot::RightLegend); const vector offsets = CalculateOffsets(); if (offsets.size()==0) return false; // Loop over all columns in our list of requested columns vector columns; for (vector::const_iterator it=listNamesOnly.begin(); it!=listNamesOnly.end(); it++) { MyColumn *cCol = static_cast(fColMap.find(*it)->second); columns.push_back(cCol); } //add the time column to the given columns if (fColMap.find("Time") == fColMap.end() && fColMap.find("UnixTimeUTC") == fColMap.end()) { cerr << "Error: time column could not be found in given table. Aborting" << endl; return false; } MyColumn* timeCol; bool unixTime = false; int endIndex = 0; if (fColMap.find("Time") != fColMap.end()) { timeCol = static_cast(fColMap.find("Time")->second); ranges.push_back(make_pair(0,1)); endIndex = fTable->rows(); } if (fColMap.find("UnixTimeUTC") != fColMap.end()) { timeCol = static_cast(fColMap.find("UnixTimeUTC")->second); ranges.push_back(make_pair(0,2)); endIndex = fTable->rows()-1; unixTime = true; } columns.push_back(timeCol); ///// const int size = offsets[offsets.size()-1]; unsigned char* fitsBuffer = new unsigned char[size]; // stringstream str; str.str(""); int status = 0; vector xValues(totalSize); double* yValues; cout.precision(10); str.precision(20); for (auto it=xValues.begin(); it!=xValues.end(); it++) *it = new double[fTable->rows()]; yValues = new double[fTable->rows()]; cout.precision(3); for (int i=1; i<=endIndex; i++) { cout << "/r" << "Constructing graph " << ((float)(i)/(float)(endIndex))*100.0 << "%"; fits_read_tblbytes(fFile->fitsPointer(), i, 1, size, fitsBuffer, &status); if (status) { cerr << "An error occurred while reading fits row #" << i << " error code: " << status << endl; break; } if (WriteRow(str, columns, offsets, fitsBuffer, ranges)<0) { status=1; cerr << "An Error occured while reading the fits row " << i << endl; return -1; } // yValues[i-1] = i; for (auto it=xValues.begin(); it!= xValues.end(); it++) { str >> (*it)[i-1]; // cout << (*it)[i-1] << " "; } if (unixTime) { long u1, u2; str >> u1 >> u2; // cout << u1 << " " << u2; boost::posix_time::ptime unixTimeT( boost::gregorian::date(1970, boost::gregorian::Jan, 1), boost::posix_time::seconds(u1) + boost::posix_time::microsec(u2)); Time mjdTime(unixTimeT); yValues[i-1] = mjdTime.Mjd(); // cout << " " << mjdTime.Mjd() << endl; } else { str >> yValues[i-1]; } if (i==1) { Time t(yValues[0]); title += " - " + t.GetAsStr("%Y-%m-%d"); plot->setTitle(title.c_str()); } // cout << yValues[i-1] << " "; // cout << endl; } //set the actual data. auto jt = xValues.begin(); for (auto it=curves.begin(); it != curves.end(); it++, jt++) (*it)->setRawData(yValues, *jt, endIndex); QStack stack; double minX, minY, maxX, maxY; minX = minY = 1e10; maxX = maxY = -1e10; QRectF rect; QPointF point; for (auto it=curves.begin(); it!= curves.end(); it++) { rect = (*it)->boundingRect(); point = rect.bottomRight(); if (point.x() < minX) minX = point.x(); if (point.y() < minY) minY = point.y(); if (point.x() > maxX) maxX = point.x(); if (point.y() > maxY) maxY = point.y(); point = rect.topLeft(); if (point.x() < minX) minX = point.x(); if (point.y() < minY) minY = point.y(); if (point.x() > maxX) maxX = point.x(); if (point.y() > maxY) maxY = point.y(); } QPointF bottomRight(maxX, minY); QPointF topLeft(minX, maxY); QPointF center((bottomRight+topLeft)/2.f); stack.push(QRectF(topLeft + (topLeft-center)*(.5f),bottomRight + (bottomRight-center)*(.5f))); zoom.setZoomStack(stack); delete[] fitsBuffer; window.resize(600, 400); window.show(); a.exec(); for (auto it = curves.begin(); it != curves.end(); it++) { (*it)->detach(); delete *it; } grid->detach(); for (auto it = xValues.begin(); it != xValues.end(); it++) delete[] *it; delete[] yValues; delete[] handle; return 0; } #endif void SetupConfiguration(Configuration& conf) { po::options_description configs("Fitsdump options"); configs.add_options() ("fitsfile,f", var() #if BOOST_VERSION >= 104200 ->required() #endif , "Name of FITS file") ("tablename,t", var("DATA") #if BOOST_VERSION >= 104200 ->required() #endif , "Name of input table") ("col,c", vars(), "List of columns to dump\narg is a list of columns, separated by a space.\nAdditionnally, a list of sub-columns can be added\ne.g. Data[3] will dump sub-column 3 of column Data\nData[3:4] will dump sub-columns 3 and 4\nOmitting this argument dump the entire column\nnota: all indices start at zero") ("outfile,o", var("/dev/stdout"), "Name of output file (-:/dev/stdout)") ("precision,p", var(20), "Precision of ofstream") ("list,l", po_switch(), "List all tables and columns in file") ("header,h", po_switch(), "Dump header of given table") #ifdef PLOTTING_PLEASE ("graph,g", po_switch(), "Plot the columns instead of dumping them") #endif ; po::positional_options_description p; p.add("fitsfile", 1); // The first positional options p.add("col", -1); // All others conf.AddOptions(configs); conf.SetArgumentPositions(p); } int main(int argc, const char** argv) { Configuration conf(argv[0]); conf.SetPrintUsage(PrintUsage); SetupConfiguration(conf); if (!conf.DoParse(argc, argv, PrintHelp)) return -1; FitsDumper loader; return loader.ExecConfig(conf); }