// Copyright (C) 1999-2017 // Smithsonian Astrophysical Observatory, Cambridge, MA, USA // For conditions of distribution and use, see copyright notice in "copyright" #include #include "marker.h" #include "framebase.h" #include "frame3dbase.h" #include "fitsimage.h" extern "C" { #include "tkbltVector.h" } static int markerSeqID = 1; // hard coded const char* Marker::analysisHistogramCB_[] = { "MarkerAnalysisHistogramCB", "MarkerAnalysisHistogramDeleteCB" }; const char* Marker::analysisPlot2dCB_[] = { "MarkerAnalysisPlot2dCB", "MarkerAnalysisPlot2dDeleteCB" }; const char* Marker::analysisPlot3dCB_[] = { "MarkerAnalysisPlot3dCB", "MarkerAnalysisPlot3dDeleteCB" }; const char* Marker::analysisPandaCB_[] = { "MarkerAnalysisPandaCB", "MarkerAnalysisPandaDeleteCB" }; const char* Marker::analysisRadialCB_[] = { "MarkerAnalysisRadialCB", "MarkerAnalysisRadialDeleteCB" }; const char* Marker::analysisStatsCB_[] = { "MarkerAnalysisStatsCB", "MarkerAnalysisStatsDeleteCB" }; // Marker Members Public Marker::Marker(Base* p, const Vector& ctr, double ang) { id = markerSeqID++; type_[0] = '\0'; parent = p; center = ctr; angle = ang; handle = NULL; numHandle = 0; colorName = dupstr("green"); color = parent->getColor(colorName); lineWidth = 1; properties = INCLUDE|SOURCE; selected = 0; highlited = 0; dlist[0] = 8; dlist[1] = 3; text = dupstr(""); tkfont_ =NULL; psfont_ =NULL; initFonts("helvetica 10 normal roman"); comment = dupstr(""); display = parent->display; gc = parent->markerGC_; gcxor = parent->markerGCXOR_; for (int ii=0; ii& tg, const List& cb) { id = markerSeqID++; type_[0] = '\0'; parent = p; center = ctr; angle = ang; handle = NULL; numHandle = 0; colorName = dupstr(clr); color = parent->getColor(colorName); lineWidth = w; properties = prop; selected = 0; highlited = 0; dlist[0] = dsh[0]; dlist[1] = dsh[1]; text = dupstr(t); tkfont_ =NULL; psfont_ =NULL; initFonts(f); comment = dupstr(c); display = parent->display; gc = parent->markerGC_; gcxor = parent->markerGCXOR_; for (int ii=0; iiinterp, parent->tkwin, Tk_NameOfFont(a.tkfont_)) : NULL; psfont_ = a.psfont_ ? Tk_GetFont(parent->interp, parent->tkwin, Tk_NameOfFont(a.psfont_)) : NULL; comment = dupstr(a.comment); display = a.display; gc = a.gc; gcxor = a.gcxor; for (int ii=0; iicanvasToWidget).round(); Vector ur = (handle[2]*parent->canvasToWidget).round(); if (mode==SRC) XSetForeground(display, gc, parent->getColor("red")); XDrawLine(display, drawable, lgc, ll[0], ll[1], ur[0], ur[1]); } } void Marker::renderXText(Drawable drawable, Coord::InternalSystem sys, RenderMode mode) { if (text && *text && tkfont_) { GC lgc; switch (mode) { case SRC: lgc = gc; XSetForeground(display, gc, color); break; case XOR: lgc = gcxor; break; } XSetFont(display, lgc, Tk_FontId(tkfont_)); Tk_FontMetrics metrics; Tk_GetFontMetrics(tkfont_, &metrics); int width = Tk_TextWidth(tkfont_, text, strlen(text)); Matrix mm; Matrix nn; setMatrices(sys,&mm,&nn); Vector ll0 = bbox.ll*parent->canvasToRef; Vector ll = ll0*mm; Vector ur0 = bbox.ur*parent->canvasToRef; Vector ur = ur0*mm; BBox bb(ll,ur); Vector bbc = bb.center(); Vector tt = Vector(bbc[0], bb.ll[1]) * Translate(-width/2., -metrics.descent); Tk_DrawChars(display, drawable, lgc, tkfont_, text, strlen(text), tt[0], tt[1]); } } void Marker::renderXArrow(Drawable drawable, const Vector& p1, const Vector& p2, Coord::InternalSystem sys, GC lgc) { Vector* vv = arrow(p1,p2,sys); XPoint dd[6]; for (int ii=0; ii<6; ii++) { dd[ii].x = (short)vv[ii][0]; dd[ii].y = (short)vv[ii][1]; } XFillPolygon(display, drawable, lgc, dd, 6, Nonconvex, CoordModeOrigin); delete [] vv; } void Marker::renderXHandles(Drawable drawable) { // handles are of length 5 if (selected && canSelect()) { XSetForeground(display, gc, color); for (int ii=0; iicanvasToWidget - Vector(2,2)).round(); XFillRectangle(display, drawable, gc, vv[0], vv[1], 5, 5); } } } GC Marker::renderXGC(RenderMode mode) { // set width, color, dash switch (mode) { case SRC: XSetForeground(display, gc, color); if ((properties & SOURCE) && !(properties & DASH)) renderXLineNoDash(gc); else renderXLineDash(gc); return gc; case XOR: renderXLineDash(gcxor); return gcxor; } } void Marker::renderXLineDash(GC lgc) { char dl[2]; dl[0] = dlist[0]; dl[1] = dlist[1]; int ww = (highlited && canHighlite()) ? lineWidth*2 : lineWidth; XSetDashes(display, lgc, 0, dl, 2); XSetLineAttributes(display, lgc, ww, LineOnOffDash, CapButt, JoinMiter); } void Marker::renderXLineNoDash(GC lgc) { int ww = (highlited && canHighlite()) ? lineWidth*2 : lineWidth; XSetLineAttributes(display, lgc, ww, LineSolid, CapButt, JoinMiter); } void Marker::ps(int mode, int tt) { if (properties & HIDDEN) return; if (tt) renderPSText(mode); renderPS(mode); renderPSInclude(mode); } void Marker::renderPSInclude(int mode) { if (!(properties & INCLUDE)) { renderPSColor(mode, parent->getXColor("red")); Vector ll = handle[0]; Vector ur = handle[2]; ostringstream str; str << "newpath " << ll.TkCanvasPs(parent->canvas) << ' ' << "moveto " << ur.TkCanvasPs(parent->canvas) << ' ' << "lineto stroke" << endl << ends; Tcl_AppendResult(parent->interp, str.str().c_str(), NULL); } } void Marker::renderPSText(int mode) { if (text && *text && psfont_) { renderPSColor(mode, parent->getXColor(colorName)); ostringstream str; const char* ff = Tk_NameOfFont(psfont_); str << '/' << psFontName(ff) << " findfont " << int(psFontSize(ff)*parent->getDisplayRatio()) << " scalefont setfont" << endl; Vector bbc = bbox.center(); Vector tt = Vector(bbc[0], bbox.ll[1]).TkCanvasPs(parent->canvas); str << "gsave" << endl << "newpath " << endl << tt << " moveto" << endl << '(' << psQuote(text) << ')' << endl << "dup true charpath pathbbox " << endl << "closepath " << endl << "3 -1 roll sub 2.5 div " << endl << "3 1 roll sub 2 div exch " << endl << tt << " moveto rmoveto show " << endl << "grestore" << endl; str << ends; Tcl_AppendResult(parent->interp, (char*)str.str().c_str(), NULL); } } void Marker::renderPSArrow(const Vector& p1, const Vector& p2, Coord::InternalSystem sys) { Vector* vv = arrow(p1,p2,sys); ostringstream str; str << "newpath " << endl << vv[0].TkCanvasPs(parent->canvas) << " moveto" << endl; for (int ii=1; ii<6; ii++) str << vv[ii].TkCanvasPs(parent->canvas) << " lineto" << endl; str << "closepath fill" << endl << ends; Tcl_AppendResult(parent->interp, (char*)str.str().c_str(), NULL); delete [] vv; } void Marker::renderPSGC(int mode) { // set width, color, dash renderPSColor(mode, parent->getXColor(colorName)); if ((properties & SOURCE) && !(properties & DASH)) renderPSLineNoDash(); else renderPSLineDash(); } void Marker::renderPSLineDash() { ostringstream str; str << lineWidth << " setlinewidth" << endl << '[' << dlist[0] << ' ' << dlist[1] << "] 0 setdash" << endl << ends; Tcl_AppendResult(parent->interp, (char*)str.str().c_str(), NULL); } void Marker::renderPSLineNoDash() { ostringstream str; str << lineWidth << " setlinewidth" << endl << "[] 0 setdash" << endl << ends; Tcl_AppendResult(parent->interp, (char*)str.str().c_str(), NULL); } void Marker::renderPSColor(int mode, XColor* clr) { ostringstream str; switch ((Widget::PSColorSpace)mode) { case Widget::BW: case Widget::GRAY: psColorGray(clr, str); str << " setgray"; break; case Widget::RGB: psColorRGB(clr, str); str << " setrgbcolor"; break; case Widget::CMYK: psColorCMYK(clr, str); str << " setcmykcolor"; break; } str << endl << ends; Tcl_AppendResult(parent->interp, (char*)str.str().c_str(), NULL); } #ifdef MAC_OSX_TK void Marker::macosx(int tt) { if (properties & HIDDEN) return; if (tt) renderMACOSXText(); renderMACOSX(); renderMACOSXInclude(); } void Marker::renderMACOSXInclude() { if (!(properties & INCLUDE)) { macosxColor(parent->getXColor("red")); Vector ll = handle[0]; Vector ur = handle[2]; macosxDrawLine(ll,ur); } } void Marker::renderMACOSXText() { if (text && *text && psfont_) { macosxColor(parent->getXColor(colorName)); Tcl_DString psdstr; Tcl_DStringInit(&psdstr); int psSize = Tk_PostscriptFontName(psfont_, &psdstr); macosxFont(Tcl_DStringValue(&psdstr), psSize); Tcl_DStringFree(&psdstr); Tk_FontMetrics metrics; Tk_GetFontMetrics(psfont_, &metrics); int width = Tk_TextWidth(psfont_, text, strlen(text)); Vector bbc = bbox.center(); Vector tt = Vector(bbc[0], bbox.ll[1]) * Translate(-width/2., -metrics.descent); macosxDrawText(tt, 0, text); } } void Marker::renderMACOSXArrow(const Vector& p1, const Vector& p2, Coord::InternalSystem sys) { Vector* vv = arrow(p1,p2,sys); Vector dd[6]; for (int ii=0; ii<6; ii++) dd[ii] = vv[ii]; macosxFillPolygon(dd,6); delete [] vv; } void Marker::renderMACOSXGC() { // set width, color, dash macosxColor(parent->getXColor(colorName)); if ((properties & SOURCE) && !(properties & DASH)) renderMACOSXLineNoDash(); else renderMACOSXLineDash(); } void Marker::renderMACOSXLineDash() { macosxWidth(lineWidth); macosxDash(dlist,2); } void Marker::renderMACOSXLineNoDash() { macosxWidth(lineWidth); macosxDash(NULL,0); } #endif #ifdef __WIN32 void Marker::win32(int tt) { if (properties & HIDDEN) return; if (tt) renderWIN32Text(); renderWIN32(); renderWIN32Include(); } void Marker::renderWIN32Include() { if (!(properties & INCLUDE)) { win32Color(parent->getXColor("red")); Vector ll = handle[0]; Vector ur = handle[2]; win32DrawLine(ll,ur); } } void Marker::renderWIN32Text() { if (text && *text && tkfont_) { win32Color(parent->getXColor(colorName)); win32Font(tkfont_); Tk_FontMetrics metrics; Tk_GetFontMetrics(tkfont_, &metrics); int width = Tk_TextWidth(tkfont_, text, strlen(text)); BBox bb = bbox; Vector bbc = bb.center(); Vector tt = Vector(bbc[0], bbox.ll[1]) * Translate(-width/2., -metrics.descent); win32DrawText(tt, 0, text); } } void Marker::renderWIN32Arrow(const Vector& p1, const Vector& p2, Coord::InternalSystem sys) { Vector* vv = arrow(p1,p2,sys); Vector dd[6]; for (int ii=0; ii<6; ii++) dd[ii] = vv[ii]; win32FillPolygon(dd,6); delete [] vv; } void Marker::renderWIN32GC() { // set width, color, dash win32Color(parent->getXColor(colorName)); if ((properties & SOURCE) && !(properties & DASH)) renderWIN32LineNoDash(); else renderWIN32LineDash(); } void Marker::renderWIN32LineDash() { win32Width(lineWidth); win32Dash(dlist,2); } void Marker::renderWIN32LineNoDash() { win32Width(lineWidth); win32Dash(NULL,0); } #endif // Support void Marker::updateBBox() { // generate handles updateHandles(); // bound handles bbox = BBox(handle[0]); for (int ii=1; iicentroid(center); updateBBox(); doCallBack(CallBack::MOVECB); } void Marker::moveTo(const Vector& v) { center=v; updateBBox(); doCallBack(CallBack::MOVECB); } void Marker::moveBegin() { doCallBack(CallBack::MOVEBEGINCB); } void Marker::move(const Vector& v) { center+=v; updateBBox(); doCallBack(CallBack::MOVECB); } void Marker::moveEnd() { doCallBack(CallBack::MOVEENDCB); } void Marker::editBegin(int) { doCallBack(CallBack::EDITBEGINCB); } void Marker::edit(const Vector& v, int h) { doCallBack(CallBack::EDITCB); } void Marker::editEnd() { doCallBack(CallBack::EDITENDCB); } void Marker::rotateBegin() { doCallBack(CallBack::ROTATEBEGINCB); } void Marker::rotate(const Vector& v, int h) { // v is in ref coords // handles are in canvas coords double a = (v * Translate(-center) * FlipY()).angle(); double b = ((parent->mapToRef(handle[h-1],Coord::CANVAS) * Translate(-center) * FlipY())).angle(); angle -= a-b; updateBBox(); doCallBack(CallBack::ROTATECB); } void Marker::rotateEnd() { doCallBack(CallBack::ROTATEENDCB); } void Marker::select() { // only call the CB if not already selected if (!selected) doCallBack(CallBack::SELECTCB); selected = 1; } void Marker::unselect() { // only call the CB if already selected if (selected) doCallBack(CallBack::UNSELECTCB); selected = 0; } void Marker::toggleSelect() { selected = !selected; if (selected) doCallBack(CallBack::SELECTCB); else doCallBack(CallBack::UNSELECTCB); } void Marker::highlite() { // only call the CB if not already highlited if (!highlited) doCallBack(CallBack::HIGHLITECB); highlited = 1; } void Marker::unhighlite() { // only call the CB if already highlited if (highlited) doCallBack(CallBack::UNHIGHLITECB); highlited = 0; } void Marker::toggleHighlite() { highlited = !highlited; if (highlited) doCallBack(CallBack::HIGHLITECB); else doCallBack(CallBack::UNHIGHLITECB); } void Marker::key() { doCallBack(CallBack::KEYCB); } Vector Marker::getHandle(int h) { if (hgetColor(colorName); doCallBack(CallBack::COLORCB); } void Marker::setLineWidth(int w) { lineWidth = w; doCallBack(CallBack::LINEWIDTHCB); } void Marker::setFont(const char* f) { initFonts(f); updateBBox(); doCallBack(CallBack::FONTCB); } void Marker::initFonts(const char* ff) { if (tkfont_) Tk_FreeFont(tkfont_); tkfont_ = NULL; if (psfont_) Tk_FreeFont(psfont_); psfont_ = NULL; const char* dd = "helvetica 9 roman normal"; if (!ff) ff = dd; psfont_ = Tk_GetFont(parent->interp, parent->tkwin, ff); // determine tkfont from psfont string x(ff); istringstream str(x); char family[16] = ""; int size = 0; char weight[16] = ""; char slant[16] = ""; str >> family >> size >> weight >> slant; // old regions files will not have a slant if (strncmp(slant,"roma",4) && strncmp(slant,"ital",4)) strcpy(slant,"roman"); #ifdef MAC_OSX_TK size *= parent->getDisplayRatio(); #endif char* ptr =NULL; if (!strncmp(family,"helvetica",4)) ptr = parent->options->helvetica; else if (!strncmp(family,"times",4)) ptr = parent->options->times; else if (!strncmp(family,"courier",4)) ptr = parent->options->courier; else ptr = parent->options->helvetica; ostringstream fstr; fstr << '{' << ptr << '}' << ' ' << size << ' ' << weight << ' ' << slant << ends; tkfont_ = Tk_GetFont(parent->getInterp(), parent->getTkwin(), fstr.str().c_str()); } const char* Marker::getFont() { if (psfont_) return Tk_NameOfFont(psfont_); else return NULL; } void Marker::addTag(const char* tg) { Tag* t = new Tag(tg); tags.append(t); } void Marker::editTag(const char* from, const char* to) { // change any tags { Tag* t = tags.head(); while (t) { if (!strcmp(t->tag(),from)) { t->set(to); } t=t->next(); } } // now, remove duplicates { Tag* t = tags.head(); while (t) { Tag* tt=t->next(); while (tt) { if (!strcmp(t->tag(),tt->tag())) { Tag* ntt = tags.extractNext(tt); delete tt; tt = ntt; } else tt=tt->next(); } t=t->next(); } } } void Marker::deleteTags() { tags.deleteAll(); } void Marker::deleteTag(const char* tg) { Tag* t = tags.head(); while (t) { if (!strcmp(t->tag(),tg)) { tags.extractNext(t); delete t; return; } t = t->next(); } } void Marker::deleteTag(int w) { Tag* t = tags.head(); for (int i=0; inext(); else break; if (t) { tags.extractNext(t); delete t; } } const char* Marker::getTag() { Tag* t = tags.head(); if (t) return t->tag(); else return NULL; } const char* Marker::getNextTag() { Tag* t = tags.next(); if (t) return t->tag(); else return NULL; } const char* Marker::getTag(int w) { Tag* t = tags.head(); for (int i=0; inext(); else break; if (t) return t->tag(); else return NULL; } int Marker::hasTag(const char* tg) { Tag* t = tags.head(); while (t) { if (!strcmp(t->tag(),tg)) return 1; t = t->next(); } return 0; } int Marker::onHandle(const Vector& v) { // return handle number // work last to first for annuli for (int ii=numHandle-1; ii>=0; ii--) { BBox bb(handle[ii]); bb.expand(parent->markerEpsilon); if (bb.isIn(v)) return ii+1; } return 0; } int Marker::getProperty(unsigned short which) { return (properties & which) ? 1 : 0; } void Marker::setText(const char* str) { if (text) delete [] text; text = dupstr(str); updateBBox(); doCallBack(CallBack::TEXTCB); } void Marker::setProperty(unsigned short prop, int value) { if (value) properties |= prop; else properties &= ~prop; if (prop == FIXED) // bbox will change updateBBox(); doCallBack(CallBack::PROPERTYCB); } int Marker::addCallBack(CallBack::Type t, const char* proc, const char* arg) { CallBack* cb = new CallBack(parent->interp, t, proc, arg); if (cb) { callbacks.append(cb); return TCL_OK; } return TCL_ERROR; } void Marker::deleteCallBack(CallBack::Type t) { CallBack* cb = callbacks.head(); while (cb) { if (cb->type() == t) { CallBack* next = callbacks.extractNext(cb); delete cb; cb = next; } else cb = cb->next(); } } int Marker::deleteCallBack(CallBack::Type t, const char* proc) { CallBack* cb = callbacks.head(); while (cb) { if (cb->type() == t && (!strcmp(cb->proc(), proc))) { callbacks.extractNext(cb); delete cb; return TCL_OK; } else cb = cb->next(); } return TCL_ERROR; } int Marker::isIn(const Vector& vv, Coord::InternalSystem sys) { Vector rr = parent->mapToRef(vv,sys); Vector ss = parent->mapFromRef(rr,Coord::CANVAS); return bbox.isIn(ss); } // assume Coord::REF int Marker::isIn(const Vector& vv, const Matrix& bck) { Vector ss = parent->mapFromRef(vv,Coord::CANVAS); return bbox.isIn(ss); } int Marker::isVisible(const BBox& b) { // assume visible, prove otherwise // all coords are in canvas coords BBox bb(b); return !((allBBox.ur[0] < bb.ll[0]) || (allBBox.ll[0] > bb.ur[0]) || (allBBox.ur[1] < bb.ll[1]) || (allBBox.ll[1] > bb.ur[1])); } void Marker::doCallBack(CallBack::Type t) { if (!doCB) return; ostringstream str; str << id << ends; CallBack* cb=callbacks.head(); while (cb) { if (cb->type() == t) if (cb->eval(str.str().c_str())) { ostringstream estr; estr << "Unable to eval Marker CallBack " << cb->proc() << " : " << Tcl_GetStringResult(parent->interp) << ends; internalError(estr.str().c_str()); } cb=cb->next(); } } double Marker::calcAngle() { switch (parent->getOrientation()) { case Coord::NORMAL: case Coord::XY: return angle + parent->getRotation(); case Coord::XX: case Coord::YY: return -angle + parent->getRotation(); } } Vector Marker::modifyArrow(const Vector& p1, const Vector& p2, Coord::InternalSystem sys) { const int tip = 6; // length from end of line to tip of arrow Vector aa = parent->mapFromRef(p1,sys); Vector bb = parent->mapFromRef(p2,sys); Vector nn = (bb-aa).normalize(); double ll = (bb-aa).length(); return nn * Scale(ll-tip) * Translate(aa); } Vector* Marker::arrow(const Vector& p1, const Vector& p2, Coord::InternalSystem sys) { switch (parent->frameType()) { case Base::F2D: return arrow2D(p1,p2,sys); case Base::F3D: return arrow3D(p1,p2,sys); } } Vector* Marker::arrow2D(const Vector& p1, const Vector& p2, Coord::InternalSystem sys) { Vector aa = ((FrameBase*)parent)->mapFromRef(p1,sys); Vector bb = ((FrameBase*)parent)->mapFromRef(p2,sys); 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 Vector vv[6]; vv[0] = Vector(0, tip); vv[1] = Vector(-wc, 0); vv[2] = Vector(-wt, -tail); vv[3] = Vector(0, 0); vv[4] = Vector(wt, -tail); vv[5] = Vector(wc, 0); Vector dd = (aa-bb).normalize(); Matrix mm = Translate(0,-tip) * Scale(1.5) * Rotate(-M_PI/2) * Rotate(-dd.angle()) * Translate(bb); Vector* ww = new Vector[6]; for (int ii=0; ii<6; ii++) ww[ii] = vv[ii]*mm; return ww; } Vector* Marker::arrow3D(const Vector& p1, const Vector& p2, Coord::InternalSystem sys) { Vector p3; if (((p2-p1)[0]) == 0) p3 = p1+Vector(1,0); else p3 = p1+Vector(0,1); Vector3d aa = ((Frame3dBase*)parent)->mapFromRef3d(p1,sys); Vector3d bb = ((Frame3dBase*)parent)->mapFromRef3d(p2,sys); Vector3d cc = ((Frame3dBase*)parent)->mapFromRef3d(p3,sys); 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 // build in Y-Z plane, align on z axis Vector3d vv[6]; vv[0] = Vector3d(0,0,tip); vv[1] = Vector3d(0,-wc,0); vv[2] = Vector3d(0,-wt,-tail); vv[3] = Vector3d(0,0,0); vv[4] = Vector3d(0,wt,-tail); vv[5] = Vector3d(0,wc,0); Vector3d l1 = (aa-bb).normalize(); Vector3d l2 = (aa-cc).normalize(); Vector3d rz = -l1; Vector3d rx = (cross(l1,l2)).normalize(); Vector3d ry = cross(rz,rx); Matrix3d rr(rx,ry,rz); Matrix3d mm = Translate3d(0,0,-tip) * Scale3d(1.5) * rr.invert() * Translate3d(bb); Vector* ww = new Vector[6]; for (int ii=0; ii<6; ii++) ww[ii] = vv[ii]*mm; return ww; } void Marker::analysisXYEEResult(char* xname, char* yname, char* xcname, char* ycname, double* x, double* y, double* xc, double* yc, int num) { Blt_Vector* xx; Blt_GetVector(parent->getInterp(), xname, &xx); Blt_ResetVector(xx, x, num, num*sizeof(double), TCL_DYNAMIC); Blt_Vector* yy; Blt_GetVector(parent->getInterp(), yname, &yy); Blt_ResetVector(yy, y, num, num*sizeof(double), TCL_DYNAMIC); Blt_Vector* xxc; Blt_GetVector(parent->getInterp(), xcname, &xxc); Blt_ResetVector(xxc, xc, num, num*sizeof(double), TCL_DYNAMIC); Blt_Vector* yyc; Blt_GetVector(parent->getInterp(), ycname, &yyc); Blt_ResetVector(yyc, yc, num, num*sizeof(double), TCL_DYNAMIC); } void Marker::analysisXYResult(char* xname, char* yname, double* x, double* y, int num) { Blt_Vector* xx; Blt_GetVector(parent->getInterp(), xname, &xx); Blt_ResetVector(xx, x, num, num*sizeof(double), TCL_DYNAMIC); Blt_Vector* yy; Blt_GetVector(parent->getInterp(), yname, &yy); Blt_ResetVector(yy, y, num, num*sizeof(double), TCL_DYNAMIC); } void Marker::analysisXYEResult(char* xname, char* yname, char* ename, double* x, double* y, double* e, int num) { Blt_Vector* xx; Blt_GetVector(parent->getInterp(), xname, &xx); Blt_ResetVector(xx, x, num, num*sizeof(double), TCL_DYNAMIC); Blt_Vector* yy; Blt_GetVector(parent->getInterp(), yname, &yy); Blt_ResetVector(yy, y, num, num*sizeof(double), TCL_DYNAMIC); Blt_Vector* ee; Blt_GetVector(parent->getInterp(), ename, &ee); Blt_ResetVector(ee, e, num, num*sizeof(double), TCL_DYNAMIC); } void Marker::analysisXYEResult(double* x, double* y, double* e, int num) { for (int ii=0; iiinterp, str.str().c_str(), NULL); } } Matrix Marker::fwdMatrix() { return Rotate(angle) * FlipY() * Translate(center); } Matrix Marker::bckMatrix() { return Translate(-center) * FlipY() * Rotate(-angle); } Vector Marker::fwdMap(const Vector& vv, Coord::InternalSystem sys) { return parent->mapFromRef(vv * Rotate(angle) * FlipY() * Translate(center),sys); } Vector Marker::bckMap(const Vector& vv, Coord::InternalSystem sys) { return parent->mapToRef(vv,sys) * Translate(-center) * FlipY() * Rotate(-angle); } void Marker::setMatrices(Coord::InternalSystem sys, Matrix* fwd, Matrix* bck) { switch (sys) { case Coord::WIDGET: *fwd = parent->refToWidget; *bck = parent->widgetToRef; break; case Coord::CANVAS: *fwd = parent->refToCanvas; *bck = parent->canvasToRef; break; case Coord::WINDOW: *fwd = parent->refToWindow; *bck = parent->windowToRef; break; case Coord::MAGNIFIER: *fwd = parent->refToMagnifier; *bck = parent->magnifierToRef; break; default: // na break; } } // list void Marker::listRADEC(FitsImage* ptr, const Vector& vv, Coord::CoordSystem sys, Coord::SkyFrame sky, Coord::SkyFormat format) { char buf[64]; ptr->mapFromRef(vv,sys,sky,format,buf); string x(buf); istringstream wcs(x); wcs >> ra >> dec; } void Marker::listRADECPros(FitsImage* ptr, const Vector& vv, Coord::CoordSystem sys, Coord::SkyFrame sky, Coord::SkyFormat format) { char buf[64]; char decc[32]; ptr->mapFromRef(vv,sys,sky,format,buf); string x(buf); istringstream wcs(x); wcs >> ra >> decc; if (decc[0]=='+') strncpy(dec,decc+1,32); else strncpy(dec,decc,32); } void Marker::listPre(ostream& str, Coord::CoordSystem sys, Coord::SkyFrame sky, FitsImage* ptr, int strip, int hash) { // no props for semicolons if (!strip) { FitsImage* fits = parent->findFits(); if (fits && fits->nextMosaic()) { switch (sys) { case Coord::IMAGE: case Coord::PHYSICAL: case Coord::DETECTOR: case Coord::AMPLIFIER: str << "# tile " << parent->findFits(ptr) << endl; break; default: if (!parent->findFits()->hasWCSCel(sys)) str << "# tile " << parent->findFits(ptr) << endl; } } if (hash) str << "# "; } if (!(properties&INCLUDE)) str << '-'; } void Marker::listPost(ostream& str, int conj, int strip) { // no props for semicolons if (!strip) { if (conj) str << " ||"; listProperties(str,1); } else { if (conj) str << "||"; else str << ';'; } } void Marker::listProperties(ostream& str, int hash) { if (strncmp("green",colorName,5) || dlist[0] != 8 || dlist[1] != 3 || (lineWidth != 1) || strncmp("helvetica 10 normal roman",getFont(),25) || (text && *text) || !(properties&SELECT) || !(properties&HIGHLITE) || (properties&DASH) || (properties&FIXED) || !(properties&EDIT) || !(properties&MOVE) || !(properties&ROTATE) || !(properties&DELETE) || !(properties&SOURCE) || (tags.count() > 0) || (comment && *comment)) { if (hash) str << " #"; listProps(str); } str << endl; } void Marker::listProps(ostream& str) { if (strncmp("green",colorName,5)) str << " color=" << colorName; if (dlist[0] != 8 || dlist[1] != 3) str << " dashlist=" << dlist[0] << ' ' << dlist[1]; if (lineWidth != 1) str << " width=" << lineWidth; if (strncmp("helvetica 10 normal roman", getFont(), 25)) str << " font=\"" << getFont() << '"'; if (text && *text) // only list text if there is something to list str << " text={" << text << '}'; if (!(properties&SELECT)) str << " select=0"; if (!(properties&HIGHLITE)) str << " highlite=0"; if (properties&DASH) str << " dash=1"; if (properties&FIXED) str << " fixed=1"; if (!(properties&EDIT)) str << " edit=0"; if (!(properties&MOVE)) str << " move=0"; if (!(properties&ROTATE)) str << " rotate=0"; if (!(properties&DELETE)) str << " delete=0"; if (!(properties&SOURCE)) str << " background"; // tags Tag* t = tags.head(); while (t) { str << " tag={" << t->tag() << '}'; t = t->next(); } if (comment && *comment) str << ' ' << comment; } void Marker::listCiaoPre(ostream& str) { if (!(properties&INCLUDE)) str << '-'; } void Marker::listCiaoPost(ostream& str, int strip) { str << (strip ? ';' : '\n'); } void Marker::listProsPost(ostream& str, int strip) { str << (strip ? ';' : '\n'); } void Marker::listSAOtngPre(ostream& str, int strip) { if (!strip && text && *text) str << '#' << text << endl; if (properties&INCLUDE) str << '+'; else str << '-'; } void Marker::listSAOtngPost(ostream& str, int strip) { if (!strip) { str << " # "; if (comment && *comment) str << comment; else if (!(properties&SOURCE)) str << "background"; else str << colorName; } str << (strip ? ';' : '\n'); } void Marker::listSAOimagePre(ostream& str) { if (!(properties&INCLUDE)) str << '-'; } void Marker::listSAOimagePost(ostream& str, int strip) { str << (strip ? ';' : '\n'); } void Marker::listXY(ostream& str, Coord::CoordSystem sys, Coord::SkyFrame sky, Coord::SkyFormat format, int strip) { FitsImage* ptr = parent->findFits(); switch (sys) { case Coord::IMAGE: case Coord::PHYSICAL: case Coord::DETECTOR: case Coord::AMPLIFIER: str << setprecision(8) << ptr->mapFromRef(center,sys); break; default: if (ptr->hasWCS(sys)) { if (ptr->hasWCSCel(sys)) { switch (format) { case Coord::DEGREES: str << setprecision(10) << ptr->mapFromRef(center,sys,sky); break; case Coord::SEXAGESIMAL: listRADEC(ptr,center,sys,sky,format); str << ra << ' ' << dec; break; } } else { str << setprecision(8) << ptr->mapFromRef(center,sys); } } break; } str << (strip ? ';' : '\n'); } void Marker::XMLRowInit() { for (int ii=0; iifindFits(); if (fits && fits->nextMosaic()) { switch (sys) { case Coord::IMAGE: case Coord::PHYSICAL: case Coord::DETECTOR: case Coord::AMPLIFIER: str << parent->findFits(ptr) << ends; break; default: if (!parent->findFits()->hasWCSCel(sys)) str << parent->findFits(ptr) << ends; break; } } if (XMLCol[col]) delete [] XMLCol[col]; XMLCol[col] = dupstr(str.str().c_str()); } // color { XMLColName col = XMLCOLOR; if (XMLCol[col]) delete [] XMLCol[col]; XMLCol[col] = dupstr(colorName); } // width { ostringstream str; str << lineWidth << ends; XMLColName col = XMLWIDTH; if (XMLCol[col]) delete [] XMLCol[col]; XMLCol[col] = dupstr(str.str().c_str()); } // text if (text && *text) { XMLColName col = XMLTEXT; if (XMLCol[col]) delete [] XMLCol[col]; XMLCol[col] = dupstr(text); } // font { XMLColName col = XMLFONT; if (XMLCol[col]) delete [] XMLCol[col]; XMLCol[col] = dupstr(getFont()); } XMLRowProp(XMLSELECT,SELECT); XMLRowProp(XMLHIGHLITE,HIGHLITE); XMLRowProp(XMLEDIT,EDIT); XMLRowProp(XMLMOVE,MOVE); XMLRowProp(XMLROTATE,ROTATE); XMLRowProp(XMLDELETE,DELETE); XMLRowProp(XMLFIXED,FIXED); XMLRowProp(XMLINCLUDE,INCLUDE); XMLRowProp(XMLSOURCE,SOURCE); XMLRowProp(XMLDASH,DASH); // dashlist { ostringstream str; str << dlist[0] << ',' << dlist[1] << ends; XMLColName col = XMLDASHLIST; if (XMLCol[col]) delete [] XMLCol[col]; XMLCol[col] = dupstr(str.str().c_str()); } // tags { ostringstream str; Tag* start = tags.head(); Tag* ptr = start; while (ptr) { if (ptr != start) str << ' '; char* tag = (char*)ptr->tag(); while (*tag) { if (*tag == ' ') str << " "; else str << *tag; tag++; } ptr = ptr->next(); } str << ends; XMLColName col = XMLTAG; if (XMLCol[col]) delete [] XMLCol[col]; XMLCol[col] = dupstr(str.str().c_str()); } // comment if (comment && *comment) { XMLColName col = XMLCOMMENT; if (XMLCol[col]) delete [] XMLCol[col]; XMLCol[col] = dupstr(comment); } } void Marker::XMLRowEnd(ostream& str) { str << ""; for (int ii=0; ii"; if (XMLCol[ii]) { char* ss = XMLQuote(XMLCol[ii]); str << ss; delete [] XMLCol[ii]; delete [] ss; XMLCol[ii] = NULL; } str << ""; } str << "" << endl; } void Marker::XMLRowProp(XMLColName col, Property prop) { if (properties & prop) XMLCol[col] = dupstr("1"); else XMLCol[col] = dupstr("0"); } void Marker::XMLRowPoint(FitsImage* ptr, Coord::CoordSystem sys, Coord::SkyFrame sky, Coord::SkyFormat format, Vector vv) { switch (sys) { case Coord::IMAGE: case Coord::PHYSICAL: case Coord::DETECTOR: case Coord::AMPLIFIER: { Vector v = ptr->mapFromRef(vv,sys); XMLRow(XMLX,v[0],8); XMLRow(XMLY,v[1],8); } break; default: if (ptr->hasWCS(sys)) { if (ptr->hasWCSCel(sys)) { switch (format) { case Coord::DEGREES: { Vector v = ptr->mapFromRef(vv,sys,sky); XMLRow(XMLX,v[0],10); XMLRow(XMLY,v[1],10); } break; case Coord::SEXAGESIMAL: listRADEC(ptr,vv,sys,sky,format); XMLRow(XMLX,ra); XMLRow(XMLY,dec); break; } } else { Vector v = ptr->mapFromRef(vv,sys); XMLRow(XMLX,v[0],8); XMLRow(XMLY,v[1],8); } } } } void Marker::XMLRowPoint(FitsImage* ptr, Coord::CoordSystem sys, Coord::SkyFrame sky, Coord::SkyFormat format, Vector* vv, int cnt) { switch (sys) { case Coord::IMAGE: case Coord::PHYSICAL: case Coord::DETECTOR: case Coord::AMPLIFIER: { double xx[cnt]; double yy[cnt]; for (int ii=0; iimapFromRef(vv[ii],sys); xx[ii] = v[0]; yy[ii] = v[1]; } XMLRow(XMLXV,xx,cnt,8); XMLRow(XMLYV,yy,cnt,8); } break; default: if (ptr->hasWCS(sys)) { if (ptr->hasWCSCel(sys)) { switch (format) { case Coord::DEGREES: { double xx[cnt]; double yy[cnt]; for (int ii=0; iimapFromRef(vv[ii],sys,sky); xx[ii] = v[0]; yy[ii] = v[1]; } XMLRow(XMLXV,xx,cnt,10); XMLRow(XMLYV,yy,cnt,10); } break; case Coord::SEXAGESIMAL: { char* xx[cnt]; char* yy[cnt]; for (int ii=0; iimapFromRef(vv[ii],sys); xx[ii] = v[0]; yy[ii] = v[1]; } XMLRow(XMLXV,xx,cnt,8); XMLRow(XMLYV,yy,cnt,8); } } } } void Marker::XMLRowRadiusX(FitsImage* ptr, Coord::CoordSystem sys, Vector vv) { double rr = ptr->mapLenFromRef(vv[0],sys,Coord::ARCSEC); switch (sys) { case Coord::IMAGE: case Coord::PHYSICAL: case Coord::DETECTOR: case Coord::AMPLIFIER: XMLRow(XMLR,rr,8); break; default: if (ptr->hasWCS(sys)) { if (ptr->hasWCSCel(sys)) XMLRowARCSEC(XMLR,rr); else XMLRow(XMLR,rr,8); } break; } } void Marker::XMLRowRadiusX(FitsImage* ptr, Coord::CoordSystem sys, Vector* vv, int cnt) { double rr[cnt]; for (int ii=0; iimapLenFromRef(vv[ii][0],sys,Coord::ARCSEC); switch (sys) { case Coord::IMAGE: case Coord::PHYSICAL: case Coord::DETECTOR: case Coord::AMPLIFIER: XMLRow(XMLRV,rr,cnt,8); break; default: if (ptr->hasWCS(sys)) { if (ptr->hasWCSCel(sys)) XMLRowARCSEC(XMLRV,rr,cnt); else XMLRow(XMLRV,rr,cnt,8); } break; } } void Marker::XMLRowRadius(FitsImage* ptr, Coord::CoordSystem sys, Vector vv) { Vector v = ptr->mapLenFromRef(vv,sys,Coord::ARCSEC); switch (sys) { case Coord::IMAGE: case Coord::PHYSICAL: case Coord::DETECTOR: case Coord::AMPLIFIER: XMLRow(XMLR,v[0],8); XMLRow(XMLR2,v[1],8); break; default: if (ptr->hasWCS(sys)) { if (ptr->hasWCSCel(sys)) { XMLRowARCSEC(XMLR,v[0]); XMLRowARCSEC(XMLR2,v[1]); } else { XMLRow(XMLR,v[0],8); XMLRow(XMLR2,v[1],8); } } break; } } void Marker::XMLRowRadius(FitsImage* ptr, Coord::CoordSystem sys, Vector* vv, int cnt) { double rr[cnt]; double rr2[cnt]; for (int ii=0; iimapLenFromRef(vv[ii],sys,Coord::ARCSEC); rr[ii] = v[0]; rr2[ii] = v[1]; } switch (sys) { case Coord::IMAGE: case Coord::PHYSICAL: case Coord::DETECTOR: case Coord::AMPLIFIER: XMLRow(XMLRV,rr,cnt,8); XMLRow(XMLRV2,rr2,cnt,8); break; default: if (ptr->hasWCS(sys)) { if (ptr->hasWCSCel(sys)) { XMLRowARCSEC(XMLRV,rr,cnt); XMLRowARCSEC(XMLRV2,rr2,cnt); } else { XMLRow(XMLRV,rr,cnt,8); XMLRow(XMLRV2,rr2,cnt,8); } } break; } } void Marker::XMLRowAng(Coord::CoordSystem sys, Coord::SkyFrame sky) { XMLRow(XMLANG, radToDeg(parent->mapAngleFromRef(angle,sys,sky)),8); } void Marker::XMLRowAng(Coord::CoordSystem sys, Coord::SkyFrame sky, double* ang, int cnt) { double aa[cnt]; for (int ii=0; iimapAngleFromRef(ang[ii],sys,sky)); XMLRow(XMLANGV,aa,cnt,8); } char* Marker::XMLQuote(char* src) { char* dest = new char[strlen(src)*7+1]; char* sptr = src; char* dptr = dest; while (sptr && *sptr) { if (*sptr == '&') { // special case, char entities if (*(sptr+1) == '#') { *dptr++ = *sptr; } else { memcpy(dptr,"&",5); dptr += 5; } } else if (*sptr == '<') { memcpy(dptr,"<",4); dptr += 4; } else if (*sptr == '>') { memcpy(dptr,">",4); dptr += 4; } else if (*sptr == '\'') { memcpy(dptr,"'",6); dptr += 6; } else if (*sptr == '"') { memcpy(dptr,""",6); dptr += 6; } else *dptr++ = *sptr; sptr++; } *dptr = '\0'; return dest; } // special composite funtionallity void Marker::setComposite(const Matrix& mx, double aa) { center *= mx; angle += aa; updateBBox(); } void Marker::setComposite(const char* clr, int w, int h) { lineWidth = w; if (colorName) delete [] colorName; colorName = dupstr(clr); color = parent->getColor(colorName); highlited = h; }