コード例 #1
0
int
rt_db_get_internal(
    struct rt_db_internal *ip,
    const struct directory *dp,
    const struct db_i *dbip,
    const mat_t mat,
    struct resource *resp)
{
    struct bu_external ext;
    int id;
    int ret;

    RT_DB_INTERNAL_INIT(ip);

    if (dbip->dbi_version > 4)
	return rt_db_get_internal5(ip, dp, dbip, mat, resp);

    BU_EXTERNAL_INIT(&ext);

    if (db_get_external(&ext, dp, dbip) < 0)
	return -2;		/* FAIL */

    if (dp->d_flags & RT_DIR_COMB) {
	id = ID_COMBINATION;
    } else {
	/* As a convenience to older ft_import4 routines */
	if (mat == NULL) mat = bn_mat_identity;
	id = rt_id_solid(&ext);
    }

    /* ip is already initialized and should not be re-initialized */
    ret = -1;
    if (OBJ[id].ft_import4) {
	ret = OBJ[id].ft_import4(ip, &ext, mat, dbip, resp);
    }
    if (ret < 0) {
	bu_log("rt_db_get_internal(%s):  import failure\n",
	       dp->d_namep);
	rt_db_free_internal(ip);
	bu_free_external(&ext);
	return -1;		/* FAIL */
    }
    bu_free_external(&ext);
    RT_CK_DB_INTERNAL(ip);
    ip->idb_meth = &OBJ[id];

    /* prior to version 5, there are no attributes ... */
    bu_avs_init_empty(&ip->idb_avs);

    /* ... but this isn't the whole story: */
    if (id == ID_COMBINATION) {
	const struct rt_comb_internal *comb = (const struct rt_comb_internal *)ip->idb_ptr;
	RT_CK_COMB(comb);

	db5_sync_comb_to_attr(&ip->idb_avs, comb);
    }

    return id;			/* OK */
}
コード例 #2
0
/**
 * This routine will be called by db_walk_tree() once all the solids
 * in this region have been visited.
 *
 * This routine must be prepared to run in parallel.  As a result,
 * note that the details of the solids pointed to by the soltab
 * pointers in the tree may not be filled in when this routine is
 * called (due to the way multiple instances of solids are handled).
 * Therefore, everything which referred to the tree has been moved out
 * into the serial section.  (_rt_tree_region_assign, rt_bound_tree)
 */
HIDDEN union tree *
_rt_gettree_region_end(struct db_tree_state *tsp, const struct db_full_path *pathp, union tree *curtree, void *client_data)
{
    struct region *rp;
    struct directory *dp = NULL;
    size_t shader_len=0;
    struct rt_i *rtip;
    Tcl_HashTable *tbl = (Tcl_HashTable *)client_data;
    Tcl_HashEntry *entry;
    matp_t inv_mat;
    struct bu_attribute_value_set avs;
    struct bu_attribute_value_pair *avpp;

    RT_CK_DBI(tsp->ts_dbip);
    RT_CK_FULL_PATH(pathp);
    RT_CK_TREE(curtree);
    rtip =  tsp->ts_rtip;
    RT_CK_RTI(rtip);
    RT_CK_RESOURCE(tsp->ts_resp);

    if (curtree->tr_op == OP_NOP) {
	/* Ignore empty regions */
	return curtree;
    }

    BU_ALLOC(rp, struct region);
    rp->l.magic = RT_REGION_MAGIC;
    rp->reg_regionid = tsp->ts_regionid;
    rp->reg_is_fastgen = tsp->ts_is_fastgen;
    rp->reg_aircode = tsp->ts_aircode;
    rp->reg_gmater = tsp->ts_gmater;
    rp->reg_los = tsp->ts_los;

    dp = (struct directory *)DB_FULL_PATH_CUR_DIR(pathp);
    if (!dp)
	return TREE_NULL;

    bu_avs_init_empty(&avs);
    if (db5_get_attributes(tsp->ts_dbip, &avs, dp) == 0) {
	/* copy avs */
	bu_avs_init_empty(&(rp->attr_values));
	for (BU_AVS_FOR(avpp, &(tsp->ts_attrs))) {
	    bu_avs_add(&(rp->attr_values), avpp->name, bu_avs_get(&avs, avpp->name));
	}
    }
コード例 #3
0
HIDDEN int
constraint_eval(void *datap, int argc, const char *argv[])
{
    size_t i, obj;
    struct directory *dp;
    struct bu_attribute_value_set avs;
    struct bu_attribute_value_pair *avpp;
    int ret = BRLCAD_OK;

    struct ged *gedp = (struct ged *)datap;

    if (!gedp || argc < 1 || !argv)
	return BRLCAD_ERROR;

    GED_CHECK_READ_ONLY(gedp, GED_ERROR);

    /* multiple arguments assumed to be multiple objects */
    for (obj = 0; 2+obj < (size_t)argc; obj++) {

	/* load the constraint object */
	dp = db_lookup(gedp->ged_wdbp->dbip, argv[2+obj], LOOKUP_QUIET);
	if (dp == RT_DIR_NULL) {
	    bu_vls_printf(gedp->ged_result_str, "Unable to find %s in the database.\n", argv[2+obj]);
	    ret = BRLCAD_ERROR;
	    continue;
	}

	bu_avs_init_empty(&avs);
	if (db5_get_attributes(gedp->ged_wdbp->dbip, &avs, dp)) {
	    bu_vls_printf(gedp->ged_result_str, "Cannot get constraints from %s\n", dp->d_namep);
	    ret = BRLCAD_ERROR;
	}

	for (i=0, avpp = avs.avp; i < avs.count; i++, avpp++) {
	    bu_vls_printf(gedp->ged_result_str, "Evaluating %s constraint: %s %s\n", argv[2+obj], avpp->name, avpp->value);
	    bu_vls_printf(gedp->ged_result_str, "<<constraint eval here>>\n");
	}

	bu_avs_free(&avs);
    }

    return ret;
}
コード例 #4
0
int
ged_lc(struct ged *gedp, int argc, const char *argv[])
{
    char *file_name = NULL;
    int file_name_flag_cnt = 0;
    int sort_column = 1;
    int sort_column_flag_cnt = 0;
    int find_duplicates_flag = 0;
    int skip_special_duplicates_flag = 0;
    int skip_subtracted_regions_flag = 0;
    int descending_sort_flag = 0;
    int unrecognized_flag_cnt = 0;

    int orig_argc;
    const char **orig_argv;

    static const char *usage = "[-d|-s] [-r] [-z] [-0|-1|-2|-3|-4|-5] [-f {FileName}] {GroupName}";

    int c;
    int error_cnt = 0;

    FILE *outfile = NULL;
    struct bu_vls *output;

    const char *group_name;

    size_t i,j;
    struct bu_ptbl results1 = BU_PTBL_INIT_ZERO;
    struct bu_ptbl results2 = BU_PTBL_INIT_ZERO;
    char *path;
    char *plan;
    struct db_full_path root;
    int matches;
    struct region_record *regions;
    size_t ignored_cnt = 0;

    /* The defaults are the minimum widths to accommodate column headers */
    size_t region_id_len_max = 2;
    size_t material_id_len_max = 3;
    size_t los_len_max = 3;
    size_t obj_len_max = 6;

    /* For the output at the end */
    size_t start, end, incr;

    /* initialize result */
    bu_vls_trunc(gedp->ged_result_str, 0);

    if (argc == 1) {
	bu_vls_printf(gedp->ged_result_str, "Usage: %s\n", usage);
	return GED_HELP;
    }

    GED_CHECK_DATABASE_OPEN(gedp, GED_ERROR);
    GED_CHECK_ARGC_GT_0(gedp, argc, GED_ERROR);

    bu_optind = 1; /* re-init bu_getopt() */
    while ((c = bu_getopt(argc, (char * const *)argv, "dsrz012345f:")) != -1) {
	switch (c) {
	    case '0':
	    case '1':
	    case '2':
	    case '3':
	    case '4':
	    case '5':
		sort_column_flag_cnt++;
		sort_column = c - '0';
		break;
	    case 'f':
		file_name_flag_cnt++;
		file_name = bu_optarg;
		break;
	    case 's':
		skip_special_duplicates_flag = 1;
		/* FALLTHROUGH */
	    case 'd':
		find_duplicates_flag = 1;
		break;
	    case 'r':
		skip_subtracted_regions_flag = 1;
		break;
	    case 'z':
		descending_sort_flag = 1;
		break;
	    default:
		unrecognized_flag_cnt++;
	}
    }
    orig_argc = argc;
    orig_argv = argv;
    argc -= (bu_optind - 1);
    argv += (bu_optind - 1);

    /* Attempt to recreate the exact error messages from the original lc.tcl */

    if (file_name_flag_cnt > 1) {
	bu_vls_printf(gedp->ged_result_str, "Error: '-f' used more than once.\n");
	error_cnt++;
    }

    if (sort_column_flag_cnt > 1) {
	bu_vls_printf(gedp->ged_result_str, "Error: Sort column defined more than once.\n");
	error_cnt++;
    }

    if (file_name_flag_cnt + argc + unrecognized_flag_cnt > 3) {
	bu_vls_printf(gedp->ged_result_str, "Error: More than one group name and/or file name was specified.\n");
	error_cnt++;
    } else if (argc < 2) {
	if (file_name_flag_cnt && !file_name) {
	    bu_vls_printf(gedp->ged_result_str, "Error: Group name and file name not specified\n");
	} else {
	    bu_vls_printf(gedp->ged_result_str, "Error: Group name not specified.\n");
	}
        error_cnt++;
    } else if (argc + unrecognized_flag_cnt > 2) {
	bu_vls_printf(gedp->ged_result_str, "Error: More than one group name was specified.\n");
	error_cnt++;
    } else if (file_name_flag_cnt && !file_name) {
	bu_vls_printf(gedp->ged_result_str, "Error: File name not specified.\n");
	error_cnt++;
    }

    if (file_name) {
	char *norm_name;
	norm_name = bu_realpath(file_name, NULL);
	if (file_name[0] == '-') {
	    bu_vls_printf(gedp->ged_result_str, "Error: File name can not start with '-'.\n");
	    error_cnt++;
	} else if (bu_file_exists(file_name, NULL)) {
	    bu_vls_printf(gedp->ged_result_str, "Error: Output file %s already exists.\n",norm_name);
	    error_cnt++;
	} else {
	    outfile = fopen(file_name, "w");
	    if (!outfile) {
		bu_vls_printf(gedp->ged_result_str, "Error: %d\n", errno);
		error_cnt++;
	    }
	}
	bu_vls_printf(gedp->ged_result_str, "Output filename: %s\n", norm_name);
	bu_free(norm_name, "ged_lc");
	output = bu_vls_vlsinit();
    } else {
	output = gedp->ged_result_str;
    }

    if (error_cnt > 0) { return GED_ERROR; }

    group_name = argv[1];

    /* The 7 is for the "-name" and '\0' */
    plan = (char *) bu_malloc(sizeof(char) * (strlen(group_name) + 7), "ged_lc");
    sprintf(plan, "-name %s", group_name);
    matches = db_search(&results1, DB_SEARCH_TREE, plan, 0, NULL, gedp->ged_wdbp->dbip);
    if (matches < 1) {
	bu_vls_printf(gedp->ged_result_str, "Error: Group '%s' does not exist.\n", group_name);
	return GED_ERROR;
    }
    bu_free(plan, "ged_lc");
    db_search_free(&results1);

    if (skip_subtracted_regions_flag) {
	plan = "-type region ! -bool -";
    } else {
	plan = "-type region";
    }
    path = (char *) bu_malloc(sizeof(char) * (strlen(group_name) + 2), "ged_lc");
    sprintf(path, "/%s", group_name);
    db_string_to_path(&root, gedp->ged_wdbp->dbip, path);
    matches = db_search(&results2, DB_SEARCH_TREE, plan, root.fp_len, root.fp_names, gedp->ged_wdbp->dbip);
    bu_free(path, "ged_lc");
    if (matches < 1) { return GED_ERROR; }
    regions = (struct region_record *) bu_malloc(sizeof(struct region_record) * BU_PTBL_LEN(&results2), "ged_lc");
    for (i = 0; i < BU_PTBL_LEN(&results2); i++) {
	struct db_full_path *entry = (struct db_full_path *)BU_PTBL_GET(&results2, i);
	struct directory *dp_curr_dir = DB_FULL_PATH_CUR_DIR(entry);
	struct bu_attribute_value_set avs;

    	j = BU_PTBL_LEN(&results2) - i - 1 ;
	regions[j].ignore = 0;

	bu_avs_init_empty(&avs);
	db5_get_attributes(gedp->ged_wdbp->dbip, &avs, dp_curr_dir);

	regions[j].region_id = get_attr(&avs, "region_id");
	V_MAX(region_id_len_max, strlen(regions[j].region_id));
	regions[j].material_id = get_attr(&avs, "material_id");
	V_MAX(material_id_len_max, strlen(regions[j].material_id));
	regions[j].los = get_attr(&avs, "los");
	V_MAX(los_len_max, strlen(regions[j].los));
	regions[j].obj_name = dp_curr_dir->d_namep;
	V_MAX(obj_len_max, strlen(regions[j].obj_name));

	if (entry->fp_len > 1) {
	    struct directory *dp_parent = DB_FULL_PATH_GET(entry, entry->fp_len - 2);
	    regions[j].obj_parent = dp_parent->d_namep;
	} else {
	    regions[j].obj_parent = "--";
	}
    }

    if (find_duplicates_flag) {

	bu_sort((void *) regions, BU_PTBL_LEN(&results2), sizeof(struct region_record), cmp_regions, NULL);

	for (i = 1;  i < BU_PTBL_LEN(&results2); i++) {
	    int same;
	    if (skip_special_duplicates_flag) {
		same = !cmp_regions((void *)&(regions[i - 1]), (void *)&(regions[i]), NULL);
	    } else {
		same = !bu_strcmp(regions[i - 1].region_id, regions[i].region_id);
	    }
	    if (same) {
		regions[i].ignore = 1;
		ignored_cnt++;
	    }
	}

	if (ignored_cnt == BU_PTBL_LEN(&results2)) {
	    if (file_name) {
		print_cmd_args(output, orig_argc, orig_argv);
		bu_vls_printf(output, "No duplicate region_id\n");
		bu_vls_fwrite(outfile, output);
		fclose(outfile);
	    }
	    bu_vls_printf(gedp->ged_result_str, "No duplicate region_id\n");
	    bu_vls_printf(gedp->ged_result_str, "Done.\n");
	    bu_free(regions, "ged_lc");
	    return GED_ERROR;
	}
    }

    if (sort_column > 0) {
	bu_sort((void *) regions, BU_PTBL_LEN(&results2), sizeof(struct region_record), sort_regions, (void *)&sort_column);
    }

    if (file_name) {
	print_cmd_args(output, orig_argc, orig_argv);
    }

    bu_vls_printf(output, "List length: %d\n", BU_PTBL_LEN(&results2) - ignored_cnt);
    bu_vls_printf(output, "%-*s %-*s %-*s %-*s %s\n",
		  region_id_len_max + 1, "ID",
		  material_id_len_max + 1, "MAT",
		  los_len_max, "LOS",
		  obj_len_max,  "REGION",
		  "PARENT");
    end = BU_PTBL_LEN(&results2);
    if (descending_sort_flag) {
	start = end - 1; end = -1; incr = -1;
    } else {
	start = 0; incr = 1;
    }
    for (i = start; i != end; i += incr) {
	if (regions[i].ignore) { continue; }
	bu_vls_printf(output, "%-*s %-*s %-*s %-*s %s\n",
		      region_id_len_max + 1, regions[i].region_id,
		      material_id_len_max + 1, regions[i].material_id,
		      los_len_max, regions[i].los,
		      obj_len_max, regions[i].obj_name,
		      regions[i].obj_parent);
    }
    bu_vls_printf(gedp->ged_result_str, "Done.\n");

    if (file_name) {
	bu_vls_fwrite(outfile, output);
	fclose(outfile);
    }

    bu_free(regions, "ged_lc");

    return GED_OK;
}
コード例 #5
0
ファイル: copy.c プロジェクト: kanzure/brlcad
int
ged_dbcopy(struct ged *from_gedp, struct ged *to_gedp, const char *from, const char *to, int fflag)
{
    struct directory *from_dp;
    struct bu_external external;

    GED_CHECK_DATABASE_OPEN(from_gedp, GED_ERROR);
    GED_CHECK_DATABASE_OPEN(to_gedp, GED_ERROR);
    GED_CHECK_READ_ONLY(to_gedp, GED_ERROR);

    /* initialize result */
    bu_vls_trunc(from_gedp->ged_result_str, 0);
    bu_vls_trunc(to_gedp->ged_result_str, 0);

    GED_DB_LOOKUP(from_gedp, from_dp, from, LOOKUP_NOISY, GED_ERROR & GED_QUIET);

    if (!fflag && db_lookup(to_gedp->ged_wdbp->dbip, to, LOOKUP_QUIET) != RT_DIR_NULL) {
	bu_vls_printf(from_gedp->ged_result_str, "%s already exists.", to);
	return GED_ERROR;
    }

    if (db_get_external(&external, from_dp, from_gedp->ged_wdbp->dbip)) {
	bu_vls_printf(from_gedp->ged_result_str, "Database read error, aborting\n");
	return GED_ERROR;
    }

    if (wdb_export_external(to_gedp->ged_wdbp, &external, to,
			    from_dp->d_flags,  from_dp->d_minor_type) < 0) {
	bu_free_external(&external);
	bu_vls_printf(from_gedp->ged_result_str,
		      "Failed to write new object (%s) to database - aborting!!\n",
		      to);
	return GED_ERROR;
    }

    bu_free_external(&external);

    /* Need to do something extra for _GLOBAL */
    if (db_version(to_gedp->ged_wdbp->dbip) > 4 && BU_STR_EQUAL(to, DB5_GLOBAL_OBJECT_NAME)) {
	struct directory *to_dp;
	struct bu_attribute_value_set avs;
	const char *val;

	GED_DB_LOOKUP(to_gedp, to_dp, to, LOOKUP_NOISY, GED_ERROR & GED_QUIET);

	bu_avs_init_empty(&avs);
	if (db5_get_attributes(to_gedp->ged_wdbp->dbip, &avs, to_dp)) {
	    bu_vls_printf(from_gedp->ged_result_str, "Cannot get attributes for object %s\n", to_dp->d_namep);
	    return GED_ERROR;
	}

	if ((val = bu_avs_get(&avs, "title")) != NULL)
	    to_gedp->ged_wdbp->dbip->dbi_title = strdup(val);

	if ((val = bu_avs_get(&avs, "units")) != NULL) {
	    double loc2mm;

	    if ((loc2mm = bu_mm_value(val)) > 0) {
		to_gedp->ged_wdbp->dbip->dbi_local2base = loc2mm;
		to_gedp->ged_wdbp->dbip->dbi_base2local = 1.0 / loc2mm;
	    }
	}

	if ((val = bu_avs_get(&avs, "regionid_colortable")) != NULL) {
	    rt_color_free();
	    db5_import_color_table((char *)val);
	}

	bu_avs_free(&avs);
    }

    return GED_OK;
}
コード例 #6
0
struct bu_ptbl *
db_lookup_by_attr(struct db_i *dbip, int dir_flags, struct bu_attribute_value_set *avs, int op)
{
    struct bu_attribute_value_set obj_avs;
    struct directory *dp;
    struct bu_ptbl *tbl;
    int match_count = 0;
    int attr_count;
    int i, j;
    int draw;

    RT_CK_DBI(dbip);

    if (avs) {
	BU_CK_AVS(avs);
	attr_count = avs->count;
    } else {
	attr_count = 0;
    }

    BU_ALLOC(tbl, struct bu_ptbl);
    bu_ptbl_init(tbl, 128, "wdb_get_by_attr ptbl_init");

    FOR_ALL_DIRECTORY_START(dp, dbip) {

	if ((dp->d_flags & dir_flags) == 0) continue;

	/* Skip phony entries */
	if (dp->d_addr == RT_DIR_PHONY_ADDR) continue;

	if (attr_count) {
	    bu_avs_init_empty(&obj_avs);
	    if (db5_get_attributes(dbip, &obj_avs, dp) < 0) {
		bu_log("ERROR: failed to get attributes for %s\n", dp->d_namep);
		return (struct bu_ptbl *)NULL;
	    }

	    draw = 0;
	    match_count = 0;
	    for (i = 0; (size_t)i < (size_t)avs->count; i++) {
		for (j = 0; (size_t)j < (size_t)obj_avs.count; j++) {
		    if (BU_STR_EQUAL(avs->avp[i].name, obj_avs.avp[j].name)) {
			if (BU_STR_EQUAL(avs->avp[i].value, obj_avs.avp[j].value)) {
			    if (op == 2) {
				draw = 1;
				break;
			    } else {
				match_count++;
			    }
			}
		    }
		}
		if (draw) break;
	    }

	    bu_avs_free(&obj_avs);
	} else {
	    draw = 1;
	}
	if (draw || match_count == attr_count) {
	    bu_ptbl_ins(tbl, (long *)dp);
	}
    } FOR_ALL_DIRECTORY_END;

    return tbl;
}
コード例 #7
0
ファイル: tree.c プロジェクト: cciechad/brlcad
/**
 * R T _ G E T T R E E S _ M U V E S
 *
 * User-called function to add a set of tree hierarchies to the active
 * set. Includes getting the indicated list of attributes and a
 * Tcl_HashTable for use with the ORCA man regions. (stashed in the
 * rt_i structure).
 *
 * This function may run in parallel, but is not multiply re-entrant
 * itself, because db_walk_tree() isn't multiply re-entrant.
 *
 * Semaphores used for critical sections in parallel mode:
 *	RT_SEM_TREE*	protects rti_solidheads[] lists, d_uses(solids)
 *	RT_SEM_RESULTS	protects HeadRegion, mdl_min/max, d_uses(reg), nregions
 *	RT_SEM_WORKER	(db_walk_dispatcher, from db_walk_tree)
 *	RT_SEM_STATS	nsolids
 *
 * INPUTS
 *	rtip	- RT instance pointer
 *	attrs	- array of pointers (NULL terminated) to strings (attribute names). A corresponding
 *		  array of "bu_mro" objects containing the attribute values will be attached to region
 *		  structures ("attr_values")
 *	argc	- number of trees to get
 *	argv	- array of char pointers to the names of the tree tops
 *	ncpus	- number of cpus to use
 *
 * Returns -
 *  	0	Ordinarily
 *	-1	On major error
 */
int
rt_gettrees_muves(struct rt_i *rtip, const char **attrs, int argc, const char **argv, int ncpus)
{
    register struct soltab	*stp;
    register struct region	*regp;
    Tcl_HashTable		*tbl;
    int			prev_sol_count;
    int			i;
    int			num_attrs=0;
    point_t			region_min, region_max;

    RT_CHECK_RTI(rtip);
    RT_CK_DBI(rtip->rti_dbip);

    if (!rtip->needprep)  {
	bu_log("ERROR: rt_gettree() called again after rt_prep!\n");
	return(-1);		/* FAIL */
    }

    if ( argc <= 0 )  return(-1);	/* FAIL */

    tbl = (Tcl_HashTable *)bu_malloc( sizeof( Tcl_HashTable ), "rtip->Orca_hash_tbl" );
    Tcl_InitHashTable( tbl, TCL_ONE_WORD_KEYS );
    rtip->Orca_hash_tbl = (genptr_t)tbl;

    prev_sol_count = rtip->nsolids;

    {
	struct db_tree_state	tree_state;

	tree_state = rt_initial_tree_state;	/* struct copy */
	tree_state.ts_dbip = rtip->rti_dbip;
	tree_state.ts_rtip = rtip;
	tree_state.ts_resp = NULL;	/* sanity.  Needs to be updated */

	if ( attrs ) {
	    if ( rtip->rti_dbip->dbi_version < 5 ) {
		bu_log( "WARNING: requesting attributes from an old database version (ignored)\n" );
		bu_avs_init_empty( &tree_state.ts_attrs );
	    } else {
		while ( attrs[num_attrs] ) {
		    num_attrs++;
		}
		if ( num_attrs ) {
		    bu_avs_init( &tree_state.ts_attrs,
				 num_attrs,
				 "avs in tree_state" );
		    num_attrs = 0;
		    while ( attrs[num_attrs] ) {
			bu_avs_add( &tree_state.ts_attrs,
				    attrs[num_attrs],
				    NULL );
			num_attrs++;
		    }
		} else {
		    bu_avs_init_empty( &tree_state.ts_attrs );
		}
	    }
	} else {
	    bu_avs_init_empty( &tree_state.ts_attrs );
	}

	/* ifdef this out for now, it is only using memory.  perhaps a
	 * better way of initiating ORCA stuff can be found.
	 */
#if 0
	bu_avs_add( &tree_state.ts_attrs, "ORCA_Comp", (char *)NULL );
#endif
	i = db_walk_tree( rtip->rti_dbip, argc, argv, ncpus,
			  &tree_state,
			  rt_gettree_region_start,
			  rt_gettree_region_end,
			  rt_gettree_leaf, (genptr_t)tbl );
	bu_avs_free( &tree_state.ts_attrs );
    }

    /* DEBUG:  Ensure that all region trees are valid */
    for ( BU_LIST_FOR( regp, region, &(rtip->HeadRegion) ) )  {
	RT_CK_REGION(regp);
	db_ck_tree(regp->reg_treetop);
    }

    /*
     * Eliminate any "dead" solids that parallel code couldn't change.
     * First remove any references from the region tree, then remove
     * actual soltab structs from the soltab list.
     */
    for ( BU_LIST_FOR( regp, region, &(rtip->HeadRegion) ) )  {
	RT_CK_REGION(regp);
	rt_tree_kill_dead_solid_refs( regp->reg_treetop );
	(void)rt_tree_elim_nops( regp->reg_treetop, &rt_uniresource );
    }
 again:
    RT_VISIT_ALL_SOLTABS_START( stp, rtip )  {
	RT_CK_SOLTAB(stp);
	if ( stp->st_aradius <= 0 )  {
	    bu_log("rt_gettrees() cleaning up dead solid '%s'\n",
		   stp->st_dp->d_namep );
	    rt_free_soltab(stp);
	    /* Can't do rtip->nsolids--, that doubles as max bit number! */
	    /* The macro makes it hard to regain place, punt */
	    goto again;
	}
    } RT_VISIT_ALL_SOLTABS_END