/**
 * 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;
}
示例#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;
}
示例#3
0
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 );
    }
}
示例#4
0
/*
 *  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);
}