/*
 *	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
/**
 * 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 */
}
Пример #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;
}
Пример #4
0
int
main(int argc, char **argv)
{
    int c;
    int i;
    struct pshell *psh;
    struct pbar *pbp;
    struct wmember head;
    struct wmember all_head;
    char *nastran_file = "Converted from NASTRAN file (stdin)";

    bu_setprogname(argv[0]);

    fpin = stdin;

    units = INCHES;

    /* FIXME: These need to be improved */
    tol.magic = BN_TOL_MAGIC;
    tol.dist = 0.0005;
    tol.dist_sq = tol.dist * tol.dist;
    tol.perp = 1e-6;
    tol.para = 1 - tol.perp;

    while ((c=bu_getopt(argc, argv, "x:X:t:ni:o:mh?")) != -1) {
	switch (c) {
	    case 'x':
		sscanf(bu_optarg, "%x", (unsigned int *)&RTG.debug);
		bu_printb("librt RT_G_DEBUG", RT_G_DEBUG, DEBUG_FORMAT);
		bu_log("\n");
		break;
	    case 'X':
		sscanf(bu_optarg, "%x", (unsigned int *)&RTG.NMG_debug);
		bu_printb("librt RTG.NMG_debug", RTG.NMG_debug, NMG_DEBUG_FORMAT);
		bu_log("\n");
		break;
	    case 't':		/* calculational tolerance */
		tol.dist = atof(bu_optarg);
		tol.dist_sq = tol.dist * tol.dist;
		break;
	    case 'n':
		polysolids = 0;
		break;
	    case 'm':
		units = MM;
		break;
	    case 'i':
		fpin = fopen(bu_optarg, "rb");
		if (fpin == (FILE *)NULL) {
		    bu_log("Cannot open NASTRAN file (%s) for reading!\n", bu_optarg);
		    bu_exit(1, Usage, argv[0]);
		}
		nastran_file = bu_optarg;
		break;
	    case 'o':
		output_file = bu_optarg;
		break;
	    default:
		bu_exit(1, Usage, argv[0]);
	}
    }

    fpout = wdb_fopen(output_file);
    if (fpout == NULL) {
	bu_log("Cannot open BRL-CAD file (%s) for writing!\n", output_file);
	bu_exit(1, Usage, argv[0]);
    }

    if (!fpin || !fpout) {
	bu_exit(1, Usage, argv[0]);
    }

    line = (char *)bu_malloc(MAX_LINE_SIZE, "line");
    next_line = (char *)bu_malloc(MAX_LINE_SIZE, "next_line");
    prev_line = (char *)bu_malloc(MAX_LINE_SIZE, "prev_line");
    curr_rec = (char **)bu_calloc(NO_OF_FIELDS, sizeof(char *), "curr_rec");
    for (i=0; i<NO_OF_FIELDS; i++)
	curr_rec[i] = (char *)bu_malloc(sizeof(char)*FIELD_LENGTH, "curr_rec[i]");
    prev_rec = (char **)bu_calloc(NO_OF_FIELDS, sizeof(char *), "prev_rec");
    for (i=0; i<NO_OF_FIELDS; i++)
	prev_rec[i] = (char *)bu_malloc(sizeof(char)*FIELD_LENGTH, "prev_rec[i]");

    /* first pass, find start of NASTRAN "bulk data" */
    start_off = (-1);
    bulk_data_start_line = 0;
    while (bu_fgets(line, MAX_LINE_SIZE, fpin)) {
	bulk_data_start_line++;
	if (bu_strncmp(line, "BEGIN BULK", 10))
	    continue;

	start_off = bu_ftell(fpin);
	break;
    }

    if (start_off < 0) {
	bu_log("Cannot find start of bulk data in NASTRAN file!\n");
	bu_exit(1, Usage, argv[0]);
    }

    /* convert BULK data deck into something reasonable */
    fptmp = bu_temp_file(NULL, 0);
    if (fptmp == NULL) {
	perror(argv[0]);
	bu_exit(1, "Cannot open temporary file\n");
    }
    convert_input();

    /* initialize some lists */
    BU_LIST_INIT(&coord_head.l);
    BU_LIST_INIT(&pbar_head.l);
    BU_LIST_INIT(&pshell_head.l);
    BU_LIST_INIT(&all_head.l);

    nmg_model = (struct model *)NULL;

    /* count grid points */
    bu_fseek(fptmp, 0, SEEK_SET);
    while (bu_fgets(line, MAX_LINE_SIZE, fptmp)) {
	if (!bu_strncmp(line, "GRID", 4))
	    grid_count++;
    }
    if (!grid_count) {
	bu_exit(1, "No geometry in this NASTRAN file!\n");
    }

    /* get default values and properties */
    bu_fseek(fptmp, 0, SEEK_SET);
    while (get_next_record(fptmp, 1, 0)) {
	if (!bu_strncmp(curr_rec[0], "BAROR", 5)) {
	    /* get BAR defaults */
	    bar_def_pid = atoi(curr_rec[2]);
	} else if (!bu_strncmp(curr_rec[0], "PBAR", 4)) {
	    struct pbar *pb;

	    BU_ALLOC(pb, struct pbar);

	    pb->pid = atoi(curr_rec[1]);
	    pb->mid = atoi(curr_rec[2]);
	    pb->area = atof(curr_rec[3]);

	    BU_LIST_INIT(&pb->head.l);

	    BU_LIST_INSERT(&pbar_head.l, &pb->l);
	} else if (!bu_strncmp(curr_rec[0], "PSHELL", 6)) {
	    BU_ALLOC(psh, struct pshell);

	    psh->s = (struct shell *)NULL;
	    psh->pid = atoi(curr_rec[1]);
	    psh->mid = atoi(curr_rec[2]);
	    psh->thick = atof(curr_rec[3]);
	    BU_LIST_INSERT(&pshell_head.l, &psh->l);
	    pshell_count++;
	}
    }

    /* allocate storage for grid points */
    g_pts = (struct grid_point *)bu_calloc(grid_count, sizeof(struct grid_point), "grid points");

    /* get all grid points */
    bu_fseek(fptmp, 0, SEEK_SET);
    while (get_next_record(fptmp, 1, 0)) {
	int gid;
	int cid;
	double tmp[3];

	if (bu_strncmp(curr_rec[0], "GRID", 4))
	    continue;

	gid = atoi(curr_rec[1]);
	cid = atoi(curr_rec[2]);

	for (i=0; i<3; i++) {
	    tmp[i] = atof(curr_rec[i+3]);
	}

	g_pts[grid_used].gid = gid;
	g_pts[grid_used].cid = cid;
	g_pts[grid_used].v = (struct vertex **)bu_calloc(pshell_count + 1, sizeof(struct vertex *), "g_pts vertex array");
	VMOVE(g_pts[grid_used].pt, tmp);
	grid_used++;
    }


    /* find coordinate systems */
    bu_fseek(fptmp, 0, SEEK_SET);
    while (get_next_record(fptmp, 1, 0)) {
	if (bu_strncmp(curr_rec[0], "CORD", 4))
	    continue;

	get_coord_sys();
    }
    /* convert everything to BRL-CAD coordinate system */
    i = 0;
    while (convert_all_cs() || convert_all_pts()) {
	i++;
	if (i > 10) {
	    bu_exit(1, "Cannot convert to default coordinate system, check for circular definition\n");
	}
    }

    mk_id(fpout, nastran_file);

    /* get elements */
    bu_fseek(fptmp, 0, SEEK_SET);
    while (get_next_record(fptmp, 1, 0)) {
	if (!bu_strncmp(curr_rec[0], "CBAR", 4))
	    get_cbar();
	else if (!bu_strncmp(curr_rec[0], "CROD", 4))
	    get_cbar();
	else if (!bu_strncmp(curr_rec[0], "CTRIA3", 6))
	    get_ctria3();
	else if (!bu_strncmp(curr_rec[0], "CQUAD4", 6))
	    get_cquad4();
    }

    if (nmg_model) {
	nmg_rebound(nmg_model, &tol);
	if (polysolids)
	    mk_bot_from_nmg(fpout, "pshell.0", nmg_shell);
	else
	    mk_nmg(fpout, "pshell.0", nmg_model);
    }

    BU_LIST_INIT(&head.l);
    for (BU_LIST_FOR(psh, pshell, &pshell_head.l)) {
	struct model *m;
	char name[NAMESIZE+1];

	if (!psh->s)
	    continue;

	m = nmg_find_model(&psh->s->l.magic);
	nmg_rebound(m, &tol);
	nmg_fix_normals(psh->s, &tol);
	if (psh->thick > tol.dist) {
	    nmg_model_face_fuse(m, &tol);
	    nmg_hollow_shell(psh->s, psh->thick*conv[units], 1, &tol);
	}
	sprintf(name, "pshell.%d", psh->pid);
	if (polysolids)
	    mk_bot_from_nmg(fpout, name, psh->s);
	else
	    mk_nmg(fpout, name, m);

	mk_addmember(name, &head.l, NULL, WMOP_UNION);
    }
    if (BU_LIST_NON_EMPTY(&head.l)) {
	mk_lfcomb(fpout, "shells", &head, 0);
	mk_addmember("shells", &all_head.l, NULL, WMOP_UNION);
    }

    BU_LIST_INIT(&head.l);
    for (BU_LIST_FOR(pbp, pbar, &pbar_head.l)) {
	char name[NAMESIZE+1];

	if (BU_LIST_IS_EMPTY(&pbp->head.l))
	    continue;

	sprintf(name, "pbar_group.%d", pbp->pid);
	mk_lfcomb(fpout, name, &pbp->head, 0);

	mk_addmember(name, &head.l, NULL, WMOP_UNION);
    }
    if (BU_LIST_NON_EMPTY(&head.l)) {
	mk_lfcomb(fpout, "pbars", &head, 0);
	mk_addmember("pbars", &all_head.l, NULL, WMOP_UNION);
    }

    if (BU_LIST_NON_EMPTY(&all_head.l)) {
	mk_lfcomb(fpout, "all", &all_head, 0);
    }
    wdb_close(fpout);
    return 0;
}
int
brep(int entityno)
{

    int sol_num;		/* IGES solid type number */
    int shell_de;		/* Directory sequence number for a shell */
    int orient;			/* Orientation of shell */
    int *void_shell_de;		/* Directory sequence number for an void shell */
    int *void_orient;		/* Orientation of void shell */
    int num_of_voids;		/* Number of inner void shells */
    struct model *m;			/* NMG model */
    struct nmgregion *r;			/* NMG region */
    struct shell **void_shells;		/* List of void shells */
    struct shell *s_outer;		/* Outer shell */
    struct iges_vertex_list *v_list;
    struct iges_edge_list *e_list;
    int i;

    /* 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 , "");
    Readint(&shell_de , "");
    Readint(&orient , "");
    Readint(&num_of_voids , "");

    if (num_of_voids) {
	void_shell_de = (int *)bu_calloc(num_of_voids , sizeof(int) , "BREP: void shell DE's");
	void_orient = (int *)bu_calloc(num_of_voids , sizeof(int) , "BREP: void shell orients");
	void_shells = (struct shell **)bu_calloc(num_of_voids , sizeof(struct shell *) , "BREP: void shell pointers");
	for (i = 0; i < num_of_voids; i++) {
	    Readint(&void_shell_de[i] , "");
	    Readint(&void_orient[i] , "");
	}
    } else {
	void_shell_de = NULL;
	void_orient = NULL;
	void_shells = NULL;
    }

    /* start building */
    m = nmg_mmr();
    r = BU_LIST_FIRST(nmgregion, &m->r_hd);

    /* Put outer shell in region */
    if ((s_outer = Get_outer_shell(r , (shell_de - 1)/2)) == (struct shell *)NULL)
	goto err;

    ON_Brep* outer = ON_Brep::New();
    if (Get_outer_brep(outer, (shell_de - 1)/2, orient))
	goto err;


    /* Put voids in */
    for (i = 0; i < num_of_voids; i++) {
	if ((void_shells[i] = Add_inner_shell(r, (void_shell_de[i] - 1)/2))
	    == (struct shell *)NULL)
	    goto err;
    }

    /* orient loops */
    Orient_loops(r);

    /* orient shells */
    nmg_fix_normals(s_outer , &tol);
    for (i = 0; i < num_of_voids; i++) {
	nmg_fix_normals(void_shells[i] , &tol);
	nmg_invert_shell(void_shells[i]);
    }

    if (do_bots) {
	/* Merge all shells into one */
	for (i = 0; i < num_of_voids; i++)
	    nmg_js(s_outer, void_shells[i], &tol);

	/* write out BOT */
	if (mk_bot_from_nmg(fdout, dir[entityno]->name, s_outer))
	    goto err;
    } else {
	/* Compute "geometry" for region and shell */
	nmg_region_a(r , &tol);

	/* Write NMG solid */
	if (mk_nmg(fdout , dir[entityno]->name , m))
	    goto err;
    }

    if (num_of_voids) {
	bu_free((char *)void_shell_de , "BREP: void shell DE's");
	bu_free((char *)void_orient , "BREP: void shell orients");
	bu_free((char *)void_shells , "brep: void shell list");
    }

    v_list = vertex_root;
    while (v_list != NULL) {
	bu_free((char *)v_list->i_verts , "brep: iges_vertex");
	bu_free((char *)v_list , "brep: vertex list");
	v_list = v_list->next;
    }
    vertex_root = NULL;

    e_list = edge_root;
    while (e_list != NULL) {
	bu_free((char *)e_list->i_edge , "brep:iges_edge");
	bu_free((char *)e_list , "brep: edge list");
	e_list = e_list->next;
    }
    edge_root = NULL;
    return 1;

    err :
	if (num_of_voids) {
	    bu_free((char *)void_shell_de , "BREP: void shell DE's");
	    bu_free((char *)void_orient , "BREP: void shell orients");
	    bu_free((char *)void_shells , "brep: void shell list");
	}
    nmg_km(m);
    return 0;
}