summaryrefslogtreecommitdiffstats
path: root/tksao/frame/base.C
diff options
context:
space:
mode:
authorWilliam Joye <wjoye@cfa.harvard.edu>2016-10-27 18:59:29 (GMT)
committerWilliam Joye <wjoye@cfa.harvard.edu>2016-10-27 18:59:29 (GMT)
commitd4d595fa7fb12903db9227d33d48b2b00120dbd1 (patch)
tree7d18365de0d6d1b29399b6a17c7eb01c2eb3ed49 /tksao/frame/base.C
parent949f96e29bfe0bd8710d775ce220e597064e2589 (diff)
downloadblt-d4d595fa7fb12903db9227d33d48b2b00120dbd1.zip
blt-d4d595fa7fb12903db9227d33d48b2b00120dbd1.tar.gz
blt-d4d595fa7fb12903db9227d33d48b2b00120dbd1.tar.bz2
Initial commit
Diffstat (limited to 'tksao/frame/base.C')
-rw-r--r--tksao/frame/base.C2268
1 files changed, 2268 insertions, 0 deletions
diff --git a/tksao/frame/base.C b/tksao/frame/base.C
new file mode 100644
index 0000000..22a0d9d
--- /dev/null
+++ b/tksao/frame/base.C
@@ -0,0 +1,2268 @@
+// 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 "base.h"
+#include "context.h"
+#include "fitsimage.h"
+#include "marker.h"
+#include "ps.h"
+
+#include "circle.h"
+#include "ellipse.h"
+#include "box.h"
+#include "annulus.h"
+#include "point.h"
+#include "vect.h"
+
+// Debug
+int DebugAST= 0;
+int DebugBin= 0;
+int DebugBlock= 0;
+int DebugCompress= 0;
+int DebugCrop= 0;
+int DebugGZ= 0;
+int DebugMosaic= 0;
+int DebugPerf= 0;
+int DebugRGB= 0;
+int DebugWCS= 0;
+
+// Parser Stuff
+#undef yyFlexLexer
+#define yyFlexLexer frFlexLexer
+#include <FlexLexer.h>
+
+void* frlval;
+extern int frparse(Base*, frFlexLexer*);
+
+int frlex(void* vval, frFlexLexer* ll)
+{
+ frlval = vval;
+ return ll ? ll->yylex() : 0;
+}
+
+void frerror(Base* fr, frFlexLexer* ll, const char* m)
+{
+ fr->error(m);
+ const char* cmd = ll ? ll->YYText() : (const char*)NULL;
+ if (cmd && cmd[0] != '\n') {
+ fr->error(": ");
+ fr->error(cmd);
+ }
+}
+
+// Base Member Functions
+
+Base::Base(Tcl_Interp* i, Tk_Canvas c, Tk_Item* item)
+ : Widget(i, c, item)
+{
+ nthreads_ = 8;
+
+ byteorder_ = 0;
+ bitsperpixel_ = 0;
+
+ baseXImage = NULL;
+ basePixmap = 0;
+ needsUpdate = NOUPDATE;
+ syncUpdate = 0;
+
+ currentContext = NULL;
+ keyContext = NULL;
+ keyContextSet =0;
+
+ orientation = Coord::NORMAL;
+ zoom_ = Vector(1,1);
+ rotation = 0;
+
+ rotateRotation = 0;
+
+ preservePan = 0;
+
+ panPM = 0;
+ panGCXOR = XCreateGC(display, Tk_WindowId(tkwin), 0, NULL);
+
+ rotateGCXOR = XCreateGC(display, Tk_WindowId(tkwin), 0, NULL);
+
+ pannerPixmap = 0;
+ pannerXImage = NULL;
+ pannerWidth = 0;
+ pannerHeight = 0;
+ pannerName[0] = '\0';
+ usePanner = 0;
+ pannerGC = XCreateGC(display, Tk_WindowId(tkwin), 0, NULL);
+ XSetLineAttributes(display, pannerGC, 1, LineSolid, CapButt, JoinMiter);
+
+ magnifierPixmap = 0;
+ magnifierXImage = NULL;
+ magnifierWidth = 0;
+ magnifierHeight = 0;
+ magnifierZoom_ = 4;
+ magnifierName[0] = '\0';
+ useMagnifier = 0;
+ useMagnifierGraphics = 1;
+ useMagnifierCursor = 1;
+ magnifierColorName = dupstr("white");
+
+ wcsSystem_ = Coord::WCS;
+ wcsSky_ = Coord::FK5;
+ wcsSkyFormat_ = Coord::DEGREES;
+
+ wcsAlign_ = 0;
+
+ xySystem_ = Coord::IMAGE;
+ xySky_ = Coord::FK5;
+
+ wcsOrientation = Coord::NORMAL;
+ wcsRotation = 0;
+
+ irafAlign_ =1;
+ irafOrientation_ = (Coord::Orientation)-1;
+
+ maskColorName = dupstr("red");
+ maskAlpha = 1;
+ maskMark = 1;
+
+ invert = 0;
+
+ useHighlite = 0;
+ highliteGC = XCreateGC(display, Tk_WindowId(tkwin), 0, NULL);
+ XSetLineAttributes(display, highliteGC, 2, LineSolid, CapButt, JoinMiter);
+ XSetForeground(display, highliteGC, getColor("blue"));
+
+ useCrosshair = 0;
+
+ markerEpsilon = 3;
+ showMarkers = 1;
+ showMarkersText = 1;
+ centroidAuto = 0;
+ centroidIteration = 5;
+ centroidRadius = 10;
+ preserveMarkers = 0;
+
+ markerGC = XCreateGC(display, Tk_WindowId(tkwin), 0, NULL);
+
+ markerGCXOR = XCreateGC(display, Tk_WindowId(tkwin), 0, NULL);
+ XSetForeground(display, markerGCXOR, getColor("white"));
+
+ selectGCXOR = XCreateGC(display, Tk_WindowId(tkwin), 0, NULL);
+ XSetForeground(display, selectGCXOR, getColor("white"));
+
+ grid = NULL;
+ gridGC = XCreateGC(display, Tk_WindowId(tkwin), 0, NULL);
+
+ contourGC = XCreateGC(display, Tk_WindowId(tkwin), 0, NULL);
+ XSetLineAttributes(display, contourGC, 1, LineSolid, CapButt, JoinMiter);
+
+ bgColorName = dupstr("white");
+ bgColor = getXColor("white");
+ memset(bgTrueColor_,255,4);
+
+ nanColorName = dupstr("white");
+ nanColor = getXColor("white");
+ memset(nanTrueColor_,255,4);
+
+ dlist[0] = 8;
+ dlist[1] = 3;
+
+ colorbartag =NULL;
+
+ markers = &userMarkers;
+ undoMarkers = &undoUserMarkers;
+ pasteMarkers = &pasteUserMarkers;
+ undoMarkerType = NONE;
+
+ editMarker = NULL;
+ rotateMarker = NULL;
+
+ compositeMarker = NULL;
+
+ imageToData = Translate(-.5, -.5);
+ dataToImage = Translate( .5, .5);
+
+ inverseScale = NULL;
+}
+
+Base::~Base()
+{
+ if (basePixmap)
+ Tk_FreePixmap(display, basePixmap);
+
+ if (baseXImage)
+ XDestroyImage(baseXImage);
+
+ if (pannerPixmap)
+ Tk_FreePixmap(display, pannerPixmap);
+
+ if (pannerXImage)
+ XDestroyImage(pannerXImage);
+
+ if (panPM)
+ Tk_FreePixmap(display, panPM);
+
+ if (panGCXOR)
+ XFreeGC(display, panGCXOR);
+
+ if (rotateGCXOR)
+ XFreeGC(display, rotateGCXOR);
+
+ if (pannerGC)
+ XFreeGC(display, pannerGC);
+
+ if (magnifierPixmap)
+ Tk_FreePixmap(display, magnifierPixmap);
+
+ if (magnifierXImage)
+ XDestroyImage(magnifierXImage);
+
+ if (highliteGC)
+ XFreeGC(display, highliteGC);
+
+ if (maskColorName)
+ delete [] maskColorName;
+
+ if (markerGC)
+ XFreeGC(display, markerGC);
+
+ if (markerGCXOR)
+ XFreeGC(display, markerGCXOR);
+
+ if (selectGCXOR)
+ XFreeGC(display, selectGCXOR);
+
+ if (grid)
+ delete grid;
+
+ if (gridGC)
+ XFreeGC(display, gridGC);
+
+ if (contourGC)
+ XFreeGC(display, contourGC);
+
+ if (bgColorName)
+ delete [] bgColorName;
+
+ if (nanColorName)
+ delete [] nanColorName;
+
+ if (colorbartag)
+ delete [] colorbartag;
+
+ if (magnifierColorName)
+ delete [] magnifierColorName;
+
+ if (inverseScale)
+ delete inverseScale;
+
+}
+
+void Base::alignIRAF()
+{
+ if (irafAlign_) {
+ switch (irafOrientation_) {
+ case Coord::NORMAL:
+ irafMatrix_.identity();
+ break;
+ case Coord::XX:
+ irafMatrix_ = FlipX();
+ break;
+ case Coord::YY:
+ irafMatrix_ = FlipY();
+ break;
+ case Coord::XY:
+ irafMatrix_ = FlipXY();
+ break;
+ default:
+ irafMatrix_.identity();
+ }
+ }
+ else
+ irafMatrix_.identity();
+}
+
+void Base::alignWCS()
+{
+ if (!wcsAlign_ || !context->cfits || !hasWCS(wcsSystem_)) {
+ wcsOrientation = Coord::NORMAL;
+ wcsOrientationMatrix.identity();
+ wcsRotation = 0;
+ return;
+ }
+
+ calcAlignWCS(context->cfits, wcsSystem_, wcsSky_,
+ &wcsOrientation, &wcsOrientationMatrix, &wcsRotation);
+}
+
+void Base::alignWCS(Coord::CoordSystem sys, Coord::SkyFrame sky)
+{
+ if (!wcsAlign_ || !context->cfits || !hasWCS(sys)) {
+ wcsOrientation = Coord::NORMAL;
+ wcsOrientationMatrix.identity();
+ wcsRotation = 0;
+ return;
+ }
+
+ calcAlignWCS(context->cfits, sys, sky,
+ &wcsOrientation, &wcsOrientationMatrix, &wcsRotation);
+}
+
+void Base::alignWCS(FitsImage* ptr, Coord::CoordSystem sys)
+{
+ if (!wcsAlign_ || !ptr || !context->cfits || !hasWCS(wcsSystem_)) {
+ wcsOrientation = Coord::NORMAL;
+ wcsOrientationMatrix.identity();
+ wcsRotation = 0;
+ return;
+ }
+
+ calcAlignWCS(ptr, context->cfits, sys, wcsSystem_, wcsSky_,
+ &wcsOrientation, &wcsOrientationMatrix, &wcsRotation, &zoom_);
+}
+
+void Base::calcAlignWCS(FitsImage* fits1,
+ Coord::CoordSystem sys1, Coord::SkyFrame sky,
+ Coord::Orientation* orientation, Matrix* oo,
+ double* rotation)
+{
+ // init
+ *orientation = Coord::NORMAL;
+ oo->identity();
+ *rotation = 0;
+
+ if (!fits1 || !fits1->hasWCS(sys1))
+ return;
+
+ // orientation
+ *orientation = fits1->getWCSOrientation(sys1,sky);
+ switch (*orientation) {
+ case Coord::NORMAL:
+ oo->identity();
+ break;
+ case Coord::XX:
+ *oo = FlipX();
+ break;
+ default:
+ // na
+ break;
+ }
+
+ // rotation
+ switch (*orientation) {
+ case Coord::NORMAL:
+ *rotation = fits1->getWCSRotation(sys1,sky);
+ break;
+ case Coord::XX:
+ *rotation = -fits1->getWCSRotation(sys1,sky);
+ break;
+ default:
+ // na
+ break;
+ }
+}
+
+void Base::calcAlignWCS(FitsImage* fits1, FitsImage* fits2,
+ Coord::CoordSystem sys1, Coord::CoordSystem sys2,
+ Coord::SkyFrame sky,
+ Coord::Orientation* orientation, Matrix* oo,
+ double* rotation, Vector* zoom)
+{
+ // init
+ *orientation = Coord::NORMAL;
+ oo->identity();
+ *rotation = 0;
+
+ if ((!fits1 || !fits2) ||
+ (fits1 == fits2) ||
+ !(fits1->hasWCS(sys1)) ||
+ !(fits2->hasWCS(sys2)))
+ return;
+
+ Vector org1 = fits1->center();
+ Vector orval1 = fits1->pix2wcs(org1,sys1,sky);
+
+ // orientation
+ *orientation = fits2->getWCSOrientation(sys2,sky);
+ switch (*orientation) {
+ case Coord::NORMAL:
+ oo->identity();
+ break;
+ case Coord::XX:
+ *oo = FlipX();
+ break;
+ default:
+ // na
+ break;
+ }
+
+ // rotation
+ Vector orpix = fits2->wcs2pix(orval1, sys2, sky);
+ Vector delta = fits2->getWCScdelt(sys2).abs();
+ Vector npix =
+ fits2->wcs2pix(Vector(orval1[0],orval1[1]+delta[1]),sys2,sky);
+ Vector north = (npix-orpix).normalize();
+ Vector epix =
+ fits2->wcs2pix(Vector(orval1[0]+delta[0],orval1[1]),sys2,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)) {
+ *rotation = 0;
+ *orientation = Coord::NORMAL;
+ oo->identity();
+ return;
+ }
+
+ switch (*orientation) {
+ case Coord::NORMAL:
+ *rotation = -(north.angle()-M_PI_2);
+ break;
+ case Coord::XX:
+ *rotation = (north.angle()-M_PI_2);
+ break;
+ default:
+ // na
+ break;
+ }
+
+ // zoom
+ Vector cd1 = fits1->getWCScdelt(sys1);
+ Vector cd2 = fits2->getWCScdelt(sys2);
+ *zoom = Vector((*zoom)[0]/fabs(cd1[0]/cd2[0]),
+ (*zoom)[1]/fabs(cd1[1]/cd2[1]));
+}
+
+Matrix Base::calcAlignWCS(FitsImage* fits1, FitsImage* fits2,
+ Coord::CoordSystem sys1, Coord::CoordSystem sys2,
+ Coord::SkyFrame sky)
+{
+ if ((!fits1 || !fits2) ||
+ (fits1 == fits2) ||
+ !(fits1->hasWCS(sys1)) ||
+ !(fits2->hasWCS(sys2)))
+ return Matrix();
+
+ Vector org1 = fits1->center();
+ Vector orval1 = fits1->pix2wcs(org1,sys1,sky);
+
+ Vector org2 = fits2->center();
+ Vector orval2 = fits2->pix2wcs(org2,sys2,sky);
+
+ // orientation
+ Coord::Orientation orientation =Coord::NORMAL;
+ Coord::Orientation o1 = fits1->getWCSOrientation(sys1,sky);
+ Coord::Orientation o2 = fits2->getWCSOrientation(sys2,sky);
+ {
+ switch (o1) {
+ case Coord::NORMAL:
+ {
+ switch (o2) {
+ case Coord::NORMAL:
+ orientation = Coord::NORMAL;
+ break;
+ case Coord::XX:
+ orientation = Coord::XX;
+ break;
+ default:
+ // na
+ break;
+ }
+ }
+ break;
+ case Coord::XX:
+ {
+ switch (o2) {
+ case Coord::NORMAL:
+ orientation = Coord::XX;
+ break;
+ case Coord::XX:
+ orientation = Coord::NORMAL;
+ break;
+ default:
+ // na
+ break;
+ }
+ }
+ break;
+ default:
+ // na
+ break;
+ }
+ }
+
+ // zoom
+ Vector zoom =Vector(1,1);
+ {
+ Vector cd1 = fits1->getWCScdelt(sys1);
+ Vector cd2 = fits2->getWCScdelt(sys2);
+ zoom = Vector(cd2[0]/cd1[0], cd2[1]/cd1[1]).abs();
+ }
+
+ // rotation
+ double rotation =0;
+ {
+ double rr1=0;
+ {
+ Vector orpix = fits1->wcs2pix(orval1, sys1, sky);
+ Vector delta = fits1->getWCScdelt(sys1).abs();
+ Vector npix =
+ fits1->wcs2pix(Vector(orval1[0],orval1[1]+delta[1]),sys1,sky);
+ Vector north = (npix-orpix).normalize();
+ Vector epix =
+ fits1->wcs2pix(Vector(orval1[0]+delta[0],orval1[1]),sys1,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 Matrix();
+
+ switch (o1) {
+ case Coord::NORMAL:
+ rr1 = -(north.angle()-M_PI_2);
+ break;
+ case Coord::XX:
+ rr1 = (north.angle()-M_PI_2);
+ break;
+ default:
+ // na
+ break;
+ }
+ }
+
+ double rr2 =0;
+ {
+ Vector orpix = fits2->wcs2pix(orval1, sys2, sky);
+ Vector delta = fits2->getWCScdelt(sys2).abs();
+ Vector npix =
+ fits2->wcs2pix(Vector(orval1[0],orval1[1]+delta[1]),sys2,sky);
+ Vector north = (npix-orpix).normalize();
+ Vector epix =
+ fits2->wcs2pix(Vector(orval1[0]+delta[0],orval1[1]),sys2,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 Matrix();
+
+ switch (o2) {
+ case Coord::NORMAL:
+ rr2 = -(north.angle()-M_PI_2);
+ break;
+ case Coord::XX:
+ rr2 = north.angle()-M_PI_2;
+ break;
+ default:
+ // na
+ break;
+ }
+ }
+
+ switch (o1) {
+ case Coord::NORMAL:
+ rotation = rr1-rr2;
+ break;
+ case Coord::XX:
+ rotation = -(rr1-rr2);
+ break;
+ default:
+ // na
+ break;
+ }
+ }
+
+ // origin
+ Vector origin;
+ {
+ Vector orpix1 = fits1->wcs2pix(orval2,sys1,sky) * imageToData;
+ Vector orpix2 = fits2->wcs2pix(orval2,sys2,sky) * imageToData;
+ origin = orpix1 - orpix2;
+ }
+
+ // matrix
+ {
+ Matrix flip;
+ switch (orientation) {
+ case Coord::NORMAL:
+ break;
+ case Coord::XX:
+ flip = FlipX();
+ break;
+ default:
+ // na
+ break;
+ }
+
+ Vector orpix2 = fits2->wcs2pix(orval2,sys2,sky) * imageToData;
+
+ return
+ Translate(-orpix2) *
+ flip *
+ Scale(zoom) *
+ Rotate(rotation) *
+ Translate(orpix2) *
+ Translate(origin);
+ }
+}
+
+double Base::calcZoom(Vector src, Vector dest)
+{
+ // we need to calculate the width and height of the rotated image
+ // so we can derived a zoom factor to shrink it to fit the requested size
+
+ Vector cc = src/2.;
+
+ Vector ll;
+ Vector lr(src[0],0);
+ Vector ur(src);
+ Vector ul(0,src[1]);
+
+ Matrix mm = Translate(-cc) * Rotate(wcsRotation) * Rotate(rotation);
+
+ BBox bb(ll*mm);
+ bb.bound(lr*mm);
+ bb.bound(ur*mm);
+ bb.bound(ul*mm);
+
+ Vector bs = bb.size();
+ double r0 = dest[0]/bs[0];
+ double r1 = dest[1]/bs[1];
+
+ return r0>r1 ? r1:r0;
+}
+
+void Base::centerImage()
+{
+ if (!keyContext->fits) {
+ cursor = Vector();
+ return;
+ }
+
+ // This is here because we need mapToRef to be up-to-date
+ updateMatrices();
+ updatePannerMatrices();
+
+ // imageCenter is in IMAGE coords
+ Vector aa = imageCenter(keyContext->secMode());
+ // always center to center of pixel, even for even sized image
+ Vector bb = (aa*Translate(.5,.5)).floor();
+ // cursor is in REF coords
+ cursor = keyContext->fits->mapToRef(bb,Coord::IMAGE,Coord::FK5);
+}
+
+void Base::coordToTclArray(FitsImage* ptr, const Vector3d& vv,
+ Coord::CoordSystem out,
+ const char* var, const char* base)
+{
+ Vector rr = ptr->mapFromRef(vv, out);
+ doubleToTclArray(rr[0], var, base, "x");
+ doubleToTclArray(rr[1], var, base, "y");
+}
+
+void Base::coord3ToTclArray(FitsImage* ptr, const Vector3d& vv,
+ Coord::CoordSystem out,
+ const char* var, const char* base)
+{
+ double ss = ptr->mapFromRef3axis(((Vector3d&)vv)[2],out,2);
+ doubleToTclArray(ss, var, base, "z");
+}
+
+int Base::doRender()
+{
+ return context->cfits ? 1 : 0;
+}
+
+void Base::doubleToTclArray(double d, const char* var,
+ const char* base, const char* mod)
+{
+ ostringstream str;
+ str << base << "," << mod << ends;
+
+ ostringstream vstr;
+ vstr << fixed << setw(9) << setprecision(3) << d << ends;
+ Tcl_SetVar2(interp, (char*)var, str.str().c_str(), vstr.str().c_str(), 0);
+}
+
+FitsImage* Base::findFits()
+{
+ return keyContext->fits;
+}
+
+FitsImage* Base::findFits(Coord::CoordSystem sys, const Vector& vv)
+{
+ switch (sys) {
+ case Coord::IMAGE:
+ case Coord::PHYSICAL:
+ case Coord::DETECTOR:
+ case Coord::AMPLIFIER:
+ return findFits(vv);
+ default:
+ if (keyContext->fits && keyContext->fits->hasWCSCel(sys))
+ return keyContext->fits;
+ else
+ return findFits(vv);
+ }
+}
+
+FitsImage* Base::findFits(const Vector& vv)
+{
+ FitsImage* ptr = keyContext->fits;
+ while (ptr) {
+ Vector img = vv * ptr->refToData;
+ FitsBound* params = ptr->getDataParams(currentContext->secMode());
+ if (img[0]>=params->xmin && img[0]<params->xmax &&
+ img[1]>=params->ymin && img[1]<params->ymax)
+ return ptr;
+ ptr = ptr->nextMosaic();
+ }
+ return keyContext->fits;
+}
+
+FitsImage* Base::findFits(int which)
+{
+ FitsImage* ptr = keyContext->fits;
+ for (int ii=1; ii<which; ii++)
+ if (ptr)
+ ptr = ptr->nextMosaic();
+ return (ptr ? ptr : keyContext->fits);
+}
+
+int Base::findFits(FitsImage* p)
+{
+ FitsImage* ptr = keyContext->fits;
+ int rr = 0;
+ while (ptr) {
+ rr++;
+ if (ptr == p)
+ return rr;
+ ptr = ptr->nextMosaic();
+ }
+ return rr;
+}
+
+FitsImage* Base::findAllFits(int which)
+{
+ // modified for medatacube
+ FitsImage* rr = NULL;
+ FitsImage* ptr = currentContext->fits;
+ while (ptr && which) {
+ FitsImage* sptr = ptr;
+ while (sptr && which) {
+ which--;
+ if (!which) {
+ rr = sptr;
+ break;
+ }
+ sptr = sptr->nextSlice();
+ }
+ ptr = ptr->nextMosaic();
+ }
+
+ return rr;
+}
+
+int Base::fitsCount()
+{
+ return currentContext->fitsCount();
+}
+
+void Base::getInfoClearName(char* var)
+{
+ Tcl_SetVar2(interp,var,"filename","",0);
+ Tcl_SetVar2(interp,var,"object","",0);
+ Tcl_SetVar2(interp,var,"min","",0);
+ Tcl_SetVar2(interp,var,"max","",0);
+ Tcl_SetVar2(interp,var,"low","",0);
+ Tcl_SetVar2(interp,var,"high","",0);
+}
+
+void Base::getInfoClearValue(char* var)
+{
+ Tcl_SetVar2(interp,var,"value","",0);
+ Tcl_SetVar2(interp,var,"value,red","",0);
+ Tcl_SetVar2(interp,var,"value,green","",0);
+ Tcl_SetVar2(interp,var,"value,blue","",0);
+
+ Tcl_SetVar2(interp,var,"image,x","",0);
+ Tcl_SetVar2(interp,var,"image,y","",0);
+ Tcl_SetVar2(interp,var,"image,z","",0);
+ Tcl_SetVar2(interp,var,"physical,x","",0);
+ Tcl_SetVar2(interp,var,"physical,y","",0);
+ Tcl_SetVar2(interp,var,"physical,z","",0);
+ Tcl_SetVar2(interp,var,"amplifier,x","",0);
+ Tcl_SetVar2(interp,var,"amplifier,y","",0);
+ Tcl_SetVar2(interp,var,"amplifier,z","",0);
+ Tcl_SetVar2(interp,var,"detector,x","",0);
+ Tcl_SetVar2(interp,var,"detector,y","",0);
+ Tcl_SetVar2(interp,var,"detector,z","",0);
+}
+
+void Base::getInfoClearWCS(char* var)
+{
+ for (int ii=0; ii<MULTWCS; ii++) {
+ char buf[64];
+ char ww = !ii ? '\0' : '`'+ii;
+ Tcl_SetVar2(interp,var,varcat(buf,(char*)"wcs",ww,(char*)",x"),"",0);
+ Tcl_SetVar2(interp,var,varcat(buf,(char*)"wcs",ww,(char*)",y"),"",0);
+ Tcl_SetVar2(interp,var,varcat(buf,(char*)"wcs",ww,(char*)",z"),"",0);
+ Tcl_SetVar2(interp,var,varcat(buf,(char*)"wcs",ww,(char*)",sys"),"",0);
+ }
+}
+
+void Base::getInfoWCS(char* var, const Vector3d& rr, FitsImage* ptr,
+ FitsImage* sptr)
+{
+ Vector img = Vector(rr) * sptr->refToData;
+
+ for (int ii=0; ii<MULTWCS; ii++) {
+ char buf[64];
+ char ww = !ii ? '\0' : '`'+ii;
+ Coord::CoordSystem www = (Coord::CoordSystem)(Coord::WCS+ii);
+
+ if (hasWCS(www)) {
+ char buff[128];
+ Vector uu = img * dataToImage;
+ sptr->pix2wcs(uu, www, wcsSky_, wcsSkyFormat_, buff);
+
+ int argc;
+ const char** argv;
+ Tcl_SplitList(interp, buff, &argc, &argv);
+
+ if (argc > 0 && argv && argv[0])
+ Tcl_SetVar2(interp,var,varcat(buf,(char*)"wcs",ww,(char*)",x"),argv[0],0);
+ else
+ Tcl_SetVar2(interp,var,varcat(buf,(char*)"wcs",ww,(char*)",x"),"",0);
+ if (argc > 1 && argv && argv[1])
+ Tcl_SetVar2(interp,var,varcat(buf,(char*)"wcs",ww,(char*)",y"),argv[1],0);
+ else
+ Tcl_SetVar2(interp,var,varcat(buf,(char*)"wcs",ww,(char*)",y"),"",0);
+ // use first slice
+ coord3ToTclArray(ptr,rr,www,var,"wcs");
+
+ char* wcsname = (char*)sptr->getWCSName(www);
+ if (wcsname)
+ Tcl_SetVar2(interp,var,varcat(buf,(char*)"wcs",ww,(char*)",sys"),wcsname,0);
+ else if (argc > 2 && argv && argv[2])
+ Tcl_SetVar2(interp,var,varcat(buf,(char*)"wcs",ww,(char*)",sys"),argv[2],0);
+ else
+ Tcl_SetVar2(interp,var,varcat(buf,(char*)"wcs",ww,(char*)",sys"),"",0);
+
+ Tcl_Free((char*)argv);
+ }
+ else {
+ Tcl_SetVar2(interp,var,varcat(buf,(char*)"wcs",ww,(char*)",x"),"",0);
+ Tcl_SetVar2(interp,var,varcat(buf,(char*)"wcs",ww,(char*)",y"),"",0);
+ Tcl_SetVar2(interp,var,varcat(buf,(char*)"wcs",ww,(char*)",z"),"",0);
+ Tcl_SetVar2(interp,var,varcat(buf,(char*)"wcs",ww,(char*)",sys"),"",0);
+ }
+ }
+}
+
+int Base::hasATMV()
+{
+ return currentContext->cfits && currentContext->cfits->hasATMV();
+}
+
+int Base::hasContour()
+{
+ return currentContext->hasContour();
+}
+
+int Base::hasContourAux()
+{
+ return currentContext->hasContourAux();
+}
+
+int Base::hasDTMV()
+{
+ return currentContext->cfits && currentContext->cfits->hasDTMV();
+}
+
+int Base::hasLTMV()
+{
+ return currentContext->cfits && currentContext->cfits->hasLTMV();
+}
+
+int Base::hasWCS(Coord::CoordSystem sys)
+{
+ return currentContext->cfits && currentContext->cfits->hasWCS(sys);
+}
+
+int Base::hasWCSEqu(Coord::CoordSystem sys)
+{
+ return currentContext->cfits && currentContext->cfits->hasWCSEqu(sys);
+}
+
+int Base::hasWCSCel(Coord::CoordSystem sys)
+{
+ return currentContext->cfits && currentContext->cfits->hasWCSCel(sys);
+}
+
+int Base::hasWCSx(Coord::CoordSystem sys)
+{
+ return currentContext->cfits && currentContext->cfits->hasWCSx(sys,2);
+}
+
+Vector Base::imageCenter(FrScale::SecMode mode)
+{
+ return imageBBox(mode).center();
+}
+
+Vector Base::imageSize(FrScale::SecMode mode)
+{
+ return imageBBox(mode).size();
+}
+
+BBox Base::imageBBox(FrScale::SecMode mode)
+{
+ // returns imageBBox in IMAGE coords
+ // params are in DATA coords and extends edge to edge
+ BBox rr;
+ int first=1;
+ FitsImage* ptr = context->fits;
+ while (ptr) {
+ FitsBound* params = ptr->getDataParams(mode);
+ Matrix mm = ptr->wcsToRef() * 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;
+}
+
+int Base::isIIS()
+{
+ return 0;
+}
+
+int Base::isCube()
+{
+ return currentContext->isCube();
+}
+
+int Base::isBinTable()
+{
+ return (currentContext->fits && currentContext->fits->isBinTable()) ? 1 : 0;
+}
+
+int Base::isMosaic()
+{
+ return currentContext->isMosaic();
+}
+
+FitsImage* Base::isInFits(const Vector& vv, Coord::InternalSystem ref, Vector* rv)
+{
+ Vector ss = mapToRef(vv,ref);
+ FitsImage* ptr = currentContext->fits;
+
+ while (ptr) {
+ Vector rr = ss * ptr->refToData;
+ FitsBound* params = ptr->getDataParams(currentContext->secMode());
+
+ if (rr[0]>=params->xmin && rr[0]<params->xmax &&
+ rr[1]>=params->ymin && rr[1]<params->ymax) {
+ if (rv)
+ *rv = rr;
+ return ptr;
+ }
+ ptr = ptr->nextMosaic();
+ }
+
+ return NULL;
+}
+
+FitsImage* Base::isInCFits(const Vector& vv, Coord::InternalSystem ref, Vector* rv)
+{
+ Vector ss = mapToRef(vv,ref);
+ FitsImage* ptr = currentContext->cfits;
+
+ while (ptr) {
+ Vector rr = ss * ptr->refToData;
+ FitsBound* params = ptr->getDataParams(currentContext->secMode());
+
+ if (rr[0]>=params->xmin && rr[0]<params->xmax &&
+ rr[1]>=params->ymin && rr[1]<params->ymax) {
+ if (rv)
+ *rv = rr;
+ return ptr;
+ }
+ ptr = ptr->nextMosaic();
+ }
+
+ return NULL;
+}
+
+void Base::invalidPixmap()
+{
+ Widget::invalidPixmap();
+
+ if (basePixmap)
+ Tk_FreePixmap(display, basePixmap);
+ basePixmap = 0;
+
+ if (baseXImage)
+ XDestroyImage(baseXImage);
+ baseXImage = NULL;
+
+ needsUpdate = MATRIX;
+}
+
+Coord::Orientation Base::IRAFOrientation(Coord::Orientation oo)
+{
+ if (irafOrientation_ == (Coord::Orientation)-1) {
+ irafOrientation_ = oo;
+ alignIRAF();
+ }
+
+ return irafOrientation_;
+}
+
+int Base::parse(istringstream& istr)
+{
+ result = TCL_OK;
+ frFlexLexer* ll = new frFlexLexer(&istr);
+ frparse(this, ll);
+ delete ll;
+
+ return result;
+}
+
+int Base::postscriptProc(int prepass)
+{
+ if (!visible)
+ return TCL_OK;
+
+ if (prepass)
+ return TCL_OK;
+
+ ps();
+
+ // Markers & Contours & Grids clip path
+ ostringstream str;
+ str << psOrigin() << ' '
+ << options->width << ' ' << options->height
+ << " rectclip" << endl << ends;
+ Tcl_AppendResult(interp, str.str().c_str(), NULL);
+
+ switch (psLevel) {
+ case 1:
+ switch (psColorSpace) {
+ case BW:
+ case GRAY:
+ if (grid)
+ grid->ps(GRAY);
+
+ currentContext->contourPS(GRAY);
+
+ if (showMarkers) {
+ psMarkers(&catalogMarkers, GRAY);
+ psMarkers(&userMarkers, GRAY);
+ }
+ // psMarkers(&analysisMarkers, GRAY);
+
+ psCrosshair(GRAY);
+ psGraphics(GRAY);
+
+ break;
+ case RGB:
+ case CMYK:
+ if (grid)
+ grid->ps(RGB);
+
+ currentContext->contourPS(RGB);
+
+ if (showMarkers) {
+ psMarkers(&catalogMarkers, RGB);
+ psMarkers(&userMarkers, RGB);
+ }
+ // psMarkers(&analysisMarkers, RGB);
+
+ psCrosshair(RGB);
+ psGraphics(RGB);
+
+ break;
+ }
+ break;
+ case 2:
+ case 3:
+ if (grid)
+ grid->ps(psColorSpace);
+
+ currentContext->contourPS(psColorSpace);
+
+ if (showMarkers) {
+ psMarkers(&catalogMarkers, psColorSpace);
+ psMarkers(&userMarkers, psColorSpace);
+ }
+ // psMarkers(&analysisMarkers, psColorSpace);
+
+ psCrosshair(psColorSpace);
+ psGraphics(psColorSpace);
+
+ break;
+ }
+
+ return TCL_OK;
+}
+
+void Base::printCoordSystem(Coord::CoordSystem sys)
+{
+ Tcl_AppendResult(interp, coord.coordSystemStr(sys), NULL);
+}
+
+void Base::printDouble(double d)
+{
+ ostringstream str;
+ str << d << ends;
+ Tcl_AppendResult(interp, str.str().c_str(), NULL);
+}
+
+void Base::printInteger(int i)
+{
+ ostringstream str;
+ str << i << ends;
+ Tcl_AppendResult(interp, str.str().c_str(), NULL);
+}
+
+void Base::printSkyFrame(Coord::SkyFrame sky)
+{
+ Tcl_AppendResult(interp, coord.skyFrameStr(sky), NULL);
+}
+
+void Base::printSkyFormat(Coord::SkyFormat format)
+{
+ Tcl_AppendResult(interp, coord.skyFormatStr(format), NULL);
+}
+
+void Base::printSkyDist(Coord::SkyDist dist)
+{
+ Tcl_AppendResult(interp, coord.skyDistStr(dist), NULL);
+}
+
+void Base::printFromRef(FitsImage* ptr, const Vector& vv,
+ Coord::CoordSystem sys, Coord::SkyFrame sky,
+ Coord::SkyFormat format)
+{
+ ostringstream str;
+ ptr->listFromRef(str, vv, sys, sky, format);
+ str << ends;
+ Tcl_AppendResult(interp, str.str().c_str(), NULL);
+}
+
+void Base::printLenFromRef(FitsImage* ptr, double dd,
+ Coord::CoordSystem sys, Coord::SkyDist dist)
+{
+ ostringstream str;
+ ptr->listLenFromRef(str, dd, sys, dist);
+ str << ends;
+ Tcl_AppendResult(interp, str.str().c_str(), NULL);
+}
+
+void Base::printLenFromRef(FitsImage* ptr, const Vector& vv,
+ Coord::CoordSystem sys, Coord::SkyDist dist)
+{
+ ostringstream str;
+ ptr->listLenFromRef(str, vv, sys, dist);
+ str << ends;
+ Tcl_AppendResult(interp, str.str().c_str(), NULL);
+}
+
+void Base::printDistFromRef(FitsImage* ptr,
+ const Vector& vv1, const Vector& vv2,
+ Coord::CoordSystem sys, Coord::SkyDist dist)
+{
+ ostringstream str;
+ ptr->listDistFromRef(str, vv1, vv2, sys, dist);
+ str << ends;
+ Tcl_AppendResult(interp, str.str().c_str(), NULL);
+}
+
+void Base::ps()
+{
+
+ if (!currentContext->fits)
+ return;
+
+ Tcl_AppendResult(interp, "gsave\n", NULL);
+
+ double ss = psResolution / 96.;
+ int ww = options->width*ss;
+ int hh = options->height*ss;
+
+ ostringstream str;
+
+ str << psOrigin() << " translate " << 1/ss << ' ' << 1/ss << " scale" << endl;
+ switch (psLevel) {
+ case 1:
+ {
+ psHead1(str, ww, hh);
+ NoCompressAsciiHex filter(psLevel);
+ psImage(str, filter, ww, hh, ss);
+ }
+ break;
+ case 2:
+ {
+ psHead2(str, ww, hh, "RunLength", "ASCII85");
+ RLEAscii85 filter(psLevel);
+ psImage(str, filter, ww, hh, ss);
+ }
+ break;
+ case 3:
+ {
+ psHead2(str, ww, hh, "Flate", "ASCII85");
+ GZIPAscii85 filter(psLevel);
+ psImage(str, filter, ww, hh, ss);
+ }
+ break;
+ }
+
+ str << ends;
+ Tcl_AppendResult(interp, str.str().c_str(), NULL);
+
+ Tcl_AppendResult(interp, "grestore\n", NULL);
+}
+
+void Base::psCrosshair(PSColorSpace mode)
+{
+ if (!useCrosshair)
+ return;
+
+ Vector rr = mapFromRef(crosshair, Coord::WIDGET);
+ Vector aa = Vector(rr[0],1) * widgetToCanvas;
+ Vector bb = Vector(rr[0],options->height) * widgetToCanvas;
+ Vector cc = Vector(1,rr[1]) * widgetToCanvas;
+ Vector dd = Vector(options->width,rr[1]) * widgetToCanvas;
+
+ {
+ ostringstream str;
+ switch ((PSColorSpace)mode) {
+ case BW:
+ case GRAY:
+ psColorGray(getXColor("green"), str);
+ str << " setgray";
+ break;
+ case RGB:
+ psColorRGB(getXColor("green"), str);
+ str << " setrgbcolor";
+ break;
+ case CMYK:
+ psColorCMYK(getXColor("green"), str);
+ str << " setcmykcolor";
+ break;
+ }
+ str << endl << ends;
+ Tcl_AppendResult(interp, str.str().c_str(), NULL);
+ }
+
+ {
+ ostringstream str;
+ str << 1 << " setlinewidth" << endl << ends;
+ Tcl_AppendResult(interp, str.str().c_str(), NULL);
+ }
+
+ {
+ ostringstream str;
+
+ str << "newpath "
+ << aa.TkCanvasPs(canvas) << ' '
+ << "moveto "
+ << bb.TkCanvasPs(canvas) << ' '
+ << "lineto stroke" << endl
+ << "newpath "
+ << cc.TkCanvasPs(canvas) << ' '
+ << "moveto "
+ << dd.TkCanvasPs(canvas) << ' '
+ << "lineto stroke" << endl << ends;
+ Tcl_AppendResult(interp, str.str().c_str(), NULL);
+ }
+}
+
+void Base::psImage(ostream& str, Filter& filter,
+ int width, int height, float scale)
+{
+ pushPSMatrices(scale, width, height);
+
+ unsigned char* img = fillImage(width, height, Coord::PS);
+ if (!img)
+ return;
+ unsigned char* ptr = img;
+ for (long jj=0; jj<height; jj++) {
+ for (long ii=0; ii<width; ii++, ptr+=3) {
+ unsigned char red = ptr[0];
+ unsigned char green = ptr[1];
+ unsigned char blue = ptr[2];
+
+ switch (psColorSpace) {
+ case BW:
+ case GRAY:
+ filter << RGB2Gray(red, green, blue);
+ break;
+ case RGB:
+ filter << red << green << blue;
+ break;
+ case CMYK:
+ {
+ unsigned char cyan, magenta, yellow, black;
+ RGB2CMYK(red, green, blue, &cyan, &magenta, &yellow, &black);
+ filter << cyan << magenta << yellow << black;
+ }
+ break;
+ }
+ str << filter;
+ }
+ }
+
+ filter.flush(str);
+
+ if (img)
+ delete [] img;
+}
+
+Matrix Base::psMatrix(float scale, int width, int height)
+{
+ Matrix userToPS =
+ wcsOrientationMatrix * // flip x/y axis about center
+ orientationMatrix * // flip x/y axis about cursor position
+ Rotate(wcsRotation) * // rotate about center position
+ Rotate(rotation) * // rotate about cursor position
+
+ Scale(zoom_) * // scale about cursor position
+ Scale(scale) *
+ FlipY() *
+ Translate(Vector(width,height)/2.);
+
+ return refToUser * userToPS;
+}
+
+void Base::pushMatrices()
+{
+ Matrix rgbToRef;
+
+ FitsImage* ptr = context->fits;
+ while (ptr) {
+ FitsImage* sptr = ptr;
+ while (sptr) {
+ sptr->updateMatrices(rgbToRef, refToUser, userToWidget,
+ widgetToCanvas, canvasToWindow);
+ sptr = sptr->nextSlice();
+ }
+ ptr = ptr->nextMosaic();
+ }
+}
+
+void Base::pushMagnifierMatrices()
+{
+ FitsImage* ptr = context->fits;
+ while (ptr) {
+ FitsImage* sptr = ptr;
+ while (sptr) {
+ sptr->updateMagnifierMatrices(refToMagnifier);
+ sptr = sptr->nextSlice();
+ }
+ ptr = ptr->nextMosaic();
+ }
+}
+
+void Base::pushPannerMatrices()
+{
+ FitsImage* ptr = context->fits;
+ while (ptr) {
+ FitsImage* sptr = ptr;
+ while (sptr) {
+ sptr->updatePannerMatrices(refToPanner);
+ sptr = sptr->nextSlice();
+ }
+ ptr = ptr->nextMosaic();
+ }
+}
+
+void Base::pushPSMatrices(float scale, int width, int height)
+{
+ Matrix mx = psMatrix(scale, width, height);
+
+ FitsImage* ptr = context->fits;
+ while (ptr) {
+ FitsImage* sptr = ptr;
+ while (sptr) {
+ sptr->updatePS(mx);
+ sptr = sptr->nextSlice();
+ }
+ ptr = ptr->nextMosaic();
+ }
+}
+
+void Base::reset()
+{
+ if (!preservePan)
+ centerImage();
+
+ crosshair = cursor;
+ invert = 0;
+
+ orientation = Coord::NORMAL;
+ orientationMatrix.identity();
+ zoom_ = Vector(1,1);
+ rotation = 0;
+
+ wcsAlign_ = 0;
+
+ wcsOrientation = Coord::NORMAL;
+ wcsOrientationMatrix.identity();
+ wcsRotation = 0;
+
+ unselectMarkers(&userMarkers);
+ unselectMarkers(&catalogMarkers);
+ // unselectMarkers(&analysisMarkers);
+
+ update(MATRIX);
+}
+
+FrScale::SecMode Base::secMode()
+{
+ return currentContext->secMode();
+}
+
+void Base::resetSecMode()
+{
+ currentContext->resetSecMode();
+}
+
+void Base::setSecMode(FrScale::SecMode mode)
+{
+ currentContext->setSecMode(mode);
+}
+
+void Base::setSlice(int id, int ss)
+{
+ // real work done in derived classes
+ updateMarkers(&userMarkers);
+ updateMarkers(&catalogMarkers);
+ // updateMarkers(&analysisMarkers);
+
+ // execute any update callbacks
+ updateCBMarkers(&userMarkers);
+ updateCBMarkers(&catalogMarkers);
+ // updateCBMarkers(&analysisMarkers);
+}
+
+void Base::unloadAllFits()
+{
+ unloadFits();
+}
+
+void Base::unloadFits()
+{
+ if (DebugPerf)
+ cerr << "Base::unloadFits()" << endl;
+
+ if (!preserveMarkers) {
+ // delete markers
+ userMarkers.deleteAll();
+ undoUserMarkers.deleteAll();
+ pasteUserMarkers.deleteAll();
+ }
+
+ catalogMarkers.deleteAll();
+ undoCatalogMarkers.deleteAll();
+ pasteCatalogMarkers.deleteAll();
+
+ // analysisMarkers.deleteAll();
+ // undoAnalysisMarkers.deleteAll();
+ // pasteAnalysisMarkers.deleteAll();
+
+ if (grid)
+ delete grid;
+ grid = NULL;
+
+ irafOrientation_ = (Coord::Orientation)-1;
+ irafMatrix_.identity();
+
+ updateColorScale();
+}
+
+void Base::update(UpdateType flag)
+{
+ if (DebugPerf)
+ cerr << "Base::update(" << flag << ')' << endl;
+
+ // Be careful, someone may have already set the flag at a lower level
+ // therefor, only change the flag if we need more to be done
+
+ if (flag < needsUpdate)
+ needsUpdate = flag;
+ redraw();
+}
+
+void Base::update(UpdateType flag, BBox bb)
+{
+ if (DebugPerf)
+ cerr << "Base::update(" << flag << ' ' << bb << ')' << endl;
+
+ // bb is in canvas coords
+
+ if (flag < needsUpdate)
+ needsUpdate = flag;
+ redraw(bb);
+}
+
+void Base::updateBase()
+{
+ if (!widgetGC)
+ widgetGC = XCreateGC(display, Tk_WindowId(tkwin), 0, NULL);
+
+ if (DebugPerf)
+ cerr << "Base::updateBase()...";
+
+ int& width = options->width;
+ int& height = options->height;
+
+ if (!basePixmap) {
+ if (!(basePixmap = Tk_GetPixmap(display, Tk_WindowId(tkwin),
+ width, height, depth))){
+ internalError("Unable to Create Pixmap");
+ return;
+ }
+
+ // Geometry has changed, redefine our marker GCs including clip regions
+ updateGCs();
+ }
+
+ if (!baseXImage) {
+ if (!(baseXImage = XGetImage(display, basePixmap, 0, 0, width, height,
+ AllPlanes, ZPixmap))) {
+ internalError("Unable to Create XImage");
+ return;
+ }
+
+ // we have to wait until now, since the encodings depend on baseXImage
+ encodeTrueColor(baseXImage->byte_order, baseXImage->bits_per_pixel);
+ encodeTrueColor(bgColor, bgTrueColor_);
+ encodeTrueColor(nanColor, nanTrueColor_);
+
+ // we have a race condition. Some Truecolor ColorScales need to know the
+ // bytes per pixel, RGB masks, and byte order, from XImage struct.
+ // yet, we receive colormap commands well before we render to the
+ // screen and have a valid XImage.
+ // So, we put off creating a colorscale until we are ready to render.
+
+ if (!validColorScale())
+ updateColorScale();
+ }
+
+ if (doRender())
+ ximageToPixmap(basePixmap, baseXImage, Coord::WIDGET);
+ else {
+ XSetForeground(display, widgetGC, getColor(bgColorName));
+ XFillRectangle(display, basePixmap, widgetGC, 0,0,options->width,options->height);
+ }
+
+ if (DebugPerf)
+ cerr << "end" << endl;
+}
+
+void Base::updateBin(const Matrix& mx)
+{
+ if (keyContext->fits && (keyContext->fits == currentContext->fits)) {
+ crosshair *= mx;
+ currentContext->updateContours(mx);
+ updateMarkerCoords(&userMarkers, mx);
+ updateMarkerCoords(&catalogMarkers, mx);
+ // updateMarkerCoords(&analysisMarkers, mx);
+ }
+
+ alignWCS();
+ updateColorScale();
+ updateNow(MATRIX); // because we have changed zoom
+
+ // update markers call backs
+ // wait til matrices have been updated so that any dialogs will print
+ // the correct coords
+ updateMarkerCBs(&userMarkers);
+ updateMarkerCBs(&catalogMarkers);
+ // updateMarkerCBs(&analysisMarkers);
+}
+
+void Base::updateBlock(const Vector& vv)
+{
+ Scale mx(vv);
+
+ if (keyContext->fits && (keyContext->fits == currentContext->fits)) {
+ cursor *= mx;
+ crosshair *= mx;
+ currentContext->updateContours(mx);
+ updateMarkerCoords(&userMarkers, mx);
+ updateMarkerCoords(&catalogMarkers, mx);
+ // updateMarkerCoords(&analysisMarkers, mx);
+ }
+
+ alignWCS();
+ updateColorScale();
+ updateNow(MATRIX);
+
+ // update markers call backs
+ // wait til matrices have been updated so that any dialogs will print
+ // the correct coords
+ updateMarkerCBs(&userMarkers);
+ updateMarkerCBs(&catalogMarkers);
+ // updateMarkerCBs(&analysisMarkers);
+}
+
+void Base::updateGCs()
+{
+ // widget clip region
+ BBox bbWidget = BBox(0, 0, options->width, options->height);
+ Vector sizeWidget = bbWidget.size();
+
+ rectWidget[0].x = (int)bbWidget.ll[0];
+ rectWidget[0].y = (int)bbWidget.ll[1];
+ rectWidget[0].width = (int)sizeWidget[0];
+ rectWidget[0].height = (int)sizeWidget[1];
+
+ // window clip region
+ BBox bbWindow = bbWidget * widgetToWindow;
+ Vector sizeWindow = bbWindow.size();
+
+ rectWindow[0].x = (int)bbWindow.ll[0];
+ rectWindow[0].y = (int)bbWindow.ll[1];
+ rectWindow[0].width = (int)sizeWindow[0];
+ rectWindow[0].height = (int)sizeWindow[1];
+
+ // highliteGC
+ XSetClipRectangles(display, highliteGC, 0, 0, rectWidget, 1, Unsorted);
+
+ // panGCXOR
+ XSetClipRectangles(display, panGCXOR, 0, 0, rectWindow, 1, Unsorted);
+
+ // rotateGCXOR
+ XSetClipRectangles(display, rotateGCXOR, 0, 0, rectWindow, 1, Unsorted);
+
+ // markerGC
+ XSetClipRectangles(display, markerGC, 0, 0, rectWidget, 1, Unsorted);
+ XSetClipRectangles(display, markerGCXOR, 0, 0, rectWindow, 1, Unsorted);
+
+ // selectGC
+ x11Dash(selectGCXOR,1);
+ XSetClipRectangles(display, selectGCXOR, 0, 0, rectWindow, 1, Unsorted);
+
+ // gridGC
+ XSetClipRectangles(display, gridGC, 0, 0, rectWidget, 1, Unsorted);
+
+ // contourGC
+ XSetClipRectangles(display, contourGC, 0, 0, rectWidget, 1, Unsorted);
+}
+
+void Base::updateMagnifier()
+{
+ updateMagnifier(magnifierCursor);
+}
+
+void Base::updateMagnifier(const Vector& vv)
+{
+ // vv is in CANVAS coords
+ // save it, we may need it later
+ magnifierCursor = vv;
+
+ if (!(magnifierXImage && magnifierPixmap))
+ return;
+
+ if (useMagnifier) {
+ updateMagnifierMatrices();
+
+ if (doRender()) {
+ ximageToPixmapMagnifier();
+
+ if (useMagnifierGraphics) {
+ // render markers
+ // markers bounding box is in canvas coords
+ // map the magnifier to a bounding box in canvas coords
+ Matrix mm = magnifierToRef * refToCanvas;
+
+ Vector ll = Vector(0,0) * mm;
+ Vector ur = Vector(magnifierWidth,magnifierHeight) * mm;
+ BBox bb = BBox(vv,vv);
+ bb.bound(ll);
+ bb.bound(ur);
+
+ if (showMarkers) {
+ x11MagnifierMarkers(&userMarkers, bb);
+ x11MagnifierMarkers(&catalogMarkers, bb);
+ }
+ // x11MagnifierMarkers(&analysisMarkers, bb);
+
+ // render crosshair
+ if (useCrosshair)
+ x11Crosshair(magnifierPixmap, Coord::MAGNIFIER,
+ magnifierWidth, magnifierHeight);
+
+ // render contours
+ currentContext->contourX11(magnifierPixmap, Coord::MAGNIFIER,
+ magnifierWidth, magnifierHeight);
+ }
+
+ // render cursor
+ if (useMagnifierCursor)
+ x11MagnifierCursor(vv);
+ }
+ else {
+ XSetForeground(display, widgetGC, getColor(bgColorName));
+ XFillRectangle(display, magnifierPixmap, widgetGC, 0, 0,
+ magnifierXImage->width, magnifierXImage->height);
+ }
+
+ // notify the magnifier widget
+ ostringstream str;
+ str << magnifierName << " update " << (void*)magnifierPixmap << ends;
+ Tcl_Eval(interp, str.str().c_str());
+ }
+}
+
+void Base::updateMatrices()
+{
+ // refToUser
+ // flip y axis for X Windows
+ refToUser = Translate(-cursor) * FlipY() * irafMatrix_;
+ userToRef = refToUser.invert();
+
+ // userToWidget
+ userToWidget =
+ wcsOrientationMatrix * // flip x/y axis about center
+ orientationMatrix * // flip x/y axis about cursor position
+ Rotate(wcsRotation) * // rotate about center position
+ Rotate(rotation) * // rotate about cursor position
+
+ Scale(zoom_) * // scale about cursor position
+ // must be int to align with screen pixels
+ Translate((int)(options->width/2.), (int)(options->height/2.));
+ widgetToUser = userToWidget.invert();
+
+ // widgetToCanvas
+ widgetToCanvas = Translate(originX, originY);
+ canvasToWidget = widgetToCanvas.invert();
+
+ // canvasToWindow
+ short xx, yy;
+ Tk_CanvasWindowCoords(canvas, 0, 0, &xx, &yy);
+ canvasToWindow = Translate(xx, yy);
+ windowToCanvas = canvasToWindow.invert();
+
+ // These are derived Transformation Matrices
+ refToWidget = refToUser * userToWidget;
+ widgetToRef = refToWidget.invert();
+
+ refToCanvas = refToWidget * widgetToCanvas;
+ canvasToRef = refToCanvas.invert();
+
+ refToWindow = refToCanvas * canvasToWindow;
+ windowToRef = refToWindow.invert();
+
+ userToCanvas = userToWidget * widgetToCanvas;
+ canvasToUser = userToCanvas.invert();
+
+ widgetToWindow = widgetToCanvas * canvasToWindow;
+ windowToWidget = widgetToWindow.invert();
+
+ // Markers
+ updateMarkers(&userMarkers);
+ updateMarkers(&catalogMarkers);
+ // updateMarkers(&analysisMarkers);
+
+ pushMatrices();
+}
+
+void Base::updateMagnifierMatrices()
+{
+ // magnifierCursor is in CANVAS
+ Vector ww = magnifierCursor*canvasToRef;
+
+ // refToUser
+ Matrix refToUser;
+ refToUser = Translate(-ww) * FlipY() * irafMatrix_;
+
+ // userToMagnifier
+ userToMagnifier =
+ wcsOrientationMatrix * // flip x/y axis about center
+ orientationMatrix * // flip x/y axis about cursor position
+ Rotate(wcsRotation) * // rotate about center position
+ Rotate(rotation) * // rotate about cursor position
+
+ Scale(zoom_) * // scale about cursor position
+ Scale(magnifierZoom_) * // scale
+ // must be int to align with screen pixels
+ Translate((int)(magnifierWidth/2.), (int)(magnifierHeight/2.));
+ magnifierToUser = userToMagnifier.invert();
+
+ refToMagnifier = refToUser * userToMagnifier;
+ magnifierToRef = refToMagnifier.invert();
+
+ magnifierToWidget = magnifierToUser * userToWidget;
+ widgetToMagnifier = magnifierToWidget.invert();
+
+ pushMagnifierMatrices();
+}
+
+void Base::updatePannerMatrices()
+{
+ Vector center = imageCenter(FrScale::IMGSEC) * imageToData;
+
+ // refToUser
+ Matrix refToUser;
+ refToUser = Translate(-center) * FlipY() * irafMatrix_;
+ userToRef = refToUser.invert();
+
+ // userToPanner
+ userToPanner =
+ wcsOrientationMatrix * // flip x/y axis about center
+ orientationMatrix * // flip x/y axis about cursor position
+ Rotate(wcsRotation) * // rotate about center position
+ Rotate(rotation) * // rotate about cursor position
+
+ Scale(calcZoomPanner()) *
+ // must be int to align with screen pixels
+ Translate((int)(pannerWidth/2.), (int)(pannerHeight/2.));
+ pannerToUser = userToPanner.invert();
+
+ refToPanner = refToUser * userToPanner;
+ pannerToRef = refToPanner.invert();
+
+ pannerToWidget = pannerToRef * refToWidget;
+ widgetToPanner = pannerToWidget.invert();
+
+ pushPannerMatrices();
+}
+
+void Base::updateNow(UpdateType flag)
+{
+ if (DebugPerf)
+ cerr << "Base::updateNow(" << flag << ')' << endl;
+
+ if (flag < needsUpdate)
+ needsUpdate = flag;
+ redrawNow();
+}
+
+void Base::updateNow(UpdateType flag, BBox bb)
+{
+ if (DebugPerf)
+ cerr << "Base::updateNow(" << flag << ',' << bb << ')' << endl;
+
+ // bb is in canvas coords
+ if (flag < needsUpdate)
+ needsUpdate = flag;
+ redrawNow(bb);
+}
+
+void Base::updatePanner()
+{
+ if (usePanner) {
+ if (doRender())
+ ximageToPixmap(pannerPixmap, pannerXImage, Coord::PANNER);
+ else {
+ XSetForeground(display, pannerGC, getColor(bgColorName));
+ XFillRectangle(display, pannerPixmap, pannerGC, 0, 0,
+ pannerWidth, pannerHeight);
+ }
+ }
+}
+
+int Base::updatePixmap(const BBox& bb)
+{
+ // bbox is in canvas coords
+
+ // Note: lack of breaks-- on purpose.
+ // If Matrices are update, both Base and Pixmap
+ // also need to be updated. Same for Base-- ie, pixmap is also updated.
+ switch (needsUpdate) {
+ case NOUPDATE:
+ break;
+ case MATRIX:
+ updateMatrices();
+ updatePannerMatrices();
+ case BASE:
+ updatePanner();
+ case BASEONLY:
+ updateBase();
+ case PIXMAP:
+ updatePM(bb);
+ break;
+ }
+
+ needsUpdate = NOUPDATE;
+ return TCL_OK;
+}
+
+void Base::updatePM(const BBox& bbox)
+{
+ // bbox is in Canvas Coords
+
+ if (DebugPerf)
+ cerr << "Base::updatePM()...";
+
+ int& width = options->width;
+ int& height = options->height;
+
+ if (!pixmap) {
+ if (!(pixmap = Tk_GetPixmap(display, Tk_WindowId(tkwin),
+ width, height, depth))) {
+ internalError("Unable to Create Pixmap");
+ return;
+ }
+ }
+
+ if (!bbox.isEmpty()) {
+ BBox bb = bbox * canvasToWidget;
+ int x0 = (int)bb.ll[0] > 0 ? (int)bb.ll[0] : 0;
+ int y0 = (int)bb.ll[1] > 0 ? (int)bb.ll[1] : 0;
+ int x1 = (int)bb.ur[0] < width ? (int)bb.ur[0] : width;
+ int y1 = (int)bb.ur[1] < height ? (int)bb.ur[1] : height;
+ int sx = x1-x0;
+ int sy = y1-y0;
+
+ if (DebugPerf)
+ cerr << ' ' << x0 << ' ' << y0 << ' ' << x1 << ' ' << y1 << ' ';
+
+ XCopyArea(display, basePixmap, pixmap, widgetGC, x0, y0, sx, sy, x0, y0);
+ }
+
+ // grid
+ if (grid)
+ grid->x11();
+
+ // contours
+ currentContext->contourX11(pixmap, Coord::WIDGET,
+ options->width, options->height);
+
+ // markers
+ if (showMarkers) {
+ x11Markers(&catalogMarkers, bbox);
+ x11Markers(&userMarkers, bbox);
+ }
+ // x11Markers(&analysisMarkers, bbox);
+
+ // crosshair
+ x11Crosshair(pixmap, Coord::WIDGET, options->width, options->height);
+
+ // highlite bbox
+ x11Graphics();
+
+ if (DebugPerf)
+ cerr << "end" << endl;
+}
+
+char* Base::varcat(char* buf, char* base, char id, char* mod)
+{
+ int ll = strlen(base);
+ strcpy(buf,base);
+ buf[ll++] = id;
+ buf[ll++] = '\0';
+ strcat(buf,mod);
+ return buf;
+}
+
+void Base::x11Crosshair(Pixmap pm, Coord::InternalSystem sys,
+ int width, int height)
+{
+ if (useCrosshair) {
+ Vector rr = mapFromRef(crosshair,sys);
+
+ XSetForeground(display, widgetGC, getColor("green"));
+ if (rr[0]>=0 && rr[0]<width)
+ XDrawLine(display, pm, widgetGC, rr[0], 1, rr[0], height);
+
+ if (rr[1]>=0 && rr[1]<height)
+ XDrawLine(display, pm, widgetGC, 1, rr[1], width, rr[1]);
+ }
+}
+
+void Base::x11Dash(GC lgc, int which)
+{
+ if (which) {
+ char dl[2];
+#ifdef __WIN32
+ dl[0] = dlist[0]/2;
+ dl[1] = dlist[1]/2;
+#else
+ dl[0] = dlist[0];
+ dl[1] = dlist[1];
+#endif
+ XSetLineAttributes(display, lgc, 1, LineOnOffDash, CapButt,JoinMiter);
+ XSetDashes(display, lgc, 0, dl, 2);
+ }
+ else
+ XSetLineAttributes(display, lgc, 1, LineSolid, CapButt, JoinMiter);
+}
+
+void Base::x11Graphics()
+{
+ if (useHighlite)
+ XDrawRectangle(display, pixmap, highliteGC, 1, 1,
+ options->width-2, options->height-2);
+}
+
+void Base::ximageToPixmap(Pixmap pixmap, XImage* ximage,
+ Coord::InternalSystem sys)
+{
+ // we need a colorScale before we can render
+ if (!validColorScale())
+ return;
+
+ unsigned char* img = fillImage(ximage->width, ximage->height, sys);
+ if (img) {
+ encodeTrueColor(img, ximage);
+ delete [] img;
+ }
+
+ TkPutImage(NULL, 0, display, pixmap, widgetGC, ximage,
+ 0, 0, 0, 0, ximage->width, ximage->height);
+}
+
+void Base::ximageToPixmapMagnifier()
+{
+ ximageToPixmap(magnifierPixmap, magnifierXImage, Coord::MAGNIFIER);
+}
+
+#ifdef MAC_OSX_TK
+void Base::macosx()
+{
+ // clip rect
+ XRectangle* rr = rectWidget;
+ Vector v1 = Vector(rr->x, rr->y) * widgetToCanvas;
+ Vector v2 = Vector(rr->x+rr->width, rr->y+rr->height) * widgetToCanvas;
+ macosxClip(v1,v2-v1);
+
+ if (currentContext->fits) {
+ // scale
+ double scale = 150 / 72.;
+ int width = options->width*scale;
+ int height = options->height*scale;
+
+ // image
+ macosxImage(scale, width, height, v1, v2-v1);
+ }
+}
+
+void Base::macosxCrosshair()
+{
+ if (!useCrosshair)
+ return;
+
+ Vector rr = mapFromRef(crosshair,Coord::WIDGET);
+ Vector aa = Vector(rr[0],1) * widgetToCanvas;
+ Vector bb = Vector(rr[0],options->height) * widgetToCanvas;
+ Vector cc = Vector(1,rr[1]) * widgetToCanvas;
+ Vector dd = Vector(options->width,rr[1]) * widgetToCanvas;
+
+ macosxColor(getXColor("green"));
+ macosxWidth(1);
+ macosxDrawLine(aa,bb);
+ macosxDrawLine(cc,dd);
+}
+
+void Base::macosxImage(float scale, int width, int height,
+ const Vector& v, const Vector& s)
+{
+ // we need a colorScale before we can render
+ if (!validColorScale())
+ return;
+
+ pushPSMatrices(scale, width, height);
+
+ // source
+ unsigned char* src = fillImage(width, height, Coord::PS);
+ if (!src)
+ return;
+
+ // destination
+ unsigned char* dst = new unsigned char[width*height*4];
+ if (!dst)
+ return;
+
+ unsigned char* sptr = src;
+ unsigned char* dptr = dst;
+ for (int ii=0; ii<width*height; ii++) {
+ *dptr++ = *sptr++;
+ *dptr++ = *sptr++;
+ *dptr++ = *sptr++;
+ *dptr++ = 0;
+ }
+
+ if (src)
+ delete [] src;
+
+ macosxBitmapCreate(dst, width, height, v, s);
+
+ if (dst)
+ delete [] dst;
+}
+
+void Base::macosxPrintCmd()
+{
+ if (!visible)
+ return;
+
+ // init
+ macosxBegin();
+
+ // image
+ macosx();
+
+ // grid
+ if (grid)
+ grid->macosx();
+
+ // contours
+ currentContext->contourMacOSX();
+
+ // markers
+ if (showMarkers) {
+ macosxMarkers(&catalogMarkers);
+ macosxMarkers(&userMarkers);
+ }
+ // macosxMarkers(&analysisMarkers);
+
+ macosxCrosshair();
+ macosxGraphics();
+
+ // cleanup
+ macosxEnd();
+}
+#endif
+
+#ifdef __WIN32
+void Base::win32()
+{
+ // clip rect
+ XRectangle* rr = rectWidget;
+ Vector v1 = Vector(rr->x, rr->y) * widgetToCanvas;
+ Vector v2 = Vector(rr->x+rr->width, rr->y+rr->height) * widgetToCanvas;
+ win32Clip(v1,v2-v1);
+
+ if (currentContext->fits) {
+ // scale
+ double scale = 1.0;
+ int width = options->width*scale;
+ int height = options->height*scale;
+
+ // image
+ win32Image(scale, width, height, v1, v2-v1);
+ }
+}
+
+void Base::win32Crosshair()
+{
+ if (!useCrosshair)
+ return;
+
+ Vector rr = mapFromRef(crosshair,Coord::WIDGET);
+ Vector aa = Vector(rr[0],1) * widgetToCanvas;
+ Vector bb = Vector(rr[0],options->height) * widgetToCanvas;
+ Vector cc = Vector(1,rr[1]) * widgetToCanvas;
+ Vector dd = Vector(options->width,rr[1]) * widgetToCanvas;
+
+ win32Color(getXColor("green"));
+ win32Width(1);
+ win32Dash(NULL,0);
+ win32DrawLine(aa,bb);
+ win32DrawLine(cc,dd);
+}
+
+void Base::win32Image(float scale, int width, int height,
+ const Vector& v, const Vector& s)
+{
+ // we need a colorScale before we can render
+ if (!validColorScale())
+ return;
+
+ pushPSMatrices(scale, width, height);
+
+ // source
+ unsigned char* src = fillImage(width, height, Coord::PS);
+ if (!src)
+ return;
+
+ // destination (width must be aligned on 4-byte DWORD boundary)
+ int jjwidth=(((width+3)/4)*4);
+
+ // extra alignment padding which we have to skip over for each row
+ int jjpad=(jjwidth-width)*3;
+
+ unsigned char* dst = new unsigned char[jjwidth*height*3];
+ if (!dst)
+ return;
+ memset(dst, '\0', jjwidth*height*3);
+
+ unsigned char* sptr = src;
+ unsigned char* dptr = dst;
+ unsigned char red, green, blue;
+ for (int jj=0; jj<height; jj++) {
+ for (int ii=0; ii<width; ii++) {
+ red = *sptr++;
+ green = *sptr++;
+ blue = *sptr++;
+ *dptr++ = blue;
+ *dptr++ = green;
+ *dptr++ = red;
+ }
+ dptr += jjpad;
+ }
+
+ if (src)
+ delete [] src;
+
+ win32BitmapCreate(dst, jjwidth, height, v, s);
+
+ if (dst)
+ delete [] dst;
+}
+
+void Base::win32PrintCmd()
+{
+ if (!visible)
+ return;
+
+ // init
+ win32Begin();
+
+ // image
+ win32();
+
+ // grid
+ if (grid)
+ grid->win32();
+
+ // contours
+ currentContext->contourWin32();
+
+ // markers
+ if (showMarkers) {
+ win32Markers(&userMarkers);
+ win32Markers(&catalogMarkers);
+ }
+ // win32Markers(&analysisMarkers);
+
+ win32Crosshair();
+ win32Graphics();
+
+ // cleanup
+ win32End();
+}
+#endif