diff options
Diffstat (limited to 'tksao/util/gridbase.C')
-rw-r--r-- | tksao/util/gridbase.C | 461 |
1 files changed, 461 insertions, 0 deletions
diff --git a/tksao/util/gridbase.C b/tksao/util/gridbase.C new file mode 100644 index 0000000..a941755 --- /dev/null +++ b/tksao/util/gridbase.C @@ -0,0 +1,461 @@ +// Copyright (C) 1999-2016 +// Smithsonian Astrophysical Observatory, Cambridge, MA, USA +// For conditions of distribution and use, see copyright notice in "copyright" + +#include "gridbase.h" +#include "attribute.h" +#include "widget.h" +#include "util.h" + +EXTERN void TkDrawAngledChars(Display *display, + Drawable drawable, GC gc, Tk_Font tkfont, + const char *source, int numBytes, double x, + double y, double angle); +extern "C" { + #include "ast.h" + #include "grf.h" +} + +GridBase::GridBase(Widget* pp) : parent_(pp) +{ + option_ = NULL; + + renderMode_ = X11; + line_ = new Attribute(parent_); + text_ = new Attribute(parent_); + + gridGC_ = XCreateGC(parent_->getDisplay(), Tk_WindowId(parent_->getTkwin()), + 0, NULL); + pixmap_ = 0; + + mode_ = Widget::RGB; +} + +GridBase::GridBase(Widget* pp, const char* op) : parent_(pp) +{ + option_ = dupstr(op); + + renderMode_ = X11; + line_ = new Attribute(parent_); + text_ = new Attribute(parent_); + + gridGC_ = XCreateGC(parent_->getDisplay(), Tk_WindowId(parent_->getTkwin()), + 0, NULL); + pixmap_ = 0; + + mode_ = Widget::RGB; +} + +GridBase::~GridBase() +{ + if (option_) + delete [] option_; + + if (gridGC_) + XFreeGC(parent_->getDisplay(), gridGC_); + + if (line_) + delete line_; + if (text_) + delete text_; +} + +int GridBase::gAttr(int which, double value, double* old, int prim) +{ + Attribute* attr; + switch (prim) { + case GRF__TEXT: + attr = text_; + + switch (which) { + case GRF__STYLE: + break; + case GRF__WIDTH: + break; + case GRF__SIZE: + if (old) + *old = attr->size(); + if (value != AST__BAD) + attr->setSize(value); + break; + case GRF__FONT: + if (old) + *old = attr->font(); + if (value != AST__BAD) + attr->setFont(value); + break; + case GRF__COLOUR: + if (old) + *old = attr->colour(); + if (value != AST__BAD) + attr->setColour(value); + break; + } + + break; + case GRF__LINE: + attr = line_; + + switch (which) { + case GRF__STYLE: + if (old) + *old = attr->style(); + if (value != AST__BAD) + attr->setStyle(value); + break; + case GRF__WIDTH: + if (old) + *old = attr->width(); + if (value != AST__BAD) + attr->setWidth(value); + break; + case GRF__SIZE: + break; + case GRF__FONT: + break; + case GRF__COLOUR: + if (old) + *old = attr->colour(); + if (value != AST__BAD) + attr->setColour(value); + break; + } + + break; + } + + return 1; +} + +int GridBase::gCap(int cap, int value) +{ + switch (cap) { + case GRF__SCALES: + return 0; + case GRF__MJUST: + return 1; + case GRF__ESC: + return 0; + } + return 0; +} + +// X11 Render functions + +int GridBase::x11Line(int n, float* x, float* y) +{ + if (n<2 || !x || !y) + return 1; + + XSetForeground(parent_->getDisplay(), gridGC_, line_->color()); + int w = (int)line_->width(); + if (w<1) + w = 1; + switch (line_->style()) { + case Attribute::SOLID: + XSetLineAttributes(parent_->getDisplay(), gridGC_, w, + LineSolid, CapButt, JoinMiter); + break; + case Attribute::DASH: + XSetLineAttributes(parent_->getDisplay(), gridGC_, w, + LineOnOffDash, CapButt, JoinMiter); + char dlist[] = {8,3}; + XSetDashes(parent_->getDisplay(), gridGC_, 0, dlist, 2); + break; + } + + for (int i=0; i<n-1; i++) { + Vector s = Vector(x[i],y[i]).round(); + Vector e = Vector(x[i+1],y[i+1]).round(); + XDrawLine(parent_->getDisplay(), pixmap_, gridGC_, + (int)s[0],(int)s[1],(int)e[0],(int)e[1]); + } + + return 1; +} + +int GridBase::x11Text(const char* txt, float x, float y, + const char* just, Vector up) +{ + XSetFont(parent_->getDisplay(), gridGC_, Tk_FontId(text_->tkfont())); + XSetForeground(parent_->getDisplay(), gridGC_, text_->color()); + + Vector vv = Vector(x,y); + double angle = calcTextAngle(just, up); + Vector cc = vv * calcTextPos(vv, angle, txt, just, up, text_->tkfont()); + + TkDrawAngledChars(parent_->getDisplay(), pixmap_, gridGC_, text_->tkfont(), + txt, strlen(txt), + cc[0], cc[1], radToDeg(angle)); + return 1; +} + +// PS Render functions + +int GridBase::psLine(int n, float* x, float* y) +{ + if (n<2 || !x || !y) + return 1; + + psColor(line_); + { + ostringstream str; + str << line_->width() << " setlinewidth" << endl << ends; + Tcl_AppendResult(parent_->getInterp(), str.str().c_str(), NULL); + } + { + ostringstream str; + switch (line_->style()) { + case Attribute::SOLID: + str << "[] 0 setdash" << endl << ends; + break; + case Attribute::DASH: + str << "[8 3] 0 setdash" << endl << ends; + break; + } + Tcl_AppendResult(parent_->getInterp(), str.str().c_str(), NULL); + } + + for (int i=0; i<n; i++) { + Vector v = Vector(x[i],y[i]) * matrix_; + + ostringstream str; + if (i == 0) { + str << "newpath " << endl; + str << v.TkCanvasPs(parent_->getCanvas()) << " moveto" << endl << ends; + } + else + str << v.TkCanvasPs(parent_->getCanvas()) << " lineto" << endl << ends; + + Tcl_AppendResult(parent_->getInterp(), str.str().c_str(), NULL); + } + + ostringstream str; + str << "stroke" << endl << ends; + Tcl_AppendResult(parent_->getInterp(), str.str().c_str(), NULL); + + return 1; +} + +int GridBase::psText(const char* txt, float x, float y, + const char* just, Vector up) +{ + Tcl_DString psdstr; + Tcl_DStringInit(&psdstr); + + Vector vv = Vector(x,y) * matrix_; + double angle = calcTextAngle(just, up); + Vector cc = vv * calcTextPos(vv, angle, txt, just, up, text_->psfont()); + + ostringstream str; + const char* ff = Tk_NameOfFont(text_->psfont()); + str << '/' << psFontName(ff) + << " findfont " << int(psFontSize(ff)*parent_->getDisplayRatio()) + << " scalefont setfont" << endl; + + psColor(text_); + + str << "gsave " + << cc.TkCanvasPs(parent_->getCanvas()) << " moveto" << endl + << radToDeg(angle) << " rotate " + << '(' << psQuote(txt) << ')' << " show" + << " grestore" << endl << ends; + Tcl_AppendResult(parent_->getInterp(), str.str().c_str(), NULL); + + return 1; +} + +void GridBase::psColor(Attribute* attr) +{ + ostringstream str; + switch ((Widget::PSColorSpace)mode_) { + case Widget::BW: + case Widget::GRAY: + psColorGray(parent_->getXColor(attr->colorName()), str); + str << " setgray"; + break; + case Widget::RGB: + psColorRGB(parent_->getXColor(attr->colorName()), str); + str << " setrgbcolor"; + break; + case Widget::CMYK: + psColorCMYK(parent_->getXColor(attr->colorName()), str); + str << " setcmykcolor"; + break; + } + str << endl << ends; + Tcl_AppendResult(parent_->getInterp(), str.str().c_str(), NULL); +} + +#ifdef MAC_OSX_TK +int GridBase::macosxLine(int n, float* x, float* y) +{ + if (n<2 || !x || !y) + return 1; + + macosxColor(parent_->getXColor(line_->colorName())); + macosxWidth(line_->width()); + switch (line_->style()) { + case Attribute::SOLID: + macosxDash(NULL,0); + break; + case Attribute::DASH: + float dlist[] = {8,3}; + macosxDash(dlist,2); + break; + } + + Vector* v = new Vector[n]; + for (int i=0; i<n; i++) + v[i] = Vector(x[i],y[i]) * matrix_; + + macosxDrawLines(v, n); + delete [] v; + + return 1; +} + +int GridBase::macosxText(const char* txt, float x, float y, + const char* just, Vector up) +{ + // change this later + Tcl_DString psdstr; + Tcl_DStringInit(&psdstr); + int psSize = Tk_PostscriptFontName(text_->tkfont(), &psdstr); + + macosxFont(Tcl_DStringValue(&psdstr),psSize); + Tcl_DStringFree(&psdstr); + + Vector vv = Vector(x,y) * matrix_; + double angle = calcTextAngle(just, up); + Vector cc = vv * calcTextPos(vv, angle, txt, just, up, text_->tkfont()); + + macosxColor(parent_->getXColor(text_->colorName())); + macosxDrawText(cc, angle, txt); + + return 1; +} +#endif + +#ifdef __WIN32 +int GridBase::win32Line(int n, float* x, float* y) +{ + if (n<2 || !x || !y) + return 1; + + win32Color(parent_->getXColor(line_->colorName())); + win32Width(line_->width()); + switch (line_->style()) { + case Attribute::SOLID: + win32Dash(NULL,0); + break; + case Attribute::DASH: + float dlist[] = {8,3}; + win32Dash(dlist,2); + break; + } + + Vector v[n]; + for (int i=0; i<n; i++) + v[i] = Vector(x[i],y[i]) * matrix_; + + win32DrawLines(v, n); + + return 1; +} + +int GridBase::win32Text(const char* txt, float x, float y, + const char* just, Vector up) +{ + win32Font(text_->tkfont()); + win32Color(parent_->getXColor(text_->colorName())); + + Vector vv = Vector(x,y) * matrix_; + double angle = calcTextAngle(just, up);; + Vector cc = vv * calcTextPos(vv, angle, txt, just, up, text_->tkfont()); + + win32DrawText(cc, angle, txt); + + return 1; +} +#endif + +// Support + +double GridBase::calcTextAngle(const char* just, Vector up) +{ + double a = up.angle(); + + // our angle is 90 off from ast's, and the other direction + double rr = -(a - M_PI_2); + + // special case for text rotated exactly 90 + if (up[0]==-1 && up[1]==0) + rr += M_PI; + + // normalize + if (rr>0) + while (rr>M_TWOPI) + rr -= M_TWOPI; + else + while (rr<0) + rr += M_TWOPI; + + return rr; +} + +Matrix GridBase::calcTextPos(const Vector& vv, double angle, const char* txt, + const char* just, Vector up, Tk_Font font) +{ + Tk_FontMetrics metrics; + Tk_GetFontMetrics(font, &metrics); + int width = Tk_TextWidth(font, txt, strlen(txt)); + + Matrix m1,m2; + switch (just[0]) { + case 'T': + break; + case 'C': + m1 = Translate(0,metrics.linespace/2); + break; + case 'B': + m1 = Translate(0,metrics.ascent); + break; + case 'M': + m1 = Translate(0,metrics.linespace); + break; + } + + switch (just[1]) { + case 'L': + break; + case 'C': + m2 = Translate(-width/2.,0); + break; + case 'R': + m2 = Translate(-width,0); + break; + } + + Matrix rr = Translate(-vv) * + Rotate(-angle) * + m1 * m2 * + Rotate(angle) * + Translate(vv); + + // special case for text rotated exactly 90 + Matrix mm; + if (up[0] == -1 && up[1] == 0) { + Vector cc = vv*rr; + mm = Translate(-cc) * + Rotate(-angle) * + Translate(-width/2.,metrics.linespace/2.) * + FlipY() * + Translate(width/2.,-metrics.linespace/2.) * + Rotate(angle) * + Translate(cc); + } + + return rr*mm; +} + |