static union tree * process_boolean(union tree *curtree, struct db_tree_state *tsp, const struct db_full_path *pathp) { union tree *ret_tree = TREE_NULL; /* Begin bomb protection */ if (!BU_SETJUMP) { /* try */ (void)nmg_model_fuse(*tsp->ts_m, tsp->ts_tol); ret_tree = nmg_booltree_evaluate(curtree, tsp->ts_tol, &rt_uniresource); } else { /* catch */ char *name = db_path_to_string(pathp); /* Error, bail out */ bu_log("conversion of %s FAILED!\n", name); /* Sometimes the NMG library adds debugging bits when * it detects an internal error, before before bombing out. */ RTG.NMG_debug = NMG_debug;/* restore mode */ /* Release any intersector 2d tables */ nmg_isect2d_final_cleanup(); /* Release the tree memory & input regions */ db_free_tree(curtree, &rt_uniresource);/* Does an nmg_kr() */ /* 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"); } bu_free(name, "db_path_to_string"); /* Now, make a new, clean model structure for next pass. */ *tsp->ts_m = nmg_mm(); } BU_UNSETJUMP;/* Relinquish the protection */ return ret_tree; }
static union tree * process_boolean(struct db_tree_state *tsp, union tree *curtree, const struct db_full_path *pathp) { union tree *result = NULL; /* Begin bomb protection */ if (!BU_SETJUMP) { /* try */ (void)nmg_model_fuse(*tsp->ts_m, tsp->ts_tol); result = nmg_booltree_evaluate(curtree, tsp->ts_tol, &rt_uniresource); } else { /* catch */ char *sofar; /* Error, bail out */ sofar = db_path_to_string(pathp); bu_log("FAILED: Cannot convert %s!\n", sofar); bu_free(sofar, "path string"); /* Sometimes the NMG library adds debugging bits when * it detects an internal error, before bombing out. */ RTG.NMG_debug = NMG_debug; /* restore mode */ /* Release the tree memory & input regions */ db_free_tree(curtree, &rt_uniresource); /* Does an nmg_kr() */ /* Get rid of (m)any other intermediate structures */ if ((*tsp->ts_m)->magic == NMG_MODEL_MAGIC) nmg_km(*tsp->ts_m); /* Now, make a new, clean model structure for next pass. */ *tsp->ts_m = nmg_mm(); } BU_UNSETJUMP; /* Relinquish the protection */ return result; }
/* * 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(register struct db_tree_state *tsp, struct db_full_path *pathp, union tree *curtree, genptr_t client_data) { union tree *ret_tree; struct nmgregion *r; struct bu_list vhead; 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_done * 100) / regions_tried : 0, sofar); bu_free(sofar, "path string"); } if (curtree->tr_op == OP_NOP) return curtree; regions_tried++; /* Begin bomb protection */ if ( ncpu == 1 ) { if ( BU_SETJUMP ) { /* Error, bail out */ BU_UNSETJUMP; /* Relinquish the protection */ /* Sometimes the NMG library adds debugging bits when * it detects an internal error, before bombing out. */ rt_g.NMG_debug = NMG_debug; /* restore mode */ /* Release the tree memory & input regions */ db_free_tree(curtree, &rt_uniresource); /* Does an nmg_kr() */ /* Get rid of (m)any other intermediate structures */ if ( (*tsp->ts_m)->magic != -1L ) nmg_km(*tsp->ts_m); /* Now, make a new, clean model structure for next pass. */ *tsp->ts_m = nmg_mm(); goto out; } } (void)nmg_model_fuse(*tsp->ts_m, tsp->ts_tol); ret_tree = nmg_booltree_evaluate(curtree, tsp->ts_tol, &rt_uniresource); /* librt/nmg_bool.c */ BU_UNSETJUMP; /* Relinquish the protection */ if ( ret_tree ) r = ret_tree->tr_d.td_r; else r = (struct nmgregion *)NULL; regions_done++; if (r != 0) { FILE *fp_psurf; int i; struct bu_vls file_base; struct bu_vls file; bu_vls_init(&file_base); bu_vls_init(&file); 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() */ out: BU_GETUNION(curtree, tree); curtree->magic = RT_TREE_MAGIC; curtree->tr_op = OP_NOP; return(curtree); }
int main(int argc, char **argv) /* really has no arguments */ { struct nmgregion *r; char * id_name = "BRL-CAD t-NURBS NMG Example"; char * tea_name = "UtahTeapot"; char * uplot_name = "teapot.pl"; struct bu_list vhead; FILE *fp; int i; tol.magic = BN_TOL_MAGIC; tol.dist = 0.005; tol.dist_sq = tol.dist * tol.dist; tol.perp = 1e-6; tol.para = 1 - tol.perp; BU_LIST_INIT( &rt_g.rtg_vlfree ); outfp = wdb_fopen( "tea_nmg.g" ); rt_g.debug |= DEBUG_ALLRAYS; /* Cause core dumps on bu_bomb(), but no extra messages */ while ((i=bu_getopt(argc, argv, "d")) != EOF) { switch (i) { case 'd' : rt_g.debug |= DEBUG_MEM | DEBUG_MEM_FULL; break; default : (void)fprintf(stderr, "Usage: %s [-d] > database.g\n", *argv); return(-1); } } mk_id( outfp, id_name); m = nmg_mm(); NMG_CK_MODEL( m ); r = nmg_mrsv( m ); NMG_CK_REGION( r ); s = BU_LIST_FIRST( shell, &r->s_hd ); NMG_CK_SHELL( s ); /* Step through each patch and create a NMG TNURB face * representing the patch then dump them out. */ for ( i = 0; i < PATCH_COUNT; i++) { dump_patch( patches[i] ); } /* Connect up the coincident vertexuses and edges */ (void)nmg_model_fuse( m, &tol ); /* write NMG to output file */ (void)mk_nmg( outfp, tea_name, m ); wdb_close(outfp); /* Make a vlist drawing of the model */ BU_LIST_INIT( &vhead ); nmg_m_to_vlist( &vhead, m, 0 ); /* Make a UNIX plot file from this vlist */ if ( (fp=fopen( uplot_name, "w" )) == NULL ) { bu_log( "Cannot open plot file: %s\n", uplot_name ); perror( "teapot_nmg" ); } else rt_vlist_to_uplot( fp, &vhead ); return(0); }
/** * R T _ M E T A B A L L _ T E S S * * Tessellate a metaball. */ int rt_metaball_tess(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol) { struct rt_metaball_internal *mb; fastf_t mtol, radius; point_t center, min, max; fastf_t i, j, k, finalstep = +INFINITY; struct bu_vls times = BU_VLS_INIT_ZERO; struct wdb_metaballpt *mbpt; struct shell *s; int numtri = 0; if (r == NULL || m == NULL) return -1; *r = NULL; NMG_CK_MODEL(m); RT_CK_DB_INTERNAL(ip); mb = (struct rt_metaball_internal *)ip->idb_ptr; RT_METABALL_CK_MAGIC(mb); rt_prep_timer(); /* since this geometry isn't necessarily prepped, we have to figure out the * finalstep and bounding box manually. */ for (BU_LIST_FOR(mbpt, wdb_metaballpt, &mb->metaball_ctrl_head)) V_MIN(finalstep, mbpt->fldstr); finalstep /= (fastf_t)1e5; radius = rt_metaball_get_bounding_sphere(¢er, mb->threshold, mb); if(radius < 0) { /* no control points */ bu_log("Attempting to tesselate metaball with no control points"); return -1; } rt_metaball_bbox(ip, &min, &max, tol); /* TODO: get better sampling tolerance, unless this is "good enough" */ mtol = ttol->abs; V_MAX(mtol, ttol->rel * radius * 10); V_MAX(mtol, tol->dist); *r = nmg_mrsv(m); /* new empty nmg */ s = BU_LIST_FIRST(shell, &(*r)->s_hd); /* the incredibly naïve approach. Time could be cut in half by simply * caching 4 point values, more by actually marching or doing active * refinement. This is the simplest pattern for now. */ for (i = min[X]; i < max[X]; i += mtol) for (j = min[Y]; j < max[Y]; j += mtol) for (k = min[Z]; k < max[Z]; k += mtol) { point_t p[8]; int pv = 0; /* generate the vertex values */ #define MEH(c,di,dj,dk) VSET(p[c], i+di, j+dj, k+dk); pv |= rt_metaball_point_inside((const point_t *)&p[c], mb) << c; MEH(0, 0, 0, mtol); MEH(1, mtol, 0, mtol); MEH(2, mtol, 0, 0); MEH(3, 0, 0, 0); MEH(4, 0, mtol, mtol); MEH(5, mtol, mtol, mtol); MEH(6, mtol, mtol, 0); MEH(7, 0, mtol, 0); #undef MEH if ( pv != 0 && pv != 255 ) { /* entire cube is either inside or outside */ point_t edges[12]; int rval; /* compute the edge values (if needed) */ #define MEH(a,b,c) if(!(pv&(1<<b)&&pv&(1<<c))) { \ rt_metaball_find_intersection(edges+a, mb, (const point_t *)(p+b), (const point_t *)(p+c), mtol, finalstep); \ } /* magic numbers! an edge, then the two attached vertices. * For edge/vertex mapping, refer to the awesome ascii art * at the beginning of this file. */ MEH(0 ,0,1); MEH(1 ,1,2); MEH(2 ,2,3); MEH(3 ,0,3); MEH(4 ,4,5); MEH(5 ,5,6); MEH(6 ,6,7); MEH(7 ,4,7); MEH(8 ,0,4); MEH(9 ,1,5); MEH(10,2,6); MEH(11,3,7); #undef MEH rval = nmg_mc_realize_cube(s, pv, (point_t *)edges, tol); numtri += rval; if(rval < 0) { bu_log("Error attempting to realize a cube O.o\n"); return rval; } } } nmg_mark_edges_real(&s->l.magic); nmg_region_a(*r, tol); nmg_model_fuse(m, tol); rt_get_timer(×, NULL); bu_log("metaball tesselate (%d triangles): %s\n", numtri, bu_vls_addr(×)); return 0; }