Exemple #1
0
int
coplanar_2d_to_3d(point_t **points_3d, const point_t *origin_pnt,
		     const vect_t *u_axis, const vect_t *v_axis,
		     const point2d_t *points_2d, int n)
{
int i;
    vect_t u_x_component, u_y_component, u_z_component;
    vect_t v_x_component, v_y_component, v_z_component;
    vect_t x_axis, y_axis, z_axis;
    vect_t temp;
    fastf_t mag_u_x, mag_u_y, mag_u_z;
    fastf_t mag_v_x, mag_v_y, mag_v_z;
    VSET(x_axis, 1.0, 0.0, 0.0);
    VSET(y_axis, 0.0, 1.0, 0.0);
    VSET(z_axis, 0.0, 0.0, 1.0);
    /* Step 1 - find the 3d X, Y and Z components of u_axis and v_axis */
    VPROJECT(*u_axis, x_axis, u_x_component, temp);
    VPROJECT(temp, y_axis, u_y_component, u_z_component);
    VPROJECT(*v_axis, x_axis, v_x_component, temp);
    VPROJECT(temp, y_axis, v_y_component, v_z_component);
    mag_u_x = (VDOT(u_x_component, x_axis) > 0.0) ? (MAGNITUDE(u_x_component)) : (-1.0 * MAGNITUDE(u_x_component));
    mag_u_y = (VDOT(u_y_component, y_axis) > 0.0) ? (MAGNITUDE(u_y_component)) : (-1.0 * MAGNITUDE(u_y_component));
    mag_u_z = (VDOT(u_z_component, z_axis) > 0.0) ? (MAGNITUDE(u_z_component)) : (-1.0 * MAGNITUDE(u_z_component));
    mag_v_x = (VDOT(v_x_component, x_axis) > 0.0) ? (MAGNITUDE(v_x_component)) : (-1.0 * MAGNITUDE(v_x_component));
    mag_v_y = (VDOT(v_y_component, y_axis) > 0.0) ? (MAGNITUDE(v_y_component)) : (-1.0 * MAGNITUDE(v_y_component));
    mag_v_z = (VDOT(v_z_component, z_axis) > 0.0) ? (MAGNITUDE(v_z_component)) : (-1.0 * MAGNITUDE(v_z_component));

    /* Step 2 - for each 2D point, calculate the (x,y,z) coordinates as follows:
     * (http://math.stackexchange.com/questions/525829/how-to-find-the-3d-coordinate-of-a-2d-point-on-a-known-plane)
     */
    for (i = 0; i < n; i++) {
	vect_t temp_2d;
	VSET(temp_2d, points_2d[i][0]*mag_u_x + (points_2d)[i][1]*mag_v_x,
		(points_2d)[i][0]*mag_u_y + (points_2d)[i][1]*mag_v_y,
		(points_2d)[i][0]*mag_u_z + (points_2d)[i][1]*mag_v_z);
	VADD2((*points_3d)[i], (*origin_pnt), temp_2d);
    }

    return 0;
}
Exemple #2
0
int
coplanar_3d_to_2d(point2d_t **points_2d, const point_t *origin_pnt,
		     const vect_t *u_axis, const vect_t *v_axis,
		     const point_t *points_3d, int n)
{
    int i = 0;
    for (i = 0; i < n; i++) {
	vect_t temp, c, d;
	fastf_t u, v;
	VSUB2(temp, points_3d[i], *origin_pnt);
	VPROJECT(temp, *u_axis, c, d);
	u = (VDOT(c, *u_axis) > 0.0) ? (MAGNITUDE(c)) : (-1.0 * MAGNITUDE(c));
	v = (VDOT(d, *v_axis) > 0.0) ? (MAGNITUDE(d)) : (-1.0 * MAGNITUDE(d));
	V2SET((*points_2d)[i], u, v);
    }

    return 0;
}
Exemple #3
0
extern "C" void
rt_nmg_brep(ON_Brep **b, const struct rt_db_internal *ip, const struct bn_tol *tol)
{
    struct model *m;
    struct nmgregion *r;
    struct shell *s;
    struct faceuse *fu;
    struct loopuse *lu;
    struct edgeuse *eu;

    int edge_index;
    long* brepi;

    RT_CK_DB_INTERNAL(ip);
    m = (struct model *)ip->idb_ptr;
    NMG_CK_MODEL(m);

    brepi = static_cast<long*>(bu_malloc(m->maxindex * sizeof(long), "rt_nmg_brep: brepi[]"));
    for (int i = 0; i < m->maxindex; i++) brepi[i] = -INT_MAX;

    for (BU_LIST_FOR(r, nmgregion, &m->r_hd)) {
	for (BU_LIST_FOR(s, shell, &r->s_hd)) {
	    for (BU_LIST_FOR(fu, faceuse, &s->fu_hd)) {
		NMG_CK_FACEUSE(fu);
		if (fu->orientation != OT_SAME) continue;

		// Need to create ON_NurbsSurface based on plane of
		// face in order to have UV space in which to define
		// trimming loops.  Bounding points are NOT on the
		// face plane, so another approach must be used.
		//
		// General approach: For all loops in the faceuse,
		// collect all the vertices.  Find the center point of
		// all the vertices, and search for the point with the
		// greatest distance from that center point.  Once
		// found, cross the vector between the center point
		// and furthest point with the normal of the face and
		// scale the resulting vector to have the same length
		// as the vector to the furthest point.  Add the two
		// resulting vectors to find the first corner point.
		// Mirror the first corner point across the center to
		// find the second corner point.  Cross the two
		// vectors created by the first two corner points with
		// the face normal to get the vectors of the other two
		// corners, and scale the resulting vectors to the
		// same magnitude as the first two.  These four points
		// bound all vertices on the plane and form a suitable
		// staring point for a UV space, since all points on
		// all the edges are equal to or further than the
		// distance between the furthest vertex and the center
		// point.

		// ............. .............
		// .           .* .          .
		// .         .  .    .       .
		// .        .   .      .     .
		// .       .    .       *    .
		// .      .     .       .    .
		// .     .      .       .    .
		// .    .       .       .    .
		// .   *        *       .    .
		// .   .                .    .
		// .   .                .    .
		// .   .                .    .
		// .   *.               .    .
		// .     ...        ...*     .
		// .       .... ....         .
		// .           *             .
		// ...........................
		//


		const struct face_g_plane *fg = fu->f_p->g.plane_p;
		struct bu_ptbl vert_table;
		nmg_tabulate_face_g_verts(&vert_table, fg);
		point_t tmppt, center, max_pt;
		struct vertex **pt;

		VSET(tmppt, 0, 0, 0);
		VSET(max_pt, 0, 0, 0);

		int ptcnt = 0;
		for (BU_PTBL_FOR(pt, (struct vertex **), &vert_table)) {
		    tmppt[0] += (*pt)->vg_p->coord[0];
		    tmppt[1] += (*pt)->vg_p->coord[1];
		    tmppt[2] += (*pt)->vg_p->coord[2];
		    ptcnt++;
		    if (brepi[(*pt)->vg_p->index] == -INT_MAX) {
			ON_BrepVertex& vert = (*b)->NewVertex((*pt)->vg_p->coord, SMALL_FASTF);
			brepi[(*pt)->vg_p->index] = vert.m_vertex_index;
		    }
		}
		VSET(center, tmppt[0]/ptcnt, tmppt[1]/ptcnt, tmppt[2]/ptcnt);
		fastf_t max_dist = 0.0;
		fastf_t curr_dist;
		for (BU_PTBL_FOR(pt, (struct vertex **), &vert_table)) {
		    tmppt[0] = (*pt)->vg_p->coord[0];
		    tmppt[1] = (*pt)->vg_p->coord[1];
		    tmppt[2] = (*pt)->vg_p->coord[2];
		    curr_dist = DIST_PT_PT(center, tmppt);
		    if (curr_dist > max_dist) {
			max_dist = curr_dist;
			VMOVE(max_pt, tmppt);
		    }
		}
		bu_ptbl_free(&vert_table);
		int ccw = 0;
		vect_t vtmp, uv1, uv2, uv3, uv4, vnormal;
		// If an outer loop is found in the nmg with a cw
		// orientation, use a flipped normal to form the NURBS
		// surface
		for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd)) {
		    if (lu->orientation == OT_SAME && nmg_loop_is_ccw(lu, fg->N, tol) == -1) ccw = -1;
		}
		if (ccw != -1) {
		    VSET(vnormal, fg->N[0], fg->N[1], fg->N[2]);
		} else {
		    VSET(vnormal, -fg->N[0], -fg->N[1], -fg->N[2]);
		}
		VSUB2(uv1, max_pt, center);
		VCROSS(vtmp, uv1, vnormal);
		VADD2(uv1, uv1, vtmp);
		VCROSS(uv2, uv1, vnormal);
		VREVERSE(uv3, uv1);
		VCROSS(uv4, uv3, vnormal);
		VADD2(uv1, uv1, center);
		VADD2(uv2, uv2, center);
		VADD2(uv3, uv3, center);
		VADD2(uv4, uv4, center);

		ON_3dPoint p1 = ON_3dPoint(uv1);
		ON_3dPoint p2 = ON_3dPoint(uv2);
		ON_3dPoint p3 = ON_3dPoint(uv3);
		ON_3dPoint p4 = ON_3dPoint(uv4);

		(*b)->m_S.Append(sideSurface(p1, p4, p3, p2));
		ON_Surface *surf = (*(*b)->m_S.Last());
		int surfindex = (*b)->m_S.Count();

		// Now that we have the surface, define the face
		ON_BrepFace& face = (*b)->NewFace(surfindex - 1);

		// With the surface and the face defined, make
		// trimming loops and create faces.  To generate UV
		// coordinates for each from and to for the
		// edgecurves, the UV origin is defined to be v1,
		// v1->v2 is defined as the U domain, and v1->v4 is
		// defined as the V domain.
		vect_t u_axis, v_axis;
		VSUB2(u_axis, uv2, uv1);
		VSUB2(v_axis, uv4, uv1);
		fastf_t u_axis_dist = MAGNITUDE(u_axis);
		fastf_t v_axis_dist = MAGNITUDE(v_axis);

		// Now that the surface context is set up, add the loops.
		for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd)) {
		    int edges=0;
		    if (BU_LIST_FIRST_MAGIC(&lu->down_hd) != NMG_EDGEUSE_MAGIC) continue; // loop is a single vertex
		    ON_BrepLoop::TYPE looptype;
		    // Check if this is an inner or outer loop
		    if (lu->orientation == OT_SAME) {
			looptype = ON_BrepLoop::outer;
		    } else {
			looptype = ON_BrepLoop::inner;
		    }
		    ON_BrepLoop& loop = (*b)->NewLoop(looptype, face);
		    for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) {
			++edges;
			vect_t ev1, ev2;
			struct vertex_g *vg1, *vg2;
			vg1 = eu->vu_p->v_p->vg_p;
			NMG_CK_VERTEX_G(vg1);
			int vert1 = brepi[vg1->index];
			VMOVE(ev1, vg1->coord);
			vg2 = eu->eumate_p->vu_p->v_p->vg_p;
			NMG_CK_VERTEX_G(vg2);
			int vert2 = brepi[vg2->index];
			VMOVE(ev2, vg2->coord);
			// Add edge if not already added
			if (brepi[eu->e_p->index] == -INT_MAX) {
			    /* always add edges with the small vertex index as from */
			    if (vg1->index > vg2->index) {
				int tmpvert = vert1;
				vert1 = vert2;
				vert2 = tmpvert;
			    }
			    // Create and add 3D curve
			    ON_Curve* c3d = new ON_LineCurve((*b)->m_V[vert1].Point(), (*b)->m_V[vert2].Point());
			    c3d->SetDomain(0.0, 1.0);
			    (*b)->m_C3.Append(c3d);
			    // Create and add 3D edge
			    ON_BrepEdge& e = (*b)->NewEdge((*b)->m_V[vert1], (*b)->m_V[vert2] , (*b)->m_C3.Count() - 1);
			    e.m_tolerance = 0.0;
			    brepi[eu->e_p->index] = e.m_edge_index;
			}
			// Regardless of whether the edge existed as
			// an object, it needs to be added to the
			// trimming loop
			vect_t u_component, v_component;
			ON_3dPoint vg1pt(vg1->coord);
			int orientation = 0;
			edge_index = brepi[eu->e_p->index];
			if (vg1pt !=  (*b)->m_V[(*b)->m_E[edge_index].m_vi[0]].Point()) {
			    orientation = 1;
			}
			// Now, make 2d trimming curves
			vect_t vect1, vect2;
			VSUB2(vect1, ev1, uv1);
			VSUB2(vect2, ev2, uv1);
			ON_2dPoint from_uv, to_uv;
			double u0, u1, v0, v1;
			surf->GetDomain(0, &u0, &u1);
			surf->GetDomain(1, &v0, &v1);

			VPROJECT(vect1, u_axis, u_component, v_component);
			from_uv.y = u0 + MAGNITUDE(u_component)/u_axis_dist*(u1-u0);
			from_uv.x = v0 + MAGNITUDE(v_component)/v_axis_dist*(v1-v0);
			VPROJECT(vect2, u_axis, u_component, v_component);
			to_uv.y = u0 + MAGNITUDE(u_component)/u_axis_dist*(u1-u0);
			to_uv.x = v0 + MAGNITUDE(v_component)/v_axis_dist*(v1-v0);
			ON_3dPoint S1, S2;
			ON_3dVector Su, Sv;
			surf->Ev1Der(from_uv.x, from_uv.y, S1, Su, Sv);
			surf->Ev1Der(to_uv.x, to_uv.y, S2, Su, Sv);
			ON_Curve* c2d =  new ON_LineCurve(from_uv, to_uv);
			c2d->SetDomain(0.0, 1.0);
			int c2i = (*b)->m_C2.Count();
			(*b)->m_C2.Append(c2d);
			edge_index = brepi[eu->e_p->index];
			ON_BrepTrim& trim = (*b)->NewTrim((*b)->m_E[edge_index], orientation, loop, c2i);
			trim.m_type = ON_BrepTrim::mated;
			trim.m_tolerance[0] = 0.0;
			trim.m_tolerance[1] = 0.0;
		    }
		}
	    }
	    (*b)->SetTrimIsoFlags();
	}
    }

    bu_free(brepi, "rt_nmg_brep: brepi[]");
}
Exemple #4
0
extern "C" void
rt_hyp_brep(ON_Brep **b, const struct rt_db_internal *ip, const struct bn_tol *)
{
    struct rt_hyp_internal *eip;

    RT_CK_DB_INTERNAL(ip);
    eip = (struct rt_hyp_internal *)ip->idb_ptr;
    RT_HYP_CK_MAGIC(eip);

    point_t p1_origin, p2_origin;
    ON_3dPoint plane1_origin, plane2_origin;
    ON_3dVector plane_x_dir, plane_y_dir;

    //  First, find planes corresponding to the top and bottom faces - initially

    vect_t x_dir, y_dir;
    VMOVE(x_dir, eip->hyp_A);
    VCROSS(y_dir, eip->hyp_A, eip->hyp_Hi);
    VREVERSE(y_dir, y_dir);

    VMOVE(p1_origin, eip->hyp_Vi);
    plane1_origin = ON_3dPoint(p1_origin);
    plane_x_dir = ON_3dVector(x_dir);
    plane_y_dir = ON_3dVector(y_dir);
    const ON_Plane hyp_bottom_plane(plane1_origin, plane_x_dir, plane_y_dir);

    VADD2(p2_origin, eip->hyp_Vi, eip->hyp_Hi);
    plane2_origin = ON_3dPoint(p2_origin);
    const ON_Plane hyp_top_plane(plane2_origin, plane_x_dir, plane_y_dir);

    // Next, create ellipses in the planes corresponding to the edges of the hyp

    ON_Ellipse b_ell(hyp_bottom_plane, MAGNITUDE(eip->hyp_A), eip->hyp_b);
    ON_NurbsCurve* bcurve = ON_NurbsCurve::New();
    b_ell.GetNurbForm((*bcurve));
    bcurve->SetDomain(0.0, 1.0);

    ON_Ellipse t_ell(hyp_top_plane, MAGNITUDE(eip->hyp_A), eip->hyp_b);
    ON_NurbsCurve* tcurve = ON_NurbsCurve::New();
    t_ell.GetNurbForm((*tcurve));
    tcurve->SetDomain(0.0, 1.0);

    // Generate the bottom cap
    ON_SimpleArray<ON_Curve*> boundary;
    boundary.Append(ON_Curve::Cast(bcurve));
    ON_PlaneSurface* bp = new ON_PlaneSurface();
    bp->m_plane = hyp_bottom_plane;
    bp->SetDomain(0, -100.0, 100.0);
    bp->SetDomain(1, -100.0, 100.0);
    bp->SetExtents(0, bp->Domain(0));
    bp->SetExtents(1, bp->Domain(1));
    (*b)->m_S.Append(bp);
    const int bsi = (*b)->m_S.Count() - 1;
    ON_BrepFace& bface = (*b)->NewFace(bsi);
    (*b)->NewPlanarFaceLoop(bface.m_face_index, ON_BrepLoop::outer, boundary, true);
    const ON_BrepLoop* bloop = (*b)->m_L.Last();
    bp->SetDomain(0, bloop->m_pbox.m_min.x, bloop->m_pbox.m_max.x);
    bp->SetDomain(1, bloop->m_pbox.m_min.y, bloop->m_pbox.m_max.y);
    bp->SetExtents(0, bp->Domain(0));
    bp->SetExtents(1, bp->Domain(1));
    (*b)->FlipFace(bface);
    (*b)->SetTrimIsoFlags(bface);
    boundary.Empty();
    delete bcurve;

    // Generate the top cap
    boundary.Append(ON_Curve::Cast(tcurve));
    ON_PlaneSurface* tp = new ON_PlaneSurface();
    tp->m_plane = hyp_top_plane;
    tp->SetDomain(0, -100.0, 100.0);
    tp->SetDomain(1, -100.0, 100.0);
    tp->SetExtents(0, bp->Domain(0));
    tp->SetExtents(1, bp->Domain(1));
    (*b)->m_S.Append(tp);
    int tsi = (*b)->m_S.Count() - 1;
    ON_BrepFace& tface = (*b)->NewFace(tsi);
    (*b)->NewPlanarFaceLoop(tface.m_face_index, ON_BrepLoop::outer, boundary, true);
    ON_BrepLoop* tloop = (*b)->m_L.Last();
    tp->SetDomain(0, tloop->m_pbox.m_min.x, tloop->m_pbox.m_max.x);
    tp->SetDomain(1, tloop->m_pbox.m_min.y, tloop->m_pbox.m_max.y);
    tp->SetExtents(0, bp->Domain(0));
    tp->SetExtents(1, bp->Domain(1));
    (*b)->SetTrimIsoFlags(tface);
    delete tcurve;

    //  Now, the hard part.  Need an elliptical hyperbolic NURBS surface.
    //  First step is to create a nurbs curve.

    double MX = eip->hyp_b * eip->hyp_bnr;
    point_t ep1, ep2, ep3;
    VSET(ep1, -eip->hyp_b, 0, 0.5*MAGNITUDE(eip->hyp_Hi));
    VSET(ep2, -MX*eip->hyp_bnr, 0, 0);
    VSET(ep3, -eip->hyp_b, 0, -0.5*MAGNITUDE(eip->hyp_Hi));

    ON_3dPoint onp1 = ON_3dPoint(ep1);
    ON_3dPoint onp2 = ON_3dPoint(ep2);
    ON_3dPoint onp3 = ON_3dPoint(ep3);

    ON_3dPointArray cpts(3);
    cpts.Append(onp1);
    cpts.Append(onp2);
    cpts.Append(onp3);
    ON_BezierCurve *bezcurve = new ON_BezierCurve(cpts);
    bezcurve->MakeRational();
    bezcurve->SetWeight(1, bezcurve->Weight(0)/eip->hyp_bnr);

    ON_NurbsCurve* tnurbscurve = ON_NurbsCurve::New();
    bezcurve->GetNurbForm(*tnurbscurve);
    delete bezcurve;

    ON_3dPoint revpnt1 = ON_3dPoint(0, 0, -0.5*MAGNITUDE(eip->hyp_Hi));
    ON_3dPoint revpnt2 = ON_3dPoint(0, 0, 0.5*MAGNITUDE(eip->hyp_Hi));

    ON_Line revaxis = ON_Line(revpnt1, revpnt2);
    ON_RevSurface* hyp_surf = ON_RevSurface::New();
    hyp_surf->m_curve = tnurbscurve;
    hyp_surf->m_axis = revaxis;
    hyp_surf->m_angle = ON_Interval(0, 2*ON_PI);

    // Get the NURBS form of the surface
    ON_NurbsSurface *hypcurvedsurf = ON_NurbsSurface::New();
    hyp_surf->GetNurbForm(*hypcurvedsurf, 0.0);
    delete hyp_surf;

    for (int i = 0; i < hypcurvedsurf->CVCount(0); i++) {
	for (int j = 0; j < hypcurvedsurf->CVCount(1); j++) {
	    point_t cvpt;
	    ON_4dPoint ctrlpt;
	    hypcurvedsurf->GetCV(i, j, ctrlpt);

	    // Scale and shear
	    vect_t proj_ah;
	    vect_t proj_ax;
	    fastf_t factor;

	    VPROJECT(eip->hyp_A, eip->hyp_Hi, proj_ah, proj_ax);
	    VSET(cvpt, ctrlpt.x * MAGNITUDE(proj_ax)/eip->hyp_b, ctrlpt.y, ctrlpt.z);
	    factor = VDOT(eip->hyp_A, eip->hyp_Hi)>0 ? 1.0 : -1.0;
	    cvpt[2] += factor*cvpt[0]/MAGNITUDE(proj_ax)*MAGNITUDE(proj_ah) + 0.5*MAGNITUDE(eip->hyp_Hi)*ctrlpt.w;

	    // Rotate
	    vect_t Au, Bu, Hu;
	    mat_t R;
	    point_t new_cvpt;

	    VSCALE(Bu, y_dir, 1/MAGNITUDE(y_dir));
	    VSCALE(Hu, eip->hyp_Hi, 1/MAGNITUDE(eip->hyp_Hi));
	    VCROSS(Au, Bu, Hu);
	    VUNITIZE(Au);
	    MAT_IDN(R);
	    VMOVE(&R[0], Au);
	    VMOVE(&R[4], Bu);
	    VMOVE(&R[8], Hu);
	    VEC3X3MAT(new_cvpt, cvpt, R);
	    VMOVE(cvpt, new_cvpt);

	    // Translate
	    vect_t scale_v;
	    VSCALE(scale_v, eip->hyp_Vi, ctrlpt.w);
	    VADD2(cvpt, cvpt, scale_v);
	    ON_4dPoint newpt = ON_4dPoint(cvpt[0], cvpt[1], cvpt[2], ctrlpt.w);
	    hypcurvedsurf->SetCV(i, j, newpt);
	}
    }

    (*b)->m_S.Append(hypcurvedsurf);
    int surfindex = (*b)->m_S.Count();
    ON_BrepFace& face = (*b)->NewFace(surfindex - 1);
    (*b)->FlipFace(face);
    int faceindex = (*b)->m_F.Count();
    (*b)->NewOuterLoop(faceindex-1);

}
HIDDEN int
nmg_brep_face(ON_Brep **b, const struct faceuse *fu, const struct bn_tol *tol, long *brepi) {
    const struct face_g_plane *fg = fu->f_p->g.plane_p;
    struct bu_ptbl vert_table;
    struct vertex **pt;
    int ret = 0;
    int pnt_cnt = 0;
    int pnt_index = 0;
    vect_t u_axis, v_axis;
    point_t obr_center;
    point_t *points_3d = NULL;
    point_t *points_obr = NULL;
    struct loopuse *lu;
    struct edgeuse *eu;

    /* Find out how many points we have, set up any uninitialized ON_Brep vertex
     * structures, and prepare a map of NMG index values to the point array indices */
    nmg_tabulate_face_g_verts(&vert_table, fg);

    for (BU_PTBL_FOR(pt, (struct vertex **), &vert_table)) {
	if (brepi[(*pt)->vg_p->index] == -INT_MAX) {
	    ON_BrepVertex& vert = (*b)->NewVertex((*pt)->vg_p->coord, SMALL_FASTF);
	    brepi[(*pt)->vg_p->index] = vert.m_vertex_index;
	}
	pnt_cnt++;
    }

    /* Prepare the 3D obr input array */
    points_3d = (point_t *)bu_calloc(pnt_cnt + 1, sizeof(point_t), "nmg points");
    for (BU_PTBL_FOR(pt, (struct vertex **), &vert_table)) {
	VSET(points_3d[pnt_index], (*pt)->vg_p->coord[0],(*pt)->vg_p->coord[1],(*pt)->vg_p->coord[2]);
	pnt_index++;
    }
    bu_ptbl_free(&vert_table);


    /* Calculate the 3D coplanar oriented bounding rectangle (obr) */
    ret += bg_3d_coplanar_obr(&obr_center, &u_axis, &v_axis, (const point_t *)points_3d, pnt_cnt);
    if (ret) {
	bu_log("Failed to get oriented bounding rectangle for NMG faceuse #%lu\n", fu->index);
	return -1;
    }
    bu_free(points_3d, "done with obr 3d point inputs");

    /* Use the obr to define the 3D corner points of the NURBS surface */
    points_obr = (point_t *)bu_calloc(3 + 1, sizeof(point_t), "points_3d");
    VADD3(points_obr[2], obr_center, u_axis, v_axis);
    VSCALE(u_axis, u_axis, -1);
    VADD3(points_obr[3], obr_center, u_axis, v_axis);
    VSCALE(v_axis, v_axis, -1);
    VADD3(points_obr[0], obr_center, u_axis, v_axis);
    VSCALE(u_axis, u_axis, -1);
    VADD3(points_obr[1], obr_center, u_axis, v_axis);

    /* We need to orient our surface correctly according to the NMG - using
     * the openNURBS FlipFace function later does not seem to work very
     * well. If an outer loop is found in the NMG with a cw orientation,
     * factor that in in addition to the fu->f_p->flip flag. */
    int ccw = 0;
    vect_t vtmp, uv1, uv2, vnormal;
    point_t center;
    VADD2(center, points_obr[0], points_obr[1]);
    VADD2(center, center, points_obr[2]);
    VADD2(center, center, points_obr[3]);
    VSCALE(center, center, 0.25);
    for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd)) {
	if (lu->orientation == OT_SAME && nmg_loop_is_ccw(lu, fg->N, tol) == -1) ccw = -1;
    }
    if (ccw != -1) {
	VSET(vnormal, fg->N[0], fg->N[1], fg->N[2]);
    } else {
	VSET(vnormal, -fg->N[0], -fg->N[1], -fg->N[2]);
    }
    if (fu->f_p->flip)
	VSET(vnormal, -vnormal[0], -vnormal[1], -vnormal[2]);
    VSUB2(uv1, points_obr[0], center);
    VSUB2(uv2, points_obr[1], center);
    VCROSS(vtmp, uv1, uv2);
    if (VDOT(vtmp, vnormal) < 0) {
	VMOVE(vtmp, points_obr[0]);
	VMOVE(points_obr[0], points_obr[1]);
	VMOVE(points_obr[1], vtmp);
	VMOVE(vtmp, points_obr[3]);
	VMOVE(points_obr[3], points_obr[2]);
	VMOVE(points_obr[2], vtmp);
    }

    /* Now that we've got our points correctly oriented for
     * the NURBS surface, proceed to create it. */
    ON_3dPoint p1 = ON_3dPoint(points_obr[0]);
    ON_3dPoint p2 = ON_3dPoint(points_obr[1]);
    ON_3dPoint p3 = ON_3dPoint(points_obr[2]);
    ON_3dPoint p4 = ON_3dPoint(points_obr[3]);

    (*b)->m_S.Append(sideSurface(p1, p2, p3, p4));
    ON_Surface *surf = (*(*b)->m_S.Last());
    int surfindex = (*b)->m_S.Count();
    ON_BrepFace& face = (*b)->NewFace(surfindex - 1);

    // With the surface and the face defined, make
    // trimming loops and create faces.  To generate UV
    // coordinates for each from and to for the
    // edgecurves, the UV origin is defined to be v1,
    // v1->v2 is defined as the U domain, and v1->v4 is
    // defined as the V domain.
    VSUB2(u_axis, points_obr[2], points_obr[1]);
    VSUB2(v_axis, points_obr[0], points_obr[1]);
    fastf_t u_axis_dist = MAGNITUDE(u_axis);
    fastf_t v_axis_dist = MAGNITUDE(v_axis);

    /* Now that we have the surface and the face, add the loops */
    for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd)) {
	if (BU_LIST_FIRST_MAGIC(&lu->down_hd) != NMG_EDGEUSE_MAGIC) continue; // loop is a single vertex
	// Check if this is an inner or outer loop
	ON_BrepLoop::TYPE looptype = (lu->orientation == OT_SAME) ? ON_BrepLoop::outer : ON_BrepLoop::inner;
	ON_BrepLoop& loop = (*b)->NewLoop(looptype, face);
	for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) {
	    vect_t ev1, ev2;
	    struct vertex_g *vg1 = eu->vu_p->v_p->vg_p;
	    struct vertex_g *vg2 = eu->eumate_p->vu_p->v_p->vg_p;
	    NMG_CK_VERTEX_G(vg1);
	    NMG_CK_VERTEX_G(vg2);
	    VMOVE(ev1, vg1->coord);
	    VMOVE(ev2, vg2->coord);
	    // Add edge if not already added
	    if (brepi[eu->e_p->index] == -INT_MAX) {
		/* always add edges with the small vertex index as from */
		int vert1 = (vg1->index <= vg2->index) ? brepi[vg1->index] : brepi[vg2->index];
		int vert2 = (vg1->index > vg2->index) ? brepi[vg1->index] : brepi[vg2->index];
		// Create and add 3D curve
		ON_Curve* c3d = new ON_LineCurve((*b)->m_V[vert1].Point(), (*b)->m_V[vert2].Point());
		c3d->SetDomain(0.0, 1.0);
		(*b)->m_C3.Append(c3d);
		// Create and add 3D edge
		ON_BrepEdge& e = (*b)->NewEdge((*b)->m_V[vert1], (*b)->m_V[vert2] , (*b)->m_C3.Count() - 1);
		e.m_tolerance = 0.0;
		brepi[eu->e_p->index] = e.m_edge_index;
	    }
	    // Regardless of whether the edge existed as an object, it needs to be added to the trimming loop
	    ON_3dPoint vg1pt(vg1->coord);
	    int orientation = ((vg1pt != (*b)->m_V[(*b)->m_E[(int)brepi[eu->e_p->index]].m_vi[0]].Point())) ? 1 : 0;
	    // Make a 2d trimming curve, create a trim, and add the trim to the loop
	    vect_t vect1, vect2, u_component, v_component;
	    double u0, u1, v0, v1;
	    ON_2dPoint from_uv, to_uv;
	    VSUB2(vect1, ev1, points_obr[0]);
	    VSUB2(vect2, ev2, points_obr[0]);
	    surf->GetDomain(0, &u0, &u1);
	    surf->GetDomain(1, &v0, &v1);
	    VPROJECT(vect1, u_axis, u_component, v_component);
	    from_uv.y = u0 + MAGNITUDE(u_component)/u_axis_dist*(u1-u0);
	    from_uv.x = v0 + MAGNITUDE(v_component)/v_axis_dist*(v1-v0);
	    VPROJECT(vect2, u_axis, u_component, v_component);
	    to_uv.y = u0 + MAGNITUDE(u_component)/u_axis_dist*(u1-u0);
	    to_uv.x = v0 + MAGNITUDE(v_component)/v_axis_dist*(v1-v0);
	    ON_Curve* c2d =  new ON_LineCurve(from_uv, to_uv);
	    c2d->SetDomain(0.0, 1.0);
	    int c2i = (*b)->m_C2.Count();
	    (*b)->m_C2.Append(c2d);
	    ON_BrepTrim& trim = (*b)->NewTrim((*b)->m_E[(int)brepi[eu->e_p->index]], orientation, loop, c2i);
	    trim.m_type = ON_BrepTrim::mated;
	    trim.m_tolerance[0] = 0.0;
	    trim.m_tolerance[1] = 0.0;
	}
    }

    bu_free(points_obr, "Done with obr");

    return 0;
}