// Copyright (C) 1999-2017 // Smithsonian Astrophysical Observatory, Cambridge, MA, USA // For conditions of distribution and use, see copyright notice in "copyright" #include #include "frame3dbase.h" #include "fitsimage.h" #include "marker.h" #include "context.h" #include "ps.h" #include "sigbus.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; } 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::getInfoCmd(const Vector& vv, Coord::InternalSystem ref, char* var) { FitsBound* params; int mosaic; Vector3d rr = mapToRef3d(vv,ref); // make sure we have an image FitsImage* ptr = currentContext->cfits; FitsImage* sptr = currentContext->cfits; if (!ptr) goto noFits; mosaic = isMosaic(); params = sptr->getDataParams(currentContext->secMode()); if (!mosaic) { Tcl_SetVar2(interp,var,"filename",(char*)sptr->getFileName(ROOTBASE),0); Tcl_SetVar2(interp,var,"object",(char*)sptr->objectKeyword(),0); Tcl_SetVar2(interp,var,"min",(char*)sptr->getMin(),0); Tcl_SetVar2(interp,var,"min,x",(char*)sptr->getMinX(),0); Tcl_SetVar2(interp,var,"min,y",(char*)sptr->getMinY(),0); Tcl_SetVar2(interp,var,"max",(char*)sptr->getMax(),0); Tcl_SetVar2(interp,var,"max,x",(char*)sptr->getMaxX(),0); Tcl_SetVar2(interp,var,"max,y",(char*)sptr->getMaxY(),0); Tcl_SetVar2(interp,var,"low",(char*)sptr->getLow(),0); Tcl_SetVar2(interp,var,"high",(char*)sptr->getHigh(),0); } if (((Vector&)vv)[0]<0 && ((Vector&)vv)[1]<0) goto noImage; // clear values 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); do { Vector img = Vector(rr) * sptr->refToData; if (img[0]>=params->xmin && img[0]xmax && img[1]>=params->ymin && img[1]ymax) { if (mosaic) { Tcl_SetVar2(interp,var,"filename",(char*)sptr->getFileName(ROOTBASE),0); Tcl_SetVar2(interp,var,"object",(char*)sptr->objectKeyword(),0); Tcl_SetVar2(interp,var,"min",(char*)sptr->getMin(),0); Tcl_SetVar2(interp,var,"min,x",(char*)sptr->getMinX(),0); Tcl_SetVar2(interp,var,"min,y",(char*)sptr->getMinY(),0); Tcl_SetVar2(interp,var,"max",(char*)sptr->getMax(),0); Tcl_SetVar2(interp,var,"max,x",(char*)sptr->getMaxX(),0); Tcl_SetVar2(interp,var,"max,y",(char*)sptr->getMaxY(),0); Tcl_SetVar2(interp,var,"low",(char*)sptr->getLow(),0); Tcl_SetVar2(interp,var,"high",(char*)sptr->getHigh(),0); } SETSIGBUS Tcl_SetVar2(interp,var,"value",(char*)sptr->getValue(img),0); CLEARSIGBUS coordToTclArray(sptr,rr,Coord::IMAGE,var,"image"); coordToTclArray(sptr,rr,Coord::PHYSICAL,var,"physical"); if (hasATMV()) coordToTclArray(sptr,rr,Coord::AMPLIFIER,var,"amplifier"); if (hasDTMV()) coordToTclArray(sptr,rr,Coord::DETECTOR,var,"detector"); getInfoWCS(var,rr,ptr,sptr); return; } else { if (mosaic) { sptr = sptr->nextMosaic(); if (sptr) params = sptr->getDataParams(currentContext->secMode()); } else { getInfoWCS(var,rr,ptr,sptr); goto noImage; } } } while (mosaic && sptr); // mosaic gap getInfoWCS(var,rr,ptr,ptr); // else, return blanks noFits: getInfoClearName(var); noImage: getInfoClearValue(var); } #ifndef NEWWCS void Frame3dBase::getInfoWCS(char* var, Vector3d& rr, FitsImage* ptr, FitsImage* sptr) { Vector3d img = rr * sptr->refToImage3d; for (int ii=0; iipix2wcs(Vector(img), 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); 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); double ss = ptr->mapFromImage3d(img[2],www); doubleToTclArray(ss,var,varcat(buf,(char*)"wcs",ww,(char*)""),"z"); 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); } } } #else void Frame3dBase::getInfoWCS(char* var, Vector3d& rr, FitsImage* ptr, FitsImage* sptr) { Vector3d img = rr * sptr->refToImage3d; for (int ii=0; iipix2wcs(img, 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); if (argc > 2 && argv && argv[2]) Tcl_SetVar2(interp,var,varcat(buf,(char*)"wcs",ww,(char*)",z"),argv[2],0); else Tcl_SetVar2(interp,var,varcat(buf,(char*)"wcs",ww,(char*)",z"),"",0); char* wcsname = (char*)sptr->getWCSName(www); if (wcsname) Tcl_SetVar2(interp,var,varcat(buf,(char*)"wcs",ww,(char*)",sys"),wcsname,0); else if (argc > 3 && argv && argv[3]) Tcl_SetVar2(interp,var,varcat(buf,(char*)"wcs",ww,(char*)",sys"),argv[3],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); } } } #endif #ifndef NEWWCS void Frame3dBase::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"); double ss = ptr->mapFromImage3d(((Vector3d&)vv)[2]+.5,out); doubleToTclArray(ss, var, base, "z"); } #else void Frame3dBase::coordToTclArray(FitsImage* ptr, const Vector3d& vv, Coord::CoordSystem out, const char* var, const char* base) { Vector3d rr = ptr->mapFromRef(vv, out); doubleToTclArray(rr[0], var, base, "x"); doubleToTclArray(rr[1], var, base, "y"); doubleToTclArray(rr[2], var, base, "z"); } #endif 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*Translate3d(-.5, -.5, -.5); } 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) * Translate3d( .5, .5, .5); } 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->clearHist(); currentContext->updateClip(); currentContext->updateContours(); 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() { // imageToData3d Vector3d center = imageCenter3d(FrScale::IMGSEC) * Translate3d(-.5, -.5, -.5); // 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(); } #ifndef NEWWCS 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()); } } #else 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_)) { Matrix3d mx; Coord::Orientation oo = keyContext->fits->getWCSOrientation(wcsSystem_, wcsSky_); if (hasWCSCel(wcsSystem_)) { if (oo==Coord::XX) mx *= FlipX3d(); } else { if (oo==Coord::NORMAL) mx *= FlipX3d(); } mx *= mm; Vector north = (Vector3d(0,1)*mx).normalize(); Vector east = (Vector3d(-1,0)*mx).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()); } } #endif 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= 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