summaryrefslogtreecommitdiffstats
path: root/tksao/util
diff options
context:
space:
mode:
authorWilliam Joye <wjoye@cfa.harvard.edu>2016-10-27 18:59:29 (GMT)
committerWilliam Joye <wjoye@cfa.harvard.edu>2016-10-27 18:59:29 (GMT)
commitd4d595fa7fb12903db9227d33d48b2b00120dbd1 (patch)
tree7d18365de0d6d1b29399b6a17c7eb01c2eb3ed49 /tksao/util
parent949f96e29bfe0bd8710d775ce220e597064e2589 (diff)
downloadblt-d4d595fa7fb12903db9227d33d48b2b00120dbd1.zip
blt-d4d595fa7fb12903db9227d33d48b2b00120dbd1.tar.gz
blt-d4d595fa7fb12903db9227d33d48b2b00120dbd1.tar.bz2
Initial commit
Diffstat (limited to 'tksao/util')
-rw-r--r--tksao/util/FlexLexer.h208
-rw-r--r--tksao/util/attribute.C193
-rw-r--r--tksao/util/attribute.h62
-rw-r--r--tksao/util/fdstream.hpp184
-rw-r--r--tksao/util/fuzzy.h38
-rw-r--r--tksao/util/grf.C642
-rw-r--r--tksao/util/grf3d.C516
-rw-r--r--tksao/util/grid25dbase.C191
-rw-r--r--tksao/util/grid25dbase.h26
-rw-r--r--tksao/util/grid2dbase.C175
-rw-r--r--tksao/util/grid2dbase.h26
-rw-r--r--tksao/util/grid3dbase.C241
-rw-r--r--tksao/util/grid3dbase.h35
-rw-r--r--tksao/util/gridbase.C461
-rw-r--r--tksao/util/gridbase.h67
-rw-r--r--tksao/util/ps.C377
-rw-r--r--tksao/util/ps.h171
-rw-r--r--tksao/util/smooth.C67
-rw-r--r--tksao/util/smooth.h12
-rw-r--r--tksao/util/util.C486
-rw-r--r--tksao/util/util.h125
21 files changed, 4303 insertions, 0 deletions
diff --git a/tksao/util/FlexLexer.h b/tksao/util/FlexLexer.h
new file mode 100644
index 0000000..1d783f1
--- /dev/null
+++ b/tksao/util/FlexLexer.h
@@ -0,0 +1,208 @@
+// -*-C++-*-
+// FlexLexer.h -- define interfaces for lexical analyzer classes generated
+// by flex
+
+// Copyright (c) 1993 The Regents of the University of California.
+// All rights reserved.
+//
+// This code is derived from software contributed to Berkeley by
+// Kent Williams and Tom Epperly.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+
+// Neither the name of the University nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+
+// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+// IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+// PURPOSE.
+
+// This file defines FlexLexer, an abstract class which specifies the
+// external interface provided to flex C++ lexer objects, and yyFlexLexer,
+// which defines a particular lexer class.
+//
+// If you want to create multiple lexer classes, you use the -P flag
+// to rename each yyFlexLexer to some other xxFlexLexer. You then
+// include <FlexLexer.h> in your other sources once per lexer class:
+//
+// #undef yyFlexLexer
+// #define yyFlexLexer xxFlexLexer
+// #include <FlexLexer.h>
+//
+// #undef yyFlexLexer
+// #define yyFlexLexer zzFlexLexer
+// #include <FlexLexer.h>
+// ...
+
+#ifndef __FLEX_LEXER_H
+// Never included before - need to define base class.
+#define __FLEX_LEXER_H
+
+#include <iostream>
+# ifndef FLEX_STD
+# define FLEX_STD std::
+# endif
+
+extern "C++" {
+
+struct yy_buffer_state;
+typedef int yy_state_type;
+
+class FlexLexer {
+public:
+ virtual ~FlexLexer() { }
+
+ const char* YYText() const { return yytext; }
+ size_t YYLeng() const { return yyleng; }
+
+ virtual void
+ yy_switch_to_buffer( struct yy_buffer_state* new_buffer ) = 0;
+ virtual struct yy_buffer_state*
+ yy_create_buffer( FLEX_STD istream* s, int size ) = 0;
+ virtual void yy_delete_buffer( struct yy_buffer_state* b ) = 0;
+ virtual void yyrestart( FLEX_STD istream* s ) = 0;
+
+ virtual int yylex() = 0;
+
+ // Call yylex with new input/output sources.
+ int yylex( FLEX_STD istream* new_in, FLEX_STD ostream* new_out = 0 )
+ {
+ switch_streams( new_in, new_out );
+ return yylex();
+ }
+
+ // Switch to new input/output streams. A nil stream pointer
+ // indicates "keep the current one".
+ virtual void switch_streams( FLEX_STD istream* new_in = 0,
+ FLEX_STD ostream* new_out = 0 ) = 0;
+
+ int lineno() const { return yylineno; }
+
+ int debug() const { return yy_flex_debug; }
+ void set_debug( int flag ) { yy_flex_debug = flag; }
+
+protected:
+ char* yytext;
+ size_t yyleng;
+ int yylineno; // only maintained if you use %option yylineno
+ int yy_flex_debug; // only has effect with -d or "%option debug"
+};
+
+}
+#endif // FLEXLEXER_H
+
+#if defined(yyFlexLexer) || ! defined(yyFlexLexerOnce)
+// Either this is the first time through (yyFlexLexerOnce not defined),
+// or this is a repeated include to define a different flavor of
+// yyFlexLexer, as discussed in the flex manual.
+#define yyFlexLexerOnce
+
+extern "C++" {
+
+class yyFlexLexer : public FlexLexer {
+public:
+ // arg_yyin and arg_yyout default to the cin and cout, but we
+ // only make that assignment when initializing in yylex().
+ yyFlexLexer( FLEX_STD istream* arg_yyin = 0, FLEX_STD ostream* arg_yyout = 0 );
+
+ virtual ~yyFlexLexer();
+
+ void yy_switch_to_buffer( struct yy_buffer_state* new_buffer );
+ struct yy_buffer_state* yy_create_buffer( FLEX_STD istream* s, int size );
+ void yy_delete_buffer( struct yy_buffer_state* b );
+ void yyrestart( FLEX_STD istream* s );
+
+ void yypush_buffer_state( struct yy_buffer_state* new_buffer );
+ void yypop_buffer_state();
+
+ virtual int yylex();
+ virtual void switch_streams( FLEX_STD istream* new_in, FLEX_STD ostream* new_out = 0 );
+ virtual int yywrap();
+
+ void begin(int,int);
+
+protected:
+ virtual size_t LexerInput( char* buf, size_t max_size );
+ virtual void LexerOutput( const char* buf, size_t size );
+ virtual void LexerError( const char* msg );
+
+ void yyunput( int c, char* buf_ptr );
+ int yyinput();
+
+ void yy_load_buffer_state();
+ void yy_init_buffer( struct yy_buffer_state* b, FLEX_STD istream* s );
+ void yy_flush_buffer( struct yy_buffer_state* b );
+
+ int yy_start_stack_ptr;
+ int yy_start_stack_depth;
+ int* yy_start_stack;
+
+ void yy_push_state( int new_state );
+ void yy_pop_state();
+ int yy_top_state();
+
+ yy_state_type yy_get_previous_state();
+ yy_state_type yy_try_NUL_trans( yy_state_type current_state );
+ int yy_get_next_buffer();
+
+ FLEX_STD istream* yyin; // input source for default LexerInput
+ FLEX_STD ostream* yyout; // output sink for default LexerOutput
+
+ // yy_hold_char holds the character lost when yytext is formed.
+ char yy_hold_char;
+
+ // Number of characters read into yy_ch_buf.
+ size_t yy_n_chars;
+
+ // Points to current character in buffer.
+ char* yy_c_buf_p;
+
+ int yy_init; // whether we need to initialize
+ int yy_start; // start state number
+
+ // Flag which is used to allow yywrap()'s to do buffer switches
+ // instead of setting up a fresh yyin. A bit of a hack ...
+ int yy_did_buffer_switch_on_eof;
+
+
+ size_t yy_buffer_stack_top; /**< index of top of stack. */
+ size_t yy_buffer_stack_max; /**< capacity of stack. */
+ struct yy_buffer_state ** yy_buffer_stack; /**< Stack as an array. */
+ void yyensure_buffer_stack(void);
+
+ // The following are not always needed, but may be depending
+ // on use of certain flex features (like REJECT or yymore()).
+
+ yy_state_type yy_last_accepting_state;
+ char* yy_last_accepting_cpos;
+
+ yy_state_type* yy_state_buf;
+ yy_state_type* yy_state_ptr;
+
+ char* yy_full_match;
+ int* yy_full_state;
+ int yy_full_lp;
+
+ int yy_lp;
+ int yy_looking_for_trail_begin;
+
+ int yy_more_flag;
+ int yy_more_len;
+ int yy_more_offset;
+ int yy_prev_more_offset;
+};
+
+}
+
+#endif // yyFlexLexer || ! yyFlexLexerOnce
+
diff --git a/tksao/util/attribute.C b/tksao/util/attribute.C
new file mode 100644
index 0000000..23e49d4
--- /dev/null
+++ b/tksao/util/attribute.C
@@ -0,0 +1,193 @@
+// Copyright (C) 1999-2016
+// Smithsonian Astrophysical Observatory, Cambridge, MA, USA
+// For conditions of distribution and use, see copyright notice in "copyright"
+
+#include "attribute.h"
+#include "util.h"
+#include "widget.h"
+
+Attribute::Attribute(Widget* p) : parent(p)
+{
+ style_ = SOLID;
+ width_ = 1;
+
+ font_ = 2; // helvetica normal roman
+ size_ = 10;
+ tkfont_ = NULL;
+ psfont_ = NULL;
+ initFonts();
+
+ colour_ = 0xffffff; // white
+ colorName_ = dupstr("white");
+ color_ = parent->getColor("white");
+}
+
+Attribute::~Attribute()
+{
+ if (tkfont_)
+ Tk_FreeFont(tkfont_);
+ if (psfont_)
+ Tk_FreeFont(psfont_);
+
+ if (colorName_)
+ delete [] colorName_;
+}
+
+void Attribute::setStyle(double v)
+{
+ switch ((int)v) {
+ case SOLID:
+ case DASH:
+ break;
+ default:
+ return;
+ }
+
+ style_ = (Style)((int)v);
+}
+
+void Attribute::setWidth(double v)
+{
+ if (v>0)
+ width_ = v;
+ else
+ width_ = 1;
+}
+
+void Attribute::setSize(double v)
+{
+ if (v >= 1) {
+#ifdef MAC_OSX_TK
+ size_ = int(v*parent->getDisplayRatio());
+#else
+ size_ = (int)v;
+#endif
+ initFonts();
+ }
+}
+
+void Attribute::setFont(double v)
+{
+ font_ = (int)v;
+ initFonts();
+}
+
+void Attribute::initFonts()
+{
+ if (tkfont_)
+ Tk_FreeFont(tkfont_);
+ tkfont_ = NULL;
+ if (psfont_)
+ Tk_FreeFont(psfont_);
+ psfont_ = NULL;
+
+ WidgetOptions* opts = parent->options;
+
+ ostringstream fstr;
+ ostringstream pstr;
+ switch (font_) {
+ case 0:
+ case 2:
+ case 3:
+ fstr << '{' << opts->helvetica << '}' << ' ' << size_ << " normal roman" << ends;
+ pstr << "helvetica " << size_ << " normal roman" << ends;
+ break;
+ case 1:
+ fstr << '{' << opts->times << '}' << ' ' << size_ << " normal roman" << ends;
+ pstr << "times " << size_ << " normal roman" << ends;
+ break;
+ case 4:
+ fstr << '{' << opts->courier << '}' << ' ' << size_ << " normal roman" << ends;
+ pstr << "courier " << size_ << " normal roman" << ends;
+ break;
+
+ case 10:
+ case 12:
+ case 13:
+ fstr << '{' << opts->helvetica << '}' << ' ' << size_ << " bold roman" << ends;
+ pstr << "helvetica " << size_ << " bold roman" << ends;
+ break;
+ case 11:
+ fstr << '{' << opts->times << '}' << ' ' << size_ << " bold roman" << ends;
+ pstr << "times " << size_ << " bold roman" << ends;
+ break;
+ case 14:
+ fstr << '{' << opts->courier << '}' << ' ' << size_ << " bold roman" << ends;
+ pstr << "courier " << size_ << " bold roman" << ends;
+ break;
+
+ case 20:
+ case 22:
+ case 23:
+ fstr << '{' << opts->helvetica << '}' << ' ' << size_ << " normal italic" << ends;
+ pstr << "helvetica " << size_ << " normal italic" << ends;
+ break;
+ case 21:
+ fstr << '{' << opts->times << '}' << ' ' << size_ << " normal italic" << ends;
+ pstr << "times " << size_ << " normal italic" << ends;
+ break;
+ case 24:
+ fstr << '{' << opts->courier << '}' << ' ' << size_ << " normal italic" << ends;
+ pstr << "courier " << size_ << " normal italic" << ends;
+ break;
+
+ case 30:
+ case 32:
+ case 33:
+ fstr << '{' << opts->helvetica << '}' << ' ' << size_ << " bold italic" << ends;
+ pstr << "helvetica " << size_ << " bold italic" << ends;
+ break;
+ case 31:
+ fstr << '{' << opts->times << '}' << ' ' << size_ << " bold italic" << ends;
+ pstr << "times " << size_ << " bold italic" << ends;
+ break;
+ case 34:
+ fstr << '{' << opts->courier << '}' << ' ' << size_ << " bold italic" << ends;
+ pstr << "courier " << size_ << " bold italic" << ends;
+ break;
+
+ default:
+ fstr << '{' << opts->helvetica << '}' << ' ' << size_ << " normal roman" << ends;
+ pstr << "helvetica " << size_ << " normal roman" << ends;
+ font_ = 2;
+ break;
+ }
+
+ tkfont_ = Tk_GetFont(parent->getInterp(), parent->getTkwin(),
+ fstr.str().c_str());
+ psfont_ = Tk_GetFont(parent->getInterp(), parent->getTkwin(),
+ pstr.str().c_str());
+}
+
+void Attribute::setColour(double v)
+{
+ if (v == colour_)
+ return;
+
+ if (colorName_)
+ delete [] colorName_;
+ colorName_ = NULL;
+
+ // still provide backward compatibility for old color scheme
+ if (v==1)
+ colour_ = (int)0xffffff; // white
+ else if (v==2)
+ colour_ = (int)0xff0000; // red
+ else if (v==3)
+ colour_ = (int)0x00ff00; // green
+ else if (v==4)
+ colour_ = (int)0x0000ff; // blue
+ else if (v==5)
+ colour_ = (int)0x00ffff; // cyan
+ else if (v==6)
+ colour_ = (int)0xff00ff; // magneta
+ else if (v==7)
+ colour_ = (int)0xffff00; // yellow
+ else
+ colour_ = (int)v;
+
+ ostringstream str;
+ str << '#' << setw(6) << setfill('0') << hex << colour_ << ends;
+ colorName_ = dupstr(str.str().c_str());
+ color_ = parent->getColor(str.str().c_str());
+ }
diff --git a/tksao/util/attribute.h b/tksao/util/attribute.h
new file mode 100644
index 0000000..e32efde
--- /dev/null
+++ b/tksao/util/attribute.h
@@ -0,0 +1,62 @@
+// Copyright (C) 1999-2016
+// Smithsonian Astrophysical Observatory, Cambridge, MA, USA
+// For conditions of distribution and use, see copyright notice in "copyright"
+
+#ifndef __attribute_h__
+#define __attribute_h__
+
+#include <tk.h>
+
+#include "vector.h"
+
+class Widget;
+
+class Attribute {
+ public:
+ enum Style {SOLID,DASH};
+ enum Colour {BLACK,WHITE,RED,GREEN,BLUE,CYAN,MAGENTA,YELLOW};
+
+ private:
+ Widget* parent;
+
+ Style style_;
+ float width_;
+
+ int font_;
+ int size_;
+ Tk_Font tkfont_;
+ Tk_Font psfont_;
+
+ unsigned long colour_;
+ char* colorName_;
+ unsigned long color_;
+
+ private:
+ void initFonts();
+
+ public:
+ Attribute(Widget*);
+ ~Attribute();
+
+ void setStyle(double);
+ void setWidth(double);
+
+ void setSize(double);
+ void setFont(double);
+
+ void setColour(double);
+
+ Style style() {return style_;}
+ float width() {return width_;}
+
+ int size() {return size_;}
+ int font() {return font_;}
+ Tk_Font tkfont() {return tkfont_;}
+ Tk_Font psfont() {return psfont_;}
+
+ unsigned long colour() {return colour_;}
+ char* colorName() {return colorName_;}
+ unsigned long color() {return color_;}
+};
+
+#endif
diff --git a/tksao/util/fdstream.hpp b/tksao/util/fdstream.hpp
new file mode 100644
index 0000000..585e03d
--- /dev/null
+++ b/tksao/util/fdstream.hpp
@@ -0,0 +1,184 @@
+/* The following code declares classes to read from and write to
+ * file descriptore or file handles.
+ *
+ * See
+ * http://www.josuttis.com/cppcode
+ * for details and the latest version.
+ *
+ * - open:
+ * - integrating BUFSIZ on some systems?
+ * - optimized reading of multiple characters
+ * - stream for reading AND writing
+ * - i18n
+ *
+ * (C) Copyright Nicolai M. Josuttis 2001.
+ * Permission to copy, use, modify, sell and distribute this software
+ * is granted provided this copyright notice appears in all copies.
+ * This software is provided "as is" without express or implied
+ * warranty, and with no claim as to its suitability for any purpose.
+ *
+ * Version: Jul 28, 2002
+ * History:
+ * Jul 28, 2002: bugfix memcpy() => memmove()
+ * fdinbuf::underflow(): cast for return statements
+ * Aug 05, 2001: first public version
+ */
+#ifndef BOOST_FDSTREAM_HPP
+#define BOOST_FDSTREAM_HPP
+
+#include <istream>
+#include <ostream>
+#include <streambuf>
+// for EOF:
+#include <cstdio>
+// for memmove():
+#include <cstring>
+
+
+// low-level read and write functions
+#ifdef _MSC_VER
+# include <io.h>
+#else
+# include <unistd.h>
+//extern "C" {
+// int write (int fd, const char* buf, int num);
+// int read (int fd, char* buf, int num);
+//}
+#endif
+
+
+// BEGIN namespace BOOST
+namespace boost {
+
+
+/************************************************************
+ * fdostream
+ * - a stream that writes on a file descriptor
+ ************************************************************/
+
+
+class fdoutbuf : public std::streambuf {
+ protected:
+ int fd; // file descriptor
+ public:
+ // constructor
+ fdoutbuf (int _fd) : fd(_fd) {
+ }
+ protected:
+ // write one character
+ virtual int_type overflow (int_type c) {
+ if (c != EOF) {
+ char z = c;
+ if (write (fd, &z, 1) != 1) {
+ return EOF;
+ }
+ }
+ return c;
+ }
+ // write multiple characters
+ virtual
+ std::streamsize xsputn (const char* s,
+ std::streamsize num) {
+ return write(fd,s,num);
+ }
+};
+
+class fdostream : public std::ostream {
+ protected:
+ fdoutbuf buf;
+ public:
+ fdostream (int fd) : std::ostream(0), buf(fd) {
+ rdbuf(&buf);
+ }
+};
+
+
+/************************************************************
+ * fdistream
+ * - a stream that reads on a file descriptor
+ ************************************************************/
+
+class fdinbuf : public std::streambuf {
+ protected:
+ int fd; // file descriptor
+ protected:
+ /* data buffer:
+ * - at most, pbSize characters in putback area plus
+ * - at most, bufSize characters in ordinary read buffer
+ */
+ static const int pbSize = 4; // size of putback area
+ static const int bufSize = 1024; // size of the data buffer
+ char buffer[bufSize+pbSize]; // data buffer
+
+ public:
+ /* constructor
+ * - initialize file descriptor
+ * - initialize empty data buffer
+ * - no putback area
+ * => force underflow()
+ */
+ fdinbuf (int _fd) : fd(_fd) {
+ setg (buffer+pbSize, // beginning of putback area
+ buffer+pbSize, // read position
+ buffer+pbSize); // end position
+ }
+
+ protected:
+ // insert new characters into the buffer
+ virtual int_type underflow () {
+#ifndef _MSC_VER
+ using std::memmove;
+#endif
+
+ // is read position before end of buffer?
+ if (gptr() < egptr()) {
+ return traits_type::to_int_type(*gptr());
+ }
+
+ /* process size of putback area
+ * - use number of characters read
+ * - but at most size of putback area
+ */
+ int numPutback;
+ numPutback = gptr() - eback();
+ if (numPutback > pbSize) {
+ numPutback = pbSize;
+ }
+
+ /* copy up to pbSize characters previously read into
+ * the putback area
+ */
+ memmove (buffer+(pbSize-numPutback), gptr()-numPutback,
+ numPutback);
+
+ // read at most bufSize new characters
+ int num;
+ num = read (fd, buffer+pbSize, bufSize);
+ if (num <= 0) {
+ // ERROR or EOF
+ return EOF;
+ }
+
+ // reset buffer pointers
+ setg (buffer+(pbSize-numPutback), // beginning of putback area
+ buffer+pbSize, // read position
+ buffer+pbSize+num); // end of buffer
+
+ // return next character
+ return traits_type::to_int_type(*gptr());
+ }
+};
+
+class fdistream : public std::istream {
+ protected:
+ fdinbuf buf;
+ public:
+ fdistream (int fd) : std::istream(0), buf(fd) {
+ rdbuf(&buf);
+ }
+};
+
+
+} // END namespace boost
+
+#endif /*BOOST_FDSTREAM_HPP*/
diff --git a/tksao/util/fuzzy.h b/tksao/util/fuzzy.h
new file mode 100644
index 0000000..512e079
--- /dev/null
+++ b/tksao/util/fuzzy.h
@@ -0,0 +1,38 @@
+// Copyright (C) 1999-2016
+// Smithsonian Astrophysical Observatory, Cambridge, MA, USA
+// For conditions of distribution and use, see copyright notice in "copyright"
+
+#ifndef __fuzzy_h__
+#define __fuzzy_h__
+
+#include <iostream>
+#include <sstream>
+#include <iomanip>
+using namespace std;
+
+#include <float.h>
+
+inline void tzero(double* ff, const double epsilon= DBL_EPSILON)
+{if (*ff>=-epsilon && *ff<=epsilon) *ff = 0;}
+
+inline bool teq(const double f1, const double f2,
+ const double epsilon= DBL_EPSILON)
+{return f1-f2 >= -epsilon && f1-f2 <= epsilon;}
+
+inline bool tlt(const double f1, const double f2,
+ const double epsilon= DBL_EPSILON)
+{return f1-f2 < -epsilon;}
+
+inline bool tle(const double f1, const double f2,
+ const double epsilon= DBL_EPSILON)
+{return f1-f2 <= -epsilon; }
+
+inline bool tgt(const double f1, const double f2,
+ const double epsilon= DBL_EPSILON)
+{return f1-f2 > epsilon;}
+
+inline bool tge(const double f1, const double f2,
+ const double epsilon= DBL_EPSILON)
+{return f1-f2 >= epsilon;}
+
+#endif
diff --git a/tksao/util/grf.C b/tksao/util/grf.C
new file mode 100644
index 0000000..f4f98d7
--- /dev/null
+++ b/tksao/util/grf.C
@@ -0,0 +1,642 @@
+extern "C" {
+#include "grf.h"
+}
+
+#include "grid2dbase.h"
+#include "grid25dbase.h"
+
+extern Grid2dBase* astGrid2dPtr;
+extern Grid25dBase* astGrid25dPtr;
+
+/*
+ * Name:
+ * astGFlush
+ *
+ * Purpose:
+ * Flush all pending graphics to the output device
+ *
+ * Synopsis:
+ * #include "grf.h"
+ * int astGFlush( void )
+ *
+ * Description:
+ * This function ensures that the display device is up-to-date,
+ * by flushing any pending graphics to the output device.
+ *
+ * Parameters:
+ * None
+ *
+ * Returned Value:
+ * A value of 0 is returned if an error occurrs, and 1 is returned
+ * otherwise
+ */
+
+int astGFlush(void)
+{
+ if (astGrid2dPtr)
+ return astGrid2dPtr->gFlush();
+ else if (astGrid25dPtr)
+ return astGrid25dPtr->gFlush();
+ return 0;
+}
+
+/*
+ * Name:
+ * astGLine
+ *
+ * Purpose:
+ * Draw a polyline (i.e. a set of connected lines)
+ *
+ * Synopsis:
+ * #include "grf.h"
+ * int astGLine( int n, const float *x, const float *y )
+ *
+ * Description:
+ * This function displays lines joining the given positions
+ *
+ * Parameters:
+ * n
+ * The number of positions to be joined together
+ * x
+ * A pointer to an array holding the "n" x values
+ * y
+ * A pointer to an array holding the "n" y values
+ *
+ * Returned Value:
+ * A value of 0 is returned if an error occurrs, and 1 is returned
+ * otherwise
+ *
+ * Notes:
+ * - Nothing is done if "n" is less than 2, or if a NULL pointer is
+ * given for either "x" or "y"
+ */
+
+int astGLine(int n, const float *x, const float *y)
+{
+ if (astGrid2dPtr)
+ return astGrid2dPtr->gLine(n, (float*)x, (float*)y);
+ else if (astGrid25dPtr)
+ return astGrid25dPtr->gLine(n, (float*)x, (float*)y);
+ return 0;
+}
+
+/*
+ * Name:
+ * astGQch
+ *
+ * Purpose:
+ * Return the character height in world cooridnates
+ *
+ * Synopsis:
+ * #include "grf.h"
+ * int astGQch( float *chv, float *chh )
+ *
+ * Description:
+ * This function returns the heights of characters drawn vertically and
+ * horizontally in world coordinates
+ *
+ * Parameters:
+ * chv
+ * A pointer to the double which is to receive the height of
+ * characters drawn vertically. This will be an increment in the X
+ * axis
+ * chh
+ * A pointer to the double which is to receive the height of
+ * characters drawn vertically. This will be an increment in the Y
+ * axis
+ *
+ * Returned Value:
+ * A value of 0 is returned if an error occurrs, and 1 is returned
+ * otherwise
+ */
+
+int astGQch(float *chv, float *chh)
+{
+ if (astGrid2dPtr)
+ return astGrid2dPtr->gQch(chv, chh);
+ else if (astGrid25dPtr)
+ return astGrid25dPtr->gQch(chv, chh);
+ return 0;
+}
+
+/*
+ * Name:
+ * astGMark
+ *
+ * Purpose:
+ * Draw a set of markers
+ *
+ * Synopsis:
+ * #include "grf.h"
+ * int astGMark( int n, const float *x, const float *y, int type )
+ *
+ * Description:
+ * This function displays markers at the given positions
+ *
+ * Parameters:
+ * n
+ * The number of markers to draw
+ * x
+ * A pointer to an array holding the "n" x values
+ * y
+ * A pointer to an array holding the "n" y values
+ * type
+ * An integer which can be used to indicate the type of marker symbol
+ * required
+ *
+ * Returned Value:
+ * A value of 0 is returned if an error occurrs, and 1 is returned
+ * otherwise
+ *
+ * Notes:
+ * - Nothing is done if "n" is less than 1, or if a NULL pointer is
+ * given for either "x" or "y"
+ *
+ */
+
+int astGMark(int n, const float *x, const float *y, int type)
+{
+ if (astGrid2dPtr)
+ return astGrid2dPtr->gMark(n, x, y, type);
+ else if (astGrid25dPtr)
+ return astGrid25dPtr->gMark(n, x, y, type);
+ return 0;
+}
+
+/*
+ * Name:
+ * astGText
+ *
+ * Purpose:
+ * Draw a character string
+ *
+ * Synopsis:
+ * #include "grf.h"
+ * int astGText( const char *text, float x, float y, const char *just,
+ * float upx, float upy )
+ *
+ * Description:
+ * This function displays a character string at a given position
+ * using a specified justification and up-vector
+ *
+ * Parameters:
+ * text
+ * Pointer to a null-terminated character string to be displayed
+ * x
+ * The reference x coordinate
+ * y
+ * The reference y coordinate
+ * just
+ * A character string which specifies the location within the
+ * text string which is to be placed at the reference position
+ * given by x and y. The first character may be 'T' for "top",
+ * 'C' for "centre", or 'B' for "bottom", and specifies the
+ * vertical location of the reference position. Note, "bottom"
+ * corresponds to the base-line of normal text. Some characters
+ * (eg "y", "g", "p", etc) descend below the base-line. The second
+ * character may be 'L' for "left", 'C' for "centre", or 'R'
+ * for "right", and specifies the horizontal location of the
+ * reference position. If the string has less than 2 characters
+ * then 'C' is used for the missing characters
+ * upx
+ * The x component of the up-vector for the text, in graphics world
+ * coordinates. If necessary the supplied value should be negated
+ * to ensure that positive values always refer to displacements from
+ * left to right on the screen
+ * upy
+ * The y component of the up-vector for the text, in graphics world
+ * coordinates. If necessary the supplied value should be negated
+ * to ensure that positive values always refer to displacements from
+ * bottom to top on the screen
+ *
+ * Returned Value:
+ * A value of 0 is returned if an error occurrs, and 1 is returned
+ * otherwise
+ *
+ * Notes:
+ * - Any graphics within the rotated box enclosing the text are erased
+ * - A NULL value for "just" causes a value of "CC" to be used
+ * - Both "upx" and "upy" being zero causes an error
+ * - Any unrecognised character in "just" causes an error
+ */
+
+int astGText(const char *text, float x, float y, const char *just,
+ float upx, float upy)
+{
+ if (astGrid2dPtr)
+ return astGrid2dPtr->gText(text, x ,y, just, upx, upy);
+ else if (astGrid25dPtr)
+ return astGrid25dPtr->gText(text, x ,y, just, upx, upy);
+ return 0;
+}
+
+/*
+* Name:
+* astGTxExt
+*
+* Purpose:
+* Get the extent of a character string
+*
+* Synopsis:
+* #include "grf.h"
+* int astGTxExt( const char *text, float x, float y, const char *just,
+* float upx, float upy, float *xb, float *yb )
+*
+* Description:
+* This function returns the corners of a box which would enclose the
+* supplied character string if it were displayed using astGText
+*
+* The returned box INCLUDES any leading or trailing spaces
+*
+* Parameters:
+* text
+* Pointer to a null-terminated character string to be displayed
+* x
+* The reference x coordinate
+* y
+* The reference y coordinate
+* just
+* A character string which specifies the location within the
+* text string which is to be placed at the reference position
+* given by x and y. The first character may be 'T' for "top",
+* 'C' for "centre", or 'B' for "bottom", and specifies the
+* vertical location of the reference position. Note, "bottom"
+* corresponds to the base-line of normal text. Some characters
+* (eg "y", "g", "p", etc) descend below the base-line. The second
+* character may be 'L' for "left", 'C' for "centre", or 'R'
+* for "right", and specifies the horizontal location of the
+* reference position. If the string has less than 2 characters
+* then 'C' is used for the missing characters
+* upx
+* The x component of the up-vector for the text, in graphics world
+* coordinates. If necessary the supplied value should be negated
+* to ensure that positive values always refer to displacements from
+* left to right on the screen
+* upy
+* The y component of the up-vector for the text, in graphics world
+* coordinates. If necessary the supplied value should be negated
+* to ensure that positive values always refer to displacements from
+* bottom to top on the screen
+* xb
+* An array of 4 elements in which to return the x coordinate of
+* each corner of the bounding box
+* yb
+* An array of 4 elements in which to return the y coordinate of
+* each corner of the bounding box
+*
+* Returned Value:
+* A value of 0 is returned if an error occurrs, and 1 is returned
+* otherwise
+*
+* Notes:
+* - The order of the corners is anti-clockwise (in world coordinates)
+* starting at the bottom left
+* - A NULL value for "just" causes a value of "CC" to be used
+* - Both "upx" and "upy" being zero causes an error
+* - Any unrecognised character in "just" causes an error
+* - Zero is returned for all bounds of the box if an error occurs
+*/
+
+int astGTxExt(const char *text, float x, float y, const char *just,
+ float upx, float upy, float *xb, float *yb)
+{
+ if (astGrid2dPtr)
+ return astGrid2dPtr->gTxExt(text, x, y, just, upx, upy, xb, yb);
+ else if (astGrid25dPtr)
+ return astGrid25dPtr->gTxExt(text, x, y, just, upx, upy, xb, yb);
+ return 0;
+}
+
+/*
+ * Name:
+ * astGAttr
+ *
+ * Purpose:
+ * Enquire or set a graphics attribute value
+ *
+ * Synopsis:
+ * #include "grf.h"
+ * int int astGAttr( int attr, double value, double *old_value, int prim )
+ *
+ * Description:
+ * This function returns the current value of a specified graphics
+ * attribute, and optionally establishes a new value. The supplied
+ * value is converted to an integer value if necessary before use
+ *
+ * Parameters:
+ * attr
+ * An integer value identifying the required attribute. The
+ * following symbolic values are defined in grf.h:
+ *
+ * GRF__STYLE - Line style
+ * GRF__WIDTH - Line width
+ * GRF__SIZE - Character and marker size scale factor
+ * GRF__FONT - Character font
+ * GRF__COLOUR - Colour index
+ * value
+ * A new value to store for the attribute. If this is AST__BAD
+ * no value is stored
+ * old_value
+ * A pointer to a double in which to return the attribute value
+ * If this is NULL, no value is returned
+ * prim
+ * The sort of graphics primative to be drawn with the new attribute
+ * Identified by the following values defined in grf.h:
+ * GRF__LINE
+ * GRF__MARK
+ * GRF__TEXT
+ *
+ * Returned Value:
+ * A value of 0 is returned if an error occurrs, and 1 is returned
+ * otherwise
+ *
+ * Notes:
+ */
+
+int astGAttr(int attr, double value, double *old, int prim)
+{
+ if (astGrid2dPtr)
+ return astGrid2dPtr->gAttr(attr, value, old, prim);
+ else if (astGrid25dPtr)
+ return astGrid25dPtr->gAttr(attr, value, old, prim);
+ return 0;
+}
+
+/*
+* Name:
+* astGScales
+*
+* Purpose:
+* Get the axis scales.
+*
+* Synopsis:
+* #include "grf.h"
+* int astGScales( float *alpha, float *beta )
+*
+* Description:
+* This function returns two values (one for each axis) which scale
+* increments on the corresponding axis into a "normal" coordinate
+* system in which:
+* 1 - The axes have equal scale in terms of (for instance)
+* millimetres per unit distance.
+* 2 - X values increase from left to right.
+* 3 - Y values increase from bottom to top.
+*
+* Parameters:
+* alpha
+* A pointer to the location at which to return the scale for the
+* X axis (i.e. Xnorm = alpha*Xworld).
+* beta
+* A pointer to the location at which to return the scale for the
+* Y axis (i.e. Ynorm = beta*Yworld).
+*
+* Returned Value:
+* A value of 0 is returned if an error occurs, and 1 is returned
+* otherwise.
+*/
+
+int astGScales(float *alpha, float *beta)
+{
+ if (astGrid2dPtr)
+ return astGrid2dPtr->gScales(alpha,beta);
+ else if (astGrid25dPtr)
+ return astGrid25dPtr->gScales(alpha,beta);
+ return 0;
+}
+
+/*
+* Name:
+* astGCap
+*
+* Purpose:
+* Indicate if this grf module has a given capability.
+*
+* Synopsis:
+* #include "grf.h"
+* int astGCap( int cap, int value )
+*
+* Description:
+* This function is called by the AST Plot class to determine if the
+* grf module has a given capability, as indicated by the "cap"
+* argument.
+*
+* Parameters:
+* cap
+* The capability being inquired about. This will be one of the
+* following constants defined in grf.h:
+*
+* GRF__SCALES: This function should return a non-zero value if
+* it implements the astGScales function, and zero otherwise. The
+* supplied "value" argument should be ignored.
+*
+* GRF__MJUST: This function should return a non-zero value if
+* the astGText and astGTxExt functions recognise "M" as a
+* character in the justification string. If the first character of
+* a justification string is "M", then the text should be justified
+* with the given reference point at the bottom of the bounding box.
+* This is different to "B" justification, which requests that the
+* reference point be put on the baseline of the text, since some
+* characters hang down below the baseline. If the astGText or
+* astGTxExt function cannot differentiate between "M" and "B",
+* then this function should return zero, in which case "M"
+* justification will never be requested by Plot. The supplied
+* "value" argument should be ignored.
+*
+* GRF__ESC: This function should return a non-zero value if the
+* astGText and astGTxExt functions can recognise and interpret
+* graphics escape sequences within the supplied string. These
+* escape sequences are described below. Zero should be returned
+* if escape sequences cannot be interpreted (in which case the
+* Plot class will interpret them itself if needed). The supplied
+* "value" argument should be ignored only if escape sequences cannot
+* be interpreted by astGText and astGTxExt. Otherwise, "value"
+* indicates whether astGText and astGTxExt should interpret escape
+* sequences in subsequent calls. If "value" is non-zero then
+* escape sequences should be interpreted by astGText and
+* astGTxExt. Otherwise, they should be drawn as literal text.
+*
+* Returned Value:
+* The return value, as described above. Zero should be returned if
+* the supplied capability is not recognised.
+*
+* Escape Sequences:
+* Escape sequences are introduced into the text string by a percent
+* "%" character. The following escape sequences are currently recognised
+* ("..." represents a string of one or more decimal digits):
+*
+* %% - Print a literal "%" character (type GRF__ESPER ).
+*
+* %^...+ - Draw subsequent characters as super-scripts. The digits
+* "..." give the distance from the base-line of "normal"
+* text to the base-line of the super-script text, scaled
+* so that a value of "100" corresponds to the height of
+* "normal" text (type GRF__ESSUP ).
+* %^+ - Draw subsequent characters with the normal base-line.
+*
+* %v...+ - Draw subsequent characters as sub-scripts. The digits
+* "..." give the distance from the base-line of "normal"
+* text to the base-line of the sub-script text, scaled
+* so that a value of "100" corresponds to the height of
+* "normal" text (type GRF__ESSUB ).
+*
+* %v+ - Draw subsequent characters with the normal base-line
+* (equivalent to %^+).
+*
+* %>...+ - Leave a gap before drawing subsequent characters.
+* The digits "..." give the size of the gap, scaled
+* so that a value of "100" corresponds to the height of
+* "normal" text (type GRF__ESGAP ).
+*
+* %<...+ - Move backwards before drawing subsequent characters.
+* The digits "..." give the size of the movement, scaled
+* so that a value of "100" corresponds to the height of
+* "normal" text (type GRF_ESBAC).
+*
+* %s...+ - Change the Size attribute for subsequent characters. The
+* digits "..." give the new Size as a fraction of the
+* "normal" Size, scaled so that a value of "100" corresponds
+* to 1.0 (type GRF__ESSIZ ).
+*
+* %s+ - Reset the Size attribute to its "normal" value.
+*
+* %w...+ - Change the Width attribute for subsequent characters. The
+* digits "..." give the new width as a fraction of the
+* "normal" Width, scaled so that a value of "100" corresponds
+* to 1.0 (type GRF__ESWID ).
+*
+* %w+ - Reset the Size attribute to its "normal" value.
+*
+* %f...+ - Change the Font attribute for subsequent characters. The
+* digits "..." give the new Font value (type GRF__ESFON ).
+*
+* %f+ - Reset the Font attribute to its "normal" value.
+*
+* %c...+ - Change the Colour attribute for subsequent characters. The
+* digits "..." give the new Colour value (type GRF__ESCOL ).
+*
+* %c+ - Reset the Colour attribute to its "normal" value.
+*
+* %t...+ - Change the Style attribute for subsequent characters. The
+* digits "..." give the new Style value (type GRF__ESSTY ).
+*
+* %t+ - Reset the Style attribute to its "normal" value.
+*
+* %- - Push the current graphics attribute values onto the top of
+* the stack - see "%+" (type GRF__ESPSH).
+*
+* %+ - Pop attributes values of the top the stack - see "%-". If
+* the stack is empty, "normal" attribute values are restored
+* (type GRF__ESPOP).
+*
+* The astFindEscape function (in libast.a) can be used to locate escape
+* sequences within a text string. It has the following signature:
+*
+* #include "plot.h"
+* int astFindEscape( const char *text, int *type, int *value, int *nc )
+*
+* Parameters:
+* text
+* Pointer to the string to be checked.
+* type
+* Pointer to a location at which to return the type of escape
+* sequence. Each type is identified by a symbolic constant defined
+* in grf.h and is indicated in the above section. The returned value
+* is undefined if the supplied text does not begin with an escape
+* sequence.
+* value
+* Pointer to a lcation at which to return the integer value
+* associated with the escape sequence. All usable values will be
+* positive. Zero is returned if the escape sequence has no associated
+* integer. A value of -1 indicates that the attribute identified by
+* "type" should be reset to its "normal" value (as established using
+* the astGAttr function, etc). The returned value is undefined if
+* the supplied text does not begin with an escape sequence.
+* nc
+* Pointer to a location at which to return the number of
+* characters read by this call. If the text starts with an escape
+* sequence, the returned value will be the number of characters in
+* the escape sequence. Otherwise, the returned value will be the
+* number of characters prior to the first escape sequence, or the
+* length of the supplied text if no escape sequence is found.
+*
+* Returned Value:
+* A non-zero value is returned if the supplied text starts with a
+* graphics escape sequence, and zero is returned otherwise.
+*/
+
+int astGCap(int cap, int value)
+{
+ if (astGrid2dPtr)
+ return astGrid2dPtr->gCap(cap,value);
+ else if (astGrid25dPtr)
+ return astGrid25dPtr->gCap(cap,value);
+ return 0;
+}
+
+/*
+* Name:
+* astGBBuf
+*
+* Purpose:
+* Start a new graphics buffering context.
+*
+* Synopsis:
+* #include "grf.h"
+* int astGBBuf( void )
+*
+* Description:
+* This function begins saving graphical output commands in an
+* internal buffer; the commands are held until a matching astGEBuf
+* call (or until the buffer is emptied by astGFlush). This can
+* greatly improve the efficiency of some graphics systems. astGBBuf
+* increments an internal counter, while astGEBuf decrements this
+* counter and flushes the buffer to the output device when the
+* counter drops to zero. astGBBuf and astGEBuf calls should always
+* be paired.
+*
+* Parameters:
+* None.
+*
+* Returned Value:
+* A value of 0 is returned if an error occurs, and 1 is returned
+* otherwise.
+*
+*/
+
+int astGBBuf(void)
+{
+ return 1;
+}
+
+/*
+* Name:
+* astGEBuf
+*
+* Purpose:
+* End a graphics buffering context.
+*
+* Synopsis:
+* #include "grf.h"
+* int astGEBuf( void )
+*
+* Description:
+* This function marks the end of a batch of graphical output begun
+* with the last call of astGBBuf. astGBBuf and astGEBUF calls should
+* always be paired. Each call to astGBBuf increments a counter, while
+* each call to astGEBuf decrements the counter. When the counter
+* reaches 0, the batch of output is written on the output device.
+*
+* Parameters:
+* None.
+*
+* Returned Value:
+* A value of 0 is returned if an error occurs, and 1 is returned
+* otherwise.
+*
+*/
+
+int astGEBuf(void)
+{
+ return 1;
+}
+
diff --git a/tksao/util/grf3d.C b/tksao/util/grf3d.C
new file mode 100644
index 0000000..c6381a7
--- /dev/null
+++ b/tksao/util/grf3d.C
@@ -0,0 +1,516 @@
+extern "C" {
+#include "grf3d.h"
+}
+
+#include "grid3dbase.h"
+
+extern Grid3dBase* astGrid3dPtr;
+
+/*
+* Name:
+* astG3DCap
+*
+* Purpose:
+* Indicate if this grf3d module has a given capability.
+*
+* Synopsis:
+* #include "grf3d.h"
+* int astG3DCap( int cap, int value )
+*
+* Description:
+* This function is called by the AST Plot class to determine if the
+* grf3d module has a given capability, as indicated by the "cap"
+* argument.
+*
+* Parameters:
+* cap
+* The capability being inquired about. This will be one of the
+* following constants defined in grf3d.h:
+*
+* GRF3D__ESC: This function should return a non-zero value if the
+* astG3DText and astG3DTxExt functions can recognise and interpret
+* graphics escape sequences within the supplied string. These
+* escape sequences are described below. Zero should be returned
+* if escape sequences cannot be interpreted (in which case the
+* Plot class will interpret them itself if needed). The supplied
+* "value" argument should be ignored only if escape sequences cannot
+* be interpreted by astG3DText and astG3DTxExt. Otherwise, "value"
+* indicates whether astG3DText and astG3DTxExt should interpret escape
+* sequences in subsequent calls. If "value" is non-zero then
+* escape sequences should be interpreted by astG3DText and
+* astG3DTxExt. Otherwise, they should be drawn as literal text.
+*
+* Returned Value:
+* The return value, as described above. Zero should be returned if
+* the supplied capability is not recognised.
+*
+* Escape Sequences:
+* Escape sequences are introduced into the text string by a percent
+* "%" character. The following escape sequences are currently recognised
+* ("..." represents a string of one or more decimal digits):
+*
+* %% - Print a literal "%" character (type GRF__ESPER ).
+*
+* %^...+ - Draw subsequent characters as super-scripts. The digits
+* "..." give the distance from the base-line of "normal"
+* text to the base-line of the super-script text, scaled
+* so that a value of "100" corresponds to the height of
+* "normal" text (type GRF__ESSUP ).
+* %^+ - Draw subsequent characters with the normal base-line.
+*
+* %v...+ - Draw subsequent characters as sub-scripts. The digits
+* "..." give the distance from the base-line of "normal"
+* text to the base-line of the sub-script text, scaled
+* so that a value of "100" corresponds to the height of
+* "normal" text (type GRF__ESSUB ).
+*
+* %v+ - Draw subsequent characters with the normal base-line
+* (equivalent to %^+).
+*
+* %>...+ - Leave a gap before drawing subsequent characters.
+* The digits "..." give the size of the gap, scaled
+* so that a value of "100" corresponds to the height of
+* "normal" text (type GRF__ESGAP ).
+*
+* %<...+ - Move backwards before drawing subsequent characters.
+* The digits "..." give the size of the movement, scaled
+* so that a value of "100" corresponds to the height of
+* "normal" text (type GRF_ESBAC).
+*
+* %s...+ - Change the Size attribute for subsequent characters. The
+* digits "..." give the new Size as a fraction of the
+* "normal" Size, scaled so that a value of "100" corresponds
+* to 1.0 (type GRF__ESSIZ ).
+*
+* %s+ - Reset the Size attribute to its "normal" value.
+*
+* %w...+ - Change the Width attribute for subsequent characters. The
+* digits "..." give the new width as a fraction of the
+* "normal" Width, scaled so that a value of "100" corresponds
+* to 1.0 (type GRF__ESWID ).
+*
+* %w+ - Reset the Size attribute to its "normal" value.
+*
+* %f...+ - Change the Font attribute for subsequent characters. The
+* digits "..." give the new Font value (type GRF__ESFON ).
+*
+* %f+ - Reset the Font attribute to its "normal" value.
+*
+* %c...+ - Change the Colour attribute for subsequent characters. The
+* digits "..." give the new Colour value (type GRF__ESCOL ).
+*
+* %c+ - Reset the Colour attribute to its "normal" value.
+*
+* %t...+ - Change the Style attribute for subsequent characters. The
+* digits "..." give the new Style value (type GRF__ESSTY ).
+*
+* %t+ - Reset the Style attribute to its "normal" value.
+*
+* %- - Push the current graphics attribute values onto the top of
+* the stack - see "%+" (type GRF__ESPSH).
+*
+* %+ - Pop attributes values of the top the stack - see "%-". If
+* the stack is empty, "normal" attribute values are restored
+* (type GRF__ESPOP).
+*
+* The astFindEscape function (in libast.a) can be used to locate escape
+* sequences within a text string. It has the following signature:
+*
+* #include "plot.h"
+* int astFindEscape( const char *text, int *type, int *value, int *nc )
+*
+* Parameters:
+* text
+* Pointer to the string to be checked.
+* type
+* Pointer to a location at which to return the type of escape
+* sequence. Each type is identified by a symbolic constant defined
+* in grf.h and is indicated in the above section. The returned value
+* is undefined if the supplied text does not begin with an escape
+* sequence.
+* value
+* Pointer to a lcation at which to return the integer value
+* associated with the escape sequence. All usable values will be
+* positive. Zero is returned if the escape sequence has no associated
+* integer. A value of -1 indicates that the attribute identified by
+* "type" should be reset to its "normal" value (as established using
+* the astG3DAttr function, etc). The returned value is undefined if
+* the supplied text does not begin with an escape sequence.
+* nc
+* Pointer to a location at which to return the number of
+* characters read by this call. If the text starts with an escape
+* sequence, the returned value will be the number of characters in
+* the escape sequence. Otherwise, the returned value will be the
+* number of characters prior to the first escape sequence, or the
+* length of the supplied text if no escape sequence is found.
+*
+* Returned Value:
+* A non-zero value is returned if the supplied text starts with a
+* graphics escape sequence, and zero is returned otherwise.
+*
+*/
+
+int astG3DCap(int cap, int value)
+{
+ if (astGrid3dPtr)
+ return astGrid3dPtr->gCap(cap, value);
+ return 0;
+}
+
+/*
+* Name:
+* astG3DFlush
+*
+* Purpose:
+* Flush all pending graphics to the output device.
+*
+* Synopsis:
+* #include "grf3d.h"
+* int astG3DFlush( void )
+*
+* Description:
+* This function ensures that the display device is up-to-date,
+* by flushing any pending graphics to the output device.
+*
+* Parameters:
+* None.
+*
+* Returned Value:
+* A value of 0 is returned if an error occurs, and 1 is returned
+* otherwise.
+*
+*/
+
+int astG3DFlush(void)
+{
+ if (astGrid3dPtr)
+ return astGrid3dPtr->gFlush();
+ return 0;
+}
+
+/*
+* Name:
+* astG3DLine
+*
+* Purpose:
+* Draw a polyline (i.e. a set of connected lines).
+*
+* Synopsis:
+* #include "grf3d.h"
+* int astG3DLine( int n, float *x, float *y, float *z )
+*
+* Description:
+* This function displays lines joining the given positions.
+*
+* Parameters:
+* n
+* The number of positions to be joined together.
+* x
+* A pointer to an array holding the "n" x values.
+* y
+* A pointer to an array holding the "n" y values.
+* z
+* A pointer to an array holding the "n" z values.
+*
+* Returned Value:
+* A value of 0 is returned if an error occurs, and 1 is returned
+* otherwise.
+*
+* Notes:
+* - A camera must have been established prior to calling this
+* function using either astG3DSetCamera or astG3DAutoCamera.
+* - Nothing is done if "n" is less than 2, or if a NULL pointer is
+* given for either "x", "y" or "z".
+*
+*/
+
+int astG3DLine(int n, float *x, float *y, float *z)
+{
+ if (astGrid3dPtr)
+ return astGrid3dPtr->gLine(n, x, y, z);
+ return 0;
+}
+
+/*
+* Name:
+* astG3DQch
+*
+* Purpose:
+* Return the character height in world coordinates.
+*
+* Synopsis:
+* #include "grf3d.h"
+* int astG3DQch( float *ch )
+*
+* Description:
+* This function returns the height of characters drawn using astG3DText.
+*
+* Parameters:
+* ch
+* A pointer to the double which is to receive the height of
+* characters drawn with astG3DText.
+*
+* Returned Value:
+* A value of 0 is returned if an error occurs, and 1 is returned
+* otherwise.
+*
+* Notes:
+* - Since the 3D world coordinate axes are assumed to be equally
+* scaled, the height of text in world coordinate units is independent
+* of the orientation of the text. Therefore, this function returns
+* only one height value, unlike the equivalent 2D astGQch function
+* that returns two heights.
+*/
+
+int astG3DQch(float *ch)
+{
+ if (astGrid3dPtr)
+ return astGrid3dPtr->gQch(ch);
+ return 0;
+}
+
+/*
+* Name:
+* astG3DMark
+*
+* Purpose:
+* Draw a set of markers.
+*
+* Synopsis:
+* #include "grf.h"
+* int astG3DMark( int n, float *x, float *y, float *z, int type,
+* float norm[3] )
+*
+* Description:
+* This function draws markers centred at the given positions, on a
+* plane with a specified normal vector.
+*
+* Parameters:
+* n
+* The number of markers to draw.
+* x
+* A pointer to an array holding the "n" x values.
+* y
+* A pointer to an array holding the "n" y values.
+* z
+* A pointer to an array holding the "n" z values.
+* type
+* An integer which can be used to indicate the type of marker symbol
+* required. See the description of routine PGPT in the PGPLOT manual.
+* norm
+* The (x,y,z) components of a vector that is normal to the plane
+* containing the marker. The given vector passes through the marker
+* from the back to the front. If all components of this vector are
+* zero, then a normal vector pointing from the position of the
+* first marker towards the camera eye is used.
+*
+* Returned Value:
+* A value of 0 is returned if an error occurs, and 1 is returned
+* otherwise.
+*
+* Notes:
+* - Nothing is done if "n" is less than 1, or if a NULL pointer is
+* given for "x", "y" or "z".
+*
+*/
+
+int astG3DMark(int n, float *x, float *y, float *z, int type, float norm[3])
+{
+ if (astGrid3dPtr)
+ return astGrid3dPtr->gMark(n, x, y, z, type, norm);
+ return 0;
+}
+
+/*
+* Name:
+* astG3DText
+*
+* Purpose:
+* Draw a character string.
+*
+* Synopsis:
+* #include "grf3d.h"
+* int astG3DText( const char *text, float ref[3], const char *just,
+* float up[3], float norm[3] )
+*
+* Description:
+* This function displays a character string at a given position
+* on a given plane in 3D world coords, using a specified
+* justification and up-vector.
+*
+* Parameters:
+* text
+* Pointer to a null-terminated character string to be displayed.
+* ref
+* The reference (x,y,z) coordinates.
+* just
+* A character string which specifies the location within the
+* text string which is to be placed at the reference position
+* given by x and y. The first character may be 'T' for "top",
+* 'C' for "centre", or 'B' for "bottom", and specifies the
+* vertical location of the reference position. Note, "bottom"
+* corresponds to the base-line of normal text. Some characters
+* (eg "y", "g", "p", etc) descend below the base-line. The second
+* character may be 'L' for "left", 'C' for "centre", or 'R'
+* for "right", and specifies the horizontal location of the
+* reference position. If the string has less than 2 characters
+* then 'C' is used for the missing characters.
+* up
+* The (x,y,z) up-vector for the text. The actual up vector used is
+* the projection of the supplied vector onto the plane specified by
+* "norm".
+* norm
+* The (x,y,z) components of a vector that is normal to the plane
+* containing the text. The given vector passes through the text
+* from the back to the front. If all components of this vector are
+* zero, then a normal vector pointing towards the camera eye is used.
+*
+* Returned Value:
+* A value of 0 is returned if an error occurs, and 1 is returned
+* otherwise.
+*
+* Notes:
+* - This routine does not recognise PGPLOT escape sequences.
+* - A NULL value for "just" causes a value of "CC" to be used.
+*/
+
+int astG3DText(const char *text, float ref[3], const char *just,
+ float up[3], float norm[3] )
+{
+ if (astGrid3dPtr)
+ return astGrid3dPtr->gText(text, ref, just, up, norm);
+ return 0;
+}
+
+/*
+* Name:
+* astG3DTxExt
+*
+* Purpose:
+* Get the extent of a character string.
+*
+* Synopsis:
+* #include "grf3d.h"
+* int astG3DTxExt( const char *text, float ref[3], const char *just,
+* float up[3], float norm[3], float *xb, float *yb,
+* float *zb, float bl[3] )
+*
+* Description:
+* This function returns the corners of a box which would enclose the
+* supplied character string if it were displayed using astG3DText.
+*
+* The returned box INCLUDES any leading or trailing spaces.
+*
+* Parameters:
+* text
+* Pointer to a null-terminated character string to be displayed.
+* ref
+* The reference (x,y,z) coordinates.
+* just
+* A character string which specifies the location within the
+* text string which is to be placed at the reference position
+* given by x and y. The first character may be 'T' for "top",
+* 'C' for "centre", 'B' for "baseline", or "M" for "bottom", and
+* specifies the vertical location of the reference position. Note,
+* "baseline" corresponds to the base-line of normal text. Some
+* characters (eg "y", "g", "p", etc) descend below the base-line,
+* and so "M" and "B" will produce different effects for such
+* characters. The second character may be 'L' for "left", 'C' for
+* "centre", or 'R' for "right", and specifies the horizontal
+* location of the reference position. If the string has less than
+* 2 characters then 'C' is used for the missing characters.
+* up
+* The (x,y,z) up-vector for the text. The actual up vector used is
+* the projection of the supplied vector onto the plane specified by
+* "norm".
+* norm
+* The (x,y,z) components of a vector that is normal to the plane
+* containing the text. The given vector passes through the text
+* from the back to the front. If all components of this vector are
+* zero, then a normal vector pointing towards the camera eye is used.
+* xb
+* An array of 4 elements in which to return the x coordinate of
+* each corner of the bounding box.
+* yb
+* An array of 4 elements in which to return the y coordinate of
+* each corner of the bounding box.
+* zb
+* An array of 4 elements in which to return the z coordinate of
+* each corner of the bounding box.
+* bl
+* The 3D world coordinates at the left hand end of the text
+* baseline.
+*
+* Returned Value:
+* A value of 0 is returned if an error occurs, and 1 is returned
+* otherwise.
+*
+* Notes:
+* - The order of the corners is anti-clockwise starting at the
+* bottom left when viewing the text normally (i.e. face on).
+* - This routine does not recognise PGPLOT escape sequences.
+* - A NULL value for "just" causes a value of "CC" to be used.
+*/
+
+int astG3DTxExt(const char *text, float ref[3], const char *just,
+ float up[3], float norm[3], float *xb, float *yb,
+ float *zb, float bl[3])
+{
+ if (astGrid3dPtr)
+ return astGrid3dPtr->gTxExt(text, ref, just, up, norm, xb, yb, zb, bl);
+ return 0;
+}
+
+/*
+* Name:
+* astG3DAttr
+*
+* Purpose:
+* Enquire or set a 3D graphics attribute value.
+*
+* Synopsis:
+* #include "grf3d.h"
+* int int astG3DAttr( int attr, double value, double *old_value, int prim )
+*
+* Description:
+* This function returns the current value of a specified 3D graphics
+* attribute, and optionally establishes a new value. The supplied
+* value is converted to an integer value if necessary before use.
+*
+* Parameters:
+* attr
+* An integer value identifying the required attribute. The
+* following symbolic values are defined in grf3d.h:
+*
+* GRF__STYLE - Line style.
+* GRF__WIDTH - Line width.
+* GRF__SIZE - Character and marker size scale factor.
+* GRF__FONT - Character font.
+* GRF__COLOUR - Colour index.
+* value
+* A new value to store for the attribute. If this is AST__BAD
+* no value is stored.
+* old_value
+* A pointer to a double in which to return the attribute value.
+* If this is NULL, no value is returned.
+* prim
+* The sort of graphics primitive to be drawn with the new attribute.
+* Identified by the following values defined in grf.h:
+* GRF__LINE
+* GRF__MARK
+* GRF__TEXT
+*
+* Returned Value:
+* A value of 0 is returned if an error occurs, and 1 is returned
+* otherwise.
+*
+* Notes:
+*
+*/
+
+int astG3DAttr(int attr, double value, double *old_value, int prim)
+{
+ if (astGrid3dPtr)
+ return astGrid3dPtr->gAttr(attr, value, old_value, prim);
+ return 0;
+}
diff --git a/tksao/util/grid25dbase.C b/tksao/util/grid25dbase.C
new file mode 100644
index 0000000..95faf7f
--- /dev/null
+++ b/tksao/util/grid25dbase.C
@@ -0,0 +1,191 @@
+// Copyright (C) 1999-2016
+// Smithsonian Astrophysical Observatory, Cambridge, MA, USA
+// For conditions of distribution and use, see copyright notice in "copyright"
+
+#include "grid25dbase.h"
+#include "attribute.h"
+#include "widget.h"
+#include "frame3dbase.h"
+
+extern "C" {
+ #include "ast.h"
+ #include "grf.h"
+}
+
+Grid25dBase* astGrid25dPtr = NULL;
+
+Grid25dBase::Grid25dBase(Widget* p) : GridBase(p)
+{}
+
+Grid25dBase::Grid25dBase(Widget* p, const char* o) : GridBase(p,o)
+{}
+
+Grid25dBase::~Grid25dBase()
+{}
+
+int Grid25dBase::gLine(int n, float* x, float* y)
+{
+ Frame3dBase* pp = (Frame3dBase*)parent_;
+ float xx[n];
+ float yy[n];
+
+ for (int ii=0; ii<n; ii++) {
+ Vector vv = pp->mapFromRef(Vector(x[ii],y[ii]),Coord::WIDGET);
+ xx[ii] = vv[0];
+ yy[ii] = vv[1];
+ }
+
+ switch (renderMode_) {
+ case X11:
+ x11Line(n,xx,yy);
+ break;
+ case PS:
+ psLine(n,xx,yy);
+ break;
+ case MACOSX:
+#ifdef MAC_OSX_TK
+ macosxLine(n,xx,yy);
+#endif
+ break;
+ case GWIN32:
+#ifdef __WIN32
+ win32Line(n,xx,yy);
+#endif
+ break;
+ }
+
+ return 1;
+}
+
+int Grid25dBase::gQch(float* chv, float* chh)
+{
+ Tk_Font font =NULL;
+ switch (renderMode_) {
+ case X11:
+ font = text_->tkfont();
+ break;
+ case PS:
+ font = text_->psfont();
+ break;
+ case MACOSX:
+#ifdef MAC_OSX_TK
+ font = text_->tkfont();
+#endif
+ break;
+ case GWIN32:
+#ifdef __WIN32
+ font = text_->tkfont();
+#endif
+ break;
+ }
+
+ if (font) {
+ Tk_FontMetrics metrics;
+ Tk_GetFontMetrics(font, &metrics);
+
+ *chv = (float)metrics.linespace;
+ *chh = (float)metrics.linespace;
+ return 1;
+ }
+ else {
+ *chv = *chh = 0;
+ return 0;
+ }
+}
+
+int Grid25dBase::gText(const char* txt, float x, float y, const char* just,
+ float upx, float upy)
+{
+ if (!(txt && txt[0] && just && just[0] && just[1]))
+ return 0;
+
+ Frame3dBase* pp = (Frame3dBase*)parent_;
+ Vector vv = pp->mapFromRef(Vector(x,y),Coord::WIDGET);
+
+ switch (renderMode_) {
+ case X11:
+ return x11Text(txt,vv[0],vv[1],just,Vector(0,1));
+ case PS:
+ return psText(txt,vv[0],vv[1],just,Vector(0,1));
+ case MACOSX:
+#ifdef MAC_OSX_TK
+ return macosxText(txt,vv[0],vv[1],just,Vector(0,1));
+#endif
+ break;
+ case GWIN32:
+#ifdef __WIN32
+ return win32Text(txt,vv[0],vv[1],just,Vector(0,1));
+#endif
+ break;
+ }
+
+ return 0;
+}
+
+int Grid25dBase::gTxExt(const char* txt, float x, float y, const char* just,
+ float upx, float upy, float* xb, float* yb)
+{
+ if (!(txt && txt[0] && just)) {
+ xb[0] = xb[1] = xb[2] = xb[3] = 0;
+ yb[0] = yb[1] = yb[2] = yb[3] = 0;
+
+ return 0;
+ }
+
+ Tk_Font font =NULL;
+
+ switch (renderMode_) {
+ case X11:
+ font = text_->tkfont();
+ break;
+ case PS:
+ font = text_->psfont();
+ break;
+ case MACOSX:
+#ifdef MAC_OSX_TK
+ font = text_->tkfont();
+#endif
+ break;
+ case GWIN32:
+#ifdef __WIN32
+ font = text_->tkfont();
+#endif
+ break;
+ }
+
+ if (!font)
+ return 0;
+
+ Frame3dBase* pp = (Frame3dBase*)parent_;
+ Vector vv = pp->mapFromRef(Vector(x,y),Coord::WIDGET);
+
+ double angle = 0;
+ Vector cc = vv * calcTextPos(vv, angle, txt, just, Vector(0, 1), font);
+
+ Tk_FontMetrics metrics;
+ Tk_GetFontMetrics(font, &metrics);
+ int width = Tk_TextWidth(font, txt, strlen(txt));
+
+ BBox nn = BBox(Vector(0,-metrics.descent), Vector(width,metrics.ascent));
+ BBox bb = nn * Rotate(angle) * Translate(cc);
+
+ xb[0] = bb.ll[0];
+ yb[0] = bb.ll[1];
+
+ xb[1] = bb.ur[0];
+ yb[1] = bb.ll[1];
+
+ xb[2] = bb.ur[0];
+ yb[2] = bb.ur[1];
+
+ xb[3] = bb.ll[0];
+ yb[3] = bb.ur[1];
+
+ return 1;
+}
+
+int Grid25dBase::gScales(float* alpha, float* beta)
+{
+ return 1;
+}
+
diff --git a/tksao/util/grid25dbase.h b/tksao/util/grid25dbase.h
new file mode 100644
index 0000000..adfe844
--- /dev/null
+++ b/tksao/util/grid25dbase.h
@@ -0,0 +1,26 @@
+// Copyright (C) 1999-2016
+// Smithsonian Astrophysical Observatory, Cambridge, MA, USA
+// For conditions of distribution and use, see copyright notice in "copyright"
+
+#ifndef __grid25dbase_h__
+#define __grid25dbase_h__
+
+#include "gridbase.h"
+
+class Grid25dBase : public GridBase {
+ public:
+ Grid25dBase(Widget*);
+ Grid25dBase(Widget*, const char*);
+ virtual ~Grid25dBase();
+
+ int gLine(int n, float* x, float* y);
+ int gQch(float*, float*);
+ int gMark(int, const float*, const float*, int) {return 1;}
+ int gText(const char* txt, float x, float y, const char* just,
+ float upx, float upy);
+ int gTxExt(const char*, float, float, const char*,
+ float, float, float*, float*);
+ int gScales(float *alpha, float *beta);
+};
+
+#endif
diff --git a/tksao/util/grid2dbase.C b/tksao/util/grid2dbase.C
new file mode 100644
index 0000000..606b592
--- /dev/null
+++ b/tksao/util/grid2dbase.C
@@ -0,0 +1,175 @@
+// Copyright (C) 1999-2016
+// Smithsonian Astrophysical Observatory, Cambridge, MA, USA
+// For conditions of distribution and use, see copyright notice in "copyright"
+
+#include "grid2dbase.h"
+#include "attribute.h"
+#include "widget.h"
+
+extern "C" {
+ #include "ast.h"
+ #include "grf.h"
+}
+
+Grid2dBase* astGrid2dPtr = NULL;
+
+Grid2dBase::Grid2dBase(Widget* p) : GridBase(p)
+{}
+
+Grid2dBase::Grid2dBase(Widget* p, const char* o) : GridBase(p,o)
+{}
+
+Grid2dBase::~Grid2dBase()
+{}
+
+int Grid2dBase::gLine(int n, float* x, float* y)
+{
+ switch (renderMode_) {
+ case X11:
+ x11Line(n,x,y);
+ break;
+ case PS:
+ psLine(n,x,y);
+ break;
+ case MACOSX:
+#ifdef MAC_OSX_TK
+ macosxLine(n,x,y);
+#endif
+ break;
+ case GWIN32:
+#ifdef __WIN32
+ win32Line(n,x,y);
+#endif
+ break;
+ }
+
+ return 1;
+}
+
+int Grid2dBase::gQch(float* chv, float* chh)
+{
+ Tk_Font font =NULL;
+ switch (renderMode_) {
+ case X11:
+ font = text_->tkfont();
+ break;
+ case PS:
+ font = text_->psfont();
+ break;
+ case MACOSX:
+#ifdef MAC_OSX_TK
+ font = text_->tkfont();
+#endif
+ break;
+ case GWIN32:
+#ifdef __WIN32
+ font = text_->tkfont();
+#endif
+ break;
+ }
+
+ if (font) {
+ Tk_FontMetrics metrics;
+ Tk_GetFontMetrics(font, &metrics);
+
+ *chv = (float)metrics.linespace;
+ *chh = (float)metrics.linespace;
+ return 1;
+ }
+ else {
+ *chv = *chh = 0;
+ return 0;
+ }
+}
+
+int Grid2dBase::gText(const char* txt, float x, float y, const char* just,
+ float upx, float upy)
+{
+ if (!(txt && txt[0] && just && just[0] && just[1]))
+ return 0;
+
+ switch (renderMode_) {
+ case X11:
+ return x11Text(txt,x,y,just,Vector(upx,upy));
+ case PS:
+ return psText(txt,x,y,just,Vector(upx,upy));
+ case MACOSX:
+#ifdef MAC_OSX_TK
+ return macosxText(txt,x,y,just,Vector(upx,upy));
+#endif
+ break;
+ case GWIN32:
+#ifdef __WIN32
+ return win32Text(txt,x,y,just,Vector(upx,upy));
+#endif
+ break;
+ }
+
+ return 0;
+}
+
+int Grid2dBase::gTxExt(const char* txt, float x, float y, const char* just,
+ float upx, float upy, float* xb, float* yb)
+{
+ if (!(txt && txt[0] && just)) {
+ xb[0] = xb[1] = xb[2] = xb[3] = 0;
+ yb[0] = yb[1] = yb[2] = yb[3] = 0;
+
+ return 0;
+ }
+
+ Tk_Font font =NULL;
+
+ switch (renderMode_) {
+ case X11:
+ font = text_->tkfont();
+ break;
+ case PS:
+ font = text_->psfont();
+ break;
+ case MACOSX:
+#ifdef MAC_OSX_TK
+ font = text_->tkfont();
+#endif
+ break;
+ case GWIN32:
+#ifdef __WIN32
+ font = text_->tkfont();
+#endif
+ break;
+ }
+
+ if (!font)
+ return 0;
+
+ Vector vv = Vector(x,y);
+ double angle = calcTextAngle(just, Vector(upx, upy));
+ Vector cc = vv * calcTextPos(vv, angle, txt, just, Vector(upx, upy), font);
+
+ Tk_FontMetrics metrics;
+ Tk_GetFontMetrics(font, &metrics);
+ int width = Tk_TextWidth(font, txt, strlen(txt));
+
+ BBox nn = BBox(Vector(0,-metrics.descent), Vector(width,metrics.ascent));
+ BBox bb = nn * Rotate(angle) * Translate(cc);
+
+ xb[0] = bb.ll[0];
+ yb[0] = bb.ll[1];
+
+ xb[1] = bb.ur[0];
+ yb[1] = bb.ll[1];
+
+ xb[2] = bb.ur[0];
+ yb[2] = bb.ur[1];
+
+ xb[3] = bb.ll[0];
+ yb[3] = bb.ur[1];
+
+ return 1;
+}
+
+int Grid2dBase::gScales(float* alpha, float* beta)
+{
+ return 1;
+}
+
diff --git a/tksao/util/grid2dbase.h b/tksao/util/grid2dbase.h
new file mode 100644
index 0000000..ae4c1ac
--- /dev/null
+++ b/tksao/util/grid2dbase.h
@@ -0,0 +1,26 @@
+// Copyright (C) 1999-2016
+// Smithsonian Astrophysical Observatory, Cambridge, MA, USA
+// For conditions of distribution and use, see copyright notice in "copyright"
+
+#ifndef __grid2dbase_h__
+#define __grid2dbase_h__
+
+#include "gridbase.h"
+
+class Grid2dBase : public GridBase {
+ public:
+ Grid2dBase(Widget*);
+ Grid2dBase(Widget*, const char*);
+ virtual ~Grid2dBase();
+
+ int gLine(int n, float* x, float* y);
+ int gQch(float*, float*);
+ int gMark(int, const float*, const float*, int) {return 1;}
+ int gText(const char* txt, float x, float y, const char* just,
+ float upx, float upy);
+ int gTxExt(const char*, float, float, const char*,
+ float, float, float*, float*);
+ int gScales(float *alpha, float *beta);
+};
+
+#endif
diff --git a/tksao/util/grid3dbase.C b/tksao/util/grid3dbase.C
new file mode 100644
index 0000000..9463d73
--- /dev/null
+++ b/tksao/util/grid3dbase.C
@@ -0,0 +1,241 @@
+// Copyright (C) 1999-2016
+// Smithsonian Astrophysical Observatory, Cambridge, MA, USA
+// For conditions of distribution and use, see copyright notice in "copyright"
+
+#include "grid3dbase.h"
+#include "attribute.h"
+#include "widget.h"
+
+extern "C" {
+ #include "ast.h"
+ #include "grf.h"
+}
+
+Grid3dBase* astGrid3dPtr = NULL;
+
+Grid3dBase::Grid3dBase(Widget* p) : GridBase(p)
+{}
+
+Grid3dBase::Grid3dBase(Widget* p, const char* o) : GridBase(p,o)
+{}
+
+Grid3dBase::~Grid3dBase()
+{}
+
+int Grid3dBase::gLine(int n, float* x, float* y, float* z)
+{
+ float xx[n];
+ float yy[n];
+
+ for (int ii=0; ii<n; ii++) {
+ Vector3d vv = Vector3d(x[ii],y[ii],z[ii])*mx_;
+ xx[ii] = vv[0];
+ yy[ii] = vv[1];
+ }
+
+ switch (renderMode_) {
+ case X11:
+ x11Line(n,xx,yy);
+ break;
+ case PS:
+ psLine(n,xx,yy);
+ break;
+ case MACOSX:
+#ifdef MAC_OSX_TK
+ macosxLine(n,xx,yy);
+#endif
+ break;
+ case GWIN32:
+#ifdef __WIN32
+ win32Line(n,xx,yy);
+#endif
+ break;
+ }
+ return 1;
+}
+
+int Grid3dBase::gQch(float* ch)
+{
+ Tk_Font font =NULL;
+ switch (renderMode_) {
+ case X11:
+ font = text_->tkfont();
+ break;
+ case PS:
+ font = text_->psfont();
+ break;
+ case MACOSX:
+#ifdef MAC_OSX_TK
+ font = text_->tkfont();
+#endif
+ break;
+ case GWIN32:
+#ifdef __WIN32
+ font = text_->tkfont();
+#endif
+ break;
+ }
+
+ if (font) {
+ Tk_FontMetrics metrics;
+ Tk_GetFontMetrics(font, &metrics);
+
+ *ch = (float)metrics.linespace;
+ return 1;
+ }
+ else {
+ *ch = 0;
+ return 0;
+ }
+}
+
+int Grid3dBase::gText(const char* txt, float* ref, const char* just,
+ float* up, float* norm)
+{
+ if (!(txt && txt[0] && just && just[0] && just[1]))
+ return 0;
+
+ Vector3d vv = Vector3d(ref[0],ref[1],ref[2])*mx_;
+
+ switch (renderMode_) {
+ case X11:
+ return x11Text(txt,vv[0],vv[1],just,Vector(0,1));
+ case PS:
+ return psText(txt,vv[0],vv[1],just,Vector(0,1));
+ case MACOSX:
+#ifdef MAC_OSX_TK
+ return macosxText(txt,vv[0],vv[1],just,Vector(0,1));
+#endif
+ break;
+ case GWIN32:
+#ifdef __WIN32
+ return win32Text(txt,vv[0],vv[1],just,Vector(0,1));
+#endif
+ break;
+ }
+
+ return 0;
+}
+
+int Grid3dBase::gTxExt(const char* txt, float* ref, const char* just,
+ float* up, float* norm, float* xb, float* yb,
+ float* zb, float* bl)
+{
+ if (!(txt && txt[0] && just)) {
+ xb[0] = xb[1] = xb[2] = xb[3] = 0;
+ yb[0] = yb[1] = yb[2] = yb[3] = 0;
+ zb[0] = zb[1] = zb[2] = zb[3] = 0;
+
+ return 0;
+ }
+
+ /*
+ cerr << txt
+ << Vector3d(ref[0],ref[1],ref[2]) << ' '
+ << just[0] << just[1]
+ << Vector3d(up[0],up[1],up[2])
+ << Vector3d(norm[0],norm[1],norm[2])
+ << endl;
+ */
+
+ Tk_Font font =NULL;
+
+ switch (renderMode_) {
+ case X11:
+ font = text_->tkfont();
+ break;
+ case PS:
+ font = text_->psfont();
+ break;
+ case MACOSX:
+#ifdef MAC_OSX_TK
+ font = text_->tkfont();
+#endif
+ break;
+ case GWIN32:
+#ifdef __WIN32
+ font = text_->tkfont();
+#endif
+ break;
+ }
+
+ if (!font)
+ return 0;
+
+ Vector3d vv = Vector3d(ref[0],ref[1],ref[2])*mx_;
+ // cerr << " vv: " << vv << endl;
+ Vector3d cc = vv * calcTextPos(vv, txt, just, font);
+ // cerr << " cc: " << cc << endl;
+
+ Tk_FontMetrics metrics;
+ Tk_GetFontMetrics(font, &metrics);
+ int width = Tk_TextWidth(font, txt, strlen(txt));
+
+ BBox3d nn(Vector3d(0,-metrics.descent,0), Vector3d(width,metrics.ascent,0));
+ // cerr << " nn: " << nn << endl;
+ Matrix3d mm = Translate3d(-nn.center()) * rx_ * Translate3d(nn.center());
+ // cerr << mm << endl;
+ BBox3d bb = nn * mm * Translate3d(cc);
+ // cerr << " bb: " << bb << endl;
+ Vector3d ll = cc * mm;
+
+ xb[0] = bb.ll[0];
+ yb[0] = bb.ll[1];
+ zb[0] = bb.ll[2];
+
+ xb[1] = bb.ur[0];
+ yb[1] = bb.ll[1];
+ zb[1] = bb.ll[2];
+
+ xb[2] = bb.ur[0];
+ yb[2] = bb.ur[1];
+ zb[2] = bb.ll[2];
+
+ xb[3] = bb.ll[0];
+ yb[3] = bb.ur[1];
+ zb[3] = bb.ll[2];
+
+ bl[0] = ll[0];
+ bl[1] = ll[1];
+ bl[2] = ll[2];
+
+ return 1;
+}
+
+Matrix3d Grid3dBase::calcTextPos(const Vector3d& vv, const char* txt,
+ const char* just, Tk_Font font)
+{
+ Tk_FontMetrics metrics;
+ Tk_GetFontMetrics(font, &metrics);
+ int width = Tk_TextWidth(font, txt, strlen(txt));
+
+ Matrix3d m1,m2;
+ switch (just[0]) {
+ case 'T':
+ break;
+ case 'C':
+ m1 = Translate3d(0,metrics.linespace/2,0);
+ break;
+ case 'B':
+ m1 = Translate3d(0,metrics.ascent,0);
+ break;
+ case 'M':
+ m1 = Translate3d(0,metrics.linespace,0);
+ break;
+ }
+
+ switch (just[1]) {
+ case 'L':
+ break;
+ case 'C':
+ m2 = Translate3d(-width/2.,0,0);
+ break;
+ case 'R':
+ m2 = Translate3d(-width,0,0);
+ break;
+ }
+
+ return Translate3d(-vv) *
+ m1 * m2 *
+ Translate3d(vv);
+}
diff --git a/tksao/util/grid3dbase.h b/tksao/util/grid3dbase.h
new file mode 100644
index 0000000..b81d17f
--- /dev/null
+++ b/tksao/util/grid3dbase.h
@@ -0,0 +1,35 @@
+// Copyright (C) 1999-2016
+// Smithsonian Astrophysical Observatory, Cambridge, MA, USA
+// For conditions of distribution and use, see copyright notice in "copyright"
+
+#ifndef __grid3dbase_h__
+#define __grid3dbase_h__
+
+#include <tk.h>
+
+#include "gridbase.h"
+#include "vector3d.h"
+
+class Grid3dBase : public GridBase {
+ protected:
+ Matrix3d mx_;
+ Matrix3d rx_;
+
+ Matrix3d calcTextPos(const Vector3d&, const char*, const char*, Tk_Font);
+
+ public:
+ Grid3dBase(Widget*);
+ Grid3dBase(Widget*, const char*);
+ virtual ~Grid3dBase();
+
+ int gLine(int n, float* x, float* y, float* z);
+ int gQch(float* ch);
+ int gMark(int n, float* x, float* y, float* z, int type, float* norm)
+ {return 1;}
+ int gText(const char* txt, float* ref, const char* just, float* up,
+ float* norm);
+ int gTxExt(const char* txt, float* ref, const char* just, float* up,
+ float* norm, float* xb, float* yb, float* zb, float* bl);
+};
+
+#endif
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;
+}
+
diff --git a/tksao/util/gridbase.h b/tksao/util/gridbase.h
new file mode 100644
index 0000000..fec7705
--- /dev/null
+++ b/tksao/util/gridbase.h
@@ -0,0 +1,67 @@
+// Copyright (C) 1999-2016
+// Smithsonian Astrophysical Observatory, Cambridge, MA, USA
+// For conditions of distribution and use, see copyright notice in "copyright"
+
+#ifndef __gridbase_h__
+#define __gridbase_h__
+
+#include <tk.h>
+
+#include "vector.h"
+
+class Widget;
+class Attribute;
+
+class GridBase {
+ public:
+ enum RenderMode {X11, PS, MACOSX, GWIN32};
+
+ protected:
+ Widget* parent_;
+ char* option_;
+
+ RenderMode renderMode_;
+ Attribute* line_;
+ Attribute* text_;
+
+ GC gridGC_;
+ Pixmap pixmap_;
+
+ Matrix matrix_;
+ int mode_;
+
+ protected:
+ int x11Line(int n, float* x, float* y);
+ int x11Text(const char*, float, float, const char*, Vector);
+
+ int psLine(int n, float* x, float* y);
+ int psText(const char*, float, float, const char*, Vector);
+ void psColor(Attribute*);
+
+#ifdef MAC_OSX_TK
+ int macosxLine(int n, float* x, float* y);
+ int macosxText(const char*, float, float, const char*, Vector);
+#endif
+
+#ifdef __WIN32
+ int win32Line(int n, float* x, float* y);
+ int win32Text(const char*, float, float, const char*, Vector);
+#endif
+
+ double calcTextAngle(const char*, Vector);
+ Matrix calcTextPos(const Vector&, double, const char*,
+ const char*, Vector, Tk_Font);
+
+ public:
+ GridBase(Widget*);
+ GridBase(Widget*, const char*);
+ virtual ~GridBase();
+
+ int gAttr(int attr, double value, double* old, int prim);
+ int gCap(int, int);
+ int gFlush() {return 1;}
+
+ const char* option() {return option_;}
+};
+
+#endif
diff --git a/tksao/util/ps.C b/tksao/util/ps.C
new file mode 100644
index 0000000..b3a5b1e
--- /dev/null
+++ b/tksao/util/ps.C
@@ -0,0 +1,377 @@
+// Copyright (C) 1999-2016
+// Smithsonian Astrophysical Observatory, Cambridge, MA, USA
+// For conditions of distribution and use, see copyright notice in "copyright"
+
+#include <string.h>
+
+#include "ps.h"
+#include "util.h"
+
+Filter::Filter()
+{
+ buf_ = new unsigned char[BUFSIZE];
+ ptr_ = buf_;
+}
+
+Filter::~Filter()
+{
+ if (buf_)
+ delete [] buf_;
+}
+
+void Filter::flush(ostream& str)
+{
+ cflush();
+ eflush(str);
+}
+
+// Compress
+
+void NoCompress::in(unsigned char c)
+{
+ *ptr_++ = c;
+}
+
+// RLE
+
+RLE::RLE()
+{
+ state = 0;
+ num = 0;
+}
+
+void RLE::in(unsigned char c)
+{
+ current = c;
+ switch (state) {
+ case 0: // start state
+ if (num == 0) // not enough info yet
+ rle[num++] = current;
+ else {
+ if (current != rle[num-1]) { // looks like non repeating
+ rle[num++] = current;
+ state = 1;
+ }
+ else { // looks like repeating
+ num++;
+ state = 2;
+ }
+ }
+ break;
+
+ case 1: // non repeat state
+ if (current != rle[num-1]) {
+ rle[num++] = current;
+
+ if (num >= RLESIZE) { // time to dump the rlefer
+ dumpNonRepeat(); // dump the buffer
+ num = 0; // and reset counter
+ state = 0;
+ }
+ }
+ else {
+ num--; // decr
+ dumpNonRepeat(); // dump the buffer
+
+ state = 2; // repeat state
+ rle[0] = current; // save repeat char
+ num = 2; // we aready have two now
+ }
+ break;
+
+ case 2: // repeat state
+ if (current == rle[0]) {
+ if (++num >= RLESIZE) {
+ dumpRepeat(); // dump the repeat count
+ state = 0;
+ num = 0;
+ }
+ }
+ else {
+ dumpRepeat(); // dump the repeat count
+ state = 1; // back to non repeat state
+ rle[0] = current; // save first char
+ num = 1; // we have one now
+ }
+ break;
+ }
+}
+
+void RLE::dumpNonRepeat()
+{
+ if (num) {
+ *ptr_++ = (unsigned char)(num-1);
+ for (int i=0; i<num; i++)
+ *ptr_++ = rle[i];
+ }
+}
+
+void RLE::dumpRepeat()
+{
+ if (num) {
+ *ptr_++ = (unsigned char)(257-num);
+ *ptr_++ = rle[0];
+ }
+}
+
+void RLE::cflush()
+{
+ switch (state) {
+ case 0:
+ case 1:
+ dumpNonRepeat();
+ break;
+ case 2:
+ dumpRepeat();
+ break;
+ }
+}
+
+// GZIP
+
+GZIP::GZIP()
+{
+ stream_ = new z_stream;
+ gzip_ = new unsigned char[GZIPSIZE];
+
+ stream_->next_in = NULL;
+ stream_->avail_in = 0;
+ stream_->next_out = NULL;
+ stream_->avail_out = 0;
+
+ stream_->zalloc = NULL;
+ stream_->zfree = NULL;
+ stream_->opaque = NULL;
+
+ if (deflateInit(stream_, Z_DEFAULT_COMPRESSION) != Z_OK) {
+ if (DebugGZ)
+ cerr << "deflateInit error" << endl;
+ return;
+ }
+
+ stream_->next_out = gzip_;
+ stream_->avail_out = GZIPSIZE;
+}
+
+GZIP::~GZIP()
+{
+ if (deflateEnd(stream_) != Z_OK)
+ if (DebugGZ)
+ cerr << "deflateEnd error" << endl;
+
+ if (gzip_)
+ delete [] gzip_;
+
+ if (stream_)
+ delete stream_;
+}
+
+void GZIP::in(unsigned char c)
+{
+ stream_->next_in = &c;
+ stream_->avail_in = 1;
+
+ while (stream_->avail_in > 0 && deflategz(Z_NO_FLUSH) == Z_OK);
+}
+
+void GZIP::cflush()
+{
+ // flush any pending output
+ while (deflategz(Z_FINISH) == Z_OK);
+}
+
+int GZIP::deflategz(int flush)
+{
+ int result = deflate(stream_, flush);
+
+ switch (result) {
+ case Z_OK:
+ if (DebugGZ)
+ cerr << "deflate OK: avail_in " << stream_->avail_in
+ << " avail_out " << stream_->avail_out << endl;
+ break;
+ case Z_STREAM_END:
+ if (DebugGZ)
+ cerr << "deflate STRM_END: avail_in " << stream_->avail_in
+ << " avail_out " << stream_->avail_out << endl;
+ break;
+ default:
+ if (DebugGZ)
+ cerr << "deflate Error " << result << endl;
+ return result;
+ }
+
+ if (stream_->avail_out == 0 || result != Z_OK) {
+ int s = GZIPSIZE - stream_->avail_out;
+ unsigned char* d = gzip_;
+
+ if (s>0) {
+ if (ptr_+s > buf_+BUFSIZE) {
+ cerr << "deflate buffer overflow "
+ << stream_->avail_out << ' ' << result << endl;
+ return result;
+ }
+
+ memcpy(ptr_,d,s);
+ ptr_ += s;
+
+ if (DebugGZ)
+ cerr << "deflate send " << s << ' ' << result << endl;
+ }
+
+ stream_->next_out = gzip_;
+ stream_->avail_out = GZIPSIZE;
+ }
+
+ return result;
+}
+
+// Encode
+
+Encode::Encode(int l)
+{
+ level = l;
+ lineCount = 0;
+}
+
+// AsciiHex
+
+AsciiHex::AsciiHex(int l) : Encode(l) {}
+
+void AsciiHex::out(ostream& str)
+{
+ unsigned char* p = buf_;
+ while (p < ptr_) {
+ unsigned short c = *p++;
+ str << hex << setfill('0') << setw(2) << c;
+
+ lineCount += 2;
+ if (lineCount >= LINELIMIT) {
+ str << endl;
+ lineCount = 0;
+ }
+ }
+ ptr_ = buf_; // reset buffer
+}
+
+void AsciiHex::eflush(ostream& str)
+{
+ out(str);
+ switch (level) {
+ case 1:
+ str << endl;
+ break;
+ case 2:
+ case 3:
+ str << endl << '>' << endl;
+ break;
+ }
+}
+
+// Ascii85
+
+Ascii85::Ascii85(int l) : Encode(l)
+{
+ byteswap = (*(short *)"\001\000" & 0x0001);
+
+ buf85.c = 0;
+ index = 0;
+}
+
+int32_t Ascii85::swap(uint32_t* p)
+{
+ int32_t r;
+ swap4((char*)p, (char*)&r);
+ return r;
+}
+
+void Ascii85::out(ostream& str)
+{
+ unsigned char* p = buf_;
+ while (p < ptr_) {
+ buf85.b[index++] = *p++;
+ if (index==4) {
+ dump(str);
+ }
+ }
+
+ ptr_ = buf_; // reset buffer
+}
+
+void Ascii85::dump(ostream& str)
+{
+ // all zeros?
+ if (buf85.c == 0) {
+ str << 'z';
+ if (++lineCount >= LINELIMIT) {
+ str << endl;
+ lineCount = 0;
+ }
+ }
+ else {
+ uint32_t b;
+ if (!byteswap)
+ b = buf85.c;
+ else
+ b = swap(&buf85.c);
+
+ for (int ii=4; ii>=0 ; ii--) {
+ uint32_t base = 1;
+ for (int jj=0; jj<ii; jj++)
+ base *= 85;
+
+ uint32_t a = b / base;
+ b -= a * base;
+ str << (char)(a + '!');
+ if (++lineCount >= LINELIMIT) {
+ str << endl;
+ lineCount = 0;
+ }
+ }
+ }
+ index = 0;
+ buf85.c = 0;
+}
+
+void Ascii85::eflush(ostream& str)
+{
+ // dump the remainder
+ out(str);
+
+ // we can't have any z's here
+ // also, only write index+1 chars
+ if (index) {
+ uint32_t b;
+ if (!byteswap)
+ b = buf85.c;
+ else
+ b = swap(&buf85.c);
+
+ for (int ii=4; ii>=(4-index); ii--) {
+ uint32_t base = 1;
+ for (int jj=0; jj<ii; jj++)
+ base *= 85;
+
+ uint32_t a = b / base;
+ b -= a * base;
+ str << (char)(a + '!');
+ if (++lineCount >= LINELIMIT) {
+ str << endl;
+ lineCount = 0;
+ }
+ }
+ }
+ index = 0;
+ buf85.c = 0;
+
+ switch (level) {
+ case 1:
+ str << endl;
+ break;
+ case 2:
+ case 3:
+ str << endl << "~>" << endl;
+ break;
+ }
+}
+
diff --git a/tksao/util/ps.h b/tksao/util/ps.h
new file mode 100644
index 0000000..83c6e70
--- /dev/null
+++ b/tksao/util/ps.h
@@ -0,0 +1,171 @@
+// Copyright (C) 1999-2016
+// Smithsonian Astrophysical Observatory, Cambridge, MA, USA
+// For conditions of distribution and use, see copyright notice in "copyright"
+
+#ifndef __ps_h__
+#define __ps_h__
+
+#include <stdint.h>
+
+#include <iostream>
+#include <sstream>
+#include <iomanip>
+using namespace std;
+
+#include "zlib.h"
+extern int DebugGZ;
+
+// we need this large for gzip
+#define GZIPSIZE 8192
+#define BUFSIZE GZIPSIZE*8
+#define RLESIZE 128
+#define LINELIMIT 80
+
+// Filter Base Class
+class Filter {
+protected:
+ unsigned char* buf_;
+ unsigned char* ptr_;
+
+ virtual void cflush() =0;
+ virtual void eflush(ostream&) =0;
+
+public:
+ Filter();
+ virtual ~Filter();
+
+ virtual void in(unsigned char) =0;
+ virtual void out(ostream&) =0;
+ void flush(ostream&);
+
+ friend Filter& operator<<(Filter& f, unsigned char c) {f.in(c); return f;}
+ friend ostream& operator<<(ostream& s, Filter& f) {f.out(s); return s;}
+};
+
+// Compress Base Class
+class Compress : public virtual Filter {
+public:
+ virtual void in(unsigned char) =0;
+ virtual void cflush() =0;
+};
+
+class NoCompress : public virtual Filter, public Compress {
+public:
+ void in(unsigned char);
+ void cflush() {}
+};
+
+// RLE
+class RLE : public virtual Filter, public Compress {
+private:
+ int state;
+ unsigned char current;
+ unsigned char rle[RLESIZE];
+ int num;
+
+ void dumpNonRepeat();
+ void dumpRepeat();
+
+public:
+ RLE();
+
+ void in(unsigned char);
+ void cflush();
+};
+
+// GZIP
+class GZIP : public virtual Filter, public Compress {
+private:
+ z_stream* stream_;
+ unsigned char* gzip_;
+
+ int deflategz(int);
+
+public:
+ GZIP();
+ ~GZIP();
+
+ void in(unsigned char);
+ void cflush();
+};
+
+// Encode Base Class
+class Encode : public virtual Filter {
+protected:
+ int level;
+ int lineCount;
+
+public:
+ Encode(int);
+
+ virtual void out(ostream&) =0;
+ virtual void eflush(ostream&) =0;
+};
+
+// AsciiHex
+class AsciiHex : public virtual Filter, public Encode {
+public:
+ AsciiHex(int);
+
+ void out(ostream&);
+ void eflush(ostream&);
+};
+
+// Ascii85
+class Ascii85 : public virtual Filter, public Encode {
+private:
+ int index;
+ int byteswap;
+ union {
+ unsigned char b[4];
+ uint32_t c;
+ } buf85;
+
+ void dump(ostream&);
+ int32_t swap(uint32_t* ptr);
+
+public:
+ Ascii85(int);
+
+ void out(ostream&);
+ void eflush(ostream&);
+};
+
+// PS Filters
+class NoCompressAsciiHex :
+public virtual Filter, public NoCompress, public AsciiHex {
+ public:
+ NoCompressAsciiHex(int l) : AsciiHex(l) {};
+};
+
+class NoCompressAscii85 :
+public virtual Filter, public NoCompress, public Ascii85 {
+ public:
+ NoCompressAscii85(int l) : Ascii85(l) {};
+};
+
+class RLEAsciiHex :
+public virtual Filter, public RLE, public AsciiHex {
+ public:
+ RLEAsciiHex(int l) : AsciiHex(l) {};
+};
+
+class RLEAscii85 :
+public virtual Filter, public RLE, public Ascii85 {
+ public:
+ RLEAscii85(int l) : Ascii85(l) {};
+};
+
+class GZIPAsciiHex :
+public virtual Filter, public GZIP, public AsciiHex {
+ public:
+ GZIPAsciiHex(int l) : AsciiHex(l) {};
+};
+
+class GZIPAscii85 :
+public virtual Filter, public GZIP, public Ascii85 {
+ public:
+ GZIPAscii85(int l) : Ascii85(l) {};
+};
+
+#endif
diff --git a/tksao/util/smooth.C b/tksao/util/smooth.C
new file mode 100644
index 0000000..db70981
--- /dev/null
+++ b/tksao/util/smooth.C
@@ -0,0 +1,67 @@
+// Copyright (C) 1999-2016
+// Smithsonian Astrophysical Observatory, Cambridge, MA, USA
+// For conditions of distribution and use, see copyright notice in "copyright"
+
+#include <iostream>
+#include <sstream>
+#include <iomanip>
+using namespace std;
+
+#include <math.h>
+
+#include "smooth.h"
+
+void boxcar(double* kernel, int r)
+{
+ int rr = 2*r+1;
+ int ksz = rr*rr;
+
+ double* ptr = kernel;
+ for (int jj=0; jj<rr; jj++)
+ for (int ii=0; ii<rr; ii++, ptr++)
+ *ptr = 1./ksz;
+}
+
+void tophat(double* kernel, int r)
+{
+ int rr = 2*r+1;
+ int ksz = rr*rr;
+
+ double kt = 0;
+ for (int y=-r; y<=r; y++) {
+ for (int x=-r; x<=r; x++) {
+ if ((x*x + y*y) <= r*r) {
+ kernel[(y+r)*rr+(x+r)] = 1;
+ kt++;
+ }
+ }
+ }
+
+ // normalize kernel
+ for (int aa=0; aa<ksz; aa++)
+ kernel[aa] /= kt;
+}
+
+void gaussian(double* kernel, int r)
+{
+ int rr = 2*r+1;
+ int ksz = rr*rr;
+ double sigma = r/2.;
+ double s2 = sigma*sigma;
+
+ double kt = 0;
+ for (int y=-r; y<=r; y++) {
+ for (int x=-r; x<=r; x++) {
+ if ((x*x + y*y) <= r*r) {
+ double vv = exp(-.5*((x*x + y*y)/s2));
+ kernel[(y+r)*rr+(x+r)] = vv;
+ kt += vv;
+ }
+ }
+ }
+
+ // normalize kernel
+ for (int aa=0; aa<ksz; aa++)
+ kernel[aa] /= kt;
+}
+
diff --git a/tksao/util/smooth.h b/tksao/util/smooth.h
new file mode 100644
index 0000000..fccf252
--- /dev/null
+++ b/tksao/util/smooth.h
@@ -0,0 +1,12 @@
+// Copyright (C) 1999-2016
+// Smithsonian Astrophysical Observatory, Cambridge, MA, USA
+// For conditions of distribution and use, see copyright notice in "copyright"
+
+#ifndef __smooth_h__
+#define __smooth_h__
+
+void boxcar(double* kernel, int r);
+void tophat(double* kernel, int r);
+void gaussian(double* kernel, int r);
+
+#endif
diff --git a/tksao/util/util.C b/tksao/util/util.C
new file mode 100644
index 0000000..644290c
--- /dev/null
+++ b/tksao/util/util.C
@@ -0,0 +1,486 @@
+// 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 "util.h"
+
+// Error in mapping
+int maperr= 0;
+
+static char tobuf[1024];
+
+int sexSign; // used by parser and lex to indicate sign of dms or hms
+
+void swap2(char* src, char* dest) {
+ *(dest ) = *(src+1);
+ *(dest+1) = *(src );
+}
+
+void swap4(char* src, char* dest) {
+ *(dest ) = *(src+3);
+ *(dest+1) = *(src+2);
+ *(dest+2) = *(src+1);
+ *(dest+3) = *(src );
+}
+
+void swap8(char* src, char* dest) {
+ *(dest ) = *(src+7);
+ *(dest+1) = *(src+6);
+ *(dest+2) = *(src+5);
+ *(dest+3) = *(src+4);
+ *(dest+4) = *(src+3);
+ *(dest+5) = *(src+2);
+ *(dest+6) = *(src+1);
+ *(dest+7) = *(src );
+}
+
+int lsb()
+{
+ return (*(short *)"\001\000" & 0x0001);
+}
+
+char* dupstr(const char* str)
+{
+ char* copy;
+ if (str) {
+ copy=new char[strlen(str)+1];
+ strcpy(copy,str);
+ }
+ else
+ copy=NULL;
+
+ return copy;
+}
+
+char* trim(const char* str)
+{
+ char* rr = dupstr(str);
+ char* ptr = rr;
+ while (ptr && *ptr)
+ ptr++;
+ ptr--;
+ while (ptr && (*ptr == ' '))
+ ptr--;
+ ptr++;
+ *ptr = '\0';
+
+ return rr;
+}
+
+char* toLower(const char* str)
+{
+ char* rr = dupstr(str);
+ char* ptr = rr;
+ while (*ptr) {
+ *ptr = (char)(tolower(((int)(*ptr))));
+ ptr++;
+ }
+ return rr;
+}
+
+char* toUpper(const char* str)
+{
+ char* rr = dupstr(str);
+ char* ptr = rr;
+ while (*ptr) {
+ *ptr = (char)(toupper(((int)(*ptr))));
+ ptr++;
+ }
+ return rr;
+}
+
+char* toConstLower(const char* str)
+{
+ strncpy(tobuf,str,1024);
+ char* ptr = tobuf;
+ while (*ptr) {
+ *ptr = (char)(tolower(((int)(*ptr))));
+ ptr++;
+ }
+ return tobuf;
+}
+
+char* toConstUpper(const char* str)
+{
+ strncpy(tobuf,str,1024);
+ char* ptr = tobuf;
+ while (*ptr) {
+ *ptr = (char)(toupper(((int)(*ptr))));
+ ptr++;
+ }
+ return tobuf;
+}
+
+double zeroTWOPI(double aa)
+{
+ double rr = aa;
+ if (rr>0)
+ while (rr>=M_TWOPI)
+ rr -= M_TWOPI;
+ else
+ while (rr<0)
+ rr += M_TWOPI;
+ return rr;
+}
+
+double zero360(double aa)
+{
+ double rr = aa;
+ if (rr>=0)
+ while (rr>360)
+ rr -= 360;
+ else
+ while (rr<0)
+ rr += 360;
+ return rr;
+}
+
+double m180To180(double aa)
+{
+ // incoming 0-360
+ double rr = aa;
+ if (rr>180)
+ rr -= 360;
+ return rr;
+}
+
+double degToRad(double dd)
+{
+ double rr = M_PI*dd/180.;
+ return zeroTWOPI(rr);
+}
+
+double radToDeg(double rr)
+{
+ double dd = 180.*rr/M_PI;
+ return zero360(dd);
+}
+
+double dmsToDegree(int sign, int degree, int min, double sec)
+{
+ // sign is needed because of -00 vs +00
+ return double(sign) * (abs(degree) + (min/60.) + (sec/60./60.));
+}
+
+int parseSection(char* lbuf, Vector* v1, Vector* v2)
+{
+ double x1, y1, x2, y2;
+ char d1,d2,d3,d4,d5; // dummy char
+ string x(lbuf);
+ istringstream str(x);
+ str >> d1 >> x1 >> d2 >> x2 >> d3 >> y1 >> d4 >> y2 >> d5;
+
+ // verify input
+ if (!(d1=='[' && d2==':' && d3==',' && d4==':' && d5==']'))
+ return 0;
+
+ // it looks ok
+ *v1 = Vector(x1,y1);
+ *v2 = Vector(x2,y2);
+
+ return 1;
+}
+
+double parseSEXStr(const char* d)
+{
+ char* dms = dupstr(d); // its going to get clobbered
+ char* ptr = dms;
+
+ int sign = 1;
+ int degree = atoi(strtok(ptr,":"));
+ int minute = atoi(strtok(NULL,":"));
+ float sec = atof(strtok(NULL,":"));
+
+ // assumes the minus sign is the first char
+ if (degree != 0)
+ sign = degree>0 ? 1 : -1;
+ else
+ sign = d[0] == '-' ? -1 : 1;
+
+ delete [] dms;
+
+ return dmsToDegree(sign,abs(degree),minute,sec);
+}
+
+double parseHMSStr(const char* str)
+{
+ char* hms = dupstr(str); // its going to get clobbered
+ char* ptr = hms;
+
+ int sign = 1;
+ int hour = atoi(strtok(ptr,"h"));
+ int minute = atoi(strtok(NULL,"m"));
+ float second = atof(strtok(NULL,"s"));
+
+ // assumes the minus sign is the first char
+ if (hour != 0)
+ sign = hour>0 ? 1 : -1;
+ else
+ sign = str[0] == '-' ? -1 : 1;
+
+ delete [] hms;
+
+ return dmsToDegree(sign,abs(hour),minute,second)/24.*360.;
+}
+
+double parseDMSStr(const char* str)
+{
+ char* dms = dupstr(str); // its going to get clobbered
+ char* ptr = dms;
+
+ int sign = 1;
+ int degree = atoi(strtok(ptr,"d"));
+ int minute = atoi(strtok(NULL,"m"));
+ float sec = atof(strtok(NULL,"s"));
+
+ // assumes the minus sign is the first char
+ if (degree != 0)
+ sign = degree>0 ? 1 : -1;
+ else
+ sign = str[0] == '-' ? -1 : 1;
+
+ delete [] dms;
+
+ return dmsToDegree(sign,abs(degree),minute,sec);
+}
+
+double RGB2Gray(double red, double green, double blue)
+{
+ return 0.30*red + 0.59*green + 0.11*blue;
+}
+
+unsigned char RGB2Gray(unsigned char red, unsigned char green,
+ unsigned char blue)
+{
+ // we have a round off problem here, add FLT_EPSILON to kick it over
+ return (unsigned char)(0.30*red + 0.59*green + 0.11*blue + FLT_EPSILON);
+}
+
+void RGB2CMYK(unsigned char red, unsigned char green, unsigned char blue,
+ unsigned char* cyan, unsigned char* magenta,
+ unsigned char* yellow, unsigned char* black)
+{
+ // convert To CMY
+
+ *cyan = UCHAR_MAX-red;
+ *magenta = UCHAR_MAX-green;
+ *yellow = UCHAR_MAX-blue;
+ *black =0;
+
+ // determine black
+
+ *black = UCHAR_MAX;
+ if (*cyan < *black)
+ *black = *cyan;
+ if (*magenta < *black)
+ *black = *magenta;
+ if (*yellow < *black)
+ *black = *yellow;
+
+ // substract out black
+
+ *cyan -= *black;
+ *magenta -= *black;
+ *yellow -= *black;
+}
+
+void RGB2CMYK(unsigned short red, unsigned short green, unsigned short blue,
+ unsigned short* cyan, unsigned short* magenta,
+ unsigned short* yellow, unsigned short* black)
+{
+ // convert To CMY
+
+ *cyan = USHRT_MAX-red;
+ *magenta = USHRT_MAX-green;
+ *yellow = USHRT_MAX-blue;
+ *black =0;
+
+ // determine black
+
+ *black = USHRT_MAX;
+ if (*cyan < *black)
+ *black = *cyan;
+ if (*magenta < *black)
+ *black = *magenta;
+ if (*yellow < *black)
+ *black = *yellow;
+
+ // substract out black
+
+ *cyan -= *black;
+ *magenta -= *black;
+ *yellow -= *black;
+}
+
+ostream& psColorGray(XColor* clr, ostream& str)
+{
+ if (clr) {
+ float red = clr->red/float(USHRT_MAX);
+ float green = clr->green/float(USHRT_MAX);
+ float blue = clr->blue/float(USHRT_MAX);
+ str << dec << RGB2Gray(red,green,blue);
+ }
+
+ return str;
+}
+
+ostream& psColorRGB(XColor* clr, ostream& str)
+{
+ if (clr) {
+ float red = clr->red/float(USHRT_MAX);
+ float green = clr->green/float(USHRT_MAX);
+ float blue = clr->blue/float(USHRT_MAX);
+ str << dec << red << ' ' << green << ' ' << blue;
+ }
+
+ return str;
+}
+
+ostream& psColorCMYK(XColor* clr, ostream& str)
+{
+ if (clr) {
+ unsigned short cyan;
+ unsigned short magenta;
+ unsigned short yellow;
+ unsigned short black;
+
+ RGB2CMYK(clr->red, clr->green, clr->blue, &cyan, &magenta, &yellow, &black);
+
+ str << dec
+ << cyan/float(USHRT_MAX) << ' '
+ << magenta/float(USHRT_MAX) << ' '
+ << yellow/float(USHRT_MAX) << ' '
+ << black/float(USHRT_MAX);
+ }
+ return str;
+}
+
+char* psStr = NULL; // psQuote returned string
+char* psQuote(const char* str)
+{
+ // we must must quote '(', ')', and '\'
+ if (psStr)
+ delete [] psStr;
+
+ psStr = new char[strlen(str)*2+1]; // worst case size
+
+ char* out = psStr;
+ const char* in = str;
+ while (in && *in) {
+ if (*in == '(' || *in == ')' || *in == '\\')
+ *out++ = '\\';
+ *out++ = *in++;
+ }
+
+ *out++ = '\0'; // terminating char
+ return psStr;
+}
+
+const char* psFontName(const char* font)
+{
+ char* str = (char*)font;
+ char* ff = str;
+ while (*str && *str++ != ' ');
+ // char* zz = str;
+ while (*str && *str++ != ' ');
+ char* ww = str;
+ while (*str && *str++ != ' ');
+ char* ss = str;
+
+ if (ff && ww && ss)
+ return psFontName(ff,ww,ss);
+ else
+ return psFonts[0];
+}
+
+int psFontSize(const char* font)
+{
+ char* str = (char*)font;
+ while (*str && *str++ != ' ');
+ return atoi(str);
+}
+
+const char* psFontName(const char* font, const char* weight, const char* slant)
+{
+ int ptr = 0;
+ if (!strncmp(font,"helvetica",4))
+ ptr = 0;
+ else if (!strncmp(font,"times",4))
+ ptr = 4;
+ else if (!strncmp(font,"courier",4))
+ ptr = 8;
+
+ if (!strncmp(weight,"normal",4))
+ ;
+ else if (!strncmp(weight,"bold",4))
+ ptr +=2;
+
+ if (!strncmp(slant,"roman",4))
+ ;
+ else if (!strncmp(slant,"italic",4))
+ ptr++;
+
+ return psFonts[ptr];
+}
+
+int fCompare(const void* a, const void* b)
+{
+ float* aa = (float*)a;
+ float* bb = (float*)b;
+
+ if (*aa < *bb)
+ return -1;
+ if (*aa > *bb)
+ return 1;
+ return 0;
+}
+
+int dCompare(const void* a, const void* b)
+{
+ double* aa = (double*)a;
+ double* bb = (double*)b;
+
+ if (*aa < *bb)
+ return -1;
+ if (*aa > *bb)
+ return 1;
+ return 0;
+}
+
+Vector mapLen(const Vector& v, const Matrix& mx)
+{
+ // remove translation
+ Vector t = Vector() * mx;
+ Matrix sr = mx * Translate(-t);
+
+ // remove rotation
+ Vector r = Vector(1,0) * sr;
+ Matrix s = sr * Rotate(r.angle());
+
+ // all that is left is Scaling
+ return (v*s).abs();
+}
+
+#if defined (MAC_OSX_TK) || (_WIN32)
+
+int XSetClipRectangles(Display *d, GC gc, int clip_x_origin, int clip_y_origin,
+ XRectangle* rectangles, int n, int ordering)
+{
+ TkRegion clipRgn = TkCreateRegion();
+
+ while (n--) {
+ XRectangle rect = *rectangles;
+
+ rect.x += clip_x_origin;
+ rect.y += clip_y_origin;
+ TkUnionRectWithRegion(&rect, clipRgn, clipRgn);
+ rectangles++;
+ }
+ TkSetRegion(d, gc, clipRgn);
+ TkDestroyRegion(clipRgn);
+ return 1;
+}
+
+#endif
diff --git a/tksao/util/util.h b/tksao/util/util.h
new file mode 100644
index 0000000..383095a
--- /dev/null
+++ b/tksao/util/util.h
@@ -0,0 +1,125 @@
+// Copyright (C) 1999-2016
+// Smithsonian Astrophysical Observatory, Cambridge, MA, USA
+// For conditions of distribution and use, see copyright notice in "copyright"
+
+#ifndef __util_h__
+#define __util_h__
+
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <float.h>
+#include <math.h>
+
+#include <iostream>
+#include <sstream>
+#include <iomanip>
+using namespace std;
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#include "fuzzy.h"
+#include "vector.h"
+
+#ifndef PATH_MAX
+#define PATH_MAX 1024
+#endif
+
+#ifdef _WIN32
+#include <win32lib.h>
+#endif
+
+#ifdef MAC_OSX_TK
+#include <macosxlib.h>
+void XXWarpPointer(Display* display, Window src_w, Window dest_w,
+ int src_x, int src_y,
+ unsigned int src_width, unsigned int src_height,
+ int dest_x, int dest_y);
+#endif
+
+#if defined (MAC_OSX_TK) || (_WIN32)
+int XSetClipRectangles(Display *d, GC gc, int clip_x_origin, int clip_y_origin,
+ XRectangle* rectangles, int n, int ordering);
+#endif
+
+#define STRCMP(which,str,cnt) (!strncmp(toConstLower(which), str, cnt) && strlen(which)==cnt)
+
+static const char psFonts[12][32] = {
+ {"Helvetica"},
+ {"Helvetica-Oblique"},
+ {"Helvetica-Bold"},
+ {"Helvetica-BoldOblique"},
+
+ {"Times-Roman"},
+ {"Times-Italic"},
+ {"Times-Bold"},
+ {"Times-BoldItalic"},
+
+ {"Courier"},
+ {"Courier-Oblique"},
+ {"Courier-Bold"},
+ {"Courier-BoldOblique"}
+};
+
+#ifndef __CYGWIN__
+static const double M_TWOPI = 2*M_PI;
+#endif
+static const double M_THREEPI = 3*M_PI;
+static const double M_FOURPI = 4*M_PI;
+
+extern int maperr;
+
+extern int lsb();
+
+extern void swap2(char* src, char* dest);
+extern void swap4(char* src, char* dest);
+extern void swap8(char* src, char* dest);
+
+// defined in ds9.C
+extern void internalError(const char*);
+
+extern char* dupstr(const char*);
+extern char* trim(const char*);
+extern char* toLower(const char*);
+extern char* toUpper(const char*);
+extern char* toConstLower(const char*);
+extern char* toConstUpper(const char*);
+
+extern double zeroTWOPI(double);
+extern double zero360(double);
+extern double m180To180(double);
+extern double degToRad(double);
+extern double radToDeg(double);
+
+extern int parseSection(char*, Vector*, Vector*);
+
+extern double dmsToDegree(int, int, int, double);
+extern double parseSEXStr(const char*);
+extern double parseHMSStr(const char*);
+extern double parseDMSStr(const char*);
+
+extern double RGB2Gray(double, double, double);
+extern unsigned char RGB2Gray(unsigned char, unsigned char, unsigned char);
+extern void RGB2CMYK(unsigned char, unsigned char, unsigned char,
+ unsigned char*, unsigned char*, unsigned char*,
+ unsigned char*);
+extern void RGB2CMYK(unsigned short, unsigned short, unsigned short,
+ unsigned short*, unsigned short*, unsigned short*,
+ unsigned short*);
+extern ostream& psColorGray(XColor*, ostream&);
+extern ostream& psColorRGB(XColor*, ostream&);
+extern ostream& psColorCMYK(XColor*, ostream&);
+
+extern char* psQuote(const char*);
+
+extern const char* psFontName(const char*);
+extern int psFontSize(const char*);
+extern const char* psFontName(const char*, const char*, const char*);
+
+extern int fCompare(const void*, const void*);
+extern int dCompare(const void*, const void*);
+
+extern Vector mapLen(const Vector& v, const Matrix& mx);
+
+#endif