Ignore:
Timestamp:
Mar 4, 2008 4:34:30 PM (16 years ago)
Author:
gah
Message:

more clean up

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/vizservers/nanovis/Command.cpp

    r913 r915  
    2424/*
    2525 * TODO:  In no particular order...
    26  *        o Convert to Tcl_CmdObj interface. (done)
     26 *        x Convert to Tcl_CmdObj interface. (done)
    2727 *        o Use Tcl command option parser to reduce size of procedures, remove
    28  *          lots of extra error checking code.
     28 *          lots of extra error checking code. (almost there)
    2929 *        o Convert GetVolumeIndices to GetVolumes.  Goal is to remove
    3030 *          all references of Nanovis::volume[] from this file.  Don't
    31  *          want to know how volumes are stored. Same for heightmaps.
     31 *          want to know how volumes are stored. Same for heightmaps. 
    3232 *        o Rationalize volume id scheme. Right now it's the index in
    3333 *          the vector. 1) Use a list instead of a vector. 2) carry
    3434 *          an id field that's a number that gets incremented each new volume.
    35  *        o Create R2, matrix, etc. libraries.
     35 *        x Create R2, matrix, etc. libraries. (done)
     36 *        o Add bookkeeping for volumes, heightmaps, flows, etc. to track
     37 *          1) id #  2) simulation # 3) include/exclude.  The include/exclude
     38 *          is to indicate whether the item should contribute to the overall
     39 *          limits of the axes.
    3640 */
    3741
    3842#define ISO_TEST                1
    39 #define PLANE_CMDS              0
     43#define PLANE_CMD               0
    4044#define __TEST_CODE__           0
    4145// FOR testing new functions
     
    135139static Tcl_ObjCmdProc GridCmd;
    136140static Tcl_ObjCmdProc LegendCmd;
    137 #if PLANE_CMDS
    138 static Tcl_ObjCmdProc PlaneEnableCmd;
    139 static Tcl_ObjCmdProc PlaneLinkCmd;
    140 static Tcl_ObjCmdProc PlaneNewCmd;
     141#if PLANE_CMD
     142static Tcl_ObjCmdProc PlaneCmd;
    141143#endif
    142144static Tcl_ObjCmdProc ScreenCmd;
     
    272274}
    273275
     276
     277/*
     278 * -----------------------------------------------------------------------
     279 *
     280 * CreateHeightMap --
     281 *
     282 *      Creates a heightmap from the given the data. The format of the data
     283 *      should be as follows:
     284 *
     285 *              xMin, xMax, xNum, yMin, yMax, yNum, heights...
     286 *
     287 *      xNum and yNum must be integer values, all others are real numbers.
     288 *      The number of heights must be xNum * yNum;
     289 *
     290 * -----------------------------------------------------------------------
     291 */
     292static HeightMap *
     293CreateHeightMap(ClientData clientData, Tcl_Interp *interp, int objc,
     294                Tcl_Obj *CONST *objv)
     295{
     296    float xMin, yMin, xMax, yMax;
     297    int xNum, yNum;
     298
     299    if (objc != 7) {
     300        Tcl_AppendResult(interp,
     301        "wrong # of values: should be xMin yMin xMax yMax xNum yNum heights",
     302                (char *)NULL);
     303        return NULL;
     304    }
     305    if ((GetFloatFromObj(interp, objv[0], &xMin) != TCL_OK) ||
     306        (GetFloatFromObj(interp, objv[1], &yMin) != TCL_OK) ||
     307        (GetFloatFromObj(interp, objv[2], &xMax) != TCL_OK) ||
     308        (GetFloatFromObj(interp, objv[3], &yMax) != TCL_OK) ||
     309        (Tcl_GetIntFromObj(interp, objv[4], &xNum) != TCL_OK) ||
     310        (Tcl_GetIntFromObj(interp, objv[5], &yNum) != TCL_OK)) {
     311        return NULL;
     312    }
     313    int nValues;
     314    Tcl_Obj **elem;
     315    if (Tcl_ListObjGetElements(interp, objv[6], &nValues, &elem) != TCL_OK) {
     316        return NULL;
     317    }
     318    if ((xNum <= 0) || (yNum <= 0)) {
     319        Tcl_AppendResult(interp, "bad number of x or y values", (char *)NULL);
     320        return NULL;
     321    }
     322    if (nValues != (xNum * yNum)) {
     323        Tcl_AppendResult(interp, "wrong # of heights", (char *)NULL);
     324        return NULL;
     325    }
     326
     327    float *heights;
     328    heights = new float[nValues];
     329    if (heights == NULL) {
     330        Tcl_AppendResult(interp, "can't allocate array of heights",
     331                (char *)NULL);
     332        return NULL;
     333    }
     334
     335    int i;
     336    for (i = 0; i < nValues; i++) {
     337        if (GetFloatFromObj(interp, elem[i], heights + i) != TCL_OK) {
     338            delete [] heights;
     339            return NULL;
     340        }
     341    }
     342    HeightMap* hMap;
     343    hMap = new HeightMap();
     344    hMap->setHeight(xMin, yMin, xMax, yMax, xNum, yNum, heights);
     345    hMap->setColorMap(NanoVis::get_transfunc("default"));
     346    hMap->setVisible(true);
     347    hMap->setLineContourVisible(true);
     348    delete [] heights;
     349    return hMap;
     350}
     351
     352/*
     353 * ----------------------------------------------------------------------
     354 * FUNCTION: GetHeightMap
     355 *
     356 * Used internally to decode a series of volume index values and
     357 * store then in the specified vector.  If there are no volume index
     358 * arguments, this means "all volumes" to most commands, so all
     359 * active volume indices are stored in the vector.
     360 *
     361 * Updates pushes index values into the vector.  Returns TCL_OK or
     362 * TCL_ERROR to indicate an error.
     363 * ----------------------------------------------------------------------
     364 */
     365static int
     366GetHeightMap(Tcl_Interp *interp, Tcl_Obj *objPtr, HeightMap **hmPtrPtr)
     367{
     368    int mapIndex;
     369    if (Tcl_GetIntFromObj(interp, objPtr, &mapIndex) != TCL_OK) {
     370        return TCL_ERROR;
     371    }
     372    if ((mapIndex < 0) || (mapIndex >= (int)NanoVis::heightMap.size()) ||
     373        (NanoVis::heightMap[mapIndex] == NULL)) {
     374        Tcl_AppendResult(interp, "invalid heightmap index \"",
     375                Tcl_GetString(objPtr), "\"", (char *)NULL);
     376        return TCL_ERROR;
     377    }
     378    *hmPtrPtr = NanoVis::heightMap[mapIndex];
     379    return TCL_OK;
     380}
     381
     382/*
     383 * ----------------------------------------------------------------------
     384 * FUNCTION: GetVolumeIndex
     385 *
     386 * Used internally to decode a series of volume index values and
     387 * store then in the specified vector.  If there are no volume index
     388 * arguments, this means "all volumes" to most commands, so all
     389 * active volume indices are stored in the vector.
     390 *
     391 * Updates pushes index values into the vector.  Returns TCL_OK or
     392 * TCL_ERROR to indicate an error.
     393 * ----------------------------------------------------------------------
     394 */
     395static int
     396GetVolumeIndex(Tcl_Interp *interp, Tcl_Obj *objPtr, unsigned int *indexPtr)
     397{
     398    int index;
     399    if (Tcl_GetIntFromObj(interp, objPtr, &index) != TCL_OK) {
     400        return TCL_ERROR;
     401    }
     402    if (index < 0) {
     403        Tcl_AppendResult(interp, "can't have negative index \"",
     404                Tcl_GetString(objPtr), "\"", (char*)NULL);
     405        return TCL_ERROR;
     406    }
     407    if (index >= (int)NanoVis::volume.size()) {
     408        Tcl_AppendResult(interp, "index \"", Tcl_GetString(objPtr),
     409                         "\" is out of range", (char*)NULL);
     410        return TCL_ERROR;
     411    }
     412    *indexPtr = (unsigned int)index;
     413    return TCL_OK;
     414}
     415
     416/*
     417 * ----------------------------------------------------------------------
     418 * FUNCTION: GetVolumeFromObj
     419 *
     420 * Used internally to decode a series of volume index values and
     421 * store then in the specified vector.  If there are no volume index
     422 * arguments, this means "all volumes" to most commands, so all
     423 * active volume indices are stored in the vector.
     424 *
     425 * Updates pushes index values into the vector.  Returns TCL_OK or
     426 * TCL_ERROR to indicate an error.
     427 * ----------------------------------------------------------------------
     428 */
     429static int
     430GetVolumeFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, Volume **volPtrPtr)
     431{
     432    unsigned int index;
     433    if (GetVolumeIndex(interp, objPtr, &index) != TCL_OK) {
     434        return TCL_ERROR;
     435    }
     436    Volume *vol;
     437    vol = NanoVis::volume[index];
     438    if (vol == NULL) {
     439        Tcl_AppendResult(interp, "no volume defined for index \"",
     440                Tcl_GetString(objPtr), "\"", (char*)NULL);
     441        return TCL_ERROR;
     442    }
     443    *volPtrPtr = vol;
     444    return TCL_OK;
     445}
     446
     447/*
     448 * ----------------------------------------------------------------------
     449 * FUNCTION: GetVolumeIndices()
     450 *
     451 * Used internally to decode a series of volume index values and
     452 * store then in the specified vector.  If there are no volume index
     453 * arguments, this means "all volumes" to most commands, so all
     454 * active volume indices are stored in the vector.
     455 *
     456 * Updates pushes index values into the vector.  Returns TCL_OK or
     457 * TCL_ERROR to indicate an error.
     458 * ----------------------------------------------------------------------
     459 */
     460static int
     461GetVolumeIndices(Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv,
     462    vector<unsigned int>* vectorPtr)
     463{
     464    if (objc == 0) {
     465        for (unsigned int n = 0; n < NanoVis::volume.size(); n++) {
     466            if (NanoVis::volume[n] != NULL) {
     467                vectorPtr->push_back(n);
     468            }
     469        }
     470    } else {
     471        for (int n = 0; n < objc; n++) {
     472            unsigned int index;
     473
     474            if (GetVolumeIndex(interp, objv[n], &index) != TCL_OK) {
     475                return TCL_ERROR;
     476            }
     477            if (index < NanoVis::volume.size() && NanoVis::volume[index] != NULL) {
     478                vectorPtr->push_back(index);
     479            }
     480        }
     481    }
     482    return TCL_OK;
     483}
     484
     485static int
     486GetIndices(Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv,
     487    vector<unsigned int>* vectorPtr)
     488{
     489    for (int n = 0; n < objc; n++) {
     490        int index;
     491
     492        if (Tcl_GetIntFromObj(interp, objv[n], &index) != TCL_OK) {
     493            return TCL_ERROR;
     494        }
     495        if (index < 0) {
     496            Tcl_AppendResult(interp, "can't have negative index \"",
     497                Tcl_GetString(objv[n]), "\"", (char *)NULL);
     498            return TCL_ERROR;
     499        }
     500        vectorPtr->push_back((unsigned int)index);
     501    }
     502    return TCL_OK;
     503}
     504
     505
     506/*
     507 * ----------------------------------------------------------------------
     508 * FUNCTION: GetVolumes()
     509 *
     510 * Used internally to decode a series of volume index values and
     511 * store then in the specified vector.  If there are no volume index
     512 * arguments, this means "all volumes" to most commands, so all
     513 * active volume indices are stored in the vector.
     514 *
     515 * Updates pushes index values into the vector.  Returns TCL_OK or
     516 * TCL_ERROR to indicate an error.
     517 * ----------------------------------------------------------------------
     518 */
     519static int
     520GetVolumes(Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv,
     521    vector<Volume *>* vectorPtr)
     522{
     523    if (objc == 0) {
     524        for (unsigned int n = 0; n < NanoVis::volume.size(); n++) {
     525            if (NanoVis::volume[n] != NULL) {
     526                vectorPtr->push_back(NanoVis::volume[n]);
     527            }
     528        }
     529    } else {
     530        for (int n = 0; n < objc; n++) {
     531            Volume *volPtr;
     532
     533            if (GetVolumeFromObj(interp, objv[n], &volPtr) != TCL_OK) {
     534                return TCL_ERROR;
     535            }
     536            if (volPtr != NULL) {
     537                vectorPtr->push_back(volPtr);
     538            }
     539        }
     540    }
     541    return TCL_OK;
     542}
     543
     544
     545/*
     546 * ----------------------------------------------------------------------
     547 * FUNCTION: GetAxis()
     548 *
     549 * Used internally to decode an axis value from a string ("x", "y",
     550 * or "z") to its index (0, 1, or 2).  Returns TCL_OK if successful,
     551 * along with a value in valPtr.  Otherwise, it returns TCL_ERROR
     552 * and an error message in the interpreter.
     553 * ----------------------------------------------------------------------
     554 */
     555static int
     556GetAxis(Tcl_Interp *interp, const char *string, int *indexPtr)
     557{
     558    if (string[1] == '\0') {
     559        char c;
     560
     561        c = tolower((unsigned char)string[0]);
     562        if (c == 'x') {
     563            *indexPtr = 0;
     564            return TCL_OK;
     565        } else if (c == 'y') {
     566            *indexPtr = 1;
     567            return TCL_OK;
     568        } else if (c == 'z') {
     569            *indexPtr = 2;
     570            return TCL_OK;
     571        }
     572        /*FALLTHRU*/
     573    }
     574    Tcl_AppendResult(interp, "bad axis \"", string,
     575        "\": should be x, y, or z", (char*)NULL);
     576    return TCL_ERROR;
     577}
     578
     579/*
     580 * ----------------------------------------------------------------------
     581 * FUNCTION: GetAxisFromObj()
     582 *
     583 * Used internally to decode an axis value from a string ("x", "y",
     584 * or "z") to its index (0, 1, or 2).  Returns TCL_OK if successful,
     585 * along with a value in indexPtr.  Otherwise, it returns TCL_ERROR
     586 * and an error message in the interpreter.
     587 * ----------------------------------------------------------------------
     588 */
     589static int
     590GetAxisFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, int *indexPtr)
     591{
     592    return GetAxis(interp, Tcl_GetString(objPtr), indexPtr);
     593}
     594
     595/*
     596 * ----------------------------------------------------------------------
     597 * FUNCTION: GetAxisDirFromObj()
     598 *
     599 * Used internally to decode an axis value from a string ("x", "y",
     600 * or "z") to its index (0, 1, or 2).  Returns TCL_OK if successful,
     601 * along with a value in indexPtr.  Otherwise, it returns TCL_ERROR
     602 * and an error message in the interpreter.
     603 * ----------------------------------------------------------------------
     604 */
     605static int
     606GetAxisDirFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, int *indexPtr, int *dirPtr)
     607{
     608    char *string = Tcl_GetString(objPtr);
     609
     610    int sign = 1;
     611    if (*string == '-') {
     612        sign = -1;
     613        string++;
     614    }
     615    if (GetAxis(interp, string, indexPtr) != TCL_OK) {
     616        return TCL_ERROR;
     617    }
     618    if (dirPtr != NULL) {
     619        *dirPtr = sign;
     620    }
     621    return TCL_OK;
     622}
     623
     624/*
     625 * ----------------------------------------------------------------------
     626 * FUNCTION: GetColor()
     627 *
     628 * Used internally to decode a color value from a string ("R G B")
     629 * as a list of three numbers 0-1.  Returns TCL_OK if successful,
     630 * along with RGB values in rgbPtr.  Otherwise, it returns TCL_ERROR
     631 * and an error message in the interpreter.
     632 * ----------------------------------------------------------------------
     633 */
     634static int
     635GetColor(Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv, float *rgbPtr)
     636{
     637    if (objc < 3) {
     638        Tcl_AppendResult(interp, "missing color values\": ",
     639                "should list of R G B values 0.0 - 1.0", (char*)NULL);
     640        return TCL_ERROR;
     641    }
     642    if ((GetFloatFromObj(interp, objv[0], rgbPtr + 0) != TCL_OK) ||
     643        (GetFloatFromObj(interp, objv[1], rgbPtr + 1) != TCL_OK) ||
     644        (GetFloatFromObj(interp, objv[2], rgbPtr + 2) != TCL_OK)) {
     645        return TCL_ERROR;
     646    }
     647    return TCL_OK;
     648}
     649
     650
     651/*
     652 * -----------------------------------------------------------------------
     653 *
     654 * GetDataStream --
     655 *
     656 *      Read the requested number of bytes from standard input into the given
     657 *      buffer.  The buffer is then decompressed and decoded.
     658 *
     659 * -----------------------------------------------------------------------
     660 */
     661static int
     662GetDataStream(Tcl_Interp *interp, Rappture::Buffer &buf, int nBytes)
     663{
     664    char buffer[8096];
     665
     666    clearerr(stdin);
     667    while (nBytes > 0) {
     668        unsigned int chunk;
     669        int nRead;
     670
     671        chunk = (sizeof(buffer) < (unsigned int) nBytes) ?
     672            sizeof(buffer) : nBytes;
     673        nRead = fread(buffer, sizeof(char), chunk, stdin);
     674        if (ferror(stdin)) {
     675            Tcl_AppendResult(interp, "while reading data stream: ",
     676                Tcl_PosixError(interp), (char*)NULL);
     677            return TCL_ERROR;
     678        }
     679        if (feof(stdin)) {
     680            Tcl_AppendResult(interp, "premature EOF while reading data stream",
     681                (char*)NULL);
     682            return TCL_ERROR;
     683        }
     684        buf.append(buffer, nRead);
     685        nBytes -= nRead;
     686    }
     687    {
     688        Rappture::Outcome err;
     689
     690        err = Rappture::encoding::decode(buf, RPENC_Z|RPENC_B64|RPENC_HDR);
     691        if (err) {
     692            printf("ERROR -- DECODING\n");
     693            fflush(stdout);
     694            Tcl_AppendResult(interp, err.remark().c_str(), (char*)NULL);
     695            return TCL_ERROR;
     696        }
     697    }
     698    return TCL_OK;
     699}
     700
     701static int
     702CameraAimOp(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv)
     703{
     704    double x0, y0, z0;
     705    if ((Tcl_GetDoubleFromObj(interp, objv[2], &x0) != TCL_OK) ||
     706        (Tcl_GetDoubleFromObj(interp, objv[3], &y0) != TCL_OK) ||
     707        (Tcl_GetDoubleFromObj(interp, objv[4], &z0) != TCL_OK)) {
     708        return TCL_ERROR;
     709    }
     710    NanoVis::cam->aim(x0, y0, z0);
     711    return TCL_OK;
     712}
     713
     714static int
     715CameraAngleOp(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv)
     716{
     717    double xangle, yangle, zangle;
     718    if ((Tcl_GetDoubleFromObj(interp, objv[2], &xangle) != TCL_OK) ||
     719        (Tcl_GetDoubleFromObj(interp, objv[3], &yangle) != TCL_OK) ||
     720        (Tcl_GetDoubleFromObj(interp, objv[4], &zangle) != TCL_OK)) {
     721        return TCL_ERROR;
     722    }
     723    NanoVis::cam->rotate(xangle, yangle, zangle);
     724    return TCL_OK;
     725}
     726
     727static int
     728CameraZoomOp(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv)
     729{
     730    double zoom;
     731    if (Tcl_GetDoubleFromObj(interp, objv[2], &zoom) != TCL_OK) {
     732        return TCL_ERROR;
     733    }
     734    NanoVis::zoom(zoom);
     735    return TCL_OK;
     736}
     737
     738static Rappture::CmdSpec cameraOps[] =
     739{
     740    {"aim",     2, CameraAimOp,      5, 5, "x y z",},
     741    {"angle",   2, CameraAngleOp,    5, 5, "xAngle yAngle zAngle",},
     742    {"zoom",    1, CameraZoomOp,     3, 3, "factor",},
     743};
     744static int nCameraOps = NumCmdSpecs(cameraOps);
     745
    274746/*
    275747 * ----------------------------------------------------------------------
     
    288760CameraCmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv)
    289761{
    290     if (objc < 2) {
    291         Tcl_AppendResult(interp, "wrong # args: should be \"",
    292                 Tcl_GetString(objv[0]), " option arg arg...\"", (char*)NULL);
    293         return TCL_ERROR;
    294     }
    295 
    296     char *string = Tcl_GetString(objv[1]);
    297     char c = string[0];
    298     if ((c == 'a') && (strcmp(string, "angle") == 0)) {
    299         if (objc != 5) {
    300             Tcl_AppendResult(interp, "wrong # args: should be \"",
    301                 Tcl_GetString(objv[0]), " angle xangle yangle zangle\"",
    302                 (char*)NULL);
    303             return TCL_ERROR;
    304         }
    305         double xangle, yangle, zangle;
    306         if ((Tcl_GetDoubleFromObj(interp, objv[2], &xangle) != TCL_OK) ||
    307             (Tcl_GetDoubleFromObj(interp, objv[3], &yangle) != TCL_OK) ||
    308             (Tcl_GetDoubleFromObj(interp, objv[4], &zangle) != TCL_OK)) {
    309             return TCL_ERROR;
    310         }
    311         NanoVis::cam->rotate(xangle, yangle, zangle);
    312     } else if ((c == 'a') && (strcmp(string, "aim") == 0)) {
    313         if (objc != 5) {
    314             Tcl_AppendResult(interp, "wrong # args: should be \"",
    315                 Tcl_GetString(objv[0]), " aim x y z\"", (char*)NULL);
    316             return TCL_ERROR;
    317         }
    318         double x0, y0, z0;
    319         if ((Tcl_GetDoubleFromObj(interp, objv[2], &x0) != TCL_OK) ||
    320             (Tcl_GetDoubleFromObj(interp, objv[3], &y0) != TCL_OK) ||
    321             (Tcl_GetDoubleFromObj(interp, objv[4], &z0) != TCL_OK)) {
    322             return TCL_ERROR;
    323         }
    324         NanoVis::cam->aim(x0, y0, z0);
    325     } else if ((c == 'z') && (strcmp(string, "zoom") == 0)) {
    326         if (objc != 3) {
    327             Tcl_AppendResult(interp, "wrong # args: should be \"",
    328                 Tcl_GetString(objv[0]), " zoom factor\"", (char*)NULL);
    329             return TCL_ERROR;
    330         }
    331        
    332         double zoom;
    333         if (Tcl_GetDoubleFromObj(interp, objv[2], &zoom) != TCL_OK) {
    334             return TCL_ERROR;
    335         }
    336         NanoVis::zoom(zoom);
    337     } else {
    338         Tcl_AppendResult(interp, "bad camera option \"", string,
    339                      "\": should be aim, angle, or zoom", (char*)NULL);
    340         return TCL_ERROR;
    341     }
    342 
    343     /*
    344     Trace("Camera pos(%f %f %f), rot(%f %f %f), aim(%f %f %f)\n",
    345             NanoVis::cam->location.x, NanoVis::cam->location.y, NanoVis::cam->location.z,
    346             NanoVis::cam->angle.x, NanoVis::cam->angle.y, NanoVis::cam->angle.z,
    347             NanoVis::cam->target.x, NanoVis::cam->target.y, NanoVis::cam->target.z);
    348 
    349     NanoVis::cam->aim(0, 0, 100);
    350     NanoVis::cam->rotate(-51.868206, 88.637497, 0.000000);
    351     NanoVis::cam->move(-0.000000, -0.000000, -0.819200);
    352     */
    353 
    354     return TCL_OK;
     762    Tcl_ObjCmdProc *proc;
     763
     764    proc = Rappture::GetOpFromObj(interp, nCameraOps, cameraOps,
     765                Rappture::CMDSPEC_ARG1, objc, objv, 0);
     766    if (proc == NULL) {
     767        return TCL_ERROR;
     768    }
     769    return (*proc) (cdata, interp, objc, objv);
    355770}
    356771
     
    390805}
    391806
     807static int
     808CutplanePositionOp(ClientData cdata, Tcl_Interp *interp, int objc,
     809                   Tcl_Obj *CONST *objv)
     810{
     811    float relval;
     812    if (GetFloatFromObj(interp, objv[2], &relval) != TCL_OK) {
     813        return TCL_ERROR;
     814    }
     815   
     816    // keep this just inside the volume so it doesn't disappear
     817    if (relval < 0.01f) {
     818        relval = 0.01f;
     819    } else if (relval > 0.99f) {
     820        relval = 0.99f;
     821    }
     822   
     823    int axis;
     824    if (GetAxisFromObj(interp, objv[3], &axis) != TCL_OK) {
     825        return TCL_ERROR;
     826    }
     827   
     828    vector<Volume *> ivol;
     829    if (GetVolumes(interp, objc-4, objv+4, &ivol) != TCL_OK) {
     830        return TCL_ERROR;
     831    }
     832    vector<Volume *>::iterator iter;
     833    for (iter = ivol.begin(); iter != ivol.end(); iter++) {
     834        (*iter)->move_cutplane(axis, relval);
     835    }
     836    return TCL_OK;
     837}
     838
     839static int
     840CutplaneStateOp(ClientData cdata, Tcl_Interp *interp, int objc,
     841                Tcl_Obj *CONST *objv)
     842{
     843    int state;
     844    if (Tcl_GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
     845        return TCL_ERROR;
     846    }
     847   
     848    int axis;
     849    if (GetAxisFromObj(interp, objv[3], &axis) != TCL_OK) {
     850        return TCL_ERROR;
     851    }
     852   
     853    vector<Volume *> ivol;
     854    if (GetVolumes(interp, objc - 4, objv + 4, &ivol) != TCL_OK) {
     855        return TCL_ERROR;
     856    }
     857    if (state) {
     858        vector<Volume *>::iterator iter;
     859        for (iter = ivol.begin(); iter != ivol.end(); iter++) {
     860            (*iter)->enable_cutplane(axis);
     861        }
     862    } else {
     863        vector<Volume *>::iterator iter;
     864        for (iter = ivol.begin(); iter != ivol.end(); iter++) {
     865            (*iter)->disable_cutplane(axis);
     866        }
     867    }
     868    return TCL_OK;
     869}
     870
     871static Rappture::CmdSpec cutplaneOps[] =
     872{
     873    {"position", 1, CutplanePositionOp, 4, 4, "bool axis ?indices?",},
     874    {"state",    1, CutplaneStateOp,    4, 0, "relval axis ?indices?",},
     875};
     876static int nCutplaneOps = NumCmdSpecs(cutplaneOps);
     877
    392878/*
    393879 * ----------------------------------------------------------------------
     
    408894CutplaneCmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv)
    409895{
    410     if (objc < 2) {
    411         Tcl_AppendResult(interp, "wrong # args: should be \"",
    412                 Tcl_GetString(objv[0]), " option ?arg arg...?\"", (char*)NULL);
    413         return TCL_ERROR;
    414     }
    415 
    416     char *string = Tcl_GetString(objv[1]);
    417     char c = string[0];
    418     if ((c == 's') && (strcmp(string, "state") == 0)) {
    419         if (objc < 4) {
    420             Tcl_AppendResult(interp, "wrong # args: should be \"",
    421                 Tcl_GetString(objv[0]), " state on|off axis ?volume ...? \"",
    422                 (char*)NULL);
    423             return TCL_ERROR;
    424         }
    425 
    426         int state;
    427         if (Tcl_GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
    428             return TCL_ERROR;
    429         }
    430 
    431         int axis;
    432         if (GetAxisFromObj(interp, objv[3], &axis) != TCL_OK) {
    433             return TCL_ERROR;
    434         }
    435 
    436         vector<Volume *> ivol;
    437         if (GetVolumes(interp, objc - 4, objv + 4, &ivol) != TCL_OK) {
    438             return TCL_ERROR;
    439         }
    440         if (state) {
    441             vector<Volume *>::iterator iter;
    442             for (iter = ivol.begin(); iter != ivol.end(); iter++) {
    443                 (*iter)->enable_cutplane(axis);
    444             }
    445         } else {
    446             vector<Volume *>::iterator iter;
    447             for (iter = ivol.begin(); iter != ivol.end(); iter++) {
    448                 (*iter)->disable_cutplane(axis);
    449             }
    450         }
    451     } else if ((c == 'p') && (strcmp(string, "position") == 0)) {
    452         if (objc < 4) {
    453             Tcl_AppendResult(interp, "wrong # args: should be \"",
    454                 Tcl_GetString(objv[0]), " position relval axis ?volume ...? \"",
    455                 (char*)NULL);
    456             return TCL_ERROR;
    457         }
    458 
    459         float relval;
    460         if (GetFloatFromObj(interp, objv[2], &relval) != TCL_OK) {
    461             return TCL_ERROR;
    462         }
    463 
    464         // keep this just inside the volume so it doesn't disappear
    465         if (relval < 0.01f) {
    466             relval = 0.01f;
    467         } else if (relval > 0.99f) {
    468             relval = 0.99f;
    469         }
    470 
    471         int axis;
    472         if (GetAxisFromObj(interp, objv[3], &axis) != TCL_OK) {
    473             return TCL_ERROR;
    474         }
    475 
    476         vector<Volume *> ivol;
    477         if (GetVolumes(interp, objc-4, objv+4, &ivol) != TCL_OK) {
    478             return TCL_ERROR;
    479         }
    480         vector<Volume *>::iterator iter;
    481         for (iter = ivol.begin(); iter != ivol.end(); iter++) {
    482             (*iter)->move_cutplane(axis, relval);
    483         }
    484     } else {
    485         Tcl_AppendResult(interp, "bad option \"", string,
    486                          "\": should be position or state", (char*)NULL);
    487         return TCL_ERROR;
    488     }
    489     return TCL_OK;
     896    Tcl_ObjCmdProc *proc;
     897
     898    proc = Rappture::GetOpFromObj(interp, nCutplaneOps, cutplaneOps,
     899                Rappture::CMDSPEC_ARG1, objc, objv, 0);
     900    if (proc == NULL) {
     901        return TCL_ERROR;
     902    }
     903    return (*proc) (cdata, interp, objc, objv);
    490904}
    491905
     
    506920    if (objc != 4) {
    507921        Tcl_AppendResult(interp, "wrong # args: should be \"",
    508                 Tcl_GetString(objv[0]), " transfunc width height\"", (char*)NULL);
     922                Tcl_GetString(objv[0]), " volIndex width height\"", (char*)NULL);
    509923        return TCL_ERROR;
    510924    }
     
    17832197}
    17842198
     2199static int
     2200GridAxisColorOp(ClientData cdata, Tcl_Interp *interp, int objc,
     2201                Tcl_Obj *CONST *objv)
     2202{
     2203    float r, g, b, a;
     2204    if ((GetFloatFromObj(interp, objv[2], &r) != TCL_OK) ||
     2205        (GetFloatFromObj(interp, objv[3], &g) != TCL_OK) ||
     2206        (GetFloatFromObj(interp, objv[4], &b) != TCL_OK)) {
     2207        return TCL_ERROR;
     2208    }
     2209    a = 1.0f;
     2210    if ((objc == 6) && (GetFloatFromObj(interp, objv[5], &a) != TCL_OK)) {
     2211        return TCL_ERROR;
     2212    }           
     2213    if (NanoVis::grid) {
     2214        NanoVis::grid->setAxisColor(r, g, b, a);
     2215    }
     2216    return TCL_OK;
     2217}
     2218
     2219static int
     2220GridAxisNameOp(ClientData cdata, Tcl_Interp *interp, int objc,
     2221                Tcl_Obj *CONST *objv)
     2222{
     2223    int axisId;
     2224    if (GetAxisFromObj(interp, objv[2], &axisId) != TCL_OK) {
     2225        return TCL_ERROR;
     2226    }
     2227    if (NanoVis::grid) {
     2228        NanoVis::grid->setAxisName(axisId, Tcl_GetString(objv[3]));
     2229    }
     2230    return TCL_OK;
     2231}
     2232
     2233static int
     2234GridLineColorOp(ClientData cdata, Tcl_Interp *interp, int objc,
     2235                Tcl_Obj *CONST *objv)
     2236{
     2237    float r, g, b, a;
     2238    if ((GetFloatFromObj(interp, objv[2], &r) != TCL_OK) ||
     2239        (GetFloatFromObj(interp, objv[3], &g) != TCL_OK) ||
     2240        (GetFloatFromObj(interp, objv[4], &b) != TCL_OK)) {
     2241        return TCL_ERROR;
     2242    }
     2243    a = 1.0f;
     2244    if ((objc == 6) && (GetFloatFromObj(interp, objv[5], &a) != TCL_OK)) {
     2245        return TCL_ERROR;
     2246    }           
     2247    if (NanoVis::grid) {
     2248        NanoVis::grid->setGridLineColor(r, g, b, a);
     2249    }
     2250    return TCL_OK;
     2251}
     2252
     2253static int
     2254GridLineCountOp(ClientData cdata, Tcl_Interp *interp, int objc,
     2255                Tcl_Obj *CONST *objv)
     2256{
     2257    int x, y, z;
     2258   
     2259    if ((Tcl_GetIntFromObj(interp, objv[2], &x) != TCL_OK) ||
     2260        (Tcl_GetIntFromObj(interp, objv[3], &y) != TCL_OK) ||
     2261        (Tcl_GetIntFromObj(interp, objv[4], &z) != TCL_OK)) {
     2262        return TCL_ERROR;
     2263    }
     2264    if (NanoVis::grid) {
     2265        NanoVis::grid->setGridLineCount(x, y, z);
     2266    }
     2267    return TCL_OK;
     2268}
     2269
     2270static int
     2271GridMinMaxOp(ClientData cdata, Tcl_Interp *interp, int objc,
     2272             Tcl_Obj *CONST *objv)
     2273{
     2274    double x1, y1, z1, x2, y2, z2;
     2275    if ((Tcl_GetDoubleFromObj(interp, objv[2], &x1) != TCL_OK) ||
     2276        (Tcl_GetDoubleFromObj(interp, objv[3], &y1) != TCL_OK) ||
     2277        (Tcl_GetDoubleFromObj(interp, objv[4], &z1) != TCL_OK) ||
     2278        (Tcl_GetDoubleFromObj(interp, objv[5], &x2) != TCL_OK) ||
     2279        (Tcl_GetDoubleFromObj(interp, objv[6], &y2) != TCL_OK) ||
     2280        (Tcl_GetDoubleFromObj(interp, objv[7], &z2) != TCL_OK)) {
     2281        return TCL_ERROR;
     2282    }
     2283    if (NanoVis::grid) {
     2284        NanoVis::grid->setMinMax(Vector3(x1, y1, z1), Vector3(x2, y2, z2));
     2285    }
     2286    return TCL_OK;
     2287}
     2288
     2289static int
     2290GridVisibleOp(ClientData cdata, Tcl_Interp *interp, int objc,
     2291             Tcl_Obj *CONST *objv)
     2292{
     2293    int ivisible;
     2294   
     2295    if (Tcl_GetBooleanFromObj(interp, objv[2], &ivisible) != TCL_OK) {
     2296        return TCL_ERROR;
     2297    }
     2298    NanoVis::grid->setVisible((bool)ivisible);
     2299    return TCL_OK;
     2300}
     2301
     2302static Rappture::CmdSpec gridOps[] =
     2303{
     2304    {"axiscolor",  5, GridAxisColorOp,  5, 6, "r g b ?a?",},
     2305    {"axisname",   5, GridAxisNameOp,   5, 5, "index width height",},
     2306    {"linecolor",  7, GridLineColorOp,  5, 6, "r g b ?a?",},
     2307    {"linecount",  7, GridLineCountOp,  5, 5, "xCount yCount zCount",},
     2308    {"minmax",     1, GridMinMaxOp,     8, 8, "xMin yMin zMin xMax yMax zMax",},
     2309    {"visible",    1, GridVisibleOp,    3, 3, "bool",},
     2310};
     2311static int nGridOps = NumCmdSpecs(gridOps);
     2312
    17852313static int
    17862314GridCmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv)
    1787 {
    1788     if (objc < 2) {
    1789         Tcl_AppendResult(interp, "wrong # args: should be \"",
    1790                 Tcl_GetString(objv[0]), " option ?args?", (char *)NULL);
    1791         return TCL_ERROR;
    1792     }
    1793     char *string = Tcl_GetString(objv[1]);
    1794     char c = string[0];
    1795     if ((c == 'v') && (strcmp(string,"visible") == 0)) {
    1796         int ivisible;
    1797 
    1798         if (Tcl_GetBooleanFromObj(interp, objv[2], &ivisible) != TCL_OK) {
    1799             return TCL_ERROR;
    1800         }
    1801         NanoVis::grid->setVisible((bool)ivisible);
    1802     } else if ((c == 'l') && (strcmp(string, "linecount") == 0)) {
    1803         int x, y, z;
    1804 
    1805         if ((Tcl_GetIntFromObj(interp, objv[2], &x) != TCL_OK) ||
    1806             (Tcl_GetIntFromObj(interp, objv[3], &y) != TCL_OK) ||
    1807             (Tcl_GetIntFromObj(interp, objv[4], &z) != TCL_OK)) {
    1808             return TCL_ERROR;
    1809         }
    1810         if (NanoVis::grid) {
    1811             NanoVis::grid->setGridLineCount(x, y, z);
    1812         }
    1813     } else if ((c == 'a') && (strcmp(string, "axiscolor") == 0)) {
    1814         float r, g, b, a;
    1815         if ((GetFloatFromObj(interp, objv[2], &r) != TCL_OK) ||
    1816             (GetFloatFromObj(interp, objv[3], &g) != TCL_OK) ||
    1817             (GetFloatFromObj(interp, objv[4], &b) != TCL_OK)) {
    1818             return TCL_ERROR;
    1819         }
    1820         a = 1.0f;
    1821         if ((objc == 6) && (GetFloatFromObj(interp, objv[5], &a) != TCL_OK)) {
    1822             return TCL_ERROR;
    1823         }           
    1824         if (NanoVis::grid) {
    1825             NanoVis::grid->setAxisColor(r, g, b, a);
    1826         }
    1827     } else if ((c == 'l') && (strcmp(string, "linecolor") == 0)) {
    1828         float r, g, b, a;
    1829         if ((GetFloatFromObj(interp, objv[2], &r) != TCL_OK) ||
    1830             (GetFloatFromObj(interp, objv[3], &g) != TCL_OK) ||
    1831             (GetFloatFromObj(interp, objv[4], &b) != TCL_OK)) {
    1832             return TCL_ERROR;
    1833         }
    1834         a = 1.0f;
    1835         if ((objc == 6) && (GetFloatFromObj(interp, objv[5], &a) != TCL_OK)) {
    1836             return TCL_ERROR;
    1837         }           
    1838         if (NanoVis::grid) {
    1839             NanoVis::grid->setGridLineColor(r, g, b, a);
    1840         }
    1841     } else if ((c == 'm') && (strcmp(string, "minmax") == 0)) {
    1842         double x1, y1, z1, x2, y2, z2;
    1843         if ((Tcl_GetDoubleFromObj(interp, objv[2], &x1) != TCL_OK) ||
    1844             (Tcl_GetDoubleFromObj(interp, objv[3], &y1) != TCL_OK) ||
    1845             (Tcl_GetDoubleFromObj(interp, objv[4], &z1) != TCL_OK) ||
    1846             (Tcl_GetDoubleFromObj(interp, objv[5], &x2) != TCL_OK) ||
    1847             (Tcl_GetDoubleFromObj(interp, objv[6], &y2) != TCL_OK) ||
    1848             (Tcl_GetDoubleFromObj(interp, objv[7], &z2) != TCL_OK)) {
    1849             return TCL_ERROR;
    1850         }
    1851         if (NanoVis::grid) {
    1852             NanoVis::grid->setMinMax(Vector3(x1, y1, z1), Vector3(x2, y2, z2));
    1853         }
    1854     } else if ((c == 'a') && (strcmp(string, "axisname") == 0)) {
    1855         int axisId;
    1856         if (GetAxisFromObj(interp, objv[2], &axisId) != TCL_OK) {
    1857             return TCL_ERROR;
    1858         }
    1859         if (NanoVis::grid) {
    1860             NanoVis::grid->setAxisName(axisId, Tcl_GetString(objv[3]));
    1861         }
    1862     } else {
    1863         Tcl_AppendResult(interp, "bad option \"", Tcl_GetString(objv[1]),
    1864                          "\": should be data, outline, shading, or state",
    1865                          (char*)NULL);
    1866         return TCL_ERROR;
    1867     }
    1868     return TCL_OK;
     2315{
     2316    Tcl_ObjCmdProc *proc;
     2317
     2318    proc = Rappture::GetOpFromObj(interp, nGridOps, gridOps,
     2319        Rappture::CMDSPEC_ARG1, objc, objv, 0);
     2320    if (proc == NULL) {
     2321        return TCL_ERROR;
     2322    }
     2323    return (*proc) (cdata, interp, objc, objv);
    18692324}
    18702325
     
    18942349}
    18952350
    1896 /*
    1897  * ----------------------------------------------------------------------
    1898  * FUNCTION: GetHeightMap
    1899  *
    1900  * Used internally to decode a series of volume index values and
    1901  * store then in the specified vector.  If there are no volume index
    1902  * arguments, this means "all volumes" to most commands, so all
    1903  * active volume indices are stored in the vector.
    1904  *
    1905  * Updates pushes index values into the vector.  Returns TCL_OK or
    1906  * TCL_ERROR to indicate an error.
    1907  * ----------------------------------------------------------------------
    1908  */
    1909 static int
    1910 GetHeightMap(Tcl_Interp *interp, Tcl_Obj *objPtr, HeightMap **hmPtrPtr)
    1911 {
    1912     int mapIndex;
    1913     if (Tcl_GetIntFromObj(interp, objPtr, &mapIndex) != TCL_OK) {
    1914         return TCL_ERROR;
    1915     }
    1916     if ((mapIndex < 0) || (mapIndex >= (int)NanoVis::heightMap.size()) ||
    1917         (NanoVis::heightMap[mapIndex] == NULL)) {
    1918         Tcl_AppendResult(interp, "invalid heightmap index \"",
    1919                 Tcl_GetString(objPtr), "\"", (char *)NULL);
    1920         return TCL_ERROR;
    1921     }
    1922     *hmPtrPtr = NanoVis::heightMap[mapIndex];
    1923     return TCL_OK;
    1924 }
    1925 
    1926 /*
    1927  * ----------------------------------------------------------------------
    1928  * FUNCTION: GetVolumeIndex
    1929  *
    1930  * Used internally to decode a series of volume index values and
    1931  * store then in the specified vector.  If there are no volume index
    1932  * arguments, this means "all volumes" to most commands, so all
    1933  * active volume indices are stored in the vector.
    1934  *
    1935  * Updates pushes index values into the vector.  Returns TCL_OK or
    1936  * TCL_ERROR to indicate an error.
    1937  * ----------------------------------------------------------------------
    1938  */
    1939 static int
    1940 GetVolumeIndex(Tcl_Interp *interp, Tcl_Obj *objPtr, unsigned int *indexPtr)
    1941 {
    1942     int index;
    1943     if (Tcl_GetIntFromObj(interp, objPtr, &index) != TCL_OK) {
    1944         return TCL_ERROR;
    1945     }
    1946     if (index < 0) {
    1947         Tcl_AppendResult(interp, "can't have negative index \"",
    1948                 Tcl_GetString(objPtr), "\"", (char*)NULL);
    1949         return TCL_ERROR;
    1950     }
    1951     if (index >= (int)NanoVis::volume.size()) {
    1952         Tcl_AppendResult(interp, "index \"", Tcl_GetString(objPtr),
    1953                          "\" is out of range", (char*)NULL);
    1954         return TCL_ERROR;
    1955     }
    1956     *indexPtr = (unsigned int)index;
    1957     return TCL_OK;
    1958 }
    1959 
    1960 /*
    1961  * ----------------------------------------------------------------------
    1962  * FUNCTION: GetVolumeFromObj
    1963  *
    1964  * Used internally to decode a series of volume index values and
    1965  * store then in the specified vector.  If there are no volume index
    1966  * arguments, this means "all volumes" to most commands, so all
    1967  * active volume indices are stored in the vector.
    1968  *
    1969  * Updates pushes index values into the vector.  Returns TCL_OK or
    1970  * TCL_ERROR to indicate an error.
    1971  * ----------------------------------------------------------------------
    1972  */
    1973 static int
    1974 GetVolumeFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, Volume **volPtrPtr)
    1975 {
    1976     unsigned int index;
    1977     if (GetVolumeIndex(interp, objPtr, &index) != TCL_OK) {
    1978         return TCL_ERROR;
    1979     }
    1980     Volume *vol;
    1981     vol = NanoVis::volume[index];
    1982     if (vol == NULL) {
    1983         Tcl_AppendResult(interp, "no volume defined for index \"",
    1984                 Tcl_GetString(objPtr), "\"", (char*)NULL);
    1985         return TCL_ERROR;
    1986     }
    1987     *volPtrPtr = vol;
    1988     return TCL_OK;
    1989 }
    1990 
    1991 /*
    1992  * ----------------------------------------------------------------------
    1993  * FUNCTION: GetVolumeIndices()
    1994  *
    1995  * Used internally to decode a series of volume index values and
    1996  * store then in the specified vector.  If there are no volume index
    1997  * arguments, this means "all volumes" to most commands, so all
    1998  * active volume indices are stored in the vector.
    1999  *
    2000  * Updates pushes index values into the vector.  Returns TCL_OK or
    2001  * TCL_ERROR to indicate an error.
    2002  * ----------------------------------------------------------------------
    2003  */
    2004 static int
    2005 GetVolumeIndices(Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv,
    2006     vector<unsigned int>* vectorPtr)
    2007 {
    2008     if (objc == 0) {
    2009         for (unsigned int n = 0; n < NanoVis::volume.size(); n++) {
    2010             if (NanoVis::volume[n] != NULL) {
    2011                 vectorPtr->push_back(n);
    2012             }
    2013         }
    2014     } else {
    2015         for (int n = 0; n < objc; n++) {
    2016             unsigned int index;
    2017 
    2018             if (GetVolumeIndex(interp, objv[n], &index) != TCL_OK) {
    2019                 return TCL_ERROR;
    2020             }
    2021             if (index < NanoVis::volume.size() && NanoVis::volume[index] != NULL) {
    2022                 vectorPtr->push_back(index);
    2023             }
    2024         }
    2025     }
    2026     return TCL_OK;
    2027 }
    2028 
    2029 static int
    2030 GetIndices(Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv,
    2031     vector<unsigned int>* vectorPtr)
    2032 {
    2033     for (int n = 0; n < objc; n++) {
    2034         int index;
    2035 
    2036         if (Tcl_GetIntFromObj(interp, objv[n], &index) != TCL_OK) {
    2037             return TCL_ERROR;
    2038         }
    2039         if (index < 0) {
    2040             Tcl_AppendResult(interp, "can't have negative index \"",
    2041                 Tcl_GetString(objv[n]), "\"", (char *)NULL);
    2042             return TCL_ERROR;
    2043         }
    2044         vectorPtr->push_back((unsigned int)index);
    2045     }
    2046     return TCL_OK;
    2047 }
    2048 
    2049 
    2050 /*
    2051  * ----------------------------------------------------------------------
    2052  * FUNCTION: GetVolumes()
    2053  *
    2054  * Used internally to decode a series of volume index values and
    2055  * store then in the specified vector.  If there are no volume index
    2056  * arguments, this means "all volumes" to most commands, so all
    2057  * active volume indices are stored in the vector.
    2058  *
    2059  * Updates pushes index values into the vector.  Returns TCL_OK or
    2060  * TCL_ERROR to indicate an error.
    2061  * ----------------------------------------------------------------------
    2062  */
    2063 static int
    2064 GetVolumes(Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv,
    2065     vector<Volume *>* vectorPtr)
    2066 {
    2067     if (objc == 0) {
    2068         for (unsigned int n = 0; n < NanoVis::volume.size(); n++) {
    2069             if (NanoVis::volume[n] != NULL) {
    2070                 vectorPtr->push_back(NanoVis::volume[n]);
    2071             }
    2072         }
    2073     } else {
    2074         for (int n = 0; n < objc; n++) {
    2075             Volume *volPtr;
    2076 
    2077             if (GetVolumeFromObj(interp, objv[n], &volPtr) != TCL_OK) {
    2078                 return TCL_ERROR;
    2079             }
    2080             if (volPtr != NULL) {
    2081                 vectorPtr->push_back(volPtr);
    2082             }
    2083         }
    2084     }
    2085     return TCL_OK;
    2086 }
    2087 
    2088 
    2089 /*
    2090  * ----------------------------------------------------------------------
    2091  * FUNCTION: GetAxis()
    2092  *
    2093  * Used internally to decode an axis value from a string ("x", "y",
    2094  * or "z") to its index (0, 1, or 2).  Returns TCL_OK if successful,
    2095  * along with a value in valPtr.  Otherwise, it returns TCL_ERROR
    2096  * and an error message in the interpreter.
    2097  * ----------------------------------------------------------------------
    2098  */
    2099 static int
    2100 GetAxis(Tcl_Interp *interp, const char *string, int *indexPtr)
    2101 {
    2102     if (string[1] == '\0') {
    2103         char c;
    2104 
    2105         c = tolower((unsigned char)string[0]);
    2106         if (c == 'x') {
    2107             *indexPtr = 0;
    2108             return TCL_OK;
    2109         } else if (c == 'y') {
    2110             *indexPtr = 1;
    2111             return TCL_OK;
    2112         } else if (c == 'z') {
    2113             *indexPtr = 2;
    2114             return TCL_OK;
    2115         }
    2116         /*FALLTHRU*/
    2117     }
    2118     Tcl_AppendResult(interp, "bad axis \"", string,
    2119         "\": should be x, y, or z", (char*)NULL);
    2120     return TCL_ERROR;
    2121 }
    2122 
    2123 
    2124 /*
    2125  * ----------------------------------------------------------------------
    2126  * FUNCTION: GetAxisFromObj()
    2127  *
    2128  * Used internally to decode an axis value from a string ("x", "y",
    2129  * or "z") to its index (0, 1, or 2).  Returns TCL_OK if successful,
    2130  * along with a value in indexPtr.  Otherwise, it returns TCL_ERROR
    2131  * and an error message in the interpreter.
    2132  * ----------------------------------------------------------------------
    2133  */
    2134 static int
    2135 GetAxisFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, int *indexPtr)
    2136 {
    2137     return GetAxis(interp, Tcl_GetString(objPtr), indexPtr);
    2138 }
    2139 
    2140 /*
    2141  * ----------------------------------------------------------------------
    2142  * FUNCTION: GetAxisDirFromObj()
    2143  *
    2144  * Used internally to decode an axis value from a string ("x", "y",
    2145  * or "z") to its index (0, 1, or 2).  Returns TCL_OK if successful,
    2146  * along with a value in indexPtr.  Otherwise, it returns TCL_ERROR
    2147  * and an error message in the interpreter.
    2148  * ----------------------------------------------------------------------
    2149  */
    2150 static int
    2151 GetAxisDirFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, int *indexPtr, int *dirPtr)
    2152 {
    2153     char *string = Tcl_GetString(objPtr);
    2154 
    2155     int sign = 1;
    2156     if (*string == '-') {
    2157         sign = -1;
    2158         string++;
    2159     }
    2160     if (GetAxis(interp, string, indexPtr) != TCL_OK) {
    2161         return TCL_ERROR;
    2162     }
    2163     if (dirPtr != NULL) {
    2164         *dirPtr = sign;
    2165     }
    2166     return TCL_OK;
    2167 }
    2168 
    2169 /*
    2170  * ----------------------------------------------------------------------
    2171  * FUNCTION: GetColor()
    2172  *
    2173  * Used internally to decode a color value from a string ("R G B")
    2174  * as a list of three numbers 0-1.  Returns TCL_OK if successful,
    2175  * along with RGB values in rgbPtr.  Otherwise, it returns TCL_ERROR
    2176  * and an error message in the interpreter.
    2177  * ----------------------------------------------------------------------
    2178  */
    2179 static int
    2180 GetColor(Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv, float *rgbPtr)
    2181 {
    2182     if (objc < 3) {
    2183         Tcl_AppendResult(interp, "missing color values\": ",
    2184                 "should list of R G B values 0.0 - 1.0", (char*)NULL);
    2185         return TCL_ERROR;
    2186     }
    2187     if ((GetFloatFromObj(interp, objv[0], rgbPtr + 0) != TCL_OK) ||
    2188         (GetFloatFromObj(interp, objv[1], rgbPtr + 1) != TCL_OK) ||
    2189         (GetFloatFromObj(interp, objv[2], rgbPtr + 2) != TCL_OK)) {
    2190         return TCL_ERROR;
    2191     }
    2192     return TCL_OK;
    2193 }
    2194 
    2195 
    2196 #if PLANE_CMDS
     2351#if PLANE_CMD
    21972352static int
    2198 PlaneNewCmd(ClientData cdata, Tcl_Interp *interp, int objc,
     2353PlaneNewOp(ClientData cdata, Tcl_Interp *interp, int objc,
    21992354            Tcl_Obj *CONST *objv)
    22002355{
     
    22352390
    22362391static int
    2237 PlaneLinkCmd(ClientData cdata, Tcl_Interp *interp, int objc,
     2392PlaneLinkOp(ClientData cdata, Tcl_Interp *interp, int objc,
    22382393             Tcl_Obj *CONST *objv)
    22392394{
     
    22602415//The plane_index is the index mantained in the 2D plane renderer
    22612416static int
    2262 PlaneEnableCmd(ClientData cdata, Tcl_Interp *interp, int objc,
    2263         Tcl_Obj *CONST *objv)
     2417PlaneEnableOp(ClientData cdata, Tcl_Interp *interp, int objc,
     2418               Tcl_Obj *CONST *objv)
    22642419{
    22652420    fprintf(stderr,"enable a plane so the 2D renderer can render it command\n");
     
    22842439    return TCL_OK;
    22852440}
    2286 #endif  /*PLANE_CMDS*/
     2441
     2442static Rappture::CmdSpec planeOps[] =
     2443{
     2444    {"enable",     1, PlaneEnableOp,    4, 4, "planeIdx mode",},
     2445    {"link",       1, PlaneLinkOp,      4, 4, "planeIdx transfuncIdx",},
     2446    {"new",        1, PlaneNewOp,       5, 5, "planeIdx width height",},
     2447};
     2448static int nPlaneOps = NumCmdSpecs(planeOps);
     2449
     2450static int
     2451PlaneCmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv)
     2452{
     2453    Tcl_ObjCmdProc *proc;
     2454
     2455    proc = Rappture::GetOpFromObj(interp, nPlaneOps, planeOps,
     2456        Rappture::CMDSPEC_ARG1, objc, objv, 0);
     2457    if (proc == NULL) {
     2458        return TCL_ERROR;
     2459    }
     2460    return (*proc) (cdata, interp, objc, objv);
     2461}
     2462
     2463#endif  /*PLANE_CMD*/
     2464
     2465/*
     2466 * This command should be Tcl procedure instead of a C command.  The reason
     2467 * for this that 1) we are using a safe interpreter so we would need a master
     2468 * interpreter to load the Tcl environment properly (including our "unirect2d"
     2469 * procedure). And 2) the way nanovis is currently deployed doesn't make it
     2470 * easy to add new directories for procedures, since it's loaded into /tmp.
     2471 *
     2472 * Ideally, the "unirect2d" proc would do a rundimentary parsing of the data
     2473 * to verify the structure and then pass it to the appropiate Tcl command
     2474 * (heightmap, volume, etc). Our C command always creates a heightmap. 
     2475 */
     2476static int
     2477UniRect2dCmd(ClientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv)
     2478{   
     2479    int xNum, yNum, zNum;
     2480    float xMin, yMin, xMax, yMax;
     2481    float *zValues;
     2482
     2483    if ((objc & 0x01) == 0) {
     2484        Tcl_AppendResult(interp, Tcl_GetString(objv[0]), ": ",
     2485                "wrong number of arguments: should be key-value pairs",
     2486                (char *)NULL);
     2487        return TCL_ERROR;
     2488    }
     2489    zValues = NULL;
     2490    xNum = yNum = zNum = 0;
     2491    xMin = yMin = xMax = yMax = 0.0f;
     2492    int i;
     2493    for (i = 1; i < objc; i += 2) {
     2494        char *string;
     2495
     2496        string = Tcl_GetString(objv[i]);
     2497        if (strcmp(string, "xmin") == 0) {
     2498            if (GetFloatFromObj(interp, objv[i+1], &xMin) != TCL_OK) {
     2499                return TCL_ERROR;
     2500            }
     2501        } else if (strcmp(string, "xmax") == 0) {
     2502            if (GetFloatFromObj(interp, objv[i+1], &xMax) != TCL_OK) {
     2503                return TCL_ERROR;
     2504            }
     2505        } else if (strcmp(string, "xnum") == 0) {
     2506            if (Tcl_GetIntFromObj(interp, objv[i+1], &xNum) != TCL_OK) {
     2507                return TCL_ERROR;
     2508            }
     2509            if (xNum <= 0) {
     2510                Tcl_AppendResult(interp, "bad xnum value: must be > 0",
     2511                                 (char *)NULL);
     2512                return TCL_ERROR;
     2513            }
     2514        } else if (strcmp(string, "ymin") == 0) {
     2515            if (GetFloatFromObj(interp, objv[i+1], &yMin) != TCL_OK) {
     2516                return TCL_ERROR;
     2517            }
     2518        } else if (strcmp(string, "ymax") == 0) {
     2519            if (GetFloatFromObj(interp, objv[i+1], &yMax) != TCL_OK) {
     2520                return TCL_ERROR;
     2521            }
     2522        } else if (strcmp(string, "ynum") == 0) {
     2523            if (Tcl_GetIntFromObj(interp, objv[i+1], &yNum) != TCL_OK) {
     2524                return TCL_ERROR;
     2525            }
     2526            if (yNum <= 0) {
     2527                Tcl_AppendResult(interp, "bad ynum value: must be > 0",
     2528                                 (char *)NULL);
     2529                return TCL_ERROR;
     2530            }
     2531        } else if (strcmp(string, "zvalues") == 0) {
     2532            Tcl_Obj **zObj;
     2533
     2534            if (Tcl_ListObjGetElements(interp, objv[i+1], &zNum, &zObj)!= TCL_OK) {
     2535                return TCL_ERROR;
     2536            }
     2537            int j;
     2538            zValues = new float[zNum];
     2539            for (j = 0; j < zNum; j++) {
     2540                if (GetFloatFromObj(interp, zObj[j], zValues + j) != TCL_OK) {
     2541                    return TCL_ERROR;
     2542                }
     2543            }
     2544        } else {
     2545            Tcl_AppendResult(interp, "unknown key \"", string,
     2546                "\": should be xmin, xmax, xnum, ymin, ymax, ynum, or zvalues",
     2547                (char *)NULL);
     2548            return TCL_ERROR;
     2549        }
     2550    }
     2551    if (zValues == NULL) {
     2552        Tcl_AppendResult(interp, "missing \"zvalues\" key", (char *)NULL);
     2553        return TCL_ERROR;
     2554    }
     2555    if (zNum != (xNum * yNum)) {
     2556        Tcl_AppendResult(interp, "wrong number of z values must be xnum*ynum",
     2557                (char *)NULL);
     2558        return TCL_ERROR;
     2559    }
     2560    HeightMap* hMap;
     2561    hMap = new HeightMap();
     2562    hMap->setHeight(xMin, yMin, xMax, yMax, xNum, yNum, zValues);
     2563    hMap->setColorMap(NanoVis::get_transfunc("default"));
     2564    hMap->setVisible(true);
     2565    hMap->setLineContourVisible(true);
     2566    NanoVis::heightMap.push_back(hMap);
     2567    delete [] zValues;
     2568    return TCL_OK;
     2569}
     2570
    22872571
    22882572void
     
    22942578    Tcl_DStringInit(&cmdbuffer);
    22952579
    2296     // manipulate the viewpoint
    2297     Tcl_CreateObjCommand(interp, "camera", CameraCmd,
    2298         NULL, (Tcl_CmdDeleteProc*)NULL);
    2299 
    2300     // turn on/off cut planes in x/y/z directions
    2301     Tcl_CreateObjCommand(interp, "cutplane", CutplaneCmd,
    2302         NULL, (Tcl_CmdDeleteProc*)NULL);
    2303 
    2304     // request the legend for a plot (transfer function)
    2305     Tcl_CreateObjCommand(interp, "legend", LegendCmd,
    2306         NULL, (Tcl_CmdDeleteProc*)NULL);
    2307 
    2308     // change the size of the screen (size of picture generated)
    2309     Tcl_CreateObjCommand(interp, "screen", ScreenCmd,
    2310         NULL, (Tcl_CmdDeleteProc*)NULL);
    2311 
    2312     // manipulate transfer functions
    2313     Tcl_CreateObjCommand(interp, "transfunc", TransfuncCmd,
    2314         NULL, (Tcl_CmdDeleteProc*)NULL);
    2315 
    2316     // set the "up" direction for volumes
    2317     Tcl_CreateObjCommand(interp, "up", UpCmd,
    2318         NULL, (Tcl_CmdDeleteProc*)NULL);
    2319 
    2320     // manipulate volume data
    2321     Tcl_CreateObjCommand(interp, "volume", VolumeCmd,
    2322         NULL, (Tcl_CmdDeleteProc*)NULL);
    2323 
    2324     Tcl_CreateObjCommand(interp, "flow", FlowCmd,
    2325         NULL, (Tcl_CmdDeleteProc*)NULL);
    2326 
    2327     Tcl_CreateObjCommand(interp, "axis", AxisCmd,
    2328         NULL, (Tcl_CmdDeleteProc*)NULL);
    2329 
    2330     Tcl_CreateObjCommand(interp, "grid", GridCmd,
    2331         NULL, (Tcl_CmdDeleteProc*)NULL);
    2332 
    2333     Tcl_CreateObjCommand(interp, "heightmap", HeightMapCmd,
    2334         NULL, (Tcl_CmdDeleteProc*)NULL);
    2335 
    2336     // get screenshot
    2337     Tcl_CreateObjCommand(interp, "screenshot", ScreenShotCmd,
    2338         NULL, (Tcl_CmdDeleteProc*)NULL);
    2339 
    2340     Tcl_CreateObjCommand(interp, "unirect2d", UniRect2dCmd,
    2341         NULL, (Tcl_CmdDeleteProc*)NULL);
    2342 
    2343     Tcl_CreateObjCommand(interp, "axis", AxisCmd,
    2344         NULL, (Tcl_CmdDeleteProc*)NULL);
    2345 
    2346     Tcl_CreateObjCommand(interp, "grid", GridCmd,
    2347         NULL, (Tcl_CmdDeleteProc*)NULL);
    2348 
    2349     Tcl_CreateObjCommand(interp, "heightmap", HeightMapCmd,
    2350         NULL, (Tcl_CmdDeleteProc*)NULL);
    2351 
    2352     // get screenshot
    2353     Tcl_CreateObjCommand(interp, "screenshot", ScreenShotCmd,
    2354         NULL, (Tcl_CmdDeleteProc*)NULL);
    2355 
    2356     Tcl_CreateObjCommand(interp, "unirect2d", UniRect2dCmd,
    2357         NULL, (Tcl_CmdDeleteProc*)NULL);
    2358 
     2580    Tcl_CreateObjCommand(interp, "axis",        AxisCmd,        NULL, NULL);
     2581    Tcl_CreateObjCommand(interp, "camera",      CameraCmd,      NULL, NULL);
     2582    Tcl_CreateObjCommand(interp, "cutplane",    CutplaneCmd,    NULL, NULL);
     2583    Tcl_CreateObjCommand(interp, "flow",        FlowCmd,        NULL, NULL);
     2584    Tcl_CreateObjCommand(interp, "grid",        GridCmd,        NULL, NULL);
     2585    Tcl_CreateObjCommand(interp, "heightmap",   HeightMapCmd,   NULL, NULL);
     2586    Tcl_CreateObjCommand(interp, "legend",      LegendCmd,      NULL, NULL);
     2587    Tcl_CreateObjCommand(interp, "screen",      ScreenCmd,      NULL, NULL);
     2588    Tcl_CreateObjCommand(interp, "screenshot",  ScreenShotCmd,  NULL, NULL);
     2589    Tcl_CreateObjCommand(interp, "transfunc",   TransfuncCmd,   NULL, NULL);
     2590    Tcl_CreateObjCommand(interp, "unirect2d",   UniRect2dCmd,   NULL, NULL);
     2591    Tcl_CreateObjCommand(interp, "up",          UpCmd,          NULL, NULL);
     2592    Tcl_CreateObjCommand(interp, "volume",      VolumeCmd,      NULL, NULL);
    23592593#if __TEST_CODE__
    2360     Tcl_CreateObjCommand(interp, "test", TestCmd,
    2361         NULL, (Tcl_CmdDeleteProc*)NULL);
    2362 
    2363 
    2364 //    Tcl_CreateObjCommand(interp, "flow", FlowCmd,
    2365  //       NULL, (Tcl_CmdDeleteProc*)NULL);
     2594    Tcl_CreateObjCommand(interp, "test", TestCmd, NULL, NULL);
    23662595#endif
    23672596
     
    23882617    while (status == TCL_OK) {
    23892618        //
    2390         //  Read the next command from the buffer.  First time through
    2391         //  we block here and wait if necessary until a command comes in.
     2619        //  Read the next command from the buffer.  First time through we
     2620        //  block here and wait if necessary until a command comes in.
    23922621        //
    2393         //  BE CAREFUL:  Read only one command, up to a newline.
    2394         //  The "volume data follows" command needs to be able to read
    2395         //  the data immediately following the command, and we shouldn't
    2396         //  consume it here.
     2622        //  BE CAREFUL: Read only one command, up to a newline.  The "volume
     2623        //  data follows" command needs to be able to read the data
     2624        //  immediately following the command, and we shouldn't consume it
     2625        //  here.
    23972626        //
    23982627        while (1) {
     
    24782707#endif
    24792708}
    2480 
    2481 
    2482 /*
    2483  * -----------------------------------------------------------------------
    2484  *
    2485  * GetDataStream --
    2486  *
    2487  *      Read the requested number of bytes from standard input into the given
    2488  *      buffer.  The buffer is then decompressed and decoded.
    2489  *
    2490  * -----------------------------------------------------------------------
    2491  */
    2492 static int
    2493 GetDataStream(Tcl_Interp *interp, Rappture::Buffer &buf, int nBytes)
    2494 {
    2495     char buffer[8096];
    2496 
    2497     clearerr(stdin);
    2498     while (nBytes > 0) {
    2499         unsigned int chunk;
    2500         int nRead;
    2501 
    2502         chunk = (sizeof(buffer) < (unsigned int) nBytes) ?
    2503             sizeof(buffer) : nBytes;
    2504         nRead = fread(buffer, sizeof(char), chunk, stdin);
    2505         if (ferror(stdin)) {
    2506             Tcl_AppendResult(interp, "while reading data stream: ",
    2507                 Tcl_PosixError(interp), (char*)NULL);
    2508             return TCL_ERROR;
    2509         }
    2510         if (feof(stdin)) {
    2511             Tcl_AppendResult(interp, "premature EOF while reading data stream",
    2512                 (char*)NULL);
    2513             return TCL_ERROR;
    2514         }
    2515         buf.append(buffer, nRead);
    2516         nBytes -= nRead;
    2517     }
    2518     {
    2519         Rappture::Outcome err;
    2520 
    2521         err = Rappture::encoding::decode(buf, RPENC_Z|RPENC_B64|RPENC_HDR);
    2522         if (err) {
    2523             printf("ERROR -- DECODING\n");
    2524             fflush(stdout);
    2525             Tcl_AppendResult(interp, err.remark().c_str(), (char*)NULL);
    2526             return TCL_ERROR;
    2527         }
    2528     }
    2529     return TCL_OK;
    2530 }
    2531 
    2532 /*
    2533  * -----------------------------------------------------------------------
    2534  *
    2535  * CreateHeightMap --
    2536  *
    2537  *      Creates a heightmap from the given the data. The format of the data
    2538  *      should be as follows:
    2539  *
    2540  *              xMin, xMax, xNum, yMin, yMax, yNum, heights...
    2541  *
    2542  *      xNum and yNum must be integer values, all others are real numbers.
    2543  *      The number of heights must be xNum * yNum;
    2544  *
    2545  * -----------------------------------------------------------------------
    2546  */
    2547 static HeightMap *
    2548 CreateHeightMap(ClientData clientData, Tcl_Interp *interp, int objc,
    2549                 Tcl_Obj *CONST *objv)
    2550 {
    2551     float xMin, yMin, xMax, yMax;
    2552     int xNum, yNum;
    2553 
    2554     if (objc != 7) {
    2555         Tcl_AppendResult(interp,
    2556         "wrong # of values: should be xMin yMin xMax yMax xNum yNum heights",
    2557                 (char *)NULL);
    2558         return NULL;
    2559     }
    2560     if ((GetFloatFromObj(interp, objv[0], &xMin) != TCL_OK) ||
    2561         (GetFloatFromObj(interp, objv[1], &yMin) != TCL_OK) ||
    2562         (GetFloatFromObj(interp, objv[2], &xMax) != TCL_OK) ||
    2563         (GetFloatFromObj(interp, objv[3], &yMax) != TCL_OK) ||
    2564         (Tcl_GetIntFromObj(interp, objv[4], &xNum) != TCL_OK) ||
    2565         (Tcl_GetIntFromObj(interp, objv[5], &yNum) != TCL_OK)) {
    2566         return NULL;
    2567     }
    2568     int nValues;
    2569     Tcl_Obj **elem;
    2570     if (Tcl_ListObjGetElements(interp, objv[6], &nValues, &elem) != TCL_OK) {
    2571         return NULL;
    2572     }
    2573     if ((xNum <= 0) || (yNum <= 0)) {
    2574         Tcl_AppendResult(interp, "bad number of x or y values", (char *)NULL);
    2575         return NULL;
    2576     }
    2577     if (nValues != (xNum * yNum)) {
    2578         Tcl_AppendResult(interp, "wrong # of heights", (char *)NULL);
    2579         return NULL;
    2580     }
    2581 
    2582     float *heights;
    2583     heights = new float[nValues];
    2584     if (heights == NULL) {
    2585         Tcl_AppendResult(interp, "can't allocate array of heights",
    2586                 (char *)NULL);
    2587         return NULL;
    2588     }
    2589 
    2590     int i;
    2591     for (i = 0; i < nValues; i++) {
    2592         if (GetFloatFromObj(interp, elem[i], heights + i) != TCL_OK) {
    2593             delete [] heights;
    2594             return NULL;
    2595         }
    2596     }
    2597     HeightMap* hMap;
    2598     hMap = new HeightMap();
    2599     hMap->setHeight(xMin, yMin, xMax, yMax, xNum, yNum, heights);
    2600     hMap->setColorMap(NanoVis::get_transfunc("default"));
    2601     hMap->setVisible(true);
    2602     hMap->setLineContourVisible(true);
    2603     delete [] heights;
    2604     return hMap;
    2605 }
    2606 
    2607 /*
    2608  * This command should be Tcl procedure instead of a C command.  The reason
    2609  * for this that 1) we are using a safe interpreter so we would need a master
    2610  * interpreter to load the Tcl environment properly (including our "unirect2d"
    2611  * procedure). And 2) the way nanovis is currently deployed, doesn't make it
    2612  * easy to add new directories for procedures, since it's loaded into /tmp.
    2613  *
    2614  * Ideally, the "unirect2d" proc would do a rundimentary parsing of the data
    2615  * to verify the structure and then pass it to the appropiate Tcl command
    2616  * (heightmap, volume, etc). Our C command always creates a heightmap. 
    2617  */
    2618 static int
    2619 UniRect2dCmd(ClientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv)
    2620 {   
    2621     int xNum, yNum, zNum;
    2622     float xMin, yMin, xMax, yMax;
    2623     float *zValues;
    2624 
    2625     if ((objc & 0x01) == 0) {
    2626         Tcl_AppendResult(interp, Tcl_GetString(objv[0]), ": ",
    2627                 "wrong number of arguments: should be key-value pairs",
    2628                 (char *)NULL);
    2629         return TCL_ERROR;
    2630     }
    2631     zValues = NULL;
    2632     xNum = yNum = zNum = 0;
    2633     xMin = yMin = xMax = yMax = 0.0f;
    2634     int i;
    2635     for (i = 1; i < objc; i += 2) {
    2636         char *string;
    2637 
    2638         string = Tcl_GetString(objv[i]);
    2639         if (strcmp(string, "xmin") == 0) {
    2640             if (GetFloatFromObj(interp, objv[i+1], &xMin) != TCL_OK) {
    2641                 return TCL_ERROR;
    2642             }
    2643         } else if (strcmp(string, "xmax") == 0) {
    2644             if (GetFloatFromObj(interp, objv[i+1], &xMax) != TCL_OK) {
    2645                 return TCL_ERROR;
    2646             }
    2647         } else if (strcmp(string, "xnum") == 0) {
    2648             if (Tcl_GetIntFromObj(interp, objv[i+1], &xNum) != TCL_OK) {
    2649                 return TCL_ERROR;
    2650             }
    2651             if (xNum <= 0) {
    2652                 Tcl_AppendResult(interp, "bad xnum value: must be > 0",
    2653                                  (char *)NULL);
    2654                 return TCL_ERROR;
    2655             }
    2656         } else if (strcmp(string, "ymin") == 0) {
    2657             if (GetFloatFromObj(interp, objv[i+1], &yMin) != TCL_OK) {
    2658                 return TCL_ERROR;
    2659             }
    2660         } else if (strcmp(string, "ymax") == 0) {
    2661             if (GetFloatFromObj(interp, objv[i+1], &yMax) != TCL_OK) {
    2662                 return TCL_ERROR;
    2663             }
    2664         } else if (strcmp(string, "ynum") == 0) {
    2665             if (Tcl_GetIntFromObj(interp, objv[i+1], &yNum) != TCL_OK) {
    2666                 return TCL_ERROR;
    2667             }
    2668             if (yNum <= 0) {
    2669                 Tcl_AppendResult(interp, "bad ynum value: must be > 0",
    2670                                  (char *)NULL);
    2671                 return TCL_ERROR;
    2672             }
    2673         } else if (strcmp(string, "zvalues") == 0) {
    2674             Tcl_Obj **zObj;
    2675 
    2676             if (Tcl_ListObjGetElements(interp, objv[i+1], &zNum, &zObj)!= TCL_OK) {
    2677                 return TCL_ERROR;
    2678             }
    2679             int j;
    2680             zValues = new float[zNum];
    2681             for (j = 0; j < zNum; j++) {
    2682                 if (GetFloatFromObj(interp, zObj[j], zValues + j) != TCL_OK) {
    2683                     return TCL_ERROR;
    2684                 }
    2685             }
    2686         } else {
    2687             Tcl_AppendResult(interp, "unknown key \"", string,
    2688                 "\": should be xmin, xmax, xnum, ymin, ymax, ynum, or zvalues",
    2689                 (char *)NULL);
    2690             return TCL_ERROR;
    2691         }
    2692     }
    2693     if (zValues == NULL) {
    2694         Tcl_AppendResult(interp, "missing \"zvalues\" key", (char *)NULL);
    2695         return TCL_ERROR;
    2696     }
    2697     if (zNum != (xNum * yNum)) {
    2698         Tcl_AppendResult(interp, "wrong number of z values must be xnum*ynum",
    2699                 (char *)NULL);
    2700         return TCL_ERROR;
    2701     }
    2702     HeightMap* hMap;
    2703     hMap = new HeightMap();
    2704     hMap->setHeight(xMin, yMin, xMax, yMax, xNum, yNum, zValues);
    2705     hMap->setColorMap(NanoVis::get_transfunc("default"));
    2706     hMap->setVisible(true);
    2707     hMap->setLineContourVisible(true);
    2708     NanoVis::heightMap.push_back(hMap);
    2709     delete [] zValues;
    2710     return TCL_OK;
    2711 }
Note: See TracChangeset for help on using the changeset viewer.