tcl.c

Go to the documentation of this file.
00001 /*                           T C L . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 1997-2006 United States Government as represented by
00005  * the U.S. Army Research Laboratory.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation; either version 2 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this file; see the file named COPYING for more
00019  * information.
00020  */
00021 
00022 /** @addtogroup librt */
00023 /*@{*/
00024 /** @file ./librt/tcl.c
00025  *  Tcl interfaces to LIBRT routines.
00026  *
00027  *  LIBRT routines are not for casual command-line use;
00028  *  as a result, the Tcl name for the function should be exactly
00029  *  the same as the C name for the underlying function.
00030  *  Typing "rt_" is no hardship when writing Tcl procs, and
00031  *  clarifies the origin of the routine.
00032  *
00033  *  Authors -
00034  *      Michael John Muuss
00035  *      Glenn Durfee
00036  *
00037  *  Source -
00038  *      The U. S. Army Research Laboratory
00039  *      Aberdeen Proving Ground, Maryland  21005-5068  USA
00040  */
00041 /*@}*/
00042 
00043 #ifndef lint
00044 static const char RCSid[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/tcl.c,v 14.17 2006/09/16 02:04:26 lbutler Exp $ (ARL)";
00045 #endif
00046 
00047 #include "common.h"
00048 
00049 #include <stdlib.h>
00050 #include <stdio.h>
00051 #include <ctype.h>
00052 #include <math.h>
00053 #ifdef HAVE_STRING_H
00054 #  include <string.h>
00055 #else
00056 #  include <strings.h>
00057 #endif
00058 
00059 #include "tcl.h"
00060 
00061 #include "machine.h"
00062 #include "bu.h"
00063 #include "vmath.h"
00064 #include "bn.h"
00065 #include "rtgeom.h"
00066 #include "raytrace.h"
00067 
00068 #include "./debug.h"
00069 
00070 /* defined in wdb_obj.c */
00071 extern int Wdb_Init(Tcl_Interp *interp);
00072 
00073 /* defined in dg_obj.c */
00074 extern int Dgo_Init(Tcl_Interp *interp);
00075 
00076 /* defined in view_obj.c */
00077 extern int Vo_Init(Tcl_Interp *interp);
00078 
00079 /************************************************************************
00080  *                                                                      *
00081  *              Tcl interface to Ray-tracing                            *
00082  *                                                                      *
00083  ************************************************************************/
00084 
00085 struct dbcmdstruct {
00086         char *cmdname;
00087         int (*cmdfunc)();
00088 };
00089 
00090 /*
00091  *                      R T _ T C L _ P A R S E _ R A Y
00092  *
00093  *  Allow specification of a ray to trace, in two convenient formats.
00094  *
00095  *  Examples -
00096  *      {0 0 0} dir {0 0 -1}
00097  *      {20 -13.5 20} at {10 .5 3}
00098  */
00099 int
00100 rt_tcl_parse_ray( Tcl_Interp *interp, struct xray *rp, const char *const*argv )
00101 {
00102         if( bn_decode_vect( rp->r_pt,  argv[0] ) != 3 )  {
00103                 Tcl_AppendResult( interp,
00104                         "badly formatted point: ", argv[0], (char *)NULL );
00105                 return TCL_ERROR;
00106         }
00107         if( bn_decode_vect( rp->r_dir, argv[2] ) != 3 )  {
00108                 Tcl_AppendResult( interp,
00109                         "badly formatted vector: ", argv[2], (char *)NULL );
00110                 return TCL_ERROR;
00111         }
00112         switch( argv[1][0] )  {
00113         case 'd':
00114                 /* [2] is direction vector */
00115                 break;
00116         case 'a':
00117                 /* [2] is target point, build a vector from start pt */
00118                 VSUB2( rp->r_dir, rp->r_dir, rp->r_pt );
00119                 break;
00120         default:
00121                 Tcl_AppendResult( interp,
00122                                 "wrong ray keyword: '", argv[1],
00123                                 "', should be one of 'dir' or 'at'",
00124                                 (char *)NULL );
00125                 return TCL_ERROR;
00126         }
00127         VUNITIZE( rp->r_dir );
00128         return TCL_OK;
00129 }
00130 
00131 /*
00132  *                      R T _ T C L _ P R _ C U T T E R
00133  *
00134  *  Format a "union cutter" structure in a TCL-friendly format.
00135  *  Useful for debugging space partitioning
00136  *
00137  *  Examples -
00138  *      type cutnode
00139  *      type boxnode
00140  *      type nugridnode
00141  */
00142 void
00143 rt_tcl_pr_cutter( Tcl_Interp *interp, const union cutter *cutp )
00144 {
00145         static const char xyz[4] = "XYZ";
00146         struct bu_vls   str;
00147         int i;
00148 
00149         bu_vls_init(&str);
00150 
00151         switch( cutp->cut_type )  {
00152         case CUT_CUTNODE:
00153                 bu_vls_printf( &str,
00154                         "type cutnode axis %c point %.25G",
00155                         xyz[cutp->cn.cn_axis], cutp->cn.cn_point );
00156                 break;
00157         case CUT_BOXNODE:
00158                 bu_vls_printf( &str,
00159                         "type boxnode min {%.25G %.25G %.25G}",
00160                         V3ARGS(cutp->bn.bn_min) );
00161                 bu_vls_printf( &str,
00162                         " max {%.25G %.25G %.25G}",
00163                         V3ARGS(cutp->bn.bn_max) );
00164                 bu_vls_printf( &str, " solids {");
00165                 for( i=0; i < cutp->bn.bn_len; i++ )  {
00166                         bu_vls_strcat( &str, cutp->bn.bn_list[i]->st_name );
00167                         bu_vls_putc( &str, ' ' );
00168                 }
00169                 bu_vls_printf( &str, "} pieces {");
00170                 for( i = 0; i < cutp->bn.bn_piecelen; i++ )  {
00171                         struct rt_piecelist *plp = &cutp->bn.bn_piecelist[i];
00172                         int j;
00173                         RT_CK_PIECELIST(plp);
00174                         /* These can be taken by user positionally */
00175                         bu_vls_printf( &str, "{%s {", plp->stp->st_name );
00176                         for( j=0; j < plp->npieces; j++ )  {
00177                                 bu_vls_printf( &str, "%ld ", plp->pieces[j] );
00178                         }
00179                         bu_vls_strcat( &str, "} } " );
00180                 }
00181                 bu_vls_strcat( &str, "}" );
00182                 break;
00183         case CUT_NUGRIDNODE:
00184                 bu_vls_printf( &str, "type nugridnode" );
00185                 for( i = 0; i < 3; i++ )  {
00186                         bu_vls_printf( &str, " %c {", xyz[i] );
00187                         bu_vls_printf( &str, "spos %.25G epos %.25G width %.25g",
00188                                 cutp->nugn.nu_axis[i]->nu_spos,
00189                                 cutp->nugn.nu_axis[i]->nu_epos,
00190                                 cutp->nugn.nu_axis[i]->nu_width );
00191                         bu_vls_printf( &str, " cells_per_axis %ld",
00192                                 cutp->nugn.nu_cells_per_axis );
00193                         bu_vls_printf( &str, " stepsize %ld}",
00194                                 cutp->nugn.nu_stepsize );
00195                 }
00196                 break;
00197         default:
00198                 bu_vls_printf( &str, "rt_tcl_pr_cutter() bad pointer cutp=x%lx",
00199                         (long)cutp);
00200                 break;
00201         }
00202         Tcl_AppendResult( interp, bu_vls_addr(&str), (char *)NULL );
00203         bu_vls_free( &str );
00204 }
00205 
00206 /*
00207  *                      R T _ T C L _ C U T T E R
00208  *
00209  *  Obtain the 'n'th space partitioning cell along the given ray,
00210  *  and return that to the user.
00211  *
00212  *  Example -
00213  *      .rt cutter 7 {0 0 0} dir {0 0 -1}
00214  */
00215 int
00216 rt_tcl_cutter( ClientData clientData, Tcl_Interp *interp, int argc, const char *const*argv )
00217 {
00218         struct application      *ap = (struct application *)clientData;
00219         struct rt_i             *rtip;
00220         const union cutter      *cutp;
00221         int                     n;
00222 
00223         if( argc != 6 )  {
00224                 Tcl_AppendResult( interp,
00225                                 "wrong # args: should be \"",
00226                                 argv[0], " ", argv[1], "cutnum {P} dir|at {V}\"",
00227                                 (char *)NULL );
00228                 return TCL_ERROR;
00229         }
00230 
00231         RT_CK_AP_TCL(interp, ap);
00232         rtip = ap->a_rt_i;
00233         RT_CK_RTI_TCL(interp,rtip);
00234 
00235         n = atoi(argv[2]);
00236         if( rt_tcl_parse_ray( interp, &ap->a_ray, &argv[3] ) == TCL_ERROR )
00237                 return TCL_ERROR;
00238 
00239         cutp = rt_cell_n_on_ray( ap, n );
00240         if( cutp == CUTTER_NULL )  {
00241                 Tcl_AppendResult( interp, "rt_cell_n_on_ray() failed to find cell ", argv[2], (char *)NULL );
00242                 return TCL_ERROR;
00243         }
00244         rt_tcl_pr_cutter( interp, cutp );
00245         return TCL_OK;
00246 }
00247 
00248 /*
00249  *                      R T _ T C L _ P R _ H I T
00250  *
00251  *  Format a hit in a TCL-friendly format.
00252  *
00253  *  It is possible that a solid may have been removed from the
00254  *  directory after this database was prepped, so check pointers
00255  *  carefully.
00256  *
00257  *  It might be beneficial to use some format other than %g to
00258  *  give the user more precision.
00259  */
00260 void
00261 rt_tcl_pr_hit( Tcl_Interp *interp, struct hit *hitp, const struct seg *segp, const struct xray  *rayp, int flipflag )
00262 {
00263         struct bu_vls   str;
00264         vect_t          norm;
00265         struct soltab   *stp;
00266         const struct directory  *dp;
00267         struct curvature crv;
00268 
00269         RT_CK_SEG(segp);
00270         stp = segp->seg_stp;
00271         RT_CK_SOLTAB(stp);
00272         dp = stp->st_dp;
00273         RT_CK_DIR(dp);
00274 
00275         RT_HIT_NORMAL( norm, hitp, stp, rayp, flipflag );
00276         RT_CURVATURE( &crv, hitp, flipflag, stp );
00277 
00278         bu_vls_init(&str);
00279         bu_vls_printf( &str, " {dist %g point {", hitp->hit_dist);
00280         bn_encode_vect( &str, hitp->hit_point );
00281         bu_vls_printf( &str, "} normal {" );
00282         bn_encode_vect( &str, norm );
00283         bu_vls_printf( &str, "} c1 %g c2 %g pdir {",
00284                 crv.crv_c1, crv.crv_c2 );
00285         bn_encode_vect( &str, crv.crv_pdir );
00286         bu_vls_printf( &str, "} surfno %d", hitp->hit_surfno );
00287         if( stp->st_path.magic == DB_FULL_PATH_MAGIC )  {
00288                 /* Magic is left 0 if the path is not filled in. */
00289                 char    *sofar = db_path_to_string(&stp->st_path);
00290                 bu_vls_printf( &str, " path ");
00291                 bu_vls_strcat( &str, sofar );
00292                 bu_free( (genptr_t)sofar, "path string" );
00293         }
00294         bu_vls_printf( &str, " solid %s}", dp->d_namep );
00295 
00296         Tcl_AppendResult( interp, bu_vls_addr( &str ), (char *)NULL );
00297         bu_vls_free( &str );
00298 }
00299 
00300 /*
00301  *                      R T _ T C L _ A _ H I T
00302  */
00303 int
00304 rt_tcl_a_hit( struct application *ap,
00305         struct partition *PartHeadp,
00306         struct seg *segHeadp )
00307 {
00308         Tcl_Interp *interp = (Tcl_Interp *)ap->a_uptr;
00309         register struct partition *pp;
00310 
00311         RT_CK_PT_HD(PartHeadp);
00312 
00313         for( pp=PartHeadp->pt_forw; pp != PartHeadp; pp = pp->pt_forw )  {
00314                 RT_CK_PT(pp);
00315                 Tcl_AppendResult( interp, "{in", (char *)NULL );
00316                 rt_tcl_pr_hit( interp, pp->pt_inhit, pp->pt_inseg,
00317                         &ap->a_ray, pp->pt_inflip );
00318                 Tcl_AppendResult( interp, "\nout", (char *)NULL );
00319                 rt_tcl_pr_hit( interp, pp->pt_outhit, pp->pt_outseg,
00320                         &ap->a_ray, pp->pt_outflip );
00321                 Tcl_AppendResult( interp,
00322                         "\nregion ",
00323                         pp->pt_regionp->reg_name,
00324                         (char *)NULL );
00325                 Tcl_AppendResult( interp, "}\n", (char *)NULL );
00326         }
00327 
00328         return 1;
00329 }
00330 
00331 /*
00332  *                      R T _ T C L _ A _ M I S S
00333  */
00334 int
00335 rt_tcl_a_miss( struct application *ap )
00336 {
00337         return 0;
00338 }
00339 
00340 /*
00341  *                      R T _ T C L _ S H O O T R A Y
00342  *
00343  *  Usage -
00344  *      procname shootray [-R] {P} dir|at {V}
00345  *              -R option specifries no overlap reporting
00346  *
00347  *  Example -
00348  *      set glob_compat_mode 0
00349  *      .inmem rt_gettrees .rt all.g
00350  *      .rt shootray -R {0 0 0} dir {0 0 -1}
00351  *
00352  *      set tgt [bu_get_value_by_keyword V [concat type [.inmem get LIGHT]]]
00353  *      .rt shootray {20 -13.5 20} at $tgt
00354  *
00355  *
00356  *  Returns -
00357  *      This "shootray" operation returns a nested set of lists. It returns
00358  *      a list of zero or more partitions. Inside each partition is a list
00359  *      containing an in, out, and region keyword, each with an associated
00360  *      value. The associated value for each "inhit" and "outhit" is itself
00361  *      a list containing a dist, point, normal, surfno, and solid keyword,
00362  *      each with an associated value.
00363  */
00364 int
00365 rt_tcl_rt_shootray(ClientData clientData, Tcl_Interp *interp, int argc, const char *const *argv)
00366 {
00367         struct application      *ap = (struct application *)clientData;
00368         struct rt_i             *rtip;
00369         int                     index;
00370 
00371         if( (argc != 5 && argc != 6) || (argc == 6 && strcmp( argv[2], "-R"))  )  {
00372                 Tcl_AppendResult( interp,
00373                                 "wrong # args: should be \"",
00374                                 argv[0], " ", argv[1], " [-R] {P} dir|at {V}\"",
00375                                 (char *)NULL );
00376                 return TCL_ERROR;
00377         }
00378 
00379         if( argc == 6 ) {
00380                 ap->a_logoverlap = rt_silent_logoverlap;
00381                 index = 3;
00382         } else {
00383                 index = 2;
00384         }
00385 
00386         RT_CK_AP_TCL(interp, ap);
00387         rtip = ap->a_rt_i;
00388         RT_CK_RTI_TCL(interp,rtip);
00389 
00390         if( rt_tcl_parse_ray( interp, &ap->a_ray, &argv[index] ) == TCL_ERROR )
00391                 return TCL_ERROR;
00392         ap->a_hit = rt_tcl_a_hit;
00393         ap->a_miss = rt_tcl_a_miss;
00394         ap->a_uptr = (genptr_t)interp;
00395 
00396         (void)rt_shootray( ap );
00397 
00398         return TCL_OK;
00399 }
00400 
00401 /*
00402  *                      R T _ T C L _ R T _ O N E H I T
00403  *  Usage -
00404  *      procname onehit
00405  *      procname onehit #
00406  */
00407 int
00408 rt_tcl_rt_onehit(ClientData clientData, Tcl_Interp *interp, int argc, const char *const *argv)
00409 {
00410         struct application      *ap = (struct application *)clientData;
00411         struct rt_i             *rtip;
00412         char                    buf[64];
00413 
00414         if( argc < 2 || argc > 3 )  {
00415                 Tcl_AppendResult( interp,
00416                                 "wrong # args: should be \"",
00417                                 argv[0], " ", argv[1], " [#]\"",
00418                                 (char *)NULL );
00419                 return TCL_ERROR;
00420         }
00421 
00422         RT_CK_AP_TCL(interp, ap);
00423         rtip = ap->a_rt_i;
00424         RT_CK_RTI_TCL(interp,rtip);
00425 
00426         if( argc == 3 )  {
00427                 ap->a_onehit = atoi(argv[2]);
00428         }
00429         sprintf(buf, "%d", ap->a_onehit );
00430         Tcl_AppendResult( interp, buf, (char *)NULL );
00431         return TCL_OK;
00432 }
00433 
00434 /*
00435  *                      R T _ T C L _ R T _ N O _ B O O L
00436  *  Usage -
00437  *      procname no_bool
00438  *      procname no_bool #
00439  */
00440 int
00441 rt_tcl_rt_no_bool(ClientData clientData, Tcl_Interp *interp, int argc, const char *const *argv)
00442 {
00443         struct application      *ap = (struct application *)clientData;
00444         struct rt_i             *rtip;
00445         char                    buf[64];
00446 
00447         if( argc < 2 || argc > 3 )  {
00448                 Tcl_AppendResult( interp,
00449                                 "wrong # args: should be \"",
00450                                 argv[0], " ", argv[1], " [#]\"",
00451                                 (char *)NULL );
00452                 return TCL_ERROR;
00453         }
00454 
00455         RT_CK_AP_TCL(interp, ap);
00456         rtip = ap->a_rt_i;
00457         RT_CK_RTI_TCL(interp,rtip);
00458 
00459         if( argc == 3 )  {
00460                 ap->a_no_booleans = atoi(argv[2]);
00461         }
00462         sprintf(buf, "%d", ap->a_no_booleans );
00463         Tcl_AppendResult( interp, buf, (char *)NULL );
00464         return TCL_OK;
00465 }
00466 
00467 /*
00468  *                      R T _ T C L _ R T _ C H E C K
00469  *
00470  *  Run some of the internal consistency checkers over the data structures.
00471  *
00472  *  Usage -
00473  *      procname check
00474  */
00475 int
00476 rt_tcl_rt_check(ClientData clientData, Tcl_Interp *interp, int argc, const char *const *argv)
00477 {
00478         struct application      *ap = (struct application *)clientData;
00479         struct rt_i             *rtip;
00480 
00481         if( argc != 2 )  {
00482                 Tcl_AppendResult( interp,
00483                                 "wrong # args: should be \"",
00484                                 argv[0], " ", argv[1], "\"",
00485                                 (char *)NULL );
00486                 return TCL_ERROR;
00487         }
00488 
00489         RT_CK_AP_TCL(interp, ap);
00490         rtip = ap->a_rt_i;
00491         RT_CK_RTI_TCL(interp,rtip);
00492 
00493         rt_ck(rtip);
00494 
00495         return TCL_OK;
00496 }
00497 
00498 /*
00499  *                      R T _ T C L _ R T _ P R E P
00500  *
00501  *  When run with no args, just prints current status of prepping.
00502  *
00503  *  Usage -
00504  *      procname prep
00505  *      procname prep use_air [hasty_prep]
00506  */
00507 int
00508 rt_tcl_rt_prep(ClientData clientData, Tcl_Interp *interp, int argc, const char *const *argv)
00509 {
00510         struct application      *ap = (struct application *)clientData;
00511         struct rt_i             *rtip;
00512         struct bu_vls           str;
00513 
00514         if( argc < 2 || argc > 4 )  {
00515                 Tcl_AppendResult( interp,
00516                                 "wrong # args: should be \"",
00517                                 argv[0], " ", argv[1],
00518                                 " [hasty_prep]\"",
00519                                 (char *)NULL );
00520                 return TCL_ERROR;
00521         }
00522 
00523         RT_CK_AP_TCL(interp, ap);
00524         rtip = ap->a_rt_i;
00525         RT_CK_RTI_TCL(interp,rtip);
00526 
00527         if( argc >= 3 && !rtip->needprep )  {
00528                 Tcl_AppendResult( interp,
00529                         argv[0], " ", argv[1],
00530                         " invoked when model has already been prepped.\n",
00531                         (char *)NULL );
00532                 return TCL_ERROR;
00533         }
00534 
00535         if( argc == 4 )  rtip->rti_hasty_prep = atoi(argv[3]);
00536 
00537         /* If args were given, prep now. */
00538         if( argc >= 3 )  rt_prep_parallel( rtip, 1 );
00539 
00540         /* Now, describe the current state */
00541         bu_vls_init( &str );
00542         bu_vls_printf( &str, "hasty_prep %d dont_instance %d useair %d needprep %d",
00543                 rtip->rti_hasty_prep,
00544                 rtip->rti_dont_instance,
00545                 rtip->useair,
00546                 rtip->needprep
00547         );
00548 
00549         bu_vls_printf( &str, " space_partition_type %s n_nugridnode %d n_cutnode %d n_boxnode %d n_empty %ld",
00550                 rtip->rti_space_partition == RT_PART_NUGRID ?
00551                         "NUGrid" : "NUBSP",
00552                 rtip->rti_ncut_by_type[CUT_NUGRIDNODE],
00553                 rtip->rti_ncut_by_type[CUT_CUTNODE],
00554                 rtip->rti_ncut_by_type[CUT_BOXNODE],
00555                 rtip->nempty_cells );
00556         bu_vls_printf( &str, " maxdepth %d maxlen %d",
00557                 rtip->rti_cut_maxdepth,
00558                 rtip->rti_cut_maxlen );
00559         if( rtip->rti_ncut_by_type[CUT_BOXNODE] )  bu_vls_printf( &str, " avglen %g",
00560                 ((double)rtip->rti_cut_totobj) /
00561                 rtip->rti_ncut_by_type[CUT_BOXNODE] );
00562 
00563         Tcl_AppendResult( interp, bu_vls_addr(&str), (char *)NULL );
00564         bu_vls_free( &str );
00565         return TCL_OK;
00566 }
00567 
00568 static struct dbcmdstruct rt_tcl_rt_cmds[] = {
00569         {"shootray",    rt_tcl_rt_shootray},
00570         {"onehit",      rt_tcl_rt_onehit},
00571         {"no_bool",     rt_tcl_rt_no_bool},
00572         {"check",       rt_tcl_rt_check},
00573         {"prep",        rt_tcl_rt_prep},
00574         {"cutter",      rt_tcl_cutter},
00575         {(char *)0,     (int (*)())0}
00576 };
00577 
00578 /*
00579  *                      R T _ T C L _ R T
00580  *
00581  * Generic interface for the LIBRT_class manipulation routines.
00582  * Usage:
00583  *        procname dbCmdName ?args?
00584  * Returns: result of cmdName LIBRT operation.
00585  *
00586  * Objects of type 'procname' must have been previously created by
00587  * the 'rt_gettrees' operation performed on a database object.
00588  *
00589  * Example -
00590  *      .inmem rt_gettrees .rt all.g
00591  *      .rt shootray {0 0 0} dir {0 0 -1}
00592  */
00593 int
00594 rt_tcl_rt(ClientData clientData, Tcl_Interp *interp, int argc, const char **argv)
00595 {
00596         struct dbcmdstruct      *dbcmd;
00597 
00598         if( argc < 2 ) {
00599                 Tcl_AppendResult( interp,
00600                                   "wrong # args: should be \"", argv[0],
00601                                   " command [args...]\"",
00602                                   (char *)NULL );
00603                 return TCL_ERROR;
00604         }
00605 
00606         for( dbcmd = rt_tcl_rt_cmds; dbcmd->cmdname != NULL; dbcmd++ ) {
00607                 if( strcmp(dbcmd->cmdname, argv[1]) == 0 ) {
00608                         return (*dbcmd->cmdfunc)( clientData, interp,
00609                                                   argc, argv );
00610                 }
00611         }
00612 
00613 
00614         Tcl_AppendResult( interp, "unknown LIBRT command '",
00615                         argv[1], "'; must be one of:",
00616                         (char *)NULL );
00617         for( dbcmd = rt_tcl_rt_cmds; dbcmd->cmdname != NULL; dbcmd++ ) {
00618                 Tcl_AppendResult( interp, " ", dbcmd->cmdname, (char *)NULL );
00619         }
00620         return TCL_ERROR;
00621 }
00622 
00623 /************************************************************************
00624  *                                                                      *
00625  *              Tcl interface to Combination import/export              *
00626  *                                                                      *
00627  ************************************************************************/
00628 
00629 /*
00630  *              D B _ T C L _ T R E E _ D E S C R I B E
00631  *
00632  * Fills a Tcl_DString with a representation of the given tree appropriate
00633  * for processing by Tcl scripts.  The reason we use Tcl_DStrings instead
00634  * of bu_vlses is that Tcl_DStrings provide "start/end sublist" commands
00635  * and automatic escaping of Tcl-special characters.
00636  *
00637  * A tree 't' is represented in the following manner:
00638  *
00639  *      t := { l dbobjname { mat } }
00640  *         | { l dbobjname }
00641  *         | { u t1 t2 }
00642  *         | { n t1 t2 }
00643  *         | { - t1 t2 }
00644  *         | { ^ t1 t2 }
00645  *         | { ! t1 }
00646  *         | { G t1 }
00647  *         | { X t1 }
00648  *         | { N }
00649  *         | {}
00650  *
00651  * where 'dbobjname' is a string containing the name of a database object,
00652  *       'mat'       is the matrix preceeding a leaf,
00653  *       't1', 't2'  are trees (recursively defined).
00654  *
00655  * Notice that in most cases, this tree will be grossly unbalanced.
00656  */
00657 
00658 void
00659 db_tcl_tree_describe(Tcl_DString *dsp, const union tree *tp)
00660 {
00661         if( !tp ) return;
00662 
00663         RT_CK_TREE(tp);
00664         switch( tp->tr_op ) {
00665         case OP_DB_LEAF:
00666                 Tcl_DStringAppendElement( dsp, "l" );
00667                 Tcl_DStringAppendElement( dsp, tp->tr_l.tl_name );
00668                 if( tp->tr_l.tl_mat )  {
00669                         struct bu_vls vls;
00670                         bu_vls_init( &vls );
00671                         bn_encode_mat( &vls, tp->tr_l.tl_mat );
00672                         Tcl_DStringAppendElement( dsp, bu_vls_addr(&vls) );
00673                         bu_vls_free( &vls );
00674                 }
00675                 break;
00676 
00677                 /* This node is known to be a binary op */
00678         case OP_UNION:
00679                 Tcl_DStringAppendElement( dsp, "u" );
00680                 goto bin;
00681         case OP_INTERSECT:
00682                 Tcl_DStringAppendElement( dsp, "n" );
00683                 goto bin;
00684         case OP_SUBTRACT:
00685                 Tcl_DStringAppendElement( dsp, "-" );
00686                 goto bin;
00687         case OP_XOR:
00688                 Tcl_DStringAppendElement( dsp, "^" );
00689         bin:
00690                 Tcl_DStringStartSublist( dsp );
00691                 db_tcl_tree_describe( dsp, tp->tr_b.tb_left );
00692                 Tcl_DStringEndSublist( dsp );
00693 
00694                 Tcl_DStringStartSublist( dsp );
00695                 db_tcl_tree_describe( dsp, tp->tr_b.tb_right );
00696                 Tcl_DStringEndSublist( dsp );
00697 
00698                 break;
00699 
00700                 /* This node is known to be a unary op */
00701         case OP_NOT:
00702                 Tcl_DStringAppendElement( dsp, "!" );
00703                 goto unary;
00704         case OP_GUARD:
00705                 Tcl_DStringAppendElement( dsp, "G" );
00706                 goto unary;
00707         case OP_XNOP:
00708                 Tcl_DStringAppendElement( dsp, "X" );
00709         unary:
00710                 Tcl_DStringStartSublist( dsp );
00711                 db_tcl_tree_describe( dsp, tp->tr_b.tb_left );
00712                 Tcl_DStringEndSublist( dsp );
00713                 break;
00714 
00715         case OP_NOP:
00716                 Tcl_DStringAppendElement( dsp, "N" );
00717                 break;
00718 
00719         default:
00720                 bu_log("db_tcl_tree_describe: bad op %d\n", tp->tr_op);
00721                 bu_bomb("db_tcl_tree_describe\n");
00722         }
00723 }
00724 
00725 /*
00726  *                      D B _ T C L _ T R E E _ P A R S E
00727  *
00728  *  Take a TCL-style string description of a binary tree, as produced by
00729  *  db_tcl_tree_describe(), and reconstruct
00730  *  the in-memory form of that tree.
00731  */
00732 union tree *
00733 db_tcl_tree_parse( Tcl_Interp *interp, const char *str, struct resource *resp )
00734 {
00735         int     argc;
00736         char    **argv;
00737         union tree      *tp = TREE_NULL;
00738 
00739         /* Skip over leading spaces in input */
00740         while( *str && isspace(*str) ) str++;
00741 
00742         if( Tcl_SplitList( interp, str, &argc, (const char ***)&argv ) != TCL_OK )
00743                 return TREE_NULL;
00744 
00745         if( argc <= 0 || argc > 3 )  {
00746                 Tcl_AppendResult( interp, "db_tcl_tree_parse: tree node does not have 1, 2 or 2 elements: ",
00747                         str, "\n", (char *)NULL );
00748                 goto out;
00749         }
00750 
00751 #if 0
00752 Tcl_AppendResult( interp, "\n\ndb_tcl_tree_parse(): ", str, "\n", NULL );
00753 
00754 Tcl_AppendResult( interp, "db_tcl_tree_parse() arg0=", argv[0], NULL );
00755 if(argc > 1 ) Tcl_AppendResult( interp, "\n\targ1=", argv[1], NULL );
00756 if(argc > 2 ) Tcl_AppendResult( interp, "\n\targ2=", argv[2], NULL );
00757 Tcl_AppendResult( interp, "\n\n", NULL);
00758 #endif
00759 
00760         if( argv[0][1] != '\0' )  {
00761                 Tcl_AppendResult( interp, "db_tcl_tree_parse() operator is not single character: ",
00762                         argv[0], (char *)NULL );
00763                 goto out;
00764         }
00765 
00766         switch( argv[0][0] )  {
00767         case 'l':
00768                 /* Leaf node: {l name {mat}} */
00769                 RT_GET_TREE( tp, resp );
00770                 tp->tr_l.magic = RT_TREE_MAGIC;
00771                 tp->tr_op = OP_DB_LEAF;
00772                 tp->tr_l.tl_name = bu_strdup( argv[1] );
00773                 /* If matrix not specified, NULL pointer ==> identity matrix */
00774                 tp->tr_l.tl_mat = NULL;
00775                 if( argc == 3 )  {
00776                         mat_t   m;
00777                         /* decode also recognizes "I" notation for identity */
00778                         if( bn_decode_mat( m, argv[2] ) != 16 )  {
00779                                 Tcl_AppendResult( interp, "db_tcl_tree_parse: unable to parse matrix '",
00780                                         argv[2], "', using identity", (char *)NULL );
00781                                 break;
00782                         }
00783                         if( bn_mat_is_identity(m) )
00784                                 break;
00785                         if( bn_mat_ck( "db_tcl_tree_parse", m ) )  {
00786                                 Tcl_AppendResult( interp, "db_tcl_tree_parse: matrix '",
00787                                         argv[2],
00788                                         "', does not preserve axis perpendicularity, using identity", (char *)NULL );
00789                                 break;
00790                         }
00791                         /* Finall, a good non-identity matrix, dup & save it */
00792                         tp->tr_l.tl_mat = bn_mat_dup(m);
00793                 }
00794                 break;
00795 
00796         case 'u':
00797                 /* Binary: Union: {u {lhs} {rhs}} */
00798                 RT_GET_TREE( tp, resp );
00799                 tp->tr_b.tb_op = OP_UNION;
00800                 goto binary;
00801         case 'n':
00802                 /* Binary: Intersection */
00803                 RT_GET_TREE( tp, resp );
00804                 tp->tr_b.tb_op = OP_INTERSECT;
00805                 goto binary;
00806         case '-':
00807                 /* Binary: Union */
00808                 RT_GET_TREE( tp, resp );
00809                 tp->tr_b.tb_op = OP_SUBTRACT;
00810                 goto binary;
00811         case '^':
00812                 /* Binary: Xor */
00813                 RT_GET_TREE( tp, resp );
00814                 tp->tr_b.tb_op = OP_XOR;
00815                 goto binary;
00816 binary:
00817                 tp->tr_b.magic = RT_TREE_MAGIC;
00818                 if( argv[1] == (char *)NULL || argv[2] == (char *)NULL )  {
00819                         Tcl_AppendResult( interp, "db_tcl_tree_parse: binary operator ",
00820                                 argv[0], " has insufficient operands in ",
00821                                 str, (char *)NULL );
00822                         RT_FREE_TREE( tp, resp );
00823                         tp = TREE_NULL;
00824                         goto out;
00825                 }
00826                 tp->tr_b.tb_left = db_tcl_tree_parse( interp, argv[1], resp );
00827                 if( tp->tr_b.tb_left == TREE_NULL )  {
00828                         RT_FREE_TREE( tp, resp );
00829                         tp = TREE_NULL;
00830                         goto out;
00831                 }
00832                 tp->tr_b.tb_right = db_tcl_tree_parse( interp, argv[2], resp );
00833                 if( tp->tr_b.tb_left == TREE_NULL )  {
00834                         db_free_tree( tp->tr_b.tb_left, resp );
00835                         RT_FREE_TREE( tp, resp );
00836                         tp = TREE_NULL;
00837                         goto out;
00838                 }
00839                 break;
00840 
00841         case '!':
00842                 /* Unary: not {! {lhs}} */
00843                 RT_GET_TREE( tp, resp );
00844                 tp->tr_b.tb_op = OP_NOT;
00845                 goto unary;
00846         case 'G':
00847                 /* Unary: GUARD {G {lhs}} */
00848                 RT_GET_TREE( tp, resp );
00849                 tp->tr_b.tb_op = OP_GUARD;
00850                 goto unary;
00851         case 'X':
00852                 /* Unary: XNOP {X {lhs}} */
00853                 RT_GET_TREE( tp, resp );
00854                 tp->tr_b.tb_op = OP_XNOP;
00855                 goto unary;
00856 unary:
00857                 tp->tr_b.magic = RT_TREE_MAGIC;
00858                 if( argv[1] == (char *)NULL )  {
00859                         Tcl_AppendResult( interp, "db_tcl_tree_parse: unary operator ",
00860                                 argv[0], " has insufficient operands in ",
00861                                 str, "\n", (char *)NULL );
00862                         bu_free( (char *)tp, "union tree" );
00863                         tp = TREE_NULL;
00864                         goto out;
00865                 }
00866                 tp->tr_b.tb_left = db_tcl_tree_parse( interp, argv[1], resp );
00867                 if( tp->tr_b.tb_left == TREE_NULL )  {
00868                         bu_free( (char *)tp, "union tree" );
00869                         tp = TREE_NULL;
00870                         goto out;
00871                 }
00872                 break;
00873 
00874         case 'N':
00875                 /* NOP: no args.  {N} */
00876                 RT_GET_TREE( tp, resp );
00877                 tp->tr_b.tb_op = OP_XNOP;
00878                 tp->tr_b.magic = RT_TREE_MAGIC;
00879                 break;
00880 
00881         default:
00882                 Tcl_AppendResult( interp, "db_tcl_tree_parse: unable to interpret operator '",
00883                         argv[1], "'\n", (char *)NULL );
00884         }
00885 
00886 out:
00887         Tcl_Free( (char *)argv);                /* not bu_free(), not free() */
00888         return tp;
00889 }
00890 
00891 /*
00892  *                      R T _ C O M B _ T C L G E T
00893  *
00894  *  Sets the interp->result string to a description of the given combination.
00895  *  Entered via rt_functab[].ft_tclget().
00896  */
00897 int
00898 rt_comb_tclget(Tcl_Interp *interp, const struct rt_db_internal *intern, const char *item)
00899 {
00900         const struct rt_comb_internal *comb;
00901         char buf[128];
00902         Tcl_DString     ds;
00903 
00904         RT_CK_DB_INTERNAL(intern);
00905         comb = (struct rt_comb_internal *)intern->idb_ptr;
00906         RT_CK_COMB_TCL(interp,comb);
00907 
00908         if( item==0 ) {
00909                 /* Print out the whole combination. */
00910                 Tcl_DStringInit( &ds );
00911 
00912                 Tcl_DStringAppendElement( &ds, "comb" );
00913                 Tcl_DStringAppendElement( &ds, "region" );
00914                 if( comb->region_flag ) {
00915                         Tcl_DStringAppendElement( &ds, "yes" );
00916 
00917                         Tcl_DStringAppendElement( &ds, "id" );
00918                         sprintf( buf, "%d", comb->region_id );
00919                         Tcl_DStringAppendElement( &ds, buf );
00920 
00921                         if( comb->aircode )  {
00922                                 Tcl_DStringAppendElement( &ds, "air" );
00923                                 sprintf( buf, "%d", comb->aircode );
00924                                 Tcl_DStringAppendElement( &ds, buf );
00925                         }
00926                         if( comb->los )  {
00927                                 Tcl_DStringAppendElement( &ds, "los" );
00928                                 sprintf( buf, "%d", comb->los );
00929                                 Tcl_DStringAppendElement( &ds, buf );
00930                         }
00931 
00932                         if( comb->GIFTmater )  {
00933                                 Tcl_DStringAppendElement( &ds, "GIFTmater" );
00934                                 sprintf( buf, "%d", comb->GIFTmater );
00935                                 Tcl_DStringAppendElement( &ds, buf );
00936                         }
00937                 } else {
00938                         Tcl_DStringAppendElement( &ds, "no" );
00939                 }
00940 
00941                 if( comb->rgb_valid ) {
00942                         Tcl_DStringAppendElement( &ds, "rgb" );
00943                         sprintf( buf, "%d %d %d", V3ARGS(comb->rgb) );
00944                         Tcl_DStringAppendElement( &ds, buf );
00945                 }
00946 
00947                 if( bu_vls_strlen(&comb->shader) > 0 )  {
00948                         Tcl_DStringAppendElement( &ds, "shader" );
00949                         Tcl_DStringAppendElement( &ds, bu_vls_addr(&comb->shader) );
00950                 }
00951 
00952                 if( bu_vls_strlen(&comb->material) > 0 )  {
00953                         Tcl_DStringAppendElement( &ds, "material" );
00954                         Tcl_DStringAppendElement( &ds, bu_vls_addr(&comb->material) );
00955                 }
00956 
00957                 if( comb->inherit ) {
00958                         Tcl_DStringAppendElement( &ds, "inherit" );
00959                         Tcl_DStringAppendElement( &ds, "yes" );
00960                 }
00961 
00962                 Tcl_DStringAppendElement( &ds, "tree" );
00963                 Tcl_DStringStartSublist( &ds );
00964                 db_tcl_tree_describe( &ds, comb->tree );
00965                 Tcl_DStringEndSublist( &ds );
00966 
00967                 Tcl_DStringResult( interp, &ds );
00968                 Tcl_DStringFree( &ds );
00969 
00970                 return TCL_OK;
00971         } else {
00972                 /* Print out only the requested item. */
00973                 register int i;
00974                 char itemlwr[128];
00975 
00976                 for( i = 0; i < 128 && item[i]; i++ ) {
00977                         itemlwr[i] = (isupper(item[i]) ? tolower(item[i]) :
00978                                       item[i]);
00979                 }
00980                 itemlwr[i] = 0;
00981 
00982                 if( strcmp(itemlwr, "region")==0 ) {
00983                         strcpy( buf, comb->region_flag ? "yes" : "no" );
00984                 } else if( strcmp(itemlwr, "id")==0 ) {
00985                         if( !comb->region_flag ) goto not_region;
00986                         sprintf( buf, "%d", comb->region_id );
00987                 } else if( strcmp(itemlwr, "air")==0 ) {
00988                         if( !comb->region_flag ) goto not_region;
00989                         sprintf( buf, "%d", comb->aircode );
00990                 } else if( strcmp(itemlwr, "los")==0 ) {
00991                         if( !comb->region_flag ) goto not_region;
00992                         sprintf( buf, "%d", comb->los );
00993                 } else if( strcmp(itemlwr, "giftmater")==0 ) {
00994                         if( !comb->region_flag ) goto not_region;
00995                         sprintf( buf, "%d", comb->GIFTmater );
00996                 } else if( strcmp(itemlwr, "rgb")==0 ) {
00997                         if( comb->rgb_valid )
00998                                 sprintf( buf, "%d %d %d", V3ARGS(comb->rgb) );
00999                         else
01000                                 strcpy( buf, "invalid" );
01001                 } else if( strcmp(itemlwr, "shader")==0 ) {
01002                         Tcl_AppendResult( interp, bu_vls_addr(&comb->shader),
01003                                           (char *)NULL );
01004                         return TCL_OK;
01005                 } else if( strcmp(itemlwr, "material")==0 ) {
01006                         Tcl_AppendResult( interp, bu_vls_addr(&comb->material),
01007                                           (char *)NULL );
01008                         return TCL_OK;
01009                 } else if( strcmp(itemlwr, "inherit")==0 ) {
01010                         strcpy( buf, comb->inherit ? "yes" : "no" );
01011                 } else if( strcmp(itemlwr, "tree")==0 ) {
01012                         Tcl_DStringInit( &ds );
01013                         db_tcl_tree_describe( &ds, comb->tree );
01014                         Tcl_DStringResult( interp, &ds );
01015                         Tcl_DStringFree( &ds );
01016                         return TCL_OK;
01017                 } else {
01018                         Tcl_AppendResult( interp, "no such attribute",
01019                                           (char *)NULL );
01020                         return TCL_ERROR;
01021                 }
01022 
01023                 Tcl_AppendResult( interp, buf, (char *)NULL );
01024                 return TCL_OK;
01025 
01026         not_region:
01027                 Tcl_AppendResult( interp, "item not valid for non-region",
01028                                   (char *)NULL );
01029                 return TCL_ERROR;
01030         }
01031 }
01032 
01033 
01034 /*
01035  *                      R T _ C O M B _ T C L A D J U S T
01036  *
01037  *  Example -
01038  *      rgb "1 2 3" ...
01039  *
01040  *  Invoked via rt_functab[ID_COMBINATION].ft_tcladjust()
01041  */
01042 int
01043 rt_comb_tcladjust(
01044         Tcl_Interp              *interp,
01045         struct rt_db_internal   *intern,
01046         int                     argc,
01047         char                    **argv,
01048         struct resource         *resp )
01049 {
01050         struct rt_comb_internal        *comb;
01051         char    buf[128];
01052         int     i;
01053         double  d;
01054 
01055         RT_CK_DB_INTERNAL(intern);
01056         RT_CK_RESOURCE(resp);
01057         comb = (struct rt_comb_internal *)intern->idb_ptr;
01058         RT_CK_COMB(comb);
01059 
01060         while( argc >= 2 ) {
01061                 /* Force to lower case */
01062                 for( i=0; i<128 && argv[0][i]!='\0'; i++ )
01063                         buf[i] = isupper(argv[0][i])?tolower(argv[0][i]):argv[0][i];
01064                 buf[i] = 0;
01065 
01066                 if( strcmp(buf, "region")==0 ) {
01067                         if( strcmp( argv[1], "none" ) == 0 )
01068                                 comb->region_flag = 0;
01069                         else
01070                         {
01071                                 if( Tcl_GetBoolean( interp, argv[1], &i )!= TCL_OK )
01072                                         return TCL_ERROR;
01073                                 comb->region_flag = (char)i;
01074                         }
01075                 } else if( strcmp(buf, "temp")==0 ) {
01076                         if( !comb->region_flag ) goto not_region;
01077                         if( strcmp( argv[1], "none" ) == 0 )
01078                                 comb->temperature = 0.0;
01079                         else
01080                         {
01081                                 if( Tcl_GetDouble( interp, argv[1], &d ) != TCL_OK )
01082                                         return TCL_ERROR;
01083                                 comb->temperature = (float)d;
01084                         }
01085                 } else if( strcmp(buf, "id")==0 ) {
01086                         if( !comb->region_flag ) goto not_region;
01087                         if( strcmp( argv[1], "none" ) == 0 )
01088                                 comb->region_id = 0;
01089                         else
01090                         {
01091                                 if( Tcl_GetInt( interp, argv[1], &i ) != TCL_OK )
01092                                         return TCL_ERROR;
01093                                 comb->region_id = i;
01094                         }
01095                 } else if( strcmp(buf, "air")==0 ) {
01096                         if( !comb->region_flag ) goto not_region;
01097                         if( strcmp( argv[1], "none" ) == 0 )
01098                                 comb->aircode = 0;
01099                         else
01100                         {
01101                                 if( Tcl_GetInt( interp, argv[1], &i ) != TCL_OK)
01102                                         return TCL_ERROR;
01103                                 comb->aircode = i;
01104                         }
01105                 } else if( strcmp(buf, "los")==0 ) {
01106                         if( !comb->region_flag ) goto not_region;
01107                         if( strcmp( argv[1], "none" ) == 0 )
01108                                 comb->los = 0;
01109                         else
01110                         {
01111                                 if( Tcl_GetInt( interp, argv[1], &i ) != TCL_OK )
01112                                         return TCL_ERROR;
01113                                 comb->los = i;
01114                         }
01115                 } else if( strcmp(buf, "giftmater")==0 ) {
01116                         if( !comb->region_flag ) goto not_region;
01117                         if( strcmp( argv[1], "none" ) == 0 )
01118                                 comb->GIFTmater = 0;
01119                         else
01120                         {
01121                                 if( Tcl_GetInt( interp, argv[1], &i ) != TCL_OK )
01122                                         return TCL_ERROR;
01123                                 comb->GIFTmater = i;
01124                         }
01125                 } else if( strcmp(buf, "rgb")==0 ) {
01126                         if( strcmp(argv[1], "invalid")==0 || strcmp( argv[1], "none" ) == 0 ) {
01127                                 comb->rgb[0] = comb->rgb[1] =
01128                                         comb->rgb[2] = 0;
01129                                 comb->rgb_valid = 0;
01130                         } else {
01131                                 unsigned int r, g, b;
01132                                 i = sscanf( argv[1], "%u %u %u",
01133                                         &r, &g, &b );
01134                                 if( i != 3 )   {
01135                                         Tcl_AppendResult( interp, "adjust rgb ",
01136                                                 argv[1], ": not valid rgb 3-tuple\n", (char *)NULL );
01137                                         return TCL_ERROR;
01138                                 }
01139                                 comb->rgb[0] = (unsigned char)r;
01140                                 comb->rgb[1] = (unsigned char)g;
01141                                 comb->rgb[2] = (unsigned char)b;
01142                                 comb->rgb_valid = 1;
01143                         }
01144                 } else if( strcmp(buf, "shader" )==0 ) {
01145                         bu_vls_trunc( &comb->shader, 0 );
01146                         if( strcmp( argv[1], "none" ) )
01147                         {
01148                                 bu_vls_strcat( &comb->shader, argv[1] );
01149                                 /* Leading spaces boggle the combination exporter */
01150                                 bu_vls_trimspace( &comb->shader );
01151                         }
01152                 } else if( strcmp(buf, "material" )==0 ) {
01153                         bu_vls_trunc( &comb->material, 0 );
01154                         if( strcmp( argv[1], "none" ) )
01155                         {
01156                                 bu_vls_strcat( &comb->material, argv[1] );
01157                                 bu_vls_trimspace( &comb->material );
01158                         }
01159                 } else if( strcmp(buf, "inherit" )==0 ) {
01160                         if( strcmp( argv[1], "none" ) == 0 )
01161                                 comb->inherit = 0;
01162                         else
01163                         {
01164                                 if( Tcl_GetBoolean( interp, argv[1], &i ) != TCL_OK )
01165                                         return TCL_ERROR;
01166                                 comb->inherit = (char)i;
01167                         }
01168                 } else if( strcmp(buf, "tree" )==0 ) {
01169                         union tree      *new;
01170 
01171                         if( *argv[1] == '\0' || strcmp( argv[1], "none" ) == 0 )
01172                         {
01173                                 if( comb->tree ) {
01174                                         db_free_tree( comb->tree, resp );
01175                                 }
01176                                 comb->tree = TREE_NULL;
01177                         }
01178                         else
01179                         {
01180                                 new = db_tcl_tree_parse( interp, argv[1], resp );
01181                                 if( new == TREE_NULL )  {
01182                                         Tcl_AppendResult( interp, "db adjust tree: bad tree '",
01183                                                 argv[1], "'\n", (char *)NULL );
01184                                         return TCL_ERROR;
01185                                 }
01186                                 if( comb->tree )
01187                                         db_free_tree( comb->tree, resp );
01188                                 comb->tree = new;
01189                         }
01190                 } else {
01191                         Tcl_AppendResult( interp, "db adjust ", buf,
01192                                           ": no such attribute",
01193                                           (char *)NULL );
01194                         return TCL_ERROR;
01195                 }
01196                 argc -= 2;
01197                 argv += 2;
01198         }
01199 
01200         return TCL_OK;
01201 
01202  not_region:
01203         Tcl_AppendResult( interp, "adjusting attribute ",
01204                 buf, " is not valid for a non-region combination.",
01205                           (char *)NULL );
01206         return TCL_ERROR;
01207 }
01208 
01209 /************************************************************************************************
01210  *                                                                                              *
01211  *                      Tcl interface to the Database                                           *
01212  *                                                                                              *
01213  ************************************************************************************************/
01214 
01215 /*
01216  *                      R T _ T C L _ I M P O R T _ F R O M _ P A T H
01217  *
01218  *  Given the name of a database object or a full path to a leaf object,
01219  *  obtain the internal form of that leaf.
01220  *  Packaged separately mainly to make available nice Tcl error handling.
01221  *
01222  *  Returns -
01223  *      TCL_OK
01224  *      TCL_ERROR
01225  */
01226 int
01227 rt_tcl_import_from_path(Tcl_Interp *interp, struct rt_db_internal *ip, const char *path, struct rt_wdb *wdb)
01228 {
01229         struct db_i     *dbip;
01230         int             status;
01231 
01232         /* Can't run RT_CK_DB_INTERNAL(ip), it hasn't been filled in yet */
01233         RT_CK_WDB(wdb);
01234         dbip = wdb->dbip;
01235         RT_CK_DBI(dbip);
01236 
01237 #if 0
01238         dp = db_lookup( dbip, path, LOOKUP_QUIET );
01239         if( dp == NULL ) {
01240                 Tcl_AppendResult( interp, path, ": not found\n",
01241                                   (char *)NULL );
01242                 return TCL_ERROR;
01243         }
01244 
01245         status = rt_db_get_internal( ip, dp, dbip, (matp_t)NULL );
01246         if( status < 0 ) {
01247                 Tcl_AppendResult( interp, "rt_tcl_import_from_path failure: ",
01248                                   path, (char *)NULL );
01249                 return TCL_ERROR;
01250         }
01251 #else
01252         if( strchr( path, '/' ) )
01253         {
01254                 /* This is a path */
01255                 struct db_tree_state    ts;
01256                 struct db_full_path     old_path;
01257                 struct db_full_path     new_path;
01258                 struct directory        *dp_curr;
01259                 int                     ret;
01260 
01261                 db_init_db_tree_state( &ts, dbip, &rt_uniresource );
01262                 db_full_path_init(&old_path);
01263                 db_full_path_init(&new_path);
01264 
01265                 if( db_string_to_path( &new_path, dbip, path ) < 0 )  {
01266                         Tcl_AppendResult(interp, "rt_tcl_import_from_path: '",
01267                                 path, "' contains unknown object names\n", (char *)NULL);
01268                         return TCL_ERROR;
01269                 }
01270 
01271                 dp_curr = DB_FULL_PATH_CUR_DIR( &new_path );
01272                 ret = db_follow_path( &ts, &old_path, &new_path, LOOKUP_NOISY, 0 );
01273                 db_free_full_path( &old_path );
01274                 db_free_full_path( &new_path );
01275 
01276                 if( ret < 0 )  {
01277                         Tcl_AppendResult(interp, "rt_tcl_import_from_path: '",
01278                                 path, "' is a bad path\n", (char *)NULL );
01279                         return TCL_ERROR;
01280                 }
01281 
01282                 status = wdb_import( wdb, ip, dp_curr->d_namep, ts.ts_mat );
01283                 if( status == -4 )  {
01284                         Tcl_AppendResult( interp, dp_curr->d_namep,
01285                                         " not found in path ", path, "\n",
01286                                         (char *)NULL );
01287                         return TCL_ERROR;
01288                 }
01289                 if( status < 0 ) {
01290                         Tcl_AppendResult( interp, "wdb_import failure: ",
01291                                           dp_curr->d_namep, (char *)NULL );
01292                         return TCL_ERROR;
01293                 }
01294         }
01295         else
01296         {
01297                 status = wdb_import( wdb, ip, path, (matp_t)NULL );
01298                 if( status == -4 )  {
01299                         Tcl_AppendResult( interp, path, ": not found\n",
01300                                           (char *)NULL );
01301                         return TCL_ERROR;
01302                 }
01303                 if( status < 0 ) {
01304                         Tcl_AppendResult( interp, "wdb_import failure: ",
01305                                           path, (char *)NULL );
01306                         return TCL_ERROR;
01307                 }
01308         }
01309 #endif
01310         return TCL_OK;
01311 }
01312 
01313 /*
01314  *                      R T _ P A R S E T A B _ T C L G E T
01315  *
01316  *  This is the generic routine to be listed in rt_functab[].ft_tclget
01317  *  for those solid types which are fully described by their ft_parsetab
01318  *  entry.
01319  *
01320  *  'attr' is specified to retrieve only one attribute, rather than all.
01321  *  Example:  "db get ell.s B" to get only the B vector.
01322  */
01323 int
01324 rt_parsetab_tclget(Tcl_Interp *interp, const struct rt_db_internal *intern, const char *attr)
01325 {
01326         register const struct bu_structparse    *sp = NULL;
01327         register const struct rt_functab        *ftp;
01328         int                     status;
01329         Tcl_DString             ds;
01330         struct bu_vls           str;
01331 
01332         RT_CK_DB_INTERNAL( intern );
01333         ftp = intern->idb_meth;
01334         RT_CK_FUNCTAB(ftp);
01335 
01336         sp = ftp->ft_parsetab;
01337         if( !sp )  {
01338                 Tcl_AppendResult( interp, ftp->ft_label,
01339  " {a Tcl output routine for this type of object has not yet been implemented}",
01340                   (char *)NULL );
01341                 return TCL_ERROR;
01342         }
01343 
01344         bu_vls_init( &str );
01345         Tcl_DStringInit( &ds );
01346 
01347         if( attr == (char *)0 ) {
01348                 /* Print out solid type and all attributes */
01349                 Tcl_DStringAppendElement( &ds, ftp->ft_label );
01350                 while( sp->sp_name != NULL ) {
01351                         Tcl_DStringAppendElement( &ds, sp->sp_name );
01352                         bu_vls_trunc( &str, 0 );
01353                         bu_vls_struct_item( &str, sp,
01354                                          (char *)intern->idb_ptr, ' ' );
01355                         Tcl_DStringAppendElement( &ds, bu_vls_addr(&str) );
01356                         ++sp;
01357                 }
01358                 status = TCL_OK;
01359         } else {
01360                 if( bu_vls_struct_item_named( &str, sp, attr,
01361                                    (char *)intern->idb_ptr, ' ') < 0 ) {
01362                         bu_vls_printf(&str,
01363                                 "Objects of type %s do not have a %s attribute.",
01364                                 ftp->ft_label, attr);
01365                         status = TCL_ERROR;
01366                 } else {
01367                         status = TCL_OK;
01368                 }
01369                 Tcl_DStringAppend( &ds, bu_vls_addr(&str), -1 );
01370         }
01371 
01372         Tcl_DStringResult( interp, &ds );
01373         Tcl_DStringFree( &ds );
01374         bu_vls_free( &str );
01375 
01376         return status;
01377 }
01378 
01379 /*
01380  *                      R T _ C O M B _ T C L F O R M
01381  */
01382 int
01383 rt_comb_tclform(const struct rt_functab *ftp, Tcl_Interp *interp)
01384 {
01385         RT_CK_FUNCTAB(ftp);
01386 
01387         Tcl_AppendResult( interp,
01388 "region {%s} id {%d} air {%d} los {%d} GIFTmater {%d} rgb {%d %d %d} \
01389 shader {%s} material {%s} inherit {%s} tree {%s}", (char *)NULL );
01390         return TCL_OK;
01391 }
01392 
01393 /*
01394  *                      R T _ C O M B _ M A K E
01395  *
01396  *  Create a blank combination with appropriate values.
01397  *
01398  *  Called via rt_functab[ID_COMBINATION].ft_make().
01399  */
01400 void
01401 rt_comb_make(const struct rt_functab *ftp, struct rt_db_internal *intern, double diameter)
01402 {
01403         struct rt_comb_internal *comb;
01404 
01405         intern->idb_major_type = DB5_MAJORTYPE_BRLCAD;
01406         intern->idb_type = ID_COMBINATION;
01407         intern->idb_meth = &rt_functab[ID_COMBINATION];
01408         intern->idb_ptr = bu_calloc( sizeof(struct rt_comb_internal), 1,
01409                                             "rt_comb_internal" );
01410 
01411         comb = (struct rt_comb_internal *)intern->idb_ptr;
01412         comb->magic = (long)RT_COMB_MAGIC;
01413         comb->temperature = -1;
01414         comb->tree = (union tree *)0;
01415         comb->region_flag = 1;
01416         comb->region_id = 0;
01417         comb->aircode = 0;
01418         comb->GIFTmater = 0;
01419         comb->los = 0;
01420         comb->rgb_valid = 0;
01421         comb->rgb[0] = comb->rgb[1] = comb->rgb[2] = 0;
01422         bu_vls_init( &comb->shader );
01423         bu_vls_init( &comb->material );
01424         comb->inherit = 0;
01425 }
01426 
01427 /*
01428  *                      R T _ G E N E R I C _ M A K E
01429  *
01430  *  This one assumes that making all the parameters null is fine.
01431  *  (More generally, diameter == 0 means make 'em all zero, otherwise
01432  *  build something interesting to look at.)
01433  */
01434 void
01435 rt_generic_make(const struct rt_functab *ftp, struct rt_db_internal *intern, double diameter)
01436 {
01437         intern->idb_type = ftp - rt_functab;
01438         intern->idb_major_type = DB5_MAJORTYPE_BRLCAD;
01439         BU_ASSERT(&rt_functab[intern->idb_type] == ftp);
01440 
01441         intern->idb_meth = ftp;
01442         intern->idb_ptr = bu_calloc( ftp->ft_internal_size, 1, "rt_generic_make");
01443         *((long *)(intern->idb_ptr)) = ftp->ft_internal_magic;
01444 }
01445 
01446 /*
01447  *                      R T _ P A R S E T A B _ T C L A D J U S T
01448  *
01449  *  For those solids entirely defined by their parsetab.
01450  *  Invoked via rt_functab[].ft_tcladjust()
01451  */
01452 int
01453 rt_parsetab_tcladjust(Tcl_Interp *interp, struct rt_db_internal *intern, int argc, char **argv)
01454 {
01455         const struct rt_functab *ftp;
01456 
01457         RT_CK_DB_INTERNAL(intern);
01458         ftp = intern->idb_meth;
01459         RT_CK_FUNCTAB(ftp);
01460 
01461         if( ftp->ft_parsetab == (struct bu_structparse *)NULL ) {
01462                 Tcl_AppendResult( interp, ftp->ft_label,
01463                           " type objects do not yet have a 'db put' (tcladjust) handler.",
01464                           (char *)NULL );
01465                 return TCL_ERROR;
01466         }
01467 
01468         return bu_structparse_argv(interp, argc, argv, ftp->ft_parsetab,
01469                                 (char *)intern->idb_ptr );
01470 }
01471 
01472 /*
01473  *                      R T _ P A R S E T A B _ T C L F O R M
01474  *
01475  *  Invoked via rt_functab[].ft_tclform()
01476  *  on solid types which are fully described by their bu_structparse table
01477  *  in ft_parsetab.
01478  */
01479 int
01480 rt_parsetab_tclform(const struct rt_functab *ftp, Tcl_Interp *interp)
01481 {
01482         RT_CK_FUNCTAB(ftp);
01483 
01484         if( ftp->ft_parsetab )  {
01485                 bu_structparse_get_terse_form( interp, ftp->ft_parsetab );
01486                 return TCL_OK;
01487         }
01488         Tcl_AppendResult(interp, ftp->ft_label,
01489                 " is a valid object type, but a 'form' routine has not yet been implemented.",
01490                 (char *)NULL );
01491         return TCL_ERROR;
01492 }
01493 
01494 
01495 /*
01496  *                      R T _ T C L _ S E T U P
01497  *
01498  *  Add all the supported Tcl interfaces to LIBRT routines to
01499  *  the list of commands known by the given interpreter.
01500  *
01501  *  wdb_open creates database "objects" which appear as Tcl procs,
01502  *  which respond to many operations.
01503  *  The "db rt_gettrees" operation in turn creates a ray-traceable object
01504  *  as yet another Tcl proc, which responds to additional operations.
01505  *
01506  *  Note that the MGED mainline C code automatically runs
01507  *  "wdb_open db" and "wdb_open .inmem" on behalf of the MGED user,
01508  *  which exposes all of this power.
01509  */
01510 void
01511 rt_tcl_setup(Tcl_Interp *interp)
01512 {
01513         extern int rt_bot_minpieces;    /* from g_bot.c */
01514         extern int rt_bot_tri_per_piece;        /* from g_bot.c */
01515 
01516         /* initialize database objects */
01517         Wdb_Init(interp);
01518 
01519         /* initialize drawable geometry objects */
01520         Dgo_Init(interp);
01521 
01522         /* initialize view objects */
01523         Vo_Init(interp);
01524 
01525         Tcl_SetVar(interp, "rt_version", (char *)rt_version+5, TCL_GLOBAL_ONLY);
01526         Tcl_LinkVar(interp, "rt_bot_minpieces", (char *)&rt_bot_minpieces, TCL_LINK_INT);
01527 
01528         Tcl_LinkVar(interp, "rt_bot_tri_per_piece",
01529                     (char *)&rt_bot_tri_per_piece, TCL_LINK_INT);
01530 }
01531 
01532 
01533 /*
01534  *                      R T _ I N I T
01535  *
01536  *  Allows LIBRT to be dynamically loade to a vanilla tclsh/wish with
01537  *  "load /usr/brlcad/lib/libbu.so"
01538  *  "load /usr/brlcad/lib/libbn.so"
01539  *  "load /usr/brlcad/lib/librt.so"
01540  */
01541 int
01542 #ifdef BRLCAD_DEBUG
01543 Rt_d_Init(Tcl_Interp *interp)
01544 #else
01545 Rt_Init(Tcl_Interp *interp)
01546 #endif
01547 {
01548         const char *version_number;
01549 
01550         /*XXX how much will this break? */
01551         if (BU_LIST_UNINITIALIZED(&rt_g.rtg_vlfree)) {
01552                 if (bu_avail_cpus() > 1) {
01553                         rt_g.rtg_parallel = 1;
01554                         bu_semaphore_init(RT_SEM_LAST);
01555                 }
01556 
01557                 /* initialize RT's global state */
01558                 BU_LIST_INIT(&rt_g.rtg_vlfree);
01559                 BU_LIST_INIT(&rt_g.rtg_headwdb.l);
01560                 rt_init_resource(&rt_uniresource, 0, NULL);
01561         }
01562 
01563         rt_tcl_setup(interp);
01564         Tcl_Eval(interp, "lindex $rt_version 2");
01565         version_number = Tcl_GetStringResult(interp);
01566         Tcl_PkgProvide(interp,  "Rt", version_number);
01567 
01568         return TCL_OK;
01569 }
01570 
01571 
01572 /* ====================================================================== */
01573 
01574 /* TCL-oriented C support for LIBRT */
01575 
01576 
01577 /*
01578  * (db_path.c)
01579  *                      D B _ F U L L _ P A T H _ A P P E N D R E S U L T
01580  *
01581  *  Take a db_full_path and append it to the TCL result string.
01582  */
01583 void
01584 db_full_path_appendresult( Tcl_Interp *interp, const struct db_full_path *pp )
01585 {
01586         register int i;
01587 
01588         RT_CK_FULL_PATH(pp);
01589 
01590         for( i=0; i<pp->fp_len; i++ )  {
01591                 Tcl_AppendResult(interp, "/", pp->fp_names[i]->d_namep, (char *)NULL );
01592         }
01593 }
01594 
01595 /*
01596  *              T C L _ O B J _ T O _ I N T _ A R R A Y
01597  *
01598  *      Expects the Tcl_obj argument (list) to be a Tcl list and
01599  *      extracts list elements, converts them to int, and stores
01600  *      them in the passed in array. If the array_len argument is zero,
01601  *      a new array of approriate length is allocated. The return value
01602  *      is the number of elements converted.
01603  */
01604 int
01605 tcl_obj_to_int_array(Tcl_Interp *interp, Tcl_Obj *list, int **array, int *array_len)
01606 {
01607         Tcl_Obj **obj_array;
01608         int len, i;
01609 
01610         if( Tcl_ListObjGetElements( interp, list, &len, &obj_array ) != TCL_OK )
01611                 return( 0 );
01612 
01613         if( len < 1 )
01614                 return( 0 );
01615 
01616         if( *array_len < 1 )
01617         {
01618                 *array = (int *)bu_calloc( len, sizeof( int ), "array" );
01619                 *array_len = len;
01620         }
01621 
01622         for( i=0 ; i<len && i<*array_len ; i++ ) {
01623                 (*array)[i] = atoi( Tcl_GetStringFromObj( obj_array[i], NULL ) );
01624                 Tcl_DecrRefCount( obj_array[i] );
01625         }
01626 
01627         return( len < *array_len ? len : *array_len );
01628 }
01629 
01630 /*      T C L _ L I S T _ T O _ I N T _ A R R A Y
01631  *
01632  *      interface to above tcl_obj_to_int_array() routine. This routine
01633  *      expects a character string instead of a Tcl_Obj.
01634  *
01635  *      Returns the number of elements converted.
01636  */
01637 
01638 int
01639 tcl_list_to_int_array(Tcl_Interp *interp, char *char_list, int **array, int *array_len)
01640 {
01641         Tcl_Obj *obj;
01642         int ret;
01643 
01644         obj = Tcl_NewStringObj( char_list, -1 );
01645 
01646         ret = tcl_obj_to_int_array( interp, obj, array, array_len );
01647 
01648         return( ret );
01649 }
01650 
01651 /*
01652  *              T C L _ O B J _ T O _ F A S T F _ A R R A Y
01653  *
01654  *      Expects the Tcl_obj argument (list) to be a Tcl list and
01655  *      extracts list elements, converts them to fastf_t, and stores
01656  *      them in the passed in array. If the array_len argument is zero,
01657  *      a new array of approriate length is allocated. The return value
01658  *      is the number of elements converted.
01659  */
01660 
01661 int
01662 tcl_obj_to_fastf_array(Tcl_Interp *interp, Tcl_Obj *list, fastf_t **array, int *array_len)
01663 {
01664         Tcl_Obj **obj_array;
01665         int len, i;
01666         int ret;
01667 
01668         if( (ret=Tcl_ListObjGetElements( interp, list, &len, &obj_array )) != TCL_OK )
01669                 return( ret );
01670 
01671         if( len < 1 )
01672                 return( 0 );
01673 
01674         if( *array_len < 1 )
01675         {
01676                 *array = (fastf_t *)bu_calloc( len, sizeof( fastf_t ), "array" );
01677                 *array_len = len;
01678         }
01679 
01680         for( i=0 ; i<len && i<*array_len ; i++ ) {
01681                 (*array)[i] = atof( Tcl_GetStringFromObj( obj_array[i], NULL ) );
01682                 Tcl_DecrRefCount( obj_array[i] );
01683         }
01684 
01685         return( len < *array_len ? len : *array_len );
01686 }
01687 
01688 /*      T C L _ L I S T _ T O _ F A S T F _ A R R A Y
01689  *
01690  *      interface to above tcl_obj_to_fastf_array() routine. This routine
01691  *      expects a character string instead of a Tcl_Obj.
01692  *
01693  *      Returns the number of elements converted.
01694  */
01695 
01696 int
01697 tcl_list_to_fastf_array(Tcl_Interp *interp, char *char_list, fastf_t **array, int *array_len)
01698 {
01699         Tcl_Obj *obj;
01700         int ret;
01701 
01702         obj = Tcl_NewStringObj( char_list, -1 );
01703 
01704         ret = tcl_obj_to_fastf_array( interp, obj, array, array_len );
01705 
01706         return( ret );
01707 }
01708 
01709 /*
01710  * Local Variables:
01711  * mode: C
01712  * tab-width: 8
01713  * c-basic-offset: 4
01714  * indent-tabs-mode: t
01715  * End:
01716  * ex: shiftwidth=4 tabstop=8
01717  */

Generated on Mon Sep 18 01:24:57 2006 for BRL-CAD by  doxygen 1.4.6