1011 lines
27 KiB
C++
1011 lines
27 KiB
C++
![]() |
|
||
|
|
||
|
// DO NOT EDIT !
|
||
|
// This file is generated using the MantaFlow preprocessor (prep generate).
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* 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
|
||
|
*
|
||
|
* Shape classes
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
#include "shapes.h"
|
||
|
#include "commonkernels.h"
|
||
|
#include "mesh.h"
|
||
|
|
||
|
using namespace std;
|
||
|
namespace Manta {
|
||
|
|
||
|
//******************************************************************************
|
||
|
// Shape class members
|
||
|
|
||
|
Shape::Shape(FluidSolver *parent) : PbClass(parent), mType(TypeNone)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
LevelsetGrid Shape::computeLevelset()
|
||
|
{
|
||
|
// note - 3d check deactivated! TODO double check...
|
||
|
LevelsetGrid phi(getParent());
|
||
|
generateLevelset(phi);
|
||
|
return phi;
|
||
|
}
|
||
|
|
||
|
bool Shape::isInside(const Vec3 &pos) const
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//! Kernel: Apply a shape to a grid, setting value inside
|
||
|
|
||
|
template<class T> struct ApplyShapeToGrid : public KernelBase {
|
||
|
ApplyShapeToGrid(Grid<T> *grid, Shape *shape, T value, FlagGrid *respectFlags)
|
||
|
: KernelBase(grid, 0), grid(grid), shape(shape), value(value), respectFlags(respectFlags)
|
||
|
{
|
||
|
runMessage();
|
||
|
run();
|
||
|
}
|
||
|
inline void op(
|
||
|
int i, int j, int k, Grid<T> *grid, Shape *shape, T value, FlagGrid *respectFlags) const
|
||
|
{
|
||
|
if (respectFlags && respectFlags->isObstacle(i, j, k))
|
||
|
return;
|
||
|
if (shape->isInsideGrid(i, j, k))
|
||
|
(*grid)(i, j, k) = value;
|
||
|
}
|
||
|
inline Grid<T> *getArg0()
|
||
|
{
|
||
|
return grid;
|
||
|
}
|
||
|
typedef Grid<T> type0;
|
||
|
inline Shape *getArg1()
|
||
|
{
|
||
|
return shape;
|
||
|
}
|
||
|
typedef Shape type1;
|
||
|
inline T &getArg2()
|
||
|
{
|
||
|
return value;
|
||
|
}
|
||
|
typedef T type2;
|
||
|
inline FlagGrid *getArg3()
|
||
|
{
|
||
|
return respectFlags;
|
||
|
}
|
||
|
typedef FlagGrid type3;
|
||
|
void runMessage()
|
||
|
{
|
||
|
debMsg("Executing kernel ApplyShapeToGrid ", 3);
|
||
|
debMsg("Kernel range"
|
||
|
<< " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
|
||
|
4);
|
||
|
};
|
||
|
void operator()(const tbb::blocked_range<IndexInt> &__r) const
|
||
|
{
|
||
|
const int _maxX = maxX;
|
||
|
const int _maxY = maxY;
|
||
|
if (maxZ > 1) {
|
||
|
for (int k = __r.begin(); k != (int)__r.end(); k++)
|
||
|
for (int j = 0; j < _maxY; j++)
|
||
|
for (int i = 0; i < _maxX; i++)
|
||
|
op(i, j, k, grid, shape, value, respectFlags);
|
||
|
}
|
||
|
else {
|
||
|
const int k = 0;
|
||
|
for (int j = __r.begin(); j != (int)__r.end(); j++)
|
||
|
for (int i = 0; i < _maxX; i++)
|
||
|
op(i, j, k, grid, shape, value, respectFlags);
|
||
|
}
|
||
|
}
|
||
|
void run()
|
||
|
{
|
||
|
if (maxZ > 1)
|
||
|
tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
|
||
|
else
|
||
|
tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
|
||
|
}
|
||
|
Grid<T> *grid;
|
||
|
Shape *shape;
|
||
|
T value;
|
||
|
FlagGrid *respectFlags;
|
||
|
};
|
||
|
|
||
|
//! Kernel: Apply a shape to a grid, setting value inside (scaling by SDF value)
|
||
|
|
||
|
template<class T> struct ApplyShapeToGridSmooth : public KernelBase {
|
||
|
ApplyShapeToGridSmooth(
|
||
|
Grid<T> *grid, Grid<Real> &phi, Real sigma, Real shift, T value, FlagGrid *respectFlags)
|
||
|
: KernelBase(grid, 0),
|
||
|
grid(grid),
|
||
|
phi(phi),
|
||
|
sigma(sigma),
|
||
|
shift(shift),
|
||
|
value(value),
|
||
|
respectFlags(respectFlags)
|
||
|
{
|
||
|
runMessage();
|
||
|
run();
|
||
|
}
|
||
|
inline void op(int i,
|
||
|
int j,
|
||
|
int k,
|
||
|
Grid<T> *grid,
|
||
|
Grid<Real> &phi,
|
||
|
Real sigma,
|
||
|
Real shift,
|
||
|
T value,
|
||
|
FlagGrid *respectFlags) const
|
||
|
{
|
||
|
if (respectFlags && respectFlags->isObstacle(i, j, k))
|
||
|
return;
|
||
|
const Real p = phi(i, j, k) - shift;
|
||
|
if (p < -sigma)
|
||
|
(*grid)(i, j, k) = value;
|
||
|
else if (p < sigma)
|
||
|
(*grid)(i, j, k) = value * (0.5f * (1.0f - p / sigma));
|
||
|
}
|
||
|
inline Grid<T> *getArg0()
|
||
|
{
|
||
|
return grid;
|
||
|
}
|
||
|
typedef Grid<T> type0;
|
||
|
inline Grid<Real> &getArg1()
|
||
|
{
|
||
|
return phi;
|
||
|
}
|
||
|
typedef Grid<Real> type1;
|
||
|
inline Real &getArg2()
|
||
|
{
|
||
|
return sigma;
|
||
|
}
|
||
|
typedef Real type2;
|
||
|
inline Real &getArg3()
|
||
|
{
|
||
|
return shift;
|
||
|
}
|
||
|
typedef Real type3;
|
||
|
inline T &getArg4()
|
||
|
{
|
||
|
return value;
|
||
|
}
|
||
|
typedef T type4;
|
||
|
inline FlagGrid *getArg5()
|
||
|
{
|
||
|
return respectFlags;
|
||
|
}
|
||
|
typedef FlagGrid type5;
|
||
|
void runMessage()
|
||
|
{
|
||
|
debMsg("Executing kernel ApplyShapeToGridSmooth ", 3);
|
||
|
debMsg("Kernel range"
|
||
|
<< " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
|
||
|
4);
|
||
|
};
|
||
|
void operator()(const tbb::blocked_range<IndexInt> &__r) const
|
||
|
{
|
||
|
const int _maxX = maxX;
|
||
|
const int _maxY = maxY;
|
||
|
if (maxZ > 1) {
|
||
|
for (int k = __r.begin(); k != (int)__r.end(); k++)
|
||
|
for (int j = 0; j < _maxY; j++)
|
||
|
for (int i = 0; i < _maxX; i++)
|
||
|
op(i, j, k, grid, phi, sigma, shift, value, respectFlags);
|
||
|
}
|
||
|
else {
|
||
|
const int k = 0;
|
||
|
for (int j = __r.begin(); j != (int)__r.end(); j++)
|
||
|
for (int i = 0; i < _maxX; i++)
|
||
|
op(i, j, k, grid, phi, sigma, shift, value, respectFlags);
|
||
|
}
|
||
|
}
|
||
|
void run()
|
||
|
{
|
||
|
if (maxZ > 1)
|
||
|
tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
|
||
|
else
|
||
|
tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
|
||
|
}
|
||
|
Grid<T> *grid;
|
||
|
Grid<Real> φ
|
||
|
Real sigma;
|
||
|
Real shift;
|
||
|
T value;
|
||
|
FlagGrid *respectFlags;
|
||
|
};
|
||
|
|
||
|
//! Kernel: Apply a shape to a MAC grid, setting value inside
|
||
|
|
||
|
struct ApplyShapeToMACGrid : public KernelBase {
|
||
|
ApplyShapeToMACGrid(MACGrid *grid, Shape *shape, Vec3 value, FlagGrid *respectFlags)
|
||
|
: KernelBase(grid, 0), grid(grid), shape(shape), value(value), respectFlags(respectFlags)
|
||
|
{
|
||
|
runMessage();
|
||
|
run();
|
||
|
}
|
||
|
inline void op(
|
||
|
int i, int j, int k, MACGrid *grid, Shape *shape, Vec3 value, FlagGrid *respectFlags) const
|
||
|
{
|
||
|
if (respectFlags && respectFlags->isObstacle(i, j, k))
|
||
|
return;
|
||
|
if (shape->isInside(Vec3(i, j + 0.5, k + 0.5)))
|
||
|
(*grid)(i, j, k).x = value.x;
|
||
|
if (shape->isInside(Vec3(i + 0.5, j, k + 0.5)))
|
||
|
(*grid)(i, j, k).y = value.y;
|
||
|
if (shape->isInside(Vec3(i + 0.5, j + 0.5, k)))
|
||
|
(*grid)(i, j, k).z = value.z;
|
||
|
}
|
||
|
inline MACGrid *getArg0()
|
||
|
{
|
||
|
return grid;
|
||
|
}
|
||
|
typedef MACGrid type0;
|
||
|
inline Shape *getArg1()
|
||
|
{
|
||
|
return shape;
|
||
|
}
|
||
|
typedef Shape type1;
|
||
|
inline Vec3 &getArg2()
|
||
|
{
|
||
|
return value;
|
||
|
}
|
||
|
typedef Vec3 type2;
|
||
|
inline FlagGrid *getArg3()
|
||
|
{
|
||
|
return respectFlags;
|
||
|
}
|
||
|
typedef FlagGrid type3;
|
||
|
void runMessage()
|
||
|
{
|
||
|
debMsg("Executing kernel ApplyShapeToMACGrid ", 3);
|
||
|
debMsg("Kernel range"
|
||
|
<< " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
|
||
|
4);
|
||
|
};
|
||
|
void operator()(const tbb::blocked_range<IndexInt> &__r) const
|
||
|
{
|
||
|
const int _maxX = maxX;
|
||
|
const int _maxY = maxY;
|
||
|
if (maxZ > 1) {
|
||
|
for (int k = __r.begin(); k != (int)__r.end(); k++)
|
||
|
for (int j = 0; j < _maxY; j++)
|
||
|
for (int i = 0; i < _maxX; i++)
|
||
|
op(i, j, k, grid, shape, value, respectFlags);
|
||
|
}
|
||
|
else {
|
||
|
const int k = 0;
|
||
|
for (int j = __r.begin(); j != (int)__r.end(); j++)
|
||
|
for (int i = 0; i < _maxX; i++)
|
||
|
op(i, j, k, grid, shape, value, respectFlags);
|
||
|
}
|
||
|
}
|
||
|
void run()
|
||
|
{
|
||
|
if (maxZ > 1)
|
||
|
tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
|
||
|
else
|
||
|
tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
|
||
|
}
|
||
|
MACGrid *grid;
|
||
|
Shape *shape;
|
||
|
Vec3 value;
|
||
|
FlagGrid *respectFlags;
|
||
|
};
|
||
|
|
||
|
void Shape::applyToGrid(GridBase *grid, FlagGrid *respectFlags)
|
||
|
{
|
||
|
#if NOPYTHON != 1
|
||
|
if (grid->getType() & GridBase::TypeInt)
|
||
|
ApplyShapeToGrid<int>((Grid<int> *)grid, this, _args.get<int>("value"), respectFlags);
|
||
|
else if (grid->getType() & GridBase::TypeReal)
|
||
|
ApplyShapeToGrid<Real>((Grid<Real> *)grid, this, _args.get<Real>("value"), respectFlags);
|
||
|
else if (grid->getType() & GridBase::TypeMAC)
|
||
|
ApplyShapeToMACGrid((MACGrid *)grid, this, _args.get<Vec3>("value"), respectFlags);
|
||
|
else if (grid->getType() & GridBase::TypeVec3)
|
||
|
ApplyShapeToGrid<Vec3>((Grid<Vec3> *)grid, this, _args.get<Vec3>("value"), respectFlags);
|
||
|
else
|
||
|
errMsg("Shape::applyToGrid(): unknown grid type");
|
||
|
#else
|
||
|
errMsg("Not yet supported...");
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void Shape::applyToGridSmooth(GridBase *grid, Real sigma, Real shift, FlagGrid *respectFlags)
|
||
|
{
|
||
|
Grid<Real> phi(grid->getParent());
|
||
|
generateLevelset(phi);
|
||
|
|
||
|
#if NOPYTHON != 1
|
||
|
if (grid->getType() & GridBase::TypeInt)
|
||
|
ApplyShapeToGridSmooth<int>(
|
||
|
(Grid<int> *)grid, phi, sigma, shift, _args.get<int>("value"), respectFlags);
|
||
|
else if (grid->getType() & GridBase::TypeReal)
|
||
|
ApplyShapeToGridSmooth<Real>(
|
||
|
(Grid<Real> *)grid, phi, sigma, shift, _args.get<Real>("value"), respectFlags);
|
||
|
else if (grid->getType() & GridBase::TypeVec3)
|
||
|
ApplyShapeToGridSmooth<Vec3>(
|
||
|
(Grid<Vec3> *)grid, phi, sigma, shift, _args.get<Vec3>("value"), respectFlags);
|
||
|
else
|
||
|
errMsg("Shape::applyToGridSmooth(): unknown grid type");
|
||
|
#else
|
||
|
errMsg("Not yet supported...");
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void Shape::collideMesh(Mesh &mesh)
|
||
|
{
|
||
|
const Real margin = 0.2;
|
||
|
|
||
|
Grid<Real> phi(getParent());
|
||
|
Grid<Vec3> grad(getParent());
|
||
|
generateLevelset(phi);
|
||
|
GradientOp(grad, phi);
|
||
|
|
||
|
const int num = mesh.numNodes();
|
||
|
for (int i = 0; i < num; i++) {
|
||
|
const Vec3 &p = mesh.nodes(i).pos;
|
||
|
mesh.nodes(i).flags &= ~(Mesh::NfCollide | Mesh::NfMarked);
|
||
|
if (!phi.isInBounds(p, 1))
|
||
|
continue;
|
||
|
|
||
|
for (int iter = 0; iter < 10; iter++) {
|
||
|
const Real dist = phi.getInterpolated(p);
|
||
|
if (dist < margin) {
|
||
|
Vec3 n = grad.getInterpolated(p);
|
||
|
normalize(n);
|
||
|
mesh.nodes(i).pos += (margin - dist) * n;
|
||
|
mesh.nodes(i).flags |= Mesh::NfCollide | Mesh::NfMarked;
|
||
|
}
|
||
|
else
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//******************************************************************************
|
||
|
// Derived shape class members
|
||
|
|
||
|
Box::Box(FluidSolver *parent, Vec3 center, Vec3 p0, Vec3 p1, Vec3 size) : Shape(parent)
|
||
|
{
|
||
|
mType = TypeBox;
|
||
|
if (center.isValid() && size.isValid()) {
|
||
|
mP0 = center - size;
|
||
|
mP1 = center + size;
|
||
|
}
|
||
|
else if (p0.isValid() && p1.isValid()) {
|
||
|
mP0 = p0;
|
||
|
mP1 = p1;
|
||
|
}
|
||
|
else
|
||
|
errMsg("Box: specify either p0,p1 or size,center");
|
||
|
}
|
||
|
|
||
|
bool Box::isInside(const Vec3 &pos) const
|
||
|
{
|
||
|
return (pos.x >= mP0.x && pos.y >= mP0.y && pos.z >= mP0.z && pos.x <= mP1.x && pos.y <= mP1.y &&
|
||
|
pos.z <= mP1.z);
|
||
|
}
|
||
|
|
||
|
void Box::generateMesh(Mesh *mesh)
|
||
|
{
|
||
|
const int quadidx[24] = {0, 4, 6, 2, 3, 7, 5, 1, 0, 1, 5, 4, 6, 7, 3, 2, 0, 2, 3, 1, 5, 7, 6, 4};
|
||
|
const int nodebase = mesh->numNodes();
|
||
|
int oldtri = mesh->numTris();
|
||
|
for (int i = 0; i < 8; i++) {
|
||
|
Node p;
|
||
|
p.flags = 0;
|
||
|
p.pos = mP0;
|
||
|
if (i & 1)
|
||
|
p.pos.x = mP1.x;
|
||
|
if (i & 2)
|
||
|
p.pos.y = mP1.y;
|
||
|
if (i & 4)
|
||
|
p.pos.z = mP1.z;
|
||
|
mesh->addNode(p);
|
||
|
}
|
||
|
for (int i = 0; i < 6; i++) {
|
||
|
mesh->addTri(Triangle(nodebase + quadidx[i * 4 + 0],
|
||
|
nodebase + quadidx[i * 4 + 1],
|
||
|
nodebase + quadidx[i * 4 + 3]));
|
||
|
mesh->addTri(Triangle(nodebase + quadidx[i * 4 + 1],
|
||
|
nodebase + quadidx[i * 4 + 2],
|
||
|
nodebase + quadidx[i * 4 + 3]));
|
||
|
}
|
||
|
mesh->rebuildCorners(oldtri, -1);
|
||
|
mesh->rebuildLookup(oldtri, -1);
|
||
|
}
|
||
|
|
||
|
//! Kernel: Analytic SDF for box shape
|
||
|
struct BoxSDF : public KernelBase {
|
||
|
BoxSDF(Grid<Real> &phi, const Vec3 &p1, const Vec3 &p2)
|
||
|
: KernelBase(&phi, 0), phi(phi), p1(p1), p2(p2)
|
||
|
{
|
||
|
runMessage();
|
||
|
run();
|
||
|
}
|
||
|
inline void op(int i, int j, int k, Grid<Real> &phi, const Vec3 &p1, const Vec3 &p2) const
|
||
|
{
|
||
|
const Vec3 p(i + 0.5, j + 0.5, k + 0.5);
|
||
|
if (p.x <= p2.x && p.x >= p1.x && p.y <= p2.y && p.y >= p1.y && p.z <= p2.z && p.z >= p1.z) {
|
||
|
// inside: minimal surface distance
|
||
|
Real mx = max(p.x - p2.x, p1.x - p.x);
|
||
|
Real my = max(p.y - p2.y, p1.y - p.y);
|
||
|
Real mz = max(p.z - p2.z, p1.z - p.z);
|
||
|
if (!phi.is3D())
|
||
|
mz = mx; // skip for 2d...
|
||
|
phi(i, j, k) = max(mx, max(my, mz));
|
||
|
}
|
||
|
else if (p.y <= p2.y && p.y >= p1.y && p.z <= p2.z && p.z >= p1.z) {
|
||
|
// outside plane X
|
||
|
phi(i, j, k) = max(p.x - p2.x, p1.x - p.x);
|
||
|
}
|
||
|
else if (p.x <= p2.x && p.x >= p1.x && p.z <= p2.z && p.z >= p1.z) {
|
||
|
// outside plane Y
|
||
|
phi(i, j, k) = max(p.y - p2.y, p1.y - p.y);
|
||
|
}
|
||
|
else if (p.x <= p2.x && p.x >= p1.x && p.y <= p2.y && p.y >= p1.y) {
|
||
|
// outside plane Z
|
||
|
phi(i, j, k) = max(p.z - p2.z, p1.z - p.z);
|
||
|
}
|
||
|
else if (p.x > p1.x && p.x < p2.x) {
|
||
|
// lines X
|
||
|
Real m1 = sqrt(square(p1.y - p.y) + square(p1.z - p.z));
|
||
|
Real m2 = sqrt(square(p2.y - p.y) + square(p1.z - p.z));
|
||
|
Real m3 = sqrt(square(p1.y - p.y) + square(p2.z - p.z));
|
||
|
Real m4 = sqrt(square(p2.y - p.y) + square(p2.z - p.z));
|
||
|
phi(i, j, k) = min(m1, min(m2, min(m3, m4)));
|
||
|
}
|
||
|
else if (p.y > p1.y && p.y < p2.y) {
|
||
|
// lines Y
|
||
|
Real m1 = sqrt(square(p1.x - p.x) + square(p1.z - p.z));
|
||
|
Real m2 = sqrt(square(p2.x - p.x) + square(p1.z - p.z));
|
||
|
Real m3 = sqrt(square(p1.x - p.x) + square(p2.z - p.z));
|
||
|
Real m4 = sqrt(square(p2.x - p.x) + square(p2.z - p.z));
|
||
|
phi(i, j, k) = min(m1, min(m2, min(m3, m4)));
|
||
|
}
|
||
|
else if (p.z > p1.x && p.z < p2.z) {
|
||
|
// lines Z
|
||
|
Real m1 = sqrt(square(p1.y - p.y) + square(p1.x - p.x));
|
||
|
Real m2 = sqrt(square(p2.y - p.y) + square(p1.x - p.x));
|
||
|
Real m3 = sqrt(square(p1.y - p.y) + square(p2.x - p.x));
|
||
|
Real m4 = sqrt(square(p2.y - p.y) + square(p2.x - p.x));
|
||
|
phi(i, j, k) = min(m1, min(m2, min(m3, m4)));
|
||
|
}
|
||
|
else {
|
||
|
// points
|
||
|
Real m = norm(p - Vec3(p1.x, p1.y, p1.z));
|
||
|
m = min(m, norm(p - Vec3(p1.x, p1.y, p2.z)));
|
||
|
m = min(m, norm(p - Vec3(p1.x, p2.y, p1.z)));
|
||
|
m = min(m, norm(p - Vec3(p1.x, p2.y, p2.z)));
|
||
|
m = min(m, norm(p - Vec3(p2.x, p1.y, p1.z)));
|
||
|
m = min(m, norm(p - Vec3(p2.x, p1.y, p2.z)));
|
||
|
m = min(m, norm(p - Vec3(p2.x, p2.y, p1.z)));
|
||
|
m = min(m, norm(p - Vec3(p2.x, p2.y, p2.z)));
|
||
|
phi(i, j, k) = m;
|
||
|
}
|
||
|
}
|
||
|
inline Grid<Real> &getArg0()
|
||
|
{
|
||
|
return phi;
|
||
|
}
|
||
|
typedef Grid<Real> type0;
|
||
|
inline const Vec3 &getArg1()
|
||
|
{
|
||
|
return p1;
|
||
|
}
|
||
|
typedef Vec3 type1;
|
||
|
inline const Vec3 &getArg2()
|
||
|
{
|
||
|
return p2;
|
||
|
}
|
||
|
typedef Vec3 type2;
|
||
|
void runMessage()
|
||
|
{
|
||
|
debMsg("Executing kernel BoxSDF ", 3);
|
||
|
debMsg("Kernel range"
|
||
|
<< " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
|
||
|
4);
|
||
|
};
|
||
|
void operator()(const tbb::blocked_range<IndexInt> &__r) const
|
||
|
{
|
||
|
const int _maxX = maxX;
|
||
|
const int _maxY = maxY;
|
||
|
if (maxZ > 1) {
|
||
|
for (int k = __r.begin(); k != (int)__r.end(); k++)
|
||
|
for (int j = 0; j < _maxY; j++)
|
||
|
for (int i = 0; i < _maxX; i++)
|
||
|
op(i, j, k, phi, p1, p2);
|
||
|
}
|
||
|
else {
|
||
|
const int k = 0;
|
||
|
for (int j = __r.begin(); j != (int)__r.end(); j++)
|
||
|
for (int i = 0; i < _maxX; i++)
|
||
|
op(i, j, k, phi, p1, p2);
|
||
|
}
|
||
|
}
|
||
|
void run()
|
||
|
{
|
||
|
if (maxZ > 1)
|
||
|
tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
|
||
|
else
|
||
|
tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
|
||
|
}
|
||
|
Grid<Real> φ
|
||
|
const Vec3 &p1;
|
||
|
const Vec3 &p2;
|
||
|
};
|
||
|
void Box::generateLevelset(Grid<Real> &phi)
|
||
|
{
|
||
|
BoxSDF(phi, mP0, mP1);
|
||
|
}
|
||
|
|
||
|
Sphere::Sphere(FluidSolver *parent, Vec3 center, Real radius, Vec3 scale)
|
||
|
: Shape(parent), mCenter(center), mScale(scale), mRadius(radius)
|
||
|
{
|
||
|
mType = TypeSphere;
|
||
|
}
|
||
|
|
||
|
bool Sphere::isInside(const Vec3 &pos) const
|
||
|
{
|
||
|
return normSquare((pos - mCenter) / mScale) <= mRadius * mRadius;
|
||
|
}
|
||
|
|
||
|
struct Tri {
|
||
|
Vec3 t[3];
|
||
|
int i[3];
|
||
|
Tri(Vec3 a, Vec3 b, Vec3 c)
|
||
|
{
|
||
|
t[0] = a;
|
||
|
t[1] = b;
|
||
|
t[2] = c;
|
||
|
}
|
||
|
};
|
||
|
void Sphere::generateMesh(Mesh *mesh)
|
||
|
{
|
||
|
vector<Tri> tris;
|
||
|
const int iterations = 3;
|
||
|
int oldtri = mesh->numTris();
|
||
|
|
||
|
// start with octahedron
|
||
|
const Real d = sqrt(0.5);
|
||
|
Vec3 p[6] = {Vec3(0, 1, 0),
|
||
|
Vec3(0, -1, 0),
|
||
|
Vec3(-d, 0, -d),
|
||
|
Vec3(d, 0, -d),
|
||
|
Vec3(d, 0, d),
|
||
|
Vec3(-d, 0, d)};
|
||
|
tris.push_back(Tri(p[0], p[4], p[3]));
|
||
|
tris.push_back(Tri(p[0], p[5], p[4]));
|
||
|
tris.push_back(Tri(p[0], p[2], p[5]));
|
||
|
tris.push_back(Tri(p[0], p[3], p[2]));
|
||
|
tris.push_back(Tri(p[1], p[3], p[4]));
|
||
|
tris.push_back(Tri(p[1], p[4], p[5]));
|
||
|
tris.push_back(Tri(p[1], p[5], p[2]));
|
||
|
tris.push_back(Tri(p[1], p[2], p[3]));
|
||
|
|
||
|
// Bisect each edge and move to the surface of a unit sphere
|
||
|
for (int it = 0; it < iterations; it++) {
|
||
|
int ntold = tris.size();
|
||
|
for (int i = 0; i < ntold; i++) {
|
||
|
Vec3 pa = 0.5 * (tris[i].t[0] + tris[i].t[1]);
|
||
|
Vec3 pb = 0.5 * (tris[i].t[1] + tris[i].t[2]);
|
||
|
Vec3 pc = 0.5 * (tris[i].t[2] + tris[i].t[0]);
|
||
|
normalize(pa);
|
||
|
normalize(pb);
|
||
|
normalize(pc);
|
||
|
|
||
|
tris.push_back(Tri(tris[i].t[0], pa, pc));
|
||
|
tris.push_back(Tri(pa, tris[i].t[1], pb));
|
||
|
tris.push_back(Tri(pb, tris[i].t[2], pc));
|
||
|
tris[i].t[0] = pa;
|
||
|
tris[i].t[1] = pb;
|
||
|
tris[i].t[2] = pc;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// index + scale
|
||
|
vector<Vec3> nodes;
|
||
|
for (size_t i = 0; i < tris.size(); i++) {
|
||
|
for (int t = 0; t < 3; t++) {
|
||
|
Vec3 p = mCenter + tris[i].t[t] * mRadius * mScale;
|
||
|
// vector already there ?
|
||
|
int idx = nodes.size();
|
||
|
for (size_t j = 0; j < nodes.size(); j++) {
|
||
|
if (p == nodes[j]) {
|
||
|
idx = j;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (idx == (int)nodes.size())
|
||
|
nodes.push_back(p);
|
||
|
tris[i].i[t] = idx;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// add the to mesh
|
||
|
const int ni = mesh->numNodes();
|
||
|
for (size_t i = 0; i < nodes.size(); i++) {
|
||
|
mesh->addNode(Node(nodes[i]));
|
||
|
}
|
||
|
for (size_t t = 0; t < tris.size(); t++)
|
||
|
mesh->addTri(Triangle(tris[t].i[0] + ni, tris[t].i[1] + ni, tris[t].i[2] + ni));
|
||
|
|
||
|
mesh->rebuildCorners(oldtri, -1);
|
||
|
mesh->rebuildLookup(oldtri, -1);
|
||
|
}
|
||
|
|
||
|
struct SphereSDF : public KernelBase {
|
||
|
SphereSDF(Grid<Real> &phi, Vec3 center, Real radius, Vec3 scale)
|
||
|
: KernelBase(&phi, 0), phi(phi), center(center), radius(radius), scale(scale)
|
||
|
{
|
||
|
runMessage();
|
||
|
run();
|
||
|
}
|
||
|
inline void op(int i, int j, int k, Grid<Real> &phi, Vec3 center, Real radius, Vec3 scale) const
|
||
|
{
|
||
|
phi(i, j, k) = norm((Vec3(i + 0.5, j + 0.5, k + 0.5) - center) / scale) - radius;
|
||
|
}
|
||
|
inline Grid<Real> &getArg0()
|
||
|
{
|
||
|
return phi;
|
||
|
}
|
||
|
typedef Grid<Real> type0;
|
||
|
inline Vec3 &getArg1()
|
||
|
{
|
||
|
return center;
|
||
|
}
|
||
|
typedef Vec3 type1;
|
||
|
inline Real &getArg2()
|
||
|
{
|
||
|
return radius;
|
||
|
}
|
||
|
typedef Real type2;
|
||
|
inline Vec3 &getArg3()
|
||
|
{
|
||
|
return scale;
|
||
|
}
|
||
|
typedef Vec3 type3;
|
||
|
void runMessage()
|
||
|
{
|
||
|
debMsg("Executing kernel SphereSDF ", 3);
|
||
|
debMsg("Kernel range"
|
||
|
<< " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
|
||
|
4);
|
||
|
};
|
||
|
void operator()(const tbb::blocked_range<IndexInt> &__r) const
|
||
|
{
|
||
|
const int _maxX = maxX;
|
||
|
const int _maxY = maxY;
|
||
|
if (maxZ > 1) {
|
||
|
for (int k = __r.begin(); k != (int)__r.end(); k++)
|
||
|
for (int j = 0; j < _maxY; j++)
|
||
|
for (int i = 0; i < _maxX; i++)
|
||
|
op(i, j, k, phi, center, radius, scale);
|
||
|
}
|
||
|
else {
|
||
|
const int k = 0;
|
||
|
for (int j = __r.begin(); j != (int)__r.end(); j++)
|
||
|
for (int i = 0; i < _maxX; i++)
|
||
|
op(i, j, k, phi, center, radius, scale);
|
||
|
}
|
||
|
}
|
||
|
void run()
|
||
|
{
|
||
|
if (maxZ > 1)
|
||
|
tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
|
||
|
else
|
||
|
tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
|
||
|
}
|
||
|
Grid<Real> φ
|
||
|
Vec3 center;
|
||
|
Real radius;
|
||
|
Vec3 scale;
|
||
|
};
|
||
|
void Sphere::generateLevelset(Grid<Real> &phi)
|
||
|
{
|
||
|
SphereSDF(phi, mCenter, mRadius, mScale);
|
||
|
}
|
||
|
|
||
|
Cylinder::Cylinder(FluidSolver *parent, Vec3 center, Real radius, Vec3 z)
|
||
|
: Shape(parent), mCenter(center), mRadius(radius)
|
||
|
{
|
||
|
mType = TypeCylinder;
|
||
|
mZDir = z;
|
||
|
mZ = normalize(mZDir);
|
||
|
}
|
||
|
|
||
|
bool Cylinder::isInside(const Vec3 &pos) const
|
||
|
{
|
||
|
Real z = dot(pos - mCenter, mZDir);
|
||
|
if (fabs(z) > mZ)
|
||
|
return false;
|
||
|
Real r2 = normSquare(pos - mCenter) - square(z);
|
||
|
return r2 < square(mRadius);
|
||
|
}
|
||
|
|
||
|
void Cylinder::generateMesh(Mesh *mesh)
|
||
|
{
|
||
|
// generate coordinate system
|
||
|
Vec3 x = getOrthogonalVector(mZDir) * mRadius;
|
||
|
Vec3 y = cross(x, mZDir);
|
||
|
Vec3 z = mZDir * mZ;
|
||
|
int oldtri = mesh->numTris();
|
||
|
|
||
|
// construct node ring
|
||
|
const int N = 20;
|
||
|
const int base = mesh->numNodes();
|
||
|
for (int i = 0; i < N; i++) {
|
||
|
const Real phi = 2.0 * M_PI * (Real)i / (Real)N;
|
||
|
Vec3 r = x * cos(phi) + y * sin(phi) + mCenter;
|
||
|
mesh->addNode(Node(r + z));
|
||
|
mesh->addNode(Node(r - z));
|
||
|
}
|
||
|
// top/bottom center
|
||
|
mesh->addNode(Node(mCenter + z));
|
||
|
mesh->addNode(Node(mCenter - z));
|
||
|
|
||
|
// connect with tris
|
||
|
for (int i = 0; i < N; i++) {
|
||
|
int cur = base + 2 * i;
|
||
|
int next = base + 2 * ((i + 1) % N);
|
||
|
// outside
|
||
|
mesh->addTri(Triangle(cur, next, cur + 1));
|
||
|
mesh->addTri(Triangle(next, next + 1, cur + 1));
|
||
|
// upper / lower
|
||
|
mesh->addTri(Triangle(cur, base + 2 * N, next));
|
||
|
mesh->addTri(Triangle(cur + 1, next + 1, base + 2 * N + 1));
|
||
|
}
|
||
|
|
||
|
mesh->rebuildCorners(oldtri, -1);
|
||
|
mesh->rebuildLookup(oldtri, -1);
|
||
|
}
|
||
|
|
||
|
struct CylinderSDF : public KernelBase {
|
||
|
CylinderSDF(Grid<Real> &phi, Vec3 center, Real radius, Vec3 zaxis, Real maxz)
|
||
|
: KernelBase(&phi, 0), phi(phi), center(center), radius(radius), zaxis(zaxis), maxz(maxz)
|
||
|
{
|
||
|
runMessage();
|
||
|
run();
|
||
|
}
|
||
|
inline void op(
|
||
|
int i, int j, int k, Grid<Real> &phi, Vec3 center, Real radius, Vec3 zaxis, Real maxz) const
|
||
|
{
|
||
|
Vec3 p = Vec3(i + 0.5, j + 0.5, k + 0.5) - center;
|
||
|
Real z = fabs(dot(p, zaxis));
|
||
|
Real r = sqrt(normSquare(p) - z * z);
|
||
|
if (z < maxz) {
|
||
|
// cylinder z area
|
||
|
if (r < radius)
|
||
|
phi(i, j, k) = max(r - radius, z - maxz);
|
||
|
else
|
||
|
phi(i, j, k) = r - radius;
|
||
|
}
|
||
|
else if (r < radius) {
|
||
|
// cylinder top area
|
||
|
phi(i, j, k) = fabs(z - maxz);
|
||
|
}
|
||
|
else {
|
||
|
// edge
|
||
|
phi(i, j, k) = sqrt(square(z - maxz) + square(r - radius));
|
||
|
}
|
||
|
}
|
||
|
inline Grid<Real> &getArg0()
|
||
|
{
|
||
|
return phi;
|
||
|
}
|
||
|
typedef Grid<Real> type0;
|
||
|
inline Vec3 &getArg1()
|
||
|
{
|
||
|
return center;
|
||
|
}
|
||
|
typedef Vec3 type1;
|
||
|
inline Real &getArg2()
|
||
|
{
|
||
|
return radius;
|
||
|
}
|
||
|
typedef Real type2;
|
||
|
inline Vec3 &getArg3()
|
||
|
{
|
||
|
return zaxis;
|
||
|
}
|
||
|
typedef Vec3 type3;
|
||
|
inline Real &getArg4()
|
||
|
{
|
||
|
return maxz;
|
||
|
}
|
||
|
typedef Real type4;
|
||
|
void runMessage()
|
||
|
{
|
||
|
debMsg("Executing kernel CylinderSDF ", 3);
|
||
|
debMsg("Kernel range"
|
||
|
<< " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
|
||
|
4);
|
||
|
};
|
||
|
void operator()(const tbb::blocked_range<IndexInt> &__r) const
|
||
|
{
|
||
|
const int _maxX = maxX;
|
||
|
const int _maxY = maxY;
|
||
|
if (maxZ > 1) {
|
||
|
for (int k = __r.begin(); k != (int)__r.end(); k++)
|
||
|
for (int j = 0; j < _maxY; j++)
|
||
|
for (int i = 0; i < _maxX; i++)
|
||
|
op(i, j, k, phi, center, radius, zaxis, maxz);
|
||
|
}
|
||
|
else {
|
||
|
const int k = 0;
|
||
|
for (int j = __r.begin(); j != (int)__r.end(); j++)
|
||
|
for (int i = 0; i < _maxX; i++)
|
||
|
op(i, j, k, phi, center, radius, zaxis, maxz);
|
||
|
}
|
||
|
}
|
||
|
void run()
|
||
|
{
|
||
|
if (maxZ > 1)
|
||
|
tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
|
||
|
else
|
||
|
tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
|
||
|
}
|
||
|
Grid<Real> φ
|
||
|
Vec3 center;
|
||
|
Real radius;
|
||
|
Vec3 zaxis;
|
||
|
Real maxz;
|
||
|
};
|
||
|
void Cylinder::generateLevelset(Grid<Real> &phi)
|
||
|
{
|
||
|
CylinderSDF(phi, mCenter, mRadius, mZDir, mZ);
|
||
|
}
|
||
|
|
||
|
Slope::Slope(FluidSolver *parent, Real anglexy, Real angleyz, Real origin, Vec3 gs)
|
||
|
: Shape(parent), mAnglexy(anglexy), mAngleyz(angleyz), mOrigin(origin), mGs(gs)
|
||
|
{
|
||
|
mType = TypeSlope;
|
||
|
}
|
||
|
|
||
|
void Slope::generateMesh(Mesh *mesh)
|
||
|
{
|
||
|
|
||
|
const int oldtri = mesh->numTris();
|
||
|
|
||
|
Vec3 v1(0., mOrigin, 0.);
|
||
|
mesh->addNode(Node(v1));
|
||
|
|
||
|
Real dy1 = mGs.z * std::tan(mAngleyz);
|
||
|
Vec3 v2(0., mOrigin - dy1, mGs.z);
|
||
|
mesh->addNode(Node(v2));
|
||
|
|
||
|
Real dy2 = mGs.x * std::tan(mAnglexy);
|
||
|
Vec3 v3(mGs.x, v2.y - dy2, mGs.z);
|
||
|
mesh->addNode(Node(v3));
|
||
|
|
||
|
Vec3 v4(mGs.x, mOrigin - dy2, 0.);
|
||
|
mesh->addNode(Node(v4));
|
||
|
|
||
|
mesh->addTri(Triangle(0, 1, 2));
|
||
|
mesh->addTri(Triangle(2, 3, 0));
|
||
|
|
||
|
mesh->rebuildCorners(oldtri, -1);
|
||
|
mesh->rebuildLookup(oldtri, -1);
|
||
|
}
|
||
|
|
||
|
bool Slope::isInside(const Vec3 &pos) const
|
||
|
{
|
||
|
|
||
|
const Real alpha = -mAnglexy * M_PI / 180.;
|
||
|
const Real beta = -mAngleyz * M_PI / 180.;
|
||
|
|
||
|
Vec3 n(0, 1, 0);
|
||
|
|
||
|
n.x = std::sin(alpha) * std::cos(beta);
|
||
|
n.y = std::cos(alpha) * std::cos(beta);
|
||
|
n.z = std::sin(beta);
|
||
|
|
||
|
normalize(n);
|
||
|
|
||
|
const Real fac = std::sqrt(n.x * n.x + n.y * n.y + n.z * n.z);
|
||
|
|
||
|
return ((n.x * (double)pos.x + n.y * (double)pos.y + n.z * (double)pos.z - mOrigin) / fac) <= 0.;
|
||
|
}
|
||
|
|
||
|
struct SlopeSDF : public KernelBase {
|
||
|
SlopeSDF(const Vec3 &n, Grid<Real> &phiObs, const Real &fac, const Real &origin)
|
||
|
: KernelBase(&phiObs, 0), n(n), phiObs(phiObs), fac(fac), origin(origin)
|
||
|
{
|
||
|
runMessage();
|
||
|
run();
|
||
|
}
|
||
|
inline void op(int i,
|
||
|
int j,
|
||
|
int k,
|
||
|
const Vec3 &n,
|
||
|
Grid<Real> &phiObs,
|
||
|
const Real &fac,
|
||
|
const Real &origin) const
|
||
|
{
|
||
|
|
||
|
phiObs(i, j, k) = (n.x * (double)i + n.y * (double)j + n.z * (double)k - origin) * fac;
|
||
|
}
|
||
|
inline const Vec3 &getArg0()
|
||
|
{
|
||
|
return n;
|
||
|
}
|
||
|
typedef Vec3 type0;
|
||
|
inline Grid<Real> &getArg1()
|
||
|
{
|
||
|
return phiObs;
|
||
|
}
|
||
|
typedef Grid<Real> type1;
|
||
|
inline const Real &getArg2()
|
||
|
{
|
||
|
return fac;
|
||
|
}
|
||
|
typedef Real type2;
|
||
|
inline const Real &getArg3()
|
||
|
{
|
||
|
return origin;
|
||
|
}
|
||
|
typedef Real type3;
|
||
|
void runMessage()
|
||
|
{
|
||
|
debMsg("Executing kernel SlopeSDF ", 3);
|
||
|
debMsg("Kernel range"
|
||
|
<< " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
|
||
|
4);
|
||
|
};
|
||
|
void operator()(const tbb::blocked_range<IndexInt> &__r) const
|
||
|
{
|
||
|
const int _maxX = maxX;
|
||
|
const int _maxY = maxY;
|
||
|
if (maxZ > 1) {
|
||
|
for (int k = __r.begin(); k != (int)__r.end(); k++)
|
||
|
for (int j = 0; j < _maxY; j++)
|
||
|
for (int i = 0; i < _maxX; i++)
|
||
|
op(i, j, k, n, phiObs, fac, origin);
|
||
|
}
|
||
|
else {
|
||
|
const int k = 0;
|
||
|
for (int j = __r.begin(); j != (int)__r.end(); j++)
|
||
|
for (int i = 0; i < _maxX; i++)
|
||
|
op(i, j, k, n, phiObs, fac, origin);
|
||
|
}
|
||
|
}
|
||
|
void run()
|
||
|
{
|
||
|
if (maxZ > 1)
|
||
|
tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
|
||
|
else
|
||
|
tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
|
||
|
}
|
||
|
const Vec3 &n;
|
||
|
Grid<Real> &phiObs;
|
||
|
const Real &fac;
|
||
|
const Real &origin;
|
||
|
};
|
||
|
|
||
|
void Slope::generateLevelset(Grid<Real> &phi)
|
||
|
{
|
||
|
|
||
|
const Real alpha = -mAnglexy * M_PI / 180.;
|
||
|
const Real beta = -mAngleyz * M_PI / 180.;
|
||
|
|
||
|
Vec3 n(0, 1, 0);
|
||
|
|
||
|
n.x = std::sin(alpha) * std::cos(beta);
|
||
|
n.y = std::cos(alpha) * std::cos(beta);
|
||
|
n.z = std::sin(beta);
|
||
|
|
||
|
normalize(n);
|
||
|
|
||
|
const Real fac = 1. / std::sqrt(n.x * n.x + n.y * n.y + n.z * n.z);
|
||
|
|
||
|
SlopeSDF(n, phi, fac, mOrigin);
|
||
|
}
|
||
|
|
||
|
} // namespace Manta
|