コード例 #1
0
/*
 *	Convert an ascii nmg description into a BRL-CAD data base.
 */
static int
ascii_to_brlcad(FILE *fpin, struct rt_wdb *fpout, char *reg_name, char *grp_name)
{
    struct model	*m;
    struct nmgregion	*r;
    struct bn_tol	tol;
    struct shell	*s;
    vect_t		Ext;
    struct faceuse *fu;
    plane_t		pl;

    VSETALL(Ext, 0.);

    m = nmg_mm();		/* Make nmg model. */
    r = nmg_mrsv(m);	/* Make region, empty shell, vertex */
    s = BU_LIST_FIRST(shell, &r->s_hd);
    descr_to_nmg(s, fpin, Ext);	/* Convert ascii description to nmg. */

    /* Copied from proc-db/nmgmodel.c */
    tol.magic = BN_TOL_MAGIC;
    tol.dist = 0.01;
    tol.dist_sq = tol.dist * tol.dist;
    tol.perp = 0.001;
    tol.para = 0.999;

    /* Associate the face geometry. */
    fu = BU_LIST_FIRST( faceuse, &s->fu_hd );
    if (nmg_loop_plane_area(BU_LIST_FIRST(loopuse, &fu->lu_hd), pl) < 0.0)
	return -1;
    else
	nmg_face_g( fu, pl );

    if (!NEAR_ZERO(MAGNITUDE(Ext), 0.001))
	nmg_extrude_face(BU_LIST_FIRST(faceuse, &s->fu_hd), Ext, &tol);

    nmg_region_a(r, &tol);	/* Calculate geometry for region and shell. */

    nmg_fix_normals( s, &tol ); /* insure that faces have outward pointing normals */

    create_brlcad_db(fpout, m, reg_name, grp_name);

    return 0;
}
コード例 #2
0
/**
 * Read a polygon file and convert it to an NMG shell
 *
 * A polygon file consists of the following:
 *
 * The first line consists of two integer numbers: the number of
 * points (vertices) in the file, followed by the number of polygons
 * in the file.  This line is followed by lines for each of the
 * vertices.  Each vertex is listed on its own line, as the 3tuple "X
 * Y Z".  After the list of vertices comes the list of polygons.
 * each polygon is represented by a line containing 1) the number of
 * vertices in the polygon, followed by 2) the indices of the
 * vertices that make up the polygon.
 *
 * Implicitly returns r->s_p which is a new shell containing all the
 * faces from the polygon file.
 *
 * XXX This is a horrible way to do this.  Lee violates his own rules
 * about not creating fundamental structures on his own...  :-)
 * Retired in favor of more modern tessellation strategies.
 */
struct shell *
nmg_polytonmg(FILE *fp, struct nmgregion *r, const struct bn_tol *tol)
{
    int i, j, num_pts, num_facets, pts_this_face, facet;
    int vl_len;
    struct vertex **v;  /* list of all vertices */
    struct vertex **vl; /* list of vertices for this polygon*/
    point_t p;
    struct shell *s;
    struct faceuse *fu;
    struct loopuse *lu;
    struct edgeuse *eu;
    plane_t plane;
    struct model *m;

    s = nmg_msv(r);
    m = s->r_p->m_p;
    nmg_kvu(s->vu_p);

    /* get number of points & number of facets in file */
    if (fscanf(fp, "%d %d", &num_pts, &num_facets) != 2)
	bu_bomb("polytonmg() Error in first line of poly file\n");
    else
	if (RTG.NMG_debug & DEBUG_POLYTO)
	    bu_log("points: %d facets: %d\n",
		   num_pts, num_facets);


    v = (struct vertex **) bu_calloc(num_pts, sizeof (struct vertex *),
				     "vertices");

    /* build the vertices */
    for (i = 0; i < num_pts; ++i) {
	GET_VERTEX(v[i], m);
	v[i]->magic = NMG_VERTEX_MAGIC;
    }

    /* read in the coordinates of the vertices */
    for (i=0; i < num_pts; ++i) {
	if (fscanf(fp, "%lg %lg %lg", &p[0], &p[1], &p[2]) != 3)
	    bu_bomb("polytonmg() Error reading point");
	else
	    if (RTG.NMG_debug & DEBUG_POLYTO)
		bu_log("read vertex #%d (%g %g %g)\n",
		       i, p[0], p[1], p[2]);

	nmg_vertex_gv(v[i], p);
    }

    vl = (struct vertex **)bu_calloc(vl_len=8, sizeof (struct vertex *),
				     "vertex parameter list");

    for (facet = 0; facet < num_facets; ++facet) {
	if (fscanf(fp, "%d", &pts_this_face) != 1)
	    bu_bomb("polytonmg() error getting pt count for this face");

	if (RTG.NMG_debug & DEBUG_POLYTO)
	    bu_log("facet %d pts in face %d\n",
		   facet, pts_this_face);

	if (pts_this_face > vl_len) {
	    while (vl_len < pts_this_face) vl_len *= 2;
	    vl = (struct vertex **)bu_realloc((char *)vl,
					      vl_len*sizeof(struct vertex *),
					      "vertex parameter list (realloc)");
	}

	for (i=0; i < pts_this_face; ++i) {
	    if (fscanf(fp, "%d", &j) != 1)
		bu_bomb("polytonmg() error getting point index for v in f");
	    vl[i] = v[j-1];
	}

	fu = nmg_cface(s, vl, pts_this_face);
	lu = BU_LIST_FIRST(loopuse, &fu->lu_hd);
	/* XXX should check for vertex-loop */
	eu = BU_LIST_FIRST(edgeuse, &lu->down_hd);
	NMG_CK_EDGEUSE(eu);
	if (bn_mk_plane_3pts(plane, eu->vu_p->v_p->vg_p->coord,
			     BU_LIST_PNEXT(edgeuse, eu)->vu_p->v_p->vg_p->coord,
			     BU_LIST_PLAST(edgeuse, eu)->vu_p->v_p->vg_p->coord,
			     tol)) {
	    bu_log("At %d in %s\n", __LINE__, __FILE__);
	    bu_bomb("polytonmg() cannot make plane equation\n");
	} else nmg_face_g(fu, plane);
    }

    for (i=0; i < num_pts; ++i) {
	if (BU_LIST_IS_EMPTY(&v[i]->vu_hd)) continue;
	FREE_VERTEX(v[i]);
    }
    bu_free((char *)v, "vertex array");
    return s;
}
コード例 #3
0
int
psurf_to_nmg(struct model *m, FILE *fp, char *jfile)
/* Input/output, nmg model. */
/* Input, pointer to psurf data file. */
/* Name of Jack data base file. */
{
    int		face, fail, i, lst[MAX_NUM_PTS], nf, nv;
    struct faceuse	*outfaceuses[MAX_NUM_PTS];
    struct nmgregion *r;
    struct shell	*s;
    struct vertex	*vertlist[MAX_NUM_PTS];
    struct vlist	vert;

    /* Copied from proc-db/nmgmodel.c */
    tol.magic = BN_TOL_MAGIC;
    tol.dist = 0.01;
    tol.dist_sq = tol.dist * tol.dist;
    tol.perp = 0.001;
    tol.para = 0.999;

    face = 0;
    r = nmg_mrsv(m);	/* Make region, empty shell, vertex. */
    s = BU_LIST_FIRST(shell, &r->s_hd);

    while ((nv = read_psurf_vertices(fp, &vert)) != 0) {
	size_t ret;

	while ((nf = read_psurf_face(fp, lst)) != 0) {

	    /* Make face out of vertices in lst (ccw ordered). */
	    for (i = 0; i < nf; i++)
		vertlist[i] = vert.vt[lst[i]-1];
	    outfaceuses[face] = nmg_cface(s, vertlist, nf);
	    face++;

	    /* Save (possibly) newly created vertex structs. */
	    for (i = 0; i < nf; i++)
		vert.vt[lst[i]-1] = vertlist[i];
	}
	ret = fscanf(fp, ";;");
	if (ret > 0)
	    bu_log("unknown parsing error\n");

	/* Associate the vertex geometry, ccw. */
	for (i = 0; i < nv; i++)
	    if (vert.vt[i])
		nmg_vertex_gv(vert.vt[i], &vert.pt[3*i]);
	    else
		fprintf(stderr, "%s, vertex %d is unused\n",
			jfile, i+1);
    }

    nmg_vertex_fuse(&m->magic, &tol);

    /* Associate the face geometry. */
    for (i = 0, fail = 0; i < face; i++)
    {
	struct loopuse *lu;
	plane_t pl;

	lu = BU_LIST_FIRST(loopuse, &outfaceuses[i]->lu_hd);
	if (nmg_loop_plane_area(lu, pl) < 0.0)
	{
	    fail = 1;
	    nmg_kfu(outfaceuses[i]);
	}
	else
	    nmg_face_g(outfaceuses[i], pl);
    }
    if (fail)
	return -1;

    if (face)
    {
	int empty_model;
	empty_model = nmg_kill_zero_length_edgeuses(m);
	if (!empty_model) {

	  /* Compute "geometry" for region and shell */
	  nmg_region_a(r, &tol);

	  nmg_break_e_on_v(&m->magic, &tol);
	  empty_model = nmg_kill_zero_length_edgeuses(m);

	  /* Glue edges of outward pointing face uses together. */
	  if (!empty_model) nmg_edge_fuse(&m->magic, &tol);
	}
    }

    return 0;
}
コード例 #4
0
ファイル: off-g.c プロジェクト: kanzure/brlcad
int read_faces(struct model *m, FILE *fgeom)
{
    int 		   nverts, nfaces, nedges;
    int 	   i, j, fail=0;
    fastf_t 	  *pts;
    struct vertex 	 **verts;
    struct faceuse 	 **outfaceuses;
    struct nmgregion  *r;
    struct shell 	  *s;
    size_t ret;

    /* Get numbers of vertices and faces, and grab the appropriate amount of memory */
    if (fscanf(fgeom, "%d %d %d", &nverts, &nfaces, &nedges) != 3)
	bu_exit(1, "Cannot read number of vertices, faces, edges.\n");

    pts = (fastf_t *) bu_malloc(sizeof(fastf_t) * 3 * nverts, "points list");
    verts = (struct vertex **) bu_malloc(sizeof(struct vertex *) * nverts, "vertices");
    outfaceuses = (struct faceuse **) bu_malloc(sizeof(struct faceuse *) * nfaces, "faceuses");

    /* Read in vertex geometry, store in geometry list */
    for (i = 0; i < nverts; i++) {
	double scan[3];
	if (fscanf(fgeom, "%lf %lf %lf", &scan[0], &scan[1], &scan[2]) != 3) {
	    bu_exit(1, "Not enough data points in geometry file.\n");
	}
	pts[3*i] = scan[0];
	pts[3*i+1] = scan[1];
	pts[3*i+2] = scan[2];

	verts[i] = (struct vertex *) 0;
	ret = fscanf(fgeom, "%*[^\n]");
	if (ret > 0)
	    bu_log("unknown parsing error\n");
    }

    r = nmg_mrsv(m);		/* Make region, empty shell, vertex. */
    s = BU_LIST_FIRST(shell, &r->s_hd);


    for (i = 0; i < nfaces; i++) {
	/* Read in each of the faces */
	struct vertex **vlist;
	int *pinds;

	if (fscanf(fgeom, "%d", &nedges) != 1) {
	    bu_exit(1, "Not enough faces in geometry file.\n");
	}
	/* Grab memory for list for this face. */
	vlist = (struct vertex **) bu_malloc(sizeof(struct vertex *) * nedges, "vertex list");
	pinds = (int *) bu_malloc(sizeof(int) * nedges, "point indices");

	for (j = 0; j < nedges; j++) {
	    /* Read list of point indices. */
	    if (fscanf(fgeom, "%d", &pinds[j]) != 1) {
		bu_exit(1, "Not enough points on face.\n");
	    }
	    vlist[j] = verts[pinds[j]-1];
	}

	outfaceuses[i] = nmg_cface(s, vlist, nedges);	/* Create face. */
	NMG_CK_FACEUSE(outfaceuses[i]);

	for (j = 0; j < nedges; j++)		/* Save (possibly) newly created vertex structs. */
	    verts[pinds[j]-1] = vlist[j];

	ret = fscanf(fgeom, "%*[^\n]");
	if (ret > 0)
	    bu_log("unknown parsing error\n");

	bu_free((char *)vlist, "vertext list");
	bu_free((char *)pinds, "point indices");
    }

    for (i = 0; i < nverts; i++)
	if (verts[i] != 0)
	    nmg_vertex_gv(verts[i], &pts[3*i]);
	else
	    fprintf(stderr, "Warning: vertex %d unused.\n", i+1);

    for (i = 0; i < nfaces; i++) {
	plane_t pl;

	fprintf(stderr, "planeeqning face %d.\n", i);
	if ( nmg_loop_plane_area( BU_LIST_FIRST( loopuse, &outfaceuses[i]->lu_hd ), pl ) < 0.0 )
	    fail = 1;
	else
	    nmg_face_g( outfaceuses[i], pl );

    }

    if (fail) return -1;

    nmg_gluefaces(outfaceuses, nfaces, &tol);
    nmg_region_a(r, &tol);

    bu_free((char *)pts, "points list");
    return 0;
}
コード例 #5
0
struct faceuse *
Make_planar_face(struct shell *s, int entityno, int face_orient)
{

    int sol_num;	/* IGES solid type number */
    int no_of_edges;	/* edge count for this loop */
    int no_of_param_curves;
    int vert_count = 0;	/* Actual number of vertices used to make face */
    struct iges_edge_use *edge_list;	/* list of edgeuses from iges loop entity */
    struct faceuse *fu = NULL;	/* NMG face use */
    struct loopuse *lu;		/* NMG loop use */
    struct vertex ***verts;	/* list of vertices */
    struct iges_vertex_list *v_list;
    int done;
    int i, j, k;

    /* Acquiring Data */

    if (dir[entityno]->param <= pstart) {
	bu_log("Illegal parameter pointer for entity D%07d (%s)\n" ,
	       dir[entityno]->direct, dir[entityno]->name);
	return 0;
    }

    Readrec(dir[entityno]->param);
    Readint(&sol_num, "");
    if (sol_num != 508) {
	bu_exit(1, "ERROR: Entity #%d is not a loop (it's a %s)\n", entityno, iges_type(sol_num));
    }

    Readint(&no_of_edges, "");
    edge_list = (struct iges_edge_use *)bu_calloc(no_of_edges, sizeof(struct iges_edge_use) ,
						  "Make_face (edge_list)");
    for (i = 0; i < no_of_edges; i++) {
	Readint(&edge_list[i].edge_is_vertex, "");
	Readint(&edge_list[i].edge_de, "");
	Readint(&edge_list[i].index, "");
	Readint(&edge_list[i].orient, "");
	if (!face_orient) {
	    /* need opposite orientation of edge */
	    if (edge_list[i].orient)
		edge_list[i].orient = 0;
	    else
		edge_list[i].orient = 1;
	}
	edge_list[i].root = (struct iges_param_curve *)NULL;
	Readint(&no_of_param_curves, "");
	for (j = 0; j < no_of_param_curves; j++) {
	    struct iges_param_curve *new_crv;
	    struct iges_param_curve *crv;

	    Readint(&k, "");	/* ignore iso-parametric flag */

	    BU_ALLOC(new_crv, struct iges_param_curve);
	    if (edge_list[i].root == (struct iges_param_curve *)NULL)
		edge_list[i].root = new_crv;
	    else {
		crv = edge_list[i].root;
		while (crv->next != (struct iges_param_curve *)NULL)
		    crv = crv->next;
		crv->next = new_crv;
	    }
	    Readint(&new_crv->curve_de, "");
	    new_crv->next = (struct iges_param_curve *)NULL;
	}
    }

    verts = (struct vertex ***)bu_calloc(no_of_edges, sizeof(struct vertex **) ,
					 "Make_face: vertex_list **");

    for (i = 0; i < no_of_edges; i++) {
	if (face_orient)
	    verts[i] = Get_vertex(&edge_list[i]);
	else
	    verts[no_of_edges-1-i] = Get_vertex(&edge_list[i]);
    }

    /* eliminate zero length edges */
    vert_count = no_of_edges;
    done = 0;
    while (!done) {
	done = 1;
	for (i = 0; i < vert_count; i++) {
	    k = i + 1;
	    if (k == vert_count)
		k = 0;

	    if (verts[i] == verts[k]) {
		bu_log("Ignoring zero length edge\n");
		done = 0;
		vert_count--;
		for (j = i; j < vert_count; j++)
		    verts[j] = verts[j+1];
	    }
	}
    }

    if (vert_count) {
	plane_t pl;		/* Plane equation for face */
	fastf_t area;		/* area of loop */
	fastf_t dist;
	vect_t min2max;
	point_t outside_pt;

	fu = nmg_cmface(s, verts, vert_count);

	/* associate geometry */
	v_list = vertex_root;
	while (v_list != NULL) {
	    for (i = 0; i < v_list->no_of_verts; i++) {
		if (v_list->i_verts[i].v != NULL && v_list->i_verts[i].v->vg_p == NULL) {
		    NMG_CK_VERTEX(v_list->i_verts[i].v);
		    nmg_vertex_gv(v_list->i_verts[i].v ,
				  v_list->i_verts[i].pt);
		}
	    }
	    v_list = v_list->next;
	}

	lu = BU_LIST_FIRST(loopuse, &fu->lu_hd);
	NMG_CK_LOOPUSE(lu);

	area = nmg_loop_plane_area(lu, pl);
	if (area < 0.0) {
	    bu_log("Could not calculate area for face (entityno = %d)\n", entityno);
	    nmg_pr_fu_briefly(fu, "");
	    nmg_kfu(fu);
	    fu = (struct faceuse *)NULL;
	    goto err;
	}

	nmg_face_g(fu, pl);
	nmg_face_bb(fu->f_p, &tol);

	/* find a point that is surely outside the loop */
	VSUB2(min2max, fu->f_p->max_pt, fu->f_p->min_pt);
	VADD2(outside_pt, fu->f_p->max_pt, min2max);

	/* move it to the plane of the face */
	dist = DIST_PT_PLANE(outside_pt, pl);
	VJOIN1(outside_pt, outside_pt, -dist, pl);

	if (nmg_class_pt_lu_except(outside_pt, lu, (struct edge *)NULL, &tol) != NMG_CLASS_AoutB) {
	    nmg_reverse_face(fu);
	    if (fu->orientation != OT_SAME) {
		fu = fu->fumate_p;
		if (fu->orientation != OT_SAME)
		    bu_exit(1, "ERROR: no OT_SAME use for a face!\n");
	    }
	}
    } else
	bu_log("No edges left!\n");

err:
    bu_free((char *)edge_list, "Make_face (edge_list)");
    bu_free((char *)verts, "Make_face (vertexlist)");
    return fu;
}
コード例 #6
0
void
make_3manifold_bits(struct bn_tol *tol)
{
    plane_t plane;
    struct faceuse *fu_end;

    memset((char *)vertl, 0, sizeof(vertl));
    memset((char *)f_vertl, 0, sizeof(f_vertl));

    /* front right */
    f_vertl[0] = &vertl[0];
    f_vertl[1] = &vertl[1];
    f_vertl[2] = &vertl[2];
    f_vertl[3] = &vertl[3];
    fr_fu = fu = nmg_cmface(s, f_vertl, 4);
    nmg_vertex_g(vertl[0],  100.0, 100.0, 100.0);
    nmg_vertex_g(vertl[1],   50.0, 100.0, 100.0);
    nmg_vertex_g(vertl[2],   50.0,   0.0, 100.0);
    nmg_vertex_g(vertl[3],  100.0,   0.0, 100.0);
    (void)nmg_fu_planeeqn(fu, tol);

    /* make top right */
    f_vertl[0] = &vertl[0];
    f_vertl[1] = &vertl[4];
    f_vertl[2] = &vertl[5];
    f_vertl[3] = &vertl[1];
    fu = nmg_cmface(s, f_vertl, 4);
    nmg_vertex_g(vertl[4],  100.0, 100.0,   0.0);
    nmg_vertex_g(vertl[5],   50.0, 100.0,   0.0);
    (void)nmg_fu_planeeqn(fu, tol);


    /* back right */
    f_vertl[0] = &vertl[5];
    f_vertl[1] = &vertl[4];
    f_vertl[2] = &vertl[6];
    f_vertl[3] = &vertl[7];
    fu = nmg_cmface(s, f_vertl, 4);
    nmg_vertex_g(vertl[6],  100.0,   0.0,   0.0);
    nmg_vertex_g(vertl[7],   50.0,   0.0,   0.0);
    (void)nmg_fu_planeeqn(fu, tol);

    /* bottom right */
    f_vertl[0] = &vertl[7];
    f_vertl[1] = &vertl[6];
    f_vertl[2] = &vertl[3];
    f_vertl[3] = &vertl[2];
    fu = nmg_cmface(s, f_vertl, 4);
    (void)nmg_fu_planeeqn(fu, tol);

    /* right end */
    f_vertl[0] = &vertl[3];
    f_vertl[1] = &vertl[6];
    f_vertl[2] = &vertl[4];
    f_vertl[3] = &vertl[0];
    fu = nmg_cmface(s, f_vertl, 4);
    (void)nmg_fu_planeeqn(fu, tol);


    /* make split top */
    f_vertl[0] = &vertl[1];
    f_vertl[1] = &vertl[5];
    f_vertl[2] = &vertl[8];
    f_vertl[3] = &vertl[9];
    tc_fu = fu = nmg_cmface(s, f_vertl, 4);
    nmg_vertex_g(vertl[8],   25.0, 100.0,   0.0);
    nmg_vertex_g(vertl[9],   25.0, 100.0, 100.0);
    (void)nmg_fu_planeeqn(fu, tol);

    f_vertl[0] = &vertl[9];
    f_vertl[1] = &vertl[8];
    f_vertl[2] = &vertl[12];
    f_vertl[3] = &vertl[13];
    fu = nmg_cmface(s, f_vertl, 4);
    nmg_vertex_g(vertl[12],   0.0, 100.0,   0.0);
    nmg_vertex_g(vertl[13],   0.0, 100.0, 100.0);
    (void)nmg_fu_planeeqn(fu, tol);


    /* make split & funky front side
     * we make the convex face first, make the second (non-convex) portion
     * after the face normal has been computed.
     */
    f_vertl[0] = &vertl[14];
    f_vertl[1] = &vertl[18];
    f_vertl[2] = &vertl[15];
    f_vertl[3] = &vertl[16];
    fl_fu = fu = nmg_cmface(s, f_vertl, 4);
    nmg_vertex_g(vertl[14],   0.0,  25.0, 100.0);
    nmg_vertex_g(vertl[15],  25.0,   0.0, 100.0);
    nmg_vertex_g(vertl[16],  25.0,  25.0, 100.0);
    nmg_vertex_g(vertl[18],   0.0,   0.0, 100.0);
    (void)nmg_fu_planeeqn(fu, tol);

    f_vertl[0] = &vertl[1];
    f_vertl[1] = &vertl[9];
    f_vertl[2] = &vertl[10];
    f_vertl[3] = &vertl[9];
    f_vertl[4] = &vertl[13];
    f_vertl[5] = &vertl[14];
    f_vertl[6] = &vertl[16];
    f_vertl[7] = &vertl[15];
    f_vertl[8] = &vertl[2];
    nmg_jf(fu, nmg_cmface(s, f_vertl, 9));
    nmg_vertex_g(vertl[10],  25.0,  75.0, 100.0);


    /* make split back side */
    f_vertl[0] = &vertl[5];
    f_vertl[1] = &vertl[7];
    f_vertl[2] = &vertl[17];
    f_vertl[3] = &vertl[12];
    f_vertl[4] = &vertl[8];
    f_vertl[5] = &vertl[11];
    f_vertl[6] = &vertl[8];
    bl_fu = fu = nmg_cmface(s, f_vertl, 7);
    nmg_vertex_g(vertl[11],  25.0,  75.0,   0.0);
    nmg_vertex_g(vertl[17],   0.0,   0.0,   0.0);

    /* this face isn't strictly convex, so we have to make the plane
     * equation the old-fashioned way.
     */
    bn_mk_plane_3pts(plane,
		     vertl[7]->vg_p->coord,
		     vertl[17]->vg_p->coord,
		     vertl[12]->vg_p->coord,
		     tol);
    nmg_face_g(fu, plane);


    /* make funky end */
    f_vertl[0] = &vertl[14];
    f_vertl[1] = &vertl[20];
    f_vertl[2] = &vertl[19];
    f_vertl[3] = &vertl[18];
    fu_end = fu = nmg_cmface(s, f_vertl, 4);
    nmg_vertex_g(vertl[19],   0.0,   0.0,  75.0);
    nmg_vertex_g(vertl[20],   0.0,  25.0,  75.0);
    (void)nmg_fu_planeeqn(fu, tol);

    f_vertl[0] = &vertl[12];
    f_vertl[1] = &vertl[17];
    f_vertl[2] = &vertl[19];
    f_vertl[3] = &vertl[20];
    f_vertl[4] = &vertl[14];
    f_vertl[5] = &vertl[13];
    nmg_jf(fu, nmg_cmface(s, f_vertl, 6));


    /* make funky bottom */
    f_vertl[0] = &vertl[15];
    f_vertl[1] = &vertl[18];
    f_vertl[2] = &vertl[19];
    f_vertl[3] = &vertl[21];
    ul_fu = fu = nmg_cmface(s, f_vertl, 4);
    nmg_vertex_g(vertl[21],  25.0,   0.0,  75.0);
    (void)nmg_fu_planeeqn(fu, tol);

    f_vertl[0] = &vertl[7];
    f_vertl[1] = &vertl[2];
    f_vertl[2] = &vertl[15];
    f_vertl[3] = &vertl[21];
    f_vertl[4] = &vertl[19];
    f_vertl[5] = &vertl[17];
    nmg_jf(fu, nmg_cmface(s, f_vertl, 6));


    /* now create the (3manifold) hole through the object */

    /* make the holes in the end face */
    f_vertl[0] = &vertl[29];
    f_vertl[1] = &vertl[28];
    f_vertl[2] = &vertl[27];
    f_vertl[3] = &vertl[26];
    fu = nmg_cmface(s, f_vertl, 4);
    nmg_vertex_g(vertl[26],  0.0,   60.0, 10.0);
    nmg_vertex_g(vertl[27],  0.0,   60.0, 25.0);
    nmg_vertex_g(vertl[28],  0.0,   40.0, 25.0);
    nmg_vertex_g(vertl[29],  0.0,   40.0, 10.0);

    /* GROSS HACK XXX
     * we reverse the orientation of the faceuses and loopuses
     * so that we can make the hole as a face, and transfer the hole
     * to an existing face
     */

    lu = BU_LIST_FIRST(loopuse, &fu->lu_hd);
    lu->orientation = OT_OPPOSITE;
    lu->lumate_p->orientation = OT_OPPOSITE;

    fu->orientation = OT_OPPOSITE;
    fu->fumate_p->orientation = OT_SAME;

    nmg_jf(fu_end, fu->fumate_p);


    f_vertl[0] = &vertl[22];
    f_vertl[1] = &vertl[23];
    f_vertl[2] = &vertl[24];
    f_vertl[3] = &vertl[25];
    fu = nmg_cmface(s, f_vertl, 4);
    nmg_vertex_g(vertl[22],  10.0, 60.0,  0.0);
    nmg_vertex_g(vertl[23],  25.0,  60.0,  0.0);
    nmg_vertex_g(vertl[24],  25.0,  40.0,  0.0);
    nmg_vertex_g(vertl[25],  10.0, 40.0,  0.0);

    /* GROSS HACK XXX
     * we reverse the orientation of the faceuses and loopuses
     * so that we can make the hole as a face, and transfer the hole
     * to an existing face.
     */

    lu = BU_LIST_FIRST(loopuse, &fu->lu_hd);
    lu->orientation = OT_OPPOSITE;
    lu->lumate_p->orientation = OT_OPPOSITE;

    fu->orientation = OT_OPPOSITE;
    fu->fumate_p->orientation = OT_SAME;

    nmg_jf(bl_fu, fu->fumate_p);


    /* make the top of the hole */
    f_vertl[0] = &vertl[22];
    f_vertl[1] = &vertl[23];
    f_vertl[2] = &vertl[27];
    f_vertl[3] = &vertl[26];
    fu = nmg_cmface(s, f_vertl, 4);
    (void)nmg_fu_planeeqn(fu, tol);


    /* make the bottom of the hole */
    f_vertl[0] = &vertl[24];
    f_vertl[1] = &vertl[25];
    f_vertl[2] = &vertl[29];
    f_vertl[3] = &vertl[28];
    fu = nmg_cmface(s, f_vertl, 4);
    (void)nmg_fu_planeeqn(fu, tol);


    /* make origin-ward side of the hole */
    f_vertl[0] = &vertl[22];
    f_vertl[1] = &vertl[26];
    f_vertl[2] = &vertl[29];
    f_vertl[3] = &vertl[25];
    fu = nmg_cmface(s, f_vertl, 4);
    (void)nmg_fu_planeeqn(fu, tol);

    /* make last side of hole */
    f_vertl[0] = &vertl[23];
    f_vertl[1] = &vertl[24];
    f_vertl[2] = &vertl[28];
    f_vertl[3] = &vertl[27];
    fu = nmg_cmface(s, f_vertl, 4);
    (void)nmg_fu_planeeqn(fu, tol);


    /* now make the void in the center of the solid */

    /* void bottom */
    f_vertl[0] = &vertl[41];
    f_vertl[1] = &vertl[40];
    f_vertl[2] = &vertl[39];
    f_vertl[3] = &vertl[38];
    fu = nmg_cmface(s, f_vertl, 4);
    nmg_vertex_g(vertl[38],  85.0, 40.0, 60.0);
    nmg_vertex_g(vertl[39],  65.0, 40.0, 60.0);
    nmg_vertex_g(vertl[40],  65.0, 40.0, 40.0);
    nmg_vertex_g(vertl[41],  85.0, 40.0, 40.0);
    (void)nmg_fu_planeeqn(fu, tol);


    /* void top */
    f_vertl[0] = &vertl[42];
    f_vertl[1] = &vertl[43];
    f_vertl[2] = &vertl[44];
    f_vertl[3] = &vertl[45];
    fu = nmg_cmface(s, f_vertl, 4);
    nmg_vertex_g(vertl[42],  85.0, 60.0, 40.0);
    nmg_vertex_g(vertl[43],  85.0, 60.0, 60.0);
    nmg_vertex_g(vertl[44],  65.0, 60.0, 60.0);
    nmg_vertex_g(vertl[45],  65.0, 60.0, 40.0);
    (void)nmg_fu_planeeqn(fu, tol);


    /* void front */
    f_vertl[0] = &vertl[44];
    f_vertl[1] = &vertl[43];
    f_vertl[2] = &vertl[38];
    f_vertl[3] = &vertl[39];
    fu = nmg_cmface(s, f_vertl, 4);
    (void)nmg_fu_planeeqn(fu, tol);

    /* void back */
    f_vertl[0] = &vertl[42];
    f_vertl[1] = &vertl[45];
    f_vertl[2] = &vertl[40];
    f_vertl[3] = &vertl[41];
    fu = nmg_cmface(s, f_vertl, 4);
    (void)nmg_fu_planeeqn(fu, tol);


    /* void left */
    f_vertl[0] = &vertl[45];
    f_vertl[1] = &vertl[44];
    f_vertl[2] = &vertl[39];
    f_vertl[3] = &vertl[40];
    fu = nmg_cmface(s, f_vertl, 4);
    (void)nmg_fu_planeeqn(fu, tol);

    /* void right */
    f_vertl[0] = &vertl[42];
    f_vertl[1] = &vertl[41];
    f_vertl[2] = &vertl[38];
    f_vertl[3] = &vertl[43];
    fu = nmg_cmface(s, f_vertl, 4);
    (void)nmg_fu_planeeqn(fu, tol);


}