// Copyright (C) 1999-2018 // Smithsonian Astrophysical Observatory, Cambridge, MA, USA // For conditions of distribution and use, see copyright notice in "copyright" #include #include "fitsimage.h" #include "framebase.h" #include "context.h" #include "mmap.h" #include "smmap.h" #include "mmapincr.h" #include "alloc.h" #include "allocgz.h" #include "channel.h" #include "share.h" #include "sshare.h" #include "socket.h" #include "socketgz.h" #include "var.h" #include "order.h" #include "iis.h" #include "hist.h" #include "compress.h" #include "analysis.h" #include "photo.h" #include "colorscale.h" FitsImage::FitsImage(Context* cx, Tcl_Interp* pp) { context_ =cx; interp_ =pp; objectKeyword_ =NULL; fileName =NULL; rootBaseFileName =NULL; fullBaseFileName =NULL; iisFileName =NULL; fits_ =NULL; post_ =NULL; hist_ =NULL; hpx_ =NULL; base_ =NULL; basedata_ =NULL; manageBlock_ =0; block_ =NULL; blockdata_ =NULL; manageAnalysis_ =0; analysis_ =NULL; analysisdata_ =NULL; image_ =NULL; data_ =NULL; nextMosaic_ =NULL; nextSlice_ =NULL; keyLTMV =0; keyATMV =0; keyDTMV =0; keyDATASEC =0; jyBeam_ =1; imageToData = Translate(-.5, -.5); dataToImage = Translate( .5, .5); imageToData3d = Translate3d(-.5, -.5, -.5); dataToImage3d = Translate3d( .5, .5, .5); imageToRef3d = imageToData3d; refToImage3d = dataToImage3d; manageWCS_ =1; ast_ =NULL; astInv_ =0; wcs_ =NULL; wcsCel_ =NULL; wcs3D_ =NULL; wcsHPX_ =0; wcsSize_ =NULL; wcsAltHeader_ =NULL; wfpc2Header_ =NULL; wcs0Header_ =NULL; iisMode_ =0; iiszt_ =0; for (int ii=0; iifitsFile(), hdr, data, sz); process(NULL,id); rootBaseFileName = dupstr(fi->rootBaseFileName); fullBaseFileName = dupstr(fi->fullBaseFileName); iisFileName = dupstr(fi->fullBaseFileName); } // Fits Next FitsImageFitsNextAlloc::FitsImageFitsNextAlloc(Context* cx, Tcl_Interp* pp, const char* fn, FitsFile* prev, int id) : FitsImage(cx, pp) { fits_ = new FitsFitsNextAlloc(prev); process(fn,id); } FitsImageFitsNextAllocGZ::FitsImageFitsNextAllocGZ(Context* cx, Tcl_Interp* pp, const char* fn, FitsFile* prev, int id) : FitsImage(cx, pp) { fits_ = new FitsFitsNextAllocGZ(prev); process(fn,id); } FitsImageFitsNextChannel::FitsImageFitsNextChannel(Context* cx, Tcl_Interp* pp, const char* fn, FitsFile* prev, int id) : FitsImage(cx, pp) { fits_ = new FitsFitsNextChannel(prev); process(fn,id); } FitsImageFitsNextMMap::FitsImageFitsNextMMap(Context* cx, Tcl_Interp* pp, const char* fn, FitsFile* prev, int id) : FitsImage(cx, pp) { fits_ = new FitsFitsNextMMap(prev); process(fn,id); } FitsImageFitsNextSMMap::FitsImageFitsNextSMMap(Context* cx, Tcl_Interp* pp, const char* fn, FitsFile* prev, int id) : FitsImage(cx, pp) { fits_ = new FitsFitsNextSMMap(prev); process(fn,id); } FitsImageFitsNextMMapIncr::FitsImageFitsNextMMapIncr(Context* cx, Tcl_Interp* pp, const char* fn, FitsFile* prev, int id) : FitsImage(cx, pp) { fits_ = new FitsFitsNextMMapIncr(prev); process(fn,id); } FitsImageFitsNextShare::FitsImageFitsNextShare(Context* cx, Tcl_Interp* pp, const char* fn, FitsFile* prev, int id) : FitsImage(cx, pp) { fits_ = new FitsFitsNextShare(prev); process(fn,id); } FitsImageFitsNextSShare::FitsImageFitsNextSShare(Context* cx, Tcl_Interp* pp, const char* fn, FitsFile* prev, int id) : FitsImage(cx, pp) { fits_ = new FitsFitsNextSShare(prev); process(fn,id); } FitsImageFitsNextSocket::FitsImageFitsNextSocket(Context* cx, Tcl_Interp* pp, const char* fn, FitsFile* prev, int id) : FitsImage(cx, pp) { fits_ = new FitsFitsNextSocket(prev); process(fn,id); } FitsImageFitsNextSocketGZ::FitsImageFitsNextSocketGZ(Context* cx, Tcl_Interp* pp, const char* fn, FitsFile* prev, int id) : FitsImage(cx, pp) { fits_ = new FitsFitsNextSocketGZ(prev); process(fn,id); } FitsImageFitsNextVar::FitsImageFitsNextVar(Context* cx, Tcl_Interp* pp, const char* fn, FitsFile* prev, int id) : FitsImage(cx, pp) { fits_ = new FitsFitsNextVar(prev); process(fn,id); } FitsImageFitsNextHist::FitsImageFitsNextHist(Context* cx, Tcl_Interp* pp, FitsImage* fi, FitsFile* prev, int id) : FitsImage(cx, pp) { fits_ = new FitsHistNext(prev); process(NULL,id); fits_->setpFilter(fi->getHistFilter()); fits_->setpBinX(fi->getHistX()); fits_->setpBinY(fi->getHistY()); fits_->setpBinZ(fi->getHistZ()); rootBaseFileName = dupstr(fi->rootBaseFileName); fullBaseFileName = dupstr(fi->fullBaseFileName); iisFileName = dupstr(fi->fullBaseFileName); } FitsImageFitsNextPost::FitsImageFitsNextPost(Context* cx, Tcl_Interp* pp, FitsImage* fi, FitsFile* prev, int id) : FitsImage(cx, pp) { fits_ = new FitsPostNext(prev); process(NULL,id); rootBaseFileName = dupstr(fi->rootBaseFileName); fullBaseFileName = dupstr(fi->fullBaseFileName); iisFileName = dupstr(fi->fullBaseFileName); } FitsImageFitsNextOrder::FitsImageFitsNextOrder(Context* cx, Tcl_Interp* pp, FitsImage* fi, FitsFile* prev, int id) : FitsImage(cx, pp) { fits_ = new FitsOrderNext(prev); process(NULL,id); rootBaseFileName = dupstr(fi->rootBaseFileName); fullBaseFileName = dupstr(fi->fullBaseFileName); iisFileName = dupstr(fi->fullBaseFileName); } // Array FitsImageArrAlloc::FitsImageArrAlloc(Context* cx, Tcl_Interp* pp, const char* ch, const char* fn, FitsFile::FlushMode flush, int id) : FitsImage(cx, pp) { fits_ = new FitsArrAlloc(ch, flush); process(fn,id); } FitsImageArrAllocGZ::FitsImageArrAllocGZ(Context* cx, Tcl_Interp* pp, const char* ch, const char* fn, FitsFile::FlushMode flush, int id) : FitsImage(cx, pp) { fits_ = new FitsArrAllocGZ(ch, flush); process(fn,id); } FitsImageArrChannel::FitsImageArrChannel(Context* cx, Tcl_Interp* pp, const char* ch, const char* fn, FitsFile::FlushMode flush, int id) : FitsImage(cx, pp) { fits_ = new FitsArrChannel(pp, ch, fn, flush); process(fn,id); } FitsImageArrMMap::FitsImageArrMMap(Context* cx, Tcl_Interp* pp, const char* fn, int id) : FitsImage(cx, pp) { fits_ = new FitsArrMMap(fn); process(fn,id); } FitsImageArrMMapIncr::FitsImageArrMMapIncr(Context* cx, Tcl_Interp* pp, const char* fn, int id) : FitsImage(cx, pp) { fits_ = new FitsArrMMapIncr(fn); process(fn,id); } FitsImageArrShare::FitsImageArrShare(Context* cx, Tcl_Interp* pp, Base::ShmType type, int sid, const char* fn, int id) : FitsImage(cx, pp) { switch (type) { case Base::SHMID: fits_ = new FitsArrShareID(sid, fn); break; case Base::KEY: fits_ = new FitsArrShareKey(sid, fn); break; } process(fn,id); } FitsImageArrSocket::FitsImageArrSocket(Context* cx, Tcl_Interp* pp, int s, const char* fn, FitsFile::FlushMode flush, int id) : FitsImage(cx, pp) { fits_ = new FitsArrSocket(s, fn, flush); process(fn,id); } FitsImageArrSocketGZ::FitsImageArrSocketGZ(Context* cx, Tcl_Interp* pp, int s, const char* fn, FitsFile::FlushMode flush, int id) : FitsImage(cx, pp) { fits_ = new FitsArrSocketGZ(s, fn, flush); process(fn,id); } FitsImageArrVar::FitsImageArrVar(Context* cx, Tcl_Interp* pp, const char* var, const char* fn, int id) : FitsImage(cx, pp) { fits_ = new FitsArrVar(pp, var, fn); process(fn,id); } // ENVI FitsImageENVISMMap::FitsImageENVISMMap(Context* cx, Tcl_Interp* pp, const char* hdr, const char* fn, int id) : FitsImage(cx, pp) { fits_ = new FitsENVISMMap(hdr,fn); process(fn,id); } // NRRD FitsImageNRRDAlloc::FitsImageNRRDAlloc(Context* cx, Tcl_Interp* pp, const char* ch, const char* fn, FitsFile::FlushMode flush, int id) : FitsImage(cx, pp) { fits_ = new FitsNRRDAlloc(ch, flush); process(fn,id); } FitsImageNRRDChannel::FitsImageNRRDChannel(Context* cx, Tcl_Interp* pp, const char* ch, const char* fn, FitsFile::FlushMode flush, int id) : FitsImage(cx, pp) { fits_ = new FitsNRRDChannel(pp, ch, fn, flush); process(fn,id); } FitsImageNRRDMMap::FitsImageNRRDMMap(Context* cx, Tcl_Interp* pp, const char* fn, int id) : FitsImage(cx, pp) { fits_ = new FitsNRRDMMap(fn); process(fn,id); } FitsImageNRRDShare::FitsImageNRRDShare(Context* cx, Tcl_Interp* pp, Base::ShmType type, int sid, const char* fn, int id) : FitsImage(cx, pp) { switch (type) { case Base::SHMID: fits_ = new FitsNRRDShareID(sid, fn); break; case Base::KEY: fits_ = new FitsNRRDShareKey(sid, fn); break; } process(fn,id); } FitsImageNRRDSocket::FitsImageNRRDSocket(Context* cx, Tcl_Interp* pp, int s, const char* fn, FitsFile::FlushMode flush, int id) : FitsImage(cx, pp) { fits_ = new FitsNRRDSocket(s, fn, flush); process(fn,id); } FitsImageNRRDVar::FitsImageNRRDVar(Context* cx, Tcl_Interp* pp, const char* var, const char* fn, int id) : FitsImage(cx, pp) { fits_ = new FitsNRRDVar(pp, var, fn); process(fn,id); } // Photo FitsImagePhoto::FitsImagePhoto(Context* cx, Tcl_Interp* pp, const char* ph, const char* fn, int id) : FitsImage(cx, pp) { fits_ = new FitsPhoto(pp, ph); process(fn,id); } FitsImagePhotoCube::FitsImagePhotoCube(Context* cx, Tcl_Interp* pp, const char* ph, const char* fn, int id) : FitsImage(cx, pp) { fits_ = new FitsPhotoCube(pp, ph); process(fn,id); } FitsImagePhotoCubeNext::FitsImagePhotoCubeNext(Context* cx, Tcl_Interp* pp, const char* fn, FitsFile* prev, int id) : FitsImage(cx, pp) { fits_ = new FitsPhotoCubeNext(prev); process(fn,id); } // Mosaic FitsImageMosaicAlloc::FitsImageMosaicAlloc(Context* cx, Tcl_Interp* pp, const char* ch, const char* fn, FitsFile::FlushMode flush, int id) : FitsImage(cx, pp) { fits_ = new FitsMosaicAlloc(ch, flush); process(fn,id); } FitsImageMosaicAllocGZ::FitsImageMosaicAllocGZ(Context* cx, Tcl_Interp* pp, const char* ch, const char* fn, FitsFile::FlushMode flush, int id) : FitsImage(cx, pp) { fits_ = new FitsMosaicAllocGZ(ch, flush); process(fn,id); } FitsImageMosaicChannel::FitsImageMosaicChannel(Context* cx, Tcl_Interp* pp, const char* ch, const char* fn, FitsFile::FlushMode flush, int id) : FitsImage(cx, pp) { fits_ = new FitsMosaicChannel(pp, ch, flush); process(fn,id); } FitsImageMosaicMMap::FitsImageMosaicMMap(Context* cx, Tcl_Interp* pp, const char* fn, int id) : FitsImage(cx, pp) { fits_ = new FitsMosaicMMap(fn); process(fn,id); } FitsImageMosaicMMapIncr::FitsImageMosaicMMapIncr(Context* cx, Tcl_Interp* pp, const char* fn, int id) : FitsImage(cx, pp) { fits_ = new FitsMosaicMMapIncr(fn); process(fn,id); } FitsImageMosaicShare::FitsImageMosaicShare(Context* cx, Tcl_Interp* pp, Base::ShmType type, int sid, const char* fn, int id) : FitsImage(cx, pp) { switch (type) { case Base::SHMID: fits_ = new FitsMosaicShareID(sid); break; case Base::KEY: fits_ = new FitsMosaicShareKey(sid); break; } process(fn,id); } FitsImageMosaicSocket::FitsImageMosaicSocket(Context* cx, Tcl_Interp* pp, int s, const char* fn, FitsFile::FlushMode flush, int id) : FitsImage(cx, pp) { fits_ = new FitsMosaicSocket(s, flush); process(fn,id); } FitsImageMosaicSocketGZ::FitsImageMosaicSocketGZ(Context* cx, Tcl_Interp* pp, int s, const char* fn, FitsFile::FlushMode flush, int id) : FitsImage(cx, pp) { fits_ = new FitsMosaicSocketGZ(s, flush); process(fn,id); } FitsImageMosaicVar::FitsImageMosaicVar(Context* cx, Tcl_Interp* pp, const char* var, const char* fn, int id) : FitsImage(cx, pp) { fits_ = new FitsMosaicVar(pp, var, fn); process(fn,id); } // Mosaic Next FitsImageMosaicNextAlloc::FitsImageMosaicNextAlloc(Context* cx, Tcl_Interp* pp, const char* fn, FitsFile* prev, FitsFile::FlushMode flush, int id) : FitsImage(cx, pp) { fits_ = new FitsMosaicNextAlloc(prev, flush); process(fn,id); } FitsImageMosaicNextAllocGZ::FitsImageMosaicNextAllocGZ(Context* cx, Tcl_Interp* pp, const char* fn, FitsFile* prev, FitsFile::FlushMode flush, int id) : FitsImage(cx, pp) { fits_ = new FitsMosaicNextAllocGZ(prev, flush); process(fn,id); } FitsImageMosaicNextChannel::FitsImageMosaicNextChannel(Context* cx, Tcl_Interp* pp, const char* fn, FitsFile* prev, FitsFile::FlushMode flush, int id) : FitsImage(cx, pp) { fits_ = new FitsMosaicNextChannel(prev, flush); process(fn,id); } FitsImageMosaicNextMMap::FitsImageMosaicNextMMap(Context* cx, Tcl_Interp* pp, const char* fn, FitsFile* prev, int id) : FitsImage(cx, pp) { fits_ = new FitsMosaicNextMMap(prev); process(fn,id); } FitsImageMosaicNextMMapIncr::FitsImageMosaicNextMMapIncr(Context* cx, Tcl_Interp* pp, const char* fn, FitsFile* prev, int id) : FitsImage(cx, pp) { fits_ = new FitsMosaicNextMMapIncr(prev); process(fn,id); } FitsImageMosaicNextShare::FitsImageMosaicNextShare(Context* cx, Tcl_Interp* pp, const char* fn, FitsFile* prev, int id) : FitsImage(cx, pp) { fits_ = new FitsMosaicNextShare(prev); process(fn,id); } FitsImageMosaicNextSocket::FitsImageMosaicNextSocket(Context* cx, Tcl_Interp* pp, const char* fn, FitsFile* prev, FitsFile::FlushMode flush, int id) : FitsImage(cx, pp) { fits_ = new FitsMosaicNextSocket(prev, flush); process(fn,id); } FitsImageMosaicNextSocketGZ::FitsImageMosaicNextSocketGZ(Context* cx, Tcl_Interp* pp, const char* fn, FitsFile* prev, FitsFile::FlushMode flush, int id) : FitsImage(cx, pp) { fits_ = new FitsMosaicNextSocketGZ(prev, flush); process(fn,id); } FitsImageMosaicNextVar::FitsImageMosaicNextVar(Context* cx, Tcl_Interp* pp, const char* fn, FitsFile* prev, int id) : FitsImage(cx, pp) { fits_ = new FitsMosaicNextVar(prev); process(fn,id); } // IIS FitsImageIIS::FitsImageIIS(Context* cx, Tcl_Interp* pp, int w, int h) : FitsImage(cx, pp) { fits_ = new FitsIIS(w, h); process("",1); iisMode_ = 1; } void FitsImageIIS::iisErase() { ((FitsIIS*)fits_)->erase(); } char* FitsImageIIS::iisGet(int xx, int yy, int dx, int dy) { return ((FitsIIS*)fits_)->get(xx, yy, dx, dy); } void FitsImageIIS::iisSet(const char* src, int xx, int yy, int dx, int dy) { ((FitsIIS*)fits_)->set(src, xx, yy, dx, dy); } void FitsImageIIS::iisWCS(const Matrix& mm, const Vector& z, int zt) { Matrix& mx = (Matrix&)mm; double sx = mx[0][0]; double sy = mx[1][1]; double tx = mx[2][0]; double ty = mx[2][1]; imageToPhysical = Translate(0,-height()/2.) * FlipY() * Translate(0,height()/2.) * Translate(-1,0) * Scale(sx,sy) * Translate(tx,ty); physicalToImage = imageToPhysical.invert(); iisz_ = z; iiszt_ = zt; } // FitsImage void FitsImage::wfpc2WCS(istream& str) { FitsHead* hh = parseWCS(str); // Process OBJECT keyword if (objectKeyword_) delete [] objectKeyword_; objectKeyword_ = dupstr(hh->getString("OBJECT")); // Process WCS keywords if (wfpc2Header_) delete wfpc2Header_; wfpc2Header_ = hh; initWCS(wfpc2Header_); } void FitsImage::appendWCS(istream& str) { FitsHead* hh = parseWCS(str); // process OBJECT keyword char* obj = dupstr(hh->getString("OBJECT")); if (obj) { if (objectKeyword_) delete [] objectKeyword_; objectKeyword_ = obj; } // Process WCS keywords FitsHead* hd = image_->head(); // append wcs keywords to the end of the header int ll = hd->headbytes()+hh->headbytes(); char* cards = new char[ll]; // copy default wcs memcpy(cards, hd->cards(), hd->headbytes()); // find first END and zero out for (int i=0; iheadbytes(); i+=80) if (!strncmp(cards+i,"END",3)) { memcpy(cards+i, " ",3); break; } // copy appended wcs memcpy(cards+hd->headbytes(), hh->cards(), hh->headbytes()); delete hh; if (wcsAltHeader_) delete wcsAltHeader_; wcsAltHeader_ = new FitsHead(cards,ll,FitsHead::ALLOC); initWCS(wcsAltHeader_); } char* FitsImage::display(FitsHead* hd) { int size = hd->ncard() * (FTY_CARDLEN+1); char* lbuf = new char[size+1]; char* lptr = lbuf; char* cptr = hd->cards(); for (int i=0; incard(); i++,cptr+=FTY_CARDLEN) { memcpy(lptr, cptr, FTY_CARDLEN); lptr+=FTY_CARDLEN; *(lptr++) = '\n'; } lbuf[size] = '\0'; return lbuf; } char* FitsImage::displayHeader() { Vector blockFactor = context_->blockFactor(); if (blockFactor[0] != 1 && blockFactor[1] != 1) return display(image_->head()); if (DebugBin || DebugCompress) return display(image_->head()); else return display(fits_->head()); } char* FitsImage::displayPrimary() { return display(fits_->primary()); } char* FitsImage::displayWCS() { if (wcsAltHeader_) return display(wcsAltHeader_); else if (wfpc2Header_) return display(wfpc2Header_); else if (wcs0Header_) return display(wcs0Header_); else return display(image_->head()); } FitsBound* FitsImage::getDataParams(FrScale::SecMode which) { switch (which) { case FrScale::IMGSEC: return &iparams; case FrScale::DATASEC: return &dparams; case FrScale::CROPSEC: return &cparams; } // just to satisfy the compiler return &iparams; } const char* FitsImage::getValue(const Vector& v) { if (!isIIS()) return data_->getValue(v); else { double val = data_->getValueDouble(v); ostringstream str; if (val == 0) str << ends; else if (val == IISMIN) str << '<' << iisz_[0] << ends; else if (val == IISMAX) str << '>' << iisz_[1] << ends; else if (val > IISMAX) str << ends; else // W_LINEAR =1 if (iiszt_ == 1) str << ((val-IISMIN) * (iisz_[1]-iisz_[0]))/(IISMAX-IISMIN) + iisz_[0] << ends; else str << val << ends; memcpy(buf,str.str().c_str(), str.str().length()); return buf; } } void FitsImage::iisSetFileName(const char* fn) { if (iisFileName) delete [] iisFileName; iisFileName = dupstr(fn); } void FitsImage::initWCS(FitsHead* hd) { if (manageWCS_) { if (ast_) astAnnul(ast_); ast_ =NULL; if (wcs_) delete [] wcs_; wcs_ =NULL; if (wcs_) delete [] wcs_; wcs_ =NULL; if (wcsCel_) delete [] wcsCel_; wcsCel_ =NULL; if (wcs3D_) delete [] wcs3D_; wcs3D_ =NULL; wcsHPX_ = 0; if (wcsSize_) delete [] wcsSize_; wcsSize_ =NULL; } // shareWCS? manageWCS_ =1; if (context_->shareWCS()) { FitsImage* ptr = context_->fits; while (ptr) { if (ptr == this) break; FitsImage* sptr = ptr->nextSlice(); while (sptr) { if (sptr == this) { ast_ = ptr->ast_; astInv_ = ptr->astInv_; wcs_ = ptr->wcs_; wcsCel_ = ptr->wcsCel_; wcs3D_ = ptr->wcs3D_; wcsHPX_ = ptr->wcsHPX_; wcsSize_ = ptr->wcsSize_; initWCSPhysical(); manageWCS_ =0; return; } sptr = sptr->nextSlice(); } ptr = ptr->nextMosaic(); } } int hasWCSAST = hd->find("BEGAST_A") ? 1 : 0; astInit(hd); wcsInit(hasWCSAST); wcsCelInit(hasWCSAST); wcs3DInit(hasWCSAST); wcsHPXInit(); wcsSizeInit(); initWCSPhysical(); if (DebugWCS && ast_) astShow(ast_); } void FitsImage::resetWCS() { // Process OBJECT keyword if (objectKeyword_) delete [] objectKeyword_; objectKeyword_ = dupstr(image_->getString("OBJECT")); if (wcsAltHeader_) delete wcsAltHeader_; wcsAltHeader_ =NULL; if (wcs0Header_) delete wcs0Header_; wcs0Header_ =NULL; if (wfpc2Header_) initWCS(wfpc2Header_); else initWCS(image_->head()); } void FitsImage::initWCS0(const Vector& pix) { if (!ast_) return; FitsHead* hd = new FitsHead(naxis(0), naxis(1), 1, -32); // CTYPE hd->appendString("CTYPE1", "RA---TAN", NULL); hd->appendString("CTYPE2", "DEC--TAN", NULL); // CRPIX Vector cc = mapFromRef(pix, Coord::IMAGE, Coord::FK5); hd->appendReal("CRPIX1", cc[1], 8, NULL); hd->appendReal("CRPIX2", cc[0], 8, NULL); // CRVAL hd->appendReal("CRVAL1", 0, 8, NULL); hd->appendReal("CRVAL2", 0, 8, NULL); // CD double ss = getWCSSize(Coord::WCS); double ang = getWCSRotation(Coord::WCS,Coord::FK5); Matrix flip; switch (getWCSOrientation(Coord::WCS,Coord::FK5)) { case Coord::NORMAL: case Coord::YY: flip = FlipX(); break; case Coord::XX: case Coord::XY: break; }; Matrix mx = flip*Rotate(ang)*Scale(ss); hd->appendReal("CD1_1", mx[0][0], 8, NULL); hd->appendReal("CD1_2", mx[0][1], 8, NULL); hd->appendReal("CD2_1", mx[1][0], 8, NULL); hd->appendReal("CD2_2", mx[1][1], 8, NULL); // EPOCH, EQUINOX hd->appendReal("EPOCH", 2000, 8, NULL); hd->appendReal("EQUINOX", 2000, 8, NULL); // RADESYS hd->appendString("RADESYS", "FK5", NULL); if (wcs0Header_) delete wcs0Header_; wcs0Header_ = hd; initWCS(wcs0Header_); } void FitsImage::initWCSPhysical() { // now see if we have a 'physical' in WCSP, if so, set LTMV keywords keyLTMV =0; char* wcsname = image_->getString("WCSNAMEP"); if (wcsname && *wcsname && !strncmp(wcsname, "PHYSICAL", 8)) { if (image_->find("CD1_1P") || image_->find("CD1_2P") || image_->find("CD2_1P") || image_->find("CD2_2P") || image_->find("CRPIX1P") || image_->find("CRPIX2P") || image_->find("CRVAL1P") || image_->find("CRVAL2P")) { keyLTMV = 1; double cd11 = image_->getReal("CD1_1P", 1); double cd12 = image_->getReal("CD1_2P", 0); double cd21 = image_->getReal("CD2_1P", 0); double cd22 = image_->getReal("CD2_2P", 1); double crpix1 = image_->getReal("CRPIX1P", 0); double crpix2 = image_->getReal("CRPIX2P", 0); double crval1 = image_->getReal("CRVAL1P", 0); double crval2 = image_->getReal("CRVAL2P", 0); double ltm11 = cd11 != 0 ? 1/cd11 : 0; double ltm12 = cd12 != 0 ? 1/cd12 : 0; double ltm21 = cd21 != 0 ? 1/cd21 : 0; double ltm22 = cd22 != 0 ? 1/cd22 : 0; double ltv1 = crpix1 - crval1*ltm11 - crval2*ltm21; double ltv2 = crpix2 - crval1*ltm12 - crval2*ltm22; physicalToImage = Matrix(ltm11, ltm12, ltm21, ltm22, ltv1, ltv2); imageToPhysical = physicalToImage.invert(); } } } void FitsImage::load() { if (post_) base_ = post_; else if (hpx_) base_ = hpx_; else if (hist_) base_ = hist_; else base_ = fits_; if (basedata_) delete basedata_; switch (base_->head()->bitpix()) { case 8: basedata_ = new FitsDatam(base_, interp_); break; case 16: basedata_ = new FitsDatam(base_, interp_); break; case -16: basedata_ = new FitsDatam(base_, interp_); break; case 32: basedata_ = new FitsDatam(base_, interp_); break; case 64: basedata_ = new FitsDatam(base_, interp_); break; case -32: basedata_ = new FitsDatam(base_, interp_); break; case -64: basedata_ = new FitsDatam(base_, interp_); break; } // block block_ = base_; blockdata_ = basedata_; // analysis analysis_ = block_; analysisdata_ = blockdata_; // image image_ = analysis_; data_ = analysisdata_; } void FitsImage::match(const char* xxname1, const char* yyname1, Coord::CoordSystem sys1, Coord::SkyFrame sky1, const char* xxname2, const char* yyname2, Coord::CoordSystem sys2, Coord::SkyFrame sky2, double rad, Coord::CoordSystem sys, Coord::DistFormat dist, const char* rrname) { if (!hasWCS(sys1) || !hasWCS(sys2)) return; // only good for skyframe astClearStatus; // just to make sure astBegin; // start memory management // get lists Tcl_Obj* listxx1 = Tcl_GetVar2Ex(interp_, xxname1, NULL, TCL_LEAVE_ERR_MSG); Tcl_Obj* listyy1 = Tcl_GetVar2Ex(interp_, yyname1, NULL, TCL_LEAVE_ERR_MSG); Tcl_Obj* listxx2 = Tcl_GetVar2Ex(interp_, xxname2, NULL, TCL_LEAVE_ERR_MSG); Tcl_Obj* listyy2 = Tcl_GetVar2Ex(interp_, yyname2, NULL, TCL_LEAVE_ERR_MSG); // get objects int nxx1; Tcl_Obj **objxx1; Tcl_ListObjGetElements(interp_, listxx1, &nxx1, &objxx1); int nyy1; Tcl_Obj **objyy1; Tcl_ListObjGetElements(interp_, listyy1, &nyy1, &objyy1); int nxx2; Tcl_Obj **objxx2; Tcl_ListObjGetElements(interp_, listxx2, &nxx2, &objxx2); int nyy2; Tcl_Obj **objyy2; Tcl_ListObjGetElements(interp_, listyy2, &nyy2, &objyy2); // sanity check if (nxx1 != nyy1 || nxx2 != nyy2) return; if (!hasWCSCel(sys1) || !hasWCSCel(sys2)) return; // get doubles double* ixx1 = new double[nxx1]; for (int ii=0 ; iihead(); FitsHead* rr = new FitsHead(hd->naxis(0), hd->naxis(1), hd->naxis(2), hd->bitpix()); // this works for both terminated (\n) and non-terminated (fits) headers while (!str.eof()) { char buf[256]; str.get(buf,80,'\n'); if (strlen(buf) > 0) { // check for blank lines if (*buf == ' ') break; string x(buf); istringstream sstr(x); char keyword[32]; sstr >> keyword; if (strchr(buf,'=')) { char dummy; sstr >> dummy; } if (strchr(buf,'\'')) { char val[64]; char* ss = strchr(buf,'\'')+1; char* ee = strrchr(buf,'\''); int ll = ee-ss; if (ll<0 || ll>63) ll =0; strncpy(val,ss,ll); val[ll] = '\0'; rr->appendString(keyword, val, ""); } else { double val; sstr >> val; rr->appendReal(keyword, val, 15, ""); } if (strlen(buf) <= 80) { // eat the \n char b; str.get(b); } } else break; } return rr; } void FitsImage::process(const char* fn, int id) { if (!fits_->isValid()) { reset(); return; } if (fits_->isImage()) { switch (fits_->pEncoding()) { case FitsFile::RAW: case FitsFile::BSQ: break; case FitsFile::GZIP: initNRRD(); if (!post_ || !post_->isValid()) { reset(); return; } break; case FitsFile::BIL: case FitsFile::BIP: initENVI(); if (!post_ || !post_->isValid()) { reset(); return; } break; default: reset(); return; } load(); } else if (fits_->isBinTable()) { // Compress if (fits_->find("ZIMAGE")) { initCompress(); if (!post_ || !post_->isValid()) { reset(); return; } load(); } // HEALPIX else if ((fits_->find("PIXTYPE") && (!strncmp(fits_->getString("PIXTYPE"),"HEALPIX",4))) || fits_->find("NSIDE")) { initHPX(); if (!hpx_ || !hpx_->isValid()) { reset(); return; } load(); } else { // Bintable initBin(); if (!hist_ || !hist_->isValid()) { reset(); return; } } } else if (fits_->isAsciiTable()) { // HEALPIX if (fits_->find("NSIDE")) { initHPX(); if (!hpx_ || !hpx_->isValid()) { reset(); return; } load(); } } // set slice address for (int ii=1; iifind("LTM1_1") || image_->find("LTM1_2") || image_->find("LTM2_1") || image_->find("LTM2_2") || image_->find("LTV1") || image_->find("LTV2")) keyLTMV = 1; double ltm11 = image_->getReal("LTM1_1", 1); double ltm12 = image_->getReal("LTM1_2", 0); double ltm21 = image_->getReal("LTM2_1", 0); double ltm22 = image_->getReal("LTM2_2", 1); double ltv1 = image_->getReal("LTV1", 0); double ltv2 = image_->getReal("LTV2", 0); physicalToImage = Matrix(ltm11, ltm12, ltm21, ltm22, ltv1, ltv2); imageToPhysical = physicalToImage.invert(); } // CDD to Detector (DTM/DTV keywords) keyDTMV =0; if (image_->find("DTM1_1") || image_->find("DTM1_2") || image_->find("DTM2_1") || image_->find("DTM2_2") || image_->find("DTV1") || image_->find("DTV2")) keyDTMV = 1; double dtm11 = image_->getReal("DTM1_1", 1); double dtm12 = image_->getReal("DTM1_2", 0); double dtm21 = image_->getReal("DTM2_1", 0); double dtm22 = image_->getReal("DTM2_2", 1); double dtv1 = image_->getReal("DTV1", 0); double dtv2 = image_->getReal("DTV2", 0); physicalToDetector = Matrix(dtm11, dtm12, dtm21, dtm22, dtv1, dtv2); detectorToPhysical = physicalToDetector.invert(); // Physical to Amplifier (ATM/ATV keywords) keyATMV =0; if (image_->find("ATM1_1") || image_->find("ATM1_2") || image_->find("ATM2_1") || image_->find("ATM2_2") || image_->find("ATV1") || image_->find("ATV2")) keyATMV = 1; double atm11 = image_->getReal("ATM1_1", 1); double atm12 = image_->getReal("ATM1_2", 0); double atm21 = image_->getReal("ATM2_1", 0); double atm22 = image_->getReal("ATM2_2", 1); double atv1 = image_->getReal("ATV1", 0); double atv2 = image_->getReal("ATV2", 0); physicalToAmplifier = Matrix(atm11, atm12, atm21, atm22, atv1, atv2); amplifierToPhysical = physicalToAmplifier.invert(); if (DebugMosaic) { cerr << endl; cerr << "ATM/V: " << physicalToAmplifier << endl; cerr << "ATM/V-1: " << amplifierToPhysical << endl; cerr << "DTM/V: " << physicalToDetector << endl; cerr << "DTM/V-1: " << detectorToPhysical << endl; cerr << "LTM/V: " << physicalToImage << endl; cerr << "LTM/V-1: " << imageToPhysical << endl; } /* // Radio data? char* bunit = image_->getString("BUNIT"); double cdelt1 = fabs(image_->getReal("CDELT1",0)); double cdelt2 = fabs(image_->getReal("CDELT2",0)); double bmaj = image_->getReal("BMAJ",0); double bmin = image_->getReal("BMIN",0); // ok we have a radio map #define GFACTOR (2.0*sqrt(2.0*log(2.0))) if (!strncmp(bunit,"JY/BEAM",7) && cdelt1 && cdelt2 && bmaj && bmin) { // convert from deg to arcsec? cdelt1 *= 3600; cdelt2 *= 3600; bmaj *= 3600; bmin *= 3600; jyBeam_ = (2*M_PI*bmaj*bmin)/(GFACTOR*GFACTOR*cdelt1*cdelt2); } if (bunit) delete [] bunit; if (cunit1) delete [] cunit1; if (cunit2) delete [] cunit2; */ } void FitsImage::processKeywordsParams() { // iparams is a BBOX in DATA coords 0-n iparams.set(0, 0, width(), height()); { char* datstr = image_->getString("DATASEC"); // default Vector v1(1,1); Vector v2(size()); keyDATASEC =0; if (datstr && *datstr && parseSection(datstr,&v1,&v2)) { // additional check if (v1[0]<1 || v1[1]<1 || v1[1]>width() || v2[1]>height() || v1[0]>v2[0] || v1[1]>v2[1]) { // default v1 = Vector(1,1); v2 = Vector(size()); keyDATASEC = 0; } else keyDATASEC = 1; } // dparams is a BBOX in DATA coords 0-n datasec = BBox(v1,v2); v1 -= Vector(1,1); dparams.set(v1[0],v1[1],v2[0],v2[1]); } // DEBUG if (DebugCrop) { cerr << "iparams " << iparams << endl; cerr << "dparams " << dparams << endl; } } void FitsImage::processKeywordsFitsSection() { Vector ll(dparams.xmin,dparams.ymin); Vector ur(dparams.xmax,dparams.ymax); if (fits_->pcoord() && fits_->pxvalid() && fits_->pyvalid()) { ll[0] = fits_->pxmin(); ur[0] = fits_->pxmax(); ll[1] = fits_->pymin(); ur[1] = fits_->pymax(); ll = ll*physicalToImage*Translate(-1,-1); ur = ur*physicalToImage; context_->setSecMode(FrScale::CROPSEC); } if (!fits_->pcoord() && fits_->pxvalid()) { ll[0] = fits_->pxmin()-1; ur[0] = fits_->pxmax(); context_->setSecMode(FrScale::CROPSEC); } if (!fits_->pcoord() && fits_->pyvalid()) { ll[1] = fits_->pymin()-1; ur[1] = fits_->pymax(); context_->setSecMode(FrScale::CROPSEC); } // params is a BBOX in DATA coords 0-n setCropParams(ll,ur,0); // DEBUG if (DebugCrop) cerr << "cparams " << cparams << endl; if (fits_->pzvalid()) { int zmin = fits_->pzmin()-1; int zmax = fits_->pzmax(); context_->setSecMode(FrScale::CROPSEC); context_->setCrop3dParams(zmin,zmax); } } int FitsImage::processKeywordsIRAF(FitsImage* fits) { // DETSEC Coord::Orientation orientation = Coord::NORMAL; char* detstr = image_->getString("DETSEC"); Vector dv1,dv2; if (!(detstr && *detstr && parseSection(detstr,&dv1,&dv2))) return 0; BBox detsec = BBox(dv1,dv2); int xx = (dv1[0] < dv2[0]); int yy = (dv1[1] < dv2[1]); if (xx && yy) orientation = Coord::NORMAL; else if (!xx && yy) orientation = Coord::XX; else if (!xx && !yy) orientation = Coord::XY; else if (xx && !yy) orientation = Coord::YY; // DETSIZE char* sizestr = image_->getString("DETSIZE"); Vector sv1(1,1); Vector sv2(10000,10000); if (sizestr && *sizestr) { if (!(parseSection(sizestr,&sv1,&sv2))) return 0; } BBox detsize = BBox(sv1,sv2); // CCDSUM Vector ccdsum(1,1); char* ccdstr = image_->getString("CCDSUM"); if (ccdstr && *ccdstr) { double Ns, Np, Ns1, Np1; string x(ccdstr); istringstream str(x); str >> Ns >> Np >> Ns1 >> Np1; ccdsum = Vector(1/Ns, 1/Np); } // origin Vector origin = detsec.ll * Scale(ccdsum) * Translate(-datasec.ll); // matrix // if the segment is flipped, we can have a discontinuity at // the edges, due to round off errors, so we 'nudge' it Matrix flip; switch (orientation) { case Coord::NORMAL: break; case Coord::XX: flip = FlipX(); break; case Coord::YY: flip = FlipY(); break; case Coord::XY: flip = FlipXY(); break; } // internal flip Matrix mflip; switch (context_->IRAFOrientation(orientation)) { case Coord::NORMAL: break; case Coord::XX: mflip = FlipX(); break; case Coord::YY: mflip = FlipY(); break; case Coord::XY: mflip = FlipXY(); break; } Vector center = datasec.center() * imageToData; Vector mcenter = detsize.center() * imageToData * Scale(ccdsum); wcsToRef_ = Translate(-center) * flip * Translate(center) * Translate(origin) * Translate(-mcenter) * mflip * Translate(mcenter); // we do this to shift the origin to the middle of the image to match // the wcs case. Needed by imageBBox() // first? reset wcsToRef if (fits == this) { irafToRef = wcsToRef_.invert(); wcsToRef_ = Matrix(); } else wcsToRef_ *= fits->irafToRef; if (DebugMosaic) { cerr << "ProcessKeywordsIRAF" << endl << " datasec: " << datasec << endl << " ccdsum : " << ccdsum << endl << " detsize: " << detsize << endl << " detsec : " << detsec << endl << " matrix : " << wcsToRef_ << endl; } return 1; } void FitsImage::replaceWCS(istream& str) { FitsHead* hh = parseWCS(str); // Process OBJECT keyword if (objectKeyword_) delete [] objectKeyword_; objectKeyword_ = dupstr(hh->getString("OBJECT")); // Process WCS keywords if (wcsAltHeader_) delete wcsAltHeader_; wcsAltHeader_ = hh; initWCS(wcsAltHeader_); } void FitsImage::reset() { if (fits_) delete fits_; fits_ =NULL; if (post_) delete post_; post_ =NULL; if (hpx_) delete hpx_; hpx_ =NULL; if (hist_) delete hist_; hist_ =NULL; base_ =NULL; if (basedata_) delete basedata_; basedata_ =NULL; if (manageBlock_) { if (block_) delete block_; if (blockdata_) delete blockdata_; } manageBlock_ =0; block_ =NULL; blockdata_ =NULL; if (manageAnalysis_) { if (analysis_) delete analysis_; if (analysisdata_) delete analysisdata_; } manageAnalysis_ =0; analysis_ =NULL; analysisdata_ =NULL; image_ =NULL; data_ =NULL; } char* FitsImage::root(const char* fn) { if (fn) { const char* ptr = fn; // init the ptr while(*ptr++); // walk it forward to end of string ptr--; // backup one while(*ptr != '/' && ptr != fn) // walk it backward til last / or beginning ptr--; if (*ptr == '/') // step it over the last '/' ptr++; return dupstr(ptr); // got it! } else return NULL; } void FitsImage::setCropParams(int datasec) { if (!datasec) cparams = iparams; else cparams = dparams; } void FitsImage::setCropParams(const Vector& ss, const Vector& tt, int datasec) { // Coord are in DATA Vector ll = ss; Vector ur = tt; int xmin = ll[0]; int xmax = ur[0]; int ymin = ll[1]; int ymax = ur[1]; if (xmin>xmax) { xmin = ur[0]; xmax = ll[0]; } if (ymin>ymax) { ymin = ur[1]; ymax = ll[1]; } setCropParams(xmin,ymin,xmax,ymax,datasec); } void FitsImage::setCropParams(int x0, int y0, int x1, int y1, int datasec) { FitsBound* params; if (!datasec) params = &iparams; else params = &dparams; // Coords are in DATA if (x0xmin) x0=params->xmin; if (x0>params->xmax) x0=params->xmax; if (x1xmin) x1=params->xmin; if (x1>params->xmax) x1=params->xmax; if (y0ymin) y0=params->ymin; if (y0>params->ymax) y0=params->ymax; if (y1ymin) y1=params->ymin; if (y1>params->ymax) y1=params->ymax; cparams.set(x0,y0,x1,y1); } void FitsImage::setFileName(const char* fn) { if (fileName) delete [] fileName; fileName = NULL; if (rootBaseFileName) delete [] rootBaseFileName; rootBaseFileName = NULL; if (fullBaseFileName) delete [] fullBaseFileName; fullBaseFileName = NULL; if (iisFileName) delete [] iisFileName; iisFileName = NULL; // no filename to set if (!fn) return; // strip any '[]' char* ffn = strip(fn); FitsFile* ptr = post_ ? post_ : fits_; if (!ptr) return; const char* ext = ptr->extname(); if (ext) { { ostringstream str; str << ffn << '[' << ext << ']' << ends; fullBaseFileName = dupstr(str.str().c_str()); } { char* m = root(ffn); ostringstream str; str << m << '[' << ext << ']' << ends; rootBaseFileName = dupstr(str.str().c_str()); delete [] m; } } else if (ptr->ext()) { { ostringstream str; str << ffn << '[' << ptr->ext() << ']' << ends; fullBaseFileName = dupstr(str.str().c_str()); } { char* m = root(ffn); ostringstream str; str << m << '[' << ptr->ext() << ']' << ends; rootBaseFileName = dupstr(str.str().c_str()); delete [] m; } } else { fullBaseFileName = dupstr(ffn); rootBaseFileName = root(ffn); } // by default, iisFileName is fullBaseFileName if (fullBaseFileName) iisFileName = dupstr(fullBaseFileName); delete [] ffn; } void FitsImage::setObjectKeyword(const char* obj) { if (objectKeyword_) delete [] objectKeyword_; objectKeyword_ = dupstr(obj); } char* FitsImage::strip(const char* fn) { if (fn) { char* r = dupstr(fn); // dup the string char* ptr = r; // init the ptr while(*ptr != '[' && *ptr) // walk it forward til '[' or end ptr++; *ptr = '\0'; // zero out rest return r; // got it! } else return NULL; } int FitsImage::nhdu() { int dd =1; for (int ii=2; iiupdateClip(fr,getDataParams(fr->secMode())); } void* clipproc(void* tt) { t_clip_arg* targ = (t_clip_arg*)tt; FitsData* data = targ->data; FrScale* fr = targ->fr; FitsBound* bb = targ->bb; data->updateClip(fr,bb); return NULL; } void FitsImage::updateClip(FrScale* fr, pthread_t* thread, t_clip_arg* targ) { targ->data = data_; targ->fr = fr; targ->bb = getDataParams(fr->secMode()); int result = pthread_create(thread, NULL, clipproc, targ); if (result) internalError("Unable to Create Thread"); } const char* FitsImage::getFileName(Base::FileNameType type) { switch (type) { case Base::ROOTBASE: return rootBaseFileName; case Base::FULLBASE: return fullBaseFileName; case Base::ROOT: case Base::FULL: // clear the buffer if (fileName) delete [] fileName; fileName =NULL; // generate filename // if FITS bin table cube, be sure to check the first slice if (context_->fits->isHist()) return updateFileNameBin(type); else return updateFileNameImage(type); } // just to satisfy the compiler return rootBaseFileName; } const char* FitsImage::updateFileNameImage(Base::FileNameType type) { // 2d/3d section char* sec =NULL; switch (context_->secMode()) { case FrScale::IMGSEC: case FrScale::DATASEC: { Vector blockFactor = context_->blockFactor(); if (blockFactor[0] != 1) { ostringstream str; str << "*," << blockFactor[0] << ends; sec = dupstr(str.str().c_str()); } } break; case FrScale::CROPSEC: { FitsBound* params =getDataParams(FrScale::CROPSEC); // params is a BBOX in DATA coords 0-n // xlate to 1-n Vector ll= Vector(params->xmin,params->ymin) * Translate(1,1); Vector ur(params->xmax,params->ymax); Vector blockFactor = context_->blockFactor(); if (blockFactor[0] != 1) { ostringstream str; str << ll[0] << ':' << ur[0] << ',' << ll[1] << ':' << ur[1] << ',' << blockFactor[0] << ends; sec = dupstr(str.str().c_str()); } else { ostringstream str; str << ll[0] << ':' << ur[0] << ',' << ll[1] << ':' << ur[1] << ends; sec = dupstr(str.str().c_str()); } } break; } // address char* add =NULL; { int doAdd =0; ostringstream str; int jj; for (jj=FTY_MAXAXES-1; jj>=2; jj--) { if (address[jj]!=1) break; } jj++; for (int ii=2; ii=" << ll[0] << ',' << fits_->pBinX() << "<=" << ur[0] << ',' << fits_->pBinY() << ">=" << ll[1] << ',' << fits_->pBinY() << "<=" << ur[1] << ends; sec = dupstr(str.str().c_str()); } break; } } // z filter char* slice =NULL; { char* zcol = (char*)fits_->pBinZ(); int bd = context_->binDepth(); if (bd>1 && zcol) { // only the first slice will have this FitsImage* first = context_->fits; if (first) { Vector zlim = first->fits_->getColMinMax(zcol); double zlen = zlim[1]-zlim[0]; double zdelta = zlen/bd; double zptr = zlim[0] + (address[2]-1)*zdelta; ostringstream str; str << zcol << ">=" << zptr << '&' << zcol << '<' << zptr+zdelta <0) || (!hasWCSCel(sys) && ang<0)) return Coord::XX; else return Coord::NORMAL; } else return Coord::NORMAL; } double FitsImage::getWCSRotation(Coord::CoordSystem sys, Coord::SkyFrame sky) { if (!hasWCS(sys)) return 0; setWCSSkyFrame(sys, sky); if (!wcsHPX_) { Vector in[3]; Vector out[3]; in[0] = center(); in[1] = center()+Vector(0,1); in[2] = center()+Vector(1,0); wcsTran(3, in, 1, out); double ang = wcsAxAngle(out[0], out[1]); double ang3 = wcsAngle(out[1],out[0],out[2]); if ((!(isnan(ang )||isinf(ang) ||(ang ==-DBL_MAX)||(ang ==DBL_MAX))) && (!(isnan(ang3)||isinf(ang3)||(ang3==-DBL_MAX)||(ang3==DBL_MAX)))) { if ((hasWCSCel(sys) && ang3>0) || (!hasWCSCel(sys) && ang3<0)) return -ang; else return ang; } else return 0; } else { // special case for HPX Vector cc = center(); Vector wcc = wcsTran(cc, 1); Vector wnorth = wcc + Vector(0,.001); Vector north = wcsTran(wnorth,0); int current = astGetI(ast_,"Current"); int base = astGetI(ast_,"Base"); astSetI(ast_,"Current",base); double ang = wcsAxAngle(cc,north); astSetI(ast_,"Current",current); if (!(isnan(ang)||isinf(ang)||(ang == -DBL_MAX)||(ang == DBL_MAX))) return ang; else return 0; } } const char* FitsImage::getWCSName(Coord::CoordSystem sys) { if (fits_->find("WCSNAME")) return fits_->getString("WCSNAME"); else return NULL; } Vector FitsImage::pix2wcs(const Vector& in, Coord::CoordSystem sys, Coord::SkyFrame sky) { astClearStatus; // just to make sure if (!hasWCS(sys)) return Vector(); setWCSSkyFrame(sys, sky); Vector out = wcsTran(in, 1); if (astOK && checkWCS(out)) return hasWCSCel(sys) ? zero360(radToDeg(out)) : out; else return Vector(); } char* FitsImage::pix2wcs(const Vector& in, Coord::CoordSystem sys, Coord::SkyFrame sky, Coord::SkyFormat format, char* lbuf) { astClearStatus; // just to make sure lbuf[0] = '\0'; if (!hasWCS(sys)) return lbuf; setWCSSkyFrame(sys, sky); ostringstream str; Vector out = wcsTran(in, 1); if (astOK && checkWCS(out)) { if (hasWCSCel(sys)) { ostringstream hms; hms << "hms." << context_->parent_->precHMS_; ostringstream dms; dms << "+dms." << context_->parent_->precDMS_; switch (format) { case Coord::DEGREES: out = zero360(radToDeg(out)); str << setprecision(context_->parent_->precDeg_) << out[0] << ' ' << out[1] << ' ' << (hasWCSCel(sys) ? coord.skyFrameStr(sky) : "") << ends; break; case Coord::SEXAGESIMAL: out = zeroTWOPI(out); switch (sky) { case Coord::FK4: case Coord::FK4_NO_E: case Coord::FK5: case Coord::ICRS: setWCSFormat(1,hms.str().c_str()); setWCSFormat(2,dms.str().c_str()); break; case Coord::GALACTIC: case Coord::SUPERGALACTIC: case Coord::ECLIPTIC: case Coord::HELIOECLIPTIC: setWCSFormat(1,dms.str().c_str()); setWCSFormat(2,dms.str().c_str()); break; } str << astFormat(ast_,1,out[0]) << ' ' << astFormat(ast_,2,out[1]) << ' ' << (hasWCSCel(sys) ? coord.skyFrameStr(sky) : "") << ends; break; } } else str << setprecision(context_->parent_->precLinear_) << out[0] << ' ' << out[1] << ends; strncpy(lbuf, str.str().c_str(), str.str().length()); } return lbuf; } Vector3d FitsImage::pix2wcs(const Vector3d& in, Coord::CoordSystem sys, Coord::SkyFrame sky) { astClearStatus; // just to make sure if (!hasWCS(sys)) return Vector(); setWCSSkyFrame(sys, sky); Vector3d out = wcsTran(in, 1); if (astOK && checkWCS(out)) return hasWCSCel(sys) ? zero360(radToDeg(out)) : out; else return Vector3d(); } char* FitsImage::pix2wcs(const Vector3d& in, Coord::CoordSystem sys, Coord::SkyFrame sky, Coord::SkyFormat format, char* lbuf) { astClearStatus; // just to make sure lbuf[0] = '\0'; if (!hasWCS(sys)) return lbuf; setWCSSkyFrame(sys, sky); ostringstream str; Vector3d out = wcsTran(in, 1); if (astOK && checkWCS(out)) { if (hasWCSCel(sys)) { ostringstream hms; hms << "hms." << context_->parent_->precHMS_; ostringstream dms; dms << "+dms." << context_->parent_->precDMS_; switch (format) { case Coord::DEGREES: out = zero360(radToDeg(out)); str << setprecision(context_->parent_->precDeg_) << out[0] << ' ' << out[1] << ' ' << out[2] << ' ' << (hasWCSCel(sys) ? coord.skyFrameStr(sky) : "") << ends; break; case Coord::SEXAGESIMAL: out = zeroTWOPI(out); switch (sky) { case Coord::FK4: case Coord::FK4_NO_E: case Coord::FK5: case Coord::ICRS: setWCSFormat(1,hms.str().c_str()); setWCSFormat(2,dms.str().c_str()); break; case Coord::GALACTIC: case Coord::SUPERGALACTIC: case Coord::ECLIPTIC: case Coord::HELIOECLIPTIC: setWCSFormat(1,dms.str().c_str()); setWCSFormat(2,dms.str().c_str()); break; } str << astFormat(ast_,1,out[0]) << ' ' << astFormat(ast_,2,out[1]) << ' ' << out[2] << ' ' << (hasWCSCel(sys) ? coord.skyFrameStr(sky) : "") << ends; break; } } else str << setprecision(context_->parent_->precLinear_) << out[0] << ' ' << out[1] << ' ' << out[2] <2) ? 1 : 0; } } else { for (int ii=0; ii2) ? 1 : 0; } } } astEnd; } void FitsImage::wcsHPXInit() { wcsHPX_ =0; if (!ast_) return; char key[] = "CTYPE1 "; if (image_) { const char* str = image_->getKeyword(key); if (str) if (!strncmp(str+5,"HPX",3)) wcsHPX_ =1; } } void FitsImage::wcsSizeInit() { // init wcsSize_ array if (wcsSize_) delete [] wcsSize_; wcsSize_ =NULL; wcsSize_ = new double[MULTWCS]; for (int ii=0; iislice(2) : 0; astTranN(ast_, 1, 3, 1, pin, forward, 3, 1, pout); return Vector(pout[0],pout[1]); } break; case 4: { double pin[4]; double pout[4]; pin[0] = in[0]; pin[1] = in[1]; pin[2] = forward ? context_->slice(2) : 0; pin[3] = forward ? context_->slice(3) : 0; astTranN(ast_, 1, 4, 1, pin, forward, 4, 1, pout); return Vector(pout[0],pout[1]); } break; } return Vector(); } void FitsImage::wcsTran(AstFrameSet* ast, int npoint, Vector* in, int forward, Vector* out) { int naxes = astGetI(ast,"Naxes"); switch (naxes) { case 1: // error break; case 2: { double* xin = new double[npoint]; double* yin = new double[npoint]; double* xout = new double[npoint]; double* yout = new double[npoint]; for (int ii=0; iislice(2) : 0; } astTranP(ast, npoint, 3, (const double**)ptr_in, forward, 3, ptr_out); for (int kk=0; kkslice(2) : 0; ptr_in[3][kk] = forward ? context_->slice(3) : 0; } astTranP(ast, npoint, 4, (const double**)ptr_in, forward, 4, ptr_out); for (int kk=0; kkslice(3) : 0; astTranN(ast_, 1, 4, 1, pin, forward, 4, 1, pout); return Vector3d(pout[0],pout[1],pout[2]); } break; } return Vector3d(); } double FitsImage::wcsDistance(const Vector& vv1, const Vector& vv2) { int naxes = astGetI(ast_,"Naxes"); switch (naxes) { case 1: // error break; case 2: return astDistance(ast_, vv1.v, vv2.v); case 3: { double ptr1[3]; ptr1[0] = vv1[0]; ptr1[1] = vv1[1]; ptr1[2] = 0; double ptr2[3]; ptr2[0] = vv2[0]; ptr2[1] = vv2[1]; ptr2[2] = 0; return astDistance(ast_, ptr1, ptr2); } case 4: { double ptr1[4]; ptr1[0] = vv1[0]; ptr1[1] = vv1[1]; ptr1[2] = 0; ptr1[3] = 0; double ptr2[4]; ptr2[0] = vv2[0]; ptr2[1] = vv2[1]; ptr2[2] = 0; ptr2[3] = 0; return astDistance(ast_, ptr1, ptr2); } } return 0; } double FitsImage::wcsAngle(const Vector& vv1, const Vector& vv2, const Vector& vv3) { int naxes = astGetI(ast_,"Naxes"); switch (naxes) { case 1: // error break; case 2: return astAngle(ast_,vv1.v,vv2.v,vv3.v); case 3: { double ptr1[3]; ptr1[0] = vv1[0]; ptr1[1] = vv1[1]; ptr1[2] = 0; double ptr2[3]; ptr2[0] = vv2[0]; ptr2[1] = vv2[1]; ptr2[2] = 0; double ptr3[3]; ptr3[0] = vv3[0]; ptr3[1] = vv3[1]; ptr3[2] = 0; return astAngle(ast_, ptr1, ptr2, ptr3); } case 4: { double ptr1[4]; ptr1[0] = vv1[0]; ptr1[1] = vv1[1]; ptr1[2] = 0; ptr1[3] = 0; double ptr2[4]; ptr2[0] = vv2[0]; ptr2[1] = vv2[1]; ptr2[2] = 0; ptr2[3] = 0; double ptr3[4]; ptr3[0] = vv3[0]; ptr3[1] = vv3[1]; ptr3[2] = 0; ptr3[3] = 0; return astAngle(ast_, ptr1, ptr2, ptr3); } } return 0; } double FitsImage::wcsAxAngle(const Vector& vv1, const Vector& vv2) { int naxes = astGetI(ast_,"Naxes"); switch (naxes) { case 1: // error break; case 2: return astAxAngle(ast_, vv1.v, vv2.v, 2); case 3: { double ptr1[3]; ptr1[0] = vv1[0]; ptr1[1] = vv1[1]; ptr1[2] = 0; double ptr2[3]; ptr2[0] = vv2[0]; ptr2[1] = vv2[1]; ptr2[2] = 0; return astAxAngle(ast_, ptr1, ptr2, 2); } case 4: { double ptr1[4]; ptr1[0] = vv1[0]; ptr1[1] = vv1[1]; ptr1[2] = 0; ptr1[3] = 0; double ptr2[4]; ptr2[0] = vv2[0]; ptr2[1] = vv2[1]; ptr2[2] = 0; ptr2[3] = 0; return astAxAngle(ast_, ptr1, ptr2, 2); } } return 0; } static void fits2TAB(AstFitsChan* chan, const char* extname, int extver, int extlevel, int* status) { FitsFile* ptr = ((FitsImage*)astChannelData)->fitsFile(); FitsFile* ext =NULL; bool first=true; bool found=false; while (!found) { ext = new FitsMosaicNextMMapIncr(ptr); if (!first) delete ptr; first =false; // EOF? if (!ext || !ext->isValid()) { if (ext) delete ext; *status = 0; return; } if (!ext->isBinTable()) break; const char* name = ext->extname(); int ver = ext->extver(); int level = ext->extlevel(); if (name) { if (!strncmp(extname,name,7) && extver==ver && extlevel==level) { found =true; break; } } ptr = ext; } // ok, found it astClearStatus; // just to make sure astBegin; // start memory management FitsHead* hd = ext->head(); FitsBinTableHDU* hdu = (FitsBinTableHDU*)hd->hdu(); int cols = hdu->cols(); int rows = hdu->rows(); int rowlen = hdu->width(); // create fitstable AstFitsChan* header = astFitsChan(NULL, NULL, ""); char* cards = hd->cards(); int ncards = hd->ncard(); for (int ii=0; iifind(ii); int width = col->width(); int repeat = col->repeat(); char* ptr = (char*)ext->data(); unsigned char* data = new unsigned char[width*rows]; memset(data,0,width*rows); switch (col->type()) { case 'I': for (int ii=0; iivalue(ptr,jj); memcpy(data+ii*width+jj*2,&vv,2); } break; case 'J': for (int ii=0; iivalue(ptr,jj); memcpy(data+ii*width+jj*4,&vv,4); } break; case 'E': for (int ii=0; iivalue(ptr,jj); memcpy(data+ii*width+jj*4,&vv,4); } break; case 'D': for (int ii=0; iivalue(ptr,jj); memcpy(data+ii*width+jj*8,&vv,8); } break; } astPutColumnData(table, col->ttype(), 0, width*rows, data); if (data) delete [] data; } astPutTable(chan, table, extname); astEnd; // now, clean up memory if (ext) delete ext; *status = 1; } AstFrameSet* FitsImage::fits2ast(FitsHead* hd) { // we may have an error, just reset astClearStatus; // new fitschan AstFitsChan* chan = astFitsChan(NULL, NULL, ""); if (!astOK || chan == AST__NULL) return NULL; // enable -TAB astSetI(chan,"TabOK",1); astPutChannelData(chan, this); astTableSource(chan, fits2TAB); // no warning messages astClear(chan,"Warnings"); // fill up chan char* cards =NULL; int ncards =0; if (hd) { cards = hd->cards(); ncards = hd->ncard(); } if (cards == NULL || ncards == 0) return NULL; for (int i=0; i