static union tree * bev_facetize_region_end(struct db_tree_state *UNUSED(tsp), const struct db_full_path *pathp, union tree *curtree, genptr_t client_data) { struct bu_list vhead; struct ged *gedp = (struct ged *)client_data; BU_LIST_INIT(&vhead); if (RT_G_DEBUG&DEBUG_TREEWALK) { char *sofar = db_path_to_string(pathp); bu_vls_printf(gedp->ged_result_str, "bev_facetize_region_end() path='%s'\n", sofar); bu_free((genptr_t)sofar, "path string"); } if (curtree->tr_op == OP_NOP) return curtree; bu_semaphore_acquire(RT_SEM_MODEL); if (bev_facetize_tree) { union tree *tr; BU_ALLOC(tr, union tree); RT_TREE_INIT(tr); tr->tr_op = OP_UNION; tr->tr_b.tb_regionp = REGION_NULL; tr->tr_b.tb_left = bev_facetize_tree; tr->tr_b.tb_right = curtree; bev_facetize_tree = tr; } else { bev_facetize_tree = curtree; } bu_semaphore_release(RT_SEM_MODEL); /* Tree has been saved, and will be freed later */ return TREE_NULL; }
static union tree * facetize_region_end(struct db_tree_state *tsp, const struct db_full_path *pathp, union tree *curtree, void *client_data) { struct bu_list vhead; union tree **facetize_tree; if (tsp) RT_CK_DBTS(tsp); if (pathp) RT_CK_FULL_PATH(pathp); facetize_tree = (union tree **)client_data; BU_LIST_INIT(&vhead); if (curtree->tr_op == OP_NOP) return curtree; if (*facetize_tree) { union tree *tr; BU_ALLOC(tr, union tree); RT_TREE_INIT(tr); tr->tr_op = OP_UNION; tr->tr_b.tb_regionp = REGION_NULL; tr->tr_b.tb_left = *facetize_tree; tr->tr_b.tb_right = curtree; *facetize_tree = tr; } else { *facetize_tree = curtree; } /* Tree has been saved, and will be freed later */ return TREE_NULL; }
HIDDEN void wdb_do_inter(struct bu_list *hp) { struct tokens *tok; for (BU_LIST_FOR(tok, tokens, hp)) { struct tokens *prev, *next; union tree *tp; if (tok->type != WDB_TOK_INTER) continue; prev = BU_LIST_PREV(tokens, &tok->l); next = BU_LIST_NEXT(tokens, &tok->l); if (prev->type !=WDB_TOK_TREE || next->type != WDB_TOK_TREE) continue; /* this is an eligible intersection operation */ BU_ALLOC(tp, union tree); RT_TREE_INIT(tp); tp->tr_b.tb_op = OP_INTERSECT; tp->tr_b.tb_regionp = (struct region *)NULL; tp->tr_b.tb_left = prev->tp; tp->tr_b.tb_right = next->tp; BU_LIST_DEQUEUE(&tok->l); bu_free((char *)tok, "tok"); BU_LIST_DEQUEUE(&prev->l); bu_free((char *)prev, "prev"); next->tp = tp; tok = next; } }
HIDDEN void do_union_subtr(struct bu_list *hp) { struct tokens *tok; for (BU_LIST_FOR(tok, tokens, hp)) { struct tokens *prev, *next; union tree *tp; if (tok->type != TOK_UNION && tok->type != TOK_SUBTR) continue; prev = BU_LIST_PREV(tokens, &tok->l); next = BU_LIST_NEXT(tokens, &tok->l); if (prev->type !=TOK_TREE || next->type != TOK_TREE) continue; /* this is an eligible operation */ BU_ALLOC(tp, union tree); RT_TREE_INIT(tp); if (tok->type == TOK_UNION) tp->tr_b.tb_op = OP_UNION; else tp->tr_b.tb_op = OP_SUBTRACT; tp->tr_b.tb_regionp = (struct region *)NULL; tp->tr_b.tb_left = prev->tp; tp->tr_b.tb_right = next->tp; BU_LIST_DEQUEUE(&tok->l); bu_free((char *)tok, "tok"); BU_LIST_DEQUEUE(&prev->l); bu_free((char *)prev, "prev"); next->tp = tp; tok = next; } }
/* * Called from db_walk_tree(). * * This routine must be prepared to run in parallel. */ union tree *do_region_end(struct db_tree_state *tsp, const struct db_full_path *pathp, union tree *curtree, void *UNUSED(client_data)) { union tree *ret_tree; struct bu_list vhead; struct nmgregion *r; RT_CK_FULL_PATH(pathp); RT_CK_TREE(curtree); RT_CK_TESS_TOL(tsp->ts_ttol); BN_CK_TOL(tsp->ts_tol); NMG_CK_MODEL(*tsp->ts_m); BU_LIST_INIT(&vhead); { char *sofar = db_path_to_string(pathp); bu_log("\ndo_region_end(%d %d%%) %s\n", regions_tried, regions_tried>0 ? (regions_converted * 100) / regions_tried : 0, sofar); bu_free(sofar, "path string"); } if (curtree->tr_op == OP_NOP) return curtree; regions_tried++; if (verbose) bu_log("Attempting to process region %s\n", db_path_to_string(pathp)); ret_tree= process_boolean(curtree, tsp, pathp); if (ret_tree) r = ret_tree->tr_d.td_r; else { if (verbose) bu_log("\tNothing left of this region after Boolean evaluation\n"); regions_written++; /* don't count as a failure */ r = (struct nmgregion *)NULL; } regions_converted++; if (r != (struct nmgregion *)NULL) { struct shell *s; int empty_region=0; int empty_model=0; /* Kill cracks */ s = BU_LIST_FIRST(shell, &r->s_hd); while (BU_LIST_NOT_HEAD(&s->l, &r->s_hd)) { struct shell *next_s; next_s = BU_LIST_PNEXT(shell, &s->l); if (nmg_kill_cracks(s)) { if (nmg_ks(s)) { empty_region = 1; break; } } s = next_s; } /* kill zero length edgeuses */ if (!empty_region) { empty_model = nmg_kill_zero_length_edgeuses(*tsp->ts_m); } if (!empty_region && !empty_model) { process_triangulation(r, pathp, tsp); regions_written++; } if (!empty_model) nmg_kr(r); } /* * Dispose of original tree, so that all associated dynamic * memory is released now, not at the end of all regions. * A return of TREE_NULL from this routine signals an error, * and there is no point to adding _another_ message to our output, * so we need to cons up an OP_NOP node to return. */ db_free_tree(curtree, &rt_uniresource); /* Does an nmg_kr() */ BU_ALLOC(curtree, union tree); RT_TREE_INIT(curtree); curtree->tr_op = OP_NOP; return curtree; }
int ged_bev(struct ged *gedp, int argc, const char *argv[]) { static const char *usage = "[P|t] new_obj obj1 op obj2 op obj3 ..."; int i; int c; int ncpu; char *cmdname; char *newname; struct rt_db_internal intern; struct directory *dp; char op; int failed; /* static due to longjmp */ static int triangulate = 0; static union tree *tmp_tree = NULL; GED_CHECK_DATABASE_OPEN(gedp, GED_ERROR); GED_CHECK_READ_ONLY(gedp, GED_ERROR); GED_CHECK_ARGC_GT_0(gedp, argc, GED_ERROR); /* initialize result */ bu_vls_trunc(gedp->ged_result_str, 0); /* must be wanting help */ if (argc == 1) { bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv[0], usage); return GED_HELP; } if (argc < 3) { bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv[0], usage); return GED_ERROR; } cmdname = (char *)argv[0]; /* Establish tolerances */ gedp->ged_wdbp->wdb_initial_tree_state.ts_ttol = &gedp->ged_wdbp->wdb_ttol; gedp->ged_wdbp->wdb_initial_tree_state.ts_tol = &gedp->ged_wdbp->wdb_tol; gedp->ged_wdbp->wdb_ttol.magic = RT_TESS_TOL_MAGIC; /* Initial values for options, must be reset each time */ ncpu = 1; triangulate = 0; /* Parse options. */ bu_optind = 1; /* re-init bu_getopt() */ while ((c=bu_getopt(argc, (char * const *)argv, "tP:")) != -1) { switch (c) { case 'P': #if 0 /* not yet supported */ ncpu = atoi(bu_optarg); #endif break; case 't': triangulate = 1; break; default: { bu_vls_printf(gedp->ged_result_str, "%s: option '%c' unknown\n", cmdname, c); } break; } } argc -= bu_optind; argv += bu_optind; newname = (char *)argv[0]; argv++; argc--; if (argc < 1) { bu_vls_printf(gedp->ged_result_str, "%s: Nothing to evaluate!!!\n", cmdname); return GED_ERROR; } GED_CHECK_EXISTS(gedp, newname, LOOKUP_QUIET, GED_ERROR); bu_vls_printf(gedp->ged_result_str, "%s: tessellating primitives with tolerances a=%g, r=%g, n=%g\n", argv[0], gedp->ged_wdbp->wdb_ttol.abs, gedp->ged_wdbp->wdb_ttol.rel, gedp->ged_wdbp->wdb_ttol.norm); bev_facetize_tree = (union tree *)0; bev_nmg_model = nmg_mm(); gedp->ged_wdbp->wdb_initial_tree_state.ts_m = &bev_nmg_model; op = ' '; tmp_tree = (union tree *)NULL; while (argc) { i = db_walk_tree(gedp->ged_wdbp->dbip, 1, (const char **)argv, ncpu, &gedp->ged_wdbp->wdb_initial_tree_state, 0, /* take all regions */ bev_facetize_region_end, nmg_booltree_leaf_tess, (genptr_t)gedp); if (i < 0) { bu_vls_printf(gedp->ged_result_str, "%s: error in db_walk_tree()\n", cmdname); /* Destroy NMG */ nmg_km(bev_nmg_model); return GED_ERROR; } argc--; argv++; if (tmp_tree && op != ' ') { union tree *new_tree; BU_ALLOC(new_tree, union tree); RT_TREE_INIT(new_tree); new_tree->tr_b.tb_regionp = REGION_NULL; new_tree->tr_b.tb_left = tmp_tree; new_tree->tr_b.tb_right = bev_facetize_tree; switch (op) { case 'u': case 'U': new_tree->tr_op = OP_UNION; break; case '-': new_tree->tr_op = OP_SUBTRACT; break; case '+': new_tree->tr_op = OP_INTERSECT; break; default: { bu_vls_printf(gedp->ged_result_str, "%s: Unrecognized operator: (%c)\nAborting\n", argv[0], op); db_free_tree(bev_facetize_tree, &rt_uniresource); nmg_km(bev_nmg_model); return GED_ERROR; } } tmp_tree = new_tree; bev_facetize_tree = (union tree *)NULL; } else if (!tmp_tree && op == ' ') { /* just starting out */ tmp_tree = bev_facetize_tree; bev_facetize_tree = (union tree *)NULL; } if (argc) { op = *argv[0]; argc--; argv++; } else op = ' '; } if (tmp_tree) { /* Now, evaluate the boolean tree into ONE region */ bu_vls_printf(gedp->ged_result_str, "%s: evaluating boolean expressions\n", cmdname); if (BU_SETJUMP) { BU_UNSETJUMP; bu_vls_printf(gedp->ged_result_str, "%s: WARNING: Boolean evaluation failed!!!\n", cmdname); if (tmp_tree) db_free_tree(tmp_tree, &rt_uniresource); tmp_tree = (union tree *)NULL; nmg_km(bev_nmg_model); bev_nmg_model = (struct model *)NULL; return GED_ERROR; } failed = nmg_boolean(tmp_tree, bev_nmg_model, &gedp->ged_wdbp->wdb_tol, &rt_uniresource); BU_UNSETJUMP; } else failed = 1; if (failed) { bu_vls_printf(gedp->ged_result_str, "%s: no resulting region, aborting\n", cmdname); if (tmp_tree) db_free_tree(tmp_tree, &rt_uniresource); tmp_tree = (union tree *)NULL; nmg_km(bev_nmg_model); bev_nmg_model = (struct model *)NULL; return GED_ERROR; } /* New region remains part of this nmg "model" */ NMG_CK_REGION(tmp_tree->tr_d.td_r); bu_vls_printf(gedp->ged_result_str, "%s: facetize %s\n", cmdname, tmp_tree->tr_d.td_name); nmg_vmodel(bev_nmg_model); /* Triangulate model, if requested */ if (triangulate) { bu_vls_printf(gedp->ged_result_str, "%s: triangulating resulting object\n", cmdname); if (BU_SETJUMP) { BU_UNSETJUMP; bu_vls_printf(gedp->ged_result_str, "%s: WARNING: Triangulation failed!!!\n", cmdname); if (tmp_tree) db_free_tree(tmp_tree, &rt_uniresource); tmp_tree = (union tree *)NULL; nmg_km(bev_nmg_model); bev_nmg_model = (struct model *)NULL; return GED_ERROR; } nmg_triangulate_model(bev_nmg_model, &gedp->ged_wdbp->wdb_tol); BU_UNSETJUMP; } bu_vls_printf(gedp->ged_result_str, "%s: converting NMG to database format\n", cmdname); /* Export NMG as a new solid */ RT_DB_INTERNAL_INIT(&intern); intern.idb_major_type = DB5_MAJORTYPE_BRLCAD; intern.idb_type = ID_NMG; intern.idb_meth = &rt_functab[ID_NMG]; intern.idb_ptr = (genptr_t)bev_nmg_model; bev_nmg_model = (struct model *)NULL; GED_DB_DIRADD(gedp, dp, newname, RT_DIR_PHONY_ADDR, 0, RT_DIR_SOLID, (genptr_t)&intern.idb_type, GED_ERROR); GED_DB_PUT_INTERNAL(gedp, dp, &intern, &rt_uniresource, GED_ERROR); tmp_tree->tr_d.td_r = (struct nmgregion *)NULL; /* Free boolean tree, and the regions in it. */ db_free_tree(tmp_tree, &rt_uniresource); return GED_OK; }
/* * D O _ R E G I O N _ E N D * * Called from db_walk_tree(). * * This routine must be prepared to run in parallel. */ union tree *do_region_end(struct db_tree_state *tsp, const struct db_full_path *pathp, union tree *curtree, genptr_t UNUSED(client_data)) { union tree *ret_tree; struct nmgregion *r; RT_CK_TESS_TOL(tsp->ts_ttol); BN_CK_TOL(tsp->ts_tol); NMG_CK_MODEL(*tsp->ts_m); if (RT_G_DEBUG&DEBUG_TREEWALK || verbose) { char *sofar = db_path_to_string(pathp); bu_log("\ndo_region_end(%d %d%%) %s\n", regions_tried, regions_tried>0 ? (regions_done * 100) / regions_tried : 0, sofar); bu_free(sofar, "path string"); } if (curtree->tr_op == OP_NOP) return curtree; regions_tried++; ret_tree = process_boolean(curtree, tsp, pathp); if ( ret_tree ) r = ret_tree->tr_d.td_r; else r = (struct nmgregion *)NULL; regions_done++; if (r != 0) { FILE *fp_psurf; size_t i; struct bu_vls file_base = BU_VLS_INIT_ZERO; struct bu_vls file = BU_VLS_INIT_ZERO; bu_vls_strcpy(&file_base, prefix); bu_vls_strcat(&file_base, DB_FULL_PATH_CUR_DIR(pathp)->d_namep); /* Dots confuse Jack's Peabody language. Change to '_'. */ for (i = 0; i < file_base.vls_len; i++) if (file_base.vls_str[i] == '.') file_base.vls_str[i] = '_'; /* Write color attribute to .fig figure file. */ if (tsp->ts_mater.ma_color_valid != 0) { fprintf(fp_fig, "\tattribute %s {\n", bu_vls_addr(&file_base)); fprintf(fp_fig, "\t\trgb = (%f, %f, %f);\n", V3ARGS(tsp->ts_mater.ma_color)); fprintf(fp_fig, "\t\tambient = 0.18;\n"); fprintf(fp_fig, "\t\tdiffuse = 0.72;\n"); fprintf(fp_fig, "\t}\n"); } /* Write segment attributes to .fig figure file. */ fprintf(fp_fig, "\tsegment %s_seg {\n", bu_vls_addr(&file_base)); fprintf(fp_fig, "\t\tpsurf=\"%s.pss\";\n", bu_vls_addr(&file_base)); if (tsp->ts_mater.ma_color_valid != 0) fprintf(fp_fig, "\t\tattribute=%s;\n", bu_vls_addr(&file_base)); fprintf(fp_fig, "\t\tsite base->location=trans(0, 0, 0);\n"); fprintf(fp_fig, "\t}\n"); if ( bu_vls_strlen(&base_seg) <= 0 ) { bu_vls_vlscat( &base_seg, &file_base ); } else { fprintf(fp_fig, "\tjoint %s_jt {\n", bu_vls_addr(&file_base)); fprintf(fp_fig, "\t\tconnect %s_seg.base to %s_seg.base;\n", bu_vls_addr(&file_base), bu_vls_addr(&base_seg) ); fprintf(fp_fig, "\t}\n"); } bu_vls_vlscat(&file, &file_base); bu_vls_strcat(&file, ".pss"); /* Required Jack suffix. */ /* Write psurf to .pss file. */ if ((fp_psurf = fopen(bu_vls_addr(&file), "wb")) == NULL) perror(bu_vls_addr(&file)); else { nmg_to_psurf(r, fp_psurf); fclose(fp_psurf); if (verbose) bu_log("*** Wrote %s\n", bu_vls_addr(&file)); } bu_vls_free(&file); /* Also write as UNIX-plot file, if desired */ if ( debug_plots ) { FILE *fp; bu_vls_vlscat(&file, &file_base); bu_vls_strcat(&file, ".pl"); if ((fp = fopen(bu_vls_addr(&file), "wb")) == NULL) perror(bu_vls_addr(&file)); else { struct bu_list vhead; pl_color( fp, (int)(tsp->ts_mater.ma_color[0] * 255), (int)(tsp->ts_mater.ma_color[1] * 255), (int)(tsp->ts_mater.ma_color[2] * 255) ); /* nmg_pl_r( fp, r ); */ BU_LIST_INIT( &vhead ); nmg_r_to_vlist( &vhead, r, 0 ); rt_vlist_to_uplot( fp, &vhead ); fclose(fp); if (verbose) bu_log("*** Wrote %s\n", bu_vls_addr(&file)); } bu_vls_free(&file); } /* NMG region is no longer necessary */ nmg_kr(r); } /* * Dispose of original tree, so that all associated dynamic * memory is released now, not at the end of all regions. * A return of TREE_NULL from this routine signals an error, * so we need to cons up an OP_NOP node to return. */ db_free_tree(curtree, &rt_uniresource); /* Does an nmg_kr() */ BU_ALLOC(curtree, union tree); RT_TREE_INIT(curtree); curtree->tr_op = OP_NOP; return curtree; }
union tree * nmg_region_end(struct db_tree_state *tsp, const struct db_full_path *pathp, union tree *curtree, void *UNUSED(client_data)) { struct nmgregion *r; struct bu_list vhead; union tree *ret_tree; char *name; RT_CK_TESS_TOL(tsp->ts_ttol); BN_CK_TOL(tsp->ts_tol); NMG_CK_MODEL(*tsp->ts_m); BARRIER_CHECK; BU_LIST_INIT(&vhead); if (RT_G_DEBUG&DEBUG_TREEWALK || verbose) { bu_log("\nConverted %d%% so far (%d of %d)\n", regions_tried>0 ? (regions_converted * 100) / regions_tried : 0, regions_converted, regions_tried ); } if (curtree->tr_op == OP_NOP) return curtree; name = db_path_to_string( pathp ); bu_log( "Attempting %s\n", name ); regions_tried++; ret_tree = process_boolean(curtree, tsp, pathp); if ( ret_tree ) r = ret_tree->tr_d.td_r; else r = (struct nmgregion *)NULL; bu_free( name, "db_path_to_string" ); regions_converted++; if (r != (struct nmgregion *)NULL) { struct shell *s; int empty_region=0; int empty_model=0; /* Kill cracks */ s = BU_LIST_FIRST( shell, &r->s_hd ); while ( BU_LIST_NOT_HEAD( &s->l, &r->s_hd ) ) { struct shell *next_s; next_s = BU_LIST_PNEXT( shell, &s->l ); if ( nmg_kill_cracks( s ) ) { if ( nmg_ks( s ) ) { empty_region = 1; break; } } s = next_s; } /* kill zero length edgeuses */ if ( !empty_region ) { empty_model = nmg_kill_zero_length_edgeuses( *tsp->ts_m ); } if ( !empty_region && !empty_model ) { /* Write the nmgregion to the output file */ nmg_2_vrml( outfp, pathp, r->m_p, &tsp->ts_mater ); } /* NMG region is no longer necessary */ if ( !empty_model ) nmg_kr(r); } else bu_log( "WARNING: Nothing left after Boolean evaluation of %s\n", db_path_to_string( pathp ) ); /* * Dispose of original tree, so that all associated dynamic * memory is released now, not at the end of all regions. * A return of TREE_NULL from this routine signals an error, * so we need to cons up an OP_NOP node to return. */ db_free_tree(curtree, &rt_uniresource); /* Does an nmg_kr() */ BU_ALLOC(curtree, union tree); RT_TREE_INIT(curtree); curtree->tr_op = OP_NOP; BARRIER_CHECK; return curtree; }
/* * Called from db_walk_tree(). * * This routine must be prepared to run in parallel. */ union tree * do_region_end(struct db_tree_state *tsp, const struct db_full_path *pathp, union tree *curtree, void *UNUSED(client_data)) { struct nmgregion *r; struct bu_list vhead; union tree *ret_tree; if (verbose) bu_log("do_region_end: regionid = %d\n", tsp->ts_regionid); RT_CK_TESS_TOL(tsp->ts_ttol); BN_CK_TOL(tsp->ts_tol); NMG_CK_MODEL(*tsp->ts_m); BU_LIST_INIT(&vhead); if (RT_G_DEBUG&DEBUG_TREEWALK || verbose) { char *sofar = db_path_to_string(pathp); bu_log("\ndo_region_end(%d %d%%) %s\n", regions_tried, regions_tried>0 ? (regions_converted * 100) / regions_tried : 0, sofar); bu_free(sofar, "path string"); } if (curtree->tr_op == OP_NOP) return curtree; regions_tried++; if (verbose) bu_log("\tEvaluating region\n"); ret_tree = process_boolean(curtree, tsp, pathp); if (ret_tree) r = ret_tree->tr_d.td_r; else r = (struct nmgregion *)NULL; regions_converted++; if (r != (struct nmgregion *)NULL) { struct shell *s; int empty_region = 0; int empty_model = 0; /* Kill cracks */ s = BU_LIST_FIRST(shell, &r->s_hd); while (BU_LIST_NOT_HEAD(&s->l, &r->s_hd)) { struct shell *next_s; next_s = BU_LIST_PNEXT(shell, &s->l); if (nmg_kill_cracks(s)) { if (nmg_ks(s)) { empty_region = 1; break; } } s = next_s; } /* kill zero length edgeuses */ if (!empty_region) { empty_model = nmg_kill_zero_length_edgeuses(*tsp->ts_m); } if (!empty_region && !empty_model) { /* Write the region to the EUCLID file */ Write_euclid_region(r, tsp); } if (!empty_model) nmg_kr(r); } /* * Dispose of original tree, so that all associated dynamic * memory is released now, not at the end of all regions. * A return of TREE_NULL from this routine signals an error, * so we need to cons up an OP_NOP node to return. */ db_free_tree(curtree, &rt_uniresource); /* Does an nmg_kr() */ BU_ALLOC(curtree, union tree); RT_TREE_INIT(curtree); curtree->tr_op = OP_NOP; return curtree; }
/* * Called from db_walk_tree(). * * This routine must be prepared to run in parallel. */ union tree * do_nmg_region_end(struct db_tree_state *tsp, const struct db_full_path *pathp, union tree *curtree, void *UNUSED(client_data)) { union tree *result; struct nmgregion *r; struct bu_list vhead; struct directory *dp; int dependent; size_t i; RT_CK_TESS_TOL(tsp->ts_ttol); BN_CK_TOL(tsp->ts_tol); NMG_CK_MODEL(*tsp->ts_m); BU_LIST_INIT(&vhead); if (RT_G_DEBUG&DEBUG_TREEWALK || verbose) { char *sofar = db_path_to_string(pathp); bu_log("\ndo_nmg_region_end(%d %d%%) %s\n", regions_tried, regions_tried>0 ? (regions_done * 100) / regions_tried : 0, sofar); bu_free(sofar, "path string"); } if (curtree->tr_op == OP_NOP) return curtree; regions_tried++; if (verbose) bu_log("\ndoing boolean tree evaluate...\n"); /* evaluate the boolean */ result = process_boolean(tsp, curtree, pathp); if (result) r = result->tr_d.td_r; else r = (struct nmgregion *)NULL; if (verbose) bu_log("\nfinished boolean tree evaluate...\n"); regions_done++; if (r != NULL) { dp = DB_FULL_PATH_CUR_DIR(pathp); if (multi_file) { /* Open the output file */ if (output_file == NULL) fp_dir = stdout; else { char *multi_name; size_t len; int unique = 0; char suffix[SUFFIX_LEN+1]; /* construct a unique file name */ len = strlen(output_file) + strlen(dp->d_namep) + 6 + SUFFIX_LEN; multi_name = (char *)bu_malloc(sizeof(char)*len, "multi_name"); snprintf(multi_name, len, "%s/%s.igs", output_file, dp->d_namep); bu_strlcpy(suffix, "a", sizeof(suffix)); suffix[0]--; while (!unique) { if (bu_file_readable(multi_name)) { unique = 1; break; } /* not unique, try adding a suffix */ len = strlen(suffix); i = len - 1; suffix[i]++; while (suffix[i] > 'z' && i > 0) { suffix[i] = 'a'; i--; suffix[i]++; } if (suffix[0] > 'z' && len < SUFFIX_LEN) { for (i = 0; i <= len; i++) suffix[i] = 'a'; } else if (suffix[0] > 'z' && len >= SUFFIX_LEN) { bu_log("too many files with the same name (%s)\n", dp->d_namep); bu_exit(1, "Cannot create a unique filename, \n"); } snprintf(multi_name, len, "%s/%s%s.igs", output_file, dp->d_namep, suffix); } if ((fp_dir = fopen(multi_name, "wb")) == NULL) { perror("g-iges"); bu_exit(1, "Cannot open output file: %s\n", multi_name); } } /* Open the temporary file for the parameter section */ if ((fp_param = bu_temp_file(NULL, 0)) == NULL) { perror("g-iges"); bu_exit(1, "Cannot open temporary file\n"); } /* let the IGES routines know the selected tolerances and the database pointer */ iges_init(&tol, &ttol, verbose, DBIP); /* Write start and global sections of the IGES file */ w_start_global(fp_dir, fp_param, db_name, prog_name, output_file, __DATE__, brlcad_version()); } if (mode == FACET_MODE) { dependent = 1; for (i = 0; i < no_of_indeps; i++) { if (!bu_strncmp(dp->d_namep, independent[i], NAMESIZE+1)) { dependent = 0; break; } } dp->d_uses = (-nmgregion_to_iges(dp->d_namep, r, dependent, fp_dir, fp_param)); } else if (mode == TRIMMED_SURF_MODE) dp->d_uses = (-nmgregion_to_tsurf(dp->d_namep, r, fp_dir, fp_param)); /* NMG region is no longer necessary */ nmg_kr(r); if (multi_file) { char copy_buffer[CP_BUF_SIZE] = {0}; /* Copy the parameter section from the temporary file to the output file */ if ((bu_fseek(fp_param, 0, 0))) { perror("g-iges"); bu_exit(1, "Cannot seek to start of temporary file\n"); } while ((i = fread(copy_buffer, 1, CP_BUF_SIZE, fp_param))) if (fwrite(copy_buffer, 1, i, fp_dir) != i) { perror("g-iges"); bu_exit(1, "Error in copying parameter data to %s\n", output_file); } /* Write the terminate section */ w_terminate(fp_dir); fclose(fp_dir); fclose(fp_param); } } /* * Dispose of original tree, so that all associated dynamic * memory is released now, not at the end of all regions. * A return of TREE_NULL from this routine signals an error, * so we need to cons up an OP_NOP node to return. */ db_free_tree(curtree, &rt_uniresource); /* Does an nmg_kr() */ BU_ALLOC(curtree, union tree); RT_TREE_INIT(curtree); curtree->tr_op = OP_NOP; return curtree; }
int make_hole(struct rt_wdb *wdbp, /* database to be modified */ point_t hole_start, /* center of start of hole */ vect_t hole_depth, /* depth and direction of hole */ fastf_t hole_radius, /* radius of hole */ int num_objs, /* number of objects that this hole affects */ struct directory **dp) /* array of directory pointers * [num_objs] of objects to * get this hole applied */ { struct bu_vls tmp_name = BU_VLS_INIT_ZERO; int i, base_len, count=0; RT_CHECK_WDB(wdbp); /* make sure we are only making holes in combinations, they do not * have to be regions */ for (i=0; i<num_objs; i++) { RT_CK_DIR(dp[i]); if (!(dp[i]->d_flags & RT_DIR_COMB)) { bu_log("make_hole(): can only make holes in combinations\n"); bu_log("\t%s is not a combination\n", dp[i]->d_namep); return 4; } } /* 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, "%d", count); } /* build the RCC based on parameters passed in */ if (mk_rcc(wdbp, bu_vls_addr(&tmp_name), hole_start, hole_depth, hole_radius)) { bu_log("Failed to create hole cylinder!!!\n"); bu_vls_free(&tmp_name); return 2; } /* subtract this RCC from each combination in the list passed in */ for (i=0; i<num_objs; i++) { struct rt_db_internal intern; struct rt_comb_internal *comb; union tree *tree; /* get the internal form of the combination */ if (rt_db_get_internal(&intern, dp[i], wdbp->dbip, NULL, wdbp->wdb_resp) < 0) { bu_log("Failed to get %s\n", dp[i]->d_namep); bu_vls_free(&tmp_name); return 3; } comb = (struct rt_comb_internal *)intern.idb_ptr; /* Build a new "subtract" node (will be the root of the new tree) */ BU_ALLOC(tree, union tree); RT_TREE_INIT(tree); tree->tr_b.tb_op = OP_SUBTRACT; tree->tr_b.tb_left = comb->tree; /* subtract from the original tree */ comb->tree = tree; /* Build a node for the RCC to be subtracted */ BU_ALLOC(tree, union tree); RT_TREE_INIT(tree); tree->tr_l.tl_op = OP_DB_LEAF; tree->tr_l.tl_mat = NULL; tree->tr_l.tl_name = bu_strdup(bu_vls_addr(&tmp_name)); /* copy name of RCC */ /* Put the RCC node to the right of the root */ comb->tree->tr_b.tb_right = tree; /* Save the modified combination. This will overwrite the * original combination if wdbp was opened with the * RT_WDB_TYPE_DB_DISK flag. If wdbp was opened with the * RT_WDB_TYPE_DB_INMEM flag, then the combination will be * temporarily over-written in memory only and the disk file * will not be modified. */ wdb_put_internal(wdbp, dp[i]->d_namep, &intern, 1.0); } 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; }
static int put_tree_into_comb(struct ged *gedp, struct rt_comb_internal *comb, struct directory *dp, const char *old_name, const char *new_name, const char *imstr) { int i; int done; char *line; char *ptr; char relation; char *name; struct rt_tree_array *rt_tree_array; struct line_list *llp; int node_count = 0; int tree_index = 0; union tree *tp; matp_t matrix; struct bu_vls vls = BU_VLS_INIT_ZERO; char *str; if (imstr == (char *)NULL) return GED_ERROR; BU_LIST_INIT(&HeadLines.l); /* duplicate the immutable str (from argv) for strtok style mutation */ str = bu_strdup(imstr); /* break str into lines */ line = str; ptr = strchr(str, '\n'); if (ptr != NULL) *ptr = '\0'; while (line != (char *)NULL) { int n; bu_vls_strcpy(&vls, line); if ((n = count_nodes(gedp, bu_vls_addr(&vls))) < 0) { bu_vls_free(&vls); bu_list_free(&HeadLines.l); bu_free(str, "dealloc bu_strdup str"); return GED_ERROR; } else if (n > 0) { BU_ALLOC(llp, struct line_list); BU_LIST_INSERT(&HeadLines.l, &llp->l); llp->line = line; node_count += n; } /* else blank line */ if (ptr != NULL && *(ptr+1) != '\0') { /* leap frog past EOS */ line = ptr + 1; ptr = strchr(line, '\n'); if (ptr != NULL) *ptr = '\0'; } else { line = NULL; } } bu_vls_free(&vls); /* build tree list */ if (node_count) rt_tree_array = (struct rt_tree_array *)bu_calloc(node_count, sizeof(struct rt_tree_array), "tree list"); else rt_tree_array = (struct rt_tree_array *)NULL; for (BU_LIST_FOR (llp, line_list, &HeadLines.l)) { done = 0; ptr = strtok(llp->line, _delims); while (!done) { if (!ptr) break; /* First non-white is the relation operator */ relation = (*ptr); if (relation == '\0') break; /* Next must be the member name */ ptr = strtok((char *)NULL, _delims); if (ptr == (char *)NULL) { bu_list_free(&HeadLines.l); if (rt_tree_array) bu_free((char *)rt_tree_array, "red: tree list"); bu_log("no name specified\n"); bu_free(str, "dealloc bu_strdup str"); return GED_ERROR; } name = ptr; /* Eliminate trailing white space from name */ i = (int)strlen(ptr); while (isspace((int)name[--i])) name[i] = '\0'; /* Check for existence of member */ if ((db_lookup(gedp->ged_wdbp->dbip, name, LOOKUP_QUIET)) == RT_DIR_NULL) bu_log("\tWARNING: ' %s ' does not exist\n", name); /* get matrix */ ptr = strtok((char *)NULL, _delims); if (ptr == (char *)NULL) { matrix = (matp_t)NULL; done = 1; } else if (*ptr == 'u' || (*ptr == '-' && *(ptr+1) == '\0') || (*ptr == '+' && *(ptr+1) == '\0')) { /* assume another relational operator */ matrix = (matp_t)NULL; } else { int k; matrix = (matp_t)bu_calloc(16, sizeof(fastf_t), "red: matrix"); matrix[0] = atof(ptr); for (k = 1; k < 16; k++) { ptr = strtok((char *)NULL, _delims); if (!ptr) { bu_log("incomplete matrix for member %s - No changes made\n", name); bu_free((char *)matrix, "red: matrix"); if (rt_tree_array) bu_free((char *)rt_tree_array, "red: tree list"); bu_list_free(&HeadLines.l); bu_free(str, "dealloc bu_strdup str"); return GED_ERROR; } matrix[k] = atof(ptr); } if (bn_mat_is_identity(matrix)) { bu_free((char *)matrix, "red: matrix"); matrix = (matp_t)NULL; } ptr = strtok((char *)NULL, _delims); if (ptr == (char *)NULL) done = 1; } /* Add it to the combination */ switch (relation) { case '+': rt_tree_array[tree_index].tl_op = OP_INTERSECT; break; case '-': rt_tree_array[tree_index].tl_op = OP_SUBTRACT; break; default: if (relation != 'u') { bu_log("unrecognized relation (assume UNION)\n"); } rt_tree_array[tree_index].tl_op = OP_UNION; break; } BU_ALLOC(tp, union tree); RT_TREE_INIT(tp); rt_tree_array[tree_index].tl_tree = tp; tp->tr_l.tl_op = OP_DB_LEAF; tp->tr_l.tl_name = bu_strdup(name); tp->tr_l.tl_mat = matrix; tree_index++; } } bu_list_free(&HeadLines.l); i = make_tree(gedp, comb, dp, node_count, old_name, new_name, rt_tree_array, tree_index); bu_free(str, "dealloc bu_strdup str"); return i; }
/* * Called from db_walk_tree(). * * This routine must be prepared to run in parallel. */ union tree * do_region_end(struct db_tree_state *tsp, const struct db_full_path *pathp, union tree *curtree, void *UNUSED(client_data)) { union tree *ret_tree = NULL; struct bu_list vhead; /* static due to longjmp */ static struct nmgregion *r = NULL; RT_CK_FULL_PATH(pathp); RT_CK_TREE(curtree); RT_CK_TESS_TOL(tsp->ts_ttol); BN_CK_TOL(tsp->ts_tol); NMG_CK_MODEL(*tsp->ts_m); BU_LIST_INIT(&vhead); if (RT_G_DEBUG&DEBUG_TREEWALK || verbose) { char *sofar = db_path_to_string(pathp); bu_log("\ndo_region_end(%d %d%%) %s\n", regions_tried, regions_tried>0 ? (regions_converted * 100) / regions_tried : 0, sofar); bu_free(sofar, "path string"); } if (curtree->tr_op == OP_NOP) return curtree; regions_tried++; /* do the deed */ ret_tree = process_region(pathp, curtree, tsp); if (ret_tree) r = ret_tree->tr_d.td_r; else { if (verbose) { printf("\tNothing left of this region after Boolean evaluation\n"); fprintf(fpe, "WARNING: Nothing left after Boolean evaluation: %s\n", db_path_to_string(pathp)); fflush(fpe); } regions_written++; /* don't count as a failure */ r = (struct nmgregion *)NULL; } regions_converted++; if (r != (struct nmgregion *)NULL) { struct shell *s; int empty_region=0; int empty_model=0; /* Kill cracks */ s = BU_LIST_FIRST(shell, &r->s_hd); while (BU_LIST_NOT_HEAD(&s->l, &r->s_hd)) { struct shell *next_s; next_s = BU_LIST_PNEXT(shell, &s->l); if (nmg_kill_cracks(s)) { if (nmg_ks(s)) { empty_region = 1; break; } } s = next_s; } /* kill zero length edgeuses */ if (!empty_region) { empty_model = nmg_kill_zero_length_edgeuses(*tsp->ts_m); } if (!empty_region && !empty_model) { if (!BU_SETJUMP) { /* try */ /* Write the region to the TANKILL file */ nmg_to_acad(r, pathp, tsp->ts_regionid); regions_written++; } else { /* catch */ char *sofar; BU_UNSETJUMP; sofar = db_path_to_string(pathp); bu_free((char *)sofar, "sofar"); /* Sometimes the NMG library adds debugging bits when * it detects an internal error, before bombing out. */ RTG.NMG_debug = NMG_debug; /* restore mode */ /* Release any intersector 2d tables */ nmg_isect2d_final_cleanup(); /* Get rid of (m)any other intermediate structures */ if ((*tsp->ts_m)->magic == NMG_MODEL_MAGIC) { nmg_km(*tsp->ts_m); } else { bu_log("WARNING: tsp->ts_m pointer corrupted, ignoring it.\n"); } /* Now, make a new, clean model structure for next pass. */ *tsp->ts_m = nmg_mm(); /* FIXME: leaking memory with curtree */ return TREE_NULL; } BU_UNSETJUMP; } if (!empty_model) nmg_kr(r); } /* * Dispose of original tree, so that all associated dynamic * memory is released now, not at the end of all regions. * A return of TREE_NULL from this routine signals an error, * and there is no point to adding _another_ message to our output, * so we need to cons up an OP_NOP node to return. */ if (regions_tried>0) { float npercent, tpercent; npercent = (float)(regions_converted * 100) / regions_tried; tpercent = (float)(regions_written * 100) / regions_tried; printf("Tried %d regions, %d conv. to NMG's %d conv. to tri. nmgper = %.2f%% triper = %.2f%% \n", regions_tried, regions_converted, regions_written, npercent, tpercent); } BU_ALLOC(curtree, union tree); RT_TREE_INIT(curtree); curtree->tr_op = OP_NOP; return curtree; }