From 94d3e79a8617f88dc0219cfdeedfa3147833719d Mon Sep 17 00:00:00 2001 From: Adrian Kummerlaender Date: Mon, 24 Jun 2019 14:43:36 +0200 Subject: Initialize at openlb-1-3 --- src/io/stlReader.hh | 1258 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1258 insertions(+) create mode 100644 src/io/stlReader.hh (limited to 'src/io/stlReader.hh') diff --git a/src/io/stlReader.hh b/src/io/stlReader.hh new file mode 100644 index 0000000..7518b54 --- /dev/null +++ b/src/io/stlReader.hh @@ -0,0 +1,1258 @@ +/* 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 -- cgit v1.2.3