static const char * save_comb(struct ged *gedp, struct directory *dpold) { /* Save a combination under a temporary name */ struct directory *dp; struct rt_db_internal intern; /* Make a new name */ const char *name = mktemp_comb(gedp, tmpcomb); if (rt_db_get_internal(&intern, dpold, gedp->ged_wdbp->dbip, (fastf_t *)NULL, &rt_uniresource) < 0) { bu_vls_printf(gedp->ged_result_str, "save_comb: Database read error, aborting\n"); return NULL; } if ((dp = db_diradd(gedp->ged_wdbp->dbip, name, RT_DIR_PHONY_ADDR, 0, dpold->d_flags, (genptr_t)&intern.idb_type)) == RT_DIR_NULL) { bu_vls_printf(gedp->ged_result_str, "save_comb: Cannot save copy of %s, no changed made\n", dpold->d_namep); return NULL; } if (rt_db_put_internal(dp, gedp->ged_wdbp->dbip, &intern, &rt_uniresource) < 0) { bu_vls_printf(gedp->ged_result_str, "save_comb: Cannot save copy of %s, no changed made\n", dpold->d_namep); return NULL; } return name; }
int ged_copyeval(struct ged *gedp, int argc, const char *argv[]) { static const char *usage = "path_to_old_prim new_prim"; struct _ged_trace_data gtd; struct directory *dp; struct rt_db_internal *ip; struct rt_db_internal internal, new_int; char *tok; int endpos = 0; int i; mat_t start_mat; 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; } /* initialize gtd */ gtd.gtd_gedp = gedp; gtd.gtd_flag = _GED_CPEVAL; gtd.gtd_prflag = 0; /* check if new solid name already exists in description */ GED_CHECK_EXISTS(gedp, argv[2], LOOKUP_QUIET, GED_ERROR); MAT_IDN(start_mat); /* build directory pointer array for desired path */ if (strchr(argv[1], '/')) { tok = strtok((char *)argv[1], "/"); while (tok) { GED_DB_LOOKUP(gedp, gtd.gtd_obj[endpos], tok, LOOKUP_NOISY, GED_ERROR & GED_QUIET); endpos++; tok = strtok((char *)NULL, "/"); } } else { GED_DB_LOOKUP(gedp, gtd.gtd_obj[endpos], argv[1], LOOKUP_NOISY, GED_ERROR & GED_QUIET); endpos++; } if (endpos < 1) { bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv[0], usage); return GED_ERROR; } gtd.gtd_objpos = endpos - 1; GED_DB_GET_INTERNAL(gedp, &internal, gtd.gtd_obj[endpos - 1], bn_mat_identity, &rt_uniresource, GED_ERROR); if (endpos > 1) { /* Make sure that final component in path is a solid */ if (internal.idb_type == ID_COMBINATION) { rt_db_free_internal(&internal); bu_vls_printf(gedp->ged_result_str, "final component on path must be a primitive!\n"); return GED_ERROR; } /* Accumulate the matrices */ ged_trace(gtd.gtd_obj[0], 0, start_mat, >d, 1); if (gtd.gtd_prflag == 0) { bu_vls_printf(gedp->ged_result_str, "PATH: "); for (i = 0; i < gtd.gtd_objpos; i++) bu_vls_printf(gedp->ged_result_str, "/%s", gtd.gtd_obj[i]->d_namep); bu_vls_printf(gedp->ged_result_str, " NOT FOUND\n"); rt_db_free_internal(&internal); return GED_ERROR; } /* Have found the desired path - wdb_xform is the transformation matrix */ /* wdb_xform matrix calculated in wdb_trace() */ /* create the new solid */ RT_DB_INTERNAL_INIT(&new_int); if (rt_generic_xform(&new_int, gtd.gtd_xform, &internal, 0, gedp->ged_wdbp->dbip, &rt_uniresource)) { rt_db_free_internal(&internal); bu_vls_printf(gedp->ged_result_str, "ged_copyeval: rt_generic_xform failed\n"); return GED_ERROR; } ip = &new_int; } else ip = &internal; /* should call GED_DB_DIRADD() but need to deal with freeing the * internals on failure. */ dp=db_diradd(gedp->ged_wdbp->dbip, argv[2], RT_DIR_PHONY_ADDR, 0, gtd.gtd_obj[endpos-1]->d_flags, (void *)&ip->idb_type); if (dp == RT_DIR_NULL) { rt_db_free_internal(&internal); if (ip == &new_int) rt_db_free_internal(&new_int); bu_vls_printf(gedp->ged_result_str, "An error has occurred while adding a new object to the database."); return GED_ERROR; } /* should call GED_DB_DIRADD() but need to deal with freeing the * internals on failure. */ if (rt_db_put_internal(dp, gedp->ged_wdbp->dbip, ip, &rt_uniresource) < 0) { /* if (ip == &new_int) then new_int gets freed by the rt_db_put_internal above * regardless of whether it succeeds or not. At this point only internal needs * to be freed. On the other hand if (ip == &internal), the internal gets freed * freed by the rt_db_put_internal above. In this case memory for new_int has * not been allocated. */ if (ip == &new_int) rt_db_free_internal(&internal); bu_vls_printf(gedp->ged_result_str, "Database write error, aborting"); return GED_ERROR; } /* see previous comment */ if (ip == &new_int) rt_db_free_internal(&internal); return GED_OK; }
int wrobj( char name[], int flags ) { struct directory *tdp; struct rt_db_internal intern; int i; if (dbip == DBI_NULL) return 0; if ( db_lookup( dbip, name, LOOKUP_QUIET) != DIR_NULL ) { Tcl_AppendResult(interp, "track naming error: ", name, " already exists\n", (char *)NULL); return(-1); } if ( flags != DIR_SOLID ) { Tcl_AppendResult(interp, "wrobj can only write solids, aborting\n" ); return( -1 ); } RT_INIT_DB_INTERNAL( &intern ); switch ( sol.s_type ) { case ID_ARB8: { struct rt_arb_internal *arb; BU_GETSTRUCT( arb, rt_arb_internal ); arb->magic = RT_ARB_INTERNAL_MAGIC; VMOVE( arb->pt[0], &sol.s_values[0] ); for ( i=1; i<8; i++ ) VADD2( arb->pt[i], &sol.s_values[i*3], arb->pt[0] ) intern.idb_ptr = (genptr_t)arb; intern.idb_major_type = DB5_MAJORTYPE_BRLCAD; intern.idb_type = ID_ARB8; intern.idb_meth = &rt_functab[ID_ARB8]; } break; case ID_TGC: { struct rt_tgc_internal *tgc; BU_GETSTRUCT( tgc, rt_tgc_internal ); tgc->magic = RT_TGC_INTERNAL_MAGIC; VMOVE( tgc->v, &sol.s_values[0] ); VMOVE( tgc->h, &sol.s_values[3] ); VMOVE( tgc->a, &sol.s_values[6] ); VMOVE( tgc->b, &sol.s_values[9] ); VMOVE( tgc->c, &sol.s_values[12] ); VMOVE( tgc->d, &sol.s_values[15] ); intern.idb_ptr = (genptr_t)tgc; intern.idb_major_type = DB5_MAJORTYPE_BRLCAD; intern.idb_type = ID_TGC; intern.idb_meth = &rt_functab[ID_TGC]; } break; default: Tcl_AppendResult(interp, "Unrecognized solid type in 'wrobj', aborting\n", (char *)NULL ); return( -1 ); } if ( (tdp = db_diradd( dbip, name, -1L, 0, flags, (genptr_t)&intern.idb_type)) == DIR_NULL ) { rt_db_free_internal( &intern, &rt_uniresource ); Tcl_AppendResult(interp, "Cannot add '", name, "' to directory, aborting\n", (char *)NULL ); return( -1 ); } if ( rt_db_put_internal( tdp, dbip, &intern, &rt_uniresource ) < 0 ) { rt_db_free_internal( &intern, &rt_uniresource ); Tcl_AppendResult(interp, "wrobj(", name, "): write error\n", (char *)NULL); TCL_ERROR_RECOVERY_SUGGESTION; return( -1 ); } return(0); }
int ged_nmg_collapse(struct ged *gedp, int argc, const char *argv[]) { char *new_name; struct model *m; struct rt_db_internal intern; struct directory *dp; struct bu_ptbl faces; struct face *fp; size_t count; fastf_t tol_coll; fastf_t min_angle; static const char *usage = "nmg_prim new_prim max_err_dist [min_angle]"; 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 < 4) { bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv[0], usage); return GED_ERROR; } if (strchr(argv[2], '/')) { bu_vls_printf(gedp->ged_result_str, "Do not use '/' in solid names: %s\n", argv[2]); return GED_ERROR; } new_name = (char *)argv[2]; if (db_lookup(gedp->ged_wdbp->dbip, new_name, LOOKUP_QUIET) != RT_DIR_NULL) { bu_vls_printf(gedp->ged_result_str, "%s already exists\n", new_name); return GED_ERROR; } if ((dp=db_lookup(gedp->ged_wdbp->dbip, argv[1], LOOKUP_NOISY)) == RT_DIR_NULL) return GED_ERROR; if (dp->d_flags & RT_DIR_COMB) { bu_vls_printf(gedp->ged_result_str, "%s is a combination, only NMG primitives are allowed here\n", argv[1]); return GED_ERROR; } if (rt_db_get_internal(&intern, dp, gedp->ged_wdbp->dbip, (matp_t)NULL, &rt_uniresource) < 0) { bu_vls_printf(gedp->ged_result_str, "Failed to get internal form of %s!!!!\n", argv[1]); return GED_ERROR; } if (intern.idb_type != ID_NMG) { bu_vls_printf(gedp->ged_result_str, "%s is not an NMG solid!!!!\n", argv[1]); rt_db_free_internal(&intern); return GED_ERROR; } tol_coll = atof(argv[3]) * gedp->ged_wdbp->dbip->dbi_local2base; if (tol_coll <= 0.0) { bu_vls_printf(gedp->ged_result_str, "tolerance distance too small\n"); return GED_ERROR; } if (argc == 5) { min_angle = atof(argv[4]); if (min_angle < 0.0) { bu_vls_printf(gedp->ged_result_str, "Minimum angle cannot be less than zero\n"); return GED_ERROR; } } else min_angle = 0.0; m = (struct model *)intern.idb_ptr; NMG_CK_MODEL(m); /* check that all faces are planar */ nmg_face_tabulate(&faces, &m->magic); for (BU_PTBL_FOR(fp, (struct face *), &faces)) { if (fp->g.magic_p != NULL && *(fp->g.magic_p) != NMG_FACE_G_PLANE_MAGIC) { bu_log("\tnot planar\n"); bu_ptbl_free(&faces); bu_vls_printf(gedp->ged_result_str, "nmg_collapse can only be applied to NMG primitives with planar faces\n"); return GED_ERROR; } } bu_ptbl_free(&faces); /* triangulate model */ nmg_triangulate_model(m, &gedp->ged_wdbp->wdb_tol); count = (size_t)nmg_edge_collapse(m, &gedp->ged_wdbp->wdb_tol, tol_coll, min_angle); dp=db_diradd(gedp->ged_wdbp->dbip, new_name, 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", new_name); rt_db_free_internal(&intern); return GED_ERROR; } if (rt_db_put_internal(dp, gedp->ged_wdbp->dbip, &intern, &rt_uniresource) < 0) { rt_db_free_internal(&intern); bu_vls_printf(gedp->ged_result_str, "Database write error, aborting.\n"); return GED_ERROR; } rt_db_free_internal(&intern); bu_vls_printf(gedp->ged_result_str, "%zu edges collapsed\n", count); return GED_OK; }
int wdb_comb_std_cmd(struct rt_wdb *wdbp, Tcl_Interp *interp, int argc, char *argv[]) { char *comb_name; int ch; int region_flag = -1; struct directory *dp; struct rt_db_internal intern; struct rt_comb_internal *comb = NULL; struct tokens tok_hd; short last_tok; int i; union tree *final_tree; if (wdbp->dbip->dbi_read_only) { Tcl_AppendResult(interp, "Database is read-only!\n", (char *)NULL); return TCL_ERROR; } if (argc < 3) { struct bu_vls vls = BU_VLS_INIT_ZERO; bu_vls_printf(&vls, "helplib_alias wdb_comb_std %s", argv[0]); Tcl_Eval(interp, bu_vls_addr(&vls)); bu_vls_free(&vls); return TCL_ERROR; } /* Parse options */ bu_optind = 1; /* re-init bu_getopt() */ while ((ch = bu_getopt(argc, argv, "cgr?")) != -1) { switch (ch) { case 'c': case 'g': region_flag = 0; break; case 'r': region_flag = 1; break; /* XXX How about -p and -v for FASTGEN? */ case '?': default: PRINT_USAGE; return TCL_OK; } } argc -= (bu_optind + 1); argv += bu_optind; comb_name = *argv++; if (argc == -1) { PRINT_USAGE; return TCL_OK; } if ((region_flag != -1) && (argc == 0)) { /* * Set/Reset the REGION flag of an existing combination */ if ((dp = db_lookup(wdbp->dbip, comb_name, LOOKUP_NOISY)) == RT_DIR_NULL) return TCL_ERROR; if (!(dp->d_flags & RT_DIR_COMB)) { Tcl_AppendResult(interp, comb_name, " is not a combination\n", (char *)0); return TCL_ERROR; } if (rt_db_get_internal(&intern, dp, wdbp->dbip, (fastf_t *)NULL, &rt_uniresource) < 0) { Tcl_AppendResult(interp, "Database read error, aborting\n", (char *)NULL); return TCL_ERROR; } comb = (struct rt_comb_internal *)intern.idb_ptr; RT_CK_COMB(comb); if (region_flag) { if (!comb->region_flag) { /* assign values from the defaults */ comb->region_id = wdbp->wdb_item_default++; comb->aircode = wdbp->wdb_air_default; comb->GIFTmater = wdbp->wdb_mat_default; comb->los = wdbp->wdb_los_default; } comb->region_flag = 1; } else comb->region_flag = 0; if (rt_db_put_internal(dp, wdbp->dbip, &intern, &rt_uniresource) < 0) { rt_db_free_internal(&intern); Tcl_AppendResult(interp, "Database write error, aborting\n", (char *)NULL); return TCL_ERROR; } return TCL_OK; } /* * At this point, we know we have a Boolean expression. * If the combination already existed and region_flag is -1, * then leave its region_flag alone. * If the combination didn't exist yet, * then pretend region_flag was 0. * Otherwise, make sure to set its c_flags according to region_flag. */ dp = db_lookup(wdbp->dbip, comb_name, LOOKUP_QUIET); if (dp != RT_DIR_NULL) { Tcl_AppendResult(interp, "ERROR: ", comb_name, " already exists\n", (char *)0); return TCL_ERROR; } /* parse Boolean expression */ BU_LIST_INIT(&tok_hd.l); tok_hd.type = WDB_TOK_NULL; last_tok = WDB_TOK_LPAREN; for (i = 0; i < argc; i++) { char *ptr; ptr = argv[i]; while (*ptr) { while (*ptr == '(' || *ptr == ')') { switch (*ptr) { case '(': wdb_append_lparen(&tok_hd.l); last_tok = WDB_TOK_LPAREN; break; case ')': wdb_append_rparen(&tok_hd.l); last_tok = WDB_TOK_RPAREN; break; } ptr++; } if (*ptr == '\0') continue; if (last_tok == WDB_TOK_RPAREN) { /* next token MUST be an operator */ if (wdb_add_operator(interp, &tok_hd.l, *ptr, &last_tok) == TCL_ERROR) { wdb_free_tokens(&tok_hd.l); return TCL_ERROR; } ptr++; } else if (last_tok == WDB_TOK_LPAREN) { /* next token MUST be an operand */ int name_len; name_len = wdb_add_operand(interp, &tok_hd.l, ptr); if (name_len < 1) { wdb_free_tokens(&tok_hd.l); return TCL_ERROR; } last_tok = WDB_TOK_TREE; ptr += name_len; } else if (last_tok == WDB_TOK_TREE) { /* must be an operator */ if (wdb_add_operator(interp, &tok_hd.l, *ptr, &last_tok) == TCL_ERROR) { wdb_free_tokens(&tok_hd.l); return TCL_ERROR; } ptr++; } else if (last_tok == WDB_TOK_UNION || last_tok == WDB_TOK_INTER || last_tok == WDB_TOK_SUBTR) { /* must be an operand */ int name_len; name_len = wdb_add_operand(interp, &tok_hd.l, ptr); if (name_len < 1) { wdb_free_tokens(&tok_hd.l); return TCL_ERROR; } last_tok = WDB_TOK_TREE; ptr += name_len; } } } if (wdb_check_syntax(interp, wdbp->dbip, &tok_hd.l, comb_name, dp)) { wdb_free_tokens(&tok_hd.l); return TCL_ERROR; } final_tree = wdb_eval_bool(&tok_hd.l); { int flags; flags = RT_DIR_COMB; BU_ALLOC(comb, struct rt_comb_internal); RT_COMB_INTERNAL_INIT(comb); comb->tree = final_tree; comb->region_id = -1; if (region_flag == (-1)) comb->region_flag = 0; else comb->region_flag = region_flag; if (comb->region_flag) { struct bu_vls tmp_vls = BU_VLS_INIT_ZERO; comb->region_flag = 1; comb->region_id = wdbp->wdb_item_default++;; comb->aircode = wdbp->wdb_air_default; comb->los = wdbp->wdb_los_default; comb->GIFTmater = wdbp->wdb_mat_default; bu_vls_printf(&tmp_vls, "Creating region id=%ld, air=%ld, los=%ld, GIFTmaterial=%ld\n", comb->region_id, comb->aircode, comb->los, comb->GIFTmater); Tcl_AppendResult(interp, bu_vls_addr(&tmp_vls), (char *)NULL); bu_vls_free(&tmp_vls); flags |= RT_DIR_REGION; } RT_DB_INTERNAL_INIT(&intern); intern.idb_major_type = DB5_MAJORTYPE_BRLCAD; intern.idb_type = ID_COMBINATION; intern.idb_meth = &rt_functab[ID_COMBINATION]; intern.idb_ptr = (genptr_t)comb; dp=db_diradd(wdbp->dbip, comb_name, RT_DIR_PHONY_ADDR, 0, flags, (genptr_t)&intern.idb_type); if (dp == RT_DIR_NULL) { Tcl_AppendResult(interp, "Failed to add ", comb_name, " to directory, aborting\n", (char *)NULL); return TCL_ERROR; } if (rt_db_put_internal(dp, wdbp->dbip, &intern, &rt_uniresource) < 0) { Tcl_AppendResult(interp, "Failed to write ", dp->d_namep, (char *)NULL); return TCL_ERROR; } } return TCL_OK; }
/** * make n copies of a v5 combination. */ static struct directory * copy_v5_comb(struct db_i *_dbip, struct directory *proto, struct clone_state *state, int idx) { struct directory *dp = (struct directory *)NULL; struct bu_vls *name; size_t i; /* sanity */ if (!proto) { bu_log("ERROR: clone internal consistency error\n"); return (struct directory *)NULL; } /* make n copies */ for (i = 0; i < state->n_copies; i++) { if (i==0) name = get_name(_dbip, proto, state, i); else { dp = db_lookup(_dbip, bu_vls_addr(&obj_list.names[idx].dest[i-1]), LOOKUP_QUIET); if (!dp) { continue; } name = get_name(_dbip, dp, state, i); } bu_vls_strcpy(&obj_list.names[idx].dest[i], bu_vls_addr(name)); /* we have a before and an after, do the copy */ if (proto->d_namep && bu_vls_addr(name)) { struct rt_db_internal dbintern; struct rt_comb_internal *comb; dp = db_lookup(_dbip, proto->d_namep, LOOKUP_QUIET); if (!dp) { bu_vls_free(name); continue; } if (rt_db_get_internal(&dbintern, dp, _dbip, bn_mat_identity, &rt_uniresource) < 0) { bu_log("ERROR: clone internal error copying %s\n", proto->d_namep); return NULL; } if ((dp=db_diradd(wdbp->dbip, bu_vls_addr(name), -1, 0, proto->d_flags, (genptr_t)&proto->d_minor_type)) == RT_DIR_NULL) { bu_log("An error has occurred while adding a new object to the database."); return NULL; } RT_CK_DB_INTERNAL(&dbintern); comb = (struct rt_comb_internal *)dbintern.idb_ptr; RT_CK_COMB(comb); RT_CK_TREE(comb->tree); /* recursively update the tree */ copy_v5_comb_tree(comb->tree, i); if (rt_db_put_internal(dp, wdbp->dbip, &dbintern, &rt_uniresource) < 0) { bu_log("ERROR: clone internal error copying %s\n", proto->d_namep); bu_vls_free(name); return NULL; } bu_vls_free(name); rt_db_free_internal(&dbintern); } /* done with this name */ bu_vls_free(name); } return dp; }
/** * make n copies of a v4 combination. */ static struct directory * copy_v4_comb(struct db_i *_dbip, struct directory *proto, struct clone_state *state, int idx) { struct directory *dp = (struct directory *)NULL; union record *rp = (union record *)NULL; size_t i; size_t j; /* make n copies */ for (i = 0; i < state->n_copies; i++) { /* get a v4 in-memory reference to the object being copied */ if ((rp = db_getmrec(_dbip, proto)) == (union record *)0) { TCL_READ_ERR; return NULL; } if (proto->d_flags & RT_DIR_REGION) { if (!is_in_list(obj_list, rp[1].M.m_instname)) { bu_log("ERROR: clone internal error looking up %s\n", rp[1].M.m_instname); return NULL; } bu_vls_strcpy(&obj_list.names[idx].dest[i], bu_vls_addr(&obj_list.names[index_in_list(obj_list, rp[1].M.m_instname)].dest[i])); /* bleh, odd convention going on here.. prefix regions with an 'r' */ *bu_vls_addr(&obj_list.names[idx].dest[i]) = 'r'; } else { struct bu_vls *name; if (i==0) name = get_name(_dbip, proto, state, i); else { dp = db_lookup(_dbip, bu_vls_addr(&obj_list.names[idx].dest[i-1]), LOOKUP_QUIET); if (!dp) { continue; } name = get_name(_dbip, dp, state, i); } bu_vls_strcpy(&obj_list.names[idx].dest[i], bu_vls_addr(name)); bu_vls_free(name); } bu_strlcpy(rp[0].c.c_name, bu_vls_addr(&obj_list.names[idx].dest[i]), NAMESIZE); /* add the object to the directory */ dp = db_diradd(_dbip, rp->c.c_name, RT_DIR_PHONY_ADDR, proto->d_len, proto->d_flags, &proto->d_minor_type); if ((dp == NULL) || (db_alloc(_dbip, dp, proto->d_len) < 0)) { TCL_ALLOC_ERR; return NULL; } for (j = 1; j < proto->d_len; j++) { if (!is_in_list(obj_list, rp[j].M.m_instname)) { bu_log("ERROR: clone internal error looking up %s\n", rp[j].M.m_instname); return NULL; } snprintf(rp[j].M.m_instname, NAMESIZE, "%s", bu_vls_addr(&obj_list.names[index_in_list(obj_list, rp[j].M.m_instname)].dest[i])); } /* write the object to disk */ if (db_put(_dbip, dp, rp, 0, dp->d_len) < 0) { bu_log("ERROR: clone internal error writing to the database\n"); return NULL; } /* our responsibility to free the record */ bu_free((char *)rp, "deallocate copy_v4_comb() db_getmrec() record"); } return dp; }
/** * make a copy of a v4 solid by adding it to our book-keeping list, * adding it to the db directory, and writing it out to disk. */ static void copy_v4_solid(struct db_i *_dbip, struct directory *proto, struct clone_state *state, int idx) { struct directory *dp = (struct directory *)NULL; union record *rp = (union record *)NULL; size_t i, j; /* make n copies */ for (i = 0; i < state->n_copies; i++) { struct bu_vls *name; if (i==0) name = get_name(_dbip, proto, state, i); else { dp = db_lookup(_dbip, bu_vls_addr(&obj_list.names[idx].dest[i-1]), LOOKUP_QUIET); if (!dp) { continue; } name = get_name(_dbip, dp, state, i); } /* XXX: this can probably be optimized. */ bu_vls_strcpy(&obj_list.names[idx].dest[i], bu_vls_addr(name)); bu_vls_free(name); /* add the object to the directory */ dp = db_diradd(_dbip, bu_vls_addr(&obj_list.names[idx].dest[i]), RT_DIR_PHONY_ADDR, proto->d_len, proto->d_flags, &proto->d_minor_type); if ((dp == RT_DIR_NULL) || (db_alloc(_dbip, dp, proto->d_len) < 0)) { TCL_ALLOC_ERR; return; } /* get an in-memory reference to the object being copied */ if ((rp = db_getmrec(_dbip, proto)) == (union record *)0) { TCL_READ_ERR; return; } if (rp->u_id == ID_SOLID) { bu_strlcpy(rp->s.s_name, dp->d_namep, NAMESIZE); /* mirror */ if (state->miraxis != W) { /* XXX er, this seems rather wrong .. but it's v4 so punt */ rp->s.s_values[state->miraxis] += 2 * (state->mirpos - rp->s.s_values[state->miraxis]); for (j = 3+state->miraxis; j < 24; j++) rp->s.s_values[j] = -rp->s.s_values[j]; } /* translate */ if (state->trans[W] > SMALL_FASTF) /* assumes primitive's first parameter is its position */ VADD2(rp->s.s_values, rp->s.s_values, state->trans); /* rotate */ if (state->rot[W] > SMALL_FASTF) { mat_t r; vect_t vec, ovec; if (state->rpnt[W] > SMALL_FASTF) VSUB2(rp->s.s_values, rp->s.s_values, state->rpnt); MAT_IDN(r); bn_mat_angles(r, state->rot[X], state->rot[Y], state->rot[Z]); for (j = 0; j < 24; j+=3) { VMOVE(vec, rp->s.s_values+j); MAT4X3VEC(ovec, r, vec); VMOVE(rp->s.s_values+j, ovec); } if (state->rpnt[W] > SMALL_FASTF) VADD2(rp->s.s_values, rp->s.s_values, state->rpnt); } } else bu_log("mods not available on %s\n", proto->d_namep); /* write the object to disk */ if (db_put(_dbip, dp, rp, 0, dp->d_len) < 0) { bu_log("ERROR: clone internal error writing to the database\n"); return; } } if (rp) bu_free((char *)rp, "copy_solid record[]"); return; }
static int copy_object(struct ged *gedp, struct directory *input_dp, struct db_i *input_dbip, struct db_i *curr_dbip, Tcl_HashTable *name_tbl, Tcl_HashTable *used_names_tbl, struct ged_concat_data *cc_data) { struct rt_db_internal ip; struct rt_extrude_internal *extr; struct rt_dsp_internal *dsp; struct rt_comb_internal *comb; struct directory *new_dp; char *new_name; if (rt_db_get_internal(&ip, input_dp, input_dbip, NULL, &rt_uniresource) < 0) { bu_vls_printf(gedp->ged_result_str, "Failed to get internal form of object (%s) - aborting!!!\n", input_dp->d_namep); return GED_ERROR; } if (ip.idb_major_type == DB5_MAJORTYPE_BRLCAD) { /* adjust names of referenced object in any object that reference other objects */ switch (ip.idb_minor_type) { case DB5_MINORTYPE_BRLCAD_COMBINATION: comb = (struct rt_comb_internal *)ip.idb_ptr; RT_CK_COMB(comb); adjust_names(comb->tree, curr_dbip, name_tbl, used_names_tbl, cc_data); break; case DB5_MINORTYPE_BRLCAD_EXTRUDE: extr = (struct rt_extrude_internal *)ip.idb_ptr; RT_EXTRUDE_CK_MAGIC(extr); new_name = get_new_name(extr->sketch_name, curr_dbip, name_tbl, used_names_tbl, cc_data); if (new_name) { bu_free(extr->sketch_name, "sketch name"); extr->sketch_name = bu_strdup(new_name); } break; case DB5_MINORTYPE_BRLCAD_DSP: dsp = (struct rt_dsp_internal *)ip.idb_ptr; RT_DSP_CK_MAGIC(dsp); if (dsp->dsp_datasrc == RT_DSP_SRC_OBJ) { /* This dsp references a database object, may need to change its name */ new_name = get_new_name(bu_vls_addr(&dsp->dsp_name), curr_dbip, name_tbl, used_names_tbl, cc_data); if (new_name) { bu_vls_free(&dsp->dsp_name); bu_vls_strcpy(&dsp->dsp_name, new_name); } } break; } } new_name = get_new_name(input_dp->d_namep, curr_dbip, name_tbl, used_names_tbl, cc_data); if (!new_name) { new_name = input_dp->d_namep; } if ((new_dp = db_diradd(curr_dbip, new_name, RT_DIR_PHONY_ADDR, 0, input_dp->d_flags, (void *)&input_dp->d_minor_type)) == RT_DIR_NULL) { bu_vls_printf(gedp->ged_result_str, "Failed to add new object name (%s) to directory - aborting!!\n", new_name); return GED_ERROR; } if (rt_db_put_internal(new_dp, curr_dbip, &ip, &rt_uniresource) < 0) { bu_vls_printf(gedp->ged_result_str, "Failed to write new object (%s) to database - aborting!!\n", new_name); return GED_ERROR; } return GED_OK; }
static int make_tree(struct ged *gedp, struct rt_comb_internal *comb, struct directory *dp, size_t node_count, const char *old_name, const char *new_name, struct rt_tree_array *rt_tree_array, int tree_index) { struct rt_db_internal intern; union tree *final_tree; if (tree_index) final_tree = (union tree *)db_mkgift_tree(rt_tree_array, node_count, &rt_uniresource); else final_tree = (union tree *)NULL; RT_DB_INTERNAL_INIT(&intern); intern.idb_major_type = DB5_MAJORTYPE_BRLCAD; intern.idb_type = ID_COMBINATION; intern.idb_meth = &rt_functab[ID_COMBINATION]; intern.idb_ptr = (genptr_t)comb; comb->tree = final_tree; if (!BU_STR_EQUAL(new_name, old_name)) { int flags; if (comb->region_flag) flags = RT_DIR_COMB | RT_DIR_REGION; else flags = RT_DIR_COMB; if (dp != RT_DIR_NULL) { if (db_delete(gedp->ged_wdbp->dbip, dp) || db_dirdelete(gedp->ged_wdbp->dbip, dp)) { bu_vls_printf(gedp->ged_result_str, "make_tree: Unable to delete directory entry for %s\n", old_name); intern.idb_meth->ft_ifree(&intern); return GED_ERROR; } } if ((dp=db_diradd(gedp->ged_wdbp->dbip, new_name, RT_DIR_PHONY_ADDR, 0, flags, (genptr_t)&intern.idb_type)) == RT_DIR_NULL) { bu_vls_printf(gedp->ged_result_str, "make_tree: Cannot add %s to directory, no changes made\n", new_name); intern.idb_meth->ft_ifree(&intern); return 1; } } else if (dp == RT_DIR_NULL) { int flags; if (comb->region_flag) flags = RT_DIR_COMB | RT_DIR_REGION; else flags = RT_DIR_COMB; if ((dp=db_diradd(gedp->ged_wdbp->dbip, new_name, RT_DIR_PHONY_ADDR, 0, flags, (genptr_t)&intern.idb_type)) == RT_DIR_NULL) { bu_vls_printf(gedp->ged_result_str, "make_tree: Cannot add %s to directory, no changes made\n", new_name); intern.idb_meth->ft_ifree(&intern); return GED_ERROR; } } else { if (comb->region_flag) dp->d_flags |= RT_DIR_REGION; else dp->d_flags &= ~RT_DIR_REGION; } if (rt_db_put_internal(dp, gedp->ged_wdbp->dbip, &intern, &rt_uniresource) < 0) { bu_vls_printf(gedp->ged_result_str, "make_tree: Unable to write new combination into database.\n"); return GED_ERROR; } return GED_OK; }
int ged_mirror(struct ged *gedp, int argc, const char *argv[]) { /* trailing x|y|z intentionally not documented */ static const char *usage = "[-h] [-p \"point\"] [-d \"dir\"] [-x|-y|-z] [-o offset] old new"; int k; point_t mirror_pt = {0.0, 0.0, 0.0}; vect_t mirror_dir = {1.0, 0.0, 0.0}; /* intentionally double for scanning */ double scanpt[3]; double scandir[3]; double mirror_offset = 0.0; int ret; struct rt_db_internal *ip; struct rt_db_internal internal; struct directory *dp; 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; } bu_optind = 1; while ((k = bu_getopt(argc, (char * const *)argv, (const char *)"d:D:hHo:O:p:P:xXyYzZ")) != -1) { switch (k) { case 'p': case 'P': if (sscanf(bu_optarg, "%lf %lf %lf", &scanpt[X], &scanpt[Y], &scanpt[Z]) != 3) { bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv[0], usage); return GED_ERROR; } /* convert from double to fastf_t */ VMOVE(mirror_pt, scanpt); break; case 'd': case 'D': if (sscanf(bu_optarg, "%lf %lf %lf", &scandir[X], &scandir[Y], &scandir[Z]) != 3) { bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv[0], usage); return GED_ERROR; } /* convert from double to fastf_t */ VMOVE(mirror_dir, scandir); break; case 'o': case 'O': if (sscanf(bu_optarg, "%lf", &mirror_offset) != 1) { bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv[0], usage); return GED_ERROR; } break; case 'x': case 'X': VSET(mirror_dir, 1.0, 0.0, 0.0); break; case 'y': case 'Y': VSET(mirror_dir, 0.0, 1.0, 0.0); break; case 'z': case 'Z': VSET(mirror_dir, 0.0, 0.0, 1.0); break; case 'h': case 'H': bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv[0], usage); return GED_HELP; default: bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv[0], usage); return GED_ERROR; break; } } argc -= bu_optind; if (argc < 2 || argc > 4) { bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv[0], usage); return GED_ERROR; } else if (argc == 3) { /* support a trailing x|y|z option as classic command * behavior. THIS IS INTENTIONALLY UNDOCUMENTED. if users * have to read the usage, they can learn the new form. */ switch (argv[bu_optind+2][0]) { case 'x': case 'X': VSET(mirror_dir, 1.0, 0.0, 0.0); break; case 'y': case 'Y': VSET(mirror_dir, 0.0, 1.0, 0.0); break; case 'z': case 'Z': VSET(mirror_dir, 0.0, 0.0, 1.0); break; default: bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv[0], usage); return GED_ERROR; break; } } /* make sure object mirroring to does not already exist */ if (db_lookup(gedp->ged_wdbp->dbip, argv[bu_optind+1], LOOKUP_QUIET) != RT_DIR_NULL) { bu_vls_printf(gedp->ged_result_str, "%s already exists\n", argv[bu_optind+1]); return GED_ERROR; } /* look up the object being mirrored */ if ((dp = db_lookup(gedp->ged_wdbp->dbip, argv[bu_optind], LOOKUP_NOISY)) == RT_DIR_NULL) { bu_vls_printf(gedp->ged_result_str, "Unable to find solid [%s]\n", argv[bu_optind]); return GED_ERROR; } /* get object being mirrored */ ret = rt_db_get_internal(&internal, dp, gedp->ged_wdbp->dbip, NULL, gedp->ged_wdbp->wdb_resp); if (ret < 0) { bu_vls_printf(gedp->ged_result_str, "Unable to load solid [%s]\n", argv[bu_optind]); return GED_ERROR; } mirror_offset *= gedp->ged_wdbp->dbip->dbi_local2base; VUNITIZE(mirror_dir); VJOIN1(mirror_pt, mirror_pt, mirror_offset, mirror_dir); /* mirror the object */ ip = rt_mirror(gedp->ged_wdbp->dbip, &internal, mirror_pt, mirror_dir, gedp->ged_wdbp->wdb_resp); if (ip == NULL) { bu_vls_printf(gedp->ged_result_str, "Unable to mirror [%s]", argv[bu_optind]); return GED_ERROR; } /* add the mirrored object to the directory */ dp = db_diradd(gedp->ged_wdbp->dbip, argv[bu_optind+1], RT_DIR_PHONY_ADDR, 0, dp->d_flags, (void *)&ip->idb_type); if (dp == RT_DIR_NULL) { bu_vls_printf(gedp->ged_result_str, "Unable to add [%s] to the database directory", argv[bu_optind+1]); return GED_ERROR; } /* save the mirrored object to disk */ if (rt_db_put_internal(dp, gedp->ged_wdbp->dbip, ip, gedp->ged_wdbp->wdb_resp) < 0) { bu_vls_printf(gedp->ged_result_str, "Unable to store [%s] to the database", argv[bu_optind+1]); return GED_ERROR; } { /* draw the new object */ const char *object = (const char *)argv[bu_optind+1]; const char *e_argv[3] = {0, 0, 0}; e_argv[0] = "draw"; e_argv[1] = object; e_argv[2] = NULL; (void)ged_draw(gedp, 2, e_argv); ged_view_update(gedp->ged_gvp); } return GED_OK; }
void pop_gop(int gop, char *parent1_id, char *parent2_id, char *child1_id, char *child2_id, struct db_i *dbi_p, struct db_i *dbi_c, struct resource *resp) { struct rt_db_internal in1, in2; struct rt_comb_internal *parent1; struct rt_comb_internal *parent2; struct directory *dp; union tree *cpoint, **cross_parent; struct node *add; int i = 0; struct node *chosen_node; int rand_node; RT_CHECK_DBI( dbi_p ); RT_CHECK_DBI( dbi_c ); RT_CK_RESOURCE( resp ); crossover_point = (union tree *)NULL; crossover_parent = (union tree **)NULL; node = (struct node*)NULL; if ( !rt_db_lookup_internal(dbi_p, parent1_id, &dp, &in1, LOOKUP_NOISY, &rt_uniresource)) bu_exit(EXIT_FAILURE, "Failed to read parent1"); shape_number =num_nodes= 0; parent1 = (struct rt_comb_internal *)in1.idb_ptr; mutate = 0; switch (gop) { case REPRODUCE: pop_functree(dbi_p, dbi_c, parent1->tree, resp, child1_id); break; case CROSSOVER: crossover = 1; /*load other parent */ if ( !rt_db_lookup_internal(dbi_p, parent2_id, &dp, &in2, LOOKUP_NOISY, resp)) bu_exit(EXIT_FAILURE, "Failed to read parent2"); parent2 = (struct rt_comb_internal *)in2.idb_ptr; BU_ALLOC(node, struct node); BU_LIST_INIT(&node->l); chosen_node = NULL; do{ num_nodes = 0; crossover_parent = &parent1->tree; crossover_node = (int)(pop_rand() * db_count_tree_nodes(parent1->tree, 0)); node_idx = 0; pop_functree(dbi_p, dbi_c, parent1->tree, resp, NULL); cross_parent = crossover_parent; cpoint = crossover_point; crossover_op = crossover_point->tr_op; #define MASK (OP_UNION | OP_XOR | OP_SUBTRACT|OP_INTERSECT) if (crossover_op & MASK)crossover_op = MASK; crossover_node = db_count_tree_nodes(crossover_point, 0); if (pop_find_nodes(parent2->tree) == crossover_node) { BU_ALLOC(add, struct node); add->s_parent = &parent2->tree; add->s_child = parent2->tree; BU_LIST_INSERT(&node->l, &add->l); ++num_nodes; } if (num_nodes > 0) { rand_node = (int)(pop_rand() * num_nodes); for (add=BU_LIST_FIRST(node, &node->l);BU_LIST_NOT_HEAD(add, &node->l) && chosen_node == NULL; add=BU_LIST_PNEXT(node, add)) { if (i++ == rand_node) { chosen_node = add; /* break cleanly...? */ } } } }while(chosen_node == NULL); /* cross trees */ *cross_parent = chosen_node->s_child; *chosen_node->s_parent =cpoint; while (BU_LIST_WHILE(add, node, &node->l)) { BU_LIST_DEQUEUE(&add->l); bu_free(add, "node"); } bu_free(node, "node"); crossover = 0; /*duplicate shapes held in trees*/ pop_functree(dbi_p, dbi_c, parent1->tree, resp, child1_id); shape_number = 0; pop_functree(dbi_p, dbi_c, parent2->tree, resp, child2_id); if ((dp = db_diradd(dbi_c, child2_id, -1, 0, dp->d_flags, (genptr_t)&dp->d_minor_type)) == RT_DIR_NULL) bu_exit(EXIT_FAILURE, "Failed to add new individual to child database"); if (rt_db_put_internal(dp, dbi_c, &in2, resp) < 0) bu_exit(EXIT_FAILURE, "Database write failure"); rt_db_free_internal(&in2); break; case MUTATE: crossover_parent = &parent1->tree; crossover_node = (int)(pop_rand() * db_count_tree_nodes(parent1->tree, 0)); node_idx = 0; mutate = 1; pop_functree(dbi_p, dbi_c, parent1->tree, resp, child1_id); mutate = 0; break; /* //random node to mutate n = (int)(pop_rand() * db_count_tree_nodes(parent1->tree, 0)); s_parent = &parent1->tree; s_node = n; node = 0; //find node pop_functree(dbi_p, dbi_c, parent1->tree, resp, NULL); */ default: bu_exit(EXIT_FAILURE, "illegal genetic operator\nfailed to execute genetic op"); } if ((dp=db_diradd(dbi_c, child1_id, -1, 0, dp->d_flags, (genptr_t)&dp->d_minor_type)) == RT_DIR_NULL) { bu_exit(EXIT_FAILURE, "Failed to add new individual to child database"); } if (rt_db_put_internal(dp, dbi_c, &in1, resp) < 0) bu_exit(EXIT_FAILURE, "Database write failure"); rt_db_free_internal(&in1); }
void pop_functree(struct db_i *dbi_p, struct db_i *dbi_c, union tree *tp, struct resource *resp, char *name ) { struct directory *dp; struct rt_db_internal in; char shape[256]; if ( !tp ) { return; } if (crossover) { if (node_idx > crossover_node) return; if (node_idx == crossover_node) { crossover_point = tp; ++node_idx; return; } else ++node_idx; } else if (mutate) ++node_idx; switch ( tp->tr_op ) { case OP_DB_LEAF: /* dont need to do any processing if crossing over */ if (crossover) { return; } /* if we aren't crossing over, we copy the individual into the * new database. If we're mutating, mutate the object after loading * the internal object */ if ( !rt_db_lookup_internal(dbi_p, tp->tr_l.tl_name, &dp, &in, LOOKUP_NOISY, resp)) bu_exit(EXIT_FAILURE, "Failed to read parent"); /* rename leaf based on individual it belongs to */ snprintf(shape, 256, "%s-%.3d", name, shape_number++); bu_free(tp->tr_l.tl_name, "bu_strdup"); tp->tr_l.tl_name = bu_strdup(shape); /* if we're mutating, and this is the node we've chosen * to modify. mutate this node */ if ( mutate && node_idx == crossover_node ) pop_mutate(in.idb_minor_type, in.idb_ptr); /* write child to new database */ if ((dp=db_diradd(dbi_c, shape, -1, 0, dp->d_flags, (genptr_t)&dp->d_minor_type)) == RT_DIR_NULL) bu_exit(EXIT_FAILURE, "Failed to add new object to the database"); if (rt_db_put_internal(dp, dbi_c, &in, resp) < 0) bu_exit(EXIT_FAILURE, "Failed to write new individual to database"); rt_db_free_internal(&in); break; case OP_UNION: case OP_INTERSECT: case OP_SUBTRACT: case OP_XOR: /* mutate CSG operation */ if (mutate) if (node_idx == crossover_node) { /* tp->tr_op = (int)(2+pop_rand()*3);//FIXME: pop_rand() can be 1!*/ } /* if we're performing, save parent as its right or left pointer will need * to be modified to point to the new child node */ if (crossover && node_idx == crossover_node) crossover_parent = &tp->tr_b.tb_left; pop_functree( dbi_p, dbi_c, tp->tr_b.tb_left, resp, name); if (crossover && node_idx == crossover_node) crossover_parent = &tp->tr_b.tb_right; pop_functree( dbi_p, dbi_c, tp->tr_b.tb_right, resp, name); break; default: bu_exit(EXIT_FAILURE, "pop_functree: unrecognized operator\n" ); } }
int ged_shells(struct ged *gedp, int argc, const char *argv[]) { struct directory *old_dp, *new_dp; struct rt_db_internal old_intern, new_intern; struct model *m_tmp, *m; struct nmgregion *r_tmp, *r; struct shell *s_tmp, *s; int shell_count=0; struct bu_vls shell_name = BU_VLS_INIT_ZERO; long **trans_tbl; static const char *usage = "nmg_model"; 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 != 2) { bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv[0], usage); return GED_ERROR; } if ((old_dp = db_lookup(gedp->ged_wdbp->dbip, argv[1], LOOKUP_NOISY)) == RT_DIR_NULL) return GED_ERROR; if (rt_db_get_internal(&old_intern, old_dp, gedp->ged_wdbp->dbip, bn_mat_identity, &rt_uniresource) < 0) { bu_vls_printf(gedp->ged_result_str, "rt_db_get_internal() error\n"); return GED_ERROR; } if (old_intern.idb_type != ID_NMG) { bu_vls_printf(gedp->ged_result_str, "Object is not an NMG!!!\n"); return GED_ERROR; } m = (struct model *)old_intern.idb_ptr; NMG_CK_MODEL(m); for (BU_LIST_FOR(r, nmgregion, &m->r_hd)) { for (BU_LIST_FOR(s, shell, &r->s_hd)) { s_tmp = nmg_dup_shell(s, &trans_tbl, &gedp->ged_wdbp->wdb_tol); bu_free((void *)trans_tbl, "trans_tbl"); m_tmp = nmg_mmr(); r_tmp = BU_LIST_FIRST(nmgregion, &m_tmp->r_hd); BU_LIST_DEQUEUE(&s_tmp->l); BU_LIST_APPEND(&r_tmp->s_hd, &s_tmp->l); s_tmp->r_p = r_tmp; nmg_m_reindex(m_tmp, 0); nmg_m_reindex(m, 0); bu_vls_printf(&shell_name, "shell.%d", shell_count); while (db_lookup(gedp->ged_wdbp->dbip, bu_vls_addr(&shell_name), 0) != RT_DIR_NULL) { bu_vls_trunc(&shell_name, 0); shell_count++; bu_vls_printf(&shell_name, "shell.%d", shell_count); } /* Export NMG as a new solid */ RT_DB_INTERNAL_INIT(&new_intern); new_intern.idb_major_type = DB5_MAJORTYPE_BRLCAD; new_intern.idb_type = ID_NMG; new_intern.idb_meth = &OBJ[ID_NMG]; new_intern.idb_ptr = (void *)m_tmp; new_dp=db_diradd(gedp->ged_wdbp->dbip, bu_vls_addr(&shell_name), RT_DIR_PHONY_ADDR, 0, RT_DIR_SOLID, (void *)&new_intern.idb_type); if (new_dp == RT_DIR_NULL) { bu_vls_printf(gedp->ged_result_str, "An error has occurred while adding a new object to the database.\n"); return GED_ERROR; } /* make sure the geometry/bounding boxes are up to date */ nmg_rebound(m_tmp, &gedp->ged_wdbp->wdb_tol); if (rt_db_put_internal(new_dp, gedp->ged_wdbp->dbip, &new_intern, &rt_uniresource) < 0) { /* Free memory */ nmg_km(m_tmp); bu_vls_printf(gedp->ged_result_str, "rt_db_put_internal() failure\n"); return GED_ERROR; } /* Internal representation has been freed by rt_db_put_internal */ new_intern.idb_ptr = (void *)NULL; } } bu_vls_free(&shell_name); 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; }