/* Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of the Johns Hopkins University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "poisson_exceptions.h" #include "binary_node.h" namespace pcl { namespace poisson { ///////////////// // BSplineData // ///////////////// // Support[i]: // Odd: i +/- 0.5 * ( 1 + Degree ) // i - 0.5 * ( 1 + Degree ) < 0 // <=> i < 0.5 * ( 1 + Degree ) // i + 0.5 * ( 1 + Degree ) > 0 // <=> i > - 0.5 * ( 1 + Degree ) // i + 0.5 * ( 1 + Degree ) > r // <=> i > r - 0.5 * ( 1 + Degree ) // i - 0.5 * ( 1 + Degree ) < r // <=> i < r + 0.5 * ( 1 + Degree ) // Even: i + 0.5 +/- 0.5 * ( 1 + Degree ) // i - 0.5 * Degree < 0 // <=> i < 0.5 * Degree // i + 1 + 0.5 * Degree > 0 // <=> i > -1 - 0.5 * Degree // i + 1 + 0.5 * Degree > r // <=> i > r - 1 - 0.5 * Degree // i - 0.5 * Degree < r // <=> i < r + 0.5 * Degree template< int Degree > inline bool LeftOverlap( unsigned int, int offset ) { offset <<= 1; if( Degree & 1 ) return (offset < 1+Degree) && (offset > -1-Degree ); else return (offset < Degree) && (offset > -2-Degree ); } template< int Degree > inline bool RightOverlap( unsigned int, int offset ) { offset <<= 1; if( Degree & 1 ) return (offset > 2-1-Degree) && (offset < 2+1+Degree ); else return (offset > 2-2-Degree) && (offset < 2+ Degree ); } template< int Degree > inline int ReflectLeft( unsigned int, int offset ) { if( Degree&1 ) return -offset; else return -1-offset; } template< int Degree > inline int ReflectRight( unsigned int depth , int offset ) { int r = 1<<(depth+1); if( Degree&1 ) return r -offset; else return r-1-offset; } template< int Degree , class Real > BSplineData::BSplineData( void ) { vvDotTable = dvDotTable = ddDotTable = NULL; valueTables = dValueTables = NULL; baseFunctions = NULL; baseBSplines = NULL; functionCount = sampleCount = 0; } template< int Degree , class Real > BSplineData< Degree , Real >::~BSplineData(void) { if( functionCount ) { delete[] vvDotTable; delete[] dvDotTable; delete[] ddDotTable; delete[] valueTables; delete[] dValueTables; delete[] baseFunctions; delete[] baseBSplines; } vvDotTable = dvDotTable = ddDotTable = NULL; valueTables = dValueTables=NULL; baseFunctions = NULL; baseBSplines = NULL; functionCount = 0; } template void BSplineData::set( int maxDepth , bool useDotRatios , bool reflectBoundary ) { this->useDotRatios = useDotRatios; this->reflectBoundary = reflectBoundary; depth = maxDepth; // [Warning] This assumes that the functions spacing is dual functionCount = BinaryNode< double >::CumulativeCenterCount( depth ); sampleCount = BinaryNode< double >::CenterCount( depth ) + BinaryNode< double >::CornerCount( depth ); baseFunctions = new PPolynomial[functionCount]; baseBSplines = new BSplineComponents[functionCount]; baseFunction = PPolynomial< Degree >::BSpline(); for( int i=0 ; i<=Degree ; i++ ) baseBSpline[i] = Polynomial< Degree >::BSplineComponent( i ).shift( double(-(Degree+1)/2) + i - 0.5 ); dBaseFunction = baseFunction.derivative(); StartingPolynomial< Degree > sPolys[Degree+3]; for( int i=0 ; i=1 && i<=Degree+1 ) sPolys[i].p += baseBSpline[i-1]; for( int j=0 ; j=1 && i<=Degree+1 ) sPolys[i].p += baseBSpline[i-1].shift( 1 ); for( int j=0 ; j::CenterAndWidth( i , c , w ); baseFunctions[i] = baseFunction.scale(w).shift(c); baseBSplines[i] = baseBSpline.scale(w).shift(c); if( reflectBoundary ) { int d , off , r; BinaryNode< double >::DepthAndOffset( i , d , off ); r = 1< void BSplineData::setDotTables( int flags ) { clearDotTables( flags ); int size = ( functionCount*functionCount + functionCount )>>1; int fullSize = functionCount*functionCount; if( flags & VV_DOT_FLAG ) { vvDotTable = new Real[size]; memset( vvDotTable , 0 , sizeof(Real)*size ); } if( flags & DV_DOT_FLAG ) { dvDotTable = new Real[fullSize]; memset( dvDotTable , 0 , sizeof(Real)*fullSize ); } if( flags & DD_DOT_FLAG ) { ddDotTable = new Real[size]; memset( ddDotTable , 0 , sizeof(Real)*size ); } double vvIntegrals[Degree+1][Degree+1]; double vdIntegrals[Degree+1][Degree ]; double dvIntegrals[Degree ][Degree+1]; double ddIntegrals[Degree ][Degree ]; int vvSums[Degree+1][Degree+1]; int vdSums[Degree+1][Degree ]; int dvSums[Degree ][Degree+1]; int ddSums[Degree ][Degree ]; SetBSplineElementIntegrals< Degree , Degree >( vvIntegrals ); SetBSplineElementIntegrals< Degree , Degree-1 >( vdIntegrals ); SetBSplineElementIntegrals< Degree-1 , Degree >( dvIntegrals ); SetBSplineElementIntegrals< Degree-1 , Degree-1 >( ddIntegrals ); for( int d1=0 ; d1<=depth ; d1++ ) for( int off1=0 ; off1<(1<::CenterIndex( d1 , off1 ); BSplineElements< Degree > b1( 1<::NEUMANN : BSplineElements< Degree>::NONE ); BSplineElements< Degree-1 > db1; b1.differentiate( db1 ); int start1 , end1; start1 = -1; for( int i=0 ; i=end1 || start1>=end2 ) continue; start2 = std::max< int >( start1 , start2 ); end2 = std::min< int >( end1 , end2 ); if( d1==d2 && off2::CenterIndex( d2 , off2 ); BSplineElements< Degree > b2( 1<::NEUMANN : BSplineElements< Degree>::NONE ); BSplineElements< Degree-1 > db2; b2.differentiate( db2 ); int idx = SymmetricIndex( ii , jj ); int idx1 = Index( ii , jj ) , idx2 = Index( jj , ii ); memset( vvSums , 0 , sizeof( int ) * ( Degree+1 ) * ( Degree+1 ) ); memset( vdSums , 0 , sizeof( int ) * ( Degree+1 ) * ( Degree ) ); memset( dvSums , 0 , sizeof( int ) * ( Degree ) * ( Degree+1 ) ); memset( ddSums , 0 , sizeof( int ) * ( Degree ) * ( Degree ) ); for( int i=start2 ; i b; b = b1; b.upSample( b1 ); b1.differentiate( db1 ); start1 = -1; for( int i=0 ; i void BSplineData::clearDotTables( int flags ) { if (flags & VV_DOT_FLAG) { delete[] vvDotTable ; vvDotTable = NULL; delete[] dvDotTable ; dvDotTable = NULL; delete[] ddDotTable ; ddDotTable = NULL; } } template< int Degree , class Real > void BSplineData< Degree , Real >::setSampleSpan( int idx , int& start , int& end , double smooth ) const { int d , off , res; BinaryNode< double >::DepthAndOffset( idx , d , off ); res = 1<_start && (start-1)/(sampleCount-1)<=_start // => start > _start * (sampleCount-1 ) && start <= _start*(sampleCount-1) + 1 // => _start * (sampleCount-1) + 1 >= start > _start * (sampleCount-1) start = int( floor( _start * (sampleCount-1) + 1 ) ); if( start<0 ) start = 0; // (end)/(sampleCount-1)<_end && (end+1)/(sampleCount-1)>=_end // => end < _end * (sampleCount-1 ) && end >= _end*(sampleCount-1) - 1 // => _end * (sampleCount-1) > end >= _end * (sampleCount-1) - 1 end = int( ceil( _end * (sampleCount-1) - 1 ) ); if( end>=sampleCount ) end = sampleCount-1; } template void BSplineData::setValueTables( int flags , double smooth ) { clearValueTables(); if( flags & VALUE_FLAG ) valueTables = new Real[functionCount*sampleCount]; if( flags & D_VALUE_FLAG ) dValueTables = new Real[functionCount*sampleCount]; PPolynomial function; PPolynomial dFunction; for( int i=0 ; i0) { function = baseFunctions[i].MovingAverage(smooth); dFunction = baseFunctions[i].derivative().MovingAverage(smooth); } else { function = baseFunctions[i]; dFunction = baseFunctions[i].derivative(); } for( int j=0 ; j void BSplineData::setValueTables(int flags,double valueSmooth,double normalSmooth){ clearValueTables(); if(flags & VALUE_FLAG){ valueTables=new Real[functionCount*sampleCount];} if(flags & D_VALUE_FLAG){dValueTables=new Real[functionCount*sampleCount];} PPolynomial function; PPolynomial dFunction; for(int i=0;i0) { function=baseFunctions[i].MovingAverage(valueSmooth);} else { function=baseFunctions[i];} if(normalSmooth>0) {dFunction=baseFunctions[i].derivative().MovingAverage(normalSmooth);} else {dFunction=baseFunctions[i].derivative();} for(int j=0;j void BSplineData::clearValueTables(void){ delete[] valueTables; delete[] dValueTables; valueTables=dValueTables=NULL; } template inline int BSplineData::Index( int i1 , int i2 ) const { return i1*functionCount+i2; } template inline int BSplineData::SymmetricIndex( int i1 , int i2 ) { if( i1>i2 ) return ((i1*i1+i1)>>1)+i2; else return ((i2*i2+i2)>>1)+i1; } template inline int BSplineData::SymmetricIndex( int i1 , int i2 , int& index ) { if( i1>1)+i1; return 1; } else { index = ((i1*i1+i1)>>1)+i2; return 0; } } //////////////////////// // BSplineElementData // //////////////////////// template< int Degree > BSplineElements< Degree >::BSplineElements( int res , int offset , int boundary ) { denominator = 1; this->resize( res , BSplineElementCoefficients() ); for( int i=0 ; i<=Degree ; i++ ) { int idx = -_off + offset + i; if( idx>=0 && idx void BSplineElements< Degree >::_addLeft( int offset , int boundary ) { int res = int( this->size() ); bool set = false; for( int i=0 ; i<=Degree ; i++ ) { int idx = -_off + offset + i; if( idx>=0 && idx void BSplineElements< Degree >::_addRight( int offset , int boundary ) { int res = int( this->size() ); bool set = false; for( int i=0 ; i<=Degree ; i++ ) { int idx = -_off + offset + i; if( idx>=0 && idx void BSplineElements< Degree >::upSample( BSplineElements< Degree >&) const { POISSON_THROW_EXCEPTION (pcl::poisson::PoissonBadArgumentException, "B-spline up-sampling not supported for degree " << Degree); } template<> void PCL_EXPORTS BSplineElements< 1 >::upSample( BSplineElements< 1 >& high ) const; template<> void PCL_EXPORTS BSplineElements< 2 >::upSample( BSplineElements< 2 >& high ) const; template< int Degree > void BSplineElements< Degree >::differentiate( BSplineElements< Degree-1 >& d ) const { d.resize( this->size() ); d.assign( d.size() , BSplineElementCoefficients< Degree-1 >() ); for( int i=0 ; isize()) ; i++ ) for( int j=0 ; j<=Degree ; j++ ) { if( j-1>=0 ) d[i][j-1] -= (*this)[i][j]; if( j void SetBSplineElementIntegrals( double integrals[Degree1+1][Degree2+1] ) { for( int i=0 ; i<=Degree1 ; i++ ) { Polynomial< Degree1 > p1 = Polynomial< Degree1 >::BSplineComponent( i ); for( int j=0 ; j<=Degree2 ; j++ ) { Polynomial< Degree2 > p2 = Polynomial< Degree2 >::BSplineComponent( j ); integrals[i][j] = ( p1 * p2 ).integral( 0 , 1 ); } } } } }