/* * R T _ N U R B _ B E Z I E R * * Given a single snurb, if it is in Bezier form, * duplicate the snurb, and enqueue it on the bezier_hd list. * If the original snurb is NOT in Bezier form, * subdivide it a set of snurbs which are, * each of which are enqueued on the bezier_hd list. * * In either case, the original surface remains untouched. * * Returns - * 0 Surface splitting was done. * 1 Original surface was Bezier, only a copy was done. */ int rt_nurb_bezier(struct bu_list *bezier_hd, const struct face_g_snurb *orig_surf, struct resource *res) { struct face_g_snurb *s; int dir; struct bu_list todo; NMG_CK_SNURB(orig_surf); if ( (dir = rt_bez_check( orig_surf )) == -1) { s = rt_nurb_scopy( orig_surf, res ); BU_LIST_APPEND( bezier_hd, &s->l ); return 1; /* Was already Bezier, nothing done */ } BU_LIST_INIT( &todo ); rt_nurb_s_split( &todo, orig_surf, dir, res ); while ( BU_LIST_WHILE( s, face_g_snurb, &todo ) ) { if ( (dir = rt_bez_check(s)) == -1) { /* This snurb is now a Bezier */ BU_LIST_DEQUEUE( &s->l ); BU_LIST_APPEND( bezier_hd, &s->l ); } else { /* Split, and keep going */ BU_LIST_DEQUEUE( &s->l ); rt_nurb_s_split( &todo, s, dir, res ); rt_nurb_free_snurb(s, res); } } return 0; /* Bezier snurbs on bezier_hd list */ }
/** * If the order of the surface is linear either direction than * approximate it. */ void rt_nurb_s_norm(struct face_g_snurb *srf, fastf_t u, fastf_t v, fastf_t *norm) { struct face_g_snurb *usrf, *vsrf; point_t uvec, vvec; fastf_t p; fastf_t se[4], ue[4], ve[4]; int i; /* Case (linear, lienar) find the normal from the polygon */ if (srf->order[0] == 2 && srf->order[1] == 2) { /* Find the correct span to get the normal */ rt_nurb_s_eval(srf, u, v, se); p = 0.0; for (i = 0; i < srf->u.k_size -1; i++) { if (srf->u.knots[i] <= u && u < srf->u.knots[i+1]) { p = srf->u.knots[i]; if (ZERO(u - p)) p = srf->u.knots[i+1]; if (ZERO(u - p) && i > 1) p = srf->u.knots[i-1]; } } rt_nurb_s_eval(srf, p, v, ue); p = 0.0; for (i = 0; i < srf->v.k_size -1; i++) { if (srf->v.knots[i] < v && !ZERO(srf->v.knots[i+1])) { p = srf->v.knots[i]; if (ZERO(v - p)) p = srf->v.knots[i+1]; if (ZERO(v - p) && i > 1) p = srf->v.knots[i-1]; } } rt_nurb_s_eval(srf, u, p, ve); if (RT_NURB_IS_PT_RATIONAL(srf->pt_type)) { ue[0] = ue[0] / ue[3]; ue[1] = ue[1] / ue[3]; ue[2] = ue[2] / ue[3]; ue[3] = ue[3] / ue[3]; ve[0] = ve[0] / ve[3]; ve[1] = ve[1] / ve[3]; ve[2] = ve[2] / ve[3]; ve[3] = ve[3] / ve[3]; } VSUB2(uvec, se, ue); VSUB2(vvec, se, ve); VCROSS(norm, uvec, vvec); VUNITIZE(norm); return; } /* Case (linear, > linear) Use the linear direction to approximate * the tangent to the surface */ if (srf->order[0] == 2 && srf->order[1] > 2) { rt_nurb_s_eval(srf, u, v, se); p = 0.0; for (i = 0; i < srf->u.k_size -1; i++) { if (srf->u.knots[i] <= u && u < srf->u.knots[i+1]) { p = srf->u.knots[i]; if (ZERO(u - p)) p = srf->u.knots[i+1]; if (ZERO(u - p) && i > 1) p = srf->u.knots[i-1]; } } rt_nurb_s_eval(srf, p, v, ue); vsrf = (struct face_g_snurb *) rt_nurb_s_diff(srf, RT_NURB_SPLIT_COL); rt_nurb_s_eval(vsrf, u, v, ve); if (RT_NURB_IS_PT_RATIONAL(srf->pt_type)) { fastf_t w, inv_w; w = se[3]; inv_w = 1.0 / w; ve[0] = (inv_w * ve[0]) - ve[3] / (w * w) * se[0]; ve[1] = (inv_w * ve[1]) - ve[3] / (w * w) * se[1]; ve[2] = (inv_w * ve[2]) - ve[3] / (w * w) * se[2]; ue[0] = ue[0] / ue[3]; ue[1] = ue[1] / ue[3]; ue[2] = ue[2] / ue[3]; ue[3] = ue[3] / ue[3]; se[0] = se[0] / se[3]; se[1] = se[1] / se[3]; se[2] = se[2] / se[3]; se[3] = se[3] / se[3]; } VSUB2(uvec, se, ue); VCROSS(norm, uvec, ve); VUNITIZE(norm); rt_nurb_free_snurb(vsrf, (struct resource *)NULL); return; } if (srf->order[1] == 2 && srf->order[0] > 2) { rt_nurb_s_eval(srf, u, v, se); p = 0.0; for (i = 0; i < srf->v.k_size -1; i++) { if (srf->v.knots[i] <= v && v < srf->v.knots[i+1]) { p = srf->v.knots[i]; if (ZERO(v - p)) p = srf->v.knots[i+1]; if (ZERO(v - p) && i > 1) p = srf->v.knots[i-1]; } } rt_nurb_s_eval(srf, u, p, ve); usrf = (struct face_g_snurb *) rt_nurb_s_diff(srf, RT_NURB_SPLIT_ROW); rt_nurb_s_eval(usrf, u, v, ue); if (RT_NURB_IS_PT_RATIONAL(srf->pt_type)) { fastf_t w, inv_w; w = se[3]; inv_w = 1.0 / w; ue[0] = (inv_w * ue[0]) - ue[3] / (w * w) * se[0]; ue[1] = (inv_w * ue[1]) - ue[3] / (w * w) * se[1]; ue[2] = (inv_w * ue[2]) - ue[3] / (w * w) * se[2]; ve[0] = ve[0] / ve[3]; ve[1] = ve[1] / ve[3]; ve[2] = ve[2] / ve[3]; ve[3] = ve[3] / ve[3]; se[0] = se[0] / se[3]; se[1] = se[1] / se[3]; se[2] = se[2] / se[3]; se[3] = se[3] / se[3]; } VSUB2(vvec, se, ve); VCROSS(norm, ue, vvec); VUNITIZE(norm); rt_nurb_free_snurb(usrf, (struct resource *)NULL); return; } /* Case Non Rational (order > 2, order > 2) */ if (!RT_NURB_IS_PT_RATIONAL(srf->pt_type)) { usrf = (struct face_g_snurb *) rt_nurb_s_diff(srf, RT_NURB_SPLIT_ROW); vsrf = (struct face_g_snurb *) rt_nurb_s_diff(srf, RT_NURB_SPLIT_COL); rt_nurb_s_eval(usrf, u, v, ue); rt_nurb_s_eval(vsrf, u, v, ve); VCROSS(norm, ue, ve); VUNITIZE(norm); rt_nurb_free_snurb(usrf, (struct resource *)NULL); rt_nurb_free_snurb(vsrf, (struct resource *)NULL); return; } /* Case Rational (order > 2, order > 2) */ if (RT_NURB_IS_PT_RATIONAL(srf->pt_type)) { fastf_t w, inv_w; vect_t unorm, vnorm; rt_nurb_s_eval(srf, u, v, se); usrf = (struct face_g_snurb *) rt_nurb_s_diff(srf, RT_NURB_SPLIT_ROW); vsrf = (struct face_g_snurb *) rt_nurb_s_diff(srf, RT_NURB_SPLIT_COL); rt_nurb_s_eval(usrf, u, v, ue); rt_nurb_s_eval(vsrf, u, v, ve); w = se[3]; inv_w = 1.0 / w; for (i = 0; i < 3; i++) { unorm[i] = (inv_w * ue[i]) - ue[3] / (w*w) * se[i]; vnorm[i] = (inv_w * ve[i]) - ve[3] / (w*w) * se[i]; } VCROSS(norm, unorm, vnorm); VUNITIZE(norm); rt_nurb_free_snurb(usrf, (struct resource *)NULL); rt_nurb_free_snurb(vsrf, (struct resource *)NULL); return; } return; }
struct rt_nurb_uv_hit * rt_nurb_intersect(const struct face_g_snurb *srf, fastf_t *plane1, fastf_t *plane2, double uv_tol, struct resource *res, struct bu_list *plist) { struct rt_nurb_uv_hit * h; struct face_g_snurb * psrf, * osrf; int dir, sub; point_t vmin, vmax; fastf_t u[2], v[2]; struct bu_list rni_plist; NMG_CK_SNURB(srf); h = (struct rt_nurb_uv_hit *) 0; if (plist == NULL) { plist = &rni_plist; BU_LIST_INIT(plist); } /* project the surface to a 2 dimensional problem */ /* NOTE that this gives a single snurb back, NOT a list */ psrf = rt_nurb_project_srf(srf, plane2, plane1, res); psrf->dir = 1; BU_LIST_APPEND(plist, &psrf->l); if (RT_G_DEBUG & DEBUG_SPLINE) rt_nurb_s_print("srf", psrf); /* This list starts out with only a single snurb, but more may be * added on as work progresses. */ while (BU_LIST_WHILE(psrf, face_g_snurb, plist)) { int flat; BU_LIST_DEQUEUE(&psrf->l); NMG_CK_SNURB(psrf); sub = 0; flat = 0; dir = psrf->dir; while (!flat) { fastf_t smin = 0.0, smax = 0.0; sub++; dir = (dir == 0)?1:0; /* change direction */ if (RT_G_DEBUG & DEBUG_SPLINE) rt_nurb_s_print("psrf", psrf); rt_nurb_pbound(psrf, vmin, vmax); /* Check for origin to be included in the bounding box */ if (!(vmin[0] <= 0.0 && vmin[1] <= 0.0 && vmax[0] >= 0.0 && vmax[1] >= 0.0)) { if (RT_G_DEBUG & DEBUG_SPLINE) bu_log("this srf doesn't include the origin\n"); flat = 1; rt_nurb_free_snurb(psrf, res); continue; } rt_nurb_clip_srf(psrf, dir, &smin, &smax); if ((smax - smin) > .8) { struct rt_nurb_uv_hit *hp; /* Split surf, requeue both sub-surfs at head */ /* New surfs will have same dir as arg, here */ if (RT_G_DEBUG & DEBUG_SPLINE) bu_log("splitting this surface\n"); rt_nurb_s_split(plist, psrf, dir, res); rt_nurb_free_snurb(psrf, res); hp = rt_nurb_intersect(srf, plane1, plane2, uv_tol, res, plist); return hp; } if (smin > 1.0 || smax < 0.0) { if (RT_G_DEBUG & DEBUG_SPLINE) bu_log("eliminating this surface (smin=%g, smax=%g)\n", smin, smax); flat = 1; rt_nurb_free_snurb(psrf, res); continue; } if (dir == RT_NURB_SPLIT_ROW) { smin = (1.0 - smin) * psrf->u.knots[0] + smin * psrf->u.knots[ psrf->u.k_size -1]; smax = (1.0 - smax) * psrf->u.knots[0] + smax * psrf->u.knots[ psrf->u.k_size -1]; } else { smin = (1.0 - smin) * psrf->v.knots[0] + smin * psrf->v.knots[ psrf->v.k_size -1]; smax = (1.0 - smax) * psrf->v.knots[0] + smax * psrf->v.knots[ psrf->v.k_size -1]; } osrf = psrf; psrf = (struct face_g_snurb *) rt_nurb_region_from_srf( osrf, dir, smin, smax, res); psrf->dir = dir; rt_nurb_free_snurb(osrf, res); if (RT_G_DEBUG & DEBUG_SPLINE) { bu_log("After call to rt_nurb_region_from_srf() (smin=%g, smax=%g)\n", smin, smax); rt_nurb_s_print("psrf", psrf); } u[0] = psrf->u.knots[0]; u[1] = psrf->u.knots[psrf->u.k_size -1]; v[0] = psrf->v.knots[0]; v[1] = psrf->v.knots[psrf->v.k_size -1]; if ((u[1] - u[0]) < uv_tol && (v[1] - v[0]) < uv_tol) { struct rt_nurb_uv_hit * hit; if (RT_G_DEBUG & DEBUG_SPLINE) { fastf_t p1[4], p2[4]; int coords; vect_t diff; coords = RT_NURB_EXTRACT_COORDS(srf->pt_type); rt_nurb_s_eval(srf, u[0], v[0], p1); rt_nurb_s_eval(srf, u[1], v[1], p2); if (RT_NURB_IS_PT_RATIONAL(srf->pt_type)) { fastf_t inv_w; inv_w = 1.0 / p1[coords-1]; VSCALE(p1, p1, inv_w); inv_w = 1.0 / p2[coords-1]; VSCALE(p2, p2, inv_w); } VSUB2(diff, p1, p2); bu_log("Precision of hit point = %g (%f %f %f) <-> (%f %f %f)\n", MAGNITUDE(diff), V3ARGS(p1), V3ARGS(p2)); } hit = (struct rt_nurb_uv_hit *) bu_malloc( sizeof(struct rt_nurb_uv_hit), "hit"); hit->next = (struct rt_nurb_uv_hit *)0; hit->sub = sub; hit->u = (u[0] + u[1])/2.0; hit->v = (v[0] + v[1])/2.0; if (h == (struct rt_nurb_uv_hit *)0) h = hit; else { hit->next = h; h = hit; } flat = 1; rt_nurb_free_snurb(psrf, res); } if ((u[1] - u[0]) > (v[1] - v[0])) dir = 1; else dir = 0; } } return (struct rt_nurb_uv_hit *)h; }
fastf_t rt_nurb_par_edge(const struct face_g_snurb *srf, fastf_t epsilon) { struct face_g_snurb * us, *vs, * uus, * vvs, *uvs; fastf_t d1, d2, d3; int i; fastf_t *pt; us = rt_nurb_s_diff(srf, RT_NURB_SPLIT_ROW); vs = rt_nurb_s_diff(srf, RT_NURB_SPLIT_COL); uus = rt_nurb_s_diff(us, RT_NURB_SPLIT_ROW); vvs = rt_nurb_s_diff(vs, RT_NURB_SPLIT_COL); uvs = rt_nurb_s_diff(vs, RT_NURB_SPLIT_ROW); d1 = 0.0; d2 = 0.0; d3 = 0.0; pt = (fastf_t *) uus->ctl_points; /* Find the maximum value of the 2nd derivative in U */ for (i = 0; i < uus->s_size[0] * uus->s_size[1]; i++) { fastf_t mag; mag = MAGNITUDE(pt); if (mag > d1) d1 = mag; pt += RT_NURB_EXTRACT_COORDS(uus->pt_type); } /* Find the maximum value of the partial derivative in UV */ pt = (fastf_t *) uvs->ctl_points; for (i = 0; i < uvs->s_size[0] * uvs->s_size[1]; i++) { fastf_t mag; mag = MAGNITUDE(pt); if (mag > d2) d2 = mag; pt += RT_NURB_EXTRACT_COORDS(uvs->pt_type); } /* Find the maximum value of the 2nd derivative in V */ pt = (fastf_t *) vvs->ctl_points; for (i = 0; i < vvs->s_size[0] * vvs->s_size[1]; i++) { fastf_t mag; mag = MAGNITUDE(pt); if (mag > d3) d3 = mag; pt += RT_NURB_EXTRACT_COORDS(vvs->pt_type); } /* free up storage */ rt_nurb_free_snurb(us, (struct resource *)NULL); rt_nurb_free_snurb(vs, (struct resource *)NULL); rt_nurb_free_snurb(uus, (struct resource *)NULL); rt_nurb_free_snurb(vvs, (struct resource *)NULL); rt_nurb_free_snurb(uvs, (struct resource *)NULL); /* The paper uses the following to calculate the longest edge size * 1/2 * 3.0 * () * (2.0) * _________________________ * (2.0 * (d1 + 2 D2 + d3) */ return 3.0 * sqrt(epsilon / (2.0*(d1 + (2.0 * d2)+ d3))); }
void build_spline(char *name, int npts, double radius) { struct face_g_snurb *bp; int i; int nv; int cur_kv; fastf_t *meshp; int col; vect_t point; /* * This spline will look like a cylinder. * In the mesh, the circular cross section will be presented * across the first row by filling in the 9 (NCOLS) columns. * * The U direction is across the first row, * and has NCOLS+order[U] positions, 12 in this instance. * The V direction is down the first column, * and has NROWS+order[V] positions. */ bp = rt_nurb_new_snurb(3, 4, /* u, v order */ N_CIRCLE_KNOTS, npts+6, /* u, v knot vector size */ npts+2, NCOLS, /* nrows, ncols */ RT_NURB_MAKE_PT_TYPE(4, 2, 1), &rt_uniresource); /* Build the U knots */ for (i=0; i<N_CIRCLE_KNOTS; i++) bp->u.knots[i] = circle_knots[i]; /* Build the V knots */ cur_kv = 0; /* current knot value */ nv = 0; /* current knot subscript */ for (i=0; i<4; i++) bp->v.knots[nv++] = cur_kv; cur_kv++; for (i=4; i<(npts+4-2); i++) bp->v.knots[nv++] = cur_kv++; for (i=0; i<4; i++) bp->v.knots[nv++] = cur_kv; /* * The control mesh is stored in row-major order, * which works out well for us, as a row is one * circular slice through the tube. So we just * have to write down the slices, one after another. * The first and last "slice" are the center points that * create the end caps. */ meshp = bp->ctl_points; /* Row 0 */ for (col=0; col<9; col++) { *meshp++ = sample[0][X]; *meshp++ = sample[0][Y]; *meshp++ = sample[0][Z]; *meshp++ = 1; } /* Rows 1..npts */ for (i=0; i<npts; i++) { /* row = i; */ VMOVE(point, sample[i]); for (col=0; col<9; col++) { fastf_t h; h = polyline[col*4+H]; *meshp++ = polyline[col*4+X]*radius + point[X]*h; *meshp++ = polyline[col*4+Y]*radius + point[Y]*h; *meshp++ = polyline[col*4+Z]*radius + point[Z]*h; *meshp++ = h; } } /* Row npts+1 */ for (col=0; col<9; col++) { *meshp++ = sample[npts-1][X]; *meshp++ = sample[npts-1][Y]; *meshp++ = sample[npts-1][Z]; *meshp++ = 1; } { struct face_g_snurb *surfp[2]; surfp[0] = bp; surfp[1] = NULL; mk_bspline(outfp, name, surfp); } rt_nurb_free_snurb(bp, &rt_uniresource); }