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;
}
Beispiel #4
0
/**
 *	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;
}
Beispiel #5
0
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);
}
Beispiel #7
0
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;
}
Beispiel #9
0
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;
}
Beispiel #12
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;
}