/** * 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_process_casec(struct edge_g_cnurb *trim, fastf_t u, fastf_t v) { struct edge_g_cnurb * clip; int jordan_hit; struct bu_list plist; int trim_flag = 0; int caset; /* determine if the the u, v values are on the curve */ if ( rt_nurb_uv_dist(trim, u, v) == TRIM_ON) return TRIM_IN; jordan_hit = 0; BU_LIST_INIT(&plist); if ( nurb_crv_is_bezier( trim ) ) rt_clip_cnurb(&plist, trim, u, v); else nurb_c_to_bezier( &plist, trim ); while ( BU_LIST_WHILE( clip, edge_g_cnurb, &plist ) ) { BU_LIST_DEQUEUE( &clip->l ); caset = rt_trim_case(clip, u, v); trim_flag = 0; if ( caset == CASE_B) trim_flag = rt_process_caseb(clip, u, v); if ( caset == CASE_C) trim_flag = rt_process_casec(clip, u, v); rt_nurb_free_cnurb( clip ); if ( trim_flag == TRIM_IN) jordan_hit++; if ( trim_flag == TRIM_ON) break; } while ( BU_LIST_WHILE( clip, edge_g_cnurb, &plist) ) { BU_LIST_DEQUEUE( &clip->l ); rt_nurb_free_cnurb( clip ); } if ( trim_flag == TRIM_ON) return TRIM_ON; else if ( jordan_hit & 01 ) return TRIM_IN; else return TRIM_OUT; }
void nurb_c_to_bezier(struct bu_list *clist, struct edge_g_cnurb *crv) { fastf_t knot_min, knot_max; int i; struct edge_g_cnurb *crv1, *crv_copy; int done; /* make a copy of original curve */ crv_copy = rt_nurb_crv_copy( crv ); /* split curve at each knot value */ done = 0; while ( !done ) { fastf_t split; knot_min = crv_copy->k.knots[0]; knot_max = crv_copy->k.knots[crv_copy->k.k_size-1]; split = MAX_FASTF; for ( i=1; i<crv_copy->k.k_size-1; i++ ) { if ( crv_copy->k.knots[i] != knot_min && crv_copy->k.knots[i] != knot_max ) { split = crv_copy->k.knots[i]; break; } } if ( split == MAX_FASTF ) { done = 1; BU_LIST_APPEND( clist, &crv_copy->l ); break; } crv1 = rt_nurb_c_xsplit( crv_copy, split ); rt_nurb_free_cnurb( crv_copy ); crv_copy = BU_LIST_PNEXT( edge_g_cnurb, &crv1->l ); BU_LIST_DEQUEUE( &crv_copy->l ); BU_LIST_APPEND( clist, &crv1->l ); } }
/* * We try and clip a curve so that it can be either Case A, or Case C. * Sometimes one of the curves is still case C though, but it is much * small than the original, and further clipping will either show that * it is on the curve or provide all Case B or Case A curves. * We try and pick the best axis to clip against, but this may not always * work. One extra step that was included, that is not in the paper for * curves but is for surfaces, is the fact that sometimes the curve is * not clipped enough, if the maximum clip is less than .2 than we sub * divide the curve in three equal parts, at .3 and .6, * Subdivision is done using the Oslo Algorithm, rather than the other * methods which were prossed. */ void rt_clip_cnurb(struct bu_list *plist, struct edge_g_cnurb *crv, fastf_t u, fastf_t v) { fastf_t ds1, dt1; struct _interior_line s_line, t_line; int axis, i; fastf_t umin, umax; int coords; struct edge_g_cnurb * c1, *c2, *tmp; fastf_t m1, m2; int zero_changed; fastf_t *ptr; fastf_t dist[10]; coords = RT_NURB_EXTRACT_COORDS( crv->pt_type); s_line.axis = 0; s_line.o_dist = v; t_line.axis = 1; t_line.o_dist = u; ds1 = 0.0; dt1 = 0.0; ptr = crv->ctl_points; /* determine what axis to clip against */ for ( i = 0; i < crv->c_size; i++, ptr += coords) { ds1 += fabs( rt_trim_line_pt_dist( &s_line, ptr, crv->pt_type) ); dt1 += fabs( rt_trim_line_pt_dist( &t_line, ptr, crv->pt_type) ); } if ( ds1 >= dt1 ) axis = 0; else axis = 1; ptr = crv->ctl_points; for ( i = 0; i < crv->c_size; i++) { if ( axis == 1) dist[i] = rt_trim_line_pt_dist(&t_line, ptr, crv->pt_type); else dist[i] = rt_trim_line_pt_dist(&s_line, ptr, crv->pt_type); ptr += coords; } /* Find the convex hull of the distances and determine the * minimum and maximum distance to clip against. See the * paper for details about this step */ umin = 10e40; umax = -10e40; zero_changed = 0; for ( i = 0; i < crv->c_size; i++) { fastf_t d1, d2; fastf_t x0, x1, zero; if ( i == (crv->c_size -1 ) ) { d1 = dist[i]; d2 = dist[0]; x0 = (fastf_t) i / (fastf_t) (crv->c_size - 1); x1 = 0.0; } else { d1 = dist[i]; d2 = dist[i+1]; x0 = (fastf_t) i / (fastf_t) (crv->c_size - 1 ); x1 = (i+1.0) / (crv->c_size - 1); } if ( _SIGN(d1) != _SIGN(d2) ) { zero = x0 - d1 * (x1 - x0)/ (d2-d1); if ( zero <= umin) umin = zero * .99; if ( zero >= umax) umax = zero * .99 + .01; zero_changed = 1; } } if ( !zero_changed) return; /* Clip is not large enough, split in thiords and try again */ if ( umax - umin < .2) { umin = .3; umax = .6; } /* Translate the 0.0-->1.09 clipping against the real knots */ m1 = (crv->k.knots[0] * (1 - umin)) + crv->k.knots[crv->k.k_size -1] * umin; m2 = (crv->k.knots[0] * (1-umax)) + crv->k.knots[crv->k.k_size -1] * umax; /* subdivide the curve */ c1 = (struct edge_g_cnurb *) rt_nurb_c_xsplit(crv, m1); c2 = rt_nurb_c_xsplit((struct edge_g_cnurb *) c1->l.forw, m2); tmp = (struct edge_g_cnurb *) c1->l.forw; BU_LIST_DEQUEUE( &tmp->l); rt_nurb_free_cnurb( tmp ); BU_LIST_INIT( plist ); BU_LIST_INSERT( &c2->l, plist); BU_LIST_APPEND( plist, &c1->l); }