// Copyright (C) 1999-2017 // Smithsonian Astrophysical Observatory, Cambridge, MA, USA // For conditions of distribution and use, see copyright notice in "copyright" #include #include "text.h" #include "fitsimage.h" EXTERN void TkDrawAngledChars(Display *display, Drawable drawable, GC gc, Tk_Font tkfont, const char *source, int numBytes, double x, double y, double angle); Text::Text(const Text& a) : Marker(a) { rotate = a.rotate; } Text::Text(Base* p, const Vector& ctr, double ang, int rot, const char* clr, int* dsh, int wth, const char* fnt, const char* txt, unsigned short prop, const char* cmt, const List& tg, const List& cb) : Marker(p, ctr, ang, clr, dsh, wth, fnt, txt, prop, cmt, tg, cb) { strcpy(type_,"text"); handle = new Vector[4]; numHandle = 4; rotate = rot; updateBBox(); } void Text::renderX(Drawable drawable, Coord::InternalSystem sys, RenderMode mode) { if (text && *text && tkfont_) { GC lgc = renderXGC(mode); XSetFont(display, lgc, Tk_FontId(tkfont_)); // origin is center of text Tk_FontMetrics metrics; Tk_GetFontMetrics(tkfont_, &metrics); int width = Tk_TextWidth(tkfont_, text, strlen(text)); int delta = (metrics.ascent-metrics.descent)/2.; double ang = rotate ? calcAngle() : 0; Vector cc = parent->mapFromRef(center,sys); Matrix mm = Translate(-cc) * Translate(-width/2., delta) * Rotate(ang) * Translate(cc); Vector vv = cc * mm; TkDrawAngledChars(display, drawable, lgc, tkfont_, text, strlen(text), vv[0], vv[1], radToDeg(ang)); } } void Text::renderPS(int mode) { renderPSGC(mode); if (text && *text && psfont_) { ostringstream str; const char* ff = Tk_NameOfFont(psfont_); str << '/' << psFontName(ff) << " findfont " << int(psFontSize(ff)*parent->getDisplayRatio()) << " scalefont setfont" << endl; double ang = rotate ? calcAngle() : 0; Vector cc = (parent->mapFromRef(center,Coord::CANVAS)).TkCanvasPs(parent->canvas); str << "gsave" << endl << "newpath " << endl << cc << " moveto" << endl << '(' << psQuote(text) << ')' << endl << "dup true charpath pathbbox " << endl << "closepath " << endl << "3 -1 roll sub 3.6 div neg " << endl << "3 1 roll sub 2 div exch " << endl << cc << " moveto " << endl << radToDeg(ang) << " rotate " << endl << " rmoveto show" << endl << "grestore" << endl; str << ends; Tcl_AppendResult(parent->interp, str.str().c_str(), NULL); } } #ifdef MAC_OSX_TK void Text::renderMACOSX() { renderMACOSXGC(); if (text && *text && psfont_) { 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)); double ang = rotate ? calcAngle() : 0; Vector cc = parent->mapFromRef(center,Coord::CANVAS); Matrix mm = Translate(-cc) * Translate(-width/2.,metrics.descent) * Rotate(ang) * Translate(cc); macosxDrawText(cc*mm, 0, text); } } #endif #ifdef __WIN32 void Text::renderWIN32() { renderWIN32GC(); if (text && *text && tkfont_) { win32Font(tkfont_); Tk_FontMetrics metrics; Tk_GetFontMetrics(tkfont_, &metrics); int width = Tk_TextWidth(tkfont_, text, strlen(text)); int delta = (metrics.ascent-metrics.descent)/2.; double ang = rotate ? calcAngle() : 0; Vector cc = parent->mapFromRef(center,Coord::CANVAS); Matrix mm = Translate(-cc) * Translate(-width/2., delta) * Rotate(ang) * Translate(cc); Vector vv = cc * mm; win32DrawText(vv, 0, text); } } #endif // Support void Text::updateHandles() { Vector cc = parent->mapFromRef(center,Coord::CANVAS); if (text && *text && tkfont_) { Tk_FontMetrics metrics; Tk_GetFontMetrics(tkfont_, &metrics); int width = Tk_TextWidth(tkfont_, text, strlen(text)); Vector s(width, metrics.linespace); double ang = rotate ? calcAngle() : 0; Matrix mm = Rotate(ang) * Translate(cc); handle[0] = Vector(-s[0],-s[1])/2 * mm; handle[1] = Vector( s[0],-s[1])/2 * mm; handle[2] = Vector( s[0], s[1])/2 * mm; handle[3] = Vector(-s[0], s[1])/2 * mm; } else { Vector s(10,10); Matrix mm = Translate(cc); handle[0] = Vector(-s[0],-s[1])/2 * mm; handle[1] = Vector( s[0],-s[1])/2 * mm; handle[2] = Vector( s[0], s[1])/2 * mm; handle[3] = Vector(-s[0], s[1])/2 * mm; } } void Text::calcAllBBox() { allBBox = bbox; } int Text::isIn(const Vector& vv) { if (text && *text && tkfont_) { // origin is center of text Tk_FontMetrics metrics; Tk_GetFontMetrics(tkfont_, &metrics); float ww = Tk_TextWidth(tkfont_, text, strlen(text))/2./parent->zoom_[0]; float hh = metrics.linespace/2./parent->zoom_[1]; Vector pp = bckMap(vv,Coord::CANVAS); if (pp[0]<-ww || pp[0]>ww || pp[1]<-hh || pp[1]>hh) return 0; else return 1; } else return 0; } void Text::setRotate(int rot) { rotate = rot ? 1 : 0; updateBBox(); } // list void Text::list(ostream& str, Coord::CoordSystem sys, Coord::SkyFrame sky, Coord::SkyFormat format, int conj, int strip) { if (!text || !*text) return; if (!strip) { FitsImage* ptr = parent->findFits(sys,center); listPre(str, sys, sky, ptr, strip, 1); switch (sys) { case Coord::IMAGE: case Coord::PHYSICAL: case Coord::DETECTOR: case Coord::AMPLIFIER: listNonCel(ptr, str, sys); break; default: if (ptr->hasWCSCel(sys)) { switch (format) { case Coord::DEGREES: { Vector vv = ptr->mapFromRef(center,sys,sky); str << type_ << '(' << setprecision(10) << vv << ')'; } break; case Coord::SEXAGESIMAL: listRADEC(ptr,center,sys,sky,format); str << type_ << '(' << ra << ',' << dec << ')'; break; } } else listNonCel(ptr, str, sys); } if (conj) str << " ||"; if (angle != 0) str << " textangle=" << radToDeg(parent->mapAngleFromRef(angle,sys,sky)); if (!rotate) str << " textrotate=" << 0; listProperties(str, 0); } } void Text::listNonCel(FitsImage* ptr, ostream& str, Coord::CoordSystem sys) { Vector vv = ptr->mapFromRef(center,sys); str << type_ << '(' << setprecision(8) << vv << ')'; } void Text::listXML(ostream& str, Coord::CoordSystem sys, Coord::SkyFrame sky, Coord::SkyFormat format) { FitsImage* ptr = parent->findFits(sys,center); XMLRowInit(); XMLRow(XMLSHAPE,type_); XMLRowCenter(ptr,sys,sky,format); XMLRowAng(sys,sky); XMLRow(XMLPARAM,rotate); XMLRowProps(ptr,sys); XMLRowEnd(str); } void Text::listSAOtng(ostream& str, Coord::CoordSystem sys, Coord::SkyFrame sky, Coord::SkyFormat format, int strip) { if (!text || !*text) return; FitsImage* ptr = parent->findFits(); if (properties&INCLUDE) str << '+'; else str << '-'; switch (sys) { case Coord::IMAGE: case Coord::PHYSICAL: case Coord::DETECTOR: case Coord::AMPLIFIER: { Vector vv = ptr->mapFromRef(center,Coord::IMAGE); str << type_ << '(' << setprecision(8) << vv << ", \"" << text << "\")"; } break; default: if (ptr->hasWCSCel(sys)) { switch (format) { case Coord::DEGREES: { Vector vv = ptr->mapFromRef(center,sys,sky); str << type_ << '(' << setprecision(10) << vv << ", \"" << text << "\")"; } break; case Coord::SEXAGESIMAL: listRADEC(ptr,center,sys,sky,format); str << type_ << '(' << ra << ',' << dec << ", \"" << text << "\")"; break; } } } listSAOtngPost(str, strip); }