/** * recursively copy a tree of geometry */ static struct directory * copy_tree(struct db_i *_dbip, struct directory *dp, struct resource *resp, struct clone_state *state) { size_t i; union record *rp = (union record *)NULL; struct directory *mdp = (struct directory *)NULL; struct directory *copy = (struct directory *)NULL; struct bu_vls *copyname = NULL; struct bu_vls *nextname = NULL; /* get the name of what the object "should" get cloned to */ copyname = get_name(_dbip, dp, state, 0); /* copy the object */ if (dp->d_flags & RT_DIR_COMB) { if (db_version(_dbip) < 5) { /* A v4 method of peeking into a combination */ int errors = 0; /* get an in-memory record of this object */ if ((rp = db_getmrec(_dbip, dp)) == (union record *)0) { TCL_READ_ERR; goto done_copy_tree; } /* * if it is a combination/region, copy the objects that * make up the object. */ for (i = 1; i < dp->d_len; i++) { if ((mdp = db_lookup(_dbip, rp[i].M.m_instname, LOOKUP_NOISY)) == RT_DIR_NULL) { errors++; bu_log("WARNING: failed to locate \"%s\"\n", rp[i].M.m_instname); continue; } copy = copy_tree(_dbip, mdp, resp, state); if (!copy) { errors++; bu_log("WARNING: unable to fully clone \"%s\"\n", rp[i].M.m_instname); } } if (errors) { bu_log("WARNING: some elements of \"%s\" could not be cloned\n", dp->d_namep); } /* copy this combination itself */ copy_comb(_dbip, dp, (genptr_t)state); } else /* A v5 method of peeking into a combination */ db_functree(_dbip, dp, copy_comb, copy_solid, resp, (genptr_t)state); } else if (dp->d_flags & RT_DIR_SOLID) /* leaf node -- make a copy the object */ copy_solid(_dbip, dp, (genptr_t)state); else { Tcl_AppendResult(state->interp, "clone: ", dp->d_namep, " is neither a combination or a primitive?\n", (char *)NULL); goto done_copy_tree; } nextname = get_name(_dbip, dp, state, 0); if (bu_vls_strcmp(copyname, nextname) == 0) bu_log("ERROR: unable to successfully clone \"%s\" to \"%s\"\n", dp->d_namep, bu_vls_addr(copyname)); else copy = db_lookup(_dbip, bu_vls_addr(copyname), LOOKUP_QUIET); done_copy_tree: if (rp) bu_free((char *)rp, "copy_tree record[]"); if (copyname) bu_free((char *)copyname, "free get_name() copyname"); if (nextname) bu_free((char *)nextname, "free get_name() copyname"); return copy; }
/** * 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; }
/* * This subroutine is called for a no-frills tree-walk, * with the provided subroutines being called when entering and * exiting combinations and at leaf (solid) nodes. * * This routine is recursive, so no variables may be declared static. * */ void db_preorder_traverse(struct directory *dp, struct db_traverse *dtp) { register size_t i; RT_CK_DB_TRAVERSE(dtp); RT_CK_DBI(dtp->dbip); if (dtp->resp) { RT_CK_RESOURCE(dtp->resp); } if (RT_G_DEBUG & DEBUG_DB) bu_log("db_preorder_traverse(%s) %p, %p, comb_enter=%lx, comb_exit=%lx, leaf=%lx, client_data=%p\n", dp->d_namep, (void *)dtp->dbip, (void *)dp, (long unsigned int)dtp->comb_enter_func, (long unsigned int)dtp->comb_exit_func, (long unsigned int)dtp->leaf_func, dtp->client_data); if (dp->d_flags & RT_DIR_COMB) { /* entering region */ if (dtp->comb_enter_func) dtp->comb_enter_func(dtp->dbip, dp, dtp->client_data); if (db_version(dtp->dbip) < 5) { register union record *rp; register struct directory *mdp; /* * Load the combination into local record buffer * This is in external v4 format. */ if ((rp = db_getmrec(dtp->dbip, dp)) == (union record *)0) return; /* recurse */ for (i=1; i < dp->d_len; i++) { if ((mdp = db_lookup(dtp->dbip, rp[i].M.m_instname, LOOKUP_NOISY)) == RT_DIR_NULL) continue; db_preorder_traverse(mdp, dtp); } bu_free((char *)rp, "db_preorder_traverse[]"); } else { struct rt_db_internal in; struct rt_comb_internal *comb; if (rt_db_get_internal5(&in, dp, dtp->dbip, NULL, dtp->resp) < 0) return; comb = (struct rt_comb_internal *)in.idb_ptr; db_traverse_subtree(comb->tree, db_preorder_traverse, dtp); rt_db_free_internal(&in); } /* exiting region */ if (dtp->comb_exit_func) dtp->comb_exit_func(dtp->dbip, dp, dtp->client_data); } else if (dp->d_flags & RT_DIR_SOLID || dp->d_major_type & DB5_MAJORTYPE_BINARY_MASK) { /* at leaf */ if (dtp->leaf_func) dtp->leaf_func(dtp->dbip, dp, dtp->client_data); } else { bu_log("db_preorder_traverse: %s is neither COMB nor SOLID?\n", dp->d_namep); } }
/** * 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; }
void db_functree(struct db_i *dbip, struct directory *dp, void (*comb_func) (struct db_i *, struct directory *, void *), void (*leaf_func) (struct db_i *, struct directory *, void *), struct resource *resp, void *client_data) { register size_t i; RT_CK_DBI(dbip); if (resp) { RT_CK_RESOURCE(resp); } if ((!dp) || (!comb_func && !leaf_func)) { return; /* nothing to do */ } if (RT_G_DEBUG&DEBUG_DB) { bu_log("db_functree(%s) %p, %p, comb=%lx, leaf=%lx, client_data=%p\n", dp->d_namep, (void *)dbip, (void *)dp, (long unsigned int)comb_func, (long unsigned int)leaf_func, client_data); } if (dp->d_flags & RT_DIR_COMB) { if (db_version(dbip) < 5) { register union record *rp; register struct directory *mdp; /* * Load the combination into local record buffer * This is in external v4 format. */ if ((rp = db_getmrec(dbip, dp)) == (union record *)0) return; /* recurse */ for (i=1; i < dp->d_len; i++) { if ((mdp = db_lookup(dbip, rp[i].M.m_instname, LOOKUP_NOISY)) == RT_DIR_NULL) continue; db_functree(dbip, mdp, comb_func, leaf_func, resp, client_data); } bu_free((char *)rp, "db_functree record[]"); } else { struct rt_db_internal in; struct rt_comb_internal *comb; if (rt_db_get_internal5(&in, dp, dbip, NULL, resp) < 0) return; comb = (struct rt_comb_internal *)in.idb_ptr; db_functree_subtree(dbip, comb->tree, comb_func, leaf_func, resp, client_data); rt_db_free_internal(&in); } /* Finally, the combination itself */ if (comb_func) comb_func(dbip, dp, client_data); } else if (dp->d_flags & RT_DIR_SOLID || dp->d_major_type & DB5_MAJORTYPE_BINARY_MASK) { if (leaf_func) leaf_func(dbip, dp, client_data); } else { bu_log("db_functree: %s is neither COMB nor SOLID?\n", dp->d_namep); } }