void db_alloc_directory_block(struct resource *resp) { struct directory *dp; size_t bytes; RT_CK_RESOURCE(resp); BU_CK_PTBL(&resp->re_directory_blocks); BU_ASSERT_PTR(resp->re_directory_hd, ==, NULL); /* Get a BIG block */ bytes = (size_t)bu_malloc_len_roundup(1024*sizeof(struct directory)); dp = (struct directory *)bu_calloc(1, bytes, "re_directory_blocks from db_alloc_directory_block() " BU_FLSTR); /* Record storage for later */ bu_ptbl_ins(&resp->re_directory_blocks, (long *)dp); while (bytes >= sizeof(struct directory)) { dp->d_magic = RT_DIR_MAGIC; dp->d_forw = resp->re_directory_hd; resp->re_directory_hd = dp; dp++; bytes -= sizeof(struct directory); } }
int bu_ptbl_ins_unique(struct bu_ptbl *b, long int *p) { register int k; register long **pp; BU_CK_PTBL(b); pp = b->buffer; /* search for existing */ for (k = b->end-1; k >= 0; k--) { if (pp[k] == p) { return k; } } if (UNLIKELY(bu_debug & BU_DEBUG_PTBL)) bu_log("bu_ptbl_ins_unique(%p, %p)\n", (void *)b, (void *)p); if (b->blen <= 0 || (size_t)b->end >= b->blen) { /* Table needs to grow */ bu_ptbl_ins(b, p); return -1; /* To signal that it was added */ } b->buffer[k=b->end++] = p; return -1; /* To signal that it was added */ }
/** * B U _ P T B L * * This version maintained for source compatibility with existing NMG code. */ int bu_ptbl(struct bu_ptbl *b, int func, long int *p) { if (func == BU_PTBL_INIT) { bu_ptbl_init(b, 64, "bu_ptbl() buffer[]"); return 0; } else if (func == BU_PTBL_RST) { bu_ptbl_reset(b); return 0; } else if (func == BU_PTBL_INS) { return bu_ptbl_ins(b, p); } else if (func == BU_PTBL_LOC) { return bu_ptbl_locate(b, p); } else if ( func == BU_PTBL_ZERO ) { bu_ptbl_zero(b, p); return( 0 ); } else if (func == BU_PTBL_INS_UNIQUE) { return bu_ptbl_ins_unique(b, p); } else if (func == BU_PTBL_RM) { return bu_ptbl_rm(b, p); } else if (func == BU_PTBL_CAT) { bu_ptbl_cat( b, (const struct bu_ptbl *)p ); return(0); } else if (func == BU_PTBL_FREE) { bu_ptbl_free(b); return (0); } else { BU_CK_PTBL(b); bu_log("bu_ptbl(%8x) Unknown table function %d\n", b, func); bu_bomb("bu_ptbl"); } return(-1);/* this is here to keep lint happy */ }
void rt_alloc_seg_block(register struct resource *res) { register struct seg *sp; size_t bytes; RT_CK_RESOURCE(res); if (!BU_LIST_IS_INITIALIZED(&res->re_seg)) { BU_LIST_INIT(&(res->re_seg)); bu_ptbl_init(&res->re_seg_blocks, 64, "re_seg_blocks ptbl"); } bytes = bu_malloc_len_roundup(64*sizeof(struct seg)); sp = (struct seg *)bu_malloc(bytes, "rt_alloc_seg_block()"); bu_ptbl_ins(&res->re_seg_blocks, (long *)sp); while (bytes >= sizeof(struct seg)) { sp->l.magic = RT_SEG_MAGIC; BU_LIST_INSERT(&(res->re_seg), &(sp->l)); res->re_seglen++; sp++; bytes -= sizeof(struct seg); } }
/** * B U _ P T B L _ I N S _ U N I Q U E * * Append item to table, if not already present. Unique insert. * * * @return index of first matchine element in array, if found. (table unchanged) * @return -1 if table extended to hold new element * * We do this a great deal, so make it go as fast as possible. * this is the biggest argument I can make for changing to an * ordered list. Someday.... */ int bu_ptbl_ins_unique(struct bu_ptbl *b, long int *p) { register int k; register long **pp = b->buffer; BU_CK_PTBL(b); /* search for existing */ for ( k = b->end-1; k >= 0; k-- ) if (pp[k] == p) return(k); if (bu_debug & BU_DEBUG_PTBL) bu_log("bu_ptbl_ins_unique(%8x, %8x)\n", b, p); if (b->blen <= 0 || b->end >= b->blen) { /* Table needs to grow */ bu_ptbl_ins( b, p ); return -1; /* To signal that it was added */ } b->buffer[k=b->end++] = p; return(-1); /* To signal that it was added */ }
HIDDEN int move_all_func(struct ged *gedp, int nflag, const char *old_name, const char *new_name) { int i; struct ged_display_list *gdlp; struct directory *dp; struct rt_db_internal intern; struct rt_comb_internal *comb; struct bu_ptbl stack; /* rename the record itself */ if ((dp = db_lookup(gedp->ged_wdbp->dbip, old_name, LOOKUP_NOISY)) == RT_DIR_NULL) return GED_ERROR; if (db_lookup(gedp->ged_wdbp->dbip, new_name, LOOKUP_QUIET) != RT_DIR_NULL) { bu_vls_printf(gedp->ged_result_str, "%s: already exists", new_name); return GED_ERROR; } /* if this was a sketch, we need to look for all the extrude * objects that might use it. * * This has to be done here, before we rename the (possible) sketch object * because the extrude will do a rt_db_get on the sketch when we call * rt_db_get_internal on it. */ if (dp->d_major_type == DB5_MAJORTYPE_BRLCAD && \ dp->d_minor_type == DB5_MINORTYPE_BRLCAD_SKETCH) { struct directory *dirp; for (i = 0; i < RT_DBNHASH; i++) { for (dirp = gedp->ged_wdbp->dbip->dbi_Head[i]; dirp != RT_DIR_NULL; dirp = dirp->d_forw) { if (dirp->d_major_type == DB5_MAJORTYPE_BRLCAD && \ dirp->d_minor_type == DB5_MINORTYPE_BRLCAD_EXTRUDE) { struct rt_extrude_internal *extrude; if (rt_db_get_internal(&intern, dirp, gedp->ged_wdbp->dbip, (fastf_t *)NULL, &rt_uniresource) < 0) { bu_log("Can't get extrude %s?\n", dirp->d_namep); continue; } extrude = (struct rt_extrude_internal *)intern.idb_ptr; RT_EXTRUDE_CK_MAGIC(extrude); if (BU_STR_EQUAL(extrude->sketch_name, old_name)) { if (nflag) { bu_vls_printf(gedp->ged_result_str, "%s ", dirp->d_namep); rt_db_free_internal(&intern); } else { bu_free(extrude->sketch_name, "sketch name"); extrude->sketch_name = bu_strdup(new_name); if (rt_db_put_internal(dirp, gedp->ged_wdbp->dbip, &intern, &rt_uniresource) < 0) { bu_log("oops\n"); } } } else rt_db_free_internal(&intern); } } } } if (!nflag) { /* Change object name in the directory. */ if (db_rename(gedp->ged_wdbp->dbip, dp, new_name) < 0) { bu_vls_printf(gedp->ged_result_str, "error in rename to %s, aborting", new_name); return GED_ERROR; } /* Change name in the file */ if (rt_db_get_internal(&intern, dp, gedp->ged_wdbp->dbip, (fastf_t *)NULL, &rt_uniresource) < 0) { bu_vls_printf(gedp->ged_result_str, "Database read error, aborting"); return GED_ERROR; } if (rt_db_put_internal(dp, gedp->ged_wdbp->dbip, &intern, &rt_uniresource) < 0) { bu_vls_printf(gedp->ged_result_str, "Database write error, aborting"); return GED_ERROR; } } bu_ptbl_init(&stack, 64, "combination stack for wdb_mvall_cmd"); /* Examine all COMB nodes */ for (i = 0; i < RT_DBNHASH; i++) { for (dp = gedp->ged_wdbp->dbip->dbi_Head[i]; dp != RT_DIR_NULL; dp = dp->d_forw) { if (nflag) { union tree *comb_leaf; int done=0; if (!(dp->d_flags & RT_DIR_COMB)) continue; if (rt_db_get_internal(&intern, dp, gedp->ged_wdbp->dbip, (fastf_t *)NULL, &rt_uniresource) < 0) continue; comb = (struct rt_comb_internal *)intern.idb_ptr; bu_ptbl_reset(&stack); /* visit each leaf in the combination */ comb_leaf = comb->tree; if (comb_leaf) { while (!done) { while (comb_leaf->tr_op != OP_DB_LEAF) { bu_ptbl_ins(&stack, (long *)comb_leaf); comb_leaf = comb_leaf->tr_b.tb_left; } if (BU_STR_EQUAL(comb_leaf->tr_l.tl_name, old_name)) { bu_vls_printf(gedp->ged_result_str, "%s ", dp->d_namep); } if (BU_PTBL_END(&stack) < 1) { done = 1; break; } comb_leaf = (union tree *)BU_PTBL_GET(&stack, BU_PTBL_END(&stack)-1); if (comb_leaf->tr_op != OP_DB_LEAF) { bu_ptbl_rm(&stack, (long *)comb_leaf); comb_leaf = comb_leaf->tr_b.tb_right; } } } rt_db_free_internal(&intern); } else { int comb_mvall_status = db_comb_mvall(dp, gedp->ged_wdbp->dbip, old_name, new_name, &stack); if (!comb_mvall_status) continue; if (comb_mvall_status == 2) { bu_ptbl_free(&stack); bu_vls_printf(gedp->ged_result_str, "Database write error, aborting"); return GED_ERROR; } } } } bu_ptbl_free(&stack); if (!nflag) { /* Change object name anywhere in the display list path. */ for (BU_LIST_FOR(gdlp, ged_display_list, gedp->ged_gdp->gd_headDisplay)) { int first = 1; int found = 0; struct bu_vls new_path = BU_VLS_INIT_ZERO; char *dupstr = strdup(bu_vls_addr(&gdlp->gdl_path)); char *tok = strtok(dupstr, "/"); while (tok) { if (BU_STR_EQUAL(tok, old_name)) { found = 1; if (first) { first = 0; bu_vls_printf(&new_path, "%s", new_name); } else bu_vls_printf(&new_path, "/%s", new_name); } else { if (first) { first = 0; bu_vls_printf(&new_path, "%s", tok); } else bu_vls_printf(&new_path, "/%s", tok); } tok = strtok((char *)NULL, "/"); } if (found) { bu_vls_free(&gdlp->gdl_path); bu_vls_printf(&gdlp->gdl_path, "%s", bu_vls_addr(&new_path)); } free((void *)dupstr); bu_vls_free(&new_path); } } return GED_OK; }
int main( int argc, char *argv[] ) { struct application *ap; int c; int verbose = 0; int i, j; int grid_size = 64; fastf_t cell_size; vect_t model_size; vect_t xdir, zdir; int job_count=0; char **result_map = NULL; struct bu_ptbl objs; int my_session_id; int do_plot=0; struct timeval startTime; struct timeval endTime; double diff; point_t mdl_min; point_t mdl_max; struct bu_vlb *vlb; /* Things like bu_malloc() must have these initialized for use with parallel processing */ bu_semaphore_init( RT_SEM_LAST ); /* initialize the list of BRL-CAD objects to be raytraced (this is used for the "-o" option) */ bu_ptbl_init( &objs, 64, "objects" ); /* process command line args */ while ( (c=bu_getopt( argc, argv, "vps:o:" ) ) != -1 ) { switch ( c ) { case 'p': /* do print plot */ do_plot = 1; break; case 's': /* set the grid size (default is 64x64) */ grid_size = atoi( bu_optarg ); break; case 'v': /* turn on verbose logging */ verbose = 1; rts_set_verbosity( 1 ); break; case 'o': /* add an object name to the list of BRL-CAD objects to raytrace */ bu_ptbl_ins( &objs, (long *)bu_optarg ); break; default: /* ERROR */ bu_exit(1, usage, argv[0]); } } if (bu_debug & BU_DEBUG_MEM_CHECK) { bu_prmem("initial memory map"); bu_mem_barriercheck(); } /* shoot a ray ten times, cleaning and loading geometry each time */ for(i=0 ; i<10 ; i++) { /* load geometry */ my_session_id = loadGeometry( argv[bu_optind], &objs ); if ( my_session_id < 0 ) { bu_exit(2, "Failed to load geometry from file (%s)\n", argv[bu_optind] ); } get_model_extents( my_session_id, mdl_min, mdl_max ); VSET( xdir, 1, 0, 0 ); VSET( zdir, 0, 0, 1 ); VSUB2( model_size, mdl_max, mdl_min ); ap = NULL; getApplication(&ap); VJOIN2( ap->a_ray.r_pt, mdl_min, model_size[Z]/2.0, zdir, model_size[X]/2.0, xdir ); VSET( ap->a_ray.r_dir, 0, 1, 0 ); rts_shootray(ap); vlb = (struct bu_vlb*)ap->a_uptr; printHits(vlb); freeApplication(ap); /*rts_clean( my_session_id );*/ bu_log( "\n\n********* %d\n", i); if (bu_debug & BU_DEBUG_MEM_CHECK) { bu_prmem("memory after shutdown"); } } my_session_id = loadGeometry( argv[bu_optind], &objs ); /* submit some jobs */ fprintf( stderr, "\nfiring a grid (%dx%d) of rays at", grid_size, grid_size ); for ( i=0; i<(int)BU_PTBL_LEN( &objs ); i++ ) { fprintf( stderr, " %s", (char *)BU_PTBL_GET( &objs, i ) ); } fprintf( stderr, "...\n" ); if( do_plot ) { result_map = (char **)bu_calloc( grid_size, sizeof( char *), "result_map" ); for ( i=0; i<grid_size; i++ ) { result_map[i] = (char *)bu_calloc( (grid_size+1), sizeof( char ), "result_map[i]" ); } } cell_size = model_size[X] / grid_size; gettimeofday( &startTime, NULL ); for ( i=0; i<grid_size; i++ ) { if( verbose ) { fprintf( stderr, "shooting row %d\n", i ); } for ( j=0; j<grid_size; j++ ) { int hitCount; getApplication(&ap); ap->a_user = my_session_id; VJOIN2( ap->a_ray.r_pt, mdl_min, i*cell_size, zdir, j*cell_size, xdir ); ap->a_ray.index = ap->a_user; VSET( ap->a_ray.r_dir, 0, 1, 0 ); rts_shootray(ap); if( do_plot ) { hitCount = countHits(ap->a_uptr); if ( hitCount == 0 ) { result_map[i][j] = ' '; } else if ( hitCount <= 9 ) { result_map[i][j] = '0' + hitCount; } else { result_map[i][j] = '*'; } } freeApplication(ap); job_count++; } } gettimeofday( &endTime, NULL ); diff = endTime.tv_sec - startTime.tv_sec + (endTime.tv_usec - startTime.tv_usec) / 1000000.0; fprintf( stderr, "time for %d individual rays: %g second\n", job_count, diff ); if(do_plot) { for ( i=grid_size-1; i>=0; i-- ) { fprintf( stderr, "%s\n", result_map[i] ); } } return 0; }
static int selection_command( struct ged *gedp, struct rt_db_internal *ip, int argc, const char *argv[]) { int i; struct rt_selection_set *selection_set; struct bu_ptbl *selections; struct rt_selection *new_selection; struct rt_selection_query query; const char *cmd, *solid_name, *selection_name; /* 0 1 2 3 * brep <solid_name> selection subcommand */ if (argc < 4) { return -1; } solid_name = argv[1]; cmd = argv[3]; if (BU_STR_EQUAL(cmd, "append")) { /* append to named selection - selection is created if it doesn't exist */ void (*free_selection)(struct rt_selection *); /* 4 5 6 7 8 9 10 * selection_name startx starty startz dirx diry dirz */ if (argc != 11) { bu_log("wrong args for selection append"); return -1; } selection_name = argv[4]; /* find matching selections */ query.start[X] = atof(argv[5]); query.start[Y] = atof(argv[6]); query.start[Z] = atof(argv[7]); query.dir[X] = atof(argv[8]); query.dir[Y] = atof(argv[9]); query.dir[Z] = atof(argv[10]); query.sorting = RT_SORT_CLOSEST_TO_START; selection_set = ip->idb_meth->ft_find_selections(ip, &query); if (!selection_set) { bu_log("no matching selections"); return -1; } /* could be multiple options, just grabbing the first and * freeing the rest */ selections = &selection_set->selections; new_selection = (struct rt_selection *)BU_PTBL_GET(selections, 0); free_selection = selection_set->free_selection; for (i = BU_PTBL_LEN(selections) - 1; i > 0; --i) { long *s = BU_PTBL_GET(selections, i); free_selection((struct rt_selection *)s); bu_ptbl_rm(selections, s); } bu_ptbl_free(selections); BU_FREE(selection_set, struct rt_selection_set); /* get existing/new selections set in gedp */ selection_set = ged_get_selection_set(gedp, solid_name, selection_name); selection_set->free_selection = free_selection; selections = &selection_set->selections; /* TODO: Need to implement append by passing new and * existing selection to an rt_brep_evaluate_selection. * For now, new selection simply replaces old one. */ for (i = BU_PTBL_LEN(selections) - 1; i >= 0; --i) { long *s = BU_PTBL_GET(selections, i); free_selection((struct rt_selection *)s); bu_ptbl_rm(selections, s); } bu_ptbl_ins(selections, (long *)new_selection); } else if (BU_STR_EQUAL(cmd, "translate")) { struct rt_selection_operation operation; /* 4 5 6 7 * selection_name dx dy dz */ if (argc != 8) { return -1; } selection_name = argv[4]; selection_set = ged_get_selection_set(gedp, solid_name, selection_name); selections = &selection_set->selections; if (BU_PTBL_LEN(selections) < 1) { return -1; } for (i = 0; i < (int)BU_PTBL_LEN(selections); ++i) { int ret; operation.type = RT_SELECTION_TRANSLATION; operation.parameters.tran.dx = atof(argv[5]); operation.parameters.tran.dy = atof(argv[6]); operation.parameters.tran.dz = atof(argv[7]); ret = ip->idb_meth->ft_process_selection(ip, gedp->ged_wdbp->dbip, (struct rt_selection *)BU_PTBL_GET(selections, i), &operation); if (ret != 0) { return ret; } } } return 0; }
int make_hole_in_prepped_regions(struct rt_wdb *wdbp, /* database to be modified */ struct rt_i *rtip, /* rt_i pointer for the same database */ point_t hole_start, /* center of start of hole */ vect_t hole_depth, /* depth and direction of hole */ fastf_t radius, /* radius of hole */ struct bu_ptbl *regions) /* list of region structures to which this hole * is to be applied */ { struct bu_vls tmp_name = BU_VLS_INIT_ZERO; size_t i, base_len, count=0; struct directory *dp; struct rt_db_internal intern; struct soltab *stp; RT_CHECK_WDB(wdbp); /* make a unique name for the RCC we will use (of the form "make_hole_%d") */ bu_vls_strcat(&tmp_name, "make_hole_"); base_len = bu_vls_strlen(&tmp_name); bu_vls_strcat(&tmp_name, "0"); while ((db_lookup(wdbp->dbip, bu_vls_addr(&tmp_name), LOOKUP_QUIET)) != RT_DIR_NULL) { count++; bu_vls_trunc(&tmp_name, base_len); bu_vls_printf(&tmp_name, "%zu", count); } /* build the RCC based on parameters passed in */ if (mk_rcc(wdbp, bu_vls_addr(&tmp_name), hole_start, hole_depth, radius)) { bu_log("Failed to create hole cylinder!!!\n"); bu_vls_free(&tmp_name); return 2; } /* lookup the newly created RCC */ dp=db_lookup(wdbp->dbip, bu_vls_addr(&tmp_name), LOOKUP_QUIET); if (dp == RT_DIR_NULL) { bu_log("Failed to lookup RCC (%s) just made by make_hole_in_prepped_regions()!!!\n", bu_vls_addr(&tmp_name)); bu_bomb("Failed to lookup RCC just made by make_hole_in_prepped_regions()!!!\n"); } /* get the internal form of the new RCC */ if (rt_db_get_internal(&intern, dp, wdbp->dbip, NULL, wdbp->wdb_resp) < 0) { bu_log("Failed to get internal form of RCC (%s) just made by make_hole_in_prepped_regions()!!!\n", bu_vls_addr(&tmp_name)); bu_bomb("Failed to get internal form of RCC just made by make_hole_in_prepped_regions()!!!\n"); } /* Build a soltab structure for the new RCC */ BU_ALLOC(stp, struct soltab); stp->l.magic = RT_SOLTAB_MAGIC; stp->l2.magic = RT_SOLTAB2_MAGIC; stp->st_uses = 1; stp->st_dp = dp; stp->st_bit = rtip->nsolids++; /* Add the new soltab structure to the rt_i structure */ rtip->rti_Solids = (struct soltab **)bu_realloc(rtip->rti_Solids, rtip->nsolids * sizeof(struct soltab *), "new rti_Solids"); rtip->rti_Solids[stp->st_bit] = stp; /* actually prep the new RCC */ if (intern.idb_meth->ft_prep(stp, &intern, rtip)) { bu_log("Failed to prep RCC (%s) just made by make_hole_in_prepped_regions()!!!\n", bu_vls_addr(&tmp_name)); bu_bomb("Failed to prep RCC just made by make_hole_in_prepped_regions()!!!\n"); } /* initialize the soltabs list of containing regions */ bu_ptbl_init(&stp->st_regions, BU_PTBL_LEN(regions), "stp->st_regions"); /* Subtract the new RCC from each region structure in the list provided */ for (i=0; i<BU_PTBL_LEN(regions); i++) { struct region *rp; union tree *treep; /* get the next region structure */ rp = (struct region *)BU_PTBL_GET(regions, i); RT_CK_REGION(rp); /* create a tree node for the subtraction operation, this will be the new tree root */ BU_ALLOC(treep, union tree); RT_TREE_INIT(treep); treep->tr_b.tb_op = OP_SUBTRACT; treep->tr_b.tb_left = rp->reg_treetop; /* subtract from the old treetop */ treep->tr_b.tb_regionp = rp; /* make the new node the new treetop */ rp->reg_treetop = treep; /* create a tree node for the new RCC */ BU_ALLOC(treep, union tree); RT_TREE_INIT(treep); treep->tr_a.tu_op = OP_SOLID; treep->tr_a.tu_stp = stp; treep->tr_a.tu_regionp = rp; /* the new RCC gets hung on the right of the subtract node */ rp->reg_treetop->tr_b.tb_right = treep; /* make sure the "all unions" flag is not set on this region */ rp->reg_all_unions = 0; /* Add this region to the list of containing regions for the new RCC */ bu_ptbl_ins(&stp->st_regions, (long *)rp); } /* insert the new RCC soltab structure into the already existing space partitioning tree */ insert_in_bsp(stp, &rtip->rti_CutHead); return 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; }
/** * R T _ G E T T R E E _ L E A F * * This routine must be prepared to run in parallel. */ HIDDEN union tree *rt_gettree_leaf(struct db_tree_state *tsp, struct db_full_path *pathp, struct rt_db_internal *ip, genptr_t client_data) /*const*/ /*const*/ { register struct soltab *stp; union tree *curtree; struct directory *dp; register matp_t mat; int i; struct rt_i *rtip; RT_CK_DBTS(tsp); RT_CK_DBI(tsp->ts_dbip); RT_CK_FULL_PATH(pathp); RT_CK_DB_INTERNAL(ip); rtip = tsp->ts_rtip; RT_CK_RTI(rtip); RT_CK_RESOURCE(tsp->ts_resp); dp = DB_FULL_PATH_CUR_DIR(pathp); /* Determine if this matrix is an identity matrix */ if ( !bn_mat_is_equal(tsp->ts_mat, bn_mat_identity, &rtip->rti_tol)) { /* Not identity matrix */ mat = (matp_t)tsp->ts_mat; } else { /* Identity matrix */ mat = (matp_t)0; } /* * Check to see if this exact solid has already been processed. * Match on leaf name and matrix. Note that there is a race here * between having st_id filled in a few lines below (which is * necessary for calling ft_prep), and ft_prep filling in * st_aradius. Fortunately, st_aradius starts out as zero, and * will never go down to -1 unless this soltab structure has * become a dead solid, so by testing against -1 (instead of <= 0, * like before, oops), it isn't a problem. */ stp = rt_find_identical_solid( mat, dp, rtip ); if ( stp->st_id != 0 ) { /* stp is an instance of a pre-existing solid */ if ( stp->st_aradius <= -1 ) { /* It's dead, Jim. st_uses was not incremented. */ return( TREE_NULL ); /* BAD: instance of dead solid */ } goto found_it; } if ( rtip->rti_add_to_new_solids_list ) { bu_ptbl_ins( &rtip->rti_new_solids, (long *)stp ); } stp->st_id = ip->idb_type; stp->st_meth = &rt_functab[ip->idb_type]; if ( mat ) { mat = stp->st_matp; } else { mat = (matp_t)bn_mat_identity; } RT_CK_DB_INTERNAL( ip ); /* init solid's maxima and minima */ VSETALL( stp->st_max, -INFINITY ); VSETALL( stp->st_min, INFINITY ); /* * If the ft_prep routine wants to keep the internal structure, * that is OK, as long as idb_ptr is set to null. Note that the * prep routine may have changed st_id. */ if ( stp->st_meth->ft_prep( stp, ip, rtip ) ) { int hash; /* Error, solid no good */ bu_log("rt_gettree_leaf(%s): prep failure\n", dp->d_namep ); /* Too late to delete soltab entry; mark it as "dead" */ hash = db_dirhash( dp->d_namep ); ACQUIRE_SEMAPHORE_TREE(hash); stp->st_aradius = -1; stp->st_uses--; RELEASE_SEMAPHORE_TREE(hash); return( TREE_NULL ); /* BAD */ } if ( rtip->rti_dont_instance ) { /* * If instanced solid refs are not being compressed, then * memory isn't an issue, and the application (such as * solids_on_ray) probably cares about the full path of this * solid, from root to leaf. So make it available here. * (stp->st_dp->d_uses could be the way to discriminate * references uniquely, if the path isn't enough. To locate * given dp and d_uses, search dp->d_use_hd list. Question * is, where to stash current val of d_uses?) */ db_full_path_init( &stp->st_path ); db_dup_full_path( &stp->st_path, pathp ); } else { /* * If there is more than just a direct reference to this leaf * from it's containing region, copy that below-region path * into st_path. Otherwise, leave st_path's magic number 0. * * XXX nothing depends on this behavior yet, and this whole * XXX 'else' clause might well be deleted. -Mike */ i = pathp->fp_len-1; if ( i > 0 && !(pathp->fp_names[i-1]->d_flags & DIR_REGION) ) { /* Search backwards for region. If no region, use whole path */ for ( --i; i > 0; i-- ) { if ( pathp->fp_names[i-1]->d_flags & DIR_REGION ) break; } if ( i < 0 ) i = 0; db_full_path_init( &stp->st_path ); db_dup_path_tail( &stp->st_path, pathp, i ); } } if (RT_G_DEBUG&DEBUG_TREEWALK && stp->st_path.magic == DB_FULL_PATH_MAGIC) { char *sofar = db_path_to_string(&stp->st_path); bu_log("rt_gettree_leaf() st_path=%s\n", sofar ); bu_free(sofar, "path string"); } if (RT_G_DEBUG&DEBUG_SOLIDS) { struct bu_vls str; bu_log("\n---Primitive %d: %s\n", stp->st_bit, dp->d_namep); bu_vls_init( &str ); /* verbose=1, mm2local=1.0 */ if ( stp->st_meth->ft_describe( &str, ip, 1, 1.0, tsp->ts_resp, tsp->ts_dbip ) < 0 ) { bu_log("rt_gettree_leaf(%s): solid describe failure\n", dp->d_namep ); } bu_log( "%s: %s", dp->d_namep, bu_vls_addr( &str ) ); bu_vls_free( &str ); } found_it: RT_GET_TREE( curtree, tsp->ts_resp ); curtree->magic = RT_TREE_MAGIC; curtree->tr_op = OP_SOLID; curtree->tr_a.tu_stp = stp; /* regionp will be filled in later by rt_tree_region_assign() */ curtree->tr_a.tu_regionp = (struct region *)0; if (RT_G_DEBUG&DEBUG_TREEWALK) { char *sofar = db_path_to_string(pathp); bu_log("rt_gettree_leaf() %s\n", sofar ); bu_free(sofar, "path string"); } return(curtree); }