Files
test/extern/mantaflow/helper/pwrapper/pconvert.cpp
Sebastián Barschkis 9fe64948ab Fluid: Updated Mantaflow source with latest OpenVDB changes
This updated set of Mantaflow files includes the improved  OpenVDB file IO. With this update it is finally possible to store multiple grids per file. It is also possible to save particle systems and particle data to OpenVDB files.
2020-06-24 16:07:35 +02:00

662 lines
17 KiB
C++

/******************************************************************************
*
* MantaFlow fluid solver framework
* Copyright 2011 Tobias Pfaff, Nils Thuerey
*
* This program is free software, distributed under the terms of the
* Apache License, Version 2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Python argument wrappers and conversion tools
*
******************************************************************************/
#include "pythonInclude.h"
#include <sstream>
#include <algorithm>
#include "vectorbase.h"
#include "manta.h"
using namespace std;
//******************************************************************************
// Explicit definition and instantiation of python object converters
namespace Manta {
extern PyTypeObject PbVec3Type;
extern PyTypeObject PbVec4Type;
struct PbVec3 {
PyObject_HEAD float data[3];
};
struct PbVec4 {
PyObject_HEAD float data[4];
};
PyObject *getPyNone()
{
Py_INCREF(Py_None);
return Py_None;
}
PyObject *incref(PyObject *obj)
{
Py_INCREF(obj);
return obj;
}
/*template<> PyObject* toPy<PyObject*>(PyObject* obj) {
return obj;
}*/
template<> PyObject *toPy<int>(const int &v)
{
return PyLong_FromLong(v);
}
/*template<> PyObject* toPy<char*>(const (char*) & val) {
return PyUnicode_DecodeLatin1(val,strlen(val),"replace");
}*/
template<> PyObject *toPy<string>(const string &val)
{
return PyUnicode_DecodeLatin1(val.c_str(), val.length(), "replace");
}
template<> PyObject *toPy<float>(const float &v)
{
return PyFloat_FromDouble(v);
}
template<> PyObject *toPy<double>(const double &v)
{
return PyFloat_FromDouble(v);
}
template<> PyObject *toPy<bool>(const bool &v)
{
return PyBool_FromLong(v);
}
template<> PyObject *toPy<Vec3i>(const Vec3i &v)
{
float x = (float)v.x, y = (float)v.y, z = (float)v.z;
return PyObject_CallFunction((PyObject *)&PbVec3Type, (char *)"fff", x, y, z);
}
template<> PyObject *toPy<Vec3>(const Vec3 &v)
{
float x = (float)v.x, y = (float)v.y, z = (float)v.z;
return PyObject_CallFunction((PyObject *)&PbVec3Type, (char *)"fff", x, y, z);
}
template<> PyObject *toPy<Vec4i>(const Vec4i &v)
{
float x = (float)v.x, y = (float)v.y, z = (float)v.z;
return PyObject_CallFunction((PyObject *)&PbVec4Type, (char *)"ffff", x, y, z);
}
template<> PyObject *toPy<Vec4>(const Vec4 &v)
{
float x = (float)v.x, y = (float)v.y, z = (float)v.z;
return PyObject_CallFunction((PyObject *)&PbVec4Type, (char *)"ffff", x, y, z);
}
template<> PyObject *toPy<PbClass *>(const PbClass_Ptr &obj)
{
return obj->getPyObject();
}
template<> PyObject *toPy<std::vector<PbClass *>>(const std::vector<PbClass *> &vec)
{
PyObject *listObj = PyList_New(vec.size());
if (!listObj)
throw logic_error("Unable to allocate memory for Python list");
for (unsigned int i = 0; i < vec.size(); i++) {
PbClass *pb = vec[i];
PyObject *item = pb->getPyObject();
if (!item) {
Py_DECREF(listObj);
throw logic_error("Unable to allocate memory for Python list");
}
PyList_SET_ITEM(listObj, i, item);
}
return listObj;
}
template<> PyObject *toPy<std::vector<float>>(const std::vector<float> &vec)
{
PyObject *listObj = PyList_New(vec.size());
if (!listObj)
throw logic_error("Unable to allocate memory for Python list");
for (unsigned int i = 0; i < vec.size(); i++) {
PyObject *item = toPy<float>(vec[i]);
if (!item) {
Py_DECREF(listObj);
throw logic_error("Unable to allocate memory for Python list");
}
PyList_SET_ITEM(listObj, i, item);
}
return listObj;
}
template<> float fromPy<float>(PyObject *obj)
{
#if PY_MAJOR_VERSION <= 2
if (PyInt_Check(obj))
return PyInt_AsLong(obj);
#endif
if (PyFloat_Check(obj))
return PyFloat_AsDouble(obj);
if (PyLong_Check(obj))
return PyLong_AsDouble(obj);
errMsg("argument is not a float");
}
template<> double fromPy<double>(PyObject *obj)
{
#if PY_MAJOR_VERSION <= 2
if (PyInt_Check(obj))
return PyInt_AsLong(obj);
#endif
if (PyFloat_Check(obj))
return PyFloat_AsDouble(obj);
if (PyLong_Check(obj))
return PyLong_AsDouble(obj);
errMsg("argument is not a double");
}
template<> PyObject *fromPy<PyObject *>(PyObject *obj)
{
return obj;
}
template<> PbClass *fromPy<PbClass *>(PyObject *obj)
{
PbClass *pbo = Pb::objFromPy(obj);
if (!PyType_Check(obj))
return pbo;
const char *tname = ((PyTypeObject *)obj)->tp_name;
pbo->setName(tname);
return pbo;
}
template<> std::vector<PbClass *> fromPy<std::vector<PbClass *>>(PyObject *obj)
{
std::vector<PbClass *> vec;
if (PyList_Check(obj)) {
int sz = PyList_Size(obj);
for (int i = 0; i < sz; ++i) {
PyObject *lobj = PyList_GetItem(obj, i);
vec.push_back(fromPy<PbClass *>(lobj));
}
}
return vec;
}
template<> std::vector<float> fromPy<std::vector<float>>(PyObject *obj)
{
std::vector<float> vec;
if (PyList_Check(obj)) {
int sz = PyList_Size(obj);
for (int i = 0; i < sz; ++i) {
PyObject *lobj = PyList_GetItem(obj, i);
vec.push_back(fromPy<float>(lobj));
}
}
return vec;
}
template<> int fromPy<int>(PyObject *obj)
{
#if PY_MAJOR_VERSION <= 2
if (PyInt_Check(obj))
return PyInt_AsLong(obj);
#endif
if (PyLong_Check(obj))
return PyLong_AsDouble(obj);
if (PyFloat_Check(obj)) {
double a = PyFloat_AsDouble(obj);
if (fabs(a - floor(a + 0.5)) > 1e-5)
errMsg("argument is not an int");
return (int)(a + 0.5);
}
errMsg("argument is not an int");
}
template<> string fromPy<string>(PyObject *obj)
{
if (PyUnicode_Check(obj))
#ifdef BLENDER
// Blender is completely UTF-8 based
return PyBytes_AsString(PyUnicode_AsUTF8String(obj));
#else
return PyBytes_AsString(PyUnicode_AsLatin1String(obj));
#endif
#if PY_MAJOR_VERSION <= 2
else if (PyString_Check(obj))
return PyString_AsString(obj);
#endif
else
errMsg("argument is not a string");
}
template<> const char *fromPy<const char *>(PyObject *obj)
{
if (PyUnicode_Check(obj))
#ifdef BLENDER
// Blender is completely UTF-8 based
return PyBytes_AsString(PyUnicode_AsUTF8String(obj));
#else
return PyBytes_AsString(PyUnicode_AsLatin1String(obj));
#endif
#if PY_MAJOR_VERSION <= 2
else if (PyString_Check(obj))
return PyString_AsString(obj);
#endif
else
errMsg("argument is not a string");
}
template<> bool fromPy<bool>(PyObject *obj)
{
if (!PyBool_Check(obj))
errMsg("argument is not a boolean");
return PyLong_AsLong(obj) != 0;
}
template<> Vec3 fromPy<Vec3>(PyObject *obj)
{
if (PyObject_IsInstance(obj, (PyObject *)&PbVec3Type)) {
return Vec3(((PbVec3 *)obj)->data);
}
else if (PyTuple_Check(obj) && PyTuple_Size(obj) == 3) {
return Vec3(fromPy<Real>(PyTuple_GetItem(obj, 0)),
fromPy<Real>(PyTuple_GetItem(obj, 1)),
fromPy<Real>(PyTuple_GetItem(obj, 2)));
}
errMsg("argument is not a Vec3");
}
template<> Vec3i fromPy<Vec3i>(PyObject *obj)
{
if (PyObject_IsInstance(obj, (PyObject *)&PbVec3Type)) {
return toVec3iChecked(((PbVec3 *)obj)->data);
}
else if (PyTuple_Check(obj) && PyTuple_Size(obj) == 3) {
return Vec3i(fromPy<int>(PyTuple_GetItem(obj, 0)),
fromPy<int>(PyTuple_GetItem(obj, 1)),
fromPy<int>(PyTuple_GetItem(obj, 2)));
}
errMsg("argument is not a Vec3i");
}
template<> Vec4 fromPy<Vec4>(PyObject *obj)
{
if (PyObject_IsInstance(obj, (PyObject *)&PbVec4Type)) {
return Vec4(((PbVec4 *)obj)->data);
}
else if (PyTuple_Check(obj) && PyTuple_Size(obj) == 4) {
return Vec4(fromPy<Real>(PyTuple_GetItem(obj, 0)),
fromPy<Real>(PyTuple_GetItem(obj, 1)),
fromPy<Real>(PyTuple_GetItem(obj, 2)),
fromPy<Real>(PyTuple_GetItem(obj, 3)));
}
errMsg("argument is not a Vec4");
}
template<> Vec4i fromPy<Vec4i>(PyObject *obj)
{
if (PyObject_IsInstance(obj, (PyObject *)&PbVec4Type)) {
return toVec4i(((PbVec4 *)obj)->data);
}
else if (PyTuple_Check(obj) && PyTuple_Size(obj) == 4) {
return Vec4i(fromPy<int>(PyTuple_GetItem(obj, 0)),
fromPy<int>(PyTuple_GetItem(obj, 1)),
fromPy<int>(PyTuple_GetItem(obj, 2)),
fromPy<int>(PyTuple_GetItem(obj, 3)));
}
errMsg("argument is not a Vec4i");
}
template<> PbType fromPy<PbType>(PyObject *obj)
{
PbType pb = {""};
if (!PyType_Check(obj))
return pb;
const char *tname = ((PyTypeObject *)obj)->tp_name;
pb.S = tname;
return pb;
}
template<> PbTypeVec fromPy<PbTypeVec>(PyObject *obj)
{
PbTypeVec vec;
if (PyType_Check(obj)) {
vec.T.push_back(fromPy<PbType>(obj));
}
else if (PyTuple_Check(obj)) {
int sz = PyTuple_Size(obj);
for (int i = 0; i < sz; i++)
vec.T.push_back(fromPy<PbType>(PyTuple_GetItem(obj, i)));
}
else
errMsg("argument is not a type tuple");
return vec;
}
template<class T> T *tmpAlloc(PyObject *obj, std::vector<void *> *tmp)
{
if (!tmp)
throw Error("dynamic de-ref not supported for this type");
T *ptr = new T(fromPy<T>(obj));
tmp->push_back(ptr);
return ptr;
}
template<> float *fromPyPtr<float>(PyObject *obj, std::vector<void *> *tmp)
{
return tmpAlloc<float>(obj, tmp);
}
template<> double *fromPyPtr<double>(PyObject *obj, std::vector<void *> *tmp)
{
return tmpAlloc<double>(obj, tmp);
}
template<> int *fromPyPtr<int>(PyObject *obj, std::vector<void *> *tmp)
{
return tmpAlloc<int>(obj, tmp);
}
template<> std::string *fromPyPtr<std::string>(PyObject *obj, std::vector<void *> *tmp)
{
return tmpAlloc<std::string>(obj, tmp);
}
template<> bool *fromPyPtr<bool>(PyObject *obj, std::vector<void *> *tmp)
{
return tmpAlloc<bool>(obj, tmp);
}
template<> Vec3 *fromPyPtr<Vec3>(PyObject *obj, std::vector<void *> *tmp)
{
return tmpAlloc<Vec3>(obj, tmp);
}
template<> Vec3i *fromPyPtr<Vec3i>(PyObject *obj, std::vector<void *> *tmp)
{
return tmpAlloc<Vec3i>(obj, tmp);
}
template<> Vec4 *fromPyPtr<Vec4>(PyObject *obj, std::vector<void *> *tmp)
{
return tmpAlloc<Vec4>(obj, tmp);
}
template<> Vec4i *fromPyPtr<Vec4i>(PyObject *obj, std::vector<void *> *tmp)
{
return tmpAlloc<Vec4i>(obj, tmp);
}
template<>
std::vector<PbClass *> *fromPyPtr<std::vector<PbClass *>>(PyObject *obj, std::vector<void *> *tmp)
{
return tmpAlloc<std::vector<PbClass *>>(obj, tmp);
}
template<> bool isPy<float>(PyObject *obj)
{
#if PY_MAJOR_VERSION <= 2
if (PyInt_Check(obj))
return true;
#endif
return PyFloat_Check(obj) || PyLong_Check(obj);
}
template<> bool isPy<double>(PyObject *obj)
{
#if PY_MAJOR_VERSION <= 2
if (PyInt_Check(obj))
return true;
#endif
return PyFloat_Check(obj) || PyLong_Check(obj);
}
template<> bool isPy<PyObject *>(PyObject *obj)
{
return true;
}
template<> bool isPy<int>(PyObject *obj)
{
#if PY_MAJOR_VERSION <= 2
if (PyInt_Check(obj))
return true;
#endif
if (PyLong_Check(obj))
return true;
if (PyFloat_Check(obj)) {
double a = PyFloat_AsDouble(obj);
return fabs(a - floor(a + 0.5)) < 1e-5;
}
return false;
}
template<> bool isPy<string>(PyObject *obj)
{
if (PyUnicode_Check(obj))
return true;
#if PY_MAJOR_VERSION <= 2
if (PyString_Check(obj))
return true;
#endif
return false;
}
template<> bool isPy<const char *>(PyObject *obj)
{
if (PyUnicode_Check(obj))
return true;
#if PY_MAJOR_VERSION <= 2
if (PyString_Check(obj))
return true;
#endif
return false;
}
template<> bool isPy<bool>(PyObject *obj)
{
return PyBool_Check(obj);
}
template<> bool isPy<Vec3>(PyObject *obj)
{
if (PyObject_IsInstance(obj, (PyObject *)&PbVec3Type))
return true;
if (PyTuple_Check(obj) && PyTuple_Size(obj) == 3) {
return isPy<Real>(PyTuple_GetItem(obj, 0)) && isPy<Real>(PyTuple_GetItem(obj, 1)) &&
isPy<Real>(PyTuple_GetItem(obj, 2));
}
return false;
}
template<> bool isPy<Vec3i>(PyObject *obj)
{
if (PyObject_IsInstance(obj, (PyObject *)&PbVec3Type))
return true;
if (PyTuple_Check(obj) && PyTuple_Size(obj) == 3) {
return isPy<int>(PyTuple_GetItem(obj, 0)) && isPy<int>(PyTuple_GetItem(obj, 1)) &&
isPy<int>(PyTuple_GetItem(obj, 2));
}
return false;
}
template<> bool isPy<Vec4>(PyObject *obj)
{
if (PyObject_IsInstance(obj, (PyObject *)&PbVec4Type))
return true;
if (PyTuple_Check(obj) && PyTuple_Size(obj) == 4) {
return isPy<Real>(PyTuple_GetItem(obj, 0)) && isPy<Real>(PyTuple_GetItem(obj, 1)) &&
isPy<Real>(PyTuple_GetItem(obj, 2)) && isPy<Real>(PyTuple_GetItem(obj, 3));
}
return false;
}
template<> bool isPy<Vec4i>(PyObject *obj)
{
if (PyObject_IsInstance(obj, (PyObject *)&PbVec4Type))
return true;
if (PyTuple_Check(obj) && PyTuple_Size(obj) == 4) {
return isPy<int>(PyTuple_GetItem(obj, 0)) && isPy<int>(PyTuple_GetItem(obj, 1)) &&
isPy<int>(PyTuple_GetItem(obj, 2)) && isPy<int>(PyTuple_GetItem(obj, 3));
}
return false;
}
template<> bool isPy<PbType>(PyObject *obj)
{
return PyType_Check(obj);
}
template<> bool isPy<std::vector<PbClass *>>(PyObject *obj)
{
if (PyList_Check(obj))
return true;
return false;
}
template<> bool isPy<std::vector<float>>(PyObject *obj)
{
if (PyList_Check(obj))
return true;
return false;
}
//******************************************************************************
// PbArgs class defs
PbArgs PbArgs::EMPTY(NULL, NULL);
PbArgs::PbArgs(PyObject *linarg, PyObject *dict) : mLinArgs(0), mKwds(0)
{
setup(linarg, dict);
}
PbArgs::~PbArgs()
{
for (int i = 0; i < (int)mTmpStorage.size(); i++)
operator delete(mTmpStorage[i]);
mTmpStorage.clear();
}
void PbArgs::copy(PbArgs &a)
{
mKwds = a.mKwds;
mData = a.mData;
mLinData = a.mLinData;
mLinArgs = a.mLinArgs;
}
void PbArgs::clear()
{
mLinArgs = 0;
mKwds = 0;
mData.clear();
mLinData.clear();
}
PbArgs &PbArgs::operator=(const PbArgs &a)
{
// mLinArgs = 0;
// mKwds = 0;
return *this;
}
void PbArgs::setup(PyObject *linarg, PyObject *dict)
{
if (dict) {
PyObject *key, *value;
Py_ssize_t pos = 0;
while (PyDict_Next(dict, &pos, &key, &value)) {
DataElement el;
el.obj = value;
el.visited = false;
mData[fromPy<string>(key)] = el;
}
mKwds = dict;
}
if (linarg) {
size_t len = PyTuple_Size(linarg);
for (size_t i = 0; i < len; i++) {
DataElement el;
el.obj = PyTuple_GetItem(linarg, i);
el.visited = false;
mLinData.push_back(el);
}
mLinArgs = linarg;
}
}
void PbArgs::addLinArg(PyObject *obj)
{
DataElement el = {obj, false};
mLinData.push_back(el);
}
void PbArgs::check()
{
if (has("nocheck"))
return;
for (map<string, DataElement>::iterator it = mData.begin(); it != mData.end(); it++) {
if (!it->second.visited)
errMsg("Argument '" + it->first + "' unknown");
}
for (size_t i = 0; i < mLinData.size(); i++) {
if (!mLinData[i].visited) {
stringstream s;
s << "Function does not read argument number #" << i;
errMsg(s.str());
}
}
}
FluidSolver *PbArgs::obtainParent()
{
FluidSolver *solver = getPtrOpt<FluidSolver>("solver", -1, NULL);
if (solver != 0)
return solver;
for (map<string, DataElement>::iterator it = mData.begin(); it != mData.end(); it++) {
PbClass *obj = Pb::objFromPy(it->second.obj);
if (obj) {
if (solver == NULL)
solver = obj->getParent();
}
}
for (vector<DataElement>::iterator it = mLinData.begin(); it != mLinData.end(); it++) {
PbClass *obj = Pb::objFromPy(it->obj);
if (obj) {
if (solver == NULL)
solver = obj->getParent();
}
}
return solver;
}
void PbArgs::visit(int number, const string &key)
{
if (number >= 0 && number < (int)mLinData.size())
mLinData[number].visited = true;
map<string, DataElement>::iterator lu = mData.find(key);
if (lu != mData.end())
lu->second.visited = true;
}
PyObject *PbArgs::getItem(const std::string &key, bool strict, ArgLocker *lk)
{
map<string, DataElement>::iterator lu = mData.find(key);
if (lu == mData.end()) {
if (strict)
errMsg("Argument '" + key + "' is not defined.");
return NULL;
}
PbClass *pbo = Pb::objFromPy(lu->second.obj);
// try to lock
if (pbo && lk)
lk->add(pbo);
return lu->second.obj;
}
PyObject *PbArgs::getItem(size_t number, bool strict, ArgLocker *lk)
{
if (number >= mLinData.size()) {
if (!strict)
return NULL;
stringstream s;
s << "Argument number #" << number << " not specified.";
errMsg(s.str());
}
PbClass *pbo = Pb::objFromPy(mLinData[number].obj);
// try to lock
if (pbo && lk)
lk->add(pbo);
return mLinData[number].obj;
}
//******************************************************************************
// ArgLocker class defs
void ArgLocker::add(PbClass *p)
{
if (find(locks.begin(), locks.end(), p) == locks.end()) {
locks.push_back(p);
p->lock();
}
}
ArgLocker::~ArgLocker()
{
for (size_t i = 0; i < locks.size(); i++)
locks[i]->unlock();
locks.clear();
}
} // namespace Manta