Add Chromium-only Blender WebEngine parity work

This commit is contained in:
mes123456
2026-08-12 04:47:48 -04:00
commit 9fd26010f6
18225 changed files with 11622124 additions and 0 deletions

View File

@@ -0,0 +1,31 @@
/******************************************************************************
*
* MantaFlow fluid solver framework
* Copyright 2011-2014 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
*
* Include pwrapper headers
*
******************************************************************************/
#ifndef _MANTA_H
#define _MANTA_H
// Remove preprocessor keywords, so there won't infere with autocompletion etc.
#define KERNEL(...) extern int i, j, k, idx, X, Y, Z;
#define PYTHON(...)
#define returns(X) extern X;
#define alias typedef
#include "general.h"
#include "vectorbase.h"
#include "vector4d.h"
#include "registry.h"
#include "pclass.h"
#include "pconvert.h"
#include "fluidsolver.h"
#endif

View File

@@ -0,0 +1,132 @@
/******************************************************************************
*
* MantaFlow fluid solver framework
* Copyright 2017-2018 Steffen Wiewel, Moritz Becher, Rachel Chu
*
* This program is free software, distributed under the terms of the
* Apache License, Version 2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Convert mantaflow grids to/from numpy arrays
*
******************************************************************************/
#include "manta.h"
#include "pythonInclude.h"
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#include "numpy/arrayobject.h"
namespace Manta {
#if PY_VERSION_HEX < 0x03000000
PyMODINIT_FUNC initNumpy()
{
import_array();
}
#endif
// ------------------------------------------------------------------------
// Class Functions
// ------------------------------------------------------------------------
PyArrayContainer::PyArrayContainer(void *_pParentPyArray) : pParentPyArray(_pParentPyArray)
{
ExtractData(pParentPyArray);
}
// ------------------------------------------------------------------------
PyArrayContainer::PyArrayContainer(const PyArrayContainer &_Other)
: pParentPyArray(_Other.pParentPyArray)
{
ExtractData(pParentPyArray);
Py_INCREF(pParentPyArray);
}
// ------------------------------------------------------------------------
PyArrayContainer::~PyArrayContainer()
{
Py_DECREF(pParentPyArray);
}
// ------------------------------------------------------------------------
PyArrayContainer &PyArrayContainer::operator=(const PyArrayContainer &_Other)
{
if (this != &_Other) {
// DecRef the existing resource
Py_DECREF(pParentPyArray);
// Relink new data
pParentPyArray = _Other.pParentPyArray;
ExtractData(pParentPyArray);
Py_INCREF(pParentPyArray);
}
return *this;
}
// ------------------------------------------------------------------------
void PyArrayContainer::ExtractData(void *_pParentPyArray)
{
PyArrayObject *pParent = reinterpret_cast<PyArrayObject *>(pParentPyArray);
int numDims = PyArray_NDIM(pParent);
long *pDims = (long *)PyArray_DIMS(pParent);
pData = PyArray_DATA(pParent);
TotalSize = PyArray_SIZE(pParent);
Dims = std::vector<long>(&pDims[0], &pDims[numDims]);
int iDataType = PyArray_TYPE(pParent);
switch (iDataType) {
case NPY_FLOAT:
DataType = N_FLOAT;
break;
case NPY_DOUBLE:
DataType = N_DOUBLE;
break;
case NPY_INT:
DataType = N_INT;
break;
default:
errMsg("unknown type of Numpy array");
break;
}
}
// ------------------------------------------------------------------------
// Conversion Functions
// ------------------------------------------------------------------------
template<> PyArrayContainer fromPy<PyArrayContainer>(PyObject *obj)
{
if (PyArray_API == nullptr) {
// python 3 uses the return value
#if PY_VERSION_HEX >= 0x03000000
import_array();
#else
initNumpy();
#endif
}
if (!PyArray_Check(obj)) {
errMsg("argument is not an numpy array");
}
PyArrayObject *obj_p = reinterpret_cast<PyArrayObject *>(
PyArray_CheckFromAny(obj,
nullptr,
0,
0,
/*NPY_ARRAY_ENSURECOPY*/ NPY_ARRAY_C_CONTIGUOUS |
NPY_ARRAY_ENSUREARRAY | NPY_ARRAY_NOTSWAPPED,
nullptr));
PyArrayContainer container = PyArrayContainer(obj_p);
return container;
}
// template<> PyArrayContainer* fromPyPtr<PyArrayContainer>(PyObject* obj, std::vector<void*>* tmp)
// {
// if (!tmp) throw Error("dynamic de-ref not supported for this type");
// void* ptr = malloc(sizeof(PyArrayContainer));
// tmp->push_back(ptr);
// *((PyArrayContainer*) ptr) = fromPy<PyArrayContainer>(obj);
// return (PyArrayContainer*) ptr;
// }
} // namespace Manta

View File

@@ -0,0 +1,86 @@
/******************************************************************************
*
* MantaFlow fluid solver framework
* Copyright 2017 Steffen Wiewel, Moritz Baecher, Rachel Chu
*
* This program is free software, distributed under the terms of the
* Apache License, Version 2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Convert mantaflow grids to/from numpy arrays
*
******************************************************************************/
#ifdef _PCONVERT_H
# ifndef _NUMPYCONVERT_H
# define _NUMPYCONVERT_H
enum NumpyTypes {
N_BOOL = 0,
N_BYTE,
N_UBYTE,
N_SHORT,
N_USHORT,
N_INT,
N_UINT,
N_LONG,
N_ULONG,
N_LONGLONG,
N_ULONGLONG,
N_FLOAT,
N_DOUBLE,
N_LONGDOUBLE,
N_CFLOAT,
N_CDOUBLE,
N_CLONGDOUBLE,
N_OBJECT = 17,
N_STRING,
N_UNICODE,
N_VOID,
/*
* New 1.6 types appended, may be integrated
* into the above in 2.0.
*/
N_DATETIME,
N_TIMEDELTA,
N_HALF,
N_NTYPES,
N_NOTYPE,
N_CHAR, /* special flag */
N_USERDEF = 256, /* leave room for characters */
/* The number of types not including the new 1.6 types */
N_NTYPES_ABI_COMPATIBLE = 21
};
namespace Manta {
class PyArrayContainer {
public:
/// Constructors
PyArrayContainer(void *_pParentPyArray);
PyArrayContainer(const PyArrayContainer &_Other);
~PyArrayContainer();
/// Operators
PyArrayContainer &operator=(const PyArrayContainer &_Other);
private:
void ExtractData(void *_pParentPyArray);
public:
void *pData;
NumpyTypes DataType;
unsigned int TotalSize;
std::vector<long> Dims;
private:
void *pParentPyArray;
};
// template<> PyArrayContainer* fromPyPtr<PyArrayContainer>(PyObject* obj, std::vector<void*>*
// tmp);
template<> PyArrayContainer fromPy<PyArrayContainer>(PyObject *obj);
} // namespace Manta
# endif
#endif

View File

@@ -0,0 +1,220 @@
/******************************************************************************
*
* 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
*
* Functions for property setting/getting via python
*
******************************************************************************/
#include "pythonInclude.h"
#include "structmember.h"
#include "manta.h"
#include "general.h"
#include "timing.h"
#ifdef GUI
# include <QMutex>
#else
class QMutex {
public:
void lock(){};
void unlock(){};
bool tryLock()
{
return true;
};
};
#endif
using namespace std;
namespace Manta {
//******************************************************************************
// Free functions
void pbPreparePlugin(FluidSolver *parent, const string &name, bool doTime)
{
if (doTime)
TimingData::instance().start(parent, name);
}
void pbFinalizePlugin(FluidSolver *parent, const string &name, bool doTime)
{
if (doTime)
TimingData::instance().stop(parent, name);
// GUI update, also print name of parent if there's more than one
std::ostringstream msg;
if (name != "FluidSolver::step") {
if (parent && (parent->getNumInstances() > 0))
msg << parent->getName() << string(".");
msg << name;
}
updateQtGui(false, 0, 0., msg.str());
debMsg(name << " done", 3);
// name unnamed PbClass Objects from var name
PbClass::renameObjects();
}
void pbSetError(const string &fn, const string &ex)
{
debMsg("Error in " << fn, 1);
if (!ex.empty())
PyErr_SetString(PyExc_RuntimeError, ex.c_str());
}
//******************************************************************************
// Helpers
string PbTypeVec::str() const
{
if (T.empty())
return "";
string s = "<";
for (int i = 0; i < (int)T.size(); i++) {
s += T[i].str();
s += (i != (int)T.size() - 1) ? ',' : '>';
}
return s;
}
string PbType::str() const
{
if (S == "float")
return "Real";
if (S == "manta.vec3")
return "Vec3";
return S;
}
//******************************************************************************
// PbClass
vector<PbClass *> PbClass::mInstances;
PbClass::PbClass(FluidSolver *parent, const string &name, PyObject *obj)
: mMutex(nullptr), mParent(parent), mPyObject(obj), mName(name), mHidden(false)
{
mMutex = new QMutex();
}
PbClass::PbClass(const PbClass &a)
: mMutex(nullptr), mParent(a.mParent), mPyObject(0), mName("_unnamed"), mHidden(false)
{
mMutex = new QMutex();
}
PbClass::~PbClass()
{
for (vector<PbClass *>::iterator it = mInstances.begin(); it != mInstances.end(); ++it) {
if (*it == this) {
mInstances.erase(it);
break;
}
}
delete mMutex;
}
void PbClass::lock()
{
mMutex->lock();
}
void PbClass::unlock()
{
mMutex->unlock();
}
bool PbClass::tryLock()
{
return mMutex->tryLock();
}
PbClass *PbClass::getInstance(int idx)
{
if (idx < 0 || idx > (int)mInstances.size())
errMsg("PbClass::getInstance(): invalid index");
return mInstances[idx];
}
int PbClass::getNumInstances()
{
return mInstances.size();
}
bool PbClass::isNullRef(PyObject *obj)
{
return PyLong_Check(obj) && PyLong_AsDouble(obj) == 0;
}
bool PbClass::isNoneRef(PyObject *obj)
{
return (obj == Py_None);
}
void PbClass::registerObject(PyObject *obj, PbArgs *args)
{
// cross link
Pb::setReference(this, obj);
mPyObject = obj;
mInstances.push_back(this);
if (args) {
string _name = args->getOpt<std::string>("name", -1, "");
if (!_name.empty())
setName(_name);
}
}
PbClass *PbClass::createPyObject(const string &classname,
const string &name,
PbArgs &args,
PbClass *parent)
{
return Pb::createPy(classname, name, args, parent);
}
void PbClass::checkParent()
{
if (getParent() == nullptr) {
errMsg("New class " + mName + ": no parent given -- specify using parent=xxx !");
}
}
//! Assign unnamed PbClass objects their Python variable name
void PbClass::renameObjects()
{
PyObject *sys_mod_dict = PyImport_GetModuleDict();
PyObject *loc_mod = PyMapping_GetItemString(sys_mod_dict, (char *)"__main__");
if (!loc_mod)
return;
PyObject *locdict = PyObject_GetAttrString(loc_mod, "__dict__");
if (!locdict)
return;
// iterate all PbClass instances
for (size_t i = 0; i < mInstances.size(); i++) {
PbClass *obj = mInstances[i];
if (obj->getName().empty()) {
// empty, try to find instance in module local dictionary
PyObject *lkey, *lvalue;
Py_ssize_t lpos = 0;
while (PyDict_Next(locdict, &lpos, &lkey, &lvalue)) {
if (lvalue == obj->mPyObject) {
string varName = fromPy<string>(PyObject_Str(lkey));
obj->setName(varName);
// cout << "assigning variable name '" << varName << "' to unnamed instance" << endl;
break;
}
}
}
}
Py_DECREF(locdict);
Py_DECREF(loc_mod);
}
} // namespace Manta

View File

@@ -0,0 +1,126 @@
/******************************************************************************
*
* MantaFlow fluid solver framework
* Copyright 2011-2014 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
*
* Base class for all Python-exposed classes
*
******************************************************************************/
// -----------------------------------------------------------------
// NOTE:
// Do not include this file in user code, include "manta.h" instead
// -----------------------------------------------------------------
#ifdef _MANTA_H
# ifndef _PTYPE_H
# define _PTYPE_H
# include <string>
# include <vector>
# include <map>
class QMutex;
namespace Manta {
struct PbClassData;
class FluidSolver;
class PbArgs;
struct PbType {
std::string S;
std::string str() const;
};
struct PbTypeVec {
std::vector<PbType> T;
std::string str() const;
};
//! Base class for all classes exposed to Python
class PbClass {
public:
PbClass(FluidSolver *parent, const std::string &name = "", PyObject *obj = nullptr);
PbClass(const PbClass &a);
virtual ~PbClass();
// basic property setter/getters
void setName(const std::string &name)
{
mName = name;
}
std::string getName() const
{
return mName;
}
PyObject *getPyObject() const
{
return mPyObject;
}
void registerObject(PyObject *obj, PbArgs *args);
FluidSolver *getParent() const
{
return mParent;
}
void setParent(FluidSolver *v)
{
mParent = v;
}
void checkParent();
// hidden flag for GUI, debug output
inline bool isHidden()
{
return mHidden;
}
inline void setHidden(bool v)
{
mHidden = v;
}
void lock();
void unlock();
bool tryLock();
// PbClass instance registry
static int getNumInstances();
static PbClass *getInstance(int index);
static void renameObjects();
// converters
static bool isNullRef(PyObject *o);
static bool isNoneRef(PyObject *o);
static PbClass *createPyObject(const std::string &classname,
const std::string &name,
PbArgs &args,
PbClass *parent);
inline bool canConvertTo(const std::string &classname)
{
return Pb::canConvert(mPyObject, classname);
}
protected:
QMutex *mMutex;
FluidSolver *mParent;
PyObject *mPyObject;
std::string mName;
bool mHidden;
static std::vector<PbClass *> mInstances;
};
//!\cond Register
void pbFinalizePlugin(FluidSolver *parent, const std::string &name, bool doTime = true);
void pbPreparePlugin(FluidSolver *parent, const std::string &name, bool doTime = true);
void pbSetError(const std::string &fn, const std::string &ex);
//!\endcond
} // namespace Manta
# endif
#endif

View File

@@ -0,0 +1,663 @@
/******************************************************************************
*
* 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<TmpCleanupFn> *tmp)
{
if (!tmp)
throw Error("dynamic de-ref not supported for this type");
T *ptr = new T(fromPy<T>(obj));
tmp->push_back([ptr]() { delete ptr; });
return ptr;
}
template<> float *fromPyPtr<float>(PyObject *obj, std::vector<TmpCleanupFn> *tmp)
{
return tmpAlloc<float>(obj, tmp);
}
template<> double *fromPyPtr<double>(PyObject *obj, std::vector<TmpCleanupFn> *tmp)
{
return tmpAlloc<double>(obj, tmp);
}
template<> int *fromPyPtr<int>(PyObject *obj, std::vector<TmpCleanupFn> *tmp)
{
return tmpAlloc<int>(obj, tmp);
}
template<> std::string *fromPyPtr<std::string>(PyObject *obj, std::vector<TmpCleanupFn> *tmp)
{
return tmpAlloc<std::string>(obj, tmp);
}
template<> bool *fromPyPtr<bool>(PyObject *obj, std::vector<TmpCleanupFn> *tmp)
{
return tmpAlloc<bool>(obj, tmp);
}
template<> Vec3 *fromPyPtr<Vec3>(PyObject *obj, std::vector<TmpCleanupFn> *tmp)
{
return tmpAlloc<Vec3>(obj, tmp);
}
template<> Vec3i *fromPyPtr<Vec3i>(PyObject *obj, std::vector<TmpCleanupFn> *tmp)
{
return tmpAlloc<Vec3i>(obj, tmp);
}
template<> Vec4 *fromPyPtr<Vec4>(PyObject *obj, std::vector<TmpCleanupFn> *tmp)
{
return tmpAlloc<Vec4>(obj, tmp);
}
template<> Vec4i *fromPyPtr<Vec4i>(PyObject *obj, std::vector<TmpCleanupFn> *tmp)
{
return tmpAlloc<Vec4i>(obj, tmp);
}
template<>
std::vector<PbClass *> *fromPyPtr<std::vector<PbClass *>>(PyObject *obj, std::vector<TmpCleanupFn> *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(nullptr, nullptr);
PbArgs::PbArgs(PyObject *linarg, PyObject *dict) : mLinArgs(0), mKwds(0)
{
setup(linarg, dict);
}
PbArgs::~PbArgs()
{
for (auto &fn : mTmpStorageCleanup)
fn();
mTmpStorageCleanup.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, nullptr);
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 == nullptr)
solver = obj->getParent();
}
}
for (vector<DataElement>::iterator it = mLinData.begin(); it != mLinData.end(); it++) {
PbClass *obj = Pb::objFromPy(it->obj);
if (obj) {
if (solver == nullptr)
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 nullptr;
}
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 nullptr;
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

View File

@@ -0,0 +1,266 @@
/******************************************************************************
*
* 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
*
******************************************************************************/
// -----------------------------------------------------------------
// NOTE:
// Do not include this file in user code, include "manta.h" instead
// -----------------------------------------------------------------
#ifdef _MANTA_H
# ifndef _PCONVERT_H
# define _PCONVERT_H
# include <functional>
# include <string>
# include <map>
# include <vector>
namespace Manta {
template<class T> class Grid;
//! Locks the given PbClass Arguments until ArgLocker goes out of scope
struct ArgLocker {
void add(PbClass *p);
~ArgLocker();
std::vector<PbClass *> locks;
};
PyObject *getPyNone();
using TmpCleanupFn = std::function<void()>;
// for PbClass-derived classes
template<class T> T *fromPyPtr(PyObject *obj, std::vector<TmpCleanupFn> *tmp)
{
if (PbClass::isNullRef(obj) || PbClass::isNoneRef(obj))
return 0;
PbClass *pbo = Pb::objFromPy(obj);
const std::string &type = Namify<T>::S;
if (!pbo || !(pbo->canConvertTo(type)))
throw Error("can't convert argument to " + type + "*");
return (T *)(pbo);
}
template<> float *fromPyPtr<float>(PyObject *obj, std::vector<TmpCleanupFn> *tmp);
template<> double *fromPyPtr<double>(PyObject *obj, std::vector<TmpCleanupFn> *tmp);
template<> int *fromPyPtr<int>(PyObject *obj, std::vector<TmpCleanupFn> *tmp);
template<> std::string *fromPyPtr<std::string>(PyObject *obj, std::vector<TmpCleanupFn> *tmp);
template<> bool *fromPyPtr<bool>(PyObject *obj, std::vector<TmpCleanupFn> *tmp);
template<> Vec3 *fromPyPtr<Vec3>(PyObject *obj, std::vector<TmpCleanupFn> *tmp);
template<> Vec3i *fromPyPtr<Vec3i>(PyObject *obj, std::vector<TmpCleanupFn> *tmp);
template<> Vec4 *fromPyPtr<Vec4>(PyObject *obj, std::vector<TmpCleanupFn> *tmp);
template<> Vec4i *fromPyPtr<Vec4i>(PyObject *obj, std::vector<TmpCleanupFn> *tmp);
template<>
std::vector<PbClass *> *fromPyPtr<std::vector<PbClass *>>(PyObject *obj, std::vector<TmpCleanupFn> *tmp);
template<>
std::vector<float> *fromPyPtr<std::vector<float>>(PyObject *obj, std::vector<TmpCleanupFn> *tmp);
PyObject *incref(PyObject *obj);
template<class T> PyObject *toPy(const T &v)
{
PyObject *obj = v.getPyObject();
if (obj) {
return incref(obj);
}
T *co = new T(v);
const std::string &type = Namify<typename remove_pointers<T>::type>::S;
return Pb::copyObject(co, type);
}
template<class T> bool isPy(PyObject *obj)
{
if (PbClass::isNullRef(obj) || PbClass::isNoneRef(obj))
return false;
PbClass *pbo = Pb::objFromPy(obj);
const std::string &type = Namify<typename remove_pointers<T>::type>::S;
return pbo && pbo->canConvertTo(type);
}
template<class T> T fromPy(PyObject *obj)
{
throw Error(
"Unknown type conversion. Did you pass a PbClass by value? Instead always pass "
"grids/particlesystems/etc. by reference or using a pointer.");
}
// builtin types
template<> float fromPy<float>(PyObject *obj);
template<> double fromPy<double>(PyObject *obj);
template<> int fromPy<int>(PyObject *obj);
template<> PyObject *fromPy<PyObject *>(PyObject *obj);
template<> std::string fromPy<std::string>(PyObject *obj);
template<> const char *fromPy<const char *>(PyObject *obj);
template<> bool fromPy<bool>(PyObject *obj);
template<> Vec3 fromPy<Vec3>(PyObject *obj);
template<> Vec3i fromPy<Vec3i>(PyObject *obj);
template<> Vec4 fromPy<Vec4>(PyObject *obj);
template<> Vec4i fromPy<Vec4i>(PyObject *obj);
template<> PbType fromPy<PbType>(PyObject *obj);
template<> PbTypeVec fromPy<PbTypeVec>(PyObject *obj);
template<> PbClass *fromPy<PbClass *>(PyObject *obj);
template<> std::vector<PbClass *> fromPy<std::vector<PbClass *>>(PyObject *obj);
template<> std::vector<float> fromPy<std::vector<float>>(PyObject *obj);
template<> PyObject *toPy<int>(const int &v);
template<> PyObject *toPy<std::string>(const std::string &val);
template<> PyObject *toPy<float>(const float &v);
template<> PyObject *toPy<double>(const double &v);
template<> PyObject *toPy<bool>(const bool &v);
template<> PyObject *toPy<Vec3i>(const Vec3i &v);
template<> PyObject *toPy<Vec3>(const Vec3 &v);
template<> PyObject *toPy<Vec4i>(const Vec4i &v);
template<> PyObject *toPy<Vec4>(const Vec4 &v);
typedef PbClass *PbClass_Ptr;
template<> PyObject *toPy<PbClass *>(const PbClass_Ptr &obj);
template<> PyObject *toPy<std::vector<PbClass *>>(const std::vector<PbClass *> &vec);
template<> PyObject *toPy<std::vector<float>>(const std::vector<float> &vec);
template<> bool isPy<float>(PyObject *obj);
template<> bool isPy<double>(PyObject *obj);
template<> bool isPy<int>(PyObject *obj);
template<> bool isPy<PyObject *>(PyObject *obj);
template<> bool isPy<std::string>(PyObject *obj);
template<> bool isPy<const char *>(PyObject *obj);
template<> bool isPy<bool>(PyObject *obj);
template<> bool isPy<Vec3>(PyObject *obj);
template<> bool isPy<Vec3i>(PyObject *obj);
template<> bool isPy<Vec4>(PyObject *obj);
template<> bool isPy<Vec4i>(PyObject *obj);
template<> bool isPy<PbType>(PyObject *obj);
template<> bool isPy<std::vector<PbClass *>>(PyObject *obj);
template<> bool isPy<std::vector<float>>(PyObject *obj);
//! Encapsulation of python arguments
class PbArgs {
public:
PbArgs(PyObject *linargs = nullptr, PyObject *dict = nullptr);
~PbArgs();
void setup(PyObject *linargs = nullptr, PyObject *dict = nullptr);
void check();
FluidSolver *obtainParent();
inline int numLinArgs()
{
return mLinData.size();
}
inline bool has(const std::string &key)
{
return getItem(key, false) != nullptr;
}
inline void deleteItem(const std::string &key)
{
if (mData.find(key) != mData.end())
mData.erase(mData.find(key));
}
inline PyObject *linArgs()
{
return mLinArgs;
}
inline PyObject *kwds()
{
return mKwds;
}
void addLinArg(PyObject *obj);
template<class T> inline void add(const std::string &key, T arg)
{
DataElement el = {toPy(arg), false};
mData[key] = el;
}
template<class T> inline T get(const std::string &key, int number = -1, ArgLocker *lk = nullptr)
{
visit(number, key);
PyObject *o = getItem(key, false, lk);
if (o)
return fromPy<T>(o);
o = getItem(number, false, lk);
if (o)
return fromPy<T>(o);
errMsg("Argument '" + key + "' is not defined.");
}
template<class T>
inline T getOpt(const std::string &key, int number, T defarg, ArgLocker *lk = nullptr)
{
visit(number, key);
PyObject *o = getItem(key, false, lk);
if (o)
return fromPy<T>(o);
if (number >= 0)
o = getItem(number, false, lk);
return (o) ? fromPy<T>(o) : defarg;
}
template<class T>
inline T *getPtrOpt(const std::string &key, int number, T *defarg, ArgLocker *lk = nullptr)
{
visit(number, key);
PyObject *o = getItem(key, false, lk);
if (o)
return fromPyPtr<T>(o, &mTmpStorageCleanup);
if (number >= 0)
o = getItem(number, false, lk);
return o ? fromPyPtr<T>(o, &mTmpStorageCleanup) : defarg;
}
template<class T>
inline T *getPtr(const std::string &key, int number = -1, ArgLocker *lk = nullptr)
{
visit(number, key);
PyObject *o = getItem(key, false, lk);
if (o)
return fromPyPtr<T>(o, &mTmpStorageCleanup);
o = getItem(number, false, lk);
if (o)
return fromPyPtr<T>(o, &mTmpStorageCleanup);
errMsg("Argument '" + key + "' is not defined.");
}
// automatic template type deduction
template<class T> bool typeCheck(int num, const std::string &name)
{
PyObject *o = getItem(name, false, 0);
if (!o)
o = getItem(num, false, 0);
return o ? isPy<typename remove_pointers<T>::type>(o) : false;
}
PbArgs &operator=(const PbArgs &a); // dummy
void copy(PbArgs &a);
void clear();
void visit(int num, const std::string &key);
static PbArgs EMPTY;
protected:
PyObject *getItem(const std::string &key, bool strict, ArgLocker *lk = nullptr);
PyObject *getItem(size_t number, bool strict, ArgLocker *lk = nullptr);
struct DataElement {
PyObject *obj;
bool visited;
};
std::map<std::string, DataElement> mData;
std::vector<DataElement> mLinData;
PyObject *mLinArgs, *mKwds;
std::vector<TmpCleanupFn> mTmpStorageCleanup;
};
} // namespace Manta
# if NUMPY == 1
# include "numpyWrap.h"
# endif
# endif
#endif

View File

@@ -0,0 +1,416 @@
/******************************************************************************
*
* 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
*
* Vec3 class extension for python
*
******************************************************************************/
#include "pythonInclude.h"
#include <string>
#include <sstream>
#include "vectorbase.h"
#include "structmember.h"
#include "manta.h"
using namespace std;
namespace Manta {
extern PyTypeObject PbVec3Type;
struct PbVec3 {
PyObject_HEAD
float data[3];
};
static void PbVec3Dealloc(PbVec3 *self)
{
Py_TYPE(self)->tp_free((PyObject *)self);
}
static PyObject *PbVec3New(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
return type->tp_alloc(type, 0);
}
static int PbVec3Init(PbVec3 *self, PyObject *args, PyObject *kwds)
{
float x1 = numeric_limits<float>::quiet_NaN(), x2 = x1, x3 = x1;
if (!PyArg_ParseTuple(args, "|fff", &x1, &x2, &x3))
return -1;
if (!c_isnan(x1)) {
self->data[0] = x1;
if (!c_isnan(x2) && !c_isnan(x3)) {
self->data[1] = x2;
self->data[2] = x3;
}
else {
if (!c_isnan(x2) || !c_isnan(x3)) {
errMsg("Invalid partial init of vec3");
}
self->data[1] = x1;
self->data[2] = x1;
}
}
else {
self->data[0] = 0;
self->data[1] = 0;
self->data[2] = 0;
}
return 0;
}
static PyObject *PbVec3Repr(PbVec3 *self)
{
Manta::Vec3 v(self->data[0], self->data[1], self->data[2]);
return PyUnicode_FromFormat(v.toString().c_str());
}
static PyMemberDef PbVec3Members[] = {
{(char *)"x", T_FLOAT, offsetof(PbVec3, data), 0, (char *)"X"},
{(char *)"y", T_FLOAT, offsetof(PbVec3, data) + sizeof(float), 0, (char *)"Y"},
{(char *)"z", T_FLOAT, offsetof(PbVec3, data) + sizeof(float) * 2, 0, (char *)"Z"},
{nullptr} // Sentinel
};
static PyMethodDef PbVec3Methods[] = {
//{"name", (PyCFunction)Noddy_name, METH_NOARGS, "Return the name, combining the first and last
//name" },
{nullptr} // Sentinel
};
// operator overloads
inline PyObject *PbNew(const Vec3 &a)
{
PbVec3 *obj = (PbVec3 *)PbVec3New(&PbVec3Type, 0, 0);
obj->data[0] = a.x;
obj->data[1] = a.y;
obj->data[2] = a.z;
return (PyObject *)obj;
}
#define CONVERTVEC(obj) \
Vec3 v##obj; \
if (PyObject_TypeCheck(obj, &PbVec3Type)) \
v##obj = Vec3(&(((PbVec3 *)obj)->data[0])); \
else if (PyFloat_Check(obj)) \
v##obj = Vec3(PyFloat_AsDouble(obj)); \
else if (PyLong_Check(obj)) \
v##obj = Vec3(PyLong_AsDouble(obj)); \
else { \
Py_INCREF(Py_NotImplemented); \
return Py_NotImplemented; \
}
#define OPHEADER \
if (!PyObject_TypeCheck(a, &PbVec3Type) && !PyObject_TypeCheck(b, &PbVec3Type)) { \
Py_INCREF(Py_NotImplemented); \
return Py_NotImplemented; \
} \
CONVERTVEC(a) \
CONVERTVEC(b)
#define OPHEADER1 \
if (!PyObject_TypeCheck(a, &PbVec3Type)) { \
Py_INCREF(Py_NotImplemented); \
return Py_NotImplemented; \
} \
CONVERTVEC(a)
PyObject *PbVec3Add(PyObject *a, PyObject *b)
{
OPHEADER
return PbNew(va + vb);
}
PyObject *PbVec3Sub(PyObject *a, PyObject *b)
{
OPHEADER
return PbNew(va - vb);
}
PyObject *PbVec3Mult(PyObject *a, PyObject *b)
{
OPHEADER
return PbNew(va * vb);
}
PyObject *PbVec3Div(PyObject *a, PyObject *b)
{
OPHEADER
return PbNew(va / vb);
}
PyObject *PbVec3Negative(PyObject *a)
{
OPHEADER1
return PbNew(-va);
}
// numbers are defined subtely different in Py3 (WTF?)
#if PY_MAJOR_VERSION >= 3
static PyNumberMethods PbVec3NumberMethods = {
(binaryfunc)PbVec3Add, // binaryfunc nb_add;
(binaryfunc)PbVec3Sub, // binaryfunc nb_sub;
(binaryfunc)PbVec3Mult, // binaryfunc nb_mult;
0, // binaryfunc nb_remainder;
0, // binaryfunc nb_divmod;
0, // ternaryfunc nb_power;
(unaryfunc)PbVec3Negative, // unaryfunc nb_negative;
0, // unaryfunc nb_positive;
0, // unaryfunc nb_absolute;
0, // inquiry nb_bool;
0, // unaryfunc nb_invert;
0, // binaryfunc nb_lshift;
0, // binaryfunc nb_rshift;
0, // binaryfunc nb_and;
0, // binaryfunc nb_xor;
0, // binaryfunc nb_or;
0, // unaryfunc nb_int;
0, // void *nb_reserved;
0, // unaryfunc nb_float;
0, // binaryfunc nb_inplace_add;
0, // binaryfunc nb_inplace_subtract;
0, // binaryfunc nb_inplace_multiply;
0, // binaryfunc nb_inplace_remainder;
0, // ternaryfunc nb_inplace_power;
0, // binaryfunc nb_inplace_lshift;
0, // binaryfunc nb_inplace_rshift;
0, // binaryfunc nb_inplace_and;
0, // binaryfunc nb_inplace_xor;
0, // binaryfunc nb_inplace_or;
0, // binaryfunc nb_floor_divide;
(binaryfunc)PbVec3Div, // binaryfunc nb_true_divide;
0, // binaryfunc nb_inplace_floor_divide;
0, // binaryfunc nb_inplace_true_divide;
0 // unaryfunc nb_index;
};
#else
static PyNumberMethods PbVec3NumberMethods = {
(binaryfunc)PbVec3Add, // binaryfunc nb_add;
(binaryfunc)PbVec3Sub, // binaryfunc nb_sub;
(binaryfunc)PbVec3Mult, // binaryfunc nb_mult;
0, // binaryfunc nb_divide;
0, // binaryfunc nb_remainder;
0, // binaryfunc nb_divmod;
0, // ternaryfunc nb_power;
(unaryfunc)PbVec3Negative, // unaryfunc nb_negative;
0, // unaryfunc nb_positive;
0, // unaryfunc nb_absolute;
0, // inquiry nb_nonzero;
0, // unaryfunc nb_invert;
0, // binaryfunc nb_lshift;
0, // binaryfunc nb_rshift;
0, // binaryfunc nb_and;
0, // binaryfunc nb_xor;
0, // binaryfunc nb_or;
0, // coercion nb_coerce;
0, // unaryfunc nb_int;
0, // unaryfunc nb_long;
0, // unaryfunc nb_float;
0, // unaryfunc nb_oct;
0, // unaryfunc nb_hex;
0, // binaryfunc nb_inplace_add;
0, // binaryfunc nb_inplace_subtract;
0, // binaryfunc nb_inplace_multiply;
0, // binaryfunc nb_inplace_divide;
0, // binaryfunc nb_inplace_remainder;
0, // ternaryfunc nb_inplace_power;
0, // binaryfunc nb_inplace_lshift;
0, // binaryfunc nb_inplace_rshift;
0, // binaryfunc nb_inplace_and;
0, // binaryfunc nb_inplace_xor;
0, // binaryfunc nb_inplace_or;
0, // binaryfunc nb_floor_divide;
(binaryfunc)PbVec3Div, // binaryfunc nb_true_divide;
0, // binaryfunc nb_inplace_floor_divide;
0, // binaryfunc nb_inplace_true_divide;
0, // unaryfunc nb_index;
};
#endif
PyTypeObject PbVec3Type = {
PyVarObject_HEAD_INIT(nullptr, 0) "manta.vec3", /* tp_name */
sizeof(PbVec3), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)PbVec3Dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved */
(reprfunc)PbVec3Repr, /* tp_repr */
&PbVec3NumberMethods, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
#if PY_MAJOR_VERSION >= 3
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
#else
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
#endif
"float vector type", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
PbVec3Methods, /* tp_methods */
PbVec3Members, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)PbVec3Init, /* tp_init */
0, /* tp_alloc */
PbVec3New, /* tp_new */
};
inline PyObject *castPy(PyTypeObject *p)
{
return reinterpret_cast<PyObject *>(static_cast<void *>(p));
}
// 4d vector
extern PyTypeObject PbVec4Type;
struct PbVec4 {
PyObject_HEAD
float data[4];
};
static PyMethodDef PbVec4Methods[] = {
{nullptr} // Sentinel
};
static PyMemberDef PbVec4Members[] = {
{(char *)"x", T_FLOAT, offsetof(PbVec4, data), 0, (char *)"X"},
{(char *)"y", T_FLOAT, offsetof(PbVec4, data) + sizeof(float) * 1, 0, (char *)"Y"},
{(char *)"z", T_FLOAT, offsetof(PbVec4, data) + sizeof(float) * 2, 0, (char *)"Z"},
{(char *)"t", T_FLOAT, offsetof(PbVec4, data) + sizeof(float) * 3, 0, (char *)"T"},
{nullptr} // Sentinel
};
static void PbVec4Dealloc(PbVec4 *self)
{
Py_TYPE(self)->tp_free((PyObject *)self);
}
static PyObject *PbVec4New(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
return type->tp_alloc(type, 0);
}
static int PbVec4Init(PbVec4 *self, PyObject *args, PyObject *kwds)
{
float x1 = numeric_limits<float>::quiet_NaN(), x2 = x1, x3 = x1, x4 = x1;
if (!PyArg_ParseTuple(args, "|ffff", &x1, &x2, &x3, &x4))
return -1;
if (!c_isnan(x1)) {
self->data[0] = x1;
if (!c_isnan(x2) && !c_isnan(x3) && !c_isnan(x4)) {
self->data[1] = x2;
self->data[2] = x3;
self->data[3] = x4;
}
else {
if (!c_isnan(x2) || !c_isnan(x3) || !c_isnan(x4)) {
errMsg("Invalid partial init of vec4");
}
self->data[1] = self->data[2] = self->data[3] = x1;
}
}
else {
self->data[0] = self->data[1] = self->data[2] = self->data[3] = 0;
}
return 0;
}
static PyObject *PbVec4Repr(PbVec4 *self)
{
Manta::Vec4 v(self->data[0], self->data[1], self->data[2], self->data[3]);
return PyUnicode_FromFormat(v.toString().c_str());
}
PyTypeObject PbVec4Type = {
PyVarObject_HEAD_INIT(nullptr, 0) "manta.vec4", /* tp_name */
sizeof(PbVec4), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)PbVec4Dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved */
(reprfunc)PbVec4Repr, /* tp_repr */
nullptr, // &PbVec4NumberMethods, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
#if PY_MAJOR_VERSION >= 3
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
#else
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
#endif
"float vector type", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
PbVec4Methods, /* tp_methods */
PbVec4Members, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)PbVec4Init, /* tp_init */
0, /* tp_alloc */
PbVec4New, /* tp_new */
};
// register
void PbVecInitialize(PyObject *module)
{
if (PyType_Ready(&PbVec3Type) < 0)
errMsg("can't initialize Vec3 type");
Py_INCREF(castPy(&PbVec3Type));
PyModule_AddObject(module, "vec3", (PyObject *)&PbVec3Type);
if (PyType_Ready(&PbVec4Type) < 0)
errMsg("can't initialize Vec4 type");
Py_INCREF(castPy(&PbVec4Type));
PyModule_AddObject(module, "vec4", (PyObject *)&PbVec4Type);
}
const static Pb::Register _REG(PbVecInitialize);
} // namespace Manta

View File

@@ -0,0 +1,48 @@
/******************************************************************************
*
* 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
*
* Base class for particle systems
*
******************************************************************************/
#ifndef _PYTHONINCLUDE_H
#define _PYTHONINCLUDE_H
#if defined(WIN32) || defined(_WIN32)
// note - we have to include these first!
# include <string>
# include <vector>
# include <iostream>
#endif
// the PYTHON_DEBUG_WITH_RELEASE define enables linking with python debug libraries
#if (defined(_DEBUG) || (DEBUG == 1)) && defined(DEBUG_PYTHON_WITH_RELEASE)
// special handling, disable linking with debug version of python libs
# undef _DEBUG
# define NDEBUG
# include <Python.h>
# if NUMPY == 1
# define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
# include "numpy/arrayobject.h"
# endif
# define _DEBUG
# undef NDEBUG
#else
# include <Python.h>
# if NUMPY == 1
# define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
# include "numpy/arrayobject.h"
# endif
#endif
#endif

View File

@@ -0,0 +1,817 @@
/******************************************************************************
*
* MantaFlow fluid solver framework
* Copyright 2011-2014 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
*
* Auto python registry
*
******************************************************************************/
#include <string.h>
#include "pythonInclude.h"
#include "structmember.h"
#include "manta.h"
using namespace std;
const string gDefaultModuleName = "manta";
namespace Pb {
//******************************************************************************
// Custom object definition
struct Method {
Method(const string &n, const string &d, GenericFunction f) : name(n), doc(d), func(f)
{
}
string name, doc;
GenericFunction func;
PyMethodDef def()
{
PyMethodDef def = {&name[0], (PyCFunction)func, METH_VARARGS | METH_KEYWORDS, &doc[0]};
return def;
}
};
struct GetSet {
GetSet() : getter(0), setter(0)
{
}
GetSet(const string &n, const string &d, Getter g, Setter s)
: name(n), doc(d), getter(g), setter(s)
{
}
string name, doc;
Getter getter;
Setter setter;
PyGetSetDef def()
{
PyGetSetDef def = {&name[0], getter, setter, &doc[0], nullptr};
return def;
}
};
struct ClassData {
string cName, pyName;
string cPureName, cTemplate;
InitFunc init;
PyTypeObject typeInfo;
PyNumberMethods numInfo;
// PySequenceMethods seqInfo;
vector<Method> methods;
map<string, GetSet> getset;
map<string, OperatorFunction> ops;
ClassData *baseclass;
string baseclassName;
Constructor constructor;
vector<PyMethodDef> genMethods;
vector<PyGetSetDef> genGetSet;
};
struct PbObject {
PyObject_HEAD
Manta::PbClass *instance;
ClassData *classdef;
};
//******************************************************
// Internal wrapper class
//! Registers all classes and methods exposed to Python.
/*! This class is only used internally by Pb:: framwork.
* Please use the functionality of PbClass to lookup and translate pointers. */
class WrapperRegistry {
public:
static WrapperRegistry &instance();
void addClass(const std::string &name,
const std::string &internalName,
const std::string &baseclass);
void addEnumEntry(const std::string &name, int value);
void addExternalInitializer(InitFunc func);
void addMethod(const std::string &classname,
const std::string &methodname,
GenericFunction method);
void addOperator(const std::string &classname,
const std::string &methodname,
OperatorFunction method);
void addConstructor(const std::string &classname, Constructor method);
void addGetSet(const std::string &classname,
const std::string &property,
Getter getfunc,
Setter setfunc);
void addPythonPath(const std::string &path);
void addPythonCode(const std::string &file, const std::string &code);
PyObject *createPyObject(const std::string &classname,
const std::string &name,
Manta::PbArgs &args,
Manta::PbClass *parent);
void construct(bool python_lifecycle, const std::string &scriptname, const vector<string> &args);
void cleanup();
void renameObjects();
void runPreInit(PyObject *name_space);
PyObject *initModule();
ClassData *lookup(const std::string &name);
bool canConvert(ClassData *from, ClassData *to);
private:
ClassData *getOrConstructClass(const string &name);
void registerBaseclasses();
void registerDummyTypes();
void registerMeta();
void addConstants(PyObject *module);
void registerOperators(ClassData *cls);
void addParentMethods(ClassData *cls, ClassData *base);
WrapperRegistry();
~WrapperRegistry();
std::map<std::string, ClassData *> mClasses;
std::vector<ClassData *> mClassList;
std::vector<InitFunc> mExtInitializers;
std::vector<std::string> mPaths;
std::string mCode, mScriptName;
std::vector<std::string> args;
std::map<std::string, int> mEnumValues;
};
//******************************************************************************
// Callback functions
PyObject *cbGetClass(PbObject *self, void *cl)
{
return Manta::toPy(self->classdef->cPureName);
}
PyObject *cbGetTemplate(PbObject *self, void *cl)
{
return Manta::toPy(self->classdef->cTemplate);
}
PyObject *cbGetCName(PbObject *self, void *cl)
{
return Manta::toPy(self->classdef->cName);
}
void cbDealloc(PbObject *self)
{
// cout << "dealloc " << self->instance->getName() << " " << self->classdef->cName << endl;
if (self->instance) {
#ifndef BLENDER
// don't delete top-level objects
if (self->instance->getParent() != self->instance)
delete self->instance;
#else
// in Blender we *have* to delete all objects
delete self->instance;
#endif
}
Py_TYPE(self)->tp_free((PyObject *)self);
}
PyObject *cbNew(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PbObject *self = (PbObject *)type->tp_alloc(type, 0);
if (self != nullptr) {
// lookup and link classdef
self->classdef = WrapperRegistry::instance().lookup(type->tp_name);
self->instance = nullptr;
// cout << "creating " << self->classdef->cName << endl;
}
else
errMsg("can't allocate new python class object");
return (PyObject *)self;
}
int cbDisableConstructor(PyObject *self, PyObject *args, PyObject *kwds)
{
errMsg("Can't instantiate a class template without template arguments");
return -1;
}
PyMODINIT_FUNC PyInit_manta_main(void)
{
MantaEnsureRegistration();
#if PY_MAJOR_VERSION >= 3
return WrapperRegistry::instance().initModule();
#else
WrapperRegistry::instance().initModule();
#endif
}
//******************************************************
// WrapperRegistry
WrapperRegistry::WrapperRegistry()
{
addClass("__modclass__", "__modclass__", "");
addClass("PbClass", "PbClass", "");
}
WrapperRegistry::~WrapperRegistry()
{
// Some static constructions may have called WrapperRegistry.instance() and added
// own classes, functions, etc. Ensure everything is cleaned up properly.
cleanup();
}
ClassData *WrapperRegistry::getOrConstructClass(const string &classname)
{
map<string, ClassData *>::iterator it = mClasses.find(classname);
if (it != mClasses.end())
return it->second;
ClassData *data = new ClassData;
data->cName = classname;
data->cPureName = classname;
data->cTemplate = "";
size_t tplIdx = classname.find('<');
if (tplIdx != string::npos) {
data->cPureName = classname.substr(0, tplIdx);
data->cTemplate = classname.substr(tplIdx + 1, classname.find('>') - tplIdx - 1);
}
data->baseclass = nullptr;
data->constructor = cbDisableConstructor;
mClasses[classname] = data;
mClassList.push_back(data);
return data;
}
void replaceAll(string &source, string const &find, string const &replace)
{
for (string::size_type i = 0; (i = source.find(find, i)) != std::string::npos;) {
source.replace(i, find.length(), replace);
i += replace.length() - find.length() + 1;
}
}
void WrapperRegistry::addClass(const string &pyName,
const string &internalName,
const string &baseclass)
{
ClassData *data = getOrConstructClass(internalName);
// regularize python name
string pythonName = pyName;
replaceAll(pythonName, "<", "_");
replaceAll(pythonName, ">", "");
replaceAll(pythonName, ",", "_");
if (data->pyName.empty())
data->pyName = pythonName;
mClasses[pythonName] = data;
if (!baseclass.empty())
data->baseclassName = baseclass;
}
void WrapperRegistry::addEnumEntry(const string &name, int value)
{
/// Gather static definitions to add them as static python objects afterwards
if (mEnumValues.insert(std::make_pair(name, value)).second == false) {
errMsg("Enum entry '" + name + "' already existing...");
}
}
void WrapperRegistry::addExternalInitializer(InitFunc func)
{
mExtInitializers.push_back(func);
}
void WrapperRegistry::addPythonPath(const string &path)
{
mPaths.push_back(path);
}
void WrapperRegistry::addPythonCode(const string &file, const string &code)
{
mCode += code + "\n";
}
void WrapperRegistry::addGetSet(const string &classname,
const string &property,
Getter getfunc,
Setter setfunc)
{
ClassData *classdef = getOrConstructClass(classname);
GetSet &def = classdef->getset[property];
if (def.name.empty()) {
def.name = property;
def.doc = property;
}
if (getfunc)
def.getter = getfunc;
if (setfunc)
def.setter = setfunc;
}
void WrapperRegistry::addMethod(const string &classname,
const string &methodname,
GenericFunction func)
{
string aclass = classname;
if (aclass.empty())
aclass = "__modclass__";
ClassData *classdef = getOrConstructClass(aclass);
for (int i = 0; i < (int)classdef->methods.size(); i++)
if (classdef->methods[i].name == methodname)
return; // avoid duplicates
classdef->methods.push_back(Method(methodname, methodname, func));
}
void WrapperRegistry::addOperator(const string &classname,
const string &methodname,
OperatorFunction func)
{
if (classname.empty())
errMsg("PYTHON operators have to be defined within classes.");
string op = methodname.substr(8);
ClassData *classdef = getOrConstructClass(classname);
classdef->ops[op] = func;
}
void WrapperRegistry::addConstructor(const string &classname, Constructor func)
{
ClassData *classdef = getOrConstructClass(classname);
classdef->constructor = func;
}
void WrapperRegistry::addParentMethods(ClassData *cur, ClassData *base)
{
if (base == 0)
return;
for (vector<Method>::iterator it = base->methods.begin(); it != base->methods.end(); ++it)
addMethod(cur->cName, it->name, it->func);
for (map<string, GetSet>::iterator it = base->getset.begin(); it != base->getset.end(); ++it)
addGetSet(cur->cName, it->first, it->second.getter, it->second.setter);
for (map<string, OperatorFunction>::iterator it = base->ops.begin(); it != base->ops.end(); ++it)
cur->ops[it->first] = it->second;
addParentMethods(cur, base->baseclass);
}
void WrapperRegistry::registerBaseclasses()
{
for (int i = 0; i < (int)mClassList.size(); i++) {
string bname = mClassList[i]->baseclassName;
if (!bname.empty()) {
mClassList[i]->baseclass = lookup(bname);
if (!mClassList[i]->baseclass)
errMsg("Registering class '" + mClassList[i]->cName + "' : Base class '" + bname +
"' not found");
}
}
for (int i = 0; i < (int)mClassList.size(); i++) {
addParentMethods(mClassList[i], mClassList[i]->baseclass);
}
}
void WrapperRegistry::registerMeta()
{
for (int i = 0; i < (int)mClassList.size(); i++) {
mClassList[i]->getset["_class"] = GetSet("_class", "C class name", (Getter)cbGetClass, 0);
mClassList[i]->getset["_cname"] = GetSet("_cname", "Full C name", (Getter)cbGetCName, 0);
mClassList[i]->getset["_T"] = GetSet("_T", "C template argument", (Getter)cbGetTemplate, 0);
}
}
void WrapperRegistry::registerOperators(ClassData *cls)
{
PyNumberMethods &num = cls->numInfo;
for (map<string, OperatorFunction>::iterator it = cls->ops.begin(); it != cls->ops.end(); it++) {
const string &op = it->first;
OperatorFunction func = it->second;
if (op == "+=")
num.nb_inplace_add = func;
else if (op == "-=")
num.nb_inplace_subtract = func;
else if (op == "*=")
num.nb_inplace_multiply = func;
else if (op == "+")
num.nb_add = func;
else if (op == "-")
num.nb_subtract = func;
else if (op == "*")
num.nb_multiply = func;
#if PY_MAJOR_VERSION < 3
else if (op == "/=")
num.nb_inplace_divide = func;
else if (op == "/")
num.nb_divide = func;
#else
else if (op == "/=")
num.nb_inplace_true_divide = func;
else if (op == "/")
num.nb_true_divide = func;
#endif
else
errMsg("PYTHON operator " + op + " not supported");
}
}
void WrapperRegistry::registerDummyTypes()
{
vector<string> add;
for (vector<ClassData *>::iterator it = mClassList.begin(); it != mClassList.end(); ++it) {
string cName = (*it)->cName;
if (cName.find('<') != string::npos)
add.push_back(cName.substr(0, cName.find('<')));
}
for (int i = 0; i < (int)add.size(); i++)
addClass(add[i], add[i], "");
}
ClassData *WrapperRegistry::lookup(const string &name)
{
for (map<string, ClassData *>::iterator it = mClasses.begin(); it != mClasses.end(); ++it) {
if (it->first == name || it->second->cName == name)
return it->second;
}
return nullptr;
}
void WrapperRegistry::cleanup()
{
for (vector<ClassData *>::iterator it = mClassList.begin(); it != mClassList.end(); ++it) {
delete *it;
}
mClasses.clear();
mClassList.clear();
}
WrapperRegistry &WrapperRegistry::instance()
{
static WrapperRegistry inst;
return inst;
}
bool WrapperRegistry::canConvert(ClassData *from, ClassData *to)
{
if (from == to)
return true;
if (from->baseclass)
return canConvert(from->baseclass, to);
return false;
}
void WrapperRegistry::addConstants(PyObject *module)
{
// expose arguments
PyObject *list = PyList_New(args.size());
for (int i = 0; i < (int)args.size(); i++)
PyList_SET_ITEM(list, i, Manta::toPy(args[i]));
PyModule_AddObject(module, "args", list);
PyModule_AddObject(module, "SCENEFILE", Manta::toPy(mScriptName));
// expose compile flags
#ifdef DEBUG
PyModule_AddObject(module, "DEBUG", Manta::toPy<bool>(true));
#else
PyModule_AddObject(module, "DEBUG", Manta::toPy<bool>(false));
#endif
#ifdef MANTA_MT
PyModule_AddObject(module, "MT", Manta::toPy<bool>(true));
#else
PyModule_AddObject(module, "MT", Manta::toPy<bool>(false));
#endif
#ifdef GUI
PyModule_AddObject(module, "GUI", Manta::toPy<bool>(true));
#else
PyModule_AddObject(module, "GUI", Manta::toPy<bool>(false));
#endif
#if FLOATINGPOINT_PRECISION == 2
PyModule_AddObject(module, "DOUBLEPRECISION", Manta::toPy<bool>(true));
#else
PyModule_AddObject(module, "DOUBLEPRECISION", Manta::toPy<bool>(false));
#endif
// cuda off for now
PyModule_AddObject(module, "CUDA", Manta::toPy<bool>(false));
// expose enum entries
std::map<std::string, int>::iterator it;
for (it = mEnumValues.begin(); it != mEnumValues.end(); it++) {
PyModule_AddObject(module, it->first.c_str(), Manta::toPy(it->second));
// Alternative would be:
// e.g. PyModule_AddIntConstant(module, "FlagFluid", 1);
}
}
void WrapperRegistry::runPreInit(PyObject *name_space)
{
// add python directories to path
PyObject *sys_path = PySys_GetObject((char *)"path");
for (size_t i = 0; i < mPaths.size(); i++) {
PyObject *path = Manta::toPy(mPaths[i]);
if (sys_path == nullptr || path == nullptr || PyList_Append(sys_path, path) < 0) {
errMsg("unable to set python path");
}
Py_DECREF(path);
}
if (!mCode.empty()) {
mCode = "from manta import *\n" + mCode;
PyObject *return_value = PyRun_String(mCode.c_str(), Py_file_input, name_space, name_space);
if (return_value == nullptr) {
if (PyErr_Occurred()) {
PyErr_Print();
}
}
else {
Py_DECREF(return_value);
}
}
}
PyObject *WrapperRegistry::createPyObject(const string &classname,
const string &name,
Manta::PbArgs &args,
Manta::PbClass *parent)
{
ClassData *classdef = lookup(classname);
if (!classdef)
errMsg("Class " + classname + " doesn't exist.");
// create object
PyObject *obj = cbNew(&classdef->typeInfo, nullptr, nullptr);
PbObject *self = (PbObject *)obj;
PyObject *nkw = 0;
if (args.kwds())
nkw = PyDict_Copy(args.kwds());
else
nkw = PyDict_New();
PyObject *nocheck = Py_BuildValue("s", "yes");
PyDict_SetItemString(nkw, "nocheck", nocheck);
if (parent)
PyDict_SetItemString(nkw, "parent", parent->getPyObject());
// create instance
if (self->classdef->constructor(obj, args.linArgs(), nkw) < 0)
errMsg("error raised in constructor"); // assume condition is already set
Py_DECREF(nkw);
Py_DECREF(nocheck);
self->instance->setName(name);
return obj;
}
// prepare typeinfo and register python module
void WrapperRegistry::construct(const bool python_lifecycle,
const string &scriptname,
const vector<string> &args)
{
mScriptName = scriptname;
this->args = args;
registerBaseclasses();
registerMeta();
registerDummyTypes();
// Don't extend the init-tab when Python is already initialized.
// Since Python 3.12 this isn't supported and will crash.
//
// When `python_lifecycle` is false (when manta-flow is embedded), it's the responsibility
// of the application embedding this code to include #PyInit_manta_main in the init-tab.
if (python_lifecycle) {
// work around for certain gcc versions, cast to char*
PyImport_AppendInittab((char *)gDefaultModuleName.c_str(), PyInit_manta_main);
}
}
inline PyObject *castPy(PyTypeObject *p)
{
return reinterpret_cast<PyObject *>(static_cast<void *>(p));
}
PyObject *WrapperRegistry::initModule()
{
// generate and terminate all method lists
PyMethodDef sentinelFunc = {nullptr, nullptr, 0, nullptr};
PyGetSetDef sentinelGetSet = {nullptr, nullptr, nullptr, nullptr, nullptr};
for (int i = 0; i < (int)mClassList.size(); i++) {
ClassData *cls = mClassList[i];
cls->genMethods.clear();
cls->genGetSet.clear();
for (vector<Method>::iterator i2 = cls->methods.begin(); i2 != cls->methods.end(); ++i2)
cls->genMethods.push_back(i2->def());
for (map<string, GetSet>::iterator i2 = cls->getset.begin(); i2 != cls->getset.end(); ++i2)
cls->genGetSet.push_back(i2->second.def());
cls->genMethods.push_back(sentinelFunc);
cls->genGetSet.push_back(sentinelGetSet);
}
// prepare module info
#if PY_MAJOR_VERSION >= 3
static PyModuleDef MainModule = {PyModuleDef_HEAD_INIT,
gDefaultModuleName.c_str(),
"Bridge module to the C++ solver",
-1,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr};
// get generic methods (plugin functions)
MainModule.m_methods = &mClasses["__modclass__"]->genMethods[0];
// create module
PyObject *module = PyModule_Create(&MainModule);
#else
PyObject *module = Py_InitModule(gDefaultModuleName.c_str(),
&mClasses["__modclass__"]->genMethods[0]);
#endif
if (module == nullptr)
return nullptr;
// load classes
for (vector<ClassData *>::iterator it = mClassList.begin(); it != mClassList.end(); ++it) {
ClassData &data = **it;
char *nameptr = (char *)data.pyName.c_str();
// define numeric substruct
PyNumberMethods *num = 0;
if (!data.ops.empty()) {
num = &data.numInfo;
memset(num, 0, sizeof(PyNumberMethods));
registerOperators(&data);
}
// define python classinfo
PyTypeObject t = {
PyVarObject_HEAD_INIT(nullptr, 0)(char *) data.pyName.c_str(), // tp_name
sizeof(PbObject), // tp_basicsize
0, // tp_itemsize
(destructor)cbDealloc, // tp_dealloc
0, // tp_print
0, // tp_getattr
0, // tp_setattr
0, // tp_reserved
0, // tp_repr
num, // tp_as_number
0, // tp_as_sequence
0, // tp_as_mapping
0, // tp_hash
0, // tp_call
0, // tp_str
0, // tp_getattro
0, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags
nameptr, // tp_doc
0, // tp_traverse
0, // tp_clear
0, // tp_richcompare
0, // tp_weaklistoffset
0, // tp_iter
0, // tp_iternext
&data.genMethods[0], // tp_methods
0, // tp_members
&data.genGetSet[0], // tp_getset
0, // tp_base
0, // tp_dict
0, // tp_descr_get
0, // tp_descr_set
0, // tp_dictoffset
(initproc)(data.constructor), // tp_init
0, // tp_alloc
cbNew // tp_new
};
data.typeInfo = t;
if (PyType_Ready(&data.typeInfo) < 0)
continue;
for (map<string, ClassData *>::iterator i2 = mClasses.begin(); i2 != mClasses.end(); ++i2) {
if (*it != i2->second)
continue;
// register all aliases
Py_INCREF(castPy(&data.typeInfo));
PyModule_AddObject(module, (char *)i2->first.c_str(), (PyObject *)&data.typeInfo);
}
}
// externals
for (vector<InitFunc>::iterator it = mExtInitializers.begin(); it != mExtInitializers.end();
++it) {
(*it)(module);
}
addConstants(module);
return module;
}
//******************************************************
// Register members and exposed functions
void setup(const bool python_lifecycle,
const std::string &filename,
const std::vector<std::string> &args,
PyObject *name_space)
{
WrapperRegistry::instance().construct(python_lifecycle, filename, args);
if (python_lifecycle) {
Py_Initialize();
}
WrapperRegistry::instance().runPreInit(name_space);
}
void finalize(const bool python_lifecycle)
{
if (python_lifecycle) {
Py_Finalize();
}
WrapperRegistry::instance().cleanup();
}
bool canConvert(PyObject *obj, const string &classname)
{
ClassData *from = ((PbObject *)obj)->classdef;
ClassData *dest = WrapperRegistry::instance().lookup(classname);
if (!dest)
errMsg("Classname '" + classname + "' is not registered.");
return WrapperRegistry::instance().canConvert(from, dest);
}
Manta::PbClass *objFromPy(PyObject *obj)
{
if (Py_TYPE(obj)->tp_dealloc != (destructor)cbDealloc) // not a manta object
return nullptr;
return ((PbObject *)obj)->instance;
}
PyObject *copyObject(Manta::PbClass *cls, const string &classname)
{
ClassData *classdef = WrapperRegistry::instance().lookup(classname);
assertMsg(classdef, "python class " + classname + " does not exist.");
// allocate new object
PbObject *obj = (PbObject *)classdef->typeInfo.tp_alloc(&(classdef->typeInfo), 0);
assertMsg(obj, "cannot allocate new python object");
obj->classdef = classdef;
cls->registerObject((PyObject *)obj, 0);
return cls->getPyObject();
}
Manta::PbClass *createPy(const std::string &classname,
const std::string &name,
Manta::PbArgs &args,
Manta::PbClass *parent)
{
PyObject *obj = WrapperRegistry::instance().createPyObject(classname, name, args, parent);
return ((PbObject *)obj)->instance;
}
void setReference(Manta::PbClass *cls, PyObject *obj)
{
((PbObject *)obj)->instance = cls;
}
Register::Register(const string &className, const string &funcName, GenericFunction func)
{
WrapperRegistry::instance().addMethod(className, funcName, func);
}
Register::Register(const string &className, const string &funcName, OperatorFunction func)
{
WrapperRegistry::instance().addOperator(className, funcName, func);
}
Register::Register(const string &className, const string &funcName, Constructor func)
{
WrapperRegistry::instance().addConstructor(className, func);
}
Register::Register(const string &className, const string &property, Getter getter, Setter setter)
{
WrapperRegistry::instance().addGetSet(className, property, getter, setter);
}
Register::Register(const string &className, const string &pyName, const string &baseClass)
{
WrapperRegistry::instance().addClass(pyName, className, baseClass);
}
Register::Register(const string &name, const int value)
{
WrapperRegistry::instance().addEnumEntry(name, value);
}
Register::Register(const string &file, const string &pythonCode)
{
WrapperRegistry::instance().addPythonCode(file, pythonCode);
}
Register::Register(InitFunc func)
{
WrapperRegistry::instance().addExternalInitializer(func);
}
} // namespace Pb

View File

@@ -0,0 +1,109 @@
/******************************************************************************
*
* MantaFlow fluid solver framework
* Copyright 2011-2014 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
*
* Auto python registry
*
******************************************************************************/
#ifndef _REGISTRY_H
#define _REGISTRY_H
#include <string>
#include <vector>
// forward declaration to minimize Python.h includes
#ifndef PyObject_HEAD
# ifndef PyObject_Fake
struct _object;
typedef _object PyObject;
# define PyObject_Fake
# endif
#endif
namespace Manta {
class PbClass;
class PbArgs;
} // namespace Manta
// **************************************************
// NOTE
// Everything in this file is intend only for internal
// use by the generated wrappers or pclass/pconvert.
// For user code, use the functionality exposed in
// pclass.h / pconvert.h instead.
// **************************************************
// Used to turn names into strings
namespace Manta {
template<class T> struct Namify {
static const char *S;
};
} // namespace Manta
namespace Pb {
// internal registry access
void setup(bool python_lifecycle,
const std::string &filename,
const std::vector<std::string> &args,
PyObject *name_space);
void finalize(bool python_lifecycle);
bool canConvert(PyObject *obj, const std::string &to);
Manta::PbClass *objFromPy(PyObject *obj);
Manta::PbClass *createPy(const std::string &classname,
const std::string &name,
Manta::PbArgs &args,
Manta::PbClass *parent);
void setReference(Manta::PbClass *cls, PyObject *obj);
PyObject *copyObject(Manta::PbClass *cls, const std::string &classname);
void MantaEnsureRegistration();
#ifdef BLENDER
# ifdef PyMODINIT_FUNC
PyMODINIT_FUNC PyInit_manta_main(void);
# endif
#endif
// callback type
typedef void (*InitFunc)(PyObject *);
typedef PyObject *(*GenericFunction)(PyObject *self, PyObject *args, PyObject *kwds);
typedef PyObject *(*OperatorFunction)(PyObject *self, PyObject *o);
typedef int (*Constructor)(PyObject *self, PyObject *args, PyObject *kwds);
typedef PyObject *(*Getter)(PyObject *self, void *closure);
typedef int (*Setter)(PyObject *self, PyObject *value, void *closure);
//! Auto registry of python methods and classes
struct Register {
//! register method
Register(const std::string &className, const std::string &funcName, GenericFunction func);
//! register operator
Register(const std::string &className, const std::string &funcName, OperatorFunction func);
//! register constructor
Register(const std::string &className, const std::string &funcName, Constructor func);
//! register getter/setter
Register(const std::string &className,
const std::string &property,
Getter getter,
Setter setter);
//! register class
Register(const std::string &className, const std::string &pyName, const std::string &baseClass);
//! register enum entry
Register(const std::string &name, const int value);
//! register python code
Register(const std::string &file, const std::string &pythonCode);
//! register external code
Register(InitFunc func);
};
#define KEEP_UNUSED(var) \
do { \
(void)var; \
} while (false);
} // namespace Pb
#endif

View File

@@ -0,0 +1,79 @@
/******************************************************************************
*
* 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
*
* Helper functions for simple integration
*
******************************************************************************/
#ifndef _INTEGRATE_H
#define _INTEGRATE_H
#include <vector>
#include "vectorbase.h"
#include "kernel.h"
namespace Manta {
enum IntegrationMode { IntEuler = 0, IntRK2, IntRK4 };
//! Integrate a particle set with a given velocity kernel
template<class VelKernel> void integratePointSet(VelKernel &k, int mode)
{
typedef typename VelKernel::type0 PosType;
PosType &x = k.getArg0();
const std::vector<Vec3> &u = k.getRet();
const int N = x.size();
if (mode == IntEuler) {
for (int i = 0; i < N; i++)
x[i].pos += u[i];
}
else if (mode == IntRK2) {
PosType x0(x);
for (int i = 0; i < N; i++)
x[i].pos = x0[i].pos + 0.5 * u[i];
k.run();
for (int i = 0; i < N; i++)
x[i].pos = x0[i].pos + u[i];
}
else if (mode == IntRK4) {
PosType x0(x);
std::vector<Vec3> uTotal(u);
for (int i = 0; i < N; i++)
x[i].pos = x0[i].pos + 0.5 * u[i];
k.run();
for (int i = 0; i < N; i++) {
x[i].pos = x0[i].pos + 0.5 * u[i];
uTotal[i] += 2 * u[i];
}
k.run();
for (int i = 0; i < N; i++) {
x[i].pos = x0[i].pos + u[i];
uTotal[i] += 2 * u[i];
}
k.run();
for (int i = 0; i < N; i++)
x[i].pos = x0[i].pos + (Real)(1. / 6.) * (uTotal[i] + u[i]);
}
else
errMsg("unknown integration type");
// for(int i=0; i<N; i++) std::cout << x[i].pos.y-x[0].pos.y << std::endl;
// std::cout << "<><><>" << std::endl;
}
} // namespace Manta
#endif

View File

@@ -0,0 +1,324 @@
/******************************************************************************
*
* 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
*
* Helper functions for interpolation
*
******************************************************************************/
#ifndef _INTERPOL_H
#define _INTERPOL_H
#include "vectorbase.h"
// Grid values are stored at i+0.5, j+0.5, k+0.5
// MAC grid values are stored at i,j+0.5,k+0.5 (for x) ...
namespace Manta {
inline Vec3 fdTangent(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2)
{
return 0.5 * (getNormalized(p2 - p1) + getNormalized(p1 - p0));
}
inline Vec3 crTangent(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2)
{
return 0.5 * (p2 - p0);
}
inline Vec3 hermiteSpline(const Vec3 &p0, const Vec3 &p1, const Vec3 &m0, const Vec3 &m1, Real t)
{
const Real t2 = t * t, t3 = t2 * t;
return (2.0 * t3 - 3.0 * t2 + 1.0) * p0 + (t3 - 2.0 * t2 + t) * m0 +
(-2.0 * t3 + 3.0 * t2) * p1 + (t3 - t2) * m1;
}
static inline void checkIndexInterpol(const Vec3i &size, IndexInt idx)
{
if (idx < 0 || idx > (IndexInt)size.x * size.y * size.z) {
std::ostringstream s;
s << "Grid interpol dim " << size << " : index " << idx << " out of bound ";
errMsg(s.str());
}
}
// ----------------------------------------------------------------------
// Grid interpolators
// ----------------------------------------------------------------------
#define BUILD_INDEX \
Real px = pos.x - 0.5f, py = pos.y - 0.5f, pz = pos.z - 0.5f; \
int xi = (int)px; \
int yi = (int)py; \
int zi = (int)pz; \
Real s1 = px - (Real)xi, s0 = 1. - s1; \
Real t1 = py - (Real)yi, t0 = 1. - t1; \
Real f1 = pz - (Real)zi, f0 = 1. - f1; \
/* clamp to border */ \
if (px < 0.) { \
xi = 0; \
s0 = 1.0; \
s1 = 0.0; \
} \
if (py < 0.) { \
yi = 0; \
t0 = 1.0; \
t1 = 0.0; \
} \
if (pz < 0.) { \
zi = 0; \
f0 = 1.0; \
f1 = 0.0; \
} \
if (xi >= size.x - 1) { \
xi = size.x - 2; \
s0 = 0.0; \
s1 = 1.0; \
} \
if (yi >= size.y - 1) { \
yi = size.y - 2; \
t0 = 0.0; \
t1 = 1.0; \
} \
if (size.z > 1) { \
if (zi >= size.z - 1) { \
zi = size.z - 2; \
f0 = 0.0; \
f1 = 1.0; \
} \
} \
const int X = 1; \
const int Y = size.x;
template<class T> inline T interpol(const T *data, const Vec3i &size, const int Z, const Vec3 &pos)
{
BUILD_INDEX
IndexInt idx = (IndexInt)xi + (IndexInt)Y * yi + (IndexInt)Z * zi;
DEBUG_ONLY(checkIndexInterpol(size, idx));
DEBUG_ONLY(checkIndexInterpol(size, idx + X + Y + Z));
return ((data[idx] * t0 + data[idx + Y] * t1) * s0 +
(data[idx + X] * t0 + data[idx + X + Y] * t1) * s1) *
f0 +
((data[idx + Z] * t0 + data[idx + Y + Z] * t1) * s0 +
(data[idx + X + Z] * t0 + data[idx + X + Y + Z] * t1) * s1) *
f1;
}
template<int c>
inline Real interpolComponent(const Vec3 *data, const Vec3i &size, const int Z, const Vec3 &pos)
{
BUILD_INDEX
IndexInt idx = (IndexInt)xi + (IndexInt)Y * yi + (IndexInt)Z * zi;
DEBUG_ONLY(checkIndexInterpol(size, idx));
DEBUG_ONLY(checkIndexInterpol(size, idx + X + Y + Z));
return ((data[idx][c] * t0 + data[idx + Y][c] * t1) * s0 +
(data[idx + X][c] * t0 + data[idx + X + Y][c] * t1) * s1) *
f0 +
((data[idx + Z][c] * t0 + data[idx + Y + Z][c] * t1) * s0 +
(data[idx + X + Z][c] * t0 + data[idx + X + Y + Z][c] * t1) * s1) *
f1;
}
template<class T>
inline void setInterpol(
T *data, const Vec3i &size, const int Z, const Vec3 &pos, const T &v, Real *sumBuffer)
{
BUILD_INDEX
IndexInt idx = (IndexInt)xi + (IndexInt)Y * yi + (IndexInt)Z * zi;
DEBUG_ONLY(checkIndexInterpol(size, idx));
DEBUG_ONLY(checkIndexInterpol(size, idx + X + Y + Z));
T *ref = &data[idx];
Real *sum = &sumBuffer[idx];
Real s0f0 = s0 * f0, s1f0 = s1 * f0, s0f1 = s0 * f1, s1f1 = s1 * f1;
Real w0 = t0 * s0f0, wx = t0 * s1f0, wy = t1 * s0f0, wxy = t1 * s1f0;
Real wz = t0 * s0f1, wxz = t0 * s1f1, wyz = t1 * s0f1, wxyz = t1 * s1f1;
sum[Z] += wz;
sum[X + Z] += wxz;
sum[Y + Z] += wyz;
sum[X + Y + Z] += wxyz;
ref[Z] += wz * v;
ref[X + Z] += wxz * v;
ref[Y + Z] += wyz * v;
ref[X + Y + Z] += wxyz * v;
sum[0] += w0;
sum[X] += wx;
sum[Y] += wy;
sum[X + Y] += wxy;
ref[0] += w0 * v;
ref[X] += wx * v;
ref[Y] += wy * v;
ref[X + Y] += wxy * v;
}
#define BUILD_INDEX_SHIFT \
BUILD_INDEX \
/* shifted coords */ \
int s_xi = (int)pos.x, s_yi = (int)pos.y, s_zi = (int)pos.z; \
Real s_s1 = pos.x - (Real)s_xi, s_s0 = 1. - s_s1; \
Real s_t1 = pos.y - (Real)s_yi, s_t0 = 1. - s_t1; \
Real s_f1 = pos.z - (Real)s_zi, s_f0 = 1. - s_f1; \
/* clamp to border */ \
if (pos.x < 0) { \
s_xi = 0; \
s_s0 = 1.0; \
s_s1 = 0.0; \
} \
if (pos.y < 0) { \
s_yi = 0; \
s_t0 = 1.0; \
s_t1 = 0.0; \
} \
if (pos.z < 0) { \
s_zi = 0; \
s_f0 = 1.0; \
s_f1 = 0.0; \
} \
if (s_xi >= size.x - 1) { \
s_xi = size.x - 2; \
s_s0 = 0.0; \
s_s1 = 1.0; \
} \
if (s_yi >= size.y - 1) { \
s_yi = size.y - 2; \
s_t0 = 0.0; \
s_t1 = 1.0; \
} \
if (size.z > 1) { \
if (s_zi >= size.z - 1) { \
s_zi = size.z - 2; \
s_f0 = 0.0; \
s_f1 = 1.0; \
} \
}
inline Vec3 interpolMAC(const Vec3 *data, const Vec3i &size, const int Z, const Vec3 &pos)
{
BUILD_INDEX_SHIFT;
DEBUG_ONLY(checkIndexInterpol(size, (zi * (IndexInt)size.y + yi) * (IndexInt)size.x + xi));
DEBUG_ONLY(checkIndexInterpol(
size, (s_zi * (IndexInt)size.y + s_yi) * (IndexInt)size.x + s_xi + X + Y + Z));
// process individual components
Vec3 ret(0.);
{ // X
const Vec3 *ref = &data[((zi * size.y + yi) * size.x + s_xi)];
ret.x = f0 * ((ref[0].x * t0 + ref[Y].x * t1) * s_s0 +
(ref[X].x * t0 + ref[X + Y].x * t1) * s_s1) +
f1 * ((ref[Z].x * t0 + ref[Z + Y].x * t1) * s_s0 +
(ref[X + Z].x * t0 + ref[X + Y + Z].x * t1) * s_s1);
}
{ // Y
const Vec3 *ref = &data[((zi * size.y + s_yi) * size.x + xi)];
ret.y = f0 * ((ref[0].y * s_t0 + ref[Y].y * s_t1) * s0 +
(ref[X].y * s_t0 + ref[X + Y].y * s_t1) * s1) +
f1 * ((ref[Z].y * s_t0 + ref[Z + Y].y * s_t1) * s0 +
(ref[X + Z].y * s_t0 + ref[X + Y + Z].y * s_t1) * s1);
}
{ // Z
const Vec3 *ref = &data[((s_zi * size.y + yi) * size.x + xi)];
ret.z = s_f0 *
((ref[0].z * t0 + ref[Y].z * t1) * s0 + (ref[X].z * t0 + ref[X + Y].z * t1) * s1) +
s_f1 * ((ref[Z].z * t0 + ref[Z + Y].z * t1) * s0 +
(ref[X + Z].z * t0 + ref[X + Y + Z].z * t1) * s1);
}
return ret;
}
inline void setInterpolMAC(
Vec3 *data, const Vec3i &size, const int Z, const Vec3 &pos, const Vec3 &val, Vec3 *sumBuffer)
{
BUILD_INDEX_SHIFT;
DEBUG_ONLY(checkIndexInterpol(size, (zi * (IndexInt)size.y + yi) * (IndexInt)size.x + xi));
DEBUG_ONLY(checkIndexInterpol(
size, (s_zi * (IndexInt)size.y + s_yi) * (IndexInt)size.x + s_xi + X + Y + Z));
// process individual components
{ // X
const IndexInt idx = (IndexInt)(zi * size.y + yi) * size.x + s_xi;
Vec3 *ref = &data[idx], *sum = &sumBuffer[idx];
Real s0f0 = s_s0 * f0, s1f0 = s_s1 * f0, s0f1 = s_s0 * f1, s1f1 = s_s1 * f1;
Real w0 = t0 * s0f0, wx = t0 * s1f0, wy = t1 * s0f0, wxy = t1 * s1f0;
Real wz = t0 * s0f1, wxz = t0 * s1f1, wyz = t1 * s0f1, wxyz = t1 * s1f1;
sum[Z].x += wz;
sum[X + Z].x += wxz;
sum[Y + Z].x += wyz;
sum[X + Y + Z].x += wxyz;
ref[Z].x += wz * val.x;
ref[X + Z].x += wxz * val.x;
ref[Y + Z].x += wyz * val.x;
ref[X + Y + Z].x += wxyz * val.x;
sum[0].x += w0;
sum[X].x += wx;
sum[Y].x += wy;
sum[X + Y].x += wxy;
ref[0].x += w0 * val.x;
ref[X].x += wx * val.x;
ref[Y].x += wy * val.x;
ref[X + Y].x += wxy * val.x;
}
{ // Y
const IndexInt idx = (IndexInt)(zi * size.y + s_yi) * size.x + xi;
Vec3 *ref = &data[idx], *sum = &sumBuffer[idx];
Real s0f0 = s0 * f0, s1f0 = s1 * f0, s0f1 = s0 * f1, s1f1 = s1 * f1;
Real w0 = s_t0 * s0f0, wx = s_t0 * s1f0, wy = s_t1 * s0f0, wxy = s_t1 * s1f0;
Real wz = s_t0 * s0f1, wxz = s_t0 * s1f1, wyz = s_t1 * s0f1, wxyz = s_t1 * s1f1;
sum[Z].y += wz;
sum[X + Z].y += wxz;
sum[Y + Z].y += wyz;
sum[X + Y + Z].y += wxyz;
ref[Z].y += wz * val.y;
ref[X + Z].y += wxz * val.y;
ref[Y + Z].y += wyz * val.y;
ref[X + Y + Z].y += wxyz * val.y;
sum[0].y += w0;
sum[X].y += wx;
sum[Y].y += wy;
sum[X + Y].y += wxy;
ref[0].y += w0 * val.y;
ref[X].y += wx * val.y;
ref[Y].y += wy * val.y;
ref[X + Y].y += wxy * val.y;
}
{ // Z
const IndexInt idx = (IndexInt)(s_zi * size.y + yi) * size.x + xi;
Vec3 *ref = &data[idx], *sum = &sumBuffer[idx];
Real s0f0 = s0 * s_f0, s1f0 = s1 * s_f0, s0f1 = s0 * s_f1, s1f1 = s1 * s_f1;
Real w0 = t0 * s0f0, wx = t0 * s1f0, wy = t1 * s0f0, wxy = t1 * s1f0;
Real wz = t0 * s0f1, wxz = t0 * s1f1, wyz = t1 * s0f1, wxyz = t1 * s1f1;
sum[0].z += w0;
sum[X].z += wx;
sum[Y].z += wy;
sum[X + Y].z += wxy;
sum[Z].z += wz;
sum[X + Z].z += wxz;
sum[Y + Z].z += wyz;
sum[X + Y + Z].z += wxyz;
ref[0].z += w0 * val.z;
ref[X].z += wx * val.z;
ref[Y].z += wy * val.z;
ref[X + Y].z += wxy * val.z;
ref[Z].z += wz * val.z;
ref[X + Z].z += wxz * val.z;
ref[Y + Z].z += wyz * val.z;
ref[X + Y + Z].z += wxyz * val.z;
}
}
#undef BUILD_INDEX
#undef BUILD_INDEX_SHIFT
} // namespace Manta
#endif

View File

@@ -0,0 +1,204 @@
/******************************************************************************
*
* MantaFlow fluid solver framework
* Copyright 2014 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
*
* Helper functions for higher order interpolation
*
******************************************************************************/
#ifndef _INTERPOLHIGH_H
#define _INTERPOLHIGH_H
#include "vectorbase.h"
namespace Manta {
template<class T> inline T cubicInterp(const Real interp, const T *points)
{
T d0 = (points[2] - points[0]) * 0.5;
T d1 = (points[3] - points[1]) * 0.5;
T deltak = (points[2] - points[1]);
// disabled: if (deltak * d0 < 0.0) d0 = 0;
// disabled: if (deltak * d1 < 0.0) d1 = 0;
T a0 = points[1];
T a1 = d0;
T a2 = 3.0 * deltak - 2.0 * d0 - d1;
T a3 = -2.0 * deltak + d0 + d1;
Real squared = interp * interp;
Real cubed = squared * interp;
return a3 * cubed + a2 * squared + a1 * interp + a0;
}
template<class T> inline T interpolCubic2D(const T *data, const Vec3i &size, const Vec3 &pos)
{
const Real px = pos.x - 0.5f, py = pos.y - 0.5f;
const int x1 = (int)px;
const int x2 = x1 + 1;
const int x3 = x1 + 2;
const int x0 = x1 - 1;
const int y1 = (int)py;
const int y2 = y1 + 1;
const int y3 = y1 + 2;
const int y0 = y1 - 1;
if (x0 < 0 || y0 < 0 || x3 >= size[0] || y3 >= size[1]) {
return interpol(data, size, 0, pos);
}
const Real xInterp = px - x1;
const Real yInterp = py - y1;
const int y0x = y0 * size[0];
const int y1x = y1 * size[0];
const int y2x = y2 * size[0];
const int y3x = y3 * size[0];
const T p0[] = {data[x0 + y0x], data[x1 + y0x], data[x2 + y0x], data[x3 + y0x]};
const T p1[] = {data[x0 + y1x], data[x1 + y1x], data[x2 + y1x], data[x3 + y1x]};
const T p2[] = {data[x0 + y2x], data[x1 + y2x], data[x2 + y2x], data[x3 + y2x]};
const T p3[] = {data[x0 + y3x], data[x1 + y3x], data[x2 + y3x], data[x3 + y3x]};
const T finalPoints[] = {cubicInterp(xInterp, p0),
cubicInterp(xInterp, p1),
cubicInterp(xInterp, p2),
cubicInterp(xInterp, p3)};
return cubicInterp(yInterp, finalPoints);
}
template<class T>
inline T interpolCubic(const T *data, const Vec3i &size, const int Z, const Vec3 &pos)
{
if (Z == 0)
return interpolCubic2D(data, size, pos);
const Real px = pos.x - 0.5f, py = pos.y - 0.5f, pz = pos.z - 0.5f;
const int x1 = (int)px;
const int x2 = x1 + 1;
const int x3 = x1 + 2;
const int x0 = x1 - 1;
const int y1 = (int)py;
const int y2 = y1 + 1;
const int y3 = y1 + 2;
const int y0 = y1 - 1;
const int z1 = (int)pz;
const int z2 = z1 + 1;
const int z3 = z1 + 2;
const int z0 = z1 - 1;
if (x0 < 0 || y0 < 0 || z0 < 0 || x3 >= size[0] || y3 >= size[1] || z3 >= size[2]) {
return interpol(data, size, Z, pos);
}
const Real xInterp = px - x1;
const Real yInterp = py - y1;
const Real zInterp = pz - z1;
const int slabsize = size[0] * size[1];
const int z0Slab = z0 * slabsize;
const int z1Slab = z1 * slabsize;
const int z2Slab = z2 * slabsize;
const int z3Slab = z3 * slabsize;
const int y0x = y0 * size[0];
const int y1x = y1 * size[0];
const int y2x = y2 * size[0];
const int y3x = y3 * size[0];
const int y0z0 = y0x + z0Slab;
const int y1z0 = y1x + z0Slab;
const int y2z0 = y2x + z0Slab;
const int y3z0 = y3x + z0Slab;
const int y0z1 = y0x + z1Slab;
const int y1z1 = y1x + z1Slab;
const int y2z1 = y2x + z1Slab;
const int y3z1 = y3x + z1Slab;
const int y0z2 = y0x + z2Slab;
const int y1z2 = y1x + z2Slab;
const int y2z2 = y2x + z2Slab;
const int y3z2 = y3x + z2Slab;
const int y0z3 = y0x + z3Slab;
const int y1z3 = y1x + z3Slab;
const int y2z3 = y2x + z3Slab;
const int y3z3 = y3x + z3Slab;
// get the z0 slice
const T p0[] = {data[x0 + y0z0], data[x1 + y0z0], data[x2 + y0z0], data[x3 + y0z0]};
const T p1[] = {data[x0 + y1z0], data[x1 + y1z0], data[x2 + y1z0], data[x3 + y1z0]};
const T p2[] = {data[x0 + y2z0], data[x1 + y2z0], data[x2 + y2z0], data[x3 + y2z0]};
const T p3[] = {data[x0 + y3z0], data[x1 + y3z0], data[x2 + y3z0], data[x3 + y3z0]};
// get the z1 slice
const T p4[] = {data[x0 + y0z1], data[x1 + y0z1], data[x2 + y0z1], data[x3 + y0z1]};
const T p5[] = {data[x0 + y1z1], data[x1 + y1z1], data[x2 + y1z1], data[x3 + y1z1]};
const T p6[] = {data[x0 + y2z1], data[x1 + y2z1], data[x2 + y2z1], data[x3 + y2z1]};
const T p7[] = {data[x0 + y3z1], data[x1 + y3z1], data[x2 + y3z1], data[x3 + y3z1]};
// get the z2 slice
const T p8[] = {data[x0 + y0z2], data[x1 + y0z2], data[x2 + y0z2], data[x3 + y0z2]};
const T p9[] = {data[x0 + y1z2], data[x1 + y1z2], data[x2 + y1z2], data[x3 + y1z2]};
const T p10[] = {data[x0 + y2z2], data[x1 + y2z2], data[x2 + y2z2], data[x3 + y2z2]};
const T p11[] = {data[x0 + y3z2], data[x1 + y3z2], data[x2 + y3z2], data[x3 + y3z2]};
// get the z3 slice
const T p12[] = {data[x0 + y0z3], data[x1 + y0z3], data[x2 + y0z3], data[x3 + y0z3]};
const T p13[] = {data[x0 + y1z3], data[x1 + y1z3], data[x2 + y1z3], data[x3 + y1z3]};
const T p14[] = {data[x0 + y2z3], data[x1 + y2z3], data[x2 + y2z3], data[x3 + y2z3]};
const T p15[] = {data[x0 + y3z3], data[x1 + y3z3], data[x2 + y3z3], data[x3 + y3z3]};
// interpolate
const T z0Points[] = {cubicInterp(xInterp, p0),
cubicInterp(xInterp, p1),
cubicInterp(xInterp, p2),
cubicInterp(xInterp, p3)};
const T z1Points[] = {cubicInterp(xInterp, p4),
cubicInterp(xInterp, p5),
cubicInterp(xInterp, p6),
cubicInterp(xInterp, p7)};
const T z2Points[] = {cubicInterp(xInterp, p8),
cubicInterp(xInterp, p9),
cubicInterp(xInterp, p10),
cubicInterp(xInterp, p11)};
const T z3Points[] = {cubicInterp(xInterp, p12),
cubicInterp(xInterp, p13),
cubicInterp(xInterp, p14),
cubicInterp(xInterp, p15)};
const T finalPoints[] = {cubicInterp(yInterp, z0Points),
cubicInterp(yInterp, z1Points),
cubicInterp(yInterp, z2Points),
cubicInterp(yInterp, z3Points)};
return cubicInterp(zInterp, finalPoints);
}
inline Vec3 interpolCubicMAC(const Vec3 *data, const Vec3i &size, const int Z, const Vec3 &pos)
{
// warning - not yet optimized...
Real vx = interpolCubic<Vec3>(data, size, Z, pos + Vec3(0.5, 0, 0))[0];
Real vy = interpolCubic<Vec3>(data, size, Z, pos + Vec3(0, 0.5, 0))[1];
Real vz = 0.f;
if (Z != 0)
vz = interpolCubic<Vec3>(data, size, Z, pos + Vec3(0, 0, 0.5))[2];
return Vec3(vx, vy, vz);
}
} // namespace Manta
#endif

View File

@@ -0,0 +1,394 @@
/******************************************************************************
*
* MantaFlow fluid solver framework
* Copyright 2015 Kiwon Um, Nils Thuerey
*
* This program is free software, distributed under the terms of the
* GNU General Public License (GPL)
* http://www.gnu.org/licenses
*
* Matrix (3x3) class
*
******************************************************************************/
#ifndef MATRIXBASE_H
#define MATRIXBASE_H
#include "vectorbase.h"
namespace Manta {
template<typename T> class Matrix3x3 {
public:
// NOTE: default is the identity matrix!
explicit Matrix3x3(const T &p00 = 1,
const T &p01 = 0,
const T &p02 = 0,
const T &p10 = 0,
const T &p11 = 1,
const T &p12 = 0,
const T &p20 = 0,
const T &p21 = 0,
const T &p22 = 1)
{
v[0][0] = p00;
v[0][1] = p01;
v[0][2] = p02;
v[1][0] = p10;
v[1][1] = p11;
v[1][2] = p12;
v[2][0] = p20;
v[2][1] = p21;
v[2][2] = p22;
}
explicit Matrix3x3(const Vector3D<T> &diag)
{
v[0][0] = diag.x;
v[0][1] = 0;
v[0][2] = 0;
v[1][0] = 0;
v[1][1] = diag.y;
v[1][2] = 0;
v[2][0] = 0;
v[2][1] = 0;
v[2][2] = diag.z;
}
Matrix3x3(const Vector3D<T> &c0, const Vector3D<T> &c1, const Vector3D<T> &c2)
{
v[0][0] = c0.x;
v[0][1] = c1.x;
v[0][2] = c2.x;
v[1][0] = c0.y;
v[1][1] = c1.y;
v[1][2] = c2.y;
v[2][0] = c0.z;
v[2][1] = c1.z;
v[2][2] = c2.z;
}
// assignment operators
Matrix3x3 &operator+=(const Matrix3x3 &m)
{
v00 += m.v00;
v01 += m.v01;
v02 += m.v02;
v10 += m.v10;
v11 += m.v11;
v12 += m.v12;
v20 += m.v20;
v21 += m.v21;
v22 += m.v22;
return *this;
}
Matrix3x3 &operator-=(const Matrix3x3 &m)
{
v00 -= m.v00;
v01 -= m.v01;
v02 -= m.v02;
v10 -= m.v10;
v11 -= m.v11;
v12 -= m.v12;
v20 -= m.v20;
v21 -= m.v21;
v22 -= m.v22;
return *this;
}
Matrix3x3 &operator*=(const T s)
{
v00 *= s;
v01 *= s;
v02 *= s;
v10 *= s;
v11 *= s;
v12 *= s;
v20 *= s;
v21 *= s;
v22 *= s;
return *this;
}
Matrix3x3 &operator/=(const T s)
{
v00 /= s;
v01 /= s;
v02 /= s;
v10 /= s;
v11 /= s;
v12 /= s;
v20 /= s;
v21 /= s;
v22 /= s;
return *this;
}
// binary operators
Matrix3x3 operator+(const Matrix3x3 &m) const
{
return Matrix3x3(*this) += m;
}
Matrix3x3 operator-(const Matrix3x3 &m) const
{
return Matrix3x3(*this) -= m;
}
Matrix3x3 operator*(const Matrix3x3 &m) const
{
return Matrix3x3(v00 * m.v00 + v01 * m.v10 + v02 * m.v20,
v00 * m.v01 + v01 * m.v11 + v02 * m.v21,
v00 * m.v02 + v01 * m.v12 + v02 * m.v22,
v10 * m.v00 + v11 * m.v10 + v12 * m.v20,
v10 * m.v01 + v11 * m.v11 + v12 * m.v21,
v10 * m.v02 + v11 * m.v12 + v12 * m.v22,
v20 * m.v00 + v21 * m.v10 + v22 * m.v20,
v20 * m.v01 + v21 * m.v11 + v22 * m.v21,
v20 * m.v02 + v21 * m.v12 + v22 * m.v22);
}
Matrix3x3 operator*(const T s) const
{
return Matrix3x3(*this) *= s;
}
Vector3D<T> operator*(const Vector3D<T> &v) const
{
return Vector3D<T>(v00 * v.x + v01 * v.y + v02 * v.z,
v10 * v.x + v11 * v.y + v12 * v.z,
v20 * v.x + v21 * v.y + v22 * v.z);
}
Vector3D<T> transposedMul(const Vector3D<T> &v) const
{
// M^T*v
return Vector3D<T>(v00 * v.x + v10 * v.y + v20 * v.z,
v01 * v.x + v11 * v.y + v21 * v.z,
v02 * v.x + v12 * v.y + v22 * v.z);
}
Matrix3x3 transposedMul(const Matrix3x3 &m) const
{
// M^T*M
return Matrix3x3(v00 * m.v00 + v10 * m.v10 + v20 * m.v20,
v00 * m.v01 + v10 * m.v11 + v20 * m.v21,
v00 * m.v02 + v10 * m.v12 + v20 * m.v22,
v01 * m.v00 + v11 * m.v10 + v21 * m.v20,
v01 * m.v01 + v11 * m.v11 + v21 * m.v21,
v01 * m.v02 + v11 * m.v12 + v21 * m.v22,
v02 * m.v00 + v12 * m.v10 + v22 * m.v20,
v02 * m.v01 + v12 * m.v11 + v22 * m.v21,
v02 * m.v02 + v12 * m.v12 + v22 * m.v22);
}
Matrix3x3 mulTranspose(const Matrix3x3 &m) const
{
// M*m^T
return Matrix3x3(v00 * m.v00 + v01 * m.v01 + v02 * m.v02,
v00 * m.v10 + v01 * m.v11 + v02 * m.v12,
v00 * m.v20 + v01 * m.v21 + v02 * m.v22,
v10 * m.v00 + v11 * m.v01 + v12 * m.v02,
v10 * m.v10 + v11 * m.v11 + v12 * m.v12,
v10 * m.v20 + v11 * m.v21 + v12 * m.v22,
v20 * m.v00 + v21 * m.v01 + v22 * m.v02,
v20 * m.v10 + v21 * m.v11 + v22 * m.v12,
v20 * m.v20 + v21 * m.v21 + v22 * m.v22);
}
bool operator==(const Matrix3x3 &m) const
{
return (v00 == m.v00 && v01 == m.v01 && v02 == m.v02 && v10 == m.v10 && v11 == m.v11 &&
v12 == m.v12 && v20 == m.v20 && v21 == m.v21 && v22 == m.v22);
}
const T &operator()(const int r, const int c) const
{
return v[r][c];
}
T &operator()(const int r, const int c)
{
return const_cast<T &>(const_cast<const Matrix3x3 &>(*this)(r, c));
}
T trace() const
{
return v00 + v11 + v22;
}
T sumSqr() const
{
return (v00 * v00 + v01 * v01 + v02 * v02 + v10 * v10 + v11 * v11 + v12 * v12 + v20 * v20 +
v21 * v21 + v22 * v22);
}
Real determinant() const
{
return (v00 * v11 * v22 - v00 * v12 * v21 + v01 * v12 * v20 - v01 * v10 * v22 +
v02 * v10 * v21 - v02 * v11 * v20);
}
Matrix3x3 &transpose()
{
return *this = transposed();
}
Matrix3x3 transposed() const
{
return Matrix3x3(v00, v10, v20, v01, v11, v21, v02, v12, v22);
}
Matrix3x3 &invert()
{
return *this = inverse();
}
Matrix3x3 inverse() const
{
const Real det = determinant(); // FIXME: assert(det);
const Real idet = 1e0 / det;
return Matrix3x3(idet * (v11 * v22 - v12 * v21),
idet * (v02 * v21 - v01 * v22),
idet * (v01 * v12 - v02 * v11),
idet * (v12 * v20 - v10 * v22),
idet * (v00 * v22 - v02 * v20),
idet * (v02 * v10 - v00 * v12),
idet * (v10 * v21 - v11 * v20),
idet * (v01 * v20 - v00 * v21),
idet * (v00 * v11 - v01 * v10));
}
bool getInverse(Matrix3x3 &inv) const
{
const Real det = determinant();
if (det == 0e0)
return false; // FIXME: is it likely to happen the floating error?
const Real idet = 1e0 / det;
inv.v00 = idet * (v11 * v22 - v12 * v21);
inv.v01 = idet * (v02 * v21 - v01 * v22);
inv.v02 = idet * (v01 * v12 - v02 * v11);
inv.v10 = idet * (v12 * v20 - v10 * v22);
inv.v11 = idet * (v00 * v22 - v02 * v20);
inv.v12 = idet * (v02 * v10 - v00 * v12);
inv.v20 = idet * (v10 * v21 - v11 * v20);
inv.v21 = idet * (v01 * v20 - v00 * v21);
inv.v22 = idet * (v00 * v11 - v01 * v10);
return true;
}
Real normOne() const
{
// the maximum absolute column sum of the matrix
return max(std::fabs(v00) + std::fabs(v10) + std::fabs(v20),
std::fabs(v01) + std::fabs(v11) + std::fabs(v21),
std::fabs(v02) + std::fabs(v12) + std::fabs(v22));
}
Real normInf() const
{
// the maximum absolute row sum of the matrix
return max(std::fabs(v00) + std::fabs(v01) + std::fabs(v02),
std::fabs(v10) + std::fabs(v11) + std::fabs(v12),
std::fabs(v20) + std::fabs(v21) + std::fabs(v22));
}
Vector3D<T> eigenvalues() const
{
Vector3D<T> eigen;
const Real b = -v00 - v11 - v22;
const Real c = v00 * (v11 + v22) + v11 * v22 - v12 * v21 - v01 * v10 - v02 * v20;
Real d = -v00 * (v11 * v22 - v12 * v21) - v20 * (v01 * v12 - v11 * v02) -
v10 * (v02 * v21 - v22 * v01);
const Real f = (3.0 * c - b * b) / 3.0;
const Real g = (2.0 * b * b * b - 9.0 * b * c + 27.0 * d) / 27.0;
const Real h = g * g / 4.0 + f * f * f / 27.0;
Real sign;
if (h > 0) {
Real r = -g / 2.0 + std::sqrt(h);
if (r < 0) {
r = -r;
sign = -1.0;
}
else
sign = 1.0;
Real s = sign * std::pow(r, 1.0 / 3.0);
Real t = -g / 2.0 - std::sqrt(h);
if (t < 0) {
t = -t;
sign = -1.0;
}
else
sign = 1.0;
Real u = sign * std::pow(t, 1.0 / 3.0);
eigen[0] = (s + u) - b / 3.0;
eigen[1] = eigen[2] = 0;
}
else if (h == 0) {
if (d < 0) {
d = -d;
sign = -1.0;
}
sign = 1.0;
eigen[0] = -1.0 * sign * std::pow(d, 1.0 / 3.0);
eigen[1] = eigen[2] = 0;
}
else {
const Real i = std::sqrt(g * g / 4.0 - h);
const Real j = std::pow(i, 1.0 / 3.0);
const Real k = std::acos(-g / (2.0 * i));
const Real l = -j;
const Real m = std::cos(k / 3.0);
const Real n = std::sqrt(3.0) * std::sin(k / 3.0);
const Real p = -b / 3.0;
eigen[0] = 2e0 * j * m + p;
eigen[1] = l * (m + n) + p;
eigen[2] = l * (m - n) + p;
}
return eigen;
}
static Matrix3x3 I()
{
return Matrix3x3(1, 0, 0, 0, 1, 0, 0, 0, 1);
}
#ifdef _WIN32
# pragma warning(disable : 4201)
#endif
union {
struct {
T v00, v01, v02, v10, v11, v12, v20, v21, v22;
};
T v[3][3];
T v1[9];
};
#ifdef _WIN32
# pragma warning(default : 4201)
#endif
};
template<typename T1, typename T> inline Matrix3x3<T> operator*(const T1 s, const Matrix3x3<T> &m)
{
return m * static_cast<T>(s);
}
template<typename T> inline Matrix3x3<T> crossProductMatrix(const Vector3D<T> &v)
{
return Matrix3x3<T>(0, -v.z, v.y, v.z, 0, -v.x, -v.y, v.x, 0);
}
template<typename T> inline Matrix3x3<T> outerProduct(const Vector3D<T> &a, const Vector3D<T> &b)
{
return Matrix3x3<T>(a.x * b.x,
a.x * b.y,
a.x * b.z,
a.y * b.x,
a.y * b.y,
a.y * b.z,
a.z * b.x,
a.z * b.y,
a.z * b.z);
}
typedef Matrix3x3<Real> Matrix3x3f;
} // namespace Manta
#endif /* MATRIXBASE_H */

View File

@@ -0,0 +1,308 @@
/******************************************************************************
*
* 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
*
* Marching cubes lookup indices
*
******************************************************************************/
#ifndef _MCUBES_H_
#define _MCUBES_H_
static const int mcEdges[24] = {0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6,
6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7};
static const int cubieOffsetX[8] = {0, 1, 1, 0, 0, 1, 1, 0};
static const int cubieOffsetY[8] = {0, 0, 1, 1, 0, 0, 1, 1};
static const int cubieOffsetZ[8] = {0, 0, 0, 0, 1, 1, 1, 1};
/* which edges are needed ? */
/* cf. http://astronomy.swin.edu.au/~pbourke/modelling/polygonise/ */
static const short mcEdgeTable[256] = {
0x0, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a,
0xd03, 0xe09, 0xf00, 0x190, 0x99, 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, 0x99c, 0x895,
0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90, 0x230, 0x339, 0x33, 0x13a, 0x636, 0x73f, 0x435,
0x53c, 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30, 0x3a0, 0x2a9, 0x1a3, 0xaa,
0x7a6, 0x6af, 0x5a5, 0x4ac, 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0, 0x460,
0x569, 0x663, 0x76a, 0x66, 0x16f, 0x265, 0x36c, 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963,
0xa69, 0xb60, 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff, 0x3f5, 0x2fc, 0xdfc, 0xcf5, 0xfff,
0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0, 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55, 0x15c,
0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950, 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6,
0x2cf, 0x1c5, 0xcc, 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0, 0x8c0, 0x9c9,
0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, 0xcc, 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9,
0x7c0, 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, 0x15c, 0x55, 0x35f, 0x256,
0x55a, 0x453, 0x759, 0x650, 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, 0x2fc,
0x3f5, 0xff, 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0, 0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f,
0xd65, 0xc6c, 0x36c, 0x265, 0x16f, 0x66, 0x76a, 0x663, 0x569, 0x460, 0xca0, 0xda9, 0xea3,
0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, 0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa, 0x1a3, 0x2a9, 0x3a0,
0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, 0x53c, 0x435, 0x73f, 0x636, 0x13a,
0x33, 0x339, 0x230, 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, 0x69c, 0x795,
0x49f, 0x596, 0x29a, 0x393, 0x99, 0x190, 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905,
0x80c, 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0};
/* triangles for the 256 intersection possibilities */
/* cf. http://astronomy.swin.edu.au/~pbourke/modelling/polygonise/ */
static const short mcTriTable[256][16] = {
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1},
{3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1},
{3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1},
{3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1},
{9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1},
{9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
{2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1},
{8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1},
{9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
{4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1},
{3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1},
{1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1},
{4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1},
{4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1},
{9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
{5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1},
{2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1},
{9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
{0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
{2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1},
{10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1},
{4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1},
{5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1},
{5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1},
{9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1},
{0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1},
{1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1},
{10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1},
{8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1},
{2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1},
{7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1},
{9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1},
{2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1},
{11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1},
{9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1},
{5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1},
{11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1},
{11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
{1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1},
{9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1},
{5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1},
{2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
{0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
{5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1},
{6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1},
{3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1},
{6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1},
{5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1},
{1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
{10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1},
{6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1},
{8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1},
{7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1},
{3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
{5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1},
{0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1},
{9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1},
{8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1},
{5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1},
{0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1},
{6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1},
{10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1},
{10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1},
{8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1},
{1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1},
{3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1},
{0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1},
{10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1},
{3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1},
{6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1},
{9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1},
{8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1},
{3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1},
{6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1},
{0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1},
{10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1},
{10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1},
{2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1},
{7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1},
{7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1},
{2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1},
{1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1},
{11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1},
{8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1},
{0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1},
{7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
{10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
{2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
{6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1},
{7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1},
{2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1},
{1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1},
{10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1},
{10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1},
{0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1},
{7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1},
{6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1},
{8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1},
{9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1},
{6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1},
{4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1},
{10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1},
{8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1},
{0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1},
{1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1},
{8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1},
{10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1},
{4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1},
{10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
{5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
{11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1},
{9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
{6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1},
{7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1},
{3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1},
{7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1},
{9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1},
{3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1},
{6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1},
{9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1},
{1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1},
{4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1},
{7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1},
{6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1},
{3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1},
{0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1},
{6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1},
{0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1},
{11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1},
{6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1},
{5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1},
{9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1},
{1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1},
{1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1},
{10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1},
{0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1},
{5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1},
{10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1},
{11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1},
{9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1},
{7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1},
{2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1},
{8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1},
{9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1},
{9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1},
{1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1},
{9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1},
{9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1},
{5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1},
{0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1},
{10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1},
{2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1},
{0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1},
{0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1},
{9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1},
{5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1},
{3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1},
{5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1},
{8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1},
{0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1},
{9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1},
{1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1},
{3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1},
{4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1},
{9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1},
{11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1},
{11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1},
{2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1},
{9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1},
{3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1},
{1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1},
{4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1},
{4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1},
{0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1},
{3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1},
{3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1},
{0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1},
{9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1},
{1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}};
#endif

View File

@@ -0,0 +1,103 @@
/******************************************************************************
*
* 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
*
* Basic quaternion class
*
******************************************************************************/
#ifndef _QUATERNION_H
#define _QUATERNION_H
#include "vectorbase.h"
namespace Manta {
//! Very basic quaternion class
class Quaternion {
public:
//! default constructor
Quaternion() : x(0), y(0), z(0), w(0)
{
}
//! copy constructor
Quaternion(const Quaternion &q) : x(q.x), y(q.y), z(q.z), w(q.w)
{
}
//! construct a quaternion from members
Quaternion(Real _x, Real _y, Real _z, Real _w) : x(_x), y(_y), z(_z), w(_w)
{
}
//! construct a quaternion from imag/real parts
Quaternion(Vec3 i, Real r) : x(i.x), y(i.y), z(i.z), w(r)
{
}
//! Assign operator
inline Quaternion &operator=(const Quaternion &q)
{
x = q.x;
y = q.y;
z = q.z;
w = q.w;
return *this;
}
//! Assign multiplication operator
inline Quaternion &operator*=(const Real a)
{
x *= a;
y *= a;
z *= a;
w *= a;
return *this;
}
//! return inverse quaternion
inline Quaternion inverse() const
{
Real mag = 1.0 / (x * x + y * y + z * z + w * w);
return Quaternion(-x * mag, -y * mag, -z * mag, w * mag);
}
//! imaginary part accessor
inline Vec3 imag()
{
return Vec3(x, y, z);
}
// imaginary part
Real x;
Real y;
Real z;
// real part
Real w;
};
//! Multiplication operator
inline Quaternion operator*(const Quaternion &q1, const Quaternion &q2)
{
return Quaternion(q2.w * q1.x + q2.x * q1.w + q2.y * q1.z - q2.z * q1.y,
q2.w * q1.y + q2.y * q1.w + q2.z * q1.x - q2.x * q1.z,
q2.w * q1.z + q2.z * q1.w + q2.x * q1.y - q2.y * q1.x,
q2.w * q1.w - q2.x * q1.x - q2.y * q1.y - q2.z * q1.z);
}
//! Multiplication operator
inline Quaternion operator*(const Quaternion &q, const Real a)
{
return Quaternion(q.x * a, q.y * a, q.z * a, q.w * a);
}
} // namespace Manta
#endif

View File

@@ -0,0 +1,442 @@
/******************************************************************************
*
* 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
*
* Random numbers
*
* Based on an example by Makoto Matsumoto, Takuji Nishimura, Shawn Cokus, and Richard J. Wagner
*
******************************************************************************/
#ifndef _RANDOMSTREAM_H
#define _RANDOMSTREAM_H
#include <iostream>
#include <stdio.h>
#include <time.h>
#include "vectorbase.h"
namespace Manta {
class MTRand {
// Data
public:
typedef unsigned long uint32; // unsigned integer type, at least 32 bits
static constexpr int N = 624; // length of state vector
static constexpr int SAVE = N + 1; // length of array for save()
protected:
static constexpr int M = 397; // period parameter
uint32 state[N]; // internal state
uint32 *pNext; // next value to get from state
int left; // number of values left before reload needed
// Methods
public:
MTRand(const uint32 &oneSeed); // initialize with a simple uint32
MTRand(uint32 *const bigSeed, uint32 const seedLength = N); // or an array
MTRand(); // auto-initialize with /dev/urandom or time() and clock()
// Do NOT use for CRYPTOGRAPHY without securely hashing several returned
// values together, otherwise the generator state can be learned after
// reading 624 consecutive values.
// Access to 32-bit random numbers
double rand(); // real number in [0,1]
double rand(const double &n); // real number in [0,n]
double randExc(); // real number in [0,1)
double randExc(const double &n); // real number in [0,n)
double randDblExc(); // real number in (0,1)
double randDblExc(const double &n); // real number in (0,n)
uint32 randInt(); // integer in [0,2^32-1]
uint32 randInt(const uint32 &n); // integer in [0,n] for n < 2^32
double operator()()
{
return rand();
} // same as rand()
// Access to 53-bit random numbers (capacity of IEEE double precision)
double rand53(); // real number in [0,1)
// Access to nonuniform random number distributions
double randNorm(const double &mean = 0.0, const double &variance = 1.0);
// Re-seeding functions with same behavior as initializers
void seed(const uint32 oneSeed);
void seed(uint32 *const bigSeed, const uint32 seedLength = N);
void seed();
// Saving and loading generator state
void save(uint32 *saveArray) const; // to array of size SAVE
void load(uint32 *const loadArray); // from such array
friend std::ostream &operator<<(std::ostream &os, const MTRand &mtrand);
friend std::istream &operator>>(std::istream &is, MTRand &mtrand);
protected:
void initialize(const uint32 oneSeed);
void reload();
uint32 hiBit(const uint32 &u) const
{
return u & 0x80000000UL;
}
uint32 loBit(const uint32 &u) const
{
return u & 0x00000001UL;
}
uint32 loBits(const uint32 &u) const
{
return u & 0x7fffffffUL;
}
uint32 mixBits(const uint32 &u, const uint32 &v) const
{
return hiBit(u) | loBits(v);
}
uint32 twist(const uint32 &m, const uint32 &s0, const uint32 &s1) const
{
return m ^ (mixBits(s0, s1) >> 1) ^ (-loBit(s1) & 0x9908b0dfUL);
}
static uint32 hash(time_t t, clock_t c);
};
inline MTRand::MTRand(const uint32 &oneSeed)
{
seed(oneSeed);
}
inline MTRand::MTRand(uint32 *const bigSeed, const uint32 seedLength)
{
seed(bigSeed, seedLength);
}
inline MTRand::MTRand()
{
seed();
}
inline double MTRand::rand()
{
return double(randInt()) * (1.0 / 4294967295.0);
}
inline double MTRand::rand(const double &n)
{
return rand() * n;
}
inline double MTRand::randExc()
{
return double(randInt()) * (1.0 / 4294967296.0);
}
inline double MTRand::randExc(const double &n)
{
return randExc() * n;
}
inline double MTRand::randDblExc()
{
return (double(randInt()) + 0.5) * (1.0 / 4294967296.0);
}
inline double MTRand::randDblExc(const double &n)
{
return randDblExc() * n;
}
inline double MTRand::rand53()
{
uint32 a = randInt() >> 5, b = randInt() >> 6;
return (a * 67108864.0 + b) * (1.0 / 9007199254740992.0); // by Isaku Wada
}
inline double MTRand::randNorm(const double &mean, const double &variance)
{
// Return a real number from a normal (Gaussian) distribution with given
// mean and variance by Box-Muller method
double r = sqrt(-2.0 * log(1.0 - randDblExc())) * variance;
double phi = 2.0 * 3.14159265358979323846264338328 * randExc();
return mean + r * cos(phi);
}
inline MTRand::uint32 MTRand::randInt()
{
// Pull a 32-bit integer from the generator state
// Every other access function simply transforms the numbers extracted here
if (left == 0)
reload();
--left;
uint32 s1;
s1 = *pNext++;
s1 ^= (s1 >> 11);
s1 ^= (s1 << 7) & 0x9d2c5680UL;
s1 ^= (s1 << 15) & 0xefc60000UL;
return (s1 ^ (s1 >> 18));
}
inline MTRand::uint32 MTRand::randInt(const uint32 &n)
{
// Find which bits are used in n
// Optimized by Magnus Jonsson (magnus@smartelectronix.com)
uint32 used = n;
used |= used >> 1;
used |= used >> 2;
used |= used >> 4;
used |= used >> 8;
used |= used >> 16;
// Draw numbers until one is found in [0,n]
uint32 i;
do
i = randInt() & used; // toss unused bits to shorten search
while (i > n);
return i;
}
inline void MTRand::seed(const uint32 oneSeed)
{
// Seed the generator with a simple uint32
initialize(oneSeed);
reload();
}
inline void MTRand::seed(uint32 *const bigSeed, const uint32 seedLength)
{
// Seed the generator with an array of uint32's
// There are 2^19937-1 possible initial states. This function allows
// all of those to be accessed by providing at least 19937 bits (with a
// default seed length of N = 624 uint32's). Any bits above the lower 32
// in each element are discarded.
// Just call seed() if you want to get array from /dev/urandom
initialize(19650218UL);
const unsigned int Nenum = N;
int i = 1;
uint32 j = 0;
int k = (Nenum > seedLength ? Nenum : seedLength);
for (; k; --k) {
state[i] = state[i] ^ ((state[i - 1] ^ (state[i - 1] >> 30)) * 1664525UL);
state[i] += (bigSeed[j] & 0xffffffffUL) + j;
state[i] &= 0xffffffffUL;
++i;
++j;
if (i >= N) {
state[0] = state[N - 1];
i = 1;
}
if (j >= seedLength)
j = 0;
}
for (k = N - 1; k; --k) {
state[i] = state[i] ^ ((state[i - 1] ^ (state[i - 1] >> 30)) * 1566083941UL);
state[i] -= i;
state[i] &= 0xffffffffUL;
++i;
if (i >= N) {
state[0] = state[N - 1];
i = 1;
}
}
state[0] = 0x80000000UL; // MSB is 1, assuring non-zero initial array
reload();
}
inline void MTRand::seed()
{
// Seed the generator with an array from /dev/urandom if available
// Otherwise use a hash of time() and clock() values
// First try getting an array from /dev/urandom
FILE *urandom = fopen("/dev/urandom", "rb");
if (urandom) {
uint32 bigSeed[N];
uint32 *s = bigSeed;
int i = N;
bool success = true;
while (success && i--)
success = fread(s++, sizeof(uint32), 1, urandom);
fclose(urandom);
if (success) {
seed(bigSeed, N);
return;
}
}
// Was not successful, so use time() and clock() instead
seed(hash(time(nullptr), clock()));
}
inline void MTRand::initialize(const uint32 intseed)
{
// Initialize generator state with seed
// See Knuth TAOCP Vol 2, 3rd Ed, p.106 for multiplier.
// In previous versions, most significant bits (MSBs) of the seed affect
// only MSBs of the state array. Modified 9 Jan 2002 by Makoto Matsumoto.
uint32 *s = state;
uint32 *r = state;
int i = 1;
*s++ = intseed & 0xffffffffUL;
for (; i < N; ++i) {
*s++ = (1812433253UL * (*r ^ (*r >> 30)) + i) & 0xffffffffUL;
r++;
}
}
inline void MTRand::reload()
{
// Generate N new values in state
// Made clearer and faster by Matthew Bellew (matthew.bellew@home.com)
uint32 *p = state;
int i;
for (i = N - M; i--; ++p)
*p = twist(p[M], p[0], p[1]);
for (i = M; --i; ++p)
*p = twist(p[M - N], p[0], p[1]);
*p = twist(p[M - N], p[0], state[0]);
left = N, pNext = state;
}
inline MTRand::uint32 MTRand::hash(time_t t, clock_t c)
{
// Get a uint32 from t and c
// Better than uint32(x) in case x is floating point in [0,1]
// Based on code by Lawrence Kirby (fred@genesis.demon.co.uk)
static uint32 differ = 0; // guarantee time-based seeds will change
uint32 h1 = 0;
unsigned char *p = (unsigned char *)&t;
for (size_t i = 0; i < sizeof(t); ++i) {
h1 *= std::numeric_limits<unsigned char>::max() + 2U;
h1 += p[i];
}
uint32 h2 = 0;
p = (unsigned char *)&c;
for (size_t j = 0; j < sizeof(c); ++j) {
h2 *= std::numeric_limits<unsigned char>::max() + 2U;
h2 += p[j];
}
return (h1 + differ++) ^ h2;
}
inline void MTRand::save(uint32 *saveArray) const
{
uint32 *sa = saveArray;
const uint32 *s = state;
int i = N;
for (; i--; *sa++ = *s++) {
}
*sa = left;
}
inline void MTRand::load(uint32 *const loadArray)
{
uint32 *s = state;
uint32 *la = loadArray;
int i = N;
for (; i--; *s++ = *la++) {
}
left = *la;
pNext = &state[N - left];
}
inline std::ostream &operator<<(std::ostream &os, const MTRand &mtrand)
{
const MTRand::uint32 *s = mtrand.state;
int i = mtrand.N;
for (; i--; os << *s++ << "\t") {
}
return os << mtrand.left;
}
inline std::istream &operator>>(std::istream &is, MTRand &mtrand)
{
MTRand::uint32 *s = mtrand.state;
int i = mtrand.N;
for (; i--; is >> *s++) {
}
is >> mtrand.left;
mtrand.pNext = &mtrand.state[mtrand.N - mtrand.left];
return is;
}
// simple interface to mersenne twister
class RandomStream {
public:
inline RandomStream(long seed) : mtr(seed){};
~RandomStream()
{
}
/*! get a random number from the stream */
inline float getRandNorm(float mean, float var)
{
return mtr.randNorm(mean, var);
};
#if FLOATINGPOINT_PRECISION == 1
inline Real getReal()
{
return getFloat();
}
inline Real getReal(float min, float max)
{
return getFloat(min, max);
}
#else
inline Real getReal()
{
return getDouble();
}
inline Real getReal(double min, double max)
{
return getDouble(min, max);
}
#endif
inline Vec3 getVec3()
{
Real a = getReal(), b = getReal(), c = getReal();
return Vec3(a, b, c);
}
inline Vec3 getVec3Norm()
{
Vec3 a = getVec3();
normalize(a);
return a;
}
private:
MTRand mtr;
inline double getDouble(void)
{
return mtr.rand();
};
inline float getFloat(void)
{
return (float)mtr.rand();
};
inline double getDouble(double min, double max)
{
return mtr.rand(max - min) + min;
};
inline float getFloat(float min, float max)
{
return (float)(mtr.rand(max - min) + min);
};
};
} // namespace Manta
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,312 @@
/******************************************************************************
*
* MantaFlow fluid solver framework
* Copyright 2014 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
*
* Simple image IO
*
******************************************************************************/
#include "vectorbase.h"
#include "simpleimage.h"
namespace Manta {
// write rectangle to ppm
bool SimpleImage::writePpm(
std::string filename, int minx, int miny, int maxx, int maxy, bool invertXY)
{
int w = maxx - minx;
int h = maxy - miny;
if (w <= 0 || h <= 0 || w > mSize[0] || h > mSize[1]) {
errMsg("SimpleImage::WritePPM Invalid rect: w="
<< w << ", h=" << h << ", size=" << mSize[0] << "," << mSize[1] << " min/max: " << minx
<< "," << miny << " to " << maxx << "," << maxy << ", resetting... ");
minx = miny = 0;
maxx = mSize[0] - 1;
maxy = mSize[1] - 1;
w = mSize[0] - 1;
h = mSize[1] - 1;
}
FILE *fp = fopen(filename.c_str(), "wb");
if (fp == nullptr) {
errMsg("SimpleImage::WritePPM Unable to open '" << filename << "' for writing");
return false;
}
fprintf(fp, "P6\n%d %d\n255\n", w, h);
int pixCnt = 0;
for (int j = maxy - 1; j >= miny; j--)
for (int i = minx; i < maxx; i++) {
unsigned char col[3];
for (int l = 0; l < 3; l++) {
float val;
if (invertXY)
val = (float)get(j, i)[l];
else
val = (float)get(i, j)[l];
val = clamp(val, (float)0., (float)1.);
col[l] = (unsigned char)(255. * val);
}
// col[1] = col[2] = col[0];
// if (fwrite(col,1,3, fp) != 3) errMsg("SimpleImage::writePpm fwrite failed");
fwrite(col, 1, 3, fp);
pixCnt++;
// fprintf(stderr,"%d %d %d \n",col[0],i,j);
}
fclose(fp);
// debMsg("WritePPM Wrote '"<<filename<<"', region="<<minx<<","<<miny<<" to
// "<<maxx<<","<<maxy<<"; "<<pixCnt, 1);
return true;
}
bool SimpleImage::writePpm(std::string filename)
{
return writePpm(filename, 0, 0, getSize()[0], getSize()[1]);
}
// read in a ppm file, and init the image accordingly
bool SimpleImage::initFromPpm(std::string filename)
{
// maximum length of a line of text
const int MAXLINE = 1024;
int filetype = 0;
enum { PGM, PPM }; // possible file types
FILE *fp;
char line[MAXLINE];
int size, rowsize;
// Read in file type
fp = fopen(filename.c_str(), "rb");
if (!fp) {
if (mAbortOnError)
debMsg("SimpleImage Error - unable to open file '" << filename << "' for reading", 1);
return 0;
}
// 1st line: PPM or PGM
if (fgets(line, MAXLINE, fp) == nullptr) {
if (mAbortOnError)
debMsg("SimpleImage::initFromPpm fgets failed", 1);
return 0;
}
if (line[1] == '5')
filetype = PGM;
else if (line[1] == '6')
filetype = PPM;
else {
if (mAbortOnError)
debMsg("SimpleImage Error: need PPM or PGM file as input!", 1);
return 0;
}
// Read in width and height, & allocate space
// 2nd line: width height
if (fgets(line, MAXLINE, fp) == nullptr) {
if (mAbortOnError)
errMsg("SimpleImage::initFromPpm fgets failed");
return 0;
}
int windW = 0, windH = 0; // size of the window on the screen
int intsFound = sscanf(line, "%d %d", &windW, &windH);
if (intsFound == 1) {
// only X found, search on next line as well for Y...
if (sscanf(line, "%d", &windH) != 1) {
if (mAbortOnError)
errMsg("initFromPpm Ppm dimensions not found!" << windW << "," << windH);
return 0;
}
else {
// ok, found 2 lines
// debMsg("initFromPpm Ppm dimensions found!"<<windW<<","<<windH, 1);
}
}
else if (intsFound == 2) {
// ok!
}
else {
if (mAbortOnError)
errMsg("initFromPpm Ppm dimensions not found at all!" << windW << "," << windH);
return 0;
}
if (filetype == PGM) {
size = windH * windW; // greymap: 1 byte per pixel
rowsize = windW;
}
else {
// filetype == PPM
size = windH * windW * 3; // pixmap: 3 bytes per pixel
rowsize = windW * 3;
}
// Read in maximum value (ignore) , could be scanned with sscanf as well, but this should be
// 255... 3rd line
if (fgets(line, MAXLINE, fp) == nullptr) {
if (mAbortOnError)
errMsg("SimpleImage::initFromPpm fgets failed");
return 0;
}
unsigned char *pic = new unsigned char[size]; // (GLubyte *)malloc (size);
// Read in the pixel array row-by-row: 1st row = top scanline */
unsigned char *ptr = nullptr;
ptr = &pic[(windH - 1) * rowsize];
for (int i = windH; i > 0; i--) {
assertMsg(fread((void *)ptr, 1, rowsize, fp) == rowsize,
"SimpleImage::initFromPpm couldn't read data");
ptr -= rowsize;
}
// init image
this->init(windW, windH);
if (filetype == PGM) {
// grayscale
for (int i = 0; i < windW; i++) {
for (int j = 0; j < windH; j++) {
double r = (double)pic[(j * windW + i) * 1 + 0] / 255.;
(*this)(i, j) = Vec3(r, r, r);
}
}
}
else {
// convert grid to RGB vec's
for (int i = 0; i < windW; i++) {
for (int j = 0; j < windH; j++) {
// return mpData[y*mSize[0]+x];
double r = (double)pic[(j * windW + i) * 3 + 0] / 255.;
double g = (double)pic[(j * windW + i) * 3 + 1] / 255.;
double b = (double)pic[(j * windW + i) * 3 + 2] / 255.;
//(*this)(i,j) = Vec3(r,g,b);
// RGB values have to be rotated to get the right colors!?
// this might also be an artifact of photoshop export...?
(*this)(i, j) = Vec3(g, b, r);
}
}
}
delete[] pic;
fclose(fp);
return 1;
}
// check index is valid
bool SimpleImage::indexIsValid(int i, int j)
{
if (i < 0)
return false;
if (j < 0)
return false;
if (i >= mSize[0])
return false;
if (j >= mSize[1])
return false;
return true;
}
}; // namespace Manta
//*****************************************************************************
#include "grid.h"
namespace Manta {
// simple shaded output , note requires grid functionality!
static void gridPrecompLight(const Grid<Real> &density, Grid<Real> &L, Vec3 light = Vec3(1, 1, 1))
{
FOR_IJK(density)
{
Vec3 n = getGradient(density, i, j, k) * -1.;
normalize(n);
Real d = dot(light, n);
L(i, j, k) = d;
}
}
// simple shading with pre-computed gradient
static inline void shadeCell(
Vec3 &dst, int shadeMode, Real src, Real light, int depthPos, Real depthInv)
{
switch (shadeMode) {
case 1: {
// surfaces
Vec3 ambient = Vec3(0.1, 0.1, 0.1);
Vec3 diffuse = Vec3(0.9, 0.9, 0.9);
Real alpha = src;
// different color for depth?
diffuse[0] *= ((Real)depthPos * depthInv) * 0.7 + 0.3;
diffuse[1] *= ((Real)depthPos * depthInv) * 0.7 + 0.3;
Vec3 col = ambient + diffuse * light;
// img( 0+i, j ) = (1.-alpha) * img( 0+i, j ) + alpha * col;
dst = (1. - alpha) * dst + alpha * col;
} break;
default: {
// volumetrics / smoke
dst += depthInv * Vec3(src, src, src);
} break;
}
}
//! helper to project a grid intro an image (used for ppm export and GUI displauy)
void projectImg(SimpleImage &img, const Grid<Real> &val, int shadeMode = 0, Real scale = 1.)
{
Vec3i s = val.getSize();
Vec3 si = Vec3(1. / (Real)s[0], 1. / (Real)s[1], 1. / (Real)s[2]);
// init image size
int imgSx = s[0];
if (val.is3D())
imgSx += s[2] + s[0]; // mult views in 3D
img.init(imgSx, std::max(s[0], std::max(s[1], s[2])));
// precompute lighting
Grid<Real> L(val);
gridPrecompLight(val, L, Vec3(1, 1, 1));
FOR_IJK(val)
{
Vec3i idx(i, j, k);
shadeCell(img(0 + i, j), shadeMode, val(idx), L(idx), k, si[2]);
}
if (val.is3D()) {
FOR_IJK(val)
{
Vec3i idx(i, j, k);
shadeCell(img(s[0] + k, j), shadeMode, val(idx), L(idx), i, si[0]);
}
FOR_IJK(val)
{
Vec3i idx(i, j, k);
shadeCell(img(s[0] + s[2] + i, k), shadeMode, val(idx), L(idx), j, si[1]);
}
} // 3d
img.mapRange(1. / scale);
}
}; // namespace Manta

View File

@@ -0,0 +1,205 @@
/******************************************************************************
*
* MantaFlow fluid solver framework
* Copyright 2014 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
*
* Simple image IO
*
******************************************************************************/
#ifndef MANTA_SIMPLEIMAGE_H
#define MANTA_SIMPLEIMAGE_H
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "manta.h"
#include "vectorbase.h"
namespace Manta {
//*****************************************************************************
// simple 2d image class
// template<class Scalar>
class SimpleImage {
public:
// cons/des
SimpleImage() : mSize(-1), mpData(nullptr), mAbortOnError(true){};
virtual ~SimpleImage()
{
if (mpData)
delete[] mpData;
};
//! set to constant
void reset(Real val = 0.)
{
const Vec3 v = Vec3(val);
for (int i = 0; i < mSize[0] * mSize[1]; i++)
mpData[i] = v;
}
//! init memory & reset to zero
void init(int x, int y)
{
mSize = Vec3i(x, y, 0);
mpData = new Vec3[x * y];
reset();
};
inline bool checkIndex(int x, int y)
{
if ((x < 0) || (y < 0) || (x > mSize[0] - 1) || (y > mSize[1] - 1)) {
errMsg("SimpleImage::operator() Invalid access to " << x << "," << y << ", size=" << mSize);
return false;
}
return true;
}
// access element
inline Vec3 &operator()(int x, int y)
{
DEBUG_ONLY(checkIndex(x, y));
return mpData[y * mSize[0] + x];
};
inline Vec3 &get(int x, int y)
{
return (*this)(x, y);
}
inline Vec3 &getMap(int x, int y, int z, int axis)
{
int i = x, j = y;
if (axis == 1)
j = z;
if (axis == 0) {
i = y;
j = z;
}
return get(i, j);
}
// output as string, debug
std::string toString()
{
std::ostringstream out;
for (int j = 0; j < mSize[1]; j++) {
for (int i = 0; i < mSize[0]; i++) {
// normal zyx order */
out << (*this)(i, j);
out << " ";
}
// if (format)
out << std::endl;
}
return out.str();
}
// multiply all values by f
void add(Vec3 f)
{
for (int j = 0; j < mSize[1]; j++)
for (int i = 0; i < mSize[0]; i++) {
get(i, j) += f;
}
}
// multiply all values by f
void multiply(Real f)
{
for (int j = 0; j < mSize[1]; j++)
for (int i = 0; i < mSize[0]; i++) {
get(i, j) *= f;
}
}
// map 0-f to 0-1 range, clamp
void mapRange(Real f)
{
for (int j = 0; j < mSize[1]; j++)
for (int i = 0; i < mSize[0]; i++) {
get(i, j) /= f;
for (int c = 0; c < 3; ++c)
get(i, j)[c] = clamp(get(i, j)[c], (Real)0., (Real)1.);
}
}
// normalize max values
void normalizeMax()
{
Real max = normSquare(get(0, 0));
for (int j = 0; j < mSize[1]; j++)
for (int i = 0; i < mSize[0]; i++) {
if (normSquare(get(i, j)) > max)
max = normSquare(get(i, j));
}
max = sqrt(max);
Real invMax = 1. / max;
for (int j = 0; j < mSize[1]; j++)
for (int i = 0; i < mSize[0]; i++) {
get(i, j) *= invMax;
}
};
// normalize min and max values
void normalizeMinMax()
{
Real max = normSquare(get(0, 0));
Real min = max;
for (int j = 0; j < mSize[1]; j++)
for (int i = 0; i < mSize[0]; i++) {
if (normSquare(get(i, j)) > max)
max = normSquare(get(i, j));
if (normSquare(get(i, j)) < min)
min = normSquare(get(i, j));
}
max = sqrt(max);
min = sqrt(min);
Real factor = 1. / (max - min);
for (int j = 0; j < mSize[1]; j++)
for (int i = 0; i < mSize[0]; i++) {
get(i, j) -= min;
get(i, j) *= factor;
}
};
void setAbortOnError(bool set)
{
mAbortOnError = set;
}
// ppm in/output
// write whole image
bool writePpm(std::string filename);
// write rectangle to ppm
bool writePpm(
std::string filename, int minx, int miny, int maxx, int maxy, bool invertXY = false);
// read in a ppm file, and init the image accordingly
bool initFromPpm(std::string filename);
// check index is valid
bool indexIsValid(int i, int j);
//! access
inline Vec3i getSize() const
{
return mSize;
}
protected:
//! size
Vec3i mSize;
//! data
Vec3 *mpData;
// make errors fatal, or continue?
bool mAbortOnError;
}; // SimpleImage
}; // namespace Manta
#endif

View File

@@ -0,0 +1,214 @@
/******************************************************************************
*
* 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
*
* Analytical solutions to some problems
* generated using MATLAB symbolic math ccode
*
******************************************************************************/
#ifndef _SOLVANA_H
#define _SOLVANA_H
//! solves the equation [e1 e2 e3; 1 1 1]*x = g using least squares
inline void SolveOverconstraint34(float e1x,
float e1y,
float e1z,
float e2x,
float e2y,
float e2z,
float e3x,
float e3y,
float e3z,
float g1,
float g2,
float g3,
float &x1,
float &x2,
float &x3)
{
float e1x2 = e1x * e1x, e1y2 = e1y * e1y, e1z2 = e1z * e1z;
float e2x2 = e2x * e2x, e2y2 = e2y * e2y, e2z2 = e2z * e2z;
float e3x2 = e3x * e3x, e3y2 = e3y * e3y, e3z2 = e3z * e3z;
float e1xy = e1x * e1y, e1xz = e1x * e1z, e1yz = e1y * e1z;
float e2xy = e2x * e2y, e2xz = e2x * e2z, e2yz = e2y * e2z;
float e3xy = e3x * e3y, e3xz = e3x * e3z, e3yz = e3y * e3z;
float e12x = e1x * e2x, e12y = e1y * e2y, e12z = e1z * e2z;
float e13x = e1x * e3x, e13y = e1y * e3y, e13z = e1z * e3z;
float e23x = e2x * e3x, e23y = e2y * e3y, e23z = e2z * e3z;
float t1543 = e3y2 * e2x2;
float t1544 = e3x2 * e2y2;
float t1545 = e3z2 * e2x2;
float t1546 = e3x2 * e2z2;
float t1547 = e3z2 * e2y2;
float t1548 = e3y2 * e2z2;
float t1549 = e2y2 * e1x2;
float t1550 = e2x2 * e1y2;
float t1551 = e2z2 * e1x2;
float t1552 = e2x2 * e1z2;
float t1553 = e2z2 * e1y2;
float t1554 = e2y2 * e1z2;
float t1555 = e3y2 * e1x2;
float t1556 = e3x2 * e1y2;
float t1557 = e3z2 * e1x2;
float t1558 = e3x2 * e1z2;
float t1559 = e3z2 * e1y2;
float t1560 = e3y2 * e1z2;
float t1561 = e3z2 * e2y2 * e1x2;
float t1562 = e3y2 * e2z2 * e1x2;
float t1563 = e3z2 * e2x2 * e1y2;
float t1564 = e3x2 * e2z2 * e1y2;
float t1565 = e3y2 * e2x2 * e1z2;
float t1566 = e3x2 * e2y2 * e1z2;
float t1567 = e1xy * e2x * e3y * 2.0;
float t1568 = e1xy * e2y * e3x * 2.0;
float t1569 = e1xz * e2x * e3z * 2.0;
float t1570 = e1xz * e2z * e3x * 2.0;
float t1571 = e1yz * e2y * e3z * 2.0;
float t1572 = e1yz * e2z * e3y * 2.0;
float t1573 = e1x * e2xy * e3y * 2.0;
float t1574 = e1y * e2xy * e3x * 2.0;
float t1575 = e1x * e2xz * e3z * 2.0;
float t1576 = e1z * e2xz * e3x * 2.0;
float t1577 = e1y * e2yz * e3z * 2.0;
float t1578 = e1z * e2yz * e3y * 2.0;
float t1579 = e1x * e2y * e3xy * 2.0;
float t1580 = e1y * e2x * e3xy * 2.0;
float t1581 = e1x * e2z * e3xz * 2.0;
float t1582 = e1z * e2x * e3xz * 2.0;
float t1583 = e1y * e2z * e3yz * 2.0;
float t1584 = e1z * e2y * e3yz * 2.0;
float t1585 = e1xy * e2xz * e3yz * 2.0;
float t1586 = e1xy * e2yz * e3xz * 2.0;
float t1587 = e1xz * e2xy * e3yz * 2.0;
float t1588 = e1xz * e2yz * e3xy * 2.0;
float t1589 = e1yz * e2xy * e3xz * 2.0;
float t1590 = e1yz * e2xz * e3xy * 2.0;
float t1596 = e12x * e3y2 * 2.0;
float t1597 = e13x * e2y2 * 2.0;
float t1598 = e23x * e1y2 * 2.0;
float t1599 = e12x * e3z2 * 2.0;
float t1600 = e13x * e2z2 * 2.0;
float t1601 = e12y * e3x2 * 2.0;
float t1602 = e13y * e2x2 * 2.0;
float t1603 = e23y * e1x2 * 2.0;
float t1604 = e23x * e1z2 * 2.0;
float t1605 = e12y * e3z2 * 2.0;
float t1606 = e13y * e2z2 * 2.0;
float t1607 = e12z * e3x2 * 2.0;
float t1608 = e13z * e2x2 * 2.0;
float t1609 = e23z * e1x2 * 2.0;
float t1610 = e23y * e1z2 * 2.0;
float t1611 = e12z * e3y2 * 2.0;
float t1612 = e13z * e2y2 * 2.0;
float t1613 = e23z * e1y2 * 2.0;
float t1614 = e1xy * e2xy * 2.0;
float t1615 = e1xz * e2xz * 2.0;
float t1616 = e1yz * e2yz * 2.0;
float t1617 = e1xy * e3xy * 2.0;
float t1618 = e1xz * e3xz * 2.0;
float t1619 = e1yz * e3yz * 2.0;
float t1620 = e2xy * e3xy * 2.0;
float t1621 = e2xz * e3xz * 2.0;
float t1622 = e2yz * e3yz * 2.0;
float t1623 = e1xy * e2xy * e3z2 * 2.0;
float t1624 = e1xz * e2xz * e3y2 * 2.0;
float t1625 = e1yz * e2yz * e3x2 * 2.0;
float t1626 = e1xy * e3xy * e2z2 * 2.0;
float t1627 = e1xz * e3xz * e2y2 * 2.0;
float t1628 = e1yz * e3yz * e2x2 * 2.0;
float t1629 = e2xy * e3xy * e1z2 * 2.0;
float t1630 = e2xz * e3xz * e1y2 * 2.0;
float t1631 = e2yz * e3yz * e1x2 * 2.0;
float t1591 = t1550 + t1551 + t1560 + t1543 + t1552 + t1561 + t1570 + t1544 + t1553 + t1562 +
t1571 + t1580 + t1545 + t1554 + t1563 + t1572 + t1581 + t1590 + t1546 + t1555 +
t1564 + t1573 + t1582 + t1547 + t1556 + t1565 + t1574 + t1583 + t1548 + t1557 +
t1566 + t1575 + t1584 + t1549 + t1558 + t1567 + t1576 + t1585 + t1559 + t1568 +
t1577 + t1586 + t1569 + t1578 + t1587 - t1596 + t1579 + t1588 - t1597 + t1589 -
t1598 - t1599 - t1600 - t1601 - t1610 - t1602 - t1611 - t1620 - t1603 - t1612 -
t1621 - t1630 - t1604 - t1613 - t1622 - t1631 - t1605 - t1614 - t1623 - t1606 -
t1615 - t1624 - t1607 - t1616 - t1625 - t1608 - t1617 - t1626 - t1609 - t1618 -
t1627 - t1619 - t1628 - t1629;
float t1592 = 1.0 / t1591;
float t1635 = e13x * e2y2;
float t1636 = e13x * e2z2;
float t1637 = e13y * e2x2;
float t1638 = e13y * e2z2;
float t1639 = e13z * e2x2;
float t1640 = e13z * e2y2;
float t1653 = e23x * 2.0;
float t1654 = e23y * 2.0;
float t1655 = e23z * 2.0;
float t1641 = e3x2 + e3z2 + e3y2 + e2y2 + t1543 + e2z2 + t1544 + e2x2 + t1545 + t1546 + t1547 +
t1548 - t1620 - t1621 - t1622 - t1653 - t1654 - t1655;
float t1642 = e12x * e3y2;
float t1643 = e12x * e3z2;
float t1644 = e12y * e3x2;
float t1645 = e12y * e3z2;
float t1646 = e12z * e3x2;
float t1647 = e12z * e3y2;
float t1656 = e1x * e2y * e3xy;
float t1657 = e1y * e2x * e3xy;
float t1658 = e1x * e2z * e3xz;
float t1659 = e1z * e2x * e3xz;
float t1660 = e1y * e2z * e3yz;
float t1661 = e1z * e2y * e3yz;
float t1648 = e3x2 + e3z2 + e3y2 - e13x - e13y - e13z + e12x - e23y + e12y + t1642 - e23z -
t1660 + e12z + t1643 - t1661 + t1644 + t1645 + t1646 + t1647 - t1656 - t1657 -
e23x - t1658 - t1659;
float t1679 = e1x * e2xy * e3y;
float t1680 = e1y * e2xy * e3x;
float t1681 = e1x * e2xz * e3z;
float t1682 = e1z * e2xz * e3x;
float t1683 = e1y * e2yz * e3z;
float t1684 = e1z * e2yz * e3y;
float t1652 = e2y2 + e2z2 + e2x2 + e13x + e13y + e13z + t1640 - e12x - e23y - e12y - e23z -
e12z + t1635 - t1680 + t1636 - t1681 + t1637 - t1682 + t1638 - t1683 + t1639 -
t1684 - e23x - t1679;
float t1662 = e23x * e1y2;
float t1663 = e23y * e1x2;
float t1664 = e23x * e1z2;
float t1665 = e23z * e1x2;
float t1666 = e23y * e1z2;
float t1667 = e23z * e1y2;
float t1670 = e1xy * e2x * e3y;
float t1671 = e1xy * e2y * e3x;
float t1672 = e1xz * e2x * e3z;
float t1673 = e1xz * e2z * e3x;
float t1674 = e1yz * e2y * e3z;
float t1675 = e1yz * e2z * e3y;
float t1668 = e1x2 + e1y2 + e1z2 - e13x - e13y - e13z - e12x + e23y - e12y + e23z - e12z -
t1670 + t1662 - t1671 + t1663 - t1672 + t1664 - t1673 + t1665 - t1674 + t1666 -
t1675 + e23x + t1667;
float t1676 = e13x * 2.0;
float t1677 = e13y * 2.0;
float t1678 = e13z * 2.0;
float t1669 = e3x2 + e3z2 + e3y2 + t1560 + e1x2 + t1555 + e1y2 + t1556 + e1z2 + t1557 + t1558 +
t1559 - t1617 - t1618 - t1619 - t1676 - t1677 - t1678;
float t1686 = e12x * 2.0;
float t1687 = e12y * 2.0;
float t1688 = e12z * 2.0;
float t1685 = t1550 + t1551 + e2y2 + t1552 + e2z2 + t1553 + e2x2 + t1554 + e1x2 + e1y2 + e1z2 +
t1549 - t1614 - t1615 - t1616 - t1686 - t1687 - t1688;
x1 = -g2 * (-e1y * t1592 * t1641 + e2y * t1592 * t1648 + e3y * t1592 * t1652) -
g3 * (-e1z * t1592 * t1641 + e2z * t1592 * t1648 + e3z * t1592 * t1652) -
g1 * (-e1x * t1592 * t1641 + e2x * t1592 * t1648 +
e3x * t1592 *
(e2y2 + e2z2 + e2x2 + e13x + e13y + e13z + t1640 + t1635 + t1636 + t1637 + t1638 +
t1639 - e12x - e12y - e12z - e23x - e23y - e23z - e1x * e2xy * e3y -
e1y * e2xy * e3x - e1x * e2xz * e3z - e1z * e2xz * e3x - e1y * e2yz * e3z -
e1z * e2yz * e3y));
x2 = -g1 * (e1x * t1592 * t1648 - e2x * t1592 * t1669 + e3x * t1592 * t1668) -
g2 * (e1y * t1592 * t1648 - e2y * t1592 * t1669 + e3y * t1592 * t1668) -
g3 * (e1z * t1592 * t1648 - e2z * t1592 * t1669 + e3z * t1592 * t1668);
x3 = -g1 * (e1x * t1592 * t1652 + e2x * t1592 * t1668 - e3x * t1592 * t1685) -
g2 * (e1y * t1592 * t1652 + e2y * t1592 * t1668 - e3y * t1592 * t1685) -
g3 * (e1z * t1592 * t1652 + e2z * t1592 * t1668 - e3z * t1592 * t1685);
}
#endif

View File

@@ -0,0 +1,50 @@
/******************************************************************************
*
* 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
*
* Basic vector class
*
******************************************************************************/
#include "vector4d.h"
using namespace std;
namespace Manta {
template<> const Vector4D<int> Vector4D<int>::Zero(0, 0, 0, 0);
template<> const Vector4D<float> Vector4D<float>::Zero(0.f, 0.f, 0.f, 0.f);
template<> const Vector4D<double> Vector4D<double>::Zero(0., 0., 0., 0.);
template<>
const Vector4D<float> Vector4D<float>::Invalid(numeric_limits<float>::quiet_NaN(),
numeric_limits<float>::quiet_NaN(),
numeric_limits<float>::quiet_NaN(),
numeric_limits<float>::quiet_NaN());
template<>
const Vector4D<double> Vector4D<double>::Invalid(numeric_limits<double>::quiet_NaN(),
numeric_limits<double>::quiet_NaN(),
numeric_limits<double>::quiet_NaN(),
numeric_limits<double>::quiet_NaN());
template<> bool Vector4D<float>::isValid() const
{
return !c_isnan(x) && !c_isnan(y) && !c_isnan(z) && !c_isnan(t);
}
template<> bool Vector4D<double>::isValid() const
{
return !c_isnan(x) && !c_isnan(y) && !c_isnan(z) && !c_isnan(t);
}
//! Specialization for readable ints
template<> std::string Vector4D<int>::toString() const
{
char buf[256];
snprintf(buf, 256, "[%d,%d,%d,%d]", (*this)[0], (*this)[1], (*this)[2], (*this)[3]);
return std::string(buf);
}
} // namespace Manta

View File

@@ -0,0 +1,543 @@
/******************************************************************************
*
* 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
*
* 4D vector class
*
******************************************************************************/
#ifndef _VECTOR4D_H
#define _VECTOR4D_H
#include "vectorbase.h"
namespace Manta {
//! Basic inlined vector class
template<class S> class Vector4D {
public:
//! Constructor
inline Vector4D() : x(0), y(0), z(0), t(0)
{
}
//! Copy-Constructor
inline Vector4D(const Vector4D<S> &v) : x(v.x), y(v.y), z(v.z), t(v.t)
{
}
//! Copy-Constructor
inline Vector4D(const float *v) : x((S)v[0]), y((S)v[1]), z((S)v[2]), t((S)v[3])
{
}
//! Copy-Constructor
inline Vector4D(const double *v) : x((S)v[0]), y((S)v[1]), z((S)v[2]), t((S)v[3])
{
}
//! Construct a vector from one S
inline Vector4D(S v) : x(v), y(v), z(v), t(v)
{
}
//! Construct a vector from three Ss
inline Vector4D(S vx, S vy, S vz, S vw) : x(vx), y(vy), z(vz), t(vw)
{
}
// Operators
//! Assignment operator
inline const Vector4D<S> &operator=(const Vector4D<S> &v)
{
x = v.x;
y = v.y;
z = v.z;
t = v.t;
return *this;
}
//! Assignment operator
inline const Vector4D<S> &operator=(S s)
{
x = y = z = t = s;
return *this;
}
//! Assign and add operator
inline const Vector4D<S> &operator+=(const Vector4D<S> &v)
{
x += v.x;
y += v.y;
z += v.z;
t += v.t;
return *this;
}
//! Assign and add operator
inline const Vector4D<S> &operator+=(S s)
{
x += s;
y += s;
z += s;
t += s;
return *this;
}
//! Assign and sub operator
inline const Vector4D<S> &operator-=(const Vector4D<S> &v)
{
x -= v.x;
y -= v.y;
z -= v.z;
t -= v.t;
return *this;
}
//! Assign and sub operator
inline const Vector4D<S> &operator-=(S s)
{
x -= s;
y -= s;
z -= s;
t -= s;
return *this;
}
//! Assign and mult operator
inline const Vector4D<S> &operator*=(const Vector4D<S> &v)
{
x *= v.x;
y *= v.y;
z *= v.z;
t *= v.t;
return *this;
}
//! Assign and mult operator
inline const Vector4D<S> &operator*=(S s)
{
x *= s;
y *= s;
z *= s;
t *= s;
return *this;
}
//! Assign and div operator
inline const Vector4D<S> &operator/=(const Vector4D<S> &v)
{
x /= v.x;
y /= v.y;
z /= v.z;
t /= v.t;
return *this;
}
//! Assign and div operator
inline const Vector4D<S> &operator/=(S s)
{
x /= s;
y /= s;
z /= s;
t /= s;
return *this;
}
//! Negation operator
inline Vector4D<S> operator-() const
{
return Vector4D<S>(-x, -y, -z, -t);
}
//! Get smallest component
// inline S min() const { return ( x<y ) ? ( ( x<z ) ? x:z ) : ( ( y<z ) ? y:z ); }
//! Get biggest component
// inline S max() const { return ( x>y ) ? ( ( x>z ) ? x:z ) : ( ( y>z ) ? y:z ); }
//! Test if all components are zero
inline bool empty()
{
return x == 0 && y == 0 && z == 0 && t == 0;
}
//! access operator
inline S &operator[](unsigned int i)
{
return value[i];
}
//! constant access operator
inline const S &operator[](unsigned int i) const
{
return value[i];
}
//! debug output vector to a string
std::string toString() const;
//! test if nans are present
bool isValid() const;
//! actual values
union {
S value[4];
struct {
S x;
S y;
S z;
S t;
};
struct {
S X;
S Y;
S Z;
S T;
};
};
// zero element
static const Vector4D<S> Zero, Invalid;
protected:
};
//************************************************************************
// Additional operators
//************************************************************************
//! Addition operator
template<class S> inline Vector4D<S> operator+(const Vector4D<S> &v1, const Vector4D<S> &v2)
{
return Vector4D<S>(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z, v1.t + v2.t);
}
//! Addition operator
template<class S, class S2> inline Vector4D<S> operator+(const Vector4D<S> &v, S2 s)
{
return Vector4D<S>(v.x + s, v.y + s, v.z + s, v.t + s);
}
//! Addition operator
template<class S, class S2> inline Vector4D<S> operator+(S2 s, const Vector4D<S> &v)
{
return Vector4D<S>(v.x + s, v.y + s, v.z + s, v.t + s);
}
//! Subtraction operator
template<class S> inline Vector4D<S> operator-(const Vector4D<S> &v1, const Vector4D<S> &v2)
{
return Vector4D<S>(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z, v1.t - v2.t);
}
//! Subtraction operator
template<class S, class S2> inline Vector4D<S> operator-(const Vector4D<S> &v, S2 s)
{
return Vector4D<S>(v.x - s, v.y - s, v.z - s, v.t - s);
}
//! Subtraction operator
template<class S, class S2> inline Vector4D<S> operator-(S2 s, const Vector4D<S> &v)
{
return Vector4D<S>(s - v.x, s - v.y, s - v.z, s - v.t);
}
//! Multiplication operator
template<class S> inline Vector4D<S> operator*(const Vector4D<S> &v1, const Vector4D<S> &v2)
{
return Vector4D<S>(v1.x * v2.x, v1.y * v2.y, v1.z * v2.z, v1.t * v2.t);
}
//! Multiplication operator
template<class S, class S2> inline Vector4D<S> operator*(const Vector4D<S> &v, S2 s)
{
return Vector4D<S>(v.x * s, v.y * s, v.z * s, v.t * s);
}
//! Multiplication operator
template<class S, class S2> inline Vector4D<S> operator*(S2 s, const Vector4D<S> &v)
{
return Vector4D<S>(s * v.x, s * v.y, s * v.z, s * v.t);
}
//! Division operator
template<class S> inline Vector4D<S> operator/(const Vector4D<S> &v1, const Vector4D<S> &v2)
{
return Vector4D<S>(v1.x / v2.x, v1.y / v2.y, v1.z / v2.z, v1.t / v2.t);
}
//! Division operator
template<class S, class S2> inline Vector4D<S> operator/(const Vector4D<S> &v, S2 s)
{
return Vector4D<S>(v.x / s, v.y / s, v.z / s, v.t / s);
}
//! Division operator
template<class S, class S2> inline Vector4D<S> operator/(S2 s, const Vector4D<S> &v)
{
return Vector4D<S>(s / v.x, s / v.y, s / v.z, s / v.t);
}
//! Comparison operator
template<class S> inline bool operator==(const Vector4D<S> &s1, const Vector4D<S> &s2)
{
return s1.x == s2.x && s1.y == s2.y && s1.z == s2.z && s1.t == s2.t;
}
//! Comparison operator
template<class S> inline bool operator!=(const Vector4D<S> &s1, const Vector4D<S> &s2)
{
return s1.x != s2.x || s1.y != s2.y || s1.z != s2.z || s1.t != s2.t;
}
//************************************************************************
// External functions
//************************************************************************
//! Dot product
template<class S> inline S dot(const Vector4D<S> &t, const Vector4D<S> &v)
{
return t.x * v.x + t.y * v.y + t.z * v.z + t.t * v.t;
}
/* Based on libstdc++ implementation from:
https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/c_global/cmath#L3769
*/
template<typename _Tp>
inline _Tp
__hypot4(_Tp __x, _Tp __y, _Tp __z, _Tp __t)
{
__x = std::abs(__x);
__y = std::abs(__y);
__z = std::abs(__z);
__t = std::abs(__t);
if (_Tp __a = __x < __y ? (__y < __z ? (__z < __t ? __t : __z ) : (__y < __t ? __t : __y )) : __x < __z ? (__z < __t ? __t : __z ) : (__x < __t ? __t : __x ))
return __a * std::sqrt((__x / __a) * (__x / __a)
+ (__y / __a) * (__y / __a)
+ (__z / __a) * (__z / __a)
+ (__t / __a) * (__t / __a));
else
return {};
}
inline float
hypot4(float __x, float __y, float __z, float __t)
{ return __hypot4<float>(__x, __y, __z, __t); }
inline double
hypot4(double __x, double __y, double __z, double __t)
{ return __hypot4<double>(__x, __y, __z, __t); }
//! Cross product
/*template<class S>
inline Vector4D<S> cross ( const Vector4D<S> &t, const Vector4D<S> &v ) {
NYI Vector4D<S> cp (
( ( t.y*v.z ) - ( t.z*v.y ) ),
( ( t.z*v.x ) - ( t.x*v.z ) ),
( ( t.x*v.y ) - ( t.y*v.x ) ) );
return cp;
}*/
//! Compute the magnitude (length) of the vector
template<class S> inline S norm(const Vector4D<S> &v)
{
S l = hypot4(v.x, v.y, v.z, v.t);
return (fabs(l - 1.) < VECTOR_EPSILON) ? 1. : l;
}
//! Compute squared magnitude
template<class S> inline S normSquare(const Vector4D<S> &v)
{
return v.x * v.x + v.y * v.y + v.z * v.z + v.t * v.t;
}
//! Returns a normalized vector
template<class S> inline Vector4D<S> getNormalized(const Vector4D<S> &v)
{
S l = hypot4(v.x, v.y, v.z, v.t);
if (fabs(l - 1.) < VECTOR_EPSILON)
return v; /* normalized "enough"... */
else if (l > VECTOR_EPSILON) {
S fac = 1. / l;
return Vector4D<S>(v.x * fac, v.y * fac, v.z * fac, v.t * fac);
}
else
return Vector4D<S>((S)0);
}
//! Compute the norm of the vector and normalize it.
/*! \return The value of the norm */
template<class S> inline S normalize(Vector4D<S> &v)
{
S norm;
S l = hypot4(v.x, v.y, v.z, v.t);
if (fabs(l - 1.) < VECTOR_EPSILON) {
norm = 1.;
}
else if (l > VECTOR_EPSILON) {
norm = l;
v *= 1. / norm;
}
else {
v = Vector4D<S>::Zero;
norm = 0.;
}
return (S)norm;
}
//! Outputs the object in human readable form as string
template<class S> std::string Vector4D<S>::toString() const
{
char buf[256];
snprintf(buf,
256,
"[%+4.6f,%+4.6f,%+4.6f,%+4.6f]",
(double)(*this)[0],
(double)(*this)[1],
(double)(*this)[2],
(double)(*this)[3]);
// for debugging, optionally increase precision:
// snprintf ( buf,256,"[%+4.16f,%+4.16f,%+4.16f,%+4.16f]", ( double ) ( *this ) [0], ( double ) (
// *this ) [1], ( double ) ( *this ) [2], ( double ) ( *this ) [3] );
return std::string(buf);
}
template<> std::string Vector4D<int>::toString() const;
//! Outputs the object in human readable form to stream
template<class S> std::ostream &operator<<(std::ostream &os, const Vector4D<S> &i)
{
os << i.toString();
return os;
}
//! Reads the contents of the object from a stream
template<class S> std::istream &operator>>(std::istream &is, Vector4D<S> &i)
{
char c;
char dummy[4];
is >> c >> i[0] >> dummy >> i[1] >> dummy >> i[2] >> dummy >> i[3] >> c;
return is;
}
/**************************************************************************/
// Define default vector alias
/**************************************************************************/
//! 3D vector class of type Real (typically float)
typedef Vector4D<Real> Vec4;
//! 3D vector class of type int
typedef Vector4D<int> Vec4i;
//! convert to Real Vector
template<class T> inline Vec4 toVec4(T v)
{
return Vec4(v[0], v[1], v[2], v[3]);
}
template<class T> inline Vec4i toVec4i(T v)
{
return Vec4i(v[0], v[1], v[2], v[3]);
}
/**************************************************************************/
// Specializations for common math functions
/**************************************************************************/
template<> inline Vec4 clamp<Vec4>(const Vec4 &a, const Vec4 &b, const Vec4 &c)
{
return Vec4(
clamp(a.x, b.x, c.x), clamp(a.y, b.y, c.y), clamp(a.z, b.z, c.z), clamp(a.t, b.t, c.t));
}
template<> inline Vec4 safeDivide<Vec4>(const Vec4 &a, const Vec4 &b)
{
return Vec4(
safeDivide(a.x, b.x), safeDivide(a.y, b.y), safeDivide(a.z, b.z), safeDivide(a.t, b.t));
}
template<> inline Vec4 nmod<Vec4>(const Vec4 &a, const Vec4 &b)
{
return Vec4(nmod(a.x, b.x), nmod(a.y, b.y), nmod(a.z, b.z), nmod(a.t, b.t));
}
/**************************************************************************/
// 4d interpolation (note only 4d here, 2d/3d interpolations are in interpol.h)
/**************************************************************************/
#define BUILD_INDEX_4D \
Real px = pos.x - 0.5f, py = pos.y - 0.5f, pz = pos.z - 0.5f, pt = pos.t - 0.5f; \
int xi = (int)px; \
int yi = (int)py; \
int zi = (int)pz; \
int ti = (int)pt; \
Real s1 = px - (Real)xi, s0 = 1. - s1; \
Real t1 = py - (Real)yi, t0 = 1. - t1; \
Real f1 = pz - (Real)zi, f0 = 1. - f1; \
Real g1 = pt - (Real)ti, g0 = 1. - g1; \
/* clamp to border */ \
if (px < 0.) { \
xi = 0; \
s0 = 1.0; \
s1 = 0.0; \
} \
if (py < 0.) { \
yi = 0; \
t0 = 1.0; \
t1 = 0.0; \
} \
if (pz < 0.) { \
zi = 0; \
f0 = 1.0; \
f1 = 0.0; \
} \
if (pt < 0.) { \
ti = 0; \
g0 = 1.0; \
g1 = 0.0; \
} \
if (xi >= size.x - 1) { \
xi = size.x - 2; \
s0 = 0.0; \
s1 = 1.0; \
} \
if (yi >= size.y - 1) { \
yi = size.y - 2; \
t0 = 0.0; \
t1 = 1.0; \
} \
if (zi >= size.z - 1) { \
zi = size.z - 2; \
f0 = 0.0; \
f1 = 1.0; \
} \
if (ti >= size.t - 1) { \
ti = size.t - 2; \
g0 = 0.0; \
g1 = 1.0; \
} \
const int sX = 1; \
const int sY = size.x;
static inline void checkIndexInterpol4d(const Vec4i &size, int idx)
{
if (idx < 0 || idx > size.x * size.y * size.z * size.t) {
std::ostringstream s;
s << "Grid interpol4d dim " << size << " : index " << idx << " out of bound ";
errMsg(s.str());
}
}
template<class T>
inline T interpol4d(
const T *data, const Vec4i &size, const IndexInt sZ, const IndexInt sT, const Vec4 &pos)
{
BUILD_INDEX_4D
IndexInt idx = (IndexInt)xi + sY * (IndexInt)yi + sZ * (IndexInt)zi + sT * (IndexInt)ti;
DEBUG_ONLY(checkIndexInterpol4d(size, idx));
DEBUG_ONLY(checkIndexInterpol4d(size, idx + sX + sY + sZ + sT));
return (((data[idx] * t0 + data[idx + sY] * t1) * s0 +
(data[idx + sX] * t0 + data[idx + sX + sY] * t1) * s1) *
f0 +
((data[idx + sZ] * t0 + data[idx + sY + sZ] * t1) * s0 +
(data[idx + sX + sZ] * t0 + data[idx + sX + sY + sZ] * t1) * s1) *
f1) *
g0 +
(((data[idx + sT] * t0 + data[idx + sT + sY] * t1) * s0 +
(data[idx + sT + sX] * t0 + data[idx + sT + sX + sY] * t1) * s1) *
f0 +
((data[idx + sT + sZ] * t0 + data[idx + sT + sY + sZ] * t1) * s0 +
(data[idx + sT + sX + sZ] * t0 + data[idx + sT + sX + sY + sZ] * t1) * s1) *
f1) *
g1;
}
}; // namespace Manta
#endif

View File

@@ -0,0 +1,49 @@
/******************************************************************************
*
* 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
*
* Basic vector class
*
******************************************************************************/
#include "vectorbase.h"
using namespace std;
namespace Manta {
template<> const Vector3D<int> Vector3D<int>::Zero(0, 0, 0);
template<> const Vector3D<float> Vector3D<float>::Zero(0.f, 0.f, 0.f);
template<> const Vector3D<double> Vector3D<double>::Zero(0., 0., 0.);
template<>
const Vector3D<float> Vector3D<float>::Invalid(numeric_limits<float>::quiet_NaN(),
numeric_limits<float>::quiet_NaN(),
numeric_limits<float>::quiet_NaN());
template<>
const Vector3D<double> Vector3D<double>::Invalid(numeric_limits<double>::quiet_NaN(),
numeric_limits<double>::quiet_NaN(),
numeric_limits<double>::quiet_NaN());
template<> bool Vector3D<float>::isValid() const
{
return !c_isnan(x) && !c_isnan(y) && !c_isnan(z);
}
template<> bool Vector3D<double>::isValid() const
{
return !c_isnan(x) && !c_isnan(y) && !c_isnan(z);
}
//! Specialization for readable ints
template<> std::string Vector3D<int>::toString() const
{
char buf[256];
snprintf(buf, 256, "[%d,%d,%d]", (*this)[0], (*this)[1], (*this)[2]);
return std::string(buf);
}
} // namespace Manta

View File

@@ -0,0 +1,709 @@
/******************************************************************************
*
* MantaFlow fluid solver framework
* Copyright 2011-2016 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
*
* Basic vector class
*
******************************************************************************/
#ifndef _VECTORBASE_H
#define _VECTORBASE_H
// get rid of windos min/max defines
#if (defined(WIN32) || defined(_WIN32)) && !defined(NOMINMAX)
# define NOMINMAX
#endif
#include <stdio.h>
#include <string>
#include <limits>
#include <iostream>
#include "general.h"
// if min/max are still around...
#if defined(WIN32) || defined(_WIN32)
# undef min
# undef max
#endif
// use which fp-precision? 1=float, 2=double
#ifndef FLOATINGPOINT_PRECISION
# define FLOATINGPOINT_PRECISION 1
#endif
// VECTOR_EPSILON is the minimal vector length
// In order to be able to discriminate floating point values near zero, and
// to be sure not to fail a comparison because of roundoff errors, use this
// value as a threshold.
#if FLOATINGPOINT_PRECISION == 1
typedef float Real;
# define VECTOR_EPSILON (1e-6f)
#else
typedef double Real;
# define VECTOR_EPSILON (1e-10)
#endif
#ifndef M_PI
# define M_PI 3.1415926536
#endif
#ifndef M_E
# define M_E 2.7182818284
#endif
namespace Manta {
//! Basic inlined vector class
template<class S> class Vector3D {
public:
//! Constructor
inline Vector3D() : x(0), y(0), z(0)
{
}
//! Copy-Constructor
inline Vector3D(const Vector3D<S> &v) : x(v.x), y(v.y), z(v.z)
{
}
//! Copy-Constructor
inline Vector3D(const int *v) : x((S)v[0]), y((S)v[1]), z((S)v[2])
{
}
//! Copy-Constructor
inline Vector3D(const float *v) : x((S)v[0]), y((S)v[1]), z((S)v[2])
{
}
//! Copy-Constructor
inline Vector3D(const double *v) : x((S)v[0]), y((S)v[1]), z((S)v[2])
{
}
//! Construct a vector from one S
inline Vector3D(S v) : x(v), y(v), z(v)
{
}
//! Construct a vector from three Ss
inline Vector3D(S vx, S vy, S vz) : x(vx), y(vy), z(vz)
{
}
// Operators
//! Assignment operator
inline const Vector3D<S> &operator=(const Vector3D<S> &v)
{
x = v.x;
y = v.y;
z = v.z;
return *this;
}
//! Assignment operator
inline const Vector3D<S> &operator=(S s)
{
x = y = z = s;
return *this;
}
//! Assign and add operator
inline const Vector3D<S> &operator+=(const Vector3D<S> &v)
{
x += v.x;
y += v.y;
z += v.z;
return *this;
}
//! Assign and add operator
inline const Vector3D<S> &operator+=(S s)
{
x += s;
y += s;
z += s;
return *this;
}
//! Assign and sub operator
inline const Vector3D<S> &operator-=(const Vector3D<S> &v)
{
x -= v.x;
y -= v.y;
z -= v.z;
return *this;
}
//! Assign and sub operator
inline const Vector3D<S> &operator-=(S s)
{
x -= s;
y -= s;
z -= s;
return *this;
}
//! Assign and mult operator
inline const Vector3D<S> &operator*=(const Vector3D<S> &v)
{
x *= v.x;
y *= v.y;
z *= v.z;
return *this;
}
//! Assign and mult operator
inline const Vector3D<S> &operator*=(S s)
{
x *= s;
y *= s;
z *= s;
return *this;
}
//! Assign and div operator
inline const Vector3D<S> &operator/=(const Vector3D<S> &v)
{
x /= v.x;
y /= v.y;
z /= v.z;
return *this;
}
//! Assign and div operator
inline const Vector3D<S> &operator/=(S s)
{
x /= s;
y /= s;
z /= s;
return *this;
}
//! Negation operator
inline Vector3D<S> operator-() const
{
return Vector3D<S>(-x, -y, -z);
}
//! Get smallest component
inline S min() const
{
return (x < y) ? ((x < z) ? x : z) : ((y < z) ? y : z);
}
//! Get biggest component
inline S max() const
{
return (x > y) ? ((x > z) ? x : z) : ((y > z) ? y : z);
}
//! Test if all components are zero
inline bool empty()
{
return x == 0 && y == 0 && z == 0;
}
//! access operator
inline S &operator[](unsigned int i)
{
return value[i];
}
//! constant access operator
inline const S &operator[](unsigned int i) const
{
return value[i];
}
//! debug output vector to a string
std::string toString() const;
//! test if nans are present
bool isValid() const;
//! actual values
union {
S value[3];
struct {
S x;
S y;
S z;
};
struct {
S X;
S Y;
S Z;
};
};
//! zero element
static const Vector3D<S> Zero, Invalid;
//! For compatibility with 4d vectors (discards 4th comp)
inline Vector3D(S vx, S vy, S vz, S vDummy) : x(vx), y(vy), z(vz)
{
}
protected:
};
//! helper to check whether value is non-zero
template<class S> inline bool notZero(S v)
{
return (std::abs(v) > VECTOR_EPSILON);
}
template<class S> inline bool notZero(Vector3D<S> v)
{
return (std::abs(norm(v)) > VECTOR_EPSILON);
}
//************************************************************************
// Additional operators
//************************************************************************
//! Addition operator
template<class S> inline Vector3D<S> operator+(const Vector3D<S> &v1, const Vector3D<S> &v2)
{
return Vector3D<S>(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);
}
//! Addition operator
template<class S, class S2> inline Vector3D<S> operator+(const Vector3D<S> &v, S2 s)
{
return Vector3D<S>(v.x + s, v.y + s, v.z + s);
}
//! Addition operator
template<class S, class S2> inline Vector3D<S> operator+(S2 s, const Vector3D<S> &v)
{
return Vector3D<S>(v.x + s, v.y + s, v.z + s);
}
//! Subtraction operator
template<class S> inline Vector3D<S> operator-(const Vector3D<S> &v1, const Vector3D<S> &v2)
{
return Vector3D<S>(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
}
//! Subtraction operator
template<class S, class S2> inline Vector3D<S> operator-(const Vector3D<S> &v, S2 s)
{
return Vector3D<S>(v.x - s, v.y - s, v.z - s);
}
//! Subtraction operator
template<class S, class S2> inline Vector3D<S> operator-(S2 s, const Vector3D<S> &v)
{
return Vector3D<S>(s - v.x, s - v.y, s - v.z);
}
//! Multiplication operator
template<class S> inline Vector3D<S> operator*(const Vector3D<S> &v1, const Vector3D<S> &v2)
{
return Vector3D<S>(v1.x * v2.x, v1.y * v2.y, v1.z * v2.z);
}
//! Multiplication operator
template<class S, class S2> inline Vector3D<S> operator*(const Vector3D<S> &v, S2 s)
{
return Vector3D<S>(v.x * s, v.y * s, v.z * s);
}
//! Multiplication operator
template<class S, class S2> inline Vector3D<S> operator*(S2 s, const Vector3D<S> &v)
{
return Vector3D<S>(s * v.x, s * v.y, s * v.z);
}
//! Division operator
template<class S> inline Vector3D<S> operator/(const Vector3D<S> &v1, const Vector3D<S> &v2)
{
return Vector3D<S>(v1.x / v2.x, v1.y / v2.y, v1.z / v2.z);
}
//! Division operator
template<class S, class S2> inline Vector3D<S> operator/(const Vector3D<S> &v, S2 s)
{
return Vector3D<S>(v.x / s, v.y / s, v.z / s);
}
//! Division operator
template<class S, class S2> inline Vector3D<S> operator/(S2 s, const Vector3D<S> &v)
{
return Vector3D<S>(s / v.x, s / v.y, s / v.z);
}
//! Comparison operator
template<class S> inline bool operator==(const Vector3D<S> &s1, const Vector3D<S> &s2)
{
return s1.x == s2.x && s1.y == s2.y && s1.z == s2.z;
}
//! Comparison operator
template<class S> inline bool operator!=(const Vector3D<S> &s1, const Vector3D<S> &s2)
{
return s1.x != s2.x || s1.y != s2.y || s1.z != s2.z;
}
//************************************************************************
// External functions
//************************************************************************
//! Min operator
template<class S> inline Vector3D<S> vmin(const Vector3D<S> &s1, const Vector3D<S> &s2)
{
return Vector3D<S>(std::min(s1.x, s2.x), std::min(s1.y, s2.y), std::min(s1.z, s2.z));
}
//! Min operator
template<class S, class S2> inline Vector3D<S> vmin(const Vector3D<S> &s1, S2 s2)
{
return Vector3D<S>(std::min(s1.x, s2), std::min(s1.y, s2), std::min(s1.z, s2));
}
//! Min operator
template<class S1, class S> inline Vector3D<S> vmin(S1 s1, const Vector3D<S> &s2)
{
return Vector3D<S>(std::min(s1, s2.x), std::min(s1, s2.y), std::min(s1, s2.z));
}
//! Max operator
template<class S> inline Vector3D<S> vmax(const Vector3D<S> &s1, const Vector3D<S> &s2)
{
return Vector3D<S>(std::max(s1.x, s2.x), std::max(s1.y, s2.y), std::max(s1.z, s2.z));
}
//! Max operator
template<class S, class S2> inline Vector3D<S> vmax(const Vector3D<S> &s1, S2 s2)
{
return Vector3D<S>(std::max(s1.x, s2), std::max(s1.y, s2), std::max(s1.z, s2));
}
//! Max operator
template<class S1, class S> inline Vector3D<S> vmax(S1 s1, const Vector3D<S> &s2)
{
return Vector3D<S>(std::max(s1, s2.x), std::max(s1, s2.y), std::max(s1, s2.z));
}
//! Dot product
template<class S> inline S dot(const Vector3D<S> &t, const Vector3D<S> &v)
{
return t.x * v.x + t.y * v.y + t.z * v.z;
}
//! Cross product
template<class S> inline Vector3D<S> cross(const Vector3D<S> &t, const Vector3D<S> &v)
{
Vector3D<S> cp(
((t.y * v.z) - (t.z * v.y)), ((t.z * v.x) - (t.x * v.z)), ((t.x * v.y) - (t.y * v.x)));
return cp;
}
//! Project a vector into a plane, defined by its normal
/*! Projects a vector into a plane normal to the given vector, which must
have unit length. Self is modified.
\param v The vector to project
\param n The plane normal
\return The projected vector */
template<class S>
inline const Vector3D<S> &projectNormalTo(const Vector3D<S> &v, const Vector3D<S> &n)
{
S sprod = dot(v, n);
return v - n * dot(v, n);
}
//! Compute the magnitude (length) of the vector
//! (clamps to 0 and 1 with VECTOR_EPSILON)
template<class S> inline S norm(const Vector3D<S> &v)
{
S l = std::hypot(v.x, v.y, v.z);
if (l <= VECTOR_EPSILON)
return (0.);
return (fabs(l - 1.) < VECTOR_EPSILON) ? 1. : l;
}
//! Compute squared magnitude
template<class S> inline S normSquare(const Vector3D<S> &v)
{
return v.x * v.x + v.y * v.y + v.z * v.z;
}
//! compatibility, allow use of int, Real and Vec inputs with norm/normSquare
inline Real norm(const Real v)
{
return fabs(v);
}
inline Real normSquare(const Real v)
{
return square(v);
}
inline Real norm(const int v)
{
return abs(v);
}
inline Real normSquare(const int v)
{
return square(v);
}
//! Compute sum of all components, allow use of int, Real too
template<class S> inline S sum(const S v)
{
return v;
}
template<class S> inline S sum(const Vector3D<S> &v)
{
return v.x + v.y + v.z;
}
//! Get absolute representation of vector, allow use of int, Real too
inline Real abs(const Real v)
{
return std::fabs(v);
}
inline int abs(const int v)
{
return std::abs(v);
}
template<class S> inline Vector3D<S> abs(const Vector3D<S> &v)
{
Vector3D<S> cp(v.x, v.y, v.z);
for (int i = 0; i < 3; ++i) {
if (cp[i] < 0)
cp[i] *= (-1.0);
}
return cp;
}
//! Returns a normalized vector
template<class S> inline Vector3D<S> getNormalized(const Vector3D<S> &v)
{
S l = std::hypot(v.x, v.y, v.z);
if (fabs(l - 1.) < VECTOR_EPSILON)
return v; /* normalized "enough"... */
else if (l > VECTOR_EPSILON) {
S fac = 1. / l;
return Vector3D<S>(v.x * fac, v.y * fac, v.z * fac);
}
else
return Vector3D<S>((S)0);
}
//! Compute the norm of the vector and normalize it.
/*! \return The value of the norm */
template<class S> inline S normalize(Vector3D<S> &v)
{
S norm;
S l = std::hypot(v.x, v.y, v.z);
if (fabs(l - 1.) < VECTOR_EPSILON) {
norm = 1.;
}
else if (l > VECTOR_EPSILON) {
norm = l;
v *= 1. / l;
}
else {
v = Vector3D<S>::Zero;
norm = 0.;
}
return (S)norm;
}
//! Obtain an orthogonal vector
/*! Compute a vector that is orthonormal to the given vector.
* Nothing else can be assumed for the direction of the new vector.
* \return The orthonormal vector */
template<class S> Vector3D<S> getOrthogonalVector(const Vector3D<S> &v)
{
// Determine the component with max. absolute value
int maxIndex = (fabs(v.x) > fabs(v.y)) ? 0 : 1;
maxIndex = (fabs(v[maxIndex]) > fabs(v.z)) ? maxIndex : 2;
// Choose another axis than the one with max. component and project
// orthogonal to self
Vector3D<S> o(0.0);
o[(maxIndex + 1) % 3] = 1;
Vector3D<S> c = cross(v, o);
normalize(c);
return c;
}
//! Convert vector to polar coordinates
/*! Stable vector to angle conversion
*\param v vector to convert
\param phi unique angle [0,2PI]
\param theta unique angle [0,PI]
*/
template<class S> inline void vecToAngle(const Vector3D<S> &v, S &phi, S &theta)
{
if (fabs(v.y) < VECTOR_EPSILON)
theta = M_PI / 2;
else if (fabs(v.x) < VECTOR_EPSILON && fabs(v.z) < VECTOR_EPSILON)
theta = (v.y >= 0) ? 0 : M_PI;
else
theta = atan(sqrt(v.x * v.x + v.z * v.z) / v.y);
if (theta < 0)
theta += M_PI;
if (fabs(v.x) < VECTOR_EPSILON)
phi = M_PI / 2;
else
phi = atan(v.z / v.x);
if (phi < 0)
phi += M_PI;
if (fabs(v.z) < VECTOR_EPSILON)
phi = (v.x >= 0) ? 0 : M_PI;
else if (v.z < 0)
phi += M_PI;
}
//! Compute vector reflected at a surface
/*! Compute a vector, that is self (as an incoming vector)
* reflected at a surface with a distinct normal vector.
* Note that the normal is reversed, if the scalar product with it is positive.
\param t The incoming vector
\param n The surface normal
\return The new reflected vector
*/
template<class S> inline Vector3D<S> reflectVector(const Vector3D<S> &t, const Vector3D<S> &n)
{
Vector3D<S> nn = (dot(t, n) > 0.0) ? (n * -1.0) : n;
return (t - nn * (2.0 * dot(nn, t)));
}
//! Compute vector refracted at a surface
/*! \param t The incoming vector
* \param n The surface normal
* \param nt The "inside" refraction index
* \param nair The "outside" refraction index
* \param refRefl Set to 1 on total reflection
* \return The refracted vector
*/
template<class S>
inline Vector3D<S> refractVector(
const Vector3D<S> &t, const Vector3D<S> &normal, S nt, S nair, int &refRefl)
{
// from Glassner's book, section 5.2 (Heckberts method)
S eta = nair / nt;
S n = -dot(t, normal);
S tt = 1.0 + eta * eta * (n * n - 1.0);
if (tt < 0.0) {
// we have total reflection!
refRefl = 1;
}
else {
// normal reflection
tt = eta * n - sqrt(tt);
return (t * eta + normal * tt);
}
return t;
}
//! Outputs the object in human readable form as string
template<class S> std::string Vector3D<S>::toString() const
{
char buf[256];
snprintf(buf,
256,
"[%+4.6f,%+4.6f,%+4.6f]",
(double)(*this)[0],
(double)(*this)[1],
(double)(*this)[2]);
// for debugging, optionally increase precision:
// snprintf ( buf,256,"[%+4.16f,%+4.16f,%+4.16f]", ( double ) ( *this ) [0], ( double ) ( *this )
// [1], ( double ) ( *this ) [2] );
return std::string(buf);
}
template<> std::string Vector3D<int>::toString() const;
//! Outputs the object in human readable form to stream
/*! Output format [x,y,z] */
template<class S> std::ostream &operator<<(std::ostream &os, const Vector3D<S> &i)
{
os << i.toString();
return os;
}
//! Reads the contents of the object from a stream
/*! Input format [x,y,z] */
template<class S> std::istream &operator>>(std::istream &is, Vector3D<S> &i)
{
char c;
char dummy[3];
is >> c >> i[0] >> dummy >> i[1] >> dummy >> i[2] >> c;
return is;
}
/**************************************************************************/
// Define default vector alias
/**************************************************************************/
//! 3D vector class of type Real (typically float)
typedef Vector3D<Real> Vec3;
//! 3D vector class of type int
typedef Vector3D<int> Vec3i;
//! convert to Real Vector
template<class T> inline Vec3 toVec3(T v)
{
return Vec3(v[0], v[1], v[2]);
}
//! convert to int Vector
template<class T> inline Vec3i toVec3i(T v)
{
return Vec3i((int)v[0], (int)v[1], (int)v[2]);
}
//! convert to int Vector
template<class T> inline Vec3i toVec3i(T v0, T v1, T v2)
{
return Vec3i((int)v0, (int)v1, (int)v2);
}
//! round, and convert to int Vector
template<class T> inline Vec3i toVec3iRound(T v)
{
return Vec3i((int)round(v[0]), (int)round(v[1]), (int)round(v[2]));
}
template<class T> inline Vec3i toVec3iFloor(T v)
{
return Vec3i((int)floor(v[0]), (int)floor(v[1]), (int)floor(v[2]));
}
//! convert to int Vector if values are close enough to an int
template<class T> inline Vec3i toVec3iChecked(T v)
{
Vec3i ret;
for (size_t i = 0; i < 3; i++) {
Real a = v[i];
if (fabs(a - floor(a + 0.5)) > 1e-5)
errMsg("argument is not an int, cannot convert");
ret[i] = (int)(a + 0.5);
}
return ret;
}
//! convert to double Vector
template<class T> inline Vector3D<double> toVec3d(T v)
{
return Vector3D<double>(v[0], v[1], v[2]);
}
//! convert to float Vector
template<class T> inline Vector3D<float> toVec3f(T v)
{
return Vector3D<float>(v[0], v[1], v[2]);
}
/**************************************************************************/
// Specializations for common math functions
/**************************************************************************/
template<> inline Vec3 clamp<Vec3>(const Vec3 &a, const Vec3 &b, const Vec3 &c)
{
return Vec3(clamp(a.x, b.x, c.x), clamp(a.y, b.y, c.y), clamp(a.z, b.z, c.z));
}
template<> inline Vec3 safeDivide<Vec3>(const Vec3 &a, const Vec3 &b)
{
return Vec3(safeDivide(a.x, b.x), safeDivide(a.y, b.y), safeDivide(a.z, b.z));
}
template<> inline Vec3 nmod<Vec3>(const Vec3 &a, const Vec3 &b)
{
return Vec3(nmod(a.x, b.x), nmod(a.y, b.y), nmod(a.z, b.z));
}
}; // namespace Manta
#endif