summaryrefslogtreecommitdiffstats
path: root/tksao/frame/frame3dbase.C
diff options
context:
space:
mode:
Diffstat (limited to 'tksao/frame/frame3dbase.C')
-rw-r--r--tksao/frame/frame3dbase.C1277
1 files changed, 1277 insertions, 0 deletions
diff --git a/tksao/frame/frame3dbase.C b/tksao/frame/frame3dbase.C
new file mode 100644
index 0000000..e1a599e
--- /dev/null
+++ b/tksao/frame/frame3dbase.C
@@ -0,0 +1,1277 @@
+// 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 "frame3dbase.h"
+#include "fitsimage.h"
+#include "marker.h"
+#include "context.h"
+#include "ps.h"
+
+Frame3dBase::Frame3dBase(Tcl_Interp* i, Tk_Canvas c, Tk_Item* item)
+ : Base(i, c, item)
+{
+ // zdepth_ =100000;
+ zdepth_ =200000;
+ zzoom_ =1;
+ zscale_ =1;
+
+ az_ =0;
+ el_ =0;
+ renderMethod_ = MIP;
+
+ preservecache_ =0;
+ render_ =NONE;
+
+ threedGC = NULL;
+
+ border_ =0;
+ borderColorName_ = dupstr("blue");
+ compass_ =0;
+ compassColorName_ = dupstr("green");
+ highlite_ =1;
+ highliteColorName_ = dupstr("cyan");
+
+ cropsl_ =0;
+
+ imageToData3d = Translate3d(-.5, -.5, -.5);
+ dataToImage3d = Translate3d( .5, .5, .5);
+}
+
+Frame3dBase::~Frame3dBase()
+{
+ if (threedGC)
+ XFreeGC(display, threedGC);
+
+ if (borderColorName_)
+ delete [] borderColorName_;
+ if (compassColorName_)
+ delete [] compassColorName_;
+ if (highliteColorName_)
+ delete [] highliteColorName_;
+
+ cache_.deleteAll();
+ pannerCache_.deleteAll();
+}
+
+
+void Frame3dBase::calcBorder(Coord::InternalSystem sys, FrScale::SecMode mode,
+ Vector3d* vv, int* dd)
+{
+ if (!keyContext->fits)
+ return;
+
+ FitsBound* params = keyContext->fits->getDataParams(mode);
+ FitsZBound* zparams = keyContext->getDataParams(mode);
+
+ Vector3d llf(params->xmin,params->ymin,zparams->zmin);
+ Vector3d lrf(params->xmax,params->ymin,zparams->zmin);
+ Vector3d urf(params->xmax,params->ymax,zparams->zmin);
+ Vector3d ulf(params->xmin,params->ymax,zparams->zmin);
+
+ Vector3d llb(params->xmin,params->ymin,zparams->zmax);
+ Vector3d lrb(params->xmax,params->ymin,zparams->zmax);
+ Vector3d urb(params->xmax,params->ymax,zparams->zmax);
+ Vector3d ulb(params->xmin,params->ymax,zparams->zmax);
+
+ Matrix3d& mm = keyContext->fits->matrixFromData3d(sys);
+ vv[0] = llf * mm;
+ vv[1] = lrf * mm;
+ vv[2] = urf * mm;
+ vv[3] = ulf * mm;
+ vv[4] = llb * mm;
+ vv[5] = lrb * mm;
+ vv[6] = urb * mm;
+ vv[7] = ulb * mm;
+
+ // init for dash
+ for (int ii=0; ii<12; ii++)
+ dd[ii] =1;
+
+ // front
+ {
+ Vector3d aa = vv[1]-vv[0];
+ Vector3d cc = vv[3]-vv[0];
+ Vector3d ff = cross(aa,cc);
+ for (int ii=0; ii<4; ii++)
+ dd[ii] &= ff[2]>0;
+ }
+
+ // right
+ {
+ Vector3d aa = vv[5]-vv[1];
+ Vector3d cc = vv[2]-vv[1];
+ Vector3d ff = cross(aa,cc);
+ int ww = ff[2]>0;
+ dd[1] &= ww;
+ dd[9] &= ww;
+ dd[5] &= ww;
+ dd[10] &= ww;
+ }
+
+ // top
+ {
+ Vector3d aa = vv[6]-vv[2];
+ Vector3d cc = vv[3]-vv[2];
+ Vector3d ff = cross(aa,cc);
+ int ww = ff[2]>0;
+ dd[2] &= ww;
+ dd[10] &= ww;
+ dd[6] &= ww;
+ dd[11] &= ww;
+ }
+
+ // left
+ {
+ Vector3d aa = vv[7]-vv[3];
+ Vector3d cc = vv[0]-vv[3];
+ Vector3d ff = cross(aa,cc);
+ int ww = ff[2]>0;
+ dd[3] &= ww;
+ dd[8] &= ww;
+ dd[7] &= ww;
+ dd[11] &= ww;
+ }
+
+ // bottom
+ {
+ Vector3d aa = vv[4]-vv[0];
+ Vector3d cc = vv[1]-vv[0];
+ Vector3d ff = cross(aa,cc);
+ int ww = ff[2]>0;
+ dd[0] &= ww;
+ dd[9] &= ww;
+ dd[4] &= ww;
+ dd[8] &= ww;
+ }
+
+ // back
+ {
+ Vector3d aa = vv[4]-vv[5];
+ Vector3d cc = vv[6]-vv[5];
+ Vector3d ff = cross(aa,cc);
+ for (int ii=4; ii<8; ii++)
+ dd[ii] &= ff[2]>0;
+ }
+}
+
+void Frame3dBase::calcHighlite(Coord::InternalSystem sys, Vector* vv, int* rr)
+{
+ if (!keyContext->fits)
+ return;
+
+ FitsBound* params = keyContext->fits->getDataParams(keyContext->secMode());
+ Vector ss(params->xmin,params->ymin);
+ Vector tt(params->xmax,params->ymax);
+
+ Vector ll = mapFromRef3d(ss,sys);
+ Vector lr = mapFromRef3d(Vector(tt[0],ss[1]),sys);
+ Vector ur = mapFromRef3d(tt,sys);
+ Vector ul = mapFromRef3d(Vector(ss[0],tt[1]),sys);
+
+ // context->slice() IMAGE (ranges 1-n)
+ double sl = keyContext->slice(2)-.5;
+ Vector3d ll1 = mapFromRef3d(ss,sys);
+ Vector3d lr1 = mapFromRef3d(Vector(tt[0],ss[1]),sys);
+ Vector3d ur1 = mapFromRef3d(tt,sys);
+ Vector3d ul1 = mapFromRef3d(Vector3d(ss[0],tt[1]),sys);
+ Vector3d ll0 = mapFromRef3d(ss,sys,sl-1);
+ Vector3d lr0 = mapFromRef3d(Vector3d(tt[0],ss[1]),sys,sl-1);
+ Vector3d ur0 = mapFromRef3d(tt,sys,sl-1);
+ Vector3d ul0 = mapFromRef3d(Vector3d(ss[0],tt[1]),sys,sl-1);
+
+ Vector3d aa1 = (ll0-ll1).normalize();
+ Vector3d aa2 = (lr0-lr1).normalize();
+ Vector3d aa3 = (ur0-ur1).normalize();
+ Vector3d aa4 = (ul0-ul1).normalize();
+ Vector3d bb1 = (lr1-ll1).normalize();
+ Vector3d bb2 = (ur1-lr1).normalize();
+ Vector3d bb3 = (ul1-ur1).normalize();
+ Vector3d bb4 = (ll1-ul1).normalize();
+
+ Vector3d cc1 = cross(bb1,aa1);
+ Vector3d cc2 = cross(bb2,aa2);
+ Vector3d cc3 = cross(bb3,aa3);
+ Vector3d cc4 = cross(bb4,aa4);
+
+ vv[0] = ll;
+ vv[1] = lr;
+ vv[2] = ur;
+ vv[3] = ul;
+
+ rr[0] = cc1[2]>0;
+ rr[1] = cc2[2]>0;
+ rr[2] = cc3[2]>0;
+ rr[3] = cc4[2]>0;
+}
+
+double Frame3dBase::calcZoom3d(Vector3d src, Vector dest)
+{
+ Vector3d cc = src/2.;
+
+ Vector3d llf(0,0,0);
+ Vector3d lrf(0,src[1],0);
+ Vector3d urf(src[0],src[1],0);
+ Vector3d ulf(src[0],0,0);
+
+ Vector3d llb(0,0,src[2]);
+ Vector3d lrb(0,src[1],src[2]);
+ Vector3d urb(src[0],src[1],src[2]);
+ Vector3d ulb(src[0],0,src[2]);
+
+ Matrix3d mx =
+ Translate3d(-cc) *
+ RotateZ3d(-wcsRotation) *
+ RotateZ3d(-rotation) *
+ RotateY3d(az_) *
+ RotateX3d(el_);
+
+ BBox3d bb(llf*mx);
+ bb.bound(lrf*mx);
+ bb.bound(urf*mx);
+ bb.bound(ulf*mx);
+ bb.bound(llb*mx);
+ bb.bound(lrb*mx);
+ bb.bound(urb*mx);
+ bb.bound(ulb*mx);
+
+ Vector3d bs = bb.size();
+ double r0 = dest[0]/bs[0];
+ double r1 = dest[1]/bs[1];
+
+ return r0>r1 ? r1:r0;
+}
+
+double Frame3dBase::calcZoomPanner()
+{
+ if (!keyContext->fits)
+ return 1;
+
+ if (!pannerPixmap)
+ return 1;
+
+ Vector3d src = imageSize3d(keyContext->datasec() ? FrScale::DATASEC : FrScale::IMGSEC) * Scale3d(1,zscale_);
+ Vector dest(pannerWidth,pannerHeight);
+
+ Vector3d cc = src/2.;
+
+ Vector3d llf = Vector3d(0,0,0);
+ Vector3d lrf = Vector3d(0,src[1],0);
+ Vector3d urf = Vector3d(src[0],src[1],0);
+ Vector3d ulf = Vector3d(src[0],0,0);
+
+ Vector3d llb = Vector3d(0,0,src[2]);
+ Vector3d lrb = Vector3d(0,src[1],src[2]);
+ Vector3d urb = Vector3d(src[0],src[1],src[2]);
+ Vector3d ulb = Vector3d(src[0],0,src[2]);
+
+ BBox3d bb;
+
+ // 0, 0
+ Matrix3d m0000 =
+ Translate3d(-cc) *
+ RotateY3d(degToRad(0)) *
+ RotateX3d(degToRad(0));
+ bb.bound(llf*m0000);
+ bb.bound(llf*m0000);
+ bb.bound(lrf*m0000);
+ bb.bound(urf*m0000);
+ bb.bound(ulf*m0000);
+ bb.bound(llb*m0000);
+ bb.bound(lrb*m0000);
+ bb.bound(urb*m0000);
+ bb.bound(ulb*m0000);
+
+ // 0, 90
+ Matrix3d m0090 =
+ Translate3d(-cc) *
+ RotateY3d(degToRad(90)) *
+ RotateX3d(degToRad(0));
+ bb.bound(llf*m0090);
+ bb.bound(llf*m0090);
+ bb.bound(lrf*m0090);
+ bb.bound(urf*m0090);
+ bb.bound(ulf*m0090);
+ bb.bound(llb*m0090);
+ bb.bound(lrb*m0090);
+ bb.bound(urb*m0090);
+ bb.bound(ulb*m0090);
+
+ // 90, 0
+ Matrix3d m9000 =
+ Translate3d(-cc) *
+ RotateY3d(degToRad(0)) *
+ RotateX3d(-degToRad(90));
+ bb.bound(llf*m9000);
+ bb.bound(llf*m9000);
+ bb.bound(lrf*m9000);
+ bb.bound(urf*m9000);
+ bb.bound(ulf*m9000);
+ bb.bound(llb*m9000);
+ bb.bound(lrb*m9000);
+ bb.bound(urb*m9000);
+ bb.bound(ulb*m9000);
+
+ // 45, 45
+ Matrix3d m4545 =
+ Translate3d(-cc) *
+ RotateY3d(degToRad(45)) *
+ RotateX3d(-degToRad(45));
+ bb.bound(llf*m4545);
+ bb.bound(llf*m4545);
+ bb.bound(lrf*m4545);
+ bb.bound(urf*m4545);
+ bb.bound(ulf*m4545);
+ bb.bound(llb*m4545);
+ bb.bound(lrb*m4545);
+ bb.bound(urb*m4545);
+ bb.bound(ulb*m4545);
+
+ // 45, 90
+ Matrix3d m4590 =
+ Translate3d(-cc) *
+ RotateY3d(degToRad(90)) *
+ RotateX3d(-degToRad(45));
+ bb.bound(llf*m4590);
+ bb.bound(lrf*m4590);
+ bb.bound(urf*m4590);
+ bb.bound(ulf*m4590);
+ bb.bound(llb*m4590);
+ bb.bound(lrb*m4590);
+ bb.bound(urb*m4590);
+ bb.bound(ulb*m4590);
+
+ // 90, 45
+ Matrix3d m9045 =
+ Translate3d(-cc) *
+ RotateY3d(degToRad(45)) *
+ RotateX3d(-degToRad(90));
+ bb.bound(llf*m9045);
+ bb.bound(lrf*m9045);
+ bb.bound(urf*m9045);
+ bb.bound(ulf*m9045);
+ bb.bound(llb*m9045);
+ bb.bound(lrb*m9045);
+ bb.bound(urb*m9045);
+ bb.bound(ulb*m9045);
+
+ Vector3d bs = bb.size();
+ double ll = bs[0] > bs[1] ? bs[0] : bs[1];
+ double mm = dest[0] > dest[1] ? dest[0] : dest[1];
+
+ return 1/ll*mm;
+}
+
+void Frame3dBase::centerImage()
+{
+ Base::centerImage();
+
+ viewCursor_ = Vector();
+ if (keyContext->fits) {
+ // imageCenter is in IMAGE coords
+ Vector3d aa = imageCenter3d(keyContext->secMode());
+ // always center to center of pixel, even for even sized image
+ Vector3d bb = (aa*Translate3d(.5,.5,.5)).floor();
+ // vp_ is in REF coords
+ vp_ = bb*imageToData3d;
+ }
+ else
+ vp_ = Vector();
+}
+
+Vector3d Frame3dBase::imageCenter3d(FrScale::SecMode mode)
+{
+ if (!keyContext->fits)
+ return Vector3d();
+
+ // params is a BBOX in DATA coords 0-n
+ FitsBound* pp = keyContext->fits->getDataParams(mode);
+ FitsZBound* zz = keyContext->getDataParams(mode);
+
+ // Note: imageCenter() is in IMAGE coords
+ return Vector3d((pp->xmax - pp->xmin)/2.+pp->xmin,
+ (pp->ymax - pp->ymin)/2.+pp->ymin,
+ (zz->zmax - zz->zmin)/2.+zz->zmin) * dataToImage3d;
+}
+
+Vector3d Frame3dBase::imageSize3d(FrScale::SecMode mode )
+{
+ if (!keyContext->fits)
+ return Vector3d();
+
+ // params is a BBOX in DATA coords 0-n
+ FitsBound* params = keyContext->fits->getDataParams(mode);
+ FitsZBound* zparams = keyContext->getDataParams(mode);
+
+ // return in IMAGE coords and extends edge to edge
+ return Vector3d(params->xmax-params->xmin, params->ymax-params->ymin,
+ zparams->zmax-zparams->zmin);
+}
+
+void Frame3dBase::psColor(PSColorSpace mode, const char* color)
+{
+ ostringstream str;
+ switch (mode) {
+ case BW:
+ case GRAY:
+ psColorGray(getXColor(color), str);
+ str << " setgray";
+ break;
+ case RGB:
+ psColorRGB(getXColor(color), str);
+ str << " setrgbcolor";
+ break;
+ case CMYK:
+ psColorCMYK(getXColor(color), str);
+ str << " setcmykcolor";
+ break;
+ }
+ str << endl << ends;
+ Tcl_AppendResult(interp, str.str().c_str(), NULL);
+}
+
+void Frame3dBase::psLine(Vector& ss, Vector& tt, int dd)
+{
+ ostringstream str;
+ if (dd)
+ str << '[' << dlist[0] << ' ' << dlist[1] << "] 0 setdash" << endl;
+ else
+ str << "[] 0 setdash" << endl;
+
+ str << "newpath "
+ << ss.TkCanvasPs(canvas) << " moveto" << endl
+ << tt.TkCanvasPs(canvas) << " lineto stroke" << endl << ends;
+
+ Tcl_AppendResult(interp, str.str().c_str(), NULL);
+}
+
+void Frame3dBase::psWidth(int dd)
+{
+ ostringstream str;
+ str << dd << " setlinewidth" << endl << ends;
+ Tcl_AppendResult(interp, str.str().c_str(), NULL);
+}
+
+void Frame3dBase::psGraphics(PSColorSpace mode)
+{
+ if (!keyContext->fits)
+ return;
+
+ if (border_)
+ psBorder(mode);
+ if (compass_)
+ psCompass(mode);
+ if (highlite_)
+ psHighlite(mode);
+}
+
+void Frame3dBase::psBorder(PSColorSpace mode)
+{
+ Vector3d vv[8];
+ int dd[12];
+ calcBorder(Coord::WIDGET, keyContext->secMode(), vv, dd);
+
+ Vector uu[8];
+ for (int ii=0; ii<8; ii++)
+ uu[ii] = Vector(vv[ii])*widgetToCanvas;
+
+ psColor(mode, borderColorName_);
+ psWidth(1);
+
+ // front
+ psLine(uu[0],uu[1],dd[0]);
+ psLine(uu[1],uu[2],dd[1]);
+ psLine(uu[2],uu[3],dd[2]);
+ psLine(uu[3],uu[0],dd[3]);
+
+ // back
+ psLine(uu[4],uu[5],dd[4]);
+ psLine(uu[5],uu[6],dd[5]);
+ psLine(uu[6],uu[7],dd[6]);
+ psLine(uu[7],uu[4],dd[7]);
+
+ // other
+ psLine(uu[0],uu[4],dd[8]);
+ psLine(uu[1],uu[5],dd[9]);
+ psLine(uu[2],uu[6],dd[10]);
+ psLine(uu[3],uu[7],dd[11]);
+}
+
+void Frame3dBase::psCompass(PSColorSpace mode)
+{
+ Matrix3d& mm = keyContext->fits->dataToWidget3d;
+
+ double ss = 100./(zoom_[0]+zoom_[1]);
+
+ Vector3d oo = vp_*mm;
+ Vector3d xx = Vector3d(1,0,0) * Scale3d(ss) * Translate3d(vp_) * mm;
+ Vector3d yy = Vector3d(0,1,0) * Scale3d(ss) * Translate3d(vp_) * mm;
+ Vector3d zz = Vector3d(0,0,1) * Scale3d(ss) * Translate3d(vp_) * mm;
+
+ Vector o = Vector(oo)*widgetToCanvas;
+ Vector x = Vector(xx)*widgetToCanvas;
+ Vector y = Vector(yy)*widgetToCanvas;
+ Vector z = Vector(zz)*widgetToCanvas;
+
+ psColor(mode, compassColorName_);
+ psWidth(1);
+
+ psLine(o,x,0);
+ psLine(o,y,0);
+ psLine(o,z,0);
+}
+
+void Frame3dBase::psHighlite(PSColorSpace mode)
+{
+ Vector vv[4];
+ int rr[4];
+ calcHighlite(Coord::CANVAS,vv,rr);
+
+ psColor(mode, highliteColorName_);
+ psWidth(1);
+ psLine(vv[0],vv[1],rr[0]);
+ psLine(vv[1],vv[2],rr[1]);
+ psLine(vv[2],vv[3],rr[2]);
+ psLine(vv[3],vv[0],rr[3]);
+}
+
+Matrix3d Frame3dBase::psMatrix(float scale, int width, int height)
+{
+ Matrix3d userToPS3d =
+ Matrix3d(wcsOrientationMatrix) *
+ Matrix3d(orientationMatrix) *
+ RotateZ3d(-wcsRotation) *
+ RotateZ3d(-rotation) *
+
+ RotateY3d(az_) *
+ RotateX3d(el_) *
+
+ Translate3d(viewCursor_) *
+ Scale3d(zoom_, zzoom_) *
+ Scale3d(scale,1) *
+
+ FlipY3d() *
+ Translate3d(width/2., height/2., zdepth_/2.);
+
+ return refToUser3d*userToPS3d;
+}
+
+void Frame3dBase::setSlice(int id, int ss)
+{
+ // IMAGE (ranges 1-n)
+ currentContext->updateSlice(id, ss);
+
+ if (id==2) {
+ currentContext->updateContours();
+ update(BASEONLY);
+ }
+ else {
+ // load the next cube
+ currentContext->updateClip();
+ currentContext->updateContoursScale();
+ updateColorScale();
+ update(MATRIX);
+ }
+
+ Base::setSlice(id,ss);
+}
+
+void Frame3dBase::updateBin(const Matrix& mx)
+{
+ centerImage();
+ Base::updateBin(mx);
+}
+
+void Frame3dBase::updateBlock(const Vector& vv)
+{
+ centerImage();
+ Base::updateBlock(vv);
+}
+
+void Frame3dBase::updateGCs()
+{
+ 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];
+
+ // 3d highlite
+ if (!threedGC) {
+ threedGC = XCreateGC(display, Tk_WindowId(tkwin), 0, NULL);
+ XSetLineAttributes(display, threedGC, 1, LineSolid, CapButt, JoinMiter);
+ }
+ XSetClipRectangles(display, threedGC, 0, 0, rectWidget, 1, Unsorted);
+}
+
+void Frame3dBase::updateMatrices()
+{
+ if (DebugPerf)
+ cerr << "Frame3dBase::updateMatrices()..." << endl;
+
+ zzoom_ = (zoom_[0]+zoom_[1])/2.;
+ if (zzoom_<1)
+ zzoom_ = 1;
+
+ // if othogonal, reset zzoom
+ if ((teq(az_,0,.001) ||
+ teq(fabs(az_),M_PI_2,.001) ||
+ teq(fabs(az_),M_PI,.001)) &&
+ (teq(el_,0,.001) ||
+ teq(fabs(el_),M_PI_2,.001)))
+ zzoom_ =1;
+
+ // These are the basic tranformation matrices
+ // Note: imageCenter() is in IMAGE coords
+ refToUser3d =
+ Translate3d(-vp_) *
+ Scale3d(1,zscale_) *
+ FlipY3d();
+ userToRef3d = refToUser3d.invert();
+
+ // userToWidget3d
+ userToWidget3d =
+ Matrix3d(wcsOrientationMatrix) *
+ Matrix3d(orientationMatrix) *
+ RotateZ3d(-wcsRotation) *
+ RotateZ3d(-rotation) *
+
+ RotateY3d(az_) *
+ RotateX3d(el_) *
+
+ Translate3d(viewCursor_) *
+ Scale3d(zoom_, zzoom_) *
+
+ // must be int to align with screen pixels
+ Translate3d((int)(options->width/2.), (int)(options->height/2.),
+ (int)(zdepth_/2.));
+ widgetToUser3d = userToWidget3d.invert();
+
+ // widgetToCanvas
+ widgetToCanvas3d = Translate3d(originX, originY, 0);
+ canvasToWidget3d = widgetToCanvas3d.invert();
+
+ // canvasToWindow
+ short xx, yy;
+ Tk_CanvasWindowCoords(canvas, 0, 0, &xx, &yy);
+ canvasToWindow3d = Translate3d(xx, yy, 0);
+ windowToCanvas3d = canvasToWindow3d.invert();
+
+ // These are derived Transformation Matrices
+ refToWidget3d = refToUser3d * userToWidget3d;
+ widgetToRef3d = refToWidget3d.invert();
+
+ refToCanvas3d = refToWidget3d * widgetToCanvas3d;
+ canvasToRef3d = refToCanvas3d.invert();
+
+ refToWindow3d = refToCanvas3d * canvasToWindow3d;
+ windowToRef3d = refToWindow3d.invert();
+
+ userToCanvas3d = userToWidget3d * widgetToCanvas3d;
+ canvasToUser3d = userToCanvas3d.invert();
+
+ userToWindow3d = userToCanvas3d * canvasToWindow3d;
+ windowToUser3d = userToWindow3d.invert();
+
+ widgetToWindow3d = widgetToCanvas3d * canvasToWindow3d;
+ windowToWidget3d = widgetToWindow3d.invert();
+
+ Base::updateMatrices();
+
+ // delete current zbuffer since matrices have changed
+ cancelDetach();
+
+ // preserve cache?
+ if (!preservecache_) {
+ cache_.deleteAll();
+ pannerCache_.deleteAll();
+ }
+ preservecache_ =0;
+
+ if (DebugPerf)
+ cerr << "updateMatrices end" << endl;
+}
+
+void Frame3dBase::updateMagnifierMatrices()
+{
+ // vv is in CANVAS coords
+ Vector ww = magnifierCursor*canvasToRef;
+
+ // refToUser3d
+ Matrix3d refToUser3d = Translate3d(Vector3d(-ww,-vp_[2])) * FlipY3d();
+
+ // userToMagnifier
+ userToMagnifier3d =
+ Matrix3d(wcsOrientationMatrix) *
+ Matrix3d(orientationMatrix) *
+ RotateZ3d(-wcsRotation) *
+ RotateZ3d(-rotation) *
+
+ RotateY3d(az_) *
+ RotateX3d(el_) *
+
+ Translate3d(viewCursor_) *
+ Scale3d(zoom_, zzoom_) *
+ Scale3d(magnifierZoom_,magnifierZoom_) *
+
+ Translate3d((int)(magnifierWidth/2.), (int)(magnifierHeight/2.),
+ (int)(zdepth_/2.));
+ magnifierToUser3d = userToMagnifier3d.invert();
+
+ refToMagnifier3d = refToUser3d * userToMagnifier3d;
+ magnifierToRef3d = refToMagnifier3d.invert();
+
+ magnifierToWidget3d = magnifierToRef3d * refToWidget3d;
+ widgetToMagnifier3d = magnifierToWidget3d.invert();
+
+ Base::updateMagnifierMatrices();
+}
+
+void Frame3dBase::updatePannerMatrices()
+{
+ Vector3d center = imageCenter3d(FrScale::IMGSEC) * imageToData3d;
+
+ // refToUser3d
+ Matrix3d refToUser3d =
+ Translate3d(-center) *
+ Scale3d(1,zscale_) *
+ FlipY3d();
+
+ // userToPanner3d
+ double pz = calcZoomPanner();
+ double zz = zzoom_*pz;
+ if (zz<1)
+ zz =1;
+
+ userToPanner3d =
+ Matrix3d(wcsOrientationMatrix) *
+ Matrix3d(orientationMatrix) *
+ RotateZ3d(-wcsRotation) *
+ RotateZ3d(-rotation) *
+
+ RotateY3d(az_) *
+ RotateX3d(el_) *
+
+ Scale3d(pz, zz) *
+
+ Translate3d((int)(pannerWidth/2.), (int)(pannerHeight/2.),
+ (int)(zdepth_/2.));
+ pannerToUser3d = userToPanner3d.invert();
+
+ refToPanner3d = refToUser3d * userToPanner3d;
+ pannerToRef3d = refToPanner3d.invert();
+
+ pannerToWidget3d = pannerToRef3d * refToWidget3d;
+ widgetToPanner3d = pannerToWidget3d.invert();
+
+ Base::updatePannerMatrices();
+}
+
+void Frame3dBase::updatePanner()
+{
+ // do this first
+ Base::updatePanner();
+
+ // always render (to update panner background color)
+ if (usePanner) {
+ if (keyContext->fits) {
+ XSetForeground(display, pannerGC, getColor("black"));
+ x11Border(Coord::PANNER,FrScale::IMGSEC,pannerGC,pannerPixmap);
+ }
+
+ ostringstream str;
+ str << pannerName << " update " << (void*)pannerPixmap << ';';
+
+ // calculate bbox
+ Vector ll = Vector(0,0) * widgetToPanner3d;
+ Vector lr = Vector(options->width,0) * widgetToPanner3d;
+ Vector ur = Vector(options->width,options->height) * widgetToPanner3d;
+ Vector ul = Vector(0,options->height) * widgetToPanner3d;
+
+ str << pannerName << " update bbox "
+ << ll << ' ' << lr << ' ' << ur << ' ' << ul << ';';
+
+ // calculate image compass vectors
+ Matrix3d mm =
+ Matrix3d(wcsOrientationMatrix) *
+ Matrix3d(orientationMatrix) *
+ RotateZ3d(wcsRotation) *
+ RotateZ3d(rotation) *
+ RotateY3d(az_) *
+ RotateX3d(-el_) *
+ FlipY3d();
+
+ Vector xx = (Vector3d(1,0,0)*mm).normalize();
+ Vector yy = (Vector3d(0,1,0)*mm).normalize();
+ Vector zz = (Vector3d(0,0,1)*mm).normalize();
+
+ str << pannerName << " update image compass "
+ << xx << ' ' << yy << ' ' << zz << ';';
+
+ if (keyContext->fits && keyContext->fits->hasWCS(wcsSystem_)) {
+ Vector orpix = keyContext->fits->center();
+ Vector orval=keyContext->fits->pix2wcs(orpix, wcsSystem_, wcsSky_);
+ Vector orpix2 = keyContext->fits->wcs2pix(orval, wcsSystem_,wcsSky_);
+ Vector delta = keyContext->fits->getWCScdelt(wcsSystem_).abs();
+
+ // find normalized north
+ Vector npix = keyContext->fits->wcs2pix(Vector(orval[0],orval[1]+delta[1]), wcsSystem_,wcsSky_);
+ Vector north = (Vector3d(npix-orpix2)*mm).normalize();
+
+ // find normalized east
+ Vector epix = keyContext->fits->wcs2pix(Vector(orval[0]+delta[0],orval[1]), wcsSystem_,wcsSky_);
+ Vector east = (Vector3d(epix-orpix2)*mm).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)) {
+ north = (Vector3d(0,1)*mm).normalize();
+ east = (Vector3d(-1,0)*mm).normalize();
+ }
+
+ // and update the panner
+ str << pannerName << " update wcs compass "
+ << north << ' ' << east << ends;
+ }
+ else
+ str << pannerName << " update wcs compass invalid" << ends;
+
+ Tcl_Eval(interp, str.str().c_str());
+ }
+}
+
+void Frame3dBase::x11Graphics()
+{
+ Base::x11Graphics();
+
+ if (!keyContext->fits)
+ return;
+
+ if (border_) {
+ XSetForeground(display, threedGC, getColor(borderColorName_));
+ x11Border(Coord::WIDGET, keyContext->secMode(), threedGC, pixmap);
+ }
+ if (compass_)
+ x11Compass();
+ if (highlite_)
+ x11Highlite();
+}
+
+void Frame3dBase::x11Line(Vector ss, Vector tt, int dd, GC gc, Pixmap pm)
+{
+ if (clip(&ss,&tt,options->width,options->height)) {
+ x11Dash(gc, dd);
+ XDrawLine(display, pm, gc, ss[0], ss[1], tt[0], tt[1]);
+ }
+}
+
+void Frame3dBase::x11Border(Coord::InternalSystem sys,
+ FrScale::SecMode mode, GC gc, Pixmap pm)
+{
+ Vector3d vv[8];
+ int dd[12];
+ calcBorder(sys, mode, vv, dd);
+
+ // front
+ x11Line(vv[0], vv[1], dd[0], gc, pm);
+ x11Line(vv[1], vv[2], dd[1], gc, pm);
+ x11Line(vv[2], vv[3], dd[2], gc, pm);
+ x11Line(vv[3], vv[0], dd[3], gc, pm);
+
+ // back
+ x11Line(vv[4], vv[5], dd[4], gc, pm);
+ x11Line(vv[5], vv[6], dd[5], gc, pm);
+ x11Line(vv[6], vv[7], dd[6], gc, pm);
+ x11Line(vv[7], vv[4], dd[7], gc, pm);
+
+ // other
+ x11Line(vv[0], vv[4], dd[8], gc, pm);
+ x11Line(vv[1], vv[5], dd[9], gc, pm);
+ x11Line(vv[2], vv[6], dd[10], gc, pm);
+ x11Line(vv[3], vv[7], dd[11], gc, pm);
+}
+
+void Frame3dBase::x11Compass()
+{
+ Matrix3d& mm = keyContext->fits->dataToWidget3d;
+
+ double ss = 100./(zoom_[0]+zoom_[1]);
+
+ Vector3d oo = vp_*mm;
+ Vector3d xx = Vector3d(1,0,0) * Scale3d(ss) * Translate3d(vp_) * mm;
+ Vector3d yy = Vector3d(0,1,0) * Scale3d(ss) * Translate3d(vp_) * mm;
+ Vector3d zz = Vector3d(0,0,1) * Scale3d(ss) * Translate3d(vp_) * mm;
+
+ x11Dash(threedGC, 0);
+ XSetForeground(display, threedGC, getColor(compassColorName_));
+
+ XDrawLine(display, pixmap, threedGC, oo[0], oo[1], xx[0], xx[1]);
+ XDrawLine(display, pixmap, threedGC, oo[0], oo[1], yy[0], yy[1]);
+ XDrawLine(display, pixmap, threedGC, oo[0], oo[1], zz[0], zz[1]);
+}
+
+/*
+void Frame3dBase::renderArm(int length, Vector center, Rotate rot,
+ const char* str, int color)
+{
+ if (!tkfont_) {
+ ostringstream fstr;
+ fstr << '{' << options->helvetica << '}' << " 9 roman normal" << ends;
+ tkfont_ = Tk_GetFont(interp, tkwin, fstr.str().c_str());
+ if (tkfont_)
+ Tk_GetFontMetrics(tkfont_, &metric);
+ }
+
+ if (!compassGC) {
+ compassGC = XCreateGC(display, pixmap, 0, NULL);
+ XSetLineAttributes(display, compassGC, 1, LineSolid, CapButt, JoinMiter);
+ if (tkfont_)
+ XSetFont(display, compassGC, Tk_FontId(tkfont_));
+ }
+
+
+ if (length<=0)
+ return;
+
+ // set GC
+ XSetForeground(display, compassGC, color);
+ const int textOffset = 15; // Text offset
+ const int tip = 6; // length from end of line to tip of arrow
+ const int tail = 2; // length from end of line to tails of arrow
+ const int wc = 2; // width of arrow at end of line
+ const int wt = 3; // width of arrow at tails
+
+ // Arrow-- oriented on Y axis
+ Vector arrow[6];
+ arrow[0] = Vector(0, tip);
+ arrow[1] = Vector(-wc, 0);
+ arrow[2] = Vector(-wt, -tail);
+ arrow[3] = Vector(0, 0);
+ arrow[4] = Vector(wt, -tail);
+ arrow[5] = Vector(wc, 0);
+
+ // Staff-- oriented on X axis
+ XPoint arrowArray[6];
+ Matrix arrowMatrix = Rotate(M_PI_2) *
+ Translate(length,0) *
+ rot *
+ Translate(center);
+ for (int i=0; i<6; i++) {
+ Vector r = (arrow[i] * arrowMatrix).round();
+ arrowArray[i].x = (int)r[0];
+ arrowArray[i].y = (int)r[1];
+ }
+
+ Vector c = ((Vector&)center).round();
+ Vector end = (Vector(length, 0) * rot * Translate(center)).round();
+ XDrawLine(display, pixmap, compassGC, (int)c[0], (int)c[1],
+ (int)end[0], (int)end[1]);
+ XFillPolygon(display, pixmap, compassGC, arrowArray, 6,
+ Nonconvex, CoordModeOrigin);
+
+ if (useFont && tkfont_) {
+ Vector et = Vector((length + textOffset), 0) * rot * Translate(center) *
+ Translate(-Tk_TextWidth(tkfont_, str, 1)/2., metric.ascent/2.);
+ Tk_DrawChars(display, pixmap, compassGC, tkfont_, str, 1,
+ (int)et[0], (int)et[1]);
+ }
+}
+*/
+
+void Frame3dBase::x11Highlite()
+{
+ Vector vv[4];
+ int rr[4];
+ calcHighlite(Coord::WIDGET,vv,rr);
+
+ XSetForeground(display, threedGC, getColor(highliteColorName_));
+
+ x11Line(vv[0], vv[1], rr[0], threedGC, pixmap);
+ x11Line(vv[1], vv[2], rr[1], threedGC, pixmap);
+ x11Line(vv[2], vv[3], rr[2], threedGC, pixmap);
+ x11Line(vv[3], vv[0], rr[3], threedGC, pixmap);
+}
+
+void Frame3dBase::ximageToPixmapMagnifier()
+{
+ if (!basePixmap || !baseXImage || !magnifierPixmap || !magnifierXImage)
+ return;
+
+ // magnifier
+ int& ww = magnifierXImage->width;
+ int& hh = magnifierXImage->height;
+ Vector wh(ww,hh);
+ Vector cc = magnifierCursor * canvasToWidget;
+ Vector ll =cc-wh/2.;
+ Vector ur =cc+wh/2.;
+
+ // clip to base
+ BBox bb(0,0,baseXImage->width,baseXImage->height);
+ Vector uu(ll);
+ Vector vv(ur);
+ uu.clip(bb);
+ vv.clip(bb);
+ Vector zz = vv-uu;
+ Vector oo = uu-ll;
+
+ // sanity check
+ if (zz[0]<=0 || zz[1]<=0)
+ return;
+
+ XImage* srcXImage = XGetImage(display, basePixmap, uu[0], uu[1],
+ zz[0], zz[1], AllPlanes, ZPixmap);
+
+ char* src = srcXImage->data;
+ int srcBytesPerLine = srcXImage->bytes_per_line;
+
+ char* dst = magnifierXImage->data;
+ int dstBytesPerLine = magnifierXImage->bytes_per_line;
+ int bytesPerPixel = magnifierXImage->bits_per_pixel/8;
+
+ Matrix mx = Translate(-wh/2.) *
+ Translate(oo) *
+ Translate(-.5,-.5) *
+ Scale(magnifierZoom_) *
+ Translate(wh/2.);
+ Matrix mm = mx.invert();
+
+ for (int jj=0; jj<hh; jj++) {
+ char* dest = dst + jj*dstBytesPerLine;
+
+ for (int ii=0; ii<ww; ii++, dest+=bytesPerPixel) {
+ Vector vv = Vector(ii,jj)*mm;
+
+ if (vv[0] >= 0 && vv[0] < zz[0] && vv[1] >= 0 && vv[1] < zz[1]) {
+ // I really don't understand this
+#if MAC_OSX_TK
+ char* sptr = src + ((int)vv[1])*srcBytesPerLine +
+ ((int)vv[0])*bytesPerPixel;
+
+ *(dest+0) = *(sptr+3);
+ *(dest+1) = *(sptr+0);
+ *(dest+2) = *(sptr+1);
+ *(dest+3) = *(sptr+2);
+#else
+ memcpy(dest, src + ((int)vv[1])*srcBytesPerLine +
+ ((int)vv[0])*bytesPerPixel, bytesPerPixel);
+#endif
+ }
+ else
+ memcpy(dest, bgTrueColor_, bytesPerPixel);
+ }
+ }
+
+ TkPutImage(NULL, 0, display, magnifierPixmap, widgetGC, magnifierXImage,
+ 0, 0, 0, 0, magnifierXImage->width, magnifierXImage->height);
+
+ if (srcXImage)
+ XDestroyImage(srcXImage);
+}
+
+#ifdef MAC_OSX_TK
+void Frame3dBase::macosxLine(Vector& ss, Vector& tt, int dd)
+{
+ if (dd)
+ macosxDash(dlist,2);
+ else
+ macosxDash(NULL,0);
+ macosxDrawLine(ss,tt);
+}
+
+void Frame3dBase::macosxGraphics()
+{
+ if (!keyContext->fits)
+ return;
+
+ if (border_)
+ macosxBorder();
+ if (compass_)
+ macosxCompass();
+ if (highlite_)
+ macosxHighlite();
+}
+
+void Frame3dBase::macosxBorder()
+{
+ Vector3d vv[8];
+ int dd[12];
+ calcBorder(Coord::WIDGET, keyContext->secMode(), vv, dd);
+
+ Vector uu[8];
+ for (int ii=0; ii<8; ii++)
+ uu[ii] = Vector(vv[ii])*widgetToCanvas;
+
+ macosxColor(getXColor(borderColorName_));
+ macosxWidth(1);
+
+ // front
+ macosxLine(uu[0],uu[1],dd[0]);
+ macosxLine(uu[1],uu[2],dd[1]);
+ macosxLine(uu[2],uu[3],dd[2]);
+ macosxLine(uu[3],uu[0],dd[3]);
+
+ // back
+ macosxLine(uu[4],uu[5],dd[4]);
+ macosxLine(uu[5],uu[6],dd[5]);
+ macosxLine(uu[6],uu[7],dd[6]);
+ macosxLine(uu[7],uu[4],dd[7]);
+
+ // other
+ macosxLine(uu[0],uu[4],dd[8]);
+ macosxLine(uu[1],uu[5],dd[9]);
+ macosxLine(uu[2],uu[6],dd[10]);
+ macosxLine(uu[3],uu[7],dd[11]);
+}
+
+void Frame3dBase::macosxCompass()
+{
+ Matrix3d& mm = keyContext->fits->dataToWidget3d;
+
+ double ss = 100./(zoom_[0]+zoom_[1]);
+
+ Vector3d oo = vp_*mm;
+ Vector3d xx = Vector3d(1,0,0) * Scale3d(ss) * Translate3d(vp_) * mm;
+ Vector3d yy = Vector3d(0,1,0) * Scale3d(ss) * Translate3d(vp_) * mm;
+ Vector3d zz = Vector3d(0,0,1) * Scale3d(ss) * Translate3d(vp_) * mm;
+
+ Vector o = Vector(oo)*widgetToCanvas;
+ Vector x = Vector(xx)*widgetToCanvas;
+ Vector y = Vector(yy)*widgetToCanvas;
+ Vector z = Vector(zz)*widgetToCanvas;
+
+ macosxColor(getXColor(compassColorName_));
+ macosxWidth(1);
+
+ macosxLine(o,x,0);
+ macosxLine(o,y,0);
+ macosxLine(o,z,0);
+}
+
+void Frame3dBase::macosxHighlite()
+{
+ Vector vv[4];
+ int rr[4];
+ calcHighlite(Coord::CANVAS,vv,rr);
+
+ macosxColor(getXColor(highliteColorName_));
+ macosxWidth(1);
+
+ macosxLine(vv[0],vv[1],rr[0]);
+ macosxLine(vv[1],vv[2],rr[1]);
+ macosxLine(vv[2],vv[3],rr[2]);
+ macosxLine(vv[3],vv[0],rr[3]);
+}
+#endif
+
+#ifdef __WIN32
+void Frame3dBase::win32Line(Vector& ss, Vector& tt, int dd)
+{
+ if (dd)
+ win32Dash(dlist,2);
+ else
+ win32Dash(NULL,0);
+ win32DrawLine(ss,tt);
+}
+
+void Frame3dBase::win32Graphics()
+{
+ if (!keyContext->fits)
+ return;
+
+ if (border_)
+ win32Border();
+ if (compass_)
+ win32Compass();
+ if (highlite_)
+ win32Highlite();
+}
+
+void Frame3dBase::win32Border()
+{
+ Vector3d vv[8];
+ int dd[12];
+ calcBorder(Coord::WIDGET, keyContext->secMode(), vv, dd);
+
+ Vector uu[8];
+ for (int ii=0; ii<8; ii++)
+ uu[ii] = Vector(vv[ii])*widgetToCanvas;
+
+ win32Color(getXColor(borderColorName_));
+ win32Width(1);
+
+ // front
+ win32Line(uu[0],uu[1],dd[0]);
+ win32Line(uu[1],uu[2],dd[1]);
+ win32Line(uu[2],uu[3],dd[2]);
+ win32Line(uu[3],uu[0],dd[3]);
+
+ // back
+ win32Line(uu[4],uu[5],dd[4]);
+ win32Line(uu[5],uu[6],dd[5]);
+ win32Line(uu[6],uu[7],dd[6]);
+ win32Line(uu[7],uu[4],dd[7]);
+
+ // other
+ win32Line(uu[0],uu[4],dd[8]);
+ win32Line(uu[1],uu[5],dd[9]);
+ win32Line(uu[2],uu[6],dd[10]);
+ win32Line(uu[3],uu[7],dd[11]);
+}
+
+void Frame3dBase::win32Compass()
+{
+ Matrix3d& mm = keyContext->fits->dataToWidget3d;
+
+ double ss = 100./(zoom_[0]+zoom_[1]);
+
+ Vector3d oo = vp_*mm;
+ Vector3d xx = Vector3d(1,0,0) * Scale3d(ss) * Translate3d(vp_) * mm;
+ Vector3d yy = Vector3d(0,1,0) * Scale3d(ss) * Translate3d(vp_) * mm;
+ Vector3d zz = Vector3d(0,0,1) * Scale3d(ss) * Translate3d(vp_) * mm;
+
+ Vector o = Vector(oo)*widgetToCanvas;
+ Vector x = Vector(xx)*widgetToCanvas;
+ Vector y = Vector(yy)*widgetToCanvas;
+ Vector z = Vector(zz)*widgetToCanvas;
+
+ win32Color(getXColor(compassColorName_));
+ win32Width(1);
+
+ win32Line(o,x,0);
+ win32Line(o,y,0);
+ win32Line(o,z,0);
+}
+
+void Frame3dBase::win32Highlite()
+{
+ Vector vv[4];
+ int rr[4];
+ calcHighlite(Coord::CANVAS,vv,rr);
+
+ win32Color(getXColor(highliteColorName_));
+ win32Width(1);
+
+ win32Line(vv[0],vv[1],rr[0]);
+ win32Line(vv[1],vv[2],rr[1]);
+ win32Line(vv[2],vv[3],rr[2]);
+ win32Line(vv[3],vv[0],rr[3]);
+}
+#endif