mitsuba/include/mitsuba/core/util.h

471 lines
15 KiB
C++

/*
This file is part of Mitsuba, a physically based rendering system.
Copyright (c) 2007-2011 by Wenzel Jakob and others.
Mitsuba is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Mitsuba 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 for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(__UTIL_H)
#define __UTIL_H
#include <boost/static_assert.hpp>
MTS_NAMESPACE_BEGIN
/*! \addtogroup libcore */
/*! @{ */
// -----------------------------------------------------------------------
//! @{ \name String-related utility functions
// -----------------------------------------------------------------------
/**
* \brief Given a list of delimiters, tokenize
* a std::string into a vector of strings
*/
extern MTS_EXPORT_CORE std::vector<std::string> tokenize(
const std::string &string,
const std::string &delim
);
/// Trim spaces (' ', '\\n', '\\r', '\\t') from the ends of a string
extern MTS_EXPORT_CORE std::string trim(const std::string& str);
/// Indent a string (Used for recursive toString() structure dumping)
extern MTS_EXPORT_CORE std::string indent(const std::string &string, int amount=1);
/// Wrapped snprintf
extern MTS_EXPORT_CORE std::string formatString(const char *pFmt, ...);
/**
* Convert a time difference (in ms) to a string representation
* \param time Time value in milliseconds
* \param precise When set to true, a higher-precision string representation
* is generated.
*/
extern MTS_EXPORT_CORE std::string timeString(Float time, bool precise = false);
/// Turn a memory size into a human-readable string
extern MTS_EXPORT_CORE std::string memString(size_t size);
/// Return a string representation of a list of objects
template<class Iterator> std::string containerToString(const Iterator &start, const Iterator &end) {
std::ostringstream oss;
oss << "{" << endl;
Iterator it = start;
while (it != end) {
oss << " " << indent((*it)->toString());
++it;
if (it != end)
oss << "," << endl;
else
oss << endl;
}
oss << "}";
return oss.str();
}
//! @}
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
//! @{ \name Miscellaneous
// -----------------------------------------------------------------------
/// Allocate an aligned region of memory
extern MTS_EXPORT_CORE void * __restrict allocAligned(size_t size);
#if defined(WIN32)
/// Return a string version of GetLastError()
extern std::string MTS_EXPORT_CORE lastErrorText();
#endif
/// Free an aligned region of memory
extern MTS_EXPORT_CORE void freeAligned(void *ptr);
/// Determine the number of available CPU cores
extern MTS_EXPORT_CORE int getProcessorCount();
/// Return the host name of this machine
extern MTS_EXPORT_CORE std::string getHostName();
/// Return the fully qualified domain name of this machine
extern MTS_EXPORT_CORE std::string getFQDN();
/**
* Enable floating point exceptions (to catch NaNs, overflows,
* arithmetic with infinity). On Intel processors, this applies
* to both x87 and SSE2 math
*
* \return \c true if floating point exceptions were active
* before calling the function
*/
extern MTS_EXPORT_CORE bool enableFPExceptions();
/**
* Disable floating point exceptions
*
* \return \c true if floating point exceptions were active
* before calling the function
*/
extern MTS_EXPORT_CORE bool disableFPExceptions();
/// Restore floating point exceptions to the specified state
extern MTS_EXPORT_CORE void restoreFPExceptions(bool state);
/// Cast between types that have an identical binary representation.
template<typename T, typename U> inline T union_cast(const U &val) {
BOOST_STATIC_ASSERT(sizeof(T) == sizeof(U));
union {
U u;
T t;
} caster = {val};
return caster.t;
}
/// Swaps the byte order of the underlying representation
template<typename T> inline T endianness_swap(T value) {
union {
T value;
uint8_t byteValue[sizeof(T)];
} u;
u.value = value;
std::reverse(&u.byteValue[0], &u.byteValue[sizeof(T)]);
return u.value;
}
/**
* This algorithm is based on Donald Knuth's book
* "The Art of Computer Programming, Volume 3: Sorting and Searching"
* (1st edition, section 5.2, page 595)
*
* Given a permutation and an array of values, it applies the permutation
* in linear time without requiring additional memory. This is based on
* the fact that each permutation can be decomposed into a disjoint set
* of permutations, which can then be applied individually.
*/
template <typename T> void permute_inplace(T *values, std::vector<size_t> &perm) {
for (size_t i=0; i<perm.size(); i++) {
if (perm[i] != i) {
/* The start of a new cycle has been found. Save
the value at this position, since it will be
overwritten */
size_t j = i;
T curval = values[i];
do {
/* Shuffle backwards */
size_t k = perm[j];
values[j] = values[k];
/* Also fix the permutations on the way */
perm[j] = j;
j = k;
/* Until the end of the cycle has been found */
} while (perm[j] != i);
/* Fix the final position with the saved value */
values[j] = curval;
perm[j] = j;
}
}
}
//! @}
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
//! @{ \name Numerical utility functions
// -----------------------------------------------------------------------
static const int primeTableSize = 1000;
/// Table of the first 1000 prime numbers
extern const int MTS_EXPORT_CORE primeTable[primeTableSize];
/// sqrt(a^2 + b^2) without underflow (like 'hypot' on compilers that support C99)
extern MTS_EXPORT_CORE Float hypot2(Float a, Float b);
/// Base-2 logarithm
extern MTS_EXPORT_CORE Float log2(Float value);
/// Friendly modulo function (always positive)
extern MTS_EXPORT_CORE int modulo(int a, int b);
/// Integer floor function
inline int floorToInt(Float value) {
return (int) std::floor(value);
}
/// Base-2 logarithm (32-bit integer version)
extern MTS_EXPORT_CORE int log2i(uint32_t value);
/// Base-2 logarithm (64-bit integer version)
extern MTS_EXPORT_CORE int log2i(uint64_t value);
#if defined(MTS_AMBIGUOUS_SIZE_T)
inline int log2i(size_t value) {
if (sizeof(size_t) == 8)
return log2i((uint64_t) value);
else
return log2i((uint32_t) value);
}
#endif
/// Check if an integer is a power of two (unsigned 32 bit version)
inline bool isPow2(uint32_t i) { return (i & (i-1)) == 0; }
/// Check if an integer is a power of two (signed 32 bit version)
inline bool isPow2(int32_t i) { return i > 0 && (i & (i-1)) == 0; }
/// Check if an integer is a power of two (64 bit version)
inline bool isPow2(uint64_t i) { return (i & (i-1)) == 0; }
/// Check if an integer is a power of two (signed 64 bit version)
inline bool isPow2(int64_t i) { return i > 0 && (i & (i-1)) == 0; }
#if defined(MTS_AMBIGUOUS_SIZE_T)
inline bool isPow2(size_t value) {
if (sizeof(size_t) == 8)
return isPow2((uint64_t) value);
else
return isPow2((uint32_t) value);
}
#endif
/// Round an integer to the next power of two
extern MTS_EXPORT_CORE uint32_t roundToPow2(uint32_t i);
/// Round an integer to the next power of two (64 bit version)
extern MTS_EXPORT_CORE uint64_t roundToPow2(uint64_t i);
#if defined(MTS_AMBIGUOUS_SIZE_T)
inline size_t roundToPow2(size_t value) {
if (sizeof(size_t) == 8)
return (size_t) roundToPow2((uint64_t) value);
else
return (size_t) roundToPow2((uint32_t) value);
}
#endif
//// Windowed sinc filter (Lanczos envelope, tau=number of cycles)
extern MTS_EXPORT_CORE Float lanczosSinc(Float t, Float tau = 2);
/**
* \brief Solve a quadratic equation of the form a*x^2 + b*x + c = 0.
* \return \c true if a solution could be found
*/
extern MTS_EXPORT_CORE bool solveQuadratic(Float a, Float b,
Float c, Float &x0, Float &x1);
/**
* Calculate the radical inverse function
* (Implementation based on "Instant Radiosity" by Alexander Keller
* in Computer Graphics Proceedings, Annual Conference Series,
* SIGGRAPH 97, pp. 49-56.
*/
extern MTS_EXPORT_CORE Float radicalInverse(int b, size_t i);
/**
* Incrementally calculate the radical inverse function
* (Implementation based on "Instant Radiosity" by Alexander Keller
* in Computer Graphics Proceedings, Annual Conference Series,
* SIGGRAPH 97, pp. 49-56.
*/
extern MTS_EXPORT_CORE Float radicalInverseIncremental(int b, Float x);
/**
* Rational approximation to the inverse normal
* cumulative distribution function
* Source: http://home.online.no/~pjacklam/notes/invnorm/impl/sprouse/ltqnorm.c
* \author Peter J. Acklam
*/
extern MTS_EXPORT_CORE double normalQuantile(double p);
//// Convert radians to degrees
inline Float radToDeg(Float value) { return value * (180.0f / M_PI); }
/// Convert degrees to radians
inline Float degToRad(Float value) { return value * (M_PI / 180.0f); }
/// Simple floating point clamping function
inline Float clamp(Float value, Float min, Float max) {
if (value < min)
return min;
else if (value > max)
return max;
else return value;
}
/// Simple integer clamping function
inline int clamp(int value, int min, int max) {
if (value < min)
return min;
else if (value > max)
return max;
else return value;
}
/// Linearly interpolate between two values
inline Float lerp(Float t, Float v1, Float v2) {
return ((Float) 1 - t) * v1 + t * v2;
}
/// S-shaped smoothly varying interpolation between two values
inline Float smoothStep(Float min, Float max, Float value) {
Float v = clamp((value - min) / (max - min), (Float) 0, (Float) 1);
return v * v * (-2 * v + 3);
}
/**
* \brief Numerically well-behaved routine for computing the angle
* between two unit direction vectors
*
* This should be used wherever one is tempted to compute the
* arc cosine of a dot product!
*
* Proposed by Don Hatch at
* http://www.plunk.org/~hatch/rightway.php
*/
template <typename VectorType> inline Float unitAngle(const VectorType &u, const VectorType &v) {
if (dot(u, v) < 0)
return M_PI - 2 * std::asin((v+u).length()/2);
else
return 2 * std::asin((v-u).length()/2);
}
//! @}
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
//! @{ \name Warping and sampling-related utility functions
// -----------------------------------------------------------------------
/**
* \brief Solve a 2x2 linear equation system using basic linear algebra
*/
extern MTS_EXPORT_CORE bool solveLinearSystem2x2(const Float a[2][2], const Float b[2], Float x[2]);
/// Complete the set {a} to an orthonormal base
extern MTS_EXPORT_CORE void coordinateSystem(const Vector &a, Vector &b, Vector &c);
/**
* \brief Generate (optionally jittered) stratified 1D samples
* \param random Source of random numbers
* \param dest A pointer to a floating point array with at least
* count entries
* \param count The interval [0, 1] is split into count strata
* \param jitter Randomly jitter the samples?
*/
extern MTS_EXPORT_CORE void stratifiedSample1D(Random *random, Float *dest,
int count, bool jitter);
/**
* \brief Generate (optionally jittered) stratified 2D samples
* \param random Source of random numbers
* \param dest A pointer to a floating point array
* \param countX The X axis interval [0, 1] is split into countX strata
* \param countY The Y axis interval [0, 1] is split into countY strata
* \param jitter Randomly jitter the samples?
*/
extern MTS_EXPORT_CORE void stratifiedSample2D(Random *random, Point2 *dest,
int countX, int countY, bool jitter);
/// Generate latin hypercube samples
extern MTS_EXPORT_CORE void latinHypercube(Random *random, Float *dest, size_t nSamples, size_t nDim);
/// Convert spherical coordinates to a direction
extern MTS_EXPORT_CORE Vector sphericalDirection(Float theta, Float phi);
/// Convert a direction to spherical coordinates
extern MTS_EXPORT_CORE Point2 toSphericalCoordinates(const Vector &v);
/// Sample a vector on the unit sphere (PDF: 1/(4 * PI), wrt. solid angles)
extern MTS_EXPORT_CORE Vector squareToSphere(const Point2 &sample);
/// Sample a vector on the unit hemisphere (PDF: 1/(2 * PI), wrt. solid angles)
extern MTS_EXPORT_CORE Vector squareToHemisphere(const Point2 &sample);
/// Sample a vector on the unit hemisphere (PDF: cos(theta) / PI, wrt. solid angles)
extern MTS_EXPORT_CORE Vector squareToHemispherePSA(const Point2 &sample);
/// Sample a vector that lies in a cone of angles
extern MTS_EXPORT_CORE Vector squareToCone(Float cosCutoff, const Point2 &sample);
extern MTS_EXPORT_CORE Float squareToConePdf(Float cosCutoff);
/// Sample a vector on a 2D disk (PDF: 1/(2 * PI))
extern MTS_EXPORT_CORE Point2 squareToDisk(const Point2 &sample);
/// Low-distortion concentric square to disk mapping by Peter Shirley (PDF: 1/(2 * PI))
extern MTS_EXPORT_CORE Point2 squareToDiskConcentric(const Point2 &sample);
/// Convert an uniformly distributed square sample into barycentric coordinates
extern MTS_EXPORT_CORE Point2 squareToTriangle(const Point2 &sample);
//! @}
// -----------------------------------------------------------------------
/**
* Calculates the unpolarized fresnel reflection coefficient for a
* dielectric material
*
* \param cosTheta1
* Cosine of the angle between the normal and the incident ray
* \param cosTheta2
* Cosine of the angle between the normal and the transmitted ray
* \param etaExt
* Refraction coefficient outside of the material
* \param etaInt
* Refraction coefficient inside the material
*/
extern MTS_EXPORT_CORE Float fresnelDielectric(Float cosTheta1,
Float cosTheta2, Float etaExt, Float etaInt);
/**
* Calculates the unpolarized fresnel reflection coefficient for a
* dielectric material. Handles incidence from either sides.
*
* \param cosTheta1
* Cosine of the angle between the normal and the incident ray
* \param etaExt
* Refraction coefficient outside of the material
* \param etaInt
* Refraction coefficient inside the material
*/
extern MTS_EXPORT_CORE Float fresnel(Float cosTheta1, Float etaExt,
Float etaInt);
/**
* Calculates the unpolarized fresnel reflection coefficient on
* an interface to a conductor.
*
* \param cosTheta
* Cosine of the angle between the normal and the incident ray
* \param eta
* Relative refractive index (per wavelength)
* \param k
* Absorption coefficient (per wavelength)
*/
extern MTS_EXPORT_CORE Spectrum fresnelConductor(Float cosTheta,
const Spectrum &eta, const Spectrum &k);
/*! @} */
MTS_NAMESPACE_END
#endif /* __UTIL_H */