Ignore:
Timestamp:
Mar 24, 2013, 10:23:25 PM (12 years ago)
Author:
ldelgass
Message:

Refactor and cleanups in nanovis, mainly to switch to using STL hash tables
(TR1 required) instead of Tcl hash tables, split out Flow particles and boxes
to separate implementation files. The goal is to achieve better separation of
Tcl command parsing and the core graphics rendering objects and code.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/packages/vizservers/nanovis/FlowCmd.cpp

    r3566 r3567  
    2424
    2525#include <vrmath/Vector3f.h>
    26 #include <vrmath/Vector4f.h>
    27 #include <vrmath/Matrix4x4d.h>
    2826
    2927#include "nvconf.h"
    3028
    3129#include "nanovis.h"
     30#include "CmdProc.h"
    3231#include "FlowCmd.h"
    33 #include "CmdProc.h"
     32#include "FlowTypes.h"
     33#include "FlowBox.h"
     34#include "FlowParticles.h"
    3435#include "Switch.h"
    3536#include "TransferFunction.h"
     
    3940#include "VelocityArrowsSlice.h"
    4041#include "Volume.h"
    41 
    42 #define RELPOS 0
    43 #define ABSPOS 1
    4442
    4543using namespace vrmath;
     
    9694     offsetof(FlowValues, specular), 0},
    9795    {Rappture::SWITCH_CUSTOM, "-transferfunction", "name",
    98      offsetof(FlowValues, tfPtr), 0, 0, &transferFunctionSwitch},
     96     offsetof(FlowValues, transferFunction), 0, 0, &transferFunctionSwitch},
    9997    {Rappture::SWITCH_BOOLEAN, "-volume", "boolean",
    10098     offsetof(FlowValues, showVolume), 0},
     
    133131static Tcl_CmdDeleteProc FlowInstDeleteProc;
    134132
    135 FlowParticles::FlowParticles(const char *name, Tcl_HashEntry *hPtr) :
     133FlowCmd::FlowCmd(Tcl_Interp *interp, const char *name) :
     134    _interp(interp),
    136135    _name(name),
    137     _hashPtr(hPtr),
    138     _rendererPtr(new NvParticleRenderer(NMESH, NMESH))
    139 {
    140     _sv.position.value = 0.0f;
    141     _sv.position.flags = RELPOS;
    142     _sv.position.axis = 0; // X_AXIS
    143     _sv.color.r = _sv.color.g = _sv.color.b = _sv.color.a = 1.0f;
    144     _sv.isHidden = false;
    145     _sv.particleSize = 1.2;
    146 }
    147 
    148 FlowParticles::~FlowParticles()
    149 {
    150     if (_rendererPtr != NULL) {
    151         delete _rendererPtr;
    152     }
    153     if (_hashPtr != NULL) {
    154         Tcl_DeleteHashEntry(_hashPtr);
    155     }
    156     Rappture::FreeSwitches(_switches, &_sv, 0);
    157 }
    158 
    159 void
    160 FlowParticles::render()
    161 {
    162     TRACE("Particles '%s' axis: %d pos: %g rel pos: %g",
    163           _name, _sv.position.axis, _sv.position.value,
    164           FlowCmd::getRelativePosition(&_sv.position));
    165     _rendererPtr->setPos(FlowCmd::getRelativePosition(&_sv.position));
    166     _rendererPtr->setAxis(_sv.position.axis);
    167     assert(_rendererPtr->active());
    168     _rendererPtr->render();
    169 }
    170 
    171 void
    172 FlowParticles::configure()
    173 {
    174     _rendererPtr->setPos(FlowCmd::getRelativePosition(&_sv.position));
    175     _rendererPtr->setColor(Vector4f(_sv.color.r, _sv.color.g, _sv.color.b,
    176                                     _sv.color.a));
    177     _rendererPtr->particleSize(_sv.particleSize);
    178     _rendererPtr->setAxis(_sv.position.axis);
    179     _rendererPtr->active(!_sv.isHidden);
    180 }
    181 
    182 FlowBox::FlowBox(const char *name, Tcl_HashEntry *hPtr)
    183 {
    184     _name = name;
    185     _hashPtr = hPtr;
    186     _sv.isHidden = false;
    187     _sv.corner1.x = 0.0f;
    188     _sv.corner1.y = 0.0f;
    189     _sv.corner1.z = 0.0f;
    190     _sv.corner2.x = 1.0f;
    191     _sv.corner2.y = 1.0f;
    192     _sv.corner2.z = 1.0f;
    193     _sv.lineWidth = 1.2f;
    194     _sv.color.r = _sv.color.b = _sv.color.g = _sv.color.a = 1.0f;
    195 }
    196 
    197 void
    198 FlowBox::getWorldSpaceBounds(Vector3f& bboxMin,
    199                              Vector3f& bboxMax,
    200                              const Volume *vol) const
    201 {
    202     bboxMin.set(FLT_MAX, FLT_MAX, FLT_MAX);
    203     bboxMax.set(-FLT_MAX, -FLT_MAX, -FLT_MAX);
    204 
    205     Vector3f origin = vol->location();
    206     Vector3f scale = vol->getPhysicalScaling();
    207 
    208     Matrix4x4d mat;
    209     mat.makeTranslation(origin);
    210     Matrix4x4d mat2;
    211     mat2.makeScale(scale);
    212 
    213     mat.multiply(mat2);
    214 
    215     Vector3f min, max;
    216     min.x = vol->xAxis.min();
    217     min.y = vol->yAxis.min();
    218     min.z = vol->zAxis.min();
    219     max.x = vol->xAxis.max();
    220     max.y = vol->yAxis.max();
    221     max.z = vol->zAxis.max();
    222 
    223     float x0, y0, z0, x1, y1, z1;
    224     x0 = y0 = z0 = 0.0f;
    225     x1 = y1 = z1 = 0.0f;
    226     if (max.x > min.x) {
    227         x0 = (_sv.corner1.x - min.x) / (max.x - min.x);
    228         x1 = (_sv.corner2.x - min.x) / (max.x - min.x);
    229     }
    230     if (max.y > min.y) {
    231         y0 = (_sv.corner1.y - min.y) / (max.y - min.y);
    232         y1 = (_sv.corner2.y - min.y) / (max.y - min.y);
    233     }
    234     if (max.z > min.z) {
    235         z0 = (_sv.corner1.z - min.z) / (max.z - min.z);
    236         z1 = (_sv.corner2.z - min.z) / (max.z - min.z);
    237     }
    238 
    239     TRACE("Box model bounds: (%g,%g,%g) - (%g,%g,%g)",
    240           x0, y0, z0, x1, y1, z1);
    241 
    242     Vector3f modelMin(x0, y0, z0);
    243     Vector3f modelMax(x1, y1, z1);
    244 
    245     Vector4f bvert[8];
    246     bvert[0] = Vector4f(modelMin.x, modelMin.y, modelMin.z, 1);
    247     bvert[1] = Vector4f(modelMax.x, modelMin.y, modelMin.z, 1);
    248     bvert[2] = Vector4f(modelMin.x, modelMax.y, modelMin.z, 1);
    249     bvert[3] = Vector4f(modelMin.x, modelMin.y, modelMax.z, 1);
    250     bvert[4] = Vector4f(modelMax.x, modelMax.y, modelMin.z, 1);
    251     bvert[5] = Vector4f(modelMax.x, modelMin.y, modelMax.z, 1);
    252     bvert[6] = Vector4f(modelMin.x, modelMax.y, modelMax.z, 1);
    253     bvert[7] = Vector4f(modelMax.x, modelMax.y, modelMax.z, 1);
    254 
    255     for (int i = 0; i < 8; i++) {
    256         Vector4f worldVert = mat.transform(bvert[i]);
    257         if (worldVert.x < bboxMin.x) bboxMin.x = worldVert.x;
    258         if (worldVert.x > bboxMax.x) bboxMax.x = worldVert.x;
    259         if (worldVert.y < bboxMin.y) bboxMin.y = worldVert.y;
    260         if (worldVert.y > bboxMax.y) bboxMax.y = worldVert.y;
    261         if (worldVert.z < bboxMin.z) bboxMin.z = worldVert.z;
    262         if (worldVert.z > bboxMax.z) bboxMax.z = worldVert.z;
    263     }
    264 
    265     TRACE("Box world bounds: (%g,%g,%g) - (%g,%g,%g)",
    266           bboxMin.x, bboxMin.y, bboxMin.z,
    267           bboxMax.x, bboxMax.y, bboxMax.z);
    268 }
    269 
    270 void
    271 FlowBox::render(Volume *vol)
    272 {
    273     TRACE("Box: '%s'", _name);
    274 
    275     glPushAttrib(GL_ENABLE_BIT);
    276 
    277     glEnable(GL_DEPTH_TEST);
    278     glDisable(GL_TEXTURE_2D);
    279     glDisable(GL_BLEND);
    280 
    281     glMatrixMode(GL_MODELVIEW);
    282     glPushMatrix();
    283 
    284     Vector3f origin = vol->location();
    285     glTranslatef(origin.x, origin.y, origin.z);
    286 
    287     Vector3f scale = vol->getPhysicalScaling();
    288     glScalef(scale.x, scale.y, scale.z);
    289 
    290     Vector3f min, max;
    291     min.x = vol->xAxis.min();
    292     min.y = vol->yAxis.min();
    293     min.z = vol->zAxis.min();
    294     max.x = vol->xAxis.max();
    295     max.y = vol->yAxis.max();
    296     max.z = vol->zAxis.max();
    297 
    298     TRACE("box is %g,%g %g,%g %g,%g",
    299           _sv.corner1.x, _sv.corner2.x,
    300           _sv.corner1.y, _sv.corner2.y,
    301           _sv.corner1.z, _sv.corner2.z);
    302     TRACE("world is %g,%g %g,%g %g,%g",
    303           min.x, max.x, min.y, max.y, min.z, max.z);
    304 
    305     float x0, y0, z0, x1, y1, z1;
    306     x0 = y0 = z0 = 0.0f;
    307     x1 = y1 = z1 = 0.0f;
    308     if (max.x > min.x) {
    309         x0 = (_sv.corner1.x - min.x) / (max.x - min.x);
    310         x1 = (_sv.corner2.x - min.x) / (max.x - min.x);
    311     }
    312     if (max.y > min.y) {
    313         y0 = (_sv.corner1.y - min.y) / (max.y - min.y);
    314         y1 = (_sv.corner2.y - min.y) / (max.y - min.y);
    315     }
    316     if (max.z > min.z) {
    317         z0 = (_sv.corner1.z - min.z) / (max.z - min.z);
    318         z1 = (_sv.corner2.z - min.z) / (max.z - min.z);
    319     }
    320     TRACE("box bounds: %g,%g %g,%g %g,%g",
    321           x0, x1, y0, y1, z0, z1);
    322 
    323     glColor4d(_sv.color.r, _sv.color.g, _sv.color.b, _sv.color.a);
    324     glLineWidth(_sv.lineWidth);
    325     glBegin(GL_LINE_LOOP);
    326     {
    327         glVertex3d(x0, y0, z0);
    328         glVertex3d(x1, y0, z0);
    329         glVertex3d(x1, y1, z0);
    330         glVertex3d(x0, y1, z0);
    331     }
    332     glEnd();
    333     glBegin(GL_LINE_LOOP);
    334     {
    335         glVertex3d(x0, y0, z1);
    336         glVertex3d(x1, y0, z1);
    337         glVertex3d(x1, y1, z1);
    338         glVertex3d(x0, y1, z1);
    339     }
    340     glEnd();
    341    
    342     glBegin(GL_LINE_LOOP);
    343     {
    344         glVertex3d(x0, y0, z0);
    345         glVertex3d(x0, y0, z1);
    346         glVertex3d(x0, y1, z1);
    347         glVertex3d(x0, y1, z0);
    348     }
    349     glEnd();
    350    
    351     glBegin(GL_LINE_LOOP);
    352     {
    353         glVertex3d(x1, y0, z0);
    354         glVertex3d(x1, y0, z1);
    355         glVertex3d(x1, y1, z1);
    356         glVertex3d(x1, y1, z0);
    357     }
    358     glEnd();
    359 
    360     glPopMatrix();
    361     glPopAttrib();
    362 
    363     assert(CheckGL(AT));
    364 }
    365 
    366 FlowCmd::FlowCmd(Tcl_Interp *interp, const char *name, Tcl_HashEntry *hPtr) :
    367     _interp(interp),
    368     _hashPtr(hPtr),
    369     _name(name),
    370     _dataPtr(NULL),
    371     _volPtr(NULL),
    372     _fieldPtr(NULL)
     136    _data(NULL),
     137    _volume(NULL),
     138    _field(NULL)
    373139{
    374140    memset(&_sv, 0, sizeof(FlowValues));
    375141    _sv.sliceVisible = 1;
    376     _sv.tfPtr = NanoVis::getTransfunc("default");
    377 
    378     Tcl_InitHashTable(&_particlesTable, TCL_STRING_KEYS);
    379     Tcl_InitHashTable(&_boxTable, TCL_STRING_KEYS);
    380 
    381     _cmdToken = Tcl_CreateObjCommand(_interp, (char *)_name,
     142    _sv.transferFunction = NanoVis::getTransferFunction("default");
     143
     144    _cmdToken = Tcl_CreateObjCommand(_interp, (char *)name,
    382145                                     (Tcl_ObjCmdProc *)FlowInstObjCmd,
    383146                                     this, FlowInstDeleteProc);
     
    386149FlowCmd::~FlowCmd()
    387150{
     151    TRACE("Enter");
     152
    388153    Rappture::FreeSwitches(_switches, &_sv, 0);
    389     if (_hashPtr != NULL) {
    390         Tcl_DeleteHashEntry(_hashPtr);
    391     }
    392     if (_fieldPtr != NULL) {
    393         delete _fieldPtr;
    394     }
    395     if (_dataPtr != NULL) {
    396         delete _dataPtr;
    397     }
    398     if (_volPtr != NULL) {
    399         NanoVis::removeVolume(_volPtr);
    400         _volPtr = NULL;
    401     }
    402 
    403     FlowBox *boxPtr;
    404     FlowBoxIterator boxIter;
    405     for (boxPtr = firstBox(&boxIter); boxPtr != NULL;
    406          boxPtr = nextBox(&boxIter)) {
    407         boxPtr->disconnect();
    408         delete boxPtr;
    409     }
    410     FlowParticles *particlesPtr;
    411     FlowParticlesIterator partIter;
    412     for (particlesPtr = firstParticles(&partIter); particlesPtr != NULL;
    413          particlesPtr = nextParticles(&partIter)) {
    414         particlesPtr->disconnect();
    415         delete particlesPtr;
    416     }
    417     Tcl_DeleteHashTable(&_particlesTable);
    418     Tcl_DeleteHashTable(&_boxTable);
     154    if (_field != NULL) {
     155        delete _field;
     156    }
     157    if (_data != NULL) {
     158        delete _data;
     159    }
     160    if (_volume != NULL) {
     161        NanoVis::removeVolume(_volume);
     162        _volume = NULL;
     163    }
     164    for (BoxHashmap::iterator itr = _boxTable.begin();
     165         itr != _boxTable.end(); ++itr) {
     166        delete itr->second;
     167    }
     168    _boxTable.clear();
     169    for (ParticlesHashmap::iterator itr = _particlesTable.begin();
     170         itr != _particlesTable.end(); ++itr) {
     171        delete itr->second;
     172    }
     173    _particlesTable.clear();
     174}
     175
     176void
     177FlowCmd::getBounds(Vector3f& min,
     178                   Vector3f& max,
     179                   bool onlyVisible)
     180{
     181    TRACE("Enter");
     182
     183    if (onlyVisible && !visible())
     184        return;
     185
     186#if 0  // Using volume bounds instead of these
     187    if (isDataLoaded()) {
     188        Vector3f umin, umax;
     189        Rappture::Unirect3d *unirect = data();
     190        unirect->getWorldSpaceBounds(umin, umax);
     191        if (min.x > umin.x) {
     192            min.x = umin.x;
     193        }
     194        if (max.x < umax.x) {
     195            max.x = umax.x;
     196        }
     197        if (min.y > umin.y) {
     198            min.y = umin.y;
     199        }
     200        if (max.y < umax.y) {
     201            max.y = umax.y;
     202        }
     203        if (min.z > umin.z) {
     204            min.z = umin.z;
     205        }
     206        if (max.z < umax.z) {
     207            max.z = umax.z;
     208        }
     209    }
     210#endif
     211    for (BoxHashmap::iterator itr = _boxTable.begin();
     212         itr != _boxTable.end(); ++itr) {
     213        FlowBox *box = itr->second;
     214        if (!onlyVisible || box->visible()) {
     215            Vector3f fbmin, fbmax;
     216            box->getWorldSpaceBounds(fbmin, fbmax,
     217                                     getVolume());
     218            if (min.x > fbmin.x) {
     219                min.x = fbmin.x;
     220            }
     221            if (max.x < fbmax.x) {
     222                max.x = fbmax.x;
     223            }
     224            if (min.y > fbmin.y) {
     225                min.y = fbmin.y;
     226            }
     227            if (max.y < fbmax.y) {
     228                max.y = fbmax.y;
     229            }
     230            if (min.z > fbmin.z) {
     231                min.z = fbmin.z;
     232            }
     233            if (max.z < fbmax.z) {
     234                max.z = fbmax.z;
     235            }
     236        }
     237    }
    419238}
    420239
     
    422241FlowCmd::resetParticles()
    423242{
    424     FlowParticlesIterator iter;
    425     for (FlowParticles *particlesPtr = firstParticles(&iter);
    426          particlesPtr != NULL;
    427          particlesPtr = nextParticles(&iter)) {
    428         particlesPtr->reset();
     243    for (ParticlesHashmap::iterator itr = _particlesTable.begin();
     244         itr != _particlesTable.end(); ++itr) {
     245        itr->second->reset();
    429246    }
    430247}
     
    435252    NvVectorField *fieldPtr = getVectorField();
    436253    fieldPtr->active(true);
    437     FlowParticlesIterator iter;
    438     for (FlowParticles *particlesPtr = firstParticles(&iter);
    439          particlesPtr != NULL;
    440          particlesPtr = nextParticles(&iter)) {
    441         if (particlesPtr->visible()) {
    442             particlesPtr->advect();
     254    for (ParticlesHashmap::iterator itr = _particlesTable.begin();
     255         itr != _particlesTable.end(); ++itr) {
     256        if (itr->second->visible()) {
     257            itr->second->advect();
    443258        }
    444259    }
     
    448263FlowCmd::render()
    449264{
    450     _fieldPtr->active(true);
    451     _fieldPtr->render();
    452     FlowParticlesIterator iter;
    453     for (FlowParticles *particlesPtr = firstParticles(&iter);
    454          particlesPtr != NULL;
    455          particlesPtr = nextParticles(&iter)) {
    456         if (particlesPtr->visible()) {
    457             particlesPtr->render();
     265    _field->active(true);
     266    _field->render();
     267    for (ParticlesHashmap::iterator itr = _particlesTable.begin();
     268         itr != _particlesTable.end(); ++itr) {
     269        if (itr->second->visible()) {
     270            itr->second->render();
    458271        }
    459272    }
     
    461274}
    462275
    463 int
    464 FlowCmd::createParticles(Tcl_Interp *interp, Tcl_Obj *objPtr)
    465 {
    466     Tcl_HashEntry *hPtr;
    467     int isNew;
    468     const char *particlesName = Tcl_GetString(objPtr);
    469     hPtr = Tcl_CreateHashEntry(&_particlesTable, particlesName, &isNew);
    470     if (!isNew) {
    471         Tcl_AppendResult(interp, "particle injection plane \"",
    472                          particlesName, "\" already exists.", (char *)NULL);
    473         return TCL_ERROR;
    474     }
    475     particlesName = Tcl_GetHashKey(&_particlesTable, hPtr);
    476     FlowParticles *particlesPtr;
    477     particlesPtr = new FlowParticles(particlesName, hPtr);
    478     if (particlesPtr == NULL) {
    479         Tcl_AppendResult(interp, "can't allocate particle injection plane",
    480                          (char *)NULL);
    481         Tcl_DeleteHashEntry(hPtr);
    482         return TCL_ERROR;
    483     }
    484     Tcl_SetHashValue(hPtr, particlesPtr);
    485     return TCL_OK;
    486 }
    487 
    488 int
    489 FlowCmd::getParticles(Tcl_Interp *interp, Tcl_Obj *objPtr,
    490                       FlowParticles **particlesPtrPtr)
    491 {
    492     Tcl_HashEntry *hPtr;
    493     hPtr = Tcl_FindHashEntry(&_particlesTable, Tcl_GetString(objPtr));
    494     if (hPtr == NULL) {
    495         if (interp != NULL) {
    496             Tcl_AppendResult(interp, "can't find a particle injection plane \"",
    497                              Tcl_GetString(objPtr), "\"", (char *)NULL);
    498         }
    499         return TCL_ERROR;
    500     }
    501     *particlesPtrPtr = (FlowParticles *)Tcl_GetHashValue(hPtr);
    502     return TCL_OK;
    503 }
    504 
    505276FlowParticles *
    506 FlowCmd::firstParticles(FlowParticlesIterator *iterPtr)
    507 {
    508     iterPtr->hashPtr = Tcl_FirstHashEntry(&_particlesTable,
    509                                           &iterPtr->hashSearch);
    510     if (iterPtr->hashPtr == NULL) {
     277FlowCmd::createParticles(const char *particlesName)
     278{
     279    ParticlesHashmap::iterator itr = _particlesTable.find(particlesName);
     280    if (itr != _particlesTable.end()) {
     281        TRACE("Deleting existing particle injection plane '%s'", particlesName);
     282        delete itr->second;
     283        _particlesTable.erase(itr);
     284    }
     285    FlowParticles *particles = new FlowParticles(particlesName);
     286    _particlesTable[particlesName] = particles;
     287    return particles;
     288}
     289
     290FlowParticles *
     291FlowCmd::getParticles(const char *particlesName)
     292{
     293    ParticlesHashmap::iterator itr;
     294    itr = _particlesTable.find(particlesName);
     295    if (itr == _particlesTable.end()) {
     296        TRACE("Can't find particle injection plane '%s' in '%s'", particlesName, name());
    511297        return NULL;
    512298    }
    513     return (FlowParticles *)Tcl_GetHashValue(iterPtr->hashPtr);
    514 }
    515 
    516 FlowParticles *
    517 FlowCmd::nextParticles(FlowParticlesIterator *iterPtr)
    518 {
    519     if (iterPtr->hashPtr == NULL) {
     299    return itr->second;
     300}
     301
     302void
     303FlowCmd::deleteParticles(const char *particlesName)
     304{
     305    ParticlesHashmap::iterator itr = _particlesTable.find(particlesName);
     306    if (itr == _particlesTable.end()) {
     307        TRACE("Can't find particle injection plane '%s' in '%s'", particlesName, name());
     308        return;
     309    }
     310    delete itr->second;
     311    _particlesTable.erase(itr);
     312}
     313
     314void
     315FlowCmd::getParticlesNames(std::vector<std::string>& names)
     316{
     317    for (ParticlesHashmap::iterator itr = _particlesTable.begin();
     318         itr != _particlesTable.end(); ++itr) {
     319        names.push_back(std::string(itr->second->name()));
     320    }
     321}
     322
     323FlowBox *
     324FlowCmd::createBox(const char *boxName)
     325{
     326    BoxHashmap::iterator itr = _boxTable.find(boxName);
     327    if (itr != _boxTable.end()) {
     328        TRACE("Deleting existing box '%s'", boxName);
     329        delete itr->second;
     330        _boxTable.erase(itr);
     331    }
     332    FlowBox *box = new FlowBox(boxName);
     333    _boxTable[boxName] = box;
     334    return box;
     335}
     336
     337FlowBox *
     338FlowCmd::getBox(const char *boxName)
     339{
     340    BoxHashmap::iterator itr = _boxTable.find(boxName);
     341    if (itr == _boxTable.end()) {
     342        TRACE("Can't find box '%s' in '%s'", boxName, name());
    520343        return NULL;
    521344    }
    522     iterPtr->hashPtr = Tcl_NextHashEntry(&iterPtr->hashSearch);
    523     if (iterPtr->hashPtr == NULL) {
    524         return NULL;
    525     }
    526     return (FlowParticles *)Tcl_GetHashValue(iterPtr->hashPtr);
    527 }
    528 
    529 int
    530 FlowCmd::createBox(Tcl_Interp *interp, Tcl_Obj *objPtr)
    531 {
    532     Tcl_HashEntry *hPtr;
    533     int isNew;
    534     hPtr = Tcl_CreateHashEntry(&_boxTable, Tcl_GetString(objPtr), &isNew);
    535     if (!isNew) {
    536         Tcl_AppendResult(interp, "box \"", Tcl_GetString(objPtr),
    537                          "\" already exists in flow \"", name(), "\"", (char *)NULL);
    538         return TCL_ERROR;
    539     }
    540     const char *boxName;
    541     boxName = Tcl_GetHashKey(&_boxTable, hPtr);
    542     FlowBox *boxPtr;
    543     boxPtr = new FlowBox(boxName, hPtr);
    544     if (boxPtr == NULL) {
    545         Tcl_AppendResult(interp, "can't allocate box \"", boxName, "\"",
    546                          (char *)NULL);
    547         Tcl_DeleteHashEntry(hPtr);
    548         return TCL_ERROR;
    549     }
    550     Tcl_SetHashValue(hPtr, boxPtr);
    551     return TCL_OK;
    552 }
    553 
    554 int
    555 FlowCmd::getBox(Tcl_Interp *interp, Tcl_Obj *objPtr, FlowBox **boxPtrPtr)
    556 {
    557     Tcl_HashEntry *hPtr;
    558     hPtr = Tcl_FindHashEntry(&_boxTable, Tcl_GetString(objPtr));
    559     if (hPtr == NULL) {
    560         if (interp != NULL) {
    561             Tcl_AppendResult(interp, "can't find a box \"",
    562                              Tcl_GetString(objPtr), "\" in flow \"", name(), "\"",
    563                              (char *)NULL);
    564         }
    565         return TCL_ERROR;
    566     }
    567     *boxPtrPtr = (FlowBox *)Tcl_GetHashValue(hPtr);
    568     return TCL_OK;
    569 }
    570 
    571 FlowBox *
    572 FlowCmd::firstBox(FlowBoxIterator *iterPtr)
    573 {
    574     iterPtr->hashPtr = Tcl_FirstHashEntry(&_boxTable, &iterPtr->hashSearch);
    575     if (iterPtr->hashPtr == NULL) {
    576         return NULL;
    577     }
    578     return (FlowBox *)Tcl_GetHashValue(iterPtr->hashPtr);
    579 }
    580 
    581 FlowBox *
    582 FlowCmd::nextBox(FlowBoxIterator *iterPtr)
    583 {
    584     if (iterPtr->hashPtr == NULL) {
    585         return NULL;
    586     }
    587     iterPtr->hashPtr = Tcl_NextHashEntry(&iterPtr->hashSearch);
    588     if (iterPtr->hashPtr == NULL) {
    589         return NULL;
    590     }
    591     return (FlowBox *)Tcl_GetHashValue(iterPtr->hashPtr);
     345    return itr->second;
     346}
     347
     348void
     349FlowCmd::deleteBox(const char *boxName)
     350{
     351    BoxHashmap::iterator itr = _boxTable.find(boxName);
     352    if (itr == _boxTable.end()) {
     353        TRACE("Can't find box '%s' in '%s'", boxName, name());
     354        return;
     355    }
     356    delete itr->second;
     357    _boxTable.erase(itr);
     358}
     359
     360void FlowCmd::getBoxNames(std::vector<std::string>& names)
     361{
     362    for (BoxHashmap::iterator itr = _boxTable.begin();
     363         itr != _boxTable.end(); ++itr) {
     364        names.push_back(std::string(itr->second->name()));
     365    }
    592366}
    593367
     
    595369FlowCmd::initializeParticles()
    596370{
    597     FlowParticlesIterator iter;
    598     for (FlowParticles *particlesPtr = firstParticles(&iter);
    599          particlesPtr != NULL;
    600          particlesPtr = nextParticles(&iter)) {
    601         particlesPtr->initialize();
     371    for (ParticlesHashmap::iterator itr = _particlesTable.begin();
     372         itr != _particlesTable.end(); ++itr) {
     373        itr->second->initialize();
    602374    }
    603375}
     
    606378FlowCmd::scaleVectorField()
    607379{
    608     if (_volPtr != NULL) {
    609         TRACE("Removing existing volume: %s", _volPtr->name());
    610         NanoVis::removeVolume(_volPtr);
    611         _volPtr = NULL;
    612     }
    613     float *vdata;
    614     vdata = getScaledVector();
     380    if (_volume != NULL) {
     381        TRACE("Removing existing volume: %s", _volume->name());
     382        NanoVis::removeVolume(_volume);
     383        _volume = NULL;
     384    }
     385    float *vdata = getScaledVector();
    615386    if (vdata == NULL) {
    616387        return false;
    617388    }
    618     Volume *volPtr;
    619     volPtr = makeVolume(vdata);
     389    Volume *volume = makeVolume(vdata);
    620390    delete [] vdata;
    621     if (volPtr == NULL) {
     391    if (volume == NULL) {
    622392        return false;
    623393    }
    624     _volPtr = volPtr;
     394    _volume = volume;
    625395
    626396    // Remove the associated vector field.
    627     if (_fieldPtr != NULL) {
    628         delete _fieldPtr;
    629     }
    630     _fieldPtr = new NvVectorField();
    631     if (_fieldPtr == NULL) {
     397    if (_field != NULL) {
     398        delete _field;
     399    }
     400    _field = new NvVectorField();
     401    if (_field == NULL) {
    632402        return false;
    633403    }
    634404
    635     Vector3f scale = volPtr->getPhysicalScaling();
    636     Vector3f location = _volPtr->location();
    637 
    638     _fieldPtr->setVectorField(_volPtr,
    639                               location,
    640                               scale.x,
    641                               scale.y,
    642                               scale.z,
    643                               NanoVis::magMax);
    644 
    645     if (NanoVis::licRenderer != NULL) {
    646         NanoVis::licRenderer->
    647             setVectorField(_volPtr->textureID(),
     405    Vector3f scale = volume->getPhysicalScaling();
     406    Vector3f location = _volume->location();
     407
     408    _field->setVectorField(_volume,
    648409                           location,
    649410                           scale.x,
    650411                           scale.y,
    651412                           scale.z,
    652                            _volPtr->wAxis.max());
    653         setCurrentPosition();
    654         setAxis();
    655         setActive();
    656     }
    657 
    658     if (NanoVis::velocityArrowsSlice != NULL) {
    659         NanoVis::velocityArrowsSlice->
    660             setVectorField(_volPtr->textureID(),
     413                           NanoVis::magMax);
     414
     415    if (NanoVis::licRenderer != NULL) {
     416        NanoVis::licRenderer->
     417            setVectorField(_volume->textureID(),
    661418                           location,
    662419                           scale.x,
    663420                           scale.y,
    664421                           scale.z,
    665                            _volPtr->wAxis.max());
     422                           _volume->wAxis.max());
     423        setCurrentPosition();
     424        setAxis();
     425        setActive();
     426    }
     427
     428    if (NanoVis::velocityArrowsSlice != NULL) {
     429        NanoVis::velocityArrowsSlice->
     430            setVectorField(_volume->textureID(),
     431                           location,
     432                           scale.x,
     433                           scale.y,
     434                           scale.z,
     435                           _volume->wAxis.max());
    666436        NanoVis::velocityArrowsSlice->axis(_sv.slicePos.axis);
    667437        NanoVis::velocityArrowsSlice->slicePos(_sv.slicePos.value);
     
    669439    }
    670440
    671     FlowParticlesIterator partIter;
    672     for (FlowParticles *particlesPtr = firstParticles(&partIter);
    673          particlesPtr != NULL;
    674          particlesPtr = nextParticles(&partIter)) {
    675         particlesPtr->setVectorField(_volPtr,
    676                                      location,
    677                                      scale.x,
    678                                      scale.y,
    679                                      scale.z,
    680                                      _volPtr->wAxis.max());
     441    for (ParticlesHashmap::iterator itr = _particlesTable.begin();
     442         itr != _particlesTable.end(); ++itr) {
     443        itr->second->setVectorField(_volume,
     444                                    location,
     445                                    scale.x,
     446                                    scale.y,
     447                                    scale.z,
     448                                    _volume->wAxis.max());
    681449    }
    682450    return true;
     
    686454FlowCmd::renderBoxes()
    687455{
    688     FlowBoxIterator iter;
    689     FlowBox *boxPtr;
    690     for (boxPtr = firstBox(&iter); boxPtr != NULL; boxPtr = nextBox(&iter)) {
    691         if (boxPtr->visible()) {
    692             boxPtr->render(_volPtr);
     456    for (BoxHashmap::iterator itr = _boxTable.begin();
     457         itr != _boxTable.end(); ++itr) {
     458        if (itr->second->visible()) {
     459            itr->second->render(_volume);
    693460        }
    694461    }
     
    698465FlowCmd::getScaledVector()
    699466{
    700     assert(_dataPtr->nComponents() == 3);
    701     size_t n = _dataPtr->nValues() / _dataPtr->nComponents() * 4;
     467    assert(_data->nComponents() == 3);
     468    size_t n = _data->nValues() / _data->nComponents() * 4;
    702469    float *data = new float[n];
    703470    if (data == NULL) {
     
    706473    memset(data, 0, sizeof(float) * n);
    707474    float *destPtr = data;
    708     const float *values = _dataPtr->values();
    709     for (size_t iz = 0; iz < _dataPtr->zNum(); iz++) {
    710         for (size_t iy = 0; iy < _dataPtr->yNum(); iy++) {
    711             for (size_t ix = 0; ix < _dataPtr->xNum(); ix++) {
     475    const float *values = _data->values();
     476    for (size_t iz = 0; iz < _data->zNum(); iz++) {
     477        for (size_t iy = 0; iy < _data->yNum(); iy++) {
     478            for (size_t ix = 0; ix < _data->xNum(); ix++) {
    712479                double vx, vy, vz, vm;
    713480                vx = values[0];
     
    730497FlowCmd::makeVolume(float *data)
    731498{
    732     Volume *volPtr;
    733 
    734     volPtr = NanoVis::loadVolume(_name,
    735                                  _dataPtr->xNum(),
    736                                  _dataPtr->yNum(),
    737                                  _dataPtr->zNum(),
    738                                  4, data,
    739                                  NanoVis::magMin, NanoVis::magMax, 0);
    740     volPtr->xAxis.setRange(_dataPtr->xMin(), _dataPtr->xMax());
    741     volPtr->yAxis.setRange(_dataPtr->yMin(), _dataPtr->yMax());
    742     volPtr->zAxis.setRange(_dataPtr->zMin(), _dataPtr->zMax());
     499    Volume *volume =
     500        NanoVis::loadVolume(_name.c_str(),
     501                            _data->xNum(),
     502                            _data->yNum(),
     503                            _data->zNum(),
     504                            4, data,
     505                            NanoVis::magMin, NanoVis::magMax, 0);
     506    volume->xAxis.setRange(_data->xMin(), _data->xMax());
     507    volume->yAxis.setRange(_data->yMin(), _data->yMax());
     508    volume->zAxis.setRange(_data->zMin(), _data->zMax());
    743509
    744510    TRACE("min=%g %g %g max=%g %g %g mag=%g %g",
     
    747513          NanoVis::magMin, NanoVis::magMax);
    748514
    749     volPtr->disableCutplane(0);
    750     volPtr->disableCutplane(1);
    751     volPtr->disableCutplane(2);
     515    volume->disableCutplane(0);
     516    volume->disableCutplane(1);
     517    volume->disableCutplane(2);
    752518
    753519    /* Initialize the volume with the previously configured values. */
    754     volPtr->transferFunction(_sv.tfPtr);
    755     volPtr->dataEnabled(_sv.showVolume);
    756     volPtr->twoSidedLighting(_sv.twoSidedLighting);
    757     volPtr->outline(_sv.showOutline);
    758     volPtr->opacityScale(_sv.opacity);
    759     volPtr->ambient(_sv.ambient);
    760     volPtr->diffuse(_sv.diffuse);
    761     volPtr->specularLevel(_sv.specular);
    762     volPtr->specularExponent(_sv.specularExp);
    763     volPtr->visible(_sv.showVolume);
    764 
    765     Vector3f volScaling = volPtr->getPhysicalScaling();
     520    volume->transferFunction(_sv.transferFunction);
     521    volume->dataEnabled(_sv.showVolume);
     522    volume->twoSidedLighting(_sv.twoSidedLighting);
     523    volume->outline(_sv.showOutline);
     524    volume->opacityScale(_sv.opacity);
     525    volume->ambient(_sv.ambient);
     526    volume->diffuse(_sv.diffuse);
     527    volume->specularLevel(_sv.specular);
     528    volume->specularExponent(_sv.specularExp);
     529    volume->visible(_sv.showVolume);
     530
     531    Vector3f volScaling = volume->getPhysicalScaling();
    766532    Vector3f loc(volScaling);
    767533    loc *= -0.5;
    768     volPtr->location(loc);
     534    volume->location(loc);
    769535
    770536    Volume::updatePending = true;
    771     return volPtr;
     537    return volume;
    772538}
    773539
     
    996762/* Static NanoVis class commands. */
    997763
     764FlowCmd *
     765NanoVis::getFlow(const char *name)
     766{
     767    FlowHashmap::iterator itr = flowTable.find(name);
     768    if (itr == flowTable.end()) {
     769        TRACE("Can't find flow '%s'", name);
     770        return NULL;
     771    }
     772    return itr->second;
     773}
     774
     775FlowCmd *
     776NanoVis::createFlow(Tcl_Interp *interp, const char *name)
     777{
     778    FlowHashmap::iterator itr = flowTable.find(name);
     779    if (itr != flowTable.end()) {
     780        ERROR("Flow '%s' already exists", name);
     781        return NULL;
     782    }
     783    FlowCmd *flow = new FlowCmd(interp, name);
     784    flowTable[name] = flow;
     785    return flow;
     786}
     787
     788/**
     789 * \brief Delete flow object and hash table entry
     790 *
     791 * This is called by the flow command instance delete callback
     792 */
    998793void
    999 NanoVis::initFlows()
    1000 {
    1001     Tcl_InitHashTable(&flowTable, TCL_STRING_KEYS);
    1002 }
    1003 
    1004 FlowCmd *
    1005 NanoVis::firstFlow(FlowIterator *iterPtr)
    1006 {
    1007     iterPtr->hashPtr = Tcl_FirstHashEntry(&flowTable, &iterPtr->hashSearch);
    1008     if (iterPtr->hashPtr == NULL) {
    1009         return NULL;
    1010     }
    1011     return (FlowCmd *)Tcl_GetHashValue(iterPtr->hashPtr);
    1012 }
    1013 
    1014 FlowCmd *
    1015 NanoVis::nextFlow(FlowIterator *iterPtr)
    1016 {
    1017     if (iterPtr->hashPtr == NULL) {
    1018         return NULL;
    1019     }
    1020     iterPtr->hashPtr = Tcl_NextHashEntry(&iterPtr->hashSearch);
    1021     if (iterPtr->hashPtr == NULL) {
    1022         return NULL;
    1023     }
    1024     return (FlowCmd *)Tcl_GetHashValue(iterPtr->hashPtr);
    1025 }
    1026 
    1027 int
    1028 NanoVis::getFlow(Tcl_Interp *interp, Tcl_Obj *objPtr, FlowCmd **flowPtrPtr)
    1029 {
    1030     Tcl_HashEntry *hPtr;
    1031     hPtr = Tcl_FindHashEntry(&flowTable, Tcl_GetString(objPtr));
    1032     if (hPtr == NULL) {
    1033         if (interp != NULL) {
    1034             Tcl_AppendResult(interp, "can't find a flow \"",
    1035                              Tcl_GetString(objPtr), "\"", (char *)NULL);
    1036         }
    1037         return TCL_ERROR;
    1038     }
    1039     *flowPtrPtr = (FlowCmd *)Tcl_GetHashValue(hPtr);
    1040     return TCL_OK;
    1041 }
    1042 
    1043 int
    1044 NanoVis::createFlow(Tcl_Interp *interp, Tcl_Obj *objPtr)
    1045 {
    1046     Tcl_HashEntry *hPtr;
    1047     int isNew;
    1048     const char *name;
    1049     name = Tcl_GetString(objPtr);
    1050     hPtr = Tcl_CreateHashEntry(&flowTable, name, &isNew);
    1051     if (!isNew) {
    1052         Tcl_AppendResult(interp, "flow \"", name, "\" already exists.",
    1053                          (char *)NULL);
    1054         return TCL_ERROR;
    1055     }
    1056     Tcl_CmdInfo cmdInfo;
    1057     if (Tcl_GetCommandInfo(interp, name, &cmdInfo)) {
    1058         Tcl_AppendResult(interp, "an another command \"", name,
    1059                          "\" already exists.", (char *)NULL);
    1060         return TCL_ERROR;
    1061     }
    1062     FlowCmd *flowPtr;
    1063     name = Tcl_GetHashKey(&flowTable, hPtr);
    1064     flowPtr = new FlowCmd(interp, name, hPtr);
    1065     if (flowPtr == NULL) {
    1066         Tcl_AppendResult(interp, "can't allocate a flow object \"", name,
    1067                          "\"", (char *)NULL);
    1068         return TCL_ERROR;
    1069     }
    1070     Tcl_SetHashValue(hPtr, flowPtr);
    1071     return TCL_OK;
    1072 }
    1073 
     794NanoVis::deleteFlow(const char *name)
     795{
     796    FlowHashmap::iterator itr = flowTable.find(name);
     797    if (itr != flowTable.end()) {
     798        delete itr->second;
     799        flowTable.erase(itr);
     800    }
     801}
     802
     803/**
     804 * \brief Delete all flow object commands
     805 *
     806 * This will also delete the flow objects and hash table entries
     807 */
    1074808void
    1075809NanoVis::deleteFlows(Tcl_Interp *interp)
    1076810{
    1077     FlowCmd *flowPtr;
    1078     FlowIterator iter;
    1079     for (flowPtr = firstFlow(&iter); flowPtr != NULL;
    1080          flowPtr = nextFlow(&iter)) {
    1081         flowPtr->disconnect();                /* Don't disrupt the hash walk */
    1082         Tcl_DeleteCommand(interp, flowPtr->name());
    1083     }
    1084     Tcl_DeleteHashTable(&flowTable);
     811    FlowHashmap::iterator itr;
     812    for (itr = flowTable.begin();
     813         itr != flowTable.end(); ++itr) {
     814        Tcl_DeleteCommandFromToken(interp, itr->second->getCommandToken());
     815    }
     816    flowTable.clear();
    1085817}
    1086818
     
    1098830    magMin = DBL_MAX, magMax = -DBL_MAX;
    1099831
    1100     FlowCmd *flowPtr;
    1101     FlowIterator iter;
    1102     for (flowPtr = firstFlow(&iter); flowPtr != NULL;
    1103          flowPtr = nextFlow(&iter)) {
     832    for (FlowHashmap::iterator itr = flowTable.begin();
     833         itr != flowTable.end(); ++itr) {
     834        FlowCmd *flow = itr->second;
    1104835        double min, max;
    1105         if (!flowPtr->isDataLoaded()) {
     836        if (!flow->isDataLoaded()) {
    1106837            continue;
    1107838        }
    1108         Rappture::Unirect3d *dataPtr = flowPtr->data();
    1109         min = dataPtr->magMin();
    1110         max = dataPtr->magMax();
     839        Rappture::Unirect3d *data = flow->data();
     840        min = data->magMin();
     841        max = data->magMax();
    1111842        if (min < magMin) {
    1112843            magMin = min;
     
    1115846            magMax = max;
    1116847        }
    1117         if (dataPtr->xMin() < xMin) {
    1118             xMin = dataPtr->xMin();
    1119         }
    1120         if (dataPtr->yMin() < yMin) {
    1121             yMin = dataPtr->yMin();
    1122         }
    1123         if (dataPtr->zMin() < zMin) {
    1124             zMin = dataPtr->zMin();
    1125         }
    1126         if (dataPtr->xMax() > xMax) {
    1127             xMax = dataPtr->xMax();
    1128         }
    1129         if (dataPtr->yMax() > yMax) {
    1130             yMax = dataPtr->yMax();
    1131         }
    1132         if (dataPtr->zMax() > zMax) {
    1133             zMax = dataPtr->zMax();
     848        if (data->xMin() < xMin) {
     849            xMin = data->xMin();
     850        }
     851        if (data->yMin() < yMin) {
     852            yMin = data->yMin();
     853        }
     854        if (data->zMin() < zMin) {
     855            zMin = data->zMin();
     856        }
     857        if (data->xMax() > xMax) {
     858            xMax = data->xMax();
     859        }
     860        if (data->yMax() > yMax) {
     861            yMax = data->yMax();
     862        }
     863        if (data->zMax() > zMax) {
     864            zMax = data->zMax();
    1134865        }
    1135866    }
     
    1140871     * Step 2. Generate the vector field from each data set.
    1141872     */
    1142     for (flowPtr = firstFlow(&iter); flowPtr != NULL;
    1143          flowPtr = nextFlow(&iter)) {
    1144         if (!flowPtr->isDataLoaded()) {
     873    for (FlowHashmap::iterator itr = flowTable.begin();
     874         itr != flowTable.end(); ++itr) {
     875        FlowCmd *flow = itr->second;
     876        if (!flow->isDataLoaded()) {
    1145877            continue; // Flow exists, but no data has been loaded yet.
    1146878        }
    1147         if (flowPtr->visible()) {
    1148             flowPtr->initializeParticles();
    1149         }
    1150         if (!flowPtr->scaleVectorField()) {
     879        if (flow->visible()) {
     880            flow->initializeParticles();
     881        }
     882        if (!flow->scaleVectorField()) {
    1151883            return false;
    1152884        }
    1153885        // FIXME: This doesn't work when there is more than one flow.
    1154         licRenderer->setOffset(flowPtr->getRelativePosition());
    1155         velocityArrowsSlice->slicePos(flowPtr->getRelativePosition());
     886        licRenderer->setOffset(flow->getRelativePosition());
     887        velocityArrowsSlice->slicePos(flow->getRelativePosition());
    1156888    }
    1157889    advectFlows();
     
    1169901    max.set(-FLT_MAX, -FLT_MAX, -FLT_MAX);
    1170902
    1171     FlowCmd *flow;
    1172     FlowIterator iter;
    1173     for (flow = firstFlow(&iter); flow != NULL;
    1174          flow = nextFlow(&iter)) {
    1175         if (onlyVisible && !flow->visible())
    1176             continue;
    1177  #if 0  // Using volume bounds instead of these
    1178         if (flow->isDataLoaded()) {
    1179             Vector3f umin, umax;
    1180             Rappture::Unirect3d *unirect = flow->data();
    1181             unirect->getWorldSpaceBounds(umin, umax);
    1182             if (min.x > umin.x) {
    1183                 min.x = umin.x;
    1184             }
    1185             if (max.x < umax.x) {
    1186                 max.x = umax.x;
    1187             }
    1188             if (min.y > umin.y) {
    1189                 min.y = umin.y;
    1190             }
    1191             if (max.y < umax.y) {
    1192                 max.y = umax.y;
    1193             }
    1194             if (min.z > umin.z) {
    1195                 min.z = umin.z;
    1196             }
    1197             if (max.z < umax.z) {
    1198                 max.z = umax.z;
    1199             }
    1200         }
    1201 #endif
    1202         FlowBox *box;
    1203         FlowBoxIterator iter;
    1204         for (box = flow->firstBox(&iter); box != NULL;
    1205              box = flow->nextBox(&iter)) {
    1206             if (!onlyVisible || box->visible()) {
    1207                 Vector3f fbmin, fbmax;
    1208                 box->getWorldSpaceBounds(fbmin, fbmax,
    1209                                          flow->getVolume());
    1210                 if (min.x > fbmin.x) {
    1211                     min.x = fbmin.x;
    1212                 }
    1213                 if (max.x < fbmax.x) {
    1214                     max.x = fbmax.x;
    1215                 }
    1216                 if (min.y > fbmin.y) {
    1217                     min.y = fbmin.y;
    1218                 }
    1219                 if (max.y < fbmax.y) {
    1220                     max.y = fbmax.y;
    1221                 }
    1222                 if (min.z > fbmin.z) {
    1223                     min.z = fbmin.z;
    1224                 }
    1225                 if (max.z < fbmax.z) {
    1226                     max.z = fbmax.z;
    1227                 }
    1228             }
    1229         }
     903    for (FlowHashmap::iterator itr = flowTable.begin();
     904         itr != flowTable.end(); ++itr) {
     905        itr->second->getBounds(min, max, onlyVisible);
    1230906    }
    1231907}
     
    1234910NanoVis::renderFlows()
    1235911{
    1236     FlowCmd *flowPtr;
    1237     FlowIterator iter;
    1238     for (flowPtr = firstFlow(&iter); flowPtr != NULL;
    1239          flowPtr = nextFlow(&iter)) {
    1240         if ((flowPtr->isDataLoaded()) && (flowPtr->visible())) {
    1241             flowPtr->render();
     912    for (FlowHashmap::iterator itr = flowTable.begin();
     913         itr != flowTable.end(); ++itr) {
     914        FlowCmd *flow = itr->second;
     915        if (flow->isDataLoaded() && flow->visible()) {
     916            flow->render();
    1242917        }
    1243918    }
     
    1248923NanoVis::resetFlows()
    1249924{
    1250     FlowCmd *flowPtr;
    1251     FlowIterator iter;
    1252 
    1253925    if (licRenderer->active()) {
    1254926        NanoVis::licRenderer->reset();
    1255927    }
    1256     for (flowPtr = firstFlow(&iter); flowPtr != NULL;
    1257          flowPtr = nextFlow(&iter)) {
    1258         if ((flowPtr->isDataLoaded()) && (flowPtr->visible())) {
    1259             flowPtr->resetParticles();
     928    for (FlowHashmap::iterator itr = flowTable.begin();
     929         itr != flowTable.end(); ++itr) {
     930        FlowCmd *flow = itr->second;
     931        if (flow->isDataLoaded() && flow->visible()) {
     932            flow->resetParticles();
    1260933        }
    1261934    }
     
    1265938NanoVis::advectFlows()
    1266939{
    1267     FlowCmd *flowPtr;
    1268     FlowIterator iter;
    1269     for (flowPtr = firstFlow(&iter); flowPtr != NULL;
    1270          flowPtr = nextFlow(&iter)) {
    1271         if ((flowPtr->isDataLoaded()) && (flowPtr->visible())) {
    1272             flowPtr->advect();
     940    for (FlowHashmap::iterator itr = flowTable.begin();
     941         itr != flowTable.end(); ++itr) {
     942        FlowCmd *flow = itr->second;
     943        if (flow->isDataLoaded() && flow->visible()) {
     944            flow->advect();
    1273945        }
    1274946    }
     
    13391011    Tcl_Obj **objv;
    13401012    int objc;
    1341     FlowColor *colorPtr = (FlowColor *)(record + offset);
     1013    FlowColor *color = (FlowColor *)(record + offset);
    13421014
    13431015    if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) {
     
    13661038        values[i] = value;
    13671039    }
    1368     colorPtr->r = values[0];
    1369     colorPtr->g = values[1];
    1370     colorPtr->b = values[2];
    1371     colorPtr->a = values[3];
     1040    color->r = values[0];
     1041    color->g = values[1];
     1042    color->b = values[2];
     1043    color->a = values[3];
    13721044    return TCL_OK;
    13731045}
     
    13921064                char *record, int offset, int flags)
    13931065{
    1394     FlowPoint *pointPtr = (FlowPoint *)(record + offset);
     1066    FlowPoint *point = (FlowPoint *)(record + offset);
    13951067    int objc;
    13961068    Tcl_Obj **objv;
     
    14141086        values[i] = value;
    14151087    }
    1416     pointPtr->x = values[0];
    1417     pointPtr->y = values[1];
    1418     pointPtr->z = values[2];
     1088    point->x = values[0];
     1089    point->y = values[1];
     1090    point->z = values[2];
    14191091    return TCL_OK;
    14201092}
     
    14891161{
    14901162    TransferFunction **funcPtrPtr = (TransferFunction **)(record + offset);
    1491     TransferFunction *funcPtr;
    1492     funcPtr = NanoVis::getTransfunc(Tcl_GetString(objPtr));
    1493     if (funcPtr == NULL) {
     1163    TransferFunction *tf = NanoVis::getTransferFunction(Tcl_GetString(objPtr));
     1164    if (tf == NULL) {
    14941165        Tcl_AppendResult(interp, "transfer function \"", Tcl_GetString(objPtr),
    14951166                         "\" is not defined", (char*)NULL);
    14961167        return TCL_ERROR;
    14971168    }
    1498     *funcPtrPtr = funcPtr;
     1169    *funcPtrPtr = tf;
    14991170    return TCL_OK;
    15001171}
     
    15171188                   Tcl_Obj *const *objv)
    15181189{
    1519     FlowCmd *flowPtr = (FlowCmd *)clientData;
    1520 
    1521     if (flowPtr->createParticles(interp, objv[3]) != TCL_OK) {
    1522         return TCL_ERROR;
    1523     }
    1524     FlowParticles *particlesPtr;
    1525     if (flowPtr->getParticles(interp, objv[3], &particlesPtr) != TCL_OK) {
    1526         return TCL_ERROR;
    1527     }
    1528     if (particlesPtr->parseSwitches(interp, objc - 4, objv + 4) != TCL_OK) {
    1529         delete particlesPtr;
    1530         return TCL_ERROR;
    1531     }
    1532     particlesPtr->configure();
     1190    FlowCmd *flow = (FlowCmd *)clientData;
     1191    const char *particlesName = Tcl_GetString(objv[3]);
     1192    FlowParticles *particles = flow->createParticles(particlesName);
     1193    if (particles == NULL) {
     1194        Tcl_AppendResult(interp, "Flow particle injection plane \"",
     1195                         particlesName,
     1196                         "\" already exists or could not be created",
     1197                         (char*)NULL);
     1198        return TCL_ERROR;
     1199    }
     1200    if (particles->parseSwitches(interp, objc - 4, objv + 4) != TCL_OK) {
     1201        flow->deleteParticles(particlesName);
     1202        return TCL_ERROR;
     1203    }
     1204    particles->configure();
    15331205    NanoVis::eventuallyRedraw();
    15341206    Tcl_SetObjResult(interp, objv[3]);
     
    15401212                         Tcl_Obj *const *objv)
    15411213{
    1542     FlowCmd *flowPtr = (FlowCmd *)clientData;
    1543 
    1544     FlowParticles *particlesPtr;
    1545     if (flowPtr->getParticles(interp, objv[3], &particlesPtr) != TCL_OK) {
    1546         return TCL_ERROR;
    1547     }
    1548     if (particlesPtr->parseSwitches(interp, objc - 4, objv + 4) != TCL_OK) {
    1549         return TCL_ERROR;
    1550     }
    1551     particlesPtr->configure();
     1214    FlowCmd *flow = (FlowCmd *)clientData;
     1215    const char *particlesName = Tcl_GetString(objv[3]);
     1216    FlowParticles *particles = flow->getParticles(particlesName);
     1217    if (particles == NULL) {
     1218        Tcl_AppendResult(interp, "Flow particle injection plane \"",
     1219                         particlesName, "\" not found",
     1220                         (char*)NULL);
     1221        return TCL_ERROR;
     1222    }
     1223    if (particles->parseSwitches(interp, objc - 4, objv + 4) != TCL_OK) {
     1224        return TCL_ERROR;
     1225    }
     1226    particles->configure();
    15521227    NanoVis::eventuallyRedraw(NanoVis::MAP_FLOWS);
    15531228    return TCL_OK;
     
    15581233                      Tcl_Obj *const *objv)
    15591234{
    1560     FlowCmd *flowPtr = (FlowCmd *)clientData;
    1561     int i;
    1562     for (i = 3; i < objc; i++) {
    1563         FlowParticles *particlesPtr;
    1564 
    1565         if (flowPtr->getParticles(NULL, objv[i], &particlesPtr) == TCL_OK) {
    1566             delete particlesPtr;
    1567         }
     1235    FlowCmd *flow = (FlowCmd *)clientData;
     1236    for (int i = 3; i < objc; i++) {
     1237        flow->deleteParticles(Tcl_GetString(objv[i]));
    15681238    }
    15691239    NanoVis::eventuallyRedraw();
     
    15751245                     Tcl_Obj *const *objv)
    15761246{
    1577     FlowCmd *flowPtr = (FlowCmd *)clientData;
     1247    FlowCmd *flow = (FlowCmd *)clientData;
    15781248    Tcl_Obj *listObjPtr;
    15791249    listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL);
    1580     FlowParticlesIterator iter;
    1581     FlowParticles *particlesPtr;
    1582     for (particlesPtr = flowPtr->firstParticles(&iter); particlesPtr != NULL;
    1583          particlesPtr = flowPtr->nextParticles(&iter)) {
    1584         Tcl_Obj *objPtr;
    1585 
    1586         objPtr = Tcl_NewStringObj(particlesPtr->name(), -1);
     1250    std::vector<std::string> names;
     1251    flow->getParticlesNames(names);
     1252    for (std::vector<std::string>::iterator itr = names.begin();
     1253         itr != names.end(); ++itr) {
     1254        Tcl_Obj *objPtr = Tcl_NewStringObj(itr->c_str(), -1);
    15871255        Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
    15881256    }
     
    15941262    {"add",        1, FlowParticlesAddOp,        4, 0, "name ?switches?",},
    15951263    {"configure",  1, FlowParticlesConfigureOp,  4, 0, "name ?switches?",},
    1596     {"delete",     1, FlowParticlesDeleteOp,     4, 0, "?name...?"},
    1597     {"names",      1, FlowParticlesNamesOp,      3, 4, "?pattern?"},
     1264    {"delete",     1, FlowParticlesDeleteOp,     4, 0, "name ?name...?"},
     1265    {"names",      1, FlowParticlesNamesOp,      3, 3, ""},
    15981266};
    15991267
     
    16321300             Tcl_Obj *const *objv)
    16331301{
    1634     FlowCmd *flowPtr = (FlowCmd *)clientData;
    1635 
    1636     if (flowPtr->createBox(interp, objv[3]) != TCL_OK) {
    1637         return TCL_ERROR;
    1638     }
    1639     FlowBox *boxPtr;
    1640     if (flowPtr->getBox(interp, objv[3], &boxPtr) != TCL_OK) {
    1641         return TCL_ERROR;
    1642     }
    1643     if (boxPtr->parseSwitches(interp, objc - 4, objv + 4) != TCL_OK) {
    1644         delete boxPtr;
     1302    FlowCmd *flow = (FlowCmd *)clientData;
     1303    const char *boxName = Tcl_GetString(objv[3]);
     1304    FlowBox *box = flow->createBox(boxName);
     1305    if (box == NULL) {
     1306        Tcl_AppendResult(interp, "Flow box \"", boxName,
     1307                         "\" already exists or could not be created",
     1308                         (char*)NULL);
     1309        return TCL_ERROR;
     1310    }
     1311    if (box->parseSwitches(interp, objc - 4, objv + 4) != TCL_OK) {
     1312        flow->deleteBox(boxName);
    16451313        return TCL_ERROR;
    16461314    }
     
    16511319
    16521320static int
     1321FlowBoxConfigureOp(ClientData clientData, Tcl_Interp *interp, int objc,
     1322                   Tcl_Obj *const *objv)
     1323{
     1324    FlowCmd *flow = (FlowCmd *)clientData;
     1325    const char *boxName = Tcl_GetString(objv[3]);
     1326    FlowBox *box = flow->getBox(boxName);
     1327    if (box == NULL) {
     1328        Tcl_AppendResult(interp, "Flow box \"", boxName, "\" not found",
     1329                         (char*)NULL);
     1330        return TCL_ERROR;
     1331    }
     1332    if (box->parseSwitches(interp, objc - 4, objv + 4) != TCL_OK) {
     1333        return TCL_ERROR;
     1334    }
     1335    NanoVis::eventuallyRedraw();
     1336    return TCL_OK;
     1337}
     1338
     1339static int
    16531340FlowBoxDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc,
    16541341                Tcl_Obj *const *objv)
    16551342{
    1656     FlowCmd *flowPtr = (FlowCmd *)clientData;
    1657     int i;
    1658     for (i = 3; i < objc; i++) {
    1659         FlowBox *boxPtr;
    1660 
    1661         if (flowPtr->getBox(NULL, objv[i], &boxPtr) == TCL_OK) {
    1662             delete boxPtr;
    1663         }
     1343    FlowCmd *flow = (FlowCmd *)clientData;
     1344    for (int i = 3; i < objc; i++) {
     1345        flow->deleteBox(Tcl_GetString(objv[i]));
    16641346    }
    16651347    NanoVis::eventuallyRedraw();
     
    16711353               Tcl_Obj *const *objv)
    16721354{
    1673     FlowCmd *flowPtr = (FlowCmd *)clientData;
    1674     Tcl_Obj *listObjPtr;
    1675     listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL);
    1676     FlowBoxIterator iter;
    1677     FlowBox *boxPtr;
    1678     for (boxPtr = flowPtr->firstBox(&iter); boxPtr != NULL;
    1679          boxPtr = flowPtr->nextBox(&iter)) {
    1680         Tcl_Obj *objPtr;
    1681 
    1682         objPtr = Tcl_NewStringObj(boxPtr->name(), -1);
     1355    FlowCmd *flow = (FlowCmd *)clientData;
     1356    Tcl_Obj *listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL);
     1357    std::vector<std::string> names;
     1358    flow->getBoxNames(names);
     1359    for (std::vector<std::string>::iterator itr = names.begin();
     1360         itr != names.end(); ++itr) {
     1361        Tcl_Obj *objPtr = Tcl_NewStringObj(itr->c_str(), -1);
    16831362        Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
    16841363    }
    16851364    Tcl_SetObjResult(interp, listObjPtr);
    1686     return TCL_OK;
    1687 }
    1688 
    1689 static int
    1690 FlowBoxConfigureOp(ClientData clientData, Tcl_Interp *interp, int objc,
    1691                    Tcl_Obj *const *objv)
    1692 {
    1693     FlowCmd *flowPtr = (FlowCmd *)clientData;
    1694 
    1695     FlowBox *boxPtr;
    1696     if (flowPtr->getBox(interp, objv[3], &boxPtr) != TCL_OK) {
    1697         return TCL_ERROR;
    1698     }
    1699     if (boxPtr->parseSwitches(interp, objc - 4, objv + 4) != TCL_OK) {
    1700         return TCL_ERROR;
    1701     }
    1702     NanoVis::eventuallyRedraw();
    17031365    return TCL_OK;
    17041366}
     
    17071369    {"add",        1, FlowBoxAddOp,        4, 0, "name ?switches?",},
    17081370    {"configure",  1, FlowBoxConfigureOp,  4, 0, "name ?switches?",},
    1709     {"delete",     1, FlowBoxDeleteOp,     3, 0, "?name...?"},
    1710     {"names",      1, FlowBoxNamesOp,      3, 0, "?pattern?"},
     1371    {"delete",     1, FlowBoxDeleteOp,     4, 0, "name ?name...?"},
     1372    {"names",      1, FlowBoxNamesOp,      3, 3, ""},
    17111373};
    17121374
     
    18041466    }
    18051467    assert(CheckGL(AT));
    1806     FlowCmd *flowPtr = (FlowCmd *)clientData;
    1807     Tcl_Preserve(flowPtr);
    1808     int result;
    1809     result = (*proc) (clientData, interp, objc, objv);
    1810     Tcl_Release(flowPtr);
     1468    FlowCmd *flow = (FlowCmd *)clientData;
     1469    Tcl_Preserve(flow);
     1470    int result = (*proc) (clientData, interp, objc, objv);
     1471    Tcl_Release(flow);
    18111472    return result;
    18121473}
    18131474
    18141475/**
    1815  * \brief Deletes the command associated with the tree.
    1816  *
    1817  * This is called only when the command associated with the tree is destroyed.
     1476 * \brief Deletes the command associated with the flow
     1477 *
     1478 * This is called only when the command associated with the flow is destroyed.
    18181479 */
    18191480static void
    18201481FlowInstDeleteProc(ClientData clientData)
    18211482{
    1822     FlowCmd *flowPtr = (FlowCmd *)clientData;
    1823     delete flowPtr;
     1483    FlowCmd *flow = (FlowCmd *)clientData;
     1484    NanoVis::deleteFlow(flow->name());
    18241485}
    18251486
     
    18281489          Tcl_Obj *const *objv)
    18291490{
    1830     if (NanoVis::createFlow(interp, objv[2]) != TCL_OK) {
    1831         return TCL_ERROR;
    1832     }
    1833     FlowCmd *flowPtr;
    1834     if (NanoVis::getFlow(interp, objv[2], &flowPtr) != TCL_OK) {
    1835         return TCL_ERROR;
    1836     }
    1837     if (flowPtr->parseSwitches(interp, objc - 3, objv + 3) != TCL_OK) {
    1838         Tcl_DeleteCommand(interp, flowPtr->name());
     1491    const char *name = Tcl_GetString(objv[2]);
     1492    Tcl_CmdInfo cmdInfo;
     1493    if (Tcl_GetCommandInfo(interp, name, &cmdInfo)) {
     1494        Tcl_AppendResult(interp, "an another command \"", name,
     1495                         "\" already exists.", (char *)NULL);
     1496        return NULL;
     1497    }
     1498    FlowCmd *flow = NanoVis::createFlow(interp, name);
     1499    if (flow == NULL) {
     1500        Tcl_AppendResult(interp, "Flow \"", name, "\" already exists",
     1501                         (char*)NULL);
     1502        return TCL_ERROR;
     1503    }
     1504    if (flow->parseSwitches(interp, objc - 3, objv + 3) != TCL_OK) {
     1505        Tcl_DeleteCommand(interp, flow->name());
    18391506        return TCL_ERROR;
    18401507    }
     
    18481515             Tcl_Obj *const *objv)
    18491516{
    1850     int i;
    1851 
    1852     for (i = 2; i < objc; i++) {
    1853         FlowCmd *flowPtr;
    1854 
    1855         if (NanoVis::getFlow(interp, objv[i], &flowPtr) != TCL_OK) {
    1856             return TCL_ERROR;
    1857         }
    1858         Tcl_DeleteCommand(interp, flowPtr->name());
     1517    for (int i = 2; i < objc; i++) {
     1518        FlowCmd *flow = NanoVis::getFlow(Tcl_GetString(objv[i]));
     1519        if (flow != NULL) {
     1520            Tcl_DeleteCommandFromToken(interp, flow->getCommandToken());
     1521        }
    18591522    }
    18601523    NanoVis::eventuallyRedraw(NanoVis::MAP_FLOWS);
     
    18661529             Tcl_Obj *const *objv)
    18671530{
    1868     bool value;
    1869     FlowCmd *flowPtr;
    1870 
    1871     value = false;
    1872     if (NanoVis::getFlow(NULL, objv[2], &flowPtr) == TCL_OK) {
     1531    bool value = false;
     1532    FlowCmd *flow = NanoVis::getFlow(Tcl_GetString(objv[2]));
     1533    if (flow != NULL) {
    18731534        value = true;
    18741535    }
     
    18971558        NanoVis::mapFlows();
    18981559    }
    1899     int i;
    19001560    NanoVis::advectFlows();
    1901     for (i = 0; i < nSteps; i++) {
     1561    for (int i = 0; i < nSteps; i++) {
    19021562        if (NanoVis::licRenderer->active()) {
    19031563            NanoVis::licRenderer->convolve();
     
    19151575    Tcl_Obj *listObjPtr;
    19161576    listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL);
    1917     FlowCmd *flowPtr;
    1918     FlowIterator iter;
    1919     for (flowPtr = NanoVis::firstFlow(&iter); flowPtr != NULL;
    1920          flowPtr = NanoVis::nextFlow(&iter)) {
    1921         Tcl_Obj *objPtr;
    1922 
    1923         objPtr = Tcl_NewStringObj(flowPtr->name(), -1);
     1577    for (NanoVis::FlowHashmap::iterator itr = NanoVis::flowTable.begin();
     1578         itr != NanoVis::flowTable.end(); ++itr) {
     1579        FlowCmd *flow = itr->second;
     1580        Tcl_Obj *objPtr = Tcl_NewStringObj(flow->name(), -1);
    19241581        Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
    19251582    }
     
    22741931static Rappture::CmdSpec flowCmdOps[] = {
    22751932    {"add",      1, FlowAddOp,     3, 0, "name ?option value...?",},
    2276     {"delete",   1, FlowDeleteOp,  2, 0, "name...",},
     1933    {"delete",   1, FlowDeleteOp,  3, 0, "name ?name...?",},
    22771934    {"exists",   1, FlowExistsOp,  3, 3, "name",},
    22781935    {"goto",     1, FlowGotoOp,    3, 3, "nSteps",},
    2279     {"names",    1, FlowNamesOp,   2, 3, "?pattern?",},
     1936    {"names",    1, FlowNamesOp,   2, 2, "",},
    22801937    {"next",     2, FlowNextOp,    2, 2, "",},
    22811938    {"reset",    1, FlowResetOp,   2, 2, "",},
     
    22991956
    23001957/**
    2301  *\brief This procedure is invoked to initialize the "tree" command.
     1958 *\brief This procedure is invoked to initialize the "flow" command.
    23021959 *
    23031960 * Side effects:
     
    23091966{
    23101967    Tcl_CreateObjCommand(interp, "flow", FlowCmdProc, NULL, NULL);
    2311     NanoVis::initFlows();
    2312     return TCL_OK;
    2313 }
    2314 
    2315 #ifdef notdef
    2316 
    2317 // Read the header of a vtk data file. Returns 0 if error.
    2318 bool
    2319 VtkReadHeader()
    2320 {
    2321     char *p, *endPtr;
    2322 
    2323     line = getline(&p, endPtr);
    2324     if (line == endPtr) {
    2325         vtkErrorMacro(<<"Premature EOF reading first line! " << " for file: "
    2326                       << (this->FileName?this->FileName:"(Null FileName)"));
    2327         return false;
    2328     }
    2329     if (sscanf(line, "# vtk DataFile Version %s", version) != 1) {
    2330         vtkErrorMacro(<< "Unrecognized file type: "<< line << " for file: "
    2331                       << (this->FileName?this->FileName:"(Null FileName)"));
    2332         return false;
    2333     }
    2334 
    2335     // Read title
    2336     line = getline(&p, endPtr);
    2337     if (line == endPtr) {
    2338         vtkErrorMacro(<<"Premature EOF reading title! " << " for file: "
    2339                       << (this->FileName?this->FileName:"(Null FileName)"));
    2340         return false;
    2341     }
    2342     if (_title != NULL) {
    2343         delete [] _title;
    2344     }
    2345     _title = new char[strlen(line) + 1];
    2346     strcpy(_title, line);
    2347 
    2348     // Read type
    2349     line = getline(&p, endPtr);
    2350     if (line == endPtr) {
    2351         vtkErrorMacro(<<"Premature EOF reading file type!" << " for file: "
    2352                       << (this->FileName?this->FileName:"(Null FileName)"));
    2353         return false;
    2354     }
    2355     word = GetWord(line, &endPtr);
    2356     if (strncasecmp(word, "ascii", 5) == 0) {
    2357         _fileType = VTK_ASCII;
    2358     } else if (strcasecmp(word, "binary", 6) == 0) {
    2359         _fileType = VTK_BINARY;
    2360     } else {
    2361         vtkErrorMacro(<< "Unrecognized file type: "<< line << " for file: "
    2362                       << (this->FileName?this->FileName:"(Null FileName)"));
    2363         _fileType = 0;
    2364         return false;
    2365     }
    2366 
    2367     // Read dataset type
    2368     line = getline(&p, endPtr);
    2369     if (line == endPtr) {
    2370         vtkErrorMacro(<<"Premature EOF reading file type!" << " for file: "
    2371                       << (this->FileName?this->FileName:"(Null FileName)"));
    2372         return false;
    2373     }
    2374     word = GetWord(line, &endPtr);
    2375     if (strncasecmp(word, "dataset", 7) == 0) {
    2376         // Read dataset type
    2377         line = getline(&p, endPtr);
    2378         if (line == endPtr) {
    2379             // EOF
    2380         }
    2381         type = GetWord(line, &endPtr);
    2382         if (strncasecmp(word, "structured_grid", 15) == 0) {
    2383             vtkErrorMacro(<< "Cannot read dataset type: " << line);
    2384             return 1;
    2385         }
    2386         // Read keyword and dimensions
    2387         //
    2388         while (!done) {
    2389             if (!this->ReadString(line)) {
    2390                 break;
    2391             }
    2392 
    2393             // Have to read field data because it may be binary.
    2394             if (! strncmp(this->LowerCase(line), "field", 5)) {
    2395                 vtkFieldData* fd = this->ReadFieldData();
    2396                 fd->Delete();
    2397             }
    2398 
    2399             if ( ! strncmp(this->LowerCase(line),"dimensions",10) ) {
    2400                 int ext[6];
    2401                 if (!(this->Read(ext+1) &&
    2402                       this->Read(ext+3) &&
    2403                       this->Read(ext+5))) {
    2404                     vtkErrorMacro(<<"Error reading dimensions!");
    2405                     this->CloseVTKFile ();
    2406                     return 1;
    2407                 }
    2408                 // read dimensions, change to extent;
    2409                 ext[0] = ext[2] = ext[4] = 0;
    2410                 --ext[1];
    2411                 --ext[3];
    2412                 --ext[5];
    2413                 outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(),
    2414                              ext, 6);
    2415                 // That is all we wanted !!!!!!!!!!!!!!!
    2416                 this->CloseVTKFile();
    2417                 return 1;
    2418             }
    2419         }
    2420     }
    2421 
    2422     float progress = this->GetProgress();
    2423     this->UpdateProgress(progress + 0.5*(1.0 - progress));
    2424 
    2425     return 1;
    2426 }
    2427 #endif
     1968    return TCL_OK;
     1969}
Note: See TracChangeset for help on using the changeset viewer.