void CatmullRomSpline::Get(DBL p, EXPRESS& v) { if (SplineEntries.size() == 1) memcpy(&v, &SplineEntries.front().vec, sizeof(EXPRESS)); else { /* 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 only two points, return their average */ if(SplineEntries.size() == 2) v[k] = (SplineEntries[0].vec[k] + SplineEntries[1].vec[k])/2.0; /* Catmull-Rom: If only three points, return the second one */ else if(i < 2) v[k] = SplineEntries[1].vec[k]; /* Catmull-Rom: Can't interpolate before second point or after next-to-last */ else if(i >= SplineEntries.size()-1) v[k] = SplineEntries[SplineEntries.size()-2].vec[k]; /* Else, normal case */ else v[k] = catmull_rom_interpolate(SplineEntries, i-1, k, p); } } }
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]; }