...
 
Commits (21)
......@@ -4,3 +4,6 @@
[submodule "external/Catch"]
path = external/Catch
url = https://github.com/philsquared/Catch.git
[submodule "external/pybind11"]
path = external/pybind11
url = https://github.com/pybind/pybind11.git
This diff is collapsed.
Subproject commit f117a48ea2fd446d2865826a58d08027d4579cb3
......@@ -24,7 +24,7 @@
using namespace alta;
//#define DEBUG
//#define DEBUG_CORE
//! Add dynamic library extension (.so or .dll) to a dynamic object as well as
......
......@@ -22,7 +22,7 @@
#include <cmath>
#include <utility>
using namespace alta;
namespace alta {
/*! \ingroup datas
* \ingroup plugins
......@@ -56,7 +56,7 @@ public: //methods
: vertical_segment(params, size, input_data)
{ }
ASTM(const parameters& params, size_t size)
ASTM(const alta::parameters& params, size_t size)
: vertical_segment(params, size)
{ }
};
......@@ -176,3 +176,5 @@ ALTA_DLL_EXPORT data* load_data(std::istream& input, const arguments& args)
return new ASTM(params, n, std::shared_ptr<double>(data));
}
}
......@@ -19,6 +19,7 @@
#include <core/data.h>
#include <core/args.h>
#include <core/common.h>
#include <core/params.h>
using namespace alta;
......
......@@ -19,15 +19,17 @@
#include <cmath>
#include <core/common.h>
#include <core/params.h>
using namespace alta;
ALTA_DLL_EXPORT function* provide_function(const parameters& params)
ALTA_DLL_EXPORT function* provide_function(const alta::parameters& params)
{
return new lafortune_function(params);
}
lafortune_function::lafortune_function(const parameters& params)
lafortune_function::lafortune_function(const alta::parameters& params) :
nonlinear_function(params)
{
auto nY = params.dimY();
......@@ -50,7 +52,8 @@ vec lafortune_function::operator()(const vec& x) const
}
vec lafortune_function::value(const vec& x) const
{
vec res(dimY());
const int nY = _parameters.dimY();
vec res(nY);
#ifdef ADAPT_TO_PARAM
vec y(6);
......@@ -69,7 +72,7 @@ vec lafortune_function::value(const vec& x) const
#endif
// For each color channel
for(int i=0; i<dimY(); ++i)
for(int i=0; i<nY; ++i)
{
// Start with the diffuse term
res[i] = _kd[i];
......@@ -97,7 +100,8 @@ vec lafortune_function::value(const vec& x, const vec& p)
assert(p.size() == nbParameters());
setParameters(p);
vec res(dimY());
const int nY = _parameters.dimY();
vec res(nY);
#ifdef ADAPT_TO_PARAM
vec y(6);
......@@ -116,7 +120,7 @@ vec lafortune_function::value(const vec& x, const vec& p)
#endif
// For each lobe and for each color channel
for(int i=0; i<dimY(); ++i)
for(int i=0; i<nY; ++i)
{
// Start with the diffuse
res[i] = _kd[i];
......@@ -140,6 +144,7 @@ vec lafortune_function::value(const vec& x, const vec& p)
void lafortune_function::setNbLobes(int N)
{
_n = N;
const int _nY = _parameters.dimY();
// Update the length of the vectors
if(_isotropic)
......@@ -152,47 +157,49 @@ void lafortune_function::setNbLobes(int N)
//! Number of parameters to this non-linear function
int lafortune_function::nbParameters() const
{
const int nY = _parameters.dimY();
#ifdef FIT_DIFFUSE
if(_isotropic)
return (3*_n+1)*dimY();
return (3*_n+1)*nY;
else
return (4*_n+1)*dimY();
return (4*_n+1)*nY;
#else
if(_isotropic)
return (3*_n)*dimY();
return (3*_n)*nY;
else
return (4*_n)*dimY();
return (4*_n)*nY;
#endif
}
//! Get the vector of parameters for the function
vec lafortune_function::parameters() const
{
const int nY = _parameters.dimY();
vec res(nbParameters());
for(int n=0; n<_n; ++n)
for(int i=0; i<dimY(); ++i)
for(int i=0; i<nY; ++i)
{
if(_isotropic)
{
res[(n*dimY() + i)*3 + 0] = _C[(n*dimY() + i)*2 + 0];
res[(n*dimY() + i)*3 + 1] = _C[(n*dimY() + i)*2 + 1];
res[(n*dimY() + i)*3 + 2] = _N[n*dimY() + i];
res[(n*nY + i)*3 + 0] = _C[(n*nY + i)*2 + 0];
res[(n*nY + i)*3 + 1] = _C[(n*nY + i)*2 + 1];
res[(n*nY + i)*3 + 2] = _N[n*nY + i];
}
else
{
res[(n*dimY() + i)*4 + 0] = _C[(n*dimY() + i)*3 + 0];
res[(n*dimY() + i)*4 + 1] = _C[(n*dimY() + i)*3 + 1];
res[(n*dimY() + i)*4 + 2] = _C[(n*dimY() + i)*3 + 2];
res[(n*dimY() + i)*4 + 3] = _N[n*dimY() + i];
res[(n*nY + i)*4 + 0] = _C[(n*nY + i)*3 + 0];
res[(n*nY + i)*4 + 1] = _C[(n*nY + i)*3 + 1];
res[(n*nY + i)*4 + 2] = _C[(n*nY + i)*3 + 2];
res[(n*nY + i)*4 + 3] = _N[n*nY + i];
}
}
#ifdef FIT_DIFFUSE
for(int i=0; i<dimY(); ++i)
for(int i=0; i<nY; ++i)
{
if(_isotropic)
{
res[3*_n*dimY() + i] = _kd[i];
res[3*_n*nY + i] = _kd[i];
}
}
#endif
......@@ -202,21 +209,22 @@ vec lafortune_function::parameters() const
//! Update the vector of parameters for the function
void lafortune_function::setParameters(const vec& p)
{
const int nY = _parameters.dimY();
// Safety check the number of parameters
assert(p.size() == nbParameters());
for(int n=0; n<_n; ++n)
for(int i=0; i<dimY(); ++i)
for(int i=0; i<nY; ++i)
{
_C[(n*dimY() + i)*3 + 0] = p[(n*dimY() + i)*4 + 0];
_C[(n*dimY() + i)*3 + 1] = p[(n*dimY() + i)*4 + 1];
_C[(n*dimY() + i)*3 + 2] = p[(n*dimY() + i)*4 + 2];
_N[n*dimY() + i] = p[(n*dimY() + i)*4 + 3];
_C[(n*nY + i)*3 + 0] = p[(n*nY + i)*4 + 0];
_C[(n*nY + i)*3 + 1] = p[(n*nY + i)*4 + 1];
_C[(n*nY + i)*3 + 2] = p[(n*nY + i)*4 + 2];
_N[n*nY + i] = p[(n*nY + i)*4 + 3];
}
#ifdef FIT_DIFFUSE
for(int i=0; i<dimY(); ++i)
for(int i=0; i<nY; ++i)
{
_kd[i] = p[4*_n*dimY() + i];
_kd[i] = p[4*_n*nY + i];
}
#endif
}
......@@ -225,6 +233,7 @@ void lafortune_function::setParameters(const vec& p)
//! parameters.
vec lafortune_function::parametersJacobian(const vec& x) const
{
const int nY = _parameters.dimY();
#ifdef ADAPT_TO_PARAM
vec y(6);
......@@ -242,14 +251,14 @@ vec lafortune_function::parametersJacobian(const vec& x) const
dz = x[2]*x[5];
#endif
vec jac(dimY()*nbParameters());
for(int i=0; i<dimY(); ++i)
vec jac(nY*nbParameters());
for(int i=0; i<nY; ++i)
{
for(int n=0; n<_n; ++n)
for(int j=0; j<dimY(); ++j)
for(int j=0; j<nY; ++j)
{
// index of the current monochromatic lobe
int index = i*nbParameters() + 4*(n*dimY() + j);
int index = i*nbParameters() + 4*(n*nY + j);
double Cx, Cy, Cz, N;
getCurrentLobe(n, j, Cx, Cy, Cz, N);
......@@ -283,10 +292,10 @@ vec lafortune_function::parametersJacobian(const vec& x) const
}
#ifdef FIT_DIFFUSE
for(int j=0; j<dimY(); ++j)
for(int j=0; j<nY; ++j)
{
// index of the current monochromatic lobe
int index = i*nbParameters() + 4*_n*dimY() + j;
int index = i*nbParameters() + 4*_n*nY + j;
jac[index] = 1.0;
}
......@@ -298,31 +307,33 @@ vec lafortune_function::parametersJacobian(const vec& x) const
void lafortune_function::bootstrap(const ptr<data> d, const arguments& args)
{
const int nY = _parameters.dimY();
// Check the arguments for the number of lobes
this->setNbLobes(args.get_int("lobes", 1));
// Set the diffuse component
vec x0 = d->get(0);
for(int i=0; i<d->dimY(); ++i)
_kd[i] = x0[d->dimX() + i];
for(int i=0; i<d->parametrization().dimY(); ++i)
_kd[i] = x0[d->parametrization().dimX() + i];
for(int i=1; i<d->size(); ++i)
{
vec xi = d->get(i);
for(int j=0; j<d->dimY(); ++j)
_kd[j] = std::min(xi[d->dimX() + j], _kd[j]);
for(int j=0; j<d->parametrization().dimY(); ++j)
_kd[j] = std::min(xi[d->parametrization().dimX() + j], _kd[j]);
}
// The remaining data will be equal to one
for(int n=0; n<_n; ++n)
for(int i=0; i<dimY(); ++i)
for(int i=0; i<_parameters.dimY(); ++i)
{
double theta = 0.5 * M_PI * n / (double)_n;
_C[(n*dimY() + i)*3 + 0] = -sin(theta);
_C[(n*dimY() + i)*3 + 1] = -sin(theta);
_C[(n*dimY() + i)*3 + 2] = cos(theta);
_N[n*dimY() + i] = (double)_n;
_C[(n*nY + i)*3 + 0] = -sin(theta);
_C[(n*nY + i)*3 + 1] = -sin(theta);
_C[(n*nY + i)*3 + 2] = cos(theta);
_N[n*nY + i] = (double)_n;
}
}
......@@ -396,6 +407,7 @@ bool lafortune_function::load(std::istream& in)
setNbLobes(nb_lobes);
// Parse the lobe
const int _nY = _parameters.dimY();
for(int n=0; n<_n; ++n)
{
for(int i=0; i<_nY; ++i)
......@@ -418,6 +430,7 @@ void lafortune_function::save_call(std::ostream& out, const arguments& args) con
{
bool is_alta = !args.is_defined("export") || args["export"] == "alta";
const int _nY = _parameters.dimY();
if(is_alta)
{
out << "#FUNC nonlinear_function_lafortune" << std::endl ;
......
......@@ -21,6 +21,7 @@
#include <core/fitter.h>
#include <core/args.h>
#include <core/common.h>
#include <core/params.h>
using namespace alta;
......@@ -44,7 +45,7 @@ class lafortune_function : public nonlinear_function
public: // methods
lafortune_function(const parameters& params);
lafortune_function(const alta::parameters& params);
// Overload the function operator
virtual vec operator()(const vec& x) const ;
......@@ -103,6 +104,7 @@ class lafortune_function : public nonlinear_function
//! n for the color channel number c.
void getCurrentLobe(int n, int c, double& Cx, double& Cy, double& Cz, double& N) const
{
const int _nY = _parameters.dimY();
if(_isotropic)
{
Cx = _C[(n*_nY + c)*2 + 0];
......@@ -128,11 +130,5 @@ class lafortune_function : public nonlinear_function
//!\brief Flags to get an isotropic lobe
bool _isotropic;
lafortune_function()
: nonlinear_function(6, 0,
params::CARTESIAN, params::UNKNOWN_OUTPUT)
{
};
} ;
......@@ -22,18 +22,18 @@
using namespace alta;
ALTA_DLL_EXPORT function* provide_function(const parameters& params)
ALTA_DLL_EXPORT function* provide_function(const alta::parameters& params)
{
return new spherical_gaussian_function(params);
}
spherical_gaussian_function::spherical_gaussian_function(const parameters& params)
spherical_gaussian_function::spherical_gaussian_function(const alta::parameters& params)
: nonlinear_function(params.set_input(6, params::CARTESIAN)),
_non_a(1), _type(Mirror)
_a(1.0), _type(Mirror)
{
// Update the length of the vectors
_n.resize(_nY) ;
_ks.resize(_nY) ;
_n.resize(_parameters.dimY()) ;
_ks.resize(_parameters.dimY()) ;
}
// Overload the function operator
......@@ -43,10 +43,10 @@ vec spherical_gaussian_function::operator()(const vec& x) const
}
vec spherical_gaussian_function::value(const vec& x) const
{
vec res(dimY());
vec res(_parameters.dimY());
double dot = compute_dot(x);
for(int i=0; i<dimY(); ++i)
for(int i=0; i<_parameters.dimY(); ++i)
{
res[i] = _ks[i] * std::exp(_n[i] * (dot-1));
}
......@@ -95,22 +95,23 @@ int spherical_gaussian_function::nbParameters() const
{
if(_type == Moment)
{
return 2*dimY()+1;
return 2*_parameters.dimY()+1;
}
else
{
return 2*dimY();
return 2*_parameters.dimY();
}
}
//! Get the vector of parameters for the function
vec spherical_gaussian_function::parameters() const
{
const int nY = _parameters.dimY();
if(_type == Moment)
{
vec res(2*dimY()+1);
res[2*dimY()] = _a;
for(int i=0; i<dimY(); ++i)
vec res(2*nY+1);
res[2*nY] = _a;
for(int i=0; i<nY; ++i)
{
res[i*2 + 0] = _ks[i];
res[i*2 + 1] = _n[i];
......@@ -120,8 +121,8 @@ vec spherical_gaussian_function::parameters() const
}
else
{
vec res(2*dimY());
for(int i=0; i<dimY(); ++i)
vec res(2*nY);
for(int i=0; i<nY; ++i)
{
res[i*2 + 0] = _ks[i];
res[i*2 + 1] = _n[i];
......@@ -133,11 +134,12 @@ vec spherical_gaussian_function::parameters() const
//! \brief get the min values for the parameters
vec spherical_gaussian_function::getParametersMin() const
{
const int nY = _parameters.dimY();
if(_type == Moment)
{
vec res(2*dimY()+1);
res[2*dimY()] = 0.0;
for(int i=0; i<dimY(); ++i)
vec res(2*nY+1);
res[2*nY] = 0.0;
for(int i=0; i<nY; ++i)
{
res[i*2 + 0] = 0.0;
res[i*2 + 1] = 0.0;
......@@ -147,8 +149,8 @@ vec spherical_gaussian_function::getParametersMin() const
}
else
{
vec res(2*dimY());
for(int i=0; i<dimY(); ++i)
vec res(2*nY);
for(int i=0; i<nY; ++i)
{
res[i*2 + 0] = 0.0;
res[i*2 + 1] = 0.0;
......@@ -163,10 +165,10 @@ void spherical_gaussian_function::setParameters(const vec& p)
{
if(_type == Moment)
{
_a = p[2*dimY()];
_a = p[2*_parameters.dimY()];
}
for(int i=0; i<dimY(); ++i)
for(int i=0; i<_parameters.dimY(); ++i)
{
_ks[i] = p[i*2 + 0];
_n[i] = p[i*2 + 1];
......@@ -179,10 +181,10 @@ vec spherical_gaussian_function::parametersJacobian(const vec& x) const
{
double dot = compute_dot(x);
vec jac(dimY()*nbParameters());
for(int i=0; i<dimY(); ++i)
vec jac(_parameters.dimY()*nbParameters());
for(int i=0; i<_parameters.dimY(); ++i)
{
for(int j=0; j<dimY(); ++j)
for(int j=0; j<_parameters.dimY(); ++j)
{
if(i == j)
{
......@@ -221,7 +223,7 @@ vec spherical_gaussian_function::parametersJacobian(const vec& x) const
void spherical_gaussian_function::bootstrap(const ptr<data> d, const arguments& args)
{
for(int i=0; i<dimY(); ++i)
for(int i=0; i<_parameters.dimY(); ++i)
{
_ks[i] = 1.0;
_n[i] = 1.0;
......@@ -287,7 +289,7 @@ bool spherical_gaussian_function::load(std::istream& in)
}
// Parse the lobe
for(int i=0; i<_nY; ++i)
for(int i=0; i<_parameters.dimY(); ++i)
{
in >> token >> _ks[i];
......@@ -309,11 +311,12 @@ void spherical_gaussian_function::save_call(std::ostream& out, const arguments&
{
bool is_alta = !args.is_defined("export") || args["export"] == "alta";
const int nY = _parameters.dimY();
if(is_alta)
{
out << "#FUNC nonlinear_function_spherical_gaussian" << std::endl ;
for(int i=0; i<_nY; ++i)
for(int i=0; i<nY; ++i)
{
out << "Ks " << _ks[i] << std::endl;
out << "N " << _n[i] << std::endl;
......@@ -329,17 +332,17 @@ void spherical_gaussian_function::save_call(std::ostream& out, const arguments&
else
{
out << "spherical_gaussian(L, V, N, X, Y, vec3(";
for(int i=0; i<_nY; ++i)
for(int i=0; i<nY; ++i)
{
out << _ks[i];
if(i < _nY-1) { out << ", "; }
if(i < nY-1) { out << ", "; }
}
out << "), vec3(";
for(int i=0; i<_nY; ++i)
for(int i=0; i<nY; ++i)
{
out << _n[i];
if(i < _nY-1) { out << ", "; }
if(i < nY-1) { out << ", "; }
}
out << "))";
......
......@@ -20,6 +20,7 @@
#include <core/fitter.h>
#include <core/args.h>
#include <core/common.h>
#include <core/params.h>
using namespace alta;
......@@ -56,7 +57,7 @@ class spherical_gaussian_function : public nonlinear_function
Moment
};
spherical_gaussian_function(const parameters& params);
spherical_gaussian_function(const alta::parameters& params);
// Overload the function operator
virtual vec operator()(const vec& x) const ;
......
......@@ -18,15 +18,16 @@
#include <cmath>
#include <core/common.h>
#include <core/params.h>
using namespace alta;
ALTA_DLL_EXPORT function* provide_function(const parameters& params)
ALTA_DLL_EXPORT function* provide_function(const alta::parameters& params)
{
return new schlick_masking(params);
}
schlick_masking::schlick_masking(const parameters& params)
schlick_masking::schlick_masking(const alta::parameters& params)
: nonlinear_function(params.set_input(6, params::CARTESIAN))
{
w.resize(params.dimY());
......@@ -66,7 +67,7 @@ bool schlick_masking::load(std::istream& in)
}
// R [double]
for(int i=0; i<dimY(); ++i)
for(int i=0; i<_parameters.dimY(); ++i)
{
in >> token >> w[i];
}
......@@ -80,7 +81,7 @@ void schlick_masking::save_call(std::ostream& out, const arguments& args) const
if(is_alta)
{
out << "#FUNC nonlinear_masking_schlick" << std::endl ;
for(int i=0; i<dimY(); ++i)
for(int i=0; i<_parameters.dimY(); ++i)
{
out << "K " << w[i] << std::endl;
}
......@@ -89,10 +90,10 @@ void schlick_masking::save_call(std::ostream& out, const arguments& args) const
else
{
out << "masking_schlick(L, V, N, X, Y, vec3";
for(int i=0; i<dimY(); ++i)
for(int i=0; i<_parameters.dimY(); ++i)
{
out << w[i];
if(i < _nY-1) { out << ", "; }
if(i < _parameters.dimY()-1) { out << ", "; }
}
out << "))";
}
......@@ -122,11 +123,11 @@ void schlick_masking::save_body(std::ostream& out, const arguments& args) const
vec schlick_masking::value(const vec& x) const
{
vec res(dimY());
vec res(_parameters.dimY());
const double u = x[5];
const double v = x[2];
for(int i=0; i<dimY(); ++i)
for(int i=0; i<_parameters.dimY(); ++i)
{
const double Gu = u / (u + w[i] * (1.0 - u));
const double Gv = v / (v + w[i] * (1.0 - v));
......@@ -138,35 +139,35 @@ vec schlick_masking::value(const vec& x) const
//! \brief Number of parameters to this non-linear function
int schlick_masking::nbParameters() const
{
return dimY();
return _parameters.dimY();
}
vec schlick_masking::getParametersMin() const
{
vec m(dimY());
for(int i=0; i<dimY(); ++i) { m[i] = 0.0; }
vec m(_parameters.dimY());
for(int i=0; i<_parameters.dimY(); ++i) { m[i] = 0.0; }
return m;
}
//! \brief Get the vector of parameters for the function
vec schlick_masking::parameters() const
{
vec p(dimY());
for(int i=0; i<dimY(); ++i) { p[i] = w[i]; }
vec p(_parameters.dimY());
for(int i=0; i<_parameters.dimY(); ++i) { p[i] = w[i]; }
return p;
}
//! \brief Update the vector of parameters for the function
void schlick_masking::setParameters(const vec& p)
{
for(int i=0; i<dimY(); ++i) { w[i] = p[i]; }
for(int i=0; i<_parameters.dimY(); ++i) { w[i] = p[i]; }
}
//! \brief Obtain the derivatives of the function with respect to the
//! parameters.
vec schlick_masking::parametersJacobian(const vec& x) const
{
const int nY = dimY();
const int nY = _parameters.dimY();
vec jac(nY*nY);
const double u = x[5];
......@@ -184,11 +185,11 @@ vec schlick_masking::parametersJacobian(const vec& x) const
const double dGu = - u*(1.0 - u) / pow(u + w[i]*(1.0-u), 2);
const double dGv = - v*(1.0 - v) / pow(v + w[i]*(1.0-v), 2);
jac[j*dimY() + i] = Gu*dGv + Gv*dGu;
jac[j*_parameters.dimY() + i] = Gu*dGv + Gv*dGu;
}
else
{
jac[j*dimY() + i] = 0.0;
jac[j*_parameters.dimY() + i] = 0.0;
}
}
......@@ -199,5 +200,5 @@ vec schlick_masking::parametersJacobian(const vec& x) const
void schlick_masking::bootstrap(const ptr<data>, const arguments&)
{
// Start with a non occluding value for k
for(int i=0; i<dimY(); ++i) { w[i] = 0.0; }
for(int i=0; i<_parameters.dimY(); ++i) { w[i] = 0.0; }
}
......@@ -33,7 +33,7 @@ class schlick_masking : public nonlinear_function
public: // methods
schlick_masking(const parameters& params);
schlick_masking(const alta::parameters& params);
//! \brief Load function specific files
virtual bool load(std::istream& in) ;
......@@ -69,7 +69,6 @@ class schlick_masking : public nonlinear_function
private: // data
//! Fresnel reflectance at theta = 0
vec w;
schlick_masking() {};
vec w;
} ;
......@@ -66,8 +66,6 @@ class smith : public nonlinear_function//fresnel
//! Fresnel reflectance at theta = 0 ?
//! RP: I DOUBLT IT . Seems to be a brute copy and paste ???
//! RP: w^2 should be the mean-square surface slope
vec w;
smith() {};
vec w;
} ;
......@@ -5,29 +5,32 @@ Import('env', 'library_available')
env = env.Clone()
env.Prepend(LIBS = ['core'])
## Add pybind path
env.AppendUnique(CPPPATH = '#external/pybind11/include/')
## Building a test function for boost::python
##
bp_test_source = """
// STL and Boost includes
#include <memory>
#include <boost/python.hpp>
#include <pybind11/pybind11.h>
// ALTA includes
#include <core/common.h>
#include <core/ptr.h>
#include <core/function.h>
int main(int argc, char** argv) {
boost::python::class_<alta::function, alta::ptr<alta::function>, boost::noncopyable>("function", boost::python::no_init);
boost::python::register_ptr_to_python<alta::ptr<alta::function>>();
namespace py = pybind11;
return 0;
PYBIND11_MODULE(example, m) {
m.doc() = "pybind11 example plugin"; // optional module docstring
m.def("norm", &norm, "Compute the norm of vector 'v'", py::arg("v"));
}
"""
def CheckBoostPython(context):
context.Message('Checking boost::python using small example...')
result = context.TryLink(bp_test_source, '.cpp')
result = context.TryCompile(bp_test_source, '.cpp')
context.Result(result)
return result
......@@ -41,16 +44,6 @@ if library_available(env, pkgspec='python-2.7',
lib='PYTHON_LIB', header='Python.h'):
conf = Configure(env, custom_tests = {'CheckBoostPython' : CheckBoostPython})
# On GNU/Linux the '-mt' suffix is no longer used, but it is still
# used on some other platforms (see
# <http://stackoverflow.com/questions/2293962/boost-libraries-in-multithreading-aware-mode>.)
build_lib = conf.CheckLibWithHeader('boost_python-mt',
'boost/python.hpp', 'c++')
if not build_lib:
build_lib = conf.CheckLibWithHeader('boost_python',
'boost/python.hpp', 'c++')
build_lib = conf.CheckBoostPython();
env = conf.Finish()
......
......@@ -2,6 +2,7 @@
Copyright (C) 2014, 2015, 2016 Inria
Copyright (C) 2015 Université de Montréal
Copyright (C) 2018 Unity
This file is part of ALTA.
......@@ -9,8 +10,9 @@
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// Boost includes
#include <boost/python.hpp>
// Pybind11 includes
#include <pybind11/pybind11.h>
namespace py = pybind11;
// ALTA include
#include <core/common.h>
......@@ -25,57 +27,13 @@
#include <iostream>
// Local includes
#include "wrapper_vec.hpp"
#define bp boost::python
#include "wrapper_args.h"
#include "wrapper_vec.h"
#include "wrapper_data.h"
using namespace alta;
/* This class is a wrapper to ALTA's arguments class to add Python specific
* behaviour such as dictionnary initialization.
*
* Right now it does not handle automatic conversion in function call for
* example. The following code is not possible:
*
* import alta
* alta.get_data('data_merl', {'params' : 'STARK_2D'})
*
* Instead, one has to construct the arguments object from the ALTA library
* to use it afterwards:
*
* import alta
* args = alta.arguments({'params' : 'STARK_2D'})
* alta.get_data('data_merl', args)
*/
struct python_arguments : public arguments {
python_arguments() : arguments() {}
python_arguments(bp::dict d) : arguments() {
bp::list keys = d.keys();
for(int i=0; i<bp::len(keys); ++i) {
const std::string s_key = bp::extract<std::string>(keys[i]);
const std::string s_val = bp::extract<std::string>(d[keys[i]]);
this->update(s_key, s_val);
}
}
};
/* Create a data object from a plugin's name and the data filename. This
* function is here to accelerate the loading of data file.
*/
static ptr<data> load_data(const std::string& plugin_name, const std::string& filename) {
ptr<data> d = plugins_manager::load_data(filename, plugin_name);
return d;
}
static ptr<data> get_data_with_args(const std::string& plugin_name,
size_t size,
const parameters& params,
const python_arguments& args) {
return plugins_manager::get_data(plugin_name, size, params, args);
}
static ptr<data> get_data(const std::string& plugin_name, size_t size,
const parameters& params) {
return plugins_manager::get_data(plugin_name, size, params);
}
/* Creating functions for the plugins_manager calls
*
......@@ -335,137 +293,110 @@ static void brdf2data(const ptr<function>& f, ptr<data>& d) {
/* Compute distance metric between 'in' and 'ref'.
*/
static bp::dict data2stats(const ptr<data>& in, const ptr<data>& ref) {
static py::dict data2stats(const ptr<data>& in, const ptr<data>& ref) {
// Compute the metrics
errors::metrics res;
errors::compute(in.get(), ref.get(), nullptr, res);
// Fill the resulting Python vector
bp::dict py_res;
py::dict py_res;
for(auto rpair : res) {
py_res.setdefault<std::string, vec>(rpair.first, rpair.second);
py_res[py::str(rpair.first)] = rpair.second;
}
return py_res;
}
inline void register_function(py::module& m) {
py::class_<function, ptr<function>>(m, "function")
.def("__add__", &add_function)
.def("__mul__", &mult_function)
.def("__rmul__", &mult_function)
.def("value", &function::value)
.def("load", &load_from_file)
.def("load", &load_from_file_with_args)
.def("save", &function::save)
.def("save", &save_function_without_args)
.def("set", &set_function_params)
.def("get", &get_function_params);
m.def("get_function", get_function, py::arg("name") = "nonlinear_diffuse",
py::arg("param") = parameters(6, 3, params::CARTESIAN, params::RGB_COLOR));
m.def("get_function", get_function_from_args);
m.def("load_function", load_function);
m.def("load_function", load_function_with_args);
}
inline void register_fitter(py::module& m) {
py::class_<fitter, ptr<fitter>>(m, "fitter")
.def("fit_data", &fit_data_with_args)
.def("fit_data", &fit_data_without_args);
m.def("get_fitter", plugins_manager::get_fitter);
}
#define STRINGIFY_(x) #x
#define STRINGIFY(x) STRINGIFY_(x)
/* Exporting the ALTA module
*/
BOOST_PYTHON_MODULE(alta)
{
// Argument class
//
bp::class_<arguments>("_arguments");
bp::class_<python_arguments, bp::bases<arguments>>("arguments")
.def(bp::init<>())
.def(bp::init<bp::dict>())
.def("__getitem__", &arguments::operator[])
.def("update", &arguments::update);
PYBIND11_MODULE(alta, m) {
m.doc() = "ALTA python bindinds";
m.def("norm", &norm, "Compute the norm of vector 'v'", py::arg("v"));
// Vec class
//
register_wrapper_vec();
// 'parameters' class.
bp::class_<parameters>("parameters")
.def(bp::init<unsigned int, unsigned int, params::input, params::output>());
// Parameterization enums.
/* Register the 'parameters' class and the enums */
py::class_<parameters>(m, "parameters")
.def(py::init<unsigned int, unsigned int, params::input, params::output>());
#define PARAM_VALUE(name) \
.value(STRINGIFY(name), params:: name)
bp::enum_<params::input>("input_parametrization")
PARAM_VALUE(RUSIN_TH_PH_TD_PD)
PARAM_VALUE(RUSIN_TH_PH_TD)
PARAM_VALUE(RUSIN_TH_TD_PD)
PARAM_VALUE(RUSIN_TH_TD)
PARAM_VALUE(RUSIN_VH_VD)
PARAM_VALUE(RUSIN_VH)
PARAM_VALUE(COS_TH_TD)
PARAM_VALUE(COS_TH)
PARAM_VALUE(SCHLICK_TK_PK)
PARAM_VALUE(SCHLICK_VK)
PARAM_VALUE(SCHLICK_TL_TK_PROJ_DPHI)
PARAM_VALUE(COS_TK)
PARAM_VALUE(RETRO_TL_TVL_PROJ_DPHI)
PARAM_VALUE(STEREOGRAPHIC)
PARAM_VALUE(SPHERICAL_TL_PL_TV_PV)
PARAM_VALUE(COS_TLV)
PARAM_VALUE(COS_TLR)
PARAM_VALUE(ISOTROPIC_TV_TL)
PARAM_VALUE(ISOTROPIC_TV_TL_DPHI)
PARAM_VALUE(ISOTROPIC_TV_PROJ_DPHI)
PARAM_VALUE(ISOTROPIC_TL_TV_PROJ_DPHI)
PARAM_VALUE(ISOTROPIC_TD_PD)
PARAM_VALUE(STARK_2D)
PARAM_VALUE(STARK_3D)
PARAM_VALUE(NEUMANN_2D)
PARAM_VALUE(NEUMANN_3D)
PARAM_VALUE(CARTESIAN)
PARAM_VALUE(UNKNOWN_INPUT);
bp::enum_<params::output>("output_parametrization")
PARAM_VALUE(INV_STERADIAN)
PARAM_VALUE(INV_STERADIAN_COSINE_FACTOR)
PARAM_VALUE(ENERGY)
PARAM_VALUE(RGB_COLOR)
PARAM_VALUE(XYZ_COLOR)
PARAM_VALUE(UNKNOWN_OUTPUT);
py::enum_<params::input>(m, "input_parametrization")
PARAM_VALUE(RUSIN_TH_PH_TD_PD)
PARAM_VALUE(RUSIN_TH_PH_TD)
PARAM_VALUE(RUSIN_TH_TD_PD)
PARAM_VALUE(RUSIN_TH_TD)
PARAM_VALUE(RUSIN_VH_VD)
PARAM_VALUE(RUSIN_VH)
PARAM_VALUE(COS_TH_TD)
PARAM_VALUE(COS_TH)
PARAM_VALUE(SCHLICK_TK_PK)
PARAM_VALUE(SCHLICK_VK)
PARAM_VALUE(SCHLICK_TL_TK_PROJ_DPHI)
PARAM_VALUE(COS_TK)
PARAM_VALUE(RETRO_TL_TVL_PROJ_DPHI)
PARAM_VALUE(STEREOGRAPHIC)
PARAM_VALUE(SPHERICAL_TL_PL_TV_PV)
PARAM_VALUE(COS_TLV)
PARAM_VALUE(COS_TLR)
PARAM_VALUE(ISOTROPIC_TV_TL)
PARAM_VALUE(ISOTROPIC_TV_TL_DPHI)
PARAM_VALUE(ISOTROPIC_TV_PROJ_DPHI)
PARAM_VALUE(ISOTROPIC_TL_TV_PROJ_DPHI)
PARAM_VALUE(ISOTROPIC_TD_PD)
PARAM_VALUE(STARK_2D)
PARAM_VALUE(STARK_3D)
PARAM_VALUE(NEUMANN_2D)
PARAM_VALUE(NEUMANN_3D)
PARAM_VALUE(CARTESIAN)
PARAM_VALUE(UNKNOWN_INPUT);
py::enum_<params::output>(m, "output_parametrization")
PARAM_VALUE(INV_STERADIAN)
PARAM_VALUE(INV_STERADIAN_COSINE_FACTOR)
PARAM_VALUE(ENERGY)
PARAM_VALUE(RGB_COLOR)
PARAM_VALUE(XYZ_COLOR)
PARAM_VALUE(UNKNOWN_OUTPUT);
#undef PARAM_VALUE
bp::register_ptr_to_python<ptr<parameters>>();
/* Register the `args` and `vec` types */
register_args(m);
register_vec(m);
// Function interface
//
bp::class_<function, ptr<function>, boost::noncopyable>("function", bp::no_init)
.def("__add__", &add_function)
.def("__mul__", &mult_function)
.def("__rmul__", &mult_function)
.def("value", &function::value)
.def("load", &load_from_file)
.def("load", &load_from_file_with_args)
.def("save", &function::save)
.def("save", &save_function_without_args)
.def("set", &set_function_params)
.def("get", &get_function_params);
bp::def("get_function", get_function);
bp::def("get_function", get_function_from_args);
bp::def("load_function", load_function);
bp::def("load_function", load_function_with_args);
bp::register_ptr_to_python<ptr<function>>();
// Data interface
//
bp::class_<data, ptr<data>, boost::noncopyable>("data", bp::no_init)
.def("size", &data::size)
.def("get", &data::get)
//.def("set", &data::set)
.def("save", &data::save);
bp::def("get_data", get_data);
bp::def("get_data", get_data_with_args);
bp::def("load_data", load_data);
bp::register_ptr_to_python<ptr<data>>();
// Fitter interface
//
bp::class_<fitter, ptr<fitter>, boost::noncopyable>("fitter", bp::no_init)
.def("fit_data", &fit_data_with_args)
.def("fit_data", &fit_data_without_args);
bp::def("get_fitter", plugins_manager::get_fitter);
bp::register_ptr_to_python<ptr<fitter>>();
// Softs
//
bp::def("data2data", data2data);
bp::def("data2stats", data2stats);
bp::def("brdf2data", brdf2data);
}
/* register the `data`, `function` and `fitter` objects */
register_data(m);
register_function(m);
register_fitter(m);
/* register `softs` */
m.def("data2data", data2data);
m.def("data2stats", data2stats);
m.def("brdf2data", brdf2data);
}
\ No newline at end of file
/* ALTA --- Analysis of Bidirectional Reflectance Distribution Functions
Copyright (C) 2018 Unity
This file is part of ALTA.
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#pragma once
// Pybind11 includes
#include <pybind11/pybind11.h>
namespace py = pybind11;
// ALTA include
#include <core/args.h>
#include <core/ptr.h>
#include <core/data.h>
using namespace alta;
/* This class is a wrapper to ALTA's arguments class to add Python specific
* behaviour such as dictionnary initialization.
*
* Right now it does not handle automatic conversion in function call for
* example. The following code is not possible:
*
* import alta
* alta.get_data('data_merl', {'params' : 'STARK_2D'})
*
* Instead, one has to construct the arguments object from the ALTA library
* to use it afterwards:
*
* import alta
* args = alta.arguments({'params' : 'STARK_2D'})
* alta.get_data('data_merl', args)
*/
struct python_arguments : public arguments {
python_arguments() : arguments() {}
python_arguments(py::dict d) : arguments() {
for(auto item : d) {
const std::string s_key = std::string(py::str(item.first));
const std::string s_val = std::string(py::str(item.second));
this->update(s_key, s_val);
}
}
};
/* Register the `arguments` class to python */
inline void register_args(py::module& m) {
py::class_<python_arguments>(m, "arguments")
.def(py::init<>())
.def(py::init<py::dict>())
.def("__getitem__", &arguments::operator[])
.def("update", &arguments::update);
}
\ No newline at end of file
/* ALTA --- Analysis of Bidirectional Reflectance Distribution Functions
Copyright (C) 2018 Unity
This file is part of ALTA.
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#pragma once
// Pybind11 includes
#include <pybind11/pybind11.h>
namespace py = pybind11;
// ALTA include
#include <core/common.h>
#include <core/ptr.h>
#include <core/data.h>
using namespace alta;
/* Create a data object from a plugin's name and the data filename. This
* function is here to accelerate the loading of data file.
*/
static ptr<data> load_data(const std::string& plugin_name,
const std::string& filename)
{
return plugins_manager::load_data(filename, plugin_name);
}
static ptr<data> get_data_with_args(const std::string& plugin_name,
size_t size,
const parameters& params,
const arguments& args)
{
return plugins_manager::get_data(plugin_name, size, params, args);
}
static ptr<data> get_data(const std::string& plugin_name, size_t size,
const parameters& params)
{
return plugins_manager::get_data(plugin_name, size, params);
}
/* Register the `data` class to python
*/
inline void register_data(py::module& m) {
py::class_<data, ptr<data>>(m, "data")
.def("size", &data::size)
.def("get", &data::get)
.def("set", &data::set)
.def("save", &data::save)
.def("parametrization", &data::parametrization);
m.def("get_data", get_data);
m.def("get_data", get_data_with_args);
m.def("load_data", load_data);
}
/* ALTA --- Analysis of Bidirectional Reflectance Distribution Functions
Copyright (C) 2015 Université de Montréal
Copyright (C) 2018 Unity
This file is part of ALTA.
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#pragma once
// Pybind11 includes
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
namespace py = pybind11;
// ALTA include
#include <core/common.h>
// STL include
#include <iostream>
/* Specific function call to set a vector's element
*/
static void vec_set_item(vec& x, int i, double a) {
x[i] = a;
}
/* Operators on vec
*/
static vec vec_add(const vec& a, const vec& b) {
return a + b;
}
static vec vec_sub(const vec& a, const vec& b) {
return a - b;
}
/* Specific convert a vec to a string
*/
static std::string vec_str(const vec& x) {
std::stringstream stream;
stream << "[";
for(int i=0; i<x.size(); ++i) {
if(i > 0) { stream << ", "; }
stream << x[i];
}
stream << "]";
return stream.str();
}
/* Register the vector class to python
*/
inline void register_vec(py::module& m) {
py::class_<vec>(m, "vec")
.def(py::init<vec>())
.def(py::init([]( const std::vector<double>& a) {
vec v(a.size());
memcpy((void*)v.data(), (const void*)a.data(), a.size()*sizeof(double));
return v;
}))
.def("__add__", &vec_add)
.def("__sub__", &vec_sub)
.def("__len__", &vec::size)
.def("__getitem__", [](const vec &s, unsigned int i) {
if (i >= s.size()) throw py::index_error();
return s[i];
})
.def("__setitem__", &vec_set_item)
.def("__str__", &vec_str);
}
/* ALTA --- Analysis of Bidirectional Reflectance Distribution Functions
Copyright (C) 2015 Université de Montréal
This file is part of ALTA.
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#pragma once
// Boost includes
#include <boost/python.hpp>
// ALTA include
#include <core/common.h>
// STL include
#include <iostream>
#define bp boost::python
/* Create special converter from and to list/vec
*
* This allow to create a 'vec' object using a python 'list' with the following
* interface:
*
* v = alta.vec([1,1,1])
*
*/
struct converter_vec_list {
// Constructor add the converter to the registry
static void register_converter() {
bp::converter::registry::push_back(
&convertible,
&construct,
bp::type_id<vec>());
}
// Is the Python object convertible to a vec ?
static void* convertible(PyObject* obj_ptr) {
if (!PyList_Check(obj_ptr)) return nullptr;
return obj_ptr;
}
// From a PyObject, construct a vector object
static void construct(
PyObject* obj_ptr,
bp::converter::rvalue_from_python_stage1_data* data) {
auto size = PyList_Size(obj_ptr);
vec* _vec = new vec(size);
for(auto i=0; i<size; ++i) {
auto pyitem = PyList_GetItem(obj_ptr, i);
(*_vec)[i] = PyFloat_AsDouble(pyitem);
}
data->convertible = (void*) _vec;;
}
};
/* Iterator over the 'vec' class to enable construction of lists and arrays in
* python using the __iter__ interface. To build a 'list' or a numpy 'array'
* from an object (like 'vec'), Python requires another class that enable to
* iterate over the structure. This class is created using 'vec::__iter__'
* method. Then, elements of 'vec' are extracted using the 'next' method of the
* iterator. To enable use with numpy.array, the iterator needs to be nested
* (have a method '__iter__'). This is how numpy handles multidmensional arrays.
*
* With this class, it is possible to use the following code:
*
* v = alta.vec([1,1,1])
* a = np.array(v)
*/
struct iterator_vec {
const double* cur;
const double* end;
iterator_vec(const vec& x) : cur(x.data()), end(x.data()+x.size()) { }
// Iterator over the 'vec' structure.
//
static double next(iterator_vec& iter) {
if(iter.cur == iter.end) {
PyErr_SetString(PyExc_StopIteration, "No more data.");
bp::throw_error_already_set();
}
double r = *(iter.cur);
iter.cur++;
return r;
}
// Create an iterator from the 'vec' object.
//
static iterator_vec iter(const vec& x) {
return iterator_vec(x);
}
// Create a nested iterator.
//
static iterator_vec self(const iterator_vec& x) {
return x;
}
};
/* Specific function call to acces a vector's element
*/
static double vec_get_item(const vec& x, int i) {
return x[i];
}
/* Specific function call to set a vector's element
*/
static void vec_set_item(vec& x, int i, double a) {
x[i] = a;
}
/* Operators on vec
*/
static vec vec_add(const vec& a, const vec& b) {
return a + b;
}
static vec vec_sub(const vec& a, const vec& b) {
return a - b;
}
/* Specific convert a vec to a string