51 template<
int Degree >
inline bool LeftOverlap(
unsigned int depth ,
int offset )
54 if( Degree & 1 )
return (offset < 1+Degree) && (offset > -1-Degree );
55 else return (offset < Degree) && (offset > -2-Degree );
57 template<
int Degree >
inline bool RightOverlap(
unsigned int depth ,
int offset )
61 if( Degree & 1 )
return (offset > 2-1-Degree) && (offset < 2+1+Degree );
62 else return (offset > 2-2-Degree) && (offset < 2+ Degree );
64 template<
int Degree >
inline int ReflectLeft(
unsigned int depth ,
int offset )
66 if( Degree&1 )
return -offset;
67 else return -1-offset;
69 template<
int Degree >
inline int ReflectRight(
unsigned int depth ,
int offset )
72 if( Degree&1 )
return r -offset;
73 else return r-1-offset;
76 template<
int Degree,
class Real>
86 vvDotTable = dvDotTable = ddDotTable = NullPointer< Real >();
87 valueTables = dValueTables = NullPointer< Real >();
90 template<
int Degree,
class Real>
95 if( vvDotTable ) DeletePointer( vvDotTable );
96 if( dvDotTable ) DeletePointer( dvDotTable );
97 if( ddDotTable ) DeletePointer( ddDotTable );
98 if( valueTables ) DeletePointer( valueTables );
99 if( dValueTables ) DeletePointer( dValueTables );
104 template<
int Degree,
class Real>
107 this->useDotRatios = useDotRatios;
108 this->boundaryType = boundaryType;
114 baseFunctions = NewPointer< PPolynomial< Degree > >( functionCount );
115 baseBSplines = NewPointer< BSplineComponents >( functionCount );
118 for(
int i=0 ; i<=Degree ; i++ ) baseBSpline[i] = Polynomial< Degree >::BSplineComponent( i ).shift(
double(-(Degree+1)/2) + i - 0.5 );
119 dBaseFunction = baseFunction.derivative();
122 for(
int i=0 ; i<Degree+3 ; i++ )
124 sPolys[i].start = double(-(Degree+1)/2) + i - 1.5;
126 if( i<=Degree ) sPolys[i].p += baseBSpline[i ].shift( -1 ) * boundaryType;
127 if( i>=1 && i<=Degree+1 ) sPolys[i].p += baseBSpline[i-1];
128 for(
int j=0 ; j<i ; j++ ) sPolys[i].p -= sPolys[j].p;
130 leftBaseFunction.set( sPolys , Degree+3 );
131 for(
int i=0 ; i<Degree+3 ; i++ )
133 sPolys[i].start = double(-(Degree+1)/2) + i - 0.5;
135 if( i<=Degree ) sPolys[i].p += baseBSpline[i ];
136 if( i>=1 && i<=Degree+1 ) sPolys[i].p += baseBSpline[i-1].shift( 1 ) * boundaryType;
137 for(
int j=0 ; j<i ; j++ ) sPolys[i].p -= sPolys[j].p;
139 rightBaseFunction.set( sPolys , Degree+3 );
140 for(
int i=0 ; i<Degree+4 ; i++ )
142 sPolys[i].start = double(-(Degree+1)/2) + i - 1.5;
144 if( i<=Degree ) sPolys[i].p += baseBSpline[i ].shift( -1 ) * boundaryType;
145 if( i>=1 && i<=Degree+1 ) sPolys[i].p += baseBSpline[i-1];
146 if( i>=2 && i<=Degree+2 ) sPolys[i].p += baseBSpline[i-2].shift( 1 ) * boundaryType;
147 for(
int j=0 ; j<i ; j++ ) sPolys[i].p -= sPolys[j].p;
149 leftRightBaseFunction.set( sPolys , Degree+4 );
151 dLeftBaseFunction = leftBaseFunction.derivative();
152 dRightBaseFunction = rightBaseFunction.derivative();
153 dLeftRightBaseFunction = leftRightBaseFunction.derivative();
154 leftRightBSpline = leftBSpline = rightBSpline = baseBSpline;
155 leftBSpline [1] += leftBSpline[2].shift( -1 ) , leftBSpline[0] *= 0;
156 rightBSpline[1] += rightBSpline[0].shift( 1 ) , rightBSpline[2] *= 0;
157 leftRightBSpline[1] += leftRightBSpline[2].shift( -1 ) + leftRightBSpline[0].shift( 1 ) , leftRightBSpline[0] *= 0 , leftRightBSpline[2] *= 0 ;
160 for(
int i=0 ; i<functionCount ; i++ )
163 baseFunctions[i] = baseFunction.scale(w).shift(c);
164 baseBSplines[i] = baseBSpline.scale(w).shift(c);
170 if ( off==0 && off==r-1 ) baseFunctions[i] = leftRightBaseFunction.scale(w).shift(c);
171 else if( off==0 ) baseFunctions[i] = leftBaseFunction.scale(w).shift(c);
172 else if( off==r-1 ) baseFunctions[i] = rightBaseFunction.scale(w).shift(c);
173 if ( off==0 && off==r-1 ) baseBSplines [i] = leftRightBSpline.scale(w).shift(c);
174 else if( off==0 ) baseBSplines [i] = leftBSpline.scale(w).shift(c);
175 else if( off==r-1 ) baseBSplines [i] = rightBSpline.scale(w).shift(c);
179 template<
int Degree,
class Real>
182 clearDotTables( flags );
183 int size = ( functionCount*functionCount + functionCount )>>1;
184 int fullSize = functionCount*functionCount;
185 if( flags & VV_DOT_FLAG )
187 vvDotTable = NewPointer< Real >( size );
188 memset( vvDotTable , 0 ,
sizeof(Real)*size );
190 if( flags & DV_DOT_FLAG )
192 dvDotTable = NewPointer< Real >( fullSize );
193 memset( dvDotTable , 0 ,
sizeof(Real)*fullSize );
195 if( flags & DD_DOT_FLAG )
197 ddDotTable = NewPointer< Real >( size );
198 memset( ddDotTable , 0 ,
sizeof(Real)*size );
200 double vvIntegrals[Degree+1][Degree+1];
201 double vdIntegrals[Degree+1][Degree ];
202 double dvIntegrals[Degree ][Degree+1];
203 double ddIntegrals[Degree ][Degree ];
204 int vvSums[Degree+1][Degree+1];
205 int vdSums[Degree+1][Degree ];
206 int dvSums[Degree ][Degree+1];
207 int ddSums[Degree ][Degree ];
208 SetBSplineElementIntegrals< Degree , Degree >( vvIntegrals );
209 SetBSplineElementIntegrals< Degree , Degree-1 >( vdIntegrals );
210 SetBSplineElementIntegrals< Degree-1 , Degree >( dvIntegrals );
211 SetBSplineElementIntegrals< Degree-1 , Degree-1 >( ddIntegrals );
213 for(
int d1=0 ; d1<=depth ; d1++ )
214 for(
int off1=0 ; off1<(1<<d1) ; off1++ )
219 b1.differentiate( db1 );
223 start1 = -1 , end1 = -1;
224 for(
int i=0 ; i<int(b1.size()) ; i++ )
for(
int j=0 ; j<=Degree ; j++ )
226 if( b1[i][j] && start1==-1 ) start1 = i;
227 if( b1[i][j] ) end1 = i+1;
229 if( start1==end1 )
continue;
230 for(
int d2=d1 ; d2<=depth ; d2++ )
232 for(
int off2=0 ; off2<(1<<d2) ; off2++ )
234 int start2 = off2-Degree;
235 int end2 = off2+Degree+1;
236 if( start2>=end1 || start1>=end2 )
continue;
237 start2 = std::max< int >( start1 , start2 );
238 end2 = std::min< int >( end1 , end2 );
239 if( d1==d2 && off2<off1 )
continue;
243 b2.differentiate( db2 );
245 int idx = SymmetricIndex( ii , jj );
246 int idx1 = Index( ii , jj ) , idx2 = Index( jj , ii );
248 memset( vvSums , 0 ,
sizeof(
int ) * ( Degree+1 ) * ( Degree+1 ) );
249 memset( vdSums , 0 ,
sizeof(
int ) * ( Degree+1 ) * ( Degree ) );
250 memset( dvSums , 0 ,
sizeof(
int ) * ( Degree ) * ( Degree+1 ) );
251 memset( ddSums , 0 ,
sizeof(
int ) * ( Degree ) * ( Degree ) );
252 for(
int i=start2 ; i<end2 ; i++ )
254 for(
int j=0 ; j<=Degree ; j++ )
for(
int k=0 ; k<=Degree ; k++ ) vvSums[j][k] += b1[i][j] * b2[i][k];
255 for(
int j=0 ; j<=Degree ; j++ )
for(
int k=0 ; k< Degree ; k++ ) vdSums[j][k] += b1[i][j] * db2[i][k];
256 for(
int j=0 ; j< Degree ; j++ )
for(
int k=0 ; k<=Degree ; k++ ) dvSums[j][k] += db1[i][j] * b2[i][k];
257 for(
int j=0 ; j< Degree ; j++ )
for(
int k=0 ; k< Degree ; k++ ) ddSums[j][k] += db1[i][j] * db2[i][k];
259 double vvDot = 0 , dvDot = 0 , vdDot = 0 , ddDot = 0;
260 for(
int j=0 ; j<=Degree ; j++ )
for(
int k=0 ; k<=Degree ; k++ ) vvDot += vvIntegrals[j][k] * vvSums[j][k];
261 for(
int j=0 ; j<=Degree ; j++ )
for(
int k=0 ; k< Degree ; k++ ) vdDot += vdIntegrals[j][k] * vdSums[j][k];
262 for(
int j=0 ; j< Degree ; j++ )
for(
int k=0 ; k<=Degree ; k++ ) dvDot += dvIntegrals[j][k] * dvSums[j][k];
263 for(
int j=0 ; j< Degree ; j++ )
for(
int k=0 ; k< Degree ; k++ ) ddDot += ddIntegrals[j][k] * ddSums[j][k];
266 vvDot /= ( b1.denominator * b2.denominator );
267 dvDot /= ( b1.denominator * b2.denominator );
268 vdDot /= ( b1.denominator * b2.denominator );
269 ddDot /= ( b1.denominator * b2.denominator );
270 if( fabs(vvDot)<1e-15 )
continue;
271 if( flags & VV_DOT_FLAG ) vvDotTable [idx] = Real( vvDot );
274 if( flags & DV_DOT_FLAG ) dvDotTable[idx1] = Real( dvDot / vvDot );
275 if( flags & DV_DOT_FLAG ) dvDotTable[idx2] = Real( vdDot / vvDot );
276 if( flags & DD_DOT_FLAG ) ddDotTable[idx ] = Real( ddDot / vvDot );
280 if( flags & DV_DOT_FLAG ) dvDotTable[idx1] = Real( dvDot );
281 if( flags & DV_DOT_FLAG ) dvDotTable[idx2] = Real( dvDot );
282 if( flags & DD_DOT_FLAG ) ddDotTable[idx ] = Real( ddDot );
288 b1.differentiate( db1 );
290 for(
int i=0 ; i<int(b1.size()) ; i++ )
for(
int j=0 ; j<=Degree ; j++ )
292 if( b1[i][j] && start1==-1 ) start1 = i;
293 if( b1[i][j] ) end1 = i+1;
298 template<
int Degree,
class Real>
301 if( (flags & VV_DOT_FLAG) && vvDotTable ) DeletePointer( vvDotTable );
302 if( (flags & DV_DOT_FLAG) && dvDotTable ) DeletePointer( dvDotTable );
303 if( (flags & DD_DOT_FLAG) && ddDotTable ) DeletePointer( ddDotTable );
305 template<
int Degree ,
class Real >
311 double _start = ( off + 0.5 - 0.5*(Degree+1) ) / res - smooth;
312 double _end = ( off + 0.5 + 0.5*(Degree+1) ) / res + smooth;
316 start = int( floor( _start * (sampleCount-1) + 1 ) );
317 if( start<0 ) start = 0;
321 end = int( ceil( _end * (sampleCount-1) - 1 ) );
322 if( end>=sampleCount ) end = sampleCount-1;
324 template<
int Degree,
class Real>
328 if( flags & VALUE_FLAG ) valueTables = NewPointer< Real >( functionCount*sampleCount );
329 if( flags & D_VALUE_FLAG ) dValueTables = NewPointer< Real >( functionCount*sampleCount );
332 for(
int i=0 ; i<functionCount ; i++ )
336 function = baseFunctions[i].MovingAverage(smooth);
337 dFunction = baseFunctions[i].derivative().MovingAverage(smooth);
341 function = baseFunctions[i];
342 dFunction = baseFunctions[i].derivative();
344 for(
int j=0 ; j<sampleCount ; j++ )
346 double x=double(j)/(sampleCount-1);
347 if( flags & VALUE_FLAG ) valueTables[j*functionCount+i] = Real(
function(x) );
348 if( flags & D_VALUE_FLAG ) dValueTables[j*functionCount+i] = Real( dFunction(x) );
352 template<
int Degree,
class Real>
356 if(flags & VALUE_FLAG) valueTables = NewPointer< Real >( functionCount*sampleCount );
357 if(flags & D_VALUE_FLAG) dValueTables = NewPointer< Real >( functionCount*sampleCount );
358 PPolynomial<Degree+1>
function;
360 for(
int i=0 ; i<functionCount ; i++ )
362 if( valueSmooth>0 )
function=baseFunctions[i].MovingAverage( valueSmooth );
363 else function=baseFunctions[i];
364 if( derivativeSmooth>0 ) dFunction=baseFunctions[i].derivative().MovingAverage( derivativeSmooth );
365 else dFunction=baseFunctions[i].derivative();
367 for(
int j=0 ; j<sampleCount ; j++ )
369 double x=double(j)/(sampleCount-1);
370 if( flags & VALUE_FLAG ) valueTables[j*functionCount+i] = Real(
function(x));
371 if( flags & D_VALUE_FLAG ) dValueTables[j*functionCount+i] = Real(dFunction(x));
377 template<
int Degree,
class Real>
379 if( valueTables ) DeletePointer( valueTables );
380 if( dValueTables ) DeletePointer( dValueTables );
383 template<
int Degree,
class Real>
385 template<
int Degree,
class Real>
388 if( i1>i2 )
return ((i1*i1+i1)>>1)+i2;
389 else return ((i2*i2+i2)>>1)+i1;
391 template<
int Degree,
class Real>
396 index = ((i2*i2+i2)>>1)+i1;
401 index = ((i1*i1+i1)>>1)+i2;
410 template<
int Degree >
416 for(
int i=0 ; i<=Degree ; i++ )
418 int idx = -_off + offset + i;
419 if( idx>=0 && idx<res ) (*this)[idx][i] = 1;
423 _addLeft( offset-2*res , boundary ) , _addRight( offset+2*res , boundary );
424 if( Degree&1 ) _addLeft( offset-res , boundary ) , _addRight( offset+res , boundary );
425 else _addLeft( -offset-1 , boundary ) , _addRight( -offset-1+2*res , boundary );
427 if( inset )
for(
int i=0 ; i<inset && i<res ; i++ )
for(
int j=0 ; j<=Degree ; j++ ) (*
this)[i][j] = (*this)[res-1-i][j] = 0;
429 template<
int Degree >
432 int res = int( this->size() );
434 for(
int i=0 ; i<=Degree ; i++ )
436 int idx = -_off + offset + i;
437 if( idx>=0 && idx<res ) (*this)[idx][i] += boundary , set =
true;
439 if( set ) _addLeft( offset-2*res , boundary );
441 template<
int Degree >
444 int res = int( this->size() );
446 for(
int i=0 ; i<=Degree ; i++ )
448 int idx = -_off + offset + i;
449 if( idx>=0 && idx<res ) (*this)[idx][i] += boundary , set =
true;
451 if( set ) _addRight( offset+2*res , boundary );
453 template<
int Degree >
456 fprintf( stderr ,
"[ERROR] B-spline up-sampling not supported for degree %d\n" , Degree );
462 high.resize( size()*2 );
464 for(
int i=0 ; i<int(size()) ; i++ )
466 high[2*i+0][0] += 1 * (*this)[i][0];
467 high[2*i+0][1] += 0 * (*this)[i][0];
468 high[2*i+1][0] += 2 * (*this)[i][0];
469 high[2*i+1][1] += 1 * (*this)[i][0];
471 high[2*i+0][0] += 1 * (*this)[i][1];
472 high[2*i+0][1] += 2 * (*this)[i][1];
473 high[2*i+1][0] += 0 * (*this)[i][1];
474 high[2*i+1][1] += 1 * (*this)[i][1];
476 high.denominator = denominator * 2;
488 high.resize( size()*2 );
490 for(
int i=0 ; i<int(size()) ; i++ )
492 high[2*i+0][0] += 1 * (*this)[i][0];
493 high[2*i+0][1] += 0 * (*this)[i][0];
494 high[2*i+0][2] += 0 * (*this)[i][0];
495 high[2*i+1][0] += 3 * (*this)[i][0];
496 high[2*i+1][1] += 1 * (*this)[i][0];
497 high[2*i+1][2] += 0 * (*this)[i][0];
499 high[2*i+0][0] += 3 * (*this)[i][1];
500 high[2*i+0][1] += 3 * (*this)[i][1];
501 high[2*i+0][2] += 1 * (*this)[i][1];
502 high[2*i+1][0] += 1 * (*this)[i][1];
503 high[2*i+1][1] += 3 * (*this)[i][1];
504 high[2*i+1][2] += 3 * (*this)[i][1];
506 high[2*i+0][0] += 0 * (*this)[i][2];
507 high[2*i+0][1] += 1 * (*this)[i][2];
508 high[2*i+0][2] += 3 * (*this)[i][2];
509 high[2*i+1][0] += 0 * (*this)[i][2];
510 high[2*i+1][1] += 0 * (*this)[i][2];
511 high[2*i+1][2] += 1 * (*this)[i][2];
513 high.denominator = denominator * 4;
516 template<
int Degree >
519 d.resize( this->size() );
521 for(
int i=0 ; i<int(this->size()) ; i++ )
for(
int j=0 ; j<=Degree ; j++ )
523 if( j>0 ) d[i][j-1] -= (*this)[i][j];
524 if( j<Degree ) d[i][j ] += (*this)[i][j];
526 d.denominator = denominator;
530 template<
int Degree1 ,
int Degree2 >
531 void SetBSplineElementIntegrals(
double integrals[Degree1+1][Degree2+1] )
533 for(
int i=0 ; i<=Degree1 ; i++ )
536 for(
int j=0 ; j<=Degree2 ; j++ )
539 integrals[i][j] = ( p1 * p2 ).integral( 0 , 1 );