diff options
Diffstat (limited to 'tksao/frame/framergb.C')
-rw-r--r-- | tksao/frame/framergb.C | 1722 |
1 files changed, 1722 insertions, 0 deletions
diff --git a/tksao/frame/framergb.C b/tksao/frame/framergb.C new file mode 100644 index 0000000..a2e2949 --- /dev/null +++ b/tksao/frame/framergb.C @@ -0,0 +1,1722 @@ +// Copyright (C) 1999-2016 +// Smithsonian Astrophysical Observatory, Cambridge, MA, USA +// For conditions of distribution and use, see copyright notice in "copyright" + +#include <tkInt.h> + +#include "framergb.h" +#include "fitsimage.h" +#include "ps.h" +#include "outfile.h" +#include "outchannel.h" +#include "outsocket.h" + +#include "sigbus.h" + +// Frame Member Functions + +FrameRGB::FrameRGB(Tcl_Interp* i, Tk_Canvas c, Tk_Item* item) + : FrameBase(i,c,item) +{ + context = new Context[3]; + context[0].parent(this); + context[1].parent(this); + context[2].parent(this); + + channel = 0; + rgbSystem = Coord::WCS; + + for (int ii=0; ii<3; ii++) { + view[ii] = 1; + bias[ii] = .5; + contrast[ii] = 1.0; + colorScale[ii] = NULL; + } + + for (int kk=0; kk<3; kk++) + colormapData[kk] = NULL; + + colorCount = 0; + colorCells = NULL; + + currentContext = &context[channel]; + keyContext = &context[channel]; + keyContextSet =0; +} + +FrameRGB::~FrameRGB() +{ + if (context) + delete [] context; + + for (int ii=0; ii<3; ii++) { + if (colorScale[ii]) + delete colorScale[ii]; + } + + for (int kk=0; kk<3; kk++) + if (colormapData[kk]) + delete [] colormapData[kk]; + + if (colorCells) + delete [] colorCells; +} + +void FrameRGB::alignWCS() +{ + if (!wcsAlign_ || !(keyContext->fits) || !keyContext->fits->hasWCS(wcsSystem_)) { + wcsOrientation = Coord::NORMAL; + wcsOrientationMatrix.identity(); + wcsRotation = 0; + } + else + calcAlignWCS(keyContext->fits, wcsSystem_, wcsSky_, + &wcsOrientation, &wcsOrientationMatrix, &wcsRotation); + + updateRGBMatrices(); +} + +void FrameRGB::alignWCS(Coord::CoordSystem sys, Coord::SkyFrame sky) +{ + if (!wcsAlign_ || !(keyContext->fits) || !keyContext->fits->hasWCS(sys)) { + wcsOrientation = Coord::NORMAL; + wcsOrientationMatrix.identity(); + wcsRotation = 0; + } + else + calcAlignWCS(keyContext->fits, sys, sky, + &wcsOrientation, &wcsOrientationMatrix, &wcsRotation); + + updateRGBMatrices(); +} + +void FrameRGB::alignWCS(FitsImage* ptr, Coord::CoordSystem sys) +{ + if (!wcsAlign_ || !(keyContext->fits) || !ptr || + !keyContext->fits->hasWCS(wcsSystem_)) { + wcsOrientation = Coord::NORMAL; + wcsOrientationMatrix.identity(); + wcsRotation = 0; + } + else + calcAlignWCS(ptr, keyContext->fits, wcsSystem_, sys, wcsSky_, + &wcsOrientation, &wcsOrientationMatrix, &wcsRotation, &zoom_); + + updateRGBMatrices(); +} + +int FrameRGB::doRender() +{ + return ((context[0].fits&&view[0]) || + (context[1].fits&&view[1]) || + (context[2].fits&&view[2])); +} + +unsigned char* FrameRGB::fillImage(int width, int height, + Coord::InternalSystem sys) +{ + // img + unsigned char* img = new unsigned char[width*height*3]; + memset(img,0,width*height*3); + + // mk + char* mk = new char[width*height]; + memset(mk,0,width*height); + + SETSIGBUS + + // one channel at a time + for (int kk=0; kk<3; kk++) { + if (!view[kk] || !context[kk].fits) + continue; + + // basics + int length = colorScale[kk]->size() - 1; + const unsigned char* table = colorScale[kk]->psColors(); + + FitsImage* sptr = context[kk].cfits; + int mosaic = context[kk].isMosaic(); + + // variable + double* mm = sptr->matrixToData(sys).mm(); + FitsBound* params = sptr->getDataParams(context[kk].secMode()); + int srcw = sptr->width(); + + double ll = sptr->low(); + double hh = sptr->high(); + double diff = hh - ll; + + // main loop + unsigned char* dest = img; + char* mkptr = mk; + + for (long jj=0; jj<height; jj++) { + for (long ii=0; ii<width; ii++, dest+=3, mkptr++) { + + if (mosaic) { + sptr = context[kk].cfits; + + mm = sptr->matrixToData(sys).mm(); + params = sptr->getDataParams(context[kk].secMode()); + srcw = sptr->width(); + + ll = sptr->low(); + hh = sptr->high(); + diff = hh - ll; + } + + do { + double xx = ii*mm[0] + jj*mm[3] + mm[6]; + double yy = ii*mm[1] + jj*mm[4] + mm[7]; + + if (xx>=params->xmin && xx<params->xmax && + yy>=params->ymin && yy<params->ymax) { + double value = sptr->getValueDouble(long(yy)*srcw + long(xx)); + + if (isfinite(diff) && isfinite(value)) { + if (value <= ll) + *(dest+kk) = *table; + else if (value >= hh) + *(dest+kk) = *(table+length); + else + *(dest+kk) = *(table+((int)(((value - ll)/diff * length) +.5))); + *mkptr =2; + } + else if (*mkptr < 2) + *mkptr =1; + + break; + } + else { + if (mosaic) { + sptr = sptr->nextMosaic(); + + if (sptr) { + mm = sptr->matrixToData(sys).mm(); + params = sptr->getDataParams(context[kk].secMode()); + srcw = sptr->width(); + + ll = sptr->low(); + hh = sptr->high(); + diff = hh - ll; + } + } + } + } + while (mosaic && sptr); + } + } + } + + // now fill in bg + { + unsigned char* dest = img; + char* mkptr = mk; + for (int jj=0; jj<height; jj++) + for (int ii=0; ii<width; ii++, dest+=3, mkptr++) { + if (*mkptr == 2) // good value + ; + else if (*mkptr == 1) { // nan + *dest = (unsigned char)nanColor->red; + *(dest+1) = (unsigned char)nanColor->green; + *(dest+2) = (unsigned char)nanColor->blue; + } + else { // bg + *dest = (unsigned char)bgColor->red; + *(dest+1) = (unsigned char)bgColor->green; + *(dest+2) = (unsigned char)bgColor->blue; + } + } + } + CLEARSIGBUS + + // clean up + delete [] mk; + + return img; +} + +BBox FrameRGB::imageBBox(FrScale::SecMode mode) +{ + // returns imageBBox in IMAGE coords + // and extends edge to edge + + updateRGBMatrices(); + + BBox rr; + int first=1; + for (int ii=0; ii<3; ii++) { + if (context[ii].fits) { + FitsImage* ptr = context[ii].fits; + while (ptr) { + FitsBound* params = ptr->getDataParams(mode); + Matrix mm = ptr->wcsToRef() * rgb[ii] * dataToImage; + + Vector aa = Vector(params->xmin,params->ymin) * mm; + if (first) { + rr = BBox(aa,aa); + first = 0; + } + else + rr.bound(aa); + + rr.bound(Vector(params->xmax,params->ymin) * mm); + rr.bound(Vector(params->xmax,params->ymax) * mm); + rr.bound(Vector(params->xmin,params->ymax) * mm); + + ptr = ptr->nextMosaic(); + } + } + } + + return rr; +} + +void FrameRGB::loadRGBCube(MemType which, const char* fn, FitsImage* img) +{ + if (!img || !img->isValid() || !(img->isImage() || img->isPost()) || (img->depth() != 3)) + goto error; + + context[0].bfits_ = img; + + if (img->isPost()) + which = POST; + + switch (which) { + case ALLOC: + if (context[0].bfits_ && context[0].bfits_->isValid()) + context[1].bfits_ = + new FitsImageFitsNextAlloc(&context[1], interp, + fn, context[0].bfits_->fitsFile(),2); + if (context[1].bfits_ && context[1].bfits_->isValid()) + context[2].bfits_ = + new FitsImageFitsNextAlloc(&context[2], interp, + fn, context[1].bfits_->fitsFile(),3); + break; + case ALLOCGZ: + if (context[0].bfits_ && context[0].bfits_->isValid()) + context[1].bfits_ = + new FitsImageFitsNextAllocGZ(&context[1], interp, + fn, context[0].bfits_->fitsFile(),2); + if (context[1].bfits_ && context[1].bfits_->isValid()) + context[2].bfits_ = + new FitsImageFitsNextAllocGZ(&context[2], interp, + fn, context[1].bfits_->fitsFile(),3); + break; + case CHANNEL: + if (context[0].bfits_ && context[0].bfits_->isValid()) + context[1].bfits_ = + new FitsImageFitsNextChannel(&context[1], interp, + fn, context[0].bfits_->fitsFile(),2); + if (context[1].bfits_ && context[1].bfits_->isValid()) + context[2].bfits_ = + new FitsImageFitsNextChannel(&context[2], interp, + fn, context[1].bfits_->fitsFile(),3); + break; + case MMAP: + if (context[0].bfits_ && context[0].bfits_->isValid()) + context[1].bfits_ = + new FitsImageFitsNextMMap(&context[1], interp, + fn, context[0].bfits_->fitsFile(),2); + if (context[1].bfits_ && context[1].bfits_->isValid()) + context[2].bfits_ = + new FitsImageFitsNextMMap(&context[2], interp, + fn, context[1].bfits_->fitsFile(),3); + break; + case SMMAP: + if (context[0].bfits_ && context[0].bfits_->isValid()) + context[1].bfits_ = + new FitsImageFitsNextSMMap(&context[1], interp, + fn, context[0].bfits_->fitsFile(),2); + if (context[1].bfits_ && context[1].bfits_->isValid()) + context[2].bfits_ = + new FitsImageFitsNextSMMap(&context[2], interp, + fn, context[1].bfits_->fitsFile(),3); + break; + case MMAPINCR: + if (context[0].bfits_ && context[0].bfits_->isValid()) + context[1].bfits_ = + new FitsImageFitsNextMMapIncr(&context[1], interp, + fn, context[0].bfits_->fitsFile(),2); + if (context[1].bfits_ && context[1].bfits_->isValid()) + context[2].bfits_ = + new FitsImageFitsNextMMapIncr(&context[2], interp, + fn, context[1].bfits_->fitsFile(),3); + break; + case SHARE: + if (context[0].bfits_ && context[0].bfits_->isValid()) + context[1].bfits_ = + new FitsImageFitsNextShare(&context[1], interp, + fn, context[0].bfits_->fitsFile(),2); + if (context[1].bfits_ && context[1].bfits_->isValid()) + context[2].bfits_ = + new FitsImageFitsNextShare(&context[2], interp, + fn, context[1].bfits_->fitsFile(),3); + break; + case SSHARE: + if (context[0].bfits_ && context[0].bfits_->isValid()) + context[1].bfits_ = + new FitsImageFitsNextSShare(&context[1], interp, + fn, context[0].bfits_->fitsFile(),2); + if (context[1].bfits_ && context[1].bfits_->isValid()) + context[2].bfits_ = + new FitsImageFitsNextSShare(&context[2], interp, + fn, context[1].bfits_->fitsFile(),3); + break; + case SOCKET: + if (context[0].bfits_ && context[0].bfits_->isValid()) + context[1].bfits_ = + new FitsImageFitsNextSocket(&context[1], interp, + fn, context[0].bfits_->fitsFile(),2); + if (context[1].bfits_ && context[1].bfits_->isValid()) + context[2].bfits_ = + new FitsImageFitsNextSocket(&context[2], interp, + fn, context[1].bfits_->fitsFile(),3); + break; + case SOCKETGZ: + if (context[0].bfits_ && context[0].bfits_->isValid()) + context[1].bfits_ = + new FitsImageFitsNextSocketGZ(&context[1], interp, + fn, context[0].bfits_->fitsFile(),2); + if (context[1].bfits_ && context[1].bfits_->isValid()) + context[2].bfits_ = + new FitsImageFitsNextSocketGZ(&context[2], interp, + fn, context[1].bfits_->fitsFile(),3); + break; + case VAR: + if (context[0].bfits_ && context[0].bfits_->isValid()) + context[1].bfits_ = + new FitsImageFitsNextVar(&context[1], interp, + fn, context[0].bfits_->fitsFile(),2); + if (context[1].bfits_ && context[1].bfits_->isValid()) + context[2].bfits_ = + new FitsImageFitsNextVar(&context[2], interp, + fn, context[1].bfits_->fitsFile(),3); + break; + case POST: + if (context[0].bfits_ && context[0].bfits_->isValid()) + context[1].bfits_ = + new FitsImageFitsNextPost(&context[1], interp, + img, context[0].bfits_->baseFile(),2); + if (context[1].bfits_ && context[1].bfits_->isValid()) + context[2].bfits_ = + new FitsImageFitsNextPost(&context[2], interp, + img, context[1].bfits_->baseFile(),3); + break; + case PHOTO: + if (context[0].bfits_ && context[0].bfits_->isValid()) + context[1].bfits_ = + new FitsImagePhotoCubeNext(&context[1], interp, + fn, context[0].bfits_->baseFile(),2); + if (context[1].bfits_ && context[1].bfits_->isValid()) + context[2].bfits_ = + new FitsImagePhotoCubeNext(&context[2], interp, + fn, context[1].bfits_->baseFile(),3); + break; + default: + // na + break; + } + + // is everything ok? + if (context[0].bfits_ && context[0].bfits_->isValid() && + (context[0].bfits_->isImage() || context[0].bfits_->isPost()) && + context[1].bfits_ && context[1].bfits_->isValid() && + (context[1].bfits_->isImage() || context[1].bfits_->isPost()) && + context[2].bfits_ && context[2].bfits_->isValid() && + (context[2].bfits_->isImage() || context[2].bfits_->isPost())) { + + loadRGBFinish(); + return; + } + + error: + context[0].unload(); + context[1].unload(); + context[2].unload(); + + reset(); + updateColorScale(); + + Tcl_AppendResult(interp, "Unable to load rgb cube file", NULL); + result = TCL_ERROR; + return; +} + +void FrameRGB::loadRGBImage(MemType which, const char* fn, FitsImage* img) +{ + FitsImage* r = img; + FitsImage* g = NULL; + FitsImage* b = NULL; + + if (!img || !img->isValid() || !(img->isImage() || img->isPost())) + goto error; + + switch (which) { + case ALLOC: + if (r && r->isValid()) + g = new FitsImageMosaicNextAlloc(&context[1], interp, + fn, r->fitsFile(), + FitsFile::NOFLUSH,1); + if (g && g->isValid()) + b = new FitsImageMosaicNextAlloc(&context[2], interp, + fn, g->fitsFile(), + FitsFile::NOFLUSH,1); + break; + case ALLOCGZ: + if (r && r->isValid()) + g = new FitsImageMosaicNextAllocGZ(&context[1], interp, + fn, r->fitsFile(), + FitsFile::NOFLUSH,1); + if (g && g->isValid()) + b = new FitsImageMosaicNextAllocGZ(&context[2], interp, + fn, g->fitsFile(), + FitsFile::NOFLUSH,1); + break; + case CHANNEL: + if (r && r->isValid()) + g = new FitsImageMosaicNextChannel(&context[1], interp, + fn, r->fitsFile(), + FitsFile::NOFLUSH,1); + if (g && g->isValid()) + b = new FitsImageMosaicNextChannel(&context[2], interp, + fn, g->fitsFile(), + FitsFile::NOFLUSH,1); + break; + case MMAP: + if (r && r->isValid()) + g = new FitsImageMosaicNextMMap(&context[1], interp, + fn, r->fitsFile(),1); + if (g && g->isValid()) + b = new FitsImageMosaicNextMMap(&context[2], interp, + fn, g->fitsFile(),1); + break; + case MMAPINCR: + if (r && r->isValid()) + g = new FitsImageMosaicNextMMapIncr(&context[1], interp, + fn, r->fitsFile(),1); + if (g && g->isValid()) + b = new FitsImageMosaicNextMMapIncr(&context[2], interp, + fn, g->fitsFile(),1); + break; + case SHARE: + if (r && r->isValid()) + g = new FitsImageMosaicNextShare(&context[1], interp, + fn, r->fitsFile(),1); + if (g && g->isValid()) + b = new FitsImageMosaicNextShare(&context[2], interp, + fn, g->fitsFile(),1); + break; + case SOCKET: + if (r && r->isValid()) + g = new FitsImageMosaicNextSocket(&context[1], interp, + fn, r->fitsFile(), + FitsFile::FLUSH,1); + if (g && g->isValid()) + b = new FitsImageMosaicNextSocket(&context[2], interp, + fn,g->fitsFile(), + FitsFile::FLUSH,1); + break; + case SOCKETGZ: + if (r && r->isValid()) + g = new FitsImageMosaicNextSocketGZ(&context[1], interp, + fn, r->fitsFile(), + FitsFile::FLUSH,1); + if (g && g->isValid()) + b = new FitsImageMosaicNextSocketGZ(&context[2], interp, + fn, g->fitsFile(), + FitsFile::FLUSH,1); + break; + case VAR: + if (r && r->isValid()) + g = new FitsImageMosaicNextVar(&context[1], interp, + fn, r->fitsFile(),1); + if (g && g->isValid()) + b = new FitsImageMosaicNextVar(&context[2], interp, + fn, g->fitsFile(),1); + break; + default: + // na + break; + } + + // ok, figure out which is which channel + context[0].bfits_ = context[1].bfits_ = context[2].bfits_ = NULL; + + { + const char* ext = r->fitsFile()->extname(); + if (ext) { + if (!strncmp(ext,"RED",3)) + context[0].bfits_ = r; + else if (!strncmp(ext,"GREEN",3)) { + context[1].bfits_ = r; + r->setContext(&context[1]); + } + else if (!strncmp(ext,"BLUE",3)) { + context[2].bfits_ = r; + r->setContext(&context[2]); + } + else + context[0].bfits_ = r; + } + else + context[0].bfits_ = r; + } + + { + const char* ext = g->fitsFile()->extname(); + if (ext) { + if (!strncmp(ext,"RED",3)) { + context[0].bfits_ = g; + g->setContext(&context[0]); + } + else if (!strncmp(ext,"GREEN",3)) + context[1].bfits_ = g; + else if (!strncmp(ext,"BLUE",3)) { + context[2].bfits_ = g; + g->setContext(&context[3]); + } + else + context[1].bfits_ = g; + } + else + context[1].bfits_ = g; + } + + { + const char* ext = b->fitsFile()->extname(); + if (ext) { + if (!strncmp(ext,"RED",3)) { + context[0].bfits_ = b; + b->setContext(&context[0]); + } + else if (!strncmp(ext,"GREEN",3)) { + context[1].bfits_ = b; + b->setContext(&context[1]); + } + else if (!strncmp(ext,"BLUE",3)) + context[2].bfits_ = b; + else + context[2].bfits_ = b; + } + else + context[2].bfits_ = b; + } + + // is everything ok? + if (context[0].bfits_ && context[0].bfits_->isValid() && + (context[0].bfits_->isImage() || context[0].bfits_->isPost()) && + context[1].bfits_ && context[1].bfits_->isValid() && + (context[1].bfits_->isImage() || context[1].bfits_->isPost()) && + context[2].bfits_ && context[2].bfits_->isValid() && + (context[2].bfits_->isImage() || context[2].bfits_->isPost())) { + + loadRGBFinish(); + return; + } + + error: + context[0].unload(); + context[1].unload(); + context[2].unload(); + + reset(); + updateColorScale(); + + Tcl_AppendResult(interp, "Unable to load rgb image file", NULL); + result = TCL_ERROR; + return; +} + +void FrameRGB::loadRGBFinish() +{ + for (int ii=0; ii<3; ii++) { + context[ii].loadInit(1,NOMOSAIC,Coord::WCS); + context[ii].loadFinish(); + } + + channel = 0; + currentContext = &context[channel]; + keyContext = &context[channel]; + keyContextSet =1; + + alignWCS(); + if (!preservePan) { + centerImage(); + // cursor is in REF, crosshair in REF + crosshair = cursor; + } + updateColorScale(); + update(MATRIX); +} + +void FrameRGB::pushMatrices() +{ + for (int ii=0; ii<3; ii++) { + FitsImage* ptr = context[ii].fits; + while (ptr) { + FitsImage* sptr = ptr; + while (sptr) { + sptr->updateMatrices(rgb[ii], refToUser, userToWidget, + widgetToCanvas, canvasToWindow); + sptr = sptr->nextSlice(); + } + ptr = ptr->nextMosaic(); + } + } +} + +void FrameRGB::pushMagnifierMatrices() +{ + for (int ii=0; ii<3; ii++) { + FitsImage* ptr = context[ii].fits; + while (ptr) { + FitsImage* sptr = ptr; + while (sptr) { + sptr->updateMagnifierMatrices(refToMagnifier); + sptr = sptr->nextSlice(); + } + ptr = ptr->nextMosaic(); + } + } +} + +void FrameRGB::pushPannerMatrices() +{ + for (int ii=0; ii<3; ii++) { + FitsImage* ptr = context[ii].fits; + while (ptr) { + FitsImage* sptr = ptr; + while (sptr) { + sptr->updatePannerMatrices(refToPanner); + sptr = sptr->nextSlice(); + } + ptr = ptr->nextMosaic(); + } + } +} + +void FrameRGB::pushPSMatrices(float scale, int width, int height) +{ + Matrix mx = psMatrix(scale, width, height); + for (int kk=0; kk<3; kk++) + if (context[kk].fits) { + FitsImage* ptr = context[kk].cfits; + while (ptr) { + ptr->updatePS(mx); + ptr = ptr->nextMosaic(); + } + } +} + +void FrameRGB::reset() +{ + for (int ii=0; ii<3; ii++) { + bias[ii] = 0.5; + contrast[ii] = 1.0; + context[ii].resetSecMode(); + context[ii].updateClip(); + } + + Base::reset(); +} + +void FrameRGB::rgbAlignWCS(int ii) +{ + if (keyContext->fits && keyContext->fits->hasWCS(rgbSystem)) + rgb[ii] = calcAlignWCS(keyContext->fits, context[ii].fits, rgbSystem, rgbSystem, Coord::FK5); + + if (DebugRGB) + cerr << "rgbAlignWCS " << rgb[ii] << endl; +} + +void FrameRGB::setBinCursor() +{ + for (int ii=0; ii<3; ii++) + if (context[ii].fits) + context[ii].fits->setBinCursor(cursor); +} + +void FrameRGB::updateColorCells(unsigned char* cells, int cnt) +{ + if (DebugRGB) + cerr << "updateColorCells" << endl; + + colorCount = cnt; + if (colorCells) + delete [] colorCells; + colorCells = new unsigned char[cnt*3]; + if (!colorCells) { + internalError("Unable to Alloc colorCells"); + return; + } + memcpy(colorCells, cells, cnt*3); +} + +void FrameRGB::updateColorScale() +{ + // we need colors before we can construct a scale + if (!colorCells) + return; + + if (DebugRGB) + cerr << "updateColorScale" << endl; + + for (int ii=0; ii<3; ii++) { + if (colorScale[ii]) + delete colorScale[ii]; + + switch (context[ii].colorScaleType()) { + case FrScale::LINEARSCALE: + colorScale[ii] = + new LinearScaleRGB(ii, colorCount, colorCells, colorCount); + break; + case FrScale::LOGSCALE: + colorScale[ii] = + new LogScaleRGB(ii, SCALESIZE, colorCells, colorCount, + context[ii].expo()); + break; + case FrScale::POWSCALE: + colorScale[ii] = + new PowScaleRGB(ii, SCALESIZE, colorCells, colorCount, + context[ii].expo()); + break; + case FrScale::SQRTSCALE: + colorScale[ii] = + new SqrtScaleRGB(ii, SCALESIZE, colorCells, colorCount); + break; + case FrScale::SQUAREDSCALE: + colorScale[ii] = + new SquaredScaleRGB(ii, SCALESIZE, colorCells, colorCount); + break; + case FrScale::ASINHSCALE: + colorScale[ii] = + new AsinhScaleRGB(ii, SCALESIZE, colorCells, colorCount); + break; + case FrScale::SINHSCALE: + colorScale[ii] = + new SinhScaleRGB(ii, SCALESIZE, colorCells, colorCount); + break; + case FrScale::HISTEQUSCALE: + colorScale[ii] = + new HistEquScaleRGB(ii, SCALESIZE, colorCells, colorCount, + context[ii].histequ(), HISTEQUSIZE); + break; + case FrScale::IISSCALE: + // na + break; + } + } +} + + +void FrameRGB::updateRGBMatrices() +{ + // image,pysical,amplifier,detector are ok, check for wcs + if (rgbSystem >= Coord::WCS) { + for (int ii=0; ii<3; ii++) { + if (context[ii].fits && !context[ii].fits->hasWCS(rgbSystem)) { + // ok, don't have requested coordinate system + // down grade to image + rgbSystem = Coord::IMAGE; + break; + } + } + } + + // rgb align + for (int ii=0; ii<3; ii++) { + rgb[ii].identity(); + + if (context[ii].fits && keyContext->fits) { + switch (rgbSystem) { + case Coord::IMAGE: + // nothing to do here + break; + case Coord::PHYSICAL: + if (context[ii].fits != keyContext->fits) + rgb[ii] = + context[ii].fits->imageToPhysical * + keyContext->fits->physicalToImage; + break; + case Coord::AMPLIFIER: + if (context[ii].fits != keyContext->fits) + rgb[ii] = context[ii].fits->imageToAmplifier * + keyContext->fits->amplifierToImage; + break; + case Coord::DETECTOR: + if (context[ii].fits != keyContext->fits) + rgb[ii] = context[ii].fits->imageToDetector * + keyContext->fits->detectorToImage; + break; + default: + rgbAlignWCS(ii); + break; + } + } + + if (DebugRGB) + cerr << "rgb[" << ii << "] " << rgb[ii] << endl; + } +} + +void FrameRGB::unloadAllFits() +{ + if (DebugPerf) + cerr << "FrameRGB::unloadAllFits()" << endl; + + for (int ii=0; ii<3; ii++) { + rgb[ii].identity(); + context[ii].unload(); + + // always (for HISTEQU and LOG) + updateColorScale(); + } + + channel =0; + currentContext = &context[channel]; + keyContext = &context[channel]; + keyContextSet =0; + + FrameBase::unloadFits(); +} + +void FrameRGB::unloadFits() +{ + if (DebugPerf) + cerr << "FrameRGB::unloadFits()" << endl; + + rgb[channel].identity(); + context[channel].unload(); + + // always (for HISTEQU and LOG) + updateColorScale(); +} + +// Commands + +void FrameRGB::colormapCmd(float rb, float gb, float bb, + float rc, float gc, float bc, int i, + unsigned char* cells, int cnt) +{ + bias[0] = rb; + bias[1] = gb; + bias[2] = bb; + contrast[0] = rc; + contrast[1] = gc; + contrast[2] = bc; + invert = i; + + updateColorCells(cells, cnt); + updateColorScale(); + update(BASE); +} + +void FrameRGB::colormapBeginCmd() +{ + // we need a colorScale before we can render + if (!validColorScale()) + return; + + // we need some fits data + // we assume the colorScale length will not change during motion calls + if (!context[0].fits && !context[1].fits && !context[2].fits) + return; + + int width = options->width; + int height = options->height; + + // Create XImage + if (!(colormapXM = XGetImage(display, pixmap, 0, 0, + width, height, AllPlanes, ZPixmap))) { + internalError("Unable to Create Colormap XImage"); + return; + } + + // Create Pixmap + colormapPM = + Tk_GetPixmap(display, Tk_WindowId(tkwin), width, height, depth); + if (!colormapPM) { + internalError("Unable to Create Colormap Pixmap"); + return; + } + + // colormapGCXOR + colormapGCXOR = XCreateGC(display, Tk_WindowId(tkwin), 0, NULL); + + // Create table index array + for (int kk=0; kk<3; kk++) { + if (colormapData[kk]) + delete [] colormapData[kk]; + colormapData[kk] = new long[width*height]; + + if (!colormapData[kk]) { + internalError("Unable to alloc tmp data array"); + return; + } + } + + SETSIGBUS + + // fill data array + for (int kk=0; kk<3; kk++) { + if (!view[kk] || !context[kk].fits) + continue; + + // basics + int length = colorScale[kk]->size() - 1; + + FitsImage* sptr = context[kk].cfits; + int mosaic = context[kk].isMosaic(); + + // variable + double* mm = sptr->matrixToData(Coord::WIDGET).mm(); + FitsBound* params = sptr->getDataParams(context[kk].secMode()); + int srcw = sptr->width(); + + double ll = sptr->low(); + double hh = sptr->high(); + double diff = hh - ll; + + // main loop + long* dest = colormapData[kk]; + + for (long jj=0; jj<height; jj++) { + for (long ii=0; ii<width; ii++, dest++) { + *dest = -2; // bg + + if (mosaic) { + sptr = context[kk].cfits; + + mm = sptr->matrixToData(Coord::WIDGET).mm(); + params = sptr->getDataParams(context[kk].secMode()); + srcw = sptr->width(); + + ll = sptr->low(); + hh = sptr->high(); + diff = hh - ll; + } + + do { + double xx = ii*mm[0] + jj*mm[3] + mm[6]; + double yy = ii*mm[1] + jj*mm[4] + mm[7]; + + if (xx>=params->xmin && xx<params->xmax && + yy>=params->ymin && yy<params->ymax) { + double value = sptr->getValueDouble(long(yy)*srcw + long(xx)); + + if (isfinite(diff) && isfinite(value)) { + if (value <= ll) + *dest = 0; + else if (value >= hh) + *dest = length; + else + *dest = (int)(((value - ll)/diff * length) + .5); + } + else + *dest = -1; // nan + + break; + } + else { + if (mosaic) { + sptr = sptr->nextMosaic(); + + if (sptr) { + mm = sptr->matrixToData(Coord::WIDGET).mm(); + params = sptr->getDataParams(context[kk].secMode()); + srcw = sptr->width(); + + ll = sptr->low(); + hh = sptr->high(); + diff = hh - ll; + } + } + } + } + while (mosaic && sptr); + } + } + } + CLEARSIGBUS +} + +void FrameRGB::colormapEndCmd() +{ + if (colormapXM) { + XDestroyImage(colormapXM); + colormapXM = NULL; + } + + if (colormapPM) { + Tk_FreePixmap(display, colormapPM); + colormapPM = 0; + } + + if (colormapGCXOR) { + XFreeGC(display, colormapGCXOR); + colormapGCXOR = 0; + } + + for (int kk=0; kk<3; kk++) + if (colormapData[kk]) { + delete [] colormapData[kk]; + colormapData[kk] = NULL; + } + + update(BASE); // always update +} + +void FrameRGB::colormapMotionCmd(float rb, float gb, float bb, + float rc, float gc, float bc, int i, + unsigned char* cells, int cnt) +{ + // we need a colorScale before we can render + if (!validColorScale()) + return; + + // first check for change + if (bias[0] == rb && bias[1] == gb && bias[2] == bb && + contrast[0] == rc && contrast[1] == gc && contrast[2] == bc && + invert == i && colorCells) + return; + + // we got a change + bias[0] = rb; + bias[1] = gb; + bias[2] = bb; + contrast[0] = rc; + contrast[1] = gc; + contrast[2] = bc; + invert = i; + + updateColorCells(cells, cnt); + updateColorScale(); + + // special case + if ((!view[0] || !context[0].fits) && + (!view[1] || !context[1].fits) && + (!view[2] || !context[2].fits)) + return; + + int& width = colormapXM->width; + int& height = colormapXM->height; + + // create img + unsigned char* img = new unsigned char[width*height*3]; + memset(img, 0, width*height*3); + char* mk = new char[width*height]; + memset(mk, 0, width*height); + + for (int kk=0; kk<3; kk++) { + if (!view[kk] || !context[kk].fits) + continue; + + const unsigned char* table = colorScale[kk]->psColors(); + long* src = colormapData[kk]; + unsigned char* dest = img; + char* mptr = mk; + for (long jj=0; jj<height; jj++) + for (long ii=0; ii<width; ii++, src++, dest+=3, mptr++) + if (*src >= 0) { + memcpy(dest+kk, table+(*src), 1); + *mptr = 2; + } + else if (*src == -1 && *mptr < 2) + *mptr = 1; + } + + // set remainder to bg + { + unsigned char* dest = img; + char* mptr = mk; + for (long jj=0; jj<height; jj++) + for (long ii=0; ii<width; ii++, dest+=3, mptr++) + if (*mptr == 2) // good value + ; + else if (*mptr == 1) { // nan + *(dest ) = (unsigned char)nanColor->red; + *(dest+1) = (unsigned char)nanColor->green; + *(dest+2) = (unsigned char)nanColor->blue; + } + else { // bg + *(dest ) = (unsigned char)bgColor->red; + *(dest+1) = (unsigned char)bgColor->green; + *(dest+2) = (unsigned char)bgColor->blue; + } + } + + // build colormapXM + encodeTrueColor((unsigned char*)img, colormapXM); + + // clean up + if (img) + delete [] img; + if (mk) + delete [] mk; + + // XImage to Pixmap + TkPutImage(NULL, 0, display, colormapPM, widgetGC, colormapXM, + 0, 0, 0, 0, width, height); + + // Display Pixmap + Vector dd = Vector() * widgetToWindow; + XCopyArea(display, colormapPM, Tk_WindowId(tkwin), colormapGCXOR, 0, 0, + width, height, dd[0], dd[1]); + + // update panner + updatePanner(); +} + +void FrameRGB::getColorbarCmd() +{ + ostringstream str; + + str << "rgb " << fixed; + for (int ii=0; ii<3; ii++) + str << bias[ii] << ' '; + for (int ii=0; ii<3; ii++) + str << contrast[ii] << ' '; + str << invert << ' ' << ends; + + Tcl_AppendResult(interp, str.str().c_str(), NULL); +} + +void FrameRGB::getInfoCmd(const Vector& vv, Coord::InternalSystem ref, char* var) +{ + FrameBase::getInfoCmd(vv, ref, var); + if (!currentContext->cfits) + return; + + const char* array[3] = {"value,red","value,green","value,blue"}; + + SETSIGBUS + for (int ii=0; ii<3; ii++) { + + // make sure we have an image + FitsImage* sptr = context[ii].cfits; + if (!sptr) + continue; + + int mosaic = context[ii].isMosaic(); + FitsBound* params = sptr->getDataParams(context[ii].secMode()); + + do { + Vector3d rr = mapToRef3d(vv,ref); + Vector img = Vector(rr) * sptr->refToData; + + if (img[0]>=params->xmin && img[0]<params->xmax && + img[1]>=params->ymin && img[1]<params->ymax) { + + Tcl_SetVar2(interp,var,array[ii],(char*)sptr->getValue(img),0); + break; + } + else { + if (mosaic) { + sptr = sptr->nextMosaic(); + if (sptr) + params = sptr->getDataParams(context[ii].secMode()); + } + } + } + while (mosaic && sptr); + } + CLEARSIGBUS +} + +void FrameRGB::getRGBChannelCmd() +{ + switch (channel) { + case 0: + Tcl_AppendResult(interp, "red", NULL); + return; + case 1: + Tcl_AppendResult(interp, "green", NULL); + return; + case 2: + Tcl_AppendResult(interp, "blue", NULL); + return; + } +} + +void FrameRGB::getRGBSystemCmd() +{ + printCoordSystem(rgbSystem); +} + +void FrameRGB::getRGBViewCmd() +{ + for (int ii=0; ii<3; ii++) + Tcl_AppendElement(interp, view[ii] ? "1" : "0"); +} + +void FrameRGB::getTypeCmd() +{ + Tcl_AppendResult(interp, "rgb", NULL); +} + +// RGBCube FITS + +void FrameRGB::loadRGBCubeAllocCmd(const char* ch, const char* fn) +{ + unloadAllFits(); + FitsImage* img = new FitsImageFitsAlloc(&context[0], interp, + ch, fn, FitsFile::NOFLUSH, 1); + loadRGBCube(ALLOC,fn,img); +} + +void FrameRGB::loadRGBCubeAllocGZCmd(const char* ch, const char* fn) +{ + unloadAllFits(); + FitsImage* img = new FitsImageFitsAllocGZ(&context[0], interp, + ch, fn, FitsFile::NOFLUSH, 1); + loadRGBCube(ALLOCGZ,fn,img); +} + +void FrameRGB::loadRGBCubeChannelCmd(const char* ch, const char* fn) +{ + unloadAllFits(); + FitsImage* img = new FitsImageFitsChannel(&context[0], interp, + ch, fn, FitsFile::NOFLUSH, 1); + loadRGBCube(CHANNEL,fn,img); +} + +void FrameRGB::loadRGBCubeMMapCmd(const char* fn) +{ + unloadAllFits(); + FitsImage* img = new FitsImageFitsMMap(&context[0], interp, fn, 1); + loadRGBCube(MMAP,fn,img); +} + +void FrameRGB::loadRGBCubeSMMapCmd(const char* hdr, const char* fn) +{ + unloadAllFits(); + FitsImage* img = new FitsImageFitsSMMap(&context[0], interp, hdr, fn, 1); + loadRGBCube(SMMAP,fn,img); +} + +void FrameRGB::loadRGBCubeMMapIncrCmd(const char* fn) +{ + unloadAllFits(); + FitsImage* img = new FitsImageFitsMMapIncr(&context[0], interp, fn, 1); + loadRGBCube(MMAPINCR,fn,img); +} + +void FrameRGB::loadRGBCubeShareCmd(ShmType type, int id, const char* fn) +{ + unloadAllFits(); + FitsImage* img = new FitsImageFitsShare(&context[0], interp, type, id, fn, 1); + loadRGBCube(SHARE,fn,img); +} + +void FrameRGB::loadRGBCubeSShareCmd(ShmType type, int hdr, int id, + const char* fn) +{ + unloadAllFits(); + FitsImage* img = new FitsImageFitsSShare(&context[0], interp, + type, hdr, id, fn, 1); + loadRGBCube(SSHARE,fn,img); +} + +void FrameRGB::loadRGBCubeSocketCmd(int s, const char* fn) +{ + unloadAllFits(); + FitsImage* img = new FitsImageFitsSocket(&context[0], interp, + s, fn, FitsFile::FLUSH, 1); + loadRGBCube(SOCKET,fn,img); +} + +void FrameRGB::loadRGBCubeSocketGZCmd(int s, const char* fn) +{ + unloadAllFits(); + FitsImage* img = new FitsImageFitsSocketGZ(&context[0], interp, + s, fn, FitsFile::FLUSH, 1); + loadRGBCube(SOCKETGZ,fn,img); +} + +void FrameRGB::loadRGBCubeVarCmd(const char* ch, const char* fn) +{ + unloadAllFits(); + FitsImage* img = new FitsImageFitsVar(&context[0], interp, ch, fn, 1); + loadRGBCube(VAR,fn,img); +} + +// RGBImage FITS + +void FrameRGB::loadRGBImageAllocCmd(const char* ch, const char* fn) +{ + unloadAllFits(); + FitsImage* img = new FitsImageMosaicAlloc(&context[0], interp, + ch, fn, FitsFile::NOFLUSH, 1); + loadRGBImage(ALLOC,fn,img); +} + +void FrameRGB::loadRGBImageAllocGZCmd(const char* ch, const char* fn) +{ + unloadAllFits(); + FitsImage* img = new FitsImageMosaicAllocGZ(&context[0], interp, + ch, fn, FitsFile::NOFLUSH, 1); + loadRGBImage(ALLOCGZ,fn,img); +} + +void FrameRGB::loadRGBImageChannelCmd(const char* ch, const char* fn) +{ + unloadAllFits(); + FitsImage* img = new FitsImageMosaicChannel(&context[0], interp, + ch, fn, FitsFile::NOFLUSH, 1); + loadRGBImage(CHANNEL,fn,img); +} + +void FrameRGB::loadRGBImageMMapCmd(const char* fn) +{ + unloadAllFits(); + FitsImage* img = new FitsImageMosaicMMap(&context[0], interp, fn, 1); + loadRGBImage(MMAP,fn,img); +} + +void FrameRGB::loadRGBImageMMapIncrCmd(const char* fn) +{ + unloadAllFits(); + FitsImage* img = new FitsImageMosaicMMapIncr(&context[0], interp, fn, 1); + loadRGBImage(MMAPINCR,fn,img); +} + +void FrameRGB::loadRGBImageShareCmd(ShmType type, int id, const char* fn) +{ + unloadAllFits(); + FitsImage* img = new FitsImageMosaicShare(&context[0], interp, + type, id, fn, 1); + loadRGBImage(SHARE,fn,img); +} + +void FrameRGB::loadRGBImageSocketCmd(int s, const char* fn) +{ + unloadAllFits(); + FitsImage* img = new FitsImageMosaicSocket(&context[0], interp, + s, fn, FitsFile::FLUSH, 1); + loadRGBImage(SOCKET,fn,img); +} + +void FrameRGB::loadRGBImageSocketGZCmd(int s, const char* fn) +{ + unloadAllFits(); + FitsImage* img = new FitsImageMosaicSocketGZ(&context[0], interp, + s, fn, FitsFile::FLUSH, 1); + loadRGBImage(SOCKETGZ,fn,img); +} + +void FrameRGB::loadRGBImageVarCmd(const char* ch, const char* fn) +{ + unloadAllFits(); + FitsImage* img = new FitsImageMosaicVar(&context[0], interp, ch, fn, 1); + loadRGBImage(VAR,fn,img); +} + +// RGBCube Array + +void FrameRGB::loadArrayRGBCubeAllocCmd(const char* ch, const char* fn) +{ + unloadAllFits(); + FitsImage* img = new FitsImageArrAlloc(&context[0], interp, + ch, fn, FitsFile::NOFLUSH, 1); + loadRGBCube(ALLOC,fn,img); +} + +void FrameRGB::loadArrayRGBCubeAllocGZCmd(const char* ch, const char* fn) +{ + unloadAllFits(); + FitsImage* img = new FitsImageArrAllocGZ(&context[0], interp, + ch, fn, FitsFile::NOFLUSH, 1); + loadRGBCube(ALLOCGZ,fn,img); +} + +void FrameRGB::loadArrayRGBCubeChannelCmd(const char* ch, const char* fn) +{ + unloadAllFits(); + FitsImage* img = new FitsImageArrChannel(&context[0], interp, ch, fn, + FitsFile::NOFLUSH, 1); + loadRGBCube(CHANNEL,fn,img); +} + +void FrameRGB::loadArrayRGBCubeMMapCmd(const char* fn) +{ + unloadAllFits(); + FitsImage* img = new FitsImageArrMMap(&context[0], interp, fn, 1); + loadRGBCube(MMAP,fn,img); +} + +void FrameRGB::loadArrayRGBCubeMMapIncrCmd(const char* fn) +{ + unloadAllFits(); + FitsImage* img = new FitsImageArrMMapIncr(&context[0], interp, fn, 1); + loadRGBCube(MMAPINCR,fn,img); +} + +void FrameRGB::loadArrayRGBCubeShareCmd(ShmType type, int id, const char* fn) +{ + unloadAllFits(); + FitsImage* img = new FitsImageArrShare(&context[0], interp, + type, id, fn, 1); + loadRGBCube(SHARE,fn,img); +} + +void FrameRGB::loadArrayRGBCubeSocketCmd(int s, const char* fn) +{ + unloadAllFits(); + FitsImage* img = new FitsImageArrSocket(&context[0], interp, + s, fn, FitsFile::FLUSH, 1); + loadRGBCube(SOCKET,fn,img); +} + +void FrameRGB::loadArrayRGBCubeSocketGZCmd(int s, const char* fn) +{ + unloadAllFits(); + FitsImage* img = new FitsImageArrSocketGZ(&context[0], interp, + s, fn, FitsFile::FLUSH, 1); + loadRGBCube(SOCKETGZ,fn,img); +} + +void FrameRGB::loadArrayRGBCubeVarCmd(const char* ch, const char* fn) +{ + unloadAllFits(); + FitsImage* img = new FitsImageArrVar(&context[0], interp, ch, fn, 1); + loadRGBCube(VAR,fn,img); +} + +// RGBPhoto + +void FrameRGB::loadPhotoCmd(const char* ph, const char* fn) +{ + unloadAllFits(); + FitsImage* img = new FitsImagePhotoCube(&context[0], interp, ph, fn, 1); + loadRGBCube(ALLOC,fn,img); +} + +void FrameRGB::saveFitsRGBImageFileCmd(const char* fn) +{ + if (keyContext->fits) { + OutFitsFile str(fn); + saveFitsRGBImage(str); + } +} + +void FrameRGB::saveFitsRGBImageChannelCmd(const char* ch) +{ + if (keyContext->fits) { + OutFitsChannel str(interp, ch); + saveFitsRGBImage(str); + } +} + +void FrameRGB::saveFitsRGBImageSocketCmd(int ss) +{ + if (keyContext->fits) { + OutFitsSocket str(ss); + saveFitsRGBImage(str); + } +} + +void FrameRGB::saveFitsRGBCubeFileCmd(const char* fn) +{ + if (keyContext->fits) { + OutFitsFile str(fn); + saveFitsRGBCube(str); + } +} + +void FrameRGB::saveFitsRGBCubeChannelCmd(const char* ch) +{ + if (keyContext->fits) { + OutFitsChannel str(interp, ch); + saveFitsRGBCube(str); + } +} + +void FrameRGB::saveFitsRGBCubeSocketCmd(int ss) +{ + if (keyContext->fits) { + OutFitsSocket str(ss); + saveFitsRGBCube(str); + } +} + +void FrameRGB::saveArrayRGBCubeFileCmd(const char* fn, FitsFile::ArchType endian) +{ + if (keyContext->fits) { + OutFitsFile str(fn); + saveArrayRGBCube(str, endian); + } +} + +void FrameRGB::saveArrayRGBCubeChannelCmd(const char* ch, FitsFile::ArchType endian) +{ + if (keyContext->fits) { + OutFitsChannel str(interp, ch); + saveArrayRGBCube(str, endian); + } +} + +void FrameRGB::saveArrayRGBCubeSocketCmd(int ss, FitsFile::ArchType endian) +{ + if (keyContext->fits) { + OutFitsSocket str(ss); + saveArrayRGBCube(str, endian); + } +} + +void FrameRGB::savePhotoCmd(const char* ph) +{ + // need to determine size from key context + FitsImage* fits = keyContext->fits; + if (!fits) + return; + + // check size + FitsBound* params = fits->getDataParams(context->secMode()); + for (int kk=0; kk<3; kk++) { + if (!view[kk] || !context[kk].fits) + continue; + + FitsImage* ptr = context[kk].fits; + FitsBound* pptr = ptr->getDataParams(context[kk].secMode()); + if (params->xmin != pptr->xmin || params->xmax != pptr->xmax || + params->ymin != pptr->ymin || params->ymax != pptr->ymax) { + internalError("All channels need to be same size."); + return; + } + } + + // width,height + int width = params->xmax - params->xmin; + int height = params->ymax - params->ymin; + + // photo + if (*ph == '\0') { + Tcl_AppendResult(interp, "bad image name ", NULL); + return; + } + Tk_PhotoHandle photo = Tk_FindPhoto(interp, ph); + if (!photo) { + Tcl_AppendResult(interp, "bad image handle ", NULL); + return; + } + if (Tk_PhotoSetSize(interp, photo, width, height) != TCL_OK) { + Tcl_AppendResult(interp, "bad photo set size ", NULL); + return; + } + Tk_PhotoBlank(photo); + Tk_PhotoImageBlock block; + if (!Tk_PhotoGetImage(photo,&block)) { + Tcl_AppendResult(interp, "bad image block ", NULL); + return; + } + + if (block.pixelSize<4) { + Tcl_AppendResult(interp, "bad pixel size ", NULL); + return; + } + + // clear, set alpha channel + unsigned char* dest = block.pixelPtr; + for (long jj=0; jj<height; jj++) { + for (long ii=0; ii<width; ii++, dest+=block.pixelSize) { + *(dest+block.offset[0]) = 0; // red + *(dest+block.offset[1]) = 0; // green + *(dest+block.offset[2]) = 0; // blue + *(dest+block.offset[3]) = 255; // alpha + } + } + + // main loop + SETSIGBUS + + // one channel at a time + for (int kk=0; kk<3; kk++) { + if (!view[kk] || !context[kk].fits) + continue; + + // basics + int length = colorScale[kk]->size() - 1; + const unsigned char* table = colorScale[kk]->psColors(); + + // variable + FitsImage* fits = context[kk].cfits; + double ll = fits->low(); + double hh = fits->high(); + double diff = hh - ll; + + unsigned char* dest = block.pixelPtr; + for (long jj=params->ymax-1; jj>=params->ymin; jj--) { + for (long ii=params->xmin; ii<params->xmax; ii++, dest+=block.pixelSize) { + double value = fits->getValueDouble(Vector(ii,jj)); + + if (isfinite(diff) && isfinite(value)) { + if (value <= ll) + *(dest+block.offset[kk]) = table[0]; + else if (value >= hh) + *(dest+block.offset[kk]) = table[length]; + else + *(dest+block.offset[kk]) = table[(int)(((value - ll)/diff * length) + .5)]; + } + } + } + } + CLEARSIGBUS + + if (Tk_PhotoPutBlock(interp, photo, &block, 0, 0, width, height, + TK_PHOTO_COMPOSITE_SET) != TCL_OK) { + Tcl_AppendResult(interp, "bad put block ", NULL); + return; + } +} + +void FrameRGB::setRGBChannelCmd(const char* c) +{ + if (!strncmp(c,"red",3)) + channel = 0; + else if (!strncmp(c,"gre",3)) + channel = 1; + else if (!strncmp(c,"blu",3)) + channel = 2; + else + channel = 0; + + currentContext = &context[channel]; + + // execute any update callbacks + updateCBMarkers(&userMarkers); + updateCBMarkers(&catalogMarkers); + // updateCBMarkers(&analysisMarkers); + + // always update + update(BASE); +} + +void FrameRGB::setRGBSystemCmd(Coord::CoordSystem sys) +{ + rgbSystem = sys; + + // save current matrix + Matrix old[3]; + for (int ii=0; ii<3; ii++) + old[ii] = rgb[ii]; + + alignWCS(); + + // fix any contours + for (int ii=0; ii<3; ii++) { + Matrix mm = old[ii].invert() * rgb[ii]; + context[ii].updateContours(mm); + } + + update(MATRIX); +} + +void FrameRGB::setRGBViewCmd(int r, int g, int b) +{ + view[0] = r ? 1 : 0; + view[1] = g ? 1 : 0; + view[2] = b ? 1 : 0; + + update(BASE); // always update +} |