Index: /nanovis/tags/1.1.4/Axis.cpp
===================================================================
--- /nanovis/tags/1.1.4/Axis.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/Axis.cpp	(revision 4930)
@@ -0,0 +1,534 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors: George A. Howlett <gah@purdue.edu>
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <float.h>
+#include <string.h>
+
+#include "Axis.h"
+
+using namespace nv;
+
+inline bool DEFINED(double x) {
+    return !isnan(x);
+}
+
+inline double EXP10(double x) {
+    return pow(10.0, x);
+}
+
+inline int ROUND(double x) {
+    return (int)round(x);
+}
+
+inline double UROUND(double x, double u) {
+    return (ROUND((x)/(u)))*u;
+}
+
+inline double UCEIL(double x, double u) {
+    return (ceil((x)/(u)))*u;
+}
+
+inline double UFLOOR(double x, double u) {
+    return (floor((x)/(u)))*u;
+}
+
+/**
+ * Reference: Paul Heckbert, "Nice Numbers for Graph Labels",
+ *            Graphics Gems, pp 61-63.  
+ *
+ * Finds a "nice" number approximately equal to x.
+ */
+static double
+niceNum(double x,
+        int round)              /* If non-zero, round. Otherwise take ceiling
+                                 * of value. */
+{
+    double expt;                /* Exponent of x */
+    double frac;                /* Fractional part of x */
+    double nice;                /* Nice, rounded fraction */
+
+    expt = floor(log10(x));
+    frac = x / EXP10(expt);     /* between 1 and 10 */
+    if (round) {
+        if (frac < 1.5) {
+            nice = 1.0;
+        } else if (frac < 3.0) {
+            nice = 2.0;
+        } else if (frac < 7.0) {
+            nice = 5.0;
+        } else {
+            nice = 10.0;
+        }
+    } else {
+        if (frac <= 1.0) {
+            nice = 1.0;
+        } else if (frac <= 2.0) {
+            nice = 2.0;
+        } else if (frac <= 5.0) {
+            nice = 5.0;
+        } else {
+            nice = 10.0;
+        }
+    }
+    return nice * EXP10(expt);
+}
+
+void 
+Ticks::setTicks()
+{
+    _numTicks = 0;
+    _ticks = new float[_nSteps];
+    if (_step == 0.0) { 
+        /* Hack: A zero step indicates to use log values. */
+        unsigned int i;
+        /* Precomputed log10 values [1..10] */
+        static double logTable[] = {
+            0.0, 
+            0.301029995663981, 
+            0.477121254719662, 
+            0.602059991327962, 
+            0.698970004336019, 
+            0.778151250383644, 
+            0.845098040014257,
+            0.903089986991944, 
+            0.954242509439325, 
+            1.0
+        };
+        for (i = 0; i < _nSteps; i++) {
+            _ticks[i] = logTable[i];
+        }
+    } else {
+        double value;
+        unsigned int i;
+    
+        value = _initial;        /* Start from smallest axis tick */
+        for (i = 0; i < _nSteps; i++) {
+            value = _initial + (_step * i);
+            _ticks[i] = UROUND(value, _step);
+        }
+    }
+    _numTicks = _nSteps;
+}
+
+Axis::Axis(const char *axisName) :
+    _name(strdup(axisName)),
+    _flags(AUTOSCALE),
+    _title(NULL),
+    _units(NULL),
+    _valueMin(DBL_MAX),
+    _valueMax(-DBL_MAX),
+    _reqMin(NAN),
+    _reqMax(NAN),
+    _min(DBL_MAX),
+    _max(-DBL_MAX),
+    _range(0.0),
+    _scale(0.0),
+    _reqStep(0.0),
+    _major(5),
+    _minor(2)
+{
+}
+
+/**
+ * \brief Determines if a value lies within a given range.
+ *
+ * The value is normalized by the current axis range. If the normalized
+ * value is between [0.0..1.0] then it's in range.  The value is compared
+ * to 0 and 1., where 0.0 is the minimum and 1.0 is the maximum.
+ * DBL_EPSILON is the smallest number that can be represented on the host
+ * machine, such that (1.0 + epsilon) != 1.0.
+ *
+ * Please note, *max* can't equal *min*.
+ *
+ * \return If the value is within the interval [min..max], 1 is returned; 0
+ * otherwise.
+ */
+bool
+Axis::inRange(double x)
+{
+    if (_range < DBL_EPSILON) {
+        return (fabs(_max - x) >= DBL_EPSILON);
+    } else {
+        x = (x - _min) * _scale;
+        return ((x >= -DBL_EPSILON) && ((x - 1.0) < DBL_EPSILON));
+    }
+}
+
+void
+Axis::fixRange(double min, double max)
+{
+    if (min == DBL_MAX) {
+        if (DEFINED(_reqMin)) {
+            min = _reqMin;
+        } else {
+            min = (_flags & LOGSCALE) ? 0.001 : 0.0;
+        }
+    }
+    if (max == -DBL_MAX) {
+        if (DEFINED(_reqMax)) {
+            max = _reqMax;
+        } else {
+            max = 1.0;
+        }
+    }
+    if (min >= max) {
+        /*
+         * There is no range of data (i.e. min is not less than max), so
+         * manufacture one.
+         */
+        if (min == 0.0) {
+            min = 0.0, max = 1.0;
+        } else {
+            max = min + (fabs(min) * 0.1);
+        }
+    }
+
+    /*   
+     * The axis limits are either the current data range or overridden by the
+     * values selected by the user with the -min or -max options.
+     */
+    _valueMin = (DEFINED(_reqMin)) ? _reqMin : min;
+    _valueMax = (DEFINED(_reqMax)) ? _reqMax : max;
+    if (_valueMax < _valueMin) {
+        /*   
+         * If the limits still don't make sense, it's because one limit
+         * configuration option (-min or -max) was set and the other default
+         * (based upon the data) is too small or large.  Remedy this by making
+         * up a new min or max from the user-defined limit.
+         */
+        if (!DEFINED(_reqMin)) {
+            _valueMin = _valueMax - (fabs(_valueMax) * 0.1);
+        }
+        if (!DEFINED(_reqMax)) {
+            _valueMax = _valueMin + (fabs(_valueMax) * 0.1);
+        }
+    }
+}
+
+/**
+ * \brief Determine the range and units of a log scaled axis.
+ *
+ * Unless the axis limits are specified, the axis is scaled
+ * automatically, where the smallest and largest major ticks encompass
+ * the range of actual data values.  When an axis limit is specified,
+ * that value represents the smallest(min)/largest(max) value in the
+ * displayed range of values.
+ *
+ * Both manual and automatic scaling are affected by the step used.  By
+ * default, the step is the largest power of ten to divide the range in
+ * more than one piece.
+ *
+ * Automatic scaling:
+ * Find the smallest number of units which contain the range of values.
+ * The minimum and maximum major tick values will be represent the
+ * range of values for the axis. This greatest number of major ticks
+ * possible is 10.
+ *
+ * Manual scaling:
+ * Make the minimum and maximum data values the represent the range of
+ * the values for the axis.  The minimum and maximum major ticks will be
+ * inclusive of this range.  This provides the largest area for plotting
+ * and the expected results when the axis min and max values have be set
+ * by the user (.e.g zooming).  The maximum number of major ticks is 20.
+ *
+ * For log scale, there's the possibility that the minimum and
+ * maximum data values are the same magnitude.  To represent the
+ * points properly, at least one full decade should be shown.
+ * However, if you zoom a log scale plot, the results should be
+ * predictable. Therefore, in that case, show only minor ticks.
+ * Lastly, there should be an appropriate way to handle numbers
+ * <=0.
+ * <pre>
+ *          maxY
+ *            |    units = magnitude (of least significant digit)
+ *            |    high  = largest unit tick < max axis value
+ *      high _|    low   = smallest unit tick > min axis value
+ *            |
+ *            |    range = high - low
+ *            |    # ticks = greatest factor of range/units
+ *           _|
+ *        U   |
+ *        n   |
+ *        i   |
+ *        t  _|
+ *            |
+ *            |
+ *            |
+ *       low _|
+ *            |
+ *            |_minX________________maxX__
+ *            |   |       |      |       |
+ *     minY  low                        high
+ *           minY
+ *
+ *      numTicks = Number of ticks
+ *      min = Minimum value of axis
+ *      max = Maximum value of axis
+ *      range = Range of values (max - min)
+ *
+ * </pre>
+ *
+ *      If the number of decades is greater than ten, it is assumed
+ *      that the full set of log-style ticks can't be drawn properly.
+ */
+void
+Axis::logScale()
+{
+    double range;
+    double tickMin, tickMax;
+    double majorStep, minorStep;
+    int nMajor, nMinor;
+    double min, max;
+
+    nMajor = nMinor = 0;
+    /* Suppress compiler warnings. */
+    majorStep = minorStep = 0.0;
+    tickMin = tickMax = NAN;
+    min = _valueMin, max = _valueMax;
+    if (min < max) {
+        min = (min != 0.0) ? log10(fabs(min)) : 0.0;
+        max = (max != 0.0) ? log10(fabs(max)) : 1.0;
+
+        tickMin = floor(min);
+        tickMax = ceil(max);
+        range = tickMax - tickMin;
+        
+        if (range > 10) {
+            /* There are too many decades to display a major tick at every
+             * decade.  Instead, treat the axis as a linear scale.  */
+            range = niceNum(range, 0);
+            majorStep = niceNum(range / _major.reqNumTicks, 1);
+            tickMin = UFLOOR(tickMin, majorStep);
+            tickMax = UCEIL(tickMax, majorStep);
+            nMajor = (int)((tickMax - tickMin) / majorStep) + 1;
+            minorStep = EXP10(floor(log10(majorStep)));
+            if (minorStep == majorStep) {
+                nMinor = 4, minorStep = 0.2;
+            } else {
+                nMinor = ROUND(majorStep / minorStep) - 1;
+            }
+        } else {
+            if (tickMin == tickMax) {
+                tickMax++;
+            }
+            majorStep = 1.0;
+            nMajor = (int)(tickMax - tickMin + 1); /* FIXME: Check this. */
+            
+            minorStep = 0.0;    /* This is a special hack to pass
+                                 * information to the SetTicks
+                                 * method. An interval of 0.0 indicates
+                                 *   1) this is a minor sweep and 
+                                 *   2) the axis is log scale.  
+                                 */
+            nMinor = 10;
+        }
+        if ((_flags & TIGHT_MIN) || (DEFINED(_reqMin))) {
+            tickMin = min;
+            nMajor++;
+        }
+        if ((_flags & TIGHT_MAX) || (DEFINED(_reqMax))) {
+            tickMax = max;
+        }
+    }
+    _major.setValues(floor(tickMin), majorStep, nMajor);
+    _minor.setValues(minorStep, minorStep, nMinor);
+    _min = tickMin;
+    _max = tickMax;
+    _range = _max - _min;
+    _scale = 1.0 / _range;
+}
+
+/**
+ * \brief Determine the units of a linear scaled axis.
+ *
+ * The axis limits are either the range of the data values mapped
+ * to the axis (autoscaled), or the values specified by the -min
+ * and -max options (manual).
+ *
+ * If autoscaled, the smallest and largest major ticks will
+ * encompass the range of data values.  If the -loose option is
+ * selected, the next outer ticks are choosen.  If tight, the
+ * ticks are at or inside of the data limits are used.
+ *
+ * If manually set, the ticks are at or inside the data limits
+ * are used.  This makes sense for zooming.  You want the
+ * selected range to represent the next limit, not something a
+ * bit bigger.
+ *
+ * Note: I added an "always" value to the -loose option to force
+ * the manually selected axes to be loose. It's probably
+ * not a good idea.
+ *
+ * <pre>
+ *          maxY
+ *            |    units = magnitude (of least significant digit)
+ *            |    high  = largest unit tick < max axis value
+ *      high _|    low   = smallest unit tick > min axis value
+ *            |
+ *            |    range = high - low
+ *            |    # ticks = greatest factor of range/units
+ *           _|
+ *        U   |
+ *        n   |
+ *        i   |
+ *        t  _|
+ *            |
+ *            |
+ *            |
+ *       low _|
+ *            |
+ *            |_minX________________maxX__
+ *            |   |       |      |       |
+ *     minY  low                        high
+ *           minY
+ *
+ * 	numTicks = Number of ticks
+ * 	min = Minimum value of axis
+ * 	max = Maximum value of axis
+ * 	range = Range of values (max - min)
+ *
+ * </pre>
+ *
+ * Side Effects:
+ *	The axis tick information is set.  The actual tick values will
+ *	be generated later.
+ */
+void
+Axis::linearScale()
+{
+    double step;
+    double tickMin, tickMax;
+    unsigned int nTicks;
+
+    nTicks = 0;
+    step = 1.0;
+    /* Suppress compiler warning. */
+    tickMin = tickMax = 0.0;
+    if (_valueMin < _valueMax) {
+        double range;
+
+        range = _valueMax - _valueMin;
+        /* Calculate the major tick stepping. */
+        if (_reqStep > 0.0) {
+            /* An interval was designated by the user.  Keep scaling it until
+             * it fits comfortably within the current range of the axis.  */
+            step = _reqStep;
+            while ((2 * step) >= range) {
+                step *= 0.5;
+            }
+        } else {
+            range = niceNum(range, 0);
+            step = niceNum(range / _major.reqNumTicks, 1);
+        }
+        
+        /* Find the outer tick values. Add 0.0 to prevent getting -0.0. */
+        tickMin = floor(_valueMin / step) * step + 0.0;
+        tickMax = ceil(_valueMax / step) * step + 0.0;
+        
+        nTicks = ROUND((tickMax - tickMin) / step) + 1;
+    } 
+    _major.setValues(tickMin, step, nTicks);
+
+    /*
+     * The limits of the axis are either the range of the data ("tight") or at
+     * the next outer tick interval ("loose").  The looseness or tightness has
+     * to do with how the axis fits the range of data values.  This option is
+     * overridden when the user sets an axis limit (by either -min or -max
+     * option).  The axis limit is always at the selected limit (otherwise we
+     * assume that user would have picked a different number).
+     */
+    _min = ((_flags & TIGHT_MIN)||(DEFINED(_reqMin))) ? _valueMin : tickMin;
+    _max = ((_flags & TIGHT_MAX)||(DEFINED(_reqMax))) ? _valueMax : tickMax;
+    _range = _max - _min;
+    _scale = 1.0 / _range;
+
+    /* Now calculate the minor tick step and number. */
+
+    if ((_minor.reqNumTicks > 0) && (_minor.autoscale())) {
+        nTicks = _minor.reqNumTicks - 1;
+        step = 1.0 / (nTicks + 1);
+    } else {
+        nTicks = 0;             /* No minor ticks. */
+        step = 0.5;             /* Don't set the minor tick interval to
+                                 * 0.0. It makes the GenerateTicks routine
+                                 * create minor log-scale tick marks.  */
+    }
+    _minor.setValues(step, step, nTicks);
+}
+
+
+void
+Axis::setScale(double min, double max)
+{
+    fixRange(min, max);
+    if (_flags & LOGSCALE) {
+        logScale();
+    } else {
+        linearScale();
+    }
+    _major.sweepTicks();
+    _minor.sweepTicks();
+    makeTicks();
+}
+
+void
+Axis::makeTicks()
+{
+    _major.reset();
+    _minor.reset();
+    int i;
+    for (i = 0; i < _major.numTicks(); i++) {
+        double t1, t2;
+        int j;
+        
+        t1 = _major.tick(i);
+        /* Minor ticks */
+        for (j = 0; j < _minor.numTicks(); j++) {
+            t2 = t1 + (_major.step() * _minor.tick(j));
+            if (!inRange(t2)) {
+                continue;
+            }
+            if (t1 == t2) {
+                continue;        // Don't add duplicate minor ticks.
+            }
+            _minor.append(t2);
+        }
+        if (!inRange(t1)) {
+            continue;
+        }
+        _major.append(t1);
+    }
+}
+
+double
+Axis::map(double x)
+{
+    if ((_flags & LOGSCALE) && (x != 0.0)) {
+        x = log10(fabs(x));
+    }
+    /* Map graph coordinate to normalized coordinates [0..1] */
+    x = (x - _min) * _scale;
+    if (_flags & DESCENDING) {
+        x = 1.0 - x;
+    }
+    return x;
+}
+
+double
+Axis::invMap(double x)
+{
+    if (_flags & DESCENDING) {
+        x = 1.0 - x;
+    }
+    x = (x * _range) + _min;
+    if (_flags & LOGSCALE) {
+        x = EXP10(x);
+    }
+    return x;
+}
Index: /nanovis/tags/1.1.4/Axis.h
===================================================================
--- /nanovis/tags/1.1.4/Axis.h	(revision 4930)
+++ /nanovis/tags/1.1.4/Axis.h	(revision 4930)
@@ -0,0 +1,415 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors: George A. Howlett <gah@purdue.edu>
+ */
+#ifndef NV_AXIS_H
+#define NV_AXIS_H
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <cmath>
+#include <limits>
+
+#include "Chain.h"
+
+#ifndef NAN
+#define NAN (std::numeric_limits<double>::quiet_NaN())
+#endif
+
+namespace nv {
+
+class Axis;
+
+class TickIter
+{
+public:
+    void setStartingLink(ChainLink *linkPtr)
+    {
+        _linkPtr = linkPtr;
+    }
+
+    bool next()
+    {
+        if (_linkPtr == NULL) {
+            return false;
+        }
+        _linkPtr = _linkPtr->next();
+        return (_linkPtr != NULL);
+    }
+
+    float getValue()
+    {
+        union {
+            float x;
+            void *clientData;
+        } value;
+        value.clientData = _linkPtr->getValue();
+        return value.x;
+    }
+
+private:
+    ChainLink *_linkPtr;
+};
+
+/**
+ * Class containing information where the ticks (major or
+ * minor) will be displayed on the graph.
+ */
+class Ticks
+{
+public:
+    Ticks(int numTicks) :
+        reqNumTicks(numTicks),
+        _autoscale(true),
+        _numTicks(0),
+        _ticks(NULL)
+    {
+    }
+
+    ~Ticks()
+    {
+        if (_ticks != NULL) {
+            delete [] _ticks;
+        }
+        _chain.reset();
+    }
+
+    void setTicks(float *ticks, int nTicks)
+    {
+        _ticks = ticks, _numTicks = nTicks;
+    }
+
+    int numTicks()
+    {
+        return _numTicks;
+    }
+
+    double tick(int i)
+    {
+        if ((i < 0) || (i >= _numTicks)) {
+            return NAN;
+        }
+        return _ticks[i];
+    }
+
+    void reset()
+    {
+        _chain.reset();
+    }
+
+    float step()
+    {
+        return _step;
+    }
+
+    void append (float x)
+    {
+        _chain.append(getClientData(x));
+    }
+
+    void setValues(double initial, double step, unsigned int nSteps)
+    {
+        _initial = initial, _step = step, _nSteps = nSteps;
+    }
+
+    bool autoscale()
+    {
+        return _autoscale;
+    }
+
+    void sweepTicks()
+    {
+        if (_autoscale) {
+            if (_ticks != NULL) {
+                delete [] _ticks;
+            }
+            setTicks();
+        }
+    }
+
+    bool firstTick(TickIter &iter)
+    {
+        ChainLink *linkPtr;
+
+        linkPtr = _chain.firstLink();
+        iter.setStartingLink(linkPtr);
+        return (linkPtr != NULL);
+    }
+
+    int reqNumTicks;		/**< Default number of ticks to be displayed. */
+
+private:
+    void setTicks();	/**< Routine used internally to create the array
+				 * of ticks as defined by a given sweep. */
+    void *getClientData(float x)
+    {
+        union {
+            float x;
+            void *clientData;
+        } value;
+        value.x = x;
+        return value.clientData;
+    }
+
+    bool _autoscale;		/**< Indicates if the ticks are autoscaled. */
+    /* 
+     * Tick locations may be generated in two fashions
+     */
+    /* 1. an array of values provided by the user. */
+    int _numTicks;		/* # of ticks on axis */
+    float *_ticks;		/* Array of tick values (alloc-ed).  Right now
+				 * it's a float so we don't have to allocate
+				 * store for the list of ticks generated.  In
+				 * the future when we store both the tick
+				 * label and the value in the list, we may
+				 * extend this to a double.
+				 */
+    /*
+     * 2. a defined sweep of initial, step, and nsteps.  This in turn
+     *    will generate the an array of values.
+     */
+    double _initial;		/**< Initial value */
+    double _step;		/**< Size of interval */
+    unsigned int _nSteps;	/**< Number of intervals. */
+
+    /**
+     *This finally generates a list of ticks values that exclude duplicate
+     * minor ticks (that are always represented by major ticks).  In the
+     * future, the string representing the tick label will be stored in 
+     * the chain.
+     */
+    Chain _chain;
+};
+
+/**
+ * Class contains options controlling how the axis will be
+ * displayed.
+ */
+class Axis
+{
+public:
+    /// Flags associated with the axis.
+    enum AxisFlags {
+        AUTOSCALE  = (1<<0),
+        DESCENDING = (1<<1),
+        LOGSCALE   = (1<<2),
+        TIGHT_MIN  = (1<<3),
+        TIGHT_MAX  = (1<<4)
+    };
+
+    Axis(const char *name);
+
+    ~Axis()
+    {
+        if (_name != NULL) {
+            free((void *)_name);
+        }
+        if (_units != NULL) {
+            free((void *)_units);
+        }
+        if (_title != NULL) {
+            free((void *)_title);
+        }
+    }
+
+    bool firstMajor(TickIter& iter)
+    {
+        return _major.firstTick(iter);
+    }
+
+    bool firstMinor(TickIter& iter)
+    {
+        return _minor.firstTick(iter);
+    }
+
+    void resetRange();
+
+    void fixRange(double min, double max);
+
+    void setScale(double min, double max);
+
+    double scale() const
+    {
+        return _scale;
+    }
+
+    double range() const
+    {
+        return _range;
+    }
+
+    double dataMin() const
+    {
+        return _valueMin;
+    }
+
+    double dataMax() const
+    {
+        return _valueMax;
+    }
+
+    double min() const
+    {
+        return _min;
+    }
+
+    double max() const
+    {
+        return _max;
+    }
+
+    void setLimits(double min, double max)
+    {
+        _reqMin = min, _reqMax = max;
+    }
+
+    void unsetLimits()
+    {
+        setLimits(NAN, NAN);
+    }
+
+    double map(double x);
+
+    double invMap(double x);
+
+    const char *name()
+    {
+        return _name;
+    }
+
+    void name(const char *name)
+    {
+        if (_name != NULL) {
+            free((void *)_name);
+        }
+        _name = strdup(name);
+    }
+
+    const char *units()
+    {
+        return _units;
+    }
+
+    void units(const char *units)
+    {
+        if (_units != NULL) {
+            free((void *)_units);
+        }
+        _units = strdup(units);
+    }
+
+    const char *title()
+    {
+        return _title;
+    }
+
+    void title(const char *title)
+    {
+        if (_title != NULL) {
+            free((void *)_title);
+        }
+        _title = strdup(title);
+    }
+
+    void setDescendingOption(bool value)
+    {
+        if (value) {
+            _flags |= DESCENDING;
+        } else {
+            _flags &= ~DESCENDING;
+        }
+    }
+
+    void setTightMinOption(bool value)
+    {
+        if (value) {
+            _flags |= TIGHT_MIN;
+        } else {
+            _flags &= ~TIGHT_MIN;
+        }
+    }
+
+    void setTightMaxOption(bool value)
+    {
+        if (value) {
+            _flags |= TIGHT_MAX;
+        } else {
+            _flags &= ~TIGHT_MAX;
+        }
+    }
+
+    void setLogScaleOption(bool value)
+    {
+        if (value) {
+            _flags |= LOGSCALE;
+        } else {
+            _flags &= ~LOGSCALE;
+        }
+    }
+
+    void setMajorStepOption(double value)
+    {
+        _reqStep = value;	// Setting to 0.0 resets step to "auto"
+    }
+
+    void setNumMinorTicksOption(int n)
+    {
+        _minor.reqNumTicks = n;
+    }
+
+    void setNumMajorTicksOption(int n)
+    {
+        _major.reqNumTicks = n;
+    }
+
+private:
+    void logScale();
+
+    void linearScale();
+
+    bool inRange(double x);
+
+    void makeTicks();
+
+    const char *_name;		/**< Name of the axis. Malloc-ed */
+
+    unsigned int _flags;
+
+    const char *_title;		/**< Title of the axis. */
+
+    const char *_units;		/**< Units of the axis. */
+
+    double _valueMin, _valueMax; /**< The limits of the data. */
+
+    double _reqMin, _reqMax;	/**< Requested axis bounds. Consult the
+				 * axisPtr->flags field for
+				 * Axis::CONFIG_MIN and Axis::CONFIG_MAX
+				 * to see if the requested bound have
+				 * been set.  They override the
+				 * computed range of the axis
+				 * (determined by auto-scaling). */
+
+    double _min, _max;		/**< Smallest and largest major tick values for
+				 * the axis.  If loose, the tick values lie
+				 * outside the range of data values.  If
+				 * tight, they lie interior to the limits of
+				 * the data. */
+
+    double _range;		/**< Range of values on axis (_max - _min) */
+    double _scale;		/**< Scale factor for axis (1.0/_range) */
+
+    double _reqStep;		/**< If > 0.0, overrides the computed major tick
+				 * interval.  Otherwise a stepsize is
+				 * automatically calculated, based upon the
+				 * range of elements mapped to the axis. The
+				 * default value is 0.0. */
+
+    Ticks _major, _minor;
+};
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/AxisRange.h
===================================================================
--- /nanovis/tags/1.1.4/AxisRange.h	(revision 4930)
+++ /nanovis/tags/1.1.4/AxisRange.h	(revision 4930)
@@ -0,0 +1,87 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors: George A. Howlett <gah@purdue.edu>
+ */
+#ifndef NV_AXIS_RANGE_H
+#define NV_AXIS_RANGE_H
+
+#include <string.h>
+
+namespace nv {
+
+class AxisRange
+{
+public:
+    AxisRange() :
+        _min(0.0),
+        _max(1.0),
+        _units(NULL)
+    {
+    }
+
+    ~AxisRange()
+    {
+        if (_units != NULL) {
+            delete [] _units;
+        }
+    }
+
+    void setRange(double min, double max)
+    {
+        _min = min;
+        _max = max;
+    }
+
+    double min() const
+    {
+        return _min;
+    }
+
+    void min(double min)
+    {
+        _min = min;
+    }
+
+    double max() const
+    {
+        return _max;
+    }
+
+    void max(double max)
+    {
+        _max = max;
+    }
+
+    double length() const
+    {
+        return (_max - _min);
+    }
+
+    const char *units() const
+    {
+        return _units;
+    }
+
+    void units(const char *units)
+    {
+        if (_units != NULL) {
+            delete [] _units;
+        }
+        if (units == NULL) {
+            _units = NULL;
+        } else {
+            _units = new char[strlen(units) + 1];
+            strcpy(_units, units);
+        }
+    }
+
+private:
+    double _min, _max;
+    char *_units;
+};
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/BucketSort.cpp
===================================================================
--- /nanovis/tags/1.1.4/BucketSort.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/BucketSort.cpp	(revision 4930)
@@ -0,0 +1,48 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+
+#include <vrmath/Vector3f.h>
+#include <vrmath/Matrix4x4d.h>
+
+#include "BucketSort.h"
+
+using namespace PCA;
+using namespace vrmath;
+
+void 
+BucketSort::init()
+{
+    _count = 0;
+    memset(_buffer, 0, sizeof(ClusterList*) * _size);
+}
+
+void 
+BucketSort::sort(ClusterAccel* clusterAccel, const Matrix4x4d& cameraMat, int level)
+{
+    if (clusterAccel == 0) {
+        return;
+    }
+    Cluster* cluster = clusterAccel->startPointerCluster[level - 1];
+    Cluster* c = &(cluster[0]);
+    Cluster* end = &(cluster[clusterAccel->numOfClusters[level - 1] - 1]);
+
+    for (; c <= end; c = (Cluster*) ((char *)c + sizeof(Cluster))) {
+        Vector4f pt = cameraMat.transform(Vector4f(c->centroid, 1));
+        Vector3f pos(pt.x, pt.y, pt.z);
+        addBucket(c, pos.length()*_invMaxLength);
+    }
+}       
+
+void 
+BucketSort::addBucket(Cluster* cluster, float ratio)
+{
+    int index = (int) (ratio * _size);
+    ClusterList* c = &(_memChunck[_count++]);
+    c->data = cluster;
+    c->next =_buffer[index];
+    _buffer[index] = c;
+}
+
Index: /nanovis/tags/1.1.4/BucketSort.h
===================================================================
--- /nanovis/tags/1.1.4/BucketSort.h	(revision 4930)
+++ /nanovis/tags/1.1.4/BucketSort.h	(revision 4930)
@@ -0,0 +1,90 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#ifndef PCA_BUCKETSORT_H
+#define PCA_BUCKETSORT_H
+
+#include <vector>
+#include <list>
+
+#include <vrmath/Matrix4x4d.h>
+
+#include "PCASplit.h"
+
+namespace PCA {
+
+class ClusterList
+{
+public :
+    ClusterList(Cluster *d, ClusterList *n) :
+        data(d), next(n)
+    {}
+
+    ClusterList() :
+        data(0), next(0)
+    {}
+
+    ~ClusterList()
+    {
+        //if (next) delete next;
+    }
+
+    Cluster *data;
+    ClusterList *next;
+};
+
+class BucketSort
+{
+public:
+    BucketSort(int maxSize)
+    {
+        _size = maxSize;
+        _buffer = new ClusterList*[maxSize];
+        memset(_buffer, 0, _size * sizeof(ClusterList*));
+
+        _memChuckSize = 1000000;
+        _memChunck = new ClusterList[_memChuckSize];
+
+        _invMaxLength = 1.0f / 4.0f;
+    }
+
+    ~BucketSort()
+    {
+        delete [] _buffer;
+        delete [] _memChunck;
+    }
+
+    int getSize() const
+    { return _size; }
+
+    int getSortedItemCount() const
+    { return _count; }
+
+    void init();
+
+    void sort(ClusterAccel* cluster, const vrmath::Matrix4x4d& cameraMat, int level);
+
+    void addBucket(Cluster* cluster, float ratio);
+
+    ClusterList **getBucket()
+    { return _buffer; }
+
+private:
+    void _sort(Cluster *cluster, const vrmath::Matrix4x4d& cameraMat, int level);
+
+    ClusterList **_buffer;
+    int _size;
+    int _count;
+
+    int _memChuckSize;
+    bool _memChunckUsedFlag;
+    ClusterList *_memChunck;
+
+    float _invMaxLength;
+};
+
+}
+
+#endif 
Index: /nanovis/tags/1.1.4/Camera.cpp
===================================================================
--- /nanovis/tags/1.1.4/Camera.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/Camera.cpp	(revision 4930)
@@ -0,0 +1,297 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ *  Authors:
+ *    Wei Qiao <qiaow@purdue.edu>
+ */
+#include <stdio.h>
+#include <math.h>
+#include <float.h>
+
+#include <GL/glew.h>
+#include <GL/glu.h>
+
+#include <vrmath/Quaternion.h>
+#include <vrmath/Rotation.h>
+#include <vrmath/Matrix4x4d.h>
+#include <vrmath/Vector3f.h>
+#include <vrmath/Vector4f.h>
+#include <vrmath/BBox.h>
+
+#include "nanovis.h"
+#include "Camera.h"
+#include "Trace.h"
+
+using namespace nv;
+using namespace vrmath;
+
+static inline double deg2rad(double deg)
+{
+    return ((deg * M_PI) / 180.);
+}
+
+static inline double rad2deg(double rad)
+{
+    return ((rad * 180.) / M_PI);
+}
+
+Camera::Camera(int x, int y, int width, int height) :
+    _updir(Y_POS),
+    _position(0, 0, 2.5),
+    _fov(30.0),
+    _near(0.1),
+    _far(50.0)
+{
+    _viewport[0] = x;
+    _viewport[1] = y;
+    _viewport[2] = width;
+    _viewport[3] = height;
+}
+
+const Matrix4x4d&
+Camera::getUpDirMatrix() const
+{
+    return _updirMatrix;
+}
+
+void
+Camera::setUpDirMatrix(AxisDirection dir)
+{
+    _updir = dir;
+
+    switch (_updir) {
+    case X_POS: {
+        _updirMatrix.makeRotation(0, 0, 1, deg2rad(90));
+        Matrix4x4d tmp;
+        tmp.makeRotation(1, 0, 0, deg2rad(90));
+        _updirMatrix.multiply(tmp);
+    }
+        break;
+    case Y_POS:
+        _updirMatrix.makeIdentity();
+        break;
+    case Z_POS: {
+        _updirMatrix.makeRotation(1, 0, 0, deg2rad(-90));
+        Matrix4x4d tmp;
+        tmp.makeRotation(0, 0, 1, deg2rad(-90));
+        _updirMatrix.multiply(tmp);
+    }
+        break;
+    case X_NEG:
+        _updirMatrix.makeRotation(0, 0, 1, deg2rad(-90));
+        break;
+    case Y_NEG: {
+        _updirMatrix.makeRotation(0, 0, 1, deg2rad(180));
+        Matrix4x4d tmp;
+        tmp.makeRotation(0, 1, 0, deg2rad(-90));
+        _updirMatrix.multiply(tmp);
+    }
+        break;
+    case Z_NEG:
+        _updirMatrix.makeRotation(1, 0, 0, deg2rad(90));
+        break;
+    }
+}
+
+/**
+ * \brief Reset zoom to include extents
+ */
+void
+Camera::reset(const Vector3f& bboxMin,
+              const Vector3f& bboxMax,
+              bool resetOrientation)
+{
+    TRACE("Enter");
+
+    if (resetOrientation) {
+        _rotationMatrix.makeIdentity();
+    }
+
+    Vector3f center(bboxMin + bboxMax);
+    center.scale(0.5);
+
+    Matrix4x4d mat, upMat;
+    upMat = getUpDirMatrix();
+    mat.makeTranslation(-center);
+    mat.multiply(_rotationMatrix, mat);
+    mat.multiply(upMat);
+
+    Vector3f emin(FLT_MAX, FLT_MAX, FLT_MAX), emax(-FLT_MAX, -FLT_MAX, -FLT_MAX);
+
+    // Transform bounds by camera matrix
+    Vector4f bboxEye[8];
+    bboxEye[0] = Vector4f(bboxMin.x, bboxMin.y, bboxMin.z, 1);
+    bboxEye[1] = Vector4f(bboxMax.x, bboxMin.y, bboxMin.z, 1);
+    bboxEye[2] = Vector4f(bboxMin.x, bboxMax.y, bboxMin.z, 1);
+    bboxEye[3] = Vector4f(bboxMin.x, bboxMin.y, bboxMax.z, 1);
+    bboxEye[4] = Vector4f(bboxMax.x, bboxMax.y, bboxMin.z, 1);
+    bboxEye[5] = Vector4f(bboxMax.x, bboxMin.y, bboxMax.z, 1);
+    bboxEye[6] = Vector4f(bboxMin.x, bboxMax.y, bboxMax.z, 1);
+    bboxEye[7] = Vector4f(bboxMax.x, bboxMax.y, bboxMax.z, 1);
+
+    for (int i = 0; i < 8; i++) {
+        Vector4f eyeVert = mat.transform(bboxEye[i]);
+        if (eyeVert.x < emin.x) emin.x = eyeVert.x;
+        if (eyeVert.x > emax.x) emax.x = eyeVert.x;
+        if (eyeVert.y < emin.y) emin.y = eyeVert.y;
+        if (eyeVert.y > emax.y) emax.y = eyeVert.y;
+        if (eyeVert.z < emin.z) emin.z = eyeVert.z;
+        if (eyeVert.z > emax.z) emax.z = eyeVert.z;
+    }
+
+    TRACE("Eye bounds: (%g,%g,%g) - (%g,%g,%g)",
+          emin.x, emin.y, emin.z,
+          emax.x, emax.y, emax.z);
+
+    double bwidth = emax.x - emin.x;
+    double bheight = emax.y - emin.y;
+    double bdepth = emax.z - emin.z;
+
+    TRACE("bwidth: %g, bheight: %g, bdepth: %g", bwidth, bheight, bdepth);
+
+    double angle = deg2rad(_fov);
+    double distance;
+
+    // Deal with vertical aspect window
+    double winAspect = (double)_viewport[2]/(double)_viewport[3];
+    double sceneAspect = 1.0;;
+    if (bheight > 0.0)
+        sceneAspect = bwidth / bheight;
+
+    if (sceneAspect >= winAspect) {
+        angle = 2.0 * atan(tan(angle*0.5)*winAspect);
+        _near = bwidth / (2.0 * tan(angle*0.5));
+    } else {
+        _near = bheight / (2.0 * tan(angle*0.5));
+    }
+
+    distance = _near + bdepth * 0.5;
+    _far = _near + bdepth;
+
+    _position.set(center.x, center.y, center.z + distance);
+
+    TRACE("win aspect: %g scene aspect: %g", winAspect, sceneAspect);
+    TRACE("c: %g,%g,%g, d: %g", center.x, center.y, center.z, distance);
+    TRACE("pos: %g, %g, %g", _position.x, _position.y, _position.z);
+    TRACE("near: %g, far: %g", _near, _far);
+
+    initialize();
+    resetClippingRange(bboxMin, bboxMax);
+}
+
+/**
+ * \brief Reset near and far planes based on given world space
+ * bounding box
+ */
+void
+Camera::resetClippingRange(const Vector3f& bboxMin, const Vector3f& bboxMax)
+{
+    Vector3f emin(bboxMin.x, bboxMin.y, bboxMin.z), emax(bboxMax.x, bboxMax.y, bboxMax.z);
+
+    Vector3f center(emin + emax);
+    center.scale(0.5);
+
+    // Compute the radius of the enclosing sphere,
+    // which is half the bounding box diagonal
+    Vector3f diagonal(emax - emin);
+    double radius = diagonal.length() * 0.5;
+
+    // If we have just a single point, pick a radius of 1.0
+    radius = (radius == 0) ? 1.0 : radius;
+
+    TRACE("c: %g,%g,%g, r: %g cam z: %g", center.x, center.y, center.z, radius, _position.z);
+
+    _near = _position.z - radius;
+    _far = _position.z + radius;
+
+    if (_near < 0.0) {
+        _near = 0.001;
+    }
+    if (_far < 0.0) {
+        _far = 1.0;
+    }
+
+    TRACE("Resetting camera clipping range to: near: %g, far: %g", _near, _far);
+
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    gluPerspective(_fov, 
+                   (GLdouble)_viewport[2]/(GLdouble)_viewport[3], 
+                   _near, _far);
+    glMatrixMode(GL_MODELVIEW);
+
+    print();
+}
+
+void 
+Camera::initialize()
+{
+    TRACE("Enter");
+    print();
+
+    glViewport(_viewport[0], _viewport[1], _viewport[2], _viewport[3]);
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    gluPerspective(_fov, 
+                   (GLdouble)_viewport[2]/(GLdouble)_viewport[3], 
+                   _near, _far);
+
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+
+    glTranslatef(-_position.x, -_position.y, -_position.z);
+    glMultMatrixd((const GLdouble *)_rotationMatrix.get());
+}
+
+void Camera::getProjectionMatrix(Matrix4x4d& mat)
+{
+    glMatrixMode(GL_PROJECTION);
+    glPushMatrix();
+    glLoadIdentity();
+    gluPerspective(_fov, 
+                   (GLdouble)_viewport[2]/(GLdouble)_viewport[3], 
+                   _near, _far);
+    glGetDoublev(GL_PROJECTION_MATRIX, (GLdouble *)mat.get());
+    glPopMatrix();
+    glMatrixMode(GL_MODELVIEW);
+}
+
+void Camera::orient(double *quat)
+{
+    Quaternion q(quat[0], quat[1], quat[2], quat[3]);
+    Rotation rot;
+    rot.set(q);
+    _rotationMatrix.makeRotation(rot);
+    _rotationMatrix.transpose();
+
+    TRACE("Set rotation to quat: %g %g %g %g",
+          quat[0], quat[1], quat[2], quat[3]);
+}
+
+void Camera::orient(float angleX, float angleY, float angleZ)
+{
+    angleX = -angleX;
+    angleY = angleY - 180.;
+
+    _rotationMatrix.makeRotation(1, 0, 0, deg2rad(angleX));
+    Matrix4x4d mat;
+    mat.makeRotation(0, 1, 0, deg2rad(angleY));
+    _rotationMatrix.multiply(mat);
+    mat.makeRotation(0, 0, 1, deg2rad(angleZ));
+    _rotationMatrix.multiply(mat);
+
+    TRACE("Set rotation to angles: %g %g %g",
+          angleX, angleY, angleZ);
+}
+
+void Camera::print() const
+{
+    TRACE("x: %d y: %d w: %d h: %d",
+          _viewport[0], _viewport[1], _viewport[2], _viewport[3]);
+    TRACE("fov: %g near: %g far: %g", _fov, _near, _far);
+    TRACE("pos: %g %g %g",
+          _position.x, _position.y, _position.z);
+    TRACE("Rotation matrix: ");
+    _rotationMatrix.print();
+}
Index: /nanovis/tags/1.1.4/Camera.h
===================================================================
--- /nanovis/tags/1.1.4/Camera.h	(revision 4930)
+++ /nanovis/tags/1.1.4/Camera.h	(revision 4930)
@@ -0,0 +1,156 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ *  Authors:
+ *    Wei Qiao <qiaow@purdue.edu>
+ */
+#ifndef NV_CAMERA_H
+#define NV_CAMERA_H
+
+#include <vrmath/Matrix4x4d.h>
+#include <vrmath/Vector3f.h>
+
+#include "config.h"
+
+namespace nv {
+
+class Camera
+{
+public:
+    enum AxisDirection {
+        X_POS = 1,
+        Y_POS = 2,
+        Z_POS = 3,
+        X_NEG = -1,
+        Y_NEG = -2,
+        Z_NEG = -3
+    };
+
+    Camera(int x, int y, int width, int height);
+
+    ~Camera()
+    {}
+
+    void setUpdir(AxisDirection dir)
+    {
+        setUpDirMatrix(dir);
+    }
+
+    AxisDirection getUpdir()
+    {
+        return _updir;
+    }
+
+    void setPosition(const vrmath::Vector3f& pos)
+    {
+        _position = pos;
+    }
+
+    const vrmath::Vector3f& getPosition() const
+    {
+        return _position;
+    }
+
+    void x(float loc_x)
+    {
+        _position.x = loc_x;
+    }
+
+    float x() const
+    {
+        return _position.x;
+    }
+
+    void y(float loc_y)
+    {
+        _position.y = loc_y;
+    }
+
+    float y() const
+    {
+        return _position.y;
+    }
+
+    void z(float loc_z)
+    {
+        _position.z = loc_z;
+    }
+
+    float z() const
+    {
+        return _position.z;
+    }
+
+    void orient(double *quat);
+
+    void orient(float angleX, float angleY, float angleZ);
+
+    void setFov(float fov)
+    {
+        _fov = fov;
+    }
+
+    float getFov() const
+    {
+        return _fov;
+    }
+
+    void reset(const vrmath::Vector3f& bboxMin,
+               const vrmath::Vector3f& bboxMax,
+               bool resetOrientation = false);
+
+    void resetClippingRange(const vrmath::Vector3f& bboxMin,
+                            const vrmath::Vector3f& bboxMax);
+
+    void setViewport(int x, int y, int width, int height)
+    {
+        _viewport[0] = x;
+        _viewport[1] = y;
+        _viewport[2] = width;
+        _viewport[3] = height;
+    }
+
+    /**
+     * \brief Make the camera setting active, this has to be
+     * called before drawing things
+     */
+    void initialize();
+
+    void print() const;
+
+    void getProjectionMatrix(vrmath::Matrix4x4d& mat);
+
+    const vrmath::Matrix4x4d& getUpDirMatrix() const;
+
+private:
+    void setClippingRange(float near, float far)
+    {
+        _near = near;
+        _far = far;
+    }
+
+    void setUpDirMatrix(AxisDirection dir);
+
+    AxisDirection _updir;
+
+    /// Position of the camera in the scene
+    vrmath::Vector3f _position;
+
+    /// Model transform for z-up scene
+    vrmath::Matrix4x4d _updirMatrix;
+    /// Camera orientation
+    vrmath::Matrix4x4d _rotationMatrix;
+
+    /// Field of view (vertical angle in degrees)
+    float _fov;
+    /// Near, far z clipping
+    float _near, _far;
+
+    // x, y, width, height
+    int _viewport[4];
+};
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/Chain.cpp
===================================================================
--- /nanovis/tags/1.1.4/Chain.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/Chain.cpp	(revision 4930)
@@ -0,0 +1,254 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* The module implements a generic linked list package.
+ *
+ * Copyright 1991-2004 George A Howlett.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "Chain.h"
+
+using namespace nv;
+
+typedef int (QSortCompareProc) (const void *, const void *);
+
+/**
+ * Removes all the links from the chain, freeing the memory for each
+ * link.  Memory pointed to by the link (clientData) is not freed.  It's
+ * the caller's responsibility to deallocate it.
+ */
+void
+Chain::reset()
+{
+    ChainLink *oldPtr;
+    ChainLink *linkPtr = _head;
+
+    while (linkPtr != NULL) {
+	oldPtr = linkPtr;
+	linkPtr = linkPtr->next();
+	delete oldPtr;
+    }
+    init();
+}
+
+/**
+ * Inserts a link after another link.  If afterPtr is NULL, then the new
+ * link is prepended to the beginning of the chain.
+ */
+void
+Chain::linkAfter(ChainLink *linkPtr, ChainLink *afterPtr)
+{
+    if (_head == NULL) {
+	_tail = _head = linkPtr;
+    } else {
+	if (afterPtr == NULL) {
+	    /* Prepend to the front of the chain */
+	    linkPtr->_next = _head;
+	    linkPtr->_prev = NULL;
+	    _head->_prev = linkPtr;
+	    _head = linkPtr;
+	} else {
+	    linkPtr->_next = afterPtr->next();
+	    linkPtr->_prev = afterPtr;
+	    if (afterPtr == _tail) {
+		_tail = linkPtr;
+	    } else {
+		afterPtr->next()->_prev = linkPtr;
+	    }
+	    afterPtr->_next = linkPtr;
+	}
+    }
+    _nLinks++;
+}
+
+/**
+ * Inserts a new link preceding a given link in a chain.  If beforePtr is
+ * NULL, then the new link is placed at the beginning of the list.
+ *
+ * \param linkPtr New entry to be inserted
+ * \param beforePtr Entry to link before
+ */
+void
+Chain::linkBefore(ChainLink *linkPtr,
+                  ChainLink *beforePtr)
+{
+    if (_head == NULL) {
+	_tail = _head = linkPtr;
+    } else {
+	if (beforePtr == NULL) {
+	    // Append to the end of the chain.
+	    linkPtr->_next = NULL;
+	    linkPtr->_prev = _tail;
+	    _tail->_next = linkPtr;
+	    _tail = linkPtr;
+	} else {
+	    linkPtr->_prev = beforePtr->prev();
+	    linkPtr->_next = beforePtr;
+	    if (beforePtr == _head) {
+		_head = linkPtr;
+	    } else {
+		beforePtr->prev()->_next = linkPtr;
+	    }
+	    beforePtr->_prev = linkPtr;
+	}
+    }
+    _nLinks++;
+}
+
+/**
+ * Unlinks a link from the chain. The link is not deallocated, 
+ * but only removed from the chain.
+ */
+void
+Chain::unlink(ChainLink *linkPtr)
+{
+    bool unlinked;		/* Indicates if the link is actually removed
+				 * from the chain. */
+
+    unlinked = false;
+    if (_head == linkPtr) {
+	_head = linkPtr->next();
+	unlinked = true;
+    }
+    if (_tail == linkPtr) {
+	_tail = linkPtr->prev();
+	unlinked = true;
+    }
+    if (linkPtr->next() != NULL) {
+	linkPtr->next()->_prev = linkPtr->prev();
+	unlinked = true;
+    }
+    if (linkPtr->prev() != NULL) {
+	linkPtr->prev()->_next = linkPtr->next();
+	unlinked = true;
+    }
+    if (unlinked) {
+	_nLinks--;
+    }
+    linkPtr->_prev = linkPtr->_next = NULL;
+}
+
+/**
+ * Unlinks and frees the given link from the chain.  It's assumed that
+ * the link belong to the chain. No error checking is performed to verify
+ * this.
+ */
+void
+Chain::deleteLink(ChainLink *linkPtr)
+{
+    unlink(linkPtr);
+    delete linkPtr;
+}
+
+/**
+ * Creates and new link with the given data and appends it to the end of
+ * the chain.
+ *
+ * \return a pointer to the link created.
+ */
+ChainLink *
+Chain::append(void *clientData)
+{
+    ChainLink *linkPtr;
+
+    linkPtr = new ChainLink(clientData);
+    linkBefore(linkPtr, (ChainLink *)NULL);
+    return linkPtr;
+}
+
+/**
+ * Creates and new link with the given data and prepends it to beginning
+ * of the chain.
+ *
+ * \return a pointer to the link created.
+ */
+ChainLink  *
+Chain::prepend(void *clientData)
+{
+    ChainLink *linkPtr;
+
+    linkPtr = new ChainLink(clientData);
+    linkAfter(linkPtr, (ChainLink *)NULL);
+    return linkPtr;
+}
+
+/**
+ * Find the link at the given position in the chain.
+ *
+ * \param position Index of link to select from front or back of the chain.
+ *
+ * \return  the pointer to the link, if that numbered link
+ * exists. Otherwise NULL.
+ */
+ChainLink *
+Chain::getNthLink(long position)
+{
+    ChainLink *linkPtr;
+
+    for (linkPtr = _head; linkPtr != NULL; linkPtr = linkPtr->next()) {
+	if (position == 0) {
+	    return linkPtr;
+	}
+	position--;
+    }
+    return NULL;
+}
+
+/**
+ * Sorts the chain according to the given comparison routine.  
+ *
+ * Side Effects:
+ *   The chain is reordered.
+ */
+void
+Chain::sort(ChainCompareProc *proc)
+{
+    ChainLink *linkPtr;
+    long i;
+
+    if (_nLinks < 2) {
+	return;
+    }
+    ChainLink **linkArr = new ChainLink *[_nLinks + 1];
+    if (linkArr == NULL) {
+	return;			/* Out of memory. */
+    }
+    i = 0;
+    for (linkPtr = _head; linkPtr != NULL; linkPtr = linkPtr->next()) { 
+	linkArr[i++] = linkPtr;
+    }
+    qsort((char *)linkArr, _nLinks, sizeof(ChainLink *), 
+	  (QSortCompareProc *)proc);
+
+    /* Rethread the chain. */
+    linkPtr = linkArr[0];
+    _head = linkPtr;
+    linkPtr->_prev = NULL;
+    for (i = 1; i < _nLinks; i++) {
+	linkPtr->_next = linkArr[i];
+	linkPtr->next()->_prev = linkPtr;
+	linkPtr = linkPtr->next();
+    }
+    _tail = linkPtr;
+    linkPtr->_next = NULL;
+    delete [] linkArr;
+}
Index: /nanovis/tags/1.1.4/Chain.h
===================================================================
--- /nanovis/tags/1.1.4/Chain.h	(revision 4930)
+++ /nanovis/tags/1.1.4/Chain.h	(revision 4930)
@@ -0,0 +1,149 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993-2004 George A Howlett.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef NV_CHAIN_H
+#define NV_CHAIN_H
+
+namespace nv {
+
+/**
+ * \brief A ChainLink is the container structure for the Chain.
+ */
+class ChainLink
+{
+public:
+    ChainLink()
+    {
+        _clientData = NULL;
+        _next = _prev = NULL;
+    }
+
+    ChainLink(void *clientData)
+    {
+        _clientData = clientData;
+         _next = _prev = NULL;
+    }
+
+    void *getValue()
+    {
+        return _clientData;
+    }
+
+    void setValue(void *clientData)
+    {
+        _clientData = clientData;
+    }
+
+    ChainLink *next()
+    {
+        return _next;
+    }
+
+    ChainLink *prev()
+    {
+        return _prev;
+    }
+
+    friend class Chain;
+
+private:
+    ChainLink *_prev;  ///< Link to the previous link
+    ChainLink *_next;  ///< Link to the next link
+    void *_clientData; ///< Pointer to the data object
+};
+
+typedef int (ChainCompareProc) (ChainLink *l1Ptr, ChainLink *l2Ptr);
+
+/**
+ * \brief A Chain is a doubly linked list structure.
+ */
+class Chain
+{
+public:
+    Chain()
+    {
+        init();
+    }
+    ~Chain()
+    {
+        reset();
+    }
+
+    void init()
+    {
+        _nLinks = 0;
+        _head = _tail = NULL;
+    }
+
+    ChainLink *append(void *clientData);
+
+    ChainLink *prepend(void *clientData);
+
+    ChainLink *getNthLink(long position);
+
+    void linkBefore(ChainLink *linkPtr, ChainLink *beforePtr);
+
+    void linkAfter(ChainLink *linkPtr, ChainLink *afterPtr);
+
+    void deleteLink(ChainLink *linkPtr);
+
+    void unlink(ChainLink *linkPtr);
+
+    void reset();
+
+    void sort(ChainCompareProc *proc);
+
+    long getLength()
+    {
+        return _nLinks;
+    }
+
+    ChainLink *firstLink()
+    {
+        return _head;
+    }
+
+    ChainLink *lastLink()
+    {
+        return _tail;
+    }
+
+    void appendLink(ChainLink *linkPtr)
+    {
+        linkBefore(linkPtr, (ChainLink *)NULL);
+    }
+
+    void prependLink(ChainLink *linkPtr)
+    {
+        linkAfter(linkPtr, (ChainLink *)NULL);
+    }
+
+private:
+    ChainLink *_head; ///< Pointer to first element in chain
+    ChainLink *_tail; ///< Pointer to last element in chain
+    long _nLinks;     ///< Number of elements in chain
+};
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/CircularQueue.h
===================================================================
--- /nanovis/tags/1.1.4/CircularQueue.h	(revision 4930)
+++ /nanovis/tags/1.1.4/CircularQueue.h	(revision 4930)
@@ -0,0 +1,183 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* CircularFifo.h 
+* Not any company's property but Public-Domain
+* Do with source-code as you will. No requirement to keep this
+* header if need to use it/change it/ or do whatever with it
+*
+* Note that there is No guarantee that this code will work 
+* and I take no responsibility for this code and any problems you
+* might get if using it. The code is highly platform dependent!
+*
+* Code & platform dependent issues with it was originally 
+* published at http://www.kjellkod.cc/threadsafecircularqueue
+* 2009-11-02
+* @author Kjell Hedström, hedstrom@kjellkod.cc */
+
+#ifndef CIRCULARFIFO_H
+#define CIRCULARFIFO_H
+
+/** Circular Fifo (a.k.a. Circular Buffer) 
+* Thread safe for one reader, and one writer */
+template<typename Element, unsigned int Size>
+class CircularFifo {
+public:
+   enum {Capacity = Size+1};
+
+   CircularFifo() : tail(0), head(0){}
+   virtual ~CircularFifo() {}
+
+   bool push(Element& item_);
+   bool pop(Element& item_);
+   bool isEmpty() const;
+   bool isFull() const;
+   
+   // INSOO
+   bool push();
+   int tailIndex();
+   bool pop();
+   bool top(Element&);
+   
+public:
+   volatile unsigned int tail; // input index
+   Element array[Capacity];
+   volatile unsigned int head; // output index
+
+   unsigned int increment(unsigned int idx_) const;
+};
+
+
+
+
+/** Producer only: Adds item to the circular queue. 
+* If queue is full at 'push' operation no update/overwrite
+* will happen, it is up to the caller to handle this case
+*
+* \param item_ copy by reference the input item
+* \return whether operation was successful or not */
+template<typename Element, unsigned int Size>
+bool CircularFifo<Element, Size>::push(Element& item_)
+{
+   int nextTail = increment(tail);
+   if(((unsigned int) nextTail) != head)
+   {
+      array[tail] = item_;
+      tail = nextTail;
+      return true;
+   }
+
+   // queue was full
+   return false;
+}
+
+template<typename Element, unsigned int Size>
+bool CircularFifo<Element, Size>::top(Element& data)
+{
+   if(head == tail)
+      return false;  // empty queue
+
+   data = array[head];
+   head = increment(head);
+   return true;
+}
+
+
+/** Consumer only: Removes and returns item from the queue
+* If queue is empty at 'pop' operation no retrieve will happen
+* It is up to the caller to handle this case
+*
+* \param item_ return by reference the wanted item
+* \return whether operation was successful or not */
+template<typename Element, unsigned int Size>
+bool CircularFifo<Element, Size>::pop(Element& item_)
+{
+   if(head == tail)
+      return false;  // empty queue
+
+   item_ = array[head];
+   head = increment(head);
+   return true;
+}
+
+/** Consumer only: Removes and returns item from the queue
+* If queue is empty at 'pop' operation no retrieve will happen
+* It is up to the caller to handle this case
+*
+* \return whether operation was successful or not */
+template<typename Element, unsigned int Size>
+bool CircularFifo<Element, Size>::pop()
+{
+   if(head == tail)
+      return false;  // empty queue
+   head = increment(head);
+   return true;
+}
+
+/** Useful for testinng and Consumer check of status
+  * Remember that the 'empty' status can change quickly
+  * as the Procuder adds more items.
+  *
+  * \return true if circular buffer is empty */
+template<typename Element, unsigned int Size>
+bool CircularFifo<Element, Size>::isEmpty() const
+{
+   return (head == tail);
+}
+
+/** Useful for testing and Producer check of status
+  * Remember that the 'full' status can change quickly
+  * as the Consumer catches up.
+  *
+  * \return true if circular buffer is full.  */
+template<typename Element, unsigned int Size>
+bool CircularFifo<Element, Size>::isFull() const
+{
+   int tailCheck = (tail+1) % Capacity;
+   return (((unsigned int) tailCheck) == head);
+}
+
+/** Increment helper function for index of the circular queue
+* index is inremented or wrapped
+*
+*  \param idx_ the index to the incremented/wrapped
+*  \return new value for the index */
+template<typename Element, unsigned int Size>
+unsigned int CircularFifo<Element, Size>::increment(unsigned int idx_) const
+{
+   // increment or wrap
+   // =================
+   //    index++;
+   //    if(index == array.lenght) -> index = 0;
+   //
+   //or as written below:   
+   //    index = (index+1) % array.length
+   idx_ = (idx_+1) % Capacity;
+   return idx_;
+}
+
+template<typename Element, unsigned int Size>
+int CircularFifo<Element, Size>::tailIndex()
+{
+   int nextTail = increment(tail);
+   if(((unsigned int)nextTail) != head)
+   {
+      return tail;
+   }
+
+   return -1;
+}
+
+
+template<typename Element, unsigned int Size>
+bool CircularFifo<Element, Size>::push()
+{
+   int nextTail = increment(tail);
+   if(((unsigned int)nextTail) != head)
+   {
+      tail = nextTail;
+      return true;
+   }
+
+   return false;
+}
+
+#endif
Index: /nanovis/tags/1.1.4/CmdProc.cpp
===================================================================
--- /nanovis/tags/1.1.4/CmdProc.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/CmdProc.cpp	(revision 4930)
@@ -0,0 +1,212 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#include <string.h>
+
+#include <tcl.h>
+
+#include "CmdProc.h"
+
+using namespace nv;
+
+/**
+ * Performs a linear search on the array of command operation
+ * specifications to find a partial, anchored match for the given
+ * operation string.
+ *
+ * \return If the string matches unambiguously the index of the specification in
+ * the array is returned.  If the string does not match, even as an
+ * abbreviation, any operation, -1 is returned.  If the string matches,
+ * but ambiguously -2 is returned.
+ */
+static int
+LinearOpSearch(CmdSpec *specs, int low, int high, const char *string,
+               int length)
+{
+    CmdSpec *specPtr;
+    char c;
+    int nMatches, last;
+    int i;
+
+    c = string[0];
+    nMatches = 0;
+    last = -1;
+    for (specPtr = specs+low, i = low; i <= high; i++, specPtr++) {
+        if ((c == specPtr->name[0]) && 
+            (strncmp(string, specPtr->name, length) == 0)) {
+            last = i;
+            nMatches++;
+            if (length == specPtr->minChars) {
+                break;
+            }
+        }
+    }
+    if (nMatches > 1) {
+        return -2;      /* Ambiguous operation name */
+    } 
+    if (nMatches == 0) {
+        return -1;      /* Can't find operation */
+    } 
+    return last;        /* Op found. */
+}
+
+/**
+ * Performs a binary search on the array of command operation
+ * specifications to find a partial, anchored match for the given
+ * operation string.  If we get to a point where the sample string
+ * partially matches an entry, we then revert to a linear search
+ * over the given range to check if it's an exact match or
+ * ambiguous (example: "color" with commands color and colormode).
+ *
+ * \return If the string matches unambiguously the index of the specification in
+ * the array is returned.  If the string does not match, even as an
+ * abbreviation, any operation, -1 is returned.  If the string matches,
+ * but ambiguously -2 is returned.
+ */
+static int
+BinaryOpSearch(CmdSpec *specs, int low, int high, const char *string,
+               int length)
+{
+    char c;
+
+    c = string[0];
+    while (low <= high) {
+        CmdSpec *specPtr;
+        int compare;
+        int median;
+    
+        median = (low + high) >> 1;
+        specPtr = specs + median;
+
+        /* Test the first character */
+        compare = c - specPtr->name[0];
+        if (compare == 0) {
+            /* Now test the entire string */
+            compare = strncmp(string, specPtr->name, length);
+        }
+        if (compare < 0) {
+            high = median - 1;
+        } else if (compare > 0) {
+            low = median + 1;
+        } else {
+            if (length < specPtr->minChars) {
+                /* Verify that the string is either ambiguous or an exact
+                 * match of another command by doing a linear search over the
+                 * given interval. */
+                return LinearOpSearch(specs, low, high, string, length);
+            }
+            return median;  /* Op found. */
+        }
+    }
+    return -1;          /* Can't find operation */
+}
+
+/**
+ * \brief Find the command operation given a string name.
+ * 
+ * This is useful where a group of command operations have the same argument 
+ * signature.
+ *
+ * \return If found, a pointer to the procedure (function pointer) is returned.
+ * Otherwise NULL is returned and an error message containing a list of
+ * the possible commands is returned in interp->result.
+ */
+Tcl_ObjCmdProc *
+nv::GetOpFromObj(Tcl_Interp *interp,	/* Interpreter to report errors to */
+                 int nSpecs,		/* Number of specifications in array */
+                 CmdSpec *specs,	/* Op specification array */
+                 int operPos,		/* Position of operation in argument
+                                         * list. */
+                 int objc,		/* Number of arguments in the argument
+                                         * vector.  This includes any prefixed
+                                         * arguments */ 
+                 Tcl_Obj *const *objv,	/* Argument vector */
+                 int flags)
+{
+    CmdSpec *specPtr;
+    char *string;
+    int length;
+    int n;
+
+    if (objc <= operPos) {  /* No operation argument */
+        if (interp != NULL) {
+            Tcl_AppendResult(interp, "wrong # args: ", (char *)NULL);
+        usage:
+            Tcl_AppendResult(interp, "should be one of...", (char *)NULL);
+            for (n = 0; n < nSpecs; n++) {
+                int i;
+
+                Tcl_AppendResult(interp, "\n  ", (char *)NULL);
+                for (i = 0; i < operPos; i++) {
+                    Tcl_AppendResult(interp, Tcl_GetString(objv[i]), " ", 
+                                     (char *)NULL);
+                }
+                specPtr = specs + n;
+                Tcl_AppendResult(interp, specPtr->name, " ", specPtr->usage,
+                                 (char *)NULL);
+            }
+        }
+        return NULL;
+    }
+    string = Tcl_GetStringFromObj(objv[operPos], &length);
+    if (flags & CMDSPEC_LINEAR_SEARCH) {
+        n = LinearOpSearch(specs, 0, nSpecs - 1, string, length);
+    } else {
+        n = BinaryOpSearch(specs, 0, nSpecs - 1, string, length);
+    }
+    if (n == -2) {
+        if (interp != NULL) {
+            char c;
+
+            Tcl_AppendResult(interp, "ambiguous", (char *)NULL);
+            if (operPos > 2) {
+                Tcl_AppendResult(interp, " ", Tcl_GetString(objv[operPos - 1]), 
+                                 (char *)NULL);
+            }
+            Tcl_AppendResult(interp, " operation \"", string, "\" matches: ",
+                             (char *)NULL);
+
+            c = string[0];
+            length = strlen(string);
+            for (n = 0; n < nSpecs; n++) {
+                specPtr = specs + n;
+                if ((c == specPtr->name[0]) &&
+                    (strncmp(string, specPtr->name, length) == 0)) {
+                    Tcl_AppendResult(interp, " ", specPtr->name, (char *)NULL);
+                }
+            }
+        }
+        return NULL;
+
+    } else if (n == -1) {   /* Can't find operation, display help */
+        if (interp != NULL) {
+            Tcl_AppendResult(interp, "bad", (char *)NULL);
+            if (operPos > 2) {
+                Tcl_AppendResult(interp, " ", Tcl_GetString(objv[operPos - 1]), 
+                                 (char *)NULL);
+            }
+            Tcl_AppendResult(interp, " operation \"", string, "\": ", (char *)NULL);
+            goto usage;
+        }
+        return NULL;
+    }
+    specPtr = specs + n;
+    if ((objc < specPtr->minArgs) || 
+        ((specPtr->maxArgs > 0) && (objc > specPtr->maxArgs))) {
+        if (interp != NULL) {
+            int i;
+
+            Tcl_AppendResult(interp, "wrong # args: should be \"", (char *)NULL);
+            for (i = 0; i < operPos; i++) {
+                Tcl_AppendResult(interp, Tcl_GetString(objv[i]), " ", 
+                                 (char *)NULL);
+            }
+            Tcl_AppendResult(interp, specPtr->name, " ", specPtr->usage, "\"",
+                             (char *)NULL);
+        }
+        return NULL;
+    }
+    return specPtr->proc;
+}
Index: /nanovis/tags/1.1.4/CmdProc.h
===================================================================
--- /nanovis/tags/1.1.4/CmdProc.h	(revision 4930)
+++ /nanovis/tags/1.1.4/CmdProc.h	(revision 4930)
@@ -0,0 +1,44 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#ifndef NV_CMDPROC_H
+#define NV_CMDPROC_H
+
+namespace nv {
+
+/**
+ * Structure to specify a set of operations for a Tcl command.
+ * This is passed to the Blt_GetOp procedure to look
+ * for a function pointer associated with the operation name.
+ */
+typedef struct {
+    const char *name;		/**< Name of operation */
+    int minChars;		/**< Minimum # characters to disambiguate */
+    Tcl_ObjCmdProc *proc;
+    int minArgs;		/**< Minimum # args required */
+    int maxArgs;		/**< Maximum # args required */
+    const char *usage;		/**< Usage message */
+} CmdSpec;
+
+typedef enum {
+    CMDSPEC_ARG0,		/**< Op is the first argument. */
+    CMDSPEC_ARG1,		/**< Op is the second argument. */
+    CMDSPEC_ARG2,		/**< Op is the third argument. */
+    CMDSPEC_ARG3,		/**< Op is the fourth argument. */
+    CMDSPEC_ARG4		/**< Op is the fifth argument. */
+} CmdSpecIndex;
+
+#define CMDSPEC_LINEAR_SEARCH	1
+#define CMDSPEC_BINARY_SEARCH	0
+
+extern Tcl_ObjCmdProc *
+GetOpFromObj(Tcl_Interp *interp, int nSpecs, 
+             CmdSpec *specs, int operPos, int objc, Tcl_Obj *const *objv, int flags);
+
+#define NumCmdSpecs(s) (sizeof(s) / sizeof(nv::CmdSpec))
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/ColorTableShader.cpp
===================================================================
--- /nanovis/tags/1.1.4/ColorTableShader.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/ColorTableShader.cpp	(revision 4930)
@@ -0,0 +1,40 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#include "ColorTableShader.h"
+
+using namespace nv;
+
+ColorTableShader::ColorTableShader()
+{
+    init();
+}
+
+ColorTableShader::~ColorTableShader()
+{
+}
+
+void ColorTableShader::init()
+{
+    loadFragmentProgram("one_plane.cg"); 
+}
+
+void ColorTableShader::bind(Texture2D *plane, TransferFunction *tf)
+{
+    setFPTextureParameter("data", plane->id());
+    setFPTextureParameter("tf", tf->id());
+
+    setFPParameter4f("render_param", 0., 0., 0., 0.);
+
+    Shader::bind();
+}
+
+void ColorTableShader::unbind()
+{
+    disableFPTextureParameter("data");
+    disableFPTextureParameter("tf");
+
+    Shader::unbind();
+}
Index: /nanovis/tags/1.1.4/ColorTableShader.h
===================================================================
--- /nanovis/tags/1.1.4/ColorTableShader.h	(revision 4930)
+++ /nanovis/tags/1.1.4/ColorTableShader.h	(revision 4930)
@@ -0,0 +1,32 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#ifndef NV_COLORTABLE_SHADER_H
+#define NV_COLORTABLE_SHADER_H
+
+#include "Shader.h"
+#include "Texture2D.h"
+#include "TransferFunction.h"
+
+namespace nv {
+
+class ColorTableShader : public Shader
+{
+public:
+    ColorTableShader();
+
+    virtual ~ColorTableShader();
+
+    virtual void bind(Texture2D *plane, TransferFunction *tf);
+
+    virtual void unbind();
+
+private :
+    void init();
+};
+
+}
+
+#endif 
Index: /nanovis/tags/1.1.4/Command.cpp
===================================================================
--- /nanovis/tags/1.1.4/Command.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/Command.cpp	(revision 4930)
@@ -0,0 +1,2345 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * ----------------------------------------------------------------------
+ * Command.cpp
+ *
+ *      This modules creates the Tcl interface to the nanovis server.  The
+ *      communication protocol of the server is the Tcl language.  Commands
+ *      given to the server by clients are executed in a safe interpreter and
+ *      the resulting image rendered offscreen is returned as BMP-formatted
+ *      image data.
+ *
+ * ======================================================================
+ *  AUTHOR:  Wei Qiao <qiaow@purdue.edu>
+ *           Michael McLennan <mmclennan@purdue.edu>
+ *           Purdue Rendering and Perceptualization Lab (PURPL)
+ *
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ *  See the file "license.terms" for information on usage and
+ *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ * ======================================================================
+ */
+
+/*
+ * TODO:  In no particular order...
+ *        o Use Tcl command option parser to reduce size of procedures, remove
+ *          lots of extra error checking code. (almost there)
+ *        o Add bookkeeping for volumes, heightmaps, flows, etc. to track
+ *          1) simulation # 2) include/exclude.  The include/exclude
+ *          is to indicate whether the item should contribute to the overall
+ *          limits of the axes.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>                     /* Needed for getpid, gethostname,
+                                         * write, etc. */
+
+#include <sstream>
+
+#include <tcl.h>
+
+#include <RpEncode.h>
+#include <RpBuffer.h>
+
+#include <vrmath/Vector3f.h>
+
+#include "nanovisServer.h"
+#include "nanovis.h"
+#include "ReadBuffer.h"
+#include "Command.h"
+#include "CmdProc.h"
+#include "FlowCmd.h"
+#include "dxReader.h"
+#include "VtkReader.h"
+#include "Grid.h"
+#include "HeightMap.h"
+#include "Camera.h"
+#include "ZincBlendeVolume.h"
+#include "ZincBlendeReconstructor.h"
+#include "Unirect.h"
+#include "Volume.h"
+#include "VolumeRenderer.h"
+#include "Trace.h"
+
+using namespace nv;
+using namespace nv::graphics;
+using namespace vrmath;
+
+// default transfer function
+static const char def_transfunc[] =
+    "transfunc define default {\n\
+  0.00  0 0 1\n\
+  0.25  0 1 1\n\
+  0.50  0 1 0\n\
+  0.75  1 1 0\n\
+  1.00  1 0 0\n\
+} {\n\
+  0.000000 0.0\n\
+  0.107847 0.0\n\
+  0.107857 1.0\n\
+  0.177857 1.0\n\
+  0.177867 0.0\n\
+  0.250704 0.0\n\
+  0.250714 1.0\n\
+  0.320714 1.0\n\
+  0.320724 0.0\n\
+  0.393561 0.0\n\
+  0.393571 1.0\n\
+  0.463571 1.0\n\
+  0.463581 0.0\n\
+  0.536419 0.0\n\
+  0.536429 1.0\n\
+  0.606429 1.0\n\
+  0.606439 0.0\n\
+  0.679276 0.0\n\
+  0.679286 1.0\n\
+  0.749286 1.0\n\
+  0.749296 0.0\n\
+  0.822133 0.0\n\
+  0.822143 1.0\n\
+  0.892143 1.0\n\
+  0.892153 0.0\n\
+  1.000000 0.0\n\
+}";
+
+static int lastCmdStatus;
+
+ssize_t
+nv::SocketWrite(const void *bytes, size_t len)
+{
+    size_t ofs = 0;
+    ssize_t bytesWritten;
+    while ((bytesWritten = write(g_fdOut, (const char *)bytes + ofs, len - ofs)) > 0) {
+        ofs += bytesWritten;
+        if (ofs == len)
+            break;
+    }
+    if (bytesWritten < 0) {
+        ERROR("write: %s", strerror(errno));
+    }
+    return bytesWritten;
+}
+
+bool
+nv::SocketRead(char *bytes, size_t len)
+{
+    ReadBuffer::BufferStatus status;
+    status = g_inBufPtr->followingData((unsigned char *)bytes, len);
+    TRACE("followingData status: %d", status);
+    return (status == ReadBuffer::OK);
+}
+
+static int
+ExecuteCommand(Tcl_Interp *interp, Tcl_DString *dsPtr) 
+{
+    int result;
+#ifdef WANT_TRACE
+    char *str = Tcl_DStringValue(dsPtr);
+    std::string cmd(str);
+    cmd.erase(cmd.find_last_not_of(" \n\r\t")+1);
+    TRACE("command %lu: '%s'", g_stats.nCommands+1, cmd.c_str());
+#endif
+
+    lastCmdStatus = TCL_OK;
+    result = Tcl_EvalEx(interp, Tcl_DStringValue(dsPtr),
+                        Tcl_DStringLength(dsPtr),
+                        TCL_EVAL_DIRECT | TCL_EVAL_GLOBAL);
+    Tcl_DStringSetLength(dsPtr, 0);
+
+    if (lastCmdStatus == TCL_BREAK) {
+        return TCL_BREAK;
+    }
+    lastCmdStatus = result;
+    if (result != TCL_OK) {
+        TRACE("Error: %d", result);
+    }
+    return result;
+}
+
+int
+nv::GetBooleanFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, bool *boolPtr)
+{
+    int value;
+
+    if (Tcl_GetBooleanFromObj(interp, objPtr, &value) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    *boolPtr = (bool)value;
+    return TCL_OK;
+}
+
+int
+nv::GetFloatFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, float *valuePtr)
+{
+    double value;
+
+    if (Tcl_GetDoubleFromObj(interp, objPtr, &value) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    *valuePtr = (float)value;
+    return TCL_OK;
+}
+
+static int
+GetCullMode(Tcl_Interp *interp, Tcl_Obj *objPtr,
+            RenderContext::CullMode *modePtr)
+{
+    const char *string = Tcl_GetString(objPtr);
+    if (strcmp(string, "none") == 0) {
+        *modePtr = RenderContext::NO_CULL;
+    } else if (strcmp(string, "front") == 0) {
+        *modePtr = RenderContext::FRONT;
+    } else if (strcmp(string, "back") == 0) {
+        *modePtr = RenderContext::BACK;
+    } else {
+        Tcl_AppendResult(interp, "invalid cull mode \"", string,
+                         "\": should be front, back, or none\"", (char *)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+GetShadingModel(Tcl_Interp *interp, Tcl_Obj *objPtr,
+                RenderContext::ShadingModel *modelPtr)
+{
+    const char *string = Tcl_GetString(objPtr);
+
+    if (strcmp(string,"flat") == 0) {
+        *modelPtr = RenderContext::FLAT;
+    } else if (strcmp(string,"smooth") == 0) {
+        *modelPtr = RenderContext::SMOOTH;
+    } else {
+        Tcl_AppendResult(interp, "bad shading model \"", string,
+                         "\": should be flat or smooth", (char *)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+GetPolygonMode(Tcl_Interp *interp, Tcl_Obj *objPtr,
+               RenderContext::PolygonMode *modePtr)
+{
+    const char *string = Tcl_GetString(objPtr);
+
+    if (strcmp(string,"wireframe") == 0) {
+        *modePtr = RenderContext::LINE;
+    } else if (strcmp(string,"fill") == 0) {
+        *modePtr = RenderContext::FILL;
+    } else {
+        Tcl_AppendResult(interp, "invalid polygon mode \"", string,
+                         "\": should be wireframe or fill\"", (char *)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+/**
+ * Creates a heightmap from the given the data. The format of the data
+ * should be as follows:
+ *
+ *     xMin, xMax, xNum, yMin, yMax, yNum, heights...
+ *
+ * xNum and yNum must be integer values, all others are real numbers.
+ * The number of heights must be xNum * yNum;
+ */
+static HeightMap *
+CreateHeightMap(ClientData clientData, Tcl_Interp *interp, int objc,
+                Tcl_Obj *const *objv)
+{
+    float xMin, yMin, xMax, yMax;
+    int xNum, yNum;
+
+    if (objc != 7) {
+        Tcl_AppendResult(interp,
+        "wrong # of values: should be xMin yMin xMax yMax xNum yNum heights",
+        (char *)NULL);
+        return NULL;
+    }
+    if ((GetFloatFromObj(interp, objv[0], &xMin) != TCL_OK) ||
+        (GetFloatFromObj(interp, objv[1], &yMin) != TCL_OK) ||
+        (GetFloatFromObj(interp, objv[2], &xMax) != TCL_OK) ||
+        (GetFloatFromObj(interp, objv[3], &yMax) != TCL_OK) ||
+        (Tcl_GetIntFromObj(interp, objv[4], &xNum) != TCL_OK) ||
+        (Tcl_GetIntFromObj(interp, objv[5], &yNum) != TCL_OK)) {
+        return NULL;
+    }
+    int nValues;
+    Tcl_Obj **elem;
+    if (Tcl_ListObjGetElements(interp, objv[6], &nValues, &elem) != TCL_OK) {
+        return NULL;
+    }
+    if ((xNum <= 0) || (yNum <= 0)) {
+        Tcl_AppendResult(interp, "bad number of x or y values", (char *)NULL);
+        return NULL;
+    }
+    if (nValues != (xNum * yNum)) {
+        Tcl_AppendResult(interp, "wrong # of heights", (char *)NULL);
+        return NULL;
+    }
+
+    float *heights;
+    heights = new float[nValues];
+    if (heights == NULL) {
+        Tcl_AppendResult(interp, "can't allocate array of heights",
+                         (char *)NULL);
+        return NULL;
+    }
+
+    int i;
+    for (i = 0; i < nValues; i++) {
+        if (GetFloatFromObj(interp, elem[i], heights + i) != TCL_OK) {
+            delete [] heights;
+            return NULL;
+        }
+    }
+    HeightMap *heightMap = new HeightMap();
+    heightMap->setHeight(xMin, yMin, xMax, yMax, xNum, yNum, heights);
+    heightMap->transferFunction(NanoVis::getTransferFunction("default"));
+    heightMap->setVisible(true);
+    heightMap->setLineContourVisible(true);
+    delete [] heights;
+    return heightMap;
+}
+
+static int
+GetHeightMapFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, HeightMap **hmPtrPtr)
+{
+    const char *string = Tcl_GetString(objPtr);
+
+    NanoVis::HeightMapHashmap::iterator itr = NanoVis::heightMapTable.find(string);
+    if (itr == NanoVis::heightMapTable.end()) {
+        if (interp != NULL) {
+            Tcl_AppendResult(interp, "can't find a heightmap named \"",
+                         string, "\"", (char*)NULL);
+        }
+        return TCL_ERROR;
+    }
+    *hmPtrPtr = itr->second;
+    return TCL_OK;
+}
+
+/**
+ * Used internally to decode a series of volume index values and
+ * store then in the specified vector.  If there are no volume index
+ * arguments, this means "all volumes" to most commands, so all
+ * active volume indices are stored in the vector.
+ *
+ * Updates pushes index values into the vector.  Returns TCL_OK or
+ * TCL_ERROR to indicate an error.
+ */
+static int
+GetVolumeFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, Volume **volPtrPtr)
+{
+    const char *string = Tcl_GetString(objPtr);
+
+    NanoVis::VolumeHashmap::iterator itr = NanoVis::volumeTable.find(string);
+    if (itr == NanoVis::volumeTable.end()) {
+        if (interp != NULL) {
+            Tcl_AppendResult(interp, "can't find a volume named \"",
+                         string, "\"", (char*)NULL);
+        }
+        return TCL_ERROR;
+    }
+    *volPtrPtr = itr->second;
+    return TCL_OK;
+}
+
+/**
+ * Used internally to decode a series of volume index values and
+ * store then in the specified vector.  If there are no volume index
+ * arguments, this means "all volumes" to most commands, so all
+ * active volume indices are stored in the vector.
+ *
+ * Updates pushes index values into the vector.  Returns TCL_OK or
+ * TCL_ERROR to indicate an error.
+ */
+static int
+GetVolumes(Tcl_Interp *interp, int objc, Tcl_Obj *const *objv,
+           std::vector<Volume *>* vectorPtr)
+{
+    if (objc == 0) {
+        // No arguments. Get all volumes.
+        NanoVis::VolumeHashmap::iterator itr;
+        for (itr = NanoVis::volumeTable.begin();
+             itr != NanoVis::volumeTable.end(); ++itr) {
+            vectorPtr->push_back(itr->second);
+        }
+    } else {
+        // Get the volumes associated with the given index arguments.
+        for (int n = 0; n < objc; n++) {
+            Volume *volume;
+            if (GetVolumeFromObj(interp, objv[n], &volume) != TCL_OK) {
+                return TCL_ERROR;
+            }
+            vectorPtr->push_back(volume);
+        }
+    }
+    return TCL_OK;
+}
+
+/**
+ * Used internally to decode a series of volume index values and
+ * store then in the specified vector.  If there are no volume index
+ * arguments, this means "all volumes" to most commands, so all
+ * active volume indices are stored in the vector.
+ *
+ * Updates pushes index values into the vector.  Returns TCL_OK or
+ * TCL_ERROR to indicate an error.
+ */
+static int
+GetHeightMaps(Tcl_Interp *interp, int objc, Tcl_Obj *const *objv,
+              std::vector<HeightMap *>* vectorPtr)
+{
+    if (objc == 0) {
+        // No arguments. Get all heightmaps.
+        NanoVis::HeightMapHashmap::iterator itr;
+        for (itr = NanoVis::heightMapTable.begin();
+             itr != NanoVis::heightMapTable.end(); ++itr) {
+            vectorPtr->push_back(itr->second);
+        }
+    } else {
+        for (int n = 0; n < objc; n++) {
+            HeightMap *heightMap;
+            if (GetHeightMapFromObj(interp, objv[n], &heightMap) != TCL_OK) {
+                return TCL_ERROR;
+            }
+            vectorPtr->push_back(heightMap);
+        }
+    }
+    return TCL_OK;
+}
+
+/**
+ * Used internally to decode an axis value from a string ("x", "y",
+ * or "z") to its index (0, 1, or 2).  Returns TCL_OK if successful,
+ * along with a value in valPtr.  Otherwise, it returns TCL_ERROR
+ * and an error message in the interpreter.
+ */
+static int
+GetAxis(Tcl_Interp *interp, const char *string, int *indexPtr)
+{
+    if (string[1] == '\0') {
+        char c;
+
+        c = tolower((unsigned char)string[0]);
+        if (c == 'x') {
+            *indexPtr = 0;
+            return TCL_OK;
+        } else if (c == 'y') {
+            *indexPtr = 1;
+            return TCL_OK;
+        } else if (c == 'z') {
+            *indexPtr = 2;
+            return TCL_OK;
+        }
+        /*FALLTHRU*/
+    }
+    Tcl_AppendResult(interp, "bad axis \"", string,
+                     "\": should be x, y, or z", (char*)NULL);
+    return TCL_ERROR;
+}
+
+/**
+ * Used internally to decode an axis value from a string ("x", "y",
+ * or "z") to its index (0, 1, or 2).  Returns TCL_OK if successful,
+ * along with a value in indexPtr.  Otherwise, it returns TCL_ERROR
+ * and an error message in the interpreter.
+ */
+int
+nv::GetAxisFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, int *indexPtr)
+{
+    return GetAxis(interp, Tcl_GetString(objPtr), indexPtr);
+}
+
+/**
+ * Used internally to decode an axis value from a string ("x", "y",
+ * or "z") to its index (0, 1, or 2).  Returns TCL_OK if successful,
+ * along with a value in indexPtr.  Otherwise, it returns TCL_ERROR
+ * and an error message in the interpreter.
+ */
+static int
+GetAxisDirFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, int *indexPtr, int *dirPtr)
+{
+    const char *string = Tcl_GetString(objPtr);
+
+    int sign = 1;
+    if (*string == '-') {
+        sign = -1;
+        string++;
+    }
+    if (GetAxis(interp, string, indexPtr) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (dirPtr != NULL) {
+        *dirPtr = sign;
+    }
+    return TCL_OK;
+}
+
+/**
+ * Used internally to decode a color value from a string ("R G B")
+ * as a list of three numbers 0-1.  Returns TCL_OK if successful,
+ * along with RGB values in rgbPtr.  Otherwise, it returns TCL_ERROR
+ * and an error message in the interpreter.
+ */
+static int
+GetColor(Tcl_Interp *interp, int objc, Tcl_Obj *const *objv, float *rgbPtr)
+{
+    if (objc < 3) {
+        Tcl_AppendResult(interp, "missing color values\": ",
+                         "should list of R G B values 0.0 - 1.0", (char*)NULL);
+        return TCL_ERROR;
+    }
+    if ((GetFloatFromObj(interp, objv[0], rgbPtr + 0) != TCL_OK) ||
+        (GetFloatFromObj(interp, objv[1], rgbPtr + 1) != TCL_OK) ||
+        (GetFloatFromObj(interp, objv[2], rgbPtr + 2) != TCL_OK)) {
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+/**
+ * Read the requested number of bytes from standard input into the given
+ * buffer.  The buffer must have already been allocated for nBytes.  The 
+ * buffer is then decompressed and decoded.
+ */
+int
+nv::GetDataStream(Tcl_Interp *interp, Rappture::Buffer &buf, int nBytes)
+{
+#ifdef USE_NEW_EVENT_LOOP
+    if (!SocketRead((char *)buf.bytes(), nBytes)) {
+        return TCL_ERROR;
+    }
+    buf.count(nBytes);
+#else
+    char buffer[8096];
+
+    clearerr(g_fIn);
+    while (nBytes > 0) {
+        unsigned int chunk;
+        int nRead;
+
+        chunk = (sizeof(buffer) < (unsigned int) nBytes) ?
+            sizeof(buffer) : nBytes;
+        nRead = fread(buffer, sizeof(char), chunk, g_fIn);
+        if (ferror(g_fIn)) {
+            Tcl_AppendResult(interp, "while reading data stream: ",
+                             Tcl_PosixError(interp), (char*)NULL);
+            return TCL_ERROR;
+        }
+        if (feof(g_fIn)) {
+            Tcl_AppendResult(interp, "premature EOF while reading data stream",
+                             (char*)NULL);
+            return TCL_ERROR;
+        }
+        buf.append(buffer, nRead);
+        nBytes -= nRead;
+    }
+#endif
+    Rappture::Outcome err;
+    TRACE("Checking header[%.13s]", buf.bytes());
+    if (strncmp (buf.bytes(), "@@RP-ENC:", 9) == 0) {
+        /* There's a header on the buffer, use it to decode the data. */
+        if (!Rappture::encoding::decode(err, buf, RPENC_HDR)) {
+            Tcl_AppendResult(interp, err.remark(), (char*)NULL);
+            return TCL_ERROR;
+        }
+    } else if (Rappture::encoding::isBase64(buf.bytes(), buf.size())) {
+        /* No header, but it's base64 encoded.  It's likely that it's both
+         * base64 encoded and compressed. */
+        if (!Rappture::encoding::decode(err, buf, RPENC_B64 | RPENC_Z)) {
+            Tcl_AppendResult(interp, err.remark(), (char*)NULL);
+            return TCL_ERROR;
+        }
+    }
+    return TCL_OK;
+}
+
+static int
+CameraAngleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+              Tcl_Obj *const *objv)
+{
+    float theta, phi, psi;
+    if ((GetFloatFromObj(interp, objv[2], &phi) != TCL_OK) ||
+        (GetFloatFromObj(interp, objv[3], &theta) != TCL_OK) ||
+        (GetFloatFromObj(interp, objv[4], &psi) != TCL_OK)) {
+        return TCL_ERROR;
+    }
+    NanoVis::rotateCamera(phi, theta, psi);
+    return TCL_OK;
+}
+
+static int
+CameraOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    double quat[4];
+    if ((Tcl_GetDoubleFromObj(interp, objv[2], &quat[3]) != TCL_OK) ||
+        (Tcl_GetDoubleFromObj(interp, objv[3], &quat[0]) != TCL_OK) ||
+        (Tcl_GetDoubleFromObj(interp, objv[4], &quat[1]) != TCL_OK) ||
+        (Tcl_GetDoubleFromObj(interp, objv[5], &quat[2]) != TCL_OK)) {
+        return TCL_ERROR;
+    }
+    NanoVis::orientCamera(quat);
+    return TCL_OK;
+}
+
+static int
+CameraPanOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+             Tcl_Obj *const *objv)
+{
+    float x, y;
+    if ((GetFloatFromObj(interp, objv[2], &x) != TCL_OK) ||
+        (GetFloatFromObj(interp, objv[3], &y) != TCL_OK)) {
+        return TCL_ERROR;
+    }
+    NanoVis::panCamera(x, y);
+    return TCL_OK;
+}
+
+static int
+CameraPositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    Vector3f pos;
+    if ((GetFloatFromObj(interp, objv[2], &pos.x) != TCL_OK) ||
+        (GetFloatFromObj(interp, objv[3], &pos.y) != TCL_OK) ||
+        (GetFloatFromObj(interp, objv[4], &pos.z) != TCL_OK)) {
+        return TCL_ERROR;
+    }
+    NanoVis::setCameraPosition(pos);
+    return TCL_OK;
+}
+
+static int
+CameraResetOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+              Tcl_Obj *const *objv)
+{
+    bool all = false;
+    if (objc == 3) {
+        const char *string = Tcl_GetString(objv[2]);
+        char c = string[0];
+        if ((c != 'a') || (strcmp(string, "all") != 0)) {
+            Tcl_AppendResult(interp, "bad camera reset option \"", string,
+                             "\": should be all", (char*)NULL);
+            return TCL_ERROR;
+        }
+        all = true;
+    }
+    NanoVis::resetCamera(all);
+    return TCL_OK;
+}
+
+static int
+CameraZoomOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+             Tcl_Obj *const *objv)
+{
+    float z;
+    if (GetFloatFromObj(interp, objv[2], &z) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    NanoVis::zoomCamera(z);
+    return TCL_OK;
+}
+
+static CmdSpec cameraOps[] = {
+    {"angle",   2, CameraAngleOp,    5, 5, "xAngle yAngle zAngle",},
+    {"orient",  1, CameraOrientOp,   6, 6, "qw qx qy qz",},
+    {"pan",     2, CameraPanOp,      4, 4, "x y",},
+    {"pos",     2, CameraPositionOp, 5, 5, "x y z",},
+    {"reset",   1, CameraResetOp,    2, 3, "?all?",},
+    {"zoom",    1, CameraZoomOp,     3, 3, "factor",},
+};
+static int nCameraOps = NumCmdSpecs(cameraOps);
+
+static int
+CameraCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+          Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = GetOpFromObj(interp, nCameraOps, cameraOps,
+                        CMDSPEC_ARG1, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+SnapshotCmd(ClientData clientData, Tcl_Interp *interp, int objc,
+            Tcl_Obj *const *objv)
+{
+    int origWidth, origHeight, width, height;
+
+    origWidth = NanoVis::winWidth;
+    origHeight = NanoVis::winHeight;
+    width = 2048;
+    height = 2048;
+
+    NanoVis::resizeOffscreenBuffer(width, height);
+    NanoVis::bindOffscreenBuffer();
+    NanoVis::render();
+    NanoVis::readScreen();
+
+    NanoVis::ppmWrite("nv>image -type print -bytes");
+    NanoVis::resizeOffscreenBuffer(origWidth, origHeight);
+
+    return TCL_OK;
+}
+
+static int
+CutplanePositionOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                   Tcl_Obj *const *objv)
+{
+    float relval;
+    if (GetFloatFromObj(interp, objv[2], &relval) != TCL_OK) {
+        return TCL_ERROR;
+    }
+
+    // keep this just inside the volume so it doesn't disappear
+    if (relval < 0.01f) {
+        relval = 0.01f;
+    } else if (relval > 0.99f) {
+        relval = 0.99f;
+    }
+
+    int axis;
+    if (GetAxisFromObj(interp, objv[3], &axis) != TCL_OK) {
+        return TCL_ERROR;
+    }
+
+    std::vector<Volume *> ivol;
+    if (GetVolumes(interp, objc - 4, objv + 4, &ivol) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    std::vector<Volume *>::iterator iter;
+    for (iter = ivol.begin(); iter != ivol.end(); iter++) {
+        (*iter)->setCutplanePosition(axis, relval);
+    }
+    return TCL_OK;
+}
+
+static int
+CutplaneStateOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+
+    int axis;
+    if (GetAxisFromObj(interp, objv[3], &axis) != TCL_OK) {
+        return TCL_ERROR;
+    }
+
+    std::vector<Volume *> ivol;
+    if (GetVolumes(interp, objc - 4, objv + 4, &ivol) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (state) {
+        std::vector<Volume *>::iterator iter;
+        for (iter = ivol.begin(); iter != ivol.end(); iter++) {
+            (*iter)->enableCutplane(axis);
+        }
+    } else {
+        std::vector<Volume *>::iterator iter;
+        for (iter = ivol.begin(); iter != ivol.end(); iter++) {
+            (*iter)->disableCutplane(axis);
+        }
+    }
+    return TCL_OK;
+}
+
+static int
+CutplaneVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                  Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+
+    std::vector<Volume *> ivol;
+    if (GetVolumes(interp, objc - 3, objv + 3, &ivol) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    std::vector<Volume *>::iterator iter;
+    for (iter = ivol.begin(); iter != ivol.end(); iter++) {
+        (*iter)->cutplanesVisible(state);
+    }
+    return TCL_OK;
+}
+
+static CmdSpec cutplaneOps[] = {
+    {"position", 1, CutplanePositionOp, 4, 0, "relval axis ?indices?",},
+    {"state",    1, CutplaneStateOp,    4, 0, "bool axis ?indices?",},
+    {"visible",  1, CutplaneVisibleOp,  3, 0, "bool ?indices?",},
+};
+static int nCutplaneOps = NumCmdSpecs(cutplaneOps);
+
+/*
+ * ----------------------------------------------------------------------
+ * CLIENT COMMAND:
+ *   cutplane state on|off <axis> ?<volume>...?
+ *   cutplane position <relvalue> <axis> ?<volume>...?
+ *
+ * Clients send these commands to manipulate the cutplanes in one or
+ * more data volumes.  The "state" command turns a cutplane on or
+ * off.  The "position" command changes the position to a relative
+ * value in the range 0-1.  The <axis> can be x, y, or z.  These
+ * options are applied to the volumes represented by one or more
+ * <volume> indices.  If no volumes are specified, then all volumes
+ * are updated.
+ * ----------------------------------------------------------------------
+ */
+static int
+CutplaneCmd(ClientData clientData, Tcl_Interp *interp, int objc,
+            Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = GetOpFromObj(interp, nCutplaneOps, cutplaneOps,
+                        CMDSPEC_ARG1, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+/* 
+ * ClientInfoCmd --
+ *
+ *      Log initial values to stats file.  The first time this is called
+ *      "render_start" is written into the stats file.  Afterwards, it 
+ *      is "render_info". 
+ *        
+ *         clientinfo list
+ */
+static int
+ClientInfoCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+              Tcl_Obj *const *objv)
+{
+    Tcl_DString ds;
+    Tcl_Obj *objPtr, *listObjPtr, **items;
+    int result;
+    int i, numItems, length;
+    char buf[BUFSIZ];
+    const char *string;
+    static int first = 1;
+
+    if (objc != 2) {
+        Tcl_AppendResult(interp, "wrong # of arguments: should be \"", 
+                Tcl_GetString(objv[0]), " list\"", (char *)NULL);
+        return TCL_ERROR;
+    }
+#ifdef KEEPSTATS
+    /* Use the initial client key value pairs as the parts for a generating
+     * a unique file name. */
+    int f = getStatsFile(objv[1]);
+    if (f < 0) {
+        Tcl_AppendResult(interp, "can't open stats file: ", 
+                         Tcl_PosixError(interp), (char *)NULL);
+        return TCL_ERROR;
+    }
+#endif
+    listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
+    Tcl_IncrRefCount(listObjPtr);
+    if (first) {
+        first = false;
+        objPtr = Tcl_NewStringObj("render_start", 12);
+        Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
+        /* renderer */
+        objPtr = Tcl_NewStringObj("renderer", 8);
+        Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
+        objPtr = Tcl_NewStringObj("nanovis", 7);
+        Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
+        /* pid */
+        objPtr = Tcl_NewStringObj("pid", 3);
+        Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
+        Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewLongObj((long)g_stats.pid));
+        /* host */
+        objPtr = Tcl_NewStringObj("host", 4);
+        Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
+        gethostname(buf, BUFSIZ-1);
+        buf[BUFSIZ-1] = '\0';
+        objPtr = Tcl_NewStringObj(buf, -1);
+        Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
+    } else {
+        objPtr = Tcl_NewStringObj("render_info", 11);
+        Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
+    }
+    Tcl_DStringInit(&ds);
+    /* date */
+    Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewStringObj("date", 4));
+    strcpy(buf, ctime(&g_stats.start.tv_sec));
+    buf[strlen(buf) - 1] = '\0';
+    Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewStringObj(buf, -1));
+    /* date_secs */
+    Tcl_ListObjAppendElement(interp, listObjPtr, 
+                             Tcl_NewStringObj("date_secs", 9));
+    Tcl_ListObjAppendElement(interp, listObjPtr, 
+                             Tcl_NewLongObj(g_stats.start.tv_sec));
+    /* Client arguments. */
+    if (Tcl_ListObjGetElements(interp, objv[1], &numItems, &items) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    for (i = 0; i < numItems; i++) {
+        Tcl_ListObjAppendElement(interp, listObjPtr, items[i]);
+    }
+    Tcl_DStringInit(&ds);
+    string = Tcl_GetStringFromObj(listObjPtr, &length);
+    Tcl_DStringAppend(&ds, string, length);
+    Tcl_DStringAppend(&ds, "\n", 1);
+#ifdef KEEPSTATS
+    result = writeToStatsFile(f, Tcl_DStringValue(&ds), 
+                              Tcl_DStringLength(&ds));
+#else
+    TRACE("clientinfo: %s", Tcl_DStringValue(&ds));
+#endif
+    Tcl_DStringFree(&ds);
+    Tcl_DecrRefCount(listObjPtr);
+    return result;
+}
+
+/*
+ * ----------------------------------------------------------------------
+ * CLIENT COMMAND:
+ *   legend <volumeIndex> <width> <height>
+ *
+ * Clients use this to generate a legend image for the specified
+ * transfer function.  The legend image is a color gradient from 0
+ * to one, drawn in the given transfer function.  The resulting image
+ * is returned in the size <width> x <height>.
+ * ----------------------------------------------------------------------
+ */
+static int
+LegendCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+          Tcl_Obj *const *objv)
+{
+    if (objc != 4) {
+        Tcl_AppendResult(interp, "wrong # args: should be \"",
+            Tcl_GetString(objv[0]), " transfunc width height\"", (char*)NULL);
+        return TCL_ERROR;
+    }
+
+    const char *tfName = Tcl_GetString(objv[1]);
+    TransferFunction *tf = NanoVis::getTransferFunction(tfName);
+    if (tf == NULL) {
+        Tcl_AppendResult(interp, "unknown transfer function \"", tfName, "\"",
+                             (char*)NULL);
+        return TCL_ERROR;
+    }
+    int w, h;
+    if ((Tcl_GetIntFromObj(interp, objv[2], &w) != TCL_OK) ||
+        (Tcl_GetIntFromObj(interp, objv[3], &h) != TCL_OK)) {
+        return TCL_ERROR;
+    }
+    if (Volume::updatePending) {
+        NanoVis::setVolumeRanges();
+    }
+    NanoVis::renderLegend(tf, Volume::valueMin, Volume::valueMax, w, h, tfName);
+    return TCL_OK;
+}
+
+static int
+ScreenBgColorOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                Tcl_Obj *const *objv)
+{
+    float rgb[3];
+    if ((GetFloatFromObj(interp, objv[2], &rgb[0]) != TCL_OK) ||
+        (GetFloatFromObj(interp, objv[3], &rgb[1]) != TCL_OK) ||
+        (GetFloatFromObj(interp, objv[4], &rgb[2]) != TCL_OK)) {
+        return TCL_ERROR;
+    }
+    NanoVis::setBgColor(rgb);
+    return TCL_OK;
+}
+
+/*
+ * ----------------------------------------------------------------------
+ * CLIENT COMMAND:
+ *   screen size <width> <height>
+ *
+ * Clients send this command to set the size of the rendering area.
+ * Future images are generated at the specified width/height.
+ * ----------------------------------------------------------------------
+ */
+static int
+ScreenSizeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+             Tcl_Obj *const *objv)
+{
+    int w, h;
+    if ((Tcl_GetIntFromObj(interp, objv[2], &w) != TCL_OK) ||
+        (Tcl_GetIntFromObj(interp, objv[3], &h) != TCL_OK)) {
+        return TCL_ERROR;
+    }
+    NanoVis::resizeOffscreenBuffer(w, h);
+    return TCL_OK;
+}
+
+static CmdSpec screenOps[] = {
+    {"bgcolor",  1, ScreenBgColorOp,  5, 5, "r g b",},
+    {"size",     1, ScreenSizeOp, 4, 4, "width height",},
+};
+static int nScreenOps = NumCmdSpecs(screenOps);
+
+static int
+ScreenCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+          Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = GetOpFromObj(interp, nScreenOps, screenOps,
+                        CMDSPEC_ARG1, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+/*
+ * ----------------------------------------------------------------------
+ * CLIENT COMMAND:
+ *   transfunc define <name> <colormap> <alphamap>
+ *     where <colormap> = { <v> <r> <g> <b> ... }
+ *           <alphamap> = { <v> <w> ... }
+ *
+ * Clients send these commands to manipulate the transfer functions.
+ * ----------------------------------------------------------------------
+ */
+static int
+TransfuncCmd(ClientData clientData, Tcl_Interp *interp, int objc,
+             Tcl_Obj *const *objv)
+{
+    if (objc < 2) {
+        Tcl_AppendResult(interp, "wrong # args: should be \"",
+                Tcl_GetString(objv[0]), " option arg arg...\"", (char*)NULL);
+        return TCL_ERROR;
+    }
+
+    const char *string = Tcl_GetString(objv[1]);
+    char c = string[0];
+    if ((c == 'd') && (strcmp(string, "define") == 0)) {
+        if (objc != 5) {
+            Tcl_AppendResult(interp, "wrong # args: should be \"",
+                Tcl_GetString(objv[0]), " define name colorMap alphaMap\"",
+                (char*)NULL);
+            return TCL_ERROR;
+        }
+
+        // decode the data and store in a series of fields
+        int cmapc, amapc, i;
+        Tcl_Obj **cmapv;
+        Tcl_Obj **amapv;
+
+        amapv = cmapv = NULL;
+        if (Tcl_ListObjGetElements(interp, objv[3], &cmapc, &cmapv) != TCL_OK) {
+            return TCL_ERROR;
+        }
+        if ((cmapc % 4) != 0) {
+            Tcl_AppendResult(interp, "wrong # elements is colormap: should be ",
+                "{ v r g b ... }", (char*)NULL);
+            return TCL_ERROR;
+        }
+        if (Tcl_ListObjGetElements(interp, objv[4], &amapc, &amapv) != TCL_OK) {
+            return TCL_ERROR;
+        }
+        if ((amapc % 2) != 0) {
+            Tcl_AppendResult(interp, "wrong # elements in alphamap: should be ",
+                " { v w ... }", (char*)NULL);
+            return TCL_ERROR;
+        }
+
+        int numColors = cmapc/4;
+        float *colorKeys = new float[numColors];
+        Vector3f *colors = new Vector3f[numColors];
+        for (i = 0; i < cmapc; i += 4) {
+            int j;
+            double q[4];
+
+            for (j=0; j < 4; j++) {
+                if (Tcl_GetDoubleFromObj(interp, cmapv[i+j], &q[j]) != TCL_OK) {
+                    return TCL_ERROR;
+                }
+                if ((q[j] < 0.0) || (q[j] > 1.0)) {
+                    Tcl_AppendResult(interp, "bad colormap value \"",
+                        Tcl_GetString(cmapv[i+j]),
+                        "\": should be in the range 0-1", (char*)NULL);
+                    return TCL_ERROR;
+                }
+            }
+
+            colorKeys[i/4] = (float)q[0];
+            colors[i/4].set((float)q[1], (float)q[2], (float)q[3]);
+        }
+        int numAlphas = amapc/2;
+        float *alphaKeys = new float[numAlphas];
+        float *alphas = new float[numAlphas];
+        for (i=0; i < amapc; i += 2) {
+            double q[2];
+            int j;
+
+            for (j=0; j < 2; j++) {
+                if (Tcl_GetDoubleFromObj(interp, amapv[i+j], &q[j]) != TCL_OK) {
+                    return TCL_ERROR;
+                }
+                if ((q[j] < 0.0) || (q[j] > 1.0)) {
+                    Tcl_AppendResult(interp, "bad alphamap value \"",
+                        Tcl_GetString(amapv[i+j]),
+                        "\": should be in the range 0-1", (char*)NULL);
+                    return TCL_ERROR;
+                }
+            }
+
+            alphaKeys[i/2] = (float)q[0];
+            alphas[i/2] = (float)q[1];
+        }
+        // sample the given function into discrete slots
+        const int nslots = 256;
+        float data[4*nslots];
+        for (i=0; i < nslots; i++) {
+            float x = float(i)/(nslots-1);
+            Vector3f color;
+            float alpha;
+            TransferFunction::sample(x, colorKeys, colors, numColors, &color);
+            TransferFunction::sample(x, alphaKeys, alphas, numAlphas, &alpha);
+
+            data[4*i]   = color.r;
+            data[4*i+1] = color.g;
+            data[4*i+2] = color.b;
+            data[4*i+3] = alpha;
+        }
+        delete [] colorKeys;
+        delete [] colors;
+        delete [] alphaKeys;
+        delete [] alphas;
+        // find or create this transfer function
+        NanoVis::defineTransferFunction(Tcl_GetString(objv[2]), nslots, data);
+    } else {
+        Tcl_AppendResult(interp, "bad option \"", string,
+                "\": should be define", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+/*
+ * ----------------------------------------------------------------------
+ * CLIENT COMMAND:
+ *   up axis
+ *
+ * Clients use this to set the "up" direction for all volumes.  Volumes
+ * are oriented such that this direction points upward.
+ * ----------------------------------------------------------------------
+ */
+static int
+UpCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
+{
+    if (objc != 2) {
+        Tcl_AppendResult(interp, "wrong # args: should be \"",
+                         Tcl_GetString(objv[0]), " x|y|z|-x|-y|-z\"", (char*)NULL);
+        return TCL_ERROR;
+    }
+
+    int sign;
+    int axis;
+    if (GetAxisDirFromObj(interp, objv[1], &axis, &sign) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    NanoVis::setCameraUpdir(Camera::AxisDirection((axis+1)*sign));
+    return TCL_OK;
+}
+
+static int
+VolumeAnimationCaptureOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                         Tcl_Obj *const *objv)
+{
+    int total;
+    if (Tcl_GetIntFromObj(interp, objv[3], &total) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    VolumeInterpolator *interpolator =
+        NanoVis::volRenderer->getVolumeInterpolator();
+    interpolator->start();
+    if (interpolator->isStarted()) {
+        const char *dirName = (objc < 5) ? NULL : Tcl_GetString(objv[4]);
+        for (int frameNum = 0; frameNum < total; ++frameNum) {
+            float fraction;
+
+            fraction = ((float)frameNum) / (total - 1);
+            TRACE("fraction : %f", fraction);
+            interpolator->update(fraction);
+
+            int fboOrig;
+            glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &fboOrig);
+
+            NanoVis::bindOffscreenBuffer();  //enable offscreen render
+
+            NanoVis::render();
+            NanoVis::readScreen();
+
+            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboOrig);
+
+            NanoVis::bmpWriteToFile(frameNum, dirName);
+        }
+    }
+    return TCL_OK;
+}
+
+static int
+VolumeAnimationClearOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                       Tcl_Obj *const *objv)
+{
+    NanoVis::volRenderer->clearAnimatedVolumeInfo();
+    return TCL_OK;
+}
+
+static int
+VolumeAnimationStartOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                       Tcl_Obj *const *objv)
+{
+    NanoVis::volRenderer->startVolumeAnimation();
+    return TCL_OK;
+}
+
+static int
+VolumeAnimationStopOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                      Tcl_Obj *const *objv)
+{
+    NanoVis::volRenderer->stopVolumeAnimation();
+    return TCL_OK;
+}
+
+static int
+VolumeAnimationVolumesOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                         Tcl_Obj *const *objv)
+{
+    std::vector<Volume *> volumes;
+    if (GetVolumes(interp, objc - 3, objv + 3, &volumes) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    TRACE("parsing volume data identifier");
+    NanoVis::VolumeHashmap::iterator itr;
+    for (itr = NanoVis::volumeTable.begin();
+         itr != NanoVis::volumeTable.end(); ++itr) {
+        NanoVis::volRenderer->addAnimatedVolume(itr->second);
+    }
+    return TCL_OK;
+}
+
+static CmdSpec volumeAnimationOps[] = {
+    {"capture",   2, VolumeAnimationCaptureOp,  4, 5, "numframes ?filename?",},
+    {"clear",     2, VolumeAnimationClearOp,    3, 3, "",},
+    {"start",     3, VolumeAnimationStartOp,    3, 3, "",},
+    {"stop",      3, VolumeAnimationStopOp,     3, 3, "",},
+    {"volumes",   1, VolumeAnimationVolumesOp,  3, 0, "?indices?",},
+};
+
+static int nVolumeAnimationOps = NumCmdSpecs(volumeAnimationOps);
+
+static int
+VolumeAnimationOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                  Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = GetOpFromObj(interp, nVolumeAnimationOps, 
+                        volumeAnimationOps, CMDSPEC_ARG2, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+VolumeDataFollowsOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                    Tcl_Obj *const *objv)
+{
+    TRACE("Data Loading");
+
+    int nbytes;
+    if (Tcl_GetIntFromObj(interp, objv[3], &nbytes) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    const char *tag = Tcl_GetString(objv[4]);
+
+    Rappture::Buffer buf(nbytes);
+    if (GetDataStream(interp, buf, nbytes) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    const char *bytes = buf.bytes();
+    size_t nBytes = buf.size();
+
+    TRACE("Checking header[%.20s]", bytes);
+
+    Volume *volume = NULL;
+
+    if ((nBytes > 5) && (strncmp(bytes, "<HDR>", 5) == 0)) {
+        TRACE("ZincBlende Stream loading...");
+        volume = ZincBlendeReconstructor::getInstance()->loadFromMemory(bytes);
+        if (volume == NULL) {
+            Tcl_AppendResult(interp, "can't get volume instance", (char *)NULL);
+            return TCL_ERROR;
+        }
+        TRACE("finish loading");
+
+        Vector3f scale = volume->getPhysicalScaling();
+        Vector3f pos(scale);
+        pos *= -0.5;
+        volume->setPosition(pos);
+
+        NanoVis::VolumeHashmap::iterator itr = NanoVis::volumeTable.find(tag);
+        if (itr != NanoVis::volumeTable.end()) {
+            Tcl_AppendResult(interp, "volume \"", tag, "\" already exists.",
+                             (char *)NULL);
+            return TCL_ERROR;
+        }
+        NanoVis::volumeTable[tag] = volume;
+        volume->name(tag);
+    } else if ((nBytes > 14) && (strncmp(bytes, "# vtk DataFile", 14) == 0)) {
+        TRACE("VTK loading...");
+        if (nBytes <= 0) {
+            ERROR("data buffer is empty");
+            abort();
+        }
+        std::stringstream fdata;
+        fdata.write(bytes, nBytes);
+        volume = load_vtk_volume_stream(tag, fdata);
+        if (volume == NULL) {
+            Tcl_AppendResult(interp, "Failed to load VTK file", (char*)NULL);
+            return TCL_ERROR;
+        }
+    } else {
+        // **Deprecated** OpenDX format
+        if ((nBytes > 5) && (strncmp(bytes, "<ODX>", 5) == 0)) {
+            bytes += 5;
+            nBytes -= 5;
+        } else if ((nBytes > 4) && (strncmp(bytes, "<DX>", 4) == 0)) {
+            bytes += 4;
+            nBytes -= 4;
+        }
+        TRACE("DX loading...");
+        if (nBytes <= 0) {
+            ERROR("data buffer is empty");
+            abort();
+        }
+        std::stringstream fdata;
+        fdata.write(bytes, nBytes);
+        volume = load_dx_volume_stream(tag, fdata);
+        if (volume == NULL) {
+            Tcl_AppendResult(interp, "Failed to load DX file", (char*)NULL);
+            return TCL_ERROR;
+        }
+    }
+
+    if (volume != NULL) {
+        volume->disableCutplane(0);
+        volume->disableCutplane(1);
+        volume->disableCutplane(2);
+        volume->transferFunction(NanoVis::getTransferFunction("default"));
+        volume->visible(true);
+
+        if (Volume::updatePending) {
+            NanoVis::setVolumeRanges();
+        }
+
+        char info[1024];
+        int cmdLength =
+            sprintf(info, "nv>data tag %s min %g max %g vmin %g vmax %g\n", tag,
+                    volume->wAxis.min(), volume->wAxis.max(),
+                    Volume::valueMin, Volume::valueMax);
+        if (SocketWrite(info, (size_t)cmdLength) != (ssize_t)cmdLength) {
+            ERROR("Short write");
+            return TCL_ERROR;
+        }
+    }
+
+    return TCL_OK;
+}
+
+static int
+VolumeDataStateOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                  Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[3], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    std::vector<Volume *> ivol;
+    if (GetVolumes(interp, objc - 4, objv + 4, &ivol) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    std::vector<Volume *>::iterator iter;
+    for (iter = ivol.begin(); iter != ivol.end(); iter++) {
+        (*iter)->dataEnabled(state);
+    }
+    return TCL_OK;
+}
+
+static CmdSpec volumeDataOps[] = {
+    {"follows",   1, VolumeDataFollowsOp, 5, 5, "nbytes tag",},
+    {"state",     1, VolumeDataStateOp,   4, 0, "bool ?indices?",},
+};
+static int nVolumeDataOps = NumCmdSpecs(volumeDataOps);
+
+static int
+VolumeDataOp(ClientData clientData, Tcl_Interp *interp, int objc,
+             Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = GetOpFromObj(interp, nVolumeDataOps, volumeDataOps,
+                        CMDSPEC_ARG2, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+VolumeDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc,
+               Tcl_Obj *const *objv)
+{
+    for (int i = 2; i < objc; i++) {
+        Volume *volume;
+        if (GetVolumeFromObj(interp, objv[i], &volume) != TCL_OK) {
+            return TCL_ERROR;
+        }
+        NanoVis::removeVolume(volume);
+    }
+    NanoVis::eventuallyRedraw();
+    return TCL_OK;
+}
+
+static int
+VolumeExistsOp(ClientData clientData, Tcl_Interp *interp, int objc,
+               Tcl_Obj *const *objv)
+{
+    bool value;
+    Volume *volume;
+
+    value = false;
+    if (GetVolumeFromObj(NULL, objv[2], &volume) == TCL_OK) {
+        value = true;
+    }
+    Tcl_SetBooleanObj(Tcl_GetObjResult(interp), (int)value);
+    return TCL_OK;
+}
+
+static int
+VolumeNamesOp(ClientData clientData, Tcl_Interp *interp, int objc,
+              Tcl_Obj *const *objv)
+{
+    Tcl_Obj *listObjPtr;
+    listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL);
+    NanoVis::VolumeHashmap::iterator itr;
+    for (itr = NanoVis::volumeTable.begin();
+         itr != NanoVis::volumeTable.end(); ++itr) {
+        Tcl_Obj *objPtr = Tcl_NewStringObj(itr->second->name(), -1);
+        Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
+    }
+    Tcl_SetObjResult(interp, listObjPtr);
+    return TCL_OK;
+}
+
+static int
+VolumeOutlineColorOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                     Tcl_Obj *const *objv)
+{
+    float rgb[3];
+    if (GetColor(interp, objc - 3, objv + 3, rgb) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    std::vector<Volume *> ivol;
+    if (GetVolumes(interp, objc - 6, objv + 6, &ivol) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    std::vector<Volume *>::iterator iter;
+    for (iter = ivol.begin(); iter != ivol.end(); iter++) {
+        (*iter)->setOutlineColor(rgb);
+    }
+    return TCL_OK;
+}
+
+static int
+VolumeOutlineStateOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                     Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[3], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    std::vector<Volume *> ivol;
+    if (GetVolumes(interp, objc - 4, objv + 4, &ivol) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    std::vector<Volume *>::iterator iter;
+    for (iter = ivol.begin(); iter != ivol.end(); iter++) {
+        (*iter)->outline(state);
+    }
+    return TCL_OK;
+}
+
+static CmdSpec volumeOutlineOps[] = {
+    {"color",     1, VolumeOutlineColorOp,  6, 0, "r g b ?indices?",},
+    {"state",     1, VolumeOutlineStateOp,  4, 0, "bool ?indices?",},
+    {"visible",   1, VolumeOutlineStateOp,  4, 0, "bool ?indices?",},
+};
+static int nVolumeOutlineOps = NumCmdSpecs(volumeOutlineOps);
+
+static int
+VolumeOutlineOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = GetOpFromObj(interp, nVolumeOutlineOps, volumeOutlineOps,
+                        CMDSPEC_ARG2, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+VolumeShadingAmbientOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                       Tcl_Obj *const *objv)
+{
+    float ambient;
+    if (GetFloatFromObj(interp, objv[3], &ambient) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (ambient < 0.0f || ambient > 1.0f) {
+        WARN("Invalid ambient coefficient requested: %g, should be [0,1]", ambient);
+    }
+    std::vector<Volume *> ivol;
+    if (GetVolumes(interp, objc - 4, objv + 4, &ivol) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    std::vector<Volume *>::iterator iter;
+    for (iter = ivol.begin(); iter != ivol.end(); iter++) {
+        (*iter)->ambient(ambient);
+    }
+    return TCL_OK;
+}
+
+static int
+VolumeShadingDiffuseOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                       Tcl_Obj *const *objv)
+{
+    float diffuse;
+    if (GetFloatFromObj(interp, objv[3], &diffuse) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (diffuse < 0.0f || diffuse > 1.0f) {
+        WARN("Invalid diffuse coefficient requested: %g, should be [0,1]", diffuse);
+    }
+    std::vector<Volume *> ivol;
+    if (GetVolumes(interp, objc - 4, objv + 4, &ivol) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    std::vector<Volume *>::iterator iter;
+    for (iter = ivol.begin(); iter != ivol.end(); iter++) {
+        (*iter)->diffuse(diffuse);
+    }
+    return TCL_OK;
+}
+
+static int
+VolumeShadingIsosurfaceOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                          Tcl_Obj *const *objv)
+{
+    bool iso_surface;
+    if (GetBooleanFromObj(interp, objv[3], &iso_surface) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    std::vector<Volume *> ivol;
+    if (GetVolumes(interp, objc - 4, objv + 4, &ivol) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    std::vector<Volume *>::iterator iter;
+    for (iter = ivol.begin(); iter != ivol.end(); iter++) {
+        (*iter)->isosurface(iso_surface);
+    }
+    return TCL_OK;
+}
+
+static int
+VolumeShadingLight2SideOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                          Tcl_Obj *const *objv)
+{
+    bool twoSidedLighting;
+    if (GetBooleanFromObj(interp, objv[3], &twoSidedLighting) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    std::vector<Volume *> ivol;
+    if (GetVolumes(interp, objc - 4, objv + 4, &ivol) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    std::vector<Volume *>::iterator iter;
+    for (iter = ivol.begin(); iter != ivol.end(); iter++) {
+        (*iter)->twoSidedLighting(twoSidedLighting);
+    }
+    return TCL_OK;
+}
+
+static int
+VolumeShadingOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                       Tcl_Obj *const *objv)
+{
+
+    float opacity;
+    if (GetFloatFromObj(interp, objv[3], &opacity) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    TRACE("set opacity %f", opacity);
+    std::vector<Volume *> ivol;
+    if (GetVolumes(interp, objc - 4, objv + 4, &ivol) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    std::vector<Volume *>::iterator iter;
+    for (iter = ivol.begin(); iter != ivol.end(); iter++) {
+        (*iter)->opacityScale(opacity);
+    }
+    return TCL_OK;
+}
+
+static int
+VolumeShadingSpecularOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                        Tcl_Obj *const *objv)
+{
+    float specular;
+    if (GetFloatFromObj(interp, objv[3], &specular) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (specular < 0.0f || specular > 1.0f) {
+        WARN("Invalid specular coefficient requested: %g, should be [0,1]", specular);
+    }
+    std::vector<Volume *> ivol;
+    if (GetVolumes(interp, objc - 4, objv + 4, &ivol) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    std::vector<Volume *>::iterator iter;
+    for (iter = ivol.begin(); iter != ivol.end(); iter++) {
+        (*iter)->specularLevel(specular);
+    }
+    return TCL_OK;
+}
+
+static int
+VolumeShadingSpecularExpOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                           Tcl_Obj *const *objv)
+{
+    float specularExp;
+    if (GetFloatFromObj(interp, objv[3], &specularExp) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (specularExp < 0.0f || specularExp > 128.0f) {
+        WARN("Invalid specular exponent requested: %g, should be [0,128]", specularExp);
+    }
+    std::vector<Volume *> ivol;
+    if (GetVolumes(interp, objc - 4, objv + 4, &ivol) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    std::vector<Volume *>::iterator iter;
+    for (iter = ivol.begin(); iter != ivol.end(); iter++) {
+        (*iter)->specularExponent(specularExp);
+    }
+    return TCL_OK;
+}
+
+static int
+VolumeShadingTransFuncOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                         Tcl_Obj *const *objv)
+{
+    const char *name = Tcl_GetString(objv[3]);
+    TransferFunction *tf = NanoVis::getTransferFunction(name);
+    if (tf == NULL) {
+        Tcl_AppendResult(interp, "transfer function \"", name,
+                         "\" is not defined", (char*)NULL);
+        return TCL_ERROR;
+    }
+    std::vector<Volume *> ivol;
+    if (GetVolumes(interp, objc - 4, objv + 4, &ivol) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    std::vector<Volume *>::iterator iter;
+    for (iter = ivol.begin(); iter != ivol.end(); ++iter) {
+        TRACE("setting %s with transfer function %s", (*iter)->name(),
+               tf->name());
+        (*iter)->transferFunction(tf);
+    }
+    return TCL_OK;
+}
+
+static CmdSpec volumeShadingOps[] = {
+    {"ambient",       1, VolumeShadingAmbientOp,     4, 0, "value ?indices?",},
+    {"diffuse",       1, VolumeShadingDiffuseOp,     4, 0, "value ?indices?",},
+    {"isosurface",    1, VolumeShadingIsosurfaceOp,  4, 0, "bool ?indices?",},
+    {"light2side",    1, VolumeShadingLight2SideOp,  4, 0, "bool ?indices?",},
+    {"opacity",       1, VolumeShadingOpacityOp,     4, 0, "value ?indices?",},
+    {"specularExp",   9, VolumeShadingSpecularExpOp, 4, 0, "value ?indices?",},
+    {"specularLevel", 9, VolumeShadingSpecularOp,    4, 0, "value ?indices?",},
+    {"transfunc",     1, VolumeShadingTransFuncOp,   4, 0, "funcName ?indices?",},
+};
+static int nVolumeShadingOps = NumCmdSpecs(volumeShadingOps);
+
+static int
+VolumeShadingOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = GetOpFromObj(interp, nVolumeShadingOps, volumeShadingOps,
+                        CMDSPEC_ARG2, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+VolumeStateOp(ClientData clientData, Tcl_Interp *interp, int objc,
+              Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    std::vector<Volume *> ivol;
+    if (GetVolumes(interp, objc - 3, objv + 3, &ivol) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    std::vector<Volume *>::iterator iter;
+    for (iter = ivol.begin(); iter != ivol.end(); iter++) {
+        (*iter)->visible(state);
+    }
+    return TCL_OK;
+}
+
+static CmdSpec volumeOps[] = {
+    {"animation", 2, VolumeAnimationOp,   3, 0, "oper ?args?",},
+    {"data",      2, VolumeDataOp,        3, 0, "oper ?args?",},
+    {"delete",    2, VolumeDeleteOp,      3, 0, "?name...?",},
+    {"exists",    1, VolumeExistsOp,      3, 3, "name",},
+    {"names",     1, VolumeNamesOp,       2, 2, "",},
+    {"outline",   1, VolumeOutlineOp,     3, 0, "oper ?args?",},
+    {"shading",   2, VolumeShadingOp,     3, 0, "oper ?args?",},
+    {"state",     2, VolumeStateOp,       3, 0, "bool ?indices?",},
+};
+static int nVolumeOps = NumCmdSpecs(volumeOps);
+
+static int
+VolumeCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+          Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = GetOpFromObj(interp, nVolumeOps, volumeOps,
+                        CMDSPEC_ARG1, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+HeightMapDataFollowsOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                       Tcl_Obj *const *objv)
+{
+    int nBytes;
+    if (Tcl_GetIntFromObj(interp, objv[3], &nBytes) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    const char *tag = Tcl_GetString(objv[4]);
+
+    Rappture::Buffer buf(nBytes);
+    if (GetDataStream(interp, buf, nBytes) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    Unirect2d data(1);
+    if (data.parseBuffer(interp, buf.bytes(), buf.size()) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (data.nValues() == 0) {
+        Tcl_AppendResult(interp, "no data found in stream", (char *)NULL);
+        return TCL_ERROR;
+    }
+    if (!data.isInitialized()) {
+        return TCL_ERROR;
+    }
+    HeightMap *heightMap;
+    NanoVis::HeightMapHashmap::iterator itr = NanoVis::heightMapTable.find(tag);
+    if (itr != NanoVis::heightMapTable.end()) {
+        heightMap = itr->second;
+    } else {
+        heightMap = new HeightMap();
+        NanoVis::heightMapTable[tag] = heightMap;
+    }
+    TRACE("Number of heightmaps=%d", NanoVis::heightMapTable.size());
+    // Must set units before the heights.
+    heightMap->xAxis.units(data.xUnits());
+    heightMap->yAxis.units(data.yUnits());
+    heightMap->zAxis.units(data.vUnits());
+    heightMap->wAxis.units(data.yUnits());
+    heightMap->setHeight(data.xMin(), data.yMin(), data.xMax(), data.yMax(), 
+                         data.xNum(), data.yNum(), data.transferValues());
+    heightMap->transferFunction(NanoVis::getTransferFunction("default"));
+    heightMap->setVisible(true);
+    heightMap->setLineContourVisible(true);
+    NanoVis::eventuallyRedraw();
+    return TCL_OK;
+}
+
+static int
+HeightMapDataVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                       Tcl_Obj *const *objv)
+{
+    bool visible;
+    if (GetBooleanFromObj(interp, objv[3], &visible) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    std::vector<HeightMap *> imap;
+    if (GetHeightMaps(interp, objc - 4, objv + 4, &imap) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    std::vector<HeightMap *>::iterator iter;
+    for (iter = imap.begin(); iter != imap.end(); iter++) {
+        (*iter)->setVisible(visible);
+    }
+    NanoVis::eventuallyRedraw();
+    return TCL_OK;
+}
+
+static CmdSpec heightMapDataOps[] = {
+    {"follows",  1, HeightMapDataFollowsOp, 5, 5, "size heightmapName",},
+    {"visible",  1, HeightMapDataVisibleOp, 4, 0, "bool ?heightmapNames...?",},
+};
+static int nHeightMapDataOps = NumCmdSpecs(heightMapDataOps);
+
+static int
+HeightMapDataOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = GetOpFromObj(interp, nHeightMapDataOps, heightMapDataOps,
+                        CMDSPEC_ARG2, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+HeightMapLineContourColorOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                            Tcl_Obj *const *objv)
+{
+    float rgb[3];
+    if (GetColor(interp, objc - 3, objv + 3, rgb) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    std::vector<HeightMap *> imap;
+    if (GetHeightMaps(interp, objc - 6, objv + 6, &imap) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    std::vector<HeightMap *>::iterator iter;
+    for (iter = imap.begin(); iter != imap.end(); iter++) {
+        (*iter)->setLineContourColor(rgb);
+    }
+    NanoVis::eventuallyRedraw();
+    return TCL_OK;
+}
+
+static int
+HeightMapLineContourVisibleOp(ClientData clientData, Tcl_Interp *interp, 
+                              int objc, Tcl_Obj *const *objv)
+{
+    bool visible;
+    if (GetBooleanFromObj(interp, objv[3], &visible) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    std::vector<HeightMap *> imap;
+    if (GetHeightMaps(interp, objc - 4, objv + 4, &imap) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    std::vector<HeightMap *>::iterator iter;
+    for (iter = imap.begin(); iter != imap.end(); iter++) {
+        (*iter)->setLineContourVisible(visible);
+    }
+    NanoVis::eventuallyRedraw();
+    return TCL_OK;
+}
+
+static CmdSpec heightMapLineContourOps[] = {
+    {"color",   1, HeightMapLineContourColorOp,   6, 0, "r g b ?heightmapNames...?",},
+    {"visible", 1, HeightMapLineContourVisibleOp, 4, 0, "bool ?heightmapNames...?",},
+};
+static int nHeightMapLineContourOps = NumCmdSpecs(heightMapLineContourOps);
+
+static int 
+HeightMapLineContourOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                       Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = GetOpFromObj(interp, nHeightMapLineContourOps,
+                        heightMapLineContourOps, CMDSPEC_ARG2, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+HeightMapCullOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                Tcl_Obj *const *objv)
+{
+    RenderContext::CullMode mode;
+    if (GetCullMode(interp, objv[2], &mode) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    NanoVis::renderContext->setCullMode(mode);
+    NanoVis::eventuallyRedraw();
+    return TCL_OK;
+}
+
+static int
+HeightMapCreateOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                  Tcl_Obj *const *objv)
+{
+    const char *tag = Tcl_GetString(objv[2]);
+    NanoVis::HeightMapHashmap::iterator itr = NanoVis::heightMapTable.find(tag);
+    if (itr != NanoVis::heightMapTable.end()) {
+        Tcl_AppendResult(interp, "heightmap \"", tag, "\" already exists.",
+                         (char *)NULL);
+        return TCL_ERROR;
+    }
+    /* heightmap create xmin ymin xmax ymax xnum ynum values */
+    HeightMap *heightMap = CreateHeightMap(clientData, interp, objc - 3, objv + 3);
+    if (heightMap == NULL) {
+        return TCL_ERROR;
+    }
+    NanoVis::heightMapTable[tag] = heightMap;
+    NanoVis::eventuallyRedraw();
+    TRACE("Number of heightmaps=%d", NanoVis::heightMapTable.size());
+    return TCL_OK;
+}
+
+static int
+HeightMapLegendOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                  Tcl_Obj *const *objv)
+{
+    HeightMap *hmPtr;
+    if (GetHeightMapFromObj(interp, objv[2], &hmPtr) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    const char *tag;
+    tag = Tcl_GetString(objv[2]);
+    TransferFunction *tfPtr;
+    tfPtr = hmPtr->transferFunction();
+    if (tfPtr == NULL) {
+        Tcl_AppendResult(interp, "no transfer function defined for heightmap"
+                         " \"", tag, "\"", (char*)NULL);
+        return TCL_ERROR;
+    }
+    int w, h;
+    if ((Tcl_GetIntFromObj(interp, objv[3], &w) != TCL_OK) ||
+        (Tcl_GetIntFromObj(interp, objv[4], &h) != TCL_OK)) {
+        return TCL_ERROR;
+    }
+    if (HeightMap::updatePending) {
+        NanoVis::setHeightmapRanges();
+    }
+    NanoVis::renderLegend(tfPtr, HeightMap::valueMin, HeightMap::valueMax, 
+                          w, h, tag);
+    return TCL_OK;
+}
+
+static int
+HeightMapPolygonOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                   Tcl_Obj *const *objv)
+{
+    RenderContext::PolygonMode mode;
+    if (GetPolygonMode(interp, objv[2], &mode) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    NanoVis::renderContext->setPolygonMode(mode);
+    NanoVis::eventuallyRedraw();
+    return TCL_OK;
+}
+
+static int
+HeightMapShadingOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                 Tcl_Obj *const *objv)
+{
+    RenderContext::ShadingModel model;
+    if (GetShadingModel(interp, objv[2], &model) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    NanoVis::renderContext->setShadingModel(model);
+    NanoVis::eventuallyRedraw();
+    return TCL_OK;
+}
+
+static int
+HeightMapTransFuncOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                     Tcl_Obj *const *objv)
+{
+    const char *name;
+    name = Tcl_GetString(objv[2]);
+    TransferFunction *tf = NanoVis::getTransferFunction(name);
+    if (tf == NULL) {
+        Tcl_AppendResult(interp, "transfer function \"", name,
+                         "\" is not defined", (char*)NULL);
+        return TCL_ERROR;
+    }
+    std::vector<HeightMap *> imap;
+    if (GetHeightMaps(interp, objc - 3, objv + 3, &imap) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    std::vector<HeightMap *>::iterator iter;
+    for (iter = imap.begin(); iter != imap.end(); iter++) {
+        (*iter)->transferFunction(tf);
+    }
+    NanoVis::eventuallyRedraw();
+    return TCL_OK;
+}
+
+static int
+HeightMapOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                   Tcl_Obj *const *objv)
+{
+    float opacity;
+    if (GetFloatFromObj(interp, objv[2], &opacity) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    std::vector<HeightMap *> heightmaps;
+    if (GetHeightMaps(interp, objc - 3, objv + 3, &heightmaps) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    std::vector<HeightMap *>::iterator iter;
+    for (iter = heightmaps.begin(); iter != heightmaps.end(); iter++) {
+        (*iter)->opacity(opacity);
+    }
+    NanoVis::eventuallyRedraw();
+    return TCL_OK;
+}
+
+static CmdSpec heightMapOps[] = {
+    {"create",       2, HeightMapCreateOp,      10, 10, "heightmapName xmin ymin xmax ymax xnum ynum values",},
+    {"cull",         2, HeightMapCullOp,        3, 3, "mode",},
+    {"data",         1, HeightMapDataOp,        3, 0, "oper ?args?",},
+    {"legend",       2, HeightMapLegendOp,      5, 5, "heightmapName width height",},
+    {"linecontour",  2, HeightMapLineContourOp, 2, 0, "oper ?args?",},
+    {"opacity",      1, HeightMapOpacityOp,     3, 0, "value ?heightmapNames...? ",},
+    {"polygon",      1, HeightMapPolygonOp,     3, 3, "mode",},
+    {"shading",      1, HeightMapShadingOp,     3, 3, "model",},
+    {"transfunc",    2, HeightMapTransFuncOp,   3, 0, "name ?heightmapNames...?",},
+};
+static int nHeightMapOps = NumCmdSpecs(heightMapOps);
+
+static int
+HeightMapCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+             Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = GetOpFromObj(interp, nHeightMapOps, heightMapOps,
+                        CMDSPEC_ARG1, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+GridAxisColorOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                Tcl_Obj *const *objv)
+{
+    float r, g, b, a;
+    if ((GetFloatFromObj(interp, objv[2], &r) != TCL_OK) ||
+        (GetFloatFromObj(interp, objv[3], &g) != TCL_OK) ||
+        (GetFloatFromObj(interp, objv[4], &b) != TCL_OK)) {
+        return TCL_ERROR;
+    }
+    a = 1.0f;
+    if ((objc == 6) && (GetFloatFromObj(interp, objv[5], &a) != TCL_OK)) {
+        return TCL_ERROR;
+    }
+    if (NanoVis::grid) {
+        NanoVis::grid->setAxisColor(r, g, b, a);
+    }
+    return TCL_OK;
+}
+
+static int
+GridAxisNameOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    int axis;
+    if (GetAxisFromObj(interp, objv[2], &axis) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (NanoVis::grid != NULL) {
+        Axis *axisPtr;
+
+        axisPtr = NULL;     /* Suppress compiler warning. */
+        switch (axis) {
+        case 0: axisPtr = &NanoVis::grid->xAxis; break;
+        case 1: axisPtr = &NanoVis::grid->yAxis; break;
+        case 2: axisPtr = &NanoVis::grid->zAxis; break;
+        }
+        axisPtr->name(Tcl_GetString(objv[3]));
+        axisPtr->units(Tcl_GetString(objv[4]));
+    }
+    return TCL_OK;
+}
+
+static int
+GridLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                Tcl_Obj *const *objv)
+{
+    float r, g, b, a;
+    if ((GetFloatFromObj(interp, objv[2], &r) != TCL_OK) ||
+        (GetFloatFromObj(interp, objv[3], &g) != TCL_OK) ||
+        (GetFloatFromObj(interp, objv[4], &b) != TCL_OK)) {
+        return TCL_ERROR;
+    }
+    a = 1.0f;
+    if ((objc == 6) && (GetFloatFromObj(interp, objv[5], &a) != TCL_OK)) {
+        return TCL_ERROR;
+    }
+    if (NanoVis::grid) {
+        NanoVis::grid->setLineColor(r, g, b, a);
+    }
+    return TCL_OK;
+}
+
+static int
+GridVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+              Tcl_Obj *const *objv)
+{
+    bool visible;
+    if (GetBooleanFromObj(interp, objv[2], &visible) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    NanoVis::grid->setVisible(visible);
+    return TCL_OK;
+}
+
+static CmdSpec gridOps[] = {
+    {"axiscolor",  5, GridAxisColorOp,  5, 6, "r g b ?a?",},
+    {"axisname",   5, GridAxisNameOp,   5, 5, "index title units",},
+    {"linecolor",  7, GridLineColorOp,  5, 6, "r g b ?a?",},
+    {"visible",    1, GridVisibleOp,    3, 3, "bool",},
+};
+static int nGridOps = NumCmdSpecs(gridOps);
+
+static int
+GridCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+        Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = GetOpFromObj(interp, nGridOps, gridOps,
+                        CMDSPEC_ARG1, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+AxisCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+        Tcl_Obj *const *objv)
+{
+    if (objc < 2) {
+        Tcl_AppendResult(interp, "wrong # args: should be \"",
+                Tcl_GetString(objv[0]), " option arg arg...\"", (char*)NULL);
+        return TCL_ERROR;
+    }
+    const char *string = Tcl_GetString(objv[1]);
+    char c = string[0];
+    if ((c == 'v') && (strcmp(string, "visible") == 0)) {
+        bool visible;
+
+        if (GetBooleanFromObj(interp, objv[2], &visible) != TCL_OK) {
+            return TCL_ERROR;
+        }
+        NanoVis::axisOn = visible;
+    } else {
+        Tcl_AppendResult(interp, "bad axis option \"", string,
+                         "\": should be visible", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+ImageFlushCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+              Tcl_Obj *const *objv)
+{
+    lastCmdStatus = TCL_BREAK;
+    return TCL_OK;
+}
+
+/**
+ * \brief Execute commands from client in Tcl interpreter
+ * 
+ * In this threaded model, the select call is for event compression.  We
+ * want to execute render server commands as long as they keep coming.  
+ * This lets us execute a stream of many commands but render once.  This 
+ * benefits camera movements, screen resizing, and opacity changes 
+ * (using a slider on the client).  The down side is you don't render
+ * until there's a lull in the command stream.  If the client needs an
+ * image, it can issue an "imgflush" command.  That breaks us out of the
+ * read loop.
+ */
+int
+nv::processCommands(Tcl_Interp *interp,
+                    ReadBuffer *inBufPtr, int fdOut)
+{
+    int ret = 1;
+    int status = TCL_OK;
+
+    Tcl_DString command;
+    Tcl_DStringInit(&command);
+    fd_set readFds;
+    struct timeval tv, *tvPtr;
+
+    FD_ZERO(&readFds);
+    FD_SET(inBufPtr->file(), &readFds);
+    tvPtr = NULL;                       /* Wait for the first read. This is so
+                                         * that we don't spin when no data is
+                                         * available. */
+    while (inBufPtr->isLineAvailable() || 
+           (select(inBufPtr->file()+1, &readFds, NULL, NULL, tvPtr) > 0)) {
+        size_t numBytes;
+        unsigned char *buffer;
+
+        /* A short read is treated as an error here because we assume that we
+         * will always get commands line by line. */
+        if (inBufPtr->getLine(&numBytes, &buffer) != ReadBuffer::OK) {
+            /* Terminate the server if we can't communicate with the client
+             * anymore. */
+            if (inBufPtr->status() == ReadBuffer::ENDFILE) {
+                TRACE("Exiting server on EOF from client");
+                return -1;
+            } else {
+                ERROR("Exiting server, failed to read from client: %s",
+                      strerror(errno));
+                return -1;
+            }
+        }
+        Tcl_DStringAppend(&command, (char *)buffer, numBytes);
+        if (Tcl_CommandComplete(Tcl_DStringValue(&command))) {
+            struct timeval start, finish;
+            gettimeofday(&start, NULL);
+            status = ExecuteCommand(interp, &command);
+            gettimeofday(&finish, NULL);
+            g_stats.cmdTime += (MSECS_ELAPSED(start, finish) / 1.0e+3);
+            g_stats.nCommands++;
+            if (status == TCL_BREAK) {
+                return 1;               /* This was caused by a "imgflush"
+                                         * command. Break out of the read loop
+                                         * and allow a new image to be
+                                         * rendered. */
+            } else { //if (status != TCL_OK) {
+                ret = 0;
+                if (handleError(interp, status, fdOut) < 0) {
+                    return -1;
+                }
+            }
+        }
+
+        tv.tv_sec = tv.tv_usec = 0L;    /* On successive reads, we break out
+                                         * if no data is available. */
+        FD_SET(inBufPtr->file(), &readFds);
+        tvPtr = &tv;
+    }
+
+    return ret;
+}
+
+/**
+ * \brief Send error message to client socket
+ */
+int
+nv::handleError(Tcl_Interp *interp, int status, int fdOut)
+{
+    const char *string;
+    int nBytes;
+
+    if (status != TCL_OK) {
+        string = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
+        nBytes = strlen(string);
+        if (nBytes > 0) {
+            TRACE("status=%d errorInfo=(%s)", status, string);
+
+            std::ostringstream oss;
+            oss << "nv>viserror -type internal_error -token " << g_stats.nCommands << " -bytes " << nBytes << "\n" << string;
+            std::string ostr = oss.str();
+            nBytes = ostr.length();
+
+            if (write(fdOut, oss.str().c_str(), nBytes) < 0) {
+                ERROR("write failed: %s", strerror(errno));
+                return -1;
+            }
+        }
+    }
+
+    std::string msg = getUserMessages();
+    nBytes = msg.length();
+    if (nBytes > 0) {
+        string = msg.c_str();
+        TRACE("userError=(%s)", string);
+
+        std::ostringstream oss;
+        oss << "nv>viserror -type error -token " << g_stats.nCommands << " -bytes " << nBytes << "\n" << string;
+        std::string ostr = oss.str();
+        nBytes = ostr.length();
+
+        if (write(fdOut, ostr.c_str(), nBytes) < 0) {
+            ERROR("write failed: %s", strerror(errno));
+            return -1;
+        }
+        clearUserMessages();
+    }
+
+    return 0;
+}
+
+void
+nv::initTcl(Tcl_Interp *interp, ClientData clientData)
+{
+    Tcl_MakeSafe(interp);
+
+    Tcl_CreateObjCommand(interp, "axis",        AxisCmd,        clientData, NULL);
+    Tcl_CreateObjCommand(interp, "camera",      CameraCmd,      clientData, NULL);
+    Tcl_CreateObjCommand(interp, "clientinfo",  ClientInfoCmd,  clientData, NULL);
+    Tcl_CreateObjCommand(interp, "cutplane",    CutplaneCmd,    clientData, NULL);
+    FlowCmdInitProc(interp, clientData);
+    Tcl_CreateObjCommand(interp, "grid",        GridCmd,        clientData, NULL);
+    Tcl_CreateObjCommand(interp, "heightmap",   HeightMapCmd,   clientData, NULL);
+    Tcl_CreateObjCommand(interp, "imgflush",    ImageFlushCmd,  clientData, NULL);
+    Tcl_CreateObjCommand(interp, "legend",      LegendCmd,      clientData, NULL);
+    Tcl_CreateObjCommand(interp, "screen",      ScreenCmd,      clientData, NULL);
+    Tcl_CreateObjCommand(interp, "snapshot",    SnapshotCmd,    clientData, NULL);
+    Tcl_CreateObjCommand(interp, "transfunc",   TransfuncCmd,   clientData, NULL);
+    Tcl_CreateObjCommand(interp, "up",          UpCmd,          clientData, NULL);
+    Tcl_CreateObjCommand(interp, "volume",      VolumeCmd,      clientData, NULL);
+
+    // create a default transfer function
+    if (Tcl_Eval(interp, def_transfunc) != TCL_OK) {
+        WARN("bad default transfer function:\n%s", 
+             Tcl_GetStringResult(interp));
+    }
+}
Index: /nanovis/tags/1.1.4/Command.h
===================================================================
--- /nanovis/tags/1.1.4/Command.h	(revision 4930)
+++ /nanovis/tags/1.1.4/Command.h	(revision 4930)
@@ -0,0 +1,54 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors:
+ *   Wei Qiao <qiaow@purdue.edu>
+ *   Insoo Woo <iwoo@purdue.edu>
+ *   George A. Howlett <gah@purdue.edu>
+ *   Leif Delgass <ldelgass@purdue.edu>
+ */
+#ifndef NV_COMMAND_H
+#define NV_COMMAND_H
+
+#include <unistd.h>
+
+#include <tcl.h>
+
+namespace Rappture {
+class Buffer;
+}
+
+namespace nv {
+
+class ReadBuffer;
+class Volume;
+
+extern ssize_t SocketWrite(const void *bytes, size_t len);
+
+extern bool SocketRead(char *bytes, size_t len);
+
+extern int processCommands(Tcl_Interp *interp,
+                           ReadBuffer *inBufPtr,
+                           int fdOut);
+
+extern int handleError(Tcl_Interp *interp,
+                       int status,
+                       int fdOut);
+
+extern void initTcl(Tcl_Interp *interp, ClientData clientData);
+
+extern int GetAxisFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr,
+                          int *axisVal);
+
+extern int GetBooleanFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr,
+                             bool *boolVal);
+
+extern int GetDataStream(Tcl_Interp *interp, Rappture::Buffer &buf, int nBytes);
+
+extern int GetFloatFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr,
+                           float *floatVal);
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/ContourLineFilter.cpp
===================================================================
--- /nanovis/tags/1.1.4/ContourLineFilter.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/ContourLineFilter.cpp	(revision 4930)
@@ -0,0 +1,299 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * @note : I refer to 'http://www.codeproject.com/useritems/ScoOterVisualizationPart2.asp'
+ * @note : for this class
+ */
+
+#include <stdlib.h>
+#include <memory.h>
+
+#include <string>
+
+#include <graphics/VertexBuffer.h>
+
+#include "ContourLineFilter.h"
+
+using namespace nv;
+using namespace nv::graphics;
+using namespace vrmath;
+
+ContourLineFilter::ContourLineFilter()
+    : _colorMap(0), _top(false)
+{
+}
+
+void 
+ContourLineFilter::clear()
+{
+	
+    ContourLineFilter::ContourLineList::iterator iter;
+    for (iter = _lines.begin(); iter != _lines.end(); ++iter) { 
+	delete (*iter);
+    }
+    _lines.clear();	
+}
+
+Geometry * 
+ContourLineFilter::create(float min, float max, int linecount, 
+			  Vector3f* vertices, int width, int height)
+{
+    _lines.clear();
+    
+    float transtion = (max - min) / (linecount + 1);
+    float val;
+    int totalPoints = 0, numPoints;
+    for (int i = 1; i <= linecount; ++i) {
+	val = min + i * transtion;
+	
+	ContourLine* c = new ContourLine(val);
+	numPoints = c->createLine(width, height, vertices, _top);
+	if (numPoints != 0) {
+	    totalPoints += numPoints;
+	    _lines.push_back(c);
+	} else {
+	    delete c;
+	}
+    }
+    Vector3f* vertexSet = (Vector3f *)malloc(sizeof(Vector3f) * totalPoints);
+    Vector3f* colorSet = NULL;
+    if (_colorMap) {
+	colorSet = (Vector3f *)malloc(sizeof(Vector3f) * totalPoints);
+    }
+    ContourLineFilter::ContourLineList::iterator iter;
+    unsigned int index = 0, colorIndex = 0;
+    for (iter = _lines.begin(); iter != _lines.end(); ++iter, ++colorIndex) {
+	std::list<Vector3f>& lines = (*iter)->_points;
+	std::list<Vector3f>::iterator iter2;
+	for (iter2 = lines.begin(); iter2 != lines.end(); ++iter2, ++index) {
+	    if (_colorMap && (colorIndex < _colorMap->size())) {
+		colorSet[index] = _colorMap->at(colorIndex);
+	    } else {
+		//colorSet[index].set((*iter)->_value, (*iter)->_value, (*iter)->_value);
+	    }
+	    vertexSet[index] = (*iter2);
+	}
+    }
+    VertexBuffer *vertexBuffer = 
+        new VertexBuffer(VertexBuffer::POSITION3, totalPoints,
+                         totalPoints * sizeof(Vector3f), vertexSet, false);
+    VertexBuffer *colorBuffer = NULL;
+    if (_colorMap) {
+        colorBuffer =
+            new VertexBuffer(VertexBuffer::COLOR4, totalPoints, 
+                             totalPoints * sizeof(Vector3f), colorSet, false);
+    }
+    Geometry *geometry = new Geometry(Geometry::LINES, vertexBuffer, colorBuffer, 0);
+    clear();
+    return geometry;
+}
+
+Geometry * 
+ContourLineFilter::create(float min, float max, int linecount, 
+			  Vector4f* vertices, int width, int height)
+{
+    _lines.clear();
+
+    float transtion = (max - min) / (linecount + 1);
+
+    float val;
+    int totalPoints = 0, numPoints;
+    for (int i = 1; i <= linecount; ++i) {
+	val = min + i * transtion;
+	
+	ContourLine* c = new ContourLine(val);
+	numPoints = c->createLine(width, height, vertices, _top);
+	if (numPoints != 0) {
+	    totalPoints += numPoints;
+	    _lines.push_back(c);
+	} else {
+	    delete c;
+	}
+    }
+    Vector3f* vertexSet = (Vector3f *)malloc(sizeof(Vector3f) * totalPoints);
+    Vector3f* colorSet  = (Vector3f *)malloc(sizeof(Vector3f) * totalPoints);
+	
+    ContourLineFilter::ContourLineList::iterator iter;
+    unsigned int index = 0, colorIndex = 0;
+    for (iter = _lines.begin(); iter != _lines.end(); ++iter, ++colorIndex) {
+	std::list<Vector3f>& lines = (*iter)->_points;
+	std::list<Vector3f>::iterator iter2;
+	for (iter2 = lines.begin(); iter2 != lines.end(); ++iter2, ++index) {
+	    if (_colorMap && (colorIndex < _colorMap->size())) {
+		colorSet[index] = _colorMap->at(colorIndex);
+	    } else {
+		colorSet[index].set((*iter)->_value, (*iter)->_value, 
+				    (*iter)->_value);
+	    }
+	    vertexSet[index] = (*iter2);
+	}
+    }
+    VertexBuffer *vertexBuffer =
+        new VertexBuffer(VertexBuffer::POSITION3, totalPoints,
+                         totalPoints * sizeof(Vector3f), vertexSet, false);
+    VertexBuffer *colorBuffer =
+        new VertexBuffer(VertexBuffer::COLOR4, totalPoints,
+                         totalPoints * sizeof(Vector3f), colorSet, false);
+    Geometry *geometry =
+        new Geometry(Geometry::LINES, vertexBuffer, colorBuffer, 0);
+    clear();
+    return geometry;
+}
+
+
+ContourLineFilter::ContourLine::ContourLine(float value)
+    : _value(value)
+{
+}
+
+
+int 
+ContourLineFilter::ContourLine::createLine(int width, int height, 
+					   Vector3f* vertices, bool top)
+{
+    _points.clear();
+
+    int hl = height - 1;
+    int wl = width - 1;
+    int index1, index2, index3, index4;
+    for (int i = 0; i < hl; ++i) {
+	for (int j = 0; j < wl; ++j) {
+	    index1 = j + i * width;
+	    index2 = j + 1 + i * width;
+	    index3 = j + 1 + (i + 1) * width;
+	    index4 = j + (i + 1) * width;
+	    
+	    if (isValueWithIn(vertices[index1].y, vertices[index2].y)) 
+		getContourPoint(index1, index2, vertices, width, top);
+	    if (isValueWithIn(vertices[index2].y, vertices[index3].y)) 
+		getContourPoint(index2, index3, vertices, width, top);
+	    if (isValueWithIn(vertices[index3].y, vertices[index1].y)) 
+		getContourPoint(index3, index1, vertices, width, top);
+	    
+	    if (isValueWithIn(vertices[index1].y, vertices[index3].y)) 
+		getContourPoint(index1, index3, vertices, width, top);
+	    if (isValueWithIn(vertices[index3].y, vertices[index4].y)) 
+		getContourPoint(index3, index4, vertices, width, top);
+	    if (isValueWithIn(vertices[index4].y, vertices[index1].y)) 
+		getContourPoint(index4, index1, vertices, width, top);
+	}
+    }
+    return _points.size();
+}
+
+
+int 
+ContourLineFilter::ContourLine::createLine(int width, int height, 
+					   Vector4f* vertices, bool top)
+{
+    _points.clear();
+
+    int hl = height - 1;
+    int wl = width - 1;
+    int index1, index2, index3, index4;
+    for (int i = 0; i < hl; ++i) {
+	for (int j = 0; j < wl; ++j) {
+	    index1 = j + i * width;
+	    index2 = j + 1 + i * width;
+	    index3 = j + 1 + (i + 1) * width;
+	    index4 = j + (i + 1) * width;
+	    
+	    if (isValueWithIn(vertices[index1].y, vertices[index2].y)) 
+		getContourPoint(index1, index2, vertices, width, top);
+	    if (isValueWithIn(vertices[index2].y, vertices[index3].y)) 
+		getContourPoint(index2, index3, vertices, width, top);
+	    if (isValueWithIn(vertices[index3].y, vertices[index1].y)) 
+		getContourPoint(index3, index1, vertices, width, top);
+	    
+	    if (isValueWithIn(vertices[index1].y, vertices[index3].y)) 
+		getContourPoint(index1, index3, vertices, width, top);
+	    if (isValueWithIn(vertices[index3].y, vertices[index4].y)) 
+		getContourPoint(index3, index4, vertices, width, top);
+	    if (isValueWithIn(vertices[index4].y, vertices[index1].y)) 
+		getContourPoint(index4, index1, vertices, width, top);
+	}
+    }
+    
+    return _points.size();
+}
+
+
+void 
+ContourLineFilter::ContourLine::getContourPoint(int vertexIndex1, 
+	int vertexIndex2, Vector3f* vertices, int width, bool top)
+{
+    float diff = vertices[vertexIndex2].y - vertices[vertexIndex1].y;
+    float t = 0.0;
+    if (diff != 0) {
+	    t = (_value - vertices[vertexIndex1].y) / diff; 
+    }
+
+    Vector3f p;
+    p.x = vertices[vertexIndex1].x + t * 
+	(vertices[vertexIndex2].x - vertices[vertexIndex1].x);
+
+    if (top)
+    {
+        p.y = 1.0f;
+    }
+    else
+    {
+    p.y = vertices[vertexIndex1].y + t * 
+	(vertices[vertexIndex2].y - vertices[vertexIndex1].y);
+    }
+
+    p.z = vertices[vertexIndex1].z + t * 
+	(vertices[vertexIndex2].z - vertices[vertexIndex1].z);
+    _points.push_back(p);
+}
+
+void 
+ContourLineFilter::ContourLine::getContourPoint(int vertexIndex1, 
+	int vertexIndex2, Vector4f* vertices, int width, bool top)
+{
+    float diff = vertices[vertexIndex2].y - vertices[vertexIndex1].y;
+    float t = 0.0;
+    if (diff != 0) {
+	t = (_value - vertices[vertexIndex1].y) / diff; 
+    }
+
+    Vector3f p;
+    p.x = vertices[vertexIndex1].x + 
+	t * (vertices[vertexIndex2].x - vertices[vertexIndex1].x);
+    if (top)
+    {
+        p.y = 1.0f;
+    }
+    else
+    {
+        p.y = vertices[vertexIndex1].y + 
+	    t * (vertices[vertexIndex2].y - vertices[vertexIndex1].y);
+    }
+
+    p.z = vertices[vertexIndex1].z + 
+	t * (vertices[vertexIndex2].z - vertices[vertexIndex1].z);
+    _points.push_back(p);
+}
+
+
+void 
+ContourLineFilter::setColorMap(Vector3fArray* colorMap)
+{
+    if (colorMap == _colorMap) {
+	return;
+    }
+    if (colorMap && _colorMap) {
+	if (colorMap->size() != _colorMap->size()) {
+	    _colorMap->resize(_colorMap->size());
+	}
+	_colorMap->assign(colorMap->begin(), colorMap->end());
+    } else {
+	delete _colorMap;
+	
+	if (colorMap && colorMap->size()) {	
+	    _colorMap = new Vector3fArray(colorMap->size());
+	    _colorMap->assign(colorMap->begin(), colorMap->end());
+	} else {
+	    _colorMap = 0;
+	}
+    }
+}
Index: /nanovis/tags/1.1.4/ContourLineFilter.h
===================================================================
--- /nanovis/tags/1.1.4/ContourLineFilter.h	(revision 4930)
+++ /nanovis/tags/1.1.4/ContourLineFilter.h	(revision 4930)
@@ -0,0 +1,66 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+#ifndef NV_CONTOURLINEFILTER_H
+#define NV_CONTOURLINEFILTER_H
+
+#include <list>
+#include <vector>
+
+#include <graphics/Geometry.h>
+#include <vrmath/Vector3f.h>
+#include <vrmath/Vector4f.h>
+
+namespace nv {
+
+class ContourLineFilter
+{
+public:
+    class ContourLine
+    {
+    public:
+	ContourLine(float value);
+
+        /**
+	 * @return Returns the number of points
+	 */
+	int createLine(int width, int height, vrmath::Vector3f *vertices, bool top);
+	int createLine(int width, int height, vrmath::Vector4f *vertices, bool top);
+
+	float _value;
+	std::list<vrmath::Vector3f> _points;
+
+    private:
+	bool isValueWithIn(float v1, float v2)
+        {
+	    return ((_value >= v1 && _value <= v2) || 
+		    (_value >= v2 && _value <= v1));
+	}
+	void getContourPoint(int vertexIndex1, int vertexIndex2, vrmath::Vector3f *vertices, int width, bool top);
+	void getContourPoint(int vertexIndex1, int vertexIndex2, vrmath::Vector4f *vertices, int width, bool top);
+    };
+
+    typedef std::list<ContourLine *> ContourLineList;
+    typedef std::vector<vrmath::Vector3f> Vector3fArray;
+
+    ContourLineFilter();
+
+    nv::graphics::Geometry *create(float min, float max, int linecount, vrmath::Vector3f *vertices, int width, int height);
+    nv::graphics::Geometry *create(float min, float max, int linecount, vrmath::Vector4f *vertices, int width, int height);
+
+    void setColorMap(Vector3fArray *colorMap);
+    
+    void setHeightTop(bool top)
+    {
+	_top = top;
+    }
+
+private:
+    void clear();
+
+    ContourLineList _lines;
+    Vector3fArray *_colorMap;
+    bool _top;
+};
+
+}
+
+#endif 
Index: /nanovis/tags/1.1.4/ConvexPolygon.cpp
===================================================================
--- /nanovis/tags/1.1.4/ConvexPolygon.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/ConvexPolygon.cpp	(revision 4930)
@@ -0,0 +1,172 @@
+ /* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * ----------------------------------------------------------------------
+ * ConvexPolygon.cpp: convex polygon class
+ *
+ * ======================================================================
+ *  AUTHOR:  Wei Qiao <qiaow@purdue.edu>
+ *           Purdue Rendering and Perceptualization Lab (PURPL)
+ *
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ *  See the file "license.terms" for information on usage and
+ *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ * ======================================================================
+ */
+#include <assert.h>
+
+#include <GL/glew.h>
+
+#include "ConvexPolygon.h"
+#include "Trace.h"
+
+using namespace nv;
+using namespace vrmath;
+
+ConvexPolygon::ConvexPolygon(VertexVector newvertices)
+{
+    vertices.insert(vertices.begin(), newvertices.begin(), newvertices.end());
+}
+
+void
+ConvexPolygon::transform(const Matrix4x4d& mat)
+{
+    VertexVector tmp = vertices;
+    vertices.clear();
+
+    for (unsigned int i = 0; i < tmp.size(); i++) {
+        Vector4f vec = tmp[i];
+        vertices.push_back(mat.transform(vec));
+    }
+}
+
+void
+ConvexPolygon::translate(const Vector4f& shift)
+{
+    VertexVector tmp = vertices;
+    vertices.clear();
+
+    for (unsigned int i = 0; i < tmp.size(); i++) {
+        Vector4f vec = tmp[i];
+        vertices.push_back(vec + shift);
+    }
+}
+
+#define SIGN_DIFFERS(x, y) \
+    ( ((x) < 0.0 && (y) > 0.0) || ((x) > 0.0 && (y) < 0.0) )
+
+bool
+ConvexPolygon::clip(nv::Plane& clipPlane, bool copyToTexcoord)
+{
+    if (vertices.size() == 0) {
+        ERROR("polygon has no vertices");
+        return false;
+    }
+
+    VertexVector clippedVerts;
+    clippedVerts.reserve(2 * vertices.size());
+
+    // The algorithm is as follows: for each vertex
+    // in the current poly, check to see which 
+    // half space it is in: clipped (outside) or inside.
+    // If the previous vertex was in the other
+    // half space, find the intersection of that edge
+    // with the clip plane and add that intersection
+    // point to the new list of vertices.  If the 
+    // current vertex is in the inside half-space,
+    // add it to the new list as well.
+
+    Vector4f plane = clipPlane.getCoeffs();
+
+    // This implementation is based on the Mesa 3D library (MIT license)
+    int v1 = 0;
+    // dot product >= 0 on/inside half-space, < 0 outside half-space
+    float dot1 = vertices[v1] * plane;
+    for (unsigned int i = 1; i <= vertices.size(); i++) {
+        int v2 = (i == vertices.size()) ? 0 : i;
+        float dot2 = vertices[v2] * plane;
+        if (dot1 >= 0.0) {
+            // on/inside
+            clippedVerts.push_back(vertices[v1]);
+        }
+        if (SIGN_DIFFERS(dot1, dot2)) {
+            if (dot1 < 0.0) {
+                // outside -> inside
+                double t = dot1 / (dot1 - dot2);
+                clippedVerts.push_back(vlerp(vertices[v1], vertices[v2], t));
+            } else {
+                // inside -> outside
+                double t = dot2 / (dot2 - dot1);
+                clippedVerts.push_back(vlerp(vertices[v2], vertices[v1], t));
+            }
+        }
+        dot1 = dot2;
+        v1 = v2;
+    }
+
+    vertices.clear();
+
+    if (clippedVerts.size() < 3) {
+        texcoords.clear();
+        return false;
+    } else {
+        vertices.insert(vertices.begin(), 
+                        clippedVerts.begin(),
+                        clippedVerts.end());
+
+        if (copyToTexcoord)
+            copyVerticesToTexcoords();
+
+        return true;
+    }
+}
+
+#undef SIGN_DIFFERS
+
+void
+ConvexPolygon::copyVerticesToTexcoords()
+{
+    if (texcoords.size() > 0)
+        texcoords.clear();
+
+    for (unsigned int i = 0; i < vertices.size(); i++) {
+        texcoords.push_back(vertices[i]);
+    }
+}
+
+void
+ConvexPolygon::emit(bool useTexture)
+{
+    if (vertices.size() >= 3) {
+	for (unsigned int i = 0; i < vertices.size(); i++) {
+	    if (useTexture) {
+		glTexCoord4fv((float *)&(texcoords[i]));
+		//glTexCoord4fv((float *)&(vertices[i]));
+	    }
+	    glVertex4fv((float *)&(vertices[i]));
+	}
+    } else {
+        WARN("No polygons to render");
+    }
+}
+
+void 
+ConvexPolygon::emit(bool useTexture, const Vector3f& shift, const Vector3f& scale) 
+{
+    if (vertices.size() >= 3) {
+	for (unsigned int i = 0; i < vertices.size(); i++) {
+	    if (useTexture) {
+		glTexCoord4fv((float *)&(vertices[i]));
+	    }
+	    Vector4f tmp = (vertices[i]);
+	    Vector4f shift_4d = Vector4f(shift.x, shift.y, shift.z, 0);
+	    tmp = tmp + shift_4d;
+	    tmp.x = tmp.x * scale.x;
+	    tmp.y = tmp.y * scale.y;
+	    tmp.z = tmp.z * scale.z;
+	    glVertex4fv((float *)(&tmp));
+	}
+    } else {
+        WARN("No polygons to render");
+    }
+}
Index: /nanovis/tags/1.1.4/ConvexPolygon.h
===================================================================
--- /nanovis/tags/1.1.4/ConvexPolygon.h	(revision 4930)
+++ /nanovis/tags/1.1.4/ConvexPolygon.h	(revision 4930)
@@ -0,0 +1,69 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors:
+ *   Wei Qiao <qiaow@purdue.edu>
+ */
+#ifndef NV_CONVEX_POLYGON_H
+#define NV_CONVEX_POLYGON_H
+
+#include <assert.h>
+#include <vector>
+
+#include <vrmath/Vector3f.h>
+#include <vrmath/Vector4f.h>
+#include <vrmath/Matrix4x4d.h>
+
+#include "Plane.h"
+
+namespace nv {
+
+typedef std::vector<vrmath::Vector4f> VertexVector;
+typedef std::vector<vrmath::Vector4f> TexVector;
+
+class ConvexPolygon
+{
+public:
+    ConvexPolygon()
+    {}
+
+    ConvexPolygon(VertexVector vertices);
+
+    void transform(const vrmath::Matrix4x4d& mat);
+
+    void translate(const vrmath::Vector4f& shift);
+
+    // Clips the polygon, retaining the portion where ax + by + cz + d >= 0
+    bool clip(nv::Plane& clipPlane, bool copyToTexcoords);
+
+    void emit(bool useTexture);
+
+    void emit(bool useTexture, const vrmath::Vector3f& shift, const vrmath::Vector3f& scale);
+
+    void copyVerticesToTexcoords();
+
+    void setId(int id)
+    { 
+        volumeId = id; 
+    }
+
+    void appendVertex(const vrmath::Vector4f& vert)
+    {
+        vertices.push_back(vert);
+    }
+
+    void insertVertex(unsigned int index, const vrmath::Vector4f& vert)
+    {
+        assert(index < vertices.size());
+        vertices.insert(vertices.begin() + index, vert);
+    }
+
+    VertexVector vertices;
+    TexVector texcoords;
+    int volumeId;	//which volume this polygon slice belongs to
+};
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/Doxyfile.in
===================================================================
--- /nanovis/tags/1.1.4/Doxyfile.in	(revision 4930)
+++ /nanovis/tags/1.1.4/Doxyfile.in	(revision 4930)
@@ -0,0 +1,1520 @@
+# Doxyfile 1.6.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = "HUBzero Nanovis Render Server"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER         =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = docs/doxygen
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it parses.
+# With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this tag.
+# The format is ext=language, where ext is a file extension, and language is one of
+# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP,
+# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat
+# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran),
+# use: inc=Fortran f=C. Note that for custom extensions you also need to set 
+# FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = YES
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen to replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penality.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will rougly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the (brief and detailed) documentation of class members so that constructors and destructors are listed first. If set to NO (the default) the constructors will appear in the respective orders defined by SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by
+# doxygen. The layout file controls the global structure of the generated output files
+# in an output format independent way. The create the layout file that represents
+# doxygen's defaults, run doxygen with the -l option. You can optionally specify a
+# file name after the option, if omitted DoxygenLayout.xml will be used as the name
+# of the layout file.
+
+LAYOUT_FILE            =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT                  = @srcdir@
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS          =
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                = @srcdir@/newmat11 @srcdir@/CircularQueue.h @srcdir@/ParticleEmitter.h @srcdir@/ParticleEmitter.cpp @srcdir@/ParticleSystem.h @srcdir@/ParticleSystem.cpp @srcdir@/ParticleSystemFactory.h @srcdir@/ParticleSystemFactory.cpp @srcdir@/BucketSort.h @srcdir@/BucketSort.cpp @srcdir@/PCASplit.h @srcdir@/PCASplit.cpp @srcdir@/PointSet.h @srcdir@/PointSet.cpp @srcdir@/PointSetRenderer.h @srcdir@/PointSetRenderer.cpp @srcdir@/PointShader.h @srcdir@/PointShader.cpp
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       = */.svn/* */test/*
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER            =
+
+# If the HTML_TIMESTAMP tag is set to YES then the generated HTML
+# documentation will contain the timesstamp.
+
+HTML_TIMESTAMP         = NO
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
+
+GENERATE_DOCSET        = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE               =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING     =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER
+# are set, an additional index file will be generated that can be used as input for
+# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated
+# HTML documentation.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE          =
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add.
+# For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION           =
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = NO
+
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list.
+
+USE_INLINE_TREES       = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE       = 10
+
+# When the SEARCHENGINE tag is enable doxygen will generate a search box for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP) or Qt help (GENERATE_QHP)
+# there is already a search function so this one should typically
+# be disabled.
+
+SEARCHENGINE           = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE      = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA             =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD                =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = YES
+
+# By default doxygen will write a font called FreeSans.ttf to the output
+# directory and reference it in all dot files that doxygen generates. This
+# font does not include all possible unicode characters however, so when you need
+# these (or just want a differently looking font) you can specify the font name
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME           = FreeSans
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS           =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP            = YES
Index: /nanovis/tags/1.1.4/Flow.cpp
===================================================================
--- /nanovis/tags/1.1.4/Flow.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/Flow.cpp	(revision 4930)
@@ -0,0 +1,414 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors:
+ *   Wei Qiao <qiaow@purdue.edu>
+ *   Insoo Woo <iwoo@purdue.edu>
+ *   George A. Howlett <gah@purdue.edu>
+ *   Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#include <float.h>
+
+#include <tcl.h>
+
+#include <vrmath/Vector3f.h>
+
+#include "nanovis.h"
+#include "Flow.h"
+#include "FlowCmd.h"
+#include "FlowTypes.h"
+#include "FlowParticles.h"
+#include "FlowBox.h"
+#include "LIC.h"
+#include "VelocityArrowsSlice.h"
+#include "Switch.h"
+#include "Unirect.h"
+#include "Volume.h"
+#include "Trace.h"
+#include "TransferFunction.h"
+
+using namespace nv;
+using namespace vrmath;
+
+bool Flow::updatePending = false;
+
+Flow::Flow(Tcl_Interp *interp, const char *name) :
+    _interp(interp),
+    _name(name),
+    _data(NULL),
+    _volume(NULL)
+{
+    memset(&_sv, 0, sizeof(FlowValues));
+    _sv.sliceVisible = 1;
+    _sv.transferFunction = NanoVis::getTransferFunction("default");
+
+    _cmdToken = Tcl_CreateObjCommand(_interp, (char *)name, 
+                                     (Tcl_ObjCmdProc *)FlowInstObjCmd,
+                                     this, FlowInstDeleteProc);
+}
+
+Flow::~Flow()
+{
+    TRACE("Enter");
+
+    FreeSwitches(_switches, &_sv, 0);
+
+    if (_data != NULL) {
+        delete _data;
+    }
+    if (_volume != NULL) {
+        NanoVis::removeVolume(_volume);
+        _volume = NULL;
+    }
+    for (BoxHashmap::iterator itr = _boxTable.begin();
+         itr != _boxTable.end(); ++itr) {
+        delete itr->second;
+    }
+    _boxTable.clear();
+    for (ParticlesHashmap::iterator itr = _particlesTable.begin();
+         itr != _particlesTable.end(); ++itr) {
+        delete itr->second;
+    }
+    _particlesTable.clear();
+}
+
+void
+Flow::getBounds(Vector3f& min,
+                Vector3f& max,
+                bool onlyVisible)
+{
+    TRACE("Enter");
+
+    if (onlyVisible && !visible())
+        return;
+
+    for (BoxHashmap::iterator itr = _boxTable.begin();
+         itr != _boxTable.end(); ++itr) {
+        FlowBox *box = itr->second;
+        if (!onlyVisible || box->visible()) {
+            Vector3f fbmin, fbmax;
+            box->getWorldSpaceBounds(fbmin, fbmax,
+                                     getVolume());
+            if (min.x > fbmin.x) {
+                min.x = fbmin.x;
+            }
+            if (max.x < fbmax.x) {
+                max.x = fbmax.x;
+            }
+            if (min.y > fbmin.y) {
+                min.y = fbmin.y;
+            }
+            if (max.y < fbmax.y) {
+                max.y = fbmax.y;
+            }
+            if (min.z > fbmin.z) {
+                min.z = fbmin.z;
+            }
+            if (max.z < fbmax.z) {
+                max.z = fbmax.z;
+            }
+        }
+    }
+}
+
+float
+Flow::getRelativePosition(FlowPosition *position)
+{
+    if (position->flags == RELPOS) {
+        return position->value;
+    }
+    switch (position->axis) {
+    case AXIS_X:  
+        return (position->value - NanoVis::xMin) / 
+            (NanoVis::xMax - NanoVis::xMin); 
+    case AXIS_Y:  
+        return (position->value - NanoVis::yMin) / 
+            (NanoVis::yMax - NanoVis::yMin); 
+    case AXIS_Z:  
+        return (position->value - NanoVis::zMin) / 
+            (NanoVis::zMax - NanoVis::zMin); 
+    }
+    return 0.0;
+}
+
+void
+Flow::resetParticles()
+{
+    for (ParticlesHashmap::iterator itr = _particlesTable.begin();
+         itr != _particlesTable.end(); ++itr) {
+        itr->second->reset();
+    }
+}
+
+void
+Flow::advect()
+{
+    for (ParticlesHashmap::iterator itr = _particlesTable.begin();
+         itr != _particlesTable.end(); ++itr) {
+        if (itr->second->visible()) {
+            itr->second->advect();
+        }
+    }
+}
+
+void
+Flow::render()
+{
+    for (ParticlesHashmap::iterator itr = _particlesTable.begin();
+         itr != _particlesTable.end(); ++itr) {
+        if (itr->second->visible()) {
+            itr->second->render();
+        }
+    }
+    renderBoxes();
+}
+
+FlowParticles *
+Flow::createParticles(const char *particlesName)
+{
+    ParticlesHashmap::iterator itr = _particlesTable.find(particlesName);
+    if (itr != _particlesTable.end()) {
+        TRACE("Deleting existing particle injection plane '%s'", particlesName);
+        delete itr->second;
+        _particlesTable.erase(itr);
+    }
+    FlowParticles *particles = new FlowParticles(particlesName);
+    _particlesTable[particlesName] = particles;
+    return particles;
+}
+
+FlowParticles *
+Flow::getParticles(const char *particlesName)
+{
+    ParticlesHashmap::iterator itr;
+    itr = _particlesTable.find(particlesName);
+    if (itr == _particlesTable.end()) {
+        TRACE("Can't find particle injection plane '%s' in '%s'", particlesName, name());
+        return NULL;
+    }
+    return itr->second;
+}
+
+void
+Flow::deleteParticles(const char *particlesName)
+{
+    ParticlesHashmap::iterator itr = _particlesTable.find(particlesName);
+    if (itr == _particlesTable.end()) {
+        TRACE("Can't find particle injection plane '%s' in '%s'", particlesName, name());
+        return;
+    }
+    delete itr->second;
+    _particlesTable.erase(itr);
+}
+
+void
+Flow::getParticlesNames(std::vector<std::string>& names)
+{
+    for (ParticlesHashmap::iterator itr = _particlesTable.begin();
+         itr != _particlesTable.end(); ++itr) {
+        names.push_back(std::string(itr->second->name()));
+    }
+}
+
+FlowBox *
+Flow::createBox(const char *boxName)
+{
+    BoxHashmap::iterator itr = _boxTable.find(boxName);
+    if (itr != _boxTable.end()) {
+        TRACE("Deleting existing box '%s'", boxName);
+        delete itr->second;
+        _boxTable.erase(itr);
+    }
+    FlowBox *box = new FlowBox(boxName);
+    _boxTable[boxName] = box;
+    return box;
+}
+
+FlowBox *
+Flow::getBox(const char *boxName)
+{
+    BoxHashmap::iterator itr = _boxTable.find(boxName);
+    if (itr == _boxTable.end()) {
+        TRACE("Can't find box '%s' in '%s'", boxName, name());
+        return NULL;
+    }
+    return itr->second;
+}
+
+void
+Flow::deleteBox(const char *boxName)
+{
+    BoxHashmap::iterator itr = _boxTable.find(boxName);
+    if (itr == _boxTable.end()) {
+        TRACE("Can't find box '%s' in '%s'", boxName, name());
+        return;
+    }
+    delete itr->second;
+    _boxTable.erase(itr);
+}
+
+void Flow::getBoxNames(std::vector<std::string>& names)
+{
+    for (BoxHashmap::iterator itr = _boxTable.begin();
+         itr != _boxTable.end(); ++itr) {
+        names.push_back(std::string(itr->second->name()));
+    }
+}
+
+void
+Flow::initializeParticles()
+{
+    for (ParticlesHashmap::iterator itr = _particlesTable.begin();
+         itr != _particlesTable.end(); ++itr) {
+        itr->second->initialize();
+    }
+}
+
+bool
+Flow::scaleVectorField()
+{
+    if (_volume != NULL) {
+        TRACE("Removing existing volume: %s", _volume->name());
+        NanoVis::removeVolume(_volume);
+        _volume = NULL;
+    }
+    float *vdata = getScaledVector();
+    if (vdata == NULL) {
+        return false;
+    }
+    Volume *volume = makeVolume(vdata);
+    delete [] vdata;
+    if (volume == NULL) {
+        return false;
+    }
+    _volume = volume;
+
+    Vector3f scale = volume->getPhysicalScaling();
+    Vector3f pos = _volume->getPosition();
+
+    if (NanoVis::licRenderer != NULL) {
+        NanoVis::licRenderer->
+            setVectorField(_volume->textureID(),
+                           pos,
+                           scale.x,
+                           scale.y,
+                           scale.z,
+                           _volume->wAxis.max());
+        NanoVis::licRenderer->setSliceAxis(_sv.slicePos.axis);
+        NanoVis::licRenderer->setSlicePosition(_sv.slicePos.value);
+        NanoVis::licRenderer->visible(_sv.sliceVisible);
+    }
+
+    if (NanoVis::velocityArrowsSlice != NULL) {
+        NanoVis::velocityArrowsSlice->
+            setVectorField(_volume->textureID(),
+                           pos,
+                           scale.x,
+                           scale.y,
+                           scale.z,
+                           _volume->wAxis.max());
+        NanoVis::velocityArrowsSlice->setSliceAxis(_sv.slicePos.axis);
+        NanoVis::velocityArrowsSlice->setSlicePosition(_sv.slicePos.value);
+        NanoVis::velocityArrowsSlice->visible(_sv.showArrows);
+    }
+
+    for (ParticlesHashmap::iterator itr = _particlesTable.begin();
+         itr != _particlesTable.end(); ++itr) {
+        itr->second->setVectorField(_volume,
+                                    pos,
+                                    scale.x,
+                                    scale.y,
+                                    scale.z,
+                                    _volume->wAxis.max());
+    }
+    return true;
+}
+
+void
+Flow::renderBoxes()
+{
+    for (BoxHashmap::iterator itr = _boxTable.begin();
+         itr != _boxTable.end(); ++itr) {
+        if (itr->second->visible()) {
+            itr->second->render(_volume);
+        }
+    }
+}
+
+float *
+Flow::getScaledVector()
+{
+    assert(_data->nComponents() == 3);
+    size_t n = _data->nValues() / _data->nComponents() * 4;
+    float *data = new float[n];
+    if (data == NULL) {
+        return NULL;
+    }
+    memset(data, 0, sizeof(float) * n);
+    float *dest = data;
+    const float *values = _data->values();
+    for (size_t iz = 0; iz < _data->zNum(); iz++) {
+        for (size_t iy = 0; iy < _data->yNum(); iy++) {
+            for (size_t ix = 0; ix < _data->xNum(); ix++) {
+                double vx, vy, vz, vm;
+                vx = values[0];
+                vy = values[1];
+                vz = values[2];
+                vm = sqrt(vx*vx + vy*vy + vz*vz);
+                dest[0] = vm / NanoVis::magMax;
+                dest[1] = vx /(2.0*NanoVis::magMax) + 0.5;
+                dest[2] = vy /(2.0*NanoVis::magMax) + 0.5;
+                dest[3] = vz /(2.0*NanoVis::magMax) + 0.5;
+                values += 3;
+                dest += 4;
+            }
+        }
+    }
+    return data;
+}
+
+Volume *
+Flow::makeVolume(float *data)
+{
+    Volume *volume =
+        NanoVis::loadVolume(_name.c_str(),
+                            _data->xNum(),
+                            _data->yNum(), 
+                            _data->zNum(),
+                            4, data, 
+                            NanoVis::magMin, NanoVis::magMax, 0);
+    volume->xAxis.setRange(_data->xMin(), _data->xMax());
+    volume->yAxis.setRange(_data->yMin(), _data->yMax());
+    volume->zAxis.setRange(_data->zMin(), _data->zMax());
+
+    TRACE("min=%g %g %g max=%g %g %g mag=%g %g",
+          NanoVis::xMin, NanoVis::yMin, NanoVis::zMin,
+          NanoVis::xMax, NanoVis::yMax, NanoVis::zMax,
+          NanoVis::magMin, NanoVis::magMax);
+
+    volume->disableCutplane(0);
+    volume->disableCutplane(1);
+    volume->disableCutplane(2);
+
+    /* Initialize the volume with the previously configured values. */
+    volume->transferFunction(_sv.transferFunction);
+    volume->dataEnabled(_sv.showVolume);
+    volume->twoSidedLighting(_sv.twoSidedLighting);
+    volume->outline(_sv.showOutline);
+    volume->opacityScale(_sv.opacity);
+    volume->ambient(_sv.ambient);
+    volume->diffuse(_sv.diffuse);
+    volume->specularLevel(_sv.specular);
+    volume->specularExponent(_sv.specularExp);
+    volume->visible(_sv.showVolume);
+
+    Vector3f volScaling = volume->getPhysicalScaling();
+    Vector3f pos(volScaling);
+    pos *= -0.5;
+    volume->setPosition(pos);
+
+    Volume::updatePending = true;
+    return volume;
+}
Index: /nanovis/tags/1.1.4/Flow.h
===================================================================
--- /nanovis/tags/1.1.4/Flow.h	(revision 4930)
+++ /nanovis/tags/1.1.4/Flow.h	(revision 4930)
@@ -0,0 +1,256 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors:
+ *   Wei Qiao <qiaow@purdue.edu>
+ *   Insoo Woo <iwoo@purdue.edu>
+ *   George A. Howlett <gah@purdue.edu>
+ *   Leif Delgass <ldelgass@purdue.edu>
+ */
+#ifndef NV_FLOW_H
+#define NV_FLOW_H
+
+#include <tr1/unordered_map>
+#include <vector>
+#include <string>
+
+#include <tcl.h>
+
+#include <vrmath/Vector3f.h>
+
+#include "Switch.h"
+#include "FlowTypes.h"
+#include "FlowParticles.h"
+#include "FlowBox.h"
+#include "LIC.h"
+#include "Unirect.h"
+#include "Volume.h"
+#include "TransferFunction.h"
+
+namespace nv {
+
+struct FlowValues {
+    TransferFunction *transferFunction;
+    FlowPosition slicePos;
+    int showArrows;
+    int sliceVisible;
+    int showVolume;
+    int showOutline;
+    int isHidden;
+    int twoSidedLighting;
+    float ambient;     ///< Ambient volume shading
+    float diffuse;     ///< Diffuse volume shading
+    float specular;    ///< Specular level volume shading
+    float specularExp; ///< Specular exponent volume shading
+    float opacity;     ///< Volume opacity scaling
+};
+
+class Flow
+{
+public:
+    Flow(Tcl_Interp *interp, const char *name);
+
+    ~Flow();
+
+    void getBounds(vrmath::Vector3f& min,
+                   vrmath::Vector3f& max,
+                   bool onlyVisible);
+
+    FlowParticles *createParticles(const char *particlesName);
+
+    FlowParticles *getParticles(const char *particlesName);
+
+    void deleteParticles(const char *particlesName);
+
+    void getParticlesNames(std::vector<std::string>& names);
+
+    void render();
+
+    void advect();
+
+    void resetParticles();
+
+    void initializeParticles();
+
+    FlowBox *createBox(const char *boxName);
+
+    FlowBox *getBox(const char *boxName);
+
+    void deleteBox(const char *boxName);
+
+    void getBoxNames(std::vector<std::string>& names);
+
+    float *getScaledVector();
+
+    Volume *makeVolume(float *data);
+
+    bool scaleVectorField();
+
+    bool visible()
+    {
+        return !_sv.isHidden;
+    }
+
+    const char *name() const
+    {
+        return _name.c_str();
+    }
+
+    bool isDataLoaded()
+    {
+        return (_data != NULL);
+    }
+
+    Unirect3d *data()
+    {
+        return _data;
+    }
+
+    void data(Unirect3d *unirect)
+    {
+        if (_data != NULL) {
+            delete _data;
+        }
+        _data = unirect;
+    }
+
+    FlowSliceAxis getSliceAxis()
+    {
+        return _sv.slicePos.axis;
+    }
+
+    TransferFunction *getTransferFunction()
+    {
+        return _sv.transferFunction;
+    }
+
+    float getRelativePosition()
+    {
+        return getRelativePosition(&_sv.slicePos);
+    }
+
+#if 0
+    void setSliceAxis(FlowSliceAxis axis)
+    {
+        _sv.slicePos.axis = axis;
+        if (NanoVis::licRenderer != NULL) {
+            NanoVis::licRenderer->setSliceAxis(_sv.slicePos.axis);
+        }
+        if (NanoVis::velocityArrowsSlice != NULL) {
+            NanoVis::velocityArrowsSlice->setSliceAxis(_sv.slicePos.axis);
+        }
+    }
+
+    void setCurrentPosition(float position)
+    {
+        _sv.slicePos.value = position;
+        if (NanoVis::licRenderer != NULL) {
+            NanoVis::licRenderer->setSlicePosition(_sv.slicePos.value);
+        }
+        if (NanoVis::velocityArrowsSlice != NULL) {
+            NanoVis::velocityArrowsSlice->setSlicePosition(_sv.slicePos.value);
+        }
+    }
+
+    void setLICActive(bool state)
+    {
+        _sv.sliceVisible = state;
+        if (NanoVis::licRenderer != NULL) {
+            NanoVis::licRenderer->setVectorField(_volume);
+            NanoVis::licRenderer->setSliceAxis(_sv.slicePos.axis);
+            NanoVis::licRenderer->setSlicePosition(_sv.slicePos.value);
+            NanoVis::licRenderer->visible(state);
+        }
+    }
+
+    void setArrowsActive(bool state)
+        _sv.showArrows = state;
+        if (NanoVis::velocityArrowsSlice != NULL) {
+            NanoVis::velocityArrowsSlice->setVectorField(_volume);
+            NanoVis::velocityArrowsSlice->setSliceAxis(_sv.slicePos.axis);
+            NanoVis::velocityArrowsSlice->setSlicePosition(_sv.slicePos.value);
+            NanoVis::velocityArrowsSlice->visible(_sv.showArrows);
+        }
+    }
+#endif
+    const Volume *getVolume() const
+    {
+        return _volume;
+    }
+
+    int parseSwitches(Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
+    {
+        if (nv::ParseSwitches(interp, _switches, objc, objv, &_sv,
+                              SWITCH_DEFAULTS) < 0) {
+            return TCL_ERROR;
+        }
+        return TCL_OK;
+    }
+
+    Tcl_Command getCommandToken()
+    {
+        return _cmdToken;
+    }
+
+    static float getRelativePosition(FlowPosition *pos);
+
+    static bool updatePending;
+
+private:
+    typedef std::string ParticlesId;
+    typedef std::string BoxId;
+    typedef std::tr1::unordered_map<ParticlesId, FlowParticles *> ParticlesHashmap;
+    typedef std::tr1::unordered_map<BoxId, FlowBox *> BoxHashmap;
+
+    void renderBoxes();
+
+    Tcl_Interp *_interp;
+    /**
+     * Name of the flow.  This may differ
+     * from the name of the command
+     * associated with the flow, if the
+     * command was renamed. */
+    std::string _name;
+
+    /**
+     * Command associated with the flow.
+     * When the command is deleted, so is
+     * the flow. */
+    Tcl_Command _cmdToken;
+
+    /**
+     * Uniform rectangular data
+     * representing the mesh and vector
+     * field values.  These values are
+     * kept to regenerate the volume
+     * associated with the flow. */
+    Unirect3d *_data;
+
+    /**
+     * The volume associated with the
+     * flow.  This isn't the same thing as
+     * a normal volume displayed. */
+    Volume *_volume;
+
+    /**
+     * For each field there can be one or
+     * more particle injection planes
+     * where the particles are injected
+     * into the flow. */
+    ParticlesHashmap _particlesTable;
+
+    /**
+     * A table of boxes.  There maybe
+     * zero or more boxes associated
+     * with each field. */
+    BoxHashmap _boxTable;
+
+    FlowValues _sv;
+
+    static SwitchSpec _switches[];
+};
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/FlowBox.cpp
===================================================================
--- /nanovis/tags/1.1.4/FlowBox.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/FlowBox.cpp	(revision 4930)
@@ -0,0 +1,213 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors:
+ *   Wei Qiao <qiaow@purdue.edu>
+ *   Insoo Woo <iwoo@purdue.edu>
+ *   George A. Howlett <gah@purdue.edu>
+ *   Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#include <float.h>
+#include <assert.h>
+
+#include <vrmath/Vector3f.h>
+#include <vrmath/Vector4f.h>
+#include <vrmath/Matrix4x4d.h>
+
+#include "FlowBox.h"
+#include "Volume.h"
+#include "Trace.h"
+
+using namespace nv;
+using namespace vrmath;
+
+FlowBox::FlowBox(const char *name) :
+    _name(name)
+{
+    _sv.isHidden = false;
+    _sv.corner1.x = 0.0f;
+    _sv.corner1.y = 0.0f;
+    _sv.corner1.z = 0.0f;
+    _sv.corner2.x = 1.0f;
+    _sv.corner2.y = 1.0f;
+    _sv.corner2.z = 1.0f;
+    _sv.lineWidth = 1.2f;
+    _sv.color.r = _sv.color.b = _sv.color.g = _sv.color.a = 1.0f;
+}
+
+FlowBox::~FlowBox()
+{
+    TRACE("Freeing switches");
+    FreeSwitches(_switches, &_sv, 0);
+}
+
+void
+FlowBox::getWorldSpaceBounds(Vector3f& bboxMin,
+                             Vector3f& bboxMax,
+                             const Volume *vol) const
+{
+    bboxMin.set(FLT_MAX, FLT_MAX, FLT_MAX);
+    bboxMax.set(-FLT_MAX, -FLT_MAX, -FLT_MAX);
+
+    Vector3f origin = vol->getPosition();
+    Vector3f scale = vol->getPhysicalScaling();
+
+    Matrix4x4d mat;
+    mat.makeTranslation(origin);
+    Matrix4x4d mat2;
+    mat2.makeScale(scale);
+
+    mat.multiply(mat2);
+
+    Vector3f min, max;
+    min.x = vol->xAxis.min();
+    min.y = vol->yAxis.min();
+    min.z = vol->zAxis.min();
+    max.x = vol->xAxis.max();
+    max.y = vol->yAxis.max();
+    max.z = vol->zAxis.max();
+
+    float x0, y0, z0, x1, y1, z1;
+    x0 = y0 = z0 = 0.0f;
+    x1 = y1 = z1 = 0.0f;
+    if (max.x > min.x) {
+        x0 = (_sv.corner1.x - min.x) / (max.x - min.x);
+        x1 = (_sv.corner2.x - min.x) / (max.x - min.x);
+    }
+    if (max.y > min.y) {
+        y0 = (_sv.corner1.y - min.y) / (max.y - min.y);
+        y1 = (_sv.corner2.y - min.y) / (max.y - min.y);
+    }
+    if (max.z > min.z) {
+        z0 = (_sv.corner1.z - min.z) / (max.z - min.z);
+        z1 = (_sv.corner2.z - min.z) / (max.z - min.z);
+    }
+
+    TRACE("Box model bounds: (%g,%g,%g) - (%g,%g,%g)",
+          x0, y0, z0, x1, y1, z1);
+
+    Vector3f modelMin(x0, y0, z0);
+    Vector3f modelMax(x1, y1, z1);
+
+    Vector4f bvert[8];
+    bvert[0] = Vector4f(modelMin.x, modelMin.y, modelMin.z, 1);
+    bvert[1] = Vector4f(modelMax.x, modelMin.y, modelMin.z, 1);
+    bvert[2] = Vector4f(modelMin.x, modelMax.y, modelMin.z, 1);
+    bvert[3] = Vector4f(modelMin.x, modelMin.y, modelMax.z, 1);
+    bvert[4] = Vector4f(modelMax.x, modelMax.y, modelMin.z, 1);
+    bvert[5] = Vector4f(modelMax.x, modelMin.y, modelMax.z, 1);
+    bvert[6] = Vector4f(modelMin.x, modelMax.y, modelMax.z, 1);
+    bvert[7] = Vector4f(modelMax.x, modelMax.y, modelMax.z, 1);
+
+    for (int i = 0; i < 8; i++) {
+        Vector4f worldVert = mat.transform(bvert[i]);
+        if (worldVert.x < bboxMin.x) bboxMin.x = worldVert.x;
+        if (worldVert.x > bboxMax.x) bboxMax.x = worldVert.x;
+        if (worldVert.y < bboxMin.y) bboxMin.y = worldVert.y;
+        if (worldVert.y > bboxMax.y) bboxMax.y = worldVert.y;
+        if (worldVert.z < bboxMin.z) bboxMin.z = worldVert.z;
+        if (worldVert.z > bboxMax.z) bboxMax.z = worldVert.z;
+    }
+
+    TRACE("Box world bounds: (%g,%g,%g) - (%g,%g,%g)",
+          bboxMin.x, bboxMin.y, bboxMin.z,
+          bboxMax.x, bboxMax.y, bboxMax.z);
+}
+
+void 
+FlowBox::render(Volume *vol)
+{
+    TRACE("Box: '%s'", _name.c_str());
+
+    glPushAttrib(GL_ENABLE_BIT);
+
+    glEnable(GL_DEPTH_TEST);
+    glDisable(GL_TEXTURE_2D);
+    glDisable(GL_BLEND);
+
+    glMatrixMode(GL_MODELVIEW);
+    glPushMatrix();
+
+    Vector3f origin = vol->getPosition();
+    glTranslatef(origin.x, origin.y, origin.z);
+
+    Vector3f scale = vol->getPhysicalScaling();
+    glScalef(scale.x, scale.y, scale.z);
+
+    Vector3f min, max;
+    min.x = vol->xAxis.min();
+    min.y = vol->yAxis.min();
+    min.z = vol->zAxis.min();
+    max.x = vol->xAxis.max();
+    max.y = vol->yAxis.max();
+    max.z = vol->zAxis.max();
+
+    TRACE("box is %g,%g %g,%g %g,%g",
+          _sv.corner1.x, _sv.corner2.x,
+          _sv.corner1.y, _sv.corner2.y,
+          _sv.corner1.z, _sv.corner2.z);
+    TRACE("world is %g,%g %g,%g %g,%g",
+          min.x, max.x, min.y, max.y, min.z, max.z);
+
+    float x0, y0, z0, x1, y1, z1;
+    x0 = y0 = z0 = 0.0f;
+    x1 = y1 = z1 = 0.0f;
+    if (max.x > min.x) {
+        x0 = (_sv.corner1.x - min.x) / (max.x - min.x);
+        x1 = (_sv.corner2.x - min.x) / (max.x - min.x);
+    }
+    if (max.y > min.y) {
+        y0 = (_sv.corner1.y - min.y) / (max.y - min.y);
+        y1 = (_sv.corner2.y - min.y) / (max.y - min.y);
+    }
+    if (max.z > min.z) {
+        z0 = (_sv.corner1.z - min.z) / (max.z - min.z);
+        z1 = (_sv.corner2.z - min.z) / (max.z - min.z);
+    }
+    TRACE("box bounds: %g,%g %g,%g %g,%g",
+          x0, x1, y0, y1, z0, z1);
+
+    glColor4d(_sv.color.r, _sv.color.g, _sv.color.b, _sv.color.a);
+    glLineWidth(_sv.lineWidth);
+    glBegin(GL_LINE_LOOP); 
+    {
+        glVertex3d(x0, y0, z0);
+        glVertex3d(x1, y0, z0);
+        glVertex3d(x1, y1, z0);
+        glVertex3d(x0, y1, z0);
+    }
+    glEnd();
+    glBegin(GL_LINE_LOOP);
+    {
+        glVertex3d(x0, y0, z1);
+        glVertex3d(x1, y0, z1);
+        glVertex3d(x1, y1, z1);
+        glVertex3d(x0, y1, z1);
+    }
+    glEnd();
+    
+    glBegin(GL_LINE_LOOP);
+    {
+        glVertex3d(x0, y0, z0);
+        glVertex3d(x0, y0, z1);
+        glVertex3d(x0, y1, z1);
+        glVertex3d(x0, y1, z0);
+    }
+    glEnd();
+    
+    glBegin(GL_LINE_LOOP);
+    {
+        glVertex3d(x1, y0, z0);
+        glVertex3d(x1, y0, z1);
+        glVertex3d(x1, y1, z1);
+        glVertex3d(x1, y1, z0);
+    }
+    glEnd();
+
+    glPopMatrix();
+    glPopAttrib();
+
+    assert(CheckGL(AT));
+}
Index: /nanovis/tags/1.1.4/FlowBox.h
===================================================================
--- /nanovis/tags/1.1.4/FlowBox.h	(revision 4930)
+++ /nanovis/tags/1.1.4/FlowBox.h	(revision 4930)
@@ -0,0 +1,77 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors:
+ *   Wei Qiao <qiaow@purdue.edu>
+ *   Insoo Woo <iwoo@purdue.edu>
+ *   George A. Howlett <gah@purdue.edu>
+ *   Leif Delgass <ldelgass@purdue.edu>
+ */
+#ifndef NV_FLOWBOX_H
+#define NV_FLOWBOX_H
+
+#include <string>
+
+#include <tcl.h>
+
+#include <vrmath/Vector3f.h>
+
+#include "FlowTypes.h"
+#include "Switch.h"
+#include "Volume.h"
+
+namespace nv {
+
+struct FlowBoxValues {
+    FlowPoint corner1, corner2;    ///< Coordinates of the box.
+    FlowColor color;               ///< Color of box
+    float lineWidth;
+    int isHidden;
+};
+
+class FlowBox
+{
+public:
+    FlowBox(const char *name);
+    ~FlowBox();
+
+    const char *name() const
+    {
+        return _name.c_str();
+    }
+
+    bool visible() const
+    {
+        return !_sv.isHidden;
+    }
+
+    int parseSwitches(Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
+    {
+        if (nv::ParseSwitches(interp, _switches, objc, objv, &_sv, 
+                              SWITCH_DEFAULTS) < 0) {
+            return TCL_ERROR;
+        }
+        return TCL_OK;
+    }
+
+    void render(Volume *volume);
+
+    const FlowBoxValues *getValues() const
+    {
+        return &_sv;
+    }
+
+    void getWorldSpaceBounds(vrmath::Vector3f& min,
+                             vrmath::Vector3f& max,
+                             const Volume *volume) const;
+
+private:
+    std::string _name;          ///< Name of this box in the hash table.
+    FlowBoxValues _sv;
+    static SwitchSpec _switches[];
+};
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/FlowCmd.cpp
===================================================================
--- /nanovis/tags/1.1.4/FlowCmd.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/FlowCmd.cpp	(revision 4930)
@@ -0,0 +1,1302 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#include <assert.h>
+#include <errno.h>
+#define _OPEN_SYS
+#include <fcntl.h>
+#define _XOPEN_SOURCE_EXTENDED 1
+#include <sys/uio.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <limits.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <poll.h>
+
+#include <sstream>
+
+#include <tcl.h>
+
+#include <RpBuffer.h>
+
+#include <vrmath/Vector3f.h>
+
+#include "nvconf.h"
+
+#include "nanovisServer.h"
+#include "nanovis.h"
+#include "CmdProc.h"
+#include "Command.h"
+#include "FlowCmd.h"
+#include "FlowTypes.h"
+#include "Flow.h"
+#include "FlowBox.h"
+#include "FlowParticles.h"
+#include "Switch.h"
+#include "TransferFunction.h"
+#include "LIC.h"
+#include "Unirect.h"
+#include "VelocityArrowsSlice.h"
+#include "Volume.h"
+#include "Trace.h"
+
+using namespace nv;
+using namespace vrmath;
+
+static SwitchParseProc AxisSwitchProc;
+static SwitchCustom axisSwitch = {
+    AxisSwitchProc, NULL, 0,
+};
+
+static SwitchParseProc ColorSwitchProc;
+static SwitchCustom colorSwitch = {
+    ColorSwitchProc, NULL, 0,
+};
+
+static SwitchParseProc PointSwitchProc;
+static SwitchCustom pointSwitch = {
+    PointSwitchProc, NULL, 0,
+};
+
+static SwitchParseProc PositionSwitchProc;
+static SwitchCustom positionSwitch = {
+    PositionSwitchProc, NULL, 0,
+};
+
+static SwitchParseProc TransferFunctionSwitchProc;
+static SwitchCustom transferFunctionSwitch = {
+    TransferFunctionSwitchProc, NULL, 0,
+};
+
+SwitchSpec Flow::_switches[] = {
+    {SWITCH_FLOAT, "-ambient", "value",
+     offsetof(FlowValues, ambient), 0},
+    {SWITCH_BOOLEAN, "-arrows", "boolean",
+     offsetof(FlowValues, showArrows), 0},
+    {SWITCH_CUSTOM, "-axis", "axis",
+     offsetof(FlowValues, slicePos.axis), 0, 0, &axisSwitch},
+    {SWITCH_FLOAT, "-diffuse", "value",
+     offsetof(FlowValues, diffuse), 0},
+    {SWITCH_BOOLEAN, "-hide", "boolean",
+     offsetof(FlowValues, isHidden), 0},
+    {SWITCH_BOOLEAN, "-light2side", "boolean",
+     offsetof(FlowValues, twoSidedLighting), 0},
+    {SWITCH_FLOAT, "-opacity", "value",
+     offsetof(FlowValues, opacity), 0},
+    {SWITCH_BOOLEAN, "-outline", "boolean",
+     offsetof(FlowValues, showOutline), 0},
+    {SWITCH_CUSTOM, "-position", "number",
+     offsetof(FlowValues, slicePos), 0, 0, &positionSwitch},
+    {SWITCH_BOOLEAN, "-slice", "boolean",
+     offsetof(FlowValues, sliceVisible), 0},
+    {SWITCH_FLOAT, "-specularExp", "value",
+     offsetof(FlowValues, specularExp), 0},
+    {SWITCH_FLOAT, "-specularLevel", "value",
+     offsetof(FlowValues, specular), 0},
+    {SWITCH_CUSTOM, "-transferfunction", "name",
+     offsetof(FlowValues, transferFunction), 0, 0, &transferFunctionSwitch},
+    {SWITCH_BOOLEAN, "-volume", "boolean",
+     offsetof(FlowValues, showVolume), 0},
+    {SWITCH_END}
+};
+
+SwitchSpec FlowParticles::_switches[] = {
+    {SWITCH_CUSTOM, "-axis", "axis",
+     offsetof(FlowParticlesValues, position.axis), 0, 0, &axisSwitch},
+    {SWITCH_CUSTOM, "-color", "{r g b a}",
+     offsetof(FlowParticlesValues, color), 0, 0,  &colorSwitch},
+    {SWITCH_BOOLEAN, "-hide", "boolean",
+     offsetof(FlowParticlesValues, isHidden), 0},
+    {SWITCH_CUSTOM, "-position", "number",
+     offsetof(FlowParticlesValues, position), 0, 0, &positionSwitch},
+    {SWITCH_FLOAT, "-size", "float",
+     offsetof(FlowParticlesValues, particleSize), 0},
+    {SWITCH_END}
+};
+
+SwitchSpec FlowBox::_switches[] = {
+    {SWITCH_CUSTOM, "-color", "{r g b a}",
+     offsetof(FlowBoxValues, color), 0, 0,  &colorSwitch},
+    {SWITCH_CUSTOM, "-corner1", "{x y z}",
+     offsetof(FlowBoxValues, corner1), 0, 0, &pointSwitch},
+    {SWITCH_CUSTOM, "-corner2", "{x y z}",
+     offsetof(FlowBoxValues, corner2), 0, 0, &pointSwitch},
+    {SWITCH_BOOLEAN, "-hide", "boolean",
+     offsetof(FlowBoxValues, isHidden), 0},
+    {SWITCH_FLOAT, "-linewidth", "number",
+     offsetof(FlowBoxValues, lineWidth), 0},
+    {SWITCH_END}
+};
+
+/**
+ * $flow data follows nbytes nComponents
+ */
+static int
+FlowDataFollowsOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                  Tcl_Obj *const *objv)
+{
+    TRACE("Enter");
+
+    int nBytes;
+    if (Tcl_GetIntFromObj(interp, objv[3], &nBytes) != TCL_OK) {
+        ERROR("Bad nBytes \"%s\"", Tcl_GetString(objv[3]));
+        return TCL_ERROR;
+    }
+    if (nBytes <= 0) {
+        Tcl_AppendResult(interp, "bad # bytes request \"", 
+                         Tcl_GetString(objv[3]), "\" for \"data follows\"", (char *)NULL);
+        ERROR("Bad nbytes %d", nBytes);
+        return TCL_ERROR;
+    }
+    int nComponents;
+    if (Tcl_GetIntFromObj(interp, objv[4], &nComponents) != TCL_OK) {
+        ERROR("Bad # of components \"%s\"", Tcl_GetString(objv[4]));
+        return TCL_ERROR;
+    }
+    if (nComponents <= 0) {
+        Tcl_AppendResult(interp, "bad # of components request \"", 
+                         Tcl_GetString(objv[4]), "\" for \"data follows\"", (char *)NULL);
+        ERROR("Bad # of components %d", nComponents);
+        return TCL_ERROR;
+    }
+    Rappture::Buffer buf(nBytes);
+    TRACE("Flow data loading bytes: %d components: %d", nBytes, nComponents);
+    if (GetDataStream(interp, buf, nBytes) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    char *bytes = (char *)buf.bytes();
+    size_t length = buf.size();
+
+    Unirect3d *unirect = NULL;
+
+    Flow *flow = (Flow *)clientData;
+    if ((length > 4) && (strncmp(bytes, "<DX>", 4) == 0)) {
+        unirect = new Unirect3d(nComponents);
+        if (!unirect->importDx(nComponents, length - 4, bytes + 4)) {
+            Tcl_AppendResult(interp, "Failed to load DX file", (char *)NULL);
+            delete unirect;
+            return TCL_ERROR;
+        }
+    } else if ((length > 10) && (strncmp(bytes, "unirect3d ", 10) == 0)) {
+        unirect = new Unirect3d(nComponents);
+        if (unirect->parseBuffer(interp, bytes, length) != TCL_OK) {
+            delete unirect;
+            return TCL_ERROR;
+        }
+    } else if ((length > 10) && (strncmp(bytes, "unirect2d ", 10) == 0)) {
+        Unirect2d *u2dPtr = new Unirect2d(nComponents);
+        if (u2dPtr->parseBuffer(interp, bytes, length) != TCL_OK) {
+            delete u2dPtr;
+            return TCL_ERROR;
+        }
+        unirect = new Unirect3d(nComponents);
+        unirect->convert(u2dPtr);
+        delete u2dPtr;
+    } else {
+        TRACE("header is %.14s", buf.bytes());
+        unirect = new Unirect3d(nComponents);
+        if (!unirect->importDx(nComponents, length, bytes)) {
+            Tcl_AppendResult(interp, "Failed to load DX file", (char *)NULL);
+            delete unirect;
+            return TCL_ERROR;
+        }
+    }
+    if (unirect != NULL && unirect->nValues() == 0) {
+        delete unirect;
+        Tcl_AppendResult(interp, "no data found in stream", (char *)NULL);
+        return TCL_ERROR;
+    }
+    if (unirect != NULL) {
+        TRACE("nx = %d ny = %d nz = %d",
+              unirect->xNum(), unirect->yNum(), unirect->zNum());
+        TRACE("x0 = %lg y0 = %lg z0 = %lg",
+              unirect->xMin(), unirect->yMin(), unirect->zMin());
+        TRACE("lx = %lg ly = %lg lz = %lg",
+              unirect->xMax() - unirect->xMin(),
+              unirect->yMax() - unirect->yMin(),
+              unirect->zMax() - unirect->zMin());
+        TRACE("dx = %lg dy = %lg dz = %lg",
+              unirect->xNum() > 1 ? (unirect->xMax() - unirect->xMin())/(unirect->xNum()-1) : 0,
+              unirect->yNum() > 1 ? (unirect->yMax() - unirect->yMin())/(unirect->yNum()-1) : 0,
+              unirect->zNum() > 1 ? (unirect->zMax() - unirect->zMin())/(unirect->zNum()-1) : 0);
+        TRACE("magMin = %lg magMax = %lg",
+              unirect->magMin(), unirect->magMax());
+        flow->data(unirect);
+
+        char info[1024];
+        int length =
+            sprintf(info, "nv>data tag %s min %g max %g\n",
+                    flow->name(), unirect->magMin(), unirect->magMax());
+        if (SocketWrite(info, (size_t)length) < 0) {
+            return TCL_ERROR;
+        }
+    }
+    Flow::updatePending = true;
+    NanoVis::eventuallyRedraw();
+    return TCL_OK;
+}
+
+static CmdSpec flowDataOps[] = {
+    {"follows", 1, FlowDataFollowsOp, 5, 5, "size nComponents",},
+};
+static int nFlowDataOps = NumCmdSpecs(flowDataOps);
+
+static int
+FlowDataOp(ClientData clientData, Tcl_Interp *interp, int objc,
+           Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = GetOpFromObj(interp, nFlowDataOps, flowDataOps,
+                        CMDSPEC_ARG2, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+/**
+ * \brief Convert a Tcl_Obj representing the label of a child node into its
+ * integer node id.
+ *
+ * \param clientData Flag indicating if the node is considered before or 
+ * after the insertion position.
+ * \param interp Interpreter to send results back to
+ * \param switchName Not used
+ * \param objPtr String representation
+ * \param record Structure record
+ * \param offset Not used
+ * \param flags Not used
+ *
+ * \return The return value is a standard Tcl result.
+ */
+static int
+AxisSwitchProc(ClientData clientData, Tcl_Interp *interp,
+               const char *switchName, Tcl_Obj *objPtr,
+               char *record, int offset, int flags)
+{
+    const char *string = Tcl_GetString(objPtr);
+    if (string[1] == '\0') {
+        FlowSliceAxis *axisPtr = (FlowSliceAxis *)(record + offset);
+        char c;
+        c = tolower((unsigned char)string[0]);
+        if (c == 'x') {
+            *axisPtr = AXIS_X;
+            return TCL_OK;
+        } else if (c == 'y') {
+            *axisPtr = AXIS_Y;
+            return TCL_OK;
+        } else if (c == 'z') {
+            *axisPtr = AXIS_Z;
+            return TCL_OK;
+        }
+        /*FALLTHRU*/
+    }
+    Tcl_AppendResult(interp, "bad axis \"", string,
+                     "\": should be x, y, or z", (char*)NULL);
+    return TCL_ERROR;
+}
+
+/**
+ * \brief Convert a Tcl_Obj representing the label of a list of four color 
+ * components in to a RGBA color value.
+ *
+ * \param clientData Flag indicating if the node is considered before or 
+ * after the insertion position.
+ * \param interp Interpreter to send results back to
+ * \param switchName Not used
+ * \param objPtr String representation
+ * \param record Structure record
+ * \param offset Not used
+ * \param flags Not used
+ * 
+ * \return The return value is a standard Tcl result.
+ */
+static int
+ColorSwitchProc(ClientData clientData, Tcl_Interp *interp,
+                const char *switchName, Tcl_Obj *objPtr,
+                char *record, int offset, int flags)
+{
+    Tcl_Obj **objv;
+    int objc;
+    FlowColor *color = (FlowColor *)(record + offset);
+
+    if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if ((objc < 3) || (objc > 4)) {
+        Tcl_AppendResult(interp, "wrong # of elements in color definition",
+                         (char *)NULL);
+        return TCL_ERROR;
+    }
+    float values[4];
+    int i;
+    values[3] = 1.0f;
+    for (i = 0; i < objc; i++) {
+        float value;
+
+        if (GetFloatFromObj(interp, objv[i], &value) != TCL_OK) {
+            return TCL_ERROR;
+        }
+        if ((value < 0.0) || (value > 1.0)) {
+            Tcl_AppendResult(interp, "bad component value in \"",
+                             Tcl_GetString(objPtr), "\": color values must be [0..1]",
+                             (char *)NULL);
+            return TCL_ERROR;
+        }
+        values[i] = value;
+    }
+    color->r = values[0];
+    color->g = values[1];
+    color->b = values[2];
+    color->a = values[3];
+    return TCL_OK;
+}
+
+/**
+ * \brief Convert a Tcl_Obj representing the a 3-D coordinate into a point.
+ *
+ * \param clientData Flag indicating if the node is considered before or 
+ * after the insertion position.
+ * \param interp Interpreter to send results back to
+ * \param switchName Not used
+ * \param objPtr String representation
+ * \param record Structure record
+ * \param offset Not used
+ * \param flags Not used
+ *
+ * \return The return value is a standard Tcl result.
+ */
+static int
+PointSwitchProc(ClientData clientData, Tcl_Interp *interp,
+                const char *switchName, Tcl_Obj *objPtr,
+                char *record, int offset, int flags)
+{
+    FlowPoint *point = (FlowPoint *)(record + offset);
+    int objc;
+    Tcl_Obj **objv;
+
+    if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc != 3) {
+        Tcl_AppendResult(interp, "wrong # of elements for box coordinates: "
+                         " should be \"x y z\"", (char *)NULL);
+        return TCL_ERROR;
+    }
+    float values[3];
+    int i;
+    for (i = 0; i < objc; i++) {
+        float value;
+
+        if (GetFloatFromObj(interp, objv[i], &value) != TCL_OK) {
+            return TCL_ERROR;
+        }
+        values[i] = value;
+    }
+    point->x = values[0];
+    point->y = values[1];
+    point->z = values[2];
+    return TCL_OK;
+}
+
+/**
+ * \brief Convert a Tcl_Obj representing the a 3-D coordinate into a point.
+ *
+ * \param clientData Flag indicating if the node is considered before or 
+ * after the insertion position.
+ * \param interp Interpreter to send results back to
+ * \param switchName Not used
+ * \param objPtr String representation
+ * \param record Structure record
+ * \param offset Not used
+ * \param flags Not used
+ *
+ * \return The return value is a standard Tcl result.
+ */
+static int
+PositionSwitchProc(ClientData clientData, Tcl_Interp *interp,
+                   const char *switchName, Tcl_Obj *objPtr,
+                   char *record, int offset, int flags)
+{
+    FlowPosition *posPtr = (FlowPosition *)(record + offset);
+    const char *string;
+    char *p;
+
+    string = Tcl_GetString(objPtr);
+    p = strrchr((char *)string, '%');
+    if (p == NULL) {
+        float value;
+
+        if (GetFloatFromObj(interp, objPtr, &value) != TCL_OK) {
+            return TCL_ERROR;
+        }
+        posPtr->value = value;
+        posPtr->flags = ABSPOS;
+    } else {
+        double value;
+
+        *p = '\0';
+        if (Tcl_GetDouble(interp, string, &value) != TCL_OK) {
+            return TCL_ERROR;
+        }
+        posPtr->value = (float)value * 0.01;
+        posPtr->flags = RELPOS;
+    }
+    return TCL_OK;
+}
+
+/**
+ * \brief Convert a Tcl_Obj representing the transfer function into a
+ *  TransferFunction pointer.  
+ *
+ * The transfer function must have been previously defined.
+ *
+ * \param clientData Flag indicating if the node is considered before or 
+ * after the insertion position.
+ * \param interp Interpreter to send results back to
+ * \param switchName Not used
+ * \param objPtr String representation
+ * \param record Structure record
+ * \param offset Not used
+ * \param flags Not used
+ *
+ * \return The return value is a standard Tcl result.
+ */
+static int
+TransferFunctionSwitchProc(ClientData clientData, Tcl_Interp *interp,
+                           const char *switchName, Tcl_Obj *objPtr,
+                           char *record, int offset, int flags)
+{
+    TransferFunction **funcPtrPtr = (TransferFunction **)(record + offset);
+    TransferFunction *tf = NanoVis::getTransferFunction(Tcl_GetString(objPtr));
+    if (tf == NULL) {
+        Tcl_AppendResult(interp, "transfer function \"", Tcl_GetString(objPtr),
+                         "\" is not defined", (char*)NULL);
+        return TCL_ERROR;
+    }
+    *funcPtrPtr = tf;
+    return TCL_OK;
+}
+
+static int
+FlowConfigureOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                Tcl_Obj *const *objv)
+{
+    Flow *flow = (Flow *)clientData;
+
+    if (flow->parseSwitches(interp, objc - 2, objv + 2) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    Flow::updatePending = true;
+    NanoVis::eventuallyRedraw();
+    return TCL_OK;
+}
+
+static int
+FlowParticlesAddOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                   Tcl_Obj *const *objv)
+{
+    Flow *flow = (Flow *)clientData;
+    const char *particlesName = Tcl_GetString(objv[3]);
+    FlowParticles *particles = flow->createParticles(particlesName);
+    if (particles == NULL) {
+        Tcl_AppendResult(interp, "Flow particle injection plane \"",
+                         particlesName,
+                         "\" already exists or could not be created",
+                         (char*)NULL);
+        return TCL_ERROR;
+    }
+    if (particles->parseSwitches(interp, objc - 4, objv + 4) != TCL_OK) {
+        flow->deleteParticles(particlesName);
+        return TCL_ERROR;
+    }
+    particles->configure();
+    Flow::updatePending = true;
+    NanoVis::eventuallyRedraw();
+    Tcl_SetObjResult(interp, objv[3]);
+    return TCL_OK;
+}
+
+static int
+FlowParticlesConfigureOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                         Tcl_Obj *const *objv)
+{
+    Flow *flow = (Flow *)clientData;
+    const char *particlesName = Tcl_GetString(objv[3]);
+    FlowParticles *particles = flow->getParticles(particlesName);
+    if (particles == NULL) {
+        Tcl_AppendResult(interp, "Flow particle injection plane \"",
+                         particlesName, "\" not found",
+                         (char*)NULL);
+        return TCL_ERROR;
+    }
+    if (particles->parseSwitches(interp, objc - 4, objv + 4) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (particles->configure()) {
+        Flow::updatePending = true;
+    }
+    NanoVis::eventuallyRedraw();
+    return TCL_OK;
+}
+
+static int
+FlowParticlesDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                      Tcl_Obj *const *objv)
+{
+    Flow *flow = (Flow *)clientData;
+    for (int i = 3; i < objc; i++) {
+        flow->deleteParticles(Tcl_GetString(objv[i]));
+    }
+    NanoVis::eventuallyRedraw();
+    return TCL_OK;
+}
+
+static int
+FlowParticlesNamesOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                     Tcl_Obj *const *objv)
+{
+    Flow *flow = (Flow *)clientData;
+    Tcl_Obj *listObjPtr;
+    listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL);
+    std::vector<std::string> names;
+    flow->getParticlesNames(names);
+    for (std::vector<std::string>::iterator itr = names.begin();
+         itr != names.end(); ++itr) {
+        Tcl_Obj *objPtr = Tcl_NewStringObj(itr->c_str(), -1);
+        Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
+    }
+    Tcl_SetObjResult(interp, listObjPtr);
+    return TCL_OK;
+}
+
+static CmdSpec flowParticlesOps[] = {
+    {"add",        1, FlowParticlesAddOp,        4, 0, "name ?switches?",},
+    {"configure",  1, FlowParticlesConfigureOp,  4, 0, "name ?switches?",},
+    {"delete",     1, FlowParticlesDeleteOp,     4, 0, "name ?name...?"},
+    {"names",      1, FlowParticlesNamesOp,      3, 3, ""},
+};
+
+static int nFlowParticlesOps = NumCmdSpecs(flowParticlesOps);
+
+/**
+ * \brief This procedure is invoked to process commands on behalf of the flow
+ * object.
+ * 
+ * Side effects: See the user documentation.
+ * 
+ * $flow particles oper $name 
+ *
+ * \return A standard Tcl result.
+ */
+static int
+FlowParticlesOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+    proc = GetOpFromObj(interp, nFlowParticlesOps, flowParticlesOps, 
+                        CMDSPEC_ARG2, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    Flow *flow = (Flow *)clientData;
+    Tcl_Preserve(flow);
+    int result;
+    result = (*proc) (clientData, interp, objc, objv);
+    Tcl_Release(flow);
+    return result;
+}
+
+static int
+FlowBoxAddOp(ClientData clientData, Tcl_Interp *interp, int objc,
+             Tcl_Obj *const *objv)
+{
+    Flow *flow = (Flow *)clientData;
+    const char *boxName = Tcl_GetString(objv[3]);
+    FlowBox *box = flow->createBox(boxName);
+    if (box == NULL) {
+        Tcl_AppendResult(interp, "Flow box \"", boxName, 
+                         "\" already exists or could not be created",
+                         (char*)NULL);
+        return TCL_ERROR;
+    }
+    if (box->parseSwitches(interp, objc - 4, objv + 4) != TCL_OK) {
+        flow->deleteBox(boxName);
+        return TCL_ERROR;
+    }
+    NanoVis::eventuallyRedraw();
+    Tcl_SetObjResult(interp, objv[3]);
+    return TCL_OK;
+}
+
+static int
+FlowBoxConfigureOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                   Tcl_Obj *const *objv)
+{
+    Flow *flow = (Flow *)clientData;
+    const char *boxName = Tcl_GetString(objv[3]);
+    FlowBox *box = flow->getBox(boxName);
+    if (box == NULL) {
+        Tcl_AppendResult(interp, "Flow box \"", boxName, "\" not found",
+                         (char*)NULL);
+        return TCL_ERROR;
+    }
+    if (box->parseSwitches(interp, objc - 4, objv + 4) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    NanoVis::eventuallyRedraw();
+    return TCL_OK;
+}
+
+static int
+FlowBoxDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc,
+                Tcl_Obj *const *objv)
+{
+    Flow *flow = (Flow *)clientData;
+    for (int i = 3; i < objc; i++) {
+        flow->deleteBox(Tcl_GetString(objv[i]));
+    }
+    NanoVis::eventuallyRedraw();
+    return TCL_OK;
+}
+
+static int
+FlowBoxNamesOp(ClientData clientData, Tcl_Interp *interp, int objc,
+               Tcl_Obj *const *objv)
+{
+    Flow *flow = (Flow *)clientData;
+    Tcl_Obj *listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL);
+    std::vector<std::string> names;
+    flow->getBoxNames(names);
+    for (std::vector<std::string>::iterator itr = names.begin();
+         itr != names.end(); ++itr) {
+        Tcl_Obj *objPtr = Tcl_NewStringObj(itr->c_str(), -1);
+        Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
+    }
+    Tcl_SetObjResult(interp, listObjPtr);
+    return TCL_OK;
+}
+
+static CmdSpec flowBoxOps[] = {
+    {"add",        1, FlowBoxAddOp,        4, 0, "name ?switches?",},
+    {"configure",  1, FlowBoxConfigureOp,  4, 0, "name ?switches?",},
+    {"delete",     1, FlowBoxDeleteOp,     4, 0, "name ?name...?"},
+    {"names",      1, FlowBoxNamesOp,      3, 3, ""},
+};
+
+static int nFlowBoxOps = NumCmdSpecs(flowBoxOps);
+
+/**
+ * \brief This procedure is invoked to process commands on behalf of the flow
+ *         object.
+ *
+ * Side effects:  See the user documentation.
+ *
+ * \return A standard Tcl result.
+ */
+static int
+FlowBoxOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+          Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+    proc = GetOpFromObj(interp, nFlowBoxOps, flowBoxOps, 
+                        CMDSPEC_ARG2, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    Flow *flow = (Flow *)clientData;
+    Tcl_Preserve(flow);
+    int result;
+    result = (*proc) (clientData, interp, objc, objv);
+    Tcl_Release(flow);
+    return result;
+}
+
+/*
+ * CLIENT COMMAND:
+ *   $flow legend <width> <height>
+ *
+ * Clients use this to generate a legend image for the specified
+ * transfer function.  The legend image is a color gradient from 0
+ * to one, drawn in the given transfer function.  The resulting image
+ * is returned in the size <width> x <height>.
+ */
+static int
+FlowLegendOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+             Tcl_Obj *const *objv)
+{
+    Flow *flow = (Flow *)clientData;
+    
+    const char *string = Tcl_GetString(objv[1]);
+    TransferFunction *tf;
+    tf = flow->getTransferFunction();
+    if (tf == NULL) {
+        Tcl_AppendResult(interp, "unknown transfer function \"", string, "\"",
+                         (char*)NULL);
+        return TCL_ERROR;
+    }
+    const char *label;
+    label = Tcl_GetString(objv[0]);
+    int w, h;
+    if ((Tcl_GetIntFromObj(interp, objv[2], &w) != TCL_OK) ||
+        (Tcl_GetIntFromObj(interp, objv[3], &h) != TCL_OK)) {
+        return TCL_ERROR;
+    }
+    if (Flow::updatePending) {
+        NanoVis::setFlowRanges();
+    }
+    NanoVis::renderLegend(tf, NanoVis::magMin, NanoVis::magMax, w, h, label);
+    return TCL_OK;
+}
+
+static CmdSpec flowInstOps[] = {
+    {"box",         1, FlowBoxOp,        2, 0, "oper ?args?"},
+    {"configure",   1, FlowConfigureOp,  2, 0, "?switches?"},
+    {"data",        1, FlowDataOp,       2, 0, "oper ?args?"},
+    {"legend",      1, FlowLegendOp,     4, 4, "w h"},
+    {"particles",   1, FlowParticlesOp,  2, 0, "oper ?args?"}
+};
+static int nFlowInstOps = NumCmdSpecs(flowInstOps);
+
+/**
+ * \brief This procedure is invoked to process commands on behalf of the flow
+ * object.
+ *
+ * Side effects: See the user documentation.
+ *
+ * \return A standard Tcl result.
+ */
+int
+nv::FlowInstObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+                   Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+    proc = GetOpFromObj(interp, nFlowInstOps, flowInstOps, 
+                        CMDSPEC_ARG1, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    assert(CheckGL(AT));
+    Flow *flow = (Flow *)clientData;
+    Tcl_Preserve(flow);
+    int result = (*proc) (clientData, interp, objc, objv);
+    Tcl_Release(flow);
+    return result;
+}
+
+/**
+ * \brief Deletes the command associated with the flow
+ *
+ * This is called only when the command associated with the flow is destroyed.
+ */
+void
+nv::FlowInstDeleteProc(ClientData clientData)
+{
+    Flow *flow = (Flow *)clientData;
+    NanoVis::deleteFlow(flow->name());
+}
+
+static int
+FlowAddOp(ClientData clientData, Tcl_Interp *interp, int objc,
+          Tcl_Obj *const *objv)
+{
+    const char *name = Tcl_GetString(objv[2]);
+    Tcl_CmdInfo cmdInfo;
+    if (Tcl_GetCommandInfo(interp, name, &cmdInfo)) {
+        Tcl_AppendResult(interp, "an another command \"", name, 
+                         "\" already exists.", (char *)NULL);
+        return TCL_ERROR;
+    }
+    Flow *flow = NanoVis::createFlow(interp, name);
+    if (flow == NULL) {
+        Tcl_AppendResult(interp, "Flow \"", name, "\" already exists",
+                         (char*)NULL);
+        return TCL_ERROR;
+    }
+    if (flow->parseSwitches(interp, objc - 3, objv + 3) != TCL_OK) {
+        Tcl_DeleteCommand(interp, flow->name());
+        return TCL_ERROR;
+    }
+    Tcl_SetObjResult(interp, objv[2]);
+    NanoVis::eventuallyRedraw();
+    return TCL_OK;
+}
+
+static int
+FlowDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc,
+             Tcl_Obj *const *objv)
+{
+    for (int i = 2; i < objc; i++) {
+        Flow *flow = NanoVis::getFlow(Tcl_GetString(objv[i]));
+        if (flow != NULL) {
+            Tcl_DeleteCommandFromToken(interp, flow->getCommandToken());
+        }
+    }
+    Flow::updatePending = true;
+    NanoVis::eventuallyRedraw();
+    return TCL_OK;
+}
+
+static int
+FlowExistsOp(ClientData clientData, Tcl_Interp *interp, int objc,
+             Tcl_Obj *const *objv)
+{
+    bool value = false;
+    Flow *flow = NanoVis::getFlow(Tcl_GetString(objv[2]));
+    if (flow != NULL) {
+        value = true;
+    }
+    Tcl_SetBooleanObj(Tcl_GetObjResult(interp), (int)value);
+    return TCL_OK;
+}
+
+/**
+ * \brief flow goto number
+ */
+static int
+FlowGotoOp(ClientData clientData, Tcl_Interp *interp, int objc,
+           Tcl_Obj *const *objv)
+{
+    int nSteps;
+    if (Tcl_GetIntFromObj(interp, objv[2], &nSteps) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if ((nSteps < 0) || (nSteps > SHRT_MAX)) {
+        Tcl_AppendResult(interp, "flow goto: bad # of steps \"",
+                         Tcl_GetString(objv[2]), "\"", (char *)NULL);
+        return TCL_ERROR;
+    }
+    NanoVis::resetFlows();
+    if (Flow::updatePending) {
+        NanoVis::setFlowRanges();
+    }
+    for (int i = 0; i < nSteps; i++) {
+        NanoVis::licRenderer->convolve();
+        NanoVis::advectFlows();
+    }
+    NanoVis::eventuallyRedraw();
+    return TCL_OK;
+}
+
+static int
+FlowNamesOp(ClientData clientData, Tcl_Interp *interp, int objc,
+            Tcl_Obj *const *objv)
+{
+    Tcl_Obj *listObjPtr;
+    listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL);
+    for (NanoVis::FlowHashmap::iterator itr = NanoVis::flowTable.begin();
+         itr != NanoVis::flowTable.end(); ++itr) {
+        Flow *flow = itr->second;
+        Tcl_Obj *objPtr = Tcl_NewStringObj(flow->name(), -1);
+        Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
+    }
+    Tcl_SetObjResult(interp, listObjPtr);
+    return TCL_OK;
+}
+
+static int
+FlowNextOp(ClientData clientData, Tcl_Interp *interp, int objc,
+           Tcl_Obj *const *objv)
+{
+    assert(NanoVis::licRenderer != NULL);
+    if (Flow::updatePending) {
+        NanoVis::setFlowRanges();
+    }
+    NanoVis::licRenderer->convolve();
+    NanoVis::advectFlows();
+    NanoVis::eventuallyRedraw();
+    return TCL_OK;
+}
+
+static int
+FlowResetOp(ClientData clientData, Tcl_Interp *interp, int objc,
+            Tcl_Obj *const *objv)
+{
+    NanoVis::resetFlows();
+    return TCL_OK;
+}
+
+#if defined(HAVE_FFMPEG) || defined(HAVE_AVCONV)
+
+/**
+ * \brief Convert a Tcl_Obj representing the video format into its
+ * integer id.
+ *
+ * \param clientData Not used
+ * \param interp Interpreter to send results back to
+ * \param switchName Not used
+ * \param objPtr String representation
+ * \param record Structure record
+ * \param offset Not used
+ * \param flags Not used
+ *
+ * \return The return value is a standard Tcl result.
+ */
+static int
+VideoFormatSwitchProc(ClientData clientData, Tcl_Interp *interp,
+                      const char *switchName, Tcl_Obj *objPtr,
+                      char *record, int offset, int flags)
+{
+    Tcl_Obj **formatObjPtr = (Tcl_Obj **)(record + offset);
+    Tcl_Obj *fmtObjPtr;
+    const char *string;
+    char c; 
+    int length;
+
+    string = Tcl_GetStringFromObj(objPtr, &length);
+    c = string[0];
+    if ((c == 'm') && (length > 1) && 
+        (strncmp(string, "mpeg", length) == 0)) {
+        fmtObjPtr =  Tcl_NewStringObj("mpeg1video", 10);
+    } else if ((c == 't') && (strncmp(string, "theora", length) == 0)) {
+        fmtObjPtr =  Tcl_NewStringObj("theora", 6);
+    } else if ((c == 'm') && (length > 1) &&
+               (strncmp(string, "mov", length) == 0)) {
+        fmtObjPtr =  Tcl_NewStringObj("mov", 3);
+    } else {
+        Tcl_AppendResult(interp, "bad video format \"", string,
+                         "\": should be mpeg, theora, or mov", (char*)NULL);
+        return TCL_ERROR;
+    }
+    if (*formatObjPtr != NULL) {
+        Tcl_DecrRefCount(*formatObjPtr);
+    }
+    Tcl_IncrRefCount(fmtObjPtr);
+    *formatObjPtr = fmtObjPtr;
+    return TCL_OK;
+}
+
+struct FlowVideoSwitches {
+    float frameRate;         /**< Frame rate */
+    int bitRate;             /**< Video bitrate */
+    int width, height;       /**< Dimensions of video frame. */
+    int numFrames;
+    Tcl_Obj *formatObjPtr;
+};
+
+static SwitchParseProc VideoFormatSwitchProc;
+static SwitchCustom videoFormatSwitch = {
+    VideoFormatSwitchProc, NULL, 0,
+};
+
+static SwitchSpec flowVideoSwitches[] = {
+    {SWITCH_INT, "-bitrate", "value",
+     offsetof(FlowVideoSwitches, bitRate), 0},
+    {SWITCH_CUSTOM, "-format", "string",
+     offsetof(FlowVideoSwitches, formatObjPtr), 0, 0, &videoFormatSwitch},
+    {SWITCH_FLOAT, "-framerate", "value",
+     offsetof(FlowVideoSwitches, frameRate), 0},
+    {SWITCH_INT, "-height", "integer",
+     offsetof(FlowVideoSwitches, height), 0},
+    {SWITCH_INT, "-numframes", "count",
+     offsetof(FlowVideoSwitches, numFrames), 0},
+    {SWITCH_INT, "-width", "integer",
+     offsetof(FlowVideoSwitches, width), 0},
+    {SWITCH_END}
+};
+
+static bool
+ppmWriteToFile(const char *path, const unsigned char *imgData,
+               int width, int height)
+{
+    /* Open the named file for writing. */
+    int fdOut = creat(path, 0600);
+    if (fdOut < 0) {
+        ERROR("can't open temporary image file \"%s\": %s", path, strerror(errno));
+        return false;
+    }
+    // Generate the PPM binary file header
+    char header[200];
+#define PPM_MAXVAL 255
+    sprintf(header, "P6 %d %d %d\n", width, height, 
+        PPM_MAXVAL);
+
+    size_t header_length = strlen(header);
+    size_t wordsPerRow = (width * 24 + 31) / 32;
+    size_t bytesPerRow = wordsPerRow * 4;
+    size_t rowLength = width * 3;
+    size_t numRecords = height + 1;
+
+    struct iovec *iov;
+    iov = (struct iovec *)malloc(sizeof(struct iovec) * numRecords);
+
+    // Add the PPM image header.
+    iov[0].iov_base = header;
+    iov[0].iov_len = header_length;
+
+    // Now add the image data, reversing the order of the rows.
+    int y;
+    unsigned char *srcRowPtr = const_cast<unsigned char *>(imgData);
+    /* Reversing the pointers for the image rows.  PPM is top-to-bottom. */
+    for (y = height; y >= 1; y--) {
+        iov[y].iov_base = srcRowPtr;
+        iov[y].iov_len = rowLength;
+        srcRowPtr += bytesPerRow;
+    }
+    if (writev(fdOut, iov, numRecords) < 0) {
+        ERROR("writing image to \"%s\" failed: %s", path, strerror(errno));
+        free(iov);
+        close(fdOut);
+        return false;
+    }
+    close(fdOut);
+    free(iov);
+    return true;
+}
+
+static bool
+MakeImageFiles(char *tmpFileName,
+               int width, int height, int numFrames,
+               bool *cancelPtr)
+{
+    struct pollfd pollResults;
+    pollResults.fd = g_fdIn;
+    pollResults.events = POLLIN;
+#define PENDING_TIMEOUT          10  /* milliseconds. */
+    int timeout = PENDING_TIMEOUT;
+
+    int oldWidth, oldHeight;
+    oldWidth = NanoVis::winWidth;
+    oldHeight = NanoVis::winHeight;
+
+    if (width != oldWidth ||
+        height != oldHeight) {
+        // Resize to the requested size.
+        NanoVis::resizeOffscreenBuffer(width, height);
+    }
+    NanoVis::resetFlows();
+    *cancelPtr = false;
+    bool result = true;
+    size_t length = strlen(tmpFileName);
+    for (int i = 1; i <= numFrames; i++) {
+        if (((i & 0xF) == 0) && (poll(&pollResults, 1, timeout) > 0)) {
+            /* If there's another command on stdin, that means the client is
+             * trying to cancel this operation. */
+            *cancelPtr = true;
+            break;
+        }
+        NanoVis::licRenderer->convolve();
+        NanoVis::advectFlows();
+
+        int fboOrig;
+        glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &fboOrig);
+
+        NanoVis::bindOffscreenBuffer();
+        NanoVis::render();
+        NanoVis::readScreen();
+
+        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboOrig);
+
+        sprintf(tmpFileName + length, "/image%d.ppm", i);
+        result = ppmWriteToFile(tmpFileName, NanoVis::screenBuffer,
+                                width, height);
+        if (!result) {
+            break;
+        }
+    }
+    if (width != oldWidth || 
+        height != oldHeight) {
+        NanoVis::resizeOffscreenBuffer(oldWidth, oldHeight);
+    }
+    tmpFileName[length] = '\0';
+    NanoVis::resetFlows();
+    return result;
+}
+
+static int
+MakeMovie(Tcl_Interp *interp, char *tmpFileName, const char *token,
+          FlowVideoSwitches *switchesPtr)
+{
+    char cmd[BUFSIZ];
+#ifdef HAVE_AVCONV
+    /* Generate the movie from the frame images by exec-ing avconv */
+    /* The avconv command is
+     *   avconv -f image2 -i /var/tmp/xxxxx/image%d.ppm                 \
+     *      -f outformat -b bitrate -r framerate /var/tmp/xxxxx/movie.mpeg 
+     */
+#ifndef AVCONV
+#  define AVCONV "/usr/bin/avconv"
+#endif
+    sprintf(cmd, "%s -f image2 -i %s/image%%d.ppm -f %s -b %d -r %f -",
+            AVCONV, tmpFileName, Tcl_GetString(switchesPtr->formatObjPtr), 
+            switchesPtr->bitRate, switchesPtr->frameRate);
+#else
+    /* Generate the movie from the frame images by exec-ing ffmpeg */
+    /* The ffmpeg command is
+     *   ffmpeg -f image2 -i /var/tmp/xxxxx/image%d.ppm                 \
+     *      -b bitrate -f framerate /var/tmp/xxxxx/movie.mpeg 
+     */
+#ifndef FFMPEG 
+#  define FFMPEG "/usr/bin/ffmpeg"
+#endif
+    sprintf(cmd, "%s -f image2 -i %s/image%%d.ppm -f %s -b %d -r %f -",
+            FFMPEG, tmpFileName, Tcl_GetString(switchesPtr->formatObjPtr), 
+            switchesPtr->bitRate, switchesPtr->frameRate);
+#endif
+    TRACE("Enter: %s", cmd);
+    FILE *f = popen(cmd, "r");
+    if (f == NULL) {
+        Tcl_AppendResult(interp, "can't run ffmpeg: ", 
+                         Tcl_PosixError(interp), (char *)NULL);
+        return TCL_ERROR;
+    }
+    Rappture::Buffer data;
+    size_t total = 0;
+    for (;;) {
+        char buffer[BUFSIZ]; 
+        
+        ssize_t numRead = fread(buffer, sizeof(unsigned char), BUFSIZ, f);
+        total += numRead;
+        if (numRead == 0) {             // EOF
+            break;
+        }
+        if (numRead < 0) {              // Error
+            ERROR("Can't read movie data: %s",
+                  Tcl_PosixError(interp));
+            Tcl_AppendResult(interp, "can't read movie data: ", 
+                Tcl_PosixError(interp), (char *)NULL);
+            return TCL_ERROR;
+        }
+        if (!data.append(buffer, numRead)) {
+            ERROR("Can't append movie data to buffer %d bytes",
+                  numRead);
+            Tcl_AppendResult(interp, "can't append movie data to buffer",
+                             (char *)NULL);
+            return TCL_ERROR;
+        }
+    }
+    if (data.size() == 0) {
+        ERROR("ffmpeg returned 0 bytes");
+    }
+    // Send zero length to client so it can deal with error
+    sprintf(cmd,"nv>image -type movie -token \"%s\" -bytes %lu\n", 
+            token, (unsigned long)data.size());
+    nv::sendDataToClient(cmd, data.bytes(), data.size());
+    return TCL_OK;
+}
+
+static int
+FlowVideoOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+            Tcl_Obj *const *objv)
+{
+    FlowVideoSwitches switches;
+    const char *token;
+
+    token = Tcl_GetString(objv[2]);
+    switches.frameRate = 25.0f;                // Default frame rate 25 fps
+    switches.bitRate = 6000000;                // Default video bit rate.
+    switches.width = NanoVis::winWidth;
+    switches.height = NanoVis::winHeight;
+    switches.numFrames = 100;
+    switches.formatObjPtr = Tcl_NewStringObj("mpeg1video", 10);
+    Tcl_IncrRefCount(switches.formatObjPtr);
+    if (ParseSwitches(interp, flowVideoSwitches, 
+                objc - 3, objv + 3, &switches, SWITCH_DEFAULTS) < 0) {
+        return TCL_ERROR;
+    }
+    if ((switches.width < 0) || (switches.width > SHRT_MAX) || 
+        (switches.height < 0) || (switches.height > SHRT_MAX)) {
+        Tcl_AppendResult(interp, "bad dimensions for video", (char *)NULL);
+        return TCL_ERROR;
+    }
+    if ((switches.frameRate < 0.0f) || (switches.frameRate > 30.0f)) {
+        Tcl_AppendResult(interp, "bad frame rate.", (char *)NULL);
+        return TCL_ERROR;
+    }
+    if (switches.bitRate < 0) {
+        Tcl_AppendResult(interp, "bad bit rate.", (char *)NULL);
+        return TCL_ERROR;
+    }
+    if (NanoVis::licRenderer == NULL) {
+        Tcl_AppendResult(interp, "no lic renderer.", (char *)NULL);
+        return TCL_ERROR;
+    }
+    TRACE("FLOW started");
+
+    char *tmpFileName;
+    char nameTemplate[200];
+    strcpy(nameTemplate,"/var/tmp/flowXXXXXX");
+    tmpFileName = mkdtemp(nameTemplate);
+    int result = TCL_OK;
+    if (tmpFileName == NULL) {
+        Tcl_AppendResult(interp, "can't create temporary directory \"",
+                         nameTemplate, "\" for frame image files: ", 
+                         Tcl_PosixError(interp), (char *)NULL);
+        return TCL_ERROR;
+    }
+    size_t length = strlen(tmpFileName);
+    bool canceled = false;
+    if (MakeImageFiles(tmpFileName,
+                       switches.width, switches.height, switches.numFrames,
+                       &canceled)) {
+        result = TCL_OK;
+    } else {
+        result = TCL_ERROR;
+    }
+    if ((result == TCL_OK) && (!canceled)) {
+        result = MakeMovie(interp, tmpFileName, token, &switches);
+    }
+    for (int i = 1; i <= switches.numFrames; i++) {
+        sprintf(tmpFileName + length, "/image%d.ppm", i);
+        unlink(tmpFileName);
+    }
+    tmpFileName[length] = '\0';
+    rmdir(tmpFileName);
+    FreeSwitches(flowVideoSwitches, &switches, 0);
+    return result;
+}
+#else
+/**
+ *  Not implemented 
+ */
+static int
+FlowVideoOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+            Tcl_Obj *const *objv)
+{
+    return TCL_OK;
+}
+#endif /* HAVE_FFMPEG */
+
+static CmdSpec flowCmdOps[] = {
+    {"add",      1, FlowAddOp,     3, 0, "name ?option value...?",},
+    {"delete",   1, FlowDeleteOp,  3, 0, "name ?name...?",},
+    {"exists",   1, FlowExistsOp,  3, 3, "name",},
+    {"goto",     1, FlowGotoOp,    3, 3, "nSteps",},
+    {"names",    1, FlowNamesOp,   2, 2, "",},
+    {"next",     2, FlowNextOp,    2, 2, "",},
+    {"reset",    1, FlowResetOp,   2, 2, "",},
+    {"video",    1, FlowVideoOp,   3, 0, "token ?switches...?",},
+};
+static int nFlowCmdOps = NumCmdSpecs(flowCmdOps);
+
+static int
+FlowCmdProc(ClientData clientData, Tcl_Interp *interp, int objc,
+            Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = GetOpFromObj(interp, nFlowCmdOps, flowCmdOps, 
+                        CMDSPEC_ARG1, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+/**
+ *\brief This procedure is invoked to initialize the "flow" command.
+ *
+ * Side effects:
+ *    Creates the new command and adds a new entry into a global Tcl
+ *    associative array.
+ */
+void
+nv::FlowCmdInitProc(Tcl_Interp *interp, ClientData clientData)
+{
+    Tcl_CreateObjCommand(interp, "flow", FlowCmdProc, clientData, NULL);
+}
Index: /nanovis/tags/1.1.4/FlowCmd.h
===================================================================
--- /nanovis/tags/1.1.4/FlowCmd.h	(revision 4930)
+++ /nanovis/tags/1.1.4/FlowCmd.h	(revision 4930)
@@ -0,0 +1,24 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors:
+ *   Wei Qiao <qiaow@purdue.edu>
+ *   Insoo Woo <iwoo@purdue.edu>
+ *   Michael McLennan <mmclennan@purdue.edu>
+ */
+#ifndef NV_FLOWCMD_H
+#define NV_FLOWCMD_H
+
+#include <tcl.h>
+
+namespace nv {
+
+extern void FlowCmdInitProc(Tcl_Interp *interp, ClientData clientData);
+
+extern Tcl_ObjCmdProc FlowInstObjCmd;
+extern Tcl_CmdDeleteProc FlowInstDeleteProc;
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/FlowParticles.cpp
===================================================================
--- /nanovis/tags/1.1.4/FlowParticles.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/FlowParticles.cpp	(revision 4930)
@@ -0,0 +1,81 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors:
+ *   Wei Qiao <qiaow@purdue.edu>
+ *   Insoo Woo <iwoo@purdue.edu>
+ *   George A. Howlett <gah@purdue.edu>
+ *   Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#include <assert.h>
+
+#include <vrmath/Color4f.h>
+
+#include "nanovis.h"        // For NMESH
+#include "FlowParticles.h"
+#include "Flow.h"
+#include "Trace.h"
+
+using namespace nv;
+using namespace vrmath;
+
+FlowParticles::FlowParticles(const char *name) :
+    _name(name),
+    _renderer(new ParticleRenderer(NMESH, NMESH))
+{
+    _sv.position.value = 0.0f;
+    _sv.position.flags = RELPOS;
+    _sv.position.axis = AXIS_Z;
+    _sv.color.r = _sv.color.g = _sv.color.b = _sv.color.a = 1.0f;
+    _sv.isHidden = false;
+    _sv.particleSize = 1.2;
+}
+
+FlowParticles::~FlowParticles() 
+{
+    TRACE("Deleting renderer");
+    if (_renderer != NULL) {
+        delete _renderer;
+    }
+    TRACE("Freeing switches");
+    FreeSwitches(_switches, &_sv, 0);
+}
+
+void
+FlowParticles::render() 
+{
+    TRACE("Particles '%s' axis: %d pos: %g rel pos: %g",
+          _name.c_str(), _sv.position.axis, _sv.position.value,
+          Flow::getRelativePosition(&_sv.position));
+
+    _renderer->setSlicePosition(Flow::getRelativePosition(&_sv.position));
+    _renderer->setSliceAxis(_sv.position.axis);
+    assert(_renderer->active());
+    _renderer->render();
+}
+
+bool
+FlowParticles::configure() 
+{
+    bool needReset = false;
+
+    _renderer->setColor(Color4f(_sv.color.r,
+                                _sv.color.g,
+                                _sv.color.b, 
+                                _sv.color.a));
+    _renderer->particleSize(_sv.particleSize);
+    if (_renderer->getSliceAxis() != _sv.position.axis) {
+        needReset = true;
+        _renderer->setSliceAxis(_sv.position.axis);
+    }
+    float pos = Flow::getRelativePosition(&_sv.position);
+    if (_renderer->getSlicePosition() != pos) {
+        needReset = true;
+        _renderer->setSlicePosition(pos);
+    }
+    _renderer->active(!_sv.isHidden);
+
+    return needReset;
+}
Index: /nanovis/tags/1.1.4/FlowParticles.h
===================================================================
--- /nanovis/tags/1.1.4/FlowParticles.h	(revision 4930)
+++ /nanovis/tags/1.1.4/FlowParticles.h	(revision 4930)
@@ -0,0 +1,108 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors:
+ *   Wei Qiao <qiaow@purdue.edu>
+ *   Insoo Woo <iwoo@purdue.edu>
+ *   George A. Howlett <gah@purdue.edu>
+ *   Leif Delgass <ldelgass@purdue.edu>
+ */
+#ifndef NV_FLOWPARTICLES_H
+#define NV_FLOWPARTICLES_H
+
+#include <cassert>
+#include <string>
+
+#include <tcl.h>
+
+#include <vrmath/Vector3f.h>
+
+#include "FlowTypes.h"
+#include "Switch.h"
+#include "ParticleRenderer.h"
+#include "Volume.h"
+
+namespace nv {
+
+struct FlowParticlesValues {
+    FlowPosition position;   ///< Position on axis of particle plane
+    FlowColor color;         ///< Color of particles
+    int isHidden;            ///< Is particle injection plane active
+    float particleSize;      ///< Size of the particles
+};
+
+class FlowParticles
+{
+public:
+    FlowParticles(const char *name);
+
+    ~FlowParticles();
+
+    const char *name() const
+    {
+        return _name.c_str();
+    }
+
+    bool visible() const
+    {
+        return !_sv.isHidden;
+    }
+
+    int parseSwitches(Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
+    {
+        if (nv::ParseSwitches(interp, _switches, objc, objv, &_sv, 
+                              SWITCH_DEFAULTS) < 0) {
+            return TCL_ERROR;
+        }
+        return TCL_OK;
+    }
+
+    void advect()
+    {
+        assert(_renderer->active());
+        _renderer->advect();
+    }
+
+    void render();
+
+    void reset()
+    {
+        _renderer->reset();
+    }
+
+    void initialize()
+    {
+        _renderer->initialize();
+    }
+
+    void setVectorField(Volume *volume, const vrmath::Vector3f& location,
+                        float scaleX, float scaleY, float scaleZ,
+                        float max)
+    {
+        _renderer->
+            setVectorField(volume->textureID(),
+                           location,
+                           scaleX,
+                           scaleY,
+                           scaleZ,
+                           max);
+    }
+
+    bool configure();
+
+private:
+    /**
+     * Name of particle injection plane. Actual character string is
+     * stored in hash table.
+     */
+    std::string _name;
+    nv::ParticleRenderer *_renderer;        ///< Particle renderer
+    FlowParticlesValues _sv;
+
+    static SwitchSpec _switches[];
+};
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/FlowTypes.h
===================================================================
--- /nanovis/tags/1.1.4/FlowTypes.h	(revision 4930)
+++ /nanovis/tags/1.1.4/FlowTypes.h	(revision 4930)
@@ -0,0 +1,42 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors:
+ *   Wei Qiao <qiaow@purdue.edu>
+ *   Insoo Woo <iwoo@purdue.edu>
+ *   George A. Howlett <gah@purdue.edu>
+ *   Leif Delgass <ldelgass@purdue.edu>
+ */
+#ifndef NV_FLOWTYPES_H
+#define NV_FLOWTYPES_H
+
+namespace nv {
+
+enum FlowSliceAxis {
+    AXIS_X,
+    AXIS_Y,
+    AXIS_Z
+};
+
+struct FlowColor {
+    float r, g, b, a;
+};
+
+struct FlowPoint {
+    float x, y, z;
+};
+
+struct FlowPosition {
+    float value;
+    unsigned int flags;
+    FlowSliceAxis axis;
+};
+
+// FlowPosition flag values
+#define RELPOS 0
+#define ABSPOS 1
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/GradientFilter.cpp
===================================================================
--- /nanovis/tags/1.1.4/GradientFilter.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/GradientFilter.cpp	(revision 4930)
@@ -0,0 +1,534 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#include <stdlib.h>
+#include <float.h>
+#include <math.h>
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "Trace.h"
+#include "GradientFilter.h"
+
+using namespace nv;
+
+#ifndef SQR
+#define SQR(a) ((a) * (a))
+#endif
+
+static int g_numOfSlices[3] = { 256, 256, 256 };
+static void *g_volData = NULL;
+static float g_sliceDists[3];
+
+#define SOBEL               1
+#define GRAD_FILTER_SIZE    5
+#define SIGMA2              5.0
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define EPS 1e-6f
+
+#ifdef notused
+static char *
+getFloatGradientsFilename()
+{
+    char floatExt[] = "_float";
+    char *filename;
+    char extension[] = ".grd";
+
+    if (! (filename = (char *)malloc(strlen("base") +
+                                     strlen(floatExt) +
+                                     strlen(extension) + 1))) {
+        ERROR("not enough memory for filename");
+        exit(1);
+    }
+
+    strcpy(filename, "base");
+    strcat(filename, floatExt);
+    strcat(filename, extension);
+
+    return filename;
+}
+
+static void 
+saveFloatGradients(float *gradients, int *sizes)
+{
+    char *filename;
+    FILE *fp;
+
+    filename = getFloatGradientsFilename();
+    if (! (fp = fopen(filename, "wb"))) {
+        perror("cannot open gradients file for writing");
+        exit(1);
+    }
+    if (fwrite(gradients, 3 * sizes[0] * sizes[1] * sizes[2] * sizeof(float),
+               1, fp) != 1) {
+        ERROR("writing float gradients failed");
+        exit(1);
+    }
+    fclose(fp);
+}
+
+static void
+saveGradients(void *gradients, int *sizes, DataType dataType)
+{
+    char *filename;
+    int size;
+    FILE *fp;
+
+    filename = getGradientsFilename();
+    if (! (fp = fopen(filename, "wb"))) {
+        perror("cannot open gradients file for writing");
+        exit(1);
+    }
+
+    size = 3 * sizes[0] * sizes[1] * sizes[2]
+           * getDataTypeSize(dataType);
+
+    if (fwrite(gradients, size, 1, fp) != 1) {
+        ERROR("writing gradients failed");
+        exit(1);
+    }
+
+    fclose(fp);
+}
+#endif
+
+static unsigned char
+getVoxel8(int x, int y, int z)
+{
+    return ((unsigned char*)g_volData)[z * g_numOfSlices[0] * g_numOfSlices[1] +
+                                       y * g_numOfSlices[0] +
+                                       x];
+}
+
+static unsigned short
+getVoxel16(int x, int y, int z)
+{
+    return ((unsigned short*)g_volData)[z * g_numOfSlices[0] * g_numOfSlices[1] +
+                                        y * g_numOfSlices[0] +
+                                        x];
+}
+
+static float
+getVoxelFloat(int x, int y, int z)
+{
+    return ((float*)g_volData)[z * g_numOfSlices[0] * g_numOfSlices[1] +
+                               y * g_numOfSlices[0] +
+                               x];
+}
+
+static float
+getVoxel(int x, int y, int z, nv::DataType dataType)
+{
+    switch (dataType) {
+    case nv::DATRAW_UCHAR:
+        return (float)getVoxel8(x, y, z);
+        break;
+    case nv::DATRAW_USHORT:
+        return (float)getVoxel16(x, y, z);
+        break;
+    case nv::DATRAW_FLOAT:
+        return (float)getVoxelFloat(x, y, z);
+        break;
+    default:
+        ERROR("Unsupported data type");
+        exit(1);
+    }
+    return 0.0;
+}
+
+void
+nv::computeGradients(float *gradients, void *volData, int *sizes, 
+                     float *spacing, DataType dataType)
+{
+    g_volData = volData;
+    g_numOfSlices[0] = sizes[0];
+    g_numOfSlices[1] = sizes[1];
+    g_numOfSlices[2] = sizes[2];
+
+    g_sliceDists[0] = spacing[0];
+    g_sliceDists[1] = spacing[1];
+    g_sliceDists[2] = spacing[2];
+
+    int i, j, k, dir, idz, idy, idx;
+    float *gp;
+
+    static int weights[][3][3][3] = {
+        {{{-1, -3, -1},
+          {-3, -6, -3},
+          {-1, -3, -1}},
+         {{ 0,  0,  0},
+          { 0,  0,  0},
+          { 0,  0,  0}},
+         {{ 1,  3,  1},
+          { 3,  6,  3},
+          { 1,  3,  1}}},
+        {{{-1, -3, -1},
+          { 0,  0,  0},
+          { 1,  3,  1}},
+         {{-3, -6, -3},
+          { 0,  0,  0},
+          { 3,  6,  3}},
+         {{-1, -3, -1},
+          { 0,  0,  0},
+          { 1,  3,  1}}},
+        {{{-1,  0,  1},
+          {-3,  0,  3},
+          {-1,  0,  1}},
+         {{-3,  0,  3},
+          {-6,  0,  6},
+          {-3,  0,  3}},
+         {{-1,  0,  1},
+          {-3,  0,  3},
+          {-1,  0,  1}}}
+    };
+
+    TRACE("computing gradients ... may take a while");
+
+    gp = gradients;
+    for (idz = 0; idz < sizes[2]; idz++) {
+        for (idy = 0; idy < sizes[1]; idy++) {
+            for (idx = 0; idx < sizes[0]; idx++) {
+#if SOBEL == 1
+                if (idx > 0 && idx < sizes[0] - 1 &&
+                    idy > 0 && idy < sizes[1] - 1 &&
+                    idz > 0 && idz < sizes[2] - 1) {
+
+                    for (dir = 0; dir < 3; dir++) {
+                        gp[dir] = 0.0;
+                        for (i = -1; i < 2; i++) {
+                            for (j = -1; j < 2; j++) {
+                                for (k = -1; k < 2; k++) {
+                                    gp[dir] += weights[dir][i + 1]
+                                                           [j + 1]
+                                                           [k + 1] *
+                                               getVoxel(idx + i,
+                                                        idy + j,
+                                                        idz + k,
+                                                        dataType);
+                                }
+                            }
+                        }
+
+                        gp[dir] /= 2.0 * g_sliceDists[dir];
+                    }
+                } else {
+                    /* X-direction */
+                    if (idx < 1) {
+                        gp[0] = (getVoxel(idx + 1, idy, idz, dataType) -
+                                 getVoxel(idx, idy, idz, dataType))/
+                                (g_sliceDists[0]);
+                    } else {
+                        gp[0] = (getVoxel(idx, idy, idz, dataType) -
+                                 getVoxel(idx - 1, idy, idz, dataType))/
+                                (g_sliceDists[0]);
+                    }
+
+                    /* Y-direction */
+                    if (idy < 1) {
+                        gp[1] = (getVoxel(idx, idy + 1, idz, dataType) -
+                                   getVoxel(idx, idy, idz, dataType))/
+                                   (g_sliceDists[1]);
+                    } else {
+                        gp[1] = (getVoxel(idx, idy, idz, dataType) -
+                                   getVoxel(idx, idy - 1, idz, dataType))/
+                                   (g_sliceDists[1]);
+                    }
+
+                    /* Z-direction */
+                    if (idz < 1) {
+                        gp[2] = (getVoxel(idx, idy, idz + 1, dataType) -
+                                 getVoxel(idx, idy, idz, dataType))/
+                                (g_sliceDists[2]);
+                    } else {
+                        gp[2] = (getVoxel(idx, idy, idz, dataType) -
+                                 getVoxel(idx, idy, idz - 1, dataType))/
+                                (g_sliceDists[2]);
+                    }
+                }
+#else
+                /* X-direction */
+                if (idx < 1) {
+                    gp[0] = (getVoxel(idx + 1, idy, idz, dataType) -
+                             getVoxel(idx, idy, idz, dataType))/
+                            (g_sliceDists[0]);
+                } else if (idx > g_numOfSlices[0] - 1) {
+                    gp[0] = (getVoxel(idx, idy, idz, dataType) -
+                             getVoxel(idx - 1, idy, idz, dataType))/
+                            (g_sliceDists[0]);
+                } else {
+                    gp[0] = (getVoxel(idx + 1, idy, idz, dataType) -
+                             getVoxel(idx - 1, idy, idz, dataType))/
+                            (2.0 * g_sliceDists[0]);
+                }
+
+                /* Y-direction */
+                if (idy < 1) {
+                    gp[1] = (getVoxel(idx, idy + 1, idz, dataType) -
+                             getVoxel(idx, idy, idz, dataType))/
+                            (g_sliceDists[1]);
+                } else if (idy > g_numOfSlices[1] - 1) {
+                    gp[1] = (getVoxel(idx, idy, idz, dataType) -
+                             getVoxel(idx, idy - 1, idz, dataType))/
+                            (g_sliceDists[1]);
+                } else {
+                    gp[1] = (getVoxel(idx, idy + 1, idz, dataType) -
+                             getVoxel(idx, idy - 1, idz, dataType))/
+                            (2.0 * g_sliceDists[1]);
+                }
+
+                /* Z-direction */
+                if (idz < 1) {
+                    gp[2] = (getVoxel(idx, idy, idz + 1, dataType) -
+                             getVoxel(idx, idy, idz, dataType))/
+                            (g_sliceDists[2]);
+                } else if (idz > g_numOfSlices[2] - 1) {
+                    gp[2] = (getVoxel(idx, idy, idz, dataType) -
+                             getVoxel(idx, idy, idz - 1, dataType))/
+                            (g_sliceDists[2]);
+                } else {
+                    gp[2] = (getVoxel(idx, idy, idz + 1, dataType) -
+                             getVoxel(idx, idy, idz - 1, dataType))/
+                            (2.0 * g_sliceDists[2]);
+                }
+#endif
+                gp += 3;
+            }
+        }
+    }
+}
+
+void
+nv::filterGradients(float *gradients, int *sizes)
+{
+    int i, j, k, idz, idy, idx, gi, ogi, filterWidth, n, borderDist[3];
+    float sum, *filteredGradients, ****filter;
+
+    TRACE("filtering gradients ... may also take a while");
+
+    if (! (filteredGradients = (float *)malloc(sizes[0] * sizes[1] * sizes[2]
+                                               * 3 * sizeof(float)))) {
+        ERROR("not enough memory for filtered gradients");
+        exit(1);
+    }
+
+    /* Allocate storage for filter kernels */
+    if (! (filter = (float ****)malloc((GRAD_FILTER_SIZE/2 + 1) * 
+                                       sizeof(float ***)))) {
+        ERROR("failed to allocate gradient filter");
+        exit(1);
+    }
+
+    for (i = 0; i < GRAD_FILTER_SIZE/2 + 1; i++) {
+        if (! (filter[i] = (float ***)malloc((GRAD_FILTER_SIZE) * 
+                                             sizeof(float **)))) {
+            ERROR("failed to allocate gradient filter");
+            exit(1);
+        }
+    }
+    for (i = 0; i < GRAD_FILTER_SIZE/2 + 1; i++) {
+        for (j = 0; j < GRAD_FILTER_SIZE; j++) {
+            if (! (filter[i][j] = (float **)malloc((GRAD_FILTER_SIZE) * 
+                                                   sizeof(float *)))) {
+                ERROR("failed to allocate gradient filter");
+                exit(1);
+            }
+        }
+    }
+    for (i = 0; i < GRAD_FILTER_SIZE/2 + 1; i++) {
+        for (j = 0; j < GRAD_FILTER_SIZE; j++) {
+            for (k = 0; k < GRAD_FILTER_SIZE; k++) {
+                if (! (filter[i][j][k] = (float *)malloc((GRAD_FILTER_SIZE) *
+                                                         sizeof(float)))) {
+                    ERROR("failed to allocate gradient filter");
+                    exit(1);
+                }
+            }
+        }
+    }
+
+    filterWidth = GRAD_FILTER_SIZE/2;
+
+    /* Compute the filter kernels */
+    for (n = 0; n <= filterWidth; n++) {
+        sum = 0.0f;
+        for (k = -filterWidth; k <= filterWidth; k++) {
+            for (j = -filterWidth; j <= filterWidth; j++) {
+                for (i = -filterWidth; i <= filterWidth; i++) {
+                    sum += (filter[n][filterWidth + k]
+                                     [filterWidth + j]
+                                     [filterWidth + i] =
+                            exp(-(SQR(i) + SQR(j) + SQR(k)) / SIGMA2));
+                }
+            }
+        }
+        for (k = -filterWidth; k <= filterWidth; k++) {
+            for (j = -filterWidth; j <= filterWidth; j++) {
+                for (i = -filterWidth; i <= filterWidth; i++) {
+                    filter[n][filterWidth + k]
+                             [filterWidth + j]
+                             [filterWidth + i] /= sum;
+                }
+            }
+        }
+    }
+
+    gi = 0;
+    /* Filter the gradients */
+    for (idz = 0; idz < sizes[2]; idz++) {
+        for (idy = 0; idy < sizes[1]; idy++) {
+            for (idx = 0; idx < sizes[0]; idx++) {
+                borderDist[0] = MIN(idx, sizes[0] - idx - 1);
+                borderDist[1] = MIN(idy, sizes[1] - idy - 1);
+                borderDist[2] = MIN(idz, sizes[2] - idz - 1);
+
+                filterWidth = MIN(GRAD_FILTER_SIZE/2,
+                                  MIN(MIN(borderDist[0], 
+                                          borderDist[1]),
+                                          borderDist[2]));
+
+                for (n = 0; n < 3; n++) {
+                    filteredGradients[gi] = 0.0;
+                    for (k = -filterWidth; k <= filterWidth; k++) {
+                        for (j = -filterWidth; j <= filterWidth; j++) {
+                            for (i = -filterWidth; i <= filterWidth; i++) {
+                                ogi = (((idz + k) * sizes[1]  + (idy + j)) *
+                                      sizes[0] + (idx + i)) * 3 + 
+                                      n;
+                                filteredGradients[gi] += filter[filterWidth]
+                                                       [filterWidth + k]
+                                                       [filterWidth + j]
+                                                       [filterWidth + i] * 
+                                                       gradients[ogi];
+                            }
+                        }
+                    }
+                    gi++;
+                }
+            }
+        }
+    }
+
+    /* Replace the orignal gradients by the filtered gradients */
+    memcpy(gradients, filteredGradients,
+           sizes[0] * sizes[1] * sizes[2] * 3 * sizeof(float));
+
+    free(filteredGradients);
+
+    /* free storage of filter kernel(s) */
+    for (i = 0; i < GRAD_FILTER_SIZE/2 + 1; i++) {
+        for (j = 0; j < GRAD_FILTER_SIZE; j++) {
+            for (k = 0; k < GRAD_FILTER_SIZE; k++) {
+                free(filter[i][j][k]);
+            }
+        }
+    }
+    for (i = 0; i < GRAD_FILTER_SIZE/2 + 1; i++) {
+        for (j = 0; j < GRAD_FILTER_SIZE; j++) {
+            free(filter[i][j]);
+        }
+    }
+    for (i = 0; i < GRAD_FILTER_SIZE/2 + 1; i++) {
+        free(filter[i]);
+    }
+    free(filter);
+}
+
+static void
+quantize8(float *grad, unsigned char *data)
+{
+    float len;
+    int i;
+
+    len = sqrt(SQR(grad[0]) + SQR(grad[1]) + SQR(grad[2]));
+
+    if (len < EPS) {
+        grad[0] = grad[1] = grad[2] = 0.0;
+    } else {
+        grad[0] /= len;
+        grad[1] /= len;
+        grad[2] /= len;
+    }
+
+    for (i = 0; i < 3; i++) {
+        data[i] = (unsigned char)((grad[i] + 1.0)/2.0 * UCHAR_MAX);
+    }
+}
+
+static void
+quantize16(float *grad, unsigned short *data)
+{
+    float len;
+    int i;
+
+    len = sqrt(SQR(grad[0]) + SQR(grad[1]) + SQR(grad[2]));
+
+    if (len < EPS) {
+        grad[0] = grad[1] = grad[2] = 0.0;
+    } else {
+        grad[0] /= len;
+        grad[1] /= len;
+        grad[2] /= len;
+    }
+
+    for (i = 0; i < 3; i++) {
+        data[i] = (unsigned short)((grad[i] + 1.0)/2.0 * USHRT_MAX);
+    }
+}
+
+static void
+quantizeFloat(float *grad, float *data)
+{
+    float len;
+    int i;
+
+    len = sqrt(SQR(grad[0]) + SQR(grad[1]) + SQR(grad[2]));
+
+    if (len < EPS) {
+        grad[0] = grad[1] = grad[2] = 0.0;
+    } else {
+        grad[0] /= len;
+        grad[1] /= len;
+        grad[2] /= len;
+    }
+
+    for (i = 0; i < 3; i++) {
+        data[i] = (float)((grad[i] + 1.0)/2.0);
+    }
+}
+
+void
+nv::quantizeGradients(float *gradientsIn, void *gradientsOut,
+                      int *sizes, DataType dataType)
+{
+    int idx, idy, idz, di;
+
+    di = 0;
+    for (idz = 0; idz < sizes[2]; idz++) {
+        for (idy = 0; idy < sizes[1]; idy++) {
+            for (idx = 0; idx < sizes[0]; idx++) {
+                switch (dataType) {
+                case DATRAW_UCHAR:
+                    quantize8(&gradientsIn[di], 
+                              &((unsigned char*)gradientsOut)[di]);
+                    break;
+                case DATRAW_USHORT:
+                    quantize16(&gradientsIn[di], 
+                               &((unsigned short*)gradientsOut)[di]);
+                    break;
+                case DATRAW_FLOAT:
+                    quantizeFloat(&gradientsIn[di], 
+                               &((float*)gradientsOut)[di]);
+                    break;
+                default:
+                    ERROR("unsupported data type");
+                    break;
+                }
+                di += 3;
+            }
+        }
+    }
+}
Index: /nanovis/tags/1.1.4/GradientFilter.h
===================================================================
--- /nanovis/tags/1.1.4/GradientFilter.h	(revision 4930)
+++ /nanovis/tags/1.1.4/GradientFilter.h	(revision 4930)
@@ -0,0 +1,27 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#ifndef NV_GRADIENT_FILTER_H
+#define NV_GRADIENT_FILTER_H
+
+namespace nv {
+
+typedef enum {
+    DATRAW_UCHAR,
+    DATRAW_FLOAT,
+    DATRAW_USHORT
+} DataType;
+
+extern void computeGradients(float *gradients, void *volData,
+                             int *sizes, float *spacing, DataType dataType);
+
+extern void filterGradients(float *gradients, int *sizes);
+
+extern void quantizeGradients(float *gradientsIn, void *gradientsOut,
+                              int *sizes, DataType dataType);
+
+}
+
+#endif 
Index: /nanovis/tags/1.1.4/Grid.cpp
===================================================================
--- /nanovis/tags/1.1.4/Grid.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/Grid.cpp	(revision 4930)
@@ -0,0 +1,310 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <GL/glew.h>
+#include <GL/gl.h>
+
+#include <util/Fonts.h>
+#include <vrmath/Color4f.h>
+
+#include "Grid.h"
+#include "Trace.h"
+
+using namespace nv;
+using namespace nv::util;
+
+#define NUMDIGITS	6
+#define TICK_LENGTH	0.05
+#define LABEL_OFFSET	0.06
+#define TITLE_OFFSET	0.2
+
+Grid::Grid() :
+    xAxis("X"), 
+    yAxis("Y"), 
+    zAxis("Z"),
+    _axisColor(1.0f, 1.0f, 1.0f, 1.0f), 
+    _majorColor(1.0f, 1.0f, 1.0f, 1.0f), 
+    _minorColor(0.5f, 0.5f, 0.5f, 1.0f), 
+    _font(NULL), 
+    _visible(false)
+{
+}
+
+Grid::~Grid()
+{
+}
+
+void Grid::getBounds(vrmath::Vector3f& bboxMin, vrmath::Vector3f& bboxMax) const
+{
+    bboxMin.set(xAxis.min(), yAxis.min(), zAxis.min());
+    bboxMax.set(xAxis.min() + xAxis.range(),
+                yAxis.min() + yAxis.range(),
+                zAxis.min() + zAxis.range());
+}
+
+void Grid::render()
+{
+    if (!isVisible())
+        return;
+
+    glPushAttrib(GL_ENABLE_BIT);
+
+    glEnable(GL_DEPTH_TEST);
+    glDisable(GL_TEXTURE_2D);
+#ifdef notdef
+    glEnable(GL_BLEND);
+    glEnable(GL_LINE_SMOOTH);
+#else
+    glDisable(GL_BLEND);
+#endif
+
+    glMatrixMode(GL_MODELVIEW);
+    glPushMatrix();
+
+    double xDataRange = xAxis.dataMax() - xAxis.dataMin();
+    double yDataRange = yAxis.dataMax() - yAxis.dataMin();
+    double zDataRange = zAxis.dataMax() - zAxis.dataMin();
+
+    double paspectX = 1.0f;
+    double paspectY = yDataRange / xDataRange;
+    double paspectZ = zDataRange / xDataRange;
+ 
+    double xscale = xAxis.range() / xDataRange;
+    double yscale = yAxis.range() / xDataRange;
+    double zscale = zAxis.range() / xDataRange;
+
+    double xoffset = (xAxis.min() - xAxis.dataMin()) * xAxis.scale();
+    double yoffset = (yAxis.min() - yAxis.dataMin()) * yAxis.scale();
+    double zoffset = (zAxis.min() - zAxis.dataMin()) * zAxis.scale();
+
+    float xTickLen = TICK_LENGTH;
+    float yTickLen = TICK_LENGTH;
+    float zTickLen = TICK_LENGTH;
+    float xLabelOfs = LABEL_OFFSET;
+    //float yLabelOfs = LABEL_OFFSET;
+    float zLabelOfs = LABEL_OFFSET;
+    float xTitleOfs = TITLE_OFFSET;
+    float yTitleOfs = TITLE_OFFSET;
+    float zTitleOfs = TITLE_OFFSET;
+
+    TRACE("Axis ranges: %g %g %g", xAxis.range(), yAxis.range(), zAxis.range());
+    TRACE("Axis scales: %g %g %g", xAxis.scale(), yAxis.scale(), zAxis.scale());
+    TRACE("Axis min/max: %g,%g %g,%g %g,%g",
+          xAxis.min(), xAxis.max(), 
+          yAxis.min(), yAxis.max(),
+          zAxis.min(), zAxis.max());
+    TRACE("Axis vmin/vmax: %g,%g %g,%g %g,%g",
+          xAxis.dataMin(), xAxis.dataMax(), 
+          yAxis.dataMin(), yAxis.dataMax(),
+          zAxis.dataMin(), zAxis.dataMax());
+    TRACE("paspect: %g %g %g", paspectX, paspectY, paspectZ);
+    TRACE("scale: %g %g %g", xscale, yscale, zscale);
+
+    glTranslatef(-0.5f * paspectX, -0.5f * paspectY, -0.5f * paspectZ);
+    glScalef(xscale, yscale, zscale);
+    glTranslatef(xoffset, yoffset, zoffset);
+
+    glLineWidth(2.0f);
+    glColor4f(_axisColor.r, _axisColor.g, _axisColor.b,
+              _axisColor.a);
+
+    glBegin(GL_LINES);
+    {
+        glVertex3f(0.0f, 0.0f, 0.0f);
+        glVertex3f(1.0f + xTickLen, 0.0f, 0.0f);
+        glVertex3f(0.0f, 0.0f, 0.0f);
+        glVertex3f(0.0f, 1.0f + yTickLen, 0.0f);
+        glVertex3f(0.0f, 0.0f, 0.0f);
+        glVertex3f(0.0f, 0.0f, 1.0f + zTickLen);
+    }
+    glEnd();
+
+    glLineWidth(1.0f);
+    glColor4f(_majorColor.r, _majorColor.g, _majorColor.b,
+              _majorColor.a);
+
+    glBegin(GL_LINES);
+    {
+        bool result;
+        TickIter iter;
+
+        for (result = xAxis.firstMajor(iter); result; result = iter.next()) {
+            float x;
+            x = xAxis.map(iter.getValue());
+            glVertex3f(x, 0.0f, 0.0f);
+            glVertex3f(x, 1.0f, 0.0f);
+            glVertex3f(x, 0.0f, 0.0f);
+            glVertex3f(x, 0.0f, 1.0f + zTickLen);
+        }
+        for (result = yAxis.firstMajor(iter); result; result = iter.next()) {
+            float y;
+            y = yAxis.map(iter.getValue());
+            glVertex3f(0.0f, y, 0.0f);
+            glVertex3f(1.0f + xTickLen, y, 0.0f);
+            glVertex3f(0.0f, y, 0.0f);
+            glVertex3f(0.0f, y, 1.0f);
+        }
+        for (result = zAxis.firstMajor(iter); result; result = iter.next()) {
+            float z;
+            z = zAxis.map(iter.getValue());
+            glVertex3f(0.0f, 0.0f, z);
+            glVertex3f(0.0f, 1.0f, z);
+            glVertex3f(0.0f, 0.0f, z);
+            glVertex3f(1.0f + xTickLen, 0.0f, z);
+        }
+    }
+    glEnd();
+
+    // Set minor line color
+    glColor4f(_minorColor.r, _minorColor.g, _minorColor.b,
+              _minorColor.a);
+
+    glBegin(GL_LINES);
+    {
+        bool result;
+        TickIter iter;
+
+        for (result = xAxis.firstMinor(iter); result; result = iter.next()) {
+            float x;
+            x = xAxis.map(iter.getValue());
+            glVertex3f(x, 0.0f, 0.0f);
+            glVertex3f(x, 1.0f, 0.0f);
+            glVertex3f(x, 0.0f, 0.0f);
+            glVertex3f(x, 0.0f, 1.0f);
+        }
+        for (result = yAxis.firstMinor(iter); result; result = iter.next()) {
+            float y;
+            y = yAxis.map(iter.getValue());
+            glVertex3f(0.0f, y, 0.0f);
+            glVertex3f(1.0f, y, 0.0f);
+            glVertex3f(0.0f, y, 0.0f);
+            glVertex3f(0.0f, y, 1.0f);
+        }
+        for (result = zAxis.firstMinor(iter); result; result = iter.next()) {
+            float z;
+            z = zAxis.map(iter.getValue());
+            glVertex3f(0.0f, 0.0f, z);
+            glVertex3f(0.0f, 1.0f, z);
+            glVertex3f(0.0f, 0.0f, z);
+            glVertex3f(1.0f, 0.0f, z);
+        }
+    }
+    glEnd();
+
+    if (_font != NULL) {
+        double mv[16], prjm[16];
+        int viewport[4];
+        double wx, wy, wz;
+        bool result;
+        TickIter iter;
+
+        glGetDoublev(GL_MODELVIEW_MATRIX, mv);
+        glGetDoublev(GL_PROJECTION_MATRIX, prjm);
+        glGetIntegerv(GL_VIEWPORT, viewport);
+
+        _font->begin();
+
+        glColor4f(_axisColor.r, _axisColor.g, _axisColor.b,
+                  _axisColor.a);
+
+        if (gluProject(1.0 + xTitleOfs, 0.0, 0.0,
+                       mv, prjm, viewport,
+                       &wx, &wy, &wz) &&
+            wz >= 0.0 && wz <= 1.0) {
+            glLoadIdentity();
+            glTranslatef((int) wx, viewport[3] - (int) wy, 0);
+            const char *name = xAxis.name();
+            if (name == NULL) {
+                name = "???";
+            }
+            _font->draw(name);
+        }
+        
+        if (gluProject(0.0, 1.0 + yTitleOfs, 0.0,
+                       mv, prjm, viewport,
+                       &wx, &wy, &wz) &&
+            wz >= 0.0 && wz <= 1.0) {
+            glLoadIdentity();
+            glTranslatef((int) wx, viewport[3] - (int)wy, 0);
+            const char *name = yAxis.name();
+            if (name == NULL) {
+                name = "???";
+            }
+            _font->draw(name);
+        }
+        
+        if (gluProject(0.0, 0.0, 1.0 + zTitleOfs,
+                       mv, prjm, viewport,
+                       &wx, &wy, &wz) &&
+            wz >= 0.0 && wz <= 1.0) {
+            glLoadIdentity();
+            glTranslatef((int) wx, (int) viewport[3] - (int)wy, 0.0f);
+            const char *name = zAxis.name();
+            if (name == NULL) {
+                name = "???";
+            }
+            _font->draw(name);
+        }
+
+        glColor4f(_majorColor.r, _majorColor.g, _majorColor.b,
+                  _majorColor.a);
+
+        for (result = xAxis.firstMajor(iter); result; result = iter.next()) {
+            float x;
+            x = xAxis.map(iter.getValue());
+            if (gluProject(x, 0.0f, 1.0 + zLabelOfs,
+                           mv, prjm, viewport,
+                           &wx, &wy, &wz) &&
+                wz >= 0.0 && wz <= 1.0) {
+                char buff[20];
+                glLoadIdentity();
+                glTranslatef((int) wx, (int) viewport[3] - (int)wy, 0.0f);
+                sprintf(buff, "%.*g", NUMDIGITS, iter.getValue());
+                _font->draw(buff);
+            }
+        }
+        for (result = yAxis.firstMajor(iter); result; result = iter.next()) {
+            float y;
+            y = yAxis.map(iter.getValue());
+            if (gluProject(1.0 + xLabelOfs, y, 0.0f,
+                           mv, prjm, viewport,
+                           &wx, &wy, &wz) &&
+                wz >= 0.0 && wz <= 1.0) {
+                char buff[20];
+                glLoadIdentity();
+                glTranslatef((int) wx, (int) viewport[3] - (int)wy, 0.0f);
+                sprintf(buff, "%.*g", NUMDIGITS, iter.getValue());
+                _font->draw(buff);
+            }
+        }
+        for (result = zAxis.firstMajor(iter); result; result = iter.next()) {
+            float z;
+            z = zAxis.map(iter.getValue());
+            if (gluProject(1.0 + xLabelOfs, 0.0f, z,
+                           mv, prjm, viewport,
+                           &wx, &wy, &wz) &&
+                wz >= 0.0 && wz <= 1.0) {
+                char buff[20];
+                glLoadIdentity();
+                glTranslatef((int) wx, (int) viewport[3] - (int)wy, 0.0f);
+                sprintf(buff, "%.*g", NUMDIGITS, iter.getValue());
+                _font->draw(buff);
+            }
+        }
+        _font->end();
+    };
+
+    glPopMatrix();
+    glPopAttrib();
+}
+
+void Grid::setFont(Fonts *font)
+{
+    _font = font;
+}
+
Index: /nanovis/tags/1.1.4/Grid.h
===================================================================
--- /nanovis/tags/1.1.4/Grid.h	(revision 4930)
+++ /nanovis/tags/1.1.4/Grid.h	(revision 4930)
@@ -0,0 +1,67 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#ifndef NV_GRID_H
+#define NV_GRID_H
+
+#include <vrmath/Vector3f.h>
+#include <vrmath/Color4f.h>
+
+#include "Axis.h"
+#include "AxisRange.h"
+
+namespace nv {
+
+namespace util {
+class Fonts;
+}
+
+class Grid
+{
+public:
+    Grid();
+    virtual ~Grid();
+
+    bool isVisible() const
+    {
+        return _visible;
+    }
+
+    void setVisible(bool visible)
+    {
+        _visible = visible;
+    }
+
+    void setAxisColor(float r, float g, float b, float a)
+    {
+        _axisColor.set(r, g, b, a);
+    }
+
+    void setLineColor(float r, float g, float b, float a)
+    {
+        _majorColor.set(r, g, b, a);
+        _minorColor = _majorColor;
+    }
+
+    void render();
+
+    void setFont(nv::util::Fonts *font);
+
+    void getBounds(vrmath::Vector3f& bboxMin,
+                   vrmath::Vector3f& bboxMax) const;
+
+    Axis xAxis;
+    Axis yAxis;
+    Axis zAxis;
+
+private:
+    vrmath::Color4f _axisColor, _majorColor, _minorColor;
+    nv::util::Fonts *_font;
+    bool _visible;
+};
+
+}
+
+#endif 
Index: /nanovis/tags/1.1.4/HeightMap.cpp
===================================================================
--- /nanovis/tags/1.1.4/HeightMap.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/HeightMap.cpp	(revision 4930)
@@ -0,0 +1,497 @@
+ /* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#include <float.h>
+
+#include <GL/glew.h>
+
+#include <graphics/RenderContext.h>
+
+#include "Grid.h"
+#include "HeightMap.h"
+#include "ContourLineFilter.h"
+#include "Texture1D.h"
+
+using namespace nv;
+using namespace nv::graphics;
+using namespace vrmath;
+
+bool HeightMap::updatePending = false;
+double HeightMap::valueMin = 0.0;
+double HeightMap::valueMax = 1.0;
+
+HeightMap::HeightMap() : 
+    _vertexBufferObjectID(0),
+    _texcoordBufferObjectID(0),
+    _vertexCount(0),
+    _contour(NULL),
+    _transferFunc(NULL),
+    _opacity(0.5f),
+    _indexBuffer(NULL),
+    _indexCount(0),
+    _contourColor(1.0f, 0.0f, 0.0f),
+    _contourVisible(false),
+    _visible(false),
+    _scale(1.0f, 1.0f, 1.0f),
+    _centerPoint(0.0f, 0.0f, 0.0f),
+    _heights(NULL)
+{
+    _shader = new Shader();
+    _shader->loadFragmentProgram("heightcolor.cg");
+}
+
+HeightMap::~HeightMap()
+{
+    reset();
+
+    if (_shader != NULL) {
+        delete _shader;
+    }
+    if (_heights != NULL) {
+	delete [] _heights;
+    }
+}
+
+void 
+HeightMap::render(RenderContext *renderContext)
+{
+    if (!isVisible())
+        return;
+
+    glPushAttrib(GL_ENABLE_BIT | GL_POLYGON_BIT | GL_LIGHTING_BIT);
+
+    if (renderContext->getCullMode() == RenderContext::NO_CULL) {
+        glDisable(GL_CULL_FACE);
+    } else {
+        glEnable(GL_CULL_FACE);
+        glCullFace((GLuint)renderContext->getCullMode());
+    }
+    glPolygonMode(GL_FRONT_AND_BACK, (GLuint)renderContext->getPolygonMode());
+    glShadeModel((GLuint)renderContext->getShadingModel());
+
+    glMatrixMode(GL_MODELVIEW);
+    glPushMatrix();
+
+#ifndef notdef
+    if (_scale.x != 0.0) {
+        glScalef(1 / _scale.x, 1 / _scale.y , 1 / _scale.z);
+    }
+#endif
+    glTranslatef(-_centerPoint.x, -_centerPoint.y, -_centerPoint.z);
+
+    if (_contour != NULL) {
+        glDepthRange(0.001, 1.0);
+    }
+        
+    glEnable(GL_DEPTH_TEST);
+
+    if (_vertexBufferObjectID) {
+        glColor3f(1.0f, 1.0f, 1.0f);
+        glShadeModel(GL_SMOOTH);
+        glEnable(GL_BLEND);
+        glEnableClientState(GL_VERTEX_ARRAY);
+        glDisableClientState(GL_COLOR_ARRAY);
+        glDisableClientState(GL_INDEX_ARRAY);
+        glDisableClientState(GL_NORMAL_ARRAY);
+
+        if (_transferFunc) {
+            // PUT vertex program here
+            //
+            //
+            _shader->bind();
+            _shader->setFPTextureParameter("tf", _transferFunc->id());
+            _shader->setFPParameter1f("opacity", _opacity);
+
+            glEnable(GL_TEXTURE_1D);
+            _transferFunc->getTexture()->activate();
+ 
+            glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+        }
+
+        glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferObjectID);
+        glVertexPointer(3, GL_FLOAT, 12, 0);
+
+        glBindBuffer(GL_ARRAY_BUFFER, _texcoordBufferObjectID);
+        glTexCoordPointer(3, GL_FLOAT, 12, 0);
+
+#define _TRIANGLES_
+#ifdef _TRIANGLES_
+        glDrawElements(GL_TRIANGLES, _indexCount, GL_UNSIGNED_INT, 
+                       _indexBuffer);
+#else
+        glDrawElements(GL_QUADS, _indexCount, GL_UNSIGNED_INT, 
+                       _indexBuffer);
+#endif
+
+        glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+        glDisableClientState(GL_VERTEX_ARRAY);
+        if (_transferFunc != NULL) {
+            _transferFunc->getTexture()->deactivate();
+            glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+
+            _shader->disableFPTextureParameter("tf");
+            _shader->unbind();
+        }
+    }
+    glShadeModel(GL_FLAT);
+    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+
+    if (_contour != NULL) {
+        if (_contourVisible) {
+            glDisable(GL_BLEND);
+            glDisable(GL_TEXTURE_2D);
+            glColor4f(_contourColor.x, _contourColor.y, _contourColor.z, 
+                      _opacity /*1.0f*/);
+            glDepthRange (0.0, 0.999);
+            _contour->render();
+        }
+
+        glDepthRange (0.0, 1.0);
+    }
+
+    glPopMatrix();
+    glPopAttrib();
+}
+
+void 
+HeightMap::createIndexBuffer(int xCount, int zCount, float* heights)
+{
+    if (_indexBuffer != NULL) {
+        delete [] _indexBuffer;
+	_indexBuffer = NULL;
+    }
+    _indexCount = (xCount - 1) * (zCount - 1) * 6;
+    _indexBuffer = new int[_indexCount];
+   
+    int i, j;
+    int boundaryWidth = xCount - 1;
+    int boundaryHeight = zCount - 1;
+    int* ptr = _indexBuffer;
+    int index1, index2, index3, index4;
+    bool index1Valid, index2Valid, index3Valid, index4Valid;
+    index1Valid = index2Valid = index3Valid = index4Valid = true;
+
+    if (heights) {
+        int ic = 0;
+        for (i = 0; i < boundaryHeight; ++i) {
+            for (j = 0; j < boundaryWidth; ++j) {
+                index1 = i * xCount +j;
+                if (isnan(heights[index1])) index1Valid = false;
+                index2 = (i + 1) * xCount + j;
+                if (isnan(heights[index2])) index2Valid = false;
+                index3 = (i + 1) * xCount + j + 1;
+                if (isnan(heights[index3])) index3Valid = false;
+                index4 = i * xCount + j + 1;
+                if (isnan(heights[index4])) index4Valid = false;
+            
+#ifdef _TRIANGLES_
+                if (index1Valid && index2Valid && index3Valid) {
+                    *ptr = index1; ++ptr;
+                    *ptr = index2; ++ptr;
+                    *ptr = index3; ++ptr;
+                    ++ic;
+                }
+                if (index1Valid && index3Valid && index4Valid) {
+                    *ptr = index1; ++ptr;
+                    *ptr = index3; ++ptr;
+                    *ptr = index4; ++ptr;
+                    ++ic;
+                }
+#else
+                if (index1Valid && index2Valid && index3Valid && index4Valid) {
+                    *ptr = index1; ++ptr;
+                    *ptr = index2; ++ptr;
+                    *ptr = index3; ++ptr;
+                    *ptr = index4; ++ptr;
+                    ++ic;
+                }
+#endif
+            }
+        }
+    } else {
+        for (i = 0; i < boundaryHeight; ++i) {
+            for (j = 0; j < boundaryWidth; ++j) {
+                *ptr = i * xCount + j; ++ptr;
+                *ptr = (i + 1) * xCount + j; ++ptr;
+                *ptr = (i + 1) * xCount + j + 1; ++ptr;
+                *ptr = i * xCount + j; ++ptr;
+                *ptr = (i + 1) * xCount + j + 1; ++ptr;
+                *ptr = i * xCount + j + 1; ++ptr;
+            }
+        }
+    }
+}
+
+void 
+HeightMap::reset()
+{
+    if (_vertexBufferObjectID) {
+        glDeleteBuffers(1, &_vertexBufferObjectID);
+	_vertexBufferObjectID = 0;
+    }
+    if (_texcoordBufferObjectID) {
+        glDeleteBuffers(1, &_texcoordBufferObjectID);
+	_texcoordBufferObjectID = 0;
+    }
+    if (_contour != NULL) {
+        delete _contour;
+	_contour = NULL;
+    }
+    if (_indexBuffer != NULL) {
+        delete [] _indexBuffer;
+	_indexBuffer = NULL;
+    }
+}
+#if 0
+void 
+HeightMap::setHeight(int xCount, int yCount, Vector3f *heights)
+{
+    _vertexCount = xCount * yCount;
+    reset();
+
+    _heights = (float *)heights;
+    float min, max;
+    min = heights[0].y, max = heights[0].y;
+
+    int count = xCount * yCount;
+    for (int i = 0; i < count; ++i) {
+        if (min > heights[i].y) {
+            min = heights[i].y;
+        } 
+        if (max < heights[i].y) {
+            max = heights[i].y;
+        }
+    }
+
+    _scale.x = 1.0f;
+    _scale.z = max - min;
+    _scale.y = 1.0f;
+
+    xAxis.setRange(0.0, 1.0);
+    yAxis.setRange(0.0, 1.0);
+    zAxis.setRange(0.0, 1.0);
+    wAxis.setRange(min, max);
+    updatePending = true;
+
+    _centerPoint.set(_scale.x * 0.5, _scale.z * 0.5 + min, _scale.y * 0.5);
+
+    Vector3f* texcoord = new Vector3f[count];
+    for (int i = 0; i < count; ++i) {
+        texcoord[i].set(0, 0, heights[i].y);
+    }
+    
+    glGenBuffers(1, &_vertexBufferObjectID);
+    glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferObjectID);
+    glBufferData(GL_ARRAY_BUFFER, _vertexCount * sizeof( Vector3f ), heights, 
+	GL_STATIC_DRAW);
+    glGenBuffers(1, &_texcoordBufferObjectID);
+    glBindBuffer(GL_ARRAY_BUFFER, _texcoordBufferObjectID);
+    glBufferData(GL_ARRAY_BUFFER, _vertexCount * sizeof(float) * 3, texcoord, 
+	GL_STATIC_DRAW);
+    glBindBuffer(GL_ARRAY_BUFFER, 0);
+    
+    delete [] texcoord;
+    
+    if (_contour != NULL) {
+        delete _contour;
+	_contour = NULL;
+    }
+    ContourLineFilter lineFilter;
+    _contour = lineFilter.create(0.0f, 1.0f, 10, heights, xCount, yCount);
+
+    //if (heightMap)
+    //{
+    //  VertexBuffer* vertexBuffer = new VertexBuffer(VertexBuffer::POSITION3, xCount * yCount, sizeof(Vector3f) * xCount * yCount, heightMap, false);
+    this->createIndexBuffer(xCount, yCount, 0);
+    //}
+    //else
+    //{
+    //ERROR("HeightMap::setHeight");
+    //}
+}
+#endif
+void 
+HeightMap::setHeight(float xMin, float yMin, float xMax, float yMax, 
+                     int xNum, int yNum, float *heights)
+{
+    _vertexCount = xNum * yNum;
+    _xNum = xNum, _yNum = yNum;
+    _heights = heights; 
+    reset();
+    
+    // Get the min/max of the heights. */
+    float min, max;
+    min = max = heights[0];
+    for (int i = 0; i < _vertexCount; ++i) {
+        if (min > heights[i]) {
+            min = heights[i];
+        } else if (max < heights[i]) {
+            max = heights[i];
+        }
+    }
+#ifdef notdef
+    if (retainScale_) {
+	// Check the units of each axis.  If they are the same, we want to
+	// retain the surface's aspect ratio when transforming coordinates to
+	// the grid. Use the range of the longest axis when the units are the
+	// same.  
+	if (xAxis.units() != NULL) && (xAxis.units() == yAxis.units()) {
+	}
+	if (yAxis.units() != NULL) && (yAxis.units() == zAxis.units()) {
+	}
+    }
+#endif
+
+    wAxis.setRange(min, max);
+    yAxis.setRange(min, max);
+    xAxis.setRange(xMin, xMax);
+    zAxis.setRange(yMin, yMax);
+
+    min = 0.0, max = 1.0;
+    xMin = yMin = min = 0.0; 
+    xMax = yMax = max = 1.0;
+    // Save the scales.
+    _scale.x = _scale.y = _scale.z = 1.0;
+
+    updatePending = true;
+
+    _centerPoint.set(0.5, 0.5, 0.5);
+    
+#ifndef notdef
+    Vector3f* texcoord = new Vector3f[_vertexCount];
+    for (int i = 0; i < _vertexCount; ++i) {
+        texcoord[i].set(0, 0, heights[i]);
+    }
+    
+    Vector3f* map = createHeightVertices(xMin, yMin, xMax, yMax, xNum, yNum, 
+					heights);
+    
+    glGenBuffers(1, &_vertexBufferObjectID);
+    glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferObjectID);
+    glBufferData(GL_ARRAY_BUFFER, _vertexCount * sizeof(Vector3f), map, 
+        GL_STATIC_DRAW);
+    glGenBuffers(1, &_texcoordBufferObjectID);
+    glBindBuffer(GL_ARRAY_BUFFER, _texcoordBufferObjectID);
+    glBufferData(GL_ARRAY_BUFFER, _vertexCount * sizeof(float) * 3, texcoord, 
+        GL_STATIC_DRAW);
+    glBindBuffer(GL_ARRAY_BUFFER, 0);
+    
+    delete [] texcoord;
+    
+    
+    if (_contour != NULL) {
+        delete _contour;
+	_contour = NULL;
+    }
+    ContourLineFilter lineFilter;
+    //lineFilter.transferFunction(_transferFunc);
+    _contour = lineFilter.create(0.0f, 1.0f, 10, map, xNum, yNum);
+
+    this->createIndexBuffer(xNum, yNum, heights);
+    delete [] map;
+#endif
+}
+
+Vector3f *
+HeightMap::createHeightVertices(float xMin, float yMin, float xMax, 
+				float yMax, int xNum, int yNum, float *height)
+{
+    Vector3f* vertices = new Vector3f[xNum * yNum];
+
+    Vector3f* dstData = vertices;
+    float* srcData = height;
+    
+    for (int y = 0; y < yNum; ++y) {
+        float yCoord;
+
+        yCoord = yMin + ((yMax - yMin) * y) / (yNum - 1); 
+        for (int x = 0; x < xNum; ++x) {
+            float xCoord;
+
+            xCoord = xMin + ((xMax - xMin) * x) / (xNum - 1); 
+            dstData->set(xCoord, *srcData, yCoord);
+
+            ++dstData;
+            ++srcData;
+        }
+    }
+    return vertices;
+}
+
+/**
+ * \brief Maps the data coordinates of the surface into the grid's axes.
+ */
+void 
+HeightMap::mapToGrid(Grid *grid)
+{
+    int count = _xNum * _yNum;
+
+    reset();
+
+    // The range of the grid's y-axis 0..1 represents the distance between the
+    // smallest and largest major ticks for all surfaces plotted.  Translate
+    // this surface's y-values (heights) into the grid's axis coordinates.
+
+    float yScale = 1.0 / (grid->yAxis.max() - grid->yAxis.min());
+    float *p, *q, *pend;
+    float *normHeights = new float[count];
+    for (p = _heights, pend = p + count, q = normHeights; p < pend; p++, q++) {
+	*q = (*p - grid->yAxis.min()) * yScale;
+    }
+    Vector3f *t, *texcoord;
+    texcoord = new Vector3f[count];
+    for (t = texcoord, p = normHeights, pend = p + count; p < pend; p++, t++) {
+        t->set(0, 0, *p);
+    }
+
+    // Normalize the mesh coordinates (x and z min/max) the range of the major
+    // ticks for the x and z grid axes as well.
+
+    float xScale, zScale;
+    float xMin, xMax, zMin, zMax;
+
+    xScale = 1.0 / (grid->xAxis.max() - grid->xAxis.min());
+    xMin = (xAxis.min() - grid->xAxis.min()) * xScale;
+    xMax = (xAxis.max() - grid->xAxis.min()) * xScale;
+    zScale = 1.0 / (grid->zAxis.max() - grid->zAxis.min());
+    zMin = (zAxis.min() - grid->zAxis.min()) * zScale;
+    zMax = (zAxis.max() - grid->zAxis.min()) * zScale;
+
+    Vector3f* vertices;
+    vertices = createHeightVertices(xMin, zMin, xMax, zMax, _xNum, _yNum, 
+	normHeights);
+    
+    glGenBuffers(1, &_vertexBufferObjectID);
+    glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferObjectID);
+    glBufferData(GL_ARRAY_BUFFER, _vertexCount * sizeof(Vector3f), vertices, 
+        GL_STATIC_DRAW);
+    glGenBuffers(1, &_texcoordBufferObjectID);
+    glBindBuffer(GL_ARRAY_BUFFER, _texcoordBufferObjectID);
+    glBufferData(GL_ARRAY_BUFFER, _vertexCount * sizeof(float) * 3, texcoord, 
+        GL_STATIC_DRAW);
+    glBindBuffer(GL_ARRAY_BUFFER, 0);
+    delete [] texcoord;
+
+    if (_contour != NULL) {
+        delete _contour;
+	_contour = NULL;
+    }
+    ContourLineFilter lineFilter;
+    //lineFilter.transferFunction(_transferFunc);
+    _contour = lineFilter.create(0.0f, 1.0f, 10, vertices, _xNum, _yNum);
+    
+    this->createIndexBuffer(_xNum, _yNum, normHeights);
+    delete [] normHeights;
+    delete [] vertices;
+}
+
+void
+HeightMap::getWorldSpaceBounds(Vector3f& bboxMin,
+                               Vector3f& bboxMax) const
+{
+    bboxMin.set(xAxis.min(), yAxis.min(), zAxis.min());
+    bboxMax.set(xAxis.max(), yAxis.max(), zAxis.max());
+}
Index: /nanovis/tags/1.1.4/HeightMap.h
===================================================================
--- /nanovis/tags/1.1.4/HeightMap.h	(revision 4930)
+++ /nanovis/tags/1.1.4/HeightMap.h	(revision 4930)
@@ -0,0 +1,151 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#ifndef NV_HEIGHTMAP_H
+#define NV_HEIGHTMAP_H
+
+#include <graphics/Geometry.h>
+#include <graphics/RenderContext.h>
+#include <vrmath/Vector3f.h>
+
+#include "TransferFunction.h"
+#include "Shader.h"
+#include "AxisRange.h"
+
+namespace nv {
+
+class Grid;
+
+/**
+ *@brief Create a surface from height map and line contour of the generated surface
+ */
+class HeightMap
+{
+public:
+    HeightMap();
+
+    ~HeightMap();
+
+    void render(nv::graphics::RenderContext *renderContext);
+
+    /**
+     *@brief Create a height map with height values
+     *@param startX x position of the first height value
+     *@param startY y position of the first height value
+     *@param endX x position of the last height value
+     *@param endY y position of the last height value
+     *@param xCount the number of columns of height values
+     *@param yCount the number of rows of height values
+     *@param height a pointer value adrressing xCount * yCount values of heights
+     */
+    void setHeight(float startX, float startY, float endX, float endY, 
+		   int xCount, int yCount, float *height);
+#if 0
+    /**
+     *@brief Create a height map with a set of points
+     *@param xCount the number of columns of height values
+     *@param yCount the number of rows of height values
+     */
+    void setHeight(int xCount, int yCount, vrmath::Vector3f *heights);
+#endif
+    void mapToGrid(Grid *grid);
+
+    /**
+     *@brief Define a color map for color shading of heightmap
+     */
+    void transferFunction(TransferFunction *transferFunc)
+    {
+        _transferFunc = transferFunc;
+    }
+
+    /**
+     *@brief Get the color map defined for shading of this heightmap
+     */
+    TransferFunction *transferFunction()
+    {
+        return _transferFunc;
+    }
+
+    /**
+     *@brief Set the visibility of the height map
+     */
+    void setVisible(bool visible)
+    {
+        _visible = visible;
+    }
+
+    /**
+     *@brief Return the status of the visibility
+     */
+    bool isVisible() const
+    {
+        return _visible;
+    }
+
+    /**
+     *@brief Set the visibility of the line contour
+     */
+    void setLineContourVisible(bool visible)
+    {
+        _contourVisible = visible;
+    }
+
+    void opacity(float opacity)
+    {
+        _opacity = opacity;
+    }
+
+    float opacity()
+    {
+	return _opacity;
+    }
+
+    /**
+     *@brief Defind the color of the line contour
+     */
+    void setLineContourColor(float *rgb)
+    {
+	_contourColor.x = rgb[0];
+	_contourColor.y = rgb[1];
+	_contourColor.z = rgb[2];
+    }
+
+    void getWorldSpaceBounds(vrmath::Vector3f& bboxMin, vrmath::Vector3f& bboxMax) const;
+
+    AxisRange xAxis, yAxis, zAxis, wAxis;
+    static bool updatePending;
+    static double valueMin, valueMax;
+
+private:
+    void createIndexBuffer(int xCount, int zCount, float *heights);
+    vrmath::Vector3f *createHeightVertices(float startX, float startY,
+                                           float endX, float endY,
+                                           int xCount, int yCount, float *height);
+    void reset();
+
+    unsigned int _vertexBufferObjectID;
+    unsigned int _texcoordBufferObjectID;
+    int _vertexCount;
+    nv::graphics::Geometry *_contour;
+    TransferFunction *_transferFunc;
+    float _opacity;
+    Shader *_shader;
+    int *_indexBuffer;
+    int _indexCount;
+    vrmath::Vector3f _contourColor;
+
+    bool _contourVisible;
+    bool _visible;
+
+    vrmath::Vector3f _scale;
+    vrmath::Vector3f _centerPoint;
+    int _xNum, _yNum;		// Number of elements x and y axes in grid.
+    float *_heights;		// Array of original (unscaled) heights
+				// (y-values)
+};
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/LIC.cpp
===================================================================
--- /nanovis/tags/1.1.4/LIC.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/LIC.cpp	(revision 4930)
@@ -0,0 +1,550 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ *  Authors:
+ *    Insoo Woo <iwoo@purdue.edu>
+ *    Wei Qiao <qiaow@purdue.edu>
+ */
+#include <stdlib.h>
+#include <math.h>
+#include <assert.h>
+
+#include "nanovis.h"
+#include "define.h"
+
+#include "LIC.h"
+#include "Shader.h"
+#include "Trace.h"
+
+#define NPN 256   //resolution of background pattern
+#define DM ((float) (1.0/(NMESH-1.0))) //distance in world coords between mesh lines
+#define SCALE 3.0 //scale for background pattern. small value -> fine texture
+
+using namespace nv;
+using namespace vrmath;
+
+LIC::LIC(FlowSliceAxis axis, float offset) :
+    _width(NPIX),
+    _height(NPIX),
+    _size(NMESH),
+    _scale(1.0f, 1.0f, 1.0f),
+    _origin(0, 0, 0),
+    _offset(offset),
+    _axis(axis),
+    _iframe(0),
+    _Npat(64),
+    _alpha((int)0.12*255),
+    _tmax(NPIX/(SCALE*NPN)),
+    _dmax(SCALE/NPIX),
+    _max(1.0f),
+    _disListID(0),
+    _vectorFieldId(0),
+    _visible(false)
+{
+    _sliceVector = new float[_size * _size * 4];
+    memset(_sliceVector, 0, sizeof(float) * _size * _size * 4);
+
+    int fboOrig;
+    glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &fboOrig);
+
+    //initialize the pattern texture
+    glGenTextures(1, &_patternTex);
+    glBindTexture(GL_TEXTURE_2D, _patternTex);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, NPN, NPN, 0,
+                 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+
+    //initialize frame buffer objects
+    //render buffer for projecting 3D velocity onto a 2D plane
+    glGenFramebuffersEXT(1, &_velFbo);
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _velFbo);
+
+    glGenTextures(1, &_sliceVectorTex);
+    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _sliceVectorTex);
+    glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA32F_ARB, _size, _size, 
+                 0, GL_RGBA, GL_FLOAT, NULL);
+
+    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, 
+                              GL_TEXTURE_RECTANGLE_ARB, _sliceVectorTex, 0);
+
+    //render buffer for the convolution
+    glGenFramebuffersEXT(1, &_fbo);
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _fbo);
+
+    //initialize color texture for lic
+    glGenTextures(1, &_colorTex);
+    glBindTexture(GL_TEXTURE_2D, _colorTex);
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, _width, _height, 0,
+                 GL_RGB, GL_UNSIGNED_BYTE, NULL);
+
+    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+                              GL_TEXTURE_2D, _colorTex, 0);
+
+    // Check framebuffer completeness at the end of initialization.
+    CHECK_FRAMEBUFFER_STATUS();
+
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboOrig);
+
+    _renderVelShader = new Shader();
+    _renderVelShader->loadFragmentProgram("render_vel.cg");
+
+    makePatterns();
+}
+
+LIC::~LIC()
+{
+    glDeleteTextures(1, &_patternTex);
+    glDeleteTextures(1, &_magTex);
+
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _velFbo);
+    glDeleteTextures(1, &_sliceVectorTex);
+
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _fbo);
+    glDeleteTextures(1, &_colorTex);
+
+    GLuint buffers[2] = {_velFbo, _fbo};
+    glDeleteFramebuffersEXT(2, buffers);
+
+    glDeleteLists(_disListID, _Npat);
+
+    delete _renderVelShader;
+
+    delete [] _sliceVector;
+}
+
+void 
+LIC::makePatterns() 
+{ 
+    TRACE("Enter");
+
+    if (_disListID > 0) {
+        glDeleteLists(_disListID, _Npat);
+    }
+    _disListID = glGenLists(_Npat);
+
+    TRACE("DisplayList : %d", _disListID);
+
+    int lut[256];
+    int phase[NPN][NPN];
+    GLubyte pat[NPN][NPN][4];
+    int i, j, k, t;
+
+    for (i = 0; i < 256; i++) {
+        lut[i] = i < 127 ? 0 : 255;
+    }
+    for (i = 0; i < NPN; i++) {
+        for (j = 0; j < NPN; j++) {
+            phase[i][j] = rand() >> 8;
+        }
+    }
+    for (k = 0; k < _Npat; k++) {
+        t = (k << 8) / _Npat;
+        for (i = 0; i < NPN; i++) {
+            for (j = 0; j < NPN; j++) {
+                pat[i][j][0] = pat[i][j][1] = pat[i][j][2] = 
+                    lut[(t + phase[i][j]) % 255];
+                pat[i][j][3] = _alpha;
+            }
+        }
+        glNewList(_disListID + k, GL_COMPILE);
+        glBindTexture(GL_TEXTURE_2D, _patternTex);
+        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, NPN, NPN, 0,
+                     GL_RGBA, GL_UNSIGNED_BYTE, pat);
+        glEndList();
+    }
+
+    glBindTexture(GL_TEXTURE_2D, _patternTex);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, NPN, NPN, 0,
+                 GL_RGBA, GL_UNSIGNED_BYTE, pat);
+
+    TRACE("Leave");
+}
+
+void
+LIC::makeMagnitudes()
+{
+    GLubyte mag[NMESH][NMESH][4];
+
+    //read vector field
+    for (int i = 0; i < NMESH; i++) {
+        for (int j = 0; j < NMESH; j++) {
+            float x = DM*i;
+            float y = DM*j;
+ 
+            float magnitude = sqrt(x*x+y*y)/1.414;
+
+            //from green to red
+            GLubyte r = (GLubyte)floor(magnitude*255);
+            GLubyte g = 0;
+            GLubyte b = 255 - r;
+            GLubyte a = 122;
+
+            mag[i][j][0] = r;
+            mag[i][j][1] = g;
+            mag[i][j][2] = b;
+            mag[i][j][3] = a;
+        }
+    }
+    glGenTextures(1, &_magTex);
+    glBindTexture(GL_TEXTURE_2D, _magTex);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, NMESH, NMESH, 0, GL_RGBA, 
+                 GL_UNSIGNED_BYTE, mag);
+    glBindTexture(GL_TEXTURE_2D, 0);
+}
+
+void 
+LIC::getSlice()
+{
+    int fboOrig;
+    glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &fboOrig);
+
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _velFbo);
+
+    glPushAttrib(GL_VIEWPORT_BIT | GL_ENABLE_BIT);
+
+    glClear(GL_COLOR_BUFFER_BIT);
+    glDisable(GL_DEPTH_TEST);
+    glDisable(GL_BLEND);
+
+    glViewport(0, 0, _size, _size);
+    glMatrixMode(GL_PROJECTION);
+    glPushMatrix();
+    glLoadIdentity();
+    gluOrtho2D(0, _size, 0, _size);
+    glMatrixMode(GL_MODELVIEW);
+    glPushMatrix();
+    glLoadIdentity();
+
+    glEnable(GL_TEXTURE_3D);
+    glBindTexture(GL_TEXTURE_3D, _vectorFieldId);
+
+    _renderVelShader->bind();
+    _renderVelShader->setFPTextureParameter("vel_tex", _vectorFieldId);
+    _renderVelShader->setFPParameter1f("timestep", 0.0005);
+    _renderVelShader->setFPParameter1f("vmax", _max > 100.0 ? 100.0 : _max);
+
+    switch (_axis) {
+    case AXIS_X:
+        _renderVelShader->setFPParameter3f("projection_vector", 0., 1., 1.);
+        break;
+    case AXIS_Y:
+        _renderVelShader->setFPParameter3f("projection_vector", 1., 0., 1.);
+        break;
+    default:
+    case AXIS_Z:
+        _renderVelShader->setFPParameter3f("projection_vector", 1., 1., 0.);
+        break;
+    }
+
+    glBegin(GL_QUADS);
+    {
+        switch (_axis) {
+        case AXIS_X:
+            glTexCoord3f(_offset, 0., 0.); glVertex2f(0.,    0.);
+            glTexCoord3f(_offset, 1., 0.); glVertex2f(_size, 0.);
+            glTexCoord3f(_offset, 1., 1.); glVertex2f(_size, _size);
+            glTexCoord3f(_offset, 0., 1.); glVertex2f(0.,    _size);
+            break;
+        case AXIS_Y:
+            glTexCoord3f(0., _offset, 0.); glVertex2f(0.,    0.);
+            glTexCoord3f(1., _offset, 0.); glVertex2f(_size, 0.);
+            glTexCoord3f(1., _offset, 1.); glVertex2f(_size, _size);
+            glTexCoord3f(0., _offset, 1.); glVertex2f(0.,    _size);
+            break;
+        case AXIS_Z:
+            glTexCoord3f(0., 0., _offset); glVertex2f(0.,    0.);
+            glTexCoord3f(1., 0., _offset); glVertex2f(_size, 0.);
+            glTexCoord3f(1., 1., _offset); glVertex2f(_size, _size);
+            glTexCoord3f(0., 1., _offset); glVertex2f(0.,    _size);
+            break;
+        }
+    }
+    glEnd();
+
+    _renderVelShader->disableFPTextureParameter("vel_tex");
+    _renderVelShader->unbind();
+
+    glBindTexture(GL_TEXTURE_3D, 0);
+    glDisable(GL_TEXTURE_3D);
+
+    //read the vectors
+    glReadPixels(0, 0, _size, _size, GL_RGBA, GL_FLOAT, _sliceVector);
+
+    int lim = _size * _size * 4;
+    float *v = _sliceVector;
+    for (int i = 0; i < lim; ++i) {
+        if (isnan(*v)) {
+            *v = 0.0f;    
+        }
+        ++v;
+    }
+
+    glMatrixMode(GL_PROJECTION);
+    glPopMatrix();
+    glMatrixMode(GL_MODELVIEW);
+    glPopMatrix();
+
+    glPopAttrib();
+
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboOrig);
+}
+
+//line integral convolution
+void 
+LIC::convolve()
+{
+    if (_vectorFieldId == 0) {
+        return;
+    }
+
+    int   i, j; 
+    float x1, x2, y, px, py;
+
+    int fboOrig;
+    glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &fboOrig);
+
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _fbo);
+
+    glPushAttrib(GL_VIEWPORT_BIT | GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_TEXTURE_BIT);
+
+    glMatrixMode(GL_PROJECTION);
+    glPushMatrix();
+    glLoadIdentity();
+
+    glViewport(0, 0, (GLsizei) NPIX, (GLsizei) NPIX);
+    //glTranslatef(-1.0, -1.0, 0.0); 
+    //glScalef(2.0, 2.0, 1.0);
+    glOrtho(0.0f, 1.0f, 0.0f, 1.0f, -10.0f, 10.0f);
+
+    glMatrixMode(GL_MODELVIEW);
+    glPushMatrix();
+    glLoadIdentity();
+
+    glClear(GL_COLOR_BUFFER_BIT);
+    //glDepthMask(GL_FALSE);
+    glDisable(GL_DEPTH_TEST);
+    glDisable(GL_LIGHTING);
+    glDisable(GL_ALPHA_TEST);
+
+    //_sa = 0.010*cos(_iframe*2.0*M_PI/200.0);
+    glEnable(GL_TEXTURE_2D);
+    glBindTexture(GL_TEXTURE_2D, _patternTex);
+    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+    _sa = 0.01;
+ 
+    glColor4f(1, 1, 1, 1);
+    for (i = 0; i < NMESH-1; i++) {
+        x1 = DM*i; x2 = x1 + DM;
+        glBegin(GL_QUAD_STRIP);
+        for (j = 0; j < NMESH-1; j++) {
+            y = DM*j;
+            glTexCoord2f(x1, y);
+            getVelocity(x1, y, &px, &py);
+            glVertex2f(px, py);
+
+            glTexCoord2f(x2, y);
+            getVelocity(x2, y, &px, &py);
+            glVertex2f(px, py);
+        }
+        glEnd();
+    }
+    _iframe = _iframe + 1;
+
+    glEnable(GL_BLEND);
+
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+    glEnable(GL_TEXTURE_2D);
+    glCallList(_iframe % _Npat + _disListID);
+    glBegin(GL_QUADS);
+    {
+        glTexCoord2f(0.0,   0.0);   glVertex2f(0.0, 0.0);
+        glTexCoord2f(_tmax, 0.0);   glVertex2f(1.0, 0.0);
+        glTexCoord2f(_tmax, _tmax); glVertex2f(1.0, 1.0);
+        glTexCoord2f(0.0,   _tmax); glVertex2f(0.0, 1.0);
+    }
+    glEnd();
+    glDisable(GL_TEXTURE_2D);
+
+    /*
+    //inject dye
+    glDisable(GL_TEXTURE_2D);
+    glColor4f(1.,0.8,0.,1.);
+    glBegin(GL_QUADS);
+    glVertex2d(0.6, 0.6);
+    glVertex2d(0.6, 0.62);
+    glVertex2d(0.62, 0.62);
+    glVertex2d(0.62, 0.6);
+    glEnd();
+    */
+
+    glDisable(GL_BLEND);
+    glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, NPIX, NPIX, 0);
+
+    /*
+    //blend magnitude texture
+    glBindTexture(GL_TEXTURE_2D, _magTex);
+    glEnable(GL_TEXTURE_2D);
+    glEnable(GL_BLEND);
+    glBegin(GL_QUADS);
+    glTexCoord2f(0.0,  0.0);  glVertex2f(0.0, 0.0);
+    glTexCoord2f(0.0,  1.0); glVertex2f(0.0, 1.);
+    glTexCoord2f(1.0, 1.0);  glVertex2f(1., 1.);
+    glTexCoord2f(1.0, 0.0); glVertex2f(1., 0.0);
+    glEnd();
+    */
+
+    glMatrixMode(GL_PROJECTION);
+    glPopMatrix();
+    glMatrixMode(GL_MODELVIEW);
+    glPopMatrix();
+
+    glPopAttrib();
+
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboOrig);
+}
+
+void 
+LIC::render()
+{
+    if (_vectorFieldId == 0 || !_visible) {
+        return;
+    }
+
+    //draw line integral convolution quad
+
+    glPushAttrib(GL_ENABLE_BIT | GL_LIGHTING_BIT | GL_TEXTURE_BIT);
+    glBindTexture(GL_TEXTURE_2D, _colorTex);
+    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+    glEnable(GL_TEXTURE_2D);
+    //glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
+    //glEnable(GL_LIGHTING);
+    glDisable(GL_LIGHTING);
+    glEnable(GL_DEPTH_TEST);
+
+    glMatrixMode(GL_MODELVIEW);
+    glPushMatrix();
+
+    glTranslatef(_origin.x, _origin.y, _origin.z);
+    glScalef(_scale.x, _scale.y, _scale.z);
+
+    glColor4f(1, 1, 1, 1);
+    glBegin(GL_QUADS);
+    switch (_axis) {
+    case AXIS_X:
+        glNormal3f(1, 0, 0);
+        glTexCoord2f(0, 0); glVertex3f(_offset, 0, 0);
+        glTexCoord2f(1, 0); glVertex3f(_offset, 1, 0);
+        glTexCoord2f(1, 1); glVertex3f(_offset, 1, 1);
+        glTexCoord2f(0, 1); glVertex3f(_offset, 0, 1);
+        break;
+    case AXIS_Y:
+        glNormal3f(0, 1, 0);
+        glTexCoord2f(0, 0); glVertex3f(0, _offset, 0);
+        glTexCoord2f(1, 0); glVertex3f(1, _offset, 0);
+        glTexCoord2f(1, 1); glVertex3f(1, _offset, 1);
+        glTexCoord2f(0, 1); glVertex3f(0, _offset, 1);
+        break;
+    case AXIS_Z:
+        glNormal3f(0, 0, 1);
+        glTexCoord2f(0, 0); glVertex3f(0, 0, _offset);
+        glTexCoord2f(1, 0); glVertex3f(1, 0, _offset);
+        glTexCoord2f(1, 1); glVertex3f(1, 1, _offset);
+        glTexCoord2f(0, 1); glVertex3f(0, 1, _offset);
+        break;
+    }
+    glEnd();
+
+    glPopMatrix();
+
+    glBindTexture(GL_TEXTURE_2D, 0);
+
+    glPopAttrib();
+}
+
+void 
+LIC::setVectorField(unsigned int texID, const Vector3f& origin, 
+                      float scaleX, float scaleY, float scaleZ, float max)
+{
+    TRACE("LIC: vector field is assigned [%d]", texID);
+    _vectorFieldId = texID;
+    _origin = origin;
+    _scale.set(scaleX, scaleY, scaleZ);
+    _max = max;
+
+    makePatterns();
+
+    getSlice();
+}
+
+void 
+LIC::getVelocity(float x, float y, float *px, float *py) 
+{
+   float vx, vy, r;
+
+   int xi = (int)(x*_size);
+   int yi = (int)(y*_size);
+
+    //TRACE("(xi yi) = (%d %d), ", xi, yi);
+   switch (_axis) {
+   case AXIS_X:
+       vx = _sliceVector[4 * (xi+yi*_size)+2];
+       vy = _sliceVector[4 * (xi+yi*_size)+1];
+       break;
+   case AXIS_Y:
+       vx = _sliceVector[4 * (xi+yi*_size)];
+       vy = _sliceVector[4 * (xi+yi*_size)+2];
+       break;
+   case AXIS_Z:
+   default:
+       vx = _sliceVector[4 * (xi+yi*_size)];
+       vy = _sliceVector[4 * (xi+yi*_size)+1];
+       break;
+   }
+   r  = vx*vx + vy*vy;
+
+    //TRACE("(vx vx) = (%f %f), r=%f, ", vx, vy, r);
+   if (r > (_dmax * _dmax)) {
+      r  = sqrt(r);
+      vx *= _dmax/r;
+      vy *= _dmax/r;
+   }
+
+   *px = x + vx;
+   *py = y + vy;
+
+    //TRACE("vel %f %f -> %f %f, (dmax = %f)", x, y, *px, *py, dmax);
+}
+
+void 
+LIC::setSlicePosition(float offset)
+{
+    _offset = offset;
+    getSlice();
+}
+
+void LIC::setSliceAxis(FlowSliceAxis axis)
+{
+    _axis = axis;
+}
+
+void LIC::reset()
+{
+    makePatterns();
+}
Index: /nanovis/tags/1.1.4/LIC.h
===================================================================
--- /nanovis/tags/1.1.4/LIC.h	(revision 4930)
+++ /nanovis/tags/1.1.4/LIC.h	(revision 4930)
@@ -0,0 +1,118 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ *  Authors:
+ *    Wei Qiao <qiaow@purdue.edu>
+ */
+#ifndef NV_LIC_H
+#define NV_LIC_H
+
+#include <GL/glew.h>
+
+#include <vrmath/Vector3f.h>
+
+#include "FlowTypes.h"
+#include "Volume.h"
+#include "Shader.h"
+
+namespace nv {
+
+class LIC
+{ 
+public:
+    LIC(FlowSliceAxis axis = AXIS_Z, float offset = 0.f);
+    ~LIC();
+
+    /// project 3D vectors to a 2D slice for line integral convolution
+    void convolve();
+
+    /// Display the convolution result
+    void render();
+
+    void setSlicePosition(float pos);
+
+    float getSlicePosition() const
+    {
+        return _offset;
+    }
+
+    /** 
+     * \brief Specify the perpendicular axis
+     */
+    void setSliceAxis(FlowSliceAxis axis);
+
+    FlowSliceAxis getSliceAxis() const
+    {
+        return _axis;
+    }
+
+    void setVectorField(unsigned int texID, const vrmath::Vector3f& origin,
+                        float scaleX, float scaleY, float scaleZ, float max);
+
+    void reset();
+
+    void visible(bool state)
+    {
+	_visible = state;
+    }
+
+    bool visible() const
+    {
+	return _visible;
+    }
+
+private:
+    void getVelocity(float x, float y, float *px, float *py);
+
+    void getSlice();
+
+    void makePatterns();
+
+    void makeMagnitudes();
+
+    /**
+     * \brief the normal vector of the LIC plane, 
+     * the inherited Vector3 location is its center
+     */
+    vrmath::Vector3f _normal;
+
+    int _width, _height;
+    int _size;			/**< The lic is a square of size, it can
+                                   be stretched */
+    float *_sliceVector;        /**< Storage for the per slice vectors
+                                   driving the flow */
+    vrmath::Vector3f _scale;    /**< Scaling factor stretching the lic
+                                   plane to fit the actual dimensions */
+    vrmath::Vector3f _origin;
+    float _offset;              ///< [0,1] offset of slice plane
+    FlowSliceAxis _axis;        ///< Axis normal to slice plane
+
+    //some convolve variables. They can pretty much stay fixed
+    int _iframe;
+    int _Npat;
+    int _alpha;
+    float _sa;
+    float _tmax;
+    float _dmax;
+    float _max;
+
+    GLuint _disListID;
+
+    Shader *_renderVelShader;
+
+    GLuint _colorTex, _patternTex, _magTex;
+    GLuint _fbo, _velFbo, _sliceVectorTex;  // For projecting 3d vector to 2d
+					    // vector on a plane.
+    GLuint _vectorFieldId;
+
+    Volume *_vectorField; 
+    /**
+     * flag for rendering
+     */
+    bool _visible;			// Indicates if LIC plane is displayed.
+};
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/Makefile.in
===================================================================
--- /nanovis/tags/1.1.4/Makefile.in	(revision 4930)
+++ /nanovis/tags/1.1.4/Makefile.in	(revision 4930)
@@ -0,0 +1,326 @@
+TRACE			= #yes
+USE_POINTSET_RENDERER	= #yes
+USE_PARTICLE_SYSTEM	= #yes
+
+SHELL = /bin/sh
+
+bindir          = @bindir@
+datadir         = @datadir@
+datarootdir     = @datarootdir@
+exec_prefix     = @exec_prefix@
+includedir      = @includedir@
+libdir          = @libdir@
+mandir          = @mandir@
+prefix          = @prefix@
+srcdir          = @srcdir@
+
+VPATH           = $(srcdir)
+
+INSTALL         = @INSTALL@
+MKDIR_P         = @MKDIR_P@
+
+#Why are these files installed owner writable?
+INSTALL_PROGRAM = ${INSTALL} -m 0555
+INSTALL_DATA    = ${INSTALL} -m 0444
+INSTALL_SCRIPT  = ${INSTALL} -m 0444
+RM              = rm -f
+
+CG_INC_SPEC     = @CG_INC_SPEC@
+CG_LIB_SPEC     = @CG_LIB_SPEC@
+
+GL_INC_SPEC     =
+GL_LIB_SPEC     = -lglut -lGLEW -lGLU -lGL
+GRAPHICS_DIR	  = ./graphics
+GRAPHICS_INC_SPEC = -I$(srcdir)/$(GRAPHICS_DIR)/include
+GRAPHICS_LIB	  = $(GRAPHICS_DIR)/nvgraphics.a
+GRAPHICS_LIB_SPEC = $(GRAPHICS_LIB)
+IMG_DIR		= ./imgLoaders
+IMG_INC_SPEC	= -I$(srcdir)/$(IMG_DIR)
+IMG_LIB		= $(IMG_DIR)/ImageLoaders.a
+IMG_LIB_SPEC	= $(IMG_LIB)
+MAT_DIR		= ./newmat11
+MAT_INC_SPEC	= -I$(srcdir)/$(MAT_DIR)
+MAT_LIB		= $(MAT_DIR)/newmat11.a
+MAT_LIB_SPEC	= $(MAT_LIB)
+UTIL_DIR	= ./util
+UTIL_INC_SPEC	= -I$(srcdir)/$(UTIL_DIR)
+UTIL_LIB	= $(UTIL_DIR)/nvutil.a
+UTIL_LIB_SPEC	= $(UTIL_LIB)
+VRMATH_DIR	= ./vrmath
+VRMATH_INC_SPEC	= -I$(srcdir)/$(VRMATH_DIR)/include
+VRMATH_LIB	= $(VRMATH_DIR)/vrmath.a
+VRMATH_LIB_SPEC	= $(VRMATH_LIB)
+
+EXTRA_LIBS      = -lm -lpthread
+RP_DIR          =  @RP_DIR@
+RP_INC_SPEC     = -I$(RP_DIR)/include -I$(RP_DIR)/include/rappture2
+RP_LIB_SPEC     = -L$(RP_DIR)/lib -lrappture2 -lrappture -lexpat -lz
+
+TCL_LIB_SPEC    = @TCL_LIB_SPEC@
+TCL_INC_SPEC    = @TCL_INC_SPEC@
+
+LD_RUN_PATH     = $(libdir):@LD_RPATH@
+
+SVN_VERSION	= $(shell svnversion $(srcdir))
+STATSDIR	= @STATSDIR@
+
+LIBS		= \
+		$(RP_LIB_SPEC) \
+		$(TCL_LIB_SPEC) \
+		$(CG_LIB_SPEC) \
+		$(GL_LIB_SPEC) \
+		$(EXTRA_LIBS) \
+		-Wl,-rpath,$(LD_RUN_PATH)
+
+STATIC_LIBS	= \
+		$(GRAPHICS_LIB) \
+		$(IMG_LIB) \
+		$(UTIL_LIB) \
+		$(VRMATH_LIB)
+
+INCLUDES	= \
+		-I. \
+		-I$(srcdir) \
+		$(IMG_INC_SPEC) \
+		$(VRMATH_INC_SPEC) \
+		$(TCL_INC_SPEC) \
+		$(CG_INC_SPEC) \
+		$(GL_INC_SPEC) \
+		$(RP_INC_SPEC)
+
+CC              = @CC@
+CXX             = @CXX@
+CFLAGS          = @CFLAGS@
+EXTRA_CFLAGS    = -Wall
+DEFINES         = -DSVN_VERSION=\"$(SVN_VERSION)\" -DSTATSDIR=\"$(STATSDIR)\"
+ifdef TRACE
+DEFINES		+= -DWANT_TRACE
+endif
+ifdef USE_POINTSET_RENDERER
+DEFINES         += -DUSE_POINTSET_RENDERER
+endif
+CXX_SWITCHES    = $(CFLAGS) $(EXTRA_CFLAGS) $(DEFINES) $(INCLUDES)
+
+OBJS		= \
+		Axis.o \
+		Camera.o \
+		Chain.o \
+		CmdProc.o \
+		ColorTableShader.o \
+		Command.o \
+		ContourLineFilter.o \
+		ConvexPolygon.o \
+		Flow.o \
+		FlowBox.o \
+		FlowCmd.o \
+		FlowParticles.o \
+		GradientFilter.o \
+		Grid.o \
+		HeightMap.o \
+		LIC.o \
+		ParticleAdvectionShader.o \
+		ParticleRenderer.o \
+		PerfQuery.o \
+		Plane.o \
+		PlaneRenderer.o \
+		ReadBuffer.o \
+		ReaderCommon.o \
+		RegularVolumeShader.o \
+		RenderVertexArray.o \
+		Shader.o \
+		StdVertexShader.o \
+		Switch.o \
+		Texture1D.o \
+		Texture2D.o \
+		Texture3D.o \
+		Trace.o \
+		TransferFunction.o \
+		Unirect.o \
+		VelocityArrowsSlice.o \
+		Volume.o \
+		VolumeInterpolator.o \
+		VolumeRenderer.o \
+		VolumeShader.o \
+		VtkReader.o \
+		ZincBlendeReconstructor.o \
+		ZincBlendeVolume.o \
+		ZincBlendeVolumeShader.o \
+		dxReader.o \
+		md5.o \
+		nanovis.o \
+		nanovisServer.o
+
+resources	= \
+		$(srcdir)/resources/arrows.bmp \
+		$(srcdir)/resources/particle2.bmp \
+		$(srcdir)/resources/verdana.fnt \
+		$(srcdir)/resources/verdana_bold.fnt
+
+shaders		= \
+		$(srcdir)/shaders/common.cg \
+		$(srcdir)/shaders/cutplane_fp.cg \
+		$(srcdir)/shaders/cutplane_vp.cg \
+		$(srcdir)/shaders/heightcolor.cg \
+		$(srcdir)/shaders/one_plane.cg \
+		$(srcdir)/shaders/one_volume.cg \
+                $(srcdir)/shaders/particle_common.cg \
+		$(srcdir)/shaders/queryvelocity.cg \
+		$(srcdir)/shaders/render_vel.cg \
+		$(srcdir)/shaders/update_pos.cg \
+                $(srcdir)/shaders/velocityslicefp.cg \
+                $(srcdir)/shaders/velocityslicevp.cg \
+		$(srcdir)/shaders/vertex_std.cg \
+		$(srcdir)/shaders/zincblende_volume.cg
+
+ifdef USE_PARTICLE_SYSTEM
+OBJS +=		ParticleEmitter.o \
+		ParticleSystem.o \
+		ParticleSystemFactory.o
+
+shaders +=      $(srcdir)/shaders/passthrough.cg \
+		$(srcdir)/shaders/distance.cg \
+		$(srcdir)/shaders/mergesort.cg \
+		$(srcdir)/shaders/moveparticles.cg \
+		$(srcdir)/shaders/particlefp.cg \
+		$(srcdir)/shaders/particlevp.cg
+endif
+
+ifdef USE_POINTSET_RENDERER
+OBJS += 	BucketSort.o \
+		PCASplit.o \
+		PointSet.o \
+		PointSetRenderer.o \
+		PointShader.o
+STATIC_LIBS +=	$(MAT_LIB)
+INCLUDES +=	$(MAT_INC_SPEC)
+shaders +=      $(srcdir)/shaders/pointsvp.cg
+endif
+
+.PHONY: all install install-resources install-shaders install-nanovis docs clean-docs clean distclean graphics imgloaders newmat11 util vrmath
+
+all: nanovis 
+
+install: install-nanovis install-resources install-shaders
+
+docs:
+	$(MKDIR_P) -m 0755 docs/doxygen
+	doxygen
+
+graphics:		$(GRAPHICS_LIB)
+imgloaders:		$(IMG_LIB)
+newmat11:		$(MAT_LIB)
+util:			$(UTIL_LIB)
+vrmath:			$(VRMATH_LIB)
+
+$(GRAPHICS_LIB): 
+	$(MAKE) -C $(GRAPHICS_DIR) all
+
+$(IMG_LIB): 
+	$(MAKE) -C $(IMG_DIR) all
+
+$(MAT_LIB):
+	$(MAKE) -C $(MAT_DIR) all
+
+$(UTIL_LIB): 
+	$(MAKE) -C $(UTIL_DIR) all
+
+$(VRMATH_LIB):
+	$(MAKE) -C $(VRMATH_DIR) all
+
+nanovis: $(OBJS) $(STATIC_LIBS)
+	$(CXX) $(CXX_SWITCHES) -o $@ $^ $(LIBS)
+
+.cpp.o:
+	$(CXX) $(CXX_SWITCHES) -o $@ -c $<
+
+install-resources:
+	$(MKDIR_P) $(libdir)/resources
+	@for i in $(resources) ; do \
+	    echo "installing $$i..." ; \
+	    $(INSTALL_DATA) $$i $(libdir)/resources ; \
+	done
+
+install-shaders:
+	$(MKDIR_P) $(libdir)/shaders
+	@for i in $(shaders) ; do \
+	    echo "installing $$i..." ; \
+	    $(INSTALL_DATA) $$i $(libdir)/shaders ; \
+	done
+
+install-nanovis: nanovis
+	$(INSTALL_PROGRAM) nanovis $(bindir)
+
+clean:
+	$(MAKE) -C $(MAT_DIR) clean
+	$(MAKE) -C $(GRAPHICS_DIR) clean
+	$(MAKE) -C $(IMG_DIR) clean
+	$(MAKE) -C $(UTIL_DIR) clean
+	$(MAKE) -C $(VRMATH_DIR) clean
+	$(RM) nanovis client *.o
+
+clean-docs:
+	$(RM) -r docs
+
+distclean: clean clean-docs
+	$(MAKE) -C $(MAT_DIR) distclean
+	$(MAKE) -C $(GRAPHICS_DIR) distclean
+	$(MAKE) -C $(IMG_DIR) distclean
+	$(MAKE) -C $(UTIL_DIR) distclean
+	$(MAKE) -C $(VRMATH_DIR) distclean
+	$(RM) Makefile nvconf.h *~
+
+Axis.o: Axis.cpp Axis.h Chain.h
+BucketSort.o: BucketSort.cpp BucketSort.h $(VRMATH_DIR)/include/vrmath/Vector3f.h $(VRMATH_DIR)/include/vrmath/Vector4f.h $(VRMATH_DIR)/include/vrmath/Matrix4x4d.h PCASplit.h
+Camera.o: Camera.cpp Camera.h config.h $(VRMATH_DIR)/include/vrmath/Matrix4x4d.h
+Chain.o: Chain.cpp Chain.h
+CmdProc.o: CmdProc.cpp CmdProc.h
+ColorTableShader.o: ColorTableShader.cpp ColorTableShader.h Shader.h
+Command.o: Command.cpp nanovis.h nanovisServer.h ReadBuffer.h config.h define.h FlowCmd.h CmdProc.h Trace.h PlaneRenderer.h dxReader.h Grid.h HeightMap.h Camera.h ZincBlendeReconstructor.h Unirect.h Volume.h VolumeRenderer.h
+ContourLineFilter.o: ContourLineFilter.cpp ContourLineFilter.h
+ConvexPolygon.o: ConvexPolygon.cpp ConvexPolygon.h $(VRMATH_DIR)/include/vrmath/Vector4f.h $(VRMATH_DIR)/include/vrmath/Matrix4x4d.h Plane.h
+Flow.o: Flow.cpp Flow.h FlowCmd.h FlowTypes.h FlowBox.h FlowParticles.h LIC.h VelocityArrowsSlice.h Switch.h Unirect.h Volume.h TransferFunction.h Trace.h
+FlowBox.o: FlowBox.cpp FlowBox.h FlowTypes.h Switch.h Trace.h Volume.h $(VRMATH_DIR)/include/vrmath/Vector3f.h $(VRMATH_DIR)/include/vrmath/Vector4f.h $(VRMATH_DIR)/include/vrmath/Matrix4x4d.h
+<FlowCmd.o: FlowCmd.cpp FlowCmd.h FlowParticles.h FlowBox.h FlowTypes.h Command.h Switch.h Trace.h TransferFunction.h nanovis.h nanovisServer.h CmdProc.h LIC.h Unirect.h Volume.h VelocityArrowsSlice.h $(VRMATH_DIR)/include/vrmath/Vector3f.h
+FlowParticles.o: FlowParticles.cpp FlowParticles.h FlowTypes.h FlowCmd.h Switch.h Trace.h ParticleRenderer.h Volume.h $(VRMATH_DIR)/include/vrmath/Vector3f.h $(VRMATH_DIR)/include/vrmath/Vector4f.h
+GradientFilter.o: GradientFilter.cpp GradientFilter.h
+Grid.o: Grid.cpp Grid.h Axis.h Chain.h $(UTIL_DIR)/Fonts.h $(VRMATH_DIR)/include/vrmath/Color4f.h $(VRMATH_DIR)/include/vrmath/Vector4f.h
+HeightMap.o: HeightMap.cpp HeightMap.h Shader.h
+LIC.o: LIC.cpp LIC.h FlowTypes.h Shader.h define.h
+ParticleAdvectionShader.o: ParticleAdvectionShader.cpp ParticleAdvectionShader.h Shader.h
+ParticleEmitter.o: ParticleEmitter.cpp ParticleEmitter.h
+ParticleRenderer.o: ParticleRenderer.cpp ParticleRenderer.h FlowTypes.h define.h
+ParticleSystem.o: ParticleSystem.cpp ParticleSystem.h
+ParticleSystemFactory.o: ParticleSystemFactory.cpp ParticleSystemFactory.h
+PCASplit.o: PCASplit.cpp PCASplit.h
+PerfQuery.o: PerfQuery.cpp PerfQuery.h
+Plane.o: Plane.cpp Plane.h $(VRMATH_DIR)/include/vrmath/Vector4f.h $(VRMATH_DIR)/include/vrmath/Matrix4x4d.h
+PlaneRenderer.o: PlaneRenderer.cpp PlaneRenderer.h
+PointSet.o: PointSet.cpp PointSet.h
+PointSetRenderer.o: PointSetRenderer.cpp PointSetRenderer.h
+PointShader.o: PointShader.cpp PointShader.h
+ReadBuffer.o: ReadBuffer.cpp ReadBuffer.h Trace.h
+ReaderCommon.o: ReaderCommon.cpp ReaderCommon.h GradientFilter.h $(VRMATH_DIR)/include/vrmath/Vector3f.h
+RegularVolumeShader.o: RegularVolumeShader.cpp RegularVolumeShader.h VolumeShader.h Shader.h
+RenderVertexArray.o: RenderVertexArray.cpp RenderVertexArray.h
+Shader.o: Shader.cpp Shader.h
+StdVertexShader.o: StdVertexShader.cpp StdVertexShader.h Shader.h
+Switch.o: Switch.cpp Switch.h
+Texture1D.o: Texture1D.cpp Texture1D.h
+Texture2D.o: Texture2D.cpp Texture2D.h config.h define.h
+Texture3D.o: Texture3D.cpp Texture3D.h config.h define.h
+Trace.o: Trace.cpp Trace.h
+TransferFunction.o: TransferFunction.cpp
+Unirect.o: Unirect.cpp Unirect.h Command.h Trace.h
+VelocityArrowsSlice.o: VelocityArrowsSlice.cpp VelocityArrowsSlice.h nanovis.h FlowTypes.h Camera.h Volume.h Shader.h
+Volume.o: Volume.cpp Volume.h config.h define.h
+VolumeInterpolator.o: VolumeInterpolator.cpp VolumeInterpolator.h Volume.h
+VolumeRenderer.o: VolumeRenderer.cpp VolumeRenderer.h ConvexPolygon.h Volume.h nanovis.h Trace.h Plane.h StdVertexShader.h Shader.h
+VolumeShader.o: VolumeShader.cpp VolumeShader.h Shader.h
+VtkReader.o: VtkReader.h Trace.h Volume.h $(VRMATH_DIR)/include/vrmath/Vector3f.h ReaderCommon.h nanovis.h config.h
+ZincBlendeReconstructor.o: ZincBlendeReconstructor.cpp ZincBlendeReconstructor.h ZincBlendeVolume.h Volume.h $(VRMATH_DIR)/include/vrmath/Vector3f.h
+ZincBlendeVolume.o: ZincBlendeVolume.cpp ZincBlendeVolume.h config.h define.h
+ZincBlendeVolumeShader.o: ZincBlendeVolumeShader.cpp ZincBlendeVolumeShader.h VolumeShader.h Shader.h
+dxReader.o: dxReader.cpp ReaderCommon.h config.h nanovis.h Unirect.h ZincBlendeVolume.h ZincBlendeReconstructor.h
+md5.o: md5.h
+nanovis.o: nanovis.cpp nanovis.h nanovisServer.h config.h define.h Command.h Flow.h Grid.h HeightMap.h Camera.h LIC.h ZincBlendeReconstructor.h PerfQuery.h PlaneRenderer.h PointSetRenderer.h PointSet.h Switch.h Trace.h Unirect.h VelocityArrowsSlice.h VolumeInterpolator.h VolumeRenderer.h ZincBlendeVolume.h Axis.h Chain.h $(UTIL_DIR)/Fonts.h
+nanovisServer.o: nanovisServer.cpp nanovisServer.h config.h nanovis.h define.h Command.h ReadBuffer.h Shader.h Trace.h
Index: /nanovis/tags/1.1.4/PCASplit.cpp
===================================================================
--- /nanovis/tags/1.1.4/PCASplit.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/PCASplit.cpp	(revision 4930)
@@ -0,0 +1,380 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#include <stdio.h>
+
+#define WANT_STREAM                  // include.h will get stream fns
+#define WANT_MATH                    // include.h will get math fns
+                                     // newmatap.h will get include.h
+#include <newmatap.h>                // need matrix applications
+#include <newmatio.h>                // need matrix output routines
+#include <newmatrc.h>
+#ifdef use_namespace
+using namespace NEWMAT;              // access NEWMAT namespace
+#endif
+
+#include "PCASplit.h"
+#include "Trace.h"
+
+using namespace vrmath;
+using namespace PCA;
+
+PCASplit::PCASplit() : 
+    _maxLevel(4),
+    _minDistance(0.5f),
+    _distanceScale(0.2f),
+    _indexCount(0),
+    _finalMaxLevel(0)
+{
+    _indices = new unsigned int[MAX_INDEX];
+    _memClusterChunk1 = new ClusterListNode[MAX_INDEX];
+    _memClusterChunk2 = new ClusterListNode[MAX_INDEX];
+    _curMemClusterChunk = _memClusterChunk1;
+    _memClusterChunkIndex = 0;
+}
+
+PCASplit::~PCASplit()
+{
+    delete [] _indices;
+    delete [] _memClusterChunk1;
+    delete [] _memClusterChunk2;
+}
+
+void 
+PCASplit::computeCentroid(Point *data, int count, Vector3f& mean)
+{
+    float sumx = 0, sumy = 0, sumz = 0;
+    float size = 0;
+    float sumsize = 0;
+    for (int i = 0; i < count; ++i) {
+	size = data[i].size;
+	sumx += data[i].position.x * size;
+	sumy += data[i].position.y * size;
+	sumz += data[i].position.z * size;
+	sumsize += size;
+    }
+    sumsize = 1.0f / sumsize;
+    mean.set(sumx * sumsize, sumy * sumsize, sumz * sumsize);
+}
+
+void 
+PCASplit::computeCovariant(Point *data, int count, const Vector3f& mean, 
+                           float *m)
+{
+    memset(m, 0, sizeof(float) * 9);
+
+    for (int i = 0; i < count; ++i) {
+	m[0] += (data[i].position.x - mean.x) * (data[i].position.x - mean.x);
+	m[1] += (data[i].position.x - mean.x) * (data[i].position.y - mean.y);
+	m[2] += (data[i].position.x - mean.x) * (data[i].position.z - mean.z);
+	m[4] += (data[i].position.y - mean.y) * (data[i].position.y - mean.y);
+	m[5] += (data[i].position.y - mean.y) * (data[i].position.z - mean.z);
+	m[8] += (data[i].position.z - mean.z) * (data[i].position.z - mean.z);
+    }
+    
+    float invCount = 1.0f / (count - 1);
+    m[0] *= invCount;
+    m[1] *= invCount;
+    m[2] *= invCount;
+    m[4] *= invCount;
+    m[5] *= invCount;
+    m[8] *= invCount;
+    m[3] = m[1];
+    m[6] = m[2];
+    m[7] = m[5];
+}
+
+void 
+PCASplit::computeDistortion(Point *data, int count, const Vector3f& mean, 
+			    float& distortion, float& finalSize)
+{
+    distortion = 0.0f;
+    finalSize = 0.0f;
+        
+    float maxSize = 0.0f;
+    float distance;
+    for (int i = 0; i < count; ++i) {
+        // sum 
+        distance = mean.distanceSquare(data[i].position.x, data[i].position.y, data[i].position.z);
+        distortion += distance;
+
+        if (data[i].size > maxSize) {
+            maxSize = data[i].size;
+        }
+
+        /*
+          finalSize += data[i].size * sqrt(distance);
+        */
+        if (distance > finalSize) {
+            finalSize = distance;
+        }
+    }
+    // equation 2
+    //finalSize = 0.5f * sqrt (finalSize) / (float) (count - 1) + maxSize;
+    finalSize = sqrt (finalSize) + maxSize;
+}
+
+void
+PCASplit::init()
+{
+    _curClusterNode = NULL;
+    _curClusterCount = 0;
+}
+
+Cluster *
+PCASplit::createClusterBlock(ClusterListNode *clusterList, int count, int level)
+{
+    static int cc = 0;
+    cc += count;
+    Cluster *clusterBlock = new Cluster[count];
+
+    _clusterHeader->numOfClusters[level - 1] = count;
+    _clusterHeader->startPointerCluster[level - 1] = clusterBlock;
+
+    TRACE("Cluster created %d [in level %d]:total %d", count, level, cc);
+
+    int i = 0;
+    ClusterListNode *clusterNode = clusterList;
+    while (clusterNode) {
+        clusterBlock[i].centroid = clusterList->data->centroid_t;
+        clusterBlock[i].level = level;
+        clusterBlock[i].scale = clusterList->data->scale_t;
+
+        clusterNode = clusterNode->next;
+        ++i;
+    }
+    if (count != i) {
+        ERROR("Problem walking clusterList: count: %d, i: %d", count, i);
+    }
+    return clusterBlock;
+}
+
+ClusterAccel *
+PCASplit::doIt(Point *data, int count)
+{
+    init();
+
+    _clusterHeader = new ClusterAccel(_maxLevel);
+
+    Cluster *root = new Cluster;
+    Cluster_t *cluster_t = new Cluster_t();
+    cluster_t->points_t = data;
+    cluster_t->numOfPoints_t = count;
+    root->level = 1;
+
+    _clusterHeader->root = root;
+    _clusterHeader->numOfClusters[0] = 1;
+    _clusterHeader->startPointerCluster[0] = root;
+
+    Vector3f mean;
+    float distortion, scale;
+
+    computeCentroid(cluster_t->points_t, cluster_t->numOfPoints_t, mean);
+    computeDistortion(cluster_t->points_t, cluster_t->numOfPoints_t, mean, 
+		      distortion, scale);
+
+    cluster_t->centroid_t = mean;
+    cluster_t->scale_t = scale;
+
+    float mindistance = _minDistance;
+    int level = 2;
+
+    ClusterListNode *clustNodeList = &(_memClusterChunk2[0]);
+    clustNodeList->data = cluster_t;
+    clustNodeList->next = NULL;
+
+    _curRoot = root;
+    do {
+        analyze(clustNodeList, _curRoot, level, mindistance);
+
+        mindistance *= _distanceScale;
+        ++level;
+
+        // swap memory buffer & init
+        _curMemClusterChunk = (_curMemClusterChunk == _memClusterChunk1) ?
+            _memClusterChunk2 : _memClusterChunk1;
+        _memClusterChunkIndex = 0;
+
+        clustNodeList = _curClusterNode;
+    } while (level <= _maxLevel);
+
+    return _clusterHeader;
+}
+
+void 
+PCASplit::addLeafCluster(Cluster_t *cluster)
+{
+    ClusterListNode *clusterNode = 
+        &_curMemClusterChunk[_memClusterChunkIndex++];
+    clusterNode->data = cluster;
+    clusterNode->next = _curClusterNode;
+    _curClusterNode = clusterNode;
+    ++_curClusterCount;
+}
+
+void 
+PCASplit::split(Point *data, int count, float limit)
+{
+    Vector3f mean;
+    float m[9];
+
+    computeCentroid(data, count, mean);
+    float scale, distortion;
+    computeDistortion(data, count, mean, distortion, scale);
+
+    //if (distortion < limit)
+    if (scale < limit) {
+	Cluster_t *cluster_t = new Cluster_t();
+	cluster_t->centroid_t = mean;
+	cluster_t->points_t = data;
+	cluster_t->numOfPoints_t = count;
+	cluster_t->scale_t = scale;
+	addLeafCluster(cluster_t);
+	return;
+    }
+
+    computeCovariant(data, count, mean, m);
+
+    // Begin newmat11 dependency
+
+    SymmetricMatrix A(3);
+    for (int i = 1; i <= 3; ++i) {
+        for (int j = 1; j <= i; ++j) {
+	    A(i, j) = m[(i - 1) * 3 + j - 1];
+	}
+    }
+
+    Matrix U;
+    DiagonalMatrix D;
+    eigenvalues(A, D ,U);
+    Vector3f emax(U(1, 3), U(2, 3), U(3, 3));
+
+    // End newmat11 dependency
+
+    int left = 0, right = count - 1;
+
+    Point p;
+    for (;left < right;) {
+        while (left < count && emax.dot(data[left].position - mean) >= 0.0f) {
+            ++left;
+        }
+        while (right >= 0 && emax.dot(data[right].position - mean) < 0.0f) {
+            --right;
+        }
+        if (left > right) {
+            break;
+        }
+
+        p = data[left];
+        data[left] = data[right];
+        data[right] = p;
+        ++left, --right;
+    }
+
+    if (left == 0 || right == count - 1) {
+        TRACE("error");
+        exit(1);
+    } else {
+        split(data, left, limit);
+        split(data + left, count - left, limit);
+    }
+}
+
+void 
+PCASplit::analyze(ClusterListNode *clusterNode, Cluster *parent, int level, 
+		  float limit)
+{
+    if (level > _maxLevel) {
+        return;
+    } 
+    if (level > _finalMaxLevel) {
+        _finalMaxLevel = level;
+    }
+
+    init();
+
+    ClusterListNode *clNode = clusterNode;
+
+    // initialize the indexCount of indices
+    _indexCount = 0;
+    while (clNode) {
+        if (clNode->data) {
+            split(clNode->data->points_t, clNode->data->numOfPoints_t, limit);
+            _indices[_indexCount++] = _curClusterCount;
+        }
+        clNode = clNode->next;
+    }
+
+    //Vector3f mean;
+    //computeCentroid(cluster->points, cluster->numOfPoints, mean);
+
+    // the process values of split are in _curClusterNode and _curClusterCount
+    ClusterListNode *curClusterNode = _curClusterNode;
+    unsigned int curClusterNodeCount = _curClusterCount;
+
+    if (curClusterNodeCount) {
+	// create and init centroid
+        Cluster *retClusterBlock = 
+            createClusterBlock(curClusterNode, curClusterNodeCount, level);
+
+        _curRoot = retClusterBlock;
+
+        if (level == _maxLevel) {
+            ClusterListNode *node = curClusterNode;
+            if (_indexCount > 0) {
+                // for parent
+                Point *points = new Point[curClusterNodeCount];
+
+                parent[0].setChildren(retClusterBlock, _indices[0]);
+                parent[0].setPoints(points, _indices[0]);
+
+                for (unsigned int i = 0, in = 0; i < curClusterNodeCount; ++i) {
+                    if (i >= _indices[in]) {
+                        in++;
+                        parent[in].setChildren(retClusterBlock + _indices[in - 1], _indices[in] - _indices[in - 1]);
+                        parent[in].setPoints(points + _indices[in - 1], _indices[in] - _indices[in - 1]);
+                    }
+
+                    retClusterBlock[i].scale = node->data->scale_t;
+                    retClusterBlock[i].centroid = node->data->centroid_t;
+                    retClusterBlock[i].points = node->data->points_t;
+                    retClusterBlock[i].numOfPoints = node->data->numOfPoints_t;
+                    retClusterBlock[i].color.set(float(rand()) / RAND_MAX, 
+                                                 float(rand()) / RAND_MAX, 
+                                                 float(rand()) / RAND_MAX,
+                                                 0.2);
+
+                    points[i].position = node->data->centroid_t;
+                    points[i].color.set(1.0f, 1.0f, 1.0f, 0.2f);
+                    points[i].size = node->data->scale_t;
+
+                    node = node->next;
+                }
+            }
+        } else {
+            Point *points = new Point[curClusterNodeCount];
+            ClusterListNode *node = curClusterNode;
+
+            if (_indexCount > 0) {
+                parent[0].setPoints(points, _indices[0]);
+                parent[0].setChildren(retClusterBlock, _indices[0]);
+                for (int k = 1; k < _indexCount; ++k) {
+                    parent[k].setPoints(points + _indices[k - 1], 
+                                        _indices[k] - _indices[k - 1]);
+                    parent[k].setChildren(retClusterBlock + _indices[k - 1], 
+                                          _indices[k] - _indices[k - 1]);
+                }
+
+                // set points of sub-clusters
+                for (unsigned int i = 0; i < curClusterNodeCount; ++i) {
+                    points[i].position = node->data->centroid_t;
+                    points[i].color.set(1.0f, 1.0f, 1.0f, 0.2f);
+                    points[i].size = node->data->scale_t;
+                    node = node->next;
+                }
+            }
+        }
+    }
+}
Index: /nanovis/tags/1.1.4/PCASplit.h
===================================================================
--- /nanovis/tags/1.1.4/PCASplit.h	(revision 4930)
+++ /nanovis/tags/1.1.4/PCASplit.h	(revision 4930)
@@ -0,0 +1,187 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#ifndef PCA_PCASPLIT_H
+#define PCA_PCASPLIT_H
+
+#include <memory.h>
+
+#include <vrmath/Vector3f.h>
+#include <vrmath/Color4f.h>
+
+namespace PCA {
+
+class Point
+{
+public:
+    Point() :
+        size(1.0f),
+        value(0.0f)
+    {}
+
+    vrmath::Vector3f position;
+    vrmath::Color4f color;
+    float size;
+    float value;
+};
+
+class Cluster
+{
+public:
+    Cluster() :
+        centroid(0.0f, 0.0f, 0.0f),
+        color(1.0f, 1.0f, 1.0f, 1.0f),
+        scale(0.0f),
+        numOfChildren(0),
+        numOfPoints(0),
+        points(NULL),
+        children(NULL),
+        vbo(0),
+        level(0)
+    {
+    }
+
+    void setChildren(Cluster *children, int count)
+    {
+        this->children = children;
+        numOfChildren = count;
+    }
+
+    void setPoints(Point *points, int count)
+    {
+        this->points = points;
+        numOfPoints = count;
+    }
+
+    vrmath::Vector3f centroid;
+    vrmath::Color4f color;
+    float scale;
+
+    int numOfChildren;
+    int numOfPoints;
+    Point *points;
+    Cluster *children;
+    unsigned int vbo;
+    int level;
+};
+
+class ClusterAccel
+{
+public:
+    ClusterAccel(int maxlevel) :
+        root(NULL),
+        maxLevel(maxlevel)
+    {
+        startPointerCluster = new Cluster *[maxLevel];
+        numOfClusters = new int[maxLevel];
+        vbo = new unsigned int[maxLevel];
+        memset(vbo, 0, sizeof(unsigned int) * maxLevel);
+    }
+
+    Cluster *root;
+    int maxLevel;
+    Cluster **startPointerCluster;
+    int *numOfClusters;
+    unsigned int *vbo;
+};
+
+class Cluster_t
+{
+public:
+    Cluster_t() :
+        numOfPoints_t(0),
+        scale_t(0.0f),
+        points_t(0)
+    {}
+
+    vrmath::Vector3f centroid_t;
+    int numOfPoints_t;
+    float scale_t;
+    Point *points_t;
+};
+
+class ClusterListNode
+{
+public:
+    ClusterListNode(Cluster_t *d, ClusterListNode *n) :
+        data(d),
+        next(n)
+    {}
+
+    ClusterListNode() :
+        data(NULL),
+        next(NULL)
+    {}
+
+    Cluster_t *data;
+    ClusterListNode *next;
+};
+
+class PCASplit
+{
+public:
+    enum {
+        MAX_INDEX = 8000000
+    };
+
+    PCASplit();
+
+    ~PCASplit();
+
+    ClusterAccel *doIt(Point *data, int count);
+
+    void setMinDistance(float minDistance)
+    {
+        _minDistance = minDistance;
+    }
+
+    void setMaxLevel(int maxLevel)
+    {
+        _maxLevel = maxLevel;
+    }
+
+    static void computeDistortion(Point *data, int count, const vrmath::Vector3f& mean, float& distortion, float& maxSize);
+
+    static void computeCentroid(Point *data, int count, vrmath::Vector3f& mean);
+
+    static void computeCovariant(Point *data, int count, const vrmath::Vector3f& mean, float *m);
+
+private:
+    void init();
+
+    void analyze(ClusterListNode *cluster, Cluster *parent, int level, float limit);
+
+    void addLeafCluster(Cluster_t *cluster);
+
+    Cluster *createClusterBlock(ClusterListNode *clusterList, int count, int level);
+
+    void split(Point *data, int count, float maxDistortion);
+
+    float getMaxDistortionSquare(ClusterListNode *clusterList, int count);
+
+    ClusterAccel *_clusterHeader;
+
+    ClusterListNode *_curClusterNode;
+    ClusterListNode *_memClusterChunk1;
+    ClusterListNode *_memClusterChunk2;
+    ClusterListNode *_curMemClusterChunk;
+
+    int _memClusterChunkIndex;
+
+    Cluster *_curRoot;
+
+    int _curClusterCount;
+    int _maxLevel;
+    float _minDistance;
+    float _distanceScale;
+    unsigned int *_indices;
+    int _indexCount;
+    int _finalMaxLevel;
+};	
+
+}
+
+#endif 
+
Index: /nanovis/tags/1.1.4/ParticleAdvectionShader.cpp
===================================================================
--- /nanovis/tags/1.1.4/ParticleAdvectionShader.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/ParticleAdvectionShader.cpp	(revision 4930)
@@ -0,0 +1,50 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#include "ParticleAdvectionShader.h"
+
+using namespace nv;
+
+ParticleAdvectionShader::ParticleAdvectionShader() : 
+    _velocityVolumeID(0), 
+    _scale(1.0f, 1.0f, 1.0f), 
+    _max(1.0f), 
+    _timeStep(0.0005f)
+{
+    init();
+}
+
+ParticleAdvectionShader::~ParticleAdvectionShader()
+{
+}
+
+void ParticleAdvectionShader::init()
+{
+    loadFragmentProgram("update_pos.cg");
+}
+
+void 
+ParticleAdvectionShader::bind(unsigned int texID, unsigned int initPosTexID)
+{
+    setFPTextureParameter("pos_tex", texID);
+    setFPTextureParameter("init_pos_tex", initPosTexID);
+    setFPTextureParameter("vel_tex", _velocityVolumeID);
+
+    setFPParameter1f("timestep", _timeStep);
+    setFPParameter1f("max", _max);
+    setFPParameter3f("scale", _scale.x, _scale.y, _scale.z);
+
+    Shader::bind();
+}
+
+void
+ParticleAdvectionShader::unbind()
+{
+     disableFPTextureParameter("pos_tex");
+     disableFPTextureParameter("init_pos_tex");
+     disableFPTextureParameter("vel_tex");
+
+     Shader::unbind();
+}
Index: /nanovis/tags/1.1.4/ParticleAdvectionShader.h
===================================================================
--- /nanovis/tags/1.1.4/ParticleAdvectionShader.h	(revision 4930)
+++ /nanovis/tags/1.1.4/ParticleAdvectionShader.h	(revision 4930)
@@ -0,0 +1,56 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#ifndef NV_PARTICLE_ADVECTION_SHADER_H
+#define NV_PARTICLE_ADVECTION_SHADER_H
+
+#include <vrmath/Vector3f.h>
+
+#include "Shader.h"
+
+namespace nv {
+
+class ParticleAdvectionShader : public Shader
+{
+public:
+    ParticleAdvectionShader();
+
+    virtual ~ParticleAdvectionShader();
+
+    virtual void bind(unsigned int texID, unsigned int initPosTexID);
+
+    virtual void unbind();
+
+    void setScale(const vrmath::Vector3f& scale)
+    {
+        _scale = scale;
+    }
+
+    void setVelocityVolume(unsigned int texID, float max)
+    {
+        _velocityVolumeID = texID;
+        _max = max;
+        // FIXME: Is this needed?
+        if (_max > 100.f)
+            _max = 100.0f;
+    }
+
+    void setTimeStep(float timeStep)
+    {
+        _timeStep = timeStep;
+    }
+
+private:
+    void init();
+
+    unsigned int _velocityVolumeID;
+    vrmath::Vector3f _scale;
+    float _max;
+    float _timeStep;
+};
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/ParticleEmitter.cpp
===================================================================
--- /nanovis/tags/1.1.4/ParticleEmitter.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/ParticleEmitter.cpp	(revision 4930)
@@ -0,0 +1,19 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#include "ParticleEmitter.h"
+
+using namespace nv;
+
+ParticleEmitter::ParticleEmitter() :
+    _minLifeTime(30.0f), _maxLifeTime(100.0f),
+    _maxPositionOffset(1, 1, 1),
+    _minNumOfNewParticles(10), _maxNumOfNewParticles(20)
+{
+}
+
+void ParticleEmitter::setVectorField()
+{
+}
Index: /nanovis/tags/1.1.4/ParticleEmitter.h
===================================================================
--- /nanovis/tags/1.1.4/ParticleEmitter.h	(revision 4930)
+++ /nanovis/tags/1.1.4/ParticleEmitter.h	(revision 4930)
@@ -0,0 +1,90 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#ifndef NV_PARTICLEEMITTER_H
+#define NV_PARTICLEEMITTER_H
+
+#include <string>
+
+#include <vrmath/Vector3f.h>
+
+namespace nv {
+
+class ParticleEmitter
+{
+public:
+    ParticleEmitter();
+
+    void setName(const std::string& name);
+    void setPosition(float x, float y, float z);
+    void setMinMaxLifeTime(float minLifeTime, float maxLifeTime);
+    void setMaxPositionOffset(float offsetX, float offsetY, float offsetZ);
+    void setMinMaxNumOfNewParticles(int minNum, int maxNum);
+
+    void setVectorField();
+    void setEnabled(bool enabled);
+    bool isEnabled() const;
+
+    std::string _name;
+    vrmath::Vector3f _position;
+
+    vrmath::Vector3f _oldPosition;
+
+    float _minLifeTime;
+    float _maxLifeTime;
+
+    // [0..1] * _maxPositionOffset;
+    vrmath::Vector3f _maxPositionOffset;
+
+    int _minNumOfNewParticles;
+    int _maxNumOfNewParticles;
+
+    bool _enabled;
+};
+
+inline void ParticleEmitter::setName(const std::string& name)
+{
+    _name = name;
+}
+
+inline void ParticleEmitter::setPosition(float x, float y, float z)
+{
+    _position.x = x;
+    _position.y = y;
+    _position.z = z;
+}
+
+inline void ParticleEmitter::setMinMaxLifeTime(float minLifeTime, float maxLifeTime)
+{
+    _minLifeTime = minLifeTime;
+    _maxLifeTime = maxLifeTime;
+}
+
+inline void ParticleEmitter::setMaxPositionOffset(float offsetX, float offsetY, float offsetZ)
+{
+    _maxPositionOffset.x = offsetX;
+    _maxPositionOffset.y = offsetY;
+    _maxPositionOffset.z = offsetZ;
+}
+
+inline void ParticleEmitter::setMinMaxNumOfNewParticles(int minNum, int maxNum)
+{
+    _minNumOfNewParticles = minNum;
+    _maxNumOfNewParticles = maxNum;
+}
+
+inline void ParticleEmitter::setEnabled(bool enabled)
+{
+    _enabled = enabled;
+}
+
+inline bool ParticleEmitter::isEnabled() const
+{
+    return _enabled;
+}
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/ParticleRenderer.cpp
===================================================================
--- /nanovis/tags/1.1.4/ParticleRenderer.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/ParticleRenderer.cpp	(revision 4930)
@@ -0,0 +1,352 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* 
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ *  Authors:
+ *    Wei Qiao <qiaow@purdue.edu>
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <GL/glew.h>
+
+#include <vrmath/Color4f.h>
+
+#include "ParticleRenderer.h"
+#include "define.h"
+#include "Trace.h"
+
+using namespace nv;
+
+ParticleAdvectionShader *ParticleRenderer::_advectionShader = NULL;
+ParticleAdvectionShaderInstance shaderInstance;
+
+ParticleRenderer::ParticleRenderer(int w, int h) :
+    _initPosTex(0),
+    _data(NULL),
+    _psysFrame(0U),
+    _reborn(true),
+    _flip(true),
+    _maxLife(500U),
+    _particleSize(1.2),
+    _vertexArray(NULL),
+    _scale(1, 1, 1), 
+    _origin(0, 0, 0),
+    _activate(false),
+    _slicePos(0.0),
+    _sliceAxis(AXIS_Z),
+    _color(0.2, 0.2, 1.0, 1.0),
+    _psysWidth(w),
+    _psysHeight(h)
+{
+    _data = new Particle[w * h];
+    memset(_data, 0, sizeof(Particle) * w * h);
+
+    _vertexArray = new RenderVertexArray(_psysWidth * _psysHeight, 3, GL_FLOAT);
+
+    assert(CheckGL(AT));
+
+    glGenFramebuffersEXT(2, _psysFbo);
+    glGenTextures(2, _psysTex);
+
+    int fboOrig;
+    glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &fboOrig);
+
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _psysFbo[0]);
+
+    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _psysTex[0]);
+    glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+#ifdef HAVE_FLOAT_TEXTURES
+    glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA32F_ARB, 
+                 _psysWidth, _psysHeight, 0, GL_RGBA, GL_FLOAT, NULL);
+#else
+    glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA,
+                 _psysWidth, _psysHeight, 0, GL_RGBA, GL_FLOAT, NULL);
+#endif
+    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, 
+                              GL_TEXTURE_RECTANGLE_ARB, _psysTex[0], 0);
+
+    CHECK_FRAMEBUFFER_STATUS();
+
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _psysFbo[1]);
+
+    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _psysTex[1]);
+    glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+#ifdef HAVE_FLOAT_TEXTURES
+    glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA32F_ARB, 
+                 _psysWidth, _psysHeight, 0, GL_RGBA, GL_FLOAT, NULL);
+#else
+    glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA,
+                 _psysWidth, _psysHeight, 0, GL_RGBA, GL_FLOAT, NULL);
+#endif
+    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, 
+                              GL_TEXTURE_RECTANGLE_ARB, _psysTex[1], 0);
+ 
+    CHECK_FRAMEBUFFER_STATUS();
+
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboOrig);
+
+    glGenTextures(1, &_initPosTex);
+    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _initPosTex);
+    glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+#ifdef HAVE_FLOAT_TEXTURES
+    glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA32F_ARB, 
+                 _psysWidth, _psysHeight, 0, GL_RGBA, GL_FLOAT, NULL);
+#else
+    glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA,
+                 _psysWidth, _psysHeight, 0, GL_RGBA, GL_FLOAT, NULL);
+#endif
+
+    if (_advectionShader == NULL) {
+        _advectionShader = new ParticleAdvectionShader();
+    }
+}
+
+ParticleRenderer::~ParticleRenderer()
+{
+    glDeleteTextures(1, &_initPosTex);
+
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _psysFbo[0]);
+    glDeleteTextures(1, _psysTex);
+
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _psysFbo[1]);
+    glDeleteTextures(1, _psysTex+1);
+
+    glDeleteFramebuffersEXT(2, _psysFbo);
+
+    delete _vertexArray;
+    delete [] _data;
+}
+
+void
+ParticleRenderer::initializeDataArray()
+{
+    size_t n = _psysWidth * _psysHeight * 4;
+    memset(_data, 0, sizeof(float)* n);
+
+    int index;
+    bool particle;
+    float *p = (float *)_data;
+    for (int i = 0; i < _psysWidth; i++) {
+        for (int j = 0; j < _psysHeight; j++) {
+            index = i + _psysHeight*j;
+            particle = (rand() % 256) > 150;
+            if (particle) {
+                //assign any location (x,y,z) in range [0,1]
+                switch (_sliceAxis) {
+                case 0:
+                    p[4*index]   = _slicePos;
+                    p[4*index+1] = j/float(_psysHeight);
+                    p[4*index+2] = i/float(_psysWidth);
+                    break;
+                case 1:
+                    p[4*index]   = j/float(_psysHeight);
+                    p[4*index+1] = _slicePos;
+                    p[4*index+2] = i/float(_psysWidth);
+                    break;
+                case 2:
+                    p[4*index]   = j/float(_psysHeight);
+                    p[4*index+1] = i/float(_psysWidth);
+                    p[4*index+2] = _slicePos;
+                    break;
+                default:
+                    p[4*index]   = 0;
+                    p[4*index+1] = 0;
+                    p[4*index+2] = 0;
+                    p[4*index+3] = 0;
+                }
+
+                //shorter life span, quicker iterations
+                p[4*index+3] = rand() / ((float) RAND_MAX) * 0.5  + 0.5f; 
+            } else {
+                p[4*index]   = 0;
+                p[4*index+1] = 0;
+                p[4*index+2] = 0;
+                p[4*index+3] = 0;
+            }
+        }
+    }
+}
+
+void
+ParticleRenderer::initialize()
+{
+    initializeDataArray();
+
+    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _psysTex[0]);
+#ifdef HAVE_FLOAT_TEXTURES
+    glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA32F_ARB, 
+                 _psysWidth, _psysHeight, 0, GL_RGBA, GL_FLOAT, (float*)_data);
+#else
+    glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA,
+                 _psysWidth, _psysHeight, 0, GL_RGBA, GL_FLOAT, (float*)_data);
+#endif
+    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
+
+    _flip = true;
+    _reborn = false;
+
+    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _initPosTex);
+#ifdef HAVE_FLOAT_TEXTURES
+    glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA32F_ARB, 
+                 _psysWidth, _psysHeight, 0, GL_RGBA, GL_FLOAT, (float*)_data);
+#else
+    glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA,
+                 _psysWidth, _psysHeight, 0, GL_RGBA, GL_FLOAT, (float*)_data);
+#endif
+    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
+
+    TRACE("Leave");
+}
+
+void
+ParticleRenderer::reset()
+{
+    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _psysTex[0]);
+#ifdef HAVE_FLOAT_TEXTURES
+    glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA32F_ARB, 
+                 _psysWidth, _psysHeight, 0, GL_RGBA, GL_FLOAT, (float*)_data);
+#else
+    glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA,
+                 _psysWidth, _psysHeight, 0, GL_RGBA, GL_FLOAT, (float*)_data);
+#endif
+    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
+    _flip = true;
+    _reborn = false;
+    _psysFrame = 0U;
+}
+
+void
+ParticleRenderer::advect()
+{
+    if (_reborn) 
+        reset();
+
+    glPushAttrib(GL_VIEWPORT_BIT | GL_ENABLE_BIT);
+
+    int fboOrig;
+    glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &fboOrig);
+
+    glDisable(GL_BLEND);
+    glDisable(GL_DEPTH_TEST);
+
+    int fbo, tex;
+    if (_flip) {
+        fbo = 1;
+        tex = 0;
+    } else {
+        fbo = 0;
+        tex = 1;
+    }
+
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _psysFbo[fbo]);
+    glEnable(GL_TEXTURE_RECTANGLE_ARB);
+    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _psysTex[tex]);
+
+    glClear(GL_COLOR_BUFFER_BIT);
+
+    glViewport(0, 0, _psysWidth, _psysHeight);
+    glMatrixMode(GL_PROJECTION);
+    glPushMatrix();
+    glLoadIdentity();
+    //gluOrtho2D(0, _psysWidth, 0, _psysHeight);
+    glOrtho(0, _psysWidth, 0, _psysHeight, -10.0f, 10.0f);
+    glMatrixMode(GL_MODELVIEW);
+    glPushMatrix();
+    glLoadIdentity();
+
+    _advectionShader->bind(_psysTex[tex], _initPosTex);
+
+    draw_quad(_psysWidth, _psysHeight, _psysWidth, _psysHeight);
+
+    _advectionShader->unbind();
+
+    glMatrixMode(GL_PROJECTION);
+    glPopMatrix();
+
+    glMatrixMode(GL_MODELVIEW);
+    glPopMatrix();
+
+    glDisable(GL_TEXTURE_RECTANGLE_ARB);
+
+    updateVertexBuffer();
+
+    _flip = (!_flip);
+
+    _psysFrame++;
+    if (_psysFrame == _maxLife) {
+        _psysFrame = 0U;
+        // _reborn = true;
+    }
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboOrig);
+
+    glPopAttrib();
+}
+
+void
+ParticleRenderer::updateVertexBuffer()
+{
+    _vertexArray->read(_psysWidth, _psysHeight);
+
+    //_vertexArray->loadData(vert);     //does not work??
+    //assert(glGetError()==0);
+}
+
+void 
+ParticleRenderer::render()
+{
+    glPushAttrib(GL_ENABLE_BIT);
+    glDisable(GL_TEXTURE_2D);
+    glDisable(GL_BLEND);
+    glEnable(GL_DEPTH_TEST);
+
+    glEnable(GL_COLOR_MATERIAL);
+
+    glMatrixMode(GL_MODELVIEW);
+    glPushMatrix();
+
+    glTranslatef(_origin.x, _origin.y, _origin.z);
+    glScaled(_scale.x, _scale.y, _scale.z);
+
+    glPointSize(_particleSize);
+    glColor4f(_color.x, _color.y, _color.z, _color.w);
+
+    glEnableClientState(GL_VERTEX_ARRAY);
+    _vertexArray->setPointer(0);
+    glDrawArrays(GL_POINTS, 0, _psysWidth * _psysHeight);
+    glDisableClientState(GL_VERTEX_ARRAY);
+
+    glPopMatrix();
+    glPopAttrib();
+}
+
+void 
+ParticleRenderer::setVectorField(unsigned int texID, const vrmath::Vector3f& origin, 
+                                 float scaleX, float scaleY, float scaleZ, 
+                                 float max)
+{
+    _origin = origin;
+    _scale.set(scaleX, scaleY, scaleZ);
+    _advectionShader->setScale(_scale);
+    _advectionShader->setVelocityVolume(texID, max);
+}
+
+void
+ParticleRenderer::setSliceAxis(FlowSliceAxis axis)
+{
+    _sliceAxis = axis;
+    initializeDataArray();
+}
+
+void
+ParticleRenderer::setSlicePosition(float pos)
+{
+    _slicePos = pos;
+    initializeDataArray();
+}
Index: /nanovis/tags/1.1.4/ParticleRenderer.h
===================================================================
--- /nanovis/tags/1.1.4/ParticleRenderer.h	(revision 4930)
+++ /nanovis/tags/1.1.4/ParticleRenderer.h	(revision 4930)
@@ -0,0 +1,161 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ *  Authors:
+ *    Wei Qiao <qiaow@purdue.edu>
+ */
+#ifndef NV_PARTICLE_RENDERER_H
+#define NV_PARTICLE_RENDERER_H
+
+#include <GL/glew.h>
+
+#include <vrmath/Vector3f.h>
+#include <vrmath/Color4f.h>
+
+#include "FlowTypes.h"
+#include "ParticleAdvectionShader.h"
+#include "RenderVertexArray.h"
+
+namespace nv {
+
+struct Particle {
+    float x;
+    float y;
+    float z;
+    float life;
+
+    Particle()
+    {}
+
+    Particle(float _x, float _y, float _z, float _life) :
+        x(_x),
+        y(_y),
+        z(_z),
+        life(_life)
+    {}
+};
+
+class ParticleRenderer
+{
+public:
+    ParticleRenderer(int w, int h);
+
+    ~ParticleRenderer();
+
+    void setVectorField(unsigned int texID, const vrmath::Vector3f& origin,
+                        float scaleX, float scaleY, float scaleZ, float max);
+
+    void initialize();
+
+    void advect();
+
+    void reset();
+
+    void render();
+
+    bool active() const
+    {
+        return _activate;
+    }
+
+    void active(bool state)
+    {
+        _activate = state;
+    }
+
+    void setColor(const vrmath::Color4f& color)
+    {
+        _color = color;
+    }
+
+    void setSliceAxis(FlowSliceAxis axis);
+
+    FlowSliceAxis getSliceAxis() const
+    {
+        return _sliceAxis;
+    }
+
+    void setSlicePosition(float pos);
+
+    float getSlicePosition() const
+    {
+        return _slicePos;
+    }
+
+    void particleSize(float size)
+    {
+        _particleSize = size;
+    }
+
+    float particleSize() const
+    {
+        return _particleSize;
+    }
+
+   static ParticleAdvectionShader *_advectionShader;
+
+private:
+    void initializeDataArray();
+
+    void updateVertexBuffer();
+
+    /// frame buffer objects: two are defined, flip them as input output every step
+    GLuint _psysFbo[2];
+
+    /// color textures attached to frame buffer objects
+    GLuint _psysTex[2];
+    GLuint _initPosTex;
+    Particle *_data;
+
+    /// Count the frame number of particle system iteration
+    unsigned int _psysFrame;
+
+    /// Reinitiate particles
+    bool _reborn;
+
+    /// flip the source and destination render targets
+    bool _flip;
+
+    unsigned int _maxLife;
+
+    /// Size of the particle: default is 1.2
+    float _particleSize;
+
+    /// vertex array for display particles
+    RenderVertexArray *_vertexArray;
+
+    /// scale of flow data
+    vrmath::Vector3f _scale;
+
+    vrmath::Vector3f _origin;
+
+    bool _activate;
+
+    float _slicePos;
+    FlowSliceAxis _sliceAxis;
+
+    vrmath::Color4f _color;
+
+    //the storage of particles is implemented as a 2D array.
+    int _psysWidth;
+    int _psysHeight;
+};
+
+class ParticleAdvectionShaderInstance
+{
+public :
+    ParticleAdvectionShaderInstance()
+    {}
+
+    ~ParticleAdvectionShaderInstance()
+    {
+        if (ParticleRenderer::_advectionShader) {
+            delete ParticleRenderer::_advectionShader;
+        }
+    }
+};
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/ParticleSystem.cpp
===================================================================
--- /nanovis/tags/1.1.4/ParticleSystem.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/ParticleSystem.cpp	(revision 4930)
@@ -0,0 +1,1869 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+
+#include <time.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <pthread.h>
+
+#include <GL/glew.h>
+#include <Cg/cgGL.h>
+
+#include <util/FilePath.h>
+
+#include <Image.h>
+#include <ImageLoader.h>
+#include <ImageLoaderFactory.h>
+
+#include <vrmath/Matrix4x4d.h>
+#include <vrmath/Vector3f.h>
+#include <vrmath/Vector4f.h>
+
+#include "ParticleSystem.h"
+#include "ParticleEmitter.h"
+#include "Texture2D.h"
+#include "Texture3D.h"
+#include "Shader.h"
+#include "Trace.h"
+
+using namespace nv;
+using namespace nv::util;
+
+#define USE_RGBA_ARROW
+
+//#define TEST
+
+inline float randomRange(float rangeMin, float rangeMax)
+{
+    return ((float)rand() / RAND_MAX) * (rangeMax - rangeMin) + rangeMin ;
+}
+
+inline int logd(int value)
+{
+    int l;
+    for (l = 0; value >> l; l++);
+    return l - 1;
+}
+
+inline void swap(int& x, int& y)
+{
+    if (x != y) {
+        x ^= y;
+        y ^= x;
+        x ^= y;
+    }
+}
+
+void *ParticleSystem::dataLoadMain(void *data)
+{
+    ParticleSystem *particleSystem = (ParticleSystem *)data;
+    CircularFifo<float*, 10>& queue = particleSystem->_queue;
+
+    // TBD..
+    //float min = particleSystem->_time_series_vel_mag_min;
+    //float max = particleSystem->_time_series_vel_mag_max;
+
+    int startIndex = particleSystem->_flowFileStartIndex;
+    int endIndex = particleSystem->_flowFileEndIndex;
+
+    int curIndex = startIndex;
+    int flowWidth = particleSystem->_flowWidth;
+    int flowHeight = particleSystem->_flowHeight;
+    int flowDepth = particleSystem->_flowDepth;
+
+    const char* fileNameFormat = particleSystem->_fileNameFormat.c_str();
+    char buff[256];
+
+    bool done = false;
+    while (!done) {
+        if (curIndex > endIndex) {
+            curIndex = startIndex;
+        }
+
+        if (!queue.isFull()) {
+            int tail = queue.tailIndex();
+            if (tail != -1) {
+                sprintf(buff, fileNameFormat, curIndex);
+                //std::string path = FilePath::getInstance()->getPath(buff);
+#ifdef WANT_TRACE
+                float t = clock() /(float) CLOCKS_PER_SEC;
+#endif
+                LoadProcessedFlowRaw(buff, flowWidth, flowHeight, flowDepth, queue.array[tail]);
+#ifdef WANT_TRACE
+                float ti = clock() / (float) CLOCKS_PER_SEC;
+                TRACE("LoadProcessedFlowRaw time: %f", ti - t);
+#endif
+                queue.push();
+                TRACE("%d loaded", curIndex);
+                ++curIndex;
+            }
+        }
+    }
+
+    return 0;
+}
+
+CGcontext ParticleSystem::_context = 0;
+
+unsigned int SpotTexID = 0;
+
+void MakeSphereTexture()
+{
+    const int DIM = 128;
+    const int DIM2 = 63;
+    //const float TEX_SCALE = 6.0;
+
+    glGenTextures(1, (GLuint *)&SpotTexID);
+    glBindTexture(GL_TEXTURE_2D, SpotTexID);
+
+    float col[4] = {1.f, 1.f, 1.f, 1.f};
+    glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, col);
+    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+
+    float *img = new float[DIM*DIM];
+
+    vrmath::Vector3f light(1,1,3);
+    light = light.normalize();
+
+    for (int y = 0; y < DIM; y++) {
+        for (int x = 0; x < DIM; x++) {
+            // Clamping the edges to zero allows Nvidia's blend optimizations to do their thing.
+            if (x == 0 || x == DIM-1 || y == 0 || y == DIM-1) {
+                img[y*DIM+x] = 0;
+            } else {
+                vrmath::Vector3f p(x, y, 0);
+                p = p - vrmath::Vector3f(DIM2, DIM2, 0);
+                float len = p.length();
+                float z = sqrt(DIM2*DIM2 - len*len);
+                p.z = z;
+                if (len >= DIM2) {
+                    img[y*DIM+x] = 0.0;
+                    continue;
+                }
+
+                p = p.normalize();
+                float v = p.dot(light);
+                if(v < 0) v = 0;
+
+                img[y*DIM+x] = v;
+            }
+        }
+    }
+
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+
+    gluBuild2DMipmaps(GL_TEXTURE_2D, GL_ALPHA16, DIM, DIM, GL_ALPHA, GL_FLOAT, img);
+}
+
+//extern void algorithm_test(vrmath::Vector4f* data, int flowWidth, int flowHeight, int flowDepth);
+//extern std::vector<vrmath::Vector3f>* find_critical_points(vrmath::Vector4f* data, int flowWidth, int flowHeight, int flowDepth);
+ParticleSystem::ParticleSystem(int width, int height,
+                               const std::string& fileName,
+                               int fieldWidth, int fieldHeight, int fieldDepth, 
+                               bool timeVaryingData,
+                               int flowFileStartIndex, int flowFileEndIndex) :
+    _width(width),
+    _height(height)
+{
+    ////////////////////////////////
+    // TIME-VARYING SERIES
+    _isTimeVaryingField = timeVaryingData;
+    _flowFileStartIndex = flowFileStartIndex;
+    _flowFileEndIndex = flowFileEndIndex;
+    _userDefinedParticleMaxCount = width * height;
+
+    _skipByte = 0;
+
+    _screenWidth = _screenHeight = 1;
+    _fov = 60.0f;
+
+    _particleMaxCount = _width * _height;
+
+    _pointSize = 10.0f;
+    _camx = 0.0f;
+    _camy = 0.0f;
+    _camz = 0.0f;
+
+    _scalex = _scaley = _scalez = 1.0f;
+    _currentSortIndex = 0;
+    _destSortIndex = 1;
+
+    _currentPosIndex = 0;
+    _destPosIndex = 1;
+
+    _currentSortPass = 0;
+    // TBD
+    //_sortPassesPerFrame = 5;
+    _sortPassesPerFrame = 4;
+    _maxSortPasses = 0;
+
+    _sortBegin = 0;
+    _sortEnd = _sortPassesPerFrame;
+    _currentTime = 0;
+    _sortEnabled = false;
+    _glyphEnabled = false;
+    _advectionEnabled = false;
+    _streamlineEnabled = false;
+    _particles = new Particle[_particleMaxCount];
+    memset(_particles, 0, sizeof(Particle) * _particleMaxCount);
+
+    _colorBuffer = new color4[_particleMaxCount];
+    memset(_colorBuffer, 0, sizeof(color4) * _particleMaxCount);
+
+    _positionBuffer = new vrmath::Vector3f[_particleMaxCount];
+    _vertices = new RenderVertexArray(_particleMaxCount, 3, GL_FLOAT);
+
+    srand(time(0));
+
+    /*
+    // TBD..
+    glGenBuffersARB(1, &_colorBufferID);
+    glBindBufferARB(GL_ARRAY_BUFFER, _colorBufferID);
+    glBufferDataARB(GL_ARRAY_BUFFER, _width * _height * 4, _colorBuffer, GL_STREAM_DRAW_ARB); // undefined data
+    glBindBufferARB(GL_ARRAY_BUFFER, 0);
+    */
+
+    _flowWidth = fieldWidth;
+    _flowHeight = fieldHeight;
+    _flowDepth = fieldDepth;
+
+    float min, max, nonzero_min, axisScaleX, axisScaleY, axisScaleZ;
+    int index = fileName.rfind('.');
+    std::string ext = fileName.substr(index + 1, fileName.size() - (index + 1));
+    float *data = 0;
+
+    if (this->isTimeVaryingField()) {
+        axisScaleX = _flowWidth;
+        axisScaleY = _flowHeight;
+        axisScaleZ = _flowDepth;
+        _fileNameFormat = fileName;
+        for (int i = 0; i < CircularFifo<float*, 10>::Capacity; ++i) {
+            _queue.array[i] = new float[_flowWidth * _flowHeight * _flowDepth * 4];
+        }
+
+        // INSOO
+        // TBD
+        min = 0;
+        max = 234.99;
+    } else {
+        if (ext == "dx") {
+            data = (float*) LoadFlowDx(fileName.c_str(), _flowWidth, _flowHeight, _flowDepth, min, max, nonzero_min, axisScaleX, axisScaleY, axisScaleZ);
+        } else if (ext == "raw") {
+            data = (float*) LoadFlowRaw(fileName.c_str(), _flowWidth, _flowHeight, _flowDepth, min, max, nonzero_min, axisScaleX, axisScaleY, axisScaleZ, 0, false);
+            //data = (float*) LoadProcessedFlowRaw(fileName.c_str(), _flowWidth, _flowHeight, _flowDepth, min, max, axisScaleX, axisScaleY, axisScaleZ);
+#ifdef notdef
+        } else if (ext == "raws") {
+            data = (float*) LoadFlowRaw(fileName.c_str(), _flowWidth, _flowHeight, _flowDepth, min, max, nonzero_min, axisScaleX, axisScaleY, axisScaleZ, 5 * sizeof(int), true);
+        } else if (ext == "data") {
+            data = (float*) LoadFlowRaw(fileName.c_str(), _flowWidth, _flowHeight, _flowDepth, min, max, nonzero_min, axisScaleX, axisScaleY, axisScaleZ, 0, true);
+#endif
+        }
+        //_criticalPoints = find_critical_points((vrmath::Vector4f*) data, _flowWidth,  _flowHeight,  _flowDepth);
+        //algorithm_test((vrmath::Vector4f*) data,  _flowWidth,  _flowHeight,  _flowDepth);
+    }
+
+    _scalex = 1;
+    _scaley = axisScaleY / axisScaleX;
+    _scalez = axisScaleZ / axisScaleX;
+    _maxVelocityScale = max;
+
+    if (!this->isTimeVaryingField()) {
+        Texture3D *flow = new Texture3D(_flowWidth, _flowHeight, _flowDepth,
+                                        GL_FLOAT, GL_LINEAR, 4, data);
+        _curVectorFieldID = flow->id();
+        _vectorFieldIDs.push_back(_curVectorFieldID);
+    } else {
+        for (int i = 0; i < 3; ++i) {
+            Texture3D *flow = new Texture3D(_flowWidth, _flowHeight, _flowDepth,
+                                            GL_FLOAT, GL_LINEAR, 4, data);
+            _vectorFields.push_back(flow);
+            _vectorFieldIDs.push_back(flow->id());
+        }
+        _curVectorFieldID = _vectorFieldIDs[0];
+    }
+
+    std::string path = FilePath::getInstance()->getPath("arrows.bmp");
+
+    if (!path.empty()) {
+        ImageLoader *loader = ImageLoaderFactory::getInstance()->createLoader("bmp");
+        if (loader != NULL) {
+#ifdef USE_RGBA_ARROW
+            Image *image = loader->load(path.c_str(), Image::IMG_RGBA);
+#else
+            Image *image = loader->load(path.c_str(), Image::IMG_RGB);
+#endif
+            if (image != NULL) {
+                unsigned char *bytes = (unsigned char *)image->getImageBuffer();
+                if (bytes != NULL) {
+#ifdef USE_RGBA_ARROW
+                    _arrows = new Texture2D(image->getWidth(), image->getHeight(),
+                                            GL_UNSIGNED_BYTE, GL_LINEAR, 4, NULL);
+#else
+                    _arrows = new Texture2D(image->getWidth(), image->getHeight(),
+                                            GL_UNSIGNED_BYTE, GL_LINEAR, 3, NULL);
+#endif
+                    _arrows->setWrapS(GL_MIRRORED_REPEAT);
+                    _arrows->setWrapT(GL_MIRRORED_REPEAT);
+                    _arrows->initialize(image->getImageBuffer());
+                }
+                delete image;
+            } else {
+                ERROR("Failed to load image: arrows.bmp");
+            }
+            delete loader;
+        } else {
+            ERROR("Couldn't find loader for arrows.bmp");
+        }
+    } else {
+        ERROR("Couldn't find path to arrows.bmp");
+    }
+
+#ifdef TEST
+    MakeSphereTexture();
+#endif
+
+    glGenBuffersARB(1, &_particleInfoBufferID);
+    glBindBufferARB(GL_ARRAY_BUFFER_ARB, _particleInfoBufferID);
+    glBufferDataARB(GL_ARRAY_BUFFER_ARB, _particleMaxCount * 4 * sizeof(float), 0, GL_DYNAMIC_DRAW);
+    glVertexAttribPointerARB(8, 4, GL_FLOAT, GL_FALSE, 0, 0);  // 8 = texcoord0
+    glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
+
+    // TBD..
+    initStreamlines(_width, _height);
+    initInitPosTex();
+
+    initShaders();
+    createRenderTargets();
+    createSortRenderTargets();
+    createStreamlineRenderTargets();
+
+    if (this->isTimeVaryingField()) {
+        pthread_t _threads;
+        pthread_attr_t pthread_custom_attr;
+        pthread_attr_init(&pthread_custom_attr);
+        pthread_create(&_threads, &pthread_custom_attr, dataLoadMain, (void *) this);
+    }
+}
+
+void ParticleSystem::initInitPosTex()
+{
+    glGenFramebuffersEXT(1, &_initPos_fbo);
+    glGenTextures(1, &_initPosTex);
+
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _initPos_fbo);
+
+    glViewport(0, 0, _width, _height);
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    glOrtho(0, _width, 0, _height, -10.0f, 10.0f);
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+
+    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _initPosTex);
+    glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB32F_ARB,
+                 _width, _height, 0, GL_RGB, GL_FLOAT, NULL);
+    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
+
+    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, 
+                              GL_TEXTURE_RECTANGLE_ARB, _initPosTex, 0);
+
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+}
+
+void ParticleSystem::initStreamlines(int width, int height)
+{
+    _atlas_x = 32;
+    _atlas_y = 32;
+
+    _atlasWidth = width * _atlas_x;
+    _atlasHeight = height * _atlas_y;
+    _maxAtlasCount = _atlas_x * _atlas_y;
+
+    _stepSizeStreamline = 1;
+    _curStepCount = 0;
+    _particleCount = width * height;
+
+    _currentStreamlineOffset = 0;
+    _currentStreamlineIndex = 0;
+    _streamVertices = new RenderVertexArray(_atlasWidth*_atlasHeight * 2, 3, GL_FLOAT);
+
+    _maxIndexBufferSize = _width * _height * _atlas_x * _atlas_y;
+    _indexBuffer = new unsigned int[_maxIndexBufferSize * 2];
+    unsigned int* pindex = _indexBuffer;
+    int ax, ay, old_ax = 0, old_ay = 0;
+    for (unsigned int i = 1; i < _maxAtlasCount; ++i) {
+        ax = (i % _atlas_x) * width;
+        ay = (i / _atlas_x) * height;
+
+        for (int y = 0; y < height ; ++y) {
+            for (int x = 0; x < width; ++x) {
+                *pindex = (old_ay + y) * _atlasWidth + old_ax + x; ++pindex;
+                *pindex = (ay + y) * _atlasWidth + ax + x; ++pindex;
+            }
+        }
+
+        old_ax = ax;
+        old_ay = ay;
+    }
+}
+
+void ParticleSystem::initShaders()
+{
+    // TBD...
+    _context = Shader::getCgContext();
+
+    std::string path = FilePath::getInstance()->getPath("distance.cg");
+    _distanceInitFP =  
+        cgCreateProgramFromFile(_context, CG_SOURCE, path.c_str(),
+                                CG_PROFILE_FP40, "initSortIndex", NULL);
+    cgGLLoadProgram(_distanceInitFP);
+
+    _distanceSortFP = 
+        cgCreateProgramFromFile(_context, CG_SOURCE,  path.c_str(),
+                                CG_PROFILE_FP40, "computeDistance", NULL);
+    _viewPosParam = cgGetNamedParameter(_distanceSortFP, "viewerPosition");
+    cgGLLoadProgram(_distanceSortFP);
+
+    _distanceSortLookupFP = 
+        cgCreateProgramFromFile(_context, CG_SOURCE,  path.c_str(),
+                                CG_PROFILE_FP40, "lookupPosition", NULL);
+    cgGLLoadProgram(_distanceSortLookupFP);
+
+    path = FilePath::getInstance()->getPath("mergesort.cg");
+    _sortRecursionFP = 
+        cgCreateProgramFromFile(_context, CG_SOURCE, path.c_str(),
+                                CG_PROFILE_FP40, "mergeSortRecursion", NULL);
+    cgGLLoadProgram(_sortRecursionFP);
+
+    _srSizeParam = cgGetNamedParameter(_sortRecursionFP, "_Size");
+    _srStepParam = cgGetNamedParameter(_sortRecursionFP, "_Step");
+    _srCountParam = cgGetNamedParameter(_sortRecursionFP, "_Count");
+
+    _sortEndFP = 
+        cgCreateProgramFromFile(_context, CG_SOURCE, path.c_str(),
+                                CG_PROFILE_FP40, "mergeSortEnd", NULL);
+    cgGLLoadProgram(_sortEndFP);
+
+    _seSizeParam = cgGetNamedParameter(_sortEndFP, "size");
+    _seStepParam = cgGetNamedParameter(_sortEndFP, "step");
+
+    path = FilePath::getInstance()->getPath("passthrough.cg");
+    _passthroughFP = 
+        cgCreateProgramFromFile(_context, CG_SOURCE, path.c_str(),
+                                CG_PROFILE_FP40, "main", NULL);
+    cgGLLoadProgram(_passthroughFP);
+
+    _scaleParam = cgGetNamedParameter(_passthroughFP, "scale");
+    _biasParam = cgGetNamedParameter(_passthroughFP, "bias");
+
+    path = FilePath::getInstance()->getPath("moveparticles.cg");
+    _moveParticlesFP = 
+        cgCreateProgramFromFile(_context, CG_SOURCE, path.c_str(),
+                                CG_PROFILE_FP40, "main", NULL);
+    cgGLLoadProgram(_moveParticlesFP);
+    _mpTimeScale = cgGetNamedParameter(_moveParticlesFP, "timeStep");
+    _mpVectorField = cgGetNamedParameter(_moveParticlesFP, "vfield");
+    _mpUseInitTex= cgGetNamedParameter(_moveParticlesFP, "useInitPos");
+    _mpCurrentTime= cgGetNamedParameter(_moveParticlesFP, "currentTime");
+    _mpMaxScale = cgGetNamedParameter(_moveParticlesFP, "maxScale");
+    _mpScale= cgGetNamedParameter(_moveParticlesFP, "scale");
+
+    path = FilePath::getInstance()->getPath("particlevp.cg");
+    _particleVP = 
+        cgCreateProgramFromFile(_context, CG_SOURCE, path.c_str(),
+                                CG_PROFILE_VP40, "vpmain", NULL);
+    cgGLLoadProgram(_particleVP);
+    _mvpParticleParam = cgGetNamedParameter(_particleVP, "mvp");
+    _mvParticleParam = cgGetNamedParameter(_particleVP, "modelview");
+    _mvTanHalfFOVParam = cgGetNamedParameter(_particleVP, "tanHalfFOV");
+    _mvCurrentTimeParam =  cgGetNamedParameter(_particleVP, "currentTime");
+
+    path = FilePath::getInstance()->getPath("particlefp.cg");
+    _particleFP = 
+        cgCreateProgramFromFile(_context, CG_SOURCE, path.c_str(),
+                                CG_PROFILE_FP40, "fpmain", NULL);
+    cgGLLoadProgram(_particleFP);
+    _vectorParticleParam = cgGetNamedParameter(_particleVP, "vfield");
+
+    path = FilePath::getInstance()->getPath("moveparticles.cg");
+    _initParticlePosFP = 
+        cgCreateProgramFromFile(_context, CG_SOURCE, path.c_str(),
+				CG_PROFILE_FP40, "initParticlePosMain", NULL);
+    cgGLLoadProgram(_initParticlePosFP);
+    _ipVectorFieldParam = cgGetNamedParameter(_moveParticlesFP, "vfield");
+}
+
+void ParticleSystem::passThoughPositions()
+{
+    cgGLBindProgram(_passthroughFP);
+    cgGLEnableProfile(CG_PROFILE_FP40);
+
+    cgGLSetParameter4f(_scaleParam, 1.0, 1.0, 1.0, 1.0);
+    cgGLSetParameter4f(_biasParam, 0.0, 0.0, 0.0, 0.0);
+
+    glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB32F_ARB, 
+                 _width, _height, 0, GL_RGB, GL_FLOAT, (GLfloat *) _positionBuffer);
+
+    drawQuad();
+
+    cgGLDisableProfile(CG_PROFILE_FP40);
+}
+
+void ParticleSystem::resetStreamlines()
+{
+    _currentStreamlineIndex = 0;
+    _currentStreamlineOffset = 0;
+    _curStepCount = 0;
+}
+
+void ParticleSystem::reset()
+{
+    _currentTime = 0.0f;
+    _sortBegin = 0;
+    _sortEnd = _sortPassesPerFrame;
+
+    glPushAttrib(GL_VIEWPORT_BIT);
+    glMatrixMode(GL_PROJECTION);
+    glPushMatrix();
+    glMatrixMode(GL_MODELVIEW);
+
+    resetStreamlines();
+
+    unsigned int maxsize = _userDefinedParticleMaxCount;
+
+    while (!_availableIndices.empty())
+        _availableIndices.pop();
+    while (!_activeParticles.empty())
+        _activeParticles.pop();
+
+    _activeParticles.reserve(maxsize);
+    _availableIndices.reserve(maxsize);
+
+    for (unsigned int i = 0; i < maxsize; i++)
+        _availableIndices.push(i);
+
+    for (int i = 0; i < _particleMaxCount; i++) {
+        _particles[i].timeOfBirth = -1.0f;
+        _particles[i].lifeTime = 0.0f;
+        _particles[i].attributeType = 0.0f;
+        _particles[i].index = (float)i;
+    }
+
+    glBindBufferARB(GL_ARRAY_BUFFER_ARB, _particleInfoBufferID);
+    Particle* pinfo = (Particle*) glMapBufferARB(GL_ARRAY_BUFFER, GL_WRITE_ONLY_ARB);
+
+    for (int i = 0; i < _particleMaxCount; i++)	{
+        pinfo[i] = _particles[i];
+    }
+
+    glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
+
+    // POSITION
+    memset(_positionBuffer, 0, sizeof(vrmath::Vector3f) * _width * _height);
+    for (int y = 0; y < _height; y++) {
+        for (int x = 0; x < _width; x++) {
+            _positionBuffer[_width * y + x].x = (float)rand() / (float) RAND_MAX;
+            //_positionBuffer[_width * y + x].x = 0.9;
+            _positionBuffer[_width * y + x].y = (float)rand() / (float) RAND_MAX;
+            _positionBuffer[_width * y + x].z = (float)rand() / (float) RAND_MAX;
+        }
+    }
+
+    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _initPosTex);
+    glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB32F_ARB,
+                 _width, _height, 0, GL_RGB, GL_FLOAT, (float*)_positionBuffer);
+    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
+
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, psys_fbo[_currentPosIndex]);
+    glViewport(0, 0, _width, _height);
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    glOrtho(0, _width, 0, _height, -10.0f, 10.0f);
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+    passThoughPositions();
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, velocity_fbo[_currentPosIndex]);
+    glViewport(0, 0, _width, _height);
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    glOrtho(0, _width, 0, _height, -10.0f, 10.0f);
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+    glClearColor(0, 0, 0, 0);
+    glClear(GL_COLOR_BUFFER_BIT);
+    // TBD..
+    // velocity
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+
+
+    /// TBD...
+    //DeathTimePBuffer->BeginCapture();
+    //glClear(GL_COLOR_BUFFER_BIT);
+    //DeathTimePBuffer->EndCapture();
+
+    if (_sortEnabled) {
+        glDisable(GL_BLEND);
+        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, sort_fbo[_currentSortIndex]);
+        glViewport(0, 0, _width, _height);
+        glMatrixMode(GL_PROJECTION);
+        glLoadIdentity();
+        glOrtho(0, _width, 0, _height, -10.0f, 10.0f);
+        glMatrixMode(GL_MODELVIEW);
+        glLoadIdentity();
+
+        cgGLBindProgram(_distanceInitFP);
+        cgGLEnableProfile(CG_PROFILE_FP40);
+
+        drawQuad();
+
+        cgGLDisableProfile(CG_PROFILE_FP40);
+        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);		
+
+        _currentSortPass = 0;
+        this->_maxSortPasses = 100000;
+    }
+
+    glMatrixMode(GL_PROJECTION);
+    glPopMatrix();
+    glMatrixMode(GL_MODELVIEW);
+    glPopAttrib();
+}
+
+void ParticleSystem::createRenderTargets()
+{
+    glGenFramebuffersEXT(2, psys_fbo);
+    glGenTextures(2, psys_tex);
+
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, psys_fbo[0]);
+
+    glViewport(0, 0, _width, _height);
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    glOrtho(0, _width, 0, _height, -10.0f, 10.0f);
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+
+    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, psys_tex[0]);
+    glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+    glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA32F_ARB, 
+                 _width, _height, 0, GL_RGBA, GL_FLOAT, NULL);
+
+    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, 
+                              GL_TEXTURE_RECTANGLE_ARB, psys_tex[0], 0);
+
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, psys_fbo[1]);
+
+    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, psys_tex[1]);
+    glViewport(0, 0, _width, _height);
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    glOrtho(0, _width, 0, _height, -10.0f, 10.0f);
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+
+    glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+    glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA32F_ARB, 
+                 _width, _height, 0, GL_RGBA, GL_FLOAT, NULL);
+
+    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, 
+                              GL_TEXTURE_RECTANGLE_ARB, psys_tex[1], 0);
+ 
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+}
+
+//#define ATLAS_TEXTURE_TARGET GL_TEXTURE_RECTANGLE_ARB
+//#define ATLAS_INTERNAL_TYPE GL_RGBA32F_ARB
+#define ATLAS_TEXTURE_TARGET GL_TEXTURE_2D
+#define ATLAS_INTERNAL_TYPE GL_RGBA
+
+void ParticleSystem::createStreamlineRenderTargets()
+{
+    glGenFramebuffersEXT(1, &_atlas_fbo);
+    glGenTextures(1, &_atlas_tex);
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _atlas_fbo);
+    glViewport(0, 0, _atlasWidth, _atlasHeight);
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    glOrtho(0, _atlasWidth, 0, _atlasHeight, -10.0f, 10.0f);
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+
+    glBindTexture(ATLAS_TEXTURE_TARGET, _atlas_tex);
+    glTexParameterf(ATLAS_TEXTURE_TARGET, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameterf(ATLAS_TEXTURE_TARGET, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    //glTexParameteri(ATLAS_TEXTURE_TARGET, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    //glTexParameteri(ATLAS_TEXTURE_TARGET, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+    glTexImage2D(ATLAS_TEXTURE_TARGET, 0, ATLAS_INTERNAL_TYPE, 
+                 _atlasWidth, _atlasHeight, 0, GL_RGBA, GL_FLOAT, NULL);
+
+    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, 
+                              ATLAS_TEXTURE_TARGET, _atlas_tex, 0);
+ 
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+}
+
+//#define SORT_TEXTURE_FORMAT  GL_LUMINANCE_ALPHA
+//#define SORT_TEXTURE_INNER_FORMAT GL_LUMINANCE_ALPHA_FLOAT32_ATI
+#define SORT_TEXTURE_FORMAT  GL_RGB
+#define SORT_TEXTURE_INNER_FORMAT GL_RGB32F_ARB
+
+void ParticleSystem::createSortRenderTargets()
+{
+    glGenFramebuffersEXT(2, sort_fbo);
+    glGenTextures(2, sort_tex);
+
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, sort_fbo[0]);
+    glViewport(0, 0, _width, _height);
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    glOrtho(0, _width, 0, _height, -10.0f, 10.0f);
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+
+    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, sort_tex[0]);
+    glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, SORT_TEXTURE_INNER_FORMAT, 
+                 _width, _height, 0, SORT_TEXTURE_FORMAT, GL_FLOAT, NULL);
+
+    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, 
+                              GL_TEXTURE_RECTANGLE_ARB, sort_tex[0], 0);
+
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, sort_fbo[1]);
+    glViewport(0, 0, _width, _height);
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    glOrtho(0, _width, 0, _height, -10.0f, 10.0f);
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+
+    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, sort_tex[1]);
+    glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, SORT_TEXTURE_INNER_FORMAT, 
+                 _width, _height, 0, SORT_TEXTURE_FORMAT, GL_FLOAT, NULL);
+
+    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, 
+                              GL_TEXTURE_RECTANGLE_ARB, sort_tex[1], 0);
+
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+}
+
+ParticleSystem::~ParticleSystem()
+{
+    std::vector<ParticleEmitter*>::iterator iter;
+    for (iter = _emitters.begin(); iter != _emitters.end(); ++iter)
+        delete (*iter);
+
+    // Particle Position
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, psys_fbo[0]);
+    glDeleteTextures(1, psys_tex);
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, psys_fbo[1]);
+    glDeleteTextures(1, psys_tex+1);
+    glDeleteFramebuffersEXT(2, psys_fbo);
+
+    // Sort
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, sort_fbo[0]);
+    glDeleteTextures(1, sort_tex);
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, sort_fbo[1]);
+    glDeleteTextures(1, sort_tex+1);
+    glDeleteFramebuffersEXT(2, sort_fbo);
+
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, velocity_fbo[0]);
+    glDeleteTextures(1, velocity_tex);
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, velocity_fbo[1]);
+    glDeleteTextures(1, velocity_tex+1);
+    glDeleteFramebuffersEXT(2, velocity_fbo);
+
+    if (_vertices) delete _vertices;
+
+    delete [] _particles;
+    delete [] _positionBuffer;
+    delete [] _colorBuffer;
+
+    if (_arrows) delete _arrows;
+
+    // STREAM LINE
+    if (_streamVertices) delete _streamVertices;
+    if (_indexBuffer) delete _indexBuffer;
+
+    cgDestroyProgram(_distanceInitFP);
+
+    cgDestroyParameter(_viewPosParam);
+    cgDestroyProgram(_distanceSortFP);
+
+    cgDestroyProgram(_distanceSortLookupFP);
+
+    cgDestroyParameter(_scaleParam);
+    cgDestroyParameter(_biasParam);
+    cgDestroyProgram(_passthroughFP);
+
+    cgDestroyParameter(_srSizeParam);
+    cgDestroyParameter(_srStepParam);
+    cgDestroyParameter(_srCountParam);
+
+    cgDestroyProgram(_sortRecursionFP);
+
+    cgDestroyParameter(_seSizeParam);
+    cgDestroyParameter(_seStepParam);
+    cgDestroyProgram(_sortEndFP);
+
+    cgDestroyParameter(_mpTimeScale);
+    cgDestroyParameter(_mpVectorField);
+    cgDestroyParameter(_mpUseInitTex);
+    cgDestroyParameter(_mpCurrentTime);
+    cgDestroyProgram(_moveParticlesFP);
+
+    cgDestroyParameter(_ipVectorFieldParam);
+    cgDestroyProgram(_initParticlePosFP);
+
+    cgDestroyParameter(_mvpParticleParam);
+    cgDestroyParameter(_mvParticleParam);
+    cgDestroyParameter(_mvTanHalfFOVParam);
+    cgDestroyParameter(_mvCurrentTimeParam);
+    cgDestroyProgram(_particleFP);
+
+    cgDestroyParameter(_vectorParticleParam);
+    cgDestroyProgram(_particleVP);
+}
+
+bool ParticleSystem::isEnabled(EnableEnum enabled)
+{
+    switch (enabled) {
+    case PS_SORT :
+        return _sortEnabled;
+        break;
+    case PS_GLYPH :
+        return _glyphEnabled;
+        break;
+    case PS_DRAW_BBOX :
+        return _drawBBoxEnabled;
+        break;
+    case PS_ADVECTION :
+        return _advectionEnabled;
+    case PS_STREAMLINE :
+        return _streamlineEnabled;
+    }
+    return false;
+}
+
+void ParticleSystem::enable(EnableEnum enabled)
+{
+    switch (enabled) {
+    case PS_SORT :
+        _sortEnabled = true;
+        break;
+    case PS_GLYPH :
+        _glyphEnabled = true;
+        break;
+    case PS_DRAW_BBOX :
+        _drawBBoxEnabled = true;
+        break;
+    case PS_ADVECTION :
+        _advectionEnabled = true;
+        break;
+    case PS_STREAMLINE :
+        _streamlineEnabled = true;
+        break;
+    }
+}
+
+void ParticleSystem::disable(EnableEnum enabled)
+{
+    switch (enabled) {
+    case PS_SORT :
+        _sortEnabled = false;
+        break;
+    case PS_GLYPH :
+        _glyphEnabled = false;
+        break;
+    case PS_DRAW_BBOX :
+        _drawBBoxEnabled = false;
+        break;
+    case PS_ADVECTION :
+        _advectionEnabled = false;
+        break;
+    case PS_STREAMLINE :
+        _streamlineEnabled = false;
+        break;
+    }
+}
+
+void ParticleSystem::advectStreamlines()
+{
+    glDisable(GL_BLEND);
+    glDisable(GL_DEPTH_TEST);
+
+    //glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, psys_fbo[_destPosIndex]);
+    //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+    glPushAttrib(GL_VIEWPORT_BIT);
+    glViewport(0, 0, _width, _height);
+    glMatrixMode(GL_PROJECTION);
+    glPushMatrix();
+    glLoadIdentity();
+    glOrtho(0, _width, 0, _height, -10.0f, 10.0f);
+    glMatrixMode(GL_MODELVIEW);
+    glPushMatrix();
+    glLoadIdentity();
+
+    glEnable(GL_TEXTURE_RECTANGLE_ARB);
+
+    cgGLBindProgram(_moveParticlesFP);
+    cgGLEnableProfile(CG_PROFILE_FP40);
+    cgGLSetParameter1f(_mpTimeScale, 0.005);
+    cgGLSetParameter1f(_mpUseInitTex, 1.0);
+    cgGLSetParameter1f(_mpCurrentTime, _currentTime);
+    cgGLSetParameter3f(_mpScale, _scalex, _scaley, _scalez);
+    cgGLSetParameter1f(_mpMaxScale, _maxVelocityScale);
+    cgGLSetTextureParameter(_mpVectorField, _curVectorFieldID);
+    cgGLEnableTextureParameter(_mpVectorField);
+
+    for (int i = 0; i < _stepSizeStreamline; ++i) {
+        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, psys_fbo[_destPosIndex]);
+        glClear(GL_COLOR_BUFFER_BIT);
+        glActiveTextureARB(GL_TEXTURE0_ARB);
+        glBindTexture(GL_TEXTURE_RECTANGLE_ARB, psys_tex[_currentPosIndex]);
+        glActiveTextureARB(GL_TEXTURE1_ARB);
+        glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _initPosTex);
+        drawQuad();
+        swap(_currentPosIndex, _destPosIndex);
+    }
+
+    cgGLDisableTextureParameter(_mpVectorField);
+    glDisable(GL_TEXTURE_RECTANGLE_ARB);
+    cgGLDisableProfile(CG_PROFILE_FP40);
+
+    glMatrixMode(GL_PROJECTION);
+    glPopMatrix();
+    glMatrixMode(GL_MODELVIEW);
+    glPopMatrix();
+    glPopAttrib();
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+
+    if (_currentStreamlineIndex < _maxAtlasCount) {
+        int xoffset = (_currentStreamlineIndex % _atlas_x) * _width;
+        int yoffset = (_currentStreamlineIndex / _atlas_x) * _height;
+
+        glActiveTextureARB(GL_TEXTURE0_ARB);
+        glEnable(ATLAS_TEXTURE_TARGET);
+        glBindTexture(ATLAS_TEXTURE_TARGET, _atlas_tex);
+
+        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, psys_fbo[_destPosIndex]);
+        //glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, psys_fbo[_currentPosIndex]);
+        glCopyTexSubImage2D(ATLAS_TEXTURE_TARGET, 0, xoffset, yoffset, 
+                            0, 0, _width, _height);
+        glActiveTextureARB(GL_TEXTURE0_ARB);
+        glBindTexture(ATLAS_TEXTURE_TARGET, 0);
+        glDisable(ATLAS_TEXTURE_TARGET);
+
+        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _atlas_fbo);
+        _streamVertices->read(_atlasWidth, _atlasHeight);
+        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+        _currentStreamlineIndex++;
+
+        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+    }
+}
+
+bool ParticleSystem::advect(float deltaT, float camx, float camy, float camz)
+{
+    static bool firstLoad = true;
+    if (this->isTimeVaryingField()) {
+        static float oldTime = (float)clock()/(float)CLOCKS_PER_SEC;
+#ifdef WANT_TRACE
+        static int index = 0;
+#endif
+        float time = (float)clock()/(float)CLOCKS_PER_SEC;
+        if ((time - oldTime) > 2.0) {
+            if (!_queue.isEmpty()) {
+                float *data = NULL;
+                if (_queue.top(data)) {
+#ifdef WANT_TRACE
+                    float t = clock() /(float) CLOCKS_PER_SEC;
+#endif
+                    _vectorFields[0]->update(data);
+#ifdef WANT_TRACE
+                    float ti = clock() / (float) CLOCKS_PER_SEC;
+                    TRACE("updatePixels time: %f", ti - t);
+#endif
+                    _queue.pop();
+                    oldTime = time;
+
+                    firstLoad = false;
+                    TRACE("%d bound", index++);
+                }
+            }		
+        }
+        if (firstLoad) return false;
+    }
+
+    if (!_advectionEnabled) return true;
+    if (this->_streamlineEnabled) {
+        advectStreamlines();
+        _currentTime += deltaT;
+    } else {
+        _camx = camx;
+        _camy = camy;
+        _camz = camz;
+
+        glDisable(GL_BLEND);
+        glDisable(GL_DEPTH_TEST);
+
+        glPushAttrib(GL_VIEWPORT_BIT);
+        glViewport(0, 0, _width, _height);
+        glMatrixMode(GL_PROJECTION);
+        glPushMatrix();
+        glLoadIdentity();
+        glOrtho(0, _width, 0, _height, -10.0f, 10.0f);
+        glMatrixMode(GL_MODELVIEW);
+        glPushMatrix();
+        glLoadIdentity();
+
+        glEnable(GL_TEXTURE_RECTANGLE_ARB);
+
+        cgGLBindProgram(_moveParticlesFP);
+        cgGLEnableProfile(CG_PROFILE_FP40);
+
+        // INSOO
+        // TIME SCALE
+
+        cgGLSetParameter1f(_mpTimeScale, 0.005);
+
+        //////////////////////////////////////////////////////
+        // UPDATE POS
+        cgGLSetTextureParameter(_mpVectorField, _curVectorFieldID);
+        cgGLEnableTextureParameter(_mpVectorField);
+        cgGLSetParameter3f(_mpScale, _scalex, _scaley, _scalez);
+        cgGLSetParameter1f(_mpMaxScale, _maxVelocityScale);
+        for (int i = 0; i < _stepSizeStreamline; ++i) {
+            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, psys_fbo[_destPosIndex]);
+            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+            glActiveTextureARB(GL_TEXTURE0_ARB);
+            glBindTexture(GL_TEXTURE_RECTANGLE_ARB, psys_tex[_currentPosIndex]);
+            glActiveTextureARB(GL_TEXTURE1_ARB);
+            glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _initPosTex);
+            drawQuad();
+            swap(_currentPosIndex, _destPosIndex);
+        }
+        cgGLDisableTextureParameter(_mpVectorField);
+
+        glActiveTextureARB(GL_TEXTURE1_ARB);
+        glDisable(GL_TEXTURE_RECTANGLE_ARB);
+        glActiveTextureARB(GL_TEXTURE0_ARB);
+        glDisable(GL_TEXTURE_RECTANGLE_ARB);
+
+        glDisable(GL_TEXTURE_RECTANGLE_ARB);
+        cgGLDisableProfile(CG_PROFILE_FP40);
+
+        glMatrixMode(GL_PROJECTION);
+        glPopMatrix();
+        glMatrixMode(GL_MODELVIEW);
+        glPopMatrix();
+        glPopAttrib();
+        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+
+        if (_sortEnabled) {
+            sort();
+
+            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, psys_fbo[_destPosIndex]);
+            _vertices->read(_width, _height);
+            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+        } else {
+            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, psys_fbo[_currentPosIndex]);
+            _vertices->read(_width, _height);
+            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+        }
+
+        // NEW PARTICLES
+        for (unsigned int i = 0; i < _emitters.size(); ++i) {
+            // TBD..
+            unsigned int numOfNewParticles = (unsigned int)(randomRange(_emitters[i]->_minNumOfNewParticles, _emitters[i]->_maxNumOfNewParticles) * deltaT);
+            for (unsigned int k = 0; k < numOfNewParticles; ++k) {
+                vrmath::Vector3f position = _emitters[i]->_position;
+                position +=
+                    _emitters[i]->_maxPositionOffset.scale(vrmath::Vector3f(randomRange(-1.0f, 1.0f),
+                                                                            randomRange(-1.0f, 1.0f),
+                                                                            randomRange(-1.0f, 1.0f)));
+                float lifetime = randomRange(_emitters[i]->_minLifeTime, _emitters[i]->_maxLifeTime);
+
+                // TBD..
+                allocateParticle(position, vrmath::Vector3f(0.0f, 0.0f, 0.0f),  lifetime, 1 - (float) k / numOfNewParticles);
+            }
+        }
+
+        initNewParticles();
+
+        _currentTime += deltaT;
+
+        cleanUpParticles();
+    }
+
+    return true;
+}
+
+void ParticleSystem::allocateParticle(const vrmath::Vector3f& position, const vrmath::Vector3f& velocity,
+                                      float lifeTime, float initTimeStep)
+{
+    if (_availableIndices.empty()) {
+        return;
+    }
+
+    int index = _availableIndices.top(); 
+    _availableIndices.pop();
+
+    ActiveParticle p;
+    p.index = index;
+    p.timeOfDeath = _currentTime + lifeTime;
+    _activeParticles.push(p);
+
+    NewParticle newParticle;
+    newParticle.index = index;
+    newParticle.position = position;
+    newParticle.velocity = velocity;
+    newParticle.timeOfDeath = p.timeOfDeath;
+    newParticle.initTimeStep = initTimeStep;
+
+    _newParticles.push_back(newParticle);
+
+    _particles[index].timeOfBirth = _currentTime;
+    _particles[index].lifeTime = lifeTime;
+}
+
+void ParticleSystem::initNewParticles()
+{
+    /////////////////////////////
+    // INIT NEW PARTICLE
+    glBindBufferARB(GL_ARRAY_BUFFER_ARB, _particleInfoBufferID);
+    Particle* pinfo = (Particle*) glMapBufferARB(GL_ARRAY_BUFFER, GL_WRITE_ONLY_ARB);
+
+    std::vector<NewParticle>::iterator iter;
+    for (iter = _newParticles.begin(); iter != _newParticles.end(); ++iter) {
+        pinfo[iter->index] = _particles[iter->index];
+    }
+
+    glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
+
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, psys_fbo[_currentPosIndex]);
+
+    glPushAttrib(GL_VIEWPORT_BIT);
+    glViewport(0, 0, _width, _height);
+    glMatrixMode(GL_PROJECTION);
+    glPushMatrix();
+    glLoadIdentity();
+    glOrtho(0, _width, 0, _height, -10.0f, 10.0f);
+    glMatrixMode(GL_MODELVIEW);
+    glPushMatrix();
+    glLoadIdentity();
+
+    cgGLBindProgram(_initParticlePosFP);
+    cgGLEnableProfile(CG_PROFILE_FP40);
+    cgGLSetTextureParameter(_ipVectorFieldParam, _curVectorFieldID);
+    cgGLEnableTextureParameter(_ipVectorFieldParam);
+    // TBD..
+    //glActiveTextureARB(GL_TEXTURE0_ARB);
+    //VelocityPBuffers[VelocityCurrent]->Bind();
+
+    glActiveTextureARB(GL_TEXTURE0_ARB);
+    glEnable(GL_TEXTURE_RECTANGLE_ARB);
+    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, psys_tex[_destPosIndex]);
+
+    glBegin(GL_POINTS);
+    for (iter = _newParticles.begin(); iter != _newParticles.end(); iter++) {
+        //TRACE("[%d] %f %f %f", iter->index, iter->position.x,iter->position.y,iter->position.z);
+        glMultiTexCoord3f(GL_TEXTURE0, iter->position.x,iter->position.y,iter->position.z);
+
+        // TBD..
+        //glMultiTexCoord2f(GL_TEXTURE1_ARB, (float)(i->Index % Width), (float)(i->Index / Height));
+        //glMultiTexCoord1f(GL_TEXTURE2_ARB, iter->initTimeStep);
+
+        glVertex2f((float)(iter->index % _width),
+                   (float)(iter->index / _height) + 1/* + offsetY*/ /* + offsetY shouldn't be */);
+        //TRACE("%f %f", (float) (iter->index % _width), (float)(iter->index / _width));
+    }
+    glEnd();
+
+    glDisable(GL_TEXTURE_RECTANGLE_ARB);
+    cgGLDisableTextureParameter(_ipVectorFieldParam);
+    cgGLDisableProfile(CG_PROFILE_FP40);
+
+    glMatrixMode(GL_PROJECTION);
+    glPopMatrix();
+    glMatrixMode(GL_MODELVIEW);
+    glPopMatrix();
+    glPopAttrib();
+
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+
+    // INIT NEW END
+    /////////////////////////////
+#if 1
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _initPos_fbo);
+    glPushAttrib(GL_VIEWPORT_BIT);
+    glViewport(0, 0, _width, _height);
+    glMatrixMode(GL_PROJECTION);
+    glPushMatrix();
+    glLoadIdentity();
+    glOrtho(0, _width, 0, _height, -10.0f, 10.0f);
+    glMatrixMode(GL_MODELVIEW);
+    glPushMatrix();
+    glLoadIdentity();
+
+    cgGLBindProgram(_initParticlePosFP);
+    cgGLEnableProfile(CG_PROFILE_FP40);
+    cgGLSetTextureParameter(_ipVectorFieldParam, _curVectorFieldID);
+    cgGLEnableTextureParameter(_ipVectorFieldParam);
+    // TBD..
+    //glActiveTextureARB(GL_TEXTURE0_ARB);
+    //VelocityPBuffers[VelocityCurrent]->Bind();
+
+    glActiveTextureARB(GL_TEXTURE0_ARB);
+    glEnable(GL_TEXTURE_RECTANGLE_ARB);
+    //glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _initPosTex);
+    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, psys_tex[_destPosIndex]);
+
+    glBegin(GL_POINTS);
+    for (iter = _newParticles.begin(); iter != _newParticles.end(); iter++) {
+        //TRACE("[%d] %f %f %f", iter->index, iter->position.x,iter->position.y,iter->position.z);
+        glMultiTexCoord3f(GL_TEXTURE0, iter->position.x,iter->position.y,iter->position.z);
+
+        // TBD..
+        //glMultiTexCoord2f(GL_TEXTURE1_ARB, (float)(i->Index % Width), (float)(i->Index / Height));
+        //glMultiTexCoord1f(GL_TEXTURE2_ARB, iter->initTimeStep);
+
+        glVertex2f((float)(iter->index % _width),
+                   (float)(iter->index / _height) + 1/* + offsetY*/ /* + offsetY shouldn't be */);
+        //TRACE("%f %f", (float) (iter->index % _width), (float)(iter->index / _width));
+    }
+    glEnd();
+
+    glDisable(GL_TEXTURE_RECTANGLE_ARB);
+    cgGLDisableTextureParameter(_ipVectorFieldParam);
+    cgGLDisableProfile(CG_PROFILE_FP40);
+
+    glMatrixMode(GL_PROJECTION);
+    glPopMatrix();
+    glMatrixMode(GL_MODELVIEW);
+    glPopMatrix();
+    glPopAttrib();
+
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+#endif
+
+    // Free array.
+    _newParticles.clear();
+}
+
+void ParticleSystem::cleanUpParticles()
+{
+    if (! _activeParticles.empty()) {
+        while (_activeParticles.top().timeOfDeath < _currentTime) {
+            unsigned int i = _activeParticles.top().index;
+            _activeParticles.pop();
+            _availableIndices.push(i);
+            //_usedIndices[i] = false;
+
+            //if (i >= _maxUsedIndex)
+            //    while (!_usedIndices[_maxUsedIndex])
+            //        _maxUsedIndex--;
+        }
+    }
+}
+
+void ParticleSystem::sort()
+{
+    ///////////////////////////////////////////////////////////
+    // BEGIN - COMPUTE DISTANCE	
+    vrmath::Vector3f pos;
+    vrmath::Matrix4x4d mat;
+    glPushMatrix();
+    glLoadIdentity();
+    glScalef(_scalex, _scaley, _scalez);
+    glTranslatef(-0.5f, -0.5f, -0.5f);
+    glGetDoublev(GL_MODELVIEW_MATRIX, mat.get());
+    glPopMatrix();
+    mat.invert();
+    mat.getTranslation(pos);
+
+    cgGLBindProgram(_distanceSortFP);
+    cgGLEnableProfile(CG_PROFILE_FP40);
+
+    glActiveTextureARB(GL_TEXTURE0_ARB);
+    glEnable(GL_TEXTURE_RECTANGLE_ARB);
+    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, sort_tex[_currentSortIndex]);
+
+    glActiveTextureARB(GL_TEXTURE1_ARB);
+    glEnable(GL_TEXTURE_RECTANGLE_ARB);
+    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, psys_tex[_currentPosIndex]);
+
+    cgGLSetParameter3f(_viewPosParam, pos.x, pos.y, pos.z);
+
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, sort_fbo[_destSortIndex]);
+    glPushAttrib(GL_VIEWPORT_BIT);
+    glViewport(0, 0, _width, _height);
+    glMatrixMode(GL_PROJECTION);
+    glPushMatrix();
+    glLoadIdentity();
+    glOrtho(0, _width, 0, _height, -10.0f, 10.0f);
+    glMatrixMode(GL_MODELVIEW);
+    glPushMatrix();
+    glLoadIdentity();
+
+    drawQuad();
+
+    cgGLDisableProfile(CG_PROFILE_FP40);
+
+    glMatrixMode(GL_PROJECTION);
+    glPopMatrix();
+    glMatrixMode(GL_MODELVIEW);
+    glPopMatrix();
+    glPopAttrib();
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+
+    // _DEBUG
+    /*
+    {
+        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, sort_fbo[_destSortIndex]);
+        static float debug[256];
+        glReadPixels(0, 0, _width, _height, GL_RGB, GL_FLOAT, (float*)debug);
+        TRACE("[%d]", _currentSortIndex);
+        for (int i = 0; i < _width * _height * 3; i += 3)
+            TRACE("%.2f, %.2f, %.2f", debug[i], debug[i+1], debug[i+2]);
+        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+    }
+    */
+
+    // _DEBUG
+    /*
+    {
+        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, psys_fbo[_currentPosIndex]);
+        static float debug[256];
+        glReadPixels(0, 0, _width, _height, GL_RGB, GL_FLOAT, (float*)debug);
+        TRACE("currentPos[%d]", _currentPosIndex);
+        for (int i = 0; i < _width * _height * 3; i += 3)
+            TRACE("%.2f, %.2f, %.2f", debug[i], debug[i+1], debug[i+2]);
+        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+    }
+    */
+
+    // compute distance
+    swap(_currentSortIndex, _destSortIndex);
+
+    // END - COMPUTE DISTANCE
+    ///////////////////////////////////////////////////////////
+
+    ///////////////////////////////////////////////////////////
+    // BEGIN - MERGE SORT
+    _currentSortPass = 0;
+
+    int logdSize = logd(_particleMaxCount);
+    _maxSortPasses = (logdSize + 1) * logdSize / 2;
+
+    _sortBegin = _sortEnd;
+    _sortEnd = (_sortBegin + _sortPassesPerFrame) % _maxSortPasses;
+
+    cgGLSetParameter2f(_srSizeParam, (float)_width, (float)_height);
+    cgGLSetParameter2f(_seSizeParam, (float)_width, (float)_height);
+
+    mergeSort(this->_particleMaxCount);
+
+    // _DEBUG
+    /*
+    {
+        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, sort_fbo[_currentSortIndex]);
+        static float debug[256];
+        glReadPixels(0, 0, _width, _height, GL_RGB, GL_FLOAT, (float*)debug);
+        TRACE("[%d]", _currentSortIndex);
+        for (int i = 0; i < _width * _height * 3; i += 3)
+            TRACE("%.2f, %.2f, %.2f", debug[i], debug[i+1], debug[i+2]);
+        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+    }
+    */
+
+    // END - MERGE SORT
+    ///////////////////////////////////////////////////////////
+
+    ///////////////////////////////////////////////////////////
+    // POSITION LOOKUP
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, psys_fbo[_destPosIndex]);
+    cgGLBindProgram(_distanceSortLookupFP);
+    cgGLEnableProfile(CG_PROFILE_FP40);
+
+    glActiveTextureARB(GL_TEXTURE0_ARB);
+    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, sort_tex[_currentSortIndex]);
+
+    glActiveTextureARB(GL_TEXTURE1_ARB);
+    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, psys_tex[_currentPosIndex]);
+
+    glPushAttrib(GL_VIEWPORT_BIT);
+    glViewport(0, 0, _width, _height);
+    glMatrixMode(GL_PROJECTION);
+    glPushMatrix();
+    glLoadIdentity();
+    glOrtho(0, _width, 0, _height, -10.0f, 10.0f);
+    glMatrixMode(GL_MODELVIEW);
+    glPushMatrix();
+    glLoadIdentity();
+
+    drawQuad();
+
+    glMatrixMode(GL_PROJECTION);
+    glPopMatrix();
+    glMatrixMode(GL_MODELVIEW);
+    glPopMatrix();
+    glPopAttrib();
+
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+    cgGLDisableProfile(CG_PROFILE_FP40);
+
+    // POSITION LOOKUP
+    ///////////////////////////////////////////////////////////
+    glActiveTextureARB(GL_TEXTURE1_ARB);
+    glDisable(GL_TEXTURE_RECTANGLE_ARB);
+
+    glActiveTextureARB(GL_TEXTURE0_ARB);
+    glDisable(GL_TEXTURE_RECTANGLE_ARB);
+
+    // _DEBUG
+    /*
+    {
+        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, psys_fbo[_destPosIndex]);
+        static float debug[256];
+        glReadPixels(0, 0, _width, _height, GL_RGB, GL_FLOAT, (float*)debug);
+        TRACE("[%d]", _currentSortIndex);
+        for (int i = 0; i < _width * _height * 3; i += 3)
+            TRACE("%.2f, %.2f, %.2f", debug[i], debug[i+1], debug[i+2]);
+        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+    }
+    */
+}
+
+void ParticleSystem::mergeSort(int count)
+{
+    if (count > 1) {
+        mergeSort(count >> 1);
+        merge(count, 1);
+    }
+}
+
+void ParticleSystem::merge(int count, int step)
+{
+    if (count > 2) {
+        merge(count >> 1, step << 1);
+
+        ++_currentSortPass;
+
+        if (_sortBegin < _sortEnd) {
+            if (_currentSortPass < _sortBegin || _currentSortPass >= _sortEnd)
+                return;
+        } else {
+            if (_currentSortPass < _sortBegin && _currentSortPass >= _sortEnd)
+                return;
+        }
+
+        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, sort_fbo[_destSortIndex]);
+        cgGLBindProgram(_sortRecursionFP);
+        cgGLEnableProfile(CG_PROFILE_FP40);
+
+        glActiveTextureARB(GL_TEXTURE0_ARB);
+        glBindTexture(GL_TEXTURE_RECTANGLE_ARB , sort_tex[_currentSortIndex]);
+
+        cgGLSetParameter1f(_srStepParam, (float)step);
+        cgGLSetParameter1f(_srCountParam, (float)count);
+
+        glPushAttrib(GL_VIEWPORT_BIT);
+        glViewport(0, 0, _width, _height);
+        glMatrixMode(GL_PROJECTION);
+        glPushMatrix();
+        glLoadIdentity();
+        glOrtho(0, _width, 0, _height, -10.0f, 10.0f);
+        glMatrixMode(GL_MODELVIEW);
+        glPushMatrix();
+        glLoadIdentity();
+
+        drawQuad();
+
+        glMatrixMode(GL_PROJECTION);
+        glPopMatrix();
+        glMatrixMode(GL_MODELVIEW);
+        glPopMatrix();
+        glPopAttrib();
+
+        cgGLDisableProfile(CG_PROFILE_FP40);
+
+        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+        glBindTexture(GL_TEXTURE_RECTANGLE_ARB , 0);
+    } else {
+        _currentSortPass++;
+
+        if (_sortBegin < _sortEnd) {
+            if (_currentSortPass < _sortBegin || _currentSortPass >= _sortEnd)
+                return;
+        } else {
+            if (_currentSortPass < _sortBegin && _currentSortPass >= _sortEnd)
+                return;
+        }
+
+        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, sort_fbo[_destSortIndex]);
+        cgGLBindProgram(_sortEndFP);
+        cgGLEnableProfile(CG_PROFILE_FP40);
+
+        glActiveTextureARB(GL_TEXTURE0_ARB);
+        glBindTexture(GL_TEXTURE_RECTANGLE_ARB , sort_tex[_currentSortIndex]);
+
+        cgGLSetParameter1f(_seStepParam, (float)step);
+
+        glPushAttrib(GL_VIEWPORT_BIT);
+        glViewport(0, 0, _width, _height);
+        glMatrixMode(GL_PROJECTION);
+        glPushMatrix();
+        glLoadIdentity();
+        glOrtho(0, _width, 0, _height, -10.0f, 10.0f);
+        glMatrixMode(GL_MODELVIEW);
+        glPushMatrix();
+        glLoadIdentity();
+
+        drawQuad();
+
+        glMatrixMode(GL_PROJECTION);
+        glPopMatrix();
+        glMatrixMode(GL_MODELVIEW);
+        glPopMatrix();
+        glPopAttrib();
+
+        cgGLDisableProfile(CG_PROFILE_FP40);
+
+        glBindTexture(GL_TEXTURE_RECTANGLE_ARB , 0);
+        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+    }
+
+    swap(_currentSortIndex, _destSortIndex);
+}
+
+void ParticleSystem::renderStreamlines()
+{
+    if (_currentStreamlineIndex > 2) {
+        glPushMatrix();
+        glScalef(_scalex, _scaley, _scalez);
+        glTranslatef(-0.5f, -0.5f, -0.5f);
+
+        if (_drawBBoxEnabled) drawUnitBox();
+
+        glColor3f(1.0f, 0.0f, 0.0f);
+        glEnableClientState(GL_VERTEX_ARRAY);
+        //glEnableClientState(GL_COLOR_ARRAY);
+
+        _streamVertices->setPointer(0);
+        //glColorPointer(4, GL_FLOAT, 0, 0);
+
+        ::glDrawElements(GL_LINES, _particleCount * 2 * (_currentStreamlineIndex - 1),
+                         GL_UNSIGNED_INT, _indexBuffer);
+        glDisableClientState(GL_VERTEX_ARRAY);
+        glPopMatrix();
+    }
+}
+
+void ParticleSystem::render()
+{
+    glPushMatrix();
+
+    if (_streamlineEnabled) {
+        renderStreamlines();
+    } else {
+        glScalef(_scalex, _scaley, _scalez);
+        glTranslatef(-0.5f, -0.5f, -0.5f);
+        if (_glyphEnabled) {
+            if (_drawBBoxEnabled) drawUnitBox();
+            glColor3f(1, 1, 1);
+
+            glDepthMask(GL_FALSE);
+            glEnable(GL_BLEND);
+
+#ifndef USE_RGBA_ARROW
+            glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+#else
+            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+#endif
+            glEnable(GL_ALPHA_TEST);
+            glAlphaFunc(GL_GREATER, 0.6);
+
+            glEnable(GL_POINT_SPRITE_ARB);
+            glPointSize(_pointSize);
+
+            glEnable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB);
+
+#ifndef TEST
+            _arrows->activate();
+            glEnable(GL_TEXTURE_2D);
+            glPointParameterfARB(GL_POINT_FADE_THRESHOLD_SIZE_ARB, 0.0f);
+
+            glPointParameterfARB(GL_POINT_SIZE_MIN_ARB, 1.0f);
+            glPointParameterfARB(GL_POINT_SIZE_MAX_ARB, 100.0f);
+            glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
+
+            cgGLBindProgram(_particleVP);
+            cgGLBindProgram(_particleFP);
+            cgGLEnableProfile(CG_PROFILE_VP40);
+            cgGLEnableProfile(CG_PROFILE_FP40);
+
+            cgSetParameter1f(_mvCurrentTimeParam, _currentTime);
+            //TRACE("%f %f, %f %d", _fov, tan(_fov), tan(_fov / 2.0), _screenHeight);
+            //cgSetParameter1f(_mvTanHalfFOVParam, -tan(_fov * M_PI / 180 * 0.5) * _screenHeight * 0.5);
+            //float v = tan(_fov * M_PI / 180 * 0.5) * _screenHeight * 0.5;
+            cgSetParameter1f(_mvTanHalfFOVParam, tan(_fov * M_PI / 180 * 0.5) * _screenHeight * 0.5);
+            //cgSetParameter1f(_mvTanHalfFOVParam,  _screenHeight * 0.5 / tan(_fov * M_PI / 180 * 0.5));
+
+            cgGLSetStateMatrixParameter(_mvpParticleParam,
+                                        CG_GL_MODELVIEW_PROJECTION_MATRIX,
+                                        CG_GL_MATRIX_IDENTITY);
+            cgGLSetStateMatrixParameter(_mvParticleParam,
+                                        CG_GL_MODELVIEW_MATRIX,
+                                        CG_GL_MATRIX_IDENTITY);
+
+            // TBD..
+            glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);			
+            glEnableVertexAttribArrayARB(8);
+            glEnableClientState(GL_VERTEX_ARRAY);
+            //glEnableClientState(GL_COLOR_ARRAY);
+            _vertices->setPointer(0);
+            //glBindBufferARB(GL_ARRAY_BUFFER, _colorBufferID);
+            //glColorPointer(4, GL_FLOAT, 0, 0);
+            //glBindBufferARB(GL_ARRAY_BUFFER, 0);
+
+            // TBD...
+            glDrawArrays(GL_POINTS, 0, this->_particleMaxCount);
+            glPointSize(1);
+
+            glDisableClientState(GL_VERTEX_ARRAY);
+            //glDisableClientState(GL_COLOR_ARRAY);
+
+            // TBD...
+            ::glDisableVertexAttribArray(8);
+            glPopClientAttrib();
+
+            cgGLDisableProfile(CG_PROFILE_VP40);
+            cgGLDisableProfile(CG_PROFILE_FP40);
+
+            glDepthMask(GL_TRUE);
+
+            glDisable(GL_POINT_SPRITE_ARB);
+            glDisable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB);
+
+            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+            glDisable(GL_BLEND);
+#else
+            glBindTexture(GL_TEXTURE_2D, ::SpotTexID);
+            glEnable(GL_TEXTURE_2D);
+            //glPointParameterfARB(GL_POINT_FADE_THRESHOLD_SIZE_ARB, 60.0f);
+            glPointParameterfARB(GL_POINT_FADE_THRESHOLD_SIZE_ARB, 0.0f);
+
+            glPointParameterfARB(GL_POINT_SIZE_MIN_ARB, 1.0f);
+            glPointParameterfARB(GL_POINT_SIZE_MAX_ARB, 100.0f);
+            glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
+
+            glEnableClientState(GL_VERTEX_ARRAY);
+            //glEnableClientState(GL_COLOR_ARRAY);
+            _vertices->setPointer(0);
+            //glBindBufferARB(GL_ARRAY_BUFFER, _colorBufferID);
+            //glColorPointer(4, GL_FLOAT, 0, 0);
+            //glBindBufferARB(GL_ARRAY_BUFFER, 0);
+
+            // TBD...
+            glDrawArrays(GL_POINTS, 0, this->_particleMaxCount);
+            glPointSize(1);
+            glDrawArrays(GL_POINTS, 0, this->_particleMaxCount);
+
+            glDisableClientState(GL_VERTEX_ARRAY);
+
+            glDepthMask(GL_TRUE);
+
+            glDisable(GL_POINT_SPRITE_ARB);
+            glDisable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB);
+
+            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+            glDisable(GL_BLEND);
+#endif
+        } else {
+            if (_drawBBoxEnabled) drawUnitBox();
+
+            glColor3f(1, 1, 1);
+            glEnableClientState(GL_VERTEX_ARRAY);
+            //glEnableClientState(GL_COLOR_ARRAY);
+            glPointSize(10);
+            _vertices->setPointer(0);
+            //glBindBufferARB(GL_ARRAY_BUFFER, _colorBufferID);
+            //glColorPointer(4, GL_FLOAT, 0, 0);
+            //glBindBufferARB(GL_ARRAY_BUFFER, 0);
+            glDrawArrays(GL_POINTS, 0, _particleMaxCount);
+
+            glPointSize(1);
+            _vertices->setPointer(0);
+            //glBindBufferARB(GL_ARRAY_BUFFER, _colorBufferID);
+            //glColorPointer(4, GL_FLOAT, 0, 0);
+            //glBindBufferARB(GL_ARRAY_BUFFER, 0);
+            glDrawArrays(GL_POINTS, 0, _particleMaxCount);
+
+            glDisableClientState(GL_VERTEX_ARRAY);
+        }
+
+#ifdef notdef
+        if (_criticalPoints && _criticalPoints->size()) {
+            std::vector<vrmath::Vector3f>::iterator iter;
+            glColor4f(1, 1, 1, 1);
+            glPointSize(10);
+            glBegin(GL_POINTS);
+            for (iter = _criticalPoints->begin(); iter != _criticalPoints->end(); ++iter) {
+                glVertex3f((*iter).x, (*iter).y, (*iter).z);
+            }
+            glEnd();
+            glPointSize(1);
+        }
+#endif
+    }
+
+    glPopMatrix();
+}
+
+void ParticleSystem::drawQuad(int x1, int y1, int x2, int y2)
+{
+    glBegin(GL_QUADS);
+
+    glTexCoord2f(x1, y1);
+    glVertex2f(x1, y1);
+
+    glTexCoord2f(x2, y1);
+    glVertex2f(x2, y1);
+
+    glTexCoord2f(x2, y2); 
+    glVertex2f(x2, y2);
+
+    glTexCoord2f(x1, y2);
+    glVertex2f(x1, y2);
+
+    glEnd();
+}
+
+void ParticleSystem::drawQuad()
+{
+    glBegin(GL_QUADS);
+
+    glTexCoord2f(0, 0);
+    glVertex2f(0, 0);
+
+    glTexCoord2f((float)_width, 0);
+    glVertex2f((float)_width, 0);
+
+    glTexCoord2f((float)_width, (float)_height); 
+    glVertex2f((float)_width, (float)_height);
+
+    glTexCoord2f(0, (float)_height);
+    glVertex2f(0, (float)_height);
+
+    glEnd();
+}
+
+void ParticleSystem::addEmitter(ParticleEmitter* emitter)
+{
+    _emitters.push_back(emitter);
+}
+
+void ParticleSystem::removeEmitter(int index)
+{
+    // TBD...
+}
+
+void ParticleSystem::removeAllEmitters()
+{
+    std::vector<ParticleEmitter*>::iterator iter;
+    for (iter = _emitters.begin(); iter != _emitters.end(); ++iter) {
+        delete *iter;
+    }
+    _emitters.clear();
+}
+
+void ParticleSystem::drawUnitBox()
+{
+    float x0 = 0.0f, y0 = 0.0f, z0 = 0.0f;
+    float x1 = 1.0f, y1 = 1.0f, z1 = 1.0f;
+    float r = 1.0f, g = 1.0f, b = 0.0f;
+    float line_width = 2.0f;
+    glEnable(GL_DEPTH_TEST);
+    glDisable(GL_TEXTURE_2D);
+    glEnable(GL_BLEND);
+
+    glColor4d(r, g, b, 1.0);
+    glLineWidth(line_width);
+
+    glBegin(GL_LINE_LOOP);
+    {
+        glVertex3d(x0, y0, z0);
+        glVertex3d(x1, y0, z0);
+        glVertex3d(x1, y1, z0);
+        glVertex3d(x0, y1, z0);
+    }
+    glEnd();
+
+    glBegin(GL_LINE_LOOP);
+    {
+        glVertex3d(x0, y0, z1);
+        glVertex3d(x1, y0, z1);
+        glVertex3d(x1, y1, z1);
+        glVertex3d(x0, y1, z1);
+    }
+    glEnd();
+
+    glBegin(GL_LINE_LOOP);
+    {
+        glVertex3d(x0, y0, z0);
+        glVertex3d(x0, y0, z1);
+        glVertex3d(x0, y1, z1);
+        glVertex3d(x0, y1, z0);
+    }
+    glEnd();
+
+    glBegin(GL_LINE_LOOP);
+    {
+        glVertex3d(x1, y0, z0);
+        glVertex3d(x1, y0, z1);
+        glVertex3d(x1, y1, z1);
+        glVertex3d(x1, y1, z0);
+    }
+    glEnd();
+    glLineWidth(1.0f);
+}
+
+void ParticleSystem::setUserDefinedNumOfParticles(int numParticles)
+{
+    if (numParticles < _particleMaxCount)
+        _userDefinedParticleMaxCount = numParticles;
+    else
+        _userDefinedParticleMaxCount = _particleMaxCount;
+    reset();
+}
Index: /nanovis/tags/1.1.4/ParticleSystem.h
===================================================================
--- /nanovis/tags/1.1.4/ParticleSystem.h	(revision 4930)
+++ /nanovis/tags/1.1.4/ParticleSystem.h	(revision 4930)
@@ -0,0 +1,411 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#ifndef NV_PARTICLESYSTEM_H
+#define NV_PARTICLESYSTEM_H
+
+#include <vector>
+#include <queue>
+#include <string>
+#include <algorithm>
+#include <limits>
+
+#include <Cg/cg.h>
+
+#include <vrmath/Vector3f.h>
+
+#include "ParticleEmitter.h"
+#include "RenderVertexArray.h"
+#include "Texture2D.h"
+#include "Texture3D.h"
+
+#include "CircularQueue.h"
+
+namespace nv {
+
+struct NewParticle {
+    int index;
+    vrmath::Vector3f position;
+    vrmath::Vector3f velocity;
+    float timeOfDeath;
+    float initTimeStep;
+};
+
+template <typename Type, typename Compare=std::less<Type> >
+class priority_queue_vector : public std::priority_queue<Type, std::vector<Type>, Compare>
+{
+public:
+    void reserve(typename priority_queue_vector<Type>::size_type count)
+    {
+        //priority_queue<Type, std::vector<Type>, Compare>::reserve(count);
+    }
+};
+
+struct ActiveParticle {
+    float timeOfDeath;
+    int index;
+};
+
+struct particle_greater {
+    bool operator() (const ActiveParticle& left, const ActiveParticle& right)
+    {
+        return (left.timeOfDeath > right.timeOfDeath);
+    }
+};
+
+struct color4 {
+    float r, g, b, a;
+};
+
+struct Particle {
+    float timeOfBirth;
+    float lifeTime;
+    float attributeType;
+    float index;
+};
+
+class ParticleSystem
+{
+public:
+    enum EnableEnum {
+        PS_SORT = 1,
+        PS_GLYPH = 2,
+        PS_DRAW_BBOX = 4,
+        PS_ADVECTION = 8,
+        PS_STREAMLINE = 16,
+    };
+
+    ParticleSystem(int width, int height, const std::string& fileName,
+                   int fieldWidth, int fieldHeight, int fieldDepth, 
+                   bool timeVaryingData, int flowFileStartIndex, int flowFileEndIndex);
+    ~ParticleSystem();
+    void createRenderTargets();
+    void createSortRenderTargets();
+    void createStreamlineRenderTargets();
+    void advectStreamlines();
+    void renderStreamlines();
+
+    bool advect(float deltaT, float camx, float camy, float camz);
+    void enable(EnableEnum enabled);
+    void disable(EnableEnum enabled);
+    bool isEnabled(EnableEnum enabled);
+
+    ////////////////////////////////////////////
+    void addEmitter(ParticleEmitter *emitter);
+    ParticleEmitter *getEmitter(int index);
+    unsigned int getNumEmitters() const;
+    void removeEmitter(int index);
+    void removeAllEmitters();
+
+    int getMaxSize() const;
+
+    void render();
+
+    void reset();
+
+    void setDefaultPointSize(float size);
+
+    unsigned int getNumOfActiveParticles() const;
+
+    void setScreenSize(int sreenWidth, int screenHeight);
+
+    void setFOV(float fov);
+
+    void setUserDefinedNumOfParticles(int numParticles);
+
+    float getScaleX() const;
+    float getScaleY() const;
+    float getScaleZ() const;
+    unsigned int getVectorFieldGraphicsID() const;
+
+    bool isTimeVaryingField() const;
+    void setTimeVaryingField(bool timeVarying);
+
+    void setDepthCueEnabled(bool enabled);
+    bool getDepthCueEnabled() const;
+
+    static void *dataLoadMain(void *data);
+    // TEMP
+    static void callbackForCgError();
+
+    const int _width;
+    const int _height;
+    /**
+     * @brief The total number of particles (= _width * _height)
+     */
+    int _particleMaxCount;
+    /**
+     * @brief The total number of particles avaiable (1 <= _userDefinedParticleMaxCount <= _width * _height)
+     */
+    unsigned int _userDefinedParticleMaxCount;
+
+    int _currentSortPass;
+    int _maxSortPasses;
+    int _sortPassesPerFrame;
+
+    int _sortBegin;
+    int _sortEnd;
+
+    float _pointSize;
+
+    /**
+     * @brief The index for the source render target
+     */
+    int _currentSortIndex;
+
+    /**
+     * @brief The index for the destination render target
+     */
+    int _destSortIndex;
+
+    int _currentPosIndex;
+    int _destPosIndex;
+
+    std::vector<ParticleEmitter *> _emitters;
+
+    float _currentTime;
+
+    priority_queue_vector<int, std::greater<int> > _availableIndices;
+    priority_queue_vector<ActiveParticle, particle_greater > _activeParticles;
+    std::vector<NewParticle> _newParticles;
+
+    /**
+     * @brief frame buffer objects: two are defined, flip them as input output every step
+     */
+    unsigned int psys_fbo[2]; 	
+
+    /**
+     * @brief color textures attached to frame buffer objects
+     */
+    unsigned int psys_tex[2];	
+
+    unsigned int sort_fbo[2]; 
+    unsigned int sort_tex[2];
+
+    unsigned int velocity_fbo[2]; 
+    unsigned int velocity_tex[2];
+
+    ///////////////////////////////////////////////////
+    // TIME SERIES
+    std::vector<unsigned int> _vectorFieldIDs;
+    std::vector<Texture3D *> _vectorFields;
+    unsigned int _curVectorFieldID;
+    float _time_series_vel_mag_min;
+    float _time_series_vel_mag_max;
+    CircularFifo<float *, 10> _queue;
+    int _flowFileStartIndex;
+    int _flowFileEndIndex;
+    ///////////////////////////////////////////////////
+    int _skipByte;
+
+    float _maxVelocityScale;
+	
+    RenderVertexArray* _vertices;
+
+    Particle *_particles;
+    vrmath::Vector3f *_positionBuffer;
+    color4 *_colorBuffer;
+    unsigned _colorBufferID;
+    //////////////////////////////////////////
+    Texture2D *_arrows;
+
+    float _camx;
+    float _camy;
+    float _camz;
+
+    float _scalex, _scaley, _scalez;
+
+    bool _sortEnabled;
+    bool _glyphEnabled;
+    bool _drawBBoxEnabled;
+    bool _advectionEnabled;
+    bool _streamlineEnabled;
+    bool _depthCueEnabled;
+
+    CGprogram _distanceInitFP;
+
+    CGprogram _distanceSortFP;
+    CGparameter _viewPosParam;
+
+    CGprogram _distanceSortLookupFP;
+
+    CGprogram _passthroughFP;
+    CGparameter _scaleParam;
+    CGparameter _biasParam;
+
+    CGprogram _sortRecursionFP;
+    CGparameter _srSizeParam;
+    CGparameter _srStepParam;
+    CGparameter _srCountParam;
+
+    CGprogram _sortEndFP;
+    CGparameter _seSizeParam;
+    CGparameter _seStepParam;
+
+    CGprogram _moveParticlesFP;
+    CGparameter _mpTimeScale;
+    CGparameter _mpVectorField;
+    CGparameter _mpUseInitTex;
+    CGparameter _mpCurrentTime;
+    CGparameter _mpMaxScale;
+    CGparameter _mpScale;
+
+    CGprogram _initParticlePosFP;
+    CGparameter _ipVectorFieldParam;
+
+    CGprogram _particleVP;
+    CGparameter _mvpParticleParam;
+    CGparameter _mvParticleParam;
+    CGparameter _mvTanHalfFOVParam;
+    CGparameter _mvCurrentTimeParam;
+	
+    CGprogram _particleFP;
+    CGparameter _vectorParticleParam;
+
+    //////////////////////////////////////////
+    // STREAMLINE
+    unsigned int _maxAtlasCount;
+    unsigned int _currentStreamlineIndex;
+    int _currentStreamlineOffset;
+    int _particleCount;
+    int _stepSizeStreamline;
+    int _curStepCount;
+    int _atlasWidth, _atlasHeight;
+    unsigned int _atlas_fbo;
+    unsigned int _atlas_tex;
+    RenderVertexArray *_streamVertices;
+    unsigned int _atlasIndexBufferID;
+
+    unsigned int _maxIndexBufferSize;
+    unsigned int *_indexBuffer;
+    int _atlas_x, _atlas_y;
+
+    //////////////////////////////////////////
+    // Initial Position
+    unsigned int _initPos_fbo;
+    unsigned int _initPosTex;
+
+    /////////////////////////////////////////
+    // Particle Info Vertex Buffer
+    unsigned int _particleInfoBufferID;
+
+    int _screenWidth;
+    int _screenHeight;
+    float _fov;
+
+    bool _isTimeVaryingField;
+
+    int _flowWidth;
+    int _flowHeight;
+    int _flowDepth;
+
+    std::string _fileNameFormat;
+
+    // INSOO
+    // TEST
+    std::vector<vrmath::Vector3f> *_criticalPoints;
+
+    // TEMP
+    static CGcontext _context;
+
+protected:
+    void mergeSort(int count);
+    void merge(int count, int step);
+    void sort();
+    void drawQuad();
+    void drawUnitBox();
+    void drawQuad(int x1, int y1, int x2, int y2);
+    void initShaders();
+    void passThoughPositions();
+    void initStreamlines(int width, int height);
+    void resetStreamlines();
+    void initInitPosTex();
+
+    void allocateParticle(const vrmath::Vector3f&, const vrmath::Vector3f&, float, float);
+    void initNewParticles();
+    void cleanUpParticles();
+};
+
+inline unsigned int ParticleSystem::getNumEmitters() const
+{
+    return _emitters.size();
+}
+
+inline int ParticleSystem::getMaxSize() const
+{
+    return _width * _height;
+}
+
+inline void ParticleSystem::setDefaultPointSize(float size)
+{
+    _pointSize = size;
+}
+
+inline unsigned int ParticleSystem::getNumOfActiveParticles() const
+{
+    return _activeParticles.size();
+}
+
+inline ParticleEmitter* ParticleSystem::getEmitter(int index)
+{
+    if ((unsigned int) index < _emitters.size())
+        return _emitters[index];
+    return 0;
+}
+
+inline void ParticleSystem::setScreenSize(int screenWidth, int screenHeight)
+{
+    _screenWidth = screenWidth;
+    _screenHeight = screenHeight;
+}
+
+inline void ParticleSystem::setFOV(float fov)
+{
+    _fov = fov;
+}
+
+inline float ParticleSystem::getScaleX()const
+{
+    return _scalex;
+}
+
+inline float ParticleSystem::getScaleY()const
+{
+    return _scaley;
+}
+
+inline float ParticleSystem::getScaleZ()const
+{
+    return _scalez;
+}
+
+inline unsigned int ParticleSystem::getVectorFieldGraphicsID()const
+{
+    return _curVectorFieldID;
+}
+
+inline bool ParticleSystem::isTimeVaryingField() const
+{
+    return _isTimeVaryingField;
+}
+
+inline void ParticleSystem::setTimeVaryingField(bool timeVarying)
+{
+    _isTimeVaryingField = timeVarying;
+}
+
+inline void ParticleSystem::setDepthCueEnabled(bool enabled)
+{
+    _depthCueEnabled = enabled;
+}
+
+inline bool ParticleSystem::getDepthCueEnabled() const
+{
+    return _depthCueEnabled;
+}
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/ParticleSystemFactory.cpp
===================================================================
--- /nanovis/tags/1.1.4/ParticleSystemFactory.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/ParticleSystemFactory.cpp	(revision 4930)
@@ -0,0 +1,222 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#include <stdio.h>
+#include <string.h>
+
+#include <expat.h>
+
+#include <util/FilePath.h>
+
+#include "ParticleSystemFactory.h"
+#include "ParticleSystem.h"
+#include "Trace.h"
+
+using namespace nv;
+using namespace nv::util;
+
+#define BUFSIZE 4096
+
+void ParticleSystemFactory::text(void *data, const XML_Char *txt, int len)
+{
+}
+
+void ParticleSystemFactory::startElement(void *userData, const char *elementName, const char **attrs)
+{
+    ParticleSystemFactory* This = reinterpret_cast<ParticleSystemFactory*>(userData);
+
+    if (!strcmp(elementName, "particle-sys-info")) {
+        This->parseParticleSysInfo(attrs);
+    } else if (!strcmp(elementName, "emitter"))	{
+        This->parseEmitterInfo(attrs);
+    }
+}
+
+void ParticleSystemFactory::endElement(void *userData, const char *name)
+{
+}
+
+ParticleSystemFactory::ParticleSystemFactory() :
+    _newParticleSystem(0)
+{
+}
+
+ParticleSystemFactory::~ParticleSystemFactory()
+{
+}
+
+ParticleSystem* ParticleSystemFactory::create(const std::string& fileName)
+{
+    FILE* fp = fopen(fileName.c_str(), "rb");
+
+    if (fp == 0) {
+        return 0;
+    }
+    XML_Parser parser = XML_ParserCreate(NULL);
+
+    XML_SetUserData(parser, this);
+    XML_SetElementHandler(parser, startElement, endElement);
+
+    size_t stat;
+    size_t cnt;
+
+    while (! feof(fp)) {
+        void *buff = XML_GetBuffer(parser, BUFSIZE);
+        if (! buff) {
+            break;
+        }
+        cnt = fread(buff, 1, BUFSIZE, fp);
+        stat = XML_ParseBuffer(parser, (int) cnt, 0);
+        if (!stat) {
+            //TRACE("Parse error at line %d", XML_GetCurrentLineNumber(parser));
+            break;
+        }
+    }
+
+    fclose(fp);
+
+    XML_ParserFree(parser);
+
+    return _newParticleSystem;
+}
+
+void ParticleSystemFactory::parseParticleSysInfo(const char** attrs)
+{
+    int width = 2, height = 2; // default
+    std::string fileName = "J-wire-vec.dx";
+    float pointSize = -1.0f;
+    int numOfUsedParticles = -1;
+    bool sortEnabled = false;
+    bool glyphEnabled = false;
+    bool bboxVisible = false;
+    bool advectionEnabled = false;
+    bool streamlineEnabled = false;
+    bool timeVaryingData = false;
+    int fieldWidth = 1;
+    int fieldHeight = 1;
+    int fieldDepth = 1;
+    // TBD..
+    //float timeSeries_vel_mag_min;
+    //float timeSeries_vel_mag_max;
+    //float timeSeriesVelMagMax;
+    int startIndex = -1, endIndex = -1;
+    for (int i = 0; attrs[i]; i += 2) {
+        if (!strcmp(attrs[i], "rendertarget-width")) {
+            width = atoi(attrs[i + 1]);
+        } else if (!strcmp(attrs[i], "rendertarget-height")) {
+            height = atoi(attrs[i + 1]);
+        } else if (!strcmp(attrs[i], "particle-point-size")) {
+            pointSize = (float) atof(attrs[i + 1]);
+        } else if (!strcmp(attrs[i], "vector-field-x")) {
+            fieldWidth = atoi(attrs[i + 1]);
+        } else if (!strcmp(attrs[i], "vector-field-y")) {
+            fieldHeight = atoi(attrs[i + 1]);
+        } else if (!strcmp(attrs[i], "vector-field-z")) {
+            fieldDepth = atoi(attrs[i + 1]);
+        } else if (!strcmp(attrs[i], "sort-enabled")) {
+            if (!strcmp(attrs[i + 1], "true"))
+                sortEnabled = true;
+        } else if (!strcmp(attrs[i], "glyph-enabled")) {
+            if (!strcmp(attrs[i + 1], "true"))
+                glyphEnabled = true;
+        } else if (!strcmp(attrs[i], "bbox-draw-enabled")) {
+            if (!strcmp(attrs[i + 1], "true"))
+                bboxVisible = true;
+        } else if (!strcmp(attrs[i], "advection-enabled")) {
+            if (!strcmp(attrs[i + 1], "true"))
+                advectionEnabled = true;
+        } else if (!strcmp(attrs[i], "stream-line-enabled")) {
+            if (!strcmp(attrs[i + 1], "true"))
+                streamlineEnabled = true;
+        } else if (!strcmp(attrs[i], "vector-field")) {
+            fileName = attrs[i + 1];
+        } else if (!strcmp(attrs[i], "vector-field")) {
+            if (!strcmp(attrs[i + 1], "true"))
+                timeVaryingData = true;
+        } else if (!strcmp(attrs[i], "particle-user-num")) {
+            numOfUsedParticles = atoi(attrs[i + 1]);
+        } else if (!strcmp(attrs[i], "time-series-start-index")) {
+            startIndex = atoi(attrs[i + 1]);
+        } else if (!strcmp(attrs[i], "time-series-end-index")) {
+            endIndex = atoi(attrs[i + 1]);
+        } else if (!strcmp(attrs[i], "time-varying")) {
+            if (!strcmp(attrs[i + 1], "true"))
+                timeVaryingData = true;
+        }
+    }
+
+    if (timeVaryingData) {
+        char buff[256];
+        sprintf(buff, fileName.c_str(), startIndex);
+        std::string path = FilePath::getInstance()->getPath(buff);
+        if (path.size()) {
+            std::string dir;
+            int index = path.rfind('/');
+            if (index == -1) {
+                index = path.rfind('\\');
+                if (index == -1) {
+                    TRACE("file not found");
+                }
+            }
+
+            dir = path.substr(0, index + 1);
+            path = dir + fileName;
+		
+            _newParticleSystem =
+                new ParticleSystem(width, height, path.c_str(),
+                                   fieldWidth, fieldHeight, fieldDepth,
+                                   timeVaryingData, startIndex, endIndex);
+        } else {
+            _newParticleSystem =
+                new ParticleSystem(width, height, fileName.c_str(),
+                                   fieldWidth, fieldHeight, fieldDepth,
+                                   timeVaryingData, startIndex, endIndex);
+        }
+    } else {
+        std::string path = FilePath::getInstance()->getPath(fileName.c_str());
+        _newParticleSystem =
+            new ParticleSystem(width, height, path.c_str(),
+                               fieldWidth, fieldHeight, fieldDepth,
+                               timeVaryingData, startIndex, endIndex);
+    }
+
+    if (pointSize != -1.0f) _newParticleSystem->setDefaultPointSize(pointSize);
+    if (sortEnabled) _newParticleSystem->enable(ParticleSystem::PS_SORT);
+    if (glyphEnabled) _newParticleSystem->enable(ParticleSystem::PS_GLYPH);
+    if (bboxVisible) _newParticleSystem->enable(ParticleSystem::PS_DRAW_BBOX);
+    if (advectionEnabled) _newParticleSystem->enable(ParticleSystem::PS_ADVECTION);
+    if (streamlineEnabled) _newParticleSystem->enable(ParticleSystem::PS_STREAMLINE);
+    if (numOfUsedParticles != -1) _newParticleSystem->setUserDefinedNumOfParticles(numOfUsedParticles);
+}
+
+void ParticleSystemFactory::parseEmitterInfo(const char** attrs)
+{
+    ParticleEmitter* emitter = new ParticleEmitter;
+    for (int i = 0; attrs[i]; i += 2) {
+        if (!strcmp(attrs[i], "max-position-offset")) {
+            float x = 0, y = 0, z = 0;
+            sscanf(attrs[i+1], "%f%f%f",&x, &y, &z);
+            emitter->setMaxPositionOffset(x, y, z);
+        } else if (!strcmp(attrs[i], "position")) {
+            float x = 0, y = 0, z = 0;
+            sscanf(attrs[i+1], "%f%f%f",&x, &y, &z);
+            emitter->setPosition(x, y, z);
+        } else if (!strcmp(attrs[i], "min-max-life-time")) {
+            float min = 0, max = 0;
+            sscanf(attrs[i+1], "%f%f",&min, &max);
+            emitter->setMinMaxLifeTime(min, max);
+        } else if (!strcmp(attrs[i], "min-max-new-particles")) {
+            int min = 0, max = 0;
+            sscanf(attrs[i+1], "%d%d",&min, &max);
+            emitter->setMinMaxNumOfNewParticles(min, max);
+        } else if (!strcmp(attrs[i], "enabled")) {
+            if (!strcmp(attrs[i + 1], "true"))
+                emitter->setEnabled(true);
+            else
+                emitter->setEnabled(false);
+        }
+    }
+    _newParticleSystem->addEmitter(emitter);
+}
Index: /nanovis/tags/1.1.4/ParticleSystemFactory.h
===================================================================
--- /nanovis/tags/1.1.4/ParticleSystemFactory.h	(revision 4930)
+++ /nanovis/tags/1.1.4/ParticleSystemFactory.h	(revision 4930)
@@ -0,0 +1,38 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#ifndef NV_PARTICLESYSTEMFACTORY_H
+#define NV_PARTICLESYSTEMFACTORY_H
+
+#include <string>
+
+#include <expat.h>
+
+namespace nv {
+
+class ParticleSystem;
+
+class ParticleSystemFactory
+{
+public:
+    ParticleSystemFactory();
+    ~ParticleSystemFactory();
+
+    ParticleSystem *create(const std::string& fileName);
+
+private:
+    void parseParticleSysInfo(const char **attrs);
+    void parseEmitterInfo(const char **attrs);
+
+    static void endElement(void *userData, const char *name);
+    static void startElement(void *userData, const char *elementName, const char **attrs);
+    static void text(void *data, const XML_Char *txt, int len);
+
+    ParticleSystem *_newParticleSystem;
+};
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/PerfQuery.cpp
===================================================================
--- /nanovis/tags/1.1.4/PerfQuery.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/PerfQuery.cpp	(revision 4930)
@@ -0,0 +1,48 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * ----------------------------------------------------------------------
+ * PerfQuery.cpp: performance query class
+ *
+ * ======================================================================
+ *  AUTHOR:  Wei Qiao <qiaow@purdue.edu>
+ *           Purdue Rendering and Perceptualization Lab (PURPL)
+ *
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ *  See the file "license.terms" for information on usage and
+ *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ * ======================================================================
+ */
+#include <assert.h>
+
+#include "PerfQuery.h"
+
+using namespace nv;
+
+PerfQuery::PerfQuery()
+{
+    glGenQueriesARB(1, &id);
+    pixel = 0;
+}
+
+PerfQuery::~PerfQuery()
+{
+    glDeleteQueriesARB(1, &id);
+}
+
+//There can only be one active query at any given moment
+void PerfQuery::enable()
+{
+    glBeginQueryARB(GL_SAMPLES_PASSED_ARB, id);
+}
+
+void PerfQuery::disable()
+{
+    glEndQueryARB(GL_SAMPLES_PASSED_ARB);
+
+    GLuint count;
+    glGetQueryObjectuivARB(id, GL_QUERY_RESULT_ARB, &count);
+
+    //accumulate pixel count count
+    pixel += count;
+}
Index: /nanovis/tags/1.1.4/PerfQuery.h
===================================================================
--- /nanovis/tags/1.1.4/PerfQuery.h	(revision 4930)
+++ /nanovis/tags/1.1.4/PerfQuery.h	(revision 4930)
@@ -0,0 +1,76 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * ----------------------------------------------------------------------
+ * PerfQuery.h: performance query class
+ * 		It counts then number of pixels rendered on screen using
+ * 		OpenGL occlusion query extension
+ *
+ * ======================================================================
+ *  AUTHOR:  Wei Qiao <qiaow@purdue.edu>
+ *           Purdue Rendering and Perceptualization Lab (PURPL)
+ *
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ *  See the file "license.terms" for information on usage and
+ *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ * ======================================================================
+ */
+#ifndef NV_PERFQUERY_H
+#define NV_PERFQUERY_H
+
+#include <stdio.h>
+
+#include <GL/glew.h>
+
+#include "Trace.h"
+
+namespace nv {
+
+class PerfQuery
+{
+public:
+    PerfQuery();
+    ~PerfQuery();
+
+    void enable();	//start counting how many pixels are rendered
+    void disable();	//stop counting
+
+    void reset()
+    {
+        pixel = 0; 
+    }
+
+    int getPixelCount()
+    {
+        return pixel;		//return current pixel count
+    }
+
+    static bool checkQuerySupport();
+
+    GLuint id;
+    int pixel;
+};
+
+//check if occlusion query is supported
+inline bool PerfQuery::checkQuerySupport()
+{
+    if (!GLEW_ARB_occlusion_query) {
+        TRACE("ARB_occlusion_query extension not supported");
+        return false;
+    }
+    int bitsSupported = -1;
+    glGetQueryivARB(GL_SAMPLES_PASSED_ARB, GL_QUERY_COUNTER_BITS_ARB, 
+                    &bitsSupported);
+    if (bitsSupported == 0) {
+        TRACE("occlusion query not supported!");
+        return false;
+    } else {
+        TRACE("Occlusion query with %d bits supported", bitsSupported);
+        return true;
+    }
+}
+
+}
+
+#endif
+
Index: /nanovis/tags/1.1.4/Plane.cpp
===================================================================
--- /nanovis/tags/1.1.4/Plane.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/Plane.cpp	(revision 4930)
@@ -0,0 +1,72 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * ----------------------------------------------------------------------
+ * Plane.cpp: plane class
+ *
+ * ======================================================================
+ *  AUTHOR:  Wei Qiao <qiaow@purdue.edu>
+ *           Purdue Rendering and Perceptualization Lab (PURPL)
+ *
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ *  See the file "license.terms" for information on usage and
+ *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ * ======================================================================
+ */
+#include <assert.h>
+
+#include "Plane.h"
+
+using namespace nv;
+
+Plane::Plane(float _a, float _b, float _c, float _d) :
+    a(_a),
+    b(_b),
+    c(_c),
+    d(_d)
+{
+    assert(a != 0 || b != 0 || c != 0);
+}
+
+Plane::Plane(float coeffs[4])
+{
+    a = coeffs[0];
+    b = coeffs[1];
+    c = coeffs[2];
+    d = coeffs[3];
+
+    assert(a != 0 || b != 0 || c != 0);
+}
+
+void
+Plane::transform(const vrmath::Matrix4x4d& mat)
+{
+    vrmath::Vector4f coeffs(a, b, c, d);
+
+    vrmath::Matrix4x4d inv = mat.inverse();
+    vrmath::Vector4f new_coeffs = inv.preMultiplyRowVector(coeffs);
+    a = new_coeffs.x;
+    b = new_coeffs.y;
+    c = new_coeffs.z;
+    d = new_coeffs.w;
+}
+
+void
+Plane::getPoint(vrmath::Vector3f& point)
+{
+    if (a != 0) {
+        point.x = -d/a;
+        point.y = 0;
+        point.z = 0;
+    } else if (b != 0) {
+        point.y = -d/b;
+        point.x = 0;
+        point.z = 0;
+    } else if (c != 0) {
+        point.z = -d /c;
+        point.y = 0;
+        point.x = 0;
+    } else {
+        assert(false);
+    }
+}
Index: /nanovis/tags/1.1.4/Plane.h
===================================================================
--- /nanovis/tags/1.1.4/Plane.h	(revision 4930)
+++ /nanovis/tags/1.1.4/Plane.h	(revision 4930)
@@ -0,0 +1,76 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * ----------------------------------------------------------------------
+ * Plane.h: plane class
+ *
+ * ======================================================================
+ *  AUTHOR:  Wei Qiao <qiaow@purdue.edu>
+ *           Purdue Rendering and Perceptualization Lab (PURPL)
+ *
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ *  See the file "license.terms" for information on usage and
+ *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ * ======================================================================
+ */
+#ifndef NV_PLANE_H
+#define NV_PLANE_H
+
+#include <vrmath/Vector3f.h>
+#include <vrmath/Vector4f.h>
+#include <vrmath/Matrix4x4d.h>
+
+namespace nv {
+
+class Plane
+{
+public:
+    Plane(float a, float b, float c, float d);
+
+    Plane(float coeffs[4]);
+
+    Plane()
+    {}
+
+    void getPoint(vrmath::Vector3f& point);
+
+    //bool clips(float point[3]) const { return !retains(point); }
+
+    void transform(const vrmath::Matrix4x4d& mat);
+
+    void transform(float *m)
+    {
+        vrmath::Matrix4x4d mat;
+        mat.setFloat(m);
+        transform(mat);
+    }
+
+    bool retains(const vrmath::Vector3f& point) const
+    {
+	return ((a*point.x + b*point.y + c*point.z + d) >= 0);
+    }
+
+    vrmath::Vector4f getCoeffs() const
+    {
+        return vrmath::Vector4f(a, b, c, d);
+    }
+
+    void setCoeffs(float a_val, float b_val, float c_val, float d_val)
+    {
+        a = a_val, b = b_val, c = c_val, d = d_val;
+    }
+
+    void getNormal(vrmath::Vector3f& normal) const
+    {
+        normal.x = a;
+        normal.y = b;
+        normal.z = c;
+    }
+
+private:
+    float a, b, c, d;
+};
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/PlaneRenderer.cpp
===================================================================
--- /nanovis/tags/1.1.4/PlaneRenderer.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/PlaneRenderer.cpp	(revision 4930)
@@ -0,0 +1,114 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ *  Authors:
+ *    Wei Qiao <qiaow@purdue.edu>
+ */
+
+#include <GL/glew.h>
+
+#include "PlaneRenderer.h"
+#include "Trace.h"
+
+using namespace nv;
+
+PlaneRenderer::PlaneRenderer(int width, int height) :
+    _activePlane(-1),
+    _numPlanes(0),
+    _renderWidth(width),
+    _renderHeight(height),
+    _shader(new ColorTableShader())
+{
+    _plane.clear();
+    _tf.clear();
+}
+
+PlaneRenderer::~PlaneRenderer() 
+{
+    delete _shader;
+}
+
+int 
+PlaneRenderer::addPlane(Texture2D *planeTexture, TransferFunction *tf)
+{
+    int ret = _numPlanes;
+
+    _plane.push_back(planeTexture);
+    _tf.push_back(tf);
+
+    if (ret == 0)
+        _activePlane = ret;
+
+    _numPlanes++;
+    return ret;
+}
+
+void
+PlaneRenderer::removePlane(int index)
+{
+    std::vector<Texture2D *>::iterator piter = _plane.begin()+index;
+    std::vector<TransferFunction *>::iterator tfiter = _tf.begin()+index;
+
+    _plane.erase(piter);
+    _tf.erase(tfiter);
+
+    _numPlanes--;
+}
+
+void 
+PlaneRenderer::render()
+{
+    if (_numPlanes == 0)
+        return;
+
+    glPushAttrib(GL_VIEWPORT_BIT | GL_ENABLE_BIT);
+
+    glEnable(GL_TEXTURE_2D);
+    glEnable(GL_BLEND);
+
+    glViewport(0, 0, _renderWidth, _renderHeight);
+    glMatrixMode(GL_PROJECTION);
+    glPushMatrix();
+    glLoadIdentity();
+    gluOrtho2D(0, _renderWidth, 0, _renderHeight);
+    glMatrixMode(GL_MODELVIEW);
+    glPushMatrix();
+    glLoadIdentity();
+
+    //glColor3f(1., 1., 1.);         //MUST HAVE THIS LINE!!!
+
+    //if no active plane
+    if (_activePlane == -1)
+        return;
+
+    _shader->bind(_plane[_activePlane], _tf[_activePlane]);
+    glBegin(GL_QUADS);
+    glTexCoord2f(0, 0); glVertex2f(0, 0);
+    glTexCoord2f(1, 0); glVertex2f(_renderWidth, 0);
+    glTexCoord2f(1, 1); glVertex2f(_renderWidth, _renderHeight);
+    glTexCoord2f(0, 1); glVertex2f(0, _renderHeight);
+    glEnd();
+    _shader->unbind();
+
+    glMatrixMode(GL_PROJECTION);
+    glPopMatrix();
+
+    glMatrixMode(GL_MODELVIEW);
+    glPopMatrix();
+
+    glPopAttrib();
+}
+
+void
+PlaneRenderer::setActivePlane(int index) 
+{
+    _activePlane = index;
+}
+
+void
+PlaneRenderer::setScreenSize(int w, int h) 
+{
+    _renderWidth = w;
+    _renderHeight = h;
+}
Index: /nanovis/tags/1.1.4/PlaneRenderer.h
===================================================================
--- /nanovis/tags/1.1.4/PlaneRenderer.h	(revision 4930)
+++ /nanovis/tags/1.1.4/PlaneRenderer.h	(revision 4930)
@@ -0,0 +1,53 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ *  Authors:
+ *    Wei Qiao <qiaow@purdue.edu>
+ */
+#ifndef NV_PLANE_RENDERER_H
+#define NV_PLANE_RENDERER_H
+
+#include <vector>
+
+#include "ColorTableShader.h"
+#include "TransferFunction.h"
+#include "Texture2D.h"
+
+namespace nv {
+
+class PlaneRenderer
+{
+public:
+    PlaneRenderer(int width, int height);
+
+    ~PlaneRenderer();
+
+    /// Add a plane and its transfer function.
+    int addPlane(Texture2D *p, TransferFunction *tf);
+
+    void removePlane(int index);
+
+    /// Set the active plane to be rendered
+    void setActivePlane(int index);
+
+    /// Change the rendering size
+    void setScreenSize(int w, int h);
+
+    void render();
+
+private:
+    std::vector<Texture2D *> _plane;	 ///< Array of images
+    std::vector<TransferFunction *> _tf; ///< Array of corresponding transfer functions 
+    int _activePlane;                    ///< The active plane, only one is rendered
+    int _numPlanes;
+
+    int _renderWidth;
+    int _renderHeight;  
+
+    ColorTableShader *_shader;
+};
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/PointSet.cpp
===================================================================
--- /nanovis/tags/1.1.4/PointSet.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/PointSet.cpp	(revision 4930)
@@ -0,0 +1,77 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <vrmath/Vector3f.h>
+#include <vrmath/Vector4f.h>
+#include <vrmath/Color4f.h>
+
+#include "PointSet.h"
+#include "PCASplit.h"
+
+using namespace nv;
+
+void 
+PointSet::initialize(vrmath::Vector4f *values, const unsigned int count, 
+		     const vrmath::Vector3f& scale, const vrmath::Vector3f& origin, 
+		     float min, float max)
+{
+    PCA::PCASplit pcaSplit;
+
+    _scale = scale;
+    _origin = origin;
+    _min = min;
+    _max = max;
+
+    PCA::Point *points = (PCA::Point *)malloc(sizeof(PCA::Point) * count);
+    for (unsigned int i = 0; i < count; ++i) {
+        points[i].position.set(values[i].x, values[i].y, values[i].z);
+        points[i].color.set(1.0f, 1.0f, 1.0f, 0.2f);
+        points[i].value = values[i].w;
+        points[i].size = 0.001;
+    }
+
+    if (_cluster != 0) {
+        delete _cluster;
+    }
+    
+    pcaSplit.setMinDistance(scale.length() / 3.0f);
+    _cluster = pcaSplit.doIt(points, count);
+}
+
+void 
+PointSet::updateColor(float *color, int colorCount)
+{
+    if (_cluster == 0) {
+	return;
+    }
+    int level = 4;
+
+    PCA::Cluster *cluster = _cluster->startPointerCluster[level - 1];
+    PCA::Cluster *c = &(cluster[0]);
+    PCA::Cluster *end = &(cluster[_cluster->numOfClusters[level - 1] - 1]);
+
+    vrmath::Vector3f pos;
+
+    PCA::Point *points;
+    vrmath::Color4f *colors = (vrmath::Color4f *)color;
+    int numOfPoints;
+    int index;
+    float d = _max - _min;
+    for (; c <= end; c = (PCA::Cluster *)((char *)c + sizeof(PCA::Cluster))) {
+        points = c->points;
+        numOfPoints = c->numOfPoints;
+
+        for (int i = 0; i < numOfPoints; ++i) {
+            index = (int)((points[i].value - _min) / d  * (colorCount - 1));
+            if (index >= colorCount) {
+		index = colorCount - 1;
+	    }
+            points[i].color = colors[index];
+        }
+    }
+}
Index: /nanovis/tags/1.1.4/PointSet.h
===================================================================
--- /nanovis/tags/1.1.4/PointSet.h	(revision 4930)
+++ /nanovis/tags/1.1.4/PointSet.h	(revision 4930)
@@ -0,0 +1,93 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#ifndef NV_POINT_SET_H
+#define NV_POINT_SET_H
+
+#include <vrmath/Vector3f.h>
+#include <vrmath/Vector4f.h>
+
+#include "PCASplit.h"
+
+namespace nv {
+
+class PointSet
+{
+public :
+    PointSet() :
+        _sortLevel(4),
+        _cluster(0),
+        _max(1.0f),
+        _min(0.0f), 
+        _visible(false)
+    {
+    }
+
+    ~PointSet() {
+	if (_cluster) {
+	    delete _cluster;
+	}
+    }
+
+    void initialize(vrmath::Vector4f *values, const unsigned int count, 
+		    const vrmath::Vector3f& scale, const vrmath::Vector3f& origin, 
+		    float min, float max);
+
+    void updateColor(float *color, int count);
+
+    bool isVisible() const
+    {
+        return _visible;
+    }
+
+    void setVisible(bool visible)
+    {
+        _visible = visible;
+    }
+
+    unsigned int getSortLevel() const
+    {
+        return _sortLevel;
+    }
+
+    PCA::ClusterAccel* getCluster()
+    {
+        return _cluster;
+    }
+
+    vrmath::Vector3f& getScale()
+    {
+        return _scale;
+    }
+
+    const vrmath::Vector3f& getScale() const
+    {
+        return _scale;
+    }
+
+    vrmath::Vector3f& getOrigin()
+    {
+        return _origin;
+    }
+
+    const vrmath::Vector3f& getOrigin() const
+    {
+        return _origin;
+    }
+
+private:
+    unsigned int _sortLevel;
+    PCA::ClusterAccel *_cluster;
+
+    vrmath::Vector3f _scale;
+    vrmath::Vector3f _origin;
+    float _max;
+    float _min;
+    bool _visible;
+};
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/PointSetRenderer.cpp
===================================================================
--- /nanovis/tags/1.1.4/PointSetRenderer.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/PointSetRenderer.cpp	(revision 4930)
@@ -0,0 +1,163 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#include <GL/glew.h>
+
+#include <Image.h>
+#include <ImageLoaderFactory.h>
+#include <ImageLoader.h>
+#include <util/FilePath.h>
+
+#include "PointSetRenderer.h"
+#include "PCASplit.h"
+
+using namespace nv;
+using namespace nv::util;
+using namespace vrmath;
+using namespace PCA;
+
+#define USE_TEXTURE 
+//#define USE_SHADER 
+#define POINT_SIZE 5
+
+PointSetRenderer::PointSetRenderer()
+{
+    _shader = new PointShader();
+    std::string path = FilePath::getInstance()->getPath("particle2.bmp");
+    if (path.empty()) {
+        ERROR("Particle image not found");
+        return;
+    }
+
+    ImageLoader *loader = ImageLoaderFactory::getInstance()->createLoader("bmp");
+    Image *image = loader->load(path.c_str(), Image::IMG_RGBA);
+    unsigned char *bytes = (unsigned char *)image->getImageBuffer();
+    if (bytes) {
+        for (unsigned int y = 0; y < image->getHeight(); ++y) {
+            for (unsigned int x = 0; x < image->getWidth(); ++x, bytes += 4) {
+                bytes[3] = (bytes[0] == 0) ? 0 : 255;
+            }
+        }
+    }
+
+    if (image) {
+        _pointTexture = new Texture2D(image->getWidth(), image->getHeight(), 
+                                      GL_UNSIGNED_BYTE, GL_LINEAR,    
+                                      4, image->getImageBuffer());
+    } else {
+        ERROR("Failed to load particle image");
+    }
+
+    delete loader;
+    delete image;
+    _bucketSort = new BucketSort(1024);
+}
+
+PointSetRenderer::~PointSetRenderer()
+{
+}
+
+void PointSetRenderer::renderPoints(Point *points, int length)
+{
+    Point *p = points;
+    for (int i = 0; i < length; ++i, ++p) {
+        glColor4f(p->color.r, p->color.g, p->color.b, p->color.a);
+        glVertex3f(p->position.x, p->position.y, p->position.z);
+    }
+}
+
+void PointSetRenderer::renderCluster(ClusterList** bucket, int size, int level)
+{
+    float quadratic[] = { 1.0f, 0.0f, 0.01f };
+
+    glEnable(GL_POINT_SPRITE_ARB);
+    glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, quadratic);
+    glPointParameterfARB(GL_POINT_FADE_THRESHOLD_SIZE_ARB, 60.0f);
+    glPointParameterfARB(GL_POINT_SIZE_MIN_ARB, 1.0f);
+    glPointParameterfARB(GL_POINT_SIZE_MAX_ARB, 100);
+#ifdef USE_TEXTURE 
+    glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
+#endif
+
+    bool setSize = false;
+    glBegin(GL_POINTS);
+
+    ClusterList *p;
+    for (int i = size - 1; i >= 0; --i) {
+        p = bucket[i];
+        if (p) {
+            if (!setSize) {
+#ifdef USE_SHADER 
+                _shader->setScale(p->data->points[0].size);
+#endif
+                setSize = true;
+            }
+        }
+
+        while (p) {
+            renderPoints(p->data->points, p->data->numOfPoints);
+
+            p = p->next;
+        }
+    }
+
+    glEnd();
+
+    glDisable(GL_POINT_SPRITE_ARB);
+    glPointSize(1);
+}
+
+void PointSetRenderer::render(ClusterAccel *cluster, const Matrix4x4d& mat,
+                              int sortLevel, const Vector3f& scale, const Vector3f& origin)
+{
+    _bucketSort->init();
+    _bucketSort->sort(cluster, mat, sortLevel);
+
+    glDisable(GL_TEXTURE_2D);
+
+#ifdef USE_TEXTURE 
+    _pointTexture->activate();
+    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+#endif
+
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    //glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+    glEnable(GL_BLEND);
+
+    glDisable(GL_LIGHTING);
+    glEnable(GL_COLOR_MATERIAL);
+
+    glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
+    glPushMatrix();
+    float s = 1.0f / scale.x;
+    Vector3f shift(origin.x + scale.x * 0.5, origin.x + scale.x * 0.5, origin.x + scale.x * 0.5);
+    glScalef(s, scale.y / scale.x * s, scale.z / scale.x * s);
+
+    //glTranslatef(-shift.x, -shift.y, -shift.z);
+
+#ifdef USE_SHADER 
+    _shader->bind();
+#else
+    glPointSize(POINT_SIZE);
+#endif
+    renderCluster(_bucketSort->getBucket(), _bucketSort->getSize(), 4);
+#ifdef USE_SHADER 
+    _shader->unbind();
+#else
+    glPointSize(1.0f);
+#endif
+
+    glPopMatrix();
+
+    glDisable(GL_COLOR_MATERIAL);
+    glEnable(GL_LIGHTING);
+    glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
+    glDisable(GL_BLEND);
+
+#ifdef USE_TEXTURE 
+    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+    _pointTexture->deactivate();
+#endif
+}
Index: /nanovis/tags/1.1.4/PointSetRenderer.h
===================================================================
--- /nanovis/tags/1.1.4/PointSetRenderer.h	(revision 4930)
+++ /nanovis/tags/1.1.4/PointSetRenderer.h	(revision 4930)
@@ -0,0 +1,40 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#ifndef NV_POINT_SET_RENDERER_H
+#define NV_POINT_SET_RENDERER_H
+
+#include <vrmath/Vector3f.h>
+#include <vrmath/Matrix4x4d.h>
+
+#include "PCASplit.h"
+#include "BucketSort.h"
+#include "PointShader.h"
+#include "Texture2D.h"
+
+namespace nv {
+
+class PointSetRenderer
+{
+public:
+    PointSetRenderer();
+    ~PointSetRenderer();
+
+    void render(PCA::ClusterAccel *cluster, const vrmath::Matrix4x4d& mat,
+                int sortLevel, const vrmath::Vector3f& scale, const vrmath::Vector3f& origin);
+
+private:
+    void renderPoints(PCA::Point *points, int length);
+
+    void renderCluster(PCA::ClusterList **bucket, int size, int level);
+
+    PCA::BucketSort *_bucketSort;
+    PointShader *_shader;
+    Texture2D *_pointTexture;
+};
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/PointShader.cpp
===================================================================
--- /nanovis/tags/1.1.4/PointShader.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/PointShader.cpp	(revision 4930)
@@ -0,0 +1,41 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#include "PointShader.h"
+
+using namespace nv;
+
+PointShader::PointShader() : 
+    Shader(),
+    _scale(1.0f),
+    _normal(NULL)
+{
+    loadVertexProgram("pointsvp.cg");
+}
+
+PointShader::~PointShader()
+{
+}
+
+void PointShader::bind()
+{
+    setGLStateMatrixVPParameter("modelView", MODELVIEW_MATRIX, MATRIX_IDENTITY);
+    setGLStateMatrixVPParameter("modelViewProj", MODELVIEW_PROJECTION_MATRIX, MATRIX_IDENTITY);
+
+    setVPParameter1f("atten", 1.0f);
+    setVPParameter4f("posoffset", 1.0f, 1.0f, 1.0f, 1.0f);
+    setVPParameter4f("basepos", 1.0f, 1.0f, 1.0f, 1.0f);
+    setVPParameter4f("scale", _scale, 1.0f, 1.0f, 1.0f);
+    //setVPTextureParameter("normal", _normal->getGraphicsObjectID());
+
+    Shader::bind();
+}
+
+void PointShader::unbind()
+{
+    //disableVPTextureParameter("normal");
+
+    Shader::unbind();
+}
Index: /nanovis/tags/1.1.4/PointShader.h
===================================================================
--- /nanovis/tags/1.1.4/PointShader.h	(revision 4930)
+++ /nanovis/tags/1.1.4/PointShader.h	(revision 4930)
@@ -0,0 +1,42 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#ifndef NV_POINTSHADER_H
+#define NV_POINTSHADER_H
+
+#include "Shader.h"
+#include "Texture3D.h"
+
+namespace nv {
+
+class PointShader : public Shader
+{
+public:
+    PointShader();
+
+    virtual ~PointShader();
+
+    void setScale(float scale)
+    {
+        _scale = scale;
+    }
+
+    void setNormalTexture(Texture3D *normal)
+    {
+        _normal = normal;
+    }
+
+    virtual void bind();
+
+    virtual void unbind();
+
+private:
+    float _scale;
+    Texture3D *_normal;
+};
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/README
===================================================================
--- /nanovis/tags/1.1.4/README	(revision 4930)
+++ /nanovis/tags/1.1.4/README	(revision 4930)
@@ -0,0 +1,41 @@
+======================================================================
+        N A N O V I S - Visualization of Nanoelectronics Data
+======================================================================
+
+ This part builds a visualization server used by the Rappture
+ toolkit GUI to visualize 2D/3D scalar and vector data.
+ 
+ Image based flow visulaiztion code based on van Wijk 2002, 
+ Technische Universiteit Eindhoven
+ 
+======================================================================
+ AUTHORS:  Wei Qiao <qiaow.purdue.edu>
+           Purdue Rendering & Perceptualization Lab
+
+           Michael Mclennan <mmclennan@purdue.edu> 
+           Network for Computational Nanotechnology
+
+ Copyright (c) 2004-2012  HUBzero Foundation, LLC
+
+ See the file "license.terms" for information on usage and
+ redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+======================================================================
+
+1. Hardware Requirements:
+     Nvidia 6 series (6xxx) or Quadro 3400, 4400 graphics hardware and up.
+     Pentium 4 or compatible CPU
+
+2. Software Requirement:
+     Reasonably new Linux distribution (Application developed on Mandrake 9.2)
+     Nvidia OpenGL graphics driver installed.
+       (See http://www.nvidia.com/object/unix.html)
+     Nvidia CG Toolkit for GPU (Graphics Processing Unit) programming.
+       (See http://developer.nvidia.com/object/cg_toolkit.html)
+     The OpenGL Wrangler Library (>= 1.1.0) for OpenGL extension management.
+       (See http://glew.sourceforge.net/)
+     OpenGL Utility Toolkit (GLUT). Freeglut is an opensource GLUT replacement.
+       (See http://freeglut.sourceforge.net/)
+
+3. Build:
+     Type "make" to build.
+     Executable is nanovis.
Index: /nanovis/tags/1.1.4/ReadBuffer.cpp
===================================================================
--- /nanovis/tags/1.1.4/ReadBuffer.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/ReadBuffer.cpp	(revision 4930)
@@ -0,0 +1,187 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: George A. Howlett <gah@purdue.edu>
+ */
+
+#include <cstdlib>
+#include <cerrno>
+#include <cstdio>
+#include <unistd.h>
+#include <cstring>
+
+#include <RpBuffer.h>
+
+#include "ReadBuffer.h"
+#include "Trace.h"
+
+using namespace nv;
+
+/**
+ * \param[in] fd File descriptor to read
+ * \param[in] bufferSize Block size to use in internal buffer
+ */
+ReadBuffer::ReadBuffer(int fd, size_t bufferSize) :
+    _bufferSize(bufferSize),
+    _fd(fd),
+    _lastStatus(OK)
+{
+    _bytes = new unsigned char [_bufferSize];
+    flush();
+}
+
+ReadBuffer::~ReadBuffer()
+{
+    TRACE("Deleting ReadBuffer");
+    delete [] _bytes;
+}
+
+/**
+ * \brief Checks if a new line is currently in the buffer.
+ *
+ * \return the index of the character past the new line.
+ */
+size_t
+ReadBuffer::nextNewLine()
+{
+    /* Check for a newline in the current buffer. */
+    unsigned char *ptr = 
+        (unsigned char *)memchr(_bytes + _mark, '\n', _fill - _mark);
+    if (ptr == NULL)
+        return 0;
+    else
+        return (ptr - _bytes + 1);
+}
+
+/**  
+ * \brief Fills the buffer with available data.
+ * 
+ * Any existing data in the buffer is moved to the front of the buffer, 
+ * then the channel is read to fill the rest of the buffer.
+ *
+ * \return If an error occur when reading the channel, then ERROR is
+ * returned. ENDFILE is returned on EOF.  If the buffer can't be filled, 
+ * then CONTINUE is returned.
+ */
+ReadBuffer::BufferStatus
+ReadBuffer::doFill()
+{
+    //TRACE("Enter, mark: %lu fill: %lu", _mark, _fill);
+    if (_mark >= _fill) {
+        flush();                        /* Fully consumed buffer */
+    }
+    if (_mark > 0) {
+        /* Some data has been consumed. Move the unconsumed data to the front
+         * of the buffer. */
+        TRACE("memmove %lu bytes", _fill-_mark);
+        memmove(_bytes, _bytes + _mark, _fill - _mark);
+        _fill -= _mark;
+        _mark = 0;
+    }
+    ssize_t numRead;
+    size_t bytesLeft;
+
+    bytesLeft = _bufferSize - _fill;
+    //TRACE("going to read %lu bytes", bytesLeft);
+    numRead = read(_fd, _bytes + _fill, bytesLeft);
+    if (numRead == 0) {
+        /* EOF */
+        TRACE("EOF found reading buffer");
+        return ReadBuffer::ENDFILE;
+    }
+    if (numRead < 0) {
+        if (errno != EAGAIN) {
+            ERROR("error reading buffer: %s", strerror(errno));
+            return ReadBuffer::ERROR;
+        }
+        TRACE("Short read for buffer");
+        return ReadBuffer::CONTINUE;
+    }
+    _fill += numRead;
+    //TRACE("Read %lu bytes", numRead);
+    return ((size_t)numRead == bytesLeft) 
+        ? ReadBuffer::OK : ReadBuffer::CONTINUE;
+}
+
+/**
+ * \brief Read the requested number of bytes from the buffer.
+
+ * Fails if the requested number of bytes are not immediately 
+ * available. Never should be short. 
+ */
+ReadBuffer::BufferStatus
+ReadBuffer::followingData(unsigned char *out, size_t numBytes)
+{
+    TRACE("Enter");
+    while (numBytes > 0) {
+        size_t bytesLeft;
+
+        bytesLeft = _fill - _mark;
+        if (bytesLeft > 0) {
+            int size;
+
+            /* Pull bytes out of the buffer, updating the mark. */
+            size = (bytesLeft >  numBytes) ? numBytes : bytesLeft;
+            memcpy(out, _bytes + _mark, size);
+            _mark += size;
+            numBytes -= size;
+            out += size;
+        }
+        if (numBytes == 0) {
+            /* Received requested # bytes. */
+            return ReadBuffer::OK;
+        }
+        /* Didn't get enough bytes, need to read some more. */
+        _lastStatus = doFill();
+        if (_lastStatus == ReadBuffer::ERROR ||
+            _lastStatus == ReadBuffer::ENDFILE) {
+            return _lastStatus;
+        }
+    }
+    return ReadBuffer::OK;
+}
+
+/** 
+ * \brief Returns the next available line (terminated by a newline)
+ * 
+ * If insufficient data is in the buffer, then the channel is
+ * read for more data.  If reading the channel results in a
+ * short read, CONTINUE is returned and *numBytesPtr is set to 0.
+ */
+ReadBuffer::BufferStatus
+ReadBuffer::getLine(size_t *numBytesPtr, unsigned char **bytesPtr)
+{
+    TRACE("Enter");
+    *numBytesPtr = 0;
+    *bytesPtr = NULL;
+
+    _lastStatus = ReadBuffer::OK;
+    for (;;) {
+        size_t _newline;
+
+        _newline = nextNewLine();
+        if (_newline > 0) {
+            /* Start of the line. */
+            *bytesPtr = _bytes + _mark;
+            /* Number of bytes in the line. */
+            *numBytesPtr = _newline - _mark;
+            _mark = _newline;
+            return ReadBuffer::OK;
+        }
+        /* Couldn't find a newline, so it may be that we need to read some
+         * more. Check first that last read wasn't a short read. */
+        if (_lastStatus == ReadBuffer::CONTINUE) {
+            /* No complete line just yet. */
+            return ReadBuffer::CONTINUE;
+        }
+        /* Try to add more data to the buffer. */
+        _lastStatus = doFill();
+        if (_lastStatus == ReadBuffer::ERROR ||
+            _lastStatus == ReadBuffer::ENDFILE) {
+            return _lastStatus;
+        }
+        /* OK or CONTINUE */
+    }
+    return ReadBuffer::CONTINUE;
+}
Index: /nanovis/tags/1.1.4/ReadBuffer.h
===================================================================
--- /nanovis/tags/1.1.4/ReadBuffer.h	(revision 4930)
+++ /nanovis/tags/1.1.4/ReadBuffer.h	(revision 4930)
@@ -0,0 +1,86 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: George A. Howlett <gah@purdue.edu>
+ */
+
+#include <cstdlib>
+
+#include <RpBuffer.h>
+
+#ifndef NV_READBUFFER_H
+#define NV_READBUFFER_H
+
+namespace nv {
+
+/**
+ * \brief Buffered input for reading socket
+ */
+class ReadBuffer
+{
+public:
+    enum BufferStatus {
+        ENDFILE=-1,
+        OK,
+        ERROR,
+        CONTINUE,
+    };
+
+    ReadBuffer(int fd, size_t bufferSize);
+
+    virtual ~ReadBuffer();
+
+    BufferStatus getLine(size_t *numBytesPtr, unsigned char **bytesPtr);
+
+    BufferStatus followingData(unsigned char *out, size_t numBytes);
+
+    /**
+     * \brief Check if buffer contains data ending in a newline
+     * 
+     * \return bool indicating if getLine can be called without blocking 
+     */
+    bool isLineAvailable()
+    {
+        return (nextNewLine() > 0);
+    }
+
+    /**
+     * \brief Get the file descriptor this object reads from
+     */
+    int file()
+    {
+        return _fd;
+    }
+
+    /**
+     * \brief Get the status of the last read
+     */
+    BufferStatus status()
+    {
+        return _lastStatus;
+    }
+
+private:
+    unsigned char *_bytes;		/**< New-ed buffer to hold read
+					 * characters. */
+    size_t _bufferSize;			/**< # of bytes allocated for buffer */
+    size_t _fill;			/**< # of bytes used in the buffer */
+    size_t _mark;			/**< Starting point of the unconsumed
+					 * data in the buffer. */
+    int _fd;				/**< File descriptor to get data. */
+    BufferStatus _lastStatus;           /**< Status of last read operation. */
+
+    BufferStatus doFill();
+
+    void flush()
+    {
+        _fill = _mark = 0;
+    }
+
+    size_t nextNewLine();
+};
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/ReaderCommon.cpp
===================================================================
--- /nanovis/tags/1.1.4/ReaderCommon.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/ReaderCommon.cpp	(revision 4930)
@@ -0,0 +1,208 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+
+#include <cstdlib>
+
+#include <vrmath/Vector3f.h>
+
+#include "ReaderCommon.h"
+#include "GradientFilter.h"
+
+using namespace nv;
+using namespace vrmath;
+
+float *
+nv::merge(float *scalar, float *gradient, int size)
+{
+    float *data = (float *)malloc(sizeof(float) * 4 * size);
+
+    Vector3f *g = (Vector3f *)gradient;
+
+    int ngen = 0, sindex = 0;
+    for (sindex = 0; sindex < size; ++sindex) {
+        data[ngen++] = scalar[sindex];
+        data[ngen++] = 1.0 - g[sindex].x;
+        data[ngen++] = 1.0 - g[sindex].y;
+        data[ngen++] = 1.0 - g[sindex].z;
+    }
+    return data;
+}
+
+/**
+ * \brief Normalize data to [0,1] based on vmin,vmax range
+ * 
+ * Data outside of given range is clamped, and NaNs are set to
+ * -1 in the output
+ *
+ * \param data Float array of unnormalized data, will be normalized on return
+ * \param count Number of elts in array
+ * \param stride Stride between values in data array
+ * \param vmin Minimum value in data array
+ * \param vmax Maximum value in data array
+ */
+void
+nv::normalizeScalar(float *data, int count, int stride, double vmin, double vmax)
+{
+    double dv = vmax - vmin;
+    dv = (dv == 0.0) ? 1.0 : dv;
+    for (int pt = 0, i = 0; pt < count; ++pt, i += stride) {
+        double v = data[i];
+        if (isnan(v)) {
+            data[i] = -1.0f;
+        } else if (v < vmin) {
+            data[i] = 0.0f;
+        } else if (v > vmax) {
+            data[i] = 1.0f;
+        } else {
+            data[i] = (float)((v - vmin)/ dv);
+        }
+    }
+}
+
+/**
+ * \brief Normalize data to [0,1] based on vmin,vmax range
+ * 
+ * \param data Float array of unnormalized data, will be normalized on return
+ * \param count Number of elts in array
+ * \param vmin Minimum value in data array
+ * \param vmax Maximum value in data array
+ */
+void
+nv::normalizeVector(float *data, int count, double vmin, double vmax)
+{
+    for (int p = 0; p < count; p++) {
+        int i = p * 4;
+        data[i  ] = data[i]/vmax;
+        data[i+1] = data[i+1]/(2.0 * vmax) + 0.5;
+        data[i+2] = data[i+2]/(2.0 * vmax) + 0.5;
+        data[i+3] = data[i+3]/(2.0 * vmax) + 0.5;
+    }
+}
+
+/**
+ * \brief Compute Sobel filtered gradients for a 3D volume
+ *
+ * This technique is fairly expensive in terms of memory and
+ * running time due to the filter extent.
+ *
+ * \param data Data array with X the fastest running, stride of
+ * 1 float
+ * \param nx number of values in X direction
+ * \param ny number of values in Y direction
+ * \param nz number of values in Z direction
+ * \param dx Size of voxels in X direction
+ * \param dy Size of voxels in Y direction
+ * \param dz Size of voxels in Z direction
+ * \param min Minimum value in data
+ * \param max Maximum value in data
+ * \return Returns a float array with stride of 4 floats 
+ * containing the normalized scalar and the x,y,z components of 
+ * the (normalized) gradient vector
+ */
+float *
+nv::computeGradient(float *data,
+                    int nx, int ny, int nz,
+                    float dx, float dy, float dz,
+                    float min, float max)
+{
+    int npts = nx * ny * nz;
+    float *gradients = (float *)malloc(npts * 3 * sizeof(float));
+    float *tempGradients = (float *)malloc(npts * 3 * sizeof(float));
+    int sizes[3] = { nx, ny, nz };
+    float spacing[3] = { dx, dy, dz };
+    computeGradients(tempGradients, data, sizes, spacing, DATRAW_FLOAT);
+    filterGradients(tempGradients, sizes);
+    quantizeGradients(tempGradients, gradients, sizes, DATRAW_FLOAT);
+    free(tempGradients);
+    normalizeScalar(data, npts, 1, min, max);
+    float *dataOut = merge(data, gradients, npts);
+    free(gradients);
+    return dataOut;
+}
+
+/**
+ * \brief Compute gradients for a 3D volume with cubic cells
+ * 
+ * The gradients are estimated using the central difference
+ * method.  This function assumes the data are normalized
+ * to [0,1] with missing data/NaNs represented by a negative
+ * value.
+ *
+ * \param data Data array with X the fastest running. There
+ * should be 4 floats allocated for each node, with the 
+ * first float containing the scalar value.  The subsequent
+ * 3 floats will be filled with the x,y,z components of the
+ * gradient vector
+ * \param nx The number of nodes in the X direction
+ * \param ny The number of nodes in the Y direction
+ * \param nz The number of nodes in the Z direction
+ * \param dx The spacing (cell length) in the X direction
+ * \param dy The spacing (cell length) in the Y direction
+ * \param dz The spacing (cell length) in the Z direction
+ */
+void
+nv::computeSimpleGradient(float *data,
+                          int nx, int ny, int nz,
+                          float dx, float dy, float dz)
+{
+    bool clampToEdge = true;
+    double borderVal = 0.0;
+
+#define BORDER ((clampToEdge ? data[ngen] : borderVal))
+
+    // Compute the gradient of this data.  BE CAREFUL: center
+    // calculation on each node to avoid skew in either direction.
+    int ngen = 0;
+    for (int iz = 0; iz < nz; iz++) {
+        for (int iy = 0; iy < ny; iy++) {
+            for (int ix = 0; ix < nx; ix++) {
+                // gradient in x-direction
+                double valm1 = (ix == 0) ? BORDER : data[ngen - 4];
+                double valp1 = (ix == nx-1) ? BORDER : data[ngen + 4];
+                if (valm1 < 0.0 || valp1 < 0.0) {
+                    data[ngen+1] = 0.0;
+                } else {
+                    data[ngen+1] = -(valp1-valm1)/(2. * dx);
+                 }
+
+                // gradient in y-direction
+                valm1 = (iy == 0) ? BORDER : data[ngen - 4*nx];
+                valp1 = (iy == ny-1) ? BORDER : data[ngen + 4*nx];
+                if (valm1 < 0.0 || valp1 < 0.0) {
+                    data[ngen+2] = 0.0;
+                } else {
+                    data[ngen+2] = -(valp1-valm1)/(2. * dy);
+                }
+
+                // gradient in z-direction
+                valm1 = (iz == 0) ? BORDER : data[ngen - 4*nx*ny];
+                valp1 = (iz == nz-1) ? BORDER : data[ngen + 4*nx*ny];
+                if (valm1 < 0.0 || valp1 < 0.0) {
+                    data[ngen+3] = 0.0;
+                } else {
+                    data[ngen+3] = -(valp1-valm1)/(2. * dz);
+                }
+                // Normalize and scale/bias to [0,1] range
+                // The volume shader will expand to [-1,1]
+                double len = sqrt(data[ngen+1]*data[ngen+1] +
+                                  data[ngen+2]*data[ngen+2] +
+                                  data[ngen+3]*data[ngen+3]);
+                if (len < 1.0e-6) {
+                    data[ngen+1] = 0.0;
+                    data[ngen+2] = 0.0;
+                    data[ngen+3] = 0.0;
+                } else {
+                    data[ngen+1] = (data[ngen+1]/len + 1.0) * 0.5;
+                    data[ngen+2] = (data[ngen+2]/len + 1.0) * 0.5;
+                    data[ngen+3] = (data[ngen+3]/len + 1.0) * 0.5;
+                }
+                ngen += 4;
+            }
+        }
+    }
+
+#undef BORDER
+}
Index: /nanovis/tags/1.1.4/ReaderCommon.h
===================================================================
--- /nanovis/tags/1.1.4/ReaderCommon.h	(revision 4930)
+++ /nanovis/tags/1.1.4/ReaderCommon.h	(revision 4930)
@@ -0,0 +1,33 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#ifndef NV_READER_COMMON_H
+#define NV_READER_COMMON_H
+
+namespace nv {
+
+extern float *
+merge(float *scalar, float *gradient, int size);
+
+extern void
+normalizeScalar(float *data, int count, int stride, double min, double max);
+
+extern void
+normalizeVector(float *data, int count, double min, double max);
+
+extern float *
+computeGradient(float *data,
+                int nx, int ny, int nz,
+                float dx, float dy, float dz,
+                float min, float max);
+
+extern void
+computeSimpleGradient(float *data,
+                      int nx, int ny, int nz,
+                      float dx = 1.0f, float dy = 1.0f, float dz = 1.0f);
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/RegularVolumeShader.cpp
===================================================================
--- /nanovis/tags/1.1.4/RegularVolumeShader.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/RegularVolumeShader.cpp	(revision 4930)
@@ -0,0 +1,57 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#include "RegularVolumeShader.h"
+
+using namespace nv;
+
+RegularVolumeShader::RegularVolumeShader()
+{
+    init();
+}
+
+RegularVolumeShader::~RegularVolumeShader()
+{
+}
+
+void RegularVolumeShader::init()
+{
+    loadFragmentProgram("one_volume.cg");
+}
+
+void RegularVolumeShader::bind(unsigned int tfID, Volume *volume,
+                               int sliceMode, float sampleRatio)
+{
+    //regular cubic volume
+    setGLStateMatrixFPParameter("modelViewInv", MODELVIEW_MATRIX,
+                                MATRIX_INVERSE);
+    setGLStateMatrixFPParameter("modelView", MODELVIEW_MATRIX,
+                                MATRIX_IDENTITY);
+
+    setFPTextureParameter("volume", volume->textureID());
+    setFPTextureParameter("tf", tfID);
+
+    setFPParameter4f("material",
+                     volume->ambient(),
+                     volume->diffuse(),
+                     volume->specularLevel(),
+                     volume->specularExponent());
+
+    setFPParameter4f("renderParams",
+                     (sliceMode ? 0.0f : sampleRatio),
+                     volume->isosurface(),
+                     volume->opacityScale(),
+                     (volume->twoSidedLighting() ? 1.0f : 0.0f));
+
+    Shader:: bind();
+}
+
+void RegularVolumeShader::unbind()
+{
+    disableFPTextureParameter("volume");
+    disableFPTextureParameter("tf");
+
+    Shader::unbind();
+}
Index: /nanovis/tags/1.1.4/RegularVolumeShader.h
===================================================================
--- /nanovis/tags/1.1.4/RegularVolumeShader.h	(revision 4930)
+++ /nanovis/tags/1.1.4/RegularVolumeShader.h	(revision 4930)
@@ -0,0 +1,33 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#ifndef NV_REGULAR_VOLUME_SHADER_H
+#define NV_REGULAR_VOLUME_SHADER_H
+
+#include "Volume.h"
+#include "VolumeShader.h"
+
+namespace nv {
+
+/// Shader for regular volume (uniform grid)
+class RegularVolumeShader : public VolumeShader
+{
+public:
+    RegularVolumeShader();
+
+    virtual ~RegularVolumeShader();
+
+    virtual void bind(unsigned int tfID, Volume *volume,
+                      int sliceMode, float sampleRatio);
+
+    virtual void unbind();
+
+private:
+    void init();
+};
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/RenderVertexArray.cpp
===================================================================
--- /nanovis/tags/1.1.4/RenderVertexArray.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/RenderVertexArray.cpp	(revision 4930)
@@ -0,0 +1,127 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * ----------------------------------------------------------------------
+ *  Render to vertex array
+ *
+ *  This class implements "render to vertex array" functionality
+ *  using vertex and pixel buffer objects (VBO and PBO).
+ *
+ *  Operation:
+ *  1. A buffer object is created
+ *  2. The buffer object is bound to the pixel pack (destination) buffer
+ *  3. glReadPixels is used to read from the frame buffer to the buffer object
+ *  4. The buffer object is bound to the vertex array
+ *  5. Vertex array pointers are set
+ *  
+ *  Usage:
+ *  1. Create a floating point pbuffer
+ *  2. Create a RenderVertexArray object for each vertex attribute 
+ *       you want to render to
+ *  3. Render vertex data to pbuffer using a fragment program (could
+ *       use multiple draw buffers here)
+ *  4. Call Read() method to read data from pbuffer to vertex array
+ *  5. Call SetPointer() method to set vertex array pointers
+ *  6. Set any other other static vertex array attribute pointers
+ *  7. Render geometry as usual using glDrawArrays or glDrawElements
+ *
+ * ======================================================================
+ *  AUTHOR:  Wei Qiao <qiaow@purdue.edu>
+ *           Purdue Rendering and Perceptualization Lab (PURPL)
+ *
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ *  See the file "license.terms" for information on usage and
+ *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ * ======================================================================
+ */
+#include <stdio.h>
+
+#include <GL/glew.h>
+#include <GL/gl.h>
+
+#include "RenderVertexArray.h"
+#include "Trace.h"
+
+using namespace nv;
+
+RenderVertexArray::RenderVertexArray(int nverts, GLint size, GLenum type) :
+    _usage(GL_STREAM_COPY_ARB),
+    _nverts(nverts), 
+    _size(size), 
+    _type(type)
+{
+    switch (_type) {
+    case GL_HALF_FLOAT_NV:
+        _bytesPerComponent = 2;
+        break;
+    case GL_FLOAT:
+        _bytesPerComponent = sizeof(float);
+        break;
+    default:
+        ERROR("unsupported RenderVertexArray type");
+        return;
+    }
+
+    // create the buffer object
+    glGenBuffersARB(1, &_buffer);
+    glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, _buffer);
+    glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, 
+                    _nverts*_size*_bytesPerComponent,
+                    0, _usage); // undefined data
+    glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
+
+    // set equivalent image format
+    switch(_size) {
+    case 1:
+        _format = GL_LUMINANCE;
+        break;
+    case 3:
+        _format = GL_RGB;
+        break;
+    case 4:
+        _format = GL_RGBA;
+        break;
+    default:
+        ERROR("unsupported RenderVertexArray size");
+        return;
+    }
+}
+
+RenderVertexArray::~RenderVertexArray()
+{
+    glDeleteBuffersARB(1, &_buffer);
+}
+
+void
+RenderVertexArray::loadData(void *data)
+{
+    // load data to buffer object
+    glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, _buffer);
+    glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, 
+		    _nverts*_size*_bytesPerComponent,
+                    data, _usage);
+    glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
+}
+
+void
+RenderVertexArray::read(int w, int h)
+{
+    // bind buffer object to pixel pack buffer
+    glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, _buffer);
+
+    // read from frame buffer to buffer object
+    glReadPixels(0, 0, w, h, _format, _type, 0);
+
+    glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
+}
+
+void
+RenderVertexArray::setPointer(GLuint index)
+{
+    // bind buffer object to vertex array 
+    glBindBufferARB(GL_ARRAY_BUFFER_ARB, _buffer);
+    //glVertexAttribPointerARB(index, _size, _type, GL_FALSE, 0, 0);          //doesn't work
+    glVertexPointer(_size, _type, 0, 0);
+
+    glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
+}
Index: /nanovis/tags/1.1.4/RenderVertexArray.h
===================================================================
--- /nanovis/tags/1.1.4/RenderVertexArray.h	(revision 4930)
+++ /nanovis/tags/1.1.4/RenderVertexArray.h	(revision 4930)
@@ -0,0 +1,42 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Author:
+ *   Wei Qiao <qiaow@purdue.edu>
+ */
+#ifndef NV_RENDERVERTEXARRAY_H
+#define NV_RENDERVERTEXARRAY_H
+
+#include <GL/glew.h>
+#include <GL/gl.h>
+
+namespace nv {
+
+class RenderVertexArray
+{
+public:
+    RenderVertexArray(int nverts, GLint size, GLenum type = GL_FLOAT);
+
+    ~RenderVertexArray();
+
+    void loadData(void *data);	// load vertex data from memory
+
+    void read(int w, int h);   // read vertex data from frame buffer
+
+    void setPointer(GLuint index);
+
+private:
+    GLenum _usage;     // vbo usage flag
+    GLuint _buffer;
+    GLuint _index;
+    GLuint _nverts;
+    GLint _size;       // size of attribute       
+    GLenum _format;    // readpixels image format
+    GLenum _type;      // FLOAT or HALF_FLOAT
+    int _bytesPerComponent;
+};
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/Shader.cpp
===================================================================
--- /nanovis/tags/1.1.4/Shader.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/Shader.cpp	(revision 4930)
@@ -0,0 +1,130 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#include <stdio.h>
+
+#include <GL/glew.h>
+#include <Cg/cg.h>
+#include <Cg/cgGL.h>
+
+#include <util/FilePath.h>
+
+#include "Shader.h"
+#include "Trace.h"
+
+using namespace nv;
+using namespace nv::util;
+
+CGprofile Shader::_defaultVertexProfile = CG_PROFILE_VP40;
+CGprofile Shader::_defaultFragmentProfile = CG_PROFILE_FP40;
+CGcontext Shader::_cgContext = NULL;
+
+void Shader::init()
+{
+    _cgContext = cgCreateContext();
+}
+
+void Shader::exit()
+{
+    setErrorCallback(NULL);
+    printErrorInfo();
+    if (_cgContext != NULL) {
+        TRACE("Before DestroyContext");
+        cgDestroyContext(_cgContext);
+        TRACE("After DestroyContext");
+        _cgContext = NULL;
+    }
+}
+
+bool Shader::printErrorInfo()
+{
+    CGerror lastError = cgGetError();
+
+    if (lastError) {
+        TRACE("Cg Error: %s", cgGetErrorString(lastError));
+        if (getCgContext())
+            TRACE("%s", cgGetLastListing(getCgContext()));
+        return false;
+    }
+    return true;
+}
+
+CGprogram
+Shader::loadCgSourceProgram(CGcontext context, const char *fileName,
+                            CGprofile profile, const char *entryPoint)
+{
+    std::string path = FilePath::getInstance()->getPath(fileName);
+    if (path.empty()) {
+        ERROR("can't find program \"%s\"", fileName);
+    }
+    TRACE("cg program compiling: %s", path.c_str());
+    CGprogram program;
+    program = cgCreateProgramFromFile(context, CG_SOURCE, path.c_str(), profile, 
+                                      entryPoint, NULL);
+    cgGLLoadProgram(program);
+    CGerror LastError = cgGetError();
+    if (LastError) {
+        ERROR("Error message: %s", cgGetLastListing(context));
+    }
+    TRACE("successfully compiled program: %s", path.c_str());
+    return program;
+}
+
+Shader::Shader():
+    _vertexProfile(_defaultVertexProfile),
+    _fragmentProfile(_defaultFragmentProfile),
+    _cgVP(NULL),
+    _cgFP(NULL)
+{
+}
+
+Shader::~Shader()
+{
+    TRACE("Enter");
+    if (_cgContext == NULL) {
+        TRACE("Lost Cg context: vp: %s, fp: %s", _vpFile.c_str(), _fpFile.c_str());
+    } else {
+        resetPrograms();
+    }
+}
+
+void Shader::loadVertexProgram(const char *fileName)
+{
+    if (_cgVP != NULL) {
+        cgDestroyProgram(_cgVP);
+    }
+    _cgVP = loadCgSourceProgram(_cgContext, fileName,
+                                _vertexProfile, "main");
+    _vpFile = fileName;
+}
+
+void Shader::loadFragmentProgram(const char *fileName)
+{
+    if (_cgFP != NULL) {
+        cgDestroyProgram(_cgFP);
+    }
+    _cgFP = loadCgSourceProgram(_cgContext, fileName,
+                                _fragmentProfile, "main");
+    _fpFile = fileName;
+}
+
+void Shader::resetPrograms()
+{
+    if (_cgVP != NULL) {
+        TRACE("Destroying vertex program: %s", _vpFile.c_str());
+        cgDestroyProgram(_cgVP);
+    }
+
+    if (_cgFP != NULL) {
+        TRACE("Destroying fragment program: %s", _fpFile.c_str());
+        cgDestroyProgram(_cgFP);
+    }
+}
+
+void Shader::setErrorCallback(ShaderCallbackFunction callback)
+{
+    TRACE("Shader setting error callback to: %p", callback);
+    cgSetErrorCallback(callback);
+}
Index: /nanovis/tags/1.1.4/Shader.h
===================================================================
--- /nanovis/tags/1.1.4/Shader.h	(revision 4930)
+++ /nanovis/tags/1.1.4/Shader.h	(revision 4930)
@@ -0,0 +1,354 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#ifndef NV_SHADER_H
+#define NV_SHADER_H
+
+#include <string>
+#include <tr1/unordered_map>
+
+#include <GL/glew.h>
+#include <Cg/cg.h>
+#include <Cg/cgGL.h>
+
+#include "Trace.h"
+
+namespace nv {
+
+class Shader
+{
+public:
+    enum GLMatrix {
+        MODELVIEW_MATRIX = CG_GL_MODELVIEW_MATRIX,
+        PROJECTION_MATRIX = CG_GL_PROJECTION_MATRIX,
+        MODELVIEW_PROJECTION_MATRIX = CG_GL_MODELVIEW_PROJECTION_MATRIX
+    };
+    enum GLMatrixType {
+        MATRIX_IDENTITY = CG_GL_MATRIX_IDENTITY,
+        MATRIX_INVERSE = CG_GL_MATRIX_INVERSE
+    };
+
+    typedef void (*ShaderCallbackFunction)(void);
+
+    Shader();
+
+    virtual ~Shader();
+
+    /**
+     * \brief Load and compile a vertex shader
+     * \param fileName the name of the shader source file
+     */
+    void loadVertexProgram(const char *fileName);
+
+    /**
+     * \brief Load and compile a fragment shader
+     * \param fileName the name of the shader source file
+     */
+    void loadFragmentProgram(const char *fileName);
+
+    bool isVertexProgramLoaded()
+    {
+        return (getVP() == NULL);
+    }
+
+    bool isFragmentProgramLoaded()
+    {
+        return (getFP() == NULL);
+    }
+
+    void setVPParameter1f(const char *name, float val)
+    {
+        Parameter param = getVPParam(name);
+        if (param == NULL)
+            return;
+        cgSetParameter1f(param, val);
+    }
+
+    void setFPParameter1f(const char *name, float val)
+    {
+        Parameter param = getFPParam(name);
+        if (param == NULL)
+            return;
+        cgSetParameter1f(param, val);
+    }
+
+    void setVPParameter2f(const char *name, float val1, float val2)
+    {
+        Parameter param = getVPParam(name);
+        if (param == NULL)
+            return;
+        cgSetParameter2f(param, val1, val2);
+    }
+
+    void setFPParameter2f(const char *name, float val1, float val2)
+    {
+        Parameter param = getFPParam(name);
+        if (param == NULL)
+            return;
+        cgSetParameter2f(param, val1, val2);
+    }
+
+    void setVPParameter3f(const char *name, float val1, float val2, float val3)
+    {
+        Parameter param = getVPParam(name);
+        if (param == NULL)
+            return;
+        cgSetParameter3f(param, val1, val2, val3);
+    }
+
+    void setFPParameter3f(const char *name, float val1, float val2, float val3)
+    {
+        Parameter param = getFPParam(name);
+        if (param == NULL)
+            return;
+        cgSetParameter3f(param, val1, val2, val3);
+    }
+
+    void setVPParameter4f(const char *name, float val1, float val2, float val3, float val4)
+    {
+        Parameter param = getVPParam(name);
+        if (param == NULL)
+            return;
+        cgSetParameter4f(param, val1, val2, val3, val4);
+    }
+
+    void setFPParameter4f(const char *name, float val1, float val2, float val3, float val4)
+    {
+        Parameter param = getFPParam(name);
+        if (param == NULL)
+            return;
+        cgSetParameter4f(param, val1, val2, val3, val4);
+    }
+
+    void setVPMatrixParameterf(const char *name, float *mat)
+    {
+        Parameter param = getVPParam(name);
+        if (param == NULL)
+            return;
+        cgSetMatrixParameterfc(param, mat);
+    }
+
+    void setFPMatrixParameterf(const char *name, float *mat)
+    {
+        Parameter param = getFPParam(name);
+        if (param == NULL)
+            return;
+        cgSetMatrixParameterfc(param, mat);
+    }
+
+    void setVPTextureParameter(const char *name, GLuint texobj, bool enable = true)
+    {
+        Parameter param = getVPParam(name);
+        if (param == NULL)
+            return;
+        cgGLSetTextureParameter(param, texobj);
+        if (enable)
+            cgGLEnableTextureParameter(param);
+    }
+
+    void setFPTextureParameter(const char *name, GLuint texobj, bool enable = true)
+    {
+        Parameter param = getFPParam(name);
+        if (param == NULL)
+            return;
+        cgGLSetTextureParameter(param, texobj);
+        if (enable)
+            cgGLEnableTextureParameter(param);
+    }
+
+    void enableVPTextureParameter(const char *name)
+    {
+        Parameter param = getVPParam(name);
+        if (param == NULL)
+            return;
+        cgGLEnableTextureParameter(param);
+    }
+
+    void enaableFPTextureParameter(const char *name)
+    {
+        Parameter param = getFPParam(name);
+        if (param == NULL)
+            return;
+        cgGLEnableTextureParameter(param);
+    }
+
+    void disableVPTextureParameter(const char *name)
+    {
+        Parameter param = getVPParam(name);
+        if (param == NULL)
+            return;
+        cgGLDisableTextureParameter(param);
+    }
+
+    void disableFPTextureParameter(const char *name)
+    {
+        Parameter param = getFPParam(name);
+        if (param == NULL)
+            return;
+        cgGLDisableTextureParameter(param);
+    }
+
+    void setGLStateMatrixVPParameter(const char *name, GLMatrix matrix,
+                                     GLMatrixType type = MATRIX_IDENTITY)
+    {
+        Parameter param = getVPParam(name);
+        if (param == NULL)
+            return;
+        cgGLSetStateMatrixParameter(param, (CGGLenum)matrix, (CGGLenum)type);
+    }
+
+    void setGLStateMatrixFPParameter(const char *name, GLMatrix matrix,
+                                     GLMatrixType type = MATRIX_IDENTITY)
+    {
+        Parameter param = getFPParam(name);
+        if (param == NULL)
+            return;
+        cgGLSetStateMatrixParameter(param, (CGGLenum)matrix, (CGGLenum)type);
+    }
+
+    virtual void bind()
+    {
+        if (_cgVP) {
+            cgGLBindProgram(_cgVP);
+            enableVertexProfile();
+        }
+        if (_cgFP) {
+            cgGLBindProgram(_cgFP);
+            enableFragmentProfile();
+        }
+    }
+
+    virtual void unbind()
+    {
+        if (_cgVP)
+            disableVertexProfile();
+        if (_cgFP)
+            disableFragmentProfile();
+    }
+
+    static void init();
+
+    static void exit();
+
+    static bool printErrorInfo();
+
+    static void setErrorCallback(ShaderCallbackFunction callback);
+
+    static CGcontext getCgContext()
+    {
+        return _cgContext;
+    }
+
+protected:
+    typedef CGparameter Parameter;
+    typedef std::tr1::unordered_map<std::string, Parameter> ParameterHashmap;
+
+    Parameter getNamedParameterFromFP(const char *paramName)
+    {
+        if (_cgFP) {
+            return cgGetNamedParameter(_cgFP, paramName);
+        }
+        ERROR("Unknown fragment program parameter: %s", paramName);
+        return 0;
+    }
+
+    Parameter getNamedParameterFromVP(const char *paramName)
+    {
+        if (_cgVP) {
+            return cgGetNamedParameter(_cgVP, paramName);
+        }
+        ERROR("Unknown vertex program parameter: %s", paramName);
+        return 0;
+    }
+
+    Parameter getVPParam(const char *name)
+    {
+        Parameter param;
+        ParameterHashmap::iterator itr = _vpParams.find(name);
+        if (itr == _vpParams.end()) {
+            param = getNamedParameterFromVP(name);
+            if (param != NULL)
+                _vpParams[name] = param;
+            else
+                ERROR("Unknown vertex program parameter: %s", name);
+        } else {
+            param = itr->second;
+        }
+        return param;
+    }
+
+    Parameter getFPParam(const char *name)
+    {
+        Parameter param;
+        ParameterHashmap::iterator itr = _fpParams.find(name);
+        if (itr == _fpParams.end()) {
+            param = getNamedParameterFromFP(name);
+            if (param != NULL)
+                _fpParams[name] = param;
+            else
+                ERROR("Unknown fragment program parameter: %s", name);
+        } else {
+            param = itr->second;
+        }
+        return param;
+    }
+
+    void resetPrograms();
+
+    CGprogram getVP()
+    {
+        return _cgVP;
+    }
+
+    CGprogram getFP()
+    {
+        return _cgFP;
+    }
+
+    void enableVertexProfile()
+    {
+        cgGLEnableProfile(_vertexProfile);
+    }
+
+    void disableVertexProfile()
+    {
+        cgGLDisableProfile(_vertexProfile);
+    }
+
+    void enableFragmentProfile()
+    {
+        cgGLEnableProfile(_fragmentProfile);
+    }
+
+    void disableFragmentProfile()
+    {
+        cgGLDisableProfile(_fragmentProfile);
+    }
+
+    std::string _vpFile;
+    std::string _fpFile;
+
+    ParameterHashmap _vpParams;
+    ParameterHashmap _fpParams;
+
+    CGprofile _vertexProfile;
+    CGprofile _fragmentProfile;
+
+    CGprogram _cgVP;
+    CGprogram _cgFP;
+
+    static CGprofile _defaultVertexProfile;
+    static CGprofile _defaultFragmentProfile;
+    static CGcontext _cgContext;
+
+private:
+    static CGprogram
+    loadCgSourceProgram(CGcontext context, const char *filename, 
+                        CGprofile profile, const char *entryPoint);
+};
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/StdVertexShader.cpp
===================================================================
--- /nanovis/tags/1.1.4/StdVertexShader.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/StdVertexShader.cpp	(revision 4930)
@@ -0,0 +1,40 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#include "StdVertexShader.h"
+
+using namespace nv;
+
+StdVertexShader::StdVertexShader()
+{
+    init();
+}
+
+StdVertexShader::~StdVertexShader()
+{
+}
+
+void StdVertexShader::init()
+{
+    loadVertexProgram("vertex_std.cg");
+}
+
+void StdVertexShader::bind(float *mvp, float *mvInv)
+{
+    if (mvp != NULL) {
+        setVPMatrixParameterf("modelViewProjMatrix", mvp);
+    } else {
+        setGLStateMatrixVPParameter("modelViewProjMatrix",
+                                    MODELVIEW_PROJECTION_MATRIX);
+    }
+    if (mvInv != NULL) {
+        setVPMatrixParameterf("modelViewInv", mvInv);
+    } else {
+        setGLStateMatrixVPParameter("modelViewInv",
+                                    MODELVIEW_MATRIX, MATRIX_INVERSE);
+    }
+
+    Shader::bind();
+}
Index: /nanovis/tags/1.1.4/StdVertexShader.h
===================================================================
--- /nanovis/tags/1.1.4/StdVertexShader.h	(revision 4930)
+++ /nanovis/tags/1.1.4/StdVertexShader.h	(revision 4930)
@@ -0,0 +1,34 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#ifndef NV_STD_VERTEX_SHADER_H
+#define NV_STD_VERTEX_SHADER_H
+
+#include "Shader.h"
+
+namespace nv {
+
+class StdVertexShader : public Shader
+{
+public:
+    StdVertexShader();
+
+    virtual ~StdVertexShader();
+
+    virtual void bind(float *mvp = NULL, float *mvInv = NULL);
+
+    virtual void unbind()
+    {
+        Shader::unbind();
+    }
+
+private:
+    void init();
+};
+
+}
+
+#endif 
+
Index: /nanovis/tags/1.1.4/Switch.cpp
===================================================================
--- /nanovis/tags/1.1.4/Switch.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/Switch.cpp	(revision 4930)
@@ -0,0 +1,491 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Switch.cpp --
+ *
+ * This module implements command/argument switch parsing procedures for the
+ * BLT toolkit.
+ *
+ *	Copyright 1991-2004 George A Howlett.
+ *
+ *	Permission is hereby granted, free of charge, to any person obtaining
+ *	a copy of this software and associated documentation files (the
+ *	"Software"), to deal in the Software without restriction, including
+ *	without limitation the rights to use, copy, modify, merge, publish,
+ *	distribute, sublicense, and/or sell copies of the Software, and to
+ *	permit persons to whom the Software is furnished to do so, subject to
+ *	the following conditions:
+ *
+ *	The above copyright notice and this permission notice shall be
+ *	included in all copies or substantial portions of the Software.
+ *
+ *	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *	EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *	MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *	NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ *	LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ *	OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ *	WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <malloc.h>
+#include <tcl.h>
+#include "Switch.h"
+
+namespace nv {
+
+static void
+DoHelp(Tcl_Interp *interp, SwitchSpec *specs)
+{
+    Tcl_DString ds;
+    SwitchSpec *sp;
+
+    Tcl_DStringInit(&ds);
+    Tcl_DStringAppend(&ds, "following switches are available:", -1);
+    for (sp = specs; sp->type != SWITCH_END; sp++) {
+	Tcl_DStringAppend(&ds, "\n    ", 4);
+	Tcl_DStringAppend(&ds, sp->switchName, -1);
+	Tcl_DStringAppend(&ds, " ", 1);
+	Tcl_DStringAppend(&ds, sp->help, -1);
+    }
+    Tcl_AppendResult(interp, Tcl_DStringValue(&ds), (char *)NULL);
+    Tcl_DStringFree(&ds);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * FindSwitchSpec --
+ *
+ *	Search through a table of configuration specs, looking for one that
+ *	matches a given argvName.
+ *
+ * Results:
+ *	The return value is a pointer to the matching entry, or NULL if
+ *	nothing matched.  In that case an error message is left in the
+ *	interp's result.
+ *
+ * Side effects:
+ *	None.
+ *
+ *---------------------------------------------------------------------------
+ */
+static SwitchSpec *
+FindSwitchSpec(
+    Tcl_Interp *interp,		/* Used for reporting errors. */
+    SwitchSpec *specs,		/* Pointer to table of configuration
+				 * specifications for a widget. */
+    const char *name,		/* Name identifying a particular switch. */
+    int length,			/* Length of name. */
+    int needFlags,		/* Flags that must be present in matching
+				 * entry. */
+    int hateFlags)		/* Flags that must NOT be present in matching
+				 * entry. */
+{
+    SwitchSpec *sp;
+    char c;			/* First character of current argument. */
+    SwitchSpec *matchPtr;	/* Matching spec, or NULL. */
+
+    c = name[1];
+    matchPtr = NULL;
+    for (sp = specs; sp->type != SWITCH_END; sp++) {
+	if (sp->switchName == NULL) {
+	    continue;
+	}
+	if (((sp->flags & needFlags) != needFlags) || (sp->flags & hateFlags)) {
+	    continue;
+	}
+	if ((sp->switchName[1] != c) || 
+	    (strncmp(sp->switchName, name, length) != 0)) {
+	    continue;
+	}
+	if (sp->switchName[length] == '\0') {
+	    return sp;		/* Stop on a perfect match. */
+	}
+	if (matchPtr != NULL) {
+	    Tcl_AppendResult(interp, "ambiguous switch \"", name, "\"\n", 
+		(char *) NULL);
+	    DoHelp(interp, specs);
+	    return NULL;
+	}
+	matchPtr = sp;
+    }
+    if (strcmp(name, "-help") == 0) {
+	DoHelp(interp, specs);
+	return NULL;
+    }
+    if (matchPtr == NULL) {
+	Tcl_AppendResult(interp, "unknown switch \"", name, "\"\n", 
+			 (char *)NULL);
+	DoHelp(interp, specs);
+	return NULL;
+    }
+    return matchPtr;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * DoSwitch --
+ *
+ *	This procedure applies a single configuration switch to a widget
+ *	record.
+ *
+ * Results:
+ *	A standard Tcl return value.
+ *
+ * Side effects:
+ *	WidgRec is modified as indicated by specPtr and value.  The old value
+ *	is recycled, if that is appropriate for the value type.
+ *
+ *---------------------------------------------------------------------------
+ */
+static int
+DoSwitch(
+    Tcl_Interp *interp,		/* Interpreter for error reporting. */
+    SwitchSpec *sp,		/* Specifier to apply. */
+    Tcl_Obj *objPtr,		/* Value to use to fill in widgRec. */
+    void *record)		/* Record whose fields are to be modified.
+				 * Values must be properly initialized. */
+{
+    do {
+	char *ptr;
+
+	ptr = (char *)record + sp->offset;
+	switch (sp->type) {
+	case SWITCH_BOOLEAN:
+	    {
+		int value;
+
+		if (Tcl_GetBooleanFromObj(interp, objPtr, &value) != TCL_OK) {
+		    return TCL_ERROR;
+		}
+		if (sp->mask > 0) {
+		    if (value) {
+			*((int *)ptr) |= sp->mask;
+		    } else {
+			*((int *)ptr) &= ~sp->mask;
+		    }
+		} else {
+		    *((int *)ptr) = value;
+		}
+	    }
+	    break;
+
+	case SWITCH_DOUBLE:
+	    if (Tcl_GetDoubleFromObj(interp, objPtr, (double *)ptr) != TCL_OK) {
+		return TCL_ERROR;
+	    }
+	    break;
+
+	case SWITCH_OBJ:
+	    *(Tcl_Obj **)ptr = objPtr;
+	    break;
+
+	case SWITCH_FLOAT:
+	    {
+		double value;
+
+		if (Tcl_GetDoubleFromObj(interp, objPtr, &value) != TCL_OK) {
+		    return TCL_ERROR;
+		}
+		*(float *)ptr = (float)value;
+	    }
+	    break;
+
+	case SWITCH_INT:
+	    if (Tcl_GetIntFromObj(interp, objPtr, (int *)ptr) != TCL_OK) {
+		return TCL_ERROR;
+	    }
+	    break;
+
+	case SWITCH_LIST:
+	    {
+		int argc;
+
+		if (Tcl_SplitList(interp, Tcl_GetString(objPtr), &argc, 
+				  (const char ***)ptr) != TCL_OK) {
+		    return TCL_ERROR;
+		}
+	    }
+	    break;
+
+	case SWITCH_LONG:
+	    if (Tcl_GetLongFromObj(interp, objPtr, (long *)ptr) != TCL_OK) {
+		return TCL_ERROR;
+	    }
+	    break;
+
+	case SWITCH_STRING: 
+	    {
+		char *oldPtr, *newPtr, **strPtr;
+		char *string;
+
+		string = Tcl_GetString(objPtr);
+		strPtr = (char **)ptr;
+		newPtr = ((*string == '\0') && (sp->flags & SWITCH_NULL_OK))
+		    ? NULL : strdup(string);
+		oldPtr = *strPtr;
+		if (oldPtr != NULL) {
+		    free(oldPtr);
+		}
+		*strPtr = newPtr;
+	    }
+	    break;
+
+	case SWITCH_CUSTOM:
+	    assert(sp->customPtr != NULL);
+	    if ((*sp->customPtr->parseProc)(sp->customPtr->clientData, interp,
+		sp->switchName, objPtr, (char *)record, sp->offset, sp->flags) 
+		!= TCL_OK) {
+		return TCL_ERROR;
+	    }
+	    break;
+
+	default: 
+	    Tcl_AppendResult(interp, "bad switch table: unknown type", 
+			     (char *)NULL);
+	    return TCL_ERROR;
+	}
+	sp++;
+    } while ((sp->switchName == NULL) && (sp->type != SWITCH_END));
+    return TCL_OK;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * ParseSwitches --
+ *
+ *	Process command-line switches to fill in fields of a record with
+ *	resources and other parameters.
+ *
+ * Results:
+ *	Returns the number of arguments comsumed by parsing the command line.
+ *	If an error occurred, -1 will be returned and an error messages can be
+ *	found as the interpreter result.
+ *
+ * Side effects:
+ *	The fields of widgRec get filled in with information from argc/argv.
+ *	Old information in widgRec's fields gets recycled.
+ *
+ *---------------------------------------------------------------------------
+ */
+int
+ParseSwitches(
+    Tcl_Interp *interp,		/* Interpreter for error reporting. */
+    SwitchSpec *specs,		/* Describes legal switches. */
+    int objc,			/* Number of elements in argv. */
+    Tcl_Obj *const *objv,	/* Command-line switches. */
+    void *record,		/* Record whose fields are to be modified.
+				 * Values must be properly initialized. */
+    int flags)			/* Used to specify additional flags that must
+				 * be present in switch specs for them to be
+				 * considered.  */
+{
+    SwitchSpec *sp;
+    int count;
+    int needFlags;		/* Specs must contain this set of flags or
+				 * else they are not considered. */
+    int hateFlags;		/* If a spec contains any bits here, it's not
+				 * considered. */
+
+    needFlags = flags & ~(SWITCH_USER_BIT - 1);
+    hateFlags = 0;
+
+    /*
+     * Pass 1:  Clear the change flags on all the specs so that we 
+     *          can check it later.
+     */
+    for (sp = specs; sp->type != SWITCH_END; sp++) {
+	sp->flags &= ~SWITCH_SPECIFIED;
+    }
+    /*
+     * Pass 2:  Process the arguments that match entries in the specs.
+     *		It's an error if the argument doesn't match anything.
+     */
+    for (count = 0; count < objc; count++) {
+	char *arg;
+	int length;
+
+	arg = Tcl_GetStringFromObj(objv[count], &length);
+	if (flags & SWITCH_OBJV_PARTIAL) {
+	    /* 
+	     * If the argument doesn't start with a '-' (not a switch) or is
+	     * '--', stop processing and return the number of arguments
+	     * comsumed.
+	     */
+	    if (arg[0] != '-') {
+		return count;
+	    }
+	    if ((arg[1] == '-') && (arg[2] == '\0')) {
+		return count + 1; /* include the "--" in the count. */
+	    }
+	}
+	sp = FindSwitchSpec(interp, specs, arg, length, needFlags, hateFlags);
+	if (sp == NULL) {
+	    return -1;
+	}
+	if (sp->type == SWITCH_BITMASK) {
+	    char *ptr;
+
+	    ptr = (char *)record + sp->offset;
+	    *((int *)ptr) |= sp->mask;
+	} else if (sp->type == SWITCH_BITMASK_NEG) {
+	    char *ptr;
+	    
+	    ptr = (char *)record + sp->offset;
+	    *((int *)ptr) &= ~sp->mask;
+	} else if (sp->type == SWITCH_VALUE) {
+	    char *ptr;
+	    
+	    ptr = (char *)record + sp->offset;
+	    *((int *)ptr) = sp->mask;
+	} else {
+	    count++;
+	    if (count == objc) {
+		Tcl_AppendResult(interp, "value for \"", arg, "\" missing", 
+				 (char *) NULL);
+		return -1;
+	    }
+	    if (DoSwitch(interp, sp, objv[count], record) != TCL_OK) {
+		char msg[200];
+
+		sprintf(msg, "\n    (processing \"%.40s\" switch)", 
+			sp->switchName);
+		Tcl_AddErrorInfo(interp, msg);
+		return -1;
+	    }
+	}
+	sp->flags |= SWITCH_SPECIFIED;
+    }
+    return count;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * FreeSwitches --
+ *
+ *	Free up all resources associated with switches.
+ *
+ * Results:
+ *	None.
+ *
+ *---------------------------------------------------------------------------
+ */
+void
+FreeSwitches(
+    SwitchSpec *specs,		/* Describes legal switches. */
+    void *record,		/* Record whose fields contain current values
+				 * for switches. */
+    int needFlags)		/* Used to specify additional flags that must
+				 * be present in config specs for them to be
+				 * considered. */
+{
+    SwitchSpec *sp;
+
+    for (sp = specs; sp->type != SWITCH_END; sp++) {
+	if ((sp->flags & needFlags) == needFlags) {
+	    char *ptr;
+
+	    ptr = (char *)record + sp->offset;
+	    switch (sp->type) {
+	    case SWITCH_STRING:
+	    case SWITCH_LIST:
+		if (*((char **) ptr) != NULL) {
+		    free(*((char **) ptr));
+		    *((char **) ptr) = NULL;
+		}
+		break;
+
+	    case SWITCH_CUSTOM:
+		assert(sp->customPtr != NULL);
+		if ((*(char **)ptr != NULL) && 
+		    (sp->customPtr->freeProc != NULL)) {
+		    (*sp->customPtr->freeProc)((char *)record, sp->offset, 
+			sp->flags);
+		}
+		break;
+
+	    default:
+		break;
+	    }
+	}
+    }
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * SwitchModified --
+ *
+ *      Given the configuration specifications and one or more switch patterns
+ *      (terminated by a NULL), indicate if any of the matching switches has
+ *      been reset.
+ *
+ * Results:
+ *      Returns 1 if one of the switches have changed, 0 otherwise.
+ *
+ *---------------------------------------------------------------------------
+ */
+int 
+SwitchChanged TCL_VARARGS_DEF(SwitchSpec *, arg1)
+{
+    va_list argList;
+    SwitchSpec *specs;
+    SwitchSpec *sp;
+    char *switchName;
+
+    specs = TCL_VARARGS_START(SwitchSpec *, arg1, argList);
+    while ((switchName = va_arg(argList, char *)) != NULL) {
+	for (sp = specs; sp->type != SWITCH_END; sp++) {
+	    if ((Tcl_StringMatch(sp->switchName, switchName)) &&
+		(sp->flags & SWITCH_SPECIFIED)) {
+		va_end(argList);
+		return 1;
+	    }
+	}
+    }
+    va_end(argList);
+    return 0;
+}
+
+int 
+ExprDoubleFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, double *valuePtr)
+{
+    /* First try to extract the value as a double precision number. */
+    if (Tcl_GetDoubleFromObj((Tcl_Interp *)NULL, objPtr, valuePtr) == TCL_OK) {
+	return TCL_OK;
+    }
+    /* Then try to parse it as an expression. */
+    if (Tcl_ExprDouble(interp, Tcl_GetString(objPtr), valuePtr) == TCL_OK) {
+	return TCL_OK;
+    }
+    return TCL_ERROR;
+}
+
+int 
+ExprIntFromObj(
+    Tcl_Interp *interp, 
+    Tcl_Obj *objPtr, 
+    int *valuePtr)
+{
+    long lvalue;
+
+    /* First try to extract the value as a simple integer. */
+    if (Tcl_GetIntFromObj((Tcl_Interp *)NULL, objPtr, valuePtr) == TCL_OK) {
+	return TCL_OK;
+    }
+    /* Otherwise try to parse it as an expression. */
+    if (Tcl_ExprLong(interp, Tcl_GetString(objPtr), &lvalue) == TCL_OK) {
+	*valuePtr = lvalue;
+	return TCL_OK;
+    }
+    return TCL_ERROR;
+}
+
+}
Index: /nanovis/tags/1.1.4/Switch.h
===================================================================
--- /nanovis/tags/1.1.4/Switch.h	(revision 4930)
+++ /nanovis/tags/1.1.4/Switch.h	(revision 4930)
@@ -0,0 +1,135 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Switch.h --
+ *
+ *	Copyright 1993-2004 George A Howlett.
+ *
+ *	Permission is hereby granted, free of charge, to any person
+ *	obtaining a copy of this software and associated documentation
+ *	files (the "Software"), to deal in the Software without
+ *	restriction, including without limitation the rights to use,
+ *	copy, modify, merge, publish, distribute, sublicense, and/or
+ *	sell copies of the Software, and to permit persons to whom the
+ *	Software is furnished to do so, subject to the following
+ *	conditions:
+ *
+ *	The above copyright notice and this permission notice shall be
+ *	included in all copies or substantial portions of the
+ *	Software.
+ *
+ *	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+ *	KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ *	WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ *	PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
+ *	OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ *	OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ *	OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ *	SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef NV_SWITCH_H
+#define NV_SWITCH_H
+
+#ifdef HAVE_STDDEF_H
+#  include <stddef.h>
+#endif /* HAVE_STDDEF_H */
+
+namespace nv {
+
+typedef int (SwitchParseProc)(ClientData clientData, Tcl_Interp *interp, 
+                              const char *switchName, Tcl_Obj *valueObjPtr,
+                              char *record, int offset,
+                              int flags);
+
+typedef void (SwitchFreeProc)(char *record, int offset, int flags);
+
+typedef struct {
+    SwitchParseProc *parseProc; /* Procedure to parse a switch
+				 * value and store it in its *
+				 * converted form in the data *
+				 * record. */
+
+    SwitchFreeProc *freeProc;	/* Procedure to free a switch. */
+
+    ClientData clientData;	/* Arbitrary one-word value used by
+				 * switch parser, passed to
+				 * parseProc. */
+} SwitchCustom;
+
+
+/*
+ * Type values for SwitchSpec structures.  See the user
+ * documentation for details.
+ */
+typedef enum {
+    SWITCH_BOOLEAN, 
+    SWITCH_DOUBLE, 
+    SWITCH_BITMASK, 
+    SWITCH_BITMASK_NEG, 
+    SWITCH_FLOAT, 
+    SWITCH_INT, 
+    SWITCH_INT_NNEG, 
+    SWITCH_INT_POS,
+    SWITCH_LIST, 
+    SWITCH_LONG, 
+    SWITCH_LONG_NNEG, 
+    SWITCH_LONG_POS,
+    SWITCH_OBJ,
+    SWITCH_STRING, 
+    SWITCH_VALUE, 
+    SWITCH_CUSTOM, 
+    SWITCH_END
+} SwitchTypes;
+
+
+typedef struct {
+    SwitchTypes type;		/* Type of option, such as
+				 * SWITCH_COLOR; see definitions
+				 * below.  Last option in table must
+				 * have type SWITCH_END. */
+
+    const char *switchName;	/* Switch used to specify option in
+				 * argv.  NULL means this spec is part
+				 * of a group. */
+
+    const char *help;		/* Help string. */
+    int offset;			/* Where in widget record to store
+				 * value; use Blt_Offset macro to
+				 * generate values for this. */
+
+    int flags;			/* Any combination of the values
+				 * defined below. */
+
+    unsigned int mask;
+
+    SwitchCustom *customPtr;	/* If type is SWITCH_CUSTOM then
+				 * this is a pointer to info about how
+				 * to parse and print the option.
+				 * Otherwise it is irrelevant. */
+} SwitchSpec;
+
+#define SWITCH_DEFAULTS		(0)  
+#define SWITCH_ARGV_PARTIAL	(1<<1)
+#define SWITCH_OBJV_PARTIAL	(1<<1)
+
+/*
+ * Possible flag values for Blt_SwitchSpec structures.  Any bits at or
+ * above BLT_SWITCH_USER_BIT may be used by clients for selecting
+ * certain entries.
+ */
+#define SWITCH_NULL_OK		(1<<0)
+#define SWITCH_DONT_SET_DEFAULT	(1<<3)
+#define SWITCH_SPECIFIED	(1<<4)
+#define SWITCH_USER_BIT		(1<<8)
+
+extern int ParseSwitches(Tcl_Interp *interp, SwitchSpec *specPtr, 
+                         int objc, Tcl_Obj *const *objv,
+                         void *rec, int flags);
+
+extern void FreeSwitches(SwitchSpec *specs, void *rec, int flags);
+
+extern int SwitchChanged TCL_VARARGS(SwitchSpec *, specs);
+ 
+}
+
+#endif
Index: /nanovis/tags/1.1.4/Texture1D.cpp
===================================================================
--- /nanovis/tags/1.1.4/Texture1D.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/Texture1D.cpp	(revision 4930)
@@ -0,0 +1,120 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * ----------------------------------------------------------------------
+ * Texture1d.cpp: 1d texture class
+ *
+ * ======================================================================
+ *  AUTHOR:  Wei Qiao <qiaow@purdue.edu>
+ *           Purdue Rendering and Perceptualization Lab (PURPL)
+ *
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ *  See the file "license.terms" for information on usage and
+ *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ * ======================================================================
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include <math.h>
+
+#include "Texture1D.h"
+#include "Trace.h"
+
+using namespace nv;
+
+Texture1D::Texture1D() :
+    _width(0),
+    _numComponents(3),
+    _glResourceAllocated(false),
+    _id(0),
+    _type(GL_FLOAT),
+    _interpType(GL_LINEAR),
+    _wrapS(GL_CLAMP_TO_EDGE)
+{
+}
+
+Texture1D::Texture1D(int width,
+                     GLuint type, GLuint interp,
+                     int numComponents, void *data) :
+    _width(width),
+    _numComponents(numComponents),
+    _glResourceAllocated(false),
+    _id(0),
+    _type(type),
+    _interpType(interp),
+    _wrapS(GL_CLAMP_TO_EDGE)
+{
+    if (data != NULL)
+        initialize(data);
+}
+
+Texture1D::~Texture1D()
+{
+    glDeleteTextures(1, &_id);
+}
+
+GLuint Texture1D::initialize(void *data)
+{
+    if (_glResourceAllocated)
+        glDeleteTextures(1, &_id);
+
+    glGenTextures(1, &_id);
+
+    update(data);
+        
+    _glResourceAllocated = true;
+    return _id;
+}
+
+void Texture1D::update(void *data)
+{
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+    glBindTexture(GL_TEXTURE_1D, _id);
+        
+    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, _wrapS);
+    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, _interpType);
+    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, _interpType);
+
+    GLuint format[5] = { 
+        (GLuint)-1, GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_RGB, GL_RGBA
+    };
+
+    glTexImage1D(GL_TEXTURE_1D, 0, format[_numComponents], _width, 0,
+                 format[_numComponents], _type, data);
+
+    assert(glGetError()==0);    
+}
+
+void Texture1D::activate()
+{
+    glBindTexture(GL_TEXTURE_1D, _id);
+    glEnable(GL_TEXTURE_1D);
+}
+
+void Texture1D::deactivate()
+{
+    glDisable(GL_TEXTURE_1D);           
+}
+
+void Texture1D::setWrapS(GLuint wrapMode)
+{
+    _wrapS = wrapMode;
+}
+
+void Texture1D::checkMaxSize()
+{
+    GLint max = 0;
+    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max);
+
+    TRACE("max texture size: %d", max);
+}
+
+void Texture1D::checkMaxUnit()
+{
+    int max;
+    glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &max);
+
+    TRACE("max texture units: %d", max);
+}
Index: /nanovis/tags/1.1.4/Texture1D.h
===================================================================
--- /nanovis/tags/1.1.4/Texture1D.h	(revision 4930)
+++ /nanovis/tags/1.1.4/Texture1D.h	(revision 4930)
@@ -0,0 +1,74 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * ----------------------------------------------------------------------
+ * Texture1D.h: 1d texture class
+ *
+ * ======================================================================
+ *  AUTHOR:  Wei Qiao <qiaow@purdue.edu>
+ *           Purdue Rendering and Perceptualization Lab (PURPL)
+ *
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ *  See the file "license.terms" for information on usage and
+ *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ * ======================================================================
+ */
+#ifndef NV_TEXTURE1D_H
+#define NV_TEXTURE1D_H
+
+#include <GL/glew.h>
+
+namespace nv {
+
+class Texture1D
+{
+public:
+    Texture1D();
+
+    Texture1D(int width,
+              GLuint type = GL_FLOAT,
+              GLuint interp = GL_LINEAR,
+              int numComponents = 4,
+              void *data = NULL);
+
+    ~Texture1D();
+
+    GLuint initialize(void *data);
+
+    void update(void *data);
+
+    void activate();
+
+    void deactivate();
+
+    int width() const
+    {
+        return _width;
+    }
+
+    GLuint id() const
+    {
+        return _id;
+    }
+
+    void setWrapS(GLuint wrapMode);
+
+    static void checkMaxSize();
+
+    static void checkMaxUnit();
+
+private:
+    int _width;
+
+    int _numComponents;
+
+    bool _glResourceAllocated;
+    GLuint _id;
+    GLuint _type;
+    GLuint _interpType;
+    GLuint _wrapS;
+};
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/Texture2D.cpp
===================================================================
--- /nanovis/tags/1.1.4/Texture2D.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/Texture2D.cpp	(revision 4930)
@@ -0,0 +1,159 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * ----------------------------------------------------------------------
+ * Texture2D.h: 2d texture class
+ *
+ * ======================================================================
+ *  AUTHOR:  Wei Qiao <qiaow@purdue.edu>
+ *           Purdue Rendering and Perceptualization Lab (PURPL)
+ *
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ *  See the file "license.terms" for information on usage and
+ *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ * ======================================================================
+ */
+#include <stdio.h>
+#include <assert.h>
+#include <math.h>
+
+#include "config.h"
+
+#include "Texture2D.h"
+#include "Trace.h"
+
+using namespace nv;
+
+Texture2D::Texture2D() :
+    _width(0),
+    _height(0),
+    _numComponents(3),
+    _glResourceAllocated(false),
+    _id(0),
+    _type(GL_FLOAT),
+    _interpType(GL_LINEAR),
+    _wrapS(GL_CLAMP_TO_EDGE),
+    _wrapT(GL_CLAMP_TO_EDGE)
+{}
+
+Texture2D::Texture2D(int width, int height,
+                     GLuint type, GLuint interp,
+                     int numComponents, void *data) :
+    _width(width),
+    _height(height),
+    _numComponents(numComponents),
+    _glResourceAllocated(false),
+    _id(0),
+    _type(type),
+    _interpType(interp),
+    _wrapS(GL_CLAMP_TO_EDGE),
+    _wrapT(GL_CLAMP_TO_EDGE)
+{
+    if (data != NULL)
+        initialize(data);
+}
+
+Texture2D::~Texture2D()
+{
+    glDeleteTextures(1, &_id);
+}
+
+GLuint Texture2D::initialize(void *data)
+{
+    if (_glResourceAllocated)
+        glDeleteTextures(1, &_id);
+
+    glGenTextures(1, &_id);
+
+    update(data);
+
+    _glResourceAllocated = true;
+    return _id;
+}
+
+void Texture2D::update(void *data)
+{
+#ifdef USE_HALF_FLOAT
+    static GLuint halfFloatFormats[] = {
+        (GLuint)-1, GL_LUMINANCE16F_ARB, GL_LUMINANCE_ALPHA16F_ARB,
+        GL_RGB16F_ARB, GL_RGBA16F_ARB
+    };
+#elif defined(HAVE_FLOAT_TEXTURES)
+    static GLuint floatFormats[] = {
+        (GLuint)-1, GL_LUMINANCE32F_ARB, GL_LUMINANCE_ALPHA32F_ARB,
+        GL_RGB32F_ARB, GL_RGBA32F_ARB
+    };
+#endif
+    static GLuint basicFormats[] = {
+       (GLuint) -1, GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_RGB, GL_RGBA
+    };
+
+    glBindTexture(GL_TEXTURE_2D, _id);
+
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, _wrapS);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, _wrapT);
+
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _interpType);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, _interpType);
+
+    //to do: add handling to more formats
+    GLuint *targetFormats;
+#ifdef HAVE_FLOAT_TEXTURES
+    if (_type == GL_FLOAT) {
+# ifdef USE_HALF_FLOAT
+        targetFormats = halfFloatFormats;
+# else
+        targetFormats = floatFormats;
+# endif
+    } else {
+#endif
+        targetFormats = basicFormats;
+#ifdef HAVE_FLOAT_TEXTURES
+    }
+#endif
+
+    glTexImage2D(GL_TEXTURE_2D, 0, targetFormats[_numComponents],
+                 _width, _height, 0, 
+                 basicFormats[_numComponents], _type, data);
+
+    assert(glGetError() == 0);
+}
+
+void Texture2D::activate()
+{
+    glBindTexture(GL_TEXTURE_2D, _id);
+    glEnable(GL_TEXTURE_2D);
+}
+
+void Texture2D::deactivate()
+{
+    glDisable(GL_TEXTURE_2D);           
+}
+
+void Texture2D::setWrapS(GLuint wrapMode)
+{
+    _wrapS = wrapMode;
+}
+
+void Texture2D::setWrapT(GLuint wrapMode)
+{
+    _wrapT = wrapMode;
+}
+
+void Texture2D::checkMaxSize()
+{
+    GLint max = 0;
+    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max);
+        
+    TRACE("max texture size: %d", max);
+}
+
+void Texture2D::checkMaxUnit()
+{
+    int max = 0;
+    glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &max);
+
+    TRACE("max texture units: %d", max);
+}
Index: /nanovis/tags/1.1.4/Texture2D.h
===================================================================
--- /nanovis/tags/1.1.4/Texture2D.h	(revision 4930)
+++ /nanovis/tags/1.1.4/Texture2D.h	(revision 4930)
@@ -0,0 +1,83 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * ----------------------------------------------------------------------
+ * Texture2D.h: 2d texture class
+ *
+ * ======================================================================
+ *  AUTHOR:  Wei Qiao <qiaow@purdue.edu>
+ *           Purdue Rendering and Perceptualization Lab (PURPL)
+ *
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ *  See the file "license.terms" for information on usage and
+ *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ * ======================================================================
+ */
+#ifndef NV_TEXTURE2D_H
+#define NV_TEXTURE2D_H
+
+#include <GL/glew.h>
+
+namespace nv {
+
+class Texture2D
+{
+public:
+    Texture2D();
+
+    Texture2D(int width, int height,
+              GLuint type = GL_FLOAT,
+              GLuint interp = GL_LINEAR,
+              int numComponents = 4,
+              void *data = NULL);
+
+    ~Texture2D();
+
+    GLuint initialize(void *data);
+
+    void update(void *data);
+
+    void activate();
+
+    void deactivate();
+
+    int width() const
+    {
+        return _width;
+    }
+
+    int height() const
+    {
+        return _width;
+    }
+
+    GLuint id() const
+    {
+        return _id;
+    }
+
+    void setWrapS(GLuint wrapMode);
+
+    void setWrapT(GLuint wrapMode);
+
+    static void checkMaxSize();
+
+    static void checkMaxUnit();
+
+private:
+    int _width;
+    int _height;
+
+    int _numComponents;
+
+    bool _glResourceAllocated;
+    GLuint _id;
+    GLuint _type;
+    GLuint _interpType;
+    GLuint _wrapS;
+    GLuint _wrapT;
+};
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/Texture3D.cpp
===================================================================
--- /nanovis/tags/1.1.4/Texture3D.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/Texture3D.cpp	(revision 4930)
@@ -0,0 +1,169 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * ----------------------------------------------------------------------
+ * Texture3d.cpp: 3d texture class
+ *
+ * ======================================================================
+ *  AUTHOR:  Wei Qiao <qiaow@purdue.edu>
+ *           Purdue Rendering and Perceptualization Lab (PURPL)
+ *
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ *  See the file "license.terms" for information on usage and
+ *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ * ======================================================================
+ */
+#include <stdio.h>
+#include <assert.h>
+#include <math.h>
+
+#include "config.h"
+
+#include "Texture3D.h"
+#include "Trace.h"
+
+using namespace nv;
+
+Texture3D::Texture3D() :
+    _width(0),
+    _height(0),
+    _depth(0),
+    _numComponents(3),
+    _glResourceAllocated(false),
+    _id(0),
+    _type(GL_FLOAT),
+    _interpType(GL_LINEAR),
+    _wrapS(GL_CLAMP_TO_EDGE),
+    _wrapT(GL_CLAMP_TO_EDGE),
+    _wrapR(GL_CLAMP_TO_EDGE)
+{}
+
+Texture3D::Texture3D(int width, int height, int depth,
+                     GLuint type, GLuint interp,
+                     int numComponents, void *data) :
+    _width(width),
+    _height(height),
+    _depth(depth),
+    _numComponents(numComponents),
+    _glResourceAllocated(false),
+    _id(0),
+    _type(type),
+    _interpType(interp),
+    _wrapS(GL_CLAMP_TO_EDGE),
+    _wrapT(GL_CLAMP_TO_EDGE),
+    _wrapR(GL_CLAMP_TO_EDGE)
+{
+    if (data != NULL)
+        initialize(data);
+}
+
+Texture3D::~Texture3D()
+{
+    glDeleteTextures(1, &_id);
+}
+
+GLuint Texture3D::initialize(void *data)
+{
+    if (_glResourceAllocated)
+        glDeleteTextures(1, &_id);
+
+    glGenTextures(1, &_id);
+
+    update(data);
+
+    _glResourceAllocated = true;
+    return _id;
+}
+
+void Texture3D::update(void *data)
+{
+#ifdef USE_HALF_FLOAT
+    static GLuint halfFloatFormats[] = {
+        (GLuint)-1, GL_LUMINANCE16F_ARB, GL_LUMINANCE_ALPHA16F_ARB,
+        GL_RGB16F_ARB, GL_RGBA16F_ARB
+    };
+#elif defined(HAVE_FLOAT_TEXTURES)
+    static GLuint floatFormats[] = {
+        (GLuint)-1, GL_LUMINANCE32F_ARB, GL_LUMINANCE_ALPHA32F_ARB,
+        GL_RGB32F_ARB, GL_RGBA32F_ARB
+    };
+#endif
+    static GLuint basicFormats[] = {
+        (GLuint)-1, GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_RGB, GL_RGBA
+    };
+
+    glBindTexture(GL_TEXTURE_3D, _id);
+
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, _wrapS);
+    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, _wrapT);
+    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, _wrapR);
+
+    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, _interpType);
+    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, _interpType);
+
+    //to do: add handling to more formats
+    GLuint *targetFormats;
+#ifdef HAVE_FLOAT_TEXTURES
+    if (_type == GL_FLOAT) {
+# ifdef USE_HALF_FLOAT
+        targetFormats = halfFloatFormats;
+# else
+        targetFormats = floatFormats;
+# endif
+    } else {
+#endif
+        targetFormats = basicFormats;
+#ifdef HAVE_FLOAT_TEXTURES
+    }
+#endif
+
+    glTexImage3D(GL_TEXTURE_3D, 0, targetFormats[_numComponents],
+                 _width, _height, _depth, 0, 
+                 basicFormats[_numComponents], _type, data);
+
+    assert(glGetError()==0);
+}
+
+void Texture3D::activate()
+{
+    glEnable(GL_TEXTURE_3D);
+    glBindTexture(GL_TEXTURE_3D, _id);
+}
+
+void Texture3D::deactivate()
+{
+    glDisable(GL_TEXTURE_3D);           
+}
+
+void Texture3D::setWrapS(GLuint wrapMode)
+{
+    _wrapS = wrapMode;
+}
+
+void Texture3D::setWrapT(GLuint wrapMode)
+{
+    _wrapT = wrapMode;
+}
+
+void Texture3D::setWrapR(GLuint wrapMode)
+{
+    _wrapR = wrapMode;
+}
+
+void Texture3D::checkMaxSize()
+{
+    GLint max = 0;
+    glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE_EXT, &max);
+
+    TRACE("max 3d texture size: %d", max);
+}
+
+void Texture3D::checkMaxUnit()
+{
+    int max;
+    glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &max);
+
+    TRACE("max texture units: %d", max);
+}
Index: /nanovis/tags/1.1.4/Texture3D.h
===================================================================
--- /nanovis/tags/1.1.4/Texture3D.h	(revision 4930)
+++ /nanovis/tags/1.1.4/Texture3D.h	(revision 4930)
@@ -0,0 +1,92 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * ----------------------------------------------------------------------
+ * texture3d.h: 3d texture class
+ *
+ * ======================================================================
+ *  AUTHOR:  Wei Qiao <qiaow@purdue.edu>
+ *           Purdue Rendering and Perceptualization Lab (PURPL)
+ *
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ *  See the file "license.terms" for information on usage and
+ *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ * ======================================================================
+ */
+#ifndef NV_TEXTURE3D_H
+#define NV_TEXTURE3D_H
+
+#include <GL/glew.h>
+
+namespace nv {
+
+class Texture3D
+{
+public:
+    Texture3D();
+
+    Texture3D(int width, int height, int depth,
+              GLuint type = GL_FLOAT,
+              GLuint interp = GL_LINEAR,
+              int numComponents = 4,
+              void *data = NULL);
+
+    ~Texture3D();
+
+    GLuint initialize(void *data);
+
+    void update(void *data);
+
+    void activate();
+
+    void deactivate();
+
+    int width() const
+    {
+        return _width;
+    }
+
+    int height() const
+    {
+        return _width;
+    }
+
+    int depth() const
+    {
+        return _width;
+    }
+
+    GLuint id() const
+    {
+        return _id;
+    }
+
+    void setWrapS(GLuint wrapMode);
+
+    void setWrapT(GLuint wrapMode);
+
+    void setWrapR(GLuint wrapMode);
+
+    static void checkMaxSize();
+
+    static void checkMaxUnit();
+
+private:
+    int _width;
+    int _height;
+    int _depth;
+
+    int _numComponents;
+
+    bool _glResourceAllocated;
+    GLuint _id;
+    GLuint _type;
+    GLuint _interpType;
+    GLuint _wrapS;
+    GLuint _wrapT;
+    GLuint _wrapR;
+};
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/Trace.cpp
===================================================================
--- /nanovis/tags/1.1.4/Trace.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/Trace.cpp	(revision 4930)
@@ -0,0 +1,175 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Author: George A. Howlett <gah@purdue.edu>
+ */
+#include <stdio.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <string.h>
+
+#include <string>
+#include <sstream>
+
+#include <GL/glew.h>
+
+#include "nanovis.h"
+#include "Trace.h"
+
+using namespace nv;
+
+static std::ostringstream g_UserErrorString;
+
+#define MSG_LEN	2047
+
+/**
+ * \brief Open syslog for writing
+ */
+void
+nv::initLog()
+{
+    openlog("nanovis", LOG_CONS | LOG_PERROR | LOG_PID,  LOG_USER);
+}
+
+/**
+ * \brief Close syslog
+ */
+void
+nv::closeLog()
+{
+    closelog();
+}
+
+/**
+ * \brief Write a message to syslog
+ */
+void 
+nv::LogMessage(int priority, const char *funcname,
+               const char *path, int lineNum, const char* fmt, ...)
+{
+    char message[MSG_LEN+1];
+    const char *s;
+    int length;
+    va_list lst;
+
+    va_start(lst, fmt);
+    s = strrchr(path, '/');
+    if (s == NULL) {
+	s = path;
+    } else {
+	s++;
+    }
+    if (priority & LOG_DEBUG) {
+        length = snprintf(message, MSG_LEN, "%s:%d(%s): ", s, lineNum, funcname);
+    } else {
+        length = snprintf(message, MSG_LEN, "%s:%d: ", s, lineNum);
+    }
+    length += vsnprintf(message + length, MSG_LEN - length, fmt, lst);
+    message[MSG_LEN] = '\0';
+
+    syslog(priority, "%s", message);
+}
+
+/**
+ * \brief Write a user message to buffer
+ */
+void 
+nv::logUserMessage(const char* fmt, ...)
+{
+    char message[MSG_LEN + 1];
+    int length = 0;
+    va_list lst;
+
+    va_start(lst, fmt);
+
+    length += vsnprintf(message, MSG_LEN, fmt, lst);
+    message[MSG_LEN] = '\0';
+
+    g_UserErrorString << message << "\n";
+}
+
+std::string
+nv::getUserMessages()
+{
+    return g_UserErrorString.str();
+}
+
+void 
+nv::clearUserMessages()
+{
+    g_UserErrorString.str(std::string());
+}
+
+bool
+CheckFBO(GLenum *status) 
+{
+    *status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+    return (*status == GL_FRAMEBUFFER_COMPLETE_EXT);
+}
+
+void
+PrintFBOStatus(GLenum status, const char *prefix) 
+{
+#ifdef WANT_TRACE
+    const char *mesg;
+
+    switch(status) {
+    case GL_FRAMEBUFFER_COMPLETE_EXT:
+	mesg = "<<<< OK >>>>";						break;
+    case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
+	mesg = "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT";		break;
+    case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
+	mesg = "GL_FRAMEBUFFER_UNSUPPORTED_EXT";			break;
+    case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
+	mesg = "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT";	break;
+    case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
+	mesg = "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT";		break;
+    case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
+	mesg = "GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT";			break;
+    case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
+	mesg = "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT";		break;
+    case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
+	mesg = "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT";		break;
+    default:
+	TRACE("FB Status: %s: UNKNOWN framebuffer status %u", 
+	       prefix, (unsigned int)status);
+	return;
+    }
+    TRACE("FB Status: %s: %s", prefix, mesg);
+#endif  /*WANT_TRACE*/
+}
+
+bool
+CheckGL(const char *prefix)
+{
+    GLenum status = (GLenum)glGetError();
+    if (status == GL_NO_ERROR) {
+	return true;
+    }
+#ifdef WANT_TRACE
+    const char *mesg;                   
+
+    switch(status) {
+    case GL_INVALID_ENUM:
+	mesg = "GL_INVALID_ENUM";			break;
+    case GL_INVALID_VALUE:
+	mesg = "GL_INVALID_VALUE";			break;
+    case GL_INVALID_OPERATION:
+	mesg = "GL_INVALID_OPERATION";			break;
+    case GL_STACK_OVERFLOW:
+	mesg = "GL_STACK_OVERFLOW";			break;
+    case GL_STACK_UNDERFLOW:
+	mesg = "GL_STACK_UNDERFLOW";			break;
+    case GL_OUT_OF_MEMORY:
+	mesg = "GL_OUT_OF_MEMORY";			break;
+    case GL_INVALID_FRAMEBUFFER_OPERATION_EXT:
+	mesg = "GL_INVALID_FRAMEBUFFER_OPERATION_EXT";	break;
+    default:
+	TRACE("GL Status: %s: Unknown status %d", prefix, status);
+	return false;
+    } 
+    TRACE("GL Status: %s: %s", prefix, mesg);
+#endif
+    return false;
+}
Index: /nanovis/tags/1.1.4/Trace.h
===================================================================
--- /nanovis/tags/1.1.4/Trace.h	(revision 4930)
+++ /nanovis/tags/1.1.4/Trace.h	(revision 4930)
@@ -0,0 +1,54 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Author: George A. Howlett <gah@purdue.edu>
+ */
+
+#ifndef NV_TRACE_H
+#define NV_TRACE_H
+
+#include <string>
+
+#include <GL/glew.h>
+#include <syslog.h>
+
+#include "config.h"
+
+#define MAKE_STRING(x) #x
+#define NEWSTRING(x) MAKE_STRING(x)
+#define AT __FILE__ ":" NEWSTRING(__LINE__)
+
+namespace nv {
+
+extern void logUserMessage(const char* format, ...);
+
+extern std::string getUserMessages();
+
+extern void clearUserMessages();
+
+extern void initLog();
+
+extern void closeLog();
+
+extern void LogMessage(int priority, const char *funcname, const char *fileName,
+                       int lineNum, const char* format, ...);
+
+#define ERROR(...)	nv::LogMessage(LOG_ERR, __FUNCTION__, __FILE__, __LINE__, __VA_ARGS__)
+#ifdef WANT_TRACE
+#define TRACE(...)	nv::LogMessage(LOG_DEBUG, __FUNCTION__, __FILE__, __LINE__, __VA_ARGS__)
+#else 
+#define TRACE(...) 
+#endif
+#define WARN(...)	nv::LogMessage(LOG_WARNING, __FUNCTION__, __FILE__, __LINE__, __VA_ARGS__)
+#define INFO(...)	nv::LogMessage(LOG_INFO, __FUNCTION__, __FILE__, __LINE__, __VA_ARGS__)
+
+#define USER_ERROR(...) nv::logUserMessage(__VA_ARGS__)
+
+}
+
+extern bool CheckFBO(GLenum *status);
+extern void PrintFBOStatus(GLenum status, const char *prefix);
+extern bool CheckGL(const char *prefix);
+
+#endif
Index: /nanovis/tags/1.1.4/TransferFunction.cpp
===================================================================
--- /nanovis/tags/1.1.4/TransferFunction.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/TransferFunction.cpp	(revision 4930)
@@ -0,0 +1,104 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * ----------------------------------------------------------------------
+ * ColorMap.h: color map class contains an array of (RGBA) values 
+ *
+ * ======================================================================
+ *  AUTHOR:  Wei Qiao <qiaow@purdue.edu>
+ *           Purdue Rendering and Perceptualization Lab (PURPL)
+ *
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ *  See the file "license.terms" for information on usage and
+ *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ * ======================================================================
+ */
+
+#include <memory.h>
+#include <assert.h>
+
+#include <vrmath/Vector3f.h>
+
+#include "TransferFunction.h"
+
+using namespace nv;
+using namespace vrmath;
+
+TransferFunction::TransferFunction(const char *name, int size, float *data) :
+    _name(name)
+{
+    // _size : # of slot, 4 : rgba
+    _size = size * 4;
+    _data = new float[_size];
+    memcpy(_data, data, sizeof(float) * _size);
+
+    _tex = new Texture1D(size, GL_FLOAT, GL_LINEAR, 4, data);
+    _id = _tex->id();
+}
+
+TransferFunction::~TransferFunction()
+{ 
+    delete [] _data;
+    delete _tex; 
+}
+
+void
+TransferFunction::update(float *data)
+{
+    memcpy(_data, data, sizeof(float) * _size);
+    _tex->update(_data);
+}
+
+void
+TransferFunction::update(int size, float *data)
+{
+    // TBD..
+    //assert((size*4) == _size);
+    update(data);
+}
+
+void
+TransferFunction::sample(float fraction, float *keys, Vector3f *keyValues, int count, Vector3f *ret)
+{
+    int limit = count - 1;
+    if (fraction <= keys[0]) {
+        *ret = keyValues[0];
+    } else if (fraction >= keys[limit]) {
+        *ret = keyValues[limit];
+    } else {
+        int n;
+        for (n = 0; n < limit; n++) {
+            if (fraction >= keys[n] && fraction < keys[n+1]) break;
+        }
+        if (n >= limit) {
+            *ret = keyValues[limit];
+        } else {
+            float inter = (fraction - keys[n]) / (keys[n + 1] - keys[n]);
+            ret->set(inter * (keyValues[n + 1].x - keyValues[n].x) + keyValues[n].x,
+                     inter * (keyValues[n + 1].y - keyValues[n].y) + keyValues[n].y,
+                     inter * (keyValues[n + 1].z - keyValues[n].z) + keyValues[n].z);
+        }
+    }
+}
+
+void
+TransferFunction::sample(float fraction, float *keys, float *keyValues, int count, float *ret)
+{
+    int limit = count - 1;
+    if (fraction <= keys[0]) {
+        *ret = keyValues[0];
+    } else if (fraction >= keys[limit]) {
+        *ret = keyValues[limit];
+    } else {
+        int n;
+        for (n = 0; n < limit; n++) {
+            if (fraction >= keys[n] && fraction < keys[n+1]) break;
+        }
+        if (n >= limit) {
+            *ret = keyValues[limit];
+        } else {
+            float inter = (fraction - keys[n]) / (keys[n + 1] - keys[n]);
+            *ret = inter * (keyValues[n + 1] - keyValues[n]) + keyValues[n];
+        }
+    }
+}
Index: /nanovis/tags/1.1.4/TransferFunction.h
===================================================================
--- /nanovis/tags/1.1.4/TransferFunction.h	(revision 4930)
+++ /nanovis/tags/1.1.4/TransferFunction.h	(revision 4930)
@@ -0,0 +1,84 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * ----------------------------------------------------------------------
+ * ColorMap.h: color map class contains an array of (RGBA) values 
+ *
+ * ======================================================================
+ *  AUTHOR:  Wei Qiao <qiaow@purdue.edu>
+ *           Purdue Rendering and Perceptualization Lab (PURPL)
+ *
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ *  See the file "license.terms" for information on usage and
+ *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ * ======================================================================
+ */
+#ifndef NV_TRANSFER_FUNCTION_H
+#define NV_TRANSFER_FUNCTION_H
+
+#include <string>
+
+#include <vrmath/Vector3f.h>
+
+#include "Texture1D.h"
+
+namespace nv {
+
+class TransferFunction
+{
+public:
+    TransferFunction(const char *name, int size, float *data);
+
+    void update(float *data);
+
+    void update(int size, float *data);
+
+    GLuint id()
+    {
+        return _id;
+    }
+
+    void id(GLuint id)
+    {
+        _id = id;
+    }
+
+    Texture1D *getTexture()
+    {
+        return _tex;
+    }
+
+    float *getData()
+    { 
+        return _data; 
+    }
+
+    int getSize() const
+    {
+        return _size;
+    }
+
+    const char *name() const
+    {
+        return _name.c_str();
+    }
+
+    static void sample(float fraction, float *keys, vrmath::Vector3f *keyValues, int count, vrmath::Vector3f *ret);
+
+    static void sample(float fraction, float *keys, float *keyValues, int count, float *ret);
+
+protected :
+    ~TransferFunction();
+
+private:
+    /// the resolution of the color map, how many (RGBA) quadraples
+    int _size;
+    float *_data;
+    Texture1D *_tex;	///< the texture storing the colors 
+    std::string _name;
+    GLuint _id;		///< OpenGL texture identifier
+};
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/Unirect.cpp
===================================================================
--- /nanovis/tags/1.1.4/Unirect.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/Unirect.cpp	(revision 4930)
@@ -0,0 +1,706 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Author: George A. Howlett <gah@purdue.edu>
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <math.h>
+#include <float.h>
+#include <ctype.h> // For isspace()
+
+#include <tcl.h>
+
+#include "Command.h"
+#include "Unirect.h"
+#include "Trace.h"
+
+using namespace nv;
+
+static inline char *
+skipspaces(char *string) 
+{
+    while (isspace(*string)) {
+        string++;
+    }
+    return string;
+}
+
+static inline char *
+getline(char **stringPtr, char *endPtr) 
+{
+    char *line, *p;
+
+    line = skipspaces(*stringPtr);
+    for (p = line; p < endPtr; p++) {
+        if (*p == '\n') {
+            *p++ = '\0';
+            *stringPtr = p;
+            return line;
+        }
+    }
+    *stringPtr = p;
+    return line;
+}
+
+int
+nv::Unirect2d::parseBuffer(Tcl_Interp *interp, const char *bytes, size_t len)
+{
+    Tcl_Obj *objPtr = Tcl_NewStringObj(bytes, len);
+    Tcl_Obj **objv;
+    int objc;
+    if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    int result = loadData(interp, objc, objv);
+    Tcl_DecrRefCount(objPtr);
+    if ((result != TCL_OK) || (!isInitialized())) {
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+int
+nv::Unirect3d::parseBuffer(Tcl_Interp *interp, const char *bytes, size_t len)
+{
+    Tcl_Obj *objPtr = Tcl_NewStringObj(bytes, len);
+    Tcl_Obj **objv;
+    int objc;
+    if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    int result = loadData(interp, objc, objv);
+    Tcl_DecrRefCount(objPtr);
+    if ((result != TCL_OK) || (!isInitialized())) {
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+int 
+nv::Unirect3d::loadData(Tcl_Interp *interp, int objc, 
+                        Tcl_Obj *const *objv)
+{
+    int num[3], nValues;
+    float min[3], max[3];
+    const char *units[4];
+
+    if ((objc-1) & 0x01) {
+        Tcl_AppendResult(interp, Tcl_GetString(objv[0]), ": ",
+                "wrong # of arguments: should be key-value pairs",
+                (char *)NULL);
+        return TCL_ERROR;
+    }
+
+    /* Default order is  z, y, x. */
+    int axis1, axis2, axis3;
+    axis1 = 0; 			/* X-axis */
+    axis2 = 1; 			/* Y-axis */
+    axis3 = 2;			/* Z-axis */
+
+    num[0] = num[1] = num[2] = nValues = 0;
+    min[0] = min[1] = min[2] = max[0] = max[1] = max[2] = 0.0f;
+    units[0] = units[1] = units[2] = units[3] = NULL;
+
+    int i;
+    for (i = 1; i < objc; i += 2) {
+        const char *string;
+        char c;
+
+        string = Tcl_GetString(objv[i]);
+        c = string[0];
+        if ((c == 'x') && (strcmp(string, "xmin") == 0)) {
+            if (GetFloatFromObj(interp, objv[i+1], min+2) != TCL_OK) {
+                return TCL_ERROR;
+            }
+        } else if ((c == 'x') && (strcmp(string, "xmax") == 0)) {
+            if (GetFloatFromObj(interp, objv[i+1], max+2) != TCL_OK) {
+                return TCL_ERROR;
+            }
+        } else if ((c == 'x') && (strcmp(string, "xnum") == 0)) {
+            if (Tcl_GetIntFromObj(interp, objv[i+1], num+2) != TCL_OK) {
+                return TCL_ERROR;
+            }
+            if (num[2] <= 0) {
+                Tcl_AppendResult(interp, "bad xnum value: must be > 0",
+                     (char *)NULL);
+                return TCL_ERROR;
+            }
+        } else if ((c == 'x') && (strcmp(string, "xunits") == 0)) {
+            units[2] = Tcl_GetString(objv[i+1]);
+        } else if ((c == 'y') && (strcmp(string, "ymin") == 0)) {
+            if (GetFloatFromObj(interp, objv[i+1], min+1) != TCL_OK) {
+                return TCL_ERROR;
+            }
+        } else if ((c == 'y') && (strcmp(string, "ymax") == 0)) {
+            if (GetFloatFromObj(interp, objv[i+1], max+1) != TCL_OK) {
+                return TCL_ERROR;
+            }
+        } else if ((c == 'y') && (strcmp(string, "ynum") == 0)) {
+            if (Tcl_GetIntFromObj(interp, objv[i+1], num+1) != TCL_OK) {
+                return TCL_ERROR;
+            }
+            if (num[1] <= 0) {
+                Tcl_AppendResult(interp, "bad ynum value: must be > 0",
+                                 (char *)NULL);
+                return TCL_ERROR;
+            }
+        } else if ((c == 'y') && (strcmp(string, "yunits") == 0)) {
+            units[1] = Tcl_GetString(objv[i+1]);
+        } else if ((c == 'z') && (strcmp(string, "zmin") == 0)) {
+            if (GetFloatFromObj(interp, objv[i+1], min) != TCL_OK) {
+                return TCL_ERROR;
+            }
+        } else if ((c == 'z') && (strcmp(string, "zmax") == 0)) {
+            if (GetFloatFromObj(interp, objv[i+1], max) != TCL_OK) {
+                return TCL_ERROR;
+            }
+        } else if ((c == 'z') && (strcmp(string, "znum") == 0)) {
+            if (Tcl_GetIntFromObj(interp, objv[i+1], num) != TCL_OK) {
+                return TCL_ERROR;
+            }
+            if (num[0] <= 0) {
+                Tcl_AppendResult(interp, "bad znum value: must be > 0",
+                                 (char *)NULL);
+                return TCL_ERROR;
+            }
+        } else if ((c == 'z') && (strcmp(string, "zunits") == 0)) {
+            units[0] = Tcl_GetString(objv[i+1]);
+        } else if ((c == 'v') && (strcmp(string, "values") == 0)) {
+            Tcl_Obj **vobj;
+
+            if (Tcl_ListObjGetElements(interp, objv[i+1], &nValues, &vobj)
+                != TCL_OK) {
+                return TCL_ERROR;
+            }
+            _values = (float *)realloc(_values, sizeof(float) * nValues);
+            int j;
+            for (j = 0; j < nValues; j++) {
+                if (GetFloatFromObj(interp, vobj[j], _values + j)!=TCL_OK) {
+                    return TCL_ERROR;
+                }
+            }
+        } else if ((c == 'u') && (strcmp(string, "units") == 0)) {
+            _vUnits = strdup(Tcl_GetString(objv[i+1]));
+        } else if ((c == 'c') && (strcmp(string, "components") == 0)) {
+            int n;
+
+            if (Tcl_GetIntFromObj(interp, objv[i+1], &n) != TCL_OK) {
+                return TCL_ERROR;
+            }
+            if (n <= 0) {
+                Tcl_AppendResult(interp, "bad extents value: must be > 0",
+                                 (char *)NULL);
+                return TCL_ERROR;
+            }
+            _nComponents = n;
+        } else if ((c == 'a') && (strcmp(string, "axisorder") == 0)) {
+            Tcl_Obj **axes;
+            int n;
+
+            if (Tcl_ListObjGetElements(interp, objv[i+1], &n, &axes) 
+                != TCL_OK) {
+                return TCL_ERROR;
+            }
+            if (n != 3) {
+                return TCL_ERROR;
+            }
+            if ((GetAxisFromObj(interp, axes[0], &axis1) != TCL_OK) ||
+                (GetAxisFromObj(interp, axes[1], &axis2) != TCL_OK) ||
+                (GetAxisFromObj(interp, axes[2], &axis3) != TCL_OK)) {
+                return TCL_ERROR;
+            }
+        } else {
+            Tcl_AppendResult(interp, "unknown key \"", string,
+                (char *)NULL);
+            return TCL_ERROR;
+        }
+    }
+    if (_values == NULL) {
+        Tcl_AppendResult(interp, "missing \"values\" key", (char *)NULL);
+        return TCL_ERROR;
+    }
+    if ((size_t)nValues != (num[0] * num[1] * num[2] * _nComponents)) {
+        TRACE("num[0]=%d num[1]=%d num[2]=%d ncomponents=%d nValues=%d",
+               num[0], num[1], num[2], _nComponents, nValues);
+        Tcl_AppendResult(interp, 
+                "wrong # of values: must be xnum*ynum*znum*extents", 
+                         (char *)NULL);
+       return TCL_ERROR;
+    }
+    
+#ifdef notdef
+    if ((axis1 != 0) || (axis2 != 1) || (axis3 != 2)) {
+        // Reorder the data into x, y, z where x varies fastest and so on.
+        int z;
+        float *data, *dp;
+
+        dp = data = new float[nValues];
+        for (z = 0; z < num[0]; z++) {
+            int y;
+
+            for (y = 0; y < num[1]; y++) {
+                int x;
+
+                for (x = 0; x < num[2]; x++) {
+                    int i;
+                    
+                    /* Compute the index from the data's described ordering. */
+                    i = ((z*num[axis2]*num[axis3]) + (y*num[axis3]) + x) * 3;
+                    for(size_t v = 0; v < _nComponents; v++) {
+                        dp[v] = values[i+v];
+                    }
+                    dp += _nComponents;
+                }
+            }
+        }
+        delete [] values;
+        values = data;
+    }
+#endif
+    _nValues = nValues;
+    if (units[3] != NULL) {
+        if (_vUnits != NULL) {
+            free(_vUnits);
+        }
+        _vUnits = strdup(units[3]);
+    }
+    _xMin = min[axis3];
+    _xMax = max[axis3];
+    _xNum = num[axis3];
+    if (units[axis3] != NULL) {
+        if (_xUnits != NULL) {
+            free(_xUnits);
+        }
+        _xUnits = strdup(units[axis3]);
+    }
+    _yMin = min[axis2];
+    _yMax = max[axis2];
+    _yNum = num[axis2];
+    if (units[axis2] != NULL) {
+        if (_yUnits != NULL) {
+            free(_yUnits);
+        }
+        _yUnits = strdup(units[axis2]);
+    }
+    _zMin = min[axis1];
+    _zMax = max[axis1];
+    _zNum = num[axis1];
+    if (units[axis1] != NULL) {
+        if (_zUnits != NULL) {
+            free(_zUnits);
+        }
+        _zUnits = strdup(units[axis1]);
+    }
+    _initialized = true;
+#ifdef notdef
+    { 
+        FILE *f;
+        f = fopen("/tmp/unirect3d.txt", "w");
+        fprintf(f, "unirect3d xmin %g xmax %g xnum %d ", _xMin, _xMax, _xNum);
+        fprintf(f, "ymin %g ymax %g ynum %d ", _yMin, _yMax, _yNum);
+        fprintf(f, "zmin %g zmax %g znum %d ", _zMin, _zMax, _zNum);
+        fprintf(f, "components %d values {\n",  _nComponents);
+        for (size_t i = 0; i < _nValues; i+= 3) {
+            fprintf(f, "%g %g %g\n", _values[i], _values[i+1], _values[i+2]);
+        }
+        fprintf(f, "}\n");
+        fclose(f);
+    }
+#endif
+    return TCL_OK;
+}
+
+int 
+nv::Unirect2d::loadData(Tcl_Interp *interp, int objc, 
+                        Tcl_Obj *const *objv)
+{
+    if ((objc & 0x01) == 0) {
+        Tcl_AppendResult(interp, Tcl_GetString(objv[0]), ": ",
+                "wrong number of arguments: should be key-value pairs",
+                (char *)NULL);
+        return TCL_ERROR;
+    }
+
+    int axis[2];
+    axis[0] = 1;                         /* X-axis */
+    axis[1] = 0;			/* Y-axis */
+
+    _xNum = _yNum = _nValues = 0;
+    _xMin = _yMin = _xMax = _yMax = 0.0f;
+    if (_xUnits != NULL) {
+        free(_xUnits);
+    }
+    if (_yUnits != NULL) {
+        free(_yUnits);
+    }
+    if (_vUnits != NULL) {
+        free(_vUnits);
+    }
+    _xUnits = _yUnits = _vUnits = NULL;
+    _nValues = 0;
+
+    int i;
+    for (i = 1; i < objc; i += 2) {
+        const char *string;
+        char c;
+
+        string = Tcl_GetString(objv[i]);
+        c = string[0];
+        if ((c == 'x') && (strcmp(string, "xmin") == 0)) {
+            if (GetFloatFromObj(interp, objv[i+1], &_xMin) != TCL_OK) {
+                return TCL_ERROR;
+            }
+        } else if ((c == 'x') && (strcmp(string, "xmax") == 0)) {
+            if (GetFloatFromObj(interp, objv[i+1], &_xMax) != TCL_OK) {
+                return TCL_ERROR;
+            }
+        } else if ((c == 'x') && (strcmp(string, "xnum") == 0)) {
+            int n;
+            if (Tcl_GetIntFromObj(interp, objv[i+1], &n) != TCL_OK) {
+                return TCL_ERROR;
+            }
+            if (n <= 0) {
+                Tcl_AppendResult(interp, "bad xnum value: must be > 0",
+                     (char *)NULL);
+                return TCL_ERROR;
+            }
+            _xNum = n;
+        } else if ((c == 'x') && (strcmp(string, "xunits") == 0)) {
+            _xUnits = strdup(Tcl_GetString(objv[i+1]));
+        } else if ((c == 'y') && (strcmp(string, "ymin") == 0)) {
+            if (GetFloatFromObj(interp, objv[i+1], &_yMin) != TCL_OK) {
+                return TCL_ERROR;
+            }
+        } else if ((c == 'y') && (strcmp(string, "ymax") == 0)) {
+            if (GetFloatFromObj(interp, objv[i+1], &_yMax) != TCL_OK) {
+                return TCL_ERROR;
+            }
+        } else if ((c == 'y') && (strcmp(string, "ynum") == 0)) {
+            int n;
+            if (Tcl_GetIntFromObj(interp, objv[i+1], &n) != TCL_OK) {
+                return TCL_ERROR;
+            }
+            if (n <= 0) {
+                Tcl_AppendResult(interp, "bad ynum value: must be > 0",
+                                 (char *)NULL);
+                return TCL_ERROR;
+            }
+            _yNum = n;
+        } else if ((c == 'y') && (strcmp(string, "yunits") == 0)) {
+            _yUnits = strdup(Tcl_GetString(objv[i+1]));
+        } else if ((c == 'v') && (strcmp(string, "values") == 0)) {
+            Tcl_Obj **vobj;
+            int n;
+
+            Tcl_IncrRefCount(objv[i+1]);
+            if (Tcl_ListObjGetElements(interp, objv[i+1], &n, &vobj) != TCL_OK){
+                return TCL_ERROR;
+            }
+            if (n <= 0) {
+                Tcl_AppendResult(interp, "empty values list : must be > 0",
+                                 (char *)NULL);
+                return TCL_ERROR;
+            }
+            _nValues = n;
+            _values = (float *)realloc(_values, sizeof(float) * _nValues);
+            size_t j;
+            for (j = 0; j < _nValues; j++) {
+                if (GetFloatFromObj(interp, vobj[j], _values + j)!=TCL_OK) {
+                    return TCL_ERROR;
+                }
+            }
+            Tcl_DecrRefCount(objv[i+1]);
+        } else if ((c == 'u') && (strcmp(string, "units") == 0)) {
+            _vUnits = strdup(Tcl_GetString(objv[i+1]));
+        } else if ((c == 'c') && (strcmp(string, "components") == 0)) {
+            int n;
+
+            if (Tcl_GetIntFromObj(interp, objv[i+1], &n) != TCL_OK) {
+                return TCL_ERROR;
+            }
+            if (n <= 0) {
+                Tcl_AppendResult(interp, "bad extents value: must be > 0",
+                                 (char *)NULL);
+                return TCL_ERROR;
+            }
+            _nComponents = n;
+        } else if ((c == 'a') && (strcmp(string, "axisorder") == 0)) {
+            Tcl_Obj **order;
+            int n;
+
+            if (Tcl_ListObjGetElements(interp, objv[i+1], &n, &order) 
+                != TCL_OK) {
+                return TCL_ERROR;
+            }
+            if (n != 2) {
+                Tcl_AppendResult(interp, 
+                        "wrong # of axes defined for ordering the data",
+                        (char *)NULL);
+                return TCL_ERROR;
+            }
+            if ((GetAxisFromObj(interp, order[0], axis) != TCL_OK) ||
+                (GetAxisFromObj(interp, order[1], axis+1) != TCL_OK)) {
+                return TCL_ERROR;
+            }
+        } else {
+            Tcl_AppendResult(interp, "unknown key \"", string,
+                (char *)NULL);
+            return TCL_ERROR;
+        }
+    }
+    if (_nValues == 0) {
+        Tcl_AppendResult(interp, "missing \"values\" key", (char *)NULL);
+        return TCL_ERROR;
+    }
+    if (_nValues != (_xNum * _yNum * _nComponents)) {
+        Tcl_AppendResult(interp, 
+                "wrong number of values: must be xnum*ynum*components", 
+                         (char *)NULL);
+        return TCL_ERROR;
+    }
+    
+    if ((axis[0] != 1) || (axis[1] != 0)) {
+        TRACE("reordering data");
+        /* Reorder the data into x, y where x varies fastest and so on. */
+        size_t y;
+        float *dp;
+
+        dp = _values = (float *)realloc(_values, sizeof(float) * _nValues);
+        for (y = 0; y < _yNum; y++) {
+            size_t x;
+
+            for (x = 0; x < _xNum; x++) {
+                size_t i, v;
+                    
+                /* Compute the index from the data's described ordering. */
+                i = (y + (_yNum * x)) * _nComponents;
+                for(v = 0; v < _nComponents; v++) {
+                    dp[v] = _values[i+v];
+                }
+                dp += _nComponents;
+            }
+        }
+    }
+    _initialized = true;
+    return TCL_OK;
+}
+
+bool
+nv::Unirect3d::importDx(size_t nComponents,
+                        size_t length, char *string) 
+{
+    int nx, ny, nz, npts;
+    double x0, y0, z0, dx, dy, dz, ddx, ddy, ddz;
+    char *p, *pend;
+
+    dx = dy = dz = 0.0;			/* Suppress compiler warning. */
+    x0 = y0 = z0 = 0.0;			/* May not have an origin line. */
+    nx = ny = nz = npts = 0;		/* Suppress compiler warning. */
+    for (p = string, pend = p + length; p < pend; /*empty*/) {
+        char *line;
+
+        line = getline(&p, pend);
+        if (line == pend) {
+            break;                        /* EOF */
+        }
+        if ((line[0] == '#') || (line == '\0')) {
+            continue;                        /* Skip blank or comment lines. */
+        }
+        if (sscanf(line, "object %*d class gridpositions counts %d %d %d", 
+                   &nx, &ny, &nz) == 3) {
+            if ((nx < 0) || (ny < 0) || (nz < 0)) {
+                ERROR("invalid grid size: x=%d, y=%d, z=%d", 
+                      nx, ny, nz);
+                return false;
+            }
+        } else if (sscanf(line, "origin %lg %lg %lg", &x0, &y0, &z0) == 3) {
+            /* Found origin. */
+        } else if (sscanf(line, "delta %lg %lg %lg", &ddx, &ddy, &ddz) == 3) {
+            /* Found one of the delta lines. */
+            if (ddx != 0.0) {
+                dx = ddx;
+            } else if (ddy != 0.0) {
+                dy = ddy;
+            } else if (ddz != 0.0) {
+                dz = ddz;
+            }
+        } else if (sscanf(line, "object %*d class array type %*s shape 3"
+                " rank 1 items %d data follows", &npts) == 1) {
+            if (npts < 0) {
+                ERROR("bad # points %d", npts);
+                return false;
+            }
+            TRACE("#points=%d", npts);
+            if (npts != nx*ny*nz) {
+                ERROR("inconsistent data: expected %d points"
+                      " but found %d points", nx*ny*nz, npts);
+                return false;
+            }
+            break;
+        } else if (sscanf(line, "object %*d class array type %*s rank 0"
+                " times %d data follows", &npts) == 1) {
+            if (npts != nx*ny*nz) {
+                ERROR("inconsistent data: expected %d points"
+                      " but found %d points", nx*ny*nz, npts);
+                return false;
+            }
+            break;
+        }
+    }
+    if (npts != nx*ny*nz) {
+        ERROR("inconsistent data: expected %d points"
+              " but found %d points", nx*ny*nz, npts);
+        return false;
+    }
+
+    _initialized = false;
+    _xValueMin = _yValueMin = _zValueMin = FLT_MAX;
+    _xValueMax = _yValueMax = _zValueMax = -FLT_MAX;
+    _xMin = x0, _yMin = y0, _zMin = z0;
+    _xNum = nx, _yNum = ny, _zNum = nz;
+    _xMax = _xMin + dx * _xNum;
+    _yMax = _yMin + dy * _yNum;
+    _zMax = _zMin + dz * _zNum;
+    _nComponents = nComponents;
+
+    _values = (float *)realloc(_values, sizeof(float) * npts * _nComponents);
+    _nValues = 0;
+    for (size_t ix = 0; ix < _xNum; ix++) {
+        for (size_t iy = 0; iy < _yNum; iy++) {
+            for (size_t iz = 0; iz < _zNum; iz++) {
+                char *line;
+                if ((p == pend) || (_nValues > (size_t)npts)) {
+                    break;
+                }
+                line = getline(&p, pend);
+                if ((line[0] == '#') || (line[0] == '\0')) {
+                    continue;                /* Skip blank or comment lines. */
+                }
+                double vx, vy, vz;
+                if (sscanf(line, "%lg %lg %lg", &vx, &vy, &vz) == 3) {
+                    int nindex = (iz*nx*ny + iy*nx + ix) * 3;
+                    if (vx < _xValueMin) {
+                        _xValueMin = vx;
+                    } else if (vx > _xValueMax) {
+                        _xValueMax = vx;
+                    }
+                    if (vy < _yValueMin) {
+                        _yValueMin = vy;
+                    } else if (vy > _yValueMax) {
+                        _yValueMax = vy;
+                    }
+                    if (vz < _zValueMin) {
+                        _zValueMin = vz;
+                    } else if (vz > _zValueMax) {
+                        _zValueMax = vz;
+                    }
+                    _values[nindex] = vx;
+                    _values[nindex+1] = vy;
+                    _values[nindex+2] = vz;
+                    _nValues++;
+                }
+            }
+        }
+    }
+    /* Make sure that we read all of the expected points. */
+    if (_nValues != (size_t)npts) {
+        ERROR("inconsistent data: expected %d points"
+              " but found %d points", npts, _nValues);
+        free(_values);
+        _values = NULL;
+        return false;
+    }
+    _nValues *= _nComponents;
+    _initialized = true;
+#ifdef notdef
+    { 
+        FILE *f;
+        f = fopen("/tmp/dx.txt", "w");
+        fprintf(f, "unirect3d xmin %g xmax %g xnum %d ", _xMin, _xMax, _xNum);
+        fprintf(f, "ymin %g ymax %g ynum %d ", _yMin, _yMax, _yNum);
+        fprintf(f, "zmin %g zmax %g znum %d ", _zMin, _zMax, _zNum);
+        fprintf(f, "components %d values {\n",  _nComponents);
+        for (size_t i = 0; i < _nValues; i+= 3) {
+            fprintf(f, "%g %g %g\n", _values[i], _values[i+1], _values[i+2]);
+        }
+        fprintf(f, "}\n");
+        fclose(f);
+    }
+#endif
+    return true;
+}
+
+void
+nv::Unirect3d::getVectorRange()
+{
+    assert(_nComponents == 3);
+    _magMax = -DBL_MAX, _magMin = DBL_MAX;
+    size_t i;
+    for (i = 0; i < _nValues; i += _nComponents) {
+        double vx, vy, vz, vm;
+
+        vx = _values[i];
+        vy = _values[i+1];
+        vz = _values[i+2];
+                    
+        vm = sqrt(vx*vx + vy*vy + vz*vz);
+        if (vm > _magMax) {
+            _magMax = vm;
+        }
+        if (vm < _magMin) {
+            _magMin = vm;
+        }
+    }
+    TRACE("getVectorRange: %g %g", _magMin, _magMax);
+}
+
+bool 
+nv::Unirect3d::convert(nv::Unirect2d *dataPtr)
+{
+    _initialized = false;
+
+    _xValueMin = dataPtr->xValueMin();
+    _yValueMin = dataPtr->yValueMin();
+    _zValueMin = 0.0;
+    _xMin = dataPtr->xMin();
+    _yMin = dataPtr->yMin();
+    _zMin = 0.0;
+    _xMax = dataPtr->xMax();
+    _yMax = dataPtr->yMax();
+    _zMax = 0.0;
+    _xNum = dataPtr->xNum();
+    _yNum = dataPtr->yNum();
+    _zNum = 1;
+    switch (dataPtr->nComponents()) {
+    case 1:
+    case 3:
+        _values = (float *)realloc(_values, sizeof(float) * dataPtr->nValues());
+        if (_values == NULL) {
+            return false;
+        }
+        memcpy(_values, dataPtr->values(), dataPtr->nValues());
+        _nValues = dataPtr->nValues();
+        _nComponents = dataPtr->nComponents();
+        break;
+    case 2:
+        float *values;
+        _nValues = 3 * _xNum * _yNum * _zNum;
+        _values = (float *)realloc(_values, sizeof(float) * _nValues);
+        if (_values == NULL) {
+            return false;
+        }
+        values = dataPtr->values();
+        size_t i, j;
+        for (j = i = 0; i < dataPtr->nValues(); i += 2, j+= 3) {
+            _values[j] = values[i];
+            _values[j+1] = values[i+1];
+            _values[j+2] = 0.0f;
+        }
+        _nComponents = 3;
+        break;
+    }
+    return true;
+}
Index: /nanovis/tags/1.1.4/Unirect.h
===================================================================
--- /nanovis/tags/1.1.4/Unirect.h	(revision 4930)
+++ /nanovis/tags/1.1.4/Unirect.h	(revision 4930)
@@ -0,0 +1,409 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Author: George A. Howlett <gah@purdue.edu>
+ */
+#ifndef NV_UNIRECT_H
+#define NV_UNIRECT_H
+
+#include <float.h>
+#include <stdlib.h>
+
+#include <tcl.h>
+
+#include <vrmath/Vector3f.h>
+
+#include "Trace.h"
+
+namespace nv {
+
+class Unirect2d;
+
+class Unirect3d
+{
+public:
+    Unirect3d(float xMin, float xMax, size_t xNum,
+              float yMin, float yMax, size_t yNum,
+              float zMin, float zMax, size_t zNum,
+              size_t nValues, float *values, size_t nComponents) :
+        _xNum(xNum), _yNum(yNum), _zNum(zNum), 
+        _nValues(nValues), 
+        _nComponents(nComponents),
+        _xMin(xMin), _xMax(xMax), 
+        _yMin(yMin), _yMax(yMax), 
+        _zMin(zMin), _zMax(zMax),
+        _xValueMin(FLT_MAX), _xValueMax(-FLT_MAX),
+        _yValueMin(FLT_MAX), _yValueMax(-FLT_MAX),
+        _zValueMin(FLT_MAX), _zValueMax(-FLT_MAX),
+        _magMin(DBL_MAX), _magMax(-DBL_MAX),
+        _xUnits(NULL), _yUnits(NULL), _zUnits(NULL), _vUnits(NULL),
+        _values(NULL),
+        _initialized(false)
+    {
+        _initialized = true;
+    }
+
+    Unirect3d(size_t nComponents = 1) :
+        _nValues(0), 
+        _nComponents(nComponents),
+        _xValueMin(FLT_MAX), _xValueMax(-FLT_MAX),
+        _yValueMin(FLT_MAX), _yValueMax(-FLT_MAX),
+        _zValueMin(FLT_MAX), _zValueMax(-FLT_MAX),
+        _magMin(DBL_MAX), _magMax(-DBL_MAX),
+        _xUnits(NULL), _yUnits(NULL), _zUnits(NULL), _vUnits(NULL),
+        _values(NULL),
+        _initialized(false)
+    {
+        _nComponents = nComponents;
+    }
+
+    ~Unirect3d()
+    {
+        if (_values != NULL) {
+            free(_values);
+        }
+        if (_xUnits != NULL) {
+            free(_xUnits);
+        }
+        if (_yUnits != NULL) {
+            free(_yUnits);
+        }
+        if (_zUnits != NULL) {
+            free(_zUnits);
+        }
+        if (_vUnits != NULL) {
+            free(_vUnits);
+        }
+    }
+
+    size_t xNum()
+    {
+        return _xNum;
+    }
+
+    size_t yNum()
+    {
+        return _yNum;
+    }
+
+    size_t zNum()
+    {
+        return _zNum;
+    }
+
+    float xMin()
+    {
+        return _xMin;
+    }
+
+    float yMin()
+    {
+        return _yMin;
+    }
+
+    float zMin()
+    {
+        return _zMin;
+    }
+
+    float xMax()
+    {
+        return _xMax;
+    }
+
+    float yMax()
+    {
+        return _yMax;
+    }
+
+    float zMax()
+    {
+        return _zMax;
+    }
+
+    float xValueMin()
+    {
+        return _xValueMin;
+    }
+
+    float yValueMin()
+    {
+        return _yValueMin;
+    }
+
+    float zValueMin()
+    {
+        return _zValueMin;
+    }
+
+    float xValueMax()
+    {
+        return _xValueMax;
+    }
+
+    float yValueMax()
+    {
+        return _yValueMax;
+    }
+
+    float zValueMax()
+    {
+        return _zValueMax;
+    }
+
+    size_t nComponents()
+    {
+        return _nComponents;
+    }
+
+    const char *xUnits()
+    {
+        return _xUnits;
+    }
+
+    const char *yUnits()
+    {
+        return _yUnits;
+    }
+    const char *zUnits()
+    {
+        return _zUnits;
+    }
+
+    const char *vUnits()
+    {
+        return _vUnits;
+    }
+
+    const float *values()
+    {
+        return _values;
+    }
+
+    double magMin()
+    {
+        if (_magMin == DBL_MAX) {
+            getVectorRange();
+        }
+        return _magMin;
+    }
+
+    double magMax()
+    {
+        if (_magMax == -DBL_MAX) {
+            getVectorRange();
+        }
+        return _magMax;
+    }
+
+    void getBounds(vrmath::Vector3f& bboxMin,
+                   vrmath::Vector3f& bboxMax) const
+    {
+        bboxMin.set(_xMin, _yMin, _zMin);
+        bboxMax.set(_xMax, _yMax, _zMax);
+    }
+
+    const float *SaveValues()
+    {
+        float *values;
+        values = _values;
+        _values = NULL;
+        _nValues = 0;
+        return values;
+    }
+
+    size_t nValues()
+    {
+        return _nValues;
+    }
+
+    int loadData(Tcl_Interp *interp, int objc, Tcl_Obj *const *objv);
+
+    int parseBuffer(Tcl_Interp *interp, const char *bytes, size_t len);
+
+    bool importDx(size_t nComponents, size_t length, char *string);
+
+    bool convert(Unirect2d *dataPtr);
+
+    bool isInitialized()
+    {
+        return _initialized;
+    }
+
+private:
+    void getVectorRange();
+
+    size_t _xNum, _yNum, _zNum;
+    size_t _nValues;
+    size_t _nComponents;
+    float _xMin, _xMax, _yMin, _yMax, _zMin, _zMax;
+    float _xValueMin, _xValueMax;
+    float _yValueMin, _yValueMax;
+    float _zValueMin, _zValueMax;
+    double _magMin, _magMax;                /* Range of magnitudes of vector
+                                             * data. */
+    char *_xUnits;
+    char *_yUnits;
+    char *_zUnits;
+    char *_vUnits;
+
+    float *_values;
+    bool _initialized;
+};
+
+class Unirect2d
+{
+public:
+    Unirect2d(size_t nComponents = 1) :
+        _xNum(0), _yNum(0),
+        _nValues(0),
+        _nComponents(nComponents),
+        _xUnits(NULL), _yUnits(NULL), _vUnits(NULL),
+        _values(NULL),
+        _initialized(false)
+    {
+    }
+
+    ~Unirect2d()
+    {
+        if (_values != NULL) {
+            free(_values);
+        }
+        if (_xUnits != NULL) {
+            free(_xUnits);
+        }
+        if (_yUnits != NULL) {
+            free(_yUnits);
+        }
+        if (_vUnits != NULL) {
+            free(_vUnits);
+        }
+    }
+
+    size_t xNum()
+    {
+        return _xNum;
+    }
+
+    size_t yNum()
+    {
+        return _yNum;
+    }
+
+    float xMin()
+    {
+        return _xMin;
+    }
+
+    float yMin()
+    {
+        return _yMin;
+    }
+
+    float xMax()
+    {
+        return _xMax;
+    }
+
+    float yMax()
+    {
+        return _yMax;
+    }
+
+    const char *xUnits()
+    {
+        return _xUnits;
+    }
+
+    const char *yUnits()
+    {
+        return _yUnits;
+    }
+
+    const char *vUnits()
+    {
+        return _vUnits;
+    }
+
+    float *values()
+    {
+        return _values;
+    }
+
+    float xValueMin()
+    {
+        return _xValueMin;
+    }
+
+    float yValueMin()
+    {
+        return _yValueMin;
+    }
+
+    float xValueMax()
+    {
+        return _xValueMax;
+    }
+
+    float yValueMax()
+    {
+        return _yValueMax;
+    }
+
+    size_t nComponents()
+    {
+        return _nComponents;
+    }
+
+    void getBounds(vrmath::Vector3f& bboxMin,
+                   vrmath::Vector3f& bboxMax) const
+    {
+        bboxMin.set(_xMin, _yMin, 0);
+        bboxMax.set(_xMax, _yMax, 0);
+    }
+
+    float *transferValues()
+    {
+        float *values;
+        values = _values;
+        _values = NULL;
+        _nValues = 0;
+        return values;
+    }
+
+    size_t nValues()
+    {
+        return _nValues;
+    }
+
+    int loadData(Tcl_Interp *interp, int objc, Tcl_Obj *const *objv);
+
+    int parseBuffer(Tcl_Interp *interp, const char *bytes, size_t len);
+
+    bool isInitialized()
+    {
+        return _initialized;
+    }
+
+private:
+    size_t _xNum, _yNum;
+    size_t _nValues;
+    size_t _nComponents;
+
+    float _xMin, _xMax;
+    float _yMin, _yMax;
+    float _xValueMin, _xValueMax;
+    float _yValueMin, _yValueMax;
+
+    char *_xUnits;
+    char *_yUnits;
+    char *_vUnits;
+
+    float *_values;
+    bool _initialized;
+};
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/VelocityArrowsSlice.cpp
===================================================================
--- /nanovis/tags/1.1.4/VelocityArrowsSlice.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/VelocityArrowsSlice.cpp	(revision 4930)
@@ -0,0 +1,586 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+
+#include <math.h>
+
+#include <GL/glew.h>
+#include <GL/gl.h>
+
+#include <vrmath/Vector3f.h>
+#include <util/FilePath.h>
+#include <Image.h>
+#include <ImageLoaderFactory.h>
+#include <ImageLoader.h>
+
+#include "nanovis.h"
+#include "VelocityArrowsSlice.h"
+#include "Shader.h"
+#include "Camera.h"
+
+using namespace nv;
+using namespace nv::util;
+using namespace vrmath;
+
+static inline float deg2rad(float deg)
+{
+    return ((deg * M_PI) / 180.);
+}
+
+static inline float rad2deg(float rad)
+{
+    return ((rad * 180.) / M_PI);
+}
+
+VelocityArrowsSlice::VelocityArrowsSlice() :
+    _vectorFieldGraphicsID(0),
+    _slicePos(0.5f),
+    _axis(AXIS_Z),
+    _fbo(0),
+    _tex(0),
+    _maxPointSize(1.0f),
+    _renderTargetWidth(128),
+    _renderTargetHeight(128),
+    _velocities(NULL),
+    _projectionVector(1, 1, 0),
+    _tickCountForMinSizeAxis(10),
+    _tickCountX(0),
+    _tickCountY(0),
+    _tickCountZ(0),
+    _pointCount(0),
+    _maxVelocityScale(1, 1, 1),
+    _arrowColor(1, 1, 0),
+    _visible(false),
+    _dirty(true),
+    _vertexBufferGraphicsID(0),
+    _arrowsTex(NULL),
+    _renderMode(LINES)
+{
+    setSliceAxis(_axis);
+
+    _queryVelocityFP.loadFragmentProgram("queryvelocity.cg");
+
+    _particleShader.loadVertexProgram("velocityslicevp.cg");
+    _particleShader.loadFragmentProgram("velocityslicefp.cg");
+
+    createRenderTarget();
+
+    std::string path = FilePath::getInstance()->getPath("arrows.bmp");
+    if (!path.empty()) {
+        ImageLoader *loader = ImageLoaderFactory::getInstance()->createLoader("bmp");
+        if (loader != NULL) {
+            Image *image = loader->load(path.c_str(), Image::IMG_RGBA);
+            if (image != NULL) {
+                unsigned char *bytes = (unsigned char *)image->getImageBuffer();
+                if (bytes != NULL) {
+                    _arrowsTex = new Texture2D(image->getWidth(), image->getHeight(),
+                                               GL_UNSIGNED_BYTE, GL_LINEAR, 4, NULL);
+                    _arrowsTex->setWrapS(GL_MIRRORED_REPEAT);
+                    _arrowsTex->setWrapT(GL_MIRRORED_REPEAT);
+                    _arrowsTex->initialize(image->getImageBuffer());
+                }
+                delete image;
+            } else {
+                ERROR("Failed to load arrows image");
+            }
+            delete loader;
+        } else {
+            ERROR("Couldn't find loader for arrows image");
+        }
+    } else {
+        ERROR("Couldn't find arrows image");
+    }
+
+    GLfloat minMax[2];
+    glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, minMax);
+    TRACE("Aliased point size range: %g %g", minMax[0], minMax[1]);
+    _maxPointSize = minMax[1];
+    glGetFloatv(GL_SMOOTH_POINT_SIZE_RANGE, minMax);
+    TRACE("Smooth point size range: %g %g", minMax[0], minMax[1]);
+    _maxPointSize = minMax[1] > _maxPointSize ? minMax[1] : _maxPointSize;
+    TRACE("Max point size: %g", _maxPointSize);
+
+    TRACE("Leaving VelocityArrowsSlice constructor");
+}
+
+VelocityArrowsSlice::~VelocityArrowsSlice()
+{
+    if (_tex != 0) {
+        glDeleteTextures(1, &_tex);
+    }
+    if (_fbo != 0) {
+        glDeleteFramebuffersEXT(1, &_fbo);
+    }
+    if (_arrowsTex != NULL) {
+        delete _arrowsTex;
+    }
+    if (_vertexBufferGraphicsID != 0) {
+        glDeleteBuffers(1, &_vertexBufferGraphicsID);
+    }
+    if (_velocities != NULL) {
+        delete [] _velocities;
+    }
+}
+
+void VelocityArrowsSlice::createRenderTarget()
+{
+    if (_velocities != NULL) {
+        delete [] _velocities;
+    }
+    _velocities = new Vector3f[_renderTargetWidth * _renderTargetHeight];
+
+    if (_vertexBufferGraphicsID != 0) {
+        glDeleteBuffers(1, &_vertexBufferGraphicsID);
+    }
+
+    glGenBuffers(1, &_vertexBufferGraphicsID);
+    glBindBufferARB(GL_ARRAY_BUFFER_ARB, _vertexBufferGraphicsID);
+    glBufferDataARB(GL_ARRAY_BUFFER_ARB, _renderTargetWidth * _renderTargetHeight * 3 * sizeof(float), 
+                    0, GL_DYNAMIC_DRAW_ARB);
+    glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
+
+    if (_tex != 0) {
+        glDeleteTextures(1, &_tex);
+    }
+    if (_fbo != 0) {
+        glDeleteFramebuffersEXT(1, &_fbo);
+    }
+
+    glGenFramebuffersEXT(1, &_fbo);
+    glGenTextures(1, &_tex);
+    int fboOrig;
+    glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &fboOrig);
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _fbo);
+
+    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _tex);
+    glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+    glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA32F_ARB, 
+                 _renderTargetWidth, _renderTargetHeight, 0,
+                 GL_RGBA, GL_FLOAT, NULL);
+
+    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, 
+                              GL_TEXTURE_RECTANGLE_ARB, _tex, 0);
+
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboOrig);
+}
+
+void VelocityArrowsSlice::setSliceAxis(FlowSliceAxis axis)
+{
+    _axis = axis;
+    switch (_axis) {
+    case AXIS_X:
+        _projectionVector.x = 0;
+        _projectionVector.y = 1;
+        _projectionVector.z = 1;
+        break;
+    case AXIS_Y:
+        _projectionVector.x = 1;
+        _projectionVector.y = 0;
+        _projectionVector.z = 1;
+        break;
+    case AXIS_Z:
+        _projectionVector.x = 1;
+        _projectionVector.y = 1;
+        _projectionVector.z = 0;
+        break;
+    }
+    _dirty = true;
+}
+
+void VelocityArrowsSlice::queryVelocity()
+{
+    glPushAttrib(GL_VIEWPORT_BIT | GL_ENABLE_BIT);
+    int fboOrig;
+    glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &fboOrig);
+
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _fbo);
+
+    _queryVelocityFP.bind();
+    _queryVelocityFP.setFPTextureParameter("vfield", _vectorFieldGraphicsID);
+
+    glDisable(GL_DEPTH_TEST);
+    glViewport(0, 0, _renderTargetWidth, _renderTargetHeight);
+    glMatrixMode(GL_PROJECTION);
+    glPushMatrix();
+    glLoadIdentity();
+    glOrtho(0, _renderTargetWidth, 0, _renderTargetHeight, -10.0f, 10.0f);
+    glMatrixMode(GL_MODELVIEW);
+    glPushMatrix();
+    glLoadIdentity();
+
+    glBegin(GL_QUADS);
+    switch (_axis) {
+    case AXIS_X:
+        glTexCoord3f(_slicePos, 0, 0); glVertex2i(0,                  0);
+        glTexCoord3f(_slicePos, 1, 0); glVertex2i(_renderTargetWidth, 0);
+        glTexCoord3f(_slicePos, 1, 1); glVertex2i(_renderTargetWidth, _renderTargetHeight);
+        glTexCoord3f(_slicePos, 0, 1); glVertex2i(0,                  _renderTargetHeight);
+        break;
+    case AXIS_Y:
+        glTexCoord3f(0, _slicePos, 0); glVertex2i(0,                  0);
+        glTexCoord3f(1, _slicePos, 0); glVertex2i(_renderTargetWidth, 0);
+        glTexCoord3f(1, _slicePos, 1); glVertex2i(_renderTargetWidth, _renderTargetHeight);
+        glTexCoord3f(0, _slicePos, 1); glVertex2i(0,                  _renderTargetHeight);
+        break;
+    case AXIS_Z:
+    default:
+        glTexCoord3f(0, 0, _slicePos); glVertex2i(0,                  0);
+        glTexCoord3f(1, 0, _slicePos); glVertex2i(_renderTargetWidth, 0);
+        glTexCoord3f(1, 1, _slicePos); glVertex2i(_renderTargetWidth, _renderTargetHeight);
+        glTexCoord3f(0, 1, _slicePos); glVertex2i(0,                  _renderTargetHeight);
+        break;
+    }
+    glEnd();
+
+    _queryVelocityFP.disableFPTextureParameter("vfield");
+    _queryVelocityFP.unbind();
+
+    glReadPixels(0, 0, _renderTargetWidth, _renderTargetHeight, GL_RGB, GL_FLOAT, _velocities);
+
+    glMatrixMode(GL_PROJECTION);
+    glPopMatrix();
+    glMatrixMode(GL_MODELVIEW);
+    glPopMatrix();
+
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboOrig);
+
+    glPopAttrib();
+}
+
+static void drawLineArrow(FlowSliceAxis axis)
+{
+    glBegin(GL_LINES);
+    switch (axis) {
+    case AXIS_X: // ZY plane
+        glVertex3f(0.0, 0.0, 0.0);
+        glVertex3f(0.0, 0.0, 1.0);
+
+        glVertex3f(0.0, 0.0, 1.0);
+        glVertex3f(0.0, 0.25, 0.75);
+
+        glVertex3f(0.0, 0.0, 1.0);
+        glVertex3f(0.0, -0.25, 0.75);
+        break;
+    case AXIS_Y: // XZ plane
+        glVertex3f(0.0, 0.0, 0.0);
+        glVertex3f(1.0, 0.0, 0.0);
+
+        glVertex3f(1.0, 0.0, 0.0);
+        glVertex3f(0.75, 0.0, 0.25);
+
+        glVertex3f(1.0, 0.0, 0.0);
+        glVertex3f(0.75, 0.0, -0.25);
+        break;
+    case AXIS_Z: // XY plane
+    default:
+        glVertex3f(0.0, 0.0, 0.0);
+        glVertex3f(1.0, 0.0, 0.0);
+
+        glVertex3f(1.0, 0.0, 0.0);
+        glVertex3f(0.75, 0.25, 0.0);
+
+        glVertex3f(1.0, 0.0, 0.0);
+        glVertex3f(0.75, -0.25, 0.0);
+        break;
+    }
+    glEnd();
+}
+
+void VelocityArrowsSlice::render()
+{
+    if (!_visible)
+        return;
+
+    if (_dirty) {
+        computeSamplingTicks();
+        queryVelocity();
+        _dirty = false;
+    }
+
+    TRACE("_scale: %g %g %g", _scale.x, _scale.y, _scale.z);
+    TRACE("_maxVelocityScale: %g %g %g",
+          _maxVelocityScale.x, _maxVelocityScale.y, _maxVelocityScale.z);
+
+    glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+    glMatrixMode(GL_MODELVIEW);
+    glPushMatrix();
+
+    glScalef(_scale.x, _scale.y, _scale.z);
+    glTranslatef(-0.5f, -0.5f, -0.5f);
+
+    if (_renderMode == LINES) {
+        glDisable(GL_TEXTURE_2D);
+        glDisable(GL_LIGHTING);
+        glLineWidth(2.0);
+        glColor3f(_arrowColor.x, _arrowColor.y, _arrowColor.z);
+ 
+        Vector3f pos;
+        Vector3f vel;
+        Vector3f refVec;
+        Vector3f blue(0, 0, 1);
+        Vector3f red(1, 0, 0);
+
+        int index = 0, icount, jcount;
+        switch (_axis) {
+        case AXIS_X:
+            icount = _tickCountZ;
+            jcount = _tickCountY;
+            refVec.set(0, 0, 1);
+            break;
+        case AXIS_Y:
+            icount = _tickCountZ;
+            jcount = _tickCountX;
+            refVec.set(1, 0, 0);
+            break;
+        case AXIS_Z:
+        default:
+            icount = _tickCountY;
+            jcount = _tickCountX;
+            refVec.set(1, 0, 0);
+            break;
+        }
+
+        for (int i = 0; i < icount; ++i) {
+            for (int j = 0; j < jcount; ++j, ++index) {
+                pos = _samplingPositions[index];
+                // Normalized velocity: [-1,1] components
+                // Project 3D vector onto sample plane
+                vel = _velocities[index].scale(_projectionVector);
+                // Length: [0,1]
+                double length = vel.length();
+                if (length < 0.0 || length > 1.0) {
+                    TRACE("***vec: (%g, %g, %g) length: %g***", vel.x, vel.y, vel.z, length);
+                    continue;
+                }
+                if (length > 0.0) {
+                    Vector3f vnorm = vel.normalize();
+                    Vector3f rotationAxis = refVec.cross(vnorm);
+                    double angle = rad2deg(acos(refVec.dot(vnorm)));
+                    Vector3f color = blue * (1.0 - length) + red * length;
+                    float scale = length;
+                    if (scale < 0.10) scale = 0.10;
+                    glMatrixMode(GL_MODELVIEW);
+                    glPushMatrix();
+                    glColor3f(color.x, color.y, color.z);
+                    glTranslatef(pos.x, pos.y, pos.z);
+                    glScalef(2.0 * _maxVelocityScale.x,
+                             2.0 * _maxVelocityScale.y,
+                             2.0 * _maxVelocityScale.z);
+                    glScalef(scale, scale, scale);
+                    if (angle > 1.0e-6 || angle < -1.0e-6)
+                        glRotated(angle, rotationAxis.x, rotationAxis.y, rotationAxis.z);
+                    drawLineArrow(_axis);
+                    glPopMatrix();
+                }
+            }
+        }
+
+        glLineWidth(1.0);
+    } else {
+        glColor4f(_arrowColor.x, _arrowColor.y, _arrowColor.z, 1.0f);
+        glEnable(GL_DEPTH_TEST);
+        glDisable(GL_LIGHTING);
+#if 0
+        glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+        glEnable(GL_BLEND);
+        glDepthMask(GL_FALSE);
+#else
+        glDisable(GL_BLEND);
+#endif
+        glAlphaFunc(GL_GREATER, 0.6);
+        glEnable(GL_ALPHA_TEST);
+        glEnable(GL_POINT_SPRITE_ARB);
+        glPointSize(20);
+        glEnable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB);
+
+        _arrowsTex->activate();
+        glEnable(GL_TEXTURE_2D);
+        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+        GLfloat atten[] = {1, 0, 0};
+        glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, atten);
+        glPointParameterfARB(GL_POINT_FADE_THRESHOLD_SIZE_ARB, 0.0f);
+        glPointParameterfARB(GL_POINT_SIZE_MIN_ARB, 1.0f);
+        glPointParameterfARB(GL_POINT_SIZE_MAX_ARB, _maxPointSize);
+        glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
+
+        _particleShader.bind();
+        _particleShader.setVPTextureParameter("vfield", _vectorFieldGraphicsID);
+        _particleShader.setFPTextureParameter("arrows", _arrowsTex->id());
+        _particleShader.setVPParameter1f("tanHalfFOV",
+                                         tan(NanoVis::getCamera()->getFov() * 0.5) * NanoVis::winHeight * 0.5);
+        _particleShader.setGLStateMatrixVPParameter("modelview",
+                                                    Shader::MODELVIEW_MATRIX,
+                                                    Shader::MATRIX_IDENTITY);
+        _particleShader.setGLStateMatrixVPParameter("mvp",
+                                                    Shader::MODELVIEW_PROJECTION_MATRIX,
+                                                    Shader::MATRIX_IDENTITY);
+
+        glEnableClientState(GL_VERTEX_ARRAY);
+        glBindBufferARB(GL_ARRAY_BUFFER_ARB, _vertexBufferGraphicsID);
+        glVertexPointer(3, GL_FLOAT, 0, 0);
+        //glEnableClientState(GL_COLOR_ARRAY);
+
+        // TBD..
+        glDrawArrays(GL_POINTS, 0, _pointCount);
+        glPointSize(1);
+
+        glDisableClientState(GL_VERTEX_ARRAY);
+        glDisable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB);
+        glDisable(GL_POINT_SPRITE_ARB);
+
+        _particleShader.disableVPTextureParameter("vfield");
+        _particleShader.disableFPTextureParameter("arrows");
+        _particleShader.unbind();
+
+        glActiveTexture(GL_TEXTURE0);
+        glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_FALSE);
+        _arrowsTex->deactivate();
+    }
+
+    glPopMatrix();
+    glPopAttrib();
+}
+
+void 
+VelocityArrowsSlice::setVectorField(unsigned int vfGraphicsID, const Vector3f& origin,
+                                    float xScale, float yScale, float zScale, float max)
+{
+    _vectorFieldGraphicsID = vfGraphicsID;
+    _scale.set(xScale, yScale, zScale);
+
+    _dirty = true;
+}
+
+void VelocityArrowsSlice::computeSamplingTicks()
+{
+    if (_scale.x < _scale.y) {
+        if (_scale.x < _scale.z || _scale.z == 0.0) {
+            // _scale.x
+            _tickCountX = _tickCountForMinSizeAxis;
+
+            float step = _scale.x / (_tickCountX + 1);
+            _tickCountY = (int)(_scale.y/step);
+            _tickCountZ = (int)(_scale.z/step);
+        } else {
+            // _scale.z
+            _tickCountZ = _tickCountForMinSizeAxis;
+
+            float step = _scale.z / (_tickCountZ + 1);
+            _tickCountX = (int)(_scale.x/step);
+            _tickCountY = (int)(_scale.y/step);
+        }
+    } else {
+        if (_scale.y < _scale.z || _scale.z == 0.0) {
+            // _scale.y
+            _tickCountY = _tickCountForMinSizeAxis;
+
+            float step = _scale.y / (_tickCountY + 1);
+            _tickCountX = (int)(_scale.x/step);
+            _tickCountZ = (int)(_scale.z/step);
+        } else {
+            // _scale.z
+            _tickCountZ = _tickCountForMinSizeAxis;
+
+            float step = _scale.z / (_tickCountZ + 1);
+            _tickCountX = (int)(_scale.x/step);
+            _tickCountY = (int)(_scale.y/step);
+        }
+    }
+
+    switch (_axis) {
+    case AXIS_X:
+        _tickCountX = 1;
+        _renderTargetWidth = _tickCountY;
+        _renderTargetHeight = _tickCountZ;
+        break;
+    case AXIS_Y:
+        _tickCountY = 1;
+        _renderTargetWidth = _tickCountX;
+        _renderTargetHeight = _tickCountZ;
+        break;
+    default:
+    case AXIS_Z:
+        _tickCountZ = 1;
+        _renderTargetWidth = _tickCountX;
+        _renderTargetHeight = _tickCountY;
+        break;
+    }
+
+    _maxVelocityScale.x = (1.0f / _tickCountX) * 0.8f;
+    _maxVelocityScale.y = (1.0f / _tickCountY) * 0.8f;
+    _maxVelocityScale.z = (1.0f / _tickCountZ) * 0.8f;
+
+    TRACE("Tick counts: %d %d %d", _tickCountX, _tickCountY, _tickCountZ);
+
+    int pointCount = _tickCountX * _tickCountY * _tickCountZ;
+    if (_pointCount != pointCount) {
+        _samplingPositions.clear();
+        _samplingPositions.reserve(pointCount);
+        _pointCount = pointCount;
+    }
+
+    createRenderTarget();
+
+    Vector3f pos;
+    Vector3f *pinfo = NULL;
+    if (_renderMode == GLYPHS) {
+        glBindBufferARB(GL_ARRAY_BUFFER_ARB, _vertexBufferGraphicsID);
+        pinfo = (Vector3f *)glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+    }
+
+    if (_axis == AXIS_Z) {
+        for (int y = 1; y <= _tickCountY; ++y) {
+            for (int x = 1; x <= _tickCountX; ++x) {
+                pos.x = (1.0f / (_tickCountX + 1)) * x;
+                pos.y = (1.0f / (_tickCountY + 1)) * y;
+                pos.z = _slicePos;
+                if (_renderMode == LINES) {
+                    _samplingPositions.push_back(pos);
+                } else {
+                    *pinfo = pos;
+                    ++pinfo;
+                }
+            }
+        }
+    } else if (_axis == AXIS_Y) {
+        for (int z = 1; z <= _tickCountZ; ++z) {
+            for (int x = 1; x <= _tickCountX; ++x) {
+                pos.x = (1.0f / (_tickCountX + 1)) * x;
+                pos.y = _slicePos;
+                pos.z = (1.0f / (_tickCountZ + 1)) * z;
+                if (_renderMode == LINES) {
+                    _samplingPositions.push_back(pos);
+                } else {
+                    *pinfo = pos;
+                    ++pinfo;
+                }
+            }
+        }
+    } else if (_axis == AXIS_X) {
+        for (int z = 1; z <= _tickCountZ; ++z) {
+            for (int y = 1; y <= _tickCountY; ++y) {
+                pos.x = _slicePos;
+                pos.y = (1.0f / (_tickCountY + 1)) * y;
+                pos.z = (1.0f / (_tickCountZ + 1)) * z;
+                if (_renderMode == LINES) {
+                    _samplingPositions.push_back(pos);
+                } else {
+                    *pinfo = pos;
+                    ++pinfo;
+                }
+            }
+        }
+    }
+
+    if (_renderMode == GLYPHS) {
+        glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
+    }
+}
Index: /nanovis/tags/1.1.4/VelocityArrowsSlice.h
===================================================================
--- /nanovis/tags/1.1.4/VelocityArrowsSlice.h	(revision 4930)
+++ /nanovis/tags/1.1.4/VelocityArrowsSlice.h	(revision 4930)
@@ -0,0 +1,140 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#ifndef NV_VELOCITY_ARROW_SLICE_H
+#define NV_VELOCITY_ARROW_SLICE_H
+
+#include <vector>
+
+#include <vrmath/Vector3f.h>
+
+#include "FlowTypes.h"
+#include "Texture2D.h"
+#include "Shader.h"
+
+namespace nv {
+
+class VelocityArrowsSlice
+{
+public:
+    enum RenderMode {
+        LINES,
+        GLYPHS,
+    };
+
+    VelocityArrowsSlice();
+
+    ~VelocityArrowsSlice();
+
+    void setVectorField(unsigned int vfGraphicsID, const vrmath::Vector3f& origin,
+                        float xScale, float yScale, float zScale, float max);
+
+    void setSliceAxis(FlowSliceAxis axis);
+
+    int getSliceAxis() const
+    {
+        return _axis;
+    }
+
+    void setSlicePosition(float pos)
+    {
+        _slicePos = pos;
+        _dirty = true;
+    }
+
+    float getSlicePosition() const
+    {
+        return _slicePos;
+    }
+
+    void render();
+
+    void visible(bool visible)
+    {
+        _visible = visible;
+    }
+
+    bool visible() const
+    {
+        return _visible;
+    }
+
+    void tickCountForMinSizeAxis(int tickCount)
+    {
+        _tickCountForMinSizeAxis = tickCount;
+    }
+
+    int tickCountForMinSizeAxis() const
+    {
+        return _tickCountForMinSizeAxis;
+    }
+
+    void arrowColor(const vrmath::Vector3f& color)
+    {
+        _arrowColor = color;
+    }
+
+    void renderMode(RenderMode mode)
+    {
+        _renderMode = mode;
+        _dirty = true;
+    }
+
+    RenderMode renderMode() const
+    {
+        return _renderMode;
+    }
+
+private:
+    void queryVelocity();
+
+    void createRenderTarget();
+
+    void computeSamplingTicks();
+
+    unsigned int _vectorFieldGraphicsID;
+    vrmath::Vector3f _scale;
+
+    float _slicePos;
+    FlowSliceAxis _axis;
+
+    unsigned int _fbo;
+    unsigned int _tex;
+    float _maxPointSize;
+
+    Shader _queryVelocityFP;
+    Shader _particleShader;
+
+    int _renderTargetWidth;
+    int _renderTargetHeight;
+    vrmath::Vector3f *_velocities;
+    std::vector<vrmath::Vector3f> _samplingPositions;
+    vrmath::Vector3f _projectionVector;
+
+    int _tickCountForMinSizeAxis;
+    int _tickCountX;
+    int _tickCountY;
+    int _tickCountZ;
+
+    int _pointCount;
+
+    vrmath::Vector3f _maxVelocityScale;
+    vrmath::Vector3f _arrowColor;
+
+    bool _visible;
+    bool _dirty;
+    bool _dirtySamplingPosition;
+    bool _dirtyRenderTarget;
+
+    unsigned int _vertexBufferGraphicsID;
+
+    Texture2D *_arrowsTex;
+
+    RenderMode _renderMode;
+};
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/Volume.cpp
===================================================================
--- /nanovis/tags/1.1.4/Volume.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/Volume.cpp	(revision 4930)
@@ -0,0 +1,134 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * ----------------------------------------------------------------------
+ * Volume.cpp: 3d volume class
+ *
+ * ======================================================================
+ *  AUTHOR:  Wei Qiao <qiaow@purdue.edu>
+ *           Purdue Rendering and Perceptualization Lab (PURPL)
+ *
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ *  See the file "license.terms" for information on usage and
+ *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ * ======================================================================
+ */
+#include <memory.h>
+#include <assert.h>
+#include <float.h>
+
+#include <vrmath/Vector4f.h>
+#include <vrmath/Matrix4x4d.h>
+
+#include "Volume.h"
+#include "Trace.h"
+
+using namespace nv;
+using namespace vrmath;
+
+bool Volume::updatePending = false;
+double Volume::valueMin = 0.0;
+double Volume::valueMax = 1.0;
+
+Volume::Volume(float x, float y, float z,
+               int width, int height, int depth,
+               int numComponents, float *data,
+               double vmin, double vmax, double nonZeroMin) :
+    _id(0),
+    _width(width),
+    _height(height),
+    _depth(depth),
+    _transferFunc(NULL),
+    _ambient(0.6f),
+    _diffuse(0.4f),
+    _specular(0.3f),
+    _specularExp(90.0f),
+    _lightTwoSide(false),
+    _opacityScale(0.5f),
+    _data(NULL),
+    _numComponents(numComponents),
+    _nonZeroMin(nonZeroMin),
+    _cutplanesVisible(true),
+    _tex(NULL),
+    _position(x, y, z),
+    _scale(1, 1, 1),
+    _numSlices(512),
+    _enabled(true),
+    _dataEnabled(true),
+    _outlineEnabled(true),
+    _volumeType(CUBIC),
+    _isosurface(0)
+{
+    TRACE("Enter: %dx%dx%d", _width, _height, _depth);
+
+    _outlineColor[0] = _outlineColor[1] = _outlineColor[2] = 1.0f;
+
+    _tex = new Texture3D(_width, _height, _depth, GL_FLOAT, GL_LINEAR, _numComponents);
+    int fcount = _width * _height * _depth * _numComponents;
+    _data = new float[fcount];
+    if (data != NULL) {
+        memcpy(_data, data, fcount * sizeof(float));
+    } else {
+        TRACE("data is NULL");
+        memset(_data, 0, fcount * sizeof(float));
+    }
+    _tex->initialize(_data);
+    _id = _tex->id();
+
+    wAxis.setRange(vmin, vmax);
+
+    //Add cut planes. We create 3 default cut planes facing x, y, z directions.
+    //The default location of cut plane is in the middle of the data.
+    _plane.clear();
+    addCutplane(CutPlane::X_AXIS, 0.5f);
+    addCutplane(CutPlane::Y_AXIS, 0.5f);
+    addCutplane(CutPlane::Z_AXIS, 0.5f);
+
+    TRACE("Leave");
+}
+
+Volume::~Volume()
+{
+    TRACE("Enter");
+
+    delete [] _data;
+    delete _tex;
+}
+
+void Volume::getWorldSpaceBounds(Vector3f& bboxMin, Vector3f& bboxMax) const
+{
+    Vector3f scale = getPhysicalScaling();
+
+    Matrix4x4d mat;
+    mat.makeTranslation(_position);
+    Matrix4x4d mat2;
+    mat2.makeScale(scale);
+
+    mat.multiply(mat2);
+
+    bboxMin.set(FLT_MAX, FLT_MAX, FLT_MAX);
+    bboxMax.set(-FLT_MAX, -FLT_MAX, -FLT_MAX);
+
+    Vector3f modelMin(0, 0, 0);
+    Vector3f modelMax(1, 1, 1);
+
+    Vector4f bvert[8];
+    bvert[0] = Vector4f(modelMin.x, modelMin.y, modelMin.z, 1);
+    bvert[1] = Vector4f(modelMax.x, modelMin.y, modelMin.z, 1);
+    bvert[2] = Vector4f(modelMin.x, modelMax.y, modelMin.z, 1);
+    bvert[3] = Vector4f(modelMin.x, modelMin.y, modelMax.z, 1);
+    bvert[4] = Vector4f(modelMax.x, modelMax.y, modelMin.z, 1);
+    bvert[5] = Vector4f(modelMax.x, modelMin.y, modelMax.z, 1);
+    bvert[6] = Vector4f(modelMin.x, modelMax.y, modelMax.z, 1);
+    bvert[7] = Vector4f(modelMax.x, modelMax.y, modelMax.z, 1);
+
+    for (int i = 0; i < 8; i++) {
+        Vector4f worldVert = mat.transform(bvert[i]);
+        if (worldVert.x < bboxMin.x) bboxMin.x = worldVert.x;
+        if (worldVert.x > bboxMax.x) bboxMax.x = worldVert.x;
+        if (worldVert.y < bboxMin.y) bboxMin.y = worldVert.y;
+        if (worldVert.y > bboxMax.y) bboxMax.y = worldVert.y;
+        if (worldVert.z < bboxMin.z) bboxMin.z = worldVert.z;
+        if (worldVert.z > bboxMax.z) bboxMax.z = worldVert.z;
+    }
+}
Index: /nanovis/tags/1.1.4/Volume.h
===================================================================
--- /nanovis/tags/1.1.4/Volume.h	(revision 4930)
+++ /nanovis/tags/1.1.4/Volume.h	(revision 4930)
@@ -0,0 +1,493 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Author:
+ *   Wei Qiao <qiaow@purdue.edu>
+ */
+#ifndef NV_VOLUME_H
+#define NV_VOLUME_H
+
+#include <cstring>
+#include <string>
+#include <vector>
+
+#include <vrmath/Vector3f.h>
+
+#include "Texture3D.h"
+#include "AxisRange.h"
+#include "TransferFunction.h"
+
+namespace nv {
+
+class CutPlane {
+public:
+    enum Axis {
+        X_AXIS = 1,
+        Y_AXIS = 2,
+        Z_AXIS = 3
+    };
+
+    CutPlane(Axis _orient, float _offset) :
+        orient(_orient),
+        offset(_offset),
+        enabled(true)
+    {
+    }
+
+    Axis orient;
+    float offset;	///< normalized offset [0,1] in the volume
+    bool enabled;
+};
+
+class VolumeInterpolator;
+
+class Volume
+{
+public:
+    enum VolumeType {
+        CUBIC,
+        VOLQD,
+        ZINCBLENDE
+    };
+
+    /**
+     * \brief Volume data constructor
+     *
+     * Represents a 3D regular grid with uniform spacing along
+     * each axis.  Sample spacing may differ between X, Y and Z
+     *
+     * \param x X location
+     * \param y Y location
+     * \param z Z location
+     * \param width Number of samples in X
+     * \param height Number of samples in Y
+     * \param depth Number of samples in Z
+     * \param numComponents Number of components per sample
+     * \param data width * height * depth * numComponent sample array
+     * \param vmin Scalar value minimum
+     * \param vmax Scalar value maximum
+     * \param nonZeroMin Scalar minimum which is greater than zero
+     */
+    Volume(float x, float y, float z,
+           int width, int height, int depth, 
+           int numComponents,
+           float *data,
+           double vmin, double vmax, 
+           double nonZeroMin);
+
+    virtual ~Volume();
+
+    int width() const
+    {
+        return _width;
+    }
+
+    int height() const
+    {
+        return _height;
+    }
+
+    int depth() const
+    {
+        return _depth;
+    }
+
+    void visible(bool value)
+    { 
+        _enabled = value; 
+    }
+
+    bool visible() const
+    { 
+        return _enabled; 
+    }
+
+    int isosurface() const
+    {
+        return _isosurface;
+    }
+
+    void isosurface(int iso)
+    {
+        _isosurface = iso;
+    }
+
+    int numComponents() const
+    {
+        return _numComponents;
+    }
+
+    double nonZeroMin() const
+    {
+        return _nonZeroMin;
+    }
+
+    int volumeType() const
+    {
+        return _volumeType;
+    }
+
+    const float *data() const
+    {
+        return _data;
+    }
+
+    const Texture3D *tex() const
+    {
+        return _tex;
+    }
+
+    int numSlices() const
+    {
+        return _numSlices;
+    }
+
+    void numSlices(int n)
+    {
+        _numSlices = n;
+    }
+
+    // methods related to cutplanes
+    /// add a plane and returns its index
+    int addCutplane(CutPlane::Axis orientation, float location);
+
+    void enableCutplane(int index);
+
+    void disableCutplane(int index);
+
+    void cutplanesVisible(bool state)
+    {
+        _cutplanesVisible = state;
+    }
+
+    bool cutplanesVisible() const
+    {
+        return _cutplanesVisible;
+    }
+
+    void setCutplanePosition(int index, float location);
+
+    CutPlane *getCutplane(int index);
+
+    /// returns the number of cutplanes in the volume
+    int getCutplaneCount();
+
+    /// check if a cutplane is enabled
+    bool isCutplaneEnabled(int index) const;
+
+    // methods related to shading. These parameters are per volume 
+
+    /// Get ambient coefficient
+    float ambient() const
+    {
+        return _ambient;
+    }
+
+    /// Set ambient coefficient [0,1]
+    void ambient(float value)
+    {
+        if (value < 0.0f) value = 0.0f;
+        if (value > 1.0f) value = 1.0f;
+        _ambient = value;
+    }
+
+    /// Get diffuse coefficient
+    float diffuse() const
+    {
+        return _diffuse;
+    }
+
+    /// Set diffuse coefficient [0,1]
+    void diffuse(float value)
+    {
+        if (value < 0.0f) value = 0.0f;
+        if (value > 1.0f) value = 1.0f;
+        _diffuse = value;
+    }
+
+    /// Get specular coefficient
+    float specularLevel() const
+    {
+        return _specular;
+    }
+
+    /// Set specular coefficient [0,1]
+    void specularLevel(float value)
+    {
+        if (value < 0.0f) value = 0.0f;
+        if (value > 1.0f) value = 1.0f;
+        _specular = value;
+    }
+
+    /// Get specular exponent
+    float specularExponent() const
+    {
+        return _specularExp;
+    }
+
+    /// Set specular exponent [0,128]
+    void specularExponent(float value)
+    {
+        if (value < 0.0f) value = 0.0f;
+        if (value > 128.0f) value = 128.0f;
+        _specularExp = value;
+    }
+
+    bool twoSidedLighting() const
+    {
+        return _lightTwoSide;
+    }
+
+    void twoSidedLighting(bool value)
+    {
+        _lightTwoSide = value;
+    }
+
+    float opacityScale() const
+    {
+        return _opacityScale;
+    }
+
+    void opacityScale(float value)
+    {
+        _opacityScale = value;
+    }
+
+    void dataEnabled(bool value)
+    {
+        _dataEnabled = value;
+    }
+
+    bool dataEnabled() const
+    {
+        return _dataEnabled;
+    }
+
+    void outline(bool value)
+    {
+        _outlineEnabled = value; 
+    }
+
+    bool outline()
+    {
+        return _outlineEnabled;
+    }
+
+    TransferFunction *transferFunction()
+    {
+        return _transferFunc;
+    }
+
+    void transferFunction(TransferFunction *transferFunc)
+    {
+        _transferFunc = transferFunc;
+    }
+
+    void setOutlineColor(float *rgb);
+
+    void getOutlineColor(float *rgb);
+
+    void setPosition(const vrmath::Vector3f& pos)
+    {
+        _position = pos;
+    }
+
+    const vrmath::Vector3f& getPosition() const
+    {
+        return _position;
+    }
+
+    vrmath::Vector3f getPhysicalScaling() const
+    {
+        vrmath::Vector3f scale;
+        scale.x = 1;
+        scale.y = yAxis.length() / xAxis.length();
+        scale.z = zAxis.length() / xAxis.length();
+        return scale;
+    }
+
+    void setScale(const vrmath::Vector3f& scale)
+    {
+        _scale = scale;
+    }
+
+    const vrmath::Vector3f& getScale() const
+    {
+        return _scale;
+    }
+
+    void getWorldSpaceBounds(vrmath::Vector3f& bboxMin,
+                             vrmath::Vector3f& bboxMax) const;
+ 
+    double sampleDistanceX() const
+    {
+        return (xAxis.length() / ((double)_width-1.0));
+    }
+
+    double sampleDistanceY() const
+    {
+        return (yAxis.length() / ((double)_height-1.0));
+    }
+
+    double sampleDistanceZ() const
+    {
+        if (_depth == 1)
+            return sampleDistanceX();
+        return (zAxis.length() / ((double)_depth-1.0));
+    }
+
+    const char *name() const
+    {
+        return _name.c_str();
+    }
+
+    void name(const char *name)
+    {
+        _name = name;
+    }
+
+    GLuint textureID() const
+    {
+        return _id;
+    }
+
+    AxisRange xAxis, yAxis, zAxis, wAxis;
+
+    static bool updatePending;
+    static double valueMin, valueMax;
+
+    friend class VolumeInterpolator;
+
+protected:
+    float *data()
+    {
+        return _data;
+    }
+
+    Texture3D *tex()
+    {
+        return _tex;
+    }
+
+    GLuint _id;		///< OpenGL textue identifier (==_tex->id)
+
+    // Width, height and depth are point resolution, NOT physical
+    // units
+    /// The resolution of the data (how many points in X direction)
+    int _width;
+    /// The resolution of the data (how many points in Y direction)
+    int _height;
+    /// The resolution of the data (how many points in Z direction)
+    int _depth;
+
+    /**
+     * This is the designated transfer function to use to
+     * render this volume.
+     */
+    TransferFunction *_transferFunc;
+
+    float _ambient;      ///< Ambient material coefficient
+    float _diffuse;      ///< Diffuse material coefficient
+    float _specular;     ///< Specular level material coefficient
+    float _specularExp;  ///< Specular exponent
+    bool _lightTwoSide;  ///< Two-sided lighting flag
+
+    /**
+     * The scale multiplied to the opacity assigned by the 
+     * transfer function.
+     */
+    float _opacityScale;
+
+    std::string _name;
+
+    float *_data;
+
+    int _numComponents;
+
+    double _nonZeroMin;
+
+    bool _cutplanesVisible;
+    std::vector<CutPlane> _plane; ///< cut planes
+
+    Texture3D *_tex;		///< OpenGL texture storing the volume
+
+    vrmath::Vector3f _position;
+    vrmath::Vector3f _scale;
+
+    /**
+     * Number of slices when rendered. The greater
+     * the better quality, lower speed.
+     */
+    int _numSlices;
+    bool _enabled; 
+    bool _dataEnabled;		///< show/hide cloud of volume data
+    bool _outlineEnabled;	///< show/hide outline around volume
+    float _outlineColor[3];	///< color for outline around volume
+    int _volumeType;		///< cubic or zincblende
+    int _isosurface;
+};
+
+inline int
+Volume::addCutplane(CutPlane::Axis orientation, float location)
+{
+    _plane.push_back(CutPlane(orientation, location));
+    return _plane.size() - 1;
+}
+
+inline void 
+Volume::enableCutplane(int index)
+{ 
+    //assert(index < plane.size());
+    _plane[index].enabled = true;
+}
+
+inline void 
+Volume::disableCutplane(int index)
+{
+    //assert(index < plane.size());
+    _plane[index].enabled = false;
+}
+
+inline void 
+Volume::setCutplanePosition(int index, float position)
+{
+    //assert(index < plane.size());
+    _plane[index].offset = position;
+}
+
+inline CutPlane * 
+Volume::getCutplane(int index)
+{
+    //assert(index < plane.size());
+    return &_plane[index];
+}
+
+inline int 
+Volume::getCutplaneCount()
+{
+    return _plane.size();
+}
+
+inline bool 
+Volume::isCutplaneEnabled(int index) const
+{
+    //assert(index < plane.size());
+    return _plane[index].enabled; 
+}
+
+inline void 
+Volume::setOutlineColor(float *rgb) 
+{
+    memcpy(_outlineColor, rgb, sizeof(float)*3);
+}
+
+inline void 
+Volume::getOutlineColor(float *rgb) 
+{
+    memcpy(rgb, _outlineColor, sizeof(float)*3);
+}
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/VolumeInterpolator.cpp
===================================================================
--- /nanovis/tags/1.1.4/VolumeInterpolator.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/VolumeInterpolator.cpp	(revision 4930)
@@ -0,0 +1,170 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#include <string.h>
+#include <sys/time.h>
+
+#include <vrmath/Vector3f.h>
+
+#include "VolumeInterpolator.h"
+#include "Volume.h"
+#include "Trace.h"
+
+using namespace nv;
+using namespace vrmath;
+
+VolumeInterpolator::VolumeInterpolator() : 
+    _volume(NULL), 
+    _interval(8.0), 
+    _started(false), 
+    _numBytes(0), 
+    _dataCount(0), 
+    _numComponents(0)
+{
+}
+
+void VolumeInterpolator::start()
+{
+    if (!_volumes.empty()) {
+        TRACE("Volume Interpolation Started");
+        _started = true;
+    } else {
+        TRACE("Volume Interpolation NOT Started");
+        _started = false;
+    }
+    struct timeval clock;
+    gettimeofday(&clock, NULL);
+    _startTime = clock.tv_sec + clock.tv_usec/1000000.0;
+    TRACE("Leave");
+}
+
+void VolumeInterpolator::stop()
+{
+    _started = false;
+}
+
+Volume *VolumeInterpolator::update(float fraction)
+{
+    int key1, key2;
+    float interp;
+
+    computeKeys(fraction, (int)_volumes.size(), &interp, &key1, &key2);
+
+    if (interp == 0.0f) {
+        memcpy(_volume->data(), _volumes[key1]->data(), _numBytes);
+        _volume->tex()->update(_volume->data());
+    } else {
+        float *data1 = _volumes[key1]->data();
+        float *data2 = _volumes[key2]->data();
+        float *result = _volume->data();
+
+        Vector3f normal1, normal2, normal;
+        for (unsigned int i = 0; i < _dataCount; ++i) {
+            *result = interp * (*data2 - *data1) + *data1;
+            normal1 = (*(Vector3f*)(data1 + 1) - 0.5) * 2;
+            normal2 = (*(Vector3f*)(data2 + 1) - 0.5) * 2;
+            normal = (normal2 - normal1) * interp + normal1;
+            normal = normal.normalize();
+            normal = normal * 0.5 + 0.5;
+            *((Vector3f*)(result + 1)) = normal;
+
+            result += _numComponents;
+            data1 += _numComponents;
+            data2 += _numComponents;
+        }
+
+        _volume->tex()->update(_volume->data());
+    }
+
+    return _volume;
+}
+
+void
+VolumeInterpolator::computeKeys(float fraction, int count, float *interp, 
+                                int *key1, int *key2)
+{
+    int limit = count - 1;
+    if (fraction <= 0) {
+        *key1 = *key2 = 0;
+        *interp = 0.0f;
+    } else if (fraction >= 1.0f) {
+        *key1 = *key2 = limit;
+        *interp = 0.0f;
+    } else {
+        int n;
+        for (n = 0; n < limit; n++) {
+            if (fraction >= (n / (count - 1.0f)) &&
+                fraction < ((n+1)/(count-1.0f))) {
+                break;
+            }
+        }
+
+        TRACE("n = %d count = %d", n, count);
+        if (n >= limit) {
+            *key1 = *key2 = limit;
+            *interp = 0.0f;
+        } else {
+            *key1 = n;
+            *key2 = n+1;
+            *interp = (fraction - (n / (count -1.0f))) / ((n + 1) / (count - 1.0f) - n / (count - 1.0f));
+            //*ret = inter * (keyValue[n + 1] - keyValue[n]) + keyValue[n];
+        }
+    }
+}
+
+void
+VolumeInterpolator::clearAll()
+{
+    _volumes.clear();
+}
+
+void
+VolumeInterpolator::addVolume(Volume *volume)
+{
+    if (!_volumes.empty()) {
+        if (_volumes[0]->width() != volume->width() || 
+            _volumes[0]->height() != volume->height() ||   
+            _volumes[0]->depth() != volume->depth() || 
+            _volumes[0]->numComponents() != volume->numComponents()) {
+            TRACE("The volume should be the same width, height, number of components");
+            return;
+        }
+    } else {
+        _dataCount = volume->width() * volume->height() * volume->depth();
+        _numComponents = volume->numComponents();
+        _numBytes = _dataCount * _numComponents * sizeof(float);
+        Vector3f pos = volume->getPosition();
+        _volume = new Volume(pos.x, pos.y, pos.z,
+                             volume->width(),
+                             volume->height(),
+                             volume->depth(), 
+                             volume->numComponents(), 
+                             volume->data(), 
+                             volume->wAxis.min(), 
+                             volume->wAxis.max(), 
+                             volume->nonZeroMin());
+
+        _volume->setPosition(volume->getPosition());
+        _volume->setScale(volume->getScale());
+        _volume->disableCutplane(0);
+        _volume->disableCutplane(1);
+        _volume->disableCutplane(2);
+        _volume->visible(true);
+        _volume->dataEnabled(true);
+        _volume->ambient(volume->ambient());
+        _volume->diffuse(volume->diffuse());
+        _volume->specularLevel(volume->specularLevel());
+        _volume->specularExponent(volume->specularExponent());
+        _volume->opacityScale(volume->opacityScale());
+        _volume->isosurface(0);
+    }
+    _volumes.push_back(volume);
+    TRACE("Volume \"%s\" is added to VolumeInterpolator", volume->name());
+}
+
+Volume *VolumeInterpolator::getVolume()
+{
+    return _volume;
+}
Index: /nanovis/tags/1.1.4/VolumeInterpolator.h
===================================================================
--- /nanovis/tags/1.1.4/VolumeInterpolator.h	(revision 4930)
+++ /nanovis/tags/1.1.4/VolumeInterpolator.h	(revision 4930)
@@ -0,0 +1,70 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#ifndef NV_VOLUME_INTERPOLATOR_H
+#define NV_VOLUME_INTERPOLATOR_H
+
+#include <vector>
+
+#include "Volume.h"
+
+namespace nv {
+
+class VolumeInterpolator
+{
+public :
+    VolumeInterpolator();
+
+    void addVolume(Volume *vol);
+
+    void clearAll();
+    
+    void start();
+
+    Volume *update(float fraction);
+
+    void stop();
+
+    void computeKeys(float fraction, int count, float *interp, int *key1, int *key2);
+
+    bool isStarted() const;
+
+    double getInterval() const;
+
+    double getStartTime() const;
+
+    Volume *getVolume();
+
+private:
+    Volume *_volume;
+    std::vector<Volume *> _volumes;
+
+    double _interval;
+    bool _started;
+    unsigned int _numBytes;
+    unsigned int _dataCount;
+    unsigned int _numComponents;
+    double _startTime;
+};
+
+inline bool VolumeInterpolator::isStarted() const
+{
+    return _started;
+}
+
+inline double VolumeInterpolator::getStartTime() const
+{
+    return _startTime;
+}
+
+inline double VolumeInterpolator::getInterval() const
+{
+    return _interval;
+}
+
+}
+
+#endif
+
Index: /nanovis/tags/1.1.4/VolumeRenderer.cpp
===================================================================
--- /nanovis/tags/1.1.4/VolumeRenderer.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/VolumeRenderer.cpp	(revision 4930)
@@ -0,0 +1,572 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * ----------------------------------------------------------------------
+ * VolumeRenderer.cpp : VolumeRenderer class for volume visualization
+ *
+ * ======================================================================
+ *  AUTHOR:  Wei Qiao <qiaow@purdue.edu>
+ *           Purdue Rendering and Perceptualization Lab (PURPL)
+ *
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ *  See the file "license.terms" for information on usage and
+ *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ * ======================================================================
+ */
+#include <stdlib.h>
+#include <float.h>
+
+#include <vector>
+
+#include <GL/glew.h>
+
+#include <vrmath/Vector3f.h>
+#include <vrmath/Matrix4x4d.h>
+
+#include "nanovis.h"
+#include "VolumeRenderer.h"
+#include "Plane.h"
+#include "ConvexPolygon.h"
+#include "StdVertexShader.h"
+#include "Trace.h"
+
+using namespace nv;
+using namespace vrmath;
+
+VolumeRenderer::VolumeRenderer()
+{
+    initShaders();
+
+    _volumeInterpolator = new VolumeInterpolator();
+}
+
+VolumeRenderer::~VolumeRenderer()
+{
+    delete _cutplaneShader;
+    delete _zincBlendeShader;
+    delete _regularVolumeShader;
+    delete _stdVertexShader;
+    delete _volumeInterpolator;
+}
+
+//initialize the volume shaders
+void VolumeRenderer::initShaders()
+{
+    _cutplaneShader = new Shader();
+    _cutplaneShader->loadVertexProgram("cutplane_vp.cg");
+    _cutplaneShader->loadFragmentProgram("cutplane_fp.cg");
+
+    //standard vertex program
+    _stdVertexShader = new StdVertexShader();
+
+    //volume rendering shader: one cubic volume
+    _regularVolumeShader = new RegularVolumeShader();
+
+    //volume rendering shader: one zincblende orbital volume.
+    //This shader renders one orbital of the simulation.
+    //A sim has S, P, D, SS orbitals. thus a full rendering requires 4 zincblende orbital volumes. 
+    //A zincblende orbital volume is decomposed into 2 "interlocking" cubic 4-component volumes and passed to the shader. 
+    //We render each orbital with independent transfer functions then blend the result.
+    //
+    //The engine is already capable of rendering multiple volumes and combine them. Thus, we just invoke this shader on
+    //S, P, D and SS orbitals with different transfor functions. The result is a multi-orbital rendering.
+    _zincBlendeShader = new ZincBlendeVolumeShader();
+}
+
+struct SortElement {
+    float z;
+    int volumeId;
+    int sliceId;
+
+    SortElement(float _z, int _v, int _s) :
+        z(_z),
+        volumeId(_v),
+        sliceId(_s)
+    {}
+};
+
+static int sliceSort(const void *a, const void *b)
+{
+    if ((*((SortElement*)a)).z > (*((SortElement*)b)).z)
+        return 1;
+    else
+        return -1;
+}
+
+void 
+VolumeRenderer::renderAll()
+{
+    size_t total_rendered_slices = 0;
+
+    if (_volumeInterpolator->isStarted()) {
+#ifdef notdef
+        ani_vol = _volumeInterpolator->getVolume();
+        ani_tf = ani_vol->transferFunction();
+#endif
+        TRACE("VOLUME INTERPOLATOR IS STARTED ----------------------------");
+    }
+    // Determine the volumes that are to be rendered.
+    std::vector<Volume *> volumes;
+    for (NanoVis::VolumeHashmap::iterator itr = NanoVis::volumeTable.begin();
+         itr != NanoVis::volumeTable.end(); ++itr) {
+        Volume *volume = itr->second;
+        if (!volume->visible()) {
+            continue; // Skip this volume
+        }
+        // BE CAREFUL: Set the number of slices to something slightly
+        // different for each volume.  If we have identical volumes at exactly
+        // the same position with exactly the same number of slices, the
+        // second volume will overwrite the first, so the first won't appear
+        // at all.
+        volumes.push_back(volume);
+        volume->numSlices(256 - volumes.size());
+    }
+
+    glPushAttrib(GL_ENABLE_BIT);
+
+    //two dimension pointer array
+    ConvexPolygon ***polys = new ConvexPolygon**[volumes.size()];
+    //number of actual slices for each volume
+    size_t *actual_slices = new size_t[volumes.size()];
+    float *z_steps = new float[volumes.size()];
+
+    TRACE("start loop %d", volumes.size());
+    for (size_t i = 0; i < volumes.size(); i++) {
+        Volume *volume = volumes[i];
+        polys[i] = NULL;
+        actual_slices[i] = 0;
+
+        int n_slices = volume->numSlices();
+        if (volume->isosurface()) {
+            // double the number of slices
+            n_slices <<= 1;
+        }
+
+        // Get any additional transforms on Volume
+        Vector3f volPos = volume->getPosition();
+        Vector3f volScale = volume->getPhysicalScaling();
+        // Get world coords of volume bbox
+        double x0 = 0;
+        double y0 = 0;
+        double z0 = 0;
+        double x1 = x0 + 1;
+        double y1 = y0 + 1;
+        double z1 = z0 + 1;
+
+        Matrix4x4d model_view_no_trans, model_view_trans;
+        Matrix4x4d model_view_no_trans_inverse, model_view_trans_inverse;
+
+        //initialize volume plane with world coordinates
+        nv::Plane volume_planes[6];
+        volume_planes[0].setCoeffs( 1,  0,  0, -x0);
+        volume_planes[1].setCoeffs(-1,  0,  0,  x1);
+        volume_planes[2].setCoeffs( 0,  1,  0, -y0);
+        volume_planes[3].setCoeffs( 0, -1,  0,  y1);
+        volume_planes[4].setCoeffs( 0,  0,  1, -z0);
+        volume_planes[5].setCoeffs( 0,  0, -1,  z1);
+
+        TRACE("VOL POS: %g %g %g",
+              volPos.x, volPos.y, volPos.z);
+        TRACE("VOL SCALE: %g %g %g",
+              volScale.x, volScale.y, volScale.z);
+
+        //get modelview matrix with no translation
+        glPushMatrix();
+        glScalef(volScale.x, volScale.y, volScale.z);
+
+        glEnable(GL_DEPTH_TEST);
+
+        GLdouble mv_no_trans[16];
+        glGetDoublev(GL_MODELVIEW_MATRIX, mv_no_trans);
+
+        model_view_no_trans = Matrix4x4d(mv_no_trans);
+        model_view_no_trans_inverse = model_view_no_trans.inverse();
+
+        glPopMatrix();
+
+        //get modelview matrix with translation
+        glPushMatrix();
+        glTranslatef(volPos.x, volPos.y, volPos.z);
+        glScalef(volScale.x, volScale.y, volScale.z);
+
+        GLdouble mv_trans[16];
+        glGetDoublev(GL_MODELVIEW_MATRIX, mv_trans);
+
+        model_view_trans = Matrix4x4d(mv_trans);
+        model_view_trans_inverse = model_view_trans.inverse();
+
+        model_view_trans.print();
+
+        //draw volume bounding box with translation (the correct location in
+        //space)
+        if (volume->outline()) {
+            float olcolor[3];
+            volume->getOutlineColor(olcolor);
+            drawBoundingBox(x0, y0, z0, x1, y1, z1,
+                            olcolor[0], olcolor[1], olcolor[2],
+                            1.5);
+        }
+        glPopMatrix();
+
+        // transform volume_planes to eye coordinates.
+        // Need to transform without translation since we don't want
+        // to translate plane normals, just rotate them
+        for (size_t j = 0; j < 6; j++) {
+            volume_planes[j].transform(model_view_no_trans);
+        }
+        double eyeMinX, eyeMaxX, eyeMinY, eyeMaxY;
+        double zNear, zFar;
+        getEyeSpaceBounds(model_view_no_trans, 
+                          eyeMinX, eyeMaxX,
+                          eyeMinY, eyeMaxY,
+                          zNear, zFar);
+
+        //compute actual rendering slices
+        float z_step = fabs(zNear-zFar)/n_slices;
+        z_steps[i] = z_step;
+        size_t n_actual_slices;
+
+        if (volume->dataEnabled()) {
+            if (z_step == 0.0f)
+                n_actual_slices = 1;
+            else
+                n_actual_slices = (int)(fabs(zNear-zFar)/z_step + 1);
+            polys[i] = new ConvexPolygon*[n_actual_slices];
+        } else {
+            n_actual_slices = 0;
+            polys[i] = NULL;
+        }
+        actual_slices[i] = n_actual_slices;
+
+        TRACE("near: %g far: %g eye space bounds: (%g,%g)-(%g,%g) z_step: %g slices: %d",
+              zNear, zFar, eyeMinX, eyeMaxX, eyeMinY, eyeMaxY, z_step, n_actual_slices);
+
+        Vector4f vert1, vert2, vert3, vert4;
+
+        // Render cutplanes first with depth test enabled.  They will mark the
+        // image with their depth values.  Then we render other volume slices.
+        // These volume slices will be occluded correctly by the cutplanes and
+        // vice versa.
+
+        for (int j = 0; j < volume->getCutplaneCount(); j++) {
+            if (!volume->cutplanesVisible() || !volume->isCutplaneEnabled(j)) {
+                continue;
+            }
+            Vector4f texcoord1, texcoord2, texcoord3, texcoord4;
+            float offset = volume->getCutplane(j)->offset;
+            int axis = volume->getCutplane(j)->orient;
+
+            switch (axis) {
+            case CutPlane::X_AXIS: // YZ plane
+                vert1 = Vector4f(offset, 0, 0, 1);
+                vert2 = Vector4f(offset, 1, 0, 1);
+                vert3 = Vector4f(offset, 1, 1, 1);
+                vert4 = Vector4f(offset, 0, 1, 1);
+                texcoord1 = Vector4f(offset, 0, 0, 1);
+                texcoord2 = Vector4f(offset, 1, 0, 1);
+                texcoord3 = Vector4f(offset, 1, 1, 1);
+                texcoord4 = Vector4f(offset, 0, 1, 1);
+                break;
+            case CutPlane::Y_AXIS: // XZ plane
+                vert1 = Vector4f(0, offset, 0, 1);
+                vert2 = Vector4f(1, offset, 0, 1);
+                vert3 = Vector4f(1, offset, 1, 1);
+                vert4 = Vector4f(0, offset, 1, 1);
+                texcoord1 = Vector4f(0, offset, 0, 1);
+                texcoord2 = Vector4f(1, offset, 0, 1);
+                texcoord3 = Vector4f(1, offset, 1, 1);
+                texcoord4 = Vector4f(0, offset, 1, 1);
+                break;
+            case CutPlane::Z_AXIS: // XY plane
+            default:
+                vert1 = Vector4f(0, 0, offset, 1);
+                vert2 = Vector4f(1, 0, offset, 1);
+                vert3 = Vector4f(1, 1, offset, 1);
+                vert4 = Vector4f(0, 1, offset, 1);
+                texcoord1 = Vector4f(0, 0, offset, 1);
+                texcoord2 = Vector4f(1, 0, offset, 1);
+                texcoord3 = Vector4f(1, 1, offset, 1);
+                texcoord4 = Vector4f(0, 1, offset, 1);
+                break;
+            }
+
+            _cutplaneShader->bind();
+            _cutplaneShader->setFPTextureParameter("volume", volume->textureID());
+            _cutplaneShader->setFPTextureParameter("tf", volume->transferFunction()->id());
+
+            glPushMatrix();
+            glTranslatef(volPos.x, volPos.y, volPos.z);
+            glScalef(volScale.x, volScale.y, volScale.z);
+            _cutplaneShader->setGLStateMatrixVPParameter("modelViewProjMatrix",
+                                                         Shader::MODELVIEW_PROJECTION_MATRIX);
+            glPopMatrix();
+
+            glEnable(GL_DEPTH_TEST);
+            glDisable(GL_BLEND);
+
+            glBegin(GL_QUADS);
+            glTexCoord3f(texcoord1.x, texcoord1.y, texcoord1.z);
+            glVertex3f(vert1.x, vert1.y, vert1.z);
+            glTexCoord3f(texcoord2.x, texcoord2.y, texcoord2.z);
+            glVertex3f(vert2.x, vert2.y, vert2.z);
+            glTexCoord3f(texcoord3.x, texcoord3.y, texcoord3.z);
+            glVertex3f(vert3.x, vert3.y, vert3.z);
+            glTexCoord3f(texcoord4.x, texcoord4.y, texcoord4.z);
+            glVertex3f(vert4.x, vert4.y, vert4.z);
+            glEnd();
+
+            glDisable(GL_DEPTH_TEST);
+            _cutplaneShader->disableFPTextureParameter("tf");
+            _cutplaneShader->disableFPTextureParameter("volume");
+            _cutplaneShader->unbind();
+        } //done cutplanes
+
+        // Now prepare proxy geometry slices
+
+        // Initialize view-aligned quads with eye space bounds of
+        // volume
+        vert1 = Vector4f(eyeMinX, eyeMinY, -0.5, 1);
+        vert2 = Vector4f(eyeMaxX, eyeMinY, -0.5, 1);
+        vert3 = Vector4f(eyeMaxX, eyeMaxY, -0.5, 1);
+        vert4 = Vector4f(eyeMinX, eyeMaxY, -0.5, 1);
+
+        size_t counter = 0;
+
+        // Transform slices and store them
+        float slice_z;
+        for (size_t j = 0; j < n_actual_slices; j++) {
+            slice_z = zFar + j * z_step; //back to front
+
+            ConvexPolygon *poly = new ConvexPolygon();
+            polys[i][counter] = poly;
+            counter++;
+
+            poly->vertices.clear();
+            poly->setId(i);
+
+            // Set eye space Z-coordinate of slice
+            vert1.z = slice_z;
+            vert2.z = slice_z;
+            vert3.z = slice_z;
+            vert4.z = slice_z;
+
+            poly->appendVertex(vert1);
+            poly->appendVertex(vert2);
+            poly->appendVertex(vert3);
+            poly->appendVertex(vert4);
+
+            for (size_t k = 0; k < 6; k++) {
+                if (!poly->clip(volume_planes[k], true))
+                    break;
+            }
+
+            if (poly->vertices.size() >= 3) {
+                poly->transform(model_view_no_trans_inverse);
+                poly->transform(model_view_trans);
+                total_rendered_slices++;
+            }
+        }
+    } //iterate all volumes
+    TRACE("end loop");
+
+    // We sort all the polygons according to their eye-space depth, from
+    // farthest to the closest.  This step is critical for correct blending
+
+    SortElement *slices = (SortElement *)
+        malloc(sizeof(SortElement) * total_rendered_slices);
+
+    size_t counter = 0;
+    for (size_t i = 0; i < volumes.size(); i++) {
+        for (size_t j = 0; j < actual_slices[i]; j++) {
+            if (polys[i][j]->vertices.size() >= 3) {
+                slices[counter] = SortElement(polys[i][j]->vertices[0].z, i, j);
+                counter++;
+            }
+        }
+    }
+
+    //sort them
+    qsort(slices, total_rendered_slices, sizeof(SortElement), sliceSort);
+
+    //Now we are ready to render all the slices from back to front
+    glEnable(GL_DEPTH_TEST);
+    // Non pre-multiplied alpha
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    glEnable(GL_BLEND);
+
+    for (size_t i = 0; i < total_rendered_slices; i++) {
+        int volIdx = slices[i].volumeId;
+        int sliceIdx = slices[i].sliceId;
+        ConvexPolygon *currentSlice = polys[volIdx][sliceIdx];
+
+        Volume *volume = volumes[volIdx];
+        Vector3f volScale = volume->getPhysicalScaling();
+
+        glPushMatrix();
+        glScalef(volScale.x, volScale.y, volScale.z);
+
+        float z_step = z_steps[volIdx];
+        // FIXME: compute view-dependent volume sample distance
+        double avgSampleDistance = 1.0 / pow(volume->width() * volScale.x * 
+                                             volume->height() * volScale.y * 
+                                             volume->depth() * volScale.z, 1.0/3.0);
+        float sampleRatio = z_step / avgSampleDistance;
+
+#ifdef notdef
+        TRACE("shading slice: volume %s addr=%x slice=%d, volume=%d z_step=%g avgSD=%g", 
+              volume->name(), volume, sliceIdx, volIdx, z_step, avgSampleDistance);
+#endif
+        activateVolumeShader(volume, false, sampleRatio);
+        glPopMatrix();
+
+        glBegin(GL_POLYGON);
+        currentSlice->emit(true);
+        glEnd();
+
+        deactivateVolumeShader();
+    }
+
+    glPopAttrib();
+
+    //Deallocate all the memory used
+    for (size_t i = 0; i < volumes.size(); i++) {
+        for (size_t j = 0; j <actual_slices[i]; j++) {
+            delete polys[i][j];
+        }
+        if (polys[i]) {
+            delete[] polys[i];
+        }
+    }
+    delete[] polys;
+    delete[] actual_slices;
+    delete[] z_steps;
+    free(slices);
+}
+
+void 
+VolumeRenderer::drawBoundingBox(float x0, float y0, float z0, 
+                                float x1, float y1, float z1,
+                                float r, float g, float b, 
+                                float lineWidth)
+{
+    glPushAttrib(GL_ENABLE_BIT);
+
+    glEnable(GL_DEPTH_TEST);
+    glDisable(GL_TEXTURE_2D);
+    glEnable(GL_BLEND);
+
+    glMatrixMode(GL_MODELVIEW);
+    glPushMatrix();
+
+    glColor4d(r, g, b, 1.0);
+    glLineWidth(lineWidth);
+
+    glBegin(GL_LINE_LOOP);
+    {
+        glVertex3d(x0, y0, z0);
+        glVertex3d(x1, y0, z0);
+        glVertex3d(x1, y1, z0);
+        glVertex3d(x0, y1, z0);
+    }
+    glEnd();
+
+    glBegin(GL_LINE_LOOP);
+    {
+        glVertex3d(x0, y0, z1);
+        glVertex3d(x1, y0, z1);
+        glVertex3d(x1, y1, z1);
+        glVertex3d(x0, y1, z1);
+    }
+    glEnd();
+
+    glBegin(GL_LINE_LOOP);
+    {
+        glVertex3d(x0, y0, z0);
+        glVertex3d(x0, y0, z1);
+        glVertex3d(x0, y1, z1);
+        glVertex3d(x0, y1, z0);
+    }
+    glEnd();
+
+    glBegin(GL_LINE_LOOP);
+    {
+        glVertex3d(x1, y0, z0);
+        glVertex3d(x1, y0, z1);
+        glVertex3d(x1, y1, z1);
+        glVertex3d(x1, y1, z0);
+    }
+    glEnd();
+
+    glPopMatrix();
+    glPopAttrib();
+}
+
+void 
+VolumeRenderer::activateVolumeShader(Volume *volume,
+                                     bool sliceMode,
+                                     float sampleRatio)
+{
+    //vertex shader
+    _stdVertexShader->bind();
+    TransferFunction *transferFunc  = volume->transferFunction();
+    if (volume->volumeType() == Volume::CUBIC) {
+        _regularVolumeShader->bind(transferFunc->id(), volume, sliceMode, sampleRatio);
+    } else if (volume->volumeType() == Volume::ZINCBLENDE) {
+        _zincBlendeShader->bind(transferFunc->id(), volume, sliceMode, sampleRatio);
+    }
+}
+
+void VolumeRenderer::deactivateVolumeShader()
+{
+    _stdVertexShader->unbind();
+    _regularVolumeShader->unbind();
+    _zincBlendeShader->unbind();
+}
+
+void VolumeRenderer::getEyeSpaceBounds(const Matrix4x4d& mv,
+                                       double& xMin, double& xMax,
+                                       double& yMin, double& yMax,
+                                       double& zNear, double& zFar)
+{
+    double x0 = 0;
+    double y0 = 0;
+    double z0 = 0;
+    double x1 = 1;
+    double y1 = 1;
+    double z1 = 1;
+
+    double zMin, zMax;
+    xMin = DBL_MAX;
+    xMax = -DBL_MAX;
+    yMin = DBL_MAX;
+    yMax = -DBL_MAX;
+    zMin = DBL_MAX;
+    zMax = -DBL_MAX;
+
+    double vertex[8][4];
+
+    vertex[0][0]=x0; vertex[0][1]=y0; vertex[0][2]=z0; vertex[0][3]=1.0;
+    vertex[1][0]=x1; vertex[1][1]=y0; vertex[1][2]=z0; vertex[1][3]=1.0;
+    vertex[2][0]=x0; vertex[2][1]=y1; vertex[2][2]=z0; vertex[2][3]=1.0;
+    vertex[3][0]=x0; vertex[3][1]=y0; vertex[3][2]=z1; vertex[3][3]=1.0;
+    vertex[4][0]=x1; vertex[4][1]=y1; vertex[4][2]=z0; vertex[4][3]=1.0;
+    vertex[5][0]=x1; vertex[5][1]=y0; vertex[5][2]=z1; vertex[5][3]=1.0;
+    vertex[6][0]=x0; vertex[6][1]=y1; vertex[6][2]=z1; vertex[6][3]=1.0;
+    vertex[7][0]=x1; vertex[7][1]=y1; vertex[7][2]=z1; vertex[7][3]=1.0;
+
+    for (int i = 0; i < 8; i++) {
+        Vector4f eyeVert = mv.transform(Vector4f(vertex[i][0],
+                                                 vertex[i][1],
+                                                 vertex[i][2],
+                                                 vertex[i][3]));
+        if (eyeVert.x < xMin) xMin = eyeVert.x;
+        if (eyeVert.x > xMax) xMax = eyeVert.x;
+        if (eyeVert.y < yMin) yMin = eyeVert.y;
+        if (eyeVert.y > yMax) yMax = eyeVert.y;
+        if (eyeVert.z < zMin) zMin = eyeVert.z;
+        if (eyeVert.z > zMax) zMax = eyeVert.z;
+    }
+
+    zNear = zMax;
+    zFar = zMin;
+}
Index: /nanovis/tags/1.1.4/VolumeRenderer.h
===================================================================
--- /nanovis/tags/1.1.4/VolumeRenderer.h	(revision 4930)
+++ /nanovis/tags/1.1.4/VolumeRenderer.h	(revision 4930)
@@ -0,0 +1,112 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors:
+ *   Wei Qiao <qiaow@purdue.edu>
+ */
+#ifndef NV_VOLUME_RENDERER_H
+#define NV_VOLUME_RENDERER_H
+
+#include <vrmath/Matrix4x4d.h>
+
+#include "Volume.h"
+#include "VolumeInterpolator.h"
+#include "RegularVolumeShader.h"
+#include "ZincBlendeVolumeShader.h"
+#include "StdVertexShader.h"
+
+namespace nv {
+
+class VolumeRenderer
+{
+public:
+    VolumeRenderer();
+
+    ~VolumeRenderer();
+
+    /// render all enabled volumes
+    void renderAll();
+
+    void specular(float val);
+
+    void diffuse(float val);
+
+    void clearAnimatedVolumeInfo()
+    {
+        _volumeInterpolator->clearAll();
+    }
+
+    void addAnimatedVolume(Volume* volume)
+    {
+        _volumeInterpolator->addVolume(volume);
+    }
+
+    void startVolumeAnimation()
+    {
+        _volumeInterpolator->start();
+    }
+
+    void stopVolumeAnimation()
+    {
+        _volumeInterpolator->stop();
+    }
+
+    VolumeInterpolator* getVolumeInterpolator()
+    {
+        return _volumeInterpolator;
+    }
+
+private:
+    void initShaders();
+
+    void activateVolumeShader(Volume *vol, bool sliceMode, float sampleRatio);
+
+    void deactivateVolumeShader();
+
+    void drawBoundingBox(float x0, float y0, float z0,
+                         float x1, float y1, float z1,
+                         float r, float g, float b, float line_width);
+
+    void getEyeSpaceBounds(const vrmath::Matrix4x4d& mv,
+                           double& xMin, double& xMax,
+                           double& yMin, double& yMax,
+                           double& zNear, double& zFar);
+
+    VolumeInterpolator *_volumeInterpolator;
+
+    /**
+     * Shader for single slice cutplane render
+     */
+    Shader *_cutplaneShader;
+
+    /**
+     * Shader for rendering a single cubic volume
+     */
+    RegularVolumeShader *_regularVolumeShader;
+
+    /**
+     * Shader for rendering a single zincblende orbital.  A
+     * simulation contains S, P, D and SS, total of 4 orbitals. A full
+     * rendering requires 4 zincblende orbital volumes.  A zincblende orbital
+     * volume is decomposed into two "interlocking" cubic volumes and passed
+     * to the shader.  We render each orbital with its own independent
+     * transfer functions then blend the result.
+     * 
+     * The engine is already capable of rendering multiple volumes and combine
+     * them. Thus, we just invoke this shader on S, P, D and SS orbitals with
+     * different transfor functions. The result is a multi-orbital rendering.
+     * This is equivalent to rendering 4 unrelated data sets occupying the
+     * same space.
+     */
+    ZincBlendeVolumeShader *_zincBlendeShader;
+
+    /**
+     * standard vertex shader 
+     */
+    StdVertexShader *_stdVertexShader;
+};
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/VolumeShader.cpp
===================================================================
--- /nanovis/tags/1.1.4/VolumeShader.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/VolumeShader.cpp	(revision 4930)
@@ -0,0 +1,17 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#include "VolumeShader.h"
+
+using namespace nv;
+
+VolumeShader::VolumeShader()
+{
+}
+
+VolumeShader::~VolumeShader()
+{
+}
+
Index: /nanovis/tags/1.1.4/VolumeShader.h
===================================================================
--- /nanovis/tags/1.1.4/VolumeShader.h	(revision 4930)
+++ /nanovis/tags/1.1.4/VolumeShader.h	(revision 4930)
@@ -0,0 +1,35 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#ifndef NV_VOLUME_SHADER_H
+#define NV_VOLUME_SHADER_H
+
+#include "Shader.h"
+
+namespace nv {
+
+class Volume;
+
+class VolumeShader : public Shader
+{
+public :
+    virtual ~VolumeShader();
+
+    virtual void bind(unsigned int tfID, Volume *volume,
+                      int sliceMode, float sampleRatio) = 0;
+
+    virtual void unbind()
+    {
+        Shader::unbind();
+    }
+
+protected :
+    VolumeShader();
+};
+
+}
+
+#endif // 
+
Index: /nanovis/tags/1.1.4/VtkReader.cpp
===================================================================
--- /nanovis/tags/1.1.4/VtkReader.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/VtkReader.cpp	(revision 4930)
@@ -0,0 +1,501 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+
+#include <iostream>
+#include <float.h>
+
+#include <RpField1D.h>
+#include <RpFieldRect3D.h>
+
+#include <vrmath/Vector3f.h>
+
+#include "ReaderCommon.h"
+
+#include "config.h"
+#include "nanovis.h"
+#include "VtkReader.h"
+#include "Volume.h"
+#include "Trace.h"
+
+using namespace nv;
+
+enum FieldType {
+    FLOAT,
+    DOUBLE,
+    UCHAR,
+    SHORT,
+    USHORT,
+    INT,
+    UINT
+};
+
+static inline int typeSize(FieldType type)
+{
+    switch (type) {
+    case FLOAT:
+        return sizeof(float);
+    case DOUBLE:
+        return sizeof(double);
+    case UCHAR:
+        return sizeof(unsigned char);
+    case SHORT:
+        return sizeof(short);
+    case USHORT:
+        return sizeof(unsigned short);
+    case INT:
+        return sizeof(int);
+    case UINT:
+        return sizeof(unsigned int);
+    default:
+        return 0;
+    }
+}
+
+static inline void allocFieldData(void **data, int npts, FieldType type)
+{
+    switch (type) {
+    case FLOAT:
+        *data = (float *)(new float[npts]);
+        break;
+    case DOUBLE:
+        *data = (double *)(new double[npts]);
+        break;
+    case UCHAR:
+        *data = (unsigned char *)(new unsigned char[npts]);
+        break;
+    case SHORT:
+        *data = (short *)(new short[npts]);
+        break;
+    case USHORT:
+        *data = (unsigned short *)(new unsigned short[npts]);
+        break;
+    case INT:
+        *data = (int *)(new int[npts]);
+        break;
+    case UINT:
+        *data = (unsigned int *)(new unsigned int[npts]);
+        break;
+    default:
+        ;
+    }
+}
+
+static inline void readFieldValue(void *data, int idx, FieldType type, std::iostream& fin)
+{
+    switch (type) {
+    case FLOAT: {
+        float val;
+        fin >> val;
+        ((float *)data)[idx] = val;
+    }
+        break;
+    case DOUBLE: {
+        double val;
+        fin >> val;
+        ((double *)data)[idx] = val;
+    }
+        break;
+    case SHORT: {
+        short val;
+        fin >> val;
+        ((short *)data)[idx] = val;
+    }
+        break;
+    case USHORT: {
+        unsigned short val;
+        fin >> val;
+        ((unsigned short *)data)[idx] = val;
+    }
+        break;
+    case INT: {
+        int val;
+        fin >> val;
+        ((int *)data)[idx] = val;
+    }
+        break;
+    case UINT: {
+        unsigned int val;
+        fin >> val;
+        ((unsigned int *)data)[idx] = val;
+    }
+        break;
+    default:
+        break;
+    }
+
+}
+
+static inline float getFieldData(void *data, int i, FieldType type)
+{
+    switch (type) {
+    case FLOAT:
+        return ((float *)data)[i];
+    case DOUBLE:
+        return (float)((double *)data)[i];
+    case UCHAR:
+        return ((float)((unsigned char *)data)[i]);
+    case SHORT:
+        return (float)((short *)data)[i];
+    case USHORT:
+        return (float)((unsigned short *)data)[i];
+    case INT:
+        return (float)((int *)data)[i];
+    case UINT:
+        return (float)((unsigned int *)data)[i];
+    default:
+        return 0.0f;
+    }
+}
+
+static inline void deleteFieldData(void *data, FieldType type)
+{
+    if (data == NULL)
+        return;
+    switch (type) {
+    case FLOAT:
+        delete [] ((float *)data);
+        break;
+    case DOUBLE:
+        delete [] ((double *)data);
+        break;
+    case UCHAR:
+        delete [] ((unsigned char *)data);
+        break;
+    case SHORT:
+        delete [] ((short *)data);
+        break;
+    case USHORT:
+        delete [] ((unsigned short *)data);
+        break;
+    case INT:
+        delete [] ((int *)data);
+        break;
+    case UINT:
+        delete [] ((unsigned int *)data);
+        break;
+    default:
+        ;
+    }
+}
+
+Volume *
+nv::load_vtk_volume_stream(const char *tag, std::iostream& fin)
+{
+    TRACE("Enter tag:%s", tag);
+
+    int nx, ny, nz, npts;
+    // origin
+    double x0, y0, z0;
+    // deltas (cell dimensions)
+    double dx, dy, dz;
+    // length of volume edges
+    double lx, ly, lz;
+    char line[128], str[128], type[128], *start;
+    int isBinary = -1;
+    int isRect = -1;
+    FieldType ftype = DOUBLE;
+    void *fieldData = NULL;
+    int numRead = 0;
+
+    dx = dy = dz = 0.0;
+    x0 = y0 = z0 = 0.0;
+    nx = ny = nz = npts = 0;
+    while (!fin.eof()) {
+        fin.getline(line, sizeof(line) - 1);
+        if (fin.fail()) {
+            ERROR("Error in data stream");
+            return NULL;
+        }
+        for (start = line; *start == ' ' || *start == '\t'; start++)
+            ;  // skip leading blanks
+
+        if (*start != '#') {  // skip comment lines
+            if (strncmp(start, "BINARY", 6) == 0) {
+                isBinary = 1;
+            } else if (strncmp(start, "ASCII", 5) == 0) {
+                isBinary = 0;
+            } else if (sscanf(start, "DATASET %s", str) == 1) {
+                if (strncmp(str, "STRUCTURED_POINTS", 17) == 0) {
+                    isRect = 1;
+                } else {
+                    ERROR("Unsupported DataSet type '%s'", str);
+                    return NULL;
+                }
+            } else if (sscanf(start, "DIMENSIONS %d %d %d", &nx, &ny, &nz) == 3) {
+                if (nx <= 0 || ny <= 0 || nz <= 0) {
+                    ERROR("Found non-positive dimensions");
+                    return NULL;
+                }
+                // found dimensions
+            } else if (sscanf(start, "ORIGIN %lg %lg %lg", &x0, &y0, &z0) == 3) {
+                // found origin
+            } else if (sscanf(start, "SPACING %lg %lg %lg", &dx, &dy, &dz) == 3) {
+                if ((nx > 1 && dx == 0.0) || (ny > 1 && dy == 0.0) || (nz > 1 && dz == 0.0)) {
+                    ERROR("Found zero spacing for dimension");
+                    return NULL;
+                }
+                // found cell spacing
+            } else if (sscanf(start, "POINT_DATA %d", &npts) == 1) {
+                if (npts < 1 || npts != nx * ny * nz) {
+                    ERROR("Error in data stream: unexpected number of point data: %d", npts);
+                    return NULL;
+                }
+                if (isBinary < 0 || fin.eof()) {
+                    // Should know if ASCII or BINARY by now
+                    ERROR("Error in data stream");
+                    return NULL;
+                }
+                fin.getline(line, sizeof(line) - 1);
+                if (fin.fail()) {
+                    ERROR("Error in data stream");
+                    return NULL;
+                }
+                for (start = line; *start == ' ' || *start == '\t'; start++)
+                    ;  // skip leading blanks
+                if (sscanf(start, "SCALARS %s %s", str, type) != 2) {
+                    ERROR("Error in data stream");
+                    return NULL;
+                }
+                if (strncmp(type, "double", 6) == 0) {
+                    ftype = DOUBLE;
+                } else if (strncmp(type, "float", 5) == 0) {
+                    ftype = FLOAT;
+                } else if (strncmp(type, "unsigned_char", 13) == 0) {
+                    ftype = UCHAR;
+                    if (!isBinary) {
+                        ERROR("unsigned char only supported in binary VTK files");
+                        return NULL;
+                    }
+                } else if (strncmp(type, "short", 5) == 0) {
+                    ftype = SHORT;
+                } else if (strncmp(type, "unsigned_short", 14) == 0) {
+                    ftype = USHORT;
+                } else if (strncmp(type, "int", 3) == 0) {
+                    ftype = INT;
+                } else if (strncmp(type, "unsigned_int", 12) == 0) {
+                    ftype = UINT;
+                } else {
+                    ERROR("Unsupported scalar type: '%s'", type);
+                    return NULL;
+                }
+                if (fin.eof()) {
+                    ERROR("Error in data stream");
+                    return NULL;
+                }
+                fin.getline(line, sizeof(line) - 1);
+                if (fin.fail()) {
+                    ERROR("Error in data stream");
+                    return NULL;
+                }
+                for (start = line; *start == ' ' || *start == '\t'; start++)
+                    ;  // skip leading blanks
+                if (sscanf(start, "LOOKUP_TABLE %s", str) == 1) {
+                    // skip lookup table, but don't read ahead
+                    if (fin.eof()) {
+                        ERROR("Error in data stream");
+                        return NULL;
+                    }
+                } else {
+                    // Lookup table line is required
+                    ERROR("Missing LOOKUP_TABLE");
+                    return NULL;
+                }
+                // found start of field data
+                allocFieldData(&fieldData, npts, ftype);
+                if (isBinary) {
+                    fin.read((char *)fieldData, npts * typeSize(ftype));
+                    if (fin.fail()) {
+                        deleteFieldData(fieldData, ftype);
+                        ERROR("Error in data stream");
+                        return NULL;
+                    }
+                    numRead = npts;
+                } else {
+                    numRead = 0;
+                    while (!fin.eof() && numRead < npts) {
+                        readFieldValue(fieldData, numRead++, ftype, fin);
+                        if (fin.fail()) {
+                            deleteFieldData(fieldData, ftype);
+                            ERROR("Error in data stream");
+                            return NULL;
+                        }
+                    }
+                }
+                
+                break;
+            }
+        }
+    }
+
+    if (isRect < 0 || numRead != npts || npts < 1) {
+        deleteFieldData(fieldData, ftype);
+        ERROR("Error in data stream");
+        return NULL;
+    }
+
+    TRACE("found nx=%d ny=%d nz=%d\ndx=%f dy=%f dz=%f\nx0=%f y0=%f z0=%f", 
+          nx, ny, nz, dx, dy, dz, x0, y0, z0);
+
+    lx = (nx - 1) * dx;
+    ly = (ny - 1) * dy;
+    lz = (nz - 1) * dz;
+
+    Volume *volume = NULL;
+    double vmin = DBL_MAX;
+    double nzero_min = DBL_MAX;
+    double vmax = -DBL_MAX;
+    float *data = NULL;
+
+    if (isRect) {
+#ifdef DOWNSAMPLE_DATA
+        Rappture::Mesh1D xgrid(x0, x0 + lx, nx);
+        Rappture::Mesh1D ygrid(y0, y0 + ly, ny);
+        Rappture::Mesh1D zgrid(z0, z0 + lz, nz);
+        Rappture::FieldRect3D field(xgrid, ygrid, zgrid);
+#else // !DOWNSAMPLE_DATA
+        data = new float[npts * 4];
+        memset(data, 0, npts * 4);
+#endif // DOWNSAMPLE_DATA
+        for (int p = 0; p < npts; p++) {
+#ifdef DOWNSAMPLE_DATA
+            field.define(p, getFieldData(fieldData, p, ftype));
+#else // !DOWNSAMPLE_DATA
+            int nindex = p * 4;
+            data[nindex] = getFieldData(fieldData, p, ftype);
+            if (data[nindex] < vmin) {
+                vmin = data[nindex];
+            } else if (data[nindex] > vmax) {
+                vmax = data[nindex];
+            }
+            if (data[nindex] != 0.0 && data[nindex] < nzero_min) {
+                nzero_min = data[nindex];
+            }
+#endif // DOWNSAMPLE_DATA
+        }
+
+        deleteFieldData(fieldData, ftype);
+
+#ifndef DOWNSAMPLE_DATA
+
+        // scale all values [0-1], -1 => out of bounds
+        normalizeScalar(data, npts, 4, vmin, vmax);
+        computeSimpleGradient(data, nx, ny, nz,
+                              dx, dy, dz);
+#else // DOWNSAMPLE_DATA
+        // figure out a good mesh spacing
+        int nsample = 64;
+        double dmin = pow((lx*ly*lz)/((nsample-1)*(nsample-1)*(nsample-1)), 0.333);
+
+        nx = (int)ceil(lx/dmin) + 1;
+        ny = (int)ceil(ly/dmin) + 1;
+        nz = (int)ceil(lz/dmin) + 1;
+
+#ifndef HAVE_NPOT_TEXTURES
+        // must be an even power of 2 for older cards
+        nx = (int)pow(2.0, ceil(log10((double)nx)/log10(2.0)));
+        ny = (int)pow(2.0, ceil(log10((double)ny)/log10(2.0)));
+        nz = (int)pow(2.0, ceil(log10((double)nz)/log10(2.0)));
+#endif
+
+        dx = lx /(double)(nx - 1);
+        dy = ly /(double)(ny - 1);
+        dz = lz /(double)(nz - 1);
+
+        vmin = field.valueMin();
+        vmax = field.valueMax();
+        nzero_min = DBL_MAX;
+        double dv = vmax - vmin;
+        if (dv == 0.0) {
+            dv = 1.0;
+        }
+
+        int ngen = 0;
+#ifdef FILTER_GRADIENTS
+        // Sobel filter expects a single float at
+        // each node
+        const int step = 1;
+        float *cdata = new float[npts * step];
+#else // !FILTER_GRADIENTS
+        // Leave 3 floats of space for gradients
+        // to be filled in by computeSimpleGradient()
+        const int step = 4;
+        data = new float[npts * step];
+#endif // FILTER_GRADIENTS
+
+        for (int iz = 0; iz < nz; iz++) {
+            double zval = z0 + iz*dz;
+            for (int iy = 0; iy < ny; iy++) {
+                double yval = y0 + iy*dy;
+                for (int ix = 0; ix < nx; ix++) {
+                    double xval = x0 + ix*dx;
+                    double v = field.value(xval, yval, zval);
+#ifdef notdef
+                    if (isnan(v)) {
+                        TRACE("NAN at %d,%d,%d: (%g, %g, %g)", ix, iy, iz, xval, yval, zval);
+                    }
+#endif
+                    if (v != 0.0 && v < nzero_min) {
+                        nzero_min = v;
+                    }
+#ifdef FILTER_GRADIENTS
+                    // NOT normalized, may have NaNs (FIXME: how does gradient filter handle NaN?)
+                    cdata[ngen] = v;
+#else // !FILTER_GRADIENTS
+                    // scale all values [0-1], -1 => out of bounds
+                    v = (isnan(v)) ? -1.0 : (v - vmin)/dv;
+                    data[ngen] = v;
+#endif // FILTER_GRADIENTS
+                    ngen += step;
+                }
+            }
+        }
+#ifdef FILTER_GRADIENTS
+        // computeGradient returns a new array with gradients
+        // filled in, so data is now 4 floats per node
+        data = computeGradient(cdata, nx, ny, nz,
+                               dx, dy, dz,
+                               vmin, vmax);
+        delete [] cdata;
+#else // !FILTER_GRADIENTS
+        computeSimpleGradient(data, nx, ny, nz,
+                              dx, dy, dz);
+#endif // FILTER_GRADIENTS
+
+#endif // DOWNSAMPLE_DATA
+    } else {
+        deleteFieldData(fieldData, ftype);
+        ERROR("Unsupported DataSet");
+        return NULL;
+    }
+
+    TRACE("nx = %i ny = %i nz = %i", nx, ny, nz);
+    TRACE("x0 = %lg y0 = %lg z0 = %lg", x0, y0, z0);
+    TRACE("lx = %lg ly = %lg lz = %lg", lx, ly, lz);
+    TRACE("dx = %lg dy = %lg dz = %lg", dx, dy, dz);
+    TRACE("dataMin = %lg dataMax = %lg nzero_min = %lg",
+          vmin, vmax, nzero_min);
+
+    volume = NanoVis::loadVolume(tag, nx, ny, nz, 4, data,
+                                 vmin, vmax, nzero_min);
+    volume->xAxis.setRange(x0, x0 + lx);
+    volume->yAxis.setRange(y0, y0 + ly);
+    volume->zAxis.setRange(z0, z0 + lz);
+    volume->updatePending = true;
+
+    delete [] data;
+
+    //
+    // Center this new volume on the origin.
+    //
+    float dx0 = -0.5;
+    float dy0 = -0.5*ly/lx;
+    float dz0 = -0.5*lz/lx;
+    if (volume) {
+        volume->setPosition(vrmath::Vector3f(dx0, dy0, dz0));
+        TRACE("Set volume position to %g %g %g", dx0, dy0, dz0);
+    }
+    return volume;
+}
Index: /nanovis/tags/1.1.4/VtkReader.h
===================================================================
--- /nanovis/tags/1.1.4/VtkReader.h	(revision 4930)
+++ /nanovis/tags/1.1.4/VtkReader.h	(revision 4930)
@@ -0,0 +1,20 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#ifndef NV_VTKREADER_H
+#define NV_VTKREADER_H
+
+#include <iostream>
+
+namespace nv {
+
+class Volume;
+
+extern Volume *
+load_vtk_volume_stream(const char *tag, std::iostream& fin);
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/ZincBlendeReconstructor.cpp
===================================================================
--- /nanovis/tags/1.1.4/ZincBlendeReconstructor.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/ZincBlendeReconstructor.cpp	(revision 4930)
@@ -0,0 +1,485 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ * 
+ * Authors:
+ *   Insoo Woo <iwoo@purdue.edu>
+ */
+#include <cstdio>
+#include <cstring>
+#include <cstdlib>
+#include <fstream>
+
+#include <vrmath/Vector3f.h>
+
+#include "ZincBlendeReconstructor.h"
+#include "ZincBlendeVolume.h"
+#include "Trace.h"
+
+using namespace nv;
+using namespace vrmath;
+
+ZincBlendeReconstructor *ZincBlendeReconstructor::_instance = NULL;
+
+ZincBlendeReconstructor::ZincBlendeReconstructor()
+{
+}
+
+ZincBlendeReconstructor::~ZincBlendeReconstructor()
+{
+}
+
+ZincBlendeReconstructor *ZincBlendeReconstructor::getInstance()
+{
+    if (_instance == NULL) {
+        return (_instance = new ZincBlendeReconstructor());
+    }
+
+    return _instance;
+}
+
+ZincBlendeVolume *ZincBlendeReconstructor::loadFromFile(const char *fileName)
+{
+    std::ifstream stream;
+    stream.open(fileName, std::ios::binary);
+
+    ZincBlendeVolume *volume = loadFromStream(stream);
+
+    stream.close();
+
+    return volume;
+}
+
+ZincBlendeVolume *ZincBlendeReconstructor::loadFromStream(std::istream& stream)
+{
+    ZincBlendeVolume *volume = NULL;
+    Vector3f origin, delta;
+    int width = 0, height = 0, depth = 0;
+    void *data = NULL;
+    int version = 1;
+
+    char str[5][20];
+    do {
+        getLine(stream);
+        if (_buff[0] == '#') {
+            continue;
+        } else if (strstr((const char*) _buff, "object") != 0) {
+            TRACE("VERSION 1");
+            version = 1;
+            break;
+        } else if (strstr(_buff, "record format") != 0) {
+            TRACE("VERSION 2");
+            version = 2;
+            break;
+        }
+    } while (1);
+
+    if (version == 1) {
+	float dummy;
+
+        sscanf(_buff, "%s%s%s%s%s%d%d%d", str[0], str[1], str[2], str[3], str[4], &width, &height, &depth);
+        getLine(stream); 
+        sscanf(_buff, "%s%f%f%f", str[0], &(origin.x), &(origin.y), &(origin.z));
+        getLine(stream); 
+        sscanf(_buff, "%s%f%f%f", str[0], &(delta.x), &dummy, &dummy);
+        getLine(stream); 
+        sscanf(_buff, "%s%f%f%f", str[0], &dummy, &(delta.y), &dummy);
+        getLine(stream); 
+        sscanf(_buff, "%s%f%f%f", str[0], &dummy, &dummy, &(delta.z));
+        do {
+            getLine(stream);
+        } while (strcmp(_buff, "<\\HDR>") != 0);
+
+        width = width / 4;
+        height = height / 4;
+        depth = depth / 4;
+        //data = new double[width * height * depth * 8 * 4]; 
+        data = malloc(width * height * depth * 8 * 4 * sizeof(double)); 
+        // 8 atom per cell, 4 double (x, y, z, and probability) per atom
+        try {
+            stream.read((char *)data, width * height * depth * 8 * 4 * sizeof(double));
+        } catch (...) {
+            ERROR("Caught exception trying to read stream");
+        }
+
+        volume = buildUp(origin, delta, width, height, depth, data);
+
+        free(data);
+    } else if (version == 2) {
+        const char *pt;
+        int datacount;
+        double emptyvalue;
+        do {
+            getLine(stream);
+            if ((pt = strstr(_buff, "delta")) != 0) {
+                sscanf(pt, "%s%f%f%f", str[0], &(delta.x), &(delta.y), &(delta.z));
+#ifdef _LOADER_DEBUG_
+                TRACE("delta : %f %f %f", delta.x, delta.y, delta.z);
+#endif
+            } else if ((pt = strstr(_buff, "datacount")) != 0) {
+                sscanf(pt, "%s%d", str[0], &datacount);
+#ifdef _LOADER_DEBUG_
+                TRACE("datacount = %d", datacount);
+#endif
+            } else if ((pt = strstr(_buff, "datatype")) != 0) {
+                sscanf(pt, "%s%s", str[0], str[1]);
+                if (strcmp(str[1], "double64")) {
+                }
+            } else if ((pt = strstr(_buff, "count")) != 0) {
+                sscanf(pt, "%s%d%d%d", str[0], &width, &height, &depth);
+#ifdef _LOADER_DEBUG_
+                TRACE("width height depth %d %d %d", width, height, depth);
+#endif
+            } else if ((pt = strstr(_buff, "emptymark")) != 0) {
+                sscanf(pt, "%s%lf", str[0], &emptyvalue);
+#ifdef _LOADER_DEBUG_
+                TRACE("emptyvalue %lf", emptyvalue);
+#endif
+            }
+        } while (strcmp(_buff, "<\\HDR>") != 0 && strcmp(_buff, "</HDR>") != 0);
+
+        data = malloc(width * height * depth * 8 * 4 * sizeof(double)); 
+        memset(data, 0, width * height * depth * 8 * 4 * sizeof(double)); 
+        stream.read((char *) data, width * height * depth * 8 * 4 * sizeof(double));
+
+        volume =  buildUp(origin, delta, width, height, depth, datacount, emptyvalue, data);
+        free(data);
+    }
+    return volume;
+}
+
+struct _NvAtomInfo {
+    double indexX, indexY, indexZ;
+    double atom;
+
+    int getIndex(int width, int height) const 
+    {
+        // NOTE 
+        // Zinc blende data has different axes from OpenGL
+        // + z -> +x (OpenGL)
+        // + x -> +y (OpenGL)
+        // + y -> +z (OpenGL), But in 3D texture coordinate is the opposite direction of z 
+        // The reason why index is multiplied by 4 is that one unit cell has half of eight atoms,
+        // i.e. four atoms are mapped into RGBA component of one texel
+        //return ((int) (indexZ - 1)+ (int) (indexX - 1) * width + (int) (indexY - 1) * width * height) * 4;
+        return ((int)(indexX - 1) + (int)(indexY - 1) * width + (int)(indexZ - 1) * width * height) * 4;
+    }
+};
+
+template<class T>
+inline T _NvMax2(T a, T b)
+{ return ((a >= b)? a : b); }
+
+template<class T>
+inline T _NvMin2(T a, T b)
+{ return ((a >= b)? a : b); }
+
+template<class T>
+inline T _NvMax3(T a, T b, T c)
+{ return ((a >= b)? ((a >= c) ? a : c) : ((b >= c)? b : c)); }
+
+template<class T>
+inline T _NvMin3(T a, T b, T c)
+{ return ((a <= b)? ((a <= c) ? a : c) : ((b <= c)? b : c)); }
+
+template<class T>
+inline T _NvMax9(T* a, T curMax)
+{ return _NvMax3(_NvMax3(a[0], a[1], a[2]), _NvMax3(a[3], a[4], a[5]), _NvMax3(a[6], a[7], curMax)); }
+
+template<class T>
+inline T _NvMin9(T* a, T curMax)
+{ return _NvMin3(_NvMax3(a[0], a[1], a[2]), _NvMin3(a[3], a[4], a[5]), _NvMin3(a[6], a[7], curMax)); }
+
+template<class T>
+inline T _NvMax4(T* a)
+{ return _NvMax2(_NvMax2(a[0], a[1]), _NvMax2(a[2], a[3])); }
+
+template<class T>
+inline T _NvMin4(T* a)
+{ return _NvMin2(_NvMin2(a[0], a[1]), _NvMin2(a[2], a[3])); }
+
+ZincBlendeVolume * 
+ZincBlendeReconstructor::buildUp(const Vector3f& origin, const Vector3f& delta,
+                                   int width, int height, int depth, void *data)
+{
+    ZincBlendeVolume *zincBlendeVolume = NULL;
+
+    float *fourAnionVolume, *fourCationVolume;
+    int cellCount = width * height * depth;
+    fourAnionVolume = new float[cellCount * sizeof(float) * 4];
+    fourCationVolume = new float[cellCount * sizeof(float) * 4];
+
+    _NvAtomInfo *srcPtr = (_NvAtomInfo *)data;
+
+    float vmin, vmax, nzero_min;
+    float *component4A, *component4B;
+    int index;
+
+    nzero_min = 0.0f;		/* Suppress compiler warning. */
+    vmin = vmax = srcPtr->atom;
+
+    for (int i = 0; i < cellCount; ++i) {
+        index = srcPtr->getIndex(width, height);
+
+#ifdef _LOADER_DEBUG_
+        TRACE("index %d", index);
+#endif
+
+        component4A = fourAnionVolume + index;
+        component4B = fourCationVolume + index;
+
+        component4A[0] = (float)srcPtr->atom; srcPtr++;
+        component4A[1] = (float)srcPtr->atom; srcPtr++;
+        component4A[2] = (float)srcPtr->atom; srcPtr++;
+        component4A[3] = (float)srcPtr->atom; srcPtr++;
+      
+        component4B[0] = (float)srcPtr->atom; srcPtr++;
+        component4B[1] = (float)srcPtr->atom; srcPtr++;
+        component4B[2] = (float)srcPtr->atom; srcPtr++;
+        component4B[3] = (float)srcPtr->atom; srcPtr++;
+
+        vmax = _NvMax3(_NvMax4(component4A), _NvMax4(component4B), vmax);
+        vmin = _NvMin3(_NvMin4(component4A), _NvMin4(component4B), vmin);
+
+        if (vmin != 0.0 && vmin < nzero_min) {
+            nzero_min = vmin;
+        }
+    }
+
+    double dv = vmax - vmin;
+    if (vmax != 0.0f) {
+        for (int i = 0; i < cellCount; ++i) {
+            fourAnionVolume[i] = (fourAnionVolume[i] - vmin)/ dv;
+            fourCationVolume[i] = (fourCationVolume[i] - vmin) / dv;
+        }
+    }
+
+    Vector3f cellSize;
+    cellSize.x = 0.25 / width;
+    cellSize.y = 0.25 / height;
+    cellSize.z = 0.25 / depth;
+
+    zincBlendeVolume = new ZincBlendeVolume(origin.x, origin.y, origin.z,
+                                            width, height, depth, 4,
+                                            fourAnionVolume, fourCationVolume,
+                                            vmin, vmax, nzero_min, cellSize);
+
+    return zincBlendeVolume;
+}
+
+ZincBlendeVolume *
+ZincBlendeReconstructor::buildUp(const Vector3f& origin, const Vector3f& delta,
+                                   int width, int height, int depth,
+                                   int datacount, double emptyvalue, void* data)
+{
+    ZincBlendeVolume *zincBlendeVolume = NULL;
+    float *fourAnionVolume, *fourCationVolume;
+    int size = width * height * depth * 4;
+    fourAnionVolume = new float[size];
+    fourCationVolume = new float[size];
+
+    memset(fourAnionVolume, 0, size * sizeof(float));
+    memset(fourCationVolume, 0, size * sizeof(float));
+
+    _NvAtomInfo *srcPtr = (_NvAtomInfo *) data;
+
+    float *component4A, *component4B;
+    float vmin, vmax, nzero_min;
+    int index;
+    nzero_min = 1e23f;
+    vmin = vmax = srcPtr->atom;
+    for (int i = 0; i < datacount; ++i) {
+        index = srcPtr->getIndex(width, height);
+
+#ifdef _LOADER_DEBUG_
+        TRACE("[%d] index %d (width:%lf height:%lf depth:%lf)", i, index, srcPtr->indexX, srcPtr->indexY, srcPtr->indexZ);
+#endif
+
+        if (index < 0) {
+#ifdef _LOADER_DEBUG_
+            TRACE("There is an invalid data");
+#endif
+            srcPtr +=8;
+            continue;
+        }
+
+        component4A = fourAnionVolume + index;
+        component4B = fourCationVolume + index;
+
+        component4A[0] = (srcPtr->atom != emptyvalue)? (float) srcPtr->atom : 0.0f; srcPtr++;
+        component4A[1] = (srcPtr->atom != emptyvalue)? (float) srcPtr->atom : 0.0f; srcPtr++;
+        component4A[2] = (srcPtr->atom != emptyvalue)? (float) srcPtr->atom : 0.0f; srcPtr++;
+        component4A[3] = (srcPtr->atom != emptyvalue)? (float) srcPtr->atom : 0.0f; srcPtr++;
+      
+        component4B[0] = (srcPtr->atom != emptyvalue)? (float) srcPtr->atom : 0.0f; srcPtr++;
+        component4B[1] = (srcPtr->atom != emptyvalue)? (float) srcPtr->atom : 0.0f; srcPtr++;
+        component4B[2] = (srcPtr->atom != emptyvalue)? (float) srcPtr->atom : 0.0f; srcPtr++;
+        component4B[3] = (srcPtr->atom != emptyvalue)? (float) srcPtr->atom : 0.0f; srcPtr++;
+
+        vmax = _NvMax3(_NvMax4(component4A), _NvMax4(component4B), vmax);
+        vmin = _NvMin3(_NvMin4(component4A), _NvMin4(component4B), vmin);
+
+        if (vmin != 0.0 && vmin < nzero_min) {
+            nzero_min = vmin;    
+        }
+    }
+
+    double dv = vmax - vmin;
+    if (vmax != 0.0f) {
+        for (int i = 0; i < datacount; ++i) {
+            fourAnionVolume[i] = (fourAnionVolume[i] - vmin)/ dv;
+            fourCationVolume[i] = (fourCationVolume[i] - vmin) / dv;
+        }
+    }
+
+    Vector3f cellSize;
+    cellSize.x = 0.25 / width;
+    cellSize.y = 0.25 / height;
+    cellSize.z = 0.25 / depth;
+
+    zincBlendeVolume = new ZincBlendeVolume(origin.x, origin.y, origin.z,
+                                            width, height, depth, 4,
+                                            fourAnionVolume, fourCationVolume,
+                                            vmin, vmax, nzero_min, cellSize);
+
+    return zincBlendeVolume;
+}
+
+void ZincBlendeReconstructor::getLine(std::istream& sin)
+{
+    char ch;
+    int index = 0;
+    do {
+        sin.get(ch);
+        if (ch == '\n') break;
+        _buff[index++] = ch;
+        if (ch == '>') {
+            if (_buff[1] == '\\')
+                break;
+        }
+    } while (!sin.eof());
+
+    _buff[index] = '\0';
+
+#ifdef _LOADER_DEBUG_
+    TRACE("%s", _buff);
+#endif
+}
+
+ZincBlendeVolume *
+ZincBlendeReconstructor::loadFromMemory(const void *dataBlock)
+{
+    ZincBlendeVolume *volume = NULL;
+    Vector3f origin, delta;
+    int width = 0, height = 0, depth = 0;
+    void *data = NULL;
+    int version = 1;
+
+    const unsigned char *stream = (const unsigned char *)dataBlock;
+    char str[5][20];
+    do {
+        getLine(stream);
+        if (_buff[0] == '#') {
+            continue;
+        } else if (strstr((const char *)_buff, "object") != 0) {
+            TRACE("VERSION 1");
+            version = 1; 
+            break;
+        } else if (strstr(_buff, "record format") != 0) {
+            TRACE("VERSION 2");
+            version = 2; 
+            break;
+        }
+    } while (1);
+
+    if (version == 1) {
+	float dummy;
+
+        sscanf(_buff, "%s%s%s%s%s%d%d%d", str[0], str[1], str[2], str[3], str[4],&width, &height, &depth);
+        getLine(stream); 
+        sscanf(_buff, "%s%f%f%f", str[0], &(origin.x), &(origin.y), &(origin.z));
+        getLine(stream); 
+        sscanf(_buff, "%s%f%f%f", str[0], &(delta.x), &dummy, &dummy);
+        getLine(stream); 
+        sscanf(_buff, "%s%f%f%f", str[0], &dummy, &(delta.y), &dummy);
+        getLine(stream); 
+        sscanf(_buff, "%s%f%f%f", str[0], &dummy, &dummy, &(delta.z));
+        do {
+            getLine(stream);
+        } while (strcmp(_buff, "<\\HDR>") != 0);
+
+        width = width / 4;
+        height = height / 4;
+        depth = depth / 4;
+        data = malloc(width * height * depth * 8 * 4 * sizeof(double)); 
+        // 8 atom per cell, 4 double (x, y, z, and probability) per atom
+        memcpy(data, stream, width * height * depth * 8 * 4 * sizeof(double));
+
+        volume = buildUp(origin, delta, width, height, depth, data);
+
+        free(data);
+    } else if (version == 2) {
+        const char *pt;
+        int datacount = -1;
+        double emptyvalue;
+        do {
+            getLine(stream);
+            if ((pt = strstr(_buff, "delta")) != 0) {   
+                sscanf(pt, "%s%f%f%f", str[0], &(delta.x), &(delta.y), &(delta.z));
+#ifdef _LOADER_DEBUG_
+                TRACE("delta : %f %f %f", delta.x, delta.y, delta.z);
+#endif
+            } else if ((pt = strstr(_buff, "datacount")) != 0) {
+                sscanf(pt, "%s%d", str[0], &datacount);
+                TRACE("datacount = %d", datacount);
+            } else if ((pt = strstr(_buff, "datatype")) != 0) {
+                sscanf(pt, "%s%s", str[0], str[1]);
+                if (strcmp(str[1], "double64")) {
+                }
+            } else if ((pt = strstr(_buff, "count")) != 0) {
+                sscanf(pt, "%s%d%d%d", str[0], &width, &height, &depth);
+#ifdef _LOADER_DEBUG_
+                TRACE("width height depth %d %d %d", width, height, depth);
+#endif
+            } else if ((pt = strstr(_buff, "emptymark")) != 0) {
+                sscanf(pt, "%s%lf", str[0], &emptyvalue);
+#ifdef _LOADER_DEBUG_
+                TRACE("emptyvalue %lf", emptyvalue);
+#endif
+            }
+        } while (strcmp(_buff, "<\\HDR>") != 0 && strcmp(_buff, "</HDR>") != 0);
+
+        if (datacount == -1) datacount = width * height * depth;
+
+        data = malloc(datacount * 8 * 4 * sizeof(double)); 
+        memset(data, 0, datacount * 8 * 4 * sizeof(double)); 
+        memcpy(data, stream, datacount * 8 * 4 * sizeof(double));
+
+        volume =  buildUp(origin, delta, width, height, depth, datacount, emptyvalue, data);
+
+        free(data);
+    }
+    return volume;
+}
+
+void ZincBlendeReconstructor::getLine(const unsigned char*& stream)
+{
+    char ch;
+    int index = 0;
+    do {
+        ch = stream[0];
+        ++stream;
+        if (ch == '\n') break;
+        _buff[index++] = ch;
+        if (ch == '>') {
+            if (_buff[1] == '\\')
+                break;
+        }
+    } while (1);
+
+    _buff[index] = '\0';
+
+#ifdef _LOADER_DEBUG_
+    TRACE("%s", _buff);
+#endif
+}
Index: /nanovis/tags/1.1.4/ZincBlendeReconstructor.h
===================================================================
--- /nanovis/tags/1.1.4/ZincBlendeReconstructor.h	(revision 4930)
+++ /nanovis/tags/1.1.4/ZincBlendeReconstructor.h	(revision 4930)
@@ -0,0 +1,76 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/**
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ * 
+ * Authors:
+ *   Insoo Woo <iwoo@purdue.edu>
+ */
+#ifndef NV_ZINC_BLENDE_RECONSTRUCTOR_H
+#define NV_ZINC_BLENDE_RECONSTRUCTOR_H
+
+#include <istream>
+
+#include <vrmath/Vector3f.h>
+
+namespace nv {
+
+class ZincBlendeVolume;
+
+class ZincBlendeReconstructor
+{
+public:
+    /**
+     * @brief Load Zinc blende binary volume data and create ZincBlendeVolume with the file
+     * @param fileName Zinc blende file name, which data is generated by NEMO-3D
+     */
+    ZincBlendeVolume *loadFromFile(const char *fileName);
+
+    /**
+     * @brief Load Zinc blende binary volume data and create ZincBlendeVolume with the file
+     * @param stream Zinc blende binary volume data, which data is generated by NEMO-3D and transferred from nanoscale
+     */
+    ZincBlendeVolume *loadFromStream(std::istream& stream);
+
+    ZincBlendeVolume *loadFromMemory(const void *dataBlock);
+
+    /**
+     * @brief Create ZincBlendVolume with output data of NEMO-3D
+     * @param origin the start position of the volume data
+     * @param delta  the delta value among atoms
+     * @param width  the width of unit cells in the data
+     * @param height the height of unit cells in the data
+     * @param depth  the depth of unit cells in the data
+     * @param data the memory block of output data of NEMO-3D
+     */
+    ZincBlendeVolume *buildUp(const vrmath::Vector3f& origin, const vrmath::Vector3f& delta,
+                              int width, int height, int depth, void *data);
+
+    ZincBlendeVolume *buildUp(const vrmath::Vector3f& origin, const vrmath::Vector3f& delta,
+                              int width, int height, int depth,
+                              int datacount, double emptyvalue, void *data);
+
+    /**
+     * @brief Return a singleton instance
+     */
+    static ZincBlendeReconstructor *getInstance();
+
+private:
+    ZincBlendeReconstructor();
+
+    ~ZincBlendeReconstructor();
+
+    /**
+     * @brief Get a line from file. It is used for reading header because header is written in ascii.
+     */
+    void getLine(std::istream& stream);
+    void getLine(const unsigned char*& stream);
+
+    char _buff[255];
+
+    /// A ZincBlendeReconstructor Singleton instance
+    static ZincBlendeReconstructor *_instance;
+};
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/ZincBlendeVolume.cpp
===================================================================
--- /nanovis/tags/1.1.4/ZincBlendeVolume.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/ZincBlendeVolume.cpp	(revision 4930)
@@ -0,0 +1,55 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * ----------------------------------------------------------------------
+ * ZincBlendeVolume.cpp: 3d zincblende volume class, a subclass of Volume.
+ * 			It contains two cubic volumes.
+ *
+ * ======================================================================
+ *  AUTHOR:  Wei Qiao <qiaow@purdue.edu>
+ *           Purdue Rendering and Perceptualization Lab (PURPL)
+ *
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ *  See the file "license.terms" for information on usage and
+ *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ * ======================================================================
+ */
+#include <assert.h>
+
+#include <vrmath/Vector3f.h>
+
+#include "ZincBlendeVolume.h"
+
+using namespace nv;
+using namespace vrmath;
+
+ZincBlendeVolume::ZincBlendeVolume(float x, float y, float z,
+                                   int width, int height, int depth,
+                                   int numComponents, 
+                                   float *dataVolumeA, float *dataVolumeB,
+                                   double vmin, double vmax, double nonZeroMin,
+                                   const Vector3f& cellSz) :
+    Volume(x, y, z, width, height, depth, numComponents, dataVolumeA, vmin, vmax, nonZeroMin),
+    cellSize(cellSz)
+{
+    //label it as zincblende
+    _volumeType = ZINCBLENDE;
+
+    //store member tex initialize in Volume() as zincblendeTex[0]
+    assert(_tex);
+    zincblendeTex[0] = _tex;
+
+    //now add another tex as zincblendeTex[1]
+    Texture3D *secondTex = new Texture3D(width, height, depth, GL_FLOAT, GL_LINEAR, numComponents);
+    assert(secondTex);
+    secondTex->initialize(dataVolumeB);
+
+    zincblendeTex[1] = secondTex;
+}
+
+ZincBlendeVolume::~ZincBlendeVolume()
+{ 
+    // First texture will be deleted in ~Volume()
+    if (zincblendeTex[1])
+	delete zincblendeTex[1];
+}
Index: /nanovis/tags/1.1.4/ZincBlendeVolume.h
===================================================================
--- /nanovis/tags/1.1.4/ZincBlendeVolume.h	(revision 4930)
+++ /nanovis/tags/1.1.4/ZincBlendeVolume.h	(revision 4930)
@@ -0,0 +1,37 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors:
+ *   Wei Qiao <qiaow@purdue.edu>
+ */
+#ifndef NV_ZINCBLENDE_VOLUME_H
+#define NV_ZINCBLENDE_VOLUME_H
+
+#include <vrmath/Vector3f.h>
+
+#include "Volume.h"
+
+namespace nv {
+
+/**
+ * \brief 3D ZincBlende volume, contains two cubic volumes
+ */
+class ZincBlendeVolume : public Volume
+{
+public:
+    ZincBlendeVolume(float x, float y, float z,
+                     int width, int height, int depth, int numComponents,
+                     float *dataVolumeA, float *dataVolumeB,
+                     double vmin, double vmax, double nonZeroMin,
+                     const vrmath::Vector3f& cellSize);
+
+    virtual ~ZincBlendeVolume();
+
+    Texture3D *zincblendeTex[2]; //the textures of two cubic volumes
+    vrmath::Vector3f cellSize;	//the cell size in texture space
+};
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/ZincBlendeVolumeShader.cpp
===================================================================
--- /nanovis/tags/1.1.4/ZincBlendeVolumeShader.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/ZincBlendeVolumeShader.cpp	(revision 4930)
@@ -0,0 +1,58 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+
+#include "ZincBlendeVolumeShader.h"
+#include "ZincBlendeVolume.h"
+
+using namespace nv;
+
+ZincBlendeVolumeShader::ZincBlendeVolumeShader()
+{
+    init();
+}
+
+ZincBlendeVolumeShader::~ZincBlendeVolumeShader()
+{
+}
+
+void ZincBlendeVolumeShader::init()
+{
+    loadFragmentProgram("zincblende_volume.cg");
+}
+
+void ZincBlendeVolumeShader::bind(unsigned int tfID, Volume *volume,
+                                    int sliceMode, float sampleRatio)
+{
+    ZincBlendeVolume *vol = (ZincBlendeVolume *)volume;
+    setGLStateMatrixFPParameter("modelViewInv", MODELVIEW_MATRIX,
+                                MATRIX_INVERSE);
+
+    setFPTextureParameter("tf", tfID);
+    setFPTextureParameter("volumeA", vol->zincblendeTex[0]->id());
+    setFPTextureParameter("volumeB", vol->zincblendeTex[1]->id());
+
+    setFPParameter4f("cellSize",
+                     vol->cellSize.x,
+                     vol->cellSize.y,
+                     vol->cellSize.z, 0.);
+
+    setFPParameter4f("renderParams",
+                     (sliceMode ? 0.0f : sampleRatio),
+                     volume->isosurface(),
+                     volume->opacityScale(),
+                     0.0f);
+
+    Shader::bind();
+}
+
+void ZincBlendeVolumeShader::unbind() 
+{
+    disableFPTextureParameter("tf");
+    disableFPTextureParameter("volumeA");
+    disableFPTextureParameter("volumeB");
+
+    Shader::unbind();
+}
Index: /nanovis/tags/1.1.4/ZincBlendeVolumeShader.h
===================================================================
--- /nanovis/tags/1.1.4/ZincBlendeVolumeShader.h	(revision 4930)
+++ /nanovis/tags/1.1.4/ZincBlendeVolumeShader.h	(revision 4930)
@@ -0,0 +1,31 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#ifndef NV_ZINCBLENDE_SHADER_H
+#define NV_ZINCBLENDE_SHADER_H
+
+#include "VolumeShader.h"
+
+namespace nv {
+
+class ZincBlendeVolumeShader : public VolumeShader
+{
+public:
+    ZincBlendeVolumeShader();
+
+    virtual ~ZincBlendeVolumeShader();
+
+    virtual void bind(unsigned int tfID, Volume *volume,
+                      int sliceMode, float sampleRatio);
+
+    virtual void unbind();
+
+private:
+    void init();
+};
+
+}
+
+#endif 
Index: /nanovis/tags/1.1.4/cf/install-sh
===================================================================
--- /nanovis/tags/1.1.4/cf/install-sh	(revision 4930)
+++ /nanovis/tags/1.1.4/cf/install-sh	(revision 4930)
@@ -0,0 +1,269 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+#
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.  It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+	-c) instcmd="$cpprog"
+	    shift
+	    continue;;
+
+	-d) dir_arg=true
+	    shift
+	    continue;;
+
+	-m) chmodcmd="$chmodprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-o) chowncmd="$chownprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-g) chgrpcmd="$chgrpprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-s) stripcmd="$stripprog"
+	    shift
+	    continue;;
+
+	-t=*) transformarg=`echo $1 | sed 's/-t=//'`
+	    shift
+	    continue;;
+
+	-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+	    shift
+	    continue;;
+
+	*)  if [ x"$src" = x ]
+	    then
+		src=$1
+	    else
+		# this colon is to work around a 386BSD /bin/sh bug
+		:
+		dst=$1
+	    fi
+	    shift
+	    continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+	echo "install:	no input file specified"
+	exit 1
+else
+	true
+fi
+
+if [ x"$dir_arg" != x ]; then
+	dst=$src
+	src=""
+	
+	if [ -d $dst ]; then
+		instcmd=:
+		chmodcmd=""
+	else
+		instcmd=mkdir
+	fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad 
+# if $src (and thus $dsttmp) contains '*'.
+
+	if [ -f $src -o -d $src ]
+	then
+		true
+	else
+		echo "install:  $src does not exist"
+		exit 1
+	fi
+	
+	if [ x"$dst" = x ]
+	then
+		echo "install:	no destination specified"
+		exit 1
+	else
+		true
+	fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+	if [ -d $dst ]
+	then
+		dst="$dst"/`basename $src`
+	else
+		true
+	fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+#  this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS=' 	
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+	pathcomp="${pathcomp}${1}"
+	shift
+
+	if [ ! -d "${pathcomp}" ] ;
+        then
+		$mkdirprog "${pathcomp}"
+	else
+		true
+	fi
+
+	pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+	$doit $instcmd $dst &&
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+	if [ x"$transformarg" = x ] 
+	then
+		dstfile=`basename $dst`
+	else
+		dstfile=`basename $dst $transformbasename | 
+			sed $transformarg`$transformbasename
+	fi
+
+# don't allow the sed command to completely eliminate the filename
+
+	if [ x"$dstfile" = x ] 
+	then
+		dstfile=`basename $dst`
+	else
+		true
+	fi
+
+# Make a temp file name in the proper directory.
+
+	dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+	$doit $instcmd $src $dsttmp &&
+
+	trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing.  If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+	$doit $rmcmd -f $dstdir/$dstfile &&
+	$doit $mvcmd $dsttmp $dstdir/$dstfile 
+
+fi &&
+
+
+exit 0
Index: /nanovis/tags/1.1.4/cf/mkinstalldirs
===================================================================
--- /nanovis/tags/1.1.4/cf/mkinstalldirs	(revision 4930)
+++ /nanovis/tags/1.1.4/cf/mkinstalldirs	(revision 4930)
@@ -0,0 +1,40 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain
+
+# $Id: mkinstalldirs,v 1.13 1999/01/05 03:18:55 bje Exp $
+
+errstatus=0
+
+for file
+do
+   set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+   shift
+
+   pathcomp=
+   for d
+   do
+     pathcomp="$pathcomp$d"
+     case "$pathcomp" in
+       -* ) pathcomp=./$pathcomp ;;
+     esac
+
+     if test ! -d "$pathcomp"; then
+        echo "mkdir $pathcomp"
+
+        mkdir "$pathcomp" || lasterr=$?
+
+        if test ! -d "$pathcomp"; then
+  	  errstatus=$lasterr
+        fi
+     fi
+
+     pathcomp="$pathcomp/"
+   done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
Index: /nanovis/tags/1.1.4/config.h
===================================================================
--- /nanovis/tags/1.1.4/config.h	(revision 4930)
+++ /nanovis/tags/1.1.4/config.h	(revision 4930)
@@ -0,0 +1,57 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * ----------------------------------------------------------------------
+ * Nanovis: Visualization of Nanoelectronics Data
+ *
+ * ======================================================================
+ *  AUTHOR:  Wei Qiao <qiaow@purdue.edu>
+ *           Purdue Rendering and Perceptualization Lab (PURPL)
+ *
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ *  See the file "license.terms" for information on usage and
+ *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ * ======================================================================
+ */
+
+#ifndef CONFIG_H__
+#define CONFIG_H__
+
+/*
+ * GeForce 6 series and above cards support non-power-of-two texture
+ * dimensions.  If using a 5 series card, disable this define
+ */
+#define HAVE_NPOT_TEXTURES
+
+/*
+ * GeForce 6 series and above cards support 16- or 32-bit float filtering 
+ * and blending.  If using a 5 series card, disable this define
+ */
+#define HAVE_FLOAT_TEXTURES
+
+/*
+ * GeForce 8 series cards support 32-bit float filtering and blending.
+ * If using a 6 or 7 series card, enable this define to use 16-bit float
+ * textures and blending
+ */
+#define USE_HALF_FLOAT
+
+/*
+ * Keep statistics
+ */
+#define KEEPSTATS
+
+//#define USE_NEW_EVENT_LOOP
+
+/*
+ * Controls whether DX data is downsampled.
+ */
+//#define DOWNSAMPLE_DATA
+
+/*
+ * Determines if Sobel filter is applied to gradients when loading a 
+ * volume
+ */
+//#define FILTER_GRADIENTS
+
+#endif 
Index: /nanovis/tags/1.1.4/configure
===================================================================
--- /nanovis/tags/1.1.4/configure	(revision 4930)
+++ /nanovis/tags/1.1.4/configure	(revision 4930)
@@ -0,0 +1,6292 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69 for nanovis 1.1.
+#
+# Report bugs to <rappture@nanohub.org>.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+	expr "X$arg" : "X\\(.*\\)$as_nl";
+	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+  # into an infinite loop, continuously re-executing ourselves.
+  if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+    _as_can_reexec=no; export _as_can_reexec;
+    # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+  fi
+  # We don't want this to propagate to other subprocesses.
+          { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+  as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '\${1+\"\$@\"}'='\"\$@\"'
+  setopt NO_GLOB_SUBST
+else
+  case \`(set -o) 2>/dev/null\` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+"
+  as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+  exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+  as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+  as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+  eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+  test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1"
+  if (eval "$as_required") 2>/dev/null; then :
+  as_have_required=yes
+else
+  as_have_required=no
+fi
+  if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  as_found=:
+  case $as_dir in #(
+	 /*)
+	   for as_base in sh bash ksh sh5; do
+	     # Try only shells that exist, to save several forks.
+	     as_shell=$as_dir/$as_base
+	     if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+		    { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  CONFIG_SHELL=$as_shell as_have_required=yes
+		   if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  break 2
+fi
+fi
+	   done;;
+       esac
+  as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+	      { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+  CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+      if test "x$CONFIG_SHELL" != x; then :
+  export CONFIG_SHELL
+             # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+    if test x$as_have_required = xno; then :
+  $as_echo "$0: This script requires a shell more modern than all"
+  $as_echo "$0: the shells that I found on your system."
+  if test x${ZSH_VERSION+set} = xset ; then
+    $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+    $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+  else
+    $as_echo "$0: Please tell bug-autoconf@gnu.org and
+$0: rappture@nanohub.org about your system, including any
+$0: error possibly output before this message. Then install
+$0: a modern shell, or manually run the script under such a
+$0: shell if you do have one."
+  fi
+  exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+  as_lineno_1=$LINENO as_lineno_1a=$LINENO
+  as_lineno_2=$LINENO as_lineno_2a=$LINENO
+  eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+  test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+  # Blame Lee E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+  # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+  # already done that, so ensure we don't try to do so again and fall
+  # in an infinite loop.  This has already happened in practice.
+  _as_can_reexec=no; export _as_can_reexec
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='	';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -pR'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -pR'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -pR'
+  fi
+else
+  as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME='nanovis'
+PACKAGE_TARNAME='nanovis'
+PACKAGE_VERSION='1.1'
+PACKAGE_STRING='nanovis 1.1'
+PACKAGE_BUGREPORT='rappture@nanohub.org'
+PACKAGE_URL=''
+
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+TCL_VERSION
+TCL_LIB_SPEC
+TCL_INC_SPEC
+STATSDIR
+RP_LIB_DIR
+RP_INC_SPEC
+RP_DIR
+LD_RPATH
+CG_LIB_SPEC
+CG_INC_SPEC
+FFMPEG
+AVCONV
+EGREP
+GREP
+CXXCPP
+ac_ct_CXX
+CXXFLAGS
+CXX
+CPP
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+MKDIR_P
+LN_S
+RANLIB
+INSTALL_DATA
+INSTALL_SCRIPT
+INSTALL_PROGRAM
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+with_tcllib
+with_rappture
+with_ffmpeg
+with_avconv
+with_statsdir
+'
+      ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP
+CXX
+CXXFLAGS
+CCC
+CXXCPP'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval $ac_prev=\$ac_option
+    ac_prev=
+    continue
+  fi
+
+  case $ac_option in
+  *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+  *=)   ac_optarg= ;;
+  *)    ac_optarg=yes ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case $ac_dashdash$ac_option in
+  --)
+    ac_dashdash=yes ;;
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir=$ac_optarg ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build_alias ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build_alias=$ac_optarg ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file=$ac_optarg ;;
+
+  --config-cache | -C)
+    cache_file=config.cache ;;
+
+  -datadir | --datadir | --datadi | --datad)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=*)
+    datadir=$ac_optarg ;;
+
+  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+  | --dataroo | --dataro | --datar)
+    ac_prev=datarootdir ;;
+  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+    datarootdir=$ac_optarg ;;
+
+  -disable-* | --disable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=no ;;
+
+  -docdir | --docdir | --docdi | --doc | --do)
+    ac_prev=docdir ;;
+  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+    docdir=$ac_optarg ;;
+
+  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+    ac_prev=dvidir ;;
+  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+    dvidir=$ac_optarg ;;
+
+  -enable-* | --enable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=\$ac_optarg ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix=$ac_optarg ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he | -h)
+    ac_init_help=long ;;
+  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+    ac_init_help=recursive ;;
+  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+    ac_init_help=short ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host_alias ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host_alias=$ac_optarg ;;
+
+  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+    ac_prev=htmldir ;;
+  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+  | --ht=*)
+    htmldir=$ac_optarg ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir=$ac_optarg ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir=$ac_optarg ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir=$ac_optarg ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir=$ac_optarg ;;
+
+  -localedir | --localedir | --localedi | --localed | --locale)
+    ac_prev=localedir ;;
+  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+    localedir=$ac_optarg ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst | --locals)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+    localstatedir=$ac_optarg ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir=$ac_optarg ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c | -n)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir=$ac_optarg ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix=$ac_optarg ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix=$ac_optarg ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix=$ac_optarg ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name=$ac_optarg ;;
+
+  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+    ac_prev=pdfdir ;;
+  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+    pdfdir=$ac_optarg ;;
+
+  -psdir | --psdir | --psdi | --psd | --ps)
+    ac_prev=psdir ;;
+  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+    psdir=$ac_optarg ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir=$ac_optarg ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir=$ac_optarg ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site=$ac_optarg ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir=$ac_optarg ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir=$ac_optarg ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target_alias ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target_alias=$ac_optarg ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers | -V)
+    ac_init_version=: ;;
+
+  -with-* | --with-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=\$ac_optarg ;;
+
+  -without-* | --without-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=no ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes=$ac_optarg ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries=$ac_optarg ;;
+
+  -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+    ;;
+
+  *=*)
+    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+    # Reject names that are not valid shell variable names.
+    case $ac_envvar in #(
+      '' | [0-9]* | *[!_$as_cr_alnum]* )
+      as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+    esac
+    eval $ac_envvar=\$ac_optarg
+    export $ac_envvar ;;
+
+  *)
+    # FIXME: should be removed in autoconf 3.0.
+    $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+    : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+  as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+  case $enable_option_checking in
+    no) ;;
+    fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+    *)     $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+  esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in	exec_prefix prefix bindir sbindir libexecdir datarootdir \
+		datadir sysconfdir sharedstatedir localstatedir includedir \
+		oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+		libdir localedir mandir
+do
+  eval ac_val=\$$ac_var
+  # Remove trailing slashes.
+  case $ac_val in
+    */ )
+      ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+      eval $ac_var=\$ac_val;;
+  esac
+  # Be sure to have absolute directory names.
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* )  continue;;
+    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+  esac
+  as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+  if test "x$build_alias" = x; then
+    cross_compiling=maybe
+  elif test "x$build_alias" != "x$host_alias"; then
+    cross_compiling=yes
+  fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+  as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+  as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then the parent directory.
+  ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_myself" : 'X\(//\)[^/]' \| \
+	 X"$as_myself" : 'X\(//\)$' \| \
+	 X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+  srcdir=$ac_confdir
+  if test ! -r "$srcdir/$ac_unique_file"; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+  test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+  as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+	cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+	pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+  srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+  eval ac_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_env_${ac_var}_value=\$${ac_var}
+  eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+  # Omit some internal or obsolete options to make the list less imposing.
+  # This message is too long to be a string in the A/UX 3.1 sh.
+  cat <<_ACEOF
+\`configure' configures nanovis 1.1 to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE.  See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+  -h, --help              display this help and exit
+      --help=short        display options specific to this package
+      --help=recursive    display the short help of all the included packages
+  -V, --version           display version information and exit
+  -q, --quiet, --silent   do not print \`checking ...' messages
+      --cache-file=FILE   cache test results in FILE [disabled]
+  -C, --config-cache      alias for \`--cache-file=config.cache'
+  -n, --no-create         do not create output files
+      --srcdir=DIR        find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+  --bindir=DIR            user executables [EPREFIX/bin]
+  --sbindir=DIR           system admin executables [EPREFIX/sbin]
+  --libexecdir=DIR        program executables [EPREFIX/libexec]
+  --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --libdir=DIR            object code libraries [EPREFIX/lib]
+  --includedir=DIR        C header files [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc [/usr/include]
+  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
+  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]
+  --infodir=DIR           info documentation [DATAROOTDIR/info]
+  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
+  --mandir=DIR            man documentation [DATAROOTDIR/man]
+  --docdir=DIR            documentation root [DATAROOTDIR/doc/nanovis]
+  --htmldir=DIR           html documentation [DOCDIR]
+  --dvidir=DIR            dvi documentation [DOCDIR]
+  --pdfdir=DIR            pdf documentation [DOCDIR]
+  --psdir=DIR             ps documentation [DOCDIR]
+_ACEOF
+
+  cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+  case $ac_init_help in
+     short | recursive ) echo "Configuration of nanovis 1.1:";;
+   esac
+  cat <<\_ACEOF
+
+Optional Packages:
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-tcllib=DIR       location of Tcl binary library libtclstubs.a
+                          [default=/usr/lib]
+  --with-rappture=DIR     location of rappture files lib/librappture.a and
+                          include/rappture.h [default=/usr]
+  --with-ffmpeg=DIR       location of ffmpeg [default=yes]
+  --with-avconv=DIR       location of avconv [default=yes]
+  --with-statsdir=DIR     Write statistics in DIR
+
+Some influential environment variables:
+  CC          C compiler command
+  CFLAGS      C compiler flags
+  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
+              nonstandard directory <lib dir>
+  LIBS        libraries to pass to the linker, e.g. -l<library>
+  CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+              you have headers in a nonstandard directory <include dir>
+  CPP         C preprocessor
+  CXX         C++ compiler command
+  CXXFLAGS    C++ compiler flags
+  CXXCPP      C++ preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to <rappture@nanohub.org>.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+  # If there are subdirs, report their specific --help.
+  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+    test -d "$ac_dir" ||
+      { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+      continue
+    ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+    cd "$ac_dir" || { ac_status=$?; continue; }
+    # Check for guested configure.
+    if test -f "$ac_srcdir/configure.gnu"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+    elif test -f "$ac_srcdir/configure"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure" --help=recursive
+    else
+      $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+    fi || ac_status=$?
+    cd "$ac_pwd" || { ac_status=$?; break; }
+  done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+  cat <<\_ACEOF
+nanovis configure 1.1
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+  exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext
+  if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } > conftest.i && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+    ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_cxx_try_compile LINENO
+# ----------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_cxx_try_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext
+  if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_cxx_try_compile
+
+# ac_fn_cxx_try_cpp LINENO
+# ------------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_cxx_try_cpp ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } > conftest.i && {
+	 test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+    ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_cxx_try_cpp
+
+# ac_fn_cxx_try_run LINENO
+# ------------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_cxx_try_run ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: program exited with status $ac_status" >&5
+       $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_retval=$ac_status
+fi
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_cxx_try_run
+
+# ac_fn_cxx_check_header_compile LINENO HEADER VAR INCLUDES
+# ---------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_cxx_check_header_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_cxx_check_header_compile
+
+# ac_fn_cxx_check_header_mongrel LINENO HEADER VAR INCLUDES
+# ---------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_cxx_check_header_mongrel ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if eval \${$3+:} false; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_header_compiler=yes
+else
+  ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <$2>
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+  ac_header_preproc=yes
+else
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_cxx_preproc_warn_flag in #((
+  yes:no: )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+( $as_echo "## ----------------------------------- ##
+## Report this to rappture@nanohub.org ##
+## ----------------------------------- ##"
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_cxx_check_header_mongrel
+
+# ac_fn_cxx_try_link LINENO
+# -------------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_cxx_try_link ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext conftest$ac_exeext
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 test -x conftest$ac_exeext
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+  # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+  # interfere with the next link command; also delete a directory that is
+  # left behind by Apple's compiler.  We do this before executing the actions.
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_cxx_try_link
+
+# ac_fn_cxx_check_func LINENO FUNC VAR
+# ------------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_cxx_check_func ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $2 (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_cxx_check_func
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by nanovis $as_me 1.1, which was
+generated by GNU Autoconf 2.69.  Invocation command line was
+
+  $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
+
+/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
+/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
+/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    $as_echo "PATH: $as_dir"
+  done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+  for ac_arg
+  do
+    case $ac_arg in
+    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+    | -silent | --silent | --silen | --sile | --sil)
+      continue ;;
+    *\'*)
+      ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    case $ac_pass in
+    1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+    2)
+      as_fn_append ac_configure_args1 " '$ac_arg'"
+      if test $ac_must_keep_next = true; then
+	ac_must_keep_next=false # Got value, back to normal.
+      else
+	case $ac_arg in
+	  *=* | --config-cache | -C | -disable-* | --disable-* \
+	  | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+	  | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+	  | -with-* | --with-* | -without-* | --without-* | --x)
+	    case "$ac_configure_args0 " in
+	      "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+	    esac
+	    ;;
+	  -* ) ac_must_keep_next=true ;;
+	esac
+      fi
+      as_fn_append ac_configure_args " '$ac_arg'"
+      ;;
+    esac
+  done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log.  We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+  # Save into config.log some information that might help in debugging.
+  {
+    echo
+
+    $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+    echo
+    # The following way of writing the cache mishandles newlines in values,
+(
+  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+  (set) 2>&1 |
+    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      sed -n \
+	"s/'\''/'\''\\\\'\'''\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+      ;; #(
+    *)
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+)
+    echo
+
+    $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+    echo
+    for ac_var in $ac_subst_vars
+    do
+      eval ac_val=\$$ac_var
+      case $ac_val in
+      *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+      esac
+      $as_echo "$ac_var='\''$ac_val'\''"
+    done | sort
+    echo
+
+    if test -n "$ac_subst_files"; then
+      $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+      echo
+      for ac_var in $ac_subst_files
+      do
+	eval ac_val=\$$ac_var
+	case $ac_val in
+	*\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+	esac
+	$as_echo "$ac_var='\''$ac_val'\''"
+      done | sort
+      echo
+    fi
+
+    if test -s confdefs.h; then
+      $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+      echo
+      cat confdefs.h
+      echo
+    fi
+    test "$ac_signal" != 0 &&
+      $as_echo "$as_me: caught signal $ac_signal"
+    $as_echo "$as_me: exit $exit_status"
+  } >&5
+  rm -f core *.core core.conftest.* &&
+    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+    exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+  trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+  # We do not want a PATH search for config.site.
+  case $CONFIG_SITE in #((
+    -*)  ac_site_file1=./$CONFIG_SITE;;
+    */*) ac_site_file1=$CONFIG_SITE;;
+    *)   ac_site_file1=./$CONFIG_SITE;;
+  esac
+elif test "x$prefix" != xNONE; then
+  ac_site_file1=$prefix/share/config.site
+  ac_site_file2=$prefix/etc/config.site
+else
+  ac_site_file1=$ac_default_prefix/share/config.site
+  ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+  test "x$ac_site_file" = xNONE && continue
+  if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+    sed 's/^/| /' "$ac_site_file" >&5
+    . "$ac_site_file" \
+      || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+  fi
+done
+
+if test -r "$cache_file"; then
+  # Some versions of bash will fail to source /dev/null (special files
+  # actually), so we avoid doing that.  DJGPP emulates it as a regular file.
+  if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+    case $cache_file in
+      [\\/]* | ?:[\\/]* ) . "$cache_file";;
+      *)                      . "./$cache_file";;
+    esac
+  fi
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+  >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+  eval ac_old_set=\$ac_cv_env_${ac_var}_set
+  eval ac_new_set=\$ac_env_${ac_var}_set
+  eval ac_old_val=\$ac_cv_env_${ac_var}_value
+  eval ac_new_val=\$ac_env_${ac_var}_value
+  case $ac_old_set,$ac_new_set in
+    set,)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,set)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,);;
+    *)
+      if test "x$ac_old_val" != "x$ac_new_val"; then
+	# differences in whitespace do not lead to failure.
+	ac_old_val_w=`echo x $ac_old_val`
+	ac_new_val_w=`echo x $ac_new_val`
+	if test "$ac_old_val_w" != "$ac_new_val_w"; then
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+	  ac_cache_corrupted=:
+	else
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+	  eval $ac_var=\$ac_old_val
+	fi
+	{ $as_echo "$as_me:${as_lineno-$LINENO}:   former value:  \`$ac_old_val'" >&5
+$as_echo "$as_me:   former value:  \`$ac_old_val'" >&2;}
+	{ $as_echo "$as_me:${as_lineno-$LINENO}:   current value: \`$ac_new_val'" >&5
+$as_echo "$as_me:   current value: \`$ac_new_val'" >&2;}
+      fi;;
+  esac
+  # Pass precious variables to config.status.
+  if test "$ac_new_set" = set; then
+    case $ac_new_val in
+    *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+    *) ac_arg=$ac_var=$ac_new_val ;;
+    esac
+    case " $ac_configure_args " in
+      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
+      *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+    esac
+  fi
+done
+if $ac_cache_corrupted; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+  as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+ac_aux_dir=
+for ac_dir in cf "$srcdir"/cf; do
+  if test -f "$ac_dir/install-sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f "$ac_dir/install.sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  elif test -f "$ac_dir/shtool"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/shtool install -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  as_fn_error $? "cannot find install-sh, install.sh, or shtool in cf \"$srcdir\"/cf" "$LINENO" 5
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"  # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"  # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
+
+
+ac_config_headers="$ac_config_headers nvconf.h"
+
+
+
+# Check whether --with-tcllib was given.
+if test "${with_tcllib+set}" = set; then :
+  withval=$with_tcllib; with_tcllib=$withval
+else
+  with_tcllib=""
+fi
+
+
+
+# Check whether --with-rappture was given.
+if test "${with_rappture+set}" = set; then :
+  withval=$with_rappture; with_rappture=$withval
+else
+  with_rappture=yes
+fi
+
+
+
+# Check whether --with-ffmpeg was given.
+if test "${with_ffmpeg+set}" = set; then :
+  withval=$with_ffmpeg;
+else
+  with_ffmpeg=yes
+fi
+
+
+
+# Check whether --with-avconv was given.
+if test "${with_avconv+set}" = set; then :
+  withval=$with_avconv;
+else
+  with_avconv=yes
+fi
+
+
+
+# Check whether --with-statsdir was given.
+if test "${with_statsdir+set}" = set; then :
+  withval=$with_statsdir; STATSDIR=$withval
+else
+  STATSDIR="/var/tmp/visservers"
+fi
+
+
+#------------------------------------------------------------------------
+# Handle the --prefix=... option
+#------------------------------------------------------------------------
+
+if test "${prefix}" = "NONE"; then
+    prefix=/usr/local
+fi
+if test "${exec_prefix}" = "NONE"; then
+    exec_prefix=$prefix
+fi
+
+if test "x${incdir}" == "x"; then
+  incdir=${exec_prefix}/include
+fi
+libdir=${exec_prefix}/lib
+
+if test "${libdir}" != "${prefix}/lib"; then
+    LIB_SEARCH_DIRS="-L ${prefix}/lib -L ${libdir}"
+else
+    LIB_SEARCH_DIRS="-L ${libdir}"
+fi
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+# Reject install programs that cannot install multiple files.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
+$as_echo_n "checking for a BSD-compatible install... " >&6; }
+if test -z "$INSTALL"; then
+if ${ac_cv_path_install+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in #((
+  ./ | .// | /[cC]/* | \
+  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+  ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
+  /usr/ucb/* ) ;;
+  *)
+    # OSF1 and SCO ODT 3.0 have their own names for install.
+    # Don't use installbsd from OSF since it installs stuff as root
+    # by default.
+    for ac_prog in ginstall scoinst install; do
+      for ac_exec_ext in '' $ac_executable_extensions; do
+	if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+	  if test $ac_prog = install &&
+	    grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    :
+	  elif test $ac_prog = install &&
+	    grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+	    # program-specific install script used by HP pwplus--don't use.
+	    :
+	  else
+	    rm -rf conftest.one conftest.two conftest.dir
+	    echo one > conftest.one
+	    echo two > conftest.two
+	    mkdir conftest.dir
+	    if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
+	      test -s conftest.one && test -s conftest.two &&
+	      test -s conftest.dir/conftest.one &&
+	      test -s conftest.dir/conftest.two
+	    then
+	      ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+	      break 3
+	    fi
+	  fi
+	fi
+      done
+    done
+    ;;
+esac
+
+  done
+IFS=$as_save_IFS
+
+rm -rf conftest.one conftest.two conftest.dir
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL=$ac_cv_path_install
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    INSTALL=$ac_install_sh
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
+$as_echo "$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_RANLIB+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
+$as_echo "$RANLIB" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+  ac_ct_RANLIB=$RANLIB
+  # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_RANLIB+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_RANLIB"; then
+  ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_RANLIB="ranlib"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
+$as_echo "$ac_ct_RANLIB" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_RANLIB" = x; then
+    RANLIB=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    RANLIB=$ac_ct_RANLIB
+  fi
+else
+  RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5
+$as_echo_n "checking whether ln -s works... " >&6; }
+LN_S=$as_ln_s
+if test "$LN_S" = "ln -s"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5
+$as_echo "no, using $LN_S" >&6; }
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5
+$as_echo_n "checking for a thread-safe mkdir -p... " >&6; }
+if test -z "$MKDIR_P"; then
+  if ${ac_cv_path_mkdir+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in mkdir gmkdir; do
+	 for ac_exec_ext in '' $ac_executable_extensions; do
+	   as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue
+	   case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
+	     'mkdir (GNU coreutils) '* | \
+	     'mkdir (coreutils) '* | \
+	     'mkdir (fileutils) '4.1*)
+	       ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext
+	       break 3;;
+	   esac
+	 done
+       done
+  done
+IFS=$as_save_IFS
+
+fi
+
+  test -d ./--version && rmdir ./--version
+  if test "${ac_cv_path_mkdir+set}" = set; then
+    MKDIR_P="$ac_cv_path_mkdir -p"
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for MKDIR_P within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    MKDIR_P="$ac_install_sh -d"
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5
+$as_echo "$MKDIR_P" >&6; }
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+          if test -n "$ac_tool_prefix"; then
+    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  fi
+fi
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# != 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl.exe
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$CC" && break
+  done
+fi
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl.exe
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CC" && break
+done
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+  esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link_default") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile.  We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+	;;
+    [ab].out )
+	# We found the default executable, but exeext='' is most
+	# certainly right.
+	break;;
+    *.* )
+	if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+	then :; else
+	   ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	fi
+	# We set ac_cv_exeext here because the later test for it is not
+	# safe: cross compilers may not add the suffix if given an `-o'
+	# argument, so we may need to know it at that point already.
+	# Even if this section looks crufty: it has the advantage of
+	# actually working.
+	break;;
+    * )
+	break;;
+  esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+  ac_file=''
+fi
+if test -z "$ac_file"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	  break;;
+    * ) break;;
+  esac
+done
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+  { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+  if { ac_try='./conftest$ac_cv_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then
+    cross_compiling=no
+  else
+    if test "$cross_compiling" = maybe; then
+	cross_compiling=yes
+    else
+	{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+    fi
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  for ac_file in conftest.o conftest.obj conftest.*; do
+  test -f "$ac_file" || continue;
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+       break;;
+  esac
+done
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_compiler_gnu=yes
+else
+  ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_c_werror_flag=$ac_c_werror_flag
+   ac_c_werror_flag=yes
+   ac_cv_prog_cc_g=no
+   CFLAGS="-g"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+else
+  CFLAGS=""
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+  ac_c_werror_flag=$ac_save_c_werror_flag
+	 CFLAGS="-g"
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+   inside strings and character constants.  */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+	-Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+  test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+  x)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+  xno)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c89"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+  if ${ac_cv_prog_CPP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+      # Double quotes because CPP needs to be expanded
+    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+  break
+fi
+
+    done
+    ac_cv_prog_CPP=$CPP
+
+fi
+  CPP=$ac_cv_prog_CPP
+else
+  ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+if test -z "$CXX"; then
+  if test -n "$CCC"; then
+    CXX=$CCC
+  else
+    if test -n "$ac_tool_prefix"; then
+  for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CXX"; then
+  ac_cv_prog_CXX="$CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CXX="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CXX=$ac_cv_prog_CXX
+if test -n "$CXX"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5
+$as_echo "$CXX" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$CXX" && break
+  done
+fi
+if test -z "$CXX"; then
+  ac_ct_CXX=$CXX
+  for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CXX"; then
+  ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CXX="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CXX=$ac_cv_prog_ac_ct_CXX
+if test -n "$ac_ct_CXX"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5
+$as_echo "$ac_ct_CXX" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CXX" && break
+done
+
+  if test "x$ac_ct_CXX" = x; then
+    CXX="g++"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CXX=$ac_ct_CXX
+  fi
+fi
+
+  fi
+fi
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5
+$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; }
+if ${ac_cv_cxx_compiler_gnu+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_compiler_gnu=yes
+else
+  ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_cxx_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5
+$as_echo "$ac_cv_cxx_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GXX=yes
+else
+  GXX=
+fi
+ac_test_CXXFLAGS=${CXXFLAGS+set}
+ac_save_CXXFLAGS=$CXXFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5
+$as_echo_n "checking whether $CXX accepts -g... " >&6; }
+if ${ac_cv_prog_cxx_g+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_cxx_werror_flag=$ac_cxx_werror_flag
+   ac_cxx_werror_flag=yes
+   ac_cv_prog_cxx_g=no
+   CXXFLAGS="-g"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_cv_prog_cxx_g=yes
+else
+  CXXFLAGS=""
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+
+else
+  ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+	 CXXFLAGS="-g"
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_cv_prog_cxx_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5
+$as_echo "$ac_cv_prog_cxx_g" >&6; }
+if test "$ac_test_CXXFLAGS" = set; then
+  CXXFLAGS=$ac_save_CXXFLAGS
+elif test $ac_cv_prog_cxx_g = yes; then
+  if test "$GXX" = yes; then
+    CXXFLAGS="-g -O2"
+  else
+    CXXFLAGS="-g"
+  fi
+else
+  if test "$GXX" = yes; then
+    CXXFLAGS="-O2"
+  else
+    CXXFLAGS=
+  fi
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5
+$as_echo_n "checking how to run the C++ preprocessor... " >&6; }
+if test -z "$CXXCPP"; then
+  if ${ac_cv_prog_CXXCPP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+      # Double quotes because CXXCPP needs to be expanded
+    for CXXCPP in "$CXX -E" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_cxx_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+  break
+fi
+
+    done
+    ac_cv_prog_CXXCPP=$CXXCPP
+
+fi
+  CXXCPP=$ac_cv_prog_CXXCPP
+else
+  ac_cv_prog_CXXCPP=$CXXCPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5
+$as_echo "$CXXCPP" >&6; }
+ac_preproc_ok=false
+for ac_cxx_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+if test -z "$CXX"; then
+  if test -n "$CCC"; then
+    CXX=$CCC
+  else
+    if test -n "$ac_tool_prefix"; then
+  for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CXX"; then
+  ac_cv_prog_CXX="$CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CXX="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CXX=$ac_cv_prog_CXX
+if test -n "$CXX"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5
+$as_echo "$CXX" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$CXX" && break
+  done
+fi
+if test -z "$CXX"; then
+  ac_ct_CXX=$CXX
+  for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CXX"; then
+  ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CXX="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CXX=$ac_cv_prog_ac_ct_CXX
+if test -n "$ac_ct_CXX"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5
+$as_echo "$ac_ct_CXX" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CXX" && break
+done
+
+  if test "x$ac_ct_CXX" = x; then
+    CXX="g++"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CXX=$ac_ct_CXX
+  fi
+fi
+
+  fi
+fi
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5
+$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; }
+if ${ac_cv_cxx_compiler_gnu+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_compiler_gnu=yes
+else
+  ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_cxx_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5
+$as_echo "$ac_cv_cxx_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GXX=yes
+else
+  GXX=
+fi
+ac_test_CXXFLAGS=${CXXFLAGS+set}
+ac_save_CXXFLAGS=$CXXFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5
+$as_echo_n "checking whether $CXX accepts -g... " >&6; }
+if ${ac_cv_prog_cxx_g+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_cxx_werror_flag=$ac_cxx_werror_flag
+   ac_cxx_werror_flag=yes
+   ac_cv_prog_cxx_g=no
+   CXXFLAGS="-g"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_cv_prog_cxx_g=yes
+else
+  CXXFLAGS=""
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+
+else
+  ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+	 CXXFLAGS="-g"
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_cv_prog_cxx_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5
+$as_echo "$ac_cv_prog_cxx_g" >&6; }
+if test "$ac_test_CXXFLAGS" = set; then
+  CXXFLAGS=$ac_save_CXXFLAGS
+elif test $ac_cv_prog_cxx_g = yes; then
+  if test "$GXX" = yes; then
+    CXXFLAGS="-g -O2"
+  else
+    CXXFLAGS="-g"
+  fi
+else
+  if test "$GXX" = yes; then
+    CXXFLAGS="-O2"
+  else
+    CXXFLAGS=
+  fi
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$GREP"; then
+  ac_path_GREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in grep ggrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_GREP" || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+  # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'GREP' >> "conftest.nl"
+    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_GREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_GREP="$ac_path_GREP"
+      ac_path_GREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_GREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_GREP"; then
+    as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+   then ac_cv_path_EGREP="$GREP -E"
+   else
+     if test -z "$EGREP"; then
+  ac_path_EGREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in egrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_EGREP" || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+  # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'EGREP' >> "conftest.nl"
+    "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_EGREP="$ac_path_EGREP"
+      ac_path_EGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_EGREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_EGREP"; then
+    as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_EGREP=$EGREP
+fi
+
+   fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if ${ac_cv_header_stdc+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_cv_header_stdc=yes
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "free" >/dev/null 2>&1; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+  if test "$cross_compiling" = yes; then :
+  :
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+		   (('a' <= (c) && (c) <= 'i') \
+		     || ('j' <= (c) && (c) <= 'r') \
+		     || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+  int i;
+  for (i = 0; i < 256; i++)
+    if (XOR (islower (i), ISLOWER (i))
+	|| toupper (i) != TOUPPER (i))
+      return 2;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_run "$LINENO"; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+		  inttypes.h stdint.h unistd.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_cxx_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5
+$as_echo_n "checking whether byte ordering is bigendian... " >&6; }
+if ${ac_cv_c_bigendian+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_c_bigendian=unknown
+    # See if we're dealing with a universal compiler.
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifndef __APPLE_CC__
+	       not a universal capable compiler
+	     #endif
+	     typedef int dummy;
+
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+
+	# Check for potential -arch flags.  It is not universal unless
+	# there are at least two -arch flags with different values.
+	ac_arch=
+	ac_prev=
+	for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do
+	 if test -n "$ac_prev"; then
+	   case $ac_word in
+	     i?86 | x86_64 | ppc | ppc64)
+	       if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then
+		 ac_arch=$ac_word
+	       else
+		 ac_cv_c_bigendian=universal
+		 break
+	       fi
+	       ;;
+	   esac
+	   ac_prev=
+	 elif test "x$ac_word" = "x-arch"; then
+	   ac_prev=arch
+	 fi
+       done
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+    if test $ac_cv_c_bigendian = unknown; then
+      # See if sys/param.h defines the BYTE_ORDER macro.
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+	     #include <sys/param.h>
+
+int
+main ()
+{
+#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \
+		     && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \
+		     && LITTLE_ENDIAN)
+	      bogus endian macros
+	     #endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  # It does; now see whether it defined to BIG_ENDIAN or not.
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+		#include <sys/param.h>
+
+int
+main ()
+{
+#if BYTE_ORDER != BIG_ENDIAN
+		 not big endian
+		#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_cv_c_bigendian=yes
+else
+  ac_cv_c_bigendian=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+    fi
+    if test $ac_cv_c_bigendian = unknown; then
+      # See if <limits.h> defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris).
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <limits.h>
+
+int
+main ()
+{
+#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN)
+	      bogus endian macros
+	     #endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  # It does; now see whether it defined to _BIG_ENDIAN or not.
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <limits.h>
+
+int
+main ()
+{
+#ifndef _BIG_ENDIAN
+		 not big endian
+		#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_cv_c_bigendian=yes
+else
+  ac_cv_c_bigendian=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+    fi
+    if test $ac_cv_c_bigendian = unknown; then
+      # Compile a test program.
+      if test "$cross_compiling" = yes; then :
+  # Try to guess by grepping values from an object file.
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+short int ascii_mm[] =
+		  { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
+		short int ascii_ii[] =
+		  { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
+		int use_ascii (int i) {
+		  return ascii_mm[i] + ascii_ii[i];
+		}
+		short int ebcdic_ii[] =
+		  { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
+		short int ebcdic_mm[] =
+		  { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
+		int use_ebcdic (int i) {
+		  return ebcdic_mm[i] + ebcdic_ii[i];
+		}
+		extern int foo;
+
+int
+main ()
+{
+return use_ascii (foo) == use_ebcdic (foo);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then
+	      ac_cv_c_bigendian=yes
+	    fi
+	    if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then
+	      if test "$ac_cv_c_bigendian" = unknown; then
+		ac_cv_c_bigendian=no
+	      else
+		# finding both strings is unlikely to happen, but who knows?
+		ac_cv_c_bigendian=unknown
+	      fi
+	    fi
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+
+	     /* Are we little or big endian?  From Harbison&Steele.  */
+	     union
+	     {
+	       long int l;
+	       char c[sizeof (long int)];
+	     } u;
+	     u.l = 1;
+	     return u.c[sizeof (long int) - 1] == 1;
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_run "$LINENO"; then :
+  ac_cv_c_bigendian=no
+else
+  ac_cv_c_bigendian=yes
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+    fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5
+$as_echo "$ac_cv_c_bigendian" >&6; }
+ case $ac_cv_c_bigendian in #(
+   yes)
+     $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h
+;; #(
+   no)
+      ;; #(
+   universal)
+
+$as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h
+
+     ;; #(
+   *)
+     as_fn_error $? "unknown endianness
+ presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;;
+ esac
+
+
+# Save the values as shell variables so that we can substitute them
+# into bltHash.h for situtations where there's no bltInt.h.
+
+
+LD_RPATH="";
+
+#
+# Need to check for the following dependencies:
+#	Rappture headers and library (done)
+#       Tcl headers and library (done)
+#       GL headers and library
+#       GLuT headers and library
+#       GLEW header and library
+#       Cg headers and library
+#       CgGL headers and library
+#       pthread library
+#       ffmpeg headers and library (started)
+#
+
+TCL_VERSION="8.4"
+for dir in \
+ ${exec_prefix} \
+ ${exec_prefix}/lib \
+ ${with_rappture} \
+ ${with_rappture}/lib ; do
+  tclconfig="${dir}/tclConfig.sh"
+  if test -f "$tclconfig" ; then
+    . $tclconfig
+    break
+  fi
+done
+TCL_INC_SPEC="$TCL_INCLUDE_SPEC"
+
+if test "x$with_tcllib" != "x" ; then
+   tclconfig="${with_tcllib}/tclConfig.sh"
+   if test -f "$tclconfig" ; then
+    . $tclconfig
+   fi
+   TCL_LIB_SPEC="-L${with_tcllib} -ltcl${TCL_VERSION}"
+fi
+if test "x$with_tclinclude" != "x" ; then
+   TCL_INC_SPEC="-I${with_tclinclude}"
+fi
+
+RP_DIR=""
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for rappture" >&5
+$as_echo_n "checking for rappture... " >&6; }
+if test "$with_rappture" == "yes" ; then
+  for dir in "$exec_prefix" "/usr" ; do
+    if test -r "$dir/include/rappture2/rappture2.h" -a \
+     -r "$dir/lib/librappture.a"; then
+      RP_DIR="$dir"
+      RP_INC_SPEC="-I$dir/include -I$dir/include/rappture2"
+      RP_LIB_DIR="$dir/lib"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dir" >&5
+$as_echo "$dir" >&6; }
+      break
+    fi
+  done
+else
+  if test ! -d "$with_rappture" ; then
+    as_fn_error $? "--with-rappture: no such directory $with_rappture" "$LINENO" 5
+  fi
+  RP_DIR=$with_rappture
+  RP_INC_SPEC="-I$with_rappture/include -I$with_rappture/include/rappture2"
+  RP_LIB_DIR="$with_rappture/lib"
+fi
+if test "x${RP_DIR}" = "x" ; then
+  as_fn_error $? "cannot find rappture.h and librappture2.a, try using --with-rappture" "$LINENO" 5
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_rappture" >&5
+$as_echo "$with_rappture" >&6; }
+fi
+
+ac_fn_cxx_check_header_mongrel "$LINENO" "GL/glut.h" "ac_cv_header_GL_glut_h" "$ac_includes_default"
+if test "x$ac_cv_header_GL_glut_h" = xyes; then :
+
+fi
+
+
+ac_fn_cxx_check_header_mongrel "$LINENO" "GL/glew.h" "ac_cv_header_GL_glew_h" "$ac_includes_default"
+if test "x$ac_cv_header_GL_glew_h" = xyes; then :
+
+fi
+
+
+
+for ac_header in stdio.h unistd.h stdlib.h string.h sys/types.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_cxx_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+for ac_header in sys/socket.h sys/time.h netinet/in.h arpa/inet.h netdb.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_cxx_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_func in accept4
+do :
+  ac_fn_cxx_check_func "$LINENO" "accept4" "ac_cv_func_accept4"
+if test "x$ac_cv_func_accept4" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_ACCEPT4 1
+_ACEOF
+
+fi
+done
+
+
+#--------------------------------------------------------------------
+# search for avconv executable
+#--------------------------------------------------------------------
+if test "${with_avconv}" != "no" ; then
+  if test "${with_avconv}" = "yes" ; then
+    # Extract the first word of "avconv", so it can be a program name with args.
+set dummy avconv; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_AVCONV+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $AVCONV in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_AVCONV="$AVCONV" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_AVCONV="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+AVCONV=$ac_cv_path_AVCONV
+if test -n "$AVCONV"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AVCONV" >&5
+$as_echo "$AVCONV" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  else
+    # Extract the first word of "avconv", so it can be a program name with args.
+set dummy avconv; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_AVCONV+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $AVCONV in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_AVCONV="$AVCONV" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_dummy="${with_avconv}/bin:${with_avconv}"
+for as_dir in $as_dummy
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_AVCONV="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+AVCONV=$ac_cv_path_AVCONV
+if test -n "$AVCONV"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AVCONV" >&5
+$as_echo "$AVCONV" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  fi
+  if test "${AVCONV}x" != "x" ; then
+
+$as_echo "#define HAVE_AVCONV 1" >>confdefs.h
+
+  fi
+fi
+
+#--------------------------------------------------------------------
+# search for ffmpeg executable
+#--------------------------------------------------------------------
+if test "${with_ffmpeg}" != "no" ; then
+  if test "${with_ffmpeg}" = "yes" ; then
+    # Extract the first word of "ffmpeg", so it can be a program name with args.
+set dummy ffmpeg; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_FFMPEG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $FFMPEG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_FFMPEG="$FFMPEG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_FFMPEG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+FFMPEG=$ac_cv_path_FFMPEG
+if test -n "$FFMPEG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $FFMPEG" >&5
+$as_echo "$FFMPEG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  else
+    # Extract the first word of "ffmpeg", so it can be a program name with args.
+set dummy ffmpeg; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_FFMPEG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $FFMPEG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_FFMPEG="$FFMPEG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_dummy="${with_ffmpeg}/bin:${with_ffmpeg}"
+for as_dir in $as_dummy
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_FFMPEG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+FFMPEG=$ac_cv_path_FFMPEG
+if test -n "$FFMPEG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $FFMPEG" >&5
+$as_echo "$FFMPEG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  fi
+  if test "${FFMPEG}x" != "x" ; then
+
+$as_echo "#define HAVE_FFMPEG 1" >>confdefs.h
+
+  fi
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for nVidia Cg installation" >&5
+$as_echo_n "checking for nVidia Cg installation... " >&6; }
+CG_DIR=""
+for dir in \
+ /opt/nvidia-cg-toolkit \
+ /usr/cg \
+ /usr
+do
+  if test -r "$dir/include" ; then
+    CG_DIR=$dir
+    break
+  fi
+done
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${CG_DIR}" >&5
+$as_echo "${CG_DIR}" >&6; }
+
+CG_INC_SPEC="-I${CG_DIR}/include"
+
+save_CPPFLAGS=$CPPFLAGS
+CPPFLAGS="${CG_INC_SPEC} $CPPFLAGS"
+for ac_header in Cg/cgGL.h
+do :
+  ac_fn_cxx_check_header_mongrel "$LINENO" "Cg/cgGL.h" "ac_cv_header_Cg_cgGL_h" "$ac_includes_default"
+if test "x$ac_cv_header_Cg_cgGL_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_CG_CGGL_H 1
+_ACEOF
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot find nVidia Cg headers" >&5
+$as_echo "$as_me: WARNING: cannot find nVidia Cg headers" >&2;}
+fi
+
+done
+
+CPPFLAGS=$save_CPPFLAGS
+
+CG_LIB_DIR=""
+for dir in \
+ /opt/nvidia-cg-toolkit \
+ /usr/cg \
+ /usr
+do
+  if test -r "$dir/lib" ; then
+    CG_LIB_DIR=$dir/lib
+    break
+  fi
+  if test -r "$dir/lib64" ; then
+    CG_LIB_DIR=$dir/lib64
+    break
+  fi
+done
+
+if test "${CG_LIB_DIR}" = "/usr/lib" ; then
+  CG_INC_SPEC=""
+  CG_LIB_SPEC="-lCg -lCgGL"
+else
+  CG_LIB_SPEC="-L${CG_LIB_DIR} -lCg -lCgGL"
+  LD_RPATH="$loader_run_path:${CG_LIB_DIR}"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ac_config_files="$ac_config_files Doxyfile Makefile graphics/Makefile imgLoaders/Makefile newmat11/Makefile util/Makefile vrmath/Makefile"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems.  If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+  for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+
+  (set) 2>&1 |
+    case $as_nl`(ac_space=' '; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      # `set' does not quote correctly, so add quotes: double-quote
+      # substitution turns \\\\ into \\, and sed turns \\ into \.
+      sed -n \
+	"s/'/'\\\\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+      ;; #(
+    *)
+      # `set' quotes correctly as required by POSIX, so do not add quotes.
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+) |
+  sed '
+     /^ac_cv_env_/b end
+     t clear
+     :clear
+     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+     t end
+     s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+     :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+  if test -w "$cache_file"; then
+    if test "x$cache_file" != "x/dev/null"; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+      if test ! -f "$cache_file" || test -h "$cache_file"; then
+	cat confcache >"$cache_file"
+      else
+        case $cache_file in #(
+        */* | ?:*)
+	  mv -f confcache "$cache_file"$$ &&
+	  mv -f "$cache_file"$$ "$cache_file" ;; #(
+        *)
+	  mv -f confcache "$cache_file" ;;
+	esac
+      fi
+    fi
+  else
+    { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+  fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+  # 1. Remove the extension, and $U if already installed.
+  ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+  ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
+  #    will be set to the directory where LIBOBJS objects are built.
+  as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+  as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+	expr "X$arg" : "X\\(.*\\)$as_nl";
+	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='	';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -pR'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -pR'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -pR'
+  fi
+else
+  as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by nanovis $as_me 1.1, which was
+generated by GNU Autoconf 2.69.  Invocation command line was
+
+  CONFIG_FILES    = $CONFIG_FILES
+  CONFIG_HEADERS  = $CONFIG_HEADERS
+  CONFIG_LINKS    = $CONFIG_LINKS
+  CONFIG_COMMANDS = $CONFIG_COMMANDS
+  $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration.  Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+  -h, --help       print this help, then exit
+  -V, --version    print version number and configuration settings, then exit
+      --config     print configuration, then exit
+  -q, --quiet, --silent
+                   do not print progress messages
+  -d, --debug      don't remove temporary files
+      --recheck    update $as_me by reconfiguring in the same conditions
+      --file=FILE[:TEMPLATE]
+                   instantiate the configuration file FILE
+      --header=FILE[:TEMPLATE]
+                   instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to <rappture@nanohub.org>."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+nanovis config.status 1.1
+configured by $0, generated by GNU Autoconf 2.69,
+  with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+INSTALL='$INSTALL'
+MKDIR_P='$MKDIR_P'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+  case $1 in
+  --*=?*)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+    ac_shift=:
+    ;;
+  --*=)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=
+    ac_shift=:
+    ;;
+  *)
+    ac_option=$1
+    ac_optarg=$2
+    ac_shift=shift
+    ;;
+  esac
+
+  case $ac_option in
+  # Handling of the options.
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    ac_cs_recheck=: ;;
+  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+    $as_echo "$ac_cs_version"; exit ;;
+  --config | --confi | --conf | --con | --co | --c )
+    $as_echo "$ac_cs_config"; exit ;;
+  --debug | --debu | --deb | --de | --d | -d )
+    debug=: ;;
+  --file | --fil | --fi | --f )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    '') as_fn_error $? "missing file argument" ;;
+    esac
+    as_fn_append CONFIG_FILES " '$ac_optarg'"
+    ac_need_defaults=false;;
+  --header | --heade | --head | --hea )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+    ac_need_defaults=false;;
+  --he | --h)
+    # Conflict between --help and --header
+    as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+  --help | --hel | -h )
+    $as_echo "$ac_cs_usage"; exit ;;
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil | --si | --s)
+    ac_cs_silent=: ;;
+
+  # This is an error.
+  -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+  *) as_fn_append ac_config_targets " $1"
+     ac_need_defaults=false ;;
+
+  esac
+  shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+  exec 6>/dev/null
+  ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+  set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+  shift
+  \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+  CONFIG_SHELL='$SHELL'
+  export CONFIG_SHELL
+  exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+  echo
+  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+  $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+  case $ac_config_target in
+    "nvconf.h") CONFIG_HEADERS="$CONFIG_HEADERS nvconf.h" ;;
+    "Doxyfile") CONFIG_FILES="$CONFIG_FILES Doxyfile" ;;
+    "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+    "graphics/Makefile") CONFIG_FILES="$CONFIG_FILES graphics/Makefile" ;;
+    "imgLoaders/Makefile") CONFIG_FILES="$CONFIG_FILES imgLoaders/Makefile" ;;
+    "newmat11/Makefile") CONFIG_FILES="$CONFIG_FILES newmat11/Makefile" ;;
+    "util/Makefile") CONFIG_FILES="$CONFIG_FILES util/Makefile" ;;
+    "vrmath/Makefile") CONFIG_FILES="$CONFIG_FILES vrmath/Makefile" ;;
+
+  *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+  esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used.  Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+  test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience.  Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+  tmp= ac_tmp=
+  trap 'exit_status=$?
+  : "${ac_tmp:=$tmp}"
+  { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+  trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+  test -d "$tmp"
+}  ||
+{
+  tmp=./conf$$-$RANDOM
+  (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+  eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+  ac_cs_awk_cr='\\r'
+else
+  ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+  echo "cat >conf$$subs.awk <<_ACEOF" &&
+  echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+  echo "_ACEOF"
+} >conf$$subs.sh ||
+  as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+  . ./conf$$subs.sh ||
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+  ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+  if test $ac_delim_n = $ac_delim_num; then
+    break
+  elif $ac_last_try; then
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+  N
+  s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+  for (key in S) S_is_set[key] = 1
+  FS = ""
+
+}
+{
+  line = $ 0
+  nfields = split(line, field, "@")
+  substed = 0
+  len = length(field[1])
+  for (i = 2; i < nfields; i++) {
+    key = field[i]
+    keylen = length(key)
+    if (S_is_set[key]) {
+      value = S[key]
+      line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+      len += length(value) + length(field[++i])
+      substed = 1
+    } else
+      len += 1 + keylen
+  }
+
+  print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+  sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+  cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+  || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[	 ]*VPATH[	 ]*=[	 ]*/{
+h
+s///
+s/^/:/
+s/[	 ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[	 ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[	 ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+  ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
+  if test -z "$ac_tt"; then
+    break
+  elif $ac_last_try; then
+    as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any.  Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[	 ]*#[	 ]*define[	 ][	 ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[	 ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[	 ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[	 ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[	 ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  for (key in D) D_is_set[key] = 1
+  FS = ""
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+  line = \$ 0
+  split(line, arg, " ")
+  if (arg[1] == "#") {
+    defundef = arg[2]
+    mac1 = arg[3]
+  } else {
+    defundef = substr(arg[1], 2)
+    mac1 = arg[2]
+  }
+  split(mac1, mac2, "(") #)
+  macro = mac2[1]
+  prefix = substr(line, 1, index(line, defundef) - 1)
+  if (D_is_set[macro]) {
+    # Preserve the white space surrounding the "#".
+    print prefix "define", macro P[macro] D[macro]
+    next
+  } else {
+    # Replace #undef with comments.  This is necessary, for example,
+    # in the case of _POSIX_SOURCE, which is predefined and required
+    # on some systems where configure will not decide to define it.
+    if (defundef == "undef") {
+      print "/*", prefix defundef, macro, "*/"
+      next
+    }
+  }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+  as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X "  :F $CONFIG_FILES  :H $CONFIG_HEADERS    "
+shift
+for ac_tag
+do
+  case $ac_tag in
+  :[FHLC]) ac_mode=$ac_tag; continue;;
+  esac
+  case $ac_mode$ac_tag in
+  :[FHL]*:*);;
+  :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+  :[FH]-) ac_tag=-:-;;
+  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+  esac
+  ac_save_IFS=$IFS
+  IFS=:
+  set x $ac_tag
+  IFS=$ac_save_IFS
+  shift
+  ac_file=$1
+  shift
+
+  case $ac_mode in
+  :L) ac_source=$1;;
+  :[FH])
+    ac_file_inputs=
+    for ac_f
+    do
+      case $ac_f in
+      -) ac_f="$ac_tmp/stdin";;
+      *) # Look for the file first in the build tree, then in the source tree
+	 # (if the path is not absolute).  The absolute path cannot be DOS-style,
+	 # because $ac_f cannot contain `:'.
+	 test -f "$ac_f" ||
+	   case $ac_f in
+	   [\\/$]*) false;;
+	   *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+	   esac ||
+	   as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+      esac
+      case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+      as_fn_append ac_file_inputs " '$ac_f'"
+    done
+
+    # Let's still pretend it is `configure' which instantiates (i.e., don't
+    # use $as_me), people would be surprised to read:
+    #    /* config.h.  Generated by config.status.  */
+    configure_input='Generated from '`
+	  $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+	`' by configure.'
+    if test x"$ac_file" != x-; then
+      configure_input="$ac_file.  $configure_input"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+    fi
+    # Neutralize special characters interpreted by sed in replacement strings.
+    case $configure_input in #(
+    *\&* | *\|* | *\\* )
+       ac_sed_conf_input=`$as_echo "$configure_input" |
+       sed 's/[\\\\&|]/\\\\&/g'`;; #(
+    *) ac_sed_conf_input=$configure_input;;
+    esac
+
+    case $ac_tag in
+    *:-:* | *:-) cat >"$ac_tmp/stdin" \
+      || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+    esac
+    ;;
+  esac
+
+  ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$ac_file" : 'X\(//\)[^/]' \| \
+	 X"$ac_file" : 'X\(//\)$' \| \
+	 X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+  as_dir="$ac_dir"; as_fn_mkdir_p
+  ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+  case $ac_mode in
+  :F)
+  #
+  # CONFIG_FILE
+  #
+
+  case $INSTALL in
+  [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+  *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+  esac
+  ac_MKDIR_P=$MKDIR_P
+  case $MKDIR_P in
+  [\\/$]* | ?:[\\/]* ) ;;
+  */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;;
+  esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+  p
+  q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  ac_datarootdir_hack='
+  s&@datadir@&$datadir&g
+  s&@docdir@&$docdir&g
+  s&@infodir@&$infodir&g
+  s&@localedir@&$localedir&g
+  s&@mandir@&$mandir&g
+  s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+s&@MKDIR_P@&$ac_MKDIR_P&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+  >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+  { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+  { ac_out=`sed -n '/^[	 ]*datarootdir[	 ]*:*=/p' \
+      "$ac_tmp/out"`; test -z "$ac_out"; } &&
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&2;}
+
+  rm -f "$ac_tmp/stdin"
+  case $ac_file in
+  -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+  *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+  esac \
+  || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+  :H)
+  #
+  # CONFIG_HEADER
+  #
+  if test x"$ac_file" != x-; then
+    {
+      $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
+    } >"$ac_tmp/config.h" \
+      || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+    if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+    else
+      rm -f "$ac_file"
+      mv "$ac_tmp/config.h" "$ac_file" \
+	|| as_fn_error $? "could not create $ac_file" "$LINENO" 5
+    fi
+  else
+    $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
+      || as_fn_error $? "could not create -" "$LINENO" 5
+  fi
+ ;;
+
+
+  esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+  as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded.  So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status.  When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+  ac_cs_success=:
+  ac_config_status_args=
+  test "$silent" = yes &&
+    ac_config_status_args="$ac_config_status_args --quiet"
+  exec 5>/dev/null
+  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+  exec 5>>config.log
+  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+  # would make configure fail if this is the last instruction.
+  $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
Index: /nanovis/tags/1.1.4/configure.in
===================================================================
--- /nanovis/tags/1.1.4/configure.in	(revision 4930)
+++ /nanovis/tags/1.1.4/configure.in	(revision 4930)
@@ -0,0 +1,249 @@
+AC_PREREQ([2.60])
+AC_INIT([nanovis], [1.1], [rappture@nanohub.org])
+AC_CONFIG_AUX_DIR(cf)
+AC_CONFIG_HEADERS([nvconf.h])
+
+AC_ARG_WITH(
+    [tcllib],
+    [AS_HELP_STRING([--with-tcllib[=DIR]],
+        [location of Tcl binary library libtclstubs.a @<:@default=/usr/lib@:>@])],
+    [with_tcllib=$withval],
+    [with_tcllib=""])
+
+AC_ARG_WITH(
+    [rappture],
+    [AS_HELP_STRING([--with-rappture[=DIR]],
+        [location of rappture files lib/librappture.a and include/rappture.h @<:@default=/usr@:>@])],
+    [with_rappture=$withval],
+    [with_rappture=yes])
+
+AC_ARG_WITH(
+    [ffmpeg],
+    [AS_HELP_STRING([--with-ffmpeg[=DIR]],
+      [location of ffmpeg @<:@default=yes@:>@])],
+    [],
+    [with_ffmpeg=yes])
+
+AC_ARG_WITH(
+    [avconv],
+    [AS_HELP_STRING([--with-avconv[=DIR]],
+      [location of avconv @<:@default=yes@:>@])],
+    [],
+    [with_avconv=yes])
+
+AC_ARG_WITH(
+    [statsdir],
+    [AS_HELP_STRING([--with-statsdir=DIR],
+        [Write statistics in DIR])],
+    [STATSDIR=$withval],
+    [STATSDIR="/var/tmp/visservers"])
+
+#------------------------------------------------------------------------
+# Handle the --prefix=... option
+#------------------------------------------------------------------------
+
+if test "${prefix}" = "NONE"; then
+    prefix=/usr/local
+fi
+if test "${exec_prefix}" = "NONE"; then
+    exec_prefix=$prefix
+fi
+
+if test "x${incdir}" == "x"; then
+  incdir=${exec_prefix}/include
+fi
+libdir=${exec_prefix}/lib
+
+if test "${libdir}" != "${prefix}/lib"; then
+    LIB_SEARCH_DIRS="-L ${prefix}/lib -L ${libdir}"
+else
+    LIB_SEARCH_DIRS="-L ${libdir}"
+fi
+
+AC_PROG_INSTALL
+AC_PROG_RANLIB
+AC_PROG_LN_S
+AC_PROG_MKDIR_P
+
+dnl find and test the C compiler
+AC_PROG_CC
+AC_PROG_CPP
+AC_PROG_CXXCPP
+AC_PROG_CXX
+AC_LANG_CPLUSPLUS
+
+AC_C_BIGENDIAN
+
+# Save the values as shell variables so that we can substitute them
+# into bltHash.h for situtations where there's no bltInt.h.
+
+
+LD_RPATH="";
+
+#
+# Need to check for the following dependencies:
+#	Rappture headers and library (done)
+#       Tcl headers and library (done)
+#       GL headers and library
+#       GLuT headers and library
+#       GLEW header and library
+#       Cg headers and library
+#       CgGL headers and library
+#       pthread library
+#       ffmpeg headers and library (started)
+#
+
+TCL_VERSION="8.4"
+for dir in \
+ ${exec_prefix} \
+ ${exec_prefix}/lib \
+ ${with_rappture} \
+ ${with_rappture}/lib ; do
+  tclconfig="${dir}/tclConfig.sh"
+  if test -f "$tclconfig" ; then
+    . $tclconfig
+    break
+  fi
+done
+TCL_INC_SPEC="$TCL_INCLUDE_SPEC"
+
+if test "x$with_tcllib" != "x" ; then
+   tclconfig="${with_tcllib}/tclConfig.sh"
+   if test -f "$tclconfig" ; then
+    . $tclconfig
+   fi
+   TCL_LIB_SPEC="-L${with_tcllib} -ltcl${TCL_VERSION}"
+fi
+if test "x$with_tclinclude" != "x" ; then
+   TCL_INC_SPEC="-I${with_tclinclude}"
+fi
+
+RP_DIR=""
+AC_MSG_CHECKING([for rappture])
+if test "$with_rappture" == "yes" ; then
+  for dir in "$exec_prefix" "/usr" ; do
+    if test -r "$dir/include/rappture2/rappture2.h" -a \
+     -r "$dir/lib/librappture.a"; then
+      RP_DIR="$dir"
+      RP_INC_SPEC="-I$dir/include -I$dir/include/rappture2"
+      RP_LIB_DIR="$dir/lib"
+      AC_MSG_RESULT([$dir])
+      break
+    fi
+  done
+else
+  if test ! -d "$with_rappture" ; then 
+    AC_MSG_ERROR([--with-rappture: no such directory $with_rappture])
+  fi
+  RP_DIR=$with_rappture
+  RP_INC_SPEC="-I$with_rappture/include -I$with_rappture/include/rappture2"
+  RP_LIB_DIR="$with_rappture/lib"
+fi
+if test "x${RP_DIR}" = "x" ; then
+  AC_MSG_ERROR([cannot find rappture.h and librappture2.a, try using --with-rappture])
+else
+  AC_MSG_RESULT([$with_rappture])
+fi
+
+AC_CHECK_HEADER([GL/glut.h])
+AC_CHECK_HEADER([GL/glew.h])
+
+AC_CHECK_HEADERS([stdio.h unistd.h stdlib.h string.h sys/types.h])
+AC_CHECK_HEADERS([sys/socket.h sys/time.h netinet/in.h arpa/inet.h netdb.h])
+
+AC_CHECK_FUNCS([accept4])
+
+#--------------------------------------------------------------------
+# search for avconv executable
+#--------------------------------------------------------------------
+if test "${with_avconv}" != "no" ; then
+  if test "${with_avconv}" = "yes" ; then 
+    AC_PATH_PROG(AVCONV, avconv)
+  else 
+    AC_PATH_PROG(AVCONV, avconv, [], [${with_avconv}/bin:${with_avconv}])
+  fi 
+  if test "${AVCONV}x" != "x" ; then
+    AC_DEFINE(HAVE_AVCONV, 1, [nanovis can use avconv to create videos.])
+  fi
+fi
+
+#--------------------------------------------------------------------
+# search for ffmpeg executable
+#--------------------------------------------------------------------
+if test "${with_ffmpeg}" != "no" ; then
+  if test "${with_ffmpeg}" = "yes" ; then 
+    AC_PATH_PROG(FFMPEG, ffmpeg)
+  else 
+    AC_PATH_PROG(FFMPEG, ffmpeg, [], [${with_ffmpeg}/bin:${with_ffmpeg}])
+  fi 
+  if test "${FFMPEG}x" != "x" ; then
+    AC_DEFINE(HAVE_FFMPEG, 1, [nanovis can use ffmpeg to create videos.])
+  fi
+fi
+
+AC_MSG_CHECKING([for nVidia Cg installation])
+CG_DIR=""
+for dir in \
+ /opt/nvidia-cg-toolkit \
+ /usr/cg \
+ /usr
+do
+  if test -r "$dir/include" ; then
+    CG_DIR=$dir
+    break
+  fi
+done
+AC_MSG_RESULT([${CG_DIR}])
+
+CG_INC_SPEC="-I${CG_DIR}/include"
+
+save_CPPFLAGS=$CPPFLAGS
+CPPFLAGS="${CG_INC_SPEC} $CPPFLAGS"
+AC_CHECK_HEADERS([Cg/cgGL.h], [], AC_MSG_WARN([cannot find nVidia Cg headers]))
+CPPFLAGS=$save_CPPFLAGS
+
+CG_LIB_DIR=""
+for dir in \
+ /opt/nvidia-cg-toolkit \
+ /usr/cg \
+ /usr
+do
+  if test -r "$dir/lib" ; then
+    CG_LIB_DIR=$dir/lib
+    break
+  fi
+  if test -r "$dir/lib64" ; then
+    CG_LIB_DIR=$dir/lib64
+    break
+  fi
+done
+
+if test "${CG_LIB_DIR}" = "/usr/lib" ; then
+  CG_INC_SPEC=""
+  CG_LIB_SPEC="-lCg -lCgGL"
+else 
+  CG_LIB_SPEC="-L${CG_LIB_DIR} -lCg -lCgGL"
+  LD_RPATH="$loader_run_path:${CG_LIB_DIR}"
+fi
+
+AC_SUBST(CG_INC_SPEC)
+AC_SUBST(CG_LIB_SPEC)
+AC_SUBST(AVCONV)
+AC_SUBST(FFMPEG)
+AC_SUBST(LD_RPATH)
+AC_SUBST(RP_DIR)
+AC_SUBST(RP_INC_SPEC)
+AC_SUBST(RP_LIB_DIR)
+AC_SUBST(STATSDIR)
+AC_SUBST(TCL_INC_SPEC)
+AC_SUBST(TCL_LIB_SPEC)
+AC_SUBST(TCL_VERSION)
+
+AC_OUTPUT([
+   Doxyfile \
+   Makefile \
+   graphics/Makefile \
+   imgLoaders/Makefile \
+   newmat11/Makefile \
+   util/Makefile \
+   vrmath/Makefile])
Index: /nanovis/tags/1.1.4/define.h
===================================================================
--- /nanovis/tags/1.1.4/define.h	(revision 4930)
+++ /nanovis/tags/1.1.4/define.h	(revision 4930)
@@ -0,0 +1,72 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * ----------------------------------------------------------------------
+ * Nanovis: Visualization of Nanoelectronics Data
+ *
+ * ======================================================================
+ *  AUTHOR:  Wei Qiao <qiaow@purdue.edu>
+ *           Purdue Rendering and Perceptualization Lab (PURPL)
+ *
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ *  See the file "license.terms" for information on usage and
+ *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ * ======================================================================
+ */
+#ifndef DEFINE_H
+#define DEFINE_H
+
+#include <GL/glew.h>
+
+#define CHECK_FRAMEBUFFER_STATUS()                              \
+do {                                                            \
+    GLenum status;                                              \
+    status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);   \
+    switch(status) {                                            \
+    case GL_FRAMEBUFFER_COMPLETE_EXT:                           \
+        TRACE("Framebuffer complete");                          \
+        break;                                                  \
+    case GL_FRAMEBUFFER_UNSUPPORTED_EXT:                        \
+        ERROR("Framebuffer GL_FRAMEBUFFER_UNSUPPORTED_EXT");    \
+        assert(0);                                              \
+        break;                                                  \
+    case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:              \
+        TRACE("Framebuffer INCOMPLETE_ATTACHMENT");             \
+        break;                                                  \
+    case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:      \
+        TRACE("Framebuffer FRAMEBUFFER_MISSING_ATTACHMENT");    \
+        break;                                                  \
+    case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:              \
+        TRACE("Framebuffer FRAMEBUFFER_DIMENSIONS");            \
+        break;                                                  \
+    case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:                 \
+        TRACE("Framebuffer INCOMPLETE_FORMATS");                \
+        break;                                                  \
+    case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:             \
+        TRACE("Framebuffer INCOMPLETE_DRAW_BUFFER");            \
+        break;                                                  \
+    case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:             \
+        TRACE("Framebuffer INCOMPLETE_READ_BUFFER");            \
+        break;                                                  \
+    case GL_FRAMEBUFFER_BINDING_EXT:                            \
+        TRACE("Framebuffer BINDING_EXT");                       \
+        break;                                                  \
+    default:                                                    \
+        ERROR("Unknown framebuffer error %d", status);          \
+        /* programming error; will fail on all hardware */      \
+        assert(0);                                              \
+    }                                                           \
+} while(0)
+
+inline void 
+draw_quad(int w, int h, int tw, int th)
+{
+    glBegin(GL_QUADS);
+    glTexCoord2f(0,         0);         glVertex2f(0,        0);
+    glTexCoord2f((float)tw, 0);         glVertex2f((float)w, 0);
+    glTexCoord2f((float)tw, (float)th); glVertex2f((float)w, (float) h);
+    glTexCoord2f(0,         (float)th); glVertex2f(0,        (float) h);
+    glEnd();
+}
+
+#endif
Index: /nanovis/tags/1.1.4/dxReader.cpp
===================================================================
--- /nanovis/tags/1.1.4/dxReader.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/dxReader.cpp	(revision 4930)
@@ -0,0 +1,499 @@
+ /* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * ----------------------------------------------------------------------
+ * Nanovis: Visualization of Nanoelectronics Data
+ *
+ *  dxReader.cpp 
+ *      This module contains openDX readers for 2D and 3D volumes.
+ *
+ * ======================================================================
+ *  AUTHOR:  Wei Qiao <qiaow@purdue.edu>
+ *           Michael McLennan <mmclennan@purdue.edu>
+ *           Purdue Rendering and Perceptualization Lab (PURPL)
+ *
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ *  See the file "license.terms" for information on usage and
+ *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ * ======================================================================
+ */
+#include <stdio.h>
+#include <math.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <float.h>
+
+#include <fstream>
+#include <iostream>
+#include <sstream>
+#include <string>
+
+#include <RpMesh1D.h>
+#include <RpFieldRect3D.h>
+#include <RpFieldPrism3D.h>
+
+// common file/data reader functions
+#include "ReaderCommon.h"
+
+#include "config.h"
+#include "nanovis.h"
+#include "dxReader.h"
+#include "Unirect.h"
+#include "Volume.h"
+
+using namespace nv;
+
+/**
+ * \brief Load a 3D volume from a dx-format file
+ *
+ * In DX format:
+ *  rank 0 means scalars,
+ *  rank 1 means vectors,
+ *  rank 2 means matrices,
+ *  rank 3 means tensors
+ * 
+ *  For rank 1, shape is a single number equal to the number of dimensions.
+ *  e.g. rank 1 shape 3 means a 3-component vector field
+ */
+Volume *
+nv::load_dx_volume_stream(const char *tag, std::iostream& fin)
+{
+    TRACE("Enter tag:%s", tag);
+
+    Rappture::MeshTri2D xymesh;
+    int dummy, nx, ny, nz, nxy, npts;
+    // origin
+    double x0, y0, z0;
+    // deltas (cell dimensions)
+    double dx, dy, dz;
+    // length of volume edges
+    double lx, ly, lz;
+    // temps for delta values
+    double ddx, ddy, ddz;
+    char line[128], type[128], *start;
+
+    int isrect = 1;
+
+    dx = dy = dz = 0.0;
+    x0 = y0 = z0 = 0.0; // May not have an origin line.
+    nx = ny = nz = npts = nxy = 0;
+    while (!fin.eof()) {
+        fin.getline(line, sizeof(line) - 1);
+        if (fin.fail()) {
+            ERROR("error in data stream");
+            return NULL;
+        }
+        for (start = line; *start == ' ' || *start == '\t'; start++)
+            ;  // skip leading blanks
+
+        if (*start != '#') {  // skip comment lines
+            if (sscanf(start, "object %d class gridpositions counts %d %d %d",
+                       &dummy, &nx, &ny, &nz) == 4) {
+                // found grid size
+                isrect = 1;
+            } else if (sscanf(start, "object %d class array type float rank 1 shape 3 items %d data follows",
+                              &dummy, &nxy) == 2) {
+                isrect = 0;
+
+                double xx, yy, zz;
+                for (int i = 0; i < nxy; i++) {
+                    fin.getline(line,sizeof(line)-1);
+                    if (sscanf(line, "%lg %lg %lg", &xx, &yy, &zz) == 3) {
+                        xymesh.addNode(Rappture::Node2D(xx, yy));
+                    }
+                }
+
+                char fpts[128];
+                sprintf(fpts, "/tmp/tmppts%d", getpid());
+                char fcells[128];
+                sprintf(fcells, "/tmp/tmpcells%d", getpid());
+
+                std::ofstream ftmp(fpts);
+                // save corners of bounding box first, to work around meshing
+                // problems in voronoi utility
+                int numBoundaryPoints = 4;
+
+                // Bump out the bounds by an epsilon to avoid problem when
+                // corner points are already nodes
+                double XEPS = (xymesh.rangeMax(Rappture::xaxis) - 
+                               xymesh.rangeMin(Rappture::xaxis)) / 10.0f;
+
+                double YEPS = (xymesh.rangeMax(Rappture::yaxis) - 
+                               xymesh.rangeMin(Rappture::yaxis)) / 10.0f;
+
+                ftmp << xymesh.rangeMin(Rappture::xaxis) - XEPS << " "
+                     << xymesh.rangeMin(Rappture::yaxis) - YEPS << std::endl;
+                ftmp << xymesh.rangeMax(Rappture::xaxis) + XEPS << " "
+                     << xymesh.rangeMin(Rappture::yaxis) - YEPS << std::endl;
+                ftmp << xymesh.rangeMax(Rappture::xaxis) + XEPS << " "
+                     << xymesh.rangeMax(Rappture::yaxis) + YEPS << std::endl;
+                ftmp << xymesh.rangeMin(Rappture::xaxis) - XEPS << " "
+                     << xymesh.rangeMax(Rappture::yaxis) + YEPS << std::endl;
+
+                for (int i = 0; i < nxy; i++) {
+                    ftmp << xymesh.atNode(i).x() << " " << xymesh.atNode(i).y() << std::endl;
+                }
+                ftmp.close();
+
+                char cmdstr[512];
+                sprintf(cmdstr, "voronoi -t < %s > %s", fpts, fcells);
+                if (system(cmdstr) == 0) {
+                    int cx, cy, cz;
+                    std::ifstream ftri(fcells);
+                    while (!ftri.eof()) {
+                        ftri.getline(line,sizeof(line)-1);
+                        if (sscanf(line, "%d %d %d", &cx, &cy, &cz) == 3) {
+                            if (cx >= numBoundaryPoints &&
+                                cy >= numBoundaryPoints &&
+                                cz >= numBoundaryPoints) {
+                                // skip boundary points we added
+                                xymesh.addCell(cx - numBoundaryPoints,
+                                               cy - numBoundaryPoints,
+                                               cz - numBoundaryPoints);
+                            }
+                        }
+                    }
+                    ftri.close();
+                } else {
+                    ERROR("triangularization failed");
+                    return NULL;
+                }
+                unlink(fpts);
+                unlink(fcells);
+            } else if (sscanf(start, "object %d class regulararray count %d", &dummy, &nz) == 2) {
+                // found z-grid
+            } else if (sscanf(start, "origin %lg %lg %lg", &x0, &y0, &z0) == 3) {
+                // found origin
+            } else if (sscanf(start, "delta %lg %lg %lg", &ddx, &ddy, &ddz) == 3) {
+                // found one of the delta lines
+                int count = 0;
+                if (ddx != 0.0) {
+                    dx = ddx;
+                    count++;
+                }
+                if (ddy != 0.0) {
+                    dy = ddy;
+                    count++;
+                }
+                if (ddz != 0.0) {
+                    dz = ddz;
+                    count++;
+                }
+                if (count > 1) {
+                    ERROR("don't know how to handle multiple non-zero"
+                          " delta values");
+                    return NULL;
+                }
+            } else if (sscanf(start, "object %d class array type %s rank 0 items %d data follows",
+                              &dummy, type, &npts) == 3) {
+                if (isrect && (npts != nx*ny*nz)) {
+                    ERROR("inconsistent data: expected %d points"
+                          " but found %d points", nx*ny*nz, npts);
+                    return NULL;
+                } else if (!isrect && (npts != nxy*nz)) {
+                    ERROR("inconsistent data: expected %d points"
+                          " but found %d points", nxy*nz, npts);
+                    return NULL;
+                }
+                break;
+            } else if (sscanf(start, "object %d class array type %s rank 0 times %d data follows",
+                              &dummy, type, &npts) == 3) {
+                if (npts != nx*ny*nz) {
+                    ERROR("inconsistent data: expected %d points"
+                          " but found %d points", nx*ny*nz, npts);
+                    return NULL;
+                }
+                break;
+            }
+        }
+    }
+
+    TRACE("found nx=%d ny=%d nxy=%d nz=%d\ndx=%g dy=%g dz=%g\nx0=%g y0=%g z0=%g", 
+          nx, ny, nxy, nz, dx, dy, dz, x0, y0, z0);
+
+    lx = (nx - 1) * dx;
+    ly = (ny - 1) * dy;
+    lz = (nz - 1) * dz;
+
+    // read data points
+    if (fin.eof()) {
+        ERROR("data not found in stream");
+        return NULL;
+    }
+    Volume *volume = NULL;
+    float *data = NULL;
+    double vmin = DBL_MAX;
+    double nzero_min = DBL_MAX;
+    double vmax = -DBL_MAX;
+    if (isrect) {
+#ifdef DOWNSAMPLE_DATA
+        Rappture::Mesh1D xgrid(x0, x0 + lx, nx);
+        Rappture::Mesh1D ygrid(y0, y0 + ly, ny);
+        Rappture::Mesh1D zgrid(z0, z0 + lz, nz);
+        Rappture::FieldRect3D field(xgrid, ygrid, zgrid);
+#else // !DOWNSAMPLE_DATA
+        data = new float[nx *  ny *  nz * 4];
+        memset(data, 0, nx*ny*nz*4);
+#endif // DOWNSAMPLE_DATA
+        double dval[6];
+        int nread = 0;
+        int ix = 0;
+        int iy = 0;
+        int iz = 0;
+
+        while (!fin.eof() && nread < npts) {
+            fin.getline(line,sizeof(line)-1);
+            if (fin.fail()) {
+                ERROR("error reading data points");
+                return NULL;
+            }
+            int n = sscanf(line, "%lg %lg %lg %lg %lg %lg",
+                           &dval[0], &dval[1], &dval[2], &dval[3], &dval[4], &dval[5]);
+            for (int p = 0; p < n; p++) {
+#ifdef notdef
+                if (isnan(dval[p])) {
+                    TRACE("Found NAN in input at %d,%d,%d", ix, iy, iz);
+                }
+#endif
+#ifdef DOWNSAMPLE_DATA
+                int nindex = iz*nx*ny + iy*nx + ix;
+                field.define(nindex, dval[p]);
+#else // !DOWNSAMPLE_DATA
+                int nindex = (iz*nx*ny + iy*nx + ix) * 4;
+                data[nindex] = dval[p];
+
+                if (dval[p] < vmin) {
+                    vmin = dval[p];
+                } else if (dval[p] > vmax) {
+                    vmax = dval[p];
+                }
+                if (dval[p] != 0.0 && dval[p] < nzero_min) {
+                    nzero_min = dval[p];
+                }
+#endif // DOWNSAMPLE_DATA
+                nread++;
+                if (++iz >= nz) {
+                    iz = 0;
+                    if (++iy >= ny) {
+                        iy = 0;
+                        ++ix;
+                    }
+                }
+            }
+        }
+
+        // make sure that we read all of the expected points
+        if (nread != npts) {
+            ERROR("inconsistent data: expected %d points"
+                  " but found %d points", npts, nread);
+            return NULL;
+        }
+
+#ifndef DOWNSAMPLE_DATA
+
+        // scale all values [0-1], -1 => out of bounds
+        normalizeScalar(data, npts, 4, vmin, vmax);
+        computeSimpleGradient(data, nx, ny, nz,
+                              dx, dy, dz);
+#else // DOWNSAMPLE_DATA
+        // figure out a good mesh spacing
+        int nsample = 64;
+        double dmin = pow((lx*ly*lz)/((nsample-1)*(nsample-1)*(nsample-1)), 0.333);
+
+        nx = (int)ceil(lx/dmin) + 1;
+        ny = (int)ceil(ly/dmin) + 1;
+        nz = (int)ceil(lz/dmin) + 1;
+
+#ifndef HAVE_NPOT_TEXTURES
+        // must be an even power of 2 for older cards
+        nx = (int)pow(2.0, ceil(log10((double)nx)/log10(2.0)));
+        ny = (int)pow(2.0, ceil(log10((double)ny)/log10(2.0)));
+        nz = (int)pow(2.0, ceil(log10((double)nz)/log10(2.0)));
+#endif
+
+        dx = lx /(double)(nx - 1);
+        dy = ly /(double)(ny - 1);
+        dz = lz /(double)(nz - 1);
+
+        vmin = field.valueMin();
+        vmax = field.valueMax();
+        nzero_min = DBL_MAX;
+        double dv = vmax - vmin;
+        if (dv == 0.0) {
+            dv = 1.0;
+        }
+
+        int ngen = 0;
+#ifdef FILTER_GRADIENTS
+        // Sobel filter expects a single float at
+        // each node
+        const int step = 1;
+        float *cdata = new float[nx*ny*nz * step];
+#else // !FILTER_GRADIENTS
+        // Leave 3 floats of space for gradients
+        // to be filled in by computeSimpleGradient()
+        const int step = 4;
+        data = new float[nx*ny*nz * step];
+#endif // FILTER_GRADIENTS
+
+        for (int iz = 0; iz < nz; iz++) {
+            double zval = z0 + iz*dz;
+            for (int iy = 0; iy < ny; iy++) {
+                double yval = y0 + iy*dy;
+                for (int ix = 0; ix < nx; ix++) {
+                    double xval = x0 + ix*dx;
+                    double v = field.value(xval, yval, zval);
+#ifdef notdef
+                    if (isnan(v)) {
+                        TRACE("NAN at %d,%d,%d: (%g, %g, %g)", ix, iy, iz, xval, yval, zval);
+                    }
+#endif
+                    if (v != 0.0 && v < nzero_min) {
+                        nzero_min = v;
+                    }
+#ifdef FILTER_GRADIENTS
+                    // NOT normalized, may have NaNs (FIXME: how does gradient filter handle NaN?)
+                    cdata[ngen] = v;
+#else // !FILTER_GRADIENTS
+                    // scale all values [0-1], -1 => out of bounds
+                    v = (isnan(v)) ? -1.0 : (v - vmin)/dv;
+                    data[ngen] = v;
+#endif // FILTER_GRADIENTS
+                    ngen += step;
+                }
+            }
+        }
+#ifdef FILTER_GRADIENTS
+        // computeGradient returns a new array with gradients
+        // filled in, so data is now 4 floats per node
+        data = computeGradient(cdata, nx, ny, nz,
+                               dx, dy, dz,
+                               vmin, vmax);
+        delete [] cdata;
+#else // !FILTER_GRADIENTS
+        computeSimpleGradient(data, nx, ny, nz,
+                              dx, dy, dz);
+#endif // FILTER_GRADIENTS
+
+#endif // DOWNSAMPLE_DATA
+    } else {
+        Rappture::Mesh1D zgrid(z0, z0 + (nz-1)*dz, nz);
+        Rappture::FieldPrism3D field(xymesh, zgrid);
+
+        double dval;
+        int nread = 0;
+        int ixy = 0;
+        int iz = 0;
+        while (!fin.eof() && nread < npts) {
+            fin >> dval;
+            if (fin.fail()) {
+                ERROR("after %d of %d points: can't read number", 
+                      nread, npts);
+                return NULL;
+            } else {
+                int nid = nxy*iz + ixy;
+                field.define(nid, dval);
+
+                nread++;
+                if (++iz >= nz) {
+                    iz = 0;
+                    ixy++;
+                }
+            }
+        }
+
+        // make sure that we read all of the expected points
+        if (nread != npts) {
+            ERROR("inconsistent data: expected %d points"
+                  " but found %d points", npts, nread);
+            return NULL;
+        }
+
+        x0 = field.rangeMin(Rappture::xaxis);
+        lx = field.rangeMax(Rappture::xaxis) - field.rangeMin(Rappture::xaxis);
+        y0 = field.rangeMin(Rappture::yaxis);
+        ly = field.rangeMax(Rappture::yaxis) - field.rangeMin(Rappture::yaxis);
+        z0 = field.rangeMin(Rappture::zaxis);
+        lz = field.rangeMax(Rappture::zaxis) - field.rangeMin(Rappture::zaxis);
+
+        // figure out a good mesh spacing
+        int nsample = 64;
+        double dmin = pow((lx*ly*lz)/((nsample-1)*(nsample-1)*(nsample-1)), 0.333);
+
+        nx = (int)ceil(lx/dmin) + 1;
+        ny = (int)ceil(ly/dmin) + 1;
+        nz = (int)ceil(lz/dmin) + 1;
+#ifndef HAVE_NPOT_TEXTURES
+        // must be an even power of 2 for older cards
+        nx = (int)pow(2.0, ceil(log10((double)nx)/log10(2.0)));
+        ny = (int)pow(2.0, ceil(log10((double)ny)/log10(2.0)));
+        nz = (int)pow(2.0, ceil(log10((double)nz)/log10(2.0)));
+#endif
+
+        dx = lx /(double)(nx - 1);
+        dy = ly /(double)(ny - 1);
+        dz = lz /(double)(nz - 1);
+
+        vmin = field.valueMin();
+        vmax = field.valueMax();
+        nzero_min = DBL_MAX;
+        double dv = vmax - vmin;
+        if (dv == 0.0) {
+            dv = 1.0;
+        }
+
+        data = new float[4*nx*ny*nz];
+        // generate the uniformly sampled data that we need for a volume
+        int ngen = 0;
+        for (int iz = 0; iz < nz; iz++) {
+            double zval = z0 + iz*dz;
+            for (int iy = 0; iy < ny; iy++) {
+                double yval = y0 + iy*dy;
+                for (int ix = 0; ix < nx; ix++) {
+                    double xval = x0 + ix*dx;
+                    double v = field.value(xval, yval, zval);
+
+                    if (v != 0.0 && v < nzero_min) {
+                        nzero_min = v;
+                    }
+                    // scale all values [0-1], -1 => out of bounds
+                    v = (isnan(v)) ? -1.0 : (v - vmin)/dv;
+                    data[ngen] = v;
+
+                    ngen += 4;
+                }
+            }
+        }
+
+        computeSimpleGradient(data, nx, ny, nz,
+                              dx, dy, dz);
+    }
+
+    TRACE("nx = %i ny = %i nz = %i", nx, ny, nz);
+    TRACE("x0 = %lg y0 = %lg z0 = %lg", x0, y0, z0);
+    TRACE("lx = %lg ly = %lg lz = %lg", lx, ly, lz);
+    TRACE("dx = %lg dy = %lg dz = %lg", dx, dy, dz);
+    TRACE("dataMin = %lg dataMax = %lg nzero_min = %lg",
+          vmin, vmax, nzero_min);
+
+    volume = NanoVis::loadVolume(tag, nx, ny, nz, 4, data,
+                                 vmin, vmax, nzero_min);
+    volume->xAxis.setRange(x0, x0 + lx);
+    volume->yAxis.setRange(y0, y0 + ly);
+    volume->zAxis.setRange(z0, z0 + lz);
+    volume->updatePending = true;
+
+    delete [] data;
+
+    //
+    // Center this new volume on the origin.
+    //
+    float dx0 = -0.5;
+    float dy0 = -0.5*ly/lx;
+    float dz0 = -0.5*lz/lx;
+    if (volume) {
+        volume->setPosition(vrmath::Vector3f(dx0, dy0, dz0));
+        TRACE("Set volume position to %g %g %g", dx0, dy0, dz0);
+    }
+    return volume;
+}
Index: /nanovis/tags/1.1.4/dxReader.h
===================================================================
--- /nanovis/tags/1.1.4/dxReader.h	(revision 4930)
+++ /nanovis/tags/1.1.4/dxReader.h	(revision 4930)
@@ -0,0 +1,20 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#ifndef DXREADER_H
+#define DXREADER_H
+
+#include <iostream>
+
+namespace nv {
+
+class Volume;
+
+extern Volume *
+load_dx_volume_stream(const char *tag, std::iostream& fin);
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/graphics/Geometry.cpp
===================================================================
--- /nanovis/tags/1.1.4/graphics/Geometry.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/graphics/Geometry.cpp	(revision 4930)
@@ -0,0 +1,68 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ */
+
+#include <GL/glew.h>
+#include <GL/gl.h>
+
+#include "Geometry.h"
+
+using namespace nv::graphics;
+
+Geometry::Geometry(int primitive,
+                   VertexBuffer *vertexBuffer, 
+                   IndexBuffer *indexBuffer) : 
+    _vertexBuffer(vertexBuffer), 
+    _colorBuffer(0),
+    _indexBuffer(indexBuffer), 
+    _primitiveType(primitive)
+{
+}
+
+Geometry::Geometry(int primitive,
+                   VertexBuffer *vertexBuffer, 
+                   VertexBuffer *colorBuffer,
+                   IndexBuffer *indexBuffer) : 
+    _vertexBuffer(vertexBuffer), 
+    _colorBuffer(colorBuffer),
+    _indexBuffer(indexBuffer), 
+    _primitiveType(primitive) 
+{
+}
+
+Geometry::~Geometry()
+{
+}
+
+void 
+Geometry::render()
+{
+    //glDisableClientState(GL_NORMAL_ARRAY);
+    //glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+    glEnableClientState(GL_VERTEX_ARRAY);
+    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer->getGraphicObjectID());
+    glVertexPointer(3, GL_FLOAT, 0, 0);
+
+    if (_colorBuffer) {
+        glEnableClientState(GL_COLOR_ARRAY);
+        glBindBuffer(GL_ARRAY_BUFFER, _colorBuffer->getGraphicObjectID());
+        glColorPointer(3, GL_FLOAT, 0, 0);
+    } else {
+        glDisableClientState(GL_COLOR_ARRAY);
+    }
+    glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+    if (_indexBuffer) {
+        glDrawElements(GL_QUADS, _indexBuffer->getIndexCount(), GL_UNSIGNED_INT, 
+                       _indexBuffer->getData());
+    } else {
+        glBindBuffer(GL_ARRAY_BUFFER, 0);
+        glDrawArrays(_primitiveType, 0, _vertexBuffer->getVertexCount());
+    }
+
+    glDisableClientState(GL_VERTEX_ARRAY);
+    if (_colorBuffer) {
+        glDisableClientState(GL_COLOR_ARRAY);
+    }
+}
Index: /nanovis/tags/1.1.4/graphics/Geometry.h
===================================================================
--- /nanovis/tags/1.1.4/graphics/Geometry.h	(revision 4930)
+++ /nanovis/tags/1.1.4/graphics/Geometry.h	(revision 4930)
@@ -0,0 +1,45 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ */
+#ifndef NV_GRAPHICS_GEOMETRY_H
+#define NV_GRAPHICS_GEOMETRY_H
+
+#include <GL/glew.h>
+
+#include <graphics/VertexBuffer.h>
+#include <graphics/IndexBuffer.h>
+
+namespace nv {
+namespace graphics {
+
+class Geometry
+{
+public:
+    enum {
+        LINES = GL_LINES,
+        LINE_STRIP = GL_LINE_STRIP,
+        TRIANGLES = GL_TRIANGLES,
+        TRIANGLE_STRIP = GL_TRIANGLE_STRIP,
+        QUADS = GL_QUADS
+    };
+
+    Geometry(int primitive, VertexBuffer *vertexBuffer, 
+             IndexBuffer *indexBuffer);
+    Geometry(int primitive, VertexBuffer *pointBuffer, 
+             VertexBuffer *colorBuffer, IndexBuffer *indexBuffer);
+    ~Geometry();
+
+    void render();
+
+private:
+    VertexBuffer *_vertexBuffer;
+    VertexBuffer *_colorBuffer;
+    IndexBuffer *_indexBuffer;
+    int _primitiveType;
+};
+
+}
+}
+
+#endif
Index: /nanovis/tags/1.1.4/graphics/IndexBuffer.cpp
===================================================================
--- /nanovis/tags/1.1.4/graphics/IndexBuffer.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/graphics/IndexBuffer.cpp	(revision 4930)
@@ -0,0 +1,28 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ */
+#include <stdlib.h>
+#include <memory.h>
+
+#include "IndexBuffer.h"
+
+using namespace nv::graphics;
+
+IndexBuffer::IndexBuffer(int indexCount, int* data, bool copy) :
+    _indexCount(indexCount)
+{
+    if (copy) {
+        _data = (int*)malloc(sizeof(int) * indexCount);
+        memcpy(_data, data, sizeof(int) * indexCount);
+    } else {
+        _data = data;
+    }
+}
+
+IndexBuffer::~IndexBuffer()
+{
+    if (_data) {
+        free(_data);
+    }
+}
Index: /nanovis/tags/1.1.4/graphics/IndexBuffer.h
===================================================================
--- /nanovis/tags/1.1.4/graphics/IndexBuffer.h	(revision 4930)
+++ /nanovis/tags/1.1.4/graphics/IndexBuffer.h	(revision 4930)
@@ -0,0 +1,38 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ */
+#ifndef NV_GRAPHICS_INDEX_BUFFER_H
+#define NV_GRAPHICS_INDEX_BUFFER_H
+
+namespace nv {
+namespace graphics {
+
+class IndexBuffer
+{
+public:
+    IndexBuffer(int indexCount, int *data, bool copy = true);
+    ~IndexBuffer();
+
+    int getIndexCount() const;
+    const int *getData() const;
+
+private:
+    int _indexCount;
+    int *_data;
+};
+
+inline int IndexBuffer::getIndexCount() const
+{
+    return _indexCount;
+}
+
+inline const int *IndexBuffer::getData() const
+{
+    return _data;
+}
+
+}
+}
+
+#endif
Index: /nanovis/tags/1.1.4/graphics/Makefile.in
===================================================================
--- /nanovis/tags/1.1.4/graphics/Makefile.in	(revision 4930)
+++ /nanovis/tags/1.1.4/graphics/Makefile.in	(revision 4930)
@@ -0,0 +1,69 @@
+
+SHELL = /bin/sh
+
+.PHONY: all install clean distclean
+
+bindir          = @bindir@
+datadir		= @datadir@
+datarootdir	= @datarootdir@
+exec_prefix     = @exec_prefix@
+includedir      = @includedir@
+libdir          = @libdir@
+mandir          = @mandir@
+prefix          = @prefix@
+srcdir		= @srcdir@
+
+INSTALL		= @INSTALL@
+INSTALL_PROGRAM	= ${INSTALL} -m 555
+INSTALL_DATA	= ${INSTALL} -m 444
+INSTALL_SCRIPT	= ${INSTALL} -m 444
+RM		= rm -f
+AR		= ar rc
+RANLIB		= @RANLIB@
+CC		= @CC@
+CXX		= @CXX@
+VPATH		= $(srcdir)
+
+RP_DIR          =  @RP_DIR@
+RP_INC_SPEC     = -I$(RP_DIR)/include -I$(RP_DIR)/include/rappture2
+
+INCLUDES	= \
+		-I$(srcdir)/include \
+		-I$(srcdir)/.. \
+		$(RP_INC_SPEC)
+
+CFLAGS		= @CFLAGS@ 
+EXTRA_CFLAGS	= -Wall 
+DEFINES		= @DEFINES@
+CXX_SWITCHES	= $(CFLAGS) $(EXTRA_CFLAGS) $(INCLUDES)
+
+NVGRAPHICSLIB	= nvgraphics.a
+
+OBJS		= \
+		Geometry.o \
+		IndexBuffer.o \
+		RenderContext.o \
+		VertexBuffer.o
+
+all: $(NVGRAPHICSLIB)
+
+install: all
+
+$(NVGRAPHICSLIB): $(OBJS)
+	$(RM) $@
+	$(AR) $@ $(OBJS) 
+	$(RANLIB) $@
+
+.cpp.o:
+	$(CXX) $(CXX_SWITCHES) -o $@ -c $<
+
+clean:
+	$(RM) *.a *.o
+
+distclean: clean
+	$(RM) Makefile *~
+
+Geometry.o: Geometry.h IndexBuffer.h VertexBuffer.h
+IndexBuffer.o: IndexBuffer.h
+RenderContext.o: RenderContext.h
+VertexBuffer.o: VertexBuffer.h
Index: /nanovis/tags/1.1.4/graphics/RenderContext.cpp
===================================================================
--- /nanovis/tags/1.1.4/graphics/RenderContext.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/graphics/RenderContext.cpp	(revision 4930)
@@ -0,0 +1,19 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ */
+#include "RenderContext.h"
+
+using namespace nv::graphics;
+
+RenderContext::RenderContext() :
+    _cullMode(NO_CULL),
+    _fillMode(FILL),
+    _shadingModel(SMOOTH)
+{
+}
+
+RenderContext::~RenderContext()
+{
+}
+
Index: /nanovis/tags/1.1.4/graphics/RenderContext.h
===================================================================
--- /nanovis/tags/1.1.4/graphics/RenderContext.h	(revision 4930)
+++ /nanovis/tags/1.1.4/graphics/RenderContext.h	(revision 4930)
@@ -0,0 +1,78 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ */
+#ifndef NV_GRAPHICS_RENDER_CONTEXT_H
+#define NV_GRAPHICS_RENDER_CONTEXT_H
+
+#include <GL/gl.h>
+
+namespace nv {
+namespace graphics {
+
+class RenderContext
+{
+public:
+    enum ShadingModel {
+        FLAT = GL_FLAT ,	//!< Flat Shading
+        SMOOTH = GL_SMOOTH	//!< Smooth shading (Gouraud shading model)
+    };
+
+    enum PolygonMode {
+        LINE = GL_LINE,
+        FILL = GL_FILL
+    };
+
+    enum CullMode {
+        NO_CULL,		//!< No culling
+        BACK= GL_BACK,		//!< Back face culling
+        FRONT= GL_FRONT		//!< Front face culling
+    };
+
+    RenderContext();
+
+    ~RenderContext();
+
+    /**
+     *@brief Set the shading model such as flat, smooth
+     */
+    void setShadingModel(const ShadingModel shadeModel)
+    {
+        _shadingModel = shadeModel;
+    }
+
+    ShadingModel getShadingModel() const
+    {
+        return _shadingModel;
+    }
+
+    void setCullMode(const CullMode cullMode)
+    {
+        _cullMode = cullMode;
+    }
+
+    CullMode getCullMode() const
+    {
+        return _cullMode;
+    }
+
+    void setPolygonMode(const PolygonMode fillMode)
+    {
+        _fillMode = fillMode;
+    }
+
+    PolygonMode getPolygonMode() const
+    {
+        return _fillMode;
+    }
+
+private :
+    CullMode _cullMode;
+    PolygonMode _fillMode;
+    ShadingModel _shadingModel;
+};
+
+}
+}
+
+#endif
Index: /nanovis/tags/1.1.4/graphics/VertexBuffer.cpp
===================================================================
--- /nanovis/tags/1.1.4/graphics/VertexBuffer.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/graphics/VertexBuffer.cpp	(revision 4930)
@@ -0,0 +1,44 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ */
+#include <memory.h>
+#include <stdlib.h>
+
+#include <GL/glew.h>
+#include <GL/gl.h>
+
+#include "VertexBuffer.h"
+
+using namespace nv::graphics;
+
+VertexBuffer::VertexBuffer(int type, int vertexCount,
+                           int byteSize, void *data, bool copy) :
+    _graphicObjectID(0),
+    _byteSize(byteSize),
+    _vertexCount(vertexCount)
+{
+    if (copy) {
+        _data = (void*) malloc(byteSize);
+    } else {
+        _data = data;
+    }
+
+    glGenBuffers(1, &_graphicObjectID);
+    glBindBuffer(GL_ARRAY_BUFFER, _graphicObjectID);
+    glBufferData(GL_ARRAY_BUFFER,
+                 _byteSize,
+                 data,
+                 GL_STATIC_DRAW);
+    glBindBuffer(GL_ARRAY_BUFFER, 0);
+}
+
+VertexBuffer::~VertexBuffer()
+{
+    if (_graphicObjectID != 0) {
+        glDeleteBuffers(1, &_graphicObjectID);
+    }
+    if (_data) {
+        free(_data);
+    }
+}
Index: /nanovis/tags/1.1.4/graphics/VertexBuffer.h
===================================================================
--- /nanovis/tags/1.1.4/graphics/VertexBuffer.h	(revision 4930)
+++ /nanovis/tags/1.1.4/graphics/VertexBuffer.h	(revision 4930)
@@ -0,0 +1,53 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ */
+#ifndef NV_GRAPHICS_VERTEXBUFFER_H
+#define NV_GRAPHICS_VERTEXBUFFER_H
+
+namespace nv {
+namespace graphics {
+
+class VertexBuffer
+{
+public:
+    enum {
+        POSITION3 = 0x01,
+        NORMAL3 = 0x02,
+        COLOR3 = 0x04,
+        COLOR4 = 0x08
+    };
+
+    VertexBuffer(int type, int vertexCount,
+                 int byteSize, void *data, bool copy = true);
+
+    ~VertexBuffer();
+
+    unsigned int getGraphicObjectID() const;
+
+    void updateBuffer(void *data);
+
+    int getVertexCount() const;
+
+    void *_data;
+
+private:
+    unsigned int _graphicObjectID;
+    int _byteSize;
+    int _vertexCount;
+};
+
+inline int VertexBuffer::getVertexCount() const
+{
+    return _vertexCount;
+}
+
+inline unsigned int VertexBuffer::getGraphicObjectID() const
+{
+    return _graphicObjectID;
+}
+
+}
+}
+
+#endif
Index: /nanovis/tags/1.1.4/imgLoaders/BMPImageLoaderImpl.cpp
===================================================================
--- /nanovis/tags/1.1.4/imgLoaders/BMPImageLoaderImpl.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/imgLoaders/BMPImageLoaderImpl.cpp	(revision 4930)
@@ -0,0 +1,141 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+#include <stdio.h>
+#include <memory.h>
+#include <stdlib.h>
+
+#include "BMPImageLoaderImpl.h"
+#include "Image.h"
+#include "Trace.h"
+
+BMPImageLoaderImpl::BMPImageLoaderImpl()
+{
+}
+
+BMPImageLoaderImpl::~BMPImageLoaderImpl()
+{
+}
+
+// I referred to cjbackhouse@hotmail.com                www.backhouse.tk
+Image *BMPImageLoaderImpl::load(const char *fileName)
+{
+    TRACE("BMP loader\n");
+    Image *image = NULL;
+
+    TRACE("opening image file \"%s\"\n", fileName);
+    FILE *f = fopen(fileName, "rb");
+
+    if (!f)  {
+        TRACE("File not found\n");
+        return 0;
+    }
+
+    char header[54];
+    if (fread(&header, 54, 1, f) != 1) {
+        TRACE("can't read header of BMP file\n");
+        return 0;
+    }
+
+    if (header[0] != 'B' ||  header[1] != 'M') {
+        TRACE("File is not BMP format\n");
+        return 0;
+    }
+
+    //it seems gimp sometimes makes its headers small, so we have to do
+    //this. hence all the fseeks
+    int offset = *(unsigned int*)(header+10);
+
+    const unsigned int width = *(int*)(header+18);
+    const unsigned int height = *(int*)(header+22);
+
+    int bits = int(header[28]);           //colourdepth
+
+    TRACE("image width = %d height = %d bits=%d\n", width, height, bits);
+
+    image = new Image(width, height, _targetImageFormat, 
+                      Image::IMG_UNSIGNED_BYTE, NULL);
+
+    TRACE("image created\n");
+
+    unsigned char *bytes = (unsigned char *)image->getImageBuffer();
+    memset(bytes, 0, sizeof(unsigned char) * width * height * _targetImageFormat);
+
+    TRACE("reset image buffer\n");
+
+    unsigned int x, y;
+    unsigned char cols[256*4];	//colourtable
+    switch (bits) {
+    case 24:
+        fseek(f, offset, SEEK_SET);
+        if (_targetImageFormat == Image::IMG_RGB) {
+            if (fread(bytes, width*height*3, 1, f) != 1) {
+                ERROR("can't read image data\n");
+            }
+            for (x = 0; x < width*height*3; x += 3)  { //except the format is BGR, grr
+                unsigned char temp = bytes[x];
+                bytes[x] = bytes[x+2];
+                bytes[x+2] = temp;
+            }
+        } else if (_targetImageFormat == Image::IMG_RGBA) {
+            unsigned char *buff = (unsigned char*)malloc(width * height * sizeof(unsigned char) * 3);
+            if (fread(buff, width*height*3, 1, f) != 1) {
+                ERROR("can't read BMP image data\n");
+            }
+            for (x = 0, y = 0; x < width*height*3; x += 3, y += 4) {       //except the format is BGR, grr
+                bytes[y] = buff[x+2];
+                bytes[y+1] = buff[x+1];
+                bytes[y+2] = buff[x];
+                bytes[y+3] = 255;
+            }
+            free(buff);
+        }
+        break;
+    case 32:
+        fseek(f, offset, SEEK_SET);
+        if (_targetImageFormat == Image::IMG_RGBA) {
+            if (fread(bytes, width*height*4, 1, f) != 1) {
+                ERROR("can't read image data\n");
+            }
+            for (x = 0; x < width*height*4; x += 4)  { //except the format is BGR, grr
+                unsigned char temp = bytes[x];
+                bytes[x] = bytes[x+2];
+                bytes[x+2] = temp;
+            }
+        } else if (_targetImageFormat == Image::IMG_RGB) {
+            unsigned char *buff = (unsigned char*)malloc(width * height * sizeof(unsigned char) * 4);
+            if (fread(buff, width*height*4, 1, f) != 1) {
+                ERROR("can't read BMP image data\n");
+            }
+            for (x = 0, y = 0; x < width*height*4; x += 4, y += 3) {       //except the format is BGR, grr
+                bytes[y] = buff[x+2];
+                bytes[y+1] = buff[x+1];
+                bytes[y+2] = buff[x];
+            }
+            free(buff);
+        }
+        break;
+    case 8:
+        if (fread(cols, 256 * 4, 1, f) != 1) {
+            ERROR("can't read colortable from BMP file\n");
+        }
+        fseek(f,offset,SEEK_SET);  
+        for (y = 0; y < height; ++y) {	//(Notice 4bytes/col for some reason)
+            for (x = 0; x < width; ++x) {
+                unsigned char byte;                 
+                if (fread(&byte, 1, 1, f) != 1) {
+                    ERROR("error reading BMP file\n");
+                }
+                for (int c = 0; c < 3; ++c) {
+                    //bytes[(y*width+x)*3+c] = cols[byte*4+2-c];        //and look up in the table 
+                    bytes[(y*width+x)*_targetImageFormat + c] = cols[byte*4+2-c];       //and look up in the table
+                }
+                if (_targetImageFormat == Image::IMG_RGBA) {
+                    bytes[(y*width+x)*_targetImageFormat + 3] = 255;
+                }
+            }
+        }
+        break;
+    }
+
+    TRACE("image initialized\n");
+    return image;
+}
Index: /nanovis/tags/1.1.4/imgLoaders/BMPImageLoaderImpl.h
===================================================================
--- /nanovis/tags/1.1.4/imgLoaders/BMPImageLoaderImpl.h	(revision 4930)
+++ /nanovis/tags/1.1.4/imgLoaders/BMPImageLoaderImpl.h	(revision 4930)
@@ -0,0 +1,16 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+#ifndef BMP_IMAGE_LOADER_IMPL_H
+#define BMP_IMAGE_LOADER_IMPL_H
+
+#include <ImageLoaderImpl.h>
+
+class BMPImageLoaderImpl : public ImageLoaderImpl
+{
+public:
+    BMPImageLoaderImpl();
+
+    virtual ~BMPImageLoaderImpl();
+
+    virtual Image *load(const char *fileName);
+};
+#endif
Index: /nanovis/tags/1.1.4/imgLoaders/Image.cpp
===================================================================
--- /nanovis/tags/1.1.4/imgLoaders/Image.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/imgLoaders/Image.cpp	(revision 4930)
@@ -0,0 +1,37 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+#include <memory.h>
+#include <stdlib.h>
+
+#include "Image.h"
+
+Image::Image(const unsigned int width, const unsigned int height, 
+	     const ImageFormat format, const Image::DataType type, void *data) :
+    _width(width),
+    _height(height),
+    _format(format),
+    _dataType(type)
+{
+    switch (type) {
+    case IMG_UNSIGNED_BYTE:
+        _dataTypeByteSize = 1;
+        break;
+    case IMG_FLOAT:
+        _dataTypeByteSize = 4;
+        break;
+    }
+
+    //_dataBuffer = aligned_malloc(width * height * comp * _dataTypeByteSize, 16);
+    _dataBuffer = malloc(width * height * format * _dataTypeByteSize);
+
+    if (data != NULL) {
+        memcpy(_dataBuffer, data, width *height * format * _dataTypeByteSize);
+    } else {
+        memset(_dataBuffer, 0, width * height * format * _dataTypeByteSize);
+    }
+}
+
+Image::~Image()
+{
+    //aligend_free(_dataBuffer);
+    free(_dataBuffer);
+}   
Index: /nanovis/tags/1.1.4/imgLoaders/Image.h
===================================================================
--- /nanovis/tags/1.1.4/imgLoaders/Image.h	(revision 4930)
+++ /nanovis/tags/1.1.4/imgLoaders/Image.h	(revision 4930)
@@ -0,0 +1,63 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+#ifndef IMAGE_H
+#define IMAGE_H
+
+class Image
+{
+public:
+    enum DataType {
+        IMG_UNSIGNED_BYTE,
+        IMG_FLOAT
+    };
+
+    enum ImageFormat {
+        IMG_RGB = 3,
+        IMG_RGBA = 4
+    };
+
+    Image(const unsigned int width, const unsigned int height,
+          const ImageFormat format, const DataType dataType, void *data = NULL);
+
+    ~Image();
+
+    unsigned int getWidth() const
+    {
+        return _width;
+    }
+
+    unsigned int getHeight() const
+    {
+        return _height;
+    }
+
+    unsigned int getComponentCount() const
+    {
+        return (unsigned int)_format;
+    }
+
+    unsigned int getDataTypeByteSize() const
+    {
+        return _dataTypeByteSize;
+    }
+
+    DataType getDataType() const
+    {
+        return _dataType;
+    }
+
+    void *getImageBuffer()
+    {
+        return _dataBuffer;
+    }
+
+private:
+    const unsigned int _width;
+    const unsigned int _height;
+    ImageFormat _format;
+    DataType _dataType;
+    unsigned int _dataTypeByteSize;
+    void *_dataBuffer;
+};
+
+#endif
+
Index: /nanovis/tags/1.1.4/imgLoaders/ImageLoader.cpp
===================================================================
--- /nanovis/tags/1.1.4/imgLoaders/ImageLoader.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/imgLoaders/ImageLoader.cpp	(revision 4930)
@@ -0,0 +1,23 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+#include <stdio.h>
+
+#include <map>
+#include <string>
+
+#include "ImageLoader.h"
+#include "ImageLoaderImpl.h"
+
+ImageLoader::ImageLoader() :
+    _loaderImpl(NULL)
+{
+}
+
+Image *ImageLoader::load(const char* fileName, const Image::ImageFormat format)
+{
+    if (_loaderImpl) {
+        _loaderImpl->_targetImageFormat = format;
+        return _loaderImpl->load(fileName);
+    }
+
+    return 0;
+}
Index: /nanovis/tags/1.1.4/imgLoaders/ImageLoader.h
===================================================================
--- /nanovis/tags/1.1.4/imgLoaders/ImageLoader.h	(revision 4930)
+++ /nanovis/tags/1.1.4/imgLoaders/ImageLoader.h	(revision 4930)
@@ -0,0 +1,30 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+#ifndef IMAGE_LOADER_H
+#define IMAGE_LOADER_H
+
+#include <map>
+
+#include <Image.h>
+
+class ImageLoaderImpl;
+
+class ImageLoader
+{
+public:
+    friend class ImageLoaderFactory;
+
+    ImageLoader();
+
+    Image *load(const char *fileName, const Image::ImageFormat targetFormat = Image::IMG_RGB);
+
+private:
+    void setLoaderImpl(ImageLoaderImpl *loaderImpl)
+    {
+        _loaderImpl = loaderImpl;
+    }
+
+    ImageLoaderImpl * _loaderImpl;
+};
+
+#endif
+
Index: /nanovis/tags/1.1.4/imgLoaders/ImageLoaderFactory.cpp
===================================================================
--- /nanovis/tags/1.1.4/imgLoaders/ImageLoaderFactory.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/imgLoaders/ImageLoaderFactory.cpp	(revision 4930)
@@ -0,0 +1,51 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+#include <map>
+#include <string>
+
+#include "ImageLoader.h"
+#include "ImageLoaderImpl.h"
+#include "ImageLoaderFactory.h"
+#include "Trace.h"
+
+ImageLoaderFactory *ImageLoaderFactory::_instance = NULL;
+
+ImageLoaderFactory::ImageLoaderFactory()
+{
+}
+
+ImageLoaderFactory *ImageLoaderFactory::getInstance()
+{
+    if (_instance == NULL) {
+        _instance = new ImageLoaderFactory();
+    }
+
+    return _instance;
+}
+
+void ImageLoaderFactory::addLoaderImpl(const std::string& ext, ImageLoaderImpl *loaderImpl)
+{
+    std::map<std::string, ImageLoaderImpl *>::iterator iter;
+    iter = _loaderImpls.find(ext);
+    if (iter == _loaderImpls.end()) {
+        _loaderImpls[ext] = loaderImpl;
+    } else {
+        TRACE("conflicting data loader for .%s files\n", ext.c_str());
+        return;
+    }
+}
+
+ImageLoader *ImageLoaderFactory::createLoader(const std::string& ext)
+{
+    std::map<std::string, ImageLoaderImpl *>::iterator iter;
+    iter = _loaderImpls.find(ext);
+    if (iter != _loaderImpls.end()) {
+        ImageLoader *imageLoader = new ImageLoader();
+        imageLoader->setLoaderImpl((*iter).second);
+        return imageLoader;
+    } else {
+        TRACE("%s file not supported\n", ext.c_str());
+    }
+    return 0;
+}
+
+
Index: /nanovis/tags/1.1.4/imgLoaders/ImageLoaderFactory.h
===================================================================
--- /nanovis/tags/1.1.4/imgLoaders/ImageLoaderFactory.h	(revision 4930)
+++ /nanovis/tags/1.1.4/imgLoaders/ImageLoaderFactory.h	(revision 4930)
@@ -0,0 +1,29 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+#ifndef IMAGE_LOADER_FACTORY_H
+#define IMAGE_LOADER_FACTORY_H
+
+#include <map>
+#include <string>
+
+class ImageLoaderImpl;
+class Image;
+class ImageLoader;
+
+class ImageLoaderFactory
+{
+public:
+    void addLoaderImpl(const std::string& ext, ImageLoaderImpl *loaderImpl);
+    ImageLoader *createLoader(const std::string& ext);
+
+    static ImageLoaderFactory *getInstance();
+
+protected :
+    ImageLoaderFactory();
+    ~ImageLoaderFactory();
+
+private:
+    std::map<std::string, ImageLoaderImpl *> _loaderImpls;
+    static ImageLoaderFactory *_instance;
+};
+
+#endif
Index: /nanovis/tags/1.1.4/imgLoaders/ImageLoaderImpl.cpp
===================================================================
--- /nanovis/tags/1.1.4/imgLoaders/ImageLoaderImpl.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/imgLoaders/ImageLoaderImpl.cpp	(revision 4930)
@@ -0,0 +1,12 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+#include <stdio.h>
+
+#include "ImageLoaderImpl.h"
+
+ImageLoaderImpl::ImageLoaderImpl()
+{
+}
+
+ImageLoaderImpl::~ImageLoaderImpl()
+{
+}
Index: /nanovis/tags/1.1.4/imgLoaders/ImageLoaderImpl.h
===================================================================
--- /nanovis/tags/1.1.4/imgLoaders/ImageLoaderImpl.h	(revision 4930)
+++ /nanovis/tags/1.1.4/imgLoaders/ImageLoaderImpl.h	(revision 4930)
@@ -0,0 +1,22 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+#ifndef IMAGE_LOADER_IMPL_H
+#define IMAGE_LOADER_IMPL_H
+
+#include <Image.h>
+
+class ImageLoaderImpl
+{
+public:
+    ImageLoaderImpl();
+
+    virtual ~ImageLoaderImpl();
+
+    virtual Image *load(const char *fileName) = 0;
+
+    friend class ImageLoader;
+
+protected:
+    Image::ImageFormat _targetImageFormat;
+};
+
+#endif
Index: /nanovis/tags/1.1.4/imgLoaders/Makefile.in
===================================================================
--- /nanovis/tags/1.1.4/imgLoaders/Makefile.in	(revision 4930)
+++ /nanovis/tags/1.1.4/imgLoaders/Makefile.in	(revision 4930)
@@ -0,0 +1,70 @@
+
+SHELL = /bin/sh
+
+.PHONY: all install clean distclean
+
+bindir          = @bindir@
+datadir		= @datadir@
+datarootdir	= @datarootdir@
+exec_prefix     = @exec_prefix@
+includedir      = @includedir@
+libdir          = @libdir@
+mandir          = @mandir@
+prefix          = @prefix@
+srcdir		= @srcdir@
+
+INSTALL		= @INSTALL@
+INSTALL_PROGRAM	= ${INSTALL} -m 555
+INSTALL_DATA	= ${INSTALL} -m 444
+INSTALL_SCRIPT	= ${INSTALL} -m 444
+RM		= rm -f
+AR		= ar rc
+RANLIB		= @RANLIB@
+CC		= @CC@
+VPATH		= $(srcdir)
+
+RP_DIR          =  @RP_DIR@
+RP_INC_SPEC     = -I$(RP_DIR)/include -I$(RP_DIR)/include/rappture2
+
+INCLUDES	= \
+		-I$(srcdir) \
+		-I$(srcdir)/.. \
+		$(RP_INC_SPEC)
+
+CFLAGS		= @CFLAGS@
+EXTRA_CFLAGS	= -Wall 
+DEFINES		= @DEFINES@
+CC_SWITCHES	= $(CFLAGS) $(EXTRA_CFLAGS) $(INCLUDES)
+
+IMGLIB		= ImageLoaders.a
+
+OBJS		= \
+		BMPImageLoaderImpl.o \
+		Image.o \
+		ImageLoader.o \
+		ImageLoaderFactory.o \
+		ImageLoaderImpl.o 
+
+all: $(IMGLIB)
+
+install: all
+
+$(IMGLIB): $(OBJS)
+	$(RM) $@
+	$(AR) $@ $(OBJS) 
+	$(RANLIB) $@
+
+.cpp.o:
+	$(CC) $(CC_SWITCHES) -o $@ -c $<
+
+clean:
+	$(RM) *.a *.o
+
+distclean: clean
+	$(RM) Makefile *~
+
+BMPImageLoaderImpl.o: BMPImageLoaderImpl.h Image.h $(srcdir)/../Trace.h
+Image.o: Image.h
+ImageLoader.o: ImageLoader.h ImageLoaderImpl.h Image.h
+ImageLoaderFactory.o: ImageLoaderFactory.h ImageLoader.h ImageLoaderImpl.h Image.h $(srcdir)/../Trace.h
+ImageLoaderImpl.o: ImageLoaderImpl.h Image.h
Index: /nanovis/tags/1.1.4/md5.c
===================================================================
--- /nanovis/tags/1.1.4/md5.c	(revision 4930)
+++ /nanovis/tags/1.1.4/md5.c	(revision 4930)
@@ -0,0 +1,381 @@
+/*
+  Copyright (C) 1999, 2000, 2002 Aladdin Enterprises.  All rights reserved.
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  L. Peter Deutsch
+  ghost@aladdin.com
+
+ */
+/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */
+/*
+  Independent implementation of MD5 (RFC 1321).
+
+  This code implements the MD5 Algorithm defined in RFC 1321, whose
+  text is available at
+	http://www.ietf.org/rfc/rfc1321.txt
+  The code is derived from the text of the RFC, including the test suite
+  (section A.5) but excluding the rest of Appendix A.  It does not include
+  any code or documentation that is identified in the RFC as being
+  copyrighted.
+
+  The original and principal author of md5.c is L. Peter Deutsch
+  <ghost@aladdin.com>.  Other authors are noted in the change history
+  that follows (in reverse chronological order):
+
+  2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
+	either statically or dynamically; added missing #include <string.h>
+	in library.
+  2002-03-11 lpd Corrected argument list for main(), and added int return
+	type, in test program and T value program.
+  2002-02-21 lpd Added missing #include <stdio.h> in test program.
+  2000-07-03 lpd Patched to eliminate warnings about "constant is
+	unsigned in ANSI C, signed in traditional"; made test program
+	self-checking.
+  1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+  1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
+  1999-05-03 lpd Original version.
+ */
+
+#include "md5.h"
+#include <string.h>
+
+#undef BYTE_ORDER	/* 1 = big-endian, -1 = little-endian, 0 = unknown */
+#ifdef ARCH_IS_BIG_ENDIAN
+#  define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
+#else
+#  define BYTE_ORDER 0
+#endif
+
+#define T_MASK ((md5_word_t)~0)
+#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
+#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
+#define T3    0x242070db
+#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
+#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
+#define T6    0x4787c62a
+#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
+#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
+#define T9    0x698098d8
+#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
+#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
+#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
+#define T13    0x6b901122
+#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
+#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
+#define T16    0x49b40821
+#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
+#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
+#define T19    0x265e5a51
+#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
+#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
+#define T22    0x02441453
+#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
+#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
+#define T25    0x21e1cde6
+#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
+#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
+#define T28    0x455a14ed
+#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
+#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
+#define T31    0x676f02d9
+#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
+#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
+#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
+#define T35    0x6d9d6122
+#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
+#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
+#define T38    0x4bdecfa9
+#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
+#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
+#define T41    0x289b7ec6
+#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
+#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
+#define T44    0x04881d05
+#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
+#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
+#define T47    0x1fa27cf8
+#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
+#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
+#define T50    0x432aff97
+#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
+#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
+#define T53    0x655b59c3
+#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
+#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
+#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
+#define T57    0x6fa87e4f
+#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
+#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
+#define T60    0x4e0811a1
+#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
+#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
+#define T63    0x2ad7d2bb
+#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
+
+
+static void
+md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
+{
+    md5_word_t
+	a = pms->abcd[0], b = pms->abcd[1],
+	c = pms->abcd[2], d = pms->abcd[3];
+    md5_word_t t;
+#if BYTE_ORDER > 0
+    /* Define storage only for big-endian CPUs. */
+    md5_word_t X[16];
+#else
+    /* Define storage for little-endian or both types of CPUs. */
+    md5_word_t xbuf[16];
+    const md5_word_t *X;
+#endif
+
+    {
+#if BYTE_ORDER == 0
+	/*
+	 * Determine dynamically whether this is a big-endian or
+	 * little-endian machine, since we can use a more efficient
+	 * algorithm on the latter.
+	 */
+	static const int w = 1;
+
+	if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
+#endif
+#if BYTE_ORDER <= 0		/* little-endian */
+	{
+	    /*
+	     * On little-endian machines, we can process properly aligned
+	     * data without copying it.
+	     */
+	    if (!((data - (const md5_byte_t *)0) & 3)) {
+		/* data are properly aligned */
+		X = (const md5_word_t *)data;
+	    } else {
+		/* not aligned */
+		memcpy(xbuf, data, 64);
+		X = xbuf;
+	    }
+	}
+#endif
+#if BYTE_ORDER == 0
+	else			/* dynamic big-endian */
+#endif
+#if BYTE_ORDER >= 0		/* big-endian */
+	{
+	    /*
+	     * On big-endian machines, we must arrange the bytes in the
+	     * right order.
+	     */
+	    const md5_byte_t *xp = data;
+	    int i;
+
+#  if BYTE_ORDER == 0
+	    X = xbuf;		/* (dynamic only) */
+#  else
+#    define xbuf X		/* (static only) */
+#  endif
+	    for (i = 0; i < 16; ++i, xp += 4)
+		xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
+	}
+#endif
+    }
+
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+    /* Round 1. */
+    /* Let [abcd k s i] denote the operation
+       a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
+#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define SET(a, b, c, d, k, s, Ti)\
+  t = a + F(b,c,d) + X[k] + Ti;\
+  a = ROTATE_LEFT(t, s) + b
+    /* Do the following 16 operations. */
+    SET(a, b, c, d,  0,  7,  T1);
+    SET(d, a, b, c,  1, 12,  T2);
+    SET(c, d, a, b,  2, 17,  T3);
+    SET(b, c, d, a,  3, 22,  T4);
+    SET(a, b, c, d,  4,  7,  T5);
+    SET(d, a, b, c,  5, 12,  T6);
+    SET(c, d, a, b,  6, 17,  T7);
+    SET(b, c, d, a,  7, 22,  T8);
+    SET(a, b, c, d,  8,  7,  T9);
+    SET(d, a, b, c,  9, 12, T10);
+    SET(c, d, a, b, 10, 17, T11);
+    SET(b, c, d, a, 11, 22, T12);
+    SET(a, b, c, d, 12,  7, T13);
+    SET(d, a, b, c, 13, 12, T14);
+    SET(c, d, a, b, 14, 17, T15);
+    SET(b, c, d, a, 15, 22, T16);
+#undef SET
+
+     /* Round 2. */
+     /* Let [abcd k s i] denote the operation
+          a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
+#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+  t = a + G(b,c,d) + X[k] + Ti;\
+  a = ROTATE_LEFT(t, s) + b
+     /* Do the following 16 operations. */
+    SET(a, b, c, d,  1,  5, T17);
+    SET(d, a, b, c,  6,  9, T18);
+    SET(c, d, a, b, 11, 14, T19);
+    SET(b, c, d, a,  0, 20, T20);
+    SET(a, b, c, d,  5,  5, T21);
+    SET(d, a, b, c, 10,  9, T22);
+    SET(c, d, a, b, 15, 14, T23);
+    SET(b, c, d, a,  4, 20, T24);
+    SET(a, b, c, d,  9,  5, T25);
+    SET(d, a, b, c, 14,  9, T26);
+    SET(c, d, a, b,  3, 14, T27);
+    SET(b, c, d, a,  8, 20, T28);
+    SET(a, b, c, d, 13,  5, T29);
+    SET(d, a, b, c,  2,  9, T30);
+    SET(c, d, a, b,  7, 14, T31);
+    SET(b, c, d, a, 12, 20, T32);
+#undef SET
+
+     /* Round 3. */
+     /* Let [abcd k s t] denote the operation
+          a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define SET(a, b, c, d, k, s, Ti)\
+  t = a + H(b,c,d) + X[k] + Ti;\
+  a = ROTATE_LEFT(t, s) + b
+     /* Do the following 16 operations. */
+    SET(a, b, c, d,  5,  4, T33);
+    SET(d, a, b, c,  8, 11, T34);
+    SET(c, d, a, b, 11, 16, T35);
+    SET(b, c, d, a, 14, 23, T36);
+    SET(a, b, c, d,  1,  4, T37);
+    SET(d, a, b, c,  4, 11, T38);
+    SET(c, d, a, b,  7, 16, T39);
+    SET(b, c, d, a, 10, 23, T40);
+    SET(a, b, c, d, 13,  4, T41);
+    SET(d, a, b, c,  0, 11, T42);
+    SET(c, d, a, b,  3, 16, T43);
+    SET(b, c, d, a,  6, 23, T44);
+    SET(a, b, c, d,  9,  4, T45);
+    SET(d, a, b, c, 12, 11, T46);
+    SET(c, d, a, b, 15, 16, T47);
+    SET(b, c, d, a,  2, 23, T48);
+#undef SET
+
+     /* Round 4. */
+     /* Let [abcd k s t] denote the operation
+          a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+  t = a + I(b,c,d) + X[k] + Ti;\
+  a = ROTATE_LEFT(t, s) + b
+     /* Do the following 16 operations. */
+    SET(a, b, c, d,  0,  6, T49);
+    SET(d, a, b, c,  7, 10, T50);
+    SET(c, d, a, b, 14, 15, T51);
+    SET(b, c, d, a,  5, 21, T52);
+    SET(a, b, c, d, 12,  6, T53);
+    SET(d, a, b, c,  3, 10, T54);
+    SET(c, d, a, b, 10, 15, T55);
+    SET(b, c, d, a,  1, 21, T56);
+    SET(a, b, c, d,  8,  6, T57);
+    SET(d, a, b, c, 15, 10, T58);
+    SET(c, d, a, b,  6, 15, T59);
+    SET(b, c, d, a, 13, 21, T60);
+    SET(a, b, c, d,  4,  6, T61);
+    SET(d, a, b, c, 11, 10, T62);
+    SET(c, d, a, b,  2, 15, T63);
+    SET(b, c, d, a,  9, 21, T64);
+#undef SET
+
+     /* Then perform the following additions. (That is increment each
+        of the four registers by the value it had before this block
+        was started.) */
+    pms->abcd[0] += a;
+    pms->abcd[1] += b;
+    pms->abcd[2] += c;
+    pms->abcd[3] += d;
+}
+
+void
+md5_init(md5_state_t *pms)
+{
+    pms->count[0] = pms->count[1] = 0;
+    pms->abcd[0] = 0x67452301;
+    pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
+    pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
+    pms->abcd[3] = 0x10325476;
+}
+
+void
+md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
+{
+    const md5_byte_t *p = data;
+    int left = nbytes;
+    int offset = (pms->count[0] >> 3) & 63;
+    md5_word_t nbits = (md5_word_t)(nbytes << 3);
+
+    if (nbytes <= 0)
+	return;
+
+    /* Update the message length. */
+    pms->count[1] += nbytes >> 29;
+    pms->count[0] += nbits;
+    if (pms->count[0] < nbits)
+	pms->count[1]++;
+
+    /* Process an initial partial block. */
+    if (offset) {
+	int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
+
+	memcpy(pms->buf + offset, p, copy);
+	if (offset + copy < 64)
+	    return;
+	p += copy;
+	left -= copy;
+	md5_process(pms, pms->buf);
+    }
+
+    /* Process full blocks. */
+    for (; left >= 64; p += 64, left -= 64)
+	md5_process(pms, p);
+
+    /* Process a final partial block. */
+    if (left)
+	memcpy(pms->buf, p, left);
+}
+
+void
+md5_finish(md5_state_t *pms, md5_byte_t digest[16])
+{
+    static const md5_byte_t pad[64] = {
+	0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+    };
+    md5_byte_t data[8];
+    int i;
+
+    /* Save the length before padding. */
+    for (i = 0; i < 8; ++i)
+	data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
+    /* Pad to 56 bytes mod 64. */
+    md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
+    /* Append the length. */
+    md5_append(pms, data, 8);
+    for (i = 0; i < 16; ++i)
+	digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
+}
Index: /nanovis/tags/1.1.4/md5.h
===================================================================
--- /nanovis/tags/1.1.4/md5.h	(revision 4930)
+++ /nanovis/tags/1.1.4/md5.h	(revision 4930)
@@ -0,0 +1,91 @@
+/*
+  Copyright (C) 1999, 2002 Aladdin Enterprises.  All rights reserved.
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  L. Peter Deutsch
+  ghost@aladdin.com
+
+ */
+/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */
+/*
+  Independent implementation of MD5 (RFC 1321).
+
+  This code implements the MD5 Algorithm defined in RFC 1321, whose
+  text is available at
+	http://www.ietf.org/rfc/rfc1321.txt
+  The code is derived from the text of the RFC, including the test suite
+  (section A.5) but excluding the rest of Appendix A.  It does not include
+  any code or documentation that is identified in the RFC as being
+  copyrighted.
+
+  The original and principal author of md5.h is L. Peter Deutsch
+  <ghost@aladdin.com>.  Other authors are noted in the change history
+  that follows (in reverse chronological order):
+
+  2002-04-13 lpd Removed support for non-ANSI compilers; removed
+	references to Ghostscript; clarified derivation from RFC 1321;
+	now handles byte order either statically or dynamically.
+  1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+  1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
+	added conditionalization for C++ compilation from Martin
+	Purschke <purschke@bnl.gov>.
+  1999-05-03 lpd Original version.
+ */
+
+#ifndef md5_INCLUDED
+#  define md5_INCLUDED
+
+/*
+ * This package supports both compile-time and run-time determination of CPU
+ * byte order.  If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
+ * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
+ * defined as non-zero, the code will be compiled to run only on big-endian
+ * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
+ * run on either big- or little-endian CPUs, but will run slightly less
+ * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
+ */
+
+typedef unsigned char md5_byte_t; /* 8-bit byte */
+typedef unsigned int md5_word_t; /* 32-bit word */
+
+/* Define the state of the MD5 Algorithm. */
+typedef struct md5_state_s {
+    md5_word_t count[2];	/* message length in bits, lsw first */
+    md5_word_t abcd[4];		/* digest buffer */
+    md5_byte_t buf[64];		/* accumulate block */
+} md5_state_t;
+
+#ifdef __cplusplus
+extern "C" 
+{
+#endif
+
+/* Initialize the algorithm. */
+void md5_init(md5_state_t *pms);
+
+/* Append a string to the message. */
+void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);
+
+/* Finish the message and return the digest. */
+void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
+
+#ifdef __cplusplus
+}  /* end extern "C" */
+#endif
+
+#endif /* md5_INCLUDED */
Index: /nanovis/tags/1.1.4/nanovis.cpp
===================================================================
--- /nanovis/tags/1.1.4/nanovis.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/nanovis.cpp	(revision 4930)
@@ -0,0 +1,1491 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * ----------------------------------------------------------------------
+ * Nanovis: Visualization of Nanoelectronics Data
+ *
+ * ======================================================================
+ *  AUTHOR:  Wei Qiao <qiaow@purdue.edu>
+ *           Michael McLennan <mmclennan@purdue.edu>
+ *           Purdue Rendering and Perceptualization Lab (PURPL)
+ *
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ *  See the file "license.terms" for information on usage and
+ *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ * ======================================================================
+ */
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h> // for writev in ppmWrite
+#include <unistd.h>
+
+#include <cassert>
+#include <cerrno>
+#include <cstdlib>
+#include <cstdio>
+#include <cstring>
+#include <cmath>
+
+#include <string>
+
+#include <GL/glew.h>
+#include <GL/glut.h>
+
+#include <graphics/RenderContext.h>
+#include <vrmath/Vector3f.h>
+
+#include <util/FilePath.h>
+#include <util/Fonts.h>
+
+#include <BMPImageLoaderImpl.h>
+#include <ImageLoaderFactory.h>
+
+#include "config.h"
+#include "nanovis.h"
+#include "nanovisServer.h"
+#include "define.h"
+
+#include "Flow.h"
+#include "Grid.h"
+#include "HeightMap.h"
+#include "Camera.h"
+#include "LIC.h"
+#include "Shader.h"
+#include "PlaneRenderer.h"
+#include "Texture2D.h"
+#include "Trace.h"
+#include "TransferFunction.h"
+#include "Unirect.h"
+#include "VelocityArrowsSlice.h"
+#include "Volume.h"
+#include "VolumeInterpolator.h"
+#include "VolumeRenderer.h"
+
+using namespace nv;
+using namespace nv::graphics;
+using namespace nv::util;
+using namespace vrmath;
+
+#define SIZEOF_BMP_HEADER   54
+
+// STATIC MEMBER DATA
+
+Tcl_Interp *NanoVis::interp = NULL;
+
+bool NanoVis::redrawPending = false;
+bool NanoVis::debugFlag = false;
+bool NanoVis::axisOn = true;
+
+int NanoVis::winWidth = NPIX;
+int NanoVis::winHeight = NPIX;
+int NanoVis::renderWindow = 0;
+unsigned char *NanoVis::screenBuffer = NULL;
+Texture2D *NanoVis::legendTexture = NULL;
+Fonts *NanoVis::fonts;
+Camera *NanoVis::_camera = NULL;
+RenderContext *NanoVis::renderContext = NULL;
+
+NanoVis::TransferFunctionHashmap NanoVis::tfTable;
+NanoVis::VolumeHashmap NanoVis::volumeTable;
+NanoVis::FlowHashmap NanoVis::flowTable;
+NanoVis::HeightMapHashmap NanoVis::heightMapTable;
+
+double NanoVis::magMin = DBL_MAX;
+double NanoVis::magMax = -DBL_MAX;
+float NanoVis::xMin = FLT_MAX;
+float NanoVis::xMax = -FLT_MAX;
+float NanoVis::yMin = FLT_MAX;
+float NanoVis::yMax = -FLT_MAX;
+float NanoVis::zMin = FLT_MAX;
+float NanoVis::zMax = -FLT_MAX;
+float NanoVis::wMin = FLT_MAX;
+float NanoVis::wMax = -FLT_MAX;
+Vector3f NanoVis::sceneMin, NanoVis::sceneMax;
+
+VolumeRenderer *NanoVis::volRenderer = NULL;
+VelocityArrowsSlice *NanoVis::velocityArrowsSlice = NULL;
+LIC *NanoVis::licRenderer = NULL;
+PlaneRenderer *NanoVis::planeRenderer = NULL;
+Grid *NanoVis::grid = NULL;
+
+//frame buffer for final rendering
+GLuint NanoVis::_finalFbo = 0;
+GLuint NanoVis::_finalColorTex = 0;
+GLuint NanoVis::_finalDepthRb = 0;
+
+// Default camera location.
+Vector3f def_eye(0.0f, 0.0f, 2.5f);
+
+void
+NanoVis::removeAllData()
+{
+    TRACE("Enter");
+
+    if (grid != NULL) {
+        TRACE("Deleting grid");
+        delete grid;
+    }
+    if (_camera != NULL) {
+        TRACE("Deleting camera");
+        delete _camera;
+    }
+    if (volRenderer != NULL) {
+        TRACE("Deleting volRenderer");
+        delete volRenderer;
+    }
+    if (planeRenderer != NULL) {
+        TRACE("Deleting planeRenderer");
+        delete planeRenderer;
+    }
+    if (legendTexture != NULL) {
+        TRACE("Deleting legendTexture");
+        delete legendTexture;
+    }
+    TRACE("Deleting flows");
+    deleteFlows(interp);
+    if (licRenderer != NULL) {
+        TRACE("Deleting licRenderer");
+        delete licRenderer;
+    }
+    if (velocityArrowsSlice != NULL) {
+        TRACE("Deleting velocityArrowsSlice");
+        delete velocityArrowsSlice;
+    }
+    if (renderContext != NULL) {
+        TRACE("Deleting renderContext");
+        delete renderContext;
+    }
+    if (screenBuffer != NULL) {
+        TRACE("Deleting screenBuffer");
+        delete [] screenBuffer;
+        screenBuffer = NULL;
+    }
+    if (fonts != NULL) {
+        TRACE("Deleting fonts");
+        delete fonts;
+    }
+    TRACE("Leave");
+}
+
+void
+NanoVis::eventuallyRedraw()
+{
+    if (!redrawPending) {
+        glutPostRedisplay();
+        redrawPending = true;
+    }
+}
+
+void
+NanoVis::panCamera(float dx, float dy)
+{
+    /* Move the camera and its target by equal amounts along the x and y
+     * axes. */
+    TRACE("pan: x=%f, y=%f", dx, dy);
+
+    _camera->x(def_eye.x - dx);
+    _camera->y(def_eye.y + dy);
+    TRACE("set eye to %f %f", _camera->x(), _camera->y());
+}
+
+void
+NanoVis::zoomCamera(float z)
+{
+    /* Move the camera and its target by equal amounts along the x and y
+     * axes. */
+    TRACE("zoom: z=%f", z);
+
+    _camera->z(def_eye.z / z);
+
+    collectBounds();
+    _camera->resetClippingRange(sceneMin, sceneMax);
+
+    TRACE("set camera z to %f", _camera->z());
+}
+
+void
+NanoVis::rotateCamera(float phi, float theta, float psi)
+{
+    _camera->orient(phi, theta, psi);
+}
+
+void
+NanoVis::orientCamera(double *quat)
+{
+    _camera->orient(quat);
+}
+
+void
+NanoVis::setCameraPosition(Vector3f pos)
+{
+    _camera->setPosition(pos);
+}
+
+void
+NanoVis::setCameraUpdir(Camera::AxisDirection dir)
+{
+    _camera->setUpdir(dir);
+}
+
+void
+NanoVis::resetCamera(bool resetOrientation)
+{
+    TRACE("Resetting all=%d", resetOrientation ? 1 : 0);
+
+    collectBounds();
+    _camera->reset(sceneMin, sceneMax, resetOrientation);
+
+    def_eye = _camera->getPosition();
+}
+
+/** \brief Load a 3D volume
+ *
+ * \param name Volume ID
+ * \param width Number of samples in X direction
+ * \param height Number of samples in Y direction
+ * \param depth Number of samples in Z direction
+ * \param numComponents the number of scalars for each space point. All component 
+ * scalars for a point are placed consequtively in data array
+ * width, height and depth: number of points in each dimension
+ * \param data Array of floats
+ * \param vmin Min value of field
+ * \param vmax Max value of field
+ * \param nonZeroMin Minimum non-zero value of field
+ * \param data pointer to an array of floats.
+ */
+Volume *
+NanoVis::loadVolume(const char *name, int width, int height, int depth, 
+                    int numComponents, float *data, double vmin, double vmax, 
+                    double nonZeroMin)
+{
+    VolumeHashmap::iterator itr = volumeTable.find(name);
+    if (itr != volumeTable.end()) {
+        WARN("volume \"%s\" already exists", name);
+        removeVolume(itr->second);
+    }
+
+    Volume *volume = new Volume(0.f, 0.f, 0.f,
+                                width, height, depth,
+                                numComponents,
+                                data, vmin, vmax, nonZeroMin);
+    Volume::updatePending = true;
+    volume->name(name);
+    volumeTable[name] = volume;
+
+    return volume;
+}
+
+// Gets a colormap 1D texture by name.
+TransferFunction *
+NanoVis::getTransferFunction(const TransferFunctionId& id) 
+{
+    TransferFunctionHashmap::iterator itr = tfTable.find(id);
+    if (itr == tfTable.end()) {
+        TRACE("No transfer function named \"%s\" found", id.c_str());
+        return NULL;
+    } else {
+        return itr->second;
+    }
+}
+
+// Creates of updates a colormap 1D texture by name.
+TransferFunction *
+NanoVis::defineTransferFunction(const TransferFunctionId& id,
+                                size_t n, float *data)
+{
+    TransferFunction *tf = getTransferFunction(id);
+    if (tf == NULL) {
+        TRACE("Creating new transfer function \"%s\"", id.c_str());
+        tf = new TransferFunction(id.c_str(), n, data);
+        tfTable[id] = tf;
+    } else {
+        TRACE("Updating existing transfer function \"%s\"", id.c_str());
+        tf->update(n, data);
+    }
+    return tf;
+}
+
+int
+NanoVis::renderLegend(TransferFunction *tf, double min, double max,
+                      int width, int height, const char *volArg)
+{
+    TRACE("Enter");
+
+    int old_width = winWidth;
+    int old_height = winHeight;
+
+    planeRenderer->setScreenSize(width, height);
+    resizeOffscreenBuffer(width, height);
+
+    // generate data for the legend
+    float data[512];
+    for (int i=0; i < 256; i++) {
+        data[i] = data[i+256] = (float)(i/255.0);
+    }
+    legendTexture = new Texture2D(256, 2, GL_FLOAT, GL_LINEAR, 1, data);
+    int index = planeRenderer->addPlane(legendTexture, tf);
+    planeRenderer->setActivePlane(index);
+
+    bindOffscreenBuffer();
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //clear screen
+    planeRenderer->render();
+
+    //glPixelStorei(GL_PACK_ALIGNMENT, 1);
+    glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, screenBuffer);
+    {
+        char prefix[200];
+
+        TRACE("Sending ppm legend image %s min:%g max:%g", volArg, min, max);
+        sprintf(prefix, "nv>legend %s %g %g", volArg, min, max);
+        ppmWrite(prefix);
+    }
+    planeRenderer->removePlane(index);
+    resizeOffscreenBuffer(old_width, old_height);
+
+    delete legendTexture;
+    legendTexture = NULL;
+    TRACE("Leave");
+    return TCL_OK;
+}
+
+//initialize frame buffer objects for offscreen rendering
+bool
+NanoVis::initOffscreenBuffer()
+{
+    TRACE("Enter");
+    assert(_finalFbo == 0);
+    // Initialize a fbo for final display.
+    glGenFramebuffersEXT(1, &_finalFbo);
+
+    glGenTextures(1, &_finalColorTex);
+    glBindTexture(GL_TEXTURE_2D, _finalColorTex);
+
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+
+#if defined(HAVE_FLOAT_TEXTURES) && defined(USE_HALF_FLOAT)
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, winWidth, winHeight, 0,
+                 GL_RGB, GL_INT, NULL);
+#elif defined(HAVE_FLOAT_TEXTURES)
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F_ARB, winWidth, winHeight, 0,
+                 GL_RGB, GL_INT, NULL);
+#else
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, winWidth, winHeight, 0,
+                 GL_RGB, GL_INT, NULL);
+#endif
+
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _finalFbo);
+    glGenRenderbuffersEXT(1, &_finalDepthRb);
+    glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, _finalDepthRb);
+    glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, 
+                             winWidth, winHeight);
+    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+                              GL_TEXTURE_2D, _finalColorTex, 0);
+    glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
+                                 GL_RENDERBUFFER_EXT, _finalDepthRb);
+
+    GLenum status;
+    if (!CheckFBO(&status)) {
+        PrintFBOStatus(status, "finalFbo");
+        return false;
+    }
+
+    TRACE("Leave");
+    return true;
+}
+
+//resize the offscreen buffer 
+bool
+NanoVis::resizeOffscreenBuffer(int w, int h)
+{
+    TRACE("Enter (%d, %d)", w, h);
+    if ((w == winWidth) && (h == winHeight)) {
+        return true;
+    }
+    winWidth = w;
+    winHeight = h;
+
+    if (fonts) {
+        fonts->resize(w, h);
+    }
+    TRACE("screenBuffer size: %d %d", w, h);
+
+    if (screenBuffer != NULL) {
+        delete [] screenBuffer;
+        screenBuffer = NULL;
+    }
+
+    screenBuffer = new unsigned char[4*winWidth*winHeight];
+    assert(screenBuffer != NULL);
+
+    //delete the current render buffer resources
+    glDeleteTextures(1, &_finalColorTex);
+    glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, _finalDepthRb);
+    glDeleteRenderbuffersEXT(1, &_finalDepthRb);
+
+    TRACE("before deleteframebuffers");
+    glDeleteFramebuffersEXT(1, &_finalFbo);
+
+    TRACE("reinitialize FBO");
+    //Reinitialize final fbo for final display
+    glGenFramebuffersEXT(1, &_finalFbo);
+
+    glGenTextures(1, &_finalColorTex);
+    glBindTexture(GL_TEXTURE_2D, _finalColorTex);
+
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+
+#if defined(HAVE_FLOAT_TEXTURES) && defined(USE_HALF_FLOAT)
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, winWidth, winHeight, 0,
+                 GL_RGB, GL_INT, NULL);
+#elif defined(HAVE_FLOAT_TEXTURES)
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F_ARB, winWidth, winHeight, 0,
+                 GL_RGB, GL_INT, NULL);
+#else
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, winWidth, winHeight, 0,
+                 GL_RGB, GL_INT, NULL);
+#endif
+
+    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _finalFbo);
+    glGenRenderbuffersEXT(1, &_finalDepthRb);
+    glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, _finalDepthRb);
+    glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, 
+                             winWidth, winHeight);
+    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+                              GL_TEXTURE_2D, _finalColorTex, 0);
+    glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
+                                 GL_RENDERBUFFER_EXT, _finalDepthRb);
+
+    GLenum status;
+    if (!CheckFBO(&status)) {
+        PrintFBOStatus(status, "finalFbo");
+        return false;
+    }
+
+    TRACE("change camera");
+    //change the camera setting
+    _camera->setViewport(0, 0, winWidth, winHeight);
+    planeRenderer->setScreenSize(winWidth, winHeight);
+
+    TRACE("Leave (%d, %d)", w, h);
+    return true;
+}
+
+bool NanoVis::init(const char* path)
+{
+    // print OpenGL driver information
+    TRACE("-----------------------------------------------------------");
+    TRACE("OpenGL version: %s", glGetString(GL_VERSION));
+    TRACE("OpenGL vendor: %s", glGetString(GL_VENDOR));
+    TRACE("OpenGL renderer: %s", glGetString(GL_RENDERER));
+    TRACE("-----------------------------------------------------------");
+
+    if (path == NULL) {
+        ERROR("No path defined for shaders or resources");
+        return false;
+    }
+    GLenum err = glewInit();
+    if (GLEW_OK != err) {
+        ERROR("Can't init GLEW: %s", glewGetErrorString(err));
+        return false;
+    }
+    TRACE("Using GLEW %s", glewGetString(GLEW_VERSION));
+
+    // OpenGL 2.1 includes VBOs, PBOs, MRT, NPOT textures, point parameters, point sprites,
+    // GLSL 1.2, and occlusion queries.
+    if (!GLEW_VERSION_2_1) {
+        ERROR("OpenGL version 2.1 or greater is required");
+        return false;
+    }
+
+    // NVIDIA driver may report OpenGL 2.1, but not support PBOs in 
+    // indirect GLX contexts
+    if (!GLEW_ARB_pixel_buffer_object) {
+        ERROR("Pixel buffer objects are not supported by driver, please check that the user running nanovis has permissions to create a direct rendering context (e.g. user has read/write access to /dev/nvidia* device nodes in Linux).");
+        return false;
+    }
+
+    // Additional extensions not in 2.1 core
+
+    // Framebuffer objects were promoted in 3.0
+    if (!GLEW_EXT_framebuffer_object) {
+        ERROR("EXT_framebuffer_oject extension is required");
+        return false;
+    }
+    // Rectangle textures were promoted in 3.1
+    // FIXME: can use NPOT in place of rectangle textures
+    if (!GLEW_ARB_texture_rectangle) {
+        ERROR("ARB_texture_rectangle extension is required");
+        return false;
+    }
+#ifdef HAVE_FLOAT_TEXTURES
+    // Float color buffers and textures were promoted in 3.0
+    if (!GLEW_ARB_texture_float ||
+        !GLEW_ARB_color_buffer_float) {
+        ERROR("ARB_texture_float and ARB_color_buffer_float extensions are required");
+        return false;
+    }
+#endif
+    // FIXME: should use ARB programs or (preferably) a GLSL profile for portability
+    if (!GLEW_NV_vertex_program3 ||
+        !GLEW_NV_fragment_program2) {
+        ERROR("NV_vertex_program3 and NV_fragment_program2 extensions are required");
+        return false;
+    }
+
+    if (!FilePath::getInstance()->setPath(path)) {
+        ERROR("can't set file path to %s", path);
+        return false;
+    }
+
+    ImageLoaderFactory::getInstance()->addLoaderImpl("bmp", new BMPImageLoaderImpl());
+
+    return true;
+}
+
+bool
+NanoVis::initGL()
+{
+    TRACE("in initGL");
+    //buffer to store data read from the screen
+    if (screenBuffer) {
+        delete[] screenBuffer;
+        screenBuffer = NULL;
+    }
+    screenBuffer = new unsigned char[4*winWidth*winHeight];
+    assert(screenBuffer != NULL);
+
+    //create the camera with default setting
+    _camera = new Camera(0, 0, winWidth, winHeight);
+    _camera->setPosition(def_eye);
+
+    glEnable(GL_TEXTURE_2D);
+    glShadeModel(GL_FLAT);
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    glClearColor(0, 0, 0, 1);
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+    //initialize lighting
+    GLfloat mat_specular[] = {1.0, 1.0, 1.0, 1.0};
+    GLfloat mat_shininess[] = {30.0};
+    GLfloat white_light[] = {1.0, 1.0, 1.0, 1.0};
+
+    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
+    glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
+    glLightfv(GL_LIGHT0, GL_DIFFUSE, white_light);
+    glLightfv(GL_LIGHT0, GL_SPECULAR, white_light);
+    glLightfv(GL_LIGHT1, GL_DIFFUSE, white_light);
+    glLightfv(GL_LIGHT1, GL_SPECULAR, white_light);
+
+    //frame buffer object for offscreen rendering
+    if (!initOffscreenBuffer()) {
+        return false;
+    }
+
+    fonts = new Fonts();
+    fonts->addFont("verdana", "verdana.fnt");
+    fonts->setFont("verdana");
+
+    renderContext = new RenderContext();
+
+    volRenderer = new VolumeRenderer();
+
+    planeRenderer = new PlaneRenderer(winWidth, winHeight);
+
+    velocityArrowsSlice = new VelocityArrowsSlice();
+
+    licRenderer = new LIC();
+
+    grid = new Grid();
+    grid->setFont(fonts);
+
+    //assert(glGetError()==0);
+
+    TRACE("leaving initGL");
+
+    return true;
+}
+
+// used internally to build up the BMP file header
+// Writes an integer value into the header data structure at pos
+static inline void
+bmpHeaderAddInt(unsigned char* header, int& pos, int data)
+{
+#ifdef WORDS_BIGENDIAN
+    header[pos++] = (data >> 24) & 0xFF;
+    header[pos++] = (data >> 16) & 0xFF;
+    header[pos++] = (data >> 8)  & 0xFF;
+    header[pos++] = (data)       & 0xFF;
+#else
+    header[pos++] = data & 0xff;
+    header[pos++] = (data >> 8) & 0xff;
+    header[pos++] = (data >> 16) & 0xff;
+    header[pos++] = (data >> 24) & 0xff;
+#endif
+}
+
+void
+NanoVis::bmpWriteToFile(int frame_number, const char *directory_name)
+{
+    unsigned char header[SIZEOF_BMP_HEADER];
+    int pos = 0;
+    header[pos++] = 'B';
+    header[pos++] = 'M';
+
+    // BE CAREFUL:  BMP files must have an even multiple of 4 bytes
+    // on each scan line.  If need be, we add padding to each line.
+    int pad = 0;
+    if ((3*winWidth) % 4 > 0) {
+        pad = 4 - ((3*winWidth) % 4);
+    }
+
+    // file size in bytes
+    int fsize = (3*winWidth+pad)*winHeight + SIZEOF_BMP_HEADER;
+    bmpHeaderAddInt(header, pos, fsize);
+
+    // reserved value (must be 0)
+    bmpHeaderAddInt(header, pos, 0);
+
+    // offset in bytes to start of bitmap data
+    bmpHeaderAddInt(header, pos, SIZEOF_BMP_HEADER);
+
+    // size of the BITMAPINFOHEADER
+    bmpHeaderAddInt(header, pos, 40);
+
+    // width of the image in pixels
+    bmpHeaderAddInt(header, pos, winWidth);
+
+    // height of the image in pixels
+    bmpHeaderAddInt(header, pos, winHeight);
+
+    // 1 plane + (24 bits/pixel << 16)
+    bmpHeaderAddInt(header, pos, 1572865);
+
+    // no compression
+    // size of image for compression
+    bmpHeaderAddInt(header, pos, 0);
+    bmpHeaderAddInt(header, pos, 0);
+
+    // x pixels per meter
+    // y pixels per meter
+    bmpHeaderAddInt(header, pos, 0);
+    bmpHeaderAddInt(header, pos, 0);
+
+    // number of colors used (0 = compute from bits/pixel)
+    // number of important colors (0 = all colors important)
+    bmpHeaderAddInt(header, pos, 0);
+    bmpHeaderAddInt(header, pos, 0);
+
+    // BE CAREFUL: BMP format wants BGR ordering for screen data
+    unsigned char* scr = screenBuffer;
+    for (int row=0; row < winHeight; row++) {
+        for (int col=0; col < winWidth; col++) {
+            unsigned char tmp = scr[2];
+            scr[2] = scr[0];  // B
+            scr[0] = tmp;     // R
+            scr += 3;
+        }
+        scr += pad;  // skip over padding already in screen data
+    }
+
+    FILE* f;
+    char filename[100];
+    if (frame_number >= 0) {
+        if (directory_name)
+            sprintf(filename, "%s/image%03d.bmp", directory_name, frame_number);
+        else
+            sprintf(filename, "/tmp/flow_animation/image%03d.bmp", frame_number);
+
+        TRACE("Writing %s", filename);
+        f = fopen(filename, "wb");
+        if (f == 0) {
+            ERROR("cannot create file");
+        }
+    } else {
+        f = fopen("/tmp/image.bmp", "wb");
+        if (f == 0) {
+            ERROR("cannot create file");
+        }
+    }
+    if (fwrite(header, SIZEOF_BMP_HEADER, 1, f) != 1) {
+        ERROR("can't write header: short write");
+    }
+    if (fwrite(screenBuffer, (3*winWidth+pad)*winHeight, 1, f) != 1) {
+        ERROR("can't write data: short write");
+    }
+    fclose(f);
+}
+
+void
+NanoVis::bmpWrite(const char *prefix)
+{
+    unsigned char header[SIZEOF_BMP_HEADER];
+    ssize_t nWritten;
+    int pos = 0;
+
+    // BE CAREFUL:  BMP files must have an even multiple of 4 bytes
+    // on each scan line.  If need be, we add padding to each line.
+    int pad = 0;
+    if ((3*winWidth) % 4 > 0) {
+        pad = 4 - ((3*winWidth) % 4);
+    }
+    pad = 0;
+    int fsize = (3*winWidth+pad)*winHeight + sizeof(header);
+
+    char string[200];
+    sprintf(string, "%s %d\n", prefix, fsize);
+    nWritten = write(g_fdOut, string, strlen(string));
+    assert(nWritten == (ssize_t)strlen(string));
+    header[pos++] = 'B';
+    header[pos++] = 'M';
+
+    // file size in bytes
+    bmpHeaderAddInt(header, pos, fsize);
+
+    // reserved value (must be 0)
+    bmpHeaderAddInt(header, pos, 0);
+
+    // offset in bytes to start of bitmap data
+    bmpHeaderAddInt(header, pos, SIZEOF_BMP_HEADER);
+
+    // size of the BITMAPINFOHEADER
+    bmpHeaderAddInt(header, pos, 40);
+
+    // width of the image in pixels
+    bmpHeaderAddInt(header, pos, winWidth);
+
+    // height of the image in pixels
+    bmpHeaderAddInt(header, pos, winHeight);
+
+    // 1 plane + (24 bits/pixel << 16)
+    bmpHeaderAddInt(header, pos, 1572865);
+
+    // no compression
+    // size of image for compression
+    bmpHeaderAddInt(header, pos, 0);
+    bmpHeaderAddInt(header, pos, 0);
+
+    // x pixels per meter
+    // y pixels per meter
+    bmpHeaderAddInt(header, pos, 0);
+    bmpHeaderAddInt(header, pos, 0);
+
+    // number of colors used (0 = compute from bits/pixel)
+    // number of important colors (0 = all colors important)
+    bmpHeaderAddInt(header, pos, 0);
+    bmpHeaderAddInt(header, pos, 0);
+
+    // BE CAREFUL: BMP format wants BGR ordering for screen data
+    unsigned char* scr = screenBuffer;
+    for (int row=0; row < winHeight; row++) {
+        for (int col=0; col < winWidth; col++) {
+            unsigned char tmp = scr[2];
+            scr[2] = scr[0];  // B
+            scr[0] = tmp;     // R
+            scr += 3;
+        }
+        scr += pad;  // skip over padding already in screen data
+    }
+
+    nWritten = write(g_fdOut, header, SIZEOF_BMP_HEADER);
+    assert(nWritten == SIZEOF_BMP_HEADER);
+    nWritten = write(g_fdOut, screenBuffer, (3*winWidth+pad)*winHeight);
+    assert(nWritten == (3*winWidth+pad)*winHeight);
+    g_stats.nFrames++;
+    g_stats.nFrameBytes += (3*winWidth+pad)*winHeight;
+}
+
+/*
+ * ppmWrite --
+ *
+ *  Writes the screen image as PPM binary data to the nanovisviewer
+ *  client.  The PPM binary format is very simple.
+ *
+ *      P6 w h 255\n
+ *      3-byte RGB pixel data.
+ *
+ *  The nanovisviewer client (using the TkImg library) will do less work
+ *  to unpack this format, as opposed to BMP or PNG.  (This doesn't
+ *  eliminate the need to look into DXT compression performed on the GPU).
+ *
+ *      Note that currently the image data from the screen is both row-padded
+ *      and the scan lines are reversed.  This routine could be made even
+ *      simpler (faster) if the screen buffer is an array of packed 3-bytes
+ *      per pixels (no padding) and where the origin is the top-left corner.
+ */
+void
+NanoVis::ppmWrite(const char *prefix)
+{
+#define PPM_MAXVAL 255
+    char header[200];
+
+    TRACE("Enter (%dx%d)", winWidth, winHeight);
+    // Generate the PPM binary file header
+    sprintf(header, "P6 %d %d %d\n", winWidth, winHeight, PPM_MAXVAL);
+
+    size_t header_length = strlen(header);
+    size_t data_length = winWidth * winHeight * 3;
+
+    char command[200];
+    sprintf(command, "%s %lu\n", prefix, 
+            (unsigned long)header_length + data_length);
+
+    size_t wordsPerRow = (winWidth * 24 + 31) / 32;
+    size_t bytesPerRow = wordsPerRow * 4;
+    size_t rowLength = winWidth * 3;
+    size_t nRecs = winHeight + 2;
+
+    struct iovec *iov;
+    iov = (struct iovec *)malloc(sizeof(struct iovec) * nRecs);
+
+    // Write the nanovisviewer command, then the image header and data.
+    // Command
+    iov[0].iov_base = command;
+    iov[0].iov_len = strlen(command);
+    // Header of image data
+    iov[1].iov_base = header;
+    iov[1].iov_len = header_length;
+    // Image data.
+    int y;
+    unsigned char *srcRowPtr = screenBuffer;
+    for (y = winHeight + 1; y >= 2; y--) {
+        iov[y].iov_base = srcRowPtr;
+        iov[y].iov_len = rowLength;
+        srcRowPtr += bytesPerRow;
+    }
+    if (writev(g_fdOut, iov, nRecs) < 0) {
+        ERROR("write failed: %s", strerror(errno));
+    }
+    free(iov);
+    g_stats.nFrames++;
+    g_stats.nFrameBytes += (bytesPerRow * winHeight);
+    TRACE("Leave (%dx%d)", winWidth, winHeight);
+}
+
+void 
+NanoVis::draw3dAxis()
+{
+    if (!axisOn)
+        return;
+
+    glPushAttrib(GL_ENABLE_BIT);
+
+    glDisable(GL_TEXTURE_2D);
+    glEnable(GL_DEPTH_TEST);
+    glEnable(GL_COLOR_MATERIAL);
+    glDisable(GL_BLEND);
+
+    //draw axes
+    GLUquadric *obj;
+
+    obj = gluNewQuadric();
+
+    int segments = 50;
+
+    glColor3f(0.8, 0.8, 0.8);
+    glPushMatrix();
+    glTranslatef(0.4, 0., 0.);
+    glRotatef(90, 1, 0, 0);
+    glRotatef(180, 0, 1, 0);
+    glScalef(0.0005, 0.0005, 0.0005);
+    glutStrokeCharacter(GLUT_STROKE_ROMAN, 'x');
+    glPopMatrix();
+
+    glPushMatrix();
+    glTranslatef(0., 0.4, 0.);
+    glRotatef(90, 1, 0, 0);
+    glRotatef(180, 0, 1, 0);
+    glScalef(0.0005, 0.0005, 0.0005);
+    glutStrokeCharacter(GLUT_STROKE_ROMAN, 'y');
+    glPopMatrix();
+
+    glPushMatrix();
+    glTranslatef(0., 0., 0.4);
+    glRotatef(90, 1, 0, 0);
+    glRotatef(180, 0, 1, 0);
+    glScalef(0.0005, 0.0005, 0.0005);
+    glutStrokeCharacter(GLUT_STROKE_ROMAN, 'z');
+    glPopMatrix();
+
+    glEnable(GL_LIGHTING);
+    glEnable(GL_LIGHT0);
+
+    //glColor3f(0.2, 0.2, 0.8);
+    glPushMatrix();
+    glutSolidSphere(0.02, segments, segments );
+    glPopMatrix();
+
+    glPushMatrix();
+    glRotatef(-90, 1, 0, 0);
+    gluCylinder(obj, 0.01, 0.01, 0.3, segments, segments);
+    glPopMatrix();
+
+    glPushMatrix();
+    glTranslatef(0., 0.3, 0.);
+    glRotatef(-90, 1, 0, 0);
+    gluCylinder(obj, 0.02, 0.0, 0.06, segments, segments);
+    glPopMatrix();
+
+    glPushMatrix();
+    glRotatef(90, 0, 1, 0);
+    gluCylinder(obj, 0.01, 0.01, 0.3, segments, segments);
+    glPopMatrix();
+
+    glPushMatrix();
+    glTranslatef(0.3, 0., 0.);
+    glRotatef(90, 0, 1, 0);
+    gluCylinder(obj, 0.02, 0.0, 0.06, segments, segments);
+    glPopMatrix();
+
+    glPushMatrix();
+    gluCylinder(obj, 0.01, 0.01, 0.3, segments, segments);
+    glPopMatrix();
+
+    glPushMatrix();
+    glTranslatef(0., 0., 0.3);
+    gluCylinder(obj, 0.02, 0.0, 0.06, segments, segments);
+    glPopMatrix();
+
+    gluDeleteQuadric(obj);
+
+    glPopAttrib();
+}
+
+void NanoVis::update()
+{
+    VolumeInterpolator *volInterp = volRenderer->getVolumeInterpolator();
+    if (volInterp->isStarted()) {
+        struct timeval clock;
+        gettimeofday(&clock, NULL);
+        double elapsed_time;
+
+        elapsed_time = clock.tv_sec + clock.tv_usec/1000000.0 -
+            volInterp->getStartTime();
+
+        TRACE("%lf %lf", elapsed_time, 
+              volInterp->getInterval());
+        float fraction;
+        float f;
+
+        f = fmod((float) elapsed_time, (float)volInterp->getInterval());
+        if (f == 0.0) {
+            fraction = 0.0f;
+        } else {
+            fraction = f / volInterp->getInterval();
+        }
+        TRACE("fraction : %f", fraction);
+        volInterp->update(fraction);
+    }
+}
+
+void
+NanoVis::setVolumeRanges()
+{
+    double xMin, xMax, yMin, yMax, zMin, zMax, wMin, wMax;
+
+    TRACE("Enter");
+    xMin = yMin = zMin = wMin = DBL_MAX;
+    xMax = yMax = zMax = wMax = -DBL_MAX;
+    VolumeHashmap::iterator itr;
+    for (itr = volumeTable.begin();
+         itr != volumeTable.end(); ++itr) {
+        Volume *volume = itr->second;
+        if (xMin > volume->xAxis.min()) {
+            xMin = volume->xAxis.min();
+        }
+        if (xMax < volume->xAxis.max()) {
+            xMax = volume->xAxis.max();
+        }
+        if (yMin > volume->yAxis.min()) {
+            yMin = volume->yAxis.min();
+        }
+        if (yMax < volume->yAxis.max()) {
+            yMax = volume->yAxis.max();
+        }
+        if (zMin > volume->zAxis.min()) {
+            zMin = volume->zAxis.min();
+        }
+        if (zMax < volume->zAxis.max()) {
+            zMax = volume->zAxis.max();
+        }
+        if (wMin > volume->wAxis.min()) {
+            wMin = volume->wAxis.min();
+        }
+        if (wMax < volume->wAxis.max()) {
+            wMax = volume->wAxis.max();
+        }
+    }
+    if ((xMin < DBL_MAX) && (xMax > -DBL_MAX)) {
+        grid->xAxis.setScale(xMin, xMax);
+    }
+    if ((yMin < DBL_MAX) && (yMax > -DBL_MAX)) {
+        grid->yAxis.setScale(yMin, yMax);
+    }
+    if ((zMin < DBL_MAX) && (zMax > -DBL_MAX)) {
+        grid->zAxis.setScale(zMin, zMax);
+    }
+    if ((wMin < DBL_MAX) && (wMax > -DBL_MAX)) {
+        Volume::valueMin = wMin;
+        Volume::valueMax = wMax;
+    }
+    Volume::updatePending = false;
+    TRACE("Leave");
+}
+
+void
+NanoVis::setHeightmapRanges()
+{
+    double xMin, xMax, yMin, yMax, zMin, zMax, wMin, wMax;
+
+    TRACE("Enter");
+    xMin = yMin = zMin = wMin = DBL_MAX;
+    xMax = yMax = zMax = wMax = -DBL_MAX;
+    HeightMapHashmap::iterator itr;
+    for (itr = heightMapTable.begin();
+         itr != heightMapTable.end(); ++itr) {
+        HeightMap *heightMap = itr->second;
+        if (xMin > heightMap->xAxis.min()) {
+            xMin = heightMap->xAxis.min();
+        }
+        if (xMax < heightMap->xAxis.max()) {
+            xMax = heightMap->xAxis.max();
+        }
+        if (yMin > heightMap->yAxis.min()) {
+            yMin = heightMap->yAxis.min();
+        }
+        if (yMax < heightMap->yAxis.max()) {
+            yMax = heightMap->yAxis.max();
+        }
+        if (zMin > heightMap->zAxis.min()) {
+            zMin = heightMap->zAxis.min();
+        }
+        if (zMax < heightMap->zAxis.max()) {
+            zMax = heightMap->zAxis.max();
+        }
+        if (wMin > heightMap->wAxis.min()) {
+            wMin = heightMap->wAxis.min();
+        }
+        if (wMax < heightMap->wAxis.max()) {
+            wMax = heightMap->wAxis.max();
+        }
+    }
+    if ((xMin < DBL_MAX) && (xMax > -DBL_MAX)) {
+        grid->xAxis.setScale(xMin, xMax);
+    }
+    if ((yMin < DBL_MAX) && (yMax > -DBL_MAX)) {
+        grid->yAxis.setScale(yMin, yMax);
+    }
+    if ((zMin < DBL_MAX) && (zMax > -DBL_MAX)) {
+        grid->zAxis.setScale(zMin, zMax);
+    }
+    if ((wMin < DBL_MAX) && (wMax > -DBL_MAX)) {
+        HeightMap::valueMin = grid->yAxis.min();
+        HeightMap::valueMax = grid->yAxis.max();
+    }
+    for (HeightMapHashmap::iterator itr = heightMapTable.begin();
+         itr != heightMapTable.end(); ++itr) {
+        itr->second->mapToGrid(grid);
+    }
+    HeightMap::updatePending = false;
+    TRACE("Leave");
+}
+
+void
+NanoVis::collectBounds(bool onlyVisible)
+{
+    if (Flow::updatePending) {
+        setFlowRanges();
+        grid->xAxis.setScale(xMin, xMax);
+        grid->yAxis.setScale(yMin, yMax);
+        grid->zAxis.setScale(zMin, zMax);
+    }
+
+    sceneMin.set(FLT_MAX, FLT_MAX, FLT_MAX);
+    sceneMax.set(-FLT_MAX, -FLT_MAX, -FLT_MAX);
+
+    for (VolumeHashmap::iterator itr = volumeTable.begin();
+         itr != volumeTable.end(); ++itr) {
+        Volume *volume = itr->second;
+
+        if (onlyVisible && !volume->visible())
+            continue;
+
+        Vector3f bmin, bmax;
+        volume->getWorldSpaceBounds(bmin, bmax);
+        if (bmin.x > bmax.x)
+            continue;
+
+        if (sceneMin.x > bmin.x) {
+            sceneMin.x = bmin.x;
+        }
+        if (sceneMax.x < bmax.x) {
+            sceneMax.x = bmax.x;
+        }
+        if (sceneMin.y > bmin.y) {
+            sceneMin.y = bmin.y;
+        }
+        if (sceneMax.y < bmax.y) {
+            sceneMax.y = bmax.y;
+        }
+        if (sceneMin.z > bmin.z) {
+            sceneMin.z = bmin.z;
+        }
+        if (sceneMax.z < bmax.z) {
+            sceneMax.z = bmax.z;
+        }
+    }
+
+    for (HeightMapHashmap::iterator itr = heightMapTable.begin();
+         itr != heightMapTable.end(); ++itr) {
+        HeightMap *heightMap = itr->second;
+
+        if (onlyVisible && !heightMap->isVisible())
+            continue;
+
+        Vector3f bmin, bmax;
+        heightMap->getWorldSpaceBounds(bmin, bmax);
+        if (bmin.x > bmax.x)
+            continue;
+
+        if (sceneMin.x > bmin.x) {
+            sceneMin.x = bmin.x;
+        }
+        if (sceneMax.x < bmax.x) {
+            sceneMax.x = bmax.x;
+        }
+        if (sceneMin.y > bmin.y) {
+            sceneMin.y = bmin.y;
+        }
+        if (sceneMax.y < bmax.y) {
+            sceneMax.y = bmax.y;
+        }
+        if (sceneMin.z > bmin.z) {
+            sceneMin.z = bmin.z;
+        }
+        if (sceneMax.z < bmax.z) {
+            sceneMax.z = bmax.z;
+        }
+    }
+
+    Vector3f flowMin, flowMax;
+    getFlowBounds(flowMin, flowMax, onlyVisible);
+    if (flowMin.x < flowMax.x) {
+        if (sceneMin.x > flowMin.x) {
+            sceneMin.x = flowMin.x;
+        }
+        if (sceneMax.x < flowMax.x) {
+            sceneMax.x = flowMax.x;
+        }
+        if (sceneMin.y > flowMin.y) {
+            sceneMin.y = flowMin.y;
+        }
+        if (sceneMax.y < flowMax.y) {
+            sceneMax.y = flowMax.y;
+        }
+        if (sceneMin.z > flowMin.z) {
+            sceneMin.z = flowMin.z;
+        }
+        if (sceneMax.z < flowMax.z) {
+            sceneMax.z = flowMax.z;
+        }
+    }
+
+    // TODO: Get Grid bounds
+
+    if (sceneMin.x > sceneMax.x) {
+        sceneMin.set(-0.5, -0.5, -0.5);
+        sceneMax.set( 0.5,  0.5,  0.5);
+    }
+
+    TRACE("Scene bounds: (%g,%g,%g) - (%g,%g,%g)",
+          sceneMin.x, sceneMin.y, sceneMin.z,
+          sceneMax.x, sceneMax.y, sceneMax.z);
+}
+
+void
+NanoVis::setBgColor(float color[3])
+{
+    TRACE("Setting bgcolor to %g %g %g", color[0], color[1], color[2]);
+    glClearColor(color[0], color[1], color[2], 1);
+}
+
+void 
+NanoVis::removeVolume(Volume *volume)
+{
+    VolumeHashmap::iterator itr = volumeTable.find(volume->name());
+    if (itr != volumeTable.end()) {
+        volumeTable.erase(itr);
+    }
+    delete volume;
+}
+
+Flow *
+NanoVis::getFlow(const char *name)
+{
+    FlowHashmap::iterator itr = flowTable.find(name);
+    if (itr == flowTable.end()) {
+        TRACE("Can't find flow '%s'", name);
+        return NULL;
+    }
+    return itr->second;
+}
+
+Flow *
+NanoVis::createFlow(Tcl_Interp *interp, const char *name)
+{
+    FlowHashmap::iterator itr = flowTable.find(name);
+    if (itr != flowTable.end()) {
+        ERROR("Flow '%s' already exists", name);
+        return NULL;
+    }
+    Flow *flow = new Flow(interp, name);
+    flowTable[name] = flow;
+    return flow;
+}
+
+/**
+ * \brief Delete flow object and hash table entry
+ *
+ * This is called by the flow command instance delete callback
+ */
+void
+NanoVis::deleteFlow(const char *name)
+{
+    FlowHashmap::iterator itr = flowTable.find(name);
+    if (itr != flowTable.end()) {
+        delete itr->second;
+        flowTable.erase(itr);
+    }
+}
+
+/**
+ * \brief Delete all flow object commands
+ *
+ * This will also delete the flow objects and hash table entries
+ */
+void
+NanoVis::deleteFlows(Tcl_Interp *interp)
+{
+    FlowHashmap::iterator itr;
+    for (itr = flowTable.begin();
+         itr != flowTable.end(); ++itr) {
+        Tcl_DeleteCommandFromToken(interp, itr->second->getCommandToken());
+    }
+    flowTable.clear();
+}
+
+bool
+NanoVis::setFlowRanges()
+{
+    TRACE("Enter");
+
+    /* 
+     * Step 1. Get the overall min and max magnitudes of all the 
+     *         flow vectors.
+     */
+    magMin = DBL_MAX;
+    magMax = -DBL_MAX;
+
+    for (FlowHashmap::iterator itr = flowTable.begin();
+         itr != flowTable.end(); ++itr) {
+        Flow *flow = itr->second;
+        double min, max;
+        if (!flow->isDataLoaded()) {
+            continue;
+        }
+        Unirect3d *data = flow->data();
+        min = data->magMin();
+        max = data->magMax();
+        if (min < magMin) {
+            magMin = min;
+        } 
+        if (max > magMax) {
+            magMax = max;
+        }
+        if (data->xMin() < xMin) {
+            xMin = data->xMin();
+        }
+        if (data->yMin() < yMin) {
+            yMin = data->yMin();
+        }
+        if (data->zMin() < zMin) {
+            zMin = data->zMin();
+        }
+        if (data->xMax() > xMax) {
+            xMax = data->xMax();
+        }
+        if (data->yMax() > yMax) {
+            yMax = data->yMax();
+        }
+        if (data->zMax() > zMax) {
+            zMax = data->zMax();
+        }
+    }
+
+    TRACE("magMin=%g magMax=%g", NanoVis::magMin, NanoVis::magMax);
+
+    /* 
+     * Step 2. Generate the vector field from each data set. 
+     */
+    for (FlowHashmap::iterator itr = flowTable.begin();
+         itr != flowTable.end(); ++itr) {
+        Flow *flow = itr->second;
+        if (!flow->isDataLoaded()) {
+            continue; // Flow exists, but no data has been loaded yet.
+        }
+        if (flow->visible()) {
+            flow->initializeParticles();
+        }
+        if (!flow->scaleVectorField()) {
+            return false;
+        }
+        // FIXME: This doesn't work when there is more than one flow.
+        licRenderer->setSlicePosition(flow->getRelativePosition());
+        velocityArrowsSlice->setSlicePosition(flow->getRelativePosition());
+    }
+    advectFlows();
+
+    Flow::updatePending = false;
+    return true;
+}
+
+void
+NanoVis::getFlowBounds(Vector3f& min,
+                       Vector3f& max,
+                       bool onlyVisible)
+{
+    TRACE("Enter");
+
+    min.set(FLT_MAX, FLT_MAX, FLT_MAX);
+    max.set(-FLT_MAX, -FLT_MAX, -FLT_MAX);
+
+    for (FlowHashmap::iterator itr = flowTable.begin();
+         itr != flowTable.end(); ++itr) {
+        itr->second->getBounds(min, max, onlyVisible);
+    }
+}
+
+void
+NanoVis::renderFlows()
+{
+    for (FlowHashmap::iterator itr = flowTable.begin();
+         itr != flowTable.end(); ++itr) {
+        Flow *flow = itr->second;
+        if (flow->isDataLoaded() && flow->visible()) {
+            flow->render();
+        }
+    }
+}
+
+void
+NanoVis::resetFlows()
+{
+    NanoVis::licRenderer->reset();
+    for (FlowHashmap::iterator itr = flowTable.begin();
+         itr != flowTable.end(); ++itr) {
+        Flow *flow = itr->second;
+        if (flow->isDataLoaded()) {
+            flow->resetParticles();
+        }
+    }
+}    
+
+void
+NanoVis::advectFlows()
+{
+    for (FlowHashmap::iterator itr = flowTable.begin();
+         itr != flowTable.end(); ++itr) {
+        Flow *flow = itr->second;
+        if (flow->isDataLoaded()) {
+            flow->advect();
+        }
+    }
+}
+
+void
+NanoVis::render()
+{
+    TRACE("Enter");
+
+    if (Flow::updatePending) {
+        setFlowRanges();
+        grid->xAxis.setScale(xMin, xMax);
+        grid->yAxis.setScale(yMin, yMax);
+        grid->zAxis.setScale(zMin, zMax);
+    }
+    if (HeightMap::updatePending) {
+        setHeightmapRanges();
+    }
+    if (Volume::updatePending) {
+        setVolumeRanges();
+    }
+
+    // Start final rendering
+
+    // Need to reset fbo since it may have been changed to default (0)
+    bindOffscreenBuffer();
+
+    // Clear screen
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+    glEnable(GL_DEPTH_TEST);
+    glEnable(GL_COLOR_MATERIAL);
+
+    // Emit modelview and projection matrices
+    _camera->initialize();
+
+    // Rotate for updir if required
+    glPushMatrix();
+
+    switch (_camera->getUpdir()) {
+    case Camera::X_POS:
+        glRotatef(90, 0, 0, 1);
+        glRotatef(90, 1, 0, 0);
+        break;
+    case Camera::Y_POS:
+        // this is the default
+        break;
+    case Camera::Z_POS:
+        glRotatef(-90, 1, 0, 0);
+        glRotatef(-90, 0, 0, 1);
+        break;
+    case Camera::X_NEG:
+        glRotatef(-90, 0, 0, 1);
+        break;
+    case Camera::Y_NEG:
+        glRotatef(180, 0, 0, 1);
+        glRotatef(-90, 0, 1, 0);
+        break;
+    case Camera::Z_NEG:
+        glRotatef(90, 1, 0, 0);
+        break;
+    }
+
+    // Now render things in the scene
+
+    draw3dAxis();
+
+    grid->render();
+
+    licRenderer->render();
+
+    velocityArrowsSlice->render();
+
+    renderFlows();
+
+    volRenderer->renderAll();
+
+    for (HeightMapHashmap::iterator itr = heightMapTable.begin();
+         itr != heightMapTable.end(); ++itr) {
+        itr->second->render(renderContext);
+    }
+    glPopMatrix();
+
+    CHECK_FRAMEBUFFER_STATUS();
+    TRACE("Leave");
+    redrawPending = false;
+}
Index: /nanovis/tags/1.1.4/nanovis.h
===================================================================
--- /nanovis/tags/1.1.4/nanovis.h	(revision 4930)
+++ /nanovis/tags/1.1.4/nanovis.h	(revision 4930)
@@ -0,0 +1,175 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * ----------------------------------------------------------------------
+ *  nanovis.h: package header
+ *
+ * ======================================================================
+ *  AUTHOR:  Wei Qiao <qiaow@purdue.edu>
+ *           Purdue Rendering and Perceptualization Lab (PURPL)
+ *
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ *  See the file "license.terms" for information on usage and
+ *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ * ======================================================================
+ */
+#ifndef NV_NANOVIS_H
+#define NV_NANOVIS_H
+
+#include <cstddef> // For size_t
+#include <string>
+#include <tr1/unordered_map>
+
+#include <tcl.h>
+
+#include <GL/glew.h>
+
+#include <vrmath/Vector3f.h>
+
+#include "config.h"
+#include "Camera.h"
+
+//defines for the image based flow visualization
+#define NMESH 256	//resolution of flow mesh
+#define NPIX  512	//display size
+
+namespace nv {
+namespace graphics {
+    class RenderContext;
+}
+namespace util {
+    class Fonts;
+}
+
+class Flow;
+class Grid;
+class HeightMap;
+class LIC;
+class PlaneRenderer;
+class Texture2D;
+class TransferFunction;
+class VelocityArrowsSlice;
+class Volume;
+class VolumeRenderer;
+
+class NanoVis
+{
+public:
+    typedef std::string TransferFunctionId;
+    typedef std::string VolumeId;
+    typedef std::string FlowId;
+    typedef std::string HeightMapId;
+    typedef std::tr1::unordered_map<TransferFunctionId, TransferFunction *> TransferFunctionHashmap;
+    typedef std::tr1::unordered_map<VolumeId, Volume *> VolumeHashmap;
+    typedef std::tr1::unordered_map<FlowId, Flow *> FlowHashmap;
+    typedef std::tr1::unordered_map<HeightMapId, HeightMap *> HeightMapHashmap;
+
+    static bool init(const char *path);
+    static bool initGL();
+    static bool initOffscreenBuffer();
+    static bool resizeOffscreenBuffer(int w, int h);
+    static void setBgColor(float color[3]);
+    static void render();
+    static void draw3dAxis();
+    static void update();
+    static void removeAllData();
+
+    static const Camera *getCamera()
+    {
+        return _camera;
+    }
+    static void panCamera(float dx, float dy);
+    static void zoomCamera(float z);
+    static void rotateCamera(float phi, float theta, float psi);
+    static void orientCamera(double *quat);
+    static void setCameraPosition(vrmath::Vector3f pos);
+    static void setCameraUpdir(Camera::AxisDirection dir);
+    static void resetCamera(bool resetOrientation = false);
+
+    static void eventuallyRedraw();
+
+    static void ppmWrite(const char *prefix);
+    static void bmpWrite(const char *prefix);
+    static void bmpWriteToFile(int frameNum, const char* dirName);
+ 
+    static TransferFunction *getTransferFunction(const TransferFunctionId& id);
+    static TransferFunction *defineTransferFunction(const TransferFunctionId& id, 
+                                                    size_t n, float *data);
+
+    static int renderLegend(TransferFunction *tf, double min, double max, 
+                            int width, int height, const char *volArg);
+
+    static Volume *loadVolume(const char *tag, int width, int height, int depth,
+                              int numComponents, float *data, double vmin, double vmax, 
+                              double nonZeroMin);
+
+    static void removeVolume(Volume *volume);
+
+    static void readScreen()
+    {
+        //glPixelStorei(GL_PACK_ALIGNMENT, 1);
+        glReadPixels(0, 0, winWidth, winHeight, GL_RGB, GL_UNSIGNED_BYTE, 
+                     screenBuffer);
+    }
+    static void bindOffscreenBuffer()
+    {
+        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _finalFbo);
+    }
+
+    static void setVolumeRanges();
+    static void setHeightmapRanges();
+    static bool setFlowRanges();
+
+    static Flow *getFlow(const char *name);
+    static Flow *createFlow(Tcl_Interp *interp, const char *name);
+    static void deleteFlows(Tcl_Interp *interp);
+    static void deleteFlow(const char *name);
+    static void getFlowBounds(vrmath::Vector3f& min,
+                              vrmath::Vector3f& max,
+                              bool onlyVisible = false);
+    static void renderFlows();
+    static void resetFlows();
+    static bool updateFlows();
+    static void advectFlows();
+
+    static Tcl_Interp *interp;
+
+    static bool redrawPending;
+    static bool debugFlag;
+    static bool axisOn;
+
+    static int winWidth;	///< Width of the render window
+    static int winHeight;	///< Height of the render window
+    static int renderWindow;    ///< GLUT handle for the render window
+    static unsigned char *screenBuffer;
+    static Texture2D *legendTexture;
+    static util::Fonts *fonts;
+    static graphics::RenderContext *renderContext;
+
+    static TransferFunctionHashmap tfTable; ///< maps transfunc name to TransferFunction object
+    static VolumeHashmap volumeTable;
+    static FlowHashmap flowTable;
+    static HeightMapHashmap heightMapTable;
+
+    static double magMin, magMax;
+    static float xMin, xMax, yMin, yMax, zMin, zMax, wMin, wMax;
+    static vrmath::Vector3f sceneMin, sceneMax;
+
+    static VolumeRenderer *volRenderer;
+    static VelocityArrowsSlice *velocityArrowsSlice;
+    static LIC *licRenderer;
+    static PlaneRenderer *planeRenderer;
+    static Grid *grid;
+
+private:
+    static void collectBounds(bool onlyVisible = false);
+
+    static Camera *_camera;
+
+    //frame buffer for final rendering
+    static GLuint _finalFbo, _finalColorTex, _finalDepthRb;
+};
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/nanovisServer.cpp
===================================================================
--- /nanovis/tags/1.1.4/nanovisServer.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/nanovisServer.cpp	(revision 4930)
@@ -0,0 +1,652 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+
+#include <cassert>
+#include <cstdio>
+#include <cerrno>
+#include <cstring>
+#include <csignal>
+#include <ctime>
+
+#include <fcntl.h>
+#include <getopt.h>
+#include <sys/time.h>
+#include <sys/times.h>
+#include <sys/uio.h> // for readv/writev
+#include <unistd.h>
+
+#include <sstream>
+
+#include <tcl.h>
+
+#include <GL/glew.h>
+#include <GL/glut.h>
+
+#include <util/FilePath.h>
+
+#include "md5.h"
+
+#include "nanovis.h"
+#include "nanovisServer.h"
+#include "define.h"
+#include "Command.h"
+#include "ReadBuffer.h"
+#include "Shader.h"
+#include "Trace.h"
+
+using namespace nv;
+using namespace nv::util;
+
+Stats nv::g_stats;
+int nv::g_statsFile = -1; ///< Stats output file descriptor.
+int nv::g_fdIn = STDIN_FILENO;     ///< Input file descriptor
+int nv::g_fdOut = STDOUT_FILENO;   ///< Output file descriptor
+FILE *nv::g_fIn = NULL;            ///< Input file handle
+FILE *nv::g_fOut = NULL;           ///< Output file handle
+FILE *nv::g_fLog = NULL;           ///< Trace logging file handle
+ReadBuffer *nv::g_inBufPtr = NULL; ///< Socket read buffer
+
+static void
+writeFrame(int fd, unsigned char *imgData)
+{
+#if 0
+    writePPM(fd, "nv>image -type image -bytes",
+             imgData,
+             NanoVis::winWidth,
+             NanoVis::winHeight);
+#else
+    NanoVis::ppmWrite("nv>image -type image -bytes");
+#endif
+}
+
+static int
+sendAck()
+{
+    std::ostringstream oss;
+    oss << "nv>ok -token " << g_stats.nCommands <<  "\n";
+    std::string str = oss.str();
+    size_t numBytes = str.length();
+
+    TRACE("Sending OK for commands through %lu", g_stats.nCommands);
+    if (write(g_fdOut, str.c_str(), numBytes) < 0) {
+        ERROR("write failed: %s", strerror(errno));
+        return -1;
+    }
+    return 0;
+}
+
+#ifdef KEEPSTATS
+
+#ifndef STATSDIR
+#define STATSDIR	"/var/tmp/visservers"
+#endif  /*STATSDIR*/
+
+int
+nv::getStatsFile(Tcl_Obj *objPtr)
+{
+    Tcl_DString ds;
+    char fileName[33];
+    char pidstr[200];
+    const char *path;
+    md5_state_t state;
+    md5_byte_t digest[16];
+    char *string;
+    int length;
+
+    if ((objPtr == NULL) || (g_statsFile >= 0)) {
+        return g_statsFile;
+    }
+    /* By itself the client's key/value pairs aren't unique.  Add in the
+     * process id of this render server. */
+    sprintf(pidstr, "%ld", (long)g_stats.pid);
+
+    /* Create an md5 hash of the key/value pairs and use it as the file name. */
+    string = Tcl_GetStringFromObj(objPtr, &length);
+    md5_init(&state);
+    md5_append(&state, (const md5_byte_t *)string, strlen(string));
+    md5_append(&state, (const md5_byte_t *)pidstr, strlen(pidstr));
+    md5_finish(&state, digest);
+    for (int i = 0; i < 16; i++) {
+        sprintf(fileName + i * 2, "%02x", digest[i]);
+    }
+    Tcl_DStringInit(&ds);
+    Tcl_DStringAppend(&ds, STATSDIR, -1);
+    Tcl_DStringAppend(&ds, "/", 1);
+    Tcl_DStringAppend(&ds, fileName, 32);
+    path = Tcl_DStringValue(&ds);
+
+    g_statsFile = open(path, O_EXCL | O_CREAT | O_WRONLY, 0600);
+    Tcl_DStringFree(&ds);
+    if (g_statsFile < 0) {
+        ERROR("can't open \"%s\": %s", fileName, strerror(errno));
+        return -1;
+    }
+    return g_statsFile;
+}
+
+int
+nv::writeToStatsFile(int f, const char *s, size_t length)
+{
+    if (f >= 0) {
+        ssize_t numWritten;
+
+        numWritten = write(f, s, length);
+        if (numWritten == (ssize_t)length) {
+            close(dup(f));
+        }
+    }
+    return 0;
+}
+
+static int
+serverStats(int code) 
+{
+    double start, finish;
+    char buf[BUFSIZ];
+    Tcl_DString ds;
+    int result;
+
+    {
+        struct timeval tv;
+
+        /* Get ending time.  */
+        gettimeofday(&tv, NULL);
+        finish = CVT2SECS(tv);
+        tv = g_stats.start;
+        start = CVT2SECS(tv);
+    }
+    /* 
+     * Session information:
+     *   - Name of render server
+     *   - Process ID
+     *   - Hostname where server is running
+     *   - Start date of session
+     *   - Start date of session in seconds
+     *   - Number of frames returned
+     *   - Number of bytes total returned (in frames)
+     *   - Number of commands received
+     *   - Total elapsed time of all commands
+     *   - Total elapsed time of session
+     *   - Exit code of vizserver
+     *   - User time 
+     *   - System time
+     *   - User time of children 
+     *   - System time of children
+     */ 
+
+    Tcl_DStringInit(&ds);
+    
+    Tcl_DStringAppendElement(&ds, "render_stop");
+    /* renderer */
+    Tcl_DStringAppendElement(&ds, "renderer");
+    Tcl_DStringAppendElement(&ds, "nanovis");
+    /* pid */
+    Tcl_DStringAppendElement(&ds, "pid");
+    sprintf(buf, "%ld", (long)g_stats.pid);
+    Tcl_DStringAppendElement(&ds, buf);
+    /* host */
+    Tcl_DStringAppendElement(&ds, "host");
+    gethostname(buf, BUFSIZ-1);
+    buf[BUFSIZ-1] = '\0';
+    Tcl_DStringAppendElement(&ds, buf);
+    /* date */
+    Tcl_DStringAppendElement(&ds, "date");
+    strcpy(buf, ctime(&g_stats.start.tv_sec));
+    buf[strlen(buf) - 1] = '\0';
+    Tcl_DStringAppendElement(&ds, buf);
+    /* date_secs */
+    Tcl_DStringAppendElement(&ds, "date_secs");
+    sprintf(buf, "%ld", g_stats.start.tv_sec);
+    Tcl_DStringAppendElement(&ds, buf);
+    /* num_frames */
+    Tcl_DStringAppendElement(&ds, "num_frames");
+    sprintf(buf, "%lu", (unsigned long)g_stats.nFrames);
+    Tcl_DStringAppendElement(&ds, buf);
+    /* frame_bytes */
+    Tcl_DStringAppendElement(&ds, "frame_bytes");
+    sprintf(buf, "%lu", (unsigned long)g_stats.nFrameBytes);
+    Tcl_DStringAppendElement(&ds, buf);
+    /* num_commands */
+    Tcl_DStringAppendElement(&ds, "num_commands");
+    sprintf(buf, "%lu", (unsigned long)g_stats.nCommands);
+    Tcl_DStringAppendElement(&ds, buf);
+    /* cmd_time */
+    Tcl_DStringAppendElement(&ds, "cmd_time");
+    sprintf(buf, "%g", g_stats.cmdTime);
+    Tcl_DStringAppendElement(&ds, buf);
+    /* session_time */
+    Tcl_DStringAppendElement(&ds, "session_time");
+    sprintf(buf, "%g", finish - start);
+    Tcl_DStringAppendElement(&ds, buf);
+    /* status */
+    Tcl_DStringAppendElement(&ds, "status");
+    sprintf(buf, "%d", code);
+    Tcl_DStringAppendElement(&ds, buf);
+    {
+        long clocksPerSec = sysconf(_SC_CLK_TCK);
+        double clockRes = 1.0 / clocksPerSec;
+        struct tms tms;
+
+        memset(&tms, 0, sizeof(tms));
+        times(&tms);
+        /* utime */
+        Tcl_DStringAppendElement(&ds, "utime");
+        sprintf(buf, "%g", tms.tms_utime * clockRes);
+        Tcl_DStringAppendElement(&ds, buf);
+        /* stime */
+        Tcl_DStringAppendElement(&ds, "stime");
+        sprintf(buf, "%g", tms.tms_stime * clockRes);
+        Tcl_DStringAppendElement(&ds, buf);
+        /* cutime */
+        Tcl_DStringAppendElement(&ds, "cutime");
+        sprintf(buf, "%g", tms.tms_cutime * clockRes);
+        Tcl_DStringAppendElement(&ds, buf);
+        /* cstime */
+        Tcl_DStringAppendElement(&ds, "cstime");
+        sprintf(buf, "%g", tms.tms_cstime * clockRes);
+        Tcl_DStringAppendElement(&ds, buf);
+    }
+    Tcl_DStringAppend(&ds, "\n", -1);
+    int f = getStatsFile(NULL);
+    result = writeToStatsFile(f, Tcl_DStringValue(&ds), 
+                              Tcl_DStringLength(&ds));
+    close(f);
+    Tcl_DStringFree(&ds);
+    return result;
+}
+
+#endif
+
+/**
+ * \brief Send a command with data payload
+ */
+void
+nv::sendDataToClient(const char *command, const char *data, size_t dlen)
+{
+    size_t numRecords = 2;
+    struct iovec *iov = new iovec[numRecords];
+
+    // Write the nanovisviewer command, then the image header and data.
+    // Command
+    iov[0].iov_base = const_cast<char *>(command);
+    iov[0].iov_len = strlen(command);
+    // Data
+    iov[1].iov_base = const_cast<char *>(data);
+    iov[1].iov_len = dlen;
+    if (writev(g_fdOut, iov, numRecords) < 0) {
+        ERROR("write failed: %s", strerror(errno));
+    }
+    delete [] iov;
+}
+
+static void
+initService()
+{
+    g_fIn = fdopen(g_fdIn, "r");
+    // Create a stream associated with the output file descriptor
+    g_fOut = fdopen(g_fdOut, "w");
+    // If running without a socket, use stdout for debugging
+    if (g_fOut == NULL) {
+        g_fdOut = STDOUT_FILENO;
+        g_fOut = stdout;
+    }
+
+    const char* user = getenv("USER");
+    char* logName = NULL;
+    int logNameLen = 0;
+
+    if (user == NULL) {
+        logNameLen = 20+1;
+        logName = (char *)calloc(logNameLen, sizeof(char));
+        strncpy(logName, "/tmp/nanovis_log.txt", logNameLen);
+    } else {
+        logNameLen = 17+1+strlen(user);
+        logName = (char *)calloc(logNameLen, sizeof(char));
+        strncpy(logName, "/tmp/nanovis_log_", logNameLen);
+        strncat(logName, user, strlen(user));
+    }
+
+    // open log and map stderr to log file
+    g_fLog = fopen(logName, "w");
+    dup2(fileno(g_fLog), STDERR_FILENO);
+    // If we are writing to socket, map stdout to log
+    if (g_fdOut != STDOUT_FILENO) {
+        dup2(fileno(g_fLog), STDOUT_FILENO);
+    }
+
+    fflush(stdout);
+
+    // clean up malloc'd memory
+    if (logName != NULL) {
+        free(logName);
+    }
+}
+
+static void
+exitService(int code)
+{
+    TRACE("Enter: %d", code);
+
+    NanoVis::removeAllData();
+
+    Shader::exit();
+
+    //close log file
+    if (g_fLog != NULL) {
+        fclose(g_fLog);
+        g_fLog = NULL;
+    }
+
+#ifdef KEEPSTATS
+    serverStats(code);
+#endif
+    closelog();
+
+    exit(code);
+}
+
+#ifndef USE_NEW_EVENT_LOOP
+
+static int
+executeCommand(Tcl_Interp *interp, Tcl_DString *dsPtr) 
+{
+    int result;
+#ifdef WANT_TRACE
+    char *str = Tcl_DStringValue(dsPtr);
+    std::string cmd(str);
+    cmd.erase(cmd.find_last_not_of(" \n\r\t")+1);
+    TRACE("command %lu: '%s'", g_stats.nCommands+1, cmd.c_str());
+#endif
+
+    result = Tcl_Eval(interp, Tcl_DStringValue(dsPtr));
+    Tcl_DStringSetLength(dsPtr, 0);
+
+    if (result != TCL_OK) {
+        TRACE("Error: %d", result);
+    }
+    return result;
+}
+
+static int
+processCommands(Tcl_Interp *interp, FILE *inFile, int fdOut)
+{
+    int ret = 0;
+    int status = TCL_OK;
+
+    Tcl_DString cmdbuffer;
+    Tcl_DStringInit(&cmdbuffer);
+
+    int flags = fcntl(0, F_GETFL, 0);
+    fcntl(0, F_SETFL, flags & ~O_NONBLOCK);
+
+    //  Read and execute as many commands as we can from stdin...
+    bool isComplete = false;
+    while ((!feof(inFile)) && (status == TCL_OK)) {
+        //
+        //  Read the next command from the buffer.  First time through we
+        //  block here and wait if necessary until a command comes in.
+        //
+        //  BE CAREFUL: Read only one command, up to a newline.  The "volume
+        //  data follows" command needs to be able to read the data
+        //  immediately following the command, and we shouldn't consume it
+        //  here.
+        //
+        while (!feof(inFile)) {
+            int c = fgetc(inFile);
+            char ch;
+            if (c <= 0) {
+                if (errno == EWOULDBLOCK) {
+                    break;
+                }
+                return -1;
+            }
+            ch = (char)c;
+            Tcl_DStringAppend(&cmdbuffer, &ch, 1);
+            if (ch == '\n') {
+                isComplete = Tcl_CommandComplete(Tcl_DStringValue(&cmdbuffer));
+                if (isComplete) {
+                    break;
+                }
+            }
+        }
+        // no command? then we're done for now
+        if (Tcl_DStringLength(&cmdbuffer) == 0) {
+            break;
+        }
+        if (isComplete) {
+            // back to original flags during command evaluation...
+            fcntl(0, F_SETFL, flags & ~O_NONBLOCK);
+            struct timeval start, finish;
+            gettimeofday(&start, NULL);
+            status = executeCommand(interp, &cmdbuffer);
+            gettimeofday(&finish, NULL);
+            // non-blocking for next read -- we might not get anything
+            fcntl(0, F_SETFL, flags | O_NONBLOCK);
+            isComplete = false;
+            g_stats.cmdTime += (MSECS_ELAPSED(start, finish) / 1.0e+3);
+            g_stats.nCommands++;
+            CHECK_FRAMEBUFFER_STATUS();
+        }
+    }
+    fcntl(0, F_SETFL, flags);
+
+    if (status != TCL_OK) {
+        if (handleError(interp, status, fdOut) < 0) {
+            return -1;
+        }
+        TRACE("Leaving on ERROR");
+    }
+
+    return ret;
+}
+#endif
+
+static void
+idle()
+{
+    TRACE("Enter");
+
+    glutSetWindow(NanoVis::renderWindow);
+
+#ifdef USE_NEW_EVENT_LOOP
+    if (nv::processCommands(NanoVis::interp, g_inBufPtr, g_fdOut) < 0) {
+        exitService(1);
+    }
+#else
+    if (processCommands(NanoVis::interp, g_fIn, g_fdOut) < 0) {
+        exitService(1);
+    }
+#endif
+
+    NanoVis::update();
+    NanoVis::bindOffscreenBuffer();
+    NanoVis::render();
+    bool renderedSomething = true;
+    if (renderedSomething) {
+        TRACE("Rendering new frame");
+        NanoVis::readScreen();
+        writeFrame(g_fdOut, NanoVis::screenBuffer);
+    } else {
+        TRACE("No render required");
+        sendAck();
+    }
+
+#ifdef USE_NEW_EVENT_LOOP
+    if (g_inBufPtr->status() == ReadBuffer::ENDFILE) {
+        exitService(0);
+    }
+#else
+    if (feof(g_fIn)) {
+        exitService(0);
+    }
+#endif
+
+    TRACE("Leave");
+}
+
+static
+void shaderErrorCallback(void)
+{
+    if (!Shader::printErrorInfo()) {
+        TRACE("Shader error, exiting...");
+        exitService(1);
+    }
+}
+
+static
+void reshape(int width, int height)
+{
+    NanoVis::resizeOffscreenBuffer(width, height);
+}
+
+int 
+main(int argc, char **argv)
+{
+    // Ignore SIGPIPE.  **Is this needed? **
+    signal(SIGPIPE, SIG_IGN);
+
+    const char *resourcePath = NULL;
+    while (1) {
+        static struct option long_options[] = {
+            {"debug",   no_argument,       NULL, 'd'},
+            {"path",    required_argument, NULL, 'p'},
+            {0, 0, 0, 0}
+        };
+        int option_index = 0;
+        int c = getopt_long(argc, argv, "dp:i:o:", long_options, &option_index);
+        if (c == -1) {
+            break;
+        }
+        switch (c) {
+        case 'd':
+            NanoVis::debugFlag = true;
+            break;
+        case 'p':
+            resourcePath = optarg;
+            break;
+        case 'i': {
+            int fd = atoi(optarg);
+            if (fd >=0 && fd < 5) {
+                g_fdIn = fd;
+            }
+        }
+            break;
+        case 'o': {
+            int fd = atoi(optarg);
+            if (fd >=0 && fd < 5) {
+                g_fdOut = fd;
+            }
+        }
+            break;
+        case '?':
+            break;
+        default:
+            return 1;
+        }
+    }
+
+    initService();
+    initLog();
+
+    memset(&g_stats, 0, sizeof(nv::Stats));
+    g_stats.pid = getpid();
+    gettimeofday(&g_stats.start, NULL);
+
+    TRACE("Starting NanoVis Server");
+    if (NanoVis::debugFlag) {
+        TRACE("Debugging on");
+    }
+
+    // Sanity check: log descriptor can't be used for client IO
+    if (fileno(g_fLog) == g_fdIn) {
+        ERROR("Invalid input file descriptor");
+        return 1;
+    }
+    if (fileno(g_fLog) == g_fdOut) {
+        ERROR("Invalid output file descriptor");
+        return 1;
+    }
+    TRACE("File descriptors: in %d out %d log %d", g_fdIn, g_fdOut, fileno(g_fLog));
+
+    /* This synchronizes the client with the server, so that the client 
+     * doesn't start writing commands before the server is ready. It could
+     * also be used to supply information about the server (version, memory
+     * size, etc). */
+    fprintf(g_fOut, "NanoVis %s (build %s)\n", NANOVIS_VERSION_STRING, SVN_VERSION);
+    fflush(g_fOut);
+
+#ifdef USE_NEW_EVENT_LOOP
+    g_inBufPtr = new ReadBuffer(g_fdIn, 1<<12);
+#endif
+
+    Tcl_Interp *interp = Tcl_CreateInterp();
+    ClientData clientData = NULL;
+
+    initTcl(interp, clientData);
+    NanoVis::interp = interp;
+
+    /* Initialize GLUT here so it can parse and remove GLUT-specific 
+     * command-line options before we parse the command-line below. */
+    glutInit(&argc, argv);
+    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
+    glutInitWindowSize(NanoVis::winWidth, NanoVis::winHeight);
+    glutInitWindowPosition(10, 10);
+    NanoVis::renderWindow = glutCreateWindow("nanovis");
+
+    glutIdleFunc(idle);
+    glutDisplayFunc(NanoVis::render);
+    glutReshapeFunc(reshape);
+
+    char *newResourcePath = NULL;
+    if (resourcePath == NULL) {
+        char *p;
+
+        // See if we can derive the path from the location of the program.
+        // Assume program is in the form <path>/bin/nanovis.
+        resourcePath = argv[0];
+        p = strrchr((char *)resourcePath, '/');
+        if (p != NULL) {
+            *p = '\0';
+            p = strrchr((char *)resourcePath, '/');
+        }
+        if (p == NULL) {
+            ERROR("Resource path not specified, and could not determine a valid path");
+            return 1;
+        }
+        *p = '\0';
+        newResourcePath = new char[(strlen(resourcePath) + 15) * 2 + 1];
+        sprintf(newResourcePath, "%s/lib/shaders:%s/lib/resources", resourcePath, resourcePath);
+        resourcePath = newResourcePath;
+        TRACE("No resource path specified, using: %s", resourcePath);
+    } else {
+        TRACE("Resource path: '%s'", resourcePath);
+    }
+
+    FilePath::getInstance()->setWorkingDirectory(argc, (const char**) argv);
+
+    if (!NanoVis::init(resourcePath)) {
+        exitService(1);
+    }
+    if (newResourcePath != NULL) {
+        delete [] newResourcePath;
+    }
+
+    Shader::init();
+    // Override callback with one that cleans up server on exit
+    Shader::setErrorCallback(shaderErrorCallback);
+
+    if (!NanoVis::initGL()) {
+        exitService(1);
+    }
+
+    if (!NanoVis::resizeOffscreenBuffer(NanoVis::winWidth, NanoVis::winHeight)) {
+        exitService(1);
+    }
+
+    glutMainLoop();
+
+    exitService(0);
+}
Index: /nanovis/tags/1.1.4/nanovisServer.h
===================================================================
--- /nanovis/tags/1.1.4/nanovisServer.h	(revision 4930)
+++ /nanovis/tags/1.1.4/nanovisServer.h	(revision 4930)
@@ -0,0 +1,57 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2013  HUBzero Foundation, LLC
+ *
+ */
+#ifndef NANOVIS_SERVER_H
+#define NANOVIS_SERVER_H
+
+#include <sys/types.h> // For pid_t
+#include <sys/time.h>  // For struct timeval
+#include <cstddef>     // For size_t
+#include <cstdio>      // For FILE *
+
+#include <tcl.h>
+
+#include "config.h"
+
+#define NANOVIS_VERSION_STRING "1.1.4"
+
+#define MSECS_ELAPSED(t1, t2) \
+    ((t1).tv_sec == (t2).tv_sec ? (((t2).tv_usec - (t1).tv_usec)/1.0e+3) : \
+     (((t2).tv_sec - (t1).tv_sec))*1.0e+3 + (double)((t2).tv_usec - (t1).tv_usec)/1.0e+3)
+
+#define CVT2SECS(x)  ((double)(x).tv_sec) + ((double)(x).tv_usec * 1.0e-6)
+
+namespace nv {
+    class ReadBuffer;
+
+    typedef struct {
+        pid_t pid;
+        size_t nFrames;            /**< # of frames sent to client. */
+        size_t nFrameBytes;        /**< # of bytes for all frames. */
+        size_t nCommands;          /**< # of commands executed */
+        double cmdTime;            /**< Elasped time spend executing
+                                    * commands. */
+        struct timeval start;      /**< Start of elapsed time. */
+    } Stats;
+
+    extern Stats g_stats;
+
+    extern int g_statsFile;        ///< Stats file descriptor
+    extern int g_fdIn;             ///< Input file descriptor
+    extern int g_fdOut;            ///< Output file descriptor
+    extern FILE *g_fIn;            ///< Input file handle
+    extern FILE *g_fOut;           ///< Output file handle
+    extern FILE *g_fLog;           ///< Trace logging file handle
+    extern ReadBuffer *g_inBufPtr; ///< Socket read buffer
+
+#ifdef KEEPSTATS
+    extern int getStatsFile(Tcl_Obj *objPtr);
+    extern int writeToStatsFile(int f, const char *s, size_t length);
+#endif
+    extern void sendDataToClient(const char *command, const char *data,
+                                 size_t dlen);
+}
+
+#endif
Index: /nanovis/tags/1.1.4/newmat11/Makefile.in
===================================================================
--- /nanovis/tags/1.1.4/newmat11/Makefile.in	(revision 4930)
+++ /nanovis/tags/1.1.4/newmat11/Makefile.in	(revision 4930)
@@ -0,0 +1,79 @@
+
+SHELL = /bin/sh
+
+.PHONY: all install clean distclean
+
+bindir          = @bindir@
+datadir		= @datadir@
+datarootdir	= @datarootdir@
+exec_prefix     = @exec_prefix@
+includedir      = @includedir@
+libdir          = @libdir@
+mandir          = @mandir@
+prefix          = @prefix@
+srcdir		= @srcdir@
+
+INSTALL		= @INSTALL@
+INSTALL_PROGRAM	= ${INSTALL} -m 555
+INSTALL_DATA	= ${INSTALL} -m 444
+INSTALL_SCRIPT	= ${INSTALL} -m 444
+RM		= rm -f
+AR		= ar rc
+RANLIB		= @RANLIB@
+CC		= @CC@
+VPATH		= $(srcdir)
+
+INCLUDES	= -I$(srcdir)
+
+CFLAGS		= @CFLAGS@
+EXTRA_CFLAGS	= -Wall 
+DEFINES		= @DEFINES@
+CC_SWITCHES	= $(CFLAGS) $(EXTRA_CFLAGS) $(INCLUDES)
+
+MATLIB		= newmat11.a
+
+OBJS		= \
+		bandmat.o \
+		cholesky.o \
+		evalue.o \
+		fft.o \
+		hholder.o \
+		jacobi.o \
+		myexcept.o \
+		newfft.o \
+		newmat1.o \
+		newmat2.o \
+		newmat3.o \
+		newmat4.o \
+		newmat5.o \
+		newmat6.o \
+		newmat7.o \
+		newmat8.o \
+		newmat9.o \
+		newmatex.o \
+		newmatnl.o \
+		newmatrm.o \
+		nm_misc.o \
+		solution.o \
+		sort.o \
+		submat.o \
+		svd.o 
+
+all: $(MATLIB)
+
+install: all
+
+$(MATLIB): $(OBJS)
+	$(RM) $@
+	$(AR) $@ $(OBJS) 
+	$(RANLIB) $@
+
+.cpp.o:
+	$(CC) $(CC_SWITCHES) -o $@ -c $<
+
+clean:
+	$(RM) *.a *.o
+
+distclean: clean
+	$(RM) Makefile *~
+
Index: /nanovis/tags/1.1.4/newmat11/bandmat.cpp
===================================================================
--- /nanovis/tags/1.1.4/newmat11/bandmat.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/newmat11/bandmat.cpp	(revision 4930)
@@ -0,0 +1,717 @@
+/// \ingroup newmat
+///@{
+
+/// \file bandmat.cpp
+/// Band-matrix member functions.
+
+
+// Copyright (C) 1991,2,3,4,9: R B Davies
+
+#define WANT_MATH                    // include.h will get math fns
+
+//#define WANT_STREAM
+
+#include "include.h"
+
+#include "newmat.h"
+#include "newmatrc.h"
+
+#ifdef use_namespace
+namespace NEWMAT {
+#endif
+
+
+
+#ifdef DO_REPORT
+#define REPORT { static ExeCounter ExeCount(__LINE__,10); ++ExeCount; }
+#else
+#define REPORT {}
+#endif
+
+static inline int my_min(int x, int y) { return x < y ? x : y; }
+static inline int my_max(int x, int y) { return x > y ? x : y; }
+
+
+BandMatrix::BandMatrix(const BaseMatrix& M)
+{
+   REPORT // CheckConversion(M);
+   // MatrixConversionCheck mcc;
+   GeneralMatrix* gmx=((BaseMatrix&)M).Evaluate(MatrixType::BM);
+   GetMatrix(gmx); CornerClear();
+}
+
+void BandMatrix::SetParameters(const GeneralMatrix* gmx)
+{
+   REPORT
+   MatrixBandWidth bw = gmx->bandwidth();
+   lower_val = bw.lower_val; upper_val = bw.upper_val;
+}
+
+void BandMatrix::resize(int n, int lb, int ub)
+{
+   REPORT
+   Tracer tr("BandMatrix::resize");
+   if (lb<0 || ub<0) Throw(ProgramException("Undefined bandwidth"));
+   lower_val = (lb<=n) ? lb : n-1; upper_val = (ub<=n) ? ub : n-1;
+   GeneralMatrix::resize(n,n,n*(lower_val+1+upper_val)); CornerClear();
+}
+
+// SimpleAddOK shows when we can add etc two matrices by a simple vector add
+// and when we can add one matrix into another
+//
+// *gm must be the same type as *this
+// - return 0 if simple add is OK
+// - return 1 if we can add into *gm only
+// - return 2 if we can add into *this only
+// - return 3 if we can't add either way
+//
+// For SP this will still be valid if we swap 1 and 2
+
+/// \brief can we add two band matrices with simple vector add
+///
+/// For band matrices the bandwidths must agree
+
+short BandMatrix::SimpleAddOK(const GeneralMatrix* gm)
+{
+   const BandMatrix* bm = (const BandMatrix*)gm;
+   if (bm->lower_val == lower_val && bm->upper_val == upper_val)
+      { REPORT return 0; }
+   else if (bm->lower_val >= lower_val && bm->upper_val >= upper_val)
+      { REPORT return 1; }
+   else if (bm->lower_val <= lower_val && bm->upper_val <= upper_val)
+      { REPORT return 2; }
+   else { REPORT return 3; }
+}
+
+/// \brief can we add two symmetric band matrices with simple vector add
+///
+/// Sufficient to check lower bandwidths agree
+
+short SymmetricBandMatrix::SimpleAddOK(const GeneralMatrix* gm)
+{
+   const SymmetricBandMatrix* bm = (const SymmetricBandMatrix*)gm;
+   if (bm->lower_val == lower_val) { REPORT return 0; }
+   else if (bm->lower_val > lower_val) { REPORT return 1; }
+   else { REPORT return 2; }
+}
+
+/// \brief resize UpperBandMatrix
+void UpperBandMatrix::resize(int n, int lb, int ub)
+{
+   REPORT
+   if (lb != 0)
+   {
+      Tracer tr("UpperBandMatrix::resize");
+      Throw(ProgramException("UpperBandMatrix with non-zero lower band" ));
+   }
+   BandMatrix::resize(n, lb, ub);
+}
+
+/// \brief resize LowerBandMatrix
+void LowerBandMatrix::resize(int n, int lb, int ub)
+{
+   REPORT
+   if (ub != 0)
+   {
+      Tracer tr("LowerBandMatrix::resize");
+      Throw(ProgramException("LowerBandMatrix with non-zero upper band" ));
+   }
+   BandMatrix::resize(n, lb, ub);
+}
+
+/// \brief resize BandMatrix
+void BandMatrix::resize(const GeneralMatrix& A)
+{
+   REPORT
+   int n = A.Nrows();
+   if (n != A.Ncols())
+   {
+      Tracer tr("BandMatrix::resize(GM)");
+      Throw(NotSquareException(*this));
+   }
+   MatrixBandWidth mbw = A.bandwidth();
+   resize(n, mbw.Lower(), mbw.Upper());
+}
+
+/*
+bool BandMatrix::SameStorageType(const GeneralMatrix& A) const
+{
+   if (type() != A.type()) { REPORT return false; }
+   REPORT
+   return bandwidth() == A.bandwidth();
+}
+
+void BandMatrix::resizeForAdd(const GeneralMatrix& A, const GeneralMatrix& B)
+{
+   REPORT
+   Tracer tr("BandMatrix::resizeForAdd");
+   MatrixBandWidth A_BW = A.bandwidth(); MatrixBandWidth B_BW = B.bandwidth();
+   if ((A_BW.Lower() < 0) | (A_BW.Upper() < 0) | (B_BW.Lower() < 0)
+      | (A_BW.Upper() < 0))
+         Throw(ProgramException("Can't resize to BandMatrix" ));
+   // already know A and B are square
+   resize(A.Nrows(), my_max(A_BW.Lower(), B_BW.Lower()),
+      my_max(A_BW.Upper(), B_BW.Upper()));
+}
+
+void BandMatrix::resizeForSP(const GeneralMatrix& A, const GeneralMatrix& B)
+{
+   REPORT
+   Tracer tr("BandMatrix::resizeForSP");
+   MatrixBandWidth A_BW = A.bandwidth(); MatrixBandWidth B_BW = B.bandwidth();
+   if ((A_BW.Lower() < 0) | (A_BW.Upper() < 0) | (B_BW.Lower() < 0)
+      | (A_BW.Upper() < 0))
+         Throw(ProgramException("Can't resize to BandMatrix" ));
+   // already know A and B are square
+   resize(A.Nrows(), my_min(A_BW.Lower(), B_BW.Lower()),
+      my_min(A_BW.Upper(), B_BW.Upper()));
+}
+*/
+
+/// \brief assignment operator for BandMatrix
+void BandMatrix::operator=(const BaseMatrix& X)
+{
+   REPORT // CheckConversion(X);
+   // MatrixConversionCheck mcc;
+   Eq(X,MatrixType::BM); CornerClear();
+}
+
+/// \brief set unused parts of BandMatrix to zero
+void BandMatrix::CornerClear() const
+{
+   REPORT
+   int i = lower_val; Real* s = store; int bw = lower_val + 1 + upper_val;
+   while (i)
+      { int j = i--; Real* sj = s; s += bw; while (j--) *sj++ = 0.0; }
+   i = upper_val; s = store + storage;
+   while (i)
+      { int j = i--; Real* sj = s; s -= bw; while (j--) *(--sj) = 0.0; }
+}
+
+MatrixBandWidth MatrixBandWidth::operator+(const MatrixBandWidth& bw) const
+{
+   REPORT
+   int l = bw.lower_val; int u = bw.upper_val;
+   l = (lower_val < 0 || l < 0) ? -1 : (lower_val > l) ? lower_val : l;
+   u = (upper_val < 0 || u < 0) ? -1 : (upper_val > u) ? upper_val : u;
+   return MatrixBandWidth(l,u);
+}
+
+MatrixBandWidth MatrixBandWidth::operator*(const MatrixBandWidth& bw) const
+{
+   REPORT
+   int l = bw.lower_val; int u = bw.upper_val;
+   l = (lower_val < 0 || l < 0) ? -1 : lower_val+l;
+   u = (upper_val < 0 || u < 0) ? -1 : upper_val+u;
+   return MatrixBandWidth(l,u);
+}
+
+MatrixBandWidth MatrixBandWidth::minimum(const MatrixBandWidth& bw) const
+{
+   REPORT
+   int l = bw.lower_val; int u = bw.upper_val;
+   if ((lower_val >= 0) && ( (l < 0) || (l > lower_val) )) l = lower_val;
+   if ((upper_val >= 0) && ( (u < 0) || (u > upper_val) )) u = upper_val;
+   return MatrixBandWidth(l,u);
+}
+
+UpperBandMatrix::UpperBandMatrix(const BaseMatrix& M)
+{
+   REPORT // CheckConversion(M);
+   // MatrixConversionCheck mcc;
+   GeneralMatrix* gmx=((BaseMatrix&)M).Evaluate(MatrixType::UB);
+   GetMatrix(gmx); CornerClear();
+}
+
+void UpperBandMatrix::operator=(const BaseMatrix& X)
+{
+   REPORT // CheckConversion(X);
+   // MatrixConversionCheck mcc;
+   Eq(X,MatrixType::UB); CornerClear();
+}
+
+LowerBandMatrix::LowerBandMatrix(const BaseMatrix& M)
+{
+   REPORT // CheckConversion(M);
+   // MatrixConversionCheck mcc;
+   GeneralMatrix* gmx=((BaseMatrix&)M).Evaluate(MatrixType::LB);
+   GetMatrix(gmx); CornerClear();
+}
+
+void LowerBandMatrix::operator=(const BaseMatrix& X)
+{
+   REPORT // CheckConversion(X);
+   // MatrixConversionCheck mcc;
+   Eq(X,MatrixType::LB); CornerClear();
+}
+
+BandLUMatrix::BandLUMatrix(const BaseMatrix& m)
+{
+   REPORT
+   Tracer tr("BandLUMatrix");
+   storage2 = 0; store2 = 0; indx = 0; // in event of exception during build
+   GeneralMatrix* gm = ((BaseMatrix&)m).Evaluate();
+   if (gm->nrows() != gm->ncols())
+      { gm->tDelete(); Throw(NotSquareException(*this)); }
+   if (gm->type() == MatrixType::BC)
+      { REPORT  ((BandLUMatrix*)gm)->get_aux(*this); GetMatrix(gm); }
+   else
+   {
+      REPORT
+      BandMatrix* gm1 = (BandMatrix*)(gm->Evaluate(MatrixType::BM));
+      m1 = gm1->lower_val; m2 = gm1->upper_val;
+      GetMatrix(gm1);
+      d = true; sing = false;
+      indx = new int [nrows_val]; MatrixErrorNoSpace(indx);
+      MONITOR_INT_NEW("Index (BndLUMat)",nrows_val,indx)
+      storage2 = nrows_val * m1;
+      store2 = new Real [storage2]; MatrixErrorNoSpace(store2);
+      MONITOR_REAL_NEW("Make (BandLUMat)",storage2,store2)
+      ludcmp();
+   }
+}
+
+GeneralMatrix* BandLUMatrix::Evaluate(MatrixType mt)
+{
+   if (Compare(this->Type(),mt)) { REPORT return this; }
+   REPORT
+   Tracer et("BandLUMatrix::Evaluate");
+   bool dummy = true;
+   if (dummy) Throw(ProgramException("Illegal use of BandLUMatrix", *this));
+   return this;
+}
+
+// could we use SetParameters instead of this
+void BandLUMatrix::get_aux(BandLUMatrix& X)
+{
+   X.d = d; X.sing = sing; X.storage2 = storage2; X.m1 = m1; X.m2 = m2;   
+   if (tag_val == 0 || tag_val == 1) // reuse the array 
+   {
+      REPORT
+      X.indx = indx; indx = 0;
+      X.store2 = store2; store2 = 0;
+      d = true; sing = true; storage2 = 0; m1 = 0; m2 = 0;
+      return;
+   }
+   else if (nrows_val == 0)
+   {
+      REPORT
+      indx = 0; store2 = 0; storage2 = 0;
+      d = true; sing = true; m1 = m2 = 0;
+      return;
+   }
+   else                              // copy the array
+   {
+      REPORT
+      Tracer tr("BandLUMatrix::get_aux");
+      int *ix = new int [nrows_val]; MatrixErrorNoSpace(ix);
+      MONITOR_INT_NEW("Index (BLUM::get_aux)", nrows_val, ix)
+      int n = nrows_val; int* i = ix; int* j = indx;
+      while(n--) *i++ = *j++;
+      X.indx = ix;
+      Real *rx = new Real [storage2]; MatrixErrorNoSpace(indx);
+      MONITOR_REAL_NEW("Index (BLUM::get_aux)", storage2, rx)
+      newmat_block_copy(storage2, store2, rx);
+      X.store2 = rx;
+   }
+}
+
+BandLUMatrix::BandLUMatrix(const BandLUMatrix& gm) : GeneralMatrix()
+{
+   REPORT
+   Tracer tr("BandLUMatrix(const BandLUMatrix&)");
+   ((BandLUMatrix&)gm).get_aux(*this);
+   GetMatrix(&gm);
+}
+
+void BandLUMatrix::operator=(const BandLUMatrix& gm)
+{
+   if (&gm == this) { REPORT tag_val = -1; return; }
+   REPORT
+   delete [] indx; indx = 0;
+   delete [] store2; store2 = 0; storage2 = 0;
+   ((BandLUMatrix&)gm).get_aux(*this);
+   Eq(gm);
+}
+   
+
+
+
+
+
+
+
+BandLUMatrix::~BandLUMatrix()
+{
+   REPORT
+   MONITOR_INT_DELETE("Index (BndLUMat)",nrows_val,indx)
+   MONITOR_REAL_DELETE("Delete (BndLUMt)",storage2,store2)
+   delete [] indx; delete [] store2;
+}
+
+MatrixType BandLUMatrix::type() const { REPORT return MatrixType::BC; }
+
+
+LogAndSign BandLUMatrix::log_determinant() const
+{
+   REPORT
+   if (sing) return 0.0;
+   Real* a = store; int w = m1+1+m2; LogAndSign sum; int i = nrows_val;
+   // while (i--) { sum *= *a; a += w; }
+   if (i) for (;;) { sum *= *a; if (!(--i)) break; a += w; }
+   if (!d) sum.ChangeSign(); return sum;
+}
+
+GeneralMatrix* BandMatrix::MakeSolver()
+{
+   REPORT
+   GeneralMatrix* gm = new BandLUMatrix(*this);
+   MatrixErrorNoSpace(gm); gm->ReleaseAndDelete(); return gm;
+}
+
+
+void BandLUMatrix::ludcmp()
+{
+   REPORT
+   Real* a = store2; int i = storage2;
+   // clear store2 - so unused locations are always zero -
+   // required by operator==
+   while (i--) *a++ = 0.0;
+   a = store;
+   i = m1; int j = m2; int k; int n = nrows_val; int w = m1 + 1 + m2;
+   while (i)
+   {
+      Real* ai = a + i;
+      k = ++j; while (k--) *a++ = *ai++;
+      k = i--; while (k--) *a++ = 0.0;
+   }
+
+   a = store; int l = m1;
+   for (k=0; k<n; k++)
+   {
+      Real x = *a; i = k; Real* aj = a;
+      if (l < n) l++;
+      for (j=k+1; j<l; j++)
+         { aj += w; if (fabs(x) < fabs(*aj)) { x = *aj; i = j; } }
+      indx[k] = i;
+      if (x==0) { sing = true; return; }
+      if (i!=k)
+      {
+         d = !d; Real* ak = a; Real* ai = store + i * w; j = w;
+         while (j--) { x = *ak; *ak++ = *ai; *ai++ = x; }
+      }
+      aj = a + w; Real* m = store2 + m1 * k;
+      for (j=k+1; j<l; j++)
+      {
+         *m++ = x = *aj / *a; i = w; Real* ak = a;
+         while (--i) { Real* aj1 = aj++; *aj1 = *aj - x * *(++ak); }
+         *aj++ = 0.0;
+      }
+      a += w;
+   }
+}
+
+void BandLUMatrix::lubksb(Real* B, int mini)
+{
+   REPORT
+   Tracer tr("BandLUMatrix::lubksb");
+   if (sing) Throw(SingularException(*this));
+   int n = nrows_val; int l = m1; int w = m1 + 1 + m2;
+
+   for (int k=0; k<n; k++)
+   {
+      int i = indx[k];
+      if (i!=k) { Real x=B[k]; B[k]=B[i]; B[i]=x; }
+      if (l<n) l++;
+      Real* m = store2 + k*m1; Real* b = B+k; Real* bi = b;
+      for (i=k+1; i<l; i++)  *(++bi) -= *m++ * *b;
+   }
+
+   l = -m1;
+   for (int i = n-1; i>=mini; i--)
+   {
+      Real* b = B + i; Real* bk = b; Real x = *bk;
+      Real* a = store + w*i; Real y = *a;
+      int k = l+m1; while (k--) x -=  *(++a) * *(++bk);
+      *b = x / y;
+      if (l < m2) l++;
+   }
+}
+
+void BandLUMatrix::Solver(MatrixColX& mcout, const MatrixColX& mcin)
+{
+   REPORT
+   int i = mcin.skip; Real* el = mcin.data-i; Real* el1=el;
+   while (i--) *el++ = 0.0;
+   el += mcin.storage; i = nrows_val - mcin.skip - mcin.storage;
+   while (i--) *el++ = 0.0;
+   lubksb(el1, mcout.skip);
+}
+
+// Do we need check for entirely zero output?
+
+
+void UpperBandMatrix::Solver(MatrixColX& mcout,
+   const MatrixColX& mcin)
+{
+   REPORT
+   int i = mcin.skip-mcout.skip; Real* elx = mcin.data-i;
+   while (i-- > 0) *elx++ = 0.0;
+   int nr = mcin.skip+mcin.storage;
+   elx = mcin.data+mcin.storage; Real* el = elx;
+   int j = mcout.skip+mcout.storage-nr; i = nr-mcout.skip;
+   while (j-- > 0) *elx++ = 0.0;
+
+   Real* Ael = store + (upper_val+1)*(i-1)+1; j = 0;
+   if (i > 0) for(;;)
+   {
+      elx = el; Real sum = 0.0; int jx = j;
+      while (jx--) sum += *(--Ael) * *(--elx);
+      elx--; *elx = (*elx - sum) / *(--Ael);
+      if (--i <= 0) break;
+      if (j<upper_val) Ael -= upper_val - (++j); else el--;
+   }
+}
+
+void LowerBandMatrix::Solver(MatrixColX& mcout,
+   const MatrixColX& mcin)
+{
+   REPORT
+   int i = mcin.skip-mcout.skip; Real* elx = mcin.data-i;
+   while (i-- > 0) *elx++ = 0.0;
+   int nc = mcin.skip; i = nc+mcin.storage; elx = mcin.data+mcin.storage;
+   int nr = mcout.skip+mcout.storage; int j = nr-i; i = nr-nc;
+   while (j-- > 0) *elx++ = 0.0;
+
+   Real* el = mcin.data;
+   Real* Ael = store + (lower_val+1)*nc + lower_val;
+   j = 0;
+   if (i > 0) for(;;)
+   {
+      elx = el; Real sum = 0.0; int jx = j;
+      while (jx--) sum += *Ael++ * *elx++;
+      *elx = (*elx - sum) / *Ael++;
+      if (--i <= 0) break;
+      if (j<lower_val) Ael += lower_val - (++j); else el++;
+   }
+}
+
+
+LogAndSign BandMatrix::log_determinant() const
+{
+   REPORT
+   BandLUMatrix C(*this); return C.log_determinant();
+}
+
+LogAndSign LowerBandMatrix::log_determinant() const
+{
+   REPORT
+   int i = nrows_val; LogAndSign sum;
+   Real* s = store + lower_val; int j = lower_val + 1;
+//   while (i--) { sum *= *s; s += j; }
+   if (i) for (;;) { sum *= *s; if (!(--i)) break; s += j; }
+   ((GeneralMatrix&)*this).tDelete(); return sum;
+}
+
+LogAndSign UpperBandMatrix::log_determinant() const
+{
+   REPORT
+   int i = nrows_val; LogAndSign sum; Real* s = store; int j = upper_val + 1;
+//   while (i--) { sum *= *s; s += j; }
+   if (i) for (;;) { sum *= *s; if (!(--i)) break; s += j; }
+   ((GeneralMatrix&)*this).tDelete(); return sum;
+}
+
+GeneralMatrix* SymmetricBandMatrix::MakeSolver()
+{
+   REPORT
+   GeneralMatrix* gm = new BandLUMatrix(*this);
+   MatrixErrorNoSpace(gm); gm->ReleaseAndDelete(); return gm;
+}
+
+SymmetricBandMatrix::SymmetricBandMatrix(const BaseMatrix& M)
+{
+   REPORT  // CheckConversion(M);
+   // MatrixConversionCheck mcc;
+   GeneralMatrix* gmx=((BaseMatrix&)M).Evaluate(MatrixType::SB);
+   GetMatrix(gmx);
+}
+
+GeneralMatrix* SymmetricBandMatrix::Transpose(TransposedMatrix*, MatrixType mt)
+{ REPORT  return Evaluate(mt); }
+
+LogAndSign SymmetricBandMatrix::log_determinant() const
+{
+   REPORT
+   BandLUMatrix C(*this); return C.log_determinant();
+}
+
+void SymmetricBandMatrix::SetParameters(const GeneralMatrix* gmx)
+{ REPORT lower_val = gmx->bandwidth().lower_val; }
+
+void SymmetricBandMatrix::resize(int n, int lb)
+{
+   REPORT
+   Tracer tr("SymmetricBandMatrix::resize");
+   if (lb<0) Throw(ProgramException("Undefined bandwidth"));
+   lower_val = (lb<=n) ? lb : n-1;
+   GeneralMatrix::resize(n,n,n*(lower_val+1));
+}
+
+void SymmetricBandMatrix::resize(const GeneralMatrix& A)
+{
+   REPORT
+   int n = A.Nrows();
+   if (n != A.Ncols())
+   {
+      Tracer tr("SymmetricBandMatrix::resize(GM)");
+      Throw(NotSquareException(*this));
+   }
+   MatrixBandWidth mbw = A.bandwidth(); int b = mbw.Lower();
+   if (b != mbw.Upper())
+   {
+      Tracer tr("SymmetricBandMatrix::resize(GM)");
+      Throw(ProgramException("Upper and lower band-widths not equal"));
+   }
+   resize(n, b);
+}
+/*
+bool SymmetricBandMatrix::SameStorageType(const GeneralMatrix& A) const
+{
+   if (type() != A.type()) { REPORT return false; }
+   REPORT
+   return bandwidth() == A.bandwidth();
+}
+
+void SymmetricBandMatrix::resizeForAdd(const GeneralMatrix& A,
+   const GeneralMatrix& B)
+{
+   REPORT
+   Tracer tr("SymmetricBandMatrix::resizeForAdd");
+   MatrixBandWidth A_BW = A.bandwidth(); MatrixBandWidth B_BW = B.bandwidth();
+   if ((A_BW.Lower() < 0) | (B_BW.Lower() < 0))
+         Throw(ProgramException("Can't resize to SymmetricBandMatrix" ));
+   // already know A and B are square
+   resize(A.Nrows(), my_max(A_BW.Lower(), B_BW.Lower()));
+}
+
+void SymmetricBandMatrix::resizeForSP(const GeneralMatrix& A,
+   const GeneralMatrix& B)
+{
+   REPORT
+   Tracer tr("SymmetricBandMatrix::resizeForSP");
+   MatrixBandWidth A_BW = A.bandwidth(); MatrixBandWidth B_BW = B.bandwidth();
+   if ((A_BW.Lower() < 0) | (B_BW.Lower() < 0))
+         Throw(ProgramException("Can't resize to SymmetricBandMatrix" ));
+   // already know A and B are square
+   resize(A.Nrows(), my_min(A_BW.Lower(), B_BW.Lower()));
+}
+*/
+
+void SymmetricBandMatrix::operator=(const BaseMatrix& X)
+{
+   REPORT // CheckConversion(X);
+   // MatrixConversionCheck mcc;
+   Eq(X,MatrixType::SB);
+}
+
+void SymmetricBandMatrix::CornerClear() const
+{
+   // set unused parts of BandMatrix to zero
+   REPORT
+   int i = lower_val; Real* s = store; int bw = lower_val + 1;
+   if (i) for(;;)
+   {
+      int j = i;
+      Real* sj = s;
+      while (j--) *sj++ = 0.0;
+      if (!(--i)) break;
+      s += bw;
+   }
+}
+
+MatrixBandWidth SymmetricBandMatrix::bandwidth() const
+   { REPORT return MatrixBandWidth(lower_val,lower_val); }
+
+GeneralMatrix* BandMatrix::Image() const
+{
+   REPORT
+   GeneralMatrix* gm = new BandMatrix(*this); MatrixErrorNoSpace(gm);
+   return gm;
+}
+
+GeneralMatrix* UpperBandMatrix::Image() const
+{
+   REPORT
+   GeneralMatrix* gm = new UpperBandMatrix(*this); MatrixErrorNoSpace(gm);
+   return gm;
+}
+
+GeneralMatrix* LowerBandMatrix::Image() const
+{
+   REPORT
+   GeneralMatrix* gm = new LowerBandMatrix(*this); MatrixErrorNoSpace(gm);
+   return gm;
+}
+
+GeneralMatrix* SymmetricBandMatrix::Image() const
+{
+   REPORT
+   GeneralMatrix* gm = new SymmetricBandMatrix(*this); MatrixErrorNoSpace(gm);
+   return gm;
+}
+
+GeneralMatrix* BandLUMatrix::Image() const
+{
+   REPORT
+   GeneralMatrix* gm = new BandLUMatrix(*this); MatrixErrorNoSpace(gm);
+   return gm;
+}
+
+
+inline Real square(Real x) { return x*x; }
+
+Real SymmetricBandMatrix::sum_square() const
+{
+   REPORT
+   CornerClear();
+   Real sum1=0.0; Real sum2=0.0; Real* s=store; int i=nrows_val;
+   int l=lower_val;
+   while (i--)
+      { int j = l; while (j--) sum2 += square(*s++); sum1 += square(*s++); }
+   ((GeneralMatrix&)*this).tDelete(); return sum1 + 2.0 * sum2;
+}
+
+Real SymmetricBandMatrix::sum_absolute_value() const
+{
+   REPORT
+   CornerClear();
+   Real sum1=0.0; Real sum2=0.0; Real* s=store; int i=nrows_val;
+   int l=lower_val;
+   while (i--)
+      { int j = l; while (j--) sum2 += fabs(*s++); sum1 += fabs(*s++); }
+   ((GeneralMatrix&)*this).tDelete(); return sum1 + 2.0 * sum2;
+}
+
+Real SymmetricBandMatrix::sum() const
+{
+   REPORT
+   CornerClear();
+   Real sum1=0.0; Real sum2=0.0; Real* s=store; int i=nrows_val;
+   int l=lower_val;
+   while (i--)
+      { int j = l; while (j--) sum2 += *s++; sum1 += *s++; }
+   ((GeneralMatrix&)*this).tDelete(); return sum1 + 2.0 * sum2;
+}
+
+
+
+
+
+#ifdef use_namespace
+}
+#endif
+
+///@}
+
+
Index: /nanovis/tags/1.1.4/newmat11/cholesky.cpp
===================================================================
--- /nanovis/tags/1.1.4/newmat11/cholesky.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/newmat11/cholesky.cpp	(revision 4930)
@@ -0,0 +1,289 @@
+/// \ingroup newmat
+///@{
+
+/// \file cholesky.cpp
+/// Cholesky decomposition.
+/// Cholesky decomposition of symmetric and band symmetric matrices,
+/// update, downdate, manipulate a Cholesky decomposition
+
+
+// Copyright (C) 1991,2,3,4: R B Davies
+
+#define WANT_MATH
+//#define WANT_STREAM
+
+#include "include.h"
+
+#include "newmat.h"
+#include "newmatrm.h"
+
+#ifdef use_namespace
+namespace NEWMAT {
+#endif
+
+#ifdef DO_REPORT
+#define REPORT { static ExeCounter ExeCount(__LINE__,14); ++ExeCount; }
+#else
+#define REPORT {}
+#endif
+
+/********* Cholesky decomposition of a positive definite matrix *************/
+
+// Suppose S is symmetrix and positive definite. Then there exists a unique
+// lower triangular matrix L such that L L.t() = S;
+
+
+ReturnMatrix Cholesky(const SymmetricMatrix& S)
+{
+   REPORT
+   Tracer trace("Cholesky");
+   int nr = S.Nrows();
+   LowerTriangularMatrix T(nr);
+   Real* s = S.Store(); Real* t = T.Store(); Real* ti = t;
+   for (int i=0; i<nr; i++)
+   {
+      Real* tj = t; Real sum; int k;
+      for (int j=0; j<i; j++)
+      {
+         Real* tk = ti; sum = 0.0; k = j;
+         while (k--) { sum += *tj++ * *tk++; }
+         *tk = (*s++ - sum) / *tj++;
+      }
+      sum = 0.0; k = i;
+      while (k--) { sum += square(*ti++); }
+      Real d = *s++ - sum;
+      if (d<=0.0)  Throw(NPDException(S));
+      *ti++ = sqrt(d);
+   }
+   T.release(); return T.for_return();
+}
+
+ReturnMatrix Cholesky(const SymmetricBandMatrix& S)
+{
+   REPORT
+   Tracer trace("Band-Cholesky");
+   int nr = S.Nrows(); int m = S.lower_val;
+   LowerBandMatrix T(nr,m);
+   Real* s = S.Store(); Real* t = T.Store(); Real* ti = t;
+
+   for (int i=0; i<nr; i++)
+   {
+      Real* tj = t; Real sum; int l;
+      if (i<m) { REPORT l = m-i; s += l; ti += l; l = i; }
+      else { REPORT t += (m+1); l = m; }
+
+      for (int j=0; j<l; j++)
+      {
+         Real* tk = ti; sum = 0.0; int k = j; tj += (m-j);
+         while (k--) { sum += *tj++ * *tk++; }
+         *tk = (*s++ - sum) / *tj++;
+      }
+      sum = 0.0;
+      while (l--) { sum += square(*ti++); }
+      Real d = *s++ - sum;
+      if (d<=0.0)  Throw(NPDException(S));
+      *ti++ = sqrt(d);
+   }
+
+   T.release(); return T.for_return();
+}
+
+
+
+
+// Contributed by Nick Bennett of Schlumberger-Doll Research; modified by RBD
+
+// The enclosed routines can be used to update the Cholesky decomposition of
+// a positive definite symmetric matrix.  A good reference for this routines
+// can be found in
+// LINPACK User's Guide, Chapter 10, Dongarra et. al., SIAM, Philadelphia, 1979
+
+// produces the Cholesky decomposition of A + x.t() * x where A = chol.t() * chol
+void update_Cholesky(UpperTriangularMatrix &chol, RowVector x)
+{
+   int nc = chol.Nrows();
+   ColumnVector cGivens(nc); cGivens = 0.0;
+   ColumnVector sGivens(nc); sGivens = 0.0;
+	
+   for(int j = 1; j <= nc; ++j) // process the jth column of chol
+   {
+      // apply the previous Givens rotations k = 1,...,j-1 to column j
+      for(int k = 1; k < j; ++k)
+         GivensRotation(cGivens(k), sGivens(k), chol(k,j), x(j));
+
+      // determine the jth Given's rotation
+      pythag(chol(j,j), x(j), cGivens(j), sGivens(j));
+
+      // apply the jth Given's rotation
+      {
+         Real tmp0 = cGivens(j) * chol(j,j) + sGivens(j) * x(j);
+         chol(j,j) = tmp0; x(j) = 0.0;
+      }
+
+   }
+
+}
+
+
+// produces the Cholesky decomposition of A - x.t() * x where A = chol.t() * chol
+void downdate_Cholesky(UpperTriangularMatrix &chol, RowVector x)
+{
+   int nRC = chol.Nrows();
+	
+   // solve R^T a = x
+   LowerTriangularMatrix L = chol.t();
+   ColumnVector a(nRC); a = 0.0;
+   int i, j;
+	
+   for (i = 1; i <= nRC; ++i)
+   {
+      // accumulate subtr sum
+      Real subtrsum = 0.0;
+      for(int k = 1; k < i; ++k) subtrsum += a(k) * L(i,k);
+
+      a(i) = (x(i) - subtrsum) / L(i,i);
+   }
+
+   // test that l2 norm of a is < 1
+   Real squareNormA = a.SumSquare();
+   if (squareNormA >= 1.0)
+      Throw(ProgramException("downdate_Cholesky() fails", chol));
+
+   Real alpha = sqrt(1.0 - squareNormA);
+
+   // compute and apply Givens rotations to the vector a
+   ColumnVector cGivens(nRC);  cGivens = 0.0;
+   ColumnVector sGivens(nRC);  sGivens = 0.0;
+   for(i = nRC; i >= 1; i--)
+      alpha = pythag(alpha, a(i), cGivens(i), sGivens(i));
+
+   // apply Givens rotations to the jth column of chol
+   ColumnVector xtilde(nRC); xtilde = 0.0;
+   for(j = nRC; j >= 1; j--)
+   {
+      // only the first j rotations have an affect on chol,0
+      for(int k = j; k >= 1; k--)
+         GivensRotation(cGivens(k), -sGivens(k), chol(k,j), xtilde(j));
+   }
+}
+
+
+
+// produces the Cholesky decomposition of EAE where A = chol.t() * chol
+// and E produces a RIGHT circular shift of the rows and columns from
+// 1,...,k-1,k,k+1,...l,l+1,...,p to
+// 1,...,k-1,l,k,k+1,...l-1,l+1,...p
+void right_circular_update_Cholesky(UpperTriangularMatrix &chol, int k, int l)
+{
+   int nRC = chol.Nrows();
+   int i, j;
+	
+   // I. compute shift of column l to the kth position
+   Matrix cholCopy = chol;
+   // a. grab column l
+   ColumnVector columnL = cholCopy.Column(l);
+   // b. shift columns k,...l-1 to the RIGHT
+   for(j = l-1; j >= k; --j)
+      cholCopy.Column(j+1) = cholCopy.Column(j);
+   // c. copy the top k-1 elements of columnL into the kth column of cholCopy
+   cholCopy.Column(k) = 0.0;
+   for(i = 1; i < k; ++i) cholCopy(i,k) = columnL(i);
+
+    // II. determine the l-k Given's rotations
+   int nGivens = l-k;
+   ColumnVector cGivens(nGivens); cGivens = 0.0;
+   ColumnVector sGivens(nGivens); sGivens = 0.0;
+   for(i = l; i > k; i--)
+   {
+      int givensIndex = l-i+1;
+      columnL(i-1) = pythag(columnL(i-1), columnL(i),
+         cGivens(givensIndex), sGivens(givensIndex));
+      columnL(i) = 0.0;
+   }
+   // the kth entry of columnL is the new diagonal element in column k of cholCopy
+   cholCopy(k,k) = columnL(k);
+	
+   // III. apply these Given's rotations to subsequent columns
+   // for columns k+1,...,l-1 we only need to apply the last nGivens-(j-k) rotations
+   for(j = k+1; j <= nRC; ++j)
+   {
+      ColumnVector columnJ = cholCopy.Column(j);
+      int imin = nGivens - (j-k) + 1; if (imin < 1) imin = 1;
+      for(int gIndex = imin; gIndex <= nGivens; ++gIndex)
+      {
+         // apply gIndex Given's rotation
+         int topRowIndex = k + nGivens - gIndex;
+         GivensRotationR(cGivens(gIndex), sGivens(gIndex),
+            columnJ(topRowIndex), columnJ(topRowIndex+1));
+      }
+      cholCopy.Column(j) = columnJ;
+   }
+
+   chol << cholCopy;
+}
+
+
+
+// produces the Cholesky decomposition of EAE where A = chol.t() * chol
+// and E produces a LEFT circular shift of the rows and columns from
+// 1,...,k-1,k,k+1,...l,l+1,...,p to
+// 1,...,k-1,k+1,...l,k,l+1,...,p to
+void left_circular_update_Cholesky(UpperTriangularMatrix &chol, int k, int l)
+{
+   int nRC = chol.Nrows();
+   int i, j;
+
+   // I. compute shift of column k to the lth position
+   Matrix cholCopy = chol;
+   // a. grab column k
+   ColumnVector columnK = cholCopy.Column(k);
+   // b. shift columns k+1,...l to the LEFT
+   for(j = k+1; j <= l; ++j)
+      cholCopy.Column(j-1) = cholCopy.Column(j);
+   // c. copy the elements of columnK into the lth column of cholCopy
+   cholCopy.Column(l) = 0.0;
+   for(i = 1; i <= k; ++i)
+      cholCopy(i,l) = columnK(i);
+
+   // II. apply and compute Given's rotations
+   int nGivens = l-k;
+   ColumnVector cGivens(nGivens); cGivens = 0.0;
+   ColumnVector sGivens(nGivens); sGivens = 0.0;
+   for(j = k; j <= nRC; ++j)
+   {
+      ColumnVector columnJ = cholCopy.Column(j);
+
+      // apply the previous Givens rotations to columnJ
+      int imax = j - k; if (imax > nGivens) imax = nGivens;
+      for(int i = 1; i <= imax; ++i)
+      {
+         int gIndex = i;
+         int topRowIndex = k + i - 1;
+         GivensRotationR(cGivens(gIndex), sGivens(gIndex),
+            columnJ(topRowIndex), columnJ(topRowIndex+1));
+      }
+
+      // compute a new Given's rotation when j < l
+      if(j < l)
+      {
+         int gIndex = j-k+1;
+         columnJ(j) = pythag(columnJ(j), columnJ(j+1), cGivens(gIndex),
+            sGivens(gIndex));
+         columnJ(j+1) = 0.0;
+      }
+
+      cholCopy.Column(j) = columnJ;
+   }
+
+   chol << cholCopy;
+	
+}
+
+
+
+
+#ifdef use_namespace
+}
+#endif
+
+///@}
Index: /nanovis/tags/1.1.4/newmat11/controlw.h
===================================================================
--- /nanovis/tags/1.1.4/newmat11/controlw.h	(revision 4930)
+++ /nanovis/tags/1.1.4/newmat11/controlw.h	(revision 4930)
@@ -0,0 +1,56 @@
+/// \ingroup newmat
+///@{
+
+/// \file controlw.h
+/// Control word class.
+/// Manipulate bits used for setting options.
+
+
+#ifndef CONTROL_WORD_LIB
+#define CONTROL_WORD_LIB 0
+
+/// Organise an int as a series of bits to set options.
+/// \internal
+class ControlWord
+{
+protected:
+   int cw;                                      // the control word
+public:
+   ControlWord() : cw(0) {}                     // do nothing
+   ControlWord(int i) : cw(i) {}                // load an integer
+
+      // select specific bits (for testing at least one set)
+   ControlWord operator*(ControlWord i) const
+      { return ControlWord(cw & i.cw); }
+   void operator*=(ControlWord i)  { cw &= i.cw; }
+
+      // set bits
+   ControlWord operator+(ControlWord i) const
+      { return ControlWord(cw | i.cw); }
+   void operator+=(ControlWord i)  { cw |= i.cw; }
+
+      // reset bits
+   ControlWord operator-(ControlWord i) const
+      { return ControlWord(cw - (cw & i.cw)); }
+   void operator-=(ControlWord i) { cw -= (cw & i.cw); }
+
+      // check if all of selected bits set or reset
+   bool operator>=(ControlWord i) const { return (cw & i.cw) == i.cw; }
+   bool operator<=(ControlWord i) const { return (cw & i.cw) == cw; }
+
+      // flip selected bits
+   ControlWord operator^(ControlWord i) const
+      { return ControlWord(cw ^ i.cw); }
+   ControlWord operator~() const { return ControlWord(~cw); }
+
+      // convert to integer
+   int operator+() const { return cw; }
+   int operator!() const { return cw==0; }
+   FREE_CHECK(ControlWord)
+};
+
+
+#endif
+
+///@}
+
Index: /nanovis/tags/1.1.4/newmat11/evalue.cpp
===================================================================
--- /nanovis/tags/1.1.4/newmat11/evalue.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/newmat11/evalue.cpp	(revision 4930)
@@ -0,0 +1,303 @@
+/// \ingroup newmat
+///@{
+
+/// \file evalue.cpp
+/// Eigen-value decomposition (Householder method).
+
+// Copyright (C) 1991,2,3,4: R B Davies
+
+#define WANT_MATH
+
+#include "include.h"
+#include "newmatap.h"
+#include "newmatrm.h"
+#include "precisio.h"
+
+#ifdef use_namespace
+namespace NEWMAT {
+#endif
+
+#ifdef DO_REPORT
+#define REPORT { static ExeCounter ExeCount(__LINE__,17); ++ExeCount; }
+#else
+#define REPORT {}
+#endif
+
+
+
+static void tred2(const SymmetricMatrix& A, DiagonalMatrix& D,
+   DiagonalMatrix& E, Matrix& Z)
+{
+   Tracer et("Evalue(tred2)");
+   REPORT
+   Real tol =
+      FloatingPointPrecision::Minimum()/FloatingPointPrecision::Epsilon();
+   int n = A.Nrows(); Z.resize(n,n); Z.Inject(A);
+   D.resize(n); E.resize(n);
+   Real* z = Z.Store(); int i;
+
+   for (i=n-1; i > 0; i--)                   // i=0 is excluded
+   {
+      Real f = Z.element(i,i-1); Real g = 0.0;
+      int k = i-1; Real* zik = z + i*n;
+      while (k--) g += square(*zik++);
+      Real h = g + square(f);
+      if (g <= tol) { REPORT E.element(i) = f; h = 0.0; }
+      else
+      {
+         REPORT
+         g = sign(-sqrt(h), f); E.element(i) = g; h -= f*g;
+         Z.element(i,i-1) = f-g; f = 0.0;
+         Real* zji = z + i; Real* zij = z + i*n; Real* ej = E.Store();
+         int j;
+         for (j=0; j<i; j++)
+         {
+            *zji = (*zij++)/h; g = 0.0;
+            Real* zjk = z + j*n; zik = z + i*n;
+            k = j; while (k--) g += *zjk++ * (*zik++);
+            k = i-j;
+            if (k) for(;;)
+               { g += *zjk * (*zik++); if (!(--k)) break; zjk += n; }
+            *ej++ = g/h; f += g * (*zji); zji += n;
+         }
+         Real hh = f / (h + h); zij = z + i*n; ej = E.Store();
+         for (j=0; j<i; j++)
+         {
+            f = *zij++; g = *ej - hh * f; *ej++ = g;
+            Real* zjk = z + j*n; Real* zik = z + i*n;
+            Real* ek = E.Store(); k = j+1;
+            while (k--)  *zjk++ -= ( f*(*ek++) + g*(*zik++) ); 
+         }
+      }
+      D.element(i) = h;
+   }
+
+   D.element(0) = 0.0; E.element(0) = 0.0;
+   for (i=0; i<n; i++)
+   {
+      if (D.element(i) != 0.0)
+      {
+         REPORT
+         for (int j=0; j<i; j++)
+         {
+            Real g = 0.0;
+            Real* zik = z + i*n; Real* zkj = z + j;
+            int k = i;
+            if (k) for (;;)
+               { g += *zik++ * (*zkj); if (!(--k)) break; zkj += n; }
+            Real* zki = z + i; zkj = z + j;
+            k = i;
+            if (k) for (;;)
+               { *zkj -= g * (*zki); if (!(--k)) break; zkj += n; zki += n; }
+         }
+      }
+      Real* zij = z + i*n; Real* zji = z + i;
+      int j = i;
+      if (j) for (;;)
+         { *zij++ = 0.0; *zji = 0.0; if (!(--j)) break; zji += n; }
+      D.element(i) = *zij; *zij = 1.0;
+   }
+}
+
+static void tql2(DiagonalMatrix& D, DiagonalMatrix& E, Matrix& Z)
+{
+   Tracer et("Evalue(tql2)");
+   REPORT
+   Real eps = FloatingPointPrecision::Epsilon();
+   int n = D.Nrows(); Real* z = Z.Store(); int l;
+   for (l=1; l<n; l++) E.element(l-1) = E.element(l);
+   Real b = 0.0; Real f = 0.0; E.element(n-1) = 0.0;
+   for (l=0; l<n; l++)
+   {
+      int i,j;
+      Real& dl = D.element(l); Real& el = E.element(l);
+      Real h = eps * ( fabs(dl) + fabs(el) );
+      if (b < h) { REPORT b = h; }
+      int m;
+      for (m=l; m<n; m++) if (fabs(E.element(m)) <= b) break;
+      bool test = false;
+      for (j=0; j<30; j++)
+      {
+         if (m==l) { REPORT test = true; break; }
+         Real& dl1 = D.element(l+1);
+         Real g = dl; Real p = (dl1-g) / (2.0*el); Real r = sqrt(p*p + 1.0);
+         dl = el / (p < 0.0 ? p-r : p+r); Real h = g - dl; f += h;
+         Real* dlx = &dl1; i = n-l-1; while (i--) *dlx++ -= h;
+
+         p = D.element(m); Real c = 1.0; Real s = 0.0;
+         for (i=m-1; i>=l; i--)
+         {
+            Real ei = E.element(i); Real di = D.element(i);
+            Real& ei1 = E.element(i+1);
+            g = c * ei; h = c * p;
+            if ( fabs(p) >= fabs(ei))
+            {
+               REPORT
+               c = ei / p; r = sqrt(c*c + 1.0);
+               ei1 = s*p*r; s = c/r; c = 1.0/r;
+            }
+            else
+            {
+               REPORT
+               c = p / ei; r = sqrt(c*c + 1.0);
+               ei1 = s * ei * r; s = 1.0/r; c /= r;
+            }
+            p = c * di - s*g; D.element(i+1) = h + s * (c*g + s*di);
+
+            Real* zki = z + i; Real* zki1 = zki + 1; int k = n;
+            if (k) for (;;)
+            {
+               REPORT
+               h = *zki1; *zki1 = s*(*zki) + c*h; *zki = c*(*zki) - s*h;
+               if (!(--k)) break;
+               zki += n; zki1 += n;
+            }
+         }
+         el = s*p; dl = c*p;
+         if (fabs(el) <= b) { REPORT; test = true; break; }
+      }
+      if (!test) Throw ( ConvergenceException(D) );
+      dl += f;
+   }
+/*
+   for (int i=0; i<n; i++)
+   {
+      int k = i; Real p = D.element(i);
+      for (int j=i+1; j<n; j++)
+         { if (D.element(j) < p) { k = j; p = D.element(j); } }
+      if (k != i)
+      {
+         D.element(k) = D.element(i); D.element(i) = p; int j = n;
+         Real* zji = z + i; Real* zjk = z + k;
+         if (j) for(;;)
+         {
+            p = *zji; *zji = *zjk; *zjk = p;
+            if (!(--j)) break;
+            zji += n; zjk += n;
+         }
+      }
+   }
+*/
+}
+
+static void tred3(const SymmetricMatrix& X, DiagonalMatrix& D,
+   DiagonalMatrix& E, SymmetricMatrix& A)
+{
+   Tracer et("Evalue(tred3)");
+   REPORT
+   Real tol =
+      FloatingPointPrecision::Minimum()/FloatingPointPrecision::Epsilon();
+   int n = X.Nrows(); A = X; D.resize(n); E.resize(n);
+   Real* ei = E.Store() + n;
+   for (int i = n-1; i >= 0; i--)
+   {
+      Real h = 0.0; Real f = - FloatingPointPrecision::Maximum();
+      Real* d = D.Store(); Real* a = A.Store() + (i*(i+1))/2; int k = i;
+      while (k--) { f = *a++; *d++ = f; h += square(f); }
+      if (h <= tol) { REPORT *(--ei) = 0.0; h = 0.0; }
+      else
+      {
+         REPORT
+         Real g = sign(-sqrt(h), f); *(--ei) = g; h -= f*g;
+         f -= g; *(d-1) = f; *(a-1) = f; f = 0.0;
+         Real* dj = D.Store(); Real* ej = E.Store(); int j;
+         for (j = 0; j < i; j++)
+         {
+            Real* dk = D.Store(); Real* ak = A.Store()+(j*(j+1))/2;
+            Real g = 0.0; k = j;
+            while (k--)  g += *ak++ * *dk++;
+            k = i-j; int l = j; 
+            if (k) for (;;) { g += *ak * *dk++; if (!(--k)) break; ak += ++l; }
+            g /= h; *ej++ = g; f += g * *dj++;
+         }  
+         Real hh = f / (2 * h); Real* ak = A.Store();
+         dj = D.Store(); ej = E.Store();
+         for (j = 0; j < i; j++)
+         {
+            f = *dj++; g = *ej - hh * f; *ej++ = g;
+            Real* dk = D.Store(); Real* ek = E.Store(); k = j+1;
+            while (k--) { *ak++ -= (f * *ek++ + g * *dk++); }
+         }
+      }
+      *d = *a; *a = h;
+   }
+}
+
+static void tql1(DiagonalMatrix& D, DiagonalMatrix& E)
+{
+   Tracer et("Evalue(tql1)");
+   REPORT
+   Real eps = FloatingPointPrecision::Epsilon();
+   int n = D.Nrows(); int l;
+   for (l=1; l<n; l++) E.element(l-1) = E.element(l);
+   Real b = 0.0; Real f = 0.0; E.element(n-1) = 0.0;
+   for (l=0; l<n; l++)
+   {
+      int i,j;
+      Real& dl = D.element(l); Real& el = E.element(l);
+      Real h = eps * ( fabs(dl) + fabs(el) );
+      if (b < h) b = h;
+      int m;
+      for (m=l; m<n; m++) if (fabs(E.element(m)) <= b) break;
+      bool test = false;
+      for (j=0; j<30; j++)
+      {
+         if (m==l) { REPORT test = true; break; }
+         Real& dl1 = D.element(l+1);
+         Real g = dl; Real p = (dl1-g) / (2.0*el); Real r = sqrt(p*p + 1.0);
+         dl = el / (p < 0.0 ? p-r : p+r); Real h = g - dl; f += h;
+         Real* dlx = &dl1; i = n-l-1; while (i--) *dlx++ -= h;
+
+         p = D.element(m); Real c = 1.0; Real s = 0.0;
+         for (i=m-1; i>=l; i--)
+         {
+            Real ei = E.element(i); Real di = D.element(i);
+            Real& ei1 = E.element(i+1);
+            g = c * ei; h = c * p;
+            if ( fabs(p) >= fabs(ei))
+            {
+               REPORT
+               c = ei / p; r = sqrt(c*c + 1.0);
+               ei1 = s*p*r; s = c/r; c = 1.0/r;
+            }
+            else
+            {
+               REPORT
+               c = p / ei; r = sqrt(c*c + 1.0);
+               ei1 = s * ei * r; s = 1.0/r; c /= r;
+            }
+            p = c * di - s*g; D.element(i+1) = h + s * (c*g + s*di);
+         }
+         el = s*p; dl = c*p;
+         if (fabs(el) <= b) { REPORT test = true; break; }
+      }
+      if (!test) Throw ( ConvergenceException(D) );
+      Real p = dl + f;
+      test = false;
+      for (i=l; i>0; i--)
+      {
+         if (p < D.element(i-1)) { REPORT D.element(i) = D.element(i-1); }
+         else { REPORT test = true; break; }
+      }
+      if (!test) i=0;
+      D.element(i) = p;
+   }
+}
+
+void eigenvalues(const SymmetricMatrix& A, DiagonalMatrix& D, Matrix& Z)
+{ REPORT DiagonalMatrix E; tred2(A, D, E, Z); tql2(D, E, Z); SortSV(D,Z,true); }
+
+void eigenvalues(const SymmetricMatrix& X, DiagonalMatrix& D)
+{ REPORT DiagonalMatrix E; SymmetricMatrix A; tred3(X,D,E,A); tql1(D,E); }
+
+void eigenvalues(const SymmetricMatrix& X, DiagonalMatrix& D,
+   SymmetricMatrix& A)
+{ REPORT DiagonalMatrix E; tred3(X,D,E,A); tql1(D,E); }
+
+
+#ifdef use_namespace
+}
+#endif
+
+///@}
+
Index: /nanovis/tags/1.1.4/newmat11/fft.cpp
===================================================================
--- /nanovis/tags/1.1.4/newmat11/fft.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/newmat11/fft.cpp	(revision 4930)
@@ -0,0 +1,480 @@
+/// \ingroup newmat
+///@{
+
+/// \file fft.cpp
+/// \brief Fast Fourier (Carl de Boor) and trig transforms.
+
+
+// Copyright (C) 1991,2,3,4,8: R B Davies
+
+
+#define WANT_MATH
+// #define WANT_STREAM
+
+#include "include.h"
+
+#include "newmatap.h"
+
+// #include "newmatio.h"
+
+#ifdef use_namespace
+namespace NEWMAT {
+#endif
+
+#ifdef DO_REPORT
+#define REPORT { static ExeCounter ExeCount(__LINE__,19); ++ExeCount; }
+#else
+#define REPORT {}
+#endif
+
+static void cossin(int n, int d, Real& c, Real& s)
+// calculate cos(twopi*n/d) and sin(twopi*n/d)
+// minimise roundoff error
+{
+   REPORT
+   long n4 = n * 4; int sector = (int)floor( (Real)n4 / (Real)d + 0.5 );
+   n4 -= sector * d;
+   if (sector < 0) { REPORT sector = 3 - (3 - sector) % 4; }
+   else  { REPORT sector %= 4; }
+   Real ratio = 1.5707963267948966192 * (Real)n4 / (Real)d;
+
+   switch (sector)
+   {
+   case 0: REPORT c =  cos(ratio); s =  sin(ratio); break;
+   case 1: REPORT c = -sin(ratio); s =  cos(ratio); break;
+   case 2: REPORT c = -cos(ratio); s = -sin(ratio); break;
+   case 3: REPORT c =  sin(ratio); s = -cos(ratio); break;
+   }
+}
+
+static void fftstep(ColumnVector& A, ColumnVector& B, ColumnVector& X,
+   ColumnVector& Y, int after, int now, int before)
+{
+   REPORT
+   Tracer trace("FFT(step)");
+   // const Real twopi = 6.2831853071795864769;
+   const int gamma = after * before;  const int delta = now * after;
+   // const Real angle = twopi / delta;  Real temp;
+   // Real r_omega = cos(angle);  Real i_omega = -sin(angle);
+   Real r_arg = 1.0;  Real i_arg = 0.0;
+   Real* x = X.Store();  Real* y = Y.Store();   // pointers to array storage
+   const int m = A.Nrows() - gamma;
+
+   for (int j = 0; j < now; j++)
+   {
+      Real* a = A.Store(); Real* b = B.Store(); // pointers to array storage
+      Real* x1 = x; Real* y1 = y; x += after; y += after;
+      for (int ia = 0; ia < after; ia++)
+      {
+         // generate sins & cosines explicitly rather than iteratively
+         // for more accuracy; but slower
+         cossin(-(j*after+ia), delta, r_arg, i_arg);
+
+         Real* a1 = a++; Real* b1 = b++; Real* x2 = x1++; Real* y2 = y1++;
+         if (now==2)
+         {
+            REPORT int ib = before;
+            if (ib) for (;;)
+            {
+               REPORT
+               Real* a2 = m + a1; Real* b2 = m + b1; a1 += after; b1 += after;
+               Real r_value = *a2; Real i_value = *b2;
+               *x2 = r_value * r_arg - i_value * i_arg + *(a2-gamma);
+               *y2 = r_value * i_arg + i_value * r_arg + *(b2-gamma);
+               if (!(--ib)) break;
+               x2 += delta; y2 += delta;
+            }
+         }
+         else
+         {
+            REPORT int ib = before;
+            if (ib) for (;;)
+            {
+               REPORT
+               Real* a2 = m + a1; Real* b2 = m + b1; a1 += after; b1 += after;
+               Real r_value = *a2; Real i_value = *b2;
+               int in = now-1; while (in--)
+               {
+                  // it should be possible to make this faster
+                  // hand code for now = 2,3,4,5,8
+                  // use symmetry to halve number of operations
+                  a2 -= gamma; b2 -= gamma;  Real temp = r_value;
+                  r_value = r_value * r_arg - i_value * i_arg + *a2;
+                  i_value = temp    * i_arg + i_value * r_arg + *b2;
+               }
+               *x2 = r_value; *y2 = i_value;
+               if (!(--ib)) break;
+               x2 += delta; y2 += delta;
+            }
+         }
+
+         // temp = r_arg;
+         // r_arg = r_arg * r_omega - i_arg * i_omega;
+         // i_arg = temp  * i_omega + i_arg * r_omega;
+
+      }
+   }
+}
+
+
+void FFTI(const ColumnVector& U, const ColumnVector& V,
+   ColumnVector& X, ColumnVector& Y)
+{
+   // Inverse transform
+   Tracer trace("FFTI");
+   REPORT
+   FFT(U,-V,X,Y);
+   const Real n = X.Nrows(); X /= n; Y /= (-n);
+}
+
+void RealFFT(const ColumnVector& U, ColumnVector& X, ColumnVector& Y)
+{
+   // Fourier transform of a real series
+   Tracer trace("RealFFT");
+   REPORT
+   const int n = U.Nrows();                     // length of arrays
+   const int n2 = n / 2;
+   if (n != 2 * n2)
+      Throw(ProgramException("Vector length not multiple of 2", U));
+   ColumnVector A(n2), B(n2);
+   Real* a = A.Store(); Real* b = B.Store(); Real* u = U.Store(); int i = n2;
+   while (i--) { *a++ = *u++; *b++ = *u++; }
+   FFT(A,B,A,B);
+   int n21 = n2 + 1;
+   X.resize(n21); Y.resize(n21);
+   i = n2 - 1;
+   a = A.Store(); b = B.Store();              // first els of A and B
+   Real* an = a + i; Real* bn = b + i;        // last els of A and B
+   Real* x = X.Store(); Real* y = Y.Store();  // first els of X and Y
+   Real* xn = x + n2; Real* yn = y + n2;      // last els of X and Y
+
+   *x++ = *a + *b; *y++ = 0.0;                // first complex element
+   *xn-- = *a++ - *b++; *yn-- = 0.0;          // last complex element
+
+   int j = -1; i = n2/2;
+   while (i--)
+   {
+      Real c,s; cossin(j--,n,c,s);
+      Real am = *a - *an; Real ap = *a++ + *an--;
+      Real bm = *b - *bn; Real bp = *b++ + *bn--;
+      Real samcbp = s * am + c * bp; Real sbpcam = s * bp - c * am;
+      *x++  =  0.5 * ( ap + samcbp); *y++  =  0.5 * ( bm + sbpcam);
+      *xn-- =  0.5 * ( ap - samcbp); *yn-- =  0.5 * (-bm + sbpcam);
+   }
+}
+
+void RealFFTI(const ColumnVector& A, const ColumnVector& B, ColumnVector& U)
+{
+   // inverse of a Fourier transform of a real series
+   Tracer trace("RealFFTI");
+   REPORT
+   const int n21 = A.Nrows();                     // length of arrays
+   if (n21 != B.Nrows() || n21 == 0)
+      Throw(ProgramException("Vector lengths unequal or zero", A, B));
+   const int n2 = n21 - 1;  const int n = 2 * n2;  int i = n2 - 1;
+
+   ColumnVector X(n2), Y(n2);
+   Real* a = A.Store(); Real* b = B.Store();  // first els of A and B
+   Real* an = a + n2;   Real* bn = b + n2;    // last els of A and B
+   Real* x = X.Store(); Real* y = Y.Store();  // first els of X and Y
+   Real* xn = x + i;    Real* yn = y + i;     // last els of X and Y
+
+   Real hn = 0.5 / n2;
+   *x++  = hn * (*a + *an);  *y++  = - hn * (*a - *an);
+   a++; an--; b++; bn--;
+   int j = -1;  i = n2/2;
+   while (i--)
+   {
+      Real c,s; cossin(j--,n,c,s);
+      Real am = *a - *an; Real ap = *a++ + *an--;
+      Real bm = *b - *bn; Real bp = *b++ + *bn--;
+      Real samcbp = s * am - c * bp; Real sbpcam = s * bp + c * am;
+      *x++  =  hn * ( ap + samcbp); *y++  =  - hn * ( bm + sbpcam);
+      *xn-- =  hn * ( ap - samcbp); *yn-- =  - hn * (-bm + sbpcam);
+   }
+   FFT(X,Y,X,Y);             // have done inverting elsewhere
+   U.resize(n); i = n2;
+   x = X.Store(); y = Y.Store(); Real* u = U.Store();
+   while (i--) { *u++ = *x++; *u++ = - *y++; }
+}
+
+void FFT(const ColumnVector& U, const ColumnVector& V,
+   ColumnVector& X, ColumnVector& Y)
+{
+   // from Carl de Boor (1980), Siam J Sci Stat Comput, 1 173-8
+   // but first try Sande and Gentleman
+   Tracer trace("FFT");
+   REPORT
+   const int n = U.Nrows();                     // length of arrays
+   if (n != V.Nrows() || n == 0)
+      Throw(ProgramException("Vector lengths unequal or zero", U, V));
+   if (n == 1) { REPORT X = U; Y = V; return; }
+
+   // see if we can use the newfft routine
+   if (!FFT_Controller::OnlyOldFFT && FFT_Controller::CanFactor(n))
+   {
+      REPORT
+      X = U; Y = V;
+      if ( FFT_Controller::ar_1d_ft(n,X.Store(),Y.Store()) ) return;
+   }
+
+   ColumnVector B = V;
+   ColumnVector A = U;
+   X.resize(n); Y.resize(n);
+   const int nextmx = 8;
+   int prime[8] = { 2,3,5,7,11,13,17,19 };
+   int after = 1; int before = n; int next = 0; bool inzee = true;
+   int now = 0; int b1;             // initialised to keep gnu happy
+
+   do
+   {
+      for (;;)
+      {
+	 if (next < nextmx) { REPORT now = prime[next]; }
+	 b1 = before / now;  if (b1 * now == before) { REPORT break; }
+	 next++; now += 2;
+      }
+      before = b1;
+
+      if (inzee) { REPORT fftstep(A, B, X, Y, after, now, before); }
+      else { REPORT fftstep(X, Y, A, B, after, now, before); }
+
+      inzee = !inzee; after *= now;
+   }
+   while (before != 1);
+
+   if (inzee) { REPORT A.release(); X = A; B.release(); Y = B; }
+}
+
+// Trigonometric transforms
+// see Charles Van Loan (1992) "Computational frameworks for the fast
+// Fourier transform" published by SIAM; section 4.4.
+
+void DCT_II(const ColumnVector& U, ColumnVector& V)
+{
+   // Discrete cosine transform, type II, of a real series
+   Tracer trace("DCT_II");
+   REPORT
+   const int n = U.Nrows();                     // length of arrays
+   const int n2 = n / 2; const int n4 = n * 4;
+   if (n != 2 * n2)
+      Throw(ProgramException("Vector length not multiple of 2", U));
+   ColumnVector A(n);
+   Real* a = A.Store(); Real* b = a + n; Real* u = U.Store();
+   int i = n2;
+   while (i--) { *a++ = *u++; *(--b) = *u++; }
+   ColumnVector X, Y;
+   RealFFT(A, X, Y); A.cleanup();
+   V.resize(n);
+   Real* x = X.Store(); Real* y = Y.Store();
+   Real* v = V.Store(); Real* w = v + n;
+   *v = *x;
+   int k = 0; i = n2;
+   while (i--)
+   {
+      Real c, s; cossin(++k, n4, c, s);
+      Real xi = *(++x); Real yi = *(++y);
+      *(++v) = xi * c + yi * s; *(--w) = xi * s - yi * c;
+   }
+}
+
+void DCT_II_inverse(const ColumnVector& V, ColumnVector& U)
+{
+   // Inverse of discrete cosine transform, type II
+   Tracer trace("DCT_II_inverse");
+   REPORT
+   const int n = V.Nrows();                     // length of array
+   const int n2 = n / 2; const int n4 = n * 4; const int n21 = n2 + 1;
+   if (n != 2 * n2)
+      Throw(ProgramException("Vector length not multiple of 2", V));
+   ColumnVector X(n21), Y(n21);
+   Real* x = X.Store(); Real* y = Y.Store();
+   Real* v = V.Store(); Real* w = v + n;
+   *x = *v; *y = 0.0;
+   int i = n2; int k = 0;
+   while (i--)
+   {
+      Real c, s; cossin(++k, n4, c, s);
+      Real vi = *(++v); Real wi = *(--w);
+      *(++x) = vi * c + wi * s; *(++y) = vi * s - wi * c;
+   }
+   ColumnVector A; RealFFTI(X, Y, A);
+   X.cleanup(); Y.cleanup(); U.resize(n);
+   Real* a = A.Store(); Real* b = a + n; Real* u = U.Store();
+   i = n2;
+   while (i--) { *u++ = *a++; *u++ = *(--b); }
+}
+
+void DST_II(const ColumnVector& U, ColumnVector& V)
+{
+   // Discrete sine transform, type II, of a real series
+   Tracer trace("DST_II");
+   REPORT
+   const int n = U.Nrows();                     // length of arrays
+   const int n2 = n / 2; const int n4 = n * 4;
+   if (n != 2 * n2)
+      Throw(ProgramException("Vector length not multiple of 2", U));
+   ColumnVector A(n);
+   Real* a = A.Store(); Real* b = a + n; Real* u = U.Store();
+   int i = n2;
+   while (i--) { *a++ = *u++; *(--b) = -(*u++); }
+   ColumnVector X, Y;
+   RealFFT(A, X, Y); A.cleanup();
+   V.resize(n);
+   Real* x = X.Store(); Real* y = Y.Store();
+   Real* v = V.Store(); Real* w = v + n;
+   *(--w) = *x;
+   int k = 0; i = n2;
+   while (i--)
+   {
+      Real c, s; cossin(++k, n4, c, s);
+      Real xi = *(++x); Real yi = *(++y);
+      *v++ = xi * s - yi * c; *(--w) = xi * c + yi * s;
+   }
+}
+
+void DST_II_inverse(const ColumnVector& V, ColumnVector& U)
+{
+   // Inverse of discrete sine transform, type II
+   Tracer trace("DST_II_inverse");
+   REPORT
+   const int n = V.Nrows();                     // length of array
+   const int n2 = n / 2; const int n4 = n * 4; const int n21 = n2 + 1;
+   if (n != 2 * n2)
+      Throw(ProgramException("Vector length not multiple of 2", V));
+   ColumnVector X(n21), Y(n21);
+   Real* x = X.Store(); Real* y = Y.Store();
+   Real* v = V.Store(); Real* w = v + n;
+   *x = *(--w); *y = 0.0;
+   int i = n2; int k = 0;
+   while (i--)
+   {
+      Real c, s; cossin(++k, n4, c, s);
+      Real vi = *v++; Real wi = *(--w);
+      *(++x) = vi * s + wi * c; *(++y) = - vi * c + wi * s;
+   }
+   ColumnVector A; RealFFTI(X, Y, A);
+   X.cleanup(); Y.cleanup(); U.resize(n);
+   Real* a = A.Store(); Real* b = a + n; Real* u = U.Store();
+   i = n2;
+   while (i--) { *u++ = *a++; *u++ = -(*(--b)); }
+}
+
+void DCT_inverse(const ColumnVector& V, ColumnVector& U)
+{
+   // Inverse of discrete cosine transform, type I
+   Tracer trace("DCT_inverse");
+   REPORT
+   const int n = V.Nrows()-1;                     // length of transform
+   const int n2 = n / 2; const int n21 = n2 + 1;
+   if (n != 2 * n2)
+      Throw(ProgramException("Vector length not multiple of 2", V));
+   ColumnVector X(n21), Y(n21);
+   Real* x = X.Store(); Real* y = Y.Store(); Real* v = V.Store();
+   Real vi = *v++; *x++ = vi; *y++ = 0.0;
+   Real sum1 = vi / 2.0; Real sum2 = sum1; vi = *v++;
+   int i = n2-1;
+   while (i--)
+   {
+      Real vi2 = *v++; sum1 += vi2 + vi; sum2 += vi2 - vi;
+      *x++ = vi2; vi2 = *v++; *y++ = vi - vi2; vi = vi2;
+   }
+   sum1 += vi; sum2 -= vi;
+   vi = *v; *x = vi; *y = 0.0; vi /= 2.0; sum1 += vi; sum2 += vi;
+   ColumnVector A; RealFFTI(X, Y, A);
+   X.cleanup(); Y.cleanup(); U.resize(n+1);
+   Real* a = A.Store(); Real* b = a + n; Real* u = U.Store(); v = u + n;
+   i = n2; int k = 0; *u++ = sum1 / n2; *v-- = sum2 / n2;
+   while (i--)
+   {
+      Real s = sin(1.5707963267948966192 * (++k) / n2);
+      Real ai = *(++a); Real bi = *(--b);
+      Real bz = (ai - bi) / 4 / s; Real az = (ai + bi) / 2;
+      *u++ = az - bz; *v-- = az + bz;
+   }
+}
+
+void DCT(const ColumnVector& U, ColumnVector& V)
+{
+   // Discrete cosine transform, type I
+   Tracer trace("DCT");
+   REPORT
+   DCT_inverse(U, V);
+   V *= (V.Nrows()-1)/2;
+}
+
+void DST_inverse(const ColumnVector& V, ColumnVector& U)
+{
+   // Inverse of discrete sine transform, type I
+   Tracer trace("DST_inverse");
+   REPORT
+   const int n = V.Nrows()-1;                     // length of transform
+   const int n2 = n / 2; const int n21 = n2 + 1;
+   if (n != 2 * n2)
+      Throw(ProgramException("Vector length not multiple of 2", V));
+   ColumnVector X(n21), Y(n21);
+   Real* x = X.Store(); Real* y = Y.Store(); Real* v = V.Store();
+   Real vi = *(++v); *x++ = 2 * vi; *y++ = 0.0;
+   int i = n2-1;
+   while (i--) { *y++ = *(++v); Real vi2 = *(++v); *x++ = vi2 - vi; vi = vi2; }
+   *x = -2 * vi; *y = 0.0;
+   ColumnVector A; RealFFTI(X, Y, A);
+   X.cleanup(); Y.cleanup(); U.resize(n+1);
+   Real* a = A.Store(); Real* b = a + n; Real* u = U.Store(); v = u + n;
+   i = n2; int k = 0; *u++ = 0.0; *v-- = 0.0;
+   while (i--)
+   {
+      Real s = sin(1.5707963267948966192 * (++k) / n2);
+      Real ai = *(++a); Real bi = *(--b);
+      Real az = (ai + bi) / 4 / s; Real bz = (ai - bi) / 2;
+      *u++ = az - bz; *v-- = az + bz;
+   }
+}
+
+void DST(const ColumnVector& U, ColumnVector& V)
+{
+   // Discrete sine transform, type I
+   Tracer trace("DST");
+   REPORT
+   DST_inverse(U, V);
+   V *= (V.Nrows()-1)/2;
+}
+
+// Two dimensional FFT
+void FFT2(const Matrix& U, const Matrix& V, Matrix& X, Matrix& Y)
+{
+   Tracer trace("FFT2");
+   REPORT
+   int m = U.Nrows(); int n = U.Ncols();
+   if (m != V.Nrows() || n != V.Ncols() || m == 0 || n == 0)
+      Throw(ProgramException("Matrix dimensions unequal or zero", U, V));
+   X = U; Y = V;
+   int i; ColumnVector CVR; ColumnVector CVI;
+   for (i = 1; i <= m; ++i)
+   {
+      FFT(X.Row(i).t(), Y.Row(i).t(), CVR, CVI);
+      X.Row(i) = CVR.t(); Y.Row(i) = CVI.t();
+   }
+   for (i = 1; i <= n; ++i)
+   {
+      FFT(X.Column(i), Y.Column(i), CVR, CVI);
+      X.Column(i) = CVR; Y.Column(i) = CVI;
+   }
+}
+
+void FFT2I(const Matrix& U, const Matrix& V, Matrix& X, Matrix& Y)
+{
+   // Inverse transform
+   Tracer trace("FFT2I");
+   REPORT
+   FFT2(U,-V,X,Y);
+   const Real n = X.Nrows() * X.Ncols(); X /= n; Y /= (-n);
+}
+
+
+#ifdef use_namespace
+}
+#endif
+
+
+///@}
Index: /nanovis/tags/1.1.4/newmat11/hholder.cpp
===================================================================
--- /nanovis/tags/1.1.4/newmat11/hholder.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/newmat11/hholder.cpp	(revision 4930)
@@ -0,0 +1,376 @@
+/// \ingroup newmat
+///@{
+
+/// \file hholder.cpp
+/// QR related decompositions
+/// QRZ, QRZT decompositions
+/// QR update and extend orthogonal functions
+
+// Copyright (C) 1991,2,3,4: R B Davies
+
+#define WANT_MATH
+//#define WANT_STREAM
+
+#include "include.h"
+
+#include "newmatap.h"
+
+#ifdef use_namespace
+namespace NEWMAT {
+#endif
+
+#ifdef DO_REPORT
+#define REPORT { static ExeCounter ExeCount(__LINE__,16); ++ExeCount; }
+#else
+#define REPORT {}
+#endif
+
+
+/*************************** QR decompositions ***************************/
+
+inline Real square(Real x) { return x*x; }
+
+void QRZT(Matrix& X, LowerTriangularMatrix& L)
+{
+   REPORT
+	 Tracer et("QRZT(1)");
+   int n = X.Ncols(); int s = X.Nrows(); L.resize(s);
+   if (n == 0 || s == 0) { L = 0.0; return; }
+   Real* xi = X.Store(); int k;
+   for (int i=0; i<s; i++)
+   {
+      Real sum = 0.0;
+      Real* xi0=xi; k=n; while(k--) { sum += square(*xi++); }
+      sum = sqrt(sum);
+      if (sum == 0.0)
+      {
+         REPORT
+         k=n; while(k--) { *xi0++ = 0.0; }
+         for (int j=i; j<s; j++) L.element(j,i) = 0.0;
+      }
+      else
+      {
+         L.element(i,i) = sum;
+         Real* xj0=xi0; k=n; while(k--) { *xj0++ /= sum; }
+         for (int j=i+1; j<s; j++)
+         {
+            sum=0.0;
+            xi=xi0; Real* xj=xj0; k=n; while(k--) { sum += *xi++ * *xj++; }
+            xi=xi0; k=n; while(k--) { *xj0++ -= sum * *xi++; }
+            L.element(j,i) = sum;
+         }
+      }
+   }
+}
+
+void QRZT(const Matrix& X, Matrix& Y, Matrix& M)
+{
+   REPORT
+   Tracer et("QRZT(2)");
+   int n = X.Ncols(); int s = X.Nrows(); int t = Y.Nrows();
+   if (Y.Ncols() != n)
+      { Throw(ProgramException("Unequal row lengths",X,Y)); }
+   M.resize(t,s);
+   Real* xi = X.Store(); int k;
+   for (int i=0; i<s; i++)
+   {
+      Real* xj0 = Y.Store(); Real* xi0 = xi;
+      for (int j=0; j<t; j++)
+      {
+         Real sum=0.0;
+         xi=xi0; Real* xj=xj0; k=n; while(k--) { sum += *xi++ * *xj++; }
+         xi=xi0; k=n; while(k--) { *xj0++ -= sum * *xi++; }
+         M.element(j,i) = sum;
+      }
+   }
+}
+
+/*
+void QRZ(Matrix& X, UpperTriangularMatrix& U)
+{
+	Tracer et("QRZ(1)");
+	int n = X.Nrows(); int s = X.Ncols(); U.resize(s);
+	Real* xi0 = X.Store(); int k;
+	for (int i=0; i<s; i++)
+	{
+		Real sum = 0.0;
+		Real* xi = xi0; k=n; while(k--) { sum += square(*xi); xi+=s; }
+		sum = sqrt(sum);
+		U.element(i,i) = sum;
+		if (sum==0.0) Throw(SingularException(U));
+		Real* xj0=xi0; k=n; while(k--) { *xj0 /= sum; xj0+=s; }
+		xj0 = xi0;
+		for (int j=i+1; j<s; j++)
+		{
+			sum=0.0;
+			xi=xi0; k=n; xj0++; Real* xj=xj0;
+			while(k--) { sum += *xi * *xj; xi+=s; xj+=s; }
+			xi=xi0; k=n; xj=xj0;
+			while(k--) { *xj -= sum * *xi; xj+=s; xi+=s; }
+			U.element(i,j) = sum;
+		}
+		xi0++;
+	}
+}
+*/
+
+void QRZ(Matrix& X, UpperTriangularMatrix& U)
+{
+   REPORT
+   Tracer et("QRZ(1)");
+   int n = X.Nrows(); int s = X.Ncols(); U.resize(s); U = 0.0;
+   if (n == 0 || s == 0) return;
+   Real* xi0 = X.Store(); Real* u0 = U.Store(); Real* u;
+   int j, k; int J = s; int i = s;
+   while (i--)
+   {
+      Real* xj0 = xi0; Real* xi = xi0; k = n;
+      if (k) for (;;)
+      {
+         u = u0; Real Xi = *xi; Real* xj = xj0;
+         j = J; while(j--) *u++ += Xi * *xj++;
+         if (!(--k)) break;
+         xi += s; xj0 += s;
+      }
+
+      Real sum = sqrt(*u0); *u0 = sum; u = u0+1;
+      if (sum == 0.0)
+      {
+         REPORT
+         j = J - 1; while(j--) *u++ = 0.0;
+
+         xj0 = xi0++; k = n;
+         if (k) for (;;)
+         {
+            *xj0 = 0.0;
+            if (!(--k)) break;
+	          xj0 += s;
+         }
+         u0 += J--;
+      }
+      else
+      {
+         int J1 = J-1; j = J1; while(j--) *u++ /= sum;
+
+         xj0 = xi0; xi = xi0++; k = n;
+         if (k) for (;;)
+         {
+            u = u0+1; Real Xi = *xi; Real* xj = xj0;
+            Xi /= sum; *xj++ = Xi;
+            j = J1; while(j--) *xj++ -= *u++ * Xi;
+            if (!(--k)) break;
+	          xi += s; xj0 += s;
+         }
+         u0 += J--;
+      }
+   }
+}
+
+void QRZ(const Matrix& X, Matrix& Y, Matrix& M)
+{
+   REPORT
+   Tracer et("QRZ(2)");
+   int n = X.Nrows(); int s = X.Ncols(); int t = Y.Ncols();
+   if (Y.Nrows() != n)
+      { Throw(ProgramException("Unequal column lengths",X,Y)); }
+   M.resize(s,t); M = 0;Real* m0 = M.Store(); Real* m;
+   Real* xi0 = X.Store();
+   int j, k; int i = s;
+   while (i--)
+   {
+      Real* xj0 = Y.Store(); Real* xi = xi0; k = n;
+      if (k) for (;;)
+      {
+         m = m0; Real Xi = *xi; Real* xj = xj0;
+         j = t; while(j--) *m++ += Xi * *xj++;
+         if (!(--k)) break;
+         xi += s; xj0 += t;
+      }
+
+      xj0 = Y.Store(); xi = xi0++; k = n;
+      if (k) for (;;)
+      {
+         m = m0; Real Xi = *xi; Real* xj = xj0;
+         j = t; while(j--) *xj++ -= *m++ * Xi;
+         if (!(--k)) break;
+         xi += s; xj0 += t;
+      }
+      m0 += t;
+   }
+}
+
+/*
+
+void QRZ(const Matrix& X, Matrix& Y, Matrix& M)
+{
+	Tracer et("QRZ(2)");
+	int n = X.Nrows(); int s = X.Ncols(); int t = Y.Ncols();
+	if (Y.Nrows() != n)
+	{ Throw(ProgramException("Unequal column lengths",X,Y)); }
+	M.resize(s,t);
+	Real* xi0 = X.Store(); int k;
+	for (int i=0; i<s; i++)
+	{
+		Real* xj0 = Y.Store();
+		for (int j=0; j<t; j++)
+		{
+			Real sum=0.0;
+			Real* xi=xi0; Real* xj=xj0; k=n;
+			while(k--) { sum += *xi * *xj; xi+=s; xj+=t; }
+			xi=xi0; k=n; xj=xj0++;
+			while(k--) { *xj -= sum * *xi; xj+=t; xi+=s; }
+			M.element(i,j) = sum;
+		}
+		xi0++;
+	}
+}
+*/
+
+void updateQRZT(Matrix& X, LowerTriangularMatrix& L)
+{
+   REPORT
+	 Tracer et("updateQRZT");
+   int n = X.Ncols(); int s = X.Nrows();
+   if (s != L.Nrows())
+      Throw(ProgramException("Incompatible dimensions",X,L)); 
+   if (n == 0 || s == 0) return;
+   Real* xi = X.Store(); int k;
+   for (int i=0; i<s; i++)
+   {
+      Real r = L.element(i,i); 
+      Real sum = 0.0;
+      Real* xi0=xi; k=n; while(k--) { sum += square(*xi++); }
+      sum = sqrt(sum + square(r));
+      if (sum == 0.0)
+      {
+         REPORT
+         k=n; while(k--) { *xi0++ = 0.0; }
+         for (int j=i; j<s; j++) L.element(j,i) = 0.0;
+      }
+      else
+      {
+         Real frs = fabs(r) + sum;
+         Real a0 = sqrt(frs / sum); Real alpha = a0 / frs;
+         if (r <= 0) { REPORT L.element(i,i) = sum; alpha = -alpha; }
+         else { REPORT L.element(i,i) = -sum; }
+         Real* xj0=xi0; k=n; while(k--) { *xj0++ *= alpha; }
+         for (int j=i+1; j<s; j++)
+         {
+            sum = 0.0;
+            xi=xi0; Real* xj=xj0; k=n; while(k--) { sum += *xi++ * *xj++; }
+            sum += a0 * L.element(j,i);
+            xi=xi0; k=n; while(k--) { *xj0++ -= sum * *xi++; }
+            L.element(j,i) -= sum * a0;
+         }
+      }
+   }
+}
+
+void updateQRZ(Matrix& X, UpperTriangularMatrix& U)
+{
+   REPORT
+   Tracer et("updateQRZ");
+   int n = X.Nrows(); int s = X.Ncols();
+   if (s != U.Ncols())
+      Throw(ProgramException("Incompatible dimensions",X,U));
+   if (n == 0 || s == 0) return; 
+   Real* xi0 = X.Store(); Real* u0 = U.Store(); Real* u;
+   RowVector V(s); Real* v0 = V.Store(); Real* v; V = 0.0;
+   int j, k; int J = s; int i = s;
+   while (i--)
+   {
+      Real* xj0 = xi0; Real* xi = xi0; k = n;
+      if (k) for (;;)
+      {
+         v = v0; Real Xi = *xi; Real* xj = xj0;
+         j = J; while(j--) *v++ += Xi * *xj++;
+         if (!(--k)) break;
+         xi += s; xj0 += s;
+      }
+
+      Real r = *u0;
+      Real sum = sqrt(*v0 + square(r));
+      
+      if (sum == 0.0)
+      {
+         REPORT
+         u = u0; v = v0;
+         j = J; while(j--) { *u++ = 0.0; *v++ = 0.0; }
+         xj0 = xi0++; k = n;
+         if (k) for (;;)
+         {
+            *xj0 = 0.0;
+            if (!(--k)) break;
+	          xj0 += s;
+         }
+         u0 += J--;
+      }
+      else
+      {
+         Real frs = fabs(r) + sum;
+         Real a0 = sqrt(frs / sum); Real alpha = a0 / frs;
+         if (r <= 0) { REPORT alpha = -alpha; *u0 = sum; }
+         else { REPORT *u0 = -sum; }
+      
+         j = J - 1; v = v0 + 1; u = u0 + 1;     
+         while (j--)
+            { *v = a0 * *u + alpha * *v; *u -= a0 * *v; ++v; ++u; }
+
+         xj0 = xi0; xi = xi0++; k = n;
+         if (k) for (;;)
+         {
+            v = v0 + 1; Real Xi = *xi; Real* xj = xj0;
+            Xi *= alpha; *xj++ = Xi;
+            j = J - 1; while(j--) *xj++ -= *v++ * Xi;
+            if (!(--k)) break;
+	          xi += s; xj0 += s;
+         }
+         
+         j = J; v = v0;
+         while (j--) *v++ = 0.0;
+         
+         u0 += J--;
+      }
+   }
+}
+
+// Matrix A's first n columns are orthonormal
+// so A.Columns(1,n).t() * A.Columns(1,n) is the identity matrix.
+// Fill out the remaining columns of A to make them orthonormal
+// so A.t() * A is the identity matrix 
+void extend_orthonormal(Matrix& A, int n)
+{
+   REPORT
+   Tracer et("extend_orthonormal");
+   int nr = A.nrows(); int nc = A.ncols();
+   if (nc > nr) Throw(IncompatibleDimensionsException(A));
+   if (n > nc) Throw(IncompatibleDimensionsException(A));
+   ColumnVector SSR;
+   { Matrix A1 = A.Columns(1,n); SSR = A1.sum_square_rows(); }
+   for (int i = n; i < nc; ++i)
+   {
+      // pick row with smallest SSQ
+      int k; SSR.minimum1(k);
+      // orthogonalise column with 1 at element k, 0 elsewhere
+      // next line is rather inefficient
+      ColumnVector X = - A.Columns(1, i) * A.SubMatrix(k, k, 1, i).t();
+      X(k) += 1.0;
+      // normalise
+      X /= sqrt(X.SumSquare());
+      // update row sums of squares
+      for (k = 1; k <= nr; ++k) SSR(k) += square(X(k));
+      // load new column into matrix
+      A.Column(i+1) = X;
+   }
+}
+   
+   
+
+
+
+#ifdef use_namespace
+}
+#endif
+
+
+///@}
Index: /nanovis/tags/1.1.4/newmat11/include.h
===================================================================
--- /nanovis/tags/1.1.4/newmat11/include.h	(revision 4930)
+++ /nanovis/tags/1.1.4/newmat11/include.h	(revision 4930)
@@ -0,0 +1,348 @@
+/// \defgroup rbd_common RBD common library 
+///@{
+
+/// \file include.h
+/// Set options and and details of include files.
+
+#ifndef INCLUDE_LIB
+#define INCLUDE_LIB
+
+//#define use_namespace                   // define name spaces
+
+//#define SETUP_C_SUBSCRIPTS              // allow element access via A[i][j]
+
+//#define OPT_COMPATIBLE                  // for use with opt++
+
+// Activate just one of the following 3 statements
+
+//#define SimulateExceptions              // use simulated exceptions
+#define UseExceptions                   // use C++ exceptions
+//#define DisableExceptions               // do not use exceptions
+
+
+//#define TEMPS_DESTROYED_QUICKLY         // for compilers that delete
+					// temporaries too quickly
+
+//#define TEMPS_DESTROYED_QUICKLY_R       // the same thing but applied
+					// to return from functions only
+
+//#define DO_FREE_CHECK                   // check news and deletes balance
+
+#define USING_DOUBLE                    // elements of type double
+//#define USING_FLOAT                   // elements of type float
+
+#define bool_LIB 0                      // for compatibility with my older libraries
+
+//#define ios_format_flags ios::fmtflags  // for Gnu 3 and Intel for Linux
+
+
+//#define _STANDARD_                    // using standard library
+
+//#define use_float_h                   // use float.h for precision data
+
+
+//#define HAS_INT64                     // if unsigned _int64 is recognised
+                                        // used by newran03
+                                        
+// comment out next line if Exception causes a problem
+#define TypeDefException
+
+//*********************** end of options set by user ********************
+
+
+// for Gnu C++ version 3
+#if defined __GNUG__ && __GNUG__ >= 3
+   #define _STANDARD_                   // use standard library
+   #define ios_format_flags ios::fmtflags
+#endif
+
+// for Intel C++ for Linux
+#if defined __ICC
+   #define _STANDARD_                   // use standard library
+   #define ios_format_flags ios::fmtflags
+#endif
+
+// for Microsoft Visual C++ 7 and above (and Intel simulating these)
+#if defined _MSC_VER && _MSC_VER >= 1300
+   #define _STANDARD_                   // use standard library
+#endif
+
+
+#ifdef _STANDARD_                       // using standard library
+   #include <cstdlib>
+   #if defined _MSC_VER && _MSC_VER == 1200
+      #include <limits>              // for VC++6
+   #endif
+   #ifdef WANT_STREAM
+      #include <iostream>
+      #include <iomanip>
+   #endif
+   #ifdef WANT_MATH
+      #include <cmath>
+   #endif
+   #ifdef WANT_STRING
+      #include <cstring>
+   #endif
+   #ifdef WANT_TIME
+      #include <ctime>
+   #endif
+   #ifdef WANT_FSTREAM
+      #include <fstream>
+   #endif
+   using namespace std;
+#else
+
+#define DEFAULT_HEADER                  // use AT&T style header
+                                        // if no other compiler is recognised
+
+#ifdef _MSC_VER                         // Microsoft
+   #include <stdlib.h>
+
+//   reactivate these statements to run under MSC version 7.0
+//   typedef int jmp_buf[9];
+//   extern "C"
+//   {
+//      int __cdecl setjmp(jmp_buf);
+//      void __cdecl longjmp(jmp_buf, int);
+//   }
+
+   #ifdef WANT_STREAM
+      #include <iostream.h>
+      #include <iomanip.h>
+   #endif
+   #ifdef WANT_MATH
+      #include <math.h>
+      #include <float.h>
+   #endif
+   #ifdef WANT_STRING
+      #include <string.h>
+   #endif
+   #ifdef WANT_TIME
+      #include <time.h>
+   #endif
+   #ifdef WANT_FSTREAM
+      #include <fstream.h>
+   #endif
+   #undef DEFAULT_HEADER
+#endif
+
+#ifdef __ZTC__                          // Zortech
+   #include <stdlib.h>
+   #ifdef WANT_STREAM
+      #include <iostream.hpp>
+      #include <iomanip.hpp>
+      #define flush ""                  // not defined in iomanip?
+   #endif
+   #ifdef WANT_MATH
+      #include <math.h>
+      #include <float.h>
+   #endif
+   #ifdef WANT_STRING
+      #include <string.h>
+   #endif
+   #ifdef WANT_TIME
+      #include <time.h>
+   #endif
+   #ifdef WANT_FSTREAM
+      #include <fstream.h>
+   #endif
+   #undef DEFAULT_HEADER
+#endif
+
+#if defined __BCPLUSPLUS__ || defined __TURBOC__  // Borland or Turbo
+   #include <stdlib.h>
+   #ifdef WANT_STREAM
+      #include <iostream.h>
+      #include <iomanip.h>
+   #endif
+   #ifdef WANT_MATH
+      #include <math.h>
+      #include <float.h>            // Borland has both float and values
+                                    // but values.h returns +INF for
+                                    // MAXDOUBLE in BC5
+   #endif
+   #ifdef WANT_STRING
+      #include <string.h>
+   #endif
+   #ifdef WANT_TIME
+      #include <time.h>
+   #endif
+   #ifdef WANT_FSTREAM
+      #include <fstream.h>
+   #endif
+   #undef DEFAULT_HEADER
+#endif
+
+#ifdef __GNUG__                         // Gnu C++
+   #include <stdlib.h>
+   #ifdef WANT_STREAM
+      #include <iostream.h>
+      #include <iomanip.h>
+   #endif
+   #ifdef WANT_MATH
+      #include <math.h>
+      #include <float.h>
+   #endif
+   #ifdef WANT_STRING
+      #include <string.h>
+   #endif
+   #ifdef WANT_TIME
+      #include <time.h>
+   #endif
+   #ifdef WANT_FSTREAM
+      #include <fstream.h>
+   #endif
+   #undef DEFAULT_HEADER
+#endif
+
+#ifdef __WATCOMC__                      // Watcom C/C++
+   #include <stdlib.h>
+   #ifdef WANT_STREAM
+      #include <iostream.h>
+      #include <iomanip.h>
+   #endif
+   #ifdef WANT_MATH
+      #include <math.h>
+      #include <float.h>
+   #endif
+   #ifdef WANT_STRING
+      #include <string.h>
+   #endif
+   #ifdef WANT_TIME
+      #include <time.h>
+   #endif
+   #ifdef WANT_FSTREAM
+      #include <fstream.h>
+   #endif
+   #undef DEFAULT_HEADER
+#endif
+
+
+#ifdef macintosh                        // MPW C++ on the Mac
+#include <stdlib.h>
+#ifdef WANT_STREAM
+#include <iostream.h>
+#include <iomanip.h>
+#endif
+#ifdef WANT_MATH
+#include <float.h>
+#include <math.h>
+#endif
+#ifdef WANT_STRING
+#include <string.h>
+#endif
+#ifdef WANT_TIME
+#include <time.h>
+#endif
+#ifdef WANT_FSTREAM
+#include <fstream.h>
+#endif
+#undef DEFAULT_HEADER
+#endif
+
+#ifdef use_float_h                      // use float.h for precision values
+#include <stdlib.h>
+#ifdef WANT_STREAM
+#include <iostream.h>
+#include <iomanip.h>
+#endif
+#ifdef WANT_MATH
+#include <float.h>
+#include <math.h>
+#endif
+#ifdef WANT_STRING
+#include <string.h>
+#endif
+#ifdef WANT_TIME
+#include <time.h>
+#endif
+#ifdef WANT_FSTREAM
+#include <fstream.h>
+#endif
+#undef DEFAULT_HEADER
+#endif
+
+
+#ifdef DEFAULT_HEADER                   // for example AT&T
+#define ATandT
+#include <stdlib.h>
+#ifdef WANT_STREAM
+#include <iostream.h>
+#include <iomanip.h>
+#endif
+#ifdef WANT_MATH
+#include <math.h>
+#define SystemV                         // use System V
+#include <values.h>
+#endif
+#ifdef WANT_STRING
+#include <string.h>
+#endif
+#ifdef WANT_TIME
+#include <time.h>
+#endif
+#ifdef WANT_FSTREAM
+#include <fstream.h>
+#endif
+#endif                                  // DEFAULT_HEADER
+
+#endif                                  // _STANDARD_
+
+#ifdef use_namespace
+namespace RBD_COMMON {
+#endif
+
+
+#ifdef USING_FLOAT                      // set precision type to float
+typedef float Real;
+typedef double long_Real;
+#endif
+
+#ifdef USING_DOUBLE                     // set precision type to double
+typedef double Real;
+typedef long double long_Real;
+#endif
+
+
+// This is for (very old) compilers that do not have bool automatically defined
+
+#ifndef bool_LIB
+#define bool_LIB 0
+
+class bool
+{
+	int value;
+public:
+	bool(const int b) { value = b ? 1 : 0; }
+	bool(const void* b) { value = b ? 1 : 0; }
+	bool() {}
+	operator int() const { return value; }
+	int operator!() const { return !value; }
+};
+
+
+const bool true = 1;
+const bool false = 0;
+
+#endif
+
+
+#ifdef use_namespace
+}
+#endif
+
+
+#ifdef use_namespace
+namespace RBD_COMMON {}
+namespace RBD_LIBRARIES                 // access all my libraries
+{
+   using namespace RBD_COMMON;
+}
+#endif
+
+
+#endif
+
+
+///@}
+
Index: /nanovis/tags/1.1.4/newmat11/jacobi.cpp
===================================================================
--- /nanovis/tags/1.1.4/newmat11/jacobi.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/newmat11/jacobi.cpp	(revision 4930)
@@ -0,0 +1,130 @@
+/// \ingroup newmat
+///@{
+
+/// \file jacobi.cpp
+/// Eigen value decomposition using Jacobi method.
+
+
+// Copyright (C) 1991,2,3,4: R B Davies
+
+
+//#define WANT_STREAM
+
+
+#define WANT_MATH
+
+#include "include.h"
+#include "newmatap.h"
+#include "precisio.h"
+#include "newmatrm.h"
+
+#ifdef use_namespace
+namespace NEWMAT {
+#endif
+
+#ifdef DO_REPORT
+#define REPORT { static ExeCounter ExeCount(__LINE__,18); ++ExeCount; }
+#else
+#define REPORT {}
+#endif
+
+
+void Jacobi(const SymmetricMatrix& X, DiagonalMatrix& D, SymmetricMatrix& A,
+   Matrix& V, bool eivec)
+{
+   Real epsilon = FloatingPointPrecision::Epsilon();
+   Tracer et("Jacobi");
+   REPORT
+   int n = X.Nrows(); DiagonalMatrix B(n), Z(n); D.resize(n); A = X;
+   if (eivec) { REPORT V.resize(n,n); D = 1.0; V = D; }
+   B << A; D = B; Z = 0.0; A.Inject(Z);
+   bool converged = false;
+   for (int i=1; i<=50; i++)
+   {
+      Real sm=0.0; Real* a = A.Store(); int p = A.Storage();
+      while (p--) sm += fabs(*a++);            // have previously zeroed diags
+      if (sm==0.0) { REPORT converged = true; break; }
+      Real tresh = (i<4) ? 0.2 * sm / square(n) : 0.0; a = A.Store();
+      for (p = 0; p < n; p++)
+      {
+         Real* ap1 = a + (p*(p+1))/2;
+         Real& zp = Z.element(p); Real& dp = D.element(p);
+         for (int q = p+1; q < n; q++)
+         {
+            Real* ap = ap1; Real* aq = a + (q*(q+1))/2;
+            Real& zq = Z.element(q); Real& dq = D.element(q);
+            Real& apq = A.element(q,p);
+            Real g = 100 * fabs(apq); Real adp = fabs(dp); Real adq = fabs(dq);
+
+            if (i>4 && g < epsilon*adp && g < epsilon*adq) { REPORT apq = 0.0; }
+            else if (fabs(apq) > tresh)
+            {
+               REPORT
+               Real t; Real h = dq - dp; Real ah = fabs(h);
+               if (g < epsilon*ah) { REPORT t = apq / h; }
+               else
+               {
+                  REPORT
+                  Real theta = 0.5 * h / apq;
+                  t = 1.0 / ( fabs(theta) + sqrt(1.0 + square(theta)) );
+                  if (theta<0.0) { REPORT t = -t; }
+               }
+               Real c = 1.0 / sqrt(1.0 + square(t)); Real s = t * c;
+               Real tau = s / (1.0 + c); h = t * apq;
+               zp -= h; zq += h; dp -= h; dq += h; apq = 0.0;
+               int j = p;
+               while (j--)
+               {
+                  g = *ap; h = *aq;
+                  *ap++ = g-s*(h+g*tau); *aq++ = h+s*(g-h*tau);
+               }
+               int ip = p+1; j = q-ip; ap += ip++; aq++;
+               while (j--)
+               {
+                  g = *ap; h = *aq;
+                  *ap = g-s*(h+g*tau); *aq++ = h+s*(g-h*tau);
+                  ap += ip++;
+               }
+               if (q < n-1)             // last loop is non-empty
+               {
+                  int iq = q+1; j = n-iq; ap += ip++; aq += iq++;
+                  for (;;)
+                  {
+                     g = *ap; h = *aq;
+                     *ap = g-s*(h+g*tau); *aq = h+s*(g-h*tau);
+                     if (!(--j)) break;
+                     ap += ip++; aq += iq++;
+                  }
+               }
+               if (eivec)
+               {
+                  REPORT
+                  RectMatrixCol VP(V,p); RectMatrixCol VQ(V,q);
+                  Rotate(VP, VQ, tau, s);
+               }
+            }
+         }
+      }
+      B = B + Z; D = B; Z = 0.0;
+   }
+   if (!converged) Throw(ConvergenceException(X));
+   if (eivec) SortSV(D, V, true);
+   else SortAscending(D);
+}
+
+void Jacobi(const SymmetricMatrix& X, DiagonalMatrix& D)
+{ REPORT SymmetricMatrix A; Matrix V; Jacobi(X,D,A,V,false); }
+
+void Jacobi(const SymmetricMatrix& X, DiagonalMatrix& D, SymmetricMatrix& A)
+{ REPORT Matrix V; Jacobi(X,D,A,V,false); }
+
+void Jacobi(const SymmetricMatrix& X, DiagonalMatrix& D, Matrix& V)
+{ REPORT SymmetricMatrix A; Jacobi(X,D,A,V,true); }
+
+
+#ifdef use_namespace
+}
+#endif
+
+
+///@}
Index: /nanovis/tags/1.1.4/newmat11/myexcept.cpp
===================================================================
--- /nanovis/tags/1.1.4/newmat11/myexcept.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/newmat11/myexcept.cpp	(revision 4930)
@@ -0,0 +1,496 @@
+/// \ingroup rbd_common
+///@{
+
+/// \file myexcept.cpp
+/// Exception handler.
+/// The low level classes for
+/// - my exception class hierarchy
+/// - the functions needed for my simulated exceptions
+/// - the Tracer mechanism
+/// - routines for checking whether new and delete calls are balanced
+///
+
+// Copyright (C) 1993,4,6: R B Davies
+
+
+#define WANT_STREAM                    // include.h will get stream fns
+#define WANT_STRING
+
+#include "include.h"                   // include standard files
+
+
+#include "myexcept.h"                  // for exception handling
+
+#ifdef use_namespace
+namespace RBD_COMMON {
+#endif
+
+
+//#define REG_DEREG                    // for print out uses of new/delete
+//#define CLEAN_LIST                   // to print entries being added to
+                                       // or deleted from cleanup list
+
+#ifdef SimulateExceptions
+
+void Throw()
+{
+   for (Janitor* jan = JumpBase::jl->janitor; jan; jan = jan->NextJanitor)
+      jan->CleanUp();
+   JumpItem* jx = JumpBase::jl->ji;    // previous jumpbase;
+   if ( !jx ) { Terminate(); }         // jl was initial JumpItem
+   JumpBase::jl = jx;                  // drop down a level; cannot be in front
+                                       // of previous line
+   Tracer::last = JumpBase::jl->trace;
+   longjmp(JumpBase::jl->env, 1);
+}
+
+#endif                                 // end of simulate exceptions
+
+
+unsigned long BaseException::Select;
+char* BaseException::what_error;
+int BaseException::SoFar;
+int BaseException::LastOne;
+
+BaseException::BaseException(const char* a_what)
+{
+   Select++; SoFar = 0;
+   if (!what_error)                   // make space for exception message
+   {
+      LastOne = 511;
+      what_error = new char[512];
+      if (!what_error)                // fail to make space
+      {
+         LastOne = 0;
+         what_error = (char *)"No heap space for exception message\n";
+      }
+   }
+   AddMessage("\n\nAn exception has been thrown\n");
+   AddMessage(a_what);
+   if (a_what) Tracer::AddTrace();
+}
+
+void BaseException::AddMessage(const char* a_what)
+{
+   if (a_what)
+   {
+      int l = strlen(a_what); int r = LastOne - SoFar;
+      if (l < r) { strcpy(what_error+SoFar, a_what); SoFar += l; }
+      else if (r > 0)
+      {
+         strncpy(what_error+SoFar, a_what, r);
+         what_error[LastOne] = 0;
+         SoFar = LastOne;
+      }
+   }
+}
+
+void BaseException::AddInt(int value)
+{
+   bool negative;
+   if (value == 0) { AddMessage("0"); return; }
+   else if (value < 0) { value = -value; negative = true; }
+   else negative = false;
+   int n = 0; int v = value;        // how many digits will we need?
+   while (v > 0) { v /= 10; n++; }
+   if (negative) n++;
+   if (LastOne-SoFar < n) { AddMessage("***"); return; }
+
+   SoFar += n; n = SoFar; what_error[n] = 0;
+   while (value > 0)
+   {
+      int nv = value / 10; int rm = value - nv * 10;  value = nv;
+      what_error[--n] = (char)(rm + '0');
+   }
+   if (negative) what_error[--n] = '-';
+   return;
+}
+
+void Tracer::PrintTrace()
+{
+   cout << "\n";
+   for (Tracer* et = last; et; et=et->previous)
+      cout << "  * " << et->entry << "\n";
+}
+
+void Tracer::AddTrace()
+{
+   if (last)
+   {
+      BaseException::AddMessage("Trace: ");
+      BaseException::AddMessage(last->entry);
+      for (Tracer* et = last->previous; et; et=et->previous)
+      {
+         BaseException::AddMessage("; ");
+         BaseException::AddMessage(et->entry);
+      }
+      BaseException::AddMessage(".\n");
+   }
+}
+
+#ifdef SimulateExceptions
+
+
+Janitor::Janitor()
+{
+   if (do_not_link)
+   {
+      do_not_link = false; NextJanitor = 0; OnStack = false;
+#ifdef CLEAN_LIST
+      cout << "Not added to clean-list " << (unsigned long)this << "\n";
+#endif
+   }
+   else
+   {
+      OnStack = true;
+#ifdef CLEAN_LIST
+      cout << "Add to       clean-list " << (unsigned long)this << "\n";
+#endif
+      NextJanitor = JumpBase::jl->janitor; JumpBase::jl->janitor=this;
+   }
+}
+
+Janitor::~Janitor()
+{
+   // expect the item to be deleted to be first on list
+   // but must be prepared to search list
+   if (OnStack)
+   {
+#ifdef CLEAN_LIST
+      cout << "Delete from  clean-list " << (unsigned long)this << "\n";
+#endif
+      Janitor* lastjan = JumpBase::jl->janitor;
+      if (this == lastjan) JumpBase::jl->janitor = NextJanitor;
+      else
+      {
+	 for (Janitor* jan = lastjan->NextJanitor; jan;
+	    jan = lastjan->NextJanitor)
+	 {
+	    if (jan==this)
+	       { lastjan->NextJanitor = jan->NextJanitor; return; }
+	    lastjan=jan;
+	 }
+
+	 Throw(BaseException(
+"Cannot resolve memory linked list\nSee notes in myexcept.cpp for details\n"
+         ));
+
+
+// This message occurs when a call to ~Janitor() occurs, apparently
+// without a corresponding call to Janitor(). This could happen if my
+// way of deciding whether a constructor is being called by new
+// fails.
+
+// It may happen if you are using my simulated exceptions and also have
+// your compiler s exceptions turned on.
+
+// It can also happen if you have a class derived from Janitor
+// which does not include a copy constructor [ eg X(const &X) ].
+// Possibly also if delete is applied an object on the stack (ie not
+// called by new). Otherwise, it is a bug in myexcept or your compiler.
+// If you do not #define TEMPS_DESTROYED_QUICKLY you will get this
+// error with Microsoft C 7.0. There are probably situations where
+// you will get this when you do define TEMPS_DESTROYED_QUICKLY. This
+// is a bug in MSC. Beware of "operator" statements for defining
+// conversions; particularly for converting from a Base class to a
+// Derived class.
+
+// You may get away with simply deleting this error message and Throw
+// statement if you can not find a better way of overcoming the
+// problem. In any case please tell me if you get this error message,
+// particularly for compilers apart from Microsoft C 7.0.
+
+
+      }
+   }
+}
+
+JumpItem* JumpBase::jl;              // will be set to zero
+jmp_buf JumpBase::env;
+bool Janitor::do_not_link;           // will be set to false
+
+
+int JanitorInitializer::ref_count;
+
+JanitorInitializer::JanitorInitializer()
+{
+   if (ref_count++ == 0) new JumpItem;
+                                    // need JumpItem at head of list
+}
+
+#endif                              // end of SimulateExceptions
+
+Tracer* Tracer::last;               // will be set to zero
+
+
+void Terminate()
+{
+   cout << "\n\nThere has been an exception with no handler - exiting";
+   const char* what = BaseException::what();
+   if (what) cout << what << "\n";
+   exit(1);
+}
+
+
+
+#ifdef DO_FREE_CHECK
+// Routines for tracing whether new and delete calls are balanced
+
+FreeCheckLink::FreeCheckLink() : next(FreeCheck::next)
+   { FreeCheck::next = this; }
+
+FCLClass::FCLClass(void* t, char* name) : ClassName(name) { ClassStore=t; }
+
+FCLRealArray::FCLRealArray(void* t, char* o, int s)
+  : Operation(o), size(s) { ClassStore=t; }
+
+FCLIntArray::FCLIntArray(void* t, char* o, int s)
+  : Operation(o), size(s) { ClassStore=t; }
+
+FreeCheckLink* FreeCheck::next;
+int FreeCheck::BadDelete;
+
+void FCLClass::Report()
+{ cout << "   " << ClassName << "   " << (unsigned long)ClassStore << "\n"; }
+
+void FCLRealArray::Report()
+{
+   cout << "   " << Operation << "   " << (unsigned long)ClassStore <<
+      "   " << size << "\n";
+}
+
+void FCLIntArray::Report()
+{
+   cout << "   " << Operation << "   " << (unsigned long)ClassStore <<
+      "   " << size << "\n";
+}
+
+void FreeCheck::Register(void* t, char* name)
+{
+   FCLClass* f = new FCLClass(t,name);
+   if (!f) { cout << "Out of memory in FreeCheck\n"; exit(1); }
+#ifdef REG_DEREG
+   cout << "Registering   " << name << "   " << (unsigned long)t << "\n";
+#endif
+}
+
+void FreeCheck::RegisterR(void* t, char* o, int s)
+{
+   FCLRealArray* f = new FCLRealArray(t,o,s);
+   if (!f) { cout << "Out of memory in FreeCheck\n"; exit(1); }
+#ifdef REG_DEREG
+   cout << o << "   " << s << "   " << (unsigned long)t << "\n";
+#endif
+}
+
+void FreeCheck::RegisterI(void* t, char* o, int s)
+{
+   FCLIntArray* f = new FCLIntArray(t,o,s);
+   if (!f) { cout << "Out of memory in FreeCheck\n"; exit(1); }
+#ifdef REG_DEREG
+   cout << o << "   " << s << "   " << (unsigned long)t << "\n";
+#endif
+}
+
+void FreeCheck::DeRegister(void* t, char* name)
+{
+   FreeCheckLink* last = 0;
+#ifdef REG_DEREG
+   cout << "Deregistering " << name << "   " << (unsigned long)t << "\n";
+#endif
+   for (FreeCheckLink* fcl = next; fcl; fcl = fcl->next)
+   {
+      if (fcl->ClassStore==t)
+      {
+	 if (last) last->next = fcl->next; else next = fcl->next;
+	 delete fcl; return;
+      }
+      last = fcl;
+   }
+   cout << "\nRequest to delete non-existent object of class and location:\n";
+   cout << "   " << name << "   " << (unsigned long)t << "\n";
+   BadDelete++;
+   Tracer::PrintTrace();
+   cout << "\n";
+}
+
+void FreeCheck::DeRegisterR(void* t, char* o, int s)
+{
+   FreeCheckLink* last = 0;
+#ifdef REG_DEREG
+   cout << o << "   " << s << "   " << (unsigned long)t << "\n";
+#endif
+   for (FreeCheckLink* fcl = next; fcl; fcl = fcl->next)
+   {
+      if (fcl->ClassStore==t)
+      {
+	 if (last) last->next = fcl->next; else next = fcl->next;
+	 if (s >= 0 && ((FCLRealArray*)fcl)->size != s)
+	 {
+	    cout << "\nArray sizes do not agree:\n";
+	    cout << "   " << o << "   " << (unsigned long)t
+	       << "   " << ((FCLRealArray*)fcl)->size << "   " << s << "\n";
+	    Tracer::PrintTrace();
+	    cout << "\n";
+	 }
+	 delete fcl; return;
+      }
+      last = fcl;
+   }
+   cout << "\nRequest to delete non-existent real array:\n";
+   cout << "   " << o << "   " << (unsigned long)t << "   " << s << "\n";
+   BadDelete++;
+   Tracer::PrintTrace();
+   cout << "\n";
+}
+
+void FreeCheck::DeRegisterI(void* t, char* o, int s)
+{
+   FreeCheckLink* last = 0;
+#ifdef REG_DEREG
+   cout << o << "   " << s << "   " << (unsigned long)t << "\n";
+#endif
+   for (FreeCheckLink* fcl = next; fcl; fcl = fcl->next)
+   {
+      if (fcl->ClassStore==t)
+      {
+	 if (last) last->next = fcl->next; else next = fcl->next;
+	 if (s >= 0 && ((FCLIntArray*)fcl)->size != s)
+	 {
+	    cout << "\nArray sizes do not agree:\n";
+	    cout << "   " << o << "   " << (unsigned long)t
+	       << "   " << ((FCLIntArray*)fcl)->size << "   " << s << "\n";
+	    Tracer::PrintTrace();
+	    cout << "\n";
+	 }
+	 delete fcl; return;
+      }
+      last = fcl;
+   }
+   cout << "\nRequest to delete non-existent int array:\n";
+   cout << "   " << o << "   " << (unsigned long)t << "   " << s << "\n";
+   BadDelete++;
+   Tracer::PrintTrace();
+   cout << "\n";
+}
+
+void FreeCheck::Status()
+{
+   if (next)
+   {
+      cout << "\nObjects of the following classes remain undeleted:\n";
+      for (FreeCheckLink* fcl = next; fcl; fcl = fcl->next) fcl->Report();
+      cout << "\n";
+   }
+   else cout << "\nNo objects remain undeleted\n\n";
+   if (BadDelete)
+   {
+      cout << "\nThere were " << BadDelete << 
+         " requests to delete non-existent items\n\n";
+   }
+}
+
+#endif                            // end of DO_FREE_CHECK
+
+// derived exception bodies
+
+Logic_error::Logic_error(const char* a_what) : BaseException()
+{
+   Select = BaseException::Select;
+   AddMessage("Logic error:- "); AddMessage(a_what);
+   if (a_what) Tracer::AddTrace();
+}
+
+Runtime_error::Runtime_error(const char* a_what)
+   : BaseException()
+{
+   Select = BaseException::Select;
+   AddMessage("Runtime error:- "); AddMessage(a_what);
+   if (a_what) Tracer::AddTrace();
+}
+
+Domain_error::Domain_error(const char* a_what) : Logic_error()
+{
+   Select = BaseException::Select;
+   AddMessage("domain error\n"); AddMessage(a_what);
+   if (a_what) Tracer::AddTrace();
+}
+
+Invalid_argument::Invalid_argument(const char* a_what) : Logic_error()
+{
+   Select = BaseException::Select;
+   AddMessage("invalid argument\n"); AddMessage(a_what);
+   if (a_what) Tracer::AddTrace();
+}
+
+Length_error::Length_error(const char* a_what) : Logic_error()
+{
+   Select = BaseException::Select;
+   AddMessage("length error\n"); AddMessage(a_what);
+   if (a_what) Tracer::AddTrace();
+}
+
+Out_of_range::Out_of_range(const char* a_what) : Logic_error()
+{
+   Select = BaseException::Select;
+   AddMessage("out of range\n"); AddMessage(a_what);
+   if (a_what) Tracer::AddTrace();
+}
+
+//Bad_cast::Bad_cast(const char* a_what) : Logic_error()
+//{
+//   Select = BaseException::Select;
+//   AddMessage("bad cast\n"); AddMessage(a_what);
+//   if (a_what) Tracer::AddTrace();
+//}
+
+//Bad_typeid::Bad_typeid(const char* a_what) : Logic_error()
+//{
+//   Select = BaseException::Select;
+//   AddMessage("bad type id.\n"); AddMessage(a_what);
+//   if (a_what) Tracer::AddTrace();
+//}
+
+Range_error::Range_error(const char* a_what) : Runtime_error()
+{
+   Select = BaseException::Select;
+   AddMessage("range error\n"); AddMessage(a_what);
+   if (a_what) Tracer::AddTrace();
+}
+
+Overflow_error::Overflow_error(const char* a_what) : Runtime_error()
+{
+   Select = BaseException::Select;
+   AddMessage("overflow error\n"); AddMessage(a_what);
+   if (a_what) Tracer::AddTrace();
+}
+
+Bad_alloc::Bad_alloc(const char* a_what) : BaseException()
+{
+   Select = BaseException::Select;
+   AddMessage("bad allocation\n"); AddMessage(a_what);
+   if (a_what) Tracer::AddTrace();
+}
+
+
+
+
+unsigned long Logic_error::Select;
+unsigned long Runtime_error::Select;
+unsigned long Domain_error::Select;
+unsigned long Invalid_argument::Select;
+unsigned long Length_error::Select;
+unsigned long Out_of_range::Select;
+//unsigned long Bad_cast::Select;
+//unsigned long Bad_typeid::Select;
+unsigned long Range_error::Select;
+unsigned long Overflow_error::Select;
+unsigned long Bad_alloc::Select;
+
+#ifdef use_namespace
+}
+#endif
+
+
+///@}
+
Index: /nanovis/tags/1.1.4/newmat11/myexcept.h
===================================================================
--- /nanovis/tags/1.1.4/newmat11/myexcept.h	(revision 4930)
+++ /nanovis/tags/1.1.4/newmat11/myexcept.h	(revision 4930)
@@ -0,0 +1,446 @@
+/// \ingroup rbd_common
+///@{
+
+/// \file myexcept.h
+/// Exception handler.
+/// The low level classes for
+/// - my exception class hierarchy
+/// - the functions needed for my simulated exceptions
+/// - the Tracer mechanism
+/// - routines for checking whether new and delete calls are balanced
+///
+
+
+// A set of classes to simulate exceptions in C++
+//
+//   Partially copied from Carlos Vidal s article in the C users  journal
+//   September 1992, pp 19-28
+//
+//   Operations defined
+//      Try {     }
+//      Throw ( exception object )
+//      ReThrow
+//      Catch ( exception class ) {      }
+//      CatchAll {      }
+//      CatchAndThrow
+//
+//   All catch lists must end with a CatchAll or CatchAndThrow statement
+//   but not both.
+//
+//   When exceptions are finally implemented replace Try, Throw(E), Rethrow,
+//   Catch, CatchAll, CatchAndThrow by try, throw E, throw, catch,
+//   catch(...), and {}.
+//
+//   All exception classes must be derived from BaseException, have no
+//   non-static variables and must include the statement
+//
+//      static unsigned long Select;
+//
+//   Any constructor in one of these exception classes must include
+//
+//      Select = BaseException::Select;
+//
+//   For each exceptions class, EX_1, some .cpp file must include
+//
+//      unsigned long EX_1::Select;
+//
+
+
+#ifndef EXCEPTION_LIB
+#define EXCEPTION_LIB
+
+#include "include.h"
+
+#ifdef use_namespace
+namespace RBD_COMMON {
+#endif
+
+
+void Terminate();
+
+
+//********** classes for setting up exceptions and reporting ************//
+
+class BaseException;
+
+class Tracer                             // linked list showing how
+{                                        // we got here
+   const char* entry;
+   Tracer* previous;
+public:
+   Tracer(const char*);
+   ~Tracer();
+   void ReName(const char*);
+   static void PrintTrace();             // for printing trace
+   static void AddTrace();               // insert trace in exception record
+   static Tracer* last;                  // points to Tracer list
+   friend class BaseException;
+};
+
+
+class BaseException                          // The base exception class
+{
+protected:
+   static char* what_error;              // error message
+   static int SoFar;                     // no. characters already entered
+   static int LastOne;                   // last location in error buffer
+public:
+   static void AddMessage(const char* a_what);
+                                         // messages about exception
+   static void AddInt(int value);        // integer to error message
+   static unsigned long Select;          // for identifying exception
+   BaseException(const char* a_what = 0);
+   static const char* what() { return what_error; }
+                                         // for getting error message
+};
+
+#ifdef TypeDefException
+typedef BaseException Exception;        // for compatibility with my older libraries
+#endif
+
+inline Tracer::Tracer(const char* e)
+   : entry(e), previous(last) { last = this; }
+
+inline Tracer::~Tracer() { last = previous; }
+
+inline void Tracer::ReName(const char* e) { entry=e; }
+
+#ifdef SimulateExceptions                // SimulateExceptions
+
+#include <setjmp.h>
+
+
+//************* the definitions of Try, Throw and Catch *****************//
+
+
+class JumpItem;
+class Janitor;
+
+class JumpBase         // pointer to a linked list of jmp_buf s
+{
+public:
+   static JumpItem *jl;
+   static jmp_buf env;
+};
+
+class JumpItem         // an item in a linked list of jmp_buf s
+{
+public:
+   JumpItem *ji;
+   jmp_buf env;
+   Tracer* trace;                     // to keep check on Tracer items
+   Janitor* janitor;                  // list of items for cleanup
+   JumpItem() : ji(JumpBase::jl), trace(0), janitor(0)
+      { JumpBase::jl = this; }
+   ~JumpItem() { JumpBase::jl = ji; }
+};
+
+void Throw();
+
+inline void Throw(const BaseException&) { Throw(); }
+
+#define Try                                             \
+   if (!setjmp( JumpBase::jl->env )) {                  \
+   JumpBase::jl->trace = Tracer::last;               \
+   JumpItem JI387256156;
+
+#define ReThrow Throw()
+
+#define Catch(EXCEPTION)                                \
+   } else if (BaseException::Select == EXCEPTION::Select) {
+
+#define CatchAll } else
+
+#define CatchAndThrow  } else Throw();
+
+
+//****************** cleanup heap following Throw ***********************//
+
+class Janitor
+{
+protected:
+   static bool do_not_link;                  // set when new is called
+   bool OnStack;                             // false if created by new
+public:
+   Janitor* NextJanitor;
+   virtual void CleanUp() {}
+   Janitor();
+   virtual ~Janitor();
+};
+
+
+// The tiresome old trick for initializing the Janitor class
+// this is needed for classes derived from Janitor which have objects
+// declared globally
+
+class JanitorInitializer
+{
+public:
+   JanitorInitializer();
+private:
+   static int ref_count;
+};
+
+static JanitorInitializer JanInit;
+
+#endif                                // end of SimulateExceptions
+
+#ifdef UseExceptions
+
+#define Try try
+#define Throw(E) throw E
+#define ReThrow throw
+#define Catch catch
+#define CatchAll catch(...)
+#define CatchAndThrow {}
+
+#endif                                // end of UseExceptions
+
+
+#ifdef DisableExceptions              // Disable exceptions
+
+#define Try {
+#define ReThrow Throw()
+#define Catch(EXCEPTION) } if (false) {
+#define CatchAll } if (false)
+#define CatchAndThrow }
+
+inline void Throw() { Terminate(); }
+inline void Throw(const BaseException&) { Terminate(); }
+
+
+#endif                                // end of DisableExceptions
+
+#ifndef SimulateExceptions            // ! SimulateExceptions
+
+class Janitor                         // a dummy version
+{
+public:
+   virtual void CleanUp() {}
+   Janitor() {}
+   virtual ~Janitor() {}
+};
+
+#endif                                // end of ! SimulateExceptions
+
+
+//******************** FREE_CHECK and NEW_DELETE ***********************//
+
+#ifdef DO_FREE_CHECK                          // DO_FREE_CHECK
+// Routines for tracing whether new and delete calls are balanced
+
+class FreeCheck;
+
+class FreeCheckLink
+{
+protected:
+   FreeCheckLink* next;
+   void* ClassStore;
+   FreeCheckLink();
+   virtual void Report()=0;                   // print details of link
+   friend class FreeCheck;
+};
+
+class FCLClass : public FreeCheckLink         // for registering objects
+{
+   char* ClassName;
+   FCLClass(void* t, char* name);
+   void Report();
+   friend class FreeCheck;
+};
+
+class FCLRealArray : public FreeCheckLink     // for registering real arrays
+{
+   char* Operation;
+   int size;
+   FCLRealArray(void* t, char* o, int s);
+   void Report();
+   friend class FreeCheck;
+};
+
+class FCLIntArray : public FreeCheckLink     // for registering int arrays
+{
+   char* Operation;
+   int size;
+   FCLIntArray(void* t, char* o, int s);
+   void Report();
+   friend class FreeCheck;
+};
+
+
+class FreeCheck
+{
+   static FreeCheckLink* next;
+   static int BadDelete;
+public:
+   static void Register(void*, char*);
+   static void DeRegister(void*, char*);
+   static void RegisterR(void*, char*, int);
+   static void DeRegisterR(void*, char*, int);
+   static void RegisterI(void*, char*, int);
+   static void DeRegisterI(void*, char*, int);
+   static void Status();
+   friend class FreeCheckLink;
+   friend class FCLClass;
+   friend class FCLRealArray;
+   friend class FCLIntArray;
+};
+
+#define FREE_CHECK(Class)                                                  \
+public:                                                                    \
+   void* operator new(size_t size)                                         \
+   {                                                                       \
+      void* t = ::operator new(size); FreeCheck::Register(t,#Class);       \
+      return t;                                                            \
+   }                                                                       \
+   void operator delete(void* t)                                           \
+   { FreeCheck::DeRegister(t,#Class); ::operator delete(t); }
+
+
+#ifdef SimulateExceptions         // SimulateExceptions
+
+#define NEW_DELETE(Class)                                                  \
+public:                                                                    \
+   void* operator new(size_t size)                                         \
+   {                                                                       \
+      do_not_link=true;                                                    \
+      void* t = ::operator new(size); FreeCheck::Register(t,#Class);       \
+      return t;                                                            \
+   }                                                                       \
+   void operator delete(void* t)                                           \
+   { FreeCheck::DeRegister(t,#Class); ::operator delete(t); }
+
+
+#endif                           // end of SimulateExceptions
+
+
+#define MONITOR_REAL_NEW(Operation, Size, Pointer)                         \
+	FreeCheck::RegisterR(Pointer, Operation, Size);
+#define MONITOR_INT_NEW(Operation, Size, Pointer)                          \
+	FreeCheck::RegisterI(Pointer, Operation, Size);
+#define MONITOR_REAL_DELETE(Operation, Size, Pointer)                      \
+	FreeCheck::DeRegisterR(Pointer, Operation, Size);
+#define MONITOR_INT_DELETE(Operation, Size, Pointer)                       \
+	FreeCheck::DeRegisterI(Pointer, Operation, Size);
+
+#else                            // DO_FREE_CHECK not defined
+
+#define FREE_CHECK(Class) public:
+#define MONITOR_REAL_NEW(Operation, Size, Pointer) {}
+#define MONITOR_INT_NEW(Operation, Size, Pointer) {}
+#define MONITOR_REAL_DELETE(Operation, Size, Pointer) {}
+#define MONITOR_INT_DELETE(Operation, Size, Pointer) {}
+
+
+#ifdef SimulateExceptions         // SimulateExceptions
+
+
+#define NEW_DELETE(Class)                                                  \
+public:                                                                    \
+	void* operator new(size_t size)                                    \
+	{ do_not_link=true; void* t = ::operator new(size); return t; }    \
+	void operator delete(void* t) { ::operator delete(t); }
+
+#endif                            // end of SimulateExceptions
+
+#endif                            // end of ! DO_FREE_CHECK
+
+#ifndef SimulateExceptions        // ! SimulateExceptions
+
+#define NEW_DELETE(Class) FREE_CHECK(Class)
+
+#endif                            // end of ! SimulateExceptions
+
+
+//********************* derived exceptions ******************************//
+
+class Logic_error : public BaseException
+{
+public:
+   static unsigned long Select;
+   Logic_error(const char* a_what = 0);
+};
+
+class Runtime_error : public BaseException
+{
+public:
+   static unsigned long Select;
+   Runtime_error(const char* a_what = 0);
+};
+
+class Domain_error : public Logic_error
+{
+public:
+   static unsigned long Select;
+   Domain_error(const char* a_what = 0);
+};
+
+class Invalid_argument : public Logic_error
+{
+public:
+   static unsigned long Select;
+   Invalid_argument(const char* a_what = 0);
+};
+
+class Length_error : public Logic_error
+{
+public:
+   static unsigned long Select;
+   Length_error(const char* a_what = 0);
+};
+
+class Out_of_range : public Logic_error
+{
+public:
+   static unsigned long Select;
+   Out_of_range(const char* a_what = 0);
+};
+
+//class Bad_cast : public Logic_error
+//{
+//public:
+//   static unsigned long Select;
+//   Bad_cast(const char* a_what = 0);
+//};
+
+//class Bad_typeid : public Logic_error
+//{
+//public:
+//   static unsigned long Select;
+//   Bad_typeid(const char* a_what = 0);
+//};
+
+class Range_error : public Runtime_error
+{
+public:
+   static unsigned long Select;
+   Range_error(const char* a_what = 0);
+};
+
+class Overflow_error : public Runtime_error
+{
+public:
+   static unsigned long Select;
+   Overflow_error(const char* a_what = 0);
+};
+
+class Bad_alloc : public BaseException
+{
+public:
+   static unsigned long Select;
+   Bad_alloc(const char* a_what = 0);
+};
+
+#ifdef use_namespace
+}
+#endif
+
+
+#endif                            // end of EXCEPTION_LIB
+
+
+// body file: myexcept.cpp
+
+
+///@}
+
Index: /nanovis/tags/1.1.4/newmat11/newfft.cpp
===================================================================
--- /nanovis/tags/1.1.4/newmat11/newfft.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/newmat11/newfft.cpp	(revision 4930)
@@ -0,0 +1,1065 @@
+/// \ingroup newmat
+///@{
+
+/// \file newfft.cpp
+/// Fast Fourier transform using Sande and Gentleman method.
+
+
+// This is originally by Sande and Gentleman in 1967! I have translated from
+// Fortran into C and a little bit of C++.
+
+// It takes about twice as long as fftw
+// (http://theory.lcs.mit.edu/~fftw/homepage.html)
+// but is much shorter than fftw  and so despite its age
+// might represent a reasonable
+// compromise between speed and complexity.
+// If you really need the speed get fftw.
+
+
+//    THIS SUBROUTINE WAS WRITTEN BY G.SANDE OF PRINCETON UNIVERSITY AND
+//    W.M.GENTLMAN OF THE BELL TELEPHONE LAB.  IT WAS BROUGHT TO LONDON
+//    BY DR. M.D. GODFREY AT THE IMPERIAL COLLEGE AND WAS ADAPTED FOR
+//    BURROUGHS 6700 BY D. R. BRILLINGER AND J. PEMBERTON
+//    IT REPRESENTS THE STATE OF THE ART OF COMPUTING COMPLETE FINITE
+//    DISCRETE FOURIER TRANSFORMS AS OF NOV.1967.
+//    OTHER PROGRAMS REQUIRED.
+//                                 ONLY THOSE SUBROUTINES INCLUDED HERE.
+//                      USAGE.
+//       CALL AR1DFT(N,X,Y)
+//            WHERE  N IS THE NUMBER OF POINTS IN THE SEQUENCE .
+//                   X - IS A ONE-DIMENSIONAL ARRAY CONTAINING THE REAL
+//                       PART OF THE SEQUENCE.
+//                   Y - IS A ONE-DIMENSIONAL ARRAY CONTAINING THE
+//                       IMAGINARY PART OF THE SEQUENCE.
+//    THE TRANSFORM IS RETURNED IN X AND Y.
+//            METHOD
+//               FOR A GENERAL DISCUSSION OF THESE TRANSFORMS AND OF
+//    THE FAST METHOD FOR COMPUTING THEM, SEE GENTLEMAN AND SANDE,
+//    @FAST FOURIER TRANSFORMS - FOR FUN AND PROFIT,@ 1966 FALL JOINT
+//    COMPUTER CONFERENCE.
+//    THIS PROGRAM COMPUTES THIS FOR A COMPLEX SEQUENCE Z(T) OF LENGTH
+//    N WHOSE ELEMENTS ARE STORED AT(X(I) , Y(I)) AND RETURNS THE
+//    TRANSFORM COEFFICIENTS AT (X(I), Y(I)).
+//        DESCRIPTION
+//    AR1DFT IS A HIGHLY MODULAR ROUTINE CAPABLE OF COMPUTING IN PLACE
+//    THE COMPLETE FINITE DISCRETE FOURIER TRANSFORM  OF A ONE-
+//    DIMENSIONAL SEQUENCE OF RATHER GENERAL LENGTH N.
+//       THE MAIN ROUTINE , AR1DFT ITSELF, FACTORS N. IT THEN CALLS ON
+//    ON GR 1D FT TO COMPUTE THE ACTUAL TRANSFORMS, USING THESE FACTORS.
+//    THIS GR 1D FT DOES, CALLING AT EACH STAGE ON THE APPROPRIATE KERN
+//    EL R2FTK, R4FTK, R8FTK, R16FTK, R3FTK, R5FTK, OR RPFTK TO PERFORM
+//    THE COMPUTATIONS FOR THIS PASS OVER THE SEQUENCE, DEPENDING ON
+//    WHETHER THE CORRESPONDING FACTOR IS 2, 4, 8, 16, 3, 5, OR SOME
+//    MORE GENERAL PRIME P. WHEN GR1DFT IS FINISHED THE TRANSFORM IS
+//    COMPUTED, HOWEVER, THE RESULTS ARE STORED IN "DIGITS REVERSED"
+//    ORDER. AR1DFT THEREFORE, CALLS UPON GR 1S FS TO SORT THEM OUT.
+//    TO RETURN TO THE FACTORIZATION, SINGLETON HAS POINTED OUT THAT
+//    THE TRANSFORMS ARE MORE EFFICIENT IF THE SAMPLE SIZE N, IS OF THE
+//    FORM B*A**2 AND B CONSISTS OF A SINGLE FACTOR.  IN SUCH A CASE
+//    IF WE PROCESS THE FACTORS IN THE ORDER ABA  THEN
+//    THE REORDERING CAN BE DONE AS FAST IN PLACE, AS WITH SCRATCH
+//    STORAGE.  BUT AS B BECOMES MORE COMPLICATED, THE COST OF THE DIGIT
+//    REVERSING DUE TO B PART BECOMES VERY EXPENSIVE IF WE TRY TO DO IT
+//    IN PLACE.  IN SUCH A CASE IT MIGHT BE BETTER TO USE EXTRA STORAGE
+//    A ROUTINE TO DO THIS IS, HOWEVER, NOT INCLUDED HERE.
+//    ANOTHER FEATURE INFLUENCING THE FACTORIZATION IS THAT FOR ANY FIXED
+//    FACTOR N WE CAN PREPARE A SPECIAL KERNEL WHICH WILL COMPUTE
+//    THAT STAGE OF THE TRANSFORM MORE EFFICIENTLY THAN WOULD A KERNEL
+//    FOR GENERAL FACTORS, ESPECIALLY IF THE GENERAL KERNEL HAD TO BE
+//    APPLIED SEVERAL TIMES. FOR EXAMPLE, FACTORS OF 4 ARE MORE
+//    EFFICIENT THAN FACTORS OF 2, FACTORS OF 8 MORE EFFICIENT THAN 4,ETC
+//    ON THE OTHER HAND DIMINISHING RETURNS RAPIDLY SET IN, ESPECIALLY
+//    SINCE THE LENGTH OF THE KERNEL FOR A SPECIAL CASE IS ROUGHLY
+//    PROPORTIONAL TO THE FACTOR IT DEALS WITH. HENCE THESE PROBABLY ARE
+//    ALL THE KERNELS WE WISH TO HAVE.
+//            RESTRICTIONS.
+//    AN UNFORTUNATE FEATURE OF THE SORTING PROBLEM IS THAT THE MOST
+//    EFFICIENT WAY TO DO IT IS WITH NESTED DO LOOPS, ONE FOR EACH
+//    FACTOR. THIS PUTS A RESTRICTION ON N AS TO HOW MANY FACTORS IT
+//    CAN HAVE.  CURRENTLY THE LIMIT IS 16, BUT THE LIMIT CAN BE READILY
+//    RAISED IF NECESSARY.
+//    A SECOND RESTRICTION OF THE PROGRAM IS THAT LOCAL STORAGE OF THE
+//    THE ORDER P**2 IS REQUIRED BY THE GENERAL KERNEL RPFTK, SO SOME
+//    LIMIT MUST BE SET ON P.  CURRENTLY THIS IS 19, BUT IT CAN BE INCRE
+//    INCREASED BY TRIVIAL CHANGES.
+//       OTHER COMMENTS.
+//(1) THE ROUTINE IS ADAPTED TO CHECK WHETHER A GIVEN N WILL MEET THE
+//    ABOVE FACTORING REQUIREMENTS AN, IF NOT, TO RETURN THE NEXT HIGHER
+//    NUMBER, NX, SAY, WHICH WILL MEET THESE REQUIREMENTS.
+//    THIS CAN BE ACCHIEVED BY   A STATEMENT OF THE FORM
+//            CALL FACTR(N,X,Y).
+//    IF A DIFFERENT N, SAY NX, IS RETURNED THEN THE TRANSFORMS COULD BE
+//    OBTAINED BY EXTENDING THE SIZE OF THE X-ARRAY AND Y-ARRAY TO NX,
+//    AND SETTING X(I) = Y(I) = 0., FOR I = N+1, NX.
+//(2) IF THE SEQUENCE Z IS ONLY A REAL SEQUENCE, THEN THE IMAGINARY PART
+//    Y(I)=0., THIS WILL RETURN THE COSINE TRANSFORM OF THE REAL SEQUENCE
+//    IN X, AND THE SINE TRANSFORM IN Y.
+
+
+#define WANT_STREAM
+
+#define WANT_MATH
+
+#include "newmatap.h"
+
+#ifdef use_namespace
+namespace NEWMAT {
+#endif
+
+#ifdef DO_REPORT
+#define REPORT { static ExeCounter ExeCount(__LINE__,20); ++ExeCount; }
+#else
+#define REPORT {}
+#endif
+
+inline Real square(Real x) { return x*x; }
+inline int square(int x) { return x*x; }
+
+static void GR_1D_FS (int PTS, int N_SYM, int N_UN_SYM,
+   const SimpleIntArray& SYM, int P_SYM, const SimpleIntArray& UN_SYM,
+   Real* X, Real* Y);
+static void GR_1D_FT (int N, int N_FACTOR, const SimpleIntArray& FACTOR,
+   Real* X, Real* Y);
+static void R_P_FTK (int N, int M, int P, Real* X, Real* Y);
+static void R_2_FTK (int N, int M, Real* X0, Real* Y0, Real* X1, Real* Y1);
+static void R_3_FTK (int N, int M, Real* X0, Real* Y0, Real* X1, Real* Y1,
+   Real* X2, Real* Y2);
+static void R_4_FTK (int N, int M,
+   Real* X0, Real* Y0, Real* X1, Real* Y1,
+   Real* X2, Real* Y2, Real* X3, Real* Y3);
+static void R_5_FTK (int N, int M,
+   Real* X0, Real* Y0, Real* X1, Real* Y1, Real* X2, Real* Y2,
+   Real* X3, Real* Y3, Real* X4, Real* Y4);
+static void R_8_FTK (int N, int M,
+   Real* X0, Real* Y0, Real* X1, Real* Y1,
+   Real* X2, Real* Y2, Real* X3, Real* Y3,
+   Real* X4, Real* Y4, Real* X5, Real* Y5,
+   Real* X6, Real* Y6, Real* X7, Real* Y7);
+static void R_16_FTK (int N, int M,
+   Real* X0, Real* Y0, Real* X1, Real* Y1,
+   Real* X2, Real* Y2, Real* X3, Real* Y3,
+   Real* X4, Real* Y4, Real* X5, Real* Y5,
+   Real* X6, Real* Y6, Real* X7, Real* Y7,
+   Real* X8, Real* Y8, Real* X9, Real* Y9,
+   Real* X10, Real* Y10, Real* X11, Real* Y11,
+   Real* X12, Real* Y12, Real* X13, Real* Y13,
+   Real* X14, Real* Y14, Real* X15, Real* Y15);
+static int BitReverse(int x, int prod, int n, const SimpleIntArray& f);
+
+
+bool FFT_Controller::ar_1d_ft (int PTS, Real* X, Real *Y)
+{
+//    ARBITRARY RADIX ONE DIMENSIONAL FOURIER TRANSFORM
+
+   REPORT
+
+   int  F,J,N,NF,P,PMAX,P_SYM,P_TWO,Q,R,TWO_GRP;
+
+   // NP is maximum number of squared factors allows PTS up to 2**32 at least
+   // NQ is number of not-squared factors - increase if we increase PMAX
+   const int NP = 16, NQ = 10;
+   SimpleIntArray PP(NP), QQ(NQ);
+
+   TWO_GRP=16; PMAX=19;
+
+   // PMAX is the maximum factor size
+   // TWO_GRP is the maximum power of 2 handled as a single factor
+   // Doesn't take advantage of combining powers of 2 when calculating
+   // number of factors
+
+   if (PTS<=1) return true;
+   N=PTS; P_SYM=1; F=2; P=0; Q=0;
+
+   // P counts the number of squared factors
+   // Q counts the number of the rest
+   // R = 0 for no non-squared factors; 1 otherwise
+
+   // FACTOR holds all the factors - non-squared ones in the middle
+   //   - length is 2*P+Q
+   // SYM also holds all the factors but with the non-squared ones
+   //   multiplied together - length is 2*P+R
+   // PP holds the values of the squared factors - length is P
+   // QQ holds the values of the rest - length is Q
+
+   // P_SYM holds the product of the squared factors
+
+   // find the factors - load into PP and QQ
+   while (N > 1)
+   {
+      bool fail = true;
+      for (J=F; J<=PMAX; J++)
+         if (N % J == 0) { fail = false; F=J; break; }
+      if (fail || P >= NP || Q >= NQ) return false; // can't factor
+      N /= F;
+      if (N % F != 0) QQ[Q++] = F;
+      else { N /= F; PP[P++] = F; P_SYM *= F; }
+   }
+
+   R = (Q == 0) ? 0 : 1;  // R = 0 if no not-squared factors, 1 otherwise
+
+   NF = 2*P + Q;
+   SimpleIntArray FACTOR(NF + 1), SYM(2*P + R);
+   FACTOR[NF] = 0;                // we need this in the "combine powers of 2"
+
+   // load into SYM and FACTOR
+   for (J=0; J<P; J++)
+      { SYM[J]=FACTOR[J]=PP[P-1-J]; FACTOR[P+Q+J]=SYM[P+R+J]=PP[J]; }
+
+   if (Q>0)
+   {
+      REPORT
+      for (J=0; J<Q; J++) FACTOR[P+J]=QQ[J];
+      SYM[P]=PTS/square(P_SYM);
+   }
+
+   // combine powers of 2
+   P_TWO = 1;
+   for (J=0; J < NF; J++)
+   {
+      if (FACTOR[J]!=2) continue;
+      P_TWO=P_TWO*2; FACTOR[J]=1;
+      if (P_TWO<TWO_GRP && FACTOR[J+1]==2) continue;
+      FACTOR[J]=P_TWO; P_TWO=1;
+   }
+
+   if (P==0) R=0;
+   if (Q<=1) Q=0;
+
+   // do the analysis
+   GR_1D_FT(PTS,NF,FACTOR,X,Y);                 // the transform
+   GR_1D_FS(PTS,2*P+R,Q,SYM,P_SYM,QQ,X,Y);      // the reshuffling
+
+   return true;
+
+}
+
+static void GR_1D_FS (int PTS, int N_SYM, int N_UN_SYM,
+   const SimpleIntArray& SYM, int P_SYM, const SimpleIntArray& UN_SYM,
+   Real* X, Real* Y)
+{
+//    GENERAL RADIX ONE DIMENSIONAL FOURIER SORT
+
+// PTS = number of points
+// N_SYM = length of SYM
+// N_UN_SYM = length of UN_SYM
+// SYM: squared factors + product of non-squared factors + squared factors
+// P_SYM = product of squared factors (each included only once)
+// UN_SYM: not-squared factors
+
+   REPORT
+
+   Real T;
+   int  JJ,KK,P_UN_SYM;
+
+   // I have replaced the multiple for-loop used by Sande-Gentleman code
+   // by the following code which does not limit the number of factors
+
+   if (N_SYM > 0)
+   {
+      REPORT
+      SimpleIntArray U(N_SYM);
+      for(MultiRadixCounter MRC(N_SYM, SYM, U); !MRC.Finish(); ++MRC)
+      {
+         if (MRC.Swap())
+         {
+            int P = MRC.Reverse(); int JJ = MRC.Counter(); Real T;
+            T=X[JJ]; X[JJ]=X[P]; X[P]=T; T=Y[JJ]; Y[JJ]=Y[P]; Y[P]=T;
+         }
+      }
+   }
+
+   int J,JL,K,L,M,MS;
+
+   // UN_SYM contains the non-squared factors
+   // I have replaced the Sande-Gentleman code as it runs into
+   // integer overflow problems
+   // My code (and theirs) would be improved by using a bit array
+   // as suggested by Van Loan
+
+   if (N_UN_SYM==0) { REPORT return; }
+   P_UN_SYM=PTS/square(P_SYM); JL=(P_UN_SYM-3)*P_SYM; MS=P_UN_SYM*P_SYM;
+
+   for (J = P_SYM; J<=JL; J+=P_SYM)
+   {
+      K=J;
+      do K = P_SYM * BitReverse(K / P_SYM, P_UN_SYM, N_UN_SYM, UN_SYM);
+      while (K<J);
+
+      if (K!=J)
+      {
+         REPORT
+         for (L=0; L<P_SYM; L++) for (M=L; M<PTS; M+=MS)
+         {
+            JJ=M+J; KK=M+K;
+            T=X[JJ]; X[JJ]=X[KK]; X[KK]=T; T=Y[JJ]; Y[JJ]=Y[KK]; Y[KK]=T;
+         }
+      }
+   }
+
+   return;
+}
+
+static void GR_1D_FT (int N, int N_FACTOR, const SimpleIntArray& FACTOR,
+   Real* X, Real* Y)
+{
+//    GENERAL RADIX ONE DIMENSIONAL FOURIER TRANSFORM;
+
+   REPORT
+
+   int  M = N;
+
+   for (int i = 0; i < N_FACTOR; i++)
+   {
+      int P = FACTOR[i]; M /= P;
+
+      switch(P)
+      {
+      case 1: REPORT break;
+      case 2: REPORT R_2_FTK (N,M,X,Y,X+M,Y+M); break;
+      case 3: REPORT R_3_FTK (N,M,X,Y,X+M,Y+M,X+2*M,Y+2*M); break;
+      case 4: REPORT R_4_FTK (N,M,X,Y,X+M,Y+M,X+2*M,Y+2*M,X+3*M,Y+3*M); break;
+      case 5:
+         REPORT
+         R_5_FTK (N,M,X,Y,X+M,Y+M,X+2*M,Y+2*M,X+3*M,Y+3*M,X+4*M,Y+4*M);
+         break;
+      case 8:
+         REPORT
+         R_8_FTK (N,M,X,Y,X+M,Y+M,X+2*M,Y+2*M,
+            X+3*M,Y+3*M,X+4*M,Y+4*M,X+5*M,Y+5*M,
+            X+6*M,Y+6*M,X+7*M,Y+7*M);
+         break;
+      case 16:
+         REPORT
+         R_16_FTK (N,M,X,Y,X+M,Y+M,X+2*M,Y+2*M,
+            X+3*M,Y+3*M,X+4*M,Y+4*M,X+5*M,Y+5*M,
+            X+6*M,Y+6*M,X+7*M,Y+7*M,X+8*M,Y+8*M,
+            X+9*M,Y+9*M,X+10*M,Y+10*M,X+11*M,Y+11*M,
+            X+12*M,Y+12*M,X+13*M,Y+13*M,X+14*M,Y+14*M,
+            X+15*M,Y+15*M);
+         break;
+      default: REPORT R_P_FTK (N,M,P,X,Y); break;
+      }
+   }
+
+}
+
+static void R_P_FTK (int N, int M, int P, Real* X, Real* Y)
+//    RADIX PRIME FOURIER TRANSFORM KERNEL;
+// X and Y are treated as M * P matrices with Fortran storage
+{
+   REPORT
+   bool NO_FOLD,ZERO;
+   Real ANGLE,IS,IU,RS,RU,T,TWOPI,XT,YT;
+   int  J,JJ,K0,K,M_OVER_2,MP,PM,PP,U,V;
+
+   Real AA [9][9], BB [9][9];
+   Real A [18], B [18], C [18], S [18];
+   Real IA [9], IB [9], RA [9], RB [9];
+
+   TWOPI=8.0*atan(1.0);
+   M_OVER_2=M/2+1; MP=M*P; PP=P/2; PM=P-1;
+
+   for (U=0; U<PP; U++)
+   {
+      ANGLE=TWOPI*Real(U+1)/Real(P);
+      JJ=P-U-2;
+      A[U]=cos(ANGLE); B[U]=sin(ANGLE);
+      A[JJ]=A[U]; B[JJ]= -B[U];
+   }
+
+   for (U=1; U<=PP; U++)
+   {
+      for (V=1; V<=PP; V++)
+         { JJ=U*V-U*V/P*P; AA[V-1][U-1]=A[JJ-1]; BB[V-1][U-1]=B[JJ-1]; }
+   }
+
+   for (J=0; J<M_OVER_2; J++)
+   {
+      NO_FOLD = (J==0 || 2*J==M);
+      K0=J;
+      ANGLE=TWOPI*Real(J)/Real(MP); ZERO=ANGLE==0.0;
+      C[0]=cos(ANGLE); S[0]=sin(ANGLE);
+      for (U=1; U<PM; U++)
+      {
+         C[U]=C[U-1]*C[0]-S[U-1]*S[0];
+         S[U]=S[U-1]*C[0]+C[U-1]*S[0];
+      }
+      goto L700;
+   L500:
+      REPORT
+      if (NO_FOLD) { REPORT goto L1500; }
+      REPORT
+      NO_FOLD=true; K0=M-J;
+      for (U=0; U<PM; U++)
+         { T=C[U]*A[U]+S[U]*B[U]; S[U]= -S[U]*A[U]+C[U]*B[U]; C[U]=T; }
+   L700:
+      REPORT
+      for (K=K0; K<N; K+=MP)
+      {
+         XT=X[K]; YT=Y[K];
+         for (U=1; U<=PP; U++)
+         {
+            RA[U-1]=XT; IA[U-1]=YT;
+            RB[U-1]=0.0; IB[U-1]=0.0;
+         }
+         for (U=1; U<=PP; U++)
+         {
+            JJ=P-U;
+            RS=X[K+M*U]+X[K+M*JJ]; IS=Y[K+M*U]+Y[K+M*JJ];
+            RU=X[K+M*U]-X[K+M*JJ]; IU=Y[K+M*U]-Y[K+M*JJ];
+            XT=XT+RS; YT=YT+IS;
+            for (V=0; V<PP; V++)
+            {
+               RA[V]=RA[V]+RS*AA[V][U-1]; IA[V]=IA[V]+IS*AA[V][U-1];
+               RB[V]=RB[V]+RU*BB[V][U-1]; IB[V]=IB[V]+IU*BB[V][U-1];
+            }
+         }
+         X[K]=XT; Y[K]=YT;
+         for (U=1; U<=PP; U++)
+         {
+            if (!ZERO)
+            {
+               REPORT
+               XT=RA[U-1]+IB[U-1]; YT=IA[U-1]-RB[U-1];
+               X[K+M*U]=XT*C[U-1]+YT*S[U-1]; Y[K+M*U]=YT*C[U-1]-XT*S[U-1];
+               JJ=P-U;
+               XT=RA[U-1]-IB[U-1]; YT=IA[U-1]+RB[U-1];
+               X[K+M*JJ]=XT*C[JJ-1]+YT*S[JJ-1];
+               Y[K+M*JJ]=YT*C[JJ-1]-XT*S[JJ-1];
+            }
+            else
+            {
+               REPORT
+               X[K+M*U]=RA[U-1]+IB[U-1]; Y[K+M*U]=IA[U-1]-RB[U-1];
+               JJ=P-U;
+               X[K+M*JJ]=RA[U-1]-IB[U-1]; Y[K+M*JJ]=IA[U-1]+RB[U-1];
+            }
+         }
+      }
+      goto L500;
+L1500: ;
+   }
+   return;
+}
+
+static void R_2_FTK (int N, int M, Real* X0, Real* Y0, Real* X1, Real* Y1)
+//    RADIX TWO FOURIER TRANSFORM KERNEL;
+{
+   REPORT
+   bool NO_FOLD,ZERO;
+   int  J,K,K0,M2,M_OVER_2;
+   Real ANGLE,C,IS,IU,RS,RU,S,TWOPI;
+
+   M2=M*2; M_OVER_2=M/2+1;
+   TWOPI=8.0*atan(1.0);
+
+   for (J=0; J<M_OVER_2; J++)
+   {
+      NO_FOLD = (J==0 || 2*J==M);
+      K0=J;
+      ANGLE=TWOPI*Real(J)/Real(M2); ZERO=ANGLE==0.0;
+      C=cos(ANGLE); S=sin(ANGLE);
+      goto L200;
+   L100:
+      REPORT
+      if (NO_FOLD) { REPORT goto L600; }
+      REPORT
+      NO_FOLD=true; K0=M-J; C= -C;
+   L200:
+      REPORT
+      for (K=K0; K<N; K+=M2)
+      {
+         RS=X0[K]+X1[K]; IS=Y0[K]+Y1[K];
+         RU=X0[K]-X1[K]; IU=Y0[K]-Y1[K];
+         X0[K]=RS; Y0[K]=IS;
+         if (!ZERO) { X1[K]=RU*C+IU*S; Y1[K]=IU*C-RU*S; }
+         else { X1[K]=RU; Y1[K]=IU; }
+      }
+      goto L100;
+   L600: ;
+   }
+
+   return;
+}
+
+static void R_3_FTK (int N, int M, Real* X0, Real* Y0, Real* X1, Real* Y1,
+   Real* X2, Real* Y2)
+//    RADIX THREE FOURIER TRANSFORM KERNEL
+{
+   REPORT
+   bool NO_FOLD,ZERO;
+   int  J,K,K0,M3,M_OVER_2;
+   Real ANGLE,A,B,C1,C2,S1,S2,T,TWOPI;
+   Real I0,I1,I2,IA,IB,IS,R0,R1,R2,RA,RB,RS;
+
+   M3=M*3; M_OVER_2=M/2+1; TWOPI=8.0*atan(1.0);
+   A=cos(TWOPI/3.0); B=sin(TWOPI/3.0);
+
+   for (J=0; J<M_OVER_2; J++)
+   {
+      NO_FOLD = (J==0 || 2*J==M);
+      K0=J;
+      ANGLE=TWOPI*Real(J)/Real(M3); ZERO=ANGLE==0.0;
+      C1=cos(ANGLE); S1=sin(ANGLE);
+      C2=C1*C1-S1*S1; S2=S1*C1+C1*S1;
+      goto L200;
+   L100:
+      REPORT
+      if (NO_FOLD) { REPORT goto L600; }
+      REPORT
+      NO_FOLD=true; K0=M-J;
+      T=C1*A+S1*B; S1=C1*B-S1*A; C1=T;
+      T=C2*A-S2*B; S2= -C2*B-S2*A; C2=T;
+   L200:
+      REPORT
+      for (K=K0; K<N; K+=M3)
+      {
+         R0 = X0[K]; I0 = Y0[K];
+         RS=X1[K]+X2[K]; IS=Y1[K]+Y2[K];
+         X0[K]=R0+RS; Y0[K]=I0+IS;
+         RA=R0+RS*A; IA=I0+IS*A;
+         RB=(X1[K]-X2[K])*B; IB=(Y1[K]-Y2[K])*B;
+         if (!ZERO)
+         {
+            REPORT
+            R1=RA+IB; I1=IA-RB; R2=RA-IB; I2=IA+RB;
+            X1[K]=R1*C1+I1*S1; Y1[K]=I1*C1-R1*S1;
+            X2[K]=R2*C2+I2*S2; Y2[K]=I2*C2-R2*S2;
+         }
+         else { REPORT X1[K]=RA+IB; Y1[K]=IA-RB; X2[K]=RA-IB; Y2[K]=IA+RB; }
+      }
+      goto L100;
+   L600: ;
+   }
+
+   return;
+}
+
+static void R_4_FTK (int N, int M,
+   Real* X0, Real* Y0, Real* X1, Real* Y1,
+   Real* X2, Real* Y2, Real* X3, Real* Y3)
+//    RADIX FOUR FOURIER TRANSFORM KERNEL
+{
+   REPORT
+   bool NO_FOLD,ZERO;
+   int  J,K,K0,M4,M_OVER_2;
+   Real ANGLE,C1,C2,C3,S1,S2,S3,T,TWOPI;
+   Real I1,I2,I3,IS0,IS1,IU0,IU1,R1,R2,R3,RS0,RS1,RU0,RU1;
+
+   M4=M*4; M_OVER_2=M/2+1;
+   TWOPI=8.0*atan(1.0);
+
+   for (J=0; J<M_OVER_2; J++)
+   {
+      NO_FOLD = (J==0 || 2*J==M);
+      K0=J;
+      ANGLE=TWOPI*Real(J)/Real(M4); ZERO=ANGLE==0.0;
+      C1=cos(ANGLE); S1=sin(ANGLE);
+      C2=C1*C1-S1*S1; S2=S1*C1+C1*S1;
+      C3=C2*C1-S2*S1; S3=S2*C1+C2*S1;
+      goto L200;
+   L100:
+      REPORT
+      if (NO_FOLD) { REPORT goto L600; }
+      REPORT
+      NO_FOLD=true; K0=M-J;
+      T=C1; C1=S1; S1=T;
+      C2= -C2;
+      T=C3; C3= -S3; S3= -T;
+   L200:
+      REPORT
+      for (K=K0; K<N; K+=M4)
+      {
+         RS0=X0[K]+X2[K]; IS0=Y0[K]+Y2[K];
+         RU0=X0[K]-X2[K]; IU0=Y0[K]-Y2[K];
+         RS1=X1[K]+X3[K]; IS1=Y1[K]+Y3[K];
+         RU1=X1[K]-X3[K]; IU1=Y1[K]-Y3[K];
+         X0[K]=RS0+RS1; Y0[K]=IS0+IS1;
+         if (!ZERO)
+         {
+            REPORT
+            R1=RU0+IU1; I1=IU0-RU1;
+            R2=RS0-RS1; I2=IS0-IS1;
+            R3=RU0-IU1; I3=IU0+RU1;
+            X2[K]=R1*C1+I1*S1; Y2[K]=I1*C1-R1*S1;
+            X1[K]=R2*C2+I2*S2; Y1[K]=I2*C2-R2*S2;
+            X3[K]=R3*C3+I3*S3; Y3[K]=I3*C3-R3*S3;
+         }
+         else
+         {
+            REPORT
+            X2[K]=RU0+IU1; Y2[K]=IU0-RU1;
+            X1[K]=RS0-RS1; Y1[K]=IS0-IS1;
+            X3[K]=RU0-IU1; Y3[K]=IU0+RU1;
+         }
+      }
+      goto L100;
+   L600: ;
+   }
+
+   return;
+}
+
+static void R_5_FTK (int N, int M,
+   Real* X0, Real* Y0, Real* X1, Real* Y1, Real* X2, Real* Y2,
+   Real* X3, Real* Y3, Real* X4, Real* Y4)
+//    RADIX FIVE FOURIER TRANSFORM KERNEL
+
+{
+   REPORT
+   bool NO_FOLD,ZERO;
+   int  J,K,K0,M5,M_OVER_2;
+   Real ANGLE,A1,A2,B1,B2,C1,C2,C3,C4,S1,S2,S3,S4,T,TWOPI;
+   Real R0,R1,R2,R3,R4,RA1,RA2,RB1,RB2,RS1,RS2,RU1,RU2;
+   Real I0,I1,I2,I3,I4,IA1,IA2,IB1,IB2,IS1,IS2,IU1,IU2;
+
+   M5=M*5; M_OVER_2=M/2+1;
+   TWOPI=8.0*atan(1.0);
+   A1=cos(TWOPI/5.0); B1=sin(TWOPI/5.0);
+   A2=cos(2.0*TWOPI/5.0); B2=sin(2.0*TWOPI/5.0);
+
+   for (J=0; J<M_OVER_2; J++)
+   {
+      NO_FOLD = (J==0 || 2*J==M);
+      K0=J;
+      ANGLE=TWOPI*Real(J)/Real(M5); ZERO=ANGLE==0.0;
+      C1=cos(ANGLE); S1=sin(ANGLE);
+      C2=C1*C1-S1*S1; S2=S1*C1+C1*S1;
+      C3=C2*C1-S2*S1; S3=S2*C1+C2*S1;
+      C4=C2*C2-S2*S2; S4=S2*C2+C2*S2;
+      goto L200;
+   L100:
+      REPORT
+      if (NO_FOLD) { REPORT goto L600; }
+      REPORT
+      NO_FOLD=true; K0=M-J;
+      T=C1*A1+S1*B1; S1=C1*B1-S1*A1; C1=T;
+      T=C2*A2+S2*B2; S2=C2*B2-S2*A2; C2=T;
+      T=C3*A2-S3*B2; S3= -C3*B2-S3*A2; C3=T;
+      T=C4*A1-S4*B1; S4= -C4*B1-S4*A1; C4=T;
+   L200:
+      REPORT
+      for (K=K0; K<N; K+=M5)
+      {
+         R0=X0[K]; I0=Y0[K];
+         RS1=X1[K]+X4[K]; IS1=Y1[K]+Y4[K];
+         RU1=X1[K]-X4[K]; IU1=Y1[K]-Y4[K];
+         RS2=X2[K]+X3[K]; IS2=Y2[K]+Y3[K];
+         RU2=X2[K]-X3[K]; IU2=Y2[K]-Y3[K];
+         X0[K]=R0+RS1+RS2; Y0[K]=I0+IS1+IS2;
+         RA1=R0+RS1*A1+RS2*A2; IA1=I0+IS1*A1+IS2*A2;
+         RA2=R0+RS1*A2+RS2*A1; IA2=I0+IS1*A2+IS2*A1;
+         RB1=RU1*B1+RU2*B2; IB1=IU1*B1+IU2*B2;
+         RB2=RU1*B2-RU2*B1; IB2=IU1*B2-IU2*B1;
+         if (!ZERO)
+         {
+            REPORT
+            R1=RA1+IB1; I1=IA1-RB1;
+            R2=RA2+IB2; I2=IA2-RB2;
+            R3=RA2-IB2; I3=IA2+RB2;
+            R4=RA1-IB1; I4=IA1+RB1;
+            X1[K]=R1*C1+I1*S1; Y1[K]=I1*C1-R1*S1;
+            X2[K]=R2*C2+I2*S2; Y2[K]=I2*C2-R2*S2;
+            X3[K]=R3*C3+I3*S3; Y3[K]=I3*C3-R3*S3;
+            X4[K]=R4*C4+I4*S4; Y4[K]=I4*C4-R4*S4;
+         }
+         else
+         {
+            REPORT
+            X1[K]=RA1+IB1; Y1[K]=IA1-RB1;
+            X2[K]=RA2+IB2; Y2[K]=IA2-RB2;
+            X3[K]=RA2-IB2; Y3[K]=IA2+RB2;
+            X4[K]=RA1-IB1; Y4[K]=IA1+RB1;
+         }
+      }
+      goto L100;
+   L600: ;
+   }
+
+   return;
+}
+
+static void R_8_FTK (int N, int M,
+   Real* X0, Real* Y0, Real* X1, Real* Y1,
+   Real* X2, Real* Y2, Real* X3, Real* Y3,
+   Real* X4, Real* Y4, Real* X5, Real* Y5,
+   Real* X6, Real* Y6, Real* X7, Real* Y7)
+//    RADIX EIGHT FOURIER TRANSFORM KERNEL
+{
+   REPORT
+   bool NO_FOLD,ZERO;
+   int  J,K,K0,M8,M_OVER_2;
+   Real ANGLE,C1,C2,C3,C4,C5,C6,C7,E,S1,S2,S3,S4,S5,S6,S7,T,TWOPI;
+   Real R1,R2,R3,R4,R5,R6,R7,RS0,RS1,RS2,RS3,RU0,RU1,RU2,RU3;
+   Real I1,I2,I3,I4,I5,I6,I7,IS0,IS1,IS2,IS3,IU0,IU1,IU2,IU3;
+   Real RSS0,RSS1,RSU0,RSU1,RUS0,RUS1,RUU0,RUU1;
+   Real ISS0,ISS1,ISU0,ISU1,IUS0,IUS1,IUU0,IUU1;
+
+   M8=M*8; M_OVER_2=M/2+1;
+   TWOPI=8.0*atan(1.0); E=cos(TWOPI/8.0);
+
+   for (J=0;J<M_OVER_2;J++)
+   {
+      NO_FOLD= (J==0 || 2*J==M);
+      K0=J;
+      ANGLE=TWOPI*Real(J)/Real(M8); ZERO=ANGLE==0.0;
+      C1=cos(ANGLE); S1=sin(ANGLE);
+      C2=C1*C1-S1*S1; S2=C1*S1+S1*C1;
+      C3=C2*C1-S2*S1; S3=S2*C1+C2*S1;
+      C4=C2*C2-S2*S2; S4=S2*C2+C2*S2;
+      C5=C4*C1-S4*S1; S5=S4*C1+C4*S1;
+      C6=C4*C2-S4*S2; S6=S4*C2+C4*S2;
+      C7=C4*C3-S4*S3; S7=S4*C3+C4*S3;
+      goto L200;
+   L100:
+      REPORT
+      if (NO_FOLD) { REPORT goto L600; }
+      REPORT
+      NO_FOLD=true; K0=M-J;
+      T=(C1+S1)*E; S1=(C1-S1)*E; C1=T;
+      T=S2; S2=C2; C2=T;
+      T=(-C3+S3)*E; S3=(C3+S3)*E; C3=T;
+      C4= -C4;
+      T= -(C5+S5)*E; S5=(-C5+S5)*E; C5=T;
+      T= -S6; S6= -C6; C6=T;
+      T=(C7-S7)*E; S7= -(C7+S7)*E; C7=T;
+   L200:
+      REPORT
+      for (K=K0; K<N; K+=M8)
+      {
+         RS0=X0[K]+X4[K]; IS0=Y0[K]+Y4[K];
+         RU0=X0[K]-X4[K]; IU0=Y0[K]-Y4[K];
+         RS1=X1[K]+X5[K]; IS1=Y1[K]+Y5[K];
+         RU1=X1[K]-X5[K]; IU1=Y1[K]-Y5[K];
+         RS2=X2[K]+X6[K]; IS2=Y2[K]+Y6[K];
+         RU2=X2[K]-X6[K]; IU2=Y2[K]-Y6[K];
+         RS3=X3[K]+X7[K]; IS3=Y3[K]+Y7[K];
+         RU3=X3[K]-X7[K]; IU3=Y3[K]-Y7[K];
+         RSS0=RS0+RS2; ISS0=IS0+IS2;
+         RSU0=RS0-RS2; ISU0=IS0-IS2;
+         RSS1=RS1+RS3; ISS1=IS1+IS3;
+         RSU1=RS1-RS3; ISU1=IS1-IS3;
+         RUS0=RU0-IU2; IUS0=IU0+RU2;
+         RUU0=RU0+IU2; IUU0=IU0-RU2;
+         RUS1=RU1-IU3; IUS1=IU1+RU3;
+         RUU1=RU1+IU3; IUU1=IU1-RU3;
+         T=(RUS1+IUS1)*E; IUS1=(IUS1-RUS1)*E; RUS1=T;
+         T=(RUU1+IUU1)*E; IUU1=(IUU1-RUU1)*E; RUU1=T;
+         X0[K]=RSS0+RSS1; Y0[K]=ISS0+ISS1;
+         if (!ZERO)
+         {
+            REPORT
+            R1=RUU0+RUU1; I1=IUU0+IUU1;
+            R2=RSU0+ISU1; I2=ISU0-RSU1;
+            R3=RUS0+IUS1; I3=IUS0-RUS1;
+            R4=RSS0-RSS1; I4=ISS0-ISS1;
+            R5=RUU0-RUU1; I5=IUU0-IUU1;
+            R6=RSU0-ISU1; I6=ISU0+RSU1;
+            R7=RUS0-IUS1; I7=IUS0+RUS1;
+            X4[K]=R1*C1+I1*S1; Y4[K]=I1*C1-R1*S1;
+            X2[K]=R2*C2+I2*S2; Y2[K]=I2*C2-R2*S2;
+            X6[K]=R3*C3+I3*S3; Y6[K]=I3*C3-R3*S3;
+            X1[K]=R4*C4+I4*S4; Y1[K]=I4*C4-R4*S4;
+            X5[K]=R5*C5+I5*S5; Y5[K]=I5*C5-R5*S5;
+            X3[K]=R6*C6+I6*S6; Y3[K]=I6*C6-R6*S6;
+            X7[K]=R7*C7+I7*S7; Y7[K]=I7*C7-R7*S7;
+         }
+         else
+         {
+            REPORT
+            X4[K]=RUU0+RUU1; Y4[K]=IUU0+IUU1;
+            X2[K]=RSU0+ISU1; Y2[K]=ISU0-RSU1;
+            X6[K]=RUS0+IUS1; Y6[K]=IUS0-RUS1;
+            X1[K]=RSS0-RSS1; Y1[K]=ISS0-ISS1;
+            X5[K]=RUU0-RUU1; Y5[K]=IUU0-IUU1;
+            X3[K]=RSU0-ISU1; Y3[K]=ISU0+RSU1;
+            X7[K]=RUS0-IUS1; Y7[K]=IUS0+RUS1;
+         }
+      }
+      goto L100;
+   L600: ;
+   }
+
+   return;
+}
+
+static void R_16_FTK (int N, int M,
+   Real* X0, Real* Y0, Real* X1, Real* Y1,
+   Real* X2, Real* Y2, Real* X3, Real* Y3,
+   Real* X4, Real* Y4, Real* X5, Real* Y5,
+   Real* X6, Real* Y6, Real* X7, Real* Y7,
+   Real* X8, Real* Y8, Real* X9, Real* Y9,
+   Real* X10, Real* Y10, Real* X11, Real* Y11,
+   Real* X12, Real* Y12, Real* X13, Real* Y13,
+   Real* X14, Real* Y14, Real* X15, Real* Y15)
+//    RADIX SIXTEEN FOURIER TRANSFORM KERNEL
+{
+   REPORT
+   bool NO_FOLD,ZERO;
+   int  J,K,K0,M16,M_OVER_2;
+   Real ANGLE,EI1,ER1,E2,EI3,ER3,EI5,ER5,T,TWOPI;
+   Real RS0,RS1,RS2,RS3,RS4,RS5,RS6,RS7;
+   Real IS0,IS1,IS2,IS3,IS4,IS5,IS6,IS7;
+   Real RU0,RU1,RU2,RU3,RU4,RU5,RU6,RU7;
+   Real IU0,IU1,IU2,IU3,IU4,IU5,IU6,IU7;
+   Real RUS0,RUS1,RUS2,RUS3,RUU0,RUU1,RUU2,RUU3;
+   Real ISS0,ISS1,ISS2,ISS3,ISU0,ISU1,ISU2,ISU3;
+   Real RSS0,RSS1,RSS2,RSS3,RSU0,RSU1,RSU2,RSU3;
+   Real IUS0,IUS1,IUS2,IUS3,IUU0,IUU1,IUU2,IUU3;
+   Real RSSS0,RSSS1,RSSU0,RSSU1,RSUS0,RSUS1,RSUU0,RSUU1;
+   Real ISSS0,ISSS1,ISSU0,ISSU1,ISUS0,ISUS1,ISUU0,ISUU1;
+   Real RUSS0,RUSS1,RUSU0,RUSU1,RUUS0,RUUS1,RUUU0,RUUU1;
+   Real IUSS0,IUSS1,IUSU0,IUSU1,IUUS0,IUUS1,IUUU0,IUUU1;
+   Real R1,R2,R3,R4,R5,R6,R7,R8,R9,R10,R11,R12,R13,R14,R15;
+   Real I1,I2,I3,I4,I5,I6,I7,I8,I9,I10,I11,I12,I13,I14,I15;
+   Real C1,C2,C3,C4,C5,C6,C7,C8,C9,C10,C11,C12,C13,C14,C15;
+   Real S1,S2,S3,S4,S5,S6,S7,S8,S9,S10,S11,S12,S13,S14,S15;
+
+   M16=M*16; M_OVER_2=M/2+1;
+   TWOPI=8.0*atan(1.0);
+   ER1=cos(TWOPI/16.0); EI1=sin(TWOPI/16.0);
+   E2=cos(TWOPI/8.0);
+   ER3=cos(3.0*TWOPI/16.0); EI3=sin(3.0*TWOPI/16.0);
+   ER5=cos(5.0*TWOPI/16.0); EI5=sin(5.0*TWOPI/16.0);
+
+   for (J=0; J<M_OVER_2; J++)
+   {
+      NO_FOLD = (J==0 || 2*J==M);
+      K0=J;
+      ANGLE=TWOPI*Real(J)/Real(M16);
+      ZERO=ANGLE==0.0;
+      C1=cos(ANGLE); S1=sin(ANGLE);
+      C2=C1*C1-S1*S1; S2=C1*S1+S1*C1;
+      C3=C2*C1-S2*S1; S3=S2*C1+C2*S1;
+      C4=C2*C2-S2*S2; S4=S2*C2+C2*S2;
+      C5=C4*C1-S4*S1; S5=S4*C1+C4*S1;
+      C6=C4*C2-S4*S2; S6=S4*C2+C4*S2;
+      C7=C4*C3-S4*S3; S7=S4*C3+C4*S3;
+      C8=C4*C4-S4*S4; S8=C4*S4+S4*C4;
+      C9=C8*C1-S8*S1; S9=S8*C1+C8*S1;
+      C10=C8*C2-S8*S2; S10=S8*C2+C8*S2;
+      C11=C8*C3-S8*S3; S11=S8*C3+C8*S3;
+      C12=C8*C4-S8*S4; S12=S8*C4+C8*S4;
+      C13=C8*C5-S8*S5; S13=S8*C5+C8*S5;
+      C14=C8*C6-S8*S6; S14=S8*C6+C8*S6;
+      C15=C8*C7-S8*S7; S15=S8*C7+C8*S7;
+      goto L200;
+   L100:
+      REPORT
+      if (NO_FOLD) { REPORT goto L600; }
+      REPORT
+      NO_FOLD=true; K0=M-J;
+      T=C1*ER1+S1*EI1; S1= -S1*ER1+C1*EI1; C1=T;
+      T=(C2+S2)*E2; S2=(C2-S2)*E2; C2=T;
+      T=C3*ER3+S3*EI3; S3= -S3*ER3+C3*EI3; C3=T;
+      T=S4; S4=C4; C4=T;
+      T=S5*ER1-C5*EI1; S5=C5*ER1+S5*EI1; C5=T;
+      T=(-C6+S6)*E2; S6=(C6+S6)*E2; C6=T;
+      T=S7*ER3-C7*EI3; S7=C7*ER3+S7*EI3; C7=T;
+      C8= -C8;
+      T= -(C9*ER1+S9*EI1); S9=S9*ER1-C9*EI1; C9=T;
+      T= -(C10+S10)*E2; S10=(-C10+S10)*E2; C10=T;
+      T= -(C11*ER3+S11*EI3); S11=S11*ER3-C11*EI3; C11=T;
+      T= -S12; S12= -C12; C12=T;
+      T= -S13*ER1+C13*EI1; S13= -(C13*ER1+S13*EI1); C13=T;
+      T=(C14-S14)*E2; S14= -(C14+S14)*E2; C14=T;
+      T= -S15*ER3+C15*EI3; S15= -(C15*ER3+S15*EI3); C15=T;
+   L200:
+      REPORT
+      for (K=K0; K<N; K+=M16)
+      {
+         RS0=X0[K]+X8[K]; IS0=Y0[K]+Y8[K];
+         RU0=X0[K]-X8[K]; IU0=Y0[K]-Y8[K];
+         RS1=X1[K]+X9[K]; IS1=Y1[K]+Y9[K];
+         RU1=X1[K]-X9[K]; IU1=Y1[K]-Y9[K];
+         RS2=X2[K]+X10[K]; IS2=Y2[K]+Y10[K];
+         RU2=X2[K]-X10[K]; IU2=Y2[K]-Y10[K];
+         RS3=X3[K]+X11[K]; IS3=Y3[K]+Y11[K];
+         RU3=X3[K]-X11[K]; IU3=Y3[K]-Y11[K];
+         RS4=X4[K]+X12[K]; IS4=Y4[K]+Y12[K];
+         RU4=X4[K]-X12[K]; IU4=Y4[K]-Y12[K];
+         RS5=X5[K]+X13[K]; IS5=Y5[K]+Y13[K];
+         RU5=X5[K]-X13[K]; IU5=Y5[K]-Y13[K];
+         RS6=X6[K]+X14[K]; IS6=Y6[K]+Y14[K];
+         RU6=X6[K]-X14[K]; IU6=Y6[K]-Y14[K];
+         RS7=X7[K]+X15[K]; IS7=Y7[K]+Y15[K];
+         RU7=X7[K]-X15[K]; IU7=Y7[K]-Y15[K];
+         RSS0=RS0+RS4; ISS0=IS0+IS4;
+         RSS1=RS1+RS5; ISS1=IS1+IS5;
+         RSS2=RS2+RS6; ISS2=IS2+IS6;
+         RSS3=RS3+RS7; ISS3=IS3+IS7;
+         RSU0=RS0-RS4; ISU0=IS0-IS4;
+         RSU1=RS1-RS5; ISU1=IS1-IS5;
+         RSU2=RS2-RS6; ISU2=IS2-IS6;
+         RSU3=RS3-RS7; ISU3=IS3-IS7;
+         RUS0=RU0-IU4; IUS0=IU0+RU4;
+         RUS1=RU1-IU5; IUS1=IU1+RU5;
+         RUS2=RU2-IU6; IUS2=IU2+RU6;
+         RUS3=RU3-IU7; IUS3=IU3+RU7;
+         RUU0=RU0+IU4; IUU0=IU0-RU4;
+         RUU1=RU1+IU5; IUU1=IU1-RU5;
+         RUU2=RU2+IU6; IUU2=IU2-RU6;
+         RUU3=RU3+IU7; IUU3=IU3-RU7;
+         T=(RSU1+ISU1)*E2; ISU1=(ISU1-RSU1)*E2; RSU1=T;
+         T=(RSU3+ISU3)*E2; ISU3=(ISU3-RSU3)*E2; RSU3=T;
+         T=RUS1*ER3+IUS1*EI3; IUS1=IUS1*ER3-RUS1*EI3; RUS1=T;
+         T=(RUS2+IUS2)*E2; IUS2=(IUS2-RUS2)*E2; RUS2=T;
+         T=RUS3*ER5+IUS3*EI5; IUS3=IUS3*ER5-RUS3*EI5; RUS3=T;
+         T=RUU1*ER1+IUU1*EI1; IUU1=IUU1*ER1-RUU1*EI1; RUU1=T;
+         T=(RUU2+IUU2)*E2; IUU2=(IUU2-RUU2)*E2; RUU2=T;
+         T=RUU3*ER3+IUU3*EI3; IUU3=IUU3*ER3-RUU3*EI3; RUU3=T;
+         RSSS0=RSS0+RSS2; ISSS0=ISS0+ISS2;
+         RSSS1=RSS1+RSS3; ISSS1=ISS1+ISS3;
+         RSSU0=RSS0-RSS2; ISSU0=ISS0-ISS2;
+         RSSU1=RSS1-RSS3; ISSU1=ISS1-ISS3;
+         RSUS0=RSU0-ISU2; ISUS0=ISU0+RSU2;
+         RSUS1=RSU1-ISU3; ISUS1=ISU1+RSU3;
+         RSUU0=RSU0+ISU2; ISUU0=ISU0-RSU2;
+         RSUU1=RSU1+ISU3; ISUU1=ISU1-RSU3;
+         RUSS0=RUS0-IUS2; IUSS0=IUS0+RUS2;
+         RUSS1=RUS1-IUS3; IUSS1=IUS1+RUS3;
+         RUSU0=RUS0+IUS2; IUSU0=IUS0-RUS2;
+         RUSU1=RUS1+IUS3; IUSU1=IUS1-RUS3;
+         RUUS0=RUU0+RUU2; IUUS0=IUU0+IUU2;
+         RUUS1=RUU1+RUU3; IUUS1=IUU1+IUU3;
+         RUUU0=RUU0-RUU2; IUUU0=IUU0-IUU2;
+         RUUU1=RUU1-RUU3; IUUU1=IUU1-IUU3;
+         X0[K]=RSSS0+RSSS1; Y0[K]=ISSS0+ISSS1;
+         if (!ZERO)
+         {
+            REPORT
+            R1=RUUS0+RUUS1; I1=IUUS0+IUUS1;
+            R2=RSUU0+RSUU1; I2=ISUU0+ISUU1;
+            R3=RUSU0+RUSU1; I3=IUSU0+IUSU1;
+            R4=RSSU0+ISSU1; I4=ISSU0-RSSU1;
+            R5=RUUU0+IUUU1; I5=IUUU0-RUUU1;
+            R6=RSUS0+ISUS1; I6=ISUS0-RSUS1;
+            R7=RUSS0+IUSS1; I7=IUSS0-RUSS1;
+            R8=RSSS0-RSSS1; I8=ISSS0-ISSS1;
+            R9=RUUS0-RUUS1; I9=IUUS0-IUUS1;
+            R10=RSUU0-RSUU1; I10=ISUU0-ISUU1;
+            R11=RUSU0-RUSU1; I11=IUSU0-IUSU1;
+            R12=RSSU0-ISSU1; I12=ISSU0+RSSU1;
+            R13=RUUU0-IUUU1; I13=IUUU0+RUUU1;
+            R14=RSUS0-ISUS1; I14=ISUS0+RSUS1;
+            R15=RUSS0-IUSS1; I15=IUSS0+RUSS1;
+            X8[K]=R1*C1+I1*S1; Y8[K]=I1*C1-R1*S1;
+            X4[K]=R2*C2+I2*S2; Y4[K]=I2*C2-R2*S2;
+            X12[K]=R3*C3+I3*S3; Y12[K]=I3*C3-R3*S3;
+            X2[K]=R4*C4+I4*S4; Y2[K]=I4*C4-R4*S4;
+            X10[K]=R5*C5+I5*S5; Y10[K]=I5*C5-R5*S5;
+            X6[K]=R6*C6+I6*S6; Y6[K]=I6*C6-R6*S6;
+            X14[K]=R7*C7+I7*S7; Y14[K]=I7*C7-R7*S7;
+            X1[K]=R8*C8+I8*S8; Y1[K]=I8*C8-R8*S8;
+            X9[K]=R9*C9+I9*S9; Y9[K]=I9*C9-R9*S9;
+            X5[K]=R10*C10+I10*S10; Y5[K]=I10*C10-R10*S10;
+            X13[K]=R11*C11+I11*S11; Y13[K]=I11*C11-R11*S11;
+            X3[K]=R12*C12+I12*S12; Y3[K]=I12*C12-R12*S12;
+            X11[K]=R13*C13+I13*S13; Y11[K]=I13*C13-R13*S13;
+            X7[K]=R14*C14+I14*S14; Y7[K]=I14*C14-R14*S14;
+            X15[K]=R15*C15+I15*S15; Y15[K]=I15*C15-R15*S15;
+         }
+         else
+         {
+            REPORT
+            X8[K]=RUUS0+RUUS1; Y8[K]=IUUS0+IUUS1;
+            X4[K]=RSUU0+RSUU1; Y4[K]=ISUU0+ISUU1;
+            X12[K]=RUSU0+RUSU1; Y12[K]=IUSU0+IUSU1;
+            X2[K]=RSSU0+ISSU1; Y2[K]=ISSU0-RSSU1;
+            X10[K]=RUUU0+IUUU1; Y10[K]=IUUU0-RUUU1;
+            X6[K]=RSUS0+ISUS1; Y6[K]=ISUS0-RSUS1;
+            X14[K]=RUSS0+IUSS1; Y14[K]=IUSS0-RUSS1;
+            X1[K]=RSSS0-RSSS1; Y1[K]=ISSS0-ISSS1;
+            X9[K]=RUUS0-RUUS1; Y9[K]=IUUS0-IUUS1;
+            X5[K]=RSUU0-RSUU1; Y5[K]=ISUU0-ISUU1;
+            X13[K]=RUSU0-RUSU1; Y13[K]=IUSU0-IUSU1;
+            X3[K]=RSSU0-ISSU1; Y3[K]=ISSU0+RSSU1;
+            X11[K]=RUUU0-IUUU1; Y11[K]=IUUU0+RUUU1;
+            X7[K]=RSUS0-ISUS1; Y7[K]=ISUS0+RSUS1;
+            X15[K]=RUSS0-IUSS1; Y15[K]=IUSS0+RUSS1;
+         }
+      }
+      goto L100;
+   L600: ;
+   }
+
+   return;
+}
+
+// can the number of points be factorised sufficiently
+// for the fft to run
+
+bool FFT_Controller::CanFactor(int PTS)
+{
+   REPORT
+   const int NP = 16, NQ = 10, PMAX=19;
+
+   if (PTS<=1) { REPORT return true; }
+
+   int N = PTS, F = 2, P = 0, Q = 0;
+
+   while (N > 1)
+   {
+      bool fail = true;
+      for (int J = F; J <= PMAX; J++)
+         if (N % J == 0) { fail = false; F=J; break; }
+      if (fail || P >= NP || Q >= NQ) { REPORT return false; }
+      N /= F;
+      if (N % F != 0) Q++; else { N /= F; P++; }
+   }
+
+   return true;    // can factorise
+
+}
+
+bool FFT_Controller::OnlyOldFFT;         // static variable
+
+// **************************** multi radix counter **********************
+
+MultiRadixCounter::MultiRadixCounter(int nx, const SimpleIntArray& rx,
+   SimpleIntArray& vx)
+   : Radix(rx), Value(vx), n(nx), reverse(0),
+      product(1), counter(0), finish(false)
+{
+   REPORT for (int k = 0; k < n; k++) { Value[k] = 0; product *= Radix[k]; }
+}
+
+void MultiRadixCounter::operator++()
+{
+   REPORT
+   counter++; int p = product;
+   for (int k = 0; k < n; k++)
+   {
+      Value[k]++; int p1 = p / Radix[k]; reverse += p1;
+      if (Value[k] == Radix[k]) { REPORT Value[k] = 0; reverse -= p; p = p1; }
+      else { REPORT return; }
+   }
+   finish = true;
+}
+
+
+static int BitReverse(int x, int prod, int n, const SimpleIntArray& f)
+{
+   // x = c[0]+f[0]*(c[1]+f[1]*(c[2]+...
+   // return c[n-1]+f[n-1]*(c[n-2]+f[n-2]*(c[n-3]+...
+   // prod is the product of the f[i]
+   // n is the number of f[i] (don't assume f has the correct length)
+
+   REPORT
+   const int* d = f.Data() + n; int sum = 0; int q = 1;
+   while (n--)
+   {
+      prod /= *(--d);
+      int c = x / prod; x-= c * prod;
+      sum += q * c; q *= *d;
+   }
+   return sum;
+}
+
+
+#ifdef use_namespace
+}
+#endif
+
+///@}
+
Index: /nanovis/tags/1.1.4/newmat11/newmat.h
===================================================================
--- /nanovis/tags/1.1.4/newmat11/newmat.h	(revision 4930)
+++ /nanovis/tags/1.1.4/newmat11/newmat.h	(revision 4930)
@@ -0,0 +1,2213 @@
+/// \defgroup newmat Newmat matrix manipulation library
+///@{
+
+/// \file newmat.h
+/// Definition file for matrix library.
+
+// Copyright (C) 2004: R B Davies
+
+#ifndef NEWMAT_LIB
+#define NEWMAT_LIB 0
+
+#include "include.h"
+
+#include "myexcept.h"
+
+
+#ifdef use_namespace
+namespace NEWMAT { using namespace RBD_COMMON; }
+namespace RBD_LIBRARIES { using namespace NEWMAT; }
+namespace NEWMAT {
+#endif
+
+//#define DO_REPORT                     // to activate REPORT
+
+#ifdef NO_LONG_NAMES
+#define UpperTriangularMatrix UTMatrix
+#define LowerTriangularMatrix LTMatrix
+#define SymmetricMatrix SMatrix
+#define DiagonalMatrix DMatrix
+#define BandMatrix BMatrix
+#define UpperBandMatrix UBMatrix
+#define LowerBandMatrix LBMatrix
+#define SymmetricBandMatrix SBMatrix
+#define BandLUMatrix BLUMatrix
+#endif
+
+// ************************** general utilities ****************************/
+
+class GeneralMatrix;                            // defined later
+class BaseMatrix;                               // defined later
+class MatrixInput;                              // defined later
+
+void MatrixErrorNoSpace(const void*);           ///< test for allocation fails
+
+/// Return from LogDeterminant function.
+/// Members are the log of the absolute value and the sign (+1, -1 or 0)
+class LogAndSign
+{
+   Real log_val;
+   int sign_val;
+public:
+   LogAndSign() { log_val=0.0; sign_val=1; }
+   LogAndSign(Real);
+   void operator*=(Real);                       ///< multiply by a real
+   void pow_eq(int k);                          ///< raise to power of k
+   void PowEq(int k) { pow_eq(k); }
+   void ChangeSign() { sign_val = -sign_val; }
+   void change_sign() { sign_val = -sign_val; } ///< change sign
+   Real LogValue() const { return log_val; }
+   Real log_value() const { return log_val; }   ///< log of the absolute value
+   int Sign() const { return sign_val; }
+   int sign() const { return sign_val; }        ///< sign of the value
+   Real value() const;                          ///< the value
+   Real Value() const { return value(); }
+   FREE_CHECK(LogAndSign)
+};
+
+// the following class is for counting the number of times a piece of code
+// is executed. It is used for locating any code not executed by test
+// routines. Use turbo GREP locate all places this code is called and
+// check which ones are not accessed.
+// Somewhat implementation dependent as it relies on "cout" still being
+// present when ExeCounter objects are destructed.
+
+#ifdef DO_REPORT
+
+class ExeCounter
+{
+   int line;                                    // code line number
+   int fileid;                                  // file identifier
+   long nexe;                                   // number of executions
+   static int nreports;                         // number of reports
+public:
+   ExeCounter(int,int);
+   void operator++() { nexe++; }
+   ~ExeCounter();                               // prints out reports
+};
+
+#endif
+
+
+// ************************** class MatrixType *****************************
+
+/// Find the type of a matrix resulting from matrix operations.
+/// Also identify what conversions are permissible.
+/// This class must be updated when new matrix types are added.
+
+class MatrixType
+{
+public:
+   enum Attribute {  Valid     = 1,
+                     Diagonal  = 2,             // order of these is important
+                     Symmetric = 4,
+                     Band      = 8,
+                     Lower     = 16,
+                     Upper     = 32,
+                     Square    = 64,
+                     Skew      = 128,
+                     LUDeco    = 256,
+                     Ones      = 512 };
+
+   enum            { US = 0,
+                     UT = Valid + Upper + Square,
+                     LT = Valid + Lower + Square,
+                     Rt = Valid,
+                     Sq = Valid + Square,
+                     Sm = Valid + Symmetric + Square,
+                     Sk = Valid + Skew + Square,
+                     Dg = Valid + Diagonal + Band + Lower + Upper + Symmetric
+                        + Square,
+                     Id = Valid + Diagonal + Band + Lower + Upper + Symmetric
+                        + Square + Ones,
+                     RV = Valid,     //   do not separate out
+                     CV = Valid,     //   vectors
+                     BM = Valid + Band + Square,
+                     UB = Valid + Band + Upper + Square,
+                     LB = Valid + Band + Lower + Square,
+                     SB = Valid + Band + Symmetric + Square,
+                     KB = Valid + Band + Skew + Square,
+                     Ct = Valid + LUDeco + Square,
+                     BC = Valid + Band + LUDeco + Square,
+                     Mask = ~Square
+                   };
+
+
+   static int nTypes() { return 13; }          // number of different types
+					       // exclude Ct, US, BC
+public:
+   int attribute;
+   bool DataLossOK;                            // true if data loss is OK when
+                                               // this represents a destination
+public:
+   MatrixType () : DataLossOK(false) {}
+   MatrixType (int i) : attribute(i), DataLossOK(false) {}
+   MatrixType (int i, bool dlok) : attribute(i), DataLossOK(dlok) {}
+   MatrixType (const MatrixType& mt)
+      : attribute(mt.attribute), DataLossOK(mt.DataLossOK) {}
+   void operator=(const MatrixType& mt)
+      { attribute = mt.attribute; DataLossOK = mt.DataLossOK; }
+   void SetDataLossOK() { DataLossOK = true; }
+   int operator+() const { return attribute; }
+   MatrixType operator+(MatrixType mt) const
+      { return MatrixType(attribute & mt.attribute); }
+   MatrixType operator*(const MatrixType&) const;
+   MatrixType SP(const MatrixType&) const;
+   MatrixType KP(const MatrixType&) const;
+   MatrixType operator|(const MatrixType& mt) const
+      { return MatrixType(attribute & mt.attribute & Valid); }
+   MatrixType operator&(const MatrixType& mt) const
+      { return MatrixType(attribute & mt.attribute & Valid); }
+   bool operator>=(MatrixType mt) const
+      { return ( attribute & ~mt.attribute & Mask ) == 0; }
+   bool operator<(MatrixType mt) const         // for MS Visual C++ 4
+      { return ( attribute & ~mt.attribute & Mask ) != 0; }
+   bool operator==(MatrixType t) const
+      { return (attribute == t.attribute); }
+   bool operator!=(MatrixType t) const
+      { return (attribute != t.attribute); }
+   bool operator!() const { return (attribute & Valid) == 0; }
+   MatrixType i() const;                       ///< type of inverse
+   MatrixType t() const;                       ///< type of transpose
+   MatrixType AddEqualEl() const               ///< add constant to matrix
+      { return MatrixType(attribute & (Valid + Symmetric + Square)); }
+   MatrixType MultRHS() const;                 ///< type for rhs of multiply
+   MatrixType sub() const                      ///< type of submatrix
+      { return MatrixType(attribute & Valid); }
+   MatrixType ssub() const                     ///< type of sym submatrix
+      { return MatrixType(attribute); }        // not for selection matrix
+   GeneralMatrix* New() const;                 ///< new matrix of given type
+   GeneralMatrix* New(int,int,BaseMatrix*) const;
+                                               ///< new matrix of given type
+   const char* value() const;                  ///< type as char string
+   const char* Value() const { return value(); }
+   friend bool Rectangular(MatrixType a, MatrixType b, MatrixType c);
+   friend bool Compare(const MatrixType&, MatrixType&);
+                                               ///< compare and check conversion
+   bool is_band() const { return (attribute & Band) != 0; }
+   bool is_diagonal() const { return (attribute & Diagonal) != 0; }
+   bool is_symmetric() const { return (attribute & Symmetric) != 0; }
+   bool CannotConvert() const { return (attribute & LUDeco) != 0; }
+                                               // used by operator== 
+   FREE_CHECK(MatrixType)
+};
+
+
+// *********************** class MatrixBandWidth ***********************/
+
+///Upper and lower bandwidths of a matrix.
+///That is number of diagonals strictly above or below main diagonal,
+///e.g. diagonal matrix has 0 upper and lower bandwiths.
+///-1 means the matrix may have the maximum bandwidth. 
+class MatrixBandWidth
+{
+public:
+   int lower_val;
+   int upper_val;
+   MatrixBandWidth(const int l, const int u) : lower_val(l), upper_val(u) {}
+   MatrixBandWidth(const int i) : lower_val(i), upper_val(i) {}
+   MatrixBandWidth operator+(const MatrixBandWidth&) const;
+   MatrixBandWidth operator*(const MatrixBandWidth&) const;
+   MatrixBandWidth minimum(const MatrixBandWidth&) const;
+   MatrixBandWidth t() const { return MatrixBandWidth(upper_val,lower_val); }
+   bool operator==(const MatrixBandWidth& bw) const
+      { return (lower_val == bw.lower_val) && (upper_val == bw.upper_val); }
+   bool operator!=(const MatrixBandWidth& bw) const { return !operator==(bw); }
+   int Upper() const { return upper_val; }
+   int upper() const { return upper_val; }
+   int Lower() const { return lower_val; }
+   int lower() const { return lower_val; }
+   FREE_CHECK(MatrixBandWidth)
+};
+
+
+// ********************* Array length specifier ************************/
+
+/// This class is used to avoid constructors such as
+/// ColumnVector(int) being used for conversions.
+/// Eventually this should be replaced by the use of the keyword "explicit".
+
+class ArrayLengthSpecifier
+{
+   int v;
+public:
+   int Value() const { return v; }
+   int value() const { return v; }
+   ArrayLengthSpecifier(int l) : v(l) {}
+};
+
+// ************************* Matrix routines ***************************/
+
+
+class MatrixRowCol;                             // defined later
+class MatrixRow;
+class MatrixCol;
+class MatrixColX;
+
+class GeneralMatrix;                            // defined later
+class AddedMatrix;
+class MultipliedMatrix;
+class SubtractedMatrix;
+class SPMatrix;
+class KPMatrix;
+class ConcatenatedMatrix;
+class StackedMatrix;
+class SolvedMatrix;
+class ShiftedMatrix;
+class NegShiftedMatrix;
+class ScaledMatrix;
+class TransposedMatrix;
+class ReversedMatrix;
+class NegatedMatrix;
+class InvertedMatrix;
+class RowedMatrix;
+class ColedMatrix;
+class DiagedMatrix;
+class MatedMatrix;
+class GetSubMatrix;
+class ReturnMatrix;
+class Matrix;
+class SquareMatrix;
+class nricMatrix;
+class RowVector;
+class ColumnVector;
+class SymmetricMatrix;
+class UpperTriangularMatrix;
+class LowerTriangularMatrix;
+class DiagonalMatrix;
+class CroutMatrix;
+class BandMatrix;
+class LowerBandMatrix;
+class UpperBandMatrix;
+class SymmetricBandMatrix;
+class LinearEquationSolver;
+class GenericMatrix;
+
+
+#define MatrixTypeUnSp 0
+//static MatrixType MatrixTypeUnSp(MatrixType::US);
+//						// AT&T needs this
+
+/// Base of the matrix classes.
+class BaseMatrix : public Janitor
+{
+protected:
+   virtual int search(const BaseMatrix*) const = 0;
+						// count number of times matrix is referred to
+public:
+   virtual GeneralMatrix* Evaluate(MatrixType mt=MatrixTypeUnSp) = 0;
+						// evaluate temporary
+   // for old version of G++
+   //   virtual GeneralMatrix* Evaluate(MatrixType mt) = 0;
+   //   GeneralMatrix* Evaluate() { return Evaluate(MatrixTypeUnSp); }
+   AddedMatrix operator+(const BaseMatrix&) const;    // results of operations
+   MultipliedMatrix operator*(const BaseMatrix&) const;
+   SubtractedMatrix operator-(const BaseMatrix&) const;
+   ConcatenatedMatrix operator|(const BaseMatrix&) const;
+   StackedMatrix operator&(const BaseMatrix&) const;
+   ShiftedMatrix operator+(Real) const;
+   ScaledMatrix operator*(Real) const;
+   ScaledMatrix operator/(Real) const;
+   ShiftedMatrix operator-(Real) const;
+   TransposedMatrix t() const;
+//   TransposedMatrix t;
+   NegatedMatrix operator-() const;                   // change sign of elements
+   ReversedMatrix reverse() const;
+   ReversedMatrix Reverse() const;
+   InvertedMatrix i() const;
+//   InvertedMatrix i;
+   RowedMatrix as_row() const;
+   RowedMatrix AsRow() const;
+   ColedMatrix as_column() const;
+   ColedMatrix AsColumn() const;
+   DiagedMatrix as_diagonal() const;
+   DiagedMatrix AsDiagonal() const;
+   MatedMatrix as_matrix(int,int) const;
+   MatedMatrix AsMatrix(int m, int n) const;
+   GetSubMatrix submatrix(int,int,int,int) const;
+   GetSubMatrix SubMatrix(int fr, int lr, int fc, int lc) const;
+   GetSubMatrix sym_submatrix(int,int) const;
+   GetSubMatrix SymSubMatrix(int f, int l) const;
+   GetSubMatrix row(int) const;
+   GetSubMatrix rows(int,int) const;
+   GetSubMatrix column(int) const;
+   GetSubMatrix columns(int,int) const;
+   GetSubMatrix Row(int f) const;
+   GetSubMatrix Rows(int f, int l) const;
+   GetSubMatrix Column(int f) const;
+   GetSubMatrix Columns(int f, int l) const;
+   Real as_scalar() const;                      // conversion of 1 x 1 matrix
+   Real AsScalar() const;
+   virtual LogAndSign log_determinant() const;
+   LogAndSign LogDeterminant() const { return log_determinant(); }
+   Real determinant() const;
+   Real Determinant() const { return determinant(); }
+   virtual Real sum_square() const;
+   Real SumSquare() const { return sum_square(); }
+   Real norm_Frobenius() const;
+   Real norm_frobenius() const { return norm_Frobenius(); }
+   Real NormFrobenius() const { return norm_Frobenius(); }
+   virtual Real sum_absolute_value() const;
+   Real SumAbsoluteValue() const { return sum_absolute_value(); }
+   virtual Real sum() const;
+   virtual Real Sum() const { return sum(); }
+   virtual Real maximum_absolute_value() const;
+   Real MaximumAbsoluteValue() const { return maximum_absolute_value(); }
+   virtual Real maximum_absolute_value1(int& i) const;
+   Real MaximumAbsoluteValue1(int& i) const
+      { return maximum_absolute_value1(i); }
+   virtual Real maximum_absolute_value2(int& i, int& j) const;
+   Real MaximumAbsoluteValue2(int& i, int& j) const
+      { return maximum_absolute_value2(i,j); }
+   virtual Real minimum_absolute_value() const;
+   Real MinimumAbsoluteValue() const { return minimum_absolute_value(); }
+   virtual Real minimum_absolute_value1(int& i) const;
+   Real MinimumAbsoluteValue1(int& i) const
+      { return minimum_absolute_value1(i); }
+   virtual Real minimum_absolute_value2(int& i, int& j) const;
+   Real MinimumAbsoluteValue2(int& i, int& j) const
+      { return minimum_absolute_value2(i,j); }
+   virtual Real maximum() const;
+   Real Maximum() const { return maximum(); }
+   virtual Real maximum1(int& i) const;
+   Real Maximum1(int& i) const { return maximum1(i); }
+   virtual Real maximum2(int& i, int& j) const;
+   Real Maximum2(int& i, int& j) const { return maximum2(i,j); }
+   virtual Real minimum() const;
+   Real Minimum() const { return minimum(); }
+   virtual Real minimum1(int& i) const;
+   Real Minimum1(int& i) const { return minimum1(i); }
+   virtual Real minimum2(int& i, int& j) const;
+   Real Minimum2(int& i, int& j) const { return minimum2(i,j); }
+   virtual Real trace() const;
+   Real Trace() const { return trace(); }
+   Real norm1() const;
+   Real Norm1() const { return norm1(); }
+   Real norm_infinity() const;
+   Real NormInfinity() const { return norm_infinity(); }
+   virtual MatrixBandWidth bandwidth() const;  // bandwidths of band matrix
+   virtual MatrixBandWidth BandWidth() const { return bandwidth(); }
+   void IEQND() const;                         // called by ineq. ops
+   ReturnMatrix sum_square_columns() const;
+   ReturnMatrix sum_square_rows() const;
+   ReturnMatrix sum_columns() const;
+   ReturnMatrix sum_rows() const;
+   virtual void cleanup() {}
+   void CleanUp() { cleanup(); }
+
+//   virtual ReturnMatrix Reverse() const;       // reverse order of elements
+//protected:
+//   BaseMatrix() : t(this), i(this) {}
+
+   friend class GeneralMatrix;
+   friend class Matrix;
+   friend class SquareMatrix;
+   friend class nricMatrix;
+   friend class RowVector;
+   friend class ColumnVector;
+   friend class SymmetricMatrix;
+   friend class UpperTriangularMatrix;
+   friend class LowerTriangularMatrix;
+   friend class DiagonalMatrix;
+   friend class CroutMatrix;
+   friend class BandMatrix;
+   friend class LowerBandMatrix;
+   friend class UpperBandMatrix;
+   friend class SymmetricBandMatrix;
+   friend class AddedMatrix;
+   friend class MultipliedMatrix;
+   friend class SubtractedMatrix;
+   friend class SPMatrix;
+   friend class KPMatrix;
+   friend class ConcatenatedMatrix;
+   friend class StackedMatrix;
+   friend class SolvedMatrix;
+   friend class ShiftedMatrix;
+   friend class NegShiftedMatrix;
+   friend class ScaledMatrix;
+   friend class TransposedMatrix;
+   friend class ReversedMatrix;
+   friend class NegatedMatrix;
+   friend class InvertedMatrix;
+   friend class RowedMatrix;
+   friend class ColedMatrix;
+   friend class DiagedMatrix;
+   friend class MatedMatrix;
+   friend class GetSubMatrix;
+   friend class ReturnMatrix;
+   friend class LinearEquationSolver;
+   friend class GenericMatrix;
+   NEW_DELETE(BaseMatrix)
+};
+
+
+// ***************************** working classes **************************/
+
+/// The classes for matrices that can contain data are derived from this.
+class GeneralMatrix : public BaseMatrix         // declarable matrix types
+{
+   virtual GeneralMatrix* Image() const;        // copy of matrix
+protected:
+   int tag_val;                                 // shows whether can reuse
+   int nrows_val, ncols_val;                    // dimensions
+   int storage;                                 // total store required
+   Real* store;                                 // point to store (0=not set)
+   GeneralMatrix();                             // initialise with no store
+   GeneralMatrix(ArrayLengthSpecifier);         // constructor getting store
+   void Add(GeneralMatrix*, Real);              // sum of GM and Real
+   void Add(Real);                              // add Real to this
+   void NegAdd(GeneralMatrix*, Real);           // Real - GM
+   void NegAdd(Real);                           // this = this - Real
+   void Multiply(GeneralMatrix*, Real);         // product of GM and Real
+   void Multiply(Real);                         // multiply this by Real
+   void Negate(GeneralMatrix*);                 // change sign
+   void Negate();                               // change sign
+   void ReverseElements();                      // internal reverse of elements
+   void ReverseElements(GeneralMatrix*);        // reverse order of elements
+   void operator=(Real);                        // set matrix to constant
+   Real* GetStore();                            // get store or copy
+   GeneralMatrix* BorrowStore(GeneralMatrix*, MatrixType);
+                                                // temporarily access store
+   void GetMatrix(const GeneralMatrix*);        // used by = and initialise
+   void Eq(const BaseMatrix&, MatrixType);      // used by =
+   void Eq(const GeneralMatrix&);               // version with no conversion
+   void Eq(const BaseMatrix&, MatrixType, bool);// used by <<
+   void Eq2(const BaseMatrix&, MatrixType);     // cut down version of Eq
+   int search(const BaseMatrix*) const;
+   virtual GeneralMatrix* Transpose(TransposedMatrix*, MatrixType);
+   void CheckConversion(const BaseMatrix&);     // check conversion OK
+   void resize(int, int, int);                  // change dimensions
+   virtual short SimpleAddOK(const GeneralMatrix*) { return 0; }
+             // see bandmat.cpp for explanation
+   virtual void MiniCleanUp()
+      { store = 0; storage = 0; nrows_val = 0; ncols_val = 0; tag_val = -1;}
+             // CleanUp when the data array has already been deleted
+   void PlusEqual(const GeneralMatrix& gm);
+   void MinusEqual(const GeneralMatrix& gm);
+   void PlusEqual(Real f);
+   void MinusEqual(Real f);
+   void swap(GeneralMatrix& gm);                // swap values
+public:
+   GeneralMatrix* Evaluate(MatrixType mt=MatrixTypeUnSp);
+   virtual MatrixType type() const = 0;         // type of a matrix
+   MatrixType Type() const { return type(); }
+   int Nrows() const { return nrows_val; }      // get dimensions
+   int Ncols() const { return ncols_val; }
+   int Storage() const { return storage; }
+   Real* Store() const { return store; }
+   // updated names
+   int nrows() const { return nrows_val; }      // get dimensions
+   int ncols() const { return ncols_val; }
+   int size() const { return storage; }
+   Real* data() { return store; }
+   const Real* data() const { return store; }
+   const Real* const_data() const { return store; }
+   virtual ~GeneralMatrix();                    // delete store if set
+   void tDelete();                              // delete if tag_val permits
+   bool reuse();                                // true if tag_val allows reuse
+   void protect() { tag_val=-1; }               // cannot delete or reuse
+   void Protect() { tag_val=-1; }               // cannot delete or reuse
+   int tag() const { return tag_val; }
+   int Tag() const { return tag_val; }
+   bool is_zero() const;                        // test matrix has all zeros
+   bool IsZero() const { return is_zero(); }    // test matrix has all zeros
+   void Release() { tag_val=1; }                // del store after next use
+   void Release(int t) { tag_val=t; }           // del store after t accesses
+   void ReleaseAndDelete() { tag_val=0; }       // delete matrix after use
+   void release() { tag_val=1; }                // del store after next use
+   void release(int t) { tag_val=t; }           // del store after t accesses
+   void release_and_delete() { tag_val=0; }     // delete matrix after use
+   void operator<<(const double*);              // assignment from an array
+   void operator<<(const float*);               // assignment from an array
+   void operator<<(const int*);                 // assignment from an array
+   void operator<<(const BaseMatrix& X)
+      { Eq(X,this->type(),true); }              // = without checking type
+   void inject(const GeneralMatrix&);           // copy stored els only
+   void Inject(const GeneralMatrix& GM) { inject(GM); }
+   void operator+=(const BaseMatrix&);
+   void operator-=(const BaseMatrix&);
+   void operator*=(const BaseMatrix&);
+   void operator|=(const BaseMatrix&);
+   void operator&=(const BaseMatrix&);
+   void operator+=(Real);
+   void operator-=(Real r) { operator+=(-r); }
+   void operator*=(Real);
+   void operator/=(Real r) { operator*=(1.0/r); }
+   virtual GeneralMatrix* MakeSolver();         // for solving
+   virtual void Solver(MatrixColX&, const MatrixColX&) {}
+   virtual void GetRow(MatrixRowCol&) = 0;      // Get matrix row
+   virtual void RestoreRow(MatrixRowCol&) {}    // Restore matrix row
+   virtual void NextRow(MatrixRowCol&);         // Go to next row
+   virtual void GetCol(MatrixRowCol&) = 0;      // Get matrix col
+   virtual void GetCol(MatrixColX&) = 0;        // Get matrix col
+   virtual void RestoreCol(MatrixRowCol&) {}    // Restore matrix col
+   virtual void RestoreCol(MatrixColX&) {}      // Restore matrix col
+   virtual void NextCol(MatrixRowCol&);         // Go to next col
+   virtual void NextCol(MatrixColX&);           // Go to next col
+   Real sum_square() const;
+   Real sum_absolute_value() const;
+   Real sum() const;
+   Real maximum_absolute_value1(int& i) const;
+   Real minimum_absolute_value1(int& i) const;
+   Real maximum1(int& i) const;
+   Real minimum1(int& i) const;
+   Real maximum_absolute_value() const;
+   Real maximum_absolute_value2(int& i, int& j) const;
+   Real minimum_absolute_value() const;
+   Real minimum_absolute_value2(int& i, int& j) const;
+   Real maximum() const;
+   Real maximum2(int& i, int& j) const;
+   Real minimum() const;
+   Real minimum2(int& i, int& j) const;
+   LogAndSign log_determinant() const;
+   virtual bool IsEqual(const GeneralMatrix&) const;
+                                                // same type, same values
+   void CheckStore() const;                     // check store is non-zero
+   virtual void SetParameters(const GeneralMatrix*) {}
+                                                // set parameters in GetMatrix
+   operator ReturnMatrix() const;               // for building a ReturnMatrix
+   ReturnMatrix for_return() const;
+   ReturnMatrix ForReturn() const;
+   //virtual bool SameStorageType(const GeneralMatrix& A) const;
+   //virtual void ReSizeForAdd(const GeneralMatrix& A, const GeneralMatrix& B);
+   //virtual void ReSizeForSP(const GeneralMatrix& A, const GeneralMatrix& B);
+   virtual void resize(const GeneralMatrix& A);
+   virtual void ReSize(const GeneralMatrix& A) { resize(A); }
+   MatrixInput operator<<(double);                // for loading a list
+   MatrixInput operator<<(float);                // for loading a list
+   MatrixInput operator<<(int f);
+//   ReturnMatrix Reverse() const;                // reverse order of elements
+   void cleanup();                              // to clear store
+
+   friend class Matrix;
+   friend class SquareMatrix;
+   friend class nricMatrix;
+   friend class SymmetricMatrix;
+   friend class UpperTriangularMatrix;
+   friend class LowerTriangularMatrix;
+   friend class DiagonalMatrix;
+   friend class CroutMatrix;
+   friend class RowVector;
+   friend class ColumnVector;
+   friend class BandMatrix;
+   friend class LowerBandMatrix;
+   friend class UpperBandMatrix;
+   friend class SymmetricBandMatrix;
+   friend class BaseMatrix;
+   friend class AddedMatrix;
+   friend class MultipliedMatrix;
+   friend class SubtractedMatrix;
+   friend class SPMatrix;
+   friend class KPMatrix;
+   friend class ConcatenatedMatrix;
+   friend class StackedMatrix;
+   friend class SolvedMatrix;
+   friend class ShiftedMatrix;
+   friend class NegShiftedMatrix;
+   friend class ScaledMatrix;
+   friend class TransposedMatrix;
+   friend class ReversedMatrix;
+   friend class NegatedMatrix;
+   friend class InvertedMatrix;
+   friend class RowedMatrix;
+   friend class ColedMatrix;
+   friend class DiagedMatrix;
+   friend class MatedMatrix;
+   friend class GetSubMatrix;
+   friend class ReturnMatrix;
+   friend class LinearEquationSolver;
+   friend class GenericMatrix;
+   NEW_DELETE(GeneralMatrix)
+};
+
+
+/// The usual rectangular matrix.
+class Matrix : public GeneralMatrix
+{
+   GeneralMatrix* Image() const;                // copy of matrix
+public:
+   Matrix() {}
+   ~Matrix() {}
+   Matrix(int, int);                            // standard declaration
+   Matrix(const BaseMatrix&);                   // evaluate BaseMatrix
+   void operator=(const BaseMatrix&);
+   void operator=(Real f) { GeneralMatrix::operator=(f); }
+   void operator=(const Matrix& m) { Eq(m); }
+   MatrixType type() const;
+   Real& operator()(int, int);                  // access element
+   Real& element(int, int);                     // access element
+   Real operator()(int, int) const;             // access element
+   Real element(int, int) const;                // access element
+#ifdef SETUP_C_SUBSCRIPTS
+   Real* operator[](int m) { return store+m*ncols_val; }
+   const Real* operator[](int m) const { return store+m*ncols_val; }
+   // following for Numerical Recipes in C++
+   Matrix(Real, int, int);
+   Matrix(const Real*, int, int);
+#endif
+   Matrix(const Matrix& gm) : GeneralMatrix() { GetMatrix(&gm); }
+   GeneralMatrix* MakeSolver();
+   Real trace() const;
+   void GetRow(MatrixRowCol&);
+   void GetCol(MatrixRowCol&);
+   void GetCol(MatrixColX&);
+   void RestoreCol(MatrixRowCol&);
+   void RestoreCol(MatrixColX&);
+   void NextRow(MatrixRowCol&);
+   void NextCol(MatrixRowCol&);
+   void NextCol(MatrixColX&);
+   virtual void resize(int,int);           // change dimensions
+      // virtual so we will catch it being used in a vector called as a matrix
+   virtual void resize_keep(int,int);
+   virtual void ReSize(int m, int n) { resize(m, n); }
+   void resize(const GeneralMatrix& A);
+   void ReSize(const GeneralMatrix& A) { resize(A); }
+   Real maximum_absolute_value2(int& i, int& j) const;
+   Real minimum_absolute_value2(int& i, int& j) const;
+   Real maximum2(int& i, int& j) const;
+   Real minimum2(int& i, int& j) const;
+   void operator+=(const Matrix& M) { PlusEqual(M); }
+   void operator-=(const Matrix& M) { MinusEqual(M); }
+   void operator+=(Real f) { GeneralMatrix::Add(f); }
+   void operator-=(Real f) { GeneralMatrix::Add(-f); }
+   void swap(Matrix& gm) { GeneralMatrix::swap((GeneralMatrix&)gm); }
+   friend Real dotproduct(const Matrix& A, const Matrix& B);
+   NEW_DELETE(Matrix)
+};
+
+/// Square matrix.
+class SquareMatrix : public Matrix
+{
+   GeneralMatrix* Image() const;                // copy of matrix
+public:
+   SquareMatrix() {}
+   ~SquareMatrix() {}
+   SquareMatrix(ArrayLengthSpecifier);          // standard declaration
+   SquareMatrix(const BaseMatrix&);             // evaluate BaseMatrix
+   void operator=(const BaseMatrix&);
+   void operator=(Real f) { GeneralMatrix::operator=(f); }
+   void operator=(const SquareMatrix& m) { Eq(m); }
+   void operator=(const Matrix& m);
+   MatrixType type() const;
+   SquareMatrix(const SquareMatrix& gm) : Matrix() { GetMatrix(&gm); }
+   SquareMatrix(const Matrix& gm);
+   void resize(int);                            // change dimensions
+   void ReSize(int m) { resize(m); }
+   void resize_keep(int);
+   void resize_keep(int,int);
+   void resize(int,int);                        // change dimensions
+   void ReSize(int m, int n) { resize(m, n); }
+   void resize(const GeneralMatrix& A);
+   void ReSize(const GeneralMatrix& A) { resize(A); }
+   void operator+=(const Matrix& M) { PlusEqual(M); }
+   void operator-=(const Matrix& M) { MinusEqual(M); }
+   void operator+=(Real f) { GeneralMatrix::Add(f); }
+   void operator-=(Real f) { GeneralMatrix::Add(-f); }
+   void swap(SquareMatrix& gm) { GeneralMatrix::swap((GeneralMatrix&)gm); }
+   NEW_DELETE(SquareMatrix)
+};
+
+/// Rectangular matrix for use with Numerical Recipes in C.
+class nricMatrix : public Matrix
+{
+   GeneralMatrix* Image() const;                // copy of matrix
+   Real** row_pointer;                          // points to rows
+   void MakeRowPointer();                       // build rowpointer
+   void DeleteRowPointer();
+public:
+   nricMatrix() {}
+   nricMatrix(int m, int n)                     // standard declaration
+      :  Matrix(m,n) { MakeRowPointer(); }
+   nricMatrix(const BaseMatrix& bm)             // evaluate BaseMatrix
+      :  Matrix(bm) { MakeRowPointer(); }
+   void operator=(const BaseMatrix& bm)
+      { DeleteRowPointer(); Matrix::operator=(bm); MakeRowPointer(); }
+   void operator=(Real f) { GeneralMatrix::operator=(f); }
+   void operator=(const nricMatrix& m)
+      { DeleteRowPointer(); Eq(m); MakeRowPointer(); }
+   void operator<<(const BaseMatrix& X)
+      { DeleteRowPointer(); Eq(X,this->type(),true); MakeRowPointer(); }
+   nricMatrix(const nricMatrix& gm) : Matrix()
+      { GetMatrix(&gm); MakeRowPointer(); }
+   void resize(int m, int n)               // change dimensions
+      { DeleteRowPointer(); Matrix::resize(m,n); MakeRowPointer(); }
+   void resize_keep(int m, int n)               // change dimensions
+      { DeleteRowPointer(); Matrix::resize_keep(m,n); MakeRowPointer(); }
+   void ReSize(int m, int n)               // change dimensions
+      { DeleteRowPointer(); Matrix::resize(m,n); MakeRowPointer(); }
+   void resize(const GeneralMatrix& A);
+   void ReSize(const GeneralMatrix& A) { resize(A); }
+   ~nricMatrix() { DeleteRowPointer(); }
+   Real** nric() const { CheckStore(); return row_pointer-1; }
+   void cleanup();                                // to clear store
+   void MiniCleanUp();
+   void operator+=(const Matrix& M) { PlusEqual(M); }
+   void operator-=(const Matrix& M) { MinusEqual(M); }
+   void operator+=(Real f) { GeneralMatrix::Add(f); }
+   void operator-=(Real f) { GeneralMatrix::Add(-f); }
+   void swap(nricMatrix& gm);
+   NEW_DELETE(nricMatrix)
+};
+
+/// Symmetric matrix.
+class SymmetricMatrix : public GeneralMatrix
+{
+   GeneralMatrix* Image() const;                // copy of matrix
+public:
+   SymmetricMatrix() {}
+   ~SymmetricMatrix() {}
+   SymmetricMatrix(ArrayLengthSpecifier);
+   SymmetricMatrix(const BaseMatrix&);
+   void operator=(const BaseMatrix&);
+   void operator=(Real f) { GeneralMatrix::operator=(f); }
+   void operator=(const SymmetricMatrix& m) { Eq(m); }
+   Real& operator()(int, int);                  // access element
+   Real& element(int, int);                     // access element
+   Real operator()(int, int) const;             // access element
+   Real element(int, int) const;                // access element
+#ifdef SETUP_C_SUBSCRIPTS
+   Real* operator[](int m) { return store+(m*(m+1))/2; }
+   const Real* operator[](int m) const { return store+(m*(m+1))/2; }
+#endif
+   MatrixType type() const;
+   SymmetricMatrix(const SymmetricMatrix& gm)
+      : GeneralMatrix() { GetMatrix(&gm); }
+   Real sum_square() const;
+   Real sum_absolute_value() const;
+   Real sum() const;
+   Real trace() const;
+   void GetRow(MatrixRowCol&);
+   void GetCol(MatrixRowCol&);
+   void GetCol(MatrixColX&);
+   void RestoreCol(MatrixRowCol&) {}
+   void RestoreCol(MatrixColX&);
+   GeneralMatrix* Transpose(TransposedMatrix*, MatrixType);
+   void resize(int);                           // change dimensions
+   void ReSize(int m) { resize(m); }
+   void resize_keep(int);
+   void resize(const GeneralMatrix& A);
+   void ReSize(const GeneralMatrix& A) { resize(A); }
+   void operator+=(const SymmetricMatrix& M) { PlusEqual(M); }
+   void operator-=(const SymmetricMatrix& M) { MinusEqual(M); }
+   void operator+=(Real f) { GeneralMatrix::Add(f); }
+   void operator-=(Real f) { GeneralMatrix::Add(-f); }
+   void swap(SymmetricMatrix& gm) { GeneralMatrix::swap((GeneralMatrix&)gm); }
+   NEW_DELETE(SymmetricMatrix)
+};
+
+/// Upper triangular matrix.
+class UpperTriangularMatrix : public GeneralMatrix
+{
+   GeneralMatrix* Image() const;                // copy of matrix
+public:
+   UpperTriangularMatrix() {}
+   ~UpperTriangularMatrix() {}
+   UpperTriangularMatrix(ArrayLengthSpecifier);
+   void operator=(const BaseMatrix&);
+   void operator=(const UpperTriangularMatrix& m) { Eq(m); }
+   UpperTriangularMatrix(const BaseMatrix&);
+   UpperTriangularMatrix(const UpperTriangularMatrix& gm)
+      : GeneralMatrix() { GetMatrix(&gm); }
+   void operator=(Real f) { GeneralMatrix::operator=(f); }
+   Real& operator()(int, int);                  // access element
+   Real& element(int, int);                     // access element
+   Real operator()(int, int) const;             // access element
+   Real element(int, int) const;                // access element
+#ifdef SETUP_C_SUBSCRIPTS
+   Real* operator[](int m) { return store+m*ncols_val-(m*(m+1))/2; }
+   const Real* operator[](int m) const
+      { return store+m*ncols_val-(m*(m+1))/2; }
+#endif
+   MatrixType type() const;
+   GeneralMatrix* MakeSolver() { return this; } // for solving
+   void Solver(MatrixColX&, const MatrixColX&);
+   LogAndSign log_determinant() const;
+   Real trace() const;
+   void GetRow(MatrixRowCol&);
+   void GetCol(MatrixRowCol&);
+   void GetCol(MatrixColX&);
+   void RestoreCol(MatrixRowCol&);
+   void RestoreCol(MatrixColX& c) { RestoreCol((MatrixRowCol&)c); }
+   void NextRow(MatrixRowCol&);
+   void resize(int);                       // change dimensions
+   void ReSize(int m) { resize(m); }
+   void resize(const GeneralMatrix& A);
+   void ReSize(const GeneralMatrix& A) { resize(A); }
+   void resize_keep(int);
+   MatrixBandWidth bandwidth() const;
+   void operator+=(const UpperTriangularMatrix& M) { PlusEqual(M); }
+   void operator-=(const UpperTriangularMatrix& M) { MinusEqual(M); }
+   void operator+=(Real f) { GeneralMatrix::operator+=(f); }
+   void operator-=(Real f) { GeneralMatrix::operator-=(f); }
+   void swap(UpperTriangularMatrix& gm)
+      { GeneralMatrix::swap((GeneralMatrix&)gm); }
+   NEW_DELETE(UpperTriangularMatrix)
+};
+
+/// Lower triangular matrix.
+class LowerTriangularMatrix : public GeneralMatrix
+{
+   GeneralMatrix* Image() const;                // copy of matrix
+public:
+   LowerTriangularMatrix() {}
+   ~LowerTriangularMatrix() {}
+   LowerTriangularMatrix(ArrayLengthSpecifier);
+   LowerTriangularMatrix(const LowerTriangularMatrix& gm)
+      : GeneralMatrix() { GetMatrix(&gm); }
+   LowerTriangularMatrix(const BaseMatrix& M);
+   void operator=(const BaseMatrix&);
+   void operator=(Real f) { GeneralMatrix::operator=(f); }
+   void operator=(const LowerTriangularMatrix& m) { Eq(m); }
+   Real& operator()(int, int);                  // access element
+   Real& element(int, int);                     // access element
+   Real operator()(int, int) const;             // access element
+   Real element(int, int) const;                // access element
+#ifdef SETUP_C_SUBSCRIPTS
+   Real* operator[](int m) { return store+(m*(m+1))/2; }
+   const Real* operator[](int m) const { return store+(m*(m+1))/2; }
+#endif
+   MatrixType type() const;
+   GeneralMatrix* MakeSolver() { return this; } // for solving
+   void Solver(MatrixColX&, const MatrixColX&);
+   LogAndSign log_determinant() const;
+   Real trace() const;
+   void GetRow(MatrixRowCol&);
+   void GetCol(MatrixRowCol&);
+   void GetCol(MatrixColX&);
+   void RestoreCol(MatrixRowCol&);
+   void RestoreCol(MatrixColX& c) { RestoreCol((MatrixRowCol&)c); }
+   void NextRow(MatrixRowCol&);
+   void resize(int);                       // change dimensions
+   void ReSize(int m) { resize(m); }
+   void resize_keep(int);
+   void resize(const GeneralMatrix& A);
+   void ReSize(const GeneralMatrix& A) { resize(A); }
+   MatrixBandWidth bandwidth() const;
+   void operator+=(const LowerTriangularMatrix& M) { PlusEqual(M); }
+   void operator-=(const LowerTriangularMatrix& M) { MinusEqual(M); }
+   void operator+=(Real f) { GeneralMatrix::operator+=(f); }
+   void operator-=(Real f) { GeneralMatrix::operator-=(f); }
+   void swap(LowerTriangularMatrix& gm)
+      { GeneralMatrix::swap((GeneralMatrix&)gm); }
+   NEW_DELETE(LowerTriangularMatrix)
+};
+
+/// Diagonal matrix.
+class DiagonalMatrix : public GeneralMatrix
+{
+   GeneralMatrix* Image() const;                // copy of matrix
+public:
+   DiagonalMatrix() {}
+   ~DiagonalMatrix() {}
+   DiagonalMatrix(ArrayLengthSpecifier);
+   DiagonalMatrix(const BaseMatrix&);
+   DiagonalMatrix(const DiagonalMatrix& gm)
+      : GeneralMatrix() { GetMatrix(&gm); }
+   void operator=(const BaseMatrix&);
+   void operator=(Real f) { GeneralMatrix::operator=(f); }
+   void operator=(const DiagonalMatrix& m) { Eq(m); }
+   Real& operator()(int, int);                  // access element
+   Real& operator()(int);                       // access element
+   Real operator()(int, int) const;             // access element
+   Real operator()(int) const;
+   Real& element(int, int);                     // access element
+   Real& element(int);                          // access element
+   Real element(int, int) const;                // access element
+   Real element(int) const;                     // access element
+#ifdef SETUP_C_SUBSCRIPTS
+   Real& operator[](int m) { return store[m]; }
+   const Real& operator[](int m) const { return store[m]; }
+#endif
+   MatrixType type() const;
+
+   LogAndSign log_determinant() const;
+   Real trace() const;
+   void GetRow(MatrixRowCol&);
+   void GetCol(MatrixRowCol&);
+   void GetCol(MatrixColX&);
+   void NextRow(MatrixRowCol&);
+   void NextCol(MatrixRowCol&);
+   void NextCol(MatrixColX&);
+   GeneralMatrix* MakeSolver() { return this; } // for solving
+   void Solver(MatrixColX&, const MatrixColX&);
+   GeneralMatrix* Transpose(TransposedMatrix*, MatrixType);
+   void resize(int);                       // change dimensions
+   void ReSize(int m) { resize(m); }
+   void resize_keep(int);
+   void resize(const GeneralMatrix& A);
+   void ReSize(const GeneralMatrix& A) { resize(A); }
+   Real* nric() const
+      { CheckStore(); return store-1; }         // for use by NRIC
+   MatrixBandWidth bandwidth() const;
+//   ReturnMatrix Reverse() const;                // reverse order of elements
+   void operator+=(const DiagonalMatrix& M) { PlusEqual(M); }
+   void operator-=(const DiagonalMatrix& M) { MinusEqual(M); }
+   void operator+=(Real f) { GeneralMatrix::operator+=(f); }
+   void operator-=(Real f) { GeneralMatrix::operator-=(f); }
+   void swap(DiagonalMatrix& gm)
+      { GeneralMatrix::swap((GeneralMatrix&)gm); }
+   NEW_DELETE(DiagonalMatrix)
+};
+
+/// Row vector.
+class RowVector : public Matrix
+{
+   GeneralMatrix* Image() const;                // copy of matrix
+public:
+   RowVector() { nrows_val = 1; }
+   ~RowVector() {}
+   RowVector(ArrayLengthSpecifier n) : Matrix(1,n.Value()) {}
+   RowVector(const BaseMatrix&);
+   RowVector(const RowVector& gm) : Matrix() { GetMatrix(&gm); }
+   void operator=(const BaseMatrix&);
+   void operator=(Real f) { GeneralMatrix::operator=(f); }
+   void operator=(const RowVector& m) { Eq(m); }
+   Real& operator()(int);                       // access element
+   Real& element(int);                          // access element
+   Real operator()(int) const;                  // access element
+   Real element(int) const;                     // access element
+#ifdef SETUP_C_SUBSCRIPTS
+   Real& operator[](int m) { return store[m]; }
+   const Real& operator[](int m) const { return store[m]; }
+   // following for Numerical Recipes in C++
+   RowVector(Real a, int n) : Matrix(a, 1, n) {}
+   RowVector(const Real* a, int n) : Matrix(a, 1, n) {}
+#endif
+   MatrixType type() const;
+   void GetCol(MatrixRowCol&);
+   void GetCol(MatrixColX&);
+   void NextCol(MatrixRowCol&);
+   void NextCol(MatrixColX&);
+   void RestoreCol(MatrixRowCol&) {}
+   void RestoreCol(MatrixColX& c);
+   GeneralMatrix* Transpose(TransposedMatrix*, MatrixType);
+   void resize(int);                       // change dimensions
+   void ReSize(int m) { resize(m); }
+   void resize_keep(int);
+   void resize_keep(int,int);
+   void resize(int,int);                   // in case access is matrix
+   void ReSize(int m,int n) { resize(m, n); }
+   void resize(const GeneralMatrix& A);
+   void ReSize(const GeneralMatrix& A) { resize(A); }
+   Real* nric() const
+      { CheckStore(); return store-1; }         // for use by NRIC
+   void cleanup();                              // to clear store
+   void MiniCleanUp()
+      { store = 0; storage = 0; nrows_val = 1; ncols_val = 0; tag_val = -1; }
+   // friend ReturnMatrix GetMatrixRow(Matrix& A, int row);
+   void operator+=(const Matrix& M) { PlusEqual(M); }
+   void operator-=(const Matrix& M) { MinusEqual(M); }
+   void operator+=(Real f) { GeneralMatrix::Add(f); }
+   void operator-=(Real f) { GeneralMatrix::Add(-f); }
+   void swap(RowVector& gm)
+      { GeneralMatrix::swap((GeneralMatrix&)gm); }
+   NEW_DELETE(RowVector)
+};
+
+/// Column vector.
+class ColumnVector : public Matrix
+{
+   GeneralMatrix* Image() const;                // copy of matrix
+public:
+   ColumnVector() { ncols_val = 1; }
+   ~ColumnVector() {}
+   ColumnVector(ArrayLengthSpecifier n) : Matrix(n.Value(),1) {}
+   ColumnVector(const BaseMatrix&);
+   ColumnVector(const ColumnVector& gm) : Matrix() { GetMatrix(&gm); }
+   void operator=(const BaseMatrix&);
+   void operator=(Real f) { GeneralMatrix::operator=(f); }
+   void operator=(const ColumnVector& m) { Eq(m); }
+   Real& operator()(int);                       // access element
+   Real& element(int);                          // access element
+   Real operator()(int) const;                  // access element
+   Real element(int) const;                     // access element
+#ifdef SETUP_C_SUBSCRIPTS
+   Real& operator[](int m) { return store[m]; }
+   const Real& operator[](int m) const { return store[m]; }
+   // following for Numerical Recipes in C++
+   ColumnVector(Real a, int m) : Matrix(a, m, 1) {}
+   ColumnVector(const Real* a, int m) : Matrix(a, m, 1) {}
+#endif
+   MatrixType type() const;
+   GeneralMatrix* Transpose(TransposedMatrix*, MatrixType);
+   void resize(int);                       // change dimensions
+   void ReSize(int m) { resize(m); }
+   void resize_keep(int);
+   void resize_keep(int,int);
+   void resize(int,int);                   // in case access is matrix
+   void ReSize(int m,int n) { resize(m, n); }
+   void resize(const GeneralMatrix& A);
+   void ReSize(const GeneralMatrix& A) { resize(A); }
+   Real* nric() const
+      { CheckStore(); return store-1; }         // for use by NRIC
+   void cleanup();                              // to clear store
+   void MiniCleanUp()
+      { store = 0; storage = 0; nrows_val = 0; ncols_val = 1; tag_val = -1; }
+//   ReturnMatrix Reverse() const;                // reverse order of elements
+   void operator+=(const Matrix& M) { PlusEqual(M); }
+   void operator-=(const Matrix& M) { MinusEqual(M); }
+   void operator+=(Real f) { GeneralMatrix::Add(f); }
+   void operator-=(Real f) { GeneralMatrix::Add(-f); }
+   void swap(ColumnVector& gm)
+      { GeneralMatrix::swap((GeneralMatrix&)gm); }
+   NEW_DELETE(ColumnVector)
+};
+
+/// LU matrix.
+/// A square matrix decomposed into upper and lower triangular
+/// in preparation for inverting or solving equations.
+class CroutMatrix : public GeneralMatrix
+{
+   int* indx;
+   bool d;                              // number of row swaps = even or odd
+   bool sing;
+   void ludcmp();
+   void get_aux(CroutMatrix&);                  // for copying indx[] etc
+   GeneralMatrix* Image() const;                // copy of matrix
+public:
+   CroutMatrix(const BaseMatrix&);
+   CroutMatrix() : indx(0), d(true), sing(true) {}
+   CroutMatrix(const CroutMatrix&);
+   void operator=(const CroutMatrix&);
+   GeneralMatrix* Evaluate(MatrixType mt=MatrixTypeUnSp);
+   MatrixType type() const;
+   void lubksb(Real*, int=0);
+   ~CroutMatrix();
+   GeneralMatrix* MakeSolver() { return this; } // for solving
+   LogAndSign log_determinant() const;
+   void Solver(MatrixColX&, const MatrixColX&);
+   void GetRow(MatrixRowCol&);
+   void GetCol(MatrixRowCol&);
+   void GetCol(MatrixColX& c) { GetCol((MatrixRowCol&)c); }
+   void cleanup();                                // to clear store
+   void MiniCleanUp();
+   bool IsEqual(const GeneralMatrix&) const;
+   bool is_singular() const { return sing; }
+   bool IsSingular() const { return sing; }
+   const int* const_data_indx() const { return indx; }
+   bool even_exchanges() const { return d; }
+   void swap(CroutMatrix& gm);
+   NEW_DELETE(CroutMatrix)
+};
+
+// ***************************** band matrices ***************************/
+
+/// Band matrix.
+class BandMatrix : public GeneralMatrix
+{
+   GeneralMatrix* Image() const;                // copy of matrix
+protected:
+   void CornerClear() const;                    // set unused elements to zero
+   short SimpleAddOK(const GeneralMatrix* gm);
+public:
+   int lower_val, upper_val;                            // band widths
+   BandMatrix() { lower_val=0; upper_val=0; CornerClear(); }
+   ~BandMatrix() {}
+   BandMatrix(int n,int lb,int ub) { resize(n,lb,ub); CornerClear(); }
+                                                // standard declaration
+   BandMatrix(const BaseMatrix&);               // evaluate BaseMatrix
+   void operator=(const BaseMatrix&);
+   void operator=(Real f) { GeneralMatrix::operator=(f); }
+   void operator=(const BandMatrix& m) { Eq(m); }
+   MatrixType type() const;
+   Real& operator()(int, int);                  // access element
+   Real& element(int, int);                     // access element
+   Real operator()(int, int) const;             // access element
+   Real element(int, int) const;                // access element
+#ifdef SETUP_C_SUBSCRIPTS
+   Real* operator[](int m) { return store+(upper_val+lower_val)*m+lower_val; }
+   const Real* operator[](int m) const
+      { return store+(upper_val+lower_val)*m+lower_val; }
+#endif
+   BandMatrix(const BandMatrix& gm) : GeneralMatrix() { GetMatrix(&gm); }
+   LogAndSign log_determinant() const;
+   GeneralMatrix* MakeSolver();
+   Real trace() const;
+   Real sum_square() const
+      { CornerClear(); return GeneralMatrix::sum_square(); }
+   Real sum_absolute_value() const
+      { CornerClear(); return GeneralMatrix::sum_absolute_value(); }
+   Real sum() const
+      { CornerClear(); return GeneralMatrix::sum(); }
+   Real maximum_absolute_value() const
+      { CornerClear(); return GeneralMatrix::maximum_absolute_value(); }
+   Real minimum_absolute_value() const
+      { int i, j; return GeneralMatrix::minimum_absolute_value2(i, j); }
+   Real maximum() const { int i, j; return GeneralMatrix::maximum2(i, j); }
+   Real minimum() const { int i, j; return GeneralMatrix::minimum2(i, j); }
+   void GetRow(MatrixRowCol&);
+   void GetCol(MatrixRowCol&);
+   void GetCol(MatrixColX&);
+   void RestoreCol(MatrixRowCol&);
+   void RestoreCol(MatrixColX& c) { RestoreCol((MatrixRowCol&)c); }
+   void NextRow(MatrixRowCol&);
+   virtual void resize(int, int, int);             // change dimensions
+   virtual void ReSize(int m, int n, int b) { resize(m, n, b); }
+   void resize(const GeneralMatrix& A);
+   void ReSize(const GeneralMatrix& A) { resize(A); }
+   //bool SameStorageType(const GeneralMatrix& A) const;
+   //void ReSizeForAdd(const GeneralMatrix& A, const GeneralMatrix& B);
+   //void ReSizeForSP(const GeneralMatrix& A, const GeneralMatrix& B);
+   MatrixBandWidth bandwidth() const;
+   void SetParameters(const GeneralMatrix*);
+   MatrixInput operator<<(double);                // will give error
+   MatrixInput operator<<(float);                // will give error
+   MatrixInput operator<<(int f);
+   void operator<<(const double* r);              // will give error
+   void operator<<(const float* r);              // will give error
+   void operator<<(const int* r);               // will give error
+      // the next is included because Zortech and Borland
+      // cannot find the copy in GeneralMatrix
+   void operator<<(const BaseMatrix& X) { GeneralMatrix::operator<<(X); }
+   void swap(BandMatrix& gm);
+   NEW_DELETE(BandMatrix)
+};
+
+/// Upper triangular band matrix.
+class UpperBandMatrix : public BandMatrix
+{
+   GeneralMatrix* Image() const;                // copy of matrix
+public:
+   UpperBandMatrix() {}
+   ~UpperBandMatrix() {}
+   UpperBandMatrix(int n, int ubw)              // standard declaration
+      : BandMatrix(n, 0, ubw) {}
+   UpperBandMatrix(const BaseMatrix&);          // evaluate BaseMatrix
+   void operator=(const BaseMatrix&);
+   void operator=(Real f) { GeneralMatrix::operator=(f); }
+   void operator=(const UpperBandMatrix& m) { Eq(m); }
+   MatrixType type() const;
+   UpperBandMatrix(const UpperBandMatrix& gm) : BandMatrix() { GetMatrix(&gm); }
+   GeneralMatrix* MakeSolver() { return this; }
+   void Solver(MatrixColX&, const MatrixColX&);
+   LogAndSign log_determinant() const;
+   void resize(int, int, int);             // change dimensions
+   void ReSize(int m, int n, int b) { resize(m, n, b); }
+   void resize(int n,int ubw)              // change dimensions
+      { BandMatrix::resize(n,0,ubw); }
+   void ReSize(int n,int ubw)              // change dimensions
+      { BandMatrix::resize(n,0,ubw); }
+   void resize(const GeneralMatrix& A) { BandMatrix::resize(A); }
+   void ReSize(const GeneralMatrix& A) { BandMatrix::resize(A); }
+   Real& operator()(int, int);
+   Real operator()(int, int) const;
+   Real& element(int, int);
+   Real element(int, int) const;
+#ifdef SETUP_C_SUBSCRIPTS
+   Real* operator[](int m) { return store+upper_val*m; }
+   const Real* operator[](int m) const { return store+upper_val*m; }
+#endif
+   void swap(UpperBandMatrix& gm)
+      { BandMatrix::swap((BandMatrix&)gm); }
+   NEW_DELETE(UpperBandMatrix)
+};
+
+/// Lower triangular band matrix.
+class LowerBandMatrix : public BandMatrix
+{
+   GeneralMatrix* Image() const;                // copy of matrix
+public:
+   LowerBandMatrix() {}
+   ~LowerBandMatrix() {}
+   LowerBandMatrix(int n, int lbw)              // standard declaration
+      : BandMatrix(n, lbw, 0) {}
+   LowerBandMatrix(const BaseMatrix&);          // evaluate BaseMatrix
+   void operator=(const BaseMatrix&);
+   void operator=(Real f) { GeneralMatrix::operator=(f); }
+   void operator=(const LowerBandMatrix& m) { Eq(m); }
+   MatrixType type() const;
+   LowerBandMatrix(const LowerBandMatrix& gm) : BandMatrix() { GetMatrix(&gm); }
+   GeneralMatrix* MakeSolver() { return this; }
+   void Solver(MatrixColX&, const MatrixColX&);
+   LogAndSign log_determinant() const;
+   void resize(int, int, int);             // change dimensions
+   void ReSize(int m, int n, int b) { resize(m, n, b); }
+   void resize(int n,int lbw)             // change dimensions
+      { BandMatrix::resize(n,lbw,0); }
+   void ReSize(int n,int lbw)             // change dimensions
+      { BandMatrix::resize(n,lbw,0); }
+   void resize(const GeneralMatrix& A) { BandMatrix::resize(A); }
+   void ReSize(const GeneralMatrix& A) { BandMatrix::resize(A); }
+   Real& operator()(int, int);
+   Real operator()(int, int) const;
+   Real& element(int, int);
+   Real element(int, int) const;
+#ifdef SETUP_C_SUBSCRIPTS
+   Real* operator[](int m) { return store+lower_val*(m+1); }
+   const Real* operator[](int m) const { return store+lower_val*(m+1); }
+#endif
+   void swap(LowerBandMatrix& gm)
+      { BandMatrix::swap((BandMatrix&)gm); }
+   NEW_DELETE(LowerBandMatrix)
+};
+
+/// Symmetric band matrix.
+class SymmetricBandMatrix : public GeneralMatrix
+{
+   GeneralMatrix* Image() const;                // copy of matrix
+   void CornerClear() const;                    // set unused elements to zero
+   short SimpleAddOK(const GeneralMatrix* gm);
+public:
+   int lower_val;                                   // lower band width
+   SymmetricBandMatrix() { lower_val=0; CornerClear(); }
+   ~SymmetricBandMatrix() {}
+   SymmetricBandMatrix(int n, int lb) { resize(n,lb); CornerClear(); }
+   SymmetricBandMatrix(const BaseMatrix&);
+   void operator=(const BaseMatrix&);
+   void operator=(Real f) { GeneralMatrix::operator=(f); }
+   void operator=(const SymmetricBandMatrix& m) { Eq(m); }
+   Real& operator()(int, int);                  // access element
+   Real& element(int, int);                     // access element
+   Real operator()(int, int) const;             // access element
+   Real element(int, int) const;                // access element
+#ifdef SETUP_C_SUBSCRIPTS
+   Real* operator[](int m) { return store+lower_val*(m+1); }
+   const Real* operator[](int m) const { return store+lower_val*(m+1); }
+#endif
+   MatrixType type() const;
+   SymmetricBandMatrix(const SymmetricBandMatrix& gm)
+      : GeneralMatrix() { GetMatrix(&gm); }
+   GeneralMatrix* MakeSolver();
+   Real sum_square() const;
+   Real sum_absolute_value() const;
+   Real sum() const;
+   Real maximum_absolute_value() const
+      { CornerClear(); return GeneralMatrix::maximum_absolute_value(); }
+   Real minimum_absolute_value() const
+      { int i, j; return GeneralMatrix::minimum_absolute_value2(i, j); }
+   Real maximum() const { int i, j; return GeneralMatrix::maximum2(i, j); }
+   Real minimum() const { int i, j; return GeneralMatrix::minimum2(i, j); }
+   Real trace() const;
+   LogAndSign log_determinant() const;
+   void GetRow(MatrixRowCol&);
+   void GetCol(MatrixRowCol&);
+   void GetCol(MatrixColX&);
+   void RestoreCol(MatrixRowCol&) {}
+   void RestoreCol(MatrixColX&);
+   GeneralMatrix* Transpose(TransposedMatrix*, MatrixType);
+   void resize(int,int);                       // change dimensions
+   void ReSize(int m,int b) { resize(m, b); }
+   void resize(const GeneralMatrix& A);
+   void ReSize(const GeneralMatrix& A) { resize(A); }
+   //bool SameStorageType(const GeneralMatrix& A) const;
+   //void ReSizeForAdd(const GeneralMatrix& A, const GeneralMatrix& B);
+   //void ReSizeForSP(const GeneralMatrix& A, const GeneralMatrix& B);
+   MatrixBandWidth bandwidth() const;
+   void SetParameters(const GeneralMatrix*);
+   void operator<<(const double* r);              // will give error
+   void operator<<(const float* r);              // will give error
+   void operator<<(const int* r);               // will give error
+   void operator<<(const BaseMatrix& X) { GeneralMatrix::operator<<(X); }
+   void swap(SymmetricBandMatrix& gm);
+   NEW_DELETE(SymmetricBandMatrix)
+};
+
+/// LU decomposition of a band matrix.
+class BandLUMatrix : public GeneralMatrix
+{
+   int* indx;
+   bool d;
+   bool sing;                                   // true if singular
+   Real* store2;
+   int storage2;
+   int m1,m2;                                   // lower and upper
+   void ludcmp();
+   void get_aux(BandLUMatrix&);                 // for copying indx[] etc
+   GeneralMatrix* Image() const;                // copy of matrix
+public:
+   BandLUMatrix(const BaseMatrix&);
+   BandLUMatrix()
+     : indx(0), d(true), sing(true), store2(0), storage2(0), m1(0), m2(0) {}
+   BandLUMatrix(const BandLUMatrix&);
+   void operator=(const BandLUMatrix&);
+   GeneralMatrix* Evaluate(MatrixType mt=MatrixTypeUnSp);
+   MatrixType type() const;
+   void lubksb(Real*, int=0);
+   ~BandLUMatrix();
+   GeneralMatrix* MakeSolver() { return this; } // for solving
+   LogAndSign log_determinant() const;
+   void Solver(MatrixColX&, const MatrixColX&);
+   void GetRow(MatrixRowCol&);
+   void GetCol(MatrixRowCol&);
+   void GetCol(MatrixColX& c) { GetCol((MatrixRowCol&)c); }
+   void cleanup();                                // to clear store
+   void MiniCleanUp();
+   bool IsEqual(const GeneralMatrix&) const;
+   bool is_singular() const { return sing; }
+   bool IsSingular() const { return sing; }
+   const Real* const_data2() const { return store2; }
+   int size2() const { return storage2; }
+   const int* const_data_indx() const { return indx; }
+   bool even_exchanges() const { return d; }
+   MatrixBandWidth bandwidth() const;
+   void swap(BandLUMatrix& gm);
+   NEW_DELETE(BandLUMatrix)
+};
+
+// ************************** special matrices ****************************
+
+/// Identity matrix.
+class IdentityMatrix : public GeneralMatrix
+{
+   GeneralMatrix* Image() const;          // copy of matrix
+public:
+   IdentityMatrix() {}
+   ~IdentityMatrix() {}
+   IdentityMatrix(ArrayLengthSpecifier n) : GeneralMatrix(1)
+      { nrows_val = ncols_val = n.Value(); *store = 1; }
+   IdentityMatrix(const IdentityMatrix& gm)
+      : GeneralMatrix() { GetMatrix(&gm); }
+   IdentityMatrix(const BaseMatrix&);
+   void operator=(const BaseMatrix&);
+   void operator=(const IdentityMatrix& m) { Eq(m); }
+   void operator=(Real f) { GeneralMatrix::operator=(f); }
+   MatrixType type() const;
+
+   LogAndSign log_determinant() const;
+   Real trace() const;
+   Real sum_square() const;
+   Real sum_absolute_value() const;
+   Real sum() const { return trace(); }
+   void GetRow(MatrixRowCol&);
+   void GetCol(MatrixRowCol&);
+   void GetCol(MatrixColX&);
+   void NextRow(MatrixRowCol&);
+   void NextCol(MatrixRowCol&);
+   void NextCol(MatrixColX&);
+   GeneralMatrix* MakeSolver() { return this; } // for solving
+   void Solver(MatrixColX&, const MatrixColX&);
+   GeneralMatrix* Transpose(TransposedMatrix*, MatrixType);
+   void resize(int n);
+   void ReSize(int n) { resize(n); }
+   void resize(const GeneralMatrix& A);
+   void ReSize(const GeneralMatrix& A) { resize(A); }
+   MatrixBandWidth bandwidth() const;
+//   ReturnMatrix Reverse() const;                // reverse order of elements
+   void swap(IdentityMatrix& gm)
+      { GeneralMatrix::swap((GeneralMatrix&)gm); }
+   NEW_DELETE(IdentityMatrix)
+};
+
+
+
+
+// ************************** GenericMatrix class ************************/
+
+/// A matrix which can be of any GeneralMatrix type.
+class GenericMatrix : public BaseMatrix
+{
+   GeneralMatrix* gm;
+   int search(const BaseMatrix* bm) const;
+   friend class BaseMatrix;
+public:
+   GenericMatrix() : gm(0) {}
+   GenericMatrix(const BaseMatrix& bm)
+      { gm = ((BaseMatrix&)bm).Evaluate(); gm = gm->Image(); }
+   GenericMatrix(const GenericMatrix& bm) : BaseMatrix()
+      { gm = bm.gm->Image(); }
+   void operator=(const GenericMatrix&);
+   void operator=(const BaseMatrix&);
+   void operator+=(const BaseMatrix&);
+   void operator-=(const BaseMatrix&);
+   void operator*=(const BaseMatrix&);
+   void operator|=(const BaseMatrix&);
+   void operator&=(const BaseMatrix&);
+   void operator+=(Real);
+   void operator-=(Real r) { operator+=(-r); }
+   void operator*=(Real);
+   void operator/=(Real r) { operator*=(1.0/r); }
+   ~GenericMatrix() { delete gm; }
+   void cleanup() { delete gm; gm = 0; }
+   void Release() { gm->Release(); }
+   void release() { gm->release(); }
+   GeneralMatrix* Evaluate(MatrixType = MatrixTypeUnSp);
+   MatrixBandWidth bandwidth() const;
+   void swap(GenericMatrix& x);
+   NEW_DELETE(GenericMatrix)
+};
+
+// *************************** temporary classes *************************/
+
+/// Product of two matrices.
+/// \internal
+class MultipliedMatrix : public BaseMatrix
+{
+protected:
+   // if these union statements cause problems, simply remove them
+   // and declare the items individually
+   union { const BaseMatrix* bm1; GeneralMatrix* gm1; };
+						  // pointers to summands
+   union { const BaseMatrix* bm2; GeneralMatrix* gm2; };
+   MultipliedMatrix(const BaseMatrix* bm1x, const BaseMatrix* bm2x)
+      : bm1(bm1x),bm2(bm2x) {}
+   int search(const BaseMatrix*) const;
+   friend class BaseMatrix;
+   friend class GeneralMatrix;
+   friend class GenericMatrix;
+public:
+   ~MultipliedMatrix() {}
+   GeneralMatrix* Evaluate(MatrixType mt=MatrixTypeUnSp);
+   MatrixBandWidth bandwidth() const;
+   NEW_DELETE(MultipliedMatrix)
+};
+
+/// Sum of two matrices.
+/// \internal
+class AddedMatrix : public MultipliedMatrix
+{
+protected:
+   AddedMatrix(const BaseMatrix* bm1x, const BaseMatrix* bm2x)
+      : MultipliedMatrix(bm1x,bm2x) {}
+
+   friend class BaseMatrix;
+   friend class GeneralMatrix;
+   friend class GenericMatrix;
+public:
+   ~AddedMatrix() {}
+   GeneralMatrix* Evaluate(MatrixType mt=MatrixTypeUnSp);
+   MatrixBandWidth bandwidth() const;
+   NEW_DELETE(AddedMatrix)
+};
+
+/// Schur (elementwise) product of two matrices.
+/// \internal
+class SPMatrix : public AddedMatrix
+{
+protected:
+   SPMatrix(const BaseMatrix* bm1x, const BaseMatrix* bm2x)
+      : AddedMatrix(bm1x,bm2x) {}
+
+   friend class BaseMatrix;
+   friend class GeneralMatrix;
+   friend class GenericMatrix;
+public:
+   ~SPMatrix() {}
+   GeneralMatrix* Evaluate(MatrixType mt=MatrixTypeUnSp);
+   MatrixBandWidth bandwidth() const;
+
+   friend SPMatrix SP(const BaseMatrix&, const BaseMatrix&);
+
+   NEW_DELETE(SPMatrix)
+};
+
+/// Kronecker product of two matrices.
+/// \internal
+class KPMatrix : public MultipliedMatrix
+{
+protected:
+   KPMatrix(const BaseMatrix* bm1x, const BaseMatrix* bm2x)
+      : MultipliedMatrix(bm1x,bm2x) {}
+
+   friend class BaseMatrix;
+   friend class GeneralMatrix;
+   friend class GenericMatrix;
+public:
+   ~KPMatrix() {}
+   MatrixBandWidth bandwidth() const;
+   GeneralMatrix* Evaluate(MatrixType mt=MatrixTypeUnSp);
+   friend KPMatrix KP(const BaseMatrix&, const BaseMatrix&);
+   NEW_DELETE(KPMatrix)
+};
+
+/// Two matrices horizontally concatenated.
+/// \internal
+class ConcatenatedMatrix : public MultipliedMatrix
+{
+protected:
+   ConcatenatedMatrix(const BaseMatrix* bm1x, const BaseMatrix* bm2x)
+      : MultipliedMatrix(bm1x,bm2x) {}
+
+   friend class BaseMatrix;
+   friend class GeneralMatrix;
+   friend class GenericMatrix;
+public:
+   ~ConcatenatedMatrix() {}
+   MatrixBandWidth bandwidth() const;
+   GeneralMatrix* Evaluate(MatrixType mt=MatrixTypeUnSp);
+   NEW_DELETE(ConcatenatedMatrix)
+};
+
+/// Two matrices vertically concatenated.
+/// \internal
+class StackedMatrix : public ConcatenatedMatrix
+{
+protected:
+   StackedMatrix(const BaseMatrix* bm1x, const BaseMatrix* bm2x)
+      : ConcatenatedMatrix(bm1x,bm2x) {}
+
+   friend class BaseMatrix;
+   friend class GeneralMatrix;
+   friend class GenericMatrix;
+public:
+   ~StackedMatrix() {}
+   GeneralMatrix* Evaluate(MatrixType mt=MatrixTypeUnSp);
+   NEW_DELETE(StackedMatrix)
+};
+
+/// Inverted matrix times matrix.
+/// \internal
+class SolvedMatrix : public MultipliedMatrix
+{
+   SolvedMatrix(const BaseMatrix* bm1x, const BaseMatrix* bm2x)
+      : MultipliedMatrix(bm1x,bm2x) {}
+   friend class BaseMatrix;
+   friend class InvertedMatrix;                        // for operator*
+public:
+   ~SolvedMatrix() {}
+   GeneralMatrix* Evaluate(MatrixType mt=MatrixTypeUnSp);
+   MatrixBandWidth bandwidth() const;
+   NEW_DELETE(SolvedMatrix)
+};
+
+/// Difference between two matrices.
+/// \internal
+class SubtractedMatrix : public AddedMatrix
+{
+   SubtractedMatrix(const BaseMatrix* bm1x, const BaseMatrix* bm2x)
+      : AddedMatrix(bm1x,bm2x) {}
+   friend class BaseMatrix;
+   friend class GeneralMatrix;
+   friend class GenericMatrix;
+public:
+   ~SubtractedMatrix() {}
+   GeneralMatrix* Evaluate(MatrixType mt=MatrixTypeUnSp);
+   NEW_DELETE(SubtractedMatrix)
+};
+
+/// Any type of matrix plus Real.
+/// \internal
+class ShiftedMatrix : public BaseMatrix
+{
+protected:
+   union { const BaseMatrix* bm; GeneralMatrix* gm; };
+   Real f;
+   ShiftedMatrix(const BaseMatrix* bmx, Real fx) : bm(bmx),f(fx) {}
+   int search(const BaseMatrix*) const;
+   friend class BaseMatrix;
+   friend class GeneralMatrix;
+   friend class GenericMatrix;
+public:
+   ~ShiftedMatrix() {}
+   GeneralMatrix* Evaluate(MatrixType mt=MatrixTypeUnSp);
+   friend ShiftedMatrix operator+(Real f, const BaseMatrix& BM);
+   NEW_DELETE(ShiftedMatrix)
+};
+
+/// Real minus matrix.
+/// \internal
+class NegShiftedMatrix : public ShiftedMatrix
+{
+protected:
+   NegShiftedMatrix(Real fx, const BaseMatrix* bmx) : ShiftedMatrix(bmx,fx) {}
+   friend class BaseMatrix;
+   friend class GeneralMatrix;
+   friend class GenericMatrix;
+public:
+   ~NegShiftedMatrix() {}
+   GeneralMatrix* Evaluate(MatrixType mt=MatrixTypeUnSp);
+   friend NegShiftedMatrix operator-(Real, const BaseMatrix&);
+   NEW_DELETE(NegShiftedMatrix)
+};
+
+/// Any type of matrix times Real.
+/// \internal
+class ScaledMatrix : public ShiftedMatrix
+{
+   ScaledMatrix(const BaseMatrix* bmx, Real fx) : ShiftedMatrix(bmx,fx) {}
+   friend class BaseMatrix;
+   friend class GeneralMatrix;
+   friend class GenericMatrix;
+public:
+   ~ScaledMatrix() {}
+   GeneralMatrix* Evaluate(MatrixType mt=MatrixTypeUnSp);
+   MatrixBandWidth bandwidth() const;
+   friend ScaledMatrix operator*(Real f, const BaseMatrix& BM);
+   NEW_DELETE(ScaledMatrix)
+};
+
+/// Any type of matrix times -1.
+/// \internal
+class NegatedMatrix : public BaseMatrix
+{
+protected:
+   union { const BaseMatrix* bm; GeneralMatrix* gm; };
+   NegatedMatrix(const BaseMatrix* bmx) : bm(bmx) {}
+   int search(const BaseMatrix*) const;
+private:
+   friend class BaseMatrix;
+public:
+   ~NegatedMatrix() {}
+   GeneralMatrix* Evaluate(MatrixType mt=MatrixTypeUnSp);
+   MatrixBandWidth bandwidth() const;
+   NEW_DELETE(NegatedMatrix)
+};
+
+/// Transposed matrix.
+/// \internal
+class TransposedMatrix : public NegatedMatrix
+{
+   TransposedMatrix(const BaseMatrix* bmx) : NegatedMatrix(bmx) {}
+   friend class BaseMatrix;
+public:
+   ~TransposedMatrix() {}
+   GeneralMatrix* Evaluate(MatrixType mt=MatrixTypeUnSp);
+   MatrixBandWidth bandwidth() const;
+   NEW_DELETE(TransposedMatrix)
+};
+
+/// Any type of matrix with order of elements reversed.
+/// \internal
+class ReversedMatrix : public NegatedMatrix
+{
+   ReversedMatrix(const BaseMatrix* bmx) : NegatedMatrix(bmx) {}
+   friend class BaseMatrix;
+public:
+   ~ReversedMatrix() {}
+   GeneralMatrix* Evaluate(MatrixType mt=MatrixTypeUnSp);
+   NEW_DELETE(ReversedMatrix)
+};
+
+/// Inverse of matrix.
+/// \internal
+class InvertedMatrix : public NegatedMatrix
+{
+   InvertedMatrix(const BaseMatrix* bmx) : NegatedMatrix(bmx) {}
+public:
+   ~InvertedMatrix() {}
+   SolvedMatrix operator*(const BaseMatrix&) const;       // inverse(A) * B
+   ScaledMatrix operator*(Real t) const { return BaseMatrix::operator*(t); }
+   friend class BaseMatrix;
+   GeneralMatrix* Evaluate(MatrixType mt=MatrixTypeUnSp);
+   MatrixBandWidth bandwidth() const;
+   NEW_DELETE(InvertedMatrix)
+};
+
+/// Any type of matrix interpreted as a RowVector.
+/// \internal
+class RowedMatrix : public NegatedMatrix
+{
+   RowedMatrix(const BaseMatrix* bmx) : NegatedMatrix(bmx) {}
+   friend class BaseMatrix;
+public:
+   ~RowedMatrix() {}
+   GeneralMatrix* Evaluate(MatrixType mt=MatrixTypeUnSp);
+   MatrixBandWidth bandwidth() const;
+   NEW_DELETE(RowedMatrix)
+};
+
+/// Any type of matrix interpreted as a ColumnVector.
+/// \internal
+class ColedMatrix : public NegatedMatrix
+{
+   ColedMatrix(const BaseMatrix* bmx) : NegatedMatrix(bmx) {}
+   friend class BaseMatrix;
+public:
+   ~ColedMatrix() {}
+   GeneralMatrix* Evaluate(MatrixType mt=MatrixTypeUnSp);
+   MatrixBandWidth bandwidth() const;
+   NEW_DELETE(ColedMatrix)
+};
+
+/// Any type of matrix interpreted as a DiagonalMatrix.
+/// \internal
+class DiagedMatrix : public NegatedMatrix
+{
+   DiagedMatrix(const BaseMatrix* bmx) : NegatedMatrix(bmx) {}
+   friend class BaseMatrix;
+public:
+   ~DiagedMatrix() {}
+   GeneralMatrix* Evaluate(MatrixType mt=MatrixTypeUnSp);
+   MatrixBandWidth bandwidth() const;
+   NEW_DELETE(DiagedMatrix)
+};
+
+/// Any type of matrix interpreted as a (rectangular) Matrix.
+/// \internal
+class MatedMatrix : public NegatedMatrix
+{
+   int nr, nc;
+   MatedMatrix(const BaseMatrix* bmx, int nrx, int ncx)
+      : NegatedMatrix(bmx), nr(nrx), nc(ncx) {}
+   friend class BaseMatrix;
+public:
+   ~MatedMatrix() {}
+   GeneralMatrix* Evaluate(MatrixType mt=MatrixTypeUnSp);
+   MatrixBandWidth bandwidth() const;
+   NEW_DELETE(MatedMatrix)
+};
+
+/// A matrix in an "envelope' for return from a function.
+/// \internal
+class ReturnMatrix : public BaseMatrix
+{
+   GeneralMatrix* gm;
+   int search(const BaseMatrix*) const;
+public:
+   ~ReturnMatrix() {}
+   GeneralMatrix* Evaluate(MatrixType mt=MatrixTypeUnSp);
+   friend class BaseMatrix;
+   ReturnMatrix(const ReturnMatrix& tm) : BaseMatrix(), gm(tm.gm) {}
+   ReturnMatrix(const GeneralMatrix* gmx) : gm((GeneralMatrix*&)gmx) {}
+//   ReturnMatrix(GeneralMatrix&);
+   MatrixBandWidth bandwidth() const;
+   NEW_DELETE(ReturnMatrix)
+};
+
+
+// ************************** submatrices ******************************/
+
+/// A submatrix of a matrix.
+/// \internal
+class GetSubMatrix : public NegatedMatrix
+{
+   int row_skip;
+   int row_number;
+   int col_skip;
+   int col_number;
+   bool IsSym;
+
+   GetSubMatrix
+      (const BaseMatrix* bmx, int rs, int rn, int cs, int cn, bool is)
+      : NegatedMatrix(bmx),
+      row_skip(rs), row_number(rn), col_skip(cs), col_number(cn), IsSym(is) {}
+   void SetUpLHS();
+   friend class BaseMatrix;
+public:
+   GetSubMatrix(const GetSubMatrix& g)
+      : NegatedMatrix(g.bm), row_skip(g.row_skip), row_number(g.row_number),
+      col_skip(g.col_skip), col_number(g.col_number), IsSym(g.IsSym) {}
+   ~GetSubMatrix() {}
+   GeneralMatrix* Evaluate(MatrixType mt=MatrixTypeUnSp);
+   void operator=(const BaseMatrix&);
+   void operator+=(const BaseMatrix&);
+   void operator-=(const BaseMatrix&);
+   void operator=(const GetSubMatrix& m) { operator=((const BaseMatrix&)m); }
+   void operator<<(const BaseMatrix&);
+   void operator<<(const double*);                // copy from array
+   void operator<<(const float*);                // copy from array
+   void operator<<(const int*);                 // copy from array
+   MatrixInput operator<<(double);                // for loading a list
+   MatrixInput operator<<(float);                // for loading a list
+   MatrixInput operator<<(int f);
+   void operator=(Real);                        // copy from constant
+   void operator+=(Real);                       // add constant
+   void operator-=(Real r) { operator+=(-r); }  // subtract constant
+   void operator*=(Real);                       // multiply by constant
+   void operator/=(Real r) { operator*=(1.0/r); } // divide by constant
+   void inject(const GeneralMatrix&);           // copy stored els only
+   void Inject(const GeneralMatrix& GM) { inject(GM); }
+   MatrixBandWidth bandwidth() const;
+   NEW_DELETE(GetSubMatrix)
+};
+
+// ******************** linear equation solving ****************************/
+
+/// A class for finding A.i() * B.
+/// This is supposed to choose the appropriate method depending on the
+/// type A. Not very satisfactory as it doesn't know about Cholesky for
+/// for positive definite matrices.
+class LinearEquationSolver : public BaseMatrix
+{
+   GeneralMatrix* gm;
+   int search(const BaseMatrix*) const { return 0; }
+   friend class BaseMatrix;
+public:
+   LinearEquationSolver(const BaseMatrix& bm);
+   ~LinearEquationSolver() { delete gm; }
+   void cleanup() { delete gm; } 
+   GeneralMatrix* Evaluate(MatrixType) { return gm; }
+   // probably should have an error message if MatrixType != UnSp
+   NEW_DELETE(LinearEquationSolver)
+};
+
+// ************************** matrix input *******************************/
+
+/// Class for reading values into a (small) matrix within a program.
+/// \internal
+/// Is able to detect a mismatch in the number of elements.
+
+class MatrixInput
+{
+   int n;                  // number values still to be read
+   Real* r;                // pointer to next location to be read to
+public:
+   MatrixInput(const MatrixInput& mi) : n(mi.n), r(mi.r) {}
+   MatrixInput(int nx, Real* rx) : n(nx), r(rx) {}
+   ~MatrixInput();
+   MatrixInput operator<<(double);
+   MatrixInput operator<<(float);
+   MatrixInput operator<<(int f);
+   friend class GeneralMatrix;
+};
+
+
+
+// **************** a very simple integer array class ********************/
+
+/// A very simple integer array class.
+/// A minimal array class to imitate a C style array but giving dynamic storage
+/// mostly intended for internal use by newmat.
+/// Probably to be replaced by a templated class when I start using templates.
+
+class SimpleIntArray : public Janitor
+{
+protected:
+   int* a;                    ///< pointer to the array
+   int n;                     ///< length of the array
+public:
+   SimpleIntArray(int xn);    ///< build an array length xn
+   SimpleIntArray() : a(0), n(0) {}  ///< build an array length 0
+   ~SimpleIntArray();         ///< return the space to memory
+   int& operator[](int i);    ///< access element of the array - start at 0
+   int operator[](int i) const;
+			      ///< access element of constant array
+   void operator=(int ai);    ///< set the array equal to a constant
+   void operator=(const SimpleIntArray& b);
+			      ///< copy the elements of an array
+   SimpleIntArray(const SimpleIntArray& b);
+			      ///< make a new array equal to an existing one
+   int Size() const { return n; }
+			      ///< return the size of the array
+   int size() const { return n; }
+			      ///< return the size of the array
+   int* Data() { return a; }  ///< pointer to the data
+   const int* Data() const { return a; }  ///< pointer to the data
+   int* data() { return a; }  ///< pointer to the data
+   const int* data() const { return a; }  ///< pointer to the data
+   const int* const_data() const { return a; }  ///< pointer to the data
+   void resize(int i, bool keep = false);
+                              ///< change length, keep data if keep = true
+   void ReSize(int i, bool keep = false) { resize(i, keep); }
+                              ///< change length, keep data if keep = true
+   void resize_keep(int i) { resize(i, true); }
+                              ///< change length, keep data
+   void cleanup() { resize(0); }   ///< set length to zero
+   void CleanUp() { resize(0); }   ///< set length to zero
+   NEW_DELETE(SimpleIntArray)
+};
+
+// ********************** C subscript classes ****************************
+
+/// Let matrix simulate a C type two dimensional array
+class RealStarStar
+{
+   Real** a;
+public:
+   RealStarStar(Matrix& A);
+   ~RealStarStar() { delete [] a; }
+   operator Real**() { return a; }
+};
+
+/// Let matrix simulate a C type const two dimensional array
+class ConstRealStarStar
+{
+   const Real** a;
+public:
+   ConstRealStarStar(const Matrix& A);
+   ~ConstRealStarStar() { delete [] a; }
+   operator const Real**() { return a; }
+};
+
+// *************************** exceptions ********************************/
+
+/// Not positive definite exception.
+class NPDException : public Runtime_error
+{
+public:
+   static unsigned long Select;
+   NPDException(const GeneralMatrix&);
+};
+
+/// Covergence failure exception.
+class ConvergenceException : public Runtime_error
+{
+public:
+   static unsigned long Select;
+   ConvergenceException(const GeneralMatrix& A);
+   ConvergenceException(const char* c);
+};
+
+/// Singular matrix exception.
+class SingularException : public Runtime_error
+{
+public:
+   static unsigned long Select;
+   SingularException(const GeneralMatrix& A);
+};
+
+/// Real overflow exception.
+class OverflowException : public Runtime_error
+{
+public:
+   static unsigned long Select;
+   OverflowException(const char* c);
+};
+
+/// Miscellaneous exception (details in character string). 
+class ProgramException : public Logic_error
+{
+protected:
+   ProgramException();
+public:
+   static unsigned long Select;
+   ProgramException(const char* c);
+   ProgramException(const char* c, const GeneralMatrix&);
+   ProgramException(const char* c, const GeneralMatrix&, const GeneralMatrix&);
+   ProgramException(const char* c, MatrixType, MatrixType);
+};
+
+/// Index exception.
+class IndexException : public Logic_error
+{
+public:
+   static unsigned long Select;
+   IndexException(int i, const GeneralMatrix& A);
+   IndexException(int i, int j, const GeneralMatrix& A);
+   // next two are for access via element function
+   IndexException(int i, const GeneralMatrix& A, bool);
+   IndexException(int i, int j, const GeneralMatrix& A, bool);
+};
+
+/// Cannot convert to vector exception.
+class VectorException : public Logic_error
+{
+public:
+   static unsigned long Select;
+   VectorException();
+   VectorException(const GeneralMatrix& A);
+};
+
+/// A matrix is not square exception.
+class NotSquareException : public Logic_error
+{
+public:
+   static unsigned long Select;
+   NotSquareException(const GeneralMatrix& A);
+   NotSquareException();
+};
+
+/// Submatrix dimension exception.
+class SubMatrixDimensionException : public Logic_error
+{
+public:
+   static unsigned long Select;
+   SubMatrixDimensionException();
+};
+
+/// Incompatible dimensions exception.
+class IncompatibleDimensionsException : public Logic_error
+{
+public:
+   static unsigned long Select;
+   IncompatibleDimensionsException();
+   IncompatibleDimensionsException(const GeneralMatrix&);
+   IncompatibleDimensionsException(const GeneralMatrix&, const GeneralMatrix&);
+};
+
+/// Not defined exception.
+class NotDefinedException : public Logic_error
+{
+public:
+   static unsigned long Select;
+   NotDefinedException(const char* op, const char* matrix);
+};
+
+/// Cannot build matrix with these properties exception.
+class CannotBuildException : public Logic_error
+{
+public:
+   static unsigned long Select;
+   CannotBuildException(const char* matrix);
+};
+
+
+/// Internal newmat exception - shouldn't happen.
+class InternalException : public Logic_error
+{
+public:
+   static unsigned long Select;          // for identifying exception
+   InternalException(const char* c);
+};
+
+// ************************ functions ************************************ //
+
+bool operator==(const GeneralMatrix& A, const GeneralMatrix& B);
+bool operator==(const BaseMatrix& A, const BaseMatrix& B);
+inline bool operator!=(const GeneralMatrix& A, const GeneralMatrix& B)
+   { return ! (A==B); }
+inline bool operator!=(const BaseMatrix& A, const BaseMatrix& B)
+   { return ! (A==B); }
+
+   // inequality operators are dummies included for compatibility
+   // with STL. They throw an exception if actually called.
+inline bool operator<=(const BaseMatrix& A, const BaseMatrix&)
+   { A.IEQND(); return true; }
+inline bool operator>=(const BaseMatrix& A, const BaseMatrix&)
+   { A.IEQND(); return true; }
+inline bool operator<(const BaseMatrix& A, const BaseMatrix&)
+   { A.IEQND(); return true; }
+inline bool operator>(const BaseMatrix& A, const BaseMatrix&)
+   { A.IEQND(); return true; }
+
+bool is_zero(const BaseMatrix& A);
+inline bool IsZero(const BaseMatrix& A) { return is_zero(A); }
+
+Real dotproduct(const Matrix& A, const Matrix& B);
+Matrix crossproduct(const Matrix& A, const Matrix& B);
+ReturnMatrix crossproduct_rows(const Matrix& A, const Matrix& B);
+ReturnMatrix crossproduct_columns(const Matrix& A, const Matrix& B);
+
+inline Real DotProduct(const Matrix& A, const Matrix& B)
+   { return dotproduct(A, B); }
+inline Matrix CrossProduct(const Matrix& A, const Matrix& B)
+   { return crossproduct(A, B); }
+inline ReturnMatrix CrossProductRows(const Matrix& A, const Matrix& B)
+   { return crossproduct_rows(A, B); }
+inline ReturnMatrix CrossProductColumns(const Matrix& A, const Matrix& B)
+   { return crossproduct_columns(A, B); }
+   
+void newmat_block_copy(int n, Real* from, Real* to);
+
+// ********************* friend functions ******************************** //
+
+// Functions declared as friends - G++ wants them declared externally as well
+
+bool Rectangular(MatrixType a, MatrixType b, MatrixType c);
+bool Compare(const MatrixType&, MatrixType&);
+Real dotproduct(const Matrix& A, const Matrix& B);
+SPMatrix SP(const BaseMatrix&, const BaseMatrix&);
+KPMatrix KP(const BaseMatrix&, const BaseMatrix&);
+ShiftedMatrix operator+(Real f, const BaseMatrix& BM);
+NegShiftedMatrix operator-(Real, const BaseMatrix&);
+ScaledMatrix operator*(Real f, const BaseMatrix& BM);
+
+// ********************* inline functions ******************************** //
+
+inline LogAndSign log_determinant(const BaseMatrix& B)
+   { return B.log_determinant(); }
+inline LogAndSign LogDeterminant(const BaseMatrix& B)
+   { return B.log_determinant(); }
+inline Real determinant(const BaseMatrix& B)
+   { return B.determinant(); }
+inline Real Determinant(const BaseMatrix& B)
+   { return B.determinant(); }
+inline Real sum_square(const BaseMatrix& B) { return B.sum_square(); }
+inline Real SumSquare(const BaseMatrix& B) { return B.sum_square(); }
+inline Real norm_Frobenius(const BaseMatrix& B) { return B.norm_Frobenius(); }
+inline Real norm_frobenius(const BaseMatrix& B) { return B.norm_Frobenius(); }
+inline Real NormFrobenius(const BaseMatrix& B) { return B.norm_Frobenius(); }
+inline Real trace(const BaseMatrix& B) { return B.trace(); }
+inline Real Trace(const BaseMatrix& B) { return B.trace(); }
+inline Real sum_absolute_value(const BaseMatrix& B)
+   { return B.sum_absolute_value(); }
+inline Real SumAbsoluteValue(const BaseMatrix& B)
+   { return B.sum_absolute_value(); }
+inline Real sum(const BaseMatrix& B)
+   { return B.sum(); }
+inline Real Sum(const BaseMatrix& B)
+   { return B.sum(); }
+inline Real maximum_absolute_value(const BaseMatrix& B)
+   { return B.maximum_absolute_value(); }
+inline Real MaximumAbsoluteValue(const BaseMatrix& B)
+   { return B.maximum_absolute_value(); }
+inline Real minimum_absolute_value(const BaseMatrix& B)
+   { return B.minimum_absolute_value(); }
+inline Real MinimumAbsoluteValue(const BaseMatrix& B)
+   { return B.minimum_absolute_value(); }
+inline Real maximum(const BaseMatrix& B) { return B.maximum(); }
+inline Real Maximum(const BaseMatrix& B) { return B.maximum(); }
+inline Real minimum(const BaseMatrix& B) { return B.minimum(); }
+inline Real Minimum(const BaseMatrix& B) { return B.minimum(); }
+inline Real norm1(const BaseMatrix& B) { return B.norm1(); }
+inline Real Norm1(const BaseMatrix& B) { return B.norm1(); }
+inline Real norm1(RowVector& RV) { return RV.maximum_absolute_value(); }
+inline Real Norm1(RowVector& RV) { return RV.maximum_absolute_value(); }
+inline Real norm_infinity(const BaseMatrix& B) { return B.norm_infinity(); }
+inline Real NormInfinity(const BaseMatrix& B) { return B.norm_infinity(); }
+inline Real norm_infinity(ColumnVector& CV)
+   { return CV.maximum_absolute_value(); }
+inline Real NormInfinity(ColumnVector& CV)
+   { return CV.maximum_absolute_value(); }
+inline bool IsZero(const GeneralMatrix& A) { return A.IsZero(); }
+inline bool is_zero(const GeneralMatrix& A) { return A.is_zero(); }
+
+
+inline MatrixInput MatrixInput::operator<<(int f) { return *this << (Real)f; }
+inline MatrixInput GeneralMatrix::operator<<(int f) { return *this << (Real)f; }
+inline MatrixInput BandMatrix::operator<<(int f) { return *this << (Real)f; }
+inline MatrixInput GetSubMatrix::operator<<(int f) { return *this << (Real)f; }
+
+inline ReversedMatrix BaseMatrix::Reverse() const { return reverse(); }
+inline RowedMatrix BaseMatrix::AsRow() const { return as_row(); }
+inline ColedMatrix BaseMatrix::AsColumn() const { return as_column(); }
+inline DiagedMatrix BaseMatrix::AsDiagonal() const { return as_diagonal(); }
+inline MatedMatrix BaseMatrix::AsMatrix(int m, int n) const
+   { return as_matrix(m, n); }
+inline GetSubMatrix BaseMatrix::SubMatrix(int fr, int lr, int fc, int lc) const
+   { return submatrix(fr, lr, fc, lc); }
+inline GetSubMatrix BaseMatrix::SymSubMatrix(int f, int l) const
+   { return sym_submatrix(f, l); }
+inline GetSubMatrix BaseMatrix::Row(int f) const { return row(f); }
+inline GetSubMatrix BaseMatrix::Rows(int f, int l) const { return rows(f, l); }
+inline GetSubMatrix BaseMatrix::Column(int f) const { return column(f); }
+inline GetSubMatrix BaseMatrix::Columns(int f, int l) const
+   { return columns(f, l); }
+inline Real BaseMatrix::AsScalar() const { return as_scalar(); }
+
+inline ReturnMatrix GeneralMatrix::ForReturn() const { return for_return(); }
+
+inline void swap(Matrix& A, Matrix& B) { A.swap(B); }
+inline void swap(SquareMatrix& A, SquareMatrix& B) { A.swap(B); }
+inline void swap(nricMatrix& A, nricMatrix& B) { A.swap(B); }
+inline void swap(UpperTriangularMatrix& A, UpperTriangularMatrix& B)
+   { A.swap(B); }
+inline void swap(LowerTriangularMatrix& A, LowerTriangularMatrix& B)
+   { A.swap(B); }
+inline void swap(SymmetricMatrix& A, SymmetricMatrix& B) { A.swap(B); }
+inline void swap(DiagonalMatrix& A, DiagonalMatrix& B) { A.swap(B); }
+inline void swap(RowVector& A, RowVector& B) { A.swap(B); }
+inline void swap(ColumnVector& A, ColumnVector& B) { A.swap(B); }
+inline void swap(CroutMatrix& A, CroutMatrix& B) { A.swap(B); }
+inline void swap(BandMatrix& A, BandMatrix& B) { A.swap(B); }
+inline void swap(UpperBandMatrix& A, UpperBandMatrix& B) { A.swap(B); }
+inline void swap(LowerBandMatrix& A, LowerBandMatrix& B) { A.swap(B); }
+inline void swap(SymmetricBandMatrix& A, SymmetricBandMatrix& B) { A.swap(B); }
+inline void swap(BandLUMatrix& A, BandLUMatrix& B) { A.swap(B); }
+inline void swap(IdentityMatrix& A, IdentityMatrix& B) { A.swap(B); }
+inline void swap(GenericMatrix& A, GenericMatrix& B) { A.swap(B); }
+
+#ifdef OPT_COMPATIBLE                    // for compatibility with opt++
+
+inline Real Norm2(const ColumnVector& CV) { return CV.norm_Frobenius(); }
+inline Real Dot(ColumnVector& CV1, ColumnVector& CV2)
+   { return dotproduct(CV1, CV2); }
+
+#endif
+
+
+#ifdef use_namespace
+}
+#endif
+
+
+#endif
+
+// body file: newmat1.cpp
+// body file: newmat2.cpp
+// body file: newmat3.cpp
+// body file: newmat4.cpp
+// body file: newmat5.cpp
+// body file: newmat6.cpp
+// body file: newmat7.cpp
+// body file: newmat8.cpp
+// body file: newmatex.cpp
+// body file: bandmat.cpp
+// body file: submat.cpp
+
+
+
+///@}
+
+
+
+
Index: /nanovis/tags/1.1.4/newmat11/newmat1.cpp
===================================================================
--- /nanovis/tags/1.1.4/newmat11/newmat1.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/newmat11/newmat1.cpp	(revision 4930)
@@ -0,0 +1,209 @@
+/// \ingroup newmat
+///@{
+
+/// \file newmat1.cpp
+/// MatrixType functions.
+/// Find the type of a matrix resulting from a multiply, add etc
+/// Make a new matrix corresponding to a MatrixType
+
+// Copyright (C) 1991,2,3,4: R B Davies
+
+//#define WANT_STREAM
+
+#include "newmat.h"
+
+#ifdef use_namespace
+namespace NEWMAT {
+#endif
+
+#ifdef DO_REPORT
+#define REPORT { static ExeCounter ExeCount(__LINE__,1); ++ExeCount; }
+#else
+#define REPORT {}
+#endif
+
+
+/************************* MatrixType functions *****************************/
+
+
+// Skew needs more work <<<<<<<<<
+
+// all operations to return MatrixTypes which correspond to valid types
+// of matrices.
+// Eg: if it has the Diagonal attribute, then it must also have
+// Upper, Lower, Band, Square and Symmetric.
+
+
+MatrixType MatrixType::operator*(const MatrixType& mt) const
+{
+   REPORT
+   int a = attribute & mt.attribute & ~(Symmetric | Skew);
+   a |= (a & Diagonal) * 63;                   // recognise diagonal
+   return MatrixType(a);
+}
+
+MatrixType MatrixType::SP(const MatrixType& mt) const
+// elementwise product
+// Lower, Upper, Diag, Band if only one is
+// Symmetric, Ones, Valid (and Real) if both are
+// Need to include Lower & Upper => Diagonal
+// Will need to include both Skew => Symmetric
+{
+   REPORT
+   int a = ((attribute | mt.attribute) & ~(Symmetric + Skew + Valid + Ones))
+      | (attribute & mt.attribute);
+   if ((a & Lower) != 0  &&  (a & Upper) != 0) a |= Diagonal;
+   if ((attribute & Skew) != 0)
+   {
+      if ((mt.attribute & Symmetric) != 0) a |= Skew;  
+      if ((mt.attribute & Skew) != 0) { a &= ~Skew; a |= Symmetric; }
+   }
+   else if ((mt.attribute & Skew) != 0 && (attribute & Symmetric) != 0)
+      a |= Skew;  
+   a |= (a & Diagonal) * 63;                   // recognise diagonal
+   return MatrixType(a);
+}
+
+MatrixType MatrixType::KP(const MatrixType& mt) const
+// Kronecker product
+// Lower, Upper, Diag, Symmetric, Band, Valid if both are
+// Band if LHS is band & other is square 
+// Ones is complicated so leave this out
+{
+   REPORT
+   int a = (attribute & mt.attribute)  & ~Ones;
+   if ((attribute & Band) != 0 && (mt.attribute & Square) != 0)
+      a |= Band;
+   //int a = ((attribute & mt.attribute) | (attribute & Band)) & ~Ones;
+
+   return MatrixType(a);
+}
+
+MatrixType MatrixType::i() const               // type of inverse
+{
+   REPORT
+   int a = attribute & ~(Band+LUDeco);
+   a |= (a & Diagonal) * 63;                   // recognise diagonal
+   return MatrixType(a);
+}
+
+MatrixType MatrixType::t() const
+// swap lower and upper attributes
+// assume Upper is in bit above Lower
+{
+   REPORT
+   int a = attribute;
+   a ^= (((a >> 1) ^ a) & Lower) * 3;
+   return MatrixType(a);
+}
+
+MatrixType MatrixType::MultRHS() const
+{
+   REPORT
+   // remove symmetric attribute unless diagonal
+   return (attribute >= Dg) ? attribute : (attribute & ~Symmetric);
+}
+
+// this is used for deciding type of multiplication
+bool Rectangular(MatrixType a, MatrixType b, MatrixType c)
+{
+   REPORT
+   return
+      ((a.attribute | b.attribute | c.attribute)
+      & ~(MatrixType::Valid | MatrixType::Square)) == 0;
+}
+
+const char* MatrixType::value() const
+{
+// make a string with the name of matrix with the given attributes
+   switch (attribute)
+   {
+   case Valid:                              REPORT return "Rect ";
+   case Valid+Square:                       REPORT return "Squ  ";
+   case Valid+Symmetric+Square:             REPORT return "Sym  ";
+   case Valid+Skew+Square:                  REPORT return "Skew ";
+   case Valid+Band+Square:                  REPORT return "Band ";
+   case Valid+Symmetric+Band+Square:        REPORT return "SmBnd";
+   case Valid+Skew+Band+Square:             REPORT return "SkBnd";
+   case Valid+Upper+Square:                 REPORT return "UT   ";
+   case Valid+Diagonal+Symmetric+Band+Upper+Lower+Square:
+                                            REPORT return "Diag ";
+   case Valid+Diagonal+Symmetric+Band+Upper+Lower+Ones+Square:
+                                            REPORT return "Ident";
+   case Valid+Band+Upper+Square:            REPORT return "UpBnd";
+   case Valid+Lower+Square:                 REPORT return "LT   ";
+   case Valid+Band+Lower+Square:            REPORT return "LwBnd";
+   default:
+      REPORT
+      if (!(attribute & Valid))             return "UnSp ";
+      if (attribute & LUDeco)
+         return (attribute & Band) ?     "BndLU" : "Crout";
+                                            return "?????";
+   }
+}
+
+
+GeneralMatrix* MatrixType::New(int nr, int nc, BaseMatrix* bm) const
+{
+// make a new matrix with the given attributes
+
+   Tracer tr("New"); GeneralMatrix* gm=0;   // initialised to keep gnu happy
+   switch (attribute)
+   {
+   case Valid:
+      REPORT
+      if (nc==1) { gm = new ColumnVector(nr); break; }
+      if (nr==1) { gm = new RowVector(nc); break; }
+      gm = new Matrix(nr, nc); break;
+
+   case Valid+Square:
+      REPORT
+      if (nc!=nr) { Throw(NotSquareException()); }
+      gm = new SquareMatrix(nr); break;
+
+   case Valid+Symmetric+Square:
+      REPORT gm = new SymmetricMatrix(nr); break;
+
+   case Valid+Band+Square:
+      {
+         REPORT
+         MatrixBandWidth bw = bm->bandwidth();
+         gm = new BandMatrix(nr,bw.lower_val,bw.upper_val); break;
+      }
+
+   case Valid+Symmetric+Band+Square:
+      REPORT gm = new SymmetricBandMatrix(nr,bm->bandwidth().lower_val); break;
+
+   case Valid+Upper+Square:
+      REPORT gm = new UpperTriangularMatrix(nr); break;
+
+   case Valid+Diagonal+Symmetric+Band+Upper+Lower+Square:
+      REPORT gm = new DiagonalMatrix(nr); break;
+
+   case Valid+Band+Upper+Square:
+      REPORT gm = new UpperBandMatrix(nr,bm->bandwidth().upper_val); break;
+
+   case Valid+Lower+Square:
+      REPORT gm = new LowerTriangularMatrix(nr); break;
+
+   case Valid+Band+Lower+Square:
+      REPORT gm = new LowerBandMatrix(nr,bm->bandwidth().lower_val); break;
+
+   case Valid+Diagonal+Symmetric+Band+Upper+Lower+Ones+Square:
+      REPORT gm = new IdentityMatrix(nr); break;
+
+   default:
+      Throw(ProgramException("Invalid matrix type"));
+   }
+   
+   MatrixErrorNoSpace(gm); gm->Protect(); return gm;
+}
+
+
+#ifdef use_namespace
+}
+#endif
+
+
+
+///@}
Index: /nanovis/tags/1.1.4/newmat11/newmat2.cpp
===================================================================
--- /nanovis/tags/1.1.4/newmat11/newmat2.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/newmat11/newmat2.cpp	(revision 4930)
@@ -0,0 +1,658 @@
+/// \ingroup newmat
+///@{
+
+/// \file newmat2.cpp
+/// Matrix row and column operations.
+/// The operations on individual rows and columns used to carry out matrix
+/// add, multiply etc.
+
+
+// Copyright (C) 1991,2,3,4: R B Davies
+
+#define WANT_MATH
+
+#include "include.h"
+
+#include "newmat.h"
+#include "newmatrc.h"
+
+#ifdef use_namespace
+namespace NEWMAT {
+#endif
+
+
+#ifdef DO_REPORT
+#define REPORT { static ExeCounter ExeCount(__LINE__,2); ++ExeCount; }
+#else
+#define REPORT {}
+#endif
+
+//#define MONITOR(what,storage,store) { cout << what << " " << storage << " at " << (long)store << "\n"; }
+
+#define MONITOR(what,store,storage) {}
+
+/************************** Matrix Row/Col functions ************************/
+
+void MatrixRowCol::Add(const MatrixRowCol& mrc)
+{
+   // THIS += mrc
+   REPORT
+   int f = mrc.skip; int l = f + mrc.storage; int lx = skip + storage;
+   if (f < skip) f = skip; if (l > lx) l = lx; l -= f;
+   if (l<=0) return;
+   Real* elx=data+(f-skip); Real* el=mrc.data+(f-mrc.skip);
+   while (l--) *elx++ += *el++;
+}
+
+void MatrixRowCol::AddScaled(const MatrixRowCol& mrc, Real x)
+{
+   REPORT
+   // THIS += (mrc * x)
+   int f = mrc.skip; int l = f + mrc.storage; int lx = skip + storage;
+   if (f < skip) f = skip; if (l > lx) l = lx; l -= f;
+   if (l<=0) return;
+   Real* elx=data+(f-skip); Real* el=mrc.data+(f-mrc.skip);
+   while (l--) *elx++ += *el++ * x;
+}
+
+void MatrixRowCol::Sub(const MatrixRowCol& mrc)
+{
+   REPORT
+   // THIS -= mrc
+   int f = mrc.skip; int l = f + mrc.storage; int lx = skip + storage;
+   if (f < skip) f = skip; if (l > lx) l = lx; l -= f;
+   if (l<=0) return;
+   Real* elx=data+(f-skip); Real* el=mrc.data+(f-mrc.skip);
+   while (l--) *elx++ -= *el++;
+}
+
+void MatrixRowCol::Inject(const MatrixRowCol& mrc)
+// copy stored elements only
+{
+   REPORT
+   int f = mrc.skip; int l = f + mrc.storage; int lx = skip + storage;
+   if (f < skip) f = skip; if (l > lx) l = lx; l -= f;
+   if (l<=0) return;
+   Real* elx=data+(f-skip); Real* ely=mrc.data+(f-mrc.skip);
+   while (l--) *elx++ = *ely++;
+}
+
+Real DotProd(const MatrixRowCol& mrc1, const MatrixRowCol& mrc2)
+{
+   REPORT                                         // not accessed
+   int f = mrc1.skip; int f2 = mrc2.skip;
+   int l = f + mrc1.storage; int l2 = f2 + mrc2.storage;
+   if (f < f2) f = f2; if (l > l2) l = l2; l -= f;
+   if (l<=0) return 0.0;
+
+   Real* el1=mrc1.data+(f-mrc1.skip); Real* el2=mrc2.data+(f-mrc2.skip);
+   Real sum = 0.0;
+   while (l--) sum += *el1++ * *el2++;
+   return sum;
+}
+
+void MatrixRowCol::Add(const MatrixRowCol& mrc1, const MatrixRowCol& mrc2)
+{
+   // THIS = mrc1 + mrc2
+   int f = skip; int l = skip + storage;
+   int f1 = mrc1.skip; int l1 = f1 + mrc1.storage;
+   if (f1<f) f1=f; if (l1>l) l1=l;
+   int f2 = mrc2.skip; int l2 = f2 + mrc2.storage;
+   if (f2<f) f2=f; if (l2>l) l2=l;
+   Real* el = data + (f-skip);
+   Real* el1 = mrc1.data+(f1-mrc1.skip); Real* el2 = mrc2.data+(f2-mrc2.skip);
+   if (f1<f2)
+   {
+      int i = f1-f; while (i--) *el++ = 0.0;
+      if (l1<=f2)                              // disjoint
+      {
+         REPORT                                // not accessed
+         i = l1-f1;     while (i--) *el++ = *el1++;
+         i = f2-l1;     while (i--) *el++ = 0.0;
+         i = l2-f2;     while (i--) *el++ = *el2++;
+         i = l-l2;      while (i--) *el++ = 0.0;
+      }
+      else
+      {
+         i = f2-f1;    while (i--) *el++ = *el1++;
+         if (l1<=l2)
+         {
+            REPORT
+            i = l1-f2; while (i--) *el++ = *el1++ + *el2++;
+            i = l2-l1; while (i--) *el++ = *el2++;
+            i = l-l2;  while (i--) *el++ = 0.0;
+         }
+         else
+         {
+            REPORT
+            i = l2-f2; while (i--) *el++ = *el1++ + *el2++;
+            i = l1-l2; while (i--) *el++ = *el1++;
+            i = l-l1;  while (i--) *el++ = 0.0;
+         }
+      }
+   }
+   else
+   {
+      int i = f2-f; while (i--) *el++ = 0.0;
+      if (l2<=f1)                              // disjoint
+      {
+         REPORT                                // not accessed
+         i = l2-f2;     while (i--) *el++ = *el2++;
+         i = f1-l2;     while (i--) *el++ = 0.0;
+         i = l1-f1;     while (i--) *el++ = *el1++;
+         i = l-l1;      while (i--) *el++ = 0.0;
+      }
+      else
+      {
+         i = f1-f2;    while (i--) *el++ = *el2++;
+         if (l2<=l1)
+         {
+            REPORT
+            i = l2-f1; while (i--) *el++ = *el1++ + *el2++;
+            i = l1-l2; while (i--) *el++ = *el1++;
+            i = l-l1;  while (i--) *el++ = 0.0;
+         }
+         else
+         {
+            REPORT
+            i = l1-f1; while (i--) *el++ = *el1++ + *el2++;
+            i = l2-l1; while (i--) *el++ = *el2++;
+            i = l-l2;  while (i--) *el++ = 0.0;
+         }
+      }
+   }
+}
+
+void MatrixRowCol::Sub(const MatrixRowCol& mrc1, const MatrixRowCol& mrc2)
+{
+   // THIS = mrc1 - mrc2
+   int f = skip; int l = skip + storage;
+   int f1 = mrc1.skip; int l1 = f1 + mrc1.storage;
+   if (f1<f) f1=f; if (l1>l) l1=l;
+   int f2 = mrc2.skip; int l2 = f2 + mrc2.storage;
+   if (f2<f) f2=f; if (l2>l) l2=l;
+   Real* el = data + (f-skip);
+   Real* el1 = mrc1.data+(f1-mrc1.skip); Real* el2 = mrc2.data+(f2-mrc2.skip);
+   if (f1<f2)
+   {
+      int i = f1-f; while (i--) *el++ = 0.0;
+      if (l1<=f2)                              // disjoint
+      {
+         REPORT                                // not accessed
+         i = l1-f1;     while (i--) *el++ = *el1++;
+         i = f2-l1;     while (i--) *el++ = 0.0;
+         i = l2-f2;     while (i--) *el++ = - *el2++;
+         i = l-l2;      while (i--) *el++ = 0.0;
+      }
+      else
+      {
+         i = f2-f1;    while (i--) *el++ = *el1++;
+         if (l1<=l2)
+         {
+            REPORT
+            i = l1-f2; while (i--) *el++ = *el1++ - *el2++;
+            i = l2-l1; while (i--) *el++ = - *el2++;
+            i = l-l2;  while (i--) *el++ = 0.0;
+         }
+         else
+         {
+            REPORT
+            i = l2-f2; while (i--) *el++ = *el1++ - *el2++;
+            i = l1-l2; while (i--) *el++ = *el1++;
+            i = l-l1;  while (i--) *el++ = 0.0;
+         }
+      }
+   }
+   else
+   {
+      int i = f2-f; while (i--) *el++ = 0.0;
+      if (l2<=f1)                              // disjoint
+      {
+         REPORT                                // not accessed
+         i = l2-f2;     while (i--) *el++ = - *el2++;
+         i = f1-l2;     while (i--) *el++ = 0.0;
+         i = l1-f1;     while (i--) *el++ = *el1++;
+         i = l-l1;      while (i--) *el++ = 0.0;
+      }
+      else
+      {
+         i = f1-f2;    while (i--) *el++ = - *el2++;
+         if (l2<=l1)
+         {
+            REPORT
+            i = l2-f1; while (i--) *el++ = *el1++ - *el2++;
+            i = l1-l2; while (i--) *el++ = *el1++;
+            i = l-l1;  while (i--) *el++ = 0.0;
+         }
+         else
+         {
+            REPORT
+            i = l1-f1; while (i--) *el++ = *el1++ - *el2++;
+            i = l2-l1; while (i--) *el++ = - *el2++;
+            i = l-l2;  while (i--) *el++ = 0.0;
+         }
+      }
+   }
+}
+
+
+void MatrixRowCol::Add(const MatrixRowCol& mrc1, Real x)
+{
+   // THIS = mrc1 + x
+   REPORT
+   if (!storage) return;
+   int f = mrc1.skip; int l = f + mrc1.storage; int lx = skip + storage;
+   if (f < skip) { f = skip; if (l < f) l = f; }
+   if (l > lx) { l = lx; if (f > lx) f = lx; }
+
+   Real* elx = data; Real* ely = mrc1.data+(f-mrc1.skip);
+
+   int l1 = f-skip;  while (l1--) *elx++ = x;
+       l1 = l-f;     while (l1--) *elx++ = *ely++ + x;
+       lx -= l;      while (lx--) *elx++ = x;
+}
+
+void MatrixRowCol::NegAdd(const MatrixRowCol& mrc1, Real x)
+{
+   // THIS = x - mrc1
+   REPORT
+   if (!storage) return;
+   int f = mrc1.skip; int l = f + mrc1.storage; int lx = skip + storage;
+   if (f < skip) { f = skip; if (l < f) l = f; }
+   if (l > lx) { l = lx; if (f > lx) f = lx; }
+
+   Real* elx = data; Real* ely = mrc1.data+(f-mrc1.skip);
+
+   int l1 = f-skip;  while (l1--) *elx++ = x;
+       l1 = l-f;     while (l1--) *elx++ = x - *ely++;
+       lx -= l;      while (lx--) *elx++ = x;
+}
+
+void MatrixRowCol::RevSub(const MatrixRowCol& mrc1)
+{
+   // THIS = mrc - THIS
+   REPORT
+   if (!storage) return;
+   int f = mrc1.skip; int l = f + mrc1.storage; int lx = skip + storage;
+   if (f < skip) { f = skip; if (l < f) l = f; }
+   if (l > lx) { l = lx; if (f > lx) f = lx; }
+
+   Real* elx = data; Real* ely = mrc1.data+(f-mrc1.skip);
+
+   int l1 = f-skip;  while (l1--) { *elx = - *elx; elx++; }
+       l1 = l-f;     while (l1--) { *elx = *ely++ - *elx; elx++; }
+       lx -= l;      while (lx--) { *elx = - *elx; elx++; }
+}
+
+void MatrixRowCol::ConCat(const MatrixRowCol& mrc1, const MatrixRowCol& mrc2)
+{
+   // THIS = mrc1 | mrc2
+   REPORT
+   int f1 = mrc1.skip; int l1 = f1 + mrc1.storage; int lx = skip + storage;
+   if (f1 < skip) { f1 = skip; if (l1 < f1) l1 = f1; }
+   if (l1 > lx) { l1 = lx; if (f1 > lx) f1 = lx; }
+
+   Real* elx = data;
+
+   int i = f1-skip;  while (i--) *elx++ =0.0;
+   i = l1-f1;
+   if (i)                       // in case f1 would take ely out of range
+      { Real* ely = mrc1.data+(f1-mrc1.skip);  while (i--) *elx++ = *ely++; }
+
+   int f2 = mrc2.skip; int l2 = f2 + mrc2.storage; i = mrc1.length;
+   int skipx = l1 - i; lx -= i; // addresses rel to second seg, maybe -ve
+   if (f2 < skipx) { f2 = skipx; if (l2 < f2) l2 = f2; }
+   if (l2 > lx) { l2 = lx; if (f2 > lx) f2 = lx; }
+
+   i = f2-skipx; while (i--) *elx++ = 0.0;
+   i = l2-f2;
+   if (i)                       // in case f2 would take ely out of range
+      { Real* ely = mrc2.data+(f2-mrc2.skip); while (i--) *elx++ = *ely++; }
+   lx -= l2;     while (lx--) *elx++ = 0.0;
+}
+
+void MatrixRowCol::Multiply(const MatrixRowCol& mrc1)
+// element by element multiply into
+{
+   REPORT
+   if (!storage) return;
+   int f = mrc1.skip; int l = f + mrc1.storage; int lx = skip + storage;
+   if (f < skip) { f = skip; if (l < f) l = f; }
+   if (l > lx) { l = lx; if (f > lx) f = lx; }
+
+   Real* elx = data; Real* ely = mrc1.data+(f-mrc1.skip);
+
+   int l1 = f-skip;  while (l1--) *elx++ = 0;
+       l1 = l-f;     while (l1--) *elx++ *= *ely++;
+       lx -= l;      while (lx--) *elx++ = 0;
+}
+
+void MatrixRowCol::Multiply(const MatrixRowCol& mrc1, const MatrixRowCol& mrc2)
+// element by element multiply
+{
+   int f = skip; int l = skip + storage;
+   int f1 = mrc1.skip; int l1 = f1 + mrc1.storage;
+   if (f1<f) f1=f; if (l1>l) l1=l;
+   int f2 = mrc2.skip; int l2 = f2 + mrc2.storage;
+   if (f2<f) f2=f; if (l2>l) l2=l;
+   Real* el = data + (f-skip); int i;
+   if (f1<f2) f1 = f2; if (l1>l2) l1 = l2;
+   if (l1<=f1) { REPORT i = l-f; while (i--) *el++ = 0.0; }  // disjoint
+   else
+   {
+      REPORT
+      Real* el1 = mrc1.data+(f1-mrc1.skip);
+      Real* el2 = mrc2.data+(f1-mrc2.skip);
+      i = f1-f ;    while (i--) *el++ = 0.0;
+      i = l1-f1;    while (i--) *el++ = *el1++ * *el2++;
+      i = l-l1;     while (i--) *el++ = 0.0;
+   }
+}
+
+void MatrixRowCol::KP(const MatrixRowCol& mrc1, const MatrixRowCol& mrc2)
+// row for Kronecker product
+{
+   int f = skip; int s = storage; Real* el = data; int i;
+
+   i = mrc1.skip * mrc2.length;
+   if (i > f)
+   {
+      i -= f; f = 0; if (i > s) { i = s; s = 0; }  else s -= i;
+      while (i--) *el++ = 0.0;
+      if (s == 0) return;
+   }
+   else f -= i;
+
+   i = mrc1.storage; Real* el1 = mrc1.data;
+   int mrc2_skip = mrc2.skip; int mrc2_storage = mrc2.storage;
+   int mrc2_length = mrc2.length;
+   int mrc2_remain = mrc2_length - mrc2_skip - mrc2_storage;
+   while (i--)
+   {
+      int j; Real* el2 = mrc2.data; Real vel1 = *el1;
+      if (f == 0 && mrc2_length <= s)
+      {
+         j = mrc2_skip; s -= j;    while (j--) *el++ = 0.0;
+         j = mrc2_storage; s -= j; while (j--) *el++ = vel1 * *el2++;
+         j = mrc2_remain; s -= j;  while (j--) *el++ = 0.0;
+      }
+      else if (f >= mrc2_length) f -= mrc2_length;
+      else
+      {
+         j = mrc2_skip;
+         if (j > f)
+         {
+            j -= f; f = 0; if (j > s) { j = s; s = 0; } else s -= j;
+            while (j--) *el++ = 0.0;
+         }
+         else f -= j;
+
+         j = mrc2_storage;
+         if (j > f)
+         {
+            j -= f; el2 += f; f = 0; if (j > s) { j = s; s = 0; } else s -= j;
+            while (j--) *el++ = vel1 * *el2++;
+         }
+         else f -= j;
+
+         j = mrc2_remain;
+         if (j > f)
+         {
+            j -= f; f = 0; if (j > s) { j = s; s = 0; } else s -= j;
+            while (j--) *el++ = 0.0;
+         }
+         else f -= j;
+      }
+      if (s == 0) return;
+      ++el1;
+   }
+
+   i = (mrc1.length - mrc1.skip - mrc1.storage) * mrc2.length;
+   if (i > f)
+   {
+      i -= f; if (i > s) i = s;
+      while (i--) *el++ = 0.0;
+   }
+}
+
+
+void MatrixRowCol::Copy(const MatrixRowCol& mrc1)
+{
+   // THIS = mrc1
+   REPORT
+   if (!storage) return;
+   int f = mrc1.skip; int l = f + mrc1.storage; int lx = skip + storage;
+   if (f < skip) { f = skip; if (l < f) l = f; }
+   if (l > lx) { l = lx; if (f > lx) f = lx; }
+
+   Real* elx = data; Real* ely = 0;
+
+   if (l-f) ely = mrc1.data+(f-mrc1.skip);
+
+   int l1 = f-skip;  while (l1--) *elx++ = 0.0;
+       l1 = l-f;     while (l1--) *elx++ = *ely++;
+       lx -= l;      while (lx--) *elx++ = 0.0;
+}
+
+void MatrixRowCol::CopyCheck(const MatrixRowCol& mrc1)
+// Throw an exception if this would lead to a loss of data
+{
+   REPORT
+   if (!storage) return;
+   int f = mrc1.skip; int l = f + mrc1.storage; int lx = skip + storage;
+   if (f < skip || l > lx) Throw(ProgramException("Illegal Conversion"));
+
+   Real* elx = data; Real* ely = mrc1.data+(f-mrc1.skip);
+
+   int l1 = f-skip;  while (l1--) *elx++ = 0.0;
+       l1 = l-f;     while (l1--) *elx++ = *ely++;
+       lx -= l;      while (lx--) *elx++ = 0.0;
+}
+
+void MatrixRowCol::Check(const MatrixRowCol& mrc1)
+// Throw an exception if +=, -=, copy etc would lead to a loss of data
+{
+   REPORT
+   int f = mrc1.skip; int l = f + mrc1.storage; int lx = skip + storage;
+   if (f < skip || l > lx) Throw(ProgramException("Illegal Conversion"));
+}
+
+void MatrixRowCol::Check()
+// Throw an exception if +=, -= of constant would lead to a loss of data
+// that is: check full row is present
+// may not be appropriate for symmetric matrices
+{
+   REPORT
+   if (skip!=0 || storage!=length)
+      Throw(ProgramException("Illegal Conversion"));
+}
+
+void MatrixRowCol::Negate(const MatrixRowCol& mrc1)
+{
+   // THIS = -mrc1
+   REPORT
+   if (!storage) return;
+   int f = mrc1.skip; int l = f + mrc1.storage; int lx = skip + storage;
+   if (f < skip) { f = skip; if (l < f) l = f; }
+   if (l > lx) { l = lx; if (f > lx) f = lx; }
+
+   Real* elx = data; Real* ely = mrc1.data+(f-mrc1.skip);
+
+   int l1 = f-skip;  while (l1--) *elx++ = 0.0;
+       l1 = l-f;     while (l1--) *elx++ = - *ely++;
+       lx -= l;      while (lx--) *elx++ = 0.0;
+}
+
+void MatrixRowCol::Multiply(const MatrixRowCol& mrc1, Real s)
+{
+   // THIS = mrc1 * s
+   REPORT
+   if (!storage) return;
+   int f = mrc1.skip; int l = f + mrc1.storage; int lx = skip + storage;
+   if (f < skip) { f = skip; if (l < f) l = f; }
+   if (l > lx) { l = lx; if (f > lx) f = lx; }
+
+   Real* elx = data; Real* ely = mrc1.data+(f-mrc1.skip);
+
+   int l1 = f-skip;  while (l1--) *elx++ = 0.0;
+       l1 = l-f;     while (l1--) *elx++ = *ely++ * s;
+       lx -= l;      while (lx--) *elx++ = 0.0;
+}
+
+void DiagonalMatrix::Solver(MatrixColX& mrc, const MatrixColX& mrc1)
+{
+   // mrc = mrc / mrc1   (elementwise)
+   REPORT
+   int f = mrc1.skip; int f0 = mrc.skip;
+   int l = f + mrc1.storage; int lx = f0 + mrc.storage;
+   if (f < f0) { f = f0; if (l < f) l = f; }
+   if (l > lx) { l = lx; if (f > lx) f = lx; }
+
+   Real* elx = mrc.data; Real* eld = store+f;
+
+   int l1 = f-f0;    while (l1--) *elx++ = 0.0;
+       l1 = l-f;     while (l1--) *elx++ /= *eld++;
+       lx -= l;      while (lx--) *elx++ = 0.0;
+   // Solver makes sure input and output point to same memory
+}
+
+void IdentityMatrix::Solver(MatrixColX& mrc, const MatrixColX& mrc1)
+{
+   // mrc = mrc / mrc1   (elementwise)
+   REPORT
+   int f = mrc1.skip; int f0 = mrc.skip;
+   int l = f + mrc1.storage; int lx = f0 + mrc.storage;
+   if (f < f0) { f = f0; if (l < f) l = f; }
+   if (l > lx) { l = lx; if (f > lx) f = lx; }
+
+   Real* elx = mrc.data; Real eldv = *store;
+
+   int l1 = f-f0;    while (l1--) *elx++ = 0.0;
+       l1 = l-f;     while (l1--) *elx++ /= eldv;
+       lx -= l;      while (lx--) *elx++ = 0.0;
+   // Solver makes sure input and output point to same memory
+}
+
+void MatrixRowCol::Copy(const double*& r)
+{
+   // THIS = *r
+   REPORT
+   Real* elx = data; const double* ely = r+skip; r += length;
+   int l = storage; while (l--) *elx++ = (Real)*ely++;
+}
+
+void MatrixRowCol::Copy(const float*& r)
+{
+   // THIS = *r
+   REPORT
+   Real* elx = data; const float* ely = r+skip; r += length;
+   int l = storage; while (l--) *elx++ = (Real)*ely++;
+}
+
+void MatrixRowCol::Copy(const int*& r)
+{
+   // THIS = *r
+   REPORT
+   Real* elx = data; const int* ely = r+skip; r += length;
+   int l = storage; while (l--) *elx++ = (Real)*ely++;
+}
+
+void MatrixRowCol::Copy(Real r)
+{
+   // THIS = r
+   REPORT  Real* elx = data; int l = storage; while (l--) *elx++ = r;
+}
+
+void MatrixRowCol::Zero()
+{
+   // THIS = 0
+   REPORT  Real* elx = data; int l = storage; while (l--) *elx++ = 0;
+}
+
+void MatrixRowCol::Multiply(Real r)
+{
+   // THIS *= r
+   REPORT  Real* elx = data; int l = storage; while (l--) *elx++ *= r;
+}
+
+void MatrixRowCol::Add(Real r)
+{
+   // THIS += r
+   REPORT
+   Real* elx = data; int l = storage; while (l--) *elx++ += r;
+}
+
+Real MatrixRowCol::SumAbsoluteValue()
+{
+   REPORT
+   Real sum = 0.0; Real* elx = data; int l = storage;
+   while (l--) sum += fabs(*elx++);
+   return sum;
+}
+
+// max absolute value of r and elements of row/col
+// we use <= or >= in all of these so we are sure of getting
+// r reset at least once.
+Real MatrixRowCol::MaximumAbsoluteValue1(Real r, int& i)
+{
+   REPORT
+   Real* elx = data; int l = storage; int li = -1;
+   while (l--) { Real f = fabs(*elx++); if (r <= f) { r = f; li = l; } }
+   i = (li >= 0) ? storage - li + skip : 0;
+   return r;
+}
+
+// min absolute value of r and elements of row/col
+Real MatrixRowCol::MinimumAbsoluteValue1(Real r, int& i)
+{
+   REPORT
+   Real* elx = data; int l = storage; int li = -1;
+   while (l--) { Real f = fabs(*elx++); if (r >= f) { r = f; li = l; } }
+   i = (li >= 0) ? storage - li + skip : 0;
+   return r;
+}
+
+// max value of r and elements of row/col
+Real MatrixRowCol::Maximum1(Real r, int& i)
+{
+   REPORT
+   Real* elx = data; int l = storage; int li = -1;
+   while (l--) { Real f = *elx++; if (r <= f) { r = f; li = l; } }
+   i = (li >= 0) ? storage - li + skip : 0;
+   return r;
+}
+
+// min value of r and elements of row/col
+Real MatrixRowCol::Minimum1(Real r, int& i)
+{
+   REPORT
+   Real* elx = data; int l = storage; int li = -1;
+   while (l--) { Real f = *elx++; if (r >= f) { r = f; li = l; } }
+   i = (li >= 0) ? storage - li + skip : 0;
+   return r;
+}
+
+Real MatrixRowCol::Sum()
+{
+   REPORT
+   Real sum = 0.0; Real* elx = data; int l = storage;
+   while (l--) sum += *elx++;
+   return sum;
+}
+
+void MatrixRowCol::SubRowCol(MatrixRowCol& mrc, int skip1, int l1) const
+{
+   mrc.length = l1;  int d = skip - skip1;
+   if (d<0) { mrc.skip = 0; mrc.data = data - d; }
+   else  { mrc.skip = d; mrc.data = data; }
+   d = skip + storage - skip1;
+   d = ((l1 < d) ? l1 : d) - mrc.skip;  mrc.storage = (d < 0) ? 0 : d;
+   mrc.cw = 0;
+}
+
+#ifdef use_namespace
+}
+#endif
+
+
+///@}
Index: /nanovis/tags/1.1.4/newmat11/newmat3.cpp
===================================================================
--- /nanovis/tags/1.1.4/newmat11/newmat3.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/newmat11/newmat3.cpp	(revision 4930)
@@ -0,0 +1,849 @@
+/// \ingroup newmat
+///@{
+
+/// \file newmat3.cpp
+/// Get and restore rows and columns.
+
+// Copyright (C) 1991,2,3,4: R B Davies
+
+//#define WANT_STREAM
+
+#include "include.h"
+
+#include "newmat.h"
+#include "newmatrc.h"
+
+#ifdef use_namespace
+namespace NEWMAT {
+#endif
+
+
+#ifdef DO_REPORT
+#define REPORT { static ExeCounter ExeCount(__LINE__,3); ++ExeCount; }
+#else
+#define REPORT {}
+#endif
+
+//#define MONITOR(what,storage,store)
+//   { cout << what << " " << storage << " at " << (long)store << "\n"; }
+
+#define MONITOR(what,store,storage) {}
+
+
+// Control bits codes for GetRow, GetCol, RestoreRow, RestoreCol
+//
+// LoadOnEntry:
+//    Load data into MatrixRow or Col dummy array under GetRow or GetCol
+// StoreOnExit:
+//    Restore data to original matrix under RestoreRow or RestoreCol
+// DirectPart:
+//    Load or restore only part directly stored; must be set with StoreOnExit
+//    Still have decide how to handle this with symmetric
+// StoreHere:
+//    used in columns only - store data at supplied storage address;
+//    used for GetCol, NextCol & RestoreCol. No need to fill out zeros
+// HaveStore:
+//    dummy array has been assigned (internal use only).
+
+// For symmetric matrices, treat columns as rows unless StoreHere is set;
+// then stick to columns as this will give better performance for doing
+// inverses
+
+// How components are used:
+
+// Use rows wherever possible in preference to columns
+
+// Columns without StoreHere are used in in-exact transpose, sum column,
+// multiply a column vector, and maybe in future access to column,
+// additional multiply functions, add transpose
+
+// Columns with StoreHere are used in exact transpose (not symmetric matrices
+// or vectors, load only)
+
+// Columns with MatrixColX (Store to full column) are used in inverse and solve
+
+// Functions required for each matrix class
+
+// GetRow(MatrixRowCol& mrc)
+// GetCol(MatrixRowCol& mrc)
+// GetCol(MatrixColX& mrc)
+// RestoreRow(MatrixRowCol& mrc)
+// RestoreCol(MatrixRowCol& mrc)
+// RestoreCol(MatrixColX& mrc)
+// NextRow(MatrixRowCol& mrc)
+// NextCol(MatrixRowCol& mrc)
+// NextCol(MatrixColX& mrc)
+
+// The Restore routines assume StoreOnExit has already been checked
+// Defaults for the Next routines are given below
+// Assume cannot have both !DirectPart && StoreHere for MatrixRowCol routines
+
+
+// Default NextRow and NextCol:
+// will work as a default but need to override NextRow for efficiency
+
+void GeneralMatrix::NextRow(MatrixRowCol& mrc)
+{
+   REPORT
+   if (+(mrc.cw*StoreOnExit)) { REPORT this->RestoreRow(mrc); }
+   mrc.rowcol++;
+   if (mrc.rowcol<nrows_val) { REPORT this->GetRow(mrc); }
+   else { REPORT mrc.cw -= StoreOnExit; }
+}
+
+void GeneralMatrix::NextCol(MatrixRowCol& mrc)
+{
+   REPORT                                                // 423
+   if (+(mrc.cw*StoreOnExit)) { REPORT this->RestoreCol(mrc); }
+   mrc.rowcol++;
+   if (mrc.rowcol<ncols_val) { REPORT this->GetCol(mrc); }
+   else { REPORT mrc.cw -= StoreOnExit; }
+}
+
+void GeneralMatrix::NextCol(MatrixColX& mrc)
+{
+   REPORT                                                // 423
+   if (+(mrc.cw*StoreOnExit)) { REPORT this->RestoreCol(mrc); }
+   mrc.rowcol++;
+   if (mrc.rowcol<ncols_val) { REPORT this->GetCol(mrc); }
+   else { REPORT mrc.cw -= StoreOnExit; }
+}
+
+
+// routines for matrix
+
+void Matrix::GetRow(MatrixRowCol& mrc)
+{
+   REPORT
+   mrc.skip=0; mrc.storage=mrc.length=ncols_val;
+   mrc.data=store+mrc.rowcol*ncols_val;
+}
+
+
+void Matrix::GetCol(MatrixRowCol& mrc)
+{
+   REPORT
+   mrc.skip=0; mrc.storage=mrc.length=nrows_val;
+   if ( ncols_val==1 && !(mrc.cw*StoreHere) )      // ColumnVector
+      { REPORT mrc.data=store; }
+   else
+   {
+      Real* ColCopy;
+      if ( !(mrc.cw*(HaveStore+StoreHere)) )
+      {
+         REPORT
+         ColCopy = new Real [nrows_val]; MatrixErrorNoSpace(ColCopy);
+         MONITOR_REAL_NEW("Make (MatGetCol)",nrows_val,ColCopy)
+         mrc.data = ColCopy; mrc.cw += HaveStore;
+      }
+      else { REPORT ColCopy = mrc.data; }
+      if (+(mrc.cw*LoadOnEntry))
+      {
+         REPORT
+         Real* Mstore = store+mrc.rowcol; int i=nrows_val;
+         //while (i--) { *ColCopy++ = *Mstore; Mstore+=ncols_val; }
+         if (i) for (;;)
+            { *ColCopy++ = *Mstore; if (!(--i)) break; Mstore+=ncols_val; }
+      }
+   }
+}
+
+void Matrix::GetCol(MatrixColX& mrc)
+{
+   REPORT
+   mrc.skip=0; mrc.storage=nrows_val; mrc.length=nrows_val;
+   if (+(mrc.cw*LoadOnEntry))
+   {
+      REPORT  Real* ColCopy = mrc.data;
+      Real* Mstore = store+mrc.rowcol; int i=nrows_val;
+      //while (i--) { *ColCopy++ = *Mstore; Mstore+=ncols_val; }
+      if (i) for (;;)
+          { *ColCopy++ = *Mstore; if (!(--i)) break; Mstore+=ncols_val; }
+   }
+}
+
+void Matrix::RestoreCol(MatrixRowCol& mrc)
+{
+   // always check StoreOnExit before calling RestoreCol
+   REPORT                                   // 429
+   if (+(mrc.cw*HaveStore))
+   {
+      REPORT                                // 426
+      Real* Mstore = store+mrc.rowcol; int i=nrows_val;
+      Real* Cstore = mrc.data;
+      // while (i--) { *Mstore = *Cstore++; Mstore+=ncols_val; }
+      if (i) for (;;)
+          { *Mstore = *Cstore++; if (!(--i)) break; Mstore+=ncols_val; }
+   }
+}
+
+void Matrix::RestoreCol(MatrixColX& mrc)
+{
+   REPORT
+   Real* Mstore = store+mrc.rowcol; int i=nrows_val; Real* Cstore = mrc.data;
+   // while (i--) { *Mstore = *Cstore++; Mstore+=ncols_val; }
+   if (i) for (;;)
+      { *Mstore = *Cstore++; if (!(--i)) break; Mstore+=ncols_val; }
+}
+
+void Matrix::NextRow(MatrixRowCol& mrc) { REPORT mrc.IncrMat(); }  // 1808
+
+void Matrix::NextCol(MatrixRowCol& mrc)
+{
+   REPORT                                        // 632
+   if (+(mrc.cw*StoreOnExit)) { REPORT RestoreCol(mrc); }
+   mrc.rowcol++;
+   if (mrc.rowcol<ncols_val)
+   {
+      if (+(mrc.cw*LoadOnEntry))
+      {
+         REPORT
+         Real* ColCopy = mrc.data;
+         Real* Mstore = store+mrc.rowcol; int i=nrows_val;
+         //while (i--) { *ColCopy++ = *Mstore; Mstore+=ncols_val; }
+         if (i) for (;;)
+            { *ColCopy++ = *Mstore; if (!(--i)) break; Mstore+=ncols_val; }
+      }
+   }
+   else { REPORT mrc.cw -= StoreOnExit; }
+}
+
+void Matrix::NextCol(MatrixColX& mrc)
+{
+   REPORT
+   if (+(mrc.cw*StoreOnExit)) { REPORT RestoreCol(mrc); }
+   mrc.rowcol++;
+   if (mrc.rowcol<ncols_val)
+   {
+      if (+(mrc.cw*LoadOnEntry))
+      {
+         REPORT
+         Real* ColCopy = mrc.data;
+         Real* Mstore = store+mrc.rowcol; int i=nrows_val;
+         // while (i--) { *ColCopy++ = *Mstore; Mstore+=ncols_val; }
+         if (i) for (;;)
+            { *ColCopy++ = *Mstore; if (!(--i)) break; Mstore+=ncols_val; }
+      }
+   }
+   else { REPORT mrc.cw -= StoreOnExit; }
+}
+
+// routines for diagonal matrix
+
+void DiagonalMatrix::GetRow(MatrixRowCol& mrc)
+{
+   REPORT
+   mrc.skip=mrc.rowcol; mrc.storage=1;
+   mrc.data=store+mrc.skip; mrc.length=ncols_val;
+}
+
+void DiagonalMatrix::GetCol(MatrixRowCol& mrc)
+{
+   REPORT
+   mrc.skip=mrc.rowcol; mrc.storage=1; mrc.length=nrows_val;
+   if (+(mrc.cw*StoreHere))              // should not happen
+      Throw(InternalException("DiagonalMatrix::GetCol(MatrixRowCol&)"));
+   else  { REPORT mrc.data=store+mrc.skip; }
+                                                      // not accessed
+}
+
+void DiagonalMatrix::GetCol(MatrixColX& mrc)
+{
+   REPORT
+   mrc.skip=mrc.rowcol; mrc.storage=1; mrc.length=nrows_val;
+   mrc.data = mrc.store+mrc.skip;
+   *(mrc.data)=*(store+mrc.skip);
+}
+
+void DiagonalMatrix::NextRow(MatrixRowCol& mrc) { REPORT mrc.IncrDiag(); }
+                        // 800
+
+void DiagonalMatrix::NextCol(MatrixRowCol& mrc) { REPORT mrc.IncrDiag(); }
+                        // not accessed
+
+void DiagonalMatrix::NextCol(MatrixColX& mrc)
+{
+   REPORT
+   if (+(mrc.cw*StoreOnExit))
+      { REPORT *(store+mrc.rowcol)=*(mrc.data); }
+   mrc.IncrDiag();
+   int t1 = +(mrc.cw*LoadOnEntry);
+   if (t1 && mrc.rowcol < ncols_val)
+      { REPORT *(mrc.data)=*(store+mrc.rowcol); }
+}
+
+// routines for upper triangular matrix
+
+void UpperTriangularMatrix::GetRow(MatrixRowCol& mrc)
+{
+   REPORT
+   int row = mrc.rowcol; mrc.skip=row; mrc.length=ncols_val;
+   mrc.storage=ncols_val-row; mrc.data=store+(row*(2*ncols_val-row+1))/2;
+}
+
+
+void UpperTriangularMatrix::GetCol(MatrixRowCol& mrc)
+{
+   REPORT
+   mrc.skip=0; int i=mrc.rowcol+1; mrc.storage=i;
+   mrc.length=nrows_val; Real* ColCopy;
+   if ( !(mrc.cw*(StoreHere+HaveStore)) )
+   {
+      REPORT                                              // not accessed
+      ColCopy = new Real [nrows_val]; MatrixErrorNoSpace(ColCopy);
+      MONITOR_REAL_NEW("Make (UT GetCol)",nrows_val,ColCopy)
+      mrc.data = ColCopy; mrc.cw += HaveStore;
+   }
+   else { REPORT ColCopy = mrc.data; }
+   if (+(mrc.cw*LoadOnEntry))
+   {
+      REPORT
+      Real* Mstore = store+mrc.rowcol; int j = ncols_val;
+      // while (i--) { *ColCopy++ = *Mstore; Mstore += --j; }
+      if (i) for (;;)
+         { *ColCopy++ = *Mstore; if (!(--i)) break; Mstore += --j; }
+   }
+}
+
+void UpperTriangularMatrix::GetCol(MatrixColX& mrc)
+{
+   REPORT
+   mrc.skip=0; int i=mrc.rowcol+1; mrc.storage=i;
+   mrc.length=nrows_val;
+   if (+(mrc.cw*LoadOnEntry))
+   {
+      REPORT
+      Real* ColCopy = mrc.data;
+      Real* Mstore = store+mrc.rowcol; int j = ncols_val;
+      // while (i--) { *ColCopy++ = *Mstore; Mstore += --j; }
+      if (i) for (;;)
+         { *ColCopy++ = *Mstore; if (!(--i)) break; Mstore += --j; }
+   }
+}
+
+void UpperTriangularMatrix::RestoreCol(MatrixRowCol& mrc)
+{
+  REPORT
+  Real* Mstore = store+mrc.rowcol; int i=mrc.rowcol+1; int j = ncols_val;
+  Real* Cstore = mrc.data;
+  // while (i--) { *Mstore = *Cstore++; Mstore += --j; }
+  if (i) for (;;)
+     { *Mstore = *Cstore++; if (!(--i)) break; Mstore += --j; }
+}
+
+void UpperTriangularMatrix::NextRow(MatrixRowCol& mrc) { REPORT mrc.IncrUT(); }
+						      // 722
+
+// routines for lower triangular matrix
+
+void LowerTriangularMatrix::GetRow(MatrixRowCol& mrc)
+{
+   REPORT
+   int row=mrc.rowcol; mrc.skip=0; mrc.storage=row+1; mrc.length=ncols_val;
+   mrc.data=store+(row*(row+1))/2;
+}
+
+void LowerTriangularMatrix::GetCol(MatrixRowCol& mrc)
+{
+   REPORT
+   int col=mrc.rowcol; mrc.skip=col; mrc.length=nrows_val;
+   int i=nrows_val-col; mrc.storage=i; Real* ColCopy;
+   if ( +(mrc.cw*(StoreHere+HaveStore)) )
+      { REPORT  ColCopy = mrc.data; }
+   else
+   {
+      REPORT                                            // not accessed
+      ColCopy = new Real [nrows_val]; MatrixErrorNoSpace(ColCopy);
+      MONITOR_REAL_NEW("Make (LT GetCol)",nrows_val,ColCopy)
+      mrc.cw += HaveStore; mrc.data = ColCopy;
+   }
+
+   if (+(mrc.cw*LoadOnEntry))
+   {
+      REPORT
+      Real* Mstore = store+(col*(col+3))/2;
+      // while (i--) { *ColCopy++ = *Mstore; Mstore += ++col; }
+      if (i) for (;;)
+         { *ColCopy++ = *Mstore; if (!(--i)) break; Mstore += ++col; }
+   }
+}
+
+void LowerTriangularMatrix::GetCol(MatrixColX& mrc)
+{
+   REPORT
+   int col=mrc.rowcol; mrc.skip=col; mrc.length=nrows_val;
+   int i=nrows_val-col; mrc.storage=i; mrc.data = mrc.store + col;
+
+   if (+(mrc.cw*LoadOnEntry))
+   {
+      REPORT  Real* ColCopy = mrc.data;
+      Real* Mstore = store+(col*(col+3))/2;
+      // while (i--) { *ColCopy++ = *Mstore; Mstore += ++col; }
+      if (i) for (;;)
+         { *ColCopy++ = *Mstore; if (!(--i)) break; Mstore += ++col; }
+   }
+}
+
+void LowerTriangularMatrix::RestoreCol(MatrixRowCol& mrc)
+{
+   REPORT
+   int col=mrc.rowcol; Real* Cstore = mrc.data;
+   Real* Mstore = store+(col*(col+3))/2; int i=nrows_val-col;
+   //while (i--) { *Mstore = *Cstore++; Mstore += ++col; }
+   if (i) for (;;)
+      { *Mstore = *Cstore++; if (!(--i)) break; Mstore += ++col; }
+}
+
+void LowerTriangularMatrix::NextRow(MatrixRowCol& mrc) { REPORT mrc.IncrLT(); }
+					                 //712
+
+// routines for symmetric matrix
+
+void SymmetricMatrix::GetRow(MatrixRowCol& mrc)
+{
+   REPORT                                                //571
+   mrc.skip=0; int row=mrc.rowcol; mrc.length=ncols_val;
+   if (+(mrc.cw*DirectPart))
+      { REPORT mrc.storage=row+1; mrc.data=store+(row*(row+1))/2; }
+   else
+   {
+      // do not allow StoreOnExit and !DirectPart
+      if (+(mrc.cw*StoreOnExit))
+         Throw(InternalException("SymmetricMatrix::GetRow(MatrixRowCol&)"));
+      mrc.storage=ncols_val; Real* RowCopy;
+      if (!(mrc.cw*HaveStore))
+      {
+         REPORT
+         RowCopy = new Real [ncols_val]; MatrixErrorNoSpace(RowCopy);
+         MONITOR_REAL_NEW("Make (SymGetRow)",ncols_val,RowCopy)
+         mrc.cw += HaveStore; mrc.data = RowCopy;
+      }
+      else { REPORT RowCopy = mrc.data; }
+      if (+(mrc.cw*LoadOnEntry))
+      {
+         REPORT                                         // 544
+         Real* Mstore = store+(row*(row+1))/2; int i = row;
+         while (i--) *RowCopy++ = *Mstore++;
+         i = ncols_val-row;
+         // while (i--) { *RowCopy++ = *Mstore; Mstore += ++row; }
+         if (i) for (;;)
+            { *RowCopy++ = *Mstore; if (!(--i)) break; Mstore += ++row; }
+      }
+   }
+}
+
+void SymmetricMatrix::GetCol(MatrixRowCol& mrc)
+{
+   // do not allow StoreHere
+   if (+(mrc.cw*StoreHere))
+      Throw(InternalException("SymmetricMatrix::GetCol(MatrixRowCol&)"));
+
+   int col=mrc.rowcol; mrc.length=nrows_val;
+   REPORT
+   mrc.skip=0;
+   if (+(mrc.cw*DirectPart))    // actually get row ??
+      { REPORT mrc.storage=col+1; mrc.data=store+(col*(col+1))/2; }
+   else
+   {
+      // do not allow StoreOnExit and !DirectPart
+      if (+(mrc.cw*StoreOnExit))
+         Throw(InternalException("SymmetricMatrix::GetCol(MatrixRowCol&)"));
+
+      mrc.storage=ncols_val; Real* ColCopy;
+      if ( +(mrc.cw*HaveStore)) { REPORT ColCopy = mrc.data; }
+      else
+      {
+         REPORT                                      // not accessed
+         ColCopy = new Real [ncols_val]; MatrixErrorNoSpace(ColCopy);
+         MONITOR_REAL_NEW("Make (SymGetCol)",ncols_val,ColCopy)
+         mrc.cw += HaveStore; mrc.data = ColCopy;
+      }
+      if (+(mrc.cw*LoadOnEntry))
+      {
+         REPORT
+         Real* Mstore = store+(col*(col+1))/2; int i = col;
+         while (i--) *ColCopy++ = *Mstore++;
+         i = ncols_val-col;
+         // while (i--) { *ColCopy++ = *Mstore; Mstore += ++col; }
+         if (i) for (;;)
+            { *ColCopy++ = *Mstore; if (!(--i)) break; Mstore += ++col; }
+      }
+   }
+}
+
+void SymmetricMatrix::GetCol(MatrixColX& mrc)
+{
+   int col=mrc.rowcol; mrc.length=nrows_val;
+   if (+(mrc.cw*DirectPart))
+   {
+      REPORT
+      mrc.skip=col; int i=nrows_val-col; mrc.storage=i;
+      mrc.data = mrc.store+col;
+      if (+(mrc.cw*LoadOnEntry))
+      {
+         REPORT                           // not accessed
+         Real* ColCopy = mrc.data;
+         Real* Mstore = store+(col*(col+3))/2;
+         // while (i--) { *ColCopy++ = *Mstore; Mstore += ++col; }
+         if (i) for (;;)
+            { *ColCopy++ = *Mstore; if (!(--i)) break; Mstore += ++col; }
+      }
+   }
+   else
+   {
+      REPORT
+      // do not allow StoreOnExit and !DirectPart
+      if (+(mrc.cw*StoreOnExit))
+         Throw(InternalException("SymmetricMatrix::GetCol(MatrixColX&)"));
+
+      mrc.skip=0; mrc.storage=ncols_val;
+      if (+(mrc.cw*LoadOnEntry))
+      {
+         REPORT
+         Real* ColCopy = mrc.data;
+         Real* Mstore = store+(col*(col+1))/2; int i = col;
+         while (i--) *ColCopy++ = *Mstore++;
+         i = ncols_val-col;
+         // while (i--) { *ColCopy++ = *Mstore; Mstore += ++col; }
+         if (i) for (;;)
+            { *ColCopy++ = *Mstore; if (!(--i)) break; Mstore += ++col; }
+      }
+   }
+}
+
+// Do not need RestoreRow because we do not allow !DirectPart && StoreOnExit
+
+void SymmetricMatrix::RestoreCol(MatrixColX& mrc)
+{
+   REPORT
+   // Really do restore column
+   int col=mrc.rowcol; Real* Cstore = mrc.data;
+   Real* Mstore = store+(col*(col+3))/2; int i = nrows_val-col;
+   // while (i--) { *Mstore = *Cstore++; Mstore+= ++col; }
+   if (i) for (;;)
+      { *Mstore = *Cstore++; if (!(--i)) break; Mstore+= ++col; }
+
+}
+
+// routines for row vector
+
+void RowVector::GetCol(MatrixRowCol& mrc)
+{
+   REPORT
+   // do not allow StoreHere
+   if (+(mrc.cw*StoreHere))
+      Throw(InternalException("RowVector::GetCol(MatrixRowCol&)"));
+
+   mrc.skip=0; mrc.storage=1; mrc.length=nrows_val;
+   mrc.data = store+mrc.rowcol;
+
+}
+
+void RowVector::GetCol(MatrixColX& mrc)
+{
+   REPORT
+   mrc.skip=0; mrc.storage=1; mrc.length=nrows_val;
+   if (mrc.cw >= LoadOnEntry)
+      { REPORT *(mrc.data) = *(store+mrc.rowcol); }
+
+}
+
+void RowVector::NextCol(MatrixRowCol& mrc)
+{ REPORT mrc.rowcol++; mrc.data++; }
+
+void RowVector::NextCol(MatrixColX& mrc)
+{
+   if (+(mrc.cw*StoreOnExit)) { REPORT *(store+mrc.rowcol)=*(mrc.data); }
+
+   mrc.rowcol++;
+   if (mrc.rowcol < ncols_val)
+   {
+      if (+(mrc.cw*LoadOnEntry)) { REPORT *(mrc.data)=*(store+mrc.rowcol); }
+   }
+   else { REPORT mrc.cw -= StoreOnExit; }
+}
+
+void RowVector::RestoreCol(MatrixColX& mrc)
+   { REPORT *(store+mrc.rowcol)=*(mrc.data); }           // not accessed
+
+
+// routines for band matrices
+
+void BandMatrix::GetRow(MatrixRowCol& mrc)
+{
+   REPORT
+   int r = mrc.rowcol; int w = lower_val+1+upper_val; mrc.length=ncols_val;
+   int s = r-lower_val;
+   if (s<0) { mrc.data = store+(r*w-s); w += s; s = 0; }
+   else mrc.data = store+r*w;
+   mrc.skip = s; s += w-ncols_val; if (s>0) w -= s; mrc.storage = w;
+}
+
+// should make special versions of this for upper and lower band matrices
+
+void BandMatrix::NextRow(MatrixRowCol& mrc)
+{
+   REPORT
+   int r = ++mrc.rowcol;
+   if (r<=lower_val) { mrc.storage++; mrc.data += lower_val+upper_val; }
+   else  { mrc.skip++; mrc.data += lower_val+upper_val+1; }
+   if (r>=ncols_val-upper_val) mrc.storage--;
+}
+
+void BandMatrix::GetCol(MatrixRowCol& mrc)
+{
+   REPORT
+   int c = mrc.rowcol; int n = lower_val+upper_val; int w = n+1;
+   mrc.length=nrows_val; Real* ColCopy;
+   int b; int s = c-upper_val;
+   if (s<=0) { w += s; s = 0; b = c+lower_val; } else b = s*w+n;
+   mrc.skip = s; s += w-nrows_val; if (s>0) w -= s; mrc.storage = w;
+   if ( +(mrc.cw*(StoreHere+HaveStore)) )
+      { REPORT ColCopy = mrc.data; }
+   else
+   {
+      REPORT
+      ColCopy = new Real [n+1]; MatrixErrorNoSpace(ColCopy);
+      MONITOR_REAL_NEW("Make (BMGetCol)",n+1,ColCopy)
+      mrc.cw += HaveStore; mrc.data = ColCopy;
+   }
+
+   if (+(mrc.cw*LoadOnEntry))
+   {
+      REPORT
+      Real* Mstore = store+b;
+      // while (w--) { *ColCopy++ = *Mstore; Mstore+=n; }
+      if (w) for (;;)
+         { *ColCopy++ = *Mstore; if (!(--w)) break; Mstore+=n; }
+   }
+}
+
+void BandMatrix::GetCol(MatrixColX& mrc)
+{
+   REPORT
+   int c = mrc.rowcol; int n = lower_val+upper_val; int w = n+1;
+   mrc.length=nrows_val; int b; int s = c-upper_val;
+   if (s<=0) { w += s; s = 0; b = c+lower_val; } else b = s*w+n;
+   mrc.skip = s; s += w-nrows_val; if (s>0) w -= s; mrc.storage = w;
+   mrc.data = mrc.store+mrc.skip;
+
+   if (+(mrc.cw*LoadOnEntry))
+   {
+      REPORT
+      Real* ColCopy = mrc.data; Real* Mstore = store+b;
+      // while (w--) { *ColCopy++ = *Mstore; Mstore+=n; }
+      if (w) for (;;)
+         { *ColCopy++ = *Mstore; if (!(--w)) break; Mstore+=n; }
+   }
+}
+
+void BandMatrix::RestoreCol(MatrixRowCol& mrc)
+{
+   REPORT
+   int c = mrc.rowcol; int n = lower_val+upper_val; int s = c-upper_val;
+   Real* Mstore = store + ((s<=0) ? c+lower_val : s*n+s+n);
+   Real* Cstore = mrc.data;
+   int w = mrc.storage;
+   // while (w--) { *Mstore = *Cstore++; Mstore += n; }
+   if (w) for (;;)
+      { *Mstore = *Cstore++; if (!(--w)) break; Mstore += n; }
+}
+
+// routines for symmetric band matrix
+
+void SymmetricBandMatrix::GetRow(MatrixRowCol& mrc)
+{
+   REPORT
+   int r=mrc.rowcol; int s = r-lower_val; int w1 = lower_val+1; int o = r*w1;
+   mrc.length = ncols_val;
+   if (s<0) { w1 += s; o -= s; s = 0; }
+   mrc.skip = s;
+
+   if (+(mrc.cw*DirectPart))
+      { REPORT  mrc.data = store+o; mrc.storage = w1; }
+   else
+   {
+      // do not allow StoreOnExit and !DirectPart
+      if (+(mrc.cw*StoreOnExit))
+         Throw(InternalException("SymmetricBandMatrix::GetRow(MatrixRowCol&)"));
+      int w = w1+lower_val; s += w-ncols_val; Real* RowCopy;
+      if (s>0) w -= s; mrc.storage = w; int w2 = w-w1;
+      if (!(mrc.cw*HaveStore))
+      {
+         REPORT
+         RowCopy = new Real [2*lower_val+1]; MatrixErrorNoSpace(RowCopy);
+         MONITOR_REAL_NEW("Make (SmBGetRow)",2*lower_val+1,RowCopy)
+         mrc.cw += HaveStore; mrc.data = RowCopy;
+      }
+      else { REPORT  RowCopy = mrc.data; }
+
+      if (+(mrc.cw*LoadOnEntry) && ncols_val > 0)
+      {
+         REPORT
+         Real* Mstore = store+o;
+         while (w1--) *RowCopy++ = *Mstore++;
+         Mstore--;
+         while (w2--) { Mstore += lower_val; *RowCopy++ = *Mstore; }
+      }
+   }
+}
+
+void SymmetricBandMatrix::GetCol(MatrixRowCol& mrc)
+{
+   // do not allow StoreHere
+   if (+(mrc.cw*StoreHere))
+      Throw(InternalException("SymmetricBandMatrix::GetCol(MatrixRowCol&)"));
+
+   int c=mrc.rowcol; int w1 = lower_val+1; mrc.length=nrows_val;
+   REPORT
+   int s = c-lower_val; int o = c*w1;
+   if (s<0) { w1 += s; o -= s; s = 0; }
+   mrc.skip = s;
+
+   if (+(mrc.cw*DirectPart))
+   { REPORT  mrc.data = store+o; mrc.storage = w1; }
+   else
+   {
+      // do not allow StoreOnExit and !DirectPart
+      if (+(mrc.cw*StoreOnExit))
+         Throw(InternalException("SymmetricBandMatrix::GetCol(MatrixRowCol&)"));
+      int w = w1+lower_val; s += w-ncols_val; Real* ColCopy;
+      if (s>0) w -= s; mrc.storage = w; int w2 = w-w1;
+
+      if ( +(mrc.cw*HaveStore) ) { REPORT ColCopy = mrc.data; }
+      else
+      {
+         REPORT ColCopy = new Real [2*lower_val+1]; MatrixErrorNoSpace(ColCopy);
+         MONITOR_REAL_NEW("Make (SmBGetCol)",2*lower_val+1,ColCopy)
+         mrc.cw += HaveStore; mrc.data = ColCopy;
+      }
+
+      if (+(mrc.cw*LoadOnEntry))
+      {
+         REPORT
+         Real* Mstore = store+o;
+         while (w1--) *ColCopy++ = *Mstore++;
+         Mstore--;
+         while (w2--) { Mstore += lower_val; *ColCopy++ = *Mstore; }
+      }
+   }
+}
+
+void SymmetricBandMatrix::GetCol(MatrixColX& mrc)
+{
+   int c=mrc.rowcol; int w1 = lower_val+1; mrc.length=nrows_val;
+   if (+(mrc.cw*DirectPart))
+   {
+      REPORT
+      int b = c*w1+lower_val;
+      mrc.skip = c; c += w1-nrows_val; w1 -= c; mrc.storage = w1;
+      Real* ColCopy = mrc.data = mrc.store+mrc.skip;
+      if (+(mrc.cw*LoadOnEntry))
+      {
+         REPORT
+         Real* Mstore = store+b;
+         // while (w1--) { *ColCopy++ = *Mstore; Mstore += lower; }
+         if (w1) for (;;)
+            { *ColCopy++ = *Mstore; if (!(--w1)) break; Mstore += lower_val; }
+      }
+   }
+   else
+   {
+      REPORT
+      // do not allow StoreOnExit and !DirectPart
+      if (+(mrc.cw*StoreOnExit))
+         Throw(InternalException("SymmetricBandMatrix::GetCol(MatrixColX&)"));
+      int s = c-lower_val; int o = c*w1;
+      if (s<0) { w1 += s; o -= s; s = 0; }
+      mrc.skip = s;
+
+      int w = w1+lower_val; s += w-ncols_val;
+      if (s>0) w -= s; mrc.storage = w; int w2 = w-w1;
+
+      Real* ColCopy = mrc.data = mrc.store+mrc.skip;
+
+      if (+(mrc.cw*LoadOnEntry))
+      {
+         REPORT
+         Real* Mstore = store+o;
+         while (w1--) *ColCopy++ = *Mstore++;
+         Mstore--;
+         while (w2--) { Mstore += lower_val; *ColCopy++ = *Mstore; }
+      }
+
+   }
+}
+
+void SymmetricBandMatrix::RestoreCol(MatrixColX& mrc)
+{
+   REPORT
+   int c = mrc.rowcol;
+   Real* Mstore = store + c*lower_val+c+lower_val;
+   Real* Cstore = mrc.data; int w = mrc.storage;
+   // while (w--) { *Mstore = *Cstore++; Mstore += lower_val; }
+   if (w) for (;;)
+      { *Mstore = *Cstore++; if (!(--w)) break; Mstore += lower_val; }
+}
+
+// routines for identity matrix
+
+void IdentityMatrix::GetRow(MatrixRowCol& mrc)
+{
+   REPORT
+   mrc.skip=mrc.rowcol; mrc.storage=1; mrc.data=store; mrc.length=ncols_val;
+}
+
+void IdentityMatrix::GetCol(MatrixRowCol& mrc)
+{
+   REPORT
+   mrc.skip=mrc.rowcol; mrc.storage=1; mrc.length=nrows_val;
+   if (+(mrc.cw*StoreHere))              // should not happen
+      Throw(InternalException("IdentityMatrix::GetCol(MatrixRowCol&)"));
+   else  { REPORT mrc.data=store; }
+}
+
+void IdentityMatrix::GetCol(MatrixColX& mrc)
+{
+   REPORT
+   mrc.skip=mrc.rowcol; mrc.storage=1; mrc.length=nrows_val;
+   mrc.data = mrc.store+mrc.skip; *(mrc.data)=*store;
+}
+
+void IdentityMatrix::NextRow(MatrixRowCol& mrc) { REPORT mrc.IncrId(); }
+
+void IdentityMatrix::NextCol(MatrixRowCol& mrc) { REPORT mrc.IncrId(); }
+
+void IdentityMatrix::NextCol(MatrixColX& mrc)
+{
+   REPORT
+   if (+(mrc.cw*StoreOnExit)) { REPORT *store=*(mrc.data); }
+   mrc.IncrDiag();            // must increase mrc.data so need IncrDiag
+   int t1 = +(mrc.cw*LoadOnEntry);
+   if (t1 && mrc.rowcol < ncols_val) { REPORT *(mrc.data)=*store; }
+}
+
+
+
+
+// *************************** destructors *******************************
+
+MatrixRowCol::~MatrixRowCol()
+{
+   if (+(cw*HaveStore))
+   {
+      MONITOR_REAL_DELETE("Free    (RowCol)",-1,data)  // do not know length
+      delete [] data;
+   }
+}
+
+MatrixRow::~MatrixRow() { if (+(cw*StoreOnExit)) gm->RestoreRow(*this); }
+
+MatrixCol::~MatrixCol() { if (+(cw*StoreOnExit)) gm->RestoreCol(*this); }
+
+MatrixColX::~MatrixColX() { if (+(cw*StoreOnExit)) gm->RestoreCol(*this); }
+
+#ifdef use_namespace
+}
+#endif
+
+///@}
Index: /nanovis/tags/1.1.4/newmat11/newmat4.cpp
===================================================================
--- /nanovis/tags/1.1.4/newmat11/newmat4.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/newmat11/newmat4.cpp	(revision 4930)
@@ -0,0 +1,1387 @@
+/// \ingroup newmat
+///@{
+
+/// \file newmat4.cpp
+/// Constructors, resize, basic utilities, SimpleIntArray.
+
+
+// Copyright (C) 1991,2,3,4,8,9: R B Davies
+
+//#define WANT_STREAM
+
+#include "include.h"
+
+#include "newmat.h"
+#include "newmatrc.h"
+
+#ifdef use_namespace
+namespace NEWMAT {
+#endif
+
+
+
+#ifdef DO_REPORT
+#define REPORT { static ExeCounter ExeCount(__LINE__,4); ++ExeCount; }
+#else
+#define REPORT {}
+#endif
+
+
+#define DO_SEARCH                   // search for LHS of = in RHS
+
+// ************************* general utilities *************************/
+
+static int tristore(int n)                    // elements in triangular matrix
+{ return (n*(n+1))/2; }
+
+
+// **************************** constructors ***************************/
+
+GeneralMatrix::GeneralMatrix()
+{ store=0; storage=0; nrows_val=0; ncols_val=0; tag_val=-1; }
+
+GeneralMatrix::GeneralMatrix(ArrayLengthSpecifier s)
+{
+   REPORT
+   storage=s.Value(); tag_val=-1;
+   if (storage)
+   {
+      store = new Real [storage]; MatrixErrorNoSpace(store);
+      MONITOR_REAL_NEW("Make (GenMatrix)",storage,store)
+   }
+   else store = 0;
+}
+
+Matrix::Matrix(int m, int n) : GeneralMatrix(m*n)
+{ REPORT nrows_val=m; ncols_val=n; }
+
+SquareMatrix::SquareMatrix(ArrayLengthSpecifier n)
+   : Matrix(n.Value(),n.Value())
+{ REPORT }
+
+SymmetricMatrix::SymmetricMatrix(ArrayLengthSpecifier n)
+   : GeneralMatrix(tristore(n.Value()))
+{ REPORT nrows_val=n.Value(); ncols_val=n.Value(); }
+
+UpperTriangularMatrix::UpperTriangularMatrix(ArrayLengthSpecifier n)
+   : GeneralMatrix(tristore(n.Value()))
+{ REPORT nrows_val=n.Value(); ncols_val=n.Value(); }
+
+LowerTriangularMatrix::LowerTriangularMatrix(ArrayLengthSpecifier n)
+   : GeneralMatrix(tristore(n.Value()))
+{ REPORT nrows_val=n.Value(); ncols_val=n.Value(); }
+
+DiagonalMatrix::DiagonalMatrix(ArrayLengthSpecifier m) : GeneralMatrix(m)
+{ REPORT nrows_val=m.Value(); ncols_val=m.Value(); }
+
+Matrix::Matrix(const BaseMatrix& M)
+{
+   REPORT // CheckConversion(M);
+   // MatrixConversionCheck mcc;
+   GeneralMatrix* gmx=((BaseMatrix&)M).Evaluate(MatrixType::Rt);
+   GetMatrix(gmx);
+}
+
+SquareMatrix::SquareMatrix(const BaseMatrix& M) : Matrix(M)
+{
+   REPORT
+   if (ncols_val != nrows_val)
+   {
+      Tracer tr("SquareMatrix");
+      Throw(NotSquareException(*this));
+   }
+}
+
+
+SquareMatrix::SquareMatrix(const Matrix& gm)
+{
+   REPORT
+   if (gm.ncols_val != gm.nrows_val)
+   {
+      Tracer tr("SquareMatrix(Matrix)");
+      Throw(NotSquareException(gm));
+   }
+   GetMatrix(&gm);
+}
+
+
+RowVector::RowVector(const BaseMatrix& M) : Matrix(M)
+{
+   REPORT
+   if (nrows_val!=1)
+   {
+      Tracer tr("RowVector");
+      Throw(VectorException(*this));
+   }
+}
+
+ColumnVector::ColumnVector(const BaseMatrix& M) : Matrix(M)
+{
+   REPORT
+   if (ncols_val!=1)
+   {
+      Tracer tr("ColumnVector");
+      Throw(VectorException(*this));
+   }
+}
+
+SymmetricMatrix::SymmetricMatrix(const BaseMatrix& M)
+{
+   REPORT  // CheckConversion(M);
+   // MatrixConversionCheck mcc;
+   GeneralMatrix* gmx=((BaseMatrix&)M).Evaluate(MatrixType::Sm);
+   GetMatrix(gmx);
+}
+
+UpperTriangularMatrix::UpperTriangularMatrix(const BaseMatrix& M)
+{
+   REPORT // CheckConversion(M);
+   // MatrixConversionCheck mcc;
+   GeneralMatrix* gmx=((BaseMatrix&)M).Evaluate(MatrixType::UT);
+   GetMatrix(gmx);
+}
+
+LowerTriangularMatrix::LowerTriangularMatrix(const BaseMatrix& M)
+{
+   REPORT // CheckConversion(M);
+   // MatrixConversionCheck mcc;
+   GeneralMatrix* gmx=((BaseMatrix&)M).Evaluate(MatrixType::LT);
+   GetMatrix(gmx);
+}
+
+DiagonalMatrix::DiagonalMatrix(const BaseMatrix& M)
+{
+   REPORT //CheckConversion(M);
+   // MatrixConversionCheck mcc;
+   GeneralMatrix* gmx=((BaseMatrix&)M).Evaluate(MatrixType::Dg);
+   GetMatrix(gmx);
+}
+
+IdentityMatrix::IdentityMatrix(const BaseMatrix& M)
+{
+   REPORT //CheckConversion(M);
+   // MatrixConversionCheck mcc;
+   GeneralMatrix* gmx=((BaseMatrix&)M).Evaluate(MatrixType::Id);
+   GetMatrix(gmx);
+}
+
+GeneralMatrix::~GeneralMatrix()
+{
+   if (store)
+   {
+      MONITOR_REAL_DELETE("Free (GenMatrix)",storage,store)
+      delete [] store;
+   }
+}
+
+CroutMatrix::CroutMatrix(const BaseMatrix& m)
+{
+   REPORT
+   Tracer tr("CroutMatrix");
+   indx = 0;                     // in case of exception at next line
+   GeneralMatrix* gm = ((BaseMatrix&)m).Evaluate();
+   if (gm->nrows_val!=gm->ncols_val)
+      { gm->tDelete(); Throw(NotSquareException(*gm)); }
+   if (gm->type() == MatrixType::Ct)
+      { REPORT  ((CroutMatrix*)gm)->get_aux(*this); GetMatrix(gm); }
+   else
+   {
+      REPORT
+      GeneralMatrix* gm1 = gm->Evaluate(MatrixType::Rt);
+      GetMatrix(gm1);
+      d=true; sing=false;
+      indx=new int [nrows_val]; MatrixErrorNoSpace(indx);
+      MONITOR_INT_NEW("Index (CroutMat)",nrows_val,indx)
+      ludcmp();
+   }
+}
+
+// could we use SetParameters instead of this
+void CroutMatrix::get_aux(CroutMatrix& X)
+{
+   X.d = d; X.sing = sing;
+   if (tag_val == 0 || tag_val == 1) // reuse the array 
+      { REPORT  X.indx = indx; indx = 0; d = true; sing = true; return; }
+   else if (nrows_val == 0)
+      { REPORT indx = 0; d = true; sing = true; return; }
+   else                              // copy the array
+   { 
+      REPORT
+      Tracer tr("CroutMatrix::get_aux");
+      int *ix = new int [nrows_val]; MatrixErrorNoSpace(ix);
+      MONITOR_INT_NEW("Index (CM::get_aux)", nrows_val, ix)
+      int n = nrows_val; int* i = ix; int* j = indx;
+      while(n--) *i++ = *j++;
+      X.indx = ix;
+   }
+}
+
+CroutMatrix::CroutMatrix(const CroutMatrix& gm) : GeneralMatrix()
+{
+   REPORT
+   Tracer tr("CroutMatrix(const CroutMatrix&)");
+   ((CroutMatrix&)gm).get_aux(*this);
+   GetMatrix(&gm);
+}
+
+CroutMatrix::~CroutMatrix()
+{
+   MONITOR_INT_DELETE("Index (CroutMat)",nrows_val,indx)
+   delete [] indx;
+}
+
+//ReturnMatrix::ReturnMatrix(GeneralMatrix& gmx)
+//{
+//   REPORT
+//   gm = gmx.Image(); gm->ReleaseAndDelete();
+//}
+
+
+GeneralMatrix::operator ReturnMatrix() const
+{
+   REPORT
+   GeneralMatrix* gm = Image(); gm->ReleaseAndDelete();
+   return ReturnMatrix(gm);
+}
+
+
+
+ReturnMatrix GeneralMatrix::for_return() const
+{
+   REPORT
+   GeneralMatrix* gm = Image(); gm->ReleaseAndDelete();
+   return ReturnMatrix(gm);
+}
+
+// ************ Constructors for use with NR in C++ interface ***********
+
+#ifdef SETUP_C_SUBSCRIPTS
+
+Matrix::Matrix(Real a, int m, int n) : GeneralMatrix(m * n)
+   { REPORT nrows_val=m; ncols_val=n; operator=(a); }
+   
+Matrix::Matrix(const Real* a, int m, int n) : GeneralMatrix(m * n)
+   { REPORT nrows_val=m; ncols_val=n; *this << a; }
+
+#endif
+
+
+
+// ************************** resize matrices ***************************/
+
+void GeneralMatrix::resize(int nr, int nc, int s)
+{
+   REPORT
+   if (store)
+   {
+      MONITOR_REAL_DELETE("Free (ReDimensi)",storage,store)
+      delete [] store;
+   }
+   storage=s; nrows_val=nr; ncols_val=nc; tag_val=-1;
+   if (s)
+   {
+      store = new Real [storage]; MatrixErrorNoSpace(store);
+      MONITOR_REAL_NEW("Make (ReDimensi)",storage,store)
+   }
+   else store = 0;
+}
+
+void Matrix::resize(int nr, int nc)
+{ REPORT GeneralMatrix::resize(nr,nc,nr*nc); }
+
+void SquareMatrix::resize(int n)
+{ REPORT GeneralMatrix::resize(n,n,n*n); }
+
+void SquareMatrix::resize(int nr, int nc)
+{
+   REPORT
+   Tracer tr("SquareMatrix::resize");
+   if (nc != nr) Throw(NotSquareException(*this));
+   GeneralMatrix::resize(nr,nc,nr*nc);
+}
+
+void SymmetricMatrix::resize(int nr)
+{ REPORT GeneralMatrix::resize(nr,nr,tristore(nr)); }
+
+void UpperTriangularMatrix::resize(int nr)
+{ REPORT GeneralMatrix::resize(nr,nr,tristore(nr)); }
+
+void LowerTriangularMatrix::resize(int nr)
+{ REPORT GeneralMatrix::resize(nr,nr,tristore(nr)); }
+
+void DiagonalMatrix::resize(int nr)
+{ REPORT GeneralMatrix::resize(nr,nr,nr); }
+
+void RowVector::resize(int nc)
+{ REPORT GeneralMatrix::resize(1,nc,nc); }
+
+void ColumnVector::resize(int nr)
+{ REPORT GeneralMatrix::resize(nr,1,nr); }
+
+void RowVector::resize(int nr, int nc)
+{
+   Tracer tr("RowVector::resize");
+   if (nr != 1) Throw(VectorException(*this));
+   REPORT GeneralMatrix::resize(1,nc,nc);
+}
+
+void ColumnVector::resize(int nr, int nc)
+{
+   Tracer tr("ColumnVector::resize");
+   if (nc != 1) Throw(VectorException(*this));
+   REPORT GeneralMatrix::resize(nr,1,nr);
+}
+
+void IdentityMatrix::resize(int nr)
+{ REPORT GeneralMatrix::resize(nr,nr,1); *store = 1; }
+
+
+void Matrix::resize(const GeneralMatrix& A)
+{ REPORT  resize(A.Nrows(), A.Ncols()); }
+
+void SquareMatrix::resize(const GeneralMatrix& A)
+{
+   REPORT
+   int n = A.Nrows();
+   if (n != A.Ncols())
+   {
+      Tracer tr("SquareMatrix::resize(GM)");
+      Throw(NotSquareException(*this));
+   }
+   resize(n);
+}
+
+void nricMatrix::resize(const GeneralMatrix& A)
+{ REPORT  resize(A.Nrows(), A.Ncols()); }
+
+void ColumnVector::resize(const GeneralMatrix& A)
+{ REPORT  resize(A.Nrows(), A.Ncols()); }
+
+void RowVector::resize(const GeneralMatrix& A)
+{ REPORT  resize(A.Nrows(), A.Ncols()); }
+
+void SymmetricMatrix::resize(const GeneralMatrix& A)
+{
+   REPORT
+   int n = A.Nrows();
+   if (n != A.Ncols())
+   {
+      Tracer tr("SymmetricMatrix::resize(GM)");
+      Throw(NotSquareException(*this));
+   }
+   resize(n);
+}
+
+void DiagonalMatrix::resize(const GeneralMatrix& A)
+{
+   REPORT
+   int n = A.Nrows();
+   if (n != A.Ncols())
+   {
+      Tracer tr("DiagonalMatrix::resize(GM)");
+      Throw(NotSquareException(*this));
+   }
+   resize(n);
+}
+
+void UpperTriangularMatrix::resize(const GeneralMatrix& A)
+{
+   REPORT
+   int n = A.Nrows();
+   if (n != A.Ncols())
+   {
+      Tracer tr("UpperTriangularMatrix::resize(GM)");
+      Throw(NotSquareException(*this));
+   }
+   resize(n);
+}
+
+void LowerTriangularMatrix::resize(const GeneralMatrix& A)
+{
+   REPORT
+   int n = A.Nrows();
+   if (n != A.Ncols())
+   {
+      Tracer tr("LowerTriangularMatrix::resize(GM)");
+      Throw(NotSquareException(*this));
+   }
+   resize(n);
+}
+
+void IdentityMatrix::resize(const GeneralMatrix& A)
+{
+   REPORT
+   int n = A.Nrows();
+   if (n != A.Ncols())
+   {
+      Tracer tr("IdentityMatrix::resize(GM)");
+      Throw(NotSquareException(*this));
+   }
+   resize(n);
+}
+
+void GeneralMatrix::resize(const GeneralMatrix&)
+{
+   REPORT
+   Tracer tr("GeneralMatrix::resize(GM)");
+   Throw(NotDefinedException("resize", "this type of matrix"));
+}
+
+//*********************** resize_keep *******************************
+
+void Matrix::resize_keep(int nr, int nc)
+{
+   Tracer tr("Matrix::resize_keep");
+   if (nr == nrows_val && nc == ncols_val) { REPORT return; }
+   
+   if (nr <= nrows_val && nc <= ncols_val)
+   {
+      REPORT
+      Matrix X = submatrix(1,nr,1,nc);
+      swap(X);
+   }
+   else if (nr >= nrows_val && nc >= ncols_val)
+   {
+      REPORT
+      Matrix X(nr, nc); X = 0;
+      X.submatrix(1,nrows_val,1,ncols_val) = *this;
+      swap(X);
+   }
+   else
+   {
+      REPORT
+      Matrix X(nr, nc); X = 0;
+      if (nr > nrows_val) nr = nrows_val;
+      if (nc > ncols_val) nc = ncols_val;
+      X.submatrix(1,nr,1,nc) = submatrix(1,nr,1,nc);
+      swap(X);
+   }
+} 
+
+void SquareMatrix::resize_keep(int nr)
+{
+   Tracer tr("SquareMatrix::resize_keep");
+   if (nr < nrows_val)
+   {
+      REPORT
+      SquareMatrix X = sym_submatrix(1,nr);
+      swap(X);
+   }
+   else if (nr > nrows_val)
+   {
+      REPORT
+      SquareMatrix X(nr); X = 0;
+      X.sym_submatrix(1,nrows_val) = *this;
+      swap(X);
+   }
+}
+
+void SquareMatrix::resize_keep(int nr, int nc)
+{
+   Tracer tr("SquareMatrix::resize_keep 2");
+   REPORT
+   if (nr != nc) Throw(NotSquareException(*this));
+   resize_keep(nr);
+}
+ 
+
+void SymmetricMatrix::resize_keep(int nr)
+{
+   Tracer tr("SymmetricMatrix::resize_keep");
+   if (nr < nrows_val)
+   {
+      REPORT
+      SymmetricMatrix X = sym_submatrix(1,nr);
+      swap(X);
+   }
+   else if (nr > nrows_val)
+   {
+      REPORT
+      SymmetricMatrix X(nr); X = 0;
+      X.sym_submatrix(1,nrows_val) = *this;
+      swap(X);
+   }
+} 
+
+void UpperTriangularMatrix::resize_keep(int nr)
+{
+   Tracer tr("UpperTriangularMatrix::resize_keep");
+   if (nr < nrows_val)
+   {
+      REPORT
+      UpperTriangularMatrix X = sym_submatrix(1,nr);
+      swap(X);
+   }
+   else if (nr > nrows_val)
+   {
+      REPORT
+      UpperTriangularMatrix X(nr); X = 0;
+      X.sym_submatrix(1,nrows_val) = *this;
+      swap(X);
+   }
+} 
+
+void LowerTriangularMatrix::resize_keep(int nr)
+{
+   Tracer tr("LowerTriangularMatrix::resize_keep");
+   if (nr < nrows_val)
+   {
+      REPORT
+      LowerTriangularMatrix X = sym_submatrix(1,nr);
+      swap(X);
+   }
+   else if (nr > nrows_val)
+   {
+      REPORT
+      LowerTriangularMatrix X(nr); X = 0;
+      X.sym_submatrix(1,nrows_val) = *this;
+      swap(X);
+   }
+} 
+
+void DiagonalMatrix::resize_keep(int nr)
+{
+   Tracer tr("DiagonalMatrix::resize_keep");
+   if (nr < nrows_val)
+   {
+      REPORT
+      DiagonalMatrix X = sym_submatrix(1,nr);
+      swap(X);
+   }
+   else if (nr > nrows_val)
+   {
+      REPORT
+      DiagonalMatrix X(nr); X = 0;
+      X.sym_submatrix(1,nrows_val) = *this;
+      swap(X);
+   }
+} 
+
+void RowVector::resize_keep(int nc)
+{
+   Tracer tr("RowVector::resize_keep");
+   if (nc < ncols_val)
+   {
+      REPORT
+      RowVector X = columns(1,nc);
+      swap(X);
+   }
+   else if (nc > ncols_val)
+   {
+      REPORT
+      RowVector X(nc); X = 0;
+      X.columns(1,ncols_val) = *this;
+      swap(X);
+   }
+}
+
+void RowVector::resize_keep(int nr, int nc)
+{
+   Tracer tr("RowVector::resize_keep 2");
+   REPORT
+   if (nr != 1) Throw(VectorException(*this));
+   resize_keep(nc);
+}
+
+void ColumnVector::resize_keep(int nr)
+{
+   Tracer tr("ColumnVector::resize_keep");
+   if (nr < nrows_val)
+   {
+      REPORT
+      ColumnVector X = rows(1,nr);
+      swap(X);
+   }
+   else if (nr > nrows_val)
+   {
+      REPORT
+      ColumnVector X(nr); X = 0;
+      X.rows(1,nrows_val) = *this;
+      swap(X);
+   }
+} 
+
+void ColumnVector::resize_keep(int nr, int nc)
+{
+   Tracer tr("ColumnVector::resize_keep 2");
+   REPORT
+   if (nc != 1) Throw(VectorException(*this));
+   resize_keep(nr);
+}
+
+
+/*
+void GeneralMatrix::resizeForAdd(const GeneralMatrix& A, const GeneralMatrix&)
+{ REPORT resize(A); }
+
+void GeneralMatrix::resizeForSP(const GeneralMatrix& A, const GeneralMatrix&)
+{ REPORT resize(A); }
+
+
+// ************************* SameStorageType ******************************
+
+// SameStorageType checks A and B have same storage type including bandwidth
+// It does not check same dimensions since we assume this is already done
+
+bool GeneralMatrix::SameStorageType(const GeneralMatrix& A) const
+{
+   REPORT
+   return type() == A.type();
+}
+*/
+
+// ******************* manipulate types, storage **************************/
+
+int GeneralMatrix::search(const BaseMatrix* s) const
+{ REPORT return (s==this) ? 1 : 0; }
+
+int GenericMatrix::search(const BaseMatrix* s) const
+{ REPORT return gm->search(s); }
+
+int MultipliedMatrix::search(const BaseMatrix* s) const
+{ REPORT return bm1->search(s) + bm2->search(s); }
+
+int ShiftedMatrix::search(const BaseMatrix* s) const
+{ REPORT return bm->search(s); }
+
+int NegatedMatrix::search(const BaseMatrix* s) const
+{ REPORT return bm->search(s); }
+
+int ReturnMatrix::search(const BaseMatrix* s) const
+{ REPORT return (s==gm) ? 1 : 0; }
+
+MatrixType Matrix::type() const { return MatrixType::Rt; }
+MatrixType SquareMatrix::type() const { return MatrixType::Sq; }
+MatrixType SymmetricMatrix::type() const { return MatrixType::Sm; }
+MatrixType UpperTriangularMatrix::type() const { return MatrixType::UT; }
+MatrixType LowerTriangularMatrix::type() const { return MatrixType::LT; }
+MatrixType DiagonalMatrix::type() const { return MatrixType::Dg; }
+MatrixType RowVector::type() const { return MatrixType::RV; }
+MatrixType ColumnVector::type() const { return MatrixType::CV; }
+MatrixType CroutMatrix::type() const { return MatrixType::Ct; }
+MatrixType BandMatrix::type() const { return MatrixType::BM; }
+MatrixType UpperBandMatrix::type() const { return MatrixType::UB; }
+MatrixType LowerBandMatrix::type() const { return MatrixType::LB; }
+MatrixType SymmetricBandMatrix::type() const { return MatrixType::SB; }
+
+MatrixType IdentityMatrix::type() const { return MatrixType::Id; }
+
+
+
+MatrixBandWidth BaseMatrix::bandwidth() const { REPORT return -1; }
+MatrixBandWidth DiagonalMatrix::bandwidth() const { REPORT return 0; }
+MatrixBandWidth IdentityMatrix::bandwidth() const { REPORT return 0; }
+
+MatrixBandWidth UpperTriangularMatrix::bandwidth() const
+   { REPORT return MatrixBandWidth(0,-1); }
+
+MatrixBandWidth LowerTriangularMatrix::bandwidth() const
+   { REPORT return MatrixBandWidth(-1,0); }
+
+MatrixBandWidth BandMatrix::bandwidth() const
+   { REPORT return MatrixBandWidth(lower_val,upper_val); }
+
+MatrixBandWidth BandLUMatrix::bandwidth() const
+   { REPORT return MatrixBandWidth(m1,m2); }
+   
+MatrixBandWidth GenericMatrix::bandwidth()const
+   { REPORT return gm->bandwidth(); }
+
+MatrixBandWidth AddedMatrix::bandwidth() const
+   { REPORT return gm1->bandwidth() + gm2->bandwidth(); }
+
+MatrixBandWidth SPMatrix::bandwidth() const
+   { REPORT return gm1->bandwidth().minimum(gm2->bandwidth()); }
+
+MatrixBandWidth KPMatrix::bandwidth() const
+{
+   int lower, upper;
+   MatrixBandWidth bw1 = gm1->bandwidth(), bw2 = gm2->bandwidth();
+   if (bw1.Lower() < 0)
+   {
+      if (bw2.Lower() < 0) { REPORT lower = -1; }
+      else { REPORT lower = bw2.Lower() + (gm1->Nrows() - 1) * gm2->Nrows(); }
+   }
+   else
+   {
+      if (bw2.Lower() < 0)
+         { REPORT lower = (1 + bw1.Lower()) * gm2->Nrows() - 1; }
+      else { REPORT lower = bw2.Lower() + bw1.Lower() * gm2->Nrows(); }
+   }
+   if (bw1.Upper() < 0)
+   {
+      if (bw2.Upper() < 0) { REPORT upper = -1; }
+      else { REPORT upper = bw2.Upper() + (gm1->Nrows() - 1) * gm2->Nrows(); }
+   }
+   else
+   {
+      if (bw2.Upper() < 0)
+         { REPORT upper = (1 + bw1.Upper()) * gm2->Nrows() - 1; }
+      else { REPORT upper = bw2.Upper() + bw1.Upper() * gm2->Nrows(); }
+   }
+   return MatrixBandWidth(lower, upper);
+}
+
+MatrixBandWidth MultipliedMatrix::bandwidth() const
+{ REPORT return gm1->bandwidth() * gm2->bandwidth(); }
+
+MatrixBandWidth ConcatenatedMatrix::bandwidth() const { REPORT return -1; }
+
+MatrixBandWidth SolvedMatrix::bandwidth() const
+{
+   if (+gm1->type() & MatrixType::Diagonal)
+      { REPORT return gm2->bandwidth(); }
+   else { REPORT return -1; }
+}
+
+MatrixBandWidth ScaledMatrix::bandwidth() const
+   { REPORT return gm->bandwidth(); }
+
+MatrixBandWidth NegatedMatrix::bandwidth() const
+   { REPORT return gm->bandwidth(); }
+
+MatrixBandWidth TransposedMatrix::bandwidth() const
+   { REPORT return gm->bandwidth().t(); }
+
+MatrixBandWidth InvertedMatrix::bandwidth() const
+{
+   if (+gm->type() & MatrixType::Diagonal)
+      { REPORT return MatrixBandWidth(0,0); }
+   else { REPORT return -1; }
+}
+
+MatrixBandWidth RowedMatrix::bandwidth() const { REPORT return -1; }
+MatrixBandWidth ColedMatrix::bandwidth() const { REPORT return -1; }
+MatrixBandWidth DiagedMatrix::bandwidth() const { REPORT return 0; }
+MatrixBandWidth MatedMatrix::bandwidth() const { REPORT return -1; }
+MatrixBandWidth ReturnMatrix::bandwidth() const
+   { REPORT return gm->bandwidth(); }
+
+MatrixBandWidth GetSubMatrix::bandwidth() const
+{
+
+   if (row_skip==col_skip && row_number==col_number)
+      { REPORT return gm->bandwidth(); }
+   else { REPORT return MatrixBandWidth(-1); }
+}
+
+// ********************** the memory managment tools **********************/
+
+//  Rules regarding tDelete, reuse, GetStore, BorrowStore
+//    All matrices processed during expression evaluation must be subject
+//    to exactly one of reuse(), tDelete(), GetStore() or BorrowStore().
+//    If reuse returns true the matrix must be reused.
+//    GetMatrix(gm) always calls gm->GetStore()
+//    gm->Evaluate obeys rules
+//    bm->Evaluate obeys rules for matrices in bm structure
+
+//  Meaning of tag_val
+//    tag_val = -1          memory cannot be reused (default situation)
+//    tag_val = -2          memory has been borrowed from another matrix
+//                               (don't change values)
+//    tag_val = i > 0       delete or reuse memory after i operations
+//    tag_val = 0           like value 1 but matrix was created by new
+//                               so delete it
+
+void GeneralMatrix::tDelete()
+{
+   if (tag_val<0)
+   {
+      if (tag_val<-1) { REPORT store = 0; delete this; return; }  // borrowed
+      else { REPORT return; }   // not a temporary matrix - leave alone
+   }
+   if (tag_val==1)
+   {
+      if (store)
+      {
+         REPORT  MONITOR_REAL_DELETE("Free   (tDelete)",storage,store)
+         delete [] store;
+      }
+      MiniCleanUp(); return;                           // CleanUp
+   }
+   if (tag_val==0) { REPORT delete this; return; }
+
+   REPORT tag_val--; return;
+}
+
+void newmat_block_copy(int n, Real* from, Real* to)
+{
+   REPORT
+   int i = (n >> 3);
+   while (i--)
+   {
+      *to++ = *from++; *to++ = *from++; *to++ = *from++; *to++ = *from++;
+      *to++ = *from++; *to++ = *from++; *to++ = *from++; *to++ = *from++;
+   }
+   i = n & 7; while (i--) *to++ = *from++;
+}
+
+bool GeneralMatrix::reuse()
+{
+   if (tag_val < -1)                 // borrowed storage
+   {
+      if (storage)
+      {
+         REPORT
+         Real* s = new Real [storage]; MatrixErrorNoSpace(s);
+         MONITOR_REAL_NEW("Make     (reuse)",storage,s)
+         newmat_block_copy(storage, store, s); store = s;
+      }
+      else { REPORT MiniCleanUp(); }                // CleanUp
+      tag_val = 0; return true;
+   }
+   if (tag_val < 0 ) { REPORT return false; }
+   if (tag_val <= 1 )  { REPORT return true; }
+   REPORT tag_val--; return false;
+}
+
+Real* GeneralMatrix::GetStore()
+{
+   if (tag_val<0 || tag_val>1)
+   {
+      Real* s;
+      if (storage)
+      {
+         s = new Real [storage]; MatrixErrorNoSpace(s);
+         MONITOR_REAL_NEW("Make  (GetStore)",storage,s)
+         newmat_block_copy(storage, store, s);
+      }
+      else s = 0;
+      if (tag_val > 1) { REPORT tag_val--; }
+      else if (tag_val < -1) { REPORT store = 0; delete this; } // borrowed store
+      else { REPORT }
+      return s;
+   }
+   Real* s = store;                             // cleanup - done later
+   if (tag_val==0) { REPORT store = 0; delete this; }
+   else { REPORT  MiniCleanUp(); }
+   return s;
+}
+
+void GeneralMatrix::GetMatrix(const GeneralMatrix* gmx)
+{
+   REPORT  tag_val=-1; nrows_val=gmx->Nrows(); ncols_val=gmx->Ncols();
+   storage=gmx->storage; SetParameters(gmx);
+   store=((GeneralMatrix*)gmx)->GetStore();
+}
+
+GeneralMatrix* GeneralMatrix::BorrowStore(GeneralMatrix* gmx, MatrixType mt)
+// Copy storage of *this to storage of *gmx. Then convert to type mt.
+// If mt == 0 just let *gmx point to storage of *this if tag_val==-1.
+{
+   if (!mt)
+   {
+      if (tag_val == -1) { REPORT gmx->tag_val = -2; gmx->store = store; }
+      else { REPORT gmx->tag_val = 0; gmx->store = GetStore(); }
+   }
+   else if (Compare(gmx->type(),mt))
+   { REPORT  gmx->tag_val = 0; gmx->store = GetStore(); }
+   else
+   {
+      REPORT gmx->tag_val = -2; gmx->store = store;
+      gmx = gmx->Evaluate(mt); gmx->tag_val = 0; tDelete();
+   }
+
+   return gmx;
+}
+
+void GeneralMatrix::Eq(const BaseMatrix& X, MatrixType mt)
+// Count number of references to this in X.
+// If zero delete storage in this;
+// otherwise tag this to show when storage can be deleted
+// evaluate X and copy to this
+{
+#ifdef DO_SEARCH
+   int counter=X.search(this);
+   if (counter==0)
+   {
+      REPORT
+      if (store)
+      {
+         MONITOR_REAL_DELETE("Free (operator=)",storage,store)
+         REPORT delete [] store; storage = 0; store = 0;
+      }
+   }
+   else { REPORT Release(counter); }
+   GeneralMatrix* gmx = ((BaseMatrix&)X).Evaluate(mt);
+   if (gmx!=this) { REPORT GetMatrix(gmx); }
+   else { REPORT }
+   Protect();
+#else
+   GeneralMatrix* gmx = ((BaseMatrix&)X).Evaluate(mt);
+   if (gmx!=this)
+   {
+      REPORT
+      if (store)
+      {
+         MONITOR_REAL_DELETE("Free (operator=)",storage,store)
+         REPORT delete [] store; storage = 0; store = 0;
+      }
+      GetMatrix(gmx);
+   }
+   else { REPORT }
+   Protect();
+#endif
+}
+
+// version with no conversion
+void GeneralMatrix::Eq(const GeneralMatrix& X)
+{
+   GeneralMatrix* gmx = (GeneralMatrix*)&X;
+   if (gmx!=this)
+   {
+      REPORT
+      if (store)
+      {
+         MONITOR_REAL_DELETE("Free (operator=)",storage,store)
+         REPORT delete [] store; storage = 0; store = 0;
+      }
+      GetMatrix(gmx);
+   }
+   else { REPORT }
+   Protect();
+}
+
+// version to work with operator<<
+void GeneralMatrix::Eq(const BaseMatrix& X, MatrixType mt, bool ldok)
+{
+   REPORT
+   if (ldok) mt.SetDataLossOK();
+   Eq(X, mt);
+}
+
+void GeneralMatrix::Eq2(const BaseMatrix& X, MatrixType mt)
+// a cut down version of Eq for use with += etc.
+// we know BaseMatrix points to two GeneralMatrix objects,
+// the first being this (may be the same).
+// we know tag_val has been set correctly in each.
+{
+   GeneralMatrix* gmx = ((BaseMatrix&)X).Evaluate(mt);
+   if (gmx!=this) { REPORT GetMatrix(gmx); }  // simplify GetMatrix ?
+   else { REPORT }
+   Protect();
+}
+
+void GeneralMatrix::inject(const GeneralMatrix& X)
+// copy stored values of X; otherwise leave els of *this unchanged
+{
+   REPORT
+   Tracer tr("inject");
+   if (nrows_val != X.nrows_val || ncols_val != X.ncols_val)
+      Throw(IncompatibleDimensionsException());
+   MatrixRow mr((GeneralMatrix*)&X, LoadOnEntry);
+   MatrixRow mrx(this, LoadOnEntry+StoreOnExit+DirectPart);
+   int i=nrows_val;
+   while (i--) { mrx.Inject(mr); mrx.Next(); mr.Next(); }
+}
+
+// ************* checking for data loss during conversion *******************/
+
+bool Compare(const MatrixType& source, MatrixType& destination)
+{
+   if (!destination) { destination=source; return true; }
+   if (destination==source) return true;
+   if (!destination.DataLossOK && !(destination>=source))
+      Throw(ProgramException("Illegal Conversion", source, destination));
+   return false;
+}
+
+// ************* Make a copy of a matrix on the heap *********************/
+
+GeneralMatrix* Matrix::Image() const
+{
+   REPORT
+   GeneralMatrix* gm = new Matrix(*this); MatrixErrorNoSpace(gm);
+   return gm;
+}
+
+GeneralMatrix* SquareMatrix::Image() const
+{
+   REPORT
+   GeneralMatrix* gm = new SquareMatrix(*this); MatrixErrorNoSpace(gm);
+   return gm;
+}
+
+GeneralMatrix* SymmetricMatrix::Image() const
+{
+   REPORT
+   GeneralMatrix* gm = new SymmetricMatrix(*this); MatrixErrorNoSpace(gm);
+   return gm;
+}
+
+GeneralMatrix* UpperTriangularMatrix::Image() const
+{
+   REPORT
+   GeneralMatrix* gm = new UpperTriangularMatrix(*this);
+   MatrixErrorNoSpace(gm); return gm;
+}
+
+GeneralMatrix* LowerTriangularMatrix::Image() const
+{
+   REPORT
+   GeneralMatrix* gm = new LowerTriangularMatrix(*this);
+   MatrixErrorNoSpace(gm); return gm;
+}
+
+GeneralMatrix* DiagonalMatrix::Image() const
+{
+   REPORT
+   GeneralMatrix* gm = new DiagonalMatrix(*this); MatrixErrorNoSpace(gm);
+   return gm;
+}
+
+GeneralMatrix* RowVector::Image() const
+{
+   REPORT
+   GeneralMatrix* gm = new RowVector(*this); MatrixErrorNoSpace(gm);
+   return gm;
+}
+
+GeneralMatrix* ColumnVector::Image() const
+{
+   REPORT
+   GeneralMatrix* gm = new ColumnVector(*this); MatrixErrorNoSpace(gm);
+   return gm;
+}
+
+GeneralMatrix* nricMatrix::Image() const
+{
+   REPORT
+   GeneralMatrix* gm = new nricMatrix(*this); MatrixErrorNoSpace(gm);
+   return gm;
+}
+
+GeneralMatrix* IdentityMatrix::Image() const
+{
+   REPORT
+   GeneralMatrix* gm = new IdentityMatrix(*this); MatrixErrorNoSpace(gm);
+   return gm;
+}
+
+GeneralMatrix* CroutMatrix::Image() const
+{
+   REPORT
+   GeneralMatrix* gm = new CroutMatrix(*this); MatrixErrorNoSpace(gm);
+   return gm;
+}
+
+GeneralMatrix* GeneralMatrix::Image() const
+{
+   bool dummy = true;
+   if (dummy)                                   // get rid of warning message
+      Throw(InternalException("Cannot apply Image to this matrix type"));
+   return 0;
+}
+
+
+// *********************** nricMatrix routines *****************************/
+
+void nricMatrix::MakeRowPointer()
+{
+   REPORT
+   if (nrows_val > 0)
+   {
+      row_pointer = new Real* [nrows_val]; MatrixErrorNoSpace(row_pointer);
+      Real* s = Store() - 1; int i = nrows_val; Real** rp = row_pointer;
+      if (i) for (;;) { *rp++ = s; if (!(--i)) break; s+=ncols_val; }
+   }
+   else row_pointer = 0;
+}
+
+void nricMatrix::DeleteRowPointer()
+   { REPORT if (nrows_val) delete [] row_pointer; }
+
+void GeneralMatrix::CheckStore() const
+{
+   REPORT
+   if (!store)
+      Throw(ProgramException("NRIC accessing matrix with unset dimensions"));
+}
+
+
+// *************************** CleanUp routines *****************************/
+
+void GeneralMatrix::cleanup()
+{
+   // set matrix dimensions to zero, delete storage
+   REPORT
+   if (store && storage)
+   {
+      MONITOR_REAL_DELETE("Free (cleanup)    ",storage,store)
+      REPORT delete [] store;
+   }
+   store=0; storage=0; nrows_val=0; ncols_val=0; tag_val = -1;
+}
+
+void nricMatrix::cleanup()
+   { REPORT DeleteRowPointer(); GeneralMatrix::cleanup(); }
+
+void nricMatrix::MiniCleanUp()
+   { REPORT DeleteRowPointer(); GeneralMatrix::MiniCleanUp(); }
+
+void RowVector::cleanup()
+   { REPORT GeneralMatrix::cleanup(); nrows_val=1; }
+
+void ColumnVector::cleanup()
+   { REPORT GeneralMatrix::cleanup(); ncols_val=1; }
+
+void CroutMatrix::cleanup()
+{
+   REPORT
+   if (nrows_val) delete [] indx;
+   GeneralMatrix::cleanup();
+}
+
+void CroutMatrix::MiniCleanUp()
+{
+   REPORT
+   if (nrows_val) delete [] indx;
+   GeneralMatrix::MiniCleanUp();
+}
+
+void BandLUMatrix::cleanup()
+{
+   REPORT
+   if (nrows_val) delete [] indx;
+   if (storage2) delete [] store2;
+   GeneralMatrix::cleanup();
+}
+
+void BandLUMatrix::MiniCleanUp()
+{
+   REPORT
+   if (nrows_val) delete [] indx;
+   if (storage2) delete [] store2;
+   GeneralMatrix::MiniCleanUp();
+}
+
+// ************************ simple integer array class ***********************
+
+// construct a new array of length xn. Check that xn is non-negative and
+// that space is available
+
+SimpleIntArray::SimpleIntArray(int xn) : n(xn)
+{
+   if (n < 0) Throw(Logic_error("invalid array length"));
+   else if (n == 0) { REPORT  a = 0; }
+   else { REPORT  a = new int [n]; if (!a) Throw(Bad_alloc()); }
+}
+
+// destroy an array - return its space to memory
+
+SimpleIntArray::~SimpleIntArray() { REPORT  if (a) delete [] a; }
+
+// access an element of an array; return a "reference" so elements
+// can be modified.
+// check index is within range
+// in this array class the index runs from 0 to n-1
+
+int& SimpleIntArray::operator[](int i)
+{
+   REPORT
+   if (i < 0 || i >= n) Throw(Logic_error("array index out of range"));
+   return a[i];
+}
+
+// same thing again but for arrays declared constant so we can't
+// modify its elements
+
+int SimpleIntArray::operator[](int i) const
+{
+   REPORT
+   if (i < 0 || i >= n) Throw(Logic_error("array index out of range"));
+   return a[i];
+}
+
+// set all the elements equal to a given value
+
+void SimpleIntArray::operator=(int ai)
+   { REPORT  for (int i = 0; i < n; i++) a[i] = ai; }
+
+// set the elements equal to those of another array.
+// now allow length to be changed
+
+void SimpleIntArray::operator=(const SimpleIntArray& b)
+{
+   REPORT
+   if (b.n != n) resize(b.n);
+   for (int i = 0; i < n; i++) a[i] = b.a[i];
+}
+
+// construct a new array equal to an existing array
+// check that space is available
+
+SimpleIntArray::SimpleIntArray(const SimpleIntArray& b) : Janitor(), n(b.n)
+{
+   if (n == 0) { REPORT  a = 0; }
+   else
+   {
+      REPORT
+      a = new int [n]; if (!a) Throw(Bad_alloc());
+      for (int i = 0; i < n; i++) a[i] = b.a[i];
+   }
+}
+
+// change the size of an array; optionally copy data from old array to
+// new array
+
+void SimpleIntArray::resize(int n1, bool keep)
+{
+   if (n1 == n) { REPORT  return; }
+   else if (n1 == 0) { REPORT  n = 0; delete [] a; a = 0; }
+   else if (n == 0)
+   {
+      REPORT
+      a = new int [n1]; if (!a) Throw(Bad_alloc());
+      n = n1;
+      if (keep) operator=(0);
+   }
+   else
+   {
+      int* a1 = a;
+      if (keep)
+      {
+         REPORT
+         int i;
+         a = new int [n1]; if (!a) Throw(Bad_alloc());
+         if (n > n1) n = n1;
+         else for (i = n; i < n1; i++) a[i] = 0;
+         for (i = 0; i < n; i++) a[i] = a1[i];
+         n = n1; delete [] a1;
+      }
+      else
+      {
+         REPORT  n = n1; delete [] a1;
+         a = new int [n]; if (!a) Throw(Bad_alloc());
+      }
+   }
+}
+
+//************************** swap values ********************************
+
+// swap values
+
+void GeneralMatrix::swap(GeneralMatrix& gm)
+{
+   REPORT
+   int t;
+   t = tag_val; tag_val = gm.tag_val; gm.tag_val = t;
+   t = nrows_val; nrows_val = gm.nrows_val; gm.nrows_val = t;
+   t = ncols_val; ncols_val = gm.ncols_val; gm.ncols_val = t;
+   t = storage; storage = gm.storage; gm.storage = t;
+   Real* s = store; store = gm.store; gm.store = s;
+}
+   
+void nricMatrix::swap(nricMatrix& gm)
+{
+   REPORT
+   GeneralMatrix::swap((GeneralMatrix&)gm);
+   Real** rp = row_pointer; row_pointer = gm.row_pointer; gm.row_pointer = rp;
+}
+
+void CroutMatrix::swap(CroutMatrix& gm)
+{
+   REPORT
+   GeneralMatrix::swap((GeneralMatrix&)gm);
+   int* i = indx; indx = gm.indx; gm.indx = i;
+   bool b;
+   b = d; d = gm.d; gm.d = b;
+   b = sing; sing = gm.sing; gm.sing = b;
+}
+
+void BandMatrix::swap(BandMatrix& gm)
+{
+   REPORT
+   GeneralMatrix::swap((GeneralMatrix&)gm);
+   int i;
+   i = lower_val; lower_val = gm.lower_val; gm.lower_val = i;
+   i = upper_val; upper_val = gm.upper_val; gm.upper_val = i;
+}
+
+void SymmetricBandMatrix::swap(SymmetricBandMatrix& gm)
+{
+   REPORT
+   GeneralMatrix::swap((GeneralMatrix&)gm);
+   int i;
+   i = lower_val; lower_val = gm.lower_val; gm.lower_val = i;
+}
+
+void BandLUMatrix::swap(BandLUMatrix& gm)
+{
+   REPORT
+   GeneralMatrix::swap((GeneralMatrix&)gm);
+   int* i = indx; indx = gm.indx; gm.indx = i;
+   bool b;
+   b = d; d = gm.d; gm.d = b;
+   b = sing; sing = gm.sing; gm.sing = b;
+   int m;
+   m = storage2; storage2 = gm.storage2; gm.storage2 = m;
+   m = m1; m1 = gm.m1; gm.m1 = m;
+   m = m2; m2 = gm.m2; gm.m2 = m;
+   Real* s = store2; store2 = gm.store2; gm.store2 = s;
+}
+
+void GenericMatrix::swap(GenericMatrix& x)
+{
+   REPORT
+   GeneralMatrix* tgm = gm; gm = x.gm; x.gm = tgm;
+}
+
+// ********************** C subscript classes ****************************
+
+RealStarStar::RealStarStar(Matrix& A)
+{
+   REPORT
+   Tracer tr("RealStarStar");
+   int n = A.ncols();
+   int m = A.nrows();
+   a = new Real*[m];
+   MatrixErrorNoSpace(a);
+   Real* d = A.data();
+   for (int i = 0; i < m; ++i) a[i] = d + i * n;
+} 
+
+ConstRealStarStar::ConstRealStarStar(const Matrix& A)
+{
+   REPORT
+   Tracer tr("ConstRealStarStar");
+   int n = A.ncols();
+   int m = A.nrows();
+   a = new const Real*[m];
+   MatrixErrorNoSpace(a);
+   const Real* d = A.data();
+   for (int i = 0; i < m; ++i) a[i] = d + i * n;
+} 
+
+
+
+#ifdef use_namespace
+}
+#endif
+
+
+/// \fn GeneralMatrix::SimpleAddOK(const GeneralMatrix* gm)
+/// Can we add two matrices with simple vector add.
+/// SimpleAddOK shows when we can add two matrices by a simple vector add
+/// and when we can add one matrix into another
+///
+/// *gm must be the same type as *this
+/// - return 0 if simple add is OK
+/// - return 1 if we can add into *gm only
+/// - return 2 if we can add into *this only
+/// - return 3 if we can't add either way
+///
+/// Also applies to subtract;
+/// for SP this will still be valid if we swap 1 and 2
+///
+/// For types Matrix, DiagonalMatrix, UpperTriangularMatrix,
+/// LowerTriangularMatrix, SymmetricMatrix etc return 0.
+/// For band matrices we will need to check bandwidths.
+
+
+
+
+
+
+
+///@}
Index: /nanovis/tags/1.1.4/newmat11/newmat5.cpp
===================================================================
--- /nanovis/tags/1.1.4/newmat11/newmat5.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/newmat11/newmat5.cpp	(revision 4930)
@@ -0,0 +1,557 @@
+/// \ingroup newmat
+///@{
+
+/// \file newmat5.cpp
+/// Transpose, evaluate, operations with scalar, matrix input.
+
+// Copyright (C) 1991,2,3,4: R B Davies
+
+//#define WANT_STREAM
+
+#include "include.h"
+
+#include "newmat.h"
+#include "newmatrc.h"
+
+#ifdef use_namespace
+namespace NEWMAT {
+#endif
+
+
+#ifdef DO_REPORT
+#define REPORT { static ExeCounter ExeCount(__LINE__,5); ++ExeCount; }
+#else
+#define REPORT {}
+#endif
+
+
+/************************ carry out operations ******************************/
+
+
+GeneralMatrix* GeneralMatrix::Transpose(TransposedMatrix* tm, MatrixType mt)
+{
+   GeneralMatrix* gm1;
+
+   if (Compare(Type().t(),mt))
+   {
+      REPORT
+      gm1 = mt.New(ncols_val,nrows_val,tm);
+      for (int i=0; i<ncols_val; i++)
+      {
+         MatrixRow mr(gm1, StoreOnExit+DirectPart, i);
+         MatrixCol mc(this, mr.Data(), LoadOnEntry, i);
+      }
+   }
+   else
+   {
+      REPORT
+      gm1 = mt.New(ncols_val,nrows_val,tm);
+      MatrixRow mr(this, LoadOnEntry);
+      MatrixCol mc(gm1, StoreOnExit+DirectPart);
+      int i = nrows_val;
+      while (i--) { mc.Copy(mr); mr.Next(); mc.Next(); }
+   }
+   tDelete(); gm1->ReleaseAndDelete(); return gm1;
+}
+
+GeneralMatrix* SymmetricMatrix::Transpose(TransposedMatrix*, MatrixType mt)
+{ REPORT  return Evaluate(mt); }
+
+
+GeneralMatrix* DiagonalMatrix::Transpose(TransposedMatrix*, MatrixType mt)
+{ REPORT return Evaluate(mt); }
+
+GeneralMatrix* ColumnVector::Transpose(TransposedMatrix*, MatrixType mt)
+{
+   REPORT
+   GeneralMatrix* gmx = new RowVector; MatrixErrorNoSpace(gmx);
+   gmx->nrows_val = 1; gmx->ncols_val = gmx->storage = storage;
+   return BorrowStore(gmx,mt);
+}
+
+GeneralMatrix* RowVector::Transpose(TransposedMatrix*, MatrixType mt)
+{
+   REPORT
+   GeneralMatrix* gmx = new ColumnVector; MatrixErrorNoSpace(gmx);
+   gmx->ncols_val = 1; gmx->nrows_val = gmx->storage = storage;
+   return BorrowStore(gmx,mt);
+}
+
+GeneralMatrix* IdentityMatrix::Transpose(TransposedMatrix*, MatrixType mt)
+{ REPORT return Evaluate(mt); }
+
+GeneralMatrix* GeneralMatrix::Evaluate(MatrixType mt)
+{
+   if (Compare(this->Type(),mt)) { REPORT return this; }
+   REPORT
+   GeneralMatrix* gmx = mt.New(nrows_val,ncols_val,this);
+   MatrixRow mr(this, LoadOnEntry);
+   MatrixRow mrx(gmx, StoreOnExit+DirectPart);
+   int i=nrows_val;
+   while (i--) { mrx.Copy(mr); mrx.Next(); mr.Next(); }
+   tDelete(); gmx->ReleaseAndDelete(); return gmx;
+}
+
+GeneralMatrix* CroutMatrix::Evaluate(MatrixType mt)
+{
+   if (Compare(this->Type(),mt)) { REPORT return this; }
+   REPORT
+   Tracer et("CroutMatrix::Evaluate");
+   bool dummy = true;
+   if (dummy) Throw(ProgramException("Illegal use of CroutMatrix", *this));
+   return this;
+}
+
+GeneralMatrix* GenericMatrix::Evaluate(MatrixType mt)
+   { REPORT  return gm->Evaluate(mt); }
+
+GeneralMatrix* ShiftedMatrix::Evaluate(MatrixType mt)
+{
+   gm=((BaseMatrix*&)bm)->Evaluate();
+   int nr=gm->Nrows(); int nc=gm->Ncols();
+   Compare(gm->Type().AddEqualEl(),mt);
+   if (!(mt==gm->Type()))
+   {
+      REPORT
+      GeneralMatrix* gmx = mt.New(nr,nc,this);
+      MatrixRow mr(gm, LoadOnEntry);
+      MatrixRow mrx(gmx, StoreOnExit+DirectPart);
+      while (nr--) { mrx.Add(mr,f); mrx.Next(); mr.Next(); }
+      gmx->ReleaseAndDelete(); gm->tDelete();
+      return gmx;
+   }
+   else if (gm->reuse())
+   {
+      REPORT gm->Add(f);
+      return gm;
+   }
+   else
+   {
+      REPORT GeneralMatrix* gmy = gm->Type().New(nr,nc,this);
+      gmy->ReleaseAndDelete(); gmy->Add(gm,f);
+      return gmy;
+   }
+}
+
+GeneralMatrix* NegShiftedMatrix::Evaluate(MatrixType mt)
+{
+   gm=((BaseMatrix*&)bm)->Evaluate();
+   int nr=gm->Nrows(); int nc=gm->Ncols();
+   Compare(gm->Type().AddEqualEl(),mt);
+   if (!(mt==gm->Type()))
+   {
+      REPORT
+      GeneralMatrix* gmx = mt.New(nr,nc,this);
+      MatrixRow mr(gm, LoadOnEntry);
+      MatrixRow mrx(gmx, StoreOnExit+DirectPart);
+      while (nr--) { mrx.NegAdd(mr,f); mrx.Next(); mr.Next(); }
+      gmx->ReleaseAndDelete(); gm->tDelete();
+      return gmx;
+   }
+   else if (gm->reuse())
+   {
+      REPORT gm->NegAdd(f);
+      return gm;
+   }
+   else
+   {
+      REPORT GeneralMatrix* gmy = gm->Type().New(nr,nc,this);
+      gmy->ReleaseAndDelete(); gmy->NegAdd(gm,f);
+      return gmy;
+   }
+}
+
+GeneralMatrix* ScaledMatrix::Evaluate(MatrixType mt)
+{
+   gm=((BaseMatrix*&)bm)->Evaluate();
+   int nr=gm->Nrows(); int nc=gm->Ncols();
+   if (Compare(gm->Type(),mt))
+   {
+      if (gm->reuse())
+      {
+         REPORT gm->Multiply(f);
+         return gm;
+      }
+      else
+      {
+         REPORT GeneralMatrix* gmx = gm->Type().New(nr,nc,this);
+         gmx->ReleaseAndDelete(); gmx->Multiply(gm,f);
+         return gmx;
+      }
+   }
+   else
+   {
+      REPORT
+      GeneralMatrix* gmx = mt.New(nr,nc,this);
+      MatrixRow mr(gm, LoadOnEntry);
+      MatrixRow mrx(gmx, StoreOnExit+DirectPart);
+      while (nr--) { mrx.Multiply(mr,f); mrx.Next(); mr.Next(); }
+      gmx->ReleaseAndDelete(); gm->tDelete();
+      return gmx;
+   }
+}
+
+GeneralMatrix* NegatedMatrix::Evaluate(MatrixType mt)
+{
+   gm=((BaseMatrix*&)bm)->Evaluate();
+   int nr=gm->Nrows(); int nc=gm->Ncols();
+   if (Compare(gm->Type(),mt))
+   {
+      if (gm->reuse())
+      {
+         REPORT gm->Negate();
+         return gm;
+      }
+      else
+      {
+         REPORT
+         GeneralMatrix* gmx = gm->Type().New(nr,nc,this);
+         gmx->ReleaseAndDelete(); gmx->Negate(gm);
+         return gmx;
+      }
+   }
+   else
+   {
+      REPORT
+      GeneralMatrix* gmx = mt.New(nr,nc,this);
+      MatrixRow mr(gm, LoadOnEntry);
+      MatrixRow mrx(gmx, StoreOnExit+DirectPart);
+      while (nr--) { mrx.Negate(mr); mrx.Next(); mr.Next(); }
+      gmx->ReleaseAndDelete(); gm->tDelete();
+      return gmx;
+   }
+}
+
+GeneralMatrix* ReversedMatrix::Evaluate(MatrixType mt)
+{
+   gm=((BaseMatrix*&)bm)->Evaluate(); GeneralMatrix* gmx;
+
+   if ((gm->Type()).is_band() && ! (gm->Type()).is_diagonal())
+   {
+      gm->tDelete();
+      Throw(NotDefinedException("Reverse", "band matrices"));
+   }
+
+   if (gm->reuse()) { REPORT gm->ReverseElements(); gmx = gm; }
+   else
+   {
+      REPORT
+      gmx = gm->Type().New(gm->Nrows(), gm->Ncols(), this);
+      gmx->ReverseElements(gm); gmx->ReleaseAndDelete();
+   }
+   return gmx->Evaluate(mt); // target matrix is different type?
+
+}
+
+GeneralMatrix* TransposedMatrix::Evaluate(MatrixType mt)
+{
+   REPORT
+   gm=((BaseMatrix*&)bm)->Evaluate();
+   Compare(gm->Type().t(),mt);
+   GeneralMatrix* gmx=gm->Transpose(this, mt);
+   return gmx;
+}
+
+GeneralMatrix* RowedMatrix::Evaluate(MatrixType mt)
+{
+   gm = ((BaseMatrix*&)bm)->Evaluate();
+   GeneralMatrix* gmx = new RowVector; MatrixErrorNoSpace(gmx);
+   gmx->nrows_val = 1; gmx->ncols_val = gmx->storage = gm->storage;
+   return gm->BorrowStore(gmx,mt);
+}
+
+GeneralMatrix* ColedMatrix::Evaluate(MatrixType mt)
+{
+   gm = ((BaseMatrix*&)bm)->Evaluate();
+   GeneralMatrix* gmx = new ColumnVector; MatrixErrorNoSpace(gmx);
+   gmx->ncols_val = 1; gmx->nrows_val = gmx->storage = gm->storage;
+   return gm->BorrowStore(gmx,mt);
+}
+
+GeneralMatrix* DiagedMatrix::Evaluate(MatrixType mt)
+{
+   gm = ((BaseMatrix*&)bm)->Evaluate();
+   GeneralMatrix* gmx = new DiagonalMatrix; MatrixErrorNoSpace(gmx);
+   gmx->nrows_val = gmx->ncols_val = gmx->storage = gm->storage;
+   return gm->BorrowStore(gmx,mt);
+}
+
+GeneralMatrix* MatedMatrix::Evaluate(MatrixType mt)
+{
+   Tracer tr("MatedMatrix::Evaluate");
+   gm = ((BaseMatrix*&)bm)->Evaluate();
+   GeneralMatrix* gmx = new Matrix; MatrixErrorNoSpace(gmx);
+   gmx->nrows_val = nr; gmx->ncols_val = nc; gmx->storage = gm->storage;
+   if (nr*nc != gmx->storage)
+      Throw(IncompatibleDimensionsException());
+   return gm->BorrowStore(gmx,mt);
+}
+
+GeneralMatrix* GetSubMatrix::Evaluate(MatrixType mt)
+{
+   REPORT
+   Tracer tr("SubMatrix(evaluate)");
+   gm = ((BaseMatrix*&)bm)->Evaluate();
+   if (row_number < 0) row_number = gm->Nrows();
+   if (col_number < 0) col_number = gm->Ncols();
+   if (row_skip+row_number > gm->Nrows() || col_skip+col_number > gm->Ncols())
+   {
+      gm->tDelete();
+      Throw(SubMatrixDimensionException());
+   }
+   if (IsSym) Compare(gm->Type().ssub(), mt);
+   else Compare(gm->Type().sub(), mt);
+   GeneralMatrix* gmx = mt.New(row_number, col_number, this);
+   int i = row_number;
+   MatrixRow mr(gm, LoadOnEntry, row_skip); 
+   MatrixRow mrx(gmx, StoreOnExit+DirectPart);
+   MatrixRowCol sub;
+   while (i--)
+   {
+      mr.SubRowCol(sub, col_skip, col_number);   // put values in sub
+      mrx.Copy(sub); mrx.Next(); mr.Next();
+   }
+   gmx->ReleaseAndDelete(); gm->tDelete();
+   return gmx;
+}
+
+
+GeneralMatrix* ReturnMatrix::Evaluate(MatrixType mt)
+{
+   return gm->Evaluate(mt);
+}
+
+
+void GeneralMatrix::Add(GeneralMatrix* gm1, Real f)
+{
+   REPORT
+   Real* s1=gm1->store; Real* s=store; int i=(storage >> 2);
+   while (i--)
+   { *s++ = *s1++ + f; *s++ = *s1++ + f; *s++ = *s1++ + f; *s++ = *s1++ + f; }
+   i = storage & 3; while (i--) *s++ = *s1++ + f;
+}
+   
+void GeneralMatrix::Add(Real f)
+{
+   REPORT
+   Real* s=store; int i=(storage >> 2);
+   while (i--) { *s++ += f; *s++ += f; *s++ += f; *s++ += f; }
+   i = storage & 3; while (i--) *s++ += f;
+}
+   
+void GeneralMatrix::NegAdd(GeneralMatrix* gm1, Real f)
+{
+   REPORT
+   Real* s1=gm1->store; Real* s=store; int i=(storage >> 2);
+   while (i--)
+   { *s++ = f - *s1++; *s++ = f - *s1++; *s++ = f - *s1++; *s++ = f - *s1++; }
+   i = storage & 3; while (i--) *s++ = f - *s1++;
+}
+   
+void GeneralMatrix::NegAdd(Real f)
+{
+   REPORT
+   Real* s=store; int i=(storage >> 2);
+   while (i--)
+   {
+      *s = f - *s; s++; *s = f - *s; s++;
+      *s = f - *s; s++; *s = f - *s; s++;
+   }
+   i = storage & 3; while (i--)  { *s = f - *s; s++; }
+}
+   
+void GeneralMatrix::Negate(GeneralMatrix* gm1)
+{
+   // change sign of elements
+   REPORT
+   Real* s1=gm1->store; Real* s=store; int i=(storage >> 2);
+   while (i--)
+   { *s++ = -(*s1++); *s++ = -(*s1++); *s++ = -(*s1++); *s++ = -(*s1++); }
+   i = storage & 3; while(i--) *s++ = -(*s1++);
+}
+   
+void GeneralMatrix::Negate()
+{
+   REPORT
+   Real* s=store; int i=(storage >> 2);
+   while (i--)
+   { *s = -(*s); s++; *s = -(*s); s++; *s = -(*s); s++; *s = -(*s); s++; }
+   i = storage & 3; while(i--) { *s = -(*s); s++; }
+}
+   
+void GeneralMatrix::Multiply(GeneralMatrix* gm1, Real f)
+{
+   REPORT
+   Real* s1=gm1->store; Real* s=store;  int i=(storage >> 2);
+   while (i--)
+   { *s++ = *s1++ * f; *s++ = *s1++ * f; *s++ = *s1++ * f; *s++ = *s1++ * f; }
+   i = storage & 3; while (i--) *s++ = *s1++ * f;
+}
+   
+void GeneralMatrix::Multiply(Real f)
+{
+   REPORT
+   Real* s=store; int i=(storage >> 2);
+   while (i--) { *s++ *= f; *s++ *= f; *s++ *= f; *s++ *= f; }
+   i = storage & 3; while (i--) *s++ *= f;
+}
+   
+
+/************************ MatrixInput routines ****************************/
+
+// int MatrixInput::n;          // number values still to be read
+// Real* MatrixInput::r;        // pointer to next location to be read to
+
+MatrixInput MatrixInput::operator<<(double f)
+{
+   REPORT
+   Tracer et("MatrixInput");
+   if (n<=0) Throw(ProgramException("List of values too long"));
+   *r = (Real)f; int n1 = n-1; n=0;   // n=0 so we won't trigger exception
+   return MatrixInput(n1, r+1);
+}
+
+
+MatrixInput GeneralMatrix::operator<<(double f)
+{
+   REPORT
+   Tracer et("MatrixInput");
+   int n = Storage();
+   if (n<=0) Throw(ProgramException("Loading data to zero length matrix"));
+   Real* r; r = Store(); *r = (Real)f; n--;
+   return MatrixInput(n, r+1);
+}
+
+MatrixInput GetSubMatrix::operator<<(double f)
+{
+   REPORT
+   Tracer et("MatrixInput (GetSubMatrix)");
+   SetUpLHS();
+   if (row_number != 1 || col_skip != 0 || col_number != gm->Ncols())
+   {
+      Throw(ProgramException("MatrixInput requires complete rows"));
+   }
+   MatrixRow mr(gm, DirectPart, row_skip);  // to pick up location and length
+   int n = mr.Storage();
+   if (n<=0)
+   {
+      Throw(ProgramException("Loading data to zero length row"));
+   }
+   Real* r; r = mr.Data(); *r = (Real)f; n--;
+   if (+(mr.cw*HaveStore))
+   {
+      Throw(ProgramException("Fails with this matrix type"));
+   }
+   return MatrixInput(n, r+1);
+}
+
+MatrixInput MatrixInput::operator<<(float f)
+{
+   REPORT
+   Tracer et("MatrixInput");
+   if (n<=0) Throw(ProgramException("List of values too long"));
+   *r = (Real)f; int n1 = n-1; n=0;   // n=0 so we won't trigger exception
+   return MatrixInput(n1, r+1);
+}
+
+
+MatrixInput GeneralMatrix::operator<<(float f)
+{
+   REPORT
+   Tracer et("MatrixInput");
+   int n = Storage();
+   if (n<=0) Throw(ProgramException("Loading data to zero length matrix"));
+   Real* r; r = Store(); *r = (Real)f; n--;
+   return MatrixInput(n, r+1);
+}
+
+MatrixInput GetSubMatrix::operator<<(float f)
+{
+   REPORT
+   Tracer et("MatrixInput (GetSubMatrix)");
+   SetUpLHS();
+   if (row_number != 1 || col_skip != 0 || col_number != gm->Ncols())
+   {
+      Throw(ProgramException("MatrixInput requires complete rows"));
+   }
+   MatrixRow mr(gm, DirectPart, row_skip);  // to pick up location and length
+   int n = mr.Storage();
+   if (n<=0)
+   {
+      Throw(ProgramException("Loading data to zero length row"));
+   }
+   Real* r; r = mr.Data(); *r = (Real)f; n--;
+   if (+(mr.cw*HaveStore))
+   {
+      Throw(ProgramException("Fails with this matrix type"));
+   }
+   return MatrixInput(n, r+1);
+}
+MatrixInput::~MatrixInput()
+{
+   REPORT
+   Tracer et("MatrixInput");
+   if (n!=0) Throw(ProgramException("A list of values was too short"));
+}
+
+MatrixInput BandMatrix::operator<<(double)
+{
+   Tracer et("MatrixInput");
+   bool dummy = true;
+   if (dummy)                                   // get rid of warning message
+      Throw(ProgramException("Cannot use list read with a BandMatrix"));
+   return MatrixInput(0, 0);
+}
+
+MatrixInput BandMatrix::operator<<(float)
+{
+   Tracer et("MatrixInput");
+   bool dummy = true;
+   if (dummy)                                   // get rid of warning message
+      Throw(ProgramException("Cannot use list read with a BandMatrix"));
+   return MatrixInput(0, 0);
+}
+
+void BandMatrix::operator<<(const double*)
+{ Throw(ProgramException("Cannot use array read with a BandMatrix")); }
+
+void BandMatrix::operator<<(const float*)
+{ Throw(ProgramException("Cannot use array read with a BandMatrix")); }
+
+void BandMatrix::operator<<(const int*)
+{ Throw(ProgramException("Cannot use array read with a BandMatrix")); }
+
+void SymmetricBandMatrix::operator<<(const double*)
+{ Throw(ProgramException("Cannot use array read with a BandMatrix")); }
+
+void SymmetricBandMatrix::operator<<(const float*)
+{ Throw(ProgramException("Cannot use array read with a BandMatrix")); }
+
+void SymmetricBandMatrix::operator<<(const int*)
+{ Throw(ProgramException("Cannot use array read with a BandMatrix")); }
+
+// ************************* Reverse order of elements ***********************
+
+void GeneralMatrix::ReverseElements(GeneralMatrix* gm)
+{
+   // reversing into a new matrix
+   REPORT
+   int n = Storage(); Real* rx = Store() + n; Real* x = gm->Store();
+   while (n--) *(--rx) = *(x++);
+}
+
+void GeneralMatrix::ReverseElements()
+{
+   // reversing in place
+   REPORT
+   int n = Storage(); Real* x = Store(); Real* rx = x + n;
+   n /= 2;
+   while (n--) { Real t = *(--rx); *rx = *x; *(x++) = t; }
+}
+
+
+#ifdef use_namespace
+}
+#endif
+
+///@}
Index: /nanovis/tags/1.1.4/newmat11/newmat6.cpp
===================================================================
--- /nanovis/tags/1.1.4/newmat11/newmat6.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/newmat11/newmat6.cpp	(revision 4930)
@@ -0,0 +1,909 @@
+/// \ingroup newmat
+///@{
+
+/// \file newmat6.cpp
+/// Operators, element access.
+
+// Copyright (C) 1991,2,3,4: R B Davies
+
+#include "include.h"
+
+#include "newmat.h"
+#include "newmatrc.h"
+
+#ifdef use_namespace
+namespace NEWMAT {
+#endif
+
+
+
+#ifdef DO_REPORT
+#define REPORT { static ExeCounter ExeCount(__LINE__,6); ++ExeCount; }
+#else
+#define REPORT {}
+#endif
+
+/*************************** general utilities *************************/
+
+static int tristore(int n)                      // els in triangular matrix
+{ return (n*(n+1))/2; }
+
+
+/****************************** operators *******************************/
+
+Real& Matrix::operator()(int m, int n)
+{
+   REPORT
+   if (m<=0 || m>nrows_val || n<=0 || n>ncols_val)
+      Throw(IndexException(m,n,*this));
+   return store[(m-1)*ncols_val+n-1];
+}
+
+Real& SymmetricMatrix::operator()(int m, int n)
+{
+   REPORT
+   if (m<=0 || n<=0 || m>nrows_val || n>ncols_val)
+      Throw(IndexException(m,n,*this));
+   if (m>=n) return store[tristore(m-1)+n-1];
+   else return store[tristore(n-1)+m-1];
+}
+
+Real& UpperTriangularMatrix::operator()(int m, int n)
+{
+   REPORT
+   if (m<=0 || n<m || n>ncols_val)
+      Throw(IndexException(m,n,*this));
+   return store[(m-1)*ncols_val+n-1-tristore(m-1)];
+}
+
+Real& LowerTriangularMatrix::operator()(int m, int n)
+{
+   REPORT
+   if (n<=0 || m<n || m>nrows_val)
+      Throw(IndexException(m,n,*this));
+   return store[tristore(m-1)+n-1];
+}
+
+Real& DiagonalMatrix::operator()(int m, int n)
+{
+   REPORT
+   if (n<=0 || m!=n || m>nrows_val || n>ncols_val)
+      Throw(IndexException(m,n,*this));
+   return store[n-1];
+}
+
+Real& DiagonalMatrix::operator()(int m)
+{
+   REPORT
+   if (m<=0 || m>nrows_val) Throw(IndexException(m,*this));
+   return store[m-1];
+}
+
+Real& ColumnVector::operator()(int m)
+{
+   REPORT
+   if (m<=0 || m> nrows_val) Throw(IndexException(m,*this));
+   return store[m-1];
+}
+
+Real& RowVector::operator()(int n)
+{
+   REPORT
+   if (n<=0 || n> ncols_val) Throw(IndexException(n,*this));
+   return store[n-1];
+}
+
+Real& BandMatrix::operator()(int m, int n)
+{
+   REPORT
+   int w = upper_val+lower_val+1; int i = lower_val+n-m;
+   if (m<=0 || m>nrows_val || n<=0 || n>ncols_val || i<0 || i>=w)
+      Throw(IndexException(m,n,*this));
+   return store[w*(m-1)+i];
+}
+
+Real& UpperBandMatrix::operator()(int m, int n)
+{
+   REPORT
+   int w = upper_val+1; int i = n-m;
+   if (m<=0 || m>nrows_val || n<=0 || n>ncols_val || i<0 || i>=w)
+      Throw(IndexException(m,n,*this));
+   return store[w*(m-1)+i];
+}
+
+Real& LowerBandMatrix::operator()(int m, int n)
+{
+   REPORT
+   int w = lower_val+1; int i = lower_val+n-m;
+   if (m<=0 || m>nrows_val || n<=0 || n>ncols_val || i<0 || i>=w)
+      Throw(IndexException(m,n,*this));
+   return store[w*(m-1)+i];
+}
+
+Real& SymmetricBandMatrix::operator()(int m, int n)
+{
+   REPORT
+   int w = lower_val+1;
+   if (m>=n)
+   {
+      REPORT
+      int i = lower_val+n-m;
+      if ( m>nrows_val || n<=0 || i<0 )
+         Throw(IndexException(m,n,*this));
+      return store[w*(m-1)+i];
+   }
+   else
+   {
+      REPORT
+      int i = lower_val+m-n;
+      if ( n>nrows_val || m<=0 || i<0 )
+         Throw(IndexException(m,n,*this));
+      return store[w*(n-1)+i];
+   }
+}
+
+
+Real Matrix::operator()(int m, int n) const
+{
+   REPORT
+   if (m<=0 || m>nrows_val || n<=0 || n>ncols_val)
+      Throw(IndexException(m,n,*this));
+   return store[(m-1)*ncols_val+n-1];
+}
+
+Real SymmetricMatrix::operator()(int m, int n) const
+{
+   REPORT
+   if (m<=0 || n<=0 || m>nrows_val || n>ncols_val)
+      Throw(IndexException(m,n,*this));
+   if (m>=n) return store[tristore(m-1)+n-1];
+   else return store[tristore(n-1)+m-1];
+}
+
+Real UpperTriangularMatrix::operator()(int m, int n) const
+{
+   REPORT
+   if (m<=0 || n<m || n>ncols_val)
+      Throw(IndexException(m,n,*this));
+   return store[(m-1)*ncols_val+n-1-tristore(m-1)];
+}
+
+Real LowerTriangularMatrix::operator()(int m, int n) const
+{
+   REPORT
+   if (n<=0 || m<n || m>nrows_val)
+      Throw(IndexException(m,n,*this));
+   return store[tristore(m-1)+n-1];
+}
+
+Real DiagonalMatrix::operator()(int m, int n) const
+{
+   REPORT
+   if (n<=0 || m!=n || m>nrows_val || n>ncols_val)
+      Throw(IndexException(m,n,*this));
+   return store[n-1];
+}
+
+Real DiagonalMatrix::operator()(int m) const
+{
+   REPORT
+   if (m<=0 || m>nrows_val) Throw(IndexException(m,*this));
+   return store[m-1];
+}
+
+Real ColumnVector::operator()(int m) const
+{
+   REPORT
+   if (m<=0 || m> nrows_val) Throw(IndexException(m,*this));
+   return store[m-1];
+}
+
+Real RowVector::operator()(int n) const
+{
+   REPORT
+   if (n<=0 || n> ncols_val) Throw(IndexException(n,*this));
+   return store[n-1];
+}
+
+Real BandMatrix::operator()(int m, int n) const
+{
+   REPORT
+   int w = upper_val+lower_val+1; int i = lower_val+n-m;
+   if (m<=0 || m>nrows_val || n<=0 || n>ncols_val || i<0 || i>=w)
+      Throw(IndexException(m,n,*this));
+   return store[w*(m-1)+i];
+}
+
+Real UpperBandMatrix::operator()(int m, int n) const
+{
+   REPORT
+   int w = upper_val+1; int i = n-m;
+   if (m<=0 || m>nrows_val || n<=0 || n>ncols_val || i<0 || i>=w)
+      Throw(IndexException(m,n,*this));
+   return store[w*(m-1)+i];
+}
+
+Real LowerBandMatrix::operator()(int m, int n) const
+{
+   REPORT
+   int w = lower_val+1; int i = lower_val+n-m;
+   if (m<=0 || m>nrows_val || n<=0 || n>ncols_val || i<0 || i>=w)
+      Throw(IndexException(m,n,*this));
+   return store[w*(m-1)+i];
+}
+
+Real SymmetricBandMatrix::operator()(int m, int n) const
+{
+   REPORT
+   int w = lower_val+1;
+   if (m>=n)
+   {
+      REPORT
+      int i = lower_val+n-m;
+      if ( m>nrows_val || n<=0 || i<0 )
+         Throw(IndexException(m,n,*this));
+      return store[w*(m-1)+i];
+   }
+   else
+   {
+      REPORT
+      int i = lower_val+m-n;
+      if ( n>nrows_val || m<=0 || i<0 )
+         Throw(IndexException(m,n,*this));
+      return store[w*(n-1)+i];
+   }
+}
+
+
+Real BaseMatrix::as_scalar() const
+{
+   REPORT
+   GeneralMatrix* gm = ((BaseMatrix&)*this).Evaluate();
+
+   if (gm->nrows_val!=1 || gm->ncols_val!=1)
+   {
+      Tracer tr("as_scalar");
+      Try
+         { Throw(ProgramException("Cannot convert to scalar", *gm)); }
+      CatchAll { gm->tDelete(); ReThrow; }
+   }
+
+   Real x = *(gm->store); gm->tDelete(); return x;
+}
+
+
+AddedMatrix BaseMatrix::operator+(const BaseMatrix& bm) const
+{ REPORT return AddedMatrix(this, &bm); }
+
+SPMatrix SP(const BaseMatrix& bm1,const BaseMatrix& bm2)
+{ REPORT return SPMatrix(&bm1, &bm2); }
+
+KPMatrix KP(const BaseMatrix& bm1,const BaseMatrix& bm2)
+{ REPORT return KPMatrix(&bm1, &bm2); }
+
+MultipliedMatrix BaseMatrix::operator*(const BaseMatrix& bm) const
+{ REPORT return MultipliedMatrix(this, &bm); }
+
+ConcatenatedMatrix BaseMatrix::operator|(const BaseMatrix& bm) const
+{ REPORT return ConcatenatedMatrix(this, &bm); }
+
+StackedMatrix BaseMatrix::operator&(const BaseMatrix& bm) const
+{ REPORT return StackedMatrix(this, &bm); }
+
+SolvedMatrix InvertedMatrix::operator*(const BaseMatrix& bmx) const
+{ REPORT return SolvedMatrix(bm, &bmx); }
+
+SubtractedMatrix BaseMatrix::operator-(const BaseMatrix& bm) const
+{ REPORT return SubtractedMatrix(this, &bm); }
+
+ShiftedMatrix BaseMatrix::operator+(Real f) const
+{ REPORT return ShiftedMatrix(this, f); }
+
+ShiftedMatrix operator+(Real f, const BaseMatrix& BM)
+{ REPORT return ShiftedMatrix(&BM, f); }
+
+NegShiftedMatrix operator-(Real f, const BaseMatrix& bm)
+{ REPORT return NegShiftedMatrix(f, &bm); }
+
+ScaledMatrix BaseMatrix::operator*(Real f) const
+{ REPORT return ScaledMatrix(this, f); }
+
+ScaledMatrix BaseMatrix::operator/(Real f) const
+{ REPORT return ScaledMatrix(this, 1.0/f); }
+
+ScaledMatrix operator*(Real f, const BaseMatrix& BM)
+{ REPORT return ScaledMatrix(&BM, f); }
+
+ShiftedMatrix BaseMatrix::operator-(Real f) const
+{ REPORT return ShiftedMatrix(this, -f); }
+
+TransposedMatrix BaseMatrix::t() const
+{ REPORT return TransposedMatrix(this); }
+
+NegatedMatrix BaseMatrix::operator-() const
+{ REPORT return NegatedMatrix(this); }
+
+ReversedMatrix BaseMatrix::reverse() const
+{ REPORT return ReversedMatrix(this); }
+
+InvertedMatrix BaseMatrix::i() const
+{ REPORT return InvertedMatrix(this); }
+
+
+RowedMatrix BaseMatrix::as_row() const
+{ REPORT return RowedMatrix(this); }
+
+ColedMatrix BaseMatrix::as_column() const
+{ REPORT return ColedMatrix(this); }
+
+DiagedMatrix BaseMatrix::as_diagonal() const
+{ REPORT return DiagedMatrix(this); }
+
+MatedMatrix BaseMatrix::as_matrix(int nrx, int ncx) const
+{ REPORT return MatedMatrix(this,nrx,ncx); }
+
+
+void GeneralMatrix::operator=(Real f)
+{ REPORT int i=storage; Real* s=store; while (i--) { *s++ = f; } }
+
+void Matrix::operator=(const BaseMatrix& X)
+{
+   REPORT //CheckConversion(X);
+   // MatrixConversionCheck mcc;
+   Eq(X,MatrixType::Rt);
+} 
+
+void SquareMatrix::operator=(const BaseMatrix& X)
+{
+   REPORT //CheckConversion(X);
+   // MatrixConversionCheck mcc;
+   Eq(X,MatrixType::Rt);
+   if (nrows_val != ncols_val)
+      { Tracer tr("SquareMatrix(=)"); Throw(NotSquareException(*this)); }
+}
+
+void SquareMatrix::operator=(const Matrix& m)
+{
+   REPORT
+   if (m.nrows_val != m.ncols_val)
+      { Tracer tr("SquareMatrix(=Matrix)"); Throw(NotSquareException(*this)); }
+   Eq(m);
+}
+
+void RowVector::operator=(const BaseMatrix& X)
+{
+   REPORT  // CheckConversion(X);
+   // MatrixConversionCheck mcc;
+   Eq(X,MatrixType::RV);
+   if (nrows_val!=1)
+      { Tracer tr("RowVector(=)"); Throw(VectorException(*this)); }
+}
+
+void ColumnVector::operator=(const BaseMatrix& X)
+{
+   REPORT //CheckConversion(X);
+   // MatrixConversionCheck mcc;
+   Eq(X,MatrixType::CV);
+   if (ncols_val!=1)
+      { Tracer tr("ColumnVector(=)"); Throw(VectorException(*this)); }
+}
+
+void SymmetricMatrix::operator=(const BaseMatrix& X)
+{
+   REPORT // CheckConversion(X);
+   // MatrixConversionCheck mcc;
+   Eq(X,MatrixType::Sm);
+}
+
+void UpperTriangularMatrix::operator=(const BaseMatrix& X)
+{
+   REPORT //CheckConversion(X);
+   // MatrixConversionCheck mcc;
+   Eq(X,MatrixType::UT);
+}
+
+void LowerTriangularMatrix::operator=(const BaseMatrix& X)
+{
+   REPORT //CheckConversion(X);
+   // MatrixConversionCheck mcc;
+   Eq(X,MatrixType::LT);
+}
+
+void DiagonalMatrix::operator=(const BaseMatrix& X)
+{
+   REPORT // CheckConversion(X);
+   // MatrixConversionCheck mcc;
+   Eq(X,MatrixType::Dg);
+}
+
+void IdentityMatrix::operator=(const BaseMatrix& X)
+{
+   REPORT // CheckConversion(X);
+   // MatrixConversionCheck mcc;
+   Eq(X,MatrixType::Id);
+}
+
+
+void CroutMatrix::operator=(const CroutMatrix& gm)
+{
+   if (&gm == this) { REPORT tag_val = -1; return; }
+   REPORT
+   if (indx > 0) { delete [] indx; indx = 0; }
+   ((CroutMatrix&)gm).get_aux(*this);
+   Eq(gm);
+}
+   
+
+
+
+
+void GeneralMatrix::operator<<(const double* r)
+{
+   REPORT
+   int i = storage; Real* s=store;
+   while(i--) *s++ = (Real)*r++;
+}
+
+
+void GeneralMatrix::operator<<(const float* r)
+{
+   REPORT
+   int i = storage; Real* s=store;
+   while(i--) *s++ = (Real)*r++;
+}
+
+
+void GeneralMatrix::operator<<(const int* r)
+{
+   REPORT
+   int i = storage; Real* s=store;
+   while(i--) *s++ = (Real)*r++;
+}
+
+
+void GenericMatrix::operator=(const GenericMatrix& bmx)
+{
+   if (&bmx != this) { REPORT if (gm) delete gm; gm = bmx.gm->Image();}
+   else { REPORT }
+   gm->Protect();
+}
+
+void GenericMatrix::operator=(const BaseMatrix& bmx)
+{
+   if (gm)
+   {
+      int counter=bmx.search(gm);
+      if (counter==0) { REPORT delete gm; gm=0; }
+      else { REPORT gm->Release(counter); }
+   }
+   else { REPORT }
+   GeneralMatrix* gmx = ((BaseMatrix&)bmx).Evaluate();
+   if (gmx != gm) { REPORT if (gm) delete gm; gm = gmx->Image(); }
+   else { REPORT }
+   gm->Protect();
+}
+
+
+/*************************** += etc ***************************************/
+
+
+// GeneralMatrix operators
+
+void GeneralMatrix::operator+=(const BaseMatrix& X)
+{
+   REPORT
+   Tracer tr("GeneralMatrix::operator+=");
+   // MatrixConversionCheck mcc;
+   Protect();                                   // so it cannot get deleted
+						// during Evaluate
+   GeneralMatrix* gm = ((BaseMatrix&)X).Evaluate();
+   AddedMatrix am(this,gm);
+   if (gm==this) Release(2); else Release();
+   Eq2(am,type());
+}
+
+void GeneralMatrix::operator-=(const BaseMatrix& X)
+{
+   REPORT
+   Tracer tr("GeneralMatrix::operator-=");
+   // MatrixConversionCheck mcc;
+   Protect();                                   // so it cannot get deleted
+						// during Evaluate
+   GeneralMatrix* gm = ((BaseMatrix&)X).Evaluate();
+   SubtractedMatrix am(this,gm);
+   if (gm==this) Release(2); else Release();
+   Eq2(am,type());
+}
+
+void GeneralMatrix::operator*=(const BaseMatrix& X)
+{
+   REPORT
+   Tracer tr("GeneralMatrix::operator*=");
+   // MatrixConversionCheck mcc;
+   Protect();                                   // so it cannot get deleted
+						// during Evaluate
+   GeneralMatrix* gm = ((BaseMatrix&)X).Evaluate();
+   MultipliedMatrix am(this,gm);
+   if (gm==this) Release(2); else Release();
+   Eq2(am,type());
+}
+
+void GeneralMatrix::operator|=(const BaseMatrix& X)
+{
+   REPORT
+   Tracer tr("GeneralMatrix::operator|=");
+   // MatrixConversionCheck mcc;
+   Protect();                                   // so it cannot get deleted
+						// during Evaluate
+   GeneralMatrix* gm = ((BaseMatrix&)X).Evaluate();
+   ConcatenatedMatrix am(this,gm);
+   if (gm==this) Release(2); else Release();
+   Eq2(am,type());
+}
+
+void GeneralMatrix::operator&=(const BaseMatrix& X)
+{
+   REPORT
+   Tracer tr("GeneralMatrix::operator&=");
+   // MatrixConversionCheck mcc;
+   Protect();                                   // so it cannot get deleted
+						// during Evaluate
+   GeneralMatrix* gm = ((BaseMatrix&)X).Evaluate();
+   StackedMatrix am(this,gm);
+   if (gm==this) Release(2); else Release();
+   Eq2(am,type());
+}
+
+void GeneralMatrix::operator+=(Real r)
+{
+   REPORT
+   Tracer tr("GeneralMatrix::operator+=(Real)");
+   // MatrixConversionCheck mcc;
+   ShiftedMatrix am(this,r);
+   Release(); Eq2(am,type());
+}
+
+void GeneralMatrix::operator*=(Real r)
+{
+   REPORT
+   Tracer tr("GeneralMatrix::operator*=(Real)");
+   // MatrixConversionCheck mcc;
+   ScaledMatrix am(this,r);
+   Release(); Eq2(am,type());
+}
+
+
+// Generic matrix operators
+
+void GenericMatrix::operator+=(const BaseMatrix& X)
+{
+   REPORT
+   Tracer tr("GenericMatrix::operator+=");
+   if (!gm) Throw(ProgramException("GenericMatrix is null"));
+   gm->Protect();            // so it cannot get deleted during Evaluate
+   GeneralMatrix* gmx = ((BaseMatrix&)X).Evaluate();
+   AddedMatrix am(gm,gmx);
+   if (gmx==gm) gm->Release(2); else gm->Release();
+   GeneralMatrix* gmy = am.Evaluate();
+   if (gmy != gm) { REPORT delete gm; gm = gmy->Image(); }
+   else { REPORT }
+   gm->Protect();
+}
+
+void GenericMatrix::operator-=(const BaseMatrix& X)
+{
+   REPORT
+   Tracer tr("GenericMatrix::operator-=");
+   if (!gm) Throw(ProgramException("GenericMatrix is null"));
+   gm->Protect();            // so it cannot get deleted during Evaluate
+   GeneralMatrix* gmx = ((BaseMatrix&)X).Evaluate();
+   SubtractedMatrix am(gm,gmx);
+   if (gmx==gm) gm->Release(2); else gm->Release();
+   GeneralMatrix* gmy = am.Evaluate();
+   if (gmy != gm) { REPORT delete gm; gm = gmy->Image(); }
+   else { REPORT }
+   gm->Protect();
+}
+
+void GenericMatrix::operator*=(const BaseMatrix& X)
+{
+   REPORT
+   Tracer tr("GenericMatrix::operator*=");
+   if (!gm) Throw(ProgramException("GenericMatrix is null"));
+   gm->Protect();            // so it cannot get deleted during Evaluate
+   GeneralMatrix* gmx = ((BaseMatrix&)X).Evaluate();
+   MultipliedMatrix am(gm,gmx);
+   if (gmx==gm) gm->Release(2); else gm->Release();
+   GeneralMatrix* gmy = am.Evaluate();
+   if (gmy != gm) { REPORT delete gm; gm = gmy->Image(); }
+   else { REPORT }
+   gm->Protect();
+}
+
+void GenericMatrix::operator|=(const BaseMatrix& X)
+{
+   REPORT
+   Tracer tr("GenericMatrix::operator|=");
+   if (!gm) Throw(ProgramException("GenericMatrix is null"));
+   gm->Protect();            // so it cannot get deleted during Evaluate
+   GeneralMatrix* gmx = ((BaseMatrix&)X).Evaluate();
+   ConcatenatedMatrix am(gm,gmx);
+   if (gmx==gm) gm->Release(2); else gm->Release();
+   GeneralMatrix* gmy = am.Evaluate();
+   if (gmy != gm) { REPORT delete gm; gm = gmy->Image(); }
+   else { REPORT }
+   gm->Protect();
+}
+
+void GenericMatrix::operator&=(const BaseMatrix& X)
+{
+   REPORT
+   Tracer tr("GenericMatrix::operator&=");
+   if (!gm) Throw(ProgramException("GenericMatrix is null"));
+   gm->Protect();            // so it cannot get deleted during Evaluate
+   GeneralMatrix* gmx = ((BaseMatrix&)X).Evaluate();
+   StackedMatrix am(gm,gmx);
+   if (gmx==gm) gm->Release(2); else gm->Release();
+   GeneralMatrix* gmy = am.Evaluate();
+   if (gmy != gm) { REPORT delete gm; gm = gmy->Image(); }
+   else { REPORT }
+   gm->Protect();
+}
+
+void GenericMatrix::operator+=(Real r)
+{
+   REPORT
+   Tracer tr("GenericMatrix::operator+= (Real)");
+   if (!gm) Throw(ProgramException("GenericMatrix is null"));
+   ShiftedMatrix am(gm,r);
+   gm->Release();
+   GeneralMatrix* gmy = am.Evaluate();
+   if (gmy != gm) { REPORT delete gm; gm = gmy->Image(); }
+   else { REPORT }
+   gm->Protect();
+}
+
+void GenericMatrix::operator*=(Real r)
+{
+   REPORT
+   Tracer tr("GenericMatrix::operator*= (Real)");
+   if (!gm) Throw(ProgramException("GenericMatrix is null"));
+   ScaledMatrix am(gm,r);
+   gm->Release();
+   GeneralMatrix* gmy = am.Evaluate();
+   if (gmy != gm) { REPORT delete gm; gm = gmy->Image(); }
+   else { REPORT }
+   gm->Protect();
+}
+
+
+/************************* element access *********************************/
+
+Real& Matrix::element(int m, int n)
+{
+   REPORT
+   if (m<0 || m>= nrows_val || n<0 || n>= ncols_val)
+      Throw(IndexException(m,n,*this,true));
+   return store[m*ncols_val+n];
+}
+
+Real Matrix::element(int m, int n) const
+{
+   REPORT
+   if (m<0 || m>= nrows_val || n<0 || n>= ncols_val)
+      Throw(IndexException(m,n,*this,true));
+   return store[m*ncols_val+n];
+}
+
+Real& SymmetricMatrix::element(int m, int n)
+{
+   REPORT
+   if (m<0 || n<0 || m >= nrows_val || n>=ncols_val)
+      Throw(IndexException(m,n,*this,true));
+   if (m>=n) return store[tristore(m)+n];
+   else return store[tristore(n)+m];
+}
+
+Real SymmetricMatrix::element(int m, int n) const
+{
+   REPORT
+   if (m<0 || n<0 || m >= nrows_val || n>=ncols_val)
+      Throw(IndexException(m,n,*this,true));
+   if (m>=n) return store[tristore(m)+n];
+   else return store[tristore(n)+m];
+}
+
+Real& UpperTriangularMatrix::element(int m, int n)
+{
+   REPORT
+   if (m<0 || n<m || n>=ncols_val)
+      Throw(IndexException(m,n,*this,true));
+   return store[m*ncols_val+n-tristore(m)];
+}
+
+Real UpperTriangularMatrix::element(int m, int n) const
+{
+   REPORT
+   if (m<0 || n<m || n>=ncols_val)
+      Throw(IndexException(m,n,*this,true));
+   return store[m*ncols_val+n-tristore(m)];
+}
+
+Real& LowerTriangularMatrix::element(int m, int n)
+{
+   REPORT
+   if (n<0 || m<n || m>=nrows_val)
+      Throw(IndexException(m,n,*this,true));
+   return store[tristore(m)+n];
+}
+
+Real LowerTriangularMatrix::element(int m, int n) const
+{
+   REPORT
+   if (n<0 || m<n || m>=nrows_val)
+      Throw(IndexException(m,n,*this,true));
+   return store[tristore(m)+n];
+}
+
+Real& DiagonalMatrix::element(int m, int n)
+{
+   REPORT
+   if (n<0 || m!=n || m>=nrows_val || n>=ncols_val)
+      Throw(IndexException(m,n,*this,true));
+   return store[n];
+}
+
+Real DiagonalMatrix::element(int m, int n) const
+{
+   REPORT
+   if (n<0 || m!=n || m>=nrows_val || n>=ncols_val)
+      Throw(IndexException(m,n,*this,true));
+   return store[n];
+}
+
+Real& DiagonalMatrix::element(int m)
+{
+   REPORT
+   if (m<0 || m>=nrows_val) Throw(IndexException(m,*this,true));
+   return store[m];
+}
+
+Real DiagonalMatrix::element(int m) const
+{
+   REPORT
+   if (m<0 || m>=nrows_val) Throw(IndexException(m,*this,true));
+   return store[m];
+}
+
+Real& ColumnVector::element(int m)
+{
+   REPORT
+   if (m<0 || m>= nrows_val) Throw(IndexException(m,*this,true));
+   return store[m];
+}
+
+Real ColumnVector::element(int m) const
+{
+   REPORT
+   if (m<0 || m>= nrows_val) Throw(IndexException(m,*this,true));
+   return store[m];
+}
+
+Real& RowVector::element(int n)
+{
+   REPORT
+   if (n<0 || n>= ncols_val)  Throw(IndexException(n,*this,true));
+   return store[n];
+}
+
+Real RowVector::element(int n) const
+{
+   REPORT
+   if (n<0 || n>= ncols_val)  Throw(IndexException(n,*this,true));
+   return store[n];
+}
+
+Real& BandMatrix::element(int m, int n)
+{
+   REPORT
+   int w = upper_val+lower_val+1; int i = lower_val+n-m;
+   if (m<0 || m>= nrows_val || n<0 || n>= ncols_val || i<0 || i>=w)
+      Throw(IndexException(m,n,*this,true));
+   return store[w*m+i];
+}
+
+Real BandMatrix::element(int m, int n) const
+{
+   REPORT
+   int w = upper_val+lower_val+1; int i = lower_val+n-m;
+   if (m<0 || m>= nrows_val || n<0 || n>= ncols_val || i<0 || i>=w)
+      Throw(IndexException(m,n,*this,true));
+   return store[w*m+i];
+}
+
+Real& UpperBandMatrix::element(int m, int n)
+{
+   REPORT
+   int w = upper_val+1; int i = n-m;
+   if (m<0 || m>= nrows_val || n<0 || n>= ncols_val || i<0 || i>=w)
+      Throw(IndexException(m,n,*this,true));
+   return store[w*m+i];
+}
+
+Real UpperBandMatrix::element(int m, int n) const
+{
+   REPORT
+   int w = upper_val+1; int i = n-m;
+   if (m<0 || m>= nrows_val || n<0 || n>= ncols_val || i<0 || i>=w)
+      Throw(IndexException(m,n,*this,true));
+   return store[w*m+i];
+}
+
+Real& LowerBandMatrix::element(int m, int n)
+{
+   REPORT
+   int w = lower_val+1; int i = lower_val+n-m;
+   if (m<0 || m>= nrows_val || n<0 || n>= ncols_val || i<0 || i>=w)
+      Throw(IndexException(m,n,*this,true));
+   return store[w*m+i];
+}
+
+Real LowerBandMatrix::element(int m, int n) const
+{
+   REPORT
+   int w = lower_val+1; int i = lower_val+n-m;
+   if (m<0 || m>= nrows_val || n<0 || n>= ncols_val || i<0 || i>=w)
+      Throw(IndexException(m,n,*this,true));
+   return store[w*m+i];
+}
+
+Real& SymmetricBandMatrix::element(int m, int n)
+{
+   REPORT
+   int w = lower_val+1;
+   if (m>=n)
+   {
+      REPORT
+      int i = lower_val+n-m;
+      if ( m>=nrows_val || n<0 || i<0 )
+         Throw(IndexException(m,n,*this,true));
+      return store[w*m+i];
+   }
+   else
+   {
+      REPORT
+      int i = lower_val+m-n;
+      if ( n>=nrows_val || m<0 || i<0 )
+         Throw(IndexException(m,n,*this,true));
+      return store[w*n+i];
+   }
+}
+
+Real SymmetricBandMatrix::element(int m, int n) const
+{
+   REPORT
+   int w = lower_val+1;
+   if (m>=n)
+   {
+      REPORT
+      int i = lower_val+n-m;
+      if ( m>=nrows_val || n<0 || i<0 )
+         Throw(IndexException(m,n,*this,true));
+      return store[w*m+i];
+   }
+   else
+   {
+      REPORT
+      int i = lower_val+m-n;
+      if ( n>=nrows_val || m<0 || i<0 )
+         Throw(IndexException(m,n,*this,true));
+      return store[w*n+i];
+   }
+}
+
+#ifdef use_namespace
+}
+#endif
+
+
+///}
Index: /nanovis/tags/1.1.4/newmat11/newmat7.cpp
===================================================================
--- /nanovis/tags/1.1.4/newmat11/newmat7.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/newmat11/newmat7.cpp	(revision 4930)
@@ -0,0 +1,1032 @@
+/// \ingroup newmat
+///@{
+
+/// \file newmat7.cpp
+/// Invert, solve, binary operations.
+
+// Copyright (C) 1991,2,3,4: R B Davies
+
+#include "include.h"
+
+#include "newmat.h"
+#include "newmatrc.h"
+
+#ifdef use_namespace
+namespace NEWMAT {
+#endif
+
+
+#ifdef DO_REPORT
+#define REPORT { static ExeCounter ExeCount(__LINE__,7); ++ExeCount; }
+#else
+#define REPORT {}
+#endif
+
+
+//***************************** solve routines ******************************/
+
+GeneralMatrix* GeneralMatrix::MakeSolver()
+{
+   REPORT
+   GeneralMatrix* gm = new CroutMatrix(*this);
+   MatrixErrorNoSpace(gm); gm->ReleaseAndDelete(); return gm;
+}
+
+GeneralMatrix* Matrix::MakeSolver()
+{
+   REPORT
+   GeneralMatrix* gm = new CroutMatrix(*this);
+   MatrixErrorNoSpace(gm); gm->ReleaseAndDelete(); return gm;
+}
+
+void CroutMatrix::Solver(MatrixColX& mcout, const MatrixColX& mcin)
+{
+   REPORT
+   int i = mcin.skip; Real* el = mcin.data-i; Real* el1 = el;
+   while (i--) *el++ = 0.0;
+   el += mcin.storage; i = nrows_val - mcin.skip - mcin.storage;
+   while (i--) *el++ = 0.0;
+   lubksb(el1, mcout.skip);
+}
+
+
+// Do we need check for entirely zero output?
+
+void UpperTriangularMatrix::Solver(MatrixColX& mcout,
+   const MatrixColX& mcin)
+{
+   REPORT
+   int i = mcin.skip-mcout.skip; Real* elx = mcin.data-i;
+   while (i-- > 0) *elx++ = 0.0;
+   int nr = mcin.skip+mcin.storage;
+   elx = mcin.data+mcin.storage; Real* el = elx;
+   int j = mcout.skip+mcout.storage-nr;
+   int nc = ncols_val-nr; i = nr-mcout.skip;
+   while (j-- > 0) *elx++ = 0.0;
+   Real* Ael = store + (nr*(2*ncols_val-nr+1))/2; j = 0;
+   while (i-- > 0)
+   {
+      elx = el; Real sum = 0.0; int jx = j++; Ael -= nc;
+      while (jx--) sum += *(--Ael) * *(--elx);
+      elx--; *elx = (*elx - sum) / *(--Ael);
+   }
+}
+
+void LowerTriangularMatrix::Solver(MatrixColX& mcout,
+   const MatrixColX& mcin)
+{
+   REPORT
+   int i = mcin.skip-mcout.skip; Real* elx = mcin.data-i;
+   while (i-- > 0) *elx++ = 0.0;
+   int nc = mcin.skip; i = nc+mcin.storage; elx = mcin.data+mcin.storage;
+   int nr = mcout.skip+mcout.storage; int j = nr-i; i = nr-nc;
+   while (j-- > 0) *elx++ = 0.0;
+   Real* el = mcin.data; Real* Ael = store + (nc*(nc+1))/2; j = 0;
+   while (i-- > 0)
+   {
+      elx = el; Real sum = 0.0; int jx = j++; Ael += nc;
+      while (jx--) sum += *Ael++ * *elx++;
+      *elx = (*elx - sum) / *Ael++;
+   }
+}
+
+//******************* carry out binary operations *************************/
+
+static GeneralMatrix*
+   GeneralMult(GeneralMatrix*,GeneralMatrix*,MultipliedMatrix*,MatrixType);
+static GeneralMatrix*
+   GeneralSolv(GeneralMatrix*,GeneralMatrix*,BaseMatrix*,MatrixType);
+static GeneralMatrix*
+   GeneralSolvI(GeneralMatrix*,BaseMatrix*,MatrixType);
+static GeneralMatrix*
+   GeneralKP(GeneralMatrix*,GeneralMatrix*,KPMatrix*,MatrixType);
+
+GeneralMatrix* MultipliedMatrix::Evaluate(MatrixType mt)
+{
+   REPORT
+   gm2 = ((BaseMatrix*&)bm2)->Evaluate();
+   gm2 = gm2->Evaluate(gm2->type().MultRHS());     // no symmetric on RHS
+   gm1 = ((BaseMatrix*&)bm1)->Evaluate();
+   return GeneralMult(gm1, gm2, this, mt);
+}
+
+GeneralMatrix* SolvedMatrix::Evaluate(MatrixType mt)
+{
+   REPORT
+   gm1 = ((BaseMatrix*&)bm1)->Evaluate();
+   gm2 = ((BaseMatrix*&)bm2)->Evaluate();
+   return GeneralSolv(gm1,gm2,this,mt);
+}
+
+GeneralMatrix* KPMatrix::Evaluate(MatrixType mt)
+{
+   REPORT
+   gm1 = ((BaseMatrix*&)bm1)->Evaluate();
+   gm2 = ((BaseMatrix*&)bm2)->Evaluate();
+   return GeneralKP(gm1,gm2,this,mt);
+}
+
+// routines for adding or subtracting matrices of identical storage structure
+
+static void Add(GeneralMatrix* gm, GeneralMatrix* gm1, GeneralMatrix* gm2)
+{
+   REPORT
+   Real* s1=gm1->Store(); Real* s2=gm2->Store();
+   Real* s=gm->Store(); int i=gm->Storage() >> 2;
+   while (i--)
+   {
+       *s++ = *s1++ + *s2++; *s++ = *s1++ + *s2++;
+       *s++ = *s1++ + *s2++; *s++ = *s1++ + *s2++;
+   }
+   i=gm->Storage() & 3; while (i--) *s++ = *s1++ + *s2++;
+}
+
+static void AddTo(GeneralMatrix* gm, const GeneralMatrix* gm2)
+{
+   REPORT
+   const Real* s2=gm2->Store(); Real* s=gm->Store(); int i=gm->Storage() >> 2;
+   while (i--)
+   { *s++ += *s2++; *s++ += *s2++; *s++ += *s2++; *s++ += *s2++; }
+   i=gm->Storage() & 3; while (i--) *s++ += *s2++;
+}
+
+void GeneralMatrix::PlusEqual(const GeneralMatrix& gm)
+{
+   REPORT
+   if (nrows_val != gm.nrows_val || ncols_val != gm.ncols_val)
+      Throw(IncompatibleDimensionsException(*this, gm));
+   AddTo(this, &gm);
+}
+
+static void Subtract(GeneralMatrix* gm, GeneralMatrix* gm1, GeneralMatrix* gm2)
+{
+   REPORT
+   Real* s1=gm1->Store(); Real* s2=gm2->Store();
+   Real* s=gm->Store(); int i=gm->Storage() >> 2;
+   while (i--)
+   {
+       *s++ = *s1++ - *s2++; *s++ = *s1++ - *s2++;
+       *s++ = *s1++ - *s2++; *s++ = *s1++ - *s2++;
+   }
+   i=gm->Storage() & 3; while (i--) *s++ = *s1++ - *s2++;
+}
+
+static void SubtractFrom(GeneralMatrix* gm, const GeneralMatrix* gm2)
+{
+   REPORT
+   const Real* s2=gm2->Store(); Real* s=gm->Store(); int i=gm->Storage() >> 2;
+   while (i--)
+   { *s++ -= *s2++; *s++ -= *s2++; *s++ -= *s2++; *s++ -= *s2++; }
+   i=gm->Storage() & 3; while (i--) *s++ -= *s2++;
+}
+
+void GeneralMatrix::MinusEqual(const GeneralMatrix& gm)
+{
+   REPORT
+   if (nrows_val != gm.nrows_val || ncols_val != gm.ncols_val)
+      Throw(IncompatibleDimensionsException(*this, gm));
+   SubtractFrom(this, &gm);
+}
+
+static void ReverseSubtract(GeneralMatrix* gm, const GeneralMatrix* gm2)
+{
+   REPORT
+   const Real* s2=gm2->Store(); Real* s=gm->Store(); int i=gm->Storage() >> 2;
+   while (i--)
+   {
+      *s = *s2++ - *s; s++; *s = *s2++ - *s; s++;
+      *s = *s2++ - *s; s++; *s = *s2++ - *s; s++;
+   }
+   i=gm->Storage() & 3; while (i--) { *s = *s2++ - *s; s++; }
+}
+
+static void SP(GeneralMatrix* gm, GeneralMatrix* gm1, GeneralMatrix* gm2)
+{
+   REPORT
+   Real* s1=gm1->Store(); Real* s2=gm2->Store();
+   Real* s=gm->Store(); int i=gm->Storage() >> 2;
+   while (i--)
+   {
+       *s++ = *s1++ * *s2++; *s++ = *s1++ * *s2++;
+       *s++ = *s1++ * *s2++; *s++ = *s1++ * *s2++;
+   }
+   i=gm->Storage() & 3; while (i--) *s++ = *s1++ * *s2++;
+}
+
+static void SP(GeneralMatrix* gm, GeneralMatrix* gm2)
+{
+   REPORT
+   Real* s2=gm2->Store(); Real* s=gm->Store(); int i=gm->Storage() >> 2;
+   while (i--)
+   { *s++ *= *s2++; *s++ *= *s2++; *s++ *= *s2++; *s++ *= *s2++; }
+   i=gm->Storage() & 3; while (i--) *s++ *= *s2++;
+}
+
+// routines for adding or subtracting matrices of different storage structure
+
+static void AddDS(GeneralMatrix* gm, GeneralMatrix* gm1, GeneralMatrix* gm2)
+{
+   REPORT
+   int nr = gm->Nrows();
+   MatrixRow mr1(gm1, LoadOnEntry); MatrixRow mr2(gm2, LoadOnEntry);
+   MatrixRow mr(gm, StoreOnExit+DirectPart);
+   while (nr--) { mr.Add(mr1,mr2); mr1.Next(); mr2.Next(); mr.Next(); }
+}
+
+static void AddDS(GeneralMatrix* gm, GeneralMatrix* gm2)
+// Add into first argument
+{
+   REPORT
+   int nr = gm->Nrows();
+   MatrixRow mr(gm, StoreOnExit+LoadOnEntry+DirectPart);
+   MatrixRow mr2(gm2, LoadOnEntry);
+   while (nr--) { mr.Add(mr2); mr.Next(); mr2.Next(); }
+}
+
+static void SubtractDS
+   (GeneralMatrix* gm, GeneralMatrix* gm1, GeneralMatrix* gm2)
+{
+   REPORT
+   int nr = gm->Nrows();
+   MatrixRow mr1(gm1, LoadOnEntry); MatrixRow mr2(gm2, LoadOnEntry);
+   MatrixRow mr(gm, StoreOnExit+DirectPart);
+   while (nr--) { mr.Sub(mr1,mr2); mr1.Next(); mr2.Next(); mr.Next(); }
+}
+
+static void SubtractDS(GeneralMatrix* gm, GeneralMatrix* gm2)
+{
+   REPORT
+   int nr = gm->Nrows();
+   MatrixRow mr(gm, LoadOnEntry+StoreOnExit+DirectPart);
+   MatrixRow mr2(gm2, LoadOnEntry);
+   while (nr--) { mr.Sub(mr2); mr.Next(); mr2.Next(); }
+}
+
+static void ReverseSubtractDS(GeneralMatrix* gm, GeneralMatrix* gm2)
+{
+   REPORT
+   int nr = gm->Nrows();
+   MatrixRow mr(gm, LoadOnEntry+StoreOnExit+DirectPart);
+   MatrixRow mr2(gm2, LoadOnEntry);
+   while (nr--) { mr.RevSub(mr2); mr2.Next(); mr.Next(); }
+}
+
+static void SPDS(GeneralMatrix* gm, GeneralMatrix* gm1, GeneralMatrix* gm2)
+{
+   REPORT
+   int nr = gm->Nrows();
+   MatrixRow mr1(gm1, LoadOnEntry); MatrixRow mr2(gm2, LoadOnEntry);
+   MatrixRow mr(gm, StoreOnExit+DirectPart);
+   while (nr--) { mr.Multiply(mr1,mr2); mr1.Next(); mr2.Next(); mr.Next(); }
+}
+
+static void SPDS(GeneralMatrix* gm, GeneralMatrix* gm2)
+// SP into first argument
+{
+   REPORT
+   int nr = gm->Nrows();
+   MatrixRow mr(gm, StoreOnExit+LoadOnEntry+DirectPart);
+   MatrixRow mr2(gm2, LoadOnEntry);
+   while (nr--) { mr.Multiply(mr2); mr.Next(); mr2.Next(); }
+}
+
+static GeneralMatrix* GeneralMult1(GeneralMatrix* gm1, GeneralMatrix* gm2,
+   MultipliedMatrix* mm, MatrixType mtx)
+{
+   REPORT
+   Tracer tr("GeneralMult1");
+   int nr=gm1->Nrows(); int nc=gm2->Ncols();
+   if (gm1->Ncols() !=gm2->Nrows())
+      Throw(IncompatibleDimensionsException(*gm1, *gm2));
+   GeneralMatrix* gmx = mtx.New(nr,nc,mm);
+
+   MatrixCol mcx(gmx, StoreOnExit+DirectPart);
+   MatrixCol mc2(gm2, LoadOnEntry);
+   while (nc--)
+   {
+      MatrixRow mr1(gm1, LoadOnEntry, mcx.Skip());
+      Real* el = mcx.Data();                         // pointer to an element
+      int n = mcx.Storage();
+      while (n--) { *(el++) = DotProd(mr1,mc2); mr1.Next(); }
+      mc2.Next(); mcx.Next();
+   }
+   gmx->ReleaseAndDelete(); gm1->tDelete(); gm2->tDelete(); return gmx;
+}
+
+static GeneralMatrix* GeneralMult2(GeneralMatrix* gm1, GeneralMatrix* gm2,
+   MultipliedMatrix* mm, MatrixType mtx)
+{
+   // version that accesses by row only - not good for thin matrices
+   // or column vectors in right hand term.
+   REPORT
+   Tracer tr("GeneralMult2");
+   int nr=gm1->Nrows(); int nc=gm2->Ncols();
+   if (gm1->Ncols() !=gm2->Nrows())
+      Throw(IncompatibleDimensionsException(*gm1, *gm2));
+   GeneralMatrix* gmx = mtx.New(nr,nc,mm);
+
+   MatrixRow mrx(gmx, LoadOnEntry+StoreOnExit+DirectPart);
+   MatrixRow mr1(gm1, LoadOnEntry);
+   while (nr--)
+   {
+      MatrixRow mr2(gm2, LoadOnEntry, mr1.Skip());
+      Real* el = mr1.Data();                         // pointer to an element
+      int n = mr1.Storage();
+      mrx.Zero();
+      while (n--) { mrx.AddScaled(mr2, *el++); mr2.Next(); }
+      mr1.Next(); mrx.Next();
+   }
+   gmx->ReleaseAndDelete(); gm1->tDelete(); gm2->tDelete(); return gmx;
+}
+
+static GeneralMatrix* mmMult(GeneralMatrix* gm1, GeneralMatrix* gm2)
+{
+   // matrix multiplication for type Matrix only
+   REPORT
+   Tracer tr("MatrixMult");
+
+   int nr=gm1->Nrows(); int ncr=gm1->Ncols(); int nc=gm2->Ncols();
+   if (ncr != gm2->Nrows()) Throw(IncompatibleDimensionsException(*gm1,*gm2));
+
+   Matrix* gm = new Matrix(nr,nc); MatrixErrorNoSpace(gm);
+
+   Real* s1=gm1->Store(); Real* s2=gm2->Store(); Real* s=gm->Store();
+
+   if (ncr)
+   {
+      while (nr--)
+      {
+         Real* s2x = s2; int j = ncr;
+         Real* sx = s; Real f = *s1++; int k = nc;
+         while (k--) *sx++ = f * *s2x++;
+         while (--j)
+            { sx = s; f = *s1++; k = nc; while (k--) *sx++ += f * *s2x++; }
+         s = sx;
+      }
+   }
+   else *gm = 0.0;
+
+   gm->ReleaseAndDelete(); gm1->tDelete(); gm2->tDelete(); return gm;
+}
+
+static GeneralMatrix* GeneralMult(GeneralMatrix* gm1, GeneralMatrix* gm2,
+   MultipliedMatrix* mm, MatrixType mtx)
+{
+   if ( Rectangular(gm1->type(), gm2->type(), mtx))
+      { REPORT return mmMult(gm1, gm2); }
+   Compare(gm1->type() * gm2->type(),mtx);
+   int nr = gm2->Nrows(); int nc = gm2->Ncols();
+   if (nc <= 5 && nr > nc) { REPORT return GeneralMult1(gm1, gm2, mm, mtx); }
+   REPORT return GeneralMult2(gm1, gm2, mm, mtx);
+}
+
+static GeneralMatrix* GeneralKP(GeneralMatrix* gm1, GeneralMatrix* gm2,
+   KPMatrix* kp, MatrixType mtx)
+{
+   REPORT
+   Tracer tr("GeneralKP");
+   int nr1 = gm1->Nrows(); int nc1 = gm1->Ncols();
+   int nr2 = gm2->Nrows(); int nc2 = gm2->Ncols();
+   Compare((gm1->type()).KP(gm2->type()),mtx);
+   GeneralMatrix* gmx = mtx.New(nr1*nr2, nc1*nc2, kp);
+   MatrixRow mrx(gmx, LoadOnEntry+StoreOnExit+DirectPart);
+   MatrixRow mr1(gm1, LoadOnEntry);
+   for (int i = 1; i <= nr1; ++i)
+   {
+      MatrixRow mr2(gm2, LoadOnEntry);
+      for (int j = 1; j <= nr2; ++j)
+         { mrx.KP(mr1,mr2); mr2.Next(); mrx.Next(); }
+      mr1.Next();
+   }
+   gmx->ReleaseAndDelete(); gm1->tDelete(); gm2->tDelete(); return gmx;
+}
+
+static GeneralMatrix* GeneralSolv(GeneralMatrix* gm1, GeneralMatrix* gm2,
+   BaseMatrix* sm, MatrixType mtx)
+{
+   REPORT
+   Tracer tr("GeneralSolv");
+   Compare(gm1->type().i() * gm2->type(),mtx);
+   int nr = gm1->Nrows();
+   if (nr != gm1->Ncols()) Throw(NotSquareException(*gm1));
+   int nc = gm2->Ncols();
+   if (gm1->Ncols() != gm2->Nrows())
+      Throw(IncompatibleDimensionsException(*gm1, *gm2));
+   GeneralMatrix* gmx = mtx.New(nr,nc,sm); MatrixErrorNoSpace(gmx);
+   Real* r = new Real [nr]; MatrixErrorNoSpace(r);
+   MONITOR_REAL_NEW("Make   (GenSolv)",nr,r)
+   GeneralMatrix* gms = gm1->MakeSolver();
+   Try
+   {
+
+      MatrixColX mcx(gmx, r, StoreOnExit+DirectPart);   // copy to and from r
+         // this must be inside Try so mcx is destroyed before gmx
+      MatrixColX mc2(gm2, r, LoadOnEntry);
+      while (nc--) { gms->Solver(mcx, mc2); mcx.Next(); mc2.Next(); }
+   }
+   CatchAll
+   {
+      if (gms) gms->tDelete();
+      delete gmx;                   // <--------------------
+      gm2->tDelete();
+      MONITOR_REAL_DELETE("Delete (GenSolv)",nr,r)
+                          // AT&T version 2.1 gives an internal error
+      delete [] r;
+      ReThrow;
+   }
+   gms->tDelete(); gmx->ReleaseAndDelete(); gm2->tDelete();
+   MONITOR_REAL_DELETE("Delete (GenSolv)",nr,r)
+                          // AT&T version 2.1 gives an internal error
+   delete [] r;
+   return gmx;
+}
+
+// version for inverses - gm2 is identity
+static GeneralMatrix* GeneralSolvI(GeneralMatrix* gm1, BaseMatrix* sm,
+   MatrixType mtx)
+{
+   REPORT
+   Tracer tr("GeneralSolvI");
+   Compare(gm1->type().i(),mtx);
+   int nr = gm1->Nrows();
+   if (nr != gm1->Ncols()) Throw(NotSquareException(*gm1));
+   int nc = nr;
+   // DiagonalMatrix I(nr); I = 1;
+   IdentityMatrix I(nr);
+   GeneralMatrix* gmx = mtx.New(nr,nc,sm); MatrixErrorNoSpace(gmx);
+   Real* r = new Real [nr]; MatrixErrorNoSpace(r);
+   MONITOR_REAL_NEW("Make   (GenSolvI)",nr,r)
+   GeneralMatrix* gms = gm1->MakeSolver();
+   Try
+   {
+
+      MatrixColX mcx(gmx, r, StoreOnExit+DirectPart);   // copy to and from r
+         // this must be inside Try so mcx is destroyed before gmx
+      MatrixColX mc2(&I, r, LoadOnEntry);
+      while (nc--) { gms->Solver(mcx, mc2); mcx.Next(); mc2.Next(); }
+   }
+   CatchAll
+   {
+      if (gms) gms->tDelete();
+      delete gmx;
+      MONITOR_REAL_DELETE("Delete (GenSolvI)",nr,r)
+                          // AT&T version 2.1 gives an internal error
+      delete [] r;
+      ReThrow;
+   }
+   gms->tDelete(); gmx->ReleaseAndDelete();
+   MONITOR_REAL_DELETE("Delete (GenSolvI)",nr,r)
+                          // AT&T version 2.1 gives an internal error
+   delete [] r;
+   return gmx;
+}
+
+GeneralMatrix* InvertedMatrix::Evaluate(MatrixType mtx)
+{
+   // Matrix Inversion - use solve routines
+   Tracer tr("InvertedMatrix::Evaluate");
+   REPORT
+   gm=((BaseMatrix*&)bm)->Evaluate();
+   return GeneralSolvI(gm,this,mtx);
+}
+
+//*************************** New versions ************************
+
+GeneralMatrix* AddedMatrix::Evaluate(MatrixType mtd)
+{
+   REPORT
+   Tracer tr("AddedMatrix::Evaluate");
+   gm1=((BaseMatrix*&)bm1)->Evaluate(); gm2=((BaseMatrix*&)bm2)->Evaluate();
+   int nr=gm1->Nrows(); int nc=gm1->Ncols();
+   if (nr!=gm2->Nrows() || nc!=gm2->Ncols())
+   {
+      Try { Throw(IncompatibleDimensionsException(*gm1, *gm2)); }
+      CatchAll
+      {
+         gm1->tDelete(); gm2->tDelete();
+         ReThrow;
+      }
+   }
+   MatrixType mt1 = gm1->type(), mt2 = gm2->type(); MatrixType mts = mt1 + mt2;
+   if (!mtd) { REPORT mtd = mts; }
+   else if (!(mtd.DataLossOK || mtd >= mts))
+   {
+      REPORT
+      gm1->tDelete(); gm2->tDelete();
+      Throw(ProgramException("Illegal Conversion", mts, mtd));
+   }
+   GeneralMatrix* gmx;
+   bool c1 = (mtd == mt1), c2 = (mtd == mt2);
+   if ( c1 && c2 && (gm1->SimpleAddOK(gm2) == 0) )
+   {
+      if (gm1->reuse()) { REPORT AddTo(gm1,gm2); gm2->tDelete(); gmx = gm1; }
+      else if (gm2->reuse()) { REPORT AddTo(gm2,gm1); gmx = gm2; }
+      else
+      {
+         REPORT
+         // what if new throws an exception
+         Try { gmx = mt1.New(nr,nc,this); }
+         CatchAll
+         {
+            ReThrow;
+         }
+         gmx->ReleaseAndDelete(); Add(gmx,gm1,gm2);
+      }
+   }
+   else
+   {
+      if (c1 && c2)
+      {
+         short SAO = gm1->SimpleAddOK(gm2);
+         if (SAO & 1) { REPORT c1 = false; }
+         if (SAO & 2) { REPORT c2 = false; }
+      }
+      if (c1 && gm1->reuse() )               // must have type test first
+         { REPORT AddDS(gm1,gm2); gm2->tDelete(); gmx = gm1; }
+      else if (c2 && gm2->reuse() )
+         { REPORT AddDS(gm2,gm1); if (!c1) gm1->tDelete(); gmx = gm2; }
+      else
+      {
+         REPORT
+         Try { gmx = mtd.New(nr,nc,this); }
+         CatchAll
+         {
+            if (!c1) gm1->tDelete(); if (!c2) gm2->tDelete();
+            ReThrow;
+         }
+         AddDS(gmx,gm1,gm2);
+         if (!c1) gm1->tDelete(); if (!c2) gm2->tDelete();
+         gmx->ReleaseAndDelete();
+      }
+   }
+   return gmx;
+}
+
+GeneralMatrix* SubtractedMatrix::Evaluate(MatrixType mtd)
+{
+   REPORT
+   Tracer tr("SubtractedMatrix::Evaluate");
+   gm1=((BaseMatrix*&)bm1)->Evaluate(); gm2=((BaseMatrix*&)bm2)->Evaluate();
+   int nr=gm1->Nrows(); int nc=gm1->Ncols();
+   if (nr!=gm2->Nrows() || nc!=gm2->Ncols())
+   {
+      Try { Throw(IncompatibleDimensionsException(*gm1, *gm2)); }
+      CatchAll
+      {
+         gm1->tDelete(); gm2->tDelete();
+         ReThrow;
+      }
+   }
+   MatrixType mt1 = gm1->type(), mt2 = gm2->type(); MatrixType mts = mt1 + mt2;
+   if (!mtd) { REPORT mtd = mts; }
+   else if (!(mtd.DataLossOK || mtd >= mts))
+   {
+      gm1->tDelete(); gm2->tDelete();
+      Throw(ProgramException("Illegal Conversion", mts, mtd));
+   }
+   GeneralMatrix* gmx;
+   bool c1 = (mtd == mt1), c2 = (mtd == mt2);
+   if ( c1 && c2 && (gm1->SimpleAddOK(gm2) == 0) )
+   {
+      if (gm1->reuse())
+         { REPORT SubtractFrom(gm1,gm2); gm2->tDelete(); gmx = gm1; }
+      else if (gm2->reuse()) { REPORT ReverseSubtract(gm2,gm1); gmx = gm2; }
+      else
+      {
+         REPORT
+         Try { gmx = mt1.New(nr,nc,this); }
+         CatchAll
+         {
+            ReThrow;
+         }
+         gmx->ReleaseAndDelete(); Subtract(gmx,gm1,gm2);
+      }
+   }
+   else
+   {
+      if (c1 && c2)
+      {
+         short SAO = gm1->SimpleAddOK(gm2);
+         if (SAO & 1) { REPORT c1 = false; }
+         if (SAO & 2) { REPORT c2 = false; }
+      }
+      if (c1 && gm1->reuse() )               // must have type test first
+         { REPORT SubtractDS(gm1,gm2); gm2->tDelete(); gmx = gm1; }
+      else if (c2 && gm2->reuse() )
+      {
+         REPORT ReverseSubtractDS(gm2,gm1);
+         if (!c1) gm1->tDelete(); gmx = gm2;
+      }
+      else
+      {
+         REPORT
+         // what if New throws and exception
+         Try { gmx = mtd.New(nr,nc,this); }
+         CatchAll
+         {
+            if (!c1) gm1->tDelete(); if (!c2) gm2->tDelete();
+            ReThrow;
+         }
+         SubtractDS(gmx,gm1,gm2);
+         if (!c1) gm1->tDelete(); if (!c2) gm2->tDelete();
+         gmx->ReleaseAndDelete();
+      }
+   }
+   return gmx;
+}
+
+GeneralMatrix* SPMatrix::Evaluate(MatrixType mtd)
+{
+   REPORT
+   Tracer tr("SPMatrix::Evaluate");
+   gm1=((BaseMatrix*&)bm1)->Evaluate(); gm2=((BaseMatrix*&)bm2)->Evaluate();
+   int nr=gm1->Nrows(); int nc=gm1->Ncols();
+   if (nr!=gm2->Nrows() || nc!=gm2->Ncols())
+   {
+      Try { Throw(IncompatibleDimensionsException(*gm1, *gm2)); }
+      CatchAll
+      {
+         gm1->tDelete(); gm2->tDelete();
+         ReThrow;
+      }
+   }
+   MatrixType mt1 = gm1->type(), mt2 = gm2->type();
+   MatrixType mts = mt1.SP(mt2);
+   if (!mtd) { REPORT mtd = mts; }
+   else if (!(mtd.DataLossOK || mtd >= mts))
+   {
+      gm1->tDelete(); gm2->tDelete();
+      Throw(ProgramException("Illegal Conversion", mts, mtd));
+   }
+   GeneralMatrix* gmx;
+   bool c1 = (mtd == mt1), c2 = (mtd == mt2);
+   if ( c1 && c2 && (gm1->SimpleAddOK(gm2) == 0) )
+   {
+      if (gm1->reuse()) { REPORT SP(gm1,gm2); gm2->tDelete(); gmx = gm1; }
+      else if (gm2->reuse()) { REPORT SP(gm2,gm1); gmx = gm2; }
+      else
+      {
+         REPORT
+         Try { gmx = mt1.New(nr,nc,this); }
+         CatchAll
+         {
+            ReThrow;
+         }
+         gmx->ReleaseAndDelete(); SP(gmx,gm1,gm2);
+      }
+   }
+   else
+   {
+      if (c1 && c2)
+      {
+         short SAO = gm1->SimpleAddOK(gm2);
+         if (SAO & 1) { REPORT c2 = false; }    // c1 and c2 swapped
+         if (SAO & 2) { REPORT c1 = false; }
+      }
+      if (c1 && gm1->reuse() )               // must have type test first
+         { REPORT SPDS(gm1,gm2); gm2->tDelete(); gmx = gm1; }
+      else if (c2 && gm2->reuse() )
+         { REPORT SPDS(gm2,gm1); if (!c1) gm1->tDelete(); gmx = gm2; }
+      else
+      {
+         REPORT
+         // what if New throws and exception
+         Try { gmx = mtd.New(nr,nc,this); }
+         CatchAll
+         {
+            if (!c1) gm1->tDelete(); if (!c2) gm2->tDelete();
+            ReThrow;
+         }
+         SPDS(gmx,gm1,gm2);
+         if (!c1) gm1->tDelete(); if (!c2) gm2->tDelete();
+         gmx->ReleaseAndDelete();
+      }
+   }
+   return gmx;
+}
+
+
+
+//*************************** norm functions ****************************/
+
+Real BaseMatrix::norm1() const
+{
+   // maximum of sum of absolute values of a column
+   REPORT
+   GeneralMatrix* gm = ((BaseMatrix&)*this).Evaluate();
+   int nc = gm->Ncols(); Real value = 0.0;
+   MatrixCol mc(gm, LoadOnEntry);
+   while (nc--)
+      { Real v = mc.SumAbsoluteValue(); if (value < v) value = v; mc.Next(); }
+   gm->tDelete(); return value;
+}
+
+Real BaseMatrix::norm_infinity() const
+{
+   // maximum of sum of absolute values of a row
+   REPORT
+   GeneralMatrix* gm = ((BaseMatrix&)*this).Evaluate();
+   int nr = gm->Nrows(); Real value = 0.0;
+   MatrixRow mr(gm, LoadOnEntry);
+   while (nr--)
+      { Real v = mr.SumAbsoluteValue(); if (value < v) value = v; mr.Next(); }
+   gm->tDelete(); return value;
+}
+
+//********************** Concatenation and stacking *************************/
+
+GeneralMatrix* ConcatenatedMatrix::Evaluate(MatrixType mtx)
+{
+   REPORT
+   Tracer tr("Concatenate");
+      gm2 = ((BaseMatrix*&)bm2)->Evaluate();
+      gm1 = ((BaseMatrix*&)bm1)->Evaluate();
+      Compare(gm1->type() | gm2->type(),mtx);
+      int nr=gm1->Nrows(); int nc = gm1->Ncols() + gm2->Ncols();
+      if (nr != gm2->Nrows())
+         Throw(IncompatibleDimensionsException(*gm1, *gm2));
+      GeneralMatrix* gmx = mtx.New(nr,nc,this);
+      MatrixRow mr1(gm1, LoadOnEntry); MatrixRow mr2(gm2, LoadOnEntry);
+      MatrixRow mr(gmx, StoreOnExit+DirectPart);
+      while (nr--) { mr.ConCat(mr1,mr2); mr1.Next(); mr2.Next(); mr.Next(); }
+      gmx->ReleaseAndDelete(); gm1->tDelete(); gm2->tDelete(); return gmx;
+}
+
+GeneralMatrix* StackedMatrix::Evaluate(MatrixType mtx)
+{
+   REPORT
+   Tracer tr("Stack");
+      gm2 = ((BaseMatrix*&)bm2)->Evaluate();
+      gm1 = ((BaseMatrix*&)bm1)->Evaluate();
+      Compare(gm1->type() & gm2->type(),mtx);
+      int nc=gm1->Ncols();
+      int nr1 = gm1->Nrows(); int nr2 = gm2->Nrows();
+      if (nc != gm2->Ncols())
+         Throw(IncompatibleDimensionsException(*gm1, *gm2));
+      GeneralMatrix* gmx = mtx.New(nr1+nr2,nc,this);
+      MatrixRow mr1(gm1, LoadOnEntry); MatrixRow mr2(gm2, LoadOnEntry);
+      MatrixRow mr(gmx, StoreOnExit+DirectPart);
+      while (nr1--) { mr.Copy(mr1); mr1.Next(); mr.Next(); }
+      while (nr2--) { mr.Copy(mr2); mr2.Next(); mr.Next(); }
+      gmx->ReleaseAndDelete(); gm1->tDelete(); gm2->tDelete(); return gmx;
+}
+
+// ************************* equality of matrices ******************** //
+
+static bool RealEqual(Real* s1, Real* s2, int n)
+{
+   int i = n >> 2;
+   while (i--)
+   {
+      if (*s1++ != *s2++) return false; if (*s1++ != *s2++) return false;
+      if (*s1++ != *s2++) return false; if (*s1++ != *s2++) return false;
+   }
+   i = n & 3; while (i--) if (*s1++ != *s2++) return false;
+   return true;
+}
+
+static bool intEqual(int* s1, int* s2, int n)
+{
+   int i = n >> 2;
+   while (i--)
+   {
+      if (*s1++ != *s2++) return false; if (*s1++ != *s2++) return false;
+      if (*s1++ != *s2++) return false; if (*s1++ != *s2++) return false;
+   }
+   i = n & 3; while (i--) if (*s1++ != *s2++) return false;
+   return true;
+}
+
+
+bool operator==(const BaseMatrix& A, const BaseMatrix& B)
+{
+   Tracer tr("BaseMatrix ==");
+   REPORT
+   GeneralMatrix* gmA = ((BaseMatrix&)A).Evaluate();
+   GeneralMatrix* gmB = ((BaseMatrix&)B).Evaluate();
+
+   if (gmA == gmB)                            // same matrix
+      { REPORT gmA->tDelete(); return true; }
+
+   if ( gmA->Nrows() != gmB->Nrows() || gmA->Ncols() != gmB->Ncols() )
+                                              // different dimensions
+      { REPORT gmA->tDelete(); gmB->tDelete(); return false; }
+
+   // check for CroutMatrix or BandLUMatrix
+   MatrixType AType = gmA->type(); MatrixType BType = gmB->type();
+   if (AType.CannotConvert() || BType.CannotConvert() )
+   {
+      REPORT
+      bool bx = gmA->IsEqual(*gmB);
+      gmA->tDelete(); gmB->tDelete();
+      return bx;
+   }
+
+   // is matrix storage the same
+   // will need to modify if further matrix structures are introduced
+   if (AType == BType && gmA->bandwidth() == gmB->bandwidth())
+   {                                          // compare store
+      REPORT
+      bool bx = RealEqual(gmA->Store(),gmB->Store(),gmA->Storage());
+      gmA->tDelete(); gmB->tDelete();
+      return bx;
+   }
+
+   // matrix storage different - just subtract
+   REPORT  return is_zero(*gmA-*gmB);
+}
+
+bool operator==(const GeneralMatrix& A, const GeneralMatrix& B)
+{
+   Tracer tr("GeneralMatrix ==");
+   // May or may not call tDeletes
+   REPORT
+
+   if (&A == &B)                              // same matrix
+      { REPORT return true; }
+
+   if ( A.Nrows() != B.Nrows() || A.Ncols() != B.Ncols() )
+      { REPORT return false; }                // different dimensions
+
+   // check for CroutMatrix or BandLUMatrix
+   MatrixType AType = A.Type(); MatrixType BType = B.Type();
+   if (AType.CannotConvert() || BType.CannotConvert() )
+      { REPORT  return A.IsEqual(B); }
+
+   // is matrix storage the same
+   // will need to modify if further matrix structures are introduced
+   if (AType == BType && A.bandwidth() == B.bandwidth())
+      { REPORT return RealEqual(A.Store(),B.Store(),A.Storage()); }
+
+   // matrix storage different - just subtract
+   REPORT  return is_zero(A-B);
+}
+
+bool GeneralMatrix::is_zero() const
+{
+   REPORT
+   Real* s=store; int i = storage >> 2;
+   while (i--)
+   {
+      if (*s++) return false; if (*s++) return false;
+      if (*s++) return false; if (*s++) return false;
+   }
+   i = storage & 3; while (i--) if (*s++) return false;
+   return true;
+}
+
+bool is_zero(const BaseMatrix& A)
+{
+   Tracer tr("BaseMatrix::is_zero");
+   REPORT
+   GeneralMatrix* gm1 = 0; bool bx;
+   Try { gm1=((BaseMatrix&)A).Evaluate(); bx = gm1->is_zero(); }
+   CatchAll { if (gm1) gm1->tDelete(); ReThrow; }
+   gm1->tDelete();
+   return bx;
+}
+
+// IsEqual functions - insist matrices are of same type
+// as well as equal values to be equal
+
+bool GeneralMatrix::IsEqual(const GeneralMatrix& A) const
+{
+   Tracer tr("GeneralMatrix IsEqual");
+   if (A.type() != type())                       // not same types
+      { REPORT return false; }
+   if (&A == this)                               // same matrix
+      { REPORT  return true; }
+   if (A.nrows_val != nrows_val || A.ncols_val != ncols_val)
+                                                 // different dimensions
+   { REPORT return false; }
+   // is matrix storage the same - compare store
+   REPORT
+   return RealEqual(A.store,store,storage);
+}
+
+bool CroutMatrix::IsEqual(const GeneralMatrix& A) const
+{
+   Tracer tr("CroutMatrix IsEqual");
+   if (A.type() != type())                       // not same types
+      { REPORT return false; }
+   if (&A == this)                               // same matrix
+      { REPORT  return true; }
+   if (A.nrows_val != nrows_val || A.ncols_val != ncols_val)
+                                                 // different dimensions
+   { REPORT return false; }
+   // is matrix storage the same - compare store
+   REPORT
+   return RealEqual(A.store,store,storage)
+      && intEqual(((CroutMatrix&)A).indx, indx, nrows_val);
+}
+
+
+bool BandLUMatrix::IsEqual(const GeneralMatrix& A) const
+{
+   Tracer tr("BandLUMatrix IsEqual");
+   if (A.type() != type())                       // not same types
+      { REPORT  return false; }
+   if (&A == this)                               // same matrix
+      { REPORT  return true; }
+   if ( A.Nrows() != nrows_val || A.Ncols() != ncols_val
+      || ((BandLUMatrix&)A).m1 != m1 || ((BandLUMatrix&)A).m2 != m2 )
+                                                 // different dimensions
+   { REPORT  return false; }
+
+   // matrix storage the same - compare store
+   REPORT
+   return RealEqual(A.Store(),store,storage)
+      && RealEqual(((BandLUMatrix&)A).store2,store2,storage2)
+      && intEqual(((BandLUMatrix&)A).indx, indx, nrows_val);
+}
+
+
+// ************************* cross products ******************** //
+
+inline void crossproduct_body(Real* a, Real* b, Real* c)
+{
+   c[0] = a[1] * b[2] - a[2] * b[1];
+   c[1] = a[2] * b[0] - a[0] * b[2];
+   c[2] = a[0] * b[1] - a[1] * b[0];
+}
+
+Matrix crossproduct(const Matrix& A, const Matrix& B)
+{
+   REPORT
+   int ac = A.Ncols(); int ar = A.Nrows();
+   int bc = B.Ncols(); int br = B.Nrows();
+   Real* a = A.Store(); Real* b = B.Store();
+   if (ac == 3)
+   {
+      if (bc != 3 || ar != 1 || br != 1)
+         { Tracer et("crossproduct"); IncompatibleDimensionsException(A, B); }
+      REPORT
+      RowVector C(3);  Real* c = C.Store(); crossproduct_body(a, b, c);
+      return (Matrix&)C;
+   }
+   else
+   {
+      if (ac != 1 || bc != 1 || ar != 3 || br != 3)
+         { Tracer et("crossproduct"); IncompatibleDimensionsException(A, B); }
+      REPORT
+      ColumnVector C(3);  Real* c = C.Store(); crossproduct_body(a, b, c);
+      return (Matrix&)C;
+   }
+}
+
+ReturnMatrix crossproduct_rows(const Matrix& A, const Matrix& B)
+{
+   REPORT
+   int n = A.Nrows();
+   if (A.Ncols() != 3 || B.Ncols() != 3 || n != B.Nrows())
+   {
+      Tracer et("crossproduct_rows"); IncompatibleDimensionsException(A, B);
+   }
+   Matrix C(n, 3);
+   Real* a = A.Store(); Real* b = B.Store(); Real* c = C.Store();
+   if (n--)
+   {
+      for (;;)
+      {
+         crossproduct_body(a, b, c);
+         if (!(n--)) break;
+         a += 3; b += 3; c += 3;
+      }
+   }
+
+   return C.ForReturn();
+}
+
+ReturnMatrix crossproduct_columns(const Matrix& A, const Matrix& B)
+{
+   REPORT
+   int n = A.Ncols();
+   if (A.Nrows() != 3 || B.Nrows() != 3 || n != B.Ncols())
+   {
+      Tracer et("crossproduct_columns");
+      IncompatibleDimensionsException(A, B);
+   }
+   Matrix C(3, n);
+   Real* a = A.Store(); Real* b = B.Store(); Real* c = C.Store();
+   Real* an = a+n; Real* an2 = an+n;
+   Real* bn = b+n; Real* bn2 = bn+n;
+   Real* cn = c+n; Real* cn2 = cn+n;
+
+   int i = n; 
+   while (i--)
+   {
+      *c++   = *an    * *bn2   - *an2   * *bn;
+      *cn++  = *an2++ * *b     - *a     * *bn2++;
+      *cn2++ = *a++   * *bn++  - *an++  * *b++;
+   }
+
+   return C.ForReturn();
+}
+
+
+#ifdef use_namespace
+}
+#endif
+
+///@}
+
Index: /nanovis/tags/1.1.4/newmat11/newmat8.cpp
===================================================================
--- /nanovis/tags/1.1.4/newmat11/newmat8.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/newmat11/newmat8.cpp	(revision 4930)
@@ -0,0 +1,832 @@
+/// \ingroup newmat
+///@{
+
+/// \file newmat8.cpp
+/// LU transform, scalar functions of matrices.
+
+// Copyright (C) 1991,2,3,4,8: R B Davies
+
+#define WANT_MATH
+
+#include "include.h"
+
+#include "newmat.h"
+#include "newmatrc.h"
+#include "precisio.h"
+
+#ifdef use_namespace
+namespace NEWMAT {
+#endif
+
+
+#ifdef DO_REPORT
+#define REPORT { static ExeCounter ExeCount(__LINE__,8); ++ExeCount; }
+#else
+#define REPORT {}
+#endif
+
+
+/************************** LU transformation ****************************/
+
+void CroutMatrix::ludcmp()
+// LU decomposition from Golub & Van Loan, algorithm 3.4.1, (the "outer
+// product" version).
+// This replaces the code derived from Numerical Recipes in C in previous
+// versions of newmat and being row oriented runs much faster with large
+// matrices.
+{
+   REPORT
+   Tracer tr( "Crout(ludcmp)" ); sing = false;
+   Real* akk = store;                    // runs down diagonal
+
+   Real big = fabs(*akk); int mu = 0; Real* ai = akk; int k;
+
+   for (k = 1; k < nrows_val; k++)
+   {
+      ai += nrows_val; const Real trybig = fabs(*ai);
+      if (big < trybig) { big = trybig; mu = k; }
+   }
+
+
+   if (nrows_val) for (k = 0;;)
+   {
+      /*
+      int mu1;
+      {
+         Real big = fabs(*akk); mu1 = k; Real* ai = akk; int i;
+
+         for (i = k+1; i < nrows_val; i++)
+         {
+            ai += nrows_val; const Real trybig = fabs(*ai);
+            if (big < trybig) { big = trybig; mu1 = i; }
+         }
+      }
+      if (mu1 != mu) cout << k << " " << mu << " " << mu1 << endl;
+      */
+
+      indx[k] = mu;
+
+      if (mu != k)                       //row swap
+      {
+         Real* a1 = store + nrows_val * k;
+         Real* a2 = store + nrows_val * mu; d = !d;
+         int j = nrows_val;
+         while (j--) { const Real temp = *a1; *a1++ = *a2; *a2++ = temp; }
+      }
+
+      Real diag = *akk; big = 0; mu = k + 1;
+      if (diag != 0)
+      {
+         ai = akk; int i = nrows_val - k - 1;
+         while (i--)
+         {
+            ai += nrows_val; Real* al = ai;
+            Real mult = *al / diag; *al = mult;
+            int l = nrows_val - k - 1; Real* aj = akk;
+            // work out the next pivot as part of this loop
+            // this saves a column operation
+            if (l-- != 0)
+            {
+               *(++al) -= (mult * *(++aj));
+               const Real trybig = fabs(*al);
+               if (big < trybig) { big = trybig; mu = nrows_val - i - 1; }
+               while (l--) *(++al) -= (mult * *(++aj));
+            }
+         }
+      }
+      else sing = true;
+      if (++k == nrows_val) break;          // so next line won't overflow
+      akk += nrows_val + 1;
+   }
+}
+
+void CroutMatrix::lubksb(Real* B, int mini)
+{
+   REPORT
+   // this has been adapted from Numerical Recipes in C. The code has been
+   // substantially streamlined, so I do not think much of the original
+   // copyright remains. However there is not much opportunity for
+   // variation in the code, so it is still similar to the NR code.
+   // I follow the NR code in skipping over initial zeros in the B vector.
+
+   Tracer tr("Crout(lubksb)");
+   if (sing) Throw(SingularException(*this));
+   int i, j, ii = nrows_val;       // ii initialised : B might be all zeros
+
+
+   // scan for first non-zero in B
+   for (i = 0; i < nrows_val; i++)
+   {
+      int ip = indx[i]; Real temp = B[ip]; B[ip] = B[i]; B[i] = temp;
+      if (temp != 0.0) { ii = i; break; }
+   }
+
+   Real* bi; Real* ai;
+   i = ii + 1;
+
+   if (i < nrows_val)
+   {
+      bi = B + ii; ai = store + ii + i * nrows_val;
+      for (;;)
+      {
+         int ip = indx[i]; Real sum = B[ip]; B[ip] = B[i];
+         Real* aij = ai; Real* bj = bi; j = i - ii;
+         while (j--) sum -= *aij++ * *bj++;
+         B[i] = sum;
+         if (++i == nrows_val) break;
+         ai += nrows_val;
+      }
+   }
+
+   ai = store + nrows_val * nrows_val;
+
+   for (i = nrows_val - 1; i >= mini; i--)
+   {
+      Real* bj = B+i; ai -= nrows_val; Real* ajx = ai+i;
+      Real sum = *bj; Real diag = *ajx;
+      j = nrows_val - i; while(--j) sum -= *(++ajx) * *(++bj);
+      B[i] = sum / diag;
+   }
+}
+
+/****************************** scalar functions ****************************/
+
+inline Real square(Real x) { return x*x; }
+
+Real GeneralMatrix::sum_square() const
+{
+   REPORT
+   Real sum = 0.0; int i = storage; Real* s = store;
+   while (i--) sum += square(*s++);
+   ((GeneralMatrix&)*this).tDelete(); return sum;
+}
+
+Real GeneralMatrix::sum_absolute_value() const
+{
+   REPORT
+   Real sum = 0.0; int i = storage; Real* s = store;
+   while (i--) sum += fabs(*s++);
+   ((GeneralMatrix&)*this).tDelete(); return sum;
+}
+
+Real GeneralMatrix::sum() const
+{
+   REPORT
+   Real sm = 0.0; int i = storage; Real* s = store;
+   while (i--) sm += *s++;
+   ((GeneralMatrix&)*this).tDelete(); return sm;
+}
+
+// maxima and minima
+
+// There are three sets of routines
+// maximum_absolute_value, minimum_absolute_value, maximum, minimum
+// ... these find just the maxima and minima
+// maximum_absolute_value1, minimum_absolute_value1, maximum1, minimum1
+// ... these find the maxima and minima and their locations in a
+//     one dimensional object
+// maximum_absolute_value2, minimum_absolute_value2, maximum2, minimum2
+// ... these find the maxima and minima and their locations in a
+//     two dimensional object
+
+// If the matrix has no values throw an exception
+
+// If we do not want the location find the maximum or minimum on the
+// array stored by GeneralMatrix
+// This won't work for BandMatrices. We call ClearCorner for
+// maximum_absolute_value but for the others use the absolute_minimum_value2
+// version and discard the location.
+
+// For one dimensional objects, when we want the location of the
+// maximum or minimum, work with the array stored by GeneralMatrix
+
+// For two dimensional objects where we want the location of the maximum or
+// minimum proceed as follows:
+
+// For rectangular matrices use the array stored by GeneralMatrix and
+// deduce the location from the location in the GeneralMatrix
+
+// For other two dimensional matrices use the Matrix Row routine to find the
+// maximum or minimum for each row.
+
+static void NullMatrixError(const GeneralMatrix* gm)
+{
+   ((GeneralMatrix&)*gm).tDelete();
+   Throw(ProgramException("Maximum or minimum of null matrix"));
+}
+
+Real GeneralMatrix::maximum_absolute_value() const
+{
+   REPORT
+   if (storage == 0) NullMatrixError(this);
+   Real maxval = 0.0; int l = storage; Real* s = store;
+   while (l--) { Real a = fabs(*s++); if (maxval < a) maxval = a; }
+   ((GeneralMatrix&)*this).tDelete(); return maxval;
+}
+
+Real GeneralMatrix::maximum_absolute_value1(int& i) const
+{
+   REPORT
+   if (storage == 0) NullMatrixError(this);
+   Real maxval = 0.0; int l = storage; Real* s = store; int li = storage;
+   while (l--)
+      { Real a = fabs(*s++); if (maxval <= a) { maxval = a; li = l; }  }
+   i = storage - li;
+   ((GeneralMatrix&)*this).tDelete(); return maxval;
+}
+
+Real GeneralMatrix::minimum_absolute_value() const
+{
+   REPORT
+   if (storage == 0) NullMatrixError(this);
+   int l = storage - 1; Real* s = store; Real minval = fabs(*s++);
+   while (l--) { Real a = fabs(*s++); if (minval > a) minval = a; }
+   ((GeneralMatrix&)*this).tDelete(); return minval;
+}
+
+Real GeneralMatrix::minimum_absolute_value1(int& i) const
+{
+   REPORT
+   if (storage == 0) NullMatrixError(this);
+   int l = storage - 1; Real* s = store; Real minval = fabs(*s++); int li = l;
+   while (l--)
+      { Real a = fabs(*s++); if (minval >= a) { minval = a; li = l; }  }
+   i = storage - li;
+   ((GeneralMatrix&)*this).tDelete(); return minval;
+}
+
+Real GeneralMatrix::maximum() const
+{
+   REPORT
+   if (storage == 0) NullMatrixError(this);
+   int l = storage - 1; Real* s = store; Real maxval = *s++;
+   while (l--) { Real a = *s++; if (maxval < a) maxval = a; }
+   ((GeneralMatrix&)*this).tDelete(); return maxval;
+}
+
+Real GeneralMatrix::maximum1(int& i) const
+{
+   REPORT
+   if (storage == 0) NullMatrixError(this);
+   int l = storage - 1; Real* s = store; Real maxval = *s++; int li = l;
+   while (l--) { Real a = *s++; if (maxval <= a) { maxval = a; li = l; } }
+   i = storage - li;
+   ((GeneralMatrix&)*this).tDelete(); return maxval;
+}
+
+Real GeneralMatrix::minimum() const
+{
+   REPORT
+   if (storage == 0) NullMatrixError(this);
+   int l = storage - 1; Real* s = store; Real minval = *s++;
+   while (l--) { Real a = *s++; if (minval > a) minval = a; }
+   ((GeneralMatrix&)*this).tDelete(); return minval;
+}
+
+Real GeneralMatrix::minimum1(int& i) const
+{
+   REPORT
+   if (storage == 0) NullMatrixError(this);
+   int l = storage - 1; Real* s = store; Real minval = *s++; int li = l;
+   while (l--) { Real a = *s++; if (minval >= a) { minval = a; li = l; } }
+   i = storage - li;
+   ((GeneralMatrix&)*this).tDelete(); return minval;
+}
+
+Real GeneralMatrix::maximum_absolute_value2(int& i, int& j) const
+{
+   REPORT
+   if (storage == 0) NullMatrixError(this);
+   Real maxval = 0.0; int nr = Nrows();
+   MatrixRow mr((GeneralMatrix*)this, LoadOnEntry+DirectPart);
+   for (int r = 1; r <= nr; r++)
+   {
+      int c; maxval = mr.MaximumAbsoluteValue1(maxval, c);
+      if (c > 0) { i = r; j = c; }
+      mr.Next();
+   }
+   ((GeneralMatrix&)*this).tDelete(); return maxval;
+}
+
+Real GeneralMatrix::minimum_absolute_value2(int& i, int& j) const
+{
+   REPORT
+   if (storage == 0)  NullMatrixError(this);
+   Real minval = FloatingPointPrecision::Maximum(); int nr = Nrows();
+   MatrixRow mr((GeneralMatrix*)this, LoadOnEntry+DirectPart);
+   for (int r = 1; r <= nr; r++)
+   {
+      int c; minval = mr.MinimumAbsoluteValue1(minval, c);
+      if (c > 0) { i = r; j = c; }
+      mr.Next();
+   }
+   ((GeneralMatrix&)*this).tDelete(); return minval;
+}
+
+Real GeneralMatrix::maximum2(int& i, int& j) const
+{
+   REPORT
+   if (storage == 0) NullMatrixError(this);
+   Real maxval = -FloatingPointPrecision::Maximum(); int nr = Nrows();
+   MatrixRow mr((GeneralMatrix*)this, LoadOnEntry+DirectPart);
+   for (int r = 1; r <= nr; r++)
+   {
+      int c; maxval = mr.Maximum1(maxval, c);
+      if (c > 0) { i = r; j = c; }
+      mr.Next();
+   }
+   ((GeneralMatrix&)*this).tDelete(); return maxval;
+}
+
+Real GeneralMatrix::minimum2(int& i, int& j) const
+{
+   REPORT
+   if (storage == 0) NullMatrixError(this);
+   Real minval = FloatingPointPrecision::Maximum(); int nr = Nrows();
+   MatrixRow mr((GeneralMatrix*)this, LoadOnEntry+DirectPart);
+   for (int r = 1; r <= nr; r++)
+   {
+      int c; minval = mr.Minimum1(minval, c);
+      if (c > 0) { i = r; j = c; }
+      mr.Next();
+   }
+   ((GeneralMatrix&)*this).tDelete(); return minval;
+}
+
+Real Matrix::maximum_absolute_value2(int& i, int& j) const
+{
+   REPORT
+   int k; Real m = GeneralMatrix::maximum_absolute_value1(k); k--;
+   i = k / Ncols(); j = k - i * Ncols(); i++; j++;
+   return m;
+}
+
+Real Matrix::minimum_absolute_value2(int& i, int& j) const
+{
+   REPORT
+   int k; Real m = GeneralMatrix::minimum_absolute_value1(k); k--;
+   i = k / Ncols(); j = k - i * Ncols(); i++; j++;
+   return m;
+}
+
+Real Matrix::maximum2(int& i, int& j) const
+{
+   REPORT
+   int k; Real m = GeneralMatrix::maximum1(k); k--;
+   i = k / Ncols(); j = k - i * Ncols(); i++; j++;
+   return m;
+}
+
+Real Matrix::minimum2(int& i, int& j) const
+{
+   REPORT
+   int k; Real m = GeneralMatrix::minimum1(k); k--;
+   i = k / Ncols(); j = k - i * Ncols(); i++; j++;
+   return m;
+}
+
+Real SymmetricMatrix::sum_square() const
+{
+   REPORT
+   Real sum1 = 0.0; Real sum2 = 0.0; Real* s = store; int nr = nrows_val;
+   for (int i = 0; i<nr; i++)
+   {
+      int j = i;
+      while (j--) sum2 += square(*s++);
+      sum1 += square(*s++);
+   }
+   ((GeneralMatrix&)*this).tDelete(); return sum1 + 2.0 * sum2;
+}
+
+Real SymmetricMatrix::sum_absolute_value() const
+{
+   REPORT
+   Real sum1 = 0.0; Real sum2 = 0.0; Real* s = store; int nr = nrows_val;
+   for (int i = 0; i<nr; i++)
+   {
+      int j = i;
+      while (j--) sum2 += fabs(*s++);
+      sum1 += fabs(*s++);
+   }
+   ((GeneralMatrix&)*this).tDelete(); return sum1 + 2.0 * sum2;
+}
+
+Real IdentityMatrix::sum_absolute_value() const
+   { REPORT  return fabs(trace()); }    // no need to do tDelete?
+
+Real SymmetricMatrix::sum() const
+{
+   REPORT
+   Real sum1 = 0.0; Real sum2 = 0.0; Real* s = store; int nr = nrows_val;
+   for (int i = 0; i<nr; i++)
+   {
+      int j = i;
+      while (j--) sum2 += *s++;
+      sum1 += *s++;
+   }
+   ((GeneralMatrix&)*this).tDelete(); return sum1 + 2.0 * sum2;
+}
+
+Real IdentityMatrix::sum_square() const
+{
+   Real sum = *store * *store * nrows_val;
+   ((GeneralMatrix&)*this).tDelete(); return sum;
+}
+
+
+Real BaseMatrix::sum_square() const
+{
+   REPORT GeneralMatrix* gm = ((BaseMatrix&)*this).Evaluate();
+   Real s = gm->sum_square(); return s;
+}
+
+Real BaseMatrix::norm_Frobenius() const
+   { REPORT  return sqrt(sum_square()); }
+
+Real BaseMatrix::sum_absolute_value() const
+{
+   REPORT GeneralMatrix* gm = ((BaseMatrix&)*this).Evaluate();
+   Real s = gm->sum_absolute_value(); return s;
+}
+
+Real BaseMatrix::sum() const
+{
+   REPORT GeneralMatrix* gm = ((BaseMatrix&)*this).Evaluate();
+   Real s = gm->sum(); return s;
+}
+
+Real BaseMatrix::maximum_absolute_value() const
+{
+   REPORT GeneralMatrix* gm = ((BaseMatrix&)*this).Evaluate();
+   Real s = gm->maximum_absolute_value(); return s;
+}
+
+Real BaseMatrix::maximum_absolute_value1(int& i) const
+{
+   REPORT GeneralMatrix* gm = ((BaseMatrix&)*this).Evaluate();
+   Real s = gm->maximum_absolute_value1(i); return s;
+}
+
+Real BaseMatrix::maximum_absolute_value2(int& i, int& j) const
+{
+   REPORT GeneralMatrix* gm = ((BaseMatrix&)*this).Evaluate();
+   Real s = gm->maximum_absolute_value2(i, j); return s;
+}
+
+Real BaseMatrix::minimum_absolute_value() const
+{
+   REPORT GeneralMatrix* gm = ((BaseMatrix&)*this).Evaluate();
+   Real s = gm->minimum_absolute_value(); return s;
+}
+
+Real BaseMatrix::minimum_absolute_value1(int& i) const
+{
+   REPORT GeneralMatrix* gm = ((BaseMatrix&)*this).Evaluate();
+   Real s = gm->minimum_absolute_value1(i); return s;
+}
+
+Real BaseMatrix::minimum_absolute_value2(int& i, int& j) const
+{
+   REPORT GeneralMatrix* gm = ((BaseMatrix&)*this).Evaluate();
+   Real s = gm->minimum_absolute_value2(i, j); return s;
+}
+
+Real BaseMatrix::maximum() const
+{
+   REPORT GeneralMatrix* gm = ((BaseMatrix&)*this).Evaluate();
+   Real s = gm->maximum(); return s;
+}
+
+Real BaseMatrix::maximum1(int& i) const
+{
+   REPORT GeneralMatrix* gm = ((BaseMatrix&)*this).Evaluate();
+   Real s = gm->maximum1(i); return s;
+}
+
+Real BaseMatrix::maximum2(int& i, int& j) const
+{
+   REPORT GeneralMatrix* gm = ((BaseMatrix&)*this).Evaluate();
+   Real s = gm->maximum2(i, j); return s;
+}
+
+Real BaseMatrix::minimum() const
+{
+   REPORT GeneralMatrix* gm = ((BaseMatrix&)*this).Evaluate();
+   Real s = gm->minimum(); return s;
+}
+
+Real BaseMatrix::minimum1(int& i) const
+{
+   REPORT GeneralMatrix* gm = ((BaseMatrix&)*this).Evaluate();
+   Real s = gm->minimum1(i); return s;
+}
+
+Real BaseMatrix::minimum2(int& i, int& j) const
+{
+   REPORT GeneralMatrix* gm = ((BaseMatrix&)*this).Evaluate();
+   Real s = gm->minimum2(i, j); return s;
+}
+
+Real dotproduct(const Matrix& A, const Matrix& B)
+{
+   REPORT
+   int n = A.storage;
+   if (n != B.storage)
+   {
+      Tracer tr("dotproduct");
+      Throw(IncompatibleDimensionsException(A,B));
+   }
+   Real sum = 0.0; Real* a = A.store; Real* b = B.store;
+   while (n--) sum += *a++ * *b++;
+   return sum;
+}
+
+Real Matrix::trace() const
+{
+   REPORT
+   Tracer tr("trace");
+   int i = nrows_val; int d = i+1;
+   if (i != ncols_val) Throw(NotSquareException(*this));
+   Real sum = 0.0; Real* s = store;
+//   while (i--) { sum += *s; s += d; }
+   if (i) for (;;) { sum += *s; if (!(--i)) break; s += d; }
+   ((GeneralMatrix&)*this).tDelete(); return sum;
+}
+
+Real DiagonalMatrix::trace() const
+{
+   REPORT
+   int i = nrows_val; Real sum = 0.0; Real* s = store;
+   while (i--) sum += *s++;
+   ((GeneralMatrix&)*this).tDelete(); return sum;
+}
+
+Real SymmetricMatrix::trace() const
+{
+   REPORT
+   int i = nrows_val; Real sum = 0.0; Real* s = store; int j = 2;
+   // while (i--) { sum += *s; s += j++; }
+   if (i) for (;;) { sum += *s; if (!(--i)) break; s += j++; }
+   ((GeneralMatrix&)*this).tDelete(); return sum;
+}
+
+Real LowerTriangularMatrix::trace() const
+{
+   REPORT
+   int i = nrows_val; Real sum = 0.0; Real* s = store; int j = 2;
+   // while (i--) { sum += *s; s += j++; }
+   if (i) for (;;) { sum += *s; if (!(--i)) break; s += j++; }
+   ((GeneralMatrix&)*this).tDelete(); return sum;
+}
+
+Real UpperTriangularMatrix::trace() const
+{
+   REPORT
+   int i = nrows_val; Real sum = 0.0; Real* s = store;
+   while (i) { sum += *s; s += i--; }             // won t cause a problem
+   ((GeneralMatrix&)*this).tDelete(); return sum;
+}
+
+Real BandMatrix::trace() const
+{
+   REPORT
+   int i = nrows_val; int w = lower_val+upper_val+1;
+   Real sum = 0.0; Real* s = store+lower_val;
+   // while (i--) { sum += *s; s += w; }
+   if (i) for (;;) { sum += *s; if (!(--i)) break; s += w; }
+   ((GeneralMatrix&)*this).tDelete(); return sum;
+}
+
+Real SymmetricBandMatrix::trace() const
+{
+   REPORT
+   int i = nrows_val; int w = lower_val+1;
+   Real sum = 0.0; Real* s = store+lower_val;
+   // while (i--) { sum += *s; s += w; }
+   if (i) for (;;) { sum += *s; if (!(--i)) break; s += w; }
+   ((GeneralMatrix&)*this).tDelete(); return sum;
+}
+
+Real IdentityMatrix::trace() const
+{
+   Real sum = *store * nrows_val;
+   ((GeneralMatrix&)*this).tDelete(); return sum;
+}
+
+
+Real BaseMatrix::trace() const
+{
+   REPORT
+   MatrixType Diag = MatrixType::Dg; Diag.SetDataLossOK();
+   GeneralMatrix* gm = ((BaseMatrix&)*this).Evaluate(Diag);
+   Real sum = gm->trace(); return sum;
+}
+
+void LogAndSign::operator*=(Real x)
+{
+   if (x > 0.0) { log_val += log(x); }
+   else if (x < 0.0) { log_val += log(-x); sign_val = -sign_val; }
+   else sign_val = 0;
+}
+
+void LogAndSign::pow_eq(int k)
+{
+   if (sign_val)
+   {
+      log_val *= k;
+      if ( (k & 1) == 0 ) sign_val = 1;
+   }
+}
+
+Real LogAndSign::value() const
+{
+   Tracer et("LogAndSign::value");
+   if (log_val >= FloatingPointPrecision::LnMaximum())
+      Throw(OverflowException("Overflow in exponential"));
+   return sign_val * exp(log_val);
+}
+
+LogAndSign::LogAndSign(Real f)
+{
+   if (f == 0.0) { log_val = 0.0; sign_val = 0; return; }
+   else if (f < 0.0) { sign_val = -1; f = -f; }
+   else sign_val = 1;
+   log_val = log(f);
+}
+
+LogAndSign DiagonalMatrix::log_determinant() const
+{
+   REPORT
+   int i = nrows_val; LogAndSign sum; Real* s = store;
+   while (i--) sum *= *s++;
+   ((GeneralMatrix&)*this).tDelete(); return sum;
+}
+
+LogAndSign LowerTriangularMatrix::log_determinant() const
+{
+   REPORT
+   int i = nrows_val; LogAndSign sum; Real* s = store; int j = 2;
+   // while (i--) { sum *= *s; s += j++; }
+   if (i) for(;;) { sum *= *s; if (!(--i)) break; s += j++; }
+   ((GeneralMatrix&)*this).tDelete(); return sum;
+}
+
+LogAndSign UpperTriangularMatrix::log_determinant() const
+{
+   REPORT
+   int i = nrows_val; LogAndSign sum; Real* s = store;
+   while (i) { sum *= *s; s += i--; }
+   ((GeneralMatrix&)*this).tDelete(); return sum;
+}
+
+LogAndSign IdentityMatrix::log_determinant() const
+{
+   REPORT
+   int i = nrows_val; LogAndSign sum;
+   if (i > 0) { sum = *store; sum.PowEq(i); }
+   ((GeneralMatrix&)*this).tDelete(); return sum;
+}
+
+LogAndSign BaseMatrix::log_determinant() const
+{
+   REPORT GeneralMatrix* gm = ((BaseMatrix&)*this).Evaluate();
+   LogAndSign sum = gm->log_determinant(); return sum;
+}
+
+LogAndSign GeneralMatrix::log_determinant() const
+{
+   REPORT
+   Tracer tr("log_determinant");
+   if (nrows_val != ncols_val) Throw(NotSquareException(*this));
+   CroutMatrix C(*this); return C.log_determinant();
+}
+
+LogAndSign CroutMatrix::log_determinant() const
+{
+   REPORT
+   if (sing) return 0.0;
+   int i = nrows_val; int dd = i+1; LogAndSign sum; Real* s = store;
+   if (i) for(;;)
+   {
+      sum *= *s;
+      if (!(--i)) break;
+      s += dd;
+   }
+   if (!d) sum.ChangeSign(); return sum;
+
+}
+
+Real BaseMatrix::determinant() const
+{
+   REPORT
+   Tracer tr("determinant");
+   REPORT GeneralMatrix* gm = ((BaseMatrix&)*this).Evaluate();
+   LogAndSign ld = gm->log_determinant();
+   return ld.Value();
+}
+
+LinearEquationSolver::LinearEquationSolver(const BaseMatrix& bm)
+{
+   gm = ( ((BaseMatrix&)bm).Evaluate() )->MakeSolver();
+   if (gm==&bm) { REPORT  gm = gm->Image(); }
+   // want a copy if  *gm is actually bm
+   else { REPORT  gm->Protect(); }
+}
+
+ReturnMatrix BaseMatrix::sum_square_rows() const
+{
+   REPORT
+   GeneralMatrix* gm = ((BaseMatrix&)*this).Evaluate();
+   int nr = gm->nrows();
+   ColumnVector ssq(nr);
+   if (gm->size() == 0) { REPORT ssq = 0.0; }
+   else
+   {
+      MatrixRow mr(gm, LoadOnEntry);
+      for (int i = 1; i <= nr; ++i)
+      {
+         Real sum = 0.0;
+         int s = mr.Storage();
+         Real* in = mr.Data();
+         while (s--) sum += square(*in++);
+         ssq(i) = sum;   
+         mr.Next();
+      }
+   }
+   gm->tDelete();
+   ssq.release(); return ssq.for_return();
+}
+
+ReturnMatrix BaseMatrix::sum_square_columns() const
+{
+   REPORT
+   GeneralMatrix* gm = ((BaseMatrix&)*this).Evaluate();
+   int nr = gm->nrows(); int nc = gm->ncols();
+   RowVector ssq(nc); ssq = 0.0;
+   if (gm->size() != 0)
+   {
+      MatrixRow mr(gm, LoadOnEntry);
+      for (int i = 1; i <= nr; ++i)
+      {
+         int s = mr.Storage();
+         Real* in = mr.Data(); Real* out = ssq.data() + mr.Skip();
+         while (s--) *out++ += square(*in++);
+         mr.Next();
+      }
+   }
+   gm->tDelete();
+   ssq.release(); return ssq.for_return();
+}
+
+ReturnMatrix BaseMatrix::sum_rows() const
+{
+   REPORT
+   GeneralMatrix* gm = ((BaseMatrix&)*this).Evaluate();
+   int nr = gm->nrows();
+   ColumnVector sum_vec(nr);
+   if (gm->size() == 0) { REPORT sum_vec = 0.0; }
+   else
+   {
+      MatrixRow mr(gm, LoadOnEntry);
+      for (int i = 1; i <= nr; ++i)
+      {
+         Real sum = 0.0;
+         int s = mr.Storage();
+         Real* in = mr.Data();
+         while (s--) sum += *in++;
+         sum_vec(i) = sum;   
+         mr.Next();
+      }
+   }
+   gm->tDelete();
+   sum_vec.release(); return sum_vec.for_return();
+}
+
+ReturnMatrix BaseMatrix::sum_columns() const
+{
+   REPORT
+   GeneralMatrix* gm = ((BaseMatrix&)*this).Evaluate();
+   int nr = gm->nrows(); int nc = gm->ncols();
+   RowVector sum_vec(nc); sum_vec = 0.0;
+   if (gm->size() != 0)
+   {
+      MatrixRow mr(gm, LoadOnEntry);
+      for (int i = 1; i <= nr; ++i)
+      {
+         int s = mr.Storage();
+         Real* in = mr.Data(); Real* out = sum_vec.data() + mr.Skip();
+         while (s--) *out++ += *in++;
+         mr.Next();
+      }
+   }
+   gm->tDelete();
+   sum_vec.release(); return sum_vec.for_return();
+}
+
+
+#ifdef use_namespace
+}
+#endif
+
+
+///}
Index: /nanovis/tags/1.1.4/newmat11/newmat9.cpp
===================================================================
--- /nanovis/tags/1.1.4/newmat11/newmat9.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/newmat11/newmat9.cpp	(revision 4930)
@@ -0,0 +1,81 @@
+/// \ingroup newmat
+///@{
+
+/// \file newmat9.cpp
+/// Output.
+
+// Copyright (C) 1991,2,3,4: R B Davies
+
+
+#define WANT_FSTREAM
+
+#include "include.h"
+
+#include "newmat.h"
+#include "newmatio.h"
+#include "newmatrc.h"
+
+#ifdef use_namespace
+namespace NEWMAT {
+#endif
+
+
+
+#ifdef DO_REPORT
+#define REPORT { static ExeCounter ExeCount(__LINE__,9); ++ExeCount; }
+#else
+#define REPORT {}
+#endif
+
+// for G++ 3.01
+#ifndef ios_format_flags
+#define ios_format_flags long
+#endif
+
+ostream& operator<<(ostream& s, const BaseMatrix& X)
+{
+   GeneralMatrix* gm = ((BaseMatrix&)X).Evaluate(); operator<<(s, *gm);
+   gm->tDelete(); return s;
+}
+
+
+ostream& operator<<(ostream& s, const GeneralMatrix& X)
+{
+   MatrixRow mr((GeneralMatrix*)&X, LoadOnEntry);
+   int w = s.width();  int nr = X.Nrows();  ios_format_flags f = s.flags();
+   s.setf(ios::fixed, ios::floatfield);
+   for (int i=1; i<=nr; i++)
+   {
+      int skip = mr.skip;  int storage = mr.storage;
+      Real* store = mr.data;  skip *= w+1;
+      while (skip--) s << " ";
+      while (storage--) { s.width(w); s << *store++ << " "; }
+//      while (storage--) s << setw(w) << *store++ << " ";
+      mr.Next();  s << "\n";
+   }
+   s << flush;  s.flags(f); return s;
+}
+
+// include this stuff if you are using an old version of G++
+// with an incomplete io library
+
+/*
+
+ostream& operator<<(ostream& os, Omanip_precision i)
+   { os.precision(i.x); return os; }
+
+Omanip_precision setprecision(int i) { return Omanip_precision(i); }
+
+ostream& operator<<(ostream& os, Omanip_width i)
+   { os.width(i.x); return os; }
+
+Omanip_width setw(int i) { return Omanip_width(i); }
+
+*/
+
+#ifdef use_namespace
+}
+#endif
+
+
+///@}
Index: /nanovis/tags/1.1.4/newmat11/newmatap.h
===================================================================
--- /nanovis/tags/1.1.4/newmat11/newmatap.h	(revision 4930)
+++ /nanovis/tags/1.1.4/newmat11/newmatap.h	(revision 4930)
@@ -0,0 +1,250 @@
+/// \ingroup newmat
+///@{
+
+/// \file newmatap.h
+/// Definition file for advanced matrix functions.
+
+// Copyright (C) 1991,2,3,4,8: R B Davies
+
+#ifndef NEWMATAP_LIB
+#define NEWMATAP_LIB 0
+
+#include "newmat.h"
+
+#ifdef use_namespace
+namespace NEWMAT {
+#endif
+
+
+// ************************** applications *****************************/
+
+
+void QRZT(Matrix&, LowerTriangularMatrix&);
+
+void QRZT(const Matrix&, Matrix&, Matrix&);
+
+void QRZ(Matrix&, UpperTriangularMatrix&);
+
+void QRZ(const Matrix&, Matrix&, Matrix&);
+
+inline void HHDecompose(Matrix& X, LowerTriangularMatrix& L)
+{ QRZT(X,L); }
+
+inline void HHDecompose(const Matrix& X, Matrix& Y, Matrix& M)
+{ QRZT(X, Y, M); }
+
+void updateQRZT(Matrix& X, LowerTriangularMatrix& L);
+
+void updateQRZ(Matrix& X, UpperTriangularMatrix& U);
+
+inline void UpdateQRZT(Matrix& X, LowerTriangularMatrix& L)
+   { updateQRZT(X, L); }
+
+inline void UpdateQRZ(Matrix& X, UpperTriangularMatrix& U)
+   { updateQRZ(X, U); }
+
+// Matrix A's first n columns are orthonormal
+// so A.Columns(1,n).t() * A.Columns(1,n) is the identity matrix.
+// Fill out the remaining columns of A to make them orthonormal
+// so A.t() * A is the identity matrix 
+void extend_orthonormal(Matrix& A, int n);
+
+
+ReturnMatrix Cholesky(const SymmetricMatrix&);
+
+ReturnMatrix Cholesky(const SymmetricBandMatrix&);
+
+
+// produces the Cholesky decomposition of A + x.t() * x where A = chol.t() * chol
+// and x is a RowVector
+void update_Cholesky(UpperTriangularMatrix& chol, RowVector x);
+inline void UpdateCholesky(UpperTriangularMatrix& chol, const RowVector& x)
+   { update_Cholesky(chol, x); }
+
+// produces the Cholesky decomposition of A - x.t() * x where A = chol.t() * chol
+// and x is a RowVector
+void downdate_Cholesky(UpperTriangularMatrix &chol, RowVector x);
+inline void DowndateCholesky(UpperTriangularMatrix &chol, const RowVector& x)
+   { downdate_Cholesky(chol, x); }
+
+// a RIGHT circular shift of the rows and columns from
+// 1,...,k-1,k,k+1,...l,l+1,...,p to
+// 1,...,k-1,l,k,k+1,...l-1,l+1,...p
+void right_circular_update_Cholesky(UpperTriangularMatrix &chol, int k, int l);
+inline void RightCircularUpdateCholesky(UpperTriangularMatrix &chol,
+  int k, int l) { right_circular_update_Cholesky(chol, k, l); }
+
+// a LEFT circular shift of the rows and columns from
+// 1,...,k-1,k,k+1,...l,l+1,...,p to
+// 1,...,k-1,k+1,...l,k,l+1,...,p to
+void left_circular_update_Cholesky(UpperTriangularMatrix &chol, int k, int l); 
+inline void LeftCircularUpdateCholesky(UpperTriangularMatrix &chol,
+   int k, int l) { left_circular_update_Cholesky(chol, k, l); } 
+
+
+void SVD(const Matrix&, DiagonalMatrix&, Matrix&, Matrix&,
+    bool=true, bool=true);
+
+void SVD(const Matrix&, DiagonalMatrix&);
+
+inline void SVD(const Matrix& A, DiagonalMatrix& D, Matrix& U,
+   bool withU = true) { SVD(A, D, U, U, withU, false); }
+
+void SortSV(DiagonalMatrix& D, Matrix& U, bool ascending = false);
+
+void SortSV(DiagonalMatrix& D, Matrix& U, Matrix& V, bool ascending = false);
+
+void Jacobi(const SymmetricMatrix&, DiagonalMatrix&);
+
+void Jacobi(const SymmetricMatrix&, DiagonalMatrix&, SymmetricMatrix&);
+
+void Jacobi(const SymmetricMatrix&, DiagonalMatrix&, Matrix&);
+
+void Jacobi(const SymmetricMatrix&, DiagonalMatrix&, SymmetricMatrix&,
+   Matrix&, bool=true);
+
+void eigenvalues(const SymmetricMatrix&, DiagonalMatrix&);
+
+void eigenvalues(const SymmetricMatrix&, DiagonalMatrix&, SymmetricMatrix&);
+
+void eigenvalues(const SymmetricMatrix&, DiagonalMatrix&, Matrix&);
+
+inline void EigenValues(const SymmetricMatrix& A, DiagonalMatrix& D)
+   { eigenvalues(A, D); }
+
+inline void EigenValues(const SymmetricMatrix& A, DiagonalMatrix& D,
+   SymmetricMatrix& S) { eigenvalues(A, D, S); }
+
+inline void EigenValues(const SymmetricMatrix& A, DiagonalMatrix& D, Matrix& V)
+   { eigenvalues(A, D, V); }
+
+class SymmetricEigenAnalysis
+// not implemented yet
+{
+public:
+   SymmetricEigenAnalysis(const SymmetricMatrix&);
+private:
+   DiagonalMatrix diag;
+   DiagonalMatrix offdiag;
+   SymmetricMatrix backtransform;
+   FREE_CHECK(SymmetricEigenAnalysis)
+};
+
+void sort_ascending(GeneralMatrix&);
+
+void sort_descending(GeneralMatrix&);
+
+inline void SortAscending(GeneralMatrix& gm) { sort_ascending(gm); }
+
+inline void SortDescending(GeneralMatrix& gm) { sort_descending(gm); }
+
+/// Decide which fft method to use and carry out new fft function
+class FFT_Controller
+{
+public:
+   static bool OnlyOldFFT;
+   static bool ar_1d_ft (int PTS, Real* X, Real *Y);
+   static bool CanFactor(int PTS);
+};
+
+void FFT(const ColumnVector&, const ColumnVector&,
+   ColumnVector&, ColumnVector&);
+
+void FFTI(const ColumnVector&, const ColumnVector&,
+   ColumnVector&, ColumnVector&);
+
+void RealFFT(const ColumnVector&, ColumnVector&, ColumnVector&);
+
+void RealFFTI(const ColumnVector&, const ColumnVector&, ColumnVector&);
+
+void DCT_II(const ColumnVector&, ColumnVector&);
+
+void DCT_II_inverse(const ColumnVector&, ColumnVector&);
+
+void DST_II(const ColumnVector&, ColumnVector&);
+
+void DST_II_inverse(const ColumnVector&, ColumnVector&);
+
+void DCT(const ColumnVector&, ColumnVector&);
+
+void DCT_inverse(const ColumnVector&, ColumnVector&);
+
+void DST(const ColumnVector&, ColumnVector&);
+
+void DST_inverse(const ColumnVector&, ColumnVector&);
+
+void FFT2(const Matrix& U, const Matrix& V, Matrix& X, Matrix& Y);
+
+void FFT2I(const Matrix& U, const Matrix& V, Matrix& X, Matrix& Y);
+
+
+// This class is used by the new FFT program
+
+// Suppose an integer is expressed as a sequence of digits with each
+// digit having a different radix.
+// This class supposes we are counting with this multi-radix number
+// but also keeps track of the number with the digits (and radices)
+// reversed.
+// The integer starts at zero
+// operator++() increases it by 1
+// Counter gives the number of increments
+// Reverse() gives the value with the digits in reverse order
+// Swap is true if reverse is less than counter
+// Finish is true when we have done a complete cycle and are back at zero
+
+class MultiRadixCounter
+{
+   const SimpleIntArray& Radix;
+                              // radix of each digit
+                              // n-1 highest order, 0 lowest order
+   SimpleIntArray& Value;     // value of each digit
+   const int n;               // number of digits
+   int reverse;               // value when order of digits is reversed
+   int product;               // product of radices
+   int counter;               // counter
+   bool finish;               // true when we have gone over whole range
+public:
+   MultiRadixCounter(int nx, const SimpleIntArray& rx,
+      SimpleIntArray& vx);
+   void operator++();         // increment the multi-radix counter
+   bool Swap() const { return reverse < counter; }
+   bool Finish() const { return finish; }
+   int Reverse() const { return reverse; }
+   int Counter() const { return counter; }
+};
+
+// multiplication by Helmert matrix
+ReturnMatrix Helmert(int n, bool full=false);
+ReturnMatrix Helmert(const ColumnVector& X, bool full=false);
+ReturnMatrix Helmert(int n, int j, bool full=false);
+ReturnMatrix Helmert_transpose(const ColumnVector& Y, bool full=false);
+Real Helmert_transpose(const ColumnVector& Y, int j, bool full=false);
+ReturnMatrix Helmert(const Matrix& X, bool full=false);
+ReturnMatrix Helmert_transpose(const Matrix& Y, bool full=false);
+
+
+
+
+#ifdef use_namespace
+}
+#endif
+
+
+
+#endif
+
+// body file: cholesky.cpp
+// body file: evalue.cpp
+// body file: fft.cpp
+// body file: hholder.cpp
+// body file: jacobi.cpp
+// body file: newfft.cpp
+// body file: sort.cpp
+// body file: svd.cpp
+// body file: nm_misc.cpp
+
+
+
+///@}
+
+
Index: /nanovis/tags/1.1.4/newmat11/newmatex.cpp
===================================================================
--- /nanovis/tags/1.1.4/newmat11/newmatex.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/newmat11/newmatex.cpp	(revision 4930)
@@ -0,0 +1,325 @@
+/// \file newmatex.cpp
+/// \brief Exceptions thrown by matrix library.
+
+// Copyright (C) 1992,3,4,7: R B Davies
+
+#define WANT_STREAM                  // include.h will get stream fns
+
+#include "include.h"                 // include standard files
+#include "newmat.h"
+
+#ifdef use_namespace
+namespace NEWMAT {
+#endif
+
+unsigned long OverflowException::Select;
+unsigned long SingularException::Select;
+unsigned long NPDException::Select;
+unsigned long ConvergenceException::Select;
+unsigned long ProgramException::Select;
+unsigned long IndexException::Select;
+unsigned long VectorException::Select;
+unsigned long NotSquareException::Select;
+unsigned long SubMatrixDimensionException::Select;
+unsigned long IncompatibleDimensionsException::Select;
+unsigned long NotDefinedException::Select;
+unsigned long CannotBuildException::Select;
+unsigned long InternalException::Select;
+
+
+
+static void MatrixDetails(const GeneralMatrix& A)
+// write matrix details to Exception buffer
+{
+   MatrixBandWidth bw = A.bandwidth();
+   int ubw = bw.upper_val; int lbw = bw.lower_val;
+   BaseException::AddMessage("MatrixType = ");
+   BaseException::AddMessage(A.Type().Value());
+   BaseException::AddMessage("  # Rows = "); BaseException::AddInt(A.Nrows());
+   BaseException::AddMessage("; # Cols = "); BaseException::AddInt(A.Ncols());
+   if (lbw >=0)
+   {
+      BaseException::AddMessage("; lower BW = ");
+      BaseException::AddInt(lbw);
+   }
+   if (ubw >=0)
+   {
+      BaseException::AddMessage("; upper BW = ");
+      BaseException::AddInt(ubw);
+   }
+   BaseException::AddMessage("\n");
+}
+
+NPDException::NPDException(const GeneralMatrix& A)
+   : Runtime_error()
+{
+   Select = BaseException::Select;
+   AddMessage("detected by Newmat: matrix not positive definite\n\n");
+   MatrixDetails(A);
+   Tracer::AddTrace();
+}
+
+SingularException::SingularException(const GeneralMatrix& A)
+   : Runtime_error()
+{
+   Select = BaseException::Select;
+   AddMessage("detected by Newmat: matrix is singular\n\n");
+   MatrixDetails(A);
+   Tracer::AddTrace();
+}
+
+ConvergenceException::ConvergenceException(const GeneralMatrix& A)
+   : Runtime_error()
+{
+   Select = BaseException::Select;
+   AddMessage("detected by Newmat: process fails to converge\n\n");
+   MatrixDetails(A);
+   Tracer::AddTrace();
+}
+
+ConvergenceException::ConvergenceException(const char* c) : Runtime_error()
+{
+   Select = BaseException::Select;
+   AddMessage("detected by Newmat: ");
+   AddMessage(c); AddMessage("\n\n");
+   if (c) Tracer::AddTrace();
+}
+
+OverflowException::OverflowException(const char* c) : Runtime_error()
+{
+   Select = BaseException::Select;
+   AddMessage("detected by Newmat: ");
+   AddMessage(c); AddMessage("\n\n");
+   if (c) Tracer::AddTrace();
+}
+
+ProgramException::ProgramException(const char* c) : Logic_error()
+{
+   Select = BaseException::Select;
+   AddMessage("detected by Newmat: ");
+   AddMessage(c); AddMessage("\n\n");
+   if (c) Tracer::AddTrace();
+}
+
+ProgramException::ProgramException(const char* c, const GeneralMatrix& A)
+   : Logic_error()
+{
+   Select = BaseException::Select;
+   AddMessage("detected by Newmat: ");
+   AddMessage(c); AddMessage("\n\n");
+   MatrixDetails(A);
+   if (c) Tracer::AddTrace();
+}
+
+ProgramException::ProgramException(const char* c, const GeneralMatrix& A,
+   const GeneralMatrix& B) : Logic_error()
+{
+   Select = BaseException::Select;
+   AddMessage("detected by Newmat: ");
+   AddMessage(c); AddMessage("\n\n");
+   MatrixDetails(A); MatrixDetails(B);
+   if (c) Tracer::AddTrace();
+}
+
+ProgramException::ProgramException(const char* c, MatrixType a, MatrixType b)
+   : Logic_error()
+{
+   Select = BaseException::Select;
+   AddMessage("detected by Newmat: ");
+   AddMessage(c); AddMessage("\nMatrixTypes = ");
+   AddMessage(a.Value()); AddMessage("; ");
+   AddMessage(b.Value()); AddMessage("\n\n");
+   if (c) Tracer::AddTrace();
+}
+
+VectorException::VectorException() : Logic_error()
+{
+   Select = BaseException::Select;
+   AddMessage("detected by Newmat: cannot convert matrix to vector\n\n");
+   Tracer::AddTrace();
+}
+
+VectorException::VectorException(const GeneralMatrix& A)
+   : Logic_error()
+{
+   Select = BaseException::Select;
+   AddMessage("detected by Newmat: cannot convert matrix to vector\n\n");
+   MatrixDetails(A);
+   Tracer::AddTrace();
+}
+
+NotSquareException::NotSquareException(const GeneralMatrix& A)
+   : Logic_error()
+{
+   Select = BaseException::Select;
+   AddMessage("detected by Newmat: matrix is not square\n\n");
+   MatrixDetails(A);
+   Tracer::AddTrace();
+}
+
+NotSquareException::NotSquareException()
+   : Logic_error()
+{
+   Select = BaseException::Select;
+   AddMessage("detected by Newmat: matrix is not square\n\n");
+   Tracer::AddTrace();
+}
+
+SubMatrixDimensionException::SubMatrixDimensionException()
+   : Logic_error()
+{
+   Select = BaseException::Select;
+   AddMessage("detected by Newmat: incompatible submatrix dimension\n\n");
+   Tracer::AddTrace();
+}
+
+IncompatibleDimensionsException::IncompatibleDimensionsException()
+   : Logic_error()
+{
+   Select = BaseException::Select;
+   AddMessage("detected by Newmat: incompatible dimensions\n\n");
+   Tracer::AddTrace();
+}
+
+IncompatibleDimensionsException::IncompatibleDimensionsException
+   (const GeneralMatrix& A, const GeneralMatrix& B)
+      : Logic_error()
+{
+   Select = BaseException::Select;
+   AddMessage("detected by Newmat: incompatible dimensions\n\n");
+   MatrixDetails(A); MatrixDetails(B);
+   Tracer::AddTrace();
+}
+
+IncompatibleDimensionsException::IncompatibleDimensionsException
+   (const GeneralMatrix& A)
+      : Logic_error()
+{
+   Select = BaseException::Select;
+   AddMessage("detected by Newmat: incompatible dimensions\n\n");
+   MatrixDetails(A);
+   Tracer::AddTrace();
+}
+
+NotDefinedException::NotDefinedException(const char* op, const char* matrix)
+   : Logic_error()
+{
+   Select = BaseException::Select;
+   AddMessage("detected by Newmat: ");
+   AddMessage(op);
+   AddMessage(" not defined for ");
+   AddMessage(matrix);
+   AddMessage("\n\n");
+   Tracer::AddTrace();
+}
+
+CannotBuildException::CannotBuildException(const char* matrix)
+   : Logic_error()
+{
+   Select = BaseException::Select;
+   AddMessage("detected by Newmat: cannot build matrix type ");
+   AddMessage(matrix); AddMessage("\n\n");
+   Tracer::AddTrace();
+}
+
+IndexException::IndexException(int i, const GeneralMatrix& A)
+   : Logic_error()
+{
+   Select = BaseException::Select;
+   AddMessage("detected by Newmat: index error: requested index = ");
+   AddInt(i); AddMessage("\n\n");
+   MatrixDetails(A);
+   Tracer::AddTrace();
+}
+
+IndexException::IndexException(int i, int j, const GeneralMatrix& A)
+   : Logic_error()
+{
+   Select = BaseException::Select;
+   AddMessage("detected by Newmat: index error: requested indices = ");
+   AddInt(i); AddMessage(", "); AddInt(j);
+   AddMessage("\n\n");
+   MatrixDetails(A);
+   Tracer::AddTrace();
+}
+
+
+IndexException::IndexException(int i, const GeneralMatrix& A, bool)
+   : Logic_error()
+{
+   Select = BaseException::Select;
+   AddMessage("detected by Newmat: element error: requested index (wrt 0) = ");
+   AddInt(i);
+   AddMessage("\n\n");
+   MatrixDetails(A);
+   Tracer::AddTrace();
+}
+
+IndexException::IndexException(int i, int j, const GeneralMatrix& A, bool)
+   : Logic_error()
+{
+   Select = BaseException::Select;
+   AddMessage(
+      "detected by Newmat: element error: requested indices (wrt 0) = ");
+   AddInt(i); AddMessage(", "); AddInt(j);
+   AddMessage("\n\n");
+   MatrixDetails(A);
+   Tracer::AddTrace();
+}
+
+InternalException::InternalException(const char* c) : Logic_error()
+{
+   Select = BaseException::Select;
+   AddMessage("internal error detected by Newmat: please inform author\n");
+   AddMessage(c); AddMessage("\n\n");
+   Tracer::AddTrace();
+}
+
+
+
+
+/************************* ExeCounter functions *****************************/
+
+#ifdef DO_REPORT
+
+int ExeCounter::nreports;                      // will be set to zero
+
+ExeCounter::ExeCounter(int xl, int xf) : line(xl), fileid(xf), nexe(0) {}
+
+ExeCounter::~ExeCounter()
+{
+   nreports++;
+   cout << "REPORT  " << setw(6) << nreports << "  "
+      << setw(6) << fileid << "  " << setw(6) << line
+      << "  " << setw(6) << nexe << "\n";
+}
+
+#endif
+
+/**************************** error handler *******************************/
+
+void MatrixErrorNoSpace(const void* v) { if (!v) Throw(Bad_alloc()); }
+// throw exception if v is null
+
+
+
+
+/************************* miscellanous errors ***************************/
+
+
+void CroutMatrix::GetRow(MatrixRowCol&)
+   { Throw(NotDefinedException("GetRow","Crout")); }
+void CroutMatrix::GetCol(MatrixRowCol&)
+   { Throw(NotDefinedException("GetCol","Crout")); }
+void BandLUMatrix::GetRow(MatrixRowCol&)
+   { Throw(NotDefinedException("GetRow","BandLUMatrix")); }
+void BandLUMatrix::GetCol(MatrixRowCol&)
+   { Throw(NotDefinedException("GetCol","BandLUMatrix")); }
+void BaseMatrix::IEQND() const
+   { Throw(NotDefinedException("inequalities", "matrices")); }
+
+
+#ifdef use_namespace
+}
+#endif
+
Index: /nanovis/tags/1.1.4/newmat11/newmatio.h
===================================================================
--- /nanovis/tags/1.1.4/newmat11/newmatio.h	(revision 4930)
+++ /nanovis/tags/1.1.4/newmat11/newmatio.h	(revision 4930)
@@ -0,0 +1,67 @@
+/// \ingroup newmat
+///@{
+
+/// \file newmatio.h
+/// Definition file for matrix package output.
+
+// Copyright (C) 1991,2,3,4: R B Davies
+
+#ifndef NEWMATIO_LIB
+#define NEWMATIO_LIB 0
+
+#ifndef WANT_STREAM
+#define WANT_STREAM
+#endif
+
+#include "newmat.h"
+
+#ifdef use_namespace
+namespace NEWMAT {
+#endif
+
+
+
+// **************************** input/output *****************************/
+
+ostream& operator<<(ostream&, const BaseMatrix&);
+
+ostream& operator<<(ostream&, const GeneralMatrix&);
+
+
+/*  Use in some old versions of G++ without complete iomanipulators
+
+class Omanip_precision
+{
+   int x;
+public:
+   Omanip_precision(int i) : x(i) {}
+   friend ostream& operator<<(ostream& os, Omanip_precision i);
+};
+
+
+Omanip_precision setprecision(int i);
+
+class Omanip_width
+{
+   int x;
+public:
+   Omanip_width(int i) : x(i) {}
+   friend ostream& operator<<(ostream& os, Omanip_width i);
+};
+
+Omanip_width setw(int i);
+
+*/
+
+#ifdef use_namespace
+}
+#endif
+
+
+
+#endif
+
+// body file: newmat9.cpp
+
+
+///@}
Index: /nanovis/tags/1.1.4/newmat11/newmatnl.cpp
===================================================================
--- /nanovis/tags/1.1.4/newmat11/newmatnl.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/newmat11/newmatnl.cpp	(revision 4930)
@@ -0,0 +1,266 @@
+/// \ingroup newmat
+///@{
+
+/// \file newmatnl.cpp
+/// Non-linear optimisation.
+
+// Copyright (C) 1993,4,5,6: R B Davies
+
+
+#define WANT_MATH
+#define WANT_STREAM
+
+#include "newmatap.h"
+#include "newmatnl.h"
+
+#ifdef use_namespace
+namespace NEWMAT {
+#endif
+
+
+
+void FindMaximum2::Fit(ColumnVector& Theta, int n_it)
+{
+   Tracer tr("FindMaximum2::Fit");
+   enum State {Start, Restart, Continue, Interpolate, Extrapolate,
+      Fail, Convergence};
+   State TheState = Start;
+   Real z,w,x,x2,g,l1,l2,l3,d1,d2=0,d3;
+   ColumnVector Theta1, Theta2, Theta3;
+   int np = Theta.Nrows();
+   ColumnVector H1(np), H3, HP(np), K, K1(np);
+   bool oorg, conv;
+   int counter = 0;
+   Theta1 = Theta; HP = 0.0; g = 0.0;
+
+   // This is really a set of gotos and labels, but they do not work
+   // correctly in AT&T C++ and Sun 4.01 C++.
+
+   for(;;)
+   {
+      switch (TheState)
+      {
+      case Start:
+	 tr.ReName("FindMaximum2::Fit/Start");
+	 Value(Theta1, true, l1, oorg);
+	 if (oorg) Throw(ProgramException("invalid starting value\n"));
+
+      case Restart:
+	 tr.ReName("FindMaximum2::Fit/ReStart");
+	 conv = NextPoint(H1, d1);
+	 if (conv) { TheState = Convergence; break; }
+	 if (counter++ > n_it) { TheState = Fail; break; }
+
+	 z = 1.0 / sqrt(d1);
+	 H3 = H1 * z; K = (H3 - HP) * g; HP = H3;
+	 g = 0.0;                     // de-activate to use curved projection
+	 if ( g == 0.0 ) K1 = 0.0; else K1 = K * 0.2 + K1 * 0.6;
+	 // (K - K1) * alpha + K1 * (1 - alpha)
+	 //     = K * alpha + K1 * (1 - 2 * alpha)
+	 K = K1 * d1; g = z;
+
+      case Continue:
+	 tr.ReName("FindMaximum2::Fit/Continue");
+	 Theta2 = Theta1 + H1 + K;
+	 Value(Theta2, false, l2, oorg);
+	 if (counter++ > n_it) { TheState = Fail; break; }
+	 if (oorg)
+	 {
+	    H1 *= 0.5; K *= 0.25; d1 *= 0.5; g *= 2.0;
+	    TheState =  Continue; break;
+	 }
+	 d2 = LastDerivative(H1 + K * 2.0);
+
+      case Interpolate:
+	 tr.ReName("FindMaximum2::Fit/Interpolate");
+	 z = d1 + d2 - 3.0 * (l2 - l1);
+	 w = z * z - d1 * d2;
+	 if (w < 0.0) { TheState = Extrapolate; break; }
+	 w = z + sqrt(w);
+	 if (1.5 * w + d1 < 0.0)
+	    { TheState = Extrapolate; break; }
+	 if (d2 > 0.0 && l2 > l1 && w > 0.0)
+	    { TheState = Extrapolate; break; }
+	 x = d1 / (w + d1); x2 = x * x; g /= x;
+	 Theta3 = Theta1 + H1 * x + K * x2;
+	 Value(Theta3, true, l3, oorg);
+	 if (counter++ > n_it) { TheState = Fail; break; }
+	 if (oorg)
+	 {
+	    if (x <= 1.0)
+	       { x *= 0.5; x2 = x*x; g *= 2.0; d1 *= x; H1 *= x; K *= x2; }
+	    else
+	    {
+	       x = 0.5 * (x-1.0); x2 = x*x; Theta1 = Theta2;
+	       H1 = (H1 + K * 2.0) * x;
+	       K *= x2; g = 0.0; d1 = x * d2; l1 = l2;
+	    }
+	    TheState = Continue; break;
+	 }
+
+	 if (l3 >= l1 && l3 >= l2)
+	    { Theta1 = Theta3; l1 = l3; TheState =  Restart; break; }
+
+	 d3 = LastDerivative(H1 + K * 2.0);
+	 if (l1 > l2)
+	    { H1 *= x; K *= x2; Theta2 = Theta3; d1 *= x; d2 = d3*x; }
+	 else
+	 {
+	    Theta1 = Theta2; Theta2 = Theta3;
+	    x -= 1.0; x2 = x*x; g = 0.0; H1 = (H1 + K * 2.0) * x;
+	    K *= x2; l1 = l2; l2 = l3; d1 = x*d2; d2 = x*d3;
+	    if (d1 <= 0.0) { TheState = Start; break; }
+	 }
+	 TheState =  Interpolate; break;
+
+      case Extrapolate:
+	 tr.ReName("FindMaximum2::Fit/Extrapolate");
+	 Theta1 = Theta2; g = 0.0; K *= 4.0; H1 = (H1 * 2.0 + K);
+	 d1 = 2.0 * d2; l1 = l2;
+	 TheState = Continue; break;
+
+      case Fail:
+	 Throw(ConvergenceException(Theta));
+
+      case Convergence:
+	 Theta = Theta1; return;
+      }
+   }
+}
+
+
+
+void NonLinearLeastSquares::Value
+   (const ColumnVector& Parameters, bool, Real& v, bool& oorg)
+{
+   Tracer tr("NonLinearLeastSquares::Value");
+   Y.resize(n_obs); X.resize(n_obs,n_param);
+   // put the fitted values in Y, the derivatives in X.
+   Pred.Set(Parameters);
+   if (!Pred.IsValid()) { oorg=true; return; }
+   for (int i=1; i<=n_obs; i++)
+   {
+      Y(i) = Pred(i);
+      X.Row(i) = Pred.Derivatives();
+   }
+   if (!Pred.IsValid()) { oorg=true; return; }  // check afterwards as well
+   Y = *DataPointer - Y; Real ssq = Y.SumSquare();
+   errorvar =  ssq / (n_obs - n_param);
+   cout << endl;
+   cout << setw(15) << setprecision(10) << " " << errorvar;
+   Derivs = Y.t() * X;          // get the derivative and stash it
+   oorg = false; v = -0.5 * ssq;
+}
+
+bool NonLinearLeastSquares::NextPoint(ColumnVector& Adj, Real& test)
+{
+   Tracer tr("NonLinearLeastSquares::NextPoint");
+   QRZ(X, U); QRZ(X, Y, M);     // do the QR decomposition
+   test = M.SumSquare();
+   cout << " " << setw(15) << setprecision(10)
+      << test << " " << Y.SumSquare() / (n_obs - n_param);
+   Adj = U.i() * M;
+   if (test < errorvar * criterion) return true;
+   else return false;
+}
+
+Real NonLinearLeastSquares::LastDerivative(const ColumnVector& H)
+{ return (Derivs * H).AsScalar(); }
+
+void NonLinearLeastSquares::Fit(const ColumnVector& Data,
+   ColumnVector& Parameters)
+{
+   Tracer tr("NonLinearLeastSquares::Fit");
+   n_param = Parameters.Nrows(); n_obs = Data.Nrows();
+   DataPointer = &Data;
+   FindMaximum2::Fit(Parameters, Lim);
+   cout << "\nConverged" << endl;
+}
+
+void NonLinearLeastSquares::MakeCovariance()
+{
+   if (Covariance.Nrows()==0)
+   {
+      UpperTriangularMatrix UI = U.i();
+      Covariance << UI * UI.t() * errorvar;
+      SE << Covariance;                 // get diagonals
+      for (int i = 1; i<=n_param; i++) SE(i) = sqrt(SE(i));
+   }
+}
+
+void NonLinearLeastSquares::GetStandardErrors(ColumnVector& SEX)
+   { MakeCovariance(); SEX = SE.AsColumn(); }
+
+void NonLinearLeastSquares::GetCorrelations(SymmetricMatrix& Corr)
+   { MakeCovariance(); Corr << SE.i() * Covariance * SE.i(); }
+
+void NonLinearLeastSquares::GetHatDiagonal(DiagonalMatrix& Hat) const
+{
+   Hat.resize(n_obs);
+   for (int i = 1; i<=n_obs; i++) Hat(i) = X.Row(i).SumSquare();
+}
+
+
+// the MLE_D_FI routines
+
+void MLE_D_FI::Value
+   (const ColumnVector& Parameters, bool wg, Real& v, bool& oorg)
+{
+   Tracer tr("MLE_D_FI::Value");
+   if (!LL.IsValid(Parameters,wg)) { oorg=true; return; }
+   v = LL.LogLikelihood();
+   if (!LL.IsValid()) { oorg=true; return; }     // check validity again
+   cout << endl;
+   cout << setw(20) << setprecision(10) << v;
+   oorg = false;
+   Derivs = LL.Derivatives();                    // Get derivatives
+}
+
+bool MLE_D_FI::NextPoint(ColumnVector& Adj, Real& test)
+{
+   Tracer tr("MLE_D_FI::NextPoint");
+   SymmetricMatrix FI = LL.FI();
+   LT = Cholesky(FI);
+   ColumnVector Adj1 = LT.i() * Derivs;
+   Adj = LT.t().i() * Adj1;
+   test = SumSquare(Adj1);
+   cout << "   " << setw(20) << setprecision(10) << test;
+   return (test < Criterion);
+}
+
+Real MLE_D_FI::LastDerivative(const ColumnVector& H)
+{ return (Derivs.t() * H).AsScalar(); }
+
+void MLE_D_FI::Fit(ColumnVector& Parameters)
+{
+   Tracer tr("MLE_D_FI::Fit");
+   FindMaximum2::Fit(Parameters,Lim);
+   cout << "\nConverged" << endl;
+}
+  
+void MLE_D_FI::MakeCovariance()
+{
+   if (Covariance.Nrows()==0)
+   {
+      LowerTriangularMatrix LTI = LT.i();
+      Covariance << LTI.t() * LTI;
+      SE << Covariance;                // get diagonal
+      int n = Covariance.Nrows();
+      for (int i=1; i <= n; i++) SE(i) = sqrt(SE(i));
+   }
+}
+
+void MLE_D_FI::GetStandardErrors(ColumnVector& SEX)
+{ MakeCovariance(); SEX = SE.AsColumn(); }
+   
+void MLE_D_FI::GetCorrelations(SymmetricMatrix& Corr)
+{ MakeCovariance(); Corr << SE.i() * Covariance * SE.i(); }
+
+
+
+#ifdef use_namespace
+}
+#endif
+
+
+///@}
Index: /nanovis/tags/1.1.4/newmat11/newmatnl.h
===================================================================
--- /nanovis/tags/1.1.4/newmat11/newmatnl.h	(revision 4930)
+++ /nanovis/tags/1.1.4/newmat11/newmatnl.h	(revision 4930)
@@ -0,0 +1,327 @@
+/// \ingroup newmat
+///@{
+
+/// \file newmatnl.h
+/// Header file for non-linear optimisation
+
+// Copyright (C) 1993,4,5: R B Davies
+
+#ifndef NEWMATNL_LIB
+#define NEWMATNL_LIB 0
+
+#include "newmat.h"
+
+#ifdef use_namespace
+namespace NEWMAT {
+#endif
+
+
+
+/*
+
+This is a beginning of a series of classes for non-linear optimisation.
+
+At present there are two classes. FindMaximum2 is the basic optimisation
+strategy when one is doing an optimisation where one has first
+derivatives and estimates of the second derivatives. Class
+NonLinearLeastSquares is derived from FindMaximum2. This provides the
+functions that calculate function values and derivatives.
+
+A third class is now added. This is for doing maximum-likelihood when
+you have first derviatives and something like the Fisher Information
+matrix (eg the variance covariance matrix of the first derivatives or
+minus the second derivatives - this matrix is assumed to be positive
+definite).
+
+
+
+   class FindMaximum2
+
+Suppose T is the ColumnVector of parameters, F(T) the function we want
+to maximise, D(T) the ColumnVector of derivatives of F with respect to
+T, and S(T) the matrix of second derivatives.
+
+Then the basic iteration is given a value of T, update it to
+
+           T - S.i() * D
+
+where .i() denotes inverse.
+
+If F was quadratic this would give exactly the right answer (except it
+might get a minimum rather than a maximum). Since F is not usually
+quadratic, the simple procedure would be to recalculate S and D with the
+new value of T and keep iterating until the process converges. This is
+known as the method of conjugate gradients.
+
+In practice, this method may not converge. FindMaximum2 considers an
+iteration of the form
+
+           T - x * S.i() * D
+
+where x is a number. It tries x = 1 and uses the values of F and its
+slope with respect to x at x = 0 and x = 1 to fit a cubic in x. It then
+choses x to maximise the resulting function. This gives our new value of
+T. The program checks that the value of F is getting better and carries
+out a variety of strategies if it is not.
+
+The program also has a second strategy. If the successive values of T
+seem to be lying along a curve - eg we are following along a curved
+ridge, the program will try to fit this ridge and project along it. This
+does not work at present and is commented out.
+
+FindMaximum2 has three virtual functions which need to be over-ridden by
+a derived class.
+
+   void Value(const ColumnVector& T, bool wg, Real& f, bool& oorg);
+
+T is the column vector of parameters. The function returns the value of
+the function to f, but may instead set oorg to true if the parameter
+values are not valid. If wg is true it may also calculate and store the
+second derivative information.
+
+   bool NextPoint(ColumnVector& H, Real& d);
+
+Using the value of T provided in the previous call of Value, find the
+conjugate gradients adjustment to T, that is - S.i() * D. Also return
+
+           d = D.t() * S.i() * D.
+
+NextPoint should return true if it considers that the process has
+converged (d very small) and false otherwise. The previous call of Value
+will have set wg to true, so that S will be available.
+
+   Real LastDerivative(const ColumnVector& H);
+
+Return the scalar product of H and the vector of derivatives at the last
+value of T.
+
+The function Fit is the function that calls the iteration.
+
+   void Fit(ColumnVector&, int);
+
+The arguments are the trial parameter values as a ColumnVector and the
+maximum number of iterations. The program calls a DataException if the
+initial parameters are not valid and a ConvergenceException if the
+process fails to converge.
+
+
+   class NonLinearLeastSquares
+
+This class is derived from FindMaximum2 and carries out a non-linear
+least squares fit. It uses a QR decomposition to carry out the
+operations required by FindMaximum2.
+
+A prototype class R1_Col_I_D is provided. The user needs to derive a
+class from this which includes functions the predicted value of each
+observation its derivatives. An object from this class has to be
+provided to class NonLinearLeastSquares.
+
+Suppose we observe n normal random variables with the same unknown
+variance and such the i-th one has expected value given by f(i,P)
+where P is a column vector of unknown parameters and f is a known
+function. We wish to estimate P.
+
+First derive a class from R1_Col_I_D and override Real operator()(int i)
+to give the value of the function f in terms of i and the ColumnVector
+para defined in class R1_CoL_I_D. Also override ReturnMatrix
+Derivatives() to give the derivates of f at para and the value of i
+used in the preceeding call to operator(). Return the result as a
+RowVector. Construct an object from this class. Suppose in what follows
+it is called pred.
+
+Now constuct a NonLinearLeastSquaresObject accessing pred and optionally
+an iteration limit and an accuracy critierion.
+
+   NonLinearLeastSquares NLLS(pred, 1000, 0.0001);
+
+The accuracy critierion should be somewhat less than one and 0.0001 is
+about the smallest sensible value.
+
+Define a ColumnVector P containing a guess at the value of the unknown
+parameter, and a ColumnVector Y containing the unknown data. Call
+
+   NLLS.Fit(Y,P);
+
+If the process converges, P will contain the estimates of the unknown
+parameters. If it does not converge an exception will be generated.
+
+The following member functions can be called after you have done a fit.
+
+Real ResidualVariance() const;
+
+The estimate of the variance of the observations.
+
+void GetResiduals(ColumnVector& Z) const;
+
+The residuals of the individual observations.
+
+void GetStandardErrors(ColumnVector&);
+
+The standard errors of the observations.
+
+void GetCorrelations(SymmetricMatrix&);
+
+The correlations of the observations.
+
+void GetHatDiagonal(DiagonalMatrix&) const;
+
+Forms a diagonal matrix of values between 0 and 1. If the i-th value is
+larger than, say 0.2, then the i-th data value could have an undue
+influence on your estimates.
+
+
+*/
+
+class FindMaximum2
+{
+   virtual void Value(const ColumnVector&, bool, Real&, bool&) = 0;
+   virtual bool NextPoint(ColumnVector&, Real&) = 0;
+   virtual Real LastDerivative(const ColumnVector&) = 0;
+public:
+   void Fit(ColumnVector&, int);
+   virtual ~FindMaximum2() {}            // to keep gnu happy
+};
+
+class R1_Col_I_D
+{
+   // The prototype for a Real function of a ColumnVector and an
+   // integer.
+   // You need to derive your function from this one and put in your
+   // function for operator() and Derivatives() at least.
+   // You may also want to set up a constructor to enter in additional
+   // parameter values (that will not vary during the solve).
+
+protected:
+   ColumnVector para;                 // Current x value
+
+public:
+   virtual bool IsValid() { return true; }
+                                       // is the current x value OK
+   virtual Real operator()(int i) = 0; // i-th function value at current para
+   virtual void Set(const ColumnVector& X) { para = X; }
+                                       // set current para
+   bool IsValid(const ColumnVector& X)
+      { Set(X); return IsValid(); }
+                                       // set para, check OK
+   Real operator()(int i, const ColumnVector& X)
+      { Set(X); return operator()(i); }
+                                       // set para, return value
+   virtual ReturnMatrix Derivatives() = 0;
+                                       // return derivatives as RowVector
+   virtual ~R1_Col_I_D() {}            // to keep gnu happy
+};
+
+
+class NonLinearLeastSquares : public FindMaximum2
+{
+   // these replace the corresponding functions in FindMaximum2
+   void Value(const ColumnVector&, bool, Real&, bool&);
+   bool NextPoint(ColumnVector&, Real&);
+   Real LastDerivative(const ColumnVector&);
+
+   Matrix X;                         // the things we need to do the
+   ColumnVector Y;                   // QR triangularisation
+   UpperTriangularMatrix U;          // see the write-up in newmata.txt
+   ColumnVector M;
+   Real errorvar, criterion;
+   int n_obs, n_param;
+   const ColumnVector* DataPointer;
+   RowVector Derivs;
+   SymmetricMatrix Covariance;
+   DiagonalMatrix SE;
+   R1_Col_I_D& Pred;                 // Reference to predictor object
+   int Lim;                          // maximum number of iterations
+
+public:
+   NonLinearLeastSquares(R1_Col_I_D& pred, int lim=1000, Real crit=0.0001)
+      : criterion(crit), Pred(pred), Lim(lim) {}
+   void Fit(const ColumnVector&, ColumnVector&);
+   Real ResidualVariance() const { return errorvar; }
+   void GetResiduals(ColumnVector& Z) const { Z = Y; }
+   void GetStandardErrors(ColumnVector&);
+   void GetCorrelations(SymmetricMatrix&);
+   void GetHatDiagonal(DiagonalMatrix&) const;
+
+private:
+   void MakeCovariance();
+};
+
+
+// The next class is the prototype class for calculating the
+// log-likelihood.
+// I assume first derivatives are available and something like the 
+// Fisher Information or variance/covariance matrix of the first
+// derivatives or minus the matrix of second derivatives is
+// available. This matrix must be positive definite.
+
+class LL_D_FI
+{
+protected:
+   ColumnVector para;                  // current parameter values
+   bool wg;                         // true if FI matrix wanted
+
+public:
+   virtual void Set(const ColumnVector& X) { para = X; }
+                                       // set parameter values
+   virtual void WG(bool wgx) { wg = wgx; }
+                                       // set wg
+
+   virtual bool IsValid() { return true; }
+                                       // return true is para is OK
+   bool IsValid(const ColumnVector& X, bool wgx=true)
+      { Set(X); WG(wgx); return IsValid(); }
+
+   virtual Real LogLikelihood() = 0;   // return the loglikelihhod
+   Real LogLikelihood(const ColumnVector& X, bool wgx=true)
+      { Set(X); WG(wgx); return LogLikelihood(); }
+
+   virtual ReturnMatrix Derivatives() = 0;
+                                       // column vector of derivatives
+   virtual ReturnMatrix FI() = 0;      // Fisher Information matrix
+   virtual ~LL_D_FI() {}               // to keep gnu happy
+};
+
+// This is the class for doing the maximum likelihood estimation
+
+class MLE_D_FI : public FindMaximum2
+{
+   // these replace the corresponding functions in FindMaximum2
+   void Value(const ColumnVector&, bool, Real&, bool&);
+   bool NextPoint(ColumnVector&, Real&);
+   Real LastDerivative(const ColumnVector&);
+
+   // the things we need for the analysis
+   LL_D_FI& LL;                        // reference to log-likelihood
+   int Lim;                            // maximum number of iterations
+   Real Criterion;                     // convergence criterion
+   ColumnVector Derivs;                // for the derivatives
+   LowerTriangularMatrix LT;           // Cholesky decomposition of FI
+   SymmetricMatrix Covariance;
+   DiagonalMatrix SE;
+
+public:
+   MLE_D_FI(LL_D_FI& ll, int lim=1000, Real criterion=0.0001)
+      : LL(ll), Lim(lim), Criterion(criterion) {}
+   void Fit(ColumnVector& Parameters);
+   void GetStandardErrors(ColumnVector&);
+   void GetCorrelations(SymmetricMatrix&);
+
+private:
+   void MakeCovariance();
+};
+
+
+#ifdef use_namespace
+}
+#endif
+
+
+
+#endif
+
+// body file: newmatnl.cpp
+
+
+
+///@}
+
Index: /nanovis/tags/1.1.4/newmat11/newmatrc.h
===================================================================
--- /nanovis/tags/1.1.4/newmat11/newmatrc.h	(revision 4930)
+++ /nanovis/tags/1.1.4/newmat11/newmatrc.h	(revision 4930)
@@ -0,0 +1,186 @@
+/// \ingroup newmat
+///@{
+
+/// \file newmatrc.h
+/// Header file for row/column classes
+
+// Copyright (C) 1991,2,3,4,7: R B Davies
+
+#ifndef NEWMATRC_LIB
+#define NEWMATRC_LIB 0
+
+#ifdef use_namespace
+namespace NEWMAT {
+#endif
+
+#include "controlw.h"
+
+
+/************** classes MatrixRowCol, MatrixRow, MatrixCol *****************/
+
+// Used for accessing the rows and columns of matrices
+// All matrix classes must provide routines for calculating matrix rows and
+// columns. Assume rows can be found very efficiently.
+
+enum LSF { LoadOnEntry=1,StoreOnExit=2,DirectPart=4,StoreHere=8,HaveStore=16 };
+
+
+/// Option for accessing row or column.
+/// \internal
+class LoadAndStoreFlag : public ControlWord
+{
+public:
+   LoadAndStoreFlag() {}
+   LoadAndStoreFlag(int i) : ControlWord(i) {}
+   LoadAndStoreFlag(LSF lsf) : ControlWord(lsf) {}
+   LoadAndStoreFlag(const ControlWord& cwx) : ControlWord(cwx) {}
+};
+
+
+/// Access a row or column of a matrix.
+/// \internal
+class MatrixRowCol
+{
+public:                                        // these are public to avoid
+                                               // numerous friend statements
+   int length;                                 // row or column length
+   int skip;                                   // initial number of zeros
+   int storage;                                // number of stored elements
+   int rowcol;                                 // row or column number
+   GeneralMatrix* gm;                          // pointer to parent matrix
+   Real* data;                                 // pointer to local storage
+   LoadAndStoreFlag cw;                        // Load? Store? Is a Copy?
+   void IncrMat() { rowcol++; data += storage; }   // used by NextRow
+   void IncrDiag() { rowcol++; skip++; data++; }
+   void IncrId() { rowcol++; skip++; }
+   void IncrUT() { rowcol++; data += storage; storage--; skip++; }
+   void IncrLT() { rowcol++; data += storage; storage++; }
+
+public:
+   void Zero();                                // set elements to zero
+   void Add(const MatrixRowCol&);              // add a row/col
+   void AddScaled(const MatrixRowCol&, Real);  // add a multiple of a row/col
+   void Add(const MatrixRowCol&, const MatrixRowCol&);
+                                               // add two rows/cols
+   void Add(const MatrixRowCol&, Real);        // add a row/col
+   void NegAdd(const MatrixRowCol&, Real);     // Real - a row/col
+   void Sub(const MatrixRowCol&);              // subtract a row/col
+   void Sub(const MatrixRowCol&, const MatrixRowCol&);
+					       // sub a row/col from another
+   void RevSub(const MatrixRowCol&);           // subtract from a row/col
+   void ConCat(const MatrixRowCol&, const MatrixRowCol&);
+                                               // concatenate two row/cols
+   void Multiply(const MatrixRowCol&);         // multiply a row/col
+   void Multiply(const MatrixRowCol&, const MatrixRowCol&);
+                                               // multiply two row/cols
+   void KP(const MatrixRowCol&, const MatrixRowCol&);
+                                               // Kronecker Product two row/cols
+   void Copy(const MatrixRowCol&);             // copy a row/col
+   void CopyCheck(const MatrixRowCol&);        // ... check for data loss
+   void Check(const MatrixRowCol&);            // just check for data loss
+   void Check();                               // check full row/col present
+   void Copy(const double*&);                  // copy from an array
+   void Copy(const float*&);                   // copy from an array
+   void Copy(const int*&);                     // copy from an array
+   void Copy(Real);                            // copy from constant
+   void Add(Real);                             // add a constant
+   void Multiply(Real);                        // multiply by constant
+   Real SumAbsoluteValue();                    // sum of absolute values
+   Real MaximumAbsoluteValue1(Real r, int& i); // maximum of absolute values
+   Real MinimumAbsoluteValue1(Real r, int& i); // minimum of absolute values
+   Real Maximum1(Real r, int& i);              // maximum
+   Real Minimum1(Real r, int& i);              // minimum
+   Real Sum();                                 // sum of values
+   void Inject(const MatrixRowCol&);           // copy stored els of a row/col
+   void Negate(const MatrixRowCol&);           // change sign of a row/col
+   void Multiply(const MatrixRowCol&, Real);   // scale a row/col
+   friend Real DotProd(const MatrixRowCol&, const MatrixRowCol&);
+                                               // sum of pairwise product
+   Real* Data() { return data; }
+   int Skip() { return skip; }                 // number of elements skipped
+   int Storage() { return storage; }           // number of elements stored
+   int Length() { return length; }             // length of row or column
+   void Skip(int i) { skip=i; }
+   void Storage(int i) { storage=i; }
+   void Length(int i) { length=i; }
+   void SubRowCol(MatrixRowCol&, int, int) const;
+					       // get part of a row or column
+   MatrixRowCol() {}                           // to stop warning messages
+   ~MatrixRowCol();
+   FREE_CHECK(MatrixRowCol)
+};
+
+/// Access a row of a matrix.
+/// \internal
+class MatrixRow : public MatrixRowCol
+{
+public:
+   // bodies for these are inline at the end of this .h file
+   MatrixRow(GeneralMatrix*, LoadAndStoreFlag, int=0);
+                                               // extract a row
+   ~MatrixRow();
+   void Next();                                // get next row
+   FREE_CHECK(MatrixRow)
+};
+
+/// Access a column of a matrix.
+/// \internal
+class MatrixCol : public MatrixRowCol
+{
+public:
+   // bodies for these are inline at the end of this .h file
+   MatrixCol(GeneralMatrix*, LoadAndStoreFlag, int=0);
+                                               // extract a col
+   MatrixCol(GeneralMatrix*, Real*, LoadAndStoreFlag, int=0);
+                                               // store/retrieve a col
+   ~MatrixCol();
+   void Next();                                // get next column
+   FREE_CHECK(MatrixCol)
+};
+
+/// Alternative to MatrixCol where the complete column is stored externally.
+/// \internal
+class MatrixColX : public MatrixRowCol
+{
+public:
+   // bodies for these are inline at the end of this .h file
+   MatrixColX(GeneralMatrix*, Real*, LoadAndStoreFlag, int=0);
+                                               // store/retrieve a col
+   ~MatrixColX();
+   void Next();                                // get next row
+   Real* store;                                // pointer to local storage
+                                               //    less skip
+   FREE_CHECK(MatrixColX)
+};
+
+/**************************** inline bodies ****************************/
+
+inline MatrixRow::MatrixRow(GeneralMatrix* gmx, LoadAndStoreFlag cwx, int row)
+{ gm=gmx; cw=cwx; rowcol=row; gm->GetRow(*this); }
+
+inline void MatrixRow::Next() { gm->NextRow(*this); }
+
+inline MatrixCol::MatrixCol(GeneralMatrix* gmx, LoadAndStoreFlag cwx, int col)
+{ gm=gmx; cw=cwx; rowcol=col; gm->GetCol(*this); }
+
+inline MatrixCol::MatrixCol(GeneralMatrix* gmx, Real* r,
+   LoadAndStoreFlag cwx, int col)
+{ gm=gmx; data=r; cw=cwx+StoreHere; rowcol=col; gm->GetCol(*this); }
+
+inline MatrixColX::MatrixColX(GeneralMatrix* gmx, Real* r,
+   LoadAndStoreFlag cwx, int col)
+{ gm=gmx; store=data=r; cw=cwx+StoreHere; rowcol=col; gm->GetCol(*this); }
+
+
+inline void MatrixCol::Next() { gm->NextCol(*this); }
+
+inline void MatrixColX::Next() { gm->NextCol(*this); }
+
+#ifdef use_namespace
+}
+#endif
+
+#endif
+
+
+///@}
Index: /nanovis/tags/1.1.4/newmat11/newmatrm.cpp
===================================================================
--- /nanovis/tags/1.1.4/newmat11/newmatrm.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/newmat11/newmatrm.cpp	(revision 4930)
@@ -0,0 +1,221 @@
+/// \ingroup newmat
+///@{
+
+/// \file newmatrm.cpp
+/// Rectangular matrix operations
+
+// Copyright (C) 1991,2,3,4: R B Davies
+
+#define WANT_MATH
+
+#include "newmat.h"
+#include "newmatrm.h"
+
+#ifdef use_namespace
+namespace NEWMAT {
+#endif
+
+#ifdef DO_REPORT
+#define REPORT { static ExeCounter ExeCount(__LINE__,12); ++ExeCount; }
+#else
+#define REPORT {}
+#endif
+
+
+// operations on rectangular matrices
+
+
+void RectMatrixRow::Reset (const Matrix& M, int row, int skip, int length)
+{
+   REPORT
+   RectMatrixRowCol::Reset
+      ( M.Store()+row*M.Ncols()+skip, length, 1, M.Ncols() );
+}
+
+void RectMatrixRow::Reset (const Matrix& M, int row)
+{
+   REPORT
+   RectMatrixRowCol::Reset( M.Store()+row*M.Ncols(), M.Ncols(), 1, M.Ncols() );
+}
+
+void RectMatrixCol::Reset (const Matrix& M, int skip, int col, int length)
+{
+   REPORT
+   RectMatrixRowCol::Reset
+      ( M.Store()+col+skip*M.Ncols(), length, M.Ncols(), 1 );
+}
+
+void RectMatrixCol::Reset (const Matrix& M, int col)
+{
+   REPORT
+   RectMatrixRowCol::Reset( M.Store()+col, M.Nrows(), M.Ncols(), 1 );
+}
+
+
+Real RectMatrixRowCol::SumSquare() const
+{
+   REPORT
+   long_Real sum = 0.0; int i = n; Real* s = store; int d = spacing;
+   // while (i--) { sum += (long_Real)*s * *s; s += d; }
+   if (i) for(;;)
+      { sum += (long_Real)*s * *s; if (!(--i)) break; s += d; }
+   return (Real)sum;
+}
+
+Real RectMatrixRowCol::operator*(const RectMatrixRowCol& rmrc) const
+{
+   REPORT
+   long_Real sum = 0.0; int i = n;
+   Real* s = store; int d = spacing;
+   Real* s1 = rmrc.store; int d1 = rmrc.spacing;
+   if (i!=rmrc.n)
+   {
+      Tracer tr("newmatrm");
+      Throw(InternalException("Dimensions differ in *"));
+   }
+   // while (i--) { sum += (long_Real)*s * *s1; s += d; s1 += d1; }
+   if (i) for(;;)
+      { sum += (long_Real)*s * *s1; if (!(--i)) break; s += d; s1 += d1; }
+   return (Real)sum;
+}
+
+void RectMatrixRowCol::AddScaled(const RectMatrixRowCol& rmrc, Real r)
+{
+   REPORT
+   int i = n; Real* s = store; int d = spacing;
+   Real* s1 = rmrc.store; int d1 = rmrc.spacing;
+   if (i!=rmrc.n)
+   {
+      Tracer tr("newmatrm");
+      Throw(InternalException("Dimensions differ in AddScaled"));
+   }
+   // while (i--) { *s += *s1 * r; s += d; s1 += d1; }
+   if (i) for (;;)
+      { *s += *s1 * r; if (!(--i)) break; s += d; s1 += d1; }
+}
+
+void RectMatrixRowCol::Divide(const RectMatrixRowCol& rmrc, Real r)
+{
+   REPORT
+   int i = n; Real* s = store; int d = spacing;
+   Real* s1 = rmrc.store; int d1 = rmrc.spacing;
+   if (i!=rmrc.n)
+   {
+      Tracer tr("newmatrm");
+      Throw(InternalException("Dimensions differ in Divide"));
+   }
+   // while (i--) { *s = *s1 / r; s += d; s1 += d1; }
+   if (i) for (;;) { *s = *s1 / r; if (!(--i)) break; s += d; s1 += d1; }
+}
+
+void RectMatrixRowCol::Divide(Real r)
+{
+   REPORT
+   int i = n; Real* s = store; int d = spacing;
+   // while (i--) { *s /= r; s += d; }
+   if (i) for (;;) { *s /= r; if (!(--i)) break; s += d; }
+}
+
+void RectMatrixRowCol::Negate()
+{
+   REPORT
+   int i = n; Real* s = store; int d = spacing;
+   // while (i--) { *s = - *s; s += d; }
+   if (i) for (;;) { *s = - *s; if (!(--i)) break; s += d; }
+}
+
+void RectMatrixRowCol::Zero()
+{
+   REPORT
+   int i = n; Real* s = store; int d = spacing;
+   // while (i--) { *s = 0.0; s += d; }
+   if (i) for (;;) { *s = 0.0; if (!(--i)) break; s += d; }
+}
+
+void ComplexScale(RectMatrixCol& U, RectMatrixCol& V, Real x, Real y)
+{
+   REPORT
+   int n = U.n;
+   if (n != V.n)
+   {
+      Tracer tr("newmatrm");
+      Throw(InternalException("Dimensions differ in ComplexScale"));
+   }
+   Real* u = U.store; Real* v = V.store; 
+   int su = U.spacing; int sv = V.spacing;
+   //while (n--)
+   //{
+   //   Real z = *u * x - *v * y;  *v =  *u * y + *v * x;  *u = z;
+   //   u += su;  v += sv;
+   //}
+   if (n) for (;;)
+   {
+      Real z = *u * x - *v * y;  *v =  *u * y + *v * x;  *u = z;
+      if (!(--n)) break;
+      u += su;  v += sv;
+   }
+}
+
+void Rotate(RectMatrixCol& U, RectMatrixCol& V, Real tau, Real s)
+{
+   REPORT
+   //  (U, V) = (U, V) * (c, s)  where  tau = s/(1+c), c^2 + s^2 = 1
+   int n = U.n;
+   if (n != V.n)
+   {
+      Tracer tr("newmatrm");
+      Throw(InternalException("Dimensions differ in Rotate"));
+   }
+   Real* u = U.store; Real* v = V.store;
+   int su = U.spacing; int sv = V.spacing;
+   //while (n--)
+   //{
+   //   Real zu = *u; Real zv = *v;
+   //   *u -= s * (zv + zu * tau); *v += s * (zu - zv * tau);
+   //   u += su;  v += sv;
+   //}
+   if (n) for(;;)
+   {
+      Real zu = *u; Real zv = *v;
+      *u -= s * (zv + zu * tau); *v += s * (zu - zv * tau);
+      if (!(--n)) break;
+      u += su;  v += sv;
+   }
+}
+
+
+// misc procedures for numerical things
+
+Real pythag(Real f, Real g, Real& c, Real& s)
+// return z=sqrt(f*f+g*g), c=f/z, s=g/z
+// set c=1,s=0 if z==0
+// avoid floating point overflow or divide by zero
+{
+   if (f==0 && g==0) { c=1.0; s=0.0; return 0.0; }
+   Real af = f>=0 ? f : -f;
+   Real ag = g>=0 ? g : -g;
+   if (ag<af)
+   {
+      REPORT
+      Real h = g/f; Real sq = sqrt(1.0+h*h);
+      if (f<0) sq = -sq;           // make return value non-negative
+      c = 1.0/sq; s = h/sq; return sq*f;
+   }
+   else
+   {
+      REPORT
+      Real h = f/g; Real sq = sqrt(1.0+h*h);
+      if (g<0) sq = -sq;
+      s = 1.0/sq; c = h/sq; return sq*g;
+   }
+}
+
+
+
+
+#ifdef use_namespace
+}
+#endif
+
+
+///@}
Index: /nanovis/tags/1.1.4/newmat11/newmatrm.h
===================================================================
--- /nanovis/tags/1.1.4/newmat11/newmatrm.h	(revision 4930)
+++ /nanovis/tags/1.1.4/newmat11/newmatrm.h	(revision 4930)
@@ -0,0 +1,156 @@
+/// \ingroup newmat
+///@{
+
+/// \file newmatrm.h
+/// Rectangular matrix operations.
+
+// Copyright (C) 1991,2,3,4: R B Davies
+
+#ifndef NEWMATRM_LIB
+#define NEWMATRM_LIB 0
+
+#ifdef use_namespace
+namespace NEWMAT {
+#endif
+
+
+class RectMatrixCol;
+
+/// Access rows and columns of a rectangular matrix.
+/// \internal
+class RectMatrixRowCol
+{
+protected:
+#ifdef use_namespace              // to make namespace work
+public:
+#endif
+   Real* store;                   // pointer to storage
+   int n;                         // number of elements
+   int spacing;                   // space between elements
+   int shift;                     // space between cols or rows
+   RectMatrixRowCol(Real* st, int nx, int sp, int sh)
+      : store(st), n(nx), spacing(sp), shift(sh) {}
+   void Reset(Real* st, int nx, int sp, int sh)
+      { store=st; n=nx; spacing=sp; shift=sh; }
+public:
+   Real operator*(const RectMatrixRowCol&) const;         // dot product
+   void AddScaled(const RectMatrixRowCol&, Real);         // add scaled
+   void Divide(const RectMatrixRowCol&, Real);            // scaling
+   void Divide(Real);                                     // scaling
+   void Negate();                                         // change sign
+   void Zero();                                           // zero row col
+   Real& operator[](int i) { return *(store+i*spacing); } // element
+   Real SumSquare() const;                                // sum of squares
+   Real& First() { return *store; }                       // get first element
+   void DownDiag() { store += (shift+spacing); n--; }
+   void UpDiag() { store -= (shift+spacing); n++; }
+   friend void ComplexScale(RectMatrixCol&, RectMatrixCol&, Real, Real);
+   friend void Rotate(RectMatrixCol&, RectMatrixCol&, Real, Real);
+   FREE_CHECK(RectMatrixRowCol)
+};
+
+/// Access rows of a rectangular matrix.
+/// \internal
+class RectMatrixRow : public RectMatrixRowCol
+{
+public:
+   RectMatrixRow(const Matrix&, int, int, int);
+   RectMatrixRow(const Matrix&, int);
+   void Reset(const Matrix&, int, int, int);
+   void Reset(const Matrix&, int);
+   Real& operator[](int i) { return *(store+i); }
+   void Down() { store += shift; }
+   void Right() { store++; n--; }
+   void Up() { store -= shift; }
+   void Left() { store--; n++; }
+   FREE_CHECK(RectMatrixRow)
+};
+
+/// Access columns of a rectangular matrix.
+/// \internal
+class RectMatrixCol : public RectMatrixRowCol
+{
+public:
+   RectMatrixCol(const Matrix&, int, int, int);
+   RectMatrixCol(const Matrix&, int);
+   void Reset(const Matrix&, int, int, int);
+   void Reset(const Matrix&, int);
+   void Down() { store += spacing; n--; }
+   void Right() { store++; }
+   void Up() { store -= spacing; n++; }
+   void Left() { store--; }
+   friend void ComplexScale(RectMatrixCol&, RectMatrixCol&, Real, Real);
+   friend void Rotate(RectMatrixCol&, RectMatrixCol&, Real, Real);
+   FREE_CHECK(RectMatrixCol)
+};
+
+/// Access diagonal of a rectangular matrix.
+/// \internal
+class RectMatrixDiag : public RectMatrixRowCol
+{
+public:
+   RectMatrixDiag(const DiagonalMatrix& D)
+      : RectMatrixRowCol(D.Store(), D.Nrows(), 1, 1) {}
+   Real& operator[](int i) { return *(store+i); }
+   void DownDiag() { store++; n--; }
+   void UpDiag() { store--; n++; }
+   FREE_CHECK(RectMatrixDiag)
+};
+
+
+
+
+inline RectMatrixRow::RectMatrixRow
+   (const Matrix& M, int row, int skip, int length)
+   : RectMatrixRowCol( M.Store()+row*M.Ncols()+skip, length, 1, M.Ncols() ) {}
+
+inline RectMatrixRow::RectMatrixRow (const Matrix& M, int row)
+   : RectMatrixRowCol( M.Store()+row*M.Ncols(), M.Ncols(), 1, M.Ncols() ) {}
+
+inline RectMatrixCol::RectMatrixCol
+   (const Matrix& M, int skip, int col, int length)
+   : RectMatrixRowCol( M.Store()+col+skip*M.Ncols(), length, M.Ncols(), 1 ) {}
+
+inline RectMatrixCol::RectMatrixCol (const Matrix& M, int col)
+   : RectMatrixRowCol( M.Store()+col, M.Nrows(), M.Ncols(), 1 ) {}
+
+inline Real square(Real x) { return x*x; }
+inline Real sign(Real x, Real y)
+   { return (y>=0) ? x : -x; }                    // assume x >=0
+
+
+// Misc numerical things
+
+Real pythag(Real f, Real g, Real& c, Real& s);
+
+inline void GivensRotation(Real cGivens, Real sGivens, Real& x, Real& y)
+{
+   // allow for possibility &x = &y
+   Real tmp0 = cGivens * x + sGivens * y;
+   Real tmp1 = -sGivens * x + cGivens * y;
+   x = tmp0; y = tmp1;
+}
+   
+inline void GivensRotationR(Real cGivens, Real sGivens, Real& x, Real& y)
+{
+   // also change sign of y
+   // allow for possibility &x = &y
+   Real tmp0 = cGivens * x + sGivens * y;
+   Real tmp1 = sGivens * x - cGivens * y;
+   x = tmp0; y = tmp1;
+}   
+
+
+
+
+
+#ifdef use_namespace
+}
+#endif
+
+#endif
+
+// body file: newmatrm.cpp
+
+
+///@}
Index: /nanovis/tags/1.1.4/newmat11/nm_misc.cpp
===================================================================
--- /nanovis/tags/1.1.4/newmat11/nm_misc.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/newmat11/nm_misc.cpp	(revision 4930)
@@ -0,0 +1,147 @@
+/// \ingroup newmat
+///@{
+
+/// \file nm_misc.cpp
+/// Miscellaneous programs.
+
+#define WANT_MATH
+
+#include "include.h"
+
+#include "newmatap.h"
+
+#ifdef use_namespace
+namespace NEWMAT {
+#endif
+
+
+#ifdef DO_REPORT
+#define REPORT { static ExeCounter ExeCount(__LINE__,21); ++ExeCount; }
+#else
+#define REPORT {}
+#endif
+
+ReturnMatrix Helmert(int n, bool full)
+{
+   REPORT
+   Tracer et("Helmert ");
+   if (n <= 0) Throw(ProgramException("Dimension <= 0 "));
+   Matrix H;
+   
+   if (full) H.resize(n,n); else H.resize(n-1,n);
+   H = 0.0;
+   for (int i = 1; i < n; ++i)
+   {
+      Real f = 1.0 / sqrt((Real)i * (i+1));
+      H.submatrix(i,i,1,i) = -f; H(i,i+1) = f * i;
+   }
+   if (full) { H.row(n) = 1.0 / sqrt((Real)n); }
+   H.release(); return H.for_return();
+} 
+
+
+
+// Multiply X by n-1 x n matrix to give n-1 contrasts
+// Return a ColumnVector
+ReturnMatrix Helmert(const ColumnVector& X, bool full)
+{
+   REPORT
+   Tracer et("Helmert * CV");
+   int n = X.nrows();
+   if (n == 0) Throw(ProgramException("X Vector of length 0", X));
+   Real sum = 0.0; ColumnVector Y;
+   if (full) Y.resize(n); else Y.resize(n-1);
+   for (int i = 1; i < n; ++i)
+      { sum += X(i); Y(i) = (i * X(i+1) - sum) / sqrt((Real)i * (i+1)); }
+   if (full) { sum += X(n); Y(n) = sum / sqrt((Real)n); }
+   Y.release(); return Y.for_return();
+} 
+
+// same as above for X a ColumnVector, length n, element j = 1; otherwise 0
+ReturnMatrix Helmert(int n, int j, bool full)
+{
+   REPORT
+   Tracer et("Helmert:single element ");
+   if (n <= 0) Throw(ProgramException("X Vector of length <= 0"));
+   if (j > n || j <= 0)
+      Throw(ProgramException("Out of range element number "));
+   ColumnVector Y; if (full) Y.resize(n); else Y.resize(n-1);
+   Y = 0.0;
+   if (j > 1) Y(j-1) = sqrt((Real)(j-1) / (Real)j);
+   for (int i = j; i < n; ++i) Y(i) = - 1.0 / sqrt((Real)i * (i+1));
+   if (full) Y(n) = 1.0 / sqrt((Real)n);
+   Y.release(); return Y.for_return();
+} 
+
+ReturnMatrix Helmert_transpose(const ColumnVector& Y, bool full)
+{
+   REPORT
+   Tracer et("Helmert_transpose * CV ");
+   int n = Y.nrows(); Real sum;
+   if (full) sum = Y(n) / sqrt((Real)n); else { sum = 0.0; ++n; }
+   ColumnVector X(n);
+   for (int i = n-1; i > 0; --i)
+   {
+      Real Yi = Y(i) / sqrt((Real)i * (i+1));
+      X(i+1) = i * Yi + sum; sum -= Yi;
+   }
+   X(1) = sum;
+   X.release(); return X.for_return();
+}
+
+// same as above but want only j-th element
+Real Helmert_transpose(const ColumnVector& Y, int j, bool full)
+{
+   REPORT
+   Tracer et("Helmert_transpose:single element ");
+   int n = Y.nrows(); Real sum;
+   if (full) sum = Y(n) / sqrt((Real)n); else { sum = 0.0; ++n; }
+   if (j > n || j <= 0) Throw(IndexException(j, Y));
+   for (int i = n-1; i > 0; --i)
+   {
+      Real Yi = Y(i) / sqrt((Real)i * (i+1));
+      if (i+1 == j) return i * Yi + sum;
+      sum -= Yi;
+   }
+   return sum;
+}
+
+ReturnMatrix Helmert(const Matrix& X, bool full)
+{
+   REPORT
+   Tracer et("Helmert * Matrix");
+   int m = X.nrows(); int n = X.ncols();
+   if (m == 0) Throw(ProgramException("Matrix has 0 rows ", X));
+   Matrix Y;
+   if (full) Y.resize(m,n); else Y.resize(m-1, n);
+   for (int j = 1; j <= n; ++j)
+   {
+      ColumnVector CV = X.Column(j);
+      Y.Column(j) = Helmert(CV, full);
+   }
+   Y.release(); return Y.for_return();
+}
+
+ReturnMatrix Helmert_transpose(const Matrix& Y, bool full)
+{
+   REPORT
+   Tracer et("Helmert_transpose * Matrix ");
+   int m = Y.nrows(); int n = Y.ncols(); if (!full) ++m;
+   Matrix X(m, n);
+   for (int j = 1; j <= n; ++j)
+   {
+      ColumnVector CV = Y.Column(j);
+      X.Column(j) = Helmert_transpose(CV, full);
+   }
+   X.release(); return X.for_return();
+}
+
+
+
+
+#ifdef use_namespace
+}
+#endif
+
+
+///@}
Index: /nanovis/tags/1.1.4/newmat11/precisio.h
===================================================================
--- /nanovis/tags/1.1.4/newmat11/precisio.h	(revision 4930)
+++ /nanovis/tags/1.1.4/newmat11/precisio.h	(revision 4930)
@@ -0,0 +1,266 @@
+/// \ingroup newmat
+///@{
+
+/// \file precisio.h
+/// Floating point precision constants.
+
+#ifndef PRECISION_LIB
+#define PRECISION_LIB 0
+
+#define WANT_MATH
+#include "include.h"              // in case being used as stand alone
+
+#ifdef _STANDARD_                 // standard library available
+#include <limits>
+#endif
+
+#ifdef use_namespace
+namespace NEWMAT {
+#endif
+
+#ifdef _STANDARD_                 // standard library available
+
+#ifdef OPT_COMPATIBLE
+#include <cfloat>                 // for FLT_MAX
+#endif
+
+using namespace std;
+	
+/// Floating point precision.
+class FloatingPointPrecision
+{
+public:
+   static int Dig()              // number of decimal digits or precision
+      { return numeric_limits<Real>::digits10 ; }
+
+   static Real Epsilon()         // smallest number such that 1+Eps!=Eps
+      { return numeric_limits<Real>::epsilon(); }
+
+   static int Mantissa()         // bits in mantisa
+      { return numeric_limits<Real>::digits; }
+
+   static Real Maximum()         // maximum value
+      { return numeric_limits<Real>::max(); }
+
+   static int MaximumDecimalExponent()  // maximum decimal exponent
+      { return numeric_limits<Real>::max_exponent10; }
+
+   static int MaximumExponent()  // maximum binary exponent
+      { return numeric_limits<Real>::max_exponent; }
+
+   static Real LnMaximum()       // natural log of maximum
+      { return (Real)log(Maximum()); }
+
+   static Real Minimum()         // minimum positive value
+      { return numeric_limits<Real>::min(); } 
+
+   static int MinimumDecimalExponent() // minimum decimal exponent
+      { return numeric_limits<Real>::min_exponent10; }
+
+   static int MinimumExponent()  // minimum binary exponent
+      { return numeric_limits<Real>::min_exponent; }
+
+   static Real LnMinimum()       // natural log of minimum
+      { return (Real)log(Minimum()); }
+
+   static int Radix()            // exponent radix
+      { return numeric_limits<Real>::radix; }
+
+   static int Rounds()           // addition rounding (1 = does round)
+   {
+	  return numeric_limits<Real>::round_style ==
+		 round_to_nearest ? 1 : 0;
+   }
+
+};
+
+
+#else                              // _STANDARD_ not defined
+
+#ifndef SystemV                    // if there is float.h
+
+#ifdef USING_FLOAT
+
+/// Floating point precision (type float).
+class FloatingPointPrecision
+{
+public:
+   static int Dig()
+      { return FLT_DIG; }        // number of decimal digits or precision
+
+   static Real Epsilon()
+      { return FLT_EPSILON; }    // smallest number such that 1+Eps!=Eps
+
+   static int Mantissa()
+      { return FLT_MANT_DIG; }   // bits in mantisa
+
+   static Real Maximum()
+      { return FLT_MAX; }        // maximum value
+
+   static int MaximumDecimalExponent()
+      { return FLT_MAX_10_EXP; } // maximum decimal exponent
+
+   static int MaximumExponent()
+      { return FLT_MAX_EXP; }    // maximum binary exponent
+
+   static Real LnMaximum()
+      { return (Real)log(Maximum()); } // natural log of maximum
+
+   static Real Minimum()
+      { return FLT_MIN; }        // minimum positive value
+
+   static int MinimumDecimalExponent()
+      { return FLT_MIN_10_EXP; } // minimum decimal exponent
+
+   static int MinimumExponent()
+      { return FLT_MIN_EXP; }    // minimum binary exponent
+
+   static Real LnMinimum()
+      { return (Real)log(Minimum()); } // natural log of minimum
+
+   static int Radix()
+      { return FLT_RADIX; }      // exponent radix
+
+   static int Rounds()
+      { return FLT_ROUNDS; }     // addition rounding (1 = does round)
+
+};
+
+#endif                           // USING_FLOAT
+
+
+#ifdef USING_DOUBLE
+
+/// Floating point precision (type double).
+class FloatingPointPrecision
+{
+public:
+
+   static int Dig()
+      { return DBL_DIG; }        // number of decimal digits or precision
+
+   static Real Epsilon()
+      { return DBL_EPSILON; }    // smallest number such that 1+Eps!=Eps
+
+   static int Mantissa()
+      { return DBL_MANT_DIG; }   // bits in mantisa
+
+   static Real Maximum()
+      { return DBL_MAX; }        // maximum value
+
+   static int MaximumDecimalExponent()
+      { return DBL_MAX_10_EXP; } // maximum decimal exponent
+
+   static int MaximumExponent()
+      { return DBL_MAX_EXP; }    // maximum binary exponent
+
+   static Real LnMaximum()
+      { return (Real)log(Maximum()); } // natural log of maximum
+
+   static Real Minimum()
+   {
+//#ifdef __BCPLUSPLUS__
+//       return 2.225074e-308;     // minimum positive value
+//#else
+       return DBL_MIN;
+//#endif
+   }
+
+   static int MinimumDecimalExponent()
+      { return DBL_MIN_10_EXP; } // minimum decimal exponent
+
+   static int MinimumExponent()
+      { return DBL_MIN_EXP; }    // minimum binary exponent
+
+   static Real LnMinimum()
+      { return (Real)log(Minimum()); } // natural log of minimum
+
+
+   static int Radix()
+      { return FLT_RADIX; }      // exponent radix
+
+   static int Rounds()
+      { return FLT_ROUNDS; }     // addition rounding (1 = does round)
+
+};
+
+#endif                             // USING_DOUBLE
+
+#else                              // if there is no float.h
+
+#ifdef OPT_COMPATIBLE
+#define FLT_MAX MAXFLOAT
+#endif
+
+
+#ifdef USING_FLOAT
+
+/// Floating point precision (type float).
+class FloatingPointPrecision
+{
+public:
+
+   static Real Epsilon()
+      { return pow(2.0,(int)(1-FSIGNIF)); }
+                                   // smallest number such that 1+Eps!=Eps
+
+   static Real Maximum()
+      { return MAXFLOAT; }            // maximum value
+
+   static Real LnMaximum()
+      { return (Real)log(Maximum()); }  // natural log of maximum
+
+   static Real Minimum()
+      { return MINFLOAT; }             // minimum positive value
+
+   static Real LnMinimum()
+      { return (Real)log(Minimum()); }  // natural log of minimum
+
+};
+
+#endif                                  // USING_FLOAT
+
+
+#ifdef USING_DOUBLE
+
+/// Floating point precision (type double).
+class FloatingPointPrecision
+{
+public:
+
+   static Real Epsilon()
+      { return pow(2.0,(int)(1-DSIGNIF)); }
+                                      // smallest number such that 1+Eps!=Eps
+
+   static Real Maximum()
+      { return MAXDOUBLE; }           // maximum value
+
+   static Real LnMaximum()
+      { return LN_MAXDOUBLE; }        // natural log of maximum
+
+   static Real Minimum()
+      { return MINDOUBLE; }
+
+   static Real LnMinimum()
+      { return LN_MINDOUBLE; }        // natural log of minimum
+};
+
+#endif                                // USING_DOUBLE
+
+#endif                                // SystemV
+
+#endif                                // _STANDARD_
+
+
+
+
+#ifdef use_namespace
+}
+#endif                                // use_namespace
+
+
+
+#endif                                // PRECISION_LIB
+
+
+///@}
Index: /nanovis/tags/1.1.4/newmat11/solution.cpp
===================================================================
--- /nanovis/tags/1.1.4/newmat11/solution.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/newmat11/solution.cpp	(revision 4930)
@@ -0,0 +1,205 @@
+/// \ingroup newmat
+///@{
+
+/// \file solution.cpp
+/// One dimensional solve routine.
+
+// Copyright (C) 1994: R B Davies
+
+
+#define WANT_STREAM                  // include.h will get stream fns
+#define WANT_MATH                    // include.h will get math fns
+
+#include "include.h"
+#include "myexcept.h"
+
+#include "solution.h"
+
+#ifdef use_namespace
+namespace RBD_COMMON {
+#endif
+
+
+void R1_R1::Set(Real X)
+{
+   if ((!minXinf && X <= minX) || (!maxXinf && X >= maxX))
+       Throw(SolutionException("X value out of range"));
+   x = X; xSet = true;
+}
+
+R1_R1::operator Real()
+{
+   if (!xSet) Throw(SolutionException("Value of X not set"));
+   Real y = operator()();
+   return y;
+}
+
+unsigned long SolutionException::Select;
+
+SolutionException::SolutionException(const char* a_what) : BaseException()
+{
+   Select = BaseException::Select;
+   AddMessage("Error detected by solution package\n");
+   AddMessage(a_what); AddMessage("\n");
+   if (a_what) Tracer::AddTrace();
+}
+
+inline Real square(Real x) { return x*x; }
+
+void OneDimSolve::LookAt(int V)
+{
+   lim--;
+   if (!lim) Throw(SolutionException("Does not converge"));
+   Last = V;
+   Real yy = function(x[V]) - YY;
+   Finish = (fabs(yy) <= accY) || (Captured && fabs(x[L]-x[U]) <= accX );
+   y[V] = vpol*yy;
+}
+
+void OneDimSolve::HFlip() { hpol=-hpol; State(U,C,L); }
+
+void OneDimSolve::VFlip()
+   { vpol = -vpol; y[0] = -y[0]; y[1] = -y[1]; y[2] = -y[2]; }
+
+void OneDimSolve::Flip()
+{
+   hpol=-hpol; vpol=-vpol; State(U,C,L);
+   y[0] = -y[0]; y[1] = -y[1]; y[2] = -y[2];
+}
+
+void OneDimSolve::State(int I, int J, int K) { L=I; C=J; U=K; }
+
+void OneDimSolve::Linear(int I, int J, int K)
+{
+   x[J] = (x[I]*y[K] - x[K]*y[I])/(y[K] - y[I]);
+   // cout << "Linear\n";
+}
+
+void OneDimSolve::Quadratic(int I, int J, int K)
+{
+   // result to overwrite I
+   Real YJK, YIK, YIJ, XKI, XKJ;
+   YJK = y[J] - y[K]; YIK = y[I] - y[K]; YIJ = y[I] - y[J];
+   XKI = (x[K] - x[I]);
+   XKJ = (x[K]*y[J] - x[J]*y[K])/YJK;
+   if ( square(YJK/YIK)>(x[K] - x[J])/XKI ||
+      square(YIJ/YIK)>(x[J] - x[I])/XKI )
+   {
+      x[I] = XKJ;
+      // cout << "Quadratic - exceptional\n";
+   }
+   else
+   {
+      XKI = (x[K]*y[I] - x[I]*y[K])/YIK;
+      x[I] = (XKJ*y[I] - XKI*y[J])/YIJ;
+      // cout << "Quadratic - normal\n";
+   }
+}
+
+Real OneDimSolve::Solve(Real Y, Real X, Real Dev, int Lim)
+{
+   enum Loop { start, captured1, captured2, binary, finish };
+   Tracer et("OneDimSolve::Solve");
+   lim=Lim; Captured = false;
+   if ( Dev == 0.0 ) Throw(SolutionException("Dev is zero"));
+   L=0; C=1; U=2; vpol=1; hpol=1; y[C]=0.0; y[U]=0.0;
+   if (Dev<0.0) { hpol=-1; Dev = -Dev; }
+   YY=Y;                                // target value
+   x[L] = X;                            // initial trial value
+   if (!function.IsValid(X))
+      Throw(SolutionException("Starting value is invalid"));
+   Loop TheLoop = start;
+   for (;;)
+   {
+      switch (TheLoop)
+      {
+      case start:
+         LookAt(L); if (Finish) { TheLoop = finish; break; }
+         if (y[L]>0.0) VFlip();               // so Y[L] < 0
+
+         x[U] = X + Dev * hpol;
+         if (!function.maxXinf && x[U] > function.maxX)
+            x[U] = (function.maxX + X) / 2.0;
+         if (!function.minXinf && x[U] < function.minX)
+            x[U] = (function.minX + X) / 2.0;
+
+         LookAt(U); if (Finish) { TheLoop = finish; break; }
+         if (y[U] > 0.0) { TheLoop = captured1; Captured = true; break; }
+         if (y[U] == y[L])
+            Throw(SolutionException("Function is flat"));
+         if (y[U] < y[L]) HFlip();             // Change direction
+         State(L,U,C);
+         for (i=0; i<20; i++)
+         {
+            // cout << "Searching for crossing point\n";
+            // Have L C then crossing point, Y[L]<Y[C]<0
+            x[U] = x[C] + Dev * hpol;
+            if (!function.maxXinf && x[U] > function.maxX)
+            x[U] = (function.maxX + x[C]) / 2.0;
+            if (!function.minXinf && x[U] < function.minX)
+            x[U] = (function.minX + x[C]) / 2.0;
+
+            LookAt(U); if (Finish) { TheLoop = finish; break; }
+            if (y[U] > 0) { TheLoop = captured2; Captured = true; break; }
+            if (y[U] < y[C])
+                Throw(SolutionException("Function is not monotone"));
+            Dev *= 2.0;
+            State(C,U,L);
+         }
+         if (TheLoop != start ) break;
+         Throw(SolutionException("Cannot locate a crossing point"));
+
+      case captured1:
+         // cout << "Captured - 1\n";
+         // We have 2 points L and U with crossing between them
+         Linear(L,C,U);                   // linear interpolation
+                                          // - result to C
+         LookAt(C); if (Finish) { TheLoop = finish; break; }
+         if (y[C] > 0.0) Flip();            // Want y[C] < 0
+         if (y[C] < 0.5*y[L]) { State(C,L,U); TheLoop = binary; break; }
+
+      case captured2:
+         // cout << "Captured - 2\n";
+         // We have L,C before crossing, U after crossing
+         Quadratic(L,C,U);                // quad interpolation
+                                          // - result to L
+         State(C,L,U);
+         if ((x[C] - x[L])*hpol <= 0.0 || (x[C] - x[U])*hpol >= 0.0)
+            { TheLoop = captured1; break; }
+         LookAt(C); if (Finish) { TheLoop = finish; break; }
+         // cout << "Through first stage\n";
+         if (y[C] > 0.0) Flip();
+         if (y[C] > 0.5*y[L]) { TheLoop = captured2; break; }
+         else { State(C,L,U); TheLoop = captured1; break; }
+
+      case binary:
+         // We have L, U around crossing - do binary search
+         // cout << "Binary\n";
+         for (i=3; i; i--)
+         {
+            x[C] = 0.5*(x[L]+x[U]);
+            LookAt(C); if (Finish) { TheLoop = finish; break; }
+            if (y[C]>0.0) State(L,U,C); else State(C,L,U);
+         }
+         if (TheLoop != binary) break;
+         TheLoop = captured1; break;
+
+      case finish:
+	 return x[Last];
+
+      }
+   }
+}
+
+bool R1_R1::IsValid(Real X)
+{
+   Set(X);
+   return (minXinf || x > minX) && (maxXinf || x < maxX);
+}
+
+#ifdef use_namespace
+}
+#endif
+
+
+///@}
Index: /nanovis/tags/1.1.4/newmat11/solution.h
===================================================================
--- /nanovis/tags/1.1.4/newmat11/solution.h	(revision 4930)
+++ /nanovis/tags/1.1.4/newmat11/solution.h	(revision 4930)
@@ -0,0 +1,99 @@
+/// \ingroup newmat
+///@{
+
+/// \file solution.h
+/// One dimensional solve routine.
+
+#include "myexcept.h"
+
+#ifdef use_namespace
+namespace RBD_COMMON {
+#endif
+
+
+// Solve the equation f(x)=y for x where f is a monotone continuous
+// function of x
+// Essentially Brent s method
+
+// You need to derive a class from R1_R1 and override "operator()"
+// with the function you want to solve.
+// Use an object from this class in OneDimSolve
+
+class R1_R1
+{
+   // the prototype for a Real function of a Real variable
+   // you need to derive your function from this one and put in your
+   // function for operator() at least. You probably also want to set up a
+   // constructor to put in additional parameter values (e.g. that will not
+   // vary during a solve)
+
+protected:
+   Real x;                             // Current x value
+   bool xSet;                          // true if a value assigned to x
+
+public:
+   Real minX, maxX;                    // range of value x
+   bool minXinf, maxXinf;              // true if these are infinite
+   R1_R1() : xSet(false), minXinf(true), maxXinf(true) {}
+   virtual Real operator()() = 0;      // function value at current x
+                                       // set current x
+   virtual void Set(Real X);           // set x, check OK
+   Real operator()(Real X) { Set(X); return operator()(); }
+                                       // set x, return value
+   virtual bool IsValid(Real X);
+   operator Real();                    // implicit conversion
+   virtual ~R1_R1() {}                 // keep gnu happy
+};
+
+class SolutionException : public BaseException
+{
+public:
+   static unsigned long Select;
+   SolutionException(const char* a_what = 0);
+};
+
+class OneDimSolve
+{
+   R1_R1& function;                     // reference to the function
+   Real accX;                           // accuracy in X direction
+   Real accY;                           // accuracy in Y direction
+   int lim;                             // maximum number of iterations
+
+public:
+   OneDimSolve(R1_R1& f, Real AccY = 0.0001, Real AccX = 0.0)
+      : function(f), accX(AccX), accY(AccY) {}
+                       // f is an R1_R1 function
+   Real Solve(Real Y, Real X, Real Dev, int Lim=100);
+                       // Solve for x in Y=f(x)
+                       // X is the initial trial value of x
+                       // X+Dev is the second trial value
+                       // program returns a value of x such that
+                       // |Y-f(x)| <= accY or |f.inv(Y)-x| <= accX
+
+private:
+   Real x[3], y[3];                         // Trial values of X and Y
+   int L,C,U,Last;                          // Locations of trial values
+   int vpol, hpol;                          // polarities
+   Real YY;                                 // target value
+   int i;
+   void LookAt(int);                        // get new value of function
+   bool Finish;                             // true if LookAt finds conv.
+   bool Captured;                           // true when target surrounded
+   void VFlip();
+   void HFlip();
+   void Flip();
+   void State(int I, int J, int K);
+   void Linear(int, int, int);
+   void Quadratic(int, int, int);
+};
+
+
+#ifdef use_namespace
+}
+#endif
+
+// body file: solution.cpp
+
+
+///@}
+
Index: /nanovis/tags/1.1.4/newmat11/sort.cpp
===================================================================
--- /nanovis/tags/1.1.4/newmat11/sort.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/newmat11/sort.cpp	(revision 4930)
@@ -0,0 +1,277 @@
+/// \ingroup newmat
+///@{
+
+/// \file sort.cpp
+/// Sorting functions.
+
+// Copyright (C) 1991,2,3,4: R B Davies
+
+#define WANT_MATH
+
+#include "include.h"
+
+#include "newmatap.h"
+
+#ifdef use_namespace
+namespace NEWMAT {
+#endif
+
+#ifdef DO_REPORT
+#define REPORT { static ExeCounter ExeCount(__LINE__,13); ++ExeCount; }
+#else
+#define REPORT {}
+#endif
+
+/******************************** Quick sort ********************************/
+
+// Quicksort.
+// Essentially the method described in Sedgewick s algorithms in C++
+// My version is still partially recursive, unlike Segewick s, but the
+// smallest segment of each split is used in the recursion, so it should
+// not overlead the stack.
+
+// If the process does not seems to be converging an exception is thrown.
+
+
+#define DoSimpleSort 17            // when to switch to insert sort
+#define MaxDepth 50                // maximum recursion depth
+
+static void MyQuickSortDescending(Real* first, Real* last, int depth);
+static void InsertionSortDescending(Real* first, const int length,
+   int guard);
+static Real SortThreeDescending(Real* a, Real* b, Real* c);
+
+static void MyQuickSortAscending(Real* first, Real* last, int depth);
+static void InsertionSortAscending(Real* first, const int length,
+   int guard);
+
+
+void sort_descending(GeneralMatrix& GM)
+{
+   REPORT
+   Tracer et("sort_descending");
+
+   Real* data = GM.Store(); int max = GM.Storage();
+
+   if (max > DoSimpleSort) MyQuickSortDescending(data, data + max - 1, 0);
+   InsertionSortDescending(data, max, DoSimpleSort);
+
+}
+
+static Real SortThreeDescending(Real* a, Real* b, Real* c)
+{
+   // sort *a, *b, *c; return *b; optimise for already sorted
+   if (*a >= *b)
+   {
+      if (*b >= *c) { REPORT return *b; }
+      else if (*a >= *c) { REPORT Real x = *c; *c = *b; *b = x; return x; }
+      else { REPORT Real x = *a; *a = *c; *c = *b; *b = x; return x; }
+   }
+   else if (*c >= *b) { REPORT Real x = *c; *c = *a; *a = x; return *b; }
+   else if (*a >= *c) { REPORT Real x = *a; *a = *b; *b = x; return x; }
+   else { REPORT Real x = *c; *c = *a; *a = *b; *b = x; return x; }
+}
+
+static void InsertionSortDescending(Real* first, const int length,
+   int guard)
+// guard gives the length of the sequence to scan to find first
+// element (eg = length)
+{
+   REPORT
+   if (length <= 1) return;
+
+   // scan for first element
+   Real* f = first; Real v = *f; Real* h = f;
+   if (guard > length) { REPORT guard = length; }
+   int i = guard - 1;
+   while (i--) if (v < *(++f)) { v = *f; h = f; }
+   *h = *first; *first = v;
+
+   // do the sort
+   i = length - 1; f = first;
+   while (i--)
+   {
+      Real* g = f++; h = f; v = *h;
+      while (*g < v) *h-- = *g--;
+      *h = v;
+   }
+}
+
+static void MyQuickSortDescending(Real* first, Real* last, int depth)
+{
+   REPORT
+   for (;;)
+   {
+      const int length = last - first + 1;
+      if (length < DoSimpleSort) { REPORT return; }
+      if (depth++ > MaxDepth)
+         Throw(ConvergenceException("QuickSortDescending fails: "));
+      Real* centre = first + length/2;
+      const Real test = SortThreeDescending(first, centre, last);
+      Real* f = first; Real* l = last;
+      for (;;)
+      {
+         while (*(++f) > test) {}
+         while (*(--l) < test) {}
+         if (l <= f) break;
+         const Real temp = *f; *f = *l; *l = temp;
+      }
+      if (f > centre)
+         { REPORT MyQuickSortDescending(l+1, last, depth); last = f-1; }
+      else { REPORT MyQuickSortDescending(first, f-1, depth); first = l+1; }
+   }
+}
+
+void sort_ascending(GeneralMatrix& GM)
+{
+   REPORT
+   Tracer et("sort_ascending");
+
+   Real* data = GM.Store(); int max = GM.Storage();
+
+   if (max > DoSimpleSort) MyQuickSortAscending(data, data + max - 1, 0);
+   InsertionSortAscending(data, max, DoSimpleSort);
+
+}
+
+static void InsertionSortAscending(Real* first, const int length,
+   int guard)
+// guard gives the length of the sequence to scan to find first
+// element (eg guard = length)
+{
+   REPORT
+   if (length <= 1) return;
+
+   // scan for first element
+   Real* f = first; Real v = *f; Real* h = f;
+   if (guard > length) { REPORT guard = length; }
+   int i = guard - 1;
+   while (i--) if (v > *(++f)) { v = *f; h = f; }
+   *h = *first; *first = v;
+
+   // do the sort
+   i = length - 1; f = first;
+   while (i--)
+   {
+      Real* g = f++; h = f; v = *h;
+      while (*g > v) *h-- = *g--;
+      *h = v;
+   }
+}
+static void MyQuickSortAscending(Real* first, Real* last, int depth)
+{
+   REPORT
+   for (;;)
+   {
+      const int length = last - first + 1;
+      if (length < DoSimpleSort) { REPORT return; }
+      if (depth++ > MaxDepth)
+         Throw(ConvergenceException("QuickSortAscending fails: "));
+      Real* centre = first + length/2;
+      const Real test = SortThreeDescending(last, centre, first);
+      Real* f = first; Real* l = last;
+      for (;;)
+      {
+         while (*(++f) < test) {}
+         while (*(--l) > test) {}
+         if (l <= f) break;
+         const Real temp = *f; *f = *l; *l = temp;
+      }
+      if (f > centre)
+         { REPORT MyQuickSortAscending(l+1, last, depth); last = f-1; }
+      else { REPORT MyQuickSortAscending(first, f-1, depth); first = l+1; }
+   }
+}
+
+//********* sort diagonal matrix & rearrange matrix columns ****************
+
+// used by SVD
+
+// these are for sorting singular values - should be updated with faster
+// sorts that handle exchange of columns better
+// however time is probably not significant compared with SVD time
+
+void SortSV(DiagonalMatrix& D, Matrix& U, bool ascending)
+{
+   REPORT
+   Tracer trace("SortSV_DU");
+   int m = U.Nrows(); int n = U.Ncols();
+   if (n != D.Nrows()) Throw(IncompatibleDimensionsException(D,U));
+   Real* u = U.Store();
+   for (int i=0; i<n; i++)
+   {
+      int k = i; Real p = D.element(i);
+      if (ascending)
+      {
+         for (int j=i+1; j<n; j++)
+            { if (D.element(j) < p) { k = j; p = D.element(j); } }
+      }
+      else
+      {
+         for (int j=i+1; j<n; j++)
+         { if (D.element(j) > p) { k = j; p = D.element(j); } }
+      }
+      if (k != i)
+      {
+         D.element(k) = D.element(i); D.element(i) = p; int j = m;
+         Real* uji = u + i; Real* ujk = u + k;
+         if (j) for(;;)
+         {
+            p = *uji; *uji = *ujk; *ujk = p;
+            if (!(--j)) break;
+            uji += n; ujk += n;
+         }
+      }
+   }
+}
+
+void SortSV(DiagonalMatrix& D, Matrix& U, Matrix& V, bool ascending)
+{
+   REPORT
+   Tracer trace("SortSV_DUV");
+   int mu = U.Nrows(); int mv = V.Nrows(); int n = D.Nrows();
+   if (n != U.Ncols()) Throw(IncompatibleDimensionsException(D,U));
+   if (n != V.Ncols()) Throw(IncompatibleDimensionsException(D,V));
+   Real* u = U.Store(); Real* v = V.Store();
+   for (int i=0; i<n; i++)
+   {
+      int k = i; Real p = D.element(i);
+      if (ascending)
+      {
+         for (int j=i+1; j<n; j++)
+            { if (D.element(j) < p) { k = j; p = D.element(j); } }
+      }
+      else
+      {
+         for (int j=i+1; j<n; j++)
+         { if (D.element(j) > p) { k = j; p = D.element(j); } }
+      }
+      if (k != i)
+      {
+         D.element(k) = D.element(i); D.element(i) = p;
+         Real* uji = u + i; Real* ujk = u + k;
+         Real* vji = v + i; Real* vjk = v + k;
+         int j = mu;
+         if (j) for(;;)
+         {
+            p = *uji; *uji = *ujk; *ujk = p; if (!(--j)) break;
+            uji += n; ujk += n;
+         }
+         j = mv;
+         if (j) for(;;)
+         {
+            p = *vji; *vji = *vjk; *vjk = p; if (!(--j)) break;
+            vji += n; vjk += n;
+         }
+      }
+   }
+}
+
+
+
+
+#ifdef use_namespace
+}
+#endif
+
+///@}
Index: /nanovis/tags/1.1.4/newmat11/submat.cpp
===================================================================
--- /nanovis/tags/1.1.4/newmat11/submat.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/newmat11/submat.cpp	(revision 4930)
@@ -0,0 +1,363 @@
+/// \ingroup newmat
+///@{
+
+/// \file submat.cpp
+/// Submatrix manipulation.
+
+// Copyright (C) 1991,2,3,4: R B Davies
+
+#include "include.h"
+
+#include "newmat.h"
+#include "newmatrc.h"
+
+#ifdef use_namespace
+namespace NEWMAT {
+#endif
+
+#ifdef DO_REPORT
+#define REPORT { static ExeCounter ExeCount(__LINE__,11); ++ExeCount; }
+#else
+#define REPORT {}
+#endif
+
+
+/****************************** submatrices *********************************/
+
+GetSubMatrix BaseMatrix::submatrix(int first_row, int last_row, int first_col,
+   int last_col) const
+{
+   REPORT
+   Tracer tr("submatrix");
+   int a = first_row - 1; int b = last_row - first_row + 1;
+   int c = first_col - 1; int d = last_col - first_col + 1;
+   if (a<0 || b<0 || c<0 || d<0) Throw(SubMatrixDimensionException());
+                             // allow zero rows or columns
+   return GetSubMatrix(this, a, b, c, d, false);
+}
+
+GetSubMatrix BaseMatrix::sym_submatrix(int first_row, int last_row) const
+{
+   REPORT
+   Tracer tr("sym_submatrix");
+   int a = first_row - 1; int b = last_row - first_row + 1;
+   if (a<0 || b<0) Throw(SubMatrixDimensionException());
+                             // allow zero rows or columns
+   return GetSubMatrix( this, a, b, a, b, true);
+}
+
+GetSubMatrix BaseMatrix::row(int first_row) const
+{
+   REPORT
+   Tracer tr("SubMatrix(row)");
+   int a = first_row - 1;
+   if (a<0) Throw(SubMatrixDimensionException());
+   return GetSubMatrix(this, a, 1, 0, -1, false);
+}
+
+GetSubMatrix BaseMatrix::rows(int first_row, int last_row) const
+{
+   REPORT
+   Tracer tr("SubMatrix(rows)");
+   int a = first_row - 1; int b = last_row - first_row + 1;
+   if (a<0 || b<0) Throw(SubMatrixDimensionException());
+                             // allow zero rows or columns
+   return GetSubMatrix(this, a, b, 0, -1, false);
+}
+
+GetSubMatrix BaseMatrix::column(int first_col) const
+{
+   REPORT
+   Tracer tr("SubMatrix(column)");
+   int c = first_col - 1;
+   if (c<0) Throw(SubMatrixDimensionException());
+   return GetSubMatrix(this, 0, -1, c, 1, false);
+}
+
+GetSubMatrix BaseMatrix::columns(int first_col, int last_col) const
+{
+   REPORT
+   Tracer tr("SubMatrix(columns)");
+   int c = first_col - 1; int d = last_col - first_col + 1;
+   if (c<0 || d<0) Throw(SubMatrixDimensionException());
+                             // allow zero rows or columns
+   return GetSubMatrix(this, 0, -1, c, d, false);
+}
+
+void GetSubMatrix::SetUpLHS()
+{
+   REPORT
+   Tracer tr("SubMatrix(LHS)");
+   const BaseMatrix* bm1 = bm;
+   GeneralMatrix* gm1 = ((BaseMatrix*&)bm)->Evaluate();
+   if ((BaseMatrix*)gm1!=bm1)
+      Throw(ProgramException("Invalid LHS"));
+   if (row_number < 0) row_number = gm1->Nrows();
+   if (col_number < 0) col_number = gm1->Ncols();
+   if (row_skip+row_number > gm1->Nrows()
+      || col_skip+col_number > gm1->Ncols())
+         Throw(SubMatrixDimensionException());
+}
+
+void GetSubMatrix::operator<<(const BaseMatrix& bmx)
+{
+   REPORT
+   Tracer tr("SubMatrix(<<)"); GeneralMatrix* gmx = 0;
+   Try
+   {
+      SetUpLHS(); gmx = ((BaseMatrix&)bmx).Evaluate();
+      if (row_number != gmx->Nrows() || col_number != gmx->Ncols())
+         Throw(IncompatibleDimensionsException());
+      MatrixRow mrx(gmx, LoadOnEntry);
+      MatrixRow mr(gm, LoadOnEntry+StoreOnExit+DirectPart, row_skip);
+                                     // do need LoadOnEntry
+      MatrixRowCol sub; int i = row_number;
+      while (i--)
+      {
+         mr.SubRowCol(sub, col_skip, col_number);   // put values in sub
+         sub.Copy(mrx); mr.Next(); mrx.Next();
+      }
+      gmx->tDelete();
+   }
+
+   CatchAll
+   {
+      if (gmx) gmx->tDelete();
+      ReThrow;
+   }
+}
+
+void GetSubMatrix::operator=(const BaseMatrix& bmx)
+{
+   REPORT
+   Tracer tr("SubMatrix(=)"); GeneralMatrix* gmx = 0;
+   // MatrixConversionCheck mcc;         // Check for loss of info
+   Try
+   {
+      SetUpLHS(); gmx = ((BaseMatrix&)bmx).Evaluate();
+      if (row_number != gmx->Nrows() || col_number != gmx->Ncols())
+         Throw(IncompatibleDimensionsException());
+      LoadAndStoreFlag lasf =
+         (  row_skip == col_skip
+            && gm->type().is_symmetric()
+            && gmx->type().is_symmetric() )
+        ? LoadOnEntry+DirectPart
+        : LoadOnEntry;
+      MatrixRow mrx(gmx, lasf);
+      MatrixRow mr(gm, LoadOnEntry+StoreOnExit+DirectPart, row_skip);
+                                     // do need LoadOnEntry
+      MatrixRowCol sub; int i = row_number;
+      while (i--)
+      {
+         mr.SubRowCol(sub, col_skip, col_number);   // put values in sub
+         sub.CopyCheck(mrx); mr.Next(); mrx.Next();
+      }
+      gmx->tDelete();
+   }
+
+   CatchAll
+   {
+      if (gmx) gmx->tDelete();
+      ReThrow;
+   }
+}
+
+void GetSubMatrix::operator<<(const double* r)
+{
+   REPORT
+   Tracer tr("SubMatrix(<<double*)");
+   SetUpLHS();
+   if (row_skip+row_number > gm->Nrows() || col_skip+col_number > gm->Ncols())
+      Throw(SubMatrixDimensionException());
+   MatrixRow mr(gm, LoadOnEntry+StoreOnExit+DirectPart, row_skip);
+                                  // do need LoadOnEntry
+   MatrixRowCol sub; int i = row_number;
+   while (i--)
+   {
+      mr.SubRowCol(sub, col_skip, col_number);   // put values in sub
+      sub.Copy(r); mr.Next();
+   }
+}
+
+void GetSubMatrix::operator<<(const float* r)
+{
+   REPORT
+   Tracer tr("SubMatrix(<<float*)");
+   SetUpLHS();
+   if (row_skip+row_number > gm->Nrows() || col_skip+col_number > gm->Ncols())
+      Throw(SubMatrixDimensionException());
+   MatrixRow mr(gm, LoadOnEntry+StoreOnExit+DirectPart, row_skip);
+                                  // do need LoadOnEntry
+   MatrixRowCol sub; int i = row_number;
+   while (i--)
+   {
+      mr.SubRowCol(sub, col_skip, col_number);   // put values in sub
+      sub.Copy(r); mr.Next();
+   }
+}
+
+void GetSubMatrix::operator<<(const int* r)
+{
+   REPORT
+   Tracer tr("SubMatrix(<<int*)");
+   SetUpLHS();
+   if (row_skip+row_number > gm->Nrows() || col_skip+col_number > gm->Ncols())
+      Throw(SubMatrixDimensionException());
+   MatrixRow mr(gm, LoadOnEntry+StoreOnExit+DirectPart, row_skip);
+                                  // do need LoadOnEntry
+   MatrixRowCol sub; int i = row_number;
+   while (i--)
+   {
+      mr.SubRowCol(sub, col_skip, col_number);   // put values in sub
+      sub.Copy(r); mr.Next();
+   }
+}
+
+void GetSubMatrix::operator=(Real r)
+{
+   REPORT
+   Tracer tr("SubMatrix(=Real)");
+   SetUpLHS();
+   MatrixRow mr(gm, LoadOnEntry+StoreOnExit+DirectPart, row_skip);
+                                  // do need LoadOnEntry
+   MatrixRowCol sub; int i = row_number;
+   while (i--)
+   {
+      mr.SubRowCol(sub, col_skip, col_number);   // put values in sub
+      sub.Copy(r); mr.Next();
+   }
+}
+
+void GetSubMatrix::inject(const GeneralMatrix& gmx)
+{
+   REPORT
+   Tracer tr("SubMatrix(inject)");
+   SetUpLHS();
+   if (row_number != gmx.Nrows() || col_number != gmx.Ncols())
+      Throw(IncompatibleDimensionsException());
+   MatrixRow mrx((GeneralMatrix*)(&gmx), LoadOnEntry);
+   MatrixRow mr(gm, LoadOnEntry+StoreOnExit+DirectPart, row_skip);
+                                  // do need LoadOnEntry
+   MatrixRowCol sub; int i = row_number;
+   while (i--)
+   {
+      mr.SubRowCol(sub, col_skip, col_number);   // put values in sub
+      sub.Inject(mrx); mr.Next(); mrx.Next();
+   }
+}
+
+void GetSubMatrix::operator+=(const BaseMatrix& bmx)
+{
+   REPORT
+   Tracer tr("SubMatrix(+=)"); GeneralMatrix* gmx = 0;
+   // MatrixConversionCheck mcc;         // Check for loss of info
+   Try
+   {
+      SetUpLHS(); gmx = ((BaseMatrix&)bmx).Evaluate();
+      if (row_number != gmx->Nrows() || col_number != gmx->Ncols())
+         Throw(IncompatibleDimensionsException());
+      MatrixRow mrx(gmx, LoadOnEntry);
+      MatrixRow mr(gm, LoadOnEntry+StoreOnExit+DirectPart, row_skip);
+                                     // do need LoadOnEntry
+      MatrixRowCol sub; int i = row_number;
+      while (i--)
+      {
+         mr.SubRowCol(sub, col_skip, col_number);   // put values in sub
+         sub.Check(mrx);                            // check for loss of info
+         sub.Add(mrx); mr.Next(); mrx.Next();
+      }
+      gmx->tDelete();
+   }
+
+   CatchAll
+   {
+      if (gmx) gmx->tDelete();
+      ReThrow;
+   }
+}
+
+void GetSubMatrix::operator-=(const BaseMatrix& bmx)
+{
+   REPORT
+   Tracer tr("SubMatrix(-=)"); GeneralMatrix* gmx = 0;
+   // MatrixConversionCheck mcc;         // Check for loss of info
+   Try
+   {
+      SetUpLHS(); gmx = ((BaseMatrix&)bmx).Evaluate();
+      if (row_number != gmx->Nrows() || col_number != gmx->Ncols())
+         Throw(IncompatibleDimensionsException());
+      MatrixRow mrx(gmx, LoadOnEntry);
+      MatrixRow mr(gm, LoadOnEntry+StoreOnExit+DirectPart, row_skip);
+                                     // do need LoadOnEntry
+      MatrixRowCol sub; int i = row_number;
+      while (i--)
+      {
+         mr.SubRowCol(sub, col_skip, col_number);   // put values in sub
+         sub.Check(mrx);                            // check for loss of info
+         sub.Sub(mrx); mr.Next(); mrx.Next();
+      }
+      gmx->tDelete();
+   }
+
+   CatchAll
+   {
+      if (gmx) gmx->tDelete();
+      ReThrow;
+   }
+}
+
+void GetSubMatrix::operator+=(Real r)
+{
+   REPORT
+   Tracer tr("SubMatrix(+= or -= Real)");
+   // MatrixConversionCheck mcc;         // Check for loss of info
+   Try
+   {
+      SetUpLHS();
+      MatrixRow mr(gm, LoadOnEntry+StoreOnExit+DirectPart, row_skip);
+                                     // do need LoadOnEntry
+      MatrixRowCol sub; int i = row_number;
+      while (i--)
+      {
+         mr.SubRowCol(sub, col_skip, col_number);   // put values in sub
+         sub.Check();                               // check for loss of info
+         sub.Add(r); mr.Next();
+      }
+   }
+
+   CatchAll
+   {
+      ReThrow;
+   }
+}
+
+void GetSubMatrix::operator*=(Real r)
+{
+   REPORT
+   Tracer tr("SubMatrix(*= or /= Real)");
+   // MatrixConversionCheck mcc;         // Check for loss of info
+   Try
+   {
+      SetUpLHS();
+      MatrixRow mr(gm, LoadOnEntry+StoreOnExit+DirectPart, row_skip);
+                                     // do need LoadOnEntry
+      MatrixRowCol sub; int i = row_number;
+      while (i--)
+      {
+         mr.SubRowCol(sub, col_skip, col_number);   // put values in sub
+         sub.Multiply(r); mr.Next();
+      }
+   }
+
+   CatchAll
+   {
+      ReThrow;
+   }
+}
+
+#ifdef use_namespace
+}
+#endif
+
+///@}
+
Index: /nanovis/tags/1.1.4/newmat11/svd.cpp
===================================================================
--- /nanovis/tags/1.1.4/newmat11/svd.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/newmat11/svd.cpp	(revision 4930)
@@ -0,0 +1,209 @@
+/// \ingroup newmat
+///@{
+
+/// \file svd.cpp
+/// Singular value decomposition.
+
+// Copyright (C) 1991,2,3,4,5: R B Davies
+// Updated 17 July, 1995
+
+#define WANT_MATH
+
+#include "include.h"
+#include "newmatap.h"
+#include "newmatrm.h"
+#include "precisio.h"
+
+#ifdef use_namespace
+namespace NEWMAT {
+#endif
+
+#ifdef DO_REPORT
+#define REPORT { static ExeCounter ExeCount(__LINE__,15); ++ExeCount; }
+#else
+#define REPORT {}
+#endif
+
+
+
+
+void SVD(const Matrix& A, DiagonalMatrix& Q, Matrix& U, Matrix& V,
+   bool withU, bool withV)
+// from Wilkinson and Reinsch: "Handbook of Automatic Computation"
+{
+   REPORT
+   Tracer trace("SVD");
+   Real eps = FloatingPointPrecision::Epsilon();
+   Real tol = FloatingPointPrecision::Minimum()/eps;
+
+   int m = A.Nrows(); int n = A.Ncols();
+   if (m<n)
+      Throw(ProgramException("Want no. Rows >= no. Cols", A));
+   if (withV && &U == &V)
+      Throw(ProgramException("Need different matrices for U and V", U, V));
+   U = A; Real g = 0.0; Real f,h; Real x = 0.0; int i;
+   RowVector E(n); RectMatrixRow EI(E,0); Q.ReSize(n);
+   RectMatrixCol UCI(U,0); RectMatrixRow URI(U,0,1,n-1);
+
+   if (n) for (i=0;;)
+   {
+      EI.First() = g; Real ei = g; EI.Right(); Real s = UCI.SumSquare();
+      if (s<tol) { REPORT Q.element(i) = 0.0; }
+      else
+      {
+         REPORT
+         f = UCI.First(); g = -sign(sqrt(s), f); h = f*g-s; UCI.First() = f-g;
+         Q.element(i) = g; RectMatrixCol UCJ = UCI; int j=n-i;
+         while (--j) { UCJ.Right(); UCJ.AddScaled(UCI, (UCI*UCJ)/h); }
+      }
+
+      s = URI.SumSquare();
+      if (s<tol) { REPORT g = 0.0; }
+      else
+      {
+         REPORT
+         f = URI.First(); g = -sign(sqrt(s), f); URI.First() = f-g;
+         EI.Divide(URI,f*g-s); RectMatrixRow URJ = URI; int j=m-i;
+         while (--j) { URJ.Down(); URJ.AddScaled(EI, URI*URJ); }
+      }
+
+      Real y = fabs(Q.element(i)) + fabs(ei); if (x<y) { REPORT x = y; }
+      if (++i == n) { REPORT break; }
+      UCI.DownDiag(); URI.DownDiag();
+   }
+
+   if (withV)
+   {
+      REPORT
+      V.ReSize(n,n); V = 0.0; RectMatrixCol VCI(V,n-1,n-1,1);
+      if (n) { VCI.First() = 1.0; g=E.element(n-1); if (n!=1) URI.UpDiag(); }
+      for (i=n-2; i>=0; i--)
+      {
+         VCI.Left();
+         if (g!=0.0)
+         {
+            VCI.Divide(URI, URI.First()*g); int j = n-i;
+            RectMatrixCol VCJ = VCI;
+            while (--j) { VCJ.Right(); VCJ.AddScaled( VCI, (URI*VCJ) ); }
+         }
+         VCI.Zero(); VCI.Up(); VCI.First() = 1.0; g=E.element(i);
+         if (i==0) break;
+         URI.UpDiag();
+      }
+   }
+
+   if (withU)
+   {
+      REPORT
+      for (i=n-1; i>=0; i--)
+      {
+         g = Q.element(i); URI.Reset(U,i,i+1,n-i-1); URI.Zero();
+         if (g!=0.0)
+         {
+            h=UCI.First()*g; int j=n-i; RectMatrixCol UCJ = UCI;
+            while (--j)
+            {
+               UCJ.Right(); UCI.Down(); UCJ.Down(); Real s = UCI*UCJ;
+               UCI.Up(); UCJ.Up(); UCJ.AddScaled(UCI,s/h);
+            }
+            UCI.Divide(g);
+         }
+         else UCI.Zero();
+         UCI.First() += 1.0;
+         if (i==0) break;
+         UCI.UpDiag();
+      }
+   }
+
+   eps *= x;
+   for (int k=n-1; k>=0; k--)
+   {
+      Real z = -FloatingPointPrecision::Maximum(); // to keep Gnu happy
+      Real y; int limit = 50; int l = 0;
+      while (limit--)
+      {
+         Real c, s; int i; int l1=k; bool tfc=false;
+         for (l=k; l>=0; l--)
+         {
+//          if (fabs(E.element(l))<=eps) goto test_f_convergence;
+            if (fabs(E.element(l))<=eps) { REPORT tfc=true; break; }
+            if (fabs(Q.element(l-1))<=eps) { REPORT l1=l; break; }
+            REPORT
+         }
+         if (!tfc)
+         {
+            REPORT
+            l=l1; l1=l-1; s = -1.0; c = 0.0;
+            for (i=l; i<=k; i++)
+            {
+               f = - s * E.element(i); E.element(i) *= c;
+//             if (fabs(f)<=eps) goto test_f_convergence;
+               if (fabs(f)<=eps) { REPORT break; }
+               g = Q.element(i); h = pythag(g,f,c,s); Q.element(i) = h;
+               if (withU)
+               {
+                  REPORT
+                  RectMatrixCol UCI(U,i); RectMatrixCol UCJ(U,l1);
+                  ComplexScale(UCJ, UCI, c, s);
+               }
+            }
+         }
+//       test_f_convergence: z = Q.element(k); if (l==k) goto convergence;
+         z = Q.element(k);  if (l==k) { REPORT break; }
+
+         x = Q.element(l); y = Q.element(k-1);
+         g = E.element(k-1); h = E.element(k);
+         f = ((y-z)*(y+z) + (g-h)*(g+h)) / (2*h*y);
+         if (f>1)         { REPORT g = f * sqrt(1 + square(1/f)); }
+         else if (f<-1)   { REPORT g = -f * sqrt(1 + square(1/f)); }
+         else             { REPORT g = sqrt(f*f + 1); }
+            { REPORT f = ((x-z)*(x+z) + h*(y / ((f<0.0) ? f-g : f+g)-h)) / x; }
+
+         c = 1.0; s = 1.0;
+         for (i=l+1; i<=k; i++)
+         {
+            g = E.element(i); y = Q.element(i); h = s*g; g *= c;
+            z = pythag(f,h,c,s); E.element(i-1) = z;
+            f = x*c + g*s; g = -x*s + g*c; h = y*s; y *= c;
+            if (withV)
+            {
+               REPORT
+               RectMatrixCol VCI(V,i); RectMatrixCol VCJ(V,i-1);
+               ComplexScale(VCI, VCJ, c, s);
+            }
+            z = pythag(f,h,c,s); Q.element(i-1) = z;
+            f = c*g + s*y; x = -s*g + c*y;
+            if (withU)
+            {
+               REPORT
+               RectMatrixCol UCI(U,i); RectMatrixCol UCJ(U,i-1);
+               ComplexScale(UCI, UCJ, c, s);
+            }
+         }
+         E.element(l) = 0.0; E.element(k) = f; Q.element(k) = x;
+      }
+      if (l!=k) { Throw(ConvergenceException(A)); }
+// convergence:
+      if (z < 0.0)
+      {
+         REPORT
+         Q.element(k) = -z;
+         if (withV) { RectMatrixCol VCI(V,k); VCI.Negate(); }
+      }
+   }
+   if (withU & withV) SortSV(Q, U, V);
+   else if (withU) SortSV(Q, U);
+   else if (withV) SortSV(Q, V);
+   else sort_descending(Q);
+}
+
+void SVD(const Matrix& A, DiagonalMatrix& D)
+{ REPORT Matrix U; SVD(A, D, U, U, false, false); }
+
+
+
+#ifdef use_namespace
+}
+#endif
+
+///@}
Index: /nanovis/tags/1.1.4/nvconf.h.in
===================================================================
--- /nanovis/tags/1.1.4/nvconf.h.in	(revision 4930)
+++ /nanovis/tags/1.1.4/nvconf.h.in	(revision 4930)
@@ -0,0 +1,94 @@
+/* nvconf.h.in.  Generated from configure.in by autoheader.  */
+
+/* Define if building universal (internal helper macro) */
+#undef AC_APPLE_UNIVERSAL_BUILD
+
+/* Define to 1 if you have the `accept4' function. */
+#undef HAVE_ACCEPT4
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#undef HAVE_ARPA_INET_H
+
+/* nanovis can use avconv to create videos. */
+#undef HAVE_AVCONV
+
+/* Define to 1 if you have the <Cg/cgGL.h> header file. */
+#undef HAVE_CG_CGGL_H
+
+/* nanovis can use ffmpeg to create videos. */
+#undef HAVE_FFMPEG
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#undef HAVE_NETDB_H
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#undef HAVE_NETINET_IN_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#undef HAVE_STDIO_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#undef HAVE_SYS_SOCKET_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+   significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+#  define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+#  undef WORDS_BIGENDIAN
+# endif
+#endif
Index: /nanovis/tags/1.1.4/protocol-nanovis.txt
===================================================================
--- /nanovis/tags/1.1.4/protocol-nanovis.txt	(revision 4930)
+++ /nanovis/tags/1.1.4/protocol-nanovis.txt	(revision 4930)
@@ -0,0 +1,229 @@
+================================================================================
+
+ Copyright (C) 2004-2013  HUBzero Foundation, LLC
+
+================================================================================
+Protocol for nanovis render server.  
+
+Commands take the general form of command and arguments using Tcl syntax and are
+terminated by a newline.  Some command arguments expect a Tcl list which can be
+sent by enclosing the list in curly braces to prevent the interpreter from 
+splitting the list into multiple arguments.  Likewise, strings with spaces 
+should be quoted or enclosed in curly braces.  In the documentation below,
+arguments are indicated by angle brackets and optional arguments are surrounded
+by question marks -- the brackets and question marks are not part of the
+protocol and should not be included in argument strings.  The arguments shown 
+in angle brackets should be replaced with a string (where there are fixed 
+choices this document indicates valid values by separating them with pipe 
+symbols), a list in Tcl syntax, or a numeric value.  Boolean arguments can take
+the form of 0|1, true|false, or yes|no.  Since the protocol commands are 
+executed in a Tcl interpreter, Tcl code such as math expressions in expr 
+commands enclosed in square brackets are also allowed.  Since the interpreter
+is a "safe" interpreter, some Tcl commands that could cause security issues may 
+not be available for use.
+
+Some commands such as the 'flowvis add' commands create Tcl objects within the
+server's interpreter.  The name sent as an argument when adding the object can 
+then be used as a protocol command.  For example, the string sent as the <name>
+argument to 'flowvis add' can then be used in place of <flowObj> in the commands
+documented below.  The flow object name also creates a volume name that can 
+be used in volume and cutplane commands, but in that case the name is used as
+an argument to the volume or cutplane commands rather than as the command 
+itself.
+
+When binary data is to be sent, it should follow the newline after a command 
+that indicates incoming data including a byte count argument.
+================================================================================
+================================================================================
+Requests:
+================================================================================
+axis visible <bool> 
+
+camera angle <xAngle> <yAngle> <zAngle>
+       ** Deprecated, use camera orient **
+camera orient <quatW> <quatX> <quatY> <quatZ>
+camera pan <x> <y>
+camera pos <x> <y> <z>
+camera reset <?all?>
+camera zoom <factor>
+
+clientinfo <list>
+
+cutplane position <relval> <x|y|z> <?names?>
+         Set the position of a volume cutplane.  Names is
+         an optional list of volume names.
+         relval = [0,1]
+cutplane state <bool> <x|y|z> <?names?>
+         Set the axis (normal) of a volume cutplane.  Names is
+         an optional list of volume names.
+cutplane visible <bool> <?names?>
+         Set visibility of all (x,y, and z) cutplanes for
+         named volume(s)
+
+flow add <name> <?option value...?>
+         <name> is an object name to use in <flowObj> commands
+         In addition, a volume is added with the same name
+         which can be used in volume and cutplane commands
+         see '<flowObj> configure' for switch options
+flow delete <names>
+flow exists <name>
+     This doesn't currently produce a response, it only returns a boolean
+     within the server's interpreter
+flow goto <nSteps>
+flow names
+     This doesn't currently produce a response, it only returns a Tcl list
+     within the server's interpreter
+flow next
+flow reset
+flow video <token> <?switches...?>
+     -bitrate <val>
+     -format <mpeg|theora|mov>
+     -framerate <val>
+     -height <val>
+     -numframes <val>
+     -width <val>
+
+<flowObj> box add <name> <?switches...?>
+          See '<flowObj> box configure' for switches
+<flowObj> box configure <name> <?switches...?>
+         -color <{r g b a}>
+         -corner1 <{x y z}>
+         -corner2 <{x y z}>
+         -hide <bool>
+         -linewidth <val>
+<flowObj> box delete <names>
+<flowObj> box names
+          This doesn't currently produce a response, it only returns a Tcl list
+          within the server's interpreter
+<flowObj> configure <?option value...?>
+          -ambient <val>
+          -arrows <bool>
+          -axis <x|y|z>
+          -diffuse <val>
+          -hide <bool>
+          -light2side <bool>
+          -opacity <val>
+          -outline <bool>
+          -position <val|val%>
+           val = [0,1], or val% = [0,100]
+          -slice <bool>
+          -specularExp <val>
+          -specularLevel <val>
+          -transferfunction <name>
+          -volume <bool>
+<flowObj> data follows <nbytes> <numComponents>
+          Send flow data.  Data bytes follow the newline after the command
+<flowObj> legend <w> <h>
+<flowObj> particles add <name> <?switches?>
+          see '<flowObj> particles configure' for switches
+<flowObj> particles configure <name> <?switches?>
+          -axis <x|y|z>
+          -color <{r g b a}>
+          -hide <bool>
+          -position <val|val%>
+           val = [0,1], or val% = [0,100]
+          -size <val>
+<flowObj> particles delete <names>
+<flowObj> particles names
+          This doesn't currently produce a response, it only returns a Tcl list
+          within the server's interpreter
+
+grid axiscolor <red> <green> <blue> <?alpha?>
+grid axisname <x|y|z> <name> <units>
+grid linecolor <red> <green> <blue> <?alpha?>
+grid visible <bool>
+
+heightmap create <heightmapName> <xMin> <yMin> <xMax> <yMax> <xNum> <yNum> <valueList>
+heightmap cull <none|back|front>
+heightmap data follows <nBytes> <heightmapName>
+          After newline following command, nBytes of data are sent
+heightmap data visible <bool> <?heightmapNames?>
+heightmap legend <heightmapName> <width> <height>
+heightmap linecontour color <red> <green> <blue> <?heightmapNames?>
+heightmap linecontour visible <bool> <?heightmapNames?>
+heightmap opacity <value> <?heightmapNames?>
+heightmap polygon <wireframe|fill> 
+          **Warning: This is a global setting**
+heightmap shading <flat|smooth>
+          **Warning: This is a global setting**
+heightmap transfunc <transferFunctionName> <?heightmapNames?>
+
+legend <transferfunc name> <width> <height>
+       Request render of transfer function
+
+screen bgcolor <r> <g> <b>
+       Set screen background color
+screen size <width> <height>
+       Set size of rendered images
+
+snapshot
+         Render a 2k x 2k image (offscreen buffer).  Response image data is
+         tagged as '-type print'
+
+transfunc define <name> {colors} {alpha}
+          colors => 1 line each of "value r g b"
+          alpha => 1 line each of "value alpha"
+          value => [0,1]
+
+up <x|y|z|-x|-y|-z>
+   Set orientation of volumes
+
+volume animation capture <numframes> <?filename?>
+       This is not fully implemented.  Rendered frames are not returned
+       to the client.
+volume animation clear
+volume animation start
+volume animation stop
+volume animation volumes <?names?>
+
+volume data follows <nbytes> <name>
+volume data state <bool> <?names?>
+volume delete <names>
+volume exists <name>
+       This doesn't currently produce a response, it only returns a boolean
+       within the server's interpreter
+volume names
+       This doesn't currently produce a response, it only returns a Tcl list
+       within the server's interpreter
+volume outline color <r> <g> <b> <?names?>
+volume outline state <bool> <?names?>
+volume outline visible <bool> <?names?>
+volume shading ambient <value> <?names?>
+volume shading diffuse <value> <?names?>
+volume shading isosurface <bool> <?names?>
+volume shading light2side <bool> <?names?>
+volume shading opacity <value> <?names?>
+volume shading specularExp <value> <?names?>
+volume shading specularLevel <value> <?names?>
+volume shading transfunc <tfName> <?names?>
+volume state <bool> <?names?>
+
+================================================================================
+Replies:
+================================================================================
+nv>legend <volume> <min> <max> <nbytes>
+  (followed by bytes)
+
+nv>image -type image -bytes <nbytes>
+  (followed by bytes)
+
+nv>image -type print -bytes <nbytes>
+  (followed by bytes)
+
+nv>image -type movie -token <token> -bytes <nbytes>
+  (followed by bytes)
+
+nv>data tag <dataobj-tag> min <val> max <val> vmin <val> vmax <val>
+   The min,max data values for the data object and the cumulative volume data
+   min,max over all volumes
+
+nv>data tag <flow-tag> min <val> max <val>
+   Sent after a "<flowObj> data follows...".  Min,max values are for the 
+   magnitude of the vector field.
+
+================================================================================
+Error Replies:
+================================================================================
+nv>viserror -bytes <nbytes>
+   <multi-line error string of nbytes>
+================================================================================
Index: /nanovis/tags/1.1.4/shaders/common.cg
===================================================================
--- /nanovis/tags/1.1.4/shaders/common.cg	(revision 4930)
+++ /nanovis/tags/1.1.4/shaders/common.cg	(revision 4930)
@@ -0,0 +1,105 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors:
+ *   Wei Qiao <qiaow@purdue.edu>
+ */
+
+// constrain particle to be outside volume of a sphere
+void SphereConstraint(inout float3 x, float3 center, float r)
+{
+    float3 delta = x - center;
+    float dist = length(delta);
+    if (dist < r) {
+        x = center + delta*(r / dist);
+    }
+}
+
+// constrain particle to be above floor
+void FloorConstraint(inout float3 x, float level)
+{
+    if (x.y < level) {
+        x.y = level;
+    }
+}
+
+// constrain particle to heightfield stored in texture
+void TerrainConstraint(inout float3 pos, uniform sampler2D terrain_tex,
+                       float3 scale, float3 offset)
+{
+    float2 uv = (pos.xz - offset.xz) / scale.xz;
+    float h = tex2D(terrain_tex, uv).r*scale.y + offset.y;
+    if (pos.y < h) {
+        pos.y = h;
+    }
+}
+
+void SphereCollide(inout float3 x, inout float3 vel, float3 center, float r,
+                   float3 sphere_vel, float friction, inout float3 force)
+{
+    float3 delta = x - center;
+    float dist = length(delta);
+    if (dist < r) {
+        // x = center + delta*(r / dist);    
+        vel += (delta / dist) * friction;
+        vel += sphere_vel;
+    }
+}
+
+void FloorCollide(inout float3 x, inout float3 vel, float level,
+                  float friction, inout float3 force)
+{
+    if (x.y < level) {
+        // x.y = level;
+        // force.y += -vel.y*friction;
+        vel.y += -vel.y*friction;
+    }
+}
+
+void Gravitation(float3 pos, float3 mass_pos, inout float3 force, float epsilon)
+{
+    float3 delta = mass_pos - pos;
+    float dist = length(delta);
+    float3 dir = delta / dist;
+    force += dir * (1.0 / (epsilon + dist*dist));
+}
+
+void TerrainCollide(float3 pos, inout float3 vel, uniform sampler2D terrain_tex,
+                    float3 scale, float3 offset, float friction)
+{
+    const float2 texelSize = float2( 1.0 / 256.0, 1.0 / 256.0 );
+    float2 uv = (pos.xz - offset.xz) / scale.xz;
+    float h0 = tex2D(terrain_tex, uv).r;
+    float h = h0*scale.y + offset.y;
+    if (pos.y < h) {
+        // calculate normal (could precalc this)
+        float h1 = tex2D(terrain_tex, uv + texelSize*float2(1, 0) ).r;
+        float h2 = tex2D(terrain_tex, uv + texelSize*float2(0, 1) ).r;
+        float3 N = cross(float3(scale.x*texelSize.x, (h1-h0)*scale.y, 0),
+                         float3(0, (h2-h0)*scale.y, scale.z*texelSize.y));
+        N = normalize(N);
+        vel = reflect(vel, N);
+        vel *= friction;
+    }
+}
+
+struct a2v
+{
+    //For semantics, see pages 230-240 of Cg_Toolkit.pdf
+    float4 Position : POSITION;
+    float4 TexCoord : TEXCOORD0;
+};
+
+struct v2f
+{
+    float4 HPosition: HPOS;		//Clip space pos. Not readable in frag prog
+    float4 TexCoord : TEXCOORD0;
+    float3 EyeVector: TEXCOORD1;	//world space eye vector
+    float3 Light    : TEXCOORD2;    //world space light vector 
+};
+
+struct PixelOut {
+    float4 Color:	COLOR0;
+    //float Depth:	DEPTH;
+};
Index: /nanovis/tags/1.1.4/shaders/copy_texcoord.cg
===================================================================
--- /nanovis/tags/1.1.4/shaders/copy_texcoord.cg	(revision 4930)
+++ /nanovis/tags/1.1.4/shaders/copy_texcoord.cg	(revision 4930)
@@ -0,0 +1,13 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors:
+ *   Wei Qiao <qiaow@purdue.edu>
+ */
+
+// copy texture coordinate to output color
+float4 main(in float4 texcoord : TEXCOORD0) : COLOR
+{
+    return texcoord;
+}
Index: /nanovis/tags/1.1.4/shaders/cutplane_fp.cg
===================================================================
--- /nanovis/tags/1.1.4/shaders/cutplane_fp.cg	(revision 4930)
+++ /nanovis/tags/1.1.4/shaders/cutplane_fp.cg	(revision 4930)
@@ -0,0 +1,22 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors:
+ *   Wei Qiao <qiaow@purdue.edu>
+ */
+
+float4 main(in float4 texcoord : TEXCOORD0,
+            uniform sampler3D volume,
+            uniform sampler1D tf) : COLOR
+{
+    float4 sample = tex3D(volume, texcoord.xyz);
+
+    // sample the transfer function texture
+    float4 color = tex1D(tf, sample.x);
+
+    // single slice render, only flat shading, completely opaque.
+    color.w = 1;
+
+    return color;
+}
Index: /nanovis/tags/1.1.4/shaders/cutplane_vp.cg
===================================================================
--- /nanovis/tags/1.1.4/shaders/cutplane_vp.cg	(revision 4930)
+++ /nanovis/tags/1.1.4/shaders/cutplane_vp.cg	(revision 4930)
@@ -0,0 +1,21 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors:
+ *   Wei Qiao <qiaow@purdue.edu>
+ */
+
+void main(in float4 position : POSITION,
+          in float4 texcoord : TEXCOORD0,
+          out float4 posOut : POSITION,
+          out float4 texcoordOut : TEXCOORD0,
+          uniform float4x4 modelViewProjMatrix)
+{
+    // position is in object coordinates
+    // Output clip space vertex position
+    posOut = mul(modelViewProjMatrix, position);
+
+    // Object space texture coordinates
+    texcoordOut = texcoord;
+}
Index: /nanovis/tags/1.1.4/shaders/distance.cg
===================================================================
--- /nanovis/tags/1.1.4/shaders/distance.cg	(revision 4930)
+++ /nanovis/tags/1.1.4/shaders/distance.cg	(revision 4930)
@@ -0,0 +1,102 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+// Copyright (c) 2004-2005 Lutz Latta
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+
+// Supporting functions for adapting generic sorting algorithm to distance sorting.
+//
+// Note: Packing of two 16-bit halfs into one float is used.
+// This works only perfect with texture sizes up to 1024.
+// With size 2048 the higher coordinates shift from xxxx.5 to integer values,
+// then the algorithm should be changed to store only integers and always add 0.5.
+#define USE_RGB_FORMAT
+#ifndef USE_RGB_FORMAT
+float2 initSortIndex(float2 sortIndex : TEXCOORD0) : COLOR
+{
+    // TBD...
+    return float2(0, pack_2half(sortIndex));
+    //return float2(sortIndex.x, sortIndex.y);
+}
+
+float2 computeDistance(float2 texCoord : TEXCOORD0,
+                       uniform samplerRECT sortTexture : register(s0),
+                       uniform samplerRECT positionTexture : register(s1),
+                       uniform float3 viewerPosition) : COLOR
+{
+    float sortIndex = texRECT(sortTexture, texCoord.xy).y;
+    half2 particleIndex = unpack_2half(sortIndex);
+
+    float3 particlePos = (float3)texRECT(positionTexture, particleIndex);
+	
+    float3 delta = viewerPosition - particlePos;
+    float distanceSqr = dot(delta, delta);
+
+    // Prevent unused, far-away particles from destroying comparisons in sorting.
+    if (distanceSqr > 1e6 || isnan(distanceSqr))
+        distanceSqr = 1e6;
+
+    return float2(distanceSqr, sortIndex);
+}
+float4 lookupPosition(float2 texCoord : TEXCOORD0,
+                      uniform samplerRECT sortTexture : register(s0),
+                      uniform samplerRECT positionTexture : register(s1)) : COLOR
+{
+    float sortIndex = texRECT(sortTexture, texCoord.xy).y;
+    half2 particleIndex = unpack_2half(sortIndex);
+    float4 particlePos = (float4)texRECT(positionTexture, particleIndex);
+
+    return particlePos;
+}
+
+#else
+float3 initSortIndex(float2 sortIndex : TEXCOORD0) : COLOR
+{
+    //return float3(0, sortIndex.x, sortIndex.y);
+    return float3(1e6, sortIndex.x, sortIndex.y);
+}
+
+float3 computeDistance(float2 texCoord : TEXCOORD0,
+                       uniform samplerRECT sortTexture : register(s0),
+                       uniform samplerRECT positionTexture : register(s1),
+                       uniform float3 viewerPosition) : COLOR
+{
+    float2 particleIndex = texRECT(sortTexture, texCoord.xy).yz;
+    float3 particlePos = texRECT(positionTexture, particleIndex).xyz;
+
+    float3 delta = viewerPosition - particlePos;
+    float distanceSqr = dot(delta, delta);
+
+    // Prevent unused, far-away particles from destroying comparisons in sorting.
+    if (distanceSqr > 1e6 || isnan(distanceSqr))
+        distanceSqr = 1e6;
+
+    return float3(distanceSqr, particleIndex.x, particleIndex.y);
+}
+
+float3 lookupPosition(float2 texCoord : TEXCOORD0,
+                      uniform samplerRECT sortTexture : register(s0),
+                      uniform samplerRECT positionTexture : register(s1)) : COLOR
+{
+    float2 particleIndex = texRECT(sortTexture, texCoord.xy).yz;
+    float3 particlePos = texRECT(positionTexture, particleIndex).xyz;
+
+    return particlePos;
+}
+#endif
Index: /nanovis/tags/1.1.4/shaders/distancesort.cg
===================================================================
--- /nanovis/tags/1.1.4/shaders/distancesort.cg	(revision 4930)
+++ /nanovis/tags/1.1.4/shaders/distancesort.cg	(revision 4930)
@@ -0,0 +1,64 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+// Copyright (c) 2004-2005 Lutz Latta
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+
+// Supporting functions for adapting generic sorting algorithm to distance sorting.
+//
+// Note: Packing of two 16-bit halfs into one float is used.
+// This works only perfect with texture sizes up to 1024.
+// With size 2048 the higher coordinates shift from xxxx.5 to integer values,
+// then the algorithm should be changed to store only integers and always add 0.5.
+
+float2 initSortIndex(float2 _SortIndex : TEXCOORD0) : COLOR
+{
+    return float2(0, pack_2half(_SortIndex));
+}
+
+float2 computeDistance(float2 _TexCoord : TEXCOORD0,
+                       uniform samplerRECT _SortTexture : register(s0),
+                       uniform samplerRECT _PositionTexture : register(s1),
+                       uniform float3 _ViewerPosition) : COLOR
+{
+    float sortIndex = texRECT(_SortTexture, _TexCoord.xy).y;
+    half2 particleIndex = unpack_2half(sortIndex);
+
+    float3 particlePos = (float3)texRECT(_PositionTexture, particleIndex);
+
+    float3 delta = _ViewerPosition - particlePos;
+    float distanceSqr = dot(delta, delta);
+
+    // Prevent unused, far-away particles from destroying comparisons in sorting.
+    if (distanceSqr > 1e6 || isnan(distanceSqr))
+        distanceSqr = 1e6;
+
+    return float2(distanceSqr, sortIndex);
+}
+
+float4 lookupPosition(float2 _TexCoord : TEXCOORD0,
+                      uniform samplerRECT _SortTexture : register(s0),
+                      uniform samplerRECT _PositionTexture : register(s1)) : COLOR
+{
+    float sortIndex = texRECT(_SortTexture, _TexCoord.xy).y;
+    half2 particleIndex = unpack_2half(sortIndex);
+    float4 particlePos = (float4)texRECT(_PositionTexture, particleIndex);
+
+    return particlePos;
+}
Index: /nanovis/tags/1.1.4/shaders/heightcolor.cg
===================================================================
--- /nanovis/tags/1.1.4/shaders/heightcolor.cg	(revision 4930)
+++ /nanovis/tags/1.1.4/shaders/heightcolor.cg	(revision 4930)
@@ -0,0 +1,16 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors:
+ *   Wei Qiao <qiaow@purdue.edu>
+ */
+
+float4 main(float4 texCoord : TEXCOORD0,
+            uniform float opacity, 
+            uniform sampler1D tf) : COLOR
+{
+    float4 color = tex1D(tf, texCoord.z);
+    color.w = opacity;
+    return color;
+}
Index: /nanovis/tags/1.1.4/shaders/mergesort.cg
===================================================================
--- /nanovis/tags/1.1.4/shaders/mergesort.cg	(revision 4930)
+++ /nanovis/tags/1.1.4/shaders/mergesort.cg	(revision 4930)
@@ -0,0 +1,102 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+// Copyright (c) 2004-2005 Lutz Latta
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+// Odd-even merge sort, implemented via parallel sorting network.
+#define USE_RGB_FORMAT
+
+#ifndef USE_RGB_FORMAT
+float2 
+#else
+float3
+#endif
+mergeSortEnd(float2 current : TEXCOORD0,
+             uniform samplerRECT sortData : register(s0),
+             uniform int2 size,
+             uniform int step) : COLOR
+{
+#ifndef USE_RGB_FORMAT
+    float2 currentSample = texRECT(sortData, (float2)current).xy;
+#else
+    float3 currentSample = texRECT(sortData, (float2)current).xyz;
+#endif
+
+    float i = (current.y - 0.5) * size.x + current.x;
+    //float i = current.y * size.x + current.x;
+
+    // swap direction
+    float b = (fmod(i / step, 2.0) < 1.0 ? 1.0 : -1.0);
+
+	
+    float otherI = i + (b * step);
+    float2 otherPos = float2(fmod(otherI, size.x), floor(otherI / size.x) + 0.5);
+    //float2 otherPos = float2(fmod(otherI, size.x), floor(otherI / size.x));
+#ifndef USE_RGB_FORMAT
+    float2 otherSample = texRECT(sortData, otherPos).xy;
+#else
+    float3 otherSample = texRECT(sortData, otherPos).xyz;
+#endif
+    if (b >= 0) {
+        return currentSample.x > otherSample.x ? currentSample : otherSample;
+    } else {
+        return currentSample.x < otherSample.x ? currentSample : otherSample;
+    }
+}
+#ifndef USE_RGB_FORMAT
+float2 
+#else
+float3
+#endif
+mergeSortRecursion(float2 _Current : TEXCOORD0,
+                   uniform samplerRECT _SortData : register(s0),
+                   uniform int2 _Size,
+                   uniform int _Step,
+                   uniform int _Count) : COLOR
+{
+#ifndef USE_RGB_FORMAT
+    float2 currentSample = texRECT(_SortData, (float2)_Current).xy;
+#else
+    float3 currentSample = texRECT(_SortData, (float2)_Current).xyz;
+#endif
+    float i = (_Current.y - 0.5) * _Size.x + _Current.x;
+    //float i = _Current.y * _Size.x + _Current.x;
+
+    float iMod = fmod((float)(i / _Step), (float)_Count);
+
+    if (iMod >= 1.0 && iMod < _Count - 1.0) {
+        float b = (fmod((float)iMod, 2.0) > 1.0 ? 1.0 : -1.0);
+
+        float otherI = i + (b * _Step);
+        float2 otherPos = float2(fmod(otherI, _Size.x), floor(otherI / _Size.x) + 0.5);
+        //float2 otherPos = float2(fmod(otherI, _Size.x), floor(otherI / _Size.x));
+
+#ifndef USE_RGB_FORMAT	
+        float2 otherSample = texRECT(_SortData, otherPos).xy;
+#else
+        float3 otherSample = texRECT(_SortData, otherPos).xyz;
+#endif
+        if (b >= 0) {
+            return currentSample.x > otherSample.x ? currentSample : otherSample;
+        } else {
+            return currentSample.x < otherSample.x ? currentSample : otherSample;
+        }
+    } else
+        return currentSample;
+}
Index: /nanovis/tags/1.1.4/shaders/moveparticles.cg
===================================================================
--- /nanovis/tags/1.1.4/shaders/moveparticles.cg	(revision 4930)
+++ /nanovis/tags/1.1.4/shaders/moveparticles.cg	(revision 4930)
@@ -0,0 +1,64 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors:
+ *   Wei Qiao <qiaow@purdue.edu>
+ */
+
+float4 main (float2 texCoord : TEXCOORD0,
+             uniform samplerRECT posTexture : register(s0),
+             uniform samplerRECT initTexture : register(s1),
+             uniform sampler3D vfield,
+             uniform float3 scale,
+             uniform float maxScale,
+             uniform float useInitPos,
+             uniform float timeStep,
+             uniform float currentTime) : COLOR
+{
+    if (maxScale > 100) maxScale = 100;
+
+    float3 oldPosition = f3texRECT(posTexture, texCoord);
+    float3 velocity = tex3D(vfield, oldPosition).yzw - float3(0.5, 0.5, 0.5);
+    velocity = velocity * (2 * maxScale);
+    velocity = velocity * scale;
+	
+    float3 position = oldPosition + velocity * timeStep * 0.01;
+    //float3 position = oldPosition;
+
+    //if (useInitPos) {
+        if ((position.x < 0) || (position.x > 1) || 
+            (position.y < 0) || (position.y > 1) || 
+            (position.z < 0) || (position.z > 1)) {
+            position = f3texRECT(initTexture, texCoord);
+        }
+    //}
+
+    return float4(position, 1);
+}
+
+float4 initParticlePosMain(float3 initPos : TEXCOORD0,
+                           float2 texCoord : TEXCOORD1,
+                           float timeStep : TEXCOORD2,
+                           uniform sampler3D vfield) : COLOR
+{
+    float3 oldPosition = initPos;
+    //float3 velocity = tex3D(vfield, oldPosition).yzw * 2 - float3(1, 1, 1);
+    //float3 position = oldPosition + timeStep * velocity;
+    //return float4(position, 1);
+    return float4(initPos, 1);
+}
+
+float4 mainlines(float2 texCoord : TEXCOORD0,
+                 uniform samplerRECT posTexture : register(s0),
+                 uniform sampler3D vfield,
+                 uniform float2 offset,
+                 uniform float timeStep) : COLOR
+{
+    float3 oldPosition = f3texRECT(posTexture, texCoord);
+    float3 velocity = tex3D(vfield, oldPosition).yzw * 2 - float3(1, 1, 1);
+	
+    float3 position = oldPosition + velocity * timeStep;
+
+    return float4(position, 1);
+}
Index: /nanovis/tags/1.1.4/shaders/one_plane.cg
===================================================================
--- /nanovis/tags/1.1.4/shaders/one_plane.cg	(revision 4930)
+++ /nanovis/tags/1.1.4/shaders/one_plane.cg	(revision 4930)
@@ -0,0 +1,19 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors:
+ *   Wei Qiao <qiaow@purdue.edu>
+ */
+
+float4 main(in float2 uv: TEXCOORD0,
+            uniform sampler2D data,
+            uniform sampler1D tf,
+            uniform float4 render_param) : COLOR
+{
+    float sample = tex2D(data, uv).x;
+    float4 color = tex1D(tf, sample);
+    //return float4(sample, sample, sample, 1);
+    color.w = 1.;
+    return color;
+}
Index: /nanovis/tags/1.1.4/shaders/one_volume.cg
===================================================================
--- /nanovis/tags/1.1.4/shaders/one_volume.cg	(revision 4930)
+++ /nanovis/tags/1.1.4/shaders/one_volume.cg	(revision 4930)
@@ -0,0 +1,96 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors:
+ *   Wei Qiao <qiaow@purdue.edu>
+ *   Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#include "common.cg"
+
+//#define LIGHT_TWO_SIDE
+
+/*
+ * render one volume 
+ *
+ * material:
+ *   x: ambient coefficient
+ *   y: diffuse coefficient
+ *   z: specular level/coefficient
+ *   w: specular exponent
+ * renderParams:
+ *   x: sample distance ratio (0 = single slice)
+ *   y: isosurface flag (opacity scaling on/off)
+ *   z: opacity scale
+ *   w: two-sided lighting
+ */
+PixelOut main(v2f IN,
+              uniform sampler3D volume,
+              uniform sampler1D tf,
+              uniform float4x4 modelViewInv,
+              uniform float4x4 modelView,
+              uniform float4 material,
+              uniform float4 renderParams)
+{
+    PixelOut OUT;
+    float4 tex_coord = mul(modelViewInv, IN.TexCoord);
+    float4 sample = tex3D(volume, tex_coord.xyz);
+
+    //sample the transfer function texture
+    float4 color = tex1D(tf, sample.x);
+
+    if (renderParams.x == 0.0) {
+        //If single slice render, only flat shading, completely opaque.
+        color.w = 1;
+    } else {
+        //regular volume rendering, we do PHONG SHADING 
+        //lighting parameters
+        float3 normal;
+        float diffuse, specular;
+        if (dot(sample.yzw, sample.yzw) < 5.0e-5) {
+            diffuse = 0;
+            specular = 0;
+        } else {
+            normal = normalize(sample.yzw * 2.0 - 1.0);
+            float3 light_vector = normalize(IN.Light);
+            float3 eye_vector = normalize(IN.EyeVector);
+            float3 half_vector = normalize(eye_vector+light_vector);
+
+            //lighting computation
+#ifndef LIGHT_TWO_SIDE
+            float normal_dot_light = dot(normal, light_vector);
+            float normal_dot_half = dot(normal, half_vector);
+            if (renderParams.w > 0.5) {
+                normal_dot_light = abs(normal_dot_light);
+                normal_dot_half = abs(normal_dot_half);
+            } else {
+                normal_dot_light = max(normal_dot_light, 0);
+                normal_dot_half = max(normal_dot_half, 0);
+            }
+#else
+            float normal_dot_light = abs(dot(normal, light_vector));
+            float normal_dot_half = abs(dot(normal, half_vector));
+#endif
+            diffuse = normal_dot_light * material.y;
+            if (diffuse > 1.0e-6) 
+                specular = pow(normal_dot_half, material.w) * material.z;
+            else
+                specular = 0.0;
+        }
+        float ambient = material.x;
+
+        color.xyz = color.xyz * (ambient + diffuse) + float3(specular);
+
+        if (renderParams.y < 0.5) {
+            // Opacity scaling: equivalent to scaling transfer function
+            color.w = color.w * renderParams.z;
+            // Apply opacity correction for ratio of current sample distance
+            // to data set sample distance
+            color.w = (1.0 - pow((1.0 - color.w), renderParams.x));
+        }
+    }
+
+    OUT.Color = min(max(color, 0.0), 1.0);
+    return OUT;
+}
Index: /nanovis/tags/1.1.4/shaders/particle_common.cg
===================================================================
--- /nanovis/tags/1.1.4/shaders/particle_common.cg	(revision 4930)
+++ /nanovis/tags/1.1.4/shaders/particle_common.cg	(revision 4930)
@@ -0,0 +1,14 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors:
+ *   Wei Qiao <qiaow@purdue.edu>
+ */
+
+#define SUBIMAGE_SIZE_X 32
+#define SUBIMAGE_SIZE_Y 32
+#define NUM_SUBIMAGE_X 16
+#define NUM_SUBIMAGE_Y 16
+#define SUBIMAGE_HALFSIZE_X 16
+#define SUBIMAGE_HALFSIZE_Y 16
Index: /nanovis/tags/1.1.4/shaders/particlefp.cg
===================================================================
--- /nanovis/tags/1.1.4/shaders/particlefp.cg	(revision 4930)
+++ /nanovis/tags/1.1.4/shaders/particlefp.cg	(revision 4930)
@@ -0,0 +1,63 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors:
+ *   Wei Qiao <qiaow@purdue.edu>
+ */
+
+#include "particle_common.cg"
+
+#ifdef USE_TIME_SERIES
+#define LEVEL1 0.5
+#define LEVEL2 0.4
+#else
+#define LEVEL1 0.7
+#define LEVEL2 0.5
+#endif
+
+float4 fpmain(float2 texCoord : TEXCOORD0,
+              float3 color : COLOR, 
+              float2 center : TEXCOORD2,
+              float4 rotation : TEXCOORD3,
+              float skip : TEXCOORD4,
+              float mag : TEXCOORD5,
+              float zValue : TEXCOORD6,
+              uniform sampler2D arrows : register(s0)) : COLOR
+{
+    if (skip > 0.5) {
+        discard;
+    }
+
+    float2 newTexCoord = float2((texCoord.x - 0.5) / NUM_SUBIMAGE_X, (texCoord.y - 0.5) / NUM_SUBIMAGE_Y);
+    float2 rotTexCoord;
+    rotTexCoord.x = rotation.x * newTexCoord.x + rotation.y * newTexCoord.y;
+    rotTexCoord.y = rotation.z * newTexCoord.x + rotation.w * newTexCoord.y;
+    rotTexCoord.x = rotTexCoord.x + 0.5 / NUM_SUBIMAGE_X;
+    rotTexCoord.y = rotTexCoord.y + 0.5 / NUM_SUBIMAGE_Y;
+    rotTexCoord = rotTexCoord + center;
+    float4 refColor;
+#ifdef USE_J_WIRE	
+    if (mag > 0.2)
+        refColor = float4(1, 0, 0, 1.0);
+    else if (mag > 0.1)
+        refColor = float4(1, 1, 0, 0.3);
+    else
+        refColor = float4(1, 1, 1, 0.3);
+#else
+    if (mag > LEVEL1)
+        refColor = float4(1, 0, 0, 1.0);
+    //refColor = float4(1, 0, 0, 1.0 * (3.0 + zValue) / 3);
+    else if (mag > LEVEL2)
+        refColor = float4(1, 1, 0, 0.3);
+    //refColor = float4(1, 1, 0, 1.0);
+    else
+        refColor = float4(0.5, 0.5, 0.5, 0.2);
+    //refColor = float4(0.5, 0.5, 0.5, 1.0);
+#endif
+    float4 arrowc = tex2D(arrows, rotTexCoord.xy);
+    float4 c = float4(arrowc.xyz, ((arrowc.w == 1.0)? 1 : 0));
+    //float4 c = float4(arrowc.xyz, ((arrowc.w != 0.0)? 1 : 0));
+	
+    return c * refColor;
+}
Index: /nanovis/tags/1.1.4/shaders/particlevp.cg
===================================================================
--- /nanovis/tags/1.1.4/shaders/particlevp.cg	(revision 4930)
+++ /nanovis/tags/1.1.4/shaders/particlevp.cg	(revision 4930)
@@ -0,0 +1,83 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors:
+ *   Wei Qiao <qiaow@purdue.edu>
+ */
+
+#include "particle_common.cg"
+
+void vpmain(in float4 posin : POSITION,
+            in float4 colin : COLOR0,
+            in float4 attr : TEXCOORD0,
+            inout float pointSize : PSIZE, 
+            out float4 posout : POSITION,
+            out float4 colout : COLOR0,
+            out float2 center : TEXCOORD2,
+            out float4 rotation : TEXCOORD3,
+            out float skip : TEXCOORD4,
+            out float mag : TEXCOORD5,
+            out float zValue : TEXCOORD6,
+            uniform sampler3D vfield,
+            uniform float currentTime,
+            uniform float tanHalfFOV,
+            uniform float4x4 modelview,
+            uniform float4x4 projection,
+            uniform float4x4 mvp)
+{
+    float4 vec;
+    vec.xyz = posin.xyz;
+    vec.w = 1.0;
+
+    float timeOfBirth = attr.x;
+    float lifeTime = attr.y;
+    //float index = attr.w;
+
+    // length
+    // the scale of from bottom to top 
+    float4 v = tex3D(vfield, vec.xyz);
+    float3 velocity = v.yzw * 2 - float3(1, 1, 1);
+    mag = v.x;
+
+    // bottom to top
+    // scale
+    center.y = ((((int) (length(velocity.xyz) * 511)) / SUBIMAGE_SIZE_Y) * SUBIMAGE_SIZE_Y) / 512.0;
+    //center.y = ((((int) (511)) / SUBIMAGE_SIZE_Y) * SUBIMAGE_SIZE_Y) / 512.0;
+
+    velocity = mul(modelview, float4(velocity.x, velocity.y, velocity.z, 0.0)).xyz;
+    if (length(velocity) != 0.0)
+        velocity = normalize(velocity);
+
+    float a = (asin(velocity.z) / 3.141592 + 1) * 0.5;
+    center.x = ((((int) (a * 511)) / SUBIMAGE_SIZE_X) * SUBIMAGE_SIZE_X) / 512.0;
+
+    if ((abs(velocity.x) == 0.0) && (abs(velocity.y) == 0.0)) {
+        rotation.x = 1;
+        rotation.y = 0;
+        rotation.z = 0;
+        rotation.w = 1;	
+    } else {
+        float2 xy = normalize(velocity.xy);
+        rotation.x = xy.x * 0.8;
+        rotation.y = -xy.y * 0.8;
+        rotation.z = xy.y * 0.8;
+        rotation.w = xy.x * 0.8;
+    }
+
+    float4 posEye =  mul(modelview, posin);
+#ifndef USE_J_WIRE
+    pointSize = tanHalfFOV / -posEye.z / 5;
+#else
+    pointSize = tanHalfFOV / -posEye.z / 10;
+#endif
+    //pointSize = 10 / -posEye.z;
+    zValue = posEye.z;
+    posout = mul(mvp, vec);
+
+    if ((currentTime > timeOfBirth) && (currentTime < (timeOfBirth + lifeTime))) skip = 0.0;
+    else skip = 1.0;
+
+    colout = colin;
+}
+
Index: /nanovis/tags/1.1.4/shaders/passthrough.cg
===================================================================
--- /nanovis/tags/1.1.4/shaders/passthrough.cg	(revision 4930)
+++ /nanovis/tags/1.1.4/shaders/passthrough.cg	(revision 4930)
@@ -0,0 +1,16 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors:
+ *   Wei Qiao <qiaow@purdue.edu>
+ */
+
+float4 main(float2 texCoord : TEXCOORD0,
+            uniform samplerRECT tex : register(s0),
+            uniform float4 scale,
+            uniform float4 bias) : COLOR
+{
+    return texRECT(tex, texCoord.xy) * scale + bias;
+}
+
Index: /nanovis/tags/1.1.4/shaders/passthru.cg
===================================================================
--- /nanovis/tags/1.1.4/shaders/passthru.cg	(revision 4930)
+++ /nanovis/tags/1.1.4/shaders/passthru.cg	(revision 4930)
@@ -0,0 +1,16 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors:
+ *   Wei Qiao <qiaow@purdue.edu>
+ */
+
+float4 main(in float2 uv : TEXCOORD0,
+            uniform samplerRECT tex,
+            uniform float4 scale,
+            uniform float4 bias) : COLOR
+{
+    return texRECT(tex, uv) * scale + bias;
+    //return float4(1,1,1,1);
+}
Index: /nanovis/tags/1.1.4/shaders/pointsvp.cg
===================================================================
--- /nanovis/tags/1.1.4/shaders/pointsvp.cg	(revision 4930)
+++ /nanovis/tags/1.1.4/shaders/pointsvp.cg	(revision 4930)
@@ -0,0 +1,64 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors:
+ *   Wei Qiao <qiaow@purdue.edu>
+ */
+
+void main(in float4 posin : POSITION,
+          in float4 colin : COLOR0,
+          out float psize : PSIZE,
+          out float4 posout : POSITION,
+          out float4 colout : COLOR0,
+          uniform float atten,
+          /*uniform sampler2D normal,*/
+          uniform float4 posoffset,
+          uniform float4 basepos,
+          uniform float4 scale,		
+          uniform float4x4 modelView,
+          uniform float4x4 modelViewProj)
+{
+    float4 vec, homeye, eye;
+    vec.xyz = posin.xyz;
+    vec.w = 1.0;
+    homeye = mul(modelView, vec);
+    posout = mul(modelViewProj, posin);
+
+    float4 p = mul(modelView, vec);
+    //psize = scale.x   *(p.w / -p.z) * 10;
+
+    //psize = 5 * scale.x;
+    //psize = 2 * p.w / -p.z;
+    //colout = float4(colin.xyz,0.1);
+
+    //	float tmp = posin.w * rsqrt(dot(eye.xyz, eye.xyz));
+    //	psize = scale.x * max(tmp, 1.0);
+    psize = 10 * p.w / -p.z;
+
+    colout = float4(colin.xyz, colin.w * 0.25);
+    /*
+      float4 vec, homeye, eye;
+      float tmp;
+
+      vec.xyz = posin.xyz;//(posin.xyz + posoffset.www) * basepos.www + basepos.xyz;
+      vec.w = 1.0;
+
+      homeye = mul(modelView, vec);
+      posout = mul(modelViewProj, posin);
+
+      //eye = homeye / homeye.w;
+
+      //tmp = posin.w * basepos.w * scale.w * rsqrt(atten * dot(eye.xyz, eye.xyz));
+
+      //psize = scale.x * max(tmp, 1.0);
+      //tmp = min(tmp, 1.0);
+      //colout = colin;
+      //tmp = colin.w * scale.z * tmp * tmp;
+      //colout.w = max(tmp, 4.0/256);
+
+      psize = 5.0;
+
+      colout = float4(0.0, 0.0, 1.0, 0.1);
+    */	
+}
Index: /nanovis/tags/1.1.4/shaders/queryvelocity.cg
===================================================================
--- /nanovis/tags/1.1.4/shaders/queryvelocity.cg	(revision 4930)
+++ /nanovis/tags/1.1.4/shaders/queryvelocity.cg	(revision 4930)
@@ -0,0 +1,14 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors:
+ *   Wei Qiao <qiaow@purdue.edu>
+ */
+
+float4 main(float3 pos : TEXCOORD0,
+            uniform sampler3D vfield) : COLOR
+{
+    float3 velocity = tex3D(vfield, pos).yzw * 2 - float3(1, 1, 1);
+    return float4(velocity, 1);
+}
Index: /nanovis/tags/1.1.4/shaders/render_vel.cg
===================================================================
--- /nanovis/tags/1.1.4/shaders/render_vel.cg	(revision 4930)
+++ /nanovis/tags/1.1.4/shaders/render_vel.cg	(revision 4930)
@@ -0,0 +1,22 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors:
+ *   Wei Qiao <qiaow@purdue.edu>
+ */
+
+// Project and sample 3D vector field on a 2D plane
+
+#include "common.cg"
+
+float4 main(in float3 uvw : TEXCOORD0,
+            uniform sampler3D vel_tex,
+            uniform float3 projection_vector,
+            uniform float timestep,
+            uniform float vmax) : COLOR
+{
+    float3 velocity = tex3D(vel_tex, uvw).yzw * 2.0 - float3(1.0, 1.0, 1.0);
+    velocity = velocity * projection_vector * vmax * timestep;
+    return float4(velocity, 1);
+}
Index: /nanovis/tags/1.1.4/shaders/renderparticle.cg
===================================================================
--- /nanovis/tags/1.1.4/shaders/renderparticle.cg	(revision 4930)
+++ /nanovis/tags/1.1.4/shaders/renderparticle.cg	(revision 4930)
@@ -0,0 +1,40 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors:
+ *   Wei Qiao <qiaow@purdue.edu>
+ */
+
+void main(in float4 posin : POSITION,
+          in float4 colin : COLOR0,
+          out float psize : PSIZE,
+          out float4 posout : POSITION,
+          out float4 colout : COLOR0,
+          uniform float atten,
+          //uniform sampler2D normal,
+          uniform float4 posoffset,
+          uniform float4 basepos,
+          uniform float4 scale,
+          uniform float4x4 modelview,
+          uniform float4x4 projection)
+{
+    float4 vec, homeye, eye;
+    vec.xyz = posin.xyz;
+    vec.w = 1.0;
+    homeye = mul(modelview, vec);
+    posout = mul(projection, homeye);
+
+    float4 p = mul(modelview, vec);
+    //psize = scale.x   *(p.w / -p.z) * 10;
+
+    //psize = 5 * scale.x;
+    //psize = 2 * p.w / -p.z;
+    //colout = float4(colin.xyz,0.1);
+
+    float tmp = posin.w * rsqrt(dot(eye.xyz, eye.xyz));
+    psize = scale.x * max(tmp, 1.0);
+    psize = 10 * p.w / -p.z;
+
+    colout = float4(colin.xyz, colin.w * 0.25);
+}
Index: /nanovis/tags/1.1.4/shaders/update_pos.cg
===================================================================
--- /nanovis/tags/1.1.4/shaders/update_pos.cg	(revision 4930)
+++ /nanovis/tags/1.1.4/shaders/update_pos.cg	(revision 4930)
@@ -0,0 +1,49 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors:
+ *   Wei Qiao <qiaow@purdue.edu>
+ */
+
+// update positions based on velocity
+
+#include "common.cg"
+
+float4 main(in float2 uv : TEXCOORD0,
+            uniform samplerRECT pos_tex,
+            uniform samplerRECT init_pos_tex,
+            uniform sampler3D vel_tex,
+            uniform float timestep,
+            uniform float max,
+            uniform float3 scale) : COLOR
+{
+    float4 ret;
+    // get previous position
+    float4 pos = texRECT(pos_tex, uv);
+    float time = pos.w;
+
+#ifdef EXPIRE
+    time -= timestep;
+
+    // Lifetime ended?
+    if (time < 0) {
+        return texRECT(init_pos_tex, uv);
+    }
+#endif
+
+    //reconstruct negative value
+    float4 vel = float4(tex3D(vel_tex, pos.xyz).yzw, 0.0) * 2.0 - float4(1.0, 1.0, 1.0, 0.0f);
+    vel = vel * max;
+    //vel *= float4(scale, 1);
+    ret = pos + (vel * timestep);
+
+    //not drawing if the particle is out of bound
+    if (ret.x < 0 || ret.x > 1 || ret.y < 0 || ret.y > 1 || ret.z < 0 || ret.z > 1) {
+        ret = texRECT(init_pos_tex, uv);
+    } else {
+        ret.w = time;
+    }
+
+    return ret;
+}
Index: /nanovis/tags/1.1.4/shaders/update_pos_vel.cg
===================================================================
--- /nanovis/tags/1.1.4/shaders/update_pos_vel.cg	(revision 4930)
+++ /nanovis/tags/1.1.4/shaders/update_pos_vel.cg	(revision 4930)
@@ -0,0 +1,55 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors:
+ *   Wei Qiao <qiaow@purdue.edu>
+ */
+
+// update velocity and position in a single pass using MRT
+
+#include "common.cg"
+
+void main(in float2 uv : TEXCOORD0,
+          uniform samplerRECT pos_tex,
+          uniform samplerRECT vel_tex,
+          uniform sampler2D terrain_tex,
+          uniform float timestep = 0.01,
+          uniform float damping = 0.99,
+          uniform float3 gravity = float3(0, -1, 0),
+          uniform float3 spherePos,
+          uniform float3 sphereVel,
+          out float4 new_pos : COLOR0,
+          out float4 new_vel : COLOR1)
+{
+    const float3 terrain_scale = float3(8.0, 2.0, 8.0);
+    const float3 terrain_offset = float3(-4.0, 0.01, -4.0);
+
+    float3 pos = texRECT(pos_tex, uv).xyz;
+    float3 vel = texRECT(vel_tex, uv).xyz;
+
+    float3 pos_next = pos + vel * timestep;  // predicted position next timestep
+
+    // update velocity
+    float3 force = gravity;
+    // float3 force = 0.0;
+    // Gravitation(pos, spherePos, force, 0.1);
+
+    SphereCollide(pos_next, vel, spherePos, 1.0, sphereVel, 0.5, force);
+    // FloorCollide(pos_next, vel, 0.0, 0.5, force);    
+    TerrainCollide(pos_next, vel, terrain_tex, terrain_scale, terrain_offset, 0.5);
+
+    const float inv_mass = 1.0;    
+    vel += force * inv_mass * timestep; // F = ma      
+    vel *= damping;
+
+    // update position
+    SphereConstraint(pos, spherePos, 1.0f);
+    // FloorConstraint(pos, 0.0f);
+    TerrainConstraint(pos, terrain_tex, terrain_scale, terrain_offset);
+
+    pos += vel * timestep;
+
+    new_vel = float4(vel, 1);
+    new_pos = float4(pos, 1);
+}
Index: /nanovis/tags/1.1.4/shaders/update_vel.cg
===================================================================
--- /nanovis/tags/1.1.4/shaders/update_vel.cg	(revision 4930)
+++ /nanovis/tags/1.1.4/shaders/update_vel.cg	(revision 4930)
@@ -0,0 +1,44 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors:
+ *   Wei Qiao <qiaow@purdue.edu>
+ */
+
+// update velocity based on acceleration
+
+#include "common.cg"
+
+float4 main(in float2 uv : TEXCOORD0,
+            uniform samplerRECT pos_tex,
+            uniform samplerRECT vel_tex,
+            uniform sampler2D terrain_tex,            
+            uniform float timestep = 0.01,
+            uniform float damping = 0.99,
+            uniform float3 gravity = float3(0, -1, 0),
+            uniform float3 spherePos,
+            uniform float3 sphereVel) : COLOR
+{
+    const float3 terrain_scale = float3(8.0, 2.0, 8.0);
+    const float3 terrain_offset = float3(-4.0, 0.01, -4.0);
+
+    float3 pos = texRECT(pos_tex, uv).xyz;
+    float3 vel = texRECT(vel_tex, uv).xyz;
+
+    float3 pos_next = pos + vel * timestep;  // predicted position next timestep
+
+    float3 force = gravity;
+    // float3 force = 0.0;
+    // Gravitation(pos, spherePos, force, 0.1);
+
+    SphereCollide(pos_next, vel, spherePos, 1.0, sphereVel, 0.5, force);
+    // FloorCollide(pos_next, vel, 0.0, 0.5, force);
+    TerrainCollide(pos_next, vel, terrain_tex, terrain_scale, terrain_offset, 0.5);
+
+    const float inv_mass = 1.0;    
+    vel += force * inv_mass * timestep; // F = ma      
+    vel *= damping;
+
+    return float4(vel, 1.0);
+}
Index: /nanovis/tags/1.1.4/shaders/velocity.cg
===================================================================
--- /nanovis/tags/1.1.4/shaders/velocity.cg	(revision 4930)
+++ /nanovis/tags/1.1.4/shaders/velocity.cg	(revision 4930)
@@ -0,0 +1,84 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+// Copyright (c) 2004-2005 Lutz Latta
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+// Velocity change operations.
+//#include "velocityOps.cg"
+
+// Uniform parameters influencing velocity.
+uniform float3 _SphereCenter;
+uniform samplerRECT _TerrainTexture : register(s2);
+uniform samplerRECT _FlowFieldTexture : register(s3);
+uniform float3 _LocalAttractorPosition[4];
+
+float3 advanceVelocity(float3 _Velocity, float3 _Position, float _TimeStep)
+{
+    float3 gravity = float3(0, -.01, 0);
+
+    float3 acceleration = gravity;
+
+    //acceleration += 
+    //    localAttractor(_Position, 
+    //                   getClosestPointOnLine(_LocalAttractorPosition[0],
+    //                                         _LocalAttractorPosition[1], _Position), 0.05, 0.2);
+    //acceleration += localAttractor(_Position, _LocalAttractorPosition[0], 0.02, 0.4);
+    //acceleration += localAttractor(_Position, _LocalAttractorPosition[1], 0.02, 0.02);
+    //acceleration += localRepulsor(_Position, _LocalAttractorPosition[2], 0.02, 0.1);
+    //acceleration += localRepulsor(_Position, _LocalAttractorPosition[3], 0.02, 0.1);
+    //acceleration += flowFieldVector(_Position, _FlowFieldTexture, float2(512, 512),
+    //                                float3(4, 4, 4), float3(256, 0, 256), 0.01);
+
+    float3 velocity = _Velocity + _TimeStep * acceleration;
+
+    //velocity = lerp(velocity, flowFieldVector(_Position, _FlowFieldTexture, float2(512, 512),
+    //                                          float3(4, 4, 4), float3(256, 0, 256), 1), 0.2);
+    //velocity = length(velocity) * normalize(flowFieldVector(_Position, _FlowFieldTexture, float2(512, 512),
+    //                                                        float3(4, 4, 4), float3(256, 0, 256), 1));
+
+    //spiral(velocity, _TimeStep, normalize(_LocalAttractorPosition[0] - _LocalAttractorPosition[1]), .3);
+
+    //dampen(velocity, 1.1);
+    //undampen(velocity, 1.01);
+
+    floorConstraint(velocity, _Position, 0, 0.4, 0.1, 0.01);
+    sphereConstraint(velocity, _Position, _SphereCenter, 1, 0.3, 0.7, 0.01);
+    //terrainConstraint(velocity, _Position, _TerrainTexture, float2(128, 128),
+    //	                float3(4, 4, 4), float3(64, 0, 64), 0.02, 0.7, 0.01);
+
+    return velocity;
+}
+
+float4 main(float2 _TexCoord : TEXCOORD0,
+            uniform samplerRECT _VelocityTexture : register(s0),
+            uniform samplerRECT _PositionTexture : register(s1),
+            uniform float _TimeStep) : COLOR
+{
+    float3 velocity = (float3)texRECT(_VelocityTexture, _TexCoord);
+    float3 position = (float3)texRECT(_PositionTexture, _TexCoord);
+
+    return float4(advanceVelocity(velocity, position, _TimeStep), 0);
+}
+
+float4 mainInitialization(float3 _VelocityInit : TEXCOORD0,
+                          float3 _PositionInit : TEXCOORD1,
+                          float _TimeStep : TEXCOORD2) : COLOR
+{
+    return float4(advanceVelocity(_VelocityInit, _PositionInit, _TimeStep), 0);
+}
Index: /nanovis/tags/1.1.4/shaders/velocityslicefp.cg
===================================================================
--- /nanovis/tags/1.1.4/shaders/velocityslicefp.cg	(revision 4930)
+++ /nanovis/tags/1.1.4/shaders/velocityslicefp.cg	(revision 4930)
@@ -0,0 +1,26 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors:
+ *   Wei Qiao <qiaow@purdue.edu>
+ */
+
+#include "particle_common.cg"
+
+float4 main(float2 texCoord : TEXCOORD0,
+            float4 color : COLOR0, 
+            float2 center : TEXCOORD2,
+            float4 rotation : TEXCOORD3,
+            uniform sampler2D arrows : TEXUNIT0) : COLOR
+{
+    float2 newTexCoord = float2((texCoord.x - 0.5) / NUM_SUBIMAGE_X, (texCoord.y - 0.5) / NUM_SUBIMAGE_Y);
+    float2 rotTexCoord;
+    rotTexCoord.x = rotation.x * newTexCoord.x + rotation.y * newTexCoord.y;
+    rotTexCoord.y = rotation.z * newTexCoord.x + rotation.w * newTexCoord.y;
+    rotTexCoord.x = rotTexCoord.x + 0.5 / NUM_SUBIMAGE_X;
+    rotTexCoord.y = rotTexCoord.y + 0.5 / NUM_SUBIMAGE_Y;
+    rotTexCoord = rotTexCoord + center;
+
+    return tex2D(arrows, rotTexCoord.xy) * color;
+}
Index: /nanovis/tags/1.1.4/shaders/velocityslicevp.cg
===================================================================
--- /nanovis/tags/1.1.4/shaders/velocityslicevp.cg	(revision 4930)
+++ /nanovis/tags/1.1.4/shaders/velocityslicevp.cg	(revision 4930)
@@ -0,0 +1,63 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors:
+ *   Wei Qiao <qiaow@purdue.edu>
+ */
+
+#include "particle_common.cg"
+
+void main(in float4 posin : POSITION,
+          in float4 colin : COLOR0,
+          out float4 posout : POSITION,
+          out float4 colout : COLOR0,
+          out float2 center : TEXCOORD2,
+          out float4 rotation : TEXCOORD3,
+          out float4 pointSize : PSIZE,
+          uniform sampler3D vfield : TEXUNIT1,
+          uniform float tanHalfFOV,
+          uniform float4x4 modelview,
+          uniform float4x4 mvp)
+{
+    float4 vec;
+    vec.xyz = posin.xyz;
+    vec.w = 1.0;
+
+    // length
+    // the scale of from bottom to top 
+    float3 velocity = tex3D(vfield, vec.xyz).yzw * 2 - float3(1, 1, 1);
+
+    // bottom to top
+    // scale
+    center.y = ((((int) (length(velocity.xyz) * 511)) / SUBIMAGE_SIZE_Y) * SUBIMAGE_SIZE_Y) / 512.0;
+
+    velocity = mul(modelview, float4(velocity.x, velocity.y, velocity.z, 0.0)).xyz;
+    if (length(velocity) != 0.0)
+        velocity = normalize(velocity);
+
+    float a = (asin(velocity.z) / 3.141592 + 1) * 0.5;
+    center.x = ((((int) (a * 511)) / SUBIMAGE_SIZE_X) * SUBIMAGE_SIZE_X) / 512.0;
+
+    if ((abs(velocity.x) == 0.0) && (abs(velocity.y) == 0.0)) {
+        rotation.x = 1;
+        rotation.y = 0;
+        rotation.z = 0;
+        rotation.w = 1;	
+    } else {
+        float2 xy = normalize(velocity.xy);
+        rotation.x = xy.x * 0.8;
+        rotation.y = -xy.y * 0.8;
+        rotation.z = xy.y * 0.8;
+        rotation.w = xy.x * 0.8;
+    }
+
+    float4 posEye =  mul(modelview, posin);
+    //pointSize = tanHalfFOV / -posEye.z / 5;
+    //pointSize = tanHalfFOV / -posEye.z / 10; //j-wire
+    pointSize = 20; //0 / -posEye.z;
+
+    posout = mul(mvp, vec);
+
+    colout = colin;
+}
Index: /nanovis/tags/1.1.4/shaders/vertex_std.cg
===================================================================
--- /nanovis/tags/1.1.4/shaders/vertex_std.cg	(revision 4930)
+++ /nanovis/tags/1.1.4/shaders/vertex_std.cg	(revision 4930)
@@ -0,0 +1,34 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors:
+ *   Wei Qiao <qiaow@purdue.edu>
+ */
+
+#include "common.cg"
+ 
+v2f main(a2v IN,
+         uniform float4x4 modelViewProjMatrix,
+         uniform float4x4 modelViewInv)
+{
+    v2f OUT;
+
+    // IN.Position is in eye coords
+    float4 objPos = mul(modelViewInv, IN.Position);
+    float4 eyePosObjSpace = mul(modelViewInv, float4(0,0,0,1));
+
+    // Clip space vertex position
+    OUT.HPosition = mul(modelViewProjMatrix, objPos);
+
+    // Eye space texture coordinates
+    OUT.TexCoord = IN.TexCoord;
+
+    // World space eye position
+    OUT.EyeVector = normalize(eyePosObjSpace - objPos);
+
+    // World space light postion
+    OUT.Light = normalize(mul(modelViewInv, float4(1,1,1,1))-objPos);
+
+    return OUT;
+}
Index: /nanovis/tags/1.1.4/shaders/volqd_volume.cg
===================================================================
--- /nanovis/tags/1.1.4/shaders/volqd_volume.cg	(revision 4930)
+++ /nanovis/tags/1.1.4/shaders/volqd_volume.cg	(revision 4930)
@@ -0,0 +1,54 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors:
+ *   Wei Qiao <qiaow@purdue.edu>
+ */
+
+#include "common.cg"
+
+PixelOut main(v2f IN, 
+              uniform sampler1D tf,
+              uniform sampler3D vol_grid_s, 
+              uniform float4 cell_size, 
+              uniform float4x4 ModelViewInv, 
+              uniform float4 renderParameters)
+{
+    PixelOut OUT;
+
+    float tf_coord_s, tf_coord_p, tf_coord_d, tf_coord_ss;
+
+    float4 twice_cell_size = cell_size*2.0;
+    float4 tex_coord = mul(ModelViewInv, IN.TexCoord);
+    float4 tex_coord_a = tex_coord - float4(twice_cell_size.x, twice_cell_size.y, 0, 0);
+    float4 tex_coord_b = tex_coord - float4(twice_cell_size.x, 0, twice_cell_size.z, 0);
+    float4 tex_coord_c = tex_coord - float4(0, twice_cell_size.y, twice_cell_size.z, 0); 
+
+    float4 voxel_corner = tex3D(vol_grid_s, tex_coord);
+    float4 voxel_face_center_a = tex3D(vol_grid_s, tex_coord_a);
+    float4 voxel_face_center_b = tex3D(vol_grid_s, tex_coord_b);
+    float4 voxel_face_center_c = tex3D(vol_grid_s, tex_coord_c);  
+    float sample = (voxel_corner.x + voxel_face_center_a.y + voxel_face_center_b.z + voxel_face_center_c.w)*0.25;
+
+    //sample the transfer function texture
+    float4 color = tex1D(tf, sample.x);
+
+    if (renderParameters.x < 0.5) { 
+        //If single slice render, only flat shading, completely opaque.
+        color.w = 1;
+    } else {
+        //regular volume rendering, we do FLAT SHADING 
+        //since all 4 components of the volume texture has been used to store orbital data,
+        //there is no room to store normal vector. If we really need PHONG shading we have to pass more volumes to
+        //the shader. We might add this later.
+
+        //opacity is modulated by the number of total slices
+        //to avoid very opaque volume when number of slices is high
+        color.w = renderParameters.y * color.w / renderParameters.x; 
+    }
+
+    OUT.Color = color;
+
+    return OUT;
+}
Index: /nanovis/tags/1.1.4/shaders/zincblende_volume.cg
===================================================================
--- /nanovis/tags/1.1.4/shaders/zincblende_volume.cg	(revision 4930)
+++ /nanovis/tags/1.1.4/shaders/zincblende_volume.cg	(revision 4930)
@@ -0,0 +1,78 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Authors:
+ *   Wei Qiao <qiaow@purdue.edu>
+ */
+
+#include "common.cg"
+
+/*
+ * zincblende shading fragment program
+ * 
+ * renderParams:
+ *   x: sample distance ratio (0 = single slice)
+ *   y: isosurface flag (opacity scaling on/off)
+ *   z: opacity scale
+ */
+PixelOut main(v2f IN, 
+              uniform sampler1D tf,
+              uniform sampler3D volumeA, 
+              uniform sampler3D volumeB, 
+              uniform float4 cellSize,
+              uniform float4x4 modelViewInv,
+              uniform float4 renderParams)
+
+{
+    PixelOut OUT;
+
+    float4 texcoord = mul(modelViewInv, IN.TexCoord);
+    float4 twice_cell_size = cellSize * 2.0;
+
+    // volumeA : outer
+    // volumeB : inner
+    float4 texcoord_2 = texcoord + float4(twice_cell_size.x, 0,                 twice_cell_size.z, 0);
+    float4 texcoord_3 = texcoord + float4(0,                 twice_cell_size.y, twice_cell_size.z, 0);
+    float4 texcoord_4 = texcoord + float4(twice_cell_size.x, twice_cell_size.y, 0, 0); 
+    float4 voxel_corner = tex3D(volumeB, texcoord) + tex3D(volumeA, texcoord - cellSize);
+    float4 voxel_face_center_2 = tex3D(volumeB, texcoord_2) + tex3D(volumeA, texcoord_2 - cellSize);
+    float4 voxel_face_center_3 = tex3D(volumeB, texcoord_3) + tex3D(volumeA, texcoord_3 - cellSize);
+    float4 voxel_face_center_4 = tex3D(volumeB, texcoord_4) + tex3D(volumeA, texcoord_4 - cellSize);
+
+    float sample = (voxel_corner.x + voxel_face_center_2.y + voxel_face_center_3.z + voxel_face_center_4.w) * 0.125;
+    /*
+      float4 texcoord_a = texcoord - float4(twice_cell_size.x, twice_cell_size.y, 0, 0);
+      float4 texcoord_b = texcoord - float4(twice_cell_size.x, 0, twice_cell_size.z, 0);
+      float4 texcoord_c = texcoord - float4(0, twice_cell_size.y, twice_cell_size.z, 0); 
+	
+      float4 voxel_corner = tex3D(volumeA, texcoord) + tex3D(volumeB, texcoord - cellSize);
+      float4 voxel_face_center_a = tex3D(volumeA, texcoord_a) + tex3D(volumeB, texcoord_a - cellSize);
+      float4 voxel_face_center_b = tex3D(volumeA, texcoord_b) + tex3D(volumeB, texcoord_b - cellSize);
+      float4 voxel_face_center_c = tex3D(volumeA, texcoord_c) + tex3D(volumeB, texcoord_c - cellSize);
+      //combine 8 sampling results
+      float sample = (voxel_corner.x + voxel_face_center_a.y + voxel_face_center_b.z + voxel_face_center_c.w) * 0.125;
+    */
+
+    //sample transfer function texture
+    float4 color = tex1D(tf, sample);
+
+    if (renderParams.x == 0.0) {
+        //If single slice render, only flat shading, completely opaque.
+        color.w = 1;
+    } else {
+        //regular volume rendering, we do FLAT SHADING 
+        //since all 4 components of the volume texture has been used to store orbital data,
+        //there is no room to store normal vector. If we really need PHONG shading we have to pass more volumes to
+        //the shader. We might add this later.
+
+        // Opacity scaling: equivalent to scaling transfer function
+        color.w = color.w * renderParams.z;
+        // Apply opacity correction for ratio of current sample distance
+        // to data set sample distance
+        color.w = (1.0 - pow((1.0 - color.w), renderParams.x));
+    }
+
+    OUT.Color = color;
+    return OUT;
+}
Index: /nanovis/tags/1.1.4/util/FilePath.cpp
===================================================================
--- /nanovis/tags/1.1.4/util/FilePath.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/util/FilePath.cpp	(revision 4930)
@@ -0,0 +1,116 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ */
+
+#include <string.h>
+#ifdef _WIN32
+#include <direct.h>
+#endif
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "FilePath.h"
+
+#include "Trace.h"
+
+using namespace nv::util;
+
+std::string FilePath::_curDirectory;
+FilePath FilePath::_instance;
+
+static char seps[] = ":";
+
+FilePath::FilePath()
+{
+    char buff[BUFSIZ+2];
+#ifdef _WIN32
+    _getcwd(buff, sizeof(buff)-1);
+#else
+    if (getcwd(buff, sizeof(buff)-1) == NULL) {
+        ERROR("can't get current working directory\n");
+    }
+#endif
+    size_t length = strlen(buff);
+    buff[length] = '/';
+    buff[length + 1] = '\0';
+    _curDirectory = buff;
+}
+
+bool 
+FilePath::setPath(const char *filePath)
+{
+    char buff[256];
+
+    if (filePath == NULL) {
+        return false;
+    }
+    _pathList.clear();
+
+    char *p;
+    strcpy(buff, filePath);
+    for (p = strtok(buff, seps); p != NULL; p = strtok(NULL, seps)) {
+        char *last;
+        struct stat buf;
+        if ((stat(p, &buf) != 0) || (!S_ISDIR(buf.st_mode))) {
+            return false;
+        }
+        last = p + strlen(p) - 1;
+        if (*p == '/') {
+            if (*last == '/' || *last == '\\') {
+                _pathList.push_back(std::string(p));
+            } else {
+                _pathList.push_back(std::string(p) + "/");
+            }
+        } else {
+            if (*last == '/' || *last == '\\') {
+                _pathList.push_back(_curDirectory + std::string(p));
+            } else {
+                _pathList.push_back(_curDirectory + std::string(p) + "/");
+            }
+        }
+    }
+    return true;
+}
+
+FilePath *
+FilePath::getInstance()
+{
+    return &_instance;
+}
+
+std::string
+FilePath::getPath(const char* fileName)
+{
+    std::string path;
+
+    for (StringListIter iter = _pathList.begin();
+         iter != _pathList.end(); ++iter) {
+        path = *iter + std::string(fileName);
+
+        if (access(path.c_str(), R_OK) == 0) {
+            return path;
+        } else {
+            path = "";
+        }
+    }
+    return path;
+}
+
+void 
+FilePath::setWorkingDirectory(int argc, const char **argv)
+{
+    char buff[256];
+
+    strcpy(buff, argv[0]);
+    for (int i = strlen(buff) - 1; i >= 0; --i) {
+        if (buff[i] == '\\' || buff[i] == '/') {
+            buff[i] = '/';
+            buff[i + 1] = '\0';
+            break;
+        }
+    }
+    _curDirectory = buff;
+}
Index: /nanovis/tags/1.1.4/util/FilePath.h
===================================================================
--- /nanovis/tags/1.1.4/util/FilePath.h	(revision 4930)
+++ /nanovis/tags/1.1.4/util/FilePath.h	(revision 4930)
@@ -0,0 +1,55 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ */
+#ifndef NV_UTIL_FILE_PATH_H
+#define NV_UTIL_FILE_PATH_H
+
+#include <list>
+#include <string>
+
+namespace nv {
+namespace util {
+
+class FilePath
+{
+public:
+    FilePath();
+
+    /**
+     * @brief find a file whose name is fileName and return its full path
+     * @param fileName a file name 
+     * @return return full path of the file, but if not found, return ""
+     */
+    std::string getPath(const char *fileName);
+
+    /**
+     * @brief set default data paths
+     * @param path all default paths separated by colon(:)
+     */
+    bool setPath(const char *path);
+
+    void setWorkingDirectory(int argc, const char **argv);
+
+    /// get FilePath instance
+    static FilePath *getInstance();
+
+private:
+    typedef std::list<std::string> StringList;
+    typedef std::list<std::string>::iterator StringListIter;
+
+    /// application directory
+    static std::string _curDirectory;
+
+    /// FilePath instance
+    static FilePath _instance;
+
+    /// all default file paths
+    StringList _pathList;
+};
+
+}
+}
+
+#endif
+
Index: /nanovis/tags/1.1.4/util/Fonts.cpp
===================================================================
--- /nanovis/tags/1.1.4/util/Fonts.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/util/Fonts.cpp	(revision 4930)
@@ -0,0 +1,245 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ */
+
+#include <stdarg.h>
+#include <string.h>
+
+#include <fstream>
+
+#include <GL/glew.h>
+
+#include "Fonts.h"
+#include "FilePath.h"
+
+using namespace nv::util;
+
+// constants
+const int c_nFileMagicHeader = 6666;
+
+Fonts::Fonts() : 
+    _fontIndex(-1), 
+    _screenWidth(512), 
+    _screenHeight(512)
+{
+}
+
+Fonts::~Fonts()
+{
+    for (unsigned index = 0; index < _fonts.size(); ++index) {
+        glDeleteLists(_fonts[index]._displayLists, 256);
+        glDeleteTextures(1, &(_fonts[_fontIndex]. _fontTextureID));
+    }
+}
+
+void 
+Fonts::setFont(const char *fontName)
+{
+    if (fontName != NULL) {
+        unsigned int i;
+        for (i = 0; i < _fonts.size(); ++i) {
+            if (strcmp(_fonts[i]._fontName.c_str(), fontName) == 0) {
+                _fontIndex = i;
+                break;
+            }
+        }
+    }
+}
+
+void 
+Fonts::addFont(const char *fontName, const char *fontFileName)
+{
+    FontAttributes sFont;
+    
+    loadFont(fontName, fontFileName, sFont);
+    initializeFont(sFont);
+    _fonts.push_back(sFont);
+}
+
+void 
+Fonts::draw(const char *pString, ...) const
+{
+    va_list vlArgs;
+    char szVargsBuffer[1024];
+
+    va_start(vlArgs, pString);
+    vsprintf(szVargsBuffer, pString, vlArgs);
+
+    if (_fontIndex != -1) {
+        int length = strlen(szVargsBuffer);
+
+        glListBase(_fonts[_fontIndex]._displayLists);
+        glCallLists(length, GL_UNSIGNED_BYTE, 
+                    reinterpret_cast<const GLvoid*>(szVargsBuffer));
+    }
+}
+
+void 
+Fonts::begin()
+{
+    glPushAttrib(GL_TRANSFORM_BIT | GL_ENABLE_BIT | GL_TEXTURE_BIT);
+    glEnable(GL_TEXTURE_2D);
+    glBindTexture(GL_TEXTURE_2D, _fonts[_fontIndex]._fontTextureID);
+    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+    glMatrixMode(GL_PROJECTION);
+    glPushMatrix();
+    glLoadIdentity();
+
+    gluOrtho2D(0.0f, _screenWidth, _screenHeight, 0.0f);
+
+    glMatrixMode(GL_MODELVIEW);
+    glPushMatrix();
+    glLoadIdentity();
+
+    glEnable(GL_BLEND);
+    glDisable(GL_DEPTH_TEST);
+}
+
+void 
+Fonts::end()
+{
+    glBindTexture(GL_TEXTURE_2D, 0);
+
+    glMatrixMode(GL_PROJECTION);
+    glPopMatrix();
+
+    glMatrixMode(GL_MODELVIEW);
+    glPopMatrix();
+
+    glPopAttrib();
+}
+
+void 
+Fonts::initializeFont(FontAttributes& attr)
+{
+    attr._displayLists = glGenLists(256);
+
+    int index;
+    for (index = 0; index < 256; ++index) {
+        FontAttributes::CharInfo& charInfo = attr._chars[index];
+        glNewList(attr._displayLists + index, GL_COMPILE);
+        if (charInfo._valid) {
+            glBegin(GL_TRIANGLE_STRIP);
+            
+            glTexCoord2f(charInfo._left, charInfo._top); 
+            glVertex2i(0, 0);
+            
+            glTexCoord2f(charInfo._left, charInfo._bottom);
+            glVertex2i(0, (GLint)attr._fontHeight);
+            
+            glTexCoord2f(charInfo._right, charInfo._top);
+            glVertex2i((GLint)charInfo._width, 0);
+            
+            glTexCoord2f(charInfo._right,  charInfo._bottom);
+            glVertex2i((GLint)charInfo._width, (GLint)attr._fontHeight);
+            
+            glEnd();
+            glTranslatef(charInfo._width, 0.0f, 0.0f);
+        }
+        glEndList();
+    }
+}
+
+bool 
+Fonts::loadFont(const char *fontName, const char *fontFileName, 
+                FontAttributes& sFont)
+{
+    bool bSuccess = false;
+
+    std::string path = FilePath::getInstance()->getPath(fontFileName);
+    if (path.empty()) {
+        return false;
+    }
+    std::ifstream fsInput(path.c_str(), std::ios::binary);
+    if (fsInput) {
+        sFont._fontName = fontName;
+
+        // make sure this file is the correct type by checking the header
+        unsigned int uiFileId = 0;
+        fsInput.read(reinterpret_cast<char*>(&uiFileId), sizeof(unsigned int));
+        if (uiFileId == (unsigned int)c_nFileMagicHeader) {
+            // read general font/texture dimensions
+            fsInput.read(reinterpret_cast<char*>(&sFont._textureWidth), 
+                         sizeof(unsigned int));
+            fsInput.read(reinterpret_cast<char*>(&sFont._textureHeight), 
+                         sizeof(unsigned int));
+            fsInput.read(reinterpret_cast<char*>(&sFont._fontHeight), 
+                         sizeof(unsigned int));
+
+            // read dimensions for each character in 256-char ASCII chart
+            for (int i = 0; i < 256; ++i) {
+                unsigned int uiSize = 0;
+
+                // top
+                fsInput.read(reinterpret_cast<char*>(&uiSize), 
+                             sizeof(unsigned int));
+                sFont._chars[i]._top = static_cast<float>(uiSize) / sFont._textureHeight;
+                // left
+                fsInput.read(reinterpret_cast<char*>(&uiSize), sizeof(unsigned int));
+                sFont._chars[i]._left = static_cast<float>(uiSize) / sFont._textureWidth;
+                // bottom
+                fsInput.read(reinterpret_cast<char*>(&uiSize), sizeof(unsigned int));
+                sFont._chars[i]._bottom = static_cast<float>(uiSize) / sFont._textureHeight;
+                // right
+                fsInput.read(reinterpret_cast<char*>(&uiSize), sizeof(unsigned int));
+                sFont._chars[i]._right = static_cast<float>(uiSize) / sFont._textureWidth;
+                // enabled
+                fsInput.read(reinterpret_cast<char*>(&uiSize), sizeof(unsigned int));
+                sFont._chars[i]._valid = (uiSize != 0);
+                // width factor
+                float fWidthFactor = 1.0f;
+                fsInput.read(reinterpret_cast<char*>(&fWidthFactor), sizeof(float));
+                sFont._chars[i]._width = fWidthFactor * sFont._fontHeight;
+            }
+        }
+
+        // allocate and read the texture map
+        if (!fsInput.eof() && !fsInput.fail()) {
+            unsigned int uiArea = sFont._textureWidth * sFont._textureHeight;
+            unsigned char *pRawMap = new unsigned char[uiArea];
+            fsInput.read(reinterpret_cast<char *>(pRawMap), uiArea);
+
+            // we've only read the luminance values, but we need a luminance +
+            // alpha buffer, so we make a new buffer and duplicate the
+            // luminance values
+            unsigned char *pTexMap = new unsigned char[2 * uiArea];
+            unsigned char *pMap = pTexMap;
+            for (unsigned int i = 0; i < uiArea; ++i) {
+                *pMap++ = pRawMap[i];
+                *pMap++ = pRawMap[i];
+            }
+            delete[] pRawMap;
+            pRawMap = NULL;
+
+            // make texture map out of new buffer
+            glGenTextures(1, &sFont._fontTextureID);
+            glBindTexture(GL_TEXTURE_2D, sFont._fontTextureID);
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+            glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, 
+                         sFont._textureWidth, sFont._textureHeight, 0, 
+                         GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, pTexMap);
+            glBindTexture(GL_TEXTURE_2D, 0);
+
+            delete[] pTexMap;
+            pTexMap = NULL;
+
+            bSuccess = true;
+        }
+
+        fsInput.close();
+    }
+    return bSuccess;
+}
+
+void 
+Fonts::resize(int width, int height)
+{
+    _screenWidth = width;
+    _screenHeight = height;
+}
+
Index: /nanovis/tags/1.1.4/util/Fonts.h
===================================================================
--- /nanovis/tags/1.1.4/util/Fonts.h	(revision 4930)
+++ /nanovis/tags/1.1.4/util/Fonts.h	(revision 4930)
@@ -0,0 +1,84 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ */
+#ifndef NV_UTIL_FONTS_H
+#define NV_UTIL_FONTS_H
+
+#include <vector>
+#include <string>
+
+namespace nv {
+namespace util {
+
+class Fonts
+{
+public:
+    struct FontAttributes {
+        std::string _fontName;
+        int _textureWidth;
+        int _textureHeight;
+        int _fontHeight;
+        unsigned int _fontTextureID;
+        unsigned int _displayLists;
+
+        struct CharInfo {
+            float _left;
+            float _right;
+            float _top;
+            float _bottom;
+            bool _valid;
+            float _width;
+        };
+        CharInfo _chars[256];
+    };
+
+    Fonts();
+    ~Fonts();
+
+    /// set projection to orthographic
+    void begin();
+
+    /// reset projection matrix
+    void end();
+
+    /// initialize FontAttributes
+    void initializeFont(FontAttributes& attr);
+
+    /**
+     * @brief load font data
+     */
+    bool loadFont(const char *fontName, const char *fontFileName, FontAttributes& sFont);
+
+    void addFont(const char *fontName, const char *fontFileName);
+
+    void setFont(const char *fontName);
+
+    void draw(const char *pString, ...) const;
+
+    void resize(int width, int height);
+
+    /// return font height
+    int getFontHeight() const;
+
+private:
+    typedef std::vector<FontAttributes> FontVector;
+
+    FontVector _fonts;
+    /// current font index
+    int _fontIndex;
+    // screen width
+    int _screenWidth;
+    /// screen height
+    int _screenHeight;
+};
+
+inline int Fonts::getFontHeight() const
+{
+    return _fonts[_fontIndex]._fontHeight;
+}
+
+}
+}
+
+#endif
Index: /nanovis/tags/1.1.4/util/Makefile.in
===================================================================
--- /nanovis/tags/1.1.4/util/Makefile.in	(revision 4930)
+++ /nanovis/tags/1.1.4/util/Makefile.in	(revision 4930)
@@ -0,0 +1,65 @@
+
+SHELL = /bin/sh
+
+.PHONY: all install clean distclean
+
+bindir          = @bindir@
+datadir		= @datadir@
+datarootdir	= @datarootdir@
+exec_prefix     = @exec_prefix@
+includedir      = @includedir@
+libdir          = @libdir@
+mandir          = @mandir@
+prefix          = @prefix@
+srcdir		= @srcdir@
+
+INSTALL		= @INSTALL@
+INSTALL_PROGRAM	= ${INSTALL} -m 555
+INSTALL_DATA	= ${INSTALL} -m 444
+INSTALL_SCRIPT	= ${INSTALL} -m 444
+RM		= rm -f
+AR		= ar rc
+RANLIB		= @RANLIB@
+CC		= @CC@
+CXX		= @CXX@
+VPATH		= $(srcdir)
+
+RP_DIR          =  @RP_DIR@
+RP_INC_SPEC     = -I$(RP_DIR)/include -I$(RP_DIR)/include/rappture2
+
+INCLUDES	= \
+		-I$(srcdir)/include \
+		-I$(srcdir)/.. \
+		$(RP_INC_SPEC)
+
+CFLAGS		= @CFLAGS@ 
+EXTRA_CFLAGS	= -Wall 
+DEFINES		= @DEFINES@
+CXX_SWITCHES	= $(CFLAGS) $(EXTRA_CFLAGS) $(INCLUDES)
+
+NVUTILLIB	= nvutil.a
+
+OBJS		= \
+		FilePath.o \
+		Fonts.o
+
+all: $(NVUTILLIB)
+
+install: all
+
+$(NVUTILLIB): $(OBJS)
+	$(RM) $@
+	$(AR) $@ $(OBJS) 
+	$(RANLIB) $@
+
+.cpp.o:
+	$(CXX) $(CXX_SWITCHES) -o $@ -c $<
+
+clean:
+	$(RM) *.a *.o
+
+distclean: clean
+	$(RM) Makefile *~
+
+FilePath.o: FilePath.h $(srcdir)/../Trace.h
+Fonts.o: Fonts.h
Index: /nanovis/tags/1.1.4/vrmath/BBox.cpp
===================================================================
--- /nanovis/tags/1.1.4/vrmath/BBox.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/vrmath/BBox.cpp	(revision 4930)
@@ -0,0 +1,160 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Author: Insoo Woo <iwoo@purdue.edu>
+ */
+
+#include <float.h>
+
+#include <vrmath/BBox.h>
+#include <vrmath/Matrix4x4d.h>
+#include <vrmath/Vector3f.h>
+#include <vrmath/Vector4f.h>
+
+using namespace vrmath;
+
+BBox::BBox()
+{
+    makeEmpty();
+}
+
+BBox::BBox(const BBox& other) :
+    min(other.min),
+    max(other.max)
+{
+}
+
+BBox::BBox(const Vector3f& minv, const Vector3f& maxv) :
+    min(minv),
+    max(maxv)
+{
+}
+
+void BBox::makeEmpty()
+{
+    min.set(FLT_MAX, FLT_MAX, FLT_MAX);
+    max.set(-FLT_MAX, -FLT_MAX, -FLT_MAX);
+}
+
+bool BBox::isEmpty()
+{
+    return (isEmptyX() && isEmptyY() && isEmptyZ());
+}
+
+bool BBox::isEmptyX()
+{
+    return (min.x > max.x);
+}
+
+bool BBox::isEmptyY()
+{
+    return (min.y > max.y);
+}
+
+bool BBox::isEmptyZ()
+{
+    return (min.z > max.z);
+}
+
+void BBox::make(const Vector3f& center, const Vector3f& size)
+{
+    float halfX = size.x * 0.5f, halfY = size.y * 0.5f, halfZ = size.z * 0.5f;
+
+    min.x = center.x - halfX;
+    max.x = center.x + halfX;
+
+    min.y = center.y - halfY;
+    max.y = center.y + halfY;
+
+    min.z = center.z - halfZ;
+    max.z = center.z + halfZ;
+}
+
+void BBox::extend(const Vector3f& point)
+{
+    if (min.x > point.x) {
+        min.x = point.x;
+    } else if (max.x < point.x)	{
+        max.x = point.x;
+    }
+
+    if (min.y > point.y) {
+        min.y = point.y;
+    } else if (max.y < point.y)	{
+        max.y = point.y;
+    }
+
+    if (min.z > point.z) {
+        min.z = point.z;
+    } else if (max.z < point.z)	{
+        max.z = point.z;
+    }
+}
+
+void BBox::extend(const BBox& box)
+{
+    if (min.x > box.min.x) min.x = box.min.x;
+    if (min.y > box.min.y) min.y = box.min.y;
+    if (min.z > box.min.z) min.z = box.min.z;
+
+    if (max.x < box.max.x) max.x = box.max.x;
+    if (max.y < box.max.y) max.y = box.max.y;
+    if (max.z < box.max.z) max.z = box.max.z;
+}
+
+void BBox::transform(const BBox& box, const Matrix4x4d& mat)
+{
+    float x0 = box.min.x;
+    float y0 = box.min.y;
+    float z0 = box.min.z;
+    float x1 = box.max.x;
+    float y1 = box.max.y;
+    float z1 = box.max.z;
+
+    Vector4f points[8];
+
+    points[0].set(x0, y0, z0, 1);
+    points[1].set(x1, y0, z0, 1);
+    points[2].set(x0, y1, z0, 1);
+    points[3].set(x0, y0, z1, 1);
+    points[4].set(x1, y1, z0, 1);
+    points[5].set(x1, y0, z1, 1);
+    points[6].set(x0, y1, z1, 1);
+    points[7].set(x1, y1, z1, 1);
+
+    float minX = FLT_MAX, minY = FLT_MAX, minZ = FLT_MAX;
+    float maxX = -FLT_MAX, maxY = -FLT_MAX, maxZ = -FLT_MAX;
+
+    for (int i = 0; i < 8; i++) {
+        points[i] = mat.transform(points[i]);
+
+        if (points[i].x > maxX) maxX = points[i].x;
+        if (points[i].x < minX) minX = points[i].x;
+        if (points[i].y > maxY) maxY = points[i].y;
+        if (points[i].y < minY) minY = points[i].y;
+        if (points[i].z > maxZ) maxZ = points[i].z;
+        if (points[i].z < minZ) minZ = points[i].z;
+    }
+
+    min.set(minX, minY, minZ);
+    max.set(maxX, maxY, maxZ);
+}
+
+bool BBox::intersect(const BBox& box)
+{
+    if (min.x > box.max.x || max.x < box.min.x) return false;
+    if (min.y > box.max.y || max.y < box.min.y) return false;
+    if (min.z > box.max.z || max.z < box.min.z) return false;
+
+    return true;
+}
+
+bool BBox::contains(const Vector3f& point)
+{
+    if ((point.x < min.x) || (point.x > max.x)) return false;
+    if ((point.y < min.y) || (point.y > max.y)) return false;
+    if ((point.z < min.z) || (point.z > max.z)) return false;
+
+    return true;
+}
Index: /nanovis/tags/1.1.4/vrmath/BPlane.cpp
===================================================================
--- /nanovis/tags/1.1.4/vrmath/BPlane.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/vrmath/BPlane.cpp	(revision 4930)
@@ -0,0 +1,65 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Author: Insoo Woo <iwoo@purdue.edu>
+ */
+
+#include <vrmath/BPlane.h>
+#include <vrmath/Vector3f.h>
+#include <vrmath/LineSegment.h>
+
+using namespace vrmath;
+
+void BPlane::makePts(const Vector3f& p1, const Vector3f& p2, const Vector3f& p3)
+{
+    normal = cross(p2 - p1, p3 - p1);
+    normal = normal.normalize();
+
+    point = p1;
+}
+
+void BPlane::makeNormalPt(const Vector3f& norm, const Vector3f& pos)
+{
+    normal = norm;
+    point = pos;
+}
+
+bool BPlane::intersect(const LineSegment &seg, float &d) const 
+{
+    float tu, td;
+
+    tu = normal.x * (point.x - seg.pos.x) +
+         normal.y * (point.y - seg.pos.y) +
+         normal.z * (point.z - seg.pos.z);
+
+    td = normal.x * seg.dir.x +
+         normal.y * seg.dir.y +
+         normal.z * seg.dir.z;
+
+    if ( td == 0.0f ) return false;
+
+    d = tu / td;
+
+    return true;
+}
+
+double BPlane::distance(const Vector3f& pos) const 
+{
+    Vector3f plane_point = crossPoint(pos);
+
+    return pos.distance(plane_point);
+}
+
+Vector3f BPlane::crossPoint(const Vector3f& pos) const
+{
+    LineSegment seg;
+
+    seg.pos.set(pos.x, pos.y, pos.z, 1);
+    seg.dir = normal;
+
+    float t = 0;
+    intersect(seg, t);
+
+    return seg.getPoint(t);
+}
Index: /nanovis/tags/1.1.4/vrmath/LineSegment.cpp
===================================================================
--- /nanovis/tags/1.1.4/vrmath/LineSegment.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/vrmath/LineSegment.cpp	(revision 4930)
@@ -0,0 +1,27 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Author: Insoo Woo <iwoo@purdue.edu>
+ */
+
+#include <vrmath/LineSegment.h>
+#include <vrmath/Matrix4x4d.h>
+
+using namespace vrmath;
+
+LineSegment::LineSegment():
+    pos(0, 0, 0, 1), dir(0.0f, 0.0f, -1.0f), length(0.0f)
+{
+}
+
+void LineSegment::transform(const Matrix4x4d &mat, const LineSegment &seg)
+{
+    pos = mat.transform(seg.pos);
+
+    dir *= length;
+
+    dir = mat.transformVec(seg.dir);
+    length = dir.length();
+    dir = dir.normalize();
+}
Index: /nanovis/tags/1.1.4/vrmath/Makefile.in
===================================================================
--- /nanovis/tags/1.1.4/vrmath/Makefile.in	(revision 4930)
+++ /nanovis/tags/1.1.4/vrmath/Makefile.in	(revision 4930)
@@ -0,0 +1,87 @@
+
+SHELL = /bin/sh
+
+.PHONY: all install clean distclean
+
+bindir          = @bindir@
+datadir		= @datadir@
+datarootdir	= @datarootdir@
+exec_prefix     = @exec_prefix@
+includedir      = @includedir@
+libdir          = @libdir@
+mandir          = @mandir@
+prefix          = @prefix@
+srcdir		= @srcdir@
+
+INSTALL		= @INSTALL@
+INSTALL_PROGRAM	= ${INSTALL} -m 555
+INSTALL_DATA	= ${INSTALL} -m 444
+INSTALL_SCRIPT	= ${INSTALL} -m 444
+RM		= rm -f
+AR		= ar rc
+RANLIB		= @RANLIB@
+CC		= @CC@
+CXX		= @CXX@
+VPATH		= $(srcdir)
+
+RP_DIR          =  @RP_DIR@
+RP_INC_SPEC     = -I$(RP_DIR)/include -I$(RP_DIR)/include/rappture2
+
+INCLUDES	= \
+		-I$(srcdir)/include \
+		-I$(srcdir)/.. \
+		$(RP_INC_SPEC)
+
+CFLAGS		= @CFLAGS@ 
+EXTRA_CFLAGS	= -Wall 
+DEFINES		= @DEFINES@
+CXX_SWITCHES	= $(CFLAGS) $(EXTRA_CFLAGS) $(INCLUDES)
+
+VRMATHLIB	= vrmath.a
+
+#		BPlane.o \
+#		Projection.o \
+
+OBJS		= \
+		BBox.o \
+		LineSegment.o \
+		Matrix4x4f.o \
+		Matrix4x4d.o \
+		Plane.o \
+		Quaternion.o \
+		Rotation.o \
+		Vector2f.o \
+		Vector3f.o \
+		Vector4f.o \
+
+.PHONY: all install clean distclean
+
+all: $(VRMATHLIB)
+
+install: all
+
+$(VRMATHLIB): $(OBJS)
+	$(RM) $@
+	$(AR) $@ $(OBJS) 
+	$(RANLIB) $@
+
+.cpp.o:
+	$(CXX) $(CXX_SWITCHES) -o $@ -c $<
+
+clean:
+	$(RM) *.a *.o
+
+distclean: clean
+	$(RM) Makefile *~
+
+BBox.o: $(srcdir)/include/vrmath/BBox.h $(srcdir)/include/vrmath/Vector3f.h
+BPlane.o: $(srcdir)/include/vrmath/BPlane.h $(srcdir)/include/vrmath/Vector3f.h $(srcdir)/include/vrmath/LineSegment.h
+LineSegment.o: $(srcdir)/include/vrmath/LineSegment.h
+Matrix4x4d.o: $(srcdir)/include/vrmath/Matrix4x4d.h $(srcdir)/include/vrmath/Vector3f.h $(srcdir)/include/vrmath/Vector4f.h $(srcdir)/include/vrmath/Rotation.h
+Matrix4x4f.o: $(srcdir)/include/vrmath/Matrix4x4f.h $(srcdir)/include/vrmath/Vector3f.h $(srcdir)/include/vrmath/Vector4f.h $(srcdir)/include/vrmath/Rotation.h
+Plane.o: $(srcdir)/include/vrmath/Plane.h $(srcdir)/include/vrmath/Matrix4x4f.h
+Quaternion.o: $(srcdir)/include/vrmath/Quaternion.h $(srcdir)/include/vrmath/Rotation.h $(srcdir)/include/vrmath/Vector3f.h
+Rotation.o: $(srcdir)/include/vrmath/Quaternion.h $(srcdir)/include/vrmath/Rotation.h $(srcdir)/include/vrmath/Vector3f.h
+Vector2f.o: $(srcdir)/include/vrmath/Vector2f.h
+Vector3f.o: $(srcdir)/include/vrmath/Vector3f.h $(srcdir)/include/vrmath/Matrix4x4f.h
+Vector4f.o: $(srcdir)/include/vrmath/Vector4f.h $(srcdir)/include/vrmath/Matrix4x4f.h
Index: /nanovis/tags/1.1.4/vrmath/Matrix4x4d.cpp
===================================================================
--- /nanovis/tags/1.1.4/vrmath/Matrix4x4d.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/vrmath/Matrix4x4d.cpp	(revision 4930)
@@ -0,0 +1,851 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Author: Insoo Woo <iwoo@purdue.edu>
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#include <vrmath/Matrix4x4d.h>
+#include <vrmath/Vector3f.h>
+#include <vrmath/Rotation.h>
+
+using namespace vrmath;
+
+void Matrix4x4d::makeIdentity()
+{
+    _data[1] = _data[2] = _data[3] = _data[4] =
+        _data[6] = _data[7] = _data[8] = _data[9] =
+        _data[11] = _data[12] = _data[13] = _data[14] = 0.0;
+    _data[0] = _data[5] = _data[10] = _data[15] = 1.0;
+}
+
+void Matrix4x4d::makeTranslation(const Vector3f& translation)
+{
+    _data[1] = _data[2] = _data[3] = _data[4] =
+        _data[6] = _data[7] = _data[8] = _data[9] =
+        _data[11] = 0.0;
+    _data[0] = _data[5] = _data[10] = _data[15] = 1.0;
+    _data[12] = translation.x;
+    _data[13] = translation.y;
+    _data[14] = translation.z;
+}
+
+void Matrix4x4d::makeTranslation(double x, double y, double z)
+{
+    _data[1] = _data[2] = _data[3] = _data[4] =
+        _data[6] = _data[7] = _data[8] = _data[9] =
+        _data[11] = 0.0;
+    _data[0] = _data[5] = _data[10] = _data[15] = 1.0;
+    _data[12] = x;
+    _data[13] = y;
+    _data[14] = z;
+}
+
+void Matrix4x4d::makeRotation(const Rotation& rotation)
+{
+    if (rotation.getAngle() == 0.0 || 
+        (rotation.getX() == 0.0 &&
+         rotation.getY() == 0.0 &&
+         rotation.getZ() == 0.0)) {
+        makeIdentity();
+        return;
+    }
+
+    double xAxis = rotation.getX();
+    double yAxis = rotation.getY();
+    double zAxis = rotation.getZ();
+    double invLen = 1.0 / sqrt(xAxis * xAxis + yAxis * yAxis + zAxis * zAxis);
+    double cosine = cos(rotation.getAngle());
+    double sine = sin(rotation.getAngle());
+
+    xAxis *= invLen;
+    yAxis *= invLen;
+    zAxis *= invLen;
+
+    double oneMinusCosine = 1.0 - cosine;
+
+    _data[3] = _data[7] = _data[11] = _data[12] = _data[13] = _data[14] = 0.0;
+    _data[15] = 1.0;
+
+    _data[0] = xAxis * xAxis * oneMinusCosine + cosine;
+    _data[1] = yAxis * xAxis * oneMinusCosine + zAxis * sine;
+    _data[2] = xAxis * zAxis * oneMinusCosine - yAxis * sine;
+
+    _data[4] = xAxis * yAxis * oneMinusCosine - zAxis * sine;
+    _data[5] = yAxis * yAxis * oneMinusCosine + cosine;
+    _data[6] = yAxis * zAxis * oneMinusCosine + xAxis * sine;
+
+    _data[8] = xAxis * zAxis * oneMinusCosine + yAxis * sine;
+    _data[9] = yAxis * zAxis * oneMinusCosine - xAxis * sine;
+    _data[10] = zAxis * zAxis * oneMinusCosine + cosine;
+}
+
+void Matrix4x4d::makeRotation(double xAxis, double yAxis, double zAxis, double angle)
+{
+    if (angle == 0.0 ||
+        (xAxis == 0.0 &&
+         yAxis == 0.0 &&
+         zAxis == 0.0)) {
+        makeIdentity();
+        return;
+    }
+
+    double invLen = 1.0f / sqrt(xAxis * xAxis + yAxis * yAxis + zAxis * zAxis);
+    double cosine = cos(angle);
+    double sine = sin(angle);
+
+    xAxis *= invLen;
+    yAxis *= invLen;
+    zAxis *= invLen;
+
+    float oneMinusCosine = 1.0 - cosine;
+
+    _data[3] = _data[7] = _data[11] = _data[12] = _data[13] = _data[14] = 0.0;
+    _data[15] = 1.0;
+
+    _data[0] = xAxis * xAxis * oneMinusCosine + cosine;
+    _data[1] = yAxis * xAxis * oneMinusCosine + zAxis * sine;
+    _data[2] = xAxis * zAxis * oneMinusCosine - yAxis * sine;
+
+    _data[4] = xAxis * yAxis * oneMinusCosine - zAxis * sine;
+    _data[5] = yAxis * yAxis * oneMinusCosine + cosine;
+    _data[6] = yAxis * zAxis * oneMinusCosine + xAxis * sine;
+
+    _data[8] = xAxis * zAxis * oneMinusCosine + yAxis * sine;
+    _data[9] = yAxis * zAxis * oneMinusCosine - xAxis * sine;
+    _data[10] = zAxis * zAxis * oneMinusCosine + cosine;
+}
+
+void Matrix4x4d::makeScale(const Vector3f& scale)
+{
+    _data[1] = _data[2] = _data[3] = _data[4] =
+        _data[6] = _data[7] = _data[8] = _data[9] =
+        _data[11] = 0.0f;
+
+    _data[0] = scale.x;
+    _data[5] = scale.y;
+    _data[10] = scale.z;
+
+    _data[15] = 1.0f;
+    _data[12] = _data[13] = _data[14] = 0.0f;
+}
+
+void Matrix4x4d::makeScale(double x, double y, double z)
+{
+    _data[1] = _data[2] = _data[3] = _data[4] =
+        _data[6] = _data[7] = _data[8] = _data[9] =
+        _data[11] = 0.0f;
+
+    _data[0] = x;
+    _data[5] = y;
+    _data[10] = z;
+
+    _data[15] = 1.0f;
+    _data[12] = _data[13] = _data[14] = 0.0f;
+}
+
+Vector4f
+Matrix4x4d::transform(const Vector4f& v) const
+{
+    Vector4f ret;
+    ret.x = float(_data[0] * v.x + _data[4] * v.y + _data[8] * v.z  + _data[12] * v.w);
+    ret.y = float(_data[1] * v.x + _data[5] * v.y + _data[9] * v.z  + _data[13] * v.w);
+    ret.z = float(_data[2] * v.x + _data[6] * v.y + _data[10] * v.z + _data[14] * v.w);
+    ret.w = float(_data[3] * v.x + _data[7] * v.y + _data[11] * v.z + _data[15] * v.w);
+    return ret;
+}
+
+Vector3f
+Matrix4x4d::transformVec(const Vector3f& v) const
+{
+    Vector3f ret;
+    ret.x = float(_data[0] * v.x + _data[4] * v.y + _data[8] * v.z);
+    ret.y = float(_data[1] * v.x + _data[5] * v.y + _data[9] * v.z);
+    ret.z = float(_data[2] * v.x + _data[6] * v.y + _data[10] * v.z);
+    return ret;
+}
+
+Vector4f
+Matrix4x4d::preMultiplyRowVector(const Vector4f& v) const
+{
+    Vector4f ret;
+    ret.x = float(_data[0]  * v.x + _data[1]  * v.y + _data[2]  * v.z + _data[3]  * v.w);
+    ret.y = float(_data[4]  * v.x + _data[5]  * v.y + _data[6]  * v.z + _data[7]  * v.w);
+    ret.z = float(_data[8]  * v.x + _data[9]  * v.y + _data[10] * v.z + _data[11] * v.w);
+    ret.w = float(_data[12] * v.x + _data[13] * v.y + _data[14] * v.z + _data[15] * v.w);
+    return ret;
+}
+
+void Matrix4x4d::multiply(const Matrix4x4d& m)
+{
+    double mat[16];
+    const double *mat2 = m._data;
+
+    // 1 row
+    mat[0] = _data[0] * mat2[0] + _data[4] * mat2[1] + 
+             _data[8] * mat2[2] + _data[12] * mat2[3];
+    mat[4] = _data[0] * mat2[4] + _data[4] * mat2[5] + 
+             _data[8] * mat2[6] + _data[12] * mat2[7];
+    mat[8] = _data[0] * mat2[8] + _data[4] * mat2[9] + 
+             _data[8] * mat2[10] + _data[12] * mat2[11];
+    mat[12] = _data[0] * mat2[12] + _data[4] * mat2[13] + 
+              _data[8] * mat2[14] + _data[12] * mat2[15];
+
+    // 2 row
+    mat[1] = _data[1] * mat2[0] + _data[5] * mat2[1] + 
+             _data[9] * mat2[2] + _data[13] * mat2[3];
+    mat[5] = _data[1] * mat2[4] + _data[5] * mat2[5] + 
+             _data[9] * mat2[6] + _data[13] * mat2[7];
+    mat[9] = _data[1] * mat2[8] + _data[5] * mat2[9] + 
+             _data[9] * mat2[10] + _data[13] * mat2[11];
+    mat[13] = _data[1] * mat2[12] + _data[5] * mat2[13] + 
+              _data[9] * mat2[14] + _data[13] * mat2[15];
+
+    // 3 row
+    mat[2] = _data[2] * mat2[0] + _data[6] * mat2[1] + 
+             _data[10] * mat2[2] + _data[14] * mat2[3];
+    mat[6] = _data[2] * mat2[4] + _data[6] * mat2[5] + 
+             _data[10] * mat2[6] + _data[14] * mat2[7];
+    mat[10] = _data[2] * mat2[8] + _data[6] * mat2[9] + 
+              _data[10] * mat2[10] + _data[14] * mat2[11];
+    mat[14] = _data[2] * mat2[12] + _data[6] * mat2[13] + 
+              _data[10] * mat2[14] + _data[14] * mat2[15];
+
+    // 4 row
+    mat[3] = _data[3] * mat2[0] + _data[7] * mat2[1] + 
+             _data[11] * mat2[2] + _data[15] * mat2[3];
+    mat[7] = _data[3] * mat2[4] + _data[7] * mat2[5] + 
+             _data[11] * mat2[6] + _data[15] * mat2[7];
+    mat[11] = _data[3] * mat2[8] + _data[7] * mat2[9] + 
+              _data[11] * mat2[10] + _data[15] * mat2[11];
+    mat[15] = _data[3] * mat2[12] + _data[7] * mat2[13] + 
+              _data[11] * mat2[14] + _data[15] * mat2[15];
+
+    // set matrix
+    set(mat);
+}
+
+void Matrix4x4d::multiply(const Matrix4x4d& m1, const Matrix4x4d& m2)
+{
+    if (&m1 == this && &m2 != this) {
+        multiply(m2);
+    } else if (&m1 != this && &m2 != this) {
+        multiplyFast(m1, m2);
+    } else {
+        double mat[16];
+        const double *mat1 = m1._data;
+        const double *mat2 = m2._data;
+
+        // 1 row
+        mat[0] = mat1[0] * mat2[0] + mat1[4] * mat2[1] + 
+            mat1[8] * mat2[2] + mat1[12] * mat2[3];
+        mat[4] = mat1[0] * mat2[4] + mat1[4] * mat2[5] + 
+            mat1[8] * mat2[6] + mat1[12] * mat2[7];
+        mat[8] = mat1[0] * mat2[8] + mat1[4] * mat2[9] + 
+            mat1[8] * mat2[10] + mat1[12] * mat2[11];
+        mat[12] = mat1[0] * mat2[12] + mat1[4] * mat2[13] + 
+            mat1[8] * mat2[14] + mat1[12] * mat2[15];
+
+        // 2 row
+        mat[1] = mat1[1] * mat2[0] + mat1[5] * mat2[1] + 
+            mat1[9] * mat2[2] + mat1[13] * mat2[3];
+        mat[5] = mat1[1] * mat2[4] + mat1[5] * mat2[5] + 
+            mat1[9] * mat2[6] + mat1[13] * mat2[7];
+        mat[9] = mat1[1] * mat2[8] + mat1[5] * mat2[9] + 
+            mat1[9] * mat2[10] + mat1[13] * mat2[11];
+        mat[13] = mat1[1] * mat2[12] + mat1[5] * mat2[13] + 
+            mat1[9] * mat2[14] + mat1[13] * mat2[15];
+
+        // 3 row
+        mat[2] = mat1[2] * mat2[0] + mat1[6] * mat2[1] + 
+            mat1[10] * mat2[2] + mat1[14] * mat2[3];
+        mat[6] = mat1[2] * mat2[4] + mat1[6] * mat2[5] + 
+            mat1[10] * mat2[6] + mat1[14] * mat2[7];
+        mat[10] = mat1[2] * mat2[8] + mat1[6] * mat2[9] + 
+            mat1[10] * mat2[10] + mat1[14] * mat2[11];
+        mat[14] = mat1[2] * mat2[12] + mat1[6] * mat2[13] + 
+            mat1[10] * mat2[14] + mat1[14] * mat2[15];
+
+        // 4 row
+        mat[3] = mat1[3] * mat2[0] + mat1[7] * mat2[1] + 
+            mat1[11] * mat2[2] + mat1[15] * mat2[3];
+        mat[7] = mat1[3] * mat2[4] + mat1[7] * mat2[5] + 
+            mat1[11] * mat2[6] + mat1[15] * mat2[7];
+        mat[11] = mat1[3] * mat2[8] + mat1[7] * mat2[9] + 
+            mat1[11] * mat2[10] + mat1[15] * mat2[11];
+        mat[15] = mat1[3] * mat2[12] + mat1[7] * mat2[13] + 
+            mat1[11] * mat2[14] + mat1[15] * mat2[15];
+
+        // set matrix
+        set(mat);
+    }
+}
+
+void Matrix4x4d::multiplyFast(const Matrix4x4d& m1, const Matrix4x4d& m2)
+{
+    const double *mat1 = m1._data;
+    const double *mat2 = m2._data;
+
+    // 1 row
+    _data[0] = mat1[0] * mat2[0] + mat1[4] * mat2[1] + 
+               mat1[8] * mat2[2] + mat1[12] * mat2[3];
+    _data[4] = mat1[0] * mat2[4] + mat1[4] * mat2[5] + 
+               mat1[8] * mat2[6] + mat1[12] * mat2[7];
+    _data[8] = mat1[0] * mat2[8] + mat1[4] * mat2[9] + 
+               mat1[8] * mat2[10] + mat1[12] * mat2[11];
+    _data[12] = mat1[0] * mat2[12] + mat1[4] * mat2[13] + 
+                mat1[8] * mat2[14] + mat1[12] * mat2[15];
+
+    // 2 row
+    _data[1] = mat1[1] * mat2[0] + mat1[5] * mat2[1] + 
+               mat1[9] * mat2[2] + mat1[13] * mat2[3];
+    _data[5] = mat1[1] * mat2[4] + mat1[5] * mat2[5] + 
+               mat1[9] * mat2[6] + mat1[13] * mat2[7];
+    _data[9] = mat1[1] * mat2[8] + mat1[5] * mat2[9] + 
+               mat1[9] * mat2[10] + mat1[13] * mat2[11];
+    _data[13] = mat1[1] * mat2[12] + mat1[5] * mat2[13] + 
+                mat1[9] * mat2[14] + mat1[13] * mat2[15];
+
+    // 3 row
+    _data[2] = mat1[2] * mat2[0] + mat1[6] * mat2[1] + 
+               mat1[10] * mat2[2] + mat1[14] * mat2[3];
+    _data[6] = mat1[2] * mat2[4] + mat1[6] * mat2[5] + 
+               mat1[10] * mat2[6] + mat1[14] * mat2[7];
+    _data[10] = mat1[2] * mat2[8] + mat1[6] * mat2[9] + 
+                mat1[10] * mat2[10] + mat1[14] * mat2[11];
+    _data[14] = mat1[2] * mat2[12] + mat1[6] * mat2[13] + 
+                mat1[10] * mat2[14] + mat1[14] * mat2[15];
+
+    // 4 row
+    _data[3] = mat1[3] * mat2[0] + mat1[7] * mat2[1] + 
+               mat1[11] * mat2[2] + mat1[15] * mat2[3];
+    _data[7] = mat1[3] * mat2[4] + mat1[7] * mat2[5] + 
+               mat1[11] * mat2[6] + mat1[15] * mat2[7];
+    _data[11] = mat1[3] * mat2[8] + mat1[7] * mat2[9] + 
+                mat1[11] * mat2[10] + mat1[15] * mat2[11];
+    _data[15] = mat1[3] * mat2[12] + mat1[7] * mat2[13] + 
+                mat1[11] * mat2[14] + mat1[15] * mat2[15];
+}
+
+void Matrix4x4d::getRotation(Rotation& rotation) 
+{
+    double c = (_data[0] + _data[5] + _data[10] - 1.0) * 0.5;
+
+    rotation.setAxis(_data[6] - _data[9], _data[8] - _data[2], _data[1] - _data[4]);
+
+    double len = sqrt(rotation.getX() * rotation.getX() + 
+                      rotation.getY() * rotation.getY() +
+                      rotation.getZ() * rotation.getZ());
+
+    double s = 0.5 * len;
+
+    rotation.setAngle(atan2(s, c));
+
+    if (rotation.getX() == 0.0 &&
+        rotation.getY() == 0.0 &&
+        rotation.getZ() == 0.0) {
+        rotation.set(0, 1, 0, 0);
+    } else {
+        len = 1.0 / len;
+        rotation.setAxis(rotation.getX() * len,
+                         rotation.getY() * len,
+                         rotation.getZ() * len);
+    }
+}
+
+void Matrix4x4d::invert()
+{
+    double det =
+        _data[12] * _data[9] * _data[6] * _data[3]-
+        _data[8] * _data[13] * _data[6] * _data[3]-
+        _data[12] * _data[5] * _data[10] * _data[3]+
+        _data[4] * _data[13] * _data[10] * _data[3]+
+        _data[8] * _data[5] * _data[14] * _data[3]-
+        _data[4] * _data[9] * _data[14] * _data[3]-
+        _data[12] * _data[9] * _data[2] * _data[7]+
+        _data[8] * _data[13] * _data[2] * _data[7]+
+        _data[12] * _data[1] * _data[10] * _data[7]-
+        _data[0] * _data[13] * _data[10] * _data[7]-
+        _data[8] * _data[1] * _data[14] * _data[7]+
+        _data[0] * _data[9] * _data[14] * _data[7]+
+        _data[12] * _data[5] * _data[2] * _data[11]-
+        _data[4] * _data[13] * _data[2] * _data[11]-
+        _data[12] * _data[1] * _data[6] * _data[11]+
+        _data[0] * _data[13] * _data[6] * _data[11]+
+        _data[4] * _data[1] * _data[14] * _data[11]-
+        _data[0] * _data[5] * _data[14] * _data[11]-
+        _data[8] * _data[5] * _data[2] * _data[15]+
+        _data[4] * _data[9] * _data[2] * _data[15]+
+        _data[8] * _data[1] * _data[6] * _data[15]-
+        _data[0] * _data[9] * _data[6] * _data[15]-
+        _data[4] * _data[1] * _data[10] * _data[15]+
+        _data[0] * _data[5] * _data[10] * _data[15];
+
+    if ( det == 0.0 ) return;
+    det = 1.0 / det;
+
+    double mat[16];
+
+    mat[0] = (_data[9]*_data[14]*_data[7] -
+              _data[13]*_data[10]*_data[7] +
+              _data[13]*_data[6]*_data[11] -
+              _data[5]*_data[14]*_data[11] -
+              _data[9]*_data[6]*_data[15] +
+              _data[5]*_data[10]*_data[15]) * det;
+
+    mat[4] = (_data[12]*_data[10]*_data[7] -
+              _data[8]*_data[14]*_data[7] -
+              _data[12]*_data[6]*_data[11] +
+              _data[4]*_data[14]*_data[11] +
+              _data[8]*_data[6]*_data[15] -
+              _data[4]*_data[10]*_data[15]) * det;
+
+    mat[8] = (_data[8]*_data[13]*_data[7] -
+              _data[12]*_data[9]*_data[7] +
+              _data[12]*_data[5]*_data[11] -
+              _data[4]*_data[13]*_data[11] -
+              _data[8]*_data[5]*_data[15] +
+              _data[4]*_data[9]*_data[15]) * det;
+
+    mat[12] = (_data[12]*_data[9]*_data[6] -
+               _data[8]*_data[13]*_data[6] -
+               _data[12]*_data[5]*_data[10] +
+               _data[4]*_data[13]*_data[10] +
+               _data[8]*_data[5]*_data[14] -
+               _data[4]*_data[9]*_data[14]) * det;
+
+    mat[1] = (_data[13]*_data[10]*_data[3] -
+              _data[9]*_data[14]*_data[3] -
+              _data[13]*_data[2]*_data[11] +
+              _data[1]*_data[14]*_data[11] +
+              _data[9]*_data[2]*_data[15] -
+              _data[1]*_data[10]*_data[15]) * det;
+
+    mat[5] = (_data[8]*_data[14]*_data[3] -
+              _data[12]*_data[10]*_data[3] +
+              _data[12]*_data[2]*_data[11] -
+              _data[0]*_data[14]*_data[11] -
+              _data[8]*_data[2]*_data[15] +
+              _data[0]*_data[10]*_data[15]) * det;
+
+    mat[9] = (_data[12]*_data[9]*_data[3] -
+              _data[8]*_data[13]*_data[3] -
+              _data[12]*_data[1]*_data[11] +
+              _data[0]*_data[13]*_data[11] +
+              _data[8]*_data[1]*_data[15] -
+              _data[0]*_data[9]*_data[15]) * det;
+
+    mat[13] = (_data[8]*_data[13]*_data[2] -
+               _data[12]*_data[9]*_data[2] +
+               _data[12]*_data[1]*_data[10] -
+               _data[0]*_data[13]*_data[10] -
+               _data[8]*_data[1]*_data[14] +
+               _data[0]*_data[9]*_data[14]) * det;
+
+    mat[2] = (_data[5]*_data[14]*_data[3] -
+              _data[13]*_data[6]*_data[3] +
+              _data[13]*_data[2]*_data[7] -
+              _data[1]*_data[14]*_data[7] -
+              _data[5]*_data[2]*_data[15] +
+              _data[1]*_data[6]*_data[15]) * det;
+
+    mat[6] = (_data[12]*_data[6]*_data[3] -
+              _data[4]*_data[14]*_data[3] -
+              _data[12]*_data[2]*_data[7] +
+              _data[0]*_data[14]*_data[7] +
+              _data[4]*_data[2]*_data[15] -
+              _data[0]*_data[6]*_data[15]) * det;
+
+    mat[10] = (_data[4]*_data[13]*_data[3] -
+               _data[12]*_data[5]*_data[3] +
+               _data[12]*_data[1]*_data[7] -
+               _data[0]*_data[13]*_data[7] -
+               _data[4]*_data[1]*_data[15] +
+               _data[0]*_data[5]*_data[15]) * det;
+
+    mat[14] = (_data[12]*_data[5]*_data[2] -
+               _data[4]*_data[13]*_data[2] -
+               _data[12]*_data[1]*_data[6] +
+               _data[0]*_data[13]*_data[6] +
+               _data[4]*_data[1]*_data[14] -
+               _data[0]*_data[5]*_data[14]) * det;
+
+    mat[3] = (_data[9]*_data[6]*_data[3] -
+              _data[5]*_data[10]*_data[3] -
+              _data[9]*_data[2]*_data[7] +
+              _data[1]*_data[10]*_data[7] +
+              _data[5]*_data[2]*_data[11] -
+              _data[1]*_data[6]*_data[11]) * det;
+
+    mat[7] = (_data[4]*_data[10]*_data[3] -
+              _data[8]*_data[6]*_data[3] +
+              _data[8]*_data[2]*_data[7] -
+              _data[0]*_data[10]*_data[7] -
+              _data[4]*_data[2]*_data[11] +
+              _data[0]*_data[6]*_data[11]) * det;
+
+    mat[11] = (_data[8]*_data[5]*_data[3] -
+               _data[4]*_data[9]*_data[3] -
+               _data[8]*_data[1]*_data[7] +
+               _data[0]*_data[9]*_data[7] +
+               _data[4]*_data[1]*_data[11] -
+               _data[0]*_data[5]*_data[11]) * det;
+
+    mat[15] = (_data[4]*_data[9]*_data[2] -
+               _data[8]*_data[5]*_data[2] +
+               _data[8]*_data[1]*_data[6] -
+               _data[0]*_data[9]*_data[6] -
+               _data[4]*_data[1]*_data[10] +
+               _data[0]*_data[5]*_data[10]) * det;
+
+    set(mat);
+}
+
+void Matrix4x4d::invert(const Matrix4x4d& mat)
+{
+    if (&mat == this) {
+        invert();
+    } else {
+        invertFast(mat);
+    }
+}
+
+void Matrix4x4d::invertFast(const Matrix4x4d& mat)
+{
+    const double *srcData = mat._data;
+
+    double det =
+        srcData[12] * srcData[9] * srcData[6] * srcData[3]-
+        srcData[8] * srcData[13] * srcData[6] * srcData[3]-
+        srcData[12] * srcData[5] * srcData[10] * srcData[3]+
+        srcData[4] * srcData[13] * srcData[10] * srcData[3]+
+        srcData[8] * srcData[5] * srcData[14] * srcData[3]-
+        srcData[4] * srcData[9] * srcData[14] * srcData[3]-
+        srcData[12] * srcData[9] * srcData[2] * srcData[7]+
+        srcData[8] * srcData[13] * srcData[2] * srcData[7]+
+        srcData[12] * srcData[1] * srcData[10] * srcData[7]-
+        srcData[0] * srcData[13] * srcData[10] * srcData[7]-
+        srcData[8] * srcData[1] * srcData[14] * srcData[7]+
+        srcData[0] * srcData[9] * srcData[14] * srcData[7]+
+        srcData[12] * srcData[5] * srcData[2] * srcData[11]-
+        srcData[4] * srcData[13] * srcData[2] * srcData[11]-
+        srcData[12] * srcData[1] * srcData[6] * srcData[11]+
+        srcData[0] * srcData[13] * srcData[6] * srcData[11]+
+        srcData[4] * srcData[1] * srcData[14] * srcData[11]-
+        srcData[0] * srcData[5] * srcData[14] * srcData[11]-
+        srcData[8] * srcData[5] * srcData[2] * srcData[15]+
+        srcData[4] * srcData[9] * srcData[2] * srcData[15]+
+        srcData[8] * srcData[1] * srcData[6] * srcData[15]-
+        srcData[0] * srcData[9] * srcData[6] * srcData[15]-
+        srcData[4] * srcData[1] * srcData[10] * srcData[15]+
+        srcData[0] * srcData[5] * srcData[10] * srcData[15];
+
+    if ( det == 0.0 ) return;
+    det = 1.0 / det;
+
+    _data[0] = (srcData[9]*srcData[14]*srcData[7] -
+                srcData[13]*srcData[10]*srcData[7] +
+                srcData[13]*srcData[6]*srcData[11] -
+                srcData[5]*srcData[14]*srcData[11] -
+                srcData[9]*srcData[6]*srcData[15] +
+                srcData[5]*srcData[10]*srcData[15]) * det;
+
+    _data[4] = (srcData[12]*srcData[10]*srcData[7] -
+                srcData[8]*srcData[14]*srcData[7] -
+                srcData[12]*srcData[6]*srcData[11] +
+                srcData[4]*srcData[14]*srcData[11] +
+                srcData[8]*srcData[6]*srcData[15] -
+                srcData[4]*srcData[10]*srcData[15]) * det;
+
+    _data[8] = (srcData[8]*srcData[13]*srcData[7] -
+                srcData[12]*srcData[9]*srcData[7] +
+                srcData[12]*srcData[5]*srcData[11] -
+                srcData[4]*srcData[13]*srcData[11] -
+                srcData[8]*srcData[5]*srcData[15] +
+                srcData[4]*srcData[9]*srcData[15]) * det;
+
+    _data[12] = (srcData[12]*srcData[9]*srcData[6] -
+                 srcData[8]*srcData[13]*srcData[6] -
+                 srcData[12]*srcData[5]*srcData[10] +
+                 srcData[4]*srcData[13]*srcData[10] +
+                 srcData[8]*srcData[5]*srcData[14] -
+                 srcData[4]*srcData[9]*srcData[14]) * det;
+
+    _data[1] = (srcData[13]*srcData[10]*srcData[3] -
+                srcData[9]*srcData[14]*srcData[3] -
+                srcData[13]*srcData[2]*srcData[11] +
+                srcData[1]*srcData[14]*srcData[11] +
+                srcData[9]*srcData[2]*srcData[15] -
+                srcData[1]*srcData[10]*srcData[15]) * det;
+
+    _data[5] = (srcData[8]*srcData[14]*srcData[3] -
+                srcData[12]*srcData[10]*srcData[3] +
+                srcData[12]*srcData[2]*srcData[11] -
+                srcData[0]*srcData[14]*srcData[11] -
+                srcData[8]*srcData[2]*srcData[15] +
+                srcData[0]*srcData[10]*srcData[15]) * det;
+
+    _data[9] = (srcData[12]*srcData[9]*srcData[3] -
+                srcData[8]*srcData[13]*srcData[3] -
+                srcData[12]*srcData[1]*srcData[11] +
+                srcData[0]*srcData[13]*srcData[11] +
+                srcData[8]*srcData[1]*srcData[15] -
+                srcData[0]*srcData[9]*srcData[15]) * det;
+
+    _data[13] = (srcData[8]*srcData[13]*srcData[2] -
+                 srcData[12]*srcData[9]*srcData[2] +
+                 srcData[12]*srcData[1]*srcData[10] -
+                 srcData[0]*srcData[13]*srcData[10] -
+                 srcData[8]*srcData[1]*srcData[14] +
+                 srcData[0]*srcData[9]*srcData[14]) * det;
+
+    _data[2] = (srcData[5]*srcData[14]*srcData[3] -
+                srcData[13]*srcData[6]*srcData[3] +
+                srcData[13]*srcData[2]*srcData[7] -
+                srcData[1]*srcData[14]*srcData[7] -
+                srcData[5]*srcData[2]*srcData[15] +
+                srcData[1]*srcData[6]*srcData[15]) * det;
+
+    _data[6] = (srcData[12]*srcData[6]*srcData[3] -
+                srcData[4]*srcData[14]*srcData[3] -
+                srcData[12]*srcData[2]*srcData[7] +
+                srcData[0]*srcData[14]*srcData[7] +
+                srcData[4]*srcData[2]*srcData[15] -
+                srcData[0]*srcData[6]*srcData[15]) * det;
+
+    _data[10] = (srcData[4]*srcData[13]*srcData[3] -
+                 srcData[12]*srcData[5]*srcData[3] +
+                 srcData[12]*srcData[1]*srcData[7] -
+                 srcData[0]*srcData[13]*srcData[7] -
+                 srcData[4]*srcData[1]*srcData[15] +
+                 srcData[0]*srcData[5]*srcData[15]) * det;
+
+    _data[14] = (srcData[12]*srcData[5]*srcData[2] -
+                 srcData[4]*srcData[13]*srcData[2] -
+                 srcData[12]*srcData[1]*srcData[6] +
+                 srcData[0]*srcData[13]*srcData[6] +
+                 srcData[4]*srcData[1]*srcData[14] -
+                 srcData[0]*srcData[5]*srcData[14]) * det;
+
+    _data[3] = (srcData[9]*srcData[6]*srcData[3] -
+                srcData[5]*srcData[10]*srcData[3] -
+                srcData[9]*srcData[2]*srcData[7] +
+                srcData[1]*srcData[10]*srcData[7] +
+                srcData[5]*srcData[2]*srcData[11] -
+                srcData[1]*srcData[6]*srcData[11]) * det;
+
+    _data[7] = (srcData[4]*srcData[10]*srcData[3] -
+                srcData[8]*srcData[6]*srcData[3] +
+                srcData[8]*srcData[2]*srcData[7] -
+                srcData[0]*srcData[10]*srcData[7] -
+                srcData[4]*srcData[2]*srcData[11] +
+                srcData[0]*srcData[6]*srcData[11]) * det;
+
+    _data[11] = (srcData[8]*srcData[5]*srcData[3] -
+                 srcData[4]*srcData[9]*srcData[3] -
+                 srcData[8]*srcData[1]*srcData[7] +
+                 srcData[0]*srcData[9]*srcData[7] +
+                 srcData[4]*srcData[1]*srcData[11] -
+                 srcData[0]*srcData[5]*srcData[11]) * det;
+
+    _data[15] = (srcData[4]*srcData[9]*srcData[2] -
+                 srcData[8]*srcData[5]*srcData[2] +
+                 srcData[8]*srcData[1]*srcData[6] -
+                 srcData[0]*srcData[9]*srcData[6] -
+                 srcData[4]*srcData[1]*srcData[10] +
+                 srcData[0]*srcData[5]*srcData[10]) * det;
+}
+
+Matrix4x4d
+Matrix4x4d::inverse() const
+{
+    const double *m = _data;
+    Matrix4x4d p;
+
+    double m00 = m[0], m01 = m[4], m02 = m[8], m03 = m[12];
+    double m10 = m[1], m11 = m[5], m12 = m[9], m13 = m[13];
+    double m20 = m[2], m21 = m[6], m22 = m[10], m23 = m[14];
+    double m30 = m[3], m31 = m[7], m32 = m[11], m33 = m[15];
+
+    double det0, inv0;
+
+#define det33(a1,a2,a3,b1,b2,b3,c1,c2,c3) \
+    (a1*(b2*c3-b3*c2) + b1*(c2*a3-a2*c3) + c1*(a2*b3-a3*b2))
+
+    double cof00 =  det33(m11, m12, m13, m21, m22, m23, m31, m32, m33);
+    double cof01 = -det33(m12, m13, m10, m22, m23, m20, m32, m33, m30);
+    double cof02 =  det33(m13, m10, m11, m23, m20, m21, m33, m30, m31);
+    double cof03 = -det33(m10, m11, m12, m20, m21, m22, m30, m31, m32);
+
+    double cof10 = -det33(m21, m22, m23, m31, m32, m33, m01, m02, m03);
+    double cof11 =  det33(m22, m23, m20, m32, m33, m30, m02, m03, m00);
+    double cof12 = -det33(m23, m20, m21, m33, m30, m31, m03, m00, m01);
+    double cof13 =  det33(m20, m21, m22, m30, m31, m32, m00, m01, m02);
+
+    double cof20 =  det33(m31, m32, m33, m01, m02, m03, m11, m12, m13);
+    double cof21 = -det33(m32, m33, m30, m02, m03, m00, m12, m13, m10);
+    double cof22 =  det33(m33, m30, m31, m03, m00, m01, m13, m10, m11);
+    double cof23 = -det33(m30, m31, m32, m00, m01, m02, m10, m11, m12);
+
+    double cof30 = -det33(m01, m02, m03, m11, m12, m13, m21, m22, m23);
+    double cof31 =  det33(m02, m03, m00, m12, m13, m10, m22, m23, m20);
+    double cof32 = -det33(m03, m00, m01, m13, m10, m11, m23, m20, m21);
+    double cof33 =  det33(m00, m01, m02, m10, m11, m12, m20, m21, m22);
+
+#undef det33
+
+#if 0
+    TRACE("Invert:");
+    TRACE("   %12.9f %12.9f %12.9f %12.9f", m00, m01, m02, m03);
+    TRACE("   %12.9f %12.9f %12.9f %12.9f", m10, m11, m12, m13);
+    TRACE("   %12.9f %12.9f %12.9f %12.9f", m20, m21, m22, m23);
+    TRACE("   %12.9f %12.9f %12.9f %12.9f", m30, m31, m32, m33);
+#endif
+
+#if 0
+    det0  = m00 * cof00 + m01 * cof01 + m02 * cof02 + m03 * cof03;
+#else
+    det0  = m30 * cof30 + m31 * cof31 + m32 * cof32 + m33 * cof33;
+#endif
+    inv0  = (det0 == 0.0f) ? 0.0f : 1.0f / det0;
+
+    p.get()[0] = cof00 * inv0;
+    p.get()[1] = cof01 * inv0;
+    p.get()[2] = cof02 * inv0;
+    p.get()[3] = cof03 * inv0;
+
+    p.get()[4] = cof10 * inv0;
+    p.get()[5] = cof11 * inv0;
+    p.get()[6] = cof12 * inv0;
+    p.get()[7] = cof13 * inv0;
+
+    p.get()[8] = cof20 * inv0;
+    p.get()[9] = cof21 * inv0;
+    p.get()[10] = cof22 * inv0;
+    p.get()[11] = cof23 * inv0;
+
+    p.get()[12] = cof30 * inv0;
+    p.get()[13] = cof31 * inv0;
+    p.get()[14] = cof32 * inv0;
+    p.get()[15] = cof33 * inv0;	
+
+    return p;
+}
+
+void Matrix4x4d::transpose()
+{
+    double m[16];
+
+    m[0] = _data[0];
+    m[1] = _data[4];
+    m[2] = _data[8];
+    m[3] = _data[12];
+
+    m[4] = _data[1];
+    m[5] = _data[5];
+    m[6] = _data[9];
+    m[7] = _data[13];
+
+    m[8] = _data[2];
+    m[9] = _data[6];
+    m[10] = _data[10];
+    m[11] = _data[14];
+
+    m[12] = _data[3];
+    m[13] = _data[7];
+    m[14] = _data[11];
+    m[15] = _data[15];
+
+    set(m);
+}
+
+void Matrix4x4d::transposeFast(const Matrix4x4d& mat)
+{
+    _data[0] = mat._data[0];
+    _data[1] = mat._data[4];
+    _data[2] = mat._data[8];
+    _data[3] = mat._data[12];
+
+    _data[4] = mat._data[1];
+    _data[5] = mat._data[5];
+    _data[6] = mat._data[9];
+    _data[7] = mat._data[13];
+
+    _data[8] = mat._data[2];
+    _data[9] = mat._data[6];
+    _data[10] = mat._data[10];
+    _data[11] = mat._data[14];
+
+    _data[12] = mat._data[3];
+    _data[13] = mat._data[7];
+    _data[14] = mat._data[11];
+    _data[15] = mat._data[15];
+}
+
+void Matrix4x4d::transpose(const Matrix4x4d& mat)
+{
+    if (&mat == this) {
+        transpose();
+    } else {
+        transposeFast(mat);
+    }
+}
+
+void Matrix4x4d::setFloat(const float *m)
+{
+    for (int i = 0; i < 16; ++i) {
+        _data[i] = m[i];
+    }
+}
+
+void Matrix4x4d::multiply(const Matrix4x4d& mat1, const Vector3f& position)
+{
+    Matrix4x4d mat;
+    mat.makeTranslation(position);
+    multiply(mat1, mat);
+}
+
+void Matrix4x4d::multiply(const Matrix4x4d& mat1, const Rotation& rotation)
+{
+    Matrix4x4d mat;
+    mat.makeRotation(rotation);
+    multiply(mat1, mat);
+}
+
+void Matrix4x4d::multiply(const Vector3f& position, const Matrix4x4d& mat1)
+{
+    Matrix4x4d mat;
+    mat.makeTranslation(position);
+    multiply(mat, mat1);
+}
+
+void Matrix4x4d::multiply(const Rotation& rotation, const Matrix4x4d& mat1)
+{
+    Matrix4x4d mat;
+    mat.makeRotation(rotation);
+    multiply(mat, mat1);
+}
+
+void Matrix4x4d::makeVecRotVec(const Vector3f& vec1, const Vector3f& vec2)
+{
+    Vector3f axis = cross(vec1, vec2);
+
+    float angle = atan2(axis.length(), vec1.dot(vec2));
+    axis = axis.normalize();
+    makeRotation(axis.x, axis.y, axis.z, angle);
+}
+
+void Matrix4x4d::multiplyScale(const Matrix4x4d& mat1, const Vector3f& scale)
+{
+    Matrix4x4d mat;
+    mat.makeScale(scale);
+    multiply(mat1, mat);
+}
+
+void Matrix4x4d::multiplyScale(const Vector3f& scale, const Matrix4x4d& mat1)
+{
+    Matrix4x4d mat;
+    mat.makeScale(scale);
+    multiply(mat, mat1);
+}
Index: /nanovis/tags/1.1.4/vrmath/Matrix4x4f.cpp
===================================================================
--- /nanovis/tags/1.1.4/vrmath/Matrix4x4f.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/vrmath/Matrix4x4f.cpp	(revision 4930)
@@ -0,0 +1,776 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Author: Insoo Woo <iwoo@purdue.edu>
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#include <vrmath/Vector3f.h>
+#include <vrmath/Rotation.h>
+#include <vrmath/Matrix4x4f.h>
+
+using namespace vrmath;
+
+void Matrix4x4f::makeIdentity()
+{
+    _data[1] = _data[2] = _data[3] = _data[4] =
+        _data[6] = _data[7] = _data[8] = _data[9] =
+        _data[11] = _data[12] = _data[13] = _data[14] = 0.0f;
+    _data[0] = _data[5] = _data[10] = _data[15] = 1.0f;
+}
+
+void Matrix4x4f::makeTranslation(const Vector3f& translation)
+{
+    _data[1] = _data[2] = _data[3] = _data[4] =
+        _data[6] = _data[7] = _data[8] = _data[9] =
+        _data[11] = 0.0f;
+    _data[0] = _data[5] = _data[10] = _data[15] = 1.0f;
+    _data[12] = translation.x;
+    _data[13] = translation.y;
+    _data[14] = translation.z;
+}
+
+void Matrix4x4f::makeTranslation(float x, float y, float z)
+{
+    _data[1] = _data[2] = _data[3] = _data[4] =
+        _data[6] = _data[7] = _data[8] = _data[9] =
+        _data[11] = 0.0f;
+    _data[0] = _data[5] = _data[10] = _data[15] = 1.0f;
+    _data[12] = x;
+    _data[13] = y;
+    _data[14] = z;
+}
+
+void Matrix4x4f::makeRotation(const Rotation& rotation)
+{
+    if (rotation.getAngle() == 0.0 || 
+        (rotation.getX() == 0.0 &&
+         rotation.getY() == 0.0 &&
+         rotation.getZ() == 0.0)) {
+        makeIdentity();
+        return;
+    }
+
+    double xAxis = rotation.getX();
+    double yAxis = rotation.getY();
+    double zAxis = rotation.getZ();
+    double invLen = 1.0 / sqrt(xAxis * xAxis + yAxis * yAxis + zAxis * zAxis);
+    double cosine = cos(rotation.getAngle());
+    double sine = sin(rotation.getAngle());
+
+    xAxis *= invLen;
+    yAxis *= invLen;
+    zAxis *= invLen;
+
+    double oneMinusCosine = 1.0 - cosine;
+
+    _data[3] = _data[7] = _data[11] = _data[12] = _data[13] = _data[14] = 0.0f;
+    _data[15] = 1.0f;
+
+    _data[0] = float(xAxis * xAxis * oneMinusCosine + cosine);
+    _data[1] = float(yAxis * xAxis * oneMinusCosine + zAxis * sine);
+    _data[2] = float(xAxis * zAxis * oneMinusCosine - yAxis * sine);
+
+    _data[4] = float(xAxis * yAxis * oneMinusCosine - zAxis * sine);
+    _data[5] = float(yAxis * yAxis * oneMinusCosine + cosine);
+    _data[6] = float(yAxis * zAxis * oneMinusCosine + xAxis * sine);
+
+    _data[8] = float(xAxis * zAxis * oneMinusCosine + yAxis * sine);
+    _data[9] = float(yAxis * zAxis * oneMinusCosine - xAxis * sine);
+    _data[10] = float(zAxis * zAxis * oneMinusCosine + cosine);
+}
+
+void Matrix4x4f::makeRotation(double xAxis, double yAxis, double zAxis, double angle)
+{
+    if (angle == 0.0 ||
+        (xAxis == 0.0 &&
+         yAxis == 0.0 &&
+         zAxis == 0.0)) {
+        makeIdentity();
+        return;
+    }
+
+    double invLen = 1.0 / sqrt((double)xAxis * xAxis + (double)yAxis * yAxis + (double)zAxis * zAxis);
+    double cosine = cos(angle);
+    double sine = sin(angle);
+
+    xAxis *= invLen;
+    yAxis *= invLen;
+    zAxis *= invLen;
+
+    double oneMinusCosine = 1.0 - cosine;
+
+    _data[3] = _data[7] = _data[11] = _data[12] = _data[13] = _data[14] = 0.0f;
+    _data[15] = 1.0f;
+
+    _data[0] = float(xAxis * xAxis * oneMinusCosine + cosine);
+    _data[1] = float(yAxis * xAxis * oneMinusCosine + zAxis * sine);
+    _data[2] = float(xAxis * zAxis * oneMinusCosine - yAxis * sine);
+
+    _data[4] = float(xAxis * yAxis * oneMinusCosine - zAxis * sine);
+    _data[5] = float(yAxis * yAxis * oneMinusCosine + cosine);
+    _data[6] = float(yAxis * zAxis * oneMinusCosine + xAxis * sine);
+
+    _data[8] = float(xAxis * zAxis * oneMinusCosine + yAxis * sine);
+    _data[9] = float(yAxis * zAxis * oneMinusCosine - xAxis * sine);
+    _data[10] = float(zAxis * zAxis * oneMinusCosine + cosine);
+}
+
+void Matrix4x4f::makeScale(const Vector3f& scale)
+{
+    _data[1] = _data[2] = _data[3] = _data[4] =
+        _data[6] = _data[7] = _data[8] = _data[9] =
+        _data[11] = 0.0f;
+
+    _data[0] = scale.x;
+    _data[5] = scale.y;
+    _data[10] = scale.z;
+
+    _data[15] = 1.0f;
+    _data[12] = _data[13] = _data[14] = 0.0f;
+}
+
+void Matrix4x4f::makeScale(float x, float y, float z)
+{
+    _data[1] = _data[2] = _data[3] = _data[4] =
+        _data[6] = _data[7] = _data[8] = _data[9] =
+        _data[11] = 0.0f;
+
+    _data[0] = x;
+    _data[5] = y;
+    _data[10] = z;
+
+    _data[15] = 1.0f;
+    _data[12] = _data[13] = _data[14] = 0.0f;
+}
+
+Vector4f
+Matrix4x4f::transform(const Vector4f& v) const
+{
+    Vector4f ret;
+    ret.x = _data[0] * v.x + _data[4] * v.y + _data[8] * v.z  + _data[12] * v.w;
+    ret.y = _data[1] * v.x + _data[5] * v.y + _data[9] * v.z  + _data[13] * v.w;
+    ret.z = _data[2] * v.x + _data[6] * v.y + _data[10] * v.z + _data[14] * v.w;
+    ret.w = _data[3] * v.x + _data[7] * v.y + _data[11] * v.z + _data[15] * v.w;
+    return ret;
+}
+
+Vector3f
+Matrix4x4f::transformVec(const Vector3f& v) const
+{
+    Vector3f ret;
+    ret.x = _data[0] * v.x + _data[4] * v.y + _data[8] * v.z;
+    ret.y = _data[1] * v.x + _data[5] * v.y + _data[9] * v.z;
+    ret.z = _data[2] * v.x + _data[6] * v.y + _data[10] * v.z;
+    return ret;
+}
+
+Vector4f
+Matrix4x4f::preMultiplyRowVector(const Vector4f& v) const
+{
+    Vector4f ret;
+    ret.x = (_data[0]  * v.x) + (_data[1]  * v.y) + (_data[2]  * v.z) + (_data[3]  * v.w);
+    ret.y = (_data[4]  * v.x) + (_data[5]  * v.y) + (_data[6]  * v.z) + (_data[7]  * v.w);
+    ret.z = (_data[8]  * v.x) + (_data[9]  * v.y) + (_data[10] * v.z) + (_data[11] * v.w);
+    ret.w = (_data[12] * v.x) + (_data[13] * v.y) + (_data[14] * v.z) + (_data[15] * v.w);
+    return ret;
+}
+
+void Matrix4x4f::multiply(const Matrix4x4f& m1)
+{
+    float mat[16];
+    const float *mat1 = m1._data;
+
+    // 1 row
+    mat[0] = float(_data[0] * mat1[0] + _data[4] * mat1[1] + 
+                   _data[8] * mat1[2] + _data[12] * mat1[3]);
+    mat[4] = float(_data[0] * mat1[4] + _data[4] * mat1[5] + 
+                   _data[8] * mat1[6] + _data[12] * mat1[7]);
+    mat[8] = float(_data[0] * mat1[8] + _data[4] * mat1[9] + 
+                   _data[8] * mat1[10] + _data[12] * mat1[11]);
+    mat[12] = float(_data[0] * mat1[12] + _data[4] * mat1[13] + 
+                    _data[8] * mat1[14] + _data[12] * mat1[15]);
+
+    // 2 row
+    mat[1] = float(_data[1] * mat1[0] + _data[5] * mat1[1] + 
+                   _data[9] * mat1[2] + _data[13] * mat1[3]);
+    mat[5] = float(_data[1] * mat1[4] + _data[5] * mat1[5] + 
+                   _data[9] * mat1[6] + _data[13] * mat1[7]);
+    mat[9] = float(_data[1] * mat1[8] + _data[5] * mat1[9] + 
+                   _data[9] * mat1[10] + _data[13] * mat1[11]);
+    mat[13] = float(_data[1] * mat1[12] + _data[5] * mat1[13] + 
+                    _data[9] * mat1[14] + _data[13] * mat1[15]);
+
+    // 3 row
+    mat[2] = float(_data[2] * mat1[0] + _data[6] * mat1[1] + 
+                   _data[10] * mat1[2] + _data[14] * mat1[3]);
+
+    mat[6] = float(_data[2] * mat1[4] + _data[6] * mat1[5] + 
+                   _data[10] * mat1[6] + _data[14] * mat1[7]);
+    mat[10] = float(_data[2] * mat1[8] + _data[6] * mat1[9] + 
+                    _data[10] * mat1[10] + _data[14] * mat1[11]);
+    mat[14] = float(_data[2] * mat1[12] + _data[6] * mat1[13] + 
+                    _data[10] * mat1[14] + _data[14] * mat1[15]);
+
+    // 4 row
+    mat[3] = float(_data[3] * mat1[0] + _data[7] * mat1[1] + 
+                   _data[11] * mat1[2] + _data[15] * mat1[3]);
+    mat[7] = float(_data[3] * mat1[4] + _data[7] * mat1[5] + 
+                   _data[11] * mat1[6] + _data[15] * mat1[7]);
+    mat[11] = float(_data[3] * mat1[8] + _data[7] * mat1[9] + 
+                    _data[11] * mat1[10] + _data[15] * mat1[11]);
+    mat[15] = float(_data[3] * mat1[12] + _data[7] * mat1[13] + 
+                    _data[11] * mat1[14] + _data[15] * mat1[15]);
+
+    // set matrix
+    set(mat);
+}
+
+void Matrix4x4f::multiply(const Matrix4x4f& m1, const Matrix4x4f& m2)
+{
+    if (&m1 == this && &m2 != this) {
+        multiply(m2);
+    } else if (&m1 != this && &m2 != this) {
+        multiplyFast(m1, m2);
+    } else {
+        float mat[16];
+        const float *mat1 = m1._data;
+        const float *mat2 = m2._data;
+
+        // 1 row
+        mat[0] = float(mat1[0] * mat2[0] + mat1[4] * mat2[1] + 
+                       mat1[8] * mat2[2] + mat1[12] * mat2[3]);
+        mat[4] = float(mat1[0] * mat2[4] + mat1[4] * mat2[5] + 
+                       mat1[8] * mat2[6] + mat1[12] * mat2[7]);
+        mat[8] = float(mat1[0] * mat2[8] + mat1[4] * mat2[9] + 
+                       mat1[8] * mat2[10] + mat1[12] * mat2[11]);
+        mat[12] = float(mat1[0] * mat2[12] + mat1[4] * mat2[13] + 
+                        mat1[8] * mat2[14] + mat1[12] * mat2[15]);
+
+        // 2 row
+        mat[1] = float(mat1[1] * mat2[0] + mat1[5] * mat2[1] + 
+                       mat1[9] * mat2[2] + mat1[13] * mat2[3]);
+        mat[5] = float(mat1[1] * mat2[4] + mat1[5] * mat2[5] + 
+                       mat1[9] * mat2[6] + mat1[13] * mat2[7]);
+        mat[9] = float(mat1[1] * mat2[8] + mat1[5] * mat2[9] + 
+                       mat1[9] * mat2[10] + mat1[13] * mat2[11]);
+        mat[13] = float(mat1[1] * mat2[12] + mat1[5] * mat2[13] + 
+                        mat1[9] * mat2[14] + mat1[13] * mat2[15]);
+
+        // 3 row
+        mat[2] = float(mat1[2] * mat2[0] + mat1[6] * mat2[1] + 
+                       mat1[10] * mat2[2] + mat1[14] * mat2[3]);
+        mat[6] = float(mat1[2] * mat2[4] + mat1[6] * mat2[5] + 
+                       mat1[10] * mat2[6] + mat1[14] * mat2[7]);
+        mat[10] = float(mat1[2] * mat2[8] + mat1[6] * mat2[9] + 
+                        mat1[10] * mat2[10] + mat1[14] * mat2[11]);
+        mat[14] = float(mat1[2] * mat2[12] + mat1[6] * mat2[13] + 
+                        mat1[10] * mat2[14] + mat1[14] * mat2[15]);
+
+        // 4 row
+        mat[3] = float(mat1[3] * mat2[0] + mat1[7] * mat2[1] + 
+                       mat1[11] * mat2[2] + mat1[15] * mat2[3]);
+        mat[7] = float(mat1[3] * mat2[4] + mat1[7] * mat2[5] + 
+                       mat1[11] * mat2[6] + mat1[15] * mat2[7]);
+        mat[11] = float(mat1[3] * mat2[8] + mat1[7] * mat2[9] + 
+                        mat1[11] * mat2[10] + mat1[15] * mat2[11]);
+        mat[15] = float(mat1[3] * mat2[12] + mat1[7] * mat2[13] + 
+                        mat1[11] * mat2[14] + mat1[15] * mat2[15]);
+
+        // set matrix
+        set(mat);
+    }
+}
+
+void Matrix4x4f::multiplyFast(const Matrix4x4f& m1, const Matrix4x4f& m2)
+{
+    const float *mat1 = m1._data;
+    const float *mat2 = m2._data;
+
+    // 1 row
+    _data[0] = float(mat1[0] * mat2[0] + mat1[4] * mat2[1] + 
+                     mat1[8] * mat2[2] + mat1[12] * mat2[3]);
+    _data[4] = float(mat1[0] * mat2[4] + mat1[4] * mat2[5] + 
+                     mat1[8] * mat2[6] + mat1[12] * mat2[7]);
+    _data[8] = float(mat1[0] * mat2[8] + mat1[4] * mat2[9] + 
+                     mat1[8] * mat2[10] + mat1[12] * mat2[11]);
+    _data[12] = float(mat1[0] * mat2[12] + mat1[4] * mat2[13] + 
+                      mat1[8] * mat2[14] + mat1[12] * mat2[15]);
+
+    // 2 row
+    _data[1] = float(mat1[1] * mat2[0] + mat1[5] * mat2[1] + 
+                     mat1[9] * mat2[2] + mat1[13] * mat2[3]);
+    _data[5] = float(mat1[1] * mat2[4] + mat1[5] * mat2[5] + 
+                     mat1[9] * mat2[6] + mat1[13] * mat2[7]);
+    _data[9] = float(mat1[1] * mat2[8] + mat1[5] * mat2[9] + 
+                     mat1[9] * mat2[10] + mat1[13] * mat2[11]);
+    _data[13] = float(mat1[1] * mat2[12] + mat1[5] * mat2[13] + 
+                      mat1[9] * mat2[14] + mat1[13] * mat2[15]);
+
+    // 3 row
+    _data[2] = float(mat1[2] * mat2[0] + mat1[6] * mat2[1] + 
+                     mat1[10] * mat2[2] + mat1[14] * mat2[3]);
+    _data[6] = float(mat1[2] * mat2[4] + mat1[6] * mat2[5] + 
+                     mat1[10] * mat2[6] + mat1[14] * mat2[7]);
+    _data[10] = float(mat1[2] * mat2[8] + mat1[6] * mat2[9] + 
+                      mat1[10] * mat2[10] + mat1[14] * mat2[11]);
+    _data[14] = float(mat1[2] * mat2[12] + mat1[6] * mat2[13] + 
+                      mat1[10] * mat2[14] + mat1[14] * mat2[15]);
+
+    // 4 row
+    _data[3] = float(mat1[3] * mat2[0] + mat1[7] * mat2[1] + 
+                     mat1[11] * mat2[2] + mat1[15] * mat2[3]);
+    _data[7] = float(mat1[3] * mat2[4] + mat1[7] * mat2[5] + 
+                     mat1[11] * mat2[6] + mat1[15] * mat2[7]);
+    _data[11] = float(mat1[3] * mat2[8] + mat1[7] * mat2[9] + 
+                      mat1[11] * mat2[10] + mat1[15] * mat2[11]);
+    _data[15] = float(mat1[3] * mat2[12] + mat1[7] * mat2[13] + 
+                      mat1[11] * mat2[14] + mat1[15] * mat2[15]);
+}
+
+void Matrix4x4f::getRotation(Rotation& rotation) 
+{
+    double c = (_data[0] + _data[5] + _data[10] - 1.0) * 0.5;
+
+    rotation.setAxis(_data[6] - _data[9], _data[8] - _data[2], _data[1] - _data[4]);
+
+    double len = sqrt(rotation.getX() * rotation.getX() + 
+                      rotation.getY() * rotation.getY() +
+                      rotation.getZ() * rotation.getZ());
+
+    double s = 0.5 * len;
+
+    rotation.setAngle(atan2(s, c));
+
+    if (rotation.getX() == 0.0 &&
+        rotation.getY() == 0.0 &&
+        rotation.getZ() == 0.0) {
+        rotation.set(0, 1, 0, 0);
+    } else {
+        len = 1.0 / len;
+        rotation.setAxis(rotation.getX() * len,
+                         rotation.getY() * len,
+                         rotation.getZ() * len);
+    }
+}
+
+void Matrix4x4f::invert()
+{
+    float det =
+        _data[12] * _data[9] * _data[6] * _data[3]-
+        _data[8] * _data[13] * _data[6] * _data[3]-
+        _data[12] * _data[5] * _data[10] * _data[3]+
+        _data[4] * _data[13] * _data[10] * _data[3]+
+        _data[8] * _data[5] * _data[14] * _data[3]-
+        _data[4] * _data[9] * _data[14] * _data[3]-
+        _data[12] * _data[9] * _data[2] * _data[7]+
+        _data[8] * _data[13] * _data[2] * _data[7]+
+        _data[12] * _data[1] * _data[10] * _data[7]-
+        _data[0] * _data[13] * _data[10] * _data[7]-
+        _data[8] * _data[1] * _data[14] * _data[7]+
+        _data[0] * _data[9] * _data[14] * _data[7]+
+        _data[12] * _data[5] * _data[2] * _data[11]-
+        _data[4] * _data[13] * _data[2] * _data[11]-
+        _data[12] * _data[1] * _data[6] * _data[11]+
+        _data[0] * _data[13] * _data[6] * _data[11]+
+        _data[4] * _data[1] * _data[14] * _data[11]-
+        _data[0] * _data[5] * _data[14] * _data[11]-
+        _data[8] * _data[5] * _data[2] * _data[15]+
+        _data[4] * _data[9] * _data[2] * _data[15]+
+        _data[8] * _data[1] * _data[6] * _data[15]-
+        _data[0] * _data[9] * _data[6] * _data[15]-
+        _data[4] * _data[1] * _data[10] * _data[15]+
+        _data[0] * _data[5] * _data[10] * _data[15];
+
+    if ( det == 0.0f ) return;
+    det = 1 / det;
+
+    float mat[16];
+
+    mat[0] = (_data[9]*_data[14]*_data[7] -
+              _data[13]*_data[10]*_data[7] +
+              _data[13]*_data[6]*_data[11] -
+              _data[5]*_data[14]*_data[11] -
+              _data[9]*_data[6]*_data[15] +
+              _data[5]*_data[10]*_data[15]) * det;
+
+    mat[4] = (_data[12]*_data[10]*_data[7] -
+              _data[8]*_data[14]*_data[7] -
+              _data[12]*_data[6]*_data[11] +
+              _data[4]*_data[14]*_data[11] +
+              _data[8]*_data[6]*_data[15] -
+              _data[4]*_data[10]*_data[15]) * det;
+
+    mat[8] = (_data[8]*_data[13]*_data[7] -
+              _data[12]*_data[9]*_data[7] +
+              _data[12]*_data[5]*_data[11] -
+              _data[4]*_data[13]*_data[11] -
+              _data[8]*_data[5]*_data[15] +
+              _data[4]*_data[9]*_data[15]) * det;
+
+    mat[12] = (_data[12]*_data[9]*_data[6] -
+               _data[8]*_data[13]*_data[6] -
+               _data[12]*_data[5]*_data[10] +
+               _data[4]*_data[13]*_data[10] +
+               _data[8]*_data[5]*_data[14] -
+               _data[4]*_data[9]*_data[14]) * det;
+
+    mat[1] = (_data[13]*_data[10]*_data[3] -
+              _data[9]*_data[14]*_data[3] -
+              _data[13]*_data[2]*_data[11] +
+              _data[1]*_data[14]*_data[11] +
+              _data[9]*_data[2]*_data[15] -
+              _data[1]*_data[10]*_data[15]) * det;
+
+    mat[5] = (_data[8]*_data[14]*_data[3] -
+              _data[12]*_data[10]*_data[3] +
+              _data[12]*_data[2]*_data[11] -
+              _data[0]*_data[14]*_data[11] -
+              _data[8]*_data[2]*_data[15] +
+              _data[0]*_data[10]*_data[15]) * det;
+
+    mat[9] = (_data[12]*_data[9]*_data[3] -
+              _data[8]*_data[13]*_data[3] -
+              _data[12]*_data[1]*_data[11] +
+              _data[0]*_data[13]*_data[11] +
+              _data[8]*_data[1]*_data[15] -
+              _data[0]*_data[9]*_data[15]) * det;
+
+    mat[13] = (_data[8]*_data[13]*_data[2] -
+               _data[12]*_data[9]*_data[2] +
+               _data[12]*_data[1]*_data[10] -
+               _data[0]*_data[13]*_data[10] -
+               _data[8]*_data[1]*_data[14] +
+               _data[0]*_data[9]*_data[14]) * det;
+
+    mat[2] = (_data[5]*_data[14]*_data[3] -
+              _data[13]*_data[6]*_data[3] +
+              _data[13]*_data[2]*_data[7] -
+              _data[1]*_data[14]*_data[7] -
+              _data[5]*_data[2]*_data[15] +
+              _data[1]*_data[6]*_data[15]) * det;
+
+    mat[6] = (_data[12]*_data[6]*_data[3] -
+              _data[4]*_data[14]*_data[3] -
+              _data[12]*_data[2]*_data[7] +
+              _data[0]*_data[14]*_data[7] +
+              _data[4]*_data[2]*_data[15] -
+              _data[0]*_data[6]*_data[15]) * det;
+
+    mat[10] = (_data[4]*_data[13]*_data[3] -
+               _data[12]*_data[5]*_data[3] +
+               _data[12]*_data[1]*_data[7] -
+               _data[0]*_data[13]*_data[7] -
+               _data[4]*_data[1]*_data[15] +
+               _data[0]*_data[5]*_data[15]) * det;
+
+    mat[14] = (_data[12]*_data[5]*_data[2] -
+               _data[4]*_data[13]*_data[2] -
+               _data[12]*_data[1]*_data[6] +
+               _data[0]*_data[13]*_data[6] +
+               _data[4]*_data[1]*_data[14] -
+               _data[0]*_data[5]*_data[14]) * det;
+
+    mat[3] = (_data[9]*_data[6]*_data[3] -
+              _data[5]*_data[10]*_data[3] -
+              _data[9]*_data[2]*_data[7] +
+              _data[1]*_data[10]*_data[7] +
+              _data[5]*_data[2]*_data[11] -
+              _data[1]*_data[6]*_data[11]) * det;
+
+    mat[7] = (_data[4]*_data[10]*_data[3] -
+              _data[8]*_data[6]*_data[3] +
+              _data[8]*_data[2]*_data[7] -
+              _data[0]*_data[10]*_data[7] -
+              _data[4]*_data[2]*_data[11] +
+              _data[0]*_data[6]*_data[11]) * det;
+
+    mat[11] = (_data[8]*_data[5]*_data[3] -
+               _data[4]*_data[9]*_data[3] -
+               _data[8]*_data[1]*_data[7] +
+               _data[0]*_data[9]*_data[7] +
+               _data[4]*_data[1]*_data[11] -
+               _data[0]*_data[5]*_data[11]) * det;
+
+    mat[15] = (_data[4]*_data[9]*_data[2] -
+               _data[8]*_data[5]*_data[2] +
+               _data[8]*_data[1]*_data[6] -
+               _data[0]*_data[9]*_data[6] -
+               _data[4]*_data[1]*_data[10] +
+               _data[0]*_data[5]*_data[10]) * det;
+
+    set(mat);
+}
+
+void Matrix4x4f::invert(const Matrix4x4f& mat)
+{
+    if (&mat == this) {
+        invert();
+    } else {
+        invertFast(mat);
+    }
+}
+
+void Matrix4x4f::invertFast(const Matrix4x4f& mat)
+{
+    float *srcData = (float *)mat._data;
+
+    float det =
+        srcData[12] * srcData[9] * srcData[6] * srcData[3]-
+        srcData[8] * srcData[13] * srcData[6] * srcData[3]-
+        srcData[12] * srcData[5] * srcData[10] * srcData[3]+
+        srcData[4] * srcData[13] * srcData[10] * srcData[3]+
+        srcData[8] * srcData[5] * srcData[14] * srcData[3]-
+        srcData[4] * srcData[9] * srcData[14] * srcData[3]-
+        srcData[12] * srcData[9] * srcData[2] * srcData[7]+
+        srcData[8] * srcData[13] * srcData[2] * srcData[7]+
+        srcData[12] * srcData[1] * srcData[10] * srcData[7]-
+        srcData[0] * srcData[13] * srcData[10] * srcData[7]-
+        srcData[8] * srcData[1] * srcData[14] * srcData[7]+
+        srcData[0] * srcData[9] * srcData[14] * srcData[7]+
+        srcData[12] * srcData[5] * srcData[2] * srcData[11]-
+        srcData[4] * srcData[13] * srcData[2] * srcData[11]-
+        srcData[12] * srcData[1] * srcData[6] * srcData[11]+
+        srcData[0] * srcData[13] * srcData[6] * srcData[11]+
+        srcData[4] * srcData[1] * srcData[14] * srcData[11]-
+        srcData[0] * srcData[5] * srcData[14] * srcData[11]-
+        srcData[8] * srcData[5] * srcData[2] * srcData[15]+
+        srcData[4] * srcData[9] * srcData[2] * srcData[15]+
+        srcData[8] * srcData[1] * srcData[6] * srcData[15]-
+        srcData[0] * srcData[9] * srcData[6] * srcData[15]-
+        srcData[4] * srcData[1] * srcData[10] * srcData[15]+
+        srcData[0] * srcData[5] * srcData[10] * srcData[15];
+
+    if ( det == 0.0f ) return;
+    det = 1 / det;
+
+    _data[0] = (srcData[9]*srcData[14]*srcData[7] -
+                srcData[13]*srcData[10]*srcData[7] +
+                srcData[13]*srcData[6]*srcData[11] -
+                srcData[5]*srcData[14]*srcData[11] -
+                srcData[9]*srcData[6]*srcData[15] +
+                srcData[5]*srcData[10]*srcData[15]) * det;
+
+    _data[4] = (srcData[12]*srcData[10]*srcData[7] -
+                srcData[8]*srcData[14]*srcData[7] -
+                srcData[12]*srcData[6]*srcData[11] +
+                srcData[4]*srcData[14]*srcData[11] +
+                srcData[8]*srcData[6]*srcData[15] -
+                srcData[4]*srcData[10]*srcData[15]) * det;
+
+    _data[8] = (srcData[8]*srcData[13]*srcData[7] -
+                srcData[12]*srcData[9]*srcData[7] +
+                srcData[12]*srcData[5]*srcData[11] -
+                srcData[4]*srcData[13]*srcData[11] -
+                srcData[8]*srcData[5]*srcData[15] +
+                srcData[4]*srcData[9]*srcData[15]) * det;
+
+    _data[12] = (srcData[12]*srcData[9]*srcData[6] -
+                 srcData[8]*srcData[13]*srcData[6] -
+                 srcData[12]*srcData[5]*srcData[10] +
+                 srcData[4]*srcData[13]*srcData[10] +
+                 srcData[8]*srcData[5]*srcData[14] -
+                 srcData[4]*srcData[9]*srcData[14]) * det;
+
+    _data[1] = (srcData[13]*srcData[10]*srcData[3] -
+                srcData[9]*srcData[14]*srcData[3] -
+                srcData[13]*srcData[2]*srcData[11] +
+                srcData[1]*srcData[14]*srcData[11] +
+                srcData[9]*srcData[2]*srcData[15] -
+                srcData[1]*srcData[10]*srcData[15]) * det;
+
+    _data[5] = (srcData[8]*srcData[14]*srcData[3] -
+                srcData[12]*srcData[10]*srcData[3] +
+                srcData[12]*srcData[2]*srcData[11] -
+                srcData[0]*srcData[14]*srcData[11] -
+                srcData[8]*srcData[2]*srcData[15] +
+                srcData[0]*srcData[10]*srcData[15]) * det;
+
+    _data[9] = (srcData[12]*srcData[9]*srcData[3] -
+                srcData[8]*srcData[13]*srcData[3] -
+                srcData[12]*srcData[1]*srcData[11] +
+                srcData[0]*srcData[13]*srcData[11] +
+                srcData[8]*srcData[1]*srcData[15] -
+                srcData[0]*srcData[9]*srcData[15]) * det;
+
+    _data[13] = (srcData[8]*srcData[13]*srcData[2] -
+                 srcData[12]*srcData[9]*srcData[2] +
+                 srcData[12]*srcData[1]*srcData[10] -
+                 srcData[0]*srcData[13]*srcData[10] -
+                 srcData[8]*srcData[1]*srcData[14] +
+                 srcData[0]*srcData[9]*srcData[14]) * det;
+
+    _data[2] = (srcData[5]*srcData[14]*srcData[3] -
+                srcData[13]*srcData[6]*srcData[3] +
+                srcData[13]*srcData[2]*srcData[7] -
+                srcData[1]*srcData[14]*srcData[7] -
+                srcData[5]*srcData[2]*srcData[15] +
+                srcData[1]*srcData[6]*srcData[15]) * det;
+
+    _data[6] = (srcData[12]*srcData[6]*srcData[3] -
+                srcData[4]*srcData[14]*srcData[3] -
+                srcData[12]*srcData[2]*srcData[7] +
+                srcData[0]*srcData[14]*srcData[7] +
+                srcData[4]*srcData[2]*srcData[15] -
+                srcData[0]*srcData[6]*srcData[15]) * det;
+
+    _data[10] = (srcData[4]*srcData[13]*srcData[3] -
+                 srcData[12]*srcData[5]*srcData[3] +
+                 srcData[12]*srcData[1]*srcData[7] -
+                 srcData[0]*srcData[13]*srcData[7] -
+                 srcData[4]*srcData[1]*srcData[15] +
+                 srcData[0]*srcData[5]*srcData[15]) * det;
+
+    _data[14] = (srcData[12]*srcData[5]*srcData[2] -
+                 srcData[4]*srcData[13]*srcData[2] -
+                 srcData[12]*srcData[1]*srcData[6] +
+                 srcData[0]*srcData[13]*srcData[6] +
+                 srcData[4]*srcData[1]*srcData[14] -
+                 srcData[0]*srcData[5]*srcData[14]) * det;
+
+    _data[3] = (srcData[9]*srcData[6]*srcData[3] -
+                srcData[5]*srcData[10]*srcData[3] -
+                srcData[9]*srcData[2]*srcData[7] +
+                srcData[1]*srcData[10]*srcData[7] +
+                srcData[5]*srcData[2]*srcData[11] -
+                srcData[1]*srcData[6]*srcData[11]) * det;
+
+    _data[7] = (srcData[4]*srcData[10]*srcData[3] -
+                srcData[8]*srcData[6]*srcData[3] +
+                srcData[8]*srcData[2]*srcData[7] -
+                srcData[0]*srcData[10]*srcData[7] -
+                srcData[4]*srcData[2]*srcData[11] +
+                srcData[0]*srcData[6]*srcData[11]) * det;
+
+    _data[11] = (srcData[8]*srcData[5]*srcData[3] -
+                 srcData[4]*srcData[9]*srcData[3] -
+                 srcData[8]*srcData[1]*srcData[7] +
+                 srcData[0]*srcData[9]*srcData[7] +
+                 srcData[4]*srcData[1]*srcData[11] -
+                 srcData[0]*srcData[5]*srcData[11]) * det;
+
+    _data[15] = (srcData[4]*srcData[9]*srcData[2] -
+                 srcData[8]*srcData[5]*srcData[2] +
+                 srcData[8]*srcData[1]*srcData[6] -
+                 srcData[0]*srcData[9]*srcData[6] -
+                 srcData[4]*srcData[1]*srcData[10] +
+                 srcData[0]*srcData[5]*srcData[10]) * det;
+}
+
+void Matrix4x4f::transpose()
+{
+    float m[16];
+
+    m[0] = _data[0];
+    m[1] = _data[4];
+    m[2] = _data[8];
+    m[3] = _data[12];
+
+    m[4] = _data[1];
+    m[5] = _data[5];
+    m[6] = _data[9];
+    m[7] = _data[13];
+
+    m[8] = _data[2];
+    m[9] = _data[6];
+    m[10] = _data[10];
+    m[11] = _data[14];
+
+    m[12] = _data[3];
+    m[13] = _data[7];
+    m[14] = _data[11];
+    m[15] = _data[15];
+
+    set(m);
+}
+
+void Matrix4x4f::transposeFast(const Matrix4x4f& mat)
+{
+    _data[0] = mat._data[0];
+    _data[1] = mat._data[4];
+    _data[2] = mat._data[8];
+    _data[3] = mat._data[12];
+
+    _data[4] = mat._data[1];
+    _data[5] = mat._data[5];
+    _data[6] = mat._data[9];
+    _data[7] = mat._data[13];
+
+    _data[8] = mat._data[2];
+    _data[9] = mat._data[6];
+    _data[10] = mat._data[10];
+    _data[11] = mat._data[14];
+
+    _data[12] = mat._data[3];
+    _data[13] = mat._data[7];
+    _data[14] = mat._data[11];
+    _data[15] = mat._data[15];
+}
+
+void Matrix4x4f::transpose(const Matrix4x4f& mat)
+{
+    if (&mat == this) {
+        transpose();
+    } else {
+        transposeFast(mat);
+    }
+}
+
+void Matrix4x4f::setDouble(const double *m)
+{
+    for (int i = 0; i < 16; ++i) {
+        _data[i] = (float)m[i];
+    }
+}
+
+void Matrix4x4f::multiply(const Matrix4x4f& mat1, const Vector3f& position)
+{
+    Matrix4x4f mat;
+    mat.makeTranslation(position);
+    multiply(mat1, mat);
+}
+
+void Matrix4x4f::multiply(const Matrix4x4f& mat1, const Rotation& rotation)
+{
+    Matrix4x4f mat;
+    mat.makeRotation(rotation);
+    multiply(mat1, mat);
+}
+
+void Matrix4x4f::multiply(const Vector3f& position, const Matrix4x4f& mat1)
+{
+    Matrix4x4f mat;
+    mat.makeTranslation(position);
+    multiply(mat, mat1);
+}
+
+void Matrix4x4f::multiply(const Rotation& rotation, const Matrix4x4f& mat1)
+{
+    Matrix4x4f mat;
+    mat.makeRotation(rotation);
+    multiply(mat, mat1);
+}
+
+void Matrix4x4f::makeVecRotVec(const Vector3f& vec1, const Vector3f& vec2)
+{
+    Vector3f axis = cross(vec1, vec2);
+
+    float angle = atan2(axis.length(), vec1.dot(vec2));
+    axis = axis.normalize();
+    makeRotation(axis.x, axis.y, axis.z, angle);
+}
+
+void Matrix4x4f::multiplyScale(const Matrix4x4f& mat1, const Vector3f& scale)
+{
+    Matrix4x4f mat;
+    mat.makeScale(scale);
+    multiply(mat1, mat);
+}
+
+void Matrix4x4f::multiplyScale(const Vector3f& scale, const Matrix4x4f& mat1)
+{
+    Matrix4x4f mat;
+    mat.makeScale(scale);
+    multiply(mat, mat1);
+}
Index: /nanovis/tags/1.1.4/vrmath/Plane.cpp
===================================================================
--- /nanovis/tags/1.1.4/vrmath/Plane.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/vrmath/Plane.cpp	(revision 4930)
@@ -0,0 +1,23 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Author: Insoo Woo <iwoo@purdue.edu>
+ */
+
+#include <vrmath/Plane.h>
+#include <vrmath/Matrix4x4d.h>
+
+using namespace vrmath;
+
+void Plane::transform(Matrix4x4d& mat)
+{
+    Vector4f v(normal.x, normal.y, normal.z, distance);
+    double* m = mat.get();
+
+    normal.set(m[0]*v.x + m[1]*v.y + m[2]*v.z + m[3]*v.w,
+               m[4]*v.x + m[5]*v.y + m[6]*v.z + m[7]*v.w,
+               m[8]*v.x + m[9]*v.y + m[10]*v.z + m[11]*v.w);
+
+    distance = m[12]*v.x + m[13]*v.y + m[14]*v.z + m[15]*v.w;
+}
Index: /nanovis/tags/1.1.4/vrmath/Projection.cpp
===================================================================
--- /nanovis/tags/1.1.4/vrmath/Projection.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/vrmath/Projection.cpp	(revision 4930)
@@ -0,0 +1,195 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Author: Insoo Woo <iwoo@purdue.edu>
+ */
+
+#include <math.h>
+#include <memory.h>
+
+using namespace vrmath;
+
+#if 0
+Vector3f calcNormal(const Vector3f& v1, const Vector3f& v2, const Vector3f& v3)
+{
+    Vector3f temp;
+
+    float a[3], b[3];
+
+    a[0] = v2.x - v1.x;
+    a[1] = v2.y - v1.y;
+    a[2] = v2.z - v1.z;
+    b[0] = v3.x - v1.x;
+    b[1] = v3.y - v1.y;
+    b[2] = v3.z - v1.z;
+
+    temp.x = a[1] * b[2] - a[2] * b[1];
+    temp.y = a[2] * b[0] - a[0] * b[2];
+    temp.z = a[0] * b[1] - a[1] * b[0];
+
+    float leng = (float)sqrt(temp.x * temp.x + temp.y * temp.y + temp.z * temp.z);
+
+    if (leng != 0.0f) {
+        temp.x /= leng;
+        temp.y /= leng;
+        temp.z /= leng;
+    }
+    else temp.set(-1.0f, 0.0f, 0.0f);
+
+    return temp;
+}
+#endif
+
+static void __gluMakeIdentityd(float m[16])
+{
+    m[0+4*0] = 1; m[0+4*1] = 0; m[0+4*2] = 0; m[0+4*3] = 0;
+    m[1+4*0] = 0; m[1+4*1] = 1; m[1+4*2] = 0; m[1+4*3] = 0;
+    m[2+4*0] = 0; m[2+4*1] = 0; m[2+4*2] = 1; m[2+4*3] = 0;
+    m[3+4*0] = 0; m[3+4*1] = 0; m[3+4*2] = 0; m[3+4*3] = 1;
+}
+
+static int __gluInvertMatrixd(const float m[16], float invOut[16])
+{
+    float inv[16], det;
+    int i;
+
+    inv[0] =   m[5]*m[10]*m[15] - m[5]*m[11]*m[14] - m[9]*m[6]*m[15]
+             + m[9]*m[7]*m[14] + m[13]*m[6]*m[11] - m[13]*m[7]*m[10];
+    inv[4] =  -m[4]*m[10]*m[15] + m[4]*m[11]*m[14] + m[8]*m[6]*m[15]
+             - m[8]*m[7]*m[14] - m[12]*m[6]*m[11] + m[12]*m[7]*m[10];
+    inv[8] =   m[4]*m[9]*m[15] - m[4]*m[11]*m[13] - m[8]*m[5]*m[15]
+             + m[8]*m[7]*m[13] + m[12]*m[5]*m[11] - m[12]*m[7]*m[9];
+    inv[12] = -m[4]*m[9]*m[14] + m[4]*m[10]*m[13] + m[8]*m[5]*m[14]
+             - m[8]*m[6]*m[13] - m[12]*m[5]*m[10] + m[12]*m[6]*m[9];
+    inv[1] =  -m[1]*m[10]*m[15] + m[1]*m[11]*m[14] + m[9]*m[2]*m[15]
+             - m[9]*m[3]*m[14] - m[13]*m[2]*m[11] + m[13]*m[3]*m[10];
+    inv[5] =   m[0]*m[10]*m[15] - m[0]*m[11]*m[14] - m[8]*m[2]*m[15]
+             + m[8]*m[3]*m[14] + m[12]*m[2]*m[11] - m[12]*m[3]*m[10];
+    inv[9] =  -m[0]*m[9]*m[15] + m[0]*m[11]*m[13] + m[8]*m[1]*m[15]
+             - m[8]*m[3]*m[13] - m[12]*m[1]*m[11] + m[12]*m[3]*m[9];
+    inv[13] =  m[0]*m[9]*m[14] - m[0]*m[10]*m[13] - m[8]*m[1]*m[14]
+             + m[8]*m[2]*m[13] + m[12]*m[1]*m[10] - m[12]*m[2]*m[9];
+    inv[2] =   m[1]*m[6]*m[15] - m[1]*m[7]*m[14] - m[5]*m[2]*m[15]
+             + m[5]*m[3]*m[14] + m[13]*m[2]*m[7] - m[13]*m[3]*m[6];
+    inv[6] =  -m[0]*m[6]*m[15] + m[0]*m[7]*m[14] + m[4]*m[2]*m[15]
+             - m[4]*m[3]*m[14] - m[12]*m[2]*m[7] + m[12]*m[3]*m[6];
+    inv[10] =  m[0]*m[5]*m[15] - m[0]*m[7]*m[13] - m[4]*m[1]*m[15]
+             + m[4]*m[3]*m[13] + m[12]*m[1]*m[7] - m[12]*m[3]*m[5];
+    inv[14] = -m[0]*m[5]*m[14] + m[0]*m[6]*m[13] + m[4]*m[1]*m[14]
+             - m[4]*m[2]*m[13] - m[12]*m[1]*m[6] + m[12]*m[2]*m[5];
+    inv[3] =  -m[1]*m[6]*m[11] + m[1]*m[7]*m[10] + m[5]*m[2]*m[11]
+             - m[5]*m[3]*m[10] - m[9]*m[2]*m[7] + m[9]*m[3]*m[6];
+    inv[7] =   m[0]*m[6]*m[11] - m[0]*m[7]*m[10] - m[4]*m[2]*m[11]
+             + m[4]*m[3]*m[10] + m[8]*m[2]*m[7] - m[8]*m[3]*m[6];
+    inv[11] = -m[0]*m[5]*m[11] + m[0]*m[7]*m[9] + m[4]*m[1]*m[11]
+             - m[4]*m[3]*m[9] - m[8]*m[1]*m[7] + m[8]*m[3]*m[5];
+    inv[15] =  m[0]*m[5]*m[10] - m[0]*m[6]*m[9] - m[4]*m[1]*m[10]
+             + m[4]*m[2]*m[9] + m[8]*m[1]*m[6] - m[8]*m[2]*m[5];
+
+    det = m[0]*inv[0] + m[1]*inv[4] + m[2]*inv[8] + m[3]*inv[12];
+
+    if (det == 0)
+        return 0;
+
+    det = 1.0f / det;
+
+    for (i = 0; i < 16; i++)
+        invOut[i] = inv[i] * det;
+
+    return 1;
+}
+
+static void __gluMultMatrixVecd(const float matrix[16], const float in[4],
+                                float out[4])
+{
+    int i;
+
+    for (i=0; i<4; i++) {
+        out[i] =
+            in[0] * matrix[0*4+i] +
+            in[1] * matrix[1*4+i] +
+            in[2] * matrix[2*4+i] +
+            in[3] * matrix[3*4+i];
+    }
+}
+
+static void __gluMultMatricesd(const float a[16], const float b[16],
+                               float r[16])
+{
+    int i, j;
+
+    for (i = 0; i < 4; i++) {
+        for (j = 0; j < 4; j++) {
+            r[i*4+j] =
+                a[i*4+0]*b[0*4+j] +
+                a[i*4+1]*b[1*4+j] +
+                a[i*4+2]*b[2*4+j] +
+                a[i*4+3]*b[3*4+j];
+        }
+    }
+}
+
+int unproject(float winx, float winy, float winz,
+              const float modelMatrix[16],
+              const float projMatrix[16],
+              const int viewport[4],
+              float *objx, float *objy, float *objz)
+{
+    float finalMatrix[16];
+    float in[4];
+    float out[4];
+
+    __gluMultMatricesd(modelMatrix, projMatrix, finalMatrix);
+    if (!__gluInvertMatrixd(finalMatrix, finalMatrix)) return(0);
+
+    in[0]=winx;
+    in[1]=winy;
+    in[2]=winz;
+    in[3]=1.0;
+
+    // Map x and y from window coordinates 
+    in[0] = (in[0] - viewport[0]) / viewport[2];
+    in[1] = (in[1] - viewport[1]) / viewport[3];
+
+    // Map to range -1 to 1 
+    in[0] = in[0] * 2 - 1;
+    in[1] = in[1] * 2 - 1;
+    in[2] = in[2] * 2 - 1;
+
+    __gluMultMatrixVecd(finalMatrix, in, out);
+    if (out[3] == 0.0) return(0);
+    out[0] /= out[3];
+    out[1] /= out[3];
+    out[2] /= out[3];
+    *objx = out[0];
+    *objy = out[1];
+    *objz = out[2];
+    return(1);
+}
+
+#define __glPi 3.14159265358979323846
+
+void perspective(float fovy, float aspect, float zNear, float zFar, float* matrix)
+{
+    float m[4][4];
+    float sine, cotangent, deltaZ;
+    float radians = (float) (fovy / 2.0 * __glPi / 180.0);
+
+    deltaZ = zFar - zNear;
+    sine = sin(radians);
+    if ((deltaZ == 0) || (sine == 0) || (aspect == 0)) {
+        return;
+    }
+    cotangent = cos(radians) / sine;
+
+    __gluMakeIdentityd(&m[0][0]);
+    m[0][0] = cotangent / aspect;
+    m[1][1] = cotangent;
+    m[2][2] = -(zFar + zNear) / deltaZ;
+    m[2][3] = -1;
+    m[3][2] = -2 * zNear * zFar / deltaZ;
+    m[3][3] = 0;
+    //glMultMatrixd(&m[0][0]);
+    memcpy(matrix, &m[0][0], sizeof(float) * 16);
+}
Index: /nanovis/tags/1.1.4/vrmath/Quaternion.cpp
===================================================================
--- /nanovis/tags/1.1.4/vrmath/Quaternion.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/vrmath/Quaternion.cpp	(revision 4930)
@@ -0,0 +1,90 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Author: Insoo Woo <iwoo@purdue.edu>
+ */
+
+#include <cstdlib>
+#include <cmath>
+#include <float.h>
+
+#include <vrmath/Quaternion.h>
+#include <vrmath/Rotation.h>
+#include <vrmath/Vector3f.h>
+
+#ifndef PI
+#define PI 3.14159264
+#endif
+
+using namespace vrmath;
+
+Quaternion::Quaternion() :
+    x(1.0f), y(0.0f), z(0.0f), w(0.0f)
+{
+}
+
+Quaternion::Quaternion(const Rotation& rot)
+{
+    set(rot);
+}
+
+Quaternion::Quaternion(double x1, double y1, double z1, double w1) :
+    x(x1), y(y1), z(z1), w(w1)
+{
+}
+
+Quaternion& Quaternion::normalize()
+{
+    double n = sqrt(w*w + x*x + y*y + z*z);
+    if (n == 0.0) {
+        w = 1.0; 
+        x = y = z = 0.0;
+    } else {
+        double recip = 1.0/n;
+        w *= recip;
+        x *= recip;
+        y *= recip;
+        z *= recip;
+    }
+
+    return *this;
+}
+
+const Quaternion& Quaternion::set(const Rotation& rot)
+{
+    Vector3f q(rot.x, rot.y, rot.z);
+    q.normalize();
+    double s = sin(rot.angle * 0.5);
+    x = s * q.x;
+    y = s * q.y;
+    z = s * q.z;
+    w = cos(rot.angle * 0.5);
+
+    return *this;
+}
+
+void Quaternion::slerp(const Quaternion &a,const Quaternion &b, double t)
+{
+    double alpha, beta;
+    double cosom = a.x * b.x + a.y * b.y + 
+        a.z * b.z + a.w * b.w;
+
+    bool flip = (cosom < 0.0);
+    if (flip) cosom = -cosom;
+    if ((1.0 - cosom) > 0.00001) {
+        double omega = acos(cosom);
+        double sinom = sin(omega);
+        alpha = sin((1.0 - t) * omega) / sinom;
+        beta = sin(t * omega) / sinom;
+    } else {
+        alpha = 1.0 - t;
+        beta = t;
+    }
+
+    if (flip) beta = -beta;
+    x = alpha * a.x + beta * b.x;
+    y = alpha * a.y + beta * b.y;
+    z = alpha * a.z + beta * b.z;
+    w = alpha * a.w + beta * b.w;
+}
Index: /nanovis/tags/1.1.4/vrmath/Rotation.cpp
===================================================================
--- /nanovis/tags/1.1.4/vrmath/Rotation.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/vrmath/Rotation.cpp	(revision 4930)
@@ -0,0 +1,70 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Author: Insoo Woo <iwoo@purdue.edu>
+ */
+
+#include <math.h>
+
+#include <vrmath/Rotation.h>
+#include <vrmath/Vector3f.h>
+#include <vrmath/Quaternion.h>
+
+using namespace vrmath;
+
+void Rotation::set(const Vector3f &vec1, const Vector3f &vec2)
+{
+    if (vec1 == vec2) {
+        x = 0.0f;
+        y = 0.0f;
+        z = 1.0f;
+        angle = 0.0f;
+        return;
+    }
+
+    Vector3f perp = cross(vec1, vec2);
+
+    float ang = atan2(perp.length(), vec1.dot(vec2));
+
+    perp = perp.normalize();
+
+    x = perp.x;
+    y = perp.y;
+    z = perp.z;
+    angle = ang;
+}
+
+void Rotation::set(const Quaternion& quat)
+{
+    //if (quat.w > 1) quat.normalize();
+
+    angle = acos(quat.w) * 2.0f;
+    float scale = sqrt(1 - quat.w * quat.w);
+    if (angle < 1.0e-6f) {
+        x = 1;
+        y = 0;
+        z = 0;
+    } else if (scale < 1.0e-6f) {
+        x = quat.x;
+        y = quat.y;
+        z = quat.z;
+    } else {
+        x = quat.x / scale;
+        y = quat.y / scale;
+        z = quat.z / scale;
+    }
+}
+
+Quaternion Rotation::getQuaternion() const
+{
+    Quaternion result;
+
+    result.w = cos(angle / 2.0);
+    double sinHalfAngle = sin(angle / 2.0);
+    result.x = x * sinHalfAngle;
+    result.y = y * sinHalfAngle;
+    result.z = z * sinHalfAngle;
+
+    return result;
+}
Index: /nanovis/tags/1.1.4/vrmath/Vector2f.cpp
===================================================================
--- /nanovis/tags/1.1.4/vrmath/Vector2f.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/vrmath/Vector2f.cpp	(revision 4930)
@@ -0,0 +1,8 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Author: Insoo Woo <iwoo@purdue.edu>
+ */
+
+#include <vrmath/Vector2f.h>
Index: /nanovis/tags/1.1.4/vrmath/Vector3f.cpp
===================================================================
--- /nanovis/tags/1.1.4/vrmath/Vector3f.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/vrmath/Vector3f.cpp	(revision 4930)
@@ -0,0 +1,9 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Author: Insoo Woo <iwoo@purdue.edu>
+ */
+
+#include <vrmath/Vector3f.h>
+
Index: /nanovis/tags/1.1.4/vrmath/Vector4f.cpp
===================================================================
--- /nanovis/tags/1.1.4/vrmath/Vector4f.cpp	(revision 4930)
+++ /nanovis/tags/1.1.4/vrmath/Vector4f.cpp	(revision 4930)
@@ -0,0 +1,8 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Author: Insoo Woo <iwoo@purdue.edu>
+ */
+
+#include <vrmath/Vector4f.h>
Index: /nanovis/tags/1.1.4/vrmath/include/vrmath/BBox.h
===================================================================
--- /nanovis/tags/1.1.4/vrmath/include/vrmath/BBox.h	(revision 4930)
+++ /nanovis/tags/1.1.4/vrmath/include/vrmath/BBox.h	(revision 4930)
@@ -0,0 +1,124 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Author: Insoo Woo <iwoo@purdue.edu>
+ */
+#ifndef VRBBOX_H
+#define VRBBOX_H
+
+#include <vrmath/Vector3f.h>
+
+namespace vrmath {
+
+class Matrix4x4d;
+
+class BBox
+{
+public:
+    /**
+     * @brief constructor
+     */
+    BBox();
+
+    /**
+     * @brief constructor
+     * @param bbox bounding box
+     */
+    BBox(const BBox& bbox);
+
+    /**
+     * @brief constructor
+     * @param min minimum point of the bounding box
+     * @param max maximum point of the bounding box
+     */
+    BBox(const Vector3f& min, const Vector3f& max);
+
+    BBox& operator=(const BBox& other)
+    {
+        if (&other != this) {
+            min = other.min;
+            max = other.max;
+        }
+        return *this;
+    }
+
+    /**
+     * @brief make an empty bounding box
+     */
+    void makeEmpty();
+
+    /**
+     * @brief make an bouning box
+     * @param center the center of bounding box
+     * @param size the size of bounding box
+     */
+    void make(const Vector3f& center, const Vector3f& size);
+
+    /**
+     * @brief check if the bounding box is empty
+     */
+    bool isEmpty();
+    bool isEmptyX();
+    bool isEmptyY();
+    bool isEmptyZ();
+
+    /**
+     * @brief extend the bounding box by a point
+     */
+    void extend(const Vector3f& point);
+
+    /**
+     * @brief extend the bounding box by a bbox
+     */
+    void extend(const BBox& bbox);
+
+    /**
+     * @brief transform a bounding box with a matrix and set the bounding box
+     */
+    void transform(const BBox& box, const Matrix4x4d& mat);
+
+    /**
+     * @brief check if the bounding box intersect with a box
+     */
+    bool intersect(const BBox& box);
+
+    /**
+     * @brief check if the bounding box contains a point
+     */
+    bool contains(const Vector3f& point);
+
+    float getRadius() const;
+    Vector3f getCenter() const;
+    Vector3f getSize() const;
+
+    Vector3f min;
+    Vector3f max;
+};
+
+inline float BBox::getRadius() const
+{
+    return max.distance( min ) * 0.5f;
+}
+
+inline Vector3f BBox::getCenter() const
+{
+    Vector3f temp;
+    temp.x = (max.x + min.x) * 0.5f;
+    temp.y = (max.y + min.y) * 0.5f;
+    temp.z = (max.z + min.z) * 0.5f;
+    return temp;
+}
+
+inline Vector3f BBox::getSize() const
+{
+    Vector3f temp;
+    temp.x = max.x - min.x;
+    temp.y = max.y - min.y;
+    temp.z = max.z - min.z;
+    return temp;
+}
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/vrmath/include/vrmath/BPlane.h
===================================================================
--- /nanovis/tags/1.1.4/vrmath/include/vrmath/BPlane.h	(revision 4930)
+++ /nanovis/tags/1.1.4/vrmath/include/vrmath/BPlane.h	(revision 4930)
@@ -0,0 +1,36 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Author: Insoo Woo <iwoo@purdue.edu>
+ * Author: Sung-Ye Kim <inside@purdue.edu>
+ */
+#ifndef VRBPLANE_H
+#define VRBPLANE_H
+
+#include <vrmath/Vector3f.h>
+
+namespace vrmath {
+
+class LineSegment;
+
+class BPlane
+{
+public:
+    void makePts(const Vector3f& pt1, const Vector3f& pt2, const Vector3f& pt3);
+
+    void makeNormalPt(const Vector3f& norm, const Vector3f& pos);
+
+    bool intersect(const LineSegment &seg, float &d) const;
+
+    double distance(const Vector3f& point) const;
+
+    Vector3f crossPoint(const Vector3f& point) const;
+
+    Vector3f normal;
+    Vector3f point;
+};
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/vrmath/include/vrmath/Color4f.h
===================================================================
--- /nanovis/tags/1.1.4/vrmath/include/vrmath/Color4f.h	(revision 4930)
+++ /nanovis/tags/1.1.4/vrmath/include/vrmath/Color4f.h	(revision 4930)
@@ -0,0 +1,18 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Author: Insoo Woo <iwoo@purdue.edu>
+ */
+#ifndef VRCOLOR4F_H
+#define VRCOLOR4F_H
+
+#include <vrmath/Vector4f.h>
+
+namespace vrmath {
+
+typedef Vector4f Color4f;
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/vrmath/include/vrmath/LineSegment.h
===================================================================
--- /nanovis/tags/1.1.4/vrmath/include/vrmath/LineSegment.h	(revision 4930)
+++ /nanovis/tags/1.1.4/vrmath/include/vrmath/LineSegment.h	(revision 4930)
@@ -0,0 +1,46 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Author: Insoo Woo <iwoo@purdue.edu>
+ * Author: Sung-Ye Kim <inside@purdue.edu>
+ */
+#ifndef VRLINESEGMENT_H
+#define VRLINESEGMENT_H
+
+#include <vrmath/Vector3f.h>
+#include <vrmath/Vector4f.h>
+
+namespace vrmath {
+
+class Matrix4x4d;
+
+class LineSegment
+{
+public:
+    LineSegment();
+
+    /// Return the point
+    Vector3f getPoint(float d) const;
+
+    /// Transfrom the line segment using mat
+    void transform(const Matrix4x4d &transMat, const LineSegment &seg);
+
+    /// The position of the line segment
+    Vector4f pos;
+
+    /// The direction of the line segment
+    Vector3f dir;
+
+    /// The length of the line segment
+    float length;
+};
+
+inline Vector3f LineSegment::getPoint(float d) const 
+{
+    return Vector3f(pos.x + d * dir.x, pos.y + d * dir.y, pos.z + d * dir.z);
+}
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/vrmath/include/vrmath/Matrix4x4d.h
===================================================================
--- /nanovis/tags/1.1.4/vrmath/include/vrmath/Matrix4x4d.h	(revision 4930)
+++ /nanovis/tags/1.1.4/vrmath/include/vrmath/Matrix4x4d.h	(revision 4930)
@@ -0,0 +1,192 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Author: Insoo Woo <iwoo@purdue.edu>
+ */
+#ifndef VRMATRIX4X4D_H
+#define VRMATRIX4X4D_H
+
+#include <memory.h>
+
+#include <vrmath/Vector3f.h>
+#include <vrmath/Vector4f.h>
+
+#include "Trace.h"
+
+namespace vrmath {
+
+class Rotation;
+
+class Matrix4x4d
+{
+public:
+    Matrix4x4d()
+    {
+        makeIdentity();
+    }
+
+    Matrix4x4d(double *m)
+    {
+        set(m);
+    }
+
+    Matrix4x4d(const Matrix4x4d& other)
+    {
+        set(other.get());
+    }
+
+    Matrix4x4d& operator=(const Matrix4x4d& other)
+    {
+        if (&other != this) {
+            set(other.get());
+        }
+        return *this;
+    }
+
+    /**
+     * @brief make a identity matrix
+     */
+    void makeIdentity();
+
+    /**
+     * @brief make a translation matrix
+     */
+    void makeTranslation(const Vector3f& translation);
+
+    /**
+     * @brief make a translation matrix
+     */
+    void makeTranslation(double x, double y, double z);
+
+    /**
+     * @brief make a rotation matrix
+     */
+    void makeRotation(const Rotation& rotation);
+
+    /**
+     * @brief Make a rotation matrix
+     */
+    void makeRotation(double x, double y, double z, double angle);
+
+    void makeVecRotVec(const Vector3f& vec1, const Vector3f& vec2);
+
+    /**
+     * @brief make a scale matrix
+     */
+    void makeScale(const Vector3f& scale);
+
+    void makeScale(double x, double y, double z);
+
+    void makeTR(const Vector3f& translation, const Rotation& rotation);
+    void makeTRS(const Vector3f& translation, const Rotation& rotation, const Vector3f& scale);
+
+    Vector4f transform(const Vector4f& v) const;
+    Vector3f transformVec(const Vector3f& v) const;
+    Vector4f preMultiplyRowVector(const Vector4f& v) const;
+
+    void multiply(const Matrix4x4d& mat1, const Matrix4x4d& mat2);
+
+    void multiply(const Matrix4x4d& mat1, const Vector3f& position);
+    void multiplyScale(const Matrix4x4d& mat, const Vector3f& scale);
+    void multiply(const Matrix4x4d& mat1, const Rotation& rotation);
+    void multiply(const Vector3f& position, const Matrix4x4d& mat1);
+    void multiply(const Rotation& rotation, const Matrix4x4d& mat1);
+    void multiplyScale(const Vector3f& scale, const Matrix4x4d& mat);
+
+    void multiply(const Matrix4x4d& mat1);
+    void multiplyFast(const Matrix4x4d& mat1, const Matrix4x4d& mat2);
+
+    void invert();
+    void invert(const Matrix4x4d& mat);
+    void invertFast(const Matrix4x4d& mat);
+    Matrix4x4d inverse() const;
+
+    void transpose();
+    void transpose(const Matrix4x4d& mat);
+    void transposeFast(const Matrix4x4d& mat);
+	
+    void getTranslation(Vector3f& vector);
+    void getRotation(Rotation& rotation);
+
+    /**
+     * @brief return data pointer of the matrix
+     * @return float array of the matrix
+     */
+    const double *get() const;
+
+    /**
+     * @brief return data pointer of the matrix
+     * @return float array of the matrix
+     */
+    double *get();
+
+    /**
+     * @brief set double arrary to this
+     * @param m float matrix values
+     */
+    void set(const double *m);
+
+    void setFloat(const float *m);
+
+    void print() const;
+
+private:
+    /**
+     * \brief Column-major array (like OpenGL)
+     */
+    double _data[16];
+};
+
+inline const double *Matrix4x4d::get() const
+{
+    return _data;
+}
+
+inline double *Matrix4x4d::get()
+{
+    return _data;
+}
+
+inline void Matrix4x4d::set(const double *m)
+{
+    memcpy(_data, m, sizeof(double) * 16);
+}
+
+inline void Matrix4x4d::getTranslation(Vector3f& translation)
+{
+    translation.set((float)_data[12], (float)_data[13], (float)_data[14]);
+}
+
+inline void Matrix4x4d::makeTRS(const Vector3f& translation,
+                                const Rotation& rotation,
+                                const Vector3f& scale)
+{
+    Matrix4x4d mat;
+    mat.makeTR(translation, rotation);
+	
+    makeScale(scale);
+	
+    multiply(mat, *this);
+}
+
+inline void Matrix4x4d::makeTR(const Vector3f& translation,
+                               const Rotation& rotation)
+{
+    makeRotation(rotation);
+	
+    _data[12] = translation.x;
+    _data[13] = translation.y;
+    _data[14] = translation.z;
+}
+
+inline void Matrix4x4d::print() const
+{
+    TRACE("% 8.6f % 8.6f % 8.6f % 8.6f", _data[0], _data[4], _data[8 ], _data[12]);
+    TRACE("% 8.6f % 8.6f % 8.6f % 8.6f", _data[1], _data[5], _data[9 ], _data[13]);
+    TRACE("% 8.6f % 8.6f % 8.6f % 8.6f", _data[2], _data[6], _data[10], _data[14]);
+    TRACE("% 8.6f % 8.6f % 8.6f % 8.6f", _data[3], _data[7], _data[11], _data[15]);
+}
+
+}
+#endif
Index: /nanovis/tags/1.1.4/vrmath/include/vrmath/Matrix4x4f.h
===================================================================
--- /nanovis/tags/1.1.4/vrmath/include/vrmath/Matrix4x4f.h	(revision 4930)
+++ /nanovis/tags/1.1.4/vrmath/include/vrmath/Matrix4x4f.h	(revision 4930)
@@ -0,0 +1,196 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Author: Insoo Woo <iwoo@purdue.edu>
+ */
+#ifndef VRMATRIX4X4F_H
+#define VRMATRIX4X4F_H
+
+#include <memory.h>
+
+#include <vrmath/Vector3f.h>
+#include <vrmath/Vector4f.h>
+
+#include "Trace.h"
+
+namespace vrmath {
+
+class Rotation;
+
+class Matrix4x4f
+{
+public:
+    Matrix4x4f()
+    {
+        makeIdentity();
+    }
+
+    Matrix4x4f(float *m)
+    {
+        set(m);
+    }
+
+    Matrix4x4f(const Matrix4x4f& other)
+    {
+        set(other.get());
+    }
+
+    Matrix4x4f& operator=(const Matrix4x4f& other)
+    {
+        if (&other != this) {
+            set(other.get());
+        }
+        return *this;
+    }
+
+    /**
+     * @brief make a identity matrix
+     */
+    void makeIdentity();
+
+    /**
+     * @brief make a translation matrix
+     */
+    void makeTranslation(const Vector3f& translation);
+
+    /**
+     * @brief make a translation matrix
+     */
+    void makeTranslation(float x, float y, float z);
+
+    /**
+     * @brief make a rotation matrix
+     */
+    void makeRotation(const Rotation& rotation);
+
+    /**
+     * @brief Make a rotation matrix
+     */
+    void makeRotation(double x, double y, double z, double angle);
+
+    void makeVecRotVec(const Vector3f& vec1, const Vector3f& vec2);
+
+    /**
+     * @brief make a scale matrix
+     */
+    void makeScale(const Vector3f& scale);
+
+    void makeScale(float x, float y, float z);
+
+    void makeTR(const Vector3f& translation, const Rotation& rotation);
+    void makeTRS(const Vector3f& translation, const Rotation& rotation, const Vector3f& scale);
+
+    Vector4f transform(const Vector4f& v) const;
+    Vector3f transformVec(const Vector3f& v) const;
+
+    Vector4f preMultiplyRowVector(const Vector4f& v) const;
+
+    void multiply(const Matrix4x4f& mat1, const Matrix4x4f& mat2);
+
+    void multiply(const Matrix4x4f& mat1, const Vector3f& position);
+    void multiplyScale(const Matrix4x4f& mat, const Vector3f& scale);
+    void multiply(const Matrix4x4f& mat1, const Rotation& rotation);
+    void multiply(const Vector3f& position, const Matrix4x4f& mat1);
+    void multiply(const Rotation& rotation, const Matrix4x4f& mat1);
+    void multiplyScale(const Vector3f& scale, const Matrix4x4f& mat);
+
+    void multiply(const Matrix4x4f& mat1);
+    void multiplyFast(const Matrix4x4f& mat1, const Matrix4x4f& mat2);
+
+    void invert();
+    void invert(const Matrix4x4f& mat);
+    void invertFast(const Matrix4x4f& mat);
+
+    void transpose();
+    void transpose(const Matrix4x4f& mat);
+    void transposeFast(const Matrix4x4f& mat);
+	
+    void getTranslation(Vector3f& vector);
+    void getRotation(Rotation& rotation);
+
+    /**
+     * @brief return data pointer of the matrix
+     * @return float array of the matrix
+     */
+    const float *get() const;
+
+    /**
+     * @brief return data pointer of the matrix
+     * @return float array of the matrix
+     */
+    float *get();
+
+    /**
+     * @brief set float arrary to this
+     * @param m float matrix values
+     */
+    void set(const float *m);
+
+    /**
+     * @brief set double arrary to this
+     * @param m float matrix values
+     */
+    void setDouble(const double *m);
+
+    void print() const;
+
+private:
+    /**
+     * \brief Column-major array (like OpenGL)
+     */
+    float _data[16];
+};
+
+inline const float *Matrix4x4f::get() const
+{
+    return _data;
+}
+
+inline float *Matrix4x4f::get()
+{
+    return _data;
+}
+
+inline void Matrix4x4f::set(const float *m)
+{
+    memcpy(_data, m, sizeof(float) * 16);
+}
+
+inline void Matrix4x4f::getTranslation(Vector3f& translation)
+{
+    translation.set(_data[12], _data[13], _data[14]);
+}
+
+inline void Matrix4x4f::makeTRS(const Vector3f& translation,
+                                const Rotation& rotation,
+                                const Vector3f& scale)
+{
+    Matrix4x4f mat;
+    mat.makeTR(translation, rotation);
+	
+    makeScale(scale);
+	
+    multiply(mat, *this);
+}
+
+inline void Matrix4x4f::makeTR(const Vector3f& translation,
+                               const Rotation& rotation)
+{
+    makeRotation(rotation);
+	
+    _data[12] = translation.x;
+    _data[13] = translation.y;
+    _data[14] = translation.z;
+}
+
+inline void Matrix4x4f::print() const
+{
+    TRACE("% 8.6f % 8.6f % 8.6f % 8.6f", _data[0], _data[4], _data[8 ], _data[12]);
+    TRACE("% 8.6f % 8.6f % 8.6f % 8.6f", _data[1], _data[5], _data[9 ], _data[13]);
+    TRACE("% 8.6f % 8.6f % 8.6f % 8.6f", _data[2], _data[6], _data[10], _data[14]);
+    TRACE("% 8.6f % 8.6f % 8.6f % 8.6f", _data[3], _data[7], _data[11], _data[15]);
+}
+
+}
+#endif
Index: /nanovis/tags/1.1.4/vrmath/include/vrmath/Plane.h
===================================================================
--- /nanovis/tags/1.1.4/vrmath/include/vrmath/Plane.h	(revision 4930)
+++ /nanovis/tags/1.1.4/vrmath/include/vrmath/Plane.h	(revision 4930)
@@ -0,0 +1,74 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Author: Insoo Woo <iwoo@purdue.edu>
+ * Author: Sung-Ye Kim <inside@purdue.edu>
+ */
+#ifndef VRPLANE_H
+#define VRPLANE_H
+
+#include <vrmath/Vector4f.h>
+#include <vrmath/Vector3f.h>
+
+namespace vrmath {
+
+class Matrix4x4d;
+
+class Plane
+{
+public:
+    bool intersect(const Vector3f& p1, const Vector3f& p2, Vector3f& intersectPoint) const;
+    bool intersect(const Vector3f& p1, const Vector3f& p2, Vector4f& intersectPoint) const;
+    void transform(Matrix4x4d& mat);
+
+    /// normal vector
+    Vector3f normal;
+
+    /// @brief the distance from the origin
+    float distance;
+};
+
+inline bool Plane::intersect(const Vector3f& p1, const Vector3f& p2, Vector3f& intersectPoint) const
+{
+    // http://astronomy.swin.edu.au/pbourke/geometry/planeline/
+    float numerator = normal.x * p1.x + normal.y * p1.y + normal.z * p1.z;
+    float denominator = normal.x * (p1.x - p2.x) + normal.y * (p1.y - p2.y) + normal.z * (p1.z - p2.z);
+
+    if (denominator == 0.0f) return false;
+
+    float u = numerator / denominator;
+    if ((u > 0) && (u < 1.0f)) {
+        return true;
+    }
+
+    intersectPoint.x = p1.x + u * (p2.x - p1.x);
+    intersectPoint.y = p1.y + u * (p2.y - p1.y);
+    intersectPoint.z = p1.z + u * (p2.z - p1.z);
+
+    return false;
+}
+
+inline bool Plane::intersect(const Vector3f& p1, const Vector3f& p2, Vector4f& intersectPoint) const
+{
+    // http://astronomy.swin.edu.au/pbourke/geometry/planeline/
+    float numerator = normal.x * p1.x + normal.y * p1.y + normal.z * p1.z;
+    float denominator = normal.x * (p1.x - p2.x) + normal.y * (p1.y - p2.y) + normal.z * (p1.z - p2.z);
+    if (denominator == 0.0f) return false;
+    float u = numerator / denominator;
+
+    if ((u > 0) && (u < 1.0f)) {
+        return true;
+    }
+
+    intersectPoint.x = p1.x + u * (p2.x - p1.x);
+    intersectPoint.y = p1.y + u * (p2.y - p1.y);
+    intersectPoint.z = p1.z + u * (p2.z - p1.z);
+    intersectPoint.w = 1.0f;
+
+    return false;
+}
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/vrmath/include/vrmath/Projection.h
===================================================================
--- /nanovis/tags/1.1.4/vrmath/include/vrmath/Projection.h	(revision 4930)
+++ /nanovis/tags/1.1.4/vrmath/include/vrmath/Projection.h	(revision 4930)
@@ -0,0 +1,25 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Author: Insoo Woo <iwoo@purdue.edu>
+ */
+#ifndef VRPROJECTION_H
+#define VRPROJECTION_H
+
+namespace vrmath {
+
+extern int
+unproject(float winx, float winy, float winz,
+          const float modelMatrix[16],
+          const float projMatrix[16],
+          const int viewport[4],
+          float *objx, float *objy, float *objz);
+
+extern void
+perspective(float fovy, float aspect, float zNear, float zFar, float *matrix);
+
+}
+
+#endif
+
Index: /nanovis/tags/1.1.4/vrmath/include/vrmath/Quaternion.h
===================================================================
--- /nanovis/tags/1.1.4/vrmath/include/vrmath/Quaternion.h	(revision 4930)
+++ /nanovis/tags/1.1.4/vrmath/include/vrmath/Quaternion.h	(revision 4930)
@@ -0,0 +1,101 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Author: Insoo Woo <iwoo@purdue.edu>
+ */
+#ifndef VRQUATERNION_H
+#define VRQUATERNION_H
+
+namespace vrmath {
+
+class Rotation;
+
+class Quaternion
+{
+public:
+    Quaternion();
+
+    explicit Quaternion(const Rotation& rot);
+
+    Quaternion(double x, double y, double z, double w);
+
+    Quaternion(const Quaternion& other) :
+        x(other.x), y(other.y), z(other.z), w(other.w)
+    {}
+
+    Quaternion& operator=(const Quaternion& other)
+    {
+        if (&other != this) {
+            set(other.x, other.y, other.z, other.w);
+        }
+        return *this;
+    }
+
+    void set(double x, double y, double z, double w);
+
+    const Quaternion& set(const Rotation& rot);
+
+    Quaternion conjugate() const
+    {
+        Quaternion result;
+        result.w = w;
+        result.x = -x;
+        result.y = -y;
+        result.z = -z;
+        return result;
+    }
+
+    Quaternion reciprocal() const
+    {
+        double denom =  w*w + x*x + y*y + z*z;
+        Quaternion result = conjugate();
+        result.x /= denom;
+        result.y /= denom;
+        result.z /= denom;
+        result.w /= denom;
+        return result;
+    }
+
+    void slerp(const Rotation &a,const Rotation &b, double t);
+
+    void slerp(const Quaternion &a,const Quaternion &b, double t);
+
+    Quaternion& normalize();
+
+    Quaternion operator*(const Quaternion& q2) const
+    {
+        Quaternion result;
+        result.w = (w * q2.w) - (x * q2.x) - (y * q2.y) - (z * q2.z);
+        result.x = (w * q2.x) + (x * q2.w) + (y * q2.z) - (z * q2.y);
+        result.y = (w * q2.y) + (y * q2.w) + (z * q2.x) - (x * q2.z);
+        result.z = (w * q2.z) + (z * q2.w) + (x * q2.y) - (y * q2.x);
+        return result;
+    }
+
+    friend bool operator==(const Quaternion& q1, const Quaternion& q2);
+
+    double x, y, z, w;
+};
+
+inline bool operator==(const Quaternion& q1, const Quaternion& q2)
+{
+    return ((q1.x == q2.x) && (q1.y == q2.y) && (q1.z == q2.z) && (q1.w == q2.w));
+}
+
+inline void Quaternion::slerp(const Rotation &a,const Rotation &b, double t)
+{
+    slerp(Quaternion(a), Quaternion(b), t);
+}
+
+inline void Quaternion::set(double x, double y, double z, double w)
+{
+    this->x = x;
+    this->y = y;
+    this->z = z;
+    this->w = w;
+}
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/vrmath/include/vrmath/Rotation.h
===================================================================
--- /nanovis/tags/1.1.4/vrmath/include/vrmath/Rotation.h	(revision 4930)
+++ /nanovis/tags/1.1.4/vrmath/include/vrmath/Rotation.h	(revision 4930)
@@ -0,0 +1,105 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Author: Insoo Woo <iwoo@purdue.edu>
+ */
+#ifndef VRROTATION_H
+#define VRROTATION_H
+
+#include <vrmath/Vector3f.h>
+
+namespace vrmath {
+
+class Quaternion;
+
+/**
+ * Represents an axis/angle rotation (angle in radians)
+ */
+class Rotation
+{
+public:
+    Rotation() :
+        x(0.0), y(1.0), z(0.0), angle(0.0)
+    {}
+
+    Rotation(double x1, double y1, double z1, double angle1) :
+        x(x1), y(y1), z(z1), angle(angle1)
+    {}
+
+    Rotation(const Rotation& other) :
+        x(other.x), y(other.y), z(other.z), angle(other.angle)
+    {}
+
+    Rotation& operator=(const Rotation& other)
+    {
+        if (&other != this) {
+            set(other.x, other.y, other.z, other.angle);
+        }
+        return *this;
+    }
+
+    double getX() const
+    { return x; }
+    double getY() const
+    { return y; }
+    double getZ() const
+    { return z; }
+
+    double getAngle() const
+    { return angle; }
+
+    Quaternion getQuaternion() const;
+
+    void set(double x, double y, double z, double angle);
+    void set(const Vector3f& vec1, const Vector3f& vec2);
+    void set(const Quaternion& quat);
+    void set(const Rotation& rot);
+    void setAxis(double x, double y, double z);
+    void setAxis(const Vector3f& vec);
+    void setAngle(double angle);
+
+    friend bool operator!=(const Rotation& rot1, const Rotation& rot2);
+    friend bool operator==(const Rotation& rot1, const Rotation& rot2);
+
+    double x, y, z, angle;
+};
+
+inline void Rotation::set(double x, double y, double z, double angle)
+{
+    this->x = x; this->y = y; this->z = z; this->angle = angle;
+}
+
+inline void Rotation::set(const Rotation& rot)
+{
+    this->x = rot.x; this->y = rot.y; this->z = rot.z; this->angle = rot.angle;
+}
+
+inline void Rotation::setAxis(double x, double y, double z)
+{
+    this->x = x; this->y = y; this->z = z;
+}
+
+inline void Rotation::setAxis(const Vector3f& vec)
+{
+    this->x = vec.x; this->y = vec.y; this->z = vec.z;
+}
+
+inline void Rotation::setAngle(double angle)
+{
+    this->angle = angle;
+}
+
+inline bool operator==(const Rotation& rot1, const Rotation& rot2)
+{
+    return ((rot1.x == rot2.x) && (rot1.y == rot2.y) && (rot1.z == rot2.z) && (rot1.angle == rot2.angle));
+}
+
+inline bool operator!=(const Rotation& rot1, const Rotation& rot2)
+{
+    return ((rot1.x != rot2.x) || (rot1.y != rot2.y) || (rot1.z != rot2.z) || (rot1.angle != rot2.angle));
+}
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/vrmath/include/vrmath/Vector2f.h
===================================================================
--- /nanovis/tags/1.1.4/vrmath/include/vrmath/Vector2f.h	(revision 4930)
+++ /nanovis/tags/1.1.4/vrmath/include/vrmath/Vector2f.h	(revision 4930)
@@ -0,0 +1,105 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Author: Insoo Woo <iwoo@purdue.edu>
+ */
+#ifndef VRVECTOR2F_H
+#define VRVECTOR2F_H
+
+#include <cstdlib>
+#include <cmath>
+
+namespace vrmath {
+
+class Vector2f
+{
+public:
+    Vector2f() :
+        x(0.0f), y(0.0f)
+    {}
+
+    Vector2f(const Vector2f& v) :
+        x(v.x), y(v.y)
+    {}
+
+    Vector2f(float x1, float y1) :
+        x(x1), y(y1)
+    {}
+
+    Vector2f& operator=(const Vector2f& other)
+    {
+        if (&other != this) {
+            set(other.x, other.y);
+        }
+        return *this;
+    }
+
+    void set(float x, float y);
+
+    void set(const Vector2f& v);
+
+    double dot() const;
+
+    double length() const;
+
+    double distance(const Vector2f& v) const;
+
+    double distance(float x, float y) const;
+
+    double distanceSquare(const Vector2f& v) const;
+
+    double distanceSquare(float x, float y) const;
+
+    float x, y;
+};
+
+inline void Vector2f::set(float x, float y)
+{
+    this->x = x;
+    this->y = y;
+}
+
+inline void Vector2f::set(const Vector2f& v)
+{
+    x = v.x;
+    y = v.y;
+}
+
+inline double Vector2f::dot() const
+{
+    return (x * x + y * y);
+}
+
+inline double Vector2f::length() const
+{
+    return sqrt(x * x + y * y);
+}
+
+inline double Vector2f::distance(const Vector2f& v) const
+{
+    double x1 = ((double)v.x - (double)x) , y1 = ((double)v.y - (double)y);
+    return sqrt(x1 * x1 + y1 * y1);
+}
+
+inline double Vector2f::distance(float x, float y) const
+{	
+    double x1 = ((double)x - (double)this->x) , y1 = ((double)y - (double)this->y);
+    return sqrt(x1 * x1 + y1 * y1);
+}
+
+inline double Vector2f::distanceSquare(const Vector2f& v) const
+{	
+    double x1 = ((double)v.x - (double)x) , y1 = ((double)v.y - (double)y);
+    return (x1 * x1 + y1 * y1);
+}
+
+inline double Vector2f::distanceSquare(float x, float y) const
+{	
+    double x1 = ((double)x - (double)this->x) , y1 = ((double)y - (double)this->y);
+    return (x1 * x1 + y1 * y1);
+}
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/vrmath/include/vrmath/Vector3f.h
===================================================================
--- /nanovis/tags/1.1.4/vrmath/include/vrmath/Vector3f.h	(revision 4930)
+++ /nanovis/tags/1.1.4/vrmath/include/vrmath/Vector3f.h	(revision 4930)
@@ -0,0 +1,295 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Author: Insoo Woo <iwoo@purdue.edu>
+ */
+#ifndef VRVECTOR3F_H
+#define VRVECTOR3F_H
+
+#include <cstdlib>
+#include <cmath>
+
+namespace vrmath {
+
+class Vector3f
+{
+public:
+    Vector3f() :
+        x(0.0f), y(0.0f), z(0.0f)
+    {}
+
+    Vector3f(const Vector3f& v3) :
+        x(v3.x), y(v3.y), z(v3.z)
+    {}
+
+    Vector3f(float x1, float y1, float z1) :
+        x(x1), y(y1), z(z1)
+    {}
+    
+    Vector3f& operator=(const Vector3f& other)
+    {
+        if (&other != this) {
+            set(other.x, other.y, other.z);
+        }
+        return *this;
+    }
+
+    void set(float x, float y, float z);
+
+    void set(const Vector3f& v);
+
+    double length() const;
+
+    double distance(const Vector3f& v) const;
+
+    double distance(float x, float y, float z) const;
+
+    double distanceSquare(const Vector3f& v) const;
+
+    double distanceSquare(float x, float y, float z) const;
+
+    double dot(const Vector3f& v) const;
+
+    Vector3f cross(const Vector3f& v) const;
+
+    Vector3f normalize() const;
+
+    Vector3f scale(const Vector3f& scale) const;
+
+    Vector3f scale(double scale) const;
+
+    bool operator==(const Vector3f& v) const;
+
+    bool operator!=(const Vector3f& v) const;
+
+    Vector3f operator-() const;
+
+    // scalar ops
+    Vector3f operator+(double scalar) const;
+    Vector3f operator-(double scalar) const;
+    Vector3f operator*(double scalar) const;
+    Vector3f operator/(double scalar) const;
+    Vector3f& operator*=(double scalar);
+
+    // vector ops
+    Vector3f operator+(const Vector3f& op2) const;
+    Vector3f operator-(const Vector3f& op2) const;
+    Vector3f& operator+=(const Vector3f& op2);
+    Vector3f& operator-=(const Vector3f& op2);
+
+    bool isEqual(const Vector3f& v) const;
+    bool isAlmostEqual(const Vector3f& v, float tol) const;
+
+    float getX() const;
+    float getY() const;
+    float getZ() const;
+
+    //friend Vector3f operator*(float scale, const Vector3f& value);
+
+    union {
+        struct {
+            float x, y, z;
+        };
+        struct {
+            float r, g, b;
+        };
+    };
+};
+
+inline bool Vector3f::operator==(const Vector3f &v) const 
+{
+    return (v.x == x && v.y == y && v.z == z);
+}
+
+inline bool Vector3f::operator!=(const Vector3f &v) const 
+{
+    return !(v.x == x && v.y == y && v.z == z);
+}
+
+inline Vector3f Vector3f::operator-() const
+{
+    return Vector3f(-x, -y, -z);
+}
+
+inline Vector3f Vector3f::operator+(double scalar) const
+{
+    return Vector3f(x + scalar, y + scalar, z + scalar);
+}
+
+inline Vector3f Vector3f::operator-(double scalar) const
+{
+    return Vector3f(x - scalar, y - scalar, z - scalar);
+}
+
+inline Vector3f Vector3f::operator*(double scalar) const
+{
+    return Vector3f(x * scalar, y * scalar, z * scalar);
+}
+
+inline Vector3f Vector3f::operator/(double scalar) const
+{
+    return Vector3f(x / scalar, y / scalar, z / scalar);
+}
+
+inline Vector3f& Vector3f::operator*=(double scalar)
+{
+    x *= scalar;
+    y *= scalar;
+    z *= scalar;
+    return *this;
+}
+
+inline Vector3f Vector3f::operator+(const Vector3f& op2) const
+{
+    return Vector3f(x + op2.x, y + op2.y, z + op2.z);
+}
+
+inline Vector3f Vector3f::operator-(const Vector3f& op2) const
+{
+    return Vector3f(x - op2.x, y - op2.y, z - op2.z);
+}
+
+inline Vector3f& Vector3f::operator+=(const Vector3f& op2)
+{
+    x += op2.x;
+    y += op2.y;
+    z += op2.z;
+    return *this;
+}
+
+inline Vector3f& Vector3f::operator-=(const Vector3f& op2)
+{
+    x -= op2.x;
+    y -= op2.y;
+    z -= op2.z;
+    return *this;
+}
+
+#if 0
+inline Vector3f operator*(double scale, const Vector3f& value)
+{
+    return Vector3f(value.x * scale, value.y * scale, value.z * scale);
+}
+#endif
+
+inline void Vector3f::set(float x, float y, float z)
+{
+    this->x = x;
+    this->y = y;
+    this->z = z;
+}
+
+inline void Vector3f::set(const Vector3f& v)
+{
+    x = v.x;
+    y = v.y;
+    z = v.z;
+}
+
+inline double Vector3f::dot(const Vector3f& v) const
+{
+    return ((double)x * v.x + (double)y * v.y + (double)z * v.z);
+}
+
+inline double Vector3f::length() const
+{
+    return sqrt((double)x * x + (double)y * y + (double)z * z);
+}
+
+inline double Vector3f::distance(const Vector3f& v) const
+{
+    double x1 = ((double)v.x - (double)x) , y1 = ((double)v.y - (double)y), z1 = ((double)v.z - (double)z);
+    return sqrt(x1 * x1 + y1 * y1 + z1 * z1);
+}
+
+inline double Vector3f::distance(float x, float y, float z) const
+{	
+    double x1 = ((double)x - (double)this->x) , y1 = ((double)y - (double)this->y), z1 = ((double)z - (double)this->z);
+    return sqrt(x1 * x1 + y1 * y1 + z1 * z1);
+}
+
+inline double Vector3f::distanceSquare(const Vector3f& v) const
+{	
+    double x1 = ((double)v.x - (double)x) , y1 = ((double)v.y - (double)y), z1 = ((double)v.z - (double)z);
+    return (x1 * x1 + y1 * y1 + z1 * z1);
+}
+
+inline double Vector3f::distanceSquare(float x, float y, float z) const
+{	
+    double x1 = ((double)x - (double)this->x) , y1 = ((double)y - (double)this->y), z1 = ((double)z - (double)this->z);
+    return (x1 * x1 + y1 * y1 + z1 * z1);
+}
+
+inline Vector3f Vector3f::cross(const Vector3f& op2) const
+{
+    return Vector3f(y * op2.z - z * op2.y,
+                    z * op2.x - x * op2.z,
+                    x * op2.y - y * op2.x);
+}
+
+inline Vector3f Vector3f::normalize() const
+{
+    double len = length();
+    if (len > 0.0) {
+        return Vector3f(x / len, y / len, z / len);
+    } else {
+        return *this;
+    }
+}
+
+inline Vector3f Vector3f::scale(double scale) const
+{
+    return Vector3f(x * scale, y * scale, z * scale);
+}
+
+inline Vector3f Vector3f::scale(const Vector3f& scale) const
+{
+    return Vector3f(x * scale.x, y * scale.y, z * scale.z);
+}
+
+inline bool Vector3f::isAlmostEqual(const Vector3f& v, float tol) const
+{
+    return (v.x - tol) <= x && x <= (v.x + tol) &&
+        (v.y - tol) <= y && y <= (v.y + tol) &&
+        (v.z - tol) <= z && z <= (v.z + tol);
+}
+
+inline bool Vector3f::isEqual(const Vector3f& v) const
+{
+    return ( v.x == x && v.y == y && v.z == z );
+}
+
+inline float Vector3f::getX() const
+{
+    return x;
+}
+
+inline float Vector3f::getY() const
+{
+    return y;
+}
+
+inline float Vector3f::getZ() const
+{
+    return z;
+}
+
+inline Vector3f cross(const Vector3f& op1, const Vector3f& op2)
+{
+    return Vector3f(op1.cross(op2));
+}
+
+/**
+ * \brief Linear interpolation of 2 vectors
+ */
+inline Vector3f vlerp(const Vector3f& v1, const Vector3f& v2, double t)
+{
+    return Vector3f(v1.x * (1.0-t) + v2.x * t,
+                    v1.y * (1.0-t) + v2.y * t,
+                    v1.z * (1.0-t) + v2.z * t);
+}
+
+}
+
+#endif
Index: /nanovis/tags/1.1.4/vrmath/include/vrmath/Vector4f.h
===================================================================
--- /nanovis/tags/1.1.4/vrmath/include/vrmath/Vector4f.h	(revision 4930)
+++ /nanovis/tags/1.1.4/vrmath/include/vrmath/Vector4f.h	(revision 4930)
@@ -0,0 +1,199 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Author: Insoo Woo <iwoo@purdue.edu>
+ */
+#ifndef VRVECTOR4F_H
+#define VRVECTOR4F_H
+
+#include <vrmath/Vector3f.h>
+#include <vrmath/Vector4f.h>
+
+namespace vrmath {
+
+class Vector4f
+{
+public:
+    Vector4f() :
+        x(0.0f), y(0.0f), z(0.0f), w(0.0f)
+    {}
+
+    Vector4f(const Vector4f& other) :
+        x(other.x), y(other.y), z(other.z), w(other.w)
+    {}
+
+    Vector4f(const Vector3f& v, float w1) :
+        x(v.x), y(v.y), z(v.z), w(w1)
+    {}
+
+    Vector4f(float x1, float y1, float z1, float w1) :
+        x(x1), y(y1), z(z1), w(w1)
+    {}
+
+    void set(float x, float y, float z, float w);
+ 
+    void set(const Vector3f& v, float w);
+
+    void set(const Vector4f& v);
+
+    Vector4f& operator=(const Vector4f& other)
+    {
+        if (&other != this) {
+            set(other.x, other.y, other.z, other.w);
+        }
+        return *this;
+    }
+
+    bool operator==(const Vector4f& op2) const
+    {
+        return (x == op2.x && y == op2.y && z == op2.z && w == op2.w);
+    }
+
+    Vector4f operator+(const Vector4f& op2) const
+    {
+        return Vector4f(x + op2.x, y + op2.y, z + op2.z, w + op2.w);
+    }
+
+    Vector4f operator-(const Vector4f& op2) const
+    {
+        return Vector4f(x - op2.x, y - op2.y, z - op2.z, w - op2.w);
+    }
+
+    float operator*(const Vector4f& op2) const
+    {
+        return (x * op2.x) + (y * op2.y) + (z * op2.z) + (w * op2.w);
+    }
+
+    Vector4f operator*(double op2) const
+    {
+        return Vector4f(x * op2, y * op2, z * op2, w * op2);
+    }
+
+    Vector4f operator/(double op2) const
+    {
+        return Vector4f(x / op2, y / op2, z / op2, w / op2);
+    }
+
+    void divideByW();
+
+    double dot(const Vector4f& vec) const;
+
+    union {
+        struct {
+            float x, y, z, w;
+        };
+        struct {
+            float r, g, b, a;
+        };
+    };
+};
+
+inline void Vector4f::divideByW()
+{
+    if (w != 0) {
+        x /= w; y /= w; z /= w;
+        w = 1.0f;
+    }
+}
+
+inline void Vector4f::set(float x, float y, float z, float w)
+{
+    this->x = x;
+    this->y = y;
+    this->z = z;
+    this->w = w;
+}
+
+inline void Vector4f::set(const Vector4f& v)
+{
+    x = v.x;
+    y = v.y;
+    z = v.z;
+    w = v.w;
+}
+
+inline void Vector4f::set(const Vector3f& v, float w)
+{
+    x = v.x;
+    y = v.y;
+    z = v.z;
+    this->w = w;
+}
+
+inline double Vector4f::dot(const Vector4f& v) const
+{
+    return ((double)x * v.x + (double)y * v.y + (double)z * v.z + (double)w * v.w);
+}
+
+/**
+ * \brief Linear interpolation of 2 points
+ */
+inline Vector4f vlerp(const Vector4f& v1, const Vector4f& v2, double t)
+{
+    return Vector4f(v1.x * (1.0-t) + v2.x * t,
+                    v1.y * (1.0-t) + v2.y * t,
+                    v1.z * (1.0-t) + v2.z * t,
+                    v1.w * (1.0-t) + v2.w * t);
+}
+
+/**
+ * \brief Finds the intersection of a line through 
+ * p1 and p2 with the given plane.
+ *
+ * If the line lies in the plane, an arbitrary 
+ * point on the line is returned.
+ *
+ * Reference:
+ * http://astronomy.swin.edu.au/pbourke/geometry/planeline/
+ *
+ * \param[in] pt1 First point
+ * \param[in] pt2 Second point
+ * \param[in] plane Plane equation coefficients
+ * \param[out] ret Point of intersection if a solution was found
+ * \return Bool indicating if an intersection was found
+ */
+inline bool 
+planeLineIntersection(const Vector4f& pt1, const Vector4f& pt2,
+                      const Vector4f& plane, Vector4f& ret)
+{
+    float a = plane.x;
+    float b = plane.y;
+    float c = plane.z;
+    float d = plane.w;
+
+    Vector4f p1 = pt1;
+    float x1 = p1.x;
+    float y1 = p1.y;
+    float z1 = p1.z;
+
+    Vector4f p2 = pt2;
+    float x2 = p2.x;
+    float y2 = p2.y;
+    float z2 = p2.z;
+
+    float uDenom = a * (x1 - x2) + b * (y1 - y2) + c * (z1 - z2);
+    float uNumer = a * x1 + b * y1 + c * z1 + d;
+
+    if (uDenom == 0.0f) {
+        // Plane parallel to line
+        if (uNumer == 0.0f) {
+            // Line within plane
+            ret = p1;
+            return true;
+        }
+        // No solution
+        return false;
+    }
+
+    float u = uNumer / uDenom;
+    ret.x = x1 + u * (x2 - x1);
+    ret.y = y1 + u * (y2 - y1);
+    ret.z = z1 + u * (z2 - z1);
+    ret.w = 1;
+    return true;
+}
+
+}
+
+#endif
