<commit_before>#include <boost/python.hpp>
#include <boost/python/stl_iterator.hpp>
#include <boost/numpy.hpp>
#include <boost/make_shared.hpp>
#include <flex.h>
#include <numeric>

#ifdef NDEBUG
#	define MODULE_NAME PyNvFlex
#else
#	define MODULE_NAME PyNvFlexD
#endif

namespace bpy = boost::python;
namespace np = boost::numpy;

int size(const np::ndarray &array)
{
	auto dims = array.get_nd();
	auto shape = array.get_shape();
	using Num = decltype(*shape);
	return int(std::accumulate(shape, shape + dims, Num(1), std::multiplies<Num>()));
}

bpy::object flexErrorCallback;

void _FlexErrorCallback(FlexErrorSeverity type, const char *msg, const char *file, int line)
{
	if (flexErrorCallback)
	{
		flexErrorCallback(type, std::string(msg), std::string(file), line);
	}
}

FlexError PyNvFlexInit(int version, const bpy::object &errorFunc, int deviceIndex)
{
	flexErrorCallback = errorFunc;
	return flexInit(version, _FlexErrorCallback, deviceIndex);
}

using FlexSolver_ = std::shared_ptr<FlexSolver>;
using FlexTriangleMesh_ = std::shared_ptr<FlexTriangleMesh>;
using FlexSDF_ = std::shared_ptr<FlexSDF>;

FlexSolver_ PyNvFlexCreateSolver(int maxParticles, int maxDiffuseParticles, unsigned char maxNeighborsPerParticle)
{
	return FlexSolver_(flexCreateSolver(maxParticles, maxDiffuseParticles, maxNeighborsPerParticle), [](FlexSolver* s) { flexDestroySolver(s);});
}

void PyNvFlexDestroySolver(FlexSolver_ &solver)
{
	solver.reset();
}

void PyNvFlexUpdateSolver(const FlexSolver_ &solver, float dt, int substeps, FlexTimers *timers = nullptr)
{
	if(solver) flexUpdateSolver(solver.get(), dt, substeps, timers);
}

BOOST_PYTHON_FUNCTION_OVERLOADS(flexUpdateSolverOverloads, PyNvFlexUpdateSolver, 3, 4)

np::ndarray FlexParamsGetGravity(const FlexParams &params)
{
	return np::from_data(params.mGravity, np::dtype::get_builtin<float>(), bpy::make_tuple(3), bpy::make_tuple(sizeof(float)), bpy::object());
}

void FlexParamsSetGravity(FlexParams &params, const np::ndarray &gravity)
{
	params.mGravity[0] = bpy::extract<float>(gravity[0]);
	params.mGravity[1] = bpy::extract<float>(gravity[1]);
	params.mGravity[2] = bpy::extract<float>(gravity[2]);
}

np::ndarray FlexParamsGetWind(const FlexParams &params)
{
	return np::from_data(params.mWind, np::dtype::get_builtin<float>(), bpy::make_tuple(3), bpy::make_tuple(sizeof(float)), bpy::object());
}

void FlexParamsSetWind(FlexParams &params, const np::ndarray &Wind)
{
	params.mWind[0] = bpy::extract<float>(Wind[0]);
	params.mWind[1] = bpy::extract<float>(Wind[1]);
	params.mWind[2] = bpy::extract<float>(Wind[2]);
}

np::ndarray FlexParamsGetDiffuseSortAxis(const FlexParams &params)
{
	return np::from_data(params.mDiffuseSortAxis, np::dtype::get_builtin<float>(), bpy::make_tuple(3), bpy::make_tuple(sizeof(float)), bpy::object());
}

void FlexParamsSetDiffuseSortAxis(FlexParams &params, const np::ndarray &DiffuseSortAxis)
{
	params.mDiffuseSortAxis[0] = bpy::extract<float>(DiffuseSortAxis[0]);
	params.mDiffuseSortAxis[1] = bpy::extract<float>(DiffuseSortAxis[1]);
	params.mDiffuseSortAxis[2] = bpy::extract<float>(DiffuseSortAxis[2]);
}

np::ndarray FlexParamsGetPlanes(const FlexParams &params)
{
	return np::from_data(params.mPlanes, np::dtype::get_builtin<float>(), bpy::make_tuple(8, 4), bpy::make_tuple(sizeof(float)), bpy::object());
}

void FlexParamsSetPlanes(FlexParams &params, const np::ndarray &planes)
{
	for (int i = 0; i < 8; ++i)
		for (int j = 0; j < 4; ++j)
			params.mPlanes[i][j] = bpy::extract<float>(planes[i][j]);
}

void FlexSetParams(const FlexSolver_ &solver, const FlexParams &params)
{
	flexSetParams(solver.get(), &params);
}

void FlexGetParams(const FlexSolver_ &solver, FlexParams &params)
{
	flexGetParams(solver.get(), &params);
}

void FlexSetActive(const FlexSolver_ &solver, const np::ndarray &indices)
{
	auto indicesI = indices.astype(np::dtype::get_builtin<int>());
	flexSetActive(solver.get(), reinterpret_cast<int*>(indicesI.get_data()), size(indicesI), eFlexMemoryHost);
}

int FlexGetActiveCount(const FlexSolver_ &solver)
{
	return flexGetActiveCount(solver.get());
}

np::ndarray FlexGetActive(const FlexSolver_ &solver)
{
	int activeCount = FlexGetActiveCount(solver);
	np::ndarray ret = np::zeros(bpy::make_tuple(activeCount), np::dtype::get_builtin<int>());
	flexGetActive(solver.get(), reinterpret_cast<int*>(ret.get_data()), eFlexMemoryHost);
	return ret;
}

void FlexSetParticles(const FlexSolver_ &solver, const np::ndarray &particles)
{
	auto particlesF = particles.astype(np::dtype::get_builtin<float>());
	auto data = reinterpret_cast<float*>(particlesF.get_data());
	auto n = size(particlesF) / 4;
	flexSetParticles(solver.get(), data, n, eFlexMemoryHost);
}

np::ndarray FlexGetParticles(const FlexSolver_ &solver, int n)
{
	np::ndarray particles = np::zeros(bpy::make_tuple(n, 4), np::dtype::get_builtin<float>());
	flexGetParticles(solver.get(), reinterpret_cast<float*>(particles.get_data()), n, eFlexMemoryHost);
	return particles;
}

void FlexSetRestParticles(const FlexSolver_ &solver, const np::ndarray &particles)
{
	auto particlesF = particles.astype(np::dtype::get_builtin<float>());
	flexSetRestParticles(solver.get(), reinterpret_cast<float*>(particlesF.get_data()), size(particlesF) / 4, eFlexMemoryHost);
}

np::ndarray FlexGetSmoothParticles(const FlexSolver_ &solver, int n)
{
	np::ndarray particles = np::zeros(bpy::make_tuple(n, 4), np::dtype::get_builtin<float>());
	flexGetSmoothParticles(solver.get(), reinterpret_cast<float*>(particles.get_data()), n, eFlexMemoryHost);
	return particles;
}

void FlexSetVelocities(const FlexSolver_ &solver, const np::ndarray &velocities)
{
	auto velocitiesF = velocities.astype(np::dtype::get_builtin<float>());
	flexSetVelocities(solver.get(), reinterpret_cast<float*>(velocitiesF.get_data()), size(velocitiesF) / 3, eFlexMemoryHost);
}

np::ndarray FlexGetVelocities(const FlexSolver_ &solver, int n)
{
	np::ndarray velocities = np::zeros(bpy::make_tuple(n, 4), np::dtype::get_builtin<float>());
	flexGetVelocities(solver.get(), reinterpret_cast<float*>(velocities.get_data()), n, eFlexMemoryHost);
	return velocities;
}

void FlexSetPhases(const FlexSolver_ &solver, const np::ndarray &Phases)
{
	auto PhasesF = Phases.astype(np::dtype::get_builtin<int>());
	flexSetPhases(solver.get(), reinterpret_cast<int*>(PhasesF.get_data()), size(PhasesF) / 3, eFlexMemoryHost);
}

np::ndarray FlexGetPhases(const FlexSolver_ &solver, int n)
{
	np::ndarray Phases = np::zeros(bpy::make_tuple(n, 4), np::dtype::get_builtin<int>());
	flexGetPhases(solver.get(), reinterpret_cast<int*>(Phases.get_data()), n, eFlexMemoryHost);
	return Phases;
}

void FlexSetSprings(const FlexSolver_ &solver, const np::ndarray &indices, const np::ndarray &restLengths, const np::ndarray &stifness)
{
	auto indices_ = indices.astype(np::dtype::get_builtin<int>());
	auto restLengths_ = restLengths.astype(np::dtype::get_builtin<float>());
	auto stifness_ = stifness.astype(np::dtype::get_builtin<float>());
	flexSetSprings(solver.get(),
		reinterpret_cast<int*>(indices_.get_data()),
		reinterpret_cast<float*>(restLengths_.get_data()),
		reinterpret_cast<float*>(stifness_.get_data()),
		size(indices_) / 2,
		eFlexMemoryHost);
}

bpy::tuple FlexGetSprings(const FlexSolver_ &solver, int n)
{
	auto indices = np::zeros(bpy::make_tuple(n, 2), np::dtype::get_builtin<int>());
	auto restLengths = np::zeros(bpy::make_tuple(n), np::dtype::get_builtin<float>());
	auto stiffness = np::zeros(bpy::make_tuple(n), np::dtype::get_builtin<float>());
	//flexGetSprings(solver.get(),
	//	reinterpret_cast<int*>(indices.get_data()),
	//	reinterpret_cast<float*>(restLengths.get_data()),
	//	reinterpret_cast<float*>(stiffness.get_data()),
	//	n,
	//	eFlexMemoryHost);
	return bpy::make_tuple(indices, restLengths, stiffness);
}

void FlexSetRigids(const FlexSolver_ &solver,
				   const np::ndarray &offsets,
				   const np::ndarray &indices,
				   const np::ndarray &restPositions,
				   const np::ndarray &restNormals,
				   const np::ndarray &stifness,
				   const np::ndarray &rotations,
				   const np::ndarray &translations)
{
	auto offsets_ = offsets.astype(np::dtype::get_builtin<int>());
	auto indices_ = indices.astype(np::dtype::get_builtin<int>());
	auto restPositions_ = restPositions.astype(np::dtype::get_builtin<float>());
	auto restNormals_ = restNormals.astype(np::dtype::get_builtin<float>());
	auto stifness_ = stifness.astype(np::dtype::get_builtin<float>());
	auto rotations_ = rotations.astype(np::dtype::get_builtin<float>());
	auto translations_ = translations.astype(np::dtype::get_builtin<float>());
	flexSetRigids(solver.get(),
		reinterpret_cast<int*>(offsets_.get_data()),
		reinterpret_cast<int*>(indices_.get_data()),
		reinterpret_cast<float*>(restPositions_.get_data()),
		reinterpret_cast<float*>(restNormals_.get_data()),
		reinterpret_cast<float*>(stifness_.get_data()),
		reinterpret_cast<float*>(rotations_.get_data()),
		reinterpret_cast<float*>(translations_.get_data()),
		size(offsets_) - 1,
		eFlexMemoryHost);
}

void FlexSetNormals(const FlexSolver_ &solver, const np::ndarray &normals)
{
	auto normals_ = normals.astype(np::dtype::get_builtin<float>());
	flexSetNormals(solver.get(), reinterpret_cast<float*>(normals_.get_data()), size(normals) / 4, eFlexMemoryHost);
}

np::ndarray FlexGetNormals(const FlexSolver_ &solver, int n)
{
	auto normals = np::zeros(bpy::make_tuple(n, 4), np::dtype::get_builtin<float>());
	flexGetNormals(solver.get(), reinterpret_cast<float*>(normals.get_data()), n, eFlexMemoryHost);
	return normals;
}

bpy::tuple FlexGetRigidTransforms(const FlexSolver_ &solver, int numRigids)
{
	auto rotations = np::zeros(bpy::make_tuple(numRigids, 4), np::dtype::get_builtin<float>());
	auto translations = np::zeros(bpy::make_tuple(numRigids, 3), np::dtype::get_builtin<float>());
	flexGetRigidTransforms(solver.get(),
		reinterpret_cast<float*>(rotations.get_data()),
		reinterpret_cast<float*>(translations.get_data()),
		eFlexMemoryHost);
	return bpy::make_tuple(rotations, translations);
}

FlexTriangleMesh_ FlexCreateTriangleMesh()
{
	return FlexTriangleMesh_(flexCreateTriangleMesh(), [](FlexTriangleMesh*m) {flexDestroyTriangleMesh(m);});
}

void FlexDestroyTriangleMesh(FlexTriangleMesh_ &mesh)
{
	mesh.reset();
}

void FlexUpdateTriangleMesh(const FlexTriangleMesh_ &mesh,
							const np::ndarray &vertices,
							const np::ndarray &indices,
							const np::ndarray &lower,
							const np::ndarray &upper)
{
	auto vertices_ = vertices.astype(np::dtype::get_builtin<float>());
	auto indices_ = indices.astype(np::dtype::get_builtin<int>());
	auto lower_ = lower.astype(np::dtype::get_builtin<float>());
	auto upper_ = upper.astype(np::dtype::get_builtin<float>());
	flexUpdateTriangleMesh(mesh.get(),
		reinterpret_cast<float*>(vertices_.get_data()),
		reinterpret_cast<int*>(indices_.get_data()),
		size(vertices_), size(indices_) / 3,
		reinterpret_cast<float*>(lower_.get_data()),
		reinterpret_cast<float*>(upper_.get_data()),
		eFlexMemoryHost);
}

bpy::tuple FlexGetTriangleMeshBounds(const FlexTriangleMesh_ &mesh)
{
	auto lower = np::zeros(bpy::make_tuple(3), np::dtype::get_builtin<float>());
	auto upper = np::zeros(bpy::make_tuple(3), np::dtype::get_builtin<float>());
	flexGetTriangleMeshBounds(mesh.get(),
		reinterpret_cast<float*>(lower.get_data()),
		reinterpret_cast<float*>(upper.get_data()));
	return bpy::make_tuple(lower, upper);
}

FlexSDF_ FlexCreateSDF()
{
	return FlexSDF_(flexCreateSDF(), [](FlexSDF*sdf) {flexDestroySDF(sdf);});
}

void FlexDestroySDF(FlexSDF_ &sdf)
{
	sdf.reset();
}

void FlexUpdateSDF(const FlexSDF_ &sdf, const np::ndarray &field)
{
	auto field_ = field.astype(np::dtype::get_builtin<float>());
	flexUpdateSDF(sdf.get(), field_.shape(0), field_.shape(1), field_.shape(2),
		reinterpret_cast<float*>(field_.get_data()), eFlexMemoryHost);
}

void FlexSetShapes(const FlexSolver_ &solver,
				   const bpy::object &geometry,
				   const np::ndarray &shapeAabbMins,
				   const np::ndarray &shapeAabbMaxs,
				   const np::ndarray &shapeOffsets,
				   const np::ndarray &shapePositions,
				   const np::ndarray &shapeRotations,
				   const np::ndarray &shapePrevPositions,
				   const np::ndarray &shapePrevRotations,
				   const np::ndarray &shapeFlags)
{
	bpy::stl_input_iterator<FlexCollisionGeometry> first(geometry), last;
	std::vector<FlexCollisionGeometry> geometry_(first, last);
	auto shapeAabbMins_ = shapeAabbMins.astype(np::dtype::get_builtin<float>());
	auto shapeAabbMaxs_ = shapeAabbMaxs.astype(np::dtype::get_builtin<float>());
	auto shapeOffsets_ = shapeOffsets.astype(np::dtype::get_builtin<int>());
	auto shapePositions_ = shapePositions.astype(np::dtype::get_builtin<float>());
	auto shapeRotations_ = shapeRotations.astype(np::dtype::get_builtin<float>());
	auto shapePrevPositions_ = shapePrevPositions.astype(np::dtype::get_builtin<float>());
	auto shapePrevRotations_ = shapePrevRotations.astype(np::dtype::get_builtin<float>());
	auto shapeFlags_ = shapeFlags.astype(np::dtype::get_builtin<int>());
	flexSetShapes(solver.get(),
		geometry_.data(),
		geometry_.size(),
		reinterpret_cast<float*>(shapeAabbMins_.get_data()),
		reinterpret_cast<float*>(shapeAabbMaxs_.get_data()),
		reinterpret_cast<int*>(shapeOffsets_.get_data()),
		reinterpret_cast<float*>(shapePositions_.get_data()),
		reinterpret_cast<float*>(shapeRotations_.get_data()),
		reinterpret_cast<float*>(shapePrevPositions_.get_data()),
		reinterpret_cast<float*>(shapePrevRotations_.get_data()),
		reinterpret_cast<int*>(shapeFlags.get_data()),
		size(shapeOffsets_),
		eFlexMemoryHost);
}

void FlexSetDynamicTriangles(const FlexSolver_ &solver, const np::ndarray &indices, const np::ndarray &normals)<commit_msg>No warnings<commit_after>#include <boost/python.hpp>
#include <boost/python/stl_iterator.hpp>
#include <boost/numpy.hpp>
#include <boost/make_shared.hpp>
#include <flex.h>
#include <numeric>

#ifdef NDEBUG
#	define MODULE_NAME PyNvFlex
#else
#	define MODULE_NAME PyNvFlexD
#endif

namespace bpy = boost::python;
namespace np = boost::numpy;

int size(const np::ndarray &array)
{
	int dims = array.get_nd();
	auto shape = array.get_shape();
	using int__ = std::remove_reference<std::remove_const<decltype(*shape)>::type>::type;
	return int(std::accumulate(shape, shape + dims, int__(1), std::multiplies<int__>()));
}

bpy::object flexErrorCallback;

void _FlexErrorCallback(FlexErrorSeverity type, const char *msg, const char *file, int line)
{
	if (flexErrorCallback)
	{
		flexErrorCallback(type, std::string(msg), std::string(file), line);
	}
}

FlexError PyNvFlexInit(int version, const bpy::object &errorFunc, int deviceIndex)
{
	flexErrorCallback = errorFunc;
	return flexInit(version, _FlexErrorCallback, deviceIndex);
}

using FlexSolver_ = std::shared_ptr<FlexSolver>;
using FlexTriangleMesh_ = std::shared_ptr<FlexTriangleMesh>;
using FlexSDF_ = std::shared_ptr<FlexSDF>;

FlexSolver_ PyNvFlexCreateSolver(int maxParticles, int maxDiffuseParticles, unsigned char maxNeighborsPerParticle)
{
	return FlexSolver_(flexCreateSolver(maxParticles, maxDiffuseParticles, maxNeighborsPerParticle), [](FlexSolver* s) { flexDestroySolver(s);});
}

void PyNvFlexDestroySolver(FlexSolver_ &solver)
{
	solver.reset();
}

void PyNvFlexUpdateSolver(const FlexSolver_ &solver, float dt, int substeps, FlexTimers *timers = nullptr)
{
	if(solver) flexUpdateSolver(solver.get(), dt, substeps, timers);
}

BOOST_PYTHON_FUNCTION_OVERLOADS(flexUpdateSolverOverloads, PyNvFlexUpdateSolver, 3, 4)

np::ndarray FlexParamsGetGravity(const FlexParams &params)
{
	return np::from_data(params.mGravity, np::dtype::get_builtin<float>(), bpy::make_tuple(3), bpy::make_tuple(sizeof(float)), bpy::object());
}

void FlexParamsSetGravity(FlexParams &params, const np::ndarray &gravity)
{
	params.mGravity[0] = bpy::extract<float>(gravity[0]);
	params.mGravity[1] = bpy::extract<float>(gravity[1]);
	params.mGravity[2] = bpy::extract<float>(gravity[2]);
}

np::ndarray FlexParamsGetWind(const FlexParams &params)
{
	return np::from_data(params.mWind, np::dtype::get_builtin<float>(), bpy::make_tuple(3), bpy::make_tuple(sizeof(float)), bpy::object());
}

void FlexParamsSetWind(FlexParams &params, const np::ndarray &Wind)
{
	params.mWind[0] = bpy::extract<float>(Wind[0]);
	params.mWind[1] = bpy::extract<float>(Wind[1]);
	params.mWind[2] = bpy::extract<float>(Wind[2]);
}

np::ndarray FlexParamsGetDiffuseSortAxis(const FlexParams &params)
{
	return np::from_data(params.mDiffuseSortAxis, np::dtype::get_builtin<float>(), bpy::make_tuple(3), bpy::make_tuple(sizeof(float)), bpy::object());
}

void FlexParamsSetDiffuseSortAxis(FlexParams &params, const np::ndarray &DiffuseSortAxis)
{
	params.mDiffuseSortAxis[0] = bpy::extract<float>(DiffuseSortAxis[0]);
	params.mDiffuseSortAxis[1] = bpy::extract<float>(DiffuseSortAxis[1]);
	params.mDiffuseSortAxis[2] = bpy::extract<float>(DiffuseSortAxis[2]);
}

np::ndarray FlexParamsGetPlanes(const FlexParams &params)
{
	return np::from_data(params.mPlanes, np::dtype::get_builtin<float>(), bpy::make_tuple(8, 4), bpy::make_tuple(sizeof(float)), bpy::object());
}

void FlexParamsSetPlanes(FlexParams &params, const np::ndarray &planes)
{
	for (int i = 0; i < 8; ++i)
		for (int j = 0; j < 4; ++j)
			params.mPlanes[i][j] = bpy::extract<float>(planes[i][j]);
}

void FlexSetParams(const FlexSolver_ &solver, const FlexParams &params)
{
	flexSetParams(solver.get(), &params);
}

void FlexGetParams(const FlexSolver_ &solver, FlexParams &params)
{
	flexGetParams(solver.get(), &params);
}

void FlexSetActive(const FlexSolver_ &solver, const np::ndarray &indices)
{
	auto indicesI = indices.astype(np::dtype::get_builtin<int>());
	flexSetActive(solver.get(), reinterpret_cast<int*>(indicesI.get_data()), size(indicesI), eFlexMemoryHost);
}

int FlexGetActiveCount(const FlexSolver_ &solver)
{
	return flexGetActiveCount(solver.get());
}

np::ndarray FlexGetActive(const FlexSolver_ &solver)
{
	int activeCount = FlexGetActiveCount(solver);
	np::ndarray ret = np::zeros(bpy::make_tuple(activeCount), np::dtype::get_builtin<int>());
	flexGetActive(solver.get(), reinterpret_cast<int*>(ret.get_data()), eFlexMemoryHost);
	return ret;
}

void FlexSetParticles(const FlexSolver_ &solver, const np::ndarray &particles)
{
	auto particlesF = particles.astype(np::dtype::get_builtin<float>());
	flexSetParticles(solver.get(), reinterpret_cast<float*>(particlesF.get_data()), size(particlesF) / 4, eFlexMemoryHost);
}

np::ndarray FlexGetParticles(const FlexSolver_ &solver, int n)
{
	np::ndarray particles = np::zeros(bpy::make_tuple(n, 4), np::dtype::get_builtin<float>());
	flexGetParticles(solver.get(), reinterpret_cast<float*>(particles.get_data()), n, eFlexMemoryHost);
	return particles;
}

void FlexSetRestParticles(const FlexSolver_ &solver, const np::ndarray &particles)
{
	auto particlesF = particles.astype(np::dtype::get_builtin<float>());
	flexSetRestParticles(solver.get(), reinterpret_cast<float*>(particlesF.get_data()), size(particlesF) / 4, eFlexMemoryHost);
}

np::ndarray FlexGetSmoothParticles(const FlexSolver_ &solver, int n)
{
	np::ndarray particles = np::zeros(bpy::make_tuple(n, 4), np::dtype::get_builtin<float>());
	flexGetSmoothParticles(solver.get(), reinterpret_cast<float*>(particles.get_data()), n, eFlexMemoryHost);
	return particles;
}

void FlexSetVelocities(const FlexSolver_ &solver, const np::ndarray &velocities)
{
	auto velocitiesF = velocities.astype(np::dtype::get_builtin<float>());
	flexSetVelocities(solver.get(), reinterpret_cast<float*>(velocitiesF.get_data()), size(velocitiesF) / 3, eFlexMemoryHost);
}

np::ndarray FlexGetVelocities(const FlexSolver_ &solver, int n)
{
	np::ndarray velocities = np::zeros(bpy::make_tuple(n, 4), np::dtype::get_builtin<float>());
	flexGetVelocities(solver.get(), reinterpret_cast<float*>(velocities.get_data()), n, eFlexMemoryHost);
	return velocities;
}

void FlexSetPhases(const FlexSolver_ &solver, const np::ndarray &Phases)
{
	auto PhasesF = Phases.astype(np::dtype::get_builtin<int>());
	flexSetPhases(solver.get(), reinterpret_cast<int*>(PhasesF.get_data()), size(PhasesF) / 3, eFlexMemoryHost);
}

np::ndarray FlexGetPhases(const FlexSolver_ &solver, int n)
{
	np::ndarray Phases = np::zeros(bpy::make_tuple(n, 4), np::dtype::get_builtin<int>());
	flexGetPhases(solver.get(), reinterpret_cast<int*>(Phases.get_data()), n, eFlexMemoryHost);
	return Phases;
}

void FlexSetSprings(const FlexSolver_ &solver, const np::ndarray &indices, const np::ndarray &restLengths, const np::ndarray &stifness)
{
	auto indices_ = indices.astype(np::dtype::get_builtin<int>());
	auto restLengths_ = restLengths.astype(np::dtype::get_builtin<float>());
	auto stifness_ = stifness.astype(np::dtype::get_builtin<float>());
	flexSetSprings(solver.get(),
		reinterpret_cast<int*>(indices_.get_data()),
		reinterpret_cast<float*>(restLengths_.get_data()),
		reinterpret_cast<float*>(stifness_.get_data()),
		size(indices_) / 2,
		eFlexMemoryHost);
}

bpy::tuple FlexGetSprings(const FlexSolver_ &solver, int n)
{
	auto indices = np::zeros(bpy::make_tuple(n, 2), np::dtype::get_builtin<int>());
	auto restLengths = np::zeros(bpy::make_tuple(n), np::dtype::get_builtin<float>());
	auto stiffness = np::zeros(bpy::make_tuple(n), np::dtype::get_builtin<float>());
	//flexGetSprings(solver.get(),
	//	reinterpret_cast<int*>(indices.get_data()),
	//	reinterpret_cast<float*>(restLengths.get_data()),
	//	reinterpret_cast<float*>(stiffness.get_data()),
	//	n,
	//	eFlexMemoryHost);
	return bpy::make_tuple(indices, restLengths, stiffness);
}

void FlexSetRigids(const FlexSolver_ &solver,
				   const np::ndarray &offsets,
				   const np::ndarray &indices,
				   const np::ndarray &restPositions,
				   const np::ndarray &restNormals,
				   const np::ndarray &stifness,
				   const np::ndarray &rotations,
				   const np::ndarray &translations)
{
	auto offsets_ = offsets.astype(np::dtype::get_builtin<int>());
	auto indices_ = indices.astype(np::dtype::get_builtin<int>());
	auto restPositions_ = restPositions.astype(np::dtype::get_builtin<float>());
	auto restNormals_ = restNormals.astype(np::dtype::get_builtin<float>());
	auto stifness_ = stifness.astype(np::dtype::get_builtin<float>());
	auto rotations_ = rotations.astype(np::dtype::get_builtin<float>());
	auto translations_ = translations.astype(np::dtype::get_builtin<float>());
	flexSetRigids(solver.get(),
		reinterpret_cast<int*>(offsets_.get_data()),
		reinterpret_cast<int*>(indices_.get_data()),
		reinterpret_cast<float*>(restPositions_.get_data()),
		reinterpret_cast<float*>(restNormals_.get_data()),
		reinterpret_cast<float*>(stifness_.get_data()),
		reinterpret_cast<float*>(rotations_.get_data()),
		reinterpret_cast<float*>(translations_.get_data()),
		size(offsets_) - 1,
		eFlexMemoryHost);
}

void FlexSetNormals(const FlexSolver_ &solver, const np::ndarray &normals)
{
	auto normals_ = normals.astype(np::dtype::get_builtin<float>());
	flexSetNormals(solver.get(), reinterpret_cast<float*>(normals_.get_data()), size(normals) / 4, eFlexMemoryHost);
}

np::ndarray FlexGetNormals(const FlexSolver_ &solver, int n)
{
	auto normals = np::zeros(bpy::make_tuple(n, 4), np::dtype::get_builtin<float>());
	flexGetNormals(solver.get(), reinterpret_cast<float*>(normals.get_data()), n, eFlexMemoryHost);
	return normals;
}

bpy::tuple FlexGetRigidTransforms(const FlexSolver_ &solver, int numRigids)
{
	auto rotations = np::zeros(bpy::make_tuple(numRigids, 4), np::dtype::get_builtin<float>());
	auto translations = np::zeros(bpy::make_tuple(numRigids, 3), np::dtype::get_builtin<float>());
	flexGetRigidTransforms(solver.get(),
		reinterpret_cast<float*>(rotations.get_data()),
		reinterpret_cast<float*>(translations.get_data()),
		eFlexMemoryHost);
	return bpy::make_tuple(rotations, translations);
}

FlexTriangleMesh_ FlexCreateTriangleMesh()
{
	return FlexTriangleMesh_(flexCreateTriangleMesh(), [](FlexTriangleMesh*m) {flexDestroyTriangleMesh(m);});
}

void FlexDestroyTriangleMesh(FlexTriangleMesh_ &mesh)
{
	mesh.reset();
}

void FlexUpdateTriangleMesh(const FlexTriangleMesh_ &mesh,
							const np::ndarray &vertices,
							const np::ndarray &indices,
							const np::ndarray &lower,
							const np::ndarray &upper)
{
	auto vertices_ = vertices.astype(np::dtype::get_builtin<float>());
	auto indices_ = indices.astype(np::dtype::get_builtin<int>());
	auto lower_ = lower.astype(np::dtype::get_builtin<float>());
	auto upper_ = upper.astype(np::dtype::get_builtin<float>());
	flexUpdateTriangleMesh(mesh.get(),
		reinterpret_cast<float*>(vertices_.get_data()),
		reinterpret_cast<int*>(indices_.get_data()),
		size(vertices_), size(indices_) / 3,
		reinterpret_cast<float*>(lower_.get_data()),
		reinterpret_cast<float*>(upper_.get_data()),
		eFlexMemoryHost);
}

bpy::tuple FlexGetTriangleMeshBounds(const FlexTriangleMesh_ &mesh)
{
	auto lower = np::zeros(bpy::make_tuple(3), np::dtype::get_builtin<float>());
	auto upper = np::zeros(bpy::make_tuple(3), np::dtype::get_builtin<float>());
	flexGetTriangleMeshBounds(mesh.get(),
		reinterpret_cast<float*>(lower.get_data()),
		reinterpret_cast<float*>(upper.get_data()));
	return bpy::make_tuple(lower, upper);
}

FlexSDF_ FlexCreateSDF()
{
	return FlexSDF_(flexCreateSDF(), [](FlexSDF*sdf) {flexDestroySDF(sdf);});
}

void FlexDestroySDF(FlexSDF_ &sdf)
{
	sdf.reset();
}

void FlexUpdateSDF(const FlexSDF_ &sdf, const np::ndarray &field)
{
	auto field_ = field.astype(np::dtype::get_builtin<float>());
	flexUpdateSDF(sdf.get(), int(field_.shape(0)), int(field_.shape(1)), int(field_.shape(2)),
		reinterpret_cast<float*>(field_.get_data()), eFlexMemoryHost);
}

void FlexSetShapes(const FlexSolver_ &solver,
				   const bpy::object &geometry,
				   const np::ndarray &shapeAabbMins,
				   const np::ndarray &shapeAabbMaxs,
				   const np::ndarray &shapeOffsets,
				   const np::ndarray &shapePositions,
				   const np::ndarray &shapeRotations,
				   const np::ndarray &shapePrevPositions,
				   const np::ndarray &shapePrevRotations,
				   const np::ndarray &shapeFlags)
{
	bpy::stl_input_iterator<FlexCollisionGeometry> first(geometry), last;
	std::vector<FlexCollisionGeometry> geometry_(first, last);
	auto shapeAabbMins_ = shapeAabbMins.astype(np::dtype::get_builtin<float>());
	auto shapeAabbMaxs_ = shapeAabbMaxs.astype(np::dtype::get_builtin<float>());
	auto shapeOffsets_ = shapeOffsets.astype(np::dtype::get_builtin<int>());
	auto shapePositions_ = shapePositions.astype(np::dtype::get_builtin<float>());
	auto shapeRotations_ = shapeRotations.astype(np::dtype::get_builtin<float>());
	auto shapePrevPositions_ = shapePrevPositions.astype(np::dtype::get_builtin<float>());
	auto shapePrevRotations_ = shapePrevRotations.astype(np::dtype::get_builtin<float>());
	auto shapeFlags_ = shapeFlags.astype(np::dtype::get_builtin<int>());
	flexSetShapes(solver.get(),
		geometry_.data(),
		int(geometry_.size()),
		reinterpret_cast<float*>(shapeAabbMins_.get_data()),
		reinterpret_cast<float*>(shapeAabbMaxs_.get_data()),
		reinterpret_cast<int*>(shapeOffsets_.get_data()),
		reinterpret_cast<float*>(shapePositions_.get_data()),
		reinterpret_cast<float*>(shapeRotations_.get_data()),
		reinterpret_cast<float*>(shapePrevPositions_.get_data()),
		reinterpret_cast<float*>(shapePrevRotations_.get_data()),
		reinterpret_cast<int*>(shapeFlags.get_data()),
		size(shapeOffsets_),
		eFlexMemoryHost);
}

void FlexSetDynamicTriangles(const FlexSolver_ &solver, const np::ndarray &indices, const np::ndarray &normals)
{'fraction_non_alphanumeric': 0.16056903155207003, 'fraction_numerical': 0.003720590917380996, 'mean_word_length': 8.408373369938229, 'pattern_counts': {'":': 0, '<': 229, '<?xml version=': 0, '>': 225, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2037403', 'n_tokens_mistral': 10295, 'n_tokens_neox': 9856, 'n_words': 1512}