/**************************************************************************** * VCGLib o o * * Visual and Computer Graphics Library o o * * _ O _ * * Copyright(C) 2006 \/)\/ * * Visual Computing Lab /\/| * * ISTI - Italian National Research Council | * * \ * * All rights reserved. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * * for more details. * * * ****************************************************************************/ #ifndef __VCGLIB_SPHERICAL_HARMONICS_H #define __VCGLIB_SPHERICAL_HARMONICS_H #include #include #include #include #include namespace vcg{ namespace math{ template class DummyPolarFunctor{ public: inline ScalarType operator()(ScalarType theta, ScalarType phi) {return ScalarType(0);} }; template class ScalingFactor { private : ScalarType k_factor[MAX_BAND][MAX_BAND]; static ScalingFactor sf; ScalingFactor() { for (unsigned l = 0; l < MAX_BAND; ++l) for (unsigned m = 0; m <= l; ++m) k_factor[l][m] = Sqrt( ( (2.0*l + 1.0) * Factorial(l-m) ) / (4.0 * M_PI * Factorial(l + m)) ); } public : static ScalarType K(unsigned l, unsigned m) { return sf.k_factor[l][m]; } }; template ScalingFactor ScalingFactor::sf; /** * Although the Real Spherical Harmonic Function is correctly defined over any * positive l and any -l <= m <= l, the two internal functions computing the * imaginary and real parts of the Complex Spherical Harmonic Functions are defined * for positive m only. */ template class SphericalHarmonics{ private : static DynamicLegendre legendre; static ScalarType scaling_factor(unsigned l, unsigned m) { return ScalingFactor::K(l,m); } inline static ScalarType complex_spherical_harmonic_re(unsigned l, unsigned m, ScalarType theta, ScalarType phi) { return scaling_factor(l, m) * legendre.AssociatedPolynomial(l, m, Cos(theta), Sin(theta)) * Cos(m * phi); } inline static ScalarType complex_spherical_harmonic_im(unsigned l, unsigned m, ScalarType theta, ScalarType phi) { return scaling_factor(l, m) * legendre.AssociatedPolynomial(l, m, Cos(theta), Sin(theta)) * Sin(m * phi); } ScalarType coefficients[MAX_BAND * MAX_BAND]; public : /** * Returns the Real Spherical Harmonic Function * * l is any positive integer, * m is such that -l <= m <= l * theta is inside [0, PI] * phi is inside [0, 2*PI] */ static ScalarType Real(unsigned l, int m, ScalarType theta, ScalarType phi) { assert((int)-l <= m && m <= (int)l && theta >= 0.0 && theta <= (ScalarType)M_PI && phi >= 0.0 && phi <= (ScalarType)(2.0 * M_PI)); if (m > 0) return SQRT_TWO * complex_spherical_harmonic_re(l, m, theta, phi); else if (m == 0) return scaling_factor(l, 0) * legendre.Polynomial(l, Cos(theta)); else return SQRT_TWO * complex_spherical_harmonic_im(l, -m, theta, phi); } template static SphericalHarmonics Project(PolarFunctor * fun, unsigned n_samples) { const ScalarType weight = 4 * M_PI; unsigned sqrt_n_samples = (unsigned int) Sqrt((int)n_samples); unsigned actual_n_samples = sqrt_n_samples * sqrt_n_samples; unsigned n_coeff = MAX_BAND * MAX_BAND; ScalarType one_over_n = 1.0/(ScalarType)sqrt_n_samples; MarsenneTwisterRNG rand; SphericalHarmonics sph; int i = 0; for (unsigned k = 0; k < n_coeff; k++ ) sph.coefficients[k] = 0; for (unsigned a = 0; a < sqrt_n_samples; ++a ) { for (unsigned b = 0; b < sqrt_n_samples; ++b) { ScalarType x = (a + ScalarType(rand.generate01())) * one_over_n; ScalarType y = (b + ScalarType(rand.generate01())) * one_over_n; ScalarType theta = 2.0 * Acos(Sqrt(1.0 - x)); ScalarType phi = 2.0 * M_PI * y; for (int l = 0; l < (int)MAX_BAND; ++l) { for (int m = -l; m <= l; ++m) { int index = l * (l+1) + m; sph.coefficients[index] += (*fun)(theta, phi) * Real(l, m, theta, phi); } } i++; } } ScalarType factor = weight / actual_n_samples; for(i = 0; i < (int)n_coeff; ++i) { sph.coefficients[i] *= factor; } return sph; } static SphericalHarmonics Wrap(ScalarType * _coefficients) { SphericalHarmonics sph; for(int i = 0; i < (int) MAX_BAND * MAX_BAND; ++i) sph.coefficients[i] = _coefficients[i]; return sph; } ScalarType operator()(ScalarType theta, ScalarType phi) { ScalarType f = 0; for (int l = 0; l < MAX_BAND; ++l) { for (int m = -l; m <= l; ++m) { int index = l * (l+1) + m; f += (coefficients[index] * Real(l, m, theta, phi)); } } return f; } }; template DynamicLegendre SphericalHarmonics::legendre; }} //namespace vcg::math #endif