diff options
Diffstat (limited to 'tksao/frame/frame3dbase.C')
-rw-r--r-- | tksao/frame/frame3dbase.C | 1277 |
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 |