Ejemplo n.º 1
0
/**
 * R T _ P G _ T E S S
 */
int
rt_pg_tess(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct rt_tess_tol *UNUSED(ttol), const struct bn_tol *tol)
{
    size_t i;
    struct shell *s;
    struct vertex **verts;	/* dynamic array of pointers */
    struct vertex ***vertp;/* dynamic array of ptrs to pointers */
    struct faceuse *fu;
    size_t p;	/* current polygon number */
    struct rt_pg_internal *pgp;

    RT_CK_DB_INTERNAL(ip);
    pgp = (struct rt_pg_internal *)ip->idb_ptr;
    RT_PG_CK_MAGIC(pgp);

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

    verts = (struct vertex **)bu_malloc(
	pgp->max_npts * sizeof(struct vertex *), "pg_tess verts[]");
    vertp = (struct vertex ***)bu_malloc(
	pgp->max_npts * sizeof(struct vertex **), "pg_tess vertp[]");
    for (i=0; i < pgp->max_npts; i++)
	vertp[i] = &verts[i];

    for (p = 0; p < pgp->npoly; p++) {
	struct rt_pg_face_internal *pp;

	pp = &pgp->poly[p];

	/* Locate these points, if previously mentioned */
	for (i=0; i < pp->npts; i++) {
	    verts[i] = nmg_find_pt_in_shell(s,
					    &pp->verts[3*i], tol);
	}

	/* Construct the face.  Verts should be in CCW order */
	if ((fu = nmg_cmface(s, vertp, pp->npts)) == (struct faceuse *)0) {
	    bu_log("rt_pg_tess() nmg_cmface failed, skipping face %zu\n",
		   p);
	}

	/* Associate vertex geometry, where none existed before */
	for (i=0; i < pp->npts; i++) {
	    if (verts[i]->vg_p) continue;
	    nmg_vertex_gv(verts[i], &pp->verts[3*i]);
	}

	/* Associate face geometry */
	if (nmg_calc_face_g(fu)) {
	    nmg_pr_fu_briefly(fu, "");
	    bu_free((char *)verts, "pg_tess verts[]");
	    bu_free((char *)vertp, "pg_tess vertp[]");
	    return -1;			/* FAIL */
	}
    }

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

    /* Polysolids are often built with incorrect face normals.
     * Don't depend on them here.
     */
    nmg_fix_normals(s, tol);
    bu_free((char *)verts, "pg_tess verts[]");
    bu_free((char *)vertp, "pg_tess vertp[]");

    return 0;		/* OK */
}
Ejemplo n.º 2
0
HIDDEN void
get_ctria3(void)
{
    int pid;
    int g1, g2, g3;
    int gin1, gin2, gin3;
    point_t pt1, pt2, pt3;
    struct vertex **v[3];
    struct faceuse *fu;
    struct shell *s;
    struct pshell *psh;
    int pid_index=0;

    pid = atoi(curr_rec[2]);

    pid_index = get_pid_index(pid);

    g1 = atoi(curr_rec[3]);

    g2 = atoi(curr_rec[4]);

    g3 = atoi(curr_rec[5]);

    gin1 = get_gridi(g1);
    gin2 = get_gridi(g2);
    gin3 = get_gridi(g3);

    v[0] = &g_pts[gin1].v[pid_index];
    v[1] = &g_pts[gin2].v[pid_index];
    v[2] = &g_pts[gin3].v[pid_index];

    VSCALE(pt1, g_pts[gin1].pt, conv[units]);
    VSCALE(pt2, g_pts[gin2].pt, conv[units]);
    VSCALE(pt3, g_pts[gin3].pt, conv[units]);

    if (!nmg_model && !pid) {
	struct nmgregion *r;

	nmg_model = nmg_mm();
	r = nmg_mrsv(nmg_model);
	nmg_shell = BU_LIST_FIRST(shell, &r->s_hd);
    }

    if (!pid)
	s = nmg_shell;
    else {
	int found=0;

	/* find pshell entry for this pid */
	for (BU_LIST_FOR(psh, pshell, &pshell_head.l)) {
	    if (psh->pid == pid) {
		found = 1;
		break;
	    }
	}

	if (!found) {
	    bu_log("Cannot find PSHELL entry for a CTRIA3 element (ignoring)!\n");
	    write_fields();
	    return;
	}

	if (psh->s)
	    s = psh->s;
	else {
	    struct model *m;
	    struct nmgregion *r;

	    m = nmg_mm();
	    r = nmg_mrsv(m);
	    s = BU_LIST_FIRST(shell, &r->s_hd);
	    psh->s = s;
	}
    }

    fu = nmg_cmface(s, v, 3);

    if (!g_pts[gin1].v[pid_index]->vg_p)
	nmg_vertex_gv(g_pts[gin1].v[pid_index], pt1);
    if (!g_pts[gin2].v[pid_index]->vg_p)
	nmg_vertex_gv(g_pts[gin2].v[pid_index], pt2);
    if (!g_pts[gin3].v[pid_index]->vg_p)
	nmg_vertex_gv(g_pts[gin3].v[pid_index], pt3);

    nmg_calc_face_g(fu);
}
Ejemplo n.º 3
0
/**
 * "Tessellate" an ARB into an NMG data structure.
 * Purely a mechanical transformation of one faceted object
 * into another.
 *
 * Returns -
 * -1 failure
 *  0 OK.  *r points to nmgregion that holds this tessellation.
 */
int
rt_arbn_tess(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct rt_tess_tol *UNUSED(ttol), const struct bn_tol *tol)
{
    struct rt_arbn_internal *aip;
    struct shell *s;
    struct faceuse **fu;		/* array of faceuses */
    size_t nverts;		/* maximum possible number of vertices = neqn!/(3!(neqn-3)! */
    size_t point_count = 0;	/* actual number of vertices */
    size_t face_count = 0;	/* actual number of faces built */
    size_t i, j, k, l, n;
    struct arbn_pts *pts;
    struct arbn_edges *edges;		/* A list of edges for each plane eqn (each face) */
    size_t *edge_count;	/* number of edges for each face */
    size_t max_edge_count; /* maximum number of edges for any face */
    struct vertex **verts;	/* Array of pointers to vertex structs */
    struct vertex ***loop_verts;	/* Array of pointers to vertex structs to pass to nmg_cmface */

    RT_CK_DB_INTERNAL(ip);
    aip = (struct rt_arbn_internal *)ip->idb_ptr;
    RT_ARBN_CK_MAGIC(aip);

    /* Allocate memory for the vertices */
    nverts = aip->neqn * (aip->neqn-1) * (aip->neqn-2) / 6;
    pts = (struct arbn_pts *)bu_calloc(nverts, sizeof(struct arbn_pts), "rt_arbn_tess: pts");

    /* Allocate memory for arbn_edges */
    edges = (struct arbn_edges *)bu_calloc(aip->neqn*aip->neqn, sizeof(struct arbn_edges) ,
					   "rt_arbn_tess: edges");
    edge_count = (size_t *)bu_calloc(aip->neqn, sizeof(size_t), "rt_arbn_tess: edge_count");

    /* Allocate memory for faceuses */
    fu = (struct faceuse **)bu_calloc(aip->neqn, sizeof(struct faceuse *), "rt_arbn_tess: fu");

    /* Calculate all vertices */
    for (i = 0; i < aip->neqn; i++) {
	for (j = i + 1; j < aip->neqn; j++) {
	    for (k = j + 1; k < aip->neqn; k++) {
		int keep_point = 1;

		if (bn_mkpoint_3planes(pts[point_count].pt, aip->eqn[i], aip->eqn[j], aip->eqn[k]))
		    continue;

		for (l = 0; l < aip->neqn; l++) {
		    if (l == i || l == j || l == k)
			continue;
		    if (DIST_PT_PLANE(pts[point_count].pt, aip->eqn[l]) > tol->dist) {
			keep_point = 0;
			break;
		    }
		}
		if (keep_point) {
		    pts[point_count].plane_no[0] = i;
		    pts[point_count].plane_no[1] = j;
		    pts[point_count].plane_no[2] = k;
		    point_count++;
		}
	    }
	}
    }

    /* Allocate memory for the NMG vertex pointers */
    verts = (struct vertex **)bu_calloc(point_count, sizeof(struct vertex *) ,
					"rt_arbn_tess: verts");

    /* Associate points with vertices */
    for (i = 0; i < point_count; i++)
	pts[i].vp = &verts[i];

    /* Check for duplicate points */
    for (i = 0; i < point_count; i++) {
	for (j = i + 1; j < point_count; j++) {
	    if (DIST_PT_PT_SQ(pts[i].pt, pts[j].pt) < tol->dist_sq) {
		/* These two points should point to the same vertex */
		pts[j].vp = pts[i].vp;
	    }
	}
    }

    /* Make list of edges for each face */
    for (i = 0; i < aip->neqn; i++) {
	/* look for a point that lies in this face */
	for (j = 0; j < point_count; j++) {
	    if (pts[j].plane_no[0] != (int)i
		&& pts[j].plane_no[1] != (int)i
		&& pts[j].plane_no[2] != (int)i)
		continue;

	    /* look for another point that shares plane "i" and another with this one */
	    for (k = j + 1; k < point_count; k++) {
		size_t match = (size_t)-1;
		size_t pt1, pt2;
		int duplicate = 0;

		/* skip points not on plane "i" */
		if (pts[k].plane_no[0] != (int)i
		    && pts[k].plane_no[1] != (int)i
		    && pts[k].plane_no[2] != (int)i)
		    continue;

		for (l = 0; l < 3; l++) {
		    for (n = 0; n < 3; n++) {
			if (pts[j].plane_no[l] == pts[k].plane_no[n]
			    && pts[j].plane_no[l] != (int)i) {
			    match = pts[j].plane_no[l];
			    break;
			}
		    }
		    if (match != (size_t)-1)
			break;
		}

		if (match == (size_t)-1)
		    continue;

		/* convert equivalent points to lowest point number */
		pt1 = j;
		pt2 = k;
		for (l = 0; l < pt1; l++) {
		    if (pts[pt1].vp == pts[l].vp) {
			pt1 = l;
			break;
		    }
		}
		for (l = 0; l < pt2; l++) {
		    if (pts[pt2].vp == pts[l].vp) {
			pt2 = l;
			break;
		    }
		}

		/* skip null edges */
		if (pt1 == pt2)
		    continue;

		/* check for duplicate edge */
		for (l = 0; l < edge_count[i]; l++) {
		    if ((edges[LOC(i, l)].v1_no == (int)pt1
			 && edges[LOC(i, l)].v2_no == (int)pt2)
			|| (edges[LOC(i, l)].v2_no == (int)pt1
			    && edges[LOC(i, l)].v1_no == (int)pt2))
		    {
			duplicate = 1;
			break;
		    }
		}
		if (duplicate)
		    continue;

		/* found an edge belonging to faces "i" and "match" */
		if (edge_count[i] == aip->neqn) {
		    bu_log("Too many edges found for one face\n");
		    goto fail;
		}
		edges[LOC(i, edge_count[i])].v1_no = pt1;
		edges[LOC(i, edge_count[i])].v2_no = pt2;
		edge_count[i]++;
	    }
	}
    }

    /* for each face, sort the list of edges into a loop */
    Sort_edges(edges, edge_count, aip);

    /* Get max number of edges for any face */
    max_edge_count = 0;
    for (i = 0; i < aip->neqn; i++)
	if (edge_count[i] > max_edge_count)
	    max_edge_count = edge_count[i];

    /* Allocate memory for array to pass to nmg_cmface */
    loop_verts = (struct vertex ***) bu_calloc(max_edge_count, sizeof(struct vertex **) ,
					       "rt_arbn_tess: loop_verts");

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

    /* Make the faces */
    for (i = 0; i < aip->neqn; i++) {
	int loop_length = 0;

	for (j = 0; j < edge_count[i]; j++) {
	    /* skip zero length edges */
	    if (pts[edges[LOC(i, j)].v1_no].vp == pts[edges[LOC(i, j)].v2_no].vp)
		continue;

	    /* put vertex pointers into loop_verts array */
	    loop_verts[loop_length] = pts[edges[LOC(i, j)].v2_no].vp;
	    loop_length++;
	}

	/* Make the face if there is are least 3 vertices */
	if (loop_length > 2)
	    fu[face_count++] = nmg_cmface(s, loop_verts, loop_length);
    }

    /* Associate vertex geometry */
    for (i = 0; i < point_count; i++) {
	if (!(*pts[i].vp))
	    continue;

	if ((*pts[i].vp)->vg_p)
	    continue;

	nmg_vertex_gv(*pts[i].vp, pts[i].pt);
    }

    bu_free((char *)pts, "rt_arbn_tess: pts");
    bu_free((char *)edges, "rt_arbn_tess: edges");
    bu_free((char *)edge_count, "rt_arbn_tess: edge_count");
    bu_free((char *)verts, "rt_arbn_tess: verts");
    bu_free((char *)loop_verts, "rt_arbn_tess: loop_verts");

    /* Associate face geometry */
    for (i = 0; i < face_count; i++) {
	if (nmg_fu_planeeqn(fu[i], tol)) {
	    bu_log("Failed to calculate face plane equation\n");
	    bu_free((char *)fu, "rt_arbn_tess: fu");
	    nmg_kr(*r);
	    *r = (struct nmgregion *)NULL;
	    return -1;
	}
    }

    bu_free((char *)fu, "rt_arbn_tess: fu");

    nmg_fix_normals(s, tol);

    (void)nmg_mark_edges_real(&s->l.magic);

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

    return 0;

fail:
    bu_free((char *)pts, "rt_arbn_tess: pts");
    bu_free((char *)edges, "rt_arbn_tess: edges");
    bu_free((char *)edge_count, "rt_arbn_tess: edge_count");
    bu_free((char *)verts, "rt_arbn_tess: verts");
    return -1;
}
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;
}
Ejemplo n.º 5
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);


}