int get_de_pointers(union tree *tp, struct directory *dp, int de_len, int *de_pointers) { RT_CK_TREE(tp); RT_CK_DIR(dp); switch (tp->tr_op) { case OP_UNION: case OP_SUBTRACT: case OP_INTERSECT: get_de_pointers(tp->tr_b.tb_left, dp, de_len, de_pointers); get_de_pointers(tp->tr_b.tb_right, dp, de_len, de_pointers); break; case OP_DB_LEAF: { struct directory *dp_M; dp_M = db_lookup(DBIP, tp->tr_l.tl_name, LOOKUP_NOISY); if (dp_M == RT_DIR_NULL) return 1; if (dp_M->d_uses >= 0) { bu_log("g-iges: member (%s) in combination (%s) has not been written to iges file\n", dp_M->d_namep, dp->d_namep); de_pointers[de_pointer_number++] = 0; return 1; } if (tp->tr_l.tl_mat && !bn_mat_is_identity(tp->tr_l.tl_mat)) { /* write a solid instance entity for this member with a pointer to the new matrix */ if (!NEAR_ZERO(tp->tr_l.tl_mat[15] - 1.0, tol.dist)) { /* scale factor is not 1.0, IGES can't handle it. go ahead and write the solid instance anyway, but warn the user twice */ bu_log("g-iges WARNING: member (%s) of combination (%s) is scaled, IGES cannot handle this\n", dp_M->d_namep, dp->d_namep); scale_error++; } de_pointers[de_pointer_number++] = write_solid_instance(-dp_M->d_uses, tp->tr_l.tl_mat, fp_dir, fp_param); } else de_pointers[de_pointer_number++] = (-dp_M->d_uses); if (dp_M->d_nref) comb_form = 1; } break; default: bu_log("Unrecognized operator in combination!\n"); return 1; } return 0; }
/** * D B _ T R E E _ C O U N T E R * * Count number of non-identity matrices, number of leaf nodes, * number of operator nodes, etc. * * Returns - maximum depth of stack needed to unpack this tree, if * serialized. * * Notes - We over-estimate the size of the width fields used for * holding the matrix subscripts. The caller is responsible for * correcting by saying: * * tcsp->leafbytes -= tcsp->n_leaf * (8 - db5_enc_len[wid]); */ size_t db_tree_counter(const union tree *tp, struct db_tree_counter_state *tcsp) { size_t ldepth, rdepth; RT_CK_TREE(tp); DB_CK_TREE_COUNTER_STATE(tcsp); switch (tp->tr_op) { case OP_DB_LEAF: tcsp->n_leaf++; if (tp->tr_l.tl_mat && !bn_mat_is_identity(tp->tr_l.tl_mat)) tcsp->n_mat++; /* Over-estimate storage requirement for matrix # */ tcsp->leafbytes += strlen(tp->tr_l.tl_name) + 1 + 8; return 1; case OP_NOT: /* Unary ops */ tcsp->n_oper++; tcsp->non_union_seen = 1; return 1 + db_tree_counter(tp->tr_b.tb_left, tcsp); case OP_UNION: /* This node is known to be a binary op */ tcsp->n_oper++; ldepth = db_tree_counter(tp->tr_b.tb_left, tcsp); rdepth = db_tree_counter(tp->tr_b.tb_right, tcsp); if (ldepth > rdepth) return ldepth; return rdepth; case OP_INTERSECT: case OP_SUBTRACT: case OP_XOR: /* This node is known to be a binary op */ tcsp->n_oper++; tcsp->non_union_seen = 1; ldepth = db_tree_counter(tp->tr_b.tb_left, tcsp); rdepth = db_tree_counter(tp->tr_b.tb_right, tcsp); if (ldepth > rdepth) return ldepth; return rdepth; default: bu_log("db_tree_counter: bad op %d\n", tp->tr_op); bu_bomb("db_tree_counter\n"); /* NOTREACHED */ } /* NOTREACHED */ return 0; }
static int test_bn_mat_is_identity(int argc, char *argv[]) { mat_t m; int expected; if (argc != 4) { bu_exit(1, "<args> format: M <expected_result> [%s]\n", argv[0]); } scan_mat_args(argv, 2, &m); sscanf(argv[3], "%d", &expected); return !(bn_mat_is_identity(m) == expected); }
/** * When performing "ev" on a region, consider whether to process the * whole subtree recursively. * * Normally, say "yes" to all regions by returning 0. * * Check for special case: a region of one solid, which can be * directly drawn as polygons without going through NMGs. If we draw * it here, then return -1 to signal caller to ignore further * processing of this region. A hack to view polygonal models * (converted from FASTGEN) more rapidly. */ static int draw_nmg_region_start(struct db_tree_state *tsp, const struct db_full_path *pathp, const struct rt_comb_internal *combp, void *client_data) { union tree *tp; struct directory *dp; struct rt_db_internal intern; mat_t xform; matp_t matp; struct bu_list vhead; struct _ged_client_data *dgcdp = (struct _ged_client_data *)client_data; if (RT_G_DEBUG&DEBUG_TREEWALK) { char *sofar = db_path_to_string(pathp); bu_vls_printf(dgcdp->gedp->ged_result_str, "nmg_region_start(%s)\n", sofar); bu_free((void *)sofar, "path string"); rt_pr_tree(combp->tree, 1); db_pr_tree_state(tsp); } RT_CK_DBI(tsp->ts_dbip); RT_CK_RESOURCE(tsp->ts_resp); BU_LIST_INIT(&vhead); RT_CK_COMB(combp); tp = combp->tree; if (!tp) return -1; RT_CK_TREE(tp); if (tp->tr_l.tl_op != OP_DB_LEAF) return 0; /* proceed as usual */ /* The subtree is a single node. It may be a combination, though */ /* Fetch by name, check to see if it's an easy type */ dp = db_lookup(tsp->ts_dbip, tp->tr_l.tl_name, LOOKUP_NOISY); if (!dp) return 0; /* proceed as usual */ if (!bn_mat_is_identity(tsp->ts_mat)) { if (tp->tr_l.tl_mat) { matp = xform; bn_mat_mul(xform, tsp->ts_mat, tp->tr_l.tl_mat); } else { matp = tsp->ts_mat; } } else { if (tp->tr_l.tl_mat) { matp = tp->tr_l.tl_mat; } else { matp = (matp_t)NULL; } } if (rt_db_get_internal(&intern, dp, tsp->ts_dbip, matp, &rt_uniresource) < 0) return 0; /* proceed as usual */ switch (intern.idb_type) { case ID_POLY: { if (RT_G_DEBUG&DEBUG_TREEWALK) { bu_log("fastpath draw ID_POLY %s\n", dp->d_namep); } if (dgcdp->draw_wireframes) { (void)rt_pg_plot(&vhead, &intern, tsp->ts_ttol, tsp->ts_tol, NULL); } else { (void)rt_pg_plot_poly(&vhead, &intern, tsp->ts_ttol, tsp->ts_tol); } } goto out; case ID_BOT: { if (RT_G_DEBUG&DEBUG_TREEWALK) { bu_log("fastpath draw ID_BOT %s\n", dp->d_namep); } if (dgcdp->draw_wireframes) { (void)rt_bot_plot(&vhead, &intern, tsp->ts_ttol, tsp->ts_tol, NULL); } else { (void)rt_bot_plot_poly(&vhead, &intern, tsp->ts_ttol, tsp->ts_tol); } } goto out; case ID_BREP: { if (RT_G_DEBUG&DEBUG_TREEWALK) { bu_log("fastpath draw ID_BREP %s\n", dp->d_namep); } if (dgcdp->draw_wireframes) { (void)rt_brep_plot(&vhead, &intern, tsp->ts_ttol, tsp->ts_tol, NULL); } else { (void)rt_brep_plot_poly(&vhead, pathp, &intern, tsp->ts_ttol, tsp->ts_tol, NULL); } } goto out; case ID_COMBINATION: default: break; } rt_db_free_internal(&intern); return 0; out: { struct db_full_path pp; db_full_path_init(&pp); db_dup_full_path(&pp, pathp); /* Successful fastpath drawing of this solid */ db_add_node_to_full_path(&pp, dp); _ged_drawH_part2(0, &vhead, &pp, tsp, dgcdp); db_free_full_path(&pp); } rt_db_free_internal(&intern); dgcdp->fastpath_count++; return -1; /* SKIP THIS REGION */ }
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; }
/** * Convert from "network" doubles to machine specific. * Transform */ int rt_arbn_import5(struct rt_db_internal *ip, const struct bu_external *ep, const fastf_t *mat, const struct db_i *dbip) { struct rt_arbn_internal *aip; size_t i; unsigned long neqn; int double_count; size_t byte_count; /* must be double for import and export */ double *eqn; RT_CK_DB_INTERNAL(ip); BU_CK_EXTERNAL(ep); if (dbip) RT_CK_DBI(dbip); neqn = ntohl(*(uint32_t *)ep->ext_buf); double_count = neqn * ELEMENTS_PER_PLANE; byte_count = double_count * SIZEOF_NETWORK_DOUBLE; BU_ASSERT_LONG(ep->ext_nbytes, ==, 4+ byte_count); ip->idb_major_type = DB5_MAJORTYPE_BRLCAD; ip->idb_type = ID_ARBN; ip->idb_meth = &OBJ[ID_ARBN]; BU_ALLOC(ip->idb_ptr, struct rt_arbn_internal); aip = (struct rt_arbn_internal *)ip->idb_ptr; aip->magic = RT_ARBN_INTERNAL_MAGIC; aip->neqn = neqn; if (aip->neqn <= 0) return -1; eqn = (double *)bu_malloc(byte_count, "arbn plane eqn[] temp buf"); bu_cv_ntohd((unsigned char *)eqn, (unsigned char *)ep->ext_buf + ELEMENTS_PER_PLANE, double_count); aip->eqn = (plane_t *)bu_malloc(double_count * sizeof(fastf_t), "arbn plane eqn[]"); for (i = 0; i < aip->neqn; i++) { HMOVE(aip->eqn[i], &eqn[i*ELEMENTS_PER_PLANE]); } bu_free(eqn, "arbn plane eqn[] temp buf"); /* Transform by the matrix, if we have one that is not the identity */ if (mat && !bn_mat_is_identity(mat)) { for (i = 0; i < aip->neqn; i++) { point_t orig_pt; point_t pt; vect_t norm; fastf_t factor; /* unitize the plane equation first */ factor = 1.0 / MAGNITUDE(aip->eqn[i]); VSCALE(aip->eqn[i], aip->eqn[i], factor); aip->eqn[i][W] = aip->eqn[i][W] * factor; /* Pick a point on the original halfspace */ VSCALE(orig_pt, aip->eqn[i], aip->eqn[i][W]); /* Transform the point, and the normal */ MAT4X3VEC(norm, mat, aip->eqn[i]); MAT4X3PNT(pt, mat, orig_pt); /* Measure new distance from origin to new point */ VUNITIZE(norm); VMOVE(aip->eqn[i], norm); aip->eqn[i][W] = VDOT(pt, norm); } } return 0; }
int rt_comb_import4( struct rt_db_internal *ip, const struct bu_external *ep, const mat_t matrix, /* NULL if identity */ const struct db_i *dbip, struct resource *resp) { union record *rp; struct rt_tree_array *rt_tree_array; union tree *tree; struct rt_comb_internal *comb; size_t j; size_t node_count; BU_CK_EXTERNAL(ep); rp = (union record *)ep->ext_buf; if (dbip) RT_CK_DBI(dbip); if (rp[0].u_id != ID_COMB) { bu_log("rt_comb_import4: Attempt to import a non-combination\n"); return -1; } /* Compute how many granules of MEMBER records follow */ node_count = ep->ext_nbytes/sizeof(union record) - 1; if (node_count) rt_tree_array = (struct rt_tree_array *)bu_calloc(node_count, sizeof(struct rt_tree_array), "rt_tree_array"); else rt_tree_array = (struct rt_tree_array *)NULL; for (j = 0; j < node_count; j++) { if (rp[j+1].u_id != ID_MEMB) { bu_free((void *)rt_tree_array, "rt_comb_import4: rt_tree_array"); bu_log("rt_comb_import4(): granule in external buffer is not ID_MEMB, id=%d\n", rp[j+1].u_id); return -1; } switch (rp[j+1].M.m_relation) { case '+': rt_tree_array[j].tl_op = OP_INTERSECT; break; case '-': rt_tree_array[j].tl_op = OP_SUBTRACT; break; default: bu_log("rt_comb_import4() unknown op=x%x, assuming UNION\n", rp[j+1].M.m_relation); /* Fall through */ case 'u': rt_tree_array[j].tl_op = OP_UNION; break; } /* Build leaf node for in-memory tree */ { union tree *tp; mat_t diskmat; char namebuf[NAMESIZE+1]; RT_GET_TREE(tp, resp); rt_tree_array[j].tl_tree = tp; tp->tr_l.tl_op = OP_DB_LEAF; /* bu_strlcpy not safe here, buffer size mismatch */ memset(namebuf, 0, NAMESIZE+1); memcpy(namebuf, rp[j+1].M.m_instname, sizeof(rp[j+1].M.m_instname)); tp->tr_l.tl_name = bu_strdup(namebuf); flip_mat_dbmat(diskmat, rp[j+1].M.m_mat, dbip->dbi_version < 0 ? 1 : 0); /* Verify that rotation part is pure rotation */ if (fabs(diskmat[0]) > 1 || fabs(diskmat[1]) > 1 || fabs(diskmat[2]) > 1 || fabs(diskmat[4]) > 1 || fabs(diskmat[5]) > 1 || fabs(diskmat[6]) > 1 || fabs(diskmat[8]) > 1 || fabs(diskmat[9]) > 1 || fabs(diskmat[10]) > 1) { bu_log("ERROR: %s/%s improper scaling, rotation matrix elements > 1\n", rp[0].c.c_name, namebuf); } /* Verify that perspective isn't used as a modeling transform */ if (!ZERO(diskmat[12]) || !ZERO(diskmat[13]) || !ZERO(diskmat[14])) { bu_log("ERROR: %s/%s has perspective transform\n", rp[0].c.c_name, namebuf); } /* See if disk record is identity matrix */ if (bn_mat_is_identity(diskmat)) { if (matrix == NULL) { tp->tr_l.tl_mat = NULL; /* identity */ } else { tp->tr_l.tl_mat = bn_mat_dup(matrix); } } else { if (matrix == NULL) { tp->tr_l.tl_mat = bn_mat_dup(diskmat); } else { mat_t prod; bn_mat_mul(prod, matrix, diskmat); tp->tr_l.tl_mat = bn_mat_dup(prod); } } /* bu_log("M_name=%s, matp=x%x\n", tp->tr_l.tl_name, tp->tr_l.tl_mat); */ } } if (node_count) tree = db_mkgift_tree(rt_tree_array, node_count, &rt_uniresource); else tree = (union tree *)NULL; RT_DB_INTERNAL_INIT(ip); ip->idb_major_type = DB5_MAJORTYPE_BRLCAD; ip->idb_type = ID_COMBINATION; ip->idb_meth = &OBJ[ID_COMBINATION]; BU_ALLOC(comb, struct rt_comb_internal); RT_COMB_INTERNAL_INIT(comb); comb->tree = tree; ip->idb_ptr = (void *)comb; switch (rp[0].c.c_flags) { case DBV4_NON_REGION_NULL: case DBV4_NON_REGION: comb->region_flag = 0; break; case DBV4_REGION: comb->region_flag = 1; comb->is_fastgen = REGION_NON_FASTGEN; break; case DBV4_REGION_FASTGEN_PLATE: comb->region_flag = 1; comb->is_fastgen = REGION_FASTGEN_PLATE; break; case DBV4_REGION_FASTGEN_VOLUME: comb->region_flag = 1; comb->is_fastgen = REGION_FASTGEN_VOLUME; break; default: bu_log("WARNING: combination %s has illegal c_flag=x%x\n", rp[0].c.c_name, rp[0].c.c_flags); break; } if (comb->region_flag) { if (dbip->dbi_version < 0) { comb->region_id = flip_short(rp[0].c.c_regionid); comb->aircode = flip_short(rp[0].c.c_aircode); comb->GIFTmater = flip_short(rp[0].c.c_material); comb->los = flip_short(rp[0].c.c_los); } else { comb->region_id = rp[0].c.c_regionid; comb->aircode = rp[0].c.c_aircode; comb->GIFTmater = rp[0].c.c_material; comb->los = rp[0].c.c_los; } } else { /* set some reasonable defaults */ comb->region_id = 0; comb->aircode = 0; comb->GIFTmater = 0; comb->los = 0; } comb->rgb_valid = rp[0].c.c_override; if (comb->rgb_valid) { comb->rgb[0] = rp[0].c.c_rgb[0]; comb->rgb[1] = rp[0].c.c_rgb[1]; comb->rgb[2] = rp[0].c.c_rgb[2]; } if (rp[0].c.c_matname[0] != '\0') { #define MAX_SS 128 char shader_str[MAX_SS]; memset(shader_str, 0, MAX_SS); /* copy shader info to a static string */ /* write shader name. c_matname is a buffer, bu_strlcpy not * safe here. */ memcpy(shader_str, rp[0].c.c_matname, sizeof(rp[0].c.c_matname)); bu_strlcat(shader_str, " ", MAX_SS); /* write shader parameters. c_matparm is a buffer, bu_strlcpy * not safe here. */ memcpy(shader_str+strlen(shader_str), rp[0].c.c_matparm, sizeof(rp[0].c.c_matparm)); /* convert to TCL format and place into comb->shader */ if (bu_shader_to_list(shader_str, &comb->shader)) { bu_log("rt_comb_import4: Error: Cannot convert following shader to TCL format:\n"); bu_log("\t%s\n", shader_str); bu_vls_free(&comb->shader); return -1; } } /* XXX Separate flags for color inherit, shader inherit, (new) material inherit? */ /* XXX cf: ma_cinherit, ma_minherit */ /* This ? is necessary to clean up old databases with grunge here */ comb->inherit = (rp[0].c.c_inherit == DB_INH_HIGHER) ? 1 : 0; /* Automatic material table lookup here? */ if (comb->region_flag) bu_vls_printf(&comb->material, "gift%ld", comb->GIFTmater); if (rt_tree_array) bu_free((void *)rt_tree_array, "rt_tree_array"); return 0; }