struct rt_bot_internal * dup_bot( struct rt_bot_internal *bot_in ) { struct rt_bot_internal *bot; size_t i; RT_BOT_CK_MAGIC( bot_in ); BU_ALLOC(bot, struct rt_bot_internal); *bot = *bot_in; /* struct copy */ bot->faces = (int *)bu_calloc( bot_in->num_faces*3, sizeof( int ), "bot faces" ); for ( i=0; i<bot_in->num_faces*3; i++ ) bot->faces[i] = bot_in->faces[i]; bot->vertices = (fastf_t *)bu_calloc( bot_in->num_vertices*3, sizeof( fastf_t ), "bot verts" ); for ( i=0; i<bot_in->num_vertices*3; i++ ) bot->vertices[i] = bot_in->vertices[i]; if ( bot_in->thickness ) { bot->thickness = (fastf_t *)bu_calloc( bot_in->num_faces, sizeof( fastf_t ), "bot thickness" ); for ( i=0; i<bot_in->num_faces; i++ ) bot->thickness[i] = bot_in->thickness[i]; } if ( bot_in->face_mode ) { bot->face_mode = bu_bitv_dup( bot_in->face_mode ); } return bot; }
/* CSG objects are skipped. BOTs are processed but stored outside * tree. This leaf-tess function is used when we want to output * BOTs directly to the VRML file without performing a boolean * evaluation. */ union tree * leaf_tess2(struct db_tree_state *UNUSED(tsp), const struct db_full_path *UNUSED(pathp), struct rt_db_internal *ip, void *client_data) { struct rt_bot_internal *bot; struct plate_mode *pmp = (struct plate_mode *)client_data; if (ip->idb_type != ID_BOT) { return (union tree *)NULL; } bot = (struct rt_bot_internal *)ip->idb_ptr; RT_BOT_CK_MAGIC(bot); if (pmp->array_size <= pmp->num_bots) { struct rt_bot_internal **bots_tmp; pmp->array_size += 5; bots_tmp = (struct rt_bot_internal **)bu_realloc((void *)pmp->bots, pmp->array_size * sizeof(struct rt_bot_internal *), "pmp->bots"); pmp->bots = bots_tmp; } /* walk tree will free the bot, so we need a copy */ pmp->bots[pmp->num_bots] = dup_bot(bot); pmp->num_bots++; return (union tree *)NULL; }
/* duplicate bot */ struct rt_bot_internal * dup_bot(struct rt_bot_internal *bot_in) { struct rt_bot_internal *bot; size_t i; RT_BOT_CK_MAGIC(bot_in); BU_ALLOC(bot, struct rt_bot_internal); bot->magic = bot_in->magic; bot->mode = bot_in->mode; bot->orientation = bot_in->orientation; bot->bot_flags = bot_in->bot_flags; bot->num_vertices = bot_in->num_vertices; bot->num_faces = bot_in->num_faces; bot->num_normals = bot_in->num_normals; bot->num_face_normals = bot_in->num_face_normals; bot->faces = (int *)bu_calloc(bot_in->num_faces * 3, sizeof(int), "bot faces"); for (i = 0; i < bot_in->num_faces * 3; i++) { bot->faces[i] = bot_in->faces[i]; } bot->vertices = (fastf_t *)bu_calloc(bot_in->num_vertices * 3, sizeof(fastf_t), "bot verts"); for (i = 0; i < bot_in->num_vertices * 3; i++) { bot->vertices[i] = bot_in->vertices[i]; } if ((bot_in->bot_flags & RT_BOT_PLATE) || (bot_in->bot_flags & RT_BOT_PLATE_NOCOS)) { if (bot_in->thickness) { bot->thickness = (fastf_t *)bu_calloc(bot_in->num_faces, sizeof(fastf_t), "bot thickness"); for (i = 0; i < bot_in->num_faces; i++) { bot->thickness[i] = bot_in->thickness[i]; } } else { bu_bomb("dup_bot(): flag should not say plate but thickness is null\n"); } } if (bot_in->face_mode) { bot->face_mode = bu_bitv_dup(bot_in->face_mode); } if (bot_in->bot_flags & RT_BOT_HAS_SURFACE_NORMALS) { bot->num_normals = bot_in->num_normals; bot->normals = (fastf_t *)bu_calloc(bot_in->num_normals * 3, sizeof(fastf_t), "BOT normals"); bot->face_normals = (int *)bu_calloc(bot_in->num_faces * 3, sizeof(int), "BOT face normals"); memcpy(bot->face_normals, bot_in->face_normals, bot_in->num_faces * 3 * sizeof(int)); } return bot; }
/** * L E A F _ F U N C * * @brief Function to process a leaf node. * * This is actually invoked from db_recurse() from db_walk_subtree(). * * @return (union tree *) representing the leaf, or * TREE_NULL if leaf does not exist or has an error. */ union tree * leaf_func (struct db_tree_state *UNUSED(tsp), const struct db_full_path *pathp, struct rt_db_internal *internp, genptr_t UNUSED(client_data)) { /* the rt_db_internal structure is used to manage the payload of * "internal" or "in memory" representation of geometry as opposed * to different the "on-disk" serialized "external" version. */ struct rt_db_internal *ip = internp; /* only set for commenting purposes */ if (debug&DEBUG_NAMES) { char *name = db_path_to_string(pathp); bu_log("leaf_func %s\n", name); bu_free(name, "region_end name"); } /* here we do primitive type specific processing */ switch (ip->idb_minor_type) { case ID_BOT: { /* This is the data payload for a "Bag of Triangles" or * "BOT" primitive. see rtgeom.h for more information * about primitive solid specific data structures. */ struct rt_bot_internal *bot = (struct rt_bot_internal *)ip->idb_ptr; RT_BOT_CK_MAGIC(bot); /* check for data corruption */ /* code to process bot goes here */ break; } case ID_ARB8: { struct rt_arb_internal *arb = (struct rt_arb_internal *)ip->idb_ptr; RT_ARB_CK_MAGIC(arb); /* code to process arb goes here */ break; } /* * Note: A complete program would process each possible type of object here, * not just a couple of primitive types */ } return (union tree *)NULL; }
int ged_bot_condense(struct ged *gedp, int argc, const char *argv[]) { struct directory *old_dp, *new_dp; struct rt_db_internal intern; struct rt_bot_internal *bot; int count2=0; static const char *usage = "new_bot old_bot"; 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; } GED_DB_LOOKUP(gedp, old_dp, argv[2], 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[2]); return GED_ERROR; } bot = (struct rt_bot_internal *)intern.idb_ptr; RT_BOT_CK_MAGIC(bot); count2 = rt_bot_condense(bot); bu_vls_printf(gedp->ged_result_str, "%s: %d dead vertices eliminated\n", argv[0], count2); GED_DB_DIRADD(gedp, new_dp, argv[1], RT_DIR_PHONY_ADDR, 0, RT_DIR_SOLID, (void *)&intern.idb_type, GED_ERROR); GED_DB_PUT_INTERNAL(gedp, new_dp, &intern, &rt_uniresource, GED_ERROR); return GED_OK; }
union tree * leaf_tess(struct db_tree_state *tsp, const struct db_full_path *pathp, struct rt_db_internal *ip, void *client_data) { struct rt_bot_internal *bot; struct plate_mode *pmp = (struct plate_mode *)client_data; BARRIER_CHECK; if ( ip->idb_type != ID_BOT ) { pmp->num_nonbots++; return nmg_booltree_leaf_tess(tsp, pathp, ip, client_data); } bot = (struct rt_bot_internal *)ip->idb_ptr; RT_BOT_CK_MAGIC( bot ); if ( bot->mode == RT_BOT_PLATE || bot->mode == RT_BOT_SURFACE ) { if ( pmp->array_size <= pmp->num_bots ) { pmp->array_size += 5; pmp->bots = (struct rt_bot_internal **)bu_realloc( (char *)pmp->bots, pmp->array_size * sizeof( struct rt_bot_internal *), "pmp->bots" ); } /* walk tree will free the BOT, so we need a copy */ pmp->bots[pmp->num_bots] = dup_bot( bot ); BARRIER_CHECK; pmp->num_bots++; return (union tree *)NULL; } pmp->num_nonbots++; BARRIER_CHECK; return nmg_booltree_leaf_tess(tsp, pathp, ip, client_data); }
struct soup_s * bot2soup(struct rt_bot_internal *bot, const struct bn_tol *tol) { struct soup_s *s; unsigned long int i; RT_BOT_CK_MAGIC(bot); if (bot->orientation != RT_BOT_CCW) bu_bomb("Bad orientation out of nmg_bot\n"); BU_ALLOC(s, struct soup_s); s->magic = SOUP_MAGIC; s->nfaces = 0; s->maxfaces = ceil(bot->num_faces / (double)faces_per_page) * faces_per_page; s->faces = (struct face_s *)bu_malloc(sizeof(struct face_s) * s->maxfaces, "bot soup faces"); for (i=0;i<bot->num_faces;i++) soup_add_face(s, bot->vertices+3*bot->faces[i*3+0], bot->vertices+3*bot->faces[i*3+1], bot->vertices+3*bot->faces[i*3+2], tol); return s; }
int ged_bot(struct ged *gedp, int argc, const char *argv[]) { struct directory *bot_dp; struct rt_db_internal intern; struct rt_bot_internal *bot; const char *cmd = argv[0]; const char *sub = NULL; const char *arg = NULL; const char *primitive = NULL; size_t len; fastf_t tmp; fastf_t propVal; static const char *usage = "get (faces|minEdge|maxEdge|orientation|type|vertices) bot\nchull bot_in bot_out\n"; 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) { bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", cmd, usage); return GED_ERROR; } /* determine subcommand */ sub = argv[1]; len = strlen(sub); if (bu_strncmp(sub, "get", len) == 0) { primitive = argv[argc - 1]; } if (bu_strncmp(sub, "chull", len) == 0) { primitive = argv[2]; } if (primitive == NULL) { bu_vls_printf(gedp->ged_result_str, "%s: %s is not a known subcommand!", cmd, sub); return GED_ERROR; } /* get bot */ GED_DB_LOOKUP(gedp, bot_dp, primitive, LOOKUP_NOISY, GED_ERROR & GED_QUIET); GED_DB_GET_INTERNAL(gedp, &intern, bot_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!", cmd, primitive); return GED_ERROR; } bot = (struct rt_bot_internal *)intern.idb_ptr; RT_BOT_CK_MAGIC(bot); if (bu_strncmp(sub, "get", len) == 0) { arg = argv[2]; propVal = rt_bot_propget(bot, arg); /* print result string */ if (!EQUAL(propVal, -1.0)) { tmp = (int) propVal; /* int result */ if (EQUAL(propVal, tmp)) { bu_vls_printf(gedp->ged_result_str, "%d", (int) propVal); } /* float result */ else { bu_vls_printf(gedp->ged_result_str, "%f", propVal); } } else { bu_vls_printf(gedp->ged_result_str, "%s: %s is not a valid argument!", sub, arg); return GED_ERROR; } } if (bu_strncmp(sub, "chull", len) == 0) { int retval = 0; int fc = 0; int vc = 0; point_t *vert_array; int *faces; unsigned char err = 0; /* must be wanting help */ if (argc < 4) { bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", cmd, usage); return GED_ERROR; } retval = bg_3d_chull(&faces, &fc, &vert_array, &vc, (const point_t *)bot->vertices, (int)bot->num_vertices); if (retval != 3) return GED_ERROR; retval = mk_bot(gedp->ged_wdbp, argv[3], RT_BOT_SOLID, RT_BOT_CCW, err, vc, fc, (fastf_t *)vert_array, faces, NULL, NULL); if (retval) return GED_ERROR; } return GED_OK; }
int ged_bot_face_sort(struct ged *gedp, int argc, const char *argv[]) { int i; int tris_per_piece=0; static const char *usage = "triangles_per_piece bot_solid1 [bot_solid2 bot_solid3 ...]"; 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; } tris_per_piece = atoi(argv[1]); if (tris_per_piece < 1) { bu_vls_printf(gedp->ged_result_str, "Illegal value for triangle per piece (%s)\n", argv[1]); bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv[0], usage); return GED_ERROR; } for (i = 2; i < argc; i++) { struct directory *dp; struct rt_db_internal intern; struct rt_bot_internal *bot; if ((dp=db_lookup(gedp->ged_wdbp->dbip, argv[i], LOOKUP_NOISY)) == RT_DIR_NULL) { continue; } GED_DB_GET_INTERNAL(gedp, &intern, dp, bn_mat_identity, gedp->ged_wdbp->wdb_resp, GED_ERROR); if (intern.idb_major_type != DB5_MAJORTYPE_BRLCAD || intern.idb_minor_type != DB5_MINORTYPE_BRLCAD_BOT) { rt_db_free_internal(&intern); bu_vls_printf(gedp->ged_result_str, "%s is not a BOT primitive, skipped\n", dp->d_namep); continue; } bot = (struct rt_bot_internal *)intern.idb_ptr; RT_BOT_CK_MAGIC(bot); bu_log("processing %s (%zu triangles)\n", dp->d_namep, bot->num_faces); if (rt_bot_sort_faces(bot, tris_per_piece)) { rt_db_free_internal(&intern); bu_vls_printf(gedp->ged_result_str, "Face sort failed for %s, this BOT not sorted\n", dp->d_namep); continue; } GED_DB_PUT_INTERNAL(gedp, dp, &intern, gedp->ged_wdbp->wdb_resp, GED_ERROR); } return GED_OK; }
void bot2vrml( struct plate_mode *pmp, const struct db_full_path *pathp, int region_id ) { char *path_str; int appearance; struct rt_bot_internal *bot; int bot_num; size_t i; size_t vert_count=0; BARRIER_CHECK; path_str = db_path_to_string( pathp ); /* replace all occurrences of '.' with '_' */ char_replace(path_str, '.', '_'); fprintf( outfp, "\t<Shape DEF=\"%s\">\n", path_str); bu_free( path_str, "result of db_path_to_string" ); appearance = region_id / 1000; appearance = appearance * 1000 + 999; fprintf( outfp, "\t\t<Appearance USE=\"Material_%d\">\n", appearance); fprintf( outfp, "\t\t<IndexedFaceSet coordIndex=\"\n"); vert_count = 0; for ( bot_num = 0; bot_num < pmp->num_bots; bot_num++ ) { bot = pmp->bots[bot_num]; RT_BOT_CK_MAGIC( bot ); for ( i=0; i<bot->num_faces; i++ ) fprintf( outfp, "\t\t\t\t%lu, %lu, %lu, -1,\n", (long unsigned int)vert_count+bot->faces[i*3], (long unsigned int)vert_count+bot->faces[i*3+1], (long unsigned int)vert_count+bot->faces[i*3+2]); vert_count += bot->num_vertices; } /* close coordIndex */ fprintf( outfp, "\" "); fprintf( outfp, "normalPerVertex=\"false\" "); fprintf( outfp, "convex=\"true\" "); fprintf( outfp, "creaseAngle=\"0.5\" "); fprintf( outfp, "solid=\"false\" "); /* close IndexedFaceSet open tag */ fprintf( outfp, ">\n"); fprintf( outfp, "\t\t<Coordinate point=\""); for ( bot_num = 0; bot_num < pmp->num_bots; bot_num++ ) { bot = pmp->bots[bot_num]; RT_BOT_CK_MAGIC( bot ); for ( i=0; i<bot->num_vertices; i++ ) { point_t pt; VSCALE( pt, &bot->vertices[i*3], scale_factor ); fprintf( outfp, "%10.10e %10.10e %10.10e, ", V3ARGS( pt )); vert_count++; } } /* close point */ fprintf(outfp, "\""); /* close Coordinate */ fprintf(outfp, "/>\n"); /* IndexedFaceSet end tag */ fprintf( outfp, "\t\t</IndexedFaceSet>\n"); /* Shape end tag */ fprintf( outfp, "\t</Shape>\n"); BARRIER_CHECK; }
/********************************************************** * Code for identifying semi-flat patches in bots * and creating wireframe edges **********************************************************/ extern "C" int rt_bot_adaptive_plot(struct rt_db_internal *ip, const struct rt_view_info *info) { struct rt_bot_internal *bot; RT_CK_DB_INTERNAL(ip); BU_CK_LIST_HEAD(info->vhead); bot = (struct rt_bot_internal *)ip->idb_ptr; RT_BOT_CK_MAGIC(bot); vect_t gvects[6]; VSET(gvects[0], -1,0,0); VSET(gvects[1], 0,-1,0); VSET(gvects[2], 0,0,-1); VSET(gvects[3], 1,0,0); VSET(gvects[4], 0,1,0); VSET(gvects[5], 0,0,1); if (bot->num_vertices <= 0 || !bot->vertices || bot->num_faces <= 0 || !bot->faces) return 0; /* Declare key containers */ double *face_normals= (double *)bu_calloc(bot->num_faces * 3, sizeof(double), "normals"); /* Stash all the initial categorization test results - can be re-used later */ // unsigned int *categorization_results = (unsigned int *)bu_calloc(sizeof(unsigned int) * bot->num_faces * 6, "categorization results"); /* Initial group assignments */ unsigned int *groups = (unsigned int *)bu_calloc(bot->num_faces, sizeof(unsigned int), "groups"); /* Initially, patch breakdown is made in a faces -> patch_id map */ unsigned int *patches= (unsigned int *)bu_calloc(bot->num_faces, sizeof(unsigned int), "patch_id_numbers"); /* Don't know yet how big these needs to be */ unsigned int *vert_to_face = NULL; /* Sanity check vertex indices in face definitions */ for (unsigned int i = 0; i < bot->num_faces; ++i) { if ((unsigned int)bot->faces[i*3+0] > (unsigned int)(bot->num_vertices)) return 0; if ((unsigned int)bot->faces[i*3+1] > (unsigned int)(bot->num_vertices)) return 0; if ((unsigned int)bot->faces[i*3+2] > (unsigned int)(bot->num_vertices)) return 0; } /* Pre-compute face normals once */ for (unsigned int i = 0; i < bot->num_faces; i++) { vect_t a, b, norm_dir; VSUB2(a, &bot->vertices[bot->faces[i*3+1]*3], &bot->vertices[bot->faces[i*3]*3]); VSUB2(b, &bot->vertices[bot->faces[i*3+2]*3], &bot->vertices[bot->faces[i*3]*3]); VCROSS(norm_dir, a, b); VUNITIZE(norm_dir); face_normals[i*3]=norm_dir[0]; face_normals[i*3+1]=norm_dir[1]; face_normals[i*3+2]=norm_dir[2]; } /* Calculate categorization results and assign groups */ for (unsigned int i = 0; i < bot->num_faces; i++) { int result_max = 0; double result = 0.0; double vdot = 0.0; vect_t norm_dir; VSET(norm_dir, face_normals[i*3], face_normals[i*3+1], face_normals[i*3+2]); for (unsigned int j=0; j < 6; j++) { vdot = VDOT(gvects[j],norm_dir); //categorization_results[i*j] = vdot; if (vdot > result) { result_max = j; result = vdot; } } groups[i] = result_max; } bu_free(face_normals, "face_normals"); /* Determine the maximum number of faces associated with any one vertex */ unsigned int *vert_face_cnt = (unsigned int *)bu_calloc(bot->num_vertices, sizeof(unsigned int), "vert face cnt"); for (unsigned int i = 0; i < bot->num_faces; i++) { vert_face_cnt[bot->faces[i*3+0]]++; vert_face_cnt[bot->faces[i*3+1]]++; vert_face_cnt[bot->faces[i*3+2]]++; } unsigned int max_face_cnt = 0; for (unsigned int i = 0; i < bot->num_vertices; i++) { if (vert_face_cnt[i] > max_face_cnt) max_face_cnt = vert_face_cnt[i]; } /* Now, allocate a 2D array that can hold the full vert->face map * and populate it */ vert_to_face = (unsigned int *)bu_calloc(bot->num_vertices * max_face_cnt, sizeof(unsigned int), "map"); unsigned int *vert_sizes = (unsigned int *)bu_calloc(bot->num_vertices, sizeof(unsigned int), "map"); for (unsigned int i = 0; i < bot->num_faces; i++) { for (unsigned int j = 0; j < 3; j++) { unsigned int vert = bot->faces[i*3+j]; unsigned int k = vert_sizes[vert]; /* rows are vertex indexes, columns hold the faces */ /* Need to increment face index by one so we can reference * the first face and still use the true/false test that 0 allows */ vert_to_face[max_face_cnt * vert + k] = i + 1; vert_sizes[vert]++; //bu_log("vert_to_face(%d,%d)[%d] = %d\n", vert, k, max_face_cnt * vert + k, i + 1); } } /* Order the groups by number of bots */ /* Note - needed only when group boarders are not enforced in patch building */ // unsigned int group_cnt[6] = {0}; unsigned int ordered_groups[6] = {0,1,2,3,4,5}; /* for (unsigned int i = 0; i < bot->num_faces; i++) { group_cnt[groups[i]]++; } for (unsigned int i = 0; i < 6; i++) { unsigned int more = 0; for (unsigned int j = 0; j < 6; j++) { if (group_cnt[j] > group_cnt[i]) more++; } ordered_groups[more] = i; } */ // All faces must belong to some patch - continue until all faces are processed unsigned int patch_cnt = 0; for (unsigned int i = 0; i < 6; i++) { int unused = 0; while (unused != -1) { unsigned int face_stp = 0; // Start a new patch unused = -1; patch_cnt++; // Find remaining face in group while (unused == -1 && face_stp < bot->num_faces) { if (ordered_groups[i] == groups[face_stp] && !patches[face_stp]) { unused = face_stp; } face_stp++; } if (unused != -1) { std::queue<unsigned int> face_queue; face_queue.push(unused); patches[unused] = patch_cnt; while (!face_queue.empty()) { unsigned int face_num = face_queue.front(); face_queue.pop(); for (unsigned int k = 0; k < 3; k++) { unsigned int vert_id = bot->faces[face_num*3+k]; for (unsigned int l = 0; l < vert_face_cnt[vert_id]; l++) { unsigned int new_face = vert_to_face[max_face_cnt * vert_id + l] - 1; if (groups[new_face] == ordered_groups[i] && !patches[new_face]) { face_queue.push(new_face); patches[new_face] = patch_cnt; } } } } } } } bu_free(groups, "groups"); bu_free(vert_to_face, "vert_to_face"); unsigned int *patch_vert_cnt = vert_sizes; memset(patch_vert_cnt, 0, bot->num_vertices * sizeof(unsigned int)); unsigned int *vert_edge_status = (unsigned int *)bu_calloc(bot->num_vertices, sizeof(unsigned int), "vert status"); for (unsigned int i = 0; i < patch_cnt; i++) { memset(patch_vert_cnt, 0, bot->num_vertices * sizeof(unsigned int)); for (unsigned int j = 0; j < bot->num_faces; j++) { if (patches[j] == i+1) { patch_vert_cnt[bot->faces[j*3+0]]++; patch_vert_cnt[bot->faces[j*3+1]]++; patch_vert_cnt[bot->faces[j*3+2]]++; } } for (unsigned int j = 0; j < bot->num_vertices; j++) { if (patch_vert_cnt[j] && patch_vert_cnt[j] != vert_face_cnt[j]) { vert_edge_status[j]++; } } } bu_free(patches, "patches"); bu_free(patch_vert_cnt, "patch_vert_cnt"); bu_free(vert_face_cnt, "vert_face_cnt"); for (unsigned int j = 0; j < bot->num_faces; j++) { if (vert_edge_status[bot->faces[j*3+0]] && vert_edge_status[bot->faces[j*3+1]]) { RT_ADD_VLIST(info->vhead, &(bot->vertices[bot->faces[j*3+0]*3]), BN_VLIST_LINE_MOVE); RT_ADD_VLIST(info->vhead, &(bot->vertices[bot->faces[j*3+1]*3]), BN_VLIST_LINE_DRAW); } if (vert_edge_status[bot->faces[j*3+1]] && vert_edge_status[bot->faces[j*3+2]]) { RT_ADD_VLIST(info->vhead, &(bot->vertices[bot->faces[j*3+1]*3]), BN_VLIST_LINE_MOVE); RT_ADD_VLIST(info->vhead, &(bot->vertices[bot->faces[j*3+2]*3]), BN_VLIST_LINE_DRAW); } if (vert_edge_status[bot->faces[j*3+2]] && vert_edge_status[bot->faces[j*3+0]]) { RT_ADD_VLIST(info->vhead, &(bot->vertices[bot->faces[j*3+2]*3]), BN_VLIST_LINE_MOVE); RT_ADD_VLIST(info->vhead, &(bot->vertices[bot->faces[j*3+0]*3]), BN_VLIST_LINE_DRAW); } } bu_free(vert_edge_status, "vert status"); return 0; }
int ged_bot_smooth(struct ged *gedp, int argc, const char *argv[]) { char *new_bot_name, *old_bot_name; struct directory *dp_old, *dp_new; struct rt_bot_internal *old_bot; struct rt_db_internal intern; fastf_t tolerance_angle=180.0; int arg_index=1; static const char *usage = "[-t ntol] new_bot old_bot"; GED_CHECK_DATABASE_OPEN(gedp, GED_ERROR); GED_CHECK_READ_ONLY(gedp, GED_ERROR); GED_CHECK_ARGC_GT_0(gedp, argc, GED_ERROR); dp_old = dp_new = RT_DIR_NULL; /* 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; } /* check that we are using a version 5 database */ if (db_version(gedp->ged_wdbp->dbip) < 5) { bu_vls_printf(gedp->ged_result_str, "This is an older database version.\nIt does not support BOT surface normals.\nUse \"dbupgrade\" to upgrade this database to the current version.\n"); return GED_ERROR; } if (argc < 3) { bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv[0], usage); return GED_ERROR; } while (*argv[arg_index] == '-') { /* this is an option */ if (BU_STR_EQUAL(argv[arg_index], "-t")) { arg_index++; tolerance_angle = atof(argv[arg_index]); } else { bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv[0], usage); return GED_ERROR; } arg_index++; } if (arg_index >= argc) { bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv[0], usage); return GED_ERROR; } new_bot_name = (char *)argv[arg_index++]; old_bot_name = (char *)argv[arg_index]; GED_DB_LOOKUP(gedp, dp_old, old_bot_name, LOOKUP_QUIET, GED_ERROR); if (!BU_STR_EQUAL(old_bot_name, new_bot_name)) { GED_CHECK_EXISTS(gedp, new_bot_name, LOOKUP_QUIET, GED_ERROR); } else { dp_new = dp_old; } GED_DB_GET_INTERNAL(gedp, &intern, dp_old, NULL, gedp->ged_wdbp->wdb_resp, 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 is not a BOT primitive\n", old_bot_name); rt_db_free_internal(&intern); return GED_ERROR; } old_bot = (struct rt_bot_internal *)intern.idb_ptr; RT_BOT_CK_MAGIC(old_bot); if (rt_bot_smooth(old_bot, old_bot_name, gedp->ged_wdbp->dbip, tolerance_angle*DEG2RAD)) { bu_vls_printf(gedp->ged_result_str, "Failed to smooth %s\n", old_bot_name); rt_db_free_internal(&intern); return GED_ERROR; } if (dp_new == RT_DIR_NULL) { GED_DB_DIRADD(gedp, dp_new, new_bot_name, RT_DIR_PHONY_ADDR, 0, RT_DIR_SOLID, (void *)&intern.idb_type, GED_ERROR); } GED_DB_PUT_INTERNAL(gedp, dp_new, &intern, gedp->ged_wdbp->wdb_resp, GED_ERROR); rt_db_free_internal(&intern); return GED_OK; }
int main(int argc, char *argv[]) { struct db_i *dbip; struct directory *dp; struct rt_db_internal intern; struct rt_bot_internal *bot_ip = NULL; struct rt_wdb *wdbp; struct bu_vls name; struct bu_vls bname; struct Mesh_Info *prev_mesh = NULL; struct Mesh_Info *mesh = NULL; bu_vls_init(&name); if (argc != 3) { bu_exit(1, "Usage: %s file.g object", argv[0]); } dbip = db_open(argv[1], DB_OPEN_READWRITE); if (dbip == DBI_NULL) { bu_exit(1, "ERROR: Unable to read from geometry database file %s\n", argv[1]); } if (db_dirbuild(dbip) < 0) bu_exit(1, "ERROR: Unable to read from %s\n", argv[1]); dp = db_lookup(dbip, argv[2], LOOKUP_QUIET); if (dp == RT_DIR_NULL) { bu_exit(1, "ERROR: Unable to look up object %s\n", argv[2]); } RT_DB_INTERNAL_INIT(&intern) if (rt_db_get_internal(&intern, dp, dbip, NULL, &rt_uniresource) < 0) { bu_exit(1, "ERROR: Unable to get internal representation of %s\n", argv[2]); } if (intern.idb_minor_type != DB5_MINORTYPE_BRLCAD_BOT) { bu_exit(1, "ERROR: object %s does not appear to be of type BoT\n", argv[2]); } else { bot_ip = (struct rt_bot_internal *)intern.idb_ptr; } RT_BOT_CK_MAGIC(bot_ip); for (size_t i_cnt = 1; i_cnt < 3; i_cnt++) { mesh = iterate(bot_ip, prev_mesh); prev_mesh = mesh; // Plot results struct bu_vls fname; bu_vls_init(&fname); bu_vls_printf(&fname, "root3_%d.pl", i_cnt); FILE* plot_file = fopen(bu_vls_addr(&fname), "w"); std::map<size_t, std::vector<size_t> >::iterator f_it; std::vector<size_t>::iterator l_it; int r = int(256*drand48() + 1.0); int g = int(256*drand48() + 1.0); int b = int(256*drand48() + 1.0); for (f_it = mesh->face_pts.begin(); f_it != mesh->face_pts.end(); f_it++) { l_it = (*f_it).second.begin(); plot_face(&mesh->points_p0[(int)(*l_it)], &mesh->points_p0[(int)(*(l_it+1))], &mesh->points_p0[(int)(*(l_it+2))], r, g , b, plot_file); } fclose(plot_file); } // When constructing the final BoT, use the limit points for all // vertices ON_3dPointArray points_inf; for (size_t v = 0; v < (size_t)mesh->points_p0.Count(); v++) { points_inf.Append(*mesh->points_p0.At((int)v)); //point_inf(v, mesh, &points_inf); } // The subdivision process shrinks the bot relative to its original // vertex positions - to better approximate the original surface, // average the change in position of the original vertices to get a // scaling factor and apply it to all points in the final mesh. fastf_t scale = 0.0; for (size_t pcnt = 0; pcnt < bot_ip->num_vertices; pcnt++) { ON_3dVector v1(ON_3dPoint(&bot_ip->vertices[pcnt*3])); ON_3dVector v2(*points_inf.At((int)pcnt)); scale += 1 + (v1.Length() - v2.Length())/v1.Length(); } scale = scale / bot_ip->num_vertices; for (size_t pcnt = 0; pcnt < (size_t)points_inf.Count(); pcnt++) { ON_3dPoint p0(*points_inf.At((int)pcnt)); ON_3dPoint p1 = p0 * scale; *points_inf.At((int)pcnt) = p1; } wdbp = wdb_dbopen(dbip, RT_WDB_TYPE_DB_DISK); fastf_t *vertices = (fastf_t *)bu_malloc(sizeof(fastf_t) * points_inf.Count() * 3, "new verts"); int *faces = (int *)bu_malloc(sizeof(int) * mesh->face_pts.size() * 3, "new faces"); for (size_t v = 0; v < (size_t)points_inf.Count(); v++) { vertices[v*3] = points_inf[(int)v].x; vertices[v*3+1] = points_inf[(int)v].y; vertices[v*3+2] = points_inf[(int)v].z; } std::map<size_t, std::vector<size_t> >::iterator f_it; std::vector<size_t>::iterator l_it; for (f_it = mesh->face_pts.begin(); f_it != mesh->face_pts.end(); f_it++) { l_it = (*f_it).second.begin(); faces[(*f_it).first*3] = (*l_it); faces[(*f_it).first*3+1] = (*(l_it + 1)); faces[(*f_it).first*3+2] = (*(l_it + 2)); } bu_vls_init(&bname); bu_vls_sprintf(&bname, "%s_subd", argv[2]); mk_bot(wdbp, bu_vls_addr(&bname), RT_BOT_SOLID, RT_BOT_UNORIENTED, 0, points_inf.Count(), mesh->face_pts.size(), vertices, faces, (fastf_t *)NULL, (struct bu_bitv *)NULL); wdb_close(wdbp); bu_vls_free(&bname); bu_free(vertices, "free subdivision BoT vertices"); bu_free(faces, "free subdivision BoT faces"); return 0; }
/** * Given a pointer to an internal GED database object, mirror the * object's values about the given transformation matrix. */ int rt_bot_mirror(struct rt_db_internal *ip, register const plane_t plane) { struct rt_bot_internal *bot; mat_t mirmat; mat_t rmat; mat_t temp; vect_t nvec; vect_t xvec; vect_t mirror_dir; point_t mirror_pt; fastf_t ang; size_t i; static point_t origin = {0.0, 0.0, 0.0}; RT_CK_DB_INTERNAL(ip); bot = (struct rt_bot_internal *)ip->idb_ptr; RT_BOT_CK_MAGIC(bot); MAT_IDN(mirmat); VMOVE(mirror_dir, plane); VSCALE(mirror_pt, plane, plane[W]); /* Build mirror transform matrix, for those who need it. */ /* First, perform a mirror down the X axis */ mirmat[0] = -1.0; /* Create the rotation matrix */ VSET(xvec, 1, 0, 0); VCROSS(nvec, xvec, mirror_dir); VUNITIZE(nvec); ang = -acos(VDOT(xvec, mirror_dir)); bn_mat_arb_rot(rmat, origin, nvec, ang*2.0); /* Add the rotation to mirmat */ MAT_COPY(temp, mirmat); bn_mat_mul(mirmat, temp, rmat); /* Add the translation to mirmat */ mirmat[3 + X*4] += mirror_pt[X] * mirror_dir[X]; mirmat[3 + Y*4] += mirror_pt[Y] * mirror_dir[Y]; mirmat[3 + Z*4] += mirror_pt[Z] * mirror_dir[Z]; /* mirror each vertex */ for (i=0; i<bot->num_vertices; i++) { point_t pt; VMOVE(pt, &bot->vertices[i*3]); MAT4X3PNT(&bot->vertices[i*3], mirmat, pt); } /* Reverse each faces' order */ for (i=0; i<bot->num_faces; i++) { int save_face = bot->faces[i*3]; bot->faces[i*3] = bot->faces[i*3 + Z]; bot->faces[i*3 + Z] = save_face; } /* fix normals */ for (i=0; i<bot->num_normals; i++) { vectp_t np = &bot->normals[i*3]; vect_t n1; vect_t n2; mat_t mat; VMOVE(n1, np); VCROSS(n2, mirror_dir, n1); VUNITIZE(n2); ang = M_PI_2 - acos(VDOT(n1, mirror_dir)); bn_mat_arb_rot(mat, origin, n2, ang*2); MAT4X3VEC(np, mat, n1); } return 0; }