diff options
Diffstat (limited to 'tksao/frame/fitsimage.C')
-rw-r--r-- | tksao/frame/fitsimage.C | 4049 |
1 files changed, 4049 insertions, 0 deletions
diff --git a/tksao/frame/fitsimage.C b/tksao/frame/fitsimage.C new file mode 100644 index 0000000..76d5843 --- /dev/null +++ b/tksao/frame/fitsimage.C @@ -0,0 +1,4049 @@ +// Copyright (C) 1999-2016 +// Smithsonian Astrophysical Observatory, Cambridge, MA, USA +// For conditions of distribution and use, see copyright notice in "copyright" + +#ifndef __WIN32 +#include <pthread.h> +#endif + +#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" + +// this is kluge to speed up doug minks wcssubs 'ksearch' routine +extern "C" { + FitsHead* wcshead = NULL; + FitsHead* wcsprim = NULL; + char* ksearchh(char*, char*); + + char* findit(char* cards, char* key) + { + char* rr = NULL; + if (wcshead) { + if ((rr = wcshead->find(key))) + return rr; + + if (wcsprim) + if ((rr = wcsprim->find(key))) + return rr; + + return NULL; + } + else + return ksearchh(cards, key); + } +}; + +WCSx::WCSx() +{ + for (int ii=0; ii<FTY_MAXAXES; ii++) { + crpix[ii] =0; + crval[ii] =0; + cd[ii] =0; + } +} + +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); + + manageWCS_ =1; + wcs_ =NULL; + wcsx_ =NULL; + ast_ =NULL; + wcsHeader_ =NULL; + altHeader_ =NULL; + + iisMode_ =0; + iiszt_ =0; + + for (int ii=0; ii<FTY_MAXAXES; ii++) + address[ii] =1; +} + +FitsImage::~FitsImage() +{ + if (objectKeyword_) + delete [] objectKeyword_; + + if (fileName) + delete [] fileName; + + if (rootBaseFileName) + delete [] rootBaseFileName; + + if (fullBaseFileName) + delete [] fullBaseFileName; + + if (iisFileName) + delete [] iisFileName; + + if (fits_) + delete fits_; + + if (post_) + delete post_; + + if (hist_) + delete hist_; + + if (hpx_) + delete hpx_; + + if (basedata_) + delete basedata_; + + if (manageBlock_) { + if (block_) + delete block_; + if (blockdata_) + delete blockdata_; + } + if (manageAnalysis_) { + if (analysis_) + delete analysis_; + if (analysisdata_) + delete analysisdata_; + } + + if (wcs_) { + for (int ii=0; ii<MULTWCSA; ii++) + if (manageWCS_ && wcs_[ii]) + wcsfree(wcs_[ii]); + delete [] wcs_; + } + + if (wcsx_) { + for (int ii=0; ii<MULTWCS; ii++) + if (manageWCS_ && wcsx_[ii]) + delete wcsx_[ii]; + delete [] wcsx_; + } + + if (ast_) { + for (int ii=0; ii<MULTWCSA; ii++) + if (manageWCS_ && ast_[ii]) + astAnnul(ast_[ii]); + delete [] ast_; + } + + if (wcsHeader_) + delete wcsHeader_; + if (altHeader_) + delete altHeader_; +} + +// Fits + +FitsImageFitsAlloc::FitsImageFitsAlloc(Context* cx, Tcl_Interp* pp, + const char* ch, const char* fn, + FitsFile::FlushMode flush, int id) + : FitsImage(cx, pp) +{ + fits_ = new FitsFitsAlloc(ch, FitsFile::RELAX, flush); + process(fn,id); +} + +FitsImageFitsAllocGZ::FitsImageFitsAllocGZ(Context* cx, Tcl_Interp* pp, + const char* ch, const char* fn, + FitsFile::FlushMode flush, int id) + : FitsImage(cx, pp) +{ + fits_ = new FitsFitsAllocGZ(ch, FitsFile::RELAX, flush); + process(fn,id); +} + +FitsImageFitsChannel::FitsImageFitsChannel(Context* cx, Tcl_Interp* pp, + const char* ch, const char* fn, + FitsFile::FlushMode flush, int id) + : FitsImage(cx, pp) +{ + fits_ = new FitsFitsChannel(pp, ch, fn, FitsFile::RELAX, flush); + process(fn,id); +} + +FitsImageFitsMMap::FitsImageFitsMMap(Context* cx, Tcl_Interp* pp, + const char* fn, int id) + : FitsImage(cx, pp) +{ + fits_ = new FitsFitsMMap(fn, FitsFile::RELAX); + process(fn,id); +} + +FitsImageFitsSMMap::FitsImageFitsSMMap(Context* cx, Tcl_Interp* pp, + const char* hdr, + const char* fn, int id) + : FitsImage(cx, pp) +{ + fits_ = new FitsFitsSMMap(hdr, fn); + process(fn,id); +} + +FitsImageFitsMMapIncr::FitsImageFitsMMapIncr(Context* cx, Tcl_Interp* pp, + const char* fn, int id) + : FitsImage(cx, pp) +{ + fits_ = new FitsFitsMMapIncr(fn, FitsFile::RELAX); + process(fn,id); +} + +FitsImageFitsShare::FitsImageFitsShare(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 FitsFitsShareID(sid, fn, FitsFile::RELAX); + break; + case Base::KEY: + fits_ = new FitsFitsShareKey(sid, fn, FitsFile::RELAX); + break; + } + process(fn,id); +} + +FitsImageFitsSShare::FitsImageFitsSShare(Context* cx, Tcl_Interp* pp, + Base::ShmType type, + int hdr, int sid, + const char* fn, int id) + : FitsImage(cx, pp) +{ + switch (type) { + case Base::SHMID: + fits_ = new FitsFitsSShareID(hdr, sid, fn); + break; + case Base::KEY: + fits_ = new FitsFitsSShareKey(hdr, sid, fn); + break; + } + process(fn,id); +} + +FitsImageFitsSocket::FitsImageFitsSocket(Context* cx, Tcl_Interp* pp, + int s, const char* fn, + FitsFile::FlushMode flush, int id) + : FitsImage(cx, pp) +{ + fits_ = new FitsFitsSocket(s, fn, FitsFile::RELAX, flush); + process(fn,id); +} + +FitsImageFitsSocketGZ::FitsImageFitsSocketGZ(Context* cx, Tcl_Interp* pp, + int s, const char* fn, + FitsFile::FlushMode flush, int id) + : FitsImage(cx, pp) +{ + fits_ = new FitsFitsSocketGZ(s, fn, FitsFile::RELAX, flush); + process(fn,id); +} + +FitsImageFitsVar::FitsImageFitsVar(Context* cx, Tcl_Interp* pp, + const char* var, const char* fn, int id) + : FitsImage(cx, pp) +{ + fits_ = new FitsFitsVar(pp, var, fn, FitsFile::RELAX); + process(fn,id); +} + +FitsImageFitsOrder::FitsImageFitsOrder(Context* cx, Tcl_Interp* pp, + FitsImage* fi, + FitsHead* hdr, char* data, size_t sz, + int id) + : FitsImage(cx, pp) +{ + fits_ = new FitsOrder(fi->fitsFile(), 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::altWCS(istream& str) +{ + FitsHead* hh = parseWCS(str); + + // Process OBJECT keyword + if (objectKeyword_) + delete [] objectKeyword_; + objectKeyword_ = hh->getString("OBJECT"); + + // Process WCS keywords + if (altHeader_) + delete altHeader_; + + altHeader_ = hh; + initWCS(); +} + +void FitsImage::appendWCS(istream& str) +{ + FitsHead* hh = parseWCS(str); + + // process OBJECT keyword + char* obj = 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; i<hd->headbytes(); 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 (wcsHeader_) + delete wcsHeader_; + + wcsHeader_ = new FitsHead(cards,ll,FitsHead::ALLOC); + initWCS(); +} + +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; i<hd->ncard(); 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 (wcsHeader_) + return display(wcsHeader_); + else if (altHeader_) + return display(altHeader_); + else + return display(image_->head()); +} + +int FitsImage::findKeyword(const char* key) +{ + return fits_->find(key); +} + +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 == 1) + str << '<' << iisz_[0] << ends; + else if (val == IISMAX) + str << '>' << iisz_[1] << ends; + else if (val > IISMAX) + str << ends; + else + str << ((val-1) * (iisz_[1]-iisz_[0]))/(IISMAX-1) + iisz_[0] << 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() +{ + // free up wcs and ast arrays + if (wcs_) { + for (int ii=0; ii<MULTWCSA; ii++) + if (manageWCS_ && wcs_[ii]) + wcsfree(wcs_[ii]); + delete [] wcs_; + } + wcs_ = new WorldCoor*[MULTWCSA]; + for (int ii=0; ii<MULTWCSA; ii++) + wcs_[ii] = NULL; + + if (wcsx_) { + for (int ii=0; ii<MULTWCS; ii++) + if (manageWCS_ && wcsx_[ii]) + delete wcsx_[ii]; + delete [] wcsx_; + } + wcsx_ = new WCSx*[MULTWCS]; + for (int ii=0; ii<MULTWCS; ii++) + wcsx_[ii] = NULL; + + if (ast_) { + for (int ii=0; ii<MULTWCSA; ii++) + if (manageWCS_ && ast_[ii]) + astAnnul(ast_[ii]); + delete [] ast_; + } + ast_ = new AstFrameSet*[MULTWCSA]; + for (int ii=0; ii<MULTWCSA; ii++) + ast_[ii] = 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) { + for (int ii=0; ii<MULTWCSA; ii++) + wcs_[ii] = ptr->wcs_[ii]; + for (int ii=0; ii<MULTWCS; ii++) + wcsx_[ii] = ptr->wcsx_[ii]; + for (int ii=0; ii<MULTWCSA; ii++) + ast_[ii] = ptr->ast_[ii]; + + initWCSPhysical(); + manageWCS_ =0; + return; + } + sptr = sptr->nextSlice(); + } + ptr = ptr->nextMosaic(); + } + } + + // WCSx + FitsHead* hd =NULL; + FitsHead* prim =NULL; + if (wcsHeader_) + hd = wcsHeader_; + else if (altHeader_) + hd = altHeader_; + else { + hd = image_->head(); + prim = image_->primary() && image_->inherit() ? image_->primary() : NULL; + } + + // wcsinit is sloooowwww! so try to figure it out first + // look first for default WCS. Let wcsinit figure it out since there can + // be many different non-standard wcs's present + wcshead = hd; + wcsprim = prim; + wcs_[0] = wcsinit(hd->cards()); + wcshead = NULL; + wcsprim = NULL; + + // now look for WCSA - WCSZ + // we can take a short cut here, since only valid FITS wcs's are available + for (int ii=1; ii<MULTWCS; ii++) { + char str[] = "CTYPE1 "; + str[6] = '@'+ii; + if (hd->find(str)) { + wcshead = hd; + wcsprim = prim; + wcs_[ii] = wcsinitc(hd->cards(),str+6); + wcshead = NULL; + wcsprim = NULL; + } + } + + // finally, look for AST def + if (!wcs_[0]) { + char str[] = "BEGAST_A"; + if (hd->find(str)) { + wcs_[0] = wcskinit(100, 100, (char*)"AST--WCS", (char*)"AST--WCS", + 0, 0, 0, 0, NULL, 1, 1, 0, 2000, 0); + wcs_[0]->longpole = 999; + wcs_[0]->latpole = 999; + } + } + + // AST + for (int ii=0; ii<MULTWCSA; ii++) { + if (wcs_[ii]) + astinit(ii, hd, prim); + } + + // WCSDEP + if (hd->find("WCSDEP")) { + char* str = hd->getString("WCSDEP"); + if (str) { + for (int ii=1; ii<MULTWCS; ii++) { + if (wcs_[ii]) { + if (wcs_[ii]->wcsname) { + if (!strncmp(str,wcs_[ii]->wcsname,strlen(wcs_[ii]->wcsname))) { + if (ast_[0] && ast_[ii]) { + AstFrameSet* dep = (AstFrameSet*)astCopy(ast_[ii]); + astInvert(ast_[0]); + astAddFrame(dep,2,astUnitMap(2,""),ast_[0]); + astSetI(dep,"current",4); + astAnnul(ast_[0]); + ast_[0] = dep; + } + } + } + } + } + delete [] str; + } + } + + // WCSx + char scrpix[] = "CRPIX "; + char scrval[] = "CRVAL "; + char scd[] = "CD _ "; + char spc[] = "PC _ "; + char scdelt[] = "CDELT "; + for (int ii=0; ii<MULTWCS; ii++) { + for (int jj=2; jj<FTY_MAXAXES; jj++) { + + scrpix[5] = '1'+jj; + scrpix[6] = !ii ? ' ' : '@'+jj; + scrval[5] = '1'+jj; + scrval[6] = !ii ? ' ' : '@'+jj; + scd[2] = '1'+jj; + scd[4] = '1'+jj; + scd[5] = !ii ? ' ' : '@'+jj; + spc[2] = '1'+jj; + spc[4] = '1'+jj; + spc[5] = !ii ? ' ' : '@'+jj; + scdelt[5] = '1'+jj; + scdelt[6] = !ii ? ' ' : '@'+jj; + + if (hd->find(scrpix) && hd->find(scrval)) { + if (!wcsx_[ii]) + wcsx_[ii] = new WCSx(); + wcsx_[ii]->crpix[jj] = hd->getReal(scrpix,0); + wcsx_[ii]->crval[jj] = hd->getReal(scrval,0); + + float cd = hd->getReal(scd,0); + float pc = hd->getReal(spc,0); + float cdelt = hd->getReal(scdelt,0); + if (cd) + wcsx_[ii]->cd[jj] = cd; + else if (pc && cdelt) + wcsx_[ii]->cd[jj] = pc * cdelt; + else if (cdelt) + wcsx_[ii]->cd[jj] = cdelt; + else + wcsx_[ii]->cd[jj] = 1; + } + } + } + + initWCSPhysical(); + + if (DebugWCS) { + for (int ii=0; ii<MULTWCS; ii++) { + if (wcs_[ii]) + wcsShow(wcs_[ii]); + + if (wcsx_[ii]) { + for (int jj=0; jj<FTY_MAXAXES; jj++) { + if (wcsx_[ii]->cd[jj]) { + cerr << "wcsx" << (char)(!ii ? ' ' : '@'+ii) + << "[" << ii << "]->crpix[" << jj << "]=" + << wcsx_[ii]->crpix[jj] << endl; + cerr << "wcsx" << (char)(!ii ? ' ' : '@'+ii) + << "[" << ii << "]->crval[" << jj << "]=" + << wcsx_[ii]->crval[jj] << endl; + cerr << "wcsx" << (char)(!ii ? ' ' : '@'+ii) + << "[" << ii << "]->cd[" << jj << "]=" + << wcsx_[ii]->cd[jj] << endl; + } + } + } + } + } +} + +void FitsImage::initWCSPhysical() +{ + // now see if we have a 'physical' wcs, if so, set LTMV keywords + keyLTMV =0; + for (int ii=1; ii<MULTWCS; ii++) { + if (wcs_[ii] && + wcs_[ii]->wcsname && + !strncmp(wcs_[ii]->wcsname, "PHYSICAL", 8)) { + keyLTMV = 1; + + double ltm11 = wcs_[ii]->cd[0] != 0 ? 1/wcs_[ii]->cd[0] : 0; + double ltm12 = wcs_[ii]->cd[1] != 0 ? 1/wcs_[ii]->cd[1] : 0; + double ltm21 = wcs_[ii]->cd[2] != 0 ? 1/wcs_[ii]->cd[2] : 0; + double ltm22 = wcs_[ii]->cd[3] != 0 ? 1/wcs_[ii]->cd[3] : 0; + + double ltv1 = wcs_[ii]->crpix[0] - + wcs_[ii]->crval[0]*ltm11 - wcs_[ii]->crval[1]*ltm21; + double ltv2 = wcs_[ii]->crpix[1] - + wcs_[ii]->crval[0]*ltm12 - wcs_[ii]->crval[1]*ltm22; + + physicalToImage = Matrix(ltm11, ltm12, ltm21, ltm22, ltv1, ltv2); + imageToPhysical = physicalToImage.invert(); + } + } +} + +void FitsImage::initWCS0(const Vector& pix) +{ + int ii = Coord::WCS0-Coord::WCS; + if (wcs_[ii]) + wcsfree(wcs_[ii]); + wcs_[ii] = NULL; + + if (wcs_[0]) { + Vector cc = mapFromRef(pix, Coord::IMAGE, Coord::FK5); + WorldCoor* ww = wcs_[0]; + wcs_[ii] = wcskinit(ww->nxpix, ww->nypix, + (char*)"RA---TAN", (char*)"DEC--TAN", + cc[0], cc[1], 0, 0, ww->cd, 0, 0, 0, 2000, 2000); + wcs_[ii]->longpole = 999; + wcs_[ii]->latpole = 999; + + if (ast_[ii]) + astAnnul(ast_[ii]); + ast_[ii] = NULL; + astinit0(ii); + + if (DebugWCS) { + if (wcs_[ii]) + wcsShow(wcs_[ii]); + } + } +} + +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<unsigned char>(base_, interp_); + break; + case 16: + basedata_ = new FitsDatam<short>(base_, interp_); + break; + case -16: + basedata_ = new FitsDatam<unsigned short>(base_, interp_); + break; + case 32: + basedata_ = new FitsDatam<int>(base_, interp_); + break; + case 64: + basedata_ = new FitsDatam<long long>(base_, interp_); + break; + case -32: + basedata_ = new FitsDatam<float>(base_, interp_); + break; + case -64: + basedata_ = new FitsDatam<double>(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::SkyDist dist, + const char* rrname) +{ + astClearStatus; + + // 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; + + // get doubles + double* ixx1 = new double[nxx1]; + for (int ii=0 ; ii<nxx1 ; ii++) + Tcl_GetDoubleFromObj(interp_, objxx1[ii], ixx1+ii); + double* iyy1 = new double[nyy1]; + for (int ii=0 ; ii<nyy1 ; ii++) + Tcl_GetDoubleFromObj(interp_, objyy1[ii], iyy1+ii); + + double* oxx1 = new double[nxx1]; + memset(oxx1,0,sizeof(double)*nxx1); + double* oyy1 = new double[nyy1]; + memset(oyy1,0,sizeof(double)*nyy1); + + double* ixx2 = new double[nxx2]; + for (int ii=0 ; ii<nxx2 ; ii++) + Tcl_GetDoubleFromObj(interp_, objxx2[ii], ixx2+ii); + double* iyy2 = new double[nyy2]; + for (int ii=0 ; ii<nyy2 ; ii++) + Tcl_GetDoubleFromObj(interp_, objyy2[ii], iyy2+ii); + + double* oxx2 = new double[nxx2]; + memset(oxx2,0,sizeof(double)*nxx2); + double* oyy2 = new double[nyy2]; + memset(oyy2,0,sizeof(double)*nyy2); + + // map from wcs to image + { + int ss = sys1-Coord::WCS; + if (!(ss>=0 && ast_ && ast_[ss])) + return; + + if (astIsASkyFrame(astGetFrame(ast_[0], AST__CURRENT))) { + setAstSkyFrame(ast_[ss],sky1); + for (int ii=0; ii<nxx1; ii++) { + ixx1[ii] *= M_PI/180.; + iyy1[ii] *= M_PI/180.; + } + astTran2(ast_[ss], nxx1, ixx1, iyy1, 0, oxx1, oyy1); + } + } + + { + int ss = sys2-Coord::WCS; + if (!(ss>=0 && ast_ && ast_[ss])) + return; + + if (astIsASkyFrame(astGetFrame(ast_[ss], AST__CURRENT))) { + setAstSkyFrame(ast_[ss],sky2); + for (int ii=0; ii<nxx2; ii++) { + ixx2[ii] *= M_PI/180.; + iyy2[ii] *= M_PI/180.; + } + astTran2(ast_[ss], nxx2, ixx2, iyy2, 0, oxx2, oyy2); + } + } + + // radius + Vector cd = getWCScdelt(sys); + switch (dist) { + case Coord::DEGREE: + break; + case Coord::ARCMIN: + rad /= 60; + break; + case Coord::ARCSEC: + rad /= 60*60; + break; + } + double rx = rad/cd[0]; + double ry = rad/cd[1]; + double rr = (rx*rx + ry*ry)/2; + + // now compare + int cnt=0; + Tcl_Obj* objrr = Tcl_NewListObj(0,NULL); + for(int jj=0; jj<nxx2; jj++) { + for (int ii=0; ii<nxx1; ii++) { + double dx = oxx2[jj]-oxx1[ii]; + double dy = oyy2[jj]-oyy1[ii]; + + if (dx*dx + dy*dy < rr) { + Tcl_Obj* obj[2]; + obj[0] = Tcl_NewIntObj(ii+1); + obj[1] = Tcl_NewIntObj(jj+1); + Tcl_Obj* list = Tcl_NewListObj(2,obj); + Tcl_ListObjAppendElement(interp_, objrr, list); + cnt++; + } + } + } + + Tcl_SetVar2Ex(interp_, rrname, NULL, objrr, TCL_LEAVE_ERR_MSG); + + // clean up + delete [] ixx1; + delete [] iyy1; + delete [] oxx1; + delete [] oyy1; + + delete [] ixx2; + delete [] iyy2; + delete [] oxx2; + delete [] oyy2; +} + +Matrix& FitsImage::matrixToData(Coord::InternalSystem sys) +{ + switch (sys) { + case Coord::WINDOW: + return windowToData; + case Coord::CANVAS: + return canvasToData; + case Coord::WIDGET: + return widgetToData; + case Coord::PANNER: + return pannerToData; + case Coord::MAGNIFIER: + return magnifierToData; + case Coord::PS: + return psToData; + case Coord::USER: + return userToData; + case Coord::REF: + return refToData; + } + + // just to satisfy the compiler + return refToData; +} + +Matrix& FitsImage::matrixFromData(Coord::InternalSystem sys) +{ + switch (sys) { + case Coord::WINDOW: + return dataToWindow; + case Coord::CANVAS: + return dataToCanvas; + case Coord::WIDGET: + return dataToWidget; + case Coord::PANNER: + return dataToPanner; + case Coord::MAGNIFIER: + return dataToMagnifier; + case Coord::PS: + return dataToPS; + case Coord::USER: + return dataToUser; + case Coord::REF: + return dataToRef; + } + + // just to satisfy the compiler + return dataToRef; +} + +Matrix3d& FitsImage::matrixFromData3d(Coord::InternalSystem sys) +{ + switch (sys) { + case Coord::WINDOW: + return dataToWindow3d; + case Coord::CANVAS: + return dataToCanvas3d; + case Coord::WIDGET: + return dataToWidget3d; + case Coord::PANNER: + return dataToPanner3d; + case Coord::MAGNIFIER: + return dataToMagnifier3d; + case Coord::PS: + return dataToPS3d; + case Coord::USER: + return dataToUser3d; + case Coord::REF: + return dataToRef3d; + } + + // just to satisfy the compiler + return dataToRef3d; +} + +Matrix3d& FitsImage::matrixToData3d(Coord::InternalSystem sys) +{ + switch (sys) { + case Coord::WINDOW: + return windowToData3d; + case Coord::CANVAS: + return canvasToData3d; + case Coord::WIDGET: + return widgetToData3d; + case Coord::PANNER: + return pannerToData3d; + case Coord::MAGNIFIER: + return magnifierToData3d; + case Coord::PS: + return psToData3d; + case Coord::USER: + return userToData3d; + case Coord::REF: + return refToData3d; + } + + // just to satisfy the compiler + return refToData3d; +} + +FitsHead* FitsImage::parseWCS(istream& str) +{ + FitsHead* hd = image_->head(); + 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; ii<id; ii++) { + for (int jj=2; jj<FTY_MAXAXES; jj++) { + if (address[jj]<naxis(jj)) { + address[jj]++; + break; + } + else + address[jj]=1; + } + } + + // load() can call reset() + if (fits_) + setFileName(fn); +} + +void FitsImage::processKeywordsPhysical() +{ + // Physical to Image (LTM/LTV keywords) (with no wcsname already located) + + if (!keyLTMV) { + if (image_->find("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)); + char* cunit1 = image_->getString("CUNIT1"); + double cdelt2 = fabs(image_->getReal("CDELT2",0)); + char* cunit2 = image_->getString("CUNIT2"); + 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]); + + if (datstr) + delete [] datstr; + } + + // 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))) { + if (detstr) + delete [] detstr; + return 0; + } + delete [] detstr; + 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))) { + delete [] sizestr; + return 0; + } + } + if (sizestr) + delete [] sizestr; + 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); + } + if (ccdstr) + delete [] ccdstr; + + // 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_ = hh->getString("OBJECT"); + + // Process WCS keywords + if (wcsHeader_) + delete wcsHeader_; + + wcsHeader_ = hh; + initWCS(); +} + +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; +} + +void FitsImage::resetWCS() +{ + // Process OBJECT keyword + if (objectKeyword_) + delete [] objectKeyword_; + objectKeyword_ = image_->getString("OBJECT"); + + // Process WCS keywords + if (wcsHeader_) + delete wcsHeader_; + + wcsHeader_ = NULL; + initWCS(); +} + +void FitsImage::resetWCS0() +{ + int ii = Coord::WCS0-Coord::WCS; + if (wcs_[ii]) + wcsfree(wcs_[ii]); + wcs_[ii] = NULL; + + if (ast_[ii]) + astAnnul(ast_[ii]); + ast_[ii] = 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 (x0<params->xmin) + x0=params->xmin; + if (x0>params->xmax) + x0=params->xmax; + if (x1<params->xmin) + x1=params->xmin; + if (x1>params->xmax) + x1=params->xmax; + + if (y0<params->ymin) + y0=params->ymin; + if (y0>params->ymax) + y0=params->ymax; + if (y1<params->ymin) + 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; ii<FTY_MAXAXES; ii++) + if (naxis(ii)) + dd *= naxis(ii); + return dd; +} + +void FitsImage::updateClip(FrScale* fr) +{ + data_->updateClip(fr,getDataParams(fr->secMode())); +} + +#ifndef __WIN32 + +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"); +} + +#endif + +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<jj; ii++) { + doAdd =1; + if (ii==2) + str << "plane="; + else + str << ':'; + str << address[ii]; + } + if (doAdd) { + str << ends; + add = dupstr(str.str().c_str()); + } + } + + switch (type) { + case Base::ROOTBASE: + case Base::FULLBASE: + // better not get here + return NULL; + + case Base::ROOT: + if (rootBaseFileName) { + ostringstream str; + if (add && sec) + str << rootBaseFileName << '[' << add << ']' << '[' << sec << ']'; + else if (add && !sec) + str << rootBaseFileName << '[' << add << ']'; + else if (!add && sec) + str << rootBaseFileName << '[' << sec << ']'; + else + str << rootBaseFileName; + str << ends; + fileName = dupstr(str.str().c_str()); + } + break; + + case Base::FULL: + if (fullBaseFileName) { + ostringstream str; + if (add && sec) + str << fullBaseFileName << '[' << add << ']' << '[' << sec << ']'; + else if (add && !sec) + str << fullBaseFileName << '[' << add << ']'; + else if (!add && sec) + str << fullBaseFileName << '[' << sec << ']'; + else + str << fullBaseFileName; + str << ends; + fileName = dupstr(str.str().c_str()); + } + break; + } + + if (sec) + delete [] sec; + if (add) + delete [] add; + + return fileName; +} + +const char* FitsImage::updateFileNameBin(Base::FileNameType type) +{ + char* filter = (char*)fits_->pFilter(); + int doFilter = (filter && *filter); + + // x,y filter + char* sec = NULL; + { + switch (context_->secMode()) { + case FrScale::IMGSEC: + case FrScale::DATASEC: + break; + case FrScale::CROPSEC: + { + ostringstream str; + FitsBound* params =getDataParams(FrScale::CROPSEC); + + // dataToPhysical not set yet + Vector ll = Vector(params->xmin,params->ymin) * + dataToImage * imageToPhysical; + Vector ur = Vector(params->xmax,params->ymax) * + dataToImage * imageToPhysical; + + str << fits_->pBinX() << ">=" << 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 <<ends; + slice = dupstr(str.str().c_str()); + } + } + } + + switch (type) { + case Base::ROOTBASE: + case Base::FULLBASE: + // better not get here + return NULL; + + case Base::ROOT: + if (rootBaseFileName) { + ostringstream str; + str << rootBaseFileName; + if (doFilter && sec && slice) + str << '[' << filter << ',' << sec << ',' << slice << ']'; + else if (doFilter && sec && !slice) + str << '[' << filter << ',' << sec << ']'; + else if (doFilter && !sec && slice) + str << '[' << filter << ',' << slice << ']'; + else if (doFilter && !sec && !slice) + str << '[' << filter << ']'; + else if (!doFilter && sec && slice) + str << '[' << sec << ',' << slice << ']'; + else if (!doFilter && sec && !slice) + str << '[' << sec << ']'; + else if (!doFilter && !sec && slice) + str << '[' << slice << ']'; + str << ends; + fileName = dupstr(str.str().c_str()); + } + case Base::FULL: + if (fullBaseFileName) { + ostringstream str; + str << fullBaseFileName; + if (doFilter && sec && slice) + str << '[' << filter << ',' << sec << ',' << slice << ']'; + else if (doFilter && sec && !slice) + str << '[' << filter << ',' << sec << ']'; + else if (doFilter && !sec && slice) + str << '[' << filter << ',' << slice << ']'; + else if (doFilter && !sec && !slice) + str << '[' << filter << ']'; + else if (!doFilter && sec && slice) + str << '[' << sec << ',' << slice << ']'; + else if (!doFilter && sec && !slice) + str << '[' << sec << ']'; + else if (!doFilter && !sec && slice) + str << '[' << slice << ']'; + str << ends; + fileName = dupstr(str.str().c_str()); + } + break; + } + + return fileName; +} + +void FitsImage::updateMatrices(Matrix& rgbToRef, + Matrix& refToUser, + Matrix& userToWidget, + Matrix& widgetToCanvas, + Matrix& canvasToWindow) +{ + dataToRef = wcsToRef_ * rgbToRef; + refToData = dataToRef.invert(); + + dataToUser = dataToRef * refToUser; + userToData = dataToUser.invert(); + + dataToWidget = dataToUser * userToWidget; + widgetToData = dataToWidget.invert(); + + dataToCanvas = dataToWidget * widgetToCanvas; + canvasToData = dataToCanvas.invert(); + + dataToWindow = dataToCanvas * canvasToWindow; + windowToData = dataToWindow.invert(); + + refToCanvas = refToUser * userToWidget * widgetToCanvas; + canvasToRef = refToCanvas.invert(); + + imageToRef = imageToData * dataToRef; + refToImage = imageToRef.invert(); + + imageToWidget = imageToRef * refToUser * userToWidget; + widgetToImage = imageToWidget.invert(); + + physicalToRef = physicalToImage * imageToData * dataToRef; + refToPhysical = physicalToRef.invert(); + + amplifierToRef = amplifierToPhysical * physicalToRef; + refToAmplifier = amplifierToRef.invert(); + + detectorToRef = detectorToPhysical * physicalToRef; + refToDetector = detectorToRef.invert(); +} + +void FitsImage::updateMatrices(Matrix3d& refToUser3d, + Matrix3d& userToWidget3d, + Matrix3d& widgetToCanvas3d, + Matrix3d& canvasToWindow3d) +{ + dataToUser3d = dataToRef3d * refToUser3d; + userToData3d = dataToUser3d.invert(); + + dataToWidget3d = dataToUser3d * userToWidget3d; + widgetToData3d = dataToWidget3d.invert(); + + dataToCanvas3d = dataToWidget3d * widgetToCanvas3d; + canvasToData3d = dataToCanvas3d.invert(); + + dataToWindow3d = dataToCanvas3d * canvasToWindow3d; + windowToData3d = dataToWindow3d.invert(); +} + +void FitsImage::updatePannerMatrices(Matrix& refToPanner) +{ + dataToPanner = dataToRef * refToPanner; + pannerToData = dataToPanner.invert(); +} + +void FitsImage::updatePannerMatrices(Matrix3d& refToPanner3d) +{ + dataToPanner3d = dataToRef3d * refToPanner3d; + pannerToData3d = dataToPanner3d.invert(); +} + +void FitsImage::updateMagnifierMatrices(Matrix& refToMagnifier) +{ + dataToMagnifier = dataToRef * refToMagnifier; + magnifierToData = dataToMagnifier.invert(); +} + +void FitsImage::updateMagnifierMatrices(Matrix3d& refToMagnifier3d) +{ + dataToMagnifier3d = dataToRef3d * refToMagnifier3d; + magnifierToData3d = dataToMagnifier3d.invert(); +} + +void FitsImage::updatePS(Matrix ps) +{ + dataToPS = dataToRef * ps; + psToData = dataToPS.invert(); +} + +void FitsImage::updatePS(Matrix3d ps) +{ + dataToPS3d = dataToRef3d * ps; + psToData3d = dataToPS3d.invert(); +} + +// WCS + +Vector FitsImage::getWCScdelt(Coord::CoordSystem sys) +{ + if (hasWCS(sys)) { + int ii = sys-Coord::WCS; + + // The scaling factor could be encoded in pc or cdelt or both + double pc0 = wcs_[ii]->pc[0] ? wcs_[ii]->pc[0] : 1; + double pc3 = wcs_[ii]->pc[3] ? wcs_[ii]->pc[3] : 1; + if (!wcs_[ii]->coorflip) + return Vector(wcs_[ii]->cdelt[0]*pc0, wcs_[ii]->cdelt[1]*pc3); + else + return Vector(wcs_[ii]->cdelt[1]*pc3, wcs_[ii]->cdelt[0]*pc0); + } + else + return Vector(); +} + +Coord::Orientation FitsImage::getWCSOrientation(Coord::CoordSystem sys, + Coord::SkyFrame sky) +{ + if (hasWCS(sys)) { + Vector orpix = center(); + Vector orval = pix2wcs(orpix, sys, sky); + Vector delta = getWCScdelt(sys).abs(); + Vector npix = wcs2pix(Vector(orval[0],orval[1]+delta[1]), sys, sky); + Vector north = (npix-orpix).normalize(); + Vector epix = wcs2pix(Vector(orval[0]+delta[0],orval[1]), sys, sky); + Vector east = (epix-orpix).normalize(); + + // sanity check + Vector diff = (north-east).abs(); + if ((north[0]==0 && north[1]==0) || + (east[0]==0 && east[1]==0) || + (diff[0]<.01 && diff[1]<.01)) + return Coord::NORMAL; + + // take the cross product and see which way the 3rd axis is pointing + double w = east[0]*north[1]-east[1]*north[0]; + + if (!hasWCSCel(sys)) + return w>0 ? Coord::NORMAL : Coord::XX; + else + return w<0 ? Coord::NORMAL : Coord::XX; + } + + return Coord::NORMAL; +} + +double FitsImage::getWCSRotation(Coord::CoordSystem sys, Coord::SkyFrame sky) +{ + if (hasWCS(sys)) { + Vector orpix = center(); + Vector orval = pix2wcs(orpix, sys, sky); + Vector delta = getWCScdelt(sys).abs(); + Vector npix = wcs2pix(Vector(orval[0],orval[1]+delta[1]), sys, sky); + Vector north = (npix-orpix).normalize(); + Vector epix = wcs2pix(Vector(orval[0]+delta[0],orval[1]), sys, sky); + Vector east = (epix-orpix).normalize(); + + // sanity check + Vector diff = (north-east).abs(); + if ((north[0]==0 && north[1]==0) || + (east[0]==0 && east[1]==0) || + (diff[0]<.01 && diff[1]<.01)) + return 0; + + return -(north.angle()-M_PI_2); + } + return 0; +} + +// AST +Vector FitsImage::pix2wcs(Vector in, Coord::CoordSystem sys, + Coord::SkyFrame sky) +{ + astClearStatus; + + int ii = sys-Coord::WCS; + if (ii>=0 && ast_ && ast_[ii]) { + double xx =0; + double yy =0; + if (astIsASkyFrame(astGetFrame(ast_[ii], AST__CURRENT))) { + setAstSkyFrame(ast_[ii],sky); + astTran2(ast_[ii], 1, in.v, in.v+1, 1, &xx, &yy); + if (astOK) + if (checkAst(xx,yy)) + return Vector(radToDeg(xx),yy*180./M_PI); + } + else { + astTran2(ast_[ii], 1, in.v, in.v+1, 1, &xx, &yy); + if (astOK) + if (checkAst(xx,yy)) + return Vector(xx,yy); + } + } + + maperr =1; + return Vector(); +} + +Vector* FitsImage::pix2wcs(Vector* in, int num, Coord::CoordSystem sys, + Coord::SkyFrame sky) +{ + astClearStatus; + double xin[num]; + double yin[num]; + double xout[num]; + double yout[num]; + + Vector* out = new Vector[num]; + for (int ii=0; ii<num; ii++) { + xin[ii] = (in[ii])[0]; + yin[ii] = (in[ii])[1]; + } + + int ii = sys-Coord::WCS; + if (ii>=0 && ast_ && ast_[ii]) { + if (astIsASkyFrame(astGetFrame(ast_[ii], AST__CURRENT))) { + setAstSkyFrame(ast_[ii],sky); + astTran2(ast_[ii], num, xin, yin, 1, xout, yout); + if (astOK) { + for (int ii=0; ii<num; ii++) + if (checkAst(xout[ii],yout[ii])) + out[ii] = Vector(radToDeg(xout[ii]),yout[ii]*180./M_PI); + return out; + } + } + else { + astTran2(ast_[ii], num, xin, yin, 1, xout, yout); + if (astOK) { + for (int ii=0; ii<num; ii++) + if (checkAst(xout[ii],yout[ii])) + out[ii] = Vector(xout[ii],yout[ii]); + return out; + } + } + } + + maperr =1; + return out; +} + +char* FitsImage::pix2wcs(Vector in, Coord::CoordSystem sys, + Coord::SkyFrame sky, Coord::SkyFormat format, + char* lbuf) +{ + astClearStatus; + + int ii = sys-Coord::WCS; + if (ii>=0 && ast_ && ast_[ii]) { + double xx =0; + double yy =0; + ostringstream str; + if (astIsASkyFrame(astGetFrame(ast_[ii], AST__CURRENT))) { + setAstSkyFrame(ast_[ii],sky); + astTran2(ast_[ii], 1, in.v, in.v+1, 1, &xx, &yy); + if (!astOK || !checkAst(xx,yy)) { + maperr =1; + lbuf[0] = '\0'; + return lbuf; + } + + switch (format) { + case Coord::DEGREES: + xx =radToDeg(xx); // 0 to 360 + yy *=180./M_PI; + + str << setprecision(8) << xx << ' ' << yy + << ' ' << coord.skyFrameStr(sky) << ends; + break; + + case Coord::SEXAGESIMAL: + switch (sky) { + case Coord::FK4: + case Coord::FK4_NO_E: + case Coord::FK5: + case Coord::ICRS: + xx = zeroTWOPI(xx); + setAstFormat(ast_[ii],1,"hms.3"); + setAstFormat(ast_[ii],2,"+dms.3"); + break; + case Coord::GALACTIC: + case Coord::SUPERGALACTIC: + case Coord::ECLIPTIC: + case Coord::HELIOECLIPTIC: + xx = zeroTWOPI(xx); + setAstFormat(ast_[ii],1,"+dms.3"); + setAstFormat(ast_[ii],2,"+dms.3"); + break; + } + + str << astFormat(ast_[ii], 1, xx) << ' ' << astFormat(ast_[ii], 2, yy) + << ' ' << coord.skyFrameStr(sky) << ends; + break; + } + } + else { + astTran2(ast_[ii], 1, in.v, in.v+1, 1, &xx, &yy); + if (!astOK || !checkAst(xx,yy)) { + maperr =1; + return lbuf; + } + str << setprecision(8) << xx << ' ' << yy << ends; + } + + strncpy(lbuf, str.str().c_str(), str.str().length()); + } + + return lbuf; +} + +Vector FitsImage::wcs2pix(Vector in, Coord::CoordSystem sys, + Coord::SkyFrame sky) +{ + astClearStatus; + + int ii = sys-Coord::WCS; + if (ii>=0 && ast_ && ast_[ii]) { + double xx =0; + double yy =0; + if (astIsASkyFrame(astGetFrame(ast_[ii], AST__CURRENT))) { + setAstSkyFrame(ast_[ii],sky); + Vector rr = in*M_PI/180.; + astTran2(ast_[ii], 1, rr.v, &(rr[1]), 0, &xx, &yy); + if (astOK) + if (checkAst(xx,yy)) + return Vector(xx,yy); + } + else { + astTran2(ast_[ii], 1, in.v, in.v+1, 0, &xx, &yy); + if (astOK) + if (checkAst(xx,yy)) + return Vector(xx,yy); + } + } + + maperr =1; + return Vector(); +} + +Vector* FitsImage::wcs2pix(Vector* in, int num, Coord::CoordSystem sys, + Coord::SkyFrame sky) +{ + astClearStatus; + double xin[num]; + double yin[num]; + double xout[num]; + double yout[num]; + + Vector* out = new Vector[num]; + for (int ii=0; ii<num; ii++) { + xin[ii] = (in[ii])[0]; + yin[ii] = (in[ii])[1]; + } + + int ii = sys-Coord::WCS; + if (ii>=0 && ast_ && ast_[ii]) { + if (astIsASkyFrame(astGetFrame(ast_[ii], AST__CURRENT))) { + setAstSkyFrame(ast_[ii],sky); + for (int kk=0; kk<num; kk++) { + xin[kk] *= M_PI/180.; + yin[kk] *= M_PI/180.; + } + astTran2(ast_[ii], num, xin, yin, 0, xout, yout); + if (astOK) { + for (int kk=0; kk<num; kk++) + if (checkAst(xout[kk],yout[kk])) + out[kk] = Vector(xout[kk],yout[kk]); + return out; + } + } + else { + astTran2(ast_[ii], num, xin, yin, 0, xout, yout); + if (astOK) { + for (int kk=0; kk<num; kk++) + if (checkAst(xout[kk],yout[kk])) + out[ii] = Vector(xout[kk],yout[kk]); + return out; + } + } + } + + maperr =1; + return out; +} + +double FitsImage::wcsdist(Vector a, Vector b, Coord::CoordSystem sys) +{ + astClearStatus; + + int ii = sys-Coord::WCS; + double rr=0; + if (ii>=0 && ast_ && ast_[ii]) { + if (astIsASkyFrame(astGetFrame(ast_[ii], AST__CURRENT))) { + Vector aa = a*M_PI/180.; + Vector bb = b*M_PI/180.; + rr = astDistance(ast_[ii], aa.v, bb.v) *180./M_PI; + } + else + rr = astDistance(ast_[ii], a.v, b.v); + + if (!astOK) { + maperr =1; + return 0; + } + } + + return rr; +} + +int FitsImage::hasWCS(Coord::CoordSystem sys) +{ + int ii = sys-Coord::WCS; + return (sys>=Coord::WCS && ast_ && ast_[ii]) ? 1 : 0; +} + +int FitsImage::hasWCSEqu(Coord::CoordSystem sys) +{ + astClearStatus; + + int ii = sys-Coord::WCS; + if (ii>=0 && ast_ && ast_[ii]) + if (astIsASkyFrame(astGetFrame(ast_[ii], AST__CURRENT))) { + // special case of xLON/xLAT + char* bb = &(wcs_[ii]->c1type[1]); + if (!strncmp(bb,"LON",3) || !strncmp(bb,"LAT",3)) { + switch (wcs_[ii]->c1type[0]) { + case 'G': + case 'H': + case 'E': + case 'S': + return 1; + default: + return 0; + } + } + + // special case of xyLN/xyLT + char* cc = &(wcs_[ii]->c1type[2]); + if (!strncmp(cc,"LN",2) || !strncmp(cc,"LT",2)) + return 0; + + return 1; + } + + return 0; +} + +int FitsImage::hasWCSCel(Coord::CoordSystem sys) +{ + astClearStatus; + + int ii = sys-Coord::WCS; + if (ii>=0 && ast_ && ast_[ii]) + if (astIsASkyFrame(astGetFrame(ast_[ii], AST__CURRENT))) + return 1; + + return 0; +} + +// WCSX + +int FitsImage::hasWCSx(Coord::CoordSystem sys, int ss) +{ + int ii = sys-Coord::WCS; + return (ss>=2&&ss<FTY_MAXAXES && sys>=Coord::WCS && wcsx_[ii]) ? 1 : 0; +} + +double FitsImage::pix2wcsx(double in, Coord::CoordSystem sys, int ss) +{ + if (hasWCSx(sys,ss)) { + int ii = sys-Coord::WCS; + return (in-wcsx_[ii]->crpix[ss])*wcsx_[ii]->cd[ss] + wcsx_[ii]->crval[ss]; + } + else + return in; +} + +double FitsImage::wcs2pixx(double in, Coord::CoordSystem sys, int ss) +{ + if (hasWCSx(sys,ss)) { + int ii = sys-Coord::WCS; + return (in-wcsx_[ii]->crval[ss])/wcsx_[ii]->cd[ss] + wcsx_[ii]->crpix[ss]; + } + else + return in; +} + +// WCS/AST support + +void FitsImage::wcsShow(WorldCoor* ww) +{ + if (!ww) + return; + + int n = ww->naxes; + int nn = n*n; + + cerr << "wcs->wcsname=" << (ww->wcsname ? ww->wcsname : "") << endl; + cerr << "wcs->naxes=" << ww->naxes << endl; + cerr << "wcs->naxis=" << ww->naxis << endl; + + cerr << "wcs->radecsys=" << ww->radecsys << endl; + cerr << "wcs->equinox=" << ww->equinox << endl; + cerr << "wcs->epoch=" << ww->epoch << endl; + + cerr << "wcs->ctype[0]=" << ww->ctype[0] << endl; + cerr << "wcs->ctype[1]=" << ww->ctype[1] << endl; + cerr << "wcs->c1type=" << ww->c1type << endl; + cerr << "wcs->c2type=" << ww->c2type << endl; + cerr << "wcs->ptype=" << ww->ptype << endl; + + for (int jj=0; jj<n; jj++) + cerr << "wcs->crpix[" << jj << "]=" << ww->crpix[jj] << endl; + for (int jj=0; jj<n; jj++) + cerr << "wcs->crval[" << jj << "]=" << ww->crval[jj] << endl; + for (int jj=0; jj<n; jj++) + cerr << "wcs->cdelt[" << jj << "]=" << ww->cdelt[jj] << endl; + + for (int jj=0; jj<4; jj++) + cerr << "wcs->cd[" << jj << "]=" << ww->cd[jj] << endl; + for (int jj=0; jj<nn; jj++) + cerr << "wcs->pc[" << jj << "]=" << ww->pc[jj] << endl; + + cerr << "wcs->longpole=" << ww->longpole << endl; + cerr << "wcs->latpole=" << ww->latpole << endl; + cerr << "wcs->prjcode=" << ww->prjcode << endl; + + cerr << "wcs->rot=" << ww->rot << endl; + cerr << "wcs->coorflip=" << ww->coorflip << endl; + cerr << "wcs->distcode=" << ww->distcode << endl; +} + +void FitsImage::astinit(int ii, FitsHead* hd, FitsHead* prim) +{ + if (!wcs_[ii]) { + ast_[ii] = NULL; + return; + } + + // just in case + if (!hd) + return; + // DSS,PLT,LIN goes straight to AST + // we can't send 3D directly to AST + + if (wcs_[ii]->prjcode==WCS_DSS || + wcs_[ii]->prjcode==WCS_PLT || + (wcs_[ii]->prjcode==WCS_LIN && !strncmp(wcs_[ii]->ptype,"HPX",3)) || + (wcs_[ii]->prjcode==WCS_LIN && !strncmp(wcs_[ii]->ptype,"XPH",3)) || + (wcs_[ii]->prjcode==WCS_LIN && !strncmp(wcs_[ii]->ptype,"TAB",3)) || + (wcs_[ii]->prjcode==WCS_LIN && !strncmp(wcs_[ii]->c1type,"AST",3))) + ast_[ii] = fits2ast(hd); + else + ast_[ii] = buildast(ii, hd, prim); + + if (!ast_[ii]) + return; + + // set default skyframe + if (astIsASkyFrame(astGetFrame(ast_[ii], AST__CURRENT))) + setAstSkyFrame(ast_[ii],Coord::FK5); + + if (DebugAST) + astShow(ast_[ii]); +} + +void FitsImage::astinit0(int ii) +{ + if (!wcs_[ii]) { + ast_[ii] = NULL; + return; + } + + ast_[ii] = buildast0(ii); + + if (!ast_[ii]) + return; + + // set default skyframe + if (astIsASkyFrame(astGetFrame(ast_[ii], AST__CURRENT))) + setAstSkyFrame(ast_[ii],Coord::FK5); + + if (DebugAST) + astShow(ast_[ii]); +} + +int FitsImage::checkAst(double x, double y) +{ + // check for reasonable values + return (fabs(x) < FLT_MAX && fabs(y) < FLT_MAX) ? 1 : 0; +} + +void FitsImage::setAstFormat(AstFrameSet* aa, int id, const char* format) +{ + // is it already set? + // ast is very slow when changing params + { + ostringstream str; + str << "Format(" << id << ")" << ends; + const char* out = astGetC(aa, str.str().c_str()); + if (!strcmp(out,format)) + return; + } + + ostringstream str; + str << "Format(" << id << ")=" << format << ends; + astSet(aa, str.str().c_str()); +} + +void FitsImage::setAstSkyFrame(AstFrameSet* aa, Coord::SkyFrame sky) +{ + // is sky frame + if (!astIsASkyFrame(astGetFrame(aa, AST__CURRENT))) + return; + + // is it already set? + // ast is very slow when changing system,equinox + const char* str = astGetC(aa, "System"); + + // TLON/XLON and HPX will do this + if (!strncmp(str,"Unknown",3)) + return; + + switch (sky) { + case Coord::FK4_NO_E: + if (!strncmp(str,"FK4-NO-E",8)) + return; + astSet(aa, "System=FK4-NO-E, Equinox=B1950"); + return; + case Coord::FK4: + if (!strncmp(str,"FK4",3)) + return; + astSet(aa, "System=FK4, Equinox=B1950"); + return; + case Coord::FK5: + if (!strncmp(str,"FK5",3)) + return; + astSet(aa, "System=FK5, Equinox=J2000"); + return; + case Coord::ICRS: + if (!strncmp(str,"ICRS",4)) + return; + astSet(aa, "System=ICRS"); + return; + case Coord::GALACTIC: + if (!strncmp(str,"GALACTIC",8)) + return; + astSet(aa, "System=GALACTIC"); + return; + case Coord::SUPERGALACTIC: + if (!strncmp(str,"SUPERGALACTIC",13)) + return; + astSet(aa, "System=SUPERGALACTIC"); + return; + case Coord::ECLIPTIC: + if (!strncmp(str,"ECLIPTIC",8)) + return; + astSet(aa, "System=ECLIPTIC"); + // get AST to agree with WCSSUBS + astSetD(aa, "EQUINOX", astGetD(aa, "EPOCH")); + return; + case Coord::HELIOECLIPTIC: + if (!strncmp(str,"HELIOECLIPTIC",13)) + return; + astSet(aa, "System=HELIOECLIPTIC"); + return; + } +} + +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; + + // 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<ncards; i++) { + char buf[81]; + strncpy(buf,cards+(i*80),80); + buf[80] = '\0'; + + astPutFits(chan, buf, 0); + // sometimes, we get a bad parse, just ignore + if (!astOK) + astClearStatus; + } + + // enable -TAB + //astSetI(chan,"TabOK",1); + + // we may have an error, just reset + astClearStatus; + astClear(chan, "Card"); + + // parse header + AstFrameSet* frameSet = (AstFrameSet*)astRead(chan); + + // do we have anything? + if (!astOK || frameSet == AST__NULL || + strncmp(astGetC(frameSet,"Class"), "FrameSet", 8)) + return NULL; + + return frameSet; +} + +AstFrameSet* FitsImage::buildast(int ii, FitsHead* hd, FitsHead* prim) +{ + if (DebugAST) + cerr << endl << "buildast()" << endl; + + // read wcs struct into astChannel + // we may have an error, just reset + astClearStatus; + + // new fitschan + AstFitsChan* chan = astFitsChan(NULL, NULL, ""); + if (!astOK || chan == AST__NULL) + return NULL; + + // no warning messages + astClear(chan,"Warnings"); + + // basics (needed by fitschan.c) + putFitsCard(chan, "NAXIS1", (int)naxis(0)); + putFitsCard(chan, "NAXIS2", (int)naxis(1)); + + // simple test to see if we have complete WCS + // if not (as in 3d cube reorder), wcs[] can be very unreliable + int fromwcs =0; + if (hd->find("CTYPE1") && hd->find("CTYPE2") && + hd->find("CRVAL1") && hd->find("CRVAL2") && + hd->find("CRPIX1") && hd->find("CRPIX2")) { + wcs2ast(ii,hd,prim,chan); + fromwcs =1; + } + else + header2ast(hd,chan); + + // rewind chan + astClear(chan, "Card"); + + // parse header + AstFrameSet* frameSet = (AstFrameSet*)astRead(chan); + + // do we have anything? + if (!astOK || frameSet == AST__NULL || + strncmp(astGetC(frameSet,"Class"), "FrameSet", 8)) + return NULL; + + if (fromwcs && wcs_[ii]->coorflip) { + int orr[] = {2,1}; + astPermAxes(frameSet,orr); + } + + // cleanup + astAnnul(chan); + + return frameSet; +} + +AstFrameSet* FitsImage::buildast0(int ii) +{ + if (DebugAST) + cerr << endl << "buildast0()" << endl; + + // read wcs struct into astChannel + // we may have an error, just reset + astClearStatus; + + // new fitschan + AstFitsChan* chan = astFitsChan(NULL, NULL, ""); + if (!astOK || chan == AST__NULL) + return NULL; + + // no warning messages + astClear(chan,"Warnings"); + + // basics (needed by fitschan.c) + putFitsCard(chan, "NAXIS1", (int)naxis(0)); + putFitsCard(chan, "NAXIS2", (int)naxis(1)); + + wcs2ast0(ii,chan); + + // rewind chan + astClear(chan, "Card"); + + // parse header + AstFrameSet* frameSet = (AstFrameSet*)astRead(chan); + + // do we have anything? + if (!astOK || frameSet == AST__NULL || + strncmp(astGetC(frameSet,"Class"), "FrameSet", 8)) + return NULL; + + if (wcs_[ii]->coorflip) { + int orr[] = {2,1}; + astPermAxes(frameSet,orr); + } + + // cleanup + astAnnul(chan); + + return frameSet; +} + +void FitsImage::header2ast(FitsHead* hd, void* chan) +{ + if (DebugAST) + cerr << endl << "header2ast()" << endl; + + for (int ii=0; ii<MULTWCS; ii++) { + char alt = (ii==0) ? ' ' : (char)('@'+ii); + + char key1[8]; + char key2[8]; + + // CTYPE + // We can't have RA/DEC without DEC/RA or GLON/GLAT without GLAT/GLON + const char* linear = "LINEAR"; + strcpy(key1, "CTYPE1 "); + strcpy(key2, "CTYPE2 "); + key1[6] = key2[6] = alt; + + // do we have WCSa? + if (!hd->find(key1) && !hd->find(key2)) + continue; + + char* ctype1 = hd->getString(key1); + char* ctype2 = hd->getString(key2); + + if (ctype1 && !strncmp(ctype1,"GLON",4)) { + if (!ctype2 || strncmp(ctype2,"GLAT",4)) { + ctype1 = (char*)linear; + ctype2 = (char*)linear; + } + } + else if (ctype2 && !strncmp(ctype2,"GLON",4)) { + if (!ctype1 || strncmp(ctype1,"GLAT",4)) { + ctype1 = (char*)linear; + ctype2 = (char*)linear; + } + } + else if (ctype1 && !strncmp(ctype1,"GLAT",4)) { + if (!ctype2 || strncmp(ctype2,"GLON",4)) { + ctype1 = (char*)linear; + ctype2 = (char*)linear; + } + } + else if (ctype2 && !strncmp(ctype2,"GLAT",4)) { + if (!ctype1 || strncmp(ctype1,"GLON",4)) { + ctype1 = (char*)linear; + ctype2 = (char*)linear; + } + } + else if (ctype1 && !strncmp(ctype1,"RA",2)) { + if (!ctype2 || strncmp(ctype2,"DEC",3)) { + ctype1 = (char*)linear; + ctype2 = (char*)linear; + } + } + else if (ctype2 && !strncmp(ctype2,"RA",2)) { + if (!ctype1 || strncmp(ctype1,"DEC",3)) { + ctype1 = (char*)linear; + ctype2 = (char*)linear; + } + } + else if (ctype1 && !strncmp(ctype1,"DEC",3)) { + if (!ctype2 || strncmp(ctype2,"RA",2)) { + ctype1 = (char*)linear; + ctype2 = (char*)linear; + } + } + else if (ctype2 && !strncmp(ctype2,"DEC",3)) { + if (!ctype1 || strncmp(ctype1,"RA",2)) { + ctype1 = (char*)linear; + ctype2 = (char*)linear; + } + } + else { + if (!ctype1) + ctype1 =(char*)linear; + if (!ctype2) + ctype2 =(char*)linear; + } + + putFitsCard(chan, key1, ctype1); + putFitsCard(chan, key2, ctype2); + + // CRPIX + strcpy(key1, "CRPIX1 "); + strcpy(key2, "CRPIX2 "); + key1[6] = key2[6] = alt; + putFitsCard(chan, key1, hd->getReal(key1,0)); + putFitsCard(chan, key2, hd->getReal(key2,0)); + + // CRVAL + strcpy(key1, "CRVAL1 "); + strcpy(key2, "CRVAL2 "); + key1[6] = key2[6] = alt; + putFitsCard(chan, key1, hd->getReal(key1,0)); + putFitsCard(chan, key2, hd->getReal(key2,0)); + + // CDELT/CD/PC + strcpy(key1, "CDELT1 "); + strcpy(key2, "CDELT2 "); + key1[6] = key2[6] = alt; + + char pkey1[8]; + char pkey2[8]; + char pkey3[8]; + char pkey4[8]; + strcpy(pkey1, "PC1_1 "); + strcpy(pkey2, "PC1_2 "); + strcpy(pkey3, "PC2_1 "); + strcpy(pkey4, "PC2_2 "); + pkey1[5] = pkey2[5] = pkey3[5] = pkey4[5] = alt; + + char ckey1[8]; + char ckey2[8]; + char ckey3[8]; + char ckey4[8]; + strcpy(ckey1, "CD1_1 "); + strcpy(ckey2, "CD1_2 "); + strcpy(ckey3, "CD2_1 "); + strcpy(ckey4, "CD2_2 "); + ckey1[5] = ckey2[5] = ckey3[5] = ckey4[5] = alt; + + // Give CD priority over CDELT + if (hd->find(ckey1) || + hd->find(ckey2) || + hd->find(ckey3) || + hd->find(ckey4)) { + putFitsCard(chan, ckey1, hd->getReal(ckey1,1)); + putFitsCard(chan, ckey2, hd->getReal(ckey2,0)); + putFitsCard(chan, ckey3, hd->getReal(ckey3,0)); + putFitsCard(chan, ckey4, hd->getReal(ckey4,1)); + } + else if (hd->find(key1) || hd->find(key2)) { + putFitsCard(chan, key1, hd->getReal(key1,1)); + putFitsCard(chan, key2, hd->getReal(key2,1)); + + if (hd->find(pkey1) || + hd->find(pkey2) || + hd->find(pkey3) || + hd->find(pkey4)) { + putFitsCard(chan, pkey1, hd->getReal(pkey1,1)); + putFitsCard(chan, pkey2, hd->getReal(pkey2,1)); + putFitsCard(chan, pkey3, hd->getReal(pkey3,1)); + putFitsCard(chan, pkey4, hd->getReal(pkey4,1)); + } + } + } +} + +void FitsImage::wcs2ast(int ww, FitsHead* hd, FitsHead* prim, void* chan) +{ + if (DebugAST) + cerr << endl << "wcs2ast()" << endl; + + // Alt WCS + char alt = (ww==0) ? ' ' : (char)('@'+ww); + + // CTYPE + if ( + // special case (reorder 3D cube) + (!strncmp(wcs_[ww]->c1type,"GLON",4) && + strncmp(wcs_[ww]->c2type,"GLAT",4)) || + (strncmp(wcs_[ww]->c1type,"GLON",4) && + !strncmp(wcs_[ww]->c2type,"GLAT",4)) || + (!strncmp(wcs_[ww]->c1type,"GLAT",4) && + strncmp(wcs_[ww]->c2type,"GLON",4)) || + (strncmp(wcs_[ww]->c1type,"GLAT",4) && + !strncmp(wcs_[ww]->c2type,"GLON",4)) || + (!strncmp(wcs_[ww]->c1type,"RA",2) && + strncmp(wcs_[ww]->c2type,"DEC",3)) || + (strncmp(wcs_[ww]->c1type,"RA",2) && + !strncmp(wcs_[ww]->c2type,"DEC",3)) || + (!strncmp(wcs_[ww]->c1type,"DEC",3) && + strncmp(wcs_[ww]->c2type,"RA",2)) || + (strncmp(wcs_[ww]->c1type,"DEC",3) && + !strncmp(wcs_[ww]->c2type,"RA",2))) + { + putFitsCard(chan, "CTYPE1", "LINEAR"); + putFitsCard(chan, "CTYPE2", "LINEAR"); + } + else if (wcs_[ww]->prjcode == WCS_TAN && wcs_[ww]->distcode) { + // SIP + { + ostringstream str; + str << wcs_[ww]->ctype[0] << "-SIP" << ends; + putFitsCard(chan, "CTYPE1", str.str().c_str()); + } + { + ostringstream str; + str << wcs_[ww]->ctype[1] << "-SIP" << ends; + putFitsCard(chan, "CTYPE2", str.str().c_str()); + } + } + else if ((wcs_[ww]->prjcode == WCS_LIN) && + (strncmp(wcs_[ww]->ctype[0]+2,"LN",2)) && + (strncmp(wcs_[ww]->ctype[0]+2,"LT",2)) && + (strncmp(wcs_[ww]->ctype[0]+1,"LON",3)) && + (strncmp(wcs_[ww]->ctype[0]+1,"LAT",3))) { + // this is not a mistake + putFitsCard(chan, "CTYPE1", wcs_[ww]->c1type); + putFitsCard(chan, "CTYPE2", wcs_[ww]->c2type); + } + else if (wcs_[ww]->prjcode == WCS_PIX) { + // this is not a mistake + putFitsCard(chan, "CTYPE1", wcs_[ww]->c1type); + putFitsCard(chan, "CTYPE2", wcs_[ww]->c2type); + } + else { + putFitsCard(chan, "CTYPE1", wcs_[ww]->ctype[0]); + putFitsCard(chan, "CTYPE2", wcs_[ww]->ctype[1]); + } + + // CRPIX/CRVAL + putFitsCard(chan, "CRPIX1", wcs_[ww]->crpix[0]); + putFitsCard(chan, "CRPIX2", wcs_[ww]->crpix[1]); + putFitsCard(chan, "CRVAL1", wcs_[ww]->crval[0]); + putFitsCard(chan, "CRVAL2", wcs_[ww]->crval[1]); + + // CD/CDELT/PC + // This is very complicated. AST is very, very, very picky as to which + // keywords it use... + { + ostringstream cd; + cd << "CD1_1" << alt << ends; + ostringstream cdelt; + cdelt << "CDELT1" << alt << ends; + ostringstream pc; + pc << "PC1_1" << alt << ends; + + if (hd->find(cd.str().c_str()) || + (prim && prim->find(cd.str().c_str()))) { + // simple case CD + // no rotation, no poles, no LIN, no inner cd values + if (!wcs_[ww]->cd[1] && !wcs_[ww]->cd[2] && + !wcs_[ww]->rot && + !wcs_[ww]->coorflip && + wcs_[ww]->latpole == 999 && + wcs_[ww]->longpole == 999 && + wcs_[ww]->prjcode != WCS_PIX && + wcs_[ww]->prjcode != WCS_LIN) { + putFitsCard(chan, "CDELT1", wcs_[ww]->cdelt[0]); + putFitsCard(chan, "CDELT2", wcs_[ww]->cdelt[1]); + } + else { + putFitsCard(chan, "CD1_1", wcs_[ww]->cd[0]); + putFitsCard(chan, "CD1_2", wcs_[ww]->cd[1]); + putFitsCard(chan, "CD2_1", wcs_[ww]->cd[2]); + putFitsCard(chan, "CD2_2", wcs_[ww]->cd[3]); + } + } + // CDELT + else if (hd->find(cdelt.str().c_str()) || + (prim && prim->find(cdelt.str().c_str()))) { + putFitsCard(chan, "CDELT1", wcs_[ww]->cdelt[0]); + putFitsCard(chan, "CDELT2", wcs_[ww]->cdelt[1]); + + if (hd->find(pc.str().c_str()) || + (prim && prim->find(pc.str().c_str()))) { + putFitsCard(chan, "PC1_1", wcs_[ww]->pc[0]); + putFitsCard(chan, "PC1_2", wcs_[ww]->pc[1]); + putFitsCard(chan, "PC2_1", wcs_[ww]->pc[2]); + putFitsCard(chan, "PC2_2", wcs_[ww]->pc[3]); + } + else if (!ww && + (hd->find("PC001001") || (prim && prim->find("PC001001")))) { + putFitsCard(chan, "PC001001", wcs_[ww]->pc[0]); + putFitsCard(chan, "PC001002", wcs_[ww]->pc[1]); + putFitsCard(chan, "PC002001", wcs_[ww]->pc[2]); + putFitsCard(chan, "PC002002", wcs_[ww]->pc[3]); + } + else { + if (!ww && + (hd->find("CROTA1") || (prim && prim->find("CROTA1")))) + putFitsCard(chan, "CROTA1", wcs_[ww]->rot); + if (!ww && + (hd->find("CROTA2") || (prim && hd->find("CROTA2")))) + putFitsCard(chan, "CROTA2", wcs_[ww]->rot); + } + } + // sanity check + else if (!wcs_[ww]->cd[0] && + !wcs_[ww]->cd[1] && + !wcs_[ww]->cd[2] && + !wcs_[ww]->cd[3]) { + putFitsCard(chan, "CDELT1", wcs_[ww]->cdelt[0]); + putFitsCard(chan, "CDELT2", wcs_[ww]->cdelt[1]); + putFitsCard(chan, "PC1_1", wcs_[ww]->pc[0]); + putFitsCard(chan, "PC1_2", wcs_[ww]->pc[1]); + putFitsCard(chan, "PC2_1", wcs_[ww]->pc[2]); + putFitsCard(chan, "PC2_2", wcs_[ww]->pc[3]); + } + // fall back + else { + putFitsCard(chan, "CD1_1", wcs_[ww]->cd[0]); + putFitsCard(chan, "CD1_2", wcs_[ww]->cd[1]); + putFitsCard(chan, "CD2_1", wcs_[ww]->cd[2]); + putFitsCard(chan, "CD2_2", wcs_[ww]->cd[3]); + } + } + + // equatorial keywords + if (wcs_[ww]->prjcode>0 && wcs_[ww]->prjcode<34) { + // equiniox + putFitsCard(chan, "EQUINOX", wcs_[ww]->equinox); + + // from wcssub/wcsinit.c line 800 + // wcs[ww]->epoch = 1900.0 + (mjd - 15019.81352) / 365.242198781; + putFitsCard(chan, "MJD-OBS", + (wcs_[ww]->epoch-1900)*365.242198781+15019.81352); + + ostringstream radesys; + radesys << "RADESYS" << alt << ends; + if (hd->find(radesys.str().c_str())) { + // if RADESYS present, use it + putFitsCard(chan, "RADESYS", hd->getString(radesys.str().c_str())); + } + else if (prim && prim->find(radesys.str().c_str())) { + // if RADESYS present, use it + putFitsCard(chan, "RADESYS", prim->getString(radesys.str().c_str())); + } + else if (hd->find("RADECSYS")) { + // look for old RADECSYS + putFitsCard(chan, "RADESYS", hd->getString("RADECSYS")); + } + else if (prim && prim->find("RADECSYS")) { + // look for old RADECSYS + putFitsCard(chan, "RADESYS", prim->getString("RADECSYS")); + } + else { + // fall back on wcssubs + if (!strncmp("RA",wcs_[ww]->ctype[0],2) || + !strncmp("RA",wcs_[ww]->ctype[1],2)) { + if (!strncmp("FK4",wcs_[ww]->radecsys,3) || + !strncmp("FK4-NO-E",wcs_[ww]->radecsys,8) || + !strncmp("FK5",wcs_[ww]->radecsys,3) || + !strncmp("ICRS",wcs_[ww]->radecsys,4)) + putFitsCard(chan, "RADESYS", wcs_[ww]->radecsys); + } + } + } + + // ast is picky about latpole/longpole + if ((wcs_[ww]->latpole == 999 && wcs_[ww]->longpole == 999) || + (wcs_[ww]->latpole == 0 && wcs_[ww]->longpole == 0)) + ; + else { + if (wcs_[ww]->latpole != 999) + putFitsCard(chan, "LATPOLE", wcs_[ww]->latpole); + if (wcs_[ww]->longpole != 999) + putFitsCard(chan, "LONPOLE", wcs_[ww]->longpole); + } + + // Projection parameters- PV, QV, WAT + // TAN+PV (old SCAMP-backward compatibility) + // TPV+PV (new SCAMP) + // xxx+PV (ZPN generic) + // xxx+QV (TAN AUTOASTROM) + // TNX/ZPX+WAT (IRAF) + // TAN/LIN-SIP (SIP) + + // PVx_y (old SCAMP, SCAMP, generic) + // MAXPV defined in wcs.h + for (int ii=1; ii<=2; ii++) { + for (int mm=0; mm<=MAXPV; mm++) { + ostringstream str,str2; + str << "PV" << ii << '_' << mm << alt << ends; + str2 << "PV" << ii << '_' << mm << ends; + if (hd->find(str.str().c_str())) { + double val = hd->getReal(str.str().c_str(),0); + putFitsCard(chan, str2.str().c_str(), val); + } + else if (prim && prim->find(str.str().c_str())) { + double val = prim->getReal(str.str().c_str(),0); + putFitsCard(chan, str2.str().c_str(), val); + } + } + } + + // QVx_y (Autoastrom) + for (int ii=1; ii<=2; ii++) { + for (int mm=0; mm<=MAXPV; mm++) { + ostringstream str,str2; + str << "QV" << ii << '_' << mm << alt << ends; + str2 << "QV" << ii << '_' << mm << ends; + if (hd->find(str.str().c_str())) { + double val = hd->getReal(str.str().c_str(),0); + putFitsCard(chan, str2.str().c_str(), val); + } + else if (prim && prim->find(str.str().c_str())) { + double val = prim->getReal(str.str().c_str(),0); + putFitsCard(chan, str2.str().c_str(), val); + } + } + } + + // WATx_ (IRAF) (primary only) + if ((wcs_[ww]->prjcode == WCS_TNX || wcs_[ww]->prjcode == WCS_ZPX) && !ww) { + for (int jj=0; jj<=2; jj++) { + for (int ii=1; ii<=9; ii++) { + ostringstream str; + str << "WAT" << jj << "_00" << ii << ends; + if (hd->find(str.str().c_str())) { + char* val = hd->getString(str.str().c_str()); + if (val) { + putFitsCard(chan, str.str().c_str(), val); + delete [] val; + } + } + else if (prim && prim->find(str.str().c_str())) { + char* val = prim->getString(str.str().c_str()); + if (val) { + putFitsCard(chan, str.str().c_str(), val); + delete [] val; + } + } + } + } + } + + // SIP (TAN-SIP/LIN-SIP) (primary only) + if ((wcs_[ww]->prjcode == WCS_TAN || wcs_[ww]->prjcode == WCS_LIN) && + !ww && wcs_[ww]->distcode) { + if (hd->find("A_ORDER")) { + int val = hd->getInteger("A_ORDER",0); + putFitsCard(chan, "A_ORDER", val); + } + else if (prim && prim->find("A_ORDER")) { + int val = prim->getInteger("A_ORDER",0); + putFitsCard(chan, "A_ORDER", val); + } + + if (hd->find("AP_ORDER")) { + int val = hd->getInteger("AP_ORDER",0); + putFitsCard(chan, "AP_ORDER", val); + } + else if (prim && prim->find("AP_ORDER")) { + int val = prim->getInteger("AP_ORDER",0); + putFitsCard(chan, "AP_ORDER", val); + } + + if (hd->find("A_DMAX")) { + double val = hd->getReal("A_DMAX",0); + putFitsCard(chan, "A_DMAX", val); + } + else if (prim && prim->find("A_DMAX")) { + double val = prim->getReal("A_DMAX",0); + putFitsCard(chan, "A_DMAX", val); + } + + if (hd->find("B_ORDER")) { + int val = hd->getInteger("B_ORDER",0); + putFitsCard(chan, "B_ORDER", val); + } + else if (prim && prim->find("B_ORDER")) { + int val = prim->getInteger("B_ORDER",0); + putFitsCard(chan, "B_ORDER", val); + } + + if (hd->find("BP_ORDER")) { + int val = hd->getInteger("BP_ORDER",0); + putFitsCard(chan, "BP_ORDER", val); + } + else if (prim && prim->find("BP_ORDER")) { + int val = prim->getInteger("BP_ORDER",0); + putFitsCard(chan, "BP_ORDER", val); + } + + if (hd->find("B_DMAX")) { + double val = hd->getReal("B_DMAX",0); + putFitsCard(chan, "B_DMAX", val); + } + else if (prim && prim->find("B_DMAX")) { + double val = prim->getReal("B_DMAX",0); + putFitsCard(chan, "B_DMAX", val); + } + + for (int jj=0; jj<=9; jj++) { + for (int ii=0; ii<=9; ii++) { + { + ostringstream str; + str << "A_" << jj << "_" << ii << ends; + if (hd->find(str.str().c_str())) { + double val = hd->getReal(str.str().c_str(),0); + putFitsCard(chan, str.str().c_str(), val); + } + else if (prim && prim->find(str.str().c_str())) { + double val = prim->getReal(str.str().c_str(),0); + putFitsCard(chan, str.str().c_str(), val); + } + } + { + ostringstream str; + str << "AP_" << jj << "_" << ii << ends; + if (hd->find(str.str().c_str())) { + double val = hd->getReal(str.str().c_str(),0); + putFitsCard(chan, str.str().c_str(), val); + } + else if (prim && prim->find(str.str().c_str())) { + double val = prim->getReal(str.str().c_str(),0); + putFitsCard(chan, str.str().c_str(), val); + } + } + { + ostringstream str; + str << "B_" << jj << "_" << ii << ends; + if (hd->find(str.str().c_str())) { + double val = hd->getReal(str.str().c_str(),0); + putFitsCard(chan, str.str().c_str(), val); + } + else if (prim && prim->find(str.str().c_str())) { + double val = prim->getReal(str.str().c_str(),0); + putFitsCard(chan, str.str().c_str(), val); + } + } + { + ostringstream str; + str << "BP_" << jj << "_" << ii << ends; + if (hd->find(str.str().c_str())) { + double val = hd->getReal(str.str().c_str(),0); + putFitsCard(chan, str.str().c_str(), val); + } + else if (prim && prim->find(str.str().c_str())) { + double val = prim->getReal(str.str().c_str(),0); + putFitsCard(chan, str.str().c_str(), val); + } + } + } + } + } +} + +void FitsImage::wcs2ast0(int ww, void* chan) +{ + if (DebugAST) + cerr << endl << "wcs2ast0()" << endl; + + putFitsCard(chan, "CTYPE1", wcs_[ww]->ctype[0]); + putFitsCard(chan, "CTYPE2", wcs_[ww]->ctype[1]); + + // CRPIX/CRVAL + putFitsCard(chan, "CRPIX1", wcs_[ww]->crpix[0]); + putFitsCard(chan, "CRPIX2", wcs_[ww]->crpix[1]); + putFitsCard(chan, "CRVAL1", wcs_[ww]->crval[0]); + putFitsCard(chan, "CRVAL2", wcs_[ww]->crval[1]); + + putFitsCard(chan, "CD1_1", wcs_[ww]->cd[0]); + putFitsCard(chan, "CD1_2", wcs_[ww]->cd[1]); + putFitsCard(chan, "CD2_1", wcs_[ww]->cd[2]); + putFitsCard(chan, "CD2_2", wcs_[ww]->cd[3]); + + putFitsCard(chan, "EQUINOX", wcs_[ww]->equinox); + + // from wcssub/wcsinit.c line 800 + // wcs[ww]->epoch = 1900.0 + (mjd - 15019.81352) / 365.242198781; + putFitsCard(chan, "MJD-OBS", + (wcs_[ww]->epoch-1900)*365.242198781+15019.81352); + + putFitsCard(chan, "RADESYS", wcs_[ww]->radecsys); +} + +void FitsImage::putFitsCard(void* chan, const char* key, const char* value) +{ + char buf[80]; + memset(buf,'\0', 80); + + ostringstream str; + str.setf(ios::left,ios::adjustfield); + str.width(8); + str << key << "= '" << value << "'"; + memcpy(buf,str.str().c_str(),str.str().length()); + + astPutFits(chan, buf, 0); + astClearStatus; + + if (DebugAST) + cerr << str.str().c_str() << endl; +} + +void FitsImage::putFitsCard(void* chan, const char* key, int value) +{ + char buf[80]; + memset(buf,'\0', 80); + + ostringstream str; + str.setf(ios::left,ios::adjustfield); + str.width(8); + str << key << "= " << value; + memcpy(buf,str.str().c_str(),str.str().length()); + + astPutFits(chan, buf, 0); + astClearStatus; + + if (DebugAST) + cerr << str.str().c_str() << endl; +} + +void FitsImage::putFitsCard(void* chan, const char* key, double value) +{ + char buf[80]; + memset(buf,'\0', 80); + + ostringstream str; + str.setf(ios::left,ios::adjustfield); + str.setf(ios::scientific,ios::floatfield); + str.width(8); + str.precision(16); + str << key << "= " << value; + memcpy(buf,str.str().c_str(),str.str().length()); + + astPutFits(chan, buf, 0); + astClearStatus; + + if (DebugAST) + cerr << str.str().c_str() << endl; +} |