/** * 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 */ }
extern "C" void rt_generate_mesh(int **faces, int *num_faces, point_t **points, int *num_pnts, struct db_i *dbip, const char *obj, fastf_t delta) { fastf_t d = delta; struct bu_ptbl *hit_pnts; if (!faces || !num_faces || !points || !num_pnts) return; if (!dbip || !obj) return; BU_GET(hit_pnts, struct bu_ptbl); bu_ptbl_init(hit_pnts, 64, "hit pnts"); if (NEAR_ZERO(d, SMALL_FASTF)) d = 1; if (_rt_generate_points(faces, num_faces, points, num_pnts, hit_pnts, dbip, obj, d)) { (*num_faces) = 0; (*num_pnts) = 0; return; } }
/** * B U _ P T B L _ I N S * * Append/Insert a (long *) item to/into the table. */ int bu_ptbl_ins(struct bu_ptbl *b, long int *p) { register int i; BU_CK_PTBL(b); if (bu_debug & BU_DEBUG_PTBL) bu_log("bu_ptbl_ins(%8x, %8x)\n", b, p); if (b->blen == 0) bu_ptbl_init(b, 64, "bu_ptbl_ins() buffer"); if (b->end >= b->blen) { b->buffer = (long **)bu_realloc( (char *)b->buffer, sizeof(p)*(b->blen *= 4), "bu_ptbl.buffer[] (ins)" ); } i=b->end++; b->buffer[i] = p; return(i); }
int bu_ptbl_ins(struct bu_ptbl *b, long int *p) { register int i; BU_CK_PTBL(b); if (UNLIKELY(bu_debug & BU_DEBUG_PTBL)) bu_log("bu_ptbl_ins(%p, %p)\n", (void *)b, (void *)p); if (b->blen == 0) bu_ptbl_init(b, 64, "bu_ptbl_ins() buffer"); if ((size_t)b->end >= b->blen) { b->buffer = (long **)bu_realloc((char *)b->buffer, sizeof(long *)*(b->blen *= 4), "bu_ptbl.buffer[] (ins)"); } i = b->end++; b->buffer[i] = p; return i; }
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); } }
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; }
/** * Given a ray, shoot it at all the relevant parts of the model, * (building the HeadSeg chain), and then call rt_boolregions() to * build and evaluate the partition chain. If the ray actually hit * anything, call the application's a_hit() routine with a pointer to * the partition chain, otherwise, call the application's a_miss() * routine. * * It is important to note that rays extend infinitely only in the * positive direction. The ray is composed of all points P, where * * P = r_pt + K * r_dir * * for K ranging from 0 to +infinity. There is no looking backwards. * * It is also important to note that the direction vector r_dir must * have unit length; this is mandatory, and is not ordinarily checked, * in the name of efficiency. * * Input: Pointer to an application structure, with these mandatory fields: * a_ray.r_pt Starting point of ray to be fired * a_ray.r_dir UNIT VECTOR with direction to fire in (dir cosines) * a_hit Routine to call when something is hit * a_miss Routine to call when ray misses everything * * Calls user's a_miss() or a_hit() routine as appropriate. Passes * a_hit() routine list of partitions, with only hit_dist fields * valid. Normal computation deferred to user code, to avoid needless * computation here. * * Returns: whatever the application function returns (an int). * * NOTE: The application functions may call rt_shootray() recursively. * Thus, none of the local variables may be static. * * An open issue for execution in a PARALLEL environment is locking of * the statistics variables. */ int rt_vshootray(struct application *ap) { struct seg *HeadSeg; int ret; vect_t inv_dir; /* inverses of ap->a_ray.r_dir */ struct bu_bitv *solidbits; /* bits for all solids shot so far */ struct bu_ptbl *regionbits; /* bits for all involved regions */ char *status; struct partition InitialPart; /* Head of Initial Partitions */ struct partition FinalPart; /* Head of Final Partitions */ int nrays = 1; /* for now */ int vlen; int id; int i; struct soltab **ary_stp; /* array of pointers */ struct xray **ary_rp; /* array of pointers */ struct seg *ary_seg; /* array of structures */ struct rt_i *rtip; int done; #define BACKING_DIST (-2.0) /* mm to look behind start point */ rtip = ap->a_rt_i; RT_AP_CHECK(ap); if (!ap->a_resource) { ap->a_resource = &rt_uniresource; } RT_CK_RESOURCE(ap->a_resource); if (RT_G_DEBUG&(DEBUG_ALLRAYS|DEBUG_SHOOT|DEBUG_PARTITION)) { bu_log("\n**********mshootray cpu=%d %d, %d lvl=%d (%s)\n", ap->a_resource->re_cpu, ap->a_x, ap->a_y, ap->a_level, ap->a_purpose != (char *)0 ? ap->a_purpose : "?"); VPRINT("Pnt", ap->a_ray.r_pt); VPRINT("Dir", ap->a_ray.r_dir); } rtip->rti_nrays++; if (rtip->needprep) rt_prep(rtip); /* Allocate dynamic memory */ vlen = nrays * rtip->rti_maxsol_by_type; ary_stp = (struct soltab **)bu_calloc(vlen, sizeof(struct soltab *), "*ary_stp[]"); ary_rp = (struct xray **)bu_calloc(vlen, sizeof(struct xray *), "*ary_rp[]"); ary_seg = (struct seg *)bu_calloc(vlen, sizeof(struct seg), "ary_seg[]"); /**** for each ray, do this ****/ InitialPart.pt_forw = InitialPart.pt_back = &InitialPart; FinalPart.pt_forw = FinalPart.pt_back = &FinalPart; HeadSeg = RT_SEG_NULL; solidbits = rt_get_solidbitv(rtip->nsolids, ap->a_resource); if (BU_LIST_IS_EMPTY(&ap->a_resource->re_region_ptbl)) { BU_ALLOC(regionbits, struct bu_ptbl); bu_ptbl_init(regionbits, 7, "rt_shootray() regionbits ptbl"); } else { regionbits = BU_LIST_FIRST(bu_ptbl, &ap->a_resource->re_region_ptbl); BU_LIST_DEQUEUE(®ionbits->l); BU_CK_PTBL(regionbits); } /* Compute the inverse of the direction cosines */ if (!ZERO(ap->a_ray.r_dir[X])) { inv_dir[X]=1.0/ap->a_ray.r_dir[X]; } else { inv_dir[X] = INFINITY; ap->a_ray.r_dir[X] = 0.0; } if (!ZERO(ap->a_ray.r_dir[Y])) { inv_dir[Y]=1.0/ap->a_ray.r_dir[Y]; } else { inv_dir[Y] = INFINITY; ap->a_ray.r_dir[Y] = 0.0; } if (!ZERO(ap->a_ray.r_dir[Z])) { inv_dir[Z]=1.0/ap->a_ray.r_dir[Z]; } else { inv_dir[Z] = INFINITY; ap->a_ray.r_dir[Z] = 0.0; } /* * XXX handle infinite solids here, later. */ /* * If ray does not enter the model RPP, skip on. * If ray ends exactly at the model RPP, trace it. */ if (!rt_in_rpp(&ap->a_ray, inv_dir, rtip->mdl_min, rtip->mdl_max) || ap->a_ray.r_max < 0.0) { rtip->nmiss_model++; if (ap->a_miss) ret = ap->a_miss(ap); else ret = 0; status = "MISS model"; goto out; } /* For each type of solid to be shot at, assemble the vectors */ for (id = 1; id <= ID_MAX_SOLID; id++) { register int nsol; if ((nsol = rtip->rti_nsol_by_type[id]) <= 0) continue; /* For each instance of this solid type */ for (i = nsol-1; i >= 0; i--) { ary_stp[i] = rtip->rti_sol_by_type[id][i]; ary_rp[i] = &(ap->a_ray); /* XXX, sb [ray] */ ary_seg[i].seg_stp = SOLTAB_NULL; BU_LIST_INIT(&ary_seg[i].l); } /* bounding box check */ /* bit vector per ray check */ /* mark elements to be skipped with ary_stp[] = SOLTAB_NULL */ ap->a_rt_i->nshots += nsol; /* later: skipped ones */ if (OBJ[id].ft_vshot) { OBJ[id].ft_vshot(ary_stp, ary_rp, ary_seg, nsol, ap); } else { vshot_stub(ary_stp, ary_rp, ary_seg, nsol, ap); } /* set bits for all solids shot at for each ray */ /* append resulting seg list to input for boolweave */ for (i = nsol-1; i >= 0; i--) { register struct seg *seg2; if (ary_seg[i].seg_stp == SOLTAB_NULL) { /* MISS */ ap->a_rt_i->nmiss++; continue; } ap->a_rt_i->nhits++; /* For now, do it the slow way. sb [ray] */ /* MUST dup it -- all segs have to live till after a_hit() */ RT_GET_SEG(seg2, ap->a_resource); *seg2 = ary_seg[i]; /* struct copy */ /* rt_boolweave(seg2, &InitialPart, ap); */ bu_bomb("FIXME: need to call boolweave here"); /* Add seg chain to list of used segs awaiting reclaim */ #if 0 /* FIXME: need to use waiting_segs/finished_segs here in * conjunction with rt_boolweave() { register struct seg *seg3 = seg2; while (seg3->seg_next != RT_SEG_NULL) seg3 = seg3->seg_next; seg3->seg_next = HeadSeg; HeadSeg = seg2; } */ #endif } } /* * Ray has finally left known space. */ if (InitialPart.pt_forw == &InitialPart) { if (ap->a_miss) ret = ap->a_miss(ap); else ret = 0; status = "MISSed all primitives"; goto freeup; } /* * All intersections of the ray with the model have been computed. * Evaluate the boolean trees over each partition. */ done = rt_boolfinal(&InitialPart, &FinalPart, BACKING_DIST, INFINITY, regionbits, ap, solidbits); if (done > 0) goto hitit; if (FinalPart.pt_forw == &FinalPart) { if (ap->a_miss) ret = ap->a_miss(ap); else ret = 0; status = "MISS bool"; goto freeup; } /* * Ray/model intersections exist. Pass the list to the user's * a_hit() routine. Note that only the hit_dist elements of * pt_inhit and pt_outhit have been computed yet. To compute both * hit_point and hit_normal, use the * * RT_HIT_NORMAL(NULL, hitp, stp, rayp, 0); * * macro. To compute just hit_point, use * * VJOIN1(hitp->hit_point, rp->r_pt, hitp->hit_dist, rp->r_dir); */ hitit: if (RT_G_DEBUG&DEBUG_SHOOT) rt_pr_partitions(rtip, &FinalPart, "a_hit()"); if (ap->a_hit) ret = ap->a_hit(ap, &FinalPart, HeadSeg/* &finished_segs */); else ret = 0; status = "HIT"; /* * Processing of this ray is complete. Free dynamic resources. */ freeup: { register struct partition *pp; /* Free up initial partition list */ for (pp = InitialPart.pt_forw; pp != &InitialPart;) { register struct partition *newpp; newpp = pp; pp = pp->pt_forw; FREE_PT(newpp, ap->a_resource); } /* Free up final partition list */ for (pp = FinalPart.pt_forw; pp != &FinalPart;) { register struct partition *newpp; newpp = pp; pp = pp->pt_forw; FREE_PT(newpp, ap->a_resource); } } /* Segs can't be freed until after a_hit() has returned */ #if 0 /* FIXME: depends on commented out code above */ if (HeadSeg) RT_FREE_SEG_LIST(HeadSeg, ap->a_resource); #endif out: bu_free((char *)ary_stp, "*ary_stp[]"); bu_free((char *)ary_rp, "*ary_rp[]"); bu_free((char *)ary_seg, "ary_seg[]"); if (solidbits != NULL) { bu_bitv_free(solidbits); } if (RT_G_DEBUG&(DEBUG_ALLRAYS|DEBUG_SHOOT|DEBUG_PARTITION)) { bu_log("----------mshootray cpu=%d %d, %d lvl=%d (%s) %s ret=%d\n", ap->a_resource->re_cpu, ap->a_x, ap->a_y, ap->a_level, ap->a_purpose != (char *)0 ? ap->a_purpose : "?", status, ret); } return ret; }
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; }
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 db_i * db_open(const char *name, const char *mode) { register struct db_i *dbip = DBI_NULL; register int i; char **argv; if (name == NULL) return DBI_NULL; if (RT_G_DEBUG & DEBUG_DB) { bu_log("db_open(%s, %s)\n", name, mode); } if (mode && mode[0] == 'r' && mode[1] == '\0') { /* Read-only mode */ struct bu_mapped_file *mfp; mfp = bu_open_mapped_file(name, "db_i"); if (mfp == NULL) { if (RT_G_DEBUG & DEBUG_DB) { bu_log("db_open(%s) FAILED, unable to open as a mapped file\n", name); } return DBI_NULL; } /* Is this a re-use of a previously mapped file? */ if (mfp->apbuf) { dbip = (struct db_i *)mfp->apbuf; RT_CK_DBI(dbip); dbip->dbi_uses++; /* * decrement the mapped file reference counter by 1, * references are already counted in dbip->dbi_uses */ bu_close_mapped_file(mfp); if (RT_G_DEBUG & DEBUG_DB) { bu_log("db_open(%s) dbip=%p: reused previously mapped file\n", name, (void *)dbip); } return dbip; } BU_ALLOC(dbip, struct db_i); dbip->dbi_mf = mfp; dbip->dbi_eof = (off_t)mfp->buflen; dbip->dbi_inmem = mfp->buf; dbip->dbi_mf->apbuf = (void *)dbip; /* Do this too, so we can seek around on the file */ if ((dbip->dbi_fp = fopen(name, "rb")) == NULL) { if (RT_G_DEBUG & DEBUG_DB) { bu_log("db_open(%s) FAILED, unable to open file for reading\n", name); } bu_free((char *)dbip, "struct db_i"); return DBI_NULL; } dbip->dbi_read_only = 1; } else { /* Read-write mode */ BU_ALLOC(dbip, struct db_i); dbip->dbi_eof = (off_t)-1L; if ((dbip->dbi_fp = fopen(name, "r+b")) == NULL) { if (RT_G_DEBUG & DEBUG_DB) { bu_log("db_open(%s) FAILED, unable to open file for reading/writing\n", name); } bu_free((char *)dbip, "struct db_i"); return DBI_NULL; } dbip->dbi_read_only = 0; } /* Initialize fields */ for (i = 0; i < RT_DBNHASH; i++) dbip->dbi_Head[i] = RT_DIR_NULL; dbip->dbi_local2base = 1.0; /* mm */ dbip->dbi_base2local = 1.0; dbip->dbi_title = (char *)0; dbip->dbi_uses = 1; /* FIXME: At some point, expand argv search paths with * getenv("BRLCAD_FILE_PATH") paths */ /* intentionally acquiring dynamic memory here since we set * dbip->dbi_filepath to argv. arg values and array memory are * released during db_close. */ argv = (char **)bu_malloc(3 * sizeof(char *), "dbi_filepath[3]"); argv[0] = bu_strdup("."); argv[1] = bu_dirname(name); argv[2] = NULL; dbip->dbi_filepath = argv; #if !defined(_WIN32) || defined(__CYGWIN__) /* If not a full path */ if (argv[1][0] != '/') { struct bu_vls fullpath = BU_VLS_INIT_ZERO; bu_free((void *)argv[1], "db_open: argv[1]"); argv[1] = getcwd((char *)NULL, (size_t)MAXPATHLEN); /* Something went wrong and we didn't get the CWD. So, * free up any memory allocated here and return DBI_NULL */ if (argv[1] == NULL) { if (dbip->dbi_mf) { bu_close_mapped_file(dbip->dbi_mf); bu_free_mapped_files(0); dbip->dbi_mf = (struct bu_mapped_file *)NULL; } if (dbip->dbi_fp) { fclose(dbip->dbi_fp); } bu_free((void *)argv[0], "db_open: argv[0]"); bu_free((void *)argv, "db_open: argv"); bu_free((char *)dbip, "struct db_i"); return DBI_NULL; } bu_vls_printf(&fullpath, "%s/%s", argv[1], name); dbip->dbi_filename = bu_strdup(bu_vls_addr(&fullpath)); bu_vls_free(&fullpath); } else { /* Record the filename and file path */ dbip->dbi_filename = bu_strdup(name); } #else /* Record the filename and file path */ dbip->dbi_filename = bu_strdup(name); #endif bu_ptbl_init(&dbip->dbi_clients, 128, "dbi_clients[]"); dbip->dbi_magic = DBI_MAGIC; /* Now it's valid */ /* determine version */ dbip->dbi_version = 0; /* make db_version() calculate */ dbip->dbi_version = db_version(dbip); if (dbip->dbi_version < 5) { if (rt_db_flip_endian(dbip)) { if (dbip->dbi_version > 0) dbip->dbi_version *= -1; dbip->dbi_read_only = 1; bu_log("WARNING: Binary-incompatible v4 geometry database detected.\n"); bu_log(" Endianness flipped. Converting to READ ONLY.\n"); } } if (RT_G_DEBUG & DEBUG_DB) { bu_log("db_open(%s) dbip=%p version=%d\n", dbip->dbi_filename, (void *)dbip, dbip->dbi_version); } return dbip; }
static size_t show_dangling_edges(struct ged *gedp, const uint32_t *magic_p, const char *name, int out_type) { FILE *plotfp = NULL; const char *manifolds = NULL; const struct edgeuse *eur; int done; point_t pt1, pt2; size_t i, cnt; struct bn_vlblock *vbp = NULL; struct bu_list *vhead = NULL; struct bu_ptbl faces; struct bu_vls plot_file_name = BU_VLS_INIT_ZERO; struct edgeuse *eu = NULL; struct face *fp = NULL; struct faceuse *fu, *fu1, *fu2; struct faceuse *newfu = NULL; struct loopuse *lu = NULL; /* out_type: 0 = none, 1 = show, 2 = plot */ if (out_type < 0 || out_type > 2) { bu_log("Internal error, open edge test failed.\n"); return 0; } if (out_type == 1) { vbp = rt_vlblock_init(); vhead = rt_vlblock_find(vbp, 0xFF, 0xFF, 0x00); } bu_ptbl_init(&faces, 64, "faces buffer"); nmg_face_tabulate(&faces, magic_p); cnt = 0; for (i = 0; i < (size_t)BU_PTBL_END(&faces) ; i++) { fp = (struct face *)BU_PTBL_GET(&faces, i); NMG_CK_FACE(fp); fu = fu1 = fp->fu_p; NMG_CK_FACEUSE(fu1); fu2 = fp->fu_p->fumate_p; NMG_CK_FACEUSE(fu2); done = 0; while (!done) { NMG_CK_FACEUSE(fu); for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd)) { NMG_CK_LOOPUSE(lu); if (BU_LIST_FIRST_MAGIC(&lu->down_hd) == NMG_EDGEUSE_MAGIC) { for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) { NMG_CK_EDGEUSE(eu); eur = nmg_radial_face_edge_in_shell(eu); newfu = eur->up.lu_p->up.fu_p; while (manifolds && NMG_MANIFOLDS(manifolds, newfu) & NMG_2MANIFOLD && eur != eu->eumate_p) { eur = nmg_radial_face_edge_in_shell(eur->eumate_p); newfu = eur->up.lu_p->up.fu_p; } if (eur == eu->eumate_p) { VMOVE(pt1, eu->vu_p->v_p->vg_p->coord); VMOVE(pt2, eu->eumate_p->vu_p->v_p->vg_p->coord); if (out_type == 1) { BN_ADD_VLIST(vbp->free_vlist_hd, vhead, pt1, BN_VLIST_LINE_MOVE); BN_ADD_VLIST(vbp->free_vlist_hd, vhead, pt2, BN_VLIST_LINE_DRAW); } else if (out_type == 2) { if (!plotfp) { bu_vls_sprintf(&plot_file_name, "%s.%p.pl", name, (void *)magic_p); if ((plotfp = fopen(bu_vls_addr(&plot_file_name), "wb")) == (FILE *)NULL) { bu_vls_free(&plot_file_name); bu_log("Error, unable to create plot file (%s), open edge test failed.\n", bu_vls_addr(&plot_file_name)); return 0; } } pdv_3line(plotfp, pt1, pt2); } cnt++; } } } } if (fu == fu1) fu = fu2; if (fu == fu2) done = 1; }; } if (out_type == 1) { /* Add overlay */ _ged_cvt_vlblock_to_solids(gedp, vbp, (char *)name, 0); rt_vlblock_free(vbp); bu_log("Showing open edges...\n"); } else if (out_type == 2) { if (plotfp) { (void)fclose(plotfp); bu_log("Wrote plot file (%s)\n", bu_vls_addr(&plot_file_name)); bu_vls_free(&plot_file_name); } } bu_ptbl_free(&faces); return cnt; }
/* 0 = no difference within tolerance, 1 = difference >= tolerance */ int analyze_raydiff(/* TODO - decide what to return. Probably some sort of left, common, right segment sets. See what rtcheck does... */ struct db_i *dbip, const char *obj1, const char *obj2, struct bn_tol *tol) { int ret; int count = 0; struct rt_i *rtip; int ncpus = bu_avail_cpus(); point_t min, mid, max; struct rt_pattern_data *xdata, *ydata, *zdata; fastf_t *rays; struct raydiff_container *state; if (!dbip || !obj1 || !obj2 || !tol) return 0; rtip = rt_new_rti(dbip); if (rt_gettree(rtip, obj1) < 0) return -1; if (rt_gettree(rtip, obj2) < 0) return -1; rt_prep_parallel(rtip, 1); /* Now we've got the bounding box - set up the grids */ VMOVE(min, rtip->mdl_min); VMOVE(max, rtip->mdl_max); VSET(mid, (max[0] - min[0])/2, (max[1] - min[1])/2, (max[2] - min[2])/2); BU_GET(xdata, struct rt_pattern_data); VSET(xdata->center_pt, min[0] - 0.1 * min[0], mid[1], mid[2]); VSET(xdata->center_dir, 1, 0, 0); xdata->vn = 2; xdata->pn = 2; xdata->n_vec = (vect_t *)bu_calloc(xdata->vn + 1, sizeof(vect_t), "vects array"); xdata->n_p = (fastf_t *)bu_calloc(xdata->pn + 1, sizeof(fastf_t), "params array"); xdata->n_p[0] = 50; /* TODO - get tolerances from caller */ xdata->n_p[1] = 50; VSET(xdata->n_vec[0], 0, max[1], 0); VSET(xdata->n_vec[1], 0, 0, max[2]); ret = rt_pattern(xdata, RT_PATTERN_RECT_ORTHOGRID); bu_free(xdata->n_vec, "x vec inputs"); bu_free(xdata->n_p, "x p inputs"); if (ret < 0) return -1; BU_GET(ydata, struct rt_pattern_data); VSET(ydata->center_pt, mid[0], min[1] - 0.1 * min[1], mid[2]); VSET(ydata->center_dir, 0, 1, 0); ydata->vn = 2; ydata->pn = 2; ydata->n_vec = (vect_t *)bu_calloc(ydata->vn + 1, sizeof(vect_t), "vects array"); ydata->n_p = (fastf_t *)bu_calloc(ydata->pn + 1, sizeof(fastf_t), "params array"); ydata->n_p[0] = 50; /* TODO - get tolerances from caller */ ydata->n_p[1] = 50; VSET(ydata->n_vec[0], max[0], 0, 0); VSET(ydata->n_vec[1], 0, 0, max[2]); ret = rt_pattern(ydata, RT_PATTERN_RECT_ORTHOGRID); bu_free(ydata->n_vec, "y vec inputs"); bu_free(ydata->n_p, "y p inputs"); if (ret < 0) return -1; BU_GET(zdata, struct rt_pattern_data); VSET(zdata->center_pt, mid[0], mid[1], min[2] - 0.1 * min[2]); VSET(zdata->center_dir, 0, 0, 1); zdata->vn = 2; zdata->pn = 2; zdata->n_vec = (vect_t *)bu_calloc(zdata->vn + 1, sizeof(vect_t), "vects array"); zdata->n_p = (fastf_t *)bu_calloc(zdata->pn + 1, sizeof(fastf_t), "params array"); zdata->n_p[0] = 50; /* TODO - get tolerances from caller */ zdata->n_p[1] = 50; VSET(zdata->n_vec[0], max[0], 0, 0); VSET(zdata->n_vec[1], 0, max[1], 0); ret = rt_pattern(zdata, RT_PATTERN_RECT_ORTHOGRID); bu_free(zdata->n_vec, "x vec inputs"); bu_free(zdata->n_p, "x p inputs"); if (ret < 0) return -1; /* Consolidate the grids into a single ray array */ { size_t i, j; rays = (fastf_t *)bu_calloc((xdata->ray_cnt + ydata->ray_cnt + zdata->ray_cnt + 1) * 6, sizeof(fastf_t), "rays"); count = 0; for (i = 0; i < xdata->ray_cnt; i++) { for (j = 0; j < 6; j++) { rays[6*count+j] = xdata->rays[6*i + j]; } count++; } for (i = 0; i < ydata->ray_cnt; i++) { for (j = 0; j < 6; j++) { rays[6*count+j] = ydata->rays[6*i + j]; } count++; } for (i = 0; i < zdata->ray_cnt; i++) { for (j = 0; j < 6; j++) { rays[6*count+j] = zdata->rays[6*i+j]; } count++; } } bu_free(xdata->rays, "x rays"); bu_free(ydata->rays, "y rays"); bu_free(zdata->rays, "z rays"); BU_PUT(xdata, struct rt_pattern_data); BU_PUT(ydata, struct rt_pattern_data); BU_PUT(zdata, struct rt_pattern_data); bu_log("ray cnt: %d\n", count); { int i, j; ncpus = 2; state = (struct raydiff_container *)bu_calloc(ncpus+1, sizeof(struct raydiff_container), "resources"); for (i = 0; i < ncpus+1; i++) { state[i].rtip = rtip; state[i].tol = 0.5; state[i].ncpus = ncpus; state[i].left_name = bu_strdup(obj1); state[i].right_name = bu_strdup(obj2); BU_GET(state[i].resp, struct resource); rt_init_resource(state[i].resp, i, state->rtip); BU_GET(state[i].left, struct bu_ptbl); bu_ptbl_init(state[i].left, 64, "left solid hits"); BU_GET(state[i].both, struct bu_ptbl); bu_ptbl_init(state[i].both, 64, "hits on both solids"); BU_GET(state[i].right, struct bu_ptbl); bu_ptbl_init(state[i].right, 64, "right solid hits"); state[i].rays_cnt = count; state[i].rays = rays; } bu_parallel(raydiff_gen_worker, ncpus, (void *)state); /* Collect and print all of the results */ for (i = 0; i < ncpus+1; i++) { for (j = 0; j < (int)BU_PTBL_LEN(state[i].left); j++) { struct diff_seg *dseg = (struct diff_seg *)BU_PTBL_GET(state[i].left, j); bu_log("Result: LEFT diff vol (%s): %g %g %g -> %g %g %g\n", obj1, V3ARGS(dseg->in_pt), V3ARGS(dseg->out_pt)); } for (j = 0; j < (int)BU_PTBL_LEN(state[i].both); j++) { struct diff_seg *dseg = (struct diff_seg *)BU_PTBL_GET(state[i].both, j); bu_log("Result: BOTH): %g %g %g -> %g %g %g\n", V3ARGS(dseg->in_pt), V3ARGS(dseg->out_pt)); } for (j = 0; j < (int)BU_PTBL_LEN(state[i].right); j++) { struct diff_seg *dseg = (struct diff_seg *)BU_PTBL_GET(state[i].right, j); bu_log("Result: RIGHT diff vol (%s): %g %g %g -> %g %g %g\n", obj2, V3ARGS(dseg->in_pt), V3ARGS(dseg->out_pt)); } } /* Free results */ for (i = 0; i < ncpus+1; i++) { for (j = 0; j < (int)BU_PTBL_LEN(state[i].left); j++) { struct diff_seg *dseg = (struct diff_seg *)BU_PTBL_GET(state[i].left, j); BU_PUT(dseg, struct diff_seg); } bu_ptbl_free(state[i].left); BU_PUT(state[i].left, struct diff_seg); for (j = 0; j < (int)BU_PTBL_LEN(state[i].both); j++) { struct diff_seg *dseg = (struct diff_seg *)BU_PTBL_GET(state[i].both, j); BU_PUT(dseg, struct diff_seg); } bu_ptbl_free(state[i].both); BU_PUT(state[i].both, struct diff_seg); for (j = 0; j < (int)BU_PTBL_LEN(state[i].right); j++) { struct diff_seg *dseg = (struct diff_seg *)BU_PTBL_GET(state[i].right, j); BU_PUT(dseg, struct diff_seg); } bu_ptbl_free(state[i].right); BU_PUT(state[i].right, struct diff_seg); bu_free((void *)state[i].left_name, "left name"); bu_free((void *)state[i].right_name, "right name"); BU_PUT(state[i].resp, struct resource); } bu_free(state, "free state containers"); } 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 _ F I N D _ I D E N T I C A L _ S O L I D * * See if solid "dp" as transformed by "mat" already exists in the * soltab list. If it does, return the matching stp, otherwise, * create a new soltab structure, enrole it in the list, and return a * pointer to that. * * "mat" will be a null pointer when an identity matrix is signified. * This greatly speeds the comparison process. * * The two cases can be distinguished by the fact that stp->st_id will * be 0 for a new soltab structure, and non-zero for an existing one. * * This routine will run in parallel. * * In order to avoid a race between searching the soltab list and * adding new solids to it, the new solid to be added *must* be * enrolled in the list before exiting the critical section. * * To limit the size of the list to be searched, there are many lists. * The selection of which list is determined by the hash value * computed from the solid's name. This is the same optimization used * in searching the directory lists. * * This subroutine is the critical bottleneck in parallel tree walking. * * It is safe, and much faster, to use several different critical * sections when searching different lists. * * There are only 4 dedicated semaphores defined, TREE0 through TREE3. * This unfortunately limits the code to having only 4 CPUs doing list * searching at any one time. Hopefully, this is enough parallelism * to keep the rest of the CPUs doing I/O and actual solid prepping. * * Since the algorithm has been reduced from an O((nsolid/128)**2) * search on the entire rti_solidheads[hash] list to an O(ninstance) * search on the dp->d_use_head list for this one solid, the critical * section should be relatively short-lived. Having the 3-way split * should provide ample opportunity for parallelism through here, * while still ensuring that the necessary variables are protected. * * There are two critical variables which *both* need to be protected: * the specific rti_solidhead[hash] list head, and the specific * dp->d_use_hd list head. Fortunately, since the selection of * critical section is based upon db_dirhash(dp->d_namep), any other * processor that wants to search this same 'dp' will get the same * hash as the current thread, and will thus wait for the appropriate * semaphore to be released. Similarly, any other thread that wants * to search the same rti_solidhead[hash] list as the current thread * will be using the same hash, and will thus wait for the proper * semaphore. */ HIDDEN struct soltab *rt_find_identical_solid(register const matp_t mat, register struct directory *dp, struct rt_i *rtip) { register struct soltab *stp = RT_SOLTAB_NULL; int hash; RT_CK_DIR(dp); RT_CK_RTI(rtip); hash = db_dirhash( dp->d_namep ); /* Enter the appropriate dual critical-section */ ACQUIRE_SEMAPHORE_TREE(hash); /* * If solid has not been referenced yet, the search can be * skipped. If solid is being referenced a _lot_, it certainly * isn't all going to be in the same place, so don't bother * searching. Consider the case of a million instances of the * same tree submodel solid. */ if ( dp->d_uses > 0 && dp->d_uses < 100 && rtip->rti_dont_instance == 0 ) { struct bu_list *mid; /* Search dp->d_use_hd list for other instances */ for ( BU_LIST_FOR( mid, bu_list, &dp->d_use_hd ) ) { stp = BU_LIST_MAIN_PTR( soltab, mid, l2 ); RT_CK_SOLTAB(stp); if ( stp->st_matp == (matp_t)0 ) { if ( mat == (matp_t)0 ) { /* Both have identity matrix */ goto more_checks; } continue; } if ( mat == (matp_t)0 ) continue; /* doesn't match */ if ( !bn_mat_is_equal(mat, stp->st_matp, &rtip->rti_tol)) continue; more_checks: /* Don't instance this solid from some other model * instance. As this is nearly always equal, check it * last */ if ( stp->st_rtip != rtip ) continue; /* * stp now points to re-referenced solid. stp->st_id is * non-zero, indicating pre-existing solid. */ RT_CK_SOLTAB(stp); /* sanity */ /* Only increment use counter for non-dead solids. */ if ( !(stp->st_aradius <= -1) ) stp->st_uses++; /* dp->d_uses is NOT incremented, because number of * soltab's using it has not gone up. */ if ( RT_G_DEBUG & DEBUG_SOLIDS ) { bu_log( mat ? "rt_find_identical_solid: %s re-referenced %d\n" : "rt_find_identical_solid: %s re-referenced %d (identity mat)\n", dp->d_namep, stp->st_uses ); } /* Leave the appropriate dual critical-section */ RELEASE_SEMAPHORE_TREE(hash); return stp; } } /* * Create and link a new solid into the list. * * Ensure the search keys "dp", "st_mat" and "st_rtip" are stored * now, while still inside the critical section, because they are * searched on, above. */ BU_GETSTRUCT(stp, soltab); stp->l.magic = RT_SOLTAB_MAGIC; stp->l2.magic = RT_SOLTAB2_MAGIC; stp->st_rtip = rtip; stp->st_dp = dp; dp->d_uses++; stp->st_uses = 1; /* stp->st_id is intentionally left zero here, as a flag */ if ( mat ) { stp->st_matp = (matp_t)bu_malloc( sizeof(mat_t), "st_matp" ); MAT_COPY( stp->st_matp, mat ); } else { stp->st_matp = (matp_t)0; } /* Add to the appropriate soltab list head */ /* PARALLEL NOTE: Uses critical section on rt_solidheads element */ BU_LIST_INSERT( &(rtip->rti_solidheads[hash]), &(stp->l) ); /* Also add to the directory structure list head */ /* PARALLEL NOTE: Uses critical section on this 'dp' */ BU_LIST_INSERT( &dp->d_use_hd, &(stp->l2) ); /* * Leave the 4-way critical-section protecting dp and [hash] */ RELEASE_SEMAPHORE_TREE(hash); /* Enter an exclusive critical section to protect nsolids. * nsolids++ needs to be locked to a SINGLE thread */ bu_semaphore_acquire(RT_SEM_STATS); stp->st_bit = rtip->nsolids++; bu_semaphore_release(RT_SEM_STATS); /* * Fill in the last little bit of the structure in full parallel * mode, outside of any critical section. */ /* Init tables of regions using this solid. Usually small. */ bu_ptbl_init( &stp->st_regions, 7, "st_regions ptbl" ); return stp; }