struct edge_g_cnurb * rt_nurb_c_diff(const struct edge_g_cnurb *crv) { struct edge_g_cnurb *ncrv; fastf_t * opts, *npts; int i; NMG_CK_CNURB(crv); ncrv = (struct edge_g_cnurb *) rt_nurb_new_cnurb(crv->order - 1, crv->k.k_size - 2, crv->c_size - 1, crv->pt_type); opts = (fastf_t *) crv->ctl_points; npts = (fastf_t *) ncrv->ctl_points; rt_nurb_mesh_diff(crv->order, opts, npts, crv->k.knots, RT_NURB_EXTRACT_COORDS(crv->pt_type), RT_NURB_EXTRACT_COORDS(ncrv->pt_type), crv->c_size, crv->pt_type); for (i = 1; i < crv->k.k_size - 1; i++) ncrv->k.knots[ i - 1] = crv->k.knots[i]; return ncrv; }
void rt_nurb_c_print(const struct edge_g_cnurb *crv) { register fastf_t * ptr; int i, j; NMG_CK_CNURB(crv); bu_log("curve = {\n"); bu_log("\tOrder = %d\n", crv->order); bu_log("\tKnot Vector = {\n\t\t"); for (i = 0; i < crv->k.k_size; i++) bu_log("%10.8f ", crv->k.knots[i]); bu_log("\n\t}\n"); bu_log("\t"); rt_nurb_print_pt_type(crv->pt_type); bu_log("\tmesh = {\n"); for (ptr = &crv->ctl_points[0], i= 0; i < crv->c_size; i++, ptr += RT_NURB_EXTRACT_COORDS(crv->pt_type)) { bu_log("\t\t"); for (j = 0; j < RT_NURB_EXTRACT_COORDS(crv->pt_type); j++) bu_log("%4.5f\t", ptr[j]); bu_log("\n"); } bu_log("\t}\n}\n"); }
static struct edge_g_cnurb * nmg_construct_edge_g_cnurb(const struct edge_g_cnurb *original, void **structArray) { struct edge_g_cnurb *ret; NMG_GETSTRUCT(ret, edge_g_cnurb); ret->l.magic = NMG_EDGE_G_CNURB_MAGIC; BU_LIST_INIT(&ret->eu_hd2); ret->order = original->order; ret->k.magic = NMG_KNOT_VECTOR_MAGIC; ret->k.k_size = original->k.k_size; ret->k.knots = (fastf_t *)bu_malloc(ret->k.k_size * sizeof(fastf_t), "nmg_construct_edge_g_cnurb(): k.knots"); memcpy(ret->k.knots, original->k.knots, ret->k.k_size * sizeof(fastf_t)); ret->c_size = original->c_size; ret->pt_type = original->pt_type; ret->ctl_points = (fastf_t *)bu_malloc(ret->c_size * RT_NURB_EXTRACT_COORDS(ret->pt_type) * sizeof(fastf_t), "nmg_construct_edge_g_cnurb(): ctl_points"); memcpy(ret->ctl_points, original->ctl_points, ret->c_size * RT_NURB_EXTRACT_COORDS(ret->pt_type) * sizeof(fastf_t)); ret->index = original->index; structArray[ret->index] = ret; return ret; }
/** * rt_nurb_c_xsplit() * * Split a NURB curve by inserting a multiple knot and return the * result of the two curves. * * Algorithm: * * Insert a multiple knot of the curve order. A parameter is give for * the knot value for which the curve will be split. */ struct edge_g_cnurb * rt_nurb_c_xsplit(struct edge_g_cnurb *crv, fastf_t param) { struct knot_vector new_kv; struct oslo_mat * oslo; int k_index; struct edge_g_cnurb * crv1, * crv2; int coords; NMG_CK_CNURB(crv); coords = RT_NURB_EXTRACT_COORDS(crv->pt_type), k_index = crv->order; rt_nurb_kvmult(&new_kv, &crv->k, crv->order, param, (struct resource *)NULL); oslo = (struct oslo_mat *) rt_nurb_calc_oslo(crv->order, &crv->k, &new_kv, (struct resource *)NULL); GET_CNURB(crv1); crv1->order = crv->order; rt_nurb_kvextract(&crv1->k, &new_kv, 0, k_index + crv->order, (struct resource *)NULL); crv1->pt_type = crv->pt_type; crv1->c_size = crv1->k.k_size - crv1->order; crv1->ctl_points = (fastf_t *) bu_malloc(sizeof(fastf_t) * crv1->c_size * RT_NURB_EXTRACT_COORDS(crv1->pt_type), "rt_nurb_c_xsplit: crv1 control points"); GET_CNURB(crv2); crv2->order = crv->order; rt_nurb_kvextract(&crv2->k, &new_kv, k_index, new_kv.k_size, (struct resource *)NULL); crv2->pt_type = crv->pt_type; crv2->c_size = crv2->k.k_size - crv2->order; crv2->ctl_points = (fastf_t *) bu_malloc(sizeof(fastf_t) * crv2->c_size * RT_NURB_EXTRACT_COORDS(crv2->pt_type), "rt_nurb_c_xsplit: crv2 row mesh control points"); rt_nurb_map_oslo(oslo, crv->ctl_points, crv1->ctl_points, coords, coords, 0, k_index, crv->pt_type); rt_nurb_map_oslo(oslo, crv->ctl_points, crv2->ctl_points, coords, coords, k_index, new_kv.k_size - crv2->order, crv2->pt_type); rt_nurb_free_oslo(oslo, (struct resource *)NULL); bu_free((char *) new_kv.knots, "rt_nurb_c_xsplit: new_kv.knots"); BU_LIST_APPEND(&crv1->l, &crv2->l); return crv1; }
/** * Create a place holder for a nurb surface. */ struct face_g_snurb * rt_nurb_new_snurb(int u_order, int v_order, int n_u, int n_v, int n_rows, int n_cols, int pt_type, struct resource *res) { register struct face_g_snurb * srf; int pnum; if (res) RT_CK_RESOURCE(res); GET_SNURB(srf); srf->order[0] = u_order; srf->order[1] = v_order; srf->dir = RT_NURB_SPLIT_ROW; srf->u.k_size = n_u; srf->v.k_size = n_v; srf->s_size[0] = n_rows; srf->s_size[1] = n_cols; srf->pt_type = pt_type; pnum = sizeof (fastf_t) * n_rows * n_cols * RT_NURB_EXTRACT_COORDS(pt_type); srf->u.knots = (fastf_t *) bu_malloc ( n_u * sizeof (fastf_t), "rt_nurb_new_snurb: u kv knot values"); srf->v.knots = (fastf_t *) bu_malloc ( n_v * sizeof (fastf_t), "rt_nurb_new_snurb: v kv knot values"); srf->ctl_points = (fastf_t *) bu_malloc( pnum, "rt_nurb_new_snurb: control mesh points"); return srf; }
void rt_nurb_pbound(struct face_g_snurb *srf, fastf_t *vmin, fastf_t *vmax) { register fastf_t * ptr; register int coords; int i; vmin[0] = vmin[1] = vmin[2] = INFINITY; vmax[0] = vmax[1] = vmax[2] = -INFINITY; ptr = srf->ctl_points; coords = RT_NURB_EXTRACT_COORDS(srf->pt_type); for (i = (srf->s_size[RT_NURB_SPLIT_ROW] * srf->s_size[RT_NURB_SPLIT_COL]); i > 0; i--) { V_MIN((vmin[0]), (ptr[0])); V_MAX((vmax[0]), (ptr[0])); V_MIN((vmin[1]), (ptr[1])); V_MAX((vmax[1]), (ptr[1])); ptr += coords; } }
struct face_g_snurb * rt_nurb_scopy(const struct face_g_snurb *srf, struct resource *res) { register struct face_g_snurb * n; int i; NMG_CK_SNURB(srf); n = (struct face_g_snurb *) rt_nurb_new_snurb(srf->order[0], srf->order[1], srf->u.k_size, srf->v.k_size, srf->s_size[0], srf->s_size[1], srf->pt_type, res); for (i = 0; i < srf->u.k_size; i++) n->u.knots[i] = srf->u.knots[i]; for (i = 0; i < srf->v.k_size; i++) n->v.knots[i] = srf->v.knots[i]; for (i = 0; i < srf->s_size[0] * srf->s_size[1] * RT_NURB_EXTRACT_COORDS(srf->pt_type); i++) { n->ctl_points[i] = srf->ctl_points[i]; } return (struct face_g_snurb *) n; }
struct edge_g_cnurb * rt_nurb_c_refine(const struct edge_g_cnurb *crv, struct knot_vector *kv) { struct oslo_mat * oslo; struct edge_g_cnurb * new_crv; int i, coords; NMG_CK_CNURB(crv); coords = RT_NURB_EXTRACT_COORDS(crv->pt_type); new_crv = (struct edge_g_cnurb *) rt_nurb_new_cnurb( crv->order, kv->k_size, kv->k_size - crv->order, crv->pt_type); oslo = (struct oslo_mat *) rt_nurb_calc_oslo( crv->order, &crv->k, kv, (struct resource *)NULL); rt_nurb_map_oslo(oslo, crv->ctl_points, new_crv->ctl_points, coords, coords, 0, kv->k_size - new_crv->order, new_crv->pt_type); new_crv->k.k_size = kv->k_size; for (i = 0; i < kv->k_size; i++) new_crv->k.knots[i] = kv->knots[i]; rt_nurb_free_oslo(oslo, (struct resource *)NULL); return new_crv; }
/** * Check to see if the curve control polygon wanders outside the * parametric range given. This is useful if a trimming curve * control polygon is outside but the evaluated curve is not. We will * want to refine the curve so that it lies within the range; * otherwise it breaks the surface evaluation. */ int rt_nurb_crv_in_range(struct edge_g_cnurb *crv, fastf_t u_min, fastf_t u_max, fastf_t v_min, fastf_t v_max) { point_t eval; fastf_t *pts; int coords = RT_NURB_EXTRACT_COORDS(crv->pt_type); int rat = RT_NURB_IS_PT_RATIONAL(crv->pt_type); int i; pts = &crv->ctl_points[0]; for (i = 0; i < crv->c_size; i++) { if (rat) { eval[0] = pts[0] / pts[2]; eval[1] = pts[1] / pts[2]; eval[2] = 1; } else { eval[0] = pts[0]; eval[1] = pts[1]; eval[2] = 1; } if (eval[0] < u_min || eval[0] > u_max) return 0; if (eval[1] < v_min || eval[1] > v_max) return 0; pts += coords; } return 1; }
/** * Calculate the maximum edge length (in parameter space) that will * keep the curve approximation within epsilon of the true curve * * This is a temporary guess until legitimate code can be found * * returns: * -1.0 if the curve is a straight line * maximum parameter increment otherwise */ fastf_t rt_cnurb_par_edge(const struct edge_g_cnurb *crv, fastf_t epsilon) { struct edge_g_cnurb *d1, *d2; fastf_t der2[5], t, *pt; fastf_t num_coord_factor, final_t; int num_coords; int i, j; if (crv->order < 3) return -1.0; num_coords = RT_NURB_EXTRACT_COORDS(crv->pt_type); if (num_coords > 5) { bu_log("ERROR: rt_cnurb_par_edge() cannot handle curves with more than 5 coordinates (curve has %d)\n", num_coords); bu_bomb("ERROR: rt_cnurb_par_edge() cannot handle curves with more than 5 coordinates\n"); } for (i=0; i<num_coords; i++) { der2[i] = 0.0; } final_t = MAX_FASTF; num_coord_factor = sqrt((double)num_coords); d1 = rt_nurb_c_diff(crv); d2 = rt_nurb_c_diff(d1); pt = d2->ctl_points; for (i=0; i<d2->c_size; i++) { for (j=0; j<num_coords; j++) { fastf_t abs_val; abs_val = *pt > 0.0 ? *pt : -(*pt); if (abs_val > der2[j]) der2[j] = abs_val; pt++; } } rt_nurb_free_cnurb(d1); rt_nurb_free_cnurb(d2); for (j=0; j<num_coords; j++) { if (ZERO(der2[j])) continue; t = sqrt(2.0 * epsilon / (num_coord_factor * der2[j])); if (t < final_t) final_t = t; } if (ZERO(final_t - MAX_FASTF)) return -1.0; else return final_t/2.0; }
int rt_nurb_uv_dist(struct edge_g_cnurb *trim, fastf_t u, fastf_t v) { fastf_t dist; fastf_t * ptr; int coords; int rat; fastf_t u2, v2; ptr = trim->ctl_points; coords = RT_NURB_EXTRACT_COORDS(trim->pt_type); rat = RT_NURB_IS_PT_RATIONAL(trim->pt_type); u2 = 0.0; v2 = 0.0; if ( rat ) { u2 = ptr[0]/ptr[2] - u; u2 *= u2; v2 = ptr[1]/ptr[2] - v; v2 *= v2; } else { u2 = ptr[0] - u; u2 *= u2; v2 = ptr[1] - v; v2 *= v2; } dist = sqrt( u2 + v2); if ( NEAR_ZERO( dist, 1.0e-4) ) return TRIM_ON; ptr = trim->ctl_points + coords * (trim->c_size -1); u2 = 0.0; v2 = 0.0; if ( rat ) { u2 = ptr[0]/ptr[2] - u; u2 *= u2; v2 = ptr[1]/ptr[2] - v; v2 *= v2; } else { u2 = ptr[0] - u; u2 *= u2; v2 = ptr[1] - v; v2 *= v2; } dist = sqrt( u2 + v2); if ( NEAR_ZERO( dist, 1.0e-4) ) return TRIM_ON; return TRIM_OUT; }
/* Process Case B curves. * * If the two endpoints of the curve lie in different quadrants than * the axis crosses the curve an odd number of times (TRIM_IN). Otherwise * the curve crosses the u, v axis a even number of times (TRIM_OUT). * No further processing is required. */ int rt_process_caseb(struct edge_g_cnurb *trim, fastf_t u, fastf_t v) { int q1, q2; fastf_t * pts; int rat; rat = RT_NURB_IS_PT_RATIONAL( trim->pt_type ); pts = trim->ctl_points; if ( rat) { if ( pts[0]/pts[2] > u) q1 = (pts[1]/pts[2] >= v)?QUAD1:QUAD4; else q1 = (pts[1]/pts[2] >= v)?QUAD2:QUAD3; pts = trim->ctl_points + RT_NURB_EXTRACT_COORDS(trim->pt_type) * (trim->c_size -1); if ( pts[0]/pts[2] > u) q2 = (pts[1]/pts[2] >= v)?QUAD1:QUAD4; else q2 = (pts[1]/pts[2] >= v)?QUAD2:QUAD3; } else { if ( pts[0] > u) q1 = (pts[1] >= v)?QUAD1:QUAD4; else q1 = (pts[1] >= v)?QUAD2:QUAD3; pts = trim->ctl_points + RT_NURB_EXTRACT_COORDS(trim->pt_type) * (trim->c_size -1); if ( pts[0] > u) q2 = (pts[1] >= v)?QUAD1:QUAD4; else q2 = (pts[1] >= v)?QUAD2:QUAD3; } if ( q1 != q2 ) return TRIM_IN; else return TRIM_OUT; }
void rt_nurb_pr_mesh(const struct face_g_snurb *m) { int i, j, k; fastf_t * m_ptr = m->ctl_points; int evp = RT_NURB_EXTRACT_COORDS(m->pt_type); NMG_CK_SNURB(m); bu_log("\t[%d] [%d]\n", m->s_size[0], m->s_size[1]); for (i = 0; i < m->s_size[0]; i++) { for (j =0; j < m->s_size[1]; j++) { bu_log("\t"); for (k = 0; k < evp; k++) bu_log("%f ", m_ptr[k]); bu_log("\n"); m_ptr += RT_NURB_EXTRACT_COORDS(m->pt_type); } bu_log("\n"); } }
int rt_trim_case(struct edge_g_cnurb *trim, fastf_t u, fastf_t v) { int quadrant; int qstats; fastf_t * pts; int coords, rat; int i; qstats = 0; coords = RT_NURB_EXTRACT_COORDS(trim->pt_type); pts = trim->ctl_points; rat = RT_NURB_IS_PT_RATIONAL( trim->pt_type ); /* Handle rational specially since we need to divide the rational * portion. */ if ( rat ) for ( i = 0; i < trim->c_size; i++) { if (pts[0]/pts[2] > u ) quadrant = (pts[1]/pts[2] >= v)? QUAD1:QUAD4; else quadrant = (pts[1]/pts[2] >= v)? QUAD2:QUAD3; qstats |= (1 << quadrant); pts += coords; } else for ( i = 0; i < trim->c_size; i++) { if (pts[0] > u ) quadrant = (pts[1] >= v)? QUAD1:QUAD4; else quadrant = (pts[1] >= v)? QUAD2:QUAD3; qstats |= (1 << quadrant); pts += coords; } return quad_table[qstats]; /* return the special case of the curve */ }
static struct face_g_snurb * nmg_construct_face_g_snurb(const struct face_g_snurb *original, void **structArray) { struct face_g_snurb *ret; NMG_GETSTRUCT(ret, face_g_snurb); ret->l.magic = NMG_FACE_G_SNURB_MAGIC; BU_LIST_INIT(&ret->f_hd); ret->order[0] = original->order[0]; ret->order[1] = original->order[1]; ret->u.magic = NMG_KNOT_VECTOR_MAGIC; ret->u.k_size = original->u.k_size; ret->u.knots = (fastf_t *)bu_malloc(ret->u.k_size * sizeof(fastf_t), "nmg_construct_face_g_snurb(): u.knots"); memcpy(ret->u.knots, original->u.knots, ret->u.k_size * sizeof(fastf_t)); ret->v.magic = NMG_KNOT_VECTOR_MAGIC; ret->v.k_size = original->v.k_size; ret->v.knots = (fastf_t *)bu_malloc(ret->v.k_size * sizeof(fastf_t), "nmg_construct_face_g_snurb(): v.knots"); memcpy(ret->v.knots, original->v.knots, ret->v.k_size * sizeof(fastf_t)); ret->s_size[0] = original->s_size[0]; ret->s_size[1] = original->s_size[1]; ret->pt_type = original->pt_type; ret->ctl_points = (fastf_t *)bu_malloc(original->s_size[0] * original->s_size[1] * RT_NURB_EXTRACT_COORDS(ret->pt_type) * sizeof(fastf_t), "nmg_construct_face_g_snurb(): ctl_points"); memcpy(ret->ctl_points, original->ctl_points, original->s_size[0] * original->s_size[1] * RT_NURB_EXTRACT_COORDS(ret->pt_type) * sizeof(fastf_t)); ret->dir = original->dir; VMOVE(ret->min_pt, original->min_pt); VMOVE(ret->max_pt, original->max_pt); ret->index = original->index; structArray[ret->index] = ret; return ret; }
struct edge_g_cnurb * rt_nurb_crv_copy(const struct edge_g_cnurb *crv) { register struct edge_g_cnurb * n; int i; NMG_CK_CNURB(crv); n = (struct edge_g_cnurb *) rt_nurb_new_cnurb(crv->order, crv->k.k_size, crv->c_size, crv->pt_type); for (i = 0; i < crv->k.k_size; i++) n->k.knots[i] = crv->k.knots[i]; for (i = 0; i < crv->c_size * RT_NURB_EXTRACT_COORDS(crv->pt_type); i++) n->ctl_points[i] = crv->ctl_points[i]; return (struct edge_g_cnurb *) n; }
/** * Calculates the bounding Right Parallel Piped (RPP) of the NURB * surface, and returns the minimum and maximum points of the surface. */ int rt_nurb_s_bound(struct face_g_snurb *srf, fastf_t *bmin, fastf_t *bmax) { register fastf_t *p_ptr; /* Mesh pointer */ register int coords; /* Elements per vector */ int i; int rat; VSETALL(bmin, INFINITY); VSETALL(bmax, -INFINITY); if (srf == (struct face_g_snurb *)0) { bu_log("nurb_s_bound: NULL surface\n"); return -1; /* BAD */ } p_ptr = srf->ctl_points; coords = RT_NURB_EXTRACT_COORDS(srf->pt_type); rat = RT_NURB_IS_PT_RATIONAL(srf->pt_type); for (i = (srf->s_size[RT_NURB_SPLIT_ROW] * srf->s_size[RT_NURB_SPLIT_COL]); i > 0; i--) { if (!rat) { VMINMAX(bmin, bmax, p_ptr); } else if (rat) { point_t tmp_pt; if (ZERO(p_ptr[H])) { HPRINT("mesh point", p_ptr); bu_log("nurb_s_bound: H too small\n"); } else { HDIVIDE(tmp_pt, p_ptr); VMINMAX(bmin, bmax, tmp_pt); } } p_ptr += coords; } return 0; /* OK */ }
void rt_nurb_mesh_diff(int order, const fastf_t *o_pts, fastf_t *n_pts, const fastf_t *knots, int o_stride, int n_stride, int o_size, int pt_type) { int i, k; int coords; fastf_t denom; coords = RT_NURB_EXTRACT_COORDS(pt_type); for (i = 1; i < o_size; i++) { denom = knots[ i + order - 1] - knots[i]; for (k = 0; k < coords; k++) { if (ZERO(denom)) n_pts[k] = 0.0; else n_pts[k] = (order - 1) * (o_pts[k+o_stride] - o_pts[k]) / denom; } n_pts += n_stride; o_pts += o_stride; } }
/** * Create a place holder for a new nurb curve. */ struct edge_g_cnurb * rt_nurb_new_cnurb(int order, int n_knots, int n_pts, int pt_type) { register struct edge_g_cnurb * crv; GET_CNURB(crv); crv->order = order; crv->k.k_size = n_knots; crv->k.knots = (fastf_t *) bu_malloc(n_knots * sizeof(fastf_t), "rt_nurb_new_cnurb: knot values"); crv->c_size = n_pts; crv->pt_type = pt_type; crv->ctl_points = (fastf_t *) bu_malloc(sizeof(fastf_t) * RT_NURB_EXTRACT_COORDS(pt_type) * n_pts, "rt_nurb_new_cnurb: mesh point values"); return crv; }
/** * Algorithm * * Given a parametric direction (u or v) look at the direction knot * vector and insert a multiple knot of parametric direction surface * order. This is somewhat different than rt_nurb_split in that the * surface is give a parametric value at which to split the surface. * rt_nurb_kvmult does the right thing in inserting a multiple knot * with the correct amount. Separate the surface and return the two * resulting surface. */ struct face_g_snurb * rt_nurb_s_xsplit(struct face_g_snurb *srf, fastf_t param, int dir) { struct knot_vector new_kv; struct oslo_mat * oslo; int i; int k_index; struct face_g_snurb * srf1, * srf2; NMG_CK_SNURB(srf); if (dir == RT_NURB_SPLIT_ROW) { rt_nurb_kvmult(&new_kv, &srf->u, srf->order[0], param, (struct resource *)NULL); k_index = srf->order[0]; oslo = (struct oslo_mat *) rt_nurb_calc_oslo(srf->order[RT_NURB_SPLIT_ROW], &srf->u, &new_kv, (struct resource *)NULL); GET_SNURB(srf1); srf1->order[0] = srf->order[0]; srf1->order[1] = srf->order[1]; srf1->dir = RT_NURB_SPLIT_ROW; rt_nurb_kvextract(&srf1->u, &new_kv, 0, k_index + srf1->order[0], (struct resource *)NULL); rt_nurb_kvcopy(&srf1->v, &srf->v, (struct resource *)NULL); srf1->pt_type = srf->pt_type; srf1->s_size[0] = srf1->v.k_size - srf1->order[1]; srf1->s_size[1] = srf1->u.k_size - srf1->order[0]; srf1->ctl_points = (fastf_t *) bu_malloc(sizeof(fastf_t) * srf1->s_size[0] * srf1->s_size[1] * RT_NURB_EXTRACT_COORDS(srf1->pt_type), "rt_nurb_s_xsplit: srf1 row mesh control points"); GET_SNURB(srf2); srf2->order[0] = srf->order[0]; srf2->order[1] = srf->order[1]; srf2->dir = RT_NURB_SPLIT_ROW; rt_nurb_kvextract(&srf2->u, &new_kv, k_index, new_kv.k_size, (struct resource *)NULL); rt_nurb_kvcopy(&srf2->v, &srf->v, (struct resource *)NULL); srf2->pt_type = srf->pt_type; srf2->s_size[0] = srf2->v.k_size - srf2->order[1]; srf2->s_size[1] = srf2->u.k_size - srf2->order[0]; srf2->ctl_points = (fastf_t *) bu_malloc(sizeof(fastf_t) * srf2->s_size[0] * srf2->s_size[1] * RT_NURB_EXTRACT_COORDS(srf2->pt_type), "rt_nurb_s_xsplit: srf2 row mesh control points"); for (i = 0; i < srf->s_size[0]; i++) { fastf_t * old_mesh_ptr; fastf_t * new_mesh_ptr; old_mesh_ptr = &srf->ctl_points[ i * srf->s_size[1] * RT_NURB_EXTRACT_COORDS(srf->pt_type)]; new_mesh_ptr = &srf1->ctl_points[ i * srf1->s_size[1] * RT_NURB_EXTRACT_COORDS(srf1->pt_type)]; rt_nurb_map_oslo(oslo, old_mesh_ptr, new_mesh_ptr, RT_NURB_EXTRACT_COORDS(srf->pt_type), RT_NURB_EXTRACT_COORDS(srf1->pt_type), 0, k_index, srf1->pt_type); new_mesh_ptr = &srf2->ctl_points[ i * srf2->s_size[1] * RT_NURB_EXTRACT_COORDS(srf2->pt_type)]; rt_nurb_map_oslo(oslo, old_mesh_ptr, new_mesh_ptr, RT_NURB_EXTRACT_COORDS(srf->pt_type), RT_NURB_EXTRACT_COORDS(srf2->pt_type), k_index, new_kv.k_size - srf2->order[0], srf2->pt_type); } } else { rt_nurb_kvmult(&new_kv, &srf->v, srf->order[RT_NURB_SPLIT_COL], param, (struct resource *)NULL); k_index = srf->order[1]; oslo = (struct oslo_mat *) rt_nurb_calc_oslo(srf->order[RT_NURB_SPLIT_COL], &srf->v, &new_kv, (struct resource *)NULL); GET_SNURB(srf1); srf1->order[0] = srf->order[0]; srf1->order[1] = srf->order[1]; srf1->dir = RT_NURB_SPLIT_COL; rt_nurb_kvextract(&srf1->v, &new_kv, 0, k_index + srf1->order[RT_NURB_SPLIT_COL], (struct resource *)NULL); rt_nurb_kvcopy(&srf1->u, &srf->u, (struct resource *)NULL); srf1->pt_type = srf->pt_type; srf1->s_size[0] = srf1->v.k_size - srf1->order[1]; srf1->s_size[1] = srf1->u.k_size - srf1->order[0]; srf1->ctl_points = (fastf_t *) bu_malloc(sizeof(fastf_t) * srf1->s_size[0] * srf1->s_size[1] * RT_NURB_EXTRACT_COORDS(srf1->pt_type), "rt_nurb_split: srf1 row mesh control points"); GET_SNURB(srf2); srf2->order[0] = srf->order[0]; srf2->order[1] = srf->order[1]; srf2->dir = RT_NURB_SPLIT_COL; rt_nurb_kvextract(&srf2->v, &new_kv, k_index, new_kv.k_size, (struct resource *)NULL); rt_nurb_kvcopy(&srf2->u, &srf->u, (struct resource *)NULL); srf2->pt_type = srf->pt_type; srf2->s_size[0] = srf2->v.k_size - srf2->order[1]; srf2->s_size[1] = srf2->u.k_size - srf2->order[0]; srf2->ctl_points = (fastf_t *) bu_malloc(sizeof(fastf_t) * srf2->s_size[0] * srf2->s_size[1] * RT_NURB_EXTRACT_COORDS(srf2->pt_type), "rt_nurb_s_xsplit: srf2 row mesh control points"); for (i = 0; i < srf->s_size[1]; i++) { fastf_t * old_mesh_ptr; fastf_t * new_mesh_ptr; old_mesh_ptr = &srf->ctl_points[ i * RT_NURB_EXTRACT_COORDS(srf->pt_type)]; new_mesh_ptr = &srf1->ctl_points[ i * RT_NURB_EXTRACT_COORDS(srf1->pt_type)]; rt_nurb_map_oslo(oslo, old_mesh_ptr, new_mesh_ptr, srf->s_size[1] * RT_NURB_EXTRACT_COORDS(srf->pt_type), srf1->s_size[1] * RT_NURB_EXTRACT_COORDS(srf1->pt_type), 0, k_index, srf1->pt_type); new_mesh_ptr = &srf2->ctl_points[ i * RT_NURB_EXTRACT_COORDS(srf2->pt_type)]; rt_nurb_map_oslo(oslo, old_mesh_ptr, new_mesh_ptr, srf->s_size[1] * RT_NURB_EXTRACT_COORDS(srf->pt_type), srf2->s_size[1] * RT_NURB_EXTRACT_COORDS(srf2->pt_type), k_index, new_kv.k_size - srf2->order[1], srf2->pt_type); } } BU_LIST_APPEND(&srf1->l, &srf2->l); bu_free((char *) new_kv.knots, "rt_nurb_s_xsplit: new_kv.knots"); rt_nurb_free_oslo(oslo, (struct resource *)NULL); return srf1; }
/** * Given a pointer to an internal GED database object, mirror the * object's values about the given transformation matrix. */ int rt_nurb_mirror(struct rt_db_internal *ip, register const plane_t plane) { struct rt_nurb_internal *nurb; mat_t mirmat; mat_t rmat; mat_t temp; vect_t nvec; vect_t xvec; vect_t mirror_dir; point_t mirror_pt; fastf_t ang; int i; int j; static point_t origin = {0.0, 0.0, 0.0}; RT_CK_DB_INTERNAL(ip); nurb = (struct rt_nurb_internal *)ip->idb_ptr; RT_PG_CK_MAGIC(nurb); MAT_IDN(mirmat); VMOVE(mirror_dir, plane); VSCALE(mirror_pt, plane, plane[W]); /* Build mirror transform matrix, for those who need it. */ /* First, perform a mirror down the X axis */ mirmat[0] = -1.0; /* Create the rotation matrix */ VSET(xvec, 1, 0, 0); VCROSS(nvec, xvec, mirror_dir); VUNITIZE(nvec); ang = -acos(VDOT(xvec, mirror_dir)); bn_mat_arb_rot(rmat, origin, nvec, ang*2.0); /* Add the rotation to mirmat */ MAT_COPY(temp, mirmat); bn_mat_mul(mirmat, temp, rmat); /* Add the translation to mirmat */ mirmat[3 + X*4] += mirror_pt[X] * mirror_dir[X]; mirmat[3 + Y*4] += mirror_pt[Y] * mirror_dir[Y]; mirmat[3 + Z*4] += mirror_pt[Z] * mirror_dir[Z]; for (i=0; i<nurb->nsrf; i++) { fastf_t *ptr; int tmp; int orig_size[2]; int ncoords; int m; int l; /* swap knot vectors between u and v */ ptr = nurb->srfs[i]->u.knots; tmp = nurb->srfs[i]->u.k_size; nurb->srfs[i]->u.knots = nurb->srfs[i]->v.knots; nurb->srfs[i]->u.k_size = nurb->srfs[i]->v.k_size; nurb->srfs[i]->v.knots = ptr; nurb->srfs[i]->v.k_size = tmp; /* swap order */ tmp = nurb->srfs[i]->order[0]; nurb->srfs[i]->order[0] = nurb->srfs[i]->order[1]; nurb->srfs[i]->order[1] = tmp; /* swap mesh size */ orig_size[0] = nurb->srfs[i]->s_size[0]; orig_size[1] = nurb->srfs[i]->s_size[1]; nurb->srfs[i]->s_size[0] = orig_size[1]; nurb->srfs[i]->s_size[1] = orig_size[0]; /* allocate memory for a new control mesh */ ncoords = RT_NURB_EXTRACT_COORDS(nurb->srfs[i]->pt_type); ptr = (fastf_t *)bu_calloc(orig_size[0]*orig_size[1]*ncoords, sizeof(fastf_t), "rt_mirror: ctl mesh ptr"); /* mirror each control point */ for (j=0; j<orig_size[0]*orig_size[1]; j++) { point_t pt; VMOVE(pt, &nurb->srfs[i]->ctl_points[j*ncoords]); MAT4X3PNT(&nurb->srfs[i]->ctl_points[j*ncoords], mirmat, pt); } /* copy mirrored control points into new mesh * while swapping u and v */ m = 0; for (j=0; j<orig_size[0]; j++) { for (l=0; l<orig_size[1]; l++) { VMOVEN(&ptr[(l*orig_size[0]+j)*ncoords], &nurb->srfs[i]->ctl_points[m*ncoords], ncoords); m++; } } /* free old mesh */ bu_free((char *)nurb->srfs[i]->ctl_points, "rt_mirror: ctl points"); /* put new mesh in place */ nurb->srfs[i]->ctl_points = ptr; } return 0; }
/** * Algorithm * * Given a parametric direction (u or v) look at the direction knot * vector and insert a multiple knot of parametric direction surface * order. If internal knot values exist than pick the one closest to * the middle and add additional knots to split at that value, * otherwise add multiple knots at the mid point of the knot * vector. Use the new knot vector to pass to the oslo refinement * process and split the surface. Separate the surface and return the * two resulting surface. * * The original surface is undisturbed by this operation. */ void rt_nurb_s_split(struct bu_list *split_hd, const struct face_g_snurb *srf, int dir, struct resource *res) { struct knot_vector new_kv; fastf_t value; struct oslo_mat * oslo; int i; int k_index = 0; struct face_g_snurb * srf1, * srf2; NMG_CK_SNURB(srf); if (dir == RT_NURB_SPLIT_ROW) { value = srf->u.knots[(srf->u.k_size -1)/2]; for (i = 0; i < srf->u.k_size; i++) if (ZERO(value - srf->u.knots[i])) { k_index = i; break; } if (k_index == 0) { value = (value + srf->u.knots[ srf->u.k_size -1]) /2.0; k_index = srf->order[0]; } rt_nurb_kvmult(&new_kv, &srf->u, srf->order[0], value, res); oslo = (struct oslo_mat *) rt_nurb_calc_oslo(srf->order[RT_NURB_SPLIT_ROW], &srf->u, &new_kv, res); GET_SNURB(srf1); srf1->order[0] = srf->order[0]; srf1->order[1] = srf->order[1]; srf1->dir = RT_NURB_SPLIT_ROW; rt_nurb_kvextract(&srf1->u, &new_kv, 0, k_index + srf1->order[0], res); rt_nurb_kvcopy(&srf1->v, &srf->v, res); srf1->pt_type = srf->pt_type; srf1->s_size[0] = srf1->v.k_size - srf1->order[1]; srf1->s_size[1] = srf1->u.k_size - srf1->order[0]; srf1->ctl_points = (fastf_t *) bu_malloc(sizeof(fastf_t) * srf1->s_size[0] * srf1->s_size[1] * RT_NURB_EXTRACT_COORDS(srf1->pt_type), "rt_nurb_s_split: srf1 row mesh control points"); GET_SNURB(srf2); srf2->order[0] = srf->order[0]; srf2->order[1] = srf->order[1]; srf2->dir = RT_NURB_SPLIT_ROW; rt_nurb_kvextract(&srf2->u, &new_kv, k_index, new_kv.k_size, res); rt_nurb_kvcopy(&srf2->v, &srf->v, res); srf2->pt_type = srf->pt_type; srf2->s_size[0] = srf2->v.k_size - srf2->order[1]; srf2->s_size[1] = srf2->u.k_size - srf2->order[0]; srf2->ctl_points = (fastf_t *) bu_malloc(sizeof(fastf_t) * srf2->s_size[0] * srf2->s_size[1] * RT_NURB_EXTRACT_COORDS(srf2->pt_type), "rt_nurb_s_split: srf2 row mesh control points"); for (i = 0; i < srf->s_size[0]; i++) { fastf_t * old_mesh_ptr; fastf_t * new_mesh_ptr; old_mesh_ptr = &srf->ctl_points[ i * srf->s_size[1] * RT_NURB_EXTRACT_COORDS(srf->pt_type)]; new_mesh_ptr = &srf1->ctl_points[ i * srf1->s_size[1] * RT_NURB_EXTRACT_COORDS(srf1->pt_type)]; rt_nurb_map_oslo(oslo, old_mesh_ptr, new_mesh_ptr, RT_NURB_EXTRACT_COORDS(srf->pt_type), RT_NURB_EXTRACT_COORDS(srf1->pt_type), 0, k_index, srf1->pt_type); new_mesh_ptr = &srf2->ctl_points[ i * srf2->s_size[1] * RT_NURB_EXTRACT_COORDS(srf2->pt_type)]; rt_nurb_map_oslo(oslo, old_mesh_ptr, new_mesh_ptr, RT_NURB_EXTRACT_COORDS(srf->pt_type), RT_NURB_EXTRACT_COORDS(srf2->pt_type), k_index, new_kv.k_size - srf2->order[0], srf2->pt_type); } } else { value = srf->v.knots[(srf->v.k_size -1)/2]; for (i = 0; i < srf->v.k_size; i++) if (ZERO(value - srf->v.knots[i])) { k_index = i; break; } if (k_index == 0) { value = (value + srf->v.knots[ srf->v.k_size -1]) /2.0; k_index = srf->order[1]; } rt_nurb_kvmult(&new_kv, &srf->v, srf->order[RT_NURB_SPLIT_COL], value, res); oslo = (struct oslo_mat *) rt_nurb_calc_oslo(srf->order[RT_NURB_SPLIT_COL], &srf->v, &new_kv, res); GET_SNURB(srf1); srf1->order[0] = srf->order[0]; srf1->order[1] = srf->order[1]; srf1->dir = RT_NURB_SPLIT_COL; rt_nurb_kvextract(&srf1->v, &new_kv, 0, k_index + srf1->order[RT_NURB_SPLIT_COL], res); rt_nurb_kvcopy(&srf1->u, &srf->u, res); srf1->pt_type = srf->pt_type; srf1->s_size[0] = srf1->v.k_size - srf1->order[1]; srf1->s_size[1] = srf1->u.k_size - srf1->order[0]; srf1->ctl_points = (fastf_t *) bu_malloc(sizeof(fastf_t) * srf1->s_size[0] * srf1->s_size[1] * RT_NURB_EXTRACT_COORDS(srf1->pt_type), "rt_nurb_s_split: srf1 col mesh control points"); GET_SNURB(srf2); srf2->order[0] = srf->order[0]; srf2->order[1] = srf->order[1]; srf2->dir = RT_NURB_SPLIT_COL; rt_nurb_kvextract(&srf2->v, &new_kv, k_index, new_kv.k_size, res); rt_nurb_kvcopy(&srf2->u, &srf->u, res); srf2->pt_type = srf->pt_type; srf2->s_size[0] = srf2->v.k_size - srf2->order[1]; srf2->s_size[1] = srf2->u.k_size - srf2->order[0]; srf2->ctl_points = (fastf_t *) bu_malloc(sizeof(fastf_t) * srf2->s_size[0] * srf2->s_size[1] * RT_NURB_EXTRACT_COORDS(srf2->pt_type), "rt_nurb_s_split: srf2 col mesh control points"); for (i = 0; i < srf->s_size[1]; i++) { fastf_t * old_mesh_ptr; fastf_t * new_mesh_ptr; old_mesh_ptr = &srf->ctl_points[ i * RT_NURB_EXTRACT_COORDS(srf->pt_type)]; new_mesh_ptr = &srf1->ctl_points[ i * RT_NURB_EXTRACT_COORDS(srf1->pt_type)]; rt_nurb_map_oslo(oslo, old_mesh_ptr, new_mesh_ptr, srf->s_size[1] * RT_NURB_EXTRACT_COORDS(srf->pt_type), srf1->s_size[1] * RT_NURB_EXTRACT_COORDS(srf1->pt_type), 0, k_index, srf1->pt_type); new_mesh_ptr = &srf2->ctl_points[ i * RT_NURB_EXTRACT_COORDS(srf2->pt_type)]; rt_nurb_map_oslo(oslo, old_mesh_ptr, new_mesh_ptr, srf->s_size[1] * RT_NURB_EXTRACT_COORDS(srf->pt_type), srf2->s_size[1] * RT_NURB_EXTRACT_COORDS(srf2->pt_type), k_index, new_kv.k_size - srf2->order[1], srf2->pt_type); } } /* Arrangement will be: head, srf1, srf2 */ BU_LIST_APPEND(split_hd, &srf2->l); BU_LIST_APPEND(split_hd, &srf1->l); rt_nurb_free_oslo(oslo, res); bu_free((char *)new_kv.knots, "rt_nurb_s_split: new kv knots"); }
/** * Split a NURB curve by inserting a multiple knot and return the * result of the two curves. * * Algorithm * * Insert a multiple knot of the curve order. If internal knot values * exist than pick the one closest to the middle and add additional * knots to split at that value, otherwise add multiple knots at the * mid point of the knot vector. Use the new knot vector to pass to * the oslo refinement process and split the curve. Separate the * curve and return the two resulting curves. * * The original curve is undisturbed by this operation. */ void rt_nurb_c_split(struct bu_list *split_hd, const struct edge_g_cnurb *crv) { struct knot_vector new_kv; fastf_t value; struct oslo_mat * oslo; int i; int k_index = 0; struct edge_g_cnurb * crv1, * crv2; int coords; NMG_CK_CNURB(crv); coords = RT_NURB_EXTRACT_COORDS(crv->pt_type), value = crv->k.knots[(crv->k.k_size -1)/2]; for (i = 0; i < crv->k.k_size; i++) if (ZERO(value - crv->k.knots[i])) { k_index = i; break; } if (k_index == 0) { value = (value + crv->k.knots[ crv->k.k_size -1]) /2.0; k_index = crv->order; } rt_nurb_kvmult(&new_kv, &crv->k, crv->order, value, (struct resource *)NULL); oslo = (struct oslo_mat *) rt_nurb_calc_oslo(crv->order, &crv->k, &new_kv, (struct resource *)NULL); GET_CNURB(crv1); crv1->order = crv->order; rt_nurb_kvextract(&crv1->k, &new_kv, 0, k_index + crv->order, (struct resource *)NULL); crv1->pt_type = crv->pt_type; crv1->c_size = crv1->k.k_size - crv1->order; crv1->ctl_points = (fastf_t *) bu_malloc(sizeof(fastf_t) * crv1->c_size * RT_NURB_EXTRACT_COORDS(crv1->pt_type), "rt_nurb_c_split: crv1 control points"); GET_CNURB(crv2); crv2->order = crv->order; rt_nurb_kvextract(&crv2->k, &new_kv, k_index, new_kv.k_size, (struct resource *)NULL); crv2->pt_type = crv->pt_type; crv2->c_size = crv2->k.k_size - crv2->order; crv2->ctl_points = (fastf_t *) bu_malloc(sizeof(fastf_t) * crv2->c_size * RT_NURB_EXTRACT_COORDS(crv2->pt_type), "rt_nurb_s_split: crv2 mesh control points"); rt_nurb_map_oslo(oslo, crv->ctl_points, crv1->ctl_points, coords, coords, 0, k_index, crv->pt_type); rt_nurb_map_oslo(oslo, crv->ctl_points, crv2->ctl_points, coords, coords, k_index, new_kv.k_size - crv2->order, crv2->pt_type); rt_nurb_free_oslo(oslo, (struct resource *)NULL); bu_free((char *) new_kv.knots, "rt_nurb_c_split; new_kv.knots"); /* Arrangement will be: head, crv1, crv2 */ BU_LIST_APPEND(split_hd, &crv2->l); BU_LIST_APPEND(split_hd, &crv1->l); }
struct face_g_snurb * rt_nurb_project_srf(const struct face_g_snurb *srf, fastf_t *plane1, fastf_t *plane2, struct resource *res) { register struct face_g_snurb *psrf; register fastf_t *mp1, *mp2; int n_pt_type; int rational; int i; if (RTG.NMG_debug & DEBUG_RT_ISECT) bu_log("rt_nurb_project_srf: projecting surface, planes = (%g %g %g %g) (%g %g %g %g)\n", V4ARGS(plane1), V4ARGS(plane2)); rational = RT_NURB_IS_PT_RATIONAL(srf->pt_type); n_pt_type = RT_NURB_MAKE_PT_TYPE(2, RT_NURB_PT_PROJ, 0); psrf = (struct face_g_snurb *) rt_nurb_new_snurb(srf->order[0], srf->order[1], srf->u.k_size, srf->v.k_size, srf->s_size[0], srf->s_size[1], n_pt_type, res); psrf->dir = RT_NURB_SPLIT_COL; for (i = 0; i < srf->u.k_size; i++) { psrf->u.knots[i] = srf->u.knots[i]; } for (i = 0; i < srf->v.k_size; i++) { psrf->v.knots[i] = srf->v.knots[i]; } mp1 = srf->ctl_points; mp2 = psrf->ctl_points; for (i = 0; i < srf->s_size[0] * srf->s_size[1]; i++) { if (rational) { mp2[0] = (mp1[0] / mp1[3] * plane1[0] + mp1[1] / mp1[3] * plane1[1] + mp1[2] / mp1[3] * plane1[2] - plane1[3]) * mp1[3]; mp2[1] = (mp1[0] / mp1[3] * plane2[0] + mp1[1] / mp1[3] * plane2[1] + mp1[2] / mp1[3] * plane2[2] - plane2[3]) * mp1[3]; } else { mp2[0] = mp1[0] * plane1[0] + mp1[1] * plane1[1] + mp1[2] * plane1[2] - plane1[3]; mp2[1] = mp1[0] * plane2[0] + mp1[1] * plane2[1] + mp1[2] * plane2[2] - plane2[3]; } if (RTG.NMG_debug & DEBUG_RT_ISECT) { if (rational) bu_log("\tmesh pt (%g %g %g %g), becomes (%g %g)\n", V4ARGS(mp1), mp2[0], mp2[1]); else bu_log("\tmesh pt (%g %g %g), becomes (%g %g)\n", V3ARGS(mp1), mp2[0], mp2[1]); } mp1 += RT_NURB_EXTRACT_COORDS(srf->pt_type); mp2 += RT_NURB_EXTRACT_COORDS(psrf->pt_type); } return (struct face_g_snurb *) psrf; }
struct face_g_snurb * rt_nurb_s_diff(const struct face_g_snurb *srf, int dir) { struct face_g_snurb *nsrf; int i; NMG_CK_SNURB(srf); if (dir == RT_NURB_SPLIT_ROW) { nsrf = (struct face_g_snurb *) rt_nurb_new_snurb(srf->order[0] - 1, srf->order[1], srf->u.k_size - 2, srf->v.k_size, srf->s_size[0], srf->s_size[1] - 1, srf->pt_type, (struct resource *)NULL); for (i = 0; i < srf->s_size[0]; i++) { fastf_t * old_points, *new_points; old_points = srf->ctl_points + i * RT_NURB_EXTRACT_COORDS(srf->pt_type) *srf->s_size[1]; new_points = nsrf->ctl_points + i * RT_NURB_EXTRACT_COORDS(nsrf->pt_type) *nsrf->s_size[1]; rt_nurb_mesh_diff(srf->order[0], old_points, new_points, srf->u.knots, RT_NURB_EXTRACT_COORDS(srf->pt_type), RT_NURB_EXTRACT_COORDS(nsrf->pt_type), srf->s_size[1], srf->pt_type); } for (i = 1; i < srf->u.k_size - 1; i++) nsrf->u.knots[i - 1] = srf->u.knots[i]; for (i = 0; i < srf->v.k_size; i++) nsrf->v.knots[i] = srf->v.knots[i]; } else { nsrf = (struct face_g_snurb *) rt_nurb_new_snurb( srf->order[0], srf->order[1] - 1, srf->u.k_size, srf->v.k_size - 2, srf->s_size[0] - 1, srf->s_size[1], srf->pt_type, (struct resource *)NULL); for (i = 0; i < srf->s_size[1]; i++) { fastf_t * old_points, *new_points; old_points = srf->ctl_points + i * RT_NURB_EXTRACT_COORDS(srf->pt_type); new_points = nsrf->ctl_points + i * RT_NURB_EXTRACT_COORDS(nsrf->pt_type); rt_nurb_mesh_diff(srf->order[1], old_points, new_points, srf->v.knots, RT_NURB_EXTRACT_COORDS(srf->pt_type) * srf->s_size[1], RT_NURB_EXTRACT_COORDS(nsrf->pt_type) * nsrf->s_size[1], srf->s_size[0], srf->pt_type); } for (i = 0; i < srf->u.k_size; i++) nsrf->u.knots[i] = srf->u.knots[i]; for (i = 1; i < srf->v.k_size - 1; i++) nsrf->v.knots[i-1] = srf->v.knots[i]; } return nsrf; }
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; }
void rt_nurb_clip_srf(const struct face_g_snurb *srf, int dir, fastf_t *min, fastf_t *max) { struct internal_convex_hull ch[20]; /* max order is 10 */ register fastf_t * mp1; fastf_t * p1, *p2, *p3, *p4; /* corner points of the mesh */ fastf_t v1[2], v2[2], v3[2]; /* vectors from corners */ struct internal_line l1; fastf_t norm; fastf_t value; int i; register int j; int k; int coords; int col_size, row_size; col_size = srf->s_size[1]; row_size = srf->s_size[0]; coords = RT_NURB_EXTRACT_COORDS(srf->pt_type); p1 = srf->ctl_points; p2 = srf->ctl_points + coords * (col_size - 1); p3 = srf->ctl_points + (coords * col_size * (row_size - 1)); p4 = srf->ctl_points + (coords * col_size * (row_size - 1)) + ((col_size - 1) * coords); if (dir == RT_NURB_SPLIT_ROW) { v1[0] = p1[0] - p3[0]; v1[1] = p1[1] - p3[1]; v2[0] = p2[0] - p4[0]; v2[1] = p2[1] - p4[1]; } else { v1[0] = p1[0] - p2[0]; v1[1] = p1[1] - p2[1]; v2[0] = p3[0] - p4[0]; v2[1] = p3[1] - p4[1]; } v3[0] = v1[0] + v2[0]; v3[1] = v1[1] + v1[1]; norm = sqrt(v3[1] * v3[1] + v3[0] * v3[0]); l1.a = v3[1] / norm; l1.b = -v3[0] / norm; *min = 1.0e8; *max = -1.0e8; if (dir == RT_NURB_SPLIT_ROW) { for (i = 0; i < col_size; i++) { ch[i].param = (fastf_t) i / (col_size - 1.0); ch[i].min = 1.0e8; ch[i].max = -1.0e8; } mp1 = srf->ctl_points; for (i = 0; i < row_size; i++) { for (j = 0; j < col_size; j++) { value = - (mp1[0] * l1.a + mp1[1] * l1.b); if (value <= ch[j].min) ch[j].min = value; if (value >= ch[j].max) ch[j].max = value; mp1 += coords; } } for (k = 0; k < col_size - 1; k++) for (j = k+1; j < col_size; j++) { fastf_t d; fastf_t param1, param2; param1 = ch[k].param; param2 = ch[j].param; d = FINDZERO(param1, param2, ch[k].max, ch[j].max); if (d <= *min) *min = d * .99; if (d >= *max) *max = d * .99 + .01; d = FINDZERO(param1, param2, ch[k].min, ch[j].min); if (d <= *min) *min = d * .99; if (d >= *max) *max = d * .99 + .01; } if (*min <= 0.0) *min = 0.0; if (*max >= 1.0) *max = 1.0; if (SIGN(ch[0].min) != SIGN(ch[0].max)) *min = 0.0; i = SIGN(ch[col_size -1].min); j = SIGN(ch[col_size -1].max); if (i != j) *max = 1.0; } else { for (i = 0; i < row_size; i++) { ch[i].param = (fastf_t) i / (row_size - 1.0); ch[i].min = 1.0e8; ch[i].max = -1.0e8; } for (i = 0; i < col_size; i++) { int stride; stride = coords * col_size; mp1 = srf->ctl_points + i * coords; for (j = 0; j < row_size; j++) { value = - (mp1[0] * l1.a + mp1[1] * l1.b); if (value <= ch[j].min) ch[j].min = value; if (value >= ch[j].max) ch[j].max = value; mp1 += stride; } } for (k = 0; k < row_size - 1; k++) for (j = k+1; j < row_size; j++) { fastf_t d; fastf_t param1, param2; param1 = ch[k].param; param2 = ch[j].param; d = FINDZERO(param1, param2, ch[k].max, ch[j].max); if (d <= *min) *min = d * .99; if (d >= *max) *max = d * .99 + .01; d = FINDZERO(param1, param2, ch[k].min, ch[j].min); if (d <= *min) *min = d * .99; if (d >= *max) *max = d * .99 + .01; } if (*min <= 0.0) *min = 0.0; if (*max >= 1.0) *max = 1.0; if (SIGN(ch[0].min) != SIGN(ch[0].max)) *min = 0.0; i = SIGN(ch[row_size-1 ].min); j = SIGN(ch[row_size -1].max); if (i != j) *max = 1.0; } }
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))); }
fastf_t rt_nurb_crv_flat(fastf_t *crv, int size, int pt_type) { point_t p1, p2; vect_t ln; int i; fastf_t dist; fastf_t max_dist; fastf_t length; fastf_t * c_ptr; vect_t testv, xp; hvect_t h1, h2; int coords; int rational; coords = RT_NURB_EXTRACT_COORDS(pt_type); rational = RT_NURB_IS_PT_RATIONAL(pt_type); max_dist = -INFINITY; if (!rational) { VMOVE(p1, crv); } else { HMOVE(h1, crv); HDIVIDE(p1, h1); } length = 0.0; /* * loop through all of the points until a line is found which may * not be the end pts of the curve if the endpoints are the same. */ for (i = size - 1; (i > 0) && length < SQRT_SMALL_FASTF; i--) { if (!rational) { VMOVE(p2, (crv + (i * coords))); } else { HMOVE(h2, (crv + (i * coords))); HDIVIDE(p2, h2); } VSUB2(ln, p1, p2); length = MAGNITUDE(ln); } if (length >= SQRT_SMALL_FASTF) { VSCALE(ln, ln, 1.0 / length); c_ptr = crv + coords; for (i = 1; i < size; i++) { if (!rational) { VSUB2(testv, p1, c_ptr); } else { HDIVIDE(h2, c_ptr); VSUB2(testv, p1, h2); } VCROSS(xp, testv, ln); dist = MAGNITUDE(xp); max_dist = FMAX(max_dist, dist); c_ptr += coords; } } return max_dist; }
int rt_nurb_s_flat(struct face_g_snurb *srf, fastf_t epsilon) /* Epsilon value for flatness testing */ { register fastf_t max_row_dist; register fastf_t max_col_dist; register fastf_t max_dist; int dir; fastf_t * mesh_ptr = srf->ctl_points; int coords = RT_NURB_EXTRACT_COORDS(srf->pt_type); int j, i, k; int mesh_elt; vect_t p1, p2, p3, p4, v1, v2, v3; vect_t nrm; fastf_t nrmln; fastf_t dist; fastf_t * crv; int otherdir; dir = srf->dir; otherdir = (dir == RT_NURB_SPLIT_ROW) ? RT_NURB_SPLIT_COL : RT_NURB_SPLIT_ROW; max_row_dist = max_col_dist = -INFINITY; crv = (fastf_t *) bu_malloc(sizeof(fastf_t) * RT_NURB_EXTRACT_COORDS(srf->pt_type) * srf->s_size[1], "rt_nurb_s_flat: crv"); /* Test Row and RT_NURB_SPLIT_COL curves for flatness, If a curve * is not flat than get distance to line */ /* Test Row Curves */ for (i = 0; i < (srf->s_size[0]); i++) { fastf_t rdist; for (j = 0; j < (srf->s_size[1] * RT_NURB_EXTRACT_COORDS(srf->pt_type)); j++) crv[j] = *mesh_ptr++; rdist = rt_nurb_crv_flat(crv, srf->s_size[1], srf->pt_type); max_row_dist = FMAX(max_row_dist, rdist); } bu_free((char *)crv, "rt_nurb_s_flat: crv"); crv = (fastf_t *) bu_malloc(sizeof(fastf_t) * RT_NURB_EXTRACT_COORDS(srf->pt_type) * srf->s_size[0], "rt_nurb_s_flat: crv"); for (i = 0; i < (coords * srf->s_size[1]); i += coords) { fastf_t rdist; for (j = 0; j < (srf->s_size[0]); j++) { mesh_elt = (j * (srf->s_size[1] * coords)) + i; for (k = 0; k < coords; k++) crv[j * coords + k] = srf->ctl_points[mesh_elt + k]; } rdist = rt_nurb_crv_flat(crv, srf->s_size[0], srf->pt_type); max_col_dist = FMAX(max_col_dist, rdist); } bu_free((char *)crv, "rt_nurb_s_flat: crv"); max_dist = FMAX(max_row_dist, max_col_dist); if (max_dist > epsilon) { if (max_row_dist > max_col_dist) return RT_NURB_SPLIT_ROW; else return RT_NURB_SPLIT_COL; } /* Test the corners to see if they lie in a plane. */ /* * Extract the four corners and put a plane through three of them * and see how far the fourth is to the plane. */ mesh_ptr = srf->ctl_points; if (!RT_NURB_IS_PT_RATIONAL(srf->pt_type)) { VMOVE(p1, mesh_ptr); VMOVE(p2, (mesh_ptr + (srf->s_size[1] - 1) * coords)); VMOVE(p3, (mesh_ptr + ((srf->s_size[1] * (srf->s_size[0] - 1)) + (srf->s_size[1] - 1)) * coords)); VMOVE(p4, (mesh_ptr + (srf->s_size[1] * (srf->s_size[0] - 1)) * coords)); } else { hvect_t h1, h2, h3, h4; int offset; HMOVE(h1, mesh_ptr); HDIVIDE(p1, h1); offset = (srf->s_size[1] - 1) * coords; HMOVE(h2, mesh_ptr + offset); HDIVIDE(p2, h2); offset = ((srf->s_size[1] * (srf->s_size[0] - 1)) + (srf->s_size[1] - 1)) * coords; HMOVE(h3, mesh_ptr + offset); HDIVIDE(p3, h3); offset = (srf->s_size[1] * (srf->s_size[0] - 1)) * coords; HMOVE(h4, mesh_ptr + offset); HDIVIDE(p4, h4); } VSUB2(v1, p2, p1); VSUB2(v2, p3, p1); VCROSS(nrm, v1, v2); nrmln = MAGNITUDE(nrm); if (nrmln < 0.0001) /* XXX Why this constant? */ return RT_NURB_SPLIT_FLAT; VSUB2(v3, p4, p1); dist = fabs(VDOT(v3, nrm)) / nrmln; if (dist > epsilon) return otherdir; return RT_NURB_SPLIT_FLAT; /* Must be flat */ }