/* 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