union tree * evaluate(union tree *tr, const struct rt_tess_tol *ttol, const struct bn_tol *tol) { RT_CK_TREE(tr); switch (tr->tr_op) { case OP_NOP: return tr; case OP_NMG_TESS: /* ugh, keep it as nmg_tess and just shove the rt_bot_internal ptr * in as nmgregion. :/ Also, only doing the first shell of the first * model. Primitives should only provide a single shell, right? */ { struct rt_db_internal ip; struct nmgregion *nmgr = BU_LIST_FIRST(nmgregion, &tr->tr_d.td_r->m_p->r_hd); /* the bot temporary format may be unnecessary if we can walk * the nmg shells and generate soup from them directly. */ struct rt_bot_internal *bot = nmg_bot(BU_LIST_FIRST(shell, &nmgr->s_hd), tol); /* causes a crash. nmg_kr(nmgr); free(nmgr); */ tr->tr_d.td_r->m_p = (struct model *)bot2soup(bot, tol); SOUP_CKMAG((struct soup_s *)tr->tr_d.td_r->m_p); /* fill in a db_internal with our new bot so we can free it */ RT_DB_INTERNAL_INIT(&ip); ip.idb_major_type = DB5_MAJORTYPE_BRLCAD; ip.idb_minor_type = ID_BOT; ip.idb_meth = &OBJ[ID_BOT]; ip.idb_ptr = bot; ip.idb_meth->ft_ifree(&ip); } return tr; case OP_UNION: case OP_INTERSECT: case OP_SUBTRACT: RT_CK_TREE(tr->tr_b.tb_left); RT_CK_TREE(tr->tr_b.tb_right); tr->tr_b.tb_left = evaluate(tr->tr_b.tb_left, ttol, tol); tr->tr_b.tb_right = evaluate(tr->tr_b.tb_right, ttol, tol); RT_CK_TREE(tr->tr_b.tb_left); RT_CK_TREE(tr->tr_b.tb_right); SOUP_CKMAG(tr->tr_b.tb_left->tr_d.td_r->m_p); SOUP_CKMAG(tr->tr_b.tb_right->tr_d.td_r->m_p); split_faces(tr->tr_b.tb_left, tr->tr_b.tb_right, tol); RT_CK_TREE(tr->tr_b.tb_left); RT_CK_TREE(tr->tr_b.tb_right); SOUP_CKMAG(tr->tr_b.tb_left->tr_d.td_r->m_p); SOUP_CKMAG(tr->tr_b.tb_right->tr_d.td_r->m_p); break; default: bu_bomb("bottess evaluate(): bad op (first pass)\n"); } switch (tr->tr_op) { case OP_UNION: return compose(tr->tr_b.tb_left, tr->tr_b.tb_right, OUTSIDE, SAME, OUTSIDE); case OP_INTERSECT: return compose(tr->tr_b.tb_left, tr->tr_b.tb_right, INSIDE, SAME, INSIDE); case OP_SUBTRACT: return invert(compose(tr->tr_b.tb_left, invert(tr->tr_b.tb_right), OUTSIDE, OPPOSITE, INSIDE)); default: bu_bomb("bottess evaluate(): bad op (second pass, CSG)\n"); } bu_bomb("Got somewhere I shouldn't have\n"); return NULL; }
int ged_bot_fuse(struct ged *gedp, int argc, const char **argv) { struct directory *old_dp, *new_dp; struct rt_db_internal intern, intern2; struct rt_bot_internal *bot; int count=0; static const char *usage = "new_bot old_bot"; struct model *m; struct nmgregion *r; int ret, c, i; struct bn_tol *tol = &gedp->ged_wdbp->wdb_tol; int total = 0; volatile int out_type = 0; /* open edge output type: 0 = none, 1 = show, 2 = plot */ size_t open_cnt; struct bu_vls name_prefix = BU_VLS_INIT_ZERO; /* bu_getopt() options */ static const char *bot_fuse_options = "sp"; static const char *bot_fuse_options_str = "[-s|-p]"; 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 != 3 && argc != 4) { bu_vls_printf(gedp->ged_result_str, "Usage: %s %s %s", argv[0], bot_fuse_options_str, usage); return GED_HELP; } /* Turn off getopt's error messages */ bu_opterr = 0; bu_optind = 1; /* get all the option flags from the command line */ while ((c=bu_getopt(argc, (char **)argv, bot_fuse_options)) != -1) { switch (c) { case 's': { out_type = 1; /* show open edges */ break; } case 'p': { out_type = 2; /* plot open edges */ break; } default : { bu_vls_printf(gedp->ged_result_str, "Unknown option: '%c'", c); return GED_HELP; } } } i = argc - 2; bu_log("%s: start\n", argv[0]); GED_DB_LOOKUP(gedp, old_dp, argv[i+1], LOOKUP_NOISY, GED_ERROR & GED_QUIET); GED_DB_GET_INTERNAL(gedp, &intern, old_dp, bn_mat_identity, &rt_uniresource, GED_ERROR); if (intern.idb_major_type != DB5_MAJORTYPE_BRLCAD || intern.idb_minor_type != DB5_MINORTYPE_BRLCAD_BOT) { bu_vls_printf(gedp->ged_result_str, "%s: %s is not a BOT solid!\n", argv[0], argv[i+1]); return GED_ERROR; } /* create nmg model structure */ m = nmg_mm(); /* place bot in nmg structure */ bu_log("%s: running rt_bot_tess\n", argv[0]); ret = rt_bot_tess(&r, m, &intern, &gedp->ged_wdbp->wdb_ttol, tol); /* free internal representation of original bot */ rt_db_free_internal(&intern); if (ret != 0) { bu_vls_printf(gedp->ged_result_str, "%s: %s fuse failed (1).\n", argv[0], argv[i+1]); nmg_km(m); return GED_ERROR; } total = 0; /* Step 1 -- the vertices. */ bu_log("%s: running nmg_vertex_fuse\n", argv[0]); count = nmg_vertex_fuse(&m->magic, tol); total += count; bu_log("%s: %s, %d vertex fused\n", argv[0], argv[i+1], count); /* Step 1.5 -- break edges on vertices, before fusing edges */ bu_log("%s: running nmg_break_e_on_v\n", argv[0]); count = nmg_break_e_on_v(&m->magic, tol); total += count; bu_log("%s: %s, %d broke 'e' on 'v'\n", argv[0], argv[i+1], count); if (total) { struct nmgregion *r2; struct shell *s; bu_log("%s: running nmg_make_faces_within_tol\n", argv[0]); /* vertices and/or edges have been moved, * may have created out-of-tolerance faces */ for (BU_LIST_FOR(r2, nmgregion, &m->r_hd)) { for (BU_LIST_FOR(s, shell, &r2->s_hd)) nmg_make_faces_within_tol(s, tol); } } /* Step 2 -- the face geometry */ bu_log("%s: running nmg_model_face_fuse\n", argv[0]); count = nmg_model_face_fuse(m, tol); total += count; bu_log("%s: %s, %d faces fused\n", argv[0], argv[i+1], count); /* Step 3 -- edges */ bu_log("%s: running nmg_edge_fuse\n", argv[0]); count = nmg_edge_fuse(&m->magic, tol); total += count; bu_log("%s: %s, %d edges fused\n", argv[0], argv[i+1], count); bu_log("%s: %s, %d total fused\n", argv[0], argv[i+1], total); if (!BU_SETJUMP) { /* try */ /* convert the nmg model back into a bot */ bot = nmg_bot(BU_LIST_FIRST(shell, &r->s_hd), tol); bu_vls_sprintf(&name_prefix, "open_edges.%s", argv[i]); bu_log("%s: running show_dangling_edges\n", argv[0]); open_cnt = show_dangling_edges(gedp, &m->magic, bu_vls_addr(&name_prefix), out_type); bu_log("%s: WARNING %ld open edges, new BOT may be invalid!!!\n", argv[0], open_cnt); bu_vls_free(&name_prefix); /* free the nmg model structure */ nmg_km(m); } else { /* catch */ BU_UNSETJUMP; bu_vls_printf(gedp->ged_result_str, "%s: %s fuse failed (2).\n", argv[0], argv[i+1]); return GED_ERROR; } BU_UNSETJUMP; RT_DB_INTERNAL_INIT(&intern2); intern2.idb_major_type = DB5_MAJORTYPE_BRLCAD; intern2.idb_type = ID_BOT; intern2.idb_meth = &OBJ[ID_BOT]; intern2.idb_ptr = (void *)bot; GED_DB_DIRADD(gedp, new_dp, argv[i], RT_DIR_PHONY_ADDR, 0, RT_DIR_SOLID, (void *)&intern2.idb_type, GED_ERROR); GED_DB_PUT_INTERNAL(gedp, new_dp, &intern2, &rt_uniresource, GED_ERROR); bu_log("%s: Created new BOT (%s)\n", argv[0], argv[i]); bu_log("%s: Done.\n", argv[0]); return GED_OK; }
int ged_facetize(struct ged *gedp, int argc, const char *argv[]) { int i; int c; char *newname; struct rt_db_internal intern; struct directory *dp; int failed; int nmg_use_tnurbs = 0; struct db_tree_state init_state; struct db_i *dbip; union tree *facetize_tree; struct model *nmg_model; static const char *usage = "[ [-P] | [-n] [-t] [-T] ] new_obj old_obj [old_obj2 old_obj3 ...]"; /* static due to jumping */ static int triangulate; static int make_bot; static int marching_cube; static int screened_poisson; 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; } dbip = gedp->ged_wdbp->dbip; RT_CHECK_DBI(dbip); db_init_db_tree_state(&init_state, dbip, gedp->ged_wdbp->wdb_resp); /* Establish tolerances */ init_state.ts_ttol = &gedp->ged_wdbp->wdb_ttol; init_state.ts_tol = &gedp->ged_wdbp->wdb_tol; /* Initial values for options, must be reset each time */ marching_cube = 0; screened_poisson = 0; triangulate = 0; make_bot = 1; /* Parse options. */ bu_optind = 1; /* re-init bu_getopt() */ while ((c=bu_getopt(argc, (char * const *)argv, "mntTP")) != -1) { switch (c) { case 'm': marching_cube = triangulate = 1; /* no break, marching cubes assumes nmg for now */ case 'n': make_bot = 0; break; case 'P': screened_poisson = 1; triangulate = 1; make_bot = 1; break; case 'T': triangulate = 1; break; case 't': nmg_use_tnurbs = 1; break; default: { bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv[0], usage); return GED_ERROR; } } } argc -= bu_optind; argv += bu_optind; if (argc < 0) { bu_vls_printf(gedp->ged_result_str, "facetize: missing argument\n"); return GED_ERROR; } if (screened_poisson && (marching_cube || !make_bot || nmg_use_tnurbs)) { bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv[0], usage); return GED_ERROR; } newname = (char *)argv[0]; argv++; argc--; if (argc < 0) { bu_vls_printf(gedp->ged_result_str, "facetize: missing argument\n"); return GED_ERROR; } if (db_lookup(dbip, newname, LOOKUP_QUIET) != RT_DIR_NULL) { bu_vls_printf(gedp->ged_result_str, "error: solid '%s' already exists, aborting\n", newname); return GED_ERROR; } if (screened_poisson) { struct rt_bot_internal *bot; BU_ALLOC(bot, struct rt_bot_internal); bot->magic = RT_BOT_INTERNAL_MAGIC; bot->mode = RT_BOT_SOLID; bot->orientation = RT_BOT_UNORIENTED; bot->thickness = (fastf_t *)NULL; bot->face_mode = (struct bu_bitv *)NULL; /* TODO - generate point cloud, then mesh - need to see the input points for debugging */ (void)rt_generate_mesh(&(bot->faces), (int *)&(bot->num_faces), (point_t **)&(bot->vertices), (int *)&(bot->num_vertices), dbip, argv[0], 15); /* Export BOT as a new solid */ RT_DB_INTERNAL_INIT(&intern); intern.idb_major_type = DB5_MAJORTYPE_BRLCAD; intern.idb_type = ID_BOT; intern.idb_meth = &OBJ[ID_BOT]; intern.idb_ptr = (void *) bot; } else { bu_vls_printf(gedp->ged_result_str, "facetize: tessellating primitives with tolerances a=%g, r=%g, n=%g\n", gedp->ged_wdbp->wdb_ttol.abs, gedp->ged_wdbp->wdb_ttol.rel, gedp->ged_wdbp->wdb_ttol.norm); facetize_tree = (union tree *)0; nmg_model = nmg_mm(); init_state.ts_m = &nmg_model; i = db_walk_tree(dbip, argc, (const char **)argv, 1, &init_state, 0, /* take all regions */ facetize_region_end, nmg_use_tnurbs ? nmg_booltree_leaf_tnurb : nmg_booltree_leaf_tess, (void *)&facetize_tree ); if (i < 0) { bu_vls_printf(gedp->ged_result_str, "facetize: error in db_walk_tree()\n"); /* Destroy NMG */ nmg_km(nmg_model); return GED_ERROR; } if (facetize_tree) { /* Now, evaluate the boolean tree into ONE region */ bu_vls_printf(gedp->ged_result_str, "facetize: evaluating boolean expressions\n"); if (!BU_SETJUMP) { /* try */ failed = nmg_boolean(facetize_tree, nmg_model, &gedp->ged_wdbp->wdb_tol, &rt_uniresource); } else { /* catch */ BU_UNSETJUMP; bu_vls_printf(gedp->ged_result_str, "WARNING: facetization failed!!!\n"); db_free_tree(facetize_tree, &rt_uniresource); facetize_tree = (union tree *)NULL; nmg_km(nmg_model); nmg_model = (struct model *)NULL; return GED_ERROR; } BU_UNSETJUMP; } else failed = 1; if (failed) { bu_vls_printf(gedp->ged_result_str, "facetize: no resulting region, aborting\n"); db_free_tree(facetize_tree, &rt_uniresource); facetize_tree = (union tree *)NULL; nmg_km(nmg_model); nmg_model = (struct model *)NULL; return GED_ERROR; } /* New region remains part of this nmg "model" */ NMG_CK_REGION(facetize_tree->tr_d.td_r); bu_vls_printf(gedp->ged_result_str, "facetize: %s\n", facetize_tree->tr_d.td_name); /* Triangulate model, if requested */ if (triangulate && !make_bot) { bu_vls_printf(gedp->ged_result_str, "facetize: triangulating resulting object\n"); if (!BU_SETJUMP) { /* try */ if (marching_cube == 1) nmg_triangulate_model_mc(nmg_model, &gedp->ged_wdbp->wdb_tol); else nmg_triangulate_model(nmg_model, &gedp->ged_wdbp->wdb_tol); } else { /* catch */ BU_UNSETJUMP; bu_vls_printf(gedp->ged_result_str, "WARNING: triangulation failed!!!\n"); db_free_tree(facetize_tree, &rt_uniresource); facetize_tree = (union tree *)NULL; nmg_km(nmg_model); nmg_model = (struct model *)NULL; return GED_ERROR; } BU_UNSETJUMP; } if (make_bot) { struct rt_bot_internal *bot; struct nmgregion *r; struct shell *s; bu_vls_printf(gedp->ged_result_str, "facetize: converting to BOT format\n"); /* WTF, FIXME: this is only dumping the first shell of the first region */ r = BU_LIST_FIRST(nmgregion, &nmg_model->r_hd); if (r && BU_LIST_NEXT(nmgregion, &r->l) != (struct nmgregion *)&nmg_model->r_hd) bu_vls_printf(gedp->ged_result_str, "WARNING: model has more than one region, only facetizing the first\n"); s = BU_LIST_FIRST(shell, &r->s_hd); if (s && BU_LIST_NEXT(shell, &s->l) != (struct shell *)&r->s_hd) bu_vls_printf(gedp->ged_result_str, "WARNING: model has more than one shell, only facetizing the first\n"); if (!BU_SETJUMP) { /* try */ bot = (struct rt_bot_internal *)nmg_bot(s, &gedp->ged_wdbp->wdb_tol); } else { /* catch */ BU_UNSETJUMP; bu_vls_printf(gedp->ged_result_str, "WARNING: conversion to BOT failed!\n"); db_free_tree(facetize_tree, &rt_uniresource); facetize_tree = (union tree *)NULL; nmg_km(nmg_model); nmg_model = (struct model *)NULL; return GED_ERROR; } BU_UNSETJUMP; nmg_km(nmg_model); nmg_model = (struct model *)NULL; /* Export BOT as a new solid */ RT_DB_INTERNAL_INIT(&intern); intern.idb_major_type = DB5_MAJORTYPE_BRLCAD; intern.idb_type = ID_BOT; intern.idb_meth = &OBJ[ID_BOT]; intern.idb_ptr = (void *) bot; } else { bu_vls_printf(gedp->ged_result_str, "facetize: converting NMG to database format\n"); /* 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 = &OBJ[ID_NMG]; intern.idb_ptr = (void *)nmg_model; nmg_model = (struct model *)NULL; } } dp=db_diradd(dbip, newname, RT_DIR_PHONY_ADDR, 0, RT_DIR_SOLID, (void *)&intern.idb_type); if (dp == RT_DIR_NULL) { bu_vls_printf(gedp->ged_result_str, "Cannot add %s to directory\n", newname); return GED_ERROR; } if (rt_db_put_internal(dp, dbip, &intern, &rt_uniresource) < 0) { bu_vls_printf(gedp->ged_result_str, "Failed to write %s to database\n", newname); rt_db_free_internal(&intern); return GED_ERROR; } if (!screened_poisson) { facetize_tree->tr_d.td_r = (struct nmgregion *)NULL; /* Free boolean tree, and the regions in it */ db_free_tree(facetize_tree, &rt_uniresource); facetize_tree = (union tree *)NULL; } return GED_OK; }