Пример #1
0
void NaturalSpline::Get(DBL p, EXPRESS& v)
{
    if (SplineEntries.size() == 1)
        memcpy(&v, &SplineEntries.front().vec, sizeof(EXPRESS));
    else
    {
        if (!Coeffs_Computed)
            Precompute_Cubic_Coeffs(this);
        /* Find which spline segment we're in.  i is the control point at the end of the segment */
        SplineEntryList::size_type i = findt(this, p);
        for(int k=0; k<5; k++)
        {
            /* If outside the spline range, return the first or last point */
            if(i == 0)
                v[k] = SplineEntries.front().vec[k];
            else if(i >= SplineEntries.size())
                v[k] = SplineEntries.back().vec[k];
            /* Else, normal case.  cubic_interpolate can handle the case of not enough points */
            else
                v[k] = natural_interpolate(SplineEntries, i-1, k, p);
        }
    }
}
Пример #2
0
DBL Get_Spline_Val(SPLINE *sp, DBL p, EXPRESS v, int *Terms)
{
    int i, k;
    int last;
    SPLINE_ENTRY * se;

    *Terms = sp->Terms;

    if(!sp->Coeffs_Computed)
    {
        switch(sp->Type)
        {
            case NATURAL_SPLINE:
                Precompute_Cubic_Coeffs(sp);
                break;
            default:
                break;
        }
    }

	// check if the value is in the cache
	if((sp->Cache_Point == p) && (sp->Cache_Type == sp->Type))
	{
		if(sp->Cache_Valid == true) // doing this here is more efficient as it is rarely false [trf]
		{
			Assign_Express(v, sp->Cache_Data);
			return sp->Cache_Data[0];
		}
	}

	// init some cache data
	sp->Cache_Valid = false;
	sp->Cache_Type = sp->Type;
	sp->Cache_Point = p;

    last = sp->Number_Of_Entries-1;
    se = sp->SplineEntries;
    
    if(last == 0)
    {/* if only one entry then return this */
        for(k=0; k<5; k++)
            v[k] = se[0].vec[k];
        return se[0].vec[0];
    }

    /* Find which spline segment we're in.  i is the control point at the end of the segment */
    i = findt(sp, p);

    switch(sp->Type)
    {
        case LINEAR_SPLINE:
            for(k=0; k<5; k++)
            {
                /* If outside spline range, return first or last point */
                if(i == 0)
                    v[k] = se[0].vec[k];
                else if(i > last)
                    v[k] = se[last].vec[k];
                /* Else, normal case */
                else
                    v[k] = linear_interpolate(se, i-1, k, p);
            }
            break;
        case QUADRATIC_SPLINE:
            for(k=0; k<5; k++)
            {
                /* If outside the spline range, return the first or last point */
                if(i == 0)
                    v[k] = se[0].vec[k];
                else if(i > last)
                    v[k] = se[last].vec[k];
                /* If not enough points, reduce order */
                else if(last == 1)
                    v[k] = linear_interpolate(se, i-1, k, p);
                /* Normal case: between the second and last points */
                else if(i > 1)
                {
                    v[k] = quadratic_interpolate(se, i-1, k, p);
                }
                else /* Special case: between first and second points */
                {
                    v[k] = quadratic_interpolate(se, i, k, p);
                }
            }
            break;
        case NATURAL_SPLINE:
            for(k=0; k<5; k++)
            {
                /* If outside the spline range, return the first or last point */
                if(i == 0)
                    v[k] = se[0].vec[k];
                else if(i > last)
                    v[k] = se[last].vec[k];
                /* Else, normal case.  cubic_interpolate can handle the case of not enough points */
                else
                    v[k] = natural_interpolate(se, i-1, k, p);
            }
            break;
        case CATMULL_ROM_SPLINE:
            for(k=0; k<5; k++)
            {
                /* If only two points, return their average */
                if(last == 1)
                    v[k] = (se[0].vec[k] + se[1].vec[k])/2.0;
                /* Catmull-Rom: If only three points, return the second one */
                /* Catmull-Rom: Can't interpolate before second point or after next-to-last */
                else if(i < 2)
                    v[k] = se[1].vec[k];
                else if(i >= last)
                    v[k] = se[last-1].vec[k];
                /* Else, normal case */
                else
                    v[k] = catmull_rom_interpolate(se, i-1, k, p);
            }
            break;
        default:
            Error("Unknown spline type %d found.\n", sp->Type);

    }

	// put data in cache
	Assign_Express(sp->Cache_Data, v);
	sp->Cache_Valid = true;

    return v[0];
}