/* This file is part of the OpenLB library
*
* Copyright (C) 2010-2015 Thomas Henn, Mathias J. Krause
* E-mail contact: info@openlb.net
* The most recent release of OpenLB can be downloaded at
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/** \file
* Input in STL format -- header file. - nope
*/
#ifndef STL_READER_HH
#define STL_READER_HH
#include
#include
#include
#include
#include "core/singleton.h"
#include "communication/mpiManager.h"
#include "octree.hh"
#include "stlReader.h"
using namespace olb::util;
/// All OpenLB code is contained in this namespace.
namespace olb {
template
void STLtriangle::init()
{
Vector A = point[0].r;
Vector B = point[1].r;
Vector C = point[2].r;
Vector b, c;
T bb = 0., bc = 0., cc = 0.;
for (int i = 0; i < 3; i++) {
b[i] = B[i] - A[i];
c[i] = C[i] - A[i];
bb += b[i] * b[i];
bc += b[i] * c[i];
cc += c[i] * c[i];
}
normal[0] = b[1] * c[2] - b[2] * c[1];
normal[1] = b[2] * c[0] - b[0] * c[2];
normal[2] = b[0] * c[1] - b[1] * c[0];
T norm = sqrt(
std::pow(normal[0], 2) + std::pow(normal[1], 2) + std::pow(normal[2], 2));
normal[0] /= norm;
normal[1] /= norm;
normal[2] /= norm;
T D = 1.0 / (cc * bb - bc * bc);
T bbD = bb * D;
T bcD = bc * D;
T ccD = cc * D;
kBeta = 0.;
kGamma = 0.;
d = 0.;
for (int i = 0; i < 3; i++) {
uBeta[i] = b[i] * ccD - c[i] * bcD;
uGamma[i] = c[i] * bbD - b[i] * bcD;
kBeta -= A[i] * uBeta[i];
kGamma -= A[i] * uGamma[i];
d += A[i] * normal[i];
}
}
template
std::vector STLtriangle::getE0()
{
Vector vec;
vec[0] = point[0].r[0] - point[1].r[0];
vec[1] = point[0].r[1] - point[1].r[1];
vec[2] = point[0].r[2] - point[1].r[2];
return vec;
}
template
std::vector STLtriangle::getE1()
{
Vector vec;
vec[0] = point[0].r[0] - point[2].r[0];
vec[1] = point[0].r[1] - point[2].r[1];
vec[2] = point[0].r[2] - point[2].r[2];
return vec;
}
/* Schnitttest nach
* http://www.uninformativ.de/bin/RaytracingSchnitttests-76a577a-CC-BY.pdf
*
* Creative Commons Namensnennung 3.0 Deutschland
* http://creativecommons.org/licenses/by/3.0/de/
*
* P. Hofmann, 22. August 2010
*
*/
template
bool STLtriangle::testRayIntersect(const Vector& pt,
const Vector& dir,
Vector& q, T& alpha, const T& rad,
bool print)
{
T rn = 0.;
Vector testPt = pt + rad * normal;
Vector help;
for (int i = 0; i < 3; i++) {
rn += dir[i] * normal[i];
}
#ifdef OLB_DEBUG
if (print) {
std::cout << "Pt: " << pt[0] << " " << pt[1] << " " << pt[2] << std::endl;
}
if (print)
std::cout << "testPt: " << testPt[0] << " " << testPt[1] << " " << testPt[2]
<< std::endl;
if (print)
std::cout << "PosNeg: "
<< normal[0] * testPt[0] + normal[1] * testPt[1] + normal[2] * testPt[2]
- d << std::endl;
if (print)
std::cout << "Normal: " << normal[0] << " " << normal[1] << " " << normal[2]
<< std::endl;
#endif
// Schnitttest Flugrichtung -> Ebene
if (fabs(rn) < std::numeric_limits::epsilon()) {
#ifdef OLB_DEBUG
if (print) {
std::cout << "FALSE 1" << std::endl;
}
#endif
return false;
}
alpha = d - testPt[0] * normal[0] - testPt[1] * normal[1] - testPt[2] * normal[2];
// alpha -= testPt[i] * normal[i];
alpha /= rn;
// Abstand Partikel Ebene
if (alpha < -std::numeric_limits::epsilon()) {
#ifdef OLB_DEBUG
if (print) {
std::cout << "FALSE 2" << std::endl;
}
#endif
return false;
}
for (int i = 0; i < 3; i++) {
q[i] = testPt[i] + alpha * dir[i];
}
double beta = kBeta;
for (int i = 0; i < 3; i++) {
beta += uBeta[i] * q[i];
}
#ifdef OLB_DEBUG
T dist = sqrt(
pow(q[0] - testPt[0], 2) + pow(q[1] - testPt[1], 2)
+ pow(q[2] - testPt[2], 2));
#endif
// Schnittpunkt q in der Ebene?
if (beta < -std::numeric_limits::epsilon()) {
#ifdef OLB_DEBUG
if (print) {
std::cout << "FALSE 3 BETA " << beta << " DIST " << dist << std::endl;
}
#endif
return false;
}
double gamma = kGamma;
for (int i = 0; i < 3; i++) {
gamma += uGamma[i] * q[i];
}
if (gamma < -std::numeric_limits::epsilon()) {
#ifdef OLB_DEBUG
if (print) {
std::cout << "FALSE 4 GAMMA " << gamma << " DIST " << dist << std::endl;
}
#endif
return false;
}
if (1. - beta - gamma < -std::numeric_limits::epsilon()) {
#ifdef OLB_DEBUG
if (print)
std::cout << "FALSE 5 VAL " << 1 - beta - gamma << " DIST " << dist
<< std::endl;
#endif
return false;
}
#ifdef OLB_DEBUG
if (print) {
std::cout << "TRUE" << " GAMMA " << gamma << " BETA " << beta << std::endl;
}
#endif
return true;
}
/**
* computes closest Point in a triangle to another point.
* source: Real-Time Collision Detection. Christer Ericson. ISBN-10: 1558607323
*/
template
Vector STLtriangle::closestPtPointTriangle(
const Vector& pt) const
{
const T nEps = -std::numeric_limits::epsilon();
const T Eps = std::numeric_limits::epsilon();
Vector ab = point[1].r - point[0].r;
Vector ac = point[2].r - point[0].r;
Vector bc = point[2].r - point[1].r;
T snom = (pt - point[0].r)*ab;
T sdenom = (pt - point[1].r)*(point[0].r - point[1].r);
T tnom = (pt - point[0].r)*ac;
T tdenom = (pt - point[2].r)*(point[0].r - point[2].r);
if (snom < nEps && tnom < nEps) {
return point[0].r;
}
T unom = (pt - point[1].r)*bc;
T udenom = (pt - point[2].r)*(point[1].r - point[2].r);
if (sdenom < nEps && unom < nEps) {
return point[1].r;
}
if (tdenom < nEps && udenom < nEps) {
return point[2].r;
}
T vc = normal*crossProduct3D(point[0].r - pt, point[1].r - pt);
if (vc < nEps && snom > Eps && sdenom > Eps) {
return point[0].r + snom / (snom + sdenom) * ab;
}
T va = normal*crossProduct3D(point[1].r - pt, point[2].r - pt);
if (va < nEps && unom > Eps && udenom > Eps) {
return point[1].r + unom / (unom + udenom) * bc;
}
T vb = normal*crossProduct3D(point[2].r - pt, point[0].r - pt);
if (vb < nEps && tnom > Eps && tdenom > Eps) {
return point[0].r + tnom / (tnom + tdenom) * ac;
}
T u = va / (va + vb + vc);
T v = vb / (va + vb + vc);
T w = 1. - u - v;
return u * point[0].r + v * point[1].r + w * point[2].r;
}
template
STLmesh::STLmesh(std::string fName, T stlSize)
: _fName(fName),
_min(T()),
_max(T()),
_maxDist2(0),
clout(std::cout, "STLmesh")
{
std::ifstream f(fName.c_str(), std::ios::in);
_triangles.reserve(10000);
if (!f.good()) {
throw std::runtime_error("STL File not valid.");
}
char buf[6];
buf[5] = 0;
f.read(buf, 5);
const std::string asciiHeader = "solid";
if (std::string(buf) == asciiHeader) {
f.seekg(0, std::ios::beg);
if (f.good()) {
std::string s0, s1;
int i = 0;
while (!f.eof()) {
f >> s0;
if (s0 == "facet") {
STLtriangle tri;
f >> s1 >> tri.normal[0] >> tri.normal[1] >> tri.normal[2];
f >> s0 >> s1;
f >> s0 >> tri.point[0].r[0] >> tri.point[0].r[1]
>> tri.point[0].r[2];
f >> s0 >> tri.point[1].r[0] >> tri.point[1].r[1]
>> tri.point[1].r[2];
f >> s0 >> tri.point[2].r[0] >> tri.point[2].r[1]
>> tri.point[2].r[2];
f >> s0;
f >> s0;
for (int k = 0; k < 3; k++) {
tri.point[0].r[k] *= stlSize;
tri.point[1].r[k] *= stlSize;
tri.point[2].r[k] *= stlSize;
}
if (i == 0) {
_min*=T();
_max*=T();
_min[0] = tri.point[0].r[0];
_min[1] = tri.point[0].r[1];
_min[2] = tri.point[0].r[2];
_max[0] = tri.point[0].r[0];
_max[1] = tri.point[0].r[1];
_max[2] = tri.point[0].r[2];
_min[0] = std::min(_min[0], (T) tri.point[1].r[0]);
_min[1] = std::min(_min[1], (T) tri.point[1].r[1]);
_min[2] = std::min(_min[2], (T) tri.point[1].r[2]);
_max[0] = std::max(_max[0], (T) tri.point[1].r[0]);
_max[1] = std::max(_max[1], (T) tri.point[1].r[1]);
_max[2] = std::max(_max[2], (T) tri.point[1].r[2]);
_min[0] = std::min(_min[0], (T) tri.point[2].r[0]);
_min[1] = std::min(_min[1], (T) tri.point[2].r[1]);
_min[2] = std::min(_min[2], (T) tri.point[2].r[2]);
_max[0] = std::max(_max[0], (T) tri.point[2].r[0]);
_max[1] = std::max(_max[1], (T) tri.point[2].r[1]);
_max[2] = std::max(_max[2], (T) tri.point[2].r[2]);
} else {
_min[0] = std::min(_min[0], (T) tri.point[0].r[0]);
_min[1] = std::min(_min[1], (T) tri.point[0].r[1]);
_min[2] = std::min(_min[2], (T) tri.point[0].r[2]);
_max[0] = std::max(_max[0], (T) tri.point[0].r[0]);
_max[1] = std::max(_max[1], (T) tri.point[0].r[1]);
_max[2] = std::max(_max[2], (T) tri.point[0].r[2]);
_min[0] = std::min(_min[0], (T) tri.point[1].r[0]);
_min[1] = std::min(_min[1], (T) tri.point[1].r[1]);
_min[2] = std::min(_min[2], (T) tri.point[1].r[2]);
_max[0] = std::max(_max[0], (T) tri.point[1].r[0]);
_max[1] = std::max(_max[1], (T) tri.point[1].r[1]);
_max[2] = std::max(_max[2], (T) tri.point[1].r[2]);
_min[0] = std::min(_min[0], (T) tri.point[2].r[0]);
_min[1] = std::min(_min[1], (T) tri.point[2].r[1]);
_min[2] = std::min(_min[2], (T) tri.point[2].r[2]);
_max[0] = std::max(_max[0], (T) tri.point[2].r[0]);
_max[1] = std::max(_max[1], (T) tri.point[2].r[1]);
_max[2] = std::max(_max[2], (T) tri.point[2].r[2]);
}
i++;
tri.init();
_triangles.push_back(tri);
_maxDist2 = std::max(distPoints(tri.point[0], tri.point[1]),
_maxDist2);
_maxDist2 = std::max(distPoints(tri.point[2], tri.point[1]),
_maxDist2);
_maxDist2 = std::max(distPoints(tri.point[0], tri.point[2]),
_maxDist2);
} else if (s0 == "endsolid") {
break;
}
}
}
} else {
f.close();
f.open(fName.c_str(), std::ios::in | std::ios::binary);
char comment[80];
f.read(comment, 80);
if (!f.good()) {
throw std::runtime_error("STL File not valid.");
}
comment[79] = 0;
int32_t nFacets;
f.read(reinterpret_cast(&nFacets), sizeof(int32_t));
if (!f.good()) {
throw std::runtime_error("STL File not valid.");
}
float v[12];
unsigned short uint16;
for (int32_t i = 0; i < nFacets; ++i) {
for (unsigned int j = 0; j < 12; ++j) {
f.read(reinterpret_cast(&v[j]), sizeof(float));
}
f.read(reinterpret_cast(&uint16), sizeof(unsigned short));
STLtriangle tri;
tri.normal[0] = v[0];
tri.normal[1] = v[1];
tri.normal[2] = v[2];
tri.point[0].r[0] = v[3];
tri.point[0].r[1] = v[4];
tri.point[0].r[2] = v[5];
tri.point[1].r[0] = v[6];
tri.point[1].r[1] = v[7];
tri.point[1].r[2] = v[8];
tri.point[2].r[0] = v[9];
tri.point[2].r[1] = v[10];
tri.point[2].r[2] = v[11];
for (int k = 0; k < 3; k++) {
tri.point[0].r[k] *= stlSize;
tri.point[1].r[k] *= stlSize;
tri.point[2].r[k] *= stlSize;
}
if (i == 0) {
_min[0] = tri.point[0].r[0];
_min[1] = tri.point[0].r[1];
_min[2] = tri.point[0].r[2];
_max[0] = tri.point[0].r[0];
_max[1] = tri.point[0].r[1];
_max[2] = tri.point[0].r[2];
_min[0] = std::min(_min[0], (T) tri.point[1].r[0]);
_min[1] = std::min(_min[1], (T) tri.point[1].r[1]);
_min[2] = std::min(_min[2], (T) tri.point[1].r[2]);
_max[0] = std::max(_max[0], (T) tri.point[1].r[0]);
_max[1] = std::max(_max[1], (T) tri.point[1].r[1]);
_max[2] = std::max(_max[2], (T) tri.point[1].r[2]);
_min[0] = std::min(_min[0], (T) tri.point[2].r[0]);
_min[1] = std::min(_min[1], (T) tri.point[2].r[1]);
_min[2] = std::min(_min[2], (T) tri.point[2].r[2]);
_max[0] = std::max(_max[0], (T) tri.point[2].r[0]);
_max[1] = std::max(_max[1], (T) tri.point[2].r[1]);
_max[2] = std::max(_max[2], (T) tri.point[2].r[2]);
} else {
_min[0] = std::min(_min[0], (T) tri.point[0].r[0]);
_min[1] = std::min(_min[1], (T) tri.point[0].r[1]);
_min[2] = std::min(_min[2], (T) tri.point[0].r[2]);
_max[0] = std::max(_max[0], (T) tri.point[0].r[0]);
_max[1] = std::max(_max[1], (T) tri.point[0].r[1]);
_max[2] = std::max(_max[2], (T) tri.point[0].r[2]);
_min[0] = std::min(_min[0], (T) tri.point[1].r[0]);
_min[1] = std::min(_min[1], (T) tri.point[1].r[1]);
_min[2] = std::min(_min[2], (T) tri.point[1].r[2]);
_max[0] = std::max(_max[0], (T) tri.point[1].r[0]);
_max[1] = std::max(_max[1], (T) tri.point[1].r[1]);
_max[2] = std::max(_max[2], (T) tri.point[1].r[2]);
_min[0] = std::min(_min[0], (T) tri.point[2].r[0]);
_min[1] = std::min(_min[1], (T) tri.point[2].r[1]);
_min[2] = std::min(_min[2], (T) tri.point[2].r[2]);
_max[0] = std::max(_max[0], (T) tri.point[2].r[0]);
_max[1] = std::max(_max[1], (T) tri.point[2].r[1]);
_max[2] = std::max(_max[2], (T) tri.point[2].r[2]);
}
tri.init();
_triangles.push_back(tri);
_maxDist2 = std::max(distPoints(tri.point[0], tri.point[1]), _maxDist2);
_maxDist2 = std::max(distPoints(tri.point[2], tri.point[1]), _maxDist2);
_maxDist2 = std::max(distPoints(tri.point[0], tri.point[2]), _maxDist2);
}
}
f.close();
}
template
STLmesh::STLmesh(const std::vector> meshPoints, T stlSize)
: _fName("meshPoints.stl"),
_min(T()),
_max(T()),
_maxDist2(0),
clout(std::cout, "STLmesh")
{
_triangles.reserve(10000);
for (size_t i = 0; i < meshPoints.size() / 3; i++) {
STLtriangle tri;
tri.point[0].r[0] = meshPoints[i*3 + 0][0];
tri.point[0].r[1] = meshPoints[i*3 + 0][1];
tri.point[0].r[2] = meshPoints[i*3 + 0][2];
tri.point[1].r[0] = meshPoints[i*3 + 1][0];
tri.point[1].r[1] = meshPoints[i*3 + 1][1];
tri.point[1].r[2] = meshPoints[i*3 + 1][2];
tri.point[2].r[0] = meshPoints[i*3 + 2][0];
tri.point[2].r[1] = meshPoints[i*3 + 2][1];
tri.point[2].r[2] = meshPoints[i*3 + 2][2];
for (int k = 0; k < 3; k++) {
tri.point[0].r[k] *= stlSize;
tri.point[1].r[k] *= stlSize;
tri.point[2].r[k] *= stlSize;
}
if (i == 0) {
_min*=T();
_max*=T();
_min[0] = tri.point[0].r[0];
_min[1] = tri.point[0].r[1];
_min[2] = tri.point[0].r[2];
_max[0] = tri.point[0].r[0];
_max[1] = tri.point[0].r[1];
_max[2] = tri.point[0].r[2];
_min[0] = std::min(_min[0], (T) tri.point[1].r[0]);
_min[1] = std::min(_min[1], (T) tri.point[1].r[1]);
_min[2] = std::min(_min[2], (T) tri.point[1].r[2]);
_max[0] = std::max(_max[0], (T) tri.point[1].r[0]);
_max[1] = std::max(_max[1], (T) tri.point[1].r[1]);
_max[2] = std::max(_max[2], (T) tri.point[1].r[2]);
_min[0] = std::min(_min[0], (T) tri.point[2].r[0]);
_min[1] = std::min(_min[1], (T) tri.point[2].r[1]);
_min[2] = std::min(_min[2], (T) tri.point[2].r[2]);
_max[0] = std::max(_max[0], (T) tri.point[2].r[0]);
_max[1] = std::max(_max[1], (T) tri.point[2].r[1]);
_max[2] = std::max(_max[2], (T) tri.point[2].r[2]);
} else {
_min[0] = std::min(_min[0], (T) tri.point[0].r[0]);
_min[1] = std::min(_min[1], (T) tri.point[0].r[1]);
_min[2] = std::min(_min[2], (T) tri.point[0].r[2]);
_max[0] = std::max(_max[0], (T) tri.point[0].r[0]);
_max[1] = std::max(_max[1], (T) tri.point[0].r[1]);
_max[2] = std::max(_max[2], (T) tri.point[0].r[2]);
_min[0] = std::min(_min[0], (T) tri.point[1].r[0]);
_min[1] = std::min(_min[1], (T) tri.point[1].r[1]);
_min[2] = std::min(_min[2], (T) tri.point[1].r[2]);
_max[0] = std::max(_max[0], (T) tri.point[1].r[0]);
_max[1] = std::max(_max[1], (T) tri.point[1].r[1]);
_max[2] = std::max(_max[2], (T) tri.point[1].r[2]);
_min[0] = std::min(_min[0], (T) tri.point[2].r[0]);
_min[1] = std::min(_min[1], (T) tri.point[2].r[1]);
_min[2] = std::min(_min[2], (T) tri.point[2].r[2]);
_max[0] = std::max(_max[0], (T) tri.point[2].r[0]);
_max[1] = std::max(_max[1], (T) tri.point[2].r[1]);
_max[2] = std::max(_max[2], (T) tri.point[2].r[2]);
}
tri.init();
_triangles.push_back(tri);
_maxDist2 = std::max(distPoints(tri.point[0], tri.point[1]),
_maxDist2);
_maxDist2 = std::max(distPoints(tri.point[2], tri.point[1]),
_maxDist2);
_maxDist2 = std::max(distPoints(tri.point[0], tri.point[2]),
_maxDist2);
}
}
template
T STLmesh::distPoints(STLpoint& p1, STLpoint& p2)
{
return std::pow(double(p1.r[0] - p2.r[0]), 2)
+ std::pow(double(p1.r[1] - p2.r[1]), 2)
+ std::pow(double(p1.r[2] - p2.r[2]), 2);
}
template
void STLmesh::print(bool full)
{
if (full) {
int i = 0;
clout << "Triangles: " << std::endl;
typename std::vector >::iterator it = _triangles.begin();
for (; it != _triangles.end(); ++it) {
clout << i++ << ": " << it->point[0].r[0] << " " << it->point[0].r[1]
<< " " << it->point[0].r[2] << " | " << it->point[1].r[0] << " "
<< it->point[1].r[1] << " " << it->point[1].r[2] << " | "
<< it->point[2].r[0] << " " << it->point[2].r[1] << " "
<< it->point[2].r[2] << std::endl;
}
}
clout << "nTriangles=" << _triangles.size() << "; maxDist2=" << _maxDist2
<< std::endl;
clout << "minPhysR(StlMesh)=(" << getMin()[0] << "," << getMin()[1] << ","
<< getMin()[2] << ")";
clout << "; maxPhysR(StlMesh)=(" << getMax()[0] << "," << getMax()[1] << ","
<< getMax()[2] << ")" << std::endl;
}
template
void STLmesh::write(std::string fName)
{
int rank = 0;
#ifdef PARALLEL_MODE_MPI
rank = singleton::mpi().getRank();
#endif
if (rank == 0) {
std::string fullName = singleton::directories().getVtkOutDir() + fName
+ ".stl";
std::ofstream f(fullName.c_str());
f << "solid ascii " << fullName << "\n";
for (unsigned int i = 0; i < _triangles.size(); i++) {
f << "facet normal " << _triangles[i].normal[0] << " "
<< _triangles[i].normal[1] << " " << _triangles[i].normal[2] << "\n";
f << " outer loop\n";
f << " vertex " << _triangles[i].point[0].r[0] << " "
<< _triangles[i].point[0].r[1] << " " << _triangles[i].point[0].r[2]
<< "\n";
f << " vertex " << _triangles[i].point[1].r[0] << " "
<< _triangles[i].point[1].r[1] << " " << _triangles[i].point[1].r[2]
<< "\n";
f << " vertex " << _triangles[i].point[2].r[0] << " "
<< _triangles[i].point[2].r[1] << " " << _triangles[i].point[2].r[2]
<< "\n";
f << " endloop\n";
f << "endfacet\n";
}
f.close();
}
/*if (_verbose)*/clout << "Write ... OK" << std::endl;
}
template
bool STLmesh::testRayIntersect(const std::set& tris, const Vector& pt,const Vector& dir, Vector& q, T& alpha)
{
std::set::iterator it = tris.begin();
for (; it != tris.end(); ++it) {
if (_triangles[*it].testRayIntersect(pt, dir, q, alpha) && alpha < 1) {
return true;
}
}
return false;
}
/*
* STLReader functions
*/
template
STLreader::STLreader(const std::string fName, T voxelSize, T stlSize,
unsigned short int method, bool verbose, T overlap, T max)
: _voxelSize(voxelSize),
_stlSize(stlSize),
_overlap(overlap),
_fName(fName),
_mesh(fName, stlSize),
_verbose(verbose),
clout(std::cout, "STLreader")
{
this->getName() = "STLreader";
if (_verbose) {
clout << "Voxelizing ..." << std::endl;
}
Vector extension = _mesh.getMax() - _mesh.getMin();
if ( util::nearZero(max) ) {
max = std::max(extension[0], std::max(extension[1], extension[2])) + _voxelSize;
}
int j = 0;
for (; _voxelSize * std::pow(2, j) < max; j++)
;
Vector center;
T radius = _voxelSize * std::pow(2, j - 1);
/// Find center of tree and move by _voxelSize/4.
for (unsigned i = 0; i < 3; i++) {
center[i] = (_mesh.getMin()[i] + _mesh.getMax()[i]) / 2. - _voxelSize / 4.;
}
/// Create tree
_tree = new Octree(center, radius, &_mesh, j, _overlap);
/// Compute _myMin, _myMax such that they are the smallest (greatest) Voxel inside the STL.
for (int i = 0; i < 3; i++) {
this->_myMin[i] = center[i] + _voxelSize / 2.;
this->_myMax[i] = center[i] - _voxelSize / 2.;
}
for (int i = 0; i < 3; i++) {
while (this->_myMin[i] > _mesh.getMin()[i]) {
this->_myMin[i] -= _voxelSize;
}
while (this->_myMax[i] < _mesh.getMax()[i]) {
this->_myMax[i] += _voxelSize;
}
this->_myMax[i] -= _voxelSize;
this->_myMin[i] += _voxelSize;
}
/// Indicate nodes of the tree. (Inside/Outside)
switch (method) {
case 1:
indicate1();
break;
case 3:
indicate3();
break;
default:
indicate2();
break;
}
if (_verbose) {
print();
}
if (_verbose) {
clout << "Voxelizing ... OK" << std::endl;
}
}
/*
* STLReader functions
*/
template
STLreader::STLreader(const std::vector> meshPoints, T voxelSize, T stlSize,
unsigned short int method, bool verbose, T overlap, T max)
: _voxelSize(voxelSize),
_stlSize(stlSize),
_overlap(overlap),
_fName("meshPoints.stl"),
_mesh(meshPoints, stlSize),
_verbose(verbose),
clout(std::cout, "STLreader")
{
this->getName() = "STLreader";
if (_verbose) {
clout << "Voxelizing ..." << std::endl;
}
Vector extension = _mesh.getMax() - _mesh.getMin();
if ( util::nearZero(max) ) {
max = std::max(extension[0], std::max(extension[1], extension[2])) + _voxelSize;
}
int j = 0;
for (; _voxelSize * std::pow(2, j) < max; j++)
;
Vector center;
T radius = _voxelSize * std::pow(2, j - 1);
/// Find center of tree and move by _voxelSize/4.
for (unsigned i = 0; i < 3; i++) {
center[i] = (_mesh.getMin()[i] + _mesh.getMax()[i]) / 2. - _voxelSize / 4.;
}
/// Create tree
_tree = new Octree(center, radius, &_mesh, j, _overlap);
/// Compute _myMin, _myMax such that they are the smallest (greatest) Voxel inside the STL.
for (int i = 0; i < 3; i++) {
this->_myMin[i] = center[i] + _voxelSize / 2.;
this->_myMax[i] = center[i] - _voxelSize / 2.;
}
for (int i = 0; i < 3; i++) {
while (this->_myMin[i] > _mesh.getMin()[i]) {
this->_myMin[i] -= _voxelSize;
}
while (this->_myMax[i] < _mesh.getMax()[i]) {
this->_myMax[i] += _voxelSize;
}
this->_myMax[i] -= _voxelSize;
this->_myMin[i] += _voxelSize;
}
// Indicate nodes of the tree. (Inside/Outside)
switch (method) {
case 1:
indicate1();
break;
case 3:
indicate3();
break;
default:
indicate2();
break;
}
if (_verbose) {
print();
}
if (_verbose) {
clout << "Voxelizing ... OK" << std::endl;
}
}
template
STLreader::~STLreader()
{
delete _tree;
}
/*
* Old indicate function (slower, more stable)
* Define three rays (X-, Y-, Z-direction) for each leaf and count intersections
* with STL for each ray. Odd number of intersection means inside (Majority vote).
*/
template
void STLreader::indicate1()
{
std::vector*> leafs;
_tree->getLeafs(leafs);
typename std::vector*>::iterator it = leafs.begin();
Vector dir, pt, s;
int intersections = 0;
int inside = 0;
Octree* node = nullptr;
T step = 1. / 1000. * _voxelSize;
for (; it != leafs.end(); ++it) {
inside = 0;
pt = (*it)->getCenter();
intersections = 0;
s = pt; // + step;
/// X+ dir
dir[0] = 1;
dir[1] = 0;
dir[2] = 0;
while (s[0] < _mesh.getMax()[0] + std::numeric_limits::epsilon()) {
node = _tree->find(s, (*it)->getMaxdepth());
intersections += node->testIntersection(pt, dir);
node->intersectRayNode(pt, dir, s);
s = s + step * dir;
}
inside += (intersections % 2);
/// Y+ Test
intersections = 0;
s = pt; // + step;
dir[0] = 0;
dir[1] = 1;
dir[2] = 0;
while (s[1] < _mesh.getMax()[1] + std::numeric_limits::epsilon()) {
node = _tree->find(s, (*it)->getMaxdepth());
intersections += node->testIntersection(pt, dir);
node->intersectRayNode(pt, dir, s);
s = s + step * dir;
}
inside += (intersections % 2);
/// Z+ Test
intersections = 0;
s = pt; // + step;
dir[0] = 0;
dir[1] = 0;
dir[2] = 1;
while (s[2] < _mesh.getMax()[2] + std::numeric_limits::epsilon()) {
node = _tree->find(s, (*it)->getMaxdepth());
intersections += node->testIntersection(pt, dir);
node->intersectRayNode(pt, dir, s);
s = s + step * dir;
}
inside += (intersections % 2);
(*it)->setInside(inside > 1);
}
}
/*
* New indicate function (faster, less stable)
* Define ray in Z-direction for each Voxel in XY-layer. Indicate all nodes on the fly.
*/
template
void STLreader::indicate2()
{
T rad = _tree->getRadius();
Vector rayPt = _tree->getCenter() - rad + .5 * _voxelSize;
Vector pt = rayPt;
Vector rayDir;
rayDir[0] = 0.;
rayDir[1] = 0.;
rayDir[2] = 1.;
//Vector maxEdge = _tree->getCenter() + rad;
T step = 1. / 1000. * _voxelSize;
Octree* node = nullptr;
unsigned short rayInside = 0;
Vector nodeInters;
while (pt[0] < _mesh.getMax()[0] + std::numeric_limits::epsilon()) {
node = _tree->find(pt);
nodeInters = pt;
nodeInters[2] = node->getCenter()[2] - node->getRadius();
rayInside = 0;
while (pt[1] < _mesh.getMax()[1] + std::numeric_limits::epsilon()) {
node = _tree->find(pt);
nodeInters = pt;
nodeInters[2] = node->getCenter()[2] - node->getRadius();
rayInside = 0;
while (pt[2] < _mesh.getMax()[2] + std::numeric_limits::epsilon()) {
node = _tree->find(pt);
node->checkRay(nodeInters, rayDir, rayInside);
node->intersectRayNode(pt, rayDir, nodeInters);
pt = nodeInters + step * rayDir;
}
pt[2] = rayPt[2];
pt[1] += _voxelSize;
}
pt[1] = rayPt[1];
pt[0] += _voxelSize;
}
}
/*
* Double ray approach: two times (X-, Y-, Z-direction) for each leaf.
* Could be use to deal with double layer triangles and face intersections.
*/
template
void STLreader::indicate3()
{
std::vector*> leafs;
_tree->getLeafs(leafs);
typename std::vector*>::iterator it = leafs.begin();
Vector dir, pt, s;
Octree* node = nullptr;
T step = 1. / 1000. * _voxelSize;
int intersections;
int sum_intersections;
for (; it != leafs.end(); ++it) {
pt = (*it)->getCenter();
intersections = 0;
sum_intersections = 0;
s = pt; // + step;
/// X+ dir
dir[0] = 1;
dir[1] = 0;
dir[2] = 0;
while (s[0] < _mesh.getMax()[0] + std::numeric_limits::epsilon()) {
node = _tree->find(s, (*it)->getMaxdepth());
intersections = node->testIntersection(pt, dir);
node->intersectRayNode(pt, dir, s);
s = s + step * dir;
if (intersections > 0) {
sum_intersections++;
break;
}
}
/// Y+ Test
intersections = 0;
s = pt; // + step;
dir[0] = 0;
dir[1] = 1;
dir[2] = 0;
while (s[1] < _mesh.getMax()[1] + std::numeric_limits::epsilon()) {
node = _tree->find(s, (*it)->getMaxdepth());
intersections = node->testIntersection(pt, dir);
node->intersectRayNode(pt, dir, s);
s = s + step * dir;
if (intersections > 0) {
sum_intersections++;
break;
}
}
/// Z+ Test
intersections = 0;
s = pt; // + step;
dir[0] = 0;
dir[1] = 0;
dir[2] = 1;
while (s[2] < _mesh.getMax()[2] + std::numeric_limits::epsilon()) {
node = _tree->find(s, (*it)->getMaxdepth());
intersections = node->testIntersection(pt, dir);
node->intersectRayNode(pt, dir, s);
s = s + step * dir;
if (intersections > 0) {
sum_intersections++;
break;
}
}
/// X- dir
intersections = 0;
s = pt; // + step;
dir[0] = -1;
dir[1] = 0;
dir[2] = 0;
while (s[0] > _mesh.getMin()[0] - std::numeric_limits::epsilon()) {
node = _tree->find(s, (*it)->getMaxdepth());
intersections = node->testIntersection(pt, dir);
node->intersectRayNode(pt, dir, s);
s = s + step * dir;
if (intersections > 0) {
sum_intersections++;
break;
}
}
/// Y- Test
intersections = 0;
s = pt; // + step;
dir[0] = 0;
dir[1] = -1;
dir[2] = 0;
while (s[1] > _mesh.getMin()[1] - std::numeric_limits::epsilon()) {
node = _tree->find(s, (*it)->getMaxdepth());
intersections = node->testIntersection(pt, dir);
node->intersectRayNode(pt, dir, s);
s = s + step * dir;
if (intersections > 0) {
sum_intersections++;
break;
}
}
/// Z- Test
intersections = 0;
s = pt; // + step;
dir[0] = 0;
dir[1] = 0;
dir[2] = -1;
while (s[2] > _mesh.getMin()[2] - std::numeric_limits::epsilon()) {
node = _tree->find(s, (*it)->getMaxdepth());
intersections = node->testIntersection(pt, dir);
node->intersectRayNode(pt, dir, s);
s = s + step * dir;
if (intersections > 0) {
sum_intersections++;
break;
}
}
(*it)->setInside(sum_intersections > 5);
}
}
template
bool STLreader::operator() (bool output[], const T input[])
{
output[0] = false;
T r = _tree->getRadius();
Vector c(_tree->getCenter());
if (c[0] - r < input[0] && input[0] < c[0] + r && c[1] - r < input[1]
&& input[1] < c[1] + r && c[2] - r < input[2] && input[2] < c[2] + r) {
std::vector tmp(input, input + 3);
output[0] = _tree->find(tmp)->getInside();
}
return true;
}
template
bool STLreader::distance(T& distance, const Vector& origin,
const Vector& direction, int iC)
{
Octree* node = nullptr;
Vector dir(direction);
dir.normalize();
Vector extends = _mesh.getMax() - _mesh.getMin();
Vector pt(origin);
Vector q;
Vector s;
Vector center = _mesh.getMin() + 1 / 2. * extends;
T step = _voxelSize / 1000., a = 0;
for (int i = 0; i < 3; i++) {
extends[i] /= 2.;
}
if (!(_mesh.getMin()[0] < origin[0] && origin[0] < _mesh.getMax()[0]
&& _mesh.getMin()[1] < origin[1] && origin[1] < _mesh.getMax()[1]
&& _mesh.getMin()[2] < origin[2] && origin[2] < _mesh.getMax()[2])) {
T t = T(), d = T();
bool foundQ = false;
if (dir[0] > 0) {
d = _mesh.getMin()[0];
t = (d - origin[0]) / dir[0];
pt[0] = origin[0] + (t + step) * dir[0];
pt[1] = origin[1] + (t + step) * dir[1];
pt[2] = origin[2] + (t + step) * dir[2];
if (_mesh.getMin()[1] < pt[1] && pt[1] < _mesh.getMax()[1]
&& _mesh.getMin()[2] < pt[2] && pt[2] < _mesh.getMax()[2]) {
foundQ = true;
}
} else if (dir[0] < 0) {
d = _mesh.getMax()[0];
t = (d - origin[0]) / dir[0];
pt[0] = origin[0] + (t + step) * dir[0];
pt[1] = origin[1] + (t + step) * dir[1];
pt[2] = origin[2] + (t + step) * dir[2];
if (_mesh.getMin()[1] < pt[1] && pt[1] < _mesh.getMax()[1]
&& _mesh.getMin()[2] < pt[2] && pt[2] < _mesh.getMax()[2]) {
foundQ = true;
}
}
if (dir[1] > 0 && !foundQ) {
d = _mesh.getMin()[1];
t = (d - origin[1]) / dir[1];
pt[0] = origin[0] + (t + step) * dir[0];
pt[1] = origin[1] + (t + step) * dir[1];
pt[2] = origin[2] + (t + step) * dir[2];
if (_mesh.getMin()[0] < pt[0] && pt[0] < _mesh.getMax()[0]
&& _mesh.getMin()[2] < pt[2] && pt[2] < _mesh.getMax()[2]) {
foundQ = true;
}
} else if (dir[1] < 0 && !foundQ) {
d = _mesh.getMax()[1];
t = (d - origin[1]) / dir[1];
pt[0] = origin[0] + (t + step) * dir[0];
pt[1] = origin[1] + (t + step) * dir[1];
pt[2] = origin[2] + (t + step) * dir[2];
if (_mesh.getMin()[0] < pt[0] && pt[0] < _mesh.getMax()[0]
&& _mesh.getMin()[2] < pt[2] && pt[2] < _mesh.getMax()[2]) {
foundQ = true;
}
}
if (dir[2] > 0 && !foundQ) {
d = _mesh.getMin()[2];
t = (d - origin[2]) / dir[2];
pt[0] = origin[0] + (t + step) * dir[0];
pt[1] = origin[1] + (t + step) * dir[1];
pt[2] = origin[2] + (t + step) * dir[2];
if (_mesh.getMin()[0] < pt[0] && pt[0] < _mesh.getMax()[0]
&& _mesh.getMin()[1] < pt[1] && pt[1] < _mesh.getMax()[1]) {
foundQ = true;
}
} else if (dir[2] < 0 && !foundQ) {
d = _mesh.getMax()[2];
t = (d - origin[2]) / dir[2];
pt[0] = origin[0] + (t + step) * dir[0];
pt[1] = origin[1] + (t + step) * dir[1];
pt[2] = origin[2] + (t + step) * dir[2];
if (_mesh.getMin()[0] < pt[0] && pt[0] < _mesh.getMax()[0]
&& _mesh.getMin()[1] < pt[1] && pt[1] < _mesh.getMax()[1]) {
foundQ = true;
}
}
if (!foundQ) {
return false;
}
}
while ((std::fabs(pt[0] - center[0]) < extends[0])
&& (std::fabs(pt[1] - center[1]) < extends[1])
&& (std::fabs(pt[2] - center[2]) < extends[2])) {
node = _tree->find(pt);
if (node->closestIntersection(Vector(origin), dir, q, a)) {
Vector vek(q - Vector(origin));
distance = vek.norm();
return true;
} else {
Octree* tmpNode = _tree->find(pt);
tmpNode->intersectRayNode(pt, dir, s);
for (int i = 0; i < 3; i++) {
pt[i] = s[i] + step * dir[i];
}
}
}
if (_verbose) {
clout << "Returning false" << std::endl;
}
return false;
}
template
void STLreader::print()
{
_mesh.print();
_tree->print();
clout << "voxelSize=" << _voxelSize << "; stlSize=" << _stlSize << std::endl;
clout << "minPhysR(VoxelMesh)=(" << this->_myMin[0] << "," << this->_myMin[1]
<< "," << this->_myMin[2] << ")";
clout << "; maxPhysR(VoxelMesh)=(" << this->_myMax[0] << ","
<< this->_myMax[1] << "," << this->_myMax[2] << ")" << std::endl;
}
template
void STLreader::writeOctree()
{
_tree->write(_fName);
}
template
void STLreader::writeSTL(std::string stlName)
{
if (stlName == "") {
_mesh.write(_fName);
} else {
_mesh.write(stlName);
}
}
template
void STLreader::setNormalsOutside()
{
unsigned int noTris = _mesh.triangleSize();
Vector center;
//Octree* node = nullptr;
for (unsigned int i = 0; i < noTris; i++) {
center[0] = (_mesh.getTri(i).point[0].r[0] + _mesh.getTri(i).point[1].r[0]
+ _mesh.getTri(i).point[2].r[0]) / 3.;
center[1] = (_mesh.getTri(i).point[0].r[1] + _mesh.getTri(i).point[1].r[1]
+ _mesh.getTri(i).point[2].r[1]) / 3.;
center[2] = (_mesh.getTri(i).point[0].r[2] + _mesh.getTri(i).point[1].r[2]
+ _mesh.getTri(i).point[2].r[2]) / 3.;
if (_tree->find(
center + _mesh.getTri(i).normal * std::sqrt(3.) * _voxelSize)->getInside()) {
// cout << "Wrong direction" << std::endl;
Vector pt(_mesh.getTri(i).point[0].r);
_mesh.getTri(i).point[0].r = _mesh.getTri(i).point[2].r;
_mesh.getTri(i).point[2].r = pt;
_mesh.getTri(i).init();
// _mesh.getTri(i).getNormal()[0] *= -1.;
// _mesh.getTri(i).getNormal()[1] *= -1.;
// _mesh.getTri(i).getNormal()[2] *= -1.;
}
}
}
} // namespace olb
#endif